source: Dev/trunk/src/client/dojox/mobile/ViewController.js @ 531

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

Added Dojo 1.9.3 release.

File size: 8.6 KB
Line 
1define([
2        "dojo/_base/kernel",
3        "dojo/_base/array",
4        "dojo/_base/connect",
5        "dojo/_base/declare",
6        "dojo/_base/lang",
7        "dojo/_base/window",
8        "dojo/_base/Deferred",
9        "dojo/dom",
10        "dojo/dom-class",
11        "dojo/dom-construct",
12        "dojo/on",
13        "dojo/ready",
14        "dijit/registry",
15        "./ProgressIndicator",
16        "./TransitionEvent",
17        "./viewRegistry"
18], function(dojo, array, connect, declare, lang, win, Deferred, dom, domClass, domConstruct, on, ready, registry, ProgressIndicator, TransitionEvent, viewRegistry){
19
20        // module:
21        //              dojox/mobile/ViewController
22
23        var Controller = declare("dojox.mobile.ViewController", null, {
24                // summary:
25                //              A singleton class that controls view transition.
26                // description:
27                //              This class listens to the "startTransition" events and performs
28                //              view transitions. If the transition destination is an external
29                //              view specified with the url parameter, the view content is
30                //              retrieved and parsed to create a new target view.
31
32                // dataHandlerClass: Object
33                //              The data handler class used to load external views,
34                //              by default "dojox/mobile/dh/DataHandler"
35                //              (see the Data Handlers page in the reference documentation).
36                dataHandlerClass: "dojox/mobile/dh/DataHandler",
37                // dataSourceClass: Object
38                //              The data source class used to load external views,
39                //              by default "dojox/mobile/dh/UrlDataSource"
40                //              (see the Data Handlers page in the reference documentation).
41                dataSourceClass: "dojox/mobile/dh/UrlDataSource",
42                // fileTypeMapClass: Object
43                //              The file type map class used to load external views,
44                //              by default "dojox/mobile/dh/SuffixFileTypeMap"
45                //              (see the Data Handlers page in the reference documentation).
46                fileTypeMapClass: "dojox/mobile/dh/SuffixFileTypeMap",
47
48                constructor: function(){
49                        // summary:
50                        //              Creates a new instance of the class.
51                        // tags:
52                        //              private
53                        this.viewMap = {};
54                        ready(lang.hitch(this, function(){
55                                on(win.body(), "startTransition", lang.hitch(this, "onStartTransition"));
56                        }));
57                },
58
59                findTransitionViews: function(/*String*/moveTo){
60                        // summary:
61                        //              Parses the moveTo argument and determines a starting view and a destination view.
62                        // returns: Array
63                        //              An array containing the currently showing view, the destination view
64                        //              and the transition parameters, or an empty array if the moveTo argument
65                        //              could not be parsed.
66                        if(!moveTo){ return []; }
67                        // removes a leading hash mark (#) and params if exists
68                        // ex. "#bar&myParam=0003" -> "bar"
69                        moveTo.match(/^#?([^&?]+)(.*)/);
70                        var params = RegExp.$2;
71                        var view = registry.byId(RegExp.$1);
72                        if(!view){ return []; }
73                        for(var v = view.getParent(); v; v = v.getParent()){ // search for the topmost invisible parent node
74                                if(v.isVisible && !v.isVisible()){
75                                        var sv = view.getShowingView();
76                                        if(sv && sv.id !== view.id){
77                                                view.show();
78                                        }
79                                        view = v;
80                                }
81                        }
82                        return [view.getShowingView(), view, params]; // fromView, toView, params
83                },
84
85                openExternalView: function(/*Object*/ transOpts, /*DomNode*/ target){
86                        // summary:
87                        //              Loads an external view and performs a transition to it.
88                        // returns: dojo/_base/Deferred
89                        //              Deferred object that resolves when the external view is
90                        //              ready and a transition starts. Note that it resolves before
91                        //              the transition is complete.
92                        // description:
93                        //              This method loads external view content through the
94                        //              dojox/mobile data handlers, creates a new View instance with
95                        //              the loaded content, and performs a view transition to the
96                        //              new view. The external view content can be specified with
97                        //              the url property of transOpts. The new view is created under
98                        //              a DOM node specified by target.
99                        //
100                        // example:
101                        //              This example loads view1.html, creates a new view under
102                        //              `<body>`, and performs a transition to the new view with the
103                        //              slide animation.
104                        //             
105                        //      |       var vc = ViewController.getInstance();
106                        //      |       vc.openExternalView({
107                        //      |           url: "view1.html",
108                        //      |           transition: "slide"
109                        //      |       }, win.body());
110                        //
111                        //
112                        // example:
113                        //              If you want to perform a view transition without animation,
114                        //              you can give transition:"none" to transOpts.
115                        //
116                        //      |       var vc = ViewController.getInstance();
117                        //      |       vc.openExternalView({
118                        //      |           url: "view1.html",
119                        //      |           transition: "none"
120                        //      |       }, win.body());
121                        //
122                        // example:
123                        //              If you want to dynamically create an external view, but do
124                        //              not want to perform a view transition to it, you can give noTransition:true to transOpts.
125                        //              This may be useful when you want to preload external views before the user starts using them.
126                        //
127                        //      |       var vc = ViewController.getInstance();
128                        //      |       vc.openExternalView({
129                        //      |           url: "view1.html",
130                        //      |           noTransition: true
131                        //      |       }, win.body());
132                        //
133                        // example:
134                        //              To do something when the external view is ready:
135                        //
136                        //      |       var vc = ViewController.getInstance();
137                        //      |       Deferred.when(vc.openExternalView({...}, win.body()), function(){
138                        //      |           doSomething();
139                        //      |       });
140
141                        var d = new Deferred();
142                        var id = this.viewMap[transOpts.url];
143                        if(id){
144                                transOpts.moveTo = id;
145                                if(transOpts.noTransition){
146                                        registry.byId(id).hide();
147                                }else{
148                                        new TransitionEvent(win.body(), transOpts).dispatch();
149                                }
150                                d.resolve(true);
151                                return d;
152                        }
153
154                        // if a fixed bottom bar exists, a new view should be placed before it.
155                        var refNode = null;
156                        for(var i = target.childNodes.length - 1; i >= 0; i--){
157                                var c = target.childNodes[i];
158                                if(c.nodeType === 1){
159                                        var fixed = c.getAttribute("fixed") // TODO: Remove the non-HTML5-compliant attribute in 2.0
160                                                || c.getAttribute("data-mobile-fixed")
161                                                || (registry.byNode(c) && registry.byNode(c).fixed);
162                                        if(fixed === "bottom"){
163                                                refNode = c;
164                                                break;
165                                        }
166                                }
167                        }
168
169                        var dh = transOpts.dataHandlerClass || this.dataHandlerClass;
170                        var ds = transOpts.dataSourceClass || this.dataSourceClass;
171                        var ft = transOpts.fileTypeMapClass || this.fileTypeMapClass;
172                        require([dh, ds, ft], lang.hitch(this, function(DataHandler, DataSource, FileTypeMap){
173                                var handler = new DataHandler(new DataSource(transOpts.data || transOpts.url), target, refNode);
174                                var contentType = transOpts.contentType || FileTypeMap.getContentType(transOpts.url) || "html";
175                                handler.processData(contentType, lang.hitch(this, function(id){
176                                        if(id){
177                                                this.viewMap[transOpts.url] = transOpts.moveTo = id;
178                                                if(transOpts.noTransition){
179                                                        registry.byId(id).hide();
180                                                }else{
181                                                        new TransitionEvent(win.body(), transOpts).dispatch();
182                                                }
183                                                d.resolve(true);
184                                        }else{
185                                                d.reject("Failed to load "+transOpts.url);
186                                        }
187                                }));
188                        }));
189                        return d;
190                },
191
192                onStartTransition: function(evt){
193                        // summary:
194                        //              A handler that performs view transition.
195                        evt.preventDefault();
196                        if(!evt.detail){ return; }
197                        var detail = evt.detail;
198                        if(!detail.moveTo && !detail.href && !detail.url && !detail.scene){ return; }
199
200                        if(detail.url && !detail.moveTo){
201                                var urlTarget = detail.urlTarget;
202                                var w = registry.byId(urlTarget);
203                                var target = w && w.containerNode || dom.byId(urlTarget);
204                                if(!target){
205                                        w = viewRegistry.getEnclosingView(evt.target);
206                                        target = w && w.domNode.parentNode || win.body();
207                                }
208                                this.openExternalView(detail, target);
209                                return;
210                        }else if(detail.href){
211                                if(detail.hrefTarget && detail.hrefTarget != "_self"){
212                                        win.global.open(detail.href, detail.hrefTarget);
213                                }else{
214                                        var view; // find top level visible view
215                                        for(var v = viewRegistry.getEnclosingView(evt.target); v; v = viewRegistry.getParentView(v)){
216                                                view = v;
217                                        }
218                                        if(view){
219                                                view.performTransition(null, detail.transitionDir, detail.transition, evt.target, function(){location.href = detail.href;});
220                                        }
221                                }
222                                return;
223                        }else if(detail.scene){
224                                connect.publish("/dojox/mobile/app/pushScene", [detail.scene]);
225                                return;
226                        }
227
228                        var arr = this.findTransitionViews(detail.moveTo),
229                                fromView = arr[0],
230                                toView = arr[1],
231                                params = arr[2];
232                        if(!location.hash && !detail.hashchange){
233                                viewRegistry.initialView = fromView;
234                        }
235                        if(detail.moveTo && toView){
236                                detail.moveTo = (detail.moveTo.charAt(0) === '#' ? '#' + toView.id : toView.id) + params;
237                        }
238                        if(!fromView || (detail.moveTo && fromView === registry.byId(detail.moveTo.replace(/^#?([^&?]+).*/, "$1")))){ return; }
239                        var src = registry.getEnclosingWidget(evt.target);
240                        if(src && src.callback){
241                                detail.context = src;
242                                detail.method = src.callback;
243                        }
244                        fromView.performTransition(detail);
245                }
246        });
247        Controller._instance = new Controller(); // singleton
248        Controller.getInstance = function(){
249                return Controller._instance;
250        };
251        return Controller;
252});
253
Note: See TracBrowser for help on using the repository browser.