source: Dev/branches/rest-dojo-ui/client/dojox/mobile/ViewController.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 8.5 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/dom",
9        "dojo/dom-class",
10        "dojo/dom-construct",
11//      "dojo/hash", // optionally prereq'ed
12        "dojo/on",
13        "dojo/ready",
14        "dijit/registry",       // registry.byId
15        "./ProgressIndicator",
16        "./TransitionEvent"
17], function(dojo, array, connect, declare, lang, win, dom, domClass, domConstruct, on, ready, registry, ProgressIndicator, TransitionEvent){
18
19        // module:
20        //              dojox/mobile/ViewController
21        // summary:
22        //              A singleton class that controlls view transition.
23
24        var dm = lang.getObject("dojox.mobile", true);
25
26        var Controller = declare("dojox.mobile.ViewController", null, {
27                // summary:
28                //              A singleton class that controlls view transition.
29                // description:
30                //              This class listens to the "startTransition" events and performs
31                //              view transitions. If the transition destination is an external
32                //              view specified with the url parameter, retrieves the view
33                //              content and parses it to create a new target view.
34
35                constructor: function(){
36                        this.viewMap={};
37                        this.currentView=null;
38                        this.defaultView=null;
39                        ready(lang.hitch(this, function(){
40                                on(win.body(), "startTransition", lang.hitch(this, "onStartTransition"));
41                        }));
42                },
43
44                findCurrentView: function(moveTo,src){
45                        // summary:
46                        //              Searches for the currently showing view.
47                        if(moveTo){
48                                var w = registry.byId(moveTo);
49                                if(w && w.getShowingView){ return w.getShowingView(); }
50                        }
51                        if(dm.currentView){
52                                return dm.currentView; //TODO:1.8 may not return an expected result especially when views are nested
53                        }
54                        //TODO:1.8 probably never reaches here
55                        w = src;
56                        while(true){
57                                w = w.getParent();
58                                if(!w){ return null; }
59                                if(domClass.contains(w.domNode, "mblView")){ break; }
60                        }
61                        return w;
62                },
63
64                onStartTransition: function(evt){
65                        // summary:
66                        //              A handler that performs view transition.
67
68                        evt.preventDefault();
69                        if(!evt.detail || (evt.detail && !evt.detail.moveTo && !evt.detail.href && !evt.detail.url && !evt.detail.scene)){ return; }
70                        var w = this.findCurrentView(evt.detail.moveTo, (evt.target && evt.target.id)?registry.byId(evt.target.id):registry.byId(evt.target)); // the current view widget
71                        if(!w || (evt.detail && evt.detail.moveTo && w === registry.byId(evt.detail.moveTo))){ return; }
72                        if(evt.detail.href){
73                                var t = registry.byId(evt.target.id).hrefTarget;
74                                if(t){
75                                        dm.openWindow(evt.detail.href, t);
76                                }else{
77                                        w.performTransition(null, evt.detail.transitionDir, evt.detail.transition, evt.target, function(){location.href = evt.detail.href;});
78                                }
79                                return;
80                        } else if(evt.detail.scene){
81                                connect.publish("/dojox/mobile/app/pushScene", [evt.detail.scene]);
82                                return;
83                        }
84                        var moveTo = evt.detail.moveTo;
85                        if(evt.detail.url){
86                                var id;
87                                if(dm._viewMap && dm._viewMap[evt.detail.url]){
88                                        // external view has already been loaded
89                                        id = dm._viewMap[evt.detail.url];
90                                }else{
91                                        // get the specified external view and append it to the <body>
92                                        var text = this._text;
93                                        if(!text){
94                                                if(registry.byId(evt.target.id).sync){
95                                                        // We do not add explicit dependency on dojo/_base/xhr to this module
96                                                        // to be able to create a build that does not contain dojo/_base/xhr.
97                                                        // User applications that do sync loading here need to explicitly
98                                                        // require dojo/_base/xhr up front.
99                                                        dojo.xhrGet({url:evt.detail.url, sync:true, load:function(result){
100                                                                text = lang.trim(result);
101                                                        }});
102                                                }else{
103                                                        var s = "dojo/_base/xhr"; // assign to a variable so as not to be picked up by the build tool
104                                                        require([s], lang.hitch(this, function(xhr){
105                                                                var prog = ProgressIndicator.getInstance();
106                                                                win.body().appendChild(prog.domNode);
107                                                                prog.start();
108                                                                var obj = xhr.get({
109                                                                        url: evt.detail.url,
110                                                                        handleAs: "text"
111                                                                });
112                                                                obj.addCallback(lang.hitch(this, function(response, ioArgs){
113                                                                        prog.stop();
114                                                                        if(response){
115                                                                                this._text = response;
116                                                                                new TransitionEvent(evt.target, {
117                                                                                                transition: evt.detail.transition,
118                                                                                                transitionDir: evt.detail.transitionDir,
119                                                                                                moveTo: moveTo,
120                                                                                                href: evt.detail.href,
121                                                                                                url: evt.detail.url,
122                                                                                                scene: evt.detail.scene},
123                                                                                                        evt.detail)
124                                                                                                                .dispatch();
125                                                                        }
126                                                                }));
127                                                                obj.addErrback(function(error){
128                                                                        prog.stop();
129                                                                        console.log("Failed to load "+evt.detail.url+"\n"+(error.description||error));
130                                                                });
131                                                        }));
132                                                        return;
133                                                }
134                                        }
135                                        this._text = null;
136                                        id = this._parse(text, registry.byId(evt.target.id).urlTarget);
137                                        if(!dm._viewMap){
138                                                dm._viewMap = [];
139                                        }
140                                        dm._viewMap[evt.detail.url] = id;
141                                }
142                                moveTo = id;
143                                w = this.findCurrentView(moveTo,registry.byId(evt.target.id)) || w; // the current view widget
144                        }
145                        w.performTransition(moveTo, evt.detail.transitionDir, evt.detail.transition, null, null);
146                },
147
148                _parse: function(text, id){
149                        // summary:
150                        //              Parses the given view content.
151                        // description:
152                        //              If the content is html fragment, constructs dom tree with it
153                        //              and runs the parser. If the content is json data, passes it
154                        //              to _instantiate().
155                        var container, view, i, j, len;
156                        var currentView  = this.findCurrentView();
157                        var target = registry.byId(id) && registry.byId(id).containerNode
158                                                || dom.byId(id)
159                                                || currentView && currentView.domNode.parentNode
160                                                || win.body();
161                        // if a fixed bottom bar exists, a new view should be placed before it.
162                        var refNode = null;
163                        for(j = target.childNodes.length - 1; j >= 0; j--){
164                                var c = target.childNodes[j];
165                                if(c.nodeType === 1){
166                                        if(c.getAttribute("fixed") === "bottom"){
167                                                refNode = c;
168                                        }
169                                        break;
170                                }
171                        }
172                        if(text.charAt(0) === "<"){ // html markup
173                                container = domConstruct.create("DIV", {innerHTML: text});
174                                for(i = 0; i < container.childNodes.length; i++){
175                                        var n = container.childNodes[i];
176                                        if(n.nodeType === 1){
177                                                view = n; // expecting <div dojoType="dojox.mobile.View">
178                                                break;
179                                        }
180                                }
181                                if(!view){
182                                        console.log("dojox.mobile.ViewController#_parse: invalid view content");
183                                        return;
184                                }
185                                view.style.visibility = "hidden";
186                                target.insertBefore(container, refNode);
187                                var ws = dojo.parser.parse(container);
188                                array.forEach(ws, function(w){
189                                        if(w && !w._started && w.startup){
190                                                w.startup();
191                                        }
192                                });
193
194                                // allows multiple root nodes in the fragment,
195                                // but transition will be performed to the 1st view.
196                                for(i = 0, len = container.childNodes.length; i < len; i++){
197                                        target.insertBefore(container.firstChild, refNode); // reparent
198                                }
199                                target.removeChild(container);
200
201                                registry.byNode(view)._visible = true;
202                        }else if(text.charAt(0) === "{"){ // json
203                                container = domConstruct.create("DIV");
204                                target.insertBefore(container, refNode);
205                                this._ws = [];
206                                view = this._instantiate(eval('('+text+')'), container);
207                                for(i = 0; i < this._ws.length; i++){
208                                        var w = this._ws[i];
209                                        w.startup && !w._started && (!w.getParent || !w.getParent()) && w.startup();
210                                }
211                                this._ws = null;
212                        }
213                        view.style.display = "none";
214                        view.style.visibility = "visible";
215                        return dojo.hash ? "#" + view.id : view.id;
216                },
217
218                _instantiate: function(/*Object*/obj, /*DomNode*/node, /*Widget*/parent){
219                        // summary:
220                        //              Given the evaluated json data, does the same thing as what
221                        //              the parser does.
222                        var widget;
223                        for(var key in obj){
224                                if(key.charAt(0) == "@"){ continue; }
225                                var cls = lang.getObject(key);
226                                if(!cls){ continue; }
227                                var params = {};
228                                var proto = cls.prototype;
229                                var objs = lang.isArray(obj[key]) ? obj[key] : [obj[key]];
230                                for(var i = 0; i < objs.length; i++){
231                                        for(var prop in objs[i]){
232                                                if(prop.charAt(0) == "@"){
233                                                        var val = objs[i][prop];
234                                                        prop = prop.substring(1);
235                                                        if(typeof proto[prop] == "string"){
236                                                                params[prop] = val;
237                                                        }else if(typeof proto[prop] == "number"){
238                                                                params[prop] = val - 0;
239                                                        }else if(typeof proto[prop] == "boolean"){
240                                                        params[prop] = (val != "false");
241                                                        }else if(typeof proto[prop] == "object"){
242                                                                params[prop] = eval("(" + val + ")");
243                                                        }
244                                                }
245                                        }
246                                        widget = new cls(params, node);
247                                        if(node){ // to call View's startup()
248                                                widget._visible = true;
249                                                this._ws.push(widget);
250                                        }
251                                        if(parent && parent.addChild){
252                                                parent.addChild(widget);
253                                        }
254                                        this._instantiate(objs[i], null, widget);
255                                }
256                        }
257                        return widget && widget.domNode;
258                }
259        });
260        new Controller(); // singleton
261        return Controller;
262});
263
Note: See TracBrowser for help on using the repository browser.