You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
14 KiB
363 lines
14 KiB
define([ |
|
"dojo/_base/declare", |
|
"dojo/_base/lang", |
|
"dojo/_base/array", |
|
"dojo/_base/fx", |
|
"dojo/_base/event", |
|
"dojo/_base/sniff", |
|
"dojo/dom-style", |
|
"dojo/dom-geometry", |
|
"dojo/keys", |
|
"dijit", |
|
"dojo/dnd/Mover", |
|
"dojo/dnd/Moveable", |
|
"dijit/form/_FormValueWidget", |
|
"dijit/focus", |
|
"dojo/fx", |
|
"dojox/fx" // unused? |
|
], function(declare, lang, array, fx, event, has, domStyle, domGeometry, keys, dijit, Mover, Moveable, FormValueWidget, FocusManager, fxUtils){ |
|
|
|
// make these functions once: |
|
var sortReversed = function(a, b){ return b - a; }, |
|
sortForward = function(a, b){ return a - b; }; |
|
|
|
|
|
var RangeSliderMixin = declare("dojox.form._RangeSliderMixin", null, { |
|
|
|
// list attach points that have tabIndex so they can be properly disabled |
|
_setTabIndexAttr: ["sliderHandle", "sliderHandleMax"], |
|
|
|
value: [0,100], |
|
postMixInProperties: function(){ |
|
this.inherited(arguments); |
|
this.value = array.map(this.value, function(i){ return parseInt(i, 10); }); |
|
}, |
|
|
|
postCreate: function(){ |
|
this.inherited(arguments); |
|
// we sort the values! |
|
// TODO: re-think, how to set the value |
|
this.value.sort(sortForward); |
|
|
|
// define a custom constructor for a SliderMoverMax that points back to me |
|
var _self = this; |
|
var mover = declare(SliderMoverMax, { |
|
constructor: function(){ |
|
this.widget = _self; |
|
} |
|
}); |
|
|
|
this._movableMax = new Moveable(this.sliderHandleMax,{ mover: mover }); |
|
|
|
//The valuenow of the sliderHandle (min) usually determines the valuemin of sliderHandleMax |
|
//and valuenow of sliderHandleMax usually determines the valueMax of sliderHandle |
|
//However, in our RangeSlider dragging one handle past the other one causes both to |
|
//'snap' together and move so both sliders will have the same min, max values |
|
|
|
this.sliderHandle.setAttribute("aria-valuemin", this.minimum); |
|
this.sliderHandle.setAttribute("aria-valuemax", this.maximum); |
|
this.sliderHandleMax.setAttribute("aria-valuemin", this.minimum); |
|
this.sliderHandleMax.setAttribute("aria-valuemax", this.maximum); |
|
|
|
// a dnd for the bar! |
|
var barMover = declare(SliderBarMover, { |
|
constructor: function(){ |
|
this.widget = _self; |
|
} |
|
}); |
|
this._movableBar = new Moveable(this.progressBar,{ mover: barMover }); |
|
|
|
// Remove these from the progress bar since it isn't a slider |
|
this.focusNode.removeAttribute("aria-valuemin"); |
|
this.focusNode.removeAttribute("aria-valuemax"); |
|
this.focusNode.removeAttribute("aria-valuenow"); |
|
|
|
}, |
|
|
|
destroy: function(){ |
|
this.inherited(arguments); |
|
this._movableMax.destroy(); |
|
this._movableBar.destroy(); |
|
}, |
|
|
|
_onKeyPress: function(/*Event*/ e){ |
|
if(this.disabled || this.readOnly || e.altKey || e.ctrlKey){ return; } |
|
|
|
var useMaxValue = e.target === this.sliderHandleMax; |
|
var barFocus = e.target === this.progressBar; |
|
var k = lang.delegate(keys, this.isLeftToRight() ? {PREV_ARROW: keys.LEFT_ARROW, NEXT_ARROW: keys.RIGHT_ARROW} |
|
: {PREV_ARROW: keys.RIGHT_ARROW, NEXT_ARROW: keys.LEFT_ARROW}); |
|
var delta = 0; |
|
var down = false; |
|
|
|
switch(e.keyCode){ |
|
case k.HOME : this._setValueAttr(this.minimum, true, useMaxValue);event.stop(e);return; |
|
case k.END : this._setValueAttr(this.maximum, true, useMaxValue);event.stop(e);return; |
|
case k.PREV_ARROW : |
|
case k.DOWN_ARROW : down = true; |
|
case k.NEXT_ARROW : |
|
case k.UP_ARROW : delta = 1; break; |
|
case k.PAGE_DOWN : down = true; |
|
case k.PAGE_UP : delta = this.pageIncrement; break; |
|
default : this.inherited(arguments);return; |
|
} |
|
|
|
if(down){delta = -delta;} |
|
|
|
if(delta){ |
|
if(barFocus){ |
|
this._bumpValue([ |
|
{ change: delta, useMaxValue: false }, |
|
{ change: delta, useMaxValue: true } |
|
]); |
|
}else{ |
|
this._bumpValue(delta, useMaxValue); |
|
} |
|
event.stop(e); |
|
} |
|
}, |
|
|
|
_onHandleClickMax: function(e){ |
|
if(this.disabled || this.readOnly){ return; } |
|
if(!has("ie")){ |
|
// make sure you get focus when dragging the handle |
|
// (but don't do on IE because it causes a flicker on mouse up (due to blur then focus) |
|
FocusManager.focus(this.sliderHandleMax); |
|
} |
|
event.stop(e); |
|
}, |
|
|
|
_onClkIncBumper: function(){ |
|
this._setValueAttr(this._descending === false ? this.minimum : this.maximum, true, true); |
|
}, |
|
|
|
_bumpValue: function(signedChange, useMaxValue){ |
|
|
|
// we pass an array to _setValueAttr when signedChange is an array |
|
var value = lang.isArray(signedChange) ? [ |
|
this._getBumpValue(signedChange[0].change, signedChange[0].useMaxValue), |
|
this._getBumpValue(signedChange[1].change, signedChange[1].useMaxValue) |
|
] |
|
: this._getBumpValue(signedChange, useMaxValue); |
|
|
|
this._setValueAttr(value, true, useMaxValue); |
|
}, |
|
|
|
_getBumpValue: function(signedChange, useMaxValue){ |
|
|
|
var idx = useMaxValue ? 1 : 0; |
|
|
|
var s = domStyle.getComputedStyle(this.sliderBarContainer), |
|
c = domGeometry.getContentBox(this.sliderBarContainer, s), |
|
count = this.discreteValues, |
|
myValue = this.value[idx] |
|
; |
|
|
|
if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; } |
|
count--; |
|
|
|
var value = this.maximum > this.minimum ? ((myValue - this.minimum) * count / (this.maximum - this.minimum) + signedChange) : 0; |
|
if(value < 0){ value = 0; } |
|
if(value > count){ value = count; } |
|
|
|
return value * (this.maximum - this.minimum) / count + this.minimum; |
|
}, |
|
|
|
_onBarClick: function(e){ |
|
if(this.disabled || this.readOnly){ return; } |
|
if(!has("ie")){ |
|
// make sure you get focus when dragging the handle |
|
// (but don't do on IE because it causes a flicker on mouse up (due to blur then focus) |
|
FocusManager.focus(this.progressBar); |
|
} |
|
event.stop(e); |
|
}, |
|
|
|
_onRemainingBarClick: function(e){ |
|
if(this.disabled || this.readOnly){ return; } |
|
if(!has("ie")){ |
|
// make sure you get focus when dragging the handle |
|
// (but don't do on IE because it causes a flicker on mouse up (due to blur then focus) |
|
FocusManager.focus(this.progressBar); |
|
} |
|
|
|
// now we set the min/max-value of the slider! |
|
var abspos = domGeometry.position(this.sliderBarContainer, true), |
|
bar = domGeometry.position(this.progressBar, true), |
|
mousePos = e[this._mousePixelCoord], |
|
leftPos = bar[this._startingPixelCoord], |
|
rightPos = leftPos + bar[this._pixelCount], |
|
isMaxVal = this._isReversed() ? mousePos <= leftPos : mousePos >= rightPos, |
|
p = this._isReversed() ? (abspos[this._pixelCount] - mousePos + abspos[this._startingPixelCoord]) : (mousePos - abspos[this._startingPixelCoord]) |
|
; |
|
|
|
this._setPixelValue(p, abspos[this._pixelCount], true, isMaxVal); |
|
event.stop(e); |
|
}, |
|
|
|
_setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean*/ priorityChange, /*Boolean*/ isMaxVal){ |
|
if(this.disabled || this.readOnly){ return; } |
|
var myValue = this._getValueByPixelValue(pixelValue, maxPixels); |
|
this._setValueAttr(myValue, priorityChange, isMaxVal); |
|
}, |
|
|
|
_getValueByPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels){ |
|
pixelValue = pixelValue < 0 ? 0 : maxPixels < pixelValue ? maxPixels : pixelValue; |
|
var count = this.discreteValues; |
|
if(count <= 1 || count == Infinity){ count = maxPixels; } |
|
count--; |
|
var pixelsPerValue = maxPixels / count; |
|
var wholeIncrements = Math.round(pixelValue / pixelsPerValue); |
|
return (this.maximum-this.minimum)*wholeIncrements/count + this.minimum; |
|
}, |
|
|
|
_setValueAttr: function(/*Array or Number*/ value, /*Boolean, optional*/ priorityChange, /*Boolean, optional*/ isMaxVal){ |
|
// we pass an array, when we move the slider with the bar |
|
var actValue = lang.clone(this.value); |
|
|
|
if(!lang.isArray(value)){ |
|
actValue[isMaxVal ? 1 : 0] = value; |
|
}else{ |
|
actValue = value; |
|
} |
|
// we have to reset this values. don't know the reason for that |
|
this._lastValueReported = ""; |
|
this.valueNode.value = value = actValue; |
|
|
|
actValue.sort(sortForward); |
|
|
|
this.sliderHandle.setAttribute("aria-valuenow", actValue[0]); |
|
this.sliderHandleMax.setAttribute("aria-valuenow", actValue[1]); |
|
|
|
// not calling the _setValueAttr-function of Slider, but the super-super-class (needed for the onchange-event!) |
|
FormValueWidget.prototype._setValueAttr.apply(this, arguments); |
|
|
|
this._printSliderBar(priorityChange, isMaxVal); |
|
}, |
|
|
|
_printSliderBar: function(priorityChange, isMaxVal){ |
|
var percentMin = this.maximum > this.minimum ? ((this.value[0] - this.minimum) / (this.maximum - this.minimum)) : 0; |
|
var percentMax = this.maximum > this.minimum ? ((this.value[1] - this.minimum) / (this.maximum - this.minimum)) : 0; |
|
var percentMinSave = percentMin; |
|
if(percentMin > percentMax){ |
|
percentMin = percentMax; |
|
percentMax = percentMinSave; |
|
} |
|
var sliderHandleVal = this._isReversed() ? ((1-percentMin)*100) : (percentMin * 100); |
|
var sliderHandleMaxVal = this._isReversed() ? ((1-percentMax)*100) : (percentMax * 100); |
|
var progressBarVal = this._isReversed() ? ((1-percentMax)*100) : (percentMin * 100); |
|
if(priorityChange && this.slideDuration > 0 && this.progressBar.style[this._progressPixelSize]){ |
|
// animate the slider |
|
var percent = isMaxVal ? percentMax : percentMin; |
|
var _this = this; |
|
var props = {}; |
|
var start = parseFloat(this.progressBar.style[this._handleOffsetCoord]); |
|
var duration = this.slideDuration / 10; // * (percent-start/100); |
|
if(duration === 0){ return; } |
|
if(duration < 0){ duration = 0 - duration; } |
|
var propsHandle = {}; |
|
var propsHandleMax = {}; |
|
var propsBar = {}; |
|
// hui, a lot of animations :-) |
|
propsHandle[this._handleOffsetCoord] = { start: this.sliderHandle.parentNode.style[this._handleOffsetCoord], end: sliderHandleVal, units:"%"}; |
|
propsHandleMax[this._handleOffsetCoord] = { start: this.sliderHandleMax.parentNode.style[this._handleOffsetCoord], end: sliderHandleMaxVal, units:"%"}; |
|
propsBar[this._handleOffsetCoord] = { start: this.progressBar.style[this._handleOffsetCoord], end: progressBarVal, units:"%"}; |
|
propsBar[this._progressPixelSize] = { start: this.progressBar.style[this._progressPixelSize], end: (percentMax - percentMin) * 100, units:"%"}; |
|
var animHandle = fx.animateProperty({node: this.sliderHandle.parentNode, duration: duration, properties: propsHandle}); |
|
var animHandleMax = fx.animateProperty({node: this.sliderHandleMax.parentNode, duration: duration, properties: propsHandleMax}); |
|
var animBar = fx.animateProperty({node: this.progressBar, duration: duration, properties: propsBar}); |
|
var animCombine = fxUtils.combine([animHandle, animHandleMax, animBar]); |
|
animCombine.play(); |
|
}else{ |
|
this.sliderHandle.parentNode.style[this._handleOffsetCoord] = sliderHandleVal + "%"; |
|
this.sliderHandleMax.parentNode.style[this._handleOffsetCoord] = sliderHandleMaxVal + "%"; |
|
this.progressBar.style[this._handleOffsetCoord] = progressBarVal + "%"; |
|
this.progressBar.style[this._progressPixelSize] = ((percentMax - percentMin) * 100) + "%"; |
|
} |
|
} |
|
}); |
|
|
|
var SliderMoverMax = declare("dijit.form._SliderMoverMax", Mover, { |
|
|
|
onMouseMove: function(e){ |
|
var widget = this.widget; |
|
var abspos = widget._abspos; |
|
if(!abspos){ |
|
abspos = widget._abspos = domGeometry.position(widget.sliderBarContainer, true); |
|
widget._setPixelValue_ = lang.hitch(widget, "_setPixelValue"); |
|
widget._isReversed_ = widget._isReversed(); |
|
} |
|
|
|
var pixelValue = e[widget._mousePixelCoord] - abspos[widget._startingPixelCoord]; |
|
widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false, true); |
|
}, |
|
|
|
destroy: function(e){ |
|
Mover.prototype.destroy.apply(this, arguments); |
|
var widget = this.widget; |
|
widget._abspos = null; |
|
widget._setValueAttr(widget.value, true); |
|
} |
|
}); |
|
|
|
var SliderBarMover = declare("dijit.form._SliderBarMover", Mover, { |
|
|
|
onMouseMove: function(e){ |
|
var widget = this.widget; |
|
if(widget.disabled || widget.readOnly){ return; } |
|
var abspos = widget._abspos; |
|
var bar = widget._bar; |
|
var mouseOffset = widget._mouseOffset; |
|
if(!abspos){ |
|
abspos = widget._abspos = domGeometry.position(widget.sliderBarContainer, true); |
|
widget._setPixelValue_ = lang.hitch(widget, "_setPixelValue"); |
|
widget._getValueByPixelValue_ = lang.hitch(widget, "_getValueByPixelValue"); |
|
widget._isReversed_ = widget._isReversed(); |
|
} |
|
|
|
if(!bar){ |
|
bar = widget._bar = domGeometry.position(widget.progressBar, true); |
|
} |
|
|
|
if(!mouseOffset){ |
|
mouseOffset = widget._mouseOffset = e[widget._mousePixelCoord] - bar[widget._startingPixelCoord]; |
|
} |
|
|
|
var pixelValueMin = e[widget._mousePixelCoord] - abspos[widget._startingPixelCoord] - mouseOffset, |
|
pixelValueMax = pixelValueMin + bar[widget._pixelCount]; |
|
// we don't narrow the slider when it reaches the bumper! |
|
// maybe there is a simpler way |
|
pixelValues = [pixelValueMin, pixelValueMax] |
|
; |
|
|
|
pixelValues.sort(sortForward); |
|
|
|
if(pixelValues[0] <= 0){ |
|
pixelValues[0] = 0; |
|
pixelValues[1] = bar[widget._pixelCount]; |
|
} |
|
if(pixelValues[1] >= abspos[widget._pixelCount]){ |
|
pixelValues[1] = abspos[widget._pixelCount]; |
|
pixelValues[0] = abspos[widget._pixelCount] - bar[widget._pixelCount]; |
|
} |
|
// getting the real values by pixel |
|
var myValues = [ |
|
widget._getValueByPixelValue(widget._isReversed_ ? (abspos[widget._pixelCount] - pixelValues[0]) : pixelValues[0], abspos[widget._pixelCount]), |
|
widget._getValueByPixelValue(widget._isReversed_ ? (abspos[widget._pixelCount] - pixelValues[1]) : pixelValues[1], abspos[widget._pixelCount]) |
|
]; |
|
// and setting the value of the widget |
|
widget._setValueAttr(myValues, false, false); |
|
}, |
|
|
|
destroy: function(){ |
|
Mover.prototype.destroy.apply(this, arguments); |
|
var widget = this.widget; |
|
widget._abspos = null; |
|
widget._bar = null; |
|
widget._mouseOffset = null; |
|
widget._setValueAttr(widget.value, true); |
|
} |
|
}); |
|
|
|
return RangeSliderMixin; |
|
});
|
|
|