Files
_hublib-web/dist/react/video-player/components/video-js/plugins/skip-buttons/index.js

145 lines
6.5 KiB
JavaScript
Raw Normal View History

2026-02-27 09:50:13 +03:00
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// skipButtonsPlugin.tsx
import React from "react";
import { createRoot } from "react-dom/client";
import videojs from "video.js";
import BackwardSvg from "./skip-backward.svg";
import ForwardSvg from "./skip-forward.svg";
import "./skip-buttons.css";
import { numWord } from "../../../../shared/math";
const renderSvg = (asset) => {
if (typeof asset === "string") {
return _jsx("img", { src: asset, alt: "", "aria-hidden": "true" });
}
const SvgComponent = asset;
return _jsx(SvgComponent, {});
};
const SkipButton = ({ player, skip, direction }) => {
// Накопленная сумма перемотки
const [accumulated, setAccumulated] = React.useState(0);
// Храним ID таймера debounce
const timerRef = React.useRef(null);
// Используем ref для мгновенного доступа к накопленному значению
const accumulatedRef = React.useRef(0);
const handleClick = () => {
// Вычисляем новое накопленное значение
const newAccumulated = direction === "forward"
? accumulatedRef.current + skip
: accumulatedRef.current - skip;
accumulatedRef.current = newAccumulated;
setAccumulated(newAccumulated);
// Сбрасываем предыдущий таймер
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// Устанавливаем debounce (500 мс)
timerRef.current = setTimeout(() => {
const currentTime = player.currentTime() || 0;
const newTime = currentTime + accumulatedRef.current;
player.currentTime(newTime);
// Сбрасываем накопленное значение
accumulatedRef.current = 0;
setAccumulated(0);
}, 500);
};
return (_jsxs("button", { onClick: handleClick, className: `vjs-skip-button vjs-skip-button-${direction}`, children: [_jsx("span", { className: "icon-placeholder", children: skip }), accumulated ? (_jsxs("div", { className: "scroll-info", children: [direction === "backward"
? renderSvg(BackwardSvg)
: renderSvg(ForwardSvg), `${Math.abs(accumulated)} ${numWord(accumulated, ["секунду", "секунды", "секунд"])}`] })) : null] }));
};
// Базовый Video.js компонент, обёртывающий React-компонент
class SkipButtonComponent extends videojs.getComponent("Component") {
constructor() {
super(...arguments);
this.reactRoot = null;
}
createEl() {
const direction = this.options_.direction;
const el = super.createEl("div", {
className: `vjs-skip-button-component vjs-skip-${direction}`,
});
// Рендерим React-компонент сразу внутри созданного элемента
this.reactRoot = createRoot(el);
this.reactRoot.render(_jsx(SkipButton, { player: this.player(), skip: this.options_.skip, direction: direction }));
return el;
}
dispose() {
if (this.reactRoot) {
this.reactRoot.unmount();
this.reactRoot = null;
}
super.dispose();
}
}
// Компонент для кнопки перемотки назад задаём direction через options
class SkipBackwardButtonComponent extends SkipButtonComponent {
constructor(player, options) {
options.direction = "backward";
super(player, options);
}
}
// Компонент для кнопки перемотки вперёд задаём direction через options
class SkipForwardButtonComponent extends SkipButtonComponent {
constructor(player, options) {
options.direction = "forward";
super(player, options);
}
}
// Регистрируем компоненты в Video.js
videojs.registerComponent("SkipBackwardButtonComponent", SkipBackwardButtonComponent);
videojs.registerComponent("SkipForwardButtonComponent", SkipForwardButtonComponent);
// Плагин, который добавляет два отдельных компонента через player.addChild
const skipButtonsPlugin = function (options) {
const player = this;
player.ready(() => {
// 1) Добавляем кнопки
player.addChild("SkipBackwardButtonComponent", { skip: options.skip });
player.addChild("SkipForwardButtonComponent", { skip: options.skip });
// 2) Вспомогательная функция, которая находит кнопку и вызывает click()
const triggerSkipClick = (direction) => {
// Ищем именно <button class="vjs-skip-button vjs-skip-button-{direction}">
const selector = `.vjs-skip-button-${direction}`;
const btn = player.el().querySelector(selector);
if (btn)
btn.click();
};
// 3) Обработка стрелок
const onKeydown = (e) => {
// Если фокус в инпуте/textarea/select или contenteditable — выходим
const active = document.activeElement;
const tag = active?.tagName;
const isEditable = tag === "INPUT" ||
tag === "TEXTAREA" ||
tag === "SELECT" ||
active?.getAttribute("contenteditable") === "true";
if (isEditable)
return;
if (e.key === " " || e.code === "Space") {
player.el()?.focus();
e.preventDefault();
if (player.paused())
player.play();
else
player.pause();
return;
}
if (e.key === "ArrowRight") {
player.el()?.focus();
e.preventDefault();
triggerSkipClick("forward");
}
else if (e.key === "ArrowLeft") {
player.el()?.focus();
e.preventDefault();
triggerSkipClick("backward");
}
};
document.addEventListener("keydown", onKeydown);
// 4) Убираем слушатель при dispose
player.on("dispose", () => {
document.removeEventListener("keydown", onKeydown);
});
});
};
videojs.registerPlugin("skipButtons", skipButtonsPlugin);
export default skipButtonsPlugin;
//# sourceMappingURL=index.js.map