]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/form/HorizontalSlider.js
upgrade Dojo to 1.6.1
[tt-rss.git] / lib / dijit / form / HorizontalSlider.js
1 /*
2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
5 */
6
7
8 if(!dojo._hasResource["dijit.form.HorizontalSlider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9 dojo._hasResource["dijit.form.HorizontalSlider"] = true;
10 dojo.provide("dijit.form.HorizontalSlider");
11 dojo.require("dijit.form._FormWidget");
12 dojo.require("dijit._Container");
13 dojo.require("dojo.dnd.move");
14 dojo.require("dijit.form.Button");
15 dojo.require("dojo.number");
16
17
18 dojo.declare(
19 "dijit.form.HorizontalSlider",
20 [dijit.form._FormValueWidget, dijit._Container],
21 {
22 // summary:
23 // A form widget that allows one to select a value with a horizontally draggable handle
24
25 templateString: dojo.cache("dijit.form", "templates/HorizontalSlider.html", "<table class=\"dijit dijitReset dijitSlider dijitSliderH\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" dojoAttachEvent=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></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\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><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\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onmousedown:_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\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><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 dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\n"),
26
27 // Overrides FormValueWidget.value to indicate numeric value
28 value: 0,
29
30 // showButtons: [const] Boolean
31 // Show increment/decrement buttons at the ends of the slider?
32 showButtons: true,
33
34 // minimum:: [const] Integer
35 // The minimum value the slider can be set to.
36 minimum: 0,
37
38 // maximum: [const] Integer
39 // The maximum value the slider can be set to.
40 maximum: 100,
41
42 // discreteValues: Integer
43 // If specified, indicates that the slider handle has only 'discreteValues' possible positions,
44 // and that after dragging the handle, it will snap to the nearest possible position.
45 // Thus, the slider has only 'discreteValues' possible values.
46 //
47 // For example, if minimum=10, maxiumum=30, and discreteValues=3, then the slider handle has
48 // three possible positions, representing values 10, 20, or 30.
49 //
50 // If discreteValues is not specified or if it's value is higher than the number of pixels
51 // in the slider bar, then the slider handle can be moved freely, and the slider's value will be
52 // computed/reported based on pixel position (in this case it will likely be fractional,
53 // such as 123.456789).
54 discreteValues: Infinity,
55
56 // pageIncrement: Integer
57 // If discreteValues is also specified, this indicates the amount of clicks (ie, snap positions)
58 // that the slider handle is moved via pageup/pagedown keys.
59 // If discreteValues is not specified, it indicates the number of pixels.
60 pageIncrement: 2,
61
62 // clickSelect: Boolean
63 // If clicking the slider bar changes the value or not
64 clickSelect: true,
65
66 // slideDuration: Number
67 // The time in ms to take to animate the slider handle from 0% to 100%,
68 // when clicking the slider bar to make the handle move.
69 slideDuration: dijit.defaultDuration,
70
71 // Flag to _Templated (TODO: why is this here? I see no widgets in the template.)
72 widgetsInTemplate: true,
73
74 attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
75 id: ""
76 }),
77
78 baseClass: "dijitSlider",
79
80 // Apply CSS classes to up/down arrows and handle per mouse state
81 cssStateNodes: {
82 incrementButton: "dijitSliderIncrementButton",
83 decrementButton: "dijitSliderDecrementButton",
84 focusNode: "dijitSliderThumb"
85 },
86
87 _mousePixelCoord: "pageX",
88 _pixelCount: "w",
89 _startingPixelCoord: "x",
90 _startingPixelCount: "l",
91 _handleOffsetCoord: "left",
92 _progressPixelSize: "width",
93
94 _onKeyUp: function(/*Event*/ e){
95 if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
96 this._setValueAttr(this.value, true);
97 },
98
99 _onKeyPress: function(/*Event*/ e){
100 if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
101 switch(e.charOrCode){
102 case dojo.keys.HOME:
103 this._setValueAttr(this.minimum, false);
104 break;
105 case dojo.keys.END:
106 this._setValueAttr(this.maximum, false);
107 break;
108 // this._descending === false: if ascending vertical (min on top)
109 // (this._descending || this.isLeftToRight()): if left-to-right horizontal or descending vertical
110 case ((this._descending || this.isLeftToRight()) ? dojo.keys.RIGHT_ARROW : dojo.keys.LEFT_ARROW):
111 case (this._descending === false ? dojo.keys.DOWN_ARROW : dojo.keys.UP_ARROW):
112 case (this._descending === false ? dojo.keys.PAGE_DOWN : dojo.keys.PAGE_UP):
113 this.increment(e);
114 break;
115 case ((this._descending || this.isLeftToRight()) ? dojo.keys.LEFT_ARROW : dojo.keys.RIGHT_ARROW):
116 case (this._descending === false ? dojo.keys.UP_ARROW : dojo.keys.DOWN_ARROW):
117 case (this._descending === false ? dojo.keys.PAGE_UP : dojo.keys.PAGE_DOWN):
118 this.decrement(e);
119 break;
120 default:
121 return;
122 }
123 dojo.stopEvent(e);
124 },
125
126 _onHandleClick: function(e){
127 if(this.disabled || this.readOnly){ return; }
128 if(!dojo.isIE){
129 // make sure you get focus when dragging the handle
130 // (but don't do on IE because it causes a flicker on mouse up (due to blur then focus)
131 dijit.focus(this.sliderHandle);
132 }
133 dojo.stopEvent(e);
134 },
135
136 _isReversed: function(){
137 // summary:
138 // Returns true if direction is from right to left
139 // tags:
140 // protected extension
141 return !this.isLeftToRight();
142 },
143
144 _onBarClick: function(e){
145 if(this.disabled || this.readOnly || !this.clickSelect){ return; }
146 dijit.focus(this.sliderHandle);
147 dojo.stopEvent(e);
148 var abspos = dojo.position(this.sliderBarContainer, true);
149 var pixelValue = e[this._mousePixelCoord] - abspos[this._startingPixelCoord];
150 this._setPixelValue(this._isReversed() ? (abspos[this._pixelCount] - pixelValue) : pixelValue, abspos[this._pixelCount], true);
151 this._movable.onMouseDown(e);
152 },
153
154 _setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean?*/ priorityChange){
155 if(this.disabled || this.readOnly){ return; }
156 pixelValue = pixelValue < 0 ? 0 : maxPixels < pixelValue ? maxPixels : pixelValue;
157 var count = this.discreteValues;
158 if(count <= 1 || count == Infinity){ count = maxPixels; }
159 count--;
160 var pixelsPerValue = maxPixels / count;
161 var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
162 this._setValueAttr((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, priorityChange);
163 },
164
165 _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
166 // summary:
167 // Hook so set('value', value) works.
168 this._set("value", value);
169 this.valueNode.value = value;
170 dijit.setWaiState(this.focusNode, "valuenow", value);
171 this.inherited(arguments);
172 var percent = (value - this.minimum) / (this.maximum - this.minimum);
173 var progressBar = (this._descending === false) ? this.remainingBar : this.progressBar;
174 var remainingBar = (this._descending === false) ? this.progressBar : this.remainingBar;
175 if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
176 this._inProgressAnim.stop(true);
177 }
178 if(priorityChange && this.slideDuration > 0 && progressBar.style[this._progressPixelSize]){
179 // animate the slider
180 var _this = this;
181 var props = {};
182 var start = parseFloat(progressBar.style[this._progressPixelSize]);
183 var duration = this.slideDuration * (percent-start/100);
184 if(duration == 0){ return; }
185 if(duration < 0){ duration = 0 - duration; }
186 props[this._progressPixelSize] = { start: start, end: percent*100, units:"%" };
187 this._inProgressAnim = dojo.animateProperty({ node: progressBar, duration: duration,
188 onAnimate: function(v){ remainingBar.style[_this._progressPixelSize] = (100-parseFloat(v[_this._progressPixelSize])) + "%"; },
189 onEnd: function(){ delete _this._inProgressAnim; },
190 properties: props
191 })
192 this._inProgressAnim.play();
193 }else{
194 progressBar.style[this._progressPixelSize] = (percent*100) + "%";
195 remainingBar.style[this._progressPixelSize] = ((1-percent)*100) + "%";
196 }
197 },
198
199 _bumpValue: function(signedChange, /*Boolean?*/ priorityChange){
200 if(this.disabled || this.readOnly){ return; }
201 var s = dojo.getComputedStyle(this.sliderBarContainer);
202 var c = dojo._getContentBox(this.sliderBarContainer, s);
203 var count = this.discreteValues;
204 if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; }
205 count--;
206 var value = (this.value - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
207 if(value < 0){ value = 0; }
208 if(value > count){ value = count; }
209 value = value * (this.maximum - this.minimum) / count + this.minimum;
210 this._setValueAttr(value, priorityChange);
211 },
212
213 _onClkBumper: function(val){
214 if(this.disabled || this.readOnly || !this.clickSelect){ return; }
215 this._setValueAttr(val, true);
216 },
217
218 _onClkIncBumper: function(){
219 this._onClkBumper(this._descending === false ? this.minimum : this.maximum);
220 },
221
222 _onClkDecBumper: function(){
223 this._onClkBumper(this._descending === false ? this.maximum : this.minimum);
224 },
225
226 decrement: function(/*Event*/ e){
227 // summary:
228 // Decrement slider
229 // tags:
230 // private
231 this._bumpValue(e.charOrCode == dojo.keys.PAGE_DOWN ? -this.pageIncrement : -1);
232 },
233
234 increment: function(/*Event*/ e){
235 // summary:
236 // Increment slider
237 // tags:
238 // private
239 this._bumpValue(e.charOrCode == dojo.keys.PAGE_UP ? this.pageIncrement : 1);
240 },
241
242 _mouseWheeled: function(/*Event*/ evt){
243 // summary:
244 // Event handler for mousewheel where supported
245 dojo.stopEvent(evt);
246 var janky = !dojo.isMozilla;
247 var scroll = evt[(janky ? "wheelDelta" : "detail")] * (janky ? 1 : -1);
248 this._bumpValue(scroll < 0 ? -1 : 1, true); // negative scroll acts like a decrement
249 },
250
251 startup: function(){
252 if(this._started){ return; }
253
254 dojo.forEach(this.getChildren(), function(child){
255 if(this[child.container] != this.containerNode){
256 this[child.container].appendChild(child.domNode);
257 }
258 }, this);
259
260 this.inherited(arguments);
261 },
262
263 _typematicCallback: function(/*Number*/ count, /*Object*/ button, /*Event*/ e){
264 if(count == -1){
265 this._setValueAttr(this.value, true);
266 }else{
267 this[(button == (this._descending? this.incrementButton : this.decrementButton)) ? "decrement" : "increment"](e);
268 }
269 },
270
271 buildRendering: function(){
272 this.inherited(arguments);
273 if(this.showButtons){
274 this.incrementButton.style.display="";
275 this.decrementButton.style.display="";
276 }
277
278 // find any associated label element and add to slider focusnode.
279 var label = dojo.query('label[for="'+this.id+'"]');
280 if(label.length){
281 label[0].id = (this.id+"_label");
282 dijit.setWaiState(this.focusNode, "labelledby", label[0].id);
283 }
284
285 dijit.setWaiState(this.focusNode, "valuemin", this.minimum);
286 dijit.setWaiState(this.focusNode, "valuemax", this.maximum);
287 },
288
289 postCreate: function(){
290 this.inherited(arguments);
291
292 if(this.showButtons){
293 this._connects.push(dijit.typematic.addMouseListener(
294 this.decrementButton, this, "_typematicCallback", 25, 500));
295 this._connects.push(dijit.typematic.addMouseListener(
296 this.incrementButton, this, "_typematicCallback", 25, 500));
297 }
298 this.connect(this.domNode, !dojo.isMozilla ? "onmousewheel" : "DOMMouseScroll", "_mouseWheeled");
299
300 // define a custom constructor for a SliderMover that points back to me
301 var mover = dojo.declare(dijit.form._SliderMover, {
302 widget: this
303 });
304 this._movable = new dojo.dnd.Moveable(this.sliderHandle, {mover: mover});
305
306 this._layoutHackIE7();
307 },
308
309 destroy: function(){
310 this._movable.destroy();
311 if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
312 this._inProgressAnim.stop(true);
313 }
314 this._supportingWidgets = dijit.findWidgets(this.domNode); // tells destroy about pseudo-child widgets (ruler/labels)
315 this.inherited(arguments);
316 }
317 });
318
319 dojo.declare("dijit.form._SliderMover",
320 dojo.dnd.Mover,
321 {
322 onMouseMove: function(e){
323 var widget = this.widget;
324 var abspos = widget._abspos;
325 if(!abspos){
326 abspos = widget._abspos = dojo.position(widget.sliderBarContainer, true);
327 widget._setPixelValue_ = dojo.hitch(widget, "_setPixelValue");
328 widget._isReversed_ = widget._isReversed();
329 }
330 var coordEvent = e.touches ? e.touches[0] : e, // if multitouch take first touch for coords
331 pixelValue = coordEvent[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
332 widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false);
333 },
334
335 destroy: function(e){
336 dojo.dnd.Mover.prototype.destroy.apply(this, arguments);
337 var widget = this.widget;
338 widget._abspos = null;
339 widget._setValueAttr(widget.value, true);
340 }
341 });
342
343 }