Skip to content

Instantly share code, notes, and snippets.

@wei-lee
Created December 6, 2011 18:10
Show Gist options
  • Save wei-lee/1439235 to your computer and use it in GitHub Desktop.
Save wei-lee/1439235 to your computer and use it in GitHub Desktop.
Ext.gesture.Manager = new Ext.AbstractManager({
//first, add more events
eventNames: {
'touchstart': 'start',
'touchmove': 'move',
'touchend': 'end',
'mousedown': 'mousestart',
'mouseup': 'mouseend'
},
defaultPreventedMouseEvents: [],
clickMoveThreshold: 5,
init: function () {
this.targets = [];
this.followTouches = [];
this.currentGestures = [];
this.currentTargets = [];
var touchScreen = false;
this.listenerWrappers = {
start: Ext.createDelegate(this.onTouchStart, this),
move: Ext.createDelegate(this.onTouchMove, this),
end: Ext.createDelegate(this.onTouchEnd, this),
mouse: Ext.createDelegate(this.onMouseEvent, this),
//and more wrappers
mousestart: Ext.createDelegate(this.onMouseStart, this),
mouseend: Ext.createDelegate(this.onMouseEnd, this)
};
this.attachListeners();
},
freeze: function () {
this.isFrozen = true;
},
thaw: function () {
this.isFrozen = false;
},
getEventSimulator: function () {
if (!this.eventSimulator) {
this.eventSimulator = new Ext.util.EventSimulator();
}
return this.eventSimulator;
},
attachListeners: function () {
Ext.iterate(this.eventNames, function (key, name) {
//switch key and name to add more event listeners
//document.addEventListener(name, this.listenerWrappers[key], false);
document.addEventListener(key, this.listenerWrappers[name], false);
}, this);
if (Ext.supports.Touch) {
this.defaultPreventedMouseEvents.forEach(function (name) {
document.addEventListener(name, this.listenerWrappers['mouse'], true);
}, this);
}
},
detachListeners: function () {
Ext.iterate(this.eventNames, function (key, name) {
//same again
//document.removeEventListener(name, this.listenerWrappers[key], false);
document.removeEventListener(key, this.listenerWrappers[name], false);
}, this);
if (Ext.supports.Touch) {
this.defaultPreventedMouseEvents.forEach(function (name) {
document.removeEventListener(name, this.listenerWrappers['mouse'], true);
}, this);
}
},
onMouseEvent: function (e) {
if (!e.isSimulated) {
e.preventDefault();
e.stopPropagation();
}
},
//more mouse event handlers
onMouseStart: function (e) {
if (!this.touchStartFired) {
this.onTouchStart(e, true);
} else {
this.touchStartFired = false;
}
},
onMouseEnd: function (e) {
if (!this.touchEndFired) {
this.onTouchEnd(e, true);
} else {
this.touchEndFired = false;
}
},
onTouchStart: function (e, noset) {
var targets = [],
target = e.target;
if (e.stopped === true) {
return;
}
if (Ext.is.Android) {
if (!(target.tagName && ['input', 'textarea', 'select'].indexOf(target.tagName.toLowerCase()) !== -1)) {
e.preventDefault();
}
}
if (this.isFrozen) {
return;
}
if (this.startEvent) {
this.onTouchEnd(e);
}
this.locks = {};
this.currentTargets = [target];
while (target) {
if (this.targets.indexOf(target) !== -1) {
targets.unshift(target);
}
target = target.parentNode;
this.currentTargets.push(target);
}
this.startEvent = e;
this.startPoint = Ext.util.Point.fromEvent(e);
this.lastMovePoint = null;
this.isClick = true;
this.touchMoveFired = false;
if (noset === undefined || noset === false) {
this.touchStartFired = true;
}
this.handleTargets(targets, e);
},
onTouchMove: function (e) {
if (!Ext.is.Android) {
e.preventDefault();
}
if (!this.startEvent) {
return;
}
if (Ext.is.Desktop) {
e.target = this.startEvent.target;
}
if (this.isFrozen) {
return;
}
var gestures = this.currentGestures,
gesture, touch = e.changedTouches ? e.changedTouches[0] : e;
this.lastMovePoint = Ext.util.Point.fromEvent(e);
if (Ext.supports.Touch && this.isClick && !this.lastMovePoint.isWithin(this.startPoint, this.clickMoveThreshold)) {
this.isClick = false;
}
for (var i = 0; i < gestures.length; i++) {
if (e.stopped) {
break;
}
gesture = gestures[i];
if (gesture.listenForMove) {
gesture.onTouchMove(e, touch);
}
}
this.touchMoveFired = true;
},
onTouchEnd: function (e, noset) {
if (Ext.is.Blackberry) {
//e.preventDefault();
}
if (this.isFrozen) {
return;
}
var gestures = this.currentGestures.slice(0),
ln = gestures.length,
i, gesture, endPoint, needsAnotherMove = false,
touch = e.changedTouches ? e.changedTouches[0] : e;
if (this.startPoint) {
endPoint = Ext.util.Point.fromEvent(e);
if (!(this.lastMovePoint || this.startPoint)['equals'](endPoint)) {
needsAnotherMove = true;
}
}
for (i = 0; i < ln; i++) {
gesture = gestures[i];
if (!e.stopped && gesture.listenForEnd) {
if (needsAnotherMove) {
gesture.onTouchMove(e, touch);
}
gesture.onTouchEnd(e, touch);
}
this.stopGesture(gesture);
}
if (Ext.supports.Touch && this.isClick) {
this.isClick = false;
this.getEventSimulator().fire('click', this.startEvent.target, touch);
}
if (noset === undefined || noset === false) {
this.touchEndFired = true;
}
if (this.touchMoveFired) {
this.touchEndFired = false;
}
this.lastMovePoint = null;
this.followTouches = [];
this.startedChangedTouch = false;
this.currentTargets = [];
this.startEvent = null;
this.startPoint = null;
},
//no changes after here
handleTargets: function (targets, e) {
var ln = targets.length,
i;
this.startedChangedTouch = false;
this.startedTouches = Ext.supports.Touch ? e.touches : [e];
for (i = 0; i < ln; i++) {
if (e.stopped) {
break;
}
this.handleTarget(targets[i], e, true);
}
for (i = ln - 1; i >= 0; i--) {
if (e.stopped) {
break;
}
this.handleTarget(targets[i], e, false);
}
if (this.startedChangedTouch) {
this.followTouches = this.followTouches.concat((Ext.supports.Touch && e.targetTouches) ? Ext.toArray(e.targetTouches) : [e]);
}
},
handleTarget: function (target, e, capture) {
var gestures = Ext.Element.data(target, 'x-gestures') || [],
ln = gestures.length,
i, gesture;
for (i = 0; i < ln; i++) {
gesture = gestures[i];
if (( !! gesture.capture === !! capture) && (this.followTouches.length < gesture.touches) && ((Ext.supports.Touch && e.targetTouches) ? (e.targetTouches.length === gesture.touches) : true)) {
this.startedChangedTouch = true;
this.startGesture(gesture);
if (gesture.listenForStart) {
gesture.onTouchStart(e, e.changedTouches ? e.changedTouches[0] : e);
}
if (e.stopped) {
break;
}
}
}
},
startGesture: function (gesture) {
gesture.started = true;
this.currentGestures.push(gesture);
},
stopGesture: function (gesture) {
gesture.started = false;
this.currentGestures.remove(gesture);
},
addEventListener: function (target, eventName, listener, options) {
target = Ext.getDom(target);
options = options || {};
var targets = this.targets,
name = this.getGestureName(eventName),
gestures = Ext.Element.data(target, 'x-gestures'),
gesture;
if (!gestures) {
gestures = [];
Ext.Element.data(target, 'x-gestures', gestures);
}
if (!name) {
throw new Error('Trying to subscribe to unknown event ' + eventName);
}
if (targets.indexOf(target) === -1) {
this.targets.push(target);
}
gesture = this.get(target.id + '-' + name);
if (!gesture) {
gesture = this.create(Ext.apply({}, options, {
target: target,
type: name
}));
gestures.push(gesture);
}
gesture.addListener(eventName, listener);
if (this.startedChangedTouch && this.currentTargets.contains(target) && !gesture.started && !options.subsequent) {
this.startGesture(gesture);
if (gesture.listenForStart) {
gesture.onTouchStart(this.startEvent, this.startedTouches[0]);
}
}
},
removeEventListener: function (target, eventName, listener) {
target = Ext.getDom(target);
var name = this.getGestureName(eventName),
gestures = Ext.Element.data(target, 'x-gestures') || [],
gesture;
gesture = this.get(target.id + '-' + name);
if (gesture) {
gesture.removeListener(eventName, listener);
for (name in gesture.listeners) {
return;
}
gesture.destroy();
gestures.remove(gesture);
Ext.Element.data(target, 'x-gestures', gestures);
}
},
getGestureName: function (ename) {
return this.names && this.names[ename];
},
registerType: function (type, cls) {
var handles = cls.prototype.handles,
i, ln;
this.types[type] = cls;
cls[this.typeName] = type;
if (!handles) {
handles = cls.prototype.handles = [type];
}
this.names = this.names || {};
for (i = 0, ln = handles.length; i < ln; i++) {
this.names[handles[i]] = type;
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment