| 875 |
lars |
1 |
/**
|
|
|
2 |
* jQuery.UI.iPad plugin
|
|
|
3 |
* Copyright (c) 2010 Stephen von Takach
|
|
|
4 |
* licensed under MIT.
|
|
|
5 |
* Date: 27/8/2010
|
|
|
6 |
*
|
|
|
7 |
* Project Home:
|
|
|
8 |
* http://code.google.com/p/jquery-ui-for-ipad-and-iphone/
|
|
|
9 |
*
|
|
|
10 |
* Modified: 19/01/2012
|
|
|
11 |
* Organized as a proper plugin and added addTouch()
|
|
|
12 |
*/
|
|
|
13 |
(function ($) {
|
|
|
14 |
var lastTap = null, // Holds last tapped element (so we can compare for double tap)
|
|
|
15 |
tapValid = false, // Are we still in the .6 second window where a double tap can occur
|
|
|
16 |
tapTimeout = null, // The timeout reference
|
|
|
17 |
rightClickPending = false, // Is a right click still feasible
|
|
|
18 |
rightClickEvent = null, // the original event
|
|
|
19 |
holdTimeout = null, // timeout reference
|
|
|
20 |
cancelMouseUp = false, // prevents a click from occurring as we want the context menu
|
|
|
21 |
currentDOMElement = null; // the last DOM element that was seen during a drag.
|
|
|
22 |
|
|
|
23 |
function cancelTap() {
|
|
|
24 |
tapValid = false;
|
|
|
25 |
}
|
|
|
26 |
|
|
|
27 |
function cancelHold() {
|
|
|
28 |
if (rightClickPending) {
|
|
|
29 |
window.clearTimeout(holdTimeout);
|
|
|
30 |
rightClickPending = false;
|
|
|
31 |
rightClickEvent = null;
|
|
|
32 |
}
|
|
|
33 |
}
|
|
|
34 |
|
|
|
35 |
function startHold(event) {
|
|
|
36 |
if (rightClickPending) {
|
|
|
37 |
return;
|
|
|
38 |
}
|
|
|
39 |
rightClickPending = true; // We could be performing a right click
|
|
|
40 |
rightClickEvent = (event.changedTouches)[0];
|
|
|
41 |
holdTimeout = window.setTimeout(doRightClick, 800);
|
|
|
42 |
}
|
|
|
43 |
|
|
|
44 |
function doRightClick() {
|
|
|
45 |
rightClickPending = false;
|
|
|
46 |
// We need to mouse up (as we were down)
|
|
|
47 |
var first = rightClickEvent,
|
|
|
48 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
49 |
simulatedEvent.initMouseEvent("mouseup", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
|
|
|
50 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
51 |
|
|
|
52 |
// Emulate a right click
|
|
|
53 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
54 |
simulatedEvent.initMouseEvent("mousedown", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 2, null);
|
|
|
55 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
56 |
|
|
|
57 |
// Show a context menu
|
|
|
58 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
59 |
simulatedEvent.initMouseEvent("contextmenu", true, true, window, 1, first.screenX + 50, first.screenY + 5, first.clientX + 50, first.clientY + 5, false, false, false, false, 2, null);
|
|
|
60 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
61 |
|
|
|
62 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
63 |
simulatedEvent.initMouseEvent("mouseup", true, true, window, 1, first.screenX + 50, first.screenY + 5, first.clientX + 50, first.clientY + 5, false, false, false, false, 2, null);
|
|
|
64 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
65 |
|
|
|
66 |
cancelMouseUp = true;
|
|
|
67 |
rightClickEvent = null; // Release memory
|
|
|
68 |
}
|
|
|
69 |
|
|
|
70 |
|
|
|
71 |
// mouse over event then mouse down
|
|
|
72 |
function iPadTouchStart(event) {
|
|
|
73 |
var touches = event.changedTouches,
|
|
|
74 |
first = touches[0],
|
|
|
75 |
type = "mouseover",
|
|
|
76 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
77 |
|
|
|
78 |
// Mouse over first - I have live events attached on mouse over
|
|
|
79 |
simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
|
|
|
80 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
81 |
|
|
|
82 |
type = "mousedown";
|
|
|
83 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
84 |
|
|
|
85 |
simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
|
|
|
86 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
87 |
|
|
|
88 |
if (!tapValid) {
|
|
|
89 |
lastTap = first.target;
|
|
|
90 |
tapValid = true;
|
|
|
91 |
tapTimeout = window.setTimeout(cancelTap, 600);
|
|
|
92 |
startHold(event);
|
|
|
93 |
} else {
|
|
|
94 |
window.clearTimeout(tapTimeout);
|
|
|
95 |
// If a double tap is still a possibility and the elements are the same then perform a double click
|
|
|
96 |
if (first.target == lastTap) {
|
|
|
97 |
lastTap = null;
|
|
|
98 |
tapValid = false;
|
|
|
99 |
|
|
|
100 |
type = "click";
|
|
|
101 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
102 |
|
|
|
103 |
simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
|
|
|
104 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
105 |
|
|
|
106 |
type = "dblclick";
|
|
|
107 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
108 |
|
|
|
109 |
simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
|
|
|
110 |
first.target.dispatchEvent(simulatedEvent);
|
|
|
111 |
} else {
|
|
|
112 |
lastTap = first.target;
|
|
|
113 |
tapValid = true;
|
|
|
114 |
tapTimeout = window.setTimeout(cancelTap, 600);
|
|
|
115 |
startHold(event);
|
|
|
116 |
}
|
|
|
117 |
}
|
|
|
118 |
}
|
|
|
119 |
|
|
|
120 |
function getDOMElementFromEvent(event) {
|
|
|
121 |
if (event.targetTouches && event.targetTouches[0]) {
|
|
|
122 |
return document.elementFromPoint(event.targetTouches[0].pageX - window.pageXOffset, event.targetTouches[0].pageY - window.pageYOffset);
|
|
|
123 |
}
|
|
|
124 |
return null;
|
|
|
125 |
}
|
|
|
126 |
|
|
|
127 |
function iPadTouchHandler(event) {
|
|
|
128 |
var type = "",
|
|
|
129 |
button = 0; /*left*/
|
|
|
130 |
if (event.touches.length > 1) {
|
|
|
131 |
return;
|
|
|
132 |
}
|
|
|
133 |
switch (event.type) {
|
|
|
134 |
case "touchstart":
|
|
|
135 |
if ($(event.changedTouches[0].target).is("select")) {
|
|
|
136 |
return;
|
|
|
137 |
}
|
|
|
138 |
iPadTouchStart(event); /*We need to trigger two events here to support one touch drag and drop*/
|
|
|
139 |
event.preventDefault();
|
|
|
140 |
currentDOMElement = getDOMElementFromEvent(event);
|
|
|
141 |
return false;
|
|
|
142 |
|
|
|
143 |
case "touchmove":
|
|
|
144 |
cancelHold();
|
|
|
145 |
type = "mousemove";
|
|
|
146 |
event.preventDefault();
|
|
|
147 |
|
|
|
148 |
currentDOMElement = getDOMElementFromEvent(event);
|
|
|
149 |
break;
|
|
|
150 |
|
|
|
151 |
case "touchend":
|
|
|
152 |
if (cancelMouseUp) {
|
|
|
153 |
cancelMouseUp = false;
|
|
|
154 |
event.preventDefault();
|
|
|
155 |
return false;
|
|
|
156 |
}
|
|
|
157 |
cancelHold();
|
|
|
158 |
type = "mouseup";
|
|
|
159 |
break;
|
|
|
160 |
|
|
|
161 |
default:
|
|
|
162 |
return;
|
|
|
163 |
}
|
|
|
164 |
var touches = event.changedTouches,
|
|
|
165 |
first = touches[0],
|
|
|
166 |
simulatedEvent = document.createEvent("MouseEvent");
|
|
|
167 |
simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY,false, false, false, false, button, null);
|
|
|
168 |
currentDOMElement.dispatchEvent(simulatedEvent);
|
|
|
169 |
if (type == "mouseup" && tapValid && first.target == lastTap) { // This actually emulates the ipad's default behavior (which we prevented)
|
|
|
170 |
simulatedEvent = document.createEvent("MouseEvent"); // This check avoids click being emulated on a double tap
|
|
|
171 |
simulatedEvent.initMouseEvent("click", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY,false, false, false, false, button, null);
|
|
|
172 |
currentDOMElement.dispatchEvent(simulatedEvent);
|
|
|
173 |
}
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
$.extend($.support, {
|
|
|
177 |
touch: "ontouchend" in document
|
|
|
178 |
});
|
|
|
179 |
|
|
|
180 |
$.fn.addTouch = function () {
|
|
|
181 |
if ($.support.touch) {
|
|
|
182 |
this.each(function (i, el) {
|
|
|
183 |
el.addEventListener("touchstart", iPadTouchHandler, false);
|
|
|
184 |
el.addEventListener("touchmove", iPadTouchHandler, false);
|
|
|
185 |
el.addEventListener("touchend", iPadTouchHandler, false);
|
|
|
186 |
el.addEventListener("touchcancel", iPadTouchHandler, false);
|
|
|
187 |
});
|
|
|
188 |
}
|
|
|
189 |
return this;
|
|
|
190 |
};
|
|
|
191 |
|
|
|
192 |
})(jQuery);
|