pref_ui.js revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5cr.define('options', function() {
6
7  var Preferences = options.Preferences;
8  /////////////////////////////////////////////////////////////////////////////
9  // PrefCheckbox class:
10  // TODO(jhawkins): Refactor all this copy-pasted code!
11
12  // Define a constructor that uses an input element as its underlying element.
13  var PrefCheckbox = cr.ui.define('input');
14
15  PrefCheckbox.prototype = {
16    // Set up the prototype chain
17    __proto__: HTMLInputElement.prototype,
18
19    /**
20     * Initialization function for the cr.ui framework.
21     */
22    decorate: function() {
23      this.type = 'checkbox';
24      var self = this;
25
26      self.initializeValueType(self.getAttribute('value-type'));
27
28      // Listen to pref changes.
29      Preferences.getInstance().addEventListener(
30          this.pref,
31          function(event) {
32            var value = event.value && event.value['value'] != undefined ?
33                event.value['value'] : event.value;
34
35            // Invert pref value if inverted_pref == true.
36            if (self.inverted_pref)
37              self.checked = !Boolean(value);
38            else
39              self.checked = Boolean(value);
40
41            self.managed = event.value && event.value['managed'] != undefined ?
42                event.value['managed'] : false;
43
44            // Managed UI elements can only be disabled as a result of being
45            // managed. They cannot be enabled as a result of a pref being
46            // unmanaged.
47            if (self.managed)
48              self.disabled = true;
49          });
50
51      // Listen to user events.
52      this.addEventListener(
53          'click',
54          function(e) {
55            var value = self.inverted_pref ? !self.checked : self.checked;
56            switch(self.valueType) {
57              case 'number':
58                Preferences.setIntegerPref(self.pref,
59                    Number(value), self.metric);
60                break;
61              case 'boolean':
62                Preferences.setBooleanPref(self.pref,
63                    value, self.metric);
64                break;
65            }
66          });
67    },
68
69    /**
70     * Sets up options in checkbox element.
71     * @param {String} valueType The preference type for this checkbox.
72     */
73    initializeValueType: function(valueType) {
74      this.valueType = valueType || 'boolean';
75    }
76  };
77
78  /**
79   * The preference name.
80   * @type {string}
81   */
82  cr.defineProperty(PrefCheckbox, 'pref', cr.PropertyKind.ATTR);
83
84  /**
85   * The user metric string.
86   * @type {string}
87   */
88  cr.defineProperty(PrefCheckbox, 'metric', cr.PropertyKind.ATTR);
89
90  /**
91   * Whether to use inverted pref value.
92   * @type {boolean}
93   */
94  cr.defineProperty(PrefCheckbox, 'inverted_pref', cr.PropertyKind.BOOL_ATTR);
95
96  /////////////////////////////////////////////////////////////////////////////
97  // PrefRadio class:
98
99  //Define a constructor that uses an input element as its underlying element.
100  var PrefRadio = cr.ui.define('input');
101
102  PrefRadio.prototype = {
103    // Set up the prototype chain
104    __proto__: HTMLInputElement.prototype,
105
106    /**
107     * Initialization function for the cr.ui framework.
108     */
109    decorate: function() {
110      this.type = 'radio';
111      var self = this;
112
113      // Listen to pref changes.
114      Preferences.getInstance().addEventListener(this.pref,
115          function(event) {
116            var value = event.value && event.value['value'] != undefined ?
117                event.value['value'] : event.value;
118            self.managed = event.value && event.value['managed'] != undefined ?
119                event.value['managed'] : false;
120            self.checked = String(value) == self.value;
121
122            // Managed UI elements can only be disabled as a result of being
123            // managed. They cannot be enabled as a result of a pref being
124            // unmanaged.
125            if (self.managed)
126              self.disabled = true;
127          });
128
129      // Listen to user events.
130      this.addEventListener('change',
131          function(e) {
132            if(self.value == 'true' || self.value == 'false') {
133              Preferences.setBooleanPref(self.pref,
134                  self.value == 'true', self.metric);
135            } else {
136              Preferences.setIntegerPref(self.pref,
137                  parseInt(self.value, 10), self.metric);
138            }
139          });
140    },
141
142    /**
143     * Getter for preference name attribute.
144     */
145    get pref() {
146      return this.getAttribute('pref');
147    },
148
149    /**
150     * Setter for preference name attribute.
151     */
152    set pref(name) {
153      this.setAttribute('pref', name);
154    }
155  };
156
157  /**
158   * The user metric string.
159   * @type {string}
160   */
161  cr.defineProperty(PrefRadio, 'metric', cr.PropertyKind.ATTR);
162
163  /////////////////////////////////////////////////////////////////////////////
164  // PrefNumeric class:
165
166  // Define a constructor that uses an input element as its underlying element.
167  var PrefNumeric = function() {};
168  PrefNumeric.prototype = {
169    // Set up the prototype chain
170    __proto__: HTMLInputElement.prototype,
171
172    /**
173     * Initialization function for the cr.ui framework.
174     */
175    decorate: function() {
176      var self = this;
177
178      // Listen to pref changes.
179      Preferences.getInstance().addEventListener(this.pref,
180          function(event) {
181            self.value = event.value && event.value['value'] != undefined ?
182                event.value['value'] : event.value;
183            self.managed = event.value && event.value['managed'] != undefined ?
184                event.value['managed'] : false;
185
186            // Managed UI elements can only be disabled as a result of being
187            // managed. They cannot be enabled as a result of a pref being
188            // unmanaged.
189            if (self.managed)
190              self.disabled = true;
191          });
192
193      // Listen to user events.
194      this.addEventListener('change',
195          function(e) {
196            if (this.validity.valid) {
197              Preferences.setIntegerPref(self.pref, self.value, self.metric);
198            }
199          });
200    }
201  };
202
203  /**
204   * The preference name.
205   * @type {string}
206   */
207  cr.defineProperty(PrefNumeric, 'pref', cr.PropertyKind.ATTR);
208
209  /**
210   * The user metric string.
211   * @type {string}
212   */
213  cr.defineProperty(PrefNumeric, 'metric', cr.PropertyKind.ATTR);
214
215  /////////////////////////////////////////////////////////////////////////////
216  // PrefNumber class:
217
218  // Define a constructor that uses an input element as its underlying element.
219  var PrefNumber = cr.ui.define('input');
220
221  PrefNumber.prototype = {
222    // Set up the prototype chain
223    __proto__: PrefNumeric.prototype,
224
225    /**
226     * Initialization function for the cr.ui framework.
227     */
228    decorate: function() {
229      this.type = 'number';
230      PrefNumeric.prototype.decorate.call(this);
231
232      // Listen to user events.
233      this.addEventListener('input',
234          function(e) {
235            if (this.validity.valid) {
236              Preferences.setIntegerPref(self.pref, self.value, self.metric);
237            }
238          });
239    }
240  };
241
242  /////////////////////////////////////////////////////////////////////////////
243  // PrefRange class:
244
245  // Define a constructor that uses an input element as its underlying element.
246  var PrefRange = cr.ui.define('input');
247
248  PrefRange.prototype = {
249    // Set up the prototype chain
250    __proto__: PrefNumeric.prototype,
251
252    /**
253     * Initialization function for the cr.ui framework.
254     */
255    decorate: function() {
256      this.type = 'range';
257      PrefNumeric.prototype.decorate.call(this);
258      var self = this;
259
260      // Additionally change the indicator as well.
261      Preferences.getInstance().addEventListener(this.pref,
262          function(event) {
263            self.updateIndicator();
264          });
265
266      // Listen to user events.
267      this.addEventListener('input',
268          function(e) {
269            this.updateIndicator();
270          });
271    },
272
273    updateIndicator: function() {
274      if ($(this.id + '-value')) {
275        $(this.id + '-value').textContent = this.value;
276      }
277    }
278  };
279
280  /////////////////////////////////////////////////////////////////////////////
281  // PrefSelect class:
282
283  // Define a constructor that uses an select element as its underlying element.
284  var PrefSelect = cr.ui.define('select');
285
286  PrefSelect.prototype = {
287    // Set up the prototype chain
288    __proto__: HTMLSelectElement.prototype,
289
290    /**
291    * Initialization function for the cr.ui framework.
292    */
293    decorate: function() {
294      var self = this;
295
296      var values = self.getAttribute('data-values');
297      if (values) {
298        self.initializeValues(templateData[values]);
299      }
300
301      // Listen to pref changes.
302      Preferences.getInstance().addEventListener(this.pref,
303          function(event) {
304            var value = event.value && event.value['value'] != undefined ?
305                event.value['value'] : event.value;
306
307            // Make sure |value| is a string, because the value is stored as a
308            // string in the HTMLOptionElement.
309            value = value.toString();
310
311            self.managed = event.value && event.value['managed'] != undefined ?
312                event.value['managed'] : false;
313
314            // Managed UI elements can only be disabled as a result of being
315            // managed. They cannot be enabled as a result of a pref being
316            // unmanaged.
317            if (self.managed)
318              self.disabled = true;
319
320            var found = false;
321            for (var i = 0; i < self.options.length; i++) {
322              if (self.options[i].value == value) {
323                self.selectedIndex = i;
324                found = true;
325              }
326            }
327
328            // Item not found, select first item.
329            if (!found)
330              self.selectedIndex = 0;
331
332            if (self.onchange != undefined)
333              self.onchange(event);
334          });
335
336      // Listen to user events.
337      this.addEventListener('change',
338          function(e) {
339            switch(self.dataType) {
340              case 'number':
341                Preferences.setIntegerPref(self.pref,
342                    self.options[self.selectedIndex].value, self.metric);
343                break;
344              case 'boolean':
345                var option = self.options[self.selectedIndex];
346                var value = (option.value == 'true') ? true : false;
347                Preferences.setBooleanPref(self.pref, value, self.metric);
348                break;
349              case 'string':
350                Preferences.setStringPref(self.pref,
351                    self.options[self.selectedIndex].value, self.metric);
352                break;
353            }
354          });
355    },
356
357    /**
358     * Sets up options in select element.
359     * @param {Array} options List of option and their display text.
360     *     Each element in the array is an array of length 2 which contains
361     *     options value in the first element and display text in the second
362     *     element. May be undefined.
363     *
364     * TODO(zelidrag): move this to that i18n template classes.
365     */
366    initializeValues: function(options) {
367      options.forEach(function (values) {
368        if (this.dataType == undefined)
369          this.dataType = typeof values[0];
370
371        this.appendChild(new Option(values[1], values[0]));
372      }, this);
373    }
374  };
375
376  /**
377   * The preference name.
378   * @type {string}
379   */
380  cr.defineProperty(PrefSelect, 'pref', cr.PropertyKind.ATTR);
381
382  /**
383   * The user metric string.
384   * @type {string}
385   */
386  cr.defineProperty(PrefSelect, 'metric', cr.PropertyKind.ATTR);
387
388  /////////////////////////////////////////////////////////////////////////////
389  // PrefTextField class:
390
391  // Define a constructor that uses an input element as its underlying element.
392  var PrefTextField = cr.ui.define('input');
393
394  PrefTextField.prototype = {
395    // Set up the prototype chain
396    __proto__: HTMLInputElement.prototype,
397
398    /**
399     * Initialization function for the cr.ui framework.
400     */
401    decorate: function() {
402      var self = this;
403
404      // Listen to pref changes.
405      Preferences.getInstance().addEventListener(this.pref,
406          function(event) {
407            self.value = event.value && event.value['value'] != undefined ?
408                event.value['value'] : event.value;
409            self.managed = event.value && event.value['managed'] != undefined ?
410                event.value['managed'] : false;
411
412            // Managed UI elements can only be disabled as a result of being
413            // managed. They cannot be enabled as a result of a pref being
414            // unmanaged.
415            if (self.managed)
416              self.disabled = true;
417          });
418
419      // Listen to user events.
420      this.addEventListener('change',
421          function(e) {
422            Preferences.setStringPref(self.pref, self.value, self.metric);
423          });
424
425      window.addEventListener('unload',
426          function() {
427            if (document.activeElement == self)
428              self.blur();
429          });
430    }
431  };
432
433  /**
434   * The preference name.
435   * @type {string}
436   */
437  cr.defineProperty(PrefTextField, 'pref', cr.PropertyKind.ATTR);
438
439  /**
440   * The user metric string.
441   * @type {string}
442   */
443  cr.defineProperty(PrefTextField, 'metric', cr.PropertyKind.ATTR);
444
445  // Export
446  return {
447    PrefCheckbox: PrefCheckbox,
448    PrefNumber: PrefNumber,
449    PrefNumeric: PrefNumeric,
450    PrefRadio: PrefRadio,
451    PrefRange: PrefRange,
452    PrefSelect: PrefSelect,
453    PrefTextField: PrefTextField
454  };
455
456});
457