UNPKG

dojox

Version:

Dojo eXtensions, a rollup of many useful sub-projects and varying states of maturity – from very stable and robust, to alpha and experimental. See individual projects contain README files for details.

418 lines (371 loc) 11.3 kB
define([ "dojo/_base/array", "dojo/_base/connect", "dojo/_base/declare", "dojo/_base/event", "dojo/_base/lang", "dojo/_base/window", "dojo/dom-geometry", "dojo/dom-style", "dojo/touch", "dijit/registry", "./IconItem", "./sniff", "./viewRegistry", "./_css3" ], function(array, connect, declare, event, lang, win, domGeometry, domStyle, touch, registry, IconItem, has, viewRegistry, css3){ // module: // dojox/mobile/_EditableIconMixin return declare("dojox.mobile._EditableIconMixin", null, { // summary: // A mixin for IconContainer to make it editable. deleteIconForEdit: "mblDomButtonBlackCircleCross", threshold: 4, // drag threshold value in pixels destroy: function(){ // summary: // Destroys the container. if(this._blankItem){ this._blankItem.destroy(); } this.inherited(arguments); }, startEdit: function(){ // summary: // Starts the editing. if(!this.editable || this.isEditing){ return; } this.isEditing = true; if(!this._handles){ this._handles = [ this.connect(this.domNode, css3.name("transitionStart"), "_onTransitionStart"), this.connect(this.domNode, css3.name("transitionEnd"), "_onTransitionEnd") ]; } var count = 0; array.forEach(this.getChildren(), function(w){ this.defer(function(){ w.set("deleteIcon", this.deleteIconForEdit); if(w.deleteIconNode){ w._deleteHandle = this.connect(w.deleteIconNode, "onclick", "_deleteIconClicked"); } w.highlight(0); }, 15*count++); }, this); connect.publish("/dojox/mobile/startEdit", [this]); // pubsub this.onStartEdit(); // callback }, endEdit: function(){ // summary: // Ends the editing. if(!this.isEditing){ return; } array.forEach(this.getChildren(), function(w){ w.unhighlight(); if(w._deleteHandle){ this.disconnect(w._deleteHandle); w._deleteHandle = null; } w.set("deleteIcon", ""); }, this); this._movingItem = null; if(this._handles){ array.forEach(this._handles, this.disconnect, this); this._handles = null; } connect.publish("/dojox/mobile/endEdit", [this]); // pubsub this.onEndEdit(); // callback this.isEditing = false; }, scaleItem: function(/*Widget*/widget, /*Number*/ratio){ // summary: // Scales an item according to the specified ratio. domStyle.set(widget.domNode, css3.add({}, { transition: has("android") ? "" : css3.name("transform", true) + " .1s ease-in-out", transform: ratio == 1 ? "" : "scale(" + ratio + ")" })); }, _onTransitionStart: function(e){ // tags: // private event.stop(e); }, _onTransitionEnd: function(e){ // tags: // private event.stop(e); var w = registry.getEnclosingWidget(e.target); w._moving = false; domStyle.set(w.domNode, css3.name("transition"), ""); }, _onTouchStart: function(e){ // tags: // private if(!this._blankItem){ this._blankItem = new IconItem(); this._blankItem.domNode.style.visibility = "hidden"; this._blankItem._onClick = function(){}; } var item = this._movingItem = registry.getEnclosingWidget(e.target); var iconPressed = false; var n; for(n = e.target; n !== item.domNode; n = n.parentNode){ if(n === item.iconNode){ iconPressed = true; break; } } if(!iconPressed){ return; } if(!this._conn){ this._conn = [ this.connect(this.domNode, touch.move, "_onTouchMove"), this.connect(win.doc, touch.release, "_onTouchEnd") ]; } this._touchStartPosX = e.touches ? e.touches[0].pageX : e.pageX; this._touchStartPosY = e.touches ? e.touches[0].pageY : e.pageY; if(this.isEditing){ this._onDragStart(e); }else{ // set timer to detect long press this._pressTimer = this.defer(function(){ this.startEdit(); this._onDragStart(e); }, 1000); } }, _onDragStart: function(e){ // tags: // private this._dragging = true; var movingItem = this._movingItem; if(movingItem.get("selected")){ movingItem.set("selected", false); } this.scaleItem(movingItem, 1.1); var x = e.touches ? e.touches[0].pageX : e.pageX; var y = e.touches ? e.touches[0].pageY : e.pageY; var enclosingScrollable = viewRegistry.getEnclosingScrollable(movingItem.domNode); var dx = 0; var dy = 0; if(enclosingScrollable){ // this node is placed inside a scrollable var pos = enclosingScrollable.getPos(); dx = pos.x; dy = pos.y; event.stop(e); } var startPos = this._startPos = domGeometry.position(movingItem.domNode, true); this._offsetPos = { x: startPos.x - x - dx, y: startPos.y - y - dy }; this._startIndex = this.getIndexOfChild(movingItem); this.addChild(this._blankItem, this._startIndex); this.moveChild(movingItem, this.getChildren().length); domStyle.set(movingItem.domNode, { position: "absolute", top: (startPos.y - dy) + "px", left: (startPos.x - dx) + "px", zIndex: 100 }); }, _onTouchMove: function(e){ // tags: // private var x = e.touches ? e.touches[0].pageX : e.pageX; var y = e.touches ? e.touches[0].pageY : e.pageY; if(this._dragging){ domStyle.set(this._movingItem.domNode, { top: (this._offsetPos.y + y) + "px", left: (this._offsetPos.x + x) + "px" }); this._detectOverlap({x: x, y: y}); event.stop(e); }else{ var dx = Math.abs(this._touchStartPosX - x); var dy = Math.abs(this._touchStartPosY - y); if (dx > this.threshold || dy > this.threshold) { this._clearPressTimer(); } } }, _onTouchEnd: function(e){ // tags: // private this._clearPressTimer(); if(this._conn){ array.forEach(this._conn, this.disconnect, this); this._conn = null; } if(this._dragging){ this._dragging = false; var movingItem = this._movingItem; this.scaleItem(movingItem, 1.0); domStyle.set(movingItem.domNode, { position: "", top: "", left: "", zIndex: "" }); var startIndex = this._startIndex; var endIndex = this.getIndexOfChild(this._blankItem); this.moveChild(movingItem, endIndex); this.removeChild(this._blankItem); connect.publish("/dojox/mobile/moveIconItem", [this, movingItem, startIndex, endIndex]); // pubsub this.onMoveItem(movingItem, startIndex, endIndex); // callback } }, _clearPressTimer: function(){ // tags: // private if(this._pressTimer){ this._pressTimer.remove(); this._pressTimer = null; } }, _detectOverlap: function(/*Object*/point){ // tags: // private var children = this.getChildren(), blankItem = this._blankItem, blankPos = domGeometry.position(blankItem.domNode, true), blankIndex = this.getIndexOfChild(blankItem), dir = 1, i, w, pos; if(this._contains(point, blankPos)){ return; }else if(point.y < blankPos.y || (point.y <= blankPos.y + blankPos.h && point.x < blankPos.x)){ dir = -1; } for(i = blankIndex + dir; i>=0 && i<children.length-1; i += dir){ w = children[i]; if(w._moving){ continue; } pos = domGeometry.position(w.domNode, true); if(this._contains(point, pos)){ this.defer(function(){ this.moveChildWithAnimation(blankItem, dir == 1 ? i+1 : i); }); break; }else if((dir == 1 && pos.y > point.y) || (dir == -1 && pos.y + pos.h < point.y)){ break; } } }, _contains: function(point, pos){ // tags: // private return pos.x < point.x && point.x < pos.x + pos.w && pos.y < point.y && point.y < pos.y + pos.h; }, _animate: function(/*int*/from, /*int*/to){ // tags: // private if(from == to) { return; } var dir = from < to ? 1 : -1; var children = this.getChildren(); var posArray = []; var i, j; for(i=from; i!=to; i+=dir){ posArray.push({ t: (children[i+dir].domNode.offsetTop - children[i].domNode.offsetTop) + "px", l: (children[i+dir].domNode.offsetLeft - children[i].domNode.offsetLeft) + "px" }); } for(i=from, j=0; i!=to; i+=dir, j++){ var w = children[i]; w._moving = true; domStyle.set(w.domNode, { top: posArray[j].t, left: posArray[j].l }); this.defer(lang.hitch(w, function(){ domStyle.set(this.domNode, css3.add({ top: "0px", left: "0px" }, { transition: "top .3s ease-in-out, left .3s ease-in-out" })); }), j*10); } }, removeChildWithAnimation: function(/*Widget|Number*/widget){ // summary: // Removes the given child with animation. var index = (typeof widget === "number") ? widget : this.getIndexOfChild(widget); this.removeChild(widget); // Show remove animation if(this._blankItem){ // #16868 - no _blankItem if calling deleteItem() programmatically, that is // without _onTouchStart() being called. this.addChild(this._blankItem); } this._animate(index, this.getChildren().length - 1); if(this._blankItem){ this.removeChild(this._blankItem); } }, moveChild: function(/*Widget|Number*/widget, /*Number?*/insertIndex){ // summary: // Moves a child without animation. this.addChild(widget, insertIndex); this.paneContainerWidget.addChild(widget.paneWidget, insertIndex); }, moveChildWithAnimation: function(/*Widget|Number*/widget, /*Number?*/insertIndex){ // summary: // Moves a child with animation. var index = this.getIndexOfChild(this._blankItem); this.moveChild(widget, insertIndex); // Show move animation this._animate(index, insertIndex); }, _deleteIconClicked: function(e){ // summary: // Internal handler for click events. // tags: // private if(this.deleteIconClicked(e) === false){ return; } // user's click action var item = registry.getEnclosingWidget(e.target); this.deleteItem(item); }, deleteIconClicked: function(/*Event*/ /*===== e =====*/){ // summary: // User-defined function to handle clicks for the delete icon. // tags: // callback }, deleteItem: function(/*Widget*/item){ // summary: // Deletes the given item. if(item._deleteHandle){ this.disconnect(item._deleteHandle); } this.removeChildWithAnimation(item); connect.publish("/dojox/mobile/deleteIconItem", [this, item]); // pubsub this.onDeleteItem(item); // callback item.destroy(); }, onDeleteItem: function(/*Widget*/item){ // summary: // Stub function to connect to from your application. }, onMoveItem: function(/*Widget*/item, /*int*/from, /*int*/to){ // summary: // Stub function to connect to from your application. }, onStartEdit: function(){ // summary: // Stub function to connect to from your application. }, onEndEdit: function(){ // summary: // Stub function to connect to from your application. }, _setEditableAttr: function(/*Boolean*/editable){ // tags: // private this._set("editable", editable); if(editable && !this._touchStartHandle){ // Allow users to start editing by long press on IconItems this._touchStartHandle = this.connect(this.domNode, touch.press, "_onTouchStart"); }else if(!editable && this._touchStartHandle){ this.disconnect(this._touchStartHandle); this._touchStartHandle = null; } } }); });