You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
11 KiB
333 lines
11 KiB
define(["require", "dojo/_base/lang", "dojo/_base/declare", "dojo/on", "dojo/Deferred", "dojo/when", "dojo/dom-style", "../Controller"], |
|
function(require, lang, declare, on, Deferred, when, domStyle, Controller, View){ |
|
// module: |
|
// dojox/app/controllers/Load |
|
// summary: |
|
// Bind "app-load" event on dojox/app application instance. |
|
// Load child view and sub children at one time. |
|
|
|
return declare("dojox.app.controllers.Load", Controller, { |
|
|
|
|
|
_waitingQueue:[], |
|
|
|
constructor: function(app, events){ |
|
// summary: |
|
// bind "app-load" event on application instance. |
|
// |
|
// app: |
|
// dojox/app application instance. |
|
// events: |
|
// {event : handler} |
|
this.events = { |
|
"app-init": this.init, |
|
"app-load": this.load |
|
}; |
|
}, |
|
|
|
init: function(event){ |
|
// when the load controller received "app-init", before the lifecycle really starts we create the root view |
|
// if any. This used to be done in main.js but must be done in Load to be able to create custom |
|
// views from the Load controller. |
|
//create and start child. return Deferred |
|
when(this.createView(event.parent, null, null, { |
|
templateString: event.templateString, |
|
controller: event.controller |
|
}, null, event.type), function(newView){ |
|
when(newView.start(), event.callback); |
|
}); |
|
}, |
|
|
|
load: function(event){ |
|
// summary: |
|
// Response to dojox/app "loadArray" event. |
|
// |
|
// example: |
|
// Use trigger() to trigger "loadArray" event, and this function will response the event. For example: |
|
// | this.trigger("app-load", {"parent":parent, "viewId":viewId, "viewArray":viewArray, "callback":function(){...}}); |
|
// |
|
// event: Object |
|
// LoadArray event parameter. It should be like this: {"parent":parent, "viewId":viewId, "viewArray":viewArray, "callback":function(){...}} |
|
// returns: |
|
// A dojo/Deferred object. |
|
// The return value cannot return directly. |
|
// If the caller need to use the return value, pass callback function in event parameter and process return value in callback function. |
|
|
|
this.app.log("in app/controllers/Load event.viewId="+event.viewId+" event =", event); |
|
var views = event.viewId || ""; |
|
var viewArray = []; |
|
// create an array from the diff views in event.viewId (they are separated by +) |
|
var parts = views.split('+'); |
|
while(parts.length > 0){ |
|
var viewId = parts.shift(); |
|
viewArray.push(viewId); |
|
} |
|
|
|
var def; |
|
this.proceedLoadViewDef = new Deferred(); |
|
if(viewArray && viewArray.length > 1){ |
|
// loop thru the array calling loadView for each item in the array |
|
for(var i = 0; i < viewArray.length-1; i++){ |
|
var newEvent = lang.clone(event); |
|
newEvent.callback = null; // skip callback until after last view is loaded. |
|
newEvent.viewId = viewArray[i]; |
|
this._waitingQueue.push(newEvent); |
|
} |
|
this.proceedLoadView(this._waitingQueue.shift()); |
|
when(this.proceedLoadViewDef, lang.hitch(this, function(){ |
|
// for last view leave the callback to be notified |
|
var newEvent = lang.clone(event); |
|
newEvent.viewId = viewArray[i]; |
|
def = this.loadView(newEvent); |
|
return def; |
|
})); |
|
}else{ |
|
def = this.loadView(event); |
|
return def; |
|
} |
|
}, |
|
|
|
proceedLoadView: function(loadEvt){ |
|
// summary: |
|
// Proceed load queue by FIFO by default. |
|
// If load is in proceeding, add the next load to waiting queue. |
|
// |
|
// loadEvt: Object |
|
// LoadArray event parameter. It should be like this: {"parent":parent, "viewId":viewId, "viewArray":viewArray, "callback":function(){...}} |
|
|
|
var def = this.loadView(loadEvt); |
|
when(def, lang.hitch(this, function(){ |
|
this.app.log("in app/controllers/Load proceedLoadView back from loadView for event", loadEvt); |
|
var nextEvt = this._waitingQueue.shift(); |
|
if(nextEvt){ |
|
this.app.log("in app/controllers/Load proceedLoadView back from loadView calling this.proceedLoadView(nextEvt) for ",nextEvt); |
|
this.proceedLoadView(nextEvt); |
|
}else{ |
|
this._waitingQueue = []; |
|
this.proceedLoadViewDef.resolve(); |
|
} |
|
})); |
|
}, |
|
|
|
loadView: function(loadEvent){ |
|
// summary: |
|
// Response to dojox/app "app-load" event. |
|
// |
|
// example: |
|
// Use trigger() to trigger "app-load" event, and this function will response the event. For example: |
|
// | this.trigger("app-load", {"parent":parent, "viewId":viewId, "callback":function(){...}}); |
|
// |
|
// loadEvent: Object |
|
// Load event parameter. It should be like this: {"parent":parent, "viewId":viewId, "callback":function(){...}} |
|
// returns: |
|
// A dojo/Deferred object. |
|
// The return value cannot return directly. |
|
// If the caller need to use the return value, pass callback function in event parameter and process return value in callback function. |
|
|
|
var parent = loadEvent.parent || this.app; |
|
var viewId = loadEvent.viewId || ""; |
|
var parts = viewId.split(','); |
|
var childId = parts.shift(); |
|
var subIds = parts.join(","); |
|
var params = loadEvent.params || ""; |
|
|
|
this._handleDefault = false; |
|
this._defaultHasPlus = false; |
|
var def = this.loadChild(parent, childId, subIds, params, loadEvent); |
|
// call Load event callback |
|
if(loadEvent.callback){ |
|
when(def, lang.hitch(this, function(){ |
|
if(this._handleDefault && !loadEvent.initLoad){ |
|
this.app.log("logTransitions:",""," emit app-transition this.childViews=["+this.childViews+"]"); |
|
this.app.emit("app-transition", { |
|
viewId: this.childViews, |
|
defaultView: true, |
|
forceTransitionNone: loadEvent.forceTransitionNone, |
|
opts: { params: params } |
|
}); |
|
} |
|
loadEvent.callback(this._handleDefault, this._defaultHasPlus); |
|
})) |
|
} |
|
return def; |
|
}, |
|
|
|
createChild: function(parent, childId, subIds, params){ |
|
// summary: |
|
// Create a view instance if not already loaded by calling createView. This is typically a |
|
// dojox/app/View. |
|
// |
|
// parent: Object |
|
// parent of the view. |
|
// childId: String |
|
// view id need to be loaded. |
|
// subIds: String |
|
// sub views' id of this view. |
|
// returns: |
|
// If view exist, return the view object. |
|
// Otherwise, create the view and return a dojo.Deferred instance. |
|
|
|
var id = parent.id + '_' + childId; |
|
|
|
// check for possible default params if no params were provided |
|
if(!params && parent.views[childId] && parent.views[childId].defaultParams){ |
|
params = parent.views[childId].defaultParams; |
|
} |
|
var view = parent.children[id]; |
|
if(view){ |
|
// set params to new value before returning |
|
if(params){ |
|
view.params = params; |
|
} |
|
this.app.log("in app/controllers/Load createChild view is already loaded so return the loaded view with the new parms ",view); |
|
return view; |
|
} |
|
var def = new Deferred(); |
|
// create and start child. return Deferred |
|
when(this.createView(parent, id, childId, null, params, parent.views[childId].type), function(newView){ |
|
parent.children[id] = newView; |
|
when(newView.start(), function(view){ |
|
def.resolve(view); |
|
}); |
|
}); |
|
return def; |
|
}, |
|
|
|
createView: function(parent, id, name, mixin, params, type){ |
|
// summary: |
|
// Create a dojox/app/View instance. Can be overridden to create different type of views. |
|
// parent: Object |
|
// parent of this view. |
|
// id: String |
|
// view id. |
|
// name: String |
|
// view name. |
|
// mixin: String |
|
// additional property to be mixed into the view (templateString, controller...) |
|
// params: Object |
|
// params of this view. |
|
// type: String |
|
// the MID of the View. If not provided "dojox/app/View". |
|
// returns: |
|
// A dojo/Deferred instance which will be resolved when the view will be instantiated. |
|
// tags: |
|
// protected |
|
var def = new Deferred(); |
|
var app = this.app; |
|
require([type?type:"../View"], function(View){ |
|
var newView = new View(lang.mixin({ |
|
"app": app, |
|
"id": id, |
|
"name": name, |
|
"parent": parent |
|
}, { "params": params }, mixin)); |
|
def.resolve(newView); |
|
}); |
|
return def; |
|
}, |
|
|
|
loadChild: function(parent, childId, subIds, params, loadEvent){ |
|
// summary: |
|
// Load child and sub children views recursively. |
|
// |
|
// parent: Object |
|
// parent of this view. |
|
// childId: String |
|
// view id need to be loaded. |
|
// subIds: String |
|
// sub views' id of this view. |
|
// params: Object |
|
// params of this view. |
|
// loadEvent: Object |
|
// the event passed for the load of this view. |
|
// returns: |
|
// A dojo/Deferred instance which will be resolved when all views loaded. |
|
|
|
if(!parent){ |
|
throw Error("No parent for Child '" + childId + "'."); |
|
} |
|
|
|
if(!childId){ |
|
var parts = parent.defaultView ? parent.defaultView.split(",") : "default"; |
|
if(parent.defaultView && !loadEvent.initLoad){ // in this case we need to call transfer to handle the defaultView calls to activate |
|
var childViews = this._getViewNamesFromDefaults(parent); |
|
this.app.log("logTransitions:","Load:loadChild","setting _handleDefault true for parent.defaultView childViews=["+childViews+"]"); |
|
this._handleDefault = true; |
|
if(parent.defaultView.indexOf("+") >= 0){ |
|
this._defaultHasPlus = true; |
|
} |
|
}else{ |
|
childId = parts.shift(); |
|
subIds = parts.join(','); |
|
} |
|
|
|
} |
|
|
|
var loadChildDeferred = new Deferred(); |
|
var createPromise; |
|
try{ |
|
createPromise = this.createChild(parent, childId, subIds, params); |
|
}catch(ex){ |
|
console.warn("logTransitions:","","emit reject load exception for =["+childId+"]",ex); |
|
loadChildDeferred.reject("load child '"+childId+"' error."); |
|
return loadChildDeferred.promise; |
|
} |
|
when(createPromise, lang.hitch(this, function(child){ |
|
// if no subIds and current view has default view, load the default view. |
|
if(!subIds && child.defaultView){ // in this case we need to call transfer to handle the defaultView activate |
|
var childViews = this._getViewNamesFromDefaults(child); |
|
this.app.log("logTransitions:","Load:loadChild"," setting _handleDefault = true child.defaultView childViews=["+childViews+"]"); |
|
this._handleDefault = true; |
|
if(child.defaultView.indexOf("+") >= 0){ |
|
this._defaultHasPlus = true; |
|
} |
|
this.childViews = childViews; |
|
loadChildDeferred.resolve(); |
|
} |
|
|
|
var parts = subIds.split(','); |
|
childId = parts.shift(); |
|
subIds = parts.join(','); |
|
if(childId){ |
|
var subLoadDeferred = this.loadChild(child, childId, subIds, params, loadEvent); |
|
when(subLoadDeferred, function(){ |
|
loadChildDeferred.resolve(); |
|
}, |
|
function(){ |
|
loadChildDeferred.reject("load child '"+childId+"' error."); |
|
}); |
|
}else{ |
|
loadChildDeferred.resolve(); |
|
} |
|
}), |
|
function(){ |
|
console.warn("loadChildDeferred.REJECT() for ["+childId+"] subIds=["+subIds+"]"); |
|
loadChildDeferred.reject("load child '"+childId+"' error.") |
|
}); |
|
return loadChildDeferred.promise; // dojo/Deferred.promise |
|
}, |
|
|
|
_getViewNamesFromDefaults: function(view){ |
|
// summary: |
|
// Build the full nested view name from the view and its defaultView(s) |
|
// |
|
// view: Object |
|
// the view with defaultViews to process |
|
// returns: |
|
// A string with the full nested view names |
|
var parent = view.parent; |
|
var parentNames = view.name; |
|
var viewNames = ""; |
|
while(parent !== this.app){ |
|
parentNames = parent.name+","+parentNames; |
|
parent = parent.parent; |
|
} |
|
var parts = view.defaultView.split('+'); |
|
for(var item in parts){ |
|
parts[item] = parentNames+","+parts[item]; |
|
} |
|
viewNames = parts.join('+'); |
|
return viewNames; |
|
} |
|
}); |
|
});
|
|
|