vidply 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/vidply.css +154 -52
- package/dist/vidply.esm.js +1867 -731
- package/dist/vidply.esm.js.map +3 -3
- package/dist/vidply.esm.min.js +3 -3
- package/dist/vidply.esm.min.meta.json +28 -10
- package/dist/vidply.js +1867 -731
- package/dist/vidply.js.map +3 -3
- package/dist/vidply.min.css +1 -1
- package/dist/vidply.min.js +3 -3
- package/dist/vidply.min.meta.json +27 -9
- package/package.json +1 -1
- package/src/controls/ControlBar.js +24 -14
- package/src/controls/TranscriptManager.js +658 -591
- package/src/core/Player.js +831 -331
- package/src/i18n/translations.js +55 -5
- package/src/icons/Icons.js +2 -2
- package/src/styles/vidply.css +154 -52
- package/src/utils/DraggableResizable.js +771 -0
package/dist/vidply.js
CHANGED
|
@@ -517,10 +517,20 @@ var VidPly = (() => {
|
|
|
517
517
|
settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
|
|
518
518
|
keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
|
|
519
519
|
keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
|
|
520
|
+
dragResizePrompt: "Press D to drag or R to resize. Use Home to reset position, Esc to close.",
|
|
521
|
+
dragModeEnabled: "Keyboard drag mode enabled. Use arrow keys to move, Shift+Arrow for larger steps. Press D or Esc to exit.",
|
|
522
|
+
dragModeDisabled: "Keyboard drag mode disabled.",
|
|
520
523
|
resizeWindow: "Resize Window",
|
|
524
|
+
disableResizeWindow: "Disable Resize Mode",
|
|
525
|
+
resizeModeHint: "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
|
|
526
|
+
resizeModeEnabled: "Resize mode enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
|
|
527
|
+
resizeModeDisabled: "Resize mode disabled.",
|
|
528
|
+
positionReset: "Transcript position reset.",
|
|
521
529
|
styleTranscript: "Open transcript style settings",
|
|
522
530
|
closeMenu: "Close Menu",
|
|
523
|
-
styleTitle: "Transcript Style"
|
|
531
|
+
styleTitle: "Transcript Style",
|
|
532
|
+
autoscroll: "Autoscroll",
|
|
533
|
+
settingsMenu: "Settings menu"
|
|
524
534
|
},
|
|
525
535
|
settings: {
|
|
526
536
|
title: "Settings",
|
|
@@ -638,10 +648,20 @@ var VidPly = (() => {
|
|
|
638
648
|
settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
|
|
639
649
|
keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
|
|
640
650
|
keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
|
|
651
|
+
dragResizePrompt: "Dr\xFCcken Sie D zum Verschieben oder R zur Gr\xF6\xDFen\xE4nderung. Home setzt die Position zur\xFCck, Esc schlie\xDFt.",
|
|
652
|
+
dragModeEnabled: "Tastatur-Verschiebemodus aktiviert. Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gr\xF6\xDFere Schritte. D oder Esc zum Beenden.",
|
|
653
|
+
dragModeDisabled: "Tastatur-Verschiebemodus deaktiviert.",
|
|
641
654
|
resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
|
|
655
|
+
disableResizeWindow: "Resize-Modus deaktivieren",
|
|
656
|
+
resizeModeHint: "Griffe aktiviert. Ziehen Sie Kanten oder Ecken zum Anpassen. Esc oder R zum Beenden.",
|
|
657
|
+
resizeModeEnabled: "Resize-Modus aktiviert. Kanten oder Ecken ziehen; Esc oder R beendet.",
|
|
658
|
+
resizeModeDisabled: "Resize-Modus deaktiviert.",
|
|
659
|
+
positionReset: "Transkriptposition zur\xFCckgesetzt.",
|
|
642
660
|
styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
|
|
643
661
|
closeMenu: "Men\xFC schlie\xDFen",
|
|
644
|
-
styleTitle: "Transkript-Stil"
|
|
662
|
+
styleTitle: "Transkript-Stil",
|
|
663
|
+
autoscroll: "Automatisches Scrollen",
|
|
664
|
+
settingsMenu: "Einstellungsmen\xFC"
|
|
645
665
|
},
|
|
646
666
|
settings: {
|
|
647
667
|
title: "Einstellungen",
|
|
@@ -759,10 +779,20 @@ var VidPly = (() => {
|
|
|
759
779
|
settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
|
|
760
780
|
keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
|
|
761
781
|
keyboardDragActive: "\u2328\uFE0F Modo de Arrastre con Teclado Activo (Teclas de flecha para mover, May\xFAs+Flechas para pasos grandes, D o ESC para salir)",
|
|
782
|
+
dragResizePrompt: "Pulsa D para mover o R para cambiar el tama\xF1o. Home restablece la posici\xF3n; Esc cierra.",
|
|
783
|
+
dragModeEnabled: "Modo de arrastre con teclado activado. Usa flechas para mover, May\xFAs+Flechas para pasos grandes. Pulsa D o Esc para salir.",
|
|
784
|
+
dragModeDisabled: "Modo de arrastre con teclado desactivado.",
|
|
762
785
|
resizeWindow: "Cambiar tama\xF1o de ventana",
|
|
786
|
+
disableResizeWindow: "Desactivar modo de cambio de tama\xF1o",
|
|
787
|
+
resizeModeHint: "Controladores habilitados. Arrastra bordes o esquinas para ajustar. Pulsa Esc o R para salir.",
|
|
788
|
+
resizeModeEnabled: "Modo de cambio de tama\xF1o activado. Arrastra bordes o esquinas. Pulsa Esc o R para salir.",
|
|
789
|
+
resizeModeDisabled: "Modo de cambio de tama\xF1o desactivado.",
|
|
790
|
+
positionReset: "Posici\xF3n de la transcripci\xF3n restablecida.",
|
|
763
791
|
styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
|
|
764
792
|
closeMenu: "Cerrar men\xFA",
|
|
765
|
-
styleTitle: "Estilo de Transcripci\xF3n"
|
|
793
|
+
styleTitle: "Estilo de Transcripci\xF3n",
|
|
794
|
+
autoscroll: "Desplazamiento autom\xE1tico",
|
|
795
|
+
settingsMenu: "Men\xFA de configuraci\xF3n"
|
|
766
796
|
},
|
|
767
797
|
settings: {
|
|
768
798
|
title: "Configuraci\xF3n",
|
|
@@ -880,10 +910,20 @@ var VidPly = (() => {
|
|
|
880
910
|
settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
|
|
881
911
|
keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
|
|
882
912
|
keyboardDragActive: "\u2328\uFE0F Mode Glissement Clavier Actif (Touches fl\xE9ch\xE9es pour d\xE9placer, Maj+Fl\xE9ch\xE9es pour grands pas, D ou \xC9chap pour quitter)",
|
|
913
|
+
dragResizePrompt: "Appuyez sur D pour d\xE9placer ou R pour redimensionner. Home r\xE9initialise la position, \xC9chap ferme.",
|
|
914
|
+
dragModeEnabled: "Mode glissement clavier activ\xE9. Utilisez les fl\xE8ches pour d\xE9placer, Maj+Fl\xE8ches pour de grands pas. Appuyez sur D ou \xC9chap pour quitter.",
|
|
915
|
+
dragModeDisabled: "Mode glissement clavier d\xE9sactiv\xE9.",
|
|
883
916
|
resizeWindow: "Redimensionner la fen\xEAtre",
|
|
917
|
+
disableResizeWindow: "D\xE9sactiver le mode de redimensionnement",
|
|
918
|
+
resizeModeHint: "Poign\xE9es activ\xE9es. Faites glisser les bords ou les coins pour ajuster. Appuyez sur \xC9chap ou R pour quitter.",
|
|
919
|
+
resizeModeEnabled: "Mode redimensionnement activ\xE9. Faites glisser les bords ou coins. Appuyez sur \xC9chap ou R pour quitter.",
|
|
920
|
+
resizeModeDisabled: "Mode redimensionnement d\xE9sactiv\xE9.",
|
|
921
|
+
positionReset: "Position de la transcription r\xE9initialis\xE9e.",
|
|
884
922
|
styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
|
|
885
923
|
closeMenu: "Fermer le menu",
|
|
886
|
-
styleTitle: "Style de Transcription"
|
|
924
|
+
styleTitle: "Style de Transcription",
|
|
925
|
+
autoscroll: "D\xE9filement automatique",
|
|
926
|
+
settingsMenu: "Menu des param\xE8tres"
|
|
887
927
|
},
|
|
888
928
|
settings: {
|
|
889
929
|
title: "Param\xE8tres",
|
|
@@ -1001,10 +1041,20 @@ var VidPly = (() => {
|
|
|
1001
1041
|
settings: "\u6587\u5B57\u8D77\u3053\u3057\u8A2D\u5B9A\u3002Enter\u30AD\u30FC\u3067\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F\u3001\u307E\u305F\u306FD\u30AD\u30FC\u3067\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3059\u308B",
|
|
1002
1042
|
keyboardDragMode: "\u77E2\u5370\u30AD\u30FC\u3067\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u5207\u308A\u66FF\u3048\u3002\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8\uFF1AD\u30AD\u30FC",
|
|
1003
1043
|
keyboardDragActive: "\u2328\uFE0F \u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u6709\u52B9\uFF08\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Shift+\u77E2\u5370\u30AD\u30FC\u3067\u5927\u304D\u304F\u79FB\u52D5\u3001D\u307E\u305F\u306FESC\u3067\u7D42\u4E86\uFF09",
|
|
1044
|
+
dragResizePrompt: "D\u30AD\u30FC\u3067\u79FB\u52D5\u3001R\u30AD\u30FC\u3067\u30B5\u30A4\u30BA\u5909\u66F4\u3002Home\u3067\u4F4D\u7F6E\u3092\u30EA\u30BB\u30C3\u30C8\u3001Esc\u3067\u9589\u3058\u307E\u3059\u3002",
|
|
1045
|
+
dragModeEnabled: "\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u307E\u3057\u305F\u3002\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Shift+\u77E2\u5370\u30AD\u30FC\u3067\u5927\u304D\u304F\u79FB\u52D5\u3067\u304D\u307E\u3059\u3002\u7D42\u4E86\u3059\u308B\u306B\u306F D \u307E\u305F\u306F Esc \u3092\u62BC\u3057\u307E\u3059\u3002",
|
|
1046
|
+
dragModeDisabled: "\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
|
|
1004
1047
|
resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
|
|
1048
|
+
disableResizeWindow: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3059\u308B",
|
|
1049
|
+
resizeModeHint: "\u30EA\u30B5\u30A4\u30BA\u30CF\u30F3\u30C9\u30EB\u304C\u6709\u52B9\u306B\u306A\u308A\u307E\u3057\u305F\u3002\u8FBA\u3084\u89D2\u3092\u30C9\u30E9\u30C3\u30B0\u3057\u3066\u8ABF\u6574\u3057\u307E\u3059\u3002Esc \u307E\u305F\u306F R \u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
|
|
1050
|
+
resizeModeEnabled: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u307E\u3057\u305F\u3002\u8FBA\u3084\u89D2\u3092\u30C9\u30E9\u30C3\u30B0\u3057\u3066\u8ABF\u6574\u3057\u307E\u3059\u3002Esc \u307E\u305F\u306F R \u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
|
|
1051
|
+
resizeModeDisabled: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
|
|
1052
|
+
positionReset: "\u6587\u5B57\u8D77\u3053\u3057\u306E\u4F4D\u7F6E\u3092\u30EA\u30BB\u30C3\u30C8\u3057\u307E\u3057\u305F\u3002",
|
|
1005
1053
|
styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
|
|
1006
1054
|
closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
|
|
1007
|
-
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB"
|
|
1055
|
+
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB",
|
|
1056
|
+
autoscroll: "\u81EA\u52D5\u30B9\u30AF\u30ED\u30FC\u30EB",
|
|
1057
|
+
settingsMenu: "\u8A2D\u5B9A\u30E1\u30CB\u30E5\u30FC"
|
|
1008
1058
|
},
|
|
1009
1059
|
settings: {
|
|
1010
1060
|
title: "\u8A2D\u5B9A",
|
|
@@ -1183,8 +1233,8 @@ var VidPly = (() => {
|
|
|
1183
1233
|
language: `<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"/>`,
|
|
1184
1234
|
hd: `<path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-8 12H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm7-1c0 .55-.45 1-1 1h-.75v1.5h-1.5V15H14c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v4zm-3.5-.5h2v-3h-2v3z"/>`,
|
|
1185
1235
|
transcript: `<path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/>`,
|
|
1186
|
-
audioDescription: `<rect x="2" y="5" width="20" height="14" rx="2" fill="
|
|
1187
|
-
audioDescriptionOn: `<rect x="2" y="5" width="20" height="14" rx="2" fill="
|
|
1236
|
+
audioDescription: `<rect x="2" y="5" width="20" height="14" rx="2" fill="#ffffff" stroke="#ffffff" stroke-width="2"/><text x="12" y="16" font-family="Arial, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" fill="#1a1a1a">AD</text>`,
|
|
1237
|
+
audioDescriptionOn: `<rect x="2" y="5" width="20" height="14" rx="2" fill="none" stroke="currentColor" stroke-width="2"/><text x="12" y="16" font-family="Arial, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" fill="currentColor">AD</text>`,
|
|
1188
1238
|
signLanguage: `<g transform="scale(1.5)"><path d="M16 11.3c-.1-.9-4.8 1.3-5.4 1.1-2.6-1 5.8-1.3 5.1-2.9s-5.1 1.5-6 1.4C6.5 9.4 16.5 9.1 13.5 8c-1.9-.6-8.8 2.9-6.8.4.7-.6.7-1.9-.7-1.7-9.7 7.2-.7 12.2 8.8 7 0-1.3-3.5.4-4.1.4-2.6 0 5.6-2 5.4-3ZM3.9 7.8c3.2-4.2 3.7 1.2 6 .1s.2-.2.2-.3c.7-2.7 2.5-7.5-1.5-1.3-1.6 0 1.1-4 1-4.6C8.9-1 7.3 4.4 7.2 4.9c-1.6.7-.9-1.4-.7-1.5 3-6-.6-3.1-.9.4-2.5 1.8 0-2.8 0-3.5C2.8-.9 4 9.4 1.1 4.9S.1 4.6 0 5c-.4 2.7 2.6 7.2 3.9 2.8Z"/></g>`,
|
|
1189
1239
|
signLanguageOn: `<g transform="scale(1.5)"><path d="M16 11.3c-.1-.9-4.8 1.3-5.4 1.1-2.6-1 5.8-1.3 5.1-2.9s-5.1 1.5-6 1.4C6.5 9.4 16.5 9.1 13.5 8c-1.9-.6-8.8 2.9-6.8.4.7-.6.7-1.9-.7-1.7-9.7 7.2-.7 12.2 8.8 7 0-1.3-3.5.4-4.1.4-2.6 0 5.6-2 5.4-3ZM3.9 7.8c3.2-4.2 3.7 1.2 6 .1s.2-.2.2-.3c.7-2.7 2.5-7.5-1.5-1.3-1.6 0 1.1-4 1-4.6C8.9-1 7.3 4.4 7.2 4.9c-1.6.7-.9-1.4-.7-1.5 3-6-.6-3.1-.9.4-2.5 1.8 0-2.8 0-3.5C2.8-.9 4 9.4 1.1 4.9S.1 4.6 0 5c-.4 2.7 2.6 7.2 3.9 2.8Z"/></g>`,
|
|
1190
1240
|
speaker: `<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z"/>`,
|
|
@@ -1792,10 +1842,7 @@ var VidPly = (() => {
|
|
|
1792
1842
|
}
|
|
1793
1843
|
});
|
|
1794
1844
|
this.controls.currentTimeDisplay = DOMUtils.createElement("span", {
|
|
1795
|
-
className: `${this.player.options.classPrefix}-current-time
|
|
1796
|
-
attributes: {
|
|
1797
|
-
"aria-label": i18n.t("time.seconds", { count: 0 })
|
|
1798
|
-
}
|
|
1845
|
+
className: `${this.player.options.classPrefix}-current-time`
|
|
1799
1846
|
});
|
|
1800
1847
|
const currentTimeVisual = DOMUtils.createElement("span", {
|
|
1801
1848
|
textContent: "00:00",
|
|
@@ -1803,8 +1850,14 @@ var VidPly = (() => {
|
|
|
1803
1850
|
"aria-hidden": "true"
|
|
1804
1851
|
}
|
|
1805
1852
|
});
|
|
1853
|
+
const currentTimeAccessible = DOMUtils.createElement("span", {
|
|
1854
|
+
className: "vidply-sr-only",
|
|
1855
|
+
textContent: i18n.t("time.seconds", { count: 0 })
|
|
1856
|
+
});
|
|
1806
1857
|
this.controls.currentTimeDisplay.appendChild(currentTimeVisual);
|
|
1858
|
+
this.controls.currentTimeDisplay.appendChild(currentTimeAccessible);
|
|
1807
1859
|
this.controls.currentTimeVisual = currentTimeVisual;
|
|
1860
|
+
this.controls.currentTimeAccessible = currentTimeAccessible;
|
|
1808
1861
|
const separator = DOMUtils.createElement("span", {
|
|
1809
1862
|
textContent: " / ",
|
|
1810
1863
|
attributes: {
|
|
@@ -1812,10 +1865,7 @@ var VidPly = (() => {
|
|
|
1812
1865
|
}
|
|
1813
1866
|
});
|
|
1814
1867
|
this.controls.durationDisplay = DOMUtils.createElement("span", {
|
|
1815
|
-
className: `${this.player.options.classPrefix}-duration
|
|
1816
|
-
attributes: {
|
|
1817
|
-
"aria-label": i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
|
|
1818
|
-
}
|
|
1868
|
+
className: `${this.player.options.classPrefix}-duration`
|
|
1819
1869
|
});
|
|
1820
1870
|
const durationVisual = DOMUtils.createElement("span", {
|
|
1821
1871
|
textContent: "00:00",
|
|
@@ -1823,8 +1873,14 @@ var VidPly = (() => {
|
|
|
1823
1873
|
"aria-hidden": "true"
|
|
1824
1874
|
}
|
|
1825
1875
|
});
|
|
1876
|
+
const durationAccessible = DOMUtils.createElement("span", {
|
|
1877
|
+
className: "vidply-sr-only",
|
|
1878
|
+
textContent: i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
|
|
1879
|
+
});
|
|
1826
1880
|
this.controls.durationDisplay.appendChild(durationVisual);
|
|
1881
|
+
this.controls.durationDisplay.appendChild(durationAccessible);
|
|
1827
1882
|
this.controls.durationVisual = durationVisual;
|
|
1883
|
+
this.controls.durationAccessible = durationAccessible;
|
|
1828
1884
|
container.appendChild(this.controls.currentTimeDisplay);
|
|
1829
1885
|
container.appendChild(separator);
|
|
1830
1886
|
container.appendChild(this.controls.durationDisplay);
|
|
@@ -2651,14 +2707,18 @@ var VidPly = (() => {
|
|
|
2651
2707
|
if (this.controls.currentTimeVisual) {
|
|
2652
2708
|
const currentTime = this.player.state.currentTime;
|
|
2653
2709
|
this.controls.currentTimeVisual.textContent = TimeUtils.formatTime(currentTime);
|
|
2654
|
-
this.controls.
|
|
2710
|
+
if (this.controls.currentTimeAccessible) {
|
|
2711
|
+
this.controls.currentTimeAccessible.textContent = TimeUtils.formatDuration(currentTime);
|
|
2712
|
+
}
|
|
2655
2713
|
}
|
|
2656
2714
|
}
|
|
2657
2715
|
updateDuration() {
|
|
2658
2716
|
if (this.controls.durationVisual) {
|
|
2659
2717
|
const duration = this.player.state.duration;
|
|
2660
2718
|
this.controls.durationVisual.textContent = TimeUtils.formatTime(duration);
|
|
2661
|
-
this.controls.
|
|
2719
|
+
if (this.controls.durationAccessible) {
|
|
2720
|
+
this.controls.durationAccessible.textContent = i18n.t("time.durationPrefix") + TimeUtils.formatDuration(duration);
|
|
2721
|
+
}
|
|
2662
2722
|
}
|
|
2663
2723
|
}
|
|
2664
2724
|
updateVolumeDisplay() {
|
|
@@ -3313,6 +3373,596 @@ var VidPly = (() => {
|
|
|
3313
3373
|
}
|
|
3314
3374
|
};
|
|
3315
3375
|
|
|
3376
|
+
// src/utils/DraggableResizable.js
|
|
3377
|
+
var DraggableResizable = class {
|
|
3378
|
+
constructor(element, options = {}) {
|
|
3379
|
+
this.element = element;
|
|
3380
|
+
this.options = {
|
|
3381
|
+
dragHandle: null,
|
|
3382
|
+
// Element to use as drag handle (defaults to element itself)
|
|
3383
|
+
resizeHandles: [],
|
|
3384
|
+
// Array of resize handle elements
|
|
3385
|
+
onDragStart: null,
|
|
3386
|
+
onDrag: null,
|
|
3387
|
+
onDragEnd: null,
|
|
3388
|
+
onResizeStart: null,
|
|
3389
|
+
onResize: null,
|
|
3390
|
+
onResizeEnd: null,
|
|
3391
|
+
constrainToViewport: true,
|
|
3392
|
+
// Allow movement outside viewport?
|
|
3393
|
+
minWidth: 150,
|
|
3394
|
+
minHeight: 100,
|
|
3395
|
+
maintainAspectRatio: false,
|
|
3396
|
+
keyboardDragKey: "d",
|
|
3397
|
+
keyboardResizeKey: "r",
|
|
3398
|
+
keyboardStep: 5,
|
|
3399
|
+
keyboardStepLarge: 10,
|
|
3400
|
+
maxWidth: null,
|
|
3401
|
+
maxHeight: null,
|
|
3402
|
+
pointerResizeIndicatorText: null,
|
|
3403
|
+
onPointerResizeToggle: null,
|
|
3404
|
+
classPrefix: "draggable",
|
|
3405
|
+
storage: null,
|
|
3406
|
+
// StorageManager instance for saving position/size
|
|
3407
|
+
storageKey: null,
|
|
3408
|
+
// Key for localStorage (if storage is provided)
|
|
3409
|
+
...options
|
|
3410
|
+
};
|
|
3411
|
+
this.isDragging = false;
|
|
3412
|
+
this.isResizing = false;
|
|
3413
|
+
this.resizeDirection = null;
|
|
3414
|
+
this.dragOffsetX = 0;
|
|
3415
|
+
this.dragOffsetY = 0;
|
|
3416
|
+
this.positionOffsetX = 0;
|
|
3417
|
+
this.positionOffsetY = 0;
|
|
3418
|
+
this.initialMouseX = 0;
|
|
3419
|
+
this.initialMouseY = 0;
|
|
3420
|
+
this.needsPositionConversion = false;
|
|
3421
|
+
this.resizeStartX = 0;
|
|
3422
|
+
this.resizeStartY = 0;
|
|
3423
|
+
this.resizeStartWidth = 0;
|
|
3424
|
+
this.resizeStartHeight = 0;
|
|
3425
|
+
this.resizeStartLeft = 0;
|
|
3426
|
+
this.resizeStartTop = 0;
|
|
3427
|
+
this.keyboardDragMode = false;
|
|
3428
|
+
this.keyboardResizeMode = false;
|
|
3429
|
+
this.pointerResizeMode = false;
|
|
3430
|
+
this.manuallyPositioned = false;
|
|
3431
|
+
this.resizeHandlesManaged = /* @__PURE__ */ new Map();
|
|
3432
|
+
this.resizeIndicatorElement = null;
|
|
3433
|
+
this.handlers = {
|
|
3434
|
+
mousedown: this.onMouseDown.bind(this),
|
|
3435
|
+
mousemove: this.onMouseMove.bind(this),
|
|
3436
|
+
mouseup: this.onMouseUp.bind(this),
|
|
3437
|
+
touchstart: this.onTouchStart.bind(this),
|
|
3438
|
+
touchmove: this.onTouchMove.bind(this),
|
|
3439
|
+
touchend: this.onTouchEnd.bind(this),
|
|
3440
|
+
keydown: this.onKeyDown.bind(this),
|
|
3441
|
+
resizeHandleMousedown: this.onResizeHandleMouseDown.bind(this)
|
|
3442
|
+
};
|
|
3443
|
+
this.init();
|
|
3444
|
+
}
|
|
3445
|
+
hasManagedResizeHandles() {
|
|
3446
|
+
return Array.from(this.resizeHandlesManaged.values()).some(Boolean);
|
|
3447
|
+
}
|
|
3448
|
+
storeOriginalHandleDisplay(handle) {
|
|
3449
|
+
if (!handle.dataset.originalDisplay) {
|
|
3450
|
+
handle.dataset.originalDisplay = handle.style.display || "";
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
hideResizeHandle(handle) {
|
|
3454
|
+
handle.style.display = "none";
|
|
3455
|
+
handle.setAttribute("aria-hidden", "true");
|
|
3456
|
+
}
|
|
3457
|
+
showResizeHandle(handle) {
|
|
3458
|
+
const original = handle.dataset.originalDisplay !== void 0 ? handle.dataset.originalDisplay : "";
|
|
3459
|
+
handle.style.display = original;
|
|
3460
|
+
handle.removeAttribute("aria-hidden");
|
|
3461
|
+
}
|
|
3462
|
+
setManagedHandlesVisible(visible) {
|
|
3463
|
+
if (!this.options.resizeHandles || this.options.resizeHandles.length === 0) {
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
this.options.resizeHandles.forEach((handle) => {
|
|
3467
|
+
if (!this.resizeHandlesManaged.get(handle)) {
|
|
3468
|
+
return;
|
|
3469
|
+
}
|
|
3470
|
+
if (visible) {
|
|
3471
|
+
this.showResizeHandle(handle);
|
|
3472
|
+
} else {
|
|
3473
|
+
this.hideResizeHandle(handle);
|
|
3474
|
+
}
|
|
3475
|
+
});
|
|
3476
|
+
}
|
|
3477
|
+
init() {
|
|
3478
|
+
const dragHandle = this.options.dragHandle || this.element;
|
|
3479
|
+
dragHandle.addEventListener("mousedown", this.handlers.mousedown);
|
|
3480
|
+
dragHandle.addEventListener("touchstart", this.handlers.touchstart);
|
|
3481
|
+
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
3482
|
+
document.addEventListener("mouseup", this.handlers.mouseup);
|
|
3483
|
+
document.addEventListener("touchmove", this.handlers.touchmove, { passive: false });
|
|
3484
|
+
document.addEventListener("touchend", this.handlers.touchend);
|
|
3485
|
+
this.element.addEventListener("keydown", this.handlers.keydown);
|
|
3486
|
+
if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
|
|
3487
|
+
this.options.resizeHandles.forEach((handle) => {
|
|
3488
|
+
handle.addEventListener("mousedown", this.handlers.resizeHandleMousedown);
|
|
3489
|
+
handle.addEventListener("touchstart", this.handlers.resizeHandleMousedown);
|
|
3490
|
+
const managed = handle.dataset.vidplyManagedResize === "true";
|
|
3491
|
+
this.resizeHandlesManaged.set(handle, managed);
|
|
3492
|
+
if (managed) {
|
|
3493
|
+
this.storeOriginalHandleDisplay(handle);
|
|
3494
|
+
this.hideResizeHandle(handle);
|
|
3495
|
+
}
|
|
3496
|
+
});
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
onMouseDown(e) {
|
|
3500
|
+
if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
if (this.options.onDragStart && !this.options.onDragStart(e)) {
|
|
3504
|
+
return;
|
|
3505
|
+
}
|
|
3506
|
+
this.startDragging(e.clientX, e.clientY);
|
|
3507
|
+
e.preventDefault();
|
|
3508
|
+
}
|
|
3509
|
+
onTouchStart(e) {
|
|
3510
|
+
if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
|
|
3511
|
+
return;
|
|
3512
|
+
}
|
|
3513
|
+
if (this.options.onDragStart && !this.options.onDragStart(e)) {
|
|
3514
|
+
return;
|
|
3515
|
+
}
|
|
3516
|
+
const touch = e.touches[0];
|
|
3517
|
+
this.startDragging(touch.clientX, touch.clientY);
|
|
3518
|
+
}
|
|
3519
|
+
onResizeHandleMouseDown(e) {
|
|
3520
|
+
var _a, _b, _c, _d;
|
|
3521
|
+
e.preventDefault();
|
|
3522
|
+
e.stopPropagation();
|
|
3523
|
+
const handle = e.target;
|
|
3524
|
+
this.resizeDirection = handle.getAttribute("data-direction");
|
|
3525
|
+
const clientX = e.clientX || ((_b = (_a = e.touches) == null ? void 0 : _a[0]) == null ? void 0 : _b.clientX);
|
|
3526
|
+
const clientY = e.clientY || ((_d = (_c = e.touches) == null ? void 0 : _c[0]) == null ? void 0 : _d.clientY);
|
|
3527
|
+
this.startResizing(clientX, clientY);
|
|
3528
|
+
}
|
|
3529
|
+
onMouseMove(e) {
|
|
3530
|
+
if (this.isDragging) {
|
|
3531
|
+
this.drag(e.clientX, e.clientY);
|
|
3532
|
+
e.preventDefault();
|
|
3533
|
+
} else if (this.isResizing) {
|
|
3534
|
+
this.resize(e.clientX, e.clientY);
|
|
3535
|
+
e.preventDefault();
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
onTouchMove(e) {
|
|
3539
|
+
if (this.isDragging || this.isResizing) {
|
|
3540
|
+
const touch = e.touches[0];
|
|
3541
|
+
if (this.isDragging) {
|
|
3542
|
+
this.drag(touch.clientX, touch.clientY);
|
|
3543
|
+
} else {
|
|
3544
|
+
this.resize(touch.clientX, touch.clientY);
|
|
3545
|
+
}
|
|
3546
|
+
e.preventDefault();
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
onMouseUp() {
|
|
3550
|
+
if (this.isDragging) {
|
|
3551
|
+
this.stopDragging();
|
|
3552
|
+
} else if (this.isResizing) {
|
|
3553
|
+
this.stopResizing();
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
onTouchEnd() {
|
|
3557
|
+
if (this.isDragging) {
|
|
3558
|
+
this.stopDragging();
|
|
3559
|
+
} else if (this.isResizing) {
|
|
3560
|
+
this.stopResizing();
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
onKeyDown(e) {
|
|
3564
|
+
if (e.key.toLowerCase() === this.options.keyboardDragKey.toLowerCase()) {
|
|
3565
|
+
e.preventDefault();
|
|
3566
|
+
this.toggleKeyboardDragMode();
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
if (e.key.toLowerCase() === this.options.keyboardResizeKey.toLowerCase()) {
|
|
3570
|
+
e.preventDefault();
|
|
3571
|
+
if (this.hasManagedResizeHandles()) {
|
|
3572
|
+
this.togglePointerResizeMode();
|
|
3573
|
+
} else {
|
|
3574
|
+
this.toggleKeyboardResizeMode();
|
|
3575
|
+
}
|
|
3576
|
+
return;
|
|
3577
|
+
}
|
|
3578
|
+
if (e.key === "Escape") {
|
|
3579
|
+
if (this.pointerResizeMode) {
|
|
3580
|
+
e.preventDefault();
|
|
3581
|
+
this.disablePointerResizeMode();
|
|
3582
|
+
return;
|
|
3583
|
+
}
|
|
3584
|
+
if (this.keyboardDragMode || this.keyboardResizeMode) {
|
|
3585
|
+
e.preventDefault();
|
|
3586
|
+
this.disableKeyboardDragMode();
|
|
3587
|
+
this.disableKeyboardResizeMode();
|
|
3588
|
+
return;
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3592
|
+
if (this.keyboardDragMode) {
|
|
3593
|
+
e.preventDefault();
|
|
3594
|
+
e.stopPropagation();
|
|
3595
|
+
this.keyboardDrag(e.key, e.shiftKey);
|
|
3596
|
+
} else if (this.keyboardResizeMode) {
|
|
3597
|
+
e.preventDefault();
|
|
3598
|
+
e.stopPropagation();
|
|
3599
|
+
this.keyboardResize(e.key, e.shiftKey);
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
if (e.key === "Home" && (this.keyboardDragMode || this.keyboardResizeMode)) {
|
|
3603
|
+
e.preventDefault();
|
|
3604
|
+
this.resetPosition();
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
startDragging(clientX, clientY) {
|
|
3608
|
+
const rect = this.element.getBoundingClientRect();
|
|
3609
|
+
const computedStyle = window.getComputedStyle(this.element);
|
|
3610
|
+
const needsConversion = computedStyle.right !== "auto" || computedStyle.bottom !== "auto" || computedStyle.transform !== "none";
|
|
3611
|
+
this.positionOffsetX = 0;
|
|
3612
|
+
this.positionOffsetY = 0;
|
|
3613
|
+
if (needsConversion) {
|
|
3614
|
+
let targetLeft, targetTop;
|
|
3615
|
+
if (computedStyle.position === "absolute") {
|
|
3616
|
+
const offsetParent = this.element.offsetParent || document.body;
|
|
3617
|
+
const parentRect = offsetParent.getBoundingClientRect();
|
|
3618
|
+
targetLeft = rect.left - parentRect.left;
|
|
3619
|
+
targetTop = rect.top - parentRect.top;
|
|
3620
|
+
this.positionOffsetX = parentRect.left;
|
|
3621
|
+
this.positionOffsetY = parentRect.top;
|
|
3622
|
+
} else if (computedStyle.position === "fixed") {
|
|
3623
|
+
const parsedLeft = parseFloat(computedStyle.left);
|
|
3624
|
+
const parsedTop = parseFloat(computedStyle.top);
|
|
3625
|
+
const hasLeft = Number.isFinite(parsedLeft);
|
|
3626
|
+
const hasTop = Number.isFinite(parsedTop);
|
|
3627
|
+
targetLeft = hasLeft ? parsedLeft : rect.left;
|
|
3628
|
+
targetTop = hasTop ? parsedTop : rect.top;
|
|
3629
|
+
this.positionOffsetX = rect.left - targetLeft;
|
|
3630
|
+
this.positionOffsetY = rect.top - targetTop;
|
|
3631
|
+
} else {
|
|
3632
|
+
targetLeft = rect.left;
|
|
3633
|
+
targetTop = rect.top;
|
|
3634
|
+
this.positionOffsetX = rect.left - targetLeft;
|
|
3635
|
+
this.positionOffsetY = rect.top - targetTop;
|
|
3636
|
+
}
|
|
3637
|
+
const currentCssText = this.element.style.cssText;
|
|
3638
|
+
let newCssText = currentCssText.split(";").filter((rule) => {
|
|
3639
|
+
const trimmed = rule.trim();
|
|
3640
|
+
return trimmed && !trimmed.startsWith("right:") && !trimmed.startsWith("bottom:") && !trimmed.startsWith("transform:") && !trimmed.startsWith("left:") && !trimmed.startsWith("top:") && !trimmed.startsWith("inset:");
|
|
3641
|
+
}).join("; ");
|
|
3642
|
+
if (newCssText) newCssText += "; ";
|
|
3643
|
+
newCssText += `left: ${targetLeft}px; top: ${targetTop}px; right: auto; bottom: auto; transform: none`;
|
|
3644
|
+
this.element.style.cssText = newCssText;
|
|
3645
|
+
}
|
|
3646
|
+
const finalRect = this.element.getBoundingClientRect();
|
|
3647
|
+
this.dragOffsetX = clientX - finalRect.left;
|
|
3648
|
+
this.dragOffsetY = clientY - finalRect.top;
|
|
3649
|
+
this.isDragging = true;
|
|
3650
|
+
this.element.classList.add(`${this.options.classPrefix}-dragging`);
|
|
3651
|
+
document.body.style.cursor = "grabbing";
|
|
3652
|
+
document.body.style.userSelect = "none";
|
|
3653
|
+
}
|
|
3654
|
+
drag(clientX, clientY) {
|
|
3655
|
+
if (!this.isDragging) return;
|
|
3656
|
+
let newX = clientX - this.dragOffsetX - this.positionOffsetX;
|
|
3657
|
+
let newY = clientY - this.dragOffsetY - this.positionOffsetY;
|
|
3658
|
+
if (this.options.constrainToViewport) {
|
|
3659
|
+
const rect = this.element.getBoundingClientRect();
|
|
3660
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
3661
|
+
const viewportHeight = document.documentElement.clientHeight;
|
|
3662
|
+
const minVisible = 100;
|
|
3663
|
+
const minX = -(rect.width - minVisible);
|
|
3664
|
+
const minY = -(rect.height - minVisible);
|
|
3665
|
+
const maxX = viewportWidth - minVisible;
|
|
3666
|
+
const maxY = viewportHeight - minVisible;
|
|
3667
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
3668
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
3669
|
+
}
|
|
3670
|
+
this.element.style.left = `${newX}px`;
|
|
3671
|
+
this.element.style.top = `${newY}px`;
|
|
3672
|
+
if (this.options.onDrag) {
|
|
3673
|
+
this.options.onDrag({ x: newX, y: newY });
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
stopDragging() {
|
|
3677
|
+
this.isDragging = false;
|
|
3678
|
+
this.element.classList.remove(`${this.options.classPrefix}-dragging`);
|
|
3679
|
+
document.body.style.cursor = "";
|
|
3680
|
+
document.body.style.userSelect = "";
|
|
3681
|
+
this.manuallyPositioned = true;
|
|
3682
|
+
if (this.options.onDragEnd) {
|
|
3683
|
+
this.options.onDragEnd();
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
startResizing(clientX, clientY) {
|
|
3687
|
+
this.isResizing = true;
|
|
3688
|
+
this.resizeStartX = clientX;
|
|
3689
|
+
this.resizeStartY = clientY;
|
|
3690
|
+
const rect = this.element.getBoundingClientRect();
|
|
3691
|
+
this.resizeStartWidth = rect.width;
|
|
3692
|
+
this.resizeStartHeight = rect.height;
|
|
3693
|
+
this.resizeStartLeft = rect.left;
|
|
3694
|
+
this.resizeStartTop = rect.top;
|
|
3695
|
+
this.element.classList.add(`${this.options.classPrefix}-resizing`);
|
|
3696
|
+
document.body.style.userSelect = "none";
|
|
3697
|
+
if (this.options.onResizeStart) {
|
|
3698
|
+
this.options.onResizeStart();
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
resize(clientX, clientY) {
|
|
3702
|
+
if (!this.isResizing) return;
|
|
3703
|
+
const deltaX = clientX - this.resizeStartX;
|
|
3704
|
+
const deltaY = clientY - this.resizeStartY;
|
|
3705
|
+
let newWidth = this.resizeStartWidth;
|
|
3706
|
+
let newHeight = this.resizeStartHeight;
|
|
3707
|
+
let newLeft = this.resizeStartLeft;
|
|
3708
|
+
let newTop = this.resizeStartTop;
|
|
3709
|
+
if (this.resizeDirection.includes("e")) {
|
|
3710
|
+
newWidth = Math.max(this.options.minWidth, this.resizeStartWidth + deltaX);
|
|
3711
|
+
}
|
|
3712
|
+
if (this.resizeDirection.includes("w")) {
|
|
3713
|
+
const proposedWidth = Math.max(this.options.minWidth, this.resizeStartWidth - deltaX);
|
|
3714
|
+
newLeft = this.resizeStartLeft + (this.resizeStartWidth - proposedWidth);
|
|
3715
|
+
newWidth = proposedWidth;
|
|
3716
|
+
}
|
|
3717
|
+
const maxWidthOption = typeof this.options.maxWidth === "function" ? this.options.maxWidth() : this.options.maxWidth;
|
|
3718
|
+
if (Number.isFinite(maxWidthOption)) {
|
|
3719
|
+
const clampedWidth = Math.min(newWidth, maxWidthOption);
|
|
3720
|
+
if (clampedWidth !== newWidth && this.resizeDirection.includes("w")) {
|
|
3721
|
+
newLeft += newWidth - clampedWidth;
|
|
3722
|
+
}
|
|
3723
|
+
newWidth = clampedWidth;
|
|
3724
|
+
}
|
|
3725
|
+
if (!this.options.maintainAspectRatio) {
|
|
3726
|
+
if (this.resizeDirection.includes("s")) {
|
|
3727
|
+
newHeight = Math.max(this.options.minHeight, this.resizeStartHeight + deltaY);
|
|
3728
|
+
}
|
|
3729
|
+
if (this.resizeDirection.includes("n")) {
|
|
3730
|
+
const proposedHeight = Math.max(this.options.minHeight, this.resizeStartHeight - deltaY);
|
|
3731
|
+
newTop = this.resizeStartTop + (this.resizeStartHeight - proposedHeight);
|
|
3732
|
+
newHeight = proposedHeight;
|
|
3733
|
+
}
|
|
3734
|
+
const maxHeightOption = typeof this.options.maxHeight === "function" ? this.options.maxHeight() : this.options.maxHeight;
|
|
3735
|
+
if (Number.isFinite(maxHeightOption)) {
|
|
3736
|
+
const clampedHeight = Math.min(newHeight, maxHeightOption);
|
|
3737
|
+
if (clampedHeight !== newHeight && this.resizeDirection.includes("n")) {
|
|
3738
|
+
newTop += newHeight - clampedHeight;
|
|
3739
|
+
}
|
|
3740
|
+
newHeight = clampedHeight;
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
this.element.style.width = `${newWidth}px`;
|
|
3744
|
+
if (!this.options.maintainAspectRatio) {
|
|
3745
|
+
this.element.style.height = `${newHeight}px`;
|
|
3746
|
+
} else {
|
|
3747
|
+
this.element.style.height = "auto";
|
|
3748
|
+
}
|
|
3749
|
+
if (this.resizeDirection.includes("w")) {
|
|
3750
|
+
this.element.style.left = `${newLeft}px`;
|
|
3751
|
+
}
|
|
3752
|
+
if (this.resizeDirection.includes("n") && !this.options.maintainAspectRatio) {
|
|
3753
|
+
this.element.style.top = `${newTop}px`;
|
|
3754
|
+
}
|
|
3755
|
+
if (this.options.onResize) {
|
|
3756
|
+
this.options.onResize({ width: newWidth, height: newHeight, left: newLeft, top: newTop });
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
stopResizing() {
|
|
3760
|
+
this.isResizing = false;
|
|
3761
|
+
this.resizeDirection = null;
|
|
3762
|
+
this.element.classList.remove(`${this.options.classPrefix}-resizing`);
|
|
3763
|
+
document.body.style.userSelect = "";
|
|
3764
|
+
this.manuallyPositioned = true;
|
|
3765
|
+
if (this.options.onResizeEnd) {
|
|
3766
|
+
this.options.onResizeEnd();
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3769
|
+
toggleKeyboardDragMode() {
|
|
3770
|
+
if (this.keyboardDragMode) {
|
|
3771
|
+
this.disableKeyboardDragMode();
|
|
3772
|
+
} else {
|
|
3773
|
+
this.enableKeyboardDragMode();
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
enableKeyboardDragMode() {
|
|
3777
|
+
this.keyboardDragMode = true;
|
|
3778
|
+
this.keyboardResizeMode = false;
|
|
3779
|
+
this.element.classList.add(`${this.options.classPrefix}-keyboard-drag`);
|
|
3780
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
|
|
3781
|
+
this.focusElement();
|
|
3782
|
+
}
|
|
3783
|
+
disableKeyboardDragMode() {
|
|
3784
|
+
this.keyboardDragMode = false;
|
|
3785
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
|
|
3786
|
+
}
|
|
3787
|
+
toggleKeyboardResizeMode() {
|
|
3788
|
+
if (this.keyboardResizeMode) {
|
|
3789
|
+
this.disableKeyboardResizeMode();
|
|
3790
|
+
} else {
|
|
3791
|
+
this.enableKeyboardResizeMode();
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
enableKeyboardResizeMode() {
|
|
3795
|
+
this.keyboardResizeMode = true;
|
|
3796
|
+
this.keyboardDragMode = false;
|
|
3797
|
+
this.element.classList.add(`${this.options.classPrefix}-keyboard-resize`);
|
|
3798
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
|
|
3799
|
+
this.focusElement();
|
|
3800
|
+
}
|
|
3801
|
+
disableKeyboardResizeMode() {
|
|
3802
|
+
this.keyboardResizeMode = false;
|
|
3803
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
|
|
3804
|
+
}
|
|
3805
|
+
enablePointerResizeMode({ focus = true } = {}) {
|
|
3806
|
+
if (!this.hasManagedResizeHandles()) {
|
|
3807
|
+
this.enableKeyboardResizeMode();
|
|
3808
|
+
return;
|
|
3809
|
+
}
|
|
3810
|
+
if (this.pointerResizeMode) {
|
|
3811
|
+
return;
|
|
3812
|
+
}
|
|
3813
|
+
this.pointerResizeMode = true;
|
|
3814
|
+
this.setManagedHandlesVisible(true);
|
|
3815
|
+
this.element.classList.add(`${this.options.classPrefix}-resizable`);
|
|
3816
|
+
this.enableKeyboardResizeMode();
|
|
3817
|
+
if (focus) {
|
|
3818
|
+
this.focusElement();
|
|
3819
|
+
}
|
|
3820
|
+
if (typeof this.options.onPointerResizeToggle === "function") {
|
|
3821
|
+
this.options.onPointerResizeToggle(true);
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
disablePointerResizeMode({ focus = false } = {}) {
|
|
3825
|
+
if (!this.pointerResizeMode) {
|
|
3826
|
+
return;
|
|
3827
|
+
}
|
|
3828
|
+
this.pointerResizeMode = false;
|
|
3829
|
+
this.setManagedHandlesVisible(false);
|
|
3830
|
+
this.element.classList.remove(`${this.options.classPrefix}-resizable`);
|
|
3831
|
+
this.disableKeyboardResizeMode();
|
|
3832
|
+
if (focus) {
|
|
3833
|
+
this.focusElement();
|
|
3834
|
+
}
|
|
3835
|
+
if (typeof this.options.onPointerResizeToggle === "function") {
|
|
3836
|
+
this.options.onPointerResizeToggle(false);
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
togglePointerResizeMode() {
|
|
3840
|
+
if (this.pointerResizeMode) {
|
|
3841
|
+
this.disablePointerResizeMode();
|
|
3842
|
+
} else {
|
|
3843
|
+
this.enablePointerResizeMode();
|
|
3844
|
+
}
|
|
3845
|
+
return this.pointerResizeMode;
|
|
3846
|
+
}
|
|
3847
|
+
focusElement() {
|
|
3848
|
+
if (typeof this.element.focus === "function") {
|
|
3849
|
+
try {
|
|
3850
|
+
this.element.focus({ preventScroll: true });
|
|
3851
|
+
} catch (e) {
|
|
3852
|
+
this.element.focus();
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
keyboardDrag(key, shiftKey) {
|
|
3857
|
+
const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
|
|
3858
|
+
let currentLeft = parseFloat(this.element.style.left) || 0;
|
|
3859
|
+
let currentTop = parseFloat(this.element.style.top) || 0;
|
|
3860
|
+
const computedStyle = window.getComputedStyle(this.element);
|
|
3861
|
+
if (computedStyle.transform !== "none") {
|
|
3862
|
+
const rect = this.element.getBoundingClientRect();
|
|
3863
|
+
currentLeft = rect.left;
|
|
3864
|
+
currentTop = rect.top;
|
|
3865
|
+
this.element.style.transform = "none";
|
|
3866
|
+
this.element.style.left = `${currentLeft}px`;
|
|
3867
|
+
this.element.style.top = `${currentTop}px`;
|
|
3868
|
+
}
|
|
3869
|
+
let newX = currentLeft;
|
|
3870
|
+
let newY = currentTop;
|
|
3871
|
+
switch (key) {
|
|
3872
|
+
case "ArrowLeft":
|
|
3873
|
+
newX -= step;
|
|
3874
|
+
break;
|
|
3875
|
+
case "ArrowRight":
|
|
3876
|
+
newX += step;
|
|
3877
|
+
break;
|
|
3878
|
+
case "ArrowUp":
|
|
3879
|
+
newY -= step;
|
|
3880
|
+
break;
|
|
3881
|
+
case "ArrowDown":
|
|
3882
|
+
newY += step;
|
|
3883
|
+
break;
|
|
3884
|
+
}
|
|
3885
|
+
this.element.style.left = `${newX}px`;
|
|
3886
|
+
this.element.style.top = `${newY}px`;
|
|
3887
|
+
if (this.options.onDrag) {
|
|
3888
|
+
this.options.onDrag({ x: newX, y: newY });
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
keyboardResize(key, shiftKey) {
|
|
3892
|
+
const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
|
|
3893
|
+
const rect = this.element.getBoundingClientRect();
|
|
3894
|
+
let width = rect.width;
|
|
3895
|
+
let height = rect.height;
|
|
3896
|
+
switch (key) {
|
|
3897
|
+
case "ArrowLeft":
|
|
3898
|
+
width -= step;
|
|
3899
|
+
break;
|
|
3900
|
+
case "ArrowRight":
|
|
3901
|
+
width += step;
|
|
3902
|
+
break;
|
|
3903
|
+
case "ArrowUp":
|
|
3904
|
+
if (this.options.maintainAspectRatio) {
|
|
3905
|
+
width += step;
|
|
3906
|
+
} else {
|
|
3907
|
+
height -= step;
|
|
3908
|
+
}
|
|
3909
|
+
break;
|
|
3910
|
+
case "ArrowDown":
|
|
3911
|
+
if (this.options.maintainAspectRatio) {
|
|
3912
|
+
width -= step;
|
|
3913
|
+
} else {
|
|
3914
|
+
height += step;
|
|
3915
|
+
}
|
|
3916
|
+
break;
|
|
3917
|
+
}
|
|
3918
|
+
width = Math.max(this.options.minWidth, width);
|
|
3919
|
+
height = Math.max(this.options.minHeight, height);
|
|
3920
|
+
this.element.style.width = `${width}px`;
|
|
3921
|
+
if (!this.options.maintainAspectRatio) {
|
|
3922
|
+
this.element.style.height = `${height}px`;
|
|
3923
|
+
} else {
|
|
3924
|
+
this.element.style.height = "auto";
|
|
3925
|
+
}
|
|
3926
|
+
if (this.options.onResize) {
|
|
3927
|
+
this.options.onResize({ width, height });
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
resetPosition() {
|
|
3931
|
+
this.element.style.left = "50%";
|
|
3932
|
+
this.element.style.top = "50%";
|
|
3933
|
+
this.element.style.transform = "translate(-50%, -50%)";
|
|
3934
|
+
this.element.style.right = "";
|
|
3935
|
+
this.element.style.bottom = "";
|
|
3936
|
+
this.manuallyPositioned = false;
|
|
3937
|
+
if (this.options.onDrag) {
|
|
3938
|
+
this.options.onDrag({ centered: true });
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3941
|
+
destroy() {
|
|
3942
|
+
const dragHandle = this.options.dragHandle || this.element;
|
|
3943
|
+
this.disablePointerResizeMode();
|
|
3944
|
+
dragHandle.removeEventListener("mousedown", this.handlers.mousedown);
|
|
3945
|
+
dragHandle.removeEventListener("touchstart", this.handlers.touchstart);
|
|
3946
|
+
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
3947
|
+
document.removeEventListener("mouseup", this.handlers.mouseup);
|
|
3948
|
+
document.removeEventListener("touchmove", this.handlers.touchmove);
|
|
3949
|
+
document.removeEventListener("touchend", this.handlers.touchend);
|
|
3950
|
+
this.element.removeEventListener("keydown", this.handlers.keydown);
|
|
3951
|
+
if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
|
|
3952
|
+
this.options.resizeHandles.forEach((handle) => {
|
|
3953
|
+
handle.removeEventListener("mousedown", this.handlers.resizeHandleMousedown);
|
|
3954
|
+
handle.removeEventListener("touchstart", this.handlers.resizeHandleMousedown);
|
|
3955
|
+
});
|
|
3956
|
+
}
|
|
3957
|
+
this.element.classList.remove(
|
|
3958
|
+
`${this.options.classPrefix}-dragging`,
|
|
3959
|
+
`${this.options.classPrefix}-resizing`,
|
|
3960
|
+
`${this.options.classPrefix}-keyboard-drag`,
|
|
3961
|
+
`${this.options.classPrefix}-keyboard-resize`
|
|
3962
|
+
);
|
|
3963
|
+
}
|
|
3964
|
+
};
|
|
3965
|
+
|
|
3316
3966
|
// src/controls/TranscriptManager.js
|
|
3317
3967
|
var TranscriptManager = class {
|
|
3318
3968
|
constructor(player) {
|
|
@@ -3323,25 +3973,26 @@ var VidPly = (() => {
|
|
|
3323
3973
|
this.currentActiveEntry = null;
|
|
3324
3974
|
this.isVisible = false;
|
|
3325
3975
|
this.storage = new StorageManager("vidply");
|
|
3326
|
-
this.
|
|
3327
|
-
this.dragOffsetX = 0;
|
|
3328
|
-
this.dragOffsetY = 0;
|
|
3329
|
-
this.isResizing = false;
|
|
3330
|
-
this.resizeDirection = null;
|
|
3331
|
-
this.resizeStartX = 0;
|
|
3332
|
-
this.resizeStartY = 0;
|
|
3333
|
-
this.resizeStartWidth = 0;
|
|
3334
|
-
this.resizeStartHeight = 0;
|
|
3335
|
-
this.resizeEnabled = false;
|
|
3976
|
+
this.draggableResizable = null;
|
|
3336
3977
|
this.settingsMenuVisible = false;
|
|
3337
3978
|
this.settingsMenu = null;
|
|
3338
3979
|
this.settingsButton = null;
|
|
3339
3980
|
this.settingsMenuJustOpened = false;
|
|
3340
|
-
this.
|
|
3981
|
+
this.resizeOptionButton = null;
|
|
3982
|
+
this.resizeOptionText = null;
|
|
3983
|
+
this.resizeModeIndicator = null;
|
|
3984
|
+
this.resizeModeIndicatorTimeout = null;
|
|
3985
|
+
this.transcriptResizeHandles = [];
|
|
3986
|
+
this.liveRegion = null;
|
|
3341
3987
|
this.styleDialog = null;
|
|
3342
3988
|
this.styleDialogVisible = false;
|
|
3343
3989
|
this.styleDialogJustOpened = false;
|
|
3990
|
+
this.languageSelector = null;
|
|
3991
|
+
this.currentTranscriptLanguage = null;
|
|
3992
|
+
this.availableTranscriptLanguages = [];
|
|
3993
|
+
this.languageSelectorHandler = null;
|
|
3344
3994
|
const savedPreferences = this.storage.getTranscriptPreferences();
|
|
3995
|
+
this.autoscrollEnabled = (savedPreferences == null ? void 0 : savedPreferences.autoscroll) !== void 0 ? savedPreferences.autoscroll : true;
|
|
3345
3996
|
this.transcriptStyle = {
|
|
3346
3997
|
fontSize: (savedPreferences == null ? void 0 : savedPreferences.fontSize) || this.player.options.transcriptFontSize || "100%",
|
|
3347
3998
|
fontFamily: (savedPreferences == null ? void 0 : savedPreferences.fontFamily) || this.player.options.transcriptFontFamily || "sans-serif",
|
|
@@ -3352,25 +4003,22 @@ var VidPly = (() => {
|
|
|
3352
4003
|
this.handlers = {
|
|
3353
4004
|
timeupdate: () => this.updateActiveEntry(),
|
|
3354
4005
|
resize: null,
|
|
3355
|
-
mousemove: null,
|
|
3356
|
-
mouseup: null,
|
|
3357
|
-
touchmove: null,
|
|
3358
|
-
touchend: null,
|
|
3359
|
-
mousedown: null,
|
|
3360
|
-
touchstart: null,
|
|
3361
|
-
keydown: null,
|
|
3362
4006
|
settingsClick: null,
|
|
3363
4007
|
settingsKeydown: null,
|
|
3364
4008
|
documentClick: null,
|
|
3365
4009
|
styleDialogKeydown: null
|
|
3366
4010
|
};
|
|
4011
|
+
this.timeouts = /* @__PURE__ */ new Set();
|
|
3367
4012
|
this.init();
|
|
3368
4013
|
}
|
|
3369
4014
|
init() {
|
|
4015
|
+
this.setupMetadataHandlingOnLoad();
|
|
3370
4016
|
this.player.on("timeupdate", this.handlers.timeupdate);
|
|
3371
4017
|
this.player.on("fullscreenchange", () => {
|
|
3372
4018
|
if (this.isVisible) {
|
|
3373
|
-
|
|
4019
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4020
|
+
this.setManagedTimeout(() => this.positionTranscript(), 100);
|
|
4021
|
+
}
|
|
3374
4022
|
}
|
|
3375
4023
|
});
|
|
3376
4024
|
}
|
|
@@ -3391,9 +4039,12 @@ var VidPly = (() => {
|
|
|
3391
4039
|
if (this.transcriptWindow) {
|
|
3392
4040
|
this.transcriptWindow.style.display = "flex";
|
|
3393
4041
|
this.isVisible = true;
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
4042
|
+
if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
|
|
4043
|
+
this.player.controlBar.updateTranscriptButton();
|
|
4044
|
+
}
|
|
4045
|
+
this.setManagedTimeout(() => {
|
|
4046
|
+
if (this.transcriptHeader) {
|
|
4047
|
+
this.transcriptHeader.focus();
|
|
3397
4048
|
}
|
|
3398
4049
|
}, 150);
|
|
3399
4050
|
return;
|
|
@@ -3402,10 +4053,12 @@ var VidPly = (() => {
|
|
|
3402
4053
|
this.loadTranscriptData();
|
|
3403
4054
|
if (this.transcriptWindow) {
|
|
3404
4055
|
this.transcriptWindow.style.display = "flex";
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
4056
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4057
|
+
this.setManagedTimeout(() => this.positionTranscript(), 0);
|
|
4058
|
+
}
|
|
4059
|
+
this.setManagedTimeout(() => {
|
|
4060
|
+
if (this.transcriptHeader) {
|
|
4061
|
+
this.transcriptHeader.focus();
|
|
3409
4062
|
}
|
|
3410
4063
|
}, 150);
|
|
3411
4064
|
}
|
|
@@ -3414,11 +4067,27 @@ var VidPly = (() => {
|
|
|
3414
4067
|
/**
|
|
3415
4068
|
* Hide transcript window
|
|
3416
4069
|
*/
|
|
3417
|
-
hideTranscript() {
|
|
4070
|
+
hideTranscript({ focusButton = false } = {}) {
|
|
4071
|
+
var _a, _b;
|
|
3418
4072
|
if (this.transcriptWindow) {
|
|
3419
4073
|
this.transcriptWindow.style.display = "none";
|
|
3420
4074
|
this.isVisible = false;
|
|
3421
4075
|
}
|
|
4076
|
+
if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
|
|
4077
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
4078
|
+
this.updateResizeOptionState();
|
|
4079
|
+
}
|
|
4080
|
+
this.hideResizeModeIndicator();
|
|
4081
|
+
this.announceLive("");
|
|
4082
|
+
if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
|
|
4083
|
+
this.player.controlBar.updateTranscriptButton();
|
|
4084
|
+
}
|
|
4085
|
+
if (focusButton) {
|
|
4086
|
+
const transcriptButton = (_b = (_a = this.player.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.transcript;
|
|
4087
|
+
if (transcriptButton && typeof transcriptButton.focus === "function") {
|
|
4088
|
+
transcriptButton.focus();
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
3422
4091
|
}
|
|
3423
4092
|
/**
|
|
3424
4093
|
* Create the transcript window UI
|
|
@@ -3435,7 +4104,6 @@ var VidPly = (() => {
|
|
|
3435
4104
|
this.transcriptHeader = DOMUtils.createElement("div", {
|
|
3436
4105
|
className: `${this.player.options.classPrefix}-transcript-header`,
|
|
3437
4106
|
attributes: {
|
|
3438
|
-
"aria-label": "Drag to reposition transcript. Use arrow keys to move, Home to reset position, Escape to close.",
|
|
3439
4107
|
"tabindex": "0"
|
|
3440
4108
|
}
|
|
3441
4109
|
});
|
|
@@ -3446,7 +4114,7 @@ var VidPly = (() => {
|
|
|
3446
4114
|
className: `${this.player.options.classPrefix}-transcript-settings`,
|
|
3447
4115
|
attributes: {
|
|
3448
4116
|
"type": "button",
|
|
3449
|
-
"aria-label": i18n.t("transcript.
|
|
4117
|
+
"aria-label": i18n.t("transcript.settingsMenu"),
|
|
3450
4118
|
"aria-expanded": "false"
|
|
3451
4119
|
}
|
|
3452
4120
|
});
|
|
@@ -3478,10 +4146,43 @@ var VidPly = (() => {
|
|
|
3478
4146
|
};
|
|
3479
4147
|
this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
|
|
3480
4148
|
const title = DOMUtils.createElement("h3", {
|
|
3481
|
-
textContent: i18n.t("transcript.title")
|
|
4149
|
+
textContent: `${i18n.t("transcript.title")}. ${i18n.t("transcript.dragResizePrompt")}`
|
|
4150
|
+
});
|
|
4151
|
+
const autoscrollLabel = DOMUtils.createElement("label", {
|
|
4152
|
+
className: `${this.player.options.classPrefix}-transcript-autoscroll-label`,
|
|
4153
|
+
attributes: {
|
|
4154
|
+
"title": i18n.t("transcript.autoscroll")
|
|
4155
|
+
}
|
|
3482
4156
|
});
|
|
4157
|
+
this.autoscrollCheckbox = DOMUtils.createElement("input", {
|
|
4158
|
+
attributes: {
|
|
4159
|
+
"type": "checkbox",
|
|
4160
|
+
"checked": this.autoscrollEnabled,
|
|
4161
|
+
"aria-label": i18n.t("transcript.autoscroll")
|
|
4162
|
+
}
|
|
4163
|
+
});
|
|
4164
|
+
const autoscrollText = DOMUtils.createElement("span", {
|
|
4165
|
+
textContent: i18n.t("transcript.autoscroll"),
|
|
4166
|
+
className: `${this.player.options.classPrefix}-transcript-autoscroll-text`
|
|
4167
|
+
});
|
|
4168
|
+
autoscrollLabel.appendChild(this.autoscrollCheckbox);
|
|
4169
|
+
autoscrollLabel.appendChild(autoscrollText);
|
|
4170
|
+
this.autoscrollCheckbox.addEventListener("change", (e) => {
|
|
4171
|
+
this.autoscrollEnabled = e.target.checked;
|
|
4172
|
+
this.saveAutoscrollPreference();
|
|
4173
|
+
});
|
|
4174
|
+
this.transcriptHeader.appendChild(title);
|
|
3483
4175
|
this.headerLeft.appendChild(this.settingsButton);
|
|
3484
|
-
this.headerLeft.appendChild(
|
|
4176
|
+
this.headerLeft.appendChild(autoscrollLabel);
|
|
4177
|
+
this.languageSelector = DOMUtils.createElement("select", {
|
|
4178
|
+
className: `${this.player.options.classPrefix}-transcript-language-select`,
|
|
4179
|
+
attributes: {
|
|
4180
|
+
"aria-label": i18n.t("settings.language") || "Language",
|
|
4181
|
+
"style": "display: none;"
|
|
4182
|
+
// Hidden until we detect multiple languages
|
|
4183
|
+
}
|
|
4184
|
+
});
|
|
4185
|
+
this.headerLeft.appendChild(this.languageSelector);
|
|
3485
4186
|
const closeButton = DOMUtils.createElement("button", {
|
|
3486
4187
|
className: `${this.player.options.classPrefix}-transcript-close`,
|
|
3487
4188
|
attributes: {
|
|
@@ -3490,7 +4191,7 @@ var VidPly = (() => {
|
|
|
3490
4191
|
}
|
|
3491
4192
|
});
|
|
3492
4193
|
closeButton.appendChild(createIconElement("close"));
|
|
3493
|
-
closeButton.addEventListener("click", () => this.hideTranscript());
|
|
4194
|
+
closeButton.addEventListener("click", () => this.hideTranscript({ focusButton: true }));
|
|
3494
4195
|
this.transcriptHeader.appendChild(this.headerLeft);
|
|
3495
4196
|
this.transcriptHeader.appendChild(closeButton);
|
|
3496
4197
|
this.transcriptContent = DOMUtils.createElement("div", {
|
|
@@ -3498,9 +4199,20 @@ var VidPly = (() => {
|
|
|
3498
4199
|
});
|
|
3499
4200
|
this.transcriptWindow.appendChild(this.transcriptHeader);
|
|
3500
4201
|
this.transcriptWindow.appendChild(this.transcriptContent);
|
|
4202
|
+
this.createResizeHandles();
|
|
4203
|
+
this.liveRegion = DOMUtils.createElement("div", {
|
|
4204
|
+
className: "vidply-sr-only",
|
|
4205
|
+
attributes: {
|
|
4206
|
+
"aria-live": "polite",
|
|
4207
|
+
"aria-atomic": "true"
|
|
4208
|
+
}
|
|
4209
|
+
});
|
|
4210
|
+
this.transcriptWindow.appendChild(this.liveRegion);
|
|
3501
4211
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3502
|
-
this.positionTranscript();
|
|
3503
4212
|
this.setupDragAndDrop();
|
|
4213
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4214
|
+
this.positionTranscript();
|
|
4215
|
+
}
|
|
3504
4216
|
this.handlers.documentClick = (e) => {
|
|
3505
4217
|
if (this.settingsMenuJustOpened) {
|
|
3506
4218
|
return;
|
|
@@ -3524,16 +4236,42 @@ var VidPly = (() => {
|
|
|
3524
4236
|
this.documentClickHandlerAdded = false;
|
|
3525
4237
|
let resizeTimeout;
|
|
3526
4238
|
this.handlers.resize = () => {
|
|
3527
|
-
|
|
3528
|
-
|
|
4239
|
+
if (resizeTimeout) {
|
|
4240
|
+
this.clearManagedTimeout(resizeTimeout);
|
|
4241
|
+
}
|
|
4242
|
+
resizeTimeout = this.setManagedTimeout(() => {
|
|
4243
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4244
|
+
this.positionTranscript();
|
|
4245
|
+
}
|
|
4246
|
+
}, 100);
|
|
3529
4247
|
};
|
|
3530
4248
|
window.addEventListener("resize", this.handlers.resize);
|
|
3531
4249
|
}
|
|
4250
|
+
createResizeHandles() {
|
|
4251
|
+
if (!this.transcriptWindow) return;
|
|
4252
|
+
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4253
|
+
this.transcriptResizeHandles = directions.map((direction) => {
|
|
4254
|
+
const handle = DOMUtils.createElement("div", {
|
|
4255
|
+
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4256
|
+
attributes: {
|
|
4257
|
+
"data-direction": direction,
|
|
4258
|
+
"data-vidply-managed-resize": "true",
|
|
4259
|
+
"aria-hidden": "true"
|
|
4260
|
+
}
|
|
4261
|
+
});
|
|
4262
|
+
handle.style.display = "none";
|
|
4263
|
+
this.transcriptWindow.appendChild(handle);
|
|
4264
|
+
return handle;
|
|
4265
|
+
});
|
|
4266
|
+
}
|
|
3532
4267
|
/**
|
|
3533
4268
|
* Position transcript window next to video
|
|
3534
4269
|
*/
|
|
3535
4270
|
positionTranscript() {
|
|
3536
4271
|
if (!this.transcriptWindow || !this.player.videoWrapper || !this.isVisible) return;
|
|
4272
|
+
if (this.draggableResizable && this.draggableResizable.manuallyPositioned) {
|
|
4273
|
+
return;
|
|
4274
|
+
}
|
|
3537
4275
|
const isMobile = window.innerWidth < 640;
|
|
3538
4276
|
const videoRect = this.player.videoWrapper.getBoundingClientRect();
|
|
3539
4277
|
const isFullscreen = this.player.state.fullscreen;
|
|
@@ -3566,8 +4304,12 @@ var VidPly = (() => {
|
|
|
3566
4304
|
this.transcriptWindow.style.top = "auto";
|
|
3567
4305
|
this.transcriptWindow.style.maxHeight = "calc(100vh - 180px)";
|
|
3568
4306
|
this.transcriptWindow.style.height = "auto";
|
|
3569
|
-
|
|
3570
|
-
|
|
4307
|
+
const fullscreenMinWidth = 260;
|
|
4308
|
+
const fullscreenAvailable = Math.max(fullscreenMinWidth, window.innerWidth - 40);
|
|
4309
|
+
const fullscreenDesired = parseFloat(this.transcriptWindow.style.width) || 400;
|
|
4310
|
+
const fullscreenWidth = Math.max(fullscreenMinWidth, Math.min(fullscreenDesired, fullscreenAvailable));
|
|
4311
|
+
this.transcriptWindow.style.width = `${fullscreenWidth}px`;
|
|
4312
|
+
this.transcriptWindow.style.maxWidth = "none";
|
|
3571
4313
|
this.transcriptWindow.style.borderRadius = "8px";
|
|
3572
4314
|
this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
|
|
3573
4315
|
this.transcriptWindow.style.borderTop = "";
|
|
@@ -3575,15 +4317,30 @@ var VidPly = (() => {
|
|
|
3575
4317
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3576
4318
|
}
|
|
3577
4319
|
} else {
|
|
4320
|
+
const transcriptWidth = parseFloat(this.transcriptWindow.style.width) || 400;
|
|
4321
|
+
const padding = 20;
|
|
4322
|
+
const minWidth = 260;
|
|
4323
|
+
const containerRect = this.player.container.getBoundingClientRect();
|
|
4324
|
+
const ensureContainerPositioned = () => {
|
|
4325
|
+
const computed = window.getComputedStyle(this.player.container);
|
|
4326
|
+
if (computed.position === "static") {
|
|
4327
|
+
this.player.container.style.position = "relative";
|
|
4328
|
+
}
|
|
4329
|
+
};
|
|
4330
|
+
ensureContainerPositioned();
|
|
4331
|
+
const left = videoRect.right - containerRect.left + padding;
|
|
4332
|
+
const availableWidth = window.innerWidth - videoRect.right - padding;
|
|
4333
|
+
const appliedWidth = Math.max(minWidth, Math.min(transcriptWidth, availableWidth));
|
|
4334
|
+
const appliedHeight = videoRect.height;
|
|
3578
4335
|
this.transcriptWindow.style.position = "absolute";
|
|
3579
|
-
this.transcriptWindow.style.left = `${
|
|
4336
|
+
this.transcriptWindow.style.left = `${left}px`;
|
|
3580
4337
|
this.transcriptWindow.style.right = "auto";
|
|
3581
4338
|
this.transcriptWindow.style.bottom = "auto";
|
|
3582
4339
|
this.transcriptWindow.style.top = "0";
|
|
3583
|
-
this.transcriptWindow.style.height = `${
|
|
4340
|
+
this.transcriptWindow.style.height = `${appliedHeight}px`;
|
|
3584
4341
|
this.transcriptWindow.style.maxHeight = "none";
|
|
3585
|
-
this.transcriptWindow.style.width =
|
|
3586
|
-
this.transcriptWindow.style.maxWidth = "
|
|
4342
|
+
this.transcriptWindow.style.width = `${appliedWidth}px`;
|
|
4343
|
+
this.transcriptWindow.style.maxWidth = "none";
|
|
3587
4344
|
this.transcriptWindow.style.borderRadius = "8px";
|
|
3588
4345
|
this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
|
|
3589
4346
|
this.transcriptWindow.style.borderTop = "";
|
|
@@ -3595,17 +4352,94 @@ var VidPly = (() => {
|
|
|
3595
4352
|
}
|
|
3596
4353
|
}
|
|
3597
4354
|
}
|
|
4355
|
+
/**
|
|
4356
|
+
* Get available transcript languages from tracks
|
|
4357
|
+
*/
|
|
4358
|
+
getAvailableTranscriptLanguages() {
|
|
4359
|
+
const textTracks = this.player.textTracks;
|
|
4360
|
+
const languages = /* @__PURE__ */ new Map();
|
|
4361
|
+
textTracks.forEach((track) => {
|
|
4362
|
+
if ((track.kind === "captions" || track.kind === "subtitles") && track.language) {
|
|
4363
|
+
if (!languages.has(track.language)) {
|
|
4364
|
+
languages.set(track.language, {
|
|
4365
|
+
language: track.language,
|
|
4366
|
+
label: track.label || track.language,
|
|
4367
|
+
track
|
|
4368
|
+
});
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
});
|
|
4372
|
+
return Array.from(languages.values());
|
|
4373
|
+
}
|
|
4374
|
+
/**
|
|
4375
|
+
* Update language selector dropdown
|
|
4376
|
+
*/
|
|
4377
|
+
updateLanguageSelector() {
|
|
4378
|
+
if (!this.languageSelector) return;
|
|
4379
|
+
this.availableTranscriptLanguages = this.getAvailableTranscriptLanguages();
|
|
4380
|
+
this.languageSelector.innerHTML = "";
|
|
4381
|
+
if (this.availableTranscriptLanguages.length < 2) {
|
|
4382
|
+
this.languageSelector.style.display = "none";
|
|
4383
|
+
return;
|
|
4384
|
+
}
|
|
4385
|
+
this.languageSelector.style.display = "block";
|
|
4386
|
+
this.availableTranscriptLanguages.forEach((langInfo, index) => {
|
|
4387
|
+
const option = DOMUtils.createElement("option", {
|
|
4388
|
+
textContent: langInfo.label,
|
|
4389
|
+
attributes: {
|
|
4390
|
+
"value": langInfo.language
|
|
4391
|
+
}
|
|
4392
|
+
});
|
|
4393
|
+
this.languageSelector.appendChild(option);
|
|
4394
|
+
});
|
|
4395
|
+
if (this.currentTranscriptLanguage) {
|
|
4396
|
+
this.languageSelector.value = this.currentTranscriptLanguage;
|
|
4397
|
+
} else if (this.availableTranscriptLanguages.length > 0) {
|
|
4398
|
+
const activeTrack = this.player.textTracks.find(
|
|
4399
|
+
(track) => (track.kind === "captions" || track.kind === "subtitles") && track.mode === "showing"
|
|
4400
|
+
);
|
|
4401
|
+
this.currentTranscriptLanguage = activeTrack ? activeTrack.language : this.availableTranscriptLanguages[0].language;
|
|
4402
|
+
this.languageSelector.value = this.currentTranscriptLanguage;
|
|
4403
|
+
}
|
|
4404
|
+
if (this.languageSelectorHandler) {
|
|
4405
|
+
this.languageSelector.removeEventListener("change", this.languageSelectorHandler);
|
|
4406
|
+
}
|
|
4407
|
+
this.languageSelectorHandler = (e) => {
|
|
4408
|
+
this.currentTranscriptLanguage = e.target.value;
|
|
4409
|
+
this.loadTranscriptData();
|
|
4410
|
+
};
|
|
4411
|
+
this.languageSelector.addEventListener("change", this.languageSelectorHandler);
|
|
4412
|
+
}
|
|
3598
4413
|
/**
|
|
3599
4414
|
* Load transcript data from caption/subtitle tracks
|
|
3600
4415
|
*/
|
|
3601
4416
|
loadTranscriptData() {
|
|
3602
4417
|
this.transcriptEntries = [];
|
|
3603
4418
|
this.transcriptContent.innerHTML = "";
|
|
3604
|
-
const textTracks =
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
4419
|
+
const textTracks = this.player.textTracks;
|
|
4420
|
+
let captionTrack = null;
|
|
4421
|
+
if (this.currentTranscriptLanguage) {
|
|
4422
|
+
captionTrack = textTracks.find(
|
|
4423
|
+
(track) => (track.kind === "captions" || track.kind === "subtitles") && track.language === this.currentTranscriptLanguage
|
|
4424
|
+
);
|
|
4425
|
+
}
|
|
4426
|
+
if (!captionTrack) {
|
|
4427
|
+
captionTrack = textTracks.find(
|
|
4428
|
+
(track) => track.kind === "captions" || track.kind === "subtitles"
|
|
4429
|
+
);
|
|
4430
|
+
if (captionTrack) {
|
|
4431
|
+
this.currentTranscriptLanguage = captionTrack.language;
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
let descriptionTrack = null;
|
|
4435
|
+
if (this.currentTranscriptLanguage) {
|
|
4436
|
+
descriptionTrack = textTracks.find(
|
|
4437
|
+
(track) => track.kind === "descriptions" && track.language === this.currentTranscriptLanguage
|
|
4438
|
+
);
|
|
4439
|
+
}
|
|
4440
|
+
if (!descriptionTrack) {
|
|
4441
|
+
descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
4442
|
+
}
|
|
3609
4443
|
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3610
4444
|
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3611
4445
|
this.showNoTranscriptMessage();
|
|
@@ -3634,7 +4468,7 @@ var VidPly = (() => {
|
|
|
3634
4468
|
tracksToLoad.forEach((track) => {
|
|
3635
4469
|
track.addEventListener("load", onLoad, { once: true });
|
|
3636
4470
|
});
|
|
3637
|
-
|
|
4471
|
+
this.setManagedTimeout(() => {
|
|
3638
4472
|
this.loadTranscriptData();
|
|
3639
4473
|
}, 500);
|
|
3640
4474
|
return;
|
|
@@ -3667,24 +4501,61 @@ var VidPly = (() => {
|
|
|
3667
4501
|
this.transcriptContent.appendChild(entry);
|
|
3668
4502
|
});
|
|
3669
4503
|
this.applyTranscriptStyles();
|
|
4504
|
+
this.updateLanguageSelector();
|
|
4505
|
+
}
|
|
4506
|
+
/**
|
|
4507
|
+
* Setup metadata handling on player load
|
|
4508
|
+
* This runs independently of transcript loading
|
|
4509
|
+
*/
|
|
4510
|
+
setupMetadataHandlingOnLoad() {
|
|
4511
|
+
const setupMetadata = () => {
|
|
4512
|
+
const textTracks = this.player.textTracks;
|
|
4513
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
4514
|
+
if (metadataTrack) {
|
|
4515
|
+
if (metadataTrack.mode === "disabled") {
|
|
4516
|
+
metadataTrack.mode = "hidden";
|
|
4517
|
+
}
|
|
4518
|
+
if (this.metadataCueChangeHandler) {
|
|
4519
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
4520
|
+
}
|
|
4521
|
+
this.metadataCueChangeHandler = () => {
|
|
4522
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
4523
|
+
if (activeCues.length > 0) {
|
|
4524
|
+
if (this.player.options.debug) {
|
|
4525
|
+
console.log("[VidPly Metadata] Active cues:", activeCues.map((c) => ({
|
|
4526
|
+
start: c.startTime,
|
|
4527
|
+
end: c.endTime,
|
|
4528
|
+
text: c.text
|
|
4529
|
+
})));
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
activeCues.forEach((cue) => {
|
|
4533
|
+
this.handleMetadataCue(cue);
|
|
4534
|
+
});
|
|
4535
|
+
};
|
|
4536
|
+
metadataTrack.addEventListener("cuechange", this.metadataCueChangeHandler);
|
|
4537
|
+
if (this.player.options.debug) {
|
|
4538
|
+
const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;
|
|
4539
|
+
console.log("[VidPly Metadata] Track enabled,", cueCount, "cues available");
|
|
4540
|
+
}
|
|
4541
|
+
} else if (this.player.options.debug) {
|
|
4542
|
+
console.warn("[VidPly Metadata] No metadata track found");
|
|
4543
|
+
}
|
|
4544
|
+
};
|
|
4545
|
+
setupMetadata();
|
|
4546
|
+
this.player.on("loadedmetadata", setupMetadata);
|
|
3670
4547
|
}
|
|
3671
4548
|
/**
|
|
3672
4549
|
* Setup metadata handling
|
|
3673
4550
|
* Metadata cues are not displayed but can be used programmatically
|
|
4551
|
+
* This is called when transcript data is loaded (for storing cues)
|
|
3674
4552
|
*/
|
|
3675
4553
|
setupMetadataHandling() {
|
|
3676
4554
|
if (!this.metadataCues || this.metadataCues.length === 0) {
|
|
3677
4555
|
return;
|
|
3678
4556
|
}
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
if (metadataTrack) {
|
|
3682
|
-
metadataTrack.addEventListener("cuechange", () => {
|
|
3683
|
-
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3684
|
-
activeCues.forEach((cue) => {
|
|
3685
|
-
this.handleMetadataCue(cue);
|
|
3686
|
-
});
|
|
3687
|
-
});
|
|
4557
|
+
if (this.player.options.debug) {
|
|
4558
|
+
console.log("[VidPly Metadata]", this.metadataCues.length, "cues stored from transcript load");
|
|
3688
4559
|
}
|
|
3689
4560
|
}
|
|
3690
4561
|
/**
|
|
@@ -3693,6 +4564,12 @@ var VidPly = (() => {
|
|
|
3693
4564
|
*/
|
|
3694
4565
|
handleMetadataCue(cue) {
|
|
3695
4566
|
const text = cue.text.trim();
|
|
4567
|
+
if (this.player.options.debug) {
|
|
4568
|
+
console.log("[VidPly Metadata] Processing cue:", {
|
|
4569
|
+
time: cue.startTime,
|
|
4570
|
+
text
|
|
4571
|
+
});
|
|
4572
|
+
}
|
|
3696
4573
|
this.player.emit("metadata", {
|
|
3697
4574
|
time: cue.startTime,
|
|
3698
4575
|
endTime: cue.endTime,
|
|
@@ -3700,18 +4577,40 @@ var VidPly = (() => {
|
|
|
3700
4577
|
cue
|
|
3701
4578
|
});
|
|
3702
4579
|
if (text.includes("PAUSE")) {
|
|
4580
|
+
if (!this.player.state.paused) {
|
|
4581
|
+
if (this.player.options.debug) {
|
|
4582
|
+
console.log("[VidPly Metadata] Pausing video at", cue.startTime);
|
|
4583
|
+
}
|
|
4584
|
+
this.player.pause();
|
|
4585
|
+
}
|
|
3703
4586
|
this.player.emit("metadata:pause", { time: cue.startTime, text });
|
|
3704
4587
|
}
|
|
3705
4588
|
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
3706
4589
|
if (focusMatch) {
|
|
4590
|
+
const targetSelector = focusMatch[1];
|
|
4591
|
+
const targetElement = document.querySelector(targetSelector);
|
|
4592
|
+
if (targetElement) {
|
|
4593
|
+
if (this.player.options.debug) {
|
|
4594
|
+
console.log("[VidPly Metadata] Focusing element:", targetSelector);
|
|
4595
|
+
}
|
|
4596
|
+
this.setManagedTimeout(() => {
|
|
4597
|
+
targetElement.focus();
|
|
4598
|
+
}, 10);
|
|
4599
|
+
} else if (this.player.options.debug) {
|
|
4600
|
+
console.warn("[VidPly Metadata] Element not found:", targetSelector);
|
|
4601
|
+
}
|
|
3707
4602
|
this.player.emit("metadata:focus", {
|
|
3708
4603
|
time: cue.startTime,
|
|
3709
|
-
target:
|
|
4604
|
+
target: targetSelector,
|
|
4605
|
+
element: targetElement,
|
|
3710
4606
|
text
|
|
3711
4607
|
});
|
|
3712
4608
|
}
|
|
3713
4609
|
const hashtags = text.match(/#[\w-]+/g);
|
|
3714
4610
|
if (hashtags) {
|
|
4611
|
+
if (this.player.options.debug) {
|
|
4612
|
+
console.log("[VidPly Metadata] Hashtags found:", hashtags);
|
|
4613
|
+
}
|
|
3715
4614
|
this.player.emit("metadata:hashtags", {
|
|
3716
4615
|
time: cue.startTime,
|
|
3717
4616
|
hashtags,
|
|
@@ -3805,7 +4704,7 @@ var VidPly = (() => {
|
|
|
3805
4704
|
* Scroll transcript window to show active entry
|
|
3806
4705
|
*/
|
|
3807
4706
|
scrollToEntry(entryElement) {
|
|
3808
|
-
if (!this.transcriptContent) return;
|
|
4707
|
+
if (!this.transcriptContent || !this.autoscrollEnabled) return;
|
|
3809
4708
|
const contentRect = this.transcriptContent.getBoundingClientRect();
|
|
3810
4709
|
const entryRect = entryElement.getBoundingClientRect();
|
|
3811
4710
|
if (entryRect.top < contentRect.top || entryRect.bottom > contentRect.bottom) {
|
|
@@ -3816,256 +4715,121 @@ var VidPly = (() => {
|
|
|
3816
4715
|
});
|
|
3817
4716
|
}
|
|
3818
4717
|
}
|
|
4718
|
+
/**
|
|
4719
|
+
* Save autoscroll preference to localStorage
|
|
4720
|
+
*/
|
|
4721
|
+
saveAutoscrollPreference() {
|
|
4722
|
+
const savedPreferences = this.storage.getTranscriptPreferences() || {};
|
|
4723
|
+
savedPreferences.autoscroll = this.autoscrollEnabled;
|
|
4724
|
+
this.storage.saveTranscriptPreferences(savedPreferences);
|
|
4725
|
+
}
|
|
3819
4726
|
/**
|
|
3820
4727
|
* Setup drag and drop functionality
|
|
3821
4728
|
*/
|
|
3822
4729
|
setupDragAndDrop() {
|
|
3823
4730
|
if (!this.transcriptHeader || !this.transcriptWindow) return;
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
}
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
}
|
|
3857
|
-
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3858
|
-
return;
|
|
3859
|
-
}
|
|
3860
|
-
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3861
|
-
return;
|
|
3862
|
-
}
|
|
3863
|
-
const isMobile = window.innerWidth < 640;
|
|
3864
|
-
const isFullscreen = this.player.state.fullscreen;
|
|
3865
|
-
const touch = e.touches[0];
|
|
3866
|
-
if (isMobile && !isFullscreen) {
|
|
3867
|
-
return;
|
|
3868
|
-
} else {
|
|
3869
|
-
this.startDragging(touch.clientX, touch.clientY);
|
|
3870
|
-
}
|
|
3871
|
-
};
|
|
3872
|
-
this.handlers.touchmove = (e) => {
|
|
3873
|
-
const isMobile = window.innerWidth < 640;
|
|
3874
|
-
const isFullscreen = this.player.state.fullscreen;
|
|
3875
|
-
if (isMobile && !isFullscreen) {
|
|
3876
|
-
return;
|
|
3877
|
-
} else if (this.isDragging) {
|
|
3878
|
-
const touch = e.touches[0];
|
|
3879
|
-
this.drag(touch.clientX, touch.clientY);
|
|
3880
|
-
e.preventDefault();
|
|
3881
|
-
}
|
|
3882
|
-
};
|
|
3883
|
-
this.handlers.touchend = () => {
|
|
3884
|
-
if (this.isDragging) {
|
|
3885
|
-
this.stopDragging();
|
|
3886
|
-
}
|
|
3887
|
-
};
|
|
3888
|
-
this.handlers.keydown = (e) => {
|
|
3889
|
-
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3890
|
-
if (!this.keyboardDragMode) {
|
|
3891
|
-
return;
|
|
4731
|
+
const isMobile = window.innerWidth < 640;
|
|
4732
|
+
const isFullscreen = this.player.state.fullscreen;
|
|
4733
|
+
if (isMobile && !isFullscreen) {
|
|
4734
|
+
return;
|
|
4735
|
+
}
|
|
4736
|
+
this.draggableResizable = new DraggableResizable(this.transcriptWindow, {
|
|
4737
|
+
dragHandle: this.transcriptHeader,
|
|
4738
|
+
resizeHandles: this.transcriptResizeHandles,
|
|
4739
|
+
constrainToViewport: true,
|
|
4740
|
+
classPrefix: `${this.player.options.classPrefix}-transcript`,
|
|
4741
|
+
keyboardDragKey: "d",
|
|
4742
|
+
keyboardResizeKey: "r",
|
|
4743
|
+
keyboardStep: 10,
|
|
4744
|
+
keyboardStepLarge: 50,
|
|
4745
|
+
minWidth: 300,
|
|
4746
|
+
minHeight: 200,
|
|
4747
|
+
maxWidth: () => Math.max(320, window.innerWidth - 40),
|
|
4748
|
+
maxHeight: () => Math.max(200, window.innerHeight - 120),
|
|
4749
|
+
pointerResizeIndicatorText: i18n.t("transcript.resizeModeHint"),
|
|
4750
|
+
onPointerResizeToggle: (enabled) => this.onPointerResizeModeChange(enabled),
|
|
4751
|
+
onDragStart: (e) => {
|
|
4752
|
+
const ignoreSelectors = [
|
|
4753
|
+
`.${this.player.options.classPrefix}-transcript-close`,
|
|
4754
|
+
`.${this.player.options.classPrefix}-transcript-settings`,
|
|
4755
|
+
`.${this.player.options.classPrefix}-transcript-language-select`,
|
|
4756
|
+
`.${this.player.options.classPrefix}-transcript-settings-menu`,
|
|
4757
|
+
`.${this.player.options.classPrefix}-transcript-style-dialog`
|
|
4758
|
+
];
|
|
4759
|
+
for (const selector of ignoreSelectors) {
|
|
4760
|
+
if (e.target.closest(selector)) {
|
|
4761
|
+
return false;
|
|
4762
|
+
}
|
|
3892
4763
|
}
|
|
4764
|
+
return true;
|
|
4765
|
+
}
|
|
4766
|
+
});
|
|
4767
|
+
this.customKeyHandler = (e) => {
|
|
4768
|
+
const key = e.key.toLowerCase();
|
|
4769
|
+
const alreadyPrevented = e.defaultPrevented;
|
|
4770
|
+
if (key === "home") {
|
|
3893
4771
|
e.preventDefault();
|
|
3894
4772
|
e.stopPropagation();
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
this.transcriptWindow.style.transform = "none";
|
|
3904
|
-
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3905
|
-
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3906
|
-
}
|
|
3907
|
-
let newX = currentLeft;
|
|
3908
|
-
let newY = currentTop;
|
|
3909
|
-
switch (e.key) {
|
|
3910
|
-
case "ArrowLeft":
|
|
3911
|
-
newX -= step;
|
|
3912
|
-
break;
|
|
3913
|
-
case "ArrowRight":
|
|
3914
|
-
newX += step;
|
|
3915
|
-
break;
|
|
3916
|
-
case "ArrowUp":
|
|
3917
|
-
newY -= step;
|
|
3918
|
-
break;
|
|
3919
|
-
case "ArrowDown":
|
|
3920
|
-
newY += step;
|
|
3921
|
-
break;
|
|
4773
|
+
if (this.draggableResizable) {
|
|
4774
|
+
if (this.draggableResizable.pointerResizeMode) {
|
|
4775
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
4776
|
+
}
|
|
4777
|
+
this.draggableResizable.manuallyPositioned = false;
|
|
4778
|
+
this.positionTranscript();
|
|
4779
|
+
this.updateResizeOptionState();
|
|
4780
|
+
this.announceLive(i18n.t("transcript.positionReset"));
|
|
3922
4781
|
}
|
|
3923
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3924
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3925
4782
|
return;
|
|
3926
4783
|
}
|
|
3927
|
-
if (
|
|
4784
|
+
if (key === "r") {
|
|
4785
|
+
if (alreadyPrevented) {
|
|
4786
|
+
return;
|
|
4787
|
+
}
|
|
3928
4788
|
e.preventDefault();
|
|
3929
4789
|
e.stopPropagation();
|
|
3930
|
-
this.
|
|
4790
|
+
const enabled = this.toggleResizeMode();
|
|
4791
|
+
if (enabled) {
|
|
4792
|
+
this.transcriptWindow.focus();
|
|
4793
|
+
}
|
|
3931
4794
|
return;
|
|
3932
4795
|
}
|
|
3933
|
-
if (
|
|
4796
|
+
if (key === "escape") {
|
|
3934
4797
|
e.preventDefault();
|
|
3935
4798
|
e.stopPropagation();
|
|
4799
|
+
if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
|
|
4800
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
4801
|
+
return;
|
|
4802
|
+
}
|
|
3936
4803
|
if (this.styleDialogVisible) {
|
|
3937
4804
|
this.hideStyleDialog();
|
|
3938
|
-
} else if (this.keyboardDragMode) {
|
|
3939
|
-
this.disableKeyboardDragMode();
|
|
4805
|
+
} else if (this.draggableResizable && this.draggableResizable.keyboardDragMode) {
|
|
4806
|
+
this.draggableResizable.disableKeyboardDragMode();
|
|
4807
|
+
this.announceLive(i18n.t("transcript.dragModeDisabled"));
|
|
3940
4808
|
} else if (this.settingsMenuVisible) {
|
|
3941
4809
|
this.hideSettingsMenu();
|
|
3942
4810
|
} else {
|
|
3943
|
-
this.hideTranscript();
|
|
4811
|
+
this.hideTranscript({ focusButton: true });
|
|
3944
4812
|
}
|
|
3945
4813
|
return;
|
|
3946
4814
|
}
|
|
3947
4815
|
};
|
|
3948
|
-
this.
|
|
3949
|
-
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
3950
|
-
document.addEventListener("mouseup", this.handlers.mouseup);
|
|
3951
|
-
this.transcriptHeader.addEventListener("touchstart", this.handlers.touchstart);
|
|
3952
|
-
document.addEventListener("touchmove", this.handlers.touchmove);
|
|
3953
|
-
document.addEventListener("touchend", this.handlers.touchend);
|
|
3954
|
-
this.transcriptHeader.addEventListener("keydown", this.handlers.keydown);
|
|
3955
|
-
}
|
|
3956
|
-
/**
|
|
3957
|
-
* Start dragging
|
|
3958
|
-
*/
|
|
3959
|
-
startDragging(clientX, clientY) {
|
|
3960
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3961
|
-
const containerRect = this.player.container.getBoundingClientRect();
|
|
3962
|
-
const relativeLeft = rect.left - containerRect.left;
|
|
3963
|
-
const relativeTop = rect.top - containerRect.top;
|
|
3964
|
-
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3965
|
-
if (computedStyle.transform !== "none") {
|
|
3966
|
-
this.transcriptWindow.style.transform = "none";
|
|
3967
|
-
this.transcriptWindow.style.left = `${relativeLeft}px`;
|
|
3968
|
-
this.transcriptWindow.style.top = `${relativeTop}px`;
|
|
3969
|
-
}
|
|
3970
|
-
this.dragOffsetX = clientX - rect.left;
|
|
3971
|
-
this.dragOffsetY = clientY - rect.top;
|
|
3972
|
-
this.isDragging = true;
|
|
3973
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-dragging`);
|
|
3974
|
-
document.body.style.cursor = "grabbing";
|
|
3975
|
-
document.body.style.userSelect = "none";
|
|
3976
|
-
}
|
|
3977
|
-
/**
|
|
3978
|
-
* Perform drag
|
|
3979
|
-
*/
|
|
3980
|
-
drag(clientX, clientY) {
|
|
3981
|
-
if (!this.isDragging) return;
|
|
3982
|
-
const newViewportX = clientX - this.dragOffsetX;
|
|
3983
|
-
const newViewportY = clientY - this.dragOffsetY;
|
|
3984
|
-
const containerRect = this.player.container.getBoundingClientRect();
|
|
3985
|
-
const newX = newViewportX - containerRect.left;
|
|
3986
|
-
const newY = newViewportY - containerRect.top;
|
|
3987
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3988
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3989
|
-
}
|
|
3990
|
-
/**
|
|
3991
|
-
* Stop dragging
|
|
3992
|
-
*/
|
|
3993
|
-
stopDragging() {
|
|
3994
|
-
this.isDragging = false;
|
|
3995
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-dragging`);
|
|
3996
|
-
document.body.style.cursor = "";
|
|
3997
|
-
document.body.style.userSelect = "";
|
|
3998
|
-
}
|
|
3999
|
-
/**
|
|
4000
|
-
* Set window position with boundary constraints
|
|
4001
|
-
*/
|
|
4002
|
-
setPosition(x, y) {
|
|
4003
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
4004
|
-
const viewportWidth = document.documentElement.clientWidth;
|
|
4005
|
-
const viewportHeight = document.documentElement.clientHeight;
|
|
4006
|
-
const minVisible = 100;
|
|
4007
|
-
const minX = -(rect.width - minVisible);
|
|
4008
|
-
const minY = -(rect.height - minVisible);
|
|
4009
|
-
const maxX = viewportWidth - minVisible;
|
|
4010
|
-
const maxY = viewportHeight - minVisible;
|
|
4011
|
-
x = Math.max(minX, Math.min(x, maxX));
|
|
4012
|
-
y = Math.max(minY, Math.min(y, maxY));
|
|
4013
|
-
this.transcriptWindow.style.left = `${x}px`;
|
|
4014
|
-
this.transcriptWindow.style.top = `${y}px`;
|
|
4015
|
-
this.transcriptWindow.style.transform = "none";
|
|
4016
|
-
}
|
|
4017
|
-
/**
|
|
4018
|
-
* Reset position to center
|
|
4019
|
-
*/
|
|
4020
|
-
resetPosition() {
|
|
4021
|
-
this.transcriptWindow.style.left = "50%";
|
|
4022
|
-
this.transcriptWindow.style.top = "50%";
|
|
4023
|
-
this.transcriptWindow.style.transform = "translate(-50%, -50%)";
|
|
4816
|
+
this.transcriptWindow.addEventListener("keydown", this.customKeyHandler);
|
|
4024
4817
|
}
|
|
4025
4818
|
/**
|
|
4026
4819
|
* Toggle keyboard drag mode
|
|
4027
4820
|
*/
|
|
4028
4821
|
toggleKeyboardDragMode() {
|
|
4029
|
-
if (this.
|
|
4030
|
-
this.
|
|
4031
|
-
|
|
4032
|
-
this.
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4041
|
-
if (this.settingsButton) {
|
|
4042
|
-
this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
|
|
4043
|
-
}
|
|
4044
|
-
const indicator = DOMUtils.createElement("div", {
|
|
4045
|
-
className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
|
|
4046
|
-
textContent: i18n.t("transcript.keyboardDragActive")
|
|
4047
|
-
});
|
|
4048
|
-
this.transcriptHeader.appendChild(indicator);
|
|
4049
|
-
if (this.settingsMenuVisible) {
|
|
4050
|
-
this.hideSettingsMenu();
|
|
4051
|
-
}
|
|
4052
|
-
this.transcriptHeader.focus();
|
|
4053
|
-
}
|
|
4054
|
-
/**
|
|
4055
|
-
* Disable keyboard drag mode
|
|
4056
|
-
*/
|
|
4057
|
-
disableKeyboardDragMode() {
|
|
4058
|
-
this.keyboardDragMode = false;
|
|
4059
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4060
|
-
if (this.settingsButton) {
|
|
4061
|
-
this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
|
|
4062
|
-
}
|
|
4063
|
-
const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
|
|
4064
|
-
if (indicator) {
|
|
4065
|
-
indicator.remove();
|
|
4066
|
-
}
|
|
4067
|
-
if (this.settingsButton) {
|
|
4068
|
-
this.settingsButton.focus();
|
|
4822
|
+
if (this.draggableResizable) {
|
|
4823
|
+
const wasEnabled = this.draggableResizable.keyboardDragMode;
|
|
4824
|
+
this.draggableResizable.toggleKeyboardDragMode();
|
|
4825
|
+
const isEnabled = this.draggableResizable.keyboardDragMode;
|
|
4826
|
+
if (!wasEnabled && isEnabled) {
|
|
4827
|
+
this.enableMoveMode();
|
|
4828
|
+
}
|
|
4829
|
+
if (this.settingsMenuVisible) {
|
|
4830
|
+
this.hideSettingsMenu();
|
|
4831
|
+
}
|
|
4832
|
+
this.transcriptWindow.focus();
|
|
4069
4833
|
}
|
|
4070
4834
|
}
|
|
4071
4835
|
/**
|
|
@@ -4095,6 +4859,16 @@ var VidPly = (() => {
|
|
|
4095
4859
|
if (this.settingsMenu) {
|
|
4096
4860
|
this.settingsMenu.style.display = "block";
|
|
4097
4861
|
this.settingsMenuVisible = true;
|
|
4862
|
+
if (this.settingsButton) {
|
|
4863
|
+
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4864
|
+
}
|
|
4865
|
+
this.updateResizeOptionState();
|
|
4866
|
+
setTimeout(() => {
|
|
4867
|
+
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4868
|
+
if (firstItem) {
|
|
4869
|
+
firstItem.focus();
|
|
4870
|
+
}
|
|
4871
|
+
}, 0);
|
|
4098
4872
|
return;
|
|
4099
4873
|
}
|
|
4100
4874
|
this.settingsMenu = DOMUtils.createElement("div", {
|
|
@@ -4142,19 +4916,35 @@ var VidPly = (() => {
|
|
|
4142
4916
|
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4143
4917
|
attributes: {
|
|
4144
4918
|
"type": "button",
|
|
4145
|
-
"aria-label": i18n.t("transcript.resizeWindow")
|
|
4919
|
+
"aria-label": i18n.t("transcript.resizeWindow"),
|
|
4920
|
+
"aria-pressed": "false"
|
|
4146
4921
|
}
|
|
4147
4922
|
});
|
|
4148
4923
|
const resizeIcon = createIconElement("resize");
|
|
4149
4924
|
const resizeText = DOMUtils.createElement("span", {
|
|
4925
|
+
className: `${this.player.options.classPrefix}-transcript-settings-text`,
|
|
4150
4926
|
textContent: i18n.t("transcript.resizeWindow")
|
|
4151
4927
|
});
|
|
4152
4928
|
resizeOption.appendChild(resizeIcon);
|
|
4153
4929
|
resizeOption.appendChild(resizeText);
|
|
4154
|
-
resizeOption.addEventListener("click", () => {
|
|
4155
|
-
|
|
4156
|
-
|
|
4930
|
+
resizeOption.addEventListener("click", (event) => {
|
|
4931
|
+
event.preventDefault();
|
|
4932
|
+
event.stopPropagation();
|
|
4933
|
+
const enabled = this.toggleResizeMode({ focus: false });
|
|
4934
|
+
if (enabled) {
|
|
4935
|
+
this.hideSettingsMenu({ focusButton: false });
|
|
4936
|
+
this.setManagedTimeout(() => {
|
|
4937
|
+
if (this.transcriptWindow) {
|
|
4938
|
+
this.transcriptWindow.focus();
|
|
4939
|
+
}
|
|
4940
|
+
}, 20);
|
|
4941
|
+
} else {
|
|
4942
|
+
this.hideSettingsMenu({ focusButton: true });
|
|
4943
|
+
}
|
|
4157
4944
|
});
|
|
4945
|
+
this.resizeOptionButton = resizeOption;
|
|
4946
|
+
this.resizeOptionText = resizeText;
|
|
4947
|
+
this.updateResizeOptionState();
|
|
4158
4948
|
const closeOption = DOMUtils.createElement("button", {
|
|
4159
4949
|
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4160
4950
|
attributes: {
|
|
@@ -4185,6 +4975,7 @@ var VidPly = (() => {
|
|
|
4185
4975
|
if (this.settingsButton) {
|
|
4186
4976
|
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4187
4977
|
}
|
|
4978
|
+
this.updateResizeOptionState();
|
|
4188
4979
|
setTimeout(() => {
|
|
4189
4980
|
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4190
4981
|
if (firstItem) {
|
|
@@ -4195,14 +4986,16 @@ var VidPly = (() => {
|
|
|
4195
4986
|
/**
|
|
4196
4987
|
* Hide settings menu
|
|
4197
4988
|
*/
|
|
4198
|
-
hideSettingsMenu() {
|
|
4989
|
+
hideSettingsMenu({ focusButton = true } = {}) {
|
|
4199
4990
|
if (this.settingsMenu) {
|
|
4200
4991
|
this.settingsMenu.style.display = "none";
|
|
4201
4992
|
this.settingsMenuVisible = false;
|
|
4202
4993
|
this.settingsMenuJustOpened = false;
|
|
4203
4994
|
if (this.settingsButton) {
|
|
4204
4995
|
this.settingsButton.setAttribute("aria-expanded", "false");
|
|
4205
|
-
|
|
4996
|
+
if (focusButton) {
|
|
4997
|
+
this.settingsButton.focus();
|
|
4998
|
+
}
|
|
4206
4999
|
}
|
|
4207
5000
|
}
|
|
4208
5001
|
}
|
|
@@ -4210,6 +5003,7 @@ var VidPly = (() => {
|
|
|
4210
5003
|
* Enable move mode (gives visual feedback)
|
|
4211
5004
|
*/
|
|
4212
5005
|
enableMoveMode() {
|
|
5006
|
+
this.hideResizeModeIndicator();
|
|
4213
5007
|
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4214
5008
|
const tooltip = DOMUtils.createElement("div", {
|
|
4215
5009
|
className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
|
|
@@ -4226,155 +5020,64 @@ var VidPly = (() => {
|
|
|
4226
5020
|
/**
|
|
4227
5021
|
* Toggle resize mode
|
|
4228
5022
|
*/
|
|
4229
|
-
toggleResizeMode() {
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
this.enableResizeHandles();
|
|
4233
|
-
} else {
|
|
4234
|
-
this.disableResizeHandles();
|
|
5023
|
+
toggleResizeMode({ focus = true } = {}) {
|
|
5024
|
+
if (!this.draggableResizable) {
|
|
5025
|
+
return false;
|
|
4235
5026
|
}
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
*/
|
|
4240
|
-
enableResizeHandles() {
|
|
4241
|
-
if (!this.transcriptWindow) return;
|
|
4242
|
-
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4243
|
-
directions.forEach((direction) => {
|
|
4244
|
-
const handle = DOMUtils.createElement("div", {
|
|
4245
|
-
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4246
|
-
attributes: {
|
|
4247
|
-
"data-direction": direction
|
|
4248
|
-
}
|
|
4249
|
-
});
|
|
4250
|
-
handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
|
|
4251
|
-
handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
|
|
4252
|
-
this.transcriptWindow.appendChild(handle);
|
|
4253
|
-
});
|
|
4254
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4255
|
-
this.handlers.resizeMove = (e) => {
|
|
4256
|
-
if (this.isResizing) {
|
|
4257
|
-
this.performResize(e.clientX, e.clientY);
|
|
4258
|
-
}
|
|
4259
|
-
};
|
|
4260
|
-
this.handlers.resizeEnd = () => {
|
|
4261
|
-
if (this.isResizing) {
|
|
4262
|
-
this.stopResize();
|
|
4263
|
-
}
|
|
4264
|
-
};
|
|
4265
|
-
this.handlers.resizeTouchMove = (e) => {
|
|
4266
|
-
if (this.isResizing) {
|
|
4267
|
-
this.performResize(e.touches[0].clientX, e.touches[0].clientY);
|
|
4268
|
-
e.preventDefault();
|
|
4269
|
-
}
|
|
4270
|
-
};
|
|
4271
|
-
document.addEventListener("mousemove", this.handlers.resizeMove);
|
|
4272
|
-
document.addEventListener("mouseup", this.handlers.resizeEnd);
|
|
4273
|
-
document.addEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4274
|
-
document.addEventListener("touchend", this.handlers.resizeEnd);
|
|
4275
|
-
}
|
|
4276
|
-
/**
|
|
4277
|
-
* Disable resize handles
|
|
4278
|
-
*/
|
|
4279
|
-
disableResizeHandles() {
|
|
4280
|
-
if (!this.transcriptWindow) return;
|
|
4281
|
-
const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
|
|
4282
|
-
handles.forEach((handle) => handle.remove());
|
|
4283
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4284
|
-
if (this.handlers.resizeMove) {
|
|
4285
|
-
document.removeEventListener("mousemove", this.handlers.resizeMove);
|
|
5027
|
+
if (this.draggableResizable.pointerResizeMode) {
|
|
5028
|
+
this.draggableResizable.disablePointerResizeMode({ focus });
|
|
5029
|
+
return false;
|
|
4286
5030
|
}
|
|
4287
|
-
|
|
4288
|
-
|
|
5031
|
+
this.draggableResizable.enablePointerResizeMode({ focus });
|
|
5032
|
+
return true;
|
|
5033
|
+
}
|
|
5034
|
+
updateResizeOptionState() {
|
|
5035
|
+
if (!this.resizeOptionButton) {
|
|
5036
|
+
return;
|
|
4289
5037
|
}
|
|
4290
|
-
|
|
4291
|
-
|
|
5038
|
+
const isEnabled = !!(this.draggableResizable && this.draggableResizable.pointerResizeMode);
|
|
5039
|
+
const label = isEnabled ? i18n.t("transcript.disableResizeWindow") || "Disable Resize Mode" : i18n.t("transcript.resizeWindow");
|
|
5040
|
+
this.resizeOptionButton.setAttribute("aria-pressed", isEnabled ? "true" : "false");
|
|
5041
|
+
this.resizeOptionButton.setAttribute("aria-label", label);
|
|
5042
|
+
this.resizeOptionButton.setAttribute("title", label);
|
|
5043
|
+
if (this.resizeOptionText) {
|
|
5044
|
+
this.resizeOptionText.textContent = label;
|
|
4292
5045
|
}
|
|
4293
|
-
document.removeEventListener("touchend", this.handlers.resizeEnd);
|
|
4294
|
-
}
|
|
4295
|
-
/**
|
|
4296
|
-
* Start resizing
|
|
4297
|
-
*/
|
|
4298
|
-
startResize(e, direction) {
|
|
4299
|
-
e.stopPropagation();
|
|
4300
|
-
e.preventDefault();
|
|
4301
|
-
this.isResizing = true;
|
|
4302
|
-
this.resizeDirection = direction;
|
|
4303
|
-
this.resizeStartX = e.clientX;
|
|
4304
|
-
this.resizeStartY = e.clientY;
|
|
4305
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
4306
|
-
this.resizeStartWidth = rect.width;
|
|
4307
|
-
this.resizeStartHeight = rect.height;
|
|
4308
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4309
|
-
document.body.style.cursor = this.getResizeCursor(direction);
|
|
4310
|
-
document.body.style.userSelect = "none";
|
|
4311
5046
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
const
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
if (
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
4346
|
-
this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
|
|
4347
|
-
}
|
|
4348
|
-
if (direction.includes("n")) {
|
|
4349
|
-
const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
4350
|
-
this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
|
|
5047
|
+
showResizeModeIndicator() {
|
|
5048
|
+
if (!this.transcriptHeader) {
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
5051
|
+
this.hideResizeModeIndicator();
|
|
5052
|
+
const indicator = DOMUtils.createElement("div", {
|
|
5053
|
+
className: `${this.player.options.classPrefix}-transcript-resize-tooltip`,
|
|
5054
|
+
textContent: i18n.t("transcript.resizeModeHint") || "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit."
|
|
5055
|
+
});
|
|
5056
|
+
this.transcriptHeader.appendChild(indicator);
|
|
5057
|
+
this.resizeModeIndicator = indicator;
|
|
5058
|
+
this.resizeModeIndicatorTimeout = this.setManagedTimeout(() => {
|
|
5059
|
+
this.hideResizeModeIndicator();
|
|
5060
|
+
}, 3e3);
|
|
5061
|
+
}
|
|
5062
|
+
hideResizeModeIndicator() {
|
|
5063
|
+
if (this.resizeModeIndicatorTimeout) {
|
|
5064
|
+
this.clearManagedTimeout(this.resizeModeIndicatorTimeout);
|
|
5065
|
+
this.resizeModeIndicatorTimeout = null;
|
|
5066
|
+
}
|
|
5067
|
+
if (this.resizeModeIndicator && this.resizeModeIndicator.parentNode) {
|
|
5068
|
+
this.resizeModeIndicator.remove();
|
|
5069
|
+
}
|
|
5070
|
+
this.resizeModeIndicator = null;
|
|
5071
|
+
}
|
|
5072
|
+
onPointerResizeModeChange(enabled) {
|
|
5073
|
+
this.updateResizeOptionState();
|
|
5074
|
+
if (enabled) {
|
|
5075
|
+
this.showResizeModeIndicator();
|
|
5076
|
+
this.announceLive(i18n.t("transcript.resizeModeEnabled"));
|
|
5077
|
+
} else {
|
|
5078
|
+
this.hideResizeModeIndicator();
|
|
5079
|
+
this.announceLive(i18n.t("transcript.resizeModeDisabled"));
|
|
4351
5080
|
}
|
|
4352
|
-
}
|
|
4353
|
-
/**
|
|
4354
|
-
* Stop resizing
|
|
4355
|
-
*/
|
|
4356
|
-
stopResize() {
|
|
4357
|
-
this.isResizing = false;
|
|
4358
|
-
this.resizeDirection = null;
|
|
4359
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4360
|
-
document.body.style.cursor = "";
|
|
4361
|
-
document.body.style.userSelect = "";
|
|
4362
|
-
}
|
|
4363
|
-
/**
|
|
4364
|
-
* Get cursor style for resize direction
|
|
4365
|
-
*/
|
|
4366
|
-
getResizeCursor(direction) {
|
|
4367
|
-
const cursors = {
|
|
4368
|
-
"n": "ns-resize",
|
|
4369
|
-
"s": "ns-resize",
|
|
4370
|
-
"e": "ew-resize",
|
|
4371
|
-
"w": "ew-resize",
|
|
4372
|
-
"ne": "nesw-resize",
|
|
4373
|
-
"nw": "nwse-resize",
|
|
4374
|
-
"se": "nwse-resize",
|
|
4375
|
-
"sw": "nesw-resize"
|
|
4376
|
-
};
|
|
4377
|
-
return cursors[direction] || "default";
|
|
4378
5081
|
}
|
|
4379
5082
|
/**
|
|
4380
5083
|
* Show style dialog
|
|
@@ -4608,30 +5311,50 @@ var VidPly = (() => {
|
|
|
4608
5311
|
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4609
5312
|
});
|
|
4610
5313
|
}
|
|
5314
|
+
/**
|
|
5315
|
+
* Set a managed timeout that will be cleaned up on destroy
|
|
5316
|
+
* @param {Function} callback - Callback function
|
|
5317
|
+
* @param {number} delay - Delay in milliseconds
|
|
5318
|
+
* @returns {number} Timeout ID
|
|
5319
|
+
*/
|
|
5320
|
+
setManagedTimeout(callback, delay) {
|
|
5321
|
+
const timeoutId = setTimeout(() => {
|
|
5322
|
+
this.timeouts.delete(timeoutId);
|
|
5323
|
+
callback();
|
|
5324
|
+
}, delay);
|
|
5325
|
+
this.timeouts.add(timeoutId);
|
|
5326
|
+
return timeoutId;
|
|
5327
|
+
}
|
|
5328
|
+
/**
|
|
5329
|
+
* Clear a managed timeout
|
|
5330
|
+
* @param {number} timeoutId - Timeout ID to clear
|
|
5331
|
+
*/
|
|
5332
|
+
clearManagedTimeout(timeoutId) {
|
|
5333
|
+
if (timeoutId) {
|
|
5334
|
+
clearTimeout(timeoutId);
|
|
5335
|
+
this.timeouts.delete(timeoutId);
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
4611
5338
|
/**
|
|
4612
5339
|
* Cleanup
|
|
4613
5340
|
*/
|
|
4614
5341
|
destroy() {
|
|
4615
|
-
|
|
4616
|
-
|
|
5342
|
+
this.hideResizeModeIndicator();
|
|
5343
|
+
if (this.draggableResizable) {
|
|
5344
|
+
if (this.draggableResizable.pointerResizeMode) {
|
|
5345
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
5346
|
+
this.updateResizeOptionState();
|
|
5347
|
+
}
|
|
5348
|
+
this.draggableResizable.destroy();
|
|
5349
|
+
this.draggableResizable = null;
|
|
4617
5350
|
}
|
|
4618
|
-
if (this.
|
|
4619
|
-
this.
|
|
5351
|
+
if (this.transcriptWindow && this.customKeyHandler) {
|
|
5352
|
+
this.transcriptWindow.removeEventListener("keydown", this.customKeyHandler);
|
|
5353
|
+
this.customKeyHandler = null;
|
|
4620
5354
|
}
|
|
4621
5355
|
if (this.handlers.timeupdate) {
|
|
4622
5356
|
this.player.off("timeupdate", this.handlers.timeupdate);
|
|
4623
5357
|
}
|
|
4624
|
-
if (this.transcriptHeader) {
|
|
4625
|
-
if (this.handlers.mousedown) {
|
|
4626
|
-
this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
|
|
4627
|
-
}
|
|
4628
|
-
if (this.handlers.touchstart) {
|
|
4629
|
-
this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
|
|
4630
|
-
}
|
|
4631
|
-
if (this.handlers.keydown) {
|
|
4632
|
-
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
4633
|
-
}
|
|
4634
|
-
}
|
|
4635
5358
|
if (this.settingsButton) {
|
|
4636
5359
|
if (this.handlers.settingsClick) {
|
|
4637
5360
|
this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
|
|
@@ -4643,24 +5366,14 @@ var VidPly = (() => {
|
|
|
4643
5366
|
if (this.styleDialog && this.handlers.styleDialogKeydown) {
|
|
4644
5367
|
this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4645
5368
|
}
|
|
4646
|
-
if (this.handlers.mousemove) {
|
|
4647
|
-
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
4648
|
-
}
|
|
4649
|
-
if (this.handlers.mouseup) {
|
|
4650
|
-
document.removeEventListener("mouseup", this.handlers.mouseup);
|
|
4651
|
-
}
|
|
4652
|
-
if (this.handlers.touchmove) {
|
|
4653
|
-
document.removeEventListener("touchmove", this.handlers.touchmove);
|
|
4654
|
-
}
|
|
4655
|
-
if (this.handlers.touchend) {
|
|
4656
|
-
document.removeEventListener("touchend", this.handlers.touchend);
|
|
4657
|
-
}
|
|
4658
5369
|
if (this.handlers.documentClick) {
|
|
4659
5370
|
document.removeEventListener("click", this.handlers.documentClick);
|
|
4660
5371
|
}
|
|
4661
5372
|
if (this.handlers.resize) {
|
|
4662
5373
|
window.removeEventListener("resize", this.handlers.resize);
|
|
4663
5374
|
}
|
|
5375
|
+
this.timeouts.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
5376
|
+
this.timeouts.clear();
|
|
4664
5377
|
this.handlers = null;
|
|
4665
5378
|
if (this.transcriptWindow && this.transcriptWindow.parentNode) {
|
|
4666
5379
|
this.transcriptWindow.parentNode.removeChild(this.transcriptWindow);
|
|
@@ -4671,6 +5384,14 @@ var VidPly = (() => {
|
|
|
4671
5384
|
this.transcriptEntries = [];
|
|
4672
5385
|
this.settingsMenu = null;
|
|
4673
5386
|
this.styleDialog = null;
|
|
5387
|
+
this.transcriptResizeHandles = [];
|
|
5388
|
+
this.resizeOptionButton = null;
|
|
5389
|
+
this.resizeOptionText = null;
|
|
5390
|
+
this.liveRegion = null;
|
|
5391
|
+
}
|
|
5392
|
+
announceLive(message) {
|
|
5393
|
+
if (!this.liveRegion) return;
|
|
5394
|
+
this.liveRegion.textContent = message || "";
|
|
4674
5395
|
}
|
|
4675
5396
|
};
|
|
4676
5397
|
|
|
@@ -5332,7 +6053,7 @@ var VidPly = (() => {
|
|
|
5332
6053
|
};
|
|
5333
6054
|
|
|
5334
6055
|
// src/core/Player.js
|
|
5335
|
-
var Player = class extends EventEmitter {
|
|
6056
|
+
var Player = class _Player extends EventEmitter {
|
|
5336
6057
|
constructor(element, options = {}) {
|
|
5337
6058
|
super();
|
|
5338
6059
|
this.element = typeof element === "string" ? document.querySelector(element) : element;
|
|
@@ -5440,6 +6161,8 @@ var VidPly = (() => {
|
|
|
5440
6161
|
screenReaderAnnouncements: true,
|
|
5441
6162
|
highContrast: false,
|
|
5442
6163
|
focusHighlight: true,
|
|
6164
|
+
metadataAlerts: {},
|
|
6165
|
+
metadataHashtags: {},
|
|
5443
6166
|
// Languages
|
|
5444
6167
|
language: "en",
|
|
5445
6168
|
languages: ["en"],
|
|
@@ -5458,6 +6181,8 @@ var VidPly = (() => {
|
|
|
5458
6181
|
onError: null,
|
|
5459
6182
|
...options
|
|
5460
6183
|
};
|
|
6184
|
+
this.options.metadataAlerts = this.options.metadataAlerts || {};
|
|
6185
|
+
this.options.metadataHashtags = this.options.metadataHashtags || {};
|
|
5461
6186
|
this.storage = new StorageManager("vidply");
|
|
5462
6187
|
const savedPrefs = this.storage.getPlayerPreferences();
|
|
5463
6188
|
if (savedPrefs) {
|
|
@@ -5492,12 +6217,22 @@ var VidPly = (() => {
|
|
|
5492
6217
|
this.audioDescriptionSourceElement = null;
|
|
5493
6218
|
this.originalAudioDescriptionSource = null;
|
|
5494
6219
|
this.audioDescriptionCaptionTracks = [];
|
|
6220
|
+
this._audioDescriptionDesiredState = false;
|
|
6221
|
+
this._textTracksCache = null;
|
|
6222
|
+
this._textTracksDirty = true;
|
|
6223
|
+
this._sourceElementsCache = null;
|
|
6224
|
+
this._sourceElementsDirty = true;
|
|
6225
|
+
this._trackElementsCache = null;
|
|
6226
|
+
this._trackElementsDirty = true;
|
|
6227
|
+
this.timeouts = /* @__PURE__ */ new Set();
|
|
5495
6228
|
this.container = null;
|
|
5496
6229
|
this.renderer = null;
|
|
5497
6230
|
this.controlBar = null;
|
|
5498
6231
|
this.captionManager = null;
|
|
5499
6232
|
this.keyboardManager = null;
|
|
5500
6233
|
this.settingsDialog = null;
|
|
6234
|
+
this.metadataCueChangeHandler = null;
|
|
6235
|
+
this.metadataAlertHandlers = /* @__PURE__ */ new Map();
|
|
5501
6236
|
this.init();
|
|
5502
6237
|
}
|
|
5503
6238
|
async init() {
|
|
@@ -5529,6 +6264,7 @@ var VidPly = (() => {
|
|
|
5529
6264
|
if (this.options.transcript || this.options.transcriptButton) {
|
|
5530
6265
|
this.transcriptManager = new TranscriptManager(this);
|
|
5531
6266
|
}
|
|
6267
|
+
this.setupMetadataHandling();
|
|
5532
6268
|
if (this.options.keyboard) {
|
|
5533
6269
|
this.keyboardManager = new KeyboardManager(this);
|
|
5534
6270
|
}
|
|
@@ -5599,7 +6335,6 @@ var VidPly = (() => {
|
|
|
5599
6335
|
this.element.style.height = "100%";
|
|
5600
6336
|
if (this.element.tagName === "VIDEO" && this.options.playsInline) {
|
|
5601
6337
|
this.element.setAttribute("playsinline", "");
|
|
5602
|
-
this.element.setAttribute("webkit-playsinline", "");
|
|
5603
6338
|
this.element.playsInline = true;
|
|
5604
6339
|
}
|
|
5605
6340
|
if (this.options.width) {
|
|
@@ -5614,12 +6349,22 @@ var VidPly = (() => {
|
|
|
5614
6349
|
if (this.element.tagName === "VIDEO") {
|
|
5615
6350
|
this.createPlayButtonOverlay();
|
|
5616
6351
|
}
|
|
6352
|
+
this.element.vidply = this;
|
|
6353
|
+
_Player.instances.push(this);
|
|
5617
6354
|
this.element.style.cursor = "pointer";
|
|
5618
6355
|
this.element.addEventListener("click", (e) => {
|
|
5619
6356
|
if (e.target === this.element) {
|
|
5620
6357
|
this.toggle();
|
|
5621
6358
|
}
|
|
5622
6359
|
});
|
|
6360
|
+
this.on("play", () => {
|
|
6361
|
+
this.hidePosterOverlay();
|
|
6362
|
+
});
|
|
6363
|
+
this.on("timeupdate", () => {
|
|
6364
|
+
if (this.state.currentTime > 0) {
|
|
6365
|
+
this.hidePosterOverlay();
|
|
6366
|
+
}
|
|
6367
|
+
});
|
|
5623
6368
|
}
|
|
5624
6369
|
createPlayButtonOverlay() {
|
|
5625
6370
|
this.playButtonOverlay = createPlayOverlay();
|
|
@@ -5646,7 +6391,7 @@ var VidPly = (() => {
|
|
|
5646
6391
|
if (!src) {
|
|
5647
6392
|
throw new Error("No media source found");
|
|
5648
6393
|
}
|
|
5649
|
-
const sourceElements = this.
|
|
6394
|
+
const sourceElements = this.sourceElements;
|
|
5650
6395
|
for (const sourceEl of sourceElements) {
|
|
5651
6396
|
const descSrc = sourceEl.getAttribute("data-desc-src");
|
|
5652
6397
|
const origSrc = sourceEl.getAttribute("data-orig-src");
|
|
@@ -5675,7 +6420,7 @@ var VidPly = (() => {
|
|
|
5675
6420
|
}
|
|
5676
6421
|
}
|
|
5677
6422
|
}
|
|
5678
|
-
const trackElements = this.
|
|
6423
|
+
const trackElements = this.trackElements;
|
|
5679
6424
|
trackElements.forEach((trackEl) => {
|
|
5680
6425
|
const trackKind = trackEl.getAttribute("kind");
|
|
5681
6426
|
const trackDescSrc = trackEl.getAttribute("data-desc-src");
|
|
@@ -5696,19 +6441,137 @@ var VidPly = (() => {
|
|
|
5696
6441
|
if (!this.originalSrc) {
|
|
5697
6442
|
this.originalSrc = src;
|
|
5698
6443
|
}
|
|
5699
|
-
let renderer;
|
|
5700
|
-
if (src.includes("youtube.com") || src.includes("youtu.be")) {
|
|
5701
|
-
renderer = YouTubeRenderer;
|
|
5702
|
-
} else if (src.includes("vimeo.com")) {
|
|
5703
|
-
renderer = VimeoRenderer;
|
|
5704
|
-
} else if (src.includes(".m3u8")) {
|
|
5705
|
-
renderer = HLSRenderer;
|
|
5706
|
-
} else {
|
|
5707
|
-
renderer = HTML5Renderer;
|
|
6444
|
+
let renderer;
|
|
6445
|
+
if (src.includes("youtube.com") || src.includes("youtu.be")) {
|
|
6446
|
+
renderer = YouTubeRenderer;
|
|
6447
|
+
} else if (src.includes("vimeo.com")) {
|
|
6448
|
+
renderer = VimeoRenderer;
|
|
6449
|
+
} else if (src.includes(".m3u8")) {
|
|
6450
|
+
renderer = HLSRenderer;
|
|
6451
|
+
} else {
|
|
6452
|
+
renderer = HTML5Renderer;
|
|
6453
|
+
}
|
|
6454
|
+
this.log(`Using ${renderer.name} renderer`);
|
|
6455
|
+
this.renderer = new renderer(this);
|
|
6456
|
+
await this.renderer.init();
|
|
6457
|
+
this.invalidateTrackCache();
|
|
6458
|
+
}
|
|
6459
|
+
/**
|
|
6460
|
+
* Get cached text tracks array
|
|
6461
|
+
* @returns {Array} Array of text tracks
|
|
6462
|
+
*/
|
|
6463
|
+
get textTracks() {
|
|
6464
|
+
if (!this._textTracksCache || this._textTracksDirty) {
|
|
6465
|
+
this._textTracksCache = Array.from(this.element.textTracks || []);
|
|
6466
|
+
this._textTracksDirty = false;
|
|
6467
|
+
}
|
|
6468
|
+
return this._textTracksCache;
|
|
6469
|
+
}
|
|
6470
|
+
/**
|
|
6471
|
+
* Get cached source elements array
|
|
6472
|
+
* @returns {Array} Array of source elements
|
|
6473
|
+
*/
|
|
6474
|
+
get sourceElements() {
|
|
6475
|
+
if (!this._sourceElementsCache || this._sourceElementsDirty) {
|
|
6476
|
+
this._sourceElementsCache = Array.from(this.element.querySelectorAll("source"));
|
|
6477
|
+
this._sourceElementsDirty = false;
|
|
6478
|
+
}
|
|
6479
|
+
return this._sourceElementsCache;
|
|
6480
|
+
}
|
|
6481
|
+
/**
|
|
6482
|
+
* Get cached track elements array
|
|
6483
|
+
* @returns {Array} Array of track elements
|
|
6484
|
+
*/
|
|
6485
|
+
get trackElements() {
|
|
6486
|
+
if (!this._trackElementsCache || this._trackElementsDirty) {
|
|
6487
|
+
this._trackElementsCache = Array.from(this.element.querySelectorAll("track"));
|
|
6488
|
+
this._trackElementsDirty = false;
|
|
6489
|
+
}
|
|
6490
|
+
return this._trackElementsCache;
|
|
6491
|
+
}
|
|
6492
|
+
/**
|
|
6493
|
+
* Invalidate DOM query cache (call when tracks/sources change)
|
|
6494
|
+
*/
|
|
6495
|
+
invalidateTrackCache() {
|
|
6496
|
+
this._textTracksDirty = true;
|
|
6497
|
+
this._trackElementsDirty = true;
|
|
6498
|
+
this._sourceElementsDirty = true;
|
|
6499
|
+
}
|
|
6500
|
+
/**
|
|
6501
|
+
* Find a text track by kind and optionally language
|
|
6502
|
+
* @param {string} kind - Track kind (captions, subtitles, descriptions, chapters, metadata)
|
|
6503
|
+
* @param {string} [language] - Optional language code
|
|
6504
|
+
* @returns {TextTrack|null} Found track or null
|
|
6505
|
+
*/
|
|
6506
|
+
findTextTrack(kind, language = null) {
|
|
6507
|
+
const tracks = this.textTracks;
|
|
6508
|
+
if (language) {
|
|
6509
|
+
return tracks.find((t) => t.kind === kind && t.language === language);
|
|
6510
|
+
}
|
|
6511
|
+
return tracks.find((t) => t.kind === kind);
|
|
6512
|
+
}
|
|
6513
|
+
/**
|
|
6514
|
+
* Find a source element by attribute
|
|
6515
|
+
* @param {string} attribute - Attribute name (e.g., 'data-desc-src')
|
|
6516
|
+
* @param {string} [value] - Optional attribute value
|
|
6517
|
+
* @returns {Element|null} Found source element or null
|
|
6518
|
+
*/
|
|
6519
|
+
findSourceElement(attribute, value = null) {
|
|
6520
|
+
const sources = this.sourceElements;
|
|
6521
|
+
if (value) {
|
|
6522
|
+
return sources.find((el) => el.getAttribute(attribute) === value);
|
|
6523
|
+
}
|
|
6524
|
+
return sources.find((el) => el.hasAttribute(attribute));
|
|
6525
|
+
}
|
|
6526
|
+
/**
|
|
6527
|
+
* Find a track element by its associated TextTrack
|
|
6528
|
+
* @param {TextTrack} track - The TextTrack object
|
|
6529
|
+
* @returns {Element|null} Found track element or null
|
|
6530
|
+
*/
|
|
6531
|
+
findTrackElement(track) {
|
|
6532
|
+
return this.trackElements.find((el) => el.track === track);
|
|
6533
|
+
}
|
|
6534
|
+
showPosterOverlay() {
|
|
6535
|
+
if (!this.videoWrapper || this.element.tagName !== "VIDEO") {
|
|
6536
|
+
return;
|
|
6537
|
+
}
|
|
6538
|
+
const poster = this.element.getAttribute("poster") || this.element.poster || this.options.poster;
|
|
6539
|
+
if (!poster) {
|
|
6540
|
+
return;
|
|
6541
|
+
}
|
|
6542
|
+
this.videoWrapper.style.setProperty("--vidply-poster-image", `url("${poster}")`);
|
|
6543
|
+
this.videoWrapper.classList.add("vidply-forced-poster");
|
|
6544
|
+
}
|
|
6545
|
+
hidePosterOverlay() {
|
|
6546
|
+
if (!this.videoWrapper) {
|
|
6547
|
+
return;
|
|
6548
|
+
}
|
|
6549
|
+
this.videoWrapper.classList.remove("vidply-forced-poster");
|
|
6550
|
+
this.videoWrapper.style.removeProperty("--vidply-poster-image");
|
|
6551
|
+
}
|
|
6552
|
+
/**
|
|
6553
|
+
* Set a managed timeout that will be cleaned up on destroy
|
|
6554
|
+
* @param {Function} callback - Callback function
|
|
6555
|
+
* @param {number} delay - Delay in milliseconds
|
|
6556
|
+
* @returns {number} Timeout ID
|
|
6557
|
+
*/
|
|
6558
|
+
setManagedTimeout(callback, delay) {
|
|
6559
|
+
const timeoutId = setTimeout(() => {
|
|
6560
|
+
this.timeouts.delete(timeoutId);
|
|
6561
|
+
callback();
|
|
6562
|
+
}, delay);
|
|
6563
|
+
this.timeouts.add(timeoutId);
|
|
6564
|
+
return timeoutId;
|
|
6565
|
+
}
|
|
6566
|
+
/**
|
|
6567
|
+
* Clear a managed timeout
|
|
6568
|
+
* @param {number} timeoutId - Timeout ID to clear
|
|
6569
|
+
*/
|
|
6570
|
+
clearManagedTimeout(timeoutId) {
|
|
6571
|
+
if (timeoutId) {
|
|
6572
|
+
clearTimeout(timeoutId);
|
|
6573
|
+
this.timeouts.delete(timeoutId);
|
|
5708
6574
|
}
|
|
5709
|
-
this.log(`Using ${renderer.name} renderer`);
|
|
5710
|
-
this.renderer = new renderer(this);
|
|
5711
|
-
await this.renderer.init();
|
|
5712
6575
|
}
|
|
5713
6576
|
/**
|
|
5714
6577
|
* Load new media source (for playlists)
|
|
@@ -5724,8 +6587,9 @@ var VidPly = (() => {
|
|
|
5724
6587
|
if (this.renderer) {
|
|
5725
6588
|
this.pause();
|
|
5726
6589
|
}
|
|
5727
|
-
const existingTracks = this.
|
|
6590
|
+
const existingTracks = this.trackElements;
|
|
5728
6591
|
existingTracks.forEach((track) => track.remove());
|
|
6592
|
+
this.invalidateTrackCache();
|
|
5729
6593
|
this.element.src = config.src;
|
|
5730
6594
|
if (config.type) {
|
|
5731
6595
|
this.element.type = config.type;
|
|
@@ -5745,6 +6609,7 @@ var VidPly = (() => {
|
|
|
5745
6609
|
}
|
|
5746
6610
|
this.element.appendChild(track);
|
|
5747
6611
|
});
|
|
6612
|
+
this.invalidateTrackCache();
|
|
5748
6613
|
}
|
|
5749
6614
|
const shouldChangeRenderer = this.shouldChangeRenderer(config.src);
|
|
5750
6615
|
if (shouldChangeRenderer && this.renderer) {
|
|
@@ -5992,7 +6857,7 @@ var VidPly = (() => {
|
|
|
5992
6857
|
}
|
|
5993
6858
|
// Audio Description
|
|
5994
6859
|
async enableAudioDescription() {
|
|
5995
|
-
const hasSourceElementsWithDesc =
|
|
6860
|
+
const hasSourceElementsWithDesc = this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
5996
6861
|
const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;
|
|
5997
6862
|
if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
|
|
5998
6863
|
console.warn("VidPly: No audio description source, source elements, or tracks provided");
|
|
@@ -6000,10 +6865,14 @@ var VidPly = (() => {
|
|
|
6000
6865
|
}
|
|
6001
6866
|
const currentTime = this.state.currentTime;
|
|
6002
6867
|
const wasPlaying = this.state.playing;
|
|
6868
|
+
const shouldKeepPoster = !wasPlaying && currentTime === 0;
|
|
6869
|
+
if (shouldKeepPoster) {
|
|
6870
|
+
this.showPosterOverlay();
|
|
6871
|
+
}
|
|
6003
6872
|
let swappedTracksForTranscript = [];
|
|
6004
6873
|
if (this.audioDescriptionSourceElement) {
|
|
6005
6874
|
const currentSrc = this.element.currentSrc || this.element.src;
|
|
6006
|
-
const sourceElements =
|
|
6875
|
+
const sourceElements = this.sourceElements;
|
|
6007
6876
|
let sourceElementToUpdate = null;
|
|
6008
6877
|
let descSrc = this.audioDescriptionSrc;
|
|
6009
6878
|
for (const sourceEl of sourceElements) {
|
|
@@ -6100,8 +6969,9 @@ var VidPly = (() => {
|
|
|
6100
6969
|
trackInfo.trackElement = newTrackElement;
|
|
6101
6970
|
});
|
|
6102
6971
|
this.element.load();
|
|
6972
|
+
this.invalidateTrackCache();
|
|
6103
6973
|
const setupNewTracks = () => {
|
|
6104
|
-
|
|
6974
|
+
this.setManagedTimeout(() => {
|
|
6105
6975
|
swappedTracksForTranscript.forEach((trackInfo) => {
|
|
6106
6976
|
const trackElement = trackInfo.trackElement;
|
|
6107
6977
|
const newTextTrack = trackElement.track;
|
|
@@ -6137,7 +7007,7 @@ var VidPly = (() => {
|
|
|
6137
7007
|
const skippedCount = validationResults.length - tracksToSwap.length;
|
|
6138
7008
|
}
|
|
6139
7009
|
}
|
|
6140
|
-
const allSourceElements =
|
|
7010
|
+
const allSourceElements = this.sourceElements;
|
|
6141
7011
|
const sourcesToUpdate = [];
|
|
6142
7012
|
allSourceElements.forEach((sourceEl) => {
|
|
6143
7013
|
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
@@ -6181,8 +7051,15 @@ var VidPly = (() => {
|
|
|
6181
7051
|
if (sourceInfo.descSrc) {
|
|
6182
7052
|
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6183
7053
|
}
|
|
6184
|
-
this.element.
|
|
7054
|
+
const firstTrack = this.element.querySelector("track");
|
|
7055
|
+
if (firstTrack) {
|
|
7056
|
+
this.element.insertBefore(newSource, firstTrack);
|
|
7057
|
+
} else {
|
|
7058
|
+
this.element.appendChild(newSource);
|
|
7059
|
+
}
|
|
6185
7060
|
});
|
|
7061
|
+
this._sourceElementsDirty = true;
|
|
7062
|
+
this._sourceElementsCache = null;
|
|
6186
7063
|
this.element.load();
|
|
6187
7064
|
await new Promise((resolve) => {
|
|
6188
7065
|
const onLoadedMetadata = () => {
|
|
@@ -6192,18 +7069,18 @@ var VidPly = (() => {
|
|
|
6192
7069
|
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
6193
7070
|
});
|
|
6194
7071
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
6195
|
-
if (
|
|
6196
|
-
|
|
6197
|
-
this.element.currentTime = 1e-3;
|
|
6198
|
-
setTimeout(() => {
|
|
6199
|
-
this.element.currentTime = 0;
|
|
6200
|
-
}, 10);
|
|
6201
|
-
}
|
|
7072
|
+
if (currentTime > 0) {
|
|
7073
|
+
this.seek(currentTime);
|
|
6202
7074
|
}
|
|
6203
|
-
this.seek(currentTime);
|
|
6204
7075
|
if (wasPlaying) {
|
|
6205
7076
|
this.play();
|
|
6206
7077
|
}
|
|
7078
|
+
if (!shouldKeepPoster) {
|
|
7079
|
+
this.hidePosterOverlay();
|
|
7080
|
+
}
|
|
7081
|
+
if (!this._audioDescriptionDesiredState) {
|
|
7082
|
+
return;
|
|
7083
|
+
}
|
|
6207
7084
|
this.state.audioDescriptionEnabled = true;
|
|
6208
7085
|
this.emit("audiodescriptionenabled");
|
|
6209
7086
|
} else {
|
|
@@ -6315,7 +7192,7 @@ var VidPly = (() => {
|
|
|
6315
7192
|
}, 100);
|
|
6316
7193
|
}
|
|
6317
7194
|
}
|
|
6318
|
-
const fallbackSourceElements =
|
|
7195
|
+
const fallbackSourceElements = this.sourceElements;
|
|
6319
7196
|
const hasSourceElementsWithDesc2 = fallbackSourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6320
7197
|
if (hasSourceElementsWithDesc2) {
|
|
6321
7198
|
const fallbackSourcesToUpdate = [];
|
|
@@ -6363,6 +7240,7 @@ var VidPly = (() => {
|
|
|
6363
7240
|
this.element.appendChild(newSource);
|
|
6364
7241
|
});
|
|
6365
7242
|
this.element.load();
|
|
7243
|
+
this.invalidateTrackCache();
|
|
6366
7244
|
} else {
|
|
6367
7245
|
this.element.src = this.audioDescriptionSrc;
|
|
6368
7246
|
}
|
|
@@ -6377,12 +7255,14 @@ var VidPly = (() => {
|
|
|
6377
7255
|
if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
|
|
6378
7256
|
if (this.element.readyState >= 1) {
|
|
6379
7257
|
this.element.currentTime = 1e-3;
|
|
6380
|
-
|
|
7258
|
+
this.setManagedTimeout(() => {
|
|
6381
7259
|
this.element.currentTime = 0;
|
|
6382
7260
|
}, 10);
|
|
6383
7261
|
}
|
|
6384
7262
|
}
|
|
6385
|
-
|
|
7263
|
+
if (currentTime > 0) {
|
|
7264
|
+
this.seek(currentTime);
|
|
7265
|
+
}
|
|
6386
7266
|
if (wasPlaying) {
|
|
6387
7267
|
this.play();
|
|
6388
7268
|
}
|
|
@@ -6417,7 +7297,8 @@ var VidPly = (() => {
|
|
|
6417
7297
|
const swappedTracks = typeof swappedTracksForTranscript !== "undefined" ? swappedTracksForTranscript : [];
|
|
6418
7298
|
if (swappedTracks.length > 0) {
|
|
6419
7299
|
const onMetadataLoaded = () => {
|
|
6420
|
-
|
|
7300
|
+
this.invalidateTrackCache();
|
|
7301
|
+
const allTextTracks = this.textTracks;
|
|
6421
7302
|
const freshTracks = swappedTracks.map((trackInfo) => {
|
|
6422
7303
|
const trackEl = trackInfo.trackElement;
|
|
6423
7304
|
const expectedSrc = trackEl.getAttribute("src");
|
|
@@ -6427,9 +7308,7 @@ var VidPly = (() => {
|
|
|
6427
7308
|
if (!foundTrack) {
|
|
6428
7309
|
foundTrack = allTextTracks.find((track) => {
|
|
6429
7310
|
if (track.language === srclang && (track.kind === kind || kind === "captions" && track.kind === "subtitles")) {
|
|
6430
|
-
const trackElementForTrack =
|
|
6431
|
-
(el) => el.track === track
|
|
6432
|
-
);
|
|
7311
|
+
const trackElementForTrack = this.findTrackElement(track);
|
|
6433
7312
|
if (trackElementForTrack) {
|
|
6434
7313
|
const actualSrc = trackElementForTrack.getAttribute("src");
|
|
6435
7314
|
if (actualSrc === expectedSrc) {
|
|
@@ -6441,9 +7320,7 @@ var VidPly = (() => {
|
|
|
6441
7320
|
});
|
|
6442
7321
|
}
|
|
6443
7322
|
if (foundTrack) {
|
|
6444
|
-
const trackElement =
|
|
6445
|
-
(el) => el.track === foundTrack
|
|
6446
|
-
);
|
|
7323
|
+
const trackElement = this.findTrackElement(foundTrack);
|
|
6447
7324
|
if (trackElement && trackElement.getAttribute("src") !== expectedSrc) {
|
|
6448
7325
|
return null;
|
|
6449
7326
|
}
|
|
@@ -6451,7 +7328,7 @@ var VidPly = (() => {
|
|
|
6451
7328
|
return foundTrack;
|
|
6452
7329
|
}).filter(Boolean);
|
|
6453
7330
|
if (freshTracks.length === 0) {
|
|
6454
|
-
|
|
7331
|
+
this.setManagedTimeout(() => {
|
|
6455
7332
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6456
7333
|
this.transcriptManager.loadTranscriptData();
|
|
6457
7334
|
}
|
|
@@ -6467,14 +7344,13 @@ var VidPly = (() => {
|
|
|
6467
7344
|
const checkLoaded = () => {
|
|
6468
7345
|
loadedCount++;
|
|
6469
7346
|
if (loadedCount >= freshTracks.length) {
|
|
6470
|
-
|
|
7347
|
+
this.setManagedTimeout(() => {
|
|
6471
7348
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6472
|
-
|
|
7349
|
+
this.invalidateTrackCache();
|
|
7350
|
+
const allTextTracks2 = this.textTracks;
|
|
6473
7351
|
const swappedTrackSrcs = swappedTracks.map((t) => t.describedSrc);
|
|
6474
7352
|
const hasCorrectTracks = freshTracks.some((track) => {
|
|
6475
|
-
const trackEl =
|
|
6476
|
-
(el) => el.track === track
|
|
6477
|
-
);
|
|
7353
|
+
const trackEl = this.findTrackElement(track);
|
|
6478
7354
|
return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute("src"));
|
|
6479
7355
|
});
|
|
6480
7356
|
if (hasCorrectTracks || freshTracks.length > 0) {
|
|
@@ -6488,9 +7364,7 @@ var VidPly = (() => {
|
|
|
6488
7364
|
if (track.mode === "disabled") {
|
|
6489
7365
|
track.mode = "hidden";
|
|
6490
7366
|
}
|
|
6491
|
-
const trackElementForTrack =
|
|
6492
|
-
(el) => el.track === track
|
|
6493
|
-
);
|
|
7367
|
+
const trackElementForTrack = this.findTrackElement(track);
|
|
6494
7368
|
const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute("src") : null;
|
|
6495
7369
|
const expectedTrackInfo = swappedTracks.find((t) => {
|
|
6496
7370
|
const tEl = t.trackElement;
|
|
@@ -6508,10 +7382,10 @@ var VidPly = (() => {
|
|
|
6508
7382
|
track.mode = "hidden";
|
|
6509
7383
|
}
|
|
6510
7384
|
const onTrackLoad = () => {
|
|
6511
|
-
|
|
7385
|
+
this.setManagedTimeout(checkLoaded, 300);
|
|
6512
7386
|
};
|
|
6513
7387
|
if (track.readyState >= 2) {
|
|
6514
|
-
|
|
7388
|
+
this.setManagedTimeout(() => {
|
|
6515
7389
|
if (track.cues && track.cues.length > 0) {
|
|
6516
7390
|
checkLoaded();
|
|
6517
7391
|
} else {
|
|
@@ -6528,12 +7402,12 @@ var VidPly = (() => {
|
|
|
6528
7402
|
});
|
|
6529
7403
|
};
|
|
6530
7404
|
const waitForTracks = () => {
|
|
6531
|
-
|
|
7405
|
+
this.setManagedTimeout(() => {
|
|
6532
7406
|
if (this.element.readyState >= 1) {
|
|
6533
7407
|
onMetadataLoaded();
|
|
6534
7408
|
} else {
|
|
6535
7409
|
this.element.addEventListener("loadedmetadata", onMetadataLoaded, { once: true });
|
|
6536
|
-
|
|
7410
|
+
this.setManagedTimeout(onMetadataLoaded, 2e3);
|
|
6537
7411
|
}
|
|
6538
7412
|
}, 500);
|
|
6539
7413
|
};
|
|
@@ -6551,6 +7425,12 @@ var VidPly = (() => {
|
|
|
6551
7425
|
}, 800);
|
|
6552
7426
|
}
|
|
6553
7427
|
}
|
|
7428
|
+
if (!shouldKeepPoster) {
|
|
7429
|
+
this.hidePosterOverlay();
|
|
7430
|
+
}
|
|
7431
|
+
if (!this._audioDescriptionDesiredState) {
|
|
7432
|
+
return;
|
|
7433
|
+
}
|
|
6554
7434
|
this.state.audioDescriptionEnabled = true;
|
|
6555
7435
|
this.emit("audiodescriptionenabled");
|
|
6556
7436
|
}
|
|
@@ -6567,7 +7447,7 @@ var VidPly = (() => {
|
|
|
6567
7447
|
}
|
|
6568
7448
|
});
|
|
6569
7449
|
}
|
|
6570
|
-
const allSourceElements =
|
|
7450
|
+
const allSourceElements = this.sourceElements;
|
|
6571
7451
|
const hasSourceElementsToSwap = allSourceElements.some((el) => el.getAttribute("data-orig-src"));
|
|
6572
7452
|
if (hasSourceElementsToSwap) {
|
|
6573
7453
|
const sourcesToRestore = [];
|
|
@@ -6610,61 +7490,107 @@ var VidPly = (() => {
|
|
|
6610
7490
|
if (sourceInfo.descSrc) {
|
|
6611
7491
|
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6612
7492
|
}
|
|
6613
|
-
this.element.
|
|
7493
|
+
const firstTrack = this.element.querySelector("track");
|
|
7494
|
+
if (firstTrack) {
|
|
7495
|
+
this.element.insertBefore(newSource, firstTrack);
|
|
7496
|
+
} else {
|
|
7497
|
+
this.element.appendChild(newSource);
|
|
7498
|
+
}
|
|
6614
7499
|
});
|
|
7500
|
+
this._sourceElementsDirty = true;
|
|
7501
|
+
this._sourceElementsCache = null;
|
|
6615
7502
|
this.element.load();
|
|
6616
7503
|
} else {
|
|
6617
7504
|
const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;
|
|
6618
7505
|
this.element.src = originalSrcToUse;
|
|
6619
7506
|
this.element.load();
|
|
6620
7507
|
}
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
7508
|
+
if (currentTime > 0 || wasPlaying) {
|
|
7509
|
+
await new Promise((resolve) => {
|
|
7510
|
+
const onLoadedMetadata = () => {
|
|
7511
|
+
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
7512
|
+
resolve();
|
|
7513
|
+
};
|
|
7514
|
+
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
7515
|
+
});
|
|
7516
|
+
if (currentTime > 0) {
|
|
7517
|
+
this.seek(currentTime);
|
|
7518
|
+
}
|
|
7519
|
+
if (wasPlaying) {
|
|
7520
|
+
this.play();
|
|
7521
|
+
}
|
|
7522
|
+
}
|
|
7523
|
+
if (!wasPlaying && currentTime === 0) {
|
|
7524
|
+
this.showPosterOverlay();
|
|
7525
|
+
} else {
|
|
7526
|
+
this.hidePosterOverlay();
|
|
6631
7527
|
}
|
|
6632
7528
|
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
6633
|
-
|
|
7529
|
+
this.setManagedTimeout(() => {
|
|
6634
7530
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6635
7531
|
this.transcriptManager.loadTranscriptData();
|
|
6636
7532
|
}
|
|
6637
7533
|
}, 500);
|
|
6638
7534
|
}
|
|
7535
|
+
if (this._audioDescriptionDesiredState) {
|
|
7536
|
+
return;
|
|
7537
|
+
}
|
|
6639
7538
|
this.state.audioDescriptionEnabled = false;
|
|
6640
7539
|
this.emit("audiodescriptiondisabled");
|
|
6641
7540
|
}
|
|
6642
7541
|
async toggleAudioDescription() {
|
|
6643
|
-
const
|
|
6644
|
-
const
|
|
6645
|
-
const hasAudioDescriptionSrc = this.audioDescriptionSrc || Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
|
|
7542
|
+
const descriptionTrack = this.findTextTrack("descriptions");
|
|
7543
|
+
const hasAudioDescriptionSrc = this.audioDescriptionSrc || this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6646
7544
|
if (descriptionTrack && hasAudioDescriptionSrc) {
|
|
6647
7545
|
if (this.state.audioDescriptionEnabled) {
|
|
7546
|
+
this._audioDescriptionDesiredState = false;
|
|
6648
7547
|
descriptionTrack.mode = "hidden";
|
|
6649
7548
|
await this.disableAudioDescription();
|
|
6650
7549
|
} else {
|
|
7550
|
+
this._audioDescriptionDesiredState = true;
|
|
6651
7551
|
await this.enableAudioDescription();
|
|
6652
|
-
|
|
7552
|
+
const enableDescriptionTrack = () => {
|
|
7553
|
+
this.invalidateTrackCache();
|
|
7554
|
+
const descTrack = this.findTextTrack("descriptions");
|
|
7555
|
+
if (descTrack) {
|
|
7556
|
+
if (descTrack.mode === "disabled") {
|
|
7557
|
+
descTrack.mode = "hidden";
|
|
7558
|
+
this.setManagedTimeout(() => {
|
|
7559
|
+
descTrack.mode = "showing";
|
|
7560
|
+
}, 50);
|
|
7561
|
+
} else {
|
|
7562
|
+
descTrack.mode = "showing";
|
|
7563
|
+
}
|
|
7564
|
+
} else if (this.element.readyState < 2) {
|
|
7565
|
+
this.setManagedTimeout(enableDescriptionTrack, 100);
|
|
7566
|
+
}
|
|
7567
|
+
};
|
|
7568
|
+
if (this.element.readyState >= 1) {
|
|
7569
|
+
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
7570
|
+
} else {
|
|
7571
|
+
this.element.addEventListener("loadedmetadata", () => {
|
|
7572
|
+
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
7573
|
+
}, { once: true });
|
|
7574
|
+
}
|
|
6653
7575
|
}
|
|
6654
7576
|
} else if (descriptionTrack) {
|
|
6655
7577
|
if (descriptionTrack.mode === "showing") {
|
|
7578
|
+
this._audioDescriptionDesiredState = false;
|
|
6656
7579
|
descriptionTrack.mode = "hidden";
|
|
6657
7580
|
this.state.audioDescriptionEnabled = false;
|
|
6658
7581
|
this.emit("audiodescriptiondisabled");
|
|
6659
7582
|
} else {
|
|
7583
|
+
this._audioDescriptionDesiredState = true;
|
|
6660
7584
|
descriptionTrack.mode = "showing";
|
|
6661
7585
|
this.state.audioDescriptionEnabled = true;
|
|
6662
7586
|
this.emit("audiodescriptionenabled");
|
|
6663
7587
|
}
|
|
6664
7588
|
} else if (hasAudioDescriptionSrc) {
|
|
6665
7589
|
if (this.state.audioDescriptionEnabled) {
|
|
7590
|
+
this._audioDescriptionDesiredState = false;
|
|
6666
7591
|
await this.disableAudioDescription();
|
|
6667
7592
|
} else {
|
|
7593
|
+
this._audioDescriptionDesiredState = true;
|
|
6668
7594
|
await this.enableAudioDescription();
|
|
6669
7595
|
}
|
|
6670
7596
|
}
|
|
@@ -6761,177 +7687,22 @@ var VidPly = (() => {
|
|
|
6761
7687
|
}
|
|
6762
7688
|
setupSignLanguageInteraction() {
|
|
6763
7689
|
if (!this.signLanguageWrapper) return;
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
isDragging = true;
|
|
6779
|
-
startX = e.clientX;
|
|
6780
|
-
startY = e.clientY;
|
|
6781
|
-
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6782
|
-
startLeft = rect.left;
|
|
6783
|
-
startTop = rect.top;
|
|
6784
|
-
this.signLanguageWrapper.classList.add("vidply-sign-dragging");
|
|
6785
|
-
};
|
|
6786
|
-
const onMouseDownHandle = (e) => {
|
|
6787
|
-
if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
|
|
6788
|
-
e.preventDefault();
|
|
6789
|
-
e.stopPropagation();
|
|
6790
|
-
isResizing = true;
|
|
6791
|
-
resizeDirection = e.target.getAttribute("data-direction");
|
|
6792
|
-
startX = e.clientX;
|
|
6793
|
-
startY = e.clientY;
|
|
6794
|
-
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6795
|
-
startLeft = rect.left;
|
|
6796
|
-
startTop = rect.top;
|
|
6797
|
-
startWidth = rect.width;
|
|
6798
|
-
startHeight = rect.height;
|
|
6799
|
-
this.signLanguageWrapper.classList.add("vidply-sign-resizing");
|
|
6800
|
-
};
|
|
6801
|
-
const onMouseMove = (e) => {
|
|
6802
|
-
if (isDragging) {
|
|
6803
|
-
const deltaX = e.clientX - startX;
|
|
6804
|
-
const deltaY = e.clientY - startY;
|
|
6805
|
-
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6806
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
6807
|
-
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6808
|
-
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6809
|
-
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6810
|
-
let newLeft = startLeft + deltaX - containerRect.left;
|
|
6811
|
-
let newTop = startTop + deltaY - containerRect.top;
|
|
6812
|
-
const controlsHeight = 95;
|
|
6813
|
-
newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
|
|
6814
|
-
newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
|
|
6815
|
-
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6816
|
-
this.signLanguageWrapper.style.top = `${newTop}px`;
|
|
6817
|
-
this.signLanguageWrapper.style.right = "auto";
|
|
6818
|
-
this.signLanguageWrapper.style.bottom = "auto";
|
|
6819
|
-
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6820
|
-
} else if (isResizing) {
|
|
6821
|
-
const deltaX = e.clientX - startX;
|
|
6822
|
-
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6823
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
6824
|
-
let newWidth = startWidth;
|
|
6825
|
-
let newLeft = startLeft - containerRect.left;
|
|
6826
|
-
if (resizeDirection.includes("e")) {
|
|
6827
|
-
newWidth = Math.max(150, startWidth + deltaX);
|
|
6828
|
-
const maxWidth = videoWrapperRect.right - startLeft;
|
|
6829
|
-
newWidth = Math.min(newWidth, maxWidth);
|
|
6830
|
-
}
|
|
6831
|
-
if (resizeDirection.includes("w")) {
|
|
6832
|
-
const proposedWidth = Math.max(150, startWidth - deltaX);
|
|
6833
|
-
const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
|
|
6834
|
-
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6835
|
-
if (proposedLeft >= videoWrapperLeft) {
|
|
6836
|
-
newWidth = proposedWidth;
|
|
6837
|
-
newLeft = proposedLeft;
|
|
6838
|
-
}
|
|
6839
|
-
}
|
|
6840
|
-
this.signLanguageWrapper.style.width = `${newWidth}px`;
|
|
6841
|
-
this.signLanguageWrapper.style.height = "auto";
|
|
6842
|
-
if (resizeDirection.includes("w")) {
|
|
6843
|
-
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6844
|
-
}
|
|
6845
|
-
this.signLanguageWrapper.style.right = "auto";
|
|
6846
|
-
this.signLanguageWrapper.style.bottom = "auto";
|
|
6847
|
-
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6848
|
-
}
|
|
6849
|
-
};
|
|
6850
|
-
const onMouseUp = () => {
|
|
6851
|
-
if (isDragging || isResizing) {
|
|
6852
|
-
this.saveSignLanguagePreferences();
|
|
6853
|
-
}
|
|
6854
|
-
isDragging = false;
|
|
6855
|
-
isResizing = false;
|
|
6856
|
-
resizeDirection = null;
|
|
6857
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
|
|
6858
|
-
};
|
|
6859
|
-
const onKeyDown = (e) => {
|
|
6860
|
-
if (e.key === "d" || e.key === "D") {
|
|
6861
|
-
dragMode = !dragMode;
|
|
6862
|
-
resizeMode = false;
|
|
6863
|
-
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
|
|
6864
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
|
|
6865
|
-
e.preventDefault();
|
|
6866
|
-
return;
|
|
6867
|
-
}
|
|
6868
|
-
if (e.key === "r" || e.key === "R") {
|
|
6869
|
-
resizeMode = !resizeMode;
|
|
6870
|
-
dragMode = false;
|
|
6871
|
-
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
|
|
6872
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
|
|
6873
|
-
e.preventDefault();
|
|
6874
|
-
return;
|
|
6875
|
-
}
|
|
6876
|
-
if (e.key === "Escape") {
|
|
6877
|
-
dragMode = false;
|
|
6878
|
-
resizeMode = false;
|
|
6879
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
|
|
6880
|
-
e.preventDefault();
|
|
6881
|
-
return;
|
|
6882
|
-
}
|
|
6883
|
-
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
6884
|
-
const step = e.shiftKey ? 10 : 5;
|
|
6885
|
-
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6886
|
-
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6887
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
6888
|
-
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6889
|
-
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6890
|
-
if (dragMode) {
|
|
6891
|
-
let left = rect.left - containerRect.left;
|
|
6892
|
-
let top = rect.top - containerRect.top;
|
|
6893
|
-
if (e.key === "ArrowLeft") left -= step;
|
|
6894
|
-
if (e.key === "ArrowRight") left += step;
|
|
6895
|
-
if (e.key === "ArrowUp") top -= step;
|
|
6896
|
-
if (e.key === "ArrowDown") top += step;
|
|
6897
|
-
const controlsHeight = 95;
|
|
6898
|
-
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
|
|
6899
|
-
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
|
|
6900
|
-
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6901
|
-
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6902
|
-
this.signLanguageWrapper.style.right = "auto";
|
|
6903
|
-
this.signLanguageWrapper.style.bottom = "auto";
|
|
6904
|
-
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6905
|
-
this.saveSignLanguagePreferences();
|
|
6906
|
-
e.preventDefault();
|
|
6907
|
-
} else if (resizeMode) {
|
|
6908
|
-
let width = rect.width;
|
|
6909
|
-
if (e.key === "ArrowLeft") width -= step;
|
|
6910
|
-
if (e.key === "ArrowRight") width += step;
|
|
6911
|
-
if (e.key === "ArrowUp") width += step;
|
|
6912
|
-
if (e.key === "ArrowDown") width -= step;
|
|
6913
|
-
width = Math.max(150, width);
|
|
6914
|
-
width = Math.min(width, videoWrapperRect.width);
|
|
6915
|
-
this.signLanguageWrapper.style.width = `${width}px`;
|
|
6916
|
-
this.signLanguageWrapper.style.height = "auto";
|
|
6917
|
-
this.saveSignLanguagePreferences();
|
|
6918
|
-
e.preventDefault();
|
|
6919
|
-
}
|
|
6920
|
-
}
|
|
6921
|
-
};
|
|
6922
|
-
this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
|
|
6923
|
-
const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
|
|
6924
|
-
handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
|
|
6925
|
-
document.addEventListener("mousemove", onMouseMove);
|
|
6926
|
-
document.addEventListener("mouseup", onMouseUp);
|
|
6927
|
-
this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
|
|
7690
|
+
const resizeHandles = Array.from(this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle"));
|
|
7691
|
+
this.signLanguageDraggable = new DraggableResizable(this.signLanguageWrapper, {
|
|
7692
|
+
dragHandle: this.signLanguageVideo,
|
|
7693
|
+
resizeHandles,
|
|
7694
|
+
constrainToViewport: true,
|
|
7695
|
+
maintainAspectRatio: true,
|
|
7696
|
+
minWidth: 150,
|
|
7697
|
+
minHeight: 100,
|
|
7698
|
+
classPrefix: "vidply-sign",
|
|
7699
|
+
keyboardDragKey: "d",
|
|
7700
|
+
keyboardResizeKey: "r",
|
|
7701
|
+
keyboardStep: 5,
|
|
7702
|
+
keyboardStepLarge: 10
|
|
7703
|
+
});
|
|
6928
7704
|
this.signLanguageInteractionHandlers = {
|
|
6929
|
-
|
|
6930
|
-
mouseDownHandle: onMouseDownHandle,
|
|
6931
|
-
mouseMove: onMouseMove,
|
|
6932
|
-
mouseUp: onMouseUp,
|
|
6933
|
-
keyDown: onKeyDown,
|
|
6934
|
-
handles
|
|
7705
|
+
draggable: this.signLanguageDraggable
|
|
6935
7706
|
};
|
|
6936
7707
|
}
|
|
6937
7708
|
constrainSignLanguagePosition() {
|
|
@@ -6998,22 +7769,11 @@ var VidPly = (() => {
|
|
|
6998
7769
|
this.off("ratechange", this.signLanguageHandlers.ratechange);
|
|
6999
7770
|
this.signLanguageHandlers = null;
|
|
7000
7771
|
}
|
|
7001
|
-
if (this.
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
}
|
|
7005
|
-
if (this.signLanguageInteractionHandlers.handles) {
|
|
7006
|
-
this.signLanguageInteractionHandlers.handles.forEach((handle) => {
|
|
7007
|
-
handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
|
|
7008
|
-
});
|
|
7009
|
-
}
|
|
7010
|
-
document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
|
|
7011
|
-
document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
|
|
7012
|
-
if (this.signLanguageWrapper) {
|
|
7013
|
-
this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
|
|
7014
|
-
}
|
|
7015
|
-
this.signLanguageInteractionHandlers = null;
|
|
7772
|
+
if (this.signLanguageDraggable) {
|
|
7773
|
+
this.signLanguageDraggable.destroy();
|
|
7774
|
+
this.signLanguageDraggable = null;
|
|
7016
7775
|
}
|
|
7776
|
+
this.signLanguageInteractionHandlers = null;
|
|
7017
7777
|
if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
|
|
7018
7778
|
if (this.signLanguageVideo) {
|
|
7019
7779
|
this.signLanguageVideo.pause();
|
|
@@ -7062,9 +7822,25 @@ var VidPly = (() => {
|
|
|
7062
7822
|
}
|
|
7063
7823
|
}
|
|
7064
7824
|
// Logging
|
|
7065
|
-
log(
|
|
7066
|
-
if (this.options.debug) {
|
|
7067
|
-
|
|
7825
|
+
log(...messages) {
|
|
7826
|
+
if (!this.options.debug) {
|
|
7827
|
+
return;
|
|
7828
|
+
}
|
|
7829
|
+
let type = "log";
|
|
7830
|
+
if (messages.length > 0) {
|
|
7831
|
+
const potentialType = messages[messages.length - 1];
|
|
7832
|
+
if (typeof potentialType === "string" && console[potentialType]) {
|
|
7833
|
+
type = potentialType;
|
|
7834
|
+
messages = messages.slice(0, -1);
|
|
7835
|
+
}
|
|
7836
|
+
}
|
|
7837
|
+
if (messages.length === 0) {
|
|
7838
|
+
messages = [""];
|
|
7839
|
+
}
|
|
7840
|
+
if (typeof console[type] === "function") {
|
|
7841
|
+
console[type]("[VidPly]", ...messages);
|
|
7842
|
+
} else {
|
|
7843
|
+
console.log("[VidPly]", ...messages);
|
|
7068
7844
|
}
|
|
7069
7845
|
}
|
|
7070
7846
|
// Setup responsive handlers
|
|
@@ -7089,7 +7865,9 @@ var VidPly = (() => {
|
|
|
7089
7865
|
this.controlBar.updateControlsForViewport(width);
|
|
7090
7866
|
}
|
|
7091
7867
|
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
7092
|
-
this.transcriptManager.
|
|
7868
|
+
if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
7869
|
+
this.transcriptManager.positionTranscript();
|
|
7870
|
+
}
|
|
7093
7871
|
}
|
|
7094
7872
|
};
|
|
7095
7873
|
window.addEventListener("resize", this.resizeHandler);
|
|
@@ -7098,7 +7876,9 @@ var VidPly = (() => {
|
|
|
7098
7876
|
this.orientationHandler = (e) => {
|
|
7099
7877
|
setTimeout(() => {
|
|
7100
7878
|
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
7101
|
-
this.transcriptManager.
|
|
7879
|
+
if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
7880
|
+
this.transcriptManager.positionTranscript();
|
|
7881
|
+
}
|
|
7102
7882
|
}
|
|
7103
7883
|
}, 100);
|
|
7104
7884
|
};
|
|
@@ -7124,7 +7904,7 @@ var VidPly = (() => {
|
|
|
7124
7904
|
this.controlBar.updateFullscreenButton();
|
|
7125
7905
|
}
|
|
7126
7906
|
if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
|
|
7127
|
-
|
|
7907
|
+
this.setManagedTimeout(() => {
|
|
7128
7908
|
requestAnimationFrame(() => {
|
|
7129
7909
|
this.storage.saveSignLanguagePreferences({ size: null });
|
|
7130
7910
|
this.signLanguageDesiredPosition = "bottom-right";
|
|
@@ -7187,12 +7967,368 @@ var VidPly = (() => {
|
|
|
7187
7967
|
document.removeEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
|
|
7188
7968
|
this.fullscreenChangeHandler = null;
|
|
7189
7969
|
}
|
|
7970
|
+
this.timeouts.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
7971
|
+
this.timeouts.clear();
|
|
7972
|
+
if (this.metadataCueChangeHandler) {
|
|
7973
|
+
const textTracks = this.textTracks;
|
|
7974
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
7975
|
+
if (metadataTrack) {
|
|
7976
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
7977
|
+
}
|
|
7978
|
+
this.metadataCueChangeHandler = null;
|
|
7979
|
+
}
|
|
7980
|
+
if (this.metadataAlertHandlers && this.metadataAlertHandlers.size > 0) {
|
|
7981
|
+
this.metadataAlertHandlers.forEach(({ button, handler }) => {
|
|
7982
|
+
if (button && handler) {
|
|
7983
|
+
button.removeEventListener("click", handler);
|
|
7984
|
+
}
|
|
7985
|
+
});
|
|
7986
|
+
this.metadataAlertHandlers.clear();
|
|
7987
|
+
}
|
|
7190
7988
|
if (this.container && this.container.parentNode) {
|
|
7191
7989
|
this.container.parentNode.insertBefore(this.element, this.container);
|
|
7192
7990
|
this.container.parentNode.removeChild(this.container);
|
|
7193
7991
|
}
|
|
7194
7992
|
this.removeAllListeners();
|
|
7195
7993
|
}
|
|
7994
|
+
/**
|
|
7995
|
+
* Setup metadata track handling
|
|
7996
|
+
* This enables metadata tracks and listens for cue changes to trigger actions
|
|
7997
|
+
*/
|
|
7998
|
+
setupMetadataHandling() {
|
|
7999
|
+
const setupMetadata = () => {
|
|
8000
|
+
const textTracks = this.textTracks;
|
|
8001
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
8002
|
+
if (metadataTrack) {
|
|
8003
|
+
if (metadataTrack.mode === "disabled") {
|
|
8004
|
+
metadataTrack.mode = "hidden";
|
|
8005
|
+
}
|
|
8006
|
+
if (this.metadataCueChangeHandler) {
|
|
8007
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
8008
|
+
}
|
|
8009
|
+
this.metadataCueChangeHandler = () => {
|
|
8010
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
8011
|
+
if (activeCues.length > 0) {
|
|
8012
|
+
if (this.options.debug) {
|
|
8013
|
+
this.log("[Metadata] Active cues:", activeCues.map((c) => ({
|
|
8014
|
+
start: c.startTime,
|
|
8015
|
+
end: c.endTime,
|
|
8016
|
+
text: c.text
|
|
8017
|
+
})));
|
|
8018
|
+
}
|
|
8019
|
+
}
|
|
8020
|
+
activeCues.forEach((cue) => {
|
|
8021
|
+
this.handleMetadataCue(cue);
|
|
8022
|
+
});
|
|
8023
|
+
};
|
|
8024
|
+
metadataTrack.addEventListener("cuechange", this.metadataCueChangeHandler);
|
|
8025
|
+
if (this.options.debug) {
|
|
8026
|
+
const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;
|
|
8027
|
+
this.log("[Metadata] Track enabled,", cueCount, "cues available");
|
|
8028
|
+
}
|
|
8029
|
+
} else if (this.options.debug) {
|
|
8030
|
+
this.log("[Metadata] No metadata track found");
|
|
8031
|
+
}
|
|
8032
|
+
};
|
|
8033
|
+
setupMetadata();
|
|
8034
|
+
this.on("loadedmetadata", setupMetadata);
|
|
8035
|
+
}
|
|
8036
|
+
normalizeMetadataSelector(selector) {
|
|
8037
|
+
if (!selector) {
|
|
8038
|
+
return null;
|
|
8039
|
+
}
|
|
8040
|
+
const trimmed = selector.trim();
|
|
8041
|
+
if (!trimmed) {
|
|
8042
|
+
return null;
|
|
8043
|
+
}
|
|
8044
|
+
if (trimmed.startsWith("#") || trimmed.startsWith(".") || trimmed.startsWith("[")) {
|
|
8045
|
+
return trimmed;
|
|
8046
|
+
}
|
|
8047
|
+
return `#${trimmed}`;
|
|
8048
|
+
}
|
|
8049
|
+
resolveMetadataConfig(map, key) {
|
|
8050
|
+
if (!map || !key) {
|
|
8051
|
+
return null;
|
|
8052
|
+
}
|
|
8053
|
+
if (Object.prototype.hasOwnProperty.call(map, key)) {
|
|
8054
|
+
return map[key];
|
|
8055
|
+
}
|
|
8056
|
+
const withoutHash = key.replace(/^#/, "");
|
|
8057
|
+
if (Object.prototype.hasOwnProperty.call(map, withoutHash)) {
|
|
8058
|
+
return map[withoutHash];
|
|
8059
|
+
}
|
|
8060
|
+
return null;
|
|
8061
|
+
}
|
|
8062
|
+
cacheMetadataAlertContent(element, config = {}) {
|
|
8063
|
+
if (!element) {
|
|
8064
|
+
return;
|
|
8065
|
+
}
|
|
8066
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
8067
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
8068
|
+
const titleEl = element.querySelector(titleSelector);
|
|
8069
|
+
if (titleEl && !titleEl.dataset.vidplyAlertTitleOriginal) {
|
|
8070
|
+
titleEl.dataset.vidplyAlertTitleOriginal = titleEl.textContent.trim();
|
|
8071
|
+
}
|
|
8072
|
+
const messageEl = element.querySelector(messageSelector);
|
|
8073
|
+
if (messageEl && !messageEl.dataset.vidplyAlertMessageOriginal) {
|
|
8074
|
+
messageEl.dataset.vidplyAlertMessageOriginal = messageEl.textContent.trim();
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
restoreMetadataAlertContent(element, config = {}) {
|
|
8078
|
+
if (!element) {
|
|
8079
|
+
return;
|
|
8080
|
+
}
|
|
8081
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
8082
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
8083
|
+
const titleEl = element.querySelector(titleSelector);
|
|
8084
|
+
if (titleEl && titleEl.dataset.vidplyAlertTitleOriginal) {
|
|
8085
|
+
titleEl.textContent = titleEl.dataset.vidplyAlertTitleOriginal;
|
|
8086
|
+
}
|
|
8087
|
+
const messageEl = element.querySelector(messageSelector);
|
|
8088
|
+
if (messageEl && messageEl.dataset.vidplyAlertMessageOriginal) {
|
|
8089
|
+
messageEl.textContent = messageEl.dataset.vidplyAlertMessageOriginal;
|
|
8090
|
+
}
|
|
8091
|
+
}
|
|
8092
|
+
focusMetadataTarget(target, fallbackElement = null) {
|
|
8093
|
+
var _a, _b;
|
|
8094
|
+
if (!target || target === "none") {
|
|
8095
|
+
return;
|
|
8096
|
+
}
|
|
8097
|
+
if (target === "alert" && fallbackElement) {
|
|
8098
|
+
fallbackElement.focus();
|
|
8099
|
+
return;
|
|
8100
|
+
}
|
|
8101
|
+
if (target === "player") {
|
|
8102
|
+
if (this.container) {
|
|
8103
|
+
this.container.focus();
|
|
8104
|
+
}
|
|
8105
|
+
return;
|
|
8106
|
+
}
|
|
8107
|
+
if (target === "media") {
|
|
8108
|
+
this.element.focus();
|
|
8109
|
+
return;
|
|
8110
|
+
}
|
|
8111
|
+
if (target === "playButton") {
|
|
8112
|
+
const playButton = (_b = (_a = this.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.playPause;
|
|
8113
|
+
if (playButton) {
|
|
8114
|
+
playButton.focus();
|
|
8115
|
+
}
|
|
8116
|
+
return;
|
|
8117
|
+
}
|
|
8118
|
+
if (typeof target === "string") {
|
|
8119
|
+
const targetElement = document.querySelector(target);
|
|
8120
|
+
if (targetElement) {
|
|
8121
|
+
if (targetElement.tabIndex === -1 && !targetElement.hasAttribute("tabindex")) {
|
|
8122
|
+
targetElement.setAttribute("tabindex", "-1");
|
|
8123
|
+
}
|
|
8124
|
+
targetElement.focus();
|
|
8125
|
+
}
|
|
8126
|
+
}
|
|
8127
|
+
}
|
|
8128
|
+
handleMetadataAlert(selector, options = {}) {
|
|
8129
|
+
if (!selector) {
|
|
8130
|
+
return;
|
|
8131
|
+
}
|
|
8132
|
+
const config = this.resolveMetadataConfig(this.options.metadataAlerts, selector) || {};
|
|
8133
|
+
const element = options.element || document.querySelector(selector);
|
|
8134
|
+
if (!element) {
|
|
8135
|
+
if (this.options.debug) {
|
|
8136
|
+
this.log("[Metadata] Alert element not found:", selector);
|
|
8137
|
+
}
|
|
8138
|
+
return;
|
|
8139
|
+
}
|
|
8140
|
+
if (this.options.debug) {
|
|
8141
|
+
this.log("[Metadata] Handling alert", selector, { reason: options.reason, config });
|
|
8142
|
+
}
|
|
8143
|
+
this.cacheMetadataAlertContent(element, config);
|
|
8144
|
+
if (!element.dataset.vidplyAlertOriginalDisplay) {
|
|
8145
|
+
element.dataset.vidplyAlertOriginalDisplay = element.style.display || "";
|
|
8146
|
+
}
|
|
8147
|
+
if (!element.dataset.vidplyAlertDisplay) {
|
|
8148
|
+
element.dataset.vidplyAlertDisplay = config.display || "block";
|
|
8149
|
+
}
|
|
8150
|
+
const shouldShow = options.show !== void 0 ? options.show : config.show !== false;
|
|
8151
|
+
if (shouldShow) {
|
|
8152
|
+
const displayValue = config.display || element.dataset.vidplyAlertDisplay || "block";
|
|
8153
|
+
element.style.display = displayValue;
|
|
8154
|
+
element.hidden = false;
|
|
8155
|
+
element.removeAttribute("hidden");
|
|
8156
|
+
element.setAttribute("aria-hidden", "false");
|
|
8157
|
+
element.setAttribute("data-vidply-alert-active", "true");
|
|
8158
|
+
}
|
|
8159
|
+
const shouldReset = config.resetContent !== false && options.reason === "focus";
|
|
8160
|
+
if (shouldReset) {
|
|
8161
|
+
this.restoreMetadataAlertContent(element, config);
|
|
8162
|
+
}
|
|
8163
|
+
const shouldFocus = options.focus !== void 0 ? options.focus : config.focusOnShow ?? options.reason !== "focus";
|
|
8164
|
+
if (shouldShow && shouldFocus) {
|
|
8165
|
+
if (element.tabIndex === -1 && !element.hasAttribute("tabindex")) {
|
|
8166
|
+
element.setAttribute("tabindex", "-1");
|
|
8167
|
+
}
|
|
8168
|
+
element.focus();
|
|
8169
|
+
}
|
|
8170
|
+
if (shouldShow && config.autoScroll !== false && options.autoScroll !== false) {
|
|
8171
|
+
element.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
8172
|
+
}
|
|
8173
|
+
const continueSelector = config.continueButton;
|
|
8174
|
+
if (continueSelector) {
|
|
8175
|
+
let continueButton = null;
|
|
8176
|
+
if (continueSelector === "self") {
|
|
8177
|
+
continueButton = element;
|
|
8178
|
+
} else if (element.matches(continueSelector)) {
|
|
8179
|
+
continueButton = element;
|
|
8180
|
+
} else {
|
|
8181
|
+
continueButton = element.querySelector(continueSelector) || document.querySelector(continueSelector);
|
|
8182
|
+
}
|
|
8183
|
+
if (continueButton && !this.metadataAlertHandlers.has(selector)) {
|
|
8184
|
+
const handler = () => {
|
|
8185
|
+
const hideOnContinue = config.hideOnContinue !== false;
|
|
8186
|
+
if (hideOnContinue) {
|
|
8187
|
+
const originalDisplay = element.dataset.vidplyAlertOriginalDisplay || "";
|
|
8188
|
+
element.style.display = config.hideDisplay || originalDisplay || "none";
|
|
8189
|
+
element.setAttribute("aria-hidden", "true");
|
|
8190
|
+
element.removeAttribute("data-vidply-alert-active");
|
|
8191
|
+
}
|
|
8192
|
+
if (config.resume !== false && this.state.paused) {
|
|
8193
|
+
this.play();
|
|
8194
|
+
}
|
|
8195
|
+
const focusTarget = config.focusTarget || "playButton";
|
|
8196
|
+
this.setManagedTimeout(() => {
|
|
8197
|
+
this.focusMetadataTarget(focusTarget, element);
|
|
8198
|
+
}, config.focusDelay ?? 100);
|
|
8199
|
+
};
|
|
8200
|
+
continueButton.addEventListener("click", handler);
|
|
8201
|
+
this.metadataAlertHandlers.set(selector, { button: continueButton, handler });
|
|
8202
|
+
}
|
|
8203
|
+
}
|
|
8204
|
+
return element;
|
|
8205
|
+
}
|
|
8206
|
+
handleMetadataHashtags(hashtags) {
|
|
8207
|
+
if (!Array.isArray(hashtags) || hashtags.length === 0) {
|
|
8208
|
+
return;
|
|
8209
|
+
}
|
|
8210
|
+
const configMap = this.options.metadataHashtags;
|
|
8211
|
+
if (!configMap) {
|
|
8212
|
+
return;
|
|
8213
|
+
}
|
|
8214
|
+
hashtags.forEach((tag) => {
|
|
8215
|
+
const config = this.resolveMetadataConfig(configMap, tag);
|
|
8216
|
+
if (!config) {
|
|
8217
|
+
return;
|
|
8218
|
+
}
|
|
8219
|
+
const selector = this.normalizeMetadataSelector(config.alert || config.selector || config.target);
|
|
8220
|
+
if (!selector) {
|
|
8221
|
+
return;
|
|
8222
|
+
}
|
|
8223
|
+
const element = document.querySelector(selector);
|
|
8224
|
+
if (!element) {
|
|
8225
|
+
if (this.options.debug) {
|
|
8226
|
+
this.log("[Metadata] Hashtag target not found:", selector);
|
|
8227
|
+
}
|
|
8228
|
+
return;
|
|
8229
|
+
}
|
|
8230
|
+
if (this.options.debug) {
|
|
8231
|
+
this.log("[Metadata] Handling hashtag", tag, { selector, config });
|
|
8232
|
+
}
|
|
8233
|
+
this.cacheMetadataAlertContent(element, config);
|
|
8234
|
+
if (config.title) {
|
|
8235
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
8236
|
+
const titleEl = element.querySelector(titleSelector);
|
|
8237
|
+
if (titleEl) {
|
|
8238
|
+
titleEl.textContent = config.title;
|
|
8239
|
+
}
|
|
8240
|
+
}
|
|
8241
|
+
if (config.message) {
|
|
8242
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
8243
|
+
const messageEl = element.querySelector(messageSelector);
|
|
8244
|
+
if (messageEl) {
|
|
8245
|
+
messageEl.textContent = config.message;
|
|
8246
|
+
}
|
|
8247
|
+
}
|
|
8248
|
+
const show = config.show !== false;
|
|
8249
|
+
const focus = config.focus !== void 0 ? config.focus : false;
|
|
8250
|
+
this.handleMetadataAlert(selector, {
|
|
8251
|
+
element,
|
|
8252
|
+
show,
|
|
8253
|
+
focus,
|
|
8254
|
+
autoScroll: config.autoScroll,
|
|
8255
|
+
reason: "hashtag"
|
|
8256
|
+
});
|
|
8257
|
+
});
|
|
8258
|
+
}
|
|
8259
|
+
/**
|
|
8260
|
+
* Handle individual metadata cues
|
|
8261
|
+
* Parses metadata text and emits events or triggers actions
|
|
8262
|
+
*/
|
|
8263
|
+
handleMetadataCue(cue) {
|
|
8264
|
+
const text = cue.text.trim();
|
|
8265
|
+
if (this.options.debug) {
|
|
8266
|
+
this.log("[Metadata] Processing cue:", {
|
|
8267
|
+
time: cue.startTime,
|
|
8268
|
+
text
|
|
8269
|
+
});
|
|
8270
|
+
}
|
|
8271
|
+
this.emit("metadata", {
|
|
8272
|
+
time: cue.startTime,
|
|
8273
|
+
endTime: cue.endTime,
|
|
8274
|
+
text,
|
|
8275
|
+
cue
|
|
8276
|
+
});
|
|
8277
|
+
if (text.includes("PAUSE")) {
|
|
8278
|
+
if (!this.state.paused) {
|
|
8279
|
+
if (this.options.debug) {
|
|
8280
|
+
this.log("[Metadata] Pausing video at", cue.startTime);
|
|
8281
|
+
}
|
|
8282
|
+
this.pause();
|
|
8283
|
+
}
|
|
8284
|
+
this.emit("metadata:pause", { time: cue.startTime, text });
|
|
8285
|
+
}
|
|
8286
|
+
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
8287
|
+
if (focusMatch) {
|
|
8288
|
+
const targetSelector = focusMatch[1];
|
|
8289
|
+
const normalizedSelector = this.normalizeMetadataSelector(targetSelector);
|
|
8290
|
+
const targetElement = normalizedSelector ? document.querySelector(normalizedSelector) : null;
|
|
8291
|
+
if (targetElement) {
|
|
8292
|
+
if (this.options.debug) {
|
|
8293
|
+
this.log("[Metadata] Focusing element:", normalizedSelector);
|
|
8294
|
+
}
|
|
8295
|
+
if (targetElement.tabIndex === -1 && !targetElement.hasAttribute("tabindex")) {
|
|
8296
|
+
targetElement.setAttribute("tabindex", "-1");
|
|
8297
|
+
}
|
|
8298
|
+
this.setManagedTimeout(() => {
|
|
8299
|
+
targetElement.focus();
|
|
8300
|
+
targetElement.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
8301
|
+
}, 10);
|
|
8302
|
+
} else if (this.options.debug) {
|
|
8303
|
+
this.log("[Metadata] Element not found:", normalizedSelector || targetSelector);
|
|
8304
|
+
}
|
|
8305
|
+
this.emit("metadata:focus", {
|
|
8306
|
+
time: cue.startTime,
|
|
8307
|
+
target: targetSelector,
|
|
8308
|
+
selector: normalizedSelector,
|
|
8309
|
+
element: targetElement,
|
|
8310
|
+
text
|
|
8311
|
+
});
|
|
8312
|
+
if (normalizedSelector) {
|
|
8313
|
+
this.handleMetadataAlert(normalizedSelector, {
|
|
8314
|
+
element: targetElement,
|
|
8315
|
+
reason: "focus"
|
|
8316
|
+
});
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
const hashtags = text.match(/#[\w-]+/g);
|
|
8320
|
+
if (hashtags) {
|
|
8321
|
+
if (this.options.debug) {
|
|
8322
|
+
this.log("[Metadata] Hashtags found:", hashtags);
|
|
8323
|
+
}
|
|
8324
|
+
this.emit("metadata:hashtags", {
|
|
8325
|
+
time: cue.startTime,
|
|
8326
|
+
hashtags,
|
|
8327
|
+
text
|
|
8328
|
+
});
|
|
8329
|
+
this.handleMetadataHashtags(hashtags);
|
|
8330
|
+
}
|
|
8331
|
+
}
|
|
7196
8332
|
};
|
|
7197
8333
|
Player.instances = [];
|
|
7198
8334
|
|