Chromium Code Reviews| Index: ui/webui/resources/cr_elements/slider/slider_host_behavior.js |
| diff --git a/ui/webui/resources/cr_elements/slider/slider_host_behavior.js b/ui/webui/resources/cr_elements/slider/slider_host_behavior.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..87279acde804d4f91e23c747d41e6dabb7492770 |
| --- /dev/null |
| +++ b/ui/webui/resources/cr_elements/slider/slider_host_behavior.js |
| @@ -0,0 +1,129 @@ |
| +// Copyright 2016 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. |
| + |
| +/** |
| + * @fileoverview |
| + * SliderHostBehavior handles data binding for paper-sliders that need to map |
| + * the slider's values from a linear UI range to a range of real values. When |
| + * the real value does not map exactly to a tick mark, it interpolates to the |
| + * nearest tick. |
| + * |
| + * Sliders should be data bound as follows: |
| + * |
| + * <paper-slider |
| + * value="[[getSliderIndexFromValue( |
| + * path.to.property.value, listOfValidValues)]]" |
| + * on-change="onSliderChange" on-value-change="onSliderValueChange" |
| + * data-value-path="path.to.property.value" |
| + * slider-tick-values="[[listOfValidValues]]"> |
| + * </paper-slider> |
| + * |
| + * In addition to the computed value binding and two events, this includes two |
| + * new attributes: |
| + * data-value-path: the path to the number value the slider should control |
| + * slider-tick-values: an {!Array<number>} of the values the ticks represent |
| + */ |
| + |
| +/** |
| + * paper-slider with the required annotations. |
| + * @constructor |
| + * @extends {PaperSliderElement} |
| + */ |
| +var SliderHostBehaviorSlider = function() {}; |
| +/** @type {!{valuePath: string}} */ |
| +SliderHostBehaviorSlider.prototype.dataset; |
| +/** @type {!Array<number>} */ |
| +SliderHostBehaviorSlider.prototype.sliderTickValues; |
| + |
| +/** @polymerBehavior */ |
| +var SliderHostBehavior = { |
| + /** |
| + * value-change is fired when the slider is first data-bound, so we can use |
| + * this as a proxy for initialization. |
| + * @param {!Event} e |
| + */ |
| + onSliderValueChange: function(e) { |
| + var slider = /** @type {!SliderHostBehaviorSlider} */(e.target); |
| + |
| + // If the slider is already initialized, do nothing. |
| + if (typeof slider.min != 'undefined' && typeof slider.max != 'undefined') |
| + return; |
| + |
| + // Asynchronously update so we can ensure all properties are bound. |
| + this.async(this.initializeSlider_.bind(this, slider)); |
| + }, |
| + |
| + /** |
| + * Sets the path to the value corresponding to the slider position in |
| + * response to user action. |
| + * @param {!Event} e Slider change event. |
| + */ |
| + onSliderChange: function(e) { |
| + var slider = /** @type {!SliderHostBehaviorSlider} */(e.target); |
| + var index = slider.value; |
| + var ticks = slider.sliderTickValues; |
| + assert(index >= 0 && index < ticks.length); |
| + this.set(slider.dataset.valuePath, ticks[index]); |
| + }, |
| + |
| + /** |
| + * Converts from raw values (what the ticks represent) to the slider index |
| + * (where the pip should be positioned on the slider). |
| + * @param {number} value Value to convert. |
| + * @param {!Array<number>} ticks Array of values corresponding to ticks. |
| + * @return {number} |
| + */ |
| + getSliderIndexFromValue: function(value, ticks) { |
| + // TODO |
|
stevenjb
2016/05/11 16:37:41
TODO?
|
| + assert(!(typeof value != 'number' || Number.isNaN(value))) |
| + //return undefined; |
| + return this.findNearestIndex_(ticks, value); |
| + }, |
| + |
| + /** |
| + * Sets the min, max and value based on the availale ticks. |
| + * @param {!PaperSliderElement} slider The slider, after data binding. |
| + * @private |
| + */ |
| + initializeSlider_: function(slider) { |
| + var ticks = slider.sliderTickValues; |
| + slider.min = 0; |
| + slider.max = ticks.length - 1; |
| + |
| + // Set the value in case it was originally out-of-bounds. |
| + var value = /** @type {number|undefined} */( |
| + this.get(slider.dataset.valuePath)); |
| + if (typeof value != 'undefined') |
| + slider.value = this.getSliderIndexFromValue(value, ticks); |
| + }, |
| + |
| + /** |
| + * Returns the index of the item in |arr| closest to |value|. Same cost as |
| + * Array.prototype.indexOf if an exact match exists. |
| + * @param {!Array<number>} arr |
| + * @param {number} value |
| + * @return {number} |
| + * @private |
| + */ |
| + findNearestIndex_: function(arr, value) { |
| + assert(arr.length); |
| + |
| + // The common case has an exact match. |
| + var closestIndex = arr.indexOf(value); |
| + if (closestIndex != -1) |
| + return closestIndex; |
| + |
| + // No exact match. Find the element closest to |value|. |
| + var minDifference = Number.MAX_VALUE; |
| + for (var i = 0; i < arr.length; i++) { |
| + var difference = Math.abs(arr[i] - value); |
| + if (difference < minDifference) { |
| + closestIndex = i; |
| + minDifference = difference; |
| + } |
| + } |
| + |
| + return closestIndex; |
| + }, |
| +}; |