forked from nervetattoo/backbone.touch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbackbone.touch.js
121 lines (109 loc) · 4.76 KB
/
backbone.touch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// (c) 2012 Raymond Julin, Keyteq AS
// Backbone.touch may be freely distributed under the MIT license.
(function (window, factory) {
"use strict";
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['underscore', 'backbone'], function(){
return factory.apply(window, arguments);
});
} else if (typeof module === 'object' && module.exports) {
// NodeJS.
module.exports = factory.call(window, require('underscore'), require('backbone'));
} else {
// Browser globals
factory.call(window, window._, window.Backbone);
}
}(typeof global === 'object' ? global : this, function (_, Backbone) {
"use strict";
// The `getValue` and `delegateEventSplitter` is copied from
// Backbones source, unfortunately these are not available
// in any form from Backbone itself
var getValue = function(object, prop) {
if (!(object && object[prop])) return null;
return _.isFunction(object[prop]) ? object[prop]() : object[prop];
};
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
_.extend(Backbone.View.prototype, {
_touching : false,
touchPrevents : true,
touchThreshold : 10,
isTouch : this.document && 'ontouchstart' in this.document && !('callPhantom' in this),
// Drop in replacement for Backbone.View#delegateEvent
// Enables better touch support
//
// If the users device is touch enabled it replace any `click`
// event with listening for touch(start|move|end) in order to
// quickly trigger touch taps
delegateEvents: function(events) {
if (!(events || (events = getValue(this, 'events')))) return;
this.undelegateEvents();
var suffix = '.delegateEvents' + this.cid;
_(events).each(function(method, key) {
if (!_.isFunction(method)) method = this[events[key]];
if (!method) throw new Error('Method "' + events[key] + '" does not exist');
var match = key.match(delegateEventSplitter);
var eventName = match[1], selector = match[2];
var boundHandler = _.bind(this._touchHandler,this);
method = _.bind(method, this);
if (this._useTouchHandlers(eventName, selector)) {
this.$el.on('touchstart' + suffix, selector, boundHandler);
this.$el.on('touchend' + suffix, selector,
{method:method},
boundHandler
);
this.$el.on(eventName, selector, boundHandler);
}
else {
eventName += suffix;
if (selector === '') {
this.$el.bind(eventName, method);
} else {
this.$el.on(eventName, selector, method);
}
}
}, this);
},
// Detect if touch handlers should be used over listening for click
// Allows custom detection implementations
_useTouchHandlers : function(eventName, selector)
{
return this.isTouch && eventName === 'click';
},
// At the first touchstart we register touchevents as ongoing
// and as soon as a touch move happens we set touching to false,
// thus implying that a fastclick will not happen when
// touchend occurs. If no touchmove happened
// inbetween touchstart and touchend we trigger the event
//
// The `touchPrevents` toggle decides if Backbone.touch
// will stop propagation and prevent default
_touchHandler : function(e) {
var oe = e.originalEvent || e;
if (!('changedTouches' in oe)) return;
var touch = oe.changedTouches[0];
var x = touch.clientX;
var y = touch.clientY;
switch (e.type) {
case 'touchstart':
this._touching = [x, y];
break;
case 'touchend':
var oldX = this._touching[0];
var oldY = this._touching[1];
var threshold = this.touchThreshold;
if (x < (oldX + threshold) && x > (oldX - threshold) &&
y < (oldY + threshold) && y > (oldY - threshold)) {
this._touching = false;
if (this.touchPrevents) {
e.preventDefault();
e.stopPropagation();
}
e.data.method(e);
}
break;
}
}
});
return Backbone;
}));