Home | History | Annotate | Download | only in resources
      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.
      8 var $ = 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  */
     19 function GeneralConfig(title, prefix, fields) {
     20   this.title = title;
     21   this.prefix = prefix;
     22   this.fields = fields;
     23 }
     24 
     25 GeneralConfig.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  */
    151 function 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: 'long_press_time_in_seconds',
    172       label: 'Long Press Time',
    173       units: 'seconds'
    174     },
    175     {
    176       key: 'semi_long_press_time_in_seconds',
    177       label: 'Semi Long Press Time',
    178       units: 'seconds',
    179       step: 0.1
    180     },
    181     {
    182       key: 'max_seconds_between_double_click',
    183       label: 'Maximum Double Click Interval',
    184       units: 'seconds',
    185       step: 0.1
    186     },
    187     {
    188       key: 'max_separation_for_gesture_touches_in_pixels',
    189       label: 'Maximum Separation for Gesture Touches',
    190       units: 'pixels'
    191     },
    192     {
    193       key: 'max_swipe_deviation_ratio',
    194       label: 'Maximum Swipe Deviation',
    195       units: ''
    196     },
    197     {
    198       key: 'max_touch_down_duration_in_seconds_for_click',
    199       label: 'Maximum Touch-Down Duration for Click',
    200       units: 'seconds',
    201       step: 0.1
    202     },
    203     {
    204       key: 'max_touch_move_in_pixels_for_click',
    205       label: 'Maximum Touch-Move for Click',
    206       units: 'pixels'
    207     },
    208     {
    209       key: 'max_distance_between_taps_for_double_tap',
    210       label: 'Maximum Distance between two taps for Double Tap',
    211       units: 'pixels'
    212     },
    213     {
    214       key: 'min_distance_for_pinch_scroll_in_pixels',
    215       label: 'Minimum Distance for Pinch Scroll',
    216       units: 'pixels'
    217     },
    218     {
    219       key: 'min_flick_speed_squared',
    220       label: 'Minimum Flick Speed Squared',
    221       units: '(pixels/sec.)<sup>2</sup>'
    222     },
    223     {
    224       key: 'min_pinch_update_distance_in_pixels',
    225       label: 'Minimum Pinch Update Distance',
    226       units: 'pixels'
    227     },
    228     {
    229       key: 'min_rail_break_velocity',
    230       label: 'Minimum Rail-Break Velocity',
    231       units: 'pixels/sec.'
    232     },
    233     {
    234       key: 'min_scroll_delta_squared',
    235       label: 'Minimum Scroll Delta Squared',
    236       units: ''
    237     },
    238     {
    239       key: 'scroll_prediction_seconds',
    240       label: 'Scroll prediction interval<br>' +
    241           '(Enable scroll prediction in ' +
    242               '<a href="chrome://flags">chrome://flags</a>)',
    243       units: 'seconds',
    244       step: 0.01
    245     },
    246     {
    247       key: 'min_swipe_speed',
    248       label: 'Minimum Swipe Speed',
    249       units: 'pixels/sec.'
    250     },
    251     {
    252       key: 'min_touch_down_duration_in_seconds_for_click',
    253       label: 'Minimum Touch-Down Duration for Click',
    254       units: 'seconds',
    255       step: 0.01
    256     },
    257     {
    258       key: 'points_buffered_for_velocity',
    259       label: 'Points Buffered for Velocity',
    260       units: '',
    261       step: 1
    262     },
    263     {
    264       key: 'rail_break_proportion',
    265       label: 'Rail-Break Proportion',
    266       units: '%'
    267     },
    268     {
    269       key: 'rail_start_proportion',
    270       label: 'Rail-Start Proportion',
    271       units: '%'
    272     },
    273     {
    274       key: 'fling_acceleration_curve_coefficient_0',
    275       label: 'Touchscreen Fling Acceleration',
    276       units: 'x<sup>3</sup>',
    277       min: '-1'
    278     },
    279     {
    280       key: 'fling_acceleration_curve_coefficient_1',
    281       label: '+',
    282       units: 'x<sup>2</sup>',
    283       min: '-1'
    284     },
    285     {
    286       key: 'fling_acceleration_curve_coefficient_2',
    287       label: '+',
    288       units: 'x<sup>1</sup>',
    289       min: '-1'
    290     },
    291     {
    292       key: 'fling_acceleration_curve_coefficient_3',
    293       label: '+',
    294       units: 'x<sup>0</sup>',
    295       min: '-1'
    296     },
    297     {
    298       key: 'fling_velocity_cap',
    299       label: 'Touchscreen Fling Velocity Cap',
    300       units: 'pixels / second'
    301     },
    302     {
    303       key: 'tab_scrub_activation_delay_in_ms',
    304       label: 'Tab scrub auto activation delay, (-1 for never)',
    305       units: 'milliseconds'
    306     }
    307   ];
    308 
    309   return new GeneralConfig(GESTURE_TITLE, GESTURE_PREFIX, GESTURE_FIELDS);
    310 }
    311 
    312 /**
    313  * Returns a GeneralConfig for configuring overscroll.* preferences.
    314  * @return {object} A GeneralConfig object.
    315  */
    316 function OverscrollConfig() {
    317   /** @const */ var OVERSCROLL_TITLE = 'Overscroll Configuration';
    318 
    319   /** @const */ var OVERSCROLL_PREFIX = 'overscroll.';
    320 
    321   var OVERSCROLL_FIELDS = [
    322     {
    323       key: 'horizontal_threshold_complete',
    324       label: 'Complete when overscrolled (horizontal)',
    325       units: '%'
    326     },
    327     {
    328       key: 'vertical_threshold_complete',
    329       label: 'Complete when overscrolled (vertical)',
    330       units: '%'
    331     },
    332     {
    333       key: 'minimum_threshold_start',
    334       label: 'Start overscroll gesture (horizontal)',
    335       units: 'pixels'
    336     },
    337     {
    338       key: 'vertical_threshold_start',
    339       label: 'Start overscroll gesture (vertical)',
    340       units: 'pixels'
    341     },
    342     {
    343       key: 'horizontal_resist_threshold',
    344       label: 'Start resisting overscroll after (horizontal)',
    345       units: 'pixels'
    346     },
    347     {
    348       key: 'vertical_resist_threshold',
    349       label: 'Start resisting overscroll after (vertical)',
    350       units: 'pixels'
    351     },
    352   ];
    353 
    354   return new GeneralConfig(OVERSCROLL_TITLE,
    355                            OVERSCROLL_PREFIX,
    356                            OVERSCROLL_FIELDS);
    357 }
    358 
    359 /**
    360  * Returns a GeneralConfig for configuring immersive.* preferences for
    361  * immersive fullscreen in Ash.
    362  * @return {object} A GeneralConfig object.
    363  */
    364 function ImmersiveConfig() {
    365   /** @const */ var IMMERSIVE_TITLE = 'Immersive Fullscreen Configuration';
    366 
    367   /** @const */ var IMMERSIVE_PREFIX = 'immersive_mode.';
    368 
    369   var IMMERSIVE_FIELDS = [
    370     {
    371       key: 'reveal_delay_ms',
    372       label: 'Top-of-screen reveal delay',
    373       units: 'milliseconds'
    374     },
    375     {
    376       key: 'reveal_x_threshold_pixels',
    377       label: 'Top-of-screen mouse x threshold',
    378       units: 'pixels'
    379     },
    380   ];
    381 
    382   return new GeneralConfig(IMMERSIVE_TITLE,
    383                            IMMERSIVE_PREFIX,
    384                            IMMERSIVE_FIELDS);
    385 }
    386 
    387 /**
    388  * Returns a GeneralConfig for configuring flingcurve.* preferences.
    389  * @return {object} A GeneralConfig object.
    390  */
    391 function FlingConfig() {
    392   /** @const */ var FLING_TITLE = 'Fling Configuration';
    393 
    394   /** @const */ var FLING_PREFIX = 'flingcurve.';
    395 
    396   var FLING_FIELDS = [
    397     {
    398       key: 'touchscreen_alpha',
    399       label: 'Touchscreen fling deacceleration coefficients',
    400       units: 'alpha',
    401       min: '-inf'
    402     },
    403     {
    404       key: 'touchscreen_beta',
    405       label: '',
    406       units: 'beta',
    407       min: '-inf'
    408     },
    409     {
    410       key: 'touchscreen_gamma',
    411       label: '',
    412       units: 'gamma',
    413       min: '-inf'
    414     },
    415     {
    416       key: 'touchpad_alpha',
    417       label: 'Touchpad fling deacceleration coefficients',
    418       units: 'alpha',
    419       min: '-inf'
    420     },
    421     {
    422       key: 'touchpad_beta',
    423       label: '',
    424       units: 'beta',
    425       min: '-inf'
    426     },
    427     {
    428       key: 'touchpad_gamma',
    429       label: '',
    430       units: 'gamma',
    431       min: '-inf'
    432     },
    433   ];
    434 
    435   return new GeneralConfig(FLING_TITLE, FLING_PREFIX, FLING_FIELDS);
    436 }
    437 
    438 /**
    439  * WebUI instance for configuring preference values related to gesture input.
    440  */
    441 window.gesture_config = {
    442   /**
    443    * Build and initialize the gesture configuration form.
    444    */
    445   initialize: function() {
    446     var g = GestureConfig();
    447     g.buildAll();
    448 
    449     var o = OverscrollConfig();
    450     o.buildAll();
    451 
    452     var f = FlingConfig();
    453     f.buildAll();
    454 
    455     var i = ImmersiveConfig();
    456     i.buildAll();
    457 
    458     $('reset-all-button').onclick = function() {
    459       g.onReset();
    460       o.onReset();
    461       f.onReset();
    462       i.onReset();
    463     };
    464   },
    465 
    466   /**
    467    * Checks if all gesture preferences are set to default by checking the status
    468    * of the reset button associated with each preference.
    469    * @return {boolean} True if all gesture preferences are set to default.
    470    */
    471   areAllPrefsSetToDefault: function() {
    472     var resets = $('gesture-form').querySelectorAll('.row-reset');
    473     for (var i = 0; i < resets.length; i++) {
    474       if (!resets[i].disabled)
    475         return false;
    476     }
    477     return true;
    478   },
    479 
    480   /**
    481    * Updates the status and label of a preference reset button.
    482    * @param {HTMLInputElement} resetButton Reset button for the preference.
    483    * @param {boolean} isDefault Whether the preference is set to the default
    484    *     value.
    485    */
    486   updateResetButton: function(resetButton, isDefault) {
    487     /** @const */ var TITLE_DEFAULT = 'Default';
    488 
    489     /** @const */ var TITLE_NOT_DEFAULT = 'Reset';
    490 
    491     resetButton.innerHTML = isDefault ? TITLE_DEFAULT : TITLE_NOT_DEFAULT;
    492     resetButton.disabled = isDefault;
    493   },
    494 
    495   /**
    496    * Updates the status and label of "Reset All" button.
    497    * @param {boolean} isDefault Whether all preference are set to their default
    498    *     values.
    499    */
    500   updateResetAllButton: function(isDefault) {
    501     /** @const */ var TITLE_DEFAULT = 'Everything is set to default';
    502 
    503     /** @const */ var TITLE_NOT_DEFAULT = 'Reset All To Default';
    504 
    505     var button = $('reset-all-button');
    506     button.innerHTML = isDefault ? TITLE_DEFAULT : TITLE_NOT_DEFAULT;
    507     button.disabled = isDefault;
    508   },
    509 
    510   /**
    511    * Handle callback from call to updatePreferenceValue.
    512    * @param {string} prefName The name of the requested preference value.
    513    * @param {value} value The current value associated with prefName.
    514    * @param {boolean} isDefault Whether the value is the default value.
    515    */
    516   updatePreferenceValueResult: function(prefName, value, isDefault) {
    517     prefName = prefName.substring(prefName.indexOf('.') + 1);
    518     $(prefName).value = value;
    519     this.updateResetButton($(prefName + '-reset'), isDefault);
    520     this.updateResetAllButton(this.areAllPrefsSetToDefault());
    521   },
    522 };
    523 
    524 document.addEventListener('DOMContentLoaded', gesture_config.initialize);
    525