1 if(!dojo._hasResource["dijit.form.Slider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dijit.form.Slider"] = true;
3 dojo.provide("dijit.form.Slider");
5 dojo.require("dijit.form._FormWidget");
6 dojo.require("dijit._Container");
7 dojo.require("dojo.dnd.move");
8 dojo.require("dijit.form.Button");
9 dojo.require("dojo.number");
10 dojo.require("dojo._base.fx");
13 "dijit.form.HorizontalSlider",
14 [dijit.form._FormValueWidget, dijit._Container],
17 // A form widget that allows one to select a value with a horizontally draggable image
19 templateString:"<table class=\"dijit dijitReset dijitSlider\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"containerNode,topDecoration\" class=\"dijitReset\" style=\"text-align:center;width:100%;\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderDecrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"decrementButton\" dojoAttachEvent=\"onclick: decrement\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper dijitSliderLeftBumper\" dojoAttachEvent=\"onclick:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" name=\"${name}\"\n\t\t\t/><div waiRole=\"presentation\" style=\"position:relative;\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onclick:_onBarClick\"\n\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderMoveable dijitSliderMoveableH\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_onHandleClick\" waiRole=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitSliderImageHandleH\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onclick:_onBarClick\"></div\n\t\t\t></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper dijitSliderRightBumper\" dojoAttachEvent=\"onclick:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\" style=\"right:0px;\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"incrementButton\" dojoAttachEvent=\"onclick: increment\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset\" style=\"text-align:center;\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\n",
22 // showButtons: boolean
23 // Show increment/decrement buttons at the ends of the slider?
27 // The minimum value allowed.
31 // The maximum allowed value.
34 // discreteValues: integer
35 // The maximum allowed values dispersed evenly between minimum and maximum (inclusive).
36 discreteValues: Infinity,
38 // pageIncrement: integer
39 // The amount of change with shift+arrow
42 // clickSelect: boolean
43 // If clicking the progress bar changes the value or not
46 // slideDuration: Number
47 // The time in ms to take to animate the slider handle from 0% to 100%
50 widgetsInTemplate: true,
52 attributeMap: dojo.mixin(dojo.clone(dijit.form._FormWidget.prototype.attributeMap),
53 {id:"", name:"valueNode"}),
55 baseClass: "dijitSlider",
57 _mousePixelCoord: "pageX",
59 _startingPixelCoord: "x",
60 _startingPixelCount: "l",
61 _handleOffsetCoord: "left",
62 _progressPixelSize: "width",
64 _onKeyPress: function(/*Event*/ e){
65 if(this.disabled || this.readOnly || e.altKey || e.ctrlKey){ return; }
68 this.setValue(this.minimum, true);
71 this.setValue(this.maximum, true);
73 // this._descending === false: if ascending vertical (min on top)
74 // (this._descending || this.isLeftToRight()): if left-to-right horizontal or descending vertical
75 case ((this._descending || this.isLeftToRight()) ? dojo.keys.RIGHT_ARROW : dojo.keys.LEFT_ARROW):
76 case (this._descending === false ? dojo.keys.DOWN_ARROW : dojo.keys.UP_ARROW):
77 case (this._descending === false ? dojo.keys.PAGE_DOWN : dojo.keys.PAGE_UP):
80 case ((this._descending || this.isLeftToRight()) ? dojo.keys.LEFT_ARROW : dojo.keys.RIGHT_ARROW):
81 case (this._descending === false ? dojo.keys.UP_ARROW : dojo.keys.DOWN_ARROW):
82 case (this._descending === false ? dojo.keys.PAGE_UP : dojo.keys.PAGE_DOWN):
86 this.inherited(arguments);
92 _onHandleClick: function(e){
93 if(this.disabled || this.readOnly){ return; }
95 // make sure you get focus when dragging the handle
96 // (but don't do on IE because it causes a flicker on mouse up (due to blur then focus)
97 dijit.focus(this.sliderHandle);
102 _isReversed: function(){
103 return !this.isLeftToRight();
106 _onBarClick: function(e){
107 if(this.disabled || this.readOnly || !this.clickSelect){ return; }
108 dijit.focus(this.sliderHandle);
110 var abspos = dojo.coords(this.sliderBarContainer, true);
111 var pixelValue = e[this._mousePixelCoord] - abspos[this._startingPixelCoord];
112 this._setPixelValue(this._isReversed() ? (abspos[this._pixelCount] - pixelValue) : pixelValue, abspos[this._pixelCount], true);
115 _setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean, optional*/ priorityChange){
116 if(this.disabled || this.readOnly){ return; }
117 pixelValue = pixelValue < 0 ? 0 : maxPixels < pixelValue ? maxPixels : pixelValue;
118 var count = this.discreteValues;
119 if(count <= 1 || count == Infinity){ count = maxPixels; }
121 var pixelsPerValue = maxPixels / count;
122 var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
123 this.setValue((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, priorityChange);
126 setValue: function(/*Number*/ value, /*Boolean, optional*/ priorityChange){
127 this.valueNode.value = this.value = value;
128 dijit.setWaiState(this.focusNode, "valuenow", value);
129 this.inherited(arguments);
130 var percent = (value - this.minimum) / (this.maximum - this.minimum);
131 var progressBar = (this._descending === false) ? this.remainingBar : this.progressBar;
132 var remainingBar = (this._descending === false) ? this.progressBar : this.remainingBar;
133 if(priorityChange && this.slideDuration > 0 && progressBar.style[this._progressPixelSize]){
134 // animate the slider
137 var start = parseFloat(progressBar.style[this._progressPixelSize]);
138 var duration = this.slideDuration * (percent-start/100);
139 if(duration == 0){ return; }
140 if(duration < 0){ duration = 0 - duration; }
141 props[this._progressPixelSize] = { start: start, end: percent*100, units:"%" };
142 dojo.animateProperty({ node: progressBar, duration: duration,
143 onAnimate: function(v){ remainingBar.style[_this._progressPixelSize] = (100-parseFloat(v[_this._progressPixelSize])) + "%"; },
148 progressBar.style[this._progressPixelSize] = (percent*100) + "%";
149 remainingBar.style[this._progressPixelSize] = ((1-percent)*100) + "%";
153 _bumpValue: function(signedChange){
154 if(this.disabled || this.readOnly){ return; }
155 var s = dojo.getComputedStyle(this.sliderBarContainer);
156 var c = dojo._getContentBox(this.sliderBarContainer, s);
157 var count = this.discreteValues;
158 if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; }
160 var value = (this.value - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
161 if(value < 0){ value = 0; }
162 if(value > count){ value = count; }
163 value = value * (this.maximum - this.minimum) / count + this.minimum;
164 this.setValue(value, true);
167 _onClkIncBumper: function(){
168 this.setValue(this._descending === false ? this.minimum : this.maximum, true);
171 _onClkDecBumper: function(){
172 this.setValue(this._descending === false ? this.maximum : this.minimum, true);
175 decrement: function(e){
177 // decrement slider by 1 unit
178 this._bumpValue(e.keyCode == dojo.keys.PAGE_DOWN?-this.pageIncrement:-1);
181 increment: function(e){
183 // increment slider by 1 unit
184 this._bumpValue(e.keyCode == dojo.keys.PAGE_UP?this.pageIncrement:1);
187 _mouseWheeled: function(/*Event*/ evt){
189 var scrollAmount = 0;
190 if(typeof evt.wheelDelta == 'number'){ // IE
191 scrollAmount = evt.wheelDelta;
192 }else if(typeof evt.detail == 'number'){ // Mozilla+Firefox
193 scrollAmount = -evt.detail;
195 if(scrollAmount > 0){
197 }else if(scrollAmount < 0){
203 dojo.forEach(this.getChildren(), function(child){
204 if(this[child.container] != this.containerNode){
205 this[child.container].appendChild(child.domNode);
210 postCreate: function(){
211 if(this.showButtons){
212 this.incrementButton.style.display="";
213 this.decrementButton.style.display="";
215 this.connect(this.domNode, dojo.isIE ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
217 // define a custom constructor for a SliderMover that points back to me
219 var mover = function(){
220 dijit.form._SliderMover.apply(this, arguments);
223 dojo.extend(mover, dijit.form._SliderMover.prototype);
225 this._movable = new dojo.dnd.Moveable(this.sliderHandle, {mover: mover});
226 dijit.setWaiState(this.focusNode, "valuemin", this.minimum);
227 dijit.setWaiState(this.focusNode, "valuemax", this.maximum);
229 this.inherited(arguments);
233 this._movable.destroy();
234 this.inherited(arguments);
239 "dijit.form.VerticalSlider",
240 dijit.form.HorizontalSlider,
243 // A form widget that allows one to select a value with a vertically draggable image
245 templateString:"<table class=\"dijitReset dijitSlider\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\"\n><tbody class=\"dijitReset\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderIncrementIconV\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"incrementButton\" dojoAttachEvent=\"onclick:_topButtonClicked\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper dijitSliderTopBumper\" dojoAttachEvent=\"onclick:_onClkIncBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td dojoAttachPoint=\"leftDecoration\" class=\"dijitReset\" style=\"text-align:center;height:100%;\"></td\n\t\t><td class=\"dijitReset\" style=\"height:100%;\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" name=\"${name}\"\n\t\t\t/><center waiRole=\"presentation\" style=\"position:relative;height:100%;\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" dojoAttachEvent=\"onclick:_onBarClick\"><!--#5629--></div\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" dojoAttachEvent=\"onclick:_onBarClick\"\n\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderMoveable\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_onHandleClick\" style=\"vertical-align:top;\" waiRole=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitSliderImageHandleV\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t></center\n\t\t></td\n\t\t><td dojoAttachPoint=\"containerNode,rightDecoration\" class=\"dijitReset\" style=\"text-align:center;height:100%;\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper dijitSliderBottomBumper\" dojoAttachEvent=\"onclick:_onClkDecBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderDecrementIconV\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"decrementButton\" dojoAttachEvent=\"onclick:_bottomButtonClicked\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n></tbody></table>\n",
246 _mousePixelCoord: "pageY",
248 _startingPixelCoord: "y",
249 _startingPixelCount: "t",
250 _handleOffsetCoord: "top",
251 _progressPixelSize: "height",
253 // _descending: boolean
254 // Specifies if the slider values go from high-on-top (true), or low-on-top (false)
255 // TODO: expose this in 1.2 - the css progress/remaining bar classes need to be reversed
259 if(this._started){ return; }
261 if(!this.isLeftToRight() && dojo.isMoz){
262 if(this.leftDecoration){this._rtlRectify(this.leftDecoration);}
263 if(this.rightDecoration){this._rtlRectify(this.rightDecoration);}
266 this.inherited(arguments);
269 _isReversed: function(){
270 return this._descending;
273 _topButtonClicked: function(e){
274 if(this._descending){
281 _bottomButtonClicked: function(e){
282 if(this._descending){
289 _rtlRectify: function(decorationNode/*NodeList*/){
291 // Rectify children nodes for left/right decoration in rtl case.
292 // Simply switch the rule and label child for each decoration node.
294 while(decorationNode.firstChild){
295 childNodes.push(decorationNode.firstChild);
296 decorationNode.removeChild(decorationNode.firstChild);
298 for(var i = childNodes.length-1; i >=0; i--){
300 decorationNode.appendChild(childNodes[i]);
306 dojo.declare("dijit.form._SliderMover",
309 onMouseMove: function(e){
310 var widget = this.widget;
311 var abspos = widget._abspos;
313 abspos = widget._abspos = dojo.coords(widget.sliderBarContainer, true);
314 widget._setPixelValue_ = dojo.hitch(widget, "_setPixelValue");
315 widget._isReversed_ = widget._isReversed();
317 var pixelValue = e[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
318 widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false);
321 destroy: function(e){
322 dojo.dnd.Mover.prototype.destroy.apply(this, arguments);
323 var widget = this.widget;
324 widget.setValue(widget.value, true);
329 dojo.declare("dijit.form.HorizontalRule", [dijit._Widget, dijit._Templated],
332 // Create hash marks for the Horizontal slider
333 templateString: '<div class="dijitRuleContainer dijitRuleContainerH"></div>',
336 // Number of hash marks to generate
340 // If this is a child widget, connect it to this parent node
341 container: "containerNode",
344 // CSS style to apply to individual hash marks
347 _positionPrefix: '<div class="dijitRuleMark dijitRuleMarkH" style="left:',
348 _positionSuffix: '%;',
351 _genHTML: function(pos, ndx){
352 return this._positionPrefix + pos + this._positionSuffix + this.ruleStyle + this._suffix;
357 postCreate: function(){
360 innerHTML = this._genHTML(50, 0);
363 var interval = 100 / (this.count-1);
364 if(!this._isHorizontal || this.isLeftToRight()){
365 innerHTML = this._genHTML(0, 0);
366 for(i=1; i < this.count-1; i++){
367 innerHTML += this._genHTML(interval*i, i);
369 innerHTML += this._genHTML(100, this.count-1);
371 innerHTML = this._genHTML(100, 0);
372 for(i=1; i < this.count-1; i++){
373 innerHTML += this._genHTML(100-interval*i, i);
375 innerHTML += this._genHTML(0, this.count-1);
378 this.domNode.innerHTML = innerHTML;
382 dojo.declare("dijit.form.VerticalRule", dijit.form.HorizontalRule,
385 // Create hash marks for the Vertical slider
386 templateString: '<div class="dijitRuleContainer dijitRuleContainerV"></div>',
387 _positionPrefix: '<div class="dijitRuleMark dijitRuleMarkV" style="top:',
392 dojo.declare("dijit.form.HorizontalRuleLabels", dijit.form.HorizontalRule,
395 // Create labels for the Horizontal slider
396 templateString: '<div class="dijitRuleContainer dijitRuleContainerH"></div>',
398 // labelStyle: String
399 // CSS style to apply to individual text labels
403 // Array of text labels to render - evenly spaced from left-to-right or bottom-to-top
406 // numericMargin: Integer
407 // Number of generated numeric labels that should be rendered as '' on the ends when labels[] are not specified
410 // numericMinimum: Integer
411 // Leftmost label value for generated numeric labels when labels[] are not specified
414 // numericMaximum: Integer
415 // Rightmost label value for generated numeric labels when labels[] are not specified
418 // constraints: object
419 // pattern, places, lang, et al (see dojo.number) for generated numeric labels when labels[] are not specified
420 constraints: {pattern:"#%"},
422 _positionPrefix: '<div class="dijitRuleLabelContainer dijitRuleLabelContainerH" style="left:',
423 _labelPrefix: '"><span class="dijitRuleLabel dijitRuleLabelH">',
424 _suffix: '</span></div>',
426 _calcPosition: function(pos){
430 _genHTML: function(pos, ndx){
431 return this._positionPrefix + this._calcPosition(pos) + this._positionSuffix + this.labelStyle + this._labelPrefix + this.labels[ndx] + this._suffix;
434 getLabels: function(){
435 // summary: user replaceable function to return the labels array
437 // if the labels array was not specified directly, then see if <li> children were
438 var labels = this.labels;
440 // for markup creation, labels are specified as child elements
441 labels = dojo.query("> li", this.srcNodeRef).map(function(node){
442 return String(node.innerHTML);
445 this.srcNodeRef.innerHTML = '';
446 // if the labels were not specified directly and not as <li> children, then calculate numeric labels
447 if(!labels.length && this.count > 1){
448 var start = this.minimum;
449 var inc = (this.maximum - start) / (this.count-1);
450 for (var i=0; i < this.count; i++){
451 labels.push((i<this.numericMargin||i>=(this.count-this.numericMargin))? '' : dojo.number.format(start, this.constraints));
458 postMixInProperties: function(){
459 this.inherited(arguments);
460 this.labels = this.getLabels();
461 this.count = this.labels.length;
465 dojo.declare("dijit.form.VerticalRuleLabels", dijit.form.HorizontalRuleLabels,
468 // Create labels for the Vertical slider
469 templateString: '<div class="dijitRuleContainer dijitRuleContainerV"></div>',
471 _positionPrefix: '<div class="dijitRuleLabelContainer dijitRuleLabelContainerV" style="top:',
472 _labelPrefix: '"><span class="dijitRuleLabel dijitRuleLabelV">',
474 _calcPosition: function(pos){