mirror of
https://github.com/Leaflet/Leaflet.git
synced 2026-02-01 17:27:23 +00:00
Feature / Fix: Extend Events.listens to search for specific function (#8161)
* Update Events.listens to search for specific function Check if listener is existing in `_panInsideMaxBounds` before rm listene revert example Fix lint * Refactor _listens * Add function definition for IE * Refactor * Return index and remove indexOf * _listens return number or false * Revert to true Co-authored-by: Volodymyr Agafonkin <agafonkin@gmail.com>
This commit is contained in:
parent
990d49773a
commit
0f987feda9
@ -659,6 +659,50 @@ describe('Events', function () {
|
||||
obj.fire('test');
|
||||
expect(obj.listens('test')).to.be(false);
|
||||
});
|
||||
|
||||
it('returns true if event handler with specific function and context is existing', function () {
|
||||
var obj = new L.Evented(),
|
||||
differentContext = new L.Evented(),
|
||||
spy = sinon.spy(),
|
||||
diffentFnc = sinon.spy();
|
||||
|
||||
obj.on('test', spy);
|
||||
|
||||
// event handler 'test' is existing
|
||||
expect(obj.listens('test')).to.be(true);
|
||||
|
||||
// event handler with specific function is existing
|
||||
expect(obj.listens('test', spy)).to.be(true); // context arg: undefined === this
|
||||
expect(obj.listens('test', spy, obj)).to.be(true);
|
||||
|
||||
// event handler with specific function and other context is not existing
|
||||
expect(obj.listens('test', spy, differentContext)).to.be(false);
|
||||
|
||||
// event handler with specific function is not existing
|
||||
expect(obj.listens('test', diffentFnc)).to.be(false);
|
||||
});
|
||||
|
||||
it('is true if there is an event handler on parent', function () {
|
||||
var fg = L.featureGroup(),
|
||||
marker = L.marker([0, 0]).addTo(fg),
|
||||
spy = sinon.spy();
|
||||
|
||||
fg.on('test', spy);
|
||||
expect(marker.listens('test', false)).to.be(false);
|
||||
expect(marker.listens('test', true)).to.be(true);
|
||||
});
|
||||
|
||||
it('is true if there is an event handler with specific function on parent', function () {
|
||||
var fg = L.featureGroup(),
|
||||
marker = L.marker([0, 0]).addTo(fg),
|
||||
spy = sinon.spy();
|
||||
|
||||
fg.on('test', spy);
|
||||
expect(marker.listens('test', spy, marker, false)).to.be(false);
|
||||
expect(marker.listens('test', spy, marker, true)).to.be(false);
|
||||
expect(marker.listens('test', spy, fg, false)).to.be(false);
|
||||
expect(marker.listens('test', spy, fg, true)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#L.Mixin.Events', function () {
|
||||
|
||||
@ -100,30 +100,22 @@ export var Events = {
|
||||
console.warn('wrong listener type: ' + typeof fn);
|
||||
return;
|
||||
}
|
||||
this._events = this._events || {};
|
||||
|
||||
/* get/init listeners for type */
|
||||
var typeListeners = this._events[type];
|
||||
if (!typeListeners) {
|
||||
typeListeners = [];
|
||||
this._events[type] = typeListeners;
|
||||
// check if fn already there
|
||||
if (this._listens(type, fn, context) !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context === this) {
|
||||
// Less memory footprint.
|
||||
context = undefined;
|
||||
}
|
||||
var newListener = {fn: fn, ctx: context},
|
||||
listeners = typeListeners;
|
||||
|
||||
// check if fn already there
|
||||
for (var i = 0, len = listeners.length; i < len; i++) {
|
||||
if (listeners[i].fn === fn && listeners[i].ctx === context) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var newListener = {fn: fn, ctx: context};
|
||||
|
||||
listeners.push(newListener);
|
||||
this._events = this._events || {};
|
||||
this._events[type] = this._events[type] || [];
|
||||
this._events[type].push(newListener);
|
||||
},
|
||||
|
||||
_off: function (type, fn, context) {
|
||||
@ -131,10 +123,11 @@ export var Events = {
|
||||
i,
|
||||
len;
|
||||
|
||||
if (!this._events) { return; }
|
||||
if (!this._events) {
|
||||
return;
|
||||
}
|
||||
|
||||
listeners = this._events[type];
|
||||
|
||||
if (!listeners) {
|
||||
return;
|
||||
}
|
||||
@ -152,30 +145,24 @@ export var Events = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context === this) {
|
||||
context = undefined;
|
||||
}
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
console.warn('wrong listener type: ' + typeof fn);
|
||||
return;
|
||||
}
|
||||
|
||||
// find fn and remove it
|
||||
for (i = 0, len = listeners.length; i < len; i++) {
|
||||
var l = listeners[i];
|
||||
if (l.ctx !== context) { continue; }
|
||||
if (l.fn === fn) {
|
||||
if (this._firingCount) {
|
||||
// set the removed listener to noop so that's not called if remove happens in fire
|
||||
l.fn = Util.falseFn;
|
||||
var index = this._listens(type, fn, context);
|
||||
if (index !== false) {
|
||||
var listener = listeners[index];
|
||||
if (this._firingCount) {
|
||||
// set the removed listener to noop so that's not called if remove happens in fire
|
||||
listener.fn = Util.falseFn;
|
||||
|
||||
/* copy array in case events are being fired */
|
||||
this._events[type] = listeners = listeners.slice();
|
||||
}
|
||||
listeners.splice(i, 1);
|
||||
|
||||
return;
|
||||
/* copy array in case events are being fired */
|
||||
this._events[type] = listeners = listeners.slice();
|
||||
}
|
||||
listeners.splice(index, 1);
|
||||
return;
|
||||
}
|
||||
console.warn('listener not found');
|
||||
},
|
||||
@ -216,24 +203,61 @@ export var Events = {
|
||||
},
|
||||
|
||||
// @method listens(type: String, propagate?: Boolean): Boolean
|
||||
// @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean
|
||||
// Returns `true` if a particular event type has any listeners attached to it.
|
||||
// The verification can optionally be propagated, it will return `true` if parents have the listener attached to it.
|
||||
listens: function (type, propagate) {
|
||||
listens: function (type, fn, context, propagate) {
|
||||
if (typeof type !== 'string') {
|
||||
console.warn('"string" type argument expected');
|
||||
}
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
propagate = !!fn;
|
||||
fn = undefined;
|
||||
context = undefined;
|
||||
}
|
||||
|
||||
var listeners = this._events && this._events[type];
|
||||
if (listeners && listeners.length) { return true; }
|
||||
if (listeners && listeners.length) {
|
||||
if (this._listens(type, fn, context) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (propagate) {
|
||||
// also check parents for listeners if event propagates
|
||||
for (var id in this._eventParents) {
|
||||
if (this._eventParents[id].listens(type, propagate)) { return true; }
|
||||
if (this._eventParents[id].listens(type, fn, context, propagate)) { return true; }
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// returns the index (number) or false
|
||||
_listens: function (type, fn, context) {
|
||||
if (!this._events) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var listeners = this._events[type] || [];
|
||||
if (!fn) {
|
||||
return !!listeners.length;
|
||||
}
|
||||
|
||||
if (context === this) {
|
||||
// Less memory footprint.
|
||||
context = undefined;
|
||||
}
|
||||
|
||||
for (var i = 0, len = listeners.length; i < len; i++) {
|
||||
if (listeners[i].fn === fn && listeners[i].ctx === context) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
},
|
||||
|
||||
// @method once(…): this
|
||||
// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
|
||||
once: function (types, fn, context) {
|
||||
|
||||
@ -446,8 +446,7 @@ export var Map = Evented.extend({
|
||||
setMaxBounds: function (bounds) {
|
||||
bounds = toLatLngBounds(bounds);
|
||||
|
||||
if (this._maxBoundsSet) {
|
||||
this._maxBoundsSet = false;
|
||||
if (this.listens('moveend', this._panInsideMaxBounds)) {
|
||||
this.off('moveend', this._panInsideMaxBounds);
|
||||
}
|
||||
|
||||
@ -462,7 +461,6 @@ export var Map = Evented.extend({
|
||||
this._panInsideMaxBounds();
|
||||
}
|
||||
|
||||
this._maxBoundsSet = true;
|
||||
return this.on('moveend', this._panInsideMaxBounds);
|
||||
},
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user