source: Dev/trunk/src/client/dojox/mobile/dh/JsonContentHandler.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: 6.7 KB
Line 
1define([
2        "dojo/_base/kernel",
3        "dojo/_base/array",
4        "dojo/_base/declare",
5        "dojo/_base/lang",
6        "dojo/_base/Deferred",
7        "dojo/json",
8        "dojo/dom-construct"
9], function(dojo, array, declare, lang, Deferred, json, domConstruct){
10
11        // module:
12        //              dojox/mobile/dh/JsonContentHandler
13
14        return declare("dojox.mobile.dh.JsonContentHandler", null, {
15                // summary:
16                //              A JSON content handler.
17                // description:
18                //              This module is a content handler that creates a view from JSON
19                //              data. If widgets used in the JSON data are not available, they
20                //              are loaded automatically before instantiation.
21                //
22                //              There are two formats as shown in the examples below. You can
23                //              choose either of them. The v1.7 format can be more compact, but
24                //              if you want multiple widgets at the same level, they must be in
25                //              an array. So, you can have, for example, two consecutive
26                //              RoundRectLists, but you cannot have, for example,
27                //              RoundRectCategory, RoundRectList, RoundRectCategory, and
28                //              RoundRectList, because they are keys in one JS object, which
29                //              causes conflict. The v1.8 format has no such limitation.
30                //
31                // example:
32                //      |       // v1.7 format
33                //      |       {
34                //      |         "dojox.mobile.View": {
35                //      |           "@id": "view1",
36                //      |           "dojox.mobile.Heading": {
37                //      |             "@back": "Home",
38                //      |             "@moveTo": "home",
39                //      |             "@label": "view1.json"
40                //      |           },
41                //      |           "dojox.mobile.EdgeToEdgeList": {
42                //      |             "dojox.mobile.ListItem": [{
43                //      |               "@label": "Jack Coleman"
44                //      |             }, {
45                //      |               "@label": "James Evans"
46                //      |             }, {
47                //      |               "@label": "Jason Griffin"
48                //      |             }]
49                //      |           }
50                //      |         }
51                //      |       }
52                //      |       
53                // example:
54                //      |       // v1.8 format
55                //      |       {
56                //      |         "class": "dojox.mobile.View",
57                //      |         "@id": "view1",
58                //      |         "children": [
59                //      |       
60                //      |           {
61                //      |             "class": "dojox.mobile.Heading",
62                //      |             "@back": "Home",
63                //      |             "@moveTo": "home",
64                //      |             "@label": "view1.json"
65                //      |           },
66                //      |       
67                //      |           {
68                //      |             "class": "dojox.mobile.EdgeToEdgeList",
69                //      |             "children": [
70                //      |               {
71                //      |                 "class": "dojox.mobile.ListItem",
72                //      |                 "@label": "Jack Coleman"
73                //      |               },
74                //      |               {
75                //      |                 "class": "dojox.mobile.ListItem",
76                //      |                 "@label": "James Evans"
77                //      |               },
78                //      |               {
79                //      |                 "class": "dojox.mobile.ListItem",
80                //      |                 "@label": "Jason Griffin"
81                //      |               }
82                //      |             ]
83                //      |           }
84                //      |       
85                //      |         ]
86                //      |       }
87                //      |       
88                // example:
89                //      |       // SpinWheel in v1.8 format
90                //      |       {
91                //      |         "class": "dojox.mobile.View",
92                //      |         "@id": "view1",
93                //      |         "children": [
94                //      |           {
95                //      |             "class": "dojox.mobile.SpinWheel",
96                //      |             "@id": "spin1",
97                //      |             "@style": {"margin":"10px auto","width":"304px"},
98                //      |             "children": [
99                //      |               {
100                //      |                 "class": "dojox.mobile.SpinWheelSlot",
101                //      |                 "@labels": "A,B,C,D,E",
102                //      |                 "@style": {"textAlign":"center","width":"300px"}
103                //      |               }
104                //      |             ]
105                //      |           }
106                //      |         ]
107                //      |       }
108
109                parse: function(/*Object*/ content, /*DomNode*/ target, /*DomNode?*/ refNode){
110                        // summary:
111                        //              Parses the given data and creates a new view at the given position.
112                        // content:
113                        //              Content data for a new view.
114                        // target:
115                        //              A DOM node under which a new view is created.
116                        // refNode:
117                        //              An optional reference DOM node before which a new view is created.
118                        var view, container = domConstruct.create("DIV");
119                        target.insertBefore(container, refNode);
120                        this._ws = [];
121                        this._req = [];
122                        var root = json.parse(content);
123                        return Deferred.when(this._loadPrereqs(root), lang.hitch(this, function(){
124                                view = this._instantiate(root, container);
125                                view.style.visibility = "hidden";
126                                array.forEach(this._ws, function(w){
127                                        if(!w._started && w.startup){
128                                                w.startup();
129                                        }
130                                });
131                                this._ws = null;
132                                return view.id;
133                        }));
134                },
135
136                _loadPrereqs: function(root){
137                        // tags:
138                        //              private
139                        var d = new Deferred();
140                        var req = this._collectRequires(root);
141                        if(req.length === 0){ return true; }
142
143                        if(dojo.require){
144                                array.forEach(req, function(c){
145                                        dojo["require"](c);
146                                });
147                                return true;
148                        }else{
149                                req = array.map(req, function(s){ return s.replace(/\./g, "/"); });
150                                require(req, function(){
151                                        d.resolve(true);
152                                });
153                        }
154                        return d;
155                },
156
157                _collectRequires: function(obj){
158                        // tags:
159                        //              private
160                        var className = obj["class"];
161                        for(var key in obj){
162                                if(key.charAt(0) == "@" || key === "children"){ continue; }
163                                var cls = className || key.replace(/:.*/, "");
164                                this._req.push(cls);
165                                if(!cls){ continue; }
166                                var objs = className ? [obj] :
167                                                (lang.isArray(obj[key]) ? obj[key] : [obj[key]]);
168                                for(var i = 0; i < objs.length; i++){
169                                        // process child widgets
170                                        if(!className){
171                                                this._collectRequires(objs[i]);
172                                        }else if(objs[i].children){
173                                                for(var j = 0; j < objs[i].children.length; j++){
174                                                        this._collectRequires(objs[i].children[j]);
175                                                }
176                                        }
177                                }
178                        }
179                        return this._req;
180                },
181
182                _instantiate: function(/*Object*/obj, /*DomNode*/node, /*Widget*/parent){
183                        // summary:
184                        //              Given the evaluated json data, does the same thing as what
185                        //              the parser does.
186                        // tags:
187                        //              private
188                        var widget;
189                        var className = obj["class"];
190                        for(var key in obj){
191                                if(key.charAt(0) == "@" || key === "children"){ continue; }
192                                var cls = lang.getObject(className || key.replace(/:.*/, ""));
193                                if(!cls){ continue; }
194                                var proto = cls.prototype,
195                                        objs = className ? [obj] :
196                                                (lang.isArray(obj[key]) ? obj[key] : [obj[key]]);
197                                for(var i = 0; i < objs.length; i++){
198                                        var params = {};
199                                        for(var prop in objs[i]){
200                                                if(prop.charAt(0) == "@"){
201                                                        var v = objs[i][prop];
202                                                        prop = prop.substring(1);
203                                                        var t = typeof proto[prop];
204                                                        if(lang.isArray(proto[prop])){
205                                                                params[prop] = v.split(/\s*,\s*/);
206                                                        }else if(t === "string"){
207                                                                params[prop] = v;
208                                                        }else if(t === "number"){
209                                                                params[prop] = v - 0;
210                                                        }else if(t === "boolean"){
211                                                                params[prop] = (v !== "false");
212                                                        }else if(t === "object"){
213                                                                params[prop] = json.parse(v);
214                                                        }else if(t === "function"){
215                                                                params[prop] = lang.getObject(v, false) || new Function(v);
216                                                        }
217                                                }
218                                        }
219                                        widget = new cls(params, node);
220                                        if(node){ // to call View's startup()
221                                                this._ws.push(widget);
222                                        }
223                                        if(parent){
224                                                widget.placeAt(parent.containerNode || parent.domNode);
225                                        }
226                                        // process child widgets
227                                        if(!className){
228                                                this._instantiate(objs[i], null, widget);
229                                        }else if(objs[i].children){
230                                                for(var j = 0; j < objs[i].children.length; j++){
231                                                        this._instantiate(objs[i].children[j], null, widget);
232                                                }
233                                        }
234                                }
235                        }
236                        return widget && widget.domNode;
237                }
238        });
239});
Note: See TracBrowser for help on using the repository browser.