if(!view && view.nodeType != 1){
alert("dojox.mobile.AbstractItem#transitionTo: invalid view content");
return;
}
view.setAttribute("_started", "true"); // to avoid startup() is called
view.style.visibility = "hidden";
target.appendChild(container);
(dojox.mobile.parser || dojo.parser).parse(container);
target.appendChild(target.removeChild(container).firstChild); // reparent
}else if(text.charAt(0) == "{"){ // json
target.appendChild(container);
this._ws = [];
view = this._instantiate(eval('('+text+')'), container);
for(var 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";
var id = view.id;
return dojo.hash ? "#" + id : id;
},
_instantiate: function(/*Object*/obj, /*DomNode*/node, /*Widget*/parent){
var widget;
for(var key in obj){
if(key.charAt(0) == "@"){ continue; }
var cls = dojo.getObject(key);
if(!cls){ continue; }
var params = {};
var proto = cls.prototype;
var objs = dojo.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){ // not to call View's startup()
this._ws.push(widget);
}
if(parent && parent.addChild){
parent.addChild(widget);
}
this._instantiate(objs[i], null, widget);
}
}
return widget && widget.domNode;
},
createDomButton: function(/*DomNode*/refNode, /*DomNode?*/toNode){
var s = refNode.className;
if(s.match(/mblDomButton\w+_(\d+)/)){
var nDiv = RegExp.$1 - 0;
for(var i = 0, p = (toNode||refNode); i < nDiv; i++){
p = dojo.create("DIV", null, p);
}
}
},
select: function(/*Boolean?*/deselect){
// subclass must implement
},
defaultClickAction: function(){
if(this.toggle){
this.select(this.selected);
}else if(!this.selected){
this.select();
if(!this.selectOne){
var _this = this;
setTimeout(function(){
_this.select(true);
}, this._duration);
}
if(this.moveTo || this.href || this.url || this.scene){
this.transitionTo(this.moveTo, this.href, this.url, this.scene);
}
}
},
getParentWidget: function(){
var ref = this.srcNodeRef || this.domNode;
return ref && ref.parentNode ? dijit.getEnclosingWidget(ref.parentNode) : null;
}
});
dojo.declare(
"dojox.mobile.ListItem",
dojox.mobile.AbstractItem,
{
rightText: "",
btnClass: "",
anchorLabel: false,
noArrow: false,
selected: false,
buildRendering: function(){
this.inheritParams();
var a = this.anchorNode = dojo.create("A");
a.className = "mblListItemAnchor";
var box = dojo.create("DIV");
box.className = "mblListItemTextBox";
if(this.anchorLabel){
box.style.cursor = "pointer";
}
var r = this.srcNodeRef;
if(r){
for(var i = 0, len = r.childNodes.length; i < len; i++){
box.appendChild(r.removeChild(r.firstChild));
}
}
if(this.label){
box.appendChild(dojo.doc.createTextNode(this.label));
}
a.appendChild(box);
if(this.rightText){
this._setRightTextAttr(this.rightText);
}
if(this.moveTo || this.href || this.url || this.clickable){
var parent = this.getParentWidget();
if(!this.noArrow && !(parent && parent.stateful)){
var arrow = dojo.create("DIV");
arrow.className = "mblArrow";
a.appendChild(arrow);
}
this.connect(a, "onclick", "onClick");
}else if(this.btnClass){
var div = this.btnNode = dojo.create("DIV");
div.className = this.btnClass+" mblRightButton";
div.appendChild(dojo.create("DIV"));
div.appendChild(dojo.create("P"));
var dummyDiv = dojo.create("DIV");
dummyDiv.className = "mblRightButtonContainer";
dummyDiv.appendChild(div);
a.appendChild(dummyDiv);
dojo.addClass(a, "mblListItemAnchorHasRightButton");
setTimeout(function(){
dummyDiv.style.width = div.offsetWidth + "px";
dummyDiv.style.height = div.offsetHeight + "px";
if(dojo.isIE){
// IE seems to ignore the height of LI without this..
a.parentNode.style.height = a.parentNode.offsetHeight + "px";
}
}, 0);
}
if(this.anchorLabel){
box.style.display = "inline"; // to narrow the text region
}
var li = this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("LI");
li.className = "mblListItem" + (this.selected ? " mblItemSelected" : "");
li.appendChild(a);
this.setIcon();
},
setIcon: function(){
if(this.iconNode){ return; }
var a = this.anchorNode;
if(this.icon && this.icon != "none"){
var img = this.iconNode = dojo.create("IMG");
img.className = "mblListItemIcon";
img.src = this.icon;
this.domNode.insertBefore(img, a);
dojox.mobile.setupIcon(this.iconNode, this.iconPos);
dojo.removeClass(a, "mblListItemAnchorNoIcon");
}else{
dojo.addClass(a, "mblListItemAnchorNoIcon");
}
},
onClick: function(e){
var a = e.currentTarget;
var li = a.parentNode;
if(dojo.hasClass(li, "mblItemSelected")){ return; } // already selected
if(this.anchorLabel){
for(var p = e.target; p.tagName != "LI"; p = p.parentNode){
if(p.className == "mblListItemTextBox"){
dojo.addClass(p, "mblListItemTextBoxSelected");
setTimeout(function(){
dojo.removeClass(p, "mblListItemTextBoxSelected");
}, 1000);
this.onAnchorLabelClicked(e);
return;
}
}
}
if(this.getParentWidget().stateful){
for(var i = 0, c = li.parentNode.childNodes; i < c.length; i++){
dojo.removeClass(c[i], "mblItemSelected");
}
}else{
setTimeout(function(){
dojo.removeClass(li, "mblItemSelected");
}, 1000);
}
dojo.addClass(li, "mblItemSelected");
this.transitionTo(this.moveTo, this.href, this.url, this.scene);
},
onAnchorLabelClicked: function(e){
},
_setRightTextAttr: function(/*String*/text){
this.rightText = text;
if(!this._rightTextNode){
this._rightTextNode = dojo.create("DIV", {className:"mblRightText"}, this.anchorNode);
}
this._rightTextNode.innerHTML = text;
}
});
dojo.declare(
"dojox.mobile.Switch",
dijit._WidgetBase,
{
value: "on",
leftLabel: "ON",
rightLabel: "OFF",
_width: 53,
buildRendering: function(){
this.domNode = this.srcNodeRef || dojo.doc.createElement("DIV");
this.domNode.className = "mblSwitch";
this.domNode.innerHTML =
'
'
+ '
'
+ '
'+this.leftLabel+'
'
+ '
'
+ '
'
+ '
'+this.rightLabel+'
'
+ '
'
+ '
'
+ '
';
var n = this.inner = this.domNode.firstChild;
this.left = n.childNodes[0];
this.right = n.childNodes[1];
this.knob = n.childNodes[2];
dojo.addClass(this.domNode, (this.value == "on") ? "mblSwitchOn" : "mblSwitchOff");
this[this.value == "off" ? "left" : "right"].style.display = "none";
},
postCreate: function(){
this.connect(this.knob, "onclick", "onClick");
this.connect(this.knob, "touchstart", "onTouchStart");
this.connect(this.knob, "mousedown", "onTouchStart");
},
_changeState: function(/*String*/state){
this.inner.style.left = "";
dojo.addClass(this.domNode, "mblSwitchAnimation");
dojo.removeClass(this.domNode, (state == "on") ? "mblSwitchOff" : "mblSwitchOn");
dojo.addClass(this.domNode, (state == "on") ? "mblSwitchOn" : "mblSwitchOff");
var _this = this;
setTimeout(function(){
_this[state == "off" ? "left" : "right"].style.display = "none";
dojo.removeClass(_this.domNode, "mblSwitchAnimation");
}, 300);
},
onClick: function(e){
if(this._moved){ return; }
this.value = (this.value == "on") ? "off" : "on";
this._changeState(this.value);
this.onStateChanged(this.value);
},
onTouchStart: function(e){
this._moved = false;
this.innerStartX = this.inner.offsetLeft;
if(e.targetTouches){
this.touchStartX = e.targetTouches[0].clientX;
this._conn1 = dojo.connect(this.inner, "touchmove", this, "onTouchMove");
this._conn2 = dojo.connect(this.inner, "touchend", this, "onTouchEnd");
}
this.left.style.display = "block";
this.right.style.display = "block";
dojo.stopEvent(e);
},
onTouchMove: function(e){
e.preventDefault();
var dx;
if(e.targetTouches){
if(e.targetTouches.length != 1){ return false; }
dx = e.targetTouches[0].clientX - this.touchStartX;
}else{
dx = e.clientX - this.touchStartX;
}
var pos = this.innerStartX + dx;
var d = 10;
if(pos <= -(this._width-d)){ pos = -this._width; }
if(pos >= -d){ pos = 0; }
this.inner.style.left = pos + "px";
this._moved = true;
},
onTouchEnd: function(e){
dojo.disconnect(this._conn1);
dojo.disconnect(this._conn2);
if(this.innerStartX == this.inner.offsetLeft){
if(dojo.isWebKit){
var ev = dojo.doc.createEvent("MouseEvents");
ev.initEvent("click", true, true);
this.knob.dispatchEvent(ev);
}
return;
}
var newState = (this.inner.offsetLeft < -(this._width/2)) ? "off" : "on";
this._changeState(newState);
if(newState != this.value){
this.value = newState;
this.onStateChanged(this.value);
}
},
onStateChanged: function(/*String*/newState){
}
});
dojo.declare(
"dojox.mobile.Button",
dijit._WidgetBase,
{
btnClass: "mblBlueButton",
duration: 1000, // duration of selection, milliseconds
label: null,
buildRendering: function(){
this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("BUTTON");
this.domNode.className = "mblButton "+this.btnClass;
if(this.label){
this.domNode.innerHTML = this.label;
}
this.connect(this.domNode, "onclick", "onClick");
},
onClick: function(e){
var button = this.domNode;
var c = "mblButtonSelected "+this.btnClass+"Selected";
dojo.addClass(button, c);
setTimeout(function(){
dojo.removeClass(button, c);
}, this.duration);
}
});
dojo.declare(
"dojox.mobile.ToolBarButton",
dojox.mobile.AbstractItem,
{
selected: false,
_defaultColor: "mblColorDefault",
_selColor: "mblColorDefaultSel",
buildRendering: function(){
this.inheritParams();
this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("div");
dojo.addClass(this.domNode, "mblToolbarButton mblArrowButtonText");
var color;
if(this.selected){
color = this._selColor;
}else if(this.domNode.className.indexOf("mblColor") == -1){
color = this._defaultColor;
}
dojo.addClass(this.domNode, color);
if(this.label){
this.domNode.innerHTML = this.label;
}else{
this.label = this.domNode.innerHTML;
}
if(this.icon && this.icon != "none"){
var img;
if(this.iconPos){
var iconDiv = dojo.create("DIV", null, this.domNode);
img = dojo.create("IMG", null, iconDiv);
img.style.position = "absolute";
var arr = this.iconPos.split(/[ ,]/);
dojo.style(iconDiv, {
position: "relative",
width: arr[2] + "px",
height: arr[3] + "px"
});
}else{
img = dojo.create("IMG", null, this.domNode);
}
img.src = this.icon;
dojox.mobile.setupIcon(img, this.iconPos);
this.iconNode = img;
}
this.createDomButton(this.domNode);
this.connect(this.domNode, "onclick", "onClick");
},
select: function(/*Boolean?*/deselect){
dojo.toggleClass(this.domNode, this._selColor, !deselect);
this.selected = !deselect;
},
onClick: function(e){
this.defaultClickAction();
}
});
dojo.declare(
"dojox.mobile.ProgressIndicator",
null,
{
interval: 100, // milliseconds
colors: [
"#C0C0C0", "#C0C0C0", "#C0C0C0", "#C0C0C0",
"#C0C0C0", "#C0C0C0", "#B8B9B8", "#AEAFAE",
"#A4A5A4", "#9A9A9A", "#8E8E8E", "#838383"
],
_bars: [],
constructor: function(){
this.domNode = dojo.create("DIV");
this.domNode.className = "mblProgContainer";
for(var i = 0; i < 12; i++){
var div = dojo.create("DIV");
div.className = "mblProg mblProg"+i;
this.domNode.appendChild(div);
this._bars.push(div);
}
},
start: function(){
var cntr = 0;
var _this = this;
this.timer = setInterval(function(){
cntr--;
cntr = cntr < 0 ? 11 : cntr;
var c = _this.colors;
for(var i = 0; i < 12; i++){
var idx = (cntr + i) % 12;
_this._bars[i].style.backgroundColor = c[idx];
}
}, this.interval);
},
stop: function(){
if(this.timer){
clearInterval(this.timer);
}
this.timer = null;
if(this.domNode.parentNode){
this.domNode.parentNode.removeChild(this.domNode);
}
}
});
dojox.mobile.ProgressIndicator._instance = null;
dojox.mobile.ProgressIndicator.getInstance = function(){
if(!dojox.mobile.ProgressIndicator._instance){
dojox.mobile.ProgressIndicator._instance = new dojox.mobile.ProgressIndicator();
}
return dojox.mobile.ProgressIndicator._instance;
};
dojox.mobile.addClass = function(){
// summary:
// Adds a theme class name to .
// description:
// Finds the currently applied theme name, such as 'iphone' or 'android'
// from link elements, and adds it as a class name for the body element.
var elems = document.getElementsByTagName("link");
for(var i = 0, len = elems.length; i < len; i++){
if(elems[i].href.match(/dojox\/mobile\/themes\/(\w+)\//)){
dojox.mobile.theme = RegExp.$1;
dojo.addClass(dojo.body(), dojox.mobile.theme);
break;
}
}
};
dojox.mobile.setupIcon = function(/*DomNode*/iconNode, /*String*/iconPos){
if(iconNode && iconPos){
var arr = dojo.map(iconPos.split(/[ ,]/),
function(item){ return item - 0; });
var t = arr[0]; // top
var r = arr[1] + arr[2]; // right
var b = arr[0] + arr[3]; // bottom
var l = arr[1]; // left
iconNode.style.clip = "rect("+t+"px "+r+"px "+b+"px "+l+"px)";
iconNode.style.top = dojo.style(iconNode, "top") - t + "px";
iconNode.style.left = dojo.style(iconNode.parentNode, "paddingLeft") - l + "px";
}
};
dojox.mobile.hideAddressBar = function(){
dojo.body().style.minHeight = "1000px"; // to ensure enough height for scrollTo to work
setTimeout(function(){ scrollTo(0, 1); }, 100);
setTimeout(function(){ scrollTo(0, 1); }, 400);
setTimeout(function(){
scrollTo(0, 1);
// re-define the min-height with the actual height
dojo.body().style.minHeight = (dojo.global.innerHeight||dojo.doc.documentElement.clientHeight) + "px";
}, 1000);
};
dojox.mobile.openWindow = function(url, target){
dojo.global.open(url, target || "_blank");
};
dojo._loaders.unshift(function(){
// avoid use of dojo.query
/*
var list = dojo.query('[lazy=true] [dojoType]', null);
list.forEach(function(node, index, nodeList){
node.setAttribute("__dojoType", node.getAttribute("dojoType"));
node.removeAttribute("dojoType");
});
*/
var nodes = dojo.body().getElementsByTagName("*");
var i, len, s;
len = nodes.length;
for(i = 0; i < len; i++){
s = nodes[i].getAttribute("dojoType");
if(s){
if(nodes[i].parentNode.getAttribute("lazy") == "true"){
nodes[i].setAttribute("__dojoType", s);
nodes[i].removeAttribute("dojoType");
}
}
}
});
dojo.addOnLoad(function(){
dojox.mobile.addClass();
if(dojo.config["mblApplyPageStyles"] !== false){
dojo.addClass(dojo.doc.documentElement, "mobile");
}
// You can disable hiding the address bar with the following djConfig.
// var djConfig = { mblHideAddressBar: false };
if(dojo.config["mblHideAddressBar"] !== false){
dojox.mobile.hideAddressBar();
if(dojo.config["mblAlwaysHideAddressBar"] == true){
if(dojo.global.onorientationchange !== undefined){
dojo.connect(dojo.global, "onorientationchange", dojox.mobile.hideAddressBar);
}else{
dojo.connect(dojo.global, "onresize", dojox.mobile.hideAddressBar);
}
}
}
// avoid use of dojo.query
/*
var list = dojo.query('[__dojoType]', null);
list.forEach(function(node, index, nodeList){
node.setAttribute("dojoType", node.getAttribute("__dojoType"));
node.removeAttribute("__dojoType");
});
*/
var nodes = dojo.body().getElementsByTagName("*");
var i, len = nodes.length, s;
for(i = 0; i < len; i++){
s = nodes[i].getAttribute("__dojoType");
if(s){
nodes[i].setAttribute("dojoType", s);
nodes[i].removeAttribute("__dojoType");
}
}
if(dojo.hash){
// find widgets under root recursively
var findWidgets = function(root){
var arr;
arr = dijit.findWidgets(root);
var widgets = arr;
for(var i = 0; i < widgets.length; i++){
arr = arr.concat(findWidgets(widgets[i].containerNode));
}
return arr;
};
dojo.subscribe("/dojo/hashchange", null, function(value){
var view = dojox.mobile.currentView;
if(!view){ return; }
var params = dojox.mobile._params;
if(!params){ // browser back/forward button was pressed
var moveTo = value ? value : dojox.mobile._defaultView.id;
var widgets = findWidgets(view.domNode);
var dir = 1, transition = "slide";
for(i = 0; i < widgets.length; i++){
var w = widgets[i];
if("#"+moveTo == w.moveTo){
// found a widget that has the given moveTo
transition = w.transition;
dir = (w instanceof dojox.mobile.Heading) ? -1 : 1;
break;
}
}
params = [ moveTo, dir, transition ];
}
view.performTransition.apply(view, params);
dojox.mobile._params = null;
});
}
dojo.body().style.visibility = "visible";
});
dijit.getEnclosingWidget = function(node){
while(node && node.tagName !== "BODY"){
if(node.getAttribute && node.getAttribute("widgetId")){
return dijit.registry.byId(node.getAttribute("widgetId"));
}
node = node._parentNode || node.parentNode;
}
return null;
};
}
if(!dojo._hasResource["dojox.mobile"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile"] = true;
dojo.provide("dojox.mobile");
dojo.experimental("dojox.mobile");
}
if(!dojo._hasResource["dojox.mobile.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.parser"] = true;
dojo.provide("dojox.mobile.parser");
dojo.provide("dojo.parser"); // not to load dojo.parser unexpectedly
dojox.mobile.parser = new function(){
this.instantiate = function(list, defaultParams){
// summary:
// Function for instantiating a list of widget nodes.
// list:
// The list of DOMNodes to walk and instantiate widgets on.
var ws = [];
if(list){
var i, len;
len = list.length;
for(i = 0; i < len; i++){
var node = list[i];
var cls = dojo.getObject(dojo.attr(node, "dojoType"));
var proto = cls.prototype;
var params = {};
if(defaultParams){
for(var name in defaultParams){
params[name] = defaultParams[name];
}
}
for(var prop in proto){
var val = dojo.attr(node, prop);
if(!val){ continue; }
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 + ")");
}
}
params["class"] = node.className;
params["style"] = node.style && node.style.cssText;
var instance = new cls(params, node);
ws.push(instance);
var jsId = node.getAttribute("jsId");
if(jsId){
dojo.setObject(jsId, instance);
}
}
len = ws.length;
for(i = 0; i < len; i++){
var w = ws[i];
w.startup && !w._started && (!w.getParent || !w.getParent()) && w.startup();
}
}
return ws;
};
this.parse = function(rootNode, defaultParams){
// summary:
// Function to handle parsing for widgets in the current document.
// It is not as powerful as the full dojo parser, but it will handle basic
// use cases fine.
// rootNode:
// The root node in the document to parse from
if(!rootNode){
rootNode = dojo.body();
}else if(!defaultParams && rootNode.rootNode){
// Case where 'rootNode' is really a params object.
rootNode = rootNode.rootNode;
}
var nodes = rootNode.getElementsByTagName("*");
var list = [];
for(var i = 0, len = nodes.length; i < len; i++){
if(nodes[i].getAttribute("dojoType")){
list.push(nodes[i]);
}
}
return this.instantiate(list, defaultParams);
};
}();
dojo._loaders.unshift(function(){
if(dojo.config.parseOnLoad){
dojox.mobile.parser.parse();
}
});
}
if(!dojo._hasResource["dojox.mobile.app._event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app._event"] = true;
dojo.provide("dojox.mobile.app._event");
dojo.experimental("dojox.mobile.app._event.js");
dojo.mixin(dojox.mobile.app, {
eventMap: {},
connectFlick: function(target, context, method){
// summary:
// Listens for a flick event on a DOM node. If the mouse/touch
// moves more than 15 pixels in any given direction it is a flick.
// The synthetic event fired specifies the direction as
//
// 'ltr' Left To Right
// 'rtl' Right To Left
// 'ttb' Top To Bottom
// 'btt' Bottom To Top
//
// target: Node
// The DOM node to connect to
var startX;
var startY;
var isFlick = false;
var currentX;
var currentY;
var connMove;
var connUp;
var direction;
var time;
// Listen to to the mousedown/touchstart event
var connDown = dojo.connect("onmousedown", target, function(event){
isFlick = false;
startX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
startY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
time = (new Date()).getTime();
connMove = dojo.connect(target, "onmousemove", onMove);
connUp = dojo.connect(target, "onmouseup", onUp);
});
// The function that handles the mousemove/touchmove event
var onMove = function(event){
dojo.stopEvent(event);
currentX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
currentY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
if(Math.abs(Math.abs(currentX) - Math.abs(startX)) > 15){
isFlick = true;
direction = (currentX > startX) ? "ltr" : "rtl";
}else if(Math.abs(Math.abs(currentY) - Math.abs(startY)) > 15){
isFlick = true;
direction = (currentY > startY) ? "ttb" : "btt";
}
};
var onUp = function(event){
dojo.stopEvent(event);
connMove && dojo.disconnect(connMove);
connUp && dojo.disconnect(connUp);
if(isFlick){
var flickEvt = {
target: target,
direction: direction,
duration: (new Date()).getTime() - time
};
if(context && method){
context[method](flickEvt);
}else{
method(flickEvt);
}
}
};
}
});
dojox.mobile.app.isIPhone = (dojo.isSafari
&& (navigator.userAgent.indexOf("iPhone") > -1 ||
navigator.userAgent.indexOf("iPod") > -1
));
dojox.mobile.app.isWebOS = (navigator.userAgent.indexOf("webOS") > -1);
dojox.mobile.app.isAndroid = (navigator.userAgent.toLowerCase().indexOf("android") > -1);
if(dojox.mobile.app.isIPhone || dojox.mobile.app.isAndroid){
// We are touchable.
// Override the dojo._connect function to replace mouse events with touch events
dojox.mobile.app.eventMap = {
onmousedown: "ontouchstart",
mousedown: "ontouchstart",
onmouseup: "ontouchend",
mouseup: "ontouchend",
onmousemove: "ontouchmove",
mousemove: "ontouchmove"
};
}
dojo._oldConnect = dojo._connect;
dojo._connect = function(obj, event, context, method, dontFix){
event = dojox.mobile.app.eventMap[event] || event;
if(event == "flick" || event == "onflick"){
if(dojo.global["Mojo"]){
event = Mojo.Event.flick;
}else{
return dojox.mobile.app.connectFlick(obj, context, method);
}
}
return dojo._oldConnect(obj, event, context, method, dontFix);
}
}
if(!dojo._hasResource["dojox.mobile.app._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app._Widget"] = true;
dojo.provide("dojox.mobile.app._Widget");
dojo.experimental("dojox.mobile.app._Widget");
dojo.declare("dojox.mobile.app._Widget", dijit._WidgetBase, {
// summary:
// The base mobile app widget.
getScroll: function(){
// summary:
// Returns the scroll position.
return {
x: dojo.global.scrollX,
y: dojo.global.scrollY
};
},
connect: function(target, event, fn){
if(event.toLowerCase() == "dblclick"
|| event.toLowerCase() == "ondblclick"){
if(dojo.global["Mojo"]){
// Handle webOS tap event
return this.connect(target, Mojo.Event.tap, fn);
}
}
return this.inherited(arguments);
}
});
}
if(!dojo._hasResource["dojox.mobile.app.SceneController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app.SceneController"] = true;
dojo.provide("dojox.mobile.app.SceneController");
dojo.experimental("dojox.mobile.app.SceneController");
(function(){
var app = dojox.mobile.app;
var templates = {};
dojo.declare("dojox.mobile.app.SceneController", dojox.mobile.View, {
stageController: null,
keepScrollPos: false,
init: function(sceneName, params){
// summary:
// Initializes the scene by loading the HTML template and code, if it has
// not already been loaded
this.sceneName = sceneName;
this.params = params;
var templateUrl = app.resolveTemplate(sceneName);
this._deferredInit = new dojo.Deferred();
if(templates[sceneName]){
// If the template has been cached, do not load it again.
this._setContents(templates[sceneName]);
}else{
// Otherwise load the template
dojo.xhrGet({
url: templateUrl,
handleAs: "text"
}).addCallback(dojo.hitch(this, this._setContents));
}
return this._deferredInit;
},
_setContents: function(templateHtml){
// summary:
// Sets the content of the View, and invokes either the loading or
// initialization of the scene assistant.
templates[this.sceneName] = templateHtml;
this.domNode.innerHTML = "
" + templateHtml + "
";
var sceneAssistantName = "";
var nameParts = this.sceneName.split("-");
for(var i = 0; i < nameParts.length; i++){
sceneAssistantName += nameParts[i].substring(0, 1).toUpperCase()
+ nameParts[i].substring(1);
}
sceneAssistantName += "Assistant";
this.sceneAssistantName = sceneAssistantName;
var _this = this;
dojox.mobile.app.loadResourcesForScene(this.sceneName, function(){
console.log("All resources for ",_this.sceneName," loaded");
var assistant;
if(typeof(dojo.global[sceneAssistantName]) != "undefined"){
_this._initAssistant();
}else{
var assistantUrl = app.resolveAssistant(_this.sceneName);
dojo.xhrGet({
url: assistantUrl,
handleAs: "text"
}).addCallback(function(text){
try{
dojo.eval(text);
}catch(e){
console.log("Error initializing code for scene " + _this.sceneName
+ '. Please check for syntax errors');
throw e;
}
_this._initAssistant();
});
}
});
},
_initAssistant: function(){
// summary:
// Initializes the scene assistant. At this point, the View is
// populated with the HTML template, and the scene assistant type
// is declared.
console.log("Instantiating the scene assistant " + this.sceneAssistantName);
var cls = dojo.getObject(this.sceneAssistantName);
if(!cls){
throw Error("Unable to resolve scene assistant "
+ this.sceneAssistantName);
}
this.assistant = new cls(this.params);
this.assistant.controller = this;
this.assistant.domNode = this.domNode.firstChild;
this.assistant.setup();
this._deferredInit.callback();
},
query: function(selector, node){
// summary:
// Queries for DOM nodes within either the node passed in as an argument
// or within this view.
return dojo.query(selector, node || this.domNode)
},
parse: function(node){
var widgets = this._widgets =
dojox.mobile.parser.parse(node || this.domNode, {
controller: this
});
// Tell all widgets what their controller is.
for(var i = 0; i < widgets.length; i++){
widgets[i].set("controller", this);
}
},
getWindowSize: function(){
// TODO, this needs cross browser testing
return {
w: dojo.global.innerWidth,
h: dojo.global.innerHeight
}
},
showAlertDialog: function(props){
var size = dojo.marginBox(this.assistant.domNode);
var dialog = new dojox.mobile.app.AlertDialog(
dojo.mixin(props, {controller: this}));
this.assistant.domNode.appendChild(dialog.domNode);
console.log("Appended " , dialog.domNode, " to ", this.assistant.domNode);
dialog.show();
},
popupSubMenu: function(info){
var widget = new dojox.mobile.app.ListSelector({
controller: this,
destroyOnHide: true,
onChoose: info.onChoose
});
this.assistant.domNode.appendChild(widget.domNode);
widget.set("data", info.choices);
widget.show(info.fromNode);
}
});
})();
}
if(!dojo._hasResource["dojox.mobile.app.StageController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app.StageController"] = true;
dojo.provide("dojox.mobile.app.StageController");
dojo.experimental("dojox.mobile.app.StageController");
dojo.declare("dojox.mobile.app.StageController", null,{
// scenes: Array
// The list of scenes currently in existance in the app.
scenes: null,
effect: "fade",
constructor: function(node){
this.domNode = node;
this.scenes = [];
if(dojo.config.mobileAnim){
this.effect = dojo.config.mobileAnim;
}
},
getActiveSceneController: function(){
return this.scenes[this.scenes.length - 1];
},
pushScene: function(sceneName, params){
if(this._opInProgress){
return;
}
this._opInProgress = true;
// Push new scenes as the first element on the page.
var node = dojo.create("div", {
"class": "scene-wrapper",
style: {
visibility: "hidden"
}
}, this.domNode);
var controller = new dojox.mobile.app.SceneController({}, node);
if(this.scenes.length > 0){
this.scenes[this.scenes.length -1].assistant.deactivate();
}
this.scenes.push(controller);
var _this = this;
dojo.forEach(this.scenes, this.setZIndex);
controller.stageController = this;
controller.init(sceneName, params).addCallback(function(){
if(_this.scenes.length == 1){
controller.domNode.style.visibility = "visible";
_this.scenes[_this.scenes.length - 1].assistant.activate(params);
_this._opInProgress = false;
}else{
_this.scenes[_this.scenes.length - 2]
.performTransition(
_this.scenes[_this.scenes.length - 1].domNode,
1,
_this.effect,
null,
function(){
// When the scene is ready, activate it.
_this.scenes[_this.scenes.length - 1].assistant.activate(params);
_this._opInProgress = false;
});
}
});
},
setZIndex: function(controller, idx){
dojo.style(controller.domNode, "zIndex", idx + 1);
},
popScene: function(data){
// performTransition: function(/*String*/moveTo, /*Number*/dir, /*String*/transition,
// /*Object|null*/context, /*String|Function*/method /*optional args*/){
if(this._opInProgress){
return;
}
var _this = this;
if(this.scenes.length > 1){
this._opInProgress = true;
this.scenes[_this.scenes.length - 2].assistant.activate(data);
this.scenes[_this.scenes.length - 1]
.performTransition(
_this.scenes[this.scenes.length - 2].domNode,
-1,
this.effect,
null,
function(){
// When the scene is no longer visible, destroy it
_this._destroyScene(_this.scenes[_this.scenes.length - 1]);
_this.scenes.splice(_this.scenes.length - 1, 1);
_this._opInProgress = false;
});
}else{
console.log("cannot pop the scene if there is just one");
}
},
popScenesTo: function(sceneName, data){
if(this._opInProgress){
return;
}
while(this.scenes.length > 2 &&
this.scenes[this.scenes.length - 2].sceneName != sceneName){
this._destroyScene(this.scenes[this.scenes.length - 2]);
this.scenes.splice(this.scenes.length - 2, 1);
}
this.popScene(data);
},
_destroyScene: function(scene){
scene.assistant.deactivate();
scene.assistant.destroy();
scene.destroyRecursive();
}
});
}
if(!dojo._hasResource["dojox.mobile.app.SceneAssistant"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app.SceneAssistant"] = true;
dojo.provide("dojox.mobile.app.SceneAssistant");
dojo.experimental("dojox.mobile.app.SceneAssistant");
dojo.declare("dojox.mobile.app.SceneAssistant", null, {
// summary:
// The base class for all scene assistants.
constructor: function(){
},
setup: function(){
// summary:
// Called to set up the widget. The UI is not visible at this time
},
activate: function(params){
// summary:
// Called each time the scene becomes visible. This can be as a result
// of a new scene being created, or a subsequent scene being destroyed
// and control transferring back to this scene assistant.
// params:
// Optional paramters, only passed when a subsequent scene pops itself
// off the stack and passes back data.
},
deactivate: function(){
// summary:
// Called each time the scene becomes invisible. This can be as a result
// of it being popped off the stack and destroyed,
// or another scene being created and pushed on top of it on the stack
},
destroy: function(){
var children =
dojo.query("> [widgetId]", this.containerNode).map(dijit.byNode);
dojo.forEach(children, function(child){ child.destroyRecursive(); });
this.disconnect();
},
connect: function(obj, method, callback){
if(!this._connects){
this._connects = [];
}
this._connects.push(dojo.connect(obj, method, callback));
},
disconnect: function(){
dojo.forEach(this._connects, dojo.disconnect);
this._connects = [];
}
});
}
if(!dojo._hasResource["dojox.mobile.app.AlertDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app.AlertDialog"] = true;
dojo.provide("dojox.mobile.app.AlertDialog");
dojo.experimental("dojox.mobile.app.AlertDialog");
dojo.declare("dojox.mobile.app.AlertDialog", dijit._WidgetBase, {
// title: String
// The title of the AlertDialog
title: "",
// text: String
// The text message displayed in the AlertDialog
text: "",
// controller: Object
// The SceneController for the currently active scene
controller: null,
// buttons: Array
buttons: null,
defaultButtonLabel: "OK",
// onChoose: Function
// The callback function that is invoked when a button is tapped.
// If the dialog is cancelled, no parameter is passed to this function.
onChoose: null,
constructor: function(){
this.onClick = dojo.hitch(this, this.onClick);
this._handleSelect = dojo.hitch(this, this._handleSelect);
},
buildRendering: function(){
this.domNode = dojo.create("div",{
"class": "alertDialog"
});
// Create the outer dialog body
var dlgBody = dojo.create("div", {"class": "alertDialogBody"}, this.domNode);
// Create the title
dojo.create("div", {"class": "alertTitle", innerHTML: this.title || ""}, dlgBody);
// Create the text
dojo.create("div", {"class": "alertText", innerHTML: this.text || ""}, dlgBody);
// Create the node that encapsulates all the buttons
var btnContainer = dojo.create("div", {"class": "alertBtns"}, dlgBody);
// If no buttons have been defined, default to a single button saying OK
if(!this.buttons || this.buttons.length == 0){
this.buttons = [{
label: this.defaultButtonLabel,
value: "ok",
"class": "affirmative"
}];
}
var _this = this;
// Create each of the buttons
dojo.forEach(this.buttons, function(btnInfo){
var btn = new dojox.mobile.Button({
btnClass: btnInfo["class"] || "",
label: btnInfo.label
});
btn._dialogValue = btnInfo.value;
dojo.place(btn.domNode, btnContainer);
_this.connect(btn, "onClick", _this._handleSelect);
});
var viewportSize = this.controller.getWindowSize();
// Create the mask that blocks out the rest of the screen
this.mask = dojo.create("div", {"class": "dialogUnderlayWrapper",
innerHTML: "
",
style: {
width: viewportSize.w + "px",
height: viewportSize.h + "px"
}
}, this.controller.assistant.domNode);
this.connect(this.mask, "onclick", function(){
_this.onChoose && _this.onChoose();
_this.hide();
});
},
postCreate: function(){
this.subscribe("/dojox/mobile/app/goback", this._handleSelect);
},
_handleSelect: function(event){
// summary:
// Handle the selection of a value
var node;
console.log("handleSelect");
if(event && event.target){
node = event.target;
// Find the widget that was tapped.
while(!dijit.byNode(node)){
node - node.parentNode;
}
}
// If an onChoose function was provided, tell it what button
// value was chosen
if(this.onChoose){
this.onChoose(node ? dijit.byNode(node)._dialogValue: undefined);
}
// Hide the dialog
this.hide();
},
show: function(){
// summary:
// Show the dialog
this._doTransition(1);
},
hide: function(){
// summary:
// Hide the dialog
this._doTransition(-1);
},
_doTransition: function(dir){
// summary:
// Either shows or hides the dialog.
// dir:
// An integer. If positive, the dialog is shown. If negative,
// the dialog is hidden.
// TODO: replace this with CSS transitions
var anim;
var h = dojo.marginBox(this.domNode.firstChild).h;
var bodyHeight = this.controller.getWindowSize().h;
console.log("dialog height = " + h, " body height = " + bodyHeight);
var high = bodyHeight - h;
var low = bodyHeight;
var anim1 = dojo.fx.slideTo({
node: this.domNode,
duration: 400,
top: {start: dir < 0 ? high : low, end: dir < 0 ? low: high}
});
var anim2 = dojo[dir < 0 ? "fadeOut" : "fadeIn"]({
node: this.mask,
duration: 400
});
var anim = dojo.fx.combine([anim1, anim2]);
var _this = this;
dojo.connect(anim, "onEnd", this, function(){
if(dir < 0){
_this.domNode.style.display = "none";
dojo.destroy(_this.domNode);
dojo.destroy(_this.mask);
}
});
anim.play();
},
destroy: function(){
this.inherited(arguments);
dojo.destroy(this.mask);
},
onClick: function(){
}
});
}
if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.string"] = true;
dojo.provide("dojo.string");
dojo.getObject("string", true, dojo);
/*=====
dojo.string = {
// summary: String utilities for Dojo
};
=====*/
dojo.string.rep = function(/*String*/str, /*Integer*/num){
// summary:
// Efficiently replicate a string `n` times.
// str:
// the string to replicate
// num:
// number of times to replicate the string
if(num <= 0 || !str){ return ""; }
var buf = [];
for(;;){
if(num & 1){
buf.push(str);
}
if(!(num >>= 1)){ break; }
str += str;
}
return buf.join(""); // String
};
dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
// summary:
// Pad a string to guarantee that it is at least `size` length by
// filling with the character `ch` at either the start or end of the
// string. Pads at the start, by default.
// text:
// the string to pad
// size:
// length to provide padding
// ch:
// character to pad, defaults to '0'
// end:
// adds padding at the end if true, otherwise pads at start
// example:
// | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++".
// | dojo.string.pad("Dojo", 10, "+", true);
if(!ch){
ch = '0';
}
var out = String(text),
pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
return end ? out + pad : pad + out; // String
};
dojo.string.substitute = function( /*String*/ template,
/*Object|Array*/map,
/*Function?*/ transform,
/*Object?*/ thisObject){
// summary:
// Performs parameterized substitutions on a string. Throws an
// exception if any parameter is unmatched.
// template:
// a string with expressions in the form `${key}` to be replaced or
// `${key:format}` which specifies a format function. keys are case-sensitive.
// map:
// hash to search for substitutions
// transform:
// a function to process all parameters before substitution takes
// place, e.g. mylib.encodeXML
// thisObject:
// where to look for optional format function; default to the global
// namespace
// example:
// Substitutes two expressions in a string from an Array or Object
// | // returns "File 'foo.html' is not found in directory '/temp'."
// | // by providing substitution data in an Array
// | dojo.string.substitute(
// | "File '${0}' is not found in directory '${1}'.",
// | ["foo.html","/temp"]
// | );
// |
// | // also returns "File 'foo.html' is not found in directory '/temp'."
// | // but provides substitution data in an Object structure. Dotted
// | // notation may be used to traverse the structure.
// | dojo.string.substitute(
// | "File '${name}' is not found in directory '${info.dir}'.",
// | { name: "foo.html", info: { dir: "/temp" } }
// | );
// example:
// Use a transform function to modify the values:
// | // returns "file 'foo.html' is not found in directory '/temp'."
// | dojo.string.substitute(
// | "${0} is not found in ${1}.",
// | ["foo.html","/temp"],
// | function(str){
// | // try to figure out the type
// | var prefix = (str.charAt(0) == "/") ? "directory": "file";
// | return prefix + " '" + str + "'";
// | }
// | );
// example:
// Use a formatter
// | // returns "thinger -- howdy"
// | dojo.string.substitute(
// | "${0:postfix}", ["thinger"], null, {
// | postfix: function(value, key){
// | return value + " -- howdy";
// | }
// | }
// | );
thisObject = thisObject || dojo.global;
transform = transform ?
dojo.hitch(thisObject, transform) : function(v){ return v; };
return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
function(match, key, format){
var value = dojo.getObject(key, false, map);
if(format){
value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
}
return transform(value, key).toString();
}); // String
};
/*=====
dojo.string.trim = function(str){
// summary:
// Trims whitespace from both sides of the string
// str: String
// String to be trimmed
// returns: String
// Returns the trimmed string
// description:
// This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
// The short yet performant version of this function is dojo.trim(),
// which is part of Dojo base. Uses String.prototype.trim instead, if available.
return ""; // String
}
=====*/
dojo.string.trim = String.prototype.trim ?
dojo.trim : // aliasing to the native function
function(str){
str = str.replace(/^\s+/, '');
for(var i = str.length - 1; i >= 0; i--){
if(/\S/.test(str.charAt(i))){
str = str.substring(0, i + 1);
break;
}
}
return str;
};
}
if(!dojo._hasResource["dojox.mobile.app.List"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app.List"] = true;
dojo.provide("dojox.mobile.app.List");
dojo.experimental("dojox.mobile.app.List");
(function(){
var templateCache = {};
dojo.declare("dojox.mobile.app.List", dijit._WidgetBase, {
// summary:
// A templated list widget. Given a simple array of data objects
// and a HTML template, it renders a list of elements, with
// support for a swipe delete action. An optional template
// can be provided for when the list is empty.
// items: Array
// The array of data items that will be rendered.
items: null,
// itemTemplate: String
// The URL to the HTML file containing the markup for each individual
// data item.
itemTemplate: "",
// emptyTemplate: String
// The URL to the HTML file containing the HTML to display if there
// are no data items. This is optional.
emptyTemplate: "",
// dividerTemplate: String
// The URL to the HTML file containing the markup for the dividers
// between groups of list items
dividerTemplate: "",
// dividerFunction: Function
// Function to create divider elements. This should return a divider
// value for each item in the list
dividerFunction: null,
// labelDelete: String
// The label to display for the Delete button
labelDelete: "Delete",
// labelCancel: String
// The label to display for the Cancel button
labelCancel: "Cancel",
// controller: Object
//
controller: null,
// autoDelete: Boolean
autoDelete: true,
// enableDelete: Boolean
enableDelete: true,
// enableHold: Boolean
enableHold: true,
// formatters: Object
// A name/value map of functions used to format data for display
formatters: null,
// _templateLoadCount: Number
// The number of templates remaining to load before the list renders.
_templateLoadCount: 0,
// _mouseDownPos: Object
// The coordinates of where a mouseDown event was detected
_mouseDownPos: null,
baseClass: "list",
constructor: function(){
this._checkLoadComplete = dojo.hitch(this, this._checkLoadComplete);
this._replaceToken = dojo.hitch(this, this._replaceToken);
this._postDeleteAnim = dojo.hitch(this, this._postDeleteAnim);
},
postCreate: function(){
var _this = this;
if(this.emptyTemplate){
this._templateLoadCount++;
}
if(this.itemTemplate){
this._templateLoadCount++;
}
if(this.dividerTemplate){
this._templateLoadCount++;
}
this.connect(this.domNode, "onmousedown", function(event){
var touch = event;
if(event.targetTouches && event.targetTouches.length > 0){
touch = event.targetTouches[0];
}
// Find the node that was tapped/clicked
var rowNode = _this._getRowNode(event.target);
if(rowNode){
// Add the rows data to the event so it can be picked up
// by any listeners
_this._setDataInfo(rowNode, event);
// Select and highlight the row
_this._selectRow(rowNode);
// Record the position that was tapped
_this._mouseDownPos = {
x: touch.pageX,
y: touch.pageY
};
_this._dragThreshold = null;
}
});
this.connect(this.domNode, "onmouseup", function(event){
// When the mouse/finger comes off the list,
// call the onSelect function and deselect the row.
if(event.targetTouches && event.targetTouches.length > 0){
event = event.targetTouches[0];
}
var rowNode = _this._getRowNode(event.target);
if(rowNode){
_this._setDataInfo(rowNode, event);
if(_this._selectedRow){
_this.onSelect(rowNode._data, rowNode._idx, rowNode);
}
this._deselectRow();
}
});
// If swipe-to-delete is enabled, listen for the mouse moving
if(this.enableDelete){
this.connect(this.domNode, "mousemove", function(event){
dojo.stopEvent(event);
if(!_this._selectedRow){
return;
}
var rowNode = _this._getRowNode(event.target);
// Still check for enableDelete in case it's changed after
// this listener is added.
if(_this.enableDelete && rowNode && !_this._deleting){
_this.handleDrag(event);
}
});
}
// Put the data and index onto each onclick event.
this.connect(this.domNode, "onclick", function(event){
if(event.touches && event.touches.length > 0){
event = event.touches[0];
}
var rowNode = _this._getRowNode(event.target, true);
if(rowNode){
_this._setDataInfo(rowNode, event);
}
});
// If the mouse or finger moves off the selected row,
// deselect it.
this.connect(this.domNode, "mouseout", function(event){
if(event.touches && event.touches.length > 0){
event = event.touches[0];
}
if(event.target == _this._selectedRow){
_this._deselectRow();
}
});
// If no item template has been provided, it is an error.
if(!this.itemTemplate){
throw Error("An item template must be provided to " + this.declaredClass);
}
// Load the item template
this._loadTemplate(this.itemTemplate, "itemTemplate", this._checkLoadComplete);
if(this.emptyTemplate){
// If the optional empty template has been provided, load it.
this._loadTemplate(this.emptyTemplate, "emptyTemplate", this._checkLoadComplete);
}
if(this.dividerTemplate){
this._loadTemplate(this.dividerTemplate, "dividerTemplate", this._checkLoadComplete);
}
},
handleDrag: function(event){
// summary:
// Handles rows being swiped for deletion.
var touch = event;
if(event.targetTouches && event.targetTouches.length > 0){
touch = event.targetTouches[0];
}
// Get the distance that the mouse or finger has moved since
// beginning the swipe action.
var diff = touch.pageX - this._mouseDownPos.x;
var absDiff = Math.abs(diff);
if(absDiff > 10 && !this._dragThreshold){
// Make the user drag the row 60% of the width to remove it
this._dragThreshold = dojo.marginBox(this._selectedRow).w * 0.6;
if(!this.autoDelete){
this.createDeleteButtons(this._selectedRow);
}
}
this._selectedRow.style.left = (absDiff > 10 ? diff : 0) + "px";
// If the user has dragged the row more than the threshold, slide
// it off the screen in preparation for deletion.
if(this._dragThreshold && this._dragThreshold < absDiff){
this.preDelete(diff);
}
},
handleDragCancel: function(){
// summary:
// Handle a drag action being cancelled, for whatever reason.
// Reset handles, remove CSS classes etc.
if(this._deleting){
return;
}
dojo.removeClass(this._selectedRow, "hold");
this._selectedRow.style.left = 0;
this._mouseDownPos = null;
this._dragThreshold = null;
this._deleteBtns && dojo.style(this._deleteBtns, "display", "none");
},
preDelete: function(currentLeftPos){
// summary:
// Slides the row offscreen before it is deleted
// TODO: do this with CSS3!
var self = this;
this._deleting = true;
dojo.animateProperty({
node: this._selectedRow,
duration: 400,
properties: {
left: {
end: currentLeftPos +
((currentLeftPos > 0 ? 1 : -1) * this._dragThreshold * 0.8)
}
},
onEnd: dojo.hitch(this, function(){
if(this.autoDelete){
this.deleteRow(this._selectedRow);
}
})
}).play();
},
deleteRow: function(row){
// First make the row invisible
// Put it back where it came from
dojo.style(row, {
visibility: "hidden",
minHeight: "0px"
});
dojo.removeClass(row, "hold");
this._deleteAnimConn =
this.connect(row, "webkitAnimationEnd", this._postDeleteAnim);
dojo.addClass(row, "collapsed");
},
_postDeleteAnim: function(event){
// summary:
// Completes the deletion of a row.
if(this._deleteAnimConn){
this.disconnect(this._deleteAnimConn);
this._deleteAnimConn = null;
}
var row = this._selectedRow;
var sibling = row.nextSibling;
var prevSibling = row.previousSibling;
// If the previous node is a divider and either this is
// the last element in the list, or the next node is
// also a divider, remove the divider for the deleted section.
if(prevSibling && prevSibling._isDivider){
if(!sibling || sibling._isDivider){
prevSibling.parentNode.removeChild(prevSibling);
}
}
row.parentNode.removeChild(row);
this.onDelete(row._data, row._idx, this.items);
// Decrement the index of each following row
while(sibling){
if(sibling._idx){
sibling._idx--;
}
sibling = sibling.nextSibling;
}
dojo.destroy(row);
// Fix up the 'first' and 'last' CSS classes on the rows
dojo.query("> *:not(.buttons)", this.domNode).forEach(this.applyClass);
this._deleting = false;
this._deselectRow();
},
createDeleteButtons: function(aroundNode){
// summary:
// Creates the two buttons displayed when confirmation is
// required before deletion of a row.
// aroundNode:
// The DOM node of the row about to be deleted.
var mb = dojo.marginBox(aroundNode);
var pos = dojo._abs(aroundNode, true);
if(!this._deleteBtns){
// Create the delete buttons.
this._deleteBtns = dojo.create("div",{
"class": "buttons"
}, this.domNode);
this.buttons = [];
this.buttons.push(new dojox.mobile.Button({
btnClass: "mblRedButton",
label: this.labelDelete
}));
this.buttons.push(new dojox.mobile.Button({
btnClass: "mblBlueButton",
label: this.labelCancel
}));
dojo.place(this.buttons[0].domNode, this._deleteBtns);
dojo.place(this.buttons[1].domNode, this._deleteBtns);
dojo.addClass(this.buttons[0].domNode, "deleteBtn");
dojo.addClass(this.buttons[1].domNode, "cancelBtn");
this._handleButtonClick = dojo.hitch(this._handleButtonClick);
this.connect(this._deleteBtns, "onclick", this._handleButtonClick);
}
dojo.removeClass(this._deleteBtns, "fade out fast");
dojo.style(this._deleteBtns, {
display: "",
width: mb.w + "px",
height: mb.h + "px",
top: (aroundNode.offsetTop) + "px",
left: "0px"
});
},
onDelete: function(data, index, array){
// summary:
// Called when a row is deleted
// data:
// The data related to the row being deleted
// index:
// The index of the data in the total array
// array:
// The array of data used.
array.splice(index, 1);
// If the data is empty, rerender in case an emptyTemplate has
// been provided
if(array.length < 1){
this.render();
}
},
cancelDelete: function(){
// summary:
// Cancels the deletion of a row.
this._deleting = false;
this.handleDragCancel();
},
_handleButtonClick: function(event){
// summary:
// Handles the click of one of the deletion buttons, either to
// delete the row or to cancel the deletion.
if(event.touches && event.touches.length > 0){
event = event.touches[0];
}
var node = event.target;
if(dojo.hasClass(node, "deleteBtn")){
this.deleteRow(this._selectedRow);
}else if(dojo.hasClass(node, "cancelBtn")){
this.cancelDelete();
}else{
return;
}
dojo.addClass(this._deleteBtns, "fade out");
},
applyClass: function(node, idx, array){
// summary:
// Applies the 'first' and 'last' CSS classes to the relevant
// rows.
dojo.removeClass(node, "first last");
if(idx == 0){
dojo.addClass(node, "first");
}
if(idx == array.length - 1){
dojo.addClass(node, "last");
}
},
_setDataInfo: function(rowNode, event){
// summary:
// Attaches the data item and index for each row to any event
// that occurs on that row.
event.item = rowNode._data;
event.index = rowNode._idx;
},
onSelect: function(data, index, rowNode){
// summary:
// Dummy function that is called when a row is tapped
},
_selectRow: function(row){
// summary:
// Selects a row, applies the relevant CSS classes.
if(this._deleting && this._selectedRow && row != this._selectedRow){
this.cancelDelete();
}
if(!dojo.hasClass(row, "row")){
return;
}
if(this.enableHold || this.enableDelete){
dojo.addClass(row, "hold");
}
this._selectedRow = row;
},
_deselectRow: function(){
// summary:
// Deselects a row, and cancels any drag actions that were
// occurring.
if(!this._selectedRow || this._deleting){
return;
}
this.handleDragCancel();
dojo.removeClass(this._selectedRow, "hold");
this._selectedRow = null;
},
_getRowNode: function(fromNode, ignoreNoClick){
// summary:
// Gets the DOM node of the row that is equal to or the parent
// of the node passed to this function.
while(fromNode && !fromNode._data && fromNode != this.domNode){
if(!ignoreNoClick && dojo.hasClass(fromNode, "noclick")){
return null;
}
fromNode = fromNode.parentNode;
}
return fromNode == this.domNode ? null : fromNode;
},
applyTemplate: function(template, data){
return dojo._toDom(dojo.string.substitute(
template, data, this._replaceToken, this.formatters || this));
},
render: function(){
// summary:
// Renders the list.
// Delete all existing nodes, except the deletion buttons.
dojo.query("> *:not(.buttons)", this.domNode).forEach(dojo.destroy);
// If there is no data, and an empty template has been provided,
// render it.
if(this.items.length < 1 && this.emptyTemplate){
dojo.place(dojo._toDom(this.emptyTemplate), this.domNode, "first");
}else{
this.domNode.appendChild(this._renderRange(0, this.items.length));
}
if(dojo.hasClass(this.domNode.parentNode, "mblRoundRect")){
dojo.addClass(this.domNode.parentNode, "mblRoundRectList")
}
var divs = dojo.query("> .row", this.domNode);
if(divs.length > 0){
dojo.addClass(divs[0], "first");
dojo.addClass(divs[divs.length - 1], "last");
}
},
_renderRange: function(startIdx, endIdx){
var rows = [];
var row, i;
var frag = document.createDocumentFragment();
startIdx = Math.max(0, startIdx);
endIdx = Math.min(endIdx, this.items.length);
for(i = startIdx; i < endIdx; i++){
// Create a document fragment containing the templated row
row = this.applyTemplate(this.itemTemplate, this.items[i]);
dojo.addClass(row, 'row');
row._data = this.items[i];
row._idx = i;
rows.push(row);
}
if(!this.dividerFunction || !this.dividerTemplate){
for(i = startIdx; i < endIdx; i++){
rows[i]._data = this.items[i];
rows[i]._idx = i;
frag.appendChild(rows[i]);
}
}else{
var prevDividerValue = null;
var dividerValue;
var divider;
for(i = startIdx; i < endIdx; i++){
rows[i]._data = this.items[i];
rows[i]._idx = i;
dividerValue = this.dividerFunction(this.items[i]);
if(dividerValue && dividerValue != prevDividerValue){
divider = this.applyTemplate(this.dividerTemplate, {
label: dividerValue,
item: this.items[i]
});
divider._isDivider = true;
frag.appendChild(divider);
prevDividerValue = dividerValue;
}
frag.appendChild(rows[i]);
}
}
return frag;
},
_replaceToken: function(value, key){
if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); }
if(typeof value == "undefined"){ return ""; } // a debugging aide
if(value == null){ return ""; }
// Substitution keys beginning with ! will skip the transform step,
// in case a user wishes to insert unescaped markup, e.g. ${!foo}
return key.charAt(0) == "!" ? value :
// Safer substitution, see heading "Attribute values" in
// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
value.toString().replace(/"/g,"""); //TODO: add &? use encodeXML method?
},
_checkLoadComplete: function(){
// summary:
// Checks if all templates have loaded
this._templateLoadCount--;
if(this._templateLoadCount < 1 && this.get("items")){
this.render();
}
},
_loadTemplate: function(url, thisAttr, callback){
// summary:
// Loads a template
if(!url){
callback();
return;
}
if(templateCache[url]){
this.set(thisAttr, templateCache[url]);
callback();
}else{
var _this = this;
dojo.xhrGet({
url: url,
sync: false,
handleAs: "text",
load: function(text){
templateCache[url] = dojo.trim(text);
_this.set(thisAttr, templateCache[url]);
callback();
}
});
}
},
_setFormattersAttr: function(formatters){
// summary:
// Sets the data items, and causes a rerender of the list
this.formatters = formatters;
},
_setItemsAttr: function(items){
// summary:
// Sets the data items, and causes a rerender of the list
this.items = items || [];
if(this._templateLoadCount < 1 && items){
this.render();
}
},
destroy: function(){
if(this.buttons){
dojo.forEach(this.buttons, function(button){
button.destroy();
});
this.buttons = null;
}
this.inherited(arguments);
}
});
})();
}
if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.fx.Toggler"] = true;
dojo.provide("dojo.fx.Toggler");
dojo.declare("dojo.fx.Toggler", null, {
// summary:
// A simple `dojo.Animation` toggler API.
//
// description:
// class constructor for an animation toggler. It accepts a packed
// set of arguments about what type of animation to use in each
// direction, duration, etc. All available members are mixed into
// these animations from the constructor (for example, `node`,
// `showDuration`, `hideDuration`).
//
// example:
// | var t = new dojo.fx.Toggler({
// | node: "nodeId",
// | showDuration: 500,
// | // hideDuration will default to "200"
// | showFunc: dojo.fx.wipeIn,
// | // hideFunc will default to "fadeOut"
// | });
// | t.show(100); // delay showing for 100ms
// | // ...time passes...
// | t.hide();
// node: DomNode
// the node to target for the showing and hiding animations
node: null,
// showFunc: Function
// The function that returns the `dojo.Animation` to show the node
showFunc: dojo.fadeIn,
// hideFunc: Function
// The function that returns the `dojo.Animation` to hide the node
hideFunc: dojo.fadeOut,
// showDuration:
// Time in milliseconds to run the show Animation
showDuration: 200,
// hideDuration:
// Time in milliseconds to run the hide Animation
hideDuration: 200,
// FIXME: need a policy for where the toggler should "be" the next
// time show/hide are called if we're stopped somewhere in the
// middle.
// FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
// each animation individually.
// FIXME: also would be nice to have events from the animations exposed/bridged
/*=====
_showArgs: null,
_showAnim: null,
_hideArgs: null,
_hideAnim: null,
_isShowing: false,
_isHiding: false,
=====*/
constructor: function(args){
var _t = this;
dojo.mixin(_t, args);
_t.node = args.node;
_t._showArgs = dojo.mixin({}, args);
_t._showArgs.node = _t.node;
_t._showArgs.duration = _t.showDuration;
_t.showAnim = _t.showFunc(_t._showArgs);
_t._hideArgs = dojo.mixin({}, args);
_t._hideArgs.node = _t.node;
_t._hideArgs.duration = _t.hideDuration;
_t.hideAnim = _t.hideFunc(_t._hideArgs);
dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true));
dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true));
},
show: function(delay){
// summary: Toggle the node to showing
// delay: Integer?
// Ammount of time to stall playing the show animation
return this.showAnim.play(delay || 0);
},
hide: function(delay){
// summary: Toggle the node to hidden
// delay: Integer?
// Ammount of time to stall playing the hide animation
return this.hideAnim.play(delay || 0);
}
});
}
if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.fx"] = true;
dojo.provide("dojo.fx");
/*=====
dojo.fx = {
// summary: Effects library on top of Base animations
};
=====*/
(function(){
var d = dojo,
_baseObj = {
_fire: function(evt, args){
if(this[evt]){
this[evt].apply(this, args||[]);
}
return this;
}
};
var _chain = function(animations){
this._index = -1;
this._animations = animations||[];
this._current = this._onAnimateCtx = this._onEndCtx = null;
this.duration = 0;
d.forEach(this._animations, function(a){
this.duration += a.duration;
if(a.delay){ this.duration += a.delay; }
}, this);
};
d.extend(_chain, {
_onAnimate: function(){
this._fire("onAnimate", arguments);
},
_onEnd: function(){
d.disconnect(this._onAnimateCtx);
d.disconnect(this._onEndCtx);
this._onAnimateCtx = this._onEndCtx = null;
if(this._index + 1 == this._animations.length){
this._fire("onEnd");
}else{
// switch animations
this._current = this._animations[++this._index];
this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
this._current.play(0, true);
}
},
play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
if(!this._current){ this._current = this._animations[this._index = 0]; }
if(!gotoStart && this._current.status() == "playing"){ return this; }
var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){
this._fire("beforeBegin");
}),
onBegin = d.connect(this._current, "onBegin", this, function(arg){
this._fire("onBegin", arguments);
}),
onPlay = d.connect(this._current, "onPlay", this, function(arg){
this._fire("onPlay", arguments);
d.disconnect(beforeBegin);
d.disconnect(onBegin);
d.disconnect(onPlay);
});
if(this._onAnimateCtx){
d.disconnect(this._onAnimateCtx);
}
this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
if(this._onEndCtx){
d.disconnect(this._onEndCtx);
}
this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
this._current.play.apply(this._current, arguments);
return this;
},
pause: function(){
if(this._current){
var e = d.connect(this._current, "onPause", this, function(arg){
this._fire("onPause", arguments);
d.disconnect(e);
});
this._current.pause();
}
return this;
},
gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
this.pause();
var offset = this.duration * percent;
this._current = null;
d.some(this._animations, function(a){
if(a.duration <= offset){
this._current = a;
return true;
}
offset -= a.duration;
return false;
});
if(this._current){
this._current.gotoPercent(offset / this._current.duration, andPlay);
}
return this;
},
stop: function(/*boolean?*/ gotoEnd){
if(this._current){
if(gotoEnd){
for(; this._index + 1 < this._animations.length; ++this._index){
this._animations[this._index].stop(true);
}
this._current = this._animations[this._index];
}
var e = d.connect(this._current, "onStop", this, function(arg){
this._fire("onStop", arguments);
d.disconnect(e);
});
this._current.stop();
}
return this;
},
status: function(){
return this._current ? this._current.status() : "stopped";
},
destroy: function(){
if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
}
});
d.extend(_chain, _baseObj);
dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
// summary:
// Chain a list of `dojo.Animation`s to run in sequence
//
// description:
// Return a `dojo.Animation` which will play all passed
// `dojo.Animation` instances in sequence, firing its own
// synthesized events simulating a single animation. (eg:
// onEnd of this animation means the end of the chain,
// not the individual animations within)
//
// example:
// Once `node` is faded out, fade in `otherNode`
// | dojo.fx.chain([
// | dojo.fadeIn({ node:node }),
// | dojo.fadeOut({ node:otherNode })
// | ]).play();
//
return new _chain(animations) // dojo.Animation
};
var _combine = function(animations){
this._animations = animations||[];
this._connects = [];
this._finished = 0;
this.duration = 0;
d.forEach(animations, function(a){
var duration = a.duration;
if(a.delay){ duration += a.delay; }
if(this.duration < duration){ this.duration = duration; }
this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
}, this);
this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
var self = this;
d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
function(evt){
self._connects.push(d.connect(self._pseudoAnimation, evt,
function(){ self._fire(evt, arguments); }
));
}
);
};
d.extend(_combine, {
_doAction: function(action, args){
d.forEach(this._animations, function(a){
a[action].apply(a, args);
});
return this;
},
_onEnd: function(){
if(++this._finished > this._animations.length){
this._fire("onEnd");
}
},
_call: function(action, args){
var t = this._pseudoAnimation;
t[action].apply(t, args);
},
play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
this._finished = 0;
this._doAction("play", arguments);
this._call("play", arguments);
return this;
},
pause: function(){
this._doAction("pause", arguments);
this._call("pause", arguments);
return this;
},
gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
var ms = this.duration * percent;
d.forEach(this._animations, function(a){
a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
});
this._call("gotoPercent", arguments);
return this;
},
stop: function(/*boolean?*/ gotoEnd){
this._doAction("stop", arguments);
this._call("stop", arguments);
return this;
},
status: function(){
return this._pseudoAnimation.status();
},
destroy: function(){
d.forEach(this._connects, dojo.disconnect);
}
});
d.extend(_combine, _baseObj);
dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
// summary:
// Combine a list of `dojo.Animation`s to run in parallel
//
// description:
// Combine an array of `dojo.Animation`s to run in parallel,
// providing a new `dojo.Animation` instance encompasing each
// animation, firing standard animation events.
//
// example:
// Fade out `node` while fading in `otherNode` simultaneously
// | dojo.fx.combine([
// | dojo.fadeIn({ node:node }),
// | dojo.fadeOut({ node:otherNode })
// | ]).play();
//
// example:
// When the longest animation ends, execute a function:
// | var anim = dojo.fx.combine([
// | dojo.fadeIn({ node: n, duration:700 }),
// | dojo.fadeOut({ node: otherNode, duration: 300 })
// | ]);
// | dojo.connect(anim, "onEnd", function(){
// | // overall animation is done.
// | });
// | anim.play(); // play the animation
//
return new _combine(animations); // dojo.Animation
};
dojo.fx.wipeIn = function(/*Object*/ args){
// summary:
// Expand a node to it's natural height.
//
// description:
// Returns an animation that will expand the
// node defined in 'args' object from it's current height to
// it's natural height (with no scrollbar).
// Node must have no margin/border/padding.
//
// args: Object
// A hash-map of standard `dojo.Animation` constructor properties
// (such as easing: node: duration: and so on)
//
// example:
// | dojo.fx.wipeIn({
// | node:"someId"
// | }).play()
var node = args.node = d.byId(args.node), s = node.style, o;
var anim = d.animateProperty(d.mixin({
properties: {
height: {
// wrapped in functions so we wait till the last second to query (in case value has changed)
start: function(){
// start at current [computed] height, but use 1px rather than 0
// because 0 causes IE to display the whole panel
o = s.overflow;
s.overflow = "hidden";
if(s.visibility == "hidden" || s.display == "none"){
s.height = "1px";
s.display = "";
s.visibility = "";
return 1;
}else{
var height = d.style(node, "height");
return Math.max(height, 1);
}
},
end: function(){
return node.scrollHeight;
}
}
}
}, args));
d.connect(anim, "onEnd", function(){
s.height = "auto";
s.overflow = o;
});
return anim; // dojo.Animation
};
dojo.fx.wipeOut = function(/*Object*/ args){
// summary:
// Shrink a node to nothing and hide it.
//
// description:
// Returns an animation that will shrink node defined in "args"
// from it's current height to 1px, and then hide it.
//
// args: Object
// A hash-map of standard `dojo.Animation` constructor properties
// (such as easing: node: duration: and so on)
//
// example:
// | dojo.fx.wipeOut({ node:"someId" }).play()
var node = args.node = d.byId(args.node), s = node.style, o;
var anim = d.animateProperty(d.mixin({
properties: {
height: {
end: 1 // 0 causes IE to display the whole panel
}
}
}, args));
d.connect(anim, "beforeBegin", function(){
o = s.overflow;
s.overflow = "hidden";
s.display = "";
});
d.connect(anim, "onEnd", function(){
s.overflow = o;
s.height = "auto";
s.display = "none";
});
return anim; // dojo.Animation
};
dojo.fx.slideTo = function(/*Object*/ args){
// summary:
// Slide a node to a new top/left position
//
// description:
// Returns an animation that will slide "node"
// defined in args Object from its current position to
// the position defined by (args.left, args.top).
//
// args: Object
// A hash-map of standard `dojo.Animation` constructor properties
// (such as easing: node: duration: and so on). Special args members
// are `top` and `left`, which indicate the new position to slide to.
//
// example:
// | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
var node = args.node = d.byId(args.node),
top = null, left = null;
var init = (function(n){
return function(){
var cs = d.getComputedStyle(n);
var pos = cs.position;
top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
if(pos != 'absolute' && pos != 'relative'){
var ret = d.position(n, true);
top = ret.y;
left = ret.x;
n.style.position="absolute";
n.style.top=top+"px";
n.style.left=left+"px";
}
};
})(node);
init();
var anim = d.animateProperty(d.mixin({
properties: {
top: args.top || 0,
left: args.left || 0
}
}, args));
d.connect(anim, "beforeBegin", anim, init);
return anim; // dojo.Animation
};
})();
}
if(!dojo._hasResource["dojox.mobile.app.ListSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app.ListSelector"] = true;
dojo.provide("dojox.mobile.app.ListSelector");
dojo.experimental("dojox.mobile.app.ListSelector");
dojo.declare("dojox.mobile.app.ListSelector", dojox.mobile.app._Widget, {
// data: Array
// The array of items to display. Each element in the array
// should have both a label and value attribute, e.g.
// [{label: "Open", value: 1} , {label: "Delete", value: 2}]
data: null,
// controller: Object
// The current SceneController widget.
controller: null,
// onChoose: Function
// The callback function for when an item is selected
onChoose: null,
destroyOnHide: false,
_setDataAttr: function(data){
this.data = data;
if(this.data){
this.render();
}
},
postCreate: function(){
dojo.addClass(this.domNode, "listSelector");
var _this = this;
this.connect(this.domNode, "onclick", function(event){
if(!dojo.hasClass(event.target, "listSelectorRow")){
return;
}
if(_this.onChoose){
_this.onChoose(_this.data[event.target._idx].value);
}
_this.hide();
});
this.connect(this.domNode, "onmousedown", function(event){
if(!dojo.hasClass(event.target, "listSelectorRow")){
return;
}
dojo.addClass(event.target, "listSelectorRow-selected");
});
this.connect(this.domNode, "onmouseup", function(event){
if(!dojo.hasClass(event.target, "listSelectorRow")){
return;
}
dojo.removeClass(event.target, "listSelectorRow-selected");
});
this.connect(this.domNode, "onmouseout", function(event){
if(!dojo.hasClass(event.target, "listSelectorRow")){
return;
}
dojo.removeClass(event.target, "listSelectorRow-selected");
});
var viewportSize = this.controller.getWindowSize();
this.mask = dojo.create("div", {"class": "dialogUnderlayWrapper",
innerHTML: "
"
}, this.controller.assistant.domNode);
this.connect(this.mask, "onclick", function(){
_this.onChoose && _this.onChoose();
_this.hide();
});
},
show: function(fromNode){
// Using dojo.fx here. Must figure out how to do this with CSS animations!!
var startPos;
var windowSize = this.controller.getWindowSize();
var fromNodePos;
if(fromNode){
fromNodePos = dojo._abs(fromNode);
startPos = fromNodePos;
}else{
startPos.x = windowSize.w / 2;
startPos.y = 200;
}
console.log("startPos = ", startPos);
dojo.style(this.domNode, {
opacity: 0,
display: "",
width: Math.floor(windowSize.w * 0.8) + "px"
});
var maxWidth = 0;
dojo.query(">", this.domNode).forEach(function(node){
dojo.style(node, {
"float": "left"
});
maxWidth = Math.max(maxWidth, dojo.marginBox(node).w);
dojo.style(node, {
"float": "none"
});
});
maxWidth = Math.min(maxWidth, Math.round(windowSize.w * 0.8))
+ dojo.style(this.domNode, "paddingLeft")
+ dojo.style(this.domNode, "paddingRight")
+ 1;
dojo.style(this.domNode, "width", maxWidth + "px");
var targetHeight = dojo.marginBox(this.domNode).h;
var _this = this;
var targetY = fromNodePos ?
Math.max(30, fromNodePos.y - targetHeight - 10) :
this.getScroll().y + 30;
console.log("fromNodePos = ", fromNodePos, " targetHeight = ", targetHeight,
" targetY = " + targetY, " startPos ", startPos);
var anim1 = dojo.animateProperty({
node: this.domNode,
duration: 400,
properties: {
width: {start: 1, end: maxWidth},
height: {start: 1, end: targetHeight},
top: {start: startPos.y, end: targetY},
left: {start: startPos.x, end: (windowSize.w/2 - maxWidth/2)},
opacity: {start: 0, end: 1},
fontSize: {start: 1}
},
onEnd: function(){
dojo.style(_this.domNode, "width", "inherit");
}
});
var anim2 = dojo.fadeIn({
node: this.mask,
duration: 400
});
dojo.fx.combine([anim1, anim2]).play();
},
hide: function(){
// Using dojo.fx here. Must figure out how to do this with CSS animations!!
var _this = this;
var anim1 = dojo.animateProperty({
node: this.domNode,
duration: 500,
properties: {
width: {end: 1},
height: {end: 1},
opacity: {end: 0},
fontSize: {end: 1}
},
onEnd: function(){
if(_this.get("destroyOnHide")){
_this.destroy();
}
}
});
var anim2 = dojo.fadeOut({
node: this.mask,
duration: 400
});
dojo.fx.combine([anim1, anim2]).play();
},
render: function(){
// summary:
// Renders
dojo.empty(this.domNode);
dojo.style(this.domNode, "opacity", 0);
var row;
for(var i = 0; i < this.data.length; i++){
// Create each row and add any custom classes. Also set the _idx property.
row = dojo.create("div", {
"class": "listSelectorRow " + (this.data[i].className || ""),
innerHTML: this.data[i].label
}, this.domNode);
row._idx = i;
if(i == 0){
dojo.addClass(row, "first");
}
if(i == this.data.length - 1){
dojo.addClass(row, "last");
}
}
},
destroy: function(){
this.inherited(arguments);
dojo.destroy(this.mask);
}
});
}
if(!dojo._hasResource["dojox.mobile.app._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.mobile.app._FormWidget"] = true;
dojo.provide("dojox.mobile.app._FormWidget");
dojo.experimental("dojox.mobile.app._FormWidget");
dojo.declare("dojox.mobile.app._FormWidget", dijit._WidgetBase, {
// summary:
// Base class for widgets corresponding to native HTML elements such as
or ,
// which can be children of a