mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-16 17:46:17 -08:00
105 lines
2.6 KiB
TypeScript
105 lines
2.6 KiB
TypeScript
import type { SubscriptionHost } from './component/resources'
|
|
import { getScope, isClosing } from './lifecycle/instance'
|
|
import { addClass, removeClass } from './utils'
|
|
|
|
export interface NoticeSink {
|
|
get show(): unknown
|
|
set show(value: unknown)
|
|
}
|
|
|
|
interface NoticeHost extends SubscriptionHost<{ destroy: [] }> {
|
|
constructor: { NOTICE_TIME: number }
|
|
template: { $player: HTMLElement, $noticeInner: HTMLElement }
|
|
}
|
|
|
|
interface NoticeState {
|
|
revision: number
|
|
pending?: object
|
|
}
|
|
|
|
const states = new WeakMap<Notice, NoticeState>()
|
|
|
|
function cancelNotice(notice: Notice): void {
|
|
const state = states.get(notice)!
|
|
state.revision++
|
|
state.pending = undefined
|
|
if (notice.timer !== null) {
|
|
clearTimeout(notice.timer)
|
|
notice.timer = null
|
|
}
|
|
}
|
|
|
|
export default class Notice implements NoticeSink {
|
|
declare art: NoticeHost
|
|
declare timer: ReturnType<typeof setTimeout> | null
|
|
|
|
constructor(art: NoticeHost) {
|
|
this.art = art
|
|
this.timer = null
|
|
states.set(this, { revision: 0 })
|
|
const destroy = () => this.destroy()
|
|
art.on('destroy', destroy)
|
|
getScope(art).add(() => {
|
|
art.off('destroy', destroy)
|
|
})
|
|
getScope(art).add(() => {
|
|
this.destroy()
|
|
})
|
|
}
|
|
|
|
destroy(): void {
|
|
cancelNotice(this)
|
|
}
|
|
|
|
set show(msg: string | Error | false) {
|
|
if (isClosing(this.art))
|
|
return
|
|
const state = states.get(this)!
|
|
state.revision++
|
|
const {
|
|
constructor,
|
|
template: { $player, $noticeInner },
|
|
} = this.art
|
|
|
|
if (msg) {
|
|
cancelNotice(this)
|
|
const revision = state.revision
|
|
const active = () => !isClosing(this.art) && state.revision === revision
|
|
$noticeInner.textContent = msg instanceof Error ? msg.message.trim() : msg
|
|
if (!active())
|
|
return
|
|
addClass($player, 'art-notice-show')
|
|
if (!active())
|
|
return
|
|
const delay = constructor.NOTICE_TIME
|
|
if (!active())
|
|
return
|
|
const pending = {}
|
|
state.pending = pending
|
|
const timer = setTimeout(() => {
|
|
if (isClosing(this.art) || state.pending !== pending)
|
|
return
|
|
state.pending = undefined
|
|
const before = state.revision
|
|
$noticeInner.textContent = ''
|
|
if (!isClosing(this.art) && state.revision === before)
|
|
removeClass($player, 'art-notice-show')
|
|
}, delay)
|
|
if (active())
|
|
this.timer = timer
|
|
else
|
|
clearTimeout(timer)
|
|
}
|
|
else {
|
|
removeClass($player, 'art-notice-show')
|
|
}
|
|
}
|
|
|
|
get show(): boolean {
|
|
const {
|
|
template: { $player },
|
|
} = this.art
|
|
return $player.classList.contains('art-notice-show')
|
|
}
|
|
}
|