define("dojox/mobile/ListItem", [
"dojo/_base/array",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/dom-class",
"dojo/dom-construct",
"dojo/dom-style",
"dijit/registry",
"dijit/_WidgetBase",
"./iconUtils",
"./_ItemBase",
"./ProgressIndicator"
], function(array, declare, lang, domClass, domConstruct, domStyle, registry, WidgetBase, iconUtils, ItemBase, ProgressIndicator){
// module:
// dojox/mobile/ListItem
var ListItem = declare("dojox.mobile.ListItem", ItemBase, {
// summary:
// An item of either RoundRectList or EdgeToEdgeList.
// description:
// ListItem represents an item of either RoundRectList or
// EdgeToEdgeList. There are three ways to move to a different view:
// moveTo, href, and url. You can choose only one of them.
//
// A child DOM node (or widget) can have the layout attribute,
// whose value is "left", "right", or "center". Such nodes will be
// aligned as specified.
// example:
// |
// | Left Node
// | Right Node
// | Center Node
// |
//
// Note that even if you specify variableHeight="true" for the list
// and place a tall object inside the layout node as in the example
// below, the layout node does not expand as you may expect,
// because layout node is aligned using float:left, float:right, or
// position:absolute.
// example:
// |
// |
// |
// rightText: String
// A right-aligned text to display on the item.
rightText: "",
// rightIcon: String
// An icon to display at the right hand side of the item. The value
// can be either a path for an image file or a class name of a DOM
// button.
rightIcon: "",
// rightIcon2: String
// An icon to display at the left of the rightIcon. The value can
// be either a path for an image file or a class name of a DOM
// button.
rightIcon2: "",
// deleteIcon: String
// A delete icon to display at the left of the item. The value can
// be either a path for an image file or a class name of a DOM
// button.
deleteIcon: "",
// anchorLabel: Boolean
// If true, the label text becomes a clickable anchor text. When
// the user clicks on the text, the onAnchorLabelClicked handler is
// called. You can override or connect to the handler and implement
// any action. The handler has no default action.
anchorLabel: false,
// noArrow: Boolean
// If true, the right hand side arrow is not displayed.
noArrow: false,
// checked: Boolean
// If true, a check mark is displayed at the right of the item.
checked: false,
// arrowClass: String
// An icon to display as an arrow. The value can be either a path
// for an image file or a class name of a DOM button.
arrowClass: "",
// checkClass: String
// An icon to display as a check mark. The value can be either a
// path for an image file or a class name of a DOM button.
checkClass: "",
// uncheckClass: String
// An icon to display as an uncheck mark. The value can be either a
// path for an image file or a class name of a DOM button.
uncheckClass: "",
// variableHeight: Boolean
// If true, the height of the item varies according to its
// content. In dojo 1.6 or older, the "mblVariableHeight" class was
// used for this purpose. In dojo 1.7, adding the mblVariableHeight
// class still works for backward compatibility.
variableHeight: false,
// rightIconTitle: String
// An alt text for the right icon.
rightIconTitle: "",
// rightIcon2Title: String
// An alt text for the right icon2.
rightIcon2Title: "",
// header: Boolean
// If true, this item is rendered as a category header.
header: false,
// tag: String
// A name of html tag to create as domNode.
tag: "li",
// busy: Boolean
// If true, a progress indicator spins.
busy: false,
// progStyle: String
// A css class name to add to the progress indicator.
progStyle: "",
/* internal properties */
// The following properties are overrides of those in _ItemBase.
paramsToInherit: "variableHeight,transition,deleteIcon,icon,rightIcon,rightIcon2,uncheckIcon,arrowClass,checkClass,uncheckClass,deleteIconTitle,deleteIconRole",
baseClass: "mblListItem",
_selStartMethod: "touch",
_selEndMethod: "timer",
_delayedSelection: true,
_selClass: "mblListItemSelected",
buildRendering: function(){
this.domNode = this.containerNode = this.srcNodeRef || domConstruct.create(this.tag);
this.inherited(arguments);
if(this.selected){
domClass.add(this.domNode, this._selClass);
}
if(this.header){
domClass.replace(this.domNode, "mblEdgeToEdgeCategory", this.baseClass);
}
this.labelNode =
domConstruct.create("div", {className:"mblListItemLabel"});
var ref = this.srcNodeRef;
if(ref && ref.childNodes.length === 1 && ref.firstChild.nodeType === 3){
// if ref has only one text node, regard it as a label
this.labelNode.appendChild(ref.firstChild);
}
this.domNode.appendChild(this.labelNode);
if(this.anchorLabel){
this.labelNode.style.display = "inline"; // to narrow the text region
this.labelNode.style.cursor = "pointer";
this._anchorClickHandle = this.connect(this.labelNode, "onclick", "_onClick");
this.onTouchStart = function(e){
return (e.target !== this.labelNode);
};
}
this._layoutChildren = [];
},
startup: function(){
if(this._started){ return; }
var parent = this.getParent();
var opts = this.getTransOpts();
if(opts.moveTo || opts.href || opts.url || this.clickable || (parent && parent.select)){
this._keydownHandle = this.connect(this.domNode, "onkeydown", "_onClick"); // for desktop browsers
}else{
this._handleClick = false;
}
this.inherited(arguments);
if(domClass.contains(this.domNode, "mblVariableHeight")){
this.variableHeight = true;
}
if(this.variableHeight){
domClass.add(this.domNode, "mblVariableHeight");
this.defer(lang.hitch(this, "layoutVariableHeight"), 0);
}
if(!this._isOnLine){
this._isOnLine = true;
this.set({ // retry applying the attribute
icon: this.icon,
deleteIcon: this.deleteIcon,
rightIcon: this.rightIcon,
rightIcon2: this.rightIcon2
});
}
if(parent && parent.select){
this.set("checked", this.checked); // retry applying the attribute
}
this.setArrow();
this.layoutChildren();
},
layoutChildren: function(){
var centerNode;
array.forEach(this.domNode.childNodes, function(n){
if(n.nodeType !== 1){ return; }
var layout = n.getAttribute("layout") || (registry.byNode(n) || {}).layout;
if(layout){
domClass.add(n, "mblListItemLayout" +
layout.charAt(0).toUpperCase() + layout.substring(1));
this._layoutChildren.push(n);
if(layout === "center"){ centerNode = n; }
}
}, this);
if(centerNode){
this.domNode.insertBefore(centerNode, this.domNode.firstChild);
}
},
resize: function(){
if(this.variableHeight){
this.layoutVariableHeight();
}
// If labelNode is empty, shrink it so as not to prevent user clicks.
this.labelNode.style.display = this.labelNode.firstChild ? "block" : "inline";
},
_onTouchStart: function(e){
// tags:
// private
if(e.target.getAttribute("preventTouch") ||
(registry.getEnclosingWidget(e.target) || {}).preventTouch){
return;
}
this.inherited(arguments);
},
_onClick: function(e){
// summary:
// Internal handler for click events.
// tags:
// private
if(this.getParent().isEditing || e && e.type === "keydown" && e.keyCode !== 13){ return; }
if(this.onClick(e) === false){ return; } // user's click action
var n = this.labelNode;
if(this.anchorLabel && e.currentTarget === n){
domClass.add(n, "mblListItemLabelSelected");
setTimeout(function(){
domClass.remove(n, "mblListItemLabelSelected");
}, this._duration);
this.onAnchorLabelClicked(e);
return;
}
var parent = this.getParent();
if(parent.select){
if(parent.select === "single"){
if(!this.checked){
this.set("checked", true);
}
}else if(parent.select === "multiple"){
this.set("checked", !this.checked);
}
}
this.defaultClickAction(e);
},
onClick: function(/*Event*/ /*===== e =====*/){
// summary:
// User-defined function to handle clicks.
// tags:
// callback
},
onAnchorLabelClicked: function(e){
// summary:
// Stub function to connect to from your application.
},
layoutVariableHeight: function(){
// summary:
// Lays out the current item with variable height.
var h = this.domNode.offsetHeight;
if(h === this.domNodeHeight){ return; }
this.domNodeHeight = h;
array.forEach(this._layoutChildren.concat([
this.rightTextNode,
this.rightIcon2Node,
this.rightIconNode,
this.uncheckIconNode,
this.iconNode,
this.deleteIconNode,
this.knobIconNode
]), function(n){
if(n){
var domNode = this.domNode;
var f = function(){
var t = Math.round((domNode.offsetHeight - n.offsetHeight) / 2) -
domStyle.get(domNode, "paddingTop");
n.style.marginTop = t + "px";
}
if(n.offsetHeight === 0 && n.tagName === "IMG"){
n.onload = f;
}else{
f();
}
}
}, this);
},
setArrow: function(){
// summary:
// Sets the arrow icon if necessary.
if(this.checked){ return; }
var c = "";
var parent = this.getParent();
var opts = this.getTransOpts();
if(opts.moveTo || opts.href || opts.url || this.clickable){
if(!this.noArrow && !(parent && parent.selectOne)){
c = this.arrowClass || "mblDomButtonArrow";
}
}
if(c){
this._setRightIconAttr(c);
}
},
_findRef: function(/*String*/type){
// summary:
// Find an appropriate position to insert a new child node.
// tags:
// private
var i, node, list = ["deleteIcon", "icon", "rightIcon", "uncheckIcon", "rightIcon2", "rightText"];
for(i = array.indexOf(list, type) + 1; i < list.length; i++){
node = this[list[i] + "Node"];
if(node){ return node; }
}
for(i = list.length - 1; i >= 0; i--){
node = this[list[i] + "Node"];
if(node){ return node.nextSibling; }
}
return this.domNode.firstChild;
},
_setIcon: function(/*String*/icon, /*String*/type){
// tags:
// private
if(!this._isOnLine){ return; } // icon may be invalid because inheritParams is not called yet
this._set(type, icon);
this[type + "Node"] = iconUtils.setIcon(icon, this[type + "Pos"],
this[type + "Node"], this[type + "Title"] || this.alt, this.domNode, this._findRef(type), "before");
if(this[type + "Node"]){
var cap = type.charAt(0).toUpperCase() + type.substring(1);
domClass.add(this[type + "Node"], "mblListItem" + cap);
}
var role = this[type + "Role"];
if(role){
this[type + "Node"].setAttribute("role", role);
}
},
_setDeleteIconAttr: function(/*String*/icon){
// tags:
// private
this._setIcon(icon, "deleteIcon");
},
_setIconAttr: function(icon){
// tags:
// private
this._setIcon(icon, "icon");
},
_setRightTextAttr: function(/*String*/text){
// tags:
// private
if(!this.rightTextNode){
this.rightTextNode = domConstruct.create("div", {className:"mblListItemRightText"}, this.labelNode, "before");
}
this.rightText = text;
this.rightTextNode.innerHTML = this._cv ? this._cv(text) : text;
},
_setRightIconAttr: function(/*String*/icon){
// tags:
// private
this._setIcon(icon, "rightIcon");
},
_setUncheckIconAttr: function(/*String*/icon){
// tags:
// private
this._setIcon(icon, "uncheckIcon");
},
_setRightIcon2Attr: function(/*String*/icon){
// tags:
// private
this._setIcon(icon, "rightIcon2");
},
_setCheckedAttr: function(/*Boolean*/checked){
// tags:
// private
if(!this._isOnLine){ return; } // icon may be invalid because inheritParams is not called yet
var parent = this.getParent();
if(parent && parent.select === "single" && checked){
array.forEach(parent.getChildren(), function(child){
child !== this && child.checked && child.set("checked", false);
}, this);
}
this._setRightIconAttr(this.checkClass || "mblDomButtonCheck");
this._setUncheckIconAttr(this.uncheckClass);
domClass.toggle(this.domNode, "mblListItemChecked", checked);
domClass.toggle(this.domNode, "mblListItemUnchecked", !checked);
domClass.toggle(this.domNode, "mblListItemHasUncheck", !!this.uncheckIconNode);
this.rightIconNode.style.position = (this.uncheckIconNode && !checked) ? "absolute" : "";
if(parent && this.checked !== checked){
parent.onCheckStateChanged(this, checked);
}
this._set("checked", checked);
},
_setBusyAttr: function(/*Boolean*/busy){
// tags:
// private
var prog = this._prog;
if(busy){
if(!this._progNode){
this._progNode = domConstruct.create("div", {className:"mblListItemIcon"});
prog = this._prog = new ProgressIndicator({size:25, center:false});
domClass.add(prog.domNode, this.progStyle);
this._progNode.appendChild(prog.domNode);
}
if(this.iconNode){
this.domNode.replaceChild(this._progNode, this.iconNode);
}else{
domConstruct.place(this._progNode, this._findRef("icon"), "before");
}
prog.start();
}else{
if(this.iconNode){
this.domNode.replaceChild(this.iconNode, this._progNode);
}else{
this.domNode.removeChild(this._progNode);
}
prog.stop();
}
this._set("busy", busy);
},
_setSelectedAttr: function(/*Boolean*/selected){
// summary:
// Makes this widget in the selected or unselected state.
// tags:
// private
this.inherited(arguments);
domClass.toggle(this.domNode, this._selClass, selected);
}
});
ListItem.ChildWidgetProperties = {
// summary:
// These properties can be specified for the children of a dojox/mobile/ListItem.
// layout: String
// Specifies the position of the ListItem child ("left", "center" or "right").
layout: "",
// preventTouch: Boolean
// Disables touch events on the ListItem child.
preventTouch: false
};
// Since any widget can be specified as a ListItem child, mix ChildWidgetProperties
// into the base widget class. (This is a hack, but it's effective.)
// This is for the benefit of the parser. Remove for 2.0. Also, hide from doc viewer.
lang.extend(WidgetBase, /*===== {} || =====*/ ListItem.ChildWidgetProperties);
return ListItem;
});