/**
* @file mixins/evented.js
* @module ereignete sich
* /
import window from 'global/window';
importiere * als Dom aus '.. /utils/dom ';
importiere * als Ereignisse aus '.. /utils/events ';
importiere * als Fn aus '.. /utils/de ';
import * as Obj from '../utils/obj';
import EventTarget from '../event-target';
importiere DOMData aus '.. /utils/dom-data ';
import log from '../utils/log';
const objName = (obj) => {
if (typeof obj.name === 'Funktion') {
gib obj.name () zurück;
}
if (typeof obj.name === 'Zeichenfolge') {
gib obj.name zurück;
}
wenn (obj.name_) {
gib obj.name_ zurück;
}
wenn (obj.constructor && obj.constructor.name) {
gib obj.constructor.name zurück;
}
gibt den Typ des Objekts zurück;
};
/**
* Gibt zurück, ob auf ein Objekt das Event-Mixin angewendet wurde oder nicht.
*
* @param {Object} object
* Ein Objekt zum Testen.
*
* @return {boolean}
* Ob das Objekt ein Ereignis zu sein scheint oder nicht.
* /
const isEvented = (Objekt) =>
Objektinstanz von EventTarget ||
!! Objekt.EventBusel_ &&
['on', 'one', 'off', 'trigger']. every (k => Objekttyp [k] === 'Funktion');
/**
* Fügt einen Callback hinzu, der ausgeführt wird, nachdem das Event-Mixin angewendet wurde.
*
* @param {Object} object
* Ein Objekt zum Hinzufügen
* @param {Function} Rückruf
* Der Callback, der ausgeführt werden soll.
* /
const addEventedCallback = (Ziel, Rückruf) => {
if (isEvent (Ziel)) {
callback();
} sonst {
wenn (! target.eventedCallbacks) {
target.eventedCallbacks = [];
}
target.eventedCallbacks.push (Rückruf);
}
};
/**
* Ob ein Wert ein gültiger Ereignistyp ist — eine nicht leere Zeichenfolge oder ein Array.
*
* @privat
* @param {string|Array} type
* Der zu testende Typwert.
*
* @return {boolean}
* Ob der Typ ein gültiger Ereignistyp ist oder nicht.
* /
const isValidEventType = (Typ) =>
//Der Regex hier überprüft, ob der `Typ` mindestens einen Nicht-Typ enthält
//Leerzeichen.
(Typ === 'Zeichenfolge' && (/\ S/) .test (Typ)) ||
(Array.isArray (Typ) &&!! typ.länge);
/**
* Überprüft einen Wert, um festzustellen, ob er ein gültiges Ereignisziel ist. Wirft, wenn nicht.
*
* @privat
* @throws {Fehler}
* Wenn das Ziel kein gültiges Ereignisziel zu sein scheint.
*
* @param {Object} target
* Das zu testende Objekt.
*
* @param {Object} obj
* Das Ereignisobjekt, für das wir die Validierung durchführen
*
* @param {string} fnName
* Der Name der ereignisgesteuerten Mixin-Funktion, die diese Funktion aufgerufen hat.
* /
const validateTarget = (Ziel, obj, fnName) => {
wenn (! Ziel || (! Ziel.nodename &&! isEvented (Ziel)) {
throw new Error (`Ungültiges Ziel für $ {objName (obj)} #$ {fnName}; muss ein DOM-Knoten oder ein Ereignisobjekt sein.`);
}
};
/**
* Überprüft einen Wert, um festzustellen, ob er ein gültiges Ereignisziel ist. Wirft, wenn nicht.
*
* @privat
* @throws {Fehler}
* Wenn der Typ kein gültiger Ereignistyp zu sein scheint.
*
* @param {string|Array} type
* Der zu testende Typ.
*
* @param {Object} obj
* Das Ereignisobjekt, für das wir die Validierung durchführen
*
* @param {string} fnName
* Der Name der ereignisgesteuerten Mixin-Funktion, die diese Funktion aufgerufen hat.
* /
const validateEventType = (Typ, obj, fnName) => {
if (!isValidEventType(type)) {
throw new Error (`Ungültiger Ereignistyp für $ {objName (obj)} #$ {fnName}; muss eine nicht leere Zeichenfolge oder ein Array sein.`);
}
};
/**
* Validiert einen Wert, um festzustellen, ob es sich um einen gültigen Listener handelt. Wirft, wenn nicht.
*
* @privat
* @throws {Fehler}
* Wenn der Listener keine Funktion ist.
*
* @param {Funktion} listener
* Der zu testende Hörer.
*
* @param {Object} obj
* Das Ereignisobjekt, für das wir die Validierung durchführen
*
* @param {string} fnName
* Der Name der ereignisgesteuerten Mixin-Funktion, die diese Funktion aufgerufen hat.
* /
const validateListener = (Listener, obj, fnName) => {
if (Typ des Zuhörers! == 'Funktion') {
throw new Error (`Ungültiger Listener für $ {objName (obj)} #$ {fnName}; muss eine Funktion sein.`);
}
};
/**
* Nimmt ein Array von Argumenten, die an `on () `oder `one ()` übergeben wurden, validiert sie und
* normalisiert sie in ein Objekt.
*
* @privat
* @param {Object} selbst
* Das Ereignisobjekt, für das `on () `oder `one ()` aufgerufen wurde. Diese
* Objekt wird als `this` -Wert für den Listener gebunden.
*
* @param {Array} args
* Ein Array von Argumenten, die an `on () `oder `one ()` übergeben wurden.
*
* @param {string} fnName
* Der Name der ereignisgesteuerten Mixin-Funktion, die diese Funktion aufgerufen hat.
*
* @return {Object}
* Ein Objekt, das nützliche Werte für `on () `- oder `one ()` -Aufrufe enthält.
* /
const normalizeListenArgs = (self, args, fnName) => {
//Wenn die Anzahl der Argumente kleiner als 3 ist, ist das Ziel immer
//das Objekt selbst ereignete sich.
const isTargetingSelf = args.length < 3 || args [0] === self || args [0] === self.EventBusel_;
lass das Ziel anvisieren;
lass tippen;
lass den Zuhörer;
if (isTargetingSelf) {
Ziel = self.EventBusel_;
//Behandle Fälle, in denen wir 3 Argumente haben, aber wir hören immer noch zu
//das Ereignisobjekt selbst.
wenn (args.length >= 3) {
args.shift ();
}
[Typ, Listener] = Argumente;
} sonst {
[Ziel, Typ, Listener] = Argumente;
}
validateTarget (Ziel, Selbst, FNName);
validateEventType (Typ, self, fnName);
validateListener (Listener, self, fnName);
listener = fn.Bind (selbst, Zuhörer);
return {isTargetingSelf, Ziel, Typ, Listener};
};
/**
* Fügt den Listener zu den Ereignistypen auf dem Ziel hinzu und normalisiert für
* die Art des Ziels.
*
* @privat
* @param {Element|Object} Ziel
* Ein DOM-Knoten oder ein Ereignisobjekt.
*
* @param {string} Methode
* Die zu verwendende Methode zur Event-Bindung („on“ oder „one“).
*
* @param {string|Array} type
* Ein oder mehrere Veranstaltungstyp (en).
*
* @param {Funktion} listener
* Eine Listener-Funktion.
* /
const listen = (Ziel, Methode, Typ, Listener) => {
validateTarget (Ziel, Ziel, Methode);
if (target.nodeName) {
Ereignisse [Methode] (Ziel, Typ, Listener);
} sonst {
target [Methode] (Typ, Listener);
}
};
/**
* Enthält Methoden, die Ereignisfunktionen für ein übergebenes Objekt bereitstellen
* an {@link module:evented|evented}.
*
* @mixin EventedMixin
* /
const eventedMixin = {
/**
* Hinzufügen eines Listeners für ein Ereignis (oder Ereignisse) auf diesem Objekt oder einem anderen Ereignis
* objekt.
*
* @param {String|Array|Element|Objekt} targetOrType
* Wenn dies eine Zeichenkette oder ein Array ist, steht es für die Ereignisart(en)
* die den Hörer auslösen werden.
*
* Stattdessen kann hier ein anderes ereignisgesteuertes Objekt übergeben werden, das
* veranlassen den Listener, auf Ereignisse für _das_ Objekt zu warten.
*
* In beiden Fällen wird der `this'-Wert des Hörers an
* dieses Objekt.
*
* @param {string|Array|Funktion} typeOrListener
* Wenn das erste Argument eine Zeichenkette oder ein Array war, sollte dies die
* hörerfunktion. Andernfalls ist dies eine Zeichenkette oder ein Array von Ereignis
* art(en).
*
* @param {Funktion} [Listener]
* Wenn das erste Argument ein anderes ereignisgesteuertes Objekt war, wird dies
* die Hörerfunktion.
* /
auf (... args) {
const {isTargetingSelf, target, type, listener} = normalizeListenArgs (this, args, 'on');
listen (target, 'on', type, listener);
//Wenn dieses Objekt auf ein anderes Ereignisobjekt hört.
wenn (! zielt auf sich selbst ab) {
//Wenn dieses Objekt entsorgt wird, entferne den Listener.
const removeListenerOnDispose = () => this.off (Ziel, Typ, Listener);
//Benutze dieselbe Funktions-ID wie der Listener, damit wir sie später entfernen können
//mit der ID des ursprünglichen Listeners.
removeListenerOnDispose.GUID = listener.guid;
//Füge auch einen Listener zum Dispose-Event des Ziels hinzu. Das gewährleistet
//dass, wenn das Ziel VOR diesem Objekt entsorgt wird, wir das
//Listener entfernen, der gerade hinzugefügt wurde. Andernfalls verursachen wir ein Speicherleck.
const removeRemoverOnTargetDispose = () => this.off ('entsorgen', removeListenerOnDispose);
// Verwenden Sie dieselbe Funktions-ID wie der Hörer, damit wir ihn später entfernen können
// unter Verwendung der ID des ursprünglichen Zuhörers.
removeRemoverOnTargetDispose.GUID = listener.guid;
listen (this, 'on', 'dispose', removeListenerOnDispose);
listen (target, 'on', 'dispose', removeRemoverOnTargetDispose);
}
},
/**
* Hinzufügen eines Listeners für ein Ereignis (oder Ereignisse) auf diesem Objekt oder einem anderen Ereignis
* objekt. Der Listener wird einmal pro Ereignis aufgerufen und dann entfernt.
*
* @param {String|Array|Element|Objekt} targetOrType
* Wenn dies eine Zeichenkette oder ein Array ist, steht es für die Ereignisart(en)
* die den Hörer auslösen werden.
*
* Stattdessen kann hier ein anderes ereignisgesteuertes Objekt übergeben werden, das
* veranlassen den Listener, auf Ereignisse für _das_ Objekt zu warten.
*
* In beiden Fällen wird der `this'-Wert des Hörers an
* dieses Objekt.
*
* @param {string|Array|Funktion} typeOrListener
* Wenn das erste Argument eine Zeichenkette oder ein Array war, sollte dies die
* hörerfunktion. Andernfalls ist dies eine Zeichenkette oder ein Array von Ereignis
* art(en).
*
* @param {Funktion} [Listener]
* Wenn das erste Argument ein anderes ereignisgesteuertes Objekt war, wird dies
* die Hörerfunktion.
* /
eins (... args) {
const {isTargetingSelf, target, type, listener} = normalizeListenArgs (this, args, 'one');
// Auf dieses ereignisgesteuerte Objekt zielen.
if (isTargetingSelf) {
listen (target, 'one', type, listener);
// Ein anderes ereignisgesteuertes Objekt anvisieren.
} sonst {
// TODO: Dieser Wrapper ist falsch! Es sollte nur
//entferne den Wrapper für den Ereignistyp, der ihn aufgerufen hat.
//Stattdessen werden beim ersten Trigger alle Listener entfernt!
//siehe https://github.com/videojs/video.js/issues/5962
const wrapper = (...largs) => {
this.off(Ziel, Typ, Wrapper);
listener.apply(null, largs);
};
// Verwenden Sie dieselbe Funktions-ID wie der Hörer, damit wir ihn später entfernen können
// unter Verwendung der ID des ursprünglichen Zuhörers.
wrapper.guid = listener.guid;
listen (target, 'one', type, wrapper);
}
},
/**
* Hinzufügen eines Listeners für ein Ereignis (oder Ereignisse) auf diesem Objekt oder einem anderen Ereignis
* objekt. Der Listener wird für das erste ausgelöste Ereignis nur einmal aufgerufen
* dann entfernt.
*
* @param {String|Array|Element|Objekt} targetOrType
* Wenn dies eine Zeichenkette oder ein Array ist, steht es für die Ereignisart(en)
* die den Hörer auslösen werden.
*
* Stattdessen kann hier ein anderes ereignisgesteuertes Objekt übergeben werden, das
* veranlassen den Listener, auf Ereignisse für _das_ Objekt zu warten.
*
* In beiden Fällen wird der `this'-Wert des Hörers an
* dieses Objekt.
*
* @param {string|Array|Funktion} typeOrListener
* Wenn das erste Argument eine Zeichenkette oder ein Array war, sollte dies die
* hörerfunktion. Andernfalls ist dies eine Zeichenkette oder ein Array von Ereignis
* art(en).
*
* @param {Funktion} [Listener]
* Wenn das erste Argument ein anderes ereignisgesteuertes Objekt war, wird dies
* die Hörerfunktion.
* /
irgendein (... args) {
const {isTargetingSelf, target, type, listener} = normalizeListenArgs (this, args, 'any');
// Auf dieses ereignisgesteuerte Objekt zielen.
if (isTargetingSelf) {
listen (target, 'any', type, listener);
// Ein anderes ereignisgesteuertes Objekt anvisieren.
} sonst {
const wrapper = (...largs) => {
this.off(Ziel, Typ, Wrapper);
listener.apply(null, largs);
};
// Verwenden Sie dieselbe Funktions-ID wie der Hörer, damit wir ihn später entfernen können
// unter Verwendung der ID des ursprünglichen Zuhörers.
wrapper.guid = listener.guid;
listen (target, 'any', type, wrapper);
}
},
/**
* Entfernt Listener aus Ereignis (en) eines Ereignisobjekts.
*
* @param {String|Array|Element|Objekt} [TargetOrType]
* Wenn es sich um eine Zeichenfolge oder ein Array handelt, stellt dies die Ereignistypen dar.
*
* Stattdessen kann hier ein anderes Event-Objekt übergeben werden. In diesem Fall
* ALLE 3 Argumente sind _erforderlich_.
*
* @param {String|Array|Funktion} [typeOrListener]
* Wenn das erste Argument eine Zeichenfolge oder ein Array war, kann dies der
* hörerfunktion. Andernfalls ist dies eine Zeichenkette oder ein Array von Ereignis
* art(en).
*
* @param {Funktion} [Listener]
* Wenn das erste Argument ein anderes ereignisgesteuertes Objekt war, wird dies
* die Listener-Funktion; andernfalls sind _alle_ Listener an den gebunden
* Eventtyp (en) werden entfernt.
* /
aus (TargetOrType, TypeOrListener, Listener) {
// Auf dieses ereignisgesteuerte Objekt zielen.
wenn (! targetOrType || isValidEventType (targetOrType) {
events.off (this.EventBusel_, TargetOrType, TypeOrListener);
// Ein anderes ereignisgesteuertes Objekt anvisieren.
} sonst {
const target = TargetOrType;
const type = typeOrListener;
//Scheitere schnell und auf sinnvolle Weise!
validateTarget (target, this, 'off');
validateEventType (type, this, 'off');
validateListener (Listener, dies, 'aus');
//Stelle sicher, dass es mindestens eine GUID gibt, auch wenn die Funktion nicht benutzt wurde
listener = fn.Bind (das, Listener);
//Entferne den Dispose-Listener für dieses Event-Objekt, der angegeben wurde
//dieselbe Guid wie der Event-Listener in on ().
this.off ('entsorgen', Zuhörer);
if (target.nodeName) {
Events.OFF (Ziel, Typ, Listener);
Events.off (target, 'dispone', Listener);
} sonst if (isEvented (target)) {
target.off (Typ, Listener);
target.off ('entsorgen', Zuhörer);
}
}
},
/**
* Löst ein Ereignis für dieses Ereignisobjekt aus, wodurch dessen Listener aufgerufen werden.
*
* @param {string|Object} event
* Ein Ereignistyp oder ein Objekt mit einer Typeigenschaft.
*
* @param {Objekt} [Hash]
* Ein zusätzliches Objekt, das an die Zuhörer weitergegeben werden soll.
*
* @return {boolean}
* Ob das Standardverhalten verhindert wurde oder nicht.
* /
Trigger (Ereignis, Hash) {
validateTarget (this.eventBusel_, das, 'trigger');
const type = Ereignis & Art des Ereignisses! == 'Zeichenfolge'? event.type: Ereignis;
if (!isValidEventType(type)) {
const error = `Ungültiger Ereignistyp für $ {objName (this)} #trigger; `+
'muss eine nicht leere Zeichenfolge oder ein Objekt mit einem Typschlüssel sein, der einen nicht leeren Wert hat. ';
if (Ereignis) {
(this.log || log) .error (Fehler);
} sonst {
einen neuen Fehler auslösen (Fehler);
}
}
return events.trigger (this.EventBusel_, event, hash);
}
};
/**
* Wendet {@link module:evented~eventedMixin|eventedMixin} auf ein Zielobjekt an.
*
* @param {Object} target
* Das Objekt, dem Event-Methoden hinzugefügt werden sollen.
*
* @param {Objekt} [Optionen= {}]
* Optionen zum Anpassen des Mixin-Verhaltens.
*
* @param {string} [Options.eventBusKey]
* Fügt standardmäßig ein `EventBusel_` DOM-Element zum Zielobjekt hinzu,
* der als Eventbus genutzt wird. Wenn das Zielobjekt bereits eine hat
* DOM-Element, das verwendet werden soll, geben Sie hier seinen Schlüssel ein.
*
* @return {Object}
* Das Zielobjekt.
* /
function event (Ziel, Optionen = {}) {
const {eventBusKey} = Optionen;
//Setze oder erstelle den EventBusel_.
wenn (EventBusKey) {
wenn (! ziel [eventBusKey] .nodeName) {
throw new Error (`Der EventBusKey „$ {eventBusKey}“ bezieht sich nicht auf ein Element.`);
}
target.eventBusel_ = Ziel [EventBusKey];
} sonst {
target.eventBusel_ = dom.createEl ('span', {Klassenname: 'vjs-event-bus'});
}
obj.assign (target, eventedMixin);
wenn (target.eventedCallbacks) {
target.eventedCallbacks.forEach (Rückruf) => {
callback();
});
}
//Wenn ein Event-Objekt gelöscht wird, entfernt es alle seine Listener.
target.on ('entsorgen', () => {
ziel.aus ();
[Ziel, ziel.el_, ziel.eventBusel_] .forEach (function (val) {
wenn (val & domData.has (val)) {
domData.delete (Wert);
}
});
window.setTimeout(() => {
target.eventBusel_ = null;
}, 0);
});
ziel zurückgeben;
}
Standardereignisse exportieren;
exportiere {isEvent};
exportiere {addEventedCallback};