Path: blob/trunk/third_party/closure/goog/events/browserevent.js
4588 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview A patched, standardized event object for browser events.8*9* <pre>10* The patched event object contains the following members:11* - type {string} Event type, e.g. 'click'12* - target {Object} The element that actually triggered the event13* - currentTarget {Object} The element the listener is attached to14* - relatedTarget {Object} For mouseover and mouseout, the previous object15* - offsetX {number} X-coordinate relative to target16* - offsetY {number} Y-coordinate relative to target17* - clientX {number} X-coordinate relative to viewport18* - clientY {number} Y-coordinate relative to viewport19* - screenX {number} X-coordinate relative to the edge of the screen20* - screenY {number} Y-coordinate relative to the edge of the screen21* - button {number} Mouse button. Use isButton() to test.22* - keyCode {number} Key-code23* - ctrlKey {boolean} Was ctrl key depressed24* - altKey {boolean} Was alt key depressed25* - shiftKey {boolean} Was shift key depressed26* - metaKey {boolean} Was meta key depressed27* - pointerId {number} Pointer ID28* - pointerType {string} Pointer type, e.g. 'mouse', 'pen', or 'touch'29* - defaultPrevented {boolean} Whether the default action has been prevented30* - state {Object} History state object31*32* NOTE: The keyCode member contains the raw browser keyCode. For normalized33* key and character code use {@link goog.events.KeyHandler}.34* </pre>35*/3637goog.provide('goog.events.BrowserEvent');38goog.provide('goog.events.BrowserEvent.MouseButton');39goog.provide('goog.events.BrowserEvent.PointerType');4041goog.require('goog.debug');42goog.require('goog.events.Event');43goog.require('goog.events.EventType');44goog.require('goog.reflect');45goog.require('goog.userAgent');4647goog.require('goog.utils');4849/**50* Accepts a browser event object and creates a patched, cross browser event51* object.52* The content of this object will not be initialized if no event object is53* provided. If this is the case, init() needs to be invoked separately.54* @param {Event=} opt_e Browser event object.55* @param {EventTarget=} opt_currentTarget Current target for event.56* @constructor57* @extends {goog.events.Event}58*/59goog.events.BrowserEvent = function(opt_e, opt_currentTarget) {60'use strict';61goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : '');6263/**64* Target that fired the event.65* @override66* @type {?Node}67*/68this.target = null;6970/**71* Node that had the listener attached.72* @override73* @type {?Node|undefined}74*/75this.currentTarget = null;7677/**78* For mouseover and mouseout events, the related object for the event.79* @type {?Node}80*/81this.relatedTarget = null;8283/**84* X-coordinate relative to target.85* @type {number}86*/87this.offsetX = 0;8889/**90* Y-coordinate relative to target.91* @type {number}92*/93this.offsetY = 0;9495/**96* X-coordinate relative to the window.97* @type {number}98*/99this.clientX = 0;100101/**102* Y-coordinate relative to the window.103* @type {number}104*/105this.clientY = 0;106107/**108* X-coordinate relative to the monitor.109* @type {number}110*/111this.screenX = 0;112113/**114* Y-coordinate relative to the monitor.115* @type {number}116*/117this.screenY = 0;118119/**120* Which mouse button was pressed.121* @type {number}122*/123this.button = 0;124125/**126* Key of key press.127* @type {string}128*/129this.key = '';130131/**132* Keycode of key press.133* @type {number}134*/135this.keyCode = 0;136137/**138* Keycode of key press.139* @type {number}140*/141this.charCode = 0;142143/**144* Whether control was pressed at time of event.145* @type {boolean}146*/147this.ctrlKey = false;148149/**150* Whether alt was pressed at time of event.151* @type {boolean}152*/153this.altKey = false;154155/**156* Whether shift was pressed at time of event.157* @type {boolean}158*/159this.shiftKey = false;160161/**162* Whether the meta key was pressed at time of event.163* @type {boolean}164*/165this.metaKey = false;166167/**168* History state object, only set for PopState events where it's a copy of the169* state object provided to pushState or replaceState.170* @type {?Object}171*/172this.state = null;173174/**175* Whether the default platform modifier key was pressed at time of event.176* (This is control for all platforms except Mac, where it's Meta.)177* @type {boolean}178*/179this.platformModifierKey = false;180181/**182* @type {number}183*/184this.pointerId = 0;185186/**187* @type {string}188*/189this.pointerType = '';190191/**192* The browser event object.193* @private {?Event}194*/195this.event_ = null;196197if (opt_e) {198this.init(opt_e, opt_currentTarget);199}200};201goog.utils.inherits(goog.events.BrowserEvent, goog.events.Event);202203/**204* @define {boolean} If true, use the layerX and layerY properties of a native205* browser event over the offsetX and offsetY properties, which cause expensive206* reflow. If layerX or layerY is not defined, offsetX and offsetY will be used207* as usual.208*/209goog.events.BrowserEvent.USE_LAYER_XY_AS_OFFSET_XY =210goog.define('goog.events.BrowserEvent.USE_LAYER_XY_AS_OFFSET_XY', false);211212213/**214* Normalized button constants for the mouse.215* @enum {number}216*/217goog.events.BrowserEvent.MouseButton = {218LEFT: 0,219MIDDLE: 1,220RIGHT: 2,221BACK: 3,222FORWARD: 4,223};224225226/**227* Normalized pointer type constants for pointer events.228* @enum {string}229*/230goog.events.BrowserEvent.PointerType = {231MOUSE: 'mouse',232PEN: 'pen',233TOUCH: 'touch'234};235236237/**238* Static data for mapping mouse buttons.239* @type {!Array<number>}240* @deprecated Use `goog.events.BrowserEvent.IE_BUTTON_MAP` instead.241*/242goog.events.BrowserEvent.IEButtonMap = goog.debug.freeze([2431, // LEFT2444, // MIDDLE2452 // RIGHT246]);247248249/**250* Static data for mapping mouse buttons.251* @const {!Array<number>}252*/253goog.events.BrowserEvent.IE_BUTTON_MAP = goog.events.BrowserEvent.IEButtonMap;254255256/**257* Static data for mapping MSPointerEvent types to PointerEvent types.258* @const {!Object<number, goog.events.BrowserEvent.PointerType>}259*/260goog.events.BrowserEvent.IE_POINTER_TYPE_MAP = goog.debug.freeze({2612: goog.events.BrowserEvent.PointerType.TOUCH,2623: goog.events.BrowserEvent.PointerType.PEN,2634: goog.events.BrowserEvent.PointerType.MOUSE264});265266267/**268* Accepts a browser event object and creates a patched, cross browser event269* object.270* @param {Event} e Browser event object.271* @param {EventTarget=} opt_currentTarget Current target for event.272*/273goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {274'use strict';275var type = this.type = e.type;276277/**278* On touch devices use the first "changed touch" as the relevant touch.279* @type {?Touch}280* @suppress {strictMissingProperties} Added to tighten compiler checks281*/282var relevantTouch =283e.changedTouches && e.changedTouches.length ? e.changedTouches[0] : null;284285// TODO(nicksantos): Change this.target to type EventTarget.286this.target = /** @type {Node} */ (e.target) || e.srcElement;287288// TODO(nicksantos): Change this.currentTarget to type EventTarget.289this.currentTarget = /** @type {Node} */ (opt_currentTarget);290291var relatedTarget = /** @type {Node} */ (e.relatedTarget);292if (relatedTarget) {293// There's a bug in FireFox where sometimes, relatedTarget will be a294// chrome element, and accessing any property of it will get a permission295// denied exception. See:296// https://bugzilla.mozilla.org/show_bug.cgi?id=497780297if (goog.userAgent.GECKO) {298if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) {299relatedTarget = null;300}301}302} else if (type == goog.events.EventType.MOUSEOVER) {303relatedTarget = e.fromElement;304} else if (type == goog.events.EventType.MOUSEOUT) {305relatedTarget = e.toElement;306}307308this.relatedTarget = relatedTarget;309310if (relevantTouch) {311this.clientX = relevantTouch.clientX !== undefined ? relevantTouch.clientX :312relevantTouch.pageX;313this.clientY = relevantTouch.clientY !== undefined ? relevantTouch.clientY :314relevantTouch.pageY;315this.screenX = relevantTouch.screenX || 0;316this.screenY = relevantTouch.screenY || 0;317} else {318if (goog.events.BrowserEvent.USE_LAYER_XY_AS_OFFSET_XY) {319this.offsetX = (e.layerX !== undefined) ? e.layerX : e.offsetX;320this.offsetY = (e.layerY !== undefined) ? e.layerY : e.offsetY;321} else {322// Webkit emits a lame warning whenever layerX/layerY is accessed.323// http://code.google.com/p/chromium/issues/detail?id=101733324this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ?325e.offsetX :326e.layerX;327this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ?328e.offsetY :329e.layerY;330}331this.clientX = e.clientX !== undefined ? e.clientX : e.pageX;332this.clientY = e.clientY !== undefined ? e.clientY : e.pageY;333this.screenX = e.screenX || 0;334this.screenY = e.screenY || 0;335}336337this.button = e.button;338339this.keyCode = e.keyCode || 0;340/** @suppress {strictMissingProperties} Added to tighten compiler checks */341this.key = e.key || '';342this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0);343this.ctrlKey = e.ctrlKey;344this.altKey = e.altKey;345this.shiftKey = e.shiftKey;346this.metaKey = e.metaKey;347this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey;348/** @suppress {strictMissingProperties} Added to tighten compiler checks */349this.pointerId = e.pointerId || 0;350this.pointerType = goog.events.BrowserEvent.getPointerType_(e);351/** @suppress {strictMissingProperties} Added to tighten compiler checks */352this.state = e.state;353this.event_ = e;354if (e.defaultPrevented) {355// Sync native event state to internal state via super class, where default356// prevention is implemented and managed.357goog.events.BrowserEvent.superClass_.preventDefault.call(this);358}359};360361362/**363* Tests to see which button was pressed during the event. This is really only364* useful in IE and Gecko browsers. And in IE, it's only useful for365* mousedown/mouseup events, because click only fires for the left mouse button.366*367* Safari 2 only reports the left button being clicked, and uses the value '1'368* instead of 0. Opera only reports a mousedown event for the middle button, and369* no mouse events for the right button. Opera has default behavior for left and370* middle click that can only be overridden via a configuration setting.371*372* There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html.373*374* @param {goog.events.BrowserEvent.MouseButton} button The button375* to test for.376* @return {boolean} True if button was pressed.377*/378goog.events.BrowserEvent.prototype.isButton = function(button) {379'use strict';380return this.event_.button == button;381};382383384/**385* Whether this has an "action"-producing mouse button.386*387* By definition, this includes left-click on windows/linux, and left-click388* without the ctrl key on Macs.389*390* @return {boolean} The result.391*/392goog.events.BrowserEvent.prototype.isMouseActionButton = function() {393'use strict';394// Ctrl+click should never behave like a left-click on mac, regardless of395// whether or not the browser will actually ever emit such an event. If396// we see it, treat it like right-click always.397return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) &&398!(goog.userAgent.MAC && this.ctrlKey);399};400401402/**403* @override404*/405goog.events.BrowserEvent.prototype.stopPropagation = function() {406'use strict';407goog.events.BrowserEvent.superClass_.stopPropagation.call(this);408if (this.event_.stopPropagation) {409this.event_.stopPropagation();410} else {411this.event_.cancelBubble = true;412}413};414415416/**417* @override418*/419goog.events.BrowserEvent.prototype.preventDefault = function() {420'use strict';421goog.events.BrowserEvent.superClass_.preventDefault.call(this);422var be = this.event_;423if (!be.preventDefault) {424be.returnValue = false;425} else {426be.preventDefault();427}428};429430431/**432* @return {Event} The underlying browser event object.433*/434goog.events.BrowserEvent.prototype.getBrowserEvent = function() {435'use strict';436return this.event_;437};438439440/**441* Extracts the pointer type from the given event.442* @param {!Event} e443* @return {string} The pointer type, e.g. 'mouse', 'pen', or 'touch'.444* @private445*/446goog.events.BrowserEvent.getPointerType_ = function(e) {447'use strict';448if (typeof (e.pointerType) === 'string') {449return e.pointerType;450}451// IE10 uses integer codes for pointer type.452// https://msdn.microsoft.com/en-us/library/hh772359(v=vs.85).aspx453return goog.events.BrowserEvent.IE_POINTER_TYPE_MAP[e.pointerType] || '';454};455456457