sumeru
Version:
A Realtime Javascript RIA Framework For Mobile WebApp
1,030 lines (939 loc) • 25.6 kB
JavaScript
//version 0.2.11
var touch = touch || {};
(function(doc, exports) {
'use strict';
var os = (function() {
var navigator = window.navigator,
userAgent = navigator.userAgent,
android = userAgent.match(/(Android)[\s\/]+([\d\.]+)/),
ios = userAgent.match(/(iPad|iPhone|iPod)\s+OS\s([\d_\.]+)/),
wp = userAgent.match(/(Windows\s+Phone)\s([\d\.]+)/),
isWebkit = /WebKit\/[\d.]+/i.test(userAgent),
isSafari = ios ? (navigator.standalone ? isWebkit: (/Safari/i.test(userAgent) && !/CriOS/i.test(userAgent) && !/MQQBrowser/i.test(userAgent))) : false,
os = {};
if (android) {
os.android = true;
os.version = android[2];
}
if (ios) {
os.ios = true;
os.version = ios[2].replace(/_/g, '.');
os.ios7 = /^7/.test(os.version);
if (ios[1] === 'iPad') {
os.ipad = true;
} else if (ios[1] === 'iPhone') {
os.iphone = true;
os.iphone5 = screen.height == 568;
} else if (ios[1] === 'iPod') {
os.ipod = true;
}
}
if (wp) {
os.wp = true;
os.version = wp[2];
os.wp8 = /^8/.test(os.version);
}
if (isWebkit) {
os.webkit = true;
}
if (isSafari) {
os.safari = true;
}
return os;
})();
var PCevts = {
'touchstart': 'mousedown',
'touchmove': 'mousemove',
'touchend': 'mouseup',
'touchcancel': 'mouseout'
};
var utils = {
getType: function(obj) {
return Object.prototype.toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
},
getSelector: function(el) {
if (el.id) {
return "#" + el.id;
}
if (el.className) {
var cns = el.className.split(/\s+/);
return "." + cns.join(".");
} else if(el === document){
return "body";
}else{
return el.tagName.toLowerCase();
}
},
matchSelector: function(target, selector) {
return target.webkitMatchesSelector(selector);
},
getEventListeners: function(el) {
return el.listeners;
},
getPCevts: function(evt) {
return PCevts[evt] || evt;
},
forceReflow: function() {
var domTreeOpDiv = document.getElementById("domTreeOp");
if (!domTreeOpDiv) {
domTreeOpDiv = document.createElement("div");
domTreeOpDiv.id = "domTreeOp";
document.body.appendChild(domTreeOpDiv);
}
var parentNode = domTreeOpDiv.parentNode;
var nextSibling = domTreeOpDiv.nextSibling;
parentNode.removeChild(domTreeOpDiv);
parentNode.insertBefore(domTreeOpDiv, nextSibling);
},
simpleClone: function(obj){
return JSON.parse(JSON.stringify(obj));
}
};
/** 底层事件绑定/代理支持 */
var proxyid = 0;
var proxies = [];
var _trigger = function(el, evt, detail) {
detail = detail || {};
var e,
opt = {
bubbles: true,
cancelable: true,
detail: detail
};
if (typeof CustomEvent !== 'undefined') {
e = new CustomEvent(evt, opt);
if (el) {
el.dispatchEvent(e);
}
} else {
e = document.createEvent("CustomEvent");
e.initCustomEvent(evt, true, true, detail);
if (el) {
el.dispatchEvent(e);
}
}
};
/**
* {DOM} element
* {String} eventName
* {Function} handler
*/
var _bind = function(el, evt, handler) {
el.listeners = el.listeners || {};
if (!el.listeners[evt]) {
el.listeners[evt] = [handler];
} else {
el.listeners[evt].push(handler);
}
var proxy = function(e) {
if (os.ios7) {
utils.forceReflow();
}
e.originEvent = e;
e.startRotate = function() {
__rotation_single_finger = true;
};
for (var p in e.detail) {
if(p !== 'type'){
e[p] = e.detail[p];
}
}
var returnValue = handler.call(e.target, e);
if(typeof returnValue !== "undefined" && !returnValue){
e.stopPropagation();
e.preventDefault();
}
};
handler.proxy = handler.proxy || {};
if (!handler.proxy[evt]) {
handler.proxy[evt] = [proxyid++];
} else {
handler.proxy[evt].push(proxyid++);
}
proxies.push(proxy);
if( el.addEventListener){ el.addEventListener(evt, proxy, false); }
};
/**
* {DOM} element
* {String} eventName
* {Function} the same handler of _bind
*/
var _unbind = function(el, evt, handler) {
if (!handler) {
var handlers = el.listeners[evt];
if (handlers && handlers.length) {
handlers.forEach(function(handler) {
el.removeEventListener(evt, handler, false);
});
}
} else {
var proxyids = handler.proxy[evt];
if (proxyids && proxyids.length) {
proxyids.forEach(function(proxyid) {
if (el.removeEventListener) {
el.removeEventListener(evt, proxies[proxyid], false);
}
});
}
}
};
/**
* {DOM} delegate element
* {String} eventName
* {String} selector of sub elements
* {Function} handler
*/
var _delegate = function(el, evt, sel, handler) {
var proxy = function(e) {
var target, returnValue;
e.originEvent = e;
e.startRotate = function() {
__rotation_single_finger = true;
};
for (var p in e.detail) {
if(p !== 'type'){
e[p] = e.detail[p];
}
}
var integrateSelector = utils.getSelector(el) + " " + sel;
var match = utils.matchSelector(e.target, integrateSelector);
var ischild = utils.matchSelector(e.target, integrateSelector + " " + e.target.nodeName);
if (!match && ischild) {
if (os.ios7) {
utils.forceReflow();
}
target = e.target;
while (!utils.matchSelector(target, integrateSelector)) {
target = target.parentNode;
}
returnValue = handler.call(e.target, e);
if(typeof returnValue !== "undefined" && !returnValue){
e.stopPropagation();
e.preventDefault();
}
} else {
if (os.ios7) {
utils.forceReflow();
}
if (match || ischild) {
returnValue = handler.call(e.target, e);
if(typeof returnValue !== "undefined" && !returnValue){
e.stopPropagation();
e.preventDefault();
}
}
}
};
handler.proxy = handler.proxy || {};
if (!handler.proxy[evt]) {
handler.proxy[evt] = [proxyid++];
} else {
handler.proxy[evt].push(proxyid++);
}
proxies.push(proxy);
el.listeners = el.listeners || {};
if (!el.listeners[evt]) {
el.listeners[evt] = [proxy];
} else {
el.listeners[evt].push(proxy);
}
if(el.addEventListener){el.addEventListener(evt, proxy, false);}
};
/**
* {DOM} delegate element
* {String} eventName
* {String} selector of sub elements
* {Function} the same handler of _on
*/
var _undelegate = function(el, evt, sel, handler) {
if (!handler) {
var listeners = el.listeners[evt];
listeners.forEach(function(proxy) {
el.removeEventListener(evt, proxy, false);
});
} else {
var proxyids = handler.proxy[evt];
if (proxyids.length) {
proxyids.forEach(function(proxyid) {
if (el.removeEventListener) {
el.removeEventListener(evt, proxies[proxyid], false);
}
});
}
}
};
/** 手势识别 */
var config = {
tap: true,
doubleTap: true,
tapMaxDistance: 10,
hold: true,
holdTime: 650,
//ms
maxDoubleTapInterval: 300,
//swipe
swipe: true,
swipeTime: 300,
swipeMinDistance: 18,
swipeFactor: 5,
drag: true,
pinch: true,
minScaleRate: 0,
minRotationAngle: 0
};
var _hasTouch = ('ontouchstart' in window);
var smrEventList = {
TOUCH_START: 'touchstart',
TOUCH_MOVE: 'touchmove',
TOUCH_END: 'touchend',
TOUCH_CANCEL: 'touchcancel',
MOUSE_DOWN: 'mousedown',
MOUSE_MOVE: 'mousemove',
MOUSE_UP: 'mouseup',
CLICK: 'click',
//PINCH TYPE EVENT NAMES
PINCH_START: 'pinchstart',
PINCH_END: 'pinchend',
PINCH: 'pinch',
PINCH_IN: 'pinchin',
PINCH_OUT: 'pinchout',
ROTATION_LEFT: 'rotateleft',
ROTATION_RIGHT: 'rotateright',
ROTATION: 'rotate',
SWIPE_START: 'swipestart',
SWIPING: 'swiping',
SWIPE_END: 'swipeend',
SWIPE_LEFT: 'swipeleft',
SWIPE_RIGHT: 'swiperight',
SWIPE_UP: 'swipeup',
SWIPE_DOWN: 'swipedown',
SWIPE: 'swipe',
DRAG: 'drag',
DRAGSTART : 'dragstart',
DRAGEND : 'dragend',
//HOLD AND TAP
HOLD: 'hold',
TAP: 'tap',
DOUBLE_TAP: 'doubletap'
};
/**
* 获取事件的位置信息
* @param ev, 原生事件对象
* @return array [{ x: int, y: int }]
*/
function getPosOfEvent(ev) {
//多指触摸, 返回多个手势位置信息
if (_hasTouch) {
var posi = [];
var src = null;
for (var t = 0, len = ev.touches.length; t < len; t++) {
src = ev.touches[t];
posi.push({
x: src.pageX,
y: src.pageY
});
}
return posi;
} //处理PC浏览器的情况
else {
return [{
x: ev.pageX,
y: ev.pageY
}];
}
}
/**
*获取两点之间的距离
*/
function getDistance(pos1, pos2) {
var x = pos2.x - pos1.x,
y = pos2.y - pos1.y;
return Math.sqrt((x * x) + (y * y));
}
/**
*计算事件的手势个数
*@param ev {Event}
*/
function getFingers(ev) {
return ev.touches ? ev.touches.length: 1;
}
//计算收缩的比例
function calScale(pstart, pmove) {
if (pstart.length >= 2 && pmove.length >= 2) {
var disStart = getDistance(pstart[1], pstart[0]);
var disEnd = getDistance(pmove[1], pmove[0]);
return disEnd / disStart;
}
return 1;
}
//return 角度,范围为{-180-0,0-180}, 用来识别swipe方向。
function getAngle(p1, p2) {
return Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
}
//return 角度, 范围在{0-180}, 用来识别旋转角度
function _getAngle180(p1, p2) {
var agl = Math.atan((p2.y - p1.y) * -1 / (p2.x - p1.x)) * (180 / Math.PI);
return (agl < 0 ? (agl + 180) : agl);
}
//根据角度计算方位
//@para agl {int} 是调用getAngle获取的。
function getDirectionFromAngle(agl) {
var directions = {
up: agl < -45 && agl > -135,
down: agl >= 45 && agl < 135,
left: agl >= 135 || agl <= -135,
right: agl >= -45 && agl <= 45
};
for (var key in directions) {
if (directions[key]) return key;
}
return null;
}
function getXYByElement(el) {
var left = 0,
top = 0;
while (el.offsetParent) {
left += el.offsetLeft;
top += el.offsetTop;
el = el.offsetParent;
}
return {
left: left,
top: top
};
}
function reset() {
startEvent = moveEvent = endEvent = null;
__tapped = __touchStart = startSwiping = startPinch = false;
startDrag = false;
pos = {};
__rotation_single_finger = false;
}
function isTouchStart(ev) {
return (ev.type === 'touchstart' || ev.type === 'mousedown');
}
function isTouchMove(ev) {
return (ev.type === 'touchmove' || ev.type === 'mousemove');
}
function isTouchEnd(ev) {
return (ev.type === 'touchend' || ev.type === 'mouseup' || ev.type === 'touchcancel');
}
var pos = {
start: null,
move: null,
end: null
};
var startTime = 0;
var fingers = 0;
var startEvent = null;
var moveEvent = null;
var endEvent = null;
var startSwiping = false;
var startPinch = false;
var startDrag = false;
var __offset = {};
var __touchStart = false;
var __holdTimer = null;
var __tapped = false;
var __lastTapEndTime = null;
var __tapTimer = null;
var __scale_last_rate = 1;
var __rotation_single_finger = false;
var __rotation_single_start = []; //元素坐标中心位置
var __initial_angle = 0;
var __rotation = 0;
var __prev_tapped_end_time = 0;
var __prev_tapped_pos = null;
var gestures = {
_getAngleDiff: function(currentPos) {
var diff = parseInt(__initial_angle - _getAngle180(currentPos[0], currentPos[1]), 10);
var count = 0;
while (Math.abs(diff - __rotation) > 90 && count++<50) {
if (__rotation < 0) {
diff -= 180;
} else {
diff += 180;
}
}
__rotation = parseInt(diff, 10);
return __rotation;
},
pinch: function(ev) {
var el = ev.target;
if (config.pinch) {
//touchend进入此时的getFinger(ev) < 2
if (!__touchStart) return;
if (getFingers(ev) < 2) {
if (!isTouchEnd(ev)) return;
}
var scale = calScale(pos.start, pos.move);
var rotation = this._getAngleDiff(pos.move);
var eventObj = {
type: '',
originEvent: ev,
scale: scale,
rotation: rotation,
direction: (rotation > 0 ? 'right': 'left'),
fingersCount: getFingers(ev)
};
if (!startPinch) {
startPinch = true;
eventObj.fingerStatus = "start";
_trigger(el, smrEventList.PINCH_START, eventObj);
} else if (isTouchMove(ev)) {
eventObj.fingerStatus = "move";
_trigger(el, smrEventList.PINCH, eventObj);
} else if (isTouchEnd(ev)) {
eventObj.fingerStatus = "end";
_trigger(el, smrEventList.PINCH_END, eventObj);
reset();
}
if (Math.abs(1 - scale) > config.minScaleRate) {
var scaleEv = utils.simpleClone(eventObj);
//手势放大, 触发pinchout事件
var scale_diff = 0.00000000001; //防止touchend的scale与__scale_last_rate相等,不触发事件的情况。
if (scale > __scale_last_rate) {
__scale_last_rate = scale - scale_diff;
_trigger(el, smrEventList.PINCH_OUT, scaleEv, false);
} //手势缩小,触发pinchin事件
else if (scale < __scale_last_rate) {
__scale_last_rate = scale + scale_diff;
_trigger(el, smrEventList.PINCH_IN, scaleEv, false);
}
if (isTouchEnd(ev)) {
__scale_last_rate = 1;
}
}
if (Math.abs(rotation) > config.minRotationAngle) {
var rotationEv = utils.simpleClone(eventObj), eventType;
eventType = rotation > 0 ? smrEventList.ROTATION_RIGHT: smrEventList.ROTATION_LEFT;
_trigger(el, eventType, rotationEv, false);
_trigger(el, smrEventList.ROTATION, eventObj);
}
}
},
rotateSingleFinger: function(ev) {
var el = ev.target;
if (__rotation_single_finger && getFingers(ev) < 2) {
if (!pos.move) return;
if (__rotation_single_start.length < 2) {
var docOff = getXYByElement(el);
__rotation_single_start = [{
x: docOff.left + el.offsetWidth / 2,
y: docOff.top + el.offsetHeight / 2
},
pos.move[0]];
__initial_angle = parseInt(_getAngle180(__rotation_single_start[0], __rotation_single_start[1]), 10);
}
var move = [__rotation_single_start[0], pos.move[0]];
var rotation = this._getAngleDiff(move);
var eventObj = {
type: '',
originEvent: ev,
rotation: rotation,
direction: (rotation > 0 ? 'right': 'left'),
fingersCount: getFingers(ev)
};
if (isTouchMove(ev)) {
eventObj.fingerStatus = "move";
} else if (isTouchEnd(ev) || ev.type === 'mouseout') {
eventObj.fingerStatus = "end";
_trigger(el, smrEventList.PINCH_END, eventObj);
reset();
}
var eventType = rotation > 0 ? smrEventList.ROTATION_RIGHT: smrEventList.ROTATION_LEFT;
_trigger(el, eventType, eventObj);
_trigger(el, smrEventList.ROTATION, eventObj);
}
},
swipe: function(ev) {
//目前swipe只存在一个手势上
var el = ev.target;
if (!__touchStart || !pos.move || getFingers(ev) > 1) {
return;
}
var now = Date.now();
var touchTime = now - startTime;
var distance = getDistance(pos.start[0], pos.move[0]);
var position = {
x: pos.move[0].x - __offset.left,
y: pos.move[0].y - __offset.top
};
var angle = getAngle(pos.start[0], pos.move[0]);
var direction = getDirectionFromAngle(angle);
var touchSecond = touchTime / 1000;
var factor = ((10 - config.swipeFactor) * 10 * touchSecond * touchSecond);
var eventObj = {
type: smrEventList.SWIPE,
//DEFAULT: smrEventList.SWIPE event.
originEvent: ev,
position: position,
direction: direction,
distance: distance,
distanceX: pos.move[0].x - pos.start[0].x,
distanceY: pos.move[0].y - pos.start[0].y,
x : pos.move[0].x - pos.start[0].x,
y : pos.move[0].y - pos.start[0].y,
angle: angle,
duration: touchTime,
fingersCount: getFingers(ev),
factor: factor
};
if (config.swipe) {
var swipeTo = function() {
var elt = smrEventList;
switch (direction) {
case 'up':
_trigger(el, elt.SWIPE_UP, eventObj);
break;
case 'down':
_trigger(el, elt.SWIPE_DOWN, eventObj);
break;
case 'left':
_trigger(el, elt.SWIPE_LEFT, eventObj);
break;
case 'right':
_trigger(el, elt.SWIPE_RIGHT, eventObj);
break;
}
};
if (!startSwiping) {
eventObj.fingerStatus = eventObj.swipe = 'start';
startSwiping = true;
_trigger(el, smrEventList.SWIPE_START, eventObj);
} else if (isTouchMove(ev)) {
eventObj.fingerStatus = eventObj.swipe = 'move';
_trigger(el, smrEventList.SWIPING, eventObj);
if (touchTime > config.swipeTime && touchTime < config.swipeTime + 50 && distance > config.swipeMinDistance) {
swipeTo();
_trigger(el, smrEventList.SWIPE, eventObj, false);
}
} else if (isTouchEnd(ev) || ev.type === 'mouseout') {
eventObj.fingerStatus = eventObj.swipe = 'end';
_trigger(el, smrEventList.SWIPE_END, eventObj);
if (config.swipeTime > touchTime && distance > config.swipeMinDistance) {
swipeTo();
_trigger(el, smrEventList.SWIPE, eventObj, false);
}
}
}
if (config.drag) {
if (!startDrag) {
eventObj.fingerStatus = eventObj.swipe = 'start';
startDrag = true;
_trigger(el, smrEventList.DRAGSTART, eventObj);
} else if (isTouchMove(ev)) {
eventObj.fingerStatus = eventObj.swipe = 'move';
_trigger(el, smrEventList.DRAG, eventObj);
} else if (isTouchEnd(ev)) {
eventObj.fingerStatus = eventObj.swipe = 'end';
_trigger(el, smrEventList.DRAGEND, eventObj);
}
}
},
tap: function(ev) {
var el = ev.target;
if (config.tap) {
var now = Date.now();
var touchTime = now - startTime;
var distance = getDistance(pos.start[0], pos.move ? pos.move[0] : pos.start[0]);
clearTimeout(__holdTimer); //去除hold事件
var isDoubleTap = (function() {
if (__prev_tapped_pos && config.doubleTap && (startTime - __prev_tapped_end_time) < config.maxDoubleTapInterval) {
var doubleDis = getDistance(__prev_tapped_pos, pos.start[0]);
if (doubleDis < 16) return true;
}
return false;
})();
if (isDoubleTap) {
clearTimeout(__tapTimer);
_trigger(el, smrEventList.DOUBLE_TAP, {
type: smrEventList.DOUBLE_TAP,
originEvent: ev,
position: pos.start[0]
});
return;
}
if (config.tapMaxDistance < distance) return;
if (config.holdTime > touchTime && getFingers(ev) <= 1) {
//clearTimeout在ios上有时不work(alert引起的), 先用__tapped顶一下
__tapped = true;
__prev_tapped_end_time = now;
__prev_tapped_pos = pos.start[0];
__tapTimer = setTimeout(function(){
_trigger(el, smrEventList.TAP, {
type: smrEventList.TAP,
originEvent: ev,
fingersCount: getFingers(ev),
position: __prev_tapped_pos
});
}, 220);
}
}
},
hold: function(ev) {
var el = ev.target;
if (config.hold) {
clearTimeout(__holdTimer);
__holdTimer = setTimeout(function() {
if (!pos.start) return;
var distance = getDistance(pos.start[0], pos.move ? pos.move[0] : pos.start[0]);
if (config.tapMaxDistance < distance) return;
if (!__tapped) {
_trigger(el, "hold", {
type: 'hold',
originEvent: ev,
fingersCount: getFingers(ev),
position: pos.start[0]
});
}
},
config.holdTime);
}
}
};
var handlerOriginEvent = function(ev) {
var el = ev.target;
switch (ev.type) {
case 'touchstart':
case 'mousedown':
//__rotation_single_finger = false;
__rotation_single_start = [];
__touchStart = true;
if (!pos.start || pos.start.length < 2) {
pos.start = getPosOfEvent(ev);
}
if (getFingers(ev) >= 2) {
__initial_angle = parseInt(_getAngle180(pos.start[0], pos.start[1]), 10);
}
startTime = Date.now();
startEvent = ev;
__offset = {};
var box = el.getBoundingClientRect();
var docEl = document.documentElement;
__offset = {
top: box.top + (window.pageYOffset || docEl.scrollTop) - (docEl.clientTop || 0),
left: box.left + (window.pageXOffset || docEl.scrollLeft) - (docEl.clientLeft || 0)
};
gestures.hold(ev);
break;
case 'touchmove':
case 'mousemove':
if (!__touchStart || !pos.start) return;
pos.move = getPosOfEvent(ev);
if (getFingers(ev) >= 2) {
gestures.pinch(ev);
} else if (__rotation_single_finger) {
gestures.rotateSingleFinger(ev);
} else {
gestures.swipe(ev);
}
break;
case 'touchend':
case 'touchcancel':
case 'mouseup':
case 'mouseout':
if (!__touchStart) return;
endEvent = ev;
if (startPinch) {
gestures.pinch(ev);
} else if (__rotation_single_finger) {
gestures.rotateSingleFinger(ev);
} else if (startSwiping) {
gestures.swipe(ev);
} else {
gestures.tap(ev);
}
reset();
__initial_angle = 0;
__rotation = 0;
if (ev.touches && ev.touches.length === 1) {
__touchStart = true;
__rotation_single_finger = true;
}
break;
}
};
/**
开发者接口
usage:
touch.on("#test", "tap swipeleft swiperight", handler);
touch.trigger("#test", "tap");
touch.off("#test", "tap swipeleft swiperight", handler);
*/
var _on = function() {
var evts, handler, evtMap, sel, args = arguments;
if (args.length < 2 || args > 4) {
return console.error("unexpected arguments!");
}
var els = utils.getType(args[0]) === 'string' ? doc.querySelectorAll(args[0]) : args[0];
els = els.length ? Array.prototype.slice.call(els) : [els];
//事件绑定
if (args.length === 3 && utils.getType(args[1]) === 'string') {
evts = args[1].split(" ");
handler = args[2];
evts.forEach(function(evt) {
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
els.forEach(function(el) {
_bind(el, evt, handler);
});
});
return;
}
function evtMapDelegate( evt ){
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
els.forEach(function(el) {
_delegate(el, evt, sel, evtMap[evt]);
});
}
//mapEvent delegate
if (args.length === 3 && utils.getType(args[1]) === 'object') {
evtMap = args[1];
sel = args[2];
for (var evt1 in evtMap) {
evtMapDelegate(evt1);
}
return;
}
function evtMapBind(evt){
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
els.forEach(function(el) {
_bind(el, evt, evtMap[evt]);
});
}
//mapEvent bind
if (args.length === 2 && utils.getType(args[1]) === 'object') {
evtMap = args[1];
for (var evt2 in evtMap) {
evtMapBind(evt2);
}
return;
}
//兼容factor config
if (args.length === 4 && utils.getType(args[2]) === "object") {
evts = args[1].split(" ");
handler = args[3];
evts.forEach(function(evt) {
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
els.forEach(function(el) {
_bind(el, evt, handler);
});
});
return;
}
//事件代理
if (args.length === 4) {
var el = els[0];
evts = args[1].split(" ");
sel = args[2];
handler = args[3];
evts.forEach(function(evt) {
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
_delegate(el, evt, sel, handler);
});
return;
}
};
var _off = function() {
var evts, handler;
var args = arguments;
if (args.length < 1 || args.length > 4) {
return console.error("unexpected arguments!");
}
var els = utils.getType(args[0]) === 'string' ? doc.querySelectorAll(args[0]) : args[0];
els = els.length ? Array.prototype.slice.call(els) : [els];
if (args.length === 1 || args.length === 2) {
els.forEach(function(el) {
evts = args[1] ? args[1].split(" ") : Object.keys(el.listeners);
if (evts.length) {
evts.forEach(function(evt) {
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
_unbind(el, evt);
_undelegate(el, evt);
});
}
});
return;
}
if (args.length === 3 && utils.getType(args[2]) === 'function') {
handler = args[2];
els.forEach(function(el) {
evts = args[1].split(" ");
evts.forEach(function(evt) {
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
_unbind(el, evt, handler);
});
});
return;
}
if (args.length === 3 && utils.getType(args[2]) === 'string') {
var sel = args[2];
els.forEach(function(el) {
evts = args[1].split(" ");
evts.forEach(function(evt) {
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
_undelegate(el, evt, sel);
});
});
return;
}
if (args.length === 4) {
handler = args[3];
els.forEach(function(el) {
evts = args[1].split(" ");
evts.forEach(function(evt) {
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
_undelegate(el, evt, sel, handler);
});
});
return;
}
};
var _dispatch = function(el, evt, detail) {
var args = arguments;
if (!_hasTouch) {
evt = utils.getPCevts(evt);
}
var els = utils.getType(args[0]) === 'string' ? doc.querySelectorAll(args[0]) : args[0];
els = els.length ? Array.prototype.call(els) : [els];
els.forEach(function(el) {
_trigger(el, evt, detail);
});
};
//init gesture
function init() {
var eventNames = _hasTouch ? 'touchstart touchmove touchend touchcancel': 'mouseup mousedown mousemove mouseout';
_on(doc, eventNames, handlerOriginEvent);
}
init();
exports.on = _on;
exports.off = _off;
exports.bind = _on;
exports.unbind = _off;
exports.live = _on;
exports.die = _off;
exports.config = config;
exports.trigger = _dispatch;
})(document, touch);
Library.touch = sumeru.Library.create(function(exports){
Library.objUtils.extend(exports, touch);
return exports;
});