|
85 | 85 | var docEl = document.documentElement;
|
86 | 86 | var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
|
87 | 87 | && 'onmouseleave' in docEl;
|
88 |
| - var IE_LEGACY_EVENT_SYSTEM = (window.attachEvent && !window.addEventListener); |
89 |
| - |
| 88 | + |
| 89 | + |
| 90 | + // We need to support three different event "modes": |
| 91 | + // 1. browsers with only DOM L2 Events (WebKit, FireFox); |
| 92 | + // 2. browsers with only IE's legacy events system (IE 6-8); |
| 93 | + // 3. browsers with _both_ systems (IE 9 and arguably Opera). |
| 94 | + // |
| 95 | + // Groups 1 and 2 are easy; group three is trickier. |
| 96 | + |
| 97 | + var isIELegacyEvent = function(event) { return false; }; |
| 98 | + |
| 99 | + if (window.attachEvent) { |
| 100 | + if (window.addEventListener) { |
| 101 | + // Both systems are supported. We need to decide at runtime. |
| 102 | + // (Though Opera supports both systems, the event object appears to be |
| 103 | + // the same no matter which system is used. That means that this function |
| 104 | + // will always return `true` in Opera, but that's OK; it keeps us from |
| 105 | + // having to do a browser sniff. |
| 106 | + isIELegacyEvent = function(event) { |
| 107 | + return !(event instanceof window.Event); |
| 108 | + }; |
| 109 | + } else { |
| 110 | + // No support for DOM L2 events. All events will be legacy. |
| 111 | + isIELegacyEvent = function(event) { return true; }; |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + // The two systems have different ways of indicating which button was used |
| 116 | + // for a mouse event. |
90 | 117 | var _isButton;
|
91 |
| - if (IE_LEGACY_EVENT_SYSTEM) { |
92 |
| - // IE's event system doesn't map left/right/middle the same way. |
93 |
| - var buttonMap = { 0: 1, 1: 4, 2: 2 }; |
94 |
| - _isButton = function(event, code) { |
95 |
| - return event.button === buttonMap[code]; |
96 |
| - }; |
97 |
| - } else if (Prototype.Browser.WebKit) { |
98 |
| - // In Safari we have to account for when the user holds down |
99 |
| - // the "meta" key. |
100 |
| - _isButton = function(event, code) { |
101 |
| - switch (code) { |
102 |
| - case 0: return event.which == 1 && !event.metaKey; |
103 |
| - case 1: return event.which == 2 || (event.which == 1 && event.metaKey); |
104 |
| - case 2: return event.which == 3; |
105 |
| - default: return false; |
| 118 | + |
| 119 | + function _isButtonForDOMEvents(event, code) { |
| 120 | + return event.which ? (event.which === code + 1) : (event.button === code); |
| 121 | + } |
| 122 | + |
| 123 | + var legacyButtonMap = { 0: 1, 1: 4, 2: 2 }; |
| 124 | + function _isButtonForLegacyEvents(event, code) { |
| 125 | + return event.button === legacyButtonMap[code]; |
| 126 | + } |
| 127 | + |
| 128 | + // In WebKit we have to account for when the user holds down the "meta" key. |
| 129 | + function _isButtonForWebKit(event, code) { |
| 130 | + switch (code) { |
| 131 | + case 0: return event.which == 1 && !event.metaKey; |
| 132 | + case 1: return event.which == 2 || (event.which == 1 && event.metaKey); |
| 133 | + case 2: return event.which == 3; |
| 134 | + default: return false; |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + if (window.attachEvent) { |
| 139 | + if (!window.addEventListener) { |
| 140 | + // Legacy IE events only. |
| 141 | + _isButton = _isButtonForLegacyEvents; |
| 142 | + } else { |
| 143 | + // Both systems are supported; decide at runtime. |
| 144 | + _isButton = function(event, code) { |
| 145 | + return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) : |
| 146 | + _isButtonForDOMEvents(event, code); |
106 | 147 | }
|
107 |
| - }; |
| 148 | + } |
| 149 | + } else if (Prototype.Browser.WebKit) { |
| 150 | + _isButton = _isButtonForWebKit; |
108 | 151 | } else {
|
109 |
| - _isButton = function(event, code) { |
110 |
| - return event.which ? (event.which === code + 1) : (event.button === code); |
111 |
| - }; |
| 152 | + _isButton = _isButtonForDOMEvents; |
112 | 153 | }
|
113 | 154 |
|
114 | 155 | /**
|
|
344 | 385 | event.stopped = true;
|
345 | 386 | }
|
346 | 387 |
|
| 388 | + |
347 | 389 | Event.Methods = {
|
348 |
| - isLeftClick: isLeftClick, |
| 390 | + isLeftClick: isLeftClick, |
349 | 391 | isMiddleClick: isMiddleClick,
|
350 |
| - isRightClick: isRightClick, |
| 392 | + isRightClick: isRightClick, |
351 | 393 |
|
352 |
| - element: element, |
| 394 | + element: element, |
353 | 395 | findElement: findElement,
|
354 | 396 |
|
355 |
| - pointer: pointer, |
| 397 | + pointer: pointer, |
356 | 398 | pointerX: pointerX,
|
357 | 399 | pointerY: pointerY,
|
358 | 400 |
|
359 | 401 | stop: stop
|
360 | 402 | };
|
361 | 403 |
|
362 |
| - |
363 | 404 | // Compile the list of methods that get extended onto Events.
|
364 | 405 | var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
|
365 | 406 | m[name] = Event.Methods[name].methodize();
|
366 | 407 | return m;
|
367 | 408 | });
|
368 | 409 |
|
369 |
| - if (IE_LEGACY_EVENT_SYSTEM) { |
| 410 | + if (window.attachEvent) { |
| 411 | + // For IE's event system, we need to do some work to make the event |
| 412 | + // object behave like a standard event object. |
370 | 413 | function _relatedTarget(event) {
|
371 | 414 | var element;
|
372 | 415 | switch (event.type) {
|
|
384 | 427 | return Element.extend(element);
|
385 | 428 | }
|
386 | 429 |
|
387 |
| - Object.extend(methods, { |
| 430 | + // These methods should be added _only_ to legacy IE event objects. |
| 431 | + var additionalMethods = { |
388 | 432 | stopPropagation: function() { this.cancelBubble = true },
|
389 | 433 | preventDefault: function() { this.returnValue = false },
|
390 | 434 | inspect: function() { return '[object Event]' }
|
391 |
| - }); |
| 435 | + }; |
392 | 436 |
|
393 | 437 | /**
|
394 | 438 | * Event.extend(@event) -> Event
|
|
405 | 449 | // IE's method for extending events.
|
406 | 450 | Event.extend = function(event, element) {
|
407 | 451 | if (!event) return false;
|
408 |
| - if (event._extendedByPrototype) return event; |
409 | 452 |
|
| 453 | + // If it's not a legacy event, it doesn't need extending. |
| 454 | + if (!isIELegacyEvent(event)) return event; |
| 455 | + |
| 456 | + // Mark this event so we know not to extend a second time. |
| 457 | + if (event._extendedByPrototype) return event; |
410 | 458 | event._extendedByPrototype = Prototype.emptyFunction;
|
| 459 | + |
411 | 460 | var pointer = Event.pointer(event);
|
412 | 461 |
|
413 | 462 | // The optional `element` argument gives us a fallback value for the
|
|
418 | 467 | pageX: pointer.x,
|
419 | 468 | pageY: pointer.y
|
420 | 469 | });
|
421 |
| - |
422 |
| - return Object.extend(event, methods); |
| 470 | + |
| 471 | + Object.extend(event, methods); |
| 472 | + Object.extend(event, additionalMethods); |
423 | 473 | };
|
424 | 474 | } else {
|
| 475 | + // Only DOM events, so no manual extending necessary. |
| 476 | + Event.extend = Prototype.K; |
| 477 | + } |
| 478 | + |
| 479 | + if (window.addEventListener) { |
| 480 | + // In all browsers that support DOM L2 Events, we can augment |
| 481 | + // `Event.prototype` directly. |
425 | 482 | Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
|
426 | 483 | Object.extend(Event.prototype, methods);
|
427 |
| - Event.extend = Prototype.K; |
428 | 484 | }
|
429 | 485 |
|
430 | 486 | function _createResponder(element, eventName, handler) {
|
|
922 | 978 | },
|
923 | 979 |
|
924 | 980 | handleEvent: function(event) {
|
925 |
| - var element = event.findElement(this.selector); |
| 981 | + var element = Event.findElement(event, this.selector); |
926 | 982 | if (element) this.callback.call(this.element, event, element);
|
927 | 983 | }
|
928 | 984 | });
|
|
0 commit comments