修改包管理

This commit is contained in:
Harvey Zack committed 2018-11-07 17:12:42 +08:00
1 parent c5c673ae79
commit 0aa018db6d
99 files changed
+70 -70

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Danmu {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, i18n, danmu } = art;
this.$danmu = append($control, icons.danmu);
tooltip(this.$danmu, i18n.get('Hide danmu'));
proxy($control, 'click', () => {
if (danmu.isOpen) {
danmu.hide();
setStyle(this.$danmu, 'opacity', '1');
tooltip(this.$danmu, i18n.get('Show danmu'));
} else {
danmu.show();
setStyle(this.$danmu, 'opacity', '0.8');
tooltip(this.$danmu, i18n.get('Hide danmu'));
}
});
}
}
@@ -0,0 +1,28 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Fullscreen {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, i18n, player } = art;
this.$fullscreen = append($control, icons.fullscreen);
tooltip(this.$fullscreen, i18n.get('Fullscreen'));
proxy($control, 'click', () => {
player.fullscreenToggle();
});
art.on('fullscreen:enabled', () => {
setStyle(this.$fullscreen, 'opacity', '0.8');
tooltip(this.$fullscreen, i18n.get('Exit fullscreen'));
});
art.on('fullscreen:exit', () => {
setStyle(this.$fullscreen, 'opacity', '1');
tooltip(this.$fullscreen, i18n.get('Fullscreen'));
});
}
}
@@ -0,0 +1,28 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class FullscreenWeb {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, i18n, player } = art;
this.$fullscreenWeb = append($control, icons.fullscreenWeb);
tooltip(this.$fullscreenWeb, i18n.get('Web fullscreen'));
proxy($control, 'click', () => {
player.fullscreenWebToggle();
});
art.on('fullscreenWeb:enabled', () => {
setStyle(this.$fullscreenWeb, 'opacity', '0.8');
tooltip(this.$fullscreenWeb, i18n.get('Exit web fullscreen'));
});
art.on('fullscreenWeb:exit', () => {
setStyle(this.$fullscreenWeb, 'opacity', '1');
tooltip(this.$fullscreenWeb, i18n.get('Web fullscreen'));
});
}
}
+153
View File
@@ -0,0 +1,153 @@
import { insertByIndex } from '../utils';
import Fullscreen from './fullscreen';
import FullscreenWeb from './fullscreenWeb';
import Pip from './pip';
import PlayAndPause from './playAndPause';
import Progress from './progress';
import Subtitle from './subtitle';
import Time from './time';
import Volume from './volume';
import Setting from './setting';
import Thumbnails from './thumbnails';
import Screenshot from './screenshot';
import Quality from './quality';
let id = 0;
export default class Controls {
constructor(art) {
this.art = art;
this.art.on('firstCanplay', () => {
this.init();
});
}
init() {
this.add(new Progress({
name: 'progress',
disable: false,
position: 'top',
index: 10
}));
this.add(new Thumbnails({
name: 'thumbnails',
disable: !this.art.option.thumbnails.url,
position: 'top',
index: 20
}));
this.add(new PlayAndPause({
name: 'playAndPause',
disable: false,
position: 'left',
index: 10
}));
this.add(new Volume({
name: 'volume',
disable: false,
position: 'left',
index: 20
}));
this.add(new Time({
name: 'time',
disable: false,
position: 'left',
index: 30
}));
this.add(new Quality({
name: 'quality',
disable: this.art.option.quality.length === 0,
position: 'right',
index: 10
}));
this.add(new Screenshot({
name: 'screenshot',
disable: !this.art.option.screenshot,
position: 'right',
index: 20
}));
this.add(new Subtitle({
name: 'subtitle',
disable: !this.art.option.subtitle.url,
position: 'right',
index: 30
}));
this.add(new Setting({
name: 'setting',
disable: !this.art.option.setting,
position: 'right',
index: 40
}));
this.add(new Pip({
name: 'pip',
disable: !this.art.option.pip,
position: 'right',
index: 50
}));
this.add(new FullscreenWeb({
name: 'fullscreenWeb',
disable: !this.art.option.fullscreenWeb,
position: 'right',
index: 60
}));
this.add(new Fullscreen({
name: 'fullscreen',
disable: !this.art.option.fullscreen,
position: 'right',
index: 70
}));
this.art.option.controls.forEach(item => {
this.add(item);
});
}
add(control) {
const { option } = control;
if (option && !option.disable) {
id++;
const name = option.name || control.constructor.name.toLowerCase() || `control${id}`;
const $control = document.createElement('div');
$control.setAttribute('class', `art-control art-control-${name}`);
this.mount(option.position, $control, option.index || id);
control.apply && control.apply(this.art, $control);
this[name] = control;
}
}
mount(position, $control, index) {
const { $progress, $controlsLeft, $controlsRight } = this.art.refs;
switch (position) {
case 'top':
insertByIndex($progress, $control, index);
break;
case 'left':
insertByIndex($controlsLeft, $control, index);
break;
case 'right':
insertByIndex($controlsRight, $control, index);
break;
default:
break;
}
}
show() {
const { $player } = this.art.refs;
$player.classList.add('artplayer-controls-show');
}
hide() {
const { $player } = this.art.refs;
$player.classList.remove('artplayer-controls-show');
}
}
+17
View File
@@ -0,0 +1,17 @@
import { append, tooltip } from '../utils';
import icons from '../icons';
export default class Pip {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, i18n, player } = art;
this.$pip = append($control, icons.pip);
tooltip(this.$pip, i18n.get('Mini player'));
proxy($control, 'click', () => {
player.pipEnabled();
});
}
}
@@ -0,0 +1,35 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class PlayAndPause {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, player, i18n } = art;
this.$play = append($control, icons.play);
this.$pause = append($control, icons.pause);
tooltip(this.$play, i18n.get('Play'));
tooltip(this.$pause, i18n.get('Pause'));
setStyle(this.$pause, 'display', 'none');
proxy(this.$play, 'click', () => {
player.play();
});
proxy(this.$pause, 'click', () => {
player.pause();
});
art.on('video:playing', () => {
setStyle(this.$play, 'display', 'none');
setStyle(this.$pause, 'display', 'block');
});
art.on('video:pause', () => {
setStyle(this.$play, 'display', 'block');
setStyle(this.$pause, 'display', 'none');
});
}
}
+148
View File
@@ -0,0 +1,148 @@
import { append, clamp, secondToTime, setStyle } from '../utils';
export default class Progress {
constructor(option) {
this.option = option;
this.isDroging = false;
this.getLoaded = this.getLoaded.bind(this);
this.getPlayed = this.getPlayed.bind(this);
this.set = this.set.bind(this);
}
apply(art, $control) {
this.art = art;
this.$control = $control;
const { option: { highlight, theme }, events: { proxy }, refs: { $video }, player } = art;
append(
$control,
`
<div class="art-control-progress-inner">
<div class="art-progress-loaded"></div>
<div class="art-progress-played" style="background: ${theme}"></div>
<div class="art-progress-highlight"></div>
<div class="art-progress-indicator" style="background: ${theme}"></div>
<div class="art-progress-tip art-tip"></div>
</div>
`
);
this.$loaded = $control.querySelector('.art-progress-loaded');
this.$played = $control.querySelector('.art-progress-played');
this.$highlight = $control.querySelector('.art-progress-highlight');
this.$indicator = $control.querySelector('.art-progress-indicator');
this.$tip = $control.querySelector('.art-progress-tip');
this.set('loaded', this.getLoaded());
highlight.forEach(item => {
const left = Number(item.time) / $video.duration;
append(this.$highlight, `<span data-text="${item.text}" data-time="${item.time}" style="left: ${left * 100}%"></span>`);
});
this.art.on('video:progress', () => {
this.set('loaded', this.getLoaded());
});
this.art.on('video:timeupdate', () => {
this.set('played', this.getPlayed());
});
this.art.on('video:ended', () => {
this.set('played', 1);
});
proxy($control, 'mousemove', event => {
setStyle(this.$tip, 'display', 'block');
if (event.composedPath().indexOf(this.$highlight) > -1) {
this.showHighlight(event);
} else {
this.showTime(event);
}
});
proxy($control, 'mouseout', () => {
setStyle(this.$tip, 'display', 'none');
});
proxy($control, 'click', event => {
if (event.target !== this.$indicator) {
const { second, percentage } = this.getPosFromEvent(event);
this.set('played', percentage);
player.seek(second);
}
});
proxy(this.$indicator, 'mousedown', () => {
this.isDroging = true;
});
proxy(document, 'mousemove', event => {
if (this.isDroging) {
const { second, percentage } = this.getPosFromEvent(event);
this.$indicator.classList.add('show-indicator');
this.set('played', percentage);
player.seek(second);
}
});
proxy(document, 'mouseup', () => {
if (this.isDroging) {
this.isDroging = false;
this.$indicator.classList.remove('show-indicator');
}
});
}
showHighlight(event) {
const { $video } = this.art.refs;
const { text, time } = event.target.dataset;
this.$tip.innerHTML = text;
const left =
Number(time) / $video.duration * this.$control.clientWidth +
event.target.clientWidth / 2 -
this.$tip.clientWidth / 2;
setStyle(this.$tip, 'left', `${left}px`);
}
showTime(event) {
const { width, time } = this.getPosFromEvent(event);
const tipWidth = this.$tip.clientWidth;
this.$tip.innerHTML = time;
if (width <= tipWidth / 2) {
setStyle(this.$tip, 'left', 0);
} else if (width > this.$control.clientWidth - tipWidth / 2) {
setStyle(this.$tip, 'left', `${this.$control.clientWidth - tipWidth}px`);
} else {
setStyle(this.$tip, 'left', `${width - tipWidth / 2}px`);
}
}
getPlayed() {
const { $video } = this.art.refs;
return $video.currentTime / $video.duration;
}
getLoaded() {
const { $video } = this.art.refs;
return $video.buffered.length
? $video.buffered.end($video.buffered.length - 1) / $video.duration
: 0;
}
getPosFromEvent(event) {
const { $video, $progress } = this.art.refs;
const { left } = $progress.getBoundingClientRect();
const width = clamp(event.x - left, 0, $progress.clientWidth);
const second = width / $progress.clientWidth * $video.duration;
const time = secondToTime(second);
const percentage = clamp(width / $progress.clientWidth, 0, 1);
return { second, time, width, percentage };
}
set(type, percentage) {
setStyle(this[`$${type}`], 'width', `${percentage * 100}%`);
if (type === 'played') {
setStyle(this.$indicator, 'left', `calc(${percentage * 100}% - 6.5px)`);
}
}
}
@@ -0,0 +1,33 @@
import { append } from '../utils';
export default class Quality {
constructor(option) {
this.option = option;
this.playIndex = -1;
}
apply(art, $control) {
const { option, events: { proxy, hover }, player } = art;
const defaultQuality = option.quality.find(item => item.default) || option.quality[0];
this.playIndex = option.quality.indexOf(defaultQuality);
const $qualityName = append($control, `<div class="art-quality-name">${defaultQuality.name}</div>`);
const qualityList = option.quality.map((item, index) => `<div class="art-quality-item" data-index="${index}">${item.name}</div>`).join('');
const $qualitys = append($control, `<div class="art-qualitys">${qualityList}</div>`);
hover($control, () => {
$control.classList.add('hover');
}, () => {
$control.classList.remove('hover');
});
proxy($qualitys, 'click', event => {
const index = Number(event.target.dataset.index);
const { url, name } = option.quality[index];
if (url && name && this.playIndex !== index) {
player.switch(url, name);
$qualityName.innerHTML = name;
this.playIndex = index;
}
});
}
}
@@ -0,0 +1,17 @@
import { append, tooltip } from '../utils';
import icons from '../icons';
export default class Screenshot {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, i18n, player } = art;
this.$screenshot = append($control, icons.screenshot);
tooltip(this.$screenshot, i18n.get('Screenshot'));
proxy(this.$screenshot, 'click', () => {
player.screenshot();
});
}
}
@@ -0,0 +1,28 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Setting {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, i18n, setting } = art;
this.$setting = append($control, icons.setting);
tooltip(this.$setting, i18n.get('Show setting'));
proxy($control, 'click', () => {
setting.toggle();
});
art.on('setting:show', () => {
setStyle(this.$setting, 'opacity', '0.8');
tooltip(this.$setting, i18n.get('Hide setting'));
});
art.on('setting:hide', () => {
setStyle(this.$setting, 'opacity', '1');
tooltip(this.$setting, i18n.get('Show setting'));
});
}
}
@@ -0,0 +1,28 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Subtitle {
constructor(option) {
this.option = option;
}
apply(art, $control) {
const { events: { proxy }, i18n, subtitle } = art;
this.$subtitle = append($control, icons.subtitle);
tooltip(this.$subtitle, i18n.get('Hide subtitle'));
proxy($control, 'click', () => {
subtitle.toggle();
});
art.on('subtitle:show', () => {
setStyle(this.$subtitle, 'opacity', '0.8');
tooltip(this.$subtitle, i18n.get('Hide subtitle'));
});
art.on('subtitle:hide', () => {
setStyle(this.$subtitle, 'opacity', '1');
tooltip(this.$subtitle, i18n.get('Show subtitle'));
});
}
}
@@ -0,0 +1,72 @@
import { errorHandle, setStyle } from '../utils';
export default class Thumbnails {
constructor(option) {
this.option = option;
this.loading = false;
this.isLoad = false;
}
apply(art, $control) {
this.art = art;
errorHandle(art.controls.progress, '\'thumbnails\' control dependent on \'progress\' control');
const { refs: { $progress }, events: { proxy } } = art;
this.$control = $control;
proxy($progress, 'mousemove', event => {
if (!this.loading) {
this.loading = true;
this.load(this.art.option.thumbnails.url).then(() => {
this.isLoad = true;
});
}
if (this.isLoad) {
setStyle($control, 'display', 'block');
this.showThumbnails(event);
}
});
proxy($progress, 'mouseout', () => {
setStyle($control, 'display', 'none');
});
}
load(url) {
const { proxy } = this.art.events;
return new Promise((resolve, reject) => {
const image = new Image();
image.src = url;
if (image.complete) {
return resolve(image);
}
proxy(image, 'load', () => resolve(image));
proxy(image, 'error', () => reject(image));
});
}
showThumbnails(event) {
const { refs: { $progress }, controls } = this.art;
const { width: posWidth } = controls.progress.getPosFromEvent(event);
const { url, height, width, number, column } = this.art.option.thumbnails;
const perWidth = $progress.clientWidth / number;
const perIndex = Math.ceil(posWidth / perWidth);
let yIndex = Math.ceil(perIndex / column);
let xIndex = perIndex % column || column;
setStyle(this.$control, 'backgroundImage', `url(${url})`);
setStyle(this.$control, 'height', `${height}px`);
setStyle(this.$control, 'width', `${width}px`);
setStyle(this.$control, 'backgroundPosition', `-${--xIndex * width}px -${--yIndex * height}px`);
if (posWidth <= width / 2) {
setStyle(this.$control, 'left', 0);
} else if (posWidth > $progress.clientWidth - width / 2) {
setStyle(this.$control, 'left', `${$progress.clientWidth - width}px`);
} else {
setStyle(this.$control, 'left', `${posWidth - width / 2}px`);
}
}
}
+27
View File
@@ -0,0 +1,27 @@
import { secondToTime } from '../utils';
export default class Time {
constructor(option) {
this.option = option;
}
apply(art, $control) {
$control.innerHTML = '00:00 / 00:00';
function setTime() {
$control.innerHTML = `${secondToTime(art.player.currentTime())} / ${secondToTime(art.player.duration())}`;
}
art.on('video:canplay', () => {
setTime();
});
art.on('video:timeupdate', () => {
setTime();
});
art.on('video:seeking', () => {
setTime();
});
}
}
+101
View File
@@ -0,0 +1,101 @@
import { append, getStorage, clamp, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Volume {
constructor(option) {
this.option = option;
this.isDroging = false;
}
apply(art, $control) {
this.art = art;
this.$control = $control;
this.init();
}
init() {
const { events: { proxy }, player, i18n } = this.art;
this.$volume = append(this.$control, icons.volume);
this.$volumeClose = append(this.$control, icons.volumeClose);
this.$volumePanel = append(this.$control, '<div class="art-volume-panel"></div>');
this.$volumeHandle = append(this.$volumePanel, '<div class="art-volume-slider-handle"></div>');
tooltip(this.$volume, i18n.get('Mute'));
setStyle(this.$volumeClose, 'display', 'none');
const volume = getStorage('volume');
this.setVolumeHandle(volume);
player.volume(volume);
proxy(this.$volume, 'click', () => {
setStyle(this.$volume, 'display', 'none');
setStyle(this.$volumeClose, 'display', 'block');
player.volume(0);
});
proxy(this.$volumeClose, 'click', () => {
setStyle(this.$volume, 'display', 'block');
setStyle(this.$volumeClose, 'display', 'none');
player.volume(getStorage('volume'));
});
proxy(this.$control, 'mouseenter', () => {
this.$volumePanel.classList.add('art-volume-panel-hover');
// TODO
setTimeout(() => {
this.setVolumeHandle(player.volume());
}, 200);
});
proxy(this.$control, 'mouseleave', () => {
this.$volumePanel.classList.remove('art-volume-panel-hover');
});
proxy(this.$volumePanel, 'click', event => {
this.volumeChangeFromEvent(event);
});
proxy(this.$volumeHandle, 'mousedown', () => {
this.isDroging = true;
});
proxy(this.$volumeHandle, 'mousemove', event => {
if (this.isDroging) {
this.volumeChangeFromEvent(event);
}
});
proxy(document, 'mouseup', () => {
if (this.isDroging) {
this.isDroging = false;
}
});
this.art.on('video:volumechange', () => {
const percentage = player.volume();
this.setVolumeHandle(percentage);
if (percentage === 0) {
setStyle(this.$volume, 'display', 'none');
setStyle(this.$volumeClose, 'display', 'block');
} else {
setStyle(this.$volume, 'display', 'block');
setStyle(this.$volumeClose, 'display', 'none');
}
});
}
volumeChangeFromEvent(event) {
const { player } = this.art;
const { left: panelLeft, width: panelWidth } = this.$volumePanel.getBoundingClientRect();
const { width: handleWidth } = this.$volumeHandle.getBoundingClientRect();
const percentage = clamp(event.x - panelLeft - handleWidth / 2, 0, panelWidth - handleWidth / 2) / (panelWidth - handleWidth);
player.volume(percentage);
}
setVolumeHandle(percentage = 0.7) {
const { width: panelWidth } = this.$volumePanel.getBoundingClientRect();
const { width: handleWidth } = this.$volumeHandle.getBoundingClientRect();
const width = handleWidth / 2 + (panelWidth - handleWidth) * percentage - handleWidth / 2;
setStyle(this.$volumeHandle, 'left', `${width}px`);
}
}