Bug 1016240 - Exterminate CR+LF line endings. r=briansmith,cpearce,ehsan,gavin
authorBirunthan Mohanathas <birunthan@mohanathas.com>
Wed, 18 Jun 2014 17:56:02 -0700
changeset 189502 ca251a28d3ddae784436d28829fb019025f4b127
parent 189501 d4bf4c76854e44dc47569e2de1aae57201473348
child 189503 fcf15eb82338c3339cb39066828467b504ccc1a1
push id26988
push useremorley@mozilla.com
push dateThu, 19 Jun 2014 14:39:10 +0000
treeherdermozilla-central@ad11457bae17 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbriansmith, cpearce, ehsan, gavin
bugs1016240
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1016240 - Exterminate CR+LF line endings. r=briansmith,cpearce,ehsan,gavin
browser/base/content/test/chat/browser_chatwindow.js
browser/base/content/test/chat/browser_focus.js
browser/base/content/test/chat/browser_tearoff.js
browser/base/content/test/chat/head.js
browser/base/content/test/general/content_aboutAccounts.js
browser/base/content/test/social/browser_social_workercrash.js
browser/components/customizableui/src/logging.js
browser/components/customizableui/test/browser_885052_customize_mode_observers_disabed.js
browser/components/customizableui/test/browser_888817_currentset_updating.js
browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
browser/components/customizableui/test/browser_901207_searchbar_in_panel.js
browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js
browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js
browser/components/customizableui/test/browser_934951_zoom_in_toolbar.js
browser/components/customizableui/test/browser_938980_navbar_collapsed.js
browser/components/customizableui/test/browser_940107_home_button_in_bookmarks_toolbar.js
browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js
browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js
browser/components/customizableui/test/browser_968447_bookmarks_toolbar_items_in_panel.js
browser/components/customizableui/test/browser_970511_undo_restore_default.js
browser/components/customizableui/test/browser_980155_add_overflow_toolbar.js
browser/components/customizableui/test/browser_981305_separator_insertion.js
browser/components/customizableui/test/browser_982656_restore_defaults_builtin_widgets.js
browser/components/customizableui/test/browser_984455_bookmarks_items_reparenting.js
browser/components/customizableui/test/browser_989751_subviewbutton_class.js
browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
browser/components/dirprovider/tests/unit/head_dirprovider.js
browser/components/dirprovider/tests/unit/test_bookmark_pref.js
browser/components/migration/src/nsIEHistoryEnumerator.cpp
browser/components/migration/src/nsIEHistoryEnumerator.h
browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
browser/devtools/inspector/selector-search.js
browser/metro/base/content/bindings/circularprogress.xml
browser/metro/base/content/commandUtil.js
browser/metro/base/content/helperui/ItemPinHelper.js
browser/metro/base/tests/mochitest/browser_circular_progress_indicator.js
browser/metro/base/tests/mochitest/browser_notifications.js
browser/metro/base/tests/mochitest/browser_progress_indicator.xul
browser/metro/base/tests/mochitest/browser_tabs.js
browser/metro/base/tests/mochitest/browser_tabs_container.js
browser/metro/base/tests/mochitest/browser_ui_telemetry.js
browser/metro/base/tests/unit/test_util_populateFragmentFromString.js
browser/metro/modules/ContentUtil.jsm
browser/metro/modules/View.jsm
browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp
browser/metro/theme/platform.css
browser/modules/Chat.jsm
browser/modules/UITour.jsm
browser/modules/Windows8WindowFrameColor.jsm
browser/modules/test/uitour.js
browser/themes/linux/devtools/scratchpad.css
browser/themes/osx/devtools/scratchpad.css
browser/themes/shared/devtools/app-manager/images/add.svg
browser/themes/shared/devtools/app-manager/images/error.svg
browser/themes/shared/devtools/app-manager/images/plus.svg
browser/themes/shared/devtools/app-manager/images/rocket.svg
browser/themes/shared/devtools/app-manager/images/warning.svg
browser/themes/shared/devtools/scratchpad.inc.css
browser/themes/shared/translation/infobar.inc.css
browser/themes/windows/devtools/scratchpad.css
build/win32/procmem.py
content/canvas/src/CanvasImageCache.h
content/canvas/src/WebGLUniformLocation.cpp
content/media/ogg/OggReader.cpp
content/media/test/make-headers.sh
content/media/wmf/DXVA2Manager.cpp
content/media/wmf/DXVA2Manager.h
content/media/wmf/WMF.h
content/media/wmf/WMFByteStream.cpp
content/media/wmf/WMFByteStream.h
content/media/wmf/WMFDecoder.cpp
content/media/wmf/WMFDecoder.h
content/media/wmf/WMFReader.h
content/media/wmf/WMFSourceReaderCallback.cpp
content/media/wmf/WMFSourceReaderCallback.h
content/media/wmf/WMFUtils.cpp
content/media/wmf/WMFUtils.h
dom/media/tests/mochitest/head.js
dom/media/tests/mochitest/mediaStreamPlayback.js
dom/media/tests/mochitest/pc.js
editor/libeditor/base/EditActionListener.h
extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/dupe-dictionary.pl
gfx/2d/genshaders.sh
gfx/2d/unittest/SanityChecks.cpp
gfx/2d/unittest/SanityChecks.h
gfx/2d/unittest/TestBase.cpp
gfx/2d/unittest/TestDrawTargetBase.cpp
gfx/2d/unittest/TestDrawTargetBase.h
gfx/2d/unittest/TestDrawTargetD2D.cpp
gfx/2d/unittest/TestDrawTargetD2D.h
gfx/2d/unittest/TestPoint.cpp
gfx/2d/unittest/TestPoint.h
gfx/2d/unittest/TestScaling.cpp
gfx/2d/unittest/TestScaling.h
js/src/tests/test262/shell.js
js/xpconnect/tests/unit/test_bug451678.js
mobile/android/base/resources/layout/notification_progress.xml
mobile/android/base/resources/layout/notification_progress_text.xml
mobile/android/base/sync/jpake/stage/DecryptDataStage.java
mobile/android/branding/aurora/locales/en-US/brand.dtd
mobile/android/branding/aurora/locales/en-US/brand.properties
mobile/android/branding/beta/locales/en-US/brand.dtd
mobile/android/branding/beta/locales/en-US/brand.properties
mobile/android/branding/nightly/locales/en-US/brand.dtd
mobile/android/branding/nightly/locales/en-US/brand.properties
mobile/android/branding/official/locales/en-US/brand.dtd
mobile/android/branding/official/locales/en-US/brand.properties
mozglue/build/fixcrt.py
netwerk/base/src/AutoClose.h
python/mozbuild/mozbuild/action/xpccheck.py
security/manager/ssl/src/PSMRunnable.cpp
security/manager/ssl/src/PSMRunnable.h
security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
storage/test/unit/test_bug-429521.js
testing/marionette/client/marionette/www/javascriptPage.html
testing/tools/proxyserver/proxyserver.py
testing/tps/pages/page1.html
testing/tps/pages/page2.html
testing/tps/pages/page3.html
testing/tps/pages/page4.html
testing/tps/pages/page5.html
testing/xpcshell/example/unit/test_sample.js
toolkit/components/places/ClusterLib.js
toolkit/components/places/ColorConversion.js
toolkit/components/places/tests/bookmarks/test_818584-discard-duplicate-backups.js
toolkit/components/places/tests/bookmarks/test_818587_compress-bookmarks-backups.js
toolkit/components/places/tests/bookmarks/test_992901-backup-unsorted-hierarchy.js
toolkit/components/places/tests/bookmarks/test_997030-bookmarks-html-encode.js
toolkit/components/social/test/browser/browser_frameworker_sandbox.js
toolkit/content/aboutAbout.js
toolkit/crashreporter/InjectCrashReporter.cpp
toolkit/crashreporter/InjectCrashReporter.h
toolkit/crashreporter/LoadLibraryRemote.cpp
toolkit/crashreporter/LoadLibraryRemote.h
toolkit/crashreporter/client/crashreporter.rc
toolkit/crashreporter/injector/injector.cpp
toolkit/devtools/acorn/moz.build
toolkit/locales/en-US/chrome/global/webapps.properties
toolkit/modules/PermissionsUtils.jsm
toolkit/modules/WindowsRegistry.jsm
toolkit/mozapps/downloads/tests/chrome/test_bug_429247.xul
toolkit/mozapps/extensions/internal/moz.build
toolkit/themes/windows/global/arrow/panelarrow-horizontal-themed.svg
toolkit/themes/windows/global/arrow/panelarrow-vertical-themed.svg
webapprt/gtk/webapprt.cpp
widget/tests/chrome_context_menus_win.xul
widget/tests/test_chrome_context_menus_win.xul
widget/windows/nsColorPicker.cpp
widget/windows/nsColorPicker.h
widget/windows/winrt/WakeLockListener.h
widget/xpwidgets/ContentHelper.cpp
widget/xpwidgets/ContentHelper.h
xpcom/build/PoisonIOInterposer.h
xpcom/build/PoisonIOInterposerWin.cpp
xpcom/components/ManifestParser.h
xpcom/glue/nsClassInfoImpl.cpp
xpcom/tests/unit/test_bug725015.js
xpcom/threads/HangMonitor.h
xulrunner/app/install_app.py
--- a/browser/base/content/test/chat/browser_chatwindow.js
+++ b/browser/base/content/test/chat/browser_chatwindow.js
@@ -1,135 +1,135 @@
-/* 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/. */
-
-let chatbar = document.getElementById("pinnedchats");
-
-add_chat_task(function* testOpenCloseChat() {
-  let chatbox = yield promiseOpenChat("http://example.com");
-  Assert.strictEqual(chatbox, chatbar.selectedChat);
-  // we requested a "normal" chat, so shouldn't be minimized
-  Assert.ok(!chatbox.minimized, "chat is not minimized");
-  Assert.equal(chatbar.childNodes.length, 1, "should be 1 chat open");
-
-
-  // now request the same URL again - we should get the same chat.
-  let chatbox2 = yield promiseOpenChat("http://example.com");
-  Assert.strictEqual(chatbox2, chatbox, "got the same chat");
-  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
-
-  chatbox.toggle();
-  is(chatbox.minimized, true, "chat is now minimized");
-  // was no other chat to select, so selected becomes null.
-  is(chatbar.selectedChat, null);
-
-  // We check the content gets an unload event as we close it.
-  let promiseClosed = promiseOneEvent(chatbox.content, "unload", true);
-  chatbox.close();
-  yield promiseClosed;
-});
-
-// In this case we open a chat minimized, then request the same chat again
-// without specifying minimized.  On that second call the chat should open,
-// selected, and no longer minimized.
-add_chat_task(function* testMinimized() {
-  let chatbox = yield promiseOpenChat("http://example.com", "minimized");
-  Assert.strictEqual(chatbox, chatbar.selectedChat);
-  Assert.ok(chatbox.minimized, "chat is minimized");
-  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
-  yield promiseOpenChat("http://example.com");
-  Assert.ok(!chatbox.minimized, false, "chat is no longer minimized");
-});
-
-// open enough chats to overflow the window, then check
-// if the menupopup is visible
-add_chat_task(function* testManyChats() {
-  Assert.ok(chatbar.menupopup.parentNode.collapsed, "popup nub collapsed at start");
-  // we should *never* find a test box that needs more than this to cause
-  // an overflow!
-  let maxToOpen = 20;
-  let numOpened = 0;
-  for (let i = 0; i < maxToOpen; i++) {
-    yield promiseOpenChat("http://example.com#" + i);
-    if (!chatbar.menupopup.parentNode.collapsed) {
-      info("the menu popup appeared");
-      return;
-    }
-  }
-  Assert.ok(false, "We didn't find a collapsed chat after " + maxToOpen + "chats!");
-});
-
-// Check that closeAll works as expected.
-add_chat_task(function* testOpenTwiceCallbacks() {
-  yield promiseOpenChat("http://example.com#1");
-  yield promiseOpenChat("http://example.com#2");
-  yield promiseOpenChat("http://test2.example.com");
-  Assert.equal(numChatsInWindow(window), 3, "should be 3 chats open");
-  Chat.closeAll("http://example.com");
-  Assert.equal(numChatsInWindow(window), 1, "should have closed 2 chats");
-  Chat.closeAll("http://test2.example.com");
-  Assert.equal(numChatsInWindow(window), 0, "should have closed last chat");
-});
-
-// Check that when we open the same chat twice, the callbacks are called back
-// twice.
-add_chat_task(function* testOpenTwiceCallbacks() {
-  yield promiseOpenChatCallback("http://example.com");
-  yield promiseOpenChatCallback("http://example.com");
-});
-
-// Bug 817782 - check chats work in new top-level windows.
-add_chat_task(function* testSecondTopLevelWindow() {
-  const chatUrl = "http://example.com";
-  let secondWindow = OpenBrowserWindow();
-  yield promiseOneEvent(secondWindow, "load");
-  yield promiseOpenChat(chatUrl);
-  // the chat was created - let's make sure it was created in the second window.
-  Assert.equal(numChatsInWindow(window), 0, "main window has no chats");
-  Assert.equal(numChatsInWindow(secondWindow), 1, "second window has 1 chat");
-  secondWindow.close();
-});
-
-// Test that chats are created in the correct window.
-add_chat_task(function* testChatWindowChooser() {
-  let chat = yield promiseOpenChat("http://example.com");
-  Assert.equal(numChatsInWindow(window), 1, "first window has the chat");
-  // create a second window - this will be the "most recent" and will
-  // therefore be the window that hosts the new chat (see bug 835111)
-  let secondWindow = OpenBrowserWindow();
-  yield promiseOneEvent(secondWindow, "load");
-  Assert.equal(numChatsInWindow(secondWindow), 0, "second window starts with no chats");
-  yield promiseOpenChat("http://example.com#2");
-  Assert.equal(numChatsInWindow(secondWindow), 1, "second window now has chats");
-  Assert.equal(numChatsInWindow(window), 1, "first window still has 1 chat");
-  chat.close();
-  Assert.equal(numChatsInWindow(window), 0, "first window now has no chats");
-  // now open another chat - it should still open in the second.
-  yield promiseOpenChat("http://example.com#3");
-  Assert.equal(numChatsInWindow(window), 0, "first window still has no chats");
-  Assert.equal(numChatsInWindow(secondWindow), 2, "second window has both chats");
-
-  // focus the first window, and open yet another chat - it
-  // should open in the first window.
-  window.focus();
-  yield promiseWaitForFocus();
-  chat = yield promiseOpenChat("http://example.com#4");
-  Assert.equal(numChatsInWindow(window), 1, "first window got new chat");
-  chat.close();
-  Assert.equal(numChatsInWindow(window), 0, "first window has no chats");
-
-  let privateWindow = OpenBrowserWindow({private: true});
-  yield promiseOneEvent(privateWindow, "load")
-
-  // open a last chat - the focused window can't accept
-  // chats (it's a private window), so the chat should open
-  // in the window that was selected before. This is known
-  // to be broken on Linux.
-  chat = yield promiseOpenChat("http://example.com#5");
-  let os = Services.appinfo.OS;
-  const BROKEN_WM_Z_ORDER = os != "WINNT" && os != "Darwin";
-  let fn = BROKEN_WM_Z_ORDER ? todo : ok;
-  fn(numChatsInWindow(window) == 1, "first window got the chat");
-  chat.close();
-  privateWindow.close();
-  secondWindow.close();
-});
+/* 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/. */
+
+let chatbar = document.getElementById("pinnedchats");
+
+add_chat_task(function* testOpenCloseChat() {
+  let chatbox = yield promiseOpenChat("http://example.com");
+  Assert.strictEqual(chatbox, chatbar.selectedChat);
+  // we requested a "normal" chat, so shouldn't be minimized
+  Assert.ok(!chatbox.minimized, "chat is not minimized");
+  Assert.equal(chatbar.childNodes.length, 1, "should be 1 chat open");
+
+
+  // now request the same URL again - we should get the same chat.
+  let chatbox2 = yield promiseOpenChat("http://example.com");
+  Assert.strictEqual(chatbox2, chatbox, "got the same chat");
+  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+
+  chatbox.toggle();
+  is(chatbox.minimized, true, "chat is now minimized");
+  // was no other chat to select, so selected becomes null.
+  is(chatbar.selectedChat, null);
+
+  // We check the content gets an unload event as we close it.
+  let promiseClosed = promiseOneEvent(chatbox.content, "unload", true);
+  chatbox.close();
+  yield promiseClosed;
+});
+
+// In this case we open a chat minimized, then request the same chat again
+// without specifying minimized.  On that second call the chat should open,
+// selected, and no longer minimized.
+add_chat_task(function* testMinimized() {
+  let chatbox = yield promiseOpenChat("http://example.com", "minimized");
+  Assert.strictEqual(chatbox, chatbar.selectedChat);
+  Assert.ok(chatbox.minimized, "chat is minimized");
+  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+  yield promiseOpenChat("http://example.com");
+  Assert.ok(!chatbox.minimized, false, "chat is no longer minimized");
+});
+
+// open enough chats to overflow the window, then check
+// if the menupopup is visible
+add_chat_task(function* testManyChats() {
+  Assert.ok(chatbar.menupopup.parentNode.collapsed, "popup nub collapsed at start");
+  // we should *never* find a test box that needs more than this to cause
+  // an overflow!
+  let maxToOpen = 20;
+  let numOpened = 0;
+  for (let i = 0; i < maxToOpen; i++) {
+    yield promiseOpenChat("http://example.com#" + i);
+    if (!chatbar.menupopup.parentNode.collapsed) {
+      info("the menu popup appeared");
+      return;
+    }
+  }
+  Assert.ok(false, "We didn't find a collapsed chat after " + maxToOpen + "chats!");
+});
+
+// Check that closeAll works as expected.
+add_chat_task(function* testOpenTwiceCallbacks() {
+  yield promiseOpenChat("http://example.com#1");
+  yield promiseOpenChat("http://example.com#2");
+  yield promiseOpenChat("http://test2.example.com");
+  Assert.equal(numChatsInWindow(window), 3, "should be 3 chats open");
+  Chat.closeAll("http://example.com");
+  Assert.equal(numChatsInWindow(window), 1, "should have closed 2 chats");
+  Chat.closeAll("http://test2.example.com");
+  Assert.equal(numChatsInWindow(window), 0, "should have closed last chat");
+});
+
+// Check that when we open the same chat twice, the callbacks are called back
+// twice.
+add_chat_task(function* testOpenTwiceCallbacks() {
+  yield promiseOpenChatCallback("http://example.com");
+  yield promiseOpenChatCallback("http://example.com");
+});
+
+// Bug 817782 - check chats work in new top-level windows.
+add_chat_task(function* testSecondTopLevelWindow() {
+  const chatUrl = "http://example.com";
+  let secondWindow = OpenBrowserWindow();
+  yield promiseOneEvent(secondWindow, "load");
+  yield promiseOpenChat(chatUrl);
+  // the chat was created - let's make sure it was created in the second window.
+  Assert.equal(numChatsInWindow(window), 0, "main window has no chats");
+  Assert.equal(numChatsInWindow(secondWindow), 1, "second window has 1 chat");
+  secondWindow.close();
+});
+
+// Test that chats are created in the correct window.
+add_chat_task(function* testChatWindowChooser() {
+  let chat = yield promiseOpenChat("http://example.com");
+  Assert.equal(numChatsInWindow(window), 1, "first window has the chat");
+  // create a second window - this will be the "most recent" and will
+  // therefore be the window that hosts the new chat (see bug 835111)
+  let secondWindow = OpenBrowserWindow();
+  yield promiseOneEvent(secondWindow, "load");
+  Assert.equal(numChatsInWindow(secondWindow), 0, "second window starts with no chats");
+  yield promiseOpenChat("http://example.com#2");
+  Assert.equal(numChatsInWindow(secondWindow), 1, "second window now has chats");
+  Assert.equal(numChatsInWindow(window), 1, "first window still has 1 chat");
+  chat.close();
+  Assert.equal(numChatsInWindow(window), 0, "first window now has no chats");
+  // now open another chat - it should still open in the second.
+  yield promiseOpenChat("http://example.com#3");
+  Assert.equal(numChatsInWindow(window), 0, "first window still has no chats");
+  Assert.equal(numChatsInWindow(secondWindow), 2, "second window has both chats");
+
+  // focus the first window, and open yet another chat - it
+  // should open in the first window.
+  window.focus();
+  yield promiseWaitForFocus();
+  chat = yield promiseOpenChat("http://example.com#4");
+  Assert.equal(numChatsInWindow(window), 1, "first window got new chat");
+  chat.close();
+  Assert.equal(numChatsInWindow(window), 0, "first window has no chats");
+
+  let privateWindow = OpenBrowserWindow({private: true});
+  yield promiseOneEvent(privateWindow, "load")
+
+  // open a last chat - the focused window can't accept
+  // chats (it's a private window), so the chat should open
+  // in the window that was selected before. This is known
+  // to be broken on Linux.
+  chat = yield promiseOpenChat("http://example.com#5");
+  let os = Services.appinfo.OS;
+  const BROKEN_WM_Z_ORDER = os != "WINNT" && os != "Darwin";
+  let fn = BROKEN_WM_Z_ORDER ? todo : ok;
+  fn(numChatsInWindow(window) == 1, "first window got the chat");
+  chat.close();
+  privateWindow.close();
+  secondWindow.close();
+});
--- a/browser/base/content/test/chat/browser_focus.js
+++ b/browser/base/content/test/chat/browser_focus.js
@@ -1,230 +1,230 @@
-/* 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/. */
-
-// Tests the focus functionality.
-
-const CHAT_URL = "https://example.com/browser/browser/base/content/test/chat/chat.html";
-
-// Is the currently opened tab focused?
-function isTabFocused() {
-  let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
-  return Services.focus.focusedWindow == tabb.contentWindow;
-}
-
-// Is the specified chat focused?
-function isChatFocused(chat) {
-  return chat.chatbar._isChatFocused(chat);
-}
-
-let chatbar = document.getElementById("pinnedchats");
-
-function* setUp() {
-  // Note that (probably) due to bug 604289, if a tab is focused but the
-  // focused element is null, our chat windows can "steal" focus.  This is
-  // avoided if we explicitly focus an element in the tab.
-  // So we load a page with an <input> field and focus that before testing.
-  let html = '<input id="theinput"><button id="chat-opener"></button>';
-  let url = "data:text/html;charset=utf-8," + encodeURI(html);
-  let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true});
-  yield promiseOneEvent(tab.linkedBrowser, "load", true);
-  tab.linkedBrowser.contentDocument.getElementById("theinput").focus();
-  registerCleanupFunction(function() {
-    gBrowser.removeTab(tab);
-  });
-}
-
-// Test default focus - not user input.
-add_chat_task(function* testDefaultFocus() {
-  yield setUp();
-  let chat = yield promiseOpenChat("http://example.com");
-  // we used the default focus behaviour, which means that because this was
-  // not the direct result of user action the chat should not be focused.
-  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
-  Assert.ok(isTabFocused(), "the tab should remain focused.");
-  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
-});
-
-// Test default focus via user input.
-add_chat_task(function* testDefaultFocus() {
-  yield setUp();
-  let tab = gBrowser.selectedTab;
-  let deferred = Promise.defer();
-  let button = tab.linkedBrowser.contentDocument.getElementById("chat-opener");
-  button.addEventListener("click", function onclick() {
-    button.removeEventListener("click", onclick);
-    promiseOpenChat("http://example.com").then(
-      chat => deferred.resolve(chat)
-    );
-  })
-  // Note we must use synthesizeMouseAtCenter() rather than calling
-  // .click() directly as this causes nsIDOMWindowUtils.isHandlingUserInput
-  // to be true.
-  EventUtils.synthesizeMouseAtCenter(button, {}, button.ownerDocument.defaultView);
-  let chat = yield deferred.promise;
-
-  // we use the default focus behaviour but the chat was opened via user input,
-  // so the chat should be focused.
-  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
-  Assert.ok(!isTabFocused(), "the tab should have lost focus.");
-  Assert.ok(isChatFocused(chat), "the chat should have got focus.");
-});
-
-// We explicitly ask for the chat to be focused.
-add_chat_task(function* testExplicitFocus() {
-  yield setUp();
-  let chat = yield promiseOpenChat("http://example.com", undefined, true);
-  // we use the default focus behaviour, which means that because this was
-  // not the direct result of user action the chat should not be focused.
-  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
-  Assert.ok(!isTabFocused(), "the tab should have lost focus.");
-  Assert.ok(isChatFocused(chat), "the chat should have got focus.");
-});
-
-// Open a minimized chat via default focus behaviour - it will open and not
-// have focus.  Then open the same chat without 'minimized' - it will be
-// restored but should still not have grabbed focus.
-add_chat_task(function* testNoFocusOnAutoRestore() {
-  yield setUp();
-  let chat = yield promiseOpenChat("http://example.com", "minimized");
-  Assert.ok(chat.minimized, "chat is minimized");
-  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
-  Assert.ok(isTabFocused(), "the tab should remain focused.");
-  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
-  yield promiseOpenChat("http://example.com");
-  Assert.ok(!chat.minimized, "chat should be restored");
-  Assert.ok(isTabFocused(), "the tab should remain focused.");
-  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
-});
-
-// Here we open a chat, which will not be focused.  Then we minimize it and
-// restore it via a titlebar clock - it should get focus at that point.
-add_chat_task(function* testFocusOnExplicitRestore() {
-  yield setUp();
-  let chat = yield promiseOpenChat("http://example.com");
-  Assert.ok(!chat.minimized, "chat should have been opened restored");
-  Assert.ok(isTabFocused(), "the tab should remain focused.");
-  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
-  chat.minimized = true;
-  Assert.ok(isTabFocused(), "tab should still be focused");
-  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
-
-  let promise = promiseOneEvent(chat.contentWindow, "focus");
-  // pretend we clicked on the titlebar
-  chat.onTitlebarClick({button: 0});
-  yield promise; // wait for focus event.
-  Assert.ok(!chat.minimized, "chat should have been restored");
-  Assert.ok(isChatFocused(chat), "chat should be focused");
-  Assert.strictEqual(chat, chatbar.selectedChat, "chat is marked selected");
-});
-
-// Open 2 chats and give 1 focus.  Minimize the focused one - the second
-// should get focus.
-add_chat_task(function* testMinimizeFocused() {
-  yield setUp();
-  let chat1 = yield promiseOpenChat("http://example.com#1");
-  let chat2 = yield promiseOpenChat("http://example.com#2");
-  Assert.equal(numChatsInWindow(window), 2, "2 chats open");
-  Assert.strictEqual(chatbar.selectedChat, chat2, "chat2 is selected");
-  let promise = promiseOneEvent(chat1.contentWindow, "focus");
-  chatbar.selectedChat = chat1;
-  chatbar.focus();
-  yield promise; // wait for chat1 to get focus.
-  Assert.strictEqual(chat1, chatbar.selectedChat, "chat1 is marked selected");
-  Assert.notStrictEqual(chat2, chatbar.selectedChat, "chat2 is not marked selected");
-  promise = promiseOneEvent(chat2.contentWindow, "focus");
-  chat1.minimized = true;
-  yield promise; // wait for chat2 to get focus.
-  Assert.notStrictEqual(chat1, chatbar.selectedChat, "chat1 is not marked selected");
-  Assert.strictEqual(chat2, chatbar.selectedChat, "chat2 is marked selected");
-});
-
-// Open 2 chats, select and focus the second.  Pressing the TAB key should
-// cause focus to move between all elements in our chat window before moving
-// to the next chat window.
-add_chat_task(function* testTab() {
-  yield setUp();
-
-  function sendTabAndWaitForFocus(chat, eltid) {
-    let doc = chat.contentDocument;
-    EventUtils.sendKey("tab");
-    // ideally we would use the 'focus' event here, but that doesn't work
-    // as expected for the iframe - the iframe itself never gets the focus
-    // event (apparently the sub-document etc does.)
-    // So just poll for the correct element getting focus...
-    let deferred = Promise.defer();
-    let tries = 0;
-    let interval = setInterval(function() {
-      if (tries >= 30) {
-        clearInterval(interval);
-        deferred.reject("never got focus");
-        return;
-      }
-      tries ++;
-      let elt = eltid ? doc.getElementById(eltid) : doc.documentElement;
-      if (doc.activeElement == elt) {
-        clearInterval(interval);
-        deferred.resolve();
-      }
-      info("retrying wait for focus: " + tries);
-      info("(the active element is " + doc.activeElement + "/" + doc.activeElement.getAttribute("id") + ")");
-    }, 100);
-    info("waiting for element " + eltid + " to get focus");
-    return deferred.promise;
-  }
-
-  let chat1 = yield promiseOpenChat(CHAT_URL + "#1");
-  let chat2 = yield promiseOpenChat(CHAT_URL + "#2");
-  chatbar.selectedChat = chat2;
-  let promise = promiseOneEvent(chat2.contentWindow, "focus");
-  chatbar.focus();
-  info("waiting for second chat to get focus");
-  yield promise;
-
-  // Our chats have 3 focusable elements, so it takes 4 TABs to move
-  // to the new chat.
-  yield sendTabAndWaitForFocus(chat2, "input1");
-  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input1",
-               "first input field has focus");
-  Assert.ok(isChatFocused(chat2), "new chat still focused after first tab");
-
-  yield sendTabAndWaitForFocus(chat2, "input2");
-  Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
-  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input2",
-               "second input field has focus");
-
-  yield sendTabAndWaitForFocus(chat2, "iframe");
-  Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
-  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "iframe",
-               "iframe has focus");
-
-  // this tab now should move to the next chat, but focus the
-  // document element itself (hence the null eltid)
-  yield sendTabAndWaitForFocus(chat1, null);
-  Assert.ok(isChatFocused(chat1), "first chat is focused");
-});
-
-// Open a chat and focus an element other than the first. Move focus to some
-// other item (the tab itself in this case), then focus the chatbar - the
-// same element that was previously focused should still have focus.
-add_chat_task(function* testFocusedElement() {
-  yield setUp();
-
-  // open a chat with focus requested.
-  let chat = yield promiseOpenChat(CHAT_URL, undefined, true);
-
-  chat.contentDocument.getElementById("input2").focus();
-
-  // set focus to the tab.
-  let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
-  let promise = promiseOneEvent(tabb.contentWindow, "focus");
-  Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
-  yield promise;
-
-  promise = promiseOneEvent(chat.contentWindow, "focus");
-  chatbar.focus();
-  yield promise;
-
-  Assert.equal(chat.contentDocument.activeElement.getAttribute("id"), "input2",
-               "correct input field still has focus");
-});
+/* 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/. */
+
+// Tests the focus functionality.
+
+const CHAT_URL = "https://example.com/browser/browser/base/content/test/chat/chat.html";
+
+// Is the currently opened tab focused?
+function isTabFocused() {
+  let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+  return Services.focus.focusedWindow == tabb.contentWindow;
+}
+
+// Is the specified chat focused?
+function isChatFocused(chat) {
+  return chat.chatbar._isChatFocused(chat);
+}
+
+let chatbar = document.getElementById("pinnedchats");
+
+function* setUp() {
+  // Note that (probably) due to bug 604289, if a tab is focused but the
+  // focused element is null, our chat windows can "steal" focus.  This is
+  // avoided if we explicitly focus an element in the tab.
+  // So we load a page with an <input> field and focus that before testing.
+  let html = '<input id="theinput"><button id="chat-opener"></button>';
+  let url = "data:text/html;charset=utf-8," + encodeURI(html);
+  let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true});
+  yield promiseOneEvent(tab.linkedBrowser, "load", true);
+  tab.linkedBrowser.contentDocument.getElementById("theinput").focus();
+  registerCleanupFunction(function() {
+    gBrowser.removeTab(tab);
+  });
+}
+
+// Test default focus - not user input.
+add_chat_task(function* testDefaultFocus() {
+  yield setUp();
+  let chat = yield promiseOpenChat("http://example.com");
+  // we used the default focus behaviour, which means that because this was
+  // not the direct result of user action the chat should not be focused.
+  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+  Assert.ok(isTabFocused(), "the tab should remain focused.");
+  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
+});
+
+// Test default focus via user input.
+add_chat_task(function* testDefaultFocus() {
+  yield setUp();
+  let tab = gBrowser.selectedTab;
+  let deferred = Promise.defer();
+  let button = tab.linkedBrowser.contentDocument.getElementById("chat-opener");
+  button.addEventListener("click", function onclick() {
+    button.removeEventListener("click", onclick);
+    promiseOpenChat("http://example.com").then(
+      chat => deferred.resolve(chat)
+    );
+  })
+  // Note we must use synthesizeMouseAtCenter() rather than calling
+  // .click() directly as this causes nsIDOMWindowUtils.isHandlingUserInput
+  // to be true.
+  EventUtils.synthesizeMouseAtCenter(button, {}, button.ownerDocument.defaultView);
+  let chat = yield deferred.promise;
+
+  // we use the default focus behaviour but the chat was opened via user input,
+  // so the chat should be focused.
+  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+  Assert.ok(!isTabFocused(), "the tab should have lost focus.");
+  Assert.ok(isChatFocused(chat), "the chat should have got focus.");
+});
+
+// We explicitly ask for the chat to be focused.
+add_chat_task(function* testExplicitFocus() {
+  yield setUp();
+  let chat = yield promiseOpenChat("http://example.com", undefined, true);
+  // we use the default focus behaviour, which means that because this was
+  // not the direct result of user action the chat should not be focused.
+  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+  Assert.ok(!isTabFocused(), "the tab should have lost focus.");
+  Assert.ok(isChatFocused(chat), "the chat should have got focus.");
+});
+
+// Open a minimized chat via default focus behaviour - it will open and not
+// have focus.  Then open the same chat without 'minimized' - it will be
+// restored but should still not have grabbed focus.
+add_chat_task(function* testNoFocusOnAutoRestore() {
+  yield setUp();
+  let chat = yield promiseOpenChat("http://example.com", "minimized");
+  Assert.ok(chat.minimized, "chat is minimized");
+  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+  Assert.ok(isTabFocused(), "the tab should remain focused.");
+  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
+  yield promiseOpenChat("http://example.com");
+  Assert.ok(!chat.minimized, "chat should be restored");
+  Assert.ok(isTabFocused(), "the tab should remain focused.");
+  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
+});
+
+// Here we open a chat, which will not be focused.  Then we minimize it and
+// restore it via a titlebar clock - it should get focus at that point.
+add_chat_task(function* testFocusOnExplicitRestore() {
+  yield setUp();
+  let chat = yield promiseOpenChat("http://example.com");
+  Assert.ok(!chat.minimized, "chat should have been opened restored");
+  Assert.ok(isTabFocused(), "the tab should remain focused.");
+  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
+  chat.minimized = true;
+  Assert.ok(isTabFocused(), "tab should still be focused");
+  Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
+
+  let promise = promiseOneEvent(chat.contentWindow, "focus");
+  // pretend we clicked on the titlebar
+  chat.onTitlebarClick({button: 0});
+  yield promise; // wait for focus event.
+  Assert.ok(!chat.minimized, "chat should have been restored");
+  Assert.ok(isChatFocused(chat), "chat should be focused");
+  Assert.strictEqual(chat, chatbar.selectedChat, "chat is marked selected");
+});
+
+// Open 2 chats and give 1 focus.  Minimize the focused one - the second
+// should get focus.
+add_chat_task(function* testMinimizeFocused() {
+  yield setUp();
+  let chat1 = yield promiseOpenChat("http://example.com#1");
+  let chat2 = yield promiseOpenChat("http://example.com#2");
+  Assert.equal(numChatsInWindow(window), 2, "2 chats open");
+  Assert.strictEqual(chatbar.selectedChat, chat2, "chat2 is selected");
+  let promise = promiseOneEvent(chat1.contentWindow, "focus");
+  chatbar.selectedChat = chat1;
+  chatbar.focus();
+  yield promise; // wait for chat1 to get focus.
+  Assert.strictEqual(chat1, chatbar.selectedChat, "chat1 is marked selected");
+  Assert.notStrictEqual(chat2, chatbar.selectedChat, "chat2 is not marked selected");
+  promise = promiseOneEvent(chat2.contentWindow, "focus");
+  chat1.minimized = true;
+  yield promise; // wait for chat2 to get focus.
+  Assert.notStrictEqual(chat1, chatbar.selectedChat, "chat1 is not marked selected");
+  Assert.strictEqual(chat2, chatbar.selectedChat, "chat2 is marked selected");
+});
+
+// Open 2 chats, select and focus the second.  Pressing the TAB key should
+// cause focus to move between all elements in our chat window before moving
+// to the next chat window.
+add_chat_task(function* testTab() {
+  yield setUp();
+
+  function sendTabAndWaitForFocus(chat, eltid) {
+    let doc = chat.contentDocument;
+    EventUtils.sendKey("tab");
+    // ideally we would use the 'focus' event here, but that doesn't work
+    // as expected for the iframe - the iframe itself never gets the focus
+    // event (apparently the sub-document etc does.)
+    // So just poll for the correct element getting focus...
+    let deferred = Promise.defer();
+    let tries = 0;
+    let interval = setInterval(function() {
+      if (tries >= 30) {
+        clearInterval(interval);
+        deferred.reject("never got focus");
+        return;
+      }
+      tries ++;
+      let elt = eltid ? doc.getElementById(eltid) : doc.documentElement;
+      if (doc.activeElement == elt) {
+        clearInterval(interval);
+        deferred.resolve();
+      }
+      info("retrying wait for focus: " + tries);
+      info("(the active element is " + doc.activeElement + "/" + doc.activeElement.getAttribute("id") + ")");
+    }, 100);
+    info("waiting for element " + eltid + " to get focus");
+    return deferred.promise;
+  }
+
+  let chat1 = yield promiseOpenChat(CHAT_URL + "#1");
+  let chat2 = yield promiseOpenChat(CHAT_URL + "#2");
+  chatbar.selectedChat = chat2;
+  let promise = promiseOneEvent(chat2.contentWindow, "focus");
+  chatbar.focus();
+  info("waiting for second chat to get focus");
+  yield promise;
+
+  // Our chats have 3 focusable elements, so it takes 4 TABs to move
+  // to the new chat.
+  yield sendTabAndWaitForFocus(chat2, "input1");
+  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input1",
+               "first input field has focus");
+  Assert.ok(isChatFocused(chat2), "new chat still focused after first tab");
+
+  yield sendTabAndWaitForFocus(chat2, "input2");
+  Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
+  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input2",
+               "second input field has focus");
+
+  yield sendTabAndWaitForFocus(chat2, "iframe");
+  Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
+  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "iframe",
+               "iframe has focus");
+
+  // this tab now should move to the next chat, but focus the
+  // document element itself (hence the null eltid)
+  yield sendTabAndWaitForFocus(chat1, null);
+  Assert.ok(isChatFocused(chat1), "first chat is focused");
+});
+
+// Open a chat and focus an element other than the first. Move focus to some
+// other item (the tab itself in this case), then focus the chatbar - the
+// same element that was previously focused should still have focus.
+add_chat_task(function* testFocusedElement() {
+  yield setUp();
+
+  // open a chat with focus requested.
+  let chat = yield promiseOpenChat(CHAT_URL, undefined, true);
+
+  chat.contentDocument.getElementById("input2").focus();
+
+  // set focus to the tab.
+  let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+  let promise = promiseOneEvent(tabb.contentWindow, "focus");
+  Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
+  yield promise;
+
+  promise = promiseOneEvent(chat.contentWindow, "focus");
+  chatbar.focus();
+  yield promise;
+
+  Assert.equal(chat.contentDocument.activeElement.getAttribute("id"), "input2",
+               "correct input field still has focus");
+});
--- a/browser/base/content/test/chat/browser_tearoff.js
+++ b/browser/base/content/test/chat/browser_tearoff.js
@@ -1,128 +1,128 @@
-/* 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/. */
-
-let chatbar = document.getElementById("pinnedchats");
-
-function promiseNewWindowLoaded() {
-  let deferred = Promise.defer();
-  Services.wm.addListener({
-    onWindowTitleChange: function() {},
-    onCloseWindow: function(xulwindow) {},
-    onOpenWindow: function(xulwindow) {
-      var domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                            .getInterface(Components.interfaces.nsIDOMWindow);
-      Services.wm.removeListener(this);
-      // wait for load to ensure the window is ready for us to test
-      domwindow.addEventListener("load", function _load(event) {
-        let doc = domwindow.document;
-        if (event.target != doc)
-            return;
-        domwindow.removeEventListener("load", _load);
-        deferred.resolve(domwindow);
-      });
-    },
-  });
-  return deferred.promise;
-}
-
-add_chat_task(function* testTearoffChat() {
-  let chatbox = yield promiseOpenChat("http://example.com");
-  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
-
-  let chatDoc = chatbox.contentDocument;
-  let chatTitle = chatDoc.title;
-
-  Assert.equal(chatbox.getAttribute("label"), chatTitle,
-               "the new chatbox should show the title of the chat window");
-
-  // mutate the chat document a bit before we tear it off.
-  let div = chatDoc.createElement("div");
-  div.setAttribute("id", "testdiv");
-  div.setAttribute("test", "1");
-  chatDoc.body.appendChild(div);
-
-  // chatbox is open, lets detach. The new chat window will be caught in
-  // the window watcher below
-  let promise = promiseNewWindowLoaded();
-
-  let swap = document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
-  swap.click();
-
-  // and wait for the new window.
-  let domwindow = yield promise;
-
-  Assert.equal(domwindow.document.documentElement.getAttribute("windowtype"), "Social:Chat", "Social:Chat window opened");
-  Assert.equal(numChatsInWindow(window), 0, "should be no chats in the chat bar");
-
-  // get the chatbox from the new window.
-  chatbox = domwindow.document.getElementById("chatter")
-  Assert.equal(chatbox.getAttribute("label"), chatTitle, "window should have same title as chat");
-
-  div = chatbox.contentDocument.getElementById("testdiv");
-  Assert.equal(div.getAttribute("test"), "1", "docshell should have been swapped");
-  div.setAttribute("test", "2");
-
-  // swap the window back to the chatbar
-  promise = promiseOneEvent(domwindow, "unload");
-  swap = domwindow.document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
-  swap.click();
-
-  yield promise;
-
-  Assert.equal(numChatsInWindow(window), 1, "chat should be docked back in the window");
-  chatbox = chatbar.selectedChat;
-  Assert.equal(chatbox.getAttribute("label"), chatTitle,
-               "the new chatbox should show the title of the chat window again");
-
-  div = chatbox.contentDocument.getElementById("testdiv");
-  Assert.equal(div.getAttribute("test"), "2", "docshell should have been swapped");
-});
-
-// Similar test but with 2 chats.
-add_chat_task(function* testReattachTwice() {
-  let chatbox1 = yield promiseOpenChat("http://example.com#1");
-  let chatbox2 = yield promiseOpenChat("http://example.com#2");
-  Assert.equal(numChatsInWindow(window), 2, "both chats should be docked in the window");
-
-  info("chatboxes are open, detach from window");
-  let promise = promiseNewWindowLoaded();
-  document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
-  let domwindow1 = yield promise;
-  chatbox1 = domwindow1.document.getElementById("chatter");
-  Assert.equal(numChatsInWindow(window), 1, "only second chat should be docked in the window");
-
-  promise = promiseNewWindowLoaded();
-  document.getAnonymousElementByAttribute(chatbox2, "anonid", "swap").click();
-  let domwindow2 = yield promise;
-  chatbox2 = domwindow2.document.getElementById("chatter");
-  Assert.equal(numChatsInWindow(window), 0, "should be no docked chats");
-
-  promise = promiseOneEvent(domwindow2, "unload");
-  domwindow2.document.getAnonymousElementByAttribute(chatbox2, "anonid", "swap").click();
-  yield promise;
-  Assert.equal(numChatsInWindow(window), 1, "one chat should be docked back in the window");
-
-  promise = promiseOneEvent(domwindow1, "unload");
-  domwindow1.document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
-  yield promise;
-  Assert.equal(numChatsInWindow(window), 2, "both chats should be docked back in the window");
-});
-
-// Check that Chat.closeAll() also closes detached windows.
-add_chat_task(function* testCloseAll() {
-  let chatbox1 = yield promiseOpenChat("http://example.com#1");
-  let chatbox2 = yield promiseOpenChat("http://example.com#2");
-
-  let promise = promiseNewWindowLoaded();
-  document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
-  let domwindow = yield promise;
-  chatbox1 = domwindow.document.getElementById("chatter");
-
-  let promiseWindowUnload = promiseOneEvent(domwindow, "unload");
-
-  Assert.equal(numChatsInWindow(window), 1, "second chat should still be docked");
-  Chat.closeAll("http://example.com");
-  yield promiseWindowUnload;
-  Assert.equal(numChatsInWindow(window), 0, "should be no chats left");
-});
+/* 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/. */
+
+let chatbar = document.getElementById("pinnedchats");
+
+function promiseNewWindowLoaded() {
+  let deferred = Promise.defer();
+  Services.wm.addListener({
+    onWindowTitleChange: function() {},
+    onCloseWindow: function(xulwindow) {},
+    onOpenWindow: function(xulwindow) {
+      var domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                            .getInterface(Components.interfaces.nsIDOMWindow);
+      Services.wm.removeListener(this);
+      // wait for load to ensure the window is ready for us to test
+      domwindow.addEventListener("load", function _load(event) {
+        let doc = domwindow.document;
+        if (event.target != doc)
+            return;
+        domwindow.removeEventListener("load", _load);
+        deferred.resolve(domwindow);
+      });
+    },
+  });
+  return deferred.promise;
+}
+
+add_chat_task(function* testTearoffChat() {
+  let chatbox = yield promiseOpenChat("http://example.com");
+  Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+
+  let chatDoc = chatbox.contentDocument;
+  let chatTitle = chatDoc.title;
+
+  Assert.equal(chatbox.getAttribute("label"), chatTitle,
+               "the new chatbox should show the title of the chat window");
+
+  // mutate the chat document a bit before we tear it off.
+  let div = chatDoc.createElement("div");
+  div.setAttribute("id", "testdiv");
+  div.setAttribute("test", "1");
+  chatDoc.body.appendChild(div);
+
+  // chatbox is open, lets detach. The new chat window will be caught in
+  // the window watcher below
+  let promise = promiseNewWindowLoaded();
+
+  let swap = document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
+  swap.click();
+
+  // and wait for the new window.
+  let domwindow = yield promise;
+
+  Assert.equal(domwindow.document.documentElement.getAttribute("windowtype"), "Social:Chat", "Social:Chat window opened");
+  Assert.equal(numChatsInWindow(window), 0, "should be no chats in the chat bar");
+
+  // get the chatbox from the new window.
+  chatbox = domwindow.document.getElementById("chatter")
+  Assert.equal(chatbox.getAttribute("label"), chatTitle, "window should have same title as chat");
+
+  div = chatbox.contentDocument.getElementById("testdiv");
+  Assert.equal(div.getAttribute("test"), "1", "docshell should have been swapped");
+  div.setAttribute("test", "2");
+
+  // swap the window back to the chatbar
+  promise = promiseOneEvent(domwindow, "unload");
+  swap = domwindow.document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
+  swap.click();
+
+  yield promise;
+
+  Assert.equal(numChatsInWindow(window), 1, "chat should be docked back in the window");
+  chatbox = chatbar.selectedChat;
+  Assert.equal(chatbox.getAttribute("label"), chatTitle,
+               "the new chatbox should show the title of the chat window again");
+
+  div = chatbox.contentDocument.getElementById("testdiv");
+  Assert.equal(div.getAttribute("test"), "2", "docshell should have been swapped");
+});
+
+// Similar test but with 2 chats.
+add_chat_task(function* testReattachTwice() {
+  let chatbox1 = yield promiseOpenChat("http://example.com#1");
+  let chatbox2 = yield promiseOpenChat("http://example.com#2");
+  Assert.equal(numChatsInWindow(window), 2, "both chats should be docked in the window");
+
+  info("chatboxes are open, detach from window");
+  let promise = promiseNewWindowLoaded();
+  document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
+  let domwindow1 = yield promise;
+  chatbox1 = domwindow1.document.getElementById("chatter");
+  Assert.equal(numChatsInWindow(window), 1, "only second chat should be docked in the window");
+
+  promise = promiseNewWindowLoaded();
+  document.getAnonymousElementByAttribute(chatbox2, "anonid", "swap").click();
+  let domwindow2 = yield promise;
+  chatbox2 = domwindow2.document.getElementById("chatter");
+  Assert.equal(numChatsInWindow(window), 0, "should be no docked chats");
+
+  promise = promiseOneEvent(domwindow2, "unload");
+  domwindow2.document.getAnonymousElementByAttribute(chatbox2, "anonid", "swap").click();
+  yield promise;
+  Assert.equal(numChatsInWindow(window), 1, "one chat should be docked back in the window");
+
+  promise = promiseOneEvent(domwindow1, "unload");
+  domwindow1.document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
+  yield promise;
+  Assert.equal(numChatsInWindow(window), 2, "both chats should be docked back in the window");
+});
+
+// Check that Chat.closeAll() also closes detached windows.
+add_chat_task(function* testCloseAll() {
+  let chatbox1 = yield promiseOpenChat("http://example.com#1");
+  let chatbox2 = yield promiseOpenChat("http://example.com#2");
+
+  let promise = promiseNewWindowLoaded();
+  document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
+  let domwindow = yield promise;
+  chatbox1 = domwindow.document.getElementById("chatter");
+
+  let promiseWindowUnload = promiseOneEvent(domwindow, "unload");
+
+  Assert.equal(numChatsInWindow(window), 1, "second chat should still be docked");
+  Chat.closeAll("http://example.com");
+  yield promiseWindowUnload;
+  Assert.equal(numChatsInWindow(window), 0, "should be no chats left");
+});
--- a/browser/base/content/test/chat/head.js
+++ b/browser/base/content/test/chat/head.js
@@ -1,91 +1,91 @@
-/* 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/. */
-
-// Utility functions for Chat tests.
-
-let Chat = Cu.import("resource:///modules/Chat.jsm", {}).Chat;
-
-function promiseOpenChat(url, mode, focus) {
-  let uri = Services.io.newURI(url, null, null);
-  let origin = uri.prePath;
-  let title = origin;
-  let deferred = Promise.defer();
-  // we just through a few hoops to ensure the content document is fully
-  // loaded, otherwise tests that rely on that content may intermittently fail.
-  let callback = function(chatbox) {
-    if (chatbox.contentDocument.readyState == "complete") {
-      // already loaded.
-      deferred.resolve(chatbox);
-      return;
-    }
-    chatbox.addEventListener("load", function onload(event) {
-      if (event.target != chatbox.contentDocument || chatbox.contentDocument.location.href == "about:blank") {
-        return;
-      }
-      chatbox.removeEventListener("load", onload, true);
-      deferred.resolve(chatbox);
-    }, true);
-  }
-  let chatbox = Chat.open(null, origin, title, url, mode, focus, callback);
-  return deferred.promise;
-}
-
-// Opens a chat, returns a promise resolved when the chat callback fired.
-function promiseOpenChatCallback(url, mode) {
-  let uri = Services.io.newURI(url, null, null);
-  let origin = uri.prePath;
-  let title = origin;
-  let deferred = Promise.defer();
-  let callback = deferred.resolve;
-  Chat.open(null, origin, title, url, mode, undefined, callback);
-  return deferred.promise;
-}
-
-// Opens a chat, returns the chat window's promise which fires when the chat
-// starts loading.
-function promiseOneEvent(target, eventName, capture) {
-  let deferred = Promise.defer();
-  target.addEventListener(eventName, function handler(event) {
-    target.removeEventListener(eventName, handler, capture);
-    deferred.resolve();
-  }, capture);
-  return deferred.promise;
-}
-
-// Return the number of chats in a browser window.
-function numChatsInWindow(win) {
-  let chatbar = win.document.getElementById("pinnedchats");
-  return chatbar.childElementCount;
-}
-
-function promiseWaitForFocus() {
-  let deferred = Promise.defer();
-  waitForFocus(deferred.resolve);
-  return deferred.promise;
-}
-
-// A simple way to clean up after each test.
-function add_chat_task(genFunction) {
-  add_task(function* () {
-    info("Starting chat test " + genFunction.name);
-    try {
-      yield genFunction();
-    } finally {
-      info("Finished chat test " + genFunction.name + " - cleaning up.");
-      // close all docked chats.
-      while (chatbar.childNodes.length) {
-        chatbar.childNodes[0].close();
-      }
-      // and non-docked chats.
-      let winEnum = Services.wm.getEnumerator("Social:Chat");
-      while (winEnum.hasMoreElements()) {
-        let win = winEnum.getNext();
-        if (win.closed) {
-          continue;
-        }
-        win.close();
-      }
-    }
-  });
-}
+/* 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/. */
+
+// Utility functions for Chat tests.
+
+let Chat = Cu.import("resource:///modules/Chat.jsm", {}).Chat;
+
+function promiseOpenChat(url, mode, focus) {
+  let uri = Services.io.newURI(url, null, null);
+  let origin = uri.prePath;
+  let title = origin;
+  let deferred = Promise.defer();
+  // we just through a few hoops to ensure the content document is fully
+  // loaded, otherwise tests that rely on that content may intermittently fail.
+  let callback = function(chatbox) {
+    if (chatbox.contentDocument.readyState == "complete") {
+      // already loaded.
+      deferred.resolve(chatbox);
+      return;
+    }
+    chatbox.addEventListener("load", function onload(event) {
+      if (event.target != chatbox.contentDocument || chatbox.contentDocument.location.href == "about:blank") {
+        return;
+      }
+      chatbox.removeEventListener("load", onload, true);
+      deferred.resolve(chatbox);
+    }, true);
+  }
+  let chatbox = Chat.open(null, origin, title, url, mode, focus, callback);
+  return deferred.promise;
+}
+
+// Opens a chat, returns a promise resolved when the chat callback fired.
+function promiseOpenChatCallback(url, mode) {
+  let uri = Services.io.newURI(url, null, null);
+  let origin = uri.prePath;
+  let title = origin;
+  let deferred = Promise.defer();
+  let callback = deferred.resolve;
+  Chat.open(null, origin, title, url, mode, undefined, callback);
+  return deferred.promise;
+}
+
+// Opens a chat, returns the chat window's promise which fires when the chat
+// starts loading.
+function promiseOneEvent(target, eventName, capture) {
+  let deferred = Promise.defer();
+  target.addEventListener(eventName, function handler(event) {
+    target.removeEventListener(eventName, handler, capture);
+    deferred.resolve();
+  }, capture);
+  return deferred.promise;
+}
+
+// Return the number of chats in a browser window.
+function numChatsInWindow(win) {
+  let chatbar = win.document.getElementById("pinnedchats");
+  return chatbar.childElementCount;
+}
+
+function promiseWaitForFocus() {
+  let deferred = Promise.defer();
+  waitForFocus(deferred.resolve);
+  return deferred.promise;
+}
+
+// A simple way to clean up after each test.
+function add_chat_task(genFunction) {
+  add_task(function* () {
+    info("Starting chat test " + genFunction.name);
+    try {
+      yield genFunction();
+    } finally {
+      info("Finished chat test " + genFunction.name + " - cleaning up.");
+      // close all docked chats.
+      while (chatbar.childNodes.length) {
+        chatbar.childNodes[0].close();
+      }
+      // and non-docked chats.
+      let winEnum = Services.wm.getEnumerator("Social:Chat");
+      while (winEnum.hasMoreElements()) {
+        let win = winEnum.getNext();
+        if (win.closed) {
+          continue;
+        }
+        win.close();
+      }
+    }
+  });
+}
--- a/browser/base/content/test/general/content_aboutAccounts.js
+++ b/browser/base/content/test/general/content_aboutAccounts.js
@@ -1,48 +1,48 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This file is loaded as a "content script" for browser_aboutAccounts tests
-"use strict";
-
-addEventListener("load", function load(event) {
-  if (event.target != content.document) {
-    return;
-  }
-//  content.document.removeEventListener("load", load, true);
-  sendAsyncMessage("test:document:load");
-}, true);
-
-addEventListener("DOMContentLoaded", function domContentLoaded(event) {
-  removeEventListener("DOMContentLoaded", domContentLoaded, true);
-  let iframe = content.document.getElementById("remote");
-  iframe.addEventListener("load", function iframeLoaded(event) {
-    if (iframe.contentWindow.location.href == "about:blank" ||
-        event.target != iframe) {
-      return;
-    }
-    iframe.removeEventListener("load", iframeLoaded, true);
-    sendAsyncMessage("test:iframe:load", {url: iframe.getAttribute("src")});
-  }, true);
-}, true);
-
-// Return the visibility state of a list of ids.
-addMessageListener("test:check-visibilities", function (message) {
-  let result = {};
-  for (let id of message.data.ids) {
-    let elt = content.document.getElementById(id);
-    if (elt) {
-      let displayStyle = content.window.getComputedStyle(elt).display;
-      if (displayStyle == 'none') {
-        result[id] = false;
-      } else if (displayStyle == 'block') {
-        result[id] = true;
-      } else {
-        result[id] = "strange: " + displayStyle; // tests should fail!
-      }
-    } else {
-      result[id] = "doesn't exist: " + id;
-    }
-  }
-  sendAsyncMessage("test:check-visibilities-response", result);
-});
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This file is loaded as a "content script" for browser_aboutAccounts tests
+"use strict";
+
+addEventListener("load", function load(event) {
+  if (event.target != content.document) {
+    return;
+  }
+//  content.document.removeEventListener("load", load, true);
+  sendAsyncMessage("test:document:load");
+}, true);
+
+addEventListener("DOMContentLoaded", function domContentLoaded(event) {
+  removeEventListener("DOMContentLoaded", domContentLoaded, true);
+  let iframe = content.document.getElementById("remote");
+  iframe.addEventListener("load", function iframeLoaded(event) {
+    if (iframe.contentWindow.location.href == "about:blank" ||
+        event.target != iframe) {
+      return;
+    }
+    iframe.removeEventListener("load", iframeLoaded, true);
+    sendAsyncMessage("test:iframe:load", {url: iframe.getAttribute("src")});
+  }, true);
+}, true);
+
+// Return the visibility state of a list of ids.
+addMessageListener("test:check-visibilities", function (message) {
+  let result = {};
+  for (let id of message.data.ids) {
+    let elt = content.document.getElementById(id);
+    if (elt) {
+      let displayStyle = content.window.getComputedStyle(elt).display;
+      if (displayStyle == 'none') {
+        result[id] = false;
+      } else if (displayStyle == 'block') {
+        result[id] = true;
+      } else {
+        result[id] = "strange: " + displayStyle; // tests should fail!
+      }
+    } else {
+      result[id] = "doesn't exist: " + id;
+    }
+  }
+  sendAsyncMessage("test:check-visibilities-response", result);
+});
--- a/browser/base/content/test/social/browser_social_workercrash.js
+++ b/browser/base/content/test/social/browser_social_workercrash.js
@@ -1,157 +1,157 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This tests our recovery if a child content process hosting providers
-// crashes.
-
-// A content script we inject into one of our browsers
-const TEST_CONTENT_HELPER = "chrome://mochitests/content/browser/browser/base/content/test/social/social_crash_content_helper.js";
-
-let {getFrameWorkerHandle} = Cu.import("resource://gre/modules/FrameWorker.jsm", {});
-let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-
-function test() {
-  waitForExplicitFinish();
-
-  // We need to ensure all our workers are in the same content process.
-  Services.prefs.setIntPref("dom.ipc.processCount", 1);
-
-  // This test generates many uncaught promises that should not cause failures.
-  Promise.Debugging.clearUncaughtErrorObservers();
-
-  runSocialTestWithProvider(gProviders, function (finishcb) {
-    runSocialTests(tests, undefined, undefined, function() {
-      Services.prefs.clearUserPref("dom.ipc.processCount");
-      finishcb();
-    });
-  });
-}
-
-let gProviders = [
-  {
-    name: "provider 1",
-    origin: "https://example.com",
-    sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html?provider1",
-    workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
-    iconURL: "chrome://branding/content/icon48.png"
-  },
-  {
-    name: "provider 2",
-    origin: "https://test1.example.com",
-    sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html?provider2",
-    workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
-    iconURL: "chrome://branding/content/icon48.png"
-  }
-];
-
-var tests = {
-  testCrash: function(next) {
-    // open the sidebar, then crash the child.
-    let sbrowser = document.getElementById("social-sidebar-browser");
-    onSidebarLoad(function() {
-      // get the browser element for our provider.
-      let fw = getFrameWorkerHandle(gProviders[0].workerURL);
-      fw.port.close();
-      fw._worker.browserPromise.then(browser => {
-        let mm = browser.messageManager;
-        mm.loadFrameScript(TEST_CONTENT_HELPER, false);
-        // add an observer for the crash - after it sees the crash we attempt
-        // a reload.
-        let observer = new crashObserver(function() {
-          info("Saw the process crash.")
-          Services.obs.removeObserver(observer, 'ipc:content-shutdown');
-          // Add another sidebar load listener - it should be the error page.
-          onSidebarLoad(function() {
-            ok(sbrowser.contentDocument.location.href.indexOf("about:socialerror?")==0, "is on social error page");
-            // after reloading, the sidebar should reload
-            onSidebarLoad(function() {
-              // now ping both workers - they should both be alive.
-              ensureWorkerLoaded(gProviders[0], function() {
-                ensureWorkerLoaded(gProviders[1], function() {
-                  // and we are done!
-                  next();
-                });
-              });
-            });
-            // click the try-again button.
-            sbrowser.contentDocument.getElementById("btnTryAgain").click();
-          });
-        });
-        Services.obs.addObserver(observer, 'ipc:content-shutdown', false);
-        // and cause the crash.
-        mm.sendAsyncMessage("social-test:crash");
-      });
-    })
-    SocialSidebar.show();
-  },
-}
-
-function onSidebarLoad(callback) {
-  let sbrowser = document.getElementById("social-sidebar-browser");
-  sbrowser.addEventListener("load", function load() {
-    sbrowser.removeEventListener("load", load, true);
-    callback();
-  }, true);
-}
-
-function ensureWorkerLoaded(manifest, callback) {
-  let fw = getFrameWorkerHandle(manifest.workerURL);
-  // once the worker responds to a ping we know it must be up.
-  let port = fw.port;
-  port.onmessage = function(msg) {
-    if (msg.data.topic == "pong") {
-      port.close();
-      callback();
-    }
-  }
-  port.postMessage({topic: "ping"})
-}
-
-// More duplicated code from browser_thumbnails_brackground_crash.
-// Bug 915518 exists to unify these.
-
-// This observer is needed so we can clean up all evidence of the crash so
-// the testrunner thinks things are peachy.
-let crashObserver = function(callback) {
-  this.callback = callback;
-}
-crashObserver.prototype = {
-  observe: function(subject, topic, data) {
-    is(topic, 'ipc:content-shutdown', 'Received correct observer topic.');
-    ok(subject instanceof Components.interfaces.nsIPropertyBag2,
-       'Subject implements nsIPropertyBag2.');
-    // we might see this called as the process terminates due to previous tests.
-    // We are only looking for "abnormal" exits...
-    if (!subject.hasKey("abnormal")) {
-      info("This is a normal termination and isn't the one we are looking for...");
-      return;
-    }
-
-    var dumpID;
-    if ('nsICrashReporter' in Components.interfaces) {
-      dumpID = subject.getPropertyAsAString('dumpID');
-      ok(dumpID, "dumpID is present and not an empty string");
-    }
-
-    if (dumpID) {
-      var minidumpDirectory = getMinidumpDirectory();
-      removeFile(minidumpDirectory, dumpID + '.dmp');
-      removeFile(minidumpDirectory, dumpID + '.extra');
-    }
-    this.callback();
-  }
-}
-
-function getMinidumpDirectory() {
-  var dir = Services.dirsvc.get('ProfD', Components.interfaces.nsIFile);
-  dir.append("minidumps");
-  return dir;
-}
-function removeFile(directory, filename) {
-  var file = directory.clone();
-  file.append(filename);
-  if (file.exists()) {
-    file.remove(false);
-  }
-}
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This tests our recovery if a child content process hosting providers
+// crashes.
+
+// A content script we inject into one of our browsers
+const TEST_CONTENT_HELPER = "chrome://mochitests/content/browser/browser/base/content/test/social/social_crash_content_helper.js";
+
+let {getFrameWorkerHandle} = Cu.import("resource://gre/modules/FrameWorker.jsm", {});
+let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
+
+function test() {
+  waitForExplicitFinish();
+
+  // We need to ensure all our workers are in the same content process.
+  Services.prefs.setIntPref("dom.ipc.processCount", 1);
+
+  // This test generates many uncaught promises that should not cause failures.
+  Promise.Debugging.clearUncaughtErrorObservers();
+
+  runSocialTestWithProvider(gProviders, function (finishcb) {
+    runSocialTests(tests, undefined, undefined, function() {
+      Services.prefs.clearUserPref("dom.ipc.processCount");
+      finishcb();
+    });
+  });
+}
+
+let gProviders = [
+  {
+    name: "provider 1",
+    origin: "https://example.com",
+    sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html?provider1",
+    workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
+    iconURL: "chrome://branding/content/icon48.png"
+  },
+  {
+    name: "provider 2",
+    origin: "https://test1.example.com",
+    sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html?provider2",
+    workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
+    iconURL: "chrome://branding/content/icon48.png"
+  }
+];
+
+var tests = {
+  testCrash: function(next) {
+    // open the sidebar, then crash the child.
+    let sbrowser = document.getElementById("social-sidebar-browser");
+    onSidebarLoad(function() {
+      // get the browser element for our provider.
+      let fw = getFrameWorkerHandle(gProviders[0].workerURL);
+      fw.port.close();
+      fw._worker.browserPromise.then(browser => {
+        let mm = browser.messageManager;
+        mm.loadFrameScript(TEST_CONTENT_HELPER, false);
+        // add an observer for the crash - after it sees the crash we attempt
+        // a reload.
+        let observer = new crashObserver(function() {
+          info("Saw the process crash.")
+          Services.obs.removeObserver(observer, 'ipc:content-shutdown');
+          // Add another sidebar load listener - it should be the error page.
+          onSidebarLoad(function() {
+            ok(sbrowser.contentDocument.location.href.indexOf("about:socialerror?")==0, "is on social error page");
+            // after reloading, the sidebar should reload
+            onSidebarLoad(function() {
+              // now ping both workers - they should both be alive.
+              ensureWorkerLoaded(gProviders[0], function() {
+                ensureWorkerLoaded(gProviders[1], function() {
+                  // and we are done!
+                  next();
+                });
+              });
+            });
+            // click the try-again button.
+            sbrowser.contentDocument.getElementById("btnTryAgain").click();
+          });
+        });
+        Services.obs.addObserver(observer, 'ipc:content-shutdown', false);
+        // and cause the crash.
+        mm.sendAsyncMessage("social-test:crash");
+      });
+    })
+    SocialSidebar.show();
+  },
+}
+
+function onSidebarLoad(callback) {
+  let sbrowser = document.getElementById("social-sidebar-browser");
+  sbrowser.addEventListener("load", function load() {
+    sbrowser.removeEventListener("load", load, true);
+    callback();
+  }, true);
+}
+
+function ensureWorkerLoaded(manifest, callback) {
+  let fw = getFrameWorkerHandle(manifest.workerURL);
+  // once the worker responds to a ping we know it must be up.
+  let port = fw.port;
+  port.onmessage = function(msg) {
+    if (msg.data.topic == "pong") {
+      port.close();
+      callback();
+    }
+  }
+  port.postMessage({topic: "ping"})
+}
+
+// More duplicated code from browser_thumbnails_brackground_crash.
+// Bug 915518 exists to unify these.
+
+// This observer is needed so we can clean up all evidence of the crash so
+// the testrunner thinks things are peachy.
+let crashObserver = function(callback) {
+  this.callback = callback;
+}
+crashObserver.prototype = {
+  observe: function(subject, topic, data) {
+    is(topic, 'ipc:content-shutdown', 'Received correct observer topic.');
+    ok(subject instanceof Components.interfaces.nsIPropertyBag2,
+       'Subject implements nsIPropertyBag2.');
+    // we might see this called as the process terminates due to previous tests.
+    // We are only looking for "abnormal" exits...
+    if (!subject.hasKey("abnormal")) {
+      info("This is a normal termination and isn't the one we are looking for...");
+      return;
+    }
+
+    var dumpID;
+    if ('nsICrashReporter' in Components.interfaces) {
+      dumpID = subject.getPropertyAsAString('dumpID');
+      ok(dumpID, "dumpID is present and not an empty string");
+    }
+
+    if (dumpID) {
+      var minidumpDirectory = getMinidumpDirectory();
+      removeFile(minidumpDirectory, dumpID + '.dmp');
+      removeFile(minidumpDirectory, dumpID + '.extra');
+    }
+    this.callback();
+  }
+}
+
+function getMinidumpDirectory() {
+  var dir = Services.dirsvc.get('ProfD', Components.interfaces.nsIFile);
+  dir.append("minidumps");
+  return dir;
+}
+function removeFile(directory, filename) {
+  var file = directory.clone();
+  file.append(filename);
+  if (file.exists()) {
+    file.remove(false);
+  }
+}
--- a/browser/components/customizableui/src/logging.js
+++ b/browser/components/customizableui/src/logging.js
@@ -1,31 +1,31 @@
-#if 0
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#endif
-
-XPCOMUtils.defineLazyModuleGetter(this, "console",
-  "resource://gre/modules/devtools/Console.jsm");
-
-let gDebug = false;
-try {
-  gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
-} catch (e) {}
-
-function LOG(...args) {
-  if (gDebug) {
-    args.unshift(gModuleName);
-    console.log.apply(console, args);
-  }
-}
-
-function ERROR(...args) {
-  args.unshift(gModuleName);
-  console.error.apply(console, args);
-}
-
-function INFO(...args) {
-  args.unshift(gModuleName);
-  console.info.apply(console, args);
-}
-
+#if 0
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#endif
+
+XPCOMUtils.defineLazyModuleGetter(this, "console",
+  "resource://gre/modules/devtools/Console.jsm");
+
+let gDebug = false;
+try {
+  gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+} catch (e) {}
+
+function LOG(...args) {
+  if (gDebug) {
+    args.unshift(gModuleName);
+    console.log.apply(console, args);
+  }
+}
+
+function ERROR(...args) {
+  args.unshift(gModuleName);
+  console.error.apply(console, args);
+}
+
+function INFO(...args) {
+  args.unshift(gModuleName);
+  console.info.apply(console, args);
+}
+
--- a/browser/components/customizableui/test/browser_885052_customize_mode_observers_disabed.js
+++ b/browser/components/customizableui/test/browser_885052_customize_mode_observers_disabed.js
@@ -1,39 +1,39 @@
-/* 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";
-
-// Observers should be disabled when in customization mode.
-add_task(function() {
-  // Open and close the panel to make sure that the
-  // area is generated before getting a child of the area.
-  let shownPanelPromise = promisePanelShown(window);
-  PanelUI.toggle({type: "command"});
-  yield shownPanelPromise;
-  let hiddenPanelPromise = promisePanelHidden(window);
-  PanelUI.toggle({type: "command"});
-  yield hiddenPanelPromise;
-
-  let fullscreenButton = document.getElementById("fullscreen-button");
-  ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.")
-
-  BrowserFullScreen();
-  yield waitForCondition(function() fullscreenButton.checked);
-  ok(fullscreenButton.checked, "Fullscreen button should be checked when in fullscreen.")
-
-  yield startCustomizing();
-
-  let fullscreenButtonWrapper = document.getElementById("wrapper-fullscreen-button");
-  ok(fullscreenButtonWrapper.hasAttribute("itemobserves"), "Observer should be moved to wrapper");
-  fullscreenButton = document.getElementById("fullscreen-button");
-  ok(!fullscreenButton.hasAttribute("observes"), "Observer should be removed from button");
-  ok(!fullscreenButton.checked, "Fullscreen button should no longer be checked during customization mode");
-
-  yield endCustomizing();
-
-  BrowserFullScreen();
-  fullscreenButton = document.getElementById("fullscreen-button");
-  yield waitForCondition(function() !fullscreenButton.checked);
-  ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.")
-});
+/* 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";
+
+// Observers should be disabled when in customization mode.
+add_task(function() {
+  // Open and close the panel to make sure that the
+  // area is generated before getting a child of the area.
+  let shownPanelPromise = promisePanelShown(window);
+  PanelUI.toggle({type: "command"});
+  yield shownPanelPromise;
+  let hiddenPanelPromise = promisePanelHidden(window);
+  PanelUI.toggle({type: "command"});
+  yield hiddenPanelPromise;
+
+  let fullscreenButton = document.getElementById("fullscreen-button");
+  ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.")
+
+  BrowserFullScreen();
+  yield waitForCondition(function() fullscreenButton.checked);
+  ok(fullscreenButton.checked, "Fullscreen button should be checked when in fullscreen.")
+
+  yield startCustomizing();
+
+  let fullscreenButtonWrapper = document.getElementById("wrapper-fullscreen-button");
+  ok(fullscreenButtonWrapper.hasAttribute("itemobserves"), "Observer should be moved to wrapper");
+  fullscreenButton = document.getElementById("fullscreen-button");
+  ok(!fullscreenButton.hasAttribute("observes"), "Observer should be removed from button");
+  ok(!fullscreenButton.checked, "Fullscreen button should no longer be checked during customization mode");
+
+  yield endCustomizing();
+
+  BrowserFullScreen();
+  fullscreenButton = document.getElementById("fullscreen-button");
+  yield waitForCondition(function() !fullscreenButton.checked);
+  ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.")
+});
--- a/browser/components/customizableui/test/browser_888817_currentset_updating.js
+++ b/browser/components/customizableui/test/browser_888817_currentset_updating.js
@@ -1,57 +1,57 @@
-/* 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";
-
-// Adding, moving and removing items should update the relevant currentset attributes
-add_task(function() {
-  ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
-  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-  setToolbarVisibility(personalbar, true);
-  ok(!CustomizableUI.inDefaultState, "Making the bookmarks toolbar visible takes it out of the default state");
-
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-  let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet;
-  let personalbarCurrentset = personalbar.getAttribute("currentset") || personalbar.currentSet;
-
-  let otherWin = yield openAndLoadWindow();
-  let otherNavbar = otherWin.document.getElementById(CustomizableUI.AREA_NAVBAR);
-  let otherPersonalbar = otherWin.document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-
-  CustomizableUI.moveWidgetWithinArea("home-button", 0);
-  navbarCurrentset = "home-button," + navbarCurrentset.replace(",home-button", "");
-  is(navbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated currentSet after move.");
-  is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated other window's currentSet after move.");
-
-  CustomizableUI.addWidgetToArea("home-button", CustomizableUI.AREA_BOOKMARKS);
-  navbarCurrentset = navbarCurrentset.replace("home-button,", "");
-  personalbarCurrentset = personalbarCurrentset + ",home-button";
-  is(navbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated navbar currentSet after implied remove.");
-  is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated other window's navbar currentSet after implied remove.");
-  is(personalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated personalbar currentSet after add.");
-  is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated other window's personalbar currentSet after add.");
-
-  CustomizableUI.removeWidgetFromArea("home-button");
-  personalbarCurrentset = personalbarCurrentset.replace(",home-button", "");
-  is(personalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated currentSet after remove.");
-  is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated other window's currentSet after remove.");
-
-  yield promiseWindowClosed(otherWin);
-  // Reset in asyncCleanup will put our button back for us.
-});
-
-add_task(function asyncCleanup() {
-  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-  setToolbarVisibility(personalbar, false);
-  yield resetCustomization();
-});
+/* 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";
+
+// Adding, moving and removing items should update the relevant currentset attributes
+add_task(function() {
+  ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
+  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+  setToolbarVisibility(personalbar, true);
+  ok(!CustomizableUI.inDefaultState, "Making the bookmarks toolbar visible takes it out of the default state");
+
+  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+  let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet;
+  let personalbarCurrentset = personalbar.getAttribute("currentset") || personalbar.currentSet;
+
+  let otherWin = yield openAndLoadWindow();
+  let otherNavbar = otherWin.document.getElementById(CustomizableUI.AREA_NAVBAR);
+  let otherPersonalbar = otherWin.document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+
+  CustomizableUI.moveWidgetWithinArea("home-button", 0);
+  navbarCurrentset = "home-button," + navbarCurrentset.replace(",home-button", "");
+  is(navbar.getAttribute("currentset"), navbarCurrentset,
+     "Should have updated currentSet after move.");
+  is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
+     "Should have updated other window's currentSet after move.");
+
+  CustomizableUI.addWidgetToArea("home-button", CustomizableUI.AREA_BOOKMARKS);
+  navbarCurrentset = navbarCurrentset.replace("home-button,", "");
+  personalbarCurrentset = personalbarCurrentset + ",home-button";
+  is(navbar.getAttribute("currentset"), navbarCurrentset,
+     "Should have updated navbar currentSet after implied remove.");
+  is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
+     "Should have updated other window's navbar currentSet after implied remove.");
+  is(personalbar.getAttribute("currentset"), personalbarCurrentset,
+     "Should have updated personalbar currentSet after add.");
+  is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
+     "Should have updated other window's personalbar currentSet after add.");
+
+  CustomizableUI.removeWidgetFromArea("home-button");
+  personalbarCurrentset = personalbarCurrentset.replace(",home-button", "");
+  is(personalbar.getAttribute("currentset"), personalbarCurrentset,
+     "Should have updated currentSet after remove.");
+  is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
+     "Should have updated other window's currentSet after remove.");
+
+  yield promiseWindowClosed(otherWin);
+  // Reset in asyncCleanup will put our button back for us.
+});
+
+add_task(function asyncCleanup() {
+  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+  setToolbarVisibility(personalbar, false);
+  yield resetCustomization();
+});
--- a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
+++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
@@ -1,167 +1,167 @@
-/* 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";
-
-requestLongerTimeout(2);
-
-// One orphaned item should have two placeholders next to it.
-add_task(function() {
-  yield startCustomizing();
-  let btn = document.getElementById("open-file-button");
-  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
-
-  if (isInWin8()) {
-    CustomizableUI.removeWidgetFromArea("switch-to-metro-button");
-    placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
-    ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
-  } else {
-    ok(CustomizableUI.inDefaultState, "Should be in default state.");
-  }
-
-  assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
-  is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting");
-
-  yield endCustomizing();
-  yield startCustomizing();
-  is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering");
-
-  if (isInWin8()) {
-    CustomizableUI.addWidgetToArea("switch-to-metro-button", CustomizableUI.AREA_PANEL);
-  }
-  ok(CustomizableUI.inDefaultState, "Should be in default state again.");
-});
-
-// Two orphaned items should have one placeholder next to them (case 1).
-add_task(function() {
-  yield startCustomizing();
-  let btn = document.getElementById("open-file-button");
-  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
-
-  let placementsAfterAppend = placements;
-
-  if (!isInWin8()) {
-    placementsAfterAppend = placements.concat(["open-file-button"]);
-    simulateItemDrag(btn, panel);
-  }
-
-  assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
-  is(CustomizableUI.inDefaultState, isInWin8(), "Should only be in default state if on Win8");
-  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder before exiting");
-
-  yield endCustomizing();
-  yield startCustomizing();
-  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder after re-entering");
-
-  let palette = document.getElementById("customization-palette");
-  simulateItemDrag(btn, palette);
-
-  if (!isInWin8()) {
-    btn = document.getElementById("open-file-button");
-    simulateItemDrag(btn, palette);
-  }
-  ok(CustomizableUI.inDefaultState, "Should be in default state again."); 
-});
-
-// Two orphaned items should have one placeholder next to them (case 2).
-add_task(function() {
-  yield startCustomizing();
-  let btn = document.getElementById("add-ons-button");
-  let btn2 = document.getElementById("developer-button");
-  let btn3 = document.getElementById("switch-to-metro-button");
-  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-  let palette = document.getElementById("customization-palette");
-  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
-
-  let placementsAfterAppend = placements.filter(p => p != btn.id && p != btn2.id);
-  simulateItemDrag(btn, palette);
-  simulateItemDrag(btn2, palette);
-
-  if (isInWin8()) {
-    placementsAfterAppend = placementsAfterAppend.filter(p => p != btn3.id);
-    simulateItemDrag(btn3, palette);
-  }
-
-  assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
-  ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
-  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder before exiting");
-
-  yield endCustomizing();
-  yield startCustomizing();
-  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder after re-entering");
-
-  simulateItemDrag(btn, panel);
-  simulateItemDrag(btn2, panel);
-
-  if (isInWin8()) {
-    simulateItemDrag(btn3, panel);
-  }
-
-  assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
-  ok(CustomizableUI.inDefaultState, "Should be in default state again.");
-});
-
-// A wide widget at the bottom of the panel should have three placeholders after it.
-add_task(function() {
-  yield startCustomizing();
-  let btn = document.getElementById("edit-controls");
-  let developerButton = document.getElementById("developer-button");
-  let metroBtn = document.getElementById("switch-to-metro-button");
-  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-  let palette = document.getElementById("customization-palette");
-  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
-
-  placements.pop();
-  simulateItemDrag(developerButton, palette);
-  if (isInWin8()) {
-    // Remove switch-to-metro-button
-    placements.pop();
-    simulateItemDrag(metroBtn, palette);
-  }
-
-  let placementsAfterAppend = placements.concat([placements.shift()]);
-  simulateItemDrag(btn, panel);
-  assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
-  ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
-  is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting");
-
-  yield endCustomizing();
-  yield startCustomizing();
-  is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
-
-  simulateItemDrag(developerButton, panel);
-  if (isInWin8()) {
-    simulateItemDrag(metroBtn, panel);
-  }
-  let zoomControls = document.getElementById("zoom-controls");
-  simulateItemDrag(btn, zoomControls);
-  ok(CustomizableUI.inDefaultState, "Should be in default state again.");
-});
-
-// The default placements should have two placeholders at the bottom (or 1 in win8).
-add_task(function() {
-  yield startCustomizing();
-  let numPlaceholders = isInWin8() ? 1 : 2;
-  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-  ok(CustomizableUI.inDefaultState, "Should be in default state.");
-  is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting");
-
-  yield endCustomizing();
-  yield startCustomizing();
-  is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders after re-entering");
-
-  ok(CustomizableUI.inDefaultState, "Should still be in default state.");
-});
-
-add_task(function asyncCleanup() {
-  yield endCustomizing();
-  yield resetCustomization();
-});
-
-function getVisiblePlaceholderCount(aPanel) {
-  let visiblePlaceholders = aPanel.querySelectorAll(".panel-customization-placeholder:not([hidden=true])");
-  return visiblePlaceholders.length;
-}
+/* 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";
+
+requestLongerTimeout(2);
+
+// One orphaned item should have two placeholders next to it.
+add_task(function() {
+  yield startCustomizing();
+  let btn = document.getElementById("open-file-button");
+  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+  if (isInWin8()) {
+    CustomizableUI.removeWidgetFromArea("switch-to-metro-button");
+    placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+    ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+  } else {
+    ok(CustomizableUI.inDefaultState, "Should be in default state.");
+  }
+
+  assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
+  is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting");
+
+  yield endCustomizing();
+  yield startCustomizing();
+  is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering");
+
+  if (isInWin8()) {
+    CustomizableUI.addWidgetToArea("switch-to-metro-button", CustomizableUI.AREA_PANEL);
+  }
+  ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+});
+
+// Two orphaned items should have one placeholder next to them (case 1).
+add_task(function() {
+  yield startCustomizing();
+  let btn = document.getElementById("open-file-button");
+  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+  let placementsAfterAppend = placements;
+
+  if (!isInWin8()) {
+    placementsAfterAppend = placements.concat(["open-file-button"]);
+    simulateItemDrag(btn, panel);
+  }
+
+  assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+  is(CustomizableUI.inDefaultState, isInWin8(), "Should only be in default state if on Win8");
+  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder before exiting");
+
+  yield endCustomizing();
+  yield startCustomizing();
+  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder after re-entering");
+
+  let palette = document.getElementById("customization-palette");
+  simulateItemDrag(btn, palette);
+
+  if (!isInWin8()) {
+    btn = document.getElementById("open-file-button");
+    simulateItemDrag(btn, palette);
+  }
+  ok(CustomizableUI.inDefaultState, "Should be in default state again."); 
+});
+
+// Two orphaned items should have one placeholder next to them (case 2).
+add_task(function() {
+  yield startCustomizing();
+  let btn = document.getElementById("add-ons-button");
+  let btn2 = document.getElementById("developer-button");
+  let btn3 = document.getElementById("switch-to-metro-button");
+  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+  let palette = document.getElementById("customization-palette");
+  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+  let placementsAfterAppend = placements.filter(p => p != btn.id && p != btn2.id);
+  simulateItemDrag(btn, palette);
+  simulateItemDrag(btn2, palette);
+
+  if (isInWin8()) {
+    placementsAfterAppend = placementsAfterAppend.filter(p => p != btn3.id);
+    simulateItemDrag(btn3, palette);
+  }
+
+  assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+  ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder before exiting");
+
+  yield endCustomizing();
+  yield startCustomizing();
+  is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder after re-entering");
+
+  simulateItemDrag(btn, panel);
+  simulateItemDrag(btn2, panel);
+
+  if (isInWin8()) {
+    simulateItemDrag(btn3, panel);
+  }
+
+  assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
+  ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+});
+
+// A wide widget at the bottom of the panel should have three placeholders after it.
+add_task(function() {
+  yield startCustomizing();
+  let btn = document.getElementById("edit-controls");
+  let developerButton = document.getElementById("developer-button");
+  let metroBtn = document.getElementById("switch-to-metro-button");
+  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+  let palette = document.getElementById("customization-palette");
+  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+  placements.pop();
+  simulateItemDrag(developerButton, palette);
+  if (isInWin8()) {
+    // Remove switch-to-metro-button
+    placements.pop();
+    simulateItemDrag(metroBtn, palette);
+  }
+
+  let placementsAfterAppend = placements.concat([placements.shift()]);
+  simulateItemDrag(btn, panel);
+  assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+  ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+  is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting");
+
+  yield endCustomizing();
+  yield startCustomizing();
+  is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
+
+  simulateItemDrag(developerButton, panel);
+  if (isInWin8()) {
+    simulateItemDrag(metroBtn, panel);
+  }
+  let zoomControls = document.getElementById("zoom-controls");
+  simulateItemDrag(btn, zoomControls);
+  ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+});
+
+// The default placements should have two placeholders at the bottom (or 1 in win8).
+add_task(function() {
+  yield startCustomizing();
+  let numPlaceholders = isInWin8() ? 1 : 2;
+  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+  ok(CustomizableUI.inDefaultState, "Should be in default state.");
+  is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting");
+
+  yield endCustomizing();
+  yield startCustomizing();
+  is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders after re-entering");
+
+  ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+});
+
+add_task(function asyncCleanup() {
+  yield endCustomizing();
+  yield resetCustomization();
+});
+
+function getVisiblePlaceholderCount(aPanel) {
+  let visiblePlaceholders = aPanel.querySelectorAll(".panel-customization-placeholder:not([hidden=true])");
+  return visiblePlaceholders.length;
+}
--- a/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js
+++ b/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js
@@ -1,148 +1,148 @@
-/* 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";
-
-let openUILinkInCalled = false;
-let expectOpenUILinkInCall = false;
-this.originalOpenUILinkIn = openUILinkIn;
-openUILinkIn = (aUrl, aWhichTab) => {
-  is(aUrl, "about:home", "about:home should be requested to open.");
-  is(aWhichTab, "current", "Should use the current tab for the search page.");
-  openUILinkInCalled = true;
-  if (!expectOpenUILinkInCall) {
-    ok(false, "OpenUILinkIn was called when it shouldn't have been.");
-  }
-};
-logActiveElement();
-
-function* waitForSearchBarFocus()
-{
-  let searchbar = document.getElementById("searchbar");
-  yield waitForCondition(function () {
-    logActiveElement();
-    return document.activeElement === searchbar.textbox.inputField;
-  });
-}
-
-// Ctrl+K should open the menu panel and focus the search bar if the search bar is in the panel.
-add_task(function() {
-  let searchbar = document.getElementById("searchbar");
-  gCustomizeMode.addToPanel(searchbar);
-  let placement = CustomizableUI.getPlacementOfWidget("search-container");
-  is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
-
-  let shownPanelPromise = promisePanelShown(window);
-  sendWebSearchKeyCommand();
-  yield shownPanelPromise;
-
-  yield waitForSearchBarFocus();
-
-  let hiddenPanelPromise = promisePanelHidden(window);
-  EventUtils.synthesizeKey("VK_ESCAPE", {});
-  yield hiddenPanelPromise;
-  CustomizableUI.reset();
-});
-
-// Ctrl+K should give focus to the searchbar when the searchbar is in the menupanel and the panel is already opened.
-add_task(function() {
-  let searchbar = document.getElementById("searchbar");
-  gCustomizeMode.addToPanel(searchbar);
-  let placement = CustomizableUI.getPlacementOfWidget("search-container");
-  is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
-
-  let shownPanelPromise = promisePanelShown(window);
-  PanelUI.toggle({type: "command"});
-  yield shownPanelPromise;
-
-  sendWebSearchKeyCommand();
-
-  yield waitForSearchBarFocus();
-
-  let hiddenPanelPromise = promisePanelHidden(window);
-  EventUtils.synthesizeKey("VK_ESCAPE", {});
-  yield hiddenPanelPromise;
-  CustomizableUI.reset();
-});
-
-// Ctrl+K should open the overflow panel and focus the search bar if the search bar is overflowed.
-add_task(function() {
-  this.originalWindowWidth = window.outerWidth;
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
-  ok(CustomizableUI.inDefaultState, "Should start in default state.");
-
-  window.resizeTo(360, window.outerHeight);
-  yield waitForCondition(() => navbar.getAttribute("overflowing") == "true");
-  ok(!navbar.querySelector("#search-container"), "Search container should be overflowing");
-
-  let shownPanelPromise = promiseOverflowShown(window);
-  sendWebSearchKeyCommand();
-  yield shownPanelPromise;
-
-  let chevron = document.getElementById("nav-bar-overflow-button");
-  yield waitForCondition(function() chevron.open);
-
-  yield waitForSearchBarFocus();
-
-  let hiddenPanelPromise = promiseOverflowHidden(window);
-  EventUtils.synthesizeKey("VK_ESCAPE", {});
-  yield hiddenPanelPromise;
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  window.resizeTo(this.originalWindowWidth, window.outerHeight);
-  yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
-  ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
-});
-
-// Ctrl+K should focus the search bar if it is in the navbar and not overflowing.
-add_task(function() {
-  let placement = CustomizableUI.getPlacementOfWidget("search-container");
-  is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in nav-bar");
-
-  sendWebSearchKeyCommand();
-
-  yield waitForSearchBarFocus();
-});
-
-// Ctrl+K should open the search page if the search bar has been customized out.
-add_task(function() {
-  try {
-    expectOpenUILinkInCall = true;
-    CustomizableUI.removeWidgetFromArea("search-container");
-    let placement = CustomizableUI.getPlacementOfWidget("search-container");
-    is(placement, null, "Search container should be in palette");
-
-    openUILinkInCalled = false;
-
-    sendWebSearchKeyCommand();
-    yield waitForCondition(function() openUILinkInCalled);
-    ok(openUILinkInCalled, "The search page should have been opened.")
-    expectOpenUILinkInCall = false;
-  } catch (e) {
-    ok(false, e);
-  }
-  CustomizableUI.reset();
-});
-
-registerCleanupFunction(function() {
-  openUILinkIn = this.originalOpenUILinkIn;
-  delete this.originalOpenUILinkIn;
-});
-
-function sendWebSearchKeyCommand() {
-  if (Services.appinfo.OS === "Darwin")
-    EventUtils.synthesizeKey("k", { accelKey: true });
-  else
-    EventUtils.synthesizeKey("k", { ctrlKey: true });
-}
-
-function logActiveElement() {
-  let element = document.activeElement;
-  let str = "";
-  while (element && element.parentNode) {
-    str = " (" + element.localName + "#" + element.id + "." + [...element.classList].join(".") + ") >" + str;
-    element = element.parentNode;
-  }
-  info("Active element: " + element ? str : "null");
-}
+/* 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";
+
+let openUILinkInCalled = false;
+let expectOpenUILinkInCall = false;
+this.originalOpenUILinkIn = openUILinkIn;
+openUILinkIn = (aUrl, aWhichTab) => {
+  is(aUrl, "about:home", "about:home should be requested to open.");
+  is(aWhichTab, "current", "Should use the current tab for the search page.");
+  openUILinkInCalled = true;
+  if (!expectOpenUILinkInCall) {
+    ok(false, "OpenUILinkIn was called when it shouldn't have been.");
+  }
+};
+logActiveElement();
+
+function* waitForSearchBarFocus()
+{
+  let searchbar = document.getElementById("searchbar");
+  yield waitForCondition(function () {
+    logActiveElement();
+    return document.activeElement === searchbar.textbox.inputField;
+  });
+}
+
+// Ctrl+K should open the menu panel and focus the search bar if the search bar is in the panel.
+add_task(function() {
+  let searchbar = document.getElementById("searchbar");
+  gCustomizeMode.addToPanel(searchbar);
+  let placement = CustomizableUI.getPlacementOfWidget("search-container");
+  is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
+
+  let shownPanelPromise = promisePanelShown(window);
+  sendWebSearchKeyCommand();
+  yield shownPanelPromise;
+
+  yield waitForSearchBarFocus();
+
+  let hiddenPanelPromise = promisePanelHidden(window);
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield hiddenPanelPromise;
+  CustomizableUI.reset();
+});
+
+// Ctrl+K should give focus to the searchbar when the searchbar is in the menupanel and the panel is already opened.
+add_task(function() {
+  let searchbar = document.getElementById("searchbar");
+  gCustomizeMode.addToPanel(searchbar);
+  let placement = CustomizableUI.getPlacementOfWidget("search-container");
+  is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
+
+  let shownPanelPromise = promisePanelShown(window);
+  PanelUI.toggle({type: "command"});
+  yield shownPanelPromise;
+
+  sendWebSearchKeyCommand();
+
+  yield waitForSearchBarFocus();
+
+  let hiddenPanelPromise = promisePanelHidden(window);
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield hiddenPanelPromise;
+  CustomizableUI.reset();
+});
+
+// Ctrl+K should open the overflow panel and focus the search bar if the search bar is overflowed.
+add_task(function() {
+  this.originalWindowWidth = window.outerWidth;
+  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+  ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+  ok(CustomizableUI.inDefaultState, "Should start in default state.");
+
+  window.resizeTo(360, window.outerHeight);
+  yield waitForCondition(() => navbar.getAttribute("overflowing") == "true");
+  ok(!navbar.querySelector("#search-container"), "Search container should be overflowing");
+
+  let shownPanelPromise = promiseOverflowShown(window);
+  sendWebSearchKeyCommand();
+  yield shownPanelPromise;
+
+  let chevron = document.getElementById("nav-bar-overflow-button");
+  yield waitForCondition(function() chevron.open);
+
+  yield waitForSearchBarFocus();
+
+  let hiddenPanelPromise = promiseOverflowHidden(window);
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield hiddenPanelPromise;
+  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+  window.resizeTo(this.originalWindowWidth, window.outerHeight);
+  yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+  ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
+});
+
+// Ctrl+K should focus the search bar if it is in the navbar and not overflowing.
+add_task(function() {
+  let placement = CustomizableUI.getPlacementOfWidget("search-container");
+  is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in nav-bar");
+
+  sendWebSearchKeyCommand();
+
+  yield waitForSearchBarFocus();
+});
+
+// Ctrl+K should open the search page if the search bar has been customized out.
+add_task(function() {
+  try {
+    expectOpenUILinkInCall = true;
+    CustomizableUI.removeWidgetFromArea("search-container");
+    let placement = CustomizableUI.getPlacementOfWidget("search-container");
+    is(placement, null, "Search container should be in palette");
+
+    openUILinkInCalled = false;
+
+    sendWebSearchKeyCommand();
+    yield waitForCondition(function() openUILinkInCalled);
+    ok(openUILinkInCalled, "The search page should have been opened.")
+    expectOpenUILinkInCall = false;
+  } catch (e) {
+    ok(false, e);
+  }
+  CustomizableUI.reset();
+});
+
+registerCleanupFunction(function() {
+  openUILinkIn = this.originalOpenUILinkIn;
+  delete this.originalOpenUILinkIn;
+});
+
+function sendWebSearchKeyCommand() {
+  if (Services.appinfo.OS === "Darwin")
+    EventUtils.synthesizeKey("k", { accelKey: true });
+  else
+    EventUtils.synthesizeKey("k", { ctrlKey: true });
+}
+
+function logActiveElement() {
+  let element = document.activeElement;
+  let str = "";
+  while (element && element.parentNode) {
+    str = " (" + element.localName + "#" + element.id + "." + [...element.classList].join(".") + ") >" + str;
+    element = element.parentNode;
+  }
+  info("Active element: " + element ? str : "null");
+}
--- a/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
+++ b/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
@@ -1,31 +1,31 @@
-/* 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";
-
-// Resize to a small window, open a new window, check that new window handles overflow properly
-add_task(function() {
-  let originalWindowWidth = window.outerWidth;
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
-  let oldChildCount = navbar.customizationTarget.childElementCount;
-  window.resizeTo(400, window.outerHeight);
-  yield waitForCondition(() => navbar.hasAttribute("overflowing"));
-  ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
-
-  ok(navbar.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
-  let newWindow = yield openAndLoadWindow();
-  let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR);
-  yield waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
-  ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
-  yield promiseWindowClosed(newWindow);
-
-  window.resizeTo(originalWindowWidth, window.outerHeight);
-  yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
-  ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
-});
-
-add_task(function asyncCleanup() {
-  yield resetCustomization();
-});
+/* 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";
+
+// Resize to a small window, open a new window, check that new window handles overflow properly
+add_task(function() {
+  let originalWindowWidth = window.outerWidth;
+  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+  ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+  let oldChildCount = navbar.customizationTarget.childElementCount;
+  window.resizeTo(400, window.outerHeight);
+  yield waitForCondition(() => navbar.hasAttribute("overflowing"));
+  ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
+
+  ok(navbar.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
+  let newWindow = yield openAndLoadWindow();
+  let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR);
+  yield waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
+  ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
+  yield promiseWindowClosed(newWindow);
+
+  window.resizeTo(originalWindowWidth, window.outerHeight);
+  yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+  ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
+});
+
+add_task(function asyncCleanup() {
+  yield resetCustomization();
+});
--- a/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js
+++ b/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js
@@ -1,16 +1,16 @@
-/* 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/. */
-
-// Entering then exiting customization mode should reenable the Help and Exit buttons.
-add_task(function() {
-  yield startCustomizing();
-  let helpButton = document.getElementById("PanelUI-help");
-  let quitButton = document.getElementById("PanelUI-quit");
-  ok(helpButton.getAttribute("disabled") == "true", "Help button should be disabled while in customization mode.");
-  ok(quitButton.getAttribute("disabled") == "true", "Quit button should be disabled while in customization mode.");
-  yield endCustomizing();
-
-  ok(!helpButton.hasAttribute("disabled"), "Help button should not be disabled.");
-  ok(!quitButton.hasAttribute("disabled"), "Quit button should not be disabled.");
-});
+/* 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/. */
+
+// Entering then exiting customization mode should reenable the Help and Exit buttons.
+add_task(function() {
+  yield startCustomizing();
+  let helpButton = document.getElementById("PanelUI-help");
+  let quitButton = document.getElementById("PanelUI-quit");
+  ok(helpButton.getAttribute("disabled") == "true", "Help button should be disabled while in customization mode.");
+  ok(quitButton.getAttribute("disabled") == "true", "Quit button should be disabled while in customization mode.");
+  yield endCustomizing();
+
+  ok(!helpButton.hasAttribute("disabled"), "Help button should not be disabled.");
+  ok(!quitButton.hasAttribute("disabled"), "Quit button should not be disabled.");
+});
--- a/browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js
+++ b/browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js
@@ -1,35 +1,35 @@
-/* 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";
-
-// There should be an advert to get more addons when the palette is empty.
-add_task(function() {
-  yield startCustomizing();
-  let visiblePalette = document.getElementById("customization-palette");
-  let emptyPaletteNotice = document.getElementById("customization-empty");
-  is(emptyPaletteNotice.hidden, true, "The empty palette notice should not be shown when there are items in the palette.");
-
-  while (visiblePalette.childElementCount) {
-    gCustomizeMode.addToToolbar(visiblePalette.children[0]);
-  }
-  is(visiblePalette.childElementCount, 0, "There shouldn't be any items remaining in the visible palette.");
-  is(emptyPaletteNotice.hidden, false, "The empty palette notice should be shown when there are no items in the palette.");
-
-  yield endCustomizing();
-  yield startCustomizing();
-  visiblePalette = document.getElementById("customization-palette");
-  emptyPaletteNotice = document.getElementById("customization-empty");
-  is(emptyPaletteNotice.hidden, false,
-     "The empty palette notice should be shown when there are no items in the palette and cust. mode is re-entered.");
-
-  gCustomizeMode.removeFromArea(document.getElementById("wrapper-home-button"));
-  is(emptyPaletteNotice.hidden, true,
-     "The empty palette notice should not be shown when there is at least one item in the palette.");
-});
-
-add_task(function asyncCleanup() {
-  yield endCustomizing();
-  yield resetCustomization();
-});
+/* 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";
+
+// There should be an advert to get more addons when the palette is empty.
+add_task(function() {
+  yield startCustomizing();
+  let visiblePalette = document.getElementById("customization-palette");
+  let emptyPaletteNotice = document.getElementById("customization-empty");
+  is(emptyPaletteNotice.hidden, true, "The empty palette notice should not be shown when there are items in the palette.");
+
+  while (visiblePalette.childElementCount) {
+    gCustomizeMode.addToToolbar(visiblePalette.children[0]);
+  }
+  is(visiblePalette.childElementCount, 0, "There shouldn't be any items remaining in the visible palette.");
+  is(emptyPaletteNotice.hidden, false, "The empty palette notice should be shown when there are no items in the palette.");
+
+  yield endCustomizing();
+  yield startCustomizing();
+  visiblePalette = document.getElementById("customization-palette");
+  emptyPaletteNotice = document.getElementById("customization-empty");
+  is(emptyPaletteNotice.hidden, false,
+     "The empty palette notice should be shown when there are no items in the palette and cust. mode is re-entered.");
+
+  gCustomizeMode.removeFromArea(document.getElementById("wrapper-home-button"));
+  is(emptyPaletteNotice.hidden, true,
+     "The empty palette notice should not be shown when there is at least one item in the palette.");
+});
+
+add_task(function asyncCleanup() {
+  yield endCustomizing();
+  yield resetCustomization();
+});
--- a/browser/components/customizableui/test/browser_934951_zoom_in_toolbar.js
+++ b/browser/components/customizableui/test/browser_934951_zoom_in_toolbar.js
@@ -1,82 +1,82 @@
-/* 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 kTimeoutInMS = 20000;
-
-// Bug 934951 - Zoom controls percentage label doesn't update when it's in the toolbar and you navigate.
-add_task(function() {
-  CustomizableUI.addWidgetToArea("zoom-controls", CustomizableUI.AREA_NAVBAR);
-  let tab1 = gBrowser.addTab("about:mozilla");
-  let tab2 = gBrowser.addTab("about:newtab");
-  gBrowser.selectedTab = tab1;
-  let zoomResetButton = document.getElementById("zoom-reset-button");
-
-  registerCleanupFunction(() => {
-    info("Cleaning up.");
-    CustomizableUI.reset();
-    gBrowser.removeTab(tab2);
-    gBrowser.removeTab(tab1);
-  });
-
-  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:mozilla");
-  let zoomChangePromise = promiseObserverNotification("browser-fullZoom:zoomChange");
-  FullZoom.enlarge();
-  yield zoomChangePromise;
-  is(parseInt(zoomResetButton.label, 10), 110, "Zoom is changed to 110% for about:mozilla");
-
-  let tabSelectPromise = promiseTabSelect();
-  gBrowser.selectedTab = tab2;
-  yield tabSelectPromise;
-  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:newtab");
-
-  gBrowser.selectedTab = tab1;
-  let zoomResetPromise = promiseObserverNotification("browser-fullZoom:zoomReset");
-  FullZoom.reset();
-  yield zoomResetPromise;
-  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:mozilla");
-
-  // Test zoom label updates while navigating pages in the same tab.
-  FullZoom.enlarge();
-  yield zoomChangePromise;
-  is(parseInt(zoomResetButton.label, 10), 110, "Zoom is changed to 110% for about:mozilla");
-  yield promiseTabLoadEvent(tab1, "about:home");
-  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:home");
-  yield promiseTabHistoryNavigation(-1, function() {
-    return parseInt(zoomResetButton.label, 10) == 110;
-  });
-  is(parseInt(zoomResetButton.label, 10), 110, "Zoom is still 110% for about:mozilla");
-});
-
-function promiseObserverNotification(aObserver) {
-  let deferred = Promise.defer();
-  function notificationCallback(e) {
-    Services.obs.removeObserver(notificationCallback, aObserver, false);
-    clearTimeout(timeoutId);
-    deferred.resolve();
-  };
-  let timeoutId = setTimeout(() => {
-    Services.obs.removeObserver(notificationCallback, aObserver, false);
-    deferred.reject("Notification '" + aObserver + "' did not happen within 20 seconds.");
-  }, kTimeoutInMS);
-  Services.obs.addObserver(notificationCallback, aObserver, false);
-  return deferred.promise;
-}
-
-function promiseTabSelect() {
-  let deferred = Promise.defer();
-  let container = window.gBrowser.tabContainer;
-  let timeoutId = setTimeout(() => {
-    container.removeEventListener("TabSelect", callback);
-    deferred.reject("TabSelect did not happen within 20 seconds");
-  }, kTimeoutInMS);
-  function callback(e) {
-    container.removeEventListener("TabSelect", callback);
-    clearTimeout(timeoutId);
-    executeSoon(deferred.resolve);
-  };
-  container.addEventListener("TabSelect", callback);
-  return deferred.promise;
-}
+/* 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 kTimeoutInMS = 20000;
+
+// Bug 934951 - Zoom controls percentage label doesn't update when it's in the toolbar and you navigate.
+add_task(function() {
+  CustomizableUI.addWidgetToArea("zoom-controls", CustomizableUI.AREA_NAVBAR);
+  let tab1 = gBrowser.addTab("about:mozilla");
+  let tab2 = gBrowser.addTab("about:newtab");
+  gBrowser.selectedTab = tab1;
+  let zoomResetButton = document.getElementById("zoom-reset-button");
+
+  registerCleanupFunction(() => {
+    info("Cleaning up.");
+    CustomizableUI.reset();
+    gBrowser.removeTab(tab2);
+    gBrowser.removeTab(tab1);
+  });
+
+  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:mozilla");
+  let zoomChangePromise = promiseObserverNotification("browser-fullZoom:zoomChange");
+  FullZoom.enlarge();
+  yield zoomChangePromise;
+  is(parseInt(zoomResetButton.label, 10), 110, "Zoom is changed to 110% for about:mozilla");
+
+  let tabSelectPromise = promiseTabSelect();
+  gBrowser.selectedTab = tab2;
+  yield tabSelectPromise;
+  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:newtab");
+
+  gBrowser.selectedTab = tab1;
+  let zoomResetPromise = promiseObserverNotification("browser-fullZoom:zoomReset");
+  FullZoom.reset();
+  yield zoomResetPromise;
+  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:mozilla");
+
+  // Test zoom label updates while navigating pages in the same tab.
+  FullZoom.enlarge();
+  yield zoomChangePromise;
+  is(parseInt(zoomResetButton.label, 10), 110, "Zoom is changed to 110% for about:mozilla");
+  yield promiseTabLoadEvent(tab1, "about:home");
+  is(parseInt(zoomResetButton.label, 10), 100, "Default zoom is 100% for about:home");
+  yield promiseTabHistoryNavigation(-1, function() {
+    return parseInt(zoomResetButton.label, 10) == 110;
+  });
+  is(parseInt(zoomResetButton.label, 10), 110, "Zoom is still 110% for about:mozilla");
+});
+
+function promiseObserverNotification(aObserver) {
+  let deferred = Promise.defer();
+  function notificationCallback(e) {
+    Services.obs.removeObserver(notificationCallback, aObserver, false);
+    clearTimeout(timeoutId);
+    deferred.resolve();
+  };
+  let timeoutId = setTimeout(() => {
+    Services.obs.removeObserver(notificationCallback, aObserver, false);
+    deferred.reject("Notification '" + aObserver + "' did not happen within 20 seconds.");
+  }, kTimeoutInMS);
+  Services.obs.addObserver(notificationCallback, aObserver, false);
+  return deferred.promise;
+}
+
+function promiseTabSelect() {
+  let deferred = Promise.defer();
+  let container = window.gBrowser.tabContainer;
+  let timeoutId = setTimeout(() => {
+    container.removeEventListener("TabSelect", callback);
+    deferred.reject("TabSelect did not happen within 20 seconds");
+  }, kTimeoutInMS);
+  function callback(e) {
+    container.removeEventListener("TabSelect", callback);
+    clearTimeout(timeoutId);
+    executeSoon(deferred.resolve);
+  };
+  container.addEventListener("TabSelect", callback);
+  return deferred.promise;
+}
--- a/browser/components/customizableui/test/browser_938980_navbar_collapsed.js
+++ b/browser/components/customizableui/test/browser_938980_navbar_collapsed.js
@@ -1,122 +1,122 @@
-/* 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";
-
-let bookmarksToolbar = document.getElementById("PersonalToolbar");
-let navbar = document.getElementById("nav-bar");
-let tabsToolbar = document.getElementById("TabsToolbar");
-
-// Customization reset should restore visibility to default-visible toolbars.
-add_task(function() {
-  is(navbar.collapsed, false, "Test should start with navbar visible");
-  setToolbarVisibility(navbar, false);
-  is(navbar.collapsed, true, "navbar should be hidden now");
-
-  yield resetCustomization();
-
-  is(navbar.collapsed, false, "Customization reset should restore visibility to the navbar");
-});
-
-// Customization reset should restore collapsed-state to default-collapsed toolbars.
-add_task(function() {
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
-
-  is(bookmarksToolbar.collapsed, true, "Test should start with bookmarks toolbar collapsed");
-  is(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should have height=0");
-  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
-  is(navbar.collapsed, false, "The nav-bar should be shown by default");
-
-  setToolbarVisibility(bookmarksToolbar, true);
-  setToolbarVisibility(navbar, false);
-  isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should be visible now");
-  ok(navbar.getBoundingClientRect().height <= 1, "navbar should have height=0 or 1 (due to border)");
-  is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
-
-  yield startCustomizing();
-  gCustomizeMode.reset();
-  yield waitForCondition(function() !gCustomizeMode.resetting);
-  yield endCustomizing();
-
-  is(bookmarksToolbar.collapsed, true, "Customization reset should restore collapsed-state to the bookmarks toolbar");
-  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
-  is(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should have height=0 after reset");
-  ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
-});
-
-// Check that the menubar will be collapsed by resetting, if the platform supports it.
-add_task(function() {
-  let menubar = document.getElementById("toolbar-menubar");
-  const canMenubarCollapse = CustomizableUI.isToolbarDefaultCollapsed(menubar.id);
-  if (!canMenubarCollapse) {
-    return;
-  }
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
-
-  is(menubar.getBoundingClientRect().height, 0, "menubar should be hidden by default");
-  setToolbarVisibility(menubar, true);
-  isnot(menubar.getBoundingClientRect().height, 0, "menubar should be visible now");
-
-  yield startCustomizing();
-  gCustomizeMode.reset();
-  yield waitForCondition(function() !gCustomizeMode.resetting);
-
-  is(menubar.getAttribute("autohide"), "true", "The menubar should have autohide=true after reset in customization mode");
-  is(menubar.getBoundingClientRect().height, 0, "The menubar should have height=0 after reset in customization mode");
-
-  yield endCustomizing();
-
-  is(menubar.getAttribute("autohide"), "true", "The menubar should have autohide=true after reset");
-  is(menubar.getBoundingClientRect().height, 0, "The menubar should have height=0 after reset");
-});
-
-// Customization reset should restore collapsed-state to default-collapsed toolbars.
-add_task(function() {
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
-  is(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should have height=0");
-  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
-
-  setToolbarVisibility(bookmarksToolbar, true);
-  isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should be visible now");
-  is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
-
-  yield startCustomizing();
-
-  isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should be visible before reset");
-  isnot(navbar.getBoundingClientRect().height, 0, "The navbar should be visible before reset");
-  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
-
-  gCustomizeMode.reset();
-  yield waitForCondition(function() !gCustomizeMode.resetting);
-
-  is(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should have height=0 after reset");
-  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
-  isnot(navbar.getBoundingClientRect().height, 0, "The navbar should still be visible after reset");
-  ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
-  yield endCustomizing();
-});
-
-// Check that the menubar will be collapsed by resetting, if the platform supports it.
-add_task(function() {
-  let menubar = document.getElementById("toolbar-menubar");
-  const canMenubarCollapse = CustomizableUI.isToolbarDefaultCollapsed(menubar.id);
-  if (!canMenubarCollapse) {
-    return;
-  }
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
-  yield startCustomizing();
-  let resetButton = document.getElementById("customization-reset-button");
-  is(resetButton.disabled, true, "The reset button should be disabled when in default state");
-
-  setToolbarVisibility(menubar, true);
-  is(resetButton.disabled, false, "The reset button should be enabled when not in default state")
-  ok(!CustomizableUI.inDefaultState, "No longer in default state when the menubar is shown");
-
-  yield gCustomizeMode.reset();
-
-  is(resetButton.disabled, true, "The reset button should be disabled when in default state");
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
-
-  yield endCustomizing();
-});
+/* 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";
+
+let bookmarksToolbar = document.getElementById("PersonalToolbar");
+let navbar = document.getElementById("nav-bar");
+let tabsToolbar = document.getElementById("TabsToolbar");
+
+// Customization reset should restore visibility to default-visible toolbars.
+add_task(function() {
+  is(navbar.collapsed, false, "Test should start with navbar visible");
+  setToolbarVisibility(navbar, false);
+  is(navbar.collapsed, true, "navbar should be hidden now");
+
+  yield resetCustomization();
+
+  is(navbar.collapsed, false, "Customization reset should restore visibility to the navbar");
+});
+
+// Customization reset should restore collapsed-state to default-collapsed toolbars.
+add_task(function() {
+  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
+
+  is(bookmarksToolbar.collapsed, true, "Test should start with bookmarks toolbar collapsed");
+  is(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should have height=0");
+  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
+  is(navbar.collapsed, false, "The nav-bar should be shown by default");
+
+  setToolbarVisibility(bookmarksToolbar, true);
+  setToolbarVisibility(navbar, false);
+  isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should be visible now");
+  ok(navbar.getBoundingClientRect().height <= 1, "navbar should have height=0 or 1 (due to border)");
+  is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
+
+  yield startCustomizing();
+  gCustomizeMode.reset();
+  yield waitForCondition(function() !gCustomizeMode.resetting);
+  yield endCustomizing();
+
+  is(bookmarksToolbar.collapsed, true, "Customization reset should restore collapsed-state to the bookmarks toolbar");
+  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
+  is(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should have height=0 after reset");
+  ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
+});
+
+// Check that the menubar will be collapsed by resetting, if the platform supports it.
+add_task(function() {
+  let menubar = document.getElementById("toolbar-menubar");
+  const canMenubarCollapse = CustomizableUI.isToolbarDefaultCollapsed(menubar.id);
+  if (!canMenubarCollapse) {
+    return;
+  }
+  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
+
+  is(menubar.getBoundingClientRect().height, 0, "menubar should be hidden by default");
+  setToolbarVisibility(menubar, true);
+  isnot(menubar.getBoundingClientRect().height, 0, "menubar should be visible now");
+
+  yield startCustomizing();
+  gCustomizeMode.reset();
+  yield waitForCondition(function() !gCustomizeMode.resetting);
+
+  is(menubar.getAttribute("autohide"), "true", "The menubar should have autohide=true after reset in customization mode");
+  is(menubar.getBoundingClientRect().height, 0, "The menubar should have height=0 after reset in customization mode");
+
+  yield endCustomizing();
+
+  is(menubar.getAttribute("autohide"), "true", "The menubar should have autohide=true after reset");
+  is(menubar.getBoundingClientRect().height, 0, "The menubar should have height=0 after reset");
+});
+
+// Customization reset should restore collapsed-state to default-collapsed toolbars.
+add_task(function() {
+  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
+  is(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should have height=0");
+  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
+
+  setToolbarVisibility(bookmarksToolbar, true);
+  isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should be visible now");
+  is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
+
+  yield startCustomizing();
+
+  isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should be visible before reset");
+  isnot(navbar.getBoundingClientRect().height, 0, "The navbar should be visible before reset");
+  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
+
+  gCustomizeMode.reset();
+  yield waitForCondition(function() !gCustomizeMode.resetting);
+
+  is(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should have height=0 after reset");
+  isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
+  isnot(navbar.getBoundingClientRect().height, 0, "The navbar should still be visible after reset");
+  ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
+  yield endCustomizing();
+});
+
+// Check that the menubar will be collapsed by resetting, if the platform supports it.
+add_task(function() {
+  let menubar = document.getElementById("toolbar-menubar");
+  const canMenubarCollapse = CustomizableUI.isToolbarDefaultCollapsed(menubar.id);
+  if (!canMenubarCollapse) {
+    return;
+  }
+  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
+  yield startCustomizing();
+  let resetButton = document.getElementById("customization-reset-button");
+  is(resetButton.disabled, true, "The reset button should be disabled when in default state");
+
+  setToolbarVisibility(menubar, true);
+  is(resetButton.disabled, false, "The reset button should be enabled when not in default state")
+  ok(!CustomizableUI.inDefaultState, "No longer in default state when the menubar is shown");
+
+  yield gCustomizeMode.reset();
+
+  is(resetButton.disabled, true, "The reset button should be disabled when in default state");
+  ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
+
+  yield endCustomizing();
+});
--- a/browser/components/customizableui/test/browser_940107_home_button_in_bookmarks_toolbar.js
+++ b/browser/components/customizableui/test/browser_940107_home_button_in_bookmarks_toolbar.js
@@ -1,41 +1,41 @@
-/* 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";
-
-// Bug 940107 - Home icon not displayed correctly when in bookmarks toolbar.
-add_task(function() {
-  ok(CustomizableUI.inDefaultState, "Should be in default state when test starts.");
-  let bookmarksToolbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-  bookmarksToolbar.collapsed = false;
-
-  let homeButton = document.getElementById("home-button");
-  ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the nav-bar");
-  ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
-
-  yield startCustomizing();
-  CustomizableUI.addWidgetToArea(homeButton.id, CustomizableUI.AREA_BOOKMARKS);
-  yield endCustomizing();
-  ok(homeButton.classList.contains("bookmark-item"), "Home Button should be displayed as a bookmarks item");
-  ok(!homeButton.classList.contains("toolbarbutton-1"), "Home Button should not be displayed as a nav-bar item");
-
-  gCustomizeMode.addToPanel(homeButton);
-  let panelShownPromise = promisePanelShown(window);
-  PanelUI.toggle();
-  yield panelShownPromise;
-
-  ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the panel");
-  ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
-
-  gCustomizeMode.addToToolbar(homeButton);
-  let panelHiddenPromise = promisePanelHidden(window);
-  PanelUI.toggle();
-  yield panelHiddenPromise;
-
-  ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the nav-bar");
-  ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
-
-  bookmarksToolbar.collapsed = true;
-  CustomizableUI.reset();
-});
+/* 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";
+
+// Bug 940107 - Home icon not displayed correctly when in bookmarks toolbar.
+add_task(function() {
+  ok(CustomizableUI.inDefaultState, "Should be in default state when test starts.");
+  let bookmarksToolbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+  bookmarksToolbar.collapsed = false;
+
+  let homeButton = document.getElementById("home-button");
+  ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the nav-bar");
+  ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
+
+  yield startCustomizing();
+  CustomizableUI.addWidgetToArea(homeButton.id, CustomizableUI.AREA_BOOKMARKS);
+  yield endCustomizing();
+  ok(homeButton.classList.contains("bookmark-item"), "Home Button should be displayed as a bookmarks item");
+  ok(!homeButton.classList.contains("toolbarbutton-1"), "Home Button should not be displayed as a nav-bar item");
+
+  gCustomizeMode.addToPanel(homeButton);
+  let panelShownPromise = promisePanelShown(window);
+  PanelUI.toggle();
+  yield panelShownPromise;
+
+  ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the panel");
+  ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
+
+  gCustomizeMode.addToToolbar(homeButton);
+  let panelHiddenPromise = promisePanelHidden(window);
+  PanelUI.toggle();
+  yield panelHiddenPromise;
+
+  ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the nav-bar");
+  ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
+
+  bookmarksToolbar.collapsed = true;
+  CustomizableUI.reset();
+});
--- a/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js
+++ b/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js
@@ -1,43 +1,43 @@
-/* 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";
-
-let originalWindowWidth;
-
-// Drag to overflow chevron should open the overflow panel.
-add_task(function*() {
-  originalWindowWidth = window.outerWidth;
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
-  ok(CustomizableUI.inDefaultState, "Should start in default state.");
-  let oldChildCount = navbar.customizationTarget.childElementCount;
-  window.resizeTo(400, window.outerHeight);
-  yield waitForCondition(() => navbar.hasAttribute("overflowing"));
-  ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
-
-  let widgetOverflowPanel = document.getElementById("widget-overflow");
-  let panelShownPromise = promisePanelElementShown(window, widgetOverflowPanel);
-  let identityBox = document.getElementById("identity-box");
-  let overflowChevron = document.getElementById("nav-bar-overflow-button");
-
-  // Listen for hiding immediately so we don't miss the event because of the
-  // async-ness of the 'shown' yield...
-  let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel);
-
-  ChromeUtils.synthesizeDrop(identityBox, overflowChevron, [], null);
-  yield panelShownPromise;
-
-  info("Overflow panel is shown.");
-
-  widgetOverflowPanel.hidePopup();
-  yield panelHiddenPromise;
-});
-
-add_task(function*() {
-  window.resizeTo(originalWindowWidth, window.outerHeight);
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
-  ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
-});
+/* 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";
+
+let originalWindowWidth;
+
+// Drag to overflow chevron should open the overflow panel.
+add_task(function*() {
+  originalWindowWidth = window.outerWidth;
+  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+  ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+  ok(CustomizableUI.inDefaultState, "Should start in default state.");
+  let oldChildCount = navbar.customizationTarget.childElementCount;
+  window.resizeTo(400, window.outerHeight);
+  yield waitForCondition(() => navbar.hasAttribute("overflowing"));
+  ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
+
+  let widgetOverflowPanel = document.getElementById("widget-overflow");
+  let panelShownPromise = promisePanelElementShown(window, widgetOverflowPanel);
+  let identityBox = document.getElementById("identity-box");
+  let overflowChevron = document.getElementById("nav-bar-overflow-button");
+
+  // Listen for hiding immediately so we don't miss the event because of the
+  // async-ness of the 'shown' yield...
+  let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel);
+
+  ChromeUtils.synthesizeDrop(identityBox, overflowChevron, [], null);
+  yield panelShownPromise;
+
+  info("Overflow panel is shown.");
+
+  widgetOverflowPanel.hidePopup();
+  yield panelHiddenPromise;
+});
+
+add_task(function*() {
+  window.resizeTo(originalWindowWidth, window.outerHeight);
+  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+  yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+  ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
+});
--- a/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js
+++ b/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js
@@ -1,67 +1,67 @@
-/* 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";
-
-add_task(function() {
-  const kNormalLabel = "Character Encoding";
-  CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
-  let characterEncoding = document.getElementById("characterencoding-button");
-  const kOriginalLabel = characterEncoding.getAttribute("label");
-  characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
-  CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_PANEL);
-
-  yield PanelUI.show();
-
-  is(characterEncoding.getAttribute("auto-hyphens"), "off",
-     "Hyphens should be disabled if the &shy; character is present in the label");
-  let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
-  let multilineTextCS = getComputedStyle(multilineText);
-  is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the &shy; character is present.")
-
-  let hiddenPanelPromise = promisePanelHidden(window);
-  PanelUI.toggle();
-  yield hiddenPanelPromise;
-
-  characterEncoding.setAttribute("label", kNormalLabel);
-
-  yield PanelUI.show();
-
-  isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
-        "Hyphens should not be disabled if the &shy; character is not present in the label");
-  multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
-  let multilineTextCS = getComputedStyle(multilineText);
-  is(multilineTextCS.MozHyphens, "auto", "-moz-hyphens should be set to auto by default.")
-
-  hiddenPanelPromise = promisePanelHidden(window);
-  PanelUI.toggle();
-  yield hiddenPanelPromise;
-
-  characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
-  CustomizableUI.removeWidgetFromArea("characterencoding-button");
-  yield startCustomizing();
-
-  isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
-        "Hyphens should not be disabled when the widget is in the palette");
-
-  gCustomizeMode.addToPanel(characterEncoding);
-  is(characterEncoding.getAttribute("auto-hyphens"), "off",
-     "Hyphens should be disabled if the &shy; character is present in the label in customization mode");
-  let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
-  let multilineTextCS = getComputedStyle(multilineText);
-  is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the &shy; character is present in customization mode.")
-
-  yield endCustomizing();
-
-  CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
-  ok(!characterEncoding.hasAttribute("auto-hyphens"),
-     "Removing the widget from the panel should remove the auto-hyphens attribute");
-
-  characterEncoding.setAttribute("label", kOriginalLabel);
-});
-
-add_task(function asyncCleanup() {
-  yield endCustomizing();
-  yield resetCustomization();
-});
+/* 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";
+
+add_task(function() {
+  const kNormalLabel = "Character Encoding";
+  CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
+  let characterEncoding = document.getElementById("characterencoding-button");
+  const kOriginalLabel = characterEncoding.getAttribute("label");
+  characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
+  CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_PANEL);
+
+  yield PanelUI.show();
+
+  is(characterEncoding.getAttribute("auto-hyphens"), "off",
+     "Hyphens should be disabled if the &shy; character is present in the label");
+  let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
+  let multilineTextCS = getComputedStyle(multilineText);
+  is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the &shy; character is present.")
+
+  let hiddenPanelPromise = promisePanelHidden(window);
+  PanelUI.toggle();
+  yield hiddenPanelPromise;
+
+  characterEncoding.setAttribute("label", kNormalLabel);
+
+  yield PanelUI.show();
+
+  isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
+        "Hyphens should not be disabled if the &shy; character is not present in the label");
+  multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
+  let multilineTextCS = getComputedStyle(multilineText);
+  is(multilineTextCS.MozHyphens, "auto", "-moz-hyphens should be set to auto by default.")
+
+  hiddenPanelPromise = promisePanelHidden(window);
+  PanelUI.toggle();
+  yield hiddenPanelPromise;
+
+  characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
+  CustomizableUI.removeWidgetFromArea("characterencoding-button");
+  yield startCustomizing();
+
+  isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
+        "Hyphens should not be disabled when the widget is in the palette");
+
+  gCustomizeMode.addToPanel(characterEncoding);
+  is(characterEncoding.getAttribute("auto-hyphens"), "off",
+     "Hyphens should be disabled if the &shy; character is present in the label in customization mode");
+  let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
+  let multilineTextCS = getComputedStyle(multilineText);
+  is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the &shy; character is present in customization mode.")
+
+  yield endCustomizing();
+
+  CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
+  ok(!characterEncoding.hasAttribute("auto-hyphens"),
+     "Removing the widget from the panel should remove the auto-hyphens attribute");
+
+  characterEncoding.setAttribute("label", kOriginalLabel);
+});
+
+add_task(function asyncCleanup() {
+  yield endCustomizing();
+  yield resetCustomization();
+});
--- a/browser/components/customizableui/test/browser_968447_bookmarks_toolbar_items_in_panel.js
+++ b/browser/components/customizableui/test/browser_968447_bookmarks_toolbar_items_in_panel.js
@@ -1,65 +1,65 @@
-/* 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";
-
-// Bug 968447 - The Bookmarks Toolbar Items doesn't appear as a
-// normal menu panel button in new windows.
-add_task(function() {
-  const buttonId = "bookmarks-toolbar-placeholder";
-  yield startCustomizing();
-  CustomizableUI.addWidgetToArea("personal-bookmarks", CustomizableUI.AREA_PANEL);
-  yield endCustomizing();
-
-  yield PanelUI.show();
-
-  let bookmarksToolbarPlaceholder = document.getElementById(buttonId);
-  ok(bookmarksToolbarPlaceholder.classList.contains("toolbarbutton-1"),
-     "Button should have toolbarbutton-1 class");
-  is(bookmarksToolbarPlaceholder.getAttribute("wrap"), "true",
-     "Button should have the 'wrap' attribute");
-
-  info("Waiting for panel to close");
-  let panelHiddenPromise = promisePanelHidden(window);
-  PanelUI.hide();
-  yield panelHiddenPromise;
-
-  info("Waiting for window to open");
-  let newWin = yield openAndLoadWindow({}, true);
-
-  info("Waiting for panel in new window to open");
-  let hideTrace = function() {
-    info(new Error().stack);
-    info("Panel was hidden.");
-  };
-  newWin.PanelUI.panel.addEventListener("popuphidden", hideTrace);
-
-  yield newWin.PanelUI.show();
-  let newWinBookmarksToolbarPlaceholder = newWin.document.getElementById(buttonId);
-  ok(newWinBookmarksToolbarPlaceholder.classList.contains("toolbarbutton-1"),
-     "Button in new window should have toolbarbutton-1 class");
-  is(newWinBookmarksToolbarPlaceholder.getAttribute("wrap"), "true",
-     "Button in new window should have 'wrap' attribute");
-
-  newWin.PanelUI.panel.removeEventListener("popuphidden", hideTrace);
-  //XXXgijs on Linux, we're sometimes seeing the panel being hidden early
-  // in the newly created window, probably because something else steals focus.
-  if (newWin.PanelUI.panel.state != "closed") {
-    info("Panel is still open in new window, waiting for it to close");
-    panelHiddenPromise = promisePanelHidden(newWin);
-    newWin.PanelUI.hide();
-    yield panelHiddenPromise;
-  } else {
-    info("panel was already closed");
-  }
-
-  info("Waiting for new window to close");
-  yield promiseWindowClosed(newWin);
-});
-
-add_task(function asyncCleanUp() {
-  yield endCustomizing();
-  CustomizableUI.reset();
-});
-
+/* 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";
+
+// Bug 968447 - The Bookmarks Toolbar Items doesn't appear as a
+// normal menu panel button in new windows.
+add_task(function() {
+  const buttonId = "bookmarks-toolbar-placeholder";
+  yield startCustomizing();
+  CustomizableUI.addWidgetToArea("personal-bookmarks", CustomizableUI.AREA_PANEL);
+  yield endCustomizing();
+
+  yield PanelUI.show();
+
+  let bookmarksToolbarPlaceholder = document.getElementById(buttonId);
+  ok(bookmarksToolbarPlaceholder.classList.contains("toolbarbutton-1"),
+     "Button should have toolbarbutton-1 class");
+  is(bookmarksToolbarPlaceholder.getAttribute("wrap"), "true",
+     "Button should have the 'wrap' attribute");
+
+  info("Waiting for panel to close");
+  let panelHiddenPromise = promisePanelHidden(window);
+  PanelUI.hide();
+  yield panelHiddenPromise;
+
+  info("Waiting for window to open");
+  let newWin = yield openAndLoadWindow({}, true);
+
+  info("Waiting for panel in new window to open");
+  let hideTrace = function() {
+    info(new Error().stack);
+    info("Panel was hidden.");
+  };
+  newWin.PanelUI.panel.addEventListener("popuphidden", hideTrace);
+
+  yield newWin.PanelUI.show();
+  let newWinBookmarksToolbarPlaceholder = newWin.document.getElementById(buttonId);
+  ok(newWinBookmarksToolbarPlaceholder.classList.contains("toolbarbutton-1"),
+     "Button in new window should have toolbarbutton-1 class");
+  is(newWinBookmarksToolbarPlaceholder.getAttribute("wrap"), "true",
+     "Button in new window should have 'wrap' attribute");
+
+  newWin.PanelUI.panel.removeEventListener("popuphidden", hideTrace);
+  //XXXgijs on Linux, we're sometimes seeing the panel being hidden early
+  // in the newly created window, probably because something else steals focus.
+  if (newWin.PanelUI.panel.state != "closed") {
+    info("Panel is still open in new window, waiting for it to close");
+    panelHiddenPromise = promisePanelHidden(newWin);
+    newWin.PanelUI.hide();
+    yield panelHiddenPromise;
+  } else {
+    info("panel was already closed");
+  }
+
+  info("Waiting for new window to close");
+  yield promiseWindowClosed(newWin);
+});
+
+add_task(function asyncCleanUp() {
+  yield endCustomizing();
+  CustomizableUI.reset();
+});
+
--- a/browser/components/customizableui/test/browser_970511_undo_restore_default.js
+++ b/browser/components/customizableui/test/browser_970511_undo_restore_default.js
@@ -1,107 +1,107 @@
-/* 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";
-
-// Restoring default should show an "undo" option which undoes the restoring operation.
-add_task(function() {
-  let homeButtonId = "home-button";
-  CustomizableUI.removeWidgetFromArea(homeButtonId);
-  yield startCustomizing();
-  ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
-  is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
-  let undoResetButton = document.getElementById("customization-undo-reset-button");
-  is(undoResetButton.hidden, true, "The undo button is hidden before reset");
-
-  yield gCustomizeMode.reset();
-
-  ok(CustomizableUI.inDefaultState, "In default state after reset");
-  is(undoResetButton.hidden, false, "The undo button is visible after reset");
-
-  undoResetButton.click();
-  yield waitForCondition(function() !gCustomizeMode.resetting);
-  ok(!CustomizableUI.inDefaultState, "Not in default state after reset-undo");
-  is(undoResetButton.hidden, true, "The undo button is hidden after clicking on the undo button");
-  is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
-
-  yield gCustomizeMode.reset();
-});
-
-// Performing an action after a reset will hide the reset button.
-add_task(function() {
-  let homeButtonId = "home-button";
-  CustomizableUI.removeWidgetFromArea(homeButtonId);
-  ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
-  is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
-  let undoResetButton = document.getElementById("customization-undo-reset-button");
-  is(undoResetButton.hidden, true, "The undo button is hidden before reset");
-
-  yield gCustomizeMode.reset();
-
-  ok(CustomizableUI.inDefaultState, "In default state after reset");
-  is(undoResetButton.hidden, false, "The undo button is visible after reset");
-
-  CustomizableUI.addWidgetToArea(homeButtonId, CustomizableUI.AREA_PANEL);
-  is(undoResetButton.hidden, true, "The undo button is hidden after another change");
-});
-
-// "Restore defaults", exiting customize, and re-entering shouldn't show the Undo button
-add_task(function() {
-  let undoResetButton = document.getElementById("customization-undo-reset-button");
-  is(undoResetButton.hidden, true, "The undo button is hidden before a reset");
-  ok(!CustomizableUI.inDefaultState, "The browser should not be in default state");
-  yield gCustomizeMode.reset();
-
-  is(undoResetButton.hidden, false, "The undo button is visible after a reset");
-  yield endCustomizing();
-  yield startCustomizing();
-  is(undoResetButton.hidden, true, "The undo reset button should be hidden after entering customization mode");
-});
-
-// Bug 971626 - Restore Defaults should collapse the Title Bar
-add_task(function() {
-  if (Services.appinfo.OS != "WINNT" &&
-      Services.appinfo.OS != "Darwin") {
-    return;
-  }
-  let prefName = "browser.tabs.drawInTitlebar";
-  let defaultValue = Services.prefs.getBoolPref(prefName);
-  let restoreDefaultsButton = document.getElementById("customization-reset-button");
-  let titleBarButton = document.getElementById("customization-titlebar-visibility-button");
-  let undoResetButton = document.getElementById("customization-undo-reset-button");
-  ok(CustomizableUI.inDefaultState, "Should be in default state at start of test");
-  ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled when in default state");
-  is(titleBarButton.hasAttribute("checked"), !defaultValue, "Title bar button should reflect pref value");
-  is(undoResetButton.hidden, true, "Undo reset button should be hidden at start of test");
-
-  Services.prefs.setBoolPref(prefName, !defaultValue);
-  ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled when pref changed");
-  is(titleBarButton.hasAttribute("checked"), defaultValue, "Title bar button should reflect changed pref value");
-  ok(!CustomizableUI.inDefaultState, "With titlebar flipped, no longer default");
-  is(undoResetButton.hidden, true, "Undo reset button should be hidden after pref change");
-
-  yield gCustomizeMode.reset();
-  ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled after reset");
-  is(titleBarButton.hasAttribute("checked"), !defaultValue, "Title bar button should reflect default value after reset");
-  is(Services.prefs.getBoolPref(prefName), defaultValue, "Reset should reset drawInTitlebar");
-  ok(CustomizableUI.inDefaultState, "In default state after titlebar reset");
-  is(undoResetButton.hidden, false, "Undo reset button should be visible after reset");
-  ok(!undoResetButton.disabled, "Undo reset button should be enabled after reset");
-
-  yield gCustomizeMode.undoReset();
-  ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled after undo-reset");
-  is(titleBarButton.hasAttribute("checked"), defaultValue, "Title bar button should reflect undo-reset value");
-  ok(!CustomizableUI.inDefaultState, "No longer in default state after undo");
-  is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value");
-  is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked");
-
-  Services.prefs.clearUserPref(prefName);
-  ok(CustomizableUI.inDefaultState, "In default state after pref cleared");
-  is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test");
-});
-
-add_task(function asyncCleanup() {
-  yield gCustomizeMode.reset();
-  yield endCustomizing();
-});
+/* 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";
+
+// Restoring default should show an "undo" option which undoes the restoring operation.
+add_task(function() {
+  let homeButtonId = "home-button";
+  CustomizableUI.removeWidgetFromArea(homeButtonId);
+  yield startCustomizing();
+  ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
+  is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
+  let undoResetButton = document.getElementById("customization-undo-reset-button");
+  is(undoResetButton.hidden, true, "The undo button is hidden before reset");
+
+  yield gCustomizeMode.reset();
+
+  ok(CustomizableUI.inDefaultState, "In default state after reset");
+  is(undoResetButton.hidden, false, "The undo button is visible after reset");
+
+  undoResetButton.click();
+  yield waitForCondition(function() !gCustomizeMode.resetting);
+  ok(!CustomizableUI.inDefaultState, "Not in default state after reset-undo");
+  is(undoResetButton.hidden, true, "The undo button is hidden after clicking on the undo button");
+  is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
+
+  yield gCustomizeMode.reset();
+});
+
+// Performing an action after a reset will hide the reset button.
+add_task(function() {
+  let homeButtonId = "home-button";
+  CustomizableUI.removeWidgetFromArea(homeButtonId);
+  ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
+  is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
+  let undoResetButton = document.getElementById("customization-undo-reset-button");
+  is(undoResetButton.hidden, true, "The undo button is hidden before reset");
+
+  yield gCustomizeMode.reset();
+
+  ok(CustomizableUI.inDefaultState, "In default state after reset");
+  is(undoResetButton.hidden, false, "The undo button is visible after reset");
+
+  CustomizableUI.addWidgetToArea(homeButtonId, CustomizableUI.AREA_PANEL);
+  is(undoResetButton.hidden, true, "The undo button is hidden after another change");
+});
+
+// "Restore defaults", exiting customize, and re-entering shouldn't show the Undo button
+add_task(function() {
+  let undoResetButton = document.getElementById("customization-undo-reset-button");
+  is(undoResetButton.hidden, true, "The undo button is hidden before a reset");
+  ok(!CustomizableUI.inDefaultState, "The browser should not be in default state");
+  yield gCustomizeMode.reset();
+
+  is(undoResetButton.hidden, false, "The undo button is visible after a reset");
+  yield endCustomizing();
+  yield startCustomizing();
+  is(undoResetButton.hidden, true, "The undo reset button should be hidden after entering customization mode");
+});
+
+// Bug 971626 - Restore Defaults should collapse the Title Bar
+add_task(function() {
+  if (Services.appinfo.OS != "WINNT" &&
+      Services.appinfo.OS != "Darwin") {
+    return;
+  }
+  let prefName = "browser.tabs.drawInTitlebar";
+  let defaultValue = Services.prefs.getBoolPref(prefName);
+  let restoreDefaultsButton = document.getElementById("customization-reset-button");
+  let titleBarButton = document.getElementById("customization-titlebar-visibility-button");
+  let undoResetButton = document.getElementById("customization-undo-reset-button");
+  ok(CustomizableUI.inDefaultState, "Should be in default state at start of test");
+  ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled when in default state");
+  is(titleBarButton.hasAttribute("checked"), !defaultValue, "Title bar button should reflect pref value");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden at start of test");
+
+  Services.prefs.setBoolPref(prefName, !defaultValue);
+  ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled when pref changed");
+  is(titleBarButton.hasAttribute("checked"), defaultValue, "Title bar button should reflect changed pref value");
+  ok(!CustomizableUI.inDefaultState, "With titlebar flipped, no longer default");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden after pref change");
+
+  yield gCustomizeMode.reset();
+  ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled after reset");
+  is(titleBarButton.hasAttribute("checked"), !defaultValue, "Title bar button should reflect default value after reset");
+  is(Services.prefs.getBoolPref(prefName), defaultValue, "Reset should reset drawInTitlebar");
+  ok(CustomizableUI.inDefaultState, "In default state after titlebar reset");
+  is(undoResetButton.hidden, false, "Undo reset button should be visible after reset");
+  ok(!undoResetButton.disabled, "Undo reset button should be enabled after reset");
+
+  yield gCustomizeMode.undoReset();
+  ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled after undo-reset");
+  is(titleBarButton.hasAttribute("checked"), defaultValue, "Title bar button should reflect undo-reset value");
+  ok(!CustomizableUI.inDefaultState, "No longer in default state after undo");
+  is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked");
+
+  Services.prefs.clearUserPref(prefName);
+  ok(CustomizableUI.inDefaultState, "In default state after pref cleared");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test");
+});
+
+add_task(function asyncCleanup() {
+  yield gCustomizeMode.reset();
+  yield endCustomizing();
+});
--- a/browser/components/customizableui/test/browser_980155_add_overflow_toolbar.js
+++ b/browser/components/customizableui/test/browser_980155_add_overflow_toolbar.js
@@ -1,51 +1,51 @@
-/* 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 kToolbarName = "test-new-overflowable-toolbar";
-const kTestWidgetPrefix = "test-widget-for-overflowable-toolbar-";
-
-add_task(function addOverflowingToolbar() {
-  let originalWindowWidth = window.outerWidth;
-
-  let widgetIds = [];
-  for (let i = 0; i < 10; i++) {
-    let id = kTestWidgetPrefix + i;
-    widgetIds.push(id);
-    let spec = {id: id, type: "button", removable: true, label: "test", tooltiptext: "" + i};
-    CustomizableUI.createWidget(spec);
-  }
-
-  let toolbarNode = createOverflowableToolbarWithPlacements(kToolbarName, widgetIds);
-  assertAreaPlacements(kToolbarName, widgetIds);
-
-  for (let id of widgetIds) {
-    document.getElementById(id).style.minWidth = "200px";
-  }
-
-  isnot(toolbarNode.overflowable, null, "Toolbar should have overflowable controller");
-  isnot(toolbarNode.customizationTarget, null, "Toolbar should have customization target");
-  isnot(toolbarNode.customizationTarget, toolbarNode, "Customization target should not be toolbar node");
-
-  let oldChildCount = toolbarNode.customizationTarget.childElementCount;
-  let overflowableList = document.getElementById(kToolbarName + "-overflow-list");
-  let oldOverflowCount = overflowableList.childElementCount;
-
-  isnot(oldChildCount, 0, "Toolbar should have non-overflowing widgets");
-
-  window.resizeTo(400, window.outerHeight);
-  yield waitForCondition(() => toolbarNode.hasAttribute("overflowing"));
-  ok(toolbarNode.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
-  ok(toolbarNode.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
-  ok(overflowableList.childElementCount > oldOverflowCount, "Should have more overflowed widgets.");
-
-  window.resizeTo(originalWindowWidth, window.outerHeight);
-});
-
-
-add_task(function asyncCleanup() {
-  removeCustomToolbars();
-  yield resetCustomization();
-});
+/* 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 kToolbarName = "test-new-overflowable-toolbar";
+const kTestWidgetPrefix = "test-widget-for-overflowable-toolbar-";
+
+add_task(function addOverflowingToolbar() {
+  let originalWindowWidth = window.outerWidth;
+
+  let widgetIds = [];
+  for (let i = 0; i < 10; i++) {
+    let id = kTestWidgetPrefix + i;
+    widgetIds.push(id);
+    let spec = {id: id, type: "button", removable: true, label: "test", tooltiptext: "" + i};
+    CustomizableUI.createWidget(spec);
+  }
+
+  let toolbarNode = createOverflowableToolbarWithPlacements(kToolbarName, widgetIds);
+  assertAreaPlacements(kToolbarName, widgetIds);
+
+  for (let id of widgetIds) {
+    document.getElementById(id).style.minWidth = "200px";
+  }
+
+  isnot(toolbarNode.overflowable, null, "Toolbar should have overflowable controller");
+  isnot(toolbarNode.customizationTarget, null, "Toolbar should have customization target");
+  isnot(toolbarNode.customizationTarget, toolbarNode, "Customization target should not be toolbar node");
+
+  let oldChildCount = toolbarNode.customizationTarget.childElementCount;
+  let overflowableList = document.getElementById(kToolbarName + "-overflow-list");
+  let oldOverflowCount = overflowableList.childElementCount;
+
+  isnot(oldChildCount, 0, "Toolbar should have non-overflowing widgets");
+
+  window.resizeTo(400, window.outerHeight);
+  yield waitForCondition(() => toolbarNode.hasAttribute("overflowing"));
+  ok(toolbarNode.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
+  ok(toolbarNode.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
+  ok(overflowableList.childElementCount > oldOverflowCount, "Should have more overflowed widgets.");
+
+  window.resizeTo(originalWindowWidth, window.outerHeight);
+});
+
+
+add_task(function asyncCleanup() {
+  removeCustomToolbars();
+  yield resetCustomization();
+});
--- a/browser/components/customizableui/test/browser_981305_separator_insertion.js
+++ b/browser/components/customizableui/test/browser_981305_separator_insertion.js
@@ -1,73 +1,73 @@
-/* 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";
-
-let tempElements = [];
-
-function insertTempItemsIntoMenu(parentMenu) {
-  // Last element is null to insert at the end:
-  let beforeEls = [parentMenu.firstChild, parentMenu.lastChild, null];
-  for (let i = 0; i < beforeEls.length; i++) {
-    let sep = document.createElement("menuseparator");
-    tempElements.push(sep);
-    parentMenu.insertBefore(sep, beforeEls[i]);
-    let menu = document.createElement("menu");
-    tempElements.push(menu);
-    parentMenu.insertBefore(menu, beforeEls[i]);
-    // And another separator for good measure:
-    sep = document.createElement("menuseparator");
-    tempElements.push(sep);
-    parentMenu.insertBefore(sep, beforeEls[i]);
-  }
-}
-
-function checkSeparatorInsertion(menuId, buttonId, subviewId) {
-  return function() {
-    info("Checking for duplicate separators in " + buttonId + " widget");
-    let menu = document.getElementById(menuId);
-    insertTempItemsIntoMenu(menu);
-
-    let placement = CustomizableUI.getPlacementOfWidget(buttonId);
-    let changedPlacement = false;
-    if (!placement || placement.area != CustomizableUI.AREA_PANEL) {
-      CustomizableUI.addWidgetToArea(buttonId, CustomizableUI.AREA_PANEL);
-      changedPlacement = true;
-    }
-    yield PanelUI.show();
-
-    let button = document.getElementById(buttonId);
-    button.click();
-
-    yield waitForCondition(() => !PanelUI.multiView.hasAttribute("transitioning"));
-    let subview = document.getElementById(subviewId);
-    ok(subview.firstChild, "Subview should have a kid");
-    is(subview.firstChild.localName, "toolbarbutton", "There should be no separators to start with");
-
-    for (let kid of subview.children) {
-      if (kid.localName == "menuseparator") {
-        ok(kid.previousSibling && kid.previousSibling.localName != "menuseparator",
-           "Separators should never have another separator next to them, and should never be the first node.");
-      }
-    }
-
-    let panelHiddenPromise = promisePanelHidden(window);
-    PanelUI.hide();
-    yield panelHiddenPromise;
-
-    if (changedPlacement) {
-      CustomizableUI.reset();
-    }
-  };
-}
-
-add_task(checkSeparatorInsertion("menuWebDeveloperPopup", "developer-button", "PanelUI-developerItems"));
-add_task(checkSeparatorInsertion("viewSidebarMenu", "sidebar-button", "PanelUI-sidebarItems"));
-
-registerCleanupFunction(function() {
-  for (let el of tempElements) {
-    el.remove();
-  }
-  tempElements = null;
-});
+/* 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";
+
+let tempElements = [];
+
+function insertTempItemsIntoMenu(parentMenu) {
+  // Last element is null to insert at the end:
+  let beforeEls = [parentMenu.firstChild, parentMenu.lastChild, null];
+  for (let i = 0; i < beforeEls.length; i++) {
+    let sep = document.createElement("menuseparator");
+    tempElements.push(sep);
+    parentMenu.insertBefore(sep, beforeEls[i]);
+    let menu = document.createElement("menu");
+    tempElements.push(menu);
+    parentMenu.insertBefore(menu, beforeEls[i]);
+    // And another separator for good measure:
+    sep = document.createElement("menuseparator");
+    tempElements.push(sep);
+    parentMenu.insertBefore(sep, beforeEls[i]);
+  }
+}
+
+function checkSeparatorInsertion(menuId, buttonId, subviewId) {
+  return function() {
+    info("Checking for duplicate separators in " + buttonId + " widget");
+    let menu = document.getElementById(menuId);
+    insertTempItemsIntoMenu(menu);
+
+    let placement = CustomizableUI.getPlacementOfWidget(buttonId);
+    let changedPlacement = false;
+    if (!placement || placement.area != CustomizableUI.AREA_PANEL) {
+      CustomizableUI.addWidgetToArea(buttonId, CustomizableUI.AREA_PANEL);
+      changedPlacement = true;
+    }
+    yield PanelUI.show();
+
+    let button = document.getElementById(buttonId);
+    button.click();
+
+    yield waitForCondition(() => !PanelUI.multiView.hasAttribute("transitioning"));
+    let subview = document.getElementById(subviewId);
+    ok(subview.firstChild, "Subview should have a kid");
+    is(subview.firstChild.localName, "toolbarbutton", "There should be no separators to start with");
+
+    for (let kid of subview.children) {
+      if (kid.localName == "menuseparator") {
+        ok(kid.previousSibling && kid.previousSibling.localName != "menuseparator",
+           "Separators should never have another separator next to them, and should never be the first node.");
+      }
+    }
+
+    let panelHiddenPromise = promisePanelHidden(window);
+    PanelUI.hide();
+    yield panelHiddenPromise;
+
+    if (changedPlacement) {
+      CustomizableUI.reset();
+    }
+  };
+}
+
+add_task(checkSeparatorInsertion("menuWebDeveloperPopup", "developer-button", "PanelUI-developerItems"));
+add_task(checkSeparatorInsertion("viewSidebarMenu", "sidebar-button", "PanelUI-sidebarItems"));
+
+registerCleanupFunction(function() {
+  for (let el of tempElements) {
+    el.remove();
+  }
+  tempElements = null;
+});
--- a/browser/components/customizableui/test/browser_982656_restore_defaults_builtin_widgets.js
+++ b/browser/components/customizableui/test/browser_982656_restore_defaults_builtin_widgets.js
@@ -1,57 +1,57 @@
-/* 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";
-
-// Restoring default should not place addon widgets back in the toolbar
-add_task(function() {
-  ok(CustomizableUI.inDefaultState, "Default state to begin");
-
-  const kWidgetId = "bug982656-add-on-widget-should-not-restore-to-default-area";
-  let widgetSpec = {
-    id: kWidgetId,
-    defaultArea: CustomizableUI.AREA_NAVBAR
-  };
-  CustomizableUI.createWidget(widgetSpec);
-
-  ok(!CustomizableUI.inDefaultState, "Not in default state after widget added");
-  is(CustomizableUI.getPlacementOfWidget(kWidgetId).area, CustomizableUI.AREA_NAVBAR, "Widget should be in navbar");
-
-  yield resetCustomization();
-
-  ok(CustomizableUI.inDefaultState, "Back in default state after reset");
-  is(CustomizableUI.getPlacementOfWidget(kWidgetId), null, "Widget now in palette");
-  CustomizableUI.destroyWidget(kWidgetId);
-});
-
-
-// resetCustomization shouldn't move 3rd party widgets out of custom toolbars
-add_task(function() {
-  const kToolbarId = "bug982656-toolbar-with-defaultset";
-  const kWidgetId = "bug982656-add-on-widget-should-restore-to-default-area-when-area-is-not-builtin";
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
-  let toolbar = createToolbarWithPlacements(kToolbarId);
-  ok(CustomizableUI.areas.indexOf(kToolbarId) != -1,
-     "Toolbar has been registered.");
-  is(CustomizableUI.getAreaType(kToolbarId), CustomizableUI.TYPE_TOOLBAR,
-     "Area should be registered as toolbar");
-
-  let widgetSpec = {
-    id: kWidgetId,
-    defaultArea: kToolbarId
-  };
-  CustomizableUI.createWidget(widgetSpec);
-
-  ok(!CustomizableUI.inDefaultState, "No longer in default state after toolbar is registered and visible.");
-  is(CustomizableUI.getPlacementOfWidget(kWidgetId).area, kToolbarId, "Widget should be in custom toolbar");
-
-  yield resetCustomization();
-  ok(CustomizableUI.inDefaultState, "Back in default state after reset");
-  is(CustomizableUI.getPlacementOfWidget(kWidgetId).area, kToolbarId, "Widget still in custom toolbar");
-  ok(toolbar.collapsed, "Custom toolbar should be collapsed after reset");
-
-  toolbar.remove();
-  CustomizableUI.destroyWidget(kWidgetId);
-  CustomizableUI.unregisterArea(kToolbarId);
-});
+/* 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";
+
+// Restoring default should not place addon widgets back in the toolbar
+add_task(function() {
+  ok(CustomizableUI.inDefaultState, "Default state to begin");
+
+  const kWidgetId = "bug982656-add-on-widget-should-not-restore-to-default-area";
+  let widgetSpec = {
+    id: kWidgetId,
+    defaultArea: CustomizableUI.AREA_NAVBAR
+  };
+  CustomizableUI.createWidget(widgetSpec);
+
+  ok(!CustomizableUI.inDefaultState, "Not in default state after widget added");
+  is(CustomizableUI.getPlacementOfWidget(kWidgetId).area, CustomizableUI.AREA_NAVBAR, "Widget should be in navbar");
+
+  yield resetCustomization();
+
+  ok(CustomizableUI.inDefaultState, "Back in default state after reset");
+  is(CustomizableUI.getPlacementOfWidget(kWidgetId), null, "Widget now in palette");
+  CustomizableUI.destroyWidget(kWidgetId);
+});
+
+
+// resetCustomization shouldn't move 3rd party widgets out of custom toolbars
+add_task(function() {
+  const kToolbarId = "bug982656-toolbar-with-defaultset";
+  const kWidgetId = "bug982656-add-on-widget-should-restore-to-default-area-when-area-is-not-builtin";
+  ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
+  let toolbar = createToolbarWithPlacements(kToolbarId);
+  ok(CustomizableUI.areas.indexOf(kToolbarId) != -1,
+     "Toolbar has been registered.");
+  is(CustomizableUI.getAreaType(kToolbarId), CustomizableUI.TYPE_TOOLBAR,
+     "Area should be registered as toolbar");
+
+  let widgetSpec = {
+    id: kWidgetId,
+    defaultArea: kToolbarId
+  };
+  CustomizableUI.createWidget(widgetSpec);
+
+  ok(!CustomizableUI.inDefaultState, "No longer in default state after toolbar is registered and visible.");
+  is(CustomizableUI.getPlacementOfWidget(kWidgetId).area, kToolbarId, "Widget should be in custom toolbar");
+
+  yield resetCustomization();
+  ok(CustomizableUI.inDefaultState, "Back in default state after reset");
+  is(CustomizableUI.getPlacementOfWidget(kWidgetId).area, kToolbarId, "Widget still in custom toolbar");
+  ok(toolbar.collapsed, "Custom toolbar should be collapsed after reset");
+
+  toolbar.remove();
+  CustomizableUI.destroyWidget(kWidgetId);
+  CustomizableUI.unregisterArea(kToolbarId);
+});
--- a/browser/components/customizableui/test/browser_984455_bookmarks_items_reparenting.js
+++ b/browser/components/customizableui/test/browser_984455_bookmarks_items_reparenting.js
@@ -1,267 +1,267 @@
-/* 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";
-
-let gNavBar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-let gOverflowList = document.getElementById(gNavBar.getAttribute("overflowtarget"));
-
-const kBookmarksButton = "bookmarks-menu-button";
-const kBookmarksItems = "personal-bookmarks";
-const kOriginalWindowWidth = window.outerWidth;
-const kSmallWidth = 400;
-
-/**
- * Helper function that opens the bookmarks menu, and returns a Promise that
- * resolves as soon as the menu is ready for interaction.
- */
-function bookmarksMenuPanelShown() {
-  let deferred = Promise.defer();
-  let bookmarksMenuPopup = document.getElementById("BMB_bookmarksPopup");
-  let onTransitionEnd = (e) => {
-    if (e.target == bookmarksMenuPopup) {
-      bookmarksMenuPopup.removeEventListener("transitionend", onTransitionEnd);
-      deferred.resolve();
-    }
-  }
-  bookmarksMenuPopup.addEventListener("transitionend", onTransitionEnd);
-  return deferred.promise;
-}
-
-/**
- * Checks that the placesContext menu is correctly attached to the
- * controller of some view. Returns a Promise that resolves as soon
- * as the context menu is closed.
- *
- * @param aItemWithContextMenu the item that we need to synthesize hte
- *        right click on in order to open the context menu.
- */
-function checkPlacesContextMenu(aItemWithContextMenu) {
-  return Task.spawn(function* () {
-    let contextMenu = document.getElementById("placesContext");
-    let newBookmarkItem = document.getElementById("placesContext_new:bookmark");
-    info("Waiting for context menu on " + aItemWithContextMenu.id);
-    let shownPromise = popupShown(contextMenu);
-    EventUtils.synthesizeMouseAtCenter(aItemWithContextMenu,
-                                       {type: "contextmenu", button: 2});
-    yield shownPromise;
-
-    ok(!newBookmarkItem.hasAttribute("disabled"),
-       "New bookmark item shouldn't be disabled");
-
-    info("Closing context menu");
-    yield closePopup(contextMenu);
-  });
-}
-
-/**
- * Opens the bookmarks menu panel, and then opens each of the "special"
- * submenus in that list. Then it checks that those submenu's context menus
- * are properly hooked up to a controller.
- */
-function checkSpecialContextMenus() {
-  return Task.spawn(function* () {
-    let contextMenu = document.getElementById("placesContext");
-    let bookmarksMenuButton = document.getElementById(kBookmarksButton);
-    let bookmarksMenuPopup = document.getElementById("BMB_bookmarksPopup");
-
-    const kSpecialItemIDs = {
-      "BMB_bookmarksToolbar": "BMB_bookmarksToolbarPopup",
-      "BMB_unsortedBookmarks": "BMB_unsortedBookmarksPopup",
-    };
-
-    // Open the bookmarks menu button context menus and ensure that
-    // they have the proper views attached.
-    let shownPromise = bookmarksMenuPanelShown();
-    let dropmarker = document.getAnonymousElementByAttribute(bookmarksMenuButton,
-                                                             "anonid", "dropmarker");
-    EventUtils.synthesizeMouseAtCenter(dropmarker, {});
-    info("Waiting for bookmarks menu popup to show after clicking dropmarker.")
-    yield shownPromise;
-
-    for (let menuID in kSpecialItemIDs) {
-      let menuItem = document.getElementById(menuID);
-      let menuPopup = document.getElementById(kSpecialItemIDs[menuID]);
-      info("Waiting to open menu for " + menuID);
-      let shownPromise = popupShown(menuPopup);
-      menuPopup.openPopup(menuItem, null, 0, 0, false, false, null);
-      yield shownPromise;
-
-      yield checkPlacesContextMenu(menuPopup);
-      info("Closing menu for " + menuID);
-      yield closePopup(menuPopup);
-    }
-
-    info("Closing bookmarks menu");
-    yield closePopup(bookmarksMenuPopup);
-  });
-}
-
-/**
- * Closes a focused popup by simulating pressing the Escape key,
- * and returns a Promise that resolves as soon as the popup is closed.
- *
- * @param aPopup the popup node to close.
- */
-function closePopup(aPopup) {
-  let hiddenPromise = popupHidden(aPopup);
-  EventUtils.synthesizeKey("VK_ESCAPE", {});
-  return hiddenPromise;
-}
-
-/**
- * Helper function that checks that the context menu of the
- * bookmark toolbar items chevron popup is correctly hooked up
- * to the controller of a view.
- */
-function checkBookmarksItemsChevronContextMenu() {
-  return Task.spawn(function*() {
-    let chevronPopup = document.getElementById("PlacesChevronPopup");
-    let shownPromise = popupShown(chevronPopup);
-    let chevron = document.getElementById("PlacesChevron");
-    EventUtils.synthesizeMouseAtCenter(chevron, {});
-    info("Waiting for bookmark toolbar item chevron popup to show");
-    yield shownPromise;
-    yield waitForCondition(() => {
-      for (let child of chevronPopup.children) {
-        if (child.style.visibility != "hidden")
-          return true;
-      }
-    });
-    yield checkPlacesContextMenu(chevronPopup);
-    info("Waiting for bookmark toolbar item chevron popup to close");
-    yield closePopup(chevronPopup);
-  });
-}
-
-/**
- * Forces the window to a width that causes the nav-bar to overflow
- * its contents. Returns a Promise that resolves as soon as the
- * overflowable nav-bar is showing its chevron.
- */
-function overflowEverything() {
-  info("Waiting for overflow");
-  window.resizeTo(kSmallWidth, window.outerHeight);
-  return waitForCondition(() => gNavBar.hasAttribute("overflowing"));
-}
-
-/**
- * Returns the window to its original size from the start of the test,
- * and returns a Promise that resolves when the nav-bar is no longer
- * overflowing.
- */
-function stopOverflowing() {
-  info("Waiting until we stop overflowing");
-  window.resizeTo(kOriginalWindowWidth, window.outerHeight);
-  return waitForCondition(() => !gNavBar.hasAttribute("overflowing"));
-}
-
-/**
- * Checks that an item with ID aID is overflowing in the nav-bar.
- *
- * @param aID the ID of the node to check for overflowingness.
- */
-function checkOverflowing(aID) {
-  ok(!gNavBar.querySelector("#" + aID),
-     "Item with ID " + aID + " should no longer be in the gNavBar");
-  let item = gOverflowList.querySelector("#" + aID);
-  ok(item, "Item with ID " + aID + " should be overflowing");
-  is(item.getAttribute("overflowedItem"), "true",
-     "Item with ID " + aID + " should have overflowedItem attribute");
-}
-
-/**
- * Checks that an item with ID aID is not overflowing in the nav-bar.
- *
- * @param aID the ID of hte node to check for non-overflowingness.
- */
-function checkNotOverflowing(aID) {
-  ok(!gOverflowList.querySelector("#" + aID),
-     "Item with ID " + aID + " should no longer be overflowing");
-  let item = gNavBar.querySelector("#" + aID);
-  ok(item, "Item with ID " + aID + " should be in the nav bar");
-  ok(!item.hasAttribute("overflowedItem"),
-     "Item with ID " + aID + " should not have overflowedItem attribute");
-}
-
-/**
- * Test that overflowing the bookmarks menu button doesn't break the
- * context menus for the Unsorted and Bookmarks Toolbar menu items.
- */
-add_task(function* testOverflowingBookmarksButtonContextMenu() {
-  ok(!gNavBar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
-  ok(CustomizableUI.inDefaultState, "Should start in default state.");
-
-  // Open the Unsorted and Bookmarks Toolbar context menus and ensure
-  // that they have views attached.
-  yield checkSpecialContextMenus();
-
-  yield overflowEverything();
-  checkOverflowing(kBookmarksButton);
-
-  yield stopOverflowing();
-  checkNotOverflowing(kBookmarksButton);
-
-  yield checkSpecialContextMenus();
-});
-
-/**
- * Test that the bookmarks toolbar items context menu still works if moved
- * to the menu from the overflow panel, and then back to the toolbar.
- */
-add_task(function* testOverflowingBookmarksItemsContextMenu() {
-  info("Ensuring panel is ready.");
-  yield PanelUI.ensureReady();
-
-  let bookmarksToolbarItems = document.getElementById(kBookmarksItems);
-  gCustomizeMode.addToToolbar(bookmarksToolbarItems);
-  yield checkPlacesContextMenu(bookmarksToolbarItems);
-
-  yield overflowEverything();
-  checkOverflowing(kBookmarksItems)
-
-  gCustomizeMode.addToPanel(bookmarksToolbarItems);
-
-  yield stopOverflowing();
-
-  gCustomizeMode.addToToolbar(bookmarksToolbarItems);
-  yield checkPlacesContextMenu(bookmarksToolbarItems);
-});
-
-/**
- * Test that overflowing the bookmarks toolbar items doesn't cause the
- * context menu in the bookmarks toolbar items chevron to stop working.
- */
-add_task(function* testOverflowingBookmarksItemsChevronContextMenu() {
-  // If it's not already there, let's move the bookmarks toolbar items to
-  // the nav-bar.
-  let bookmarksToolbarItems = document.getElementById(kBookmarksItems);
-  gCustomizeMode.addToToolbar(bookmarksToolbarItems);
-
-  // We make the PlacesToolbarItems element be super tiny in order to force
-  // the bookmarks toolbar items into overflowing and making the chevron
-  // show itself.
-  let placesToolbarItems = document.getElementById("PlacesToolbarItems");
-  let placesChevron = document.getElementById("PlacesChevron");
-  placesToolbarItems.style.maxWidth = "10px";
-  info("Waiting for chevron to no longer be collapsed");
-  yield waitForCondition(() => !placesChevron.collapsed);
-
-  yield checkBookmarksItemsChevronContextMenu();
-
-  yield overflowEverything();
-  checkOverflowing(kBookmarksItems);
-
-  yield stopOverflowing();
-  checkNotOverflowing(kBookmarksItems);
-
-  yield checkBookmarksItemsChevronContextMenu();
-
-  placesToolbarItems.style.removeProperty("max-width");
-});
-
-add_task(function* asyncCleanup() {
-  window.resizeTo(kOriginalWindowWidth, window.outerHeight);
-  yield resetCustomization();
-});
+/* 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";
+
+let gNavBar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+let gOverflowList = document.getElementById(gNavBar.getAttribute("overflowtarget"));
+
+const kBookmarksButton = "bookmarks-menu-button";
+const kBookmarksItems = "personal-bookmarks";
+const kOriginalWindowWidth = window.outerWidth;
+const kSmallWidth = 400;
+
+/**
+ * Helper function that opens the bookmarks menu, and returns a Promise that
+ * resolves as soon as the menu is ready for interaction.
+ */
+function bookmarksMenuPanelShown() {
+  let deferred = Promise.defer();
+  let bookmarksMenuPopup = document.getElementById("BMB_bookmarksPopup");
+  let onTransitionEnd = (e) => {
+    if (e.target == bookmarksMenuPopup) {
+      bookmarksMenuPopup.removeEventListener("transitionend", onTransitionEnd);
+      deferred.resolve();
+    }
+  }
+  bookmarksMenuPopup.addEventListener("transitionend", onTransitionEnd);
+  return deferred.promise;
+}
+
+/**
+ * Checks that the placesContext menu is correctly attached to the
+ * controller of some view. Returns a Promise that resolves as soon
+ * as the context menu is closed.
+ *
+ * @param aItemWithContextMenu the item that we need to synthesize hte
+ *        right click on in order to open the context menu.
+ */
+function checkPlacesContextMenu(aItemWithContextMenu) {
+  return Task.spawn(function* () {
+    let contextMenu = document.getElementById("placesContext");
+    let newBookmarkItem = document.getElementById("placesContext_new:bookmark");
+    info("Waiting for context menu on " + aItemWithContextMenu.id);
+    let shownPromise = popupShown(contextMenu);
+    EventUtils.synthesizeMouseAtCenter(aItemWithContextMenu,
+                                       {type: "contextmenu", button: 2});
+    yield shownPromise;
+
+    ok(!newBookmarkItem.hasAttribute("disabled"),
+       "New bookmark item shouldn't be disabled");
+
+    info("Closing context menu");
+    yield closePopup(contextMenu);
+  });
+}
+
+/**
+ * Opens the bookmarks menu panel, and then opens each of the "special"
+ * submenus in that list. Then it checks that those submenu's context menus
+ * are properly hooked up to a controller.
+ */
+function checkSpecialContextMenus() {
+  return Task.spawn(function* () {
+    let contextMenu = document.getElementById("placesContext");
+    let bookmarksMenuButton = document.getElementById(kBookmarksButton);
+    let bookmarksMenuPopup = document.getElementById("BMB_bookmarksPopup");
+
+    const kSpecialItemIDs = {
+      "BMB_bookmarksToolbar": "BMB_bookmarksToolbarPopup",
+      "BMB_unsortedBookmarks": "BMB_unsortedBookmarksPopup",
+    };
+
+    // Open the bookmarks menu button context menus and ensure that
+    // they have the proper views attached.
+    let shownPromise = bookmarksMenuPanelShown();
+    let dropmarker = document.getAnonymousElementByAttribute(bookmarksMenuButton,
+                                                             "anonid", "dropmarker");
+    EventUtils.synthesizeMouseAtCenter(dropmarker, {});
+    info("Waiting for bookmarks menu popup to show after clicking dropmarker.")
+    yield shownPromise;
+
+    for (let menuID in kSpecialItemIDs) {
+      let menuItem = document.getElementById(menuID);
+      let menuPopup = document.getElementById(kSpecialItemIDs[menuID]);
+      info("Waiting to open menu for " + menuID);
+      let shownPromise = popupShown(menuPopup);
+      menuPopup.openPopup(menuItem, null, 0, 0, false, false, null);
+      yield shownPromise;
+
+      yield checkPlacesContextMenu(menuPopup);
+      info("Closing menu for " + menuID);
+      yield closePopup(menuPopup);
+    }
+
+    info("Closing bookmarks menu");
+    yield closePopup(bookmarksMenuPopup);
+  });
+}
+
+/**
+ * Closes a focused popup by simulating pressing the Escape key,
+ * and returns a Promise that resolves as soon as the popup is closed.
+ *
+ * @param aPopup the popup node to close.
+ */
+function closePopup(aPopup) {
+  let hiddenPromise = popupHidden(aPopup);
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  return hiddenPromise;
+}
+
+/**
+ * Helper function that checks that the context menu of the
+ * bookmark toolbar items chevron popup is correctly hooked up
+ * to the controller of a view.
+ */
+function checkBookmarksItemsChevronContextMenu() {
+  return Task.spawn(function*() {
+    let chevronPopup = document.getElementById("PlacesChevronPopup");
+    let shownPromise = popupShown(chevronPopup);
+    let chevron = document.getElementById("PlacesChevron");
+    EventUtils.synthesizeMouseAtCenter(chevron, {});
+    info("Waiting for bookmark toolbar item chevron popup to show");
+    yield shownPromise;
+    yield waitForCondition(() => {
+      for (let child of chevronPopup.children) {
+        if (child.style.visibility != "hidden")
+          return true;
+      }
+    });
+    yield checkPlacesContextMenu(chevronPopup);
+    info("Waiting for bookmark toolbar item chevron popup to close");
+    yield closePopup(chevronPopup);
+  });
+}
+
+/**
+ * Forces the window to a width that causes the nav-bar to overflow
+ * its contents. Returns a Promise that resolves as soon as the
+ * overflowable nav-bar is showing its chevron.
+ */
+function overflowEverything() {
+  info("Waiting for overflow");
+  window.resizeTo(kSmallWidth, window.outerHeight);
+  return waitForCondition(() => gNavBar.hasAttribute("overflowing"));
+}
+
+/**
+ * Returns the window to its original size from the start of the test,
+ * and returns a Promise that resolves when the nav-bar is no longer
+ * overflowing.
+ */
+function stopOverflowing() {
+  info("Waiting until we stop overflowing");
+  window.resizeTo(kOriginalWindowWidth, window.outerHeight);
+  return waitForCondition(() => !gNavBar.hasAttribute("overflowing"));
+}
+
+/**
+ * Checks that an item with ID aID is overflowing in the nav-bar.
+ *
+ * @param aID the ID of the node to check for overflowingness.
+ */
+function checkOverflowing(aID) {
+  ok(!gNavBar.querySelector("#" + aID),
+     "Item with ID " + aID + " should no longer be in the gNavBar");
+  let item = gOverflowList.querySelector("#" + aID);
+  ok(item, "Item with ID " + aID + " should be overflowing");
+  is(item.getAttribute("overflowedItem"), "true",
+     "Item with ID " + aID + " should have overflowedItem attribute");
+}
+
+/**
+ * Checks that an item with ID aID is not overflowing in the nav-bar.
+ *
+ * @param aID the ID of hte node to check for non-overflowingness.
+ */
+function checkNotOverflowing(aID) {
+  ok(!gOverflowList.querySelector("#" + aID),
+     "Item with ID " + aID + " should no longer be overflowing");
+  let item = gNavBar.querySelector("#" + aID);
+  ok(item, "Item with ID " + aID + " should be in the nav bar");
+  ok(!item.hasAttribute("overflowedItem"),
+     "Item with ID " + aID + " should not have overflowedItem attribute");
+}
+
+/**
+ * Test that overflowing the bookmarks menu button doesn't break the
+ * context menus for the Unsorted and Bookmarks Toolbar menu items.
+ */
+add_task(function* testOverflowingBookmarksButtonContextMenu() {
+  ok(!gNavBar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+  ok(CustomizableUI.inDefaultState, "Should start in default state.");
+
+  // Open the Unsorted and Bookmarks Toolbar context menus and ensure
+  // that they have views attached.
+  yield checkSpecialContextMenus();
+
+  yield overflowEverything();
+  checkOverflowing(kBookmarksButton);
+
+  yield stopOverflowing();
+  checkNotOverflowing(kBookmarksButton);
+
+  yield checkSpecialContextMenus();
+});
+
+/**
+ * Test that the bookmarks toolbar items context menu still works if moved
+ * to the menu from the overflow panel, and then back to the toolbar.
+ */
+add_task(function* testOverflowingBookmarksItemsContextMenu() {
+  info("Ensuring panel is ready.");
+  yield PanelUI.ensureReady();
+
+  let bookmarksToolbarItems = document.getElementById(kBookmarksItems);
+  gCustomizeMode.addToToolbar(bookmarksToolbarItems);
+  yield checkPlacesContextMenu(bookmarksToolbarItems);
+
+  yield overflowEverything();
+  checkOverflowing(kBookmarksItems)
+
+  gCustomizeMode.addToPanel(bookmarksToolbarItems);
+
+  yield stopOverflowing();
+
+  gCustomizeMode.addToToolbar(bookmarksToolbarItems);
+  yield checkPlacesContextMenu(bookmarksToolbarItems);
+});
+
+/**
+ * Test that overflowing the bookmarks toolbar items doesn't cause the
+ * context menu in the bookmarks toolbar items chevron to stop working.
+ */
+add_task(function* testOverflowingBookmarksItemsChevronContextMenu() {
+  // If it's not already there, let's move the bookmarks toolbar items to
+  // the nav-bar.
+  let bookmarksToolbarItems = document.getElementById(kBookmarksItems);
+  gCustomizeMode.addToToolbar(bookmarksToolbarItems);
+
+  // We make the PlacesToolbarItems element be super tiny in order to force
+  // the bookmarks toolbar items into overflowing and making the chevron
+  // show itself.
+  let placesToolbarItems = document.getElementById("PlacesToolbarItems");
+  let placesChevron = document.getElementById("PlacesChevron");
+  placesToolbarItems.style.maxWidth = "10px";
+  info("Waiting for chevron to no longer be collapsed");
+  yield waitForCondition(() => !placesChevron.collapsed);
+
+  yield checkBookmarksItemsChevronContextMenu();
+
+  yield overflowEverything();
+  checkOverflowing(kBookmarksItems);
+
+  yield stopOverflowing();
+  checkNotOverflowing(kBookmarksItems);
+
+  yield checkBookmarksItemsChevronContextMenu();
+
+  placesToolbarItems.style.removeProperty("max-width");
+});
+
+add_task(function* asyncCleanup() {
+  window.resizeTo(kOriginalWindowWidth, window.outerHeight);
+  yield resetCustomization();
+});
--- a/browser/components/customizableui/test/browser_989751_subviewbutton_class.js
+++ b/browser/components/customizableui/test/browser_989751_subviewbutton_class.js
@@ -1,62 +1,62 @@
-/* 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 kCustomClass = "acustomclassnoonewilluse";
-let tempElement = null;
-
-function insertClassNameToMenuChildren(parentMenu) {
-  let el = parentMenu.querySelector("menuitem:first-of-type");
-  el.classList.add(kCustomClass);
-  tempElement = el;
-}
-
-function checkSubviewButtonClass(menuId, buttonId, subviewId) {
-  return function() {
-    info("Checking for items without the subviewbutton class in " + buttonId + " widget");
-    let menu = document.getElementById(menuId);
-    insertClassNameToMenuChildren(menu);
-
-    let placement = CustomizableUI.getPlacementOfWidget(buttonId);
-    let changedPlacement = false;
-    if (!placement || placement.area != CustomizableUI.AREA_PANEL) {
-      CustomizableUI.addWidgetToArea(buttonId, CustomizableUI.AREA_PANEL);
-      changedPlacement = true;
-    }
-    yield PanelUI.show();
-
-    let button = document.getElementById(buttonId);
-    button.click();
-
-    yield waitForCondition(() => !PanelUI.multiView.hasAttribute("transitioning"));
-    let subview = document.getElementById(subviewId);
-    ok(subview.firstChild, "Subview should have a kid");
-    let subviewchildren = subview.querySelectorAll("toolbarbutton");
-    for (let i = 0; i < subviewchildren.length; i++) {
-      let item = subviewchildren[i];
-      let itemReadable = "Item '" + item.label + "' (classes: " + item.className + ")";
-      ok(item.classList.contains("subviewbutton"), itemReadable + " should have the subviewbutton class.");
-      if (i == 0) {
-        ok(item.classList.contains(kCustomClass), itemReadable + " should still have its own class, too.");
-      }
-    }
-
-    let panelHiddenPromise = promisePanelHidden(window);
-    PanelUI.hide();
-    yield panelHiddenPromise;
-
-    if (changedPlacement) {
-      CustomizableUI.reset();
-    }
-  };
-}
-
-add_task(checkSubviewButtonClass("menuWebDeveloperPopup", "developer-button", "PanelUI-developerItems"));
-add_task(checkSubviewButtonClass("viewSidebarMenu", "sidebar-button", "PanelUI-sidebarItems"));
-
-registerCleanupFunction(function() {
-  tempElement.classList.remove(kCustomClass)
-  tempElement = null;
-});
+/* 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 kCustomClass = "acustomclassnoonewilluse";
+let tempElement = null;
+
+function insertClassNameToMenuChildren(parentMenu) {
+  let el = parentMenu.querySelector("menuitem:first-of-type");
+  el.classList.add(kCustomClass);
+  tempElement = el;
+}
+
+function checkSubviewButtonClass(menuId, buttonId, subviewId) {
+  return function() {
+    info("Checking for items without the subviewbutton class in " + buttonId + " widget");
+    let menu = document.getElementById(menuId);
+    insertClassNameToMenuChildren(menu);
+
+    let placement = CustomizableUI.getPlacementOfWidget(buttonId);
+    let changedPlacement = false;
+    if (!placement || placement.area != CustomizableUI.AREA_PANEL) {
+      CustomizableUI.addWidgetToArea(buttonId, CustomizableUI.AREA_PANEL);
+      changedPlacement = true;
+    }
+    yield PanelUI.show();
+
+    let button = document.getElementById(buttonId);
+    button.click();
+
+    yield waitForCondition(() => !PanelUI.multiView.hasAttribute("transitioning"));
+    let subview = document.getElementById(subviewId);
+    ok(subview.firstChild, "Subview should have a kid");
+    let subviewchildren = subview.querySelectorAll("toolbarbutton");
+    for (let i = 0; i < subviewchildren.length; i++) {
+      let item = subviewchildren[i];
+      let itemReadable = "Item '" + item.label + "' (classes: " + item.className + ")";
+      ok(item.classList.contains("subviewbutton"), itemReadable + " should have the subviewbutton class.");
+      if (i == 0) {
+        ok(item.classList.contains(kCustomClass), itemReadable + " should still have its own class, too.");
+      }
+    }
+
+    let panelHiddenPromise = promisePanelHidden(window);
+    PanelUI.hide();
+    yield panelHiddenPromise;
+
+    if (changedPlacement) {
+      CustomizableUI.reset();
+    }
+  };
+}
+
+add_task(checkSubviewButtonClass("menuWebDeveloperPopup", "developer-button", "PanelUI-developerItems"));
+add_task(checkSubviewButtonClass("viewSidebarMenu", "sidebar-button", "PanelUI-sidebarItems"));
+
+registerCleanupFunction(function() {
+  tempElement.classList.remove(kCustomClass)
+  tempElement = null;
+});
--- a/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
+++ b/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
@@ -1,112 +1,112 @@
-/* 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";
-
-// Calling CustomizableUI.registerArea twice with no
-// properties should not throw an exception.
-add_task(function() {
-  try {
-    CustomizableUI.registerArea("area-996364", {});
-    CustomizableUI.registerArea("area-996364", {});
-  } catch (ex) {
-    ok(false, ex.message);
-  }
-
-  CustomizableUI.unregisterArea("area-996364", true);
-});
-
-add_task(function() {
-  let exceptionThrown = false;
-  try {
-    CustomizableUI.registerArea("area-996364-2", {type: CustomizableUI.TYPE_TOOLBAR, defaultCollapsed: "false"});
-  } catch (ex) {
-    exceptionThrown = true;
-  }
-  ok(exceptionThrown, "defaultCollapsed is not allowed as an external property");
-
-  // No need to unregister the area because registration fails.
-});
-
-add_task(function() {
-  let exceptionThrown;
-  try {
-    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_TOOLBAR});
-    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_MENU_PANEL});
-  } catch (ex) {
-    exceptionThrown = ex;
-  }
-  ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-
-  CustomizableUI.unregisterArea("area-996364-3", true);
-});
-
-add_task(function() {
-  let exceptionThrown;
-  try {
-    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_MENU_PANEL});
-    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_TOOLBAR});
-  } catch (ex) {
-    exceptionThrown = ex;
-  }
-  ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-
-  CustomizableUI.unregisterArea("area-996364-4", true);
-});
-
-add_task(function() {
-  let exceptionThrown;
-  try {
-    CustomizableUI.registerArea("area-996899-1", { anchor: "PanelUI-menu-button",
-                                                   type: CustomizableUI.TYPE_MENU_PANEL,
-                                                   defaultPlacements: [] });
-    CustomizableUI.registerArea("area-996899-1", { anchor: "home-button",
-                                                   type: CustomizableUI.TYPE_MENU_PANEL,
-                                                   defaultPlacements: [] });
-  } catch (ex) {
-    exceptionThrown = ex;
-  }
-  ok(!exceptionThrown, "Changing anchors shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-  CustomizableUI.unregisterArea("area-996899-1", true);
-});
-
-add_task(function() {
-  let exceptionThrown;
-  try {
-    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
-                                                   type: CustomizableUI.TYPE_MENU_PANEL,
-                                                   defaultPlacements: [] });
-    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
-                                                   type: CustomizableUI.TYPE_MENU_PANEL,
-                                                   defaultPlacements: ["feed-button"] });
-  } catch (ex) {
-    exceptionThrown = ex;
-  }
-  ok(!exceptionThrown, "Changing defaultPlacements shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-  CustomizableUI.unregisterArea("area-996899-2", true);
-});
-
-add_task(function() {
-  let exceptionThrown;
-  try {
-    CustomizableUI.registerArea("area-996899-3", { legacy: true });
-    CustomizableUI.registerArea("area-996899-3", { legacy: false });
-  } catch (ex) {
-    exceptionThrown = ex;
-  }
-  ok(exceptionThrown, "Changing 'legacy' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-  CustomizableUI.unregisterArea("area-996899-3", true);
-});
-
-add_task(function() {
-  let exceptionThrown;
-  try {
-    CustomizableUI.registerArea("area-996899-4", { overflowable: true });
-    CustomizableUI.registerArea("area-996899-4", { overflowable: false });
-  } catch (ex) {
-    exceptionThrown = ex;
-  }
-  ok(exceptionThrown, "Changing 'overflowable' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-  CustomizableUI.unregisterArea("area-996899-4", true);
-});
+/* 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";
+
+// Calling CustomizableUI.registerArea twice with no
+// properties should not throw an exception.
+add_task(function() {
+  try {
+    CustomizableUI.registerArea("area-996364", {});
+    CustomizableUI.registerArea("area-996364", {});
+  } catch (ex) {
+    ok(false, ex.message);
+  }
+
+  CustomizableUI.unregisterArea("area-996364", true);
+});
+
+add_task(function() {
+  let exceptionThrown = false;
+  try {
+    CustomizableUI.registerArea("area-996364-2", {type: CustomizableUI.TYPE_TOOLBAR, defaultCollapsed: "false"});
+  } catch (ex) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "defaultCollapsed is not allowed as an external property");
+
+  // No need to unregister the area because registration fails.
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_TOOLBAR});
+    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_MENU_PANEL});
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+
+  CustomizableUI.unregisterArea("area-996364-3", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_MENU_PANEL});
+    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_TOOLBAR});
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+
+  CustomizableUI.unregisterArea("area-996364-4", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-1", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+    CustomizableUI.registerArea("area-996899-1", { anchor: "home-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(!exceptionThrown, "Changing anchors shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-1", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: ["feed-button"] });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(!exceptionThrown, "Changing defaultPlacements shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-2", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-3", { legacy: true });
+    CustomizableUI.registerArea("area-996899-3", { legacy: false });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Changing 'legacy' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-3", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-4", { overflowable: true });
+    CustomizableUI.registerArea("area-996899-4", { overflowable: false });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Changing 'overflowable' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-4", true);
+});
--- a/browser/components/dirprovider/tests/unit/head_dirprovider.js
+++ b/browser/components/dirprovider/tests/unit/head_dirprovider.js
@@ -1,20 +1,20 @@
-/* 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/. */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-var gProfD = do_get_profile();
-var gDirSvc = Cc["@mozilla.org/file/directory_service;1"].
-              getService(Ci.nsIProperties);
-var gPrefSvc = Cc["@mozilla.org/preferences-service;1"].
-               getService(Ci.nsIPrefBranch);
-
-function writeTestFile(aParent, aName) {
-  let file = aParent.clone();
-  file.append(aName);
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
-  return file;
-}
-
+/* 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/. */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+var gProfD = do_get_profile();
+var gDirSvc = Cc["@mozilla.org/file/directory_service;1"].
+              getService(Ci.nsIProperties);
+var gPrefSvc = Cc["@mozilla.org/preferences-service;1"].
+               getService(Ci.nsIPrefBranch);
+
+function writeTestFile(aParent, aName) {
+  let file = aParent.clone();
+  file.append(aName);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
+  return file;
+}
+
--- a/browser/components/dirprovider/tests/unit/test_bookmark_pref.js
+++ b/browser/components/dirprovider/tests/unit/test_bookmark_pref.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/. */
-
-// We need to run this test separately since DirectoryProvider persists BMarks
-
-function run_test() {
-  let dir = gProfD.clone();
-  let tfile = writeTestFile(dir, "bookmarkfile.test");
-  gPrefSvc.setCharPref("browser.bookmarks.file", tfile.path);
-
-  let bmarks = gDirSvc.get("BMarks", Ci.nsIFile);
-  do_check_true(tfile.equals(bmarks));
-}
+/* 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/. */
+
+// We need to run this test separately since DirectoryProvider persists BMarks
+
+function run_test() {
+  let dir = gProfD.clone();
+  let tfile = writeTestFile(dir, "bookmarkfile.test");
+  gPrefSvc.setCharPref("browser.bookmarks.file", tfile.path);
+
+  let bmarks = gDirSvc.get("BMarks", Ci.nsIFile);
+  do_check_true(tfile.equals(bmarks));
+}
--- a/browser/components/migration/src/nsIEHistoryEnumerator.cpp
+++ b/browser/components/migration/src/nsIEHistoryEnumerator.cpp
@@ -1,139 +1,139 @@
-/* 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 "nsIEHistoryEnumerator.h"
-
-#include <urlhist.h>
-#include <shlguid.h>
-
-#include "nsStringAPI.h"
-#include "nsNetUtil.h"
-#include "nsIVariant.h"
-#include "nsCOMArray.h"
-#include "nsArrayEnumerator.h"
-
-namespace {
-
-  PRTime FileTimeToPRTime(FILETIME* filetime)
-  {
-    SYSTEMTIME st;
-    ::FileTimeToSystemTime(filetime, &st);
-    PRExplodedTime prt;
-    prt.tm_year = st.wYear;
-    // SYSTEMTIME's day-of-month parameter is 1-based,
-    // PRExplodedTime's is 0-based.
-    prt.tm_month = st.wMonth - 1;
-    prt.tm_mday = st.wDay;
-    prt.tm_hour = st.wHour;
-    prt.tm_min = st.wMinute;
-    prt.tm_sec = st.wSecond;
-    prt.tm_usec = st.wMilliseconds * 1000;
-    prt.tm_wday = 0;
-    prt.tm_yday = 0;
-    prt.tm_params.tp_gmt_offset = 0;
-    prt.tm_params.tp_dst_offset = 0;
-    return PR_ImplodeTime(&prt);
-  }
-
-} // Anonymous namespace.
-
-////////////////////////////////////////////////////////////////////////////////
-//// nsIEHistoryEnumerator
-
-NS_IMPL_ISUPPORTS(nsIEHistoryEnumerator, nsISimpleEnumerator)
-
-nsIEHistoryEnumerator::nsIEHistoryEnumerator()
-{
-  ::CoInitialize(nullptr);  
-}
-
-nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
-{
-  ::CoUninitialize();
-}
-
-void
-nsIEHistoryEnumerator::EnsureInitialized()
-{
-  if (mURLEnumerator)
-    return;
-
-  HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
-                                  nullptr,
-                                  CLSCTX_INPROC_SERVER,
-                                  IID_IUrlHistoryStg2,
-                                  getter_AddRefs(mIEHistory));
-  if (FAILED(hr))
-    return;
-
-  hr = mIEHistory->EnumUrls(getter_AddRefs(mURLEnumerator));
-  if (FAILED(hr))
-    return;
-}
-
-NS_IMETHODIMP
-nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
-{
-  *_retval = false;
-
-  EnsureInitialized();
-  MOZ_ASSERT(mURLEnumerator, "Should have instanced an IE History URLEnumerator");
-  if (!mURLEnumerator)
-    return NS_OK;
-
-  STATURL statURL;
-  ULONG fetched;
-
-  // First argument is not implemented, so doesn't matter what we pass.
-  HRESULT hr = mURLEnumerator->Next(1, &statURL, &fetched);
-  if (FAILED(hr) || fetched != 1UL) {
-    // Reached the last entry.
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIURI> uri;
-  if (statURL.pwcsUrl) {
-    nsDependentString url(statURL.pwcsUrl);
-    nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
-    ::CoTaskMemFree(statURL.pwcsUrl);
-    if (NS_FAILED(rv)) {
-      // Got a corrupt or invalid URI, continue to the next entry.
-      return HasMoreElements(_retval);
-    }
-  }
-
-  nsDependentString title(statURL.pwcsTitle);
-
-  PRTime lastVisited = FileTimeToPRTime(&(statURL.ftLastVisited));
-
-  mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
-  MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
-  if (mCachedNextEntry) {
-    mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
-    mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
-    mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
-
-    *_retval = true;
-  }
-
-  if (statURL.pwcsTitle)
-    ::CoTaskMemFree(statURL.pwcsTitle);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsIEHistoryEnumerator::GetNext(nsISupports** _retval)
-{
-  *_retval = nullptr;
-
-  if (!mCachedNextEntry)
-    return NS_ERROR_FAILURE;
-
-  NS_ADDREF(*_retval = mCachedNextEntry);
-  // Release the cached entry, so it can't be returned twice.
-  mCachedNextEntry = nullptr;
-
-  return NS_OK;
-}
+/* 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 "nsIEHistoryEnumerator.h"
+
+#include <urlhist.h>
+#include <shlguid.h>
+
+#include "nsStringAPI.h"
+#include "nsNetUtil.h"
+#include "nsIVariant.h"
+#include "nsCOMArray.h"
+#include "nsArrayEnumerator.h"
+
+namespace {
+
+  PRTime FileTimeToPRTime(FILETIME* filetime)
+  {
+    SYSTEMTIME st;
+    ::FileTimeToSystemTime(filetime, &st);
+    PRExplodedTime prt;
+    prt.tm_year = st.wYear;
+    // SYSTEMTIME's day-of-month parameter is 1-based,
+    // PRExplodedTime's is 0-based.
+    prt.tm_month = st.wMonth - 1;
+    prt.tm_mday = st.wDay;
+    prt.tm_hour = st.wHour;
+    prt.tm_min = st.wMinute;
+    prt.tm_sec = st.wSecond;
+    prt.tm_usec = st.wMilliseconds * 1000;
+    prt.tm_wday = 0;
+    prt.tm_yday = 0;
+    prt.tm_params.tp_gmt_offset = 0;
+    prt.tm_params.tp_dst_offset = 0;
+    return PR_ImplodeTime(&prt);
+  }
+
+} // Anonymous namespace.
+
+////////////////////////////////////////////////////////////////////////////////
+//// nsIEHistoryEnumerator
+
+NS_IMPL_ISUPPORTS(nsIEHistoryEnumerator, nsISimpleEnumerator)
+
+nsIEHistoryEnumerator::nsIEHistoryEnumerator()
+{
+  ::CoInitialize(nullptr);  
+}
+
+nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
+{
+  ::CoUninitialize();
+}
+
+void
+nsIEHistoryEnumerator::EnsureInitialized()
+{
+  if (mURLEnumerator)
+    return;
+
+  HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
+                                  nullptr,
+                                  CLSCTX_INPROC_SERVER,
+                                  IID_IUrlHistoryStg2,
+                                  getter_AddRefs(mIEHistory));
+  if (FAILED(hr))
+    return;
+
+  hr = mIEHistory->EnumUrls(getter_AddRefs(mURLEnumerator));
+  if (FAILED(hr))
+    return;
+}
+
+NS_IMETHODIMP
+nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
+{
+  *_retval = false;
+
+  EnsureInitialized();
+  MOZ_ASSERT(mURLEnumerator, "Should have instanced an IE History URLEnumerator");
+  if (!mURLEnumerator)
+    return NS_OK;
+
+  STATURL statURL;
+  ULONG fetched;
+
+  // First argument is not implemented, so doesn't matter what we pass.
+  HRESULT hr = mURLEnumerator->Next(1, &statURL, &fetched);
+  if (FAILED(hr) || fetched != 1UL) {
+    // Reached the last entry.
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  if (statURL.pwcsUrl) {
+    nsDependentString url(statURL.pwcsUrl);
+    nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
+    ::CoTaskMemFree(statURL.pwcsUrl);
+    if (NS_FAILED(rv)) {
+      // Got a corrupt or invalid URI, continue to the next entry.
+      return HasMoreElements(_retval);
+    }
+  }
+
+  nsDependentString title(statURL.pwcsTitle);
+
+  PRTime lastVisited = FileTimeToPRTime(&(statURL.ftLastVisited));
+
+  mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
+  MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
+  if (mCachedNextEntry) {
+    mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
+    mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
+    mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
+
+    *_retval = true;
+  }
+
+  if (statURL.pwcsTitle)
+    ::CoTaskMemFree(statURL.pwcsTitle);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsIEHistoryEnumerator::GetNext(nsISupports** _retval)
+{
+  *_retval = nullptr;
+
+  if (!mCachedNextEntry)
+    return NS_ERROR_FAILURE;
+
+  NS_ADDREF(*_retval = mCachedNextEntry);
+  // Release the cached entry, so it can't be returned twice.
+  mCachedNextEntry = nullptr;
+
+  return NS_OK;
+}
--- a/browser/components/migration/src/nsIEHistoryEnumerator.h
+++ b/browser/components/migration/src/nsIEHistoryEnumerator.h
@@ -1,37 +1,37 @@
-/* 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/. */
-
-#ifndef iehistoryenumerator___h___
-#define iehistoryenumerator___h___
-
-#include <urlhist.h>
-
-#include "mozilla/Attributes.h"
-#include "nsISimpleEnumerator.h"
-#include "nsIWritablePropertyBag2.h"
-#include "nsAutoPtr.h"
-
-class nsIEHistoryEnumerator MOZ_FINAL : public nsISimpleEnumerator
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSISIMPLEENUMERATOR
-
-  nsIEHistoryEnumerator();
-
-private:
-  ~nsIEHistoryEnumerator();
-
-  /**
-   * Initializes the history reader, if needed.
-   */
-  void EnsureInitialized();
-
-  nsRefPtr<IUrlHistoryStg2> mIEHistory;
-  nsRefPtr<IEnumSTATURL> mURLEnumerator;
-
-  nsCOMPtr<nsIWritablePropertyBag2> mCachedNextEntry;
-};
-
-#endif
+/* 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/. */
+
+#ifndef iehistoryenumerator___h___
+#define iehistoryenumerator___h___
+
+#include <urlhist.h>
+
+#include "mozilla/Attributes.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIWritablePropertyBag2.h"
+#include "nsAutoPtr.h"
+
+class nsIEHistoryEnumerator MOZ_FINAL : public nsISimpleEnumerator
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISIMPLEENUMERATOR
+
+  nsIEHistoryEnumerator();
+
+private:
+  ~nsIEHistoryEnumerator();
+
+  /**
+   * Initializes the history reader, if needed.
+   */
+  void EnsureInitialized();
+
+  nsRefPtr<IUrlHistoryStg2> mIEHistory;
+  nsRefPtr<IEnumSTATURL> mURLEnumerator;
+
+  nsCOMPtr<nsIWritablePropertyBag2> mCachedNextEntry;
+};
+
+#endif
--- a/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
+++ b/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
@@ -1,176 +1,176 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-this.EXPORTED_SYMBOLS = ["RecentlyClosedTabsAndWindowsMenuUtils"];
-
-const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-var Ci = Components.interfaces;
-var Cc = Components.classes;
-var Cr = Components.results;
-var Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
-                                  "resource://gre/modules/PluralForm.jsm");
-
-let navigatorBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
-let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-
-this.RecentlyClosedTabsAndWindowsMenuUtils = {
-
-  /**
-  * Builds up a document fragment of UI items for the recently closed tabs.
-  * @param   aWindow
-  *          The window that the tabs were closed in.
-  * @param   aTagName
-  *          The tag name that will be used when creating the UI items.
-  * @param   aPrefixRestoreAll (defaults to false)
-  *          Whether the 'restore all tabs' item is suffixed or prefixed to the list.
-  *          If suffixed (the default) a separator will be inserted before it.
-  * @param   aRestoreAllLabel (defaults to "menuRestoreAllTabs.label")
-  *          Which localizable string to use for the 'restore all tabs' item.
-  * @returns A document fragment with UI items for each recently closed tab.
-  */
-  getTabsFragment: function(aWindow, aTagName, aPrefixRestoreAll=false,
-                            aRestoreAllLabel="menuRestoreAllTabs.label") {
-    let doc = aWindow.document;
-    let fragment = doc.createDocumentFragment();
-    if (ss.getClosedTabCount(aWindow) != 0) {
-      let closedTabs = JSON.parse(ss.getClosedTabData(aWindow));
-      for (let i = 0; i < closedTabs.length; i++) {
-        let element = doc.createElementNS(kNSXUL, aTagName);
-        element.setAttribute("label", closedTabs[i].title);
-        if (closedTabs[i].image) {
-          setImage(closedTabs[i], element);
-        }
-        element.setAttribute("value", i);
-        if (aTagName == "menuitem") {
-          element.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
-        }
-        element.setAttribute("oncommand", "undoCloseTab(" + i + ");");
-
-        // Set the targetURI attribute so it will be shown in tooltip and trigger
-        // onLinkHovered. SessionStore uses one-based indexes, so we need to
-        // normalize them.
-        let tabData = closedTabs[i].state;
-        let activeIndex = (tabData.index || tabData.entries.length) - 1;
-        if (activeIndex >= 0 && tabData.entries[activeIndex]) {
-          element.setAttribute("targetURI", tabData.entries[activeIndex].url);
-        }
-
-        element.addEventListener("click", this._undoCloseMiddleClick, false);
-        if (i == 0)
-          element.setAttribute("key", "key_undoCloseTab");
-        fragment.appendChild(element);
-      }
-
-      let restoreAllTabs = doc.createElementNS(kNSXUL, aTagName);
-      restoreAllTabs.classList.add("restoreallitem");
-      restoreAllTabs.setAttribute("label", navigatorBundle.GetStringFromName(aRestoreAllLabel));
-      restoreAllTabs.setAttribute("oncommand",
-              "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab();");
-      if (!aPrefixRestoreAll) {
-        fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
-        fragment.appendChild(restoreAllTabs);
-      } else {
-        fragment.insertBefore(restoreAllTabs, fragment.firstChild);
-      }
-    }
-    return fragment;
-  },
-
-  /**
-  * Builds up a document fragment of UI items for the recently closed windows.
-  * @param   aWindow
-  *          A window that can be used to create the elements and document fragment.
-  * @param   aTagName
-  *          The tag name that will be used when creating the UI items.
-  * @param   aPrefixRestoreAll (defaults to false)
-  *          Whether the 'restore all windows' item is suffixed or prefixed to the list.
-  *          If suffixed (the default) a separator will be inserted before it.
-  * @param   aRestoreAllLabel (defaults to "menuRestoreAllWindows.label")
-  *          Which localizable string to use for the 'restore all windows' item.
-  * @returns A document fragment with UI items for each recently closed window.
-  */
-  getWindowsFragment: function(aWindow, aTagName, aPrefixRestoreAll=false,
-                            aRestoreAllLabel="menuRestoreAllWindows.label") {
-    let closedWindowData = JSON.parse(ss.getClosedWindowData());
-    let fragment = aWindow.document.createDocumentFragment();
-    if (closedWindowData.length != 0) {
-      let menuLabelString = navigatorBundle.GetStringFromName("menuUndoCloseWindowLabel");
-      let menuLabelStringSingleTab =
-        navigatorBundle.GetStringFromName("menuUndoCloseWindowSingleTabLabel");
-
-      let doc = aWindow.document;
-      for (let i = 0; i < closedWindowData.length; i++) {
-        let undoItem = closedWindowData[i];
-        let otherTabsCount = undoItem.tabs.length - 1;
-        let label = (otherTabsCount == 0) ? menuLabelStringSingleTab
-                                          : PluralForm.get(otherTabsCount, menuLabelString);
-        let menuLabel = label.replace("#1", undoItem.title)
-                             .replace("#2", otherTabsCount);
-        let item = doc.createElementNS(kNSXUL, aTagName);
-        item.setAttribute("label", menuLabel);
-        let selectedTab = undoItem.tabs[undoItem.selected - 1];
-        if (selectedTab.image) {
-          setImage(selectedTab, item);
-        }
-        if (aTagName == "menuitem") {
-          item.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
-        }
-        item.setAttribute("oncommand", "undoCloseWindow(" + i + ");");
-
-        // Set the targetURI attribute so it will be shown in tooltip.
-        // SessionStore uses one-based indexes, so we need to normalize them.
-        let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
-        if (activeIndex >= 0 && selectedTab.entries[activeIndex])
-          item.setAttribute("targetURI", selectedTab.entries[activeIndex].url);
-
-        if (i == 0)
-          item.setAttribute("key", "key_undoCloseWindow");
-        fragment.appendChild(item);
-      }
-
-      // "Open All in Windows"
-      let restoreAllWindows = doc.createElementNS(kNSXUL, aTagName);
-      restoreAllWindows.classList.add("restoreallitem");
-      restoreAllWindows.setAttribute("label", navigatorBundle.GetStringFromName(aRestoreAllLabel));
-      restoreAllWindows.setAttribute("oncommand",
-        "for (var i = 0; i < " + closedWindowData.length + "; i++) undoCloseWindow();");
-      if (!aPrefixRestoreAll) {
-        fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
-        fragment.appendChild(restoreAllWindows);
-      } else {
-        fragment.insertBefore(restoreAllWindows, fragment.firstChild);
-      }
-    }
-    return fragment;
-  },
-
-
-  /**
-    * Re-open a closed tab and put it to the end of the tab strip.
-    * Used for a middle click.
-    * @param aEvent
-    *        The event when the user clicks the menu item
-    */
-  _undoCloseMiddleClick: function(aEvent) {
-    if (aEvent.button != 1)
-      return;
-
-    aEvent.view.undoCloseTab(aEvent.originalTarget.getAttribute("value"));
-    aEvent.view.gBrowser.moveTabToEnd();
-  },
-};
-
-function setImage(aItem, aElement) {
-  let iconURL = aItem.image;
-  // don't initiate a connection just to fetch a favicon (see bug 467828)
-  if (/^https?:/.test(iconURL))
-    iconURL = "moz-anno:favicon:" + iconURL;
-  aElement.setAttribute("image", iconURL);
-}
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+this.EXPORTED_SYMBOLS = ["RecentlyClosedTabsAndWindowsMenuUtils"];
+
+const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
+let navigatorBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
+this.RecentlyClosedTabsAndWindowsMenuUtils = {
+
+  /**
+  * Builds up a document fragment of UI items for the recently closed tabs.
+  * @param   aWindow
+  *          The window that the tabs were closed in.
+  * @param   aTagName
+  *          The tag name that will be used when creating the UI items.
+  * @param   aPrefixRestoreAll (defaults to false)
+  *          Whether the 'restore all tabs' item is suffixed or prefixed to the list.
+  *          If suffixed (the default) a separator will be inserted before it.
+  * @param   aRestoreAllLabel (defaults to "menuRestoreAllTabs.label")
+  *          Which localizable string to use for the 'restore all tabs' item.
+  * @returns A document fragment with UI items for each recently closed tab.
+  */
+  getTabsFragment: function(aWindow, aTagName, aPrefixRestoreAll=false,
+                            aRestoreAllLabel="menuRestoreAllTabs.label") {
+    let doc = aWindow.document;
+    let fragment = doc.createDocumentFragment();
+    if (ss.getClosedTabCount(aWindow) != 0) {
+      let closedTabs = JSON.parse(ss.getClosedTabData(aWindow));
+      for (let i = 0; i < closedTabs.length; i++) {
+        let element = doc.createElementNS(kNSXUL, aTagName);
+        element.setAttribute("label", closedTabs[i].title);
+        if (closedTabs[i].image) {
+          setImage(closedTabs[i], element);
+        }
+        element.setAttribute("value", i);
+        if (aTagName == "menuitem") {
+          element.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
+        }
+        element.setAttribute("oncommand", "undoCloseTab(" + i + ");");
+
+        // Set the targetURI attribute so it will be shown in tooltip and trigger
+        // onLinkHovered. SessionStore uses one-based indexes, so we need to
+        // normalize them.
+        let tabData = closedTabs[i].state;
+        let activeIndex = (tabData.index || tabData.entries.length) - 1;
+        if (activeIndex >= 0 && tabData.entries[activeIndex]) {
+          element.setAttribute("targetURI", tabData.entries[activeIndex].url);
+        }
+
+        element.addEventListener("click", this._undoCloseMiddleClick, false);
+        if (i == 0)
+          element.setAttribute("key", "key_undoCloseTab");
+        fragment.appendChild(element);
+      }
+
+      let restoreAllTabs = doc.createElementNS(kNSXUL, aTagName);
+      restoreAllTabs.classList.add("restoreallitem");
+      restoreAllTabs.setAttribute("label", navigatorBundle.GetStringFromName(aRestoreAllLabel));
+      restoreAllTabs.setAttribute("oncommand",
+              "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab();");
+      if (!aPrefixRestoreAll) {
+        fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
+        fragment.appendChild(restoreAllTabs);
+      } else {
+        fragment.insertBefore(restoreAllTabs, fragment.firstChild);
+      }
+    }
+    return fragment;
+  },
+
+  /**
+  * Builds up a document fragment of UI items for the recently closed windows.
+  * @param   aWindow
+  *          A window that can be used to create the elements and document fragment.
+  * @param   aTagName
+  *          The tag name that will be used when creating the UI items.
+  * @param   aPrefixRestoreAll (defaults to false)
+  *          Whether the 'restore all windows' item is suffixed or prefixed to the list.
+  *          If suffixed (the default) a separator will be inserted before it.
+  * @param   aRestoreAllLabel (defaults to "menuRestoreAllWindows.label")
+  *          Which localizable string to use for the 'restore all windows' item.
+  * @returns A document fragment with UI items for each recently closed window.
+  */
+  getWindowsFragment: function(aWindow, aTagName, aPrefixRestoreAll=false,
+                            aRestoreAllLabel="menuRestoreAllWindows.label") {
+    let closedWindowData = JSON.parse(ss.getClosedWindowData());
+    let fragment = aWindow.document.createDocumentFragment();
+    if (closedWindowData.length != 0) {
+      let menuLabelString = navigatorBundle.GetStringFromName("menuUndoCloseWindowLabel");
+      let menuLabelStringSingleTab =
+        navigatorBundle.GetStringFromName("menuUndoCloseWindowSingleTabLabel");
+
+      let doc = aWindow.document;
+      for (let i = 0; i < closedWindowData.length; i++) {
+        let undoItem = closedWindowData[i];
+        let otherTabsCount = undoItem.tabs.length - 1;
+        let label = (otherTabsCount == 0) ? menuLabelStringSingleTab
+                                          : PluralForm.get(otherTabsCount, menuLabelString);
+        let menuLabel = label.replace("#1", undoItem.title)
+                             .replace("#2", otherTabsCount);
+        let item = doc.createElementNS(kNSXUL, aTagName);
+        item.setAttribute("label", menuLabel);
+        let selectedTab = undoItem.tabs[undoItem.selected - 1];
+        if (selectedTab.image) {
+          setImage(selectedTab, item);
+        }
+        if (aTagName == "menuitem") {
+          item.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
+        }
+        item.setAttribute("oncommand", "undoCloseWindow(" + i + ");");
+
+        // Set the targetURI attribute so it will be shown in tooltip.
+        // SessionStore uses one-based indexes, so we need to normalize them.
+        let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
+        if (activeIndex >= 0 && selectedTab.entries[activeIndex])
+          item.setAttribute("targetURI", selectedTab.entries[activeIndex].url);
+
+        if (i == 0)
+          item.setAttribute("key", "key_undoCloseWindow");
+        fragment.appendChild(item);
+      }
+
+      // "Open All in Windows"
+      let restoreAllWindows = doc.createElementNS(kNSXUL, aTagName);
+      restoreAllWindows.classList.add("restoreallitem");
+      restoreAllWindows.setAttribute("label", navigatorBundle.GetStringFromName(aRestoreAllLabel));
+      restoreAllWindows.setAttribute("oncommand",
+        "for (var i = 0; i < " + closedWindowData.length + "; i++) undoCloseWindow();");
+      if (!aPrefixRestoreAll) {
+        fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
+        fragment.appendChild(restoreAllWindows);
+      } else {
+        fragment.insertBefore(restoreAllWindows, fragment.firstChild);
+      }
+    }
+    return fragment;
+  },
+
+
+  /**
+    * Re-open a closed tab and put it to the end of the tab strip.
+    * Used for a middle click.
+    * @param aEvent
+    *        The event when the user clicks the menu item
+    */
+  _undoCloseMiddleClick: function(aEvent) {
+    if (aEvent.button != 1)
+      return;
+
+    aEvent.view.undoCloseTab(aEvent.originalTarget.getAttribute("value"));
+    aEvent.view.gBrowser.moveTabToEnd();
+  },
+};
+
+function setImage(aItem, aElement) {
+  let iconURL = aItem.image;
+  // don't initiate a connection just to fetch a favicon (see bug 467828)
+  if (/^https?:/.test(iconURL))
+    iconURL = "moz-anno:favicon:" + iconURL;
+  aElement.setAttribute("image", iconURL);
+}
--- a/browser/devtools/inspector/selector-search.js
+++ b/browser/devtools/inspector/selector-search.js
@@ -1,492 +1,492 @@
-/* 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 promise = require("devtools/toolkit/deprecated-sync-thenables");
-
-loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
-
-// Maximum number of selector suggestions shown in the panel.
-const MAX_SUGGESTIONS = 15;
-
-/**
- * Converts any input box on a page to a CSS selector search and suggestion box.
- *
- * @constructor
- * @param InspectorPanel aInspector
- *        The InspectorPanel whose `walker` attribute should be used for
- *        document traversal.
- * @param nsiInputElement aInputNode
- *        The input element to which the panel will be attached and from where
- *        search input will be taken.
- */
-function SelectorSearch(aInspector, aInputNode) {
-  this.inspector = aInspector;
-  this.searchBox = aInputNode;
-  this.panelDoc = this.searchBox.ownerDocument;
-
-  // initialize variables.
-  this._lastSearched = null;
-  this._lastValidSearch = "";
-  this._lastToLastValidSearch = null;
-  this._searchResults = null;
-  this._searchSuggestions = {};
-  this._searchIndex = 0;
-
-  // bind!
-  this._showPopup = this._showPopup.bind(this);
-  this._onHTMLSearch = this._onHTMLSearch.bind(this);
-  this._onSearchKeypress = this._onSearchKeypress.bind(this);
-  this._onListBoxKeypress = this._onListBoxKeypress.bind(this);
-
-  // Options for the AutocompletePopup.
-  let options = {
-    panelId: "inspector-searchbox-panel",
-    listBoxId: "searchbox-panel-listbox",
-    autoSelect: true,
-    position: "before_start",
-    direction: "ltr",
-    theme: "auto",
-    onClick: this._onListBoxKeypress,
-    onKeypress: this._onListBoxKeypress
-  };
-  this.searchPopup = new AutocompletePopup(this.panelDoc, options);
-
-  // event listeners.
-  this.searchBox.addEventListener("command", this._onHTMLSearch, true);
-  this.searchBox.addEventListener("keypress", this._onSearchKeypress, true);
-
-  // For testing, we need to be able to wait for the most recent node request
-  // to finish.  Tests can watch this promise for that.
-  this._lastQuery = promise.resolve(null);
-}
-
-exports.SelectorSearch = SelectorSearch;
-
-SelectorSearch.prototype = {
-
-  get walker() this.inspector.walker,
-
-  // The possible states of the query.
-  States: {
-    CLASS: "class",
-    ID: "id",
-    TAG: "tag",
-  },
-
-  // The current state of the query.
-  _state: null,
-
-  // The query corresponding to last state computation.
-  _lastStateCheckAt: null,
-
-  /**
-   * Computes the state of the query. State refers to whether the query
-   * currently requires a class suggestion, or a tag, or an Id suggestion.
-   * This getter will effectively compute the state by traversing the query
-   * character by character each time the query changes.
-   *
-   * @example
-   *        '#f' requires an Id suggestion, so the state is States.ID
-   *        'div > .foo' requires class suggestion, so state is States.CLASS
-   */
-  get state() {
-    if (!this.searchBox || !this.searchBox.value) {
-      return null;
-    }
-
-    let query = this.searchBox.value;
-    if (this._lastStateCheckAt == query) {
-      // If query is the same, return early.
-      return this._state;
-    }
-    this._lastStateCheckAt = query;
-
-    this._state = null;
-    let subQuery = "";
-    // Now we iterate over the query and decide the state character by character.
-    // The logic here is that while iterating, the state can go from one to
-    // another with some restrictions. Like, if the state is Class, then it can
-    // never go to Tag state without a space or '>' character; Or like, a Class
-    // state with only '.' cannot go to an Id state without any [a-zA-Z] after
-    // the '.' which means that '.#' is a selector matching a class name '#'.
-    // Similarily for '#.' which means a selctor matching an id '.'.
-    for (let i = 1; i <= query.length; i++) {
-      // Calculate the state.
-      subQuery = query.slice(0, i);
-      let [secondLastChar, lastChar] = subQuery.slice(-2);
-      switch (this._state) {
-        case null:
-          // This will happen only in the first iteration of the for loop.
-          lastChar = secondLastChar;
-        case this.States.TAG:
-          this._state = lastChar == "."
-            ? this.States.CLASS
-            : lastChar == "#"
-              ? this.States.ID
-              : this.States.TAG;
-          break;
-
-        case this.States.CLASS:
-          if (subQuery.match(/[\.]+[^\.]*$/)[0].length > 2) {
-            // Checks whether the subQuery has atleast one [a-zA-Z] after the '.'.
-            this._state = (lastChar == " " || lastChar == ">")
-            ? this.States.TAG
-            : lastChar == "#"
-              ? this.States.ID
-              : this.States.CLASS;
-          }
-          break;
-
-        case this.States.ID:
-          if (subQuery.match(/[#]+[^#]*$/)[0].length > 2) {
-            // Checks whether the subQuery has atleast one [a-zA-Z] after the '#'.
-            this._state = (lastChar == " " || lastChar == ">")
-            ? this.States.TAG
-            : lastChar == "."
-              ? this.States.CLASS
-              : this.States.ID;
-          }
-          break;
-      }
-    }
-    return this._state;
-  },
-
-  /**
-   * Removes event listeners and cleans up references.
-   */
-  destroy: function() {
-    // event listeners.
-    this.searchBox.removeEventListener("command", this._onHTMLSearch, true);
-    this.searchBox.removeEventListener("keypress", this._onSearchKeypress, true);
-    this.searchPopup.destroy();
-    this.searchPopup = null;
-    this.searchBox = null;
-    this.panelDoc = null;
-    this._searchResults = null;
-    this._searchSuggestions = null;
-  },
-
-  _selectResult: function(index) {
-    return this._searchResults.item(index).then(node => {
-      this.inspector.selection.setNodeFront(node, "selectorsearch");
-    });
-  },
-
-  /**
-   * The command callback for the input box. This function is automatically
-   * invoked as the user is typing if the input box type is search.
-   */
-  _onHTMLSearch: function() {
-    let query = this.searchBox.value;
-    if (query == this._lastSearched) {
-      return;
-    }
-    this._lastSearched = query;
-    this._searchResults = [];
-    this._searchIndex = 0;
-
-    if (query.length == 0) {
-      this._lastValidSearch = "";
-      this.searchBox.removeAttribute("filled");
-      this.searchBox.classList.remove("devtools-no-search-result");
-      if (this.searchPopup.isOpen) {
-        this.searchPopup.hidePopup();
-      }
-      return;
-    }
-
-    this.searchBox.setAttribute("filled", true);
-    let queryList = null;
-
-    this._lastQuery = this.walker.querySelectorAll(this.walker.rootNode, query).then(list => {
-      return list;
-    }, (err) => {
-      // Failures are ok here, just use a null item list;
-      return null;
-    }).then(queryList => {
-      // Value has changed since we started this request, we're done.
-      if (query != this.searchBox.value) {
-        if (queryList) {
-          queryList.release();
-        }
-        return promise.reject(null);
-      }
-
-      this._searchResults = queryList || [];
-      if (this._searchResults && this._searchResults.length > 0) {
-        this._lastValidSearch = query;
-        // Even though the selector matched atleast one node, there is still
-        // possibility of suggestions.
-        if (query.match(/[\s>+]$/)) {
-          // If the query has a space or '>' at the end, create a selector to match
-          // the children of the selector inside the search box by adding a '*'.
-          this._lastValidSearch += "*";
-        }
-        else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
-          // If the query is a partial descendant selector which does not matches
-          // any node, remove the last incomplete part and add a '*' to match
-          // everything. For ex, convert 'foo > b' to 'foo > *' .
-          let lastPart = query.match(/[\s>+][\.#a-zA-Z][^>\s+]*$/)[0];
-          this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
-        }
-
-        if (!query.slice(-1).match(/[\.#\s>+]/)) {
-          // Hide the popup if we have some matching nodes and the query is not
-          // ending with [.# >] which means that the selector is not at the
-          // beginning of a new class, tag or id.
-          if (this.searchPopup.isOpen) {
-            this.searchPopup.hidePopup();
-          }
-          this.searchBox.classList.remove("devtools-no-search-result");
-
-          return this._selectResult(0);
-        }
-        return this._selectResult(0).then(() => {
-          this.searchBox.classList.remove("devtools-no-search-result");
-        }).then(() => this.showSuggestions());
-      }
-      if (query.match(/[\s>+]$/)) {
-        this._lastValidSearch = query + "*";
-      }
-      else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
-        let lastPart = query.match(/[\s+>][\.#a-zA-Z][^>\s+]*$/)[0];
-        this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
-      }
-      this.searchBox.classList.add("devtools-no-search-result");
-      return this.showSuggestions();
-    });
-  },
-
-  /**
-   * Handles keypresses inside the input box.
-   */
-  _onSearchKeypress: function(aEvent) {
-    let query = this.searchBox.value;
-    switch(aEvent.keyCode) {
-      case aEvent.DOM_VK_RETURN:
-        if (query == this._lastSearched && this._searchResults) {
-          this._searchIndex = (this._searchIndex + 1) % this._searchResults.length;
-        }
-        else {
-          this._onHTMLSearch();
-          return;
-        }
-        break;
-
-      case aEvent.DOM_VK_UP:
-        if (this.searchPopup.isOpen && this.searchPopup.itemCount > 0) {
-          this.searchPopup.focus();
-          if (this.searchPopup.selectedIndex == this.searchPopup.itemCount - 1) {
-            this.searchPopup.selectedIndex =
-              Math.max(0, this.searchPopup.itemCount - 2);
-          }
-          else {
-            this.searchPopup.selectedIndex = this.searchPopup.itemCount - 1;
-          }
-          this.searchBox.value = this.searchPopup.selectedItem.label;
-        }
-        else if (--this._searchIndex < 0) {
-          this._searchIndex = this._searchResults.length - 1;
-        }
-        break;
-
-      case aEvent.DOM_VK_DOWN:
-        if (this.searchPopup.isOpen && this.searchPopup.itemCount > 0) {
-          this.searchPopup.focus();
-          this.searchPopup.selectedIndex = 0;
-          this.searchBox.value = this.searchPopup.selectedItem.label;
-        }
-        this._searchIndex = (this._searchIndex + 1) % this._searchResults.length;
-        break;
-
-      case aEvent.DOM_VK_TAB:
-        if (this.searchPopup.isOpen &&
-            this.searchPopup.getItemAtIndex(this.searchPopup.itemCount - 1)
-                .preLabel == query) {
-          this.searchPopup.selectedIndex = this.searchPopup.itemCount - 1;
-          this.searchBox.value = this.searchPopup.selectedItem.label;
-          this._onHTMLSearch();
-        }
-        break;
-
-      case aEvent.DOM_VK_BACK_SPACE:
-      case aEvent.DOM_VK_DELETE:
-        // need to throw away the lastValidSearch.
-        this._lastToLastValidSearch = null;
-        // This gets the most complete selector from the query. For ex.
-        // '.foo.ba' returns '.foo' , '#foo > .bar.baz' returns '#foo > .bar'
-        // '.foo +bar' returns '.foo +' and likewise.
-        this._lastValidSearch = (query.match(/(.*)[\.#][^\.# ]{0,}$/) ||
-                                 query.match(/(.*[\s>+])[a-zA-Z][^\.# ]{0,}$/) ||
-                                 ["",""])[1];
-        return;
-
-      default:
-        return;
-    }
-
-    aEvent.preventDefault();
-    aEvent.stopPropagation();
-    if (this._searchResults && this._searchResults.length > 0) {
-      this._lastQuery = this._selectResult(this._searchIndex);
-    }
-  },
-
-  /**
-   * Handles keypress and mouse click on the suggestions richlistbox.
-   */
-  _onListBoxKeypress: function(aEvent) {
-    switch(aEvent.keyCode || aEvent.button) {
-      case aEvent.DOM_VK_RETURN:
-      case aEvent.DOM_VK_TAB:
-      case 0: // left mouse button
-        aEvent.stopPropagation();
-        aEvent.preventDefault();
-        this.searchBox.value = this.searchPopup.selectedItem.label;
-        this.searchBox.focus();
-        this._onHTMLSearch();
-        break;
-
-      case aEvent.DOM_VK_UP:
-        if (this.searchPopup.selectedIndex == 0) {
-          this.searchPopup.selectedIndex = -1;
-          aEvent.stopPropagation();
-          aEvent.preventDefault();
-          this.searchBox.focus();
-        }
-        else {
-          let index = this.searchPopup.selectedIndex;
-          this.searchBox.value = this.searchPopup.getItemAtIndex(index - 1).label;
-        }
-        break;
-
-      case aEvent.DOM_VK_DOWN:
-        if (this.searchPopup.selectedIndex == this.searchPopup.itemCount - 1) {
-          this.searchPopup.selectedIndex = -1;
-          aEvent.stopPropagation();
-          aEvent.preventDefault();
-          this.searchBox.focus();
-        }
-        else {
-          let index = this.searchPopup.selectedIndex;
-          this.searchBox.value = this.searchPopup.getItemAtIndex(index + 1).label;
-        }
-        break;
-
-      case aEvent.DOM_VK_BACK_SPACE:
-        aEvent.stopPropagation();
-        aEvent.preventDefault();
-        this.searchBox.focus();
-        if (this.searchBox.selectionStart > 0) {
-          this.searchBox.value =
-            this.searchBox.value.substring(0, this.searchBox.selectionStart - 1);
-        }
-        this._lastToLastValidSearch = null;
-        let query = this.searchBox.value;
-        this._lastValidSearch = (query.match(/(.*)[\.#][^\.# ]{0,}$/) ||
-                                 query.match(/(.*[\s>+])[a-zA-Z][^\.# ]{0,}$/) ||
-                                 ["",""])[1];
-        this._onHTMLSearch();
-        break;
-    }
-  },
-
-  /**
-   * Populates the suggestions list and show the suggestion popup.
-   */
-  _showPopup: function(aList, aFirstPart) {
-    let total = 0;
-    let query = this.searchBox.value;
-    let toLowerCase = false;
-    let items = [];
-    // In case of tagNames, change the case to small.
-    if (query.match(/.*[\.#][^\.#]{0,}$/) == null) {
-      toLowerCase = true;
-    }
-    for (let [value, count] of aList) {
-      // for cases like 'div ' or 'div >' or 'div+'
-      if (query.match(/[\s>+]$/)) {
-        value = query + value;
-      }
-      // for cases like 'div #a' or 'div .a' or 'div > d' and likewise
-      else if (query.match(/[\s>+][\.#a-zA-Z][^\s>+\.#]*$/)) {
-        let lastPart = query.match(/[\s>+][\.#a-zA-Z][^>\s+\.#]*$/)[0];
-        value = query.slice(0, -1 * lastPart.length + 1) + value;
-      }
-      // for cases like 'div.class' or '#foo.bar' and likewise
-      else if (query.match(/[a-zA-Z][#\.][^#\.\s+>]*$/)) {
-        let lastPart = query.match(/[a-zA-Z][#\.][^#\.\s>+]*$/)[0];
-        value = query.slice(0, -1 * lastPart.length + 1) + value;
-      }
-      let item = {
-        preLabel: query,
-        label: value,
-        count: count
-      };
-      if (toLowerCase) {
-        item.label = value.toLowerCase();
-      }
-      items.unshift(item);
-      if (++total > MAX_SUGGESTIONS - 1) {
-        break;
-      }
-    }
-    if (total > 0) {
-      this.searchPopup.setItems(items);
-      this.searchPopup.openPopup(this.searchBox);
-    }
-    else {
-      this.searchPopup.hidePopup();
-    }
-  },
-
-  /**
-   * Suggests classes,ids and tags based on the user input as user types in the
-   * searchbox.
-   */
-  showSuggestions: function() {
-    let query = this.searchBox.value;
-    let firstPart = "";
-    if (this.state == this.States.TAG) {
-      // gets the tag that is being completed. For ex. 'div.foo > s' returns 's',
-      // 'di' returns 'di' and likewise.
-      firstPart = (query.match(/[\s>+]?([a-zA-Z]*)$/) || ["", query])[1];
-      query = query.slice(0, query.length - firstPart.length);
-    }
-    else if (this.state == this.States.CLASS) {
-      // gets the class that is being completed. For ex. '.foo.b' returns 'b'
-      firstPart = query.match(/\.([^\.]*)$/)[1];
-      query = query.slice(0, query.length - firstPart.length - 1);
-    }
-    else if (this.state == this.States.ID) {
-      // gets the id that is being completed. For ex. '.foo#b' returns 'b'
-      firstPart = query.match(/#([^#]*)$/)[1];
-      query = query.slice(0, query.length - firstPart.length - 1);
-    }
-    // TODO: implement some caching so that over the wire request is not made
-    // everytime.
-    if (/[\s+>~]$/.test(query)) {
-      query += "*";
-    }
-    this._currentSuggesting = query;
-    return this.walker.getSuggestionsForQuery(query, firstPart, this.state).then(result => {
-      if (this._currentSuggesting != result.query) {
-        // This means that this response is for a previous request and the user
-        // as since typed something extra leading to a new request.
-        return;
-      }
-      this._lastToLastValidSearch = this._lastValidSearch;
-      if (this.state == this.States.CLASS) {
-        firstPart = "." + firstPart;
-      }
-      else if (this.state == this.States.ID) {
-        firstPart = "#" + firstPart;
-      }
-      this._showPopup(result.suggestions, firstPart);
-    });
-  }
-};
+/* 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 promise = require("devtools/toolkit/deprecated-sync-thenables");
+
+loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
+
+// Maximum number of selector suggestions shown in the panel.
+const MAX_SUGGESTIONS = 15;
+
+/**
+ * Converts any input box on a page to a CSS selector search and suggestion box.
+ *
+ * @constructor
+ * @param InspectorPanel aInspector
+ *        The InspectorPanel whose `walker` attribute should be used for
+ *        document traversal.
+ * @param nsiInputElement aInputNode
+ *        The input element to which the panel will be attached and from where
+ *        search input will be taken.
+ */
+function SelectorSearch(aInspector, aInputNode) {
+  this.inspector = aInspector;
+  this.searchBox = aInputNode;
+  this.panelDoc = this.searchBox.ownerDocument;
+
+  // initialize variables.
+  this._lastSearched = null;
+  this._lastValidSearch = "";
+  this._lastToLastValidSearch = null;
+  this._searchResults = null;
+  this._searchSuggestions = {};
+  this._searchIndex = 0;
+
+  // bind!
+  this._showPopup = this._showPopup.bind(this);
+  this._onHTMLSearch = this._onHTMLSearch.bind(this);
+  this._onSearchKeypress = this._onSearchKeypress.bind(this);
+  this._onListBoxKeypress = this._onListBoxKeypress.bind(this);
+
+  // Options for the AutocompletePopup.
+  let options = {
+    panelId: "inspector-searchbox-panel",
+    listBoxId: "searchbox-panel-listbox",
+    autoSelect: true,
+    position: "before_start",
+    direction: "ltr",
+    theme: "auto",
+    onClick: this._onListBoxKeypress,
+    onKeypress: this._onListBoxKeypress
+  };
+  this.searchPopup = new AutocompletePopup(this.panelDoc, options);
+
+  // event listeners.
+  this.searchBox.addEventListener("command", this._onHTMLSearch, true);
+  this.searchBox.addEventListener("keypress", this._onSearchKeypress, true);
+
+  // For testing, we need to be able to wait for the most recent node request
+  // to finish.  Tests can watch this promise for that.
+  this._lastQuery = promise.resolve(null);
+}
+
+exports.SelectorSearch = SelectorSearch;
+
+SelectorSearch.prototype = {
+
+  get walker() this.inspector.walker,
+
+  // The possible states of the query.
+  States: {
+    CLASS: "class",
+    ID: "id",
+    TAG: "tag",
+  },
+
+  // The current state of the query.
+  _state: null,
+
+  // The query corresponding to last state computation.
+  _lastStateCheckAt: null,
+
+  /**
+   * Computes the state of the query. State refers to whether the query
+   * currently requires a class suggestion, or a tag, or an Id suggestion.
+   * This getter will effectively compute the state by traversing the query
+   * character by character each time the query changes.
+   *
+   * @example
+   *        '#f' requires an Id suggestion, so the state is States.ID
+   *        'div > .foo' requires class suggestion, so state is States.CLASS
+   */
+  get state() {
+    if (!this.searchBox || !this.searchBox.value) {
+      return null;
+    }
+
+    let query = this.searchBox.value;
+    if (this._lastStateCheckAt == query) {
+      // If query is the same, return early.
+      return this._state;
+    }
+    this._lastStateCheckAt = query;
+
+    this._state = null;
+    let subQuery = "";
+    // Now we iterate over the query and decide the state character by character.
+    // The logic here is that while iterating, the state can go from one to
+    // another with some restrictions. Like, if the state is Class, then it can
+    // never go to Tag state without a space or '>' character; Or like, a Class
+    // state with only '.' cannot go to an Id state without any [a-zA-Z] after
+    // the '.' which means that '.#' is a selector matching a class name '#'.
+    // Similarily for '#.' which means a selctor matching an id '.'.
+    for (let i = 1; i <= query.length; i++) {
+      // Calculate the state.
+      subQuery = query.slice(0, i);
+      let [secondLastChar, lastChar] = subQuery.slice(-2);
+      switch (this._state) {
+        case null:
+          // This will happen only in the first iteration of the for loop.
+          lastChar = secondLastChar;
+        case this.States.TAG:
+          this._state = lastChar == "."
+            ? this.States.CLASS
+            : lastChar == "#"
+              ? this.States.ID
+              : this.States.TAG;
+          break;
+
+        case this.States.CLASS:
+          if (subQuery.match(/[\.]+[^\.]*$/)[0].length > 2) {
+            // Checks whether the subQuery has atleast one [a-zA-Z] after the '.'.
+            this._state = (lastChar == " " || lastChar == ">")
+            ? this.States.TAG
+            : lastChar == "#"
+              ? this.States.ID
+              : this.States.CLASS;
+          }
+          break;
+
+        case this.States.ID:
+          if (subQuery.match(/[#]+[^#]*$/)[0].length > 2) {
+            // Checks whether the subQuery has atleast one [a-zA-Z] after the '#'.
+            this._state = (lastChar == " " || lastChar == ">")
+            ? this.States.TAG
+            : lastChar == "."
+              ? this.States.CLASS
+              : this.States.ID;
+          }
+          break;
+      }
+    }
+    return this._state;
+  },
+
+  /**
+   * Removes event listeners and cleans up references.
+   */
+  destroy: function() {
+    // event listeners.
+    this.searchBox.removeEventListener("command", this._onHTMLSearch, true);
+    this.searchBox.removeEventListener("keypress", this._onSearchKeypress, true);
+    this.searchPopup.destroy();
+    this.searchPopup = null;
+    this.searchBox = null;
+    this.panelDoc = null;
+    this._searchResults = null;
+    this._searchSuggestions = null;
+  },
+
+  _selectResult: function(index) {
+    return this._searchResults.item(index).then(node => {
+      this.inspector.selection.setNodeFront(node, "selectorsearch");
+    });
+  },
+
+  /**
+   * The command callback for the input box. This function is automatically
+   * invoked as the user is typing if the input box type is search.
+   */
+  _onHTMLSearch: function() {
+    let query = this.searchBox.value;
+    if (query == this._lastSearched) {
+      return;
+    }
+    this._lastSearched = query;
+    this._searchResults = [];
+    this._searchIndex = 0;
+
+    if (query.length == 0) {
+      this._lastValidSearch = "";
+      this.searchBox.removeAttribute("filled");
+      this.searchBox.classList.remove("devtools-no-search-result");
+      if (this.searchPopup.isOpen) {
+        this.searchPopup.hidePopup();
+      }
+      return;
+    }
+
+    this.searchBox.setAttribute("filled", true);
+    let queryList = null;
+
+    this._lastQuery = this.walker.querySelectorAll(this.walker.rootNode, query).then(list => {
+      return list;
+    }, (err) => {
+      // Failures are ok here, just use a null item list;
+      return null;
+    }).then(queryList => {
+      // Value has changed since we started this request, we're done.
+      if (query != this.searchBox.value) {
+        if (queryList) {
+          queryList.release();
+        }
+        return promise.reject(null);
+      }
+
+      this._searchResults = queryList || [];
+      if (this._searchResults && this._searchResults.length > 0) {
+        this._lastValidSearch = query;
+        // Even though the selector matched atleast one node, there is still
+        // possibility of suggestions.
+        if (query.match(/[\s>+]$/)) {
+          // If the query has a space or '>' at the end, create a selector to match
+          // the children of the selector inside the search box by adding a '*'.
+          this._lastValidSearch += "*";
+        }
+        else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
+          // If the query is a partial descendant selector which does not matches
+          // any node, remove the last incomplete part and add a '*' to match
+          // everything. For ex, convert 'foo > b' to 'foo > *' .
+          let lastPart = query.match(/[\s>+][\.#a-zA-Z][^>\s+]*$/)[0];
+          this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
+        }
+
+        if (!query.slice(-1).match(/[\.#\s>+]/)) {
+          // Hide the popup if we have some matching nodes and the query is not
+          // ending with [.# >] which means that the selector is not at the
+          // beginning of a new class, tag or id.
+          if (this.searchPopup.isOpen) {
+            this.searchPopup.hidePopup();
+          }
+          this.searchBox.classList.remove("devtools-no-search-result");
+
+          return this._selectResult(0);
+        }
+        return this._selectResult(0).then(() => {
+          this.searchBox.classList.remove("devtools-no-search-result");
+        }).then(() => this.showSuggestions());
+      }
+      if (query.match(/[\s>+]$/)) {
+        this._lastValidSearch = query + "*";
+      }
+      else if (query.match(/[\s>+][\.#a-zA-Z][\.#>\s+]*$/)) {
+        let lastPart = query.match(/[\s+>][\.#a-zA-Z][^>\s+]*$/)[0];
+        this._lastValidSearch = query.slice(0, -1 * lastPart.length + 1) + "*";
+      }
+      this.searchBox.classList.add("devtools-no-search-result");
+      return this.showSuggestions();
+    });
+  },
+
+  /**
+   * Handles keypresses inside the input box.
+   */
+  _onSearchKeypress: function(aEvent) {
+    let query = this.searchBox.value;
+    switch(aEvent.keyCode) {
+      case aEvent.DOM_VK_RETURN:
+        if (query == this._lastSearched && this._searchResults) {
+          this._searchIndex = (this._searchIndex + 1) % this._searchResults.length;
+        }
+        else {
+          this._onHTMLSearch();
+          return;
+        }
+        break;
+
+      case aEvent.DOM_VK_UP:
+        if (this.searchPopup.isOpen && this.searchPopup.itemCount > 0) {
+          this.searchPopup.focus();
+          if (this.searchPopup.selectedIndex == this.searchPopup.itemCount - 1) {
+            this.searchPopup.selectedIndex =
+              Math.max(0, this.searchPopup.itemCount - 2);
+          }
+          else {
+            this.searchPopup.selectedIndex = this.searchPopup.itemCount - 1;
+          }
+          this.searchBox.value = this.searchPopup.selectedItem.label;
+        }
+        else if (--this._searchIndex < 0) {
+          this._searchIndex = this._searchResults.length - 1;
+        }
+        break;
+
+      case aEvent.DOM_VK_DOWN:
+        if (this.searchPopup.isOpen && this.searchPopup.itemCount > 0) {
+          this.searchPopup.focus();
+          this.searchPopup.selectedIndex = 0;
+          this.searchBox.value = this.searchPopup.selectedItem.label;
+        }
+        this._searchIndex = (this._searchIndex + 1) % this._searchResults.length;
+        break;
+
+      case aEvent.DOM_VK_TAB:
+        if (this.searchPopup.isOpen &&
+            this.searchPopup.getItemAtIndex(this.searchPopup.itemCount - 1)
+                .preLabel == query) {
+          this.searchPopup.selectedIndex = this.searchPopup.itemCount - 1;
+          this.searchBox.value = this.searchPopup.selectedItem.label;
+          this._onHTMLSearch();
+        }
+        break;
+
+      case aEvent.DOM_VK_BACK_SPACE:
+      case aEvent.DOM_VK_DELETE:
+        // need to throw away the lastValidSearch.
+        this._lastToLastValidSearch = null;
+        // This gets the most complete selector from the query. For ex.
+        // '.foo.ba' returns '.foo' , '#foo > .bar.baz' returns '#foo > .bar'
+        // '.foo +bar' returns '.foo +' and likewise.
+        this._lastValidSearch = (query.match(/(.*)[\.#][^\.# ]{0,}$/) ||
+                                 query.match(/(.*[\s>+])[a-zA-Z][^\.# ]{0,}$/) ||
+                                 ["",""])[1];
+        return;
+
+      default:
+        return;
+    }
+
+    aEvent.preventDefault();
+    aEvent.stopPropagation();
+    if (this._searchResults && this._searchResults.length > 0) {
+      this._lastQuery = this._selectResult(this._searchIndex);
+    }
+  },
+
+  /**
+   * Handles keypress and mouse click on the suggestions richlistbox.
+   */
+  _onListBoxKeypress: function(aEvent) {
+    switch(aEvent.keyCode || aEvent.button) {
+      case aEvent.DOM_VK_RETURN:
+      case aEvent.DOM_VK_TAB:
+      case 0: // left mouse button
+        aEvent.stopPropagation();
+        aEvent.preventDefault();
+        this.searchBox.value = this.searchPopup.selectedItem.label;
+        this.searchBox.focus();
+        this._onHTMLSearch();
+        break;
+
+      case aEvent.DOM_VK_UP:
+        if (this.searchPopup.selectedIndex == 0) {
+          this.searchPopup.selectedIndex = -1;
+          aEvent.stopPropagation();
+          aEvent.preventDefault();
+          this.searchBox.focus();
+        }
+        else {
+          let index = this.searchPopup.selectedIndex;
+          this.searchBox.value = this.searchPopup.getItemAtIndex(index - 1).label;
+        }
+        break;
+
+      case aEvent.DOM_VK_DOWN:
+        if (this.searchPopup.selectedIndex == this.searchPopup.itemCount - 1) {
+          this.searchPopup.selectedIndex = -1;
+          aEvent.stopPropagation();
+          aEvent.preventDefault();
+          this.searchBox.focus();
+        }
+        else {
+          let index = this.searchPopup.selectedIndex;
+          this.searchBox.value = this.searchPopup.getItemAtIndex(index + 1).label;
+        }
+        break;
+
+      case aEvent.DOM_VK_BACK_SPACE:
+        aEvent.stopPropagation();
+        aEvent.preventDefault();
+        this.searchBox.focus();
+        if (this.searchBox.selectionStart > 0) {
+          this.searchBox.value =
+            this.searchBox.value.substring(0, this.searchBox.selectionStart - 1);
+        }
+        this._lastToLastValidSearch = null;
+        let query = this.searchBox.value;
+        this._lastValidSearch = (query.match(/(.*)[\.#][^\.# ]{0,}$/) ||
+                                 query.match(/(.*[\s>+])[a-zA-Z][^\.# ]{0,}$/) ||
+                                 ["",""])[1];
+        this._onHTMLSearch();
+        break;
+    }
+  },
+
+  /**
+   * Populates the suggestions list and show the suggestion popup.
+   */
+  _showPopup: function(aList, aFirstPart) {
+    let total = 0;
+    let query = this.searchBox.value;
+    let toLowerCase = false;
+    let items = [];
+    // In case of tagNames, change the case to small.
+    if (query.match(/.*[\.#][^\.#]{0,}$/) == null) {
+      toLowerCase = true;
+    }
+    for (let [value, count] of aList) {
+      // for cases like 'div ' or 'div >' or 'div+'
+      if (query.match(/[\s>+]$/)) {
+        value = query + value;
+      }
+      // for cases like 'div #a' or 'div .a' or 'div > d' and likewise
+      else if (query.match(/[\s>+][\.#a-zA-Z][^\s>+\.#]*$/)) {
+        let lastPart = query.match(/[\s>+][\.#a-zA-Z][^>\s+\.#]*$/)[0];
+        value = query.slice(0, -1 * lastPart.length + 1) + value;
+      }
+      // for cases like 'div.class' or '#foo.bar' and likewise
+      else if (query.match(/[a-zA-Z][#\.][^#\.\s+>]*$/)) {
+        let lastPart = query.match(/[a-zA-Z][#\.][^#\.\s>+]*$/)[0];
+        value = query.slice(0, -1 * lastPart.length + 1) + value;
+      }
+      let item = {
+        preLabel: query,
+        label: value,
+        count: count
+      };
+      if (toLowerCase) {
+        item.label = value.toLowerCase();
+      }
+      items.unshift(item);
+      if (++total > MAX_SUGGESTIONS - 1) {
+        break;
+      }
+    }
+    if (total > 0) {
+      this.searchPopup.setItems(items);
+      this.searchPopup.openPopup(this.searchBox);
+    }
+    else {
+      this.searchPopup.hidePopup();
+    }
+  },
+
+  /**
+   * Suggests classes,ids and tags based on the user input as user types in the
+   * searchbox.
+   */
+  showSuggestions: function() {
+    let query = this.searchBox.value;
+    let firstPart = "";
+    if (this.state == this.States.TAG) {
+      // gets the tag that is being completed. For ex. 'div.foo > s' returns 's',
+      // 'di' returns 'di' and likewise.
+      firstPart = (query.match(/[\s>+]?([a-zA-Z]*)$/) || ["", query])[1];
+      query = query.slice(0, query.length - firstPart.length);
+    }
+    else if (this.state == this.States.CLASS) {
+      // gets the class that is being completed. For ex. '.foo.b' returns 'b'
+      firstPart = query.match(/\.([^\.]*)$/)[1];
+      query = query.slice(0, query.length - firstPart.length - 1);
+    }
+    else if (this.state == this.States.ID) {
+      // gets the id that is being completed. For ex. '.foo#b' returns 'b'
+      firstPart = query.match(/#([^#]*)$/)[1];
+      query = query.slice(0, query.length - firstPart.length - 1);
+    }
+    // TODO: implement some caching so that over the wire request is not made
+    // everytime.
+    if (/[\s+>~]$/.test(query)) {
+      query += "*";
+    }
+    this._currentSuggesting = query;
+    return this.walker.getSuggestionsForQuery(query, firstPart, this.state).then(result => {
+      if (this._currentSuggesting != result.query) {
+        // This means that this response is for a previous request and the user
+        // as since typed something extra leading to a new request.
+        return;
+      }
+      this._lastToLastValidSearch = this._lastValidSearch;
+      if (this.state == this.States.CLASS) {
+        firstPart = "." + firstPart;
+      }
+      else if (this.state == this.States.ID) {
+        firstPart = "#" + firstPart;
+      }
+      this._showPopup(result.suggestions, firstPart);
+    });
+  }
+};
--- a/browser/metro/base/content/bindings/circularprogress.xml
+++ b/browser/metro/base/content/bindings/circularprogress.xml
@@ -1,134 +1,134 @@
-<?xml version="1.0"?>
-
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<bindings xmlns="http://www.mozilla.org/xbl"
-          xmlns:xbl="http://www.mozilla.org/xbl"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-          xmlns:html="http://www.w3.org/1999/xhtml">
-  <binding id="circular-progress-indicator">
-    <resources>
-      <stylesheet src="chrome://browser/skin/circularprogress.css"/>
-    </resources>
-
-    <content>
-      <xul:stack>
-        <xul:toolbarbutton anonid="progressButton"
-                           class="circularprogressindicator-progressButton"/>
-        <html:div anonid="progressTrack"
-                  xbl:inherits="progress"
-                  class="circularprogressindicator-progressTrack">
-        </html:div>
-        <html:canvas anonid="progressRing"
-                     xbl:inherits="progress"
-                     class="circularprogressindicator-progressRing"
-                     width="40"
-                     height="40">
-        </html:canvas>
-        <html:div anonid="progressNotification"
-                  xbl:inherits="progress"
-                  class="circularprogressindicator-progressNotification">
-        </html:div>
-      </xul:stack>
-    </content>
-
-    <implementation>
-      <field name="_progressCanvas">
-        document.getAnonymousElementByAttribute(this, "anonid", "progressRing");
-      </field>
-      <field name="_progressNotification">
-        document.getAnonymousElementByAttribute(this, "anonid",
-            "progressNotification");
-      </field>
-      <field name="_progressCircleCtx">null</field>
-      <field name="_img">null</field>
-      <constructor>
-        <![CDATA[
-          this._progressCircleCtx = this._progressCanvas.getContext('2d');
-        ]]>
-      </constructor>
-      <method name="updateProgress">
-        <parameter name="percentComplete"/>
-        <body>
-          <![CDATA[
-            const PROGRESS_RING_IMG = "chrome://browser/skin/images/progresscircle.png";
-
-            // show ring background even if % is 0.
-            this.setAttribute("progress", percentComplete);
-
-            let startAngle = 1.5 * Math.PI;
-            let endAngle = startAngle + (2 * Math.PI * (percentComplete / 100));
-
-            if (!this._img) {
-              this._img = new Image();
-              this._img.onload = () => {
-                this.updateProgress(this.getAttribute("progress"))
-              }
-              this._img.src = PROGRESS_RING_IMG;
-            }
-            else if (this._img.complete) {
-              let ctx = this._progressCircleCtx;
-              ctx.clearRect(0, 0,
-                this._progressCanvas.width, this._progressCanvas.height);
-
-              // Save the state, so we can undo the clipping
-              ctx.save();
-
-              ctx.beginPath();
-              let center = this._progressCanvas.width / 2;
-              ctx.arc(center, center, center, startAngle, endAngle, false);
-              ctx.lineTo(center, center);
-              ctx.closePath();
-              ctx.clip();
-
-              // Draw circle image.
-              ctx.translate(center, center);
-              ctx.rotate(endAngle);
-              ctx.drawImage(this._img, -center, -center);
-
-              ctx.restore();
-            } else {
-              //  Image is still loading
-            }
-            return [startAngle, endAngle];
-          ]]>
-        </body>
-      </method>
-      <method name="reset">
-        <body>
-          <![CDATA[
-            if(this._img && !this._img.complete) {
-              // cancel any pending updateProgress
-              this._img.onload = () => {};
-            }
-            this._progressCircleCtx.clearRect(0, 0,
-              this._progressCanvas.width, this._progressCanvas.height);
-            this.removeAttribute("progress");
-          ]]>
-        </body>
-      </method>
-      <method name="notify">
-        <body>
-          <![CDATA[
-            this.addEventListener("transitionend", this._onNotificationEnd);
-
-            this._progressNotification.classList.add(
-                "progressNotification-active");
-          ]]>
-        </body>
-      </method>
-      <method name="_onNotificationEnd">
-        <body>
-          <![CDATA[
-            this.removeEventListener("transitionend", this._onNotificationEnd);
-
-            this._progressNotification.classList.remove(
-                "progressNotification-active");
-          ]]>
-        </body>
-      </method>
-    </implementation>
-  </binding>
-</bindings>
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<bindings xmlns="http://www.mozilla.org/xbl"
+          xmlns:xbl="http://www.mozilla.org/xbl"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+          xmlns:html="http://www.w3.org/1999/xhtml">
+  <binding id="circular-progress-indicator">
+    <resources>
+      <stylesheet src="chrome://browser/skin/circularprogress.css"/>
+    </resources>
+
+    <content>
+      <xul:stack>
+        <xul:toolbarbutton anonid="progressButton"
+                           class="circularprogressindicator-progressButton"/>
+        <html:div anonid="progressTrack"
+                  xbl:inherits="progress"
+                  class="circularprogressindicator-progressTrack">
+        </html:div>
+        <html:canvas anonid="progressRing"
+                     xbl:inherits="progress"
+                     class="circularprogressindicator-progressRing"
+                     width="40"
+                     height="40">
+        </html:canvas>
+        <html:div anonid="progressNotification"
+                  xbl:inherits="progress"
+                  class="circularprogressindicator-progressNotification">
+        </html:div>
+      </xul:stack>
+    </content>
+
+    <implementation>
+      <field name="_progressCanvas">
+        document.getAnonymousElementByAttribute(this, "anonid", "progressRing");
+      </field>
+      <field name="_progressNotification">
+        document.getAnonymousElementByAttribute(this, "anonid",
+            "progressNotification");
+      </field>
+      <field name="_progressCircleCtx">null</field>
+      <field name="_img">null</field>
+      <constructor>
+        <![CDATA[
+          this._progressCircleCtx = this._progressCanvas.getContext('2d');
+        ]]>
+      </constructor>
+      <method name="updateProgress">
+        <parameter name="percentComplete"/>
+        <body>
+          <![CDATA[
+            const PROGRESS_RING_IMG = "chrome://browser/skin/images/progresscircle.png";
+
+            // show ring background even if % is 0.
+            this.setAttribute("progress", percentComplete);
+
+            let startAngle = 1.5 * Math.PI;
+            let endAngle = startAngle + (2 * Math.PI * (percentComplete / 100));
+
+            if (!this._img) {
+              this._img = new Image();
+              this._img.onload = () => {
+                this.updateProgress(this.getAttribute("progress"))
+              }
+              this._img.src = PROGRESS_RING_IMG;
+            }
+            else if (this._img.complete) {
+              let ctx = this._progressCircleCtx;
+              ctx.clearRect(0, 0,
+                this._progressCanvas.width, this._progressCanvas.height);
+
+              // Save the state, so we can undo the clipping
+              ctx.save();
+
+              ctx.beginPath();
+              let center = this._progressCanvas.width / 2;
+              ctx.arc(center, center, center, startAngle, endAngle, false);
+              ctx.lineTo(center, center);
+              ctx.closePath();
+              ctx.clip();
+
+              // Draw circle image.
+              ctx.translate(center, center);
+              ctx.rotate(endAngle);
+              ctx.drawImage(this._img, -center, -center);
+
+              ctx.restore();
+            } else {
+              //  Image is still loading
+            }
+            return [startAngle, endAngle];
+          ]]>
+        </body>
+      </method>
+      <method name="reset">
+        <body>
+          <![CDATA[
+            if(this._img && !this._img.complete) {
+              // cancel any pending updateProgress
+              this._img.onload = () => {};
+            }
+            this._progressCircleCtx.clearRect(0, 0,
+              this._progressCanvas.width, this._progressCanvas.height);
+            this.removeAttribute("progress");
+          ]]>
+        </body>
+      </method>
+      <method name="notify">
+        <body>
+          <![CDATA[
+            this.addEventListener("transitionend", this._onNotificationEnd);
+
+            this._progressNotification.classList.add(
+                "progressNotification-active");
+          ]]>
+        </body>
+      </method>
+      <method name="_onNotificationEnd">
+        <body>
+          <![CDATA[
+            this.removeEventListener("transitionend", this._onNotificationEnd);
+
+            this._progressNotification.classList.remove(
+                "progressNotification-active");
+          ]]>
+        </body>
+      </method>
+    </implementation>
+  </binding>
+</bindings>
--- a/browser/metro/base/content/commandUtil.js
+++ b/browser/metro/base/content/commandUtil.js
@@ -1,164 +1,164 @@
-/* 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/. */
-
-
-/**
- * Command Updater
- */
-var CommandUpdater = {
-  /**
-   * Gets a controller that can handle a particular command.
-   * @param   command
-   *          A command to locate a controller for, preferring controllers that
-   *          show the command as enabled.
-   * @returns In this order of precedence:
-   *            - the first controller supporting the specified command
-   *              associated with the focused element that advertises the
-   *              command as ENABLED
-   *            - the first controller supporting the specified command
-   *              associated with the global window that advertises the
-   *              command as ENABLED
-   *            - the first controller supporting the specified command
-   *              associated with the focused element
-   *            - the first controller supporting the specified command
-   *              associated with the global window
-   */
-  _getControllerForCommand: function(command) {
-    try {
-      var controller = top.document.commandDispatcher.getControllerForCommand(command);
-      if (controller && controller.isCommandEnabled(command))
-        return controller;
-    }
-    catch(e) {
-    }
-    var controllerCount = window.controllers.getControllerCount();
-    for (var i = 0; i < controllerCount; ++i) {
-      var current = window.controllers.getControllerAt(i);
-      try {
-        if (current.supportsCommand(command) && current.isCommandEnabled(command))
-          return current;
-      }
-      catch (e) {
-      }
-    }
-    return controller || window.controllers.getControllerForCommand(command);
-  },
-
-  /**
-   * Updates the state of a XUL <command> element for the specified command
-   * depending on its state.
-   * @param   command
-   *          The name of the command to update the XUL <command> element for
-   */
-  updateCommand: function(command) {
-    var enabled = false;
-    try {
-      var controller = this._getControllerForCommand(command);
-      if (controller) {
-        enabled = controller.isCommandEnabled(command);
-      }
-    }
-    catch(ex) { }
-
-    this.enableCommand(command, enabled);
-  },
-
-  /**
-   * Updates the state of a XUL <command> element for the specified command
-   * depending on its state.
-   * @param   command
-   *          The name of the command to update the XUL <command> element for
-   */
-  updateCommands: function(_commands) {
-    var commands = _commands.split(",");
-    for (var command in commands) {
-      this.updateCommand(commands[command]);
-    }
-  },
-
-  /**
-   * Enables or disables a XUL <command> element.
-   * @param   command
-   *          The name of the command to enable or disable
-   * @param   enabled
-   *          true if the command should be enabled, false otherwise.
-   */
-  enableCommand: function(command, enabled) {
-    var element = document.getElementById(command);
-    if (!element)
-      return;
-    if (enabled)
-      element.removeAttribute("disabled");
-    else
-      element.setAttribute("disabled", "true");
-  },
-
-  /**
-   * Performs the action associated with a specified command using the most
-   * relevant controller.
-   * @param   command
-   *          The command to perform.
-   */
-  doCommand: function(command) {
-    var controller = this._getControllerForCommand(command);
-    if (!controller)
-      return;
-    controller.doCommand(command);
-  },
-
-  /**
-   * Changes the label attribute for the specified command.
-   * @param   command
-   *          The command to update.
-   * @param   labelAttribute
-   *          The label value to use.
-   */
-  setMenuValue: function(command, labelAttribute) {
-    var commandNode = top.document.getElementById(command);
-    if (commandNode)
-    {
-      var label = commandNode.getAttribute(labelAttribute);
-      if ( label )
-        commandNode.setAttribute('label', label);
-    }
-  },
-
-  /**
-   * Changes the accesskey attribute for the specified command.
-   * @param   command
-   *          The command to update.
-   * @param   valueAttribute
-   *          The value attribute to use.
-   */
-  setAccessKey: function(command, valueAttribute) {
-    var commandNode = top.document.getElementById(command);
-    if (commandNode)
-    {
-      var value = commandNode.getAttribute(valueAttribute);
-      if ( value )
-        commandNode.setAttribute('accesskey', value);
-    }
-  },
-
-  /**
-   * Inform all the controllers attached to a node that an event has occurred
-   * (e.g. the tree controllers need to be informed of blur events so that they can change some of the
-   * menu items back to their default values)
-   * @param   node
-   *          The node receiving the event
-   * @param   event
-   *          The event.
-   */
-  onEvent: function(node, event) {
-    var numControllers = node.controllers.getControllerCount();
-    var controller;
-
-    for ( var controllerIndex = 0; controllerIndex < numControllers; controllerIndex++ )
-    {
-      controller = node.controllers.getControllerAt(controllerIndex);
-      if ( controller )
-        controller.onEvent(event);
-    }
-  }
-};
+/* 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/. */
+
+
+/**
+ * Command Updater
+ */
+var CommandUpdater = {
+  /**
+   * Gets a controller that can handle a particular command.
+   * @param   command
+   *          A command to locate a controller for, preferring controllers that
+   *          show the command as enabled.
+   * @returns In this order of precedence:
+   *            - the first controller supporting the specified command
+   *              associated with the focused element that advertises the
+   *              command as ENABLED
+   *            - the first controller supporting the specified command
+   *              associated with the global window that advertises the
+   *              command as ENABLED
+   *            - the first controller supporting the specified command
+   *              associated with the focused element
+   *            - the first controller supporting the specified command
+   *              associated with the global window
+   */
+  _getControllerForCommand: function(command) {
+    try {
+      var controller = top.document.commandDispatcher.getControllerForCommand(command);
+      if (controller && controller.isCommandEnabled(command))
+        return controller;
+    }
+    catch(e) {
+    }
+    var controllerCount = window.controllers.getControllerCount();
+    for (var i = 0; i < controllerCount; ++i) {
+      var current = window.controllers.getControllerAt(i);
+      try {
+        if (current.supportsCommand(command) && current.isCommandEnabled(command))
+          return current;
+      }
+      catch (e) {
+      }
+    }
+    return controller || window.controllers.getControllerForCommand(command);
+  },
+
+  /**
+   * Updates the state of a XUL <command> element for the specified command
+   * depending on its state.
+   * @param   command
+   *          The name of the command to update the XUL <command> element for
+   */
+  updateCommand: function(command) {
+    var enabled = false;
+    try {
+      var controller = this._getControllerForCommand(command);
+      if (controller) {
+        enabled = controller.isCommandEnabled(command);
+      }
+    }
+    catch(ex) { }
+
+    this.enableCommand(command, enabled);
+  },
+
+  /**
+   * Updates the state of a XUL <command> element for the specified command
+   * depending on its state.
+   * @param   command
+   *          The name of the command to update the XUL <command> element for
+   */
+  updateCommands: function(_commands) {
+    var commands = _commands.split(",");
+    for (var command in commands) {
+      this.updateCommand(commands[command]);
+    }
+  },
+
+  /**
+   * Enables or disables a XUL <command> element.
+   * @param   command
+   *          The name of the command to enable or disable
+   * @param   enabled
+   *          true if the command should be enabled, false otherwise.
+   */
+  enableCommand: function(command, enabled) {
+    var element = document.getElementById(command);
+    if (!element)
+      return;
+    if (enabled)
+      element.removeAttribute("disabled");
+    else
+      element.setAttribute("disabled", "true");
+  },
+
+  /**
+   * Performs the action associated with a specified command using the most
+   * relevant controller.
+   * @param   command
+   *          The command to perform.
+   */
+  doCommand: function(command) {
+    var controller = this._getControllerForCommand(command);
+    if (!controller)
+      return;
+    controller.doCommand(command);
+  },
+
+  /**
+   * Changes the label attribute for the specified command.
+   * @param   command
+   *          The command to update.
+   * @param   labelAttribute
+   *          The label value to use.
+   */
+  setMenuValue: function(command, labelAttribute) {
+    var commandNode = top.document.getElementById(command);
+    if (commandNode)
+    {
+      var label = commandNode.getAttribute(labelAttribute);
+      if ( label )
+        commandNode.setAttribute('label', label);
+    }
+  },
+
+  /**
+   * Changes the accesskey attribute for the specified command.
+   * @param   command
+   *          The command to update.
+   * @param   valueAttribute
+   *          The value attribute to use.
+   */
+  setAccessKey: function(command, valueAttribute) {
+    var commandNode = top.document.getElementById(command);
+    if (commandNode)
+    {
+      var value = commandNode.getAttribute(valueAttribute);
+      if ( value )
+        commandNode.setAttribute('accesskey', value);
+    }
+  },
+
+  /**
+   * Inform all the controllers attached to a node that an event has occurred
+   * (e.g. the tree controllers need to be informed of blur events so that they can change some of the
+   * menu items back to their default values)
+   * @param   node
+   *          The node receiving the event
+   * @param   event
+   *          The event.
+   */
+  onEvent: function(node, event) {
+    var numControllers = node.controllers.getControllerCount();
+    var controller;
+
+    for ( var controllerIndex = 0; controllerIndex < numControllers; controllerIndex++ )
+    {
+      controller = node.controllers.getControllerAt(controllerIndex);
+      if ( controller )
+        controller.onEvent(event);
+    }
+  }
+};
--- a/browser/metro/base/content/helperui/ItemPinHelper.js
+++ b/browser/metro/base/content/helperui/ItemPinHelper.js
@@ -1,59 +1,59 @@
-// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
-/* 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";
-
-function ItemPinHelper(aUnpinnedPrefName) {
-  this._prefKey = aUnpinnedPrefName;
-}
-
-// Cache preferences on a static variable shared
-// by all instances registered to the same pref key.
-ItemPinHelper._prefValue = {};
-
-ItemPinHelper.prototype = {
-  _getPrefValue: function _getPrefValue() {
-    if (ItemPinHelper._prefValue[this._prefKey])
-      return ItemPinHelper._prefValue[this._prefKey];
-
-    try {
-      // getComplexValue throws if pref never set. Really.
-      let prefValue = Services.prefs.getComplexValue(this._prefKey, Ci.nsISupportsString);
-      ItemPinHelper._prefValue[this._prefKey] = JSON.parse(prefValue.data);
-    } catch(e) {
-      ItemPinHelper._prefValue[this._prefKey] = [];
-    }
-
-    return ItemPinHelper._prefValue[this._prefKey];
-  },
-
-  _setPrefValue: function _setPrefValue(aNewValue) {
-    let stringified = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
-    stringified.data = JSON.stringify(aNewValue);
-
-    Services.prefs.setComplexValue(this._prefKey, Ci.nsISupportsString, stringified);
-    ItemPinHelper._prefValue[this._prefKey] = aNewValue;
-  },
-
-  isPinned: function isPinned(aItemId) {
-    // Bookmarks are visible on StartUI (pinned) by default
-    return this._getPrefValue().indexOf(aItemId) === -1;
-  },
-
-  setUnpinned: function setPinned(aItemId) {
-    let unpinned = this._getPrefValue();
-    unpinned.push(aItemId);
-    this._setPrefValue(unpinned);
-  },
-
-  setPinned: function unsetPinned(aItemId) {
-    let unpinned = this._getPrefValue();
-
-    let index = unpinned.indexOf(aItemId);
-    unpinned.splice(index, 1);
-
-    this._setPrefValue(unpinned);
-  },
-}
+// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
+/* 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";
+
+function ItemPinHelper(aUnpinnedPrefName) {
+  this._prefKey = aUnpinnedPrefName;
+}
+
+// Cache preferences on a static variable shared
+// by all instances registered to the same pref key.
+ItemPinHelper._prefValue = {};
+
+ItemPinHelper.prototype = {
+  _getPrefValue: function _getPrefValue() {
+    if (ItemPinHelper._prefValue[this._prefKey])
+      return ItemPinHelper._prefValue[this._prefKey];
+
+    try {
+      // getComplexValue throws if pref never set. Really.
+      let prefValue = Services.prefs.getComplexValue(this._prefKey, Ci.nsISupportsString);
+      ItemPinHelper._prefValue[this._prefKey] = JSON.parse(prefValue.data);
+    } catch(e) {
+      ItemPinHelper._prefValue[this._prefKey] = [];
+    }
+
+    return ItemPinHelper._prefValue[this._prefKey];
+  },
+
+  _setPrefValue: function _setPrefValue(aNewValue) {
+    let stringified = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+    stringified.data = JSON.stringify(aNewValue);
+
+    Services.prefs.setComplexValue(this._prefKey, Ci.nsISupportsString, stringified);
+    ItemPinHelper._prefValue[this._prefKey] = aNewValue;
+  },
+
+  isPinned: function isPinned(aItemId) {
+    // Bookmarks are visible on StartUI (pinned) by default
+    return this._getPrefValue().indexOf(aItemId) === -1;
+  },
+
+  setUnpinned: function setPinned(aItemId) {
+    let unpinned = this._getPrefValue();
+    unpinned.push(aItemId);
+    this._setPrefValue(unpinned);
+  },
+
+  setPinned: function unsetPinned(aItemId) {
+    let unpinned = this._getPrefValue();
+
+    let index = unpinned.indexOf(aItemId);
+    unpinned.splice(index, 1);
+
+    this._setPrefValue(unpinned);
+  },
+}
--- a/browser/metro/base/tests/mochitest/browser_circular_progress_indicator.js
+++ b/browser/metro/base/tests/mochitest/browser_circular_progress_indicator.js
@@ -1,57 +1,57 @@
-/* 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/. */
-
-let doc;
-
-function test() {
-  waitForExplicitFinish();
-  Task.spawn(function(){
-    info(chromeRoot + "browser_progress_indicator.xul");
-    yield addTab(chromeRoot + "browser_progress_indicator.xul");
-    doc = Browser.selectedTab.browser.contentWindow.document;
-  }).then(runTests);
-}
-
-gTests.push({
-  desc: "circular progress indicator binding is applied.",
-  run: function() {
-    ok(doc, "doc got defined");
-
-    let progressIndicator = doc.querySelector("#progress-indicator");
-    ok(progressIndicator, "progress-indicator is found");
-    is(typeof progressIndicator.reset, "function", "#progress-indicator has a reset() function");
-    is(typeof progressIndicator.updateProgress, "function", "#progress-indicator has a updateProgress() function");
-  }
-});
-
-gTests.push({
-  desc: "start and end angles are correct for various percents complete",
-  run: function() {
-    let progressIndicator = doc.querySelector("#progress-indicator");
-    ok(progressIndicator, "progress-indicator is found");
-    is(typeof progressIndicator.updateProgress, "function", "#progress-indicator has a updateProgress() function");
-
-    let expectedStartAngle = 1.5 * Math.PI;
-
-    let percentComplete = 0;
-    let [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
-    is(startAngle, expectedStartAngle, "start angle is correct");
-    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
-
-    percentComplete = 0.05;
-    [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
-    is(startAngle, expectedStartAngle, "start angle is correct");
-    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
-
-    percentComplete = 0.5;
-    [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
-    is(startAngle, expectedStartAngle, "start angle is correct");
-    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
-
-    percentComplete = 1;
-    [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
-    is(startAngle, expectedStartAngle, "start angle is correct");
-    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
-  }
+/* 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/. */
+
+let doc;
+
+function test() {
+  waitForExplicitFinish();
+  Task.spawn(function(){
+    info(chromeRoot + "browser_progress_indicator.xul");
+    yield addTab(chromeRoot + "browser_progress_indicator.xul");
+    doc = Browser.selectedTab.browser.contentWindow.document;
+  }).then(runTests);
+}
+
+gTests.push({
+  desc: "circular progress indicator binding is applied.",
+  run: function() {
+    ok(doc, "doc got defined");
+
+    let progressIndicator = doc.querySelector("#progress-indicator");
+    ok(progressIndicator, "progress-indicator is found");
+    is(typeof progressIndicator.reset, "function", "#progress-indicator has a reset() function");
+    is(typeof progressIndicator.updateProgress, "function", "#progress-indicator has a updateProgress() function");
+  }
+});
+
+gTests.push({
+  desc: "start and end angles are correct for various percents complete",
+  run: function() {
+    let progressIndicator = doc.querySelector("#progress-indicator");
+    ok(progressIndicator, "progress-indicator is found");
+    is(typeof progressIndicator.updateProgress, "function", "#progress-indicator has a updateProgress() function");
+
+    let expectedStartAngle = 1.5 * Math.PI;
+
+    let percentComplete = 0;
+    let [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
+    is(startAngle, expectedStartAngle, "start angle is correct");
+    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
+
+    percentComplete = 0.05;
+    [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
+    is(startAngle, expectedStartAngle, "start angle is correct");
+    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
+
+    percentComplete = 0.5;
+    [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
+    is(startAngle, expectedStartAngle, "start angle is correct");
+    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
+
+    percentComplete = 1;
+    [startAngle, endAngle] = progressIndicator.updateProgress(percentComplete);
+    is(startAngle, expectedStartAngle, "start angle is correct");
+    is(endAngle, startAngle + (2 * Math.PI * (percentComplete / 100)), "end angle is correct");
+  }
 });
\ No newline at end of file
--- a/browser/metro/base/tests/mochitest/browser_notifications.js
+++ b/browser/metro/base/tests/mochitest/browser_notifications.js
@@ -1,95 +1,95 @@
-/* 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";
-
-function test() {
-  runTests();
-}
-
-function cleanup() {
-  let notificationBox = Browser.getNotificationBox();
-  notificationBox && notificationBox.removeAllNotifications(true);
-}
-
-const XHTML_NS = "http://www.w3.org/1999/xhtml";
-
-function createTestNotification(aLabel, aID) {
-    let notificationBox = Browser.getNotificationBox();
-    let notn = notificationBox.appendNotification(aLabel || "some label", aID || "test-notification",
-                                                  "", notificationBox.PRIORITY_INFO_LOW, []);
-    return notn;
-}
-
-gTests.push({
-  desc: "Verify notification bindings are correct",
-  run: function () {
-    let notificationBox = Browser.getNotificationBox();
-    let notn = createTestNotification();
-
-    let binding = notn && getComputedStyle(notn).MozBinding;
-    is(binding,
-       "url(\"chrome://browser/content/bindings/notification.xml#notification\")",
-       "notification has expected binding");
-
-    is(getComputedStyle(notificationBox).MozBinding,
-       "url(\"chrome://browser/content/bindings/notification.xml#notificationbox\")",
-       "notificationbox has expected binding");
-  },
-  tearDown: cleanup
-});
-
-gTests.push({
-  desc: "Check label property handling",
-  run: function () {
-    let notn = createTestNotification("the label");
-    is(notn.label, "the label");
-
-    let doc = notn.ownerDocument;
-    let fragment = doc.createDocumentFragment();
-    try {
-      let boldLabel = doc.createElementNS(XHTML_NS, "b");
-      boldLabel.innerHTML = 'The <span class="foo">label</span>';
-      fragment.appendChild(boldLabel);
-      notn.label = fragment;
-    } catch (ex) {
-      ok(!ex, "Exception creating notification label with markup: "+ex.message);
-    }
-
-    // expect to get a documentFragment back when the label has markup
-    let labelNode = notn.label;
-    is(labelNode.nodeType,
-       Components.interfaces.nsIDOMNode.DOCUMENT_FRAGMENT_NODE,
-       "notification label getter returns documentFragment nodeType "+Components.interfaces.nsIDOMNode.DOCUMENT_FRAGMENT_NODE+", when value contains markup");
-    ok(labelNode !== fragment,
-       "label fragment is a newly created fragment, not the one we assigned in the setter");
-    ok(labelNode.querySelector("b > .foo"),
-       "label fragment has the expected elements in it");
-  },
-  tearDown: cleanup
-});
-
-gTests.push({
-  desc: "Check adoptNotification does what we expect",
-  setUp: function() {
-    yield addTab("about:start");
-    yield addTab("about:mozilla");
-  },
-  run: function () {
-    let browser = getBrowser();
-    let notn = createTestNotification("label", "adopt-notification");
-    let firstBox = Browser.getNotificationBox();
-    let nextTab = Browser.getNextTab(Browser.getTabForBrowser(browser));
-    let nextBox = Browser.getNotificationBox(nextTab.browser);
-
-    ok(firstBox.getNotificationWithValue("adopt-notification"), "notificationbox has our notification intially");
-    nextBox.adoptNotification(notn);
-
-    ok(!firstBox.getNotificationWithValue("adopt-notification"), "after adoptNotification, original notificationbox no longer has our notification");
-    ok(nextBox.getNotificationWithValue("adopt-notification"), "next notificationbox has our notification");
-  },
-  // leave browser in clean state for next tests
-  tearDown: cleanUpOpenedTabs
-});
-
+/* 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";
+
+function test() {
+  runTests();
+}
+
+function cleanup() {
+  let notificationBox = Browser.getNotificationBox();
+  notificationBox && notificationBox.removeAllNotifications(true);
+}
+
+const XHTML_NS = "http://www.w3.org/1999/xhtml";
+
+function createTestNotification(aLabel, aID) {
+    let notificationBox = Browser.getNotificationBox();
+    let notn = notificationBox.appendNotification(aLabel || "some label", aID || "test-notification",
+                                                  "", notificationBox.PRIORITY_INFO_LOW, []);
+    return notn;
+}
+
+gTests.push({
+  desc: "Verify notification bindings are correct",
+  run: function () {
+    let notificationBox = Browser.getNotificationBox();
+    let notn = createTestNotification();
+
+    let binding = notn && getComputedStyle(notn).MozBinding;
+    is(binding,
+       "url(\"chrome://browser/content/bindings/notification.xml#notification\")",
+       "notification has expected binding");
+
+    is(getComputedStyle(notificationBox).MozBinding,
+       "url(\"chrome://browser/content/bindings/notification.xml#notificationbox\")",
+       "notificationbox has expected binding");
+  },
+  tearDown: cleanup
+});
+
+gTests.push({
+  desc: "Check label property handling",
+  run: function () {
+    let notn = createTestNotification("the label");
+    is(notn.label, "the label");
+
+    let doc = notn.ownerDocument;
+    let fragment = doc.createDocumentFragment();
+    try {
+      let boldLabel = doc.createElementNS(XHTML_NS, "b");
+      boldLabel.innerHTML = 'The <span class="foo">label</span>';
+      fragment.appendChild(boldLabel);
+      notn.label = fragment;
+    } catch (ex) {
+      ok(!ex, "Exception creating notification label with markup: "+ex.message);
+    }
+
+    // expect to get a documentFragment back when the label has markup
+    let labelNode = notn.label;
+    is(labelNode.nodeType,
+       Components.interfaces.nsIDOMNode.DOCUMENT_FRAGMENT_NODE,
+       "notification label getter returns documentFragment nodeType "+Components.interfaces.nsIDOMNode.DOCUMENT_FRAGMENT_NODE+", when value contains markup");
+    ok(labelNode !== fragment,
+       "label fragment is a newly created fragment, not the one we assigned in the setter");
+    ok(labelNode.querySelector("b > .foo"),
+       "label fragment has the expected elements in it");
+  },
+  tearDown: cleanup
+});
+
+gTests.push({
+  desc: "Check adoptNotification does what we expect",
+  setUp: function() {
+    yield addTab("about:start");
+    yield addTab("about:mozilla");
+  },
+  run: function () {
+    let browser = getBrowser();
+    let notn = createTestNotification("label", "adopt-notification");
+    let firstBox = Browser.getNotificationBox();
+    let nextTab = Browser.getNextTab(Browser.getTabForBrowser(browser));
+    let nextBox = Browser.getNotificationBox(nextTab.browser);
+
+    ok(firstBox.getNotificationWithValue("adopt-notification"), "notificationbox has our notification intially");
+    nextBox.adoptNotification(notn);
+
+    ok(!firstBox.getNotificationWithValue("adopt-notification"), "after adoptNotification, original notificationbox no longer has our notification");
+    ok(nextBox.getNotificationWithValue("adopt-notification"), "next notificationbox has our notification");
+  },
+  // leave browser in clean state for next tests
+  tearDown: cleanUpOpenedTabs
+});
+
--- a/browser/metro/base/tests/mochitest/browser_progress_indicator.xul
+++ b/browser/metro/base/tests/mochitest/browser_progress_indicator.xul
@@ -1,15 +1,15 @@
-<?xml version="1.0"?>
-
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/bindings.css" type="text/css"?>
-
-<!DOCTYPE window []>
-
-<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <circularprogressindicator id="progress-indicator" oncommand=""/>
-</window>
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/bindings.css" type="text/css"?>
+
+<!DOCTYPE window []>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <circularprogressindicator id="progress-indicator" oncommand=""/>
+</window>
--- a/browser/metro/base/tests/mochitest/browser_tabs.js
+++ b/browser/metro/base/tests/mochitest/browser_tabs.js
@@ -1,72 +1,72 @@
-// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
-/* 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";
-
-let mockTab = function(aName, aIsClosing) {
-  this.name = aName;
-  this.isClosing = aIsClosing;
-};
-
-mockTab.prototype = {
-  get chromeTab () {
-    let getAttribute = () => this.isClosing;
-    return {
-      hasAttribute: getAttribute
-    }
-  }
-};
-
-let getMockBrowserTabs = function(aTestTabs, aSelected) {
-  let result = {
-    _tabs: aTestTabs,
-    _selectedTab: aTestTabs[aSelected || 0],
-    getTabAtIndex: function(i) this._tabs[i]
-  };
-
-  return [result, Browser.getNextTab.bind(result)];
-};
-
-gTests.push({