Files
_hublib-web/dist/react/video-player/components/video-js/plugins/skip-buttons/index.js
2026-02-27 09:50:13 +03:00

145 lines
6.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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