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

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

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 10.3 KB
Line 
1define([
2        "dojo/_base/array",
3        "dojo/_base/connect",
4        "dojo/_base/declare",
5        "dojo/dom",
6        "dojo/dom-class",
7        "dijit/registry",
8        "./View",
9        "./_ScrollableMixin",
10        "./sniff",
11        "./_css3",
12        "dojo/has!dojo-bidi?dojox/mobile/bidi/SwapView"
13], function(array, connect, declare, dom, domClass, registry, View, ScrollableMixin, has, css3, BidiSwapView){
14
15        // module:
16        //              dojox/mobile/SwapView
17
18        var SwapView = declare(has("dojo-bidi") ? "dojox.mobile.NonBidiSwapView" : "dojox.mobile.SwapView", [View, ScrollableMixin], {
19                // summary:
20                //              A container that can be swiped horizontally.
21                // description:
22                //              SwapView is a container widget which can be swiped horizontally.
23                //              SwapView is a subclass of dojox/mobile/View. It allows the user to
24                //              swipe the screen left or right to move between the views. When
25                //              SwapView is swiped, it finds an adjacent SwapView to open. When
26                //              the transition is done, a topic "/dojox/mobile/viewChanged" is
27                //              published. Note that, to behave properly, the SwapView needs to
28                //              occupy the entire width of the screen.
29
30                /* internal properties */       
31                // scrollDir: [private] String
32                //              Scroll direction, used by dojox/mobile/scrollable (always "f" for this class).
33                scrollDir: "f",
34                // weight: [private] Number
35                //              Frictional weight used to compute scrolling speed.
36                weight: 1.2,
37
38                // _endOfTransitionTimeoutHandle: [private] Object
39                //              The handle (returned by _WidgetBase.defer) for the timeout set on touchEnd in case
40                //      the end of transition event is not fired by the browser.
41                _endOfTransitionTimeoutHandle: null,
42
43                buildRendering: function(){
44                        this.inherited(arguments);
45                        domClass.add(this.domNode, "mblSwapView");
46                        this.setSelectable(this.domNode, false);
47                        this.containerNode = this.domNode;
48                        this.subscribe("/dojox/mobile/nextPage", "handleNextPage");
49                        this.subscribe("/dojox/mobile/prevPage", "handlePrevPage");
50                        this.noResize = true; // not to call resize() from scrollable#init
51                },
52
53                startup: function(){
54                        if(this._started){ return; }
55                        this.inherited(arguments);
56                },
57
58                resize: function(){
59                        // summary:
60                        //              Calls resize() of each child widget.
61                        this.inherited(arguments); // scrollable#resize() will be called
62                        array.forEach(this.getChildren(), function(child){
63                                if(child.resize){ child.resize(); }
64                        });
65                },
66
67                onTouchStart: function(/*Event*/e){
68                        // summary:
69                        //              Internal function to handle touchStart events.
70                        if(this._siblingViewsInMotion()){  // Ignore touchstart if the views are already in motion
71                                this.propagatable ? e.preventDefault() : event.stop(e);
72                                return;
73                        }
74                        var fromTop = this.domNode.offsetTop;
75                        var nextView = this.nextView(this.domNode);
76                        if(nextView){
77                                nextView.stopAnimation();
78                                domClass.add(nextView.domNode, "mblIn");
79                                // Temporarily add padding to align with the fromNode while transition
80                                nextView.containerNode.style.paddingTop = fromTop + "px";
81                        }
82                        var prevView = this.previousView(this.domNode);
83                        if(prevView){
84                                prevView.stopAnimation();
85                                domClass.add(prevView.domNode, "mblIn");
86                                // Temporarily add padding to align with the fromNode while transition
87                                prevView.containerNode.style.paddingTop = fromTop + "px";
88                        }
89                        this._setSiblingViewsInMotion(true);
90                        this.inherited(arguments);
91                },
92
93                onTouchEnd: function(/*Event*/e){
94                        if(e){
95                                if(!this._moved){ // No transition / animation following touchend in this case
96                                        this._setSiblingViewsInMotion(false);
97                                }else{ // There might be a transition / animation following touchend
98                                        // As the webkitTransitionEndEvent is not always fired, make sure we call this._setSiblingViewsInMotion(false) even
99                                        // if the event is not fired (and onFlickAnimationEnd is not called as a result)
100                                        this._endOfTransitionTimeoutHandle = this.defer(function(){
101                                                this._setSiblingViewsInMotion(false);
102                                        }, 1000);
103                                }
104                        }
105                        this.inherited(arguments);
106                },
107
108                handleNextPage: function(/*Widget*/w){
109                        // summary:
110                        //              Called when the "/dojox/mobile/nextPage" topic is published.
111                        var refNode = w.refId && dom.byId(w.refId) || w.domNode;
112                        if(this.domNode.parentNode !== refNode.parentNode){ return; }
113                        if(this.getShowingView() !== this){ return; }
114                        this.goTo(1);
115                },
116
117                handlePrevPage: function(/*Widget*/w){
118                        // summary:
119                        //              Called when the "/dojox/mobile/prevPage" topic is published.
120                        var refNode = w.refId && dom.byId(w.refId) || w.domNode;
121                        if(this.domNode.parentNode !== refNode.parentNode){ return; }
122                        if(this.getShowingView() !== this){ return; }
123                        this.goTo(-1);
124                },
125
126                goTo: function(/*Number*/dir, /*String?*/moveTo){
127                        // summary:
128                        //              Moves to the next or previous view.
129                        var view = moveTo ? registry.byId(moveTo) :
130                                ((dir == 1) ? this.nextView(this.domNode) : this.previousView(this.domNode));
131                        if(view && view !== this){
132                                this.stopAnimation(); // clean-up animation states
133                                view.stopAnimation();
134                                this.domNode._isShowing = false; // update isShowing flag
135                                view.domNode._isShowing = true;
136                                this.performTransition(view.id, dir, "slide", null, function(){
137                                        connect.publish("/dojox/mobile/viewChanged", [view]);
138                                });
139                        }
140                },
141
142                isSwapView: function(/*DomNode*/node){
143                        // summary:
144                        //              Returns true if the given node is a SwapView widget.
145                        return (node && node.nodeType === 1 && domClass.contains(node, "mblSwapView"));
146                },
147
148                nextView: function(/*DomNode*/node){
149                        // summary:
150                        //              Returns the next view.
151                        for(var n = node.nextSibling; n; n = n.nextSibling){
152                                if(this.isSwapView(n)){ return registry.byNode(n); }
153                        }
154                        return null;
155                },
156
157                previousView: function(/*DomNode*/node){
158                        // summary:
159                        //              Returns the previous view.
160                        for(var n = node.previousSibling; n; n = n.previousSibling){
161                                if(this.isSwapView(n)){ return registry.byNode(n); }
162                        }
163                        return null;
164                },
165
166                scrollTo: function(/*Object*/to){
167                        // summary:
168                        //              Overrides dojox/mobile/scrollable.scrollTo().
169                        if(!this._beingFlipped){
170                                var newView, x;
171                                if(to.x){
172                                        if(to.x < 0){
173                                                newView = this.nextView(this.domNode);
174                                                x = to.x + this.domNode.offsetWidth;
175                                        }else{
176                                                newView = this.previousView(this.domNode);
177                                                x = to.x - this.domNode.offsetWidth;
178                                        }
179                                }
180                                if(newView){
181                                        if(newView.domNode.style.display === "none"){
182                                                newView.domNode.style.display = "";
183                                                newView.resize();
184                                        }
185                                        newView._beingFlipped = true;
186                                        newView.scrollTo({x:x});
187                                        newView._beingFlipped = false;
188                                }
189                        }
190                        this.inherited(arguments);
191                },
192
193                findDisp: function(/*DomNode*/node){
194                        // summary:
195                        //              Overrides dojox/mobile/scrollable.findDisp().
196                        // description:
197                        //              When this function is called from scrollable.js, there are
198                        //              two visible views, one is the current view, the other is the
199                        //              next view. This function returns the current view, not the
200                        //              next view, which has the mblIn class.
201                        if(!domClass.contains(node, "mblSwapView")){
202                                return this.inherited(arguments);
203                        }
204                        if(!node.parentNode){ return null; }
205                        var nodes = node.parentNode.childNodes;
206                        for(var i = 0; i < nodes.length; i++){
207                                var n = nodes[i];
208                                if(n.nodeType === 1 && domClass.contains(n, "mblSwapView")
209                                    && !domClass.contains(n, "mblIn") && n.style.display !== "none"){
210                                        return n;
211                                }
212                        }
213                        return node;
214                },
215
216                slideTo: function(/*Object*/to, /*Number*/duration, /*String*/easing, /*Object?*/fake_pos){
217                        // summary:
218                        //              Overrides dojox/mobile/scrollable.slideTo().
219                        if(!this._beingFlipped){
220                                var w = this.domNode.offsetWidth;
221                                var pos = fake_pos || this.getPos();
222                                var newView, newX;
223                                if(pos.x < 0){ // moving to left
224                                        newView = this.nextView(this.domNode);
225                                        if(pos.x < -w/4){ // slide to next
226                                                if(newView){
227                                                        to.x = -w;
228                                                        newX = 0;
229                                                }
230                                        }else{ // go back
231                                                if(newView){
232                                                        newX = w;
233                                                }
234                                        }
235                                }else{ // moving to right
236                                        newView = this.previousView(this.domNode);
237                                        if(pos.x > w/4){ // slide to previous
238                                                if(newView){
239                                                        to.x = w;
240                                                        newX = 0;
241                                                }
242                                        }else{ // go back
243                                                if(newView){
244                                                        newX = -w;
245                                                }
246                                        }
247                                }
248
249                                if(newView){
250                                        newView._beingFlipped = true;
251                                        newView.slideTo({x:newX}, duration, easing);
252                                        newView._beingFlipped = false;
253                                        newView.domNode._isShowing = (newView && newX === 0);
254                                }
255                                this.domNode._isShowing = !(newView && newX === 0);
256                        }
257                        this.inherited(arguments);
258                },
259
260                onAnimationEnd: function(/*Event*/e){
261                        // summary:
262                        //              Overrides dojox/mobile/View.onAnimationEnd().
263                        if(e && e.target && domClass.contains(e.target, "mblScrollableScrollTo2")){ return; }
264                        this.inherited(arguments);
265                },
266
267                onFlickAnimationEnd: function(/*Event*/e){
268                        if(this._endOfTransitionTimeoutHandle){
269                                this._endOfTransitionTimeoutHandle = this._endOfTransitionTimeoutHandle.remove();
270                        }
271                        // summary:
272                        //              Overrides dojox/mobile/scrollable.onFlickAnimationEnd().
273                        if(e && e.target && !domClass.contains(e.target, "mblScrollableScrollTo2")){ return; }
274                        this.inherited(arguments);
275
276                        if(this.domNode._isShowing){
277                                // Hide all the views other than the currently showing one.
278                                // Otherwise, when the orientation is changed, other views
279                                // may appear unexpectedly.
280                                array.forEach(this.domNode.parentNode.childNodes, function(c){
281                                        if(this.isSwapView(c)){
282                                                domClass.remove(c, "mblIn");
283                                                if(!c._isShowing){
284                                                        c.style.display = "none";
285                                                        c.style[css3.name("transform")] = "";
286                                                        c.style.left = "0px"; // top/left mode needs this
287                                                        // reset the temporaty padding on the container node
288                                                        c.style.paddingTop = "";
289                                                }
290                                        }
291                                }, this);
292                                connect.publish("/dojox/mobile/viewChanged", [this]);
293                                // Reset the temporary padding
294                                this.containerNode.style.paddingTop = "";
295                        }else if(!has("css3-animations")){
296                                this.containerNode.style.left = "0px"; // compat mode needs this
297                        }
298                        this._setSiblingViewsInMotion(false);
299                },
300
301                _setSiblingViewsInMotion: function(/*Boolean*/inMotion){
302                        var inMotionAttributeValue = inMotion ? "true" : false;
303                        var parent = this.domNode.parentNode;
304                        if(parent){
305                                parent.setAttribute("data-dojox-mobile-swapview-inmotion", inMotionAttributeValue);
306                        }
307                },
308
309                _siblingViewsInMotion: function(){
310                        var parent = this.domNode.parentNode;
311                        if(parent){
312                                return parent.getAttribute("data-dojox-mobile-swapview-inmotion") == "true";
313                        }else{
314                                return false;
315                        }
316                }
317        });
318        return has("dojo-bidi") ? declare("dojox.mobile.SwapView", [SwapView, BidiSwapView]) : SwapView;
319});
Note: See TracBrowser for help on using the repository browser.