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; });