Bug 694291 - Add a preference mirroring the presence of the search widget in the navigation toolbar. r=past draft
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Fri, 02 Jun 2017 13:47:29 +0100
changeset 588232 f1568d3e14487192adb9025bef0a94ec4fd3c440
parent 588052 aeb3d0ca558f034cbef1c5a68bd07dd738611494
child 631520 5f796ff74f09deda934480ea161333767d5cc08b
push id61977
push userpaolo.mozmail@amadzone.org
push dateFri, 02 Jun 2017 12:47:57 +0000
reviewerspast
bugs694291
milestone55.0a1
Bug 694291 - Add a preference mirroring the presence of the search widget in the navigation toolbar. r=past MozReview-Commit-ID: 9UmowyRTTMK
browser/app/profile/firefox.js
browser/components/customizableui/CustomizableUI.jsm
browser/components/customizableui/SearchWidgetTracker.jsm
browser/components/customizableui/moz.build
browser/components/customizableui/test/browser.ini
browser/components/customizableui/test/browser_694291_searchbar_preference.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -399,16 +399,22 @@ pref("browser.search.order.US.3",       
 pref("browser.search.openintab", false);
 
 // context menu searches open in the foreground
 pref("browser.search.context.loadInBackground", false);
 
 // comma seperated list of of engines to hide in the search panel.
 pref("browser.search.hiddenOneOffs", "");
 
+// Mirrors whether the search-container widget is in the navigation toolbar. The
+// default value of this preference must match the DEFAULT_AREA_PLACEMENTS of
+// UITelemetry.jsm, the navbarPlacements of CustomizableUI.jsm, and the
+// position and attributes of the search-container element in browser.xul.
+pref("browser.search.widget.inNavBar", true);
+
 #ifndef RELEASE_OR_BETA
 pref("browser.search.reset.enabled", true);
 #endif
 
 pref("browser.sessionhistory.max_entries", 50);
 
 // Built-in default permissions.
 pref("permissions.manager.defaultsUrl", "resource://app/defaults/permissions");
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -8,16 +8,18 @@ this.EXPORTED_SYMBOLS = ["CustomizableUI
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PanelWideWidgetTracker",
   "resource:///modules/PanelWideWidgetTracker.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "SearchWidgetTracker",
+  "resource:///modules/SearchWidgetTracker.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableWidgets",
   "resource:///modules/CustomizableWidgets.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
   "resource://gre/modules/DeferredTask.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyGetter(this, "gWidgetsBundle", function() {
   const kUrl = "chrome://browser/locale/customizableui/customizableWidgets.properties";
@@ -294,16 +296,18 @@ var CustomizableUIInternal = {
     }, true);
 
     this.registerArea(CustomizableUI.AREA_ADDONBAR, {
       type: CustomizableUI.TYPE_TOOLBAR,
       legacy: true,
       defaultPlacements: ["addonbar-closebutton", "status-bar"],
       defaultCollapsed: false,
     }, true);
+
+    SearchWidgetTracker.init();
   },
 
   _updateAreasForPhoton() {
     if (gPhotonStructure) {
       if (gAreas.has(CustomizableUI.AREA_PANEL)) {
         this.unregisterArea(CustomizableUI.AREA_PANEL, true);
       }
       this.registerArea(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, {
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/SearchWidgetTracker.jsm
@@ -0,0 +1,71 @@
+/* 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/. */
+
+/*
+ * Keeps the "browser.search.widget.inNavBar" preference synchronized.
+ */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["SearchWidgetTracker"];
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+                                  "resource:///modules/CustomizableUI.jsm");
+
+const WIDGET_ID = "search-container";
+const PREF_NAME = "browser.search.widget.inNavBar";
+
+const SearchWidgetTracker = {
+  init() {
+    this.onWidgetAdded = this.onWidgetRemoved = (widgetId, area) => {
+      if (widgetId == WIDGET_ID && area == CustomizableUI.AREA_NAVBAR) {
+        this.syncPreferenceWithWidget();
+      }
+    };
+    this.onWidgetReset = this.onWidgetUndoMove = node => {
+      if (node.id == WIDGET_ID) {
+        this.syncPreferenceWithWidget();
+      }
+    };
+    CustomizableUI.addListener(this);
+    Services.prefs.addObserver(PREF_NAME,
+                               () => this.syncWidgetWithPreference());
+  },
+
+  onCustomizeEnd() {
+    // onWidgetUndoMove does not fire when the search container is moved back to
+    // the customization palette as a result of an undo, so we sync again here.
+    this.syncPreferenceWithWidget();
+  },
+
+  syncPreferenceWithWidget() {
+    Services.prefs.setBoolPref(PREF_NAME, this.widgetIsInNavBar);
+  },
+
+  syncWidgetWithPreference() {
+    let newValue = Services.prefs.getBoolPref(PREF_NAME);
+    if (newValue == this.widgetIsInNavBar) {
+      return;
+    }
+
+    if (newValue) {
+      // The URL bar widget is always present in the navigation toolbar, so we
+      // can simply read its position to place the search bar right after it.
+      CustomizableUI.addWidgetToArea(WIDGET_ID, CustomizableUI.AREA_NAVBAR,
+        CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1);
+    } else {
+      CustomizableUI.removeWidgetFromArea(WIDGET_ID);
+    }
+  },
+
+  get widgetIsInNavBar() {
+    let placement = CustomizableUI.getPlacementOfWidget(WIDGET_ID);
+    return placement ? placement.area == CustomizableUI.AREA_NAVBAR : false;
+  },
+};
--- a/browser/components/customizableui/moz.build
+++ b/browser/components/customizableui/moz.build
@@ -13,15 +13,16 @@ BROWSER_CHROME_MANIFESTS += ['test/brows
 EXTRA_JS_MODULES += [
     'CustomizableUI.jsm',
     'CustomizableWidgets.jsm',
     'CustomizeMode.jsm',
     'DragPositionManager.jsm',
     'PanelMultiView.jsm',
     'PanelWideWidgetTracker.jsm',
     'ScrollbarSampler.jsm',
+    'SearchWidgetTracker.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
     DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Toolbars and Customization')
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 support-files =
   head.js
   support/test_967000_charEncoding_page.html
   support/feeds_test_page.html
   support/test-feed.xml
 
+[browser_694291_searchbar_preference.js]
 [browser_873501_handle_specials.js]
 [browser_876926_customize_mode_wrapping.js]
 [browser_876944_customize_mode_create_destroy.js]
 [browser_877006_missing_view.js]
 [browser_877178_unregisterArea.js]
 [browser_877447_skip_missing_ids.js]
 [browser_878452_drag_to_panel.js]
 [browser_880164_customization_context_menus.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_694291_searchbar_preference.js
@@ -0,0 +1,49 @@
+/* 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 WIDGET_ID = "search-container";
+const PREF_NAME = "browser.search.widget.inNavBar";
+
+function checkDefaults() {
+  // If the following defaults change, then the DEFAULT_AREA_PLACEMENTS of
+  // UITelemetry.jsm, the navbarPlacements of CustomizableUI.jsm, and the
+  // position and attributes of the search-container element in browser.xul
+  // should also change at the same time.
+  ok(Services.prefs.getBoolPref(PREF_NAME));
+  let placement = CustomizableUI.getPlacementOfWidget(WIDGET_ID);
+  is(placement.area, CustomizableUI.AREA_NAVBAR);
+  is(placement.position,
+     CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1);
+}
+
+add_task(async function test_defaults() {
+  await SpecialPowers.pushPrefEnv({set: [["browser.photon.structure.enabled", false]]});
+
+  // Verify the default state before the first test.
+  checkDefaults();
+});
+
+add_task(async function test_syncPreferenceWithWidget() {
+  // Moving the widget to any position outside of the navigation toolbar should
+  // turn the preference to false.
+  CustomizableUI.addWidgetToArea(WIDGET_ID, CustomizableUI.AREA_PANEL);
+  ok(!Services.prefs.getBoolPref(PREF_NAME));
+
+  // Moving the widget back to any position in the navigation toolbar should
+  // turn the preference to true again.
+  CustomizableUI.addWidgetToArea(WIDGET_ID, CustomizableUI.AREA_NAVBAR);
+  ok(Services.prefs.getBoolPref(PREF_NAME));
+});
+
+add_task(async function test_syncWidgetWithPreference() {
+  // This should move the widget the customization palette.
+  Services.prefs.setBoolPref(PREF_NAME, false);
+  is(CustomizableUI.getPlacementOfWidget(WIDGET_ID), null);
+
+  // This should return the widget to its default placement.
+  Services.prefs.setBoolPref(PREF_NAME, true);
+  checkDefaults();
+});