mirror of https://github.com/rancher/ui.git
241 lines
6.0 KiB
JavaScript
241 lines
6.0 KiB
JavaScript
import { scheduleOnce } from '@ember/runloop';
|
|
import Component from '@ember/component';
|
|
import C from 'ui/utils/constants';
|
|
import layout from './template';
|
|
import { computed, observer, get, set } from '@ember/object';
|
|
|
|
function clientX(event) {
|
|
if ( typeof event.clientX !== 'undefined' ) {
|
|
return event.clientX;
|
|
}
|
|
|
|
var orig = event.originalEvent;
|
|
|
|
if ( orig ) {
|
|
if ( typeof orig.clientX !== 'undefined' ) {
|
|
return orig.clientX;
|
|
}
|
|
|
|
if ( orig.touches && orig.touches.length ) {
|
|
return orig.touches[0].clientX;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
export default Component.extend({
|
|
layout,
|
|
classNames: ['slider'],
|
|
classNameBindings: ['disabled', 'active'],
|
|
|
|
disabled: false,
|
|
initialValue: null,
|
|
value: null, // Bind something to this to get the value, or use the action to get it
|
|
valueMin: 0, // The smallest and biggest value is allowed to be
|
|
valueMax: 100,
|
|
scaleMin: null, // The smallest and biggest values shown on the display. If these are not equal to valueMin/max then there will be
|
|
scaleMax: null, // a part of the slider that the user can't select, e.g. if you want to show 0 but have a minimum value of 1.
|
|
step: 1, // Increment
|
|
|
|
active: false,
|
|
dragFn: null,
|
|
upFn: null,
|
|
|
|
init() {
|
|
this._super(...arguments);
|
|
|
|
var initial = get(this, 'initialValue');
|
|
|
|
if ( initial !== null ) {
|
|
set(this, 'value', initial);
|
|
}
|
|
},
|
|
|
|
didInsertElement() {
|
|
scheduleOnce('afterRender', this, 'valueChanged');
|
|
},
|
|
|
|
willDestroyElement() {
|
|
$('BODY').off('mousemove', get(this, 'dragFn')); // eslint-disable-line
|
|
$('BODY').off('mouseup', get(this, 'upFn')); // eslint-disable-line
|
|
},
|
|
|
|
valueChanged: observer('value', 'valueMin', 'valueMax', 'percent', 'elementId', function() {
|
|
const { elementId } = this
|
|
const originalValue = get(this, 'value');
|
|
let targetSliderBar = elementId ? `.${ elementId }.slider-bar` : '.slider-bar';
|
|
let targetSliderHandle = elementId ? `.${ elementId }.slider-handle` : '.slider-handle';
|
|
let value = Math.max(get(this, 'valueMin'), Math.min(originalValue, get(this, 'valueMax')));
|
|
|
|
if ( isNaN(value) ) {
|
|
value = get(this, 'valueMin');
|
|
}
|
|
|
|
this.sendAction('changed', value);
|
|
|
|
if ( value && originalValue !== value ) {
|
|
set(this, 'value', value);
|
|
|
|
return;
|
|
}
|
|
|
|
var percent = get(this, 'percent');
|
|
|
|
$(targetSliderBar).css('width', `${ percent }%`); // eslint-disable-line
|
|
$(targetSliderHandle).css('left', `${ percent }%`); // eslint-disable-line
|
|
}),
|
|
|
|
|
|
_scaleMin: computed('scaleMin', 'valueMin', function() {
|
|
var min = get(this, 'scaleMin');
|
|
|
|
if ( min === null ) {
|
|
min = get(this, 'valueMin');
|
|
}
|
|
|
|
return min;
|
|
}),
|
|
|
|
_scaleMax: computed('scaleMax', 'valueMax', function() {
|
|
var min = get(this, 'scaleMax');
|
|
|
|
if ( min === null ) {
|
|
min = get(this, 'valueMax');
|
|
}
|
|
|
|
return min;
|
|
}),
|
|
|
|
percent: computed('value', 'valueMin', 'valueMax', '_scaleMin', '_scaleMax', function() {
|
|
var cur = get(this, 'value');
|
|
var min = Math.min(get(this, '_scaleMin'), get(this, 'valueMin'));
|
|
var max = Math.max(get(this, '_scaleMax'), get(this, 'valueMax'));
|
|
|
|
return (((cur - min) / (max - min)) * 100).toFixed(3);
|
|
}),
|
|
|
|
alignValue(val) {
|
|
var step = get(this, 'step');
|
|
var min = get(this, 'valueMin');
|
|
var max = get(this, 'valueMax');
|
|
|
|
// Subtract out the minimum so that modulus will work for
|
|
// determining how close val is to a valid step
|
|
val -= min;
|
|
|
|
var diff = val % step;
|
|
|
|
if ( diff >= step / 2 ) {
|
|
val = val - diff + step;
|
|
} else if ( diff > 0 ) {
|
|
val = val - diff;
|
|
}
|
|
|
|
// Add the minimum back in
|
|
val += min;
|
|
|
|
// Make sure the value is within range
|
|
// (if `max` is not an increment of `step` it's your problem..)
|
|
val = Math.max(min, Math.min(val, max));
|
|
|
|
return val;
|
|
},
|
|
|
|
pointToValue(screenX) {
|
|
var $elem = this.$();
|
|
var offset = $elem.offset();
|
|
var width = $elem.outerWidth();
|
|
|
|
var x = screenX - offset.left;
|
|
var percent = Math.max(0, Math.min(x / width, 1));
|
|
var min = get(this, '_scaleMin');
|
|
var max = get(this, '_scaleMax');
|
|
|
|
var rawValue = min + (percent * (max - min));
|
|
var aligned = this.alignValue(rawValue);
|
|
|
|
return aligned;
|
|
},
|
|
|
|
click(event) {
|
|
if ( get(this, 'disabled') ) {
|
|
return false;
|
|
}
|
|
|
|
var value = this.pointToValue(clientX(event));
|
|
|
|
set(this, 'value', value);
|
|
|
|
this.$('.slider-handle').focus();
|
|
},
|
|
|
|
mouseDown(event) {
|
|
if ( get(this, 'disabled') ) {
|
|
return false;
|
|
}
|
|
|
|
set(this, 'active', true);
|
|
|
|
if ( !get(this, 'dragFn') ) {
|
|
set(this, 'dragFn', this.drag.bind(this));
|
|
}
|
|
|
|
if ( !get(this, 'upFn') ) {
|
|
set(this, 'upFn', this.mouseUp.bind(this));
|
|
}
|
|
|
|
$('BODY').on('mousemove', get(this, 'dragFn')); // eslint-disable-line
|
|
$('BODY').on('mouseup', get(this, 'upFn')); // eslint-disable-line
|
|
|
|
this.drag(event);
|
|
},
|
|
|
|
drag(event) {
|
|
event.preventDefault();
|
|
|
|
if ( get(this, 'disabled') ) {
|
|
return false;
|
|
}
|
|
|
|
var value = this.pointToValue(clientX(event));
|
|
|
|
set(this, 'value', value);
|
|
},
|
|
|
|
mouseUp(/* event*/) {
|
|
$('BODY').off('mousemove', get(this, 'dragFn')); // eslint-disable-line
|
|
$('BODY').off('mouseup', get(this, 'upFn')); // eslint-disable-line
|
|
|
|
set(this, 'active', false);
|
|
},
|
|
|
|
keyDown(event) {
|
|
var handled = false;
|
|
|
|
switch ( event.which ) {
|
|
case C.KEY.LEFT:
|
|
this.decrementProperty('value', get(this, 'step'));
|
|
handled = true;
|
|
break;
|
|
case C.KEY.RIGHT:
|
|
this.incrementProperty('value', get(this, 'step'));
|
|
handled = true;
|
|
break;
|
|
case C.KEY.UP:
|
|
set(this, 'value', get(this, 'valueMax'));
|
|
handled = true;
|
|
break;
|
|
case C.KEY.DOWN:
|
|
set(this, 'value', get(this, 'valueMin'));
|
|
handled = true;
|
|
break;
|
|
}
|
|
|
|
if ( handled ) {
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
|
|
});
|