UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

281 lines (280 loc) • 12.5 kB
/** * DevExtreme (esm/ui/range_slider.js) * Version: 21.1.4 * Build date: Mon Jun 21 2021 * * Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import $ from "../core/renderer"; import eventsEngine from "../events/core/events_engine"; import Slider from "./slider"; import SliderHandle from "./slider/ui.slider_handle"; import registerComponent from "../core/component_registrator"; import { extend } from "../core/utils/extend"; import { applyServerDecimalSeparator } from "../core/utils/common"; import { eventData } from "../events/utils/index"; import messageLocalization from "../localization/message"; var RANGE_SLIDER_CLASS = "dx-rangeslider"; var RANGE_SLIDER_START_HANDLE_CLASS = RANGE_SLIDER_CLASS + "-start-handle"; var RANGE_SLIDER_END_HANDLE_CLASS = RANGE_SLIDER_CLASS + "-end-handle"; var RangeSlider = Slider.inherit({ _supportedKeys: function() { var isRTL = this.option("rtlEnabled"); var that = this; var _changeHandle = function(e, capturedHandle) { if (that.option("start") === that.option("end")) { that._capturedHandle = capturedHandle; e.target = that._capturedHandle; eventsEngine.trigger(that._capturedHandle, "focus") } }; var _setHandleValue = function(e, step, sign) { var isStart = $(e.target).hasClass(RANGE_SLIDER_START_HANDLE_CLASS); var valueOption = isStart ? "start" : "end"; var val = that.option(valueOption); step = that._valueStep(step); val += sign * (isRTL ? -step : step); that.option(valueOption, val) }; var moveHandleRight = function(e, step) { _changeHandle(e, isRTL ? that._$handleStart : that._$handleEnd); _setHandleValue(e, step, 1) }; var moveHandleLeft = function(e, step) { _changeHandle(e, isRTL ? that._$handleEnd : that._$handleStart); _setHandleValue(e, step, -1) }; return extend(this.callBase(), { leftArrow: function(e) { this._processKeyboardEvent(e); moveHandleLeft(e, this.option("step")) }, rightArrow: function(e) { this._processKeyboardEvent(e); moveHandleRight(e, this.option("step")) }, pageUp: function(e) { this._processKeyboardEvent(e); moveHandleRight(e, this.option("step") * this.option("keyStep")) }, pageDown: function(e) { this._processKeyboardEvent(e); moveHandleLeft(e, this.option("step") * this.option("keyStep")) }, home: function(e) { this._processKeyboardEvent(e); var isStart = $(e.target).hasClass(RANGE_SLIDER_START_HANDLE_CLASS); var valueOption = isStart ? "start" : "end"; var startOption = isStart ? "min" : "start"; var val = this.option(startOption); this.option(valueOption, val) }, end: function(e) { this._processKeyboardEvent(e); var isStart = $(e.target).hasClass(RANGE_SLIDER_START_HANDLE_CLASS); var valueOption = isStart ? "start" : "end"; var endOption = isStart ? "end" : "max"; var val = this.option(endOption); this.option(valueOption, val) } }) }, _getDefaultOptions: function() { return extend(this.callBase(), { start: 40, end: 60, value: [40, 60], startName: "", endName: "" }) }, _renderSubmitElement: function() { 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(options) { this.callBase(options); var initialValue = this.initialOption("value"); var 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() { this.$element().addClass(RANGE_SLIDER_CLASS); this.callBase() }, _renderContentImpl: function() { this._callHandlerMethod("repaint"); this.callBase() }, _renderHandle: function() { 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(args) { var e = args.event; var $range = this._$range; var rangeWidth = $range.width(); var eventOffsetX = eventData(e).x - this._$bar.offset().left; var startHandleX = $range.position().left; var endHandleX = $range.position().left + rangeWidth; var rtlEnabled = this.option("rtlEnabled"); var startHandleIsClosest = (rtlEnabled ? -1 : 1) * ((startHandleX + endHandleX) / 2 - eventOffsetX) > 0; this._capturedHandle = startHandleIsClosest ? this._$handleStart : this._$handleEnd; this.callBase(args) }, _updateHandleAriaLabels: function() { 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() { return this._capturedHandle }, _updateHandlePosition: function(e) { var rtlEnabled = this.option("rtlEnabled"); var offsetDirection = rtlEnabled ? -1 : 1; var max = this.option("max"); var min = this.option("min"); var newRatio = this._startOffset + offsetDirection * e.event.offset / this._swipePixelRatio(); newRatio = newRatio.toPrecision(12); var newValue = newRatio * (max - min) + min; this._updateSelectedRangePosition(newRatio, newRatio); SliderHandle.getInstance(this._activeHandle()).fitTooltipPosition; this._changeValueOnSwipe(newRatio); var startValue = this.option("start"); var endValue = this.option("end"); var $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(leftRatio, rightRatio) { var rtlEnabled = this.option("rtlEnabled"); var moveRight = this._capturedHandle === this._$handleStart && rtlEnabled || this._capturedHandle === this._$handleEnd && !rtlEnabled; var prop = moveRight ? "right" : "left"; if (rtlEnabled ^ moveRight) { this._$range.css(prop, 100 - 100 * rightRatio + "%") } else { this._$range.css(prop, 100 * leftRatio + "%") } }, _setValueOnSwipe: function(value) { var option = this._capturedHandle === this._$handleStart ? "start" : "end"; var start = this.option("start"); var end = this.option("end"); var max = this.option("max"); var min = this.option("min"); start = Math.min(Math.max(start, min), max); end = Math.min(Math.max(end, min), max); if ("start" === option) { start = value > end ? end : value } else { end = value < start ? start : value } this.option("value", [start, end]) }, _renderValue: function() { var valStart = this.option("start"); var valEnd = this.option("end"); var min = this.option("min"); var max = this.option("max"); var rtlEnabled = this.option("rtlEnabled"); valStart = Math.max(min, Math.min(valStart, max)); valEnd = Math.max(valStart, Math.min(valEnd, max)); this._setOptionWithoutOptionChange("start", valStart); this._setOptionWithoutOptionChange("end", valEnd); this._setOptionWithoutOptionChange("value", [valStart, valEnd]); this._$submitStartElement.val(applyServerDecimalSeparator(valStart)); this._$submitEndElement.val(applyServerDecimalSeparator(valEnd)); var ratio1 = max === min ? 0 : (valStart - min) / (max - min); var ratio2 = max === min ? 0 : (valEnd - min) / (max - min); var startOffset = parseFloat((100 * ratio1).toPrecision(12)) + "%"; var endOffset = parseFloat((100 * (1 - ratio2)).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(name, args) { SliderHandle.getInstance(this._$handleStart)[name](args); SliderHandle.getInstance(this._$handleEnd)[name](args) }, _setValueOption: function() { var start = this.option("start"); var end = this.option("end"); this.option("value", [start, end]) }, _optionChanged: function(args) { switch (args.name) { case "value": if (args.value[0] === args.previousValue[0] && args.value[1] === args.previousValue[1]) { break } this._setOptionWithoutOptionChange("start", args.value[0]); this._setOptionWithoutOptionChange("end", args.value[1]); this._renderValue(); var start = this.option("start"); var end = this.option("end"); this._createActionByOption("onValueChanged", { excludeValidators: ["disabled", "readOnly"] })({ start: start, end: end, value: [start, end], event: this._valueChangeEventInstance }); this.validationRequest.fire({ value: [start, end], editor: this }); this._saveValueChangeEvent(void 0); break; case "start": case "end": this._setValueOption(); 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); export default RangeSlider;