summaryrefslogtreecommitdiffstats
path: root/browser/components/customizableui/SearchWidgetTracker.sys.mjs
blob: 64d7720349faeec8bbb7d786181eb076ceaca395 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/* 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,
 * and ensures persisted widths are updated if the search bar is removed.
 */

import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
import { CustomizableUI } from "resource:///modules/CustomizableUI.sys.mjs";

const lazy = {};

ChromeUtils.defineModuleGetter(
  lazy,
  "BrowserUsageTelemetry",
  "resource:///modules/BrowserUsageTelemetry.jsm"
);

const WIDGET_ID = "search-container";
const PREF_NAME = "browser.search.widget.inNavBar";

export const SearchWidgetTracker = {
  init() {
    this.onWidgetReset = this.onWidgetUndoMove = node => {
      if (node.id == WIDGET_ID) {
        this.syncPreferenceWithWidget();
        this.removePersistedWidths();
      }
    };
    CustomizableUI.addListener(this);
    Services.prefs.addObserver(PREF_NAME, () =>
      this.syncWidgetWithPreference()
    );
  },

  onWidgetAdded(widgetId, area) {
    if (widgetId == WIDGET_ID && area == CustomizableUI.AREA_NAVBAR) {
      this.syncPreferenceWithWidget();
    }
  },

  onWidgetRemoved(aWidgetId, aArea) {
    if (aWidgetId == WIDGET_ID && aArea == CustomizableUI.AREA_NAVBAR) {
      this.syncPreferenceWithWidget();
      this.removePersistedWidths();
    }
  },

  onAreaNodeRegistered(aArea) {
    // The placement of the widget always takes priority, and the preference
    // should always match the actual placement when the browser starts up - i.e.
    // once the navigation bar has been registered.
    if (aArea == CustomizableUI.AREA_NAVBAR) {
      this.syncPreferenceWithWidget();
    }
  },

  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
      );
      lazy.BrowserUsageTelemetry.recordWidgetChange(
        WIDGET_ID,
        CustomizableUI.AREA_NAVBAR,
        "searchpref"
      );
    } else {
      CustomizableUI.removeWidgetFromArea(WIDGET_ID);
      lazy.BrowserUsageTelemetry.recordWidgetChange(
        WIDGET_ID,
        null,
        "searchpref"
      );
    }
  },

  removePersistedWidths() {
    Services.xulStore.removeValue(
      AppConstants.BROWSER_CHROME_URL,
      WIDGET_ID,
      "width"
    );
    for (let win of CustomizableUI.windows) {
      let searchbar =
        win.document.getElementById(WIDGET_ID) ||
        win.gNavToolbox.palette.querySelector("#" + WIDGET_ID);
      searchbar.removeAttribute("width");
      searchbar.style.removeProperty("width");
    }
  },

  get widgetIsInNavBar() {
    let placement = CustomizableUI.getPlacementOfWidget(WIDGET_ID);
    return placement?.area == CustomizableUI.AREA_NAVBAR;
  },
};