webui-aria2/js/libs/dojox/mobile/ViewController.js.uncompressed.js
2012-05-01 19:52:07 +08:00

265 lines
8.6 KiB
JavaScript

//>>built
define("dojox/mobile/ViewController", [
"dojo/_base/kernel",
"dojo/_base/array",
"dojo/_base/connect",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/window",
"dojo/dom",
"dojo/dom-class",
"dojo/dom-construct",
// "dojo/hash", // optionally prereq'ed
"dojo/on",
"dojo/ready",
"dijit/registry", // registry.byId
"./ProgressIndicator",
"./TransitionEvent"
], function(dojo, array, connect, declare, lang, win, dom, domClass, domConstruct, on, ready, registry, ProgressIndicator, TransitionEvent){
// module:
// dojox/mobile/ViewController
// summary:
// A singleton class that controlls view transition.
var dm = lang.getObject("dojox.mobile", true);
var Controller = declare("dojox.mobile.ViewController", null, {
// summary:
// A singleton class that controlls view transition.
// description:
// This class listens to the "startTransition" events and performs
// view transitions. If the transition destination is an external
// view specified with the url parameter, retrieves the view
// content and parses it to create a new target view.
constructor: function(){
this.viewMap={};
this.currentView=null;
this.defaultView=null;
ready(lang.hitch(this, function(){
on(win.body(), "startTransition", lang.hitch(this, "onStartTransition"));
}));
},
findCurrentView: function(moveTo,src){
// summary:
// Searches for the currently showing view.
if(moveTo){
var w = registry.byId(moveTo);
if(w && w.getShowingView){ return w.getShowingView(); }
}
if(dm.currentView){
return dm.currentView; //TODO:1.8 may not return an expected result especially when views are nested
}
//TODO:1.8 probably never reaches here
w = src;
while(true){
w = w.getParent();
if(!w){ return null; }
if(domClass.contains(w.domNode, "mblView")){ break; }
}
return w;
},
onStartTransition: function(evt){
// summary:
// A handler that performs view transition.
evt.preventDefault();
if(!evt.detail || (evt.detail && !evt.detail.moveTo && !evt.detail.href && !evt.detail.url && !evt.detail.scene)){ return; }
var w = this.findCurrentView(evt.detail.moveTo, (evt.target && evt.target.id)?registry.byId(evt.target.id):registry.byId(evt.target)); // the current view widget
if(!w || (evt.detail && evt.detail.moveTo && w === registry.byId(evt.detail.moveTo))){ return; }
if(evt.detail.href){
var t = registry.byId(evt.target.id).hrefTarget;
if(t){
dm.openWindow(evt.detail.href, t);
}else{
w.performTransition(null, evt.detail.transitionDir, evt.detail.transition, evt.target, function(){location.href = evt.detail.href;});
}
return;
} else if(evt.detail.scene){
connect.publish("/dojox/mobile/app/pushScene", [evt.detail.scene]);
return;
}
var moveTo = evt.detail.moveTo;
if(evt.detail.url){
var id;
if(dm._viewMap && dm._viewMap[evt.detail.url]){
// external view has already been loaded
id = dm._viewMap[evt.detail.url];
}else{
// get the specified external view and append it to the <body>
var text = this._text;
if(!text){
if(registry.byId(evt.target.id).sync){
// We do not add explicit dependency on dojo/_base/xhr to this module
// to be able to create a build that does not contain dojo/_base/xhr.
// User applications that do sync loading here need to explicitly
// require dojo/_base/xhr up front.
dojo.xhrGet({url:evt.detail.url, sync:true, load:function(result){
text = lang.trim(result);
}});
}else{
var s = "dojo/_base/xhr"; // assign to a variable so as not to be picked up by the build tool
require([s], lang.hitch(this, function(xhr){
var prog = ProgressIndicator.getInstance();
win.body().appendChild(prog.domNode);
prog.start();
var obj = xhr.get({
url: evt.detail.url,
handleAs: "text"
});
obj.addCallback(lang.hitch(this, function(response, ioArgs){
prog.stop();
if(response){
this._text = response;
new TransitionEvent(evt.target, {
transition: evt.detail.transition,
transitionDir: evt.detail.transitionDir,
moveTo: moveTo,
href: evt.detail.href,
url: evt.detail.url,
scene: evt.detail.scene},
evt.detail)
.dispatch();
}
}));
obj.addErrback(function(error){
prog.stop();
console.log("Failed to load "+evt.detail.url+"\n"+(error.description||error));
});
}));
return;
}
}
this._text = null;
id = this._parse(text, registry.byId(evt.target.id).urlTarget);
if(!dm._viewMap){
dm._viewMap = [];
}
dm._viewMap[evt.detail.url] = id;
}
moveTo = id;
w = this.findCurrentView(moveTo,registry.byId(evt.target.id)) || w; // the current view widget
}
w.performTransition(moveTo, evt.detail.transitionDir, evt.detail.transition, null, null);
},
_parse: function(text, id){
// summary:
// Parses the given view content.
// description:
// If the content is html fragment, constructs dom tree with it
// and runs the parser. If the content is json data, passes it
// to _instantiate().
var container, view, i, j, len;
var currentView = this.findCurrentView();
var target = registry.byId(id) && registry.byId(id).containerNode
|| dom.byId(id)
|| currentView && currentView.domNode.parentNode
|| win.body();
// if a fixed bottom bar exists, a new view should be placed before it.
var refNode = null;
for(j = target.childNodes.length - 1; j >= 0; j--){
var c = target.childNodes[j];
if(c.nodeType === 1){
if(c.getAttribute("fixed") === "bottom"){
refNode = c;
}
break;
}
}
if(text.charAt(0) === "<"){ // html markup
container = domConstruct.create("DIV", {innerHTML: text});
for(i = 0; i < container.childNodes.length; i++){
var n = container.childNodes[i];
if(n.nodeType === 1){
view = n; // expecting <div dojoType="dojox.mobile.View">
break;
}
}
if(!view){
console.log("dojox.mobile.ViewController#_parse: invalid view content");
return;
}
view.style.visibility = "hidden";
target.insertBefore(container, refNode);
var ws = dojo.parser.parse(container);
array.forEach(ws, function(w){
if(w && !w._started && w.startup){
w.startup();
}
});
// allows multiple root nodes in the fragment,
// but transition will be performed to the 1st view.
for(i = 0, len = container.childNodes.length; i < len; i++){
target.insertBefore(container.firstChild, refNode); // reparent
}
target.removeChild(container);
registry.byNode(view)._visible = true;
}else if(text.charAt(0) === "{"){ // json
container = domConstruct.create("DIV");
target.insertBefore(container, refNode);
this._ws = [];
view = this._instantiate(eval('('+text+')'), container);
for(i = 0; i < this._ws.length; i++){
var w = this._ws[i];
w.startup && !w._started && (!w.getParent || !w.getParent()) && w.startup();
}
this._ws = null;
}
view.style.display = "none";
view.style.visibility = "visible";
return dojo.hash ? "#" + view.id : view.id;
},
_instantiate: function(/*Object*/obj, /*DomNode*/node, /*Widget*/parent){
// summary:
// Given the evaluated json data, does the same thing as what
// the parser does.
var widget;
for(var key in obj){
if(key.charAt(0) == "@"){ continue; }
var cls = lang.getObject(key);
if(!cls){ continue; }
var params = {};
var proto = cls.prototype;
var objs = lang.isArray(obj[key]) ? obj[key] : [obj[key]];
for(var i = 0; i < objs.length; i++){
for(var prop in objs[i]){
if(prop.charAt(0) == "@"){
var val = objs[i][prop];
prop = prop.substring(1);
if(typeof proto[prop] == "string"){
params[prop] = val;
}else if(typeof proto[prop] == "number"){
params[prop] = val - 0;
}else if(typeof proto[prop] == "boolean"){
params[prop] = (val != "false");
}else if(typeof proto[prop] == "object"){
params[prop] = eval("(" + val + ")");
}
}
}
widget = new cls(params, node);
if(node){ // to call View's startup()
widget._visible = true;
this._ws.push(widget);
}
if(parent && parent.addChild){
parent.addChild(widget);
}
this._instantiate(objs[i], null, widget);
}
}
return widget && widget.domNode;
}
});
new Controller(); // singleton
return Controller;
});