| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- /**
- * DevExtreme (ui/slider/ui.slider.js)
- * Version: 19.1.16
- * Build date: Tue Oct 18 2022
- *
- * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
- * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
- */
- "use strict";
- var $ = require("../../core/renderer");
- var eventsEngine = require("../../events/core/events_engine");
- var domUtils = require("../../core/utils/dom");
- var numberLocalization = require("../../localization/number");
- var devices = require("../../core/devices");
- var extend = require("../../core/utils/extend").extend;
- var applyServerDecimalSeparator = require("../../core/utils/common").applyServerDecimalSeparator;
- var registerComponent = require("../../core/component_registrator");
- var TrackBar = require("../track_bar");
- var eventUtils = require("../../events/utils");
- var pointerEvents = require("../../events/pointer");
- var feedbackEvents = require("../../events/core/emitter.feedback");
- var SliderHandle = require("./ui.slider_handle");
- var inkRipple = require("../widget/utils.ink_ripple");
- var clickEvent = require("../../events/click");
- var Swipeable = require("../../events/gesture/swipeable");
- var themes = require("../themes");
- var Deferred = require("../../core/utils/deferred").Deferred;
- var SLIDER_CLASS = "dx-slider";
- var SLIDER_WRAPPER_CLASS = "dx-slider-wrapper";
- var SLIDER_HANDLE_SELECTOR = ".dx-slider-handle";
- var SLIDER_BAR_CLASS = "dx-slider-bar";
- var SLIDER_RANGE_CLASS = "dx-slider-range";
- var SLIDER_RANGE_VISIBLE_CLASS = "dx-slider-range-visible";
- var SLIDER_LABEL_CLASS = "dx-slider-label";
- var SLIDER_LABEL_POSITION_CLASS_PREFIX = "dx-slider-label-position-";
- var SLIDER_TOOLTIP_POSITION_CLASS_PREFIX = "dx-slider-tooltip-position-";
- var INVALID_MESSAGE_VISIBLE_CLASS = "dx-invalid-message-visible";
- var SLIDER_VALIDATION_NAMESPACE = "Validation";
- var Slider = TrackBar.inherit({
- _activeStateUnit: SLIDER_HANDLE_SELECTOR,
- _supportedKeys: function() {
- var isRTL = this.option("rtlEnabled");
- var that = this;
- var roundedValue = function(offset, isLeftDirection) {
- offset = that._valueStep(offset);
- var step = that.option("step");
- var value = that.option("value");
- var division = (value - that.option("min")) % step;
- var result = isLeftDirection ? value - offset + (division ? step - division : 0) : value + offset - division;
- var min = that.option("min");
- var max = that.option("max");
- if (result < min) {
- result = min
- } else {
- if (result > max) {
- result = max
- }
- }
- return result
- };
- var moveHandleRight = function(offset) {
- that.option("value", roundedValue(offset, isRTL))
- };
- var moveHandleLeft = function(offset) {
- that.option("value", roundedValue(offset, !isRTL))
- };
- return extend(this.callBase(), {
- leftArrow: function(e) {
- e.preventDefault();
- e.stopPropagation();
- moveHandleLeft(this.option("step"))
- },
- rightArrow: function(e) {
- e.preventDefault();
- e.stopPropagation();
- moveHandleRight(this.option("step"))
- },
- pageUp: function(e) {
- e.preventDefault();
- e.stopPropagation();
- moveHandleRight(this.option("step") * this.option("keyStep"))
- },
- pageDown: function(e) {
- e.preventDefault();
- e.stopPropagation();
- moveHandleLeft(this.option("step") * this.option("keyStep"))
- },
- home: function(e) {
- e.preventDefault();
- e.stopPropagation();
- var min = this.option("min");
- this.option("value", min)
- },
- end: function(e) {
- e.preventDefault();
- e.stopPropagation();
- var max = this.option("max");
- this.option("value", max)
- }
- })
- },
- _getDefaultOptions: function() {
- return extend(this.callBase(), {
- value: 50,
- hoverStateEnabled: true,
- activeStateEnabled: true,
- step: 1,
- showRange: true,
- tooltip: {
- enabled: false,
- format: function(value) {
- return value
- },
- position: "top",
- showMode: "onHover"
- },
- label: {
- visible: false,
- position: "bottom",
- format: function(value) {
- return value
- }
- },
- keyStep: 1,
- useInkRipple: false,
- validationMessageOffset: themes.isMaterial() ? {
- h: 18,
- v: 0
- } : {
- h: 7,
- v: 4
- },
- focusStateEnabled: true
- })
- },
- _toggleValidationMessage: function(visible) {
- if (!this.option("isValid")) {
- this.$element().toggleClass(INVALID_MESSAGE_VISIBLE_CLASS, visible)
- }
- },
- _defaultOptionsRules: function() {
- return this.callBase().concat([{
- device: function() {
- return "desktop" === devices.real().deviceType && !devices.isSimulator()
- },
- options: {
- focusStateEnabled: true
- }
- }, {
- device: function() {
- var themeName = themes.current();
- return themes.isMaterial(themeName)
- },
- options: {
- useInkRipple: true
- }
- }])
- },
- _initMarkup: function() {
- this.$element().addClass(SLIDER_CLASS);
- this._renderSubmitElement();
- this.option("useInkRipple") && this._renderInkRipple();
- this.callBase();
- this._renderLabels();
- this._renderStartHandler();
- this._renderAriaMinAndMax()
- },
- _attachFocusEvents: function() {
- this.callBase();
- var namespace = this.NAME + SLIDER_VALIDATION_NAMESPACE;
- var focusInEvent = eventUtils.addNamespace("focusin", namespace);
- var focusOutEvent = eventUtils.addNamespace("focusout", namespace);
- var $focusTarget = this._focusTarget();
- eventsEngine.on($focusTarget, focusInEvent, this._toggleValidationMessage.bind(this, true));
- eventsEngine.on($focusTarget, focusOutEvent, this._toggleValidationMessage.bind(this, false))
- },
- _detachFocusEvents: function() {
- this.callBase();
- var $focusTarget = this._focusTarget();
- this._toggleValidationMessage(false);
- eventsEngine.off($focusTarget, this.NAME + SLIDER_VALIDATION_NAMESPACE)
- },
- _render: function() {
- this.callBase();
- this._repaintHandle()
- },
- _renderSubmitElement: function() {
- this._$submitElement = $("<input>").attr("type", "hidden").appendTo(this.$element())
- },
- _getSubmitElement: function() {
- return this._$submitElement
- },
- _renderInkRipple: function() {
- this._inkRipple = inkRipple.render({
- waveSizeCoefficient: .7,
- isCentered: true,
- wavesNumber: 2,
- useHoldAnimation: false
- })
- },
- _renderInkWave: function(element, dxEvent, doRender, waveIndex) {
- if (!this._inkRipple) {
- return
- }
- var config = {
- element: element,
- event: dxEvent,
- wave: waveIndex
- };
- if (doRender) {
- this._inkRipple.showWave(config)
- } else {
- this._inkRipple.hideWave(config)
- }
- },
- _visibilityChanged: function() {
- this.repaint()
- },
- _renderWrapper: function() {
- this.callBase();
- this._$wrapper.addClass(SLIDER_WRAPPER_CLASS);
- this._createComponent(this._$wrapper, Swipeable, {
- elastic: false,
- immediate: true,
- onStart: this._swipeStartHandler.bind(this),
- onUpdated: this._swipeUpdateHandler.bind(this),
- onEnd: this._swipeEndHandler.bind(this),
- itemSizeFunc: this._itemWidthFunc.bind(this)
- })
- },
- _renderContainer: function() {
- this.callBase();
- this._$bar.addClass(SLIDER_BAR_CLASS)
- },
- _renderRange: function() {
- this.callBase();
- this._$range.addClass(SLIDER_RANGE_CLASS);
- this._renderHandle();
- this._renderRangeVisibility()
- },
- _renderRangeVisibility: function() {
- this._$range.toggleClass(SLIDER_RANGE_VISIBLE_CLASS, Boolean(this.option("showRange")))
- },
- _renderHandle: function() {
- this._$handle = this._renderHandleImpl(this.option("value"), this._$handle)
- },
- _renderHandleImpl: function(value, $element) {
- var $handle = $element || $("<div>").appendTo(this._$range);
- var format = this.option("tooltip.format");
- var tooltipEnabled = this.option("tooltip.enabled");
- var tooltipPosition = this.option("tooltip.position");
- this.$element().toggleClass(SLIDER_TOOLTIP_POSITION_CLASS_PREFIX + "bottom", tooltipEnabled && "bottom" === tooltipPosition).toggleClass(SLIDER_TOOLTIP_POSITION_CLASS_PREFIX + "top", tooltipEnabled && "top" === tooltipPosition);
- this._createComponent($handle, SliderHandle, {
- value: value,
- tooltipEnabled: tooltipEnabled,
- tooltipPosition: tooltipPosition,
- tooltipFormat: format,
- tooltipShowMode: this.option("tooltip.showMode"),
- tooltipFitIn: this.$element()
- });
- return $handle
- },
- _renderAriaMinAndMax: function() {
- this.setAria({
- valuemin: this.option("min"),
- valuemax: this.option("max")
- }, this._$handle)
- },
- _hoverStartHandler: function(e) {
- SliderHandle.getInstance($(e.currentTarget)).updateTooltip()
- },
- _toggleActiveState: function($element, value) {
- this.callBase($element, value);
- if (value) {
- SliderHandle.getInstance($element).updateTooltip()
- }
- this._renderInkWave($element, null, !!value, 1)
- },
- _toggleFocusClass: function(isFocused, $element) {
- this.callBase(isFocused, $element);
- if (this._disposed) {
- return
- }
- var $focusTarget = $($element || this._focusTarget());
- this._renderInkWave($focusTarget, null, isFocused, 0)
- },
- _renderLabels: function() {
- this.$element().removeClass(SLIDER_LABEL_POSITION_CLASS_PREFIX + "bottom").removeClass(SLIDER_LABEL_POSITION_CLASS_PREFIX + "top");
- if (this.option("label.visible")) {
- var min = this.option("min");
- var max = this.option("max");
- var position = this.option("label.position");
- var labelFormat = this.option("label.format");
- if (!this._$minLabel) {
- this._$minLabel = $("<div>").addClass(SLIDER_LABEL_CLASS).appendTo(this._$wrapper)
- }
- this._$minLabel.html(numberLocalization.format(min, labelFormat));
- if (!this._$maxLabel) {
- this._$maxLabel = $("<div>").addClass(SLIDER_LABEL_CLASS).appendTo(this._$wrapper)
- }
- this._$maxLabel.html(numberLocalization.format(max, labelFormat));
- this.$element().addClass(SLIDER_LABEL_POSITION_CLASS_PREFIX + position)
- } else {
- if (this._$minLabel) {
- this._$minLabel.remove();
- delete this._$minLabel
- }
- if (this._$maxLabel) {
- this._$maxLabel.remove();
- delete this._$maxLabel
- }
- }
- },
- _renderStartHandler: function() {
- var pointerDownEventName = eventUtils.addNamespace(pointerEvents.down, this.NAME);
- var clickEventName = eventUtils.addNamespace(clickEvent.name, this.NAME);
- var startAction = this._createAction(this._startHandler.bind(this));
- var $element = this.$element();
- eventsEngine.off($element, pointerDownEventName);
- eventsEngine.on($element, pointerDownEventName, function(e) {
- if (eventUtils.isMouseEvent(e)) {
- startAction({
- event: e
- })
- }
- });
- eventsEngine.off($element, clickEventName);
- eventsEngine.on($element, clickEventName, function(e) {
- var $handle = this._activeHandle();
- if ($handle) {
- eventsEngine.trigger($handle, "focusin");
- eventsEngine.trigger($handle, "focus")
- }
- startAction({
- event: e
- })
- }.bind(this))
- },
- _itemWidthFunc: function() {
- return this._itemWidthRatio
- },
- _swipeStartHandler: function(e) {
- var rtlEnabled = this.option("rtlEnabled");
- if (eventUtils.isTouchEvent(e.event)) {
- this._createAction(this._startHandler.bind(this))({
- event: e.event
- })
- }
- this._feedbackDeferred = new Deferred;
- feedbackEvents.lock(this._feedbackDeferred);
- this._toggleActiveState(this._activeHandle(), this.option("activeStateEnabled"));
- this._startOffset = this._currentRatio;
- var startOffset = this._startOffset * this._swipePixelRatio();
- var endOffset = (1 - this._startOffset) * this._swipePixelRatio();
- e.event.maxLeftOffset = rtlEnabled ? endOffset : startOffset;
- e.event.maxRightOffset = rtlEnabled ? startOffset : endOffset;
- this._itemWidthRatio = this.$element().width() / this._swipePixelRatio();
- this._needPreventAnimation = true
- },
- _swipeEndHandler: function(e) {
- this._feedbackDeferred.resolve();
- this._toggleActiveState(this._activeHandle(), false);
- var offsetDirection = this.option("rtlEnabled") ? -1 : 1;
- delete this._needPreventAnimation;
- this._changeValueOnSwipe(this._startOffset + offsetDirection * e.event.targetOffset / this._swipePixelRatio());
- delete this._startOffset;
- this._renderValue()
- },
- _activeHandle: function() {
- return this._$handle
- },
- _swipeUpdateHandler: function(e) {
- this._saveValueChangeEvent(e);
- this._updateHandlePosition(e)
- },
- _updateHandlePosition: function(e) {
- var offsetDirection = this.option("rtlEnabled") ? -1 : 1;
- var newRatio = Math.min(this._startOffset + offsetDirection * e.event.offset / this._swipePixelRatio(), 1);
- this._$range.width(100 * newRatio + "%");
- SliderHandle.getInstance(this._activeHandle()).fitTooltipPosition;
- this._changeValueOnSwipe(newRatio)
- },
- _swipePixelRatio: function() {
- var min = this.option("min");
- var max = this.option("max");
- var step = this._valueStep(this.option("step"));
- return (max - min) / step
- },
- _valueStep: function(step) {
- if (!step || isNaN(step)) {
- step = 1
- }
- step = parseFloat(step.toFixed(5));
- if (0 === step) {
- step = 1e-5
- }
- return step
- },
- _changeValueOnSwipe: function(ratio) {
- var min = this.option("min");
- var max = this.option("max");
- var step = this._valueStep(this.option("step"));
- var newChange = ratio * (max - min);
- var newValue = min + newChange;
- if (step < 0) {
- return
- }
- if (newValue === max || newValue === min) {
- this._setValueOnSwipe(newValue)
- } else {
- var stepExponent = (step + "").split(".")[1];
- var minExponent = (min + "").split(".")[1];
- var exponentLength = Math.max(stepExponent && stepExponent.length || 0, minExponent && minExponent.length || 0);
- var stepCount = Math.round((newValue - min) / step);
- newValue = Number((stepCount * step + min).toFixed(exponentLength));
- this._setValueOnSwipe(Math.max(Math.min(newValue, max), min))
- }
- },
- _setValueOnSwipe: function(value) {
- this.option("value", value)
- },
- _startHandler: function(args) {
- var e = args.event;
- this._currentRatio = (eventUtils.eventData(e).x - this._$bar.offset().left) / this._$bar.width();
- if (this.option("rtlEnabled")) {
- this._currentRatio = 1 - this._currentRatio
- }
- this._saveValueChangeEvent(e);
- this._changeValueOnSwipe(this._currentRatio)
- },
- _renderValue: function() {
- this.callBase();
- var value = this.option("value");
- this._getSubmitElement().val(applyServerDecimalSeparator(value));
- SliderHandle.getInstance(this._activeHandle()).option("value", value)
- },
- _setRangeStyles: function(options) {
- options && this._$range.css(options)
- },
- _callHandlerMethod: function(name, args) {
- SliderHandle.getInstance(this._$handle)[name](args)
- },
- _repaintHandle: function() {
- this._callHandlerMethod("repaint")
- },
- _fitTooltip: function() {
- this._callHandlerMethod("fitTooltipPosition")
- },
- _optionChanged: function(args) {
- switch (args.name) {
- case "visible":
- this.callBase(args);
- this._renderHandle();
- this._repaintHandle();
- domUtils.triggerShownEvent(this.$element());
- break;
- case "min":
- case "max":
- this._renderValue();
- this.callBase(args);
- this._renderLabels();
- this._renderAriaMinAndMax();
- this._fitTooltip();
- break;
- case "step":
- this._renderValue();
- break;
- case "keyStep":
- break;
- case "showRange":
- this._renderRangeVisibility();
- break;
- case "tooltip":
- this._renderHandle();
- break;
- case "label":
- this._renderLabels();
- break;
- case "useInkRipple":
- this._invalidate();
- break;
- default:
- this.callBase(args)
- }
- },
- _refresh: function() {
- this._toggleRTLDirection(this.option("rtlEnabled"));
- this._renderDimensions();
- this._renderValue();
- this._renderHandle();
- this._repaintHandle()
- },
- _clean: function() {
- delete this._inkRipple;
- this.callBase()
- }
- });
- registerComponent("dxSlider", Slider);
- module.exports = Slider;
|