Skip to content

Instantly share code, notes, and snippets.

@sousk
Created December 26, 2014 05:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sousk/4abd5c9bdf6c4f658988 to your computer and use it in GitHub Desktop.
Save sousk/4abd5c9bdf6c4f658988 to your computer and use it in GitHub Desktop.
Dispatching touch events between HTML which contains iframe and the document of that iframe
/**
@license WTFPL
@author @sou
This library dispatches touch events from an element to another on the different document through iframe.
NOTE:
This library only suports Mobile Safari as each browsers have different specifications for touch event creation.
You might expand _dispatch method if you want to deal with other browsers.
NOTE:
Origins of src attribute of the iframe and HTML you work with should be the same as we need to access contentDocument via iframe.
**/
function TouchEventDispatcher(source, iframe) {
if (! 'ontouchstart' in source || ! 'contentDocument' in iframe) {
throw new TypeError("Unexpected type of objects has been passed");
}
this._source = source;
this._iframe = iframe;
this._listeners = {};
}
TouchEventDispatcher.prototype = {
start: TouchEventDispatcher_start,
end: TouchEventDispatcher_end,
listen: TouchEventDispatcher_listen,
once: TouchEventDispatcher_once,
_reset: TouchEventDispatcher_reset,
_dispatch: TouchEventDispatcher_dispatch,
handleEvent: TouchEventDispatcher_handleEvent
};
function TouchEventDispatcher_handleEvent(evt) {
var listeners = this._listeners[evt.type];
if (listeners) {
for (var i = 0; i < listeners.every.length; i++) {
listeners.every[i](evt);
}
for (var j = 0; j < listeners.once.length; j++) {
listeners.once[j](evt);
}
listeners.once = [];
}
}
function TouchEventDispatcher_listen(type, fn, isOnce) {
if (! this._listeners[type]) {
this._listeners[type] = {
every: [],
once: []
};
this._source.addEventListener(type, this, false);
}
if (isOnce) {
this._listeners[type].once.push(fn);
}
else {
this._listeners[type].every.push(fn);
}
}
function TouchEventDispatcher_once(type, fn) {
this.listen(type, fn, true);
}
function TouchEventDispatcher_start() {
var that = this;
this.listen('touchstart', function (evt) {
that._touched = true;
var t = evt.touches[0];
if (t) {
that._point = [t.clientX, t.clientY];
that._dispatch('touchstart');
}
});
this.listen('touchmove', function (evt) {
if (this._touched) {
var t = evt.touches[0];
if (t) {
that._point = [t.clientX, t.clientY];
}
// dispatching touchmove costs so high that we do not support it by default
// that._dispatch('touchmove');
}
});
this.listen('touchend', function (evt) {
if (that._touched) {
that._dispatch('touchend');
}
that._reset();
});
this.listen('touchcancel', function (evt) {
that._reset();
});
}
function TouchEventDispatcher_end() {
var types = this._listeners;
for (var i = 0; i < types.length; i++) {
this._source.removeEventListener(types[i], this);
}
this._reset();
}
function TouchEventDispatcher_reset() {
this._point = [null, null];
this._touched = false;
}
function TouchEventDispatcher_dispatch(type) {
var identifier = Date.now();
var x = this._point[0], y = this._point[1];
var doc = this._iframe.contentDocument;
var touch = doc.createTouch(
doc.defaultView, // view
doc.body,
identifier,
x, y, x, y
);
var touches = doc.createTouchList(touch);
var evt = doc.createEvent('TouchEvent');
evt.initTouchEvent(
type, // {String} type
true, // {Boolean} canBubble
true, // {Boolean} cancelable
doc.defaultView, // {Window} view
1, // {Number} detail
0, // {Number} screenX
0, // {Number} screenY
0, // {Number} clientX
0, // {Number} clientY
false, // {Boolean} ctrlKey
false, // {Boolean} altKey
false, // {Boolean} shiftKey
false, // {Boolean} metaKey
touches, // {TouchList} touches
touches, // {TouchList} targetTouches
touches, // {TouchList} changedTouches
0, // {Number} scale(0 - 1)
0 // {Number} rotation
);
var elm = doc.elementFromPoint(x, y);
elm.dispatchEvent(evt);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment