build all

Refactor utility functions for improved readability and consistency

- Updated compatibility.js to use consistent line endings and formatting.
- Refactored component.js for better readability and structure, including consistent use of arrow functions and binding.
- Simplified dom.js functions with consistent formatting and improved readability.
- Enhanced emitter.js with consistent formatting and arrow function usage.
- Streamlined error.js for improved readability and consistency.
- Refactored file.js to use consistent formatting and improved readability.
- Improved format.js functions for better readability and consistency.
- Updated index.js to maintain consistent export formatting.
- Refactored property.js for improved readability and consistency.
- Enhanced subtitle.js with consistent formatting and improved readability.
- Refactored time.js for better readability and consistent formatting.

fix: update lint script to target only source files for consistency

Revert "fix: restore export statements for various plugins and update type definitions for better clarity"

This reverts commit b5e969d81ec765cd8a34b06e6ef4f232ef25087f.

fix: restore export statements for various plugins and update type definitions for better clarity

Refactor type definitions to use interfaces instead of type aliases for better extensibility and clarity across i18n, icons, option, player, quality, setting, subtitle, template, and utils modules.
This commit is contained in:
Harvey Zack committed 2025-08-03 13:17:33 +08:00
1 parent 532dd67cfd
commit 35ad9883af
447 files changed
+18248 -17946

No files matched your search

+10 -10
View File
@@ -1,13 +1,13 @@
import { append } from '../utils';
import { append } from '../utils'
export default function airplay(option) {
return (art) => ({
...option,
tooltip: art.i18n.get('AirPlay'),
mounted: ($control) => {
const { proxy, icons } = art;
append($control, icons.airplay);
proxy($control, 'click', () => art.airplay());
},
});
return art => ({
...option,
tooltip: art.i18n.get('AirPlay'),
mounted: ($control) => {
const { proxy, icons } = art
append($control, icons.airplay)
proxy($control, 'click', () => art.airplay())
},
})
}
+26 -25
View File
@@ -1,31 +1,32 @@
import { append, tooltip, setStyle } from '../utils';
import { append, setStyle, tooltip } from '../utils'
export default function fullscreen(option) {
return (art) => ({
...option,
tooltip: art.i18n.get('Fullscreen'),
mounted: ($control) => {
const { proxy, icons, i18n } = art;
return art => ({
...option,
tooltip: art.i18n.get('Fullscreen'),
mounted: ($control) => {
const { proxy, icons, i18n } = art
const $fullscreenOn = append($control, icons.fullscreenOn);
const $fullscreenOff = append($control, icons.fullscreenOff);
setStyle($fullscreenOff, 'display', 'none');
const $fullscreenOn = append($control, icons.fullscreenOn)
const $fullscreenOff = append($control, icons.fullscreenOff)
setStyle($fullscreenOff, 'display', 'none')
proxy($control, 'click', () => {
art.fullscreen = !art.fullscreen;
});
proxy($control, 'click', () => {
art.fullscreen = !art.fullscreen
})
art.on('fullscreen', (state) => {
if (state) {
tooltip($control, i18n.get('Exit Fullscreen'));
setStyle($fullscreenOn, 'display', 'none');
setStyle($fullscreenOff, 'display', 'inline-flex');
} else {
tooltip($control, i18n.get('Fullscreen'));
setStyle($fullscreenOn, 'display', 'inline-flex');
setStyle($fullscreenOff, 'display', 'none');
}
});
},
});
art.on('fullscreen', (state) => {
if (state) {
tooltip($control, i18n.get('Exit Fullscreen'))
setStyle($fullscreenOn, 'display', 'none')
setStyle($fullscreenOff, 'display', 'inline-flex')
}
else {
tooltip($control, i18n.get('Fullscreen'))
setStyle($fullscreenOn, 'display', 'inline-flex')
setStyle($fullscreenOff, 'display', 'none')
}
})
},
})
}
+26 -25
View File
@@ -1,31 +1,32 @@
import { append, tooltip, setStyle } from '../utils';
import { append, setStyle, tooltip } from '../utils'
export default function fullscreenWeb(option) {
return (art) => ({
...option,
tooltip: art.i18n.get('Web Fullscreen'),
mounted: ($control) => {
const { proxy, icons, i18n } = art;
return art => ({
...option,
tooltip: art.i18n.get('Web Fullscreen'),
mounted: ($control) => {
const { proxy, icons, i18n } = art
const $fullscreenWebOn = append($control, icons.fullscreenWebOn);
const $fullscreenWebOff = append($control, icons.fullscreenWebOff);
setStyle($fullscreenWebOff, 'display', 'none');
const $fullscreenWebOn = append($control, icons.fullscreenWebOn)
const $fullscreenWebOff = append($control, icons.fullscreenWebOff)
setStyle($fullscreenWebOff, 'display', 'none')
proxy($control, 'click', () => {
art.fullscreenWeb = !art.fullscreenWeb;
});
proxy($control, 'click', () => {
art.fullscreenWeb = !art.fullscreenWeb
})
art.on('fullscreenWeb', (value) => {
if (value) {
tooltip($control, i18n.get('Exit Web Fullscreen'));
setStyle($fullscreenWebOn, 'display', 'none');
setStyle($fullscreenWebOff, 'display', 'inline-flex');
} else {
tooltip($control, i18n.get('Web Fullscreen'));
setStyle($fullscreenWebOn, 'display', 'inline-flex');
setStyle($fullscreenWebOff, 'display', 'none');
}
});
},
});
art.on('fullscreenWeb', (value) => {
if (value) {
tooltip($control, i18n.get('Exit Web Fullscreen'))
setStyle($fullscreenWebOn, 'display', 'none')
setStyle($fullscreenWebOff, 'display', 'inline-flex')
}
else {
tooltip($control, i18n.get('Web Fullscreen'))
setStyle($fullscreenWebOn, 'display', 'inline-flex')
setStyle($fullscreenWebOff, 'display', 'none')
}
})
},
})
}
+260 -257
View File
@@ -1,281 +1,284 @@
import Component from '../utils/component';
import fullscreen from './fullscreen';
import fullscreenWeb from './fullscreenWeb';
import pip from './pip';
import playAndPause from './playAndPause';
import progress from './progress';
import time from './time';
import volume from './volume';
import setting from './setting';
import screenshot from './screenshot';
import airplay from './airplay';
import {
def,
sleep,
append,
addClass,
isMobile,
removeClass,
errorHandle,
inverseClass,
createElement,
includeFromEvent,
getComposedPath,
} from '../utils';
addClass,
append,
createElement,
def,
errorHandle,
getComposedPath,
includeFromEvent,
inverseClass,
isMobile,
removeClass,
sleep,
} from '../utils'
import Component from '../utils/component'
import airplay from './airplay'
import fullscreen from './fullscreen'
import fullscreenWeb from './fullscreenWeb'
import pip from './pip'
import playAndPause from './playAndPause'
import progress from './progress'
import screenshot from './screenshot'
import setting from './setting'
import time from './time'
import volume from './volume'
export default class Control extends Component {
constructor(art) {
super(art);
constructor(art) {
super(art)
this.isHover = false;
this.name = 'control';
this.timer = Date.now();
this.isHover = false
this.name = 'control'
this.timer = Date.now()
const { constructor } = art;
const { $player, $bottom } = this.art.template;
const { constructor } = art
const { $player, $bottom } = this.art.template
art.on('mousemove', () => {
if (!isMobile) {
this.show = true;
}
});
art.on('mousemove', () => {
if (!isMobile) {
this.show = true
}
})
art.on('click', () => {
if (isMobile) {
this.toggle();
} else {
this.show = true;
}
});
art.on('click', () => {
if (isMobile) {
this.toggle()
}
else {
this.show = true
}
})
art.on('document:mousemove', (event) => {
this.isHover = includeFromEvent(event, $bottom);
});
art.on('document:mousemove', (event) => {
this.isHover = includeFromEvent(event, $bottom)
})
art.on('video:timeupdate', () => {
if (
!art.setting.show &&
!this.isHover &&
!art.isInput &&
art.playing &&
this.show &&
Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME
) {
this.show = false;
}
});
art.on('video:timeupdate', () => {
if (
!art.setting.show
&& !this.isHover
&& !art.isInput
&& art.playing
&& this.show
&& Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME
) {
this.show = false
}
})
art.on('control', (state) => {
if (state) {
removeClass($player, 'art-hide-cursor');
addClass($player, 'art-hover');
this.timer = Date.now();
} else {
addClass($player, 'art-hide-cursor');
removeClass($player, 'art-hover');
}
});
art.on('control', (state) => {
if (state) {
removeClass($player, 'art-hide-cursor')
addClass($player, 'art-hover')
this.timer = Date.now()
}
else {
addClass($player, 'art-hide-cursor')
removeClass($player, 'art-hover')
}
})
this.init();
this.init()
}
init() {
const { option } = this.art
if (!option.isLive) {
this.add(
progress({
name: 'progress',
position: 'top',
index: 10,
}),
)
}
init() {
const { option } = this.art;
this.add({
name: 'thumbnails',
position: 'top',
index: 20,
})
if (!option.isLive) {
this.add(
progress({
name: 'progress',
position: 'top',
index: 10,
}),
);
}
this.add(
playAndPause({
name: 'playAndPause',
position: 'left',
index: 10,
}),
)
this.add({
name: 'thumbnails',
position: 'top',
index: 20,
});
this.add(
volume({
name: 'volume',
position: 'left',
index: 20,
}),
)
this.add(
playAndPause({
name: 'playAndPause',
position: 'left',
index: 10,
}),
);
this.add(
volume({
name: 'volume',
position: 'left',
index: 20,
}),
);
if (!option.isLive) {
this.add(
time({
name: 'time',
position: 'left',
index: 30,
}),
);
}
if (option.quality.length) {
sleep().then(() => {
this.art.quality = option.quality;
});
}
if (option.screenshot && !isMobile) {
this.add(
screenshot({
name: 'screenshot',
position: 'right',
index: 20,
}),
);
}
if (option.setting) {
this.add(
setting({
name: 'setting',
position: 'right',
index: 30,
}),
);
}
if (option.pip) {
this.add(
pip({
name: 'pip',
position: 'right',
index: 40,
}),
);
}
if (option.airplay && window.WebKitPlaybackTargetAvailabilityEvent) {
this.add(
airplay({
name: 'airplay',
position: 'right',
index: 50,
}),
);
}
if (option.fullscreenWeb) {
this.add(
fullscreenWeb({
name: 'fullscreenWeb',
position: 'right',
index: 60,
}),
);
}
if (option.fullscreen) {
this.add(
fullscreen({
name: 'fullscreen',
position: 'right',
index: 70,
}),
);
}
for (let index = 0; index < option.controls.length; index++) {
this.add(option.controls[index]);
}
if (!option.isLive) {
this.add(
time({
name: 'time',
position: 'left',
index: 30,
}),
)
}
add(getOption) {
const option = typeof getOption === 'function' ? getOption(this.art) : getOption;
const { $progress, $controlsLeft, $controlsRight } = this.art.template;
switch (option.position) {
case 'top':
this.$parent = $progress;
break;
case 'left':
this.$parent = $controlsLeft;
break;
case 'right':
this.$parent = $controlsRight;
break;
default:
errorHandle(false, `Control option.position must one of 'top', 'left', 'right'`);
break;
}
super.add(option);
if (option.quality.length) {
sleep().then(() => {
this.art.quality = option.quality
})
}
check(target) {
target.$control_value.innerHTML = target.html;
for (let index = 0; index < target.$control_option.length; index++) {
const item = target.$control_option[index];
item.default = item === target;
if (item.default) {
inverseClass(item.$control_item, 'art-current');
}
}
if (option.screenshot && !isMobile) {
this.add(
screenshot({
name: 'screenshot',
position: 'right',
index: 20,
}),
)
}
selector(option, $ref, events) {
const { proxy } = this.art.events;
addClass($ref, 'art-control-selector');
const $value = createElement('div');
addClass($value, 'art-selector-value');
append($value, option.html);
$ref.innerText = '';
append($ref, $value);
const $list = createElement('div');
addClass($list, 'art-selector-list');
append($ref, $list);
for (let index = 0; index < option.selector.length; index++) {
const item = option.selector[index];
const $item = createElement('div');
addClass($item, 'art-selector-item');
if (item.default) addClass($item, 'art-current');
$item.dataset.index = index;
$item.dataset.value = item.value;
$item.innerHTML = item.html;
append($list, $item);
def(item, '$control_option', {
get: () => option.selector,
});
def(item, '$control_item', {
get: () => $item,
});
def(item, '$control_value', {
get: () => $value,
});
}
const event = proxy($list, 'click', async (event) => {
const path = getComposedPath(event);
const item = option.selector.find(
(item) => item.$control_item === path.find(($item) => item.$control_item === $item),
);
this.check(item);
if (option.onSelect) {
$value.innerHTML = await option.onSelect.call(this.art, item, item.$control_item, event);
}
});
events.push(event);
if (option.setting) {
this.add(
setting({
name: 'setting',
position: 'right',
index: 30,
}),
)
}
if (option.pip) {
this.add(
pip({
name: 'pip',
position: 'right',
index: 40,
}),
)
}
if (option.airplay && window.WebKitPlaybackTargetAvailabilityEvent) {
this.add(
airplay({
name: 'airplay',
position: 'right',
index: 50,
}),
)
}
if (option.fullscreenWeb) {
this.add(
fullscreenWeb({
name: 'fullscreenWeb',
position: 'right',
index: 60,
}),
)
}
if (option.fullscreen) {
this.add(
fullscreen({
name: 'fullscreen',
position: 'right',
index: 70,
}),
)
}
for (let index = 0; index < option.controls.length; index++) {
this.add(option.controls[index])
}
}
add(getOption) {
const option = typeof getOption === 'function' ? getOption(this.art) : getOption
const { $progress, $controlsLeft, $controlsRight } = this.art.template
switch (option.position) {
case 'top':
this.$parent = $progress
break
case 'left':
this.$parent = $controlsLeft
break
case 'right':
this.$parent = $controlsRight
break
default:
errorHandle(false, `Control option.position must one of 'top', 'left', 'right'`)
break
}
super.add(option)
}
check(target) {
target.$control_value.innerHTML = target.html
for (let index = 0; index < target.$control_option.length; index++) {
const item = target.$control_option[index]
item.default = item === target
if (item.default) {
inverseClass(item.$control_item, 'art-current')
}
}
}
selector(option, $ref, events) {
const { proxy } = this.art.events
addClass($ref, 'art-control-selector')
const $value = createElement('div')
addClass($value, 'art-selector-value')
append($value, option.html)
$ref.textContent = ''
append($ref, $value)
const $list = createElement('div')
addClass($list, 'art-selector-list')
append($ref, $list)
for (let index = 0; index < option.selector.length; index++) {
const item = option.selector[index]
const $item = createElement('div')
addClass($item, 'art-selector-item')
if (item.default)
addClass($item, 'art-current')
$item.dataset.index = index
$item.dataset.value = item.value
$item.innerHTML = item.html
append($list, $item)
def(item, '$control_option', {
get: () => option.selector,
})
def(item, '$control_item', {
get: () => $item,
})
def(item, '$control_value', {
get: () => $value,
})
}
const event = proxy($list, 'click', async (event) => {
const path = getComposedPath(event)
const item = option.selector.find(
item => item.$control_item === path.find($item => item.$control_item === $item),
)
this.check(item)
if (option.onSelect) {
$value.innerHTML = await option.onSelect.call(this.art, item, item.$control_item, event)
}
})
events.push(event)
}
}
+15 -15
View File
@@ -1,21 +1,21 @@
import { append, tooltip } from '../utils';
import { append, tooltip } from '../utils'
export default function pip(option) {
return (art) => ({
...option,
tooltip: art.i18n.get('PIP Mode'),
mounted: ($control) => {
const { proxy, icons, i18n } = art;
return art => ({
...option,
tooltip: art.i18n.get('PIP Mode'),
mounted: ($control) => {
const { proxy, icons, i18n } = art
append($control, icons.pip);
append($control, icons.pip)
proxy($control, 'click', () => {
art.pip = !art.pip;
});
proxy($control, 'click', () => {
art.pip = !art.pip
})
art.on('pip', (value) => {
tooltip($control, i18n.get(value ? 'Exit PIP Mode' : 'PIP Mode'));
});
},
});
art.on('pip', (value) => {
tooltip($control, i18n.get(value ? 'Exit PIP Mode' : 'PIP Mode'))
})
},
})
}
+37 -36
View File
@@ -1,47 +1,48 @@
import { append, tooltip, setStyle } from '../utils';
import { append, setStyle, tooltip } from '../utils'
export default function playAndPause(option) {
return (art) => ({
...option,
mounted: ($control) => {
const { proxy, icons, i18n } = art;
return art => ({
...option,
mounted: ($control) => {
const { proxy, icons, i18n } = art
const $play = append($control, icons.play);
const $pause = append($control, icons.pause);
tooltip($play, i18n.get('Play'));
tooltip($pause, i18n.get('Pause'));
const $play = append($control, icons.play)
const $pause = append($control, icons.pause)
tooltip($play, i18n.get('Play'))
tooltip($pause, i18n.get('Pause'))
proxy($play, 'click', () => {
art.play();
});
proxy($play, 'click', () => {
art.play()
})
proxy($pause, 'click', () => {
art.pause();
});
proxy($pause, 'click', () => {
art.pause()
})
function showPlay() {
setStyle($play, 'display', 'flex');
setStyle($pause, 'display', 'none');
}
function showPlay() {
setStyle($play, 'display', 'flex')
setStyle($pause, 'display', 'none')
}
function showPause() {
setStyle($play, 'display', 'none');
setStyle($pause, 'display', 'flex');
}
function showPause() {
setStyle($play, 'display', 'none')
setStyle($pause, 'display', 'flex')
}
if (art.playing) {
showPause();
} else {
showPlay();
}
if (art.playing) {
showPause()
}
else {
showPlay()
}
art.on('video:playing', () => {
showPause();
});
art.on('video:playing', () => {
showPause()
})
art.on('video:pause', () => {
showPlay();
});
},
});
art.on('video:pause', () => {
showPlay()
})
},
})
}
+161 -153
View File
@@ -1,36 +1,37 @@
import { query, clamp, append, setStyle, secondToTime, includeFromEvent, isMobile, getRect } from '../utils';
import { append, clamp, getRect, includeFromEvent, isMobile, query, secondToTime, setStyle } from '../utils'
export function getPosFromEvent(art, event) {
const { $progress } = art.template;
const { left } = getRect($progress);
const eventLeft = isMobile ? event.touches[0].clientX : event.clientX;
const width = clamp(eventLeft - left, 0, $progress.clientWidth);
const second = (width / $progress.clientWidth) * art.duration;
const time = secondToTime(second);
const percentage = clamp(width / $progress.clientWidth, 0, 1);
return { second, time, width, percentage };
const { $progress } = art.template
const { left } = getRect($progress)
const eventLeft = isMobile ? event.touches[0].clientX : event.clientX
const width = clamp(eventLeft - left, 0, $progress.clientWidth)
const second = (width / $progress.clientWidth) * art.duration
const time = secondToTime(second)
const percentage = clamp(width / $progress.clientWidth, 0, 1)
return { second, time, width, percentage }
}
export function setCurrentTime(art, event) {
if (art.isRotate) {
const percentage = event.touches[0].clientY / art.height;
const second = percentage * art.duration;
art.emit('setBar', 'played', percentage, event);
art.seek = second;
} else {
const { second, percentage } = getPosFromEvent(art, event);
art.emit('setBar', 'played', percentage, event);
art.seek = second;
}
if (art.isRotate) {
const percentage = event.touches[0].clientY / art.height
const second = percentage * art.duration
art.emit('setBar', 'played', percentage, event)
art.seek = second
}
else {
const { second, percentage } = getPosFromEvent(art, event)
art.emit('setBar', 'played', percentage, event)
art.seek = second
}
}
export default function progress(options) {
return (art) => {
const { icons, option, proxy } = art;
return (art) => {
const { icons, option, proxy } = art
return {
...options,
html: `
return {
...options,
html: `
<div class="art-control-progress-inner">
<div class="art-progress-hover"></div>
<div class="art-progress-loaded"></div>
@@ -40,154 +41,161 @@ export default function progress(options) {
<div class="art-progress-tip"></div>
</div>
`,
mounted: ($control) => {
let tipTimer = null;
let isDragging = false;
mounted: ($control) => {
let tipTimer = null
let isDragging = false
const $hover = query('.art-progress-hover', $control);
const $loaded = query('.art-progress-loaded', $control);
const $played = query('.art-progress-played', $control);
const $highlight = query('.art-progress-highlight', $control);
const $indicator = query('.art-progress-indicator', $control);
const $tip = query('.art-progress-tip', $control);
const $hover = query('.art-progress-hover', $control)
const $loaded = query('.art-progress-loaded', $control)
const $played = query('.art-progress-played', $control)
const $highlight = query('.art-progress-highlight', $control)
const $indicator = query('.art-progress-indicator', $control)
const $tip = query('.art-progress-tip', $control)
if (icons.indicator) {
append($indicator, icons.indicator);
} else {
setStyle($indicator, 'backgroundColor', 'var(--art-theme)');
}
if (icons.indicator) {
append($indicator, icons.indicator)
}
else {
setStyle($indicator, 'backgroundColor', 'var(--art-theme)')
}
function showHighlight(event) {
const { width } = getPosFromEvent(art, event);
const { text } = event.target.dataset;
$tip.innerText = text;
const tipWidth = $tip.clientWidth;
if (width <= tipWidth / 2) {
setStyle($tip, 'left', 0);
} else if (width > $control.clientWidth - tipWidth / 2) {
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`);
} else {
setStyle($tip, 'left', `${width - tipWidth / 2}px`);
}
}
function showHighlight(event) {
const { width } = getPosFromEvent(art, event)
const { text } = event.target.dataset
$tip.textContent = text
const tipWidth = $tip.clientWidth
if (width <= tipWidth / 2) {
setStyle($tip, 'left', 0)
}
else if (width > $control.clientWidth - tipWidth / 2) {
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`)
}
else {
setStyle($tip, 'left', `${width - tipWidth / 2}px`)
}
}
function showTime(event, touch) {
const { width, time } = touch || getPosFromEvent(art, event);
$tip.innerText = time;
const tipWidth = $tip.clientWidth;
if (width <= tipWidth / 2) {
setStyle($tip, 'left', 0);
} else if (width > $control.clientWidth - tipWidth / 2) {
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`);
} else {
setStyle($tip, 'left', `${width - tipWidth / 2}px`);
}
}
function showTime(event, touch) {
const { width, time } = touch || getPosFromEvent(art, event)
$tip.textContent = time
const tipWidth = $tip.clientWidth
if (width <= tipWidth / 2) {
setStyle($tip, 'left', 0)
}
else if (width > $control.clientWidth - tipWidth / 2) {
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`)
}
else {
setStyle($tip, 'left', `${width - tipWidth / 2}px`)
}
}
function updateHighlight() {
$highlight.innerText = '';
for (let index = 0; index < option.highlight.length; index++) {
const item = option.highlight[index];
const left = (clamp(item.time, 0, art.duration) / art.duration) * 100;
const html = `<span data-text="${item.text}" data-time="${item.time}" style="left: ${left}%"></span>`;
append($highlight, html);
}
}
function updateHighlight() {
$highlight.textContent = ''
for (let index = 0; index < option.highlight.length; index++) {
const item = option.highlight[index]
const left = (clamp(item.time, 0, art.duration) / art.duration) * 100
const html = `<span data-text="${item.text}" data-time="${item.time}" style="left: ${left}%"></span>`
append($highlight, html)
}
}
function setBar(type, percentage, event) {
const isMobileDragging = type === 'played' && event && isMobile;
function setBar(type, percentage, event) {
const isMobileDragging = type === 'played' && event && isMobile
if (type === 'loaded') {
setStyle($loaded, 'width', `${percentage * 100}%`);
}
if (type === 'loaded') {
setStyle($loaded, 'width', `${percentage * 100}%`)
}
if (type === 'hover') {
setStyle($hover, 'width', `${percentage * 100}%`);
}
if (type === 'hover') {
setStyle($hover, 'width', `${percentage * 100}%`)
}
if (type === 'played') {
setStyle($played, 'width', `${percentage * 100}%`);
setStyle($indicator, 'left', `${percentage * 100}%`);
}
if (type === 'played') {
setStyle($played, 'width', `${percentage * 100}%`)
setStyle($indicator, 'left', `${percentage * 100}%`)
}
if (isMobileDragging) {
setStyle($tip, 'display', 'flex');
const width = $control.clientWidth * percentage;
const time = secondToTime(percentage * art.duration);
showTime(event, { width, time });
clearTimeout(tipTimer);
tipTimer = setTimeout(() => {
setStyle($tip, 'display', 'none');
}, 500);
}
}
if (isMobileDragging) {
setStyle($tip, 'display', 'flex')
const width = $control.clientWidth * percentage
const time = secondToTime(percentage * art.duration)
showTime(event, { width, time })
clearTimeout(tipTimer)
tipTimer = setTimeout(() => {
setStyle($tip, 'display', 'none')
}, 500)
}
}
art.on('setBar', setBar);
art.on('video:loadedmetadata', updateHighlight);
art.on('setBar', setBar)
art.on('video:loadedmetadata', updateHighlight)
if (art.constructor.USE_RAF) {
art.on('raf', () => {
art.emit('setBar', 'played', art.played);
art.emit('setBar', 'loaded', art.loaded);
});
} else {
art.on('video:timeupdate', () => {
art.emit('setBar', 'played', art.played);
});
if (art.constructor.USE_RAF) {
art.on('raf', () => {
art.emit('setBar', 'played', art.played)
art.emit('setBar', 'loaded', art.loaded)
})
}
else {
art.on('video:timeupdate', () => {
art.emit('setBar', 'played', art.played)
})
art.on('video:progress', () => {
art.emit('setBar', 'loaded', art.loaded);
});
art.on('video:progress', () => {
art.emit('setBar', 'loaded', art.loaded)
})
art.on('video:ended', () => {
art.emit('setBar', 'played', 1);
});
}
art.on('video:ended', () => {
art.emit('setBar', 'played', 1)
})
}
art.emit('setBar', 'loaded', art.loaded || 0);
art.emit('setBar', 'loaded', art.loaded || 0)
if (!isMobile) {
proxy($control, 'click', (event) => {
if (event.target !== $indicator) {
setCurrentTime(art, event);
}
});
if (!isMobile) {
proxy($control, 'click', (event) => {
if (event.target !== $indicator) {
setCurrentTime(art, event)
}
})
proxy($control, 'mousemove', (event) => {
const { percentage } = getPosFromEvent(art, event);
art.emit('setBar', 'hover', percentage, event);
setStyle($tip, 'display', 'flex');
if (includeFromEvent(event, $highlight)) {
showHighlight(event);
} else {
showTime(event);
}
});
proxy($control, 'mousemove', (event) => {
const { percentage } = getPosFromEvent(art, event)
art.emit('setBar', 'hover', percentage, event)
setStyle($tip, 'display', 'flex')
if (includeFromEvent(event, $highlight)) {
showHighlight(event)
}
else {
showTime(event)
}
})
proxy($control, 'mouseleave', (event) => {
setStyle($tip, 'display', 'none');
art.emit('setBar', 'hover', 0, event);
});
proxy($control, 'mouseleave', (event) => {
setStyle($tip, 'display', 'none')
art.emit('setBar', 'hover', 0, event)
})
proxy($control, 'mousedown', (event) => {
isDragging = event.button === 0;
});
proxy($control, 'mousedown', (event) => {
isDragging = event.button === 0
})
art.on('document:mousemove', (event) => {
if (isDragging) {
const { second, percentage } = getPosFromEvent(art, event);
art.emit('setBar', 'played', percentage, event);
art.seek = second;
}
});
art.on('document:mousemove', (event) => {
if (isDragging) {
const { second, percentage } = getPosFromEvent(art, event)
art.emit('setBar', 'played', percentage, event)
art.seek = second
}
})
art.on('document:mouseup', () => {
if (isDragging) {
isDragging = false;
}
});
}
},
};
};
art.on('document:mouseup', () => {
if (isDragging) {
isDragging = false
}
})
}
},
}
}
}
+12 -12
View File
@@ -1,16 +1,16 @@
import { append } from '../utils';
import { append } from '../utils'
export default function screenshot(option) {
return (art) => ({
...option,
tooltip: art.i18n.get('Screenshot'),
mounted: ($control) => {
const { proxy, icons } = art;
return art => ({
...option,
tooltip: art.i18n.get('Screenshot'),
mounted: ($control) => {
const { proxy, icons } = art
append($control, icons.screenshot);
proxy($control, 'click', () => {
art.screenshot();
});
},
});
append($control, icons.screenshot)
proxy($control, 'click', () => {
art.screenshot()
})
},
})
}
+16 -16
View File
@@ -1,22 +1,22 @@
import { append, tooltip } from '../utils';
import { append, tooltip } from '../utils'
export default function setting(option) {
return (art) => ({
...option,
tooltip: art.i18n.get('Show Setting'),
mounted: ($control) => {
const { proxy, icons, i18n } = art;
return art => ({
...option,
tooltip: art.i18n.get('Show Setting'),
mounted: ($control) => {
const { proxy, icons, i18n } = art
append($control, icons.setting);
append($control, icons.setting)
proxy($control, 'click', () => {
art.setting.toggle();
art.setting.resize();
});
proxy($control, 'click', () => {
art.setting.toggle()
art.setting.resize()
})
art.on('setting', (value) => {
tooltip($control, i18n.get(value ? 'Hide Setting' : 'Show Setting'));
});
},
});
art.on('setting', (value) => {
tooltip($control, i18n.get(value ? 'Hide Setting' : 'Show Setting'))
})
},
})
}
+27 -27
View File
@@ -1,31 +1,31 @@
import { secondToTime, isMobile } from '../utils';
import { isMobile, secondToTime } from '../utils'
export default function time(option) {
return (art) => ({
...option,
style: isMobile
? {
fontSize: '12px',
padding: '0 5px',
}
: {
cursor: 'auto',
padding: '0 10px',
},
mounted: ($control) => {
function getTime() {
const newTime = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`;
if (newTime !== $control.innerText) {
$control.innerText = newTime;
}
}
getTime();
const events = ['video:loadedmetadata', 'video:timeupdate', 'video:progress'];
for (let index = 0; index < events.length; index++) {
art.on(events[index], getTime);
}
return art => ({
...option,
style: isMobile
? {
fontSize: '12px',
padding: '0 5px',
}
: {
cursor: 'auto',
padding: '0 10px',
},
});
mounted: ($control) => {
function getTime() {
const newTime = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`
if (newTime !== $control.textContent) {
$control.textContent = newTime
}
}
getTime()
const events = ['video:loadedmetadata', 'video:timeupdate', 'video:progress']
for (let index = 0; index < events.length; index++) {
art.on(events[index], getTime)
}
},
})
}
+66 -64
View File
@@ -1,77 +1,79 @@
import { append, setStyle, isMobile, getRect } from '../utils';
import { append, getRect, isMobile, setStyle } from '../utils'
export default function volume(option) {
return (art) => ({
...option,
mounted: ($control) => {
const { proxy, icons } = art;
return art => ({
...option,
mounted: ($control) => {
const { proxy, icons } = art
const $volume = append($control, icons.volume);
const $close = append($control, icons.volumeClose);
const $panel = append($control, '<div class="art-volume-panel"></div>');
const $inner = append($panel, '<div class="art-volume-inner"></div>');
const $value = append($inner, `<div class="art-volume-val"></div>`);
const $slider = append($inner, `<div class="art-volume-slider"></div>`);
const $handle = append($slider, `<div class="art-volume-handle"></div>`);
const $loaded = append($handle, `<div class="art-volume-loaded"></div>`);
const $indicator = append($slider, `<div class="art-volume-indicator"></div>`);
const $volume = append($control, icons.volume)
const $close = append($control, icons.volumeClose)
const $panel = append($control, '<div class="art-volume-panel"></div>')
const $inner = append($panel, '<div class="art-volume-inner"></div>')
const $value = append($inner, `<div class="art-volume-val"></div>`)
const $slider = append($inner, `<div class="art-volume-slider"></div>`)
const $handle = append($slider, `<div class="art-volume-handle"></div>`)
const $loaded = append($handle, `<div class="art-volume-loaded"></div>`)
const $indicator = append($slider, `<div class="art-volume-indicator"></div>`)
function getVolumeFromEvent(event) {
const { top, height } = getRect($slider);
return 1 - (event.clientY - top) / height;
}
function getVolumeFromEvent(event) {
const { top, height } = getRect($slider)
return 1 - (event.clientY - top) / height
}
function update() {
if (art.muted || art.volume === 0) {
setStyle($volume, 'display', 'none');
setStyle($close, 'display', 'flex');
setStyle($indicator, 'top', '100%');
setStyle($loaded, 'top', '100%');
$value.innerText = 0;
} else {
const percentage = art.volume * 100;
setStyle($volume, 'display', 'flex');
setStyle($close, 'display', 'none');
setStyle($indicator, 'top', `${100 - percentage}%`);
setStyle($loaded, 'top', `${100 - percentage}%`);
$value.innerText = Math.floor(percentage);
}
}
function update() {
if (art.muted || art.volume === 0) {
setStyle($volume, 'display', 'none')
setStyle($close, 'display', 'flex')
setStyle($indicator, 'top', '100%')
setStyle($loaded, 'top', '100%')
$value.textContent = 0
}
else {
const percentage = art.volume * 100
setStyle($volume, 'display', 'flex')
setStyle($close, 'display', 'none')
setStyle($indicator, 'top', `${100 - percentage}%`)
setStyle($loaded, 'top', `${100 - percentage}%`)
$value.textContent = Math.floor(percentage)
}
}
update();
art.on('video:volumechange', update);
update()
art.on('video:volumechange', update)
proxy($volume, 'click', () => {
art.muted = true;
});
proxy($volume, 'click', () => {
art.muted = true
})
proxy($close, 'click', () => {
art.muted = false;
});
proxy($close, 'click', () => {
art.muted = false
})
if (isMobile) {
setStyle($panel, 'display', 'none');
} else {
let isDragging = false;
if (isMobile) {
setStyle($panel, 'display', 'none')
}
else {
let isDragging = false
proxy($slider, 'mousedown', (event) => {
isDragging = event.button === 0;
art.volume = getVolumeFromEvent(event);
});
proxy($slider, 'mousedown', (event) => {
isDragging = event.button === 0
art.volume = getVolumeFromEvent(event)
})
art.on('document:mousemove', (event) => {
if (isDragging) {
art.muted = false;
art.volume = getVolumeFromEvent(event);
}
});
art.on('document:mousemove', (event) => {
if (isDragging) {
art.muted = false
art.volume = getVolumeFromEvent(event)
}
})
art.on('document:mouseup', () => {
if (isDragging) {
isDragging = false;
}
});
}
},
});
art.on('document:mouseup', () => {
if (isDragging) {
isDragging = false
}
})
}
},
})
}