/**
* @파일 플러그인.js
*/
'./mixins/evented'에서 이벤트 가져오기;
'./mixins/stateful'에서 상태 저장 가져오기;
import * as Events from './utils/events';
'./utils/log'에서 로그 가져오기;
'./player'에서 플레이어 가져오기;
/**
* 기본 플러그인 이름.
*
* @사적인
* @끊임없는
* @유형 {문자열}
*/
const BASE_PLUGIN_NAME = '플러그인';
/**
* 플레이어의 활성 플러그인 캐시가 저장되는 키입니다.
*
* @사적인
* @끊임없는
* @유형 {문자열}
*/
const PLUGIN_CACHE_KEY = 'activePlugins_';
/**
* 등록된 플러그인을 비공개 공간에 보관합니다.
*
* @사적인
* @type {객체}
*/
const pluginStorage = {};
/**
* 플러그인 등록 여부를 알려줍니다.
*
* @사적인
* @param {문자열} 이름
* 플러그인의 이름입니다.
*
* @return {부울}
* 플러그인 등록 여부.
*/
const pluginExists = (이름) => pluginStorage.hasOwnProperty(이름);
/**
* 등록된 단일 플러그인을 이름으로 가져옵니다.
*
* @사적인
* @param {문자열} 이름
* 플러그인의 이름입니다.
*
* @return {함수|정의되지 않음}
* 플러그인(또는 정의되지 않음).
*/
const getPlugin = (이름) => 플러그인 존재(이름) ? pluginStorage[이름] : 정의되지 않음;
/**
* 플레이어에서 플러그인을 "활성"으로 표시합니다.
*
* 또한 플레이어에 활성 플러그인을 추적하기 위한 개체가 있는지 확인합니다.
*
* @사적인
* @param {플레이어} 플레이어
* Video.js 플레이어 인스턴스.
*
* @param {문자열} 이름
* 플러그인의 이름입니다.
*/
const markPluginAsActive = (플레이어, 이름) => {
플레이어[PLUGIN_CACHE_KEY] = 플레이어[PLUGIN_CACHE_KEY] || {};
플레이어[PLUGIN_CACHE_KEY][이름] = 참;
};
/**
* 한 쌍의 플러그인 설정 이벤트를 트리거합니다.
*
* @사적인
* @param {플레이어} 플레이어
* Video.js 플레이어 인스턴스.
*
* @param {Plugin~PluginEventHash} 해시
* 플러그인 이벤트 해시.
*
* @param {부울} [이전]
* 참이면 이벤트 이름 앞에 "before"를 붙입니다. 다시 말해서,
* 이것을 사용하여 "pluginsetup" 대신 "beforepluginsetup"을 트리거합니다.
*/
const triggerSetupEvent = (플레이어, 해시, 이전) => {
const eventName = (before ? 'before' : '') + 'pluginsetup';
player.trigger(eventName, hash);
player.trigger(eventName + ':' + hash.name, hash);
};
/**
* 기본 플러그인 기능을 취하고 표시하는 래퍼 기능을 반환합니다.
* 플러그인이 활성화된 플레이어에서.
*
* @사적인
* @param {문자열} 이름
* 플러그인의 이름입니다.
*
* @param {함수} 플러그인
* 기본 플러그인.
*
* @return {함수}
* 주어진 플러그인에 대한 래퍼 함수.
*/
const createBasicPlugin = function(이름, 플러그인) {
const basicPluginWrapper = 함수() {
// 플레이어에서 "beforepluginsetup" 및 "pluginsetup" 이벤트를 트리거합니다.
// 무관하지만 해시가 제공된 해시와 일치하기를 원합니다.
// 고급 플러그인용.
//
// 여기서 직관에 반할 가능성이 있는 유일한 것은
// "pluginsetup" 이벤트는 `plugin` 함수에 의해 반환된 값입니다.
triggerSetupEvent(this, {name, plugin, instance: null}, true);
const 인스턴스 = plugin.apply(this, 인수);
markPluginAsActive(this, name);
triggerSetupEvent(this, {이름, 플러그인, 인스턴스});
반환 인스턴스;
};
Object.keys(플러그인).forEach(function(prop) {
basicPluginWrapper[prop] = 플러그인[prop];
});
basicPluginWrapper를 반환합니다.
};
/**
* 플러그인 하위 클래스를 가져오고 생성을 위한 팩토리 함수를 반환합니다.
* 인스턴스.
*
* 이 팩토리 함수는 요청된 인스턴스로 자신을 대체합니다.
* 플러그인의 하위 클래스.
*
* @사적인
* @param {문자열} 이름
* 플러그인의 이름입니다.
*
* @param {플러그인} PluginSubClass
* 고급 플러그인.
*
* @return {함수}
*/
const createPluginFactory = (이름, PluginSubClass) => {
// 플러그인 프로토타입에 `name` 속성을 추가하여 각 플러그인이
// 자신을 이름으로 참조합니다.
PluginSubClass.prototype.name = 이름;
반환 함수(...인수) {
triggerSetupEvent(이것, {이름, 플러그인: PluginSubClass, 인스턴스: null}, true);
const instance = new PluginSubClass(...[this, ...args]);
// 플러그인은 현재 인스턴스를 반환하는 함수로 대체됩니다.
이[이름] = () => 사례;
triggerSetupEvent(this, instance.getEventHash());
반환 인스턴스;
};
};
/**
* 모든 고급 플러그인의 상위 클래스.
*
* @mixes 모듈:evented~EventedMixin
* @mixes 모듈:stateful~StatefulMixin
* @fires Player#beforepluginsetup
* @fires Player#beforepluginsetup:$name
* @fires Player#pluginsetup
* @fires Player#pluginsetup:$name
* @listens Player#dispose
* @throws {오류}
* 기본 {@link Plugin} 클래스를 인스턴스화하려는 경우
* 하위 클래스를 통하지 않고 직접.
*/
클래스 플러그인 {
/**
* 이 클래스의 인스턴스를 만듭니다.
*
* 하위 클래스는 플러그인이 제대로 초기화되도록 `super`를 호출해야 합니다.
*
* @param {플레이어} 플레이어
* Video.js 플레이어 인스턴스.
*/
생성자(플레이어) {
if (this.constructor === 플러그인) {
throw new Error('플러그인은 하위 클래스여야 합니다. 직접 인스턴스화할 수 없습니다.');
}
this.player = 플레이어;
if (!this.log) {
this.log = this.player.log.createLogger(this.name);
}
// 이 객체를 이벤트로 만들지만 추가된 `trigger` 메서드를 제거하여
// 대신 프로토타입 버전을 사용합니다.
이벤트(이);
this.trigger 삭제;
stateful(this, this.constructor.defaultState);
markPluginAsActive(player, this.name);
// dispose 메서드를 자동 바인딩하여 리스너로 사용하고 바인딩을 해제할 수 있도록 합니다.
// 나중에 쉽게.
this.dispose = this.dispose.bind(this);
// 플레이어가 삭제되면 플러그인을 삭제합니다.
player.on('dispose', this.dispose);
}
/**
* 설정된 플러그인 버전 가져오기 < 플러그인 이름> .버전
*/
버전() {
this.constructor.VERSION을 반환합니다.
}
/**
* 플러그인에 의해 트리거되는 각 이벤트에는 다음과 같은 추가 데이터 해시가 포함됩니다.
* 기존 속성.
*
* 이것은 해당 객체를 반환하거나 기존 해시를 변경합니다.
*
* @param {객체} [해시={}]
* 이벤트 해시로 사용할 객체.
*
* @return {Plugin~PluginEventHash}
* 제공된 속성이 혼합된 이벤트 해시 개체입니다.
*/
getEventHash(해시 = {}) {
hash.name = this.name;
hash.plugin = this.constructor;
해시.인스턴스 = this;
반환 해시;
}
/**
* 플러그인 개체에서 이벤트를 트리거하고 재정의합니다.
* {@link module:evented~EventedMixin.trigger|EventedMixin.trigger}.
*
* @param {문자열|객체} 이벤트
* type 속성이 있는 이벤트 유형 또는 객체.
*
* @param {객체} [해시={}]
* 병합할 추가 데이터 해시
* {@link Plugin~PluginEventHash|PluginEventHash}.
*
* @return {부울}
* 불이행 방지 여부.
*/
트리거(이벤트, 해시 = {}) {
return Events.trigger(this.eventBusEl_, event, this.getEventHash(hash));
}
/**
* 플러그인에서 "statechanged" 이벤트를 처리합니다. 기본적으로 작동하지 않음, 재정의
* 서브클래싱.
*
* @추상적인
* @param {이벤트} 전자
* "statechanged" 이벤트에서 제공하는 이벤트 개체입니다.
*
* @param {Object} e.changes
* "statechanged"로 발생한 변경 사항을 설명하는 객체
* 이벤트.
*/
handleStateChanged(e) {}
/**
* 플러그인을 폐기합니다.
*
* 하위 클래스는 원하는 경우 이를 재정의할 수 있지만 안전을 위해
* "dispose" 이벤트를 구독하는 것이 가장 좋습니다.
*
* @fires 플러그인#dispose
*/
폐기() {
const {이름, 플레이어} = this;
/**
* 고급 플러그인이 곧 폐기될 것이라는 신호입니다.
*
* @event 플러그인#dispose
* @type {이벤트대상~이벤트}
*/
this.trigger('처리');
this.off();
player.off('dispose', this.dispose);
// 정리를 통해 메모리 누수 원인을 제거합니다.
// 플레이어와 플러그인 인스턴스 사이의 참조 및 무효화
// 플러그인의 상태 및 메서드를 throw하는 함수로 대체합니다.
플레이어[PLUGIN_CACHE_KEY][이름] = 거짓;
this.player = this.state = null;
// 마지막으로 플레이어의 플러그인 이름을 새 팩토리로 바꿉니다.
// 함수를 사용하여 플러그인을 다시 설정할 수 있습니다.
player[이름] = createPluginFactory(이름, pluginStorage[이름]);
}
/**
* 플러그인이 기본 플러그인인지 결정합니다(예: `Plugin`의 하위 클래스가 아님).
*
* @param {string|Function} 플러그인
* 문자열인 경우 플러그인 이름과 일치합니다. 함수라면,
* 직접 테스트했습니다.
*
* @return {부울}
* 플러그인이 기본 플러그인인지 여부.
*/
정적 isBasic(플러그인) {
const p = (플러그인 유형 === '문자열') ? getPlugin(플러그인) : 플러그인;
return typeof p === '함수' && !Plugin.prototype.isPrototypeOf(p.prototype);
}
/**
* Video.js 플러그인을 등록합니다.
*
* @param {문자열} 이름
* 등록할 플러그인의 이름. 문자열이어야 하며
* 기존 플러그인 또는 `Player`의 메서드와 일치하지 않아야 합니다.
* 프로토타입.
*
* @param {함수} 플러그인
* `Plugin`의 하위 클래스 또는 기본 플러그인의 기능.
*
* @return {함수}
* 고급 플러그인의 경우 해당 플러그인의 공장 기능. 을 위한
* 기본 플러그인, 플러그인을 초기화하는 래퍼 함수.
*/
static registerPlugin(이름, 플러그인) {
if (이름 유형 !== '문자열') {
throw new Error(`잘못된 플러그인 이름, "${name}"은 문자열이어야 합니다. ${typeof name}이었습니다.`);
}
if (pluginExists(이름)) {
log.warn(`"${name}" 플러그인이 이미 존재합니다. 플러그인 재등록을 피하고 싶을 수도 있습니다!`);
} 그렇지 않으면 (Player.prototype.hasOwnProperty(이름)) {
throw new Error(`잘못된 플러그인 이름, "${name}", 기존 플레이어 메서드와 이름을 공유할 수 없습니다!`);
}
if (플러그인 유형 !== '함수') {
throw new Error(`"${name}"에 대한 불법 플러그인, 함수여야 합니다. ${typeof plugin}이었습니다.`);
}
pluginStorage[이름] = 플러그인;
// 모든 하위 클래스 플러그인에 대한 플레이어 프로토타입 메서드를 추가합니다(단,
// 기본 플러그인 클래스).
if (이름 !== BASE_PLUGIN_NAME) {
if (Plugin.isBasic(플러그인)) {
Player.prototype[name] = createBasicPlugin(이름, 플러그인);
} else {
Player.prototype[name] = createPluginFactory(이름, 플러그인);
}
}
반환 플러그인;
}
/**
* Video.js 플러그인 등록을 취소합니다.
*
* @param {문자열} 이름
* 등록을 해제할 플러그인의 이름입니다. 다음 문자열이어야 합니다.
* 기존 플러그인과 일치합니다.
*
* @throws {오류}
* 기본 플러그인 등록 해제를 시도한 경우.
*/
정적 deregisterPlugin(이름) {
if (이름 === BASE_PLUGIN_NAME) {
throw new Error('기본 플러그인 등록을 취소할 수 없습니다.');
}
if (pluginExists(이름)) {
플러그인 저장소[이름] 삭제;
삭제 Player.prototype[이름];
}
}
/**
* 여러 Video.js 플러그인을 포함하는 개체를 가져옵니다.
*
* @param {배열} [이름]
* 제공된 경우 플러그인 이름의 배열이어야 합니다. 기본값은 _all_
* 플러그인 이름.
*
* @return {객체|정의되지 않음}
* 플러그인 이름과 관련된 플러그인을 포함하는 개체 또는
* 일치하는 플러그인이 존재하지 않는 경우 `정의되지 않음`).
*/
정적 getPlugins(이름 = Object.keys(pluginStorage)) {
결과를 보자;
이름.forEach(이름 => {
const 플러그인 = getPlugin(이름);
if (플러그인) {
결과 = 결과 || {};
결과[이름] = 플러그인;
}
});
반환 결과;
}
/**
* 가능한 경우 플러그인 버전을 가져옵니다.
*
* @param {문자열} 이름
* 플러그인의 이름입니다.
*
* @return {문자열}
* 플러그인의 버전 또는 빈 문자열.
*/
정적 getPluginVersion(이름) {
const 플러그인 = getPlugin(이름);
반환 플러그인 && 플러그인.버전 || '';
}
}
/**
* 존재하는 경우 이름으로 플러그인을 가져옵니다.
*
* @정적
* @method getPlugin
* @memberOf 플러그인
* @param {문자열} 이름
* 플러그인의 이름입니다.
*
* @returns {함수|정의되지 않음}
* 플러그인(또는 `정의되지 않음`).
*/
Plugin.getPlugin = getPlugin;
/**
* 등록된 기본 플러그인 클래스의 이름입니다.
*
* @유형 {문자열}
*/
Plugin.BASE_PLUGIN_NAME = BASE_PLUGIN_NAME;
Plugin.registerPlugin(BASE_PLUGIN_NAME, 플러그인);
/**
* player.js에 문서화됨
*
* @무시하다
*/
Player.prototype.usingPlugin = 함수(이름) {
반환 !!이[PLUGIN_CACHE_KEY] && this[PLUGIN_CACHE_KEY][이름] === 참;
};
/**
* player.js에 문서화됨
*
* @무시하다
*/
Player.prototype.hasPlugin = 함수(이름) {
return !!pluginExists(이름);
};
기본 플러그인 내보내기;
/**
* 플러그인이 플레이어에 설정되려고 한다는 신호입니다.
*
* @event Player#beforepluginsetup
* @type {Plugin~PluginEventHash}
*/
/**
* 플러그인이 플레이어에 설치될 예정임을 이름으로 알립니다. 이름
*는 플러그인의 이름입니다.
*
* @event Player#beforepluginsetup:$name
* @type {Plugin~PluginEventHash}
*/
/**
* 플러그인이 방금 플레이어에 설정되었음을 알립니다.
*
* @event Player#pluginsetup
* @type {Plugin~PluginEventHash}
*/
/**
* 플러그인이 방금 플레이어에 설정되었음을 이름으로 알립니다. 이름
*는 플러그인의 이름입니다.
*
* @event Player#pluginsetup:$name
* @type {Plugin~PluginEventHash}
*/
/**
* @typedef {객체} Plugin~PluginEventHash
*
* @property {문자열} 인스턴스
* 기본 플러그인의 경우 플러그인 함수의 반환 값입니다. 을 위한
* 고급 플러그인, 이벤트가 발생하는 플러그인 인스턴스.
*
* @property {문자열} 이름
* 플러그인의 이름입니다.
*
* @property {문자열} 플러그인
* 기본 플러그인의 경우 플러그인 기능. 고급 플러그인의 경우
* 플러그인 클래스/생성자.
*/