mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-11 22:06:17 -08:00
123 lines
3.8 KiB
TypeScript
123 lines
3.8 KiB
TypeScript
import type ArtplayerToolThumbnail from './index'
|
|
import type { InputOptions } from './types'
|
|
import { cancellation, stateFor } from './lifecycle'
|
|
import { normalizePolicy } from './policy'
|
|
|
|
type Registration = readonly [name: string, callback: EventListener]
|
|
interface InputRecord {
|
|
input: HTMLInputElement
|
|
wrapper: HTMLElement | null
|
|
position: string
|
|
listeners: Registration[]
|
|
callbacks: Registration[] | null
|
|
}
|
|
|
|
const inputs = new WeakMap<ArtplayerToolThumbnail, InputRecord>()
|
|
|
|
function release(record: InputRecord) {
|
|
let failure: unknown
|
|
for (const [name, callback] of record.listeners.splice(0)) {
|
|
try {
|
|
record.input.removeEventListener(name, callback)
|
|
}
|
|
catch (error) {
|
|
failure ||= error
|
|
}
|
|
}
|
|
if (record.wrapper) {
|
|
try {
|
|
if (record.input.parentNode)
|
|
record.input.parentNode.removeChild(record.input)
|
|
}
|
|
catch (error) {
|
|
failure ||= error
|
|
}
|
|
if (record.wrapper.style.position === 'relative')
|
|
record.wrapper.style.position = record.position
|
|
}
|
|
if (failure)
|
|
throw failure
|
|
}
|
|
|
|
function connect(record: InputRecord, callbacks: Registration[]) {
|
|
try {
|
|
for (const [name, callback] of callbacks) {
|
|
record.listeners.push([name, callback])
|
|
record.input.addEventListener(name, callback)
|
|
}
|
|
}
|
|
catch (error) {
|
|
try {
|
|
release(record)
|
|
}
|
|
catch {}
|
|
throw error
|
|
}
|
|
}
|
|
|
|
export function setupInput(tool: ArtplayerToolThumbnail, patch: InputOptions) {
|
|
const state = stateFor(tool)
|
|
const epoch = ++state.inputEpoch
|
|
const current = () => !state.closed && state.inputEpoch === epoch
|
|
const option = Object.assign({}, tool.option, patch)
|
|
const target = option.fileInput!
|
|
tool.errorHandle(target instanceof Element, 'The \'fileInput\' is not a Element')
|
|
normalizePolicy(option, (condition, message) => tool.errorHandle(condition, message))
|
|
if (!current())
|
|
throw cancellation('input setup superseded')
|
|
|
|
const previous = inputs.get(tool)
|
|
if (previous && (target === previous.input || target === previous.wrapper)) {
|
|
option.fileInput = previous.input
|
|
tool.option = option
|
|
return option
|
|
}
|
|
// A wrapper is replaced by its owned file input before the record is committed.
|
|
const record: InputRecord = { input: target as HTMLInputElement, wrapper: null, position: '', listeners: [], callbacks: previous?.callbacks || null }
|
|
try {
|
|
if (!(target.tagName === 'INPUT' && (target as HTMLInputElement).type === 'file')) {
|
|
record.wrapper = target
|
|
record.position = target.style.position
|
|
record.input = document.createElement('input')
|
|
record.input.type = 'file'
|
|
Object.assign(record.input.style, { position: 'absolute', width: '100%', height: '100%', left: '0', top: '0', right: '0', bottom: '0', opacity: '0' })
|
|
target.style.position = 'relative'
|
|
target.appendChild(record.input)
|
|
}
|
|
if (!current())
|
|
throw cancellation('input setup superseded')
|
|
if (record.callbacks)
|
|
connect(record, record.callbacks)
|
|
if (!current())
|
|
throw cancellation('input setup superseded')
|
|
}
|
|
catch (error) {
|
|
try {
|
|
release(record)
|
|
}
|
|
catch {}
|
|
throw error
|
|
}
|
|
option.fileInput = record.input
|
|
inputs.set(tool, record)
|
|
tool.option = option
|
|
if (previous)
|
|
release(previous)
|
|
return option
|
|
}
|
|
|
|
export function connectInput(tool: ArtplayerToolThumbnail, dragover: (event: DragEvent) => void) {
|
|
const record = inputs.get(tool)!
|
|
// These callbacks are registered only for their matching DOM event names.
|
|
record.callbacks = [['change', tool.inputChange], ['dragover', dragover as EventListener], ['drop', tool.ondrop as EventListener]]
|
|
connect(record, record.callbacks)
|
|
}
|
|
|
|
export function releaseInput(tool: ArtplayerToolThumbnail) {
|
|
const record = inputs.get(tool)
|
|
if (!record)
|
|
return
|
|
inputs.delete(tool)
|
|
release(record)
|
|
}
|