diff --git a/packages/core/src/core/media/delegate.ts b/packages/core/src/core/media/delegate.ts index 1c561879..8476097e 100644 --- a/packages/core/src/core/media/delegate.ts +++ b/packages/core/src/core/media/delegate.ts @@ -1,5 +1,7 @@ import type { Constructor } from '@videojs/utils/types'; +import { defineClassPropHooks } from '../utils/define-class-prop-hooks'; + export interface MediaDelegate { attach?(target: EventTarget): void; detach?(): void; @@ -52,6 +54,10 @@ export function MediaDelegateMixin, Delegate exten } } + for (let proto = DelegateClass.prototype; proto && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) { + defineClassPropHooks(DelegateMedia, proto); + } + return DelegateMedia as unknown as Constructor< InstanceType & InstanceType & { diff --git a/packages/core/src/core/media/proxy.ts b/packages/core/src/core/media/proxy.ts index 90b5a58d..ffe60464 100644 --- a/packages/core/src/core/media/proxy.ts +++ b/packages/core/src/core/media/proxy.ts @@ -1,13 +1,8 @@ import type { AnyConstructor, Constructor } from '@videojs/utils/types'; +import { defineClassPropHooks } from '../utils/define-class-prop-hooks'; export interface MediaApiProxyTarget extends EventTarget {} -type API_TYPE = 0 | 1 | 2; - -const API_METHOD: API_TYPE = 0; -const API_GET: API_TYPE = 1; -const API_GET_SET: API_TYPE = 2; - /** * This mixin creates an API from the passed classes and proxies the methods and properties to the attached target. * @@ -24,32 +19,6 @@ export const MediaProxyMixin = ( ...AdditionalClasses: AnyConstructor[] ) => { class MediaApiProxy { - static extends(...MediaApiTargetClasses: AnyConstructor[]) { - const props = getClassProps(...MediaApiTargetClasses); - - for (const [prop, type] of props.entries()) { - if (prop in MediaApiProxy.prototype) continue; - - const config: PropertyDescriptor = {}; - if (type === API_METHOD) { - config.value = function (this: MediaApiProxy, ...args: any[]) { - return this.call(prop as keyof MediaApiProxyTarget, ...args); - }; - } else if (type === API_GET || type === API_GET_SET) { - config.get = function (this: MediaApiProxy) { - return this.get(prop as keyof MediaApiProxyTarget); - }; - if (type === API_GET_SET) { - config.set = function (this: MediaApiProxy, val: any) { - this.set(prop as keyof MediaApiProxyTarget, val); - }; - } - } - - Object.defineProperty(MediaApiProxy.prototype, prop, config); - } - } - #target: MediaApiProxyTarget | null = null; get target() { @@ -82,30 +51,9 @@ export const MediaProxyMixin = ( } } - MediaApiProxy.extends(PrimaryClass, ...AdditionalClasses); + for (const Class of [PrimaryClass, ...AdditionalClasses]) { + defineClassPropHooks(MediaApiProxy, Class.prototype); + } return MediaApiProxy as unknown as Constructor; }; - -/** - * Helper function to get the methods, getters, and setters from a class prototype. - */ -export function getClassProps(...Classes: AnyConstructor[]) { - const props = new Map(); - for (const Class of Classes) { - const names = Object.getOwnPropertyNames(Class.prototype) as (keyof T)[]; - for (const name of names) { - const descriptor = Object.getOwnPropertyDescriptor(Class.prototype, name); - if (typeof descriptor?.value === 'function') { - props.set(name, API_METHOD); - } else if (typeof descriptor?.get === 'function') { - if (typeof descriptor?.set === 'function') { - props.set(name, API_GET_SET); - } else { - props.set(name, API_GET); - } - } - } - } - return props; -} diff --git a/packages/core/src/core/utils/define-class-prop-hooks.ts b/packages/core/src/core/utils/define-class-prop-hooks.ts new file mode 100644 index 00000000..a4bf81ab --- /dev/null +++ b/packages/core/src/core/utils/define-class-prop-hooks.ts @@ -0,0 +1,29 @@ +import type { Constructor } from '@videojs/utils/types'; + +export function defineClassPropHooks>(Class: T, BaseClassProto: PropertyDescriptorMap) { + for (const prop of Object.getOwnPropertyNames(BaseClassProto)) { + if (prop in Class.prototype) continue; + + const descriptor = Object.getOwnPropertyDescriptor(BaseClassProto, prop); + if (!descriptor) continue; + + const config: PropertyDescriptor = {}; + if (typeof descriptor.value === 'function') { + config.value = function (this: InstanceType, ...args: any[]) { + return this.call?.(prop, ...args); + }; + } else if (descriptor.get) { + config.get = function (this: InstanceType) { + return this.get?.(prop); + }; + + if (descriptor.set) { + config.set = function (this: InstanceType, val: any) { + this.set?.(prop, val); + }; + } + } + + Object.defineProperty(Class.prototype, prop, config); + } +} diff --git a/packages/html/src/media/hls-video/index.ts b/packages/html/src/media/hls-video/index.ts index 0544c465..e4c06d77 100644 --- a/packages/html/src/media/hls-video/index.ts +++ b/packages/html/src/media/hls-video/index.ts @@ -27,7 +27,7 @@ export class HlsVideo extends HlsCustomMedia { } disconnectedCallback(): void { - super.disconnectedCallback(); + super.disconnectedCallback?.(); if (!this.hasAttribute('keep-alive')) { this.destroy();