text: define("dojox/app/ViewBase", ["require", "dojo/when", "dojo/on", "dojo/dom-attr", "dojo/dom-style", "dojo/_base/declare", "dojo/_base/lang",
  	"dojo/Deferred", "./utils/model", "./utils/constraints"],
  	function(require, when, on, domAttr, domStyle, declare, lang, Deferred, model, constraints){
  	return declare("dojox.app.ViewBase", null, {
  		// summary:
  		//		View base class with model & controller capabilities. Subclass must implement rendering capabilities.
  		constructor: function(params){
  			// summary:
  			//		Constructs a ViewBase instance.
  			// params:
  			//		view parameters, include:
  			//
  			//		- app: the app
  			//		- id: view id
  			//		- name: view name
  			//		- parent: parent view
  			//		- controller: view controller module identifier
  			//		- children: children views
  			this.id = "";
  			this.name = "";
  			this.children = {};
  			this.selectedChildren = {};
  			this.loadedStores = {};
  			// private
  			this._started = false;
  			lang.mixin(this, params);
  			// mixin views configuration to current view instance.
  			if(this.parent.views){
  				lang.mixin(this, this.parent.views[this.name]);
  			}
  		},
  
  		// start view
  		start: function(){
  			// summary:
  			//		start view object.
  			//		load view template, view controller implement and startup all widgets in view template.
  			if(this._started){
  				return this;
  			}
  			this._startDef = new Deferred();
  			when(this.load(), lang.hitch(this, function(){
  				// call setupModel, after setupModel startup will be called after startup the loadViewDeferred will be resolved
  				this._createDataStore(this);
  				this._setupModel();
  			}));
  			return this._startDef;
  		},
  
  		load: function(){
  			var vcDef = this._loadViewController();
  			when(vcDef, lang.hitch(this, function(controller){
  				if(controller){
  					//lang.mixin(this, controller);
  					declare.safeMixin(this, controller);
  				}
  			}));
  			return vcDef;
  		},
  
  		_createDataStore: function(){
  			// summary:
  			//		Create data store instance for View specific stores
  			//
  			// TODO: move this into a common place for use by main and ViewBase
  			//
  			if(this.parent.loadedStores){
  				lang.mixin(this.loadedStores, this.parent.loadedStores);
  			}
  
  			if(this.stores){
  				//create stores in the configuration.
  				for(var item in this.stores){
  					if(item.charAt(0) !== "_"){//skip the private properties
  						var type = this.stores[item].type ? this.stores[item].type : "dojo/store/Memory";
  						var config = {};
  						if(this.stores[item].params){
  							lang.mixin(config, this.stores[item].params);
  						}
  						// we assume the store is here through dependencies
  						try{
  							var storeCtor = require(type);
  						}catch(e){
  							throw new Error(type+" must be listed in the dependencies");
  						}
  						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);
  						}
  						if(this.stores[item].observable){
  							try{
  								var observableCtor = require("dojo/store/Observable");
  							}catch(e){
  								throw new Error("dojo/store/Observable must be listed in the dependencies");
  							}
  							this.stores[item].store = observableCtor(new storeCtor(config));
  						}else{
  							this.stores[item].store = new storeCtor(config);
  						}
  						this.loadedStores[item] = this.stores[item].store; // add this store to loadedStores for the view							
  					}
  				}
  			}
  		},
  
  		_setupModel: function(){
  			// summary:
  			//		Load views model if it is not already loaded then call _startup.
  			// tags:
  			//		private
  						
  			if(!this.loadedModels){
  				var createPromise;
  				try{
  					createPromise = model(this.models, this.parent, this.app);
  				}catch(e){
  					throw new Error("Error creating models: "+e.message);
  				}
  				when(createPromise, lang.hitch(this, function(models){
  					if(models){
  						// if models is an array it comes from dojo/promise/all. Each array slot contains the same result object
  						// so pick slot 0.
  						this.loadedModels = lang.isArray(models)?models[0]:models;
  					}
  					this._startup();
  				}),
  				function(err){
  					throw new Error("Error creating models: "+err.message);					
  				});
  			}else{ // loadedModels already created so call _startup
  				this._startup();				
  			}		
  		},
  
  		_startup: function(){
  			// summary:
  			//		startup widgets in view template.
  			// tags:
  			//		private
  
  			this._initViewHidden();
  			this._needsResize = true; // flag used to be sure resize has been called before transition
  
  			this._startLayout();
  		},
  
  		_initViewHidden: function(){
  			domStyle.set(this.domNode, "visibility", "hidden");
  		},
  
  		_startLayout: function(){
  			// summary:
  			//		startup widgets in view template.
  			// tags:
  			//		private
  			this.app.log("  > in app/ViewBase _startLayout firing layout for name=[",this.name,"], parent.name=[",this.parent.name,"]");
  
  			if(!this.hasOwnProperty("constraint")){
  				this.constraint = domAttr.get(this.domNode, "data-app-constraint") || "center";
  			}
  			constraints.register(this.constraint);
  
  
  			this.app.emit("app-initLayout", {
  				"view": this, 
  				"callback": lang.hitch(this, function(){
  						//start widget
  						this.startup();
  
  						// call view assistant's init() method to initialize view
  						this.app.log("  > in app/ViewBase calling init() name=[",this.name,"], parent.name=[",this.parent.name,"]");
  						this.init();
  						this._started = true;
  						if(this._startDef){
  							this._startDef.resolve(this);
  						}
  				})
  			});
  		},
  
  
  		_loadViewController: function(){
  			// summary:
  			//		Load view controller by configuration or by default.
  			// tags:
  			//		private
  			//
  			var viewControllerDef = new Deferred();
  			var path;
  
  			if(!this.controller){ // no longer using this.controller === "none", if we dont have one it means none.
  				this.app.log("  > in app/ViewBase _loadViewController no controller set for view name=[",this.name,"], parent.name=[",this.parent.name,"]");
  				viewControllerDef.resolve(true);
  				return viewControllerDef;
  			}else{
  				path = this.controller.replace(/(\.js)$/, "");
  			}
  
  			var requireSignal;
  			try{
  				var loadFile = path;
  				var index = loadFile.indexOf("./");
  				if(index >= 0){
  					loadFile = path.substring(index+2);
  				}
  				requireSignal = require.on ? require.on("error", function(error){
  					if(viewControllerDef.isResolved() || viewControllerDef.isRejected()){
  						return;
  					}
  					if(error.info[0] && (error.info[0].indexOf(loadFile) >= 0)){
  						viewControllerDef.resolve(false);
  						if(requireSignal){
  							requireSignal.remove();
  						}
  					}
  				}) : null;
  
  				if(path.indexOf("./") == 0){
  					path = "app/"+path;
  				}
  
  				require([path], function(controller){
  					viewControllerDef.resolve(controller);
  					if(requireSignal){
  						requireSignal.remove();
  					}
  				});
  			}catch(e){
  				viewControllerDef.reject(e);
  				if(requireSignal){
  					requireSignal.remove();
  				}
  			}
  			return viewControllerDef;
  		},
  
  		init: function(){
  			// summary:
  			//		view life cycle init()
  		},
  
  		beforeActivate: function(){
  			// summary:
  			//		view life cycle beforeActivate()
  		},
  
  		afterActivate: function(){
  			// summary:
  			//		view life cycle afterActivate()
  		},
  
  		beforeDeactivate: function(){
  			// summary:
  			//		view life cycle beforeDeactivate()
  		},
  
  		afterDeactivate: function(){
  			// summary:
  			//		view life cycle afterDeactivate()
  		},
  
  		destroy: function(){
  			// summary:
  			//		view life cycle destroy()
  		}
  	});
  });
  