调整控制器结构

This commit is contained in:
Harvey Zack committed 2018-11-22 19:19:20 +08:00
1 parent cce1eda7eb
commit a380836d75
21 files changed
+1152 -1422

No files matched your search

+24 -25
View File
@@ -1,32 +1,31 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Fullscreen {
constructor(option) {
this.option = option;
}
export default function fullscreen(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
i18n,
player,
} = art;
const $fullscreen = append($control, icons.fullscreen);
tooltip($fullscreen, i18n.get('Fullscreen'));
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();
});
proxy($control, 'click', () => {
player.fullscreenToggle();
});
art.on('fullscreen:enabled', () => {
setStyle($fullscreen, 'opacity', '0.8');
tooltip($fullscreen, i18n.get('Exit fullscreen'));
});
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'));
});
}
art.on('fullscreen:exit', () => {
setStyle($fullscreen, 'opacity', '1');
tooltip($fullscreen, i18n.get('Fullscreen'));
});
},
});
}
@@ -1,32 +1,31 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class FullscreenWeb {
constructor(option) {
this.option = option;
}
export default function fullscreenWeb(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
i18n,
player,
} = art;
const $fullscreenWeb = append($control, icons.fullscreenWeb);
tooltip($fullscreenWeb, i18n.get('Web fullscreen'));
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();
});
proxy($control, 'click', () => {
player.fullscreenWebToggle();
});
art.on('fullscreenWeb:enabled', () => {
setStyle($fullscreenWeb, 'opacity', '0.8');
tooltip($fullscreenWeb, i18n.get('Exit web fullscreen'));
});
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'));
});
}
art.on('fullscreenWeb:exit', () => {
setStyle($fullscreenWeb, 'opacity', '1');
tooltip($fullscreenWeb, i18n.get('Web fullscreen'));
});
},
});
}
+36 -86
View File
@@ -1,21 +1,20 @@
import { insertByIndex, setStyle, append } 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';
import componentMethod from '../utils/componentMethod';
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) {
id = 0;
this.id = 0;
this.art = art;
this.art.on('firstCanplay', () => {
this.init();
@@ -24,8 +23,9 @@ export default class Controls {
init() {
const { option } = this.art;
this.add(
new Progress({
progress({
name: 'progress',
disable: false,
position: 'top',
@@ -34,7 +34,7 @@ export default class Controls {
);
this.add(
new Thumbnails({
thumbnails({
name: 'thumbnails',
disable: !option.thumbnails.url,
position: 'top',
@@ -43,7 +43,7 @@ export default class Controls {
);
this.add(
new PlayAndPause({
playAndPause({
name: 'playAndPause',
disable: false,
position: 'left',
@@ -52,7 +52,7 @@ export default class Controls {
);
this.add(
new Volume({
volume({
name: 'volume',
disable: false,
position: 'left',
@@ -61,7 +61,7 @@ export default class Controls {
);
this.add(
new Time({
time({
name: 'time',
disable: false,
position: 'left',
@@ -70,7 +70,7 @@ export default class Controls {
);
this.add(
new Quality({
quality({
name: 'quality',
disable: option.quality.length === 0,
position: 'right',
@@ -79,7 +79,7 @@ export default class Controls {
);
this.add(
new Screenshot({
screenshot({
name: 'screenshot',
disable: !option.screenshot,
position: 'right',
@@ -88,7 +88,7 @@ export default class Controls {
);
this.add(
new Subtitle({
subtitle({
name: 'subtitle',
disable: !option.subtitle.url,
position: 'right',
@@ -97,7 +97,7 @@ export default class Controls {
);
this.add(
new Setting({
setting({
name: 'setting',
disable: !option.setting,
position: 'right',
@@ -106,7 +106,7 @@ export default class Controls {
);
this.add(
new Pip({
pip({
name: 'pip',
disable: !option.pip,
position: 'right',
@@ -115,7 +115,7 @@ export default class Controls {
);
this.add(
new FullscreenWeb({
fullscreenWeb({
name: 'fullscreenWeb',
disable: !option.fullscreenWeb,
position: 'right',
@@ -124,7 +124,7 @@ export default class Controls {
);
this.add(
new Fullscreen({
fullscreen({
name: 'fullscreen',
disable: !option.fullscreen,
position: 'right',
@@ -138,76 +138,26 @@ export default class Controls {
}
add(item, callback) {
const control = typeof item === 'function' ? item(this.art) : item.option;
if (control && !control.disable) {
const {
events: { proxy },
} = this.art;
id += 1;
const name = control.name || `control${id}`;
const $control = document.createElement('div');
$control.classList.value = `art-control art-control-${name}`;
if (control.html) {
append($control, control.html);
}
if (control.click) {
proxy($control, 'click', event => {
event.preventDefault();
control.click.call(this, event);
this.art.emit('control:click', $control);
});
}
if (item.apply) {
item.apply(this.art, $control);
}
this.mount(control.position, $control, control.index || id);
if (control.mounted) {
control.mounted($control);
}
if (callback) {
callback($control);
}
this.commonMethod(control, $control);
this[name] = control;
this.art.emit('control:add', $control);
}
}
mount(position, $control, index) {
const option = typeof item === 'function' ? item(this.art) : item;
const { $progress, $controlsLeft, $controlsRight } = this.art.refs;
switch (position) {
let parent;
switch (option.position) {
case 'top':
insertByIndex($progress, $control, index);
parent = $progress;
break;
case 'left':
insertByIndex($controlsLeft, $control, index);
parent = $controlsLeft;
break;
case 'right':
insertByIndex($controlsRight, $control, index);
parent = $controlsRight;
break;
default:
break;
}
}
commonMethod(control, $control) {
Object.defineProperty(control, '$ref', {
get: () => $control,
});
Object.defineProperty(control, 'hide', {
value: () => {
setStyle($control, 'display', 'none');
this.art.emit('control:hide', $control);
},
});
Object.defineProperty(control, 'show', {
value: () => {
setStyle($control, 'display', 'block');
this.art.emit('control:show', $control);
},
});
if (parent) {
componentMethod(this.art, this, parent, option, callback, 'control');
}
}
show() {
+16 -17
View File
@@ -1,21 +1,20 @@
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();
});
}
export default function pip(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
i18n,
player,
} = art;
const $pip = append($control, icons.pip);
tooltip($pip, i18n.get('Mini player'));
proxy($control, 'click', () => {
player.pipEnabled();
});
},
});
}
+30 -31
View File
@@ -1,39 +1,38 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class PlayAndPause {
constructor(option) {
this.option = option;
}
export default function playAndPause(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
player,
i18n,
} = art;
const $play = append($control, icons.play);
const $pause = append($control, icons.pause);
tooltip($play, i18n.get('Play'));
tooltip($pause, i18n.get('Pause'));
setStyle($pause, 'display', 'none');
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($play, 'click', () => {
player.play();
});
proxy(this.$play, 'click', () => {
player.play();
});
proxy($pause, 'click', () => {
player.pause();
});
proxy(this.$pause, 'click', () => {
player.pause();
});
art.on('video:playing', () => {
setStyle($play, 'display', 'none');
setStyle($pause, 'display', 'flex');
});
art.on('video:playing', () => {
setStyle(this.$play, 'display', 'none');
setStyle(this.$pause, 'display', 'flex');
});
art.on('video:pause', () => {
setStyle(this.$play, 'display', 'flex');
setStyle(this.$pause, 'display', 'none');
});
}
art.on('video:pause', () => {
setStyle($play, 'display', 'flex');
setStyle($pause, 'display', 'none');
});
},
});
}
+120 -123
View File
@@ -1,148 +1,145 @@
import { append, clamp, secondToTime, setStyle, getStyle } from '../utils';
export default class Progress {
constructor(option) {
this.option = option;
this.isDroging = false;
this.set = this.set.bind(this);
}
export function getPosFromEvent(art, event) {
const {
refs: { $progress },
player,
} = art;
const { left } = $progress.getBoundingClientRect();
const width = clamp(event.x - left, 0, $progress.clientWidth);
const second = (width / $progress.clientWidth) * player.duration;
const time = secondToTime(second);
const percentage = clamp(width / $progress.clientWidth, 0, 1);
return { second, time, width, percentage };
}
apply(art, $control) {
this.art = art;
this.$control = $control;
export default function progress(controlOption) {
return art => {
const {
option: { highlight, theme },
events: { proxy },
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>
return {
...controlOption,
html: `
<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>
`,
);
mounted: $control => {
let isDroging = false;
const $loaded = $control.querySelector('.art-progress-loaded');
const $played = $control.querySelector('.art-progress-played');
const $highlight = $control.querySelector('.art-progress-highlight');
const $indicator = $control.querySelector('.art-progress-indicator');
const $tip = $control.querySelector('.art-progress-tip');
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');
function showHighlight(event) {
const { text, time } = event.target.dataset;
$tip.innerHTML = text;
const left =
(Number(time) / art.player.duration) * $control.clientWidth +
event.target.clientWidth / 2 -
$tip.clientWidth / 2;
setStyle($tip, 'left', `${left}px`);
}
highlight.forEach(item => {
const left = (clamp(item.time, 0, player.duration) / player.duration) * 100;
append(
this.$highlight,
`<span data-text="${item.text}" data-time="${item.time}" style="left: ${left}%"></span>`,
);
});
function showTime(event) {
const { width, time } = getPosFromEvent(art, event);
const tipWidth = $tip.clientWidth;
$tip.innerHTML = time;
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`);
}
}
this.set('loaded', player.loaded);
function setBar(type, percentage) {
if (type === 'loaded') {
setStyle($loaded, 'width', `${percentage * 100}%`);
}
this.art.on('video:progress', () => {
this.set('loaded', player.loaded);
});
if (type === 'played') {
setStyle($played, 'width', `${percentage * 100}%`);
setStyle(
$indicator,
'left',
`calc(${percentage * 100}% - ${getStyle($indicator, 'width') / 2}px)`,
);
}
}
this.art.on('video:timeupdate', () => {
this.set('played', player.played);
});
highlight.forEach(item => {
const left = (clamp(item.time, 0, player.duration) / player.duration) * 100;
append(
$highlight,
`<span data-text="${item.text}" data-time="${item.time}" style="left: ${left}%"></span>`,
);
});
this.art.on('video:ended', () => {
this.set('played', 1);
});
setBar('loaded', player.loaded);
proxy($control, 'mousemove', event => {
setStyle(this.$tip, 'display', 'block');
if (event.composedPath().indexOf(this.$highlight) > -1) {
this.showHighlight(event);
} else {
this.showTime(event);
}
});
art.on('video:progress', () => {
setBar('loaded', player.loaded);
});
proxy($control, 'mouseout', () => {
setStyle(this.$tip, 'display', 'none');
});
art.on('video:timeupdate', () => {
setBar('played', player.played);
});
proxy($control, 'click', event => {
if (event.target !== this.$indicator) {
const { second, percentage } = this.getPosFromEvent(event);
this.set('played', percentage);
player.seek(second);
}
});
art.on('video:ended', () => {
setBar('played', 1);
});
proxy(this.$indicator, 'mousedown', () => {
this.isDroging = true;
});
proxy($control, 'mousemove', event => {
setStyle($tip, 'display', 'block');
if (event.composedPath().indexOf($highlight) > -1) {
showHighlight(event);
} else {
showTime(event);
}
});
proxy(document, 'mousemove', event => {
if (this.isDroging) {
const { second, percentage } = this.getPosFromEvent(event);
this.$indicator.classList.add('art-show-indicator');
this.set('played', percentage);
player.seek(second);
}
});
proxy($control, 'mouseout', () => {
setStyle($tip, 'display', 'none');
});
proxy(document, 'mouseup', () => {
if (this.isDroging) {
this.isDroging = false;
this.$indicator.classList.remove('art-show-indicator');
}
});
}
proxy($control, 'click', event => {
if (event.target !== $indicator) {
const { second, percentage } = getPosFromEvent(art, event);
setBar('played', percentage);
player.seek(second);
}
});
showHighlight(event) {
const { text, time } = event.target.dataset;
this.$tip.innerHTML = text;
const left =
(Number(time) / this.art.player.duration) * this.$control.clientWidth +
event.target.clientWidth / 2 -
this.$tip.clientWidth / 2;
setStyle(this.$tip, 'left', `${left}px`);
}
proxy($indicator, 'mousedown', () => {
isDroging = true;
});
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`);
}
}
proxy(document, 'mousemove', event => {
if (isDroging) {
const { second, percentage } = getPosFromEvent(art, event);
$indicator.classList.add('art-show-indicator');
setBar('played', percentage);
player.seek(second);
}
});
getPosFromEvent(event) {
const {
player,
refs: { $progress },
} = this.art;
const { left } = $progress.getBoundingClientRect();
const width = clamp(event.x - left, 0, $progress.clientWidth);
const second = (width / $progress.clientWidth) * player.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}% - ${getStyle(this.$indicator, 'width') / 2}px)`,
);
}
}
proxy(document, 'mouseup', () => {
if (isDroging) {
isDroging = false;
$indicator.classList.remove('art-show-indicator');
}
});
},
};
};
}
+28 -39
View File
@@ -1,43 +1,32 @@
import { append } from '../utils';
export default class Quality {
constructor(option) {
this.option = option;
this.playIndex = -1;
}
export default function quality(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
option,
events: { proxy },
player,
} = art;
let playIndex = -1;
const defaultQuality = option.quality.find(item => item.default) || option.quality[0];
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>`);
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('art-quality-hover');
},
() => {
$control.classList.remove('art-quality-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.switchQuality(url, name);
$qualityName.innerHTML = name;
this.playIndex = index;
}
});
}
proxy($qualitys, 'click', event => {
const index = Number(event.target.dataset.index);
const { url, name } = option.quality[index];
if (url && name && playIndex !== index) {
player.switchQuality(url, name);
$qualityName.innerHTML = name;
playIndex = index;
}
});
},
});
}
+16 -17
View File
@@ -1,21 +1,20 @@
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();
});
}
export default function screenshot(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
i18n,
player,
} = art;
const $screenshot = append($control, icons.screenshot);
tooltip($screenshot, i18n.get('Screenshot'));
proxy($screenshot, 'click', () => {
player.screenshot();
});
},
});
}
+24 -25
View File
@@ -1,32 +1,31 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Setting {
constructor(option) {
this.option = option;
}
export default function setting(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
i18n,
setting,
} = art;
const $setting = append($control, icons.setting);
tooltip($setting, i18n.get('Show setting'));
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();
});
proxy($control, 'click', () => {
setting.toggle();
});
art.on('setting:show', () => {
setStyle($setting, 'opacity', '0.8');
tooltip($setting, i18n.get('Hide setting'));
});
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'));
});
}
art.on('setting:hide', () => {
setStyle($setting, 'opacity', '1');
tooltip($setting, i18n.get('Show setting'));
});
},
});
}
+24 -25
View File
@@ -1,32 +1,31 @@
import { append, tooltip, setStyle } from '../utils';
import icons from '../icons';
export default class Subtitle {
constructor(option) {
this.option = option;
}
export default function subtitle(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
i18n,
subtitle,
} = art;
const $subtitle = append($control, icons.subtitle);
tooltip($subtitle, i18n.get('Hide subtitle'));
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();
});
proxy($control, 'click', () => {
subtitle.toggle();
});
art.on('subtitle:show', () => {
setStyle($subtitle, 'opacity', '1');
tooltip($subtitle, i18n.get('Hide subtitle'));
});
art.on('subtitle:show', () => {
setStyle(this.$subtitle, 'opacity', '1');
tooltip(this.$subtitle, i18n.get('Hide subtitle'));
});
art.on('subtitle:hide', () => {
setStyle(this.$subtitle, 'opacity', '0.8');
tooltip(this.$subtitle, i18n.get('Show subtitle'));
});
}
art.on('subtitle:hide', () => {
setStyle($subtitle, 'opacity', '0.8');
tooltip($subtitle, i18n.get('Show subtitle'));
});
},
});
}
+47 -56
View File
@@ -1,63 +1,54 @@
import { errorHandle, setStyle } from '../utils';
import { setStyle } from '../utils';
import { getPosFromEvent } from './progress';
export default class Thumbnails {
constructor(option) {
this.option = option;
this.loading = false;
this.isLoad = false;
}
export default function thumbnails(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
refs: { $progress },
events: { proxy, loadImg },
} = art;
let loading = false;
let isLoad = false;
apply(art, $control) {
this.art = art;
errorHandle(art.controls.progress, "'thumbnails' control dependent on 'progress' control");
const {
refs: { $progress },
events: { proxy, loadImg },
} = art;
this.$control = $control;
proxy($progress, 'mousemove', event => {
if (!this.loading) {
this.loading = true;
loadImg(this.art.option.thumbnails.url).then(() => {
this.isLoad = true;
});
function showThumbnails(event) {
const { width: posWidth } = getPosFromEvent(art, event);
const { url, height, width, number, column } = art.option.thumbnails;
const perWidth = $progress.clientWidth / number;
const perIndex = Math.ceil(posWidth / perWidth);
const yIndex = Math.ceil(perIndex / column) - 1;
const xIndex = perIndex % column || column - 1;
setStyle($control, 'backgroundImage', `url(${url})`);
setStyle($control, 'height', `${height}px`);
setStyle($control, 'width', `${width}px`);
setStyle($control, 'backgroundPosition', `-${xIndex * width}px -${yIndex * height}px`);
if (posWidth <= width / 2) {
setStyle($control, 'left', 0);
} else if (posWidth > $progress.clientWidth - width / 2) {
setStyle($control, 'left', `${$progress.clientWidth - width}px`);
} else {
setStyle($control, 'left', `${posWidth - width / 2}px`);
}
}
if (this.isLoad) {
setStyle($control, 'display', 'block');
this.showThumbnails(event);
}
});
proxy($progress, 'mousemove', event => {
if (!loading) {
loading = true;
loadImg(art.option.thumbnails.url).then(() => {
isLoad = true;
});
}
proxy($progress, 'mouseout', () => {
setStyle($control, 'display', 'none');
});
}
if (isLoad) {
setStyle($control, 'display', 'block');
showThumbnails(event);
}
});
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);
const yIndex = Math.ceil(perIndex / column) - 1;
const xIndex = perIndex % column || column - 1;
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`);
}
}
proxy($progress, 'mouseout', () => {
setStyle($control, 'display', 'none');
});
},
});
}
+15 -16
View File
@@ -1,21 +1,20 @@
import { secondToTime } from '../utils';
export default class Time {
constructor(option) {
this.option = option;
}
apply(art, $control) {
function getTime() {
const newTime = `${secondToTime(art.player.currentTime)} / ${secondToTime(art.player.duration)}`;
if (newTime !== $control.innerHTML) {
$control.innerHTML = newTime;
export default function time(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
function getTime() {
const newTime = `${secondToTime(art.player.currentTime)} / ${secondToTime(art.player.duration)}`;
if (newTime !== $control.innerHTML) {
$control.innerHTML = newTime;
}
}
}
getTime();
['video:loadedmetadata', 'video:timeupdate', 'video:progress'].forEach(event => {
art.on(event, getTime);
});
}
getTime();
['video:loadedmetadata', 'video:timeupdate', 'video:progress'].forEach(event => {
art.on(event, getTime);
});
},
});
}
+69 -72
View File
@@ -1,85 +1,82 @@
import { append, clamp, tooltip, setStyle, getStyle } from '../utils';
import icons from '../icons';
export default class Volume {
constructor(option) {
this.option = option;
this.isDroging = false;
}
export default function volume(controlOption) {
return art => ({
...controlOption,
mounted: $control => {
const {
events: { proxy },
player,
i18n,
} = art;
let isDroging = false;
const $volume = append($control, icons.volume);
const $volumeClose = append($control, icons.volumeClose);
const $volumePanel = append($control, '<div class="art-volume-panel"></div>');
const $volumeHandle = append($volumePanel, '<div class="art-volume-slider-handle"></div>');
tooltip($volume, i18n.get('Mute'));
setStyle($volumeClose, 'display', 'none');
apply(art, $control) {
this.art = art;
const {
events: { proxy },
player,
i18n,
} = art;
function volumeChangeFromEvent(event) {
const { left: panelLeft, width: panelWidth } = $volumePanel.getBoundingClientRect();
const { width: handleWidth } = $volumeHandle.getBoundingClientRect();
const percentage =
clamp(event.x - panelLeft - handleWidth / 2, 0, panelWidth - handleWidth / 2) /
(panelWidth - handleWidth);
return percentage;
}
this.$volume = append($control, icons.volume);
this.$volumeClose = append($control, icons.volumeClose);
this.$volumePanel = append($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');
function setVolumeHandle(percentage = 0.7) {
if (player.muted || percentage === 0) {
setStyle($volume, 'display', 'none');
setStyle($volumeClose, 'display', 'flex');
setStyle($volumeHandle, 'left', '0');
} else {
// TODO...
const panelWidth = getStyle($volumePanel, 'width') || 60;
const handleWidth = getStyle($volumeHandle, 'width');
const width = handleWidth / 2 + (panelWidth - handleWidth) * percentage - handleWidth / 2;
setStyle($volume, 'display', 'flex');
setStyle($volumeClose, 'display', 'none');
setStyle($volumeHandle, 'left', `${width}px`);
}
}
this.setVolumeHandle(player.volume);
art.on('video:volumechange', () => {
this.setVolumeHandle(player.volume);
});
setVolumeHandle(player.volume);
art.on('video:volumechange', () => {
setVolumeHandle(player.volume);
});
proxy(this.$volume, 'click', () => {
player.muted = true;
});
proxy($volume, 'click', () => {
player.muted = true;
});
proxy(this.$volumeClose, 'click', () => {
player.muted = false;
});
proxy(this.$volumePanel, 'click', event => {
player.muted = false;
player.volume = this.volumeChangeFromEvent(event);
});
proxy(this.$volumeHandle, 'mousedown', () => {
this.isDroging = true;
});
proxy(this.$volumeHandle, 'mousemove', event => {
if (this.isDroging) {
proxy($volumeClose, 'click', () => {
player.muted = false;
player.volume = this.volumeChangeFromEvent(event);
}
});
});
proxy(document, 'mouseup', () => {
if (this.isDroging) {
this.isDroging = false;
}
});
}
proxy($volumePanel, 'click', event => {
player.muted = false;
player.volume = volumeChangeFromEvent(event);
});
volumeChangeFromEvent(event) {
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);
return percentage;
}
proxy($volumeHandle, 'mousedown', () => {
isDroging = true;
});
setVolumeHandle(percentage = 0.7) {
const { player } = this.art;
if (player.muted || percentage === 0) {
setStyle(this.$volume, 'display', 'none');
setStyle(this.$volumeClose, 'display', 'flex');
setStyle(this.$volumeHandle, 'left', '0');
} else {
// TODO...
const panelWidth = getStyle(this.$volumePanel, 'width') || 60;
const handleWidth = getStyle(this.$volumeHandle, 'width');
const width = handleWidth / 2 + (panelWidth - handleWidth) * percentage - handleWidth / 2;
setStyle(this.$volume, 'display', 'flex');
setStyle(this.$volumeClose, 'display', 'none');
setStyle(this.$volumeHandle, 'left', `${width}px`);
}
}
proxy($volumeHandle, 'mousemove', event => {
if (isDroging) {
player.muted = false;
player.volume = volumeChangeFromEvent(event);
}
});
proxy(document, 'mouseup', () => {
if (isDroging) {
isDroging = false;
}
});
},
});
}
@@ -26,4 +26,8 @@
fill: #fff;
}
}
.art-hide {
display: none !important;
}
}
+1 -1
View File
@@ -228,7 +228,7 @@
}
}
}
&.art-quality-hover .art-qualitys{
&:hover .art-qualitys{
display: block;
}
}
@@ -24,6 +24,9 @@ export default function componentMethod(art, parent, target, component, callback
const { proxy } = art.events;
const option = typeof component === 'function' ? component(art) : component;
if (!option.disable) {
if (parent.id === undefined) {
parent.id = 0;
}
parent.id += 1;
const name = option.name || `${title}${parent.id}`;
const $element = document.createElement('div');
+11
View File
@@ -118,3 +118,14 @@ export function debounce(func, wait, context) {
return fn;
}
export function show(target, display) {
target.classList.remove('art-hide');
if (display) {
target.style.display = display;
}
}
export function hide(target) {
target.classList.add('art-hide');
}