source: Dev/trunk/src/client/dojox/app/main.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: 11.4 KB
Line 
1define(["require", "dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/config",
2        "dojo/_base/window", "dojo/Evented", "dojo/Deferred", "dojo/when", "dojo/has", "dojo/on", "dojo/ready",
3        "dojo/dom-construct", "dojo/dom-attr", "./utils/model", "./utils/nls", "./module/lifecycle",
4        "./utils/hash", "./utils/constraints", "./utils/config"],
5        function(require, kernel, lang, declare, config, win, Evented, Deferred, when, has, on, ready, domConstruct, domAttr,
6                         model, nls, lifecycle, hash, constraints, configUtils){
7
8        has.add("app-log-api", (config["app"] || {}).debugApp);
9
10        var Application = declare(Evented, {
11                constructor: function(params, node){
12                        lang.mixin(this, params);
13                        this.params = params;
14                        this.id = params.id;
15                        this.defaultView = params.defaultView;
16                        this.controllers = [];
17                        this.children = {};
18                        this.loadedModels = {};
19                        this.loadedStores = {};
20                        // Create a new domNode and append to body
21                        // Need to bind startTransition event on application domNode,
22                        // Because dojox/mobile/ViewController bind startTransition event on document.body
23                        // Make application's root domNode id unique because this id can be visited by window namespace on Chrome 18.
24                        this.setDomNode(domConstruct.create("div", {
25                                id: this.id+"_Root",
26                                style: "width:100%; height:100%; overflow-y:hidden; overflow-x:hidden;"
27                        }));
28                        node.appendChild(this.domNode);
29                },
30
31                createDataStore: function(params){
32                        // summary:
33                        //              Create data store instance
34                        //
35                        // params: Object
36                        //              data stores configuration.
37
38                        if(params.stores){
39                                //create stores in the configuration.
40                                for(var item in params.stores){
41                                        if(item.charAt(0) !== "_"){//skip the private properties
42                                                var type = params.stores[item].type ? params.stores[item].type : "dojo/store/Memory";
43                                                var config = {};
44                                                if(params.stores[item].params){
45                                                        lang.mixin(config, params.stores[item].params);
46                                                }
47                                                // we assume the store is here through dependencies
48                                                try{
49                                                        var storeCtor = require(type);
50                                                }catch(e){
51                                                        throw new Error(type+" must be listed in the dependencies");
52                                                }
53                                                if(config.data && lang.isString(config.data)){
54                                                        //get the object specified by string value of data property
55                                                        //cannot assign object literal or reference to data property
56                                                        //because json.ref will generate __parent to point to its parent
57                                                        //and will cause infinitive loop when creating StatefulModel.
58                                                        config.data = lang.getObject(config.data);
59                                                }
60                                                if(params.stores[item].observable){
61                                                        try{
62                                                                var observableCtor = require("dojo/store/Observable");
63                                                        }catch(e){
64                                                                throw new Error("dojo/store/Observable must be listed in the dependencies");
65                                                        }
66                                                        params.stores[item].store = observableCtor(new storeCtor(config));
67                                                }else{
68                                                        params.stores[item].store = new storeCtor(config);
69                                                }
70                                                this.loadedStores[item] = params.stores[item].store;                                                   
71                                        }
72                                }
73                        }
74                },
75
76                createControllers: function(controllers){
77                        // summary:
78                        //              Create controller instance
79                        //
80                        // controllers: Array
81                        //              controller configuration array.
82                        // returns:
83                        //              controllerDeferred object
84
85                        if(controllers){
86                                var requireItems = [];
87                                for(var i = 0; i < controllers.length; i++){
88                                        requireItems.push(controllers[i]);
89                                }
90
91                                var def = new Deferred();
92                                var requireSignal;
93                                try{
94                                        requireSignal = require.on("error", function(error){
95                                                if(def.isResolved() || def.isRejected()){
96                                                        return;
97                                                }
98                                                def.reject("load controllers error.");
99                                                requireSignal.remove();
100                                        });
101                                        require(requireItems, function(){
102                                                def.resolve.call(def, arguments);
103                                                requireSignal.remove();
104                                        });
105                                }catch(e){
106                                        def.reject(e);
107                                        if(requireSignal){
108                                                requireSignal.remove();
109                                        }
110                                }
111
112                                var controllerDef = new Deferred();
113                                when(def, lang.hitch(this, function(){
114                                        for(var i = 0; i < arguments[0].length; i++){
115                                                // instantiate controllers, set Application object, and perform auto binding
116                                                this.controllers.push((new arguments[0][i](this)).bind());
117                                        }
118                                        controllerDef.resolve(this);
119                                }), function(){
120                                        //require def error, reject loadChildDeferred
121                                        controllerDef.reject("load controllers error.");
122                                });
123                                return controllerDef;
124                        }
125                },
126
127                trigger: function(event, params){
128                        // summary:
129                        //              trigger an event. Deprecated, use emit instead.
130                        //
131                        // event: String
132                        //              event name. The event is binded by controller.bind() method.
133                        // params: Object
134                        //              event params.
135                        kernel.deprecated("dojox.app.Application.trigger", "Use dojox.app.Application.emit instead", "2.0");
136                        this.emit(event, params);
137                },
138
139                // setup default view and Controllers and startup the default view
140                start: function(){
141                        //
142                        //create application level data store
143                        this.createDataStore(this.params);
144
145                        // create application level data model
146                        var loadModelLoaderDeferred = new Deferred();
147                        var createPromise;
148                        try{
149                                createPromise = model(this.params.models, this, this);
150                        }catch(e){
151                                loadModelLoaderDeferred.reject(e);
152                                return loadModelLoaderDeferred.promise;
153                        }
154                        when(createPromise, lang.hitch(this, function(models){
155                                // if models is an array it comes from dojo/promise/all. Each array slot contains the same result object
156                                // so pick slot 0.
157                                this.loadedModels = lang.isArray(models)?models[0]:models;
158                                this.setupControllers();
159                                // if available load root NLS
160                                when(nls(this.params), lang.hitch(this, function(nls){
161                                        if(nls){
162                                                lang.mixin(this.nls = {}, nls);
163                                        }
164                                        this.startup();
165                                }));
166                        }), function(){
167                                loadModelLoaderDeferred.reject("load model error.")
168                        });
169                },
170
171                setDomNode: function(domNode){
172                        var oldNode = this.domNode;
173                        this.domNode = domNode;
174                        this.emit("app-domNode", {
175                                oldNode: oldNode,
176                                newNode: domNode
177                        });
178                },
179
180                setupControllers: function(){
181                        // create application controller instance
182                        // move set _startView operation from history module to application
183                        var currentHash = window.location.hash;
184                //      this._startView = (((currentHash && currentHash.charAt(0) == "#") ? currentHash.substr(1) : currentHash) || this.defaultView).split('&')[0];
185                        this._startView = hash.getTarget(currentHash, this.defaultView);
186                        this._startParams = hash.getParams(currentHash);
187                },
188
189                startup: function(){
190                        // load controllers and views
191                        //
192                        this.selectedChildren = {};                     
193                        var controllers = this.createControllers(this.params.controllers);
194                        // constraint on app
195                        if(this.hasOwnProperty("constraint")){
196                                constraints.register(this.params.constraints);
197                        }else{
198                                this.constraint = "center";
199                        }
200                        var emitLoad = function(){
201                                // emit "app-load" event and let controller to load view.
202                                this.emit("app-load", {
203                                        viewId: this.defaultView,
204                                        initLoad: true,
205                                        params: this._startParams,
206                                        callback: lang.hitch(this, function (){
207                                                this.emit("app-transition", {
208                                                        viewId: this.defaultView,
209                                                        forceTransitionNone: true, // we want to avoid the transition on the first display for the defaultView
210                                                        opts: { params: this._startParams }
211                                                });
212                                                if(this.defaultView !== this._startView){
213                                                        // transition to startView. If startView==defaultView, that means initial the default view.
214                                                        this.emit("app-transition", {
215                                                                viewId: this._startView,
216                                                                opts: { params: this._startParams }
217                                                        });
218                                                }
219                                                this.setStatus(this.lifecycle.STARTED);
220                                        })
221                                });
222                        };
223                        when(controllers, lang.hitch(this, function(){
224                                if(this.template){
225                                        // emit "app-init" event so that the Load controller can initialize root view
226                                        this.emit("app-init", {
227                                                app: this,      // pass the app into the View so it can have easy access to app
228                                                name: this.name,
229                                                type: this.type,
230                                                parent: this,
231                                                templateString: this.templateString,
232                                                controller: this.controller,
233                                                callback: lang.hitch(this, function(view){
234                                                        this.setDomNode(view.domNode);
235                                                        emitLoad.call(this);
236                                                })
237                                        });
238                                }else{
239                                        emitLoad.call(this);
240                                }
241                        }));
242                }               
243        });
244
245        function generateApp(config, node){
246                // summary:
247                //              generate the application
248                //
249                // config: Object
250                //              app config
251                // node: domNode
252                //              domNode.
253                var path;
254
255                // call configProcessHas to process any has blocks in the config
256                config = configUtils.configProcessHas(config);
257
258                if(!config.loaderConfig){
259                        config.loaderConfig = {};
260                }
261                if(!config.loaderConfig.paths){
262                        config.loaderConfig.paths = {};
263                }
264                if(!config.loaderConfig.paths["app"]){
265                        // Register application module path
266                        path = window.location.pathname;
267                        if(path.charAt(path.length) != "/"){
268                                path = path.split("/");
269                                path.pop();
270                                path = path.join("/");
271                        }
272                        config.loaderConfig.paths["app"] = path;
273                }
274                require(config.loaderConfig);
275
276                if(!config.modules){
277                        config.modules = [];
278                }
279                // add dojox/app lifecycle module by default
280                config.modules.push("./module/lifecycle");
281                var modules = config.modules.concat(config.dependencies?config.dependencies:[]);
282
283                if(config.template){
284                        path = config.template;
285                        if(path.indexOf("./") == 0){
286                                path = "app/"+path;
287                        }
288                        modules.push("dojo/text!" + path);
289                }
290
291                require(modules, function(){
292                        var modules = [Application];
293                        for(var i = 0; i < config.modules.length; i++){
294                                modules.push(arguments[i]);
295                        }
296
297                        if(config.template){
298                                var ext = {
299                                        templateString: arguments[arguments.length - 1]
300                                }
301                        }
302                        App = declare(modules, ext);
303
304                        ready(function(){
305                                var app = new App(config, node || win.body());
306
307                                if(has("app-log-api")){
308                                        app.log = function(){
309                                                // summary:
310                                                //              If config is set to turn on app logging, then log msg to the console
311                                                //
312                                                // arguments:
313                                                //              the message to be logged,
314                                                //              all but the last argument will be treated as Strings and be concatenated together,
315                                                //      the last argument can be an object it will be added as an argument to the console.log                                           
316                                                var msg = "";
317                                                try{
318                                                        for(var i = 0; i < arguments.length-1; i++){
319                                                                msg = msg + arguments[i];
320                                                        }
321                                                        console.log(msg,arguments[arguments.length-1]);
322                                                }catch(e){}
323                                        };
324                                }else{
325                                        app.log = function(){}; // noop
326                                }
327
328                                app.transitionToView = function(/*DomNode*/target, /*Object*/transitionOptions, /*Event?*/triggerEvent){
329                                        // summary:
330                                        //              A convenience function to fire the transition event to transition to the view.
331                                        //
332                                        // target:
333                                        //              The DOM node that initiates the transition (for example a ListItem).
334                                        // transitionOptions:
335                                        //              Contains the transition options.
336                                        // triggerEvent:
337                                        //              The event that triggered the transition (for example a touch event on a ListItem).
338                                        var opts = {bubbles:true, cancelable:true, detail: transitionOptions, triggerEvent: triggerEvent || null};
339                                        on.emit(target,"startTransition", opts);
340                                };
341
342                                app.setStatus(app.lifecycle.STARTING);
343                                // Create global namespace for application.
344                                // The global name is application id. ie: modelApp
345                                var globalAppName = app.id;
346                                if(window[globalAppName]){
347                                        lang.mixin(app, window[globalAppName]);
348                                }
349                                window[globalAppName] = app;
350                                app.start();
351                        });
352                });
353        }
354
355        return function(config, node){
356                if(!config){
357                        throw new Error("App Config Missing");
358                }
359
360                if(config.validate){
361                        require(["dojox/json/schema", "dojox/json/ref", "dojo/text!dojox/application/schema/application.json"], function(schema, appSchema){
362                                schema = dojox.json.ref.resolveJson(schema);
363                                if(schema.validate(config, appSchema)){
364                                        generateApp(config, node);
365                                }
366                        });
367                }else{
368                        generateApp(config, node);
369                }
370        }
371});
Note: See TracBrowser for help on using the repository browser.