devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
392 lines (324 loc) • 13.9 kB
JavaScript
"use strict";
var $ = require("../core/renderer"),
eventsEngine = require("../events/core/events_engine"),
Slider = require("./slider"),
SliderHandle = require("./slider/ui.slider_handle"),
registerComponent = require("../core/component_registrator"),
extend = require("../core/utils/extend").extend,
applyServerDecimalSeparator = require("../core/utils/common").applyServerDecimalSeparator,
eventUtils = require("../events/utils"),
messageLocalization = require("../localization/message");
var RANGE_SLIDER_CLASS = "dx-rangeslider",
RANGE_SLIDER_START_HANDLE_CLASS = RANGE_SLIDER_CLASS + "-start-handle",
RANGE_SLIDER_END_HANDLE_CLASS = RANGE_SLIDER_CLASS + "-end-handle";
/**
* @name dxRangeSlider
* @isEditor
* @publicName dxRangeSlider
* @inherits dxSliderBase
* @module ui/range_slider
* @export default
*/
var RangeSlider = Slider.inherit({
_supportedKeys: function _supportedKeys() {
var isRTL = this.option("rtlEnabled");
var that = this,
_changeHandle = function _changeHandle(e, capturedHandle) {
if (that.option("start") === that.option("end")) {
that._capturedHandle = capturedHandle;
e.target = that._capturedHandle;
eventsEngine.trigger(that._capturedHandle, "focus");
}
},
_setHandleValue = function _setHandleValue(e, step, sign) {
var isStart = $(e.target).hasClass(RANGE_SLIDER_START_HANDLE_CLASS),
valueOption = isStart ? "start" : "end",
val = that.option(valueOption);
step = that._valueStep(step);
val += sign * (isRTL ? -step : step);
that.option(valueOption, val);
},
moveHandleRight = function moveHandleRight(e, step) {
_changeHandle(e, isRTL ? that._$handleStart : that._$handleEnd);
_setHandleValue(e, step, 1);
},
moveHandleLeft = function moveHandleLeft(e, step) {
_changeHandle(e, isRTL ? that._$handleEnd : that._$handleStart);
_setHandleValue(e, step, -1);
};
return extend(this.callBase(), {
leftArrow: function leftArrow(e) {
e.preventDefault();
e.stopPropagation();
moveHandleLeft(e, this.option("step"));
},
rightArrow: function rightArrow(e) {
e.preventDefault();
e.stopPropagation();
moveHandleRight(e, this.option("step"));
},
pageUp: function pageUp(e) {
e.preventDefault();
e.stopPropagation();
moveHandleRight(e, this.option("step") * this.option("keyStep"));
},
pageDown: function pageDown(e) {
e.preventDefault();
e.stopPropagation();
moveHandleLeft(e, this.option("step") * this.option("keyStep"));
},
home: function home(e) {
e.preventDefault();
e.stopPropagation();
var isStart = $(e.target).hasClass(RANGE_SLIDER_START_HANDLE_CLASS),
valueOption = isStart ? "start" : "end",
startOption = isStart ? "min" : "start",
val = this.option(startOption);
this.option(valueOption, val);
},
end: function end(e) {
e.preventDefault();
e.stopPropagation();
var isStart = $(e.target).hasClass(RANGE_SLIDER_START_HANDLE_CLASS),
valueOption = isStart ? "start" : "end",
endOption = isStart ? "end" : "max",
val = this.option(endOption);
this.option(valueOption, val);
}
});
},
_getDefaultOptions: function _getDefaultOptions() {
return extend(this.callBase(), {
/**
* @name dxRangeSliderOptions.start
* @publicName start
* @type number
* @default 40
*/
start: 40,
/**
* @name dxRangeSliderOptions.end
* @publicName end
* @type number
* @default 60
*/
end: 60,
/**
* @name dxRangeSliderOptions.value
* @type Array<number>
* @publicName value
* @default [40, 60]
* @inheritdoc
*/
value: [40, 60],
/**
* @name dxRangeSliderOptions.startName
* @publicName startName
* @type string
* @default ""
*/
startName: "",
/**
* @name dxRangeSliderOptions.endName
* @publicName endName
* @type string
* @default ""
*/
endName: ""
/**
* @name dxRangeSliderOptions.onValueChanged
* @publicName onValueChanged
* @action
* @extends Action
* @type_function_param1_field4 start:number
* @type_function_param1_field5 end:number
* @type_function_param1_field6 value:array
* @inheritdoc
*/
/**
* @name dxRangeSliderOptions.name
* @publicName name
* @hidden
* @inheritdoc
*/
});
},
_renderSubmitElement: function _renderSubmitElement() {
var $element = this.$element();
this._$submitStartElement = $("<input>").attr("type", "hidden").attr("name", this.option("startName")).appendTo($element);
this._$submitEndElement = $("<input>").attr("type", "hidden").attr("name", this.option("endName")).appendTo($element);
},
_initOptions: function _initOptions(options) {
this.callBase(options);
var initialValue = this.initialOption("value"),
value = this.option("value");
if (value[0] === initialValue[0] && value[1] === initialValue[1]) {
this.option("value", [this.option("start"), this.option("end")]);
} else {
this.option({ start: value[0], end: value[1] });
}
},
_initMarkup: function _initMarkup() {
this.$element().addClass(RANGE_SLIDER_CLASS);
this.callBase();
},
_renderContentImpl: function _renderContentImpl() {
this._callHandlerMethod("repaint");
this.callBase();
},
_renderHandle: function _renderHandle() {
this._$handleStart = this._renderHandleImpl(this.option("start"), this._$handleStart).addClass(RANGE_SLIDER_START_HANDLE_CLASS);
this._$handleEnd = this._renderHandleImpl(this.option("end"), this._$handleEnd).addClass(RANGE_SLIDER_END_HANDLE_CLASS);
this._updateHandleAriaLabels();
},
_startHandler: function _startHandler(args) {
var e = args.event,
$range = this._$range,
rangeWidth = $range.width(),
eventOffsetX = eventUtils.eventData(e).x - this._$bar.offset().left,
startHandleX = $range.position().left,
endHandleX = $range.position().left + rangeWidth,
rtlEnabled = this.option("rtlEnabled"),
startHandleIsClosest = (rtlEnabled ? -1 : 1) * ((startHandleX + endHandleX) / 2 - eventOffsetX) > 0;
this._capturedHandle = startHandleIsClosest ? this._$handleStart : this._$handleEnd;
this.callBase(args);
},
_updateHandleAriaLabels: function _updateHandleAriaLabels() {
this.setAria("label", messageLocalization.getFormatter("dxRangeSlider-ariaFrom")(this.option("dxRangeSlider-ariaFrom")), this._$handleStart);
this.setAria("label", messageLocalization.getFormatter("dxRangeSlider-ariaTill")(this.option("dxRangeSlider-ariaTill")), this._$handleEnd);
},
_activeHandle: function _activeHandle() {
return this._capturedHandle;
},
_updateHandlePosition: function _updateHandlePosition(e) {
var rtlEnabled = this.option("rtlEnabled"),
offsetDirection = rtlEnabled ? -1 : 1,
max = this.option("max"),
min = this.option("min");
var newRatio = this._startOffset + offsetDirection * e.event.offset / this._swipePixelRatio();
newRatio = newRatio.toPrecision(12); // NOTE: android 2.3 has problems with mathematics
var newValue = newRatio * (max - min) + min;
this._updateSelectedRangePosition(newRatio, newRatio);
SliderHandle.getInstance(this._activeHandle())["fitTooltipPosition"];
this._changeValueOnSwipe(newRatio);
var startValue = this.option("start"),
endValue = this.option("end"),
$nextHandle;
if (startValue === endValue) {
if (newValue < startValue) {
$nextHandle = this._$handleStart;
} else {
$nextHandle = this._$handleEnd;
}
eventsEngine.trigger($nextHandle, "focus");
if ($nextHandle && $nextHandle !== this._capturedHandle) {
this._updateSelectedRangePosition((startValue - min) / (max - min), (endValue - min) / (max - min));
this._toggleActiveState(this._activeHandle(), false);
this._toggleActiveState($nextHandle, true);
this._capturedHandle = $nextHandle;
}
this._updateSelectedRangePosition(newRatio, newRatio);
this._changeValueOnSwipe(newRatio);
}
},
_updateSelectedRangePosition: function _updateSelectedRangePosition(leftRatio, rightRatio) {
var rtlEnabled = this.option("rtlEnabled"),
moveRight = this._capturedHandle === this._$handleStart && rtlEnabled || this._capturedHandle === this._$handleEnd && !rtlEnabled;
var prop = moveRight ? "right" : "left";
if (rtlEnabled ^ moveRight) {
this._$range.css(prop, 100 - rightRatio * 100 + "%");
} else {
this._$range.css(prop, leftRatio * 100 + "%");
}
},
_setValueOnSwipe: function _setValueOnSwipe(value) {
var option = this._capturedHandle === this._$handleStart ? "start" : "end",
start = this.option("start"),
end = this.option("end"),
max = this.option("max"),
min = this.option("min");
start = Math.min(Math.max(start, min), max);
end = Math.min(Math.max(end, min), max);
if (option === "start") {
start = value > end ? end : value;
} else {
end = value < start ? start : value;
}
this.option("value", [start, end]);
},
_renderValue: function _renderValue() {
var valStart = this.option("start"),
valEnd = this.option("end"),
min = this.option("min"),
max = this.option("max"),
rtlEnabled = this.option("rtlEnabled");
valStart = Math.max(min, Math.min(valStart, max));
valEnd = Math.max(valStart, Math.min(valEnd, max));
this.option("start", valStart);
this.option("end", valEnd);
this._$submitStartElement.val(applyServerDecimalSeparator(valStart));
this._$submitEndElement.val(applyServerDecimalSeparator(valEnd));
var ratio1 = max === min ? 0 : (valStart - min) / (max - min),
ratio2 = max === min ? 0 : (valEnd - min) / (max - min);
var startOffset = parseFloat((ratio1 * 100).toPrecision(12)) + "%",
endOffset = parseFloat(((1 - ratio2) * 100).toPrecision(12)) + "%";
!this._needPreventAnimation && this._setRangeStyles({
right: rtlEnabled ? startOffset : endOffset,
left: rtlEnabled ? endOffset : startOffset
});
SliderHandle.getInstance(this._$handleStart).option("value", valStart);
SliderHandle.getInstance(this._$handleEnd).option("value", valEnd);
},
_callHandlerMethod: function _callHandlerMethod(name, args) {
SliderHandle.getInstance(this._$handleStart)[name](args);
SliderHandle.getInstance(this._$handleEnd)[name](args);
},
_setValueOption: function _setValueOption() {
var start = this.option("start"),
end = this.option("end");
this.option("value", [start, end]);
},
/**
* @name dxRangeSliderMethods.reset
* @publicName reset()
*/
reset: function reset() {
var defaultOptions = this._getDefaultOptions();
this.option("value", defaultOptions.value);
},
_optionChanged: function _optionChanged(args) {
switch (args.name) {
case "value":
this.option({ start: args.value[0], end: args.value[1] });
break;
case "start":
case "end":
this._setValueOption();
this._renderValue();
var start = this.option("start"),
end = this.option("end");
this._createActionByOption("onValueChanged", {
excludeValidators: ["disabled", "readOnly"]
})({
start: start,
end: end,
value: [start, end],
event: this._valueChangeEventInstance
});
this._saveValueChangeEvent(undefined);
break;
case "startName":
this._$submitStartElement.attr("name", args.value);
break;
case "endName":
this._$submitEndElement.attr("name", args.value);
break;
case "name":
break;
default:
this.callBase(args);
}
}
});
registerComponent("dxRangeSlider", RangeSlider);
module.exports = RangeSlider;