source: Dev/trunk/src/client/dojox/mobile/Slider.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 8.1 KB
Line 
1define([
2        "dojo/_base/array",
3        "dojo/_base/connect",
4        "dojo/_base/declare",
5        "dojo/_base/lang",
6        "dojo/_base/window",
7        "dojo/sniff",
8        "dojo/dom-class",
9        "dojo/dom-construct",
10        "dojo/dom-geometry",
11        "dojo/dom-style",
12        "dojo/keys",
13        "dojo/touch",
14        "dijit/_WidgetBase",
15        "dijit/form/_FormValueMixin"
16],
17        function(array, connect, declare, lang, win, has, domClass, domConstruct, domGeometry, domStyle, keys, touch, WidgetBase, FormValueMixin){
18
19        return declare("dojox.mobile.Slider", [WidgetBase, FormValueMixin], {
20                // summary:
21                //              A non-templated Slider widget similar to the HTML5 INPUT type=range.
22
23                // value: [const] Number
24                //              The current slider value.
25                value: 0,
26
27                // min: [const] Number
28                //              The first value the slider can be set to.
29                min: 0,
30
31                // max: [const] Number
32                //              The last value the slider can be set to.
33                max: 100,
34
35                // step: [const] Number
36                //              The delta from 1 value to another.
37                //              This causes the slider handle to snap/jump to the closest possible value.
38                //              A value of 0 means continuous (as much as allowed by pixel resolution).
39                step: 1,
40
41                // baseClass: String
42                //              The name of the CSS class of this widget.
43                baseClass: "mblSlider",
44
45                // flip: [const] Boolean
46                //              Specifies if the slider should change its default: ascending <--> descending.
47                flip: false,
48
49                // orientation: [const] String
50                //              The slider direction.
51                //
52                //              - "H": horizontal
53                //              - "V": vertical
54                //              - "auto": use width/height comparison at instantiation time (default is "H" if width/height are 0)
55                orientation: "auto",
56
57                // halo: Number
58                //              Size of the boundary that extends beyond the edges of the slider
59                //              to make it easier to touch.
60                halo: "8pt",
61
62                buildRendering: function(){
63                        if(!this.templateString){ // true if this widget is not templated
64                                this.focusNode = this.domNode = domConstruct.create("div", {});
65                                this.valueNode = domConstruct.create("input", (this.srcNodeRef && this.srcNodeRef.name) ? { type: "hidden", name: this.srcNodeRef.name } : { type: "hidden" }, this.domNode, "last");
66                                var relativeParent = domConstruct.create("div", { style: { position:"relative", height:"100%", width:"100%" } }, this.domNode, "last");
67                                this.progressBar = domConstruct.create("div", { style:{ position:"absolute" }, "class":"mblSliderProgressBar" }, relativeParent, "last");
68                                this.touchBox = domConstruct.create("div", { style:{ position:"absolute" }, "class":"mblSliderTouchBox" }, relativeParent, "last");
69                                this.handle = domConstruct.create("div", { style:{ position:"absolute" }, "class":"mblSliderHandle" }, relativeParent, "last");
70                        }
71                        this.inherited(arguments);
72                        // prevent browser scrolling on IE10 (evt.preventDefault() is not enough)
73                        if(typeof this.domNode.style.msTouchAction != "undefined"){
74                                this.domNode.style.msTouchAction = "none";
75                        }
76                },
77
78                _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
79                        // summary:
80                        //              Hook such that set('value', value) works.
81                        // tags:
82                        //              private
83                        value = Math.max(Math.min(value, this.max), this.min);
84                        var fromPercent = (this.value - this.min) * 100 / (this.max - this.min);
85                        this.valueNode.value = value;
86                        this.inherited(arguments);
87                        if(!this._started){ return; } // don't move images until all the properties are set
88                        this.focusNode.setAttribute("aria-valuenow", value);
89                        var toPercent = (value - this.min) * 100 / (this.max - this.min);
90                        // now perform visual slide
91                        var horizontal = this.orientation != "V";
92                        if(priorityChange === true){
93                                domClass.add(this.handle, "mblSliderTransition");
94                                domClass.add(this.progressBar, "mblSliderTransition");
95                        }else{
96                                domClass.remove(this.handle, "mblSliderTransition");
97                                domClass.remove(this.progressBar, "mblSliderTransition");
98                        }
99                        domStyle.set(this.handle, this._attrs.handleLeft, (this._reversed ? (100-toPercent) : toPercent) + "%");
100                        domStyle.set(this.progressBar, this._attrs.width, toPercent + "%");
101                },
102
103                postCreate: function(){
104                        this.inherited(arguments);
105
106                        function beginDrag(e){
107                                function getEventData(e){
108                                        point = isMouse ? e[this._attrs.pageX] : (e.touches ? e.touches[0][this._attrs.pageX] : e[this._attrs.clientX]);
109                                        pixelValue = point - startPixel;
110                                        pixelValue = Math.min(Math.max(pixelValue, 0), maxPixels);
111                                        var discreteValues = this.step ? ((this.max - this.min) / this.step) : maxPixels;
112                                        if(discreteValues <= 1 || discreteValues == Infinity ){ discreteValues = maxPixels; }
113                                        var wholeIncrements = Math.round(pixelValue * discreteValues / maxPixels);
114                                        value = (this.max - this.min) * wholeIncrements / discreteValues;
115                                        value = this._reversed ? (this.max - value) : (this.min + value);
116                                }
117                                function continueDrag(e){
118                                        e.preventDefault();
119                                        lang.hitch(this, getEventData)(e);
120                                        this.set('value', value, false);
121                                }
122               
123                                function endDrag(e){
124                                        e.preventDefault();
125                                        array.forEach(actionHandles, lang.hitch(this, "disconnect"));
126                                        actionHandles = [];
127                                        this.set('value', this.value, true);
128                                }
129
130                                e.preventDefault();
131                                var isMouse = e.type == "mousedown";
132                                var box = domGeometry.position(node, false); // can't use true since the added docScroll and the returned x are body-zoom incompatibile
133                                var bodyZoom = (has("ie") || has("trident") > 6) ? 1 : (domStyle.get(win.body(), "zoom") || 1);
134                                if(isNaN(bodyZoom)){ bodyZoom = 1; }
135                                var nodeZoom = (has("ie") || has("trident") > 6) ? 1 : (domStyle.get(node, "zoom") || 1);
136                                if(isNaN(nodeZoom)){ nodeZoom = 1; }
137                                var startPixel = box[this._attrs.x] * nodeZoom * bodyZoom + domGeometry.docScroll()[this._attrs.x];
138                                var maxPixels = box[this._attrs.w] * nodeZoom * bodyZoom;
139                                lang.hitch(this, getEventData)(e);
140                                if(e.target == this.touchBox){
141                                        this.set('value', value, true);
142                                }
143                                array.forEach(actionHandles, connect.disconnect);
144                                var root = win.doc.documentElement;
145                                var actionHandles = [
146                                        this.connect(root, touch.move, continueDrag),
147                                        this.connect(root, touch.release, endDrag)
148                                ];
149                        }
150
151                        function keyPress(/*Event*/ e){
152                                if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
153                                var     step = this.step,
154                                        multiplier = 1,
155                                        newValue;
156                                switch(e.keyCode){
157                                        case keys.HOME:
158                                                newValue = this.min;
159                                                break;
160                                        case keys.END:
161                                                newValue = this.max;
162                                                break;
163                                        case keys.RIGHT_ARROW:
164                                                multiplier = -1;
165                                        case keys.LEFT_ARROW:
166                                                newValue = this.value + multiplier * ((flip && horizontal) ? step : -step);
167                                                break;
168                                        case keys.DOWN_ARROW:
169                                                multiplier = -1;
170                                        case keys.UP_ARROW:
171                                                newValue = this.value + multiplier * ((!flip || horizontal) ? step : -step);
172                                                break;
173                                        default:
174                                                return;
175                                }
176                                e.preventDefault();
177                                this._setValueAttr(newValue, false);
178                        }
179
180                        function keyUp(/*Event*/ e){
181                                if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
182                                this._setValueAttr(this.value, true);
183                        }
184
185                        var     point, pixelValue, value,
186                                node = this.domNode;
187                        if(this.orientation == "auto"){
188                                 this.orientation = node.offsetHeight <= node.offsetWidth ? "H" : "V";
189                        }
190                        // add V or H suffix to baseClass for styling purposes
191                        domClass.add(this.domNode, array.map(this.baseClass.split(" "), lang.hitch(this, function(c){ return c+this.orientation; })));
192                        var     horizontal = this.orientation != "V",
193                                ltr = horizontal ? this.isLeftToRight() : false,
194                                flip = !!this.flip;
195                        // _reversed is complicated since you can have flipped right-to-left and vertical is upside down by default
196                        this._reversed = !((horizontal && ((ltr && !flip) || (!ltr && flip))) || (!horizontal && flip));
197                        this._attrs = horizontal ? { x:'x', w:'w', l:'l', r:'r', pageX:'pageX', clientX:'clientX', handleLeft:"left", left:this._reversed ? "right" : "left", width:"width" } : { x:'y', w:'h', l:'t', r:'b', pageX:'pageY', clientX:'clientY', handleLeft:"top", left:this._reversed ? "bottom" : "top", width:"height" };
198                        this.progressBar.style[this._attrs.left] = "0px";
199                        this.connect(this.touchBox, touch.press, beginDrag);
200                        this.connect(this.handle, touch.press, beginDrag);
201                        this.connect(this.domNode, "onkeypress", keyPress); // for desktop a11y
202                        this.connect(this.domNode, "onkeyup", keyUp); // fire onChange on desktop
203                        this.startup();
204                        this.set('value', this.value);
205                }
206        });
207});
Note: See TracBrowser for help on using the repository browser.