initial commit
This commit is contained in:
Executable
+447
@@ -0,0 +1,447 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview A patched, standardized event object for browser events.
|
||||
*
|
||||
* <pre>
|
||||
* The patched event object contains the following members:
|
||||
* - type {string} Event type, e.g. 'click'
|
||||
* - target {Object} The element that actually triggered the event
|
||||
* - currentTarget {Object} The element the listener is attached to
|
||||
* - relatedTarget {Object} For mouseover and mouseout, the previous object
|
||||
* - offsetX {number} X-coordinate relative to target
|
||||
* - offsetY {number} Y-coordinate relative to target
|
||||
* - clientX {number} X-coordinate relative to viewport
|
||||
* - clientY {number} Y-coordinate relative to viewport
|
||||
* - screenX {number} X-coordinate relative to the edge of the screen
|
||||
* - screenY {number} Y-coordinate relative to the edge of the screen
|
||||
* - button {number} Mouse button. Use isButton() to test.
|
||||
* - keyCode {number} Key-code
|
||||
* - ctrlKey {boolean} Was ctrl key depressed
|
||||
* - altKey {boolean} Was alt key depressed
|
||||
* - shiftKey {boolean} Was shift key depressed
|
||||
* - metaKey {boolean} Was meta key depressed
|
||||
* - pointerId {number} Pointer ID
|
||||
* - pointerType {string} Pointer type, e.g. 'mouse', 'pen', or 'touch'
|
||||
* - defaultPrevented {boolean} Whether the default action has been prevented
|
||||
* - state {Object} History state object
|
||||
*
|
||||
* NOTE: The keyCode member contains the raw browser keyCode. For normalized
|
||||
* key and character code use {@link goog.events.KeyHandler}.
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.BrowserEvent');
|
||||
goog.provide('goog.events.BrowserEvent.MouseButton');
|
||||
goog.provide('goog.events.BrowserEvent.PointerType');
|
||||
|
||||
goog.require('goog.debug');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.reflect');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
/**
|
||||
* @define {boolean} If true, use the layerX and layerY properties of a native
|
||||
* browser event over the offsetX and offsetY properties, which cause expensive
|
||||
* reflow. If layerX or layerY is not defined, offsetX and offsetY will be used
|
||||
* as usual.
|
||||
*/
|
||||
goog.events.USE_LAYER_XY_AS_OFFSET_XY =
|
||||
goog.define('goog.events.USE_LAYER_XY_AS_OFFSET_XY', false);
|
||||
|
||||
/**
|
||||
* Accepts a browser event object and creates a patched, cross browser event
|
||||
* object.
|
||||
* The content of this object will not be initialized if no event object is
|
||||
* provided. If this is the case, init() needs to be invoked separately.
|
||||
* @param {Event=} opt_e Browser event object.
|
||||
* @param {EventTarget=} opt_currentTarget Current target for event.
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
*/
|
||||
goog.events.BrowserEvent = function(opt_e, opt_currentTarget) {
|
||||
'use strict';
|
||||
goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : '');
|
||||
|
||||
/**
|
||||
* Target that fired the event.
|
||||
* @override
|
||||
* @type {?Node}
|
||||
*/
|
||||
this.target = null;
|
||||
|
||||
/**
|
||||
* Node that had the listener attached.
|
||||
* @override
|
||||
* @type {?Node|undefined}
|
||||
*/
|
||||
this.currentTarget = null;
|
||||
|
||||
/**
|
||||
* For mouseover and mouseout events, the related object for the event.
|
||||
* @type {?Node}
|
||||
*/
|
||||
this.relatedTarget = null;
|
||||
|
||||
/**
|
||||
* X-coordinate relative to target.
|
||||
* @type {number}
|
||||
*/
|
||||
this.offsetX = 0;
|
||||
|
||||
/**
|
||||
* Y-coordinate relative to target.
|
||||
* @type {number}
|
||||
*/
|
||||
this.offsetY = 0;
|
||||
|
||||
/**
|
||||
* X-coordinate relative to the window.
|
||||
* @type {number}
|
||||
*/
|
||||
this.clientX = 0;
|
||||
|
||||
/**
|
||||
* Y-coordinate relative to the window.
|
||||
* @type {number}
|
||||
*/
|
||||
this.clientY = 0;
|
||||
|
||||
/**
|
||||
* X-coordinate relative to the monitor.
|
||||
* @type {number}
|
||||
*/
|
||||
this.screenX = 0;
|
||||
|
||||
/**
|
||||
* Y-coordinate relative to the monitor.
|
||||
* @type {number}
|
||||
*/
|
||||
this.screenY = 0;
|
||||
|
||||
/**
|
||||
* Which mouse button was pressed.
|
||||
* @type {number}
|
||||
*/
|
||||
this.button = 0;
|
||||
|
||||
/**
|
||||
* Key of key press.
|
||||
* @type {string}
|
||||
*/
|
||||
this.key = '';
|
||||
|
||||
/**
|
||||
* Keycode of key press.
|
||||
* @type {number}
|
||||
*/
|
||||
this.keyCode = 0;
|
||||
|
||||
/**
|
||||
* Keycode of key press.
|
||||
* @type {number}
|
||||
*/
|
||||
this.charCode = 0;
|
||||
|
||||
/**
|
||||
* Whether control was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.ctrlKey = false;
|
||||
|
||||
/**
|
||||
* Whether alt was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.altKey = false;
|
||||
|
||||
/**
|
||||
* Whether shift was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.shiftKey = false;
|
||||
|
||||
/**
|
||||
* Whether the meta key was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.metaKey = false;
|
||||
|
||||
/**
|
||||
* History state object, only set for PopState events where it's a copy of the
|
||||
* state object provided to pushState or replaceState.
|
||||
* @type {?Object}
|
||||
*/
|
||||
this.state = null;
|
||||
|
||||
/**
|
||||
* Whether the default platform modifier key was pressed at time of event.
|
||||
* (This is control for all platforms except Mac, where it's Meta.)
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.platformModifierKey = false;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.pointerId = 0;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
this.pointerType = '';
|
||||
|
||||
/**
|
||||
* The browser event object.
|
||||
* @private {?Event}
|
||||
*/
|
||||
this.event_ = null;
|
||||
|
||||
if (opt_e) {
|
||||
this.init(opt_e, opt_currentTarget);
|
||||
}
|
||||
};
|
||||
goog.inherits(goog.events.BrowserEvent, goog.events.Event);
|
||||
|
||||
|
||||
/**
|
||||
* Normalized button constants for the mouse.
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.events.BrowserEvent.MouseButton = {
|
||||
LEFT: 0,
|
||||
MIDDLE: 1,
|
||||
RIGHT: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalized pointer type constants for pointer events.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.events.BrowserEvent.PointerType = {
|
||||
MOUSE: 'mouse',
|
||||
PEN: 'pen',
|
||||
TOUCH: 'touch'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static data for mapping mouse buttons.
|
||||
* @type {!Array<number>}
|
||||
* @deprecated Use `goog.events.BrowserEvent.IE_BUTTON_MAP` instead.
|
||||
*/
|
||||
goog.events.BrowserEvent.IEButtonMap = goog.debug.freeze([
|
||||
1, // LEFT
|
||||
4, // MIDDLE
|
||||
2 // RIGHT
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Static data for mapping mouse buttons.
|
||||
* @const {!Array<number>}
|
||||
*/
|
||||
goog.events.BrowserEvent.IE_BUTTON_MAP = goog.events.BrowserEvent.IEButtonMap;
|
||||
|
||||
|
||||
/**
|
||||
* Static data for mapping MSPointerEvent types to PointerEvent types.
|
||||
* @const {!Object<number, goog.events.BrowserEvent.PointerType>}
|
||||
*/
|
||||
goog.events.BrowserEvent.IE_POINTER_TYPE_MAP = goog.debug.freeze({
|
||||
2: goog.events.BrowserEvent.PointerType.TOUCH,
|
||||
3: goog.events.BrowserEvent.PointerType.PEN,
|
||||
4: goog.events.BrowserEvent.PointerType.MOUSE
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Accepts a browser event object and creates a patched, cross browser event
|
||||
* object.
|
||||
* @param {Event} e Browser event object.
|
||||
* @param {EventTarget=} opt_currentTarget Current target for event.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {
|
||||
'use strict';
|
||||
var type = this.type = e.type;
|
||||
|
||||
/**
|
||||
* On touch devices use the first "changed touch" as the relevant touch.
|
||||
* @type {?Touch}
|
||||
*/
|
||||
var relevantTouch =
|
||||
e.changedTouches && e.changedTouches.length ? e.changedTouches[0] : null;
|
||||
|
||||
// TODO(nicksantos): Change this.target to type EventTarget.
|
||||
this.target = /** @type {Node} */ (e.target) || e.srcElement;
|
||||
|
||||
// TODO(nicksantos): Change this.currentTarget to type EventTarget.
|
||||
this.currentTarget = /** @type {Node} */ (opt_currentTarget);
|
||||
|
||||
var relatedTarget = /** @type {Node} */ (e.relatedTarget);
|
||||
if (relatedTarget) {
|
||||
// There's a bug in FireFox where sometimes, relatedTarget will be a
|
||||
// chrome element, and accessing any property of it will get a permission
|
||||
// denied exception. See:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=497780
|
||||
if (goog.userAgent.GECKO) {
|
||||
if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) {
|
||||
relatedTarget = null;
|
||||
}
|
||||
}
|
||||
} else if (type == goog.events.EventType.MOUSEOVER) {
|
||||
relatedTarget = e.fromElement;
|
||||
} else if (type == goog.events.EventType.MOUSEOUT) {
|
||||
relatedTarget = e.toElement;
|
||||
}
|
||||
|
||||
this.relatedTarget = relatedTarget;
|
||||
|
||||
if (relevantTouch) {
|
||||
this.clientX = relevantTouch.clientX !== undefined ? relevantTouch.clientX :
|
||||
relevantTouch.pageX;
|
||||
this.clientY = relevantTouch.clientY !== undefined ? relevantTouch.clientY :
|
||||
relevantTouch.pageY;
|
||||
this.screenX = relevantTouch.screenX || 0;
|
||||
this.screenY = relevantTouch.screenY || 0;
|
||||
} else {
|
||||
if (goog.events.USE_LAYER_XY_AS_OFFSET_XY) {
|
||||
this.offsetX = (e.layerX !== undefined) ? e.layerX : e.offsetX;
|
||||
this.offsetY = (e.layerY !== undefined) ? e.layerY : e.offsetY;
|
||||
} else {
|
||||
// Webkit emits a lame warning whenever layerX/layerY is accessed.
|
||||
// http://code.google.com/p/chromium/issues/detail?id=101733
|
||||
this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ?
|
||||
e.offsetX :
|
||||
e.layerX;
|
||||
this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ?
|
||||
e.offsetY :
|
||||
e.layerY;
|
||||
}
|
||||
this.clientX = e.clientX !== undefined ? e.clientX : e.pageX;
|
||||
this.clientY = e.clientY !== undefined ? e.clientY : e.pageY;
|
||||
this.screenX = e.screenX || 0;
|
||||
this.screenY = e.screenY || 0;
|
||||
}
|
||||
|
||||
this.button = e.button;
|
||||
|
||||
this.keyCode = e.keyCode || 0;
|
||||
this.key = e.key || '';
|
||||
this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0);
|
||||
this.ctrlKey = e.ctrlKey;
|
||||
this.altKey = e.altKey;
|
||||
this.shiftKey = e.shiftKey;
|
||||
this.metaKey = e.metaKey;
|
||||
this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey;
|
||||
this.pointerId = e.pointerId || 0;
|
||||
this.pointerType = goog.events.BrowserEvent.getPointerType_(e);
|
||||
this.state = e.state;
|
||||
this.event_ = e;
|
||||
if (e.defaultPrevented) {
|
||||
// Sync native event state to internal state via super class, where default
|
||||
// prevention is implemented and managed.
|
||||
goog.events.BrowserEvent.superClass_.preventDefault.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests to see which button was pressed during the event. This is really only
|
||||
* useful in IE and Gecko browsers. And in IE, it's only useful for
|
||||
* mousedown/mouseup events, because click only fires for the left mouse button.
|
||||
*
|
||||
* Safari 2 only reports the left button being clicked, and uses the value '1'
|
||||
* instead of 0. Opera only reports a mousedown event for the middle button, and
|
||||
* no mouse events for the right button. Opera has default behavior for left and
|
||||
* middle click that can only be overridden via a configuration setting.
|
||||
*
|
||||
* There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html.
|
||||
*
|
||||
* @param {goog.events.BrowserEvent.MouseButton} button The button
|
||||
* to test for.
|
||||
* @return {boolean} True if button was pressed.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.isButton = function(button) {
|
||||
'use strict';
|
||||
return this.event_.button == button;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether this has an "action"-producing mouse button.
|
||||
*
|
||||
* By definition, this includes left-click on windows/linux, and left-click
|
||||
* without the ctrl key on Macs.
|
||||
*
|
||||
* @return {boolean} The result.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.isMouseActionButton = function() {
|
||||
'use strict';
|
||||
// Ctrl+click should never behave like a left-click on mac, regardless of
|
||||
// whether or not the browser will actually ever emit such an event. If
|
||||
// we see it, treat it like right-click always.
|
||||
return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) &&
|
||||
!(goog.userAgent.MAC && this.ctrlKey);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.stopPropagation = function() {
|
||||
'use strict';
|
||||
goog.events.BrowserEvent.superClass_.stopPropagation.call(this);
|
||||
if (this.event_.stopPropagation) {
|
||||
this.event_.stopPropagation();
|
||||
} else {
|
||||
this.event_.cancelBubble = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.preventDefault = function() {
|
||||
'use strict';
|
||||
goog.events.BrowserEvent.superClass_.preventDefault.call(this);
|
||||
var be = this.event_;
|
||||
if (!be.preventDefault) {
|
||||
be.returnValue = false;
|
||||
} else {
|
||||
be.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Event} The underlying browser event object.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.getBrowserEvent = function() {
|
||||
'use strict';
|
||||
return this.event_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the pointer type from the given event.
|
||||
* @param {!Event} e
|
||||
* @return {string} The pointer type, e.g. 'mouse', 'pen', or 'touch'.
|
||||
* @private
|
||||
*/
|
||||
goog.events.BrowserEvent.getPointerType_ = function(e) {
|
||||
'use strict';
|
||||
if (typeof (e.pointerType) === 'string') {
|
||||
return e.pointerType;
|
||||
}
|
||||
// IE10 uses integer codes for pointer type.
|
||||
// https://msdn.microsoft.com/en-us/library/hh772359(v=vs.85).aspx
|
||||
return goog.events.BrowserEvent.IE_POINTER_TYPE_MAP[e.pointerType] || '';
|
||||
};
|
||||
Executable
+118
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Browser capability checks for the events package.
|
||||
*/
|
||||
|
||||
goog.module('goog.events.BrowserFeature');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* Tricks Closure Compiler into believing that a function is pure. The compiler
|
||||
* assumes that any `valueOf` function is pure, without analyzing its contents.
|
||||
*
|
||||
* @param {function(): T} fn
|
||||
* @return {T}
|
||||
* @template T
|
||||
*/
|
||||
const purify = (fn) => {
|
||||
return ({valueOf: fn}).valueOf();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enum of browser capabilities.
|
||||
* @enum {boolean}
|
||||
*/
|
||||
exports = {
|
||||
/**
|
||||
* Whether the button attribute of the event is W3C compliant. False in
|
||||
* Internet Explorer prior to version 9; document-version dependent.
|
||||
*/
|
||||
HAS_W3C_BUTTON: true,
|
||||
|
||||
/**
|
||||
* Whether the browser supports full W3C event model.
|
||||
*/
|
||||
HAS_W3C_EVENT_SUPPORT: true,
|
||||
|
||||
/**
|
||||
* To prevent default in IE7-8 for certain keydown events we need set the
|
||||
* keyCode to -1.
|
||||
*/
|
||||
SET_KEY_CODE_TO_PREVENT_DEFAULT: false,
|
||||
|
||||
/**
|
||||
* Whether the `navigator.onLine` property is supported.
|
||||
*/
|
||||
HAS_NAVIGATOR_ONLINE_PROPERTY: true,
|
||||
|
||||
/**
|
||||
* Whether HTML5 network online/offline events are supported.
|
||||
*/
|
||||
HAS_HTML5_NETWORK_EVENT_SUPPORT: true,
|
||||
|
||||
/**
|
||||
* Whether HTML5 network events fire on document.body, or otherwise the
|
||||
* window.
|
||||
*/
|
||||
HTML5_NETWORK_EVENTS_FIRE_ON_BODY: false,
|
||||
|
||||
/**
|
||||
* Whether touch is enabled in the browser.
|
||||
*/
|
||||
TOUCH_ENABLED:
|
||||
('ontouchstart' in goog.global ||
|
||||
!!(goog.global['document'] && document.documentElement &&
|
||||
'ontouchstart' in document.documentElement) ||
|
||||
// IE10 uses non-standard touch events, so it has a different check.
|
||||
!!(goog.global['navigator'] &&
|
||||
(goog.global['navigator']['maxTouchPoints'] ||
|
||||
goog.global['navigator']['msMaxTouchPoints']))),
|
||||
|
||||
/**
|
||||
* Whether addEventListener supports W3C standard pointer events.
|
||||
* http://www.w3.org/TR/pointerevents/
|
||||
*/
|
||||
POINTER_EVENTS: ('PointerEvent' in goog.global),
|
||||
|
||||
/**
|
||||
* Whether addEventListener supports MSPointer events (only used in IE10).
|
||||
* http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx
|
||||
* http://msdn.microsoft.com/library/hh673557(v=vs.85).aspx
|
||||
*/
|
||||
MSPOINTER_EVENTS:
|
||||
('MSPointerEvent' in goog.global &&
|
||||
!!(goog.global['navigator'] &&
|
||||
goog.global['navigator']['msPointerEnabled'])),
|
||||
|
||||
/**
|
||||
* Whether addEventListener supports {passive: true}.
|
||||
* https://developers.google.com/web/updates/2016/06/passive-event-listeners
|
||||
*/
|
||||
PASSIVE_EVENTS: purify(function() {
|
||||
// If we're in a web worker or other custom environment, we can't tell.
|
||||
if (!goog.global.addEventListener || !Object.defineProperty) { // IE 8
|
||||
return false;
|
||||
}
|
||||
|
||||
var passive = false;
|
||||
var options = Object.defineProperty({}, 'passive', {
|
||||
get: function() {
|
||||
passive = true;
|
||||
}
|
||||
});
|
||||
try {
|
||||
goog.global.addEventListener('test', goog.nullFunction, options);
|
||||
goog.global.removeEventListener('test', goog.nullFunction, options);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
return passive;
|
||||
})
|
||||
};
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview A base class for event objects.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.events.Event');
|
||||
|
||||
/**
|
||||
* goog.events.Event no longer depends on goog.Disposable. Keep requiring
|
||||
* goog.Disposable here to not break projects which assume this dependency.
|
||||
* @suppress {extraRequire}
|
||||
*/
|
||||
goog.require('goog.Disposable');
|
||||
goog.require('goog.events.EventId');
|
||||
|
||||
|
||||
/**
|
||||
* A base class for event objects, so that they can support preventDefault and
|
||||
* stopPropagation.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type Event Type.
|
||||
* @param {Object=} opt_target Reference to the object that is the target of
|
||||
* this event. It has to implement the `EventTarget` interface
|
||||
* declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}.
|
||||
* @constructor
|
||||
*/
|
||||
goog.events.Event = function(type, opt_target) {
|
||||
'use strict';
|
||||
/**
|
||||
* Event type.
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = type instanceof goog.events.EventId ? String(type) : type;
|
||||
|
||||
/**
|
||||
* TODO(tbreisacher): The type should probably be
|
||||
* EventTarget|goog.events.EventTarget.
|
||||
*
|
||||
* Target of the event.
|
||||
* @type {Object|undefined}
|
||||
*/
|
||||
this.target = opt_target;
|
||||
|
||||
/**
|
||||
* Object that had the listener attached.
|
||||
* @type {Object|undefined}
|
||||
*/
|
||||
this.currentTarget = this.target;
|
||||
|
||||
/**
|
||||
* Whether to cancel the event in internal capture/bubble processing for IE.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.propagationStopped_ = false;
|
||||
|
||||
/**
|
||||
* Whether the default action has been prevented.
|
||||
* This is a property to match the W3C specification at
|
||||
* {@link http://www.w3.org/TR/DOM-Level-3-Events/
|
||||
* #events-event-type-defaultPrevented}.
|
||||
* Must be treated as read-only outside the class.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.defaultPrevented = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean} true iff internal propagation has been stopped.
|
||||
*/
|
||||
goog.events.Event.prototype.hasPropagationStopped = function() {
|
||||
'use strict';
|
||||
return this.propagationStopped_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stops event propagation.
|
||||
* @return {void}
|
||||
*/
|
||||
goog.events.Event.prototype.stopPropagation = function() {
|
||||
'use strict';
|
||||
this.propagationStopped_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prevents the default action, for example a link redirecting to a url.
|
||||
* @return {void}
|
||||
*/
|
||||
goog.events.Event.prototype.preventDefault = function() {
|
||||
'use strict';
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stops the propagation of the event. It is equivalent to
|
||||
* `e.stopPropagation()`, but can be used as the callback argument of
|
||||
* {@link goog.events.listen} without declaring another function.
|
||||
* @param {!goog.events.Event} e An event.
|
||||
* @return {void}
|
||||
*/
|
||||
goog.events.Event.stopPropagation = function(e) {
|
||||
'use strict';
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prevents the default action. It is equivalent to
|
||||
* `e.preventDefault()`, but can be used as the callback argument of
|
||||
* {@link goog.events.listen} without declaring another function.
|
||||
* @param {!goog.events.Event} e An event.
|
||||
* @return {void}
|
||||
*/
|
||||
goog.events.Event.preventDefault = function(e) {
|
||||
'use strict';
|
||||
e.preventDefault();
|
||||
};
|
||||
Executable
+488
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Class to create objects which want to handle multiple events
|
||||
* and have their listeners easily cleaned up via a dispose method.
|
||||
*
|
||||
* Example:
|
||||
* <pre>
|
||||
* function Something() {
|
||||
* Something.base(this);
|
||||
*
|
||||
* ... set up object ...
|
||||
*
|
||||
* // Add event listeners
|
||||
* this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar);
|
||||
* this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand);
|
||||
* this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse);
|
||||
* this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover);
|
||||
* this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover);
|
||||
* }
|
||||
* goog.inherits(Something, goog.events.EventHandler);
|
||||
*
|
||||
* Something.prototype.disposeInternal = function() {
|
||||
* Something.base(this, 'disposeInternal');
|
||||
* goog.dom.removeNode(this.container);
|
||||
* };
|
||||
*
|
||||
*
|
||||
* // Then elsewhere:
|
||||
*
|
||||
* var activeSomething = null;
|
||||
* function openSomething() {
|
||||
* activeSomething = new Something();
|
||||
* }
|
||||
*
|
||||
* function closeSomething() {
|
||||
* if (activeSomething) {
|
||||
* activeSomething.dispose(); // Remove event listeners
|
||||
* activeSomething = null;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.EventHandler');
|
||||
|
||||
goog.require('goog.Disposable');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.object');
|
||||
goog.requireType('goog.events.Event');
|
||||
goog.requireType('goog.events.EventId');
|
||||
goog.requireType('goog.events.EventTarget');
|
||||
goog.requireType('goog.events.EventWrapper');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Super class for objects that want to easily manage a number of event
|
||||
* listeners. It allows a short cut to listen and also provides a quick way
|
||||
* to remove all events listeners belonging to this object.
|
||||
* @param {SCOPE=} opt_scope Object in whose scope to call the listeners.
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
* @template SCOPE
|
||||
*/
|
||||
goog.events.EventHandler = function(opt_scope) {
|
||||
'use strict';
|
||||
goog.Disposable.call(this);
|
||||
// TODO(mknichel): Rename this to this.scope_ and fix the classes in google3
|
||||
// that access this private variable. :(
|
||||
this.handler_ = opt_scope;
|
||||
|
||||
/**
|
||||
* Keys for events that are being listened to.
|
||||
* @type {!Object<!goog.events.Key>}
|
||||
* @private
|
||||
*/
|
||||
this.keys_ = {};
|
||||
};
|
||||
goog.inherits(goog.events.EventHandler, goog.Disposable);
|
||||
|
||||
|
||||
/**
|
||||
* Utility array used to unify the cases of listening for an array of types
|
||||
* and listening for a single event, without using recursion or allocating
|
||||
* an array each time.
|
||||
* @type {!Array<string>}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventHandler.typeArray_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* Listen to an event on a Listenable. If the function is omitted then the
|
||||
* EventHandler's handleEvent method will be used.
|
||||
* @param {goog.events.ListenableType} src Event source.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type to listen for or array of event types.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
|
||||
* opt_fn Optional callback function to be used as the listener or an object
|
||||
* with handleEvent function.
|
||||
* @param {(boolean|!AddEventListenerOptions)=} opt_options
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template EVENTOBJ, THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listen = function(
|
||||
src, type, opt_fn, opt_options) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
return self.listen_(src, type, opt_fn, opt_options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listen to an event on a Listenable. If the function is omitted then the
|
||||
* EventHandler's handleEvent method will be used.
|
||||
* @param {goog.events.ListenableType} src Event source.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type to listen for or array of event types.
|
||||
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
|
||||
* null|undefined} fn Optional callback function to be used as the
|
||||
* listener or an object with handleEvent function.
|
||||
* @param {boolean|!AddEventListenerOptions|undefined} options
|
||||
* @param {T} scope Object in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template T, EVENTOBJ, THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listenWithScope = function(
|
||||
src, type, fn, options, scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
// TODO(mknichel): Deprecate this function.
|
||||
return self.listen_(src, type, fn, options, scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listen to an event on a Listenable. If the function is omitted then the
|
||||
* EventHandler's handleEvent method will be used.
|
||||
* @param {goog.events.ListenableType} src Event source.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type to listen for or array of event types.
|
||||
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
|
||||
* Optional callback function to be used as the listener or an object with
|
||||
* handleEvent function.
|
||||
* @param {(boolean|!AddEventListenerOptions)=} opt_options
|
||||
* @param {Object=} opt_scope Object in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template EVENTOBJ, THIS
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listen_ = function(
|
||||
src, type, opt_fn, opt_options, opt_scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
if (!Array.isArray(type)) {
|
||||
if (type) {
|
||||
goog.events.EventHandler.typeArray_[0] = type.toString();
|
||||
}
|
||||
type = goog.events.EventHandler.typeArray_;
|
||||
}
|
||||
for (var i = 0; i < type.length; i++) {
|
||||
var listenerObj = goog.events.listen(
|
||||
src, type[i], opt_fn || self.handleEvent, opt_options || false,
|
||||
opt_scope || self.handler_ || self);
|
||||
|
||||
if (!listenerObj) {
|
||||
// When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
|
||||
// (goog.events.CaptureSimulationMode) in IE8-, it will return null
|
||||
// value.
|
||||
return self;
|
||||
}
|
||||
|
||||
var key = listenerObj.key;
|
||||
self.keys_[key] = listenerObj;
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listen to an event on a Listenable. If the function is omitted, then the
|
||||
* EventHandler's handleEvent method will be used. After the event has fired the
|
||||
* event listener is removed from the target. If an array of event types is
|
||||
* provided, each event type will be listened to once.
|
||||
* @param {goog.events.ListenableType} src Event source.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type to listen for or array of event types.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
|
||||
* opt_fn
|
||||
* Optional callback function to be used as the listener or an object with
|
||||
* handleEvent function.
|
||||
* @param {(boolean|!AddEventListenerOptions)=} opt_options
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template EVENTOBJ, THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listenOnce = function(
|
||||
src, type, opt_fn, opt_options) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
return self.listenOnce_(src, type, opt_fn, opt_options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listen to an event on a Listenable. If the function is omitted, then the
|
||||
* EventHandler's handleEvent method will be used. After the event has fired the
|
||||
* event listener is removed from the target. If an array of event types is
|
||||
* provided, each event type will be listened to once.
|
||||
* @param {goog.events.ListenableType} src Event source.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type to listen for or array of event types.
|
||||
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
|
||||
* null|undefined} fn Optional callback function to be used as the
|
||||
* listener or an object with handleEvent function.
|
||||
* @param {boolean|undefined} capture Optional whether to use capture phase.
|
||||
* @param {T} scope Object in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template T, EVENTOBJ, THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listenOnceWithScope = function(
|
||||
src, type, fn, capture, scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
// TODO(mknichel): Deprecate this function.
|
||||
return self.listenOnce_(src, type, fn, capture, scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listen to an event on a Listenable. If the function is omitted, then the
|
||||
* EventHandler's handleEvent method will be used. After the event has fired
|
||||
* the event listener is removed from the target. If an array of event types is
|
||||
* provided, each event type will be listened to once.
|
||||
* @param {goog.events.ListenableType} src Event source.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type to listen for or array of event types.
|
||||
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
|
||||
* Optional callback function to be used as the listener or an object with
|
||||
* handleEvent function.
|
||||
* @param {(boolean|!AddEventListenerOptions)=} opt_options
|
||||
* @param {Object=} opt_scope Object in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template EVENTOBJ, THIS
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listenOnce_ = function(
|
||||
src, type, opt_fn, opt_options, opt_scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
if (Array.isArray(type)) {
|
||||
for (var i = 0; i < type.length; i++) {
|
||||
self.listenOnce_(src, type[i], opt_fn, opt_options, opt_scope);
|
||||
}
|
||||
} else {
|
||||
var listenerObj = goog.events.listenOnce(
|
||||
src, type, opt_fn || self.handleEvent, opt_options,
|
||||
opt_scope || self.handler_ || self);
|
||||
if (!listenerObj) {
|
||||
// When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
|
||||
// (goog.events.CaptureSimulationMode) in IE8-, it will return null
|
||||
// value.
|
||||
return self;
|
||||
}
|
||||
|
||||
var key = listenerObj.key;
|
||||
self.keys_[key] = listenerObj;
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener with a specific event wrapper on a DOM Node or an
|
||||
* object that has implemented {@link goog.events.EventTarget}. A listener can
|
||||
* only be added once to an object.
|
||||
*
|
||||
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
|
||||
* events on.
|
||||
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
|
||||
* @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener
|
||||
* Callback method, or an object with a handleEvent function.
|
||||
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
|
||||
* false).
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listenWithWrapper = function(
|
||||
src, wrapper, listener, opt_capt) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
// TODO(mknichel): Remove the opt_scope from this function and then
|
||||
// templatize it.
|
||||
return self.listenWithWrapper_(src, wrapper, listener, opt_capt);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener with a specific event wrapper on a DOM Node or an
|
||||
* object that has implemented {@link goog.events.EventTarget}. A listener can
|
||||
* only be added once to an object.
|
||||
*
|
||||
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
|
||||
* events on.
|
||||
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
|
||||
* @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null}
|
||||
* listener Optional callback function to be used as the
|
||||
* listener or an object with handleEvent function.
|
||||
* @param {boolean|undefined} capture Optional whether to use capture phase.
|
||||
* @param {T} scope Object in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template T, THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listenWithWrapperAndScope = function(
|
||||
src, wrapper, listener, capture, scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
// TODO(mknichel): Deprecate this function.
|
||||
return self.listenWithWrapper_(src, wrapper, listener, capture, scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener with a specific event wrapper on a DOM Node or an
|
||||
* object that has implemented {@link goog.events.EventTarget}. A listener can
|
||||
* only be added once to an object.
|
||||
*
|
||||
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
|
||||
* events on.
|
||||
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
|
||||
* method, or an object with a handleEvent function.
|
||||
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
|
||||
* false).
|
||||
* @param {Object=} opt_scope Element in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template THIS
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventHandler.prototype.listenWithWrapper_ = function(
|
||||
src, wrapper, listener, opt_capt, opt_scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
wrapper.listen(
|
||||
src, listener, opt_capt, opt_scope || self.handler_ || self, self);
|
||||
return self;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Number of listeners registered by this handler.
|
||||
*/
|
||||
goog.events.EventHandler.prototype.getListenerCount = function() {
|
||||
'use strict';
|
||||
var count = 0;
|
||||
for (var key in this.keys_) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.keys_, key)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Unlistens on an event.
|
||||
* @param {goog.events.ListenableType} src Event source.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type or array of event types to unlisten to.
|
||||
* @param {function(this:?, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
|
||||
* opt_fn Optional callback function to be used as the listener or an object
|
||||
* with handleEvent function.
|
||||
* @param {(boolean|!EventListenerOptions)=} opt_options
|
||||
* @param {Object=} opt_scope Object in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template EVENTOBJ, THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.unlisten = function(
|
||||
src, type, opt_fn, opt_options, opt_scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
if (Array.isArray(type)) {
|
||||
for (var i = 0; i < type.length; i++) {
|
||||
self.unlisten(src, type[i], opt_fn, opt_options, opt_scope);
|
||||
}
|
||||
} else {
|
||||
var capture =
|
||||
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
|
||||
var listener = goog.events.getListener(
|
||||
src, type, opt_fn || self.handleEvent, capture,
|
||||
opt_scope || self.handler_ || self);
|
||||
|
||||
if (listener) {
|
||||
goog.events.unlistenByKey(listener);
|
||||
delete self.keys_[listener.key];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listenWithWrapper().
|
||||
*
|
||||
* @param {EventTarget|goog.events.EventTarget} src The target to stop
|
||||
* listening to events on.
|
||||
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} listener The
|
||||
* listener function to remove.
|
||||
* @param {boolean=} opt_capt In DOM-compliant browsers, this determines
|
||||
* whether the listener is fired during the capture or bubble phase of the
|
||||
* event.
|
||||
* @param {Object=} opt_scope Element in whose scope to call the listener.
|
||||
* @return {THIS} This object, allowing for chaining of calls.
|
||||
* @this {THIS}
|
||||
* @template THIS
|
||||
*/
|
||||
goog.events.EventHandler.prototype.unlistenWithWrapper = function(
|
||||
src, wrapper, listener, opt_capt, opt_scope) {
|
||||
'use strict';
|
||||
var self = /** @type {!goog.events.EventHandler} */ (this);
|
||||
wrapper.unlisten(
|
||||
src, listener, opt_capt, opt_scope || self.handler_ || self, self);
|
||||
return self;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Unlistens to all events.
|
||||
*/
|
||||
goog.events.EventHandler.prototype.removeAll = function() {
|
||||
'use strict';
|
||||
goog.object.forEach(this.keys_, function(listenerObj, key) {
|
||||
'use strict';
|
||||
if (this.keys_.hasOwnProperty(key)) {
|
||||
goog.events.unlistenByKey(listenerObj);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.keys_ = {};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Disposes of this EventHandler and removes all listeners that it registered.
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
goog.events.EventHandler.prototype.disposeInternal = function() {
|
||||
'use strict';
|
||||
goog.events.EventHandler.superClass_.disposeInternal.call(this);
|
||||
this.removeAll();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Default event handler
|
||||
* @param {goog.events.Event} e Event object.
|
||||
*/
|
||||
goog.events.EventHandler.prototype.handleEvent = function(e) {
|
||||
'use strict';
|
||||
throw new Error('EventHandler.handleEvent not implemented');
|
||||
};
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.EventId');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A templated class that is used when registering for events. Typical usage:
|
||||
*
|
||||
* /** @type {goog.events.EventId<MyEventObj>} *\
|
||||
* var myEventId = new goog.events.EventId(
|
||||
* goog.events.getUniqueId(('someEvent'));
|
||||
*
|
||||
* // No need to cast or declare here since the compiler knows the
|
||||
* // correct type of 'evt' (MyEventObj).
|
||||
* something.listen(myEventId, function(evt) {});
|
||||
*
|
||||
* @param {string} eventId
|
||||
* @template T
|
||||
* @constructor
|
||||
* @struct
|
||||
* @final
|
||||
*/
|
||||
goog.events.EventId = function(eventId) {
|
||||
'use strict';
|
||||
/** @const */ this.id = eventId;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {string}
|
||||
*/
|
||||
goog.events.EventId.prototype.toString = function() {
|
||||
'use strict';
|
||||
return this.id;
|
||||
};
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview A typedef for event like objects that are dispatchable via the
|
||||
* goog.events.dispatchEvent function.
|
||||
*/
|
||||
goog.provide('goog.events.EventLike');
|
||||
|
||||
goog.requireType('goog.events.Event');
|
||||
goog.requireType('goog.events.EventId');
|
||||
|
||||
/**
|
||||
* A typedef for event like objects that are dispatchable via the
|
||||
* goog.events.dispatchEvent function. strings are treated as the type for a
|
||||
* goog.events.Event. Objects are treated as an extension of a new
|
||||
* goog.events.Event with the type property of the object being used as the type
|
||||
* of the Event.
|
||||
* @typedef {string|Object|goog.events.Event|goog.events.EventId}
|
||||
*/
|
||||
goog.events.EventLike;
|
||||
Executable
+960
@@ -0,0 +1,960 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview An event manager for both native browser event
|
||||
* targets and custom JavaScript event targets
|
||||
* (`goog.events.Listenable`). This provides an abstraction
|
||||
* over browsers' event systems.
|
||||
*
|
||||
* It also provides a simulation of W3C event model's capture phase in
|
||||
* Internet Explorer (IE 8 and below). Caveat: the simulation does not
|
||||
* interact well with listeners registered directly on the elements
|
||||
* (bypassing goog.events) or even with listeners registered via
|
||||
* goog.events in a separate JS binary. In these cases, we provide
|
||||
* no ordering guarantees.
|
||||
*
|
||||
* The listeners will receive a "patched" event object. Such event object
|
||||
* contains normalized values for certain event properties that differs in
|
||||
* different browsers.
|
||||
*
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* goog.events.listen(myNode, 'click', function(e) { alert('woo') });
|
||||
* goog.events.listen(myNode, 'mouseover', mouseHandler, true);
|
||||
* goog.events.unlisten(myNode, 'mouseover', mouseHandler, true);
|
||||
* goog.events.removeAll(myNode);
|
||||
* </pre>
|
||||
*
|
||||
* in IE and event object patching]
|
||||
*
|
||||
* @see ../demos/events.html
|
||||
* @see ../demos/event-propagation.html
|
||||
* @see ../demos/stopevent.html
|
||||
*/
|
||||
|
||||
// IMPLEMENTATION NOTES:
|
||||
// goog.events stores an auxiliary data structure on each EventTarget
|
||||
// source being listened on. This allows us to take advantage of GC,
|
||||
// having the data structure GC'd when the EventTarget is GC'd. This
|
||||
// GC behavior is equivalent to using W3C DOM Events directly.
|
||||
|
||||
goog.provide('goog.events');
|
||||
goog.provide('goog.events.CaptureSimulationMode');
|
||||
goog.provide('goog.events.Key');
|
||||
goog.provide('goog.events.ListenableType');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.debug.entryPointRegistry');
|
||||
goog.require('goog.events.BrowserEvent');
|
||||
goog.require('goog.events.BrowserFeature');
|
||||
goog.require('goog.events.Listenable');
|
||||
goog.require('goog.events.ListenerMap');
|
||||
goog.requireType('goog.debug.ErrorHandler');
|
||||
goog.requireType('goog.events.EventId');
|
||||
goog.requireType('goog.events.EventLike');
|
||||
goog.requireType('goog.events.EventWrapper');
|
||||
goog.requireType('goog.events.ListenableKey');
|
||||
goog.requireType('goog.events.Listener');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {number|goog.events.ListenableKey}
|
||||
*/
|
||||
goog.events.Key;
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {EventTarget|goog.events.Listenable}
|
||||
*/
|
||||
goog.events.ListenableType;
|
||||
|
||||
|
||||
/**
|
||||
* Property name on a native event target for the listener map
|
||||
* associated with the event target.
|
||||
* @private @const {string}
|
||||
*/
|
||||
goog.events.LISTENER_MAP_PROP_ = 'closure_lm_' + ((Math.random() * 1e6) | 0);
|
||||
|
||||
|
||||
/**
|
||||
* String used to prepend to IE event types.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.events.onString_ = 'on';
|
||||
|
||||
|
||||
/**
|
||||
* Map of computed "on<eventname>" strings for IE event types. Caching
|
||||
* this removes an extra object allocation in goog.events.listen which
|
||||
* improves IE6 performance.
|
||||
* @const
|
||||
* @dict
|
||||
* @private
|
||||
*/
|
||||
goog.events.onStringMap_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number} Different capture simulation mode for IE8-.
|
||||
*/
|
||||
goog.events.CaptureSimulationMode = {
|
||||
/**
|
||||
* Does not perform capture simulation. Will asserts in IE8- when you
|
||||
* add capture listeners.
|
||||
*/
|
||||
OFF_AND_FAIL: 0,
|
||||
|
||||
/**
|
||||
* Does not perform capture simulation, silently ignore capture
|
||||
* listeners.
|
||||
*/
|
||||
OFF_AND_SILENT: 1,
|
||||
|
||||
/**
|
||||
* Performs capture simulation.
|
||||
*/
|
||||
ON: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} The capture simulation mode for IE8-. By default,
|
||||
* this is ON.
|
||||
*/
|
||||
goog.events.CAPTURE_SIMULATION_MODE =
|
||||
goog.define('goog.events.CAPTURE_SIMULATION_MODE', 2);
|
||||
|
||||
|
||||
/**
|
||||
* Estimated count of total native listeners.
|
||||
* @private {number}
|
||||
*/
|
||||
goog.events.listenerCountEstimate_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener for a specific event on a native event
|
||||
* target (such as a DOM element) or an object that has implemented
|
||||
* {@link goog.events.Listenable}. A listener can only be added once
|
||||
* to an object and if it is added again the key for the listener is
|
||||
* returned. Note that if the existing listener is a one-off listener
|
||||
* (registered via listenOnce), it will no longer be a one-off
|
||||
* listener after a call to listen().
|
||||
*
|
||||
* @param {EventTarget|goog.events.Listenable} src The node to listen
|
||||
* to events on.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type or array of event types.
|
||||
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null}
|
||||
* listener Callback method, or an object with a handleEvent function.
|
||||
* WARNING: passing an Object is now softly deprecated.
|
||||
* @param {(boolean|!AddEventListenerOptions)=} opt_options
|
||||
* @param {T=} opt_handler Element in whose scope to call the listener.
|
||||
* @return {goog.events.Key} Unique key for the listener.
|
||||
* @template T,EVENTOBJ
|
||||
*/
|
||||
goog.events.listen = function(src, type, listener, opt_options, opt_handler) {
|
||||
'use strict';
|
||||
if (opt_options && opt_options.once) {
|
||||
return goog.events.listenOnce(
|
||||
src, type, listener, opt_options, opt_handler);
|
||||
}
|
||||
if (Array.isArray(type)) {
|
||||
for (var i = 0; i < type.length; i++) {
|
||||
goog.events.listen(src, type[i], listener, opt_options, opt_handler);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
listener = goog.events.wrapListener(listener);
|
||||
if (goog.events.Listenable.isImplementedBy(src)) {
|
||||
var capture =
|
||||
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
|
||||
return src.listen(
|
||||
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
|
||||
opt_handler);
|
||||
} else {
|
||||
return goog.events.listen_(
|
||||
/** @type {!EventTarget} */ (src), type, listener,
|
||||
/* callOnce */ false, opt_options, opt_handler);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener for a specific event on a native event
|
||||
* target. A listener can only be added once to an object and if it
|
||||
* is added again the key for the listener is returned.
|
||||
*
|
||||
* Note that a one-off listener will not change an existing listener,
|
||||
* if any. On the other hand a normal listener will change existing
|
||||
* one-off listener to become a normal listener.
|
||||
*
|
||||
* @param {EventTarget} src The node to listen to events on.
|
||||
* @param {string|?goog.events.EventId<EVENTOBJ>} type Event type.
|
||||
* @param {!Function} listener Callback function.
|
||||
* @param {boolean} callOnce Whether the listener is a one-off
|
||||
* listener or otherwise.
|
||||
* @param {(boolean|!AddEventListenerOptions)=} opt_options
|
||||
* @param {Object=} opt_handler Element in whose scope to call the listener.
|
||||
* @return {goog.events.ListenableKey} Unique key for the listener.
|
||||
* @template EVENTOBJ
|
||||
* @private
|
||||
*/
|
||||
goog.events.listen_ = function(
|
||||
src, type, listener, callOnce, opt_options, opt_handler) {
|
||||
'use strict';
|
||||
if (!type) {
|
||||
throw new Error('Invalid event type');
|
||||
}
|
||||
|
||||
var capture =
|
||||
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(src);
|
||||
if (!listenerMap) {
|
||||
src[goog.events.LISTENER_MAP_PROP_] = listenerMap =
|
||||
new goog.events.ListenerMap(src);
|
||||
}
|
||||
|
||||
var listenerObj = /** @type {goog.events.Listener} */ (
|
||||
listenerMap.add(type, listener, callOnce, capture, opt_handler));
|
||||
|
||||
// If the listenerObj already has a proxy, it has been set up
|
||||
// previously. We simply return.
|
||||
if (listenerObj.proxy) {
|
||||
return listenerObj;
|
||||
}
|
||||
|
||||
var proxy = goog.events.getProxy();
|
||||
listenerObj.proxy = proxy;
|
||||
|
||||
proxy.src = src;
|
||||
proxy.listener = listenerObj;
|
||||
|
||||
// Attach the proxy through the browser's API
|
||||
if (src.addEventListener) {
|
||||
// Don't pass an object as `capture` if the browser doesn't support that.
|
||||
if (!goog.events.BrowserFeature.PASSIVE_EVENTS) {
|
||||
opt_options = capture;
|
||||
}
|
||||
// Don't break tests that expect a boolean.
|
||||
if (opt_options === undefined) opt_options = false;
|
||||
src.addEventListener(type.toString(), proxy, opt_options);
|
||||
} else if (src.attachEvent) {
|
||||
// The else if above used to be an unconditional else. It would call
|
||||
// attachEvent come gws or high water. This would sometimes throw an
|
||||
// exception on IE11, spoiling the day of some callers. The previous
|
||||
// incarnation of this code, from 2007, indicates that it replaced an
|
||||
// earlier still version that caused excess allocations on IE6.
|
||||
src.attachEvent(goog.events.getOnString_(type.toString()), proxy);
|
||||
} else if (src.addListener && src.removeListener) {
|
||||
// In IE, MediaQueryList uses addListener() insteadd of addEventListener. In
|
||||
// Safari, there is no global for the MediaQueryList constructor, so we just
|
||||
// check whether the object "looks like" MediaQueryList.
|
||||
goog.asserts.assert(
|
||||
type === 'change', 'MediaQueryList only has a change event');
|
||||
src.addListener(proxy);
|
||||
} else {
|
||||
throw new Error('addEventListener and attachEvent are unavailable.');
|
||||
}
|
||||
|
||||
goog.events.listenerCountEstimate_++;
|
||||
return listenerObj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for returning a proxy function.
|
||||
* @return {!Function} A new or reused function object.
|
||||
*/
|
||||
goog.events.getProxy = function() {
|
||||
'use strict';
|
||||
const proxyCallbackFunction = goog.events.handleBrowserEvent_;
|
||||
const f = function(eventObject) {
|
||||
return proxyCallbackFunction.call(f.src, f.listener, eventObject);
|
||||
};
|
||||
return f;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener for a specific event on a native event
|
||||
* target (such as a DOM element) or an object that has implemented
|
||||
* {@link goog.events.Listenable}. After the event has fired the event
|
||||
* listener is removed from the target.
|
||||
*
|
||||
* If an existing listener already exists, listenOnce will do
|
||||
* nothing. In particular, if the listener was previously registered
|
||||
* via listen(), listenOnce() will not turn the listener into a
|
||||
* one-off listener. Similarly, if there is already an existing
|
||||
* one-off listener, listenOnce does not modify the listeners (it is
|
||||
* still a once listener).
|
||||
*
|
||||
* @param {EventTarget|goog.events.Listenable} src The node to listen
|
||||
* to events on.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type or array of event types.
|
||||
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null}
|
||||
* listener Callback method.
|
||||
* @param {(boolean|!AddEventListenerOptions)=} opt_options
|
||||
* @param {T=} opt_handler Element in whose scope to call the listener.
|
||||
* @return {goog.events.Key} Unique key for the listener.
|
||||
* @template T,EVENTOBJ
|
||||
*/
|
||||
goog.events.listenOnce = function(
|
||||
src, type, listener, opt_options, opt_handler) {
|
||||
'use strict';
|
||||
if (Array.isArray(type)) {
|
||||
for (var i = 0; i < type.length; i++) {
|
||||
goog.events.listenOnce(src, type[i], listener, opt_options, opt_handler);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
listener = goog.events.wrapListener(listener);
|
||||
if (goog.events.Listenable.isImplementedBy(src)) {
|
||||
var capture =
|
||||
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
|
||||
return src.listenOnce(
|
||||
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
|
||||
opt_handler);
|
||||
} else {
|
||||
return goog.events.listen_(
|
||||
/** @type {!EventTarget} */ (src), type, listener,
|
||||
/* callOnce */ true, opt_options, opt_handler);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener with a specific event wrapper on a DOM Node or an
|
||||
* object that has implemented {@link goog.events.Listenable}. A listener can
|
||||
* only be added once to an object.
|
||||
*
|
||||
* @param {EventTarget|goog.events.Listenable} src The target to
|
||||
* listen to events on.
|
||||
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
|
||||
* @param {function(this:T, ?):?|{handleEvent:function(?):?}|null} listener
|
||||
* Callback method, or an object with a handleEvent function.
|
||||
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
|
||||
* false).
|
||||
* @param {T=} opt_handler Element in whose scope to call the listener.
|
||||
* @template T
|
||||
*/
|
||||
goog.events.listenWithWrapper = function(
|
||||
src, wrapper, listener, opt_capt, opt_handler) {
|
||||
'use strict';
|
||||
wrapper.listen(src, listener, opt_capt, opt_handler);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listen().
|
||||
*
|
||||
* @param {EventTarget|goog.events.Listenable} src The target to stop
|
||||
* listening to events on.
|
||||
* @param {string|Array<string>|
|
||||
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
|
||||
* type Event type or array of event types to unlisten to.
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} listener The
|
||||
* listener function to remove.
|
||||
* @param {(boolean|!EventListenerOptions)=} opt_options
|
||||
* whether the listener is fired during the capture or bubble phase of the
|
||||
* event.
|
||||
* @param {Object=} opt_handler Element in whose scope to call the listener.
|
||||
* @return {?boolean} indicating whether the listener was there to remove.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.unlisten = function(src, type, listener, opt_options, opt_handler) {
|
||||
'use strict';
|
||||
if (Array.isArray(type)) {
|
||||
for (var i = 0; i < type.length; i++) {
|
||||
goog.events.unlisten(src, type[i], listener, opt_options, opt_handler);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var capture =
|
||||
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
|
||||
|
||||
listener = goog.events.wrapListener(listener);
|
||||
if (goog.events.Listenable.isImplementedBy(src)) {
|
||||
return src.unlisten(
|
||||
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
|
||||
opt_handler);
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
// TODO(chrishenry): We should tighten the API to only accept
|
||||
// non-null objects, or add an assertion here.
|
||||
return false;
|
||||
}
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(
|
||||
/** @type {!EventTarget} */ (src));
|
||||
if (listenerMap) {
|
||||
var listenerObj = listenerMap.getListener(
|
||||
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
|
||||
opt_handler);
|
||||
if (listenerObj) {
|
||||
return goog.events.unlistenByKey(listenerObj);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listen() by the key
|
||||
* returned by listen().
|
||||
*
|
||||
* @param {goog.events.Key} key The key returned by listen() for this
|
||||
* event listener.
|
||||
* @return {boolean} indicating whether the listener was there to remove.
|
||||
*/
|
||||
goog.events.unlistenByKey = function(key) {
|
||||
'use strict';
|
||||
// TODO(chrishenry): Remove this check when tests that rely on this
|
||||
// are fixed.
|
||||
if (typeof key === 'number') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var listener = key;
|
||||
if (!listener || listener.removed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var src = listener.src;
|
||||
if (goog.events.Listenable.isImplementedBy(src)) {
|
||||
return /** @type {!goog.events.Listenable} */ (src).unlistenByKey(listener);
|
||||
}
|
||||
|
||||
var type = listener.type;
|
||||
var proxy = listener.proxy;
|
||||
if (src.removeEventListener) {
|
||||
src.removeEventListener(type, proxy, listener.capture);
|
||||
} else if (src.detachEvent) {
|
||||
src.detachEvent(goog.events.getOnString_(type), proxy);
|
||||
} else if (src.addListener && src.removeListener) {
|
||||
src.removeListener(proxy);
|
||||
}
|
||||
goog.events.listenerCountEstimate_--;
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(
|
||||
/** @type {!EventTarget} */ (src));
|
||||
// TODO(chrishenry): Try to remove this conditional and execute the
|
||||
// first branch always. This should be safe.
|
||||
if (listenerMap) {
|
||||
listenerMap.removeByKey(listener);
|
||||
if (listenerMap.getTypeCount() == 0) {
|
||||
// Null the src, just because this is simple to do (and useful
|
||||
// for IE <= 7).
|
||||
listenerMap.src = null;
|
||||
// We don't use delete here because IE does not allow delete
|
||||
// on a window object.
|
||||
src[goog.events.LISTENER_MAP_PROP_] = null;
|
||||
}
|
||||
} else {
|
||||
/** @type {!goog.events.Listener} */ (listener).markAsRemoved();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listenWithWrapper().
|
||||
*
|
||||
* @param {EventTarget|goog.events.Listenable} src The target to stop
|
||||
* listening to events on.
|
||||
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} listener The
|
||||
* listener function to remove.
|
||||
* @param {boolean=} opt_capt In DOM-compliant browsers, this determines
|
||||
* whether the listener is fired during the capture or bubble phase of the
|
||||
* event.
|
||||
* @param {Object=} opt_handler Element in whose scope to call the listener.
|
||||
*/
|
||||
goog.events.unlistenWithWrapper = function(
|
||||
src, wrapper, listener, opt_capt, opt_handler) {
|
||||
'use strict';
|
||||
wrapper.unlisten(src, listener, opt_capt, opt_handler);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all listeners from an object. You can also optionally
|
||||
* remove listeners of a particular type.
|
||||
*
|
||||
* @param {Object|undefined} obj Object to remove listeners from. Must be an
|
||||
* EventTarget or a goog.events.Listenable.
|
||||
* @param {string|!goog.events.EventId=} opt_type Type of event to remove.
|
||||
* Default is all types.
|
||||
* @return {number} Number of listeners removed.
|
||||
*/
|
||||
goog.events.removeAll = function(obj, opt_type) {
|
||||
'use strict';
|
||||
// TODO(chrishenry): Change the type of obj to
|
||||
// (!EventTarget|!goog.events.Listenable).
|
||||
|
||||
if (!obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (goog.events.Listenable.isImplementedBy(obj)) {
|
||||
return /** @type {?} */ (obj).removeAllListeners(opt_type);
|
||||
}
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(
|
||||
/** @type {!EventTarget} */ (obj));
|
||||
if (!listenerMap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
var typeStr = opt_type && opt_type.toString();
|
||||
for (var type in listenerMap.listeners) {
|
||||
if (!typeStr || type == typeStr) {
|
||||
// Clone so that we don't need to worry about unlistenByKey
|
||||
// changing the content of the ListenerMap.
|
||||
var listeners = listenerMap.listeners[type].concat();
|
||||
for (var i = 0; i < listeners.length; ++i) {
|
||||
if (goog.events.unlistenByKey(listeners[i])) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the listeners for a given object, type and capture phase.
|
||||
*
|
||||
* @param {Object} obj Object to get listeners for.
|
||||
* @param {string|!goog.events.EventId} type Event type.
|
||||
* @param {boolean} capture Capture phase?.
|
||||
* @return {!Array<!goog.events.Listener>} Array of listener objects.
|
||||
*/
|
||||
goog.events.getListeners = function(obj, type, capture) {
|
||||
'use strict';
|
||||
if (goog.events.Listenable.isImplementedBy(obj)) {
|
||||
return /** @type {!goog.events.Listenable} */ (obj).getListeners(
|
||||
type, capture);
|
||||
} else {
|
||||
if (!obj) {
|
||||
// TODO(chrishenry): We should tighten the API to accept
|
||||
// !EventTarget|goog.events.Listenable, and add an assertion here.
|
||||
return [];
|
||||
}
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(
|
||||
/** @type {!EventTarget} */ (obj));
|
||||
return listenerMap ? listenerMap.getListeners(type, capture) : [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the goog.events.Listener for the event or null if no such listener is
|
||||
* in use.
|
||||
*
|
||||
* @param {EventTarget|goog.events.Listenable} src The target from
|
||||
* which to get listeners.
|
||||
* @param {?string|!goog.events.EventId<EVENTOBJ>} type The type of the event.
|
||||
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null} listener The
|
||||
* listener function to get.
|
||||
* @param {boolean=} opt_capt In DOM-compliant browsers, this determines
|
||||
* whether the listener is fired during the
|
||||
* capture or bubble phase of the event.
|
||||
* @param {Object=} opt_handler Element in whose scope to call the listener.
|
||||
* @return {goog.events.ListenableKey} the found listener or null if not found.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) {
|
||||
'use strict';
|
||||
// TODO(chrishenry): Change type from ?string to string, or add assertion.
|
||||
type = /** @type {string} */ (type);
|
||||
listener = goog.events.wrapListener(listener);
|
||||
var capture = !!opt_capt;
|
||||
if (goog.events.Listenable.isImplementedBy(src)) {
|
||||
return src.getListener(type, listener, capture, opt_handler);
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
// TODO(chrishenry): We should tighten the API to only accept
|
||||
// non-null objects, or add an assertion here.
|
||||
return null;
|
||||
}
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(
|
||||
/** @type {!EventTarget} */ (src));
|
||||
if (listenerMap) {
|
||||
return listenerMap.getListener(type, listener, capture, opt_handler);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether an event target has any active listeners matching the
|
||||
* specified signature. If either the type or capture parameters are
|
||||
* unspecified, the function will match on the remaining criteria.
|
||||
*
|
||||
* @param {EventTarget|goog.events.Listenable} obj Target to get
|
||||
* listeners for.
|
||||
* @param {string|!goog.events.EventId=} opt_type Event type.
|
||||
* @param {boolean=} opt_capture Whether to check for capture or bubble-phase
|
||||
* listeners.
|
||||
* @return {boolean} Whether an event target has one or more listeners matching
|
||||
* the requested type and/or capture phase.
|
||||
*/
|
||||
goog.events.hasListener = function(obj, opt_type, opt_capture) {
|
||||
'use strict';
|
||||
if (goog.events.Listenable.isImplementedBy(obj)) {
|
||||
return obj.hasListener(opt_type, opt_capture);
|
||||
}
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(
|
||||
/** @type {!EventTarget} */ (obj));
|
||||
return !!listenerMap && listenerMap.hasListener(opt_type, opt_capture);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Provides a nice string showing the normalized event objects public members
|
||||
* @param {Object} e Event Object.
|
||||
* @return {string} String of the public members of the normalized event object.
|
||||
*/
|
||||
goog.events.expose = function(e) {
|
||||
'use strict';
|
||||
var str = [];
|
||||
for (var key in e) {
|
||||
if (e[key] && e[key].id) {
|
||||
str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')');
|
||||
} else {
|
||||
str.push(key + ' = ' + e[key]);
|
||||
}
|
||||
}
|
||||
return str.join('\n');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string with on prepended to the specified type. This is used for IE
|
||||
* which expects "on" to be prepended. This function caches the string in order
|
||||
* to avoid extra allocations in steady state.
|
||||
* @param {string} type Event type.
|
||||
* @return {string} The type string with 'on' prepended.
|
||||
* @private
|
||||
*/
|
||||
goog.events.getOnString_ = function(type) {
|
||||
'use strict';
|
||||
if (type in goog.events.onStringMap_) {
|
||||
return goog.events.onStringMap_[type];
|
||||
}
|
||||
return goog.events.onStringMap_[type] = goog.events.onString_ + type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fires an object's listeners of a particular type and phase
|
||||
*
|
||||
* @param {Object} obj Object whose listeners to call.
|
||||
* @param {string|!goog.events.EventId} type Event type.
|
||||
* @param {boolean} capture Which event phase.
|
||||
* @param {Object} eventObject Event object to be passed to listener.
|
||||
* @return {boolean} True if all listeners returned true else false.
|
||||
*/
|
||||
goog.events.fireListeners = function(obj, type, capture, eventObject) {
|
||||
'use strict';
|
||||
if (goog.events.Listenable.isImplementedBy(obj)) {
|
||||
return /** @type {!goog.events.Listenable} */ (obj).fireListeners(
|
||||
type, capture, eventObject);
|
||||
}
|
||||
|
||||
return goog.events.fireListeners_(obj, type, capture, eventObject);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fires an object's listeners of a particular type and phase.
|
||||
* @param {Object} obj Object whose listeners to call.
|
||||
* @param {string|!goog.events.EventId} type Event type.
|
||||
* @param {boolean} capture Which event phase.
|
||||
* @param {Object} eventObject Event object to be passed to listener.
|
||||
* @return {boolean} True if all listeners returned true else false.
|
||||
* @private
|
||||
*/
|
||||
goog.events.fireListeners_ = function(obj, type, capture, eventObject) {
|
||||
'use strict';
|
||||
/** @type {boolean} */
|
||||
var retval = true;
|
||||
|
||||
var listenerMap = goog.events.getListenerMap_(
|
||||
/** @type {EventTarget} */ (obj));
|
||||
if (listenerMap) {
|
||||
// TODO(chrishenry): Original code avoids array creation when there
|
||||
// is no listener, so we do the same. If this optimization turns
|
||||
// out to be not required, we can replace this with
|
||||
// listenerMap.getListeners(type, capture) instead, which is simpler.
|
||||
var listenerArray = listenerMap.listeners[type.toString()];
|
||||
if (listenerArray) {
|
||||
listenerArray = listenerArray.concat();
|
||||
for (var i = 0; i < listenerArray.length; i++) {
|
||||
var listener = listenerArray[i];
|
||||
// We might not have a listener if the listener was removed.
|
||||
if (listener && listener.capture == capture && !listener.removed) {
|
||||
var result = goog.events.fireListener(listener, eventObject);
|
||||
retval = retval && (result !== false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fires a listener with a set of arguments
|
||||
*
|
||||
* @param {goog.events.Listener} listener The listener object to call.
|
||||
* @param {Object} eventObject The event object to pass to the listener.
|
||||
* @return {*} Result of listener.
|
||||
*/
|
||||
goog.events.fireListener = function(listener, eventObject) {
|
||||
'use strict';
|
||||
var listenerFn = listener.listener;
|
||||
var listenerHandler = listener.handler || listener.src;
|
||||
|
||||
if (listener.callOnce) {
|
||||
goog.events.unlistenByKey(listener);
|
||||
}
|
||||
return listenerFn.call(listenerHandler, eventObject);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the total number of listeners currently in the system.
|
||||
* @return {number} Number of listeners.
|
||||
* @deprecated This returns estimated count, now that Closure no longer
|
||||
* stores a central listener registry. We still return an estimation
|
||||
* to keep existing listener-related tests passing. In the near future,
|
||||
* this function will be removed.
|
||||
*/
|
||||
goog.events.getTotalListenerCount = function() {
|
||||
'use strict';
|
||||
return goog.events.listenerCountEstimate_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches an event (or event like object) and calls all listeners
|
||||
* listening for events of this type. The type of the event is decided by the
|
||||
* type property on the event object.
|
||||
*
|
||||
* If any of the listeners returns false OR calls preventDefault then this
|
||||
* function will return false. If one of the capture listeners calls
|
||||
* stopPropagation, then the bubble listeners won't fire.
|
||||
*
|
||||
* @param {goog.events.Listenable} src The event target.
|
||||
* @param {goog.events.EventLike} e Event object.
|
||||
* @return {boolean} If anyone called preventDefault on the event object (or
|
||||
* if any of the handlers returns false) this will also return false.
|
||||
* If there are no handlers, or if all handlers return true, this returns
|
||||
* true.
|
||||
*/
|
||||
goog.events.dispatchEvent = function(src, e) {
|
||||
'use strict';
|
||||
goog.asserts.assert(
|
||||
goog.events.Listenable.isImplementedBy(src),
|
||||
'Can not use goog.events.dispatchEvent with ' +
|
||||
'non-goog.events.Listenable instance.');
|
||||
return src.dispatchEvent(e);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Installs exception protection for the browser event entry point using the
|
||||
* given error handler.
|
||||
*
|
||||
* @param {goog.debug.ErrorHandler} errorHandler Error handler with which to
|
||||
* protect the entry point.
|
||||
*/
|
||||
goog.events.protectBrowserEventEntryPoint = function(errorHandler) {
|
||||
'use strict';
|
||||
goog.events.handleBrowserEvent_ =
|
||||
errorHandler.protectEntryPoint(goog.events.handleBrowserEvent_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles an event and dispatches it to the correct listeners. This
|
||||
* function is a proxy for the real listener the user specified.
|
||||
*
|
||||
* @param {goog.events.Listener} listener The listener object.
|
||||
* @param {Event=} opt_evt Optional event object that gets passed in via the
|
||||
* native event handlers.
|
||||
* @return {*} Result of the event handler.
|
||||
* @this {EventTarget} The object or Element that fired the event.
|
||||
* @private
|
||||
*/
|
||||
goog.events.handleBrowserEvent_ = function(listener, opt_evt) {
|
||||
'use strict';
|
||||
if (listener.removed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, simply fire the listener.
|
||||
return goog.events.fireListener(
|
||||
listener, new goog.events.BrowserEvent(opt_evt, this));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is used to mark the IE event object so we do not do the Closure pass
|
||||
* twice for a bubbling event.
|
||||
* @param {Event} e The IE browser event.
|
||||
* @private
|
||||
*/
|
||||
goog.events.markIeEvent_ = function(e) {
|
||||
'use strict';
|
||||
// Only the keyCode and the returnValue can be changed. We use keyCode for
|
||||
// non keyboard events.
|
||||
// event.returnValue is a bit more tricky. It is undefined by default. A
|
||||
// boolean false prevents the default action. In a window.onbeforeunload and
|
||||
// the returnValue is non undefined it will be alerted. However, we will only
|
||||
// modify the returnValue for keyboard events. We can get a problem if non
|
||||
// closure events sets the keyCode or the returnValue
|
||||
|
||||
var useReturnValue = false;
|
||||
|
||||
if (e.keyCode == 0) {
|
||||
// We cannot change the keyCode in case that srcElement is input[type=file].
|
||||
// We could test that that is the case but that would allocate 3 objects.
|
||||
// If we use try/catch we will only allocate extra objects in the case of a
|
||||
// failure.
|
||||
|
||||
try {
|
||||
e.keyCode = -1;
|
||||
return;
|
||||
} catch (ex) {
|
||||
useReturnValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (useReturnValue ||
|
||||
/** @type {boolean|undefined} */ (e.returnValue) == undefined) {
|
||||
e.returnValue = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is used to check if an IE event has already been handled by the Closure
|
||||
* system so we do not do the Closure pass twice for a bubbling event.
|
||||
* @param {Event} e The IE browser event.
|
||||
* @return {boolean} True if the event object has been marked.
|
||||
* @private
|
||||
*/
|
||||
goog.events.isMarkedIeEvent_ = function(e) {
|
||||
'use strict';
|
||||
return e.keyCode < 0 || e.returnValue != undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Counter to create unique event ids.
|
||||
* @private {number}
|
||||
*/
|
||||
goog.events.uniqueIdCounter_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a unique event id.
|
||||
*
|
||||
* @param {string} identifier The identifier.
|
||||
* @return {string} A unique identifier.
|
||||
* @idGenerator {unique}
|
||||
*/
|
||||
goog.events.getUniqueId = function(identifier) {
|
||||
'use strict';
|
||||
return identifier + '_' + goog.events.uniqueIdCounter_++;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {EventTarget} src The source object.
|
||||
* @return {goog.events.ListenerMap} A listener map for the given
|
||||
* source object, or null if none exists.
|
||||
* @private
|
||||
*/
|
||||
goog.events.getListenerMap_ = function(src) {
|
||||
'use strict';
|
||||
var listenerMap = src[goog.events.LISTENER_MAP_PROP_];
|
||||
// IE serializes the property as well (e.g. when serializing outer
|
||||
// HTML). So we must check that the value is of the correct type.
|
||||
return listenerMap instanceof goog.events.ListenerMap ? listenerMap : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Expando property for listener function wrapper for Object with
|
||||
* handleEvent.
|
||||
* @private @const {string}
|
||||
*/
|
||||
goog.events.LISTENER_WRAPPER_PROP_ =
|
||||
'__closure_events_fn_' + ((Math.random() * 1e9) >>> 0);
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object|Function} listener The listener function or an
|
||||
* object that contains handleEvent method.
|
||||
* @return {!Function} Either the original function or a function that
|
||||
* calls obj.handleEvent. If the same listener is passed to this
|
||||
* function more than once, the same function is guaranteed to be
|
||||
* returned.
|
||||
*/
|
||||
goog.events.wrapListener = function(listener) {
|
||||
'use strict';
|
||||
goog.asserts.assert(listener, 'Listener can not be null.');
|
||||
|
||||
if (typeof listener === 'function') {
|
||||
return listener;
|
||||
}
|
||||
|
||||
goog.asserts.assert(
|
||||
listener.handleEvent, 'An object listener must have handleEvent method.');
|
||||
if (!listener[goog.events.LISTENER_WRAPPER_PROP_]) {
|
||||
listener[goog.events.LISTENER_WRAPPER_PROP_] = function(e) {
|
||||
'use strict';
|
||||
return /** @type {?} */ (listener).handleEvent(e);
|
||||
};
|
||||
}
|
||||
return listener[goog.events.LISTENER_WRAPPER_PROP_];
|
||||
};
|
||||
|
||||
|
||||
// Register the browser event handler as an entry point, so that
|
||||
// it can be monitored for exception handling, etc.
|
||||
goog.debug.entryPointRegistry.register(
|
||||
/**
|
||||
* @param {function(!Function): !Function} transformer The transforming
|
||||
* function.
|
||||
*/
|
||||
function(transformer) {
|
||||
'use strict';
|
||||
goog.events.handleBrowserEvent_ =
|
||||
transformer(goog.events.handleBrowserEvent_);
|
||||
});
|
||||
Executable
+495
@@ -0,0 +1,495 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview A disposable implementation of a custom
|
||||
* listenable/event target. See also: documentation for
|
||||
* `goog.events.Listenable`.
|
||||
*
|
||||
* @see ../demos/eventtarget.html
|
||||
* @see goog.events.Listenable
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.EventTarget');
|
||||
|
||||
goog.require('goog.Disposable');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.Listenable');
|
||||
goog.require('goog.events.ListenerMap');
|
||||
goog.require('goog.object');
|
||||
goog.requireType('goog.events.EventId');
|
||||
goog.requireType('goog.events.EventLike');
|
||||
goog.requireType('goog.events.ListenableKey');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of `goog.events.Listenable` with full W3C
|
||||
* EventTarget-like support (capture/bubble mechanism, stopping event
|
||||
* propagation, preventing default actions).
|
||||
*
|
||||
* You may subclass this class to turn your class into a Listenable.
|
||||
*
|
||||
* Unless propagation is stopped, an event dispatched by an
|
||||
* EventTarget will bubble to the parent returned by
|
||||
* `getParentEventTarget`. To set the parent, call
|
||||
* `setParentEventTarget`. Subclasses that don't support
|
||||
* changing the parent can override the setter to throw an error.
|
||||
*
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* var source = new goog.events.EventTarget();
|
||||
* function handleEvent(e) {
|
||||
* alert('Type: ' + e.type + '; Target: ' + e.target);
|
||||
* }
|
||||
* source.listen('foo', handleEvent);
|
||||
* // Or: goog.events.listen(source, 'foo', handleEvent);
|
||||
* ...
|
||||
* source.dispatchEvent('foo'); // will call handleEvent
|
||||
* ...
|
||||
* source.unlisten('foo', handleEvent);
|
||||
* // Or: goog.events.unlisten(source, 'foo', handleEvent);
|
||||
* </pre>
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
* @implements {goog.events.Listenable}
|
||||
*/
|
||||
goog.events.EventTarget = function() {
|
||||
'use strict';
|
||||
goog.Disposable.call(this);
|
||||
|
||||
/**
|
||||
* Maps of event type to an array of listeners.
|
||||
* @private {!goog.events.ListenerMap}
|
||||
*/
|
||||
this.eventTargetListeners_ = new goog.events.ListenerMap(this);
|
||||
|
||||
/**
|
||||
* The object to use for event.target. Useful when mixing in an
|
||||
* EventTarget to another object.
|
||||
* @private {!Object}
|
||||
*/
|
||||
this.actualEventTarget_ = this;
|
||||
|
||||
/**
|
||||
* Parent event target, used during event bubbling.
|
||||
*
|
||||
* TODO(chrishenry): Change this to goog.events.Listenable. This
|
||||
* currently breaks people who expect getParentEventTarget to return
|
||||
* goog.events.EventTarget.
|
||||
*
|
||||
* @private {?goog.events.EventTarget}
|
||||
*/
|
||||
this.parentEventTarget_ = null;
|
||||
};
|
||||
goog.inherits(goog.events.EventTarget, goog.Disposable);
|
||||
goog.events.Listenable.addImplementation(goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* An artificial cap on the number of ancestors you can have. This is mainly
|
||||
* for loop detection.
|
||||
* @const {number}
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventTarget.MAX_ANCESTORS_ = 1000;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parent of this event target to use for bubbling.
|
||||
*
|
||||
* @return {goog.events.EventTarget} The parent EventTarget or null if
|
||||
* there is no parent.
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.getParentEventTarget = function() {
|
||||
'use strict';
|
||||
return this.parentEventTarget_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parent of this event target to use for capture/bubble
|
||||
* mechanism.
|
||||
* @param {goog.events.EventTarget} parent Parent listenable (null if none).
|
||||
*/
|
||||
goog.events.EventTarget.prototype.setParentEventTarget = function(parent) {
|
||||
'use strict';
|
||||
this.parentEventTarget_ = parent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener to the event target. The same handler can only be
|
||||
* added once per the type. Even if you add the same handler multiple times
|
||||
* using the same type then it will only be called once when the event is
|
||||
* dispatched.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The type of the event to listen for
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
|
||||
* to handle the event. The handler can also be an object that implements
|
||||
* the handleEvent method which takes the event object as argument.
|
||||
* @param {boolean=} opt_capture In DOM-compliant browsers, this determines
|
||||
* whether the listener is fired during the capture or bubble phase
|
||||
* of the event.
|
||||
* @param {Object=} opt_handlerScope Object in whose scope to call
|
||||
* the listener.
|
||||
* @deprecated Use `#listen` instead, when possible. Otherwise, use
|
||||
* `goog.events.listen` if you are passing Object
|
||||
* (instead of Function) as handler.
|
||||
*/
|
||||
goog.events.EventTarget.prototype.addEventListener = function(
|
||||
type, handler, opt_capture, opt_handlerScope) {
|
||||
'use strict';
|
||||
goog.events.listen(this, type, handler, opt_capture, opt_handlerScope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener from the event target. The handler must be the
|
||||
* same object as the one added. If the handler has not been added then
|
||||
* nothing is done.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The type of the event to listen for
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
|
||||
* to handle the event. The handler can also be an object that implements
|
||||
* the handleEvent method which takes the event object as argument.
|
||||
* @param {boolean=} opt_capture In DOM-compliant browsers, this determines
|
||||
* whether the listener is fired during the capture or bubble phase
|
||||
* of the event.
|
||||
* @param {Object=} opt_handlerScope Object in whose scope to call
|
||||
* the listener.
|
||||
* @deprecated Use `#unlisten` instead, when possible. Otherwise, use
|
||||
* `goog.events.unlisten` if you are passing Object
|
||||
* (instead of Function) as handler.
|
||||
*/
|
||||
goog.events.EventTarget.prototype.removeEventListener = function(
|
||||
type, handler, opt_capture, opt_handlerScope) {
|
||||
'use strict';
|
||||
goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?goog.events.EventLike} e Event object.
|
||||
* @return {boolean} If anyone called preventDefault on the event object (or
|
||||
* if any of the listeners returns false) this will also return false.
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.dispatchEvent = function(e) {
|
||||
'use strict';
|
||||
this.assertInitialized_();
|
||||
|
||||
var ancestorsTree, ancestor = this.getParentEventTarget();
|
||||
if (ancestor) {
|
||||
ancestorsTree = [];
|
||||
var ancestorCount = 1;
|
||||
for (; ancestor; ancestor = ancestor.getParentEventTarget()) {
|
||||
ancestorsTree.push(ancestor);
|
||||
goog.asserts.assert(
|
||||
(++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_),
|
||||
'infinite loop');
|
||||
}
|
||||
}
|
||||
|
||||
return goog.events.EventTarget.dispatchEventInternal_(
|
||||
this.actualEventTarget_, e, ancestorsTree);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes listeners from this object. Classes that extend EventTarget may
|
||||
* need to override this method in order to remove references to DOM Elements
|
||||
* and additional listeners.
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
goog.events.EventTarget.prototype.disposeInternal = function() {
|
||||
'use strict';
|
||||
goog.events.EventTarget.superClass_.disposeInternal.call(this);
|
||||
|
||||
this.removeAllListeners();
|
||||
this.parentEventTarget_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.listen = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
'use strict';
|
||||
this.assertInitialized_();
|
||||
return this.eventTargetListeners_.add(
|
||||
String(type), listener, false /* callOnce */, opt_useCapture,
|
||||
opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.listenOnce = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
'use strict';
|
||||
return this.eventTargetListeners_.add(
|
||||
String(type), listener, true /* callOnce */, opt_useCapture,
|
||||
opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call
|
||||
* the listener.
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.unlisten = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
'use strict';
|
||||
return this.eventTargetListeners_.remove(
|
||||
String(type), listener, opt_useCapture, opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!goog.events.ListenableKey} key The key returned by
|
||||
* listen() or listenOnce().
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.unlistenByKey = function(key) {
|
||||
'use strict';
|
||||
return this.eventTargetListeners_.removeByKey(key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId=} opt_type Type of event to remove,
|
||||
* default is to remove all types.
|
||||
* @return {number} Number of listeners removed.
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) {
|
||||
'use strict';
|
||||
// TODO(chrishenry): Previously, removeAllListeners can be called on
|
||||
// uninitialized EventTarget, so we preserve that behavior. We
|
||||
// should remove this when usages that rely on that fact are purged.
|
||||
if (!this.eventTargetListeners_) {
|
||||
return 0;
|
||||
}
|
||||
return this.eventTargetListeners_.removeAll(opt_type);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the
|
||||
* listeners to fire.
|
||||
* @param {boolean} capture The capture mode of the listeners to fire.
|
||||
* @param {EVENTOBJ} eventObject The event object to fire.
|
||||
* @return {boolean} Whether all listeners succeeded without
|
||||
* attempting to prevent default behavior. If any listener returns
|
||||
* false or called goog.events.Event#preventDefault, this returns
|
||||
* false.
|
||||
* @template EVENTOBJ
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.fireListeners = function(
|
||||
type, capture, eventObject) {
|
||||
'use strict';
|
||||
// TODO(chrishenry): Original code avoids array creation when there
|
||||
// is no listener, so we do the same. If this optimization turns
|
||||
// out to be not required, we can replace this with
|
||||
// getListeners(type, capture) instead, which is simpler.
|
||||
var listenerArray = this.eventTargetListeners_.listeners[String(type)];
|
||||
if (!listenerArray) {
|
||||
return true;
|
||||
}
|
||||
listenerArray = listenerArray.concat();
|
||||
|
||||
var rv = true;
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
var listener = listenerArray[i];
|
||||
// We might not have a listener if the listener was removed.
|
||||
if (listener && !listener.removed && listener.capture == capture) {
|
||||
var listenerFn = listener.listener;
|
||||
var listenerHandler = listener.handler || listener.src;
|
||||
|
||||
if (listener.callOnce) {
|
||||
this.unlistenByKey(listener);
|
||||
}
|
||||
rv = listenerFn.call(listenerHandler, eventObject) !== false && rv;
|
||||
}
|
||||
}
|
||||
|
||||
return rv && !eventObject.defaultPrevented;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId} type The type of the listeners to fire.
|
||||
* @param {boolean} capture The capture mode of the listeners to fire.
|
||||
* @return {!Array<!goog.events.ListenableKey>} An array of registered
|
||||
* listeners.
|
||||
* @template EVENTOBJ
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.getListeners = function(type, capture) {
|
||||
'use strict';
|
||||
return this.eventTargetListeners_.getListeners(String(type), capture);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event
|
||||
* without the 'on' prefix.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The
|
||||
* listener function to get.
|
||||
* @param {boolean} capture Whether the listener is a capturing listener.
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {?goog.events.ListenableKey} the found listener or null if not found.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.getListener = function(
|
||||
type, listener, capture, opt_listenerScope) {
|
||||
'use strict';
|
||||
return this.eventTargetListeners_.getListener(
|
||||
String(type), listener, capture, opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type.
|
||||
* @param {boolean=} opt_capture Whether to check for capture or bubble
|
||||
* listeners.
|
||||
* @return {boolean} Whether there is any active listeners matching
|
||||
* the requested type and/or capture phase.
|
||||
* @template EVENTOBJ
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.hasListener = function(
|
||||
opt_type, opt_capture) {
|
||||
'use strict';
|
||||
var id = (opt_type !== undefined) ? String(opt_type) : undefined;
|
||||
return this.eventTargetListeners_.hasListener(id, opt_capture);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the target to be used for `event.target` when firing
|
||||
* event. Mainly used for testing. For example, see
|
||||
* `goog.testing.events.mixinListenable`.
|
||||
* @param {!Object} target The target.
|
||||
*/
|
||||
goog.events.EventTarget.prototype.setTargetForTesting = function(target) {
|
||||
'use strict';
|
||||
this.actualEventTarget_ = target;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asserts that the event target instance is initialized properly.
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventTarget.prototype.assertInitialized_ = function() {
|
||||
'use strict';
|
||||
goog.asserts.assert(
|
||||
this.eventTargetListeners_,
|
||||
'Event target is not initialized. Did you call the superclass ' +
|
||||
'(goog.events.EventTarget) constructor?');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the given event on the ancestorsTree.
|
||||
*
|
||||
* @param {!Object} target The target to dispatch on.
|
||||
* @param {goog.events.Event|Object|string} e The event object.
|
||||
* @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors
|
||||
* tree of the target, in reverse order from the closest ancestor
|
||||
* to the root event target. May be null if the target has no ancestor.
|
||||
* @return {boolean} If anyone called preventDefault on the event object (or
|
||||
* if any of the listeners returns false) this will also return false.
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventTarget.dispatchEventInternal_ = function(
|
||||
target, e, opt_ancestorsTree) {
|
||||
'use strict';
|
||||
/** @suppress {missingProperties} */
|
||||
var type = e.type || /** @type {string} */ (e);
|
||||
|
||||
// If accepting a string or object, create a custom event object so that
|
||||
// preventDefault and stopPropagation work with the event.
|
||||
if (typeof e === 'string') {
|
||||
e = new goog.events.Event(e, target);
|
||||
} else if (!(e instanceof goog.events.Event)) {
|
||||
var oldEvent = e;
|
||||
e = new goog.events.Event(type, target);
|
||||
goog.object.extend(e, oldEvent);
|
||||
} else {
|
||||
e.target = e.target || target;
|
||||
}
|
||||
|
||||
var rv = true, currentTarget;
|
||||
|
||||
// Executes all capture listeners on the ancestors, if any.
|
||||
if (opt_ancestorsTree) {
|
||||
for (var i = opt_ancestorsTree.length - 1;
|
||||
!e.hasPropagationStopped() && i >= 0; i--) {
|
||||
currentTarget = e.currentTarget = opt_ancestorsTree[i];
|
||||
rv = currentTarget.fireListeners(type, true, e) && rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Executes capture and bubble listeners on the target.
|
||||
if (!e.hasPropagationStopped()) {
|
||||
currentTarget = /** @type {?} */ (e.currentTarget = target);
|
||||
rv = currentTarget.fireListeners(type, true, e) && rv;
|
||||
if (!e.hasPropagationStopped()) {
|
||||
rv = currentTarget.fireListeners(type, false, e) && rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Executes all bubble listeners on the ancestors, if any.
|
||||
if (opt_ancestorsTree) {
|
||||
for (i = 0; !e.hasPropagationStopped() && i < opt_ancestorsTree.length;
|
||||
i++) {
|
||||
currentTarget = e.currentTarget = opt_ancestorsTree[i];
|
||||
rv = currentTarget.fireListeners(type, false, e) && rv;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
};
|
||||
Executable
+437
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Event Types.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.events.EventType');
|
||||
goog.provide('goog.events.MouseAsMouseEventType');
|
||||
goog.provide('goog.events.MouseEvents');
|
||||
goog.provide('goog.events.PointerAsMouseEventType');
|
||||
goog.provide('goog.events.PointerAsTouchEventType');
|
||||
goog.provide('goog.events.PointerFallbackEventType');
|
||||
goog.provide('goog.events.PointerTouchFallbackEventType');
|
||||
|
||||
goog.require('goog.events.BrowserFeature');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
* Returns a prefixed event name for the current browser.
|
||||
* @param {string} eventName The name of the event.
|
||||
* @return {string} The prefixed event name.
|
||||
* @private
|
||||
*/
|
||||
goog.events.getVendorPrefixedName_ = function(eventName) {
|
||||
'use strict';
|
||||
return goog.userAgent.WEBKIT ? 'webkit' + eventName : eventName.toLowerCase();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constants for event names.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.events.EventType = {
|
||||
// Mouse events
|
||||
CLICK: 'click',
|
||||
RIGHTCLICK: 'rightclick',
|
||||
DBLCLICK: 'dblclick',
|
||||
AUXCLICK: 'auxclick',
|
||||
MOUSEDOWN: 'mousedown',
|
||||
MOUSEUP: 'mouseup',
|
||||
MOUSEOVER: 'mouseover',
|
||||
MOUSEOUT: 'mouseout',
|
||||
MOUSEMOVE: 'mousemove',
|
||||
MOUSEENTER: 'mouseenter',
|
||||
MOUSELEAVE: 'mouseleave',
|
||||
|
||||
// Non-existent event; will never fire. This exists as a mouse counterpart to
|
||||
// POINTERCANCEL.
|
||||
MOUSECANCEL: 'mousecancel',
|
||||
|
||||
// Selection events.
|
||||
// https://www.w3.org/TR/selection-api/
|
||||
SELECTIONCHANGE: 'selectionchange',
|
||||
SELECTSTART: 'selectstart', // IE, Safari, Chrome
|
||||
|
||||
// Wheel events
|
||||
// http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
|
||||
WHEEL: 'wheel',
|
||||
|
||||
// Key events
|
||||
KEYPRESS: 'keypress',
|
||||
KEYDOWN: 'keydown',
|
||||
KEYUP: 'keyup',
|
||||
|
||||
// Focus
|
||||
BLUR: 'blur',
|
||||
FOCUS: 'focus',
|
||||
DEACTIVATE: 'deactivate', // IE only
|
||||
FOCUSIN: 'focusin',
|
||||
FOCUSOUT: 'focusout',
|
||||
|
||||
// Forms
|
||||
CHANGE: 'change',
|
||||
RESET: 'reset',
|
||||
SELECT: 'select',
|
||||
SUBMIT: 'submit',
|
||||
INPUT: 'input',
|
||||
PROPERTYCHANGE: 'propertychange', // IE only
|
||||
|
||||
// Drag and drop
|
||||
DRAGSTART: 'dragstart',
|
||||
DRAG: 'drag',
|
||||
DRAGENTER: 'dragenter',
|
||||
DRAGOVER: 'dragover',
|
||||
DRAGLEAVE: 'dragleave',
|
||||
DROP: 'drop',
|
||||
DRAGEND: 'dragend',
|
||||
|
||||
// Touch events
|
||||
// Note that other touch events exist, but we should follow the W3C list here.
|
||||
// http://www.w3.org/TR/touch-events/#list-of-touchevent-types
|
||||
TOUCHSTART: 'touchstart',
|
||||
TOUCHMOVE: 'touchmove',
|
||||
TOUCHEND: 'touchend',
|
||||
TOUCHCANCEL: 'touchcancel',
|
||||
|
||||
// Misc
|
||||
BEFOREUNLOAD: 'beforeunload',
|
||||
CONSOLEMESSAGE: 'consolemessage',
|
||||
CONTEXTMENU: 'contextmenu',
|
||||
DEVICECHANGE: 'devicechange',
|
||||
DEVICEMOTION: 'devicemotion',
|
||||
DEVICEORIENTATION: 'deviceorientation',
|
||||
DOMCONTENTLOADED: 'DOMContentLoaded',
|
||||
ERROR: 'error',
|
||||
HELP: 'help',
|
||||
LOAD: 'load',
|
||||
LOSECAPTURE: 'losecapture',
|
||||
ORIENTATIONCHANGE: 'orientationchange',
|
||||
READYSTATECHANGE: 'readystatechange',
|
||||
RESIZE: 'resize',
|
||||
SCROLL: 'scroll',
|
||||
UNLOAD: 'unload',
|
||||
|
||||
// Media events
|
||||
CANPLAY: 'canplay',
|
||||
CANPLAYTHROUGH: 'canplaythrough',
|
||||
DURATIONCHANGE: 'durationchange',
|
||||
EMPTIED: 'emptied',
|
||||
ENDED: 'ended',
|
||||
LOADEDDATA: 'loadeddata',
|
||||
LOADEDMETADATA: 'loadedmetadata',
|
||||
PAUSE: 'pause',
|
||||
PLAY: 'play',
|
||||
PLAYING: 'playing',
|
||||
PROGRESS: 'progress',
|
||||
RATECHANGE: 'ratechange',
|
||||
SEEKED: 'seeked',
|
||||
SEEKING: 'seeking',
|
||||
STALLED: 'stalled',
|
||||
SUSPEND: 'suspend',
|
||||
TIMEUPDATE: 'timeupdate',
|
||||
VOLUMECHANGE: 'volumechange',
|
||||
WAITING: 'waiting',
|
||||
|
||||
// Media Source Extensions events
|
||||
// https://www.w3.org/TR/media-source/#mediasource-events
|
||||
SOURCEOPEN: 'sourceopen',
|
||||
SOURCEENDED: 'sourceended',
|
||||
SOURCECLOSED: 'sourceclosed',
|
||||
// https://www.w3.org/TR/media-source/#sourcebuffer-events
|
||||
ABORT: 'abort',
|
||||
UPDATE: 'update',
|
||||
UPDATESTART: 'updatestart',
|
||||
UPDATEEND: 'updateend',
|
||||
|
||||
// HTML 5 History events
|
||||
// See http://www.w3.org/TR/html5/browsers.html#event-definitions-0
|
||||
HASHCHANGE: 'hashchange',
|
||||
PAGEHIDE: 'pagehide',
|
||||
PAGESHOW: 'pageshow',
|
||||
POPSTATE: 'popstate',
|
||||
|
||||
// Copy and Paste
|
||||
// Support is limited. Make sure it works on your favorite browser
|
||||
// before using.
|
||||
// http://www.quirksmode.org/dom/events/cutcopypaste.html
|
||||
COPY: 'copy',
|
||||
PASTE: 'paste',
|
||||
CUT: 'cut',
|
||||
BEFORECOPY: 'beforecopy',
|
||||
BEFORECUT: 'beforecut',
|
||||
BEFOREPASTE: 'beforepaste',
|
||||
|
||||
// HTML5 online/offline events.
|
||||
// http://www.w3.org/TR/offline-webapps/#related
|
||||
ONLINE: 'online',
|
||||
OFFLINE: 'offline',
|
||||
|
||||
// HTML 5 worker events
|
||||
MESSAGE: 'message',
|
||||
CONNECT: 'connect',
|
||||
|
||||
// Service Worker Events - ServiceWorkerGlobalScope context
|
||||
// See https://w3c.github.io/ServiceWorker/#execution-context-events
|
||||
// Note: message event defined in worker events section
|
||||
INSTALL: 'install',
|
||||
ACTIVATE: 'activate',
|
||||
FETCH: 'fetch',
|
||||
FOREIGNFETCH: 'foreignfetch',
|
||||
MESSAGEERROR: 'messageerror',
|
||||
|
||||
// Service Worker Events - Document context
|
||||
// See https://w3c.github.io/ServiceWorker/#document-context-events
|
||||
STATECHANGE: 'statechange',
|
||||
UPDATEFOUND: 'updatefound',
|
||||
CONTROLLERCHANGE: 'controllerchange',
|
||||
|
||||
// CSS animation events.
|
||||
ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'),
|
||||
ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'),
|
||||
ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'),
|
||||
|
||||
// CSS transition events. Based on the browser support described at:
|
||||
// https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
|
||||
TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'),
|
||||
|
||||
// W3C Pointer Events
|
||||
// http://www.w3.org/TR/pointerevents/
|
||||
POINTERDOWN: 'pointerdown',
|
||||
POINTERUP: 'pointerup',
|
||||
POINTERCANCEL: 'pointercancel',
|
||||
POINTERMOVE: 'pointermove',
|
||||
POINTEROVER: 'pointerover',
|
||||
POINTEROUT: 'pointerout',
|
||||
POINTERENTER: 'pointerenter',
|
||||
POINTERLEAVE: 'pointerleave',
|
||||
GOTPOINTERCAPTURE: 'gotpointercapture',
|
||||
LOSTPOINTERCAPTURE: 'lostpointercapture',
|
||||
|
||||
// IE specific events.
|
||||
// See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx
|
||||
// Note: these events will be supplanted in IE11.
|
||||
MSGESTURECHANGE: 'MSGestureChange',
|
||||
MSGESTUREEND: 'MSGestureEnd',
|
||||
MSGESTUREHOLD: 'MSGestureHold',
|
||||
MSGESTURESTART: 'MSGestureStart',
|
||||
MSGESTURETAP: 'MSGestureTap',
|
||||
MSGOTPOINTERCAPTURE: 'MSGotPointerCapture',
|
||||
MSINERTIASTART: 'MSInertiaStart',
|
||||
MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture',
|
||||
MSPOINTERCANCEL: 'MSPointerCancel',
|
||||
MSPOINTERDOWN: 'MSPointerDown',
|
||||
MSPOINTERENTER: 'MSPointerEnter',
|
||||
MSPOINTERHOVER: 'MSPointerHover',
|
||||
MSPOINTERLEAVE: 'MSPointerLeave',
|
||||
MSPOINTERMOVE: 'MSPointerMove',
|
||||
MSPOINTEROUT: 'MSPointerOut',
|
||||
MSPOINTEROVER: 'MSPointerOver',
|
||||
MSPOINTERUP: 'MSPointerUp',
|
||||
|
||||
// Native IMEs/input tools events.
|
||||
TEXT: 'text',
|
||||
// The textInput event is supported in IE9+, but only in lower case. All other
|
||||
// browsers use the camel-case event name.
|
||||
TEXTINPUT: goog.userAgent.IE ? 'textinput' : 'textInput',
|
||||
COMPOSITIONSTART: 'compositionstart',
|
||||
COMPOSITIONUPDATE: 'compositionupdate',
|
||||
COMPOSITIONEND: 'compositionend',
|
||||
|
||||
// The beforeinput event is initially only supported in Safari. See
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=342670 for Chrome
|
||||
// implementation tracking.
|
||||
BEFOREINPUT: 'beforeinput',
|
||||
|
||||
// Webview tag events
|
||||
// See https://developer.chrome.com/apps/tags/webview
|
||||
EXIT: 'exit',
|
||||
LOADABORT: 'loadabort',
|
||||
LOADCOMMIT: 'loadcommit',
|
||||
LOADREDIRECT: 'loadredirect',
|
||||
LOADSTART: 'loadstart',
|
||||
LOADSTOP: 'loadstop',
|
||||
RESPONSIVE: 'responsive',
|
||||
SIZECHANGED: 'sizechanged',
|
||||
UNRESPONSIVE: 'unresponsive',
|
||||
|
||||
// HTML5 Page Visibility API. See details at
|
||||
// `goog.labs.dom.PageVisibilityMonitor`.
|
||||
VISIBILITYCHANGE: 'visibilitychange',
|
||||
|
||||
// LocalStorage event.
|
||||
STORAGE: 'storage',
|
||||
|
||||
// DOM Level 2 mutation events (deprecated).
|
||||
DOMSUBTREEMODIFIED: 'DOMSubtreeModified',
|
||||
DOMNODEINSERTED: 'DOMNodeInserted',
|
||||
DOMNODEREMOVED: 'DOMNodeRemoved',
|
||||
DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument',
|
||||
DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument',
|
||||
DOMATTRMODIFIED: 'DOMAttrModified',
|
||||
DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified',
|
||||
|
||||
// Print events.
|
||||
BEFOREPRINT: 'beforeprint',
|
||||
AFTERPRINT: 'afterprint',
|
||||
|
||||
// Web app manifest events.
|
||||
BEFOREINSTALLPROMPT: 'beforeinstallprompt',
|
||||
APPINSTALLED: 'appinstalled'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns one of the given pointer fallback event names in order of preference:
|
||||
* 1. pointerEventName
|
||||
* 2. msPointerEventName
|
||||
* 3. fallbackEventName
|
||||
* @param {string} pointerEventName
|
||||
* @param {string} msPointerEventName
|
||||
* @param {string} fallbackEventName
|
||||
* @return {string} The supported pointer or fallback (mouse or touch) event
|
||||
* name.
|
||||
* @private
|
||||
*/
|
||||
goog.events.getPointerFallbackEventName_ = function(
|
||||
pointerEventName, msPointerEventName, fallbackEventName) {
|
||||
'use strict';
|
||||
if (goog.events.BrowserFeature.POINTER_EVENTS) {
|
||||
return pointerEventName;
|
||||
}
|
||||
if (goog.events.BrowserFeature.MSPOINTER_EVENTS) {
|
||||
return msPointerEventName;
|
||||
}
|
||||
return fallbackEventName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constants for pointer event names that fall back to corresponding mouse event
|
||||
* names on unsupported platforms. These are intended to be drop-in replacements
|
||||
* for corresponding values in `goog.events.EventType`.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.events.PointerFallbackEventType = {
|
||||
POINTERDOWN: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERDOWN, goog.events.EventType.MSPOINTERDOWN,
|
||||
goog.events.EventType.MOUSEDOWN),
|
||||
POINTERUP: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERUP, goog.events.EventType.MSPOINTERUP,
|
||||
goog.events.EventType.MOUSEUP),
|
||||
POINTERCANCEL: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERCANCEL,
|
||||
goog.events.EventType.MSPOINTERCANCEL,
|
||||
// When falling back to mouse events, there is no MOUSECANCEL equivalent
|
||||
// of POINTERCANCEL. In this case POINTERUP already falls back to MOUSEUP
|
||||
// which represents both UP and CANCEL. POINTERCANCEL does not fall back
|
||||
// to MOUSEUP to prevent listening twice on the same event.
|
||||
goog.events.EventType.MOUSECANCEL),
|
||||
POINTERMOVE: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERMOVE, goog.events.EventType.MSPOINTERMOVE,
|
||||
goog.events.EventType.MOUSEMOVE),
|
||||
POINTEROVER: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTEROVER, goog.events.EventType.MSPOINTEROVER,
|
||||
goog.events.EventType.MOUSEOVER),
|
||||
POINTEROUT: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTEROUT, goog.events.EventType.MSPOINTEROUT,
|
||||
goog.events.EventType.MOUSEOUT),
|
||||
POINTERENTER: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERENTER, goog.events.EventType.MSPOINTERENTER,
|
||||
goog.events.EventType.MOUSEENTER),
|
||||
POINTERLEAVE: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERLEAVE, goog.events.EventType.MSPOINTERLEAVE,
|
||||
goog.events.EventType.MOUSELEAVE)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constants for pointer event names that fall back to corresponding touch event
|
||||
* names on unsupported platforms. These are intended to be drop-in replacements
|
||||
* for corresponding values in `goog.events.EventType`.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.events.PointerTouchFallbackEventType = {
|
||||
POINTERDOWN: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERDOWN, goog.events.EventType.MSPOINTERDOWN,
|
||||
goog.events.EventType.TOUCHSTART),
|
||||
POINTERUP: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERUP, goog.events.EventType.MSPOINTERUP,
|
||||
goog.events.EventType.TOUCHEND),
|
||||
POINTERCANCEL: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERCANCEL,
|
||||
goog.events.EventType.MSPOINTERCANCEL, goog.events.EventType.TOUCHCANCEL),
|
||||
POINTERMOVE: goog.events.getPointerFallbackEventName_(
|
||||
goog.events.EventType.POINTERMOVE, goog.events.EventType.MSPOINTERMOVE,
|
||||
goog.events.EventType.TOUCHMOVE)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mapping of mouse event names to underlying browser event names.
|
||||
* @typedef {{
|
||||
* MOUSEDOWN: string,
|
||||
* MOUSEUP: string,
|
||||
* MOUSECANCEL:string,
|
||||
* MOUSEMOVE:string,
|
||||
* MOUSEOVER:string,
|
||||
* MOUSEOUT:string,
|
||||
* MOUSEENTER:string,
|
||||
* MOUSELEAVE: string,
|
||||
* }}
|
||||
*/
|
||||
goog.events.MouseEvents;
|
||||
|
||||
|
||||
/**
|
||||
* An alias for `goog.events.EventType.MOUSE*` event types that is overridden by
|
||||
* corresponding `POINTER*` event types.
|
||||
* @const {!goog.events.MouseEvents}
|
||||
*/
|
||||
goog.events.PointerAsMouseEventType = {
|
||||
MOUSEDOWN: goog.events.PointerFallbackEventType.POINTERDOWN,
|
||||
MOUSEUP: goog.events.PointerFallbackEventType.POINTERUP,
|
||||
MOUSECANCEL: goog.events.PointerFallbackEventType.POINTERCANCEL,
|
||||
MOUSEMOVE: goog.events.PointerFallbackEventType.POINTERMOVE,
|
||||
MOUSEOVER: goog.events.PointerFallbackEventType.POINTEROVER,
|
||||
MOUSEOUT: goog.events.PointerFallbackEventType.POINTEROUT,
|
||||
MOUSEENTER: goog.events.PointerFallbackEventType.POINTERENTER,
|
||||
MOUSELEAVE: goog.events.PointerFallbackEventType.POINTERLEAVE
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An alias for `goog.events.EventType.MOUSE*` event types that continue to use
|
||||
* mouse events.
|
||||
* @const {!goog.events.MouseEvents}
|
||||
*/
|
||||
goog.events.MouseAsMouseEventType = {
|
||||
MOUSEDOWN: goog.events.EventType.MOUSEDOWN,
|
||||
MOUSEUP: goog.events.EventType.MOUSEUP,
|
||||
MOUSECANCEL: goog.events.EventType.MOUSECANCEL,
|
||||
MOUSEMOVE: goog.events.EventType.MOUSEMOVE,
|
||||
MOUSEOVER: goog.events.EventType.MOUSEOVER,
|
||||
MOUSEOUT: goog.events.EventType.MOUSEOUT,
|
||||
MOUSEENTER: goog.events.EventType.MOUSEENTER,
|
||||
MOUSELEAVE: goog.events.EventType.MOUSELEAVE
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An alias for `goog.events.EventType.TOUCH*` event types that is overridden by
|
||||
* corresponding `POINTER*` event types.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.events.PointerAsTouchEventType = {
|
||||
TOUCHCANCEL: goog.events.PointerTouchFallbackEventType.POINTERCANCEL,
|
||||
TOUCHEND: goog.events.PointerTouchFallbackEventType.POINTERUP,
|
||||
TOUCHMOVE: goog.events.PointerTouchFallbackEventType.POINTERMOVE,
|
||||
TOUCHSTART: goog.events.PointerTouchFallbackEventType.POINTERDOWN
|
||||
};
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Definition of the goog.events.EventWrapper interface.
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.EventWrapper');
|
||||
|
||||
goog.requireType('goog.events.EventHandler');
|
||||
goog.requireType('goog.events.ListenableType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for event wrappers.
|
||||
* @interface
|
||||
*/
|
||||
goog.events.EventWrapper = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener using the wrapper on a DOM Node or an object that has
|
||||
* implemented {@link goog.events.EventTarget}. A listener can only be added
|
||||
* once to an object.
|
||||
*
|
||||
* @param {goog.events.ListenableType} src The node to listen to events on.
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
|
||||
* method, or an object with a handleEvent function.
|
||||
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
|
||||
* false).
|
||||
* @param {Object=} opt_scope Element in whose scope to call the listener.
|
||||
* @param {goog.events.EventHandler=} opt_eventHandler Event handler to add
|
||||
* listener to.
|
||||
*/
|
||||
goog.events.EventWrapper.prototype.listen = function(
|
||||
src, listener, opt_capt, opt_scope, opt_eventHandler) {};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener added using goog.events.EventWrapper.listen.
|
||||
*
|
||||
* @param {goog.events.ListenableType} src The node to remove listener from.
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
|
||||
* method, or an object with a handleEvent function.
|
||||
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
|
||||
* false).
|
||||
* @param {Object=} opt_scope Element in whose scope to call the listener.
|
||||
* @param {goog.events.EventHandler=} opt_eventHandler Event handler to remove
|
||||
* listener from.
|
||||
*/
|
||||
goog.events.EventWrapper.prototype.unlisten = function(
|
||||
src, listener, opt_capt, opt_scope, opt_eventHandler) {};
|
||||
Executable
+265
@@ -0,0 +1,265 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview An interface for a listenable JavaScript object.
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.Listenable');
|
||||
|
||||
goog.requireType('goog.events.EventId');
|
||||
goog.requireType('goog.events.EventLike');
|
||||
goog.requireType('goog.events.ListenableKey');
|
||||
|
||||
|
||||
/**
|
||||
* A listenable interface. A listenable is an object with the ability
|
||||
* to dispatch/broadcast events to "event listeners" registered via
|
||||
* listen/listenOnce.
|
||||
*
|
||||
* The interface allows for an event propagation mechanism similar
|
||||
* to one offered by native browser event targets, such as
|
||||
* capture/bubble mechanism, stopping propagation, and preventing
|
||||
* default actions. Capture/bubble mechanism depends on the ancestor
|
||||
* tree constructed via `#getParentEventTarget`; this tree
|
||||
* must be directed acyclic graph. The meaning of default action(s)
|
||||
* in preventDefault is specific to a particular use case.
|
||||
*
|
||||
* Implementations that do not support capture/bubble or can not have
|
||||
* a parent listenable can simply not implement any ability to set the
|
||||
* parent listenable (and have `#getParentEventTarget` return
|
||||
* null).
|
||||
*
|
||||
* Implementation of this class can be used with or independently from
|
||||
* goog.events.
|
||||
*
|
||||
* Implementation must call `#addImplementation(implClass)`.
|
||||
*
|
||||
* @interface
|
||||
* @see goog.events
|
||||
* @see http://www.w3.org/TR/DOM-Level-2-Events/events.html
|
||||
*/
|
||||
goog.events.Listenable = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* An expando property to indicate that an object implements
|
||||
* goog.events.Listenable.
|
||||
*
|
||||
* See addImplementation/isImplementedBy.
|
||||
*
|
||||
* @type {string}
|
||||
* @const
|
||||
*/
|
||||
goog.events.Listenable.IMPLEMENTED_BY_PROP =
|
||||
'closure_listenable_' + ((Math.random() * 1e6) | 0);
|
||||
|
||||
|
||||
/**
|
||||
* Marks a given class (constructor) as an implementation of
|
||||
* Listenable, so that we can query that fact at runtime. The class
|
||||
* must have already implemented the interface.
|
||||
* @param {function(new:goog.events.Listenable,...)} cls The class constructor.
|
||||
* The corresponding class must have already implemented the interface.
|
||||
*/
|
||||
goog.events.Listenable.addImplementation = function(cls) {
|
||||
'use strict';
|
||||
cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?Object} obj The object to check.
|
||||
* @return {boolean} Whether a given instance implements Listenable. The
|
||||
* class/superclass of the instance must call addImplementation.
|
||||
*/
|
||||
goog.events.Listenable.isImplementedBy = function(obj) {
|
||||
'use strict';
|
||||
return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener. A listener can only be added once to an
|
||||
* object and if it is added again the key for the listener is
|
||||
* returned. Note that if the existing listener is a one-off listener
|
||||
* (registered via listenOnce), it will no longer be a one-off
|
||||
* listener after a call to listen().
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.listen = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener that is removed automatically after the
|
||||
* listener fired once.
|
||||
*
|
||||
* If an existing listener already exists, listenOnce will do
|
||||
* nothing. In particular, if the listener was previously registered
|
||||
* via listen(), listenOnce() will not turn the listener into a
|
||||
* one-off listener. Similarly, if there is already an existing
|
||||
* one-off listener, listenOnce does not modify the listeners (it is
|
||||
* still a once listener).
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.listenOnce = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listen() or listenOnce().
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call
|
||||
* the listener.
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.unlisten = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listen() by the key
|
||||
* returned by listen().
|
||||
*
|
||||
* @param {!goog.events.ListenableKey} key The key returned by
|
||||
* listen() or listenOnce().
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
*/
|
||||
goog.events.Listenable.prototype.unlistenByKey = function(key) {};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches an event (or event like object) and calls all listeners
|
||||
* listening for events of this type. The type of the event is decided by the
|
||||
* type property on the event object.
|
||||
*
|
||||
* If any of the listeners returns false OR calls preventDefault then this
|
||||
* function will return false. If one of the capture listeners calls
|
||||
* stopPropagation, then the bubble listeners won't fire.
|
||||
*
|
||||
* @param {?goog.events.EventLike} e Event object.
|
||||
* @return {boolean} If anyone called preventDefault on the event object (or
|
||||
* if any of the listeners returns false) this will also return false.
|
||||
*/
|
||||
goog.events.Listenable.prototype.dispatchEvent = function(e) {};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all listeners from this listenable. If type is specified,
|
||||
* it will only remove listeners of the particular type. otherwise all
|
||||
* registered listeners will be removed.
|
||||
*
|
||||
* @param {string|!goog.events.EventId=} opt_type Type of event to remove,
|
||||
* default is to remove all types.
|
||||
* @return {number} Number of listeners removed.
|
||||
*/
|
||||
goog.events.Listenable.prototype.removeAllListeners = function(opt_type) {};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parent of this event target to use for capture/bubble
|
||||
* mechanism.
|
||||
*
|
||||
* NOTE(chrishenry): The name reflects the original implementation of
|
||||
* custom event target (`goog.events.EventTarget`). We decided
|
||||
* that changing the name is not worth it.
|
||||
*
|
||||
* @return {?goog.events.Listenable} The parent EventTarget or null if
|
||||
* there is no parent.
|
||||
*/
|
||||
goog.events.Listenable.prototype.getParentEventTarget = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Fires all registered listeners in this listenable for the given
|
||||
* type and capture mode, passing them the given eventObject. This
|
||||
* does not perform actual capture/bubble. Only implementors of the
|
||||
* interface should be using this.
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the
|
||||
* listeners to fire.
|
||||
* @param {boolean} capture The capture mode of the listeners to fire.
|
||||
* @param {EVENTOBJ} eventObject The event object to fire.
|
||||
* @return {boolean} Whether all listeners succeeded without
|
||||
* attempting to prevent default behavior. If any listener returns
|
||||
* false or called goog.events.Event#preventDefault, this returns
|
||||
* false.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.fireListeners = function(
|
||||
type, capture, eventObject) {};
|
||||
|
||||
|
||||
/**
|
||||
* Gets all listeners in this listenable for the given type and
|
||||
* capture mode.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The type of the listeners to fire.
|
||||
* @param {boolean} capture The capture mode of the listeners to fire.
|
||||
* @return {!Array<!goog.events.ListenableKey>} An array of registered
|
||||
* listeners.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.getListeners = function(type, capture) {};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the goog.events.ListenableKey for the event or null if no such
|
||||
* listener is in use.
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event
|
||||
* without the 'on' prefix.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The
|
||||
* listener function to get.
|
||||
* @param {boolean} capture Whether the listener is a capturing listener.
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {?goog.events.ListenableKey} the found listener or null if not found.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.getListener = function(
|
||||
type, listener, capture, opt_listenerScope) {};
|
||||
|
||||
|
||||
/**
|
||||
* Whether there is any active listeners matching the specified
|
||||
* signature. If either the type or capture parameters are
|
||||
* unspecified, the function will match on the remaining criteria.
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type.
|
||||
* @param {boolean=} opt_capture Whether to check for capture or bubble
|
||||
* listeners.
|
||||
* @return {boolean} Whether there is any active listeners matching
|
||||
* the requested type and/or capture phase.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.hasListener = function(
|
||||
opt_type, opt_capture) {};
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview An interface that describes a single registered listener.
|
||||
*/
|
||||
goog.provide('goog.events.ListenableKey');
|
||||
|
||||
goog.requireType('goog.events.Listenable');
|
||||
|
||||
|
||||
/**
|
||||
* An interface that describes a single registered listener.
|
||||
* @interface
|
||||
*/
|
||||
goog.events.ListenableKey = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Counter used to create a unique key
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.events.ListenableKey.counter_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Reserves a key to be used for ListenableKey#key field.
|
||||
* @return {number} A number to be used to fill ListenableKey#key
|
||||
* field.
|
||||
*/
|
||||
goog.events.ListenableKey.reserveKey = function() {
|
||||
'use strict';
|
||||
return ++goog.events.ListenableKey.counter_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The source event target.
|
||||
* @type {?Object|?goog.events.Listenable}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.src;
|
||||
|
||||
|
||||
/**
|
||||
* The event type the listener is listening to.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.type;
|
||||
|
||||
|
||||
/**
|
||||
* The listener function.
|
||||
* @type {function(?):?|{handleEvent:function(?):?}|null}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.listener;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the listener works on capture phase.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.capture;
|
||||
|
||||
|
||||
/**
|
||||
* The 'this' object for the listener function's scope.
|
||||
* @type {?Object|undefined}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.handler;
|
||||
|
||||
|
||||
/**
|
||||
* A globally unique number to identify the key.
|
||||
* @type {number}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.key;
|
||||
Executable
+124
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Listener object.
|
||||
* @see ../demos/events.html
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.Listener');
|
||||
|
||||
goog.require('goog.events.ListenableKey');
|
||||
goog.requireType('goog.events.Listenable');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple class that stores information about a listener
|
||||
* @param {function(?):?} listener Callback function.
|
||||
* @param {Function} proxy Wrapper for the listener that patches the event.
|
||||
* @param {EventTarget|goog.events.Listenable} src Source object for
|
||||
* the event.
|
||||
* @param {string} type Event type.
|
||||
* @param {boolean} capture Whether in capture or bubble phase.
|
||||
* @param {Object=} opt_handler Object in whose context to execute the callback.
|
||||
* @implements {goog.events.ListenableKey}
|
||||
* @constructor
|
||||
*/
|
||||
goog.events.Listener = function(
|
||||
listener, proxy, src, type, capture, opt_handler) {
|
||||
'use strict';
|
||||
if (goog.events.Listener.ENABLE_MONITORING) {
|
||||
this.creationStack = new Error().stack;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
this.listener = listener;
|
||||
|
||||
/**
|
||||
* A wrapper over the original listener. This is used solely to
|
||||
* handle native browser events (it is used to simulate the capture
|
||||
* phase and to patch the event object).
|
||||
* @type {Function}
|
||||
*/
|
||||
this.proxy = proxy;
|
||||
|
||||
/**
|
||||
* Object or node that callback is listening to
|
||||
* @type {EventTarget|goog.events.Listenable}
|
||||
*/
|
||||
this.src = src;
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
* @const {string}
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* Whether the listener is being called in the capture or bubble phase
|
||||
* @const {boolean}
|
||||
*/
|
||||
this.capture = !!capture;
|
||||
|
||||
/**
|
||||
* Optional object whose context to execute the listener in
|
||||
* @type {Object|undefined}
|
||||
*/
|
||||
this.handler = opt_handler;
|
||||
|
||||
/**
|
||||
* The key of the listener.
|
||||
* @const {number}
|
||||
* @override
|
||||
*/
|
||||
this.key = goog.events.ListenableKey.reserveKey();
|
||||
|
||||
/**
|
||||
* Whether to remove the listener after it has been called.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.callOnce = false;
|
||||
|
||||
/**
|
||||
* Whether the listener has been removed.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.removed = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to enable the monitoring of the
|
||||
* goog.events.Listener instances. Switching on the monitoring is only
|
||||
* recommended for debugging because it has a significant impact on
|
||||
* performance and memory usage. If switched off, the monitoring code
|
||||
* compiles down to 0 bytes.
|
||||
*/
|
||||
goog.events.Listener.ENABLE_MONITORING =
|
||||
goog.define('goog.events.Listener.ENABLE_MONITORING', false);
|
||||
|
||||
|
||||
/**
|
||||
* If monitoring the goog.events.Listener instances is enabled, stores the
|
||||
* creation stack trace of the Disposable instance.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.events.Listener.prototype.creationStack;
|
||||
|
||||
|
||||
/**
|
||||
* Marks this listener as removed. This also remove references held by
|
||||
* this listener object (such as listener and event source).
|
||||
*/
|
||||
goog.events.Listener.prototype.markAsRemoved = function() {
|
||||
'use strict';
|
||||
this.removed = true;
|
||||
this.listener = null;
|
||||
this.proxy = null;
|
||||
this.src = null;
|
||||
this.handler = null;
|
||||
};
|
||||
Executable
+310
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright The Closure Library Authors.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview A map of listeners that provides utility functions to
|
||||
* deal with listeners on an event target. Used by
|
||||
* `goog.events.EventTarget`.
|
||||
*
|
||||
* WARNING: Do not use this class from outside goog.events package.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.ListenerMap');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.events.Listener');
|
||||
goog.require('goog.object');
|
||||
goog.requireType('goog.events.EventId');
|
||||
goog.requireType('goog.events.Listenable');
|
||||
goog.requireType('goog.events.ListenableKey');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new listener map.
|
||||
* @param {EventTarget|goog.events.Listenable} src The src object.
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.events.ListenerMap = function(src) {
|
||||
'use strict';
|
||||
/** @type {EventTarget|goog.events.Listenable} */
|
||||
this.src = src;
|
||||
|
||||
/**
|
||||
* Maps of event type to an array of listeners.
|
||||
* @type {!Object<string, !Array<!goog.events.Listener>>}
|
||||
*/
|
||||
this.listeners = {};
|
||||
|
||||
/**
|
||||
* The count of types in this map that have registered listeners.
|
||||
* @private {number}
|
||||
*/
|
||||
this.typeCount_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The count of event types in this map that actually
|
||||
* have registered listeners.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getTypeCount = function() {
|
||||
'use strict';
|
||||
return this.typeCount_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Total number of registered listeners.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getListenerCount = function() {
|
||||
'use strict';
|
||||
var count = 0;
|
||||
for (var type in this.listeners) {
|
||||
count += this.listeners[type].length;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener. A listener can only be added once to an
|
||||
* object and if it is added again the key for the listener is
|
||||
* returned.
|
||||
*
|
||||
* Note that a one-off listener will not change an existing listener,
|
||||
* if any. On the other hand a normal listener will change existing
|
||||
* one-off listener to become a normal listener.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The listener event type.
|
||||
* @param {!Function} listener This listener callback method.
|
||||
* @param {boolean} callOnce Whether the listener is a one-off
|
||||
* listener.
|
||||
* @param {boolean=} opt_useCapture The capture mode of the listener.
|
||||
* @param {Object=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.add = function(
|
||||
type, listener, callOnce, opt_useCapture, opt_listenerScope) {
|
||||
'use strict';
|
||||
var typeStr = type.toString();
|
||||
var listenerArray = this.listeners[typeStr];
|
||||
if (!listenerArray) {
|
||||
listenerArray = this.listeners[typeStr] = [];
|
||||
this.typeCount_++;
|
||||
}
|
||||
|
||||
var listenerObj;
|
||||
var index = goog.events.ListenerMap.findListenerIndex_(
|
||||
listenerArray, listener, opt_useCapture, opt_listenerScope);
|
||||
if (index > -1) {
|
||||
listenerObj = listenerArray[index];
|
||||
if (!callOnce) {
|
||||
// Ensure that, if there is an existing callOnce listener, it is no
|
||||
// longer a callOnce listener.
|
||||
listenerObj.callOnce = false;
|
||||
}
|
||||
} else {
|
||||
listenerObj = new goog.events.Listener(
|
||||
listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope);
|
||||
listenerObj.callOnce = callOnce;
|
||||
listenerArray.push(listenerObj);
|
||||
}
|
||||
return listenerObj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a matching listener.
|
||||
* @param {string|!goog.events.EventId} type The listener event type.
|
||||
* @param {!Function} listener This listener callback method.
|
||||
* @param {boolean=} opt_useCapture The capture mode of the listener.
|
||||
* @param {Object=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.remove = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
'use strict';
|
||||
var typeStr = type.toString();
|
||||
if (!(typeStr in this.listeners)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var listenerArray = this.listeners[typeStr];
|
||||
var index = goog.events.ListenerMap.findListenerIndex_(
|
||||
listenerArray, listener, opt_useCapture, opt_listenerScope);
|
||||
if (index > -1) {
|
||||
var listenerObj = listenerArray[index];
|
||||
listenerObj.markAsRemoved();
|
||||
goog.array.removeAt(listenerArray, index);
|
||||
if (listenerArray.length == 0) {
|
||||
delete this.listeners[typeStr];
|
||||
this.typeCount_--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given listener object.
|
||||
* @param {!goog.events.ListenableKey} listener The listener to remove.
|
||||
* @return {boolean} Whether the listener is removed.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.removeByKey = function(listener) {
|
||||
'use strict';
|
||||
var type = listener.type;
|
||||
if (!(type in this.listeners)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var removed = goog.array.remove(this.listeners[type], listener);
|
||||
if (removed) {
|
||||
/** @type {!goog.events.Listener} */ (listener).markAsRemoved();
|
||||
if (this.listeners[type].length == 0) {
|
||||
delete this.listeners[type];
|
||||
this.typeCount_--;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all listeners from this map. If opt_type is provided, only
|
||||
* listeners that match the given type are removed.
|
||||
* @param {string|!goog.events.EventId=} opt_type Type of event to remove.
|
||||
* @return {number} Number of listeners removed.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.removeAll = function(opt_type) {
|
||||
'use strict';
|
||||
var typeStr = opt_type && opt_type.toString();
|
||||
var count = 0;
|
||||
for (var type in this.listeners) {
|
||||
if (!typeStr || type == typeStr) {
|
||||
var listenerArray = this.listeners[type];
|
||||
for (var i = 0; i < listenerArray.length; i++) {
|
||||
++count;
|
||||
listenerArray[i].markAsRemoved();
|
||||
}
|
||||
delete this.listeners[type];
|
||||
this.typeCount_--;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets all listeners that match the given type and capture mode. The
|
||||
* returned array is a copy (but the listener objects are not).
|
||||
* @param {string|!goog.events.EventId} type The type of the listeners
|
||||
* to retrieve.
|
||||
* @param {boolean} capture The capture mode of the listeners to retrieve.
|
||||
* @return {!Array<!goog.events.ListenableKey>} An array of matching
|
||||
* listeners.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getListeners = function(type, capture) {
|
||||
'use strict';
|
||||
var listenerArray = this.listeners[type.toString()];
|
||||
var rv = [];
|
||||
if (listenerArray) {
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
var listenerObj = listenerArray[i];
|
||||
if (listenerObj.capture == capture) {
|
||||
rv.push(listenerObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the goog.events.ListenableKey for the event or null if no such
|
||||
* listener is in use.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The type of the listener
|
||||
* to retrieve.
|
||||
* @param {!Function} listener The listener function to get.
|
||||
* @param {boolean} capture Whether the listener is a capturing listener.
|
||||
* @param {Object=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {goog.events.ListenableKey} the found listener or null if not found.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getListener = function(
|
||||
type, listener, capture, opt_listenerScope) {
|
||||
'use strict';
|
||||
var listenerArray = this.listeners[type.toString()];
|
||||
var i = -1;
|
||||
if (listenerArray) {
|
||||
i = goog.events.ListenerMap.findListenerIndex_(
|
||||
listenerArray, listener, capture, opt_listenerScope);
|
||||
}
|
||||
return i > -1 ? listenerArray[i] : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether there is a matching listener. If either the type or capture
|
||||
* parameters are unspecified, the function will match on the
|
||||
* remaining criteria.
|
||||
*
|
||||
* @param {string|!goog.events.EventId=} opt_type The type of the listener.
|
||||
* @param {boolean=} opt_capture The capture mode of the listener.
|
||||
* @return {boolean} Whether there is an active listener matching
|
||||
* the requested type and/or capture phase.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.hasListener = function(
|
||||
opt_type, opt_capture) {
|
||||
'use strict';
|
||||
var hasType = (opt_type !== undefined);
|
||||
var typeStr = hasType ? opt_type.toString() : '';
|
||||
var hasCapture = (opt_capture !== undefined);
|
||||
|
||||
return goog.object.some(this.listeners, function(listenerArray, type) {
|
||||
'use strict';
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
if ((!hasType || listenerArray[i].type == typeStr) &&
|
||||
(!hasCapture || listenerArray[i].capture == opt_capture)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds the index of a matching goog.events.Listener in the given
|
||||
* listenerArray.
|
||||
* @param {!Array<!goog.events.Listener>} listenerArray Array of listener.
|
||||
* @param {!Function} listener The listener function.
|
||||
* @param {boolean=} opt_useCapture The capture flag for the listener.
|
||||
* @param {Object=} opt_listenerScope The listener scope.
|
||||
* @return {number} The index of the matching listener within the
|
||||
* listenerArray.
|
||||
* @private
|
||||
*/
|
||||
goog.events.ListenerMap.findListenerIndex_ = function(
|
||||
listenerArray, listener, opt_useCapture, opt_listenerScope) {
|
||||
'use strict';
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
var listenerObj = listenerArray[i];
|
||||
if (!listenerObj.removed && listenerObj.listener == listener &&
|
||||
listenerObj.capture == !!opt_useCapture &&
|
||||
listenerObj.handler == opt_listenerScope) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
Reference in New Issue
Block a user