400 lines
11 KiB
JavaScript
400 lines
11 KiB
JavaScript
define("dojox/mobile/IconItem", [
|
|
"dojo/_base/declare",
|
|
"dojo/_base/event",
|
|
"dojo/_base/lang",
|
|
"dojo/_base/sniff",
|
|
"dojo/_base/window",
|
|
"dojo/dom-class",
|
|
"dojo/dom-construct",
|
|
"dojo/dom-geometry",
|
|
"dojo/dom-style",
|
|
"./_ItemBase",
|
|
"./Badge",
|
|
"./TransitionEvent",
|
|
"./iconUtils",
|
|
"./lazyLoadUtils",
|
|
"./viewRegistry"
|
|
], function(declare, event, lang, has, win, domClass, domConstruct, domGeometry, domStyle, ItemBase, Badge, TransitionEvent, iconUtils, lazyLoadUtils, viewRegistry){
|
|
|
|
// module:
|
|
// dojox/mobile/IconItem
|
|
|
|
return declare("dojox.mobile.IconItem", ItemBase, {
|
|
// summary:
|
|
// An icon item widget.
|
|
// description:
|
|
// IconItem represents an item that has an application component
|
|
// and its icon image. You can tap the icon to open the
|
|
// corresponding application component. You can also use the icon
|
|
// to move to a different view by specifying either of the moveTo,
|
|
// href or url parameters.
|
|
|
|
// lazy: String
|
|
// If true, the content of the widget, which includes dojo markup,
|
|
// is instantiated lazily. That is, only when the widget is opened
|
|
// by the user, the required modules are loaded and the content
|
|
// widgets are instantiated.
|
|
// This option works both in the sync and async loader mode.
|
|
lazy: false,
|
|
|
|
// requires: String
|
|
// Comma-separated required module names to be lazily loaded. This
|
|
// property is effective only when lazy=true. All the modules
|
|
// specified with data-dojo-type and their depending modules are
|
|
// automatically loaded by the IconItem when it is opened.
|
|
// However, if you need other extra modules to be loaded, use this parameter.
|
|
// This option works both in the sync and async loader mode.
|
|
requires: "",
|
|
|
|
// timeout: String
|
|
// Duration of highlight in seconds.
|
|
timeout: 10,
|
|
|
|
// content: String
|
|
// An HTML fragment to embed as icon content.
|
|
content: "",
|
|
|
|
// badge: String
|
|
// A text to show in a badge (ex. "55").
|
|
badge: "",
|
|
|
|
// badgeClass: String
|
|
// A class name of a DOM button for a badge.
|
|
badgeClass: "mblDomButtonRedBadge",
|
|
|
|
// deletable: Boolean
|
|
// If true, you can delete this IconItem by clicking on the delete
|
|
// icon during edit mode.
|
|
// If false, the delete icon is not displayed during edit mode so
|
|
// that it cannot be deleted.
|
|
deletable: true,
|
|
|
|
// deleteIcon: String
|
|
// A delete icon to display at the top-left corner of the item
|
|
// during edit mode. The value can be either a path for an image
|
|
// file or a class name of a DOM button.
|
|
deleteIcon: "",
|
|
|
|
// tag: String
|
|
// A name of the HTML tag to create as domNode.
|
|
tag: "li",
|
|
|
|
/* internal properties */
|
|
// Note these are overrides for similar properties defined in _ItemBase.
|
|
paramsToInherit: "transition,icon,deleteIcon,badgeClass,deleteIconTitle,deleteIconRole",
|
|
baseClass: "mblIconItem",
|
|
_selStartMethod: "touch",
|
|
_selEndMethod: "none",
|
|
|
|
destroy: function(){
|
|
if(this.badgeObj){
|
|
delete this.badgeObj;
|
|
}
|
|
this.inherited(arguments);
|
|
},
|
|
|
|
buildRendering: function(){
|
|
this.domNode = this.srcNodeRef || domConstruct.create(this.tag);
|
|
|
|
if(this.srcNodeRef){
|
|
// reparent
|
|
this._tmpNode = domConstruct.create("div");
|
|
for(var i = 0, len = this.srcNodeRef.childNodes.length; i < len; i++){
|
|
this._tmpNode.appendChild(this.srcNodeRef.firstChild);
|
|
}
|
|
}
|
|
|
|
this.iconDivNode = domConstruct.create("div", {className:"mblIconArea"}, this.domNode);
|
|
this.iconParentNode = domConstruct.create("div", {className:"mblIconAreaInner"}, this.iconDivNode);
|
|
this.labelNode = domConstruct.create("span", {className:"mblIconAreaTitle"}, this.iconDivNode);
|
|
|
|
this.inherited(arguments);
|
|
},
|
|
|
|
startup: function(){
|
|
if(this._started){ return; }
|
|
|
|
var p = this.getParent();
|
|
require([p.iconItemPaneClass], lang.hitch(this, function(module){
|
|
var w = this.paneWidget = new module(p.iconItemPaneProps);
|
|
this.containerNode = w.containerNode;
|
|
if(this._tmpNode){
|
|
// reparent
|
|
for(var i = 0, len = this._tmpNode.childNodes.length; i < len; i++){
|
|
w.containerNode.appendChild(this._tmpNode.firstChild);
|
|
}
|
|
this._tmpNode = null;
|
|
}
|
|
p.paneContainerWidget.addChild(w, this.getIndexInParent());
|
|
w.set("label", this.label);
|
|
this._clickCloseHandle = this.connect(w.closeIconNode, "onclick", "_closeIconClicked");
|
|
this._keydownCloseHandle = this.connect(w.closeIconNode, "onkeydown", "_closeIconClicked"); // for desktop browsers
|
|
}));
|
|
|
|
this.inherited(arguments);
|
|
if(!this._isOnLine){
|
|
this._isOnLine = true;
|
|
// retry applying the attribute for which the custom setter delays the actual
|
|
// work until _isOnLine is true.
|
|
this.set("icon", this._pendingIcon !== undefined ? this._pendingIcon : this.icon);
|
|
// Not needed anymore (this code executes only once per life cycle):
|
|
delete this._pendingIcon;
|
|
}
|
|
if(!this.icon && p.defaultIcon){
|
|
this.set("icon", p.defaultIcon);
|
|
}
|
|
|
|
this._dragstartHandle = this.connect(this.domNode, "ondragstart", event.stop);
|
|
this._keydownHandle = this.connect(this.domNode, "onkeydown", "_onClick"); // for desktop browsers
|
|
},
|
|
|
|
highlight: function(/*Number?*/timeout){
|
|
// summary:
|
|
// Shakes the icon 10 seconds.
|
|
domClass.add(this.iconDivNode, "mblVibrate");
|
|
timeout = (timeout !== undefined) ? timeout : this.timeout;
|
|
if(timeout > 0){
|
|
var _this = this;
|
|
setTimeout(function(){
|
|
_this.unhighlight();
|
|
}, timeout*1000);
|
|
}
|
|
},
|
|
|
|
unhighlight: function(){
|
|
// summary:
|
|
// Stops shaking the icon.
|
|
domClass.remove(this.iconDivNode, "mblVibrate");
|
|
},
|
|
|
|
isOpen: function(e){
|
|
// summary:
|
|
// Returns true if the icon is open.
|
|
return this.paneWidget.isOpen();
|
|
},
|
|
|
|
_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
|
|
this.defaultClickAction(e);
|
|
},
|
|
|
|
onClick: function(/*Event*/ /*===== e =====*/){
|
|
// summary:
|
|
// User-defined function to handle clicks.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
_onNewWindowOpened: function(e){
|
|
// Override from _ItemBase
|
|
this.set("selected", false);
|
|
},
|
|
|
|
_prepareForTransition: function(e, transOpts){
|
|
// Override from _ItemBase
|
|
if(transOpts){
|
|
setTimeout(lang.hitch(this, function(d){
|
|
this.set("selected", false);
|
|
}), 1500);
|
|
return true;
|
|
}else{
|
|
if(this.getParent().transition === "below" && this.isOpen()){
|
|
this.close();
|
|
}else{
|
|
this.open(e);
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
|
|
_closeIconClicked: function(e){
|
|
// summary:
|
|
// Internal handler for click events.
|
|
// tags:
|
|
// private
|
|
if(e){
|
|
if(e.type === "keydown" && e.keyCode !== 13){ return; }
|
|
if(this.closeIconClicked(e) === false){ return; } // user's click action
|
|
setTimeout(lang.hitch(this, function(d){ this._closeIconClicked(); }), 0);
|
|
return;
|
|
}
|
|
this.close();
|
|
},
|
|
|
|
closeIconClicked: function(/*Event*/ /*===== e =====*/){
|
|
// summary:
|
|
// User-defined function to handle clicks for the close icon.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
open: function(e){
|
|
// summary:
|
|
// Opens the icon content, or makes a transition.
|
|
var parent = this.getParent(); // IconContainer
|
|
if(this.transition === "below"){
|
|
if(parent.single){
|
|
parent.closeAll();
|
|
}
|
|
this._open_1();
|
|
}else{
|
|
parent._opening = this;
|
|
if(parent.single){
|
|
this.paneWidget.closeHeaderNode.style.display = "none";
|
|
if(!this.isOpen()){
|
|
parent.closeAll();
|
|
}
|
|
parent.appView._heading.set("label", this.label);
|
|
}
|
|
this.moveTo = parent.id + "_mblApplView";
|
|
new TransitionEvent(this.domNode, this.getTransOpts(), e).dispatch();
|
|
}
|
|
},
|
|
|
|
_open_1: function(){
|
|
// tags:
|
|
// private
|
|
this.paneWidget.show();
|
|
this.unhighlight();
|
|
if(this.lazy){
|
|
lazyLoadUtils.instantiateLazyWidgets(this.containerNode, this.requires);
|
|
this.lazy = false;
|
|
}
|
|
this.scrollIntoView(this.paneWidget.domNode);
|
|
this.onOpen();
|
|
},
|
|
|
|
scrollIntoView: function(/*DomNode*/node){
|
|
// summary:
|
|
// Scrolls until the given node is in the view.
|
|
var s = viewRegistry.getEnclosingScrollable(node);
|
|
if(s){ // this node is placed inside scrollable
|
|
s.scrollIntoView(node, true);
|
|
}else{
|
|
win.global.scrollBy(0, domGeometry.position(node, false).y);
|
|
}
|
|
},
|
|
|
|
close: function(/*Boolean?*/noAnimation){
|
|
// summary:
|
|
// Closes the icon content.
|
|
if(!this.isOpen()){ return; }
|
|
this.set("selected", false);
|
|
if(has("webkit") && !noAnimation){
|
|
var contentNode = this.paneWidget.domNode;
|
|
if(this.getParent().transition == "below"){
|
|
domClass.add(contentNode, "mblCloseContent mblShrink");
|
|
var nodePos = domGeometry.position(contentNode, true);
|
|
var targetPos = domGeometry.position(this.domNode, true);
|
|
var origin = (targetPos.x + targetPos.w/2 - nodePos.x) + "px " + (targetPos.y + targetPos.h/2 - nodePos.y) + "px";
|
|
domStyle.set(contentNode, { webkitTransformOrigin:origin });
|
|
}else{
|
|
domClass.add(contentNode, "mblCloseContent mblShrink0");
|
|
}
|
|
}else{
|
|
this.paneWidget.hide();
|
|
}
|
|
this.onClose();
|
|
},
|
|
|
|
onOpen: function(){
|
|
// summary:
|
|
// Stub method to allow the application to connect.
|
|
},
|
|
|
|
onClose: function(){
|
|
// summary:
|
|
// Stub method to allow the application to connect.
|
|
},
|
|
|
|
_setLabelAttr: function(/*String*/text){
|
|
// tags:
|
|
// private
|
|
this.label = text;
|
|
var s = this._cv ? this._cv(text) : text;
|
|
this.labelNode.innerHTML = s;
|
|
if(this.paneWidget){
|
|
this.paneWidget.set("label", text);
|
|
}
|
|
},
|
|
|
|
_getBadgeAttr: function(){
|
|
// tags:
|
|
// private
|
|
return this.badgeObj ? this.badgeObj.getValue() : null;
|
|
},
|
|
|
|
_setBadgeAttr: function(/*String*/value){
|
|
// tags:
|
|
// private
|
|
if(!this.badgeObj){
|
|
this.badgeObj = new Badge({fontSize:14, className:this.badgeClass});
|
|
domStyle.set(this.badgeObj.domNode, {
|
|
position: "absolute",
|
|
top: "-2px",
|
|
right: "2px"
|
|
});
|
|
}
|
|
this.badgeObj.setValue(value);
|
|
if(value){
|
|
this.iconDivNode.appendChild(this.badgeObj.domNode);
|
|
}else{
|
|
this.iconDivNode.removeChild(this.badgeObj.domNode);
|
|
}
|
|
},
|
|
|
|
_setDeleteIconAttr: function(icon){
|
|
// tags:
|
|
// private
|
|
if(!this.getParent()){ return; } // icon may be invalid because inheritParams is not called yet
|
|
|
|
this._set("deleteIcon", icon);
|
|
icon = this.deletable ? icon : "";
|
|
this.deleteIconNode = iconUtils.setIcon(icon, this.deleteIconPos, this.deleteIconNode,
|
|
this.deleteIconTitle || this.alt, this.iconDivNode);
|
|
if(this.deleteIconNode){
|
|
domClass.add(this.deleteIconNode, "mblIconItemDeleteIcon");
|
|
if(this.deleteIconRole){
|
|
this.deleteIconNode.setAttribute("role", this.deleteIconRole);
|
|
}
|
|
}
|
|
},
|
|
|
|
_setContentAttr: function(/*String|DomNode*/data){
|
|
// tags:
|
|
// private
|
|
var root;
|
|
if(!this.paneWidget){
|
|
if(!this._tmpNode){
|
|
this._tmpNode = domConstruct.create("div");
|
|
}
|
|
root = this._tmpNode;
|
|
}else{
|
|
root = this.paneWidget.containerNode;
|
|
}
|
|
|
|
if(typeof data === "object"){
|
|
domConstruct.empty(root);
|
|
root.appendChild(data);
|
|
}else{
|
|
root.innerHTML = data;
|
|
}
|
|
},
|
|
|
|
_setSelectedAttr: function(/*Boolean*/selected){
|
|
// summary:
|
|
// Makes this widget in the selected or unselected state.
|
|
// tags:
|
|
// private
|
|
this.inherited(arguments);
|
|
this.iconNode && domStyle.set(this.iconNode, "opacity",
|
|
selected ? this.getParent().pressedIconOpacity : 1);
|
|
}
|
|
});
|
|
});
|