1// Copyright (c) 2013 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
5// Redefine '$' here rather than including 'cr.js', since this is
6// the only function needed.  This allows this file to be loaded
7// in a browser directly for layout and some testing purposes.
8var $ = function(id) { return document.getElementById(id); };
9
10/**
11 * A generic WebUI for configuring preference values used by Chrome's gesture
12 * recognition systems.
13 * @param {string} title The user-visible title to display for the configuration
14 *    section.
15 * @param {string} prefix The prefix for the configuration fields.
16 * @param {!Object} fields An array of fields that contain the name of the pref
17 *    and user-visible labels.
18 */
19function GeneralConfig(title, prefix, fields) {
20  this.title = title;
21  this.prefix = prefix;
22  this.fields = fields;
23}
24
25GeneralConfig.prototype = {
26  /**
27   * Sets up the form for configuring all the preference values.
28   */
29  buildAll: function() {
30    this.buildForm();
31    this.loadForm();
32    this.initForm();
33  },
34
35  /**
36   * Dynamically builds web-form based on the list of preferences.
37   */
38  buildForm: function() {
39    var buf = [];
40
41    var section = $('section-template').cloneNode(true);
42    section.removeAttribute('id');
43    var title = section.querySelector('.section-title');
44    title.textContent = this.title;
45
46    for (var i = 0; i < this.fields.length; i++) {
47      var field = this.fields[i];
48
49      var row = $('section-row-template').cloneNode(true);
50      row.removeAttribute('id');
51
52      var label = row.querySelector('.row-label');
53      var input = row.querySelector('.input');
54      var units = row.querySelector('.row-units');
55      var reset = row.querySelector('.row-reset');
56
57      label.setAttribute('for', field.key);
58      label.innerHTML = field.label;
59      input.id = field.key;
60      input.min = field.min || 0;
61
62      if (field.max)
63        input.max = field.max;
64
65      input.step = field.step || 'any';
66
67      if (field.units)
68        units.innerHTML = field.units;
69
70      reset.id = field.key + '-reset';
71      gesture_config.updateResetButton(reset, true);
72
73      section.querySelector('.section-properties').appendChild(row);
74    }
75    $('gesture-form').appendChild(section);
76  },
77
78  /**
79   * Initializes the form by adding appropriate event listeners to elements.
80   */
81  initForm: function() {
82    for (var i = 0; i < this.fields.length; i++) {
83      var field = this.fields[i];
84      var config = this;
85      $(field.key).onchange = (function(key) {
86        config.setPreferenceValue(key, $(key).value);
87        gesture_config.updateResetButton($(key + '-reset'), false);
88        gesture_config.updateResetAllButton(false);
89      }).bind(null, field.key);
90      $(field.key + '-reset').onclick = (function(key) {
91        config.resetPreferenceValue(key);
92      }).bind(null, field.key);
93    }
94  },
95
96  /**
97   * Requests preference values for all the relevant fields.
98   */
99  loadForm: function() {
100    for (var i = 0; i < this.fields.length; i++)
101      this.updatePreferenceValue(this.fields[i].key);
102  },
103
104  /**
105   * Handles processing of "Reset All" button.
106   * Causes all form values to be updated based on current preference values.
107   * @return {boolean} Returns false.
108   */
109  onReset: function() {
110    for (var i = 0; i < this.fields.length; i++) {
111      var field = this.fields[i];
112      this.resetPreferenceValue(field.key);
113    }
114    return false;
115  },
116
117  /**
118   * Requests a preference setting's value.
119   * This method is asynchronous; the result is provided by a call to
120   * updatePreferenceValueResult.
121   * @param {string} prefName The name of the preference value being requested.
122   */
123  updatePreferenceValue: function(prefName) {
124    chrome.send('updatePreferenceValue', [this.prefix + prefName]);
125  },
126
127  /**
128   * Sets a preference setting's value.
129   * @param {string} prefName The name of the preference value being set.
130   * @param {value} value The value to be associated with prefName.
131   */
132  setPreferenceValue: function(prefName, value) {
133    chrome.send('setPreferenceValue',
134        [this.prefix + prefName, parseFloat(value)]);
135  },
136
137  /**
138   * Resets a preference to its default value and get that callback
139   * to updatePreferenceValueResult with the new value of the preference.
140   * @param {string} prefName The name of the requested preference.
141   */
142  resetPreferenceValue: function(prefName) {
143    chrome.send('resetPreferenceValue', [this.prefix + prefName]);
144  }
145};
146
147/**
148 * Returns a GeneralConfig for configuring gestures.* preferences.
149 * @return {object} A GeneralConfig object.
150 */
151function GestureConfig() {
152  /** The title of the section for the gesture preferences. **/
153  /** @const */ var GESTURE_TITLE = 'Gesture Configuration';
154
155  /** Common prefix of gesture preferences. **/
156  /** @const */ var GESTURE_PREFIX = 'gesture.';
157
158  /** List of fields used to dynamically build form. **/
159  var GESTURE_FIELDS = [
160    {
161      key: 'fling_max_cancel_to_down_time_in_ms',
162      label: 'Maximum Cancel to Down Time for Tap Suppression',
163      units: 'milliseconds',
164    },
165    {
166      key: 'fling_max_tap_gap_time_in_ms',
167      label: 'Maximum Tap Gap Time for Tap Suppression',
168      units: 'milliseconds',
169    },
170    {
171      key: 'semi_long_press_time_in_seconds',
172      label: 'Semi Long Press Time',
173      units: 'seconds',
174      step: 0.1
175    },
176    {
177      key: 'max_separation_for_gesture_touches_in_pixels',
178      label: 'Maximum Separation for Gesture Touches',
179      units: 'pixels'
180    },
181    {
182      key: 'tab_scrub_activation_delay_in_ms',
183      label: 'Tab scrub auto activation delay, (-1 for never)',
184      units: 'milliseconds'
185    }
186  ];
187
188  return new GeneralConfig(GESTURE_TITLE, GESTURE_PREFIX, GESTURE_FIELDS);
189}
190
191/**
192 * Returns a GeneralConfig for configuring overscroll.* preferences.
193 * @return {object} A GeneralConfig object.
194 */
195function OverscrollConfig() {
196  /** @const */ var OVERSCROLL_TITLE = 'Overscroll Configuration';
197
198  /** @const */ var OVERSCROLL_PREFIX = 'overscroll.';
199
200  var OVERSCROLL_FIELDS = [
201    {
202      key: 'horizontal_threshold_complete',
203      label: 'Complete when overscrolled (horizontal)',
204      units: '%'
205    },
206    {
207      key: 'vertical_threshold_complete',
208      label: 'Complete when overscrolled (vertical)',
209      units: '%'
210    },
211    {
212      key: 'minimum_threshold_start_touchpad',
213      label: 'Start overscroll gesture (horizontal; touchpad)',
214      units: 'pixels'
215    },
216    {
217      key: 'minimum_threshold_start',
218      label: 'Start overscroll gesture (horizontal; touchscreen)',
219      units: 'pixels'
220    },
221    {
222      key: 'vertical_threshold_start',
223      label: 'Start overscroll gesture (vertical)',
224      units: 'pixels'
225    },
226    {
227      key: 'horizontal_resist_threshold',
228      label: 'Start resisting overscroll after (horizontal)',
229      units: 'pixels'
230    },
231    {
232      key: 'vertical_resist_threshold',
233      label: 'Start resisting overscroll after (vertical)',
234      units: 'pixels'
235    },
236  ];
237
238  return new GeneralConfig(OVERSCROLL_TITLE,
239                           OVERSCROLL_PREFIX,
240                           OVERSCROLL_FIELDS);
241}
242
243/**
244 * WebUI instance for configuring preference values related to gesture input.
245 */
246window.gesture_config = {
247  /**
248   * Build and initialize the gesture configuration form.
249   */
250  initialize: function() {
251    var g = GestureConfig();
252    g.buildAll();
253
254    var o = OverscrollConfig();
255    o.buildAll();
256
257    $('reset-all-button').onclick = function() {
258      g.onReset();
259      o.onReset();
260    };
261  },
262
263  /**
264   * Checks if all gesture preferences are set to default by checking the status
265   * of the reset button associated with each preference.
266   * @return {boolean} True if all gesture preferences are set to default.
267   */
268  areAllPrefsSetToDefault: function() {
269    var resets = $('gesture-form').querySelectorAll('.row-reset');
270    for (var i = 0; i < resets.length; i++) {
271      if (!resets[i].disabled)
272        return false;
273    }
274    return true;
275  },
276
277  /**
278   * Updates the status and label of a preference reset button.
279   * @param {HTMLInputElement} resetButton Reset button for the preference.
280   * @param {boolean} isDefault Whether the preference is set to the default
281   *     value.
282   */
283  updateResetButton: function(resetButton, isDefault) {
284    /** @const */ var TITLE_DEFAULT = 'Default';
285
286    /** @const */ var TITLE_NOT_DEFAULT = 'Reset';
287
288    resetButton.innerHTML = isDefault ? TITLE_DEFAULT : TITLE_NOT_DEFAULT;
289    resetButton.disabled = isDefault;
290  },
291
292  /**
293   * Updates the status and label of "Reset All" button.
294   * @param {boolean} isDefault Whether all preference are set to their default
295   *     values.
296   */
297  updateResetAllButton: function(isDefault) {
298    /** @const */ var TITLE_DEFAULT = 'Everything is set to default';
299
300    /** @const */ var TITLE_NOT_DEFAULT = 'Reset All To Default';
301
302    var button = $('reset-all-button');
303    button.innerHTML = isDefault ? TITLE_DEFAULT : TITLE_NOT_DEFAULT;
304    button.disabled = isDefault;
305  },
306
307  /**
308   * Handle callback from call to updatePreferenceValue.
309   * @param {string} prefName The name of the requested preference value.
310   * @param {value} value The current value associated with prefName.
311   * @param {boolean} isDefault Whether the value is the default value.
312   */
313  updatePreferenceValueResult: function(prefName, value, isDefault) {
314    prefName = prefName.substring(prefName.indexOf('.') + 1);
315    $(prefName).value = value;
316    this.updateResetButton($(prefName + '-reset'), isDefault);
317    this.updateResetAllButton(this.areAllPrefsSetToDefault());
318  },
319};
320
321document.addEventListener('DOMContentLoaded', gesture_config.initialize);
322