]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | *\r | |
3 | */\r | |
4 | Ext.define('Ext.overrides.event.Event', {\r | |
5 | override: 'Ext.event.Event',\r | |
6 | \r | |
7 | // map of events that should fire global mousedown even if stopped\r | |
8 | mousedownEvents: {\r | |
9 | mousedown: 1,\r | |
10 | pointerdown: 1,\r | |
11 | touchstart: 1\r | |
12 | },\r | |
13 | \r | |
14 | /**\r | |
15 | * @method injectEvent\r | |
16 | * @member Ext.event.Event\r | |
17 | * Injects a DOM event using the data in this object and (optionally) a new target.\r | |
18 | * This is a low-level technique and not likely to be used by application code. The\r | |
19 | * currently supported event types are:\r | |
20 | * <p><b>HTMLEvents</b></p>\r | |
21 | * <ul>\r | |
22 | * <li>load</li>\r | |
23 | * <li>unload</li>\r | |
24 | * <li>select</li>\r | |
25 | * <li>change</li>\r | |
26 | * <li>submit</li>\r | |
27 | * <li>reset</li>\r | |
28 | * <li>resize</li>\r | |
29 | * <li>scroll</li>\r | |
30 | * </ul>\r | |
31 | * <p><b>MouseEvents</b></p>\r | |
32 | * <ul>\r | |
33 | * <li>click</li>\r | |
34 | * <li>dblclick</li>\r | |
35 | * <li>mousedown</li>\r | |
36 | * <li>mouseup</li>\r | |
37 | * <li>mouseover</li>\r | |
38 | * <li>mousemove</li>\r | |
39 | * <li>mouseout</li>\r | |
40 | * </ul>\r | |
41 | * <p><b>UIEvents</b></p>\r | |
42 | * <ul>\r | |
43 | * <li>focusin</li>\r | |
44 | * <li>focusout</li>\r | |
45 | * <li>activate</li>\r | |
46 | * <li>focus</li>\r | |
47 | * <li>blur</li>\r | |
48 | * </ul>\r | |
49 | * @param {Ext.Element/HTMLElement} target (optional) If specified, the target for the event. This\r | |
50 | * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}\r | |
51 | * is used to determine the target.\r | |
52 | */\r | |
53 | injectEvent: (function () {\r | |
54 | var API,\r | |
55 | dispatchers = {}, // keyed by event type (e.g., 'mousedown')\r | |
56 | crazyIEButtons;\r | |
57 | \r | |
58 | // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html\r | |
59 | \r | |
60 | // IE9 has createEvent, but this code causes major problems with htmleditor (it\r | |
61 | // blocks all mouse events and maybe more). TODO\r | |
62 | \r | |
63 | if (!Ext.isIE9m && document.createEvent) { // if (DOM compliant)\r | |
64 | API = {\r | |
65 | createHtmlEvent: function (doc, type, bubbles, cancelable) {\r | |
66 | var event = doc.createEvent('HTMLEvents');\r | |
67 | \r | |
68 | event.initEvent(type, bubbles, cancelable);\r | |
69 | return event;\r | |
70 | },\r | |
71 | \r | |
72 | createMouseEvent: function (doc, type, bubbles, cancelable, detail,\r | |
73 | clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,\r | |
74 | button, relatedTarget) {\r | |
75 | var event = doc.createEvent('MouseEvents'),\r | |
76 | view = doc.defaultView || window;\r | |
77 | \r | |
78 | if (event.initMouseEvent) {\r | |
79 | event.initMouseEvent(type, bubbles, cancelable, view, detail,\r | |
80 | clientX, clientY, clientX, clientY, ctrlKey, altKey,\r | |
81 | shiftKey, metaKey, button, relatedTarget);\r | |
82 | } else { // old Safari\r | |
83 | event = doc.createEvent('UIEvents');\r | |
84 | event.initEvent(type, bubbles, cancelable);\r | |
85 | event.view = view;\r | |
86 | event.detail = detail;\r | |
87 | event.screenX = clientX;\r | |
88 | event.screenY = clientY;\r | |
89 | event.clientX = clientX;\r | |
90 | event.clientY = clientY;\r | |
91 | event.ctrlKey = ctrlKey;\r | |
92 | event.altKey = altKey;\r | |
93 | event.metaKey = metaKey;\r | |
94 | event.shiftKey = shiftKey;\r | |
95 | event.button = button;\r | |
96 | event.relatedTarget = relatedTarget;\r | |
97 | }\r | |
98 | \r | |
99 | return event;\r | |
100 | },\r | |
101 | \r | |
102 | createUIEvent: function (doc, type, bubbles, cancelable, detail) {\r | |
103 | var event = doc.createEvent('UIEvents'),\r | |
104 | view = doc.defaultView || window;\r | |
105 | \r | |
106 | event.initUIEvent(type, bubbles, cancelable, view, detail);\r | |
107 | return event;\r | |
108 | },\r | |
109 | \r | |
110 | fireEvent: function (target, type, event) {\r | |
111 | target.dispatchEvent(event);\r | |
112 | }\r | |
113 | };\r | |
114 | } else if (document.createEventObject) { // else if (IE)\r | |
115 | crazyIEButtons = { 0: 1, 1: 4, 2: 2 };\r | |
116 | \r | |
117 | API = {\r | |
118 | createHtmlEvent: function (doc, type, bubbles, cancelable) {\r | |
119 | var event = doc.createEventObject();\r | |
120 | event.bubbles = bubbles;\r | |
121 | event.cancelable = cancelable;\r | |
122 | return event;\r | |
123 | },\r | |
124 | \r | |
125 | createMouseEvent: function (doc, type, bubbles, cancelable, detail,\r | |
126 | clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,\r | |
127 | button, relatedTarget) {\r | |
128 | var event = doc.createEventObject();\r | |
129 | event.bubbles = bubbles;\r | |
130 | event.cancelable = cancelable;\r | |
131 | event.detail = detail;\r | |
132 | event.screenX = clientX;\r | |
133 | event.screenY = clientY;\r | |
134 | event.clientX = clientX;\r | |
135 | event.clientY = clientY;\r | |
136 | event.ctrlKey = ctrlKey;\r | |
137 | event.altKey = altKey;\r | |
138 | event.shiftKey = shiftKey;\r | |
139 | event.metaKey = metaKey;\r | |
140 | event.button = crazyIEButtons[button] || button;\r | |
141 | event.relatedTarget = relatedTarget; // cannot assign to/fromElement\r | |
142 | return event;\r | |
143 | },\r | |
144 | \r | |
145 | createUIEvent: function (doc, type, bubbles, cancelable, detail) {\r | |
146 | var event = doc.createEventObject();\r | |
147 | event.bubbles = bubbles;\r | |
148 | event.cancelable = cancelable;\r | |
149 | return event;\r | |
150 | },\r | |
151 | \r | |
152 | fireEvent: function (target, type, event) {\r | |
153 | target.fireEvent('on' + type, event);\r | |
154 | }\r | |
155 | };\r | |
156 | }\r | |
157 | \r | |
158 | //----------------\r | |
159 | // HTMLEvents\r | |
160 | \r | |
161 | Ext.Object.each({\r | |
162 | load: [false, false],\r | |
163 | unload: [false, false],\r | |
164 | select: [true, false],\r | |
165 | change: [true, false],\r | |
166 | submit: [true, true],\r | |
167 | reset: [true, false],\r | |
168 | resize: [true, false],\r | |
169 | scroll: [true, false]\r | |
170 | },\r | |
171 | function (name, value) {\r | |
172 | var bubbles = value[0], cancelable = value[1];\r | |
173 | dispatchers[name] = function (targetEl, srcEvent) {\r | |
174 | var e = API.createHtmlEvent(name, bubbles, cancelable);\r | |
175 | API.fireEvent(targetEl, name, e);\r | |
176 | };\r | |
177 | });\r | |
178 | \r | |
179 | //----------------\r | |
180 | // MouseEvents\r | |
181 | \r | |
182 | function createMouseEventDispatcher (type, detail) {\r | |
183 | var cancelable = (type !== 'mousemove');\r | |
184 | return function (targetEl, srcEvent) {\r | |
185 | var xy = srcEvent.getXY(),\r | |
186 | e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,\r | |
187 | detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,\r | |
188 | srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,\r | |
189 | srcEvent.relatedTarget);\r | |
190 | API.fireEvent(targetEl, type, e);\r | |
191 | };\r | |
192 | }\r | |
193 | \r | |
194 | Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],\r | |
195 | function (eventName) {\r | |
196 | dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);\r | |
197 | });\r | |
198 | \r | |
199 | //----------------\r | |
200 | // UIEvents\r | |
201 | \r | |
202 | Ext.Object.each({\r | |
203 | focusin: [true, false],\r | |
204 | focusout: [true, false],\r | |
205 | activate: [true, true],\r | |
206 | focus: [false, false],\r | |
207 | blur: [false, false]\r | |
208 | },\r | |
209 | function (name, value) {\r | |
210 | var bubbles = value[0], cancelable = value[1];\r | |
211 | dispatchers[name] = function (targetEl, srcEvent) {\r | |
212 | var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);\r | |
213 | API.fireEvent(targetEl, name, e);\r | |
214 | };\r | |
215 | });\r | |
216 | \r | |
217 | //---------\r | |
218 | if (!API) {\r | |
219 | // not even sure what ancient browsers fall into this category...\r | |
220 | \r | |
221 | dispatchers = {}; // never mind all those we just built :P\r | |
222 | \r | |
223 | API = {};\r | |
224 | }\r | |
225 | \r | |
226 | function cannotInject (target, srcEvent) {\r | |
227 | //<debug>\r | |
228 | // TODO log something\r | |
229 | //</debug>\r | |
230 | }\r | |
231 | \r | |
232 | return function (target) {\r | |
233 | var me = this,\r | |
234 | dispatcher = dispatchers[me.type] || cannotInject,\r | |
235 | t = target ? (target.dom || target) : me.getTarget();\r | |
236 | \r | |
237 | dispatcher(t, me);\r | |
238 | };\r | |
239 | }()), // call to produce method\r | |
240 | \r | |
241 | preventDefault: function() {\r | |
242 | var me = this,\r | |
243 | event = me.browserEvent,\r | |
244 | parentEvent = me.parentEvent,\r | |
245 | unselectable, target;\r | |
246 | \r | |
247 | \r | |
248 | // This check is for IE8/9. The event object may have been\r | |
249 | // invalidated, so we can't delve into the details of it. If so,\r | |
250 | // just fall out gracefully and don't attempt to do anything.\r | |
251 | if (typeof event.type !== 'unknown') {\r | |
252 | me.defaultPrevented = true;\r | |
253 | \r | |
254 | // if the event was created by prototype-chaining a new object to an existing event\r | |
255 | // instance, we need to make sure the parent event is defaultPrevented as well.\r | |
256 | if (parentEvent) {\r | |
257 | parentEvent.defaultPrevented = true;\r | |
258 | }\r | |
259 | \r | |
260 | if (event.preventDefault) {\r | |
261 | event.preventDefault();\r | |
262 | } else {\r | |
263 | // The purpose of the code below is for preventDefault to stop focus from\r | |
264 | // occurring like it does in other modern browsers. This only happens in\r | |
265 | // IE8/9 when using attachEvent. The use of unselectable seems the most reliable\r | |
266 | // way to prevent this from happening. We need to use a timeout to restore the\r | |
267 | // unselectable state because if we don't setting it has no effect. It's important\r | |
268 | // to set the atrribute to 'on' as opposed to just setting the property on the DOM element.\r | |
269 | // See the link below for a discussion on the issue:\r | |
270 | // http://bugs.jquery.com/ticket/10345\r | |
271 | if (event.type === 'mousedown') {\r | |
272 | target = event.target;\r | |
273 | unselectable = target.getAttribute('unselectable');\r | |
274 | if (unselectable !== 'on') {\r | |
275 | target.setAttribute('unselectable', 'on');\r | |
276 | Ext.defer(function() {\r | |
277 | target.setAttribute('unselectable', unselectable);\r | |
278 | }, 1);\r | |
279 | }\r | |
280 | }\r | |
281 | // IE9 and earlier do not support preventDefault\r | |
282 | event.returnValue = false;\r | |
283 | // Some keys events require setting the keyCode to -1 to be prevented\r | |
284 | // all ctrl + X and F1 -> F12\r | |
285 | if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {\r | |
286 | event.keyCode = -1;\r | |
287 | }\r | |
288 | }\r | |
289 | }\r | |
290 | \r | |
291 | return me;\r | |
292 | },\r | |
293 | \r | |
294 | stopPropagation: function() {\r | |
295 | var me = this,\r | |
296 | event = me.browserEvent;\r | |
297 | \r | |
298 | // This check is for IE8/9. The event object may have been\r | |
299 | // invalidated, so we can't delve into the details of it. If so,\r | |
300 | // just fall out gracefully and don't attempt to do anything.\r | |
301 | if (typeof event.type !== 'unknown') {\r | |
302 | if (me.mousedownEvents[me.type]) {\r | |
303 | // Fire the "unstoppable" global mousedown event\r | |
304 | // (used for menu hiding, etc)\r | |
305 | Ext.GlobalEvents.fireMouseDown(me);\r | |
306 | }\r | |
307 | me.callParent();\r | |
308 | }\r | |
309 | return me;\r | |
310 | },\r | |
311 | \r | |
312 | deprecated: {\r | |
313 | '5.0': {\r | |
314 | methods: {\r | |
315 | /**\r | |
316 | * @method clone\r | |
317 | * @member Ext.event.Event\r | |
318 | * Clones this event.\r | |
319 | * @return {Ext.event.Event} The cloned copy\r | |
320 | * @deprecated 5.0.0\r | |
321 | */\r | |
322 | clone: function() {\r | |
323 | return new this.self(this.browserEvent, this);\r | |
324 | }\r | |
325 | }\r | |
326 | }\r | |
327 | }\r | |
328 | }, function() {\r | |
329 | var Event = this,\r | |
330 | btnMap,\r | |
331 | onKeyDown = function(e) {\r | |
332 | if (e.keyCode === 9) {\r | |
333 | Event.forwardTab = !e.shiftKey;\r | |
334 | }\r | |
335 | },\r | |
336 | onKeyUp = function(e) {\r | |
337 | if (e.keyCode === 9) {\r | |
338 | delete Event.forwardTab;\r | |
339 | }\r | |
340 | };\r | |
341 | \r | |
342 | //<feature legacyBrowser>\r | |
343 | if (Ext.isIE9m) {\r | |
344 | btnMap = {\r | |
345 | 0: 0,\r | |
346 | 1: 0,\r | |
347 | 4: 1,\r | |
348 | 2: 2\r | |
349 | };\r | |
350 | \r | |
351 | Event.override({\r | |
352 | statics: {\r | |
353 | /**\r | |
354 | * @member Ext.event.Event\r | |
355 | * When events are attached using IE's attachEvent API instead of\r | |
356 | * addEventListener accessing any members of an event object asynchronously\r | |
357 | * results in "Member not found" error. To work around this we fabricate\r | |
358 | * our own event object by copying all of its members to a new object.\r | |
359 | * @param {Event} browserEvent The native browser event object\r | |
360 | * @private\r | |
361 | * @static\r | |
362 | */\r | |
363 | enableIEAsync: function(browserEvent) {\r | |
364 | var name,\r | |
365 | fakeEvent = {};\r | |
366 | \r | |
367 | for (name in browserEvent) {\r | |
368 | fakeEvent[name] = browserEvent[name];\r | |
369 | }\r | |
370 | \r | |
371 | return fakeEvent;\r | |
372 | }\r | |
373 | },\r | |
374 | \r | |
375 | constructor: function(event, info, touchesMap, identifiers) {\r | |
376 | var me = this;\r | |
377 | me.callParent([event, info, touchesMap, identifiers]);\r | |
378 | me.button = btnMap[event.button];\r | |
379 | \r | |
380 | if (event.type === 'contextmenu') {\r | |
381 | me.button = 2; // IE8/9 reports click as 0, so we can at least attempt to infer here\r | |
382 | } \r | |
383 | \r | |
384 | // IE8 can throw an error when trying to access properties on a browserEvent\r | |
385 | // object when the event has been buffered or delayed. Cache them here\r | |
386 | // so we can access them later.\r | |
387 | me.toElement = event.toElement;\r | |
388 | me.fromElement = event.fromElement;\r | |
389 | },\r | |
390 | \r | |
391 | mouseLeaveRe: /(mouseout|mouseleave)/,\r | |
392 | mouseEnterRe: /(mouseover|mouseenter)/,\r | |
393 | \r | |
394 | /**\r | |
395 | * @member Ext.event.Event\r | |
396 | * @inheritdoc Ext.event.Event#static-enableIEAsync\r | |
397 | * @private\r | |
398 | */\r | |
399 | enableIEAsync: function(browserEvent) {\r | |
400 | this.browserEvent = this.self.enableIEAsync(browserEvent);\r | |
401 | },\r | |
402 | \r | |
403 | getRelatedTarget: function(selector, maxDepth, returnEl) {\r | |
404 | var me = this,\r | |
405 | type, target;\r | |
406 | \r | |
407 | if (!me.relatedTarget) {\r | |
408 | type = me.type;\r | |
409 | if (me.mouseLeaveRe.test(type)) {\r | |
410 | target = me.toElement;\r | |
411 | } else if (me.mouseEnterRe.test(type)) {\r | |
412 | target = me.fromElement;\r | |
413 | }\r | |
414 | if (target) {\r | |
415 | me.relatedTarget = me.self.resolveTextNode(target);\r | |
416 | }\r | |
417 | }\r | |
418 | \r | |
419 | return me.callParent([selector, maxDepth, returnEl]);\r | |
420 | }\r | |
421 | });\r | |
422 | \r | |
423 | // We place these listeners to capture Tab and Shift-Tab key strokes\r | |
424 | // and pass this information in the focus/blur event if it happens\r | |
425 | // between keydown/keyup pair.\r | |
426 | document.attachEvent('onkeydown', onKeyDown);\r | |
427 | document.attachEvent('onkeyup', onKeyUp);\r | |
428 | \r | |
429 | window.attachEvent('onunload', function() {\r | |
430 | document.detachEvent('onkeydown', onKeyDown);\r | |
431 | document.detachEvent('onkeyup', onKeyUp);\r | |
432 | });\r | |
433 | }\r | |
434 | else\r | |
435 | //</feature>\r | |
436 | if (document.addEventListener) {\r | |
437 | document.addEventListener('keydown', onKeyDown, true);\r | |
438 | document.addEventListener('keyup', onKeyUp, true);\r | |
439 | }\r | |
440 | });\r |