summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/options/controlled_setting.js
blob: eafa7e350163abfde0d10ebd44d91c4e6ff16ec4 (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {
  var Preferences = options.Preferences;

  /**
   * A controlled setting indicator that can be placed on a setting as an
   * indicator that the value is controlled by some external entity such as
   * policy or an extension.
   * @constructor
   * @extends {HTMLSpanElement}
   */
  var ControlledSettingIndicator = cr.ui.define('span');

  ControlledSettingIndicator.prototype = {
    __proto__: cr.ui.BubbleButton.prototype,

    /**
     * Decorates the base element to show the proper icon.
     */
    decorate: function() {
      cr.ui.BubbleButton.prototype.decorate.call(this);
      this.classList.add('controlled-setting-indicator');

      // If there is a pref, track its controlledBy and recommendedValue
      // properties in order to be able to bring up the correct bubble.
      if (this.pref) {
        Preferences.getInstance().addEventListener(
            this.pref, this.handlePrefChange.bind(this));
        this.resetHandler = this.clearAssociatedPref_;
      }
    },

    /**
     * The given handler will be called when the user clicks on the 'reset to
     * recommended value' link shown in the indicator bubble. The |this| object
     * will be the indicator itself.
     * @param {function()} handler The handler to be called.
     */
    set resetHandler(handler) {
      this.resetHandler_ = handler;
    },

    /**
     * Clears the preference associated with this indicator.
     * @private
     */
    clearAssociatedPref_: function() {
      Preferences.clearPref(this.pref, !this.dialogPref);
    },

    /* Handle changes to the associated pref by hiding any currently visible
     * bubble and updating the controlledBy property.
     * @param {Event} event Pref change event.
     */
    handlePrefChange: function(event) {
      OptionsPage.hideBubble();
      if (event.value.controlledBy) {
        this.controlledBy =
            !this.value || String(event.value.value) == this.value ?
            event.value.controlledBy : null;
      } else if (event.value.recommendedValue != undefined) {
        this.controlledBy =
            !this.value || String(event.value.recommendedValue) == this.value ?
            'hasRecommendation' : null;
      } else {
        this.controlledBy = null;
      }
    },

    /**
     * Open or close a bubble with further information about the pref.
     * @private
     */
    toggleBubble_: function() {
      if (this.showingBubble) {
        OptionsPage.hideBubble();
      } else {
        var self = this;

        // Construct the bubble text.
        if (this.hasAttribute('plural')) {
          var defaultStrings = {
            'policy': loadTimeData.getString('controlledSettingsPolicy'),
            'extension': loadTimeData.getString('controlledSettingsExtension'),
          };
        } else {
          var defaultStrings = {
            'policy': loadTimeData.getString('controlledSettingPolicy'),
            'extension': loadTimeData.getString('controlledSettingExtension'),
            'recommended':
                loadTimeData.getString('controlledSettingRecommended'),
            'hasRecommendation':
                loadTimeData.getString('controlledSettingHasRecommendation'),
          };
        }

        // No controller, no bubble.
        if (!this.controlledBy || !(this.controlledBy in defaultStrings))
          return;

        var text = defaultStrings[this.controlledBy];

        // Apply text overrides.
        if (this.hasAttribute('text' + this.controlledBy))
          text = this.getAttribute('text' + this.controlledBy);

        // Create the DOM tree.
        var content = document.createElement('div');
        content.className = 'controlled-setting-bubble-content';
        content.setAttribute('controlled-by', this.controlledBy);
        content.textContent = text;

        if (this.controlledBy == 'hasRecommendation' && this.resetHandler_ &&
            !this.readOnly) {
          var container = document.createElement('div');
          var action = document.createElement('button');
          action.classList.add('link-button');
          action.classList.add('controlled-setting-bubble-action');
          action.textContent =
              loadTimeData.getString('controlledSettingFollowRecommendation');
          action.addEventListener('click', function(event) {
            self.resetHandler_();
          });
          container.appendChild(action);
          content.appendChild(container);
        }

        OptionsPage.showBubble(content, this.image, this, this.location);
      }
    },
  };

  /**
   * The name of the associated preference.
   * @type {string}
   */
  cr.defineProperty(ControlledSettingIndicator, 'pref', cr.PropertyKind.ATTR);

  /**
   * Whether this indicator is part of a dialog. If so, changes made to the
   * associated preference take effect in the settings UI immediately but are
   * only actually committed when the user confirms the dialog. If the user
   * cancels the dialog instead, the changes are rolled back in the settings UI
   * and never committed.
   * @type {boolean}
   */
  cr.defineProperty(ControlledSettingIndicator, 'dialogPref',
                    cr.PropertyKind.BOOL_ATTR);

  /**
   * The value of the associated preference that the indicator represents. If
   * this is not set, the indicator will be visible whenever any value is
   * enforced or recommended. If it is set, the indicator will be visible only
   * when the enforced or recommended value matches the value it represents.
   * This allows multiple indicators to be created for a set of radio buttons,
   * ensuring that only one of them is visible at a time.
   */
  cr.defineProperty(ControlledSettingIndicator, 'value',
                    cr.PropertyKind.ATTR);

  /**
   * The status of the associated preference:
   * - 'policy':            A specific value is enfoced by policy.
   * - 'extension':         A specific value is enforced by an extension.
   * - 'recommended':       A value is recommended by policy. The user could
   *                        override this recommendation but has not done so.
   * - 'hasRecommendation': A value is recommended by policy. The user has
   *                        overridden this recommendation.
   * - unset:               The value is controlled by the user alone.
   * @type {string}
   */
  cr.defineProperty(ControlledSettingIndicator, 'controlledBy',
                    cr.PropertyKind.ATTR);

  // Export.
  return {
    ControlledSettingIndicator: ControlledSettingIndicator
  };
});