vue-events-backbone
Version:
This plugin is an Event Bus that, by default, simulates DOM events propagation through vue components.
674 lines (673 loc) • 22.7 kB
JavaScript
var x = Object.defineProperty;
var A = (o, e, n) => e in o ? x(o, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : o[e] = n;
var l = (o, e, n) => A(o, typeof e != "symbol" ? e + "" : e, n);
import { getCurrentInstance as m } from "vue";
function w(o) {
return o.watchedIsUnmounted !== void 0;
}
const v = function(o) {
return w(o) ? o : (o = Object.defineProperties(o, {
watchedIsUnmounted: {
enumerable: !0,
writable: !0,
value: o.isUnmounted
},
isUnmountedCallbacks: {
enumerable: !0,
writable: !0,
value: []
}
}), Object.defineProperty(o, "isUnmounted", {
get() {
return this.watchedIsUnmounted;
},
set(e) {
if (e !== this.watchedIsUnmounted)
try {
for (const n of this.isUnmountedCallbacks)
n();
this.isUnmountedCallbacks.length = 0;
} catch (n) {
console.error(n);
}
this.watchedIsUnmounted = e;
}
}));
};
class R {
constructor() {
l(this, "evntsTree");
l(this, "lstnrsRegistry");
l(this, "compsRegistry");
l(this, "listenAllSymbol", Symbol("*"));
l(this, "emptyMap", /* @__PURE__ */ new Map());
this.evntsTree = /* @__PURE__ */ new Map(), this.lstnrsRegistry = /* @__PURE__ */ new Map(), this.compsRegistry = /* @__PURE__ */ new Map();
}
_getComponentFromUid(e) {
for (const n of this.compsRegistry.entries())
if (n[0].uid === e)
return n[0];
}
_callHandler(e, n, t) {
var a, c, d, u;
const r = this._rebuildEventNameFromSymbol(t), s = ((c = (a = n.handlerCallerComponentInstance) == null ? void 0 : a.type) == null ? void 0 : c.__name) || ((u = (d = n.handlerCallerComponentInstance) == null ? void 0 : d.type) == null ? void 0 : u.name);
n.once = () => {
this.off(n.handlerCallerComponentInstance.uid, r || "-", e);
};
let i;
try {
i = e(n);
} catch (p) {
return console.error(`Error in handler function: ${e == null ? void 0 : e.name} - event: ${r} - handler caller: ${s}`), console.error(p), p;
}
return i;
}
async _callHandlers(e, n) {
const t = [];
e.branchSymbols.forEach((r) => {
for (const s of (this.lstnrsRegistry.get(r) || this.emptyMap).entries()) {
const i = n ? n.uid === s[0].uid ? n : void 0 : s[0];
if (i) {
e.handlerCallerComponentInstance = i;
for (const a of s[1]) {
let c = this._callHandler(
a,
e,
r
);
!e.eager && c instanceof Promise && t.push(c);
}
}
}
}), await Promise.allSettled(t);
}
async _internalEmitEvent(e, n) {
e.handlerCallerComponentInstance = n || e.emitterComponentInstance, this.compsRegistry.has(e.handlerCallerComponentInstance) && await this._callHandlers(e, e.handlerCallerComponentInstance), !e.propagationStopped && e.handlerCallerComponentInstance.parent && await this._internalEmitEvent(e, e.handlerCallerComponentInstance.parent);
}
// get the reversed branch of event symbols a:b:c -> [c, b, a]
_getBranchSymbols(e) {
const n = e.split(":"), t = [this.listenAllSymbol];
let r;
for (; n.length > 0; ) {
r = r ? r + `:${n.splice(0, 1)[0]}` : `${n.splice(0, 1)[0]}`;
const s = this._getEventEntry(r.split(":"));
if (s)
t.unshift(s.symbol);
else
break;
}
return t;
}
// main function to handle emitted event
emitEvent(e, n, t, r) {
const s = this, i = {
emitterComponentInstance: e,
handlerCallerComponentInstance: e,
eventName: n,
branchSymbols: this._getBranchSymbols(n),
eventData: t,
global: (r == null ? void 0 : r.global) || !1,
propagationStopped: null,
eager: Object.is(r == null ? void 0 : r.eager, void 0) || Object.is(r == null ? void 0 : r.eager, null) ? !0 : !!(r != null && r.eager) || !1,
// placeholders to avoid the optional parameters in type definition
stopPropagation: function() {
if (!this.global) {
this.propagationStopped = !this.global;
return;
}
console.warn(`${this.eventName} - can not stop the propagation of an event emitted globally.`);
},
once: () => {
},
transformEvent: function(a, c) {
if (this.global) {
console.warn(`Cannot transform event ${this.eventName} into ${a} as ${this.eventName} has been emitted globally.`);
return;
}
try {
s._checkEventNameValidity(a), this.eventName = a, this.eventData = c || this.eventData, this.branchSymbols = s._getBranchSymbols(a);
} catch (d) {
console.error(`Error trying to transform event ${this.eventName} into ${a}`), console.error(d);
}
},
emitEvent: function(a, c, d, u) {
return s.emitEvent(this.handlerCallerComponentInstance, a, c, { global: d, eager: u });
}
};
return i.transformEvent = i.transformEvent.bind(i), r != null && r.global ? this._callHandlers(i) : this._internalEmitEvent(i);
}
_addEventEntry(e, n) {
return n && e !== "*" ? n.children.set(e, { symbol: Symbol(e), parent: n, children: /* @__PURE__ */ new Map() }).get(e) : this.evntsTree.set(e, { symbol: e === "*" ? this.listenAllSymbol : Symbol(e), parent: n, children: /* @__PURE__ */ new Map() }).get(e);
}
_checkEventEntryValidity(e) {
const n = !!this.lstnrsRegistry.get(e.symbol);
if (n || e.children.size === 0)
return n;
for (const t of e.children.entries())
if (this._checkEventEntryValidity(t[1]))
return !0;
return n;
}
_removeEventEntry(e) {
let n = e.parent;
if (!n) {
this.evntsTree.delete(e.symbol.description);
return;
}
for (e.parent = void 0, n.children.delete(e.symbol.description); n && !this._checkEventEntryValidity(n); ) {
const t = n.parent;
t ? (n.parent = void 0, t.children.delete(n.symbol.description)) : this.evntsTree.delete(n.symbol.description), n = t;
}
}
_rebuildEventNameFromSymbol(e) {
const n = this._findEventEntryFromNodeName(e.description);
if (n)
return this._rebuildEventNameFromEventEntry(n);
}
_rebuildEventNameFromEventEntry(e) {
let n = e.symbol.description;
for (; e.parent; )
n = `${e.parent.symbol.description}:` + n, e = e.parent;
return n;
}
_findEventEntryFromNodeName(e, n) {
if (n) {
for (const t of n.children.entries()) {
if (t[0] === e)
return t[1];
const r = this._findEventEntryFromNodeName(e, t[1]);
if (r)
return r;
}
return;
}
for (const t of this.evntsTree.entries()) {
if (t[0] === e)
return t[1];
const r = this._findEventEntryFromNodeName(e, t[1]);
if (r)
return r;
}
}
_getEventEntry(e, n, t) {
const r = e.splice(0, 1)[0];
let s = n ? n.children.get(r) : this.evntsTree.get(r);
if (!s) {
if (!t)
return s;
s = this._addEventEntry(r, n);
}
return e.length === 0 ? s : this._getEventEntry(e, s, t);
}
_checkEventNameValidity(e) {
var r, s, i, a, c, d;
const t = /(?<listenallerror>.*\*.+)|(?<consequentcolons>:{2,})|(?<spacescolons>:\s+:)|(?<finalcolon>^.*:$)|(?<startingcolon>^:.*$)|(?<spacesfound>^[a-zA-Z:]*\s+[a-zA-Z:]*$)/gi.exec(e);
if ((r = t == null ? void 0 : t.groups) != null && r.listenallerror)
throw new Error(`${e} - Invalid event name. Listen All event listeners must be registered with a lone '*'.`);
if ((s = t == null ? void 0 : t.groups) != null && s.consequentcolons)
throw new Error(`${e} - Invalid event name. The name cannot have consequent colons.`);
if ((i = t == null ? void 0 : t.groups) != null && i.finalcolon)
throw new Error(`${e} - Invalid event name. The name cannot end with a colon.`);
if ((a = t == null ? void 0 : t.groups) != null && a.startingcolon)
throw new Error(`${e} - Invalid event name. The name cannot start with a colon.`);
if ((c = t == null ? void 0 : t.groups) != null && c.spacescolons)
throw new Error(`${e} - Invalid event name. The name cannot have two colons separated by spaces.`);
if ((d = t == null ? void 0 : t.groups) != null && d.spacesfound)
throw new Error(`${e} - Invalid event name. The name cannot have spaces inside.`);
}
// da chiamare nell' ON
_addListener(e, n, t) {
const r = this._getEventEntry(n.split(":"), void 0, !0);
r && (this._addListenerEntry(e, r.symbol, t), this._addCompEntrySymbol(e, r.symbol));
}
_addListenerEntry(e, n, t) {
const r = this.lstnrsRegistry.get(n);
if (!r)
this.lstnrsRegistry.set(n, /* @__PURE__ */ new Map([[e, /* @__PURE__ */ new Set([t])]]));
else {
const s = r.get(e);
if (s) {
s.has(t) || s.add(t);
return;
}
r.set(e, /* @__PURE__ */ new Set([t]));
}
}
_addCompEntrySymbol(e, n) {
var t;
if (this.compsRegistry.has(e)) {
(t = this.compsRegistry.get(e)) == null || t.add(n);
return;
}
this.compsRegistry.set(e, /* @__PURE__ */ new Set([n]));
}
// remove functions
_removeCompEntry(e) {
this.compsRegistry.delete(e);
}
_removeCompEntrySymbol(e, n) {
const t = this.compsRegistry.get(e);
t && (t.delete(n), t.size === 0 && this._removeCompEntry(e));
}
_removeListenerEntry(e, n, t) {
const r = this.lstnrsRegistry.get(n);
if (!r)
return;
const s = r.get(e);
s && (s.delete(t), s.size === 0 && (r.delete(e), this._removeCompEntrySymbol(e, n)));
}
// da chiamare nell' OFF
_removeListener(e, n, t) {
const r = this._getEventEntry(n.split(":"));
if (r) {
this._removeListenerEntry(e, r.symbol, t);
const s = this.lstnrsRegistry.get(r.symbol);
s && s.size === 0 && this.lstnrsRegistry.delete(r.symbol), this._checkEventEntryValidity(r) || this._removeEventEntry(r);
}
}
on(e, n, t) {
try {
if (n = n.trim(), n.length === 0) {
console.error("Event name can not be an empty string");
return;
}
let r = v(e);
r.isUnmountedCallbacks.push(() => {
this.offAll(r);
}), this._checkEventNameValidity(n), this._addListener(r, n, t);
} catch (r) {
console.error(r);
}
}
// removes specific component instance handler for specific event
// if no handler is passed to the function, it removes all handlers for specific events
off(e, n, t) {
const r = this._getComponentFromUid(e);
r && t ? this._removeListener(r, n, t) : r && !t && this.offAll(r);
}
offAll(e) {
const n = this.compsRegistry.get(e);
n && (n.forEach((t) => {
const r = this.lstnrsRegistry.get(t);
r && r.has(e) && r.delete(e);
}), this.compsRegistry.delete(e));
}
}
const C = function(o) {
return new o();
}, h = C(R);
function g(o) {
o && h.offAll(o);
}
function y(o, e) {
if (e)
for (const n in o)
if (!Array.isArray(o[n]))
console.warn(`${e.type.__name || e.type.name} - eventKey value for ${n} must be an array`);
else
for (const t of o[n])
h.off(e.uid, n, t);
}
function f(o, e, n) {
if (g(n && e ? e : void 0), e)
for (const t in o)
if (Array.isArray(o[t]))
for (const r of o[t])
h.on(e, t, r);
else
console.warn(`${e.type.__name || e.type.name} - eventKey value for ${t} must be an array`);
}
const _ = {
beforeMount(o, e, n) {
var t;
f(e.value, (t = e.instance) == null ? void 0 : t.$);
},
beforeUpdate(o, e, n, t) {
var r;
f(e.value, e.arg === "update" && ((r = e.instance) == null ? void 0 : r.$), e.arg === "update");
},
beforeUnmount(o, e, n) {
var t;
g((t = e.instance) == null ? void 0 : t.$);
}
};
class q {
constructor(e, n, t) {
l(this, "neuronFrom");
l(this, "neuronTo");
l(this, "axonKey");
this.neuronFrom = n, this.axonKey = e, this.neuronTo = t;
}
async transmitSignal(e, n) {
return this.neuronTo ? await this.neuronTo.deliverSignal(e, n) : (console.log("No neuron linked to axon with key: " + this.axonKey), []);
}
getNeuronFrom() {
return this.neuronFrom;
}
getAxonKey() {
return this.axonKey;
}
destroy(e, n) {
this.neuronFrom && this.neuronTo && (e && this.neuronFrom && this.neuronFrom.notifyCutAxonFromReceiverNeuron(this.axonKey, this.neuronTo.getNeuronKey(), !!n), this.neuronTo && this.neuronTo.notifyCutAxonFromSenderNeuron(this.axonKey)), this.neuronTo = void 0, this.neuronFrom = void 0;
}
}
class k {
constructor(e, n, t) {
l(this, "dendriteComponent");
l(this, "neuron");
l(this, "callbacks");
this.callbacks = /* @__PURE__ */ new Map(), this.neuron = n, this.dendriteComponent = e, t && this.setNeurotransmitterCallbacks(t), e.isUnmountedCallbacks.push(this.destroy.bind(this));
}
getComponentInstance() {
return this.dendriteComponent;
}
setNeurotransmitterCallbacks(e) {
for (const n in e)
this.callbacks.set(n, e[n]);
}
removeNeurotransmitterCallbacks(e) {
for (const n of e)
this.callbacks.delete(n);
}
getNeuron() {
return this.neuron;
}
deliverSignalToDendrite(e, n) {
const t = this.callbacks.get(e);
if (t)
try {
return t(n);
} catch (r) {
console.error(r);
}
}
sendSignalFromDendrite(e, n, t) {
return this.getNeuron().sendSignal(e, n, t);
}
deleteAxonFromDendrite(e, n) {
var t;
console.log("deleteAxonFromDendrite"), console.log(e), console.log(n), (t = this.neuron) == null || t.deleteAxon(e, n);
}
destroy() {
var e;
this.dendriteComponent = void 0, this.callbacks.clear(), (e = this.neuron) == null || e.deleteDendrite(this), this.neuron = void 0;
}
}
class N {
// private readonly signalsQueue: Map<EventsBackboneAxonKey, [EventsBackboneNeurotransmitterKey, any]>
constructor(e, n, ...t) {
l(this, "dendrites");
l(this, "brain");
l(this, "neuronKey");
l(this, "senderAxons");
l(this, "receiverAxons");
l(this, "pendingAxonRequests");
this.brain = e, this.neuronKey = n, this.dendrites = new Set(t), this.senderAxons = /* @__PURE__ */ new Map(), this.receiverAxons = /* @__PURE__ */ new Map(), this.pendingAxonRequests = /* @__PURE__ */ new Set();
}
addDendrite(e) {
return this.dendrites.add(e), e;
}
getDendrites() {
return this.dendrites;
}
deleteDendrite(e) {
this.dendrites.delete(e), this.size === 0 && this.destroy();
}
hasDendrite(e) {
return this.dendrites.has(e);
}
getNeuronKey() {
return this.neuronKey;
}
getAxons() {
return this.senderAxons;
}
getAxon(e) {
return this.senderAxons.get(e);
}
deleteAxon(e, n) {
console.warn("deleteAxon"), console.log(e), console.log(n);
const t = this.getAxon(e);
if (console.log("a", t), t) {
t.destroy(!1, n), this.senderAxons.delete(e);
return;
} else if (this.pendingAxonRequests.has(e)) {
this.stopPendingAxonRequest(e);
return;
}
console.warn(`No axon with key ${e} has been found on neuron ${this.neuronKey}`);
}
// quando il neurone ricevente viene distrutto, notifica il neurone trasmettitore
// che occorre ricreare l'assone (attendendo per quando verrà rimontato eventualmente
// il neurone ricevente)
async notifyCutAxonFromReceiverNeuron(e, n, t) {
const r = this.senderAxons.delete(e);
t || !r || await this.requestAxon(e, n);
}
async notifyCutAxonFromSenderNeuron(e) {
this.receiverAxons.delete(e);
}
addAxonRequest(e) {
this.pendingAxonRequests.add(e);
}
removeAxonRequest(e) {
this.pendingAxonRequests.delete(e);
}
stopPendingAxonRequest(e) {
this.brain && (this.brain.stopPendingAxonRequest(this.neuronKey, e), this.removeAxonRequest(e));
}
async requestAxon(e, n) {
if (!this.brain)
throw new Error("Unable to request axon creation. Brain is not set.");
this.addAxonRequest(n);
try {
const t = await this.brain.requestNeuronForAxon(this.neuronKey, n);
if (this.removeAxonRequest(n), !t) {
console.warn("Axon request from " + this.neuronKey + " to " + n + " stopped.");
return;
}
const r = new q(e, this, t);
return t.receiveAxon(r), this.senderAxons.set(e, r), r;
} catch (t) {
console.error("Error trying to request axon from neuron " + this.neuronKey + " to neuron " + n), console.error(t), this.removeAxonRequest(n);
}
}
receiveAxon(e) {
e && !this.receiverAxons.has(e.getAxonKey()) && this.receiverAxons.set(e.getAxonKey(), e);
}
// emette il segnale tramite l'axon verso il neuron target
async sendSignal(e, n, t) {
const r = this.senderAxons.get(e);
if (r)
return await r.transmitSignal(n, t);
console.log("No axon with key: " + e + " in neuron with key: " + this.neuronKey);
}
// funzione per consegnare il segnale e i dati inviati dal neuron transmitter attraverso l'axon
// ritorna tutti i risultati delle funzioni chiamate per ogni dendrite
async deliverSignal(e, n) {
const t = [];
for (const r of this.dendrites) {
const s = r.deliverSignalToDendrite(e, n);
s && s instanceof Promise ? t.push(s) : t.push(Promise.resolve(s));
}
return await Promise.allSettled(t);
}
get size() {
return this.dendrites.size;
}
get length() {
return this.size;
}
destroy() {
var e;
for (const n of this.pendingAxonRequests)
this.stopPendingAxonRequest(n);
this.pendingAxonRequests.clear(), (e = this.brain) == null || e.deleteNeuron(this.neuronKey), this.brain = void 0;
for (const n of this.senderAxons.entries())
n[1].destroy(!1);
this.senderAxons.clear();
for (const n of this.receiverAxons.entries())
n[1].destroy(!0);
this.receiverAxons.clear();
}
}
class S {
constructor() {
l(this, "neurons");
l(this, "pendingAxonRequests");
l(this, "closePendingAxonRequests");
this.neurons = /* @__PURE__ */ new Map(), this.pendingAxonRequests = /* @__PURE__ */ new Map(), this.closePendingAxonRequests = /* @__PURE__ */ new Map();
}
// crea il neurone risolvendo allo stesso tempo le richieste pending di axon connection
// provenienti da altri neurons
generateNeuron(e, n, t) {
const r = v(n);
let s = this.neurons.get(e);
if (!s) {
s = new N(this, e), this.neurons.set(e, s);
const i = this.pendingAxonRequests.get(e);
if (i)
for (const a of i.entries())
a[1]();
}
return s.addDendrite(new k(r, s, t));
}
cleanupPendingAxonRequestsCallbacks(e, n) {
const t = this.pendingAxonRequests.get(n), r = this.closePendingAxonRequests.get(e);
t && (t.delete(e), t.size === 0 && this.pendingAxonRequests.delete(n)), r && (r.delete(n), r.size === 0 && this.closePendingAxonRequests.delete(e));
}
requestNeuronForAxon(e, n) {
const t = this.neurons.get(n);
return t ? Promise.resolve(t) : new Promise((r, s) => {
const i = this.pendingAxonRequests.get(n), a = this.closePendingAxonRequests.get(e), c = () => {
try {
this.cleanupPendingAxonRequestsCallbacks(e, n), r(this.neurons.get(n));
} catch (u) {
this.cleanupPendingAxonRequestsCallbacks(e, n), console.error(u), s("unable to retrieve requested neuron");
}
}, d = () => {
this.cleanupPendingAxonRequestsCallbacks(e, n), r();
};
if (i)
i.set(e, c);
else {
const u = /* @__PURE__ */ new Map([
[e, c]
]);
this.pendingAxonRequests.set(n, u);
}
if (a)
a.set(n, d);
else {
const u = /* @__PURE__ */ new Map([
[n, c]
]);
this.closePendingAxonRequests.set(e, u);
}
});
}
stopPendingAxonRequest(e, n) {
const t = this.closePendingAxonRequests.get(e);
if (t) {
const r = t.get(n);
if (r)
try {
r();
} catch {
console.error("Error stopping axon request from neuron " + e + " to neuron " + n);
}
}
}
deleteNeuron(e) {
this.neurons.delete(e), this.pendingAxonRequests.delete(e);
}
}
const $ = function(o) {
return new o();
}, b = $(S);
function E() {
return b;
}
function P(o, e) {
const n = m();
if (!n)
throw new Error("Cannot get current component instance. Please call createNeuron inside a lifecycle hook");
return b.generateNeuron(o, n, e);
}
function F(o) {
const e = o || m();
return e ? function(n) {
y(n, e);
} : (n) => {
const t = m();
if (t) {
y(n, t);
return;
}
console.warn(`Unable to retrieve component instance.
Probably defineRemoveEventListeners has been called outside from a lifecycle hook, this means that at least this
returned function must be called inside a lifecycle hook`);
};
}
function M(o) {
const e = o || m();
return e ? function(n, t) {
f(n, e, t);
} : (n, t) => {
const r = m();
if (r) {
f(n, r, t);
return;
}
console.warn(`Unable to retrieve component instance.
Probably defineAddEventListeners has been called outside from a lifecycle hook, this means that at least this
returned function must be called inside a lifecycle hook`);
};
}
function U(o, e) {
const n = e || m();
if (n) {
if (o) {
const t = new Map(
o.map(
(r) => [
r,
function(s, i, a) {
return h.emitEvent(n, r, s, { global: i, eager: a });
}
]
)
);
return function(r, s, i, a) {
const c = t.get(r);
return c ? c(s, i, a) : (console.warn(`Event ${r} not defined as backbone emitter.`), Promise.resolve());
};
}
return function(t, r, s, i) {
return h.emitEvent(n, t, r, { global: s, eager: i });
};
}
return console.warn("No current component instance. defineBackboneEmits has to be called inside a lifecycle hook."), (t, r, s, i) => (console.warn(`Default backbone emitter called. Event ${t} NOT emitted through the backbone.`), Promise.resolve());
}
const L = _, D = E, T = P, z = {
install: (o) => {
if (!o) {
console.warn("No app parameter provided, returning...");
return;
}
o.config.globalProperties.$EventsBackBone = h, o.config.globalProperties.$EventsBackboneBrain = E();
}
};
function V() {
return h;
}
export {
L as EventsBackBoneDirective,
T as createNeuron,
z as default,
M as defineAddEventListeners,
U as defineBackboneEmits,
F as defineRemoveEventListeners,
V as useBackbone,
D as useBackboneBrain
};