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.esm.js
CHANGED
|
@@ -497,10 +497,20 @@ var translations = {
|
|
|
497
497
|
settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
|
|
498
498
|
keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
|
|
499
499
|
keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
|
|
500
|
+
dragResizePrompt: "Press D to drag or R to resize. Use Home to reset position, Esc to close.",
|
|
501
|
+
dragModeEnabled: "Keyboard drag mode enabled. Use arrow keys to move, Shift+Arrow for larger steps. Press D or Esc to exit.",
|
|
502
|
+
dragModeDisabled: "Keyboard drag mode disabled.",
|
|
500
503
|
resizeWindow: "Resize Window",
|
|
504
|
+
disableResizeWindow: "Disable Resize Mode",
|
|
505
|
+
resizeModeHint: "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
|
|
506
|
+
resizeModeEnabled: "Resize mode enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
|
|
507
|
+
resizeModeDisabled: "Resize mode disabled.",
|
|
508
|
+
positionReset: "Transcript position reset.",
|
|
501
509
|
styleTranscript: "Open transcript style settings",
|
|
502
510
|
closeMenu: "Close Menu",
|
|
503
|
-
styleTitle: "Transcript Style"
|
|
511
|
+
styleTitle: "Transcript Style",
|
|
512
|
+
autoscroll: "Autoscroll",
|
|
513
|
+
settingsMenu: "Settings menu"
|
|
504
514
|
},
|
|
505
515
|
settings: {
|
|
506
516
|
title: "Settings",
|
|
@@ -618,10 +628,20 @@ var translations = {
|
|
|
618
628
|
settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
|
|
619
629
|
keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
|
|
620
630
|
keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
|
|
631
|
+
dragResizePrompt: "Dr\xFCcken Sie D zum Verschieben oder R zur Gr\xF6\xDFen\xE4nderung. Home setzt die Position zur\xFCck, Esc schlie\xDFt.",
|
|
632
|
+
dragModeEnabled: "Tastatur-Verschiebemodus aktiviert. Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gr\xF6\xDFere Schritte. D oder Esc zum Beenden.",
|
|
633
|
+
dragModeDisabled: "Tastatur-Verschiebemodus deaktiviert.",
|
|
621
634
|
resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
|
|
635
|
+
disableResizeWindow: "Resize-Modus deaktivieren",
|
|
636
|
+
resizeModeHint: "Griffe aktiviert. Ziehen Sie Kanten oder Ecken zum Anpassen. Esc oder R zum Beenden.",
|
|
637
|
+
resizeModeEnabled: "Resize-Modus aktiviert. Kanten oder Ecken ziehen; Esc oder R beendet.",
|
|
638
|
+
resizeModeDisabled: "Resize-Modus deaktiviert.",
|
|
639
|
+
positionReset: "Transkriptposition zur\xFCckgesetzt.",
|
|
622
640
|
styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
|
|
623
641
|
closeMenu: "Men\xFC schlie\xDFen",
|
|
624
|
-
styleTitle: "Transkript-Stil"
|
|
642
|
+
styleTitle: "Transkript-Stil",
|
|
643
|
+
autoscroll: "Automatisches Scrollen",
|
|
644
|
+
settingsMenu: "Einstellungsmen\xFC"
|
|
625
645
|
},
|
|
626
646
|
settings: {
|
|
627
647
|
title: "Einstellungen",
|
|
@@ -739,10 +759,20 @@ var translations = {
|
|
|
739
759
|
settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
|
|
740
760
|
keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
|
|
741
761
|
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)",
|
|
762
|
+
dragResizePrompt: "Pulsa D para mover o R para cambiar el tama\xF1o. Home restablece la posici\xF3n; Esc cierra.",
|
|
763
|
+
dragModeEnabled: "Modo de arrastre con teclado activado. Usa flechas para mover, May\xFAs+Flechas para pasos grandes. Pulsa D o Esc para salir.",
|
|
764
|
+
dragModeDisabled: "Modo de arrastre con teclado desactivado.",
|
|
742
765
|
resizeWindow: "Cambiar tama\xF1o de ventana",
|
|
766
|
+
disableResizeWindow: "Desactivar modo de cambio de tama\xF1o",
|
|
767
|
+
resizeModeHint: "Controladores habilitados. Arrastra bordes o esquinas para ajustar. Pulsa Esc o R para salir.",
|
|
768
|
+
resizeModeEnabled: "Modo de cambio de tama\xF1o activado. Arrastra bordes o esquinas. Pulsa Esc o R para salir.",
|
|
769
|
+
resizeModeDisabled: "Modo de cambio de tama\xF1o desactivado.",
|
|
770
|
+
positionReset: "Posici\xF3n de la transcripci\xF3n restablecida.",
|
|
743
771
|
styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
|
|
744
772
|
closeMenu: "Cerrar men\xFA",
|
|
745
|
-
styleTitle: "Estilo de Transcripci\xF3n"
|
|
773
|
+
styleTitle: "Estilo de Transcripci\xF3n",
|
|
774
|
+
autoscroll: "Desplazamiento autom\xE1tico",
|
|
775
|
+
settingsMenu: "Men\xFA de configuraci\xF3n"
|
|
746
776
|
},
|
|
747
777
|
settings: {
|
|
748
778
|
title: "Configuraci\xF3n",
|
|
@@ -860,10 +890,20 @@ var translations = {
|
|
|
860
890
|
settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
|
|
861
891
|
keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
|
|
862
892
|
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)",
|
|
893
|
+
dragResizePrompt: "Appuyez sur D pour d\xE9placer ou R pour redimensionner. Home r\xE9initialise la position, \xC9chap ferme.",
|
|
894
|
+
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.",
|
|
895
|
+
dragModeDisabled: "Mode glissement clavier d\xE9sactiv\xE9.",
|
|
863
896
|
resizeWindow: "Redimensionner la fen\xEAtre",
|
|
897
|
+
disableResizeWindow: "D\xE9sactiver le mode de redimensionnement",
|
|
898
|
+
resizeModeHint: "Poign\xE9es activ\xE9es. Faites glisser les bords ou les coins pour ajuster. Appuyez sur \xC9chap ou R pour quitter.",
|
|
899
|
+
resizeModeEnabled: "Mode redimensionnement activ\xE9. Faites glisser les bords ou coins. Appuyez sur \xC9chap ou R pour quitter.",
|
|
900
|
+
resizeModeDisabled: "Mode redimensionnement d\xE9sactiv\xE9.",
|
|
901
|
+
positionReset: "Position de la transcription r\xE9initialis\xE9e.",
|
|
864
902
|
styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
|
|
865
903
|
closeMenu: "Fermer le menu",
|
|
866
|
-
styleTitle: "Style de Transcription"
|
|
904
|
+
styleTitle: "Style de Transcription",
|
|
905
|
+
autoscroll: "D\xE9filement automatique",
|
|
906
|
+
settingsMenu: "Menu des param\xE8tres"
|
|
867
907
|
},
|
|
868
908
|
settings: {
|
|
869
909
|
title: "Param\xE8tres",
|
|
@@ -981,10 +1021,20 @@ var translations = {
|
|
|
981
1021
|
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",
|
|
982
1022
|
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",
|
|
983
1023
|
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",
|
|
1024
|
+
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",
|
|
1025
|
+
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",
|
|
1026
|
+
dragModeDisabled: "\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
|
|
984
1027
|
resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
|
|
1028
|
+
disableResizeWindow: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3059\u308B",
|
|
1029
|
+
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",
|
|
1030
|
+
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",
|
|
1031
|
+
resizeModeDisabled: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
|
|
1032
|
+
positionReset: "\u6587\u5B57\u8D77\u3053\u3057\u306E\u4F4D\u7F6E\u3092\u30EA\u30BB\u30C3\u30C8\u3057\u307E\u3057\u305F\u3002",
|
|
985
1033
|
styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
|
|
986
1034
|
closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
|
|
987
|
-
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB"
|
|
1035
|
+
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB",
|
|
1036
|
+
autoscroll: "\u81EA\u52D5\u30B9\u30AF\u30ED\u30FC\u30EB",
|
|
1037
|
+
settingsMenu: "\u8A2D\u5B9A\u30E1\u30CB\u30E5\u30FC"
|
|
988
1038
|
},
|
|
989
1039
|
settings: {
|
|
990
1040
|
title: "\u8A2D\u5B9A",
|
|
@@ -1163,8 +1213,8 @@ var iconPaths = {
|
|
|
1163
1213
|
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"/>`,
|
|
1164
1214
|
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"/>`,
|
|
1165
1215
|
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"/>`,
|
|
1166
|
-
audioDescription: `<rect x="2" y="5" width="20" height="14" rx="2" fill="
|
|
1167
|
-
audioDescriptionOn: `<rect x="2" y="5" width="20" height="14" rx="2" fill="
|
|
1216
|
+
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>`,
|
|
1217
|
+
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>`,
|
|
1168
1218
|
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>`,
|
|
1169
1219
|
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>`,
|
|
1170
1220
|
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"/>`,
|
|
@@ -1772,10 +1822,7 @@ var ControlBar = class {
|
|
|
1772
1822
|
}
|
|
1773
1823
|
});
|
|
1774
1824
|
this.controls.currentTimeDisplay = DOMUtils.createElement("span", {
|
|
1775
|
-
className: `${this.player.options.classPrefix}-current-time
|
|
1776
|
-
attributes: {
|
|
1777
|
-
"aria-label": i18n.t("time.seconds", { count: 0 })
|
|
1778
|
-
}
|
|
1825
|
+
className: `${this.player.options.classPrefix}-current-time`
|
|
1779
1826
|
});
|
|
1780
1827
|
const currentTimeVisual = DOMUtils.createElement("span", {
|
|
1781
1828
|
textContent: "00:00",
|
|
@@ -1783,8 +1830,14 @@ var ControlBar = class {
|
|
|
1783
1830
|
"aria-hidden": "true"
|
|
1784
1831
|
}
|
|
1785
1832
|
});
|
|
1833
|
+
const currentTimeAccessible = DOMUtils.createElement("span", {
|
|
1834
|
+
className: "vidply-sr-only",
|
|
1835
|
+
textContent: i18n.t("time.seconds", { count: 0 })
|
|
1836
|
+
});
|
|
1786
1837
|
this.controls.currentTimeDisplay.appendChild(currentTimeVisual);
|
|
1838
|
+
this.controls.currentTimeDisplay.appendChild(currentTimeAccessible);
|
|
1787
1839
|
this.controls.currentTimeVisual = currentTimeVisual;
|
|
1840
|
+
this.controls.currentTimeAccessible = currentTimeAccessible;
|
|
1788
1841
|
const separator = DOMUtils.createElement("span", {
|
|
1789
1842
|
textContent: " / ",
|
|
1790
1843
|
attributes: {
|
|
@@ -1792,10 +1845,7 @@ var ControlBar = class {
|
|
|
1792
1845
|
}
|
|
1793
1846
|
});
|
|
1794
1847
|
this.controls.durationDisplay = DOMUtils.createElement("span", {
|
|
1795
|
-
className: `${this.player.options.classPrefix}-duration
|
|
1796
|
-
attributes: {
|
|
1797
|
-
"aria-label": i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
|
|
1798
|
-
}
|
|
1848
|
+
className: `${this.player.options.classPrefix}-duration`
|
|
1799
1849
|
});
|
|
1800
1850
|
const durationVisual = DOMUtils.createElement("span", {
|
|
1801
1851
|
textContent: "00:00",
|
|
@@ -1803,8 +1853,14 @@ var ControlBar = class {
|
|
|
1803
1853
|
"aria-hidden": "true"
|
|
1804
1854
|
}
|
|
1805
1855
|
});
|
|
1856
|
+
const durationAccessible = DOMUtils.createElement("span", {
|
|
1857
|
+
className: "vidply-sr-only",
|
|
1858
|
+
textContent: i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
|
|
1859
|
+
});
|
|
1806
1860
|
this.controls.durationDisplay.appendChild(durationVisual);
|
|
1861
|
+
this.controls.durationDisplay.appendChild(durationAccessible);
|
|
1807
1862
|
this.controls.durationVisual = durationVisual;
|
|
1863
|
+
this.controls.durationAccessible = durationAccessible;
|
|
1808
1864
|
container.appendChild(this.controls.currentTimeDisplay);
|
|
1809
1865
|
container.appendChild(separator);
|
|
1810
1866
|
container.appendChild(this.controls.durationDisplay);
|
|
@@ -2631,14 +2687,18 @@ var ControlBar = class {
|
|
|
2631
2687
|
if (this.controls.currentTimeVisual) {
|
|
2632
2688
|
const currentTime = this.player.state.currentTime;
|
|
2633
2689
|
this.controls.currentTimeVisual.textContent = TimeUtils.formatTime(currentTime);
|
|
2634
|
-
this.controls.
|
|
2690
|
+
if (this.controls.currentTimeAccessible) {
|
|
2691
|
+
this.controls.currentTimeAccessible.textContent = TimeUtils.formatDuration(currentTime);
|
|
2692
|
+
}
|
|
2635
2693
|
}
|
|
2636
2694
|
}
|
|
2637
2695
|
updateDuration() {
|
|
2638
2696
|
if (this.controls.durationVisual) {
|
|
2639
2697
|
const duration = this.player.state.duration;
|
|
2640
2698
|
this.controls.durationVisual.textContent = TimeUtils.formatTime(duration);
|
|
2641
|
-
this.controls.
|
|
2699
|
+
if (this.controls.durationAccessible) {
|
|
2700
|
+
this.controls.durationAccessible.textContent = i18n.t("time.durationPrefix") + TimeUtils.formatDuration(duration);
|
|
2701
|
+
}
|
|
2642
2702
|
}
|
|
2643
2703
|
}
|
|
2644
2704
|
updateVolumeDisplay() {
|
|
@@ -3293,6 +3353,596 @@ var KeyboardManager = class {
|
|
|
3293
3353
|
}
|
|
3294
3354
|
};
|
|
3295
3355
|
|
|
3356
|
+
// src/utils/DraggableResizable.js
|
|
3357
|
+
var DraggableResizable = class {
|
|
3358
|
+
constructor(element, options = {}) {
|
|
3359
|
+
this.element = element;
|
|
3360
|
+
this.options = {
|
|
3361
|
+
dragHandle: null,
|
|
3362
|
+
// Element to use as drag handle (defaults to element itself)
|
|
3363
|
+
resizeHandles: [],
|
|
3364
|
+
// Array of resize handle elements
|
|
3365
|
+
onDragStart: null,
|
|
3366
|
+
onDrag: null,
|
|
3367
|
+
onDragEnd: null,
|
|
3368
|
+
onResizeStart: null,
|
|
3369
|
+
onResize: null,
|
|
3370
|
+
onResizeEnd: null,
|
|
3371
|
+
constrainToViewport: true,
|
|
3372
|
+
// Allow movement outside viewport?
|
|
3373
|
+
minWidth: 150,
|
|
3374
|
+
minHeight: 100,
|
|
3375
|
+
maintainAspectRatio: false,
|
|
3376
|
+
keyboardDragKey: "d",
|
|
3377
|
+
keyboardResizeKey: "r",
|
|
3378
|
+
keyboardStep: 5,
|
|
3379
|
+
keyboardStepLarge: 10,
|
|
3380
|
+
maxWidth: null,
|
|
3381
|
+
maxHeight: null,
|
|
3382
|
+
pointerResizeIndicatorText: null,
|
|
3383
|
+
onPointerResizeToggle: null,
|
|
3384
|
+
classPrefix: "draggable",
|
|
3385
|
+
storage: null,
|
|
3386
|
+
// StorageManager instance for saving position/size
|
|
3387
|
+
storageKey: null,
|
|
3388
|
+
// Key for localStorage (if storage is provided)
|
|
3389
|
+
...options
|
|
3390
|
+
};
|
|
3391
|
+
this.isDragging = false;
|
|
3392
|
+
this.isResizing = false;
|
|
3393
|
+
this.resizeDirection = null;
|
|
3394
|
+
this.dragOffsetX = 0;
|
|
3395
|
+
this.dragOffsetY = 0;
|
|
3396
|
+
this.positionOffsetX = 0;
|
|
3397
|
+
this.positionOffsetY = 0;
|
|
3398
|
+
this.initialMouseX = 0;
|
|
3399
|
+
this.initialMouseY = 0;
|
|
3400
|
+
this.needsPositionConversion = false;
|
|
3401
|
+
this.resizeStartX = 0;
|
|
3402
|
+
this.resizeStartY = 0;
|
|
3403
|
+
this.resizeStartWidth = 0;
|
|
3404
|
+
this.resizeStartHeight = 0;
|
|
3405
|
+
this.resizeStartLeft = 0;
|
|
3406
|
+
this.resizeStartTop = 0;
|
|
3407
|
+
this.keyboardDragMode = false;
|
|
3408
|
+
this.keyboardResizeMode = false;
|
|
3409
|
+
this.pointerResizeMode = false;
|
|
3410
|
+
this.manuallyPositioned = false;
|
|
3411
|
+
this.resizeHandlesManaged = /* @__PURE__ */ new Map();
|
|
3412
|
+
this.resizeIndicatorElement = null;
|
|
3413
|
+
this.handlers = {
|
|
3414
|
+
mousedown: this.onMouseDown.bind(this),
|
|
3415
|
+
mousemove: this.onMouseMove.bind(this),
|
|
3416
|
+
mouseup: this.onMouseUp.bind(this),
|
|
3417
|
+
touchstart: this.onTouchStart.bind(this),
|
|
3418
|
+
touchmove: this.onTouchMove.bind(this),
|
|
3419
|
+
touchend: this.onTouchEnd.bind(this),
|
|
3420
|
+
keydown: this.onKeyDown.bind(this),
|
|
3421
|
+
resizeHandleMousedown: this.onResizeHandleMouseDown.bind(this)
|
|
3422
|
+
};
|
|
3423
|
+
this.init();
|
|
3424
|
+
}
|
|
3425
|
+
hasManagedResizeHandles() {
|
|
3426
|
+
return Array.from(this.resizeHandlesManaged.values()).some(Boolean);
|
|
3427
|
+
}
|
|
3428
|
+
storeOriginalHandleDisplay(handle) {
|
|
3429
|
+
if (!handle.dataset.originalDisplay) {
|
|
3430
|
+
handle.dataset.originalDisplay = handle.style.display || "";
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
hideResizeHandle(handle) {
|
|
3434
|
+
handle.style.display = "none";
|
|
3435
|
+
handle.setAttribute("aria-hidden", "true");
|
|
3436
|
+
}
|
|
3437
|
+
showResizeHandle(handle) {
|
|
3438
|
+
const original = handle.dataset.originalDisplay !== void 0 ? handle.dataset.originalDisplay : "";
|
|
3439
|
+
handle.style.display = original;
|
|
3440
|
+
handle.removeAttribute("aria-hidden");
|
|
3441
|
+
}
|
|
3442
|
+
setManagedHandlesVisible(visible) {
|
|
3443
|
+
if (!this.options.resizeHandles || this.options.resizeHandles.length === 0) {
|
|
3444
|
+
return;
|
|
3445
|
+
}
|
|
3446
|
+
this.options.resizeHandles.forEach((handle) => {
|
|
3447
|
+
if (!this.resizeHandlesManaged.get(handle)) {
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
if (visible) {
|
|
3451
|
+
this.showResizeHandle(handle);
|
|
3452
|
+
} else {
|
|
3453
|
+
this.hideResizeHandle(handle);
|
|
3454
|
+
}
|
|
3455
|
+
});
|
|
3456
|
+
}
|
|
3457
|
+
init() {
|
|
3458
|
+
const dragHandle = this.options.dragHandle || this.element;
|
|
3459
|
+
dragHandle.addEventListener("mousedown", this.handlers.mousedown);
|
|
3460
|
+
dragHandle.addEventListener("touchstart", this.handlers.touchstart);
|
|
3461
|
+
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
3462
|
+
document.addEventListener("mouseup", this.handlers.mouseup);
|
|
3463
|
+
document.addEventListener("touchmove", this.handlers.touchmove, { passive: false });
|
|
3464
|
+
document.addEventListener("touchend", this.handlers.touchend);
|
|
3465
|
+
this.element.addEventListener("keydown", this.handlers.keydown);
|
|
3466
|
+
if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
|
|
3467
|
+
this.options.resizeHandles.forEach((handle) => {
|
|
3468
|
+
handle.addEventListener("mousedown", this.handlers.resizeHandleMousedown);
|
|
3469
|
+
handle.addEventListener("touchstart", this.handlers.resizeHandleMousedown);
|
|
3470
|
+
const managed = handle.dataset.vidplyManagedResize === "true";
|
|
3471
|
+
this.resizeHandlesManaged.set(handle, managed);
|
|
3472
|
+
if (managed) {
|
|
3473
|
+
this.storeOriginalHandleDisplay(handle);
|
|
3474
|
+
this.hideResizeHandle(handle);
|
|
3475
|
+
}
|
|
3476
|
+
});
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
onMouseDown(e) {
|
|
3480
|
+
if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
3483
|
+
if (this.options.onDragStart && !this.options.onDragStart(e)) {
|
|
3484
|
+
return;
|
|
3485
|
+
}
|
|
3486
|
+
this.startDragging(e.clientX, e.clientY);
|
|
3487
|
+
e.preventDefault();
|
|
3488
|
+
}
|
|
3489
|
+
onTouchStart(e) {
|
|
3490
|
+
if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
|
|
3491
|
+
return;
|
|
3492
|
+
}
|
|
3493
|
+
if (this.options.onDragStart && !this.options.onDragStart(e)) {
|
|
3494
|
+
return;
|
|
3495
|
+
}
|
|
3496
|
+
const touch = e.touches[0];
|
|
3497
|
+
this.startDragging(touch.clientX, touch.clientY);
|
|
3498
|
+
}
|
|
3499
|
+
onResizeHandleMouseDown(e) {
|
|
3500
|
+
var _a, _b, _c, _d;
|
|
3501
|
+
e.preventDefault();
|
|
3502
|
+
e.stopPropagation();
|
|
3503
|
+
const handle = e.target;
|
|
3504
|
+
this.resizeDirection = handle.getAttribute("data-direction");
|
|
3505
|
+
const clientX = e.clientX || ((_b = (_a = e.touches) == null ? void 0 : _a[0]) == null ? void 0 : _b.clientX);
|
|
3506
|
+
const clientY = e.clientY || ((_d = (_c = e.touches) == null ? void 0 : _c[0]) == null ? void 0 : _d.clientY);
|
|
3507
|
+
this.startResizing(clientX, clientY);
|
|
3508
|
+
}
|
|
3509
|
+
onMouseMove(e) {
|
|
3510
|
+
if (this.isDragging) {
|
|
3511
|
+
this.drag(e.clientX, e.clientY);
|
|
3512
|
+
e.preventDefault();
|
|
3513
|
+
} else if (this.isResizing) {
|
|
3514
|
+
this.resize(e.clientX, e.clientY);
|
|
3515
|
+
e.preventDefault();
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
onTouchMove(e) {
|
|
3519
|
+
if (this.isDragging || this.isResizing) {
|
|
3520
|
+
const touch = e.touches[0];
|
|
3521
|
+
if (this.isDragging) {
|
|
3522
|
+
this.drag(touch.clientX, touch.clientY);
|
|
3523
|
+
} else {
|
|
3524
|
+
this.resize(touch.clientX, touch.clientY);
|
|
3525
|
+
}
|
|
3526
|
+
e.preventDefault();
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
onMouseUp() {
|
|
3530
|
+
if (this.isDragging) {
|
|
3531
|
+
this.stopDragging();
|
|
3532
|
+
} else if (this.isResizing) {
|
|
3533
|
+
this.stopResizing();
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
onTouchEnd() {
|
|
3537
|
+
if (this.isDragging) {
|
|
3538
|
+
this.stopDragging();
|
|
3539
|
+
} else if (this.isResizing) {
|
|
3540
|
+
this.stopResizing();
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
onKeyDown(e) {
|
|
3544
|
+
if (e.key.toLowerCase() === this.options.keyboardDragKey.toLowerCase()) {
|
|
3545
|
+
e.preventDefault();
|
|
3546
|
+
this.toggleKeyboardDragMode();
|
|
3547
|
+
return;
|
|
3548
|
+
}
|
|
3549
|
+
if (e.key.toLowerCase() === this.options.keyboardResizeKey.toLowerCase()) {
|
|
3550
|
+
e.preventDefault();
|
|
3551
|
+
if (this.hasManagedResizeHandles()) {
|
|
3552
|
+
this.togglePointerResizeMode();
|
|
3553
|
+
} else {
|
|
3554
|
+
this.toggleKeyboardResizeMode();
|
|
3555
|
+
}
|
|
3556
|
+
return;
|
|
3557
|
+
}
|
|
3558
|
+
if (e.key === "Escape") {
|
|
3559
|
+
if (this.pointerResizeMode) {
|
|
3560
|
+
e.preventDefault();
|
|
3561
|
+
this.disablePointerResizeMode();
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3564
|
+
if (this.keyboardDragMode || this.keyboardResizeMode) {
|
|
3565
|
+
e.preventDefault();
|
|
3566
|
+
this.disableKeyboardDragMode();
|
|
3567
|
+
this.disableKeyboardResizeMode();
|
|
3568
|
+
return;
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3572
|
+
if (this.keyboardDragMode) {
|
|
3573
|
+
e.preventDefault();
|
|
3574
|
+
e.stopPropagation();
|
|
3575
|
+
this.keyboardDrag(e.key, e.shiftKey);
|
|
3576
|
+
} else if (this.keyboardResizeMode) {
|
|
3577
|
+
e.preventDefault();
|
|
3578
|
+
e.stopPropagation();
|
|
3579
|
+
this.keyboardResize(e.key, e.shiftKey);
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
if (e.key === "Home" && (this.keyboardDragMode || this.keyboardResizeMode)) {
|
|
3583
|
+
e.preventDefault();
|
|
3584
|
+
this.resetPosition();
|
|
3585
|
+
}
|
|
3586
|
+
}
|
|
3587
|
+
startDragging(clientX, clientY) {
|
|
3588
|
+
const rect = this.element.getBoundingClientRect();
|
|
3589
|
+
const computedStyle = window.getComputedStyle(this.element);
|
|
3590
|
+
const needsConversion = computedStyle.right !== "auto" || computedStyle.bottom !== "auto" || computedStyle.transform !== "none";
|
|
3591
|
+
this.positionOffsetX = 0;
|
|
3592
|
+
this.positionOffsetY = 0;
|
|
3593
|
+
if (needsConversion) {
|
|
3594
|
+
let targetLeft, targetTop;
|
|
3595
|
+
if (computedStyle.position === "absolute") {
|
|
3596
|
+
const offsetParent = this.element.offsetParent || document.body;
|
|
3597
|
+
const parentRect = offsetParent.getBoundingClientRect();
|
|
3598
|
+
targetLeft = rect.left - parentRect.left;
|
|
3599
|
+
targetTop = rect.top - parentRect.top;
|
|
3600
|
+
this.positionOffsetX = parentRect.left;
|
|
3601
|
+
this.positionOffsetY = parentRect.top;
|
|
3602
|
+
} else if (computedStyle.position === "fixed") {
|
|
3603
|
+
const parsedLeft = parseFloat(computedStyle.left);
|
|
3604
|
+
const parsedTop = parseFloat(computedStyle.top);
|
|
3605
|
+
const hasLeft = Number.isFinite(parsedLeft);
|
|
3606
|
+
const hasTop = Number.isFinite(parsedTop);
|
|
3607
|
+
targetLeft = hasLeft ? parsedLeft : rect.left;
|
|
3608
|
+
targetTop = hasTop ? parsedTop : rect.top;
|
|
3609
|
+
this.positionOffsetX = rect.left - targetLeft;
|
|
3610
|
+
this.positionOffsetY = rect.top - targetTop;
|
|
3611
|
+
} else {
|
|
3612
|
+
targetLeft = rect.left;
|
|
3613
|
+
targetTop = rect.top;
|
|
3614
|
+
this.positionOffsetX = rect.left - targetLeft;
|
|
3615
|
+
this.positionOffsetY = rect.top - targetTop;
|
|
3616
|
+
}
|
|
3617
|
+
const currentCssText = this.element.style.cssText;
|
|
3618
|
+
let newCssText = currentCssText.split(";").filter((rule) => {
|
|
3619
|
+
const trimmed = rule.trim();
|
|
3620
|
+
return trimmed && !trimmed.startsWith("right:") && !trimmed.startsWith("bottom:") && !trimmed.startsWith("transform:") && !trimmed.startsWith("left:") && !trimmed.startsWith("top:") && !trimmed.startsWith("inset:");
|
|
3621
|
+
}).join("; ");
|
|
3622
|
+
if (newCssText) newCssText += "; ";
|
|
3623
|
+
newCssText += `left: ${targetLeft}px; top: ${targetTop}px; right: auto; bottom: auto; transform: none`;
|
|
3624
|
+
this.element.style.cssText = newCssText;
|
|
3625
|
+
}
|
|
3626
|
+
const finalRect = this.element.getBoundingClientRect();
|
|
3627
|
+
this.dragOffsetX = clientX - finalRect.left;
|
|
3628
|
+
this.dragOffsetY = clientY - finalRect.top;
|
|
3629
|
+
this.isDragging = true;
|
|
3630
|
+
this.element.classList.add(`${this.options.classPrefix}-dragging`);
|
|
3631
|
+
document.body.style.cursor = "grabbing";
|
|
3632
|
+
document.body.style.userSelect = "none";
|
|
3633
|
+
}
|
|
3634
|
+
drag(clientX, clientY) {
|
|
3635
|
+
if (!this.isDragging) return;
|
|
3636
|
+
let newX = clientX - this.dragOffsetX - this.positionOffsetX;
|
|
3637
|
+
let newY = clientY - this.dragOffsetY - this.positionOffsetY;
|
|
3638
|
+
if (this.options.constrainToViewport) {
|
|
3639
|
+
const rect = this.element.getBoundingClientRect();
|
|
3640
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
3641
|
+
const viewportHeight = document.documentElement.clientHeight;
|
|
3642
|
+
const minVisible = 100;
|
|
3643
|
+
const minX = -(rect.width - minVisible);
|
|
3644
|
+
const minY = -(rect.height - minVisible);
|
|
3645
|
+
const maxX = viewportWidth - minVisible;
|
|
3646
|
+
const maxY = viewportHeight - minVisible;
|
|
3647
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
3648
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
3649
|
+
}
|
|
3650
|
+
this.element.style.left = `${newX}px`;
|
|
3651
|
+
this.element.style.top = `${newY}px`;
|
|
3652
|
+
if (this.options.onDrag) {
|
|
3653
|
+
this.options.onDrag({ x: newX, y: newY });
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
stopDragging() {
|
|
3657
|
+
this.isDragging = false;
|
|
3658
|
+
this.element.classList.remove(`${this.options.classPrefix}-dragging`);
|
|
3659
|
+
document.body.style.cursor = "";
|
|
3660
|
+
document.body.style.userSelect = "";
|
|
3661
|
+
this.manuallyPositioned = true;
|
|
3662
|
+
if (this.options.onDragEnd) {
|
|
3663
|
+
this.options.onDragEnd();
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
startResizing(clientX, clientY) {
|
|
3667
|
+
this.isResizing = true;
|
|
3668
|
+
this.resizeStartX = clientX;
|
|
3669
|
+
this.resizeStartY = clientY;
|
|
3670
|
+
const rect = this.element.getBoundingClientRect();
|
|
3671
|
+
this.resizeStartWidth = rect.width;
|
|
3672
|
+
this.resizeStartHeight = rect.height;
|
|
3673
|
+
this.resizeStartLeft = rect.left;
|
|
3674
|
+
this.resizeStartTop = rect.top;
|
|
3675
|
+
this.element.classList.add(`${this.options.classPrefix}-resizing`);
|
|
3676
|
+
document.body.style.userSelect = "none";
|
|
3677
|
+
if (this.options.onResizeStart) {
|
|
3678
|
+
this.options.onResizeStart();
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
resize(clientX, clientY) {
|
|
3682
|
+
if (!this.isResizing) return;
|
|
3683
|
+
const deltaX = clientX - this.resizeStartX;
|
|
3684
|
+
const deltaY = clientY - this.resizeStartY;
|
|
3685
|
+
let newWidth = this.resizeStartWidth;
|
|
3686
|
+
let newHeight = this.resizeStartHeight;
|
|
3687
|
+
let newLeft = this.resizeStartLeft;
|
|
3688
|
+
let newTop = this.resizeStartTop;
|
|
3689
|
+
if (this.resizeDirection.includes("e")) {
|
|
3690
|
+
newWidth = Math.max(this.options.minWidth, this.resizeStartWidth + deltaX);
|
|
3691
|
+
}
|
|
3692
|
+
if (this.resizeDirection.includes("w")) {
|
|
3693
|
+
const proposedWidth = Math.max(this.options.minWidth, this.resizeStartWidth - deltaX);
|
|
3694
|
+
newLeft = this.resizeStartLeft + (this.resizeStartWidth - proposedWidth);
|
|
3695
|
+
newWidth = proposedWidth;
|
|
3696
|
+
}
|
|
3697
|
+
const maxWidthOption = typeof this.options.maxWidth === "function" ? this.options.maxWidth() : this.options.maxWidth;
|
|
3698
|
+
if (Number.isFinite(maxWidthOption)) {
|
|
3699
|
+
const clampedWidth = Math.min(newWidth, maxWidthOption);
|
|
3700
|
+
if (clampedWidth !== newWidth && this.resizeDirection.includes("w")) {
|
|
3701
|
+
newLeft += newWidth - clampedWidth;
|
|
3702
|
+
}
|
|
3703
|
+
newWidth = clampedWidth;
|
|
3704
|
+
}
|
|
3705
|
+
if (!this.options.maintainAspectRatio) {
|
|
3706
|
+
if (this.resizeDirection.includes("s")) {
|
|
3707
|
+
newHeight = Math.max(this.options.minHeight, this.resizeStartHeight + deltaY);
|
|
3708
|
+
}
|
|
3709
|
+
if (this.resizeDirection.includes("n")) {
|
|
3710
|
+
const proposedHeight = Math.max(this.options.minHeight, this.resizeStartHeight - deltaY);
|
|
3711
|
+
newTop = this.resizeStartTop + (this.resizeStartHeight - proposedHeight);
|
|
3712
|
+
newHeight = proposedHeight;
|
|
3713
|
+
}
|
|
3714
|
+
const maxHeightOption = typeof this.options.maxHeight === "function" ? this.options.maxHeight() : this.options.maxHeight;
|
|
3715
|
+
if (Number.isFinite(maxHeightOption)) {
|
|
3716
|
+
const clampedHeight = Math.min(newHeight, maxHeightOption);
|
|
3717
|
+
if (clampedHeight !== newHeight && this.resizeDirection.includes("n")) {
|
|
3718
|
+
newTop += newHeight - clampedHeight;
|
|
3719
|
+
}
|
|
3720
|
+
newHeight = clampedHeight;
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
this.element.style.width = `${newWidth}px`;
|
|
3724
|
+
if (!this.options.maintainAspectRatio) {
|
|
3725
|
+
this.element.style.height = `${newHeight}px`;
|
|
3726
|
+
} else {
|
|
3727
|
+
this.element.style.height = "auto";
|
|
3728
|
+
}
|
|
3729
|
+
if (this.resizeDirection.includes("w")) {
|
|
3730
|
+
this.element.style.left = `${newLeft}px`;
|
|
3731
|
+
}
|
|
3732
|
+
if (this.resizeDirection.includes("n") && !this.options.maintainAspectRatio) {
|
|
3733
|
+
this.element.style.top = `${newTop}px`;
|
|
3734
|
+
}
|
|
3735
|
+
if (this.options.onResize) {
|
|
3736
|
+
this.options.onResize({ width: newWidth, height: newHeight, left: newLeft, top: newTop });
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
stopResizing() {
|
|
3740
|
+
this.isResizing = false;
|
|
3741
|
+
this.resizeDirection = null;
|
|
3742
|
+
this.element.classList.remove(`${this.options.classPrefix}-resizing`);
|
|
3743
|
+
document.body.style.userSelect = "";
|
|
3744
|
+
this.manuallyPositioned = true;
|
|
3745
|
+
if (this.options.onResizeEnd) {
|
|
3746
|
+
this.options.onResizeEnd();
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
toggleKeyboardDragMode() {
|
|
3750
|
+
if (this.keyboardDragMode) {
|
|
3751
|
+
this.disableKeyboardDragMode();
|
|
3752
|
+
} else {
|
|
3753
|
+
this.enableKeyboardDragMode();
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
enableKeyboardDragMode() {
|
|
3757
|
+
this.keyboardDragMode = true;
|
|
3758
|
+
this.keyboardResizeMode = false;
|
|
3759
|
+
this.element.classList.add(`${this.options.classPrefix}-keyboard-drag`);
|
|
3760
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
|
|
3761
|
+
this.focusElement();
|
|
3762
|
+
}
|
|
3763
|
+
disableKeyboardDragMode() {
|
|
3764
|
+
this.keyboardDragMode = false;
|
|
3765
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
|
|
3766
|
+
}
|
|
3767
|
+
toggleKeyboardResizeMode() {
|
|
3768
|
+
if (this.keyboardResizeMode) {
|
|
3769
|
+
this.disableKeyboardResizeMode();
|
|
3770
|
+
} else {
|
|
3771
|
+
this.enableKeyboardResizeMode();
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
enableKeyboardResizeMode() {
|
|
3775
|
+
this.keyboardResizeMode = true;
|
|
3776
|
+
this.keyboardDragMode = false;
|
|
3777
|
+
this.element.classList.add(`${this.options.classPrefix}-keyboard-resize`);
|
|
3778
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
|
|
3779
|
+
this.focusElement();
|
|
3780
|
+
}
|
|
3781
|
+
disableKeyboardResizeMode() {
|
|
3782
|
+
this.keyboardResizeMode = false;
|
|
3783
|
+
this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
|
|
3784
|
+
}
|
|
3785
|
+
enablePointerResizeMode({ focus = true } = {}) {
|
|
3786
|
+
if (!this.hasManagedResizeHandles()) {
|
|
3787
|
+
this.enableKeyboardResizeMode();
|
|
3788
|
+
return;
|
|
3789
|
+
}
|
|
3790
|
+
if (this.pointerResizeMode) {
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
this.pointerResizeMode = true;
|
|
3794
|
+
this.setManagedHandlesVisible(true);
|
|
3795
|
+
this.element.classList.add(`${this.options.classPrefix}-resizable`);
|
|
3796
|
+
this.enableKeyboardResizeMode();
|
|
3797
|
+
if (focus) {
|
|
3798
|
+
this.focusElement();
|
|
3799
|
+
}
|
|
3800
|
+
if (typeof this.options.onPointerResizeToggle === "function") {
|
|
3801
|
+
this.options.onPointerResizeToggle(true);
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
disablePointerResizeMode({ focus = false } = {}) {
|
|
3805
|
+
if (!this.pointerResizeMode) {
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3808
|
+
this.pointerResizeMode = false;
|
|
3809
|
+
this.setManagedHandlesVisible(false);
|
|
3810
|
+
this.element.classList.remove(`${this.options.classPrefix}-resizable`);
|
|
3811
|
+
this.disableKeyboardResizeMode();
|
|
3812
|
+
if (focus) {
|
|
3813
|
+
this.focusElement();
|
|
3814
|
+
}
|
|
3815
|
+
if (typeof this.options.onPointerResizeToggle === "function") {
|
|
3816
|
+
this.options.onPointerResizeToggle(false);
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
togglePointerResizeMode() {
|
|
3820
|
+
if (this.pointerResizeMode) {
|
|
3821
|
+
this.disablePointerResizeMode();
|
|
3822
|
+
} else {
|
|
3823
|
+
this.enablePointerResizeMode();
|
|
3824
|
+
}
|
|
3825
|
+
return this.pointerResizeMode;
|
|
3826
|
+
}
|
|
3827
|
+
focusElement() {
|
|
3828
|
+
if (typeof this.element.focus === "function") {
|
|
3829
|
+
try {
|
|
3830
|
+
this.element.focus({ preventScroll: true });
|
|
3831
|
+
} catch (e) {
|
|
3832
|
+
this.element.focus();
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3836
|
+
keyboardDrag(key, shiftKey) {
|
|
3837
|
+
const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
|
|
3838
|
+
let currentLeft = parseFloat(this.element.style.left) || 0;
|
|
3839
|
+
let currentTop = parseFloat(this.element.style.top) || 0;
|
|
3840
|
+
const computedStyle = window.getComputedStyle(this.element);
|
|
3841
|
+
if (computedStyle.transform !== "none") {
|
|
3842
|
+
const rect = this.element.getBoundingClientRect();
|
|
3843
|
+
currentLeft = rect.left;
|
|
3844
|
+
currentTop = rect.top;
|
|
3845
|
+
this.element.style.transform = "none";
|
|
3846
|
+
this.element.style.left = `${currentLeft}px`;
|
|
3847
|
+
this.element.style.top = `${currentTop}px`;
|
|
3848
|
+
}
|
|
3849
|
+
let newX = currentLeft;
|
|
3850
|
+
let newY = currentTop;
|
|
3851
|
+
switch (key) {
|
|
3852
|
+
case "ArrowLeft":
|
|
3853
|
+
newX -= step;
|
|
3854
|
+
break;
|
|
3855
|
+
case "ArrowRight":
|
|
3856
|
+
newX += step;
|
|
3857
|
+
break;
|
|
3858
|
+
case "ArrowUp":
|
|
3859
|
+
newY -= step;
|
|
3860
|
+
break;
|
|
3861
|
+
case "ArrowDown":
|
|
3862
|
+
newY += step;
|
|
3863
|
+
break;
|
|
3864
|
+
}
|
|
3865
|
+
this.element.style.left = `${newX}px`;
|
|
3866
|
+
this.element.style.top = `${newY}px`;
|
|
3867
|
+
if (this.options.onDrag) {
|
|
3868
|
+
this.options.onDrag({ x: newX, y: newY });
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
keyboardResize(key, shiftKey) {
|
|
3872
|
+
const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
|
|
3873
|
+
const rect = this.element.getBoundingClientRect();
|
|
3874
|
+
let width = rect.width;
|
|
3875
|
+
let height = rect.height;
|
|
3876
|
+
switch (key) {
|
|
3877
|
+
case "ArrowLeft":
|
|
3878
|
+
width -= step;
|
|
3879
|
+
break;
|
|
3880
|
+
case "ArrowRight":
|
|
3881
|
+
width += step;
|
|
3882
|
+
break;
|
|
3883
|
+
case "ArrowUp":
|
|
3884
|
+
if (this.options.maintainAspectRatio) {
|
|
3885
|
+
width += step;
|
|
3886
|
+
} else {
|
|
3887
|
+
height -= step;
|
|
3888
|
+
}
|
|
3889
|
+
break;
|
|
3890
|
+
case "ArrowDown":
|
|
3891
|
+
if (this.options.maintainAspectRatio) {
|
|
3892
|
+
width -= step;
|
|
3893
|
+
} else {
|
|
3894
|
+
height += step;
|
|
3895
|
+
}
|
|
3896
|
+
break;
|
|
3897
|
+
}
|
|
3898
|
+
width = Math.max(this.options.minWidth, width);
|
|
3899
|
+
height = Math.max(this.options.minHeight, height);
|
|
3900
|
+
this.element.style.width = `${width}px`;
|
|
3901
|
+
if (!this.options.maintainAspectRatio) {
|
|
3902
|
+
this.element.style.height = `${height}px`;
|
|
3903
|
+
} else {
|
|
3904
|
+
this.element.style.height = "auto";
|
|
3905
|
+
}
|
|
3906
|
+
if (this.options.onResize) {
|
|
3907
|
+
this.options.onResize({ width, height });
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
resetPosition() {
|
|
3911
|
+
this.element.style.left = "50%";
|
|
3912
|
+
this.element.style.top = "50%";
|
|
3913
|
+
this.element.style.transform = "translate(-50%, -50%)";
|
|
3914
|
+
this.element.style.right = "";
|
|
3915
|
+
this.element.style.bottom = "";
|
|
3916
|
+
this.manuallyPositioned = false;
|
|
3917
|
+
if (this.options.onDrag) {
|
|
3918
|
+
this.options.onDrag({ centered: true });
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
destroy() {
|
|
3922
|
+
const dragHandle = this.options.dragHandle || this.element;
|
|
3923
|
+
this.disablePointerResizeMode();
|
|
3924
|
+
dragHandle.removeEventListener("mousedown", this.handlers.mousedown);
|
|
3925
|
+
dragHandle.removeEventListener("touchstart", this.handlers.touchstart);
|
|
3926
|
+
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
3927
|
+
document.removeEventListener("mouseup", this.handlers.mouseup);
|
|
3928
|
+
document.removeEventListener("touchmove", this.handlers.touchmove);
|
|
3929
|
+
document.removeEventListener("touchend", this.handlers.touchend);
|
|
3930
|
+
this.element.removeEventListener("keydown", this.handlers.keydown);
|
|
3931
|
+
if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
|
|
3932
|
+
this.options.resizeHandles.forEach((handle) => {
|
|
3933
|
+
handle.removeEventListener("mousedown", this.handlers.resizeHandleMousedown);
|
|
3934
|
+
handle.removeEventListener("touchstart", this.handlers.resizeHandleMousedown);
|
|
3935
|
+
});
|
|
3936
|
+
}
|
|
3937
|
+
this.element.classList.remove(
|
|
3938
|
+
`${this.options.classPrefix}-dragging`,
|
|
3939
|
+
`${this.options.classPrefix}-resizing`,
|
|
3940
|
+
`${this.options.classPrefix}-keyboard-drag`,
|
|
3941
|
+
`${this.options.classPrefix}-keyboard-resize`
|
|
3942
|
+
);
|
|
3943
|
+
}
|
|
3944
|
+
};
|
|
3945
|
+
|
|
3296
3946
|
// src/controls/TranscriptManager.js
|
|
3297
3947
|
var TranscriptManager = class {
|
|
3298
3948
|
constructor(player) {
|
|
@@ -3303,25 +3953,26 @@ var TranscriptManager = class {
|
|
|
3303
3953
|
this.currentActiveEntry = null;
|
|
3304
3954
|
this.isVisible = false;
|
|
3305
3955
|
this.storage = new StorageManager("vidply");
|
|
3306
|
-
this.
|
|
3307
|
-
this.dragOffsetX = 0;
|
|
3308
|
-
this.dragOffsetY = 0;
|
|
3309
|
-
this.isResizing = false;
|
|
3310
|
-
this.resizeDirection = null;
|
|
3311
|
-
this.resizeStartX = 0;
|
|
3312
|
-
this.resizeStartY = 0;
|
|
3313
|
-
this.resizeStartWidth = 0;
|
|
3314
|
-
this.resizeStartHeight = 0;
|
|
3315
|
-
this.resizeEnabled = false;
|
|
3956
|
+
this.draggableResizable = null;
|
|
3316
3957
|
this.settingsMenuVisible = false;
|
|
3317
3958
|
this.settingsMenu = null;
|
|
3318
3959
|
this.settingsButton = null;
|
|
3319
3960
|
this.settingsMenuJustOpened = false;
|
|
3320
|
-
this.
|
|
3961
|
+
this.resizeOptionButton = null;
|
|
3962
|
+
this.resizeOptionText = null;
|
|
3963
|
+
this.resizeModeIndicator = null;
|
|
3964
|
+
this.resizeModeIndicatorTimeout = null;
|
|
3965
|
+
this.transcriptResizeHandles = [];
|
|
3966
|
+
this.liveRegion = null;
|
|
3321
3967
|
this.styleDialog = null;
|
|
3322
3968
|
this.styleDialogVisible = false;
|
|
3323
3969
|
this.styleDialogJustOpened = false;
|
|
3970
|
+
this.languageSelector = null;
|
|
3971
|
+
this.currentTranscriptLanguage = null;
|
|
3972
|
+
this.availableTranscriptLanguages = [];
|
|
3973
|
+
this.languageSelectorHandler = null;
|
|
3324
3974
|
const savedPreferences = this.storage.getTranscriptPreferences();
|
|
3975
|
+
this.autoscrollEnabled = (savedPreferences == null ? void 0 : savedPreferences.autoscroll) !== void 0 ? savedPreferences.autoscroll : true;
|
|
3325
3976
|
this.transcriptStyle = {
|
|
3326
3977
|
fontSize: (savedPreferences == null ? void 0 : savedPreferences.fontSize) || this.player.options.transcriptFontSize || "100%",
|
|
3327
3978
|
fontFamily: (savedPreferences == null ? void 0 : savedPreferences.fontFamily) || this.player.options.transcriptFontFamily || "sans-serif",
|
|
@@ -3332,25 +3983,22 @@ var TranscriptManager = class {
|
|
|
3332
3983
|
this.handlers = {
|
|
3333
3984
|
timeupdate: () => this.updateActiveEntry(),
|
|
3334
3985
|
resize: null,
|
|
3335
|
-
mousemove: null,
|
|
3336
|
-
mouseup: null,
|
|
3337
|
-
touchmove: null,
|
|
3338
|
-
touchend: null,
|
|
3339
|
-
mousedown: null,
|
|
3340
|
-
touchstart: null,
|
|
3341
|
-
keydown: null,
|
|
3342
3986
|
settingsClick: null,
|
|
3343
3987
|
settingsKeydown: null,
|
|
3344
3988
|
documentClick: null,
|
|
3345
3989
|
styleDialogKeydown: null
|
|
3346
3990
|
};
|
|
3991
|
+
this.timeouts = /* @__PURE__ */ new Set();
|
|
3347
3992
|
this.init();
|
|
3348
3993
|
}
|
|
3349
3994
|
init() {
|
|
3995
|
+
this.setupMetadataHandlingOnLoad();
|
|
3350
3996
|
this.player.on("timeupdate", this.handlers.timeupdate);
|
|
3351
3997
|
this.player.on("fullscreenchange", () => {
|
|
3352
3998
|
if (this.isVisible) {
|
|
3353
|
-
|
|
3999
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4000
|
+
this.setManagedTimeout(() => this.positionTranscript(), 100);
|
|
4001
|
+
}
|
|
3354
4002
|
}
|
|
3355
4003
|
});
|
|
3356
4004
|
}
|
|
@@ -3371,9 +4019,12 @@ var TranscriptManager = class {
|
|
|
3371
4019
|
if (this.transcriptWindow) {
|
|
3372
4020
|
this.transcriptWindow.style.display = "flex";
|
|
3373
4021
|
this.isVisible = true;
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
4022
|
+
if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
|
|
4023
|
+
this.player.controlBar.updateTranscriptButton();
|
|
4024
|
+
}
|
|
4025
|
+
this.setManagedTimeout(() => {
|
|
4026
|
+
if (this.transcriptHeader) {
|
|
4027
|
+
this.transcriptHeader.focus();
|
|
3377
4028
|
}
|
|
3378
4029
|
}, 150);
|
|
3379
4030
|
return;
|
|
@@ -3382,10 +4033,12 @@ var TranscriptManager = class {
|
|
|
3382
4033
|
this.loadTranscriptData();
|
|
3383
4034
|
if (this.transcriptWindow) {
|
|
3384
4035
|
this.transcriptWindow.style.display = "flex";
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
4036
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4037
|
+
this.setManagedTimeout(() => this.positionTranscript(), 0);
|
|
4038
|
+
}
|
|
4039
|
+
this.setManagedTimeout(() => {
|
|
4040
|
+
if (this.transcriptHeader) {
|
|
4041
|
+
this.transcriptHeader.focus();
|
|
3389
4042
|
}
|
|
3390
4043
|
}, 150);
|
|
3391
4044
|
}
|
|
@@ -3394,11 +4047,27 @@ var TranscriptManager = class {
|
|
|
3394
4047
|
/**
|
|
3395
4048
|
* Hide transcript window
|
|
3396
4049
|
*/
|
|
3397
|
-
hideTranscript() {
|
|
4050
|
+
hideTranscript({ focusButton = false } = {}) {
|
|
4051
|
+
var _a, _b;
|
|
3398
4052
|
if (this.transcriptWindow) {
|
|
3399
4053
|
this.transcriptWindow.style.display = "none";
|
|
3400
4054
|
this.isVisible = false;
|
|
3401
4055
|
}
|
|
4056
|
+
if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
|
|
4057
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
4058
|
+
this.updateResizeOptionState();
|
|
4059
|
+
}
|
|
4060
|
+
this.hideResizeModeIndicator();
|
|
4061
|
+
this.announceLive("");
|
|
4062
|
+
if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
|
|
4063
|
+
this.player.controlBar.updateTranscriptButton();
|
|
4064
|
+
}
|
|
4065
|
+
if (focusButton) {
|
|
4066
|
+
const transcriptButton = (_b = (_a = this.player.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.transcript;
|
|
4067
|
+
if (transcriptButton && typeof transcriptButton.focus === "function") {
|
|
4068
|
+
transcriptButton.focus();
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
3402
4071
|
}
|
|
3403
4072
|
/**
|
|
3404
4073
|
* Create the transcript window UI
|
|
@@ -3415,7 +4084,6 @@ var TranscriptManager = class {
|
|
|
3415
4084
|
this.transcriptHeader = DOMUtils.createElement("div", {
|
|
3416
4085
|
className: `${this.player.options.classPrefix}-transcript-header`,
|
|
3417
4086
|
attributes: {
|
|
3418
|
-
"aria-label": "Drag to reposition transcript. Use arrow keys to move, Home to reset position, Escape to close.",
|
|
3419
4087
|
"tabindex": "0"
|
|
3420
4088
|
}
|
|
3421
4089
|
});
|
|
@@ -3426,7 +4094,7 @@ var TranscriptManager = class {
|
|
|
3426
4094
|
className: `${this.player.options.classPrefix}-transcript-settings`,
|
|
3427
4095
|
attributes: {
|
|
3428
4096
|
"type": "button",
|
|
3429
|
-
"aria-label": i18n.t("transcript.
|
|
4097
|
+
"aria-label": i18n.t("transcript.settingsMenu"),
|
|
3430
4098
|
"aria-expanded": "false"
|
|
3431
4099
|
}
|
|
3432
4100
|
});
|
|
@@ -3458,10 +4126,43 @@ var TranscriptManager = class {
|
|
|
3458
4126
|
};
|
|
3459
4127
|
this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
|
|
3460
4128
|
const title = DOMUtils.createElement("h3", {
|
|
3461
|
-
textContent: i18n.t("transcript.title")
|
|
4129
|
+
textContent: `${i18n.t("transcript.title")}. ${i18n.t("transcript.dragResizePrompt")}`
|
|
4130
|
+
});
|
|
4131
|
+
const autoscrollLabel = DOMUtils.createElement("label", {
|
|
4132
|
+
className: `${this.player.options.classPrefix}-transcript-autoscroll-label`,
|
|
4133
|
+
attributes: {
|
|
4134
|
+
"title": i18n.t("transcript.autoscroll")
|
|
4135
|
+
}
|
|
3462
4136
|
});
|
|
4137
|
+
this.autoscrollCheckbox = DOMUtils.createElement("input", {
|
|
4138
|
+
attributes: {
|
|
4139
|
+
"type": "checkbox",
|
|
4140
|
+
"checked": this.autoscrollEnabled,
|
|
4141
|
+
"aria-label": i18n.t("transcript.autoscroll")
|
|
4142
|
+
}
|
|
4143
|
+
});
|
|
4144
|
+
const autoscrollText = DOMUtils.createElement("span", {
|
|
4145
|
+
textContent: i18n.t("transcript.autoscroll"),
|
|
4146
|
+
className: `${this.player.options.classPrefix}-transcript-autoscroll-text`
|
|
4147
|
+
});
|
|
4148
|
+
autoscrollLabel.appendChild(this.autoscrollCheckbox);
|
|
4149
|
+
autoscrollLabel.appendChild(autoscrollText);
|
|
4150
|
+
this.autoscrollCheckbox.addEventListener("change", (e) => {
|
|
4151
|
+
this.autoscrollEnabled = e.target.checked;
|
|
4152
|
+
this.saveAutoscrollPreference();
|
|
4153
|
+
});
|
|
4154
|
+
this.transcriptHeader.appendChild(title);
|
|
3463
4155
|
this.headerLeft.appendChild(this.settingsButton);
|
|
3464
|
-
this.headerLeft.appendChild(
|
|
4156
|
+
this.headerLeft.appendChild(autoscrollLabel);
|
|
4157
|
+
this.languageSelector = DOMUtils.createElement("select", {
|
|
4158
|
+
className: `${this.player.options.classPrefix}-transcript-language-select`,
|
|
4159
|
+
attributes: {
|
|
4160
|
+
"aria-label": i18n.t("settings.language") || "Language",
|
|
4161
|
+
"style": "display: none;"
|
|
4162
|
+
// Hidden until we detect multiple languages
|
|
4163
|
+
}
|
|
4164
|
+
});
|
|
4165
|
+
this.headerLeft.appendChild(this.languageSelector);
|
|
3465
4166
|
const closeButton = DOMUtils.createElement("button", {
|
|
3466
4167
|
className: `${this.player.options.classPrefix}-transcript-close`,
|
|
3467
4168
|
attributes: {
|
|
@@ -3470,7 +4171,7 @@ var TranscriptManager = class {
|
|
|
3470
4171
|
}
|
|
3471
4172
|
});
|
|
3472
4173
|
closeButton.appendChild(createIconElement("close"));
|
|
3473
|
-
closeButton.addEventListener("click", () => this.hideTranscript());
|
|
4174
|
+
closeButton.addEventListener("click", () => this.hideTranscript({ focusButton: true }));
|
|
3474
4175
|
this.transcriptHeader.appendChild(this.headerLeft);
|
|
3475
4176
|
this.transcriptHeader.appendChild(closeButton);
|
|
3476
4177
|
this.transcriptContent = DOMUtils.createElement("div", {
|
|
@@ -3478,9 +4179,20 @@ var TranscriptManager = class {
|
|
|
3478
4179
|
});
|
|
3479
4180
|
this.transcriptWindow.appendChild(this.transcriptHeader);
|
|
3480
4181
|
this.transcriptWindow.appendChild(this.transcriptContent);
|
|
4182
|
+
this.createResizeHandles();
|
|
4183
|
+
this.liveRegion = DOMUtils.createElement("div", {
|
|
4184
|
+
className: "vidply-sr-only",
|
|
4185
|
+
attributes: {
|
|
4186
|
+
"aria-live": "polite",
|
|
4187
|
+
"aria-atomic": "true"
|
|
4188
|
+
}
|
|
4189
|
+
});
|
|
4190
|
+
this.transcriptWindow.appendChild(this.liveRegion);
|
|
3481
4191
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3482
|
-
this.positionTranscript();
|
|
3483
4192
|
this.setupDragAndDrop();
|
|
4193
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4194
|
+
this.positionTranscript();
|
|
4195
|
+
}
|
|
3484
4196
|
this.handlers.documentClick = (e) => {
|
|
3485
4197
|
if (this.settingsMenuJustOpened) {
|
|
3486
4198
|
return;
|
|
@@ -3504,16 +4216,42 @@ var TranscriptManager = class {
|
|
|
3504
4216
|
this.documentClickHandlerAdded = false;
|
|
3505
4217
|
let resizeTimeout;
|
|
3506
4218
|
this.handlers.resize = () => {
|
|
3507
|
-
|
|
3508
|
-
|
|
4219
|
+
if (resizeTimeout) {
|
|
4220
|
+
this.clearManagedTimeout(resizeTimeout);
|
|
4221
|
+
}
|
|
4222
|
+
resizeTimeout = this.setManagedTimeout(() => {
|
|
4223
|
+
if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
|
|
4224
|
+
this.positionTranscript();
|
|
4225
|
+
}
|
|
4226
|
+
}, 100);
|
|
3509
4227
|
};
|
|
3510
4228
|
window.addEventListener("resize", this.handlers.resize);
|
|
3511
4229
|
}
|
|
4230
|
+
createResizeHandles() {
|
|
4231
|
+
if (!this.transcriptWindow) return;
|
|
4232
|
+
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4233
|
+
this.transcriptResizeHandles = directions.map((direction) => {
|
|
4234
|
+
const handle = DOMUtils.createElement("div", {
|
|
4235
|
+
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4236
|
+
attributes: {
|
|
4237
|
+
"data-direction": direction,
|
|
4238
|
+
"data-vidply-managed-resize": "true",
|
|
4239
|
+
"aria-hidden": "true"
|
|
4240
|
+
}
|
|
4241
|
+
});
|
|
4242
|
+
handle.style.display = "none";
|
|
4243
|
+
this.transcriptWindow.appendChild(handle);
|
|
4244
|
+
return handle;
|
|
4245
|
+
});
|
|
4246
|
+
}
|
|
3512
4247
|
/**
|
|
3513
4248
|
* Position transcript window next to video
|
|
3514
4249
|
*/
|
|
3515
4250
|
positionTranscript() {
|
|
3516
4251
|
if (!this.transcriptWindow || !this.player.videoWrapper || !this.isVisible) return;
|
|
4252
|
+
if (this.draggableResizable && this.draggableResizable.manuallyPositioned) {
|
|
4253
|
+
return;
|
|
4254
|
+
}
|
|
3517
4255
|
const isMobile = window.innerWidth < 640;
|
|
3518
4256
|
const videoRect = this.player.videoWrapper.getBoundingClientRect();
|
|
3519
4257
|
const isFullscreen = this.player.state.fullscreen;
|
|
@@ -3546,8 +4284,12 @@ var TranscriptManager = class {
|
|
|
3546
4284
|
this.transcriptWindow.style.top = "auto";
|
|
3547
4285
|
this.transcriptWindow.style.maxHeight = "calc(100vh - 180px)";
|
|
3548
4286
|
this.transcriptWindow.style.height = "auto";
|
|
3549
|
-
|
|
3550
|
-
|
|
4287
|
+
const fullscreenMinWidth = 260;
|
|
4288
|
+
const fullscreenAvailable = Math.max(fullscreenMinWidth, window.innerWidth - 40);
|
|
4289
|
+
const fullscreenDesired = parseFloat(this.transcriptWindow.style.width) || 400;
|
|
4290
|
+
const fullscreenWidth = Math.max(fullscreenMinWidth, Math.min(fullscreenDesired, fullscreenAvailable));
|
|
4291
|
+
this.transcriptWindow.style.width = `${fullscreenWidth}px`;
|
|
4292
|
+
this.transcriptWindow.style.maxWidth = "none";
|
|
3551
4293
|
this.transcriptWindow.style.borderRadius = "8px";
|
|
3552
4294
|
this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
|
|
3553
4295
|
this.transcriptWindow.style.borderTop = "";
|
|
@@ -3555,15 +4297,30 @@ var TranscriptManager = class {
|
|
|
3555
4297
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3556
4298
|
}
|
|
3557
4299
|
} else {
|
|
4300
|
+
const transcriptWidth = parseFloat(this.transcriptWindow.style.width) || 400;
|
|
4301
|
+
const padding = 20;
|
|
4302
|
+
const minWidth = 260;
|
|
4303
|
+
const containerRect = this.player.container.getBoundingClientRect();
|
|
4304
|
+
const ensureContainerPositioned = () => {
|
|
4305
|
+
const computed = window.getComputedStyle(this.player.container);
|
|
4306
|
+
if (computed.position === "static") {
|
|
4307
|
+
this.player.container.style.position = "relative";
|
|
4308
|
+
}
|
|
4309
|
+
};
|
|
4310
|
+
ensureContainerPositioned();
|
|
4311
|
+
const left = videoRect.right - containerRect.left + padding;
|
|
4312
|
+
const availableWidth = window.innerWidth - videoRect.right - padding;
|
|
4313
|
+
const appliedWidth = Math.max(minWidth, Math.min(transcriptWidth, availableWidth));
|
|
4314
|
+
const appliedHeight = videoRect.height;
|
|
3558
4315
|
this.transcriptWindow.style.position = "absolute";
|
|
3559
|
-
this.transcriptWindow.style.left = `${
|
|
4316
|
+
this.transcriptWindow.style.left = `${left}px`;
|
|
3560
4317
|
this.transcriptWindow.style.right = "auto";
|
|
3561
4318
|
this.transcriptWindow.style.bottom = "auto";
|
|
3562
4319
|
this.transcriptWindow.style.top = "0";
|
|
3563
|
-
this.transcriptWindow.style.height = `${
|
|
4320
|
+
this.transcriptWindow.style.height = `${appliedHeight}px`;
|
|
3564
4321
|
this.transcriptWindow.style.maxHeight = "none";
|
|
3565
|
-
this.transcriptWindow.style.width =
|
|
3566
|
-
this.transcriptWindow.style.maxWidth = "
|
|
4322
|
+
this.transcriptWindow.style.width = `${appliedWidth}px`;
|
|
4323
|
+
this.transcriptWindow.style.maxWidth = "none";
|
|
3567
4324
|
this.transcriptWindow.style.borderRadius = "8px";
|
|
3568
4325
|
this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
|
|
3569
4326
|
this.transcriptWindow.style.borderTop = "";
|
|
@@ -3575,17 +4332,94 @@ var TranscriptManager = class {
|
|
|
3575
4332
|
}
|
|
3576
4333
|
}
|
|
3577
4334
|
}
|
|
4335
|
+
/**
|
|
4336
|
+
* Get available transcript languages from tracks
|
|
4337
|
+
*/
|
|
4338
|
+
getAvailableTranscriptLanguages() {
|
|
4339
|
+
const textTracks = this.player.textTracks;
|
|
4340
|
+
const languages = /* @__PURE__ */ new Map();
|
|
4341
|
+
textTracks.forEach((track) => {
|
|
4342
|
+
if ((track.kind === "captions" || track.kind === "subtitles") && track.language) {
|
|
4343
|
+
if (!languages.has(track.language)) {
|
|
4344
|
+
languages.set(track.language, {
|
|
4345
|
+
language: track.language,
|
|
4346
|
+
label: track.label || track.language,
|
|
4347
|
+
track
|
|
4348
|
+
});
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
});
|
|
4352
|
+
return Array.from(languages.values());
|
|
4353
|
+
}
|
|
4354
|
+
/**
|
|
4355
|
+
* Update language selector dropdown
|
|
4356
|
+
*/
|
|
4357
|
+
updateLanguageSelector() {
|
|
4358
|
+
if (!this.languageSelector) return;
|
|
4359
|
+
this.availableTranscriptLanguages = this.getAvailableTranscriptLanguages();
|
|
4360
|
+
this.languageSelector.innerHTML = "";
|
|
4361
|
+
if (this.availableTranscriptLanguages.length < 2) {
|
|
4362
|
+
this.languageSelector.style.display = "none";
|
|
4363
|
+
return;
|
|
4364
|
+
}
|
|
4365
|
+
this.languageSelector.style.display = "block";
|
|
4366
|
+
this.availableTranscriptLanguages.forEach((langInfo, index) => {
|
|
4367
|
+
const option = DOMUtils.createElement("option", {
|
|
4368
|
+
textContent: langInfo.label,
|
|
4369
|
+
attributes: {
|
|
4370
|
+
"value": langInfo.language
|
|
4371
|
+
}
|
|
4372
|
+
});
|
|
4373
|
+
this.languageSelector.appendChild(option);
|
|
4374
|
+
});
|
|
4375
|
+
if (this.currentTranscriptLanguage) {
|
|
4376
|
+
this.languageSelector.value = this.currentTranscriptLanguage;
|
|
4377
|
+
} else if (this.availableTranscriptLanguages.length > 0) {
|
|
4378
|
+
const activeTrack = this.player.textTracks.find(
|
|
4379
|
+
(track) => (track.kind === "captions" || track.kind === "subtitles") && track.mode === "showing"
|
|
4380
|
+
);
|
|
4381
|
+
this.currentTranscriptLanguage = activeTrack ? activeTrack.language : this.availableTranscriptLanguages[0].language;
|
|
4382
|
+
this.languageSelector.value = this.currentTranscriptLanguage;
|
|
4383
|
+
}
|
|
4384
|
+
if (this.languageSelectorHandler) {
|
|
4385
|
+
this.languageSelector.removeEventListener("change", this.languageSelectorHandler);
|
|
4386
|
+
}
|
|
4387
|
+
this.languageSelectorHandler = (e) => {
|
|
4388
|
+
this.currentTranscriptLanguage = e.target.value;
|
|
4389
|
+
this.loadTranscriptData();
|
|
4390
|
+
};
|
|
4391
|
+
this.languageSelector.addEventListener("change", this.languageSelectorHandler);
|
|
4392
|
+
}
|
|
3578
4393
|
/**
|
|
3579
4394
|
* Load transcript data from caption/subtitle tracks
|
|
3580
4395
|
*/
|
|
3581
4396
|
loadTranscriptData() {
|
|
3582
4397
|
this.transcriptEntries = [];
|
|
3583
4398
|
this.transcriptContent.innerHTML = "";
|
|
3584
|
-
const textTracks =
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
4399
|
+
const textTracks = this.player.textTracks;
|
|
4400
|
+
let captionTrack = null;
|
|
4401
|
+
if (this.currentTranscriptLanguage) {
|
|
4402
|
+
captionTrack = textTracks.find(
|
|
4403
|
+
(track) => (track.kind === "captions" || track.kind === "subtitles") && track.language === this.currentTranscriptLanguage
|
|
4404
|
+
);
|
|
4405
|
+
}
|
|
4406
|
+
if (!captionTrack) {
|
|
4407
|
+
captionTrack = textTracks.find(
|
|
4408
|
+
(track) => track.kind === "captions" || track.kind === "subtitles"
|
|
4409
|
+
);
|
|
4410
|
+
if (captionTrack) {
|
|
4411
|
+
this.currentTranscriptLanguage = captionTrack.language;
|
|
4412
|
+
}
|
|
4413
|
+
}
|
|
4414
|
+
let descriptionTrack = null;
|
|
4415
|
+
if (this.currentTranscriptLanguage) {
|
|
4416
|
+
descriptionTrack = textTracks.find(
|
|
4417
|
+
(track) => track.kind === "descriptions" && track.language === this.currentTranscriptLanguage
|
|
4418
|
+
);
|
|
4419
|
+
}
|
|
4420
|
+
if (!descriptionTrack) {
|
|
4421
|
+
descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
4422
|
+
}
|
|
3589
4423
|
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3590
4424
|
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3591
4425
|
this.showNoTranscriptMessage();
|
|
@@ -3614,7 +4448,7 @@ var TranscriptManager = class {
|
|
|
3614
4448
|
tracksToLoad.forEach((track) => {
|
|
3615
4449
|
track.addEventListener("load", onLoad, { once: true });
|
|
3616
4450
|
});
|
|
3617
|
-
|
|
4451
|
+
this.setManagedTimeout(() => {
|
|
3618
4452
|
this.loadTranscriptData();
|
|
3619
4453
|
}, 500);
|
|
3620
4454
|
return;
|
|
@@ -3647,24 +4481,61 @@ var TranscriptManager = class {
|
|
|
3647
4481
|
this.transcriptContent.appendChild(entry);
|
|
3648
4482
|
});
|
|
3649
4483
|
this.applyTranscriptStyles();
|
|
4484
|
+
this.updateLanguageSelector();
|
|
4485
|
+
}
|
|
4486
|
+
/**
|
|
4487
|
+
* Setup metadata handling on player load
|
|
4488
|
+
* This runs independently of transcript loading
|
|
4489
|
+
*/
|
|
4490
|
+
setupMetadataHandlingOnLoad() {
|
|
4491
|
+
const setupMetadata = () => {
|
|
4492
|
+
const textTracks = this.player.textTracks;
|
|
4493
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
4494
|
+
if (metadataTrack) {
|
|
4495
|
+
if (metadataTrack.mode === "disabled") {
|
|
4496
|
+
metadataTrack.mode = "hidden";
|
|
4497
|
+
}
|
|
4498
|
+
if (this.metadataCueChangeHandler) {
|
|
4499
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
4500
|
+
}
|
|
4501
|
+
this.metadataCueChangeHandler = () => {
|
|
4502
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
4503
|
+
if (activeCues.length > 0) {
|
|
4504
|
+
if (this.player.options.debug) {
|
|
4505
|
+
console.log("[VidPly Metadata] Active cues:", activeCues.map((c) => ({
|
|
4506
|
+
start: c.startTime,
|
|
4507
|
+
end: c.endTime,
|
|
4508
|
+
text: c.text
|
|
4509
|
+
})));
|
|
4510
|
+
}
|
|
4511
|
+
}
|
|
4512
|
+
activeCues.forEach((cue) => {
|
|
4513
|
+
this.handleMetadataCue(cue);
|
|
4514
|
+
});
|
|
4515
|
+
};
|
|
4516
|
+
metadataTrack.addEventListener("cuechange", this.metadataCueChangeHandler);
|
|
4517
|
+
if (this.player.options.debug) {
|
|
4518
|
+
const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;
|
|
4519
|
+
console.log("[VidPly Metadata] Track enabled,", cueCount, "cues available");
|
|
4520
|
+
}
|
|
4521
|
+
} else if (this.player.options.debug) {
|
|
4522
|
+
console.warn("[VidPly Metadata] No metadata track found");
|
|
4523
|
+
}
|
|
4524
|
+
};
|
|
4525
|
+
setupMetadata();
|
|
4526
|
+
this.player.on("loadedmetadata", setupMetadata);
|
|
3650
4527
|
}
|
|
3651
4528
|
/**
|
|
3652
4529
|
* Setup metadata handling
|
|
3653
4530
|
* Metadata cues are not displayed but can be used programmatically
|
|
4531
|
+
* This is called when transcript data is loaded (for storing cues)
|
|
3654
4532
|
*/
|
|
3655
4533
|
setupMetadataHandling() {
|
|
3656
4534
|
if (!this.metadataCues || this.metadataCues.length === 0) {
|
|
3657
4535
|
return;
|
|
3658
4536
|
}
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
if (metadataTrack) {
|
|
3662
|
-
metadataTrack.addEventListener("cuechange", () => {
|
|
3663
|
-
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3664
|
-
activeCues.forEach((cue) => {
|
|
3665
|
-
this.handleMetadataCue(cue);
|
|
3666
|
-
});
|
|
3667
|
-
});
|
|
4537
|
+
if (this.player.options.debug) {
|
|
4538
|
+
console.log("[VidPly Metadata]", this.metadataCues.length, "cues stored from transcript load");
|
|
3668
4539
|
}
|
|
3669
4540
|
}
|
|
3670
4541
|
/**
|
|
@@ -3673,6 +4544,12 @@ var TranscriptManager = class {
|
|
|
3673
4544
|
*/
|
|
3674
4545
|
handleMetadataCue(cue) {
|
|
3675
4546
|
const text = cue.text.trim();
|
|
4547
|
+
if (this.player.options.debug) {
|
|
4548
|
+
console.log("[VidPly Metadata] Processing cue:", {
|
|
4549
|
+
time: cue.startTime,
|
|
4550
|
+
text
|
|
4551
|
+
});
|
|
4552
|
+
}
|
|
3676
4553
|
this.player.emit("metadata", {
|
|
3677
4554
|
time: cue.startTime,
|
|
3678
4555
|
endTime: cue.endTime,
|
|
@@ -3680,18 +4557,40 @@ var TranscriptManager = class {
|
|
|
3680
4557
|
cue
|
|
3681
4558
|
});
|
|
3682
4559
|
if (text.includes("PAUSE")) {
|
|
4560
|
+
if (!this.player.state.paused) {
|
|
4561
|
+
if (this.player.options.debug) {
|
|
4562
|
+
console.log("[VidPly Metadata] Pausing video at", cue.startTime);
|
|
4563
|
+
}
|
|
4564
|
+
this.player.pause();
|
|
4565
|
+
}
|
|
3683
4566
|
this.player.emit("metadata:pause", { time: cue.startTime, text });
|
|
3684
4567
|
}
|
|
3685
4568
|
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
3686
4569
|
if (focusMatch) {
|
|
4570
|
+
const targetSelector = focusMatch[1];
|
|
4571
|
+
const targetElement = document.querySelector(targetSelector);
|
|
4572
|
+
if (targetElement) {
|
|
4573
|
+
if (this.player.options.debug) {
|
|
4574
|
+
console.log("[VidPly Metadata] Focusing element:", targetSelector);
|
|
4575
|
+
}
|
|
4576
|
+
this.setManagedTimeout(() => {
|
|
4577
|
+
targetElement.focus();
|
|
4578
|
+
}, 10);
|
|
4579
|
+
} else if (this.player.options.debug) {
|
|
4580
|
+
console.warn("[VidPly Metadata] Element not found:", targetSelector);
|
|
4581
|
+
}
|
|
3687
4582
|
this.player.emit("metadata:focus", {
|
|
3688
4583
|
time: cue.startTime,
|
|
3689
|
-
target:
|
|
4584
|
+
target: targetSelector,
|
|
4585
|
+
element: targetElement,
|
|
3690
4586
|
text
|
|
3691
4587
|
});
|
|
3692
4588
|
}
|
|
3693
4589
|
const hashtags = text.match(/#[\w-]+/g);
|
|
3694
4590
|
if (hashtags) {
|
|
4591
|
+
if (this.player.options.debug) {
|
|
4592
|
+
console.log("[VidPly Metadata] Hashtags found:", hashtags);
|
|
4593
|
+
}
|
|
3695
4594
|
this.player.emit("metadata:hashtags", {
|
|
3696
4595
|
time: cue.startTime,
|
|
3697
4596
|
hashtags,
|
|
@@ -3785,7 +4684,7 @@ var TranscriptManager = class {
|
|
|
3785
4684
|
* Scroll transcript window to show active entry
|
|
3786
4685
|
*/
|
|
3787
4686
|
scrollToEntry(entryElement) {
|
|
3788
|
-
if (!this.transcriptContent) return;
|
|
4687
|
+
if (!this.transcriptContent || !this.autoscrollEnabled) return;
|
|
3789
4688
|
const contentRect = this.transcriptContent.getBoundingClientRect();
|
|
3790
4689
|
const entryRect = entryElement.getBoundingClientRect();
|
|
3791
4690
|
if (entryRect.top < contentRect.top || entryRect.bottom > contentRect.bottom) {
|
|
@@ -3796,256 +4695,121 @@ var TranscriptManager = class {
|
|
|
3796
4695
|
});
|
|
3797
4696
|
}
|
|
3798
4697
|
}
|
|
4698
|
+
/**
|
|
4699
|
+
* Save autoscroll preference to localStorage
|
|
4700
|
+
*/
|
|
4701
|
+
saveAutoscrollPreference() {
|
|
4702
|
+
const savedPreferences = this.storage.getTranscriptPreferences() || {};
|
|
4703
|
+
savedPreferences.autoscroll = this.autoscrollEnabled;
|
|
4704
|
+
this.storage.saveTranscriptPreferences(savedPreferences);
|
|
4705
|
+
}
|
|
3799
4706
|
/**
|
|
3800
4707
|
* Setup drag and drop functionality
|
|
3801
4708
|
*/
|
|
3802
4709
|
setupDragAndDrop() {
|
|
3803
4710
|
if (!this.transcriptHeader || !this.transcriptWindow) return;
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
}
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
}
|
|
3837
|
-
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3838
|
-
return;
|
|
3839
|
-
}
|
|
3840
|
-
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3841
|
-
return;
|
|
3842
|
-
}
|
|
3843
|
-
const isMobile = window.innerWidth < 640;
|
|
3844
|
-
const isFullscreen = this.player.state.fullscreen;
|
|
3845
|
-
const touch = e.touches[0];
|
|
3846
|
-
if (isMobile && !isFullscreen) {
|
|
3847
|
-
return;
|
|
3848
|
-
} else {
|
|
3849
|
-
this.startDragging(touch.clientX, touch.clientY);
|
|
3850
|
-
}
|
|
3851
|
-
};
|
|
3852
|
-
this.handlers.touchmove = (e) => {
|
|
3853
|
-
const isMobile = window.innerWidth < 640;
|
|
3854
|
-
const isFullscreen = this.player.state.fullscreen;
|
|
3855
|
-
if (isMobile && !isFullscreen) {
|
|
3856
|
-
return;
|
|
3857
|
-
} else if (this.isDragging) {
|
|
3858
|
-
const touch = e.touches[0];
|
|
3859
|
-
this.drag(touch.clientX, touch.clientY);
|
|
3860
|
-
e.preventDefault();
|
|
3861
|
-
}
|
|
3862
|
-
};
|
|
3863
|
-
this.handlers.touchend = () => {
|
|
3864
|
-
if (this.isDragging) {
|
|
3865
|
-
this.stopDragging();
|
|
3866
|
-
}
|
|
3867
|
-
};
|
|
3868
|
-
this.handlers.keydown = (e) => {
|
|
3869
|
-
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3870
|
-
if (!this.keyboardDragMode) {
|
|
3871
|
-
return;
|
|
4711
|
+
const isMobile = window.innerWidth < 640;
|
|
4712
|
+
const isFullscreen = this.player.state.fullscreen;
|
|
4713
|
+
if (isMobile && !isFullscreen) {
|
|
4714
|
+
return;
|
|
4715
|
+
}
|
|
4716
|
+
this.draggableResizable = new DraggableResizable(this.transcriptWindow, {
|
|
4717
|
+
dragHandle: this.transcriptHeader,
|
|
4718
|
+
resizeHandles: this.transcriptResizeHandles,
|
|
4719
|
+
constrainToViewport: true,
|
|
4720
|
+
classPrefix: `${this.player.options.classPrefix}-transcript`,
|
|
4721
|
+
keyboardDragKey: "d",
|
|
4722
|
+
keyboardResizeKey: "r",
|
|
4723
|
+
keyboardStep: 10,
|
|
4724
|
+
keyboardStepLarge: 50,
|
|
4725
|
+
minWidth: 300,
|
|
4726
|
+
minHeight: 200,
|
|
4727
|
+
maxWidth: () => Math.max(320, window.innerWidth - 40),
|
|
4728
|
+
maxHeight: () => Math.max(200, window.innerHeight - 120),
|
|
4729
|
+
pointerResizeIndicatorText: i18n.t("transcript.resizeModeHint"),
|
|
4730
|
+
onPointerResizeToggle: (enabled) => this.onPointerResizeModeChange(enabled),
|
|
4731
|
+
onDragStart: (e) => {
|
|
4732
|
+
const ignoreSelectors = [
|
|
4733
|
+
`.${this.player.options.classPrefix}-transcript-close`,
|
|
4734
|
+
`.${this.player.options.classPrefix}-transcript-settings`,
|
|
4735
|
+
`.${this.player.options.classPrefix}-transcript-language-select`,
|
|
4736
|
+
`.${this.player.options.classPrefix}-transcript-settings-menu`,
|
|
4737
|
+
`.${this.player.options.classPrefix}-transcript-style-dialog`
|
|
4738
|
+
];
|
|
4739
|
+
for (const selector of ignoreSelectors) {
|
|
4740
|
+
if (e.target.closest(selector)) {
|
|
4741
|
+
return false;
|
|
4742
|
+
}
|
|
3872
4743
|
}
|
|
4744
|
+
return true;
|
|
4745
|
+
}
|
|
4746
|
+
});
|
|
4747
|
+
this.customKeyHandler = (e) => {
|
|
4748
|
+
const key = e.key.toLowerCase();
|
|
4749
|
+
const alreadyPrevented = e.defaultPrevented;
|
|
4750
|
+
if (key === "home") {
|
|
3873
4751
|
e.preventDefault();
|
|
3874
4752
|
e.stopPropagation();
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
this.transcriptWindow.style.transform = "none";
|
|
3884
|
-
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3885
|
-
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3886
|
-
}
|
|
3887
|
-
let newX = currentLeft;
|
|
3888
|
-
let newY = currentTop;
|
|
3889
|
-
switch (e.key) {
|
|
3890
|
-
case "ArrowLeft":
|
|
3891
|
-
newX -= step;
|
|
3892
|
-
break;
|
|
3893
|
-
case "ArrowRight":
|
|
3894
|
-
newX += step;
|
|
3895
|
-
break;
|
|
3896
|
-
case "ArrowUp":
|
|
3897
|
-
newY -= step;
|
|
3898
|
-
break;
|
|
3899
|
-
case "ArrowDown":
|
|
3900
|
-
newY += step;
|
|
3901
|
-
break;
|
|
4753
|
+
if (this.draggableResizable) {
|
|
4754
|
+
if (this.draggableResizable.pointerResizeMode) {
|
|
4755
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
4756
|
+
}
|
|
4757
|
+
this.draggableResizable.manuallyPositioned = false;
|
|
4758
|
+
this.positionTranscript();
|
|
4759
|
+
this.updateResizeOptionState();
|
|
4760
|
+
this.announceLive(i18n.t("transcript.positionReset"));
|
|
3902
4761
|
}
|
|
3903
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3904
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3905
4762
|
return;
|
|
3906
4763
|
}
|
|
3907
|
-
if (
|
|
4764
|
+
if (key === "r") {
|
|
4765
|
+
if (alreadyPrevented) {
|
|
4766
|
+
return;
|
|
4767
|
+
}
|
|
3908
4768
|
e.preventDefault();
|
|
3909
4769
|
e.stopPropagation();
|
|
3910
|
-
this.
|
|
4770
|
+
const enabled = this.toggleResizeMode();
|
|
4771
|
+
if (enabled) {
|
|
4772
|
+
this.transcriptWindow.focus();
|
|
4773
|
+
}
|
|
3911
4774
|
return;
|
|
3912
4775
|
}
|
|
3913
|
-
if (
|
|
4776
|
+
if (key === "escape") {
|
|
3914
4777
|
e.preventDefault();
|
|
3915
4778
|
e.stopPropagation();
|
|
4779
|
+
if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
|
|
4780
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
4781
|
+
return;
|
|
4782
|
+
}
|
|
3916
4783
|
if (this.styleDialogVisible) {
|
|
3917
4784
|
this.hideStyleDialog();
|
|
3918
|
-
} else if (this.keyboardDragMode) {
|
|
3919
|
-
this.disableKeyboardDragMode();
|
|
4785
|
+
} else if (this.draggableResizable && this.draggableResizable.keyboardDragMode) {
|
|
4786
|
+
this.draggableResizable.disableKeyboardDragMode();
|
|
4787
|
+
this.announceLive(i18n.t("transcript.dragModeDisabled"));
|
|
3920
4788
|
} else if (this.settingsMenuVisible) {
|
|
3921
4789
|
this.hideSettingsMenu();
|
|
3922
4790
|
} else {
|
|
3923
|
-
this.hideTranscript();
|
|
4791
|
+
this.hideTranscript({ focusButton: true });
|
|
3924
4792
|
}
|
|
3925
4793
|
return;
|
|
3926
4794
|
}
|
|
3927
4795
|
};
|
|
3928
|
-
this.
|
|
3929
|
-
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
3930
|
-
document.addEventListener("mouseup", this.handlers.mouseup);
|
|
3931
|
-
this.transcriptHeader.addEventListener("touchstart", this.handlers.touchstart);
|
|
3932
|
-
document.addEventListener("touchmove", this.handlers.touchmove);
|
|
3933
|
-
document.addEventListener("touchend", this.handlers.touchend);
|
|
3934
|
-
this.transcriptHeader.addEventListener("keydown", this.handlers.keydown);
|
|
3935
|
-
}
|
|
3936
|
-
/**
|
|
3937
|
-
* Start dragging
|
|
3938
|
-
*/
|
|
3939
|
-
startDragging(clientX, clientY) {
|
|
3940
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3941
|
-
const containerRect = this.player.container.getBoundingClientRect();
|
|
3942
|
-
const relativeLeft = rect.left - containerRect.left;
|
|
3943
|
-
const relativeTop = rect.top - containerRect.top;
|
|
3944
|
-
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3945
|
-
if (computedStyle.transform !== "none") {
|
|
3946
|
-
this.transcriptWindow.style.transform = "none";
|
|
3947
|
-
this.transcriptWindow.style.left = `${relativeLeft}px`;
|
|
3948
|
-
this.transcriptWindow.style.top = `${relativeTop}px`;
|
|
3949
|
-
}
|
|
3950
|
-
this.dragOffsetX = clientX - rect.left;
|
|
3951
|
-
this.dragOffsetY = clientY - rect.top;
|
|
3952
|
-
this.isDragging = true;
|
|
3953
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-dragging`);
|
|
3954
|
-
document.body.style.cursor = "grabbing";
|
|
3955
|
-
document.body.style.userSelect = "none";
|
|
3956
|
-
}
|
|
3957
|
-
/**
|
|
3958
|
-
* Perform drag
|
|
3959
|
-
*/
|
|
3960
|
-
drag(clientX, clientY) {
|
|
3961
|
-
if (!this.isDragging) return;
|
|
3962
|
-
const newViewportX = clientX - this.dragOffsetX;
|
|
3963
|
-
const newViewportY = clientY - this.dragOffsetY;
|
|
3964
|
-
const containerRect = this.player.container.getBoundingClientRect();
|
|
3965
|
-
const newX = newViewportX - containerRect.left;
|
|
3966
|
-
const newY = newViewportY - containerRect.top;
|
|
3967
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3968
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3969
|
-
}
|
|
3970
|
-
/**
|
|
3971
|
-
* Stop dragging
|
|
3972
|
-
*/
|
|
3973
|
-
stopDragging() {
|
|
3974
|
-
this.isDragging = false;
|
|
3975
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-dragging`);
|
|
3976
|
-
document.body.style.cursor = "";
|
|
3977
|
-
document.body.style.userSelect = "";
|
|
3978
|
-
}
|
|
3979
|
-
/**
|
|
3980
|
-
* Set window position with boundary constraints
|
|
3981
|
-
*/
|
|
3982
|
-
setPosition(x, y) {
|
|
3983
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3984
|
-
const viewportWidth = document.documentElement.clientWidth;
|
|
3985
|
-
const viewportHeight = document.documentElement.clientHeight;
|
|
3986
|
-
const minVisible = 100;
|
|
3987
|
-
const minX = -(rect.width - minVisible);
|
|
3988
|
-
const minY = -(rect.height - minVisible);
|
|
3989
|
-
const maxX = viewportWidth - minVisible;
|
|
3990
|
-
const maxY = viewportHeight - minVisible;
|
|
3991
|
-
x = Math.max(minX, Math.min(x, maxX));
|
|
3992
|
-
y = Math.max(minY, Math.min(y, maxY));
|
|
3993
|
-
this.transcriptWindow.style.left = `${x}px`;
|
|
3994
|
-
this.transcriptWindow.style.top = `${y}px`;
|
|
3995
|
-
this.transcriptWindow.style.transform = "none";
|
|
3996
|
-
}
|
|
3997
|
-
/**
|
|
3998
|
-
* Reset position to center
|
|
3999
|
-
*/
|
|
4000
|
-
resetPosition() {
|
|
4001
|
-
this.transcriptWindow.style.left = "50%";
|
|
4002
|
-
this.transcriptWindow.style.top = "50%";
|
|
4003
|
-
this.transcriptWindow.style.transform = "translate(-50%, -50%)";
|
|
4796
|
+
this.transcriptWindow.addEventListener("keydown", this.customKeyHandler);
|
|
4004
4797
|
}
|
|
4005
4798
|
/**
|
|
4006
4799
|
* Toggle keyboard drag mode
|
|
4007
4800
|
*/
|
|
4008
4801
|
toggleKeyboardDragMode() {
|
|
4009
|
-
if (this.
|
|
4010
|
-
this.
|
|
4011
|
-
|
|
4012
|
-
this.
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4021
|
-
if (this.settingsButton) {
|
|
4022
|
-
this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
|
|
4023
|
-
}
|
|
4024
|
-
const indicator = DOMUtils.createElement("div", {
|
|
4025
|
-
className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
|
|
4026
|
-
textContent: i18n.t("transcript.keyboardDragActive")
|
|
4027
|
-
});
|
|
4028
|
-
this.transcriptHeader.appendChild(indicator);
|
|
4029
|
-
if (this.settingsMenuVisible) {
|
|
4030
|
-
this.hideSettingsMenu();
|
|
4031
|
-
}
|
|
4032
|
-
this.transcriptHeader.focus();
|
|
4033
|
-
}
|
|
4034
|
-
/**
|
|
4035
|
-
* Disable keyboard drag mode
|
|
4036
|
-
*/
|
|
4037
|
-
disableKeyboardDragMode() {
|
|
4038
|
-
this.keyboardDragMode = false;
|
|
4039
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4040
|
-
if (this.settingsButton) {
|
|
4041
|
-
this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
|
|
4042
|
-
}
|
|
4043
|
-
const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
|
|
4044
|
-
if (indicator) {
|
|
4045
|
-
indicator.remove();
|
|
4046
|
-
}
|
|
4047
|
-
if (this.settingsButton) {
|
|
4048
|
-
this.settingsButton.focus();
|
|
4802
|
+
if (this.draggableResizable) {
|
|
4803
|
+
const wasEnabled = this.draggableResizable.keyboardDragMode;
|
|
4804
|
+
this.draggableResizable.toggleKeyboardDragMode();
|
|
4805
|
+
const isEnabled = this.draggableResizable.keyboardDragMode;
|
|
4806
|
+
if (!wasEnabled && isEnabled) {
|
|
4807
|
+
this.enableMoveMode();
|
|
4808
|
+
}
|
|
4809
|
+
if (this.settingsMenuVisible) {
|
|
4810
|
+
this.hideSettingsMenu();
|
|
4811
|
+
}
|
|
4812
|
+
this.transcriptWindow.focus();
|
|
4049
4813
|
}
|
|
4050
4814
|
}
|
|
4051
4815
|
/**
|
|
@@ -4075,6 +4839,16 @@ var TranscriptManager = class {
|
|
|
4075
4839
|
if (this.settingsMenu) {
|
|
4076
4840
|
this.settingsMenu.style.display = "block";
|
|
4077
4841
|
this.settingsMenuVisible = true;
|
|
4842
|
+
if (this.settingsButton) {
|
|
4843
|
+
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4844
|
+
}
|
|
4845
|
+
this.updateResizeOptionState();
|
|
4846
|
+
setTimeout(() => {
|
|
4847
|
+
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4848
|
+
if (firstItem) {
|
|
4849
|
+
firstItem.focus();
|
|
4850
|
+
}
|
|
4851
|
+
}, 0);
|
|
4078
4852
|
return;
|
|
4079
4853
|
}
|
|
4080
4854
|
this.settingsMenu = DOMUtils.createElement("div", {
|
|
@@ -4122,19 +4896,35 @@ var TranscriptManager = class {
|
|
|
4122
4896
|
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4123
4897
|
attributes: {
|
|
4124
4898
|
"type": "button",
|
|
4125
|
-
"aria-label": i18n.t("transcript.resizeWindow")
|
|
4899
|
+
"aria-label": i18n.t("transcript.resizeWindow"),
|
|
4900
|
+
"aria-pressed": "false"
|
|
4126
4901
|
}
|
|
4127
4902
|
});
|
|
4128
4903
|
const resizeIcon = createIconElement("resize");
|
|
4129
4904
|
const resizeText = DOMUtils.createElement("span", {
|
|
4905
|
+
className: `${this.player.options.classPrefix}-transcript-settings-text`,
|
|
4130
4906
|
textContent: i18n.t("transcript.resizeWindow")
|
|
4131
4907
|
});
|
|
4132
4908
|
resizeOption.appendChild(resizeIcon);
|
|
4133
4909
|
resizeOption.appendChild(resizeText);
|
|
4134
|
-
resizeOption.addEventListener("click", () => {
|
|
4135
|
-
|
|
4136
|
-
|
|
4910
|
+
resizeOption.addEventListener("click", (event) => {
|
|
4911
|
+
event.preventDefault();
|
|
4912
|
+
event.stopPropagation();
|
|
4913
|
+
const enabled = this.toggleResizeMode({ focus: false });
|
|
4914
|
+
if (enabled) {
|
|
4915
|
+
this.hideSettingsMenu({ focusButton: false });
|
|
4916
|
+
this.setManagedTimeout(() => {
|
|
4917
|
+
if (this.transcriptWindow) {
|
|
4918
|
+
this.transcriptWindow.focus();
|
|
4919
|
+
}
|
|
4920
|
+
}, 20);
|
|
4921
|
+
} else {
|
|
4922
|
+
this.hideSettingsMenu({ focusButton: true });
|
|
4923
|
+
}
|
|
4137
4924
|
});
|
|
4925
|
+
this.resizeOptionButton = resizeOption;
|
|
4926
|
+
this.resizeOptionText = resizeText;
|
|
4927
|
+
this.updateResizeOptionState();
|
|
4138
4928
|
const closeOption = DOMUtils.createElement("button", {
|
|
4139
4929
|
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4140
4930
|
attributes: {
|
|
@@ -4165,6 +4955,7 @@ var TranscriptManager = class {
|
|
|
4165
4955
|
if (this.settingsButton) {
|
|
4166
4956
|
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4167
4957
|
}
|
|
4958
|
+
this.updateResizeOptionState();
|
|
4168
4959
|
setTimeout(() => {
|
|
4169
4960
|
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4170
4961
|
if (firstItem) {
|
|
@@ -4175,14 +4966,16 @@ var TranscriptManager = class {
|
|
|
4175
4966
|
/**
|
|
4176
4967
|
* Hide settings menu
|
|
4177
4968
|
*/
|
|
4178
|
-
hideSettingsMenu() {
|
|
4969
|
+
hideSettingsMenu({ focusButton = true } = {}) {
|
|
4179
4970
|
if (this.settingsMenu) {
|
|
4180
4971
|
this.settingsMenu.style.display = "none";
|
|
4181
4972
|
this.settingsMenuVisible = false;
|
|
4182
4973
|
this.settingsMenuJustOpened = false;
|
|
4183
4974
|
if (this.settingsButton) {
|
|
4184
4975
|
this.settingsButton.setAttribute("aria-expanded", "false");
|
|
4185
|
-
|
|
4976
|
+
if (focusButton) {
|
|
4977
|
+
this.settingsButton.focus();
|
|
4978
|
+
}
|
|
4186
4979
|
}
|
|
4187
4980
|
}
|
|
4188
4981
|
}
|
|
@@ -4190,6 +4983,7 @@ var TranscriptManager = class {
|
|
|
4190
4983
|
* Enable move mode (gives visual feedback)
|
|
4191
4984
|
*/
|
|
4192
4985
|
enableMoveMode() {
|
|
4986
|
+
this.hideResizeModeIndicator();
|
|
4193
4987
|
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4194
4988
|
const tooltip = DOMUtils.createElement("div", {
|
|
4195
4989
|
className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
|
|
@@ -4206,155 +5000,64 @@ var TranscriptManager = class {
|
|
|
4206
5000
|
/**
|
|
4207
5001
|
* Toggle resize mode
|
|
4208
5002
|
*/
|
|
4209
|
-
toggleResizeMode() {
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
this.enableResizeHandles();
|
|
4213
|
-
} else {
|
|
4214
|
-
this.disableResizeHandles();
|
|
5003
|
+
toggleResizeMode({ focus = true } = {}) {
|
|
5004
|
+
if (!this.draggableResizable) {
|
|
5005
|
+
return false;
|
|
4215
5006
|
}
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
*/
|
|
4220
|
-
enableResizeHandles() {
|
|
4221
|
-
if (!this.transcriptWindow) return;
|
|
4222
|
-
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4223
|
-
directions.forEach((direction) => {
|
|
4224
|
-
const handle = DOMUtils.createElement("div", {
|
|
4225
|
-
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4226
|
-
attributes: {
|
|
4227
|
-
"data-direction": direction
|
|
4228
|
-
}
|
|
4229
|
-
});
|
|
4230
|
-
handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
|
|
4231
|
-
handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
|
|
4232
|
-
this.transcriptWindow.appendChild(handle);
|
|
4233
|
-
});
|
|
4234
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4235
|
-
this.handlers.resizeMove = (e) => {
|
|
4236
|
-
if (this.isResizing) {
|
|
4237
|
-
this.performResize(e.clientX, e.clientY);
|
|
4238
|
-
}
|
|
4239
|
-
};
|
|
4240
|
-
this.handlers.resizeEnd = () => {
|
|
4241
|
-
if (this.isResizing) {
|
|
4242
|
-
this.stopResize();
|
|
4243
|
-
}
|
|
4244
|
-
};
|
|
4245
|
-
this.handlers.resizeTouchMove = (e) => {
|
|
4246
|
-
if (this.isResizing) {
|
|
4247
|
-
this.performResize(e.touches[0].clientX, e.touches[0].clientY);
|
|
4248
|
-
e.preventDefault();
|
|
4249
|
-
}
|
|
4250
|
-
};
|
|
4251
|
-
document.addEventListener("mousemove", this.handlers.resizeMove);
|
|
4252
|
-
document.addEventListener("mouseup", this.handlers.resizeEnd);
|
|
4253
|
-
document.addEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4254
|
-
document.addEventListener("touchend", this.handlers.resizeEnd);
|
|
4255
|
-
}
|
|
4256
|
-
/**
|
|
4257
|
-
* Disable resize handles
|
|
4258
|
-
*/
|
|
4259
|
-
disableResizeHandles() {
|
|
4260
|
-
if (!this.transcriptWindow) return;
|
|
4261
|
-
const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
|
|
4262
|
-
handles.forEach((handle) => handle.remove());
|
|
4263
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4264
|
-
if (this.handlers.resizeMove) {
|
|
4265
|
-
document.removeEventListener("mousemove", this.handlers.resizeMove);
|
|
5007
|
+
if (this.draggableResizable.pointerResizeMode) {
|
|
5008
|
+
this.draggableResizable.disablePointerResizeMode({ focus });
|
|
5009
|
+
return false;
|
|
4266
5010
|
}
|
|
4267
|
-
|
|
4268
|
-
|
|
5011
|
+
this.draggableResizable.enablePointerResizeMode({ focus });
|
|
5012
|
+
return true;
|
|
5013
|
+
}
|
|
5014
|
+
updateResizeOptionState() {
|
|
5015
|
+
if (!this.resizeOptionButton) {
|
|
5016
|
+
return;
|
|
4269
5017
|
}
|
|
4270
|
-
|
|
4271
|
-
|
|
5018
|
+
const isEnabled = !!(this.draggableResizable && this.draggableResizable.pointerResizeMode);
|
|
5019
|
+
const label = isEnabled ? i18n.t("transcript.disableResizeWindow") || "Disable Resize Mode" : i18n.t("transcript.resizeWindow");
|
|
5020
|
+
this.resizeOptionButton.setAttribute("aria-pressed", isEnabled ? "true" : "false");
|
|
5021
|
+
this.resizeOptionButton.setAttribute("aria-label", label);
|
|
5022
|
+
this.resizeOptionButton.setAttribute("title", label);
|
|
5023
|
+
if (this.resizeOptionText) {
|
|
5024
|
+
this.resizeOptionText.textContent = label;
|
|
4272
5025
|
}
|
|
4273
|
-
document.removeEventListener("touchend", this.handlers.resizeEnd);
|
|
4274
|
-
}
|
|
4275
|
-
/**
|
|
4276
|
-
* Start resizing
|
|
4277
|
-
*/
|
|
4278
|
-
startResize(e, direction) {
|
|
4279
|
-
e.stopPropagation();
|
|
4280
|
-
e.preventDefault();
|
|
4281
|
-
this.isResizing = true;
|
|
4282
|
-
this.resizeDirection = direction;
|
|
4283
|
-
this.resizeStartX = e.clientX;
|
|
4284
|
-
this.resizeStartY = e.clientY;
|
|
4285
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
4286
|
-
this.resizeStartWidth = rect.width;
|
|
4287
|
-
this.resizeStartHeight = rect.height;
|
|
4288
|
-
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4289
|
-
document.body.style.cursor = this.getResizeCursor(direction);
|
|
4290
|
-
document.body.style.userSelect = "none";
|
|
4291
5026
|
}
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
const
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
if (
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
4326
|
-
this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
|
|
4327
|
-
}
|
|
4328
|
-
if (direction.includes("n")) {
|
|
4329
|
-
const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
4330
|
-
this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
|
|
5027
|
+
showResizeModeIndicator() {
|
|
5028
|
+
if (!this.transcriptHeader) {
|
|
5029
|
+
return;
|
|
5030
|
+
}
|
|
5031
|
+
this.hideResizeModeIndicator();
|
|
5032
|
+
const indicator = DOMUtils.createElement("div", {
|
|
5033
|
+
className: `${this.player.options.classPrefix}-transcript-resize-tooltip`,
|
|
5034
|
+
textContent: i18n.t("transcript.resizeModeHint") || "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit."
|
|
5035
|
+
});
|
|
5036
|
+
this.transcriptHeader.appendChild(indicator);
|
|
5037
|
+
this.resizeModeIndicator = indicator;
|
|
5038
|
+
this.resizeModeIndicatorTimeout = this.setManagedTimeout(() => {
|
|
5039
|
+
this.hideResizeModeIndicator();
|
|
5040
|
+
}, 3e3);
|
|
5041
|
+
}
|
|
5042
|
+
hideResizeModeIndicator() {
|
|
5043
|
+
if (this.resizeModeIndicatorTimeout) {
|
|
5044
|
+
this.clearManagedTimeout(this.resizeModeIndicatorTimeout);
|
|
5045
|
+
this.resizeModeIndicatorTimeout = null;
|
|
5046
|
+
}
|
|
5047
|
+
if (this.resizeModeIndicator && this.resizeModeIndicator.parentNode) {
|
|
5048
|
+
this.resizeModeIndicator.remove();
|
|
5049
|
+
}
|
|
5050
|
+
this.resizeModeIndicator = null;
|
|
5051
|
+
}
|
|
5052
|
+
onPointerResizeModeChange(enabled) {
|
|
5053
|
+
this.updateResizeOptionState();
|
|
5054
|
+
if (enabled) {
|
|
5055
|
+
this.showResizeModeIndicator();
|
|
5056
|
+
this.announceLive(i18n.t("transcript.resizeModeEnabled"));
|
|
5057
|
+
} else {
|
|
5058
|
+
this.hideResizeModeIndicator();
|
|
5059
|
+
this.announceLive(i18n.t("transcript.resizeModeDisabled"));
|
|
4331
5060
|
}
|
|
4332
|
-
}
|
|
4333
|
-
/**
|
|
4334
|
-
* Stop resizing
|
|
4335
|
-
*/
|
|
4336
|
-
stopResize() {
|
|
4337
|
-
this.isResizing = false;
|
|
4338
|
-
this.resizeDirection = null;
|
|
4339
|
-
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4340
|
-
document.body.style.cursor = "";
|
|
4341
|
-
document.body.style.userSelect = "";
|
|
4342
|
-
}
|
|
4343
|
-
/**
|
|
4344
|
-
* Get cursor style for resize direction
|
|
4345
|
-
*/
|
|
4346
|
-
getResizeCursor(direction) {
|
|
4347
|
-
const cursors = {
|
|
4348
|
-
"n": "ns-resize",
|
|
4349
|
-
"s": "ns-resize",
|
|
4350
|
-
"e": "ew-resize",
|
|
4351
|
-
"w": "ew-resize",
|
|
4352
|
-
"ne": "nesw-resize",
|
|
4353
|
-
"nw": "nwse-resize",
|
|
4354
|
-
"se": "nwse-resize",
|
|
4355
|
-
"sw": "nesw-resize"
|
|
4356
|
-
};
|
|
4357
|
-
return cursors[direction] || "default";
|
|
4358
5061
|
}
|
|
4359
5062
|
/**
|
|
4360
5063
|
* Show style dialog
|
|
@@ -4588,30 +5291,50 @@ var TranscriptManager = class {
|
|
|
4588
5291
|
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4589
5292
|
});
|
|
4590
5293
|
}
|
|
5294
|
+
/**
|
|
5295
|
+
* Set a managed timeout that will be cleaned up on destroy
|
|
5296
|
+
* @param {Function} callback - Callback function
|
|
5297
|
+
* @param {number} delay - Delay in milliseconds
|
|
5298
|
+
* @returns {number} Timeout ID
|
|
5299
|
+
*/
|
|
5300
|
+
setManagedTimeout(callback, delay) {
|
|
5301
|
+
const timeoutId = setTimeout(() => {
|
|
5302
|
+
this.timeouts.delete(timeoutId);
|
|
5303
|
+
callback();
|
|
5304
|
+
}, delay);
|
|
5305
|
+
this.timeouts.add(timeoutId);
|
|
5306
|
+
return timeoutId;
|
|
5307
|
+
}
|
|
5308
|
+
/**
|
|
5309
|
+
* Clear a managed timeout
|
|
5310
|
+
* @param {number} timeoutId - Timeout ID to clear
|
|
5311
|
+
*/
|
|
5312
|
+
clearManagedTimeout(timeoutId) {
|
|
5313
|
+
if (timeoutId) {
|
|
5314
|
+
clearTimeout(timeoutId);
|
|
5315
|
+
this.timeouts.delete(timeoutId);
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
4591
5318
|
/**
|
|
4592
5319
|
* Cleanup
|
|
4593
5320
|
*/
|
|
4594
5321
|
destroy() {
|
|
4595
|
-
|
|
4596
|
-
|
|
5322
|
+
this.hideResizeModeIndicator();
|
|
5323
|
+
if (this.draggableResizable) {
|
|
5324
|
+
if (this.draggableResizable.pointerResizeMode) {
|
|
5325
|
+
this.draggableResizable.disablePointerResizeMode();
|
|
5326
|
+
this.updateResizeOptionState();
|
|
5327
|
+
}
|
|
5328
|
+
this.draggableResizable.destroy();
|
|
5329
|
+
this.draggableResizable = null;
|
|
4597
5330
|
}
|
|
4598
|
-
if (this.
|
|
4599
|
-
this.
|
|
5331
|
+
if (this.transcriptWindow && this.customKeyHandler) {
|
|
5332
|
+
this.transcriptWindow.removeEventListener("keydown", this.customKeyHandler);
|
|
5333
|
+
this.customKeyHandler = null;
|
|
4600
5334
|
}
|
|
4601
5335
|
if (this.handlers.timeupdate) {
|
|
4602
5336
|
this.player.off("timeupdate", this.handlers.timeupdate);
|
|
4603
5337
|
}
|
|
4604
|
-
if (this.transcriptHeader) {
|
|
4605
|
-
if (this.handlers.mousedown) {
|
|
4606
|
-
this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
|
|
4607
|
-
}
|
|
4608
|
-
if (this.handlers.touchstart) {
|
|
4609
|
-
this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
|
|
4610
|
-
}
|
|
4611
|
-
if (this.handlers.keydown) {
|
|
4612
|
-
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
4613
|
-
}
|
|
4614
|
-
}
|
|
4615
5338
|
if (this.settingsButton) {
|
|
4616
5339
|
if (this.handlers.settingsClick) {
|
|
4617
5340
|
this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
|
|
@@ -4623,24 +5346,14 @@ var TranscriptManager = class {
|
|
|
4623
5346
|
if (this.styleDialog && this.handlers.styleDialogKeydown) {
|
|
4624
5347
|
this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4625
5348
|
}
|
|
4626
|
-
if (this.handlers.mousemove) {
|
|
4627
|
-
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
4628
|
-
}
|
|
4629
|
-
if (this.handlers.mouseup) {
|
|
4630
|
-
document.removeEventListener("mouseup", this.handlers.mouseup);
|
|
4631
|
-
}
|
|
4632
|
-
if (this.handlers.touchmove) {
|
|
4633
|
-
document.removeEventListener("touchmove", this.handlers.touchmove);
|
|
4634
|
-
}
|
|
4635
|
-
if (this.handlers.touchend) {
|
|
4636
|
-
document.removeEventListener("touchend", this.handlers.touchend);
|
|
4637
|
-
}
|
|
4638
5349
|
if (this.handlers.documentClick) {
|
|
4639
5350
|
document.removeEventListener("click", this.handlers.documentClick);
|
|
4640
5351
|
}
|
|
4641
5352
|
if (this.handlers.resize) {
|
|
4642
5353
|
window.removeEventListener("resize", this.handlers.resize);
|
|
4643
5354
|
}
|
|
5355
|
+
this.timeouts.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
5356
|
+
this.timeouts.clear();
|
|
4644
5357
|
this.handlers = null;
|
|
4645
5358
|
if (this.transcriptWindow && this.transcriptWindow.parentNode) {
|
|
4646
5359
|
this.transcriptWindow.parentNode.removeChild(this.transcriptWindow);
|
|
@@ -4651,6 +5364,14 @@ var TranscriptManager = class {
|
|
|
4651
5364
|
this.transcriptEntries = [];
|
|
4652
5365
|
this.settingsMenu = null;
|
|
4653
5366
|
this.styleDialog = null;
|
|
5367
|
+
this.transcriptResizeHandles = [];
|
|
5368
|
+
this.resizeOptionButton = null;
|
|
5369
|
+
this.resizeOptionText = null;
|
|
5370
|
+
this.liveRegion = null;
|
|
5371
|
+
}
|
|
5372
|
+
announceLive(message) {
|
|
5373
|
+
if (!this.liveRegion) return;
|
|
5374
|
+
this.liveRegion.textContent = message || "";
|
|
4654
5375
|
}
|
|
4655
5376
|
};
|
|
4656
5377
|
|
|
@@ -5312,7 +6033,7 @@ var HLSRenderer = class {
|
|
|
5312
6033
|
};
|
|
5313
6034
|
|
|
5314
6035
|
// src/core/Player.js
|
|
5315
|
-
var Player = class extends EventEmitter {
|
|
6036
|
+
var Player = class _Player extends EventEmitter {
|
|
5316
6037
|
constructor(element, options = {}) {
|
|
5317
6038
|
super();
|
|
5318
6039
|
this.element = typeof element === "string" ? document.querySelector(element) : element;
|
|
@@ -5420,6 +6141,8 @@ var Player = class extends EventEmitter {
|
|
|
5420
6141
|
screenReaderAnnouncements: true,
|
|
5421
6142
|
highContrast: false,
|
|
5422
6143
|
focusHighlight: true,
|
|
6144
|
+
metadataAlerts: {},
|
|
6145
|
+
metadataHashtags: {},
|
|
5423
6146
|
// Languages
|
|
5424
6147
|
language: "en",
|
|
5425
6148
|
languages: ["en"],
|
|
@@ -5438,6 +6161,8 @@ var Player = class extends EventEmitter {
|
|
|
5438
6161
|
onError: null,
|
|
5439
6162
|
...options
|
|
5440
6163
|
};
|
|
6164
|
+
this.options.metadataAlerts = this.options.metadataAlerts || {};
|
|
6165
|
+
this.options.metadataHashtags = this.options.metadataHashtags || {};
|
|
5441
6166
|
this.storage = new StorageManager("vidply");
|
|
5442
6167
|
const savedPrefs = this.storage.getPlayerPreferences();
|
|
5443
6168
|
if (savedPrefs) {
|
|
@@ -5472,12 +6197,22 @@ var Player = class extends EventEmitter {
|
|
|
5472
6197
|
this.audioDescriptionSourceElement = null;
|
|
5473
6198
|
this.originalAudioDescriptionSource = null;
|
|
5474
6199
|
this.audioDescriptionCaptionTracks = [];
|
|
6200
|
+
this._audioDescriptionDesiredState = false;
|
|
6201
|
+
this._textTracksCache = null;
|
|
6202
|
+
this._textTracksDirty = true;
|
|
6203
|
+
this._sourceElementsCache = null;
|
|
6204
|
+
this._sourceElementsDirty = true;
|
|
6205
|
+
this._trackElementsCache = null;
|
|
6206
|
+
this._trackElementsDirty = true;
|
|
6207
|
+
this.timeouts = /* @__PURE__ */ new Set();
|
|
5475
6208
|
this.container = null;
|
|
5476
6209
|
this.renderer = null;
|
|
5477
6210
|
this.controlBar = null;
|
|
5478
6211
|
this.captionManager = null;
|
|
5479
6212
|
this.keyboardManager = null;
|
|
5480
6213
|
this.settingsDialog = null;
|
|
6214
|
+
this.metadataCueChangeHandler = null;
|
|
6215
|
+
this.metadataAlertHandlers = /* @__PURE__ */ new Map();
|
|
5481
6216
|
this.init();
|
|
5482
6217
|
}
|
|
5483
6218
|
async init() {
|
|
@@ -5509,6 +6244,7 @@ var Player = class extends EventEmitter {
|
|
|
5509
6244
|
if (this.options.transcript || this.options.transcriptButton) {
|
|
5510
6245
|
this.transcriptManager = new TranscriptManager(this);
|
|
5511
6246
|
}
|
|
6247
|
+
this.setupMetadataHandling();
|
|
5512
6248
|
if (this.options.keyboard) {
|
|
5513
6249
|
this.keyboardManager = new KeyboardManager(this);
|
|
5514
6250
|
}
|
|
@@ -5579,7 +6315,6 @@ var Player = class extends EventEmitter {
|
|
|
5579
6315
|
this.element.style.height = "100%";
|
|
5580
6316
|
if (this.element.tagName === "VIDEO" && this.options.playsInline) {
|
|
5581
6317
|
this.element.setAttribute("playsinline", "");
|
|
5582
|
-
this.element.setAttribute("webkit-playsinline", "");
|
|
5583
6318
|
this.element.playsInline = true;
|
|
5584
6319
|
}
|
|
5585
6320
|
if (this.options.width) {
|
|
@@ -5594,12 +6329,22 @@ var Player = class extends EventEmitter {
|
|
|
5594
6329
|
if (this.element.tagName === "VIDEO") {
|
|
5595
6330
|
this.createPlayButtonOverlay();
|
|
5596
6331
|
}
|
|
6332
|
+
this.element.vidply = this;
|
|
6333
|
+
_Player.instances.push(this);
|
|
5597
6334
|
this.element.style.cursor = "pointer";
|
|
5598
6335
|
this.element.addEventListener("click", (e) => {
|
|
5599
6336
|
if (e.target === this.element) {
|
|
5600
6337
|
this.toggle();
|
|
5601
6338
|
}
|
|
5602
6339
|
});
|
|
6340
|
+
this.on("play", () => {
|
|
6341
|
+
this.hidePosterOverlay();
|
|
6342
|
+
});
|
|
6343
|
+
this.on("timeupdate", () => {
|
|
6344
|
+
if (this.state.currentTime > 0) {
|
|
6345
|
+
this.hidePosterOverlay();
|
|
6346
|
+
}
|
|
6347
|
+
});
|
|
5603
6348
|
}
|
|
5604
6349
|
createPlayButtonOverlay() {
|
|
5605
6350
|
this.playButtonOverlay = createPlayOverlay();
|
|
@@ -5626,7 +6371,7 @@ var Player = class extends EventEmitter {
|
|
|
5626
6371
|
if (!src) {
|
|
5627
6372
|
throw new Error("No media source found");
|
|
5628
6373
|
}
|
|
5629
|
-
const sourceElements = this.
|
|
6374
|
+
const sourceElements = this.sourceElements;
|
|
5630
6375
|
for (const sourceEl of sourceElements) {
|
|
5631
6376
|
const descSrc = sourceEl.getAttribute("data-desc-src");
|
|
5632
6377
|
const origSrc = sourceEl.getAttribute("data-orig-src");
|
|
@@ -5655,7 +6400,7 @@ var Player = class extends EventEmitter {
|
|
|
5655
6400
|
}
|
|
5656
6401
|
}
|
|
5657
6402
|
}
|
|
5658
|
-
const trackElements = this.
|
|
6403
|
+
const trackElements = this.trackElements;
|
|
5659
6404
|
trackElements.forEach((trackEl) => {
|
|
5660
6405
|
const trackKind = trackEl.getAttribute("kind");
|
|
5661
6406
|
const trackDescSrc = trackEl.getAttribute("data-desc-src");
|
|
@@ -5676,19 +6421,137 @@ var Player = class extends EventEmitter {
|
|
|
5676
6421
|
if (!this.originalSrc) {
|
|
5677
6422
|
this.originalSrc = src;
|
|
5678
6423
|
}
|
|
5679
|
-
let renderer;
|
|
5680
|
-
if (src.includes("youtube.com") || src.includes("youtu.be")) {
|
|
5681
|
-
renderer = YouTubeRenderer;
|
|
5682
|
-
} else if (src.includes("vimeo.com")) {
|
|
5683
|
-
renderer = VimeoRenderer;
|
|
5684
|
-
} else if (src.includes(".m3u8")) {
|
|
5685
|
-
renderer = HLSRenderer;
|
|
5686
|
-
} else {
|
|
5687
|
-
renderer = HTML5Renderer;
|
|
6424
|
+
let renderer;
|
|
6425
|
+
if (src.includes("youtube.com") || src.includes("youtu.be")) {
|
|
6426
|
+
renderer = YouTubeRenderer;
|
|
6427
|
+
} else if (src.includes("vimeo.com")) {
|
|
6428
|
+
renderer = VimeoRenderer;
|
|
6429
|
+
} else if (src.includes(".m3u8")) {
|
|
6430
|
+
renderer = HLSRenderer;
|
|
6431
|
+
} else {
|
|
6432
|
+
renderer = HTML5Renderer;
|
|
6433
|
+
}
|
|
6434
|
+
this.log(`Using ${renderer.name} renderer`);
|
|
6435
|
+
this.renderer = new renderer(this);
|
|
6436
|
+
await this.renderer.init();
|
|
6437
|
+
this.invalidateTrackCache();
|
|
6438
|
+
}
|
|
6439
|
+
/**
|
|
6440
|
+
* Get cached text tracks array
|
|
6441
|
+
* @returns {Array} Array of text tracks
|
|
6442
|
+
*/
|
|
6443
|
+
get textTracks() {
|
|
6444
|
+
if (!this._textTracksCache || this._textTracksDirty) {
|
|
6445
|
+
this._textTracksCache = Array.from(this.element.textTracks || []);
|
|
6446
|
+
this._textTracksDirty = false;
|
|
6447
|
+
}
|
|
6448
|
+
return this._textTracksCache;
|
|
6449
|
+
}
|
|
6450
|
+
/**
|
|
6451
|
+
* Get cached source elements array
|
|
6452
|
+
* @returns {Array} Array of source elements
|
|
6453
|
+
*/
|
|
6454
|
+
get sourceElements() {
|
|
6455
|
+
if (!this._sourceElementsCache || this._sourceElementsDirty) {
|
|
6456
|
+
this._sourceElementsCache = Array.from(this.element.querySelectorAll("source"));
|
|
6457
|
+
this._sourceElementsDirty = false;
|
|
6458
|
+
}
|
|
6459
|
+
return this._sourceElementsCache;
|
|
6460
|
+
}
|
|
6461
|
+
/**
|
|
6462
|
+
* Get cached track elements array
|
|
6463
|
+
* @returns {Array} Array of track elements
|
|
6464
|
+
*/
|
|
6465
|
+
get trackElements() {
|
|
6466
|
+
if (!this._trackElementsCache || this._trackElementsDirty) {
|
|
6467
|
+
this._trackElementsCache = Array.from(this.element.querySelectorAll("track"));
|
|
6468
|
+
this._trackElementsDirty = false;
|
|
6469
|
+
}
|
|
6470
|
+
return this._trackElementsCache;
|
|
6471
|
+
}
|
|
6472
|
+
/**
|
|
6473
|
+
* Invalidate DOM query cache (call when tracks/sources change)
|
|
6474
|
+
*/
|
|
6475
|
+
invalidateTrackCache() {
|
|
6476
|
+
this._textTracksDirty = true;
|
|
6477
|
+
this._trackElementsDirty = true;
|
|
6478
|
+
this._sourceElementsDirty = true;
|
|
6479
|
+
}
|
|
6480
|
+
/**
|
|
6481
|
+
* Find a text track by kind and optionally language
|
|
6482
|
+
* @param {string} kind - Track kind (captions, subtitles, descriptions, chapters, metadata)
|
|
6483
|
+
* @param {string} [language] - Optional language code
|
|
6484
|
+
* @returns {TextTrack|null} Found track or null
|
|
6485
|
+
*/
|
|
6486
|
+
findTextTrack(kind, language = null) {
|
|
6487
|
+
const tracks = this.textTracks;
|
|
6488
|
+
if (language) {
|
|
6489
|
+
return tracks.find((t) => t.kind === kind && t.language === language);
|
|
6490
|
+
}
|
|
6491
|
+
return tracks.find((t) => t.kind === kind);
|
|
6492
|
+
}
|
|
6493
|
+
/**
|
|
6494
|
+
* Find a source element by attribute
|
|
6495
|
+
* @param {string} attribute - Attribute name (e.g., 'data-desc-src')
|
|
6496
|
+
* @param {string} [value] - Optional attribute value
|
|
6497
|
+
* @returns {Element|null} Found source element or null
|
|
6498
|
+
*/
|
|
6499
|
+
findSourceElement(attribute, value = null) {
|
|
6500
|
+
const sources = this.sourceElements;
|
|
6501
|
+
if (value) {
|
|
6502
|
+
return sources.find((el) => el.getAttribute(attribute) === value);
|
|
6503
|
+
}
|
|
6504
|
+
return sources.find((el) => el.hasAttribute(attribute));
|
|
6505
|
+
}
|
|
6506
|
+
/**
|
|
6507
|
+
* Find a track element by its associated TextTrack
|
|
6508
|
+
* @param {TextTrack} track - The TextTrack object
|
|
6509
|
+
* @returns {Element|null} Found track element or null
|
|
6510
|
+
*/
|
|
6511
|
+
findTrackElement(track) {
|
|
6512
|
+
return this.trackElements.find((el) => el.track === track);
|
|
6513
|
+
}
|
|
6514
|
+
showPosterOverlay() {
|
|
6515
|
+
if (!this.videoWrapper || this.element.tagName !== "VIDEO") {
|
|
6516
|
+
return;
|
|
6517
|
+
}
|
|
6518
|
+
const poster = this.element.getAttribute("poster") || this.element.poster || this.options.poster;
|
|
6519
|
+
if (!poster) {
|
|
6520
|
+
return;
|
|
6521
|
+
}
|
|
6522
|
+
this.videoWrapper.style.setProperty("--vidply-poster-image", `url("${poster}")`);
|
|
6523
|
+
this.videoWrapper.classList.add("vidply-forced-poster");
|
|
6524
|
+
}
|
|
6525
|
+
hidePosterOverlay() {
|
|
6526
|
+
if (!this.videoWrapper) {
|
|
6527
|
+
return;
|
|
6528
|
+
}
|
|
6529
|
+
this.videoWrapper.classList.remove("vidply-forced-poster");
|
|
6530
|
+
this.videoWrapper.style.removeProperty("--vidply-poster-image");
|
|
6531
|
+
}
|
|
6532
|
+
/**
|
|
6533
|
+
* Set a managed timeout that will be cleaned up on destroy
|
|
6534
|
+
* @param {Function} callback - Callback function
|
|
6535
|
+
* @param {number} delay - Delay in milliseconds
|
|
6536
|
+
* @returns {number} Timeout ID
|
|
6537
|
+
*/
|
|
6538
|
+
setManagedTimeout(callback, delay) {
|
|
6539
|
+
const timeoutId = setTimeout(() => {
|
|
6540
|
+
this.timeouts.delete(timeoutId);
|
|
6541
|
+
callback();
|
|
6542
|
+
}, delay);
|
|
6543
|
+
this.timeouts.add(timeoutId);
|
|
6544
|
+
return timeoutId;
|
|
6545
|
+
}
|
|
6546
|
+
/**
|
|
6547
|
+
* Clear a managed timeout
|
|
6548
|
+
* @param {number} timeoutId - Timeout ID to clear
|
|
6549
|
+
*/
|
|
6550
|
+
clearManagedTimeout(timeoutId) {
|
|
6551
|
+
if (timeoutId) {
|
|
6552
|
+
clearTimeout(timeoutId);
|
|
6553
|
+
this.timeouts.delete(timeoutId);
|
|
5688
6554
|
}
|
|
5689
|
-
this.log(`Using ${renderer.name} renderer`);
|
|
5690
|
-
this.renderer = new renderer(this);
|
|
5691
|
-
await this.renderer.init();
|
|
5692
6555
|
}
|
|
5693
6556
|
/**
|
|
5694
6557
|
* Load new media source (for playlists)
|
|
@@ -5704,8 +6567,9 @@ var Player = class extends EventEmitter {
|
|
|
5704
6567
|
if (this.renderer) {
|
|
5705
6568
|
this.pause();
|
|
5706
6569
|
}
|
|
5707
|
-
const existingTracks = this.
|
|
6570
|
+
const existingTracks = this.trackElements;
|
|
5708
6571
|
existingTracks.forEach((track) => track.remove());
|
|
6572
|
+
this.invalidateTrackCache();
|
|
5709
6573
|
this.element.src = config.src;
|
|
5710
6574
|
if (config.type) {
|
|
5711
6575
|
this.element.type = config.type;
|
|
@@ -5725,6 +6589,7 @@ var Player = class extends EventEmitter {
|
|
|
5725
6589
|
}
|
|
5726
6590
|
this.element.appendChild(track);
|
|
5727
6591
|
});
|
|
6592
|
+
this.invalidateTrackCache();
|
|
5728
6593
|
}
|
|
5729
6594
|
const shouldChangeRenderer = this.shouldChangeRenderer(config.src);
|
|
5730
6595
|
if (shouldChangeRenderer && this.renderer) {
|
|
@@ -5972,7 +6837,7 @@ var Player = class extends EventEmitter {
|
|
|
5972
6837
|
}
|
|
5973
6838
|
// Audio Description
|
|
5974
6839
|
async enableAudioDescription() {
|
|
5975
|
-
const hasSourceElementsWithDesc =
|
|
6840
|
+
const hasSourceElementsWithDesc = this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
5976
6841
|
const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;
|
|
5977
6842
|
if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
|
|
5978
6843
|
console.warn("VidPly: No audio description source, source elements, or tracks provided");
|
|
@@ -5980,10 +6845,14 @@ var Player = class extends EventEmitter {
|
|
|
5980
6845
|
}
|
|
5981
6846
|
const currentTime = this.state.currentTime;
|
|
5982
6847
|
const wasPlaying = this.state.playing;
|
|
6848
|
+
const shouldKeepPoster = !wasPlaying && currentTime === 0;
|
|
6849
|
+
if (shouldKeepPoster) {
|
|
6850
|
+
this.showPosterOverlay();
|
|
6851
|
+
}
|
|
5983
6852
|
let swappedTracksForTranscript = [];
|
|
5984
6853
|
if (this.audioDescriptionSourceElement) {
|
|
5985
6854
|
const currentSrc = this.element.currentSrc || this.element.src;
|
|
5986
|
-
const sourceElements =
|
|
6855
|
+
const sourceElements = this.sourceElements;
|
|
5987
6856
|
let sourceElementToUpdate = null;
|
|
5988
6857
|
let descSrc = this.audioDescriptionSrc;
|
|
5989
6858
|
for (const sourceEl of sourceElements) {
|
|
@@ -6080,8 +6949,9 @@ var Player = class extends EventEmitter {
|
|
|
6080
6949
|
trackInfo.trackElement = newTrackElement;
|
|
6081
6950
|
});
|
|
6082
6951
|
this.element.load();
|
|
6952
|
+
this.invalidateTrackCache();
|
|
6083
6953
|
const setupNewTracks = () => {
|
|
6084
|
-
|
|
6954
|
+
this.setManagedTimeout(() => {
|
|
6085
6955
|
swappedTracksForTranscript.forEach((trackInfo) => {
|
|
6086
6956
|
const trackElement = trackInfo.trackElement;
|
|
6087
6957
|
const newTextTrack = trackElement.track;
|
|
@@ -6117,7 +6987,7 @@ var Player = class extends EventEmitter {
|
|
|
6117
6987
|
const skippedCount = validationResults.length - tracksToSwap.length;
|
|
6118
6988
|
}
|
|
6119
6989
|
}
|
|
6120
|
-
const allSourceElements =
|
|
6990
|
+
const allSourceElements = this.sourceElements;
|
|
6121
6991
|
const sourcesToUpdate = [];
|
|
6122
6992
|
allSourceElements.forEach((sourceEl) => {
|
|
6123
6993
|
const descSrcAttr = sourceEl.getAttribute("data-desc-src");
|
|
@@ -6161,8 +7031,15 @@ var Player = class extends EventEmitter {
|
|
|
6161
7031
|
if (sourceInfo.descSrc) {
|
|
6162
7032
|
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6163
7033
|
}
|
|
6164
|
-
this.element.
|
|
7034
|
+
const firstTrack = this.element.querySelector("track");
|
|
7035
|
+
if (firstTrack) {
|
|
7036
|
+
this.element.insertBefore(newSource, firstTrack);
|
|
7037
|
+
} else {
|
|
7038
|
+
this.element.appendChild(newSource);
|
|
7039
|
+
}
|
|
6165
7040
|
});
|
|
7041
|
+
this._sourceElementsDirty = true;
|
|
7042
|
+
this._sourceElementsCache = null;
|
|
6166
7043
|
this.element.load();
|
|
6167
7044
|
await new Promise((resolve) => {
|
|
6168
7045
|
const onLoadedMetadata = () => {
|
|
@@ -6172,18 +7049,18 @@ var Player = class extends EventEmitter {
|
|
|
6172
7049
|
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
6173
7050
|
});
|
|
6174
7051
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
6175
|
-
if (
|
|
6176
|
-
|
|
6177
|
-
this.element.currentTime = 1e-3;
|
|
6178
|
-
setTimeout(() => {
|
|
6179
|
-
this.element.currentTime = 0;
|
|
6180
|
-
}, 10);
|
|
6181
|
-
}
|
|
7052
|
+
if (currentTime > 0) {
|
|
7053
|
+
this.seek(currentTime);
|
|
6182
7054
|
}
|
|
6183
|
-
this.seek(currentTime);
|
|
6184
7055
|
if (wasPlaying) {
|
|
6185
7056
|
this.play();
|
|
6186
7057
|
}
|
|
7058
|
+
if (!shouldKeepPoster) {
|
|
7059
|
+
this.hidePosterOverlay();
|
|
7060
|
+
}
|
|
7061
|
+
if (!this._audioDescriptionDesiredState) {
|
|
7062
|
+
return;
|
|
7063
|
+
}
|
|
6187
7064
|
this.state.audioDescriptionEnabled = true;
|
|
6188
7065
|
this.emit("audiodescriptionenabled");
|
|
6189
7066
|
} else {
|
|
@@ -6295,7 +7172,7 @@ var Player = class extends EventEmitter {
|
|
|
6295
7172
|
}, 100);
|
|
6296
7173
|
}
|
|
6297
7174
|
}
|
|
6298
|
-
const fallbackSourceElements =
|
|
7175
|
+
const fallbackSourceElements = this.sourceElements;
|
|
6299
7176
|
const hasSourceElementsWithDesc2 = fallbackSourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6300
7177
|
if (hasSourceElementsWithDesc2) {
|
|
6301
7178
|
const fallbackSourcesToUpdate = [];
|
|
@@ -6343,6 +7220,7 @@ var Player = class extends EventEmitter {
|
|
|
6343
7220
|
this.element.appendChild(newSource);
|
|
6344
7221
|
});
|
|
6345
7222
|
this.element.load();
|
|
7223
|
+
this.invalidateTrackCache();
|
|
6346
7224
|
} else {
|
|
6347
7225
|
this.element.src = this.audioDescriptionSrc;
|
|
6348
7226
|
}
|
|
@@ -6357,12 +7235,14 @@ var Player = class extends EventEmitter {
|
|
|
6357
7235
|
if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
|
|
6358
7236
|
if (this.element.readyState >= 1) {
|
|
6359
7237
|
this.element.currentTime = 1e-3;
|
|
6360
|
-
|
|
7238
|
+
this.setManagedTimeout(() => {
|
|
6361
7239
|
this.element.currentTime = 0;
|
|
6362
7240
|
}, 10);
|
|
6363
7241
|
}
|
|
6364
7242
|
}
|
|
6365
|
-
|
|
7243
|
+
if (currentTime > 0) {
|
|
7244
|
+
this.seek(currentTime);
|
|
7245
|
+
}
|
|
6366
7246
|
if (wasPlaying) {
|
|
6367
7247
|
this.play();
|
|
6368
7248
|
}
|
|
@@ -6397,7 +7277,8 @@ var Player = class extends EventEmitter {
|
|
|
6397
7277
|
const swappedTracks = typeof swappedTracksForTranscript !== "undefined" ? swappedTracksForTranscript : [];
|
|
6398
7278
|
if (swappedTracks.length > 0) {
|
|
6399
7279
|
const onMetadataLoaded = () => {
|
|
6400
|
-
|
|
7280
|
+
this.invalidateTrackCache();
|
|
7281
|
+
const allTextTracks = this.textTracks;
|
|
6401
7282
|
const freshTracks = swappedTracks.map((trackInfo) => {
|
|
6402
7283
|
const trackEl = trackInfo.trackElement;
|
|
6403
7284
|
const expectedSrc = trackEl.getAttribute("src");
|
|
@@ -6407,9 +7288,7 @@ var Player = class extends EventEmitter {
|
|
|
6407
7288
|
if (!foundTrack) {
|
|
6408
7289
|
foundTrack = allTextTracks.find((track) => {
|
|
6409
7290
|
if (track.language === srclang && (track.kind === kind || kind === "captions" && track.kind === "subtitles")) {
|
|
6410
|
-
const trackElementForTrack =
|
|
6411
|
-
(el) => el.track === track
|
|
6412
|
-
);
|
|
7291
|
+
const trackElementForTrack = this.findTrackElement(track);
|
|
6413
7292
|
if (trackElementForTrack) {
|
|
6414
7293
|
const actualSrc = trackElementForTrack.getAttribute("src");
|
|
6415
7294
|
if (actualSrc === expectedSrc) {
|
|
@@ -6421,9 +7300,7 @@ var Player = class extends EventEmitter {
|
|
|
6421
7300
|
});
|
|
6422
7301
|
}
|
|
6423
7302
|
if (foundTrack) {
|
|
6424
|
-
const trackElement =
|
|
6425
|
-
(el) => el.track === foundTrack
|
|
6426
|
-
);
|
|
7303
|
+
const trackElement = this.findTrackElement(foundTrack);
|
|
6427
7304
|
if (trackElement && trackElement.getAttribute("src") !== expectedSrc) {
|
|
6428
7305
|
return null;
|
|
6429
7306
|
}
|
|
@@ -6431,7 +7308,7 @@ var Player = class extends EventEmitter {
|
|
|
6431
7308
|
return foundTrack;
|
|
6432
7309
|
}).filter(Boolean);
|
|
6433
7310
|
if (freshTracks.length === 0) {
|
|
6434
|
-
|
|
7311
|
+
this.setManagedTimeout(() => {
|
|
6435
7312
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6436
7313
|
this.transcriptManager.loadTranscriptData();
|
|
6437
7314
|
}
|
|
@@ -6447,14 +7324,13 @@ var Player = class extends EventEmitter {
|
|
|
6447
7324
|
const checkLoaded = () => {
|
|
6448
7325
|
loadedCount++;
|
|
6449
7326
|
if (loadedCount >= freshTracks.length) {
|
|
6450
|
-
|
|
7327
|
+
this.setManagedTimeout(() => {
|
|
6451
7328
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6452
|
-
|
|
7329
|
+
this.invalidateTrackCache();
|
|
7330
|
+
const allTextTracks2 = this.textTracks;
|
|
6453
7331
|
const swappedTrackSrcs = swappedTracks.map((t) => t.describedSrc);
|
|
6454
7332
|
const hasCorrectTracks = freshTracks.some((track) => {
|
|
6455
|
-
const trackEl =
|
|
6456
|
-
(el) => el.track === track
|
|
6457
|
-
);
|
|
7333
|
+
const trackEl = this.findTrackElement(track);
|
|
6458
7334
|
return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute("src"));
|
|
6459
7335
|
});
|
|
6460
7336
|
if (hasCorrectTracks || freshTracks.length > 0) {
|
|
@@ -6468,9 +7344,7 @@ var Player = class extends EventEmitter {
|
|
|
6468
7344
|
if (track.mode === "disabled") {
|
|
6469
7345
|
track.mode = "hidden";
|
|
6470
7346
|
}
|
|
6471
|
-
const trackElementForTrack =
|
|
6472
|
-
(el) => el.track === track
|
|
6473
|
-
);
|
|
7347
|
+
const trackElementForTrack = this.findTrackElement(track);
|
|
6474
7348
|
const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute("src") : null;
|
|
6475
7349
|
const expectedTrackInfo = swappedTracks.find((t) => {
|
|
6476
7350
|
const tEl = t.trackElement;
|
|
@@ -6488,10 +7362,10 @@ var Player = class extends EventEmitter {
|
|
|
6488
7362
|
track.mode = "hidden";
|
|
6489
7363
|
}
|
|
6490
7364
|
const onTrackLoad = () => {
|
|
6491
|
-
|
|
7365
|
+
this.setManagedTimeout(checkLoaded, 300);
|
|
6492
7366
|
};
|
|
6493
7367
|
if (track.readyState >= 2) {
|
|
6494
|
-
|
|
7368
|
+
this.setManagedTimeout(() => {
|
|
6495
7369
|
if (track.cues && track.cues.length > 0) {
|
|
6496
7370
|
checkLoaded();
|
|
6497
7371
|
} else {
|
|
@@ -6508,12 +7382,12 @@ var Player = class extends EventEmitter {
|
|
|
6508
7382
|
});
|
|
6509
7383
|
};
|
|
6510
7384
|
const waitForTracks = () => {
|
|
6511
|
-
|
|
7385
|
+
this.setManagedTimeout(() => {
|
|
6512
7386
|
if (this.element.readyState >= 1) {
|
|
6513
7387
|
onMetadataLoaded();
|
|
6514
7388
|
} else {
|
|
6515
7389
|
this.element.addEventListener("loadedmetadata", onMetadataLoaded, { once: true });
|
|
6516
|
-
|
|
7390
|
+
this.setManagedTimeout(onMetadataLoaded, 2e3);
|
|
6517
7391
|
}
|
|
6518
7392
|
}, 500);
|
|
6519
7393
|
};
|
|
@@ -6531,6 +7405,12 @@ var Player = class extends EventEmitter {
|
|
|
6531
7405
|
}, 800);
|
|
6532
7406
|
}
|
|
6533
7407
|
}
|
|
7408
|
+
if (!shouldKeepPoster) {
|
|
7409
|
+
this.hidePosterOverlay();
|
|
7410
|
+
}
|
|
7411
|
+
if (!this._audioDescriptionDesiredState) {
|
|
7412
|
+
return;
|
|
7413
|
+
}
|
|
6534
7414
|
this.state.audioDescriptionEnabled = true;
|
|
6535
7415
|
this.emit("audiodescriptionenabled");
|
|
6536
7416
|
}
|
|
@@ -6547,7 +7427,7 @@ var Player = class extends EventEmitter {
|
|
|
6547
7427
|
}
|
|
6548
7428
|
});
|
|
6549
7429
|
}
|
|
6550
|
-
const allSourceElements =
|
|
7430
|
+
const allSourceElements = this.sourceElements;
|
|
6551
7431
|
const hasSourceElementsToSwap = allSourceElements.some((el) => el.getAttribute("data-orig-src"));
|
|
6552
7432
|
if (hasSourceElementsToSwap) {
|
|
6553
7433
|
const sourcesToRestore = [];
|
|
@@ -6590,61 +7470,107 @@ var Player = class extends EventEmitter {
|
|
|
6590
7470
|
if (sourceInfo.descSrc) {
|
|
6591
7471
|
newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
|
|
6592
7472
|
}
|
|
6593
|
-
this.element.
|
|
7473
|
+
const firstTrack = this.element.querySelector("track");
|
|
7474
|
+
if (firstTrack) {
|
|
7475
|
+
this.element.insertBefore(newSource, firstTrack);
|
|
7476
|
+
} else {
|
|
7477
|
+
this.element.appendChild(newSource);
|
|
7478
|
+
}
|
|
6594
7479
|
});
|
|
7480
|
+
this._sourceElementsDirty = true;
|
|
7481
|
+
this._sourceElementsCache = null;
|
|
6595
7482
|
this.element.load();
|
|
6596
7483
|
} else {
|
|
6597
7484
|
const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;
|
|
6598
7485
|
this.element.src = originalSrcToUse;
|
|
6599
7486
|
this.element.load();
|
|
6600
7487
|
}
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
7488
|
+
if (currentTime > 0 || wasPlaying) {
|
|
7489
|
+
await new Promise((resolve) => {
|
|
7490
|
+
const onLoadedMetadata = () => {
|
|
7491
|
+
this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
7492
|
+
resolve();
|
|
7493
|
+
};
|
|
7494
|
+
this.element.addEventListener("loadedmetadata", onLoadedMetadata);
|
|
7495
|
+
});
|
|
7496
|
+
if (currentTime > 0) {
|
|
7497
|
+
this.seek(currentTime);
|
|
7498
|
+
}
|
|
7499
|
+
if (wasPlaying) {
|
|
7500
|
+
this.play();
|
|
7501
|
+
}
|
|
7502
|
+
}
|
|
7503
|
+
if (!wasPlaying && currentTime === 0) {
|
|
7504
|
+
this.showPosterOverlay();
|
|
7505
|
+
} else {
|
|
7506
|
+
this.hidePosterOverlay();
|
|
6611
7507
|
}
|
|
6612
7508
|
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
6613
|
-
|
|
7509
|
+
this.setManagedTimeout(() => {
|
|
6614
7510
|
if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
|
|
6615
7511
|
this.transcriptManager.loadTranscriptData();
|
|
6616
7512
|
}
|
|
6617
7513
|
}, 500);
|
|
6618
7514
|
}
|
|
7515
|
+
if (this._audioDescriptionDesiredState) {
|
|
7516
|
+
return;
|
|
7517
|
+
}
|
|
6619
7518
|
this.state.audioDescriptionEnabled = false;
|
|
6620
7519
|
this.emit("audiodescriptiondisabled");
|
|
6621
7520
|
}
|
|
6622
7521
|
async toggleAudioDescription() {
|
|
6623
|
-
const
|
|
6624
|
-
const
|
|
6625
|
-
const hasAudioDescriptionSrc = this.audioDescriptionSrc || Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
|
|
7522
|
+
const descriptionTrack = this.findTextTrack("descriptions");
|
|
7523
|
+
const hasAudioDescriptionSrc = this.audioDescriptionSrc || this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
|
|
6626
7524
|
if (descriptionTrack && hasAudioDescriptionSrc) {
|
|
6627
7525
|
if (this.state.audioDescriptionEnabled) {
|
|
7526
|
+
this._audioDescriptionDesiredState = false;
|
|
6628
7527
|
descriptionTrack.mode = "hidden";
|
|
6629
7528
|
await this.disableAudioDescription();
|
|
6630
7529
|
} else {
|
|
7530
|
+
this._audioDescriptionDesiredState = true;
|
|
6631
7531
|
await this.enableAudioDescription();
|
|
6632
|
-
|
|
7532
|
+
const enableDescriptionTrack = () => {
|
|
7533
|
+
this.invalidateTrackCache();
|
|
7534
|
+
const descTrack = this.findTextTrack("descriptions");
|
|
7535
|
+
if (descTrack) {
|
|
7536
|
+
if (descTrack.mode === "disabled") {
|
|
7537
|
+
descTrack.mode = "hidden";
|
|
7538
|
+
this.setManagedTimeout(() => {
|
|
7539
|
+
descTrack.mode = "showing";
|
|
7540
|
+
}, 50);
|
|
7541
|
+
} else {
|
|
7542
|
+
descTrack.mode = "showing";
|
|
7543
|
+
}
|
|
7544
|
+
} else if (this.element.readyState < 2) {
|
|
7545
|
+
this.setManagedTimeout(enableDescriptionTrack, 100);
|
|
7546
|
+
}
|
|
7547
|
+
};
|
|
7548
|
+
if (this.element.readyState >= 1) {
|
|
7549
|
+
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
7550
|
+
} else {
|
|
7551
|
+
this.element.addEventListener("loadedmetadata", () => {
|
|
7552
|
+
this.setManagedTimeout(enableDescriptionTrack, 200);
|
|
7553
|
+
}, { once: true });
|
|
7554
|
+
}
|
|
6633
7555
|
}
|
|
6634
7556
|
} else if (descriptionTrack) {
|
|
6635
7557
|
if (descriptionTrack.mode === "showing") {
|
|
7558
|
+
this._audioDescriptionDesiredState = false;
|
|
6636
7559
|
descriptionTrack.mode = "hidden";
|
|
6637
7560
|
this.state.audioDescriptionEnabled = false;
|
|
6638
7561
|
this.emit("audiodescriptiondisabled");
|
|
6639
7562
|
} else {
|
|
7563
|
+
this._audioDescriptionDesiredState = true;
|
|
6640
7564
|
descriptionTrack.mode = "showing";
|
|
6641
7565
|
this.state.audioDescriptionEnabled = true;
|
|
6642
7566
|
this.emit("audiodescriptionenabled");
|
|
6643
7567
|
}
|
|
6644
7568
|
} else if (hasAudioDescriptionSrc) {
|
|
6645
7569
|
if (this.state.audioDescriptionEnabled) {
|
|
7570
|
+
this._audioDescriptionDesiredState = false;
|
|
6646
7571
|
await this.disableAudioDescription();
|
|
6647
7572
|
} else {
|
|
7573
|
+
this._audioDescriptionDesiredState = true;
|
|
6648
7574
|
await this.enableAudioDescription();
|
|
6649
7575
|
}
|
|
6650
7576
|
}
|
|
@@ -6741,177 +7667,22 @@ var Player = class extends EventEmitter {
|
|
|
6741
7667
|
}
|
|
6742
7668
|
setupSignLanguageInteraction() {
|
|
6743
7669
|
if (!this.signLanguageWrapper) return;
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
isDragging = true;
|
|
6759
|
-
startX = e.clientX;
|
|
6760
|
-
startY = e.clientY;
|
|
6761
|
-
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6762
|
-
startLeft = rect.left;
|
|
6763
|
-
startTop = rect.top;
|
|
6764
|
-
this.signLanguageWrapper.classList.add("vidply-sign-dragging");
|
|
6765
|
-
};
|
|
6766
|
-
const onMouseDownHandle = (e) => {
|
|
6767
|
-
if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
|
|
6768
|
-
e.preventDefault();
|
|
6769
|
-
e.stopPropagation();
|
|
6770
|
-
isResizing = true;
|
|
6771
|
-
resizeDirection = e.target.getAttribute("data-direction");
|
|
6772
|
-
startX = e.clientX;
|
|
6773
|
-
startY = e.clientY;
|
|
6774
|
-
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6775
|
-
startLeft = rect.left;
|
|
6776
|
-
startTop = rect.top;
|
|
6777
|
-
startWidth = rect.width;
|
|
6778
|
-
startHeight = rect.height;
|
|
6779
|
-
this.signLanguageWrapper.classList.add("vidply-sign-resizing");
|
|
6780
|
-
};
|
|
6781
|
-
const onMouseMove = (e) => {
|
|
6782
|
-
if (isDragging) {
|
|
6783
|
-
const deltaX = e.clientX - startX;
|
|
6784
|
-
const deltaY = e.clientY - startY;
|
|
6785
|
-
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6786
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
6787
|
-
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6788
|
-
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6789
|
-
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6790
|
-
let newLeft = startLeft + deltaX - containerRect.left;
|
|
6791
|
-
let newTop = startTop + deltaY - containerRect.top;
|
|
6792
|
-
const controlsHeight = 95;
|
|
6793
|
-
newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
|
|
6794
|
-
newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
|
|
6795
|
-
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6796
|
-
this.signLanguageWrapper.style.top = `${newTop}px`;
|
|
6797
|
-
this.signLanguageWrapper.style.right = "auto";
|
|
6798
|
-
this.signLanguageWrapper.style.bottom = "auto";
|
|
6799
|
-
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6800
|
-
} else if (isResizing) {
|
|
6801
|
-
const deltaX = e.clientX - startX;
|
|
6802
|
-
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6803
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
6804
|
-
let newWidth = startWidth;
|
|
6805
|
-
let newLeft = startLeft - containerRect.left;
|
|
6806
|
-
if (resizeDirection.includes("e")) {
|
|
6807
|
-
newWidth = Math.max(150, startWidth + deltaX);
|
|
6808
|
-
const maxWidth = videoWrapperRect.right - startLeft;
|
|
6809
|
-
newWidth = Math.min(newWidth, maxWidth);
|
|
6810
|
-
}
|
|
6811
|
-
if (resizeDirection.includes("w")) {
|
|
6812
|
-
const proposedWidth = Math.max(150, startWidth - deltaX);
|
|
6813
|
-
const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
|
|
6814
|
-
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6815
|
-
if (proposedLeft >= videoWrapperLeft) {
|
|
6816
|
-
newWidth = proposedWidth;
|
|
6817
|
-
newLeft = proposedLeft;
|
|
6818
|
-
}
|
|
6819
|
-
}
|
|
6820
|
-
this.signLanguageWrapper.style.width = `${newWidth}px`;
|
|
6821
|
-
this.signLanguageWrapper.style.height = "auto";
|
|
6822
|
-
if (resizeDirection.includes("w")) {
|
|
6823
|
-
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6824
|
-
}
|
|
6825
|
-
this.signLanguageWrapper.style.right = "auto";
|
|
6826
|
-
this.signLanguageWrapper.style.bottom = "auto";
|
|
6827
|
-
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6828
|
-
}
|
|
6829
|
-
};
|
|
6830
|
-
const onMouseUp = () => {
|
|
6831
|
-
if (isDragging || isResizing) {
|
|
6832
|
-
this.saveSignLanguagePreferences();
|
|
6833
|
-
}
|
|
6834
|
-
isDragging = false;
|
|
6835
|
-
isResizing = false;
|
|
6836
|
-
resizeDirection = null;
|
|
6837
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
|
|
6838
|
-
};
|
|
6839
|
-
const onKeyDown = (e) => {
|
|
6840
|
-
if (e.key === "d" || e.key === "D") {
|
|
6841
|
-
dragMode = !dragMode;
|
|
6842
|
-
resizeMode = false;
|
|
6843
|
-
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
|
|
6844
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
|
|
6845
|
-
e.preventDefault();
|
|
6846
|
-
return;
|
|
6847
|
-
}
|
|
6848
|
-
if (e.key === "r" || e.key === "R") {
|
|
6849
|
-
resizeMode = !resizeMode;
|
|
6850
|
-
dragMode = false;
|
|
6851
|
-
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
|
|
6852
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
|
|
6853
|
-
e.preventDefault();
|
|
6854
|
-
return;
|
|
6855
|
-
}
|
|
6856
|
-
if (e.key === "Escape") {
|
|
6857
|
-
dragMode = false;
|
|
6858
|
-
resizeMode = false;
|
|
6859
|
-
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
|
|
6860
|
-
e.preventDefault();
|
|
6861
|
-
return;
|
|
6862
|
-
}
|
|
6863
|
-
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
6864
|
-
const step = e.shiftKey ? 10 : 5;
|
|
6865
|
-
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6866
|
-
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6867
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
6868
|
-
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6869
|
-
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6870
|
-
if (dragMode) {
|
|
6871
|
-
let left = rect.left - containerRect.left;
|
|
6872
|
-
let top = rect.top - containerRect.top;
|
|
6873
|
-
if (e.key === "ArrowLeft") left -= step;
|
|
6874
|
-
if (e.key === "ArrowRight") left += step;
|
|
6875
|
-
if (e.key === "ArrowUp") top -= step;
|
|
6876
|
-
if (e.key === "ArrowDown") top += step;
|
|
6877
|
-
const controlsHeight = 95;
|
|
6878
|
-
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
|
|
6879
|
-
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
|
|
6880
|
-
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6881
|
-
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6882
|
-
this.signLanguageWrapper.style.right = "auto";
|
|
6883
|
-
this.signLanguageWrapper.style.bottom = "auto";
|
|
6884
|
-
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6885
|
-
this.saveSignLanguagePreferences();
|
|
6886
|
-
e.preventDefault();
|
|
6887
|
-
} else if (resizeMode) {
|
|
6888
|
-
let width = rect.width;
|
|
6889
|
-
if (e.key === "ArrowLeft") width -= step;
|
|
6890
|
-
if (e.key === "ArrowRight") width += step;
|
|
6891
|
-
if (e.key === "ArrowUp") width += step;
|
|
6892
|
-
if (e.key === "ArrowDown") width -= step;
|
|
6893
|
-
width = Math.max(150, width);
|
|
6894
|
-
width = Math.min(width, videoWrapperRect.width);
|
|
6895
|
-
this.signLanguageWrapper.style.width = `${width}px`;
|
|
6896
|
-
this.signLanguageWrapper.style.height = "auto";
|
|
6897
|
-
this.saveSignLanguagePreferences();
|
|
6898
|
-
e.preventDefault();
|
|
6899
|
-
}
|
|
6900
|
-
}
|
|
6901
|
-
};
|
|
6902
|
-
this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
|
|
6903
|
-
const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
|
|
6904
|
-
handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
|
|
6905
|
-
document.addEventListener("mousemove", onMouseMove);
|
|
6906
|
-
document.addEventListener("mouseup", onMouseUp);
|
|
6907
|
-
this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
|
|
7670
|
+
const resizeHandles = Array.from(this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle"));
|
|
7671
|
+
this.signLanguageDraggable = new DraggableResizable(this.signLanguageWrapper, {
|
|
7672
|
+
dragHandle: this.signLanguageVideo,
|
|
7673
|
+
resizeHandles,
|
|
7674
|
+
constrainToViewport: true,
|
|
7675
|
+
maintainAspectRatio: true,
|
|
7676
|
+
minWidth: 150,
|
|
7677
|
+
minHeight: 100,
|
|
7678
|
+
classPrefix: "vidply-sign",
|
|
7679
|
+
keyboardDragKey: "d",
|
|
7680
|
+
keyboardResizeKey: "r",
|
|
7681
|
+
keyboardStep: 5,
|
|
7682
|
+
keyboardStepLarge: 10
|
|
7683
|
+
});
|
|
6908
7684
|
this.signLanguageInteractionHandlers = {
|
|
6909
|
-
|
|
6910
|
-
mouseDownHandle: onMouseDownHandle,
|
|
6911
|
-
mouseMove: onMouseMove,
|
|
6912
|
-
mouseUp: onMouseUp,
|
|
6913
|
-
keyDown: onKeyDown,
|
|
6914
|
-
handles
|
|
7685
|
+
draggable: this.signLanguageDraggable
|
|
6915
7686
|
};
|
|
6916
7687
|
}
|
|
6917
7688
|
constrainSignLanguagePosition() {
|
|
@@ -6978,22 +7749,11 @@ var Player = class extends EventEmitter {
|
|
|
6978
7749
|
this.off("ratechange", this.signLanguageHandlers.ratechange);
|
|
6979
7750
|
this.signLanguageHandlers = null;
|
|
6980
7751
|
}
|
|
6981
|
-
if (this.
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
}
|
|
6985
|
-
if (this.signLanguageInteractionHandlers.handles) {
|
|
6986
|
-
this.signLanguageInteractionHandlers.handles.forEach((handle) => {
|
|
6987
|
-
handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
|
|
6988
|
-
});
|
|
6989
|
-
}
|
|
6990
|
-
document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
|
|
6991
|
-
document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
|
|
6992
|
-
if (this.signLanguageWrapper) {
|
|
6993
|
-
this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
|
|
6994
|
-
}
|
|
6995
|
-
this.signLanguageInteractionHandlers = null;
|
|
7752
|
+
if (this.signLanguageDraggable) {
|
|
7753
|
+
this.signLanguageDraggable.destroy();
|
|
7754
|
+
this.signLanguageDraggable = null;
|
|
6996
7755
|
}
|
|
7756
|
+
this.signLanguageInteractionHandlers = null;
|
|
6997
7757
|
if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
|
|
6998
7758
|
if (this.signLanguageVideo) {
|
|
6999
7759
|
this.signLanguageVideo.pause();
|
|
@@ -7042,9 +7802,25 @@ var Player = class extends EventEmitter {
|
|
|
7042
7802
|
}
|
|
7043
7803
|
}
|
|
7044
7804
|
// Logging
|
|
7045
|
-
log(
|
|
7046
|
-
if (this.options.debug) {
|
|
7047
|
-
|
|
7805
|
+
log(...messages) {
|
|
7806
|
+
if (!this.options.debug) {
|
|
7807
|
+
return;
|
|
7808
|
+
}
|
|
7809
|
+
let type = "log";
|
|
7810
|
+
if (messages.length > 0) {
|
|
7811
|
+
const potentialType = messages[messages.length - 1];
|
|
7812
|
+
if (typeof potentialType === "string" && console[potentialType]) {
|
|
7813
|
+
type = potentialType;
|
|
7814
|
+
messages = messages.slice(0, -1);
|
|
7815
|
+
}
|
|
7816
|
+
}
|
|
7817
|
+
if (messages.length === 0) {
|
|
7818
|
+
messages = [""];
|
|
7819
|
+
}
|
|
7820
|
+
if (typeof console[type] === "function") {
|
|
7821
|
+
console[type]("[VidPly]", ...messages);
|
|
7822
|
+
} else {
|
|
7823
|
+
console.log("[VidPly]", ...messages);
|
|
7048
7824
|
}
|
|
7049
7825
|
}
|
|
7050
7826
|
// Setup responsive handlers
|
|
@@ -7069,7 +7845,9 @@ var Player = class extends EventEmitter {
|
|
|
7069
7845
|
this.controlBar.updateControlsForViewport(width);
|
|
7070
7846
|
}
|
|
7071
7847
|
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
7072
|
-
this.transcriptManager.
|
|
7848
|
+
if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
7849
|
+
this.transcriptManager.positionTranscript();
|
|
7850
|
+
}
|
|
7073
7851
|
}
|
|
7074
7852
|
};
|
|
7075
7853
|
window.addEventListener("resize", this.resizeHandler);
|
|
@@ -7078,7 +7856,9 @@ var Player = class extends EventEmitter {
|
|
|
7078
7856
|
this.orientationHandler = (e) => {
|
|
7079
7857
|
setTimeout(() => {
|
|
7080
7858
|
if (this.transcriptManager && this.transcriptManager.isVisible) {
|
|
7081
|
-
this.transcriptManager.
|
|
7859
|
+
if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
|
|
7860
|
+
this.transcriptManager.positionTranscript();
|
|
7861
|
+
}
|
|
7082
7862
|
}
|
|
7083
7863
|
}, 100);
|
|
7084
7864
|
};
|
|
@@ -7104,7 +7884,7 @@ var Player = class extends EventEmitter {
|
|
|
7104
7884
|
this.controlBar.updateFullscreenButton();
|
|
7105
7885
|
}
|
|
7106
7886
|
if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
|
|
7107
|
-
|
|
7887
|
+
this.setManagedTimeout(() => {
|
|
7108
7888
|
requestAnimationFrame(() => {
|
|
7109
7889
|
this.storage.saveSignLanguagePreferences({ size: null });
|
|
7110
7890
|
this.signLanguageDesiredPosition = "bottom-right";
|
|
@@ -7167,12 +7947,368 @@ var Player = class extends EventEmitter {
|
|
|
7167
7947
|
document.removeEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
|
|
7168
7948
|
this.fullscreenChangeHandler = null;
|
|
7169
7949
|
}
|
|
7950
|
+
this.timeouts.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
7951
|
+
this.timeouts.clear();
|
|
7952
|
+
if (this.metadataCueChangeHandler) {
|
|
7953
|
+
const textTracks = this.textTracks;
|
|
7954
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
7955
|
+
if (metadataTrack) {
|
|
7956
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
7957
|
+
}
|
|
7958
|
+
this.metadataCueChangeHandler = null;
|
|
7959
|
+
}
|
|
7960
|
+
if (this.metadataAlertHandlers && this.metadataAlertHandlers.size > 0) {
|
|
7961
|
+
this.metadataAlertHandlers.forEach(({ button, handler }) => {
|
|
7962
|
+
if (button && handler) {
|
|
7963
|
+
button.removeEventListener("click", handler);
|
|
7964
|
+
}
|
|
7965
|
+
});
|
|
7966
|
+
this.metadataAlertHandlers.clear();
|
|
7967
|
+
}
|
|
7170
7968
|
if (this.container && this.container.parentNode) {
|
|
7171
7969
|
this.container.parentNode.insertBefore(this.element, this.container);
|
|
7172
7970
|
this.container.parentNode.removeChild(this.container);
|
|
7173
7971
|
}
|
|
7174
7972
|
this.removeAllListeners();
|
|
7175
7973
|
}
|
|
7974
|
+
/**
|
|
7975
|
+
* Setup metadata track handling
|
|
7976
|
+
* This enables metadata tracks and listens for cue changes to trigger actions
|
|
7977
|
+
*/
|
|
7978
|
+
setupMetadataHandling() {
|
|
7979
|
+
const setupMetadata = () => {
|
|
7980
|
+
const textTracks = this.textTracks;
|
|
7981
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
7982
|
+
if (metadataTrack) {
|
|
7983
|
+
if (metadataTrack.mode === "disabled") {
|
|
7984
|
+
metadataTrack.mode = "hidden";
|
|
7985
|
+
}
|
|
7986
|
+
if (this.metadataCueChangeHandler) {
|
|
7987
|
+
metadataTrack.removeEventListener("cuechange", this.metadataCueChangeHandler);
|
|
7988
|
+
}
|
|
7989
|
+
this.metadataCueChangeHandler = () => {
|
|
7990
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
7991
|
+
if (activeCues.length > 0) {
|
|
7992
|
+
if (this.options.debug) {
|
|
7993
|
+
this.log("[Metadata] Active cues:", activeCues.map((c) => ({
|
|
7994
|
+
start: c.startTime,
|
|
7995
|
+
end: c.endTime,
|
|
7996
|
+
text: c.text
|
|
7997
|
+
})));
|
|
7998
|
+
}
|
|
7999
|
+
}
|
|
8000
|
+
activeCues.forEach((cue) => {
|
|
8001
|
+
this.handleMetadataCue(cue);
|
|
8002
|
+
});
|
|
8003
|
+
};
|
|
8004
|
+
metadataTrack.addEventListener("cuechange", this.metadataCueChangeHandler);
|
|
8005
|
+
if (this.options.debug) {
|
|
8006
|
+
const cueCount = metadataTrack.cues ? metadataTrack.cues.length : 0;
|
|
8007
|
+
this.log("[Metadata] Track enabled,", cueCount, "cues available");
|
|
8008
|
+
}
|
|
8009
|
+
} else if (this.options.debug) {
|
|
8010
|
+
this.log("[Metadata] No metadata track found");
|
|
8011
|
+
}
|
|
8012
|
+
};
|
|
8013
|
+
setupMetadata();
|
|
8014
|
+
this.on("loadedmetadata", setupMetadata);
|
|
8015
|
+
}
|
|
8016
|
+
normalizeMetadataSelector(selector) {
|
|
8017
|
+
if (!selector) {
|
|
8018
|
+
return null;
|
|
8019
|
+
}
|
|
8020
|
+
const trimmed = selector.trim();
|
|
8021
|
+
if (!trimmed) {
|
|
8022
|
+
return null;
|
|
8023
|
+
}
|
|
8024
|
+
if (trimmed.startsWith("#") || trimmed.startsWith(".") || trimmed.startsWith("[")) {
|
|
8025
|
+
return trimmed;
|
|
8026
|
+
}
|
|
8027
|
+
return `#${trimmed}`;
|
|
8028
|
+
}
|
|
8029
|
+
resolveMetadataConfig(map, key) {
|
|
8030
|
+
if (!map || !key) {
|
|
8031
|
+
return null;
|
|
8032
|
+
}
|
|
8033
|
+
if (Object.prototype.hasOwnProperty.call(map, key)) {
|
|
8034
|
+
return map[key];
|
|
8035
|
+
}
|
|
8036
|
+
const withoutHash = key.replace(/^#/, "");
|
|
8037
|
+
if (Object.prototype.hasOwnProperty.call(map, withoutHash)) {
|
|
8038
|
+
return map[withoutHash];
|
|
8039
|
+
}
|
|
8040
|
+
return null;
|
|
8041
|
+
}
|
|
8042
|
+
cacheMetadataAlertContent(element, config = {}) {
|
|
8043
|
+
if (!element) {
|
|
8044
|
+
return;
|
|
8045
|
+
}
|
|
8046
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
8047
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
8048
|
+
const titleEl = element.querySelector(titleSelector);
|
|
8049
|
+
if (titleEl && !titleEl.dataset.vidplyAlertTitleOriginal) {
|
|
8050
|
+
titleEl.dataset.vidplyAlertTitleOriginal = titleEl.textContent.trim();
|
|
8051
|
+
}
|
|
8052
|
+
const messageEl = element.querySelector(messageSelector);
|
|
8053
|
+
if (messageEl && !messageEl.dataset.vidplyAlertMessageOriginal) {
|
|
8054
|
+
messageEl.dataset.vidplyAlertMessageOriginal = messageEl.textContent.trim();
|
|
8055
|
+
}
|
|
8056
|
+
}
|
|
8057
|
+
restoreMetadataAlertContent(element, config = {}) {
|
|
8058
|
+
if (!element) {
|
|
8059
|
+
return;
|
|
8060
|
+
}
|
|
8061
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
8062
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
8063
|
+
const titleEl = element.querySelector(titleSelector);
|
|
8064
|
+
if (titleEl && titleEl.dataset.vidplyAlertTitleOriginal) {
|
|
8065
|
+
titleEl.textContent = titleEl.dataset.vidplyAlertTitleOriginal;
|
|
8066
|
+
}
|
|
8067
|
+
const messageEl = element.querySelector(messageSelector);
|
|
8068
|
+
if (messageEl && messageEl.dataset.vidplyAlertMessageOriginal) {
|
|
8069
|
+
messageEl.textContent = messageEl.dataset.vidplyAlertMessageOriginal;
|
|
8070
|
+
}
|
|
8071
|
+
}
|
|
8072
|
+
focusMetadataTarget(target, fallbackElement = null) {
|
|
8073
|
+
var _a, _b;
|
|
8074
|
+
if (!target || target === "none") {
|
|
8075
|
+
return;
|
|
8076
|
+
}
|
|
8077
|
+
if (target === "alert" && fallbackElement) {
|
|
8078
|
+
fallbackElement.focus();
|
|
8079
|
+
return;
|
|
8080
|
+
}
|
|
8081
|
+
if (target === "player") {
|
|
8082
|
+
if (this.container) {
|
|
8083
|
+
this.container.focus();
|
|
8084
|
+
}
|
|
8085
|
+
return;
|
|
8086
|
+
}
|
|
8087
|
+
if (target === "media") {
|
|
8088
|
+
this.element.focus();
|
|
8089
|
+
return;
|
|
8090
|
+
}
|
|
8091
|
+
if (target === "playButton") {
|
|
8092
|
+
const playButton = (_b = (_a = this.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.playPause;
|
|
8093
|
+
if (playButton) {
|
|
8094
|
+
playButton.focus();
|
|
8095
|
+
}
|
|
8096
|
+
return;
|
|
8097
|
+
}
|
|
8098
|
+
if (typeof target === "string") {
|
|
8099
|
+
const targetElement = document.querySelector(target);
|
|
8100
|
+
if (targetElement) {
|
|
8101
|
+
if (targetElement.tabIndex === -1 && !targetElement.hasAttribute("tabindex")) {
|
|
8102
|
+
targetElement.setAttribute("tabindex", "-1");
|
|
8103
|
+
}
|
|
8104
|
+
targetElement.focus();
|
|
8105
|
+
}
|
|
8106
|
+
}
|
|
8107
|
+
}
|
|
8108
|
+
handleMetadataAlert(selector, options = {}) {
|
|
8109
|
+
if (!selector) {
|
|
8110
|
+
return;
|
|
8111
|
+
}
|
|
8112
|
+
const config = this.resolveMetadataConfig(this.options.metadataAlerts, selector) || {};
|
|
8113
|
+
const element = options.element || document.querySelector(selector);
|
|
8114
|
+
if (!element) {
|
|
8115
|
+
if (this.options.debug) {
|
|
8116
|
+
this.log("[Metadata] Alert element not found:", selector);
|
|
8117
|
+
}
|
|
8118
|
+
return;
|
|
8119
|
+
}
|
|
8120
|
+
if (this.options.debug) {
|
|
8121
|
+
this.log("[Metadata] Handling alert", selector, { reason: options.reason, config });
|
|
8122
|
+
}
|
|
8123
|
+
this.cacheMetadataAlertContent(element, config);
|
|
8124
|
+
if (!element.dataset.vidplyAlertOriginalDisplay) {
|
|
8125
|
+
element.dataset.vidplyAlertOriginalDisplay = element.style.display || "";
|
|
8126
|
+
}
|
|
8127
|
+
if (!element.dataset.vidplyAlertDisplay) {
|
|
8128
|
+
element.dataset.vidplyAlertDisplay = config.display || "block";
|
|
8129
|
+
}
|
|
8130
|
+
const shouldShow = options.show !== void 0 ? options.show : config.show !== false;
|
|
8131
|
+
if (shouldShow) {
|
|
8132
|
+
const displayValue = config.display || element.dataset.vidplyAlertDisplay || "block";
|
|
8133
|
+
element.style.display = displayValue;
|
|
8134
|
+
element.hidden = false;
|
|
8135
|
+
element.removeAttribute("hidden");
|
|
8136
|
+
element.setAttribute("aria-hidden", "false");
|
|
8137
|
+
element.setAttribute("data-vidply-alert-active", "true");
|
|
8138
|
+
}
|
|
8139
|
+
const shouldReset = config.resetContent !== false && options.reason === "focus";
|
|
8140
|
+
if (shouldReset) {
|
|
8141
|
+
this.restoreMetadataAlertContent(element, config);
|
|
8142
|
+
}
|
|
8143
|
+
const shouldFocus = options.focus !== void 0 ? options.focus : config.focusOnShow ?? options.reason !== "focus";
|
|
8144
|
+
if (shouldShow && shouldFocus) {
|
|
8145
|
+
if (element.tabIndex === -1 && !element.hasAttribute("tabindex")) {
|
|
8146
|
+
element.setAttribute("tabindex", "-1");
|
|
8147
|
+
}
|
|
8148
|
+
element.focus();
|
|
8149
|
+
}
|
|
8150
|
+
if (shouldShow && config.autoScroll !== false && options.autoScroll !== false) {
|
|
8151
|
+
element.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
8152
|
+
}
|
|
8153
|
+
const continueSelector = config.continueButton;
|
|
8154
|
+
if (continueSelector) {
|
|
8155
|
+
let continueButton = null;
|
|
8156
|
+
if (continueSelector === "self") {
|
|
8157
|
+
continueButton = element;
|
|
8158
|
+
} else if (element.matches(continueSelector)) {
|
|
8159
|
+
continueButton = element;
|
|
8160
|
+
} else {
|
|
8161
|
+
continueButton = element.querySelector(continueSelector) || document.querySelector(continueSelector);
|
|
8162
|
+
}
|
|
8163
|
+
if (continueButton && !this.metadataAlertHandlers.has(selector)) {
|
|
8164
|
+
const handler = () => {
|
|
8165
|
+
const hideOnContinue = config.hideOnContinue !== false;
|
|
8166
|
+
if (hideOnContinue) {
|
|
8167
|
+
const originalDisplay = element.dataset.vidplyAlertOriginalDisplay || "";
|
|
8168
|
+
element.style.display = config.hideDisplay || originalDisplay || "none";
|
|
8169
|
+
element.setAttribute("aria-hidden", "true");
|
|
8170
|
+
element.removeAttribute("data-vidply-alert-active");
|
|
8171
|
+
}
|
|
8172
|
+
if (config.resume !== false && this.state.paused) {
|
|
8173
|
+
this.play();
|
|
8174
|
+
}
|
|
8175
|
+
const focusTarget = config.focusTarget || "playButton";
|
|
8176
|
+
this.setManagedTimeout(() => {
|
|
8177
|
+
this.focusMetadataTarget(focusTarget, element);
|
|
8178
|
+
}, config.focusDelay ?? 100);
|
|
8179
|
+
};
|
|
8180
|
+
continueButton.addEventListener("click", handler);
|
|
8181
|
+
this.metadataAlertHandlers.set(selector, { button: continueButton, handler });
|
|
8182
|
+
}
|
|
8183
|
+
}
|
|
8184
|
+
return element;
|
|
8185
|
+
}
|
|
8186
|
+
handleMetadataHashtags(hashtags) {
|
|
8187
|
+
if (!Array.isArray(hashtags) || hashtags.length === 0) {
|
|
8188
|
+
return;
|
|
8189
|
+
}
|
|
8190
|
+
const configMap = this.options.metadataHashtags;
|
|
8191
|
+
if (!configMap) {
|
|
8192
|
+
return;
|
|
8193
|
+
}
|
|
8194
|
+
hashtags.forEach((tag) => {
|
|
8195
|
+
const config = this.resolveMetadataConfig(configMap, tag);
|
|
8196
|
+
if (!config) {
|
|
8197
|
+
return;
|
|
8198
|
+
}
|
|
8199
|
+
const selector = this.normalizeMetadataSelector(config.alert || config.selector || config.target);
|
|
8200
|
+
if (!selector) {
|
|
8201
|
+
return;
|
|
8202
|
+
}
|
|
8203
|
+
const element = document.querySelector(selector);
|
|
8204
|
+
if (!element) {
|
|
8205
|
+
if (this.options.debug) {
|
|
8206
|
+
this.log("[Metadata] Hashtag target not found:", selector);
|
|
8207
|
+
}
|
|
8208
|
+
return;
|
|
8209
|
+
}
|
|
8210
|
+
if (this.options.debug) {
|
|
8211
|
+
this.log("[Metadata] Handling hashtag", tag, { selector, config });
|
|
8212
|
+
}
|
|
8213
|
+
this.cacheMetadataAlertContent(element, config);
|
|
8214
|
+
if (config.title) {
|
|
8215
|
+
const titleSelector = config.titleSelector || "[data-vidply-alert-title], h3, header";
|
|
8216
|
+
const titleEl = element.querySelector(titleSelector);
|
|
8217
|
+
if (titleEl) {
|
|
8218
|
+
titleEl.textContent = config.title;
|
|
8219
|
+
}
|
|
8220
|
+
}
|
|
8221
|
+
if (config.message) {
|
|
8222
|
+
const messageSelector = config.messageSelector || "[data-vidply-alert-message], p";
|
|
8223
|
+
const messageEl = element.querySelector(messageSelector);
|
|
8224
|
+
if (messageEl) {
|
|
8225
|
+
messageEl.textContent = config.message;
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
8228
|
+
const show = config.show !== false;
|
|
8229
|
+
const focus = config.focus !== void 0 ? config.focus : false;
|
|
8230
|
+
this.handleMetadataAlert(selector, {
|
|
8231
|
+
element,
|
|
8232
|
+
show,
|
|
8233
|
+
focus,
|
|
8234
|
+
autoScroll: config.autoScroll,
|
|
8235
|
+
reason: "hashtag"
|
|
8236
|
+
});
|
|
8237
|
+
});
|
|
8238
|
+
}
|
|
8239
|
+
/**
|
|
8240
|
+
* Handle individual metadata cues
|
|
8241
|
+
* Parses metadata text and emits events or triggers actions
|
|
8242
|
+
*/
|
|
8243
|
+
handleMetadataCue(cue) {
|
|
8244
|
+
const text = cue.text.trim();
|
|
8245
|
+
if (this.options.debug) {
|
|
8246
|
+
this.log("[Metadata] Processing cue:", {
|
|
8247
|
+
time: cue.startTime,
|
|
8248
|
+
text
|
|
8249
|
+
});
|
|
8250
|
+
}
|
|
8251
|
+
this.emit("metadata", {
|
|
8252
|
+
time: cue.startTime,
|
|
8253
|
+
endTime: cue.endTime,
|
|
8254
|
+
text,
|
|
8255
|
+
cue
|
|
8256
|
+
});
|
|
8257
|
+
if (text.includes("PAUSE")) {
|
|
8258
|
+
if (!this.state.paused) {
|
|
8259
|
+
if (this.options.debug) {
|
|
8260
|
+
this.log("[Metadata] Pausing video at", cue.startTime);
|
|
8261
|
+
}
|
|
8262
|
+
this.pause();
|
|
8263
|
+
}
|
|
8264
|
+
this.emit("metadata:pause", { time: cue.startTime, text });
|
|
8265
|
+
}
|
|
8266
|
+
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
8267
|
+
if (focusMatch) {
|
|
8268
|
+
const targetSelector = focusMatch[1];
|
|
8269
|
+
const normalizedSelector = this.normalizeMetadataSelector(targetSelector);
|
|
8270
|
+
const targetElement = normalizedSelector ? document.querySelector(normalizedSelector) : null;
|
|
8271
|
+
if (targetElement) {
|
|
8272
|
+
if (this.options.debug) {
|
|
8273
|
+
this.log("[Metadata] Focusing element:", normalizedSelector);
|
|
8274
|
+
}
|
|
8275
|
+
if (targetElement.tabIndex === -1 && !targetElement.hasAttribute("tabindex")) {
|
|
8276
|
+
targetElement.setAttribute("tabindex", "-1");
|
|
8277
|
+
}
|
|
8278
|
+
this.setManagedTimeout(() => {
|
|
8279
|
+
targetElement.focus();
|
|
8280
|
+
targetElement.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
8281
|
+
}, 10);
|
|
8282
|
+
} else if (this.options.debug) {
|
|
8283
|
+
this.log("[Metadata] Element not found:", normalizedSelector || targetSelector);
|
|
8284
|
+
}
|
|
8285
|
+
this.emit("metadata:focus", {
|
|
8286
|
+
time: cue.startTime,
|
|
8287
|
+
target: targetSelector,
|
|
8288
|
+
selector: normalizedSelector,
|
|
8289
|
+
element: targetElement,
|
|
8290
|
+
text
|
|
8291
|
+
});
|
|
8292
|
+
if (normalizedSelector) {
|
|
8293
|
+
this.handleMetadataAlert(normalizedSelector, {
|
|
8294
|
+
element: targetElement,
|
|
8295
|
+
reason: "focus"
|
|
8296
|
+
});
|
|
8297
|
+
}
|
|
8298
|
+
}
|
|
8299
|
+
const hashtags = text.match(/#[\w-]+/g);
|
|
8300
|
+
if (hashtags) {
|
|
8301
|
+
if (this.options.debug) {
|
|
8302
|
+
this.log("[Metadata] Hashtags found:", hashtags);
|
|
8303
|
+
}
|
|
8304
|
+
this.emit("metadata:hashtags", {
|
|
8305
|
+
time: cue.startTime,
|
|
8306
|
+
hashtags,
|
|
8307
|
+
text
|
|
8308
|
+
});
|
|
8309
|
+
this.handleMetadataHashtags(hashtags);
|
|
8310
|
+
}
|
|
8311
|
+
}
|
|
7176
8312
|
};
|
|
7177
8313
|
Player.instances = [];
|
|
7178
8314
|
|