polardbxengine/storage/ndb/mcc/frontend/dojo/dojox/calendar/Touch.js.uncompressed.js

462 lines
13 KiB
JavaScript

define("dojox/calendar/Touch", ["dojo/_base/array", "dojo/_base/lang", "dojo/_base/declare", "dojo/dom", "dojo/dom-geometry", "dojo/_base/window", "dojo/on", "dojo/_base/event", "dojo/keys"],
function(arr, lang, declare, dom, domGeometry, win, on, event, keys){
return declare("dojox.calendar.Touch", null, {
// summary:
// This plugin is managing the touch interactions on item renderers displayed by a calendar view.
// touchStartEditingTimer: Integer
// The delay of one touch over the renderer before setting the item in editing mode.
touchStartEditingTimer: 500,
// touchEndEditingTimer: Integer
// The delay after which the item is leaving the editing mode after the previous editing gesture, in touch context.
touchEndEditingTimer: 10000,
postMixInProperties: function(){
this.on("rendererCreated", lang.hitch(this, function(ir){
var renderer = ir.renderer;
var h;
if(!renderer.__handles){
renderer.__handles = [];
}
h = on(renderer.domNode, "touchstart", lang.hitch(this, function(e){
this._onRendererTouchStart(e, renderer);
}));
renderer.__handles.push(h);
}));
},
_onRendererTouchStart: function(e, renderer){
// tags:
// private
var p = this._edProps;
if(p && p.endEditingTimer){
clearTimeout(p.endEditingTimer);
p.endEditingTimer = null;
}
var theItem = renderer.item.item;
if(p && p.endEditingTimer){
clearTimeout(p.endEditingTimer);
p.endEditingTimer = null;
}
if(p != null && p.item != theItem){
// another item is edited.
// stop previous item
if(p.startEditingTimer){
clearTimeout(p.startEditingTimer);
}
this._endItemEditing("touch", false);
p = null;
}
// initialize editing properties
if(!p){
// register event listeners to manage gestures.
var handles = [];
handles.push(on(win.doc, "touchend", lang.hitch(this, this._docEditingTouchEndHandler)));
handles.push(on(this.itemContainer, "touchmove", lang.hitch(this, this._docEditingTouchMoveHandler)));
this._setEditingProperties({
touchMoved: false,
item: theItem,
renderer: renderer,
rendererKind: renderer.rendererKind,
event: e,
handles: handles,
liveLayout: this.liveLayout
});
p = this._edProps;
}
if(this._isEditing){
// get info on touches
lang.mixin(p, this._getTouchesOnRenderers(e, p.editedItem));
// start an editing gesture.
this._startTouchItemEditingGesture(e);
} else {
// initial touch that will trigger or not the editing
if(e.touches.length > 1){
event.stop(e);
return;
}
// set the selection state without dispatching (on touch end) after a short amount of time.
// to allow a bit of time to scroll without selecting (graphically at least)
this._touchSelectionTimer = setTimeout(lang.hitch(this, function(){
this._saveSelectedItems = this.get("selectedItems");
var changed = this.selectFromEvent(e, this.renderItemToItem(theItem, this.get("store")), renderer, false);
if(changed){
this._pendingSelectedItem = theItem;
}else{
delete this._saveSelectedItems;
}
this._touchSelectionTimer = null;
}), 200);
p.start = {x: e.touches[0].screenX, y: e.touches[0].screenY};
if(this.isItemEditable(p.item, p.rendererKind)){
// editing gesture timer
this._edProps.startEditingTimer = setTimeout(lang.hitch(this, function(){
// we are editing, so the item *must* be selected.
if(this._touchSelectionTimer){
clearTimeout(this._touchSelectionTimer);
delete this._touchSelectionTime;
}
if(this._pendingSelectedItem){
this.dispatchChange(this._saveSelectedItems == null ? null : this._saveSelectedItems[0], this._pendingSelectedItem, null, e);
delete this._saveSelectedItems;
delete this._pendingSelectedItem;
}else{
this.selectFromEvent(e, this.renderItemToItem(theItem, this.get("store")), renderer);
}
this._startItemEditing(p.item, "touch", e);
p.moveTouchIndex = 0;
// A move gesture is initiated even if we don't move
this._startItemEditingGesture([this.getTime(e)], "move", "touch", e);
}), this.touchStartEditingTimer);
}
}
},
_docEditingTouchMoveHandler: function(e){
// tags:
// private
var p = this._edProps;
// When the screen is touched, it can dispatch move events if the
// user press the finger a little more...
var touch = {x: e.touches[0].screenX, y: e.touches[0].screenY};
if(p.startEditingTimer &&
(Math.abs(touch.x - p.start.x) > 25 ||
Math.abs(touch.y - p.start.y) > 25)) {
// scroll use case, do not edit
clearTimeout(p.startEditingTimer);
p.startEditingTimer = null;
clearTimeout(this._touchSelectionTimer);
this._touchSelectionTimer = null;
if(this._pendingSelectedItem){
delete this._pendingSelectedItem;
this.selectFromEvent(e, null, null, false);
}
}
p.touchMoved = true;
if(this._editingGesture){
event.stop(e);
if(p.itemBeginDispatched){
var times = [];
var d = p.editKind == "resizeEnd" ? p.editedItem.endTime : p.editedItem.startTime;
switch(p.editKind){
case "move":
var touchIndex = p.moveTouchIndex == null || p.moveTouchIndex < 0 ? 0 : p.moveTouchIndex;
times[0] = this.getTime(e, -1, -1, touchIndex);
break;
case "resizeStart":
times[0] = this.getTime(e, -1, -1, p.resizeStartTouchIndex);
break;
case "resizeEnd":
times[0] = this.getTime(e, -1, -1, p.resizeEndTouchIndex);
break;
case "resizeBoth":
times[0] = this.getTime(e, -1, -1, p.resizeStartTouchIndex);
times[1] = this.getTime(e, -1, -1, p.resizeEndTouchIndex);
break;
}
this._moveOrResizeItemGesture(times, "touch", e);
if(p.editKind == "move"){
if(this.renderData.dateModule.compare(p.editedItem.startTime, d) == -1){
this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "start", this.autoScrollTouchMargin);
}else{
this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "end", this.autoScrollTouchMargin);
}
}else if(e.editKind == "resizeStart" || e.editKind == "resizeBoth"){
this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "start", this.autoScrollTouchMargin);
}else{
this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "end", this.autoScrollTouchMargin);
}
}
} // else scroll, if any, is delegated to sub class
},
// autoScrollTouchMargin: Integer
// The minimum number of minutes of margin around the edited event.
autoScrollTouchMargin: 10,
_docEditingTouchEndHandler: function(e){
// tags:
// private
event.stop(e);
var p = this._edProps;
if(p.startEditingTimer){
clearTimeout(p.startEditingTimer);
p.startEditingTimer = null;
}
if(this._isEditing){
lang.mixin(p, this._getTouchesOnRenderers(e, p.editedItem));
if(this._editingGesture){
if(p.touchesLen == 0){
// all touches were removed => end of editing gesture
this._endItemEditingGesture("touch", e);
if(this.touchEndEditingTimer > 0){
// Timer that trigger the end of the item editing mode.
p.endEditingTimer = setTimeout(lang.hitch(this, function(){
this._endItemEditing("touch", false);
}), this.touchEndEditingTimer);
} // else validation must be explicit
}else{
if(this._editingGesture){
this._endItemEditingGesture("touch", e);
}
// there touches of interest on item, process them.
this._startTouchItemEditingGesture(e);
}
}
}else if(!p.touchMoved){
event.stop(e);
arr.forEach(p.handles, function(handle){
handle.remove();
});
if(this._touchSelectionTimer){
// selection timer was not reached to a proper selection.
clearTimeout(this._touchSelectionTimer);
this.selectFromEvent(e, this.renderItemToItem(p.item, this.get("store")), p.renderer, true);
}else if(this._pendingSelectedItem){
// selection timer was reached, dispatch change event
this.dispatchChange(this._saveSelectedItems.length == 0 ? null : this._saveSelectedItems[0],
this._pendingSelectedItem, null, e); // todo renderer ?
delete this._saveSelectedItems;
delete this._pendingSelectedItem;
}
if(this._pendingDoubleTap && this._pendingDoubleTap.item == p.item){
this._onItemDoubleClick({
triggerEvent: e,
renderer: p.renderer,
item: this.renderItemToItem(p.item, this.get("store"))
});
clearTimeout(this._pendingDoubleTap.timer);
delete this._pendingDoubleTap;
}else{
this._pendingDoubleTap = {
item: p.item,
timer: setTimeout(lang.hitch(this, function(){
delete this._pendingDoubleTap;
}), this.doubleTapDelay)
};
this._onItemClick({
triggerEvent: e,
renderer: p.renderer,
item: this.renderItemToItem(p.item, this.get("store"))
});
}
this._edProps = null;
}else{
// scroll view has finished.
if(this._saveSelectedItems){
// selection without dipatching was done, but the view scrolled,
// so revert last selection
this.set("selectedItems", this._saveSelectedItems);
delete this._saveSelectedItems;
delete this._pendingSelectedItem;
}
arr.forEach(p.handles, function(handle){
handle.remove();
});
this._edProps = null;
}
},
_startTouchItemEditingGesture: function(e){
// summary:
// Determines if a editing gesture is starting according to touches.
// tags:
// private
var p = this._edProps;
var fromResizeStart = p.resizeStartTouchIndex != -1;
var fromResizeEnd = p.resizeEndTouchIndex != -1;
if(fromResizeStart && fromResizeEnd || // initial gesture using two touches
this._editingGesture && p.touchesLen == 2 &&
(fromResizeEnd && p.editKind == "resizeStart" ||
fromResizeStart && p.editKind =="resizeEnd")){ // gesture one after the other touch
if(this._editingGesture && p.editKind != "resizeBoth"){ // stop ongoing gesture
this._endItemEditingGesture("touch", e);
}
p.editKind = "resizeBoth";
this._startItemEditingGesture([this.getTime(e, -1, -1, p.resizeStartTouchIndex),
this.getTime(e, -1, -1, p.resizeEndTouchIndex)],
p.editKind, "touch", e);
return;
}else if(fromResizeStart && p.touchesLen == 1 && !this._editingGesture){
this._startItemEditingGesture([this.getTime(e, -1, -1, p.resizeStartTouchIndex)],
"resizeStart", "touch", e);
return;
}else if(fromResizeEnd && p.touchesLen == 1 && !this._editingGesture){
this._startItemEditingGesture([this.getTime(e, -1, -1, p.resizeEndTouchIndex)],
"resizeEnd", "touch", e);
return;
} else {
// A move gesture is initiated even if we don't move
this._startItemEditingGesture([this.getTime(e)], "move", "touch", e);
}
},
_getTouchesOnRenderers: function(e, item){
// summary:
// Returns the touch indices that are on a editing handles or body of the renderers
// tags:
// private
// item: Object
// The render item.
// e: Event
// The touch event.
// tags:
// private
var irs = this._getStartEndRenderers(item);
var resizeStartTouchIndex = -1;
var resizeEndTouchIndex = -1;
var moveTouchIndex = -1;
var hasResizeStart = irs[0] != null && irs[0].resizeStartHandle != null;
var hasResizeEnd = irs[1] != null && irs[1].resizeEndHandle != null;
var len = 0;
var touched = false;
var list = this.itemToRenderer[item.id];
for(var i=0; i<e.touches.length; i++){
if(resizeStartTouchIndex == -1 && hasResizeStart){
touched = dom.isDescendant(e.touches[i].target, irs[0].resizeStartHandle);
if(touched){
resizeStartTouchIndex = i;
len++;
}
}
if(resizeEndTouchIndex == -1 && hasResizeEnd){
touched = dom.isDescendant(e.touches[i].target, irs[1].resizeEndHandle);
if(touched){
resizeEndTouchIndex = i;
len++;
}
}
if(resizeStartTouchIndex == -1 && resizeEndTouchIndex == -1){
for (var j=0; j<list.length; j++){
touched = dom.isDescendant(e.touches[i].target, list[j].container);
if(touched){
moveTouchIndex = i;
len++;
break;
}
}
}
if(resizeStartTouchIndex != -1 && resizeEndTouchIndex != -1 && moveTouchIndex != -1){
// all touches of interest were found, ignore other ones.
break;
}
}
return {
touchesLen: len,
resizeStartTouchIndex: resizeStartTouchIndex,
resizeEndTouchIndex: resizeEndTouchIndex,
moveTouchIndex: moveTouchIndex
};
}
});
});