maplair
Version:
JavaScript library for mobile-friendly interactive maps
149 lines (148 loc) • 4.59 kB
JavaScript
import { falseFn, splitWords, stamp } from "./Util.js";
import { Class } from "./Class.js";
//#region src/core/Events.js
var Evented = class Evented extends Class {
on(types, fn, context) {
if (typeof types === "object") for (const [type, f] of Object.entries(types)) this._on(type, f, fn);
else for (const type of splitWords(types)) this._on(type, fn, context);
return this;
}
off(types, fn, context) {
if (!arguments.length) {
delete this._events;
delete this._listenerIndex;
} else if (typeof types === "object") for (const [type, f] of Object.entries(types)) this._off(type, f, fn);
else {
const removeAll = arguments.length === 1;
for (const type of splitWords(types)) if (removeAll) this._off(type);
else this._off(type, fn, context);
}
return this;
}
static __REMOVED_EVENTS = [
"mousedown",
"mouseup",
"mouseover",
"mouseout",
"mousemove"
];
_on(type, fn, context, _once) {
if (Evented.__REMOVED_EVENTS.includes(type)) console.error(`The event ${type} has been removed. Use the PointerEvent variant instead.`);
if (typeof fn !== "function") {
console.warn(`wrong listener type: ${typeof fn}`);
return;
}
if (context === this) context = void 0;
const contexts = this._getListenerIndex(type).get(fn);
if (contexts?.has(context)) return;
const newListener = {
fn,
ctx: context
};
if (_once) newListener.once = true;
this._events ??= {};
this._events[type] ??= /* @__PURE__ */ new Set();
this._events[type].add(newListener);
if (contexts) contexts.set(context, newListener);
else this._listenerIndex[type].set(fn, /* @__PURE__ */ new Map([[context, newListener]]));
}
_getListenerIndex(type) {
this._listenerIndex ??= {};
return this._listenerIndex[type] ??= /* @__PURE__ */ new Map();
}
_off(type, fn, context) {
if (!this._events) return;
let listeners = this._events[type];
if (!listeners) return;
if (arguments.length === 1) {
if (this._firingCount) for (const listener of listeners) listener.fn = falseFn;
delete this._events[type];
delete this._listenerIndex?.[type];
return;
}
if (typeof fn !== "function") {
console.warn(`wrong listener type: ${typeof fn}`);
return;
}
if (context === this) context = void 0;
const contexts = this._listenerIndex?.[type]?.get(fn), listener = contexts?.get(context);
if (listener) {
contexts.delete(context);
if (!contexts.size) this._listenerIndex[type].delete(fn);
if (this._firingCount) {
listener.fn = falseFn;
this._events[type] = listeners = new Set(listeners);
}
listeners.delete(listener);
}
}
fire(type, data, propagate) {
if (!this.listens(type, propagate)) return this;
const event = {
...data,
type,
target: this,
sourceTarget: data?.sourceTarget || this
};
if (this._events) {
const listeners = this._events[type];
if (listeners) {
this._firingCount = this._firingCount + 1 || 1;
for (const l of listeners) {
const fn = l.fn;
if (l.once) this.off(type, fn, l.ctx);
fn.call(l.ctx || this, event);
}
this._firingCount--;
}
}
if (propagate) this._propagateEvent(event);
return this;
}
listens(type, fn, context, propagate) {
if (typeof type !== "string") console.warn("\"string\" type argument expected");
let _fn = fn;
if (typeof fn !== "function") {
propagate = !!fn;
_fn = void 0;
context = void 0;
}
if (this._events?.[type]?.size) {
if (this._listens(type, _fn, context) !== false) return true;
}
if (propagate) {
for (const p of Object.values(this._eventParents ?? {})) if (p.listens(type, fn, context, propagate)) return true;
}
return false;
}
_listens(type, fn, context) {
if (!this._events) return false;
const listeners = this._events[type];
if (!fn) return !!listeners?.size;
if (context === this) context = void 0;
return !!this._listenerIndex?.[type]?.get(fn)?.has(context);
}
once(types, fn, context) {
if (typeof types === "object") for (const [type, f] of Object.entries(types)) this._on(type, f, fn, true);
else for (const type of splitWords(types)) this._on(type, fn, context, true);
return this;
}
addEventParent(obj) {
this._eventParents ??= {};
this._eventParents[stamp(obj)] = obj;
return this;
}
removeEventParent(obj) {
if (this._eventParents) delete this._eventParents[stamp(obj)];
return this;
}
_propagateEvent(e) {
for (const p of Object.values(this._eventParents ?? {})) p.fire(e.type, {
propagatedFrom: e.target,
...e
}, true);
}
};
//#endregion
export { Evented };
//# sourceMappingURL=Events.js.map