vidply 1.0.5 → 1.0.7
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/LICENSE +22 -22
- package/README.md +608 -593
- package/dist/vidply.css +2422 -1807
- package/dist/vidply.esm.js +1480 -93
- package/dist/vidply.esm.js.map +3 -3
- package/dist/vidply.esm.min.js +3 -3
- package/dist/vidply.esm.min.meta.json +48 -25
- package/dist/vidply.js +1480 -93
- 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 +48 -25
- package/package.json +2 -2
- package/src/controls/CaptionManager.js +278 -248
- package/src/controls/ControlBar.js +2033 -2026
- package/src/controls/KeyboardManager.js +233 -233
- package/src/controls/SettingsDialog.js +417 -417
- package/src/controls/TranscriptManager.js +1803 -728
- package/src/core/Player.js +1616 -1134
- package/src/i18n/i18n.js +66 -66
- package/src/i18n/translations.js +616 -561
- package/src/icons/Icons.js +187 -183
- package/src/index.js +95 -95
- package/src/renderers/HLSRenderer.js +302 -302
- package/src/renderers/HTML5Renderer.js +298 -298
- package/src/renderers/VimeoRenderer.js +257 -257
- package/src/renderers/YouTubeRenderer.js +274 -274
- package/src/styles/vidply.css +2422 -1807
- package/src/utils/DOMUtils.js +154 -154
- package/src/utils/EventEmitter.js +53 -53
- package/src/utils/StorageManager.js +156 -0
- package/src/utils/TimeUtils.js +87 -87
package/dist/vidply.js
CHANGED
|
@@ -468,7 +468,11 @@ var VidPly = (() => {
|
|
|
468
468
|
noCaptions: "No captions available",
|
|
469
469
|
auto: "Auto",
|
|
470
470
|
autoQuality: "Auto (no quality selection available)",
|
|
471
|
-
noQuality: "Quality selection not available"
|
|
471
|
+
noQuality: "Quality selection not available",
|
|
472
|
+
signLanguageDragResize: "Sign Language Video - Press D to drag with keyboard, R to resize",
|
|
473
|
+
signLanguageDragActive: "Sign Language Video - Drag mode active. Use arrow keys to move, Escape to exit.",
|
|
474
|
+
signLanguageResizeActive: "Sign Language Video - Resize mode active. Use left/right arrow keys to resize, Escape to exit.",
|
|
475
|
+
resizeHandle: "Resize {direction} corner"
|
|
472
476
|
},
|
|
473
477
|
captions: {
|
|
474
478
|
off: "Off",
|
|
@@ -481,7 +485,7 @@ var VidPly = (() => {
|
|
|
481
485
|
},
|
|
482
486
|
fontSizes: {
|
|
483
487
|
small: "Small",
|
|
484
|
-
|
|
488
|
+
normal: "Normal",
|
|
485
489
|
large: "Large",
|
|
486
490
|
xlarge: "X-Large"
|
|
487
491
|
},
|
|
@@ -509,7 +513,14 @@ var VidPly = (() => {
|
|
|
509
513
|
title: "Transcript",
|
|
510
514
|
close: "Close transcript",
|
|
511
515
|
loading: "Loading transcript...",
|
|
512
|
-
noTranscript: "No transcript available for this video."
|
|
516
|
+
noTranscript: "No transcript available for this video.",
|
|
517
|
+
settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
|
|
518
|
+
keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
|
|
519
|
+
keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
|
|
520
|
+
resizeWindow: "Resize Window",
|
|
521
|
+
styleTranscript: "Open transcript style settings",
|
|
522
|
+
closeMenu: "Close Menu",
|
|
523
|
+
styleTitle: "Transcript Style"
|
|
513
524
|
},
|
|
514
525
|
settings: {
|
|
515
526
|
title: "Settings",
|
|
@@ -578,7 +589,11 @@ var VidPly = (() => {
|
|
|
578
589
|
noCaptions: "Keine Untertitel verf\xFCgbar",
|
|
579
590
|
auto: "Automatisch",
|
|
580
591
|
autoQuality: "Automatisch (keine Qualit\xE4tsauswahl verf\xFCgbar)",
|
|
581
|
-
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar"
|
|
592
|
+
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar",
|
|
593
|
+
signLanguageDragResize: "Geb\xE4rdensprache-Video - Dr\xFCcken Sie D zum Verschieben per Tastatur, R zum \xC4ndern der Gr\xF6\xDFe",
|
|
594
|
+
signLanguageDragActive: "Geb\xE4rdensprache-Video - Verschiebemodus aktiv. Pfeiltasten zum Bewegen, Escape zum Beenden.",
|
|
595
|
+
signLanguageResizeActive: "Geb\xE4rdensprache-Video - Gr\xF6\xDFen\xE4nderungsmodus aktiv. Links-/Rechts-Pfeiltasten zum \xC4ndern der Gr\xF6\xDFe, Escape zum Beenden.",
|
|
596
|
+
resizeHandle: "Gr\xF6\xDFen\xE4nderung {direction}-Ecke"
|
|
582
597
|
},
|
|
583
598
|
captions: {
|
|
584
599
|
off: "Aus",
|
|
@@ -591,7 +606,7 @@ var VidPly = (() => {
|
|
|
591
606
|
},
|
|
592
607
|
fontSizes: {
|
|
593
608
|
small: "Klein",
|
|
594
|
-
|
|
609
|
+
normal: "Normal",
|
|
595
610
|
large: "Gro\xDF",
|
|
596
611
|
xlarge: "Sehr gro\xDF"
|
|
597
612
|
},
|
|
@@ -619,7 +634,14 @@ var VidPly = (() => {
|
|
|
619
634
|
title: "Transkript",
|
|
620
635
|
close: "Transkript schlie\xDFen",
|
|
621
636
|
loading: "Transkript wird geladen...",
|
|
622
|
-
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar."
|
|
637
|
+
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar.",
|
|
638
|
+
settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
|
|
639
|
+
keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
|
|
640
|
+
keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
|
|
641
|
+
resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
|
|
642
|
+
styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
|
|
643
|
+
closeMenu: "Men\xFC schlie\xDFen",
|
|
644
|
+
styleTitle: "Transkript-Stil"
|
|
623
645
|
},
|
|
624
646
|
settings: {
|
|
625
647
|
title: "Einstellungen",
|
|
@@ -688,7 +710,11 @@ var VidPly = (() => {
|
|
|
688
710
|
noCaptions: "No hay subt\xEDtulos disponibles",
|
|
689
711
|
auto: "Autom\xE1tico",
|
|
690
712
|
autoQuality: "Autom\xE1tico (selecci\xF3n de calidad no disponible)",
|
|
691
|
-
noQuality: "Selecci\xF3n de calidad no disponible"
|
|
713
|
+
noQuality: "Selecci\xF3n de calidad no disponible",
|
|
714
|
+
signLanguageDragResize: "Video en Lengua de Se\xF1as - Presione D para arrastrar con el teclado, R para cambiar el tama\xF1o",
|
|
715
|
+
signLanguageDragActive: "Video en Lengua de Se\xF1as - Modo de arrastre activo. Use las teclas de flecha para mover, Escape para salir.",
|
|
716
|
+
signLanguageResizeActive: "Video en Lengua de Se\xF1as - Modo de cambio de tama\xF1o activo. Use las teclas de flecha izquierda/derecha para cambiar el tama\xF1o, Escape para salir.",
|
|
717
|
+
resizeHandle: "Cambiar tama\xF1o esquina {direction}"
|
|
692
718
|
},
|
|
693
719
|
captions: {
|
|
694
720
|
off: "Desactivado",
|
|
@@ -701,7 +727,7 @@ var VidPly = (() => {
|
|
|
701
727
|
},
|
|
702
728
|
fontSizes: {
|
|
703
729
|
small: "Peque\xF1o",
|
|
704
|
-
|
|
730
|
+
normal: "Normal",
|
|
705
731
|
large: "Grande",
|
|
706
732
|
xlarge: "Muy grande"
|
|
707
733
|
},
|
|
@@ -729,7 +755,14 @@ var VidPly = (() => {
|
|
|
729
755
|
title: "Transcripci\xF3n",
|
|
730
756
|
close: "Cerrar transcripci\xF3n",
|
|
731
757
|
loading: "Cargando transcripci\xF3n...",
|
|
732
|
-
noTranscript: "No hay transcripci\xF3n disponible para este video."
|
|
758
|
+
noTranscript: "No hay transcripci\xF3n disponible para este video.",
|
|
759
|
+
settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
|
|
760
|
+
keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
|
|
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
|
+
resizeWindow: "Cambiar tama\xF1o de ventana",
|
|
763
|
+
styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
|
|
764
|
+
closeMenu: "Cerrar men\xFA",
|
|
765
|
+
styleTitle: "Estilo de Transcripci\xF3n"
|
|
733
766
|
},
|
|
734
767
|
settings: {
|
|
735
768
|
title: "Configuraci\xF3n",
|
|
@@ -798,7 +831,11 @@ var VidPly = (() => {
|
|
|
798
831
|
noCaptions: "Aucun sous-titre disponible",
|
|
799
832
|
auto: "Automatique",
|
|
800
833
|
autoQuality: "Automatique (s\xE9lection de qualit\xE9 non disponible)",
|
|
801
|
-
noQuality: "S\xE9lection de qualit\xE9 non disponible"
|
|
834
|
+
noQuality: "S\xE9lection de qualit\xE9 non disponible",
|
|
835
|
+
signLanguageDragResize: "Vid\xE9o en Langue des Signes - Appuyez sur D pour d\xE9placer avec le clavier, R pour redimensionner",
|
|
836
|
+
signLanguageDragActive: "Vid\xE9o en Langue des Signes - Mode glissement actif. Utilisez les touches fl\xE9ch\xE9es pour d\xE9placer, \xC9chap pour quitter.",
|
|
837
|
+
signLanguageResizeActive: "Vid\xE9o en Langue des Signes - Mode redimensionnement actif. Utilisez les touches fl\xE9ch\xE9es gauche/droite pour redimensionner, \xC9chap pour quitter.",
|
|
838
|
+
resizeHandle: "Redimensionner coin {direction}"
|
|
802
839
|
},
|
|
803
840
|
captions: {
|
|
804
841
|
off: "D\xE9sactiv\xE9",
|
|
@@ -811,7 +848,7 @@ var VidPly = (() => {
|
|
|
811
848
|
},
|
|
812
849
|
fontSizes: {
|
|
813
850
|
small: "Petit",
|
|
814
|
-
|
|
851
|
+
normal: "Normal",
|
|
815
852
|
large: "Grand",
|
|
816
853
|
xlarge: "Tr\xE8s grand"
|
|
817
854
|
},
|
|
@@ -839,7 +876,14 @@ var VidPly = (() => {
|
|
|
839
876
|
title: "Transcription",
|
|
840
877
|
close: "Fermer la transcription",
|
|
841
878
|
loading: "Chargement de la transcription...",
|
|
842
|
-
noTranscript: "Aucune transcription disponible pour cette vid\xE9o."
|
|
879
|
+
noTranscript: "Aucune transcription disponible pour cette vid\xE9o.",
|
|
880
|
+
settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
|
|
881
|
+
keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
|
|
882
|
+
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)",
|
|
883
|
+
resizeWindow: "Redimensionner la fen\xEAtre",
|
|
884
|
+
styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
|
|
885
|
+
closeMenu: "Fermer le menu",
|
|
886
|
+
styleTitle: "Style de Transcription"
|
|
843
887
|
},
|
|
844
888
|
settings: {
|
|
845
889
|
title: "Param\xE8tres",
|
|
@@ -908,7 +952,11 @@ var VidPly = (() => {
|
|
|
908
952
|
noCaptions: "\u5B57\u5E55\u304C\u3042\u308A\u307E\u305B\u3093",
|
|
909
953
|
auto: "\u81EA\u52D5",
|
|
910
954
|
autoQuality: "\u81EA\u52D5\uFF08\u753B\u8CEA\u9078\u629E\u4E0D\u53EF\uFF09",
|
|
911
|
-
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF"
|
|
955
|
+
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF",
|
|
956
|
+
signLanguageDragResize: "\u624B\u8A71\u52D5\u753B - \u30AD\u30FC\u30DC\u30FC\u30C9\u3067\u30C9\u30E9\u30C3\u30B0\u3059\u308B\u306B\u306FD\u30AD\u30FC\u3092\u3001\u30B5\u30A4\u30BA\u5909\u66F4\u3059\u308B\u306B\u306FR\u30AD\u30FC\u3092\u62BC\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
957
|
+
signLanguageDragActive: "\u624B\u8A71\u52D5\u753B - \u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u304C\u6709\u52B9\u3067\u3059\u3002\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Escape\u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
|
|
958
|
+
signLanguageResizeActive: "\u624B\u8A71\u52D5\u753B - \u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u304C\u6709\u52B9\u3067\u3059\u3002\u5DE6\u53F3\u306E\u77E2\u5370\u30AD\u30FC\u3067\u30B5\u30A4\u30BA\u5909\u66F4\u3001Escape\u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
|
|
959
|
+
resizeHandle: "{direction}\u30B3\u30FC\u30CA\u30FC\u306E\u30B5\u30A4\u30BA\u5909\u66F4"
|
|
912
960
|
},
|
|
913
961
|
captions: {
|
|
914
962
|
off: "\u30AA\u30D5",
|
|
@@ -921,7 +969,7 @@ var VidPly = (() => {
|
|
|
921
969
|
},
|
|
922
970
|
fontSizes: {
|
|
923
971
|
small: "\u5C0F",
|
|
924
|
-
|
|
972
|
+
normal: "\u6A19\u6E96",
|
|
925
973
|
large: "\u5927",
|
|
926
974
|
xlarge: "\u7279\u5927"
|
|
927
975
|
},
|
|
@@ -949,7 +997,14 @@ var VidPly = (() => {
|
|
|
949
997
|
title: "\u6587\u5B57\u8D77\u3053\u3057",
|
|
950
998
|
close: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u9589\u3058\u308B",
|
|
951
999
|
loading: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D...",
|
|
952
|
-
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002"
|
|
1000
|
+
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
1001
|
+
settings: "\u6587\u5B57\u8D77\u3053\u3057\u8A2D\u5B9A\u3002Enter\u30AD\u30FC\u3067\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F\u3001\u307E\u305F\u306FD\u30AD\u30FC\u3067\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3059\u308B",
|
|
1002
|
+
keyboardDragMode: "\u77E2\u5370\u30AD\u30FC\u3067\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u5207\u308A\u66FF\u3048\u3002\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8\uFF1AD\u30AD\u30FC",
|
|
1003
|
+
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",
|
|
1004
|
+
resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
|
|
1005
|
+
styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
|
|
1006
|
+
closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
|
|
1007
|
+
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB"
|
|
953
1008
|
},
|
|
954
1009
|
settings: {
|
|
955
1010
|
title: "\u8A2D\u5B9A",
|
|
@@ -1128,14 +1183,16 @@ var VidPly = (() => {
|
|
|
1128
1183
|
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"/>`,
|
|
1129
1184
|
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"/>`,
|
|
1130
1185
|
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"/>`,
|
|
1131
|
-
audioDescription: `<
|
|
1132
|
-
audioDescriptionOn: `<
|
|
1186
|
+
audioDescription: `<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>`,
|
|
1187
|
+
audioDescriptionOn: `<rect x="2" y="5" width="20" height="14" rx="2" fill="#1a1a1a" stroke="#1a1a1a" stroke-width="2"/><text x="12" y="16" font-family="Arial, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" fill="#ffffff">AD</text>`,
|
|
1133
1188
|
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>`,
|
|
1134
1189
|
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>`,
|
|
1135
1190
|
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"/>`,
|
|
1136
1191
|
music: `<path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7zm-1.5 16c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>`,
|
|
1137
1192
|
moreVertical: `<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>`,
|
|
1138
|
-
moreHorizontal: `<path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
|
1193
|
+
moreHorizontal: `<path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>`,
|
|
1194
|
+
move: `<path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"/>`,
|
|
1195
|
+
resize: `<path d="M21.71 11.29l-9-9c-.39-.39-1.02-.39-1.41 0l-9 9c-.39.39-.39 1.02 0 1.41l9 9c.39.39 1.02.39 1.41 0l9-9c.39-.38.39-1.01 0-1.41zM14 14.5V12h-4v2.5L7 11l3-3.5V10h4V7.5l3 3.5-3 3.5z"/>`
|
|
1139
1196
|
};
|
|
1140
1197
|
var svgWrapper = (paths) => `<svg viewBox="0 0 24 24" fill="currentColor">${paths}</svg>`;
|
|
1141
1198
|
var Icons = Object.fromEntries(
|
|
@@ -1431,7 +1488,11 @@ var VidPly = (() => {
|
|
|
1431
1488
|
return false;
|
|
1432
1489
|
}
|
|
1433
1490
|
hasAudioDescription() {
|
|
1434
|
-
|
|
1491
|
+
if (this.player.audioDescriptionSrc && this.player.audioDescriptionSrc.length > 0) {
|
|
1492
|
+
return true;
|
|
1493
|
+
}
|
|
1494
|
+
const textTracks = Array.from(this.player.element.textTracks || []);
|
|
1495
|
+
return textTracks.some((track) => track.kind === "descriptions");
|
|
1435
1496
|
}
|
|
1436
1497
|
hasSignLanguage() {
|
|
1437
1498
|
return this.player.signLanguageSrc && this.player.signLanguageSrc.length > 0;
|
|
@@ -2042,9 +2103,9 @@ var VidPly = (() => {
|
|
|
2042
2103
|
i18n.t("styleLabels.fontSize"),
|
|
2043
2104
|
"captionsFontSize",
|
|
2044
2105
|
[
|
|
2045
|
-
{ label: i18n.t("fontSizes.small"), value: "
|
|
2046
|
-
{ label: i18n.t("fontSizes.
|
|
2047
|
-
{ label: i18n.t("fontSizes.large"), value: "
|
|
2106
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
2107
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
2108
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
2048
2109
|
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
2049
2110
|
]
|
|
2050
2111
|
);
|
|
@@ -2733,6 +2794,141 @@ var VidPly = (() => {
|
|
|
2733
2794
|
}
|
|
2734
2795
|
};
|
|
2735
2796
|
|
|
2797
|
+
// src/utils/StorageManager.js
|
|
2798
|
+
var StorageManager = class {
|
|
2799
|
+
constructor(namespace = "vidply") {
|
|
2800
|
+
this.namespace = namespace;
|
|
2801
|
+
this.storage = this.isStorageAvailable() ? localStorage : null;
|
|
2802
|
+
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Check if localStorage is available
|
|
2805
|
+
*/
|
|
2806
|
+
isStorageAvailable() {
|
|
2807
|
+
try {
|
|
2808
|
+
const test = "__storage_test__";
|
|
2809
|
+
localStorage.setItem(test, test);
|
|
2810
|
+
localStorage.removeItem(test);
|
|
2811
|
+
return true;
|
|
2812
|
+
} catch (e) {
|
|
2813
|
+
return false;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
/**
|
|
2817
|
+
* Get a namespaced key
|
|
2818
|
+
*/
|
|
2819
|
+
getKey(key) {
|
|
2820
|
+
return `${this.namespace}_${key}`;
|
|
2821
|
+
}
|
|
2822
|
+
/**
|
|
2823
|
+
* Save a value to storage
|
|
2824
|
+
*/
|
|
2825
|
+
set(key, value) {
|
|
2826
|
+
if (!this.storage) return false;
|
|
2827
|
+
try {
|
|
2828
|
+
const namespacedKey = this.getKey(key);
|
|
2829
|
+
this.storage.setItem(namespacedKey, JSON.stringify(value));
|
|
2830
|
+
return true;
|
|
2831
|
+
} catch (e) {
|
|
2832
|
+
console.warn("Failed to save to localStorage:", e);
|
|
2833
|
+
return false;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
/**
|
|
2837
|
+
* Get a value from storage
|
|
2838
|
+
*/
|
|
2839
|
+
get(key, defaultValue = null) {
|
|
2840
|
+
if (!this.storage) return defaultValue;
|
|
2841
|
+
try {
|
|
2842
|
+
const namespacedKey = this.getKey(key);
|
|
2843
|
+
const value = this.storage.getItem(namespacedKey);
|
|
2844
|
+
return value ? JSON.parse(value) : defaultValue;
|
|
2845
|
+
} catch (e) {
|
|
2846
|
+
console.warn("Failed to read from localStorage:", e);
|
|
2847
|
+
return defaultValue;
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
/**
|
|
2851
|
+
* Remove a value from storage
|
|
2852
|
+
*/
|
|
2853
|
+
remove(key) {
|
|
2854
|
+
if (!this.storage) return false;
|
|
2855
|
+
try {
|
|
2856
|
+
const namespacedKey = this.getKey(key);
|
|
2857
|
+
this.storage.removeItem(namespacedKey);
|
|
2858
|
+
return true;
|
|
2859
|
+
} catch (e) {
|
|
2860
|
+
console.warn("Failed to remove from localStorage:", e);
|
|
2861
|
+
return false;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
/**
|
|
2865
|
+
* Clear all namespaced values
|
|
2866
|
+
*/
|
|
2867
|
+
clear() {
|
|
2868
|
+
if (!this.storage) return false;
|
|
2869
|
+
try {
|
|
2870
|
+
const keys = Object.keys(this.storage);
|
|
2871
|
+
keys.forEach((key) => {
|
|
2872
|
+
if (key.startsWith(this.namespace)) {
|
|
2873
|
+
this.storage.removeItem(key);
|
|
2874
|
+
}
|
|
2875
|
+
});
|
|
2876
|
+
return true;
|
|
2877
|
+
} catch (e) {
|
|
2878
|
+
console.warn("Failed to clear localStorage:", e);
|
|
2879
|
+
return false;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Save transcript preferences
|
|
2884
|
+
*/
|
|
2885
|
+
saveTranscriptPreferences(preferences) {
|
|
2886
|
+
return this.set("transcript_preferences", preferences);
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* Get transcript preferences
|
|
2890
|
+
*/
|
|
2891
|
+
getTranscriptPreferences() {
|
|
2892
|
+
return this.get("transcript_preferences", null);
|
|
2893
|
+
}
|
|
2894
|
+
/**
|
|
2895
|
+
* Save caption preferences
|
|
2896
|
+
*/
|
|
2897
|
+
saveCaptionPreferences(preferences) {
|
|
2898
|
+
return this.set("caption_preferences", preferences);
|
|
2899
|
+
}
|
|
2900
|
+
/**
|
|
2901
|
+
* Get caption preferences
|
|
2902
|
+
*/
|
|
2903
|
+
getCaptionPreferences() {
|
|
2904
|
+
return this.get("caption_preferences", null);
|
|
2905
|
+
}
|
|
2906
|
+
/**
|
|
2907
|
+
* Save player preferences (volume, speed, etc.)
|
|
2908
|
+
*/
|
|
2909
|
+
savePlayerPreferences(preferences) {
|
|
2910
|
+
return this.set("player_preferences", preferences);
|
|
2911
|
+
}
|
|
2912
|
+
/**
|
|
2913
|
+
* Get player preferences
|
|
2914
|
+
*/
|
|
2915
|
+
getPlayerPreferences() {
|
|
2916
|
+
return this.get("player_preferences", null);
|
|
2917
|
+
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Save sign language preferences (position and size)
|
|
2920
|
+
*/
|
|
2921
|
+
saveSignLanguagePreferences(preferences) {
|
|
2922
|
+
return this.set("sign_language_preferences", preferences);
|
|
2923
|
+
}
|
|
2924
|
+
/**
|
|
2925
|
+
* Get sign language preferences
|
|
2926
|
+
*/
|
|
2927
|
+
getSignLanguagePreferences() {
|
|
2928
|
+
return this.get("sign_language_preferences", null);
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
|
|
2736
2932
|
// src/controls/CaptionManager.js
|
|
2737
2933
|
var CaptionManager = class {
|
|
2738
2934
|
constructor(player) {
|
|
@@ -2741,8 +2937,29 @@ var VidPly = (() => {
|
|
|
2741
2937
|
this.tracks = [];
|
|
2742
2938
|
this.currentTrack = null;
|
|
2743
2939
|
this.currentCue = null;
|
|
2940
|
+
this.storage = new StorageManager("vidply");
|
|
2941
|
+
this.loadSavedPreferences();
|
|
2744
2942
|
this.init();
|
|
2745
2943
|
}
|
|
2944
|
+
loadSavedPreferences() {
|
|
2945
|
+
const saved = this.storage.getCaptionPreferences();
|
|
2946
|
+
if (saved) {
|
|
2947
|
+
if (saved.fontSize) this.player.options.captionsFontSize = saved.fontSize;
|
|
2948
|
+
if (saved.fontFamily) this.player.options.captionsFontFamily = saved.fontFamily;
|
|
2949
|
+
if (saved.color) this.player.options.captionsColor = saved.color;
|
|
2950
|
+
if (saved.backgroundColor) this.player.options.captionsBackgroundColor = saved.backgroundColor;
|
|
2951
|
+
if (saved.opacity !== void 0) this.player.options.captionsOpacity = saved.opacity;
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
saveCaptionPreferences() {
|
|
2955
|
+
this.storage.saveCaptionPreferences({
|
|
2956
|
+
fontSize: this.player.options.captionsFontSize,
|
|
2957
|
+
fontFamily: this.player.options.captionsFontFamily,
|
|
2958
|
+
color: this.player.options.captionsColor,
|
|
2959
|
+
backgroundColor: this.player.options.captionsBackgroundColor,
|
|
2960
|
+
opacity: this.player.options.captionsOpacity
|
|
2961
|
+
});
|
|
2962
|
+
}
|
|
2746
2963
|
init() {
|
|
2747
2964
|
this.createElement();
|
|
2748
2965
|
this.loadTracks();
|
|
@@ -2891,6 +3108,7 @@ var VidPly = (() => {
|
|
|
2891
3108
|
break;
|
|
2892
3109
|
}
|
|
2893
3110
|
this.updateStyles();
|
|
3111
|
+
this.saveCaptionPreferences();
|
|
2894
3112
|
this.player.emit("captionschange");
|
|
2895
3113
|
}
|
|
2896
3114
|
getAvailableTracks() {
|
|
@@ -3101,11 +3319,36 @@ var VidPly = (() => {
|
|
|
3101
3319
|
this.player = player;
|
|
3102
3320
|
this.transcriptWindow = null;
|
|
3103
3321
|
this.transcriptEntries = [];
|
|
3322
|
+
this.metadataCues = [];
|
|
3104
3323
|
this.currentActiveEntry = null;
|
|
3105
3324
|
this.isVisible = false;
|
|
3325
|
+
this.storage = new StorageManager("vidply");
|
|
3106
3326
|
this.isDragging = false;
|
|
3107
3327
|
this.dragOffsetX = 0;
|
|
3108
3328
|
this.dragOffsetY = 0;
|
|
3329
|
+
this.isResizing = false;
|
|
3330
|
+
this.resizeDirection = null;
|
|
3331
|
+
this.resizeStartX = 0;
|
|
3332
|
+
this.resizeStartY = 0;
|
|
3333
|
+
this.resizeStartWidth = 0;
|
|
3334
|
+
this.resizeStartHeight = 0;
|
|
3335
|
+
this.resizeEnabled = false;
|
|
3336
|
+
this.settingsMenuVisible = false;
|
|
3337
|
+
this.settingsMenu = null;
|
|
3338
|
+
this.settingsButton = null;
|
|
3339
|
+
this.settingsMenuJustOpened = false;
|
|
3340
|
+
this.keyboardDragMode = false;
|
|
3341
|
+
this.styleDialog = null;
|
|
3342
|
+
this.styleDialogVisible = false;
|
|
3343
|
+
this.styleDialogJustOpened = false;
|
|
3344
|
+
const savedPreferences = this.storage.getTranscriptPreferences();
|
|
3345
|
+
this.transcriptStyle = {
|
|
3346
|
+
fontSize: (savedPreferences == null ? void 0 : savedPreferences.fontSize) || this.player.options.transcriptFontSize || "100%",
|
|
3347
|
+
fontFamily: (savedPreferences == null ? void 0 : savedPreferences.fontFamily) || this.player.options.transcriptFontFamily || "sans-serif",
|
|
3348
|
+
color: (savedPreferences == null ? void 0 : savedPreferences.color) || this.player.options.transcriptColor || "#ffffff",
|
|
3349
|
+
backgroundColor: (savedPreferences == null ? void 0 : savedPreferences.backgroundColor) || this.player.options.transcriptBackgroundColor || "#1e1e1e",
|
|
3350
|
+
opacity: (savedPreferences == null ? void 0 : savedPreferences.opacity) ?? this.player.options.transcriptOpacity ?? 0.98
|
|
3351
|
+
};
|
|
3109
3352
|
this.handlers = {
|
|
3110
3353
|
timeupdate: () => this.updateActiveEntry(),
|
|
3111
3354
|
resize: null,
|
|
@@ -3115,7 +3358,11 @@ var VidPly = (() => {
|
|
|
3115
3358
|
touchend: null,
|
|
3116
3359
|
mousedown: null,
|
|
3117
3360
|
touchstart: null,
|
|
3118
|
-
keydown: null
|
|
3361
|
+
keydown: null,
|
|
3362
|
+
settingsClick: null,
|
|
3363
|
+
settingsKeydown: null,
|
|
3364
|
+
documentClick: null,
|
|
3365
|
+
styleDialogKeydown: null
|
|
3119
3366
|
};
|
|
3120
3367
|
this.init();
|
|
3121
3368
|
}
|
|
@@ -3144,6 +3391,11 @@ var VidPly = (() => {
|
|
|
3144
3391
|
if (this.transcriptWindow) {
|
|
3145
3392
|
this.transcriptWindow.style.display = "flex";
|
|
3146
3393
|
this.isVisible = true;
|
|
3394
|
+
setTimeout(() => {
|
|
3395
|
+
if (this.settingsButton) {
|
|
3396
|
+
this.settingsButton.focus();
|
|
3397
|
+
}
|
|
3398
|
+
}, 150);
|
|
3147
3399
|
return;
|
|
3148
3400
|
}
|
|
3149
3401
|
this.createTranscriptWindow();
|
|
@@ -3151,6 +3403,11 @@ var VidPly = (() => {
|
|
|
3151
3403
|
if (this.transcriptWindow) {
|
|
3152
3404
|
this.transcriptWindow.style.display = "flex";
|
|
3153
3405
|
setTimeout(() => this.positionTranscript(), 0);
|
|
3406
|
+
setTimeout(() => {
|
|
3407
|
+
if (this.settingsButton) {
|
|
3408
|
+
this.settingsButton.focus();
|
|
3409
|
+
}
|
|
3410
|
+
}, 150);
|
|
3154
3411
|
}
|
|
3155
3412
|
this.isVisible = true;
|
|
3156
3413
|
}
|
|
@@ -3182,9 +3439,49 @@ var VidPly = (() => {
|
|
|
3182
3439
|
"tabindex": "0"
|
|
3183
3440
|
}
|
|
3184
3441
|
});
|
|
3442
|
+
this.headerLeft = DOMUtils.createElement("div", {
|
|
3443
|
+
className: `${this.player.options.classPrefix}-transcript-header-left`
|
|
3444
|
+
});
|
|
3445
|
+
this.settingsButton = DOMUtils.createElement("button", {
|
|
3446
|
+
className: `${this.player.options.classPrefix}-transcript-settings`,
|
|
3447
|
+
attributes: {
|
|
3448
|
+
"type": "button",
|
|
3449
|
+
"aria-label": i18n.t("transcript.settings"),
|
|
3450
|
+
"aria-expanded": "false"
|
|
3451
|
+
}
|
|
3452
|
+
});
|
|
3453
|
+
this.settingsButton.appendChild(createIconElement("settings"));
|
|
3454
|
+
this.handlers.settingsClick = (e) => {
|
|
3455
|
+
e.preventDefault();
|
|
3456
|
+
e.stopPropagation();
|
|
3457
|
+
if (this.settingsMenuVisible) {
|
|
3458
|
+
this.hideSettingsMenu();
|
|
3459
|
+
} else {
|
|
3460
|
+
this.showSettingsMenu();
|
|
3461
|
+
}
|
|
3462
|
+
};
|
|
3463
|
+
this.settingsButton.addEventListener("click", this.handlers.settingsClick);
|
|
3464
|
+
this.handlers.settingsKeydown = (e) => {
|
|
3465
|
+
if (e.key === "d" || e.key === "D") {
|
|
3466
|
+
e.preventDefault();
|
|
3467
|
+
e.stopPropagation();
|
|
3468
|
+
this.toggleKeyboardDragMode();
|
|
3469
|
+
} else if (e.key === "r" || e.key === "R") {
|
|
3470
|
+
e.preventDefault();
|
|
3471
|
+
e.stopPropagation();
|
|
3472
|
+
this.toggleResizeMode();
|
|
3473
|
+
} else if (e.key === "Escape" && this.settingsMenuVisible) {
|
|
3474
|
+
e.preventDefault();
|
|
3475
|
+
e.stopPropagation();
|
|
3476
|
+
this.hideSettingsMenu();
|
|
3477
|
+
}
|
|
3478
|
+
};
|
|
3479
|
+
this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
|
|
3185
3480
|
const title = DOMUtils.createElement("h3", {
|
|
3186
3481
|
textContent: i18n.t("transcript.title")
|
|
3187
3482
|
});
|
|
3483
|
+
this.headerLeft.appendChild(this.settingsButton);
|
|
3484
|
+
this.headerLeft.appendChild(title);
|
|
3188
3485
|
const closeButton = DOMUtils.createElement("button", {
|
|
3189
3486
|
className: `${this.player.options.classPrefix}-transcript-close`,
|
|
3190
3487
|
attributes: {
|
|
@@ -3194,7 +3491,7 @@ var VidPly = (() => {
|
|
|
3194
3491
|
});
|
|
3195
3492
|
closeButton.appendChild(createIconElement("close"));
|
|
3196
3493
|
closeButton.addEventListener("click", () => this.hideTranscript());
|
|
3197
|
-
this.transcriptHeader.appendChild(
|
|
3494
|
+
this.transcriptHeader.appendChild(this.headerLeft);
|
|
3198
3495
|
this.transcriptHeader.appendChild(closeButton);
|
|
3199
3496
|
this.transcriptContent = DOMUtils.createElement("div", {
|
|
3200
3497
|
className: `${this.player.options.classPrefix}-transcript-content`
|
|
@@ -3204,6 +3501,27 @@ var VidPly = (() => {
|
|
|
3204
3501
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3205
3502
|
this.positionTranscript();
|
|
3206
3503
|
this.setupDragAndDrop();
|
|
3504
|
+
this.handlers.documentClick = (e) => {
|
|
3505
|
+
if (this.settingsMenuJustOpened) {
|
|
3506
|
+
return;
|
|
3507
|
+
}
|
|
3508
|
+
if (this.styleDialogJustOpened) {
|
|
3509
|
+
return;
|
|
3510
|
+
}
|
|
3511
|
+
if (this.settingsButton && this.settingsButton.contains(e.target)) {
|
|
3512
|
+
return;
|
|
3513
|
+
}
|
|
3514
|
+
if (this.settingsMenu && this.settingsMenu.contains(e.target)) {
|
|
3515
|
+
return;
|
|
3516
|
+
}
|
|
3517
|
+
if (this.settingsMenuVisible) {
|
|
3518
|
+
this.hideSettingsMenu();
|
|
3519
|
+
}
|
|
3520
|
+
if (this.styleDialogVisible && this.styleDialog && !this.styleDialog.contains(e.target)) {
|
|
3521
|
+
this.hideStyleDialog();
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
this.documentClickHandlerAdded = false;
|
|
3207
3525
|
let resizeTimeout;
|
|
3208
3526
|
this.handlers.resize = () => {
|
|
3209
3527
|
clearTimeout(resizeTimeout);
|
|
@@ -3284,54 +3602,133 @@ var VidPly = (() => {
|
|
|
3284
3602
|
this.transcriptEntries = [];
|
|
3285
3603
|
this.transcriptContent.innerHTML = "";
|
|
3286
3604
|
const textTracks = Array.from(this.player.element.textTracks);
|
|
3287
|
-
const
|
|
3605
|
+
const captionTrack = textTracks.find(
|
|
3288
3606
|
(track) => track.kind === "captions" || track.kind === "subtitles"
|
|
3289
3607
|
);
|
|
3290
|
-
|
|
3608
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
3609
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3610
|
+
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3291
3611
|
this.showNoTranscriptMessage();
|
|
3292
3612
|
return;
|
|
3293
3613
|
}
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3614
|
+
const tracksToLoad = [captionTrack, descriptionTrack, metadataTrack].filter(Boolean);
|
|
3615
|
+
tracksToLoad.forEach((track) => {
|
|
3616
|
+
if (track.mode === "disabled") {
|
|
3617
|
+
track.mode = "hidden";
|
|
3618
|
+
}
|
|
3619
|
+
});
|
|
3620
|
+
const needsLoading = tracksToLoad.some((track) => !track.cues || track.cues.length === 0);
|
|
3621
|
+
if (needsLoading) {
|
|
3298
3622
|
const loadingMessage = DOMUtils.createElement("div", {
|
|
3299
3623
|
className: `${this.player.options.classPrefix}-transcript-loading`,
|
|
3300
3624
|
textContent: i18n.t("transcript.loading")
|
|
3301
3625
|
});
|
|
3302
3626
|
this.transcriptContent.appendChild(loadingMessage);
|
|
3627
|
+
let loaded = 0;
|
|
3303
3628
|
const onLoad = () => {
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
transcriptTrack.addEventListener("load", onLoad, { once: true });
|
|
3307
|
-
setTimeout(() => {
|
|
3308
|
-
if (transcriptTrack.cues && transcriptTrack.cues.length > 0) {
|
|
3629
|
+
loaded++;
|
|
3630
|
+
if (loaded >= tracksToLoad.length) {
|
|
3309
3631
|
this.loadTranscriptData();
|
|
3310
3632
|
}
|
|
3633
|
+
};
|
|
3634
|
+
tracksToLoad.forEach((track) => {
|
|
3635
|
+
track.addEventListener("load", onLoad, { once: true });
|
|
3636
|
+
});
|
|
3637
|
+
setTimeout(() => {
|
|
3638
|
+
this.loadTranscriptData();
|
|
3311
3639
|
}, 500);
|
|
3312
3640
|
return;
|
|
3313
3641
|
}
|
|
3314
|
-
const
|
|
3315
|
-
|
|
3316
|
-
|
|
3642
|
+
const allCues = [];
|
|
3643
|
+
if (captionTrack && captionTrack.cues) {
|
|
3644
|
+
Array.from(captionTrack.cues).forEach((cue) => {
|
|
3645
|
+
allCues.push({ cue, type: "caption" });
|
|
3646
|
+
});
|
|
3647
|
+
}
|
|
3648
|
+
if (descriptionTrack && descriptionTrack.cues) {
|
|
3649
|
+
Array.from(descriptionTrack.cues).forEach((cue) => {
|
|
3650
|
+
allCues.push({ cue, type: "description" });
|
|
3651
|
+
});
|
|
3652
|
+
}
|
|
3653
|
+
if (metadataTrack && metadataTrack.cues) {
|
|
3654
|
+
this.metadataCues = Array.from(metadataTrack.cues);
|
|
3655
|
+
this.setupMetadataHandling();
|
|
3656
|
+
}
|
|
3657
|
+
allCues.sort((a, b) => a.cue.startTime - b.cue.startTime);
|
|
3658
|
+
allCues.forEach((item, index) => {
|
|
3659
|
+
const entry = this.createTranscriptEntry(item.cue, index, item.type);
|
|
3317
3660
|
this.transcriptEntries.push({
|
|
3318
3661
|
element: entry,
|
|
3319
|
-
cue,
|
|
3320
|
-
|
|
3321
|
-
|
|
3662
|
+
cue: item.cue,
|
|
3663
|
+
type: item.type,
|
|
3664
|
+
startTime: item.cue.startTime,
|
|
3665
|
+
endTime: item.cue.endTime
|
|
3322
3666
|
});
|
|
3323
3667
|
this.transcriptContent.appendChild(entry);
|
|
3324
3668
|
});
|
|
3669
|
+
this.applyTranscriptStyles();
|
|
3670
|
+
}
|
|
3671
|
+
/**
|
|
3672
|
+
* Setup metadata handling
|
|
3673
|
+
* Metadata cues are not displayed but can be used programmatically
|
|
3674
|
+
*/
|
|
3675
|
+
setupMetadataHandling() {
|
|
3676
|
+
if (!this.metadataCues || this.metadataCues.length === 0) {
|
|
3677
|
+
return;
|
|
3678
|
+
}
|
|
3679
|
+
const textTracks = Array.from(this.player.element.textTracks);
|
|
3680
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3681
|
+
if (metadataTrack) {
|
|
3682
|
+
metadataTrack.addEventListener("cuechange", () => {
|
|
3683
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3684
|
+
activeCues.forEach((cue) => {
|
|
3685
|
+
this.handleMetadataCue(cue);
|
|
3686
|
+
});
|
|
3687
|
+
});
|
|
3688
|
+
}
|
|
3689
|
+
}
|
|
3690
|
+
/**
|
|
3691
|
+
* Handle individual metadata cues
|
|
3692
|
+
* Parses metadata text and emits events or triggers actions
|
|
3693
|
+
*/
|
|
3694
|
+
handleMetadataCue(cue) {
|
|
3695
|
+
const text = cue.text.trim();
|
|
3696
|
+
this.player.emit("metadata", {
|
|
3697
|
+
time: cue.startTime,
|
|
3698
|
+
endTime: cue.endTime,
|
|
3699
|
+
text,
|
|
3700
|
+
cue
|
|
3701
|
+
});
|
|
3702
|
+
if (text.includes("PAUSE")) {
|
|
3703
|
+
this.player.emit("metadata:pause", { time: cue.startTime, text });
|
|
3704
|
+
}
|
|
3705
|
+
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
3706
|
+
if (focusMatch) {
|
|
3707
|
+
this.player.emit("metadata:focus", {
|
|
3708
|
+
time: cue.startTime,
|
|
3709
|
+
target: focusMatch[1],
|
|
3710
|
+
text
|
|
3711
|
+
});
|
|
3712
|
+
}
|
|
3713
|
+
const hashtags = text.match(/#[\w-]+/g);
|
|
3714
|
+
if (hashtags) {
|
|
3715
|
+
this.player.emit("metadata:hashtags", {
|
|
3716
|
+
time: cue.startTime,
|
|
3717
|
+
hashtags,
|
|
3718
|
+
text
|
|
3719
|
+
});
|
|
3720
|
+
}
|
|
3325
3721
|
}
|
|
3326
3722
|
/**
|
|
3327
3723
|
* Create a single transcript entry element
|
|
3328
3724
|
*/
|
|
3329
|
-
createTranscriptEntry(cue, index) {
|
|
3725
|
+
createTranscriptEntry(cue, index, type = "caption") {
|
|
3330
3726
|
const entry = DOMUtils.createElement("div", {
|
|
3331
|
-
className: `${this.player.options.classPrefix}-transcript-entry`,
|
|
3727
|
+
className: `${this.player.options.classPrefix}-transcript-entry ${this.player.options.classPrefix}-transcript-${type}`,
|
|
3332
3728
|
attributes: {
|
|
3333
3729
|
"data-start": String(cue.startTime),
|
|
3334
3730
|
"data-end": String(cue.endTime),
|
|
3731
|
+
"data-type": type,
|
|
3335
3732
|
"role": "button",
|
|
3336
3733
|
"tabindex": "0"
|
|
3337
3734
|
}
|
|
@@ -3428,6 +3825,15 @@ var VidPly = (() => {
|
|
|
3428
3825
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3429
3826
|
return;
|
|
3430
3827
|
}
|
|
3828
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3829
|
+
return;
|
|
3830
|
+
}
|
|
3831
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3834
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3835
|
+
return;
|
|
3836
|
+
}
|
|
3431
3837
|
this.startDragging(e.clientX, e.clientY);
|
|
3432
3838
|
e.preventDefault();
|
|
3433
3839
|
};
|
|
@@ -3445,6 +3851,15 @@ var VidPly = (() => {
|
|
|
3445
3851
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3446
3852
|
return;
|
|
3447
3853
|
}
|
|
3854
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3855
|
+
return;
|
|
3856
|
+
}
|
|
3857
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3858
|
+
return;
|
|
3859
|
+
}
|
|
3860
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3861
|
+
return;
|
|
3862
|
+
}
|
|
3448
3863
|
const isMobile = window.innerWidth < 640;
|
|
3449
3864
|
const isFullscreen = this.player.state.fullscreen;
|
|
3450
3865
|
const touch = e.touches[0];
|
|
@@ -3471,49 +3886,64 @@ var VidPly = (() => {
|
|
|
3471
3886
|
}
|
|
3472
3887
|
};
|
|
3473
3888
|
this.handlers.keydown = (e) => {
|
|
3474
|
-
if (
|
|
3889
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3890
|
+
if (!this.keyboardDragMode) {
|
|
3891
|
+
return;
|
|
3892
|
+
}
|
|
3893
|
+
e.preventDefault();
|
|
3894
|
+
e.stopPropagation();
|
|
3895
|
+
const step = e.shiftKey ? 50 : 10;
|
|
3896
|
+
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3897
|
+
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3898
|
+
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3899
|
+
if (computedStyle.transform !== "none") {
|
|
3900
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3901
|
+
currentLeft = rect.left;
|
|
3902
|
+
currentTop = rect.top;
|
|
3903
|
+
this.transcriptWindow.style.transform = "none";
|
|
3904
|
+
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3905
|
+
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3906
|
+
}
|
|
3907
|
+
let newX = currentLeft;
|
|
3908
|
+
let newY = currentTop;
|
|
3909
|
+
switch (e.key) {
|
|
3910
|
+
case "ArrowLeft":
|
|
3911
|
+
newX -= step;
|
|
3912
|
+
break;
|
|
3913
|
+
case "ArrowRight":
|
|
3914
|
+
newX += step;
|
|
3915
|
+
break;
|
|
3916
|
+
case "ArrowUp":
|
|
3917
|
+
newY -= step;
|
|
3918
|
+
break;
|
|
3919
|
+
case "ArrowDown":
|
|
3920
|
+
newY += step;
|
|
3921
|
+
break;
|
|
3922
|
+
}
|
|
3923
|
+
this.transcriptWindow.style.left = `${newX}px`;
|
|
3924
|
+
this.transcriptWindow.style.top = `${newY}px`;
|
|
3475
3925
|
return;
|
|
3476
3926
|
}
|
|
3477
|
-
e.preventDefault();
|
|
3478
|
-
e.stopPropagation();
|
|
3479
3927
|
if (e.key === "Home") {
|
|
3928
|
+
e.preventDefault();
|
|
3929
|
+
e.stopPropagation();
|
|
3480
3930
|
this.resetPosition();
|
|
3481
3931
|
return;
|
|
3482
3932
|
}
|
|
3483
3933
|
if (e.key === "Escape") {
|
|
3484
|
-
|
|
3934
|
+
e.preventDefault();
|
|
3935
|
+
e.stopPropagation();
|
|
3936
|
+
if (this.styleDialogVisible) {
|
|
3937
|
+
this.hideStyleDialog();
|
|
3938
|
+
} else if (this.keyboardDragMode) {
|
|
3939
|
+
this.disableKeyboardDragMode();
|
|
3940
|
+
} else if (this.settingsMenuVisible) {
|
|
3941
|
+
this.hideSettingsMenu();
|
|
3942
|
+
} else {
|
|
3943
|
+
this.hideTranscript();
|
|
3944
|
+
}
|
|
3485
3945
|
return;
|
|
3486
3946
|
}
|
|
3487
|
-
const step = e.shiftKey ? 50 : 10;
|
|
3488
|
-
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3489
|
-
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3490
|
-
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3491
|
-
if (computedStyle.transform !== "none") {
|
|
3492
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3493
|
-
currentLeft = rect.left;
|
|
3494
|
-
currentTop = rect.top;
|
|
3495
|
-
this.transcriptWindow.style.transform = "none";
|
|
3496
|
-
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3497
|
-
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3498
|
-
}
|
|
3499
|
-
let newX = currentLeft;
|
|
3500
|
-
let newY = currentTop;
|
|
3501
|
-
switch (e.key) {
|
|
3502
|
-
case "ArrowLeft":
|
|
3503
|
-
newX -= step;
|
|
3504
|
-
break;
|
|
3505
|
-
case "ArrowRight":
|
|
3506
|
-
newX += step;
|
|
3507
|
-
break;
|
|
3508
|
-
case "ArrowUp":
|
|
3509
|
-
newY -= step;
|
|
3510
|
-
break;
|
|
3511
|
-
case "ArrowDown":
|
|
3512
|
-
newY += step;
|
|
3513
|
-
break;
|
|
3514
|
-
}
|
|
3515
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3516
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3517
3947
|
};
|
|
3518
3948
|
this.transcriptHeader.addEventListener("mousedown", this.handlers.mousedown);
|
|
3519
3949
|
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
@@ -3592,10 +4022,602 @@ var VidPly = (() => {
|
|
|
3592
4022
|
this.transcriptWindow.style.top = "50%";
|
|
3593
4023
|
this.transcriptWindow.style.transform = "translate(-50%, -50%)";
|
|
3594
4024
|
}
|
|
4025
|
+
/**
|
|
4026
|
+
* Toggle keyboard drag mode
|
|
4027
|
+
*/
|
|
4028
|
+
toggleKeyboardDragMode() {
|
|
4029
|
+
if (this.keyboardDragMode) {
|
|
4030
|
+
this.disableKeyboardDragMode();
|
|
4031
|
+
} else {
|
|
4032
|
+
this.enableKeyboardDragMode();
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
/**
|
|
4036
|
+
* Enable keyboard drag mode
|
|
4037
|
+
*/
|
|
4038
|
+
enableKeyboardDragMode() {
|
|
4039
|
+
this.keyboardDragMode = true;
|
|
4040
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4041
|
+
if (this.settingsButton) {
|
|
4042
|
+
this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
|
|
4043
|
+
}
|
|
4044
|
+
const indicator = DOMUtils.createElement("div", {
|
|
4045
|
+
className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
|
|
4046
|
+
textContent: i18n.t("transcript.keyboardDragActive")
|
|
4047
|
+
});
|
|
4048
|
+
this.transcriptHeader.appendChild(indicator);
|
|
4049
|
+
if (this.settingsMenuVisible) {
|
|
4050
|
+
this.hideSettingsMenu();
|
|
4051
|
+
}
|
|
4052
|
+
this.transcriptHeader.focus();
|
|
4053
|
+
}
|
|
4054
|
+
/**
|
|
4055
|
+
* Disable keyboard drag mode
|
|
4056
|
+
*/
|
|
4057
|
+
disableKeyboardDragMode() {
|
|
4058
|
+
this.keyboardDragMode = false;
|
|
4059
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4060
|
+
if (this.settingsButton) {
|
|
4061
|
+
this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
|
|
4062
|
+
}
|
|
4063
|
+
const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
|
|
4064
|
+
if (indicator) {
|
|
4065
|
+
indicator.remove();
|
|
4066
|
+
}
|
|
4067
|
+
if (this.settingsButton) {
|
|
4068
|
+
this.settingsButton.focus();
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
/**
|
|
4072
|
+
* Toggle settings menu visibility
|
|
4073
|
+
*/
|
|
4074
|
+
toggleSettingsMenu() {
|
|
4075
|
+
if (this.settingsMenuVisible) {
|
|
4076
|
+
this.hideSettingsMenu();
|
|
4077
|
+
} else {
|
|
4078
|
+
this.showSettingsMenu();
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
/**
|
|
4082
|
+
* Show settings menu
|
|
4083
|
+
*/
|
|
4084
|
+
showSettingsMenu() {
|
|
4085
|
+
this.settingsMenuJustOpened = true;
|
|
4086
|
+
setTimeout(() => {
|
|
4087
|
+
this.settingsMenuJustOpened = false;
|
|
4088
|
+
}, 350);
|
|
4089
|
+
if (!this.documentClickHandlerAdded) {
|
|
4090
|
+
setTimeout(() => {
|
|
4091
|
+
document.addEventListener("click", this.handlers.documentClick);
|
|
4092
|
+
this.documentClickHandlerAdded = true;
|
|
4093
|
+
}, 300);
|
|
4094
|
+
}
|
|
4095
|
+
if (this.settingsMenu) {
|
|
4096
|
+
this.settingsMenu.style.display = "block";
|
|
4097
|
+
this.settingsMenuVisible = true;
|
|
4098
|
+
return;
|
|
4099
|
+
}
|
|
4100
|
+
this.settingsMenu = DOMUtils.createElement("div", {
|
|
4101
|
+
className: `${this.player.options.classPrefix}-transcript-settings-menu`
|
|
4102
|
+
});
|
|
4103
|
+
const keyboardDragOption = DOMUtils.createElement("button", {
|
|
4104
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4105
|
+
attributes: {
|
|
4106
|
+
"type": "button",
|
|
4107
|
+
"aria-label": i18n.t("transcript.keyboardDragMode")
|
|
4108
|
+
}
|
|
4109
|
+
});
|
|
4110
|
+
const keyboardIcon = createIconElement("move");
|
|
4111
|
+
const keyboardText = DOMUtils.createElement("span", {
|
|
4112
|
+
textContent: i18n.t("transcript.keyboardDragMode")
|
|
4113
|
+
});
|
|
4114
|
+
keyboardDragOption.appendChild(keyboardIcon);
|
|
4115
|
+
keyboardDragOption.appendChild(keyboardText);
|
|
4116
|
+
keyboardDragOption.addEventListener("click", () => {
|
|
4117
|
+
this.toggleKeyboardDragMode();
|
|
4118
|
+
this.hideSettingsMenu();
|
|
4119
|
+
});
|
|
4120
|
+
const styleOption = DOMUtils.createElement("button", {
|
|
4121
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4122
|
+
attributes: {
|
|
4123
|
+
"type": "button",
|
|
4124
|
+
"aria-label": i18n.t("transcript.styleTranscript")
|
|
4125
|
+
}
|
|
4126
|
+
});
|
|
4127
|
+
const styleIcon = createIconElement("settings");
|
|
4128
|
+
const styleText = DOMUtils.createElement("span", {
|
|
4129
|
+
textContent: i18n.t("transcript.styleTranscript")
|
|
4130
|
+
});
|
|
4131
|
+
styleOption.appendChild(styleIcon);
|
|
4132
|
+
styleOption.appendChild(styleText);
|
|
4133
|
+
styleOption.addEventListener("click", (e) => {
|
|
4134
|
+
e.preventDefault();
|
|
4135
|
+
e.stopPropagation();
|
|
4136
|
+
this.hideSettingsMenu();
|
|
4137
|
+
setTimeout(() => {
|
|
4138
|
+
this.showStyleDialog();
|
|
4139
|
+
}, 50);
|
|
4140
|
+
});
|
|
4141
|
+
const resizeOption = DOMUtils.createElement("button", {
|
|
4142
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4143
|
+
attributes: {
|
|
4144
|
+
"type": "button",
|
|
4145
|
+
"aria-label": i18n.t("transcript.resizeWindow")
|
|
4146
|
+
}
|
|
4147
|
+
});
|
|
4148
|
+
const resizeIcon = createIconElement("resize");
|
|
4149
|
+
const resizeText = DOMUtils.createElement("span", {
|
|
4150
|
+
textContent: i18n.t("transcript.resizeWindow")
|
|
4151
|
+
});
|
|
4152
|
+
resizeOption.appendChild(resizeIcon);
|
|
4153
|
+
resizeOption.appendChild(resizeText);
|
|
4154
|
+
resizeOption.addEventListener("click", () => {
|
|
4155
|
+
this.toggleResizeMode();
|
|
4156
|
+
this.hideSettingsMenu();
|
|
4157
|
+
});
|
|
4158
|
+
const closeOption = DOMUtils.createElement("button", {
|
|
4159
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4160
|
+
attributes: {
|
|
4161
|
+
"type": "button",
|
|
4162
|
+
"aria-label": i18n.t("transcript.closeMenu")
|
|
4163
|
+
}
|
|
4164
|
+
});
|
|
4165
|
+
const closeIcon = createIconElement("close");
|
|
4166
|
+
const closeText = DOMUtils.createElement("span", {
|
|
4167
|
+
textContent: i18n.t("transcript.closeMenu")
|
|
4168
|
+
});
|
|
4169
|
+
closeOption.appendChild(closeIcon);
|
|
4170
|
+
closeOption.appendChild(closeText);
|
|
4171
|
+
closeOption.addEventListener("click", () => {
|
|
4172
|
+
this.hideSettingsMenu();
|
|
4173
|
+
});
|
|
4174
|
+
this.settingsMenu.appendChild(keyboardDragOption);
|
|
4175
|
+
this.settingsMenu.appendChild(resizeOption);
|
|
4176
|
+
this.settingsMenu.appendChild(styleOption);
|
|
4177
|
+
this.settingsMenu.appendChild(closeOption);
|
|
4178
|
+
if (this.headerLeft) {
|
|
4179
|
+
this.headerLeft.appendChild(this.settingsMenu);
|
|
4180
|
+
} else {
|
|
4181
|
+
this.transcriptHeader.appendChild(this.settingsMenu);
|
|
4182
|
+
}
|
|
4183
|
+
this.settingsMenuVisible = true;
|
|
4184
|
+
this.settingsMenu.style.display = "block";
|
|
4185
|
+
if (this.settingsButton) {
|
|
4186
|
+
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4187
|
+
}
|
|
4188
|
+
setTimeout(() => {
|
|
4189
|
+
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4190
|
+
if (firstItem) {
|
|
4191
|
+
firstItem.focus();
|
|
4192
|
+
}
|
|
4193
|
+
}, 0);
|
|
4194
|
+
}
|
|
4195
|
+
/**
|
|
4196
|
+
* Hide settings menu
|
|
4197
|
+
*/
|
|
4198
|
+
hideSettingsMenu() {
|
|
4199
|
+
if (this.settingsMenu) {
|
|
4200
|
+
this.settingsMenu.style.display = "none";
|
|
4201
|
+
this.settingsMenuVisible = false;
|
|
4202
|
+
this.settingsMenuJustOpened = false;
|
|
4203
|
+
if (this.settingsButton) {
|
|
4204
|
+
this.settingsButton.setAttribute("aria-expanded", "false");
|
|
4205
|
+
this.settingsButton.focus();
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
/**
|
|
4210
|
+
* Enable move mode (gives visual feedback)
|
|
4211
|
+
*/
|
|
4212
|
+
enableMoveMode() {
|
|
4213
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4214
|
+
const tooltip = DOMUtils.createElement("div", {
|
|
4215
|
+
className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
|
|
4216
|
+
textContent: "Drag with mouse or press D for keyboard drag mode"
|
|
4217
|
+
});
|
|
4218
|
+
this.transcriptHeader.appendChild(tooltip);
|
|
4219
|
+
setTimeout(() => {
|
|
4220
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4221
|
+
if (tooltip.parentNode) {
|
|
4222
|
+
tooltip.remove();
|
|
4223
|
+
}
|
|
4224
|
+
}, 2e3);
|
|
4225
|
+
}
|
|
4226
|
+
/**
|
|
4227
|
+
* Toggle resize mode
|
|
4228
|
+
*/
|
|
4229
|
+
toggleResizeMode() {
|
|
4230
|
+
this.resizeEnabled = !this.resizeEnabled;
|
|
4231
|
+
if (this.resizeEnabled) {
|
|
4232
|
+
this.enableResizeHandles();
|
|
4233
|
+
} else {
|
|
4234
|
+
this.disableResizeHandles();
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
/**
|
|
4238
|
+
* Enable resize handles
|
|
4239
|
+
*/
|
|
4240
|
+
enableResizeHandles() {
|
|
4241
|
+
if (!this.transcriptWindow) return;
|
|
4242
|
+
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4243
|
+
directions.forEach((direction) => {
|
|
4244
|
+
const handle = DOMUtils.createElement("div", {
|
|
4245
|
+
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4246
|
+
attributes: {
|
|
4247
|
+
"data-direction": direction
|
|
4248
|
+
}
|
|
4249
|
+
});
|
|
4250
|
+
handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
|
|
4251
|
+
handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
|
|
4252
|
+
this.transcriptWindow.appendChild(handle);
|
|
4253
|
+
});
|
|
4254
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4255
|
+
this.handlers.resizeMove = (e) => {
|
|
4256
|
+
if (this.isResizing) {
|
|
4257
|
+
this.performResize(e.clientX, e.clientY);
|
|
4258
|
+
}
|
|
4259
|
+
};
|
|
4260
|
+
this.handlers.resizeEnd = () => {
|
|
4261
|
+
if (this.isResizing) {
|
|
4262
|
+
this.stopResize();
|
|
4263
|
+
}
|
|
4264
|
+
};
|
|
4265
|
+
this.handlers.resizeTouchMove = (e) => {
|
|
4266
|
+
if (this.isResizing) {
|
|
4267
|
+
this.performResize(e.touches[0].clientX, e.touches[0].clientY);
|
|
4268
|
+
e.preventDefault();
|
|
4269
|
+
}
|
|
4270
|
+
};
|
|
4271
|
+
document.addEventListener("mousemove", this.handlers.resizeMove);
|
|
4272
|
+
document.addEventListener("mouseup", this.handlers.resizeEnd);
|
|
4273
|
+
document.addEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4274
|
+
document.addEventListener("touchend", this.handlers.resizeEnd);
|
|
4275
|
+
}
|
|
4276
|
+
/**
|
|
4277
|
+
* Disable resize handles
|
|
4278
|
+
*/
|
|
4279
|
+
disableResizeHandles() {
|
|
4280
|
+
if (!this.transcriptWindow) return;
|
|
4281
|
+
const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
|
|
4282
|
+
handles.forEach((handle) => handle.remove());
|
|
4283
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4284
|
+
if (this.handlers.resizeMove) {
|
|
4285
|
+
document.removeEventListener("mousemove", this.handlers.resizeMove);
|
|
4286
|
+
}
|
|
4287
|
+
if (this.handlers.resizeEnd) {
|
|
4288
|
+
document.removeEventListener("mouseup", this.handlers.resizeEnd);
|
|
4289
|
+
}
|
|
4290
|
+
if (this.handlers.resizeTouchMove) {
|
|
4291
|
+
document.removeEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4292
|
+
}
|
|
4293
|
+
document.removeEventListener("touchend", this.handlers.resizeEnd);
|
|
4294
|
+
}
|
|
4295
|
+
/**
|
|
4296
|
+
* Start resizing
|
|
4297
|
+
*/
|
|
4298
|
+
startResize(e, direction) {
|
|
4299
|
+
e.stopPropagation();
|
|
4300
|
+
e.preventDefault();
|
|
4301
|
+
this.isResizing = true;
|
|
4302
|
+
this.resizeDirection = direction;
|
|
4303
|
+
this.resizeStartX = e.clientX;
|
|
4304
|
+
this.resizeStartY = e.clientY;
|
|
4305
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
4306
|
+
this.resizeStartWidth = rect.width;
|
|
4307
|
+
this.resizeStartHeight = rect.height;
|
|
4308
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4309
|
+
document.body.style.cursor = this.getResizeCursor(direction);
|
|
4310
|
+
document.body.style.userSelect = "none";
|
|
4311
|
+
}
|
|
4312
|
+
/**
|
|
4313
|
+
* Perform resize
|
|
4314
|
+
*/
|
|
4315
|
+
performResize(clientX, clientY) {
|
|
4316
|
+
if (!this.isResizing) return;
|
|
4317
|
+
const deltaX = clientX - this.resizeStartX;
|
|
4318
|
+
const deltaY = clientY - this.resizeStartY;
|
|
4319
|
+
let newWidth = this.resizeStartWidth;
|
|
4320
|
+
let newHeight = this.resizeStartHeight;
|
|
4321
|
+
const direction = this.resizeDirection;
|
|
4322
|
+
if (direction.includes("e")) {
|
|
4323
|
+
newWidth = this.resizeStartWidth + deltaX;
|
|
4324
|
+
}
|
|
4325
|
+
if (direction.includes("w")) {
|
|
4326
|
+
newWidth = this.resizeStartWidth - deltaX;
|
|
4327
|
+
}
|
|
4328
|
+
if (direction.includes("s")) {
|
|
4329
|
+
newHeight = this.resizeStartHeight + deltaY;
|
|
4330
|
+
}
|
|
4331
|
+
if (direction.includes("n")) {
|
|
4332
|
+
newHeight = this.resizeStartHeight - deltaY;
|
|
4333
|
+
}
|
|
4334
|
+
const minWidth = 300;
|
|
4335
|
+
const minHeight = 200;
|
|
4336
|
+
const maxWidth = window.innerWidth - 40;
|
|
4337
|
+
const maxHeight = window.innerHeight - 40;
|
|
4338
|
+
newWidth = Math.max(minWidth, Math.min(newWidth, maxWidth));
|
|
4339
|
+
newHeight = Math.max(minHeight, Math.min(newHeight, maxHeight));
|
|
4340
|
+
this.transcriptWindow.style.width = `${newWidth}px`;
|
|
4341
|
+
this.transcriptWindow.style.height = `${newHeight}px`;
|
|
4342
|
+
this.transcriptWindow.style.maxWidth = `${newWidth}px`;
|
|
4343
|
+
this.transcriptWindow.style.maxHeight = `${newHeight}px`;
|
|
4344
|
+
if (direction.includes("w")) {
|
|
4345
|
+
const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
4346
|
+
this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
|
|
4347
|
+
}
|
|
4348
|
+
if (direction.includes("n")) {
|
|
4349
|
+
const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
4350
|
+
this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4353
|
+
/**
|
|
4354
|
+
* Stop resizing
|
|
4355
|
+
*/
|
|
4356
|
+
stopResize() {
|
|
4357
|
+
this.isResizing = false;
|
|
4358
|
+
this.resizeDirection = null;
|
|
4359
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4360
|
+
document.body.style.cursor = "";
|
|
4361
|
+
document.body.style.userSelect = "";
|
|
4362
|
+
}
|
|
4363
|
+
/**
|
|
4364
|
+
* Get cursor style for resize direction
|
|
4365
|
+
*/
|
|
4366
|
+
getResizeCursor(direction) {
|
|
4367
|
+
const cursors = {
|
|
4368
|
+
"n": "ns-resize",
|
|
4369
|
+
"s": "ns-resize",
|
|
4370
|
+
"e": "ew-resize",
|
|
4371
|
+
"w": "ew-resize",
|
|
4372
|
+
"ne": "nesw-resize",
|
|
4373
|
+
"nw": "nwse-resize",
|
|
4374
|
+
"se": "nwse-resize",
|
|
4375
|
+
"sw": "nesw-resize"
|
|
4376
|
+
};
|
|
4377
|
+
return cursors[direction] || "default";
|
|
4378
|
+
}
|
|
4379
|
+
/**
|
|
4380
|
+
* Show style dialog
|
|
4381
|
+
*/
|
|
4382
|
+
showStyleDialog() {
|
|
4383
|
+
if (this.styleDialog) {
|
|
4384
|
+
this.styleDialog.style.display = "block";
|
|
4385
|
+
this.styleDialogVisible = true;
|
|
4386
|
+
this.styleDialogJustOpened = true;
|
|
4387
|
+
setTimeout(() => {
|
|
4388
|
+
this.styleDialogJustOpened = false;
|
|
4389
|
+
}, 350);
|
|
4390
|
+
setTimeout(() => {
|
|
4391
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4392
|
+
if (firstSelect) {
|
|
4393
|
+
firstSelect.focus();
|
|
4394
|
+
}
|
|
4395
|
+
}, 0);
|
|
4396
|
+
return;
|
|
4397
|
+
}
|
|
4398
|
+
this.styleDialog = DOMUtils.createElement("div", {
|
|
4399
|
+
className: `${this.player.options.classPrefix}-transcript-style-dialog`
|
|
4400
|
+
});
|
|
4401
|
+
const title = DOMUtils.createElement("h4", {
|
|
4402
|
+
textContent: i18n.t("transcript.styleTitle"),
|
|
4403
|
+
className: `${this.player.options.classPrefix}-transcript-style-title`
|
|
4404
|
+
});
|
|
4405
|
+
this.styleDialog.appendChild(title);
|
|
4406
|
+
const fontSizeControl = this.createStyleSelectControl(
|
|
4407
|
+
i18n.t("captions.fontSize"),
|
|
4408
|
+
"fontSize",
|
|
4409
|
+
[
|
|
4410
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
4411
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
4412
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
4413
|
+
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
4414
|
+
]
|
|
4415
|
+
);
|
|
4416
|
+
this.styleDialog.appendChild(fontSizeControl);
|
|
4417
|
+
const fontFamilyControl = this.createStyleSelectControl(
|
|
4418
|
+
i18n.t("captions.fontFamily"),
|
|
4419
|
+
"fontFamily",
|
|
4420
|
+
[
|
|
4421
|
+
{ label: i18n.t("fontFamilies.sansSerif"), value: "sans-serif" },
|
|
4422
|
+
{ label: i18n.t("fontFamilies.serif"), value: "serif" },
|
|
4423
|
+
{ label: i18n.t("fontFamilies.monospace"), value: "monospace" }
|
|
4424
|
+
]
|
|
4425
|
+
);
|
|
4426
|
+
this.styleDialog.appendChild(fontFamilyControl);
|
|
4427
|
+
const colorControl = this.createStyleColorControl(i18n.t("captions.color"), "color");
|
|
4428
|
+
this.styleDialog.appendChild(colorControl);
|
|
4429
|
+
const bgColorControl = this.createStyleColorControl(i18n.t("captions.backgroundColor"), "backgroundColor");
|
|
4430
|
+
this.styleDialog.appendChild(bgColorControl);
|
|
4431
|
+
const opacityControl = this.createStyleOpacityControl(i18n.t("captions.opacity"), "opacity");
|
|
4432
|
+
this.styleDialog.appendChild(opacityControl);
|
|
4433
|
+
const closeBtn = DOMUtils.createElement("button", {
|
|
4434
|
+
className: `${this.player.options.classPrefix}-transcript-style-close`,
|
|
4435
|
+
textContent: i18n.t("settings.close"),
|
|
4436
|
+
attributes: {
|
|
4437
|
+
"type": "button"
|
|
4438
|
+
}
|
|
4439
|
+
});
|
|
4440
|
+
closeBtn.addEventListener("click", () => this.hideStyleDialog());
|
|
4441
|
+
this.styleDialog.appendChild(closeBtn);
|
|
4442
|
+
this.handlers.styleDialogKeydown = (e) => {
|
|
4443
|
+
if (e.key === "Escape") {
|
|
4444
|
+
e.preventDefault();
|
|
4445
|
+
e.stopPropagation();
|
|
4446
|
+
this.hideStyleDialog();
|
|
4447
|
+
}
|
|
4448
|
+
};
|
|
4449
|
+
this.styleDialog.addEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4450
|
+
if (this.headerLeft) {
|
|
4451
|
+
this.headerLeft.appendChild(this.styleDialog);
|
|
4452
|
+
} else {
|
|
4453
|
+
this.transcriptHeader.appendChild(this.styleDialog);
|
|
4454
|
+
}
|
|
4455
|
+
this.applyTranscriptStyles();
|
|
4456
|
+
this.styleDialogVisible = true;
|
|
4457
|
+
this.styleDialog.style.display = "block";
|
|
4458
|
+
this.styleDialogJustOpened = true;
|
|
4459
|
+
setTimeout(() => {
|
|
4460
|
+
this.styleDialogJustOpened = false;
|
|
4461
|
+
}, 350);
|
|
4462
|
+
setTimeout(() => {
|
|
4463
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4464
|
+
if (firstSelect) {
|
|
4465
|
+
firstSelect.focus();
|
|
4466
|
+
}
|
|
4467
|
+
}, 0);
|
|
4468
|
+
}
|
|
4469
|
+
/**
|
|
4470
|
+
* Hide style dialog
|
|
4471
|
+
*/
|
|
4472
|
+
hideStyleDialog() {
|
|
4473
|
+
if (this.styleDialog) {
|
|
4474
|
+
this.styleDialog.style.display = "none";
|
|
4475
|
+
this.styleDialogVisible = false;
|
|
4476
|
+
if (this.settingsButton) {
|
|
4477
|
+
this.settingsButton.focus();
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
/**
|
|
4482
|
+
* Create style select control
|
|
4483
|
+
*/
|
|
4484
|
+
createStyleSelectControl(label, property, options) {
|
|
4485
|
+
const group = DOMUtils.createElement("div", {
|
|
4486
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4487
|
+
});
|
|
4488
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4489
|
+
textContent: label
|
|
4490
|
+
});
|
|
4491
|
+
group.appendChild(labelEl);
|
|
4492
|
+
const select = DOMUtils.createElement("select", {
|
|
4493
|
+
className: `${this.player.options.classPrefix}-transcript-style-select`
|
|
4494
|
+
});
|
|
4495
|
+
options.forEach((opt) => {
|
|
4496
|
+
const option = DOMUtils.createElement("option", {
|
|
4497
|
+
textContent: opt.label,
|
|
4498
|
+
attributes: {
|
|
4499
|
+
"value": opt.value
|
|
4500
|
+
}
|
|
4501
|
+
});
|
|
4502
|
+
if (this.transcriptStyle[property] === opt.value) {
|
|
4503
|
+
option.selected = true;
|
|
4504
|
+
}
|
|
4505
|
+
select.appendChild(option);
|
|
4506
|
+
});
|
|
4507
|
+
select.addEventListener("change", (e) => {
|
|
4508
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4509
|
+
this.applyTranscriptStyles();
|
|
4510
|
+
this.savePreferences();
|
|
4511
|
+
});
|
|
4512
|
+
group.appendChild(select);
|
|
4513
|
+
return group;
|
|
4514
|
+
}
|
|
4515
|
+
/**
|
|
4516
|
+
* Create style color control
|
|
4517
|
+
*/
|
|
4518
|
+
createStyleColorControl(label, property) {
|
|
4519
|
+
const group = DOMUtils.createElement("div", {
|
|
4520
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4521
|
+
});
|
|
4522
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4523
|
+
textContent: label
|
|
4524
|
+
});
|
|
4525
|
+
group.appendChild(labelEl);
|
|
4526
|
+
const input = DOMUtils.createElement("input", {
|
|
4527
|
+
attributes: {
|
|
4528
|
+
"type": "color",
|
|
4529
|
+
"value": this.transcriptStyle[property]
|
|
4530
|
+
},
|
|
4531
|
+
className: `${this.player.options.classPrefix}-transcript-style-color`
|
|
4532
|
+
});
|
|
4533
|
+
input.addEventListener("input", (e) => {
|
|
4534
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4535
|
+
this.applyTranscriptStyles();
|
|
4536
|
+
this.savePreferences();
|
|
4537
|
+
});
|
|
4538
|
+
group.appendChild(input);
|
|
4539
|
+
return group;
|
|
4540
|
+
}
|
|
4541
|
+
/**
|
|
4542
|
+
* Create style opacity control
|
|
4543
|
+
*/
|
|
4544
|
+
createStyleOpacityControl(label, property) {
|
|
4545
|
+
const group = DOMUtils.createElement("div", {
|
|
4546
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4547
|
+
});
|
|
4548
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4549
|
+
textContent: label
|
|
4550
|
+
});
|
|
4551
|
+
group.appendChild(labelEl);
|
|
4552
|
+
const valueDisplay = DOMUtils.createElement("span", {
|
|
4553
|
+
textContent: Math.round(this.transcriptStyle[property] * 100) + "%",
|
|
4554
|
+
className: `${this.player.options.classPrefix}-transcript-style-value`
|
|
4555
|
+
});
|
|
4556
|
+
const input = DOMUtils.createElement("input", {
|
|
4557
|
+
attributes: {
|
|
4558
|
+
"type": "range",
|
|
4559
|
+
"min": "0",
|
|
4560
|
+
"max": "1",
|
|
4561
|
+
"step": "0.1",
|
|
4562
|
+
"value": String(this.transcriptStyle[property])
|
|
4563
|
+
},
|
|
4564
|
+
className: `${this.player.options.classPrefix}-transcript-style-range`
|
|
4565
|
+
});
|
|
4566
|
+
input.addEventListener("input", (e) => {
|
|
4567
|
+
const value = parseFloat(e.target.value);
|
|
4568
|
+
this.transcriptStyle[property] = value;
|
|
4569
|
+
valueDisplay.textContent = Math.round(value * 100) + "%";
|
|
4570
|
+
this.applyTranscriptStyles();
|
|
4571
|
+
this.savePreferences();
|
|
4572
|
+
});
|
|
4573
|
+
const inputContainer = DOMUtils.createElement("div", {
|
|
4574
|
+
className: `${this.player.options.classPrefix}-transcript-style-range-container`
|
|
4575
|
+
});
|
|
4576
|
+
inputContainer.appendChild(input);
|
|
4577
|
+
inputContainer.appendChild(valueDisplay);
|
|
4578
|
+
group.appendChild(labelEl);
|
|
4579
|
+
group.appendChild(inputContainer);
|
|
4580
|
+
return group;
|
|
4581
|
+
}
|
|
4582
|
+
/**
|
|
4583
|
+
* Save transcript preferences to localStorage
|
|
4584
|
+
*/
|
|
4585
|
+
savePreferences() {
|
|
4586
|
+
this.storage.saveTranscriptPreferences(this.transcriptStyle);
|
|
4587
|
+
}
|
|
4588
|
+
/**
|
|
4589
|
+
* Apply transcript styles
|
|
4590
|
+
*/
|
|
4591
|
+
applyTranscriptStyles() {
|
|
4592
|
+
if (!this.transcriptWindow) return;
|
|
4593
|
+
this.transcriptWindow.style.backgroundColor = this.transcriptStyle.backgroundColor;
|
|
4594
|
+
this.transcriptWindow.style.opacity = String(this.transcriptStyle.opacity);
|
|
4595
|
+
if (this.transcriptContent) {
|
|
4596
|
+
this.transcriptContent.style.fontSize = this.transcriptStyle.fontSize;
|
|
4597
|
+
this.transcriptContent.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4598
|
+
this.transcriptContent.style.color = this.transcriptStyle.color;
|
|
4599
|
+
}
|
|
4600
|
+
const textEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-text`);
|
|
4601
|
+
textEntries.forEach((entry) => {
|
|
4602
|
+
entry.style.fontSize = this.transcriptStyle.fontSize;
|
|
4603
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4604
|
+
entry.style.color = this.transcriptStyle.color;
|
|
4605
|
+
});
|
|
4606
|
+
const timeEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-time`);
|
|
4607
|
+
timeEntries.forEach((entry) => {
|
|
4608
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4609
|
+
});
|
|
4610
|
+
}
|
|
3595
4611
|
/**
|
|
3596
4612
|
* Cleanup
|
|
3597
4613
|
*/
|
|
3598
4614
|
destroy() {
|
|
4615
|
+
if (this.resizeEnabled) {
|
|
4616
|
+
this.disableResizeHandles();
|
|
4617
|
+
}
|
|
4618
|
+
if (this.keyboardDragMode) {
|
|
4619
|
+
this.disableKeyboardDragMode();
|
|
4620
|
+
}
|
|
3599
4621
|
if (this.handlers.timeupdate) {
|
|
3600
4622
|
this.player.off("timeupdate", this.handlers.timeupdate);
|
|
3601
4623
|
}
|
|
@@ -3610,6 +4632,17 @@ var VidPly = (() => {
|
|
|
3610
4632
|
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
3611
4633
|
}
|
|
3612
4634
|
}
|
|
4635
|
+
if (this.settingsButton) {
|
|
4636
|
+
if (this.handlers.settingsClick) {
|
|
4637
|
+
this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
|
|
4638
|
+
}
|
|
4639
|
+
if (this.handlers.settingsKeydown) {
|
|
4640
|
+
this.settingsButton.removeEventListener("keydown", this.handlers.settingsKeydown);
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
if (this.styleDialog && this.handlers.styleDialogKeydown) {
|
|
4644
|
+
this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4645
|
+
}
|
|
3613
4646
|
if (this.handlers.mousemove) {
|
|
3614
4647
|
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
3615
4648
|
}
|
|
@@ -3622,6 +4655,9 @@ var VidPly = (() => {
|
|
|
3622
4655
|
if (this.handlers.touchend) {
|
|
3623
4656
|
document.removeEventListener("touchend", this.handlers.touchend);
|
|
3624
4657
|
}
|
|
4658
|
+
if (this.handlers.documentClick) {
|
|
4659
|
+
document.removeEventListener("click", this.handlers.documentClick);
|
|
4660
|
+
}
|
|
3625
4661
|
if (this.handlers.resize) {
|
|
3626
4662
|
window.removeEventListener("resize", this.handlers.resize);
|
|
3627
4663
|
}
|
|
@@ -3633,6 +4669,8 @@ var VidPly = (() => {
|
|
|
3633
4669
|
this.transcriptHeader = null;
|
|
3634
4670
|
this.transcriptContent = null;
|
|
3635
4671
|
this.transcriptEntries = [];
|
|
4672
|
+
this.settingsMenu = null;
|
|
4673
|
+
this.styleDialog = null;
|
|
3636
4674
|
}
|
|
3637
4675
|
};
|
|
3638
4676
|
|
|
@@ -4332,6 +5370,8 @@ var VidPly = (() => {
|
|
|
4332
5370
|
playbackSpeed: 1,
|
|
4333
5371
|
preload: "metadata",
|
|
4334
5372
|
startTime: 0,
|
|
5373
|
+
playsInline: true,
|
|
5374
|
+
// Enable inline playback on iOS (prevents native fullscreen)
|
|
4335
5375
|
// Controls
|
|
4336
5376
|
controls: true,
|
|
4337
5377
|
hideControlsDelay: 3e3,
|
|
@@ -4348,7 +5388,7 @@ var VidPly = (() => {
|
|
|
4348
5388
|
captionsButton: true,
|
|
4349
5389
|
transcriptButton: true,
|
|
4350
5390
|
fullscreenButton: true,
|
|
4351
|
-
pipButton:
|
|
5391
|
+
pipButton: false,
|
|
4352
5392
|
// Seeking
|
|
4353
5393
|
seekInterval: 10,
|
|
4354
5394
|
seekIntervalLarge: 30,
|
|
@@ -4418,6 +5458,13 @@ var VidPly = (() => {
|
|
|
4418
5458
|
onError: null,
|
|
4419
5459
|
...options
|
|
4420
5460
|
};
|
|
5461
|
+
this.storage = new StorageManager("vidply");
|
|
5462
|
+
const savedPrefs = this.storage.getPlayerPreferences();
|
|
5463
|
+
if (savedPrefs) {
|
|
5464
|
+
if (savedPrefs.volume !== void 0) this.options.volume = savedPrefs.volume;
|
|
5465
|
+
if (savedPrefs.playbackSpeed !== void 0) this.options.playbackSpeed = savedPrefs.playbackSpeed;
|
|
5466
|
+
if (savedPrefs.muted !== void 0) this.options.muted = savedPrefs.muted;
|
|
5467
|
+
}
|
|
4421
5468
|
this.state = {
|
|
4422
5469
|
ready: false,
|
|
4423
5470
|
playing: false,
|
|
@@ -4547,6 +5594,11 @@ var VidPly = (() => {
|
|
|
4547
5594
|
this.element.setAttribute("tabindex", "-1");
|
|
4548
5595
|
this.element.style.width = "100%";
|
|
4549
5596
|
this.element.style.height = "100%";
|
|
5597
|
+
if (this.element.tagName === "VIDEO" && this.options.playsInline) {
|
|
5598
|
+
this.element.setAttribute("playsinline", "");
|
|
5599
|
+
this.element.setAttribute("webkit-playsinline", "");
|
|
5600
|
+
this.element.playsInline = true;
|
|
5601
|
+
}
|
|
4550
5602
|
if (this.options.width) {
|
|
4551
5603
|
this.container.style.width = typeof this.options.width === "number" ? `${this.options.width}px` : this.options.width;
|
|
4552
5604
|
}
|
|
@@ -4747,6 +5799,7 @@ var VidPly = (() => {
|
|
|
4747
5799
|
if (newVolume > 0 && this.state.muted) {
|
|
4748
5800
|
this.state.muted = false;
|
|
4749
5801
|
}
|
|
5802
|
+
this.savePlayerPreferences();
|
|
4750
5803
|
}
|
|
4751
5804
|
getVolume() {
|
|
4752
5805
|
return this.state.volume;
|
|
@@ -4756,6 +5809,7 @@ var VidPly = (() => {
|
|
|
4756
5809
|
this.renderer.setMuted(true);
|
|
4757
5810
|
}
|
|
4758
5811
|
this.state.muted = true;
|
|
5812
|
+
this.savePlayerPreferences();
|
|
4759
5813
|
this.emit("volumechange");
|
|
4760
5814
|
}
|
|
4761
5815
|
unmute() {
|
|
@@ -4763,6 +5817,7 @@ var VidPly = (() => {
|
|
|
4763
5817
|
this.renderer.setMuted(false);
|
|
4764
5818
|
}
|
|
4765
5819
|
this.state.muted = false;
|
|
5820
|
+
this.savePlayerPreferences();
|
|
4766
5821
|
this.emit("volumechange");
|
|
4767
5822
|
}
|
|
4768
5823
|
toggleMute() {
|
|
@@ -4779,11 +5834,20 @@ var VidPly = (() => {
|
|
|
4779
5834
|
this.renderer.setPlaybackSpeed(newSpeed);
|
|
4780
5835
|
}
|
|
4781
5836
|
this.state.playbackSpeed = newSpeed;
|
|
5837
|
+
this.savePlayerPreferences();
|
|
4782
5838
|
this.emit("playbackspeedchange", newSpeed);
|
|
4783
5839
|
}
|
|
4784
5840
|
getPlaybackSpeed() {
|
|
4785
5841
|
return this.state.playbackSpeed;
|
|
4786
5842
|
}
|
|
5843
|
+
// Save player preferences to localStorage
|
|
5844
|
+
savePlayerPreferences() {
|
|
5845
|
+
this.storage.savePlayerPreferences({
|
|
5846
|
+
volume: this.state.volume,
|
|
5847
|
+
muted: this.state.muted,
|
|
5848
|
+
playbackSpeed: this.state.playbackSpeed
|
|
5849
|
+
});
|
|
5850
|
+
}
|
|
4787
5851
|
// Fullscreen
|
|
4788
5852
|
enterFullscreen() {
|
|
4789
5853
|
const elem = this.container;
|
|
@@ -4908,10 +5972,24 @@ var VidPly = (() => {
|
|
|
4908
5972
|
this.emit("audiodescriptiondisabled");
|
|
4909
5973
|
}
|
|
4910
5974
|
async toggleAudioDescription() {
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
5975
|
+
const textTracks = Array.from(this.element.textTracks || []);
|
|
5976
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
5977
|
+
if (descriptionTrack) {
|
|
5978
|
+
if (descriptionTrack.mode === "showing") {
|
|
5979
|
+
descriptionTrack.mode = "hidden";
|
|
5980
|
+
this.state.audioDescriptionEnabled = false;
|
|
5981
|
+
this.emit("audiodescriptiondisabled");
|
|
5982
|
+
} else {
|
|
5983
|
+
descriptionTrack.mode = "showing";
|
|
5984
|
+
this.state.audioDescriptionEnabled = true;
|
|
5985
|
+
this.emit("audiodescriptionenabled");
|
|
5986
|
+
}
|
|
5987
|
+
} else if (this.audioDescriptionSrc) {
|
|
5988
|
+
if (this.state.audioDescriptionEnabled) {
|
|
5989
|
+
await this.disableAudioDescription();
|
|
5990
|
+
} else {
|
|
5991
|
+
await this.enableAudioDescription();
|
|
5992
|
+
}
|
|
4915
5993
|
}
|
|
4916
5994
|
}
|
|
4917
5995
|
// Sign Language
|
|
@@ -4920,24 +5998,47 @@ var VidPly = (() => {
|
|
|
4920
5998
|
console.warn("No sign language video source provided");
|
|
4921
5999
|
return;
|
|
4922
6000
|
}
|
|
4923
|
-
if (this.
|
|
4924
|
-
this.
|
|
6001
|
+
if (this.signLanguageWrapper) {
|
|
6002
|
+
this.signLanguageWrapper.style.display = "block";
|
|
4925
6003
|
this.state.signLanguageEnabled = true;
|
|
4926
6004
|
this.emit("signlanguageenabled");
|
|
4927
6005
|
return;
|
|
4928
6006
|
}
|
|
6007
|
+
this.signLanguageWrapper = document.createElement("div");
|
|
6008
|
+
this.signLanguageWrapper.className = "vidply-sign-language-wrapper";
|
|
6009
|
+
this.signLanguageWrapper.setAttribute("tabindex", "0");
|
|
6010
|
+
this.signLanguageWrapper.setAttribute("aria-label", "Sign Language Video - Press D to drag with keyboard, R to resize");
|
|
4929
6011
|
this.signLanguageVideo = document.createElement("video");
|
|
4930
6012
|
this.signLanguageVideo.className = "vidply-sign-language-video";
|
|
4931
6013
|
this.signLanguageVideo.src = this.signLanguageSrc;
|
|
4932
6014
|
this.signLanguageVideo.setAttribute("aria-label", i18n.t("player.signLanguage"));
|
|
4933
|
-
const position = this.options.signLanguagePosition || "bottom-right";
|
|
4934
|
-
this.signLanguageVideo.classList.add(`vidply-sign-position-${position}`);
|
|
4935
6015
|
this.signLanguageVideo.muted = true;
|
|
6016
|
+
const resizeHandles = ["nw", "ne", "sw", "se"].map((dir) => {
|
|
6017
|
+
const handle = document.createElement("div");
|
|
6018
|
+
handle.className = `vidply-sign-resize-handle vidply-sign-resize-${dir}`;
|
|
6019
|
+
handle.setAttribute("data-direction", dir);
|
|
6020
|
+
handle.setAttribute("aria-label", `Resize ${dir.toUpperCase()}`);
|
|
6021
|
+
return handle;
|
|
6022
|
+
});
|
|
6023
|
+
this.signLanguageWrapper.appendChild(this.signLanguageVideo);
|
|
6024
|
+
resizeHandles.forEach((handle) => this.signLanguageWrapper.appendChild(handle));
|
|
6025
|
+
const saved = this.storage.getSignLanguagePreferences();
|
|
6026
|
+
if (saved && saved.size && saved.size.width) {
|
|
6027
|
+
this.signLanguageWrapper.style.width = saved.size.width;
|
|
6028
|
+
} else {
|
|
6029
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6030
|
+
}
|
|
6031
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6032
|
+
this.signLanguageDesiredPosition = this.options.signLanguagePosition || "bottom-right";
|
|
6033
|
+
this.container.appendChild(this.signLanguageWrapper);
|
|
6034
|
+
requestAnimationFrame(() => {
|
|
6035
|
+
this.constrainSignLanguagePosition();
|
|
6036
|
+
});
|
|
4936
6037
|
this.signLanguageVideo.currentTime = this.state.currentTime;
|
|
4937
6038
|
if (!this.state.paused) {
|
|
4938
6039
|
this.signLanguageVideo.play();
|
|
4939
6040
|
}
|
|
4940
|
-
this.
|
|
6041
|
+
this.setupSignLanguageInteraction();
|
|
4941
6042
|
this.signLanguageHandlers = {
|
|
4942
6043
|
play: () => {
|
|
4943
6044
|
if (this.signLanguageVideo) {
|
|
@@ -4968,8 +6069,8 @@ var VidPly = (() => {
|
|
|
4968
6069
|
this.emit("signlanguageenabled");
|
|
4969
6070
|
}
|
|
4970
6071
|
disableSignLanguage() {
|
|
4971
|
-
if (this.
|
|
4972
|
-
this.
|
|
6072
|
+
if (this.signLanguageWrapper) {
|
|
6073
|
+
this.signLanguageWrapper.style.display = "none";
|
|
4973
6074
|
}
|
|
4974
6075
|
this.state.signLanguageEnabled = false;
|
|
4975
6076
|
this.emit("signlanguagedisabled");
|
|
@@ -4981,6 +6082,237 @@ var VidPly = (() => {
|
|
|
4981
6082
|
this.enableSignLanguage();
|
|
4982
6083
|
}
|
|
4983
6084
|
}
|
|
6085
|
+
setupSignLanguageInteraction() {
|
|
6086
|
+
if (!this.signLanguageWrapper) return;
|
|
6087
|
+
let isDragging = false;
|
|
6088
|
+
let isResizing = false;
|
|
6089
|
+
let resizeDirection = null;
|
|
6090
|
+
let startX = 0;
|
|
6091
|
+
let startY = 0;
|
|
6092
|
+
let startLeft = 0;
|
|
6093
|
+
let startTop = 0;
|
|
6094
|
+
let startWidth = 0;
|
|
6095
|
+
let startHeight = 0;
|
|
6096
|
+
let dragMode = false;
|
|
6097
|
+
let resizeMode = false;
|
|
6098
|
+
const onMouseDownVideo = (e) => {
|
|
6099
|
+
if (e.target !== this.signLanguageVideo) return;
|
|
6100
|
+
e.preventDefault();
|
|
6101
|
+
isDragging = true;
|
|
6102
|
+
startX = e.clientX;
|
|
6103
|
+
startY = e.clientY;
|
|
6104
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6105
|
+
startLeft = rect.left;
|
|
6106
|
+
startTop = rect.top;
|
|
6107
|
+
this.signLanguageWrapper.classList.add("vidply-sign-dragging");
|
|
6108
|
+
};
|
|
6109
|
+
const onMouseDownHandle = (e) => {
|
|
6110
|
+
if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
|
|
6111
|
+
e.preventDefault();
|
|
6112
|
+
e.stopPropagation();
|
|
6113
|
+
isResizing = true;
|
|
6114
|
+
resizeDirection = e.target.getAttribute("data-direction");
|
|
6115
|
+
startX = e.clientX;
|
|
6116
|
+
startY = e.clientY;
|
|
6117
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6118
|
+
startLeft = rect.left;
|
|
6119
|
+
startTop = rect.top;
|
|
6120
|
+
startWidth = rect.width;
|
|
6121
|
+
startHeight = rect.height;
|
|
6122
|
+
this.signLanguageWrapper.classList.add("vidply-sign-resizing");
|
|
6123
|
+
};
|
|
6124
|
+
const onMouseMove = (e) => {
|
|
6125
|
+
if (isDragging) {
|
|
6126
|
+
const deltaX = e.clientX - startX;
|
|
6127
|
+
const deltaY = e.clientY - startY;
|
|
6128
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6129
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6130
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6131
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6132
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6133
|
+
let newLeft = startLeft + deltaX - containerRect.left;
|
|
6134
|
+
let newTop = startTop + deltaY - containerRect.top;
|
|
6135
|
+
const controlsHeight = 95;
|
|
6136
|
+
newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
|
|
6137
|
+
newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
|
|
6138
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6139
|
+
this.signLanguageWrapper.style.top = `${newTop}px`;
|
|
6140
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6141
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6142
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6143
|
+
} else if (isResizing) {
|
|
6144
|
+
const deltaX = e.clientX - startX;
|
|
6145
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6146
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6147
|
+
let newWidth = startWidth;
|
|
6148
|
+
let newLeft = startLeft - containerRect.left;
|
|
6149
|
+
if (resizeDirection.includes("e")) {
|
|
6150
|
+
newWidth = Math.max(150, startWidth + deltaX);
|
|
6151
|
+
const maxWidth = videoWrapperRect.right - startLeft;
|
|
6152
|
+
newWidth = Math.min(newWidth, maxWidth);
|
|
6153
|
+
}
|
|
6154
|
+
if (resizeDirection.includes("w")) {
|
|
6155
|
+
const proposedWidth = Math.max(150, startWidth - deltaX);
|
|
6156
|
+
const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
|
|
6157
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6158
|
+
if (proposedLeft >= videoWrapperLeft) {
|
|
6159
|
+
newWidth = proposedWidth;
|
|
6160
|
+
newLeft = proposedLeft;
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6163
|
+
this.signLanguageWrapper.style.width = `${newWidth}px`;
|
|
6164
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6165
|
+
if (resizeDirection.includes("w")) {
|
|
6166
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6167
|
+
}
|
|
6168
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6169
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6170
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6171
|
+
}
|
|
6172
|
+
};
|
|
6173
|
+
const onMouseUp = () => {
|
|
6174
|
+
if (isDragging || isResizing) {
|
|
6175
|
+
this.saveSignLanguagePreferences();
|
|
6176
|
+
}
|
|
6177
|
+
isDragging = false;
|
|
6178
|
+
isResizing = false;
|
|
6179
|
+
resizeDirection = null;
|
|
6180
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
|
|
6181
|
+
};
|
|
6182
|
+
const onKeyDown = (e) => {
|
|
6183
|
+
if (e.key === "d" || e.key === "D") {
|
|
6184
|
+
dragMode = !dragMode;
|
|
6185
|
+
resizeMode = false;
|
|
6186
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
|
|
6187
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
|
|
6188
|
+
e.preventDefault();
|
|
6189
|
+
return;
|
|
6190
|
+
}
|
|
6191
|
+
if (e.key === "r" || e.key === "R") {
|
|
6192
|
+
resizeMode = !resizeMode;
|
|
6193
|
+
dragMode = false;
|
|
6194
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
|
|
6195
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
|
|
6196
|
+
e.preventDefault();
|
|
6197
|
+
return;
|
|
6198
|
+
}
|
|
6199
|
+
if (e.key === "Escape") {
|
|
6200
|
+
dragMode = false;
|
|
6201
|
+
resizeMode = false;
|
|
6202
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
|
|
6203
|
+
e.preventDefault();
|
|
6204
|
+
return;
|
|
6205
|
+
}
|
|
6206
|
+
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
6207
|
+
const step = e.shiftKey ? 10 : 5;
|
|
6208
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6209
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6210
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6211
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6212
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6213
|
+
if (dragMode) {
|
|
6214
|
+
let left = rect.left - containerRect.left;
|
|
6215
|
+
let top = rect.top - containerRect.top;
|
|
6216
|
+
if (e.key === "ArrowLeft") left -= step;
|
|
6217
|
+
if (e.key === "ArrowRight") left += step;
|
|
6218
|
+
if (e.key === "ArrowUp") top -= step;
|
|
6219
|
+
if (e.key === "ArrowDown") top += step;
|
|
6220
|
+
const controlsHeight = 95;
|
|
6221
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
|
|
6222
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
|
|
6223
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6224
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6225
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6226
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6227
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6228
|
+
this.saveSignLanguagePreferences();
|
|
6229
|
+
e.preventDefault();
|
|
6230
|
+
} else if (resizeMode) {
|
|
6231
|
+
let width = rect.width;
|
|
6232
|
+
if (e.key === "ArrowLeft") width -= step;
|
|
6233
|
+
if (e.key === "ArrowRight") width += step;
|
|
6234
|
+
if (e.key === "ArrowUp") width += step;
|
|
6235
|
+
if (e.key === "ArrowDown") width -= step;
|
|
6236
|
+
width = Math.max(150, width);
|
|
6237
|
+
width = Math.min(width, videoWrapperRect.width);
|
|
6238
|
+
this.signLanguageWrapper.style.width = `${width}px`;
|
|
6239
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6240
|
+
this.saveSignLanguagePreferences();
|
|
6241
|
+
e.preventDefault();
|
|
6242
|
+
}
|
|
6243
|
+
}
|
|
6244
|
+
};
|
|
6245
|
+
this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
|
|
6246
|
+
const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
|
|
6247
|
+
handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
|
|
6248
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
6249
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
6250
|
+
this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
|
|
6251
|
+
this.signLanguageInteractionHandlers = {
|
|
6252
|
+
mouseDownVideo: onMouseDownVideo,
|
|
6253
|
+
mouseDownHandle: onMouseDownHandle,
|
|
6254
|
+
mouseMove: onMouseMove,
|
|
6255
|
+
mouseUp: onMouseUp,
|
|
6256
|
+
keyDown: onKeyDown,
|
|
6257
|
+
handles
|
|
6258
|
+
};
|
|
6259
|
+
}
|
|
6260
|
+
constrainSignLanguagePosition() {
|
|
6261
|
+
if (!this.signLanguageWrapper || !this.videoWrapper) return;
|
|
6262
|
+
if (!this.signLanguageWrapper.style.width || this.signLanguageWrapper.style.width === "") {
|
|
6263
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6264
|
+
}
|
|
6265
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6266
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6267
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6268
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6269
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6270
|
+
const videoWrapperWidth = videoWrapperRect.width;
|
|
6271
|
+
const videoWrapperHeight = videoWrapperRect.height;
|
|
6272
|
+
let wrapperWidth = wrapperRect.width || 280;
|
|
6273
|
+
let wrapperHeight = wrapperRect.height || 280 * 9 / 16;
|
|
6274
|
+
let left, top;
|
|
6275
|
+
const margin = 16;
|
|
6276
|
+
const controlsHeight = 95;
|
|
6277
|
+
const position = this.signLanguageDesiredPosition || "bottom-right";
|
|
6278
|
+
switch (position) {
|
|
6279
|
+
case "bottom-right":
|
|
6280
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6281
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6282
|
+
break;
|
|
6283
|
+
case "bottom-left":
|
|
6284
|
+
left = videoWrapperLeft + margin;
|
|
6285
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6286
|
+
break;
|
|
6287
|
+
case "top-right":
|
|
6288
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6289
|
+
top = videoWrapperTop + margin;
|
|
6290
|
+
break;
|
|
6291
|
+
case "top-left":
|
|
6292
|
+
left = videoWrapperLeft + margin;
|
|
6293
|
+
top = videoWrapperTop + margin;
|
|
6294
|
+
break;
|
|
6295
|
+
default:
|
|
6296
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6297
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6298
|
+
}
|
|
6299
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));
|
|
6300
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));
|
|
6301
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6302
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6303
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6304
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6305
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6306
|
+
}
|
|
6307
|
+
saveSignLanguagePreferences() {
|
|
6308
|
+
if (!this.signLanguageWrapper) return;
|
|
6309
|
+
this.storage.saveSignLanguagePreferences({
|
|
6310
|
+
size: {
|
|
6311
|
+
width: this.signLanguageWrapper.style.width
|
|
6312
|
+
// Height is auto - maintained by aspect ratio
|
|
6313
|
+
}
|
|
6314
|
+
});
|
|
6315
|
+
}
|
|
4984
6316
|
cleanupSignLanguage() {
|
|
4985
6317
|
if (this.signLanguageHandlers) {
|
|
4986
6318
|
this.off("play", this.signLanguageHandlers.play);
|
|
@@ -4989,10 +6321,29 @@ var VidPly = (() => {
|
|
|
4989
6321
|
this.off("ratechange", this.signLanguageHandlers.ratechange);
|
|
4990
6322
|
this.signLanguageHandlers = null;
|
|
4991
6323
|
}
|
|
4992
|
-
if (this.
|
|
4993
|
-
this.signLanguageVideo
|
|
4994
|
-
|
|
4995
|
-
|
|
6324
|
+
if (this.signLanguageInteractionHandlers) {
|
|
6325
|
+
if (this.signLanguageVideo) {
|
|
6326
|
+
this.signLanguageVideo.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownVideo);
|
|
6327
|
+
}
|
|
6328
|
+
if (this.signLanguageInteractionHandlers.handles) {
|
|
6329
|
+
this.signLanguageInteractionHandlers.handles.forEach((handle) => {
|
|
6330
|
+
handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
|
|
6331
|
+
});
|
|
6332
|
+
}
|
|
6333
|
+
document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
|
|
6334
|
+
document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
|
|
6335
|
+
if (this.signLanguageWrapper) {
|
|
6336
|
+
this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
|
|
6337
|
+
}
|
|
6338
|
+
this.signLanguageInteractionHandlers = null;
|
|
6339
|
+
}
|
|
6340
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
|
|
6341
|
+
if (this.signLanguageVideo) {
|
|
6342
|
+
this.signLanguageVideo.pause();
|
|
6343
|
+
this.signLanguageVideo.src = "";
|
|
6344
|
+
}
|
|
6345
|
+
this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);
|
|
6346
|
+
this.signLanguageWrapper = null;
|
|
4996
6347
|
this.signLanguageVideo = null;
|
|
4997
6348
|
}
|
|
4998
6349
|
}
|
|
@@ -5082,6 +6433,35 @@ var VidPly = (() => {
|
|
|
5082
6433
|
}
|
|
5083
6434
|
this.orientationQuery = orientationQuery;
|
|
5084
6435
|
}
|
|
6436
|
+
this.fullscreenChangeHandler = () => {
|
|
6437
|
+
const isFullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
|
|
6438
|
+
if (this.state.fullscreen !== isFullscreen) {
|
|
6439
|
+
this.state.fullscreen = isFullscreen;
|
|
6440
|
+
if (isFullscreen) {
|
|
6441
|
+
this.container.classList.add(`${this.options.classPrefix}-fullscreen`);
|
|
6442
|
+
} else {
|
|
6443
|
+
this.container.classList.remove(`${this.options.classPrefix}-fullscreen`);
|
|
6444
|
+
}
|
|
6445
|
+
this.emit("fullscreenchange", isFullscreen);
|
|
6446
|
+
if (this.controlBar) {
|
|
6447
|
+
this.controlBar.updateFullscreenButton();
|
|
6448
|
+
}
|
|
6449
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
|
|
6450
|
+
setTimeout(() => {
|
|
6451
|
+
requestAnimationFrame(() => {
|
|
6452
|
+
this.storage.saveSignLanguagePreferences({ size: null });
|
|
6453
|
+
this.signLanguageDesiredPosition = "bottom-right";
|
|
6454
|
+
this.signLanguageWrapper.style.width = isFullscreen ? "400px" : "280px";
|
|
6455
|
+
this.constrainSignLanguagePosition();
|
|
6456
|
+
});
|
|
6457
|
+
}, 500);
|
|
6458
|
+
}
|
|
6459
|
+
}
|
|
6460
|
+
};
|
|
6461
|
+
document.addEventListener("fullscreenchange", this.fullscreenChangeHandler);
|
|
6462
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenChangeHandler);
|
|
6463
|
+
document.addEventListener("mozfullscreenchange", this.fullscreenChangeHandler);
|
|
6464
|
+
document.addEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
|
|
5085
6465
|
}
|
|
5086
6466
|
// Cleanup
|
|
5087
6467
|
destroy() {
|
|
@@ -5123,6 +6503,13 @@ var VidPly = (() => {
|
|
|
5123
6503
|
this.orientationQuery = null;
|
|
5124
6504
|
this.orientationHandler = null;
|
|
5125
6505
|
}
|
|
6506
|
+
if (this.fullscreenChangeHandler) {
|
|
6507
|
+
document.removeEventListener("fullscreenchange", this.fullscreenChangeHandler);
|
|
6508
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenChangeHandler);
|
|
6509
|
+
document.removeEventListener("mozfullscreenchange", this.fullscreenChangeHandler);
|
|
6510
|
+
document.removeEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
|
|
6511
|
+
this.fullscreenChangeHandler = null;
|
|
6512
|
+
}
|
|
5126
6513
|
if (this.container && this.container.parentNode) {
|
|
5127
6514
|
this.container.parentNode.insertBefore(this.element, this.container);
|
|
5128
6515
|
this.container.parentNode.removeChild(this.container);
|