Simplify events and store listeners only in one place

This commit is contained in:
ahocevar
2019-09-04 16:39:32 +02:00
parent d416866108
commit ebfb20440a
52 changed files with 224 additions and 599 deletions

View File

@@ -2,7 +2,7 @@
* @module ol/Feature
*/
import {assert} from './asserts.js';
import {listen, unlisten, unlistenByKey} from './events.js';
import {listen, unlistenByKey} from './events.js';
import EventType from './events/EventType.js';
import BaseObject, {getChangeEventType} from './Object.js';
@@ -101,9 +101,7 @@ class Feature extends BaseObject {
*/
this.geometryChangeKey_ = null;
listen(
this, getChangeEventType(this.geometryName_),
this.handleGeometryChanged_, this);
this.addEventListener(getChangeEventType(this.geometryName_), this.handleGeometryChanged_);
if (opt_geometryOrProperties) {
if (typeof /** @type {?} */ (opt_geometryOrProperties).getSimplifiedGeometry === 'function') {
@@ -263,13 +261,9 @@ class Feature extends BaseObject {
* @api
*/
setGeometryName(name) {
unlisten(
this, getChangeEventType(this.geometryName_),
this.handleGeometryChanged_, this);
this.removeEventListener(getChangeEventType(this.geometryName_), this.handleGeometryChanged_);
this.geometryName_ = name;
listen(
this, getChangeEventType(this.geometryName_),
this.handleGeometryChanged_, this);
this.addEventListener(getChangeEventType(this.geometryName_), this.handleGeometryChanged_);
this.handleGeometryChanged_();
}
}

View File

@@ -2,8 +2,7 @@
* @module ol/Geolocation
*/
import BaseObject, {getChangeEventType} from './Object.js';
import {listen} from './events.js';
import Event from './events/Event.js';
import BaseEvent from './events/Event.js';
import EventType from './events/EventType.js';
import {circular as circularPolygon} from './geom/Polygon.js';
import {toRadians} from './math.js';
@@ -31,7 +30,7 @@ const Property = {
* @classdesc
* Events emitted on Geolocation error.
*/
class GeolocationError extends Event {
class GeolocationError extends BaseEvent {
/**
* @param {PositionError} error error object.
*/
@@ -115,12 +114,8 @@ class Geolocation extends BaseObject {
*/
this.watchId_ = undefined;
listen(
this, getChangeEventType(Property.PROJECTION),
this.handleProjectionChanged_, this);
listen(
this, getChangeEventType(Property.TRACKING),
this.handleTrackingChanged_, this);
this.addEventListener(getChangeEventType(Property.PROJECTION), this.handleProjectionChanged_);
this.addEventListener(getChangeEventType(Property.TRACKING), this.handleTrackingChanged_);
if (options.projection !== undefined) {
this.setProjection(options.projection);

View File

@@ -1,7 +1,7 @@
/**
* @module ol/Observable
*/
import {listen, unlistenByKey, unlisten, listenOnce} from './events.js';
import {listen, unlistenByKey, listenOnce} from './events.js';
import EventTarget from './events/Target.js';
import EventType from './events/EventType.js';
@@ -101,11 +101,10 @@ class Observable extends EventTarget {
un(type, listener) {
if (Array.isArray(type)) {
for (let i = 0, ii = type.length; i < ii; ++i) {
unlisten(this, type[i], listener);
this.removeEventListener(type[i], listener);
}
return;
} else {
unlisten(this, /** @type {string} */ (type), listener);
this.removeEventListener(type, listener);
}
}
}

View File

@@ -178,25 +178,11 @@ class Overlay extends BaseObject {
*/
this.mapPostrenderListenerKey = null;
listen(
this, getChangeEventType(Property.ELEMENT),
this.handleElementChanged, this);
listen(
this, getChangeEventType(Property.MAP),
this.handleMapChanged, this);
listen(
this, getChangeEventType(Property.OFFSET),
this.handleOffsetChanged, this);
listen(
this, getChangeEventType(Property.POSITION),
this.handlePositionChanged, this);
listen(
this, getChangeEventType(Property.POSITIONING),
this.handlePositioningChanged, this);
this.addEventListener(getChangeEventType(Property.ELEMENT), this.handleElementChanged);
this.addEventListener(getChangeEventType(Property.MAP), this.handleMapChanged);
this.addEventListener(getChangeEventType(Property.OFFSET), this.handleOffsetChanged);
this.addEventListener(getChangeEventType(Property.POSITION), this.handlePositionChanged);
this.addEventListener(getChangeEventType(Property.POSITIONING), this.handlePositioningChanged);
if (options.element !== undefined) {
this.setElement(options.element);

View File

@@ -18,7 +18,7 @@ import View from './View.js';
import ViewHint from './ViewHint.js';
import {assert} from './asserts.js';
import {removeNode} from './dom.js';
import {listen, unlistenByKey, unlisten} from './events.js';
import {listen, unlistenByKey} from './events.js';
import EventType from './events/EventType.js';
import {createEmpty, clone, createOrUpdateEmpty, equals, getForViewAndSize, isEmpty} from './extent.js';
import {TRUE} from './functions.js';
@@ -149,6 +149,10 @@ class PluggableMap extends BaseObject {
const optionsInternal = createOptionsInternal(options);
/** @private */
this.boundHandleBrowserEvent_ = this.handleBrowserEvent.bind(this);
/**
* @type {number}
* @private
@@ -268,9 +272,9 @@ class PluggableMap extends BaseObject {
* @type {MapBrowserEventHandler}
*/
this.mapBrowserEventHandler_ = new MapBrowserEventHandler(this, options.moveTolerance);
const handleMapBrowserEvent = this.handleMapBrowserEvent.bind(this);
for (const key in MapBrowserEventType) {
listen(this.mapBrowserEventHandler_, MapBrowserEventType[key],
this.handleMapBrowserEvent, this);
this.mapBrowserEventHandler_.addEventListener(MapBrowserEventType[key], handleMapBrowserEvent);
}
/**
@@ -285,8 +289,9 @@ class PluggableMap extends BaseObject {
*/
this.keyHandlerKeys_ = null;
listen(this.viewport_, EventType.CONTEXTMENU, this.handleBrowserEvent, this);
listen(this.viewport_, EventType.WHEEL, this.handleBrowserEvent, this);
const handleBrowserEvent = this.handleBrowserEvent.bind(this);
this.viewport_.addEventListener(EventType.CONTEXTMENU, handleBrowserEvent, false);
this.viewport_.addEventListener(EventType.WHEEL, handleBrowserEvent, false);
/**
* @type {Collection<import("./control/Control.js").default>}
@@ -362,15 +367,10 @@ class PluggableMap extends BaseObject {
*/
this.skippedFeatureUids_ = {};
listen(
this, getChangeEventType(MapProperty.LAYERGROUP),
this.handleLayerGroupChanged_, this);
listen(this, getChangeEventType(MapProperty.VIEW),
this.handleViewChanged_, this);
listen(this, getChangeEventType(MapProperty.SIZE),
this.handleSizeChanged_, this);
listen(this, getChangeEventType(MapProperty.TARGET),
this.handleTargetChanged_, this);
this.addEventListener(getChangeEventType(MapProperty.LAYERGROUP), this.handleLayerGroupChanged_);
this.addEventListener(getChangeEventType(MapProperty.VIEW), this.handleViewChanged_);
this.addEventListener(getChangeEventType(MapProperty.SIZE), this.handleSizeChanged_);
this.addEventListener(getChangeEventType(MapProperty.TARGET), this.handleTargetChanged_);
// setProperties will trigger the rendering of the map if the map
// is "defined" already.
@@ -385,21 +385,21 @@ class PluggableMap extends BaseObject {
control.setMap(this);
}).bind(this));
listen(this.controls, CollectionEventType.ADD,
this.controls.addEventListener(CollectionEventType.ADD,
/**
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
*/
function(event) {
event.element.setMap(this);
}, this);
}.bind(this));
listen(this.controls, CollectionEventType.REMOVE,
this.controls.addEventListener(CollectionEventType.REMOVE,
/**
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
*/
function(event) {
event.element.setMap(null);
}, this);
}.bind(this));
this.interactions.forEach(
/**
@@ -410,33 +410,33 @@ class PluggableMap extends BaseObject {
interaction.setMap(this);
}).bind(this));
listen(this.interactions, CollectionEventType.ADD,
this.interactions.addEventListener(CollectionEventType.ADD,
/**
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
*/
function(event) {
event.element.setMap(this);
}, this);
}.bind(this));
listen(this.interactions, CollectionEventType.REMOVE,
this.interactions.addEventListener(CollectionEventType.REMOVE,
/**
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
*/
function(event) {
event.element.setMap(null);
}, this);
}.bind(this));
this.overlays_.forEach(this.addOverlayInternal_.bind(this));
listen(this.overlays_, CollectionEventType.ADD,
this.overlays_.addEventListener(CollectionEventType.ADD,
/**
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
*/
function(event) {
this.addOverlayInternal_(/** @type {import("./Overlay.js").default} */ (event.element));
}, this);
}.bind(this));
listen(this.overlays_, CollectionEventType.REMOVE,
this.overlays_.addEventListener(CollectionEventType.REMOVE,
/**
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
*/
@@ -447,7 +447,7 @@ class PluggableMap extends BaseObject {
delete this.overlayIdIndex_[id.toString()];
}
event.element.setMap(null);
}, this);
}.bind(this));
}
@@ -521,8 +521,8 @@ class PluggableMap extends BaseObject {
*/
disposeInternal() {
this.mapBrowserEventHandler_.dispose();
unlisten(this.viewport_, EventType.CONTEXTMENU, this.handleBrowserEvent, this);
unlisten(this.viewport_, EventType.WHEEL, this.handleBrowserEvent, this);
this.viewport_.removeEventListener(EventType.CONTEXTMENU, this.boundHandleBrowserEvent_);
this.viewport_.removeEventListener(EventType.WHEEL, this.boundHandleBrowserEvent_);
if (this.handleResize_ !== undefined) {
removeEventListener(EventType.RESIZE, this.handleResize_, false);
this.handleResize_ = undefined;

View File

@@ -2,7 +2,6 @@
* @module ol/TileQueue
*/
import TileState from './TileState.js';
import {listen, unlisten} from './events.js';
import EventType from './events/EventType.js';
import PriorityQueue from './structs/PriorityQueue.js';
@@ -36,6 +35,9 @@ class TileQueue extends PriorityQueue {
return (/** @type {import("./Tile.js").default} */ (element[0]).getKey());
});
/** @private */
this.boundHandleTileChange_ = this.handleTileChange.bind(this);
/**
* @private
* @type {function(): ?}
@@ -63,7 +65,7 @@ class TileQueue extends PriorityQueue {
const added = super.enqueue(element);
if (added) {
const tile = element[0];
listen(tile, EventType.CHANGE, this.handleTileChange, this);
tile.addEventListener(EventType.CHANGE, this.boundHandleTileChange_);
}
return added;
}
@@ -84,7 +86,7 @@ class TileQueue extends PriorityQueue {
const state = tile.getState();
if (tile.hifi && state === TileState.LOADED || state === TileState.ERROR ||
state === TileState.EMPTY || state === TileState.ABORT) {
unlisten(tile, EventType.CHANGE, this.handleTileChange, this);
tile.removeEventListener(EventType.CHANGE, this.boundHandleTileChange_);
const tileKey = tile.getKey();
if (tileKey in this.tilesLoadingKeys_) {
delete this.tilesLoadingKeys_[tileKey];

View File

@@ -5,7 +5,6 @@ import {equals} from '../array.js';
import Control from './Control.js';
import {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_COLLAPSED} from '../css.js';
import {removeChildren, replaceNode} from '../dom.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {inView} from '../layer/Layer.js';
@@ -125,7 +124,7 @@ class Attribution extends Control {
button.title = tipLabel;
button.appendChild(activeLabel);
listen(button, EventType.CLICK, this.handleClick_, this);
button.addEventListener(EventType.CLICK, this.handleClick_.bind(this), false);
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL +
(this.collapsed_ && this.collapsible_ ? ' ' + CLASS_COLLAPSED : '') +

View File

@@ -91,8 +91,7 @@ class FullScreen extends Control {
this.button_.title = tipLabel;
this.button_.appendChild(this.labelNode_);
listen(this.button_, EventType.CLICK,
this.handleClick_, this);
this.button_.addEventListener(EventType.CLICK, this.handleClick_.bind(this), false);
const cssClasses = this.cssClassName_ + ' ' + CLASS_UNSELECTABLE +
' ' + CLASS_CONTROL + ' ' +

View File

@@ -68,9 +68,7 @@ class MousePosition extends Control {
target: options.target
});
listen(this,
getChangeEventType(PROJECTION),
this.handleProjectionChanged_, this);
this.addEventListener(getChangeEventType(PROJECTION), this.handleProjectionChanged_);
if (options.coordinateFormat) {
this.setCoordinateFormat(options.coordinateFormat);

View File

@@ -14,7 +14,7 @@ import Control from './Control.js';
import {rotate as rotateCoordinate, add as addCoordinate} from '../coordinate.js';
import {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_COLLAPSED} from '../css.js';
import {replaceNode} from '../dom.js';
import {listen, listenOnce, unlisten} from '../events.js';
import {listen, listenOnce} from '../events.js';
import EventType from '../events/EventType.js';
import {containsExtent, getBottomLeft, getBottomRight, getTopLeft, getTopRight, scaleFromCenter} from '../extent.js';
@@ -84,6 +84,11 @@ class OverviewMap extends Control {
target: options.target
});
/**
* @private
*/
this.boundHandleRotationChanged_ = this.handleRotationChanged_.bind(this);
/**
* @type {boolean}
* @private
@@ -139,8 +144,7 @@ class OverviewMap extends Control {
button.title = tipLabel;
button.appendChild(activeLabel);
listen(button, EventType.CLICK,
this.handleClick_, this);
button.addEventListener(EventType.CLICK, this.handleClick_.bind(this), false);
/**
* @type {HTMLElement}
@@ -225,6 +229,7 @@ class OverviewMap extends Control {
window.addEventListener('mousemove', move);
window.addEventListener('mouseup', endMoving);
});
}
/**
@@ -284,9 +289,7 @@ class OverviewMap extends Control {
* @private
*/
bindView_(view) {
listen(view,
getChangeEventType(ViewProperty.ROTATION),
this.handleRotationChanged_, this);
view.addEventListener(getChangeEventType(ViewProperty.ROTATION), this.boundHandleRotationChanged_);
}
/**
@@ -295,9 +298,7 @@ class OverviewMap extends Control {
* @private
*/
unbindView_(view) {
unlisten(view,
getChangeEventType(ViewProperty.ROTATION),
this.handleRotationChanged_, this);
view.removeEventListener(getChangeEventType(ViewProperty.ROTATION), this.boundHandleRotationChanged_);
}
/**

View File

@@ -4,7 +4,6 @@
import Control from './Control.js';
import {CLASS_CONTROL, CLASS_HIDDEN, CLASS_UNSELECTABLE} from '../css.js';
import {easeOut} from '../easing.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
@@ -75,7 +74,7 @@ class Rotate extends Control {
button.title = tipLabel;
button.appendChild(this.label_);
listen(button, EventType.CLICK, this.handleClick_, this);
button.addEventListener(EventType.CLICK, this.handleClick_.bind(this), false);
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
const element = this.element;

View File

@@ -5,7 +5,6 @@ import {getChangeEventType} from '../Object.js';
import {assert} from '../asserts.js';
import Control from './Control.js';
import {CLASS_UNSELECTABLE} from '../css.js';
import {listen} from '../events.js';
import {getPointResolution, METERS_PER_UNIT} from '../proj.js';
import ProjUnits from '../proj/Units.js';
@@ -125,9 +124,7 @@ class ScaleLine extends Control {
*/
this.renderedHTML_ = '';
listen(
this, getChangeEventType(UNITS_PROP),
this.handleUnitsChanged_, this);
this.addEventListener(getChangeEventType(UNITS_PROP), this.handleUnitsChanged_);
this.setUnits(/** @type {Units} */ (options.units) || Units.METRIC);

View File

@@ -1,7 +1,6 @@
/**
* @module ol/control/Zoom
*/
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import Control from './Control.js';
import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';
@@ -66,7 +65,7 @@ class Zoom extends Control {
typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel
);
listen(inElement, EventType.CLICK, this.handleClick_.bind(this, delta));
inElement.addEventListener(EventType.CLICK, this.handleClick_.bind(this, delta), false);
const outElement = document.createElement('button');
outElement.className = className + '-out';
@@ -76,7 +75,7 @@ class Zoom extends Control {
typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel
);
listen(outElement, EventType.CLICK, this.handleClick_.bind(this, -delta));
outElement.addEventListener(EventType.CLICK, this.handleClick_.bind(this, -delta), false);
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
const element = this.element;

View File

@@ -139,15 +139,12 @@ class ZoomSlider extends Control {
containerElement.className = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
containerElement.appendChild(thumbElement);
listen(containerElement, PointerEventType.POINTERDOWN,
this.handleDraggerStart_, this);
listen(containerElement, PointerEventType.POINTERMOVE,
this.handleDraggerDrag_, this);
listen(containerElement, PointerEventType.POINTERUP,
this.handleDraggerEnd_, this);
containerElement.addEventListener(PointerEventType.POINTERDOWN, this.handleDraggerStart_.bind(this), false);
containerElement.addEventListener(PointerEventType.POINTERMOVE, this.handleDraggerDrag_.bind(this), false);
containerElement.addEventListener(PointerEventType.POINTERUP, this.handleDraggerEnd_.bind(this), false);
listen(containerElement, EventType.CLICK, this.handleContainerClick_, this);
listen(thumbElement, EventType.CLICK, stopPropagation);
containerElement.addEventListener(EventType.CLICK, this.handleContainerClick_.bind(this), false);
thumbElement.addEventListener(EventType.CLICK, stopPropagation, false);
}
/**

View File

@@ -1,7 +1,6 @@
/**
* @module ol/control/ZoomToExtent
*/
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import Control from './Control.js';
import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';
@@ -57,7 +56,7 @@ class ZoomToExtent extends Control {
typeof label === 'string' ? document.createTextNode(label) : label
);
listen(button, EventType.CLICK, this.handleClick_, this);
button.addEventListener(EventType.CLICK, this.handleClick_.bind(this), false);
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
const element = this.element;

View File

@@ -7,10 +7,6 @@ import {clear} from './obj.js';
/**
* Key to use with {@link module:ol/Observable~Observable#unByKey}.
* @typedef {Object} EventsKey
* @property {Object} [bindTo]
* @property {ListenerFunction} [boundListener]
* @property {boolean} callOnce
* @property {number} [deleteIndex]
* @property {ListenerFunction} listener
* @property {import("./events/Target.js").EventTargetLike} target
* @property {string} type
@@ -27,119 +23,6 @@ import {clear} from './obj.js';
*/
/**
* @param {EventsKey} listenerObj Listener object.
* @return {ListenerFunction} Bound listener.
*/
export function bindListener(listenerObj) {
let boundListener;
if (listenerObj.bindTo || listenerObj.callOnce) {
boundListener = function(evt) {
const listener = listenerObj.listener;
const bindTo = listenerObj.bindTo || listenerObj.target;
if (listenerObj.callOnce) {
unlistenByKey(listenerObj);
}
return listener.call(bindTo, evt);
};
} else {
boundListener = listenerObj.listener;
}
listenerObj.boundListener = boundListener;
return boundListener;
}
/**
* Finds the matching {@link module:ol/events~EventsKey} in the given listener
* array.
*
* @param {!Array<!EventsKey>} listeners Array of listeners.
* @param {!Function} listener The listener function.
* @param {Object=} opt_this The `this` value inside the listener.
* @param {boolean=} opt_setDeleteIndex Set the deleteIndex on the matching
* listener, for {@link module:ol/events~unlistenByKey}.
* @return {EventsKey|undefined} The matching listener object.
*/
export function findListener(listeners, listener, opt_this, opt_setDeleteIndex) {
let listenerObj;
for (let i = 0, ii = listeners.length; i < ii; ++i) {
listenerObj = listeners[i];
if (listenerObj.listener === listener &&
listenerObj.bindTo === opt_this) {
if (opt_setDeleteIndex) {
listenerObj.deleteIndex = i;
}
return listenerObj;
}
}
return undefined;
}
/**
* @param {import("./events/Target.js").EventTargetLike} target Target.
* @param {string} type Type.
* @return {Array<EventsKey>|undefined} Listeners.
*/
export function getListeners(target, type) {
const listenerMap = getListenerMap(target);
return listenerMap ? listenerMap[type] : undefined;
}
/**
* Get the lookup of listeners.
* @param {Object} target Target.
* @param {boolean=} opt_create If a map should be created if it doesn't exist.
* @return {!Object<string, Array<EventsKey>>} Map of
* listeners by event type.
*/
function getListenerMap(target, opt_create) {
let listenerMap = target.ol_lm;
if (!listenerMap && opt_create) {
listenerMap = target.ol_lm = {};
}
return listenerMap;
}
/**
* Remove the listener map from a target.
* @param {Object} target Target.
*/
function removeListenerMap(target) {
delete target.ol_lm;
}
/**
* Clean up all listener objects of the given type. All properties on the
* listener objects will be removed, and if no listeners remain in the listener
* map, it will be removed from the target.
* @param {import("./events/Target.js").EventTargetLike} target Target.
* @param {string} type Type.
*/
function removeListeners(target, type) {
const listeners = getListeners(target, type);
if (listeners) {
for (let i = 0, ii = listeners.length; i < ii; ++i) {
/** @type {import("./events/Target.js").default} */ (target).
removeEventListener(type, listeners[i].boundListener);
clear(listeners[i]);
}
listeners.length = 0;
const listenerMap = getListenerMap(target);
if (listenerMap) {
delete listenerMap[type];
if (Object.keys(listenerMap).length === 0) {
removeListenerMap(target);
}
}
}
}
/**
* Registers an event listener on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
@@ -156,31 +39,23 @@ function removeListeners(target, type) {
* @return {EventsKey} Unique key for the listener.
*/
export function listen(target, type, listener, opt_this, opt_once) {
const listenerMap = getListenerMap(target, true);
let listeners = listenerMap[type];
if (!listeners) {
listeners = listenerMap[type] = [];
if (opt_this && opt_this !== target) {
listener = listener.bind(opt_this);
}
let listenerObj = findListener(listeners, listener, opt_this, false);
if (listenerObj) {
if (!opt_once) {
// Turn one-off listener into a permanent one.
listenerObj.callOnce = false;
}
} else {
listenerObj = {
bindTo: opt_this,
callOnce: !!opt_once,
listener: listener,
target: target,
type: type
if (opt_once) {
const originalListener = listener;
listener = function() {
target.removeEventListener(type, listener);
originalListener.apply(this, arguments);
};
/** @type {import("./events/Target.js").default} */ (target).
addEventListener(type, bindListener(listenerObj));
listeners.push(listenerObj);
}
return listenerObj;
const eventsKey = {
target: target,
type: type,
listener: listener
};
target.addEventListener(type, listener);
return eventsKey;
}
@@ -209,30 +84,6 @@ export function listenOnce(target, type, listener, opt_this) {
}
/**
* Unregisters an event listener on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
*
* To return a listener, this function needs to be called with the exact same
* arguments that were used for a previous {@link module:ol/events~listen} call.
*
* @param {import("./events/Target.js").EventTargetLike} target Event target.
* @param {string} type Event type.
* @param {ListenerFunction} listener Listener.
* @param {Object=} opt_this Object referenced by the `this` keyword in the
* listener. Default is the `target`.
*/
export function unlisten(target, type, listener, opt_this) {
const listeners = getListeners(target, type);
if (listeners) {
const listenerObj = findListener(listeners, listener, opt_this, true);
if (listenerObj) {
unlistenByKey(listenerObj);
}
}
}
/**
* Unregisters event listeners on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
@@ -244,34 +95,7 @@ export function unlisten(target, type, listener, opt_this) {
*/
export function unlistenByKey(key) {
if (key && key.target) {
/** @type {import("./events/Target.js").default} */ (key.target).
removeEventListener(key.type, key.boundListener);
const listeners = getListeners(key.target, key.type);
if (listeners) {
const i = 'deleteIndex' in key ? key.deleteIndex : listeners.indexOf(key);
if (i !== -1) {
listeners.splice(i, 1);
}
if (listeners.length === 0) {
removeListeners(key.target, key.type);
}
}
key.target.removeEventListener(key.type, key.listener);
clear(key);
}
}
/**
* Unregisters all event listeners on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
*
* @param {import("./events/Target.js").EventTargetLike} target Target.
*/
export function unlistenAll(target) {
const listenerMap = getListenerMap(target);
if (listenerMap) {
for (const type in listenerMap) {
removeListeners(target, type);
}
}
}

View File

@@ -12,7 +12,7 @@
* for higher level events defined in the library, and works with
* {@link module:ol/events/Target~Target}.
*/
class Event {
class BaseEvent {
/**
* @param {string} type Type.
@@ -73,4 +73,4 @@ export function preventDefault(evt) {
evt.preventDefault();
}
export default Event;
export default BaseEvent;

View File

@@ -2,9 +2,9 @@
* @module ol/events/Target
*/
import Disposable from '../Disposable.js';
import {unlistenAll} from '../events.js';
import {VOID} from '../functions.js';
import Event from './Event.js';
import {clear} from '../obj.js';
/**
@@ -116,7 +116,7 @@ class Target extends Disposable {
* @inheritDoc
*/
disposeInternal() {
unlistenAll(this);
clear(this.listeners_);
}
/**

View File

@@ -1,7 +1,7 @@
/**
* @module ol/geom/GeometryCollection
*/
import {listen, unlisten} from '../events.js';
import {listen, unlistenByKey} from '../events.js';
import EventType from '../events/EventType.js';
import {createOrUpdateEmpty, closestSquaredDistanceXY, extend, getCenter} from '../extent.js';
import Geometry from './Geometry.js';
@@ -29,6 +29,11 @@ class GeometryCollection extends Geometry {
*/
this.geometries_ = opt_geometries ? opt_geometries : null;
/**
* @type {Array<import("../events.js").EventsKey>}
*/
this.changeEventsKeys_ = [];
this.listenGeometriesChange_();
}
@@ -36,14 +41,8 @@ class GeometryCollection extends Geometry {
* @private
*/
unlistenGeometriesChange_() {
if (!this.geometries_) {
return;
}
for (let i = 0, ii = this.geometries_.length; i < ii; ++i) {
unlisten(
this.geometries_[i], EventType.CHANGE,
this.changed, this);
}
this.changeEventsKeys_.forEach(unlistenByKey);
this.changeEventsKeys_.length = 0;
}
/**
@@ -54,9 +53,9 @@ class GeometryCollection extends Geometry {
return;
}
for (let i = 0, ii = this.geometries_.length; i < ii; ++i) {
listen(
this.changeEventsKeys_.push(listen(
this.geometries_[i], EventType.CHANGE,
this.changed, this);
this.changed, this));
}
}

View File

@@ -188,12 +188,13 @@ class DragAndDrop extends Interaction {
* @inheritDoc
*/
setActive(active) {
super.setActive(active);
if (active) {
if (!this.getActive() && active) {
this.registerListeners_();
} else {
}
if (this.getActive() && !active) {
this.unregisterListeners_();
}
super.setActive(active);
}
/**

View File

@@ -7,7 +7,6 @@ import MapBrowserEventType from '../MapBrowserEventType.js';
import MapBrowserPointerEvent from '../MapBrowserPointerEvent.js';
import {getChangeEventType} from '../Object.js';
import {squaredDistance as squaredCoordinateDistance} from '../coordinate.js';
import {listen} from '../events.js';
import Event from '../events/Event.js';
import {noModifierKeys, always, shiftKeyOnly} from '../events/condition.js';
import {boundingExtent, getBottomLeft, getBottomRight, getTopLeft, getTopRight} from '../extent.js';
@@ -448,9 +447,7 @@ class Draw extends PointerInteraction {
options.freehandCondition : shiftKeyOnly;
}
listen(this,
getChangeEventType(InteractionProperty.ACTIVE),
this.updateState_, this);
this.addEventListener(getChangeEventType(InteractionProperty.ACTIVE), this.updateState_);
}

View File

@@ -8,7 +8,6 @@ import Feature from '../Feature.js';
import MapBrowserEventType from '../MapBrowserEventType.js';
import {equals} from '../array.js';
import {equals as coordinatesEqual, distance as coordinateDistance, squaredDistance as squaredCoordinateDistance, squaredDistanceToSegment, closestOnSegment} from '../coordinate.js';
import {listen, unlisten} from '../events.js';
import Event from '../events/Event.js';
import EventType from '../events/EventType.js';
import {always, primaryAction, altKeyOnly, singleClick} from '../events/condition.js';
@@ -158,6 +157,9 @@ class Modify extends PointerInteraction {
super(/** @type {import("./Pointer.js").Options} */ (options));
/** @private */
this.boundHandleFeatureChange_ = this.handleFeatureChange_.bind(this);
/**
* @private
* @type {import("../events/condition.js").Condition}
@@ -299,10 +301,8 @@ class Modify extends PointerInteraction {
if (options.source) {
this.source_ = options.source;
features = new Collection(this.source_.getFeatures());
listen(this.source_, VectorEventType.ADDFEATURE,
this.handleSourceAdd_, this);
listen(this.source_, VectorEventType.REMOVEFEATURE,
this.handleSourceRemove_, this);
this.source_.addEventListener(VectorEventType.ADDFEATURE, this.handleSourceAdd_.bind(this));
this.source_.addEventListener(VectorEventType.REMOVEFEATURE, this.handleSourceRemove_.bind(this));
} else {
features = options.features;
}
@@ -317,10 +317,8 @@ class Modify extends PointerInteraction {
this.features_ = features;
this.features_.forEach(this.addFeature_.bind(this));
listen(this.features_, CollectionEventType.ADD,
this.handleFeatureAdd_, this);
listen(this.features_, CollectionEventType.REMOVE,
this.handleFeatureRemove_, this);
this.features_.addEventListener(CollectionEventType.ADD, this.handleFeatureAdd_.bind(this));
this.features_.addEventListener(CollectionEventType.REMOVE, this.handleFeatureRemove_.bind(this));
/**
* @type {import("../MapBrowserPointerEvent.js").default}
@@ -343,8 +341,7 @@ class Modify extends PointerInteraction {
if (map && map.isRendered() && this.getActive()) {
this.handlePointerAtPixel_(this.lastPixel_, map);
}
listen(feature, EventType.CHANGE,
this.handleFeatureChange_, this);
feature.addEventListener(EventType.CHANGE, this.boundHandleFeatureChange_);
}
/**
@@ -371,8 +368,7 @@ class Modify extends PointerInteraction {
this.overlay_.getSource().removeFeature(this.vertexFeature_);
this.vertexFeature_ = null;
}
unlisten(feature, EventType.CHANGE,
this.handleFeatureChange_, this);
feature.removeEventListener(EventType.CHANGE, this.boundHandleFeatureChange_);
}
/**

View File

@@ -4,7 +4,6 @@
import {getUid} from '../util.js';
import CollectionEventType from '../CollectionEventType.js';
import {extend, includes} from '../array.js';
import {listen} from '../events.js';
import Event from '../events/Event.js';
import {singleClick, never, shiftKeyOnly, pointerMove} from '../events/condition.js';
import {TRUE} from '../functions.js';
@@ -254,10 +253,8 @@ class Select extends Interaction {
this.featureLayerAssociation_ = {};
const features = this.getFeatures();
listen(features, CollectionEventType.ADD,
this.addFeature_, this);
listen(features, CollectionEventType.REMOVE,
this.removeFeature_, this);
features.addEventListener(CollectionEventType.ADD, this.addFeature_.bind(this));
features.addEventListener(CollectionEventType.REMOVE, this.removeFeature_.bind(this));
}
/**

View File

@@ -3,7 +3,6 @@
*/
import Collection from '../Collection.js';
import {getChangeEventType} from '../Object.js';
import {listen} from '../events.js';
import Event from '../events/Event.js';
import {TRUE} from '../functions.js';
import {includes} from '../array.js';
@@ -165,9 +164,7 @@ class Translate extends PointerInteraction {
*/
this.lastFeature_ = null;
listen(this,
getChangeEventType(InteractionProperty.ACTIVE),
this.handleActiveChanged_, this);
this.addEventListener(getChangeEventType(InteractionProperty.ACTIVE), this.handleActiveChanged_);
}

View File

@@ -80,9 +80,7 @@ class LayerGroup extends BaseLayer {
*/
this.listenerKeys_ = {};
listen(this,
getChangeEventType(Property.LAYERS),
this.handleLayersChanged_, this);
this.addEventListener(getChangeEventType(Property.LAYERS), this.handleLayersChanged_);
if (layers) {
if (Array.isArray(layers)) {

View File

@@ -1,7 +1,6 @@
/**
* @module ol/layer/Heatmap
*/
import {listen} from '../events.js';
import {getChangeEventType} from '../Object.js';
import {createCanvasContext2D} from '../dom.js';
import VectorLayer from './Vector.js';
@@ -83,9 +82,7 @@ class Heatmap extends VectorLayer {
*/
this.gradient_ = null;
listen(this,
getChangeEventType(Property.GRADIENT),
this.handleGradientChanged_, this);
this.addEventListener(getChangeEventType(Property.GRADIENT), this.handleGradientChanged_);
this.setGradient(options.gradient ? options.gradient : DEFAULT_GRADIENT);

View File

@@ -121,9 +121,7 @@ class Layer extends BaseLayer {
this.setMap(options.map);
}
listen(this,
getChangeEventType(LayerProperty.SOURCE),
this.handleSourcePropertyChange_, this);
this.addEventListener(getChangeEventType(LayerProperty.SOURCE), this.handleSourcePropertyChange_);
const source = options.source ? /** @type {SourceType} */ (options.source) : null;
this.setSource(source);

View File

@@ -4,7 +4,6 @@
import {abstract} from '../util.js';
import ImageState from '../ImageState.js';
import Observable from '../Observable.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import SourceState from '../source/State.js';
@@ -17,6 +16,9 @@ class LayerRenderer extends Observable {
super();
/** @private */
this.boundHandleImageChange_ = this.handleImageChange_.bind(this);
/**
* @private
* @type {import("../layer/Layer.js").default}
@@ -142,7 +144,7 @@ class LayerRenderer extends Observable {
loadImage(image) {
let imageState = image.getState();
if (imageState != ImageState.LOADED && imageState != ImageState.ERROR) {
listen(image, EventType.CHANGE, this.handleImageChange_, this);
image.addEventListener(EventType.CHANGE, this.boundHandleImageChange_);
}
if (imageState == ImageState.IDLE) {
image.load();

View File

@@ -8,7 +8,6 @@ import {getHeight, getWidth, isEmpty, scaleFromCenter} from '../../extent.js';
import {assign} from '../../obj.js';
import CanvasImageLayerRenderer from './ImageLayer.js';
import CanvasVectorLayerRenderer from './VectorLayer.js';
import {listen} from '../../events.js';
import EventType from '../../events/EventType.js';
import ImageState from '../../ImageState.js';
import {renderDeclutterItems} from '../../render.js';
@@ -102,12 +101,12 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
}
});
listen(image, EventType.CHANGE, function() {
image.addEventListener(EventType.CHANGE, function() {
if (image.getState() === ImageState.LOADED) {
this.image_ = image;
this.skippedFeatures_ = skippedFeatures;
}
}, this);
}.bind(this));
image.load();
}

View File

@@ -24,6 +24,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
super(vectorLayer);
/** @private */
this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this);
/**
* @private
* @type {boolean}
@@ -366,12 +370,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
for (let i = 0, ii = styles.length; i < ii; ++i) {
loading = renderFeature(
builderGroup, feature, styles[i], squaredTolerance,
this.handleStyleImageChange_, this) || loading;
this.boundHandleStyleImageChange_) || loading;
}
} else {
loading = renderFeature(
builderGroup, feature, styles, squaredTolerance,
this.handleStyleImageChange_, this);
this.boundHandleStyleImageChange_);
}
return loading;
}

View File

@@ -59,6 +59,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
constructor(layer) {
super(layer);
/** @private */
this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this);
/**
* @private
* @type {CanvasRenderingContext2D}
@@ -112,7 +115,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
* @type {import("../../transform.js").Transform}
*/
this.tmpTransform_ = createTransform();
}
/**
@@ -546,12 +548,12 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
for (let i = 0, ii = styles.length; i < ii; ++i) {
loading = renderFeature(
executorGroup, feature, styles[i], squaredTolerance,
this.handleStyleImageChange_, this) || loading;
this.boundHandleStyleImageChange_) || loading;
}
} else {
loading = renderFeature(
executorGroup, feature, styles, squaredTolerance,
this.handleStyleImageChange_, this);
this.boundHandleStyleImageChange_);
}
return loading;
}

View File

@@ -91,24 +91,23 @@ function renderCircleGeometry(builderGroup, geometry, style, feature) {
* @param {import("../Feature.js").FeatureLike} feature Feature.
* @param {import("../style/Style.js").default} style Style.
* @param {number} squaredTolerance Squared tolerance.
* @param {function(this: T, import("../events/Event.js").default): void} listener Listener function.
* @param {T} thisArg Value to use as `this` when executing `listener`.
* @param {function(import("../events/Event.js").default): void} listener Listener function.
* @return {boolean} `true` if style is loading.
* @template T
*/
export function renderFeature(replayGroup, feature, style, squaredTolerance, listener, thisArg) {
export function renderFeature(replayGroup, feature, style, squaredTolerance, listener) {
let loading = false;
const imageStyle = style.getImage();
if (imageStyle) {
let imageState = imageStyle.getImageState();
if (imageState == ImageState.LOADED || imageState == ImageState.ERROR) {
imageStyle.unlistenImageChange(listener, thisArg);
imageStyle.unlistenImageChange(listener);
} else {
if (imageState == ImageState.IDLE) {
imageStyle.load();
}
imageState = imageStyle.getImageState();
imageStyle.listenImageChange(listener, thisArg);
imageStyle.listenImageChange(listener);
loading = true;
}
}

View File

@@ -7,7 +7,6 @@ import {assert} from '../asserts.js';
import Feature from '../Feature.js';
import GeometryType from '../geom/GeometryType.js';
import {scale as scaleCoordinate, add as addCoordinate} from '../coordinate.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {buffer, createEmpty, createOrUpdateFromCoordinate} from '../extent.js';
import Point from '../geom/Point.js';
@@ -88,7 +87,7 @@ class Cluster extends VectorSource {
*/
this.source = options.source;
listen(this.source, EventType.CHANGE, this.refresh, this);
this.source.addEventListener(EventType.CHANGE, this.refresh.bind(this));
}
/**

View File

@@ -4,7 +4,6 @@
import ImageWrapper from '../Image.js';
import {assert} from '../asserts.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {containsExtent, getHeight, getWidth} from '../extent.js';
import {assign} from '../obj.js';
@@ -197,8 +196,7 @@ class ImageArcGISRest extends ImageSource {
this.renderedRevision_ = this.getRevision();
listen(this.image_, EventType.CHANGE,
this.handleImageChange, this);
this.image_.addEventListener(EventType.CHANGE, this.handleImageChange.bind(this));
return this.image_;

View File

@@ -3,7 +3,6 @@
*/
import ImageWrapper from '../Image.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {containsExtent, getCenter, getHeight, getWidth, scaleFromCenter} from '../extent.js';
import {assign} from '../obj.js';
@@ -162,8 +161,7 @@ class ImageMapGuide extends ImageSource {
image = new ImageWrapper(extent, resolution, pixelRatio,
imageUrl, this.crossOrigin_,
this.imageLoadFunction_);
listen(image, EventType.CHANGE,
this.handleImageChange, this);
image.addEventListener(EventType.CHANGE, this.handleImageChange.bind(this));
} else {
image = null;
}

View File

@@ -5,7 +5,6 @@
import ImageWrapper from '../Image.js';
import ImageState from '../ImageState.js';
import {createCanvasContext2D} from '../dom.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {intersects, getHeight, getWidth} from '../extent.js';
import {get as getProjection} from '../proj.js';
@@ -73,8 +72,7 @@ class Static extends ImageSource {
*/
this.imageSize_ = options.imageSize ? options.imageSize : null;
listen(this.image_, EventType.CHANGE,
this.handleImageChange, this);
this.image_.addEventListener(EventType.CHANGE, this.handleImageChange.bind(this));
}

View File

@@ -6,7 +6,6 @@ import {DEFAULT_WMS_VERSION} from './common.js';
import ImageWrapper from '../Image.js';
import {assert} from '../asserts.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {containsExtent, getCenter, getForViewAndSize, getHeight, getWidth} from '../extent.js';
import {assign} from '../obj.js';
@@ -296,8 +295,7 @@ class ImageWMS extends ImageSource {
this.renderedRevision_ = this.getRevision();
listen(this.image_, EventType.CHANGE,
this.handleImageChange, this);
this.image_.addEventListener(EventType.CHANGE, this.handleImageChange.bind(this));
return this.image_;

View File

@@ -4,7 +4,6 @@
import ImageCanvas from '../ImageCanvas.js';
import TileQueue from '../TileQueue.js';
import {createCanvasContext2D} from '../dom.js';
import {listen} from '../events.js';
import Event from '../events/Event.js';
import EventType from '../events/EventType.js';
import {Processor} from 'pixelworks/lib/index.js';
@@ -172,8 +171,9 @@ class RasterSource extends ImageSource {
*/
this.layers_ = createLayers(options.sources);
const changed = this.changed.bind(this);
for (let i = 0, ii = this.layers_.length; i < ii; ++i) {
listen(this.layers_[i], EventType.CHANGE, this.changed, this);
this.layers_[i].addEventListener(EventType.CHANGE, changed);
}
/**

View File

@@ -6,7 +6,6 @@ import {getUid} from '../util.js';
import ImageTile from '../ImageTile.js';
import TileCache from '../TileCache.js';
import TileState from '../TileState.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {equivalent, get as getProjection} from '../proj.js';
import ReprojTile from '../reproj/Tile.js';
@@ -261,8 +260,7 @@ class TileImage extends UrlTile {
this.tileLoadFunction,
this.tileOptions);
tile.key = key;
listen(tile, EventType.CHANGE,
this.handleTileChange, this);
tile.addEventListener(EventType.CHANGE, this.handleTileChange.bind(this));
return tile;
}

View File

@@ -428,7 +428,7 @@ class VectorSource extends Source {
*/
bindFeaturesCollection_(collection) {
let modifyingCollection = false;
listen(this, VectorEventType.ADDFEATURE,
this.addEventListener(VectorEventType.ADDFEATURE,
/**
* @param {VectorSourceEvent<Geometry>} evt The vector source event
*/
@@ -439,7 +439,7 @@ class VectorSource extends Source {
modifyingCollection = false;
}
});
listen(this, VectorEventType.REMOVEFEATURE,
this.addEventListener(VectorEventType.REMOVEFEATURE,
/**
* @param {VectorSourceEvent<Geometry>} evt The vector source event
*/
@@ -450,7 +450,7 @@ class VectorSource extends Source {
modifyingCollection = false;
}
});
listen(collection, CollectionEventType.ADD,
collection.addEventListener(CollectionEventType.ADD,
/**
* @param {import("../Collection.js").CollectionEvent} evt The collection event
*/
@@ -460,8 +460,8 @@ class VectorSource extends Source {
this.addFeature(/** @type {import("../Feature.js").default<Geometry>} */ (evt.element));
modifyingCollection = false;
}
}, this);
listen(collection, CollectionEventType.REMOVE,
}.bind(this));
collection.addEventListener(CollectionEventType.REMOVE,
/**
* @param {import("../Collection.js").CollectionEvent} evt The collection event
*/
@@ -471,7 +471,7 @@ class VectorSource extends Source {
this.removeFeature(/** @type {import("../Feature.js").default<Geometry>} */ (evt.element));
modifyingCollection = false;
}
}, this);
}.bind(this));
this.featuresCollection_ = collection;
}

View File

@@ -234,7 +234,7 @@ class VectorTile extends UrlTile {
sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
this.sourceTileByCoordKey_[coordKey] = sourceTile;
empty = false;
listen(sourceTile, EventType.CHANGE, this.handleTileChange, this);
sourceTile.addEventListener(EventType.CHANGE, this.handleTileChange.bind(this));
sourceTile.load();
}
} else {

View File

@@ -5,7 +5,6 @@ import {getUid} from '../util.js';
import ImageState from '../ImageState.js';
import {assert} from '../asserts.js';
import {asArray} from '../color.js';
import {listen, unlisten} from '../events.js';
import EventType from '../events/EventType.js';
import IconAnchorUnits from './IconAnchorUnits.js';
import {get as getIconImage} from './IconImage.js';
@@ -378,9 +377,8 @@ class Icon extends ImageStyle {
/**
* @override
*/
listenImageChange(listener, thisArg) {
return listen(this.iconImage_, EventType.CHANGE,
listener, thisArg);
listenImageChange(listener) {
this.iconImage_.addEventListener(EventType.CHANGE, listener);
}
/**
@@ -398,9 +396,8 @@ class Icon extends ImageStyle {
/**
* @override
*/
unlistenImageChange(listener, thisArg) {
unlisten(this.iconImage_, EventType.CHANGE,
listener, thisArg);
unlistenImageChange(listener) {
this.iconImage_.removeEventListener(EventType.CHANGE, listener);
}
}

View File

@@ -215,13 +215,11 @@ class ImageStyle {
/**
* @abstract
* @param {function(this: T, import("../events/Event.js").default): void} listener Listener function.
* @param {T} thisArg Value to use as `this` when executing `listener`.
* @return {import("../events.js").EventsKey|undefined} Listener key.
* @param {function(import("../events/Event.js").default): void} listener Listener function.
* @template T
*/
listenImageChange(listener, thisArg) {
return abstract();
listenImageChange(listener) {
abstract();
}
/**
@@ -234,11 +232,10 @@ class ImageStyle {
/**
* @abstract
* @param {function(this: T, import("../events/Event.js").default): void} listener Listener function.
* @param {T} thisArg Value to use as `this` when executing `listener`.
* @param {function(import("../events/Event.js").default): void} listener Listener function.
* @template T
*/
unlistenImageChange(listener, thisArg) {
unlistenImageChange(listener) {
abstract();
}
}

View File

@@ -284,9 +284,7 @@ class RegularShape extends ImageStyle {
/**
* @inheritDoc
*/
listenImageChange(listener, thisArg) {
return undefined;
}
listenImageChange(listener) {}
/**
* @inheritDoc
@@ -296,7 +294,7 @@ class RegularShape extends ImageStyle {
/**
* @inheritDoc
*/
unlistenImageChange(listener, thisArg) {}
unlistenImageChange(listener) {}
/**
* @protected

View File

@@ -3,7 +3,6 @@
*/
import {getUid} from '../util.js';
import Disposable from '../Disposable.js';
import {listen, unlistenAll} from '../events.js';
import {clear} from '../obj.js';
import ContextEventType from '../webgl/ContextEventType.js';
import {
@@ -218,6 +217,12 @@ class WebGLHelper extends Disposable {
super();
const options = opt_options || {};
/** @private */
this.boundHandleWebGLContextLost_ = this.handleWebGLContextLost.bind(this);
/** @private */
this.boundHandleWebGLContextRestored_ = this.handleWebGLContextRestored.bind(this);
/**
* @private
* @type {HTMLCanvasElement}
@@ -260,10 +265,8 @@ class WebGLHelper extends Disposable {
assert(includes(getSupportedExtensions(), 'OES_element_index_uint'), 63);
gl.getExtension('OES_element_index_uint');
listen(this.canvas_, ContextEventType.LOST,
this.handleWebGLContextLost, this);
listen(this.canvas_, ContextEventType.RESTORED,
this.handleWebGLContextRestored, this);
this.canvas_.addEventListener(ContextEventType.LOST, this.boundHandleWebGLContextLost_);
this.canvas_.addEventListener(ContextEventType.RESTORED, this.boundHandleWebGLContextRestored_);
/**
* @private
@@ -385,7 +388,8 @@ class WebGLHelper extends Disposable {
* @inheritDoc
*/
disposeInternal() {
unlistenAll(this.canvas_);
this.canvas_.removeEventListener(ContextEventType.LOST, this.boundHandleWebGLContextLost_);
this.canvas_.removeEventListener(ContextEventType.RESTORED, this.boundHandleWebGLContextRestored_);
const gl = this.getGL();
if (!gl.isContextLost()) {
for (const key in this.bufferCache_) {

View File

@@ -1,98 +1,18 @@
import {listen, listenOnce, bindListener, unlisten, unlistenAll, unlistenByKey, findListener, getListeners} from '../../../src/ol/events.js';
import {listen, listenOnce, unlistenByKey} from '../../../src/ol/events.js';
import EventTarget from '../../../src/ol/events/Target.js';
describe('ol.events', function() {
let add, remove, target;
let add, target;
beforeEach(function() {
add = sinon.spy();
remove = sinon.spy();
target = {
addEventListener: add,
removeEventListener: remove
};
target = new EventTarget();
add = sinon.spy(target, 'addEventListener');
});
describe('bindListener()', function() {
it('binds a listener and returns a bound listener function', function() {
const listenerObj = {
listener: sinon.spy(),
bindTo: {id: 1}
};
const boundListener = bindListener(listenerObj);
expect(listenerObj.boundListener).to.equal(boundListener);
boundListener();
expect(listenerObj.listener.thisValues[0]).to.equal(listenerObj.bindTo);
});
it('binds to the target when bindTo is not provided', function(done) {
const target = new EventTarget();
const listenerObj = listen(target, 'foo', function() {
expect(this).to.equal(target);
done();
});
expect(listenerObj.boundListener).to.equal(listenerObj.listener);
target.dispatchEvent('foo');
});
it('binds a self-unregistering listener when callOnce is true', function() {
const bindTo = {id: 1};
const listenerObj = {
type: 'foo',
target: target,
bindTo: bindTo,
callOnce: true
};
listenerObj.listener = function() {
expect(this).to.equal(bindTo);
};
const boundListener = bindListener(listenerObj);
expect(listenerObj.boundListener).to.equal(boundListener);
boundListener();
});
afterEach(function() {
target.addEventListener.restore();
});
describe('findListener()', function() {
let listener, listenerObj, listeners;
beforeEach(function() {
listener = function() {};
listenerObj = {
type: 'foo',
target: target,
listener: listener
};
listeners = [listenerObj];
});
it('searches a listener array for a specific listener', function() {
const bindTo = {id: 1};
let result = findListener(listeners, listener);
expect(result).to.be(listenerObj);
result = findListener(listeners, listener, bindTo);
expect(result).to.be(undefined);
listenerObj.bindTo = bindTo;
result = findListener(listeners, listener);
expect(result).to.be(undefined);
result = findListener(listeners, listener, bindTo);
expect(result).to.be(listenerObj);
});
it('marks the delete index on a listener object', function() {
const result = findListener(listeners, listener, undefined, true);
expect(result).to.be(listenerObj);
expect(listenerObj.deleteIndex).to.be(0);
});
});
describe('getListeners()', function() {
it('returns listeners for a target and type', function() {
const foo = listen(target, 'foo', function() {});
const bar = listen(target, 'bar', function() {});
expect (getListeners(target, 'foo')).to.eql([foo]);
expect (getListeners(target, 'bar')).to.eql([bar]);
});
it('returns undefined when no listeners are registered', function() {
expect (getListeners(target, 'foo')).to.be(undefined);
});
});
describe('listen()', function() {
it('calls addEventListener on the target', function() {
@@ -105,17 +25,16 @@ describe('ol.events', function() {
});
it('does not add the same listener twice', function() {
const listener = function() {};
const key1 = listen(target, 'foo', listener);
const key2 = listen(target, 'foo', listener);
expect(key1).to.equal(key2);
expect(add.callCount).to.be(1);
listen(target, 'foo', listener);
listen(target, 'foo', listener);
expect(target.listeners_['foo'].length).to.be(1);
});
it('only treats listeners as same when all args are equal', function() {
const listener = function() {};
listen(target, 'foo', listener, {});
listen(target, 'foo', listener, {});
listen(target, 'foo', listener, undefined);
expect(add.callCount).to.be(3);
expect(target.listeners_['foo'].length).to.be(3);
});
});
@@ -123,95 +42,56 @@ describe('ol.events', function() {
it('creates a one-off listener', function() {
const target = new EventTarget();
const listener = sinon.spy();
const key = listenOnce(target, 'foo', listener);
expect(key.callOnce).to.be(true);
listenOnce(target, 'foo', listener);
target.dispatchEvent('foo');
expect(listener.callCount).to.be(1);
target.dispatchEvent('foo');
expect(listener.callCount).to.be(1);
});
it('does not add the same listener twice', function() {
const listener = function() {};
const key1 = listenOnce(target, 'foo', listener);
const key2 = listenOnce(target, 'foo', listener);
expect(key1).to.equal(key2);
expect(add.callCount).to.be(1);
expect(key1.callOnce).to.be(true);
});
it('listen() can turn a one-off listener into a permanent one', function() {
it('Adds the same listener twice', function() {
const listener = sinon.spy();
let key = listenOnce(target, 'foo', listener);
expect(key.callOnce).to.be(true);
key = listen(target, 'foo', listener);
expect(add.callCount).to.be(1);
expect(key.callOnce).to.be(false);
key.boundListener();
expect(remove.callCount).to.be(0);
listenOnce(target, 'foo', listener);
listenOnce(target, 'foo', listener);
target.dispatchEvent('foo');
target.dispatchEvent('foo');
target.dispatchEvent('foo');
expect(listener.callCount).to.be(2);
});
});
describe('unlisten()', function() {
it('unregisters previously registered listeners', function() {
const listener = function() {};
listen(target, 'foo', listener);
unlisten(target, 'foo', listener);
expect(getListeners(target, 'foo')).to.be(undefined);
});
it('works with multiple types', function() {
const listener = function() {};
listen(target, ['foo', 'bar'], listener);
unlisten(target, ['bar', 'foo'], listener);
expect(getListeners(target, 'foo')).to.be(undefined);
expect(getListeners(target, 'bar')).to.be(undefined);
});
});
describe('unlistenByKey()', function() {
it('unregisters previously registered listeners', function() {
const key = listen(target, 'foo', function() {});
unlistenByKey(key);
expect(getListeners(target, 'foo')).to.be(undefined);
expect(target.listeners_['foo']).to.be(undefined);
});
it('works with multiple types', function() {
const key = listen(target, ['foo', 'bar'], function() {});
unlistenByKey(key);
expect(getListeners(target, 'foo')).to.be(undefined);
expect(getListeners(target, 'bar')).to.be(undefined);
expect(target.listeners_['foo']).to.be(undefined);
expect(target.listeners_['bar']).to.be(undefined);
});
});
describe('unlistenAll()', function() {
it('unregisters all listeners registered for a target', function() {
const keys = [
listen(target, 'foo', function() {}),
listen(target, 'bar', function() {})
];
unlistenAll(target);
expect(getListeners(target, 'foo')).to.be(undefined);
expect(getListeners(target, 'bar')).to.be(undefined);
expect('ol_lm' in target).to.be(false);
expect(keys).to.eql([{}, {}]);
});
});
describe('Compatibility with ol.events.EventTarget', function() {
describe('Listener keys', function() {
it('does not register duplicated listeners', function() {
const target = new EventTarget();
const listener = function() {};
const key1 = listen(target, 'foo', listener);
expect(target.getListeners('foo')).to.eql([key1.boundListener]);
expect(target.listeners_['foo']).to.eql([listener]);
const key2 = listen(target, 'foo', listener);
expect(key2.boundListener).to.equal(key1.boundListener);
expect(target.getListeners('foo')).to.eql([key1.boundListener]);
expect(target.listeners_['foo']).to.eql([listener]);
expect(key1.listener).to.equal(key2.listener);
});
it('registers multiple listeners if this object is different', function() {
const target = new EventTarget();
const listener = function() {};
const key1 = listen(target, 'foo', listener, {});
const key2 = listen(target, 'foo', listener, {});
expect(key1.boundListener).to.not.equal(key2.boundListener);
expect(target.getListeners('foo')).to.eql(
[key1.boundListener, key2.boundListener]);
expect(key1.listener).to.not.equal(key2.listener);
expect(target.listeners_['foo']).to.eql([key1.listener, key2.listener]);
});
});

View File

@@ -43,16 +43,6 @@ describe('ol.events.EventTarget', function() {
});
});
describe('#getListeners', function() {
it('returns listeners for a type or undefined if none', function() {
expect(eventTarget.getListeners('foo')).to.be(undefined);
const listeners = [function() {}];
eventTarget.listeners_['foo'] = listeners;
expect(eventTarget.getListeners('foo')).to.equal(listeners);
});
});
describe('#addEventListener()', function() {
it('has listeners for each registered type', function() {
eventTarget.addEventListener('foo', spy1);
@@ -72,7 +62,7 @@ describe('ol.events.EventTarget', function() {
eventTarget.addEventListener('foo', spy1);
eventTarget.addEventListener('foo', spy2);
eventTarget.removeEventListener('foo', spy1, false);
expect(eventTarget.getListeners('foo')).to.have.length(1);
expect(eventTarget.listeners_['foo']).to.have.length(1);
});
});
@@ -131,7 +121,7 @@ describe('ol.events.EventTarget', function() {
eventTarget.dispatchEvent('foo');
}).not.to.throwException();
expect(called).to.eql([3]);
expect(eventTarget.getListeners('foo')).to.have.length(1);
expect(eventTarget.listeners_['foo']).to.have.length(1);
});
it('is safe to do weird things in listeners', function() {
eventTarget.addEventListener('foo', spy2);
@@ -148,7 +138,7 @@ describe('ol.events.EventTarget', function() {
eventTarget.dispatchEvent('foo');
}).not.to.throwException();
expect(called).to.eql([2, 2]);
expect(eventTarget.getListeners('foo')).to.be(undefined);
expect(eventTarget.listeners_['foo']).to.be(undefined);
});
});

View File

@@ -3,7 +3,6 @@ import Feature from '../../../../src/ol/Feature.js';
import Map from '../../../../src/ol/Map.js';
import MapBrowserPointerEvent from '../../../../src/ol/MapBrowserPointerEvent.js';
import View from '../../../../src/ol/View.js';
import {getListeners} from '../../../../src/ol/events.js';
import {doubleClick} from '../../../../src/ol/events/condition.js';
import Circle from '../../../../src/ol/geom/Circle.js';
import LineString from '../../../../src/ol/geom/LineString.js';
@@ -13,6 +12,7 @@ import Modify, {ModifyEvent} from '../../../../src/ol/interaction/Modify.js';
import VectorLayer from '../../../../src/ol/layer/Vector.js';
import VectorSource from '../../../../src/ol/source/Vector.js';
import Event from '../../../../src/ol/events/Event.js';
import {getValues} from '../../../../src/ol/obj.js';
describe('ol.interaction.Modify', function() {
@@ -607,10 +607,10 @@ describe('ol.interaction.Modify', function() {
beforeEach(function() {
getModifyListeners = function(feature, modify) {
const listeners = getListeners(
feature, 'change');
const listeners = feature.listeners_['change'];
const candidates = getValues(modify);
return listeners.filter(function(listener) {
return listener.bindTo === modify;
return candidates.indexOf(listener) !== -1;
});
};
});

View File

@@ -130,7 +130,7 @@ describe('ol.interaction.MouseWheelZoom', function() {
map.handleMapBrowserEvent(event);
});
it.only('works on all browsers (wheel)', function(done) {
it('works on all browsers (wheel)', function(done) {
map.once('postrender', function() {
const call = view.animate.getCall(0);
expect(call.args[0].resolution).to.be(2);

View File

@@ -1,4 +1,3 @@
import {listen, unlisten} from '../../../../../src/ol/events.js';
import {clear} from '../../../../../src/ol/obj.js';
import * as render from '../../../../../src/ol/render/canvas.js';
@@ -22,11 +21,11 @@ describe('ol.render.canvas', function() {
it('does not clear label cache and measurements for unavailable fonts', function(done) {
this.timeout(4000);
const spy = sinon.spy();
listen(render.labelCache, 'clear', spy);
render.labelCache.addEventListener('clear', spy);
const interval = setInterval(function() {
if (render.checkedFonts['normal\nnormal\nfoo'] == retries && render.checkedFonts['normal\nnormal\nsans-serif'] == retries) {
clearInterval(interval);
unlisten(render.labelCache, 'clear', spy);
render.labelCache.removeEventListener('clear', spy);
expect(spy.callCount).to.be(0);
expect(render.textHeights).to.not.eql({});
done();
@@ -37,11 +36,11 @@ describe('ol.render.canvas', function() {
it('does not clear label cache and measurements for available fonts', function(done) {
const spy = sinon.spy();
listen(render.labelCache, 'clear', spy);
render.labelCache.addEventListener('clear', spy);
const interval = setInterval(function() {
if (render.checkedFonts['normal\nnormal\nsans-serif'] == retries) {
clearInterval(interval);
unlisten(render.labelCache, 'clear', spy);
render.labelCache.removeEventListener('clear', spy);
expect(spy.callCount).to.be(0);
expect(render.textHeights).to.not.eql({});
done();
@@ -52,11 +51,11 @@ describe('ol.render.canvas', function() {
it('does not clear label cache and measurements for the \'monospace\' font', function(done) {
const spy = sinon.spy();
listen(render.labelCache, 'clear', spy);
render.labelCache.addEventListener('clear', spy);
const interval = setInterval(function() {
if (render.checkedFonts['normal\nnormal\nmonospace'] == retries) {
clearInterval(interval);
unlisten(render.labelCache, 'clear', spy);
render.labelCache.removeEventListener('clear', spy);
expect(spy.callCount).to.be(0);
expect(render.textHeights).to.not.eql({});
done();
@@ -68,7 +67,7 @@ describe('ol.render.canvas', function() {
it('clears label cache and measurements for fonts that become available', function(done) {
head.appendChild(font);
render.labelCache.set('dummy', {});
listen(render.labelCache, 'clear', function() {
render.labelCache.addEventListener('clear', function() {
expect(render.textHeights).to.eql({});
done();
});

View File

@@ -40,7 +40,7 @@ describe('ol.renderer.Layer', function() {
it('registers a listener', function() {
renderer.loadImage(image);
const listeners = image.getListeners(eventType, false);
const listeners = image.listeners_[eventType];
expect(listeners).to.have.length(1);
});
@@ -76,7 +76,7 @@ describe('ol.renderer.Layer', function() {
it('does not register a new listener', function() {
renderer.loadImage(image);
const listeners = image.getListeners(eventType, false);
const listeners = image.listeners_[eventType];
expect(listeners).to.have.length(1);
});

View File

@@ -1,5 +1,4 @@
import {VOID} from '../../../../src/ol/functions.js';
import {getListeners} from '../../../../src/ol/events.js';
import LineString from '../../../../src/ol/geom/LineString.js';
import Point from '../../../../src/ol/geom/Point.js';
import Polygon from '../../../../src/ol/geom/Polygon.js';
@@ -54,8 +53,7 @@ describe('ol.renderer.vector', function() {
style, squaredTolerance, listener, listenerThis);
expect(iconStyleLoadSpy.calledOnce).to.be.ok();
listeners = getListeners(
iconStyle.iconImage_, 'change');
listeners = iconStyle.iconImage_.listeners_['change'];
expect(listeners.length).to.eql(1);
// call #2
@@ -63,8 +61,7 @@ describe('ol.renderer.vector', function() {
style, squaredTolerance, listener, listenerThis);
expect(iconStyleLoadSpy.calledOnce).to.be.ok();
listeners = getListeners(
iconStyle.iconImage_, 'change');
listeners = iconStyle.iconImage_.listeners_['change'];
expect(listeners.length).to.eql(1);
});