blob: 7c7a277ba35064877c4a1fc5b1a2fbd9c184d891 [file] [log] [blame]
// 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
* settings-slider wraps a cr-slider. It maps the slider's values from a
* linear UI range to a range of real values. When |value| does not map exactly
* to a tick mark, it interpolates to the nearest tick.
*/
import '../settings_vars_css.js';
import {SliderTick} from '//resources/cr_elements/cr_slider/cr_slider.m.js';
import {CrPolicyPrefBehavior} from '//resources/cr_elements/policy/cr_policy_pref_behavior.m.js';
import {assert} from '//resources/js/assert.m.js';
import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {loadTimeData} from '../i18n_setup.js';
Polymer({
is: 'settings-slider',
_template: html`{__html_template__}`,
behaviors: [CrPolicyPrefBehavior],
properties: {
/** @type {!chrome.settingsPrivate.PrefObject} */
pref: Object,
/**
* Values corresponding to each tick.
* @type {!Array<SliderTick>|!Array<number>}
*/
ticks: {
type: Array,
value: () => [],
},
/**
* A scale factor used to support fractional pref values. This is not
* compatible with |ticks|, i.e. if |scale| is not 1 then |ticks| must be
* empty.
*/
scale: {
type: Number,
value: 1,
},
min: Number,
max: Number,
labelAria: String,
labelMin: String,
labelMax: String,
disabled: Boolean,
showMarkers: Boolean,
/** @private */
disableSlider_: {
computed: 'computeDisableSlider_(pref.*, disabled, ticks.*)',
type: Boolean,
},
updateValueInstantly: {
type: Boolean,
value: true,
observer: 'onSliderChanged_',
},
loaded_: Boolean,
},
observers: [
'valueChanged_(pref.*, ticks.*, loaded_)',
],
attached() {
this.loaded_ = true;
},
/** @override */
focus() {
this.$.slider.focus();
},
/**
* @param {number|SliderTick} tick
* @return {number|undefined}
*/
getTickValue_(tick) {
return typeof tick === 'object' ? tick.value : tick;
},
/**
* @param {number} index
* @return {number|undefined}
* @private
*/
getTickValueAtIndex_(index) {
return this.getTickValue_(this.ticks[index]);
},
/**
* Sets the |pref.value| property to the value corresponding to the knob
* position after a user action.
* @private
*/
onSliderChanged_() {
if (!this.loaded_) {
return;
}
if (this.$.slider.dragging && !this.updateValueInstantly) {
return;
}
const sliderValue = this.$.slider.value;
let newValue;
if (this.ticks && this.ticks.length > 0) {
newValue = this.getTickValueAtIndex_(sliderValue);
} else {
newValue = sliderValue / this.scale;
}
this.set('pref.value', newValue);
},
/** @private */
computeDisableSlider_() {
return this.disabled || this.isPrefEnforced();
},
/**
* Updates the knob position when |pref.value| changes. If the knob is still
* being dragged, this instead forces |pref.value| back to the current
* position.
* @private
*/
valueChanged_() {
if (this.pref === undefined || !this.loaded_ || this.$.slider.dragging ||
this.$.slider.updatingFromKey) {
return;
}
// First update the slider settings if |ticks| was set.
const numTicks = this.ticks.length;
if (numTicks === 1) {
this.$.slider.disabled = true;
return;
}
const prefValue = /** @type {number} */ (this.pref.value);
// The preference and slider values are continuous when |ticks| is empty.
if (numTicks === 0) {
this.$.slider.value = prefValue * this.scale;
return;
}
assert(this.scale === 1);
// Limit the number of ticks to 10 to keep the slider from looking too busy.
const MAX_TICKS = 10;
this.$.slider.markerCount =
(this.showMarkers || numTicks <= MAX_TICKS) ? numTicks : 0;
// Convert from the public |value| to the slider index (where the knob
// should be positioned on the slider).
const index =
this.ticks.map(tick => Math.abs(this.getTickValue_(tick) - prefValue))
.reduce(
(acc, diff, index) => diff < acc.diff ? {index, diff} : acc,
{index: -1, diff: Number.MAX_VALUE})
.index;
assert(index !== -1);
if (this.$.slider.value !== index) {
this.$.slider.value = index;
}
const tickValue = this.getTickValueAtIndex_(index);
if (this.pref.value !== tickValue) {
this.set('pref.value', tickValue);
}
},
/**
* @return {string}
* @private
*/
getRoleDescription_() {
return loadTimeData.getStringF(
'settingsSliderRoleDescription', this.labelMin, this.labelMax);
},
});