diff --git a/jQDateRangeSlider.js b/jQDateRangeSlider.js index 57acdae1..59f19926 100644 --- a/jQDateRangeSlider.js +++ b/jQDateRangeSlider.js @@ -9,7 +9,7 @@ (function ($, undefined) { "use strict"; - + $.widget("ui.dateRangeSlider", $.ui.rangeSlider, { options: { bounds: {min: new Date(2010,0,1).valueOf(), max: new Date(2012,0,1).valueOf()}, @@ -42,8 +42,19 @@ }); }, + _setLimits: function(min, max) + { + if (((min instanceof Date) || (min === false)) || ((max instanceof Date) || (max === false))) + { + if ((min instanceof Date) && (max instanceof Date) && (min < max)) + return; + + $.ui.rangeSlider.prototype._setLimits.apply(this, [min.valueOf(), max.valueOf()]); + } + }, + _setOption: function(key, value){ - if ((key === "defaultValues" || key === "bounds") && typeof value !== "undefined" && value !== null && this._isValidDate(value.min) && this._isValidDate(value.max)){ + if ((key === "defaultValues" || key === "bounds" || key === "limits") && typeof value !== "undefined" && value !== null && this._isValidDate(value.min) && this._isValidDate(value.max)){ $.ui.rangeSlider.prototype._setOption.apply(this, [key, {min:value.min.valueOf(), max:value.max.valueOf()}]); }else{ $.ui.rangeSlider.prototype._setOption.apply(this, this._toArray(arguments)); @@ -55,7 +66,7 @@ }, option: function(key){ - if (key === "bounds" || key === "defaultValues"){ + if (key === "bounds" || key === "defaultValues" || key === "limits"){ var result = $.ui.rangeSlider.prototype.option.apply(this, arguments); return {min:new Date(result.min), max:new Date(result.max)}; @@ -81,13 +92,13 @@ return (function(formatter){ return function(value){ return formatter(new Date(value)); - } + }; }(formatter)); }, values: function(min, max){ var values = null; - + if (this._isValidDate(min) && this._isValidDate(max)) { values = $.ui.rangeSlider.prototype.values.apply(this, [min.valueOf(), max.valueOf()]); @@ -113,16 +124,16 @@ return new Date($.ui.rangeSlider.prototype.max.apply(this)); }, - + bounds: function(min, max){ var result; - + if (this._isValidDate(min) && this._isValidDate(max)) { result = $.ui.rangeSlider.prototype.bounds.apply(this, [min.valueOf(), max.valueOf()]); } else { result = $.ui.rangeSlider.prototype.bounds.apply(this, this._toArray(arguments)); } - + return {min: new Date(result.min), max: new Date(result.max)}; }, diff --git a/jQRangeSlider.js b/jQRangeSlider.js index 149e0578..6bcd3221 100644 --- a/jQRangeSlider.js +++ b/jQRangeSlider.js @@ -14,6 +14,7 @@ options: { bounds: {min:0, max:100}, defaultValues: {min:20, max:50}, + limits: {min: false, max: false}, wheelMode: null, wheelSpeed: 4, arrows: true, @@ -85,7 +86,7 @@ }, _setOption: function(key, value) { - this._setWheelOption(key, value); + this._setWheelOption(key, value); this._setArrowsOption(key, value); this._setLabelsOption(key, value); this._setLabelsDurations(key, value); @@ -94,6 +95,7 @@ this._setRangeOption(key, value); this._setStepOption(key, value); this._setScalesOption(key, value); + this._setLimitsOption(key, value); }, _validProperty: function(object, name, defaultValue){ @@ -167,7 +169,7 @@ _setFormatterOption: function(key, value){ if (key === "formatter" && value !== null && typeof value === "function"){ this.options.formatter = value; - + if (this.options.valueLabels !== "hide"){ this._destroyLabels(); this._createLabels(); @@ -213,6 +215,28 @@ } }, + _setLimits: function(min, max){ + if (!this.options.limits) + this.options.limits = {}; + + if ((typeof(min) === "number") || (min === false)) + this.options.limits.min = min; + + if ((typeof(max) === "number") || (max === false)) + this.options.limits.max = max; + + this._leftHandle("option", "limits", this.options.limits); + this._rightHandle("option", "limits", this.options.limits); + this._bar("option", "limits", this.options.limits); + }, + + _setLimitsOption: function(key, value){ + if (key === "limits" && ((typeof(value.min) !== "undefined") || (typeof value.max !== "undefined"))) + { + this._setLimits(value.min, value.max); + } + }, + _createElements: function(){ if (this.element.css("position") !== "absolute"){ this.element.css("position", "relative"); @@ -223,7 +247,7 @@ this.container = $("
") .css("position", "absolute") .appendTo(this.element); - + this.innerBar = $("
") .css("position", "absolute") .css("top", 0) @@ -251,36 +275,48 @@ }, _createHandles: function(){ - this.leftHandle = this._createHandle({ - isLeft: true, - bounds: this.options.bounds, - value: this._values.min, - step: this.options.step - }).appendTo(this.container); - - this.rightHandle = this._createHandle({ + var leftHandleParams = { + isLeft: true, + bounds: this.options.bounds, + value: this._values.min, + step: this.options.step + }; + + var rightHandleParams = { isLeft: false, bounds: this.options.bounds, value: this._values.max, step: this.options.step - }).appendTo(this.container); + }; + + var limits = this.options.limits; + if (limits) + { + leftHandleParams.limits = limits; + rightHandleParams.limits = limits; + } + + this.leftHandle = this._createHandle(leftHandleParams).appendTo(this.container); + this.rightHandle = this._createHandle(rightHandleParams).appendTo(this.container); }, - + _createBar: function(){ this.bar = $("
") .prependTo(this.container) .bind("sliderDrag scroll zoom", $.proxy(this._changing, this)) .bind("stop", $.proxy(this._changed, this)); - - this._bar({ - leftHandle: this.leftHandle, - rightHandle: this.rightHandle, - values: {min: this._values.min, max: this._values.max}, - type: this._handleType(), - range: this.options.range, - wheelMode: this.options.wheelMode, - wheelSpeed: this.options.wheelSpeed - }); + + var barParams = { + leftHandle: this.leftHandle, + rightHandle: this.rightHandle, + values: {min: this._values.min, max: this._values.max}, + type: this._handleType(), + range: this.options.range, + wheelMode: this.options.wheelMode, + wheelSpeed: this.options.wheelSpeed + }; + + this._bar(barParams); this.options.range = this._bar("option", "range"); this.options.wheelMode = this._bar("option", "wheelMode"); @@ -359,10 +395,10 @@ }, _getValue: function(position, handle){ - if (handle === this.rightHandle){ + if (handle === this.rightHandle){ position = position - handle.outerWidth(); } - + return position * (this.options.bounds.max - this.options.bounds.min) / (this.container.innerWidth() - handle.outerWidth(true)) + this.options.bounds.min; }, @@ -389,7 +425,7 @@ this._trigger("valuesChanged"); if (isAutomatic !== true){ - this._trigger("userValuesChanged"); + this._trigger("userValuesChanged"); } this._valuesChanged = false; @@ -403,8 +439,8 @@ max = this._max(left, right), changing = (min !== this._values.min || max !== this._values.max); - this._values.min = this._min(left, right); - this._values.max = this._max(left, right); + this._values.min = min; + this._values.max = max; return changing; }, @@ -520,11 +556,11 @@ this._scrollTimeout = setTimeout(function(){ if (timesBeforeSpeedingUp === 0){ if (timeout > minTimeout){ - timeout = Math.max(minTimeout, timeout / 1.5); + timeout = Math.max(minTimeout, timeout / 1.5); } else { quantity = Math.min(maxQuantity, quantity * 2); } - + timesBeforeSpeedingUp = 5; } @@ -589,7 +625,7 @@ } this._createRuler(); - this._setRulerParameters(); + this._setRulerParameters(); }, /* @@ -616,18 +652,23 @@ return this._values.max; }, - + bounds: function(min, max){ if (this._isValidValue(min) && this._isValidValue(max) && min < max){ - + this._setBounds(min, max); this._updateRuler(); this._changed(true); } - + return this.options.bounds; }, + limits: function(min, max){ + this._setLimits(min, max); + return this.options.limits; + }, + _isValidValue: function(value){ return typeof value !== "undefined" && parseFloat(value) === value; }, @@ -640,7 +681,7 @@ }, zoomIn: function(quantity){ - this._bar("zoomIn", quantity) + this._bar("zoomIn", quantity); }, zoomOut: function(quantity){ @@ -658,7 +699,7 @@ this._bar("scrollRight", quantity); this._bar("stopScroll"); }, - + /** * Resize */ @@ -675,7 +716,7 @@ this._destroyWidgets(); this._destroyElements(); - + this.element.removeClass("ui-rangeSlider"); this.options = null; diff --git a/jQRangeSliderBar.js b/jQRangeSliderBar.js index 5d21e407..2443abec 100644 --- a/jQRangeSliderBar.js +++ b/jQRangeSliderBar.js @@ -332,14 +332,19 @@ _constraintPosition: function(left){ var position = {}, - right; + right, constrainedRight; position.left = $.ui.rangeSliderDraggable.prototype._constraintPosition.apply(this, [left]); - position.left = this._leftHandle("position", position.left); - right = this._rightHandle("position", position.left + this.cache.width.outer - this.cache.rightHandle.width); - position.width = right - position.left + this.cache.rightHandle.width; + right = position.left + this.cache.width.outer - this.cache.rightHandle.width; + constrainedRight = this._rightHandle("position", right); + + if (constrainedRight !== right){ + position.left = this._leftHandle("position", position.left + constrainedRight - right); + } + + position.width = constrainedRight - position.left + this.cache.rightHandle.width; return position; }, diff --git a/jQRangeSliderDraggable.js b/jQRangeSliderDraggable.js index 44962640..1ee8d345 100644 --- a/jQRangeSliderDraggable.js +++ b/jQRangeSliderDraggable.js @@ -24,7 +24,7 @@ destroy: function(){ this.cache = null; - + $.ui.rangeSliderMouseTouch.prototype.destroy.apply(this); }, @@ -42,7 +42,7 @@ _setOption: function(key, value){ if (key === "containment"){ if (value === null || $(value).length === 0){ - this.options.containment = null + this.options.containment = null; }else{ this.options.containment = $(value); } @@ -56,8 +56,8 @@ _mouseStart: function(event){ this._cache(); this.cache.click = { - left: event.pageX, - top: event.pageY + left: event.pageX, + top: event.pageY }; this.cache.initialOffset = this.element.offset(); @@ -70,6 +70,9 @@ _mouseDrag: function(event){ var position = event.pageX - this.cache.click.left; + if (!position) + return false; + position = this._constraintPosition(position + this.cache.initialOffset.left); this._applyPosition(position); @@ -89,7 +92,7 @@ _constraintPosition: function(position){ if (this.element.parent().length !== 0 && this.cache.parent.offset !== null){ - position = Math.min(position, + position = Math.min(position, this.cache.parent.offset.left + this.cache.parent.width - this.cache.width.outer); position = Math.max(position, this.cache.parent.offset.left); } @@ -101,7 +104,7 @@ var offset = { top: this.cache.offset.top, left: position - } + }; this.element.offset({left:position}); @@ -144,7 +147,7 @@ this.cache.parent = { offset: container.offset(), width: container.width() - } + }; }else{ this.cache.parent = null; } @@ -154,11 +157,11 @@ this.cache.width = { outer: this.element.outerWidth(), inner: this.element.width() - } + }; }, _parsePixels: function(element, string){ - return parseInt(element.css(string), 10) || 0; + return parseFloat(element.css(string), 10) || 0; }, _triggerMouseEvent: function(event){ diff --git a/jQRangeSliderHandle.js b/jQRangeSliderHandle.js index 02449d2a..cdc24011 100644 --- a/jQRangeSliderHandle.js +++ b/jQRangeSliderHandle.js @@ -19,6 +19,7 @@ options: { isLeft: true, bounds: {min:0, max:100}, + limits: {min: false, max: false}, range: false, value: 0, step: false @@ -43,9 +44,9 @@ }, destroy: function(){ - this.element.empty(); + this.element.empty(); - $.ui.rangeSliderDraggable.prototype.destroy.apply(this); + $.ui.rangeSliderDraggable.prototype.destroy.apply(this); }, _setOption: function(key, value){ @@ -68,6 +69,9 @@ }else if (key === "range" && this._checkRange(value)){ this.options.range = value; this.update(); + }else if (key === "limits"){ + this.options.limits = value; + this.update(); } $.ui.rangeSliderDraggable.prototype._setOption.apply(this, [key, value]); @@ -87,7 +91,7 @@ _initElement: function(){ $.ui.rangeSliderDraggable.prototype._initElement.apply(this); - + if (this.cache.parent.width === 0 || this.cache.parent.width === null){ setTimeout($.proxy(this._initElementIfNotDestroyed, this), 500); }else{ @@ -120,7 +124,7 @@ left: this._parsePixels(parent, "paddingLeft") }, width: parent.width() - } + }; }, _position: function(value){ @@ -163,7 +167,7 @@ _constraintValue: function(value){ value = Math.min(value, this._bounds().max); value = Math.max(value, this._bounds().min); - + value = this._round(value); if (this.options.range !== false){ @@ -182,6 +186,15 @@ value = Math.max(value, this._bounds().min); } + var limits = this.options.limits; + if (limits) + { + if (this.options.isLeft && (limits.min || (limits.min === 0))) + value = Math.max(value, limits.min); + else if (limits.max || (limits.max === 0)) + value = Math.min(value, limits.max); + } + return value; }, @@ -204,7 +217,6 @@ availableWidth = this.cache.parent.width - this.cache.width.outer, parentPosition = this.cache.parent.offset.left; - return ratio * availableWidth + parentPosition; }, @@ -257,8 +269,15 @@ position: function(position){ if (typeof position !== "undefined"){ this._cache(); - + + //There might be a slight difference between the positions, + //so if this difference is lower than 0.005 we consider it null. + var oldPos = position; position = this._constraintPosition(position); + var diff = Math.abs(position - oldPos); + if (diff < 0.005) + return this._left; + this._applyPosition(position); } @@ -294,7 +313,7 @@ return this._left - previous; } - + previous = this._value; this.value(this.add(previous, this.multiplyStep(this.options.step, quantity))); diff --git a/jQRangeSliderLabel.js b/jQRangeSliderLabel.js index 5fb02fe0..94ef2bd0 100644 --- a/jQRangeSliderLabel.js +++ b/jQRangeSliderLabel.js @@ -8,7 +8,7 @@ */ (function($, undefined){ - + "use strict"; $.widget("ui.rangeSliderLabel", $.ui.rangeSliderMouseTouch, { @@ -100,7 +100,7 @@ this._display(this.options.handle[this.options.handleType]("value")); this._positionner.PositionLabels(); } - + this._positionner.options.show = this.options.show; }, @@ -158,7 +158,7 @@ _onSwitch: function(event, isLeft){ this.options.isLeft = isLeft; - + this._toggleClass(); this._positionner.PositionLabels(); }, @@ -228,7 +228,7 @@ this._resizeProxy = $.proxy(this.onWindowResize, this); $(window).resize(this._resizeProxy); - } + }; this.Destroy = function(){ if (this._resizeProxy){ @@ -246,13 +246,13 @@ this.left = null; this.right = null; } - - this.cache = null; - } + + this.cache = null; + }; this.AfterInit = function () { this.initialized = true; - } + }; this.Cache = function(){ if (this.label1.css("display") === "none"){ @@ -271,7 +271,7 @@ this.CacheElement(this.handle1, this.cache.handle1); this.CacheElement(this.handle2, this.cache.handle2); this.CacheElement(this.label1.offsetParent(), this.cache.offsetParent); - } + }; this.CacheIfNecessary = function(){ if (this.cache === null){ @@ -283,7 +283,7 @@ this.CacheHeight(this.label2, this.cache.label2); this.CacheWidth(this.label1.offsetParent(), this.cache.offsetParent); } - } + }; this.CacheElement = function(label, cache){ this.CacheWidth(label, cache); @@ -299,27 +299,27 @@ left: this.ParsePixels("borderLeftWidth", label), right: this.ParsePixels("borderRightWidth", label) }; - } + }; this.CacheWidth = function(label, cache){ cache.width = label.width(); cache.outerWidth = label.outerWidth(); - } + }; this.CacheHeight = function(label, cache){ cache.outerHeightMargin = label.outerHeight(true); - } + }; this.ParsePixels = function(name, element){ return parseInt(element.css(name), 10) || 0; - } + }; this.BindHandle = function(handle){ handle.bind("updating.positionner", $.proxy(this.onHandleUpdating, this)); handle.bind("update.positionner", $.proxy(this.onHandleUpdated, this)); handle.bind("moving.positionner", $.proxy(this.onHandleMoving, this)); handle.bind("stop.positionner", $.proxy(this.onHandleStop, this)); - } + }; this.PositionLabels = function(){ this.CacheIfNecessary(); @@ -335,7 +335,7 @@ this.PositionLabel(this.label1, label1Pos.left, this.cache.label1); this.PositionLabel(this.label2, label2Pos.left, this.cache.label2); - } + }; this.PositionLabel = function(label, leftOffset, cache){ var parentShift = this.cache.offsetParent.offset.left + this.cache.offsetParent.border.left, @@ -354,7 +354,7 @@ label.css("left", ""); label.css("right", rightPosition); } - } + }; this.ConstraintPositions = function(pos1, pos2){ if (pos1.center < pos2.center && pos1.outerRight > pos2.outerLeft){ @@ -364,7 +364,7 @@ pos2 = this.getLeftPosition(pos2, pos1); pos1 = this.getRightPosition(pos2, pos1); } - } + }; this.getLeftPosition = function(left, right){ var center = (right.center + left.center) / 2, @@ -373,7 +373,7 @@ left.left = leftPos; return left; - } + }; this.getRightPosition = function(left, right){ var center = (right.center + left.center) / 2; @@ -381,7 +381,7 @@ right.left = center + right.cache.margin.left + right.cache.border.left; return right; - } + }; this.ShowIfNecessary = function(){ if (this.options.show === "show" || this.moving || !this.initialized || this.updating) return; @@ -389,7 +389,7 @@ this.label1.stop(true, true).fadeIn(this.options.durationIn || 0); this.label2.stop(true, true).fadeIn(this.options.durationIn || 0); this.moving = true; - } + }; this.HideIfNeeded = function(){ if (this.moving === true){ @@ -397,7 +397,7 @@ this.label2.stop(true, true).delay(this.options.delayOut || 0).fadeOut(this.options.durationOut || 0); this.moving = false; } - } + }; this.onHandleMoving = function(event, ui){ this.ShowIfNecessary(); @@ -405,38 +405,38 @@ this.UpdateHandlePosition(ui); this.PositionLabels(); - } + }; this.onHandleUpdating = function(){ this.updating = true; - } + }; this.onHandleUpdated = function(){ this.updating = false; this.cache = null; - } + }; this.onHandleStop = function(){ this.HideIfNeeded(); - } + }; this.onWindowResize = function(){ this.cache = null; - } + }; this.UpdateHandlePosition = function(ui){ if (this.cache === null) return; - + if (ui.element[0] === this.handle1[0]){ this.UpdatePosition(ui, this.cache.handle1); }else{ this.UpdatePosition(ui, this.cache.handle2); } - } + }; this.UpdatePosition = function(element, cache){ cache.offset = element.offset; - } + }; this.GetRawPosition = function(labelCache, handleCache){ var handleCenter = handleCache.offset.left + handleCache.outerWidth / 2, @@ -453,8 +453,8 @@ outerRight: outerLeft + labelCache.outerWidth + labelCache.margin.left + labelCache.margin.right, cache: labelCache, center: handleCenter - } - } + }; + }; this.Init(); }