define("dojox/app/main", ["dojo/_base/kernel", "require", "dojo/_base/lang", "dojo/_base/declare", "dojo/Deferred", "dojo/when", "dojo/has", "dojo/_base/config", "dojo/on", "dojo/ready", "dojo/_base/window", "dojo/dom-construct", "./model", "./View", "./controllers/Load", "./controllers/Transition", "./controllers/Layout"], function(kernel, require, lang, declare, Deferred, when, has, config, on, ready, baseWindow, dom, Model, View, LoadController, TransitionController, LayoutController){ kernel.experimental("dojox.app"); has.add("app-log-api", (config["app"] || {}).debugApp); var Application = declare(null, { constructor: function(params, node){ lang.mixin(this, params); this.params = params; this.id = params.id; this.defaultView = params.defaultView; this.widgetId = params.id; this.controllers = []; this.children = {}; this.loadedModels = {}; // Create a new domNode and append to body // Need to bind startTransition event on application domNode, // Because dojox/mobile/ViewController bind startTransition event on document.body // Make application's root domNode id unique because this id can be visited by window namespace on Chrome 18. this.domNode = dom.create("div", { id: this.id+"_Root", style: "width:100%; height:100%; overflow-y:hidden; overflow-x:hidden;" }); node.appendChild(this.domNode); }, createDataStore: function(params){ // summary: // Create data store instance // // params: Object // data stores configuration. if(params.stores){ //create stores in the configuration. for(var item in params.stores){ if(item.charAt(0) !== "_"){//skip the private properties var type = params.stores[item].type ? params.stores[item].type : "dojo/store/Memory"; var config = {}; if(params.stores[item].params){ lang.mixin(config, params.stores[item].params); } // we assume the store is here through dependencies var storeCtor = require(type); if(config.data && lang.isString(config.data)){ //get the object specified by string value of data property //cannot assign object literal or reference to data property //because json.ref will generate __parent to point to its parent //and will cause infinitive loop when creating StatefulModel. config.data = lang.getObject(config.data); } params.stores[item].store = new storeCtor(config); } } } }, createControllers: function(controllers){ // summary: // Create controller instance // // controllers: Array // controller configuration array. // returns: // controllerDeferred object if(controllers){ var requireItems = []; for(var i = 0; i < controllers.length; i++){ requireItems.push(controllers[i]); } var def = new Deferred(); var requireSignal; try{ requireSignal = require.on("error", function(error){ if(def.isResolved() || def.isRejected()){ return; } def.reject("load controllers error."); requireSignal.remove(); }); require(requireItems, function(){ def.resolve.call(def, arguments); requireSignal.remove(); }); }catch(ex){ def.reject("load controllers error."); requireSignal.remove(); } var controllerDef = new Deferred(); when(def, lang.hitch(this, function(){ for(var i = 0; i < arguments[0].length; i++){ // Store Application object on each controller. this.controllers.push(new arguments[0][i](this)); } controllerDef.resolve(this); }), function(){ //require def error, reject loadChildDeferred controllerDef.reject("load controllers error."); }); return controllerDef; } }, trigger: function(event, params){ // summary: // trigger an event // // event: String // event name. The event is binded by controller.bind() method. // params: Object // event params. on.emit(this.domNode, event, params); }, // setup default view and Controllers and startup the default view start: function(){ // //create application level data store this.createDataStore(this.params); // create application level data model var loadModelLoaderDeferred = new Deferred(); var createPromise; try{ createPromise = Model(this.params.models, this); }catch(ex){ loadModelLoaderDeferred.reject("load model error."); return loadModelLoaderDeferred.promise; } if(createPromise.then){ when(createPromise, lang.hitch(this, function(newModel){ this.loadedModels = newModel; this.setupAppView(); }), function(){ loadModelLoaderDeferred.reject("load model error.") }); }else{ this.loadedModels = createPromise; this.setupAppView(); } }, setupAppView: function(){ //create application level view // if(this.template){ this.view = new View({ app: this, // pass the app into the View so it can have easy access to app name: this.name, parent: this, templateString: this.templateString, definition: this.definition }); when(this.view.start(), lang.hitch(this, function(){ this.domNode = this.view.domNode; this.setupControllers(); this.startup(); })); }else{ this.setupControllers(); this.startup(); } }, getParamsFromHash: function(hash){ // summary: // get the params from the hash // // hash: String // the url hash // // returns: // the params object // var params = {}; if(hash && hash.length){ for(var parts= hash.split("&"), x= 0; x