UNPKG

fomantic-ui

Version:

Fomantic empowers designers and developers by creating a shared vocabulary for UI.

1,034 lines (957 loc) • 68.8 kB
/*! * # Fomantic-UI 2.9.3 - Slider * https://github.com/fomantic/Fomantic-UI/ * * * Released under the MIT license * https://opensource.org/licenses/MIT * */ (function ($, window, document) { 'use strict'; function isFunction(obj) { return typeof obj === 'function' && typeof obj.nodeType !== 'number'; } window = window !== undefined && window.Math === Math ? window : globalThis; $.fn.slider = function (parameters) { var $allModules = $(this), $document = $(document), $window = $(window), time = Date.now(), performance = [], query = arguments[0], methodInvoked = typeof query === 'string', queryArguments = [].slice.call(arguments, 1), alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'], SINGLE_STEP = 1, BIG_STEP = 2, NO_STEP = 0, SINGLE_BACKSTEP = -1, BIG_BACKSTEP = -2, // Used to manage document bound events. // Use this so that we can distinguish between which document events are bound to which range. currentRange = 0, returnedValue ; $allModules.each(function () { var settings = $.isPlainObject(parameters) ? $.extend(true, {}, $.fn.slider.settings, parameters) : $.extend({}, $.fn.slider.settings), className = settings.className, metadata = settings.metadata, namespace = settings.namespace, error = settings.error, keys = settings.keys, interpretLabel = settings.interpretLabel, isHover = false, eventNamespace = '.' + namespace, moduleNamespace = 'module-' + namespace, $module = $(this), $currThumb, touchIdentifier, $thumb, $secondThumb, $track, $trackFill, $labels, element = this, instance = $module.data(moduleNamespace), documentEventID, value, position, secondPos, offset, precision, gapRatio = 1, previousValue, initialPosition, initialLoad, module ; module = { initialize: function () { module.debug('Initializing slider', settings); initialLoad = true; currentRange += 1; documentEventID = currentRange; module.setup.layout(); module.setup.labels(); module.bind.events(); module.read.metadata(); module.read.settings(); initialLoad = false; module.instantiate(); }, instantiate: function () { module.verbose('Storing instance of slider', module); instance = module; $module .data(moduleNamespace, module) ; }, destroy: function () { module.verbose('Destroying previous slider for', $module); clearInterval(instance.interval); module.unbind.events(); module.unbind.slidingEvents(); $module.removeData(moduleNamespace); instance = undefined; }, setup: { layout: function () { if ($module.attr('tabindex') === undefined) { $module.attr('tabindex', 0); } if ($module.find('.inner').length === 0) { $module.append('<div class="inner">' + '<div class="track"></div>' + '<div class="track-fill"></div>' + '<div class="thumb"></div>' + '</div>'); } precision = module.get.precision(); $thumb = $module.find('.thumb:not(.second)'); if (settings.showThumbTooltip) { $thumb .attr('data-position', settings.tooltipConfig.position) .attr('data-variation', settings.tooltipConfig.variation) ; } $currThumb = $thumb; if (module.is.range()) { if ($module.find('.thumb.second').length === 0) { $module.find('.inner').append('<div class="thumb second"></div>'); } $secondThumb = $module.find('.thumb.second'); if (settings.showThumbTooltip) { $secondThumb .attr('data-position', settings.tooltipConfig.position) .attr('data-variation', settings.tooltipConfig.variation) ; } } $track = $module.find('.track'); $trackFill = $module.find('.track-fill'); offset = $thumb.width() / 2; }, labels: function () { if (module.is.labeled()) { $labels = $module.find('.labels:not(.auto)'); if ($labels.length > 0) { module.setup.customLabel(); } else { module.setup.autoLabel(); } if (settings.showLabelTicks) { $module.addClass(className.ticked); } } }, customLabel: function () { var $children = $labels.find('.label'), numChildren = $children.length, min = module.get.min(), max = module.get.max(), ratio ; $children.each(function (index) { var $child = $(this), attrValue = $child.attr('data-value') ; if (attrValue) { attrValue = attrValue > max ? max : (attrValue < min ? min : attrValue); ratio = (attrValue - min) / (max - min); } else { ratio = (index + 1) / (numChildren + 1); } module.update.labelPosition(ratio, $(this)); }); }, autoLabel: function () { $labels = $module.find('.labels'); if ($labels.length > 0) { $labels.empty(); } else { $labels = $module.append('<ul class="auto labels"></ul>').find('.labels'); } for (var i = 0, len = module.get.numLabels(); i <= len; i++) { var labelText = module.get.label(i), showLabel = settings.restrictedLabels.length === 0 || settings.restrictedLabels.indexOf(labelText) >= 0, $label = labelText !== '' && (showLabel || settings.showLabelTicks === 'always') ? (!(i % module.get.gapRatio()) ? $('<li class="label">' + (showLabel ? labelText : '') + '</li>') : $('<li class="halftick label"></li>')) : null, ratio = i / len ; if ($label) { module.update.labelPosition(ratio, $label); $labels.append($label); } } }, }, bind: { events: function () { module.bind.globalKeyboardEvents(); module.bind.keyboardEvents(); module.bind.mouseEvents(); if (settings.autoAdjustLabels) { module.bind.windowEvents(); } }, keyboardEvents: function () { module.verbose('Binding keyboard events'); $module.on('keydown' + eventNamespace, module.event.keydown); }, globalKeyboardEvents: function () { $document.on('keydown' + eventNamespace + documentEventID, module.event.activateFocus); }, mouseEvents: function () { module.verbose('Binding mouse and touch events'); $module.find('.track, .thumb, .inner').on('mousedown' + eventNamespace, function (event) { event.stopImmediatePropagation(); event.preventDefault(); module.event.down(event); }); $module.on('mousedown' + eventNamespace, module.event.down); $module.on('mouseenter' + eventNamespace, function (event) { isHover = true; }); $module.on('mouseleave' + eventNamespace, function (event) { isHover = false; }); // All touch events are invoked on the element where the touch *started*. Thus, we can bind them all // on the thumb(s) and don't need to worry about interference with other components, i.e. no dynamic binding // and unbinding required. $module.find('.thumb') .on('touchstart' + eventNamespace, module.event.touchDown) .on('touchmove' + eventNamespace, module.event.move) .on('touchend' + eventNamespace, module.event.up) .on('touchcancel' + eventNamespace, module.event.touchCancel) ; }, slidingEvents: function () { // these don't need the identifier because we only ever want one of them to be registered with document module.verbose('Binding page wide events while handle is being draged'); $document.on('mousemove' + eventNamespace, module.event.move); $document.on('mouseup' + eventNamespace, module.event.up); }, windowEvents: function () { $window.on('resize' + eventNamespace, module.event.resize); }, }, unbind: { events: function () { $module.find('.track, .thumb, .inner').off('mousedown' + eventNamespace); $module.off('mousedown' + eventNamespace); $module.off('mouseenter' + eventNamespace); $module.off('mouseleave' + eventNamespace); $module.find('.thumb') .off('touchstart' + eventNamespace) .off('touchmove' + eventNamespace) .off('touchend' + eventNamespace) .off('touchcancel' + eventNamespace) ; $module.off('keydown' + eventNamespace); $module.off('focusout' + eventNamespace); $document.off('keydown' + eventNamespace + documentEventID, module.event.activateFocus); $window.off('resize' + eventNamespace); }, slidingEvents: function () { $document.off('mousemove' + eventNamespace); $document.off('mouseup' + eventNamespace); }, }, event: { down: function (event) { event.preventDefault(); if (module.is.range()) { var eventPos = module.determine.eventPos(event), newPos = module.determine.pos(eventPos) ; // Special handling if range mode and both thumbs have the same value if (settings.preventCrossover && module.is.range() && module.thumbVal === module.secondThumbVal) { initialPosition = newPos; $currThumb = undefined; } else { $currThumb = module.determine.closestThumb(newPos); } if (previousValue === undefined) { previousValue = module.get.currentThumbValue(); } } else if (previousValue === undefined) { previousValue = module.get.value(); } if (!module.is.disabled()) { module.bind.slidingEvents(); } }, touchDown: function (event) { event.preventDefault(); // disable mouse emulation and touch-scrolling event.stopImmediatePropagation(); if (touchIdentifier !== undefined) { // ignore multiple touches on the same slider -- // we cannot handle changing both thumbs at once due to shared state return; } $currThumb = $(event.target); var touchEvent = event.touches ? event : event.originalEvent; touchIdentifier = touchEvent.targetTouches[0].identifier; if (previousValue === undefined) { previousValue = module.get.currentThumbValue(); } }, move: function (event) { if (event.type === 'mousemove') { event.preventDefault(); // prevent text selection etc. } if (module.is.disabled()) { // touch events are always bound, so we need to prevent touch-sliding on disabled sliders here return; } var value = module.determine.valueFromEvent(event); if (event.type === 'mousemove' && $currThumb === undefined) { var eventPos = module.determine.eventPos(event), newPos = module.determine.pos(eventPos) ; $currThumb = initialPosition > newPos ? $thumb : $secondThumb; } if (module.is.range() && (settings.minRange || settings.maxRange)) { var currentRangeDiff = module.get.currentRangeDiff(value), isSecondThumb = $currThumb.hasClass('second') ; if ((settings.minRange && currentRangeDiff < settings.minRange) || (settings.maxRange && currentRangeDiff > settings.maxRange) || (settings.preventCrossover && !isSecondThumb && value > module.secondThumbVal) || (settings.preventCrossover && isSecondThumb && value < module.thumbVal) ) { return; } } if (module.get.step() === 0 || module.is.smooth()) { var thumbVal = module.thumbVal, secondThumbVal = module.secondThumbVal, thumbSmoothVal = module.determine.smoothValueFromEvent(event) ; if (!$currThumb.hasClass('second')) { if (settings.preventCrossover && module.is.range()) { value = Math.min(secondThumbVal, value); thumbSmoothVal = Math.min(secondThumbVal, thumbSmoothVal); } thumbVal = value; } else { if (settings.preventCrossover && module.is.range()) { value = Math.max(thumbVal, value); thumbSmoothVal = Math.max(thumbVal, thumbSmoothVal); } secondThumbVal = value; } value = Math.abs(thumbVal - (secondThumbVal || 0)); module.update.position(thumbSmoothVal); settings.onMove.call(element, value, thumbVal, secondThumbVal); } else { module.update.value(value, function (value, thumbVal, secondThumbVal) { settings.onMove.call(element, value, thumbVal, secondThumbVal); }); } }, up: function (event) { event.preventDefault(); if (module.is.disabled()) { // touch events are always bound, so we need to prevent touch-sliding on disabled sliders here return; } var value = module.determine.valueFromEvent(event); if (module.is.range() && (settings.minRange || settings.maxRange)) { if ($currThumb === undefined) { $currThumb = value <= module.get.currentThumbValue() ? $thumb : $secondThumb; } var currentRangeDiff = module.get.currentRangeDiff(value); if (settings.minRange && currentRangeDiff < settings.minRange) { value = module.get.edgeValue(value, settings.minRange); } else if (settings.maxRange && currentRangeDiff > settings.maxRange) { value = module.get.edgeValue(value, settings.maxRange); } } module.set.value(value); module.unbind.slidingEvents(); touchIdentifier = undefined; if (previousValue !== undefined) { previousValue = undefined; } }, touchCancel: function (event) { event.preventDefault(); touchIdentifier = undefined; if (previousValue !== undefined) { module.update.value(previousValue); previousValue = undefined; } }, keydown: function (event, first) { if (module.is.disabled()) { return; } if (settings.preventCrossover && module.is.range() && module.thumbVal === module.secondThumbVal) { $currThumb = undefined; } if (module.is.focused()) { $document.trigger(event); } if (first || module.is.focused()) { var step = module.determine.keyMovement(event); if (step !== NO_STEP) { event.preventDefault(); switch (step) { case SINGLE_STEP: { module.takeStep(); break; } case BIG_STEP: { module.takeStep(module.get.multiplier()); break; } case SINGLE_BACKSTEP: { module.backStep(); break; } case BIG_BACKSTEP: { module.backStep(module.get.multiplier()); break; } } } } }, activateFocus: function (event) { if (!module.is.disabled() && !module.is.focused() && module.is.hover() && module.determine.keyMovement(event) !== NO_STEP) { event.preventDefault(); module.event.keydown(event, true); $module.trigger('focus'); } }, resize: function (_event) { // To avoid a useless performance cost, we only call the label refresh when its necessary if (gapRatio !== module.get.gapRatio()) { module.setup.labels(); gapRatio = module.get.gapRatio(); } }, }, resync: function () { module.verbose('Resyncing thumb position based on value'); if (module.is.range()) { module.update.position(module.secondThumbVal, $secondThumb); } module.update.position(module.thumbVal, $thumb); module.setup.labels(); }, takeStep: function (multiplier) { if (!multiplier) { multiplier = 1; } var step = module.get.step(), currValue = module.get.currentThumbValue() ; module.verbose('Taking a step'); if (step > 0) { module.set.value(currValue + step * multiplier); } else if (step === 0) { var precision = module.get.precision(), newValue = currValue + (multiplier / precision) ; module.set.value(Math.round(newValue * precision) / precision); } }, backStep: function (multiplier) { if (!multiplier) { multiplier = 1; } var step = module.get.step(), currValue = module.get.currentThumbValue() ; module.verbose('Going back a step'); if (step > 0) { module.set.value(currValue - step * multiplier); } else if (step === 0) { var precision = module.get.precision(), newValue = currValue - (multiplier / precision) ; module.set.value(Math.round(newValue * precision) / precision); } }, is: { range: function () { var isRange = $module.hasClass(className.range); if (!isRange && (settings.minRange || settings.maxRange)) { $module.addClass(className.range); isRange = true; } return isRange; }, hover: function () { return isHover; }, focused: function () { return $module.is(':focus'); }, disabled: function () { return $module.hasClass(className.disabled); }, labeled: function () { var isLabeled = $module.hasClass(className.labeled); if (!isLabeled && (settings.restrictedLabels.length > 0 || settings.showLabelTicks !== false)) { $module.addClass(className.labeled); isLabeled = true; } return isLabeled; }, reversed: function () { return $module.hasClass(className.reversed); }, vertical: function () { return $module.hasClass(className.vertical); }, smooth: function () { return settings.smooth || $module.hasClass(className.smooth); }, }, get: { currentRangeDiff: function (value) { var currentRangeDiff; if ($currThumb.hasClass('second')) { currentRangeDiff = module.thumbVal < value ? value - module.thumbVal : module.thumbVal - value; } else { currentRangeDiff = module.secondThumbVal > value ? module.secondThumbVal - value : value - module.secondThumbVal; } return currentRangeDiff; }, edgeValue: function (value, edgeValue) { if ($currThumb.hasClass('second')) { value = module.thumbVal < value ? module.thumbVal + edgeValue : module.thumbVal - edgeValue; } else { value = module.secondThumbVal < value ? module.secondThumbVal + edgeValue : module.secondThumbVal - edgeValue; } return value; }, trackOffset: function () { if (module.is.vertical()) { return $track.offset().top; } return $track.offset().left; }, trackLength: function () { if (module.is.vertical()) { return $track.height(); } return $track.width(); }, trackLeft: function () { if (module.is.vertical()) { return $track.position().top; } return $track.position().left; }, trackStartPos: function () { return module.is.reversed() ? module.get.trackLeft() + module.get.trackLength() : module.get.trackLeft(); }, trackEndPos: function () { return module.is.reversed() ? module.get.trackLeft() : module.get.trackLeft() + module.get.trackLength(); }, trackStartMargin: function () { var margin; if (module.is.vertical()) { margin = module.is.reversed() ? $module.css('padding-bottom') : $module.css('padding-top'); } else { margin = module.is.reversed() ? $module.css('padding-right') : $module.css('padding-left'); } return margin || '0px'; }, trackEndMargin: function () { var margin; if (module.is.vertical()) { margin = module.is.reversed() ? $module.css('padding-top') : $module.css('padding-bottom'); } else { margin = module.is.reversed() ? $module.css('padding-left') : $module.css('padding-right'); } return margin || '0px'; }, precision: function () { var decimalPlaces, step = module.get.step() ; if (step !== 0) { var split = String(step).split('.'); decimalPlaces = split.length === 2 ? split[1].length : 0; } else { decimalPlaces = settings.decimalPlaces; } var precision = Math.pow(10, decimalPlaces); module.debug('Precision determined', precision); return precision; }, min: function () { return settings.min; }, max: function () { var step = module.get.step(), min = module.get.min(), precision = module.get.precision(), quotient = step === 0 ? 0 : Math.floor(Math.round(((settings.max - min) / step) * precision) / precision), remainder = step === 0 ? 0 : (settings.max - min) % step ; return remainder === 0 ? settings.max : min + quotient * step; }, step: function () { return settings.step; }, numLabels: function () { var step = module.get.step(), precision = module.get.precision(), value = Math.round(((module.get.max() - module.get.min()) / (step === 0 ? 1 : step)) * precision) / precision; module.debug('Determined that there should be ' + value + ' labels'); return value; }, labelType: function () { return settings.labelType; }, label: function (value) { if (interpretLabel) { return interpretLabel(value); } switch (settings.labelType) { case settings.labelTypes.number: { var step = module.get.step(); return Math.round(((value * (step === 0 ? 1 : step)) + module.get.min()) * precision) / precision; } case settings.labelTypes.letter: { return alphabet[value % 26]; } default: { return value; } } }, value: function () { return value; }, currentThumbValue: function () { return $currThumb !== undefined && $currThumb.hasClass('second') ? module.secondThumbVal : module.thumbVal; }, thumbValue: function (which) { switch (which) { case 'second': { if (module.is.range()) { return module.secondThumbVal; } module.error(error.notrange); break; } default: { return module.thumbVal; } } }, multiplier: function () { return settings.pageMultiplier; }, thumbPosition: function (which) { switch (which) { case 'second': { if (module.is.range()) { return secondPos; } module.error(error.notrange); break; } default: { return position; } } }, gapRatio: function () { var gapRatio = 1; if (settings.autoAdjustLabels) { var numLabels = module.get.numLabels(), trackLength = module.get.trackLength(), gapCounter = 1 ; // While the distance between two labels is too short, // we divide the number of labels at each iteration // and apply only if the modulo of the operation is an odd number. if (trackLength > 0) { while ((trackLength / numLabels) * gapCounter < settings.labelDistance) { if (!(numLabels % gapCounter)) { gapRatio = gapCounter; } gapCounter += 1; } } } return gapRatio; }, }, determine: { pos: function (pagePos) { return module.is.reversed() ? module.get.trackStartPos() - pagePos + module.get.trackOffset() : pagePos - module.get.trackOffset() - module.get.trackStartPos(); }, closestThumb: function (eventPos) { var thumbPos = parseFloat(module.determine.thumbPos($thumb)), thumbDelta = Math.abs(eventPos - thumbPos), secondThumbPos = parseFloat(module.determine.thumbPos($secondThumb)), secondThumbDelta = Math.abs(eventPos - secondThumbPos) ; if (thumbDelta === secondThumbDelta && module.get.thumbValue() === module.get.min()) { return $secondThumb; } return thumbDelta <= secondThumbDelta ? $thumb : $secondThumb; }, closestThumbPos: function (eventPos) { var thumbPos = parseFloat(module.determine.thumbPos($thumb)), thumbDelta = Math.abs(eventPos - thumbPos), secondThumbPos = parseFloat(module.determine.thumbPos($secondThumb)), secondThumbDelta = Math.abs(eventPos - secondThumbPos) ; return thumbDelta <= secondThumbDelta ? thumbPos : secondThumbPos; }, thumbPos: function ($element) { return module.is.vertical() ? (module.is.reversed() ? $element.css('bottom') : $element.css('top')) : (module.is.reversed() ? $element.css('right') : $element.css('left')) ; }, positionFromValue: function (val) { var min = module.get.min(), max = module.get.max(), value = val > max ? max : (val < min ? min : val), trackLength = module.get.trackLength(), ratio = (value - min) / (max - min), position = Math.round(ratio * trackLength) ; module.verbose('Determined position: ' + position + ' from value: ' + value); return position; }, positionFromRatio: function (ratio) { var trackLength = module.get.trackLength(), step = module.get.step(), position = Math.round(ratio * trackLength), adjustedPos = step === 0 ? position : Math.round(position / step) * step ; module.verbose('Determined position: ' + position + ' from ratio: ' + ratio); return adjustedPos; }, valueFromEvent: function (event) { var eventPos = module.determine.eventPos(event), newPos = module.determine.pos(eventPos), value ; if (eventPos < module.get.trackOffset()) { value = module.is.reversed() ? module.get.max() : module.get.min(); } else if (eventPos > module.get.trackOffset() + module.get.trackLength()) { value = module.is.reversed() ? module.get.min() : module.get.max(); } else { value = module.determine.value(newPos); } return value; }, smoothValueFromEvent: function (event) { var min = module.get.min(), max = module.get.max(), trackLength = module.get.trackLength(), eventPos = module.determine.eventPos(event), newPos = eventPos - module.get.trackOffset(), ratio, value ; newPos = newPos < 0 ? 0 : (newPos > trackLength ? trackLength : newPos); ratio = newPos / trackLength; if (module.is.reversed()) { ratio = 1 - ratio; } value = ratio * (max - min) + min; return value; }, eventPos: function (event) { if (event.type === 'touchmove' || event.type === 'touchend') { var touchEvent = event.touches ? event : event.originalEvent, touch = touchEvent.changedTouches[0]; // fall back to first touch if correct touch not found for (var i = 0; i < touchEvent.touches.length; i++) { if (touchEvent.touches[i].identifier === touchIdentifier) { touch = touchEvent.touches[i]; break; } } var touchY = touch.pageY, touchX = touch.pageX ; return module.is.vertical() ? touchY : touchX; } var clickY = event.pageY || event.originalEvent.pageY, clickX = event.pageX || event.originalEvent.pageX ; return module.is.vertical() ? clickY : clickX; }, value: function (position) { var startPos = module.is.reversed() ? module.get.trackEndPos() : module.get.trackStartPos(), endPos = module.is.reversed() ? module.get.trackStartPos() : module.get.trackEndPos(), ratio = (position - startPos) / (endPos - startPos), range = module.get.max() - module.get.min(), step = module.get.step(), value = ratio * range, difference = step === 0 ? value : Math.round(value / step) * step ; module.verbose('Determined value based upon position: ' + position + ' as: ' + value); if (value !== difference) { module.verbose('Rounding value to closest step: ' + difference); } // Use precision to avoid ugly Javascript floating point rounding issues // (like 35 * .01 = 0.35000000000000003) module.verbose('Cutting off additional decimal places'); return Math.round((difference + module.get.min()) * precision) / precision; }, keyMovement: function (event) { var key = event.which, downArrow = module.is.vertical() ? (module.is.reversed() ? keys.downArrow : keys.upArrow) : keys.downArrow, upArrow = module.is.vertical() ? (module.is.reversed() ? keys.upArrow : keys.downArrow) : keys.upArrow, leftArrow = !module.is.vertical() ? (module.is.reversed() ? keys.rightArrow : keys.leftArrow) : keys.leftArrow, rightArrow = !module.is.vertical() ? (module.is.reversed() ? keys.leftArrow : keys.rightArrow) : keys.rightArrow ; if (key === downArrow || key === leftArrow) { return SINGLE_BACKSTEP; } if (key === upArrow || key === rightArrow) { return SINGLE_STEP; } if (key === keys.pageDown) { return BIG_BACKSTEP; } if (key === keys.pageUp) { return BIG_STEP; } return NO_STEP; }, }, handleNewValuePosition: function (val) { var min = module.get.min(), max = module.get.max(), newPos ; if (val <= min) { val = min; } else if (val >= max) { val = max; } newPos = module.determine.positionFromValue(val); return newPos; }, set: { value: function (newValue, fireChange) { fireChange = fireChange !== false; var toReset = previousValue === undefined; previousValue = previousValue === undefined ? module.get.value() : previousValue; module.update.value(newValue, function (value, thumbVal, secondThumbVal) { if ((!initialLoad || settings.fireOnInit) && fireChange) { if (newValue !== previousValue) { settings.onChange.call(element, value, thumbVal, secondThumbVal); } settings.onMove.call(element, value, thumbVal, secondThumbVal); } if (toReset) { previousValue = undefined; } }); }, rangeValue: function (first, second, fireChange) { fireChange = fireChange !== false; if (module.is.range()) { var min = module.get.min(), max = module.get.max(), toReset = previousValue === undefined ; previousValue = previousValue === undefined ? module.get.value() : previousValue; if (first <= min) { first = min; } else if (first >= max) { first = max; } if (second <= min) { second = min; } else if (second >= max) { second = max; } module.thumbVal = first; module.secondThumbVal = second; value = Math.abs(module.thumbVal - module.secondThumbVal); module.update.position(module.thumbVal, $thumb); module.update.position(module.secondThumbVal, $secondThumb); if ((!initialLoad || settings.fireOnInit) && fireChange) { if (value !== previousValue) { settings.onChange.call(element, value, module.thumbVal, module.secondThumbVal); } settings.onMove.call(element, value, module.thumbVal, module.secondThumbVal); } if (toReset) { previousValue = undefined; } } else { module.error(error.notrange); } }, position: function (position, which) { var thumbVal = module.determine.value(position); if (whi