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.esm.js
CHANGED
|
@@ -448,7 +448,11 @@ var translations = {
|
|
|
448
448
|
noCaptions: "No captions available",
|
|
449
449
|
auto: "Auto",
|
|
450
450
|
autoQuality: "Auto (no quality selection available)",
|
|
451
|
-
noQuality: "Quality selection not available"
|
|
451
|
+
noQuality: "Quality selection not available",
|
|
452
|
+
signLanguageDragResize: "Sign Language Video - Press D to drag with keyboard, R to resize",
|
|
453
|
+
signLanguageDragActive: "Sign Language Video - Drag mode active. Use arrow keys to move, Escape to exit.",
|
|
454
|
+
signLanguageResizeActive: "Sign Language Video - Resize mode active. Use left/right arrow keys to resize, Escape to exit.",
|
|
455
|
+
resizeHandle: "Resize {direction} corner"
|
|
452
456
|
},
|
|
453
457
|
captions: {
|
|
454
458
|
off: "Off",
|
|
@@ -461,7 +465,7 @@ var translations = {
|
|
|
461
465
|
},
|
|
462
466
|
fontSizes: {
|
|
463
467
|
small: "Small",
|
|
464
|
-
|
|
468
|
+
normal: "Normal",
|
|
465
469
|
large: "Large",
|
|
466
470
|
xlarge: "X-Large"
|
|
467
471
|
},
|
|
@@ -489,7 +493,14 @@ var translations = {
|
|
|
489
493
|
title: "Transcript",
|
|
490
494
|
close: "Close transcript",
|
|
491
495
|
loading: "Loading transcript...",
|
|
492
|
-
noTranscript: "No transcript available for this video."
|
|
496
|
+
noTranscript: "No transcript available for this video.",
|
|
497
|
+
settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
|
|
498
|
+
keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
|
|
499
|
+
keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
|
|
500
|
+
resizeWindow: "Resize Window",
|
|
501
|
+
styleTranscript: "Open transcript style settings",
|
|
502
|
+
closeMenu: "Close Menu",
|
|
503
|
+
styleTitle: "Transcript Style"
|
|
493
504
|
},
|
|
494
505
|
settings: {
|
|
495
506
|
title: "Settings",
|
|
@@ -558,7 +569,11 @@ var translations = {
|
|
|
558
569
|
noCaptions: "Keine Untertitel verf\xFCgbar",
|
|
559
570
|
auto: "Automatisch",
|
|
560
571
|
autoQuality: "Automatisch (keine Qualit\xE4tsauswahl verf\xFCgbar)",
|
|
561
|
-
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar"
|
|
572
|
+
noQuality: "Qualit\xE4tsauswahl nicht verf\xFCgbar",
|
|
573
|
+
signLanguageDragResize: "Geb\xE4rdensprache-Video - Dr\xFCcken Sie D zum Verschieben per Tastatur, R zum \xC4ndern der Gr\xF6\xDFe",
|
|
574
|
+
signLanguageDragActive: "Geb\xE4rdensprache-Video - Verschiebemodus aktiv. Pfeiltasten zum Bewegen, Escape zum Beenden.",
|
|
575
|
+
signLanguageResizeActive: "Geb\xE4rdensprache-Video - Gr\xF6\xDFen\xE4nderungsmodus aktiv. Links-/Rechts-Pfeiltasten zum \xC4ndern der Gr\xF6\xDFe, Escape zum Beenden.",
|
|
576
|
+
resizeHandle: "Gr\xF6\xDFen\xE4nderung {direction}-Ecke"
|
|
562
577
|
},
|
|
563
578
|
captions: {
|
|
564
579
|
off: "Aus",
|
|
@@ -571,7 +586,7 @@ var translations = {
|
|
|
571
586
|
},
|
|
572
587
|
fontSizes: {
|
|
573
588
|
small: "Klein",
|
|
574
|
-
|
|
589
|
+
normal: "Normal",
|
|
575
590
|
large: "Gro\xDF",
|
|
576
591
|
xlarge: "Sehr gro\xDF"
|
|
577
592
|
},
|
|
@@ -599,7 +614,14 @@ var translations = {
|
|
|
599
614
|
title: "Transkript",
|
|
600
615
|
close: "Transkript schlie\xDFen",
|
|
601
616
|
loading: "Transkript wird geladen...",
|
|
602
|
-
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar."
|
|
617
|
+
noTranscript: "Kein Transkript f\xFCr dieses Video verf\xFCgbar.",
|
|
618
|
+
settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
|
|
619
|
+
keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
|
|
620
|
+
keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
|
|
621
|
+
resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
|
|
622
|
+
styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
|
|
623
|
+
closeMenu: "Men\xFC schlie\xDFen",
|
|
624
|
+
styleTitle: "Transkript-Stil"
|
|
603
625
|
},
|
|
604
626
|
settings: {
|
|
605
627
|
title: "Einstellungen",
|
|
@@ -668,7 +690,11 @@ var translations = {
|
|
|
668
690
|
noCaptions: "No hay subt\xEDtulos disponibles",
|
|
669
691
|
auto: "Autom\xE1tico",
|
|
670
692
|
autoQuality: "Autom\xE1tico (selecci\xF3n de calidad no disponible)",
|
|
671
|
-
noQuality: "Selecci\xF3n de calidad no disponible"
|
|
693
|
+
noQuality: "Selecci\xF3n de calidad no disponible",
|
|
694
|
+
signLanguageDragResize: "Video en Lengua de Se\xF1as - Presione D para arrastrar con el teclado, R para cambiar el tama\xF1o",
|
|
695
|
+
signLanguageDragActive: "Video en Lengua de Se\xF1as - Modo de arrastre activo. Use las teclas de flecha para mover, Escape para salir.",
|
|
696
|
+
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.",
|
|
697
|
+
resizeHandle: "Cambiar tama\xF1o esquina {direction}"
|
|
672
698
|
},
|
|
673
699
|
captions: {
|
|
674
700
|
off: "Desactivado",
|
|
@@ -681,7 +707,7 @@ var translations = {
|
|
|
681
707
|
},
|
|
682
708
|
fontSizes: {
|
|
683
709
|
small: "Peque\xF1o",
|
|
684
|
-
|
|
710
|
+
normal: "Normal",
|
|
685
711
|
large: "Grande",
|
|
686
712
|
xlarge: "Muy grande"
|
|
687
713
|
},
|
|
@@ -709,7 +735,14 @@ var translations = {
|
|
|
709
735
|
title: "Transcripci\xF3n",
|
|
710
736
|
close: "Cerrar transcripci\xF3n",
|
|
711
737
|
loading: "Cargando transcripci\xF3n...",
|
|
712
|
-
noTranscript: "No hay transcripci\xF3n disponible para este video."
|
|
738
|
+
noTranscript: "No hay transcripci\xF3n disponible para este video.",
|
|
739
|
+
settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
|
|
740
|
+
keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
|
|
741
|
+
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)",
|
|
742
|
+
resizeWindow: "Cambiar tama\xF1o de ventana",
|
|
743
|
+
styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
|
|
744
|
+
closeMenu: "Cerrar men\xFA",
|
|
745
|
+
styleTitle: "Estilo de Transcripci\xF3n"
|
|
713
746
|
},
|
|
714
747
|
settings: {
|
|
715
748
|
title: "Configuraci\xF3n",
|
|
@@ -778,7 +811,11 @@ var translations = {
|
|
|
778
811
|
noCaptions: "Aucun sous-titre disponible",
|
|
779
812
|
auto: "Automatique",
|
|
780
813
|
autoQuality: "Automatique (s\xE9lection de qualit\xE9 non disponible)",
|
|
781
|
-
noQuality: "S\xE9lection de qualit\xE9 non disponible"
|
|
814
|
+
noQuality: "S\xE9lection de qualit\xE9 non disponible",
|
|
815
|
+
signLanguageDragResize: "Vid\xE9o en Langue des Signes - Appuyez sur D pour d\xE9placer avec le clavier, R pour redimensionner",
|
|
816
|
+
signLanguageDragActive: "Vid\xE9o en Langue des Signes - Mode glissement actif. Utilisez les touches fl\xE9ch\xE9es pour d\xE9placer, \xC9chap pour quitter.",
|
|
817
|
+
signLanguageResizeActive: "Vid\xE9o en Langue des Signes - Mode redimensionnement actif. Utilisez les touches fl\xE9ch\xE9es gauche/droite pour redimensionner, \xC9chap pour quitter.",
|
|
818
|
+
resizeHandle: "Redimensionner coin {direction}"
|
|
782
819
|
},
|
|
783
820
|
captions: {
|
|
784
821
|
off: "D\xE9sactiv\xE9",
|
|
@@ -791,7 +828,7 @@ var translations = {
|
|
|
791
828
|
},
|
|
792
829
|
fontSizes: {
|
|
793
830
|
small: "Petit",
|
|
794
|
-
|
|
831
|
+
normal: "Normal",
|
|
795
832
|
large: "Grand",
|
|
796
833
|
xlarge: "Tr\xE8s grand"
|
|
797
834
|
},
|
|
@@ -819,7 +856,14 @@ var translations = {
|
|
|
819
856
|
title: "Transcription",
|
|
820
857
|
close: "Fermer la transcription",
|
|
821
858
|
loading: "Chargement de la transcription...",
|
|
822
|
-
noTranscript: "Aucune transcription disponible pour cette vid\xE9o."
|
|
859
|
+
noTranscript: "Aucune transcription disponible pour cette vid\xE9o.",
|
|
860
|
+
settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
|
|
861
|
+
keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
|
|
862
|
+
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)",
|
|
863
|
+
resizeWindow: "Redimensionner la fen\xEAtre",
|
|
864
|
+
styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
|
|
865
|
+
closeMenu: "Fermer le menu",
|
|
866
|
+
styleTitle: "Style de Transcription"
|
|
823
867
|
},
|
|
824
868
|
settings: {
|
|
825
869
|
title: "Param\xE8tres",
|
|
@@ -888,7 +932,11 @@ var translations = {
|
|
|
888
932
|
noCaptions: "\u5B57\u5E55\u304C\u3042\u308A\u307E\u305B\u3093",
|
|
889
933
|
auto: "\u81EA\u52D5",
|
|
890
934
|
autoQuality: "\u81EA\u52D5\uFF08\u753B\u8CEA\u9078\u629E\u4E0D\u53EF\uFF09",
|
|
891
|
-
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF"
|
|
935
|
+
noQuality: "\u753B\u8CEA\u9078\u629E\u4E0D\u53EF",
|
|
936
|
+
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",
|
|
937
|
+
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",
|
|
938
|
+
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",
|
|
939
|
+
resizeHandle: "{direction}\u30B3\u30FC\u30CA\u30FC\u306E\u30B5\u30A4\u30BA\u5909\u66F4"
|
|
892
940
|
},
|
|
893
941
|
captions: {
|
|
894
942
|
off: "\u30AA\u30D5",
|
|
@@ -901,7 +949,7 @@ var translations = {
|
|
|
901
949
|
},
|
|
902
950
|
fontSizes: {
|
|
903
951
|
small: "\u5C0F",
|
|
904
|
-
|
|
952
|
+
normal: "\u6A19\u6E96",
|
|
905
953
|
large: "\u5927",
|
|
906
954
|
xlarge: "\u7279\u5927"
|
|
907
955
|
},
|
|
@@ -929,7 +977,14 @@ var translations = {
|
|
|
929
977
|
title: "\u6587\u5B57\u8D77\u3053\u3057",
|
|
930
978
|
close: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u9589\u3058\u308B",
|
|
931
979
|
loading: "\u6587\u5B57\u8D77\u3053\u3057\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D...",
|
|
932
|
-
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002"
|
|
980
|
+
noTranscript: "\u3053\u306E\u30D3\u30C7\u30AA\u306E\u6587\u5B57\u8D77\u3053\u3057\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
981
|
+
settings: "\u6587\u5B57\u8D77\u3053\u3057\u8A2D\u5B9A\u3002Enter\u30AD\u30FC\u3067\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F\u3001\u307E\u305F\u306FD\u30AD\u30FC\u3067\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3059\u308B",
|
|
982
|
+
keyboardDragMode: "\u77E2\u5370\u30AD\u30FC\u3067\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u5207\u308A\u66FF\u3048\u3002\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8\uFF1AD\u30AD\u30FC",
|
|
983
|
+
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",
|
|
984
|
+
resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
|
|
985
|
+
styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
|
|
986
|
+
closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
|
|
987
|
+
styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB"
|
|
933
988
|
},
|
|
934
989
|
settings: {
|
|
935
990
|
title: "\u8A2D\u5B9A",
|
|
@@ -1108,14 +1163,16 @@ var iconPaths = {
|
|
|
1108
1163
|
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"/>`,
|
|
1109
1164
|
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"/>`,
|
|
1110
1165
|
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"/>`,
|
|
1111
|
-
audioDescription: `<
|
|
1112
|
-
audioDescriptionOn: `<
|
|
1166
|
+
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>`,
|
|
1167
|
+
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>`,
|
|
1113
1168
|
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>`,
|
|
1114
1169
|
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>`,
|
|
1115
1170
|
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"/>`,
|
|
1116
1171
|
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"/>`,
|
|
1117
1172
|
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"/>`,
|
|
1118
|
-
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"
|
|
1173
|
+
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"/>`,
|
|
1174
|
+
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"/>`,
|
|
1175
|
+
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"/>`
|
|
1119
1176
|
};
|
|
1120
1177
|
var svgWrapper = (paths) => `<svg viewBox="0 0 24 24" fill="currentColor">${paths}</svg>`;
|
|
1121
1178
|
var Icons = Object.fromEntries(
|
|
@@ -1411,7 +1468,11 @@ var ControlBar = class {
|
|
|
1411
1468
|
return false;
|
|
1412
1469
|
}
|
|
1413
1470
|
hasAudioDescription() {
|
|
1414
|
-
|
|
1471
|
+
if (this.player.audioDescriptionSrc && this.player.audioDescriptionSrc.length > 0) {
|
|
1472
|
+
return true;
|
|
1473
|
+
}
|
|
1474
|
+
const textTracks = Array.from(this.player.element.textTracks || []);
|
|
1475
|
+
return textTracks.some((track) => track.kind === "descriptions");
|
|
1415
1476
|
}
|
|
1416
1477
|
hasSignLanguage() {
|
|
1417
1478
|
return this.player.signLanguageSrc && this.player.signLanguageSrc.length > 0;
|
|
@@ -2022,9 +2083,9 @@ var ControlBar = class {
|
|
|
2022
2083
|
i18n.t("styleLabels.fontSize"),
|
|
2023
2084
|
"captionsFontSize",
|
|
2024
2085
|
[
|
|
2025
|
-
{ label: i18n.t("fontSizes.small"), value: "
|
|
2026
|
-
{ label: i18n.t("fontSizes.
|
|
2027
|
-
{ label: i18n.t("fontSizes.large"), value: "
|
|
2086
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
2087
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
2088
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
2028
2089
|
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
2029
2090
|
]
|
|
2030
2091
|
);
|
|
@@ -2713,6 +2774,141 @@ var ControlBar = class {
|
|
|
2713
2774
|
}
|
|
2714
2775
|
};
|
|
2715
2776
|
|
|
2777
|
+
// src/utils/StorageManager.js
|
|
2778
|
+
var StorageManager = class {
|
|
2779
|
+
constructor(namespace = "vidply") {
|
|
2780
|
+
this.namespace = namespace;
|
|
2781
|
+
this.storage = this.isStorageAvailable() ? localStorage : null;
|
|
2782
|
+
}
|
|
2783
|
+
/**
|
|
2784
|
+
* Check if localStorage is available
|
|
2785
|
+
*/
|
|
2786
|
+
isStorageAvailable() {
|
|
2787
|
+
try {
|
|
2788
|
+
const test = "__storage_test__";
|
|
2789
|
+
localStorage.setItem(test, test);
|
|
2790
|
+
localStorage.removeItem(test);
|
|
2791
|
+
return true;
|
|
2792
|
+
} catch (e) {
|
|
2793
|
+
return false;
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
/**
|
|
2797
|
+
* Get a namespaced key
|
|
2798
|
+
*/
|
|
2799
|
+
getKey(key) {
|
|
2800
|
+
return `${this.namespace}_${key}`;
|
|
2801
|
+
}
|
|
2802
|
+
/**
|
|
2803
|
+
* Save a value to storage
|
|
2804
|
+
*/
|
|
2805
|
+
set(key, value) {
|
|
2806
|
+
if (!this.storage) return false;
|
|
2807
|
+
try {
|
|
2808
|
+
const namespacedKey = this.getKey(key);
|
|
2809
|
+
this.storage.setItem(namespacedKey, JSON.stringify(value));
|
|
2810
|
+
return true;
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
console.warn("Failed to save to localStorage:", e);
|
|
2813
|
+
return false;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
/**
|
|
2817
|
+
* Get a value from storage
|
|
2818
|
+
*/
|
|
2819
|
+
get(key, defaultValue = null) {
|
|
2820
|
+
if (!this.storage) return defaultValue;
|
|
2821
|
+
try {
|
|
2822
|
+
const namespacedKey = this.getKey(key);
|
|
2823
|
+
const value = this.storage.getItem(namespacedKey);
|
|
2824
|
+
return value ? JSON.parse(value) : defaultValue;
|
|
2825
|
+
} catch (e) {
|
|
2826
|
+
console.warn("Failed to read from localStorage:", e);
|
|
2827
|
+
return defaultValue;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
/**
|
|
2831
|
+
* Remove a value from storage
|
|
2832
|
+
*/
|
|
2833
|
+
remove(key) {
|
|
2834
|
+
if (!this.storage) return false;
|
|
2835
|
+
try {
|
|
2836
|
+
const namespacedKey = this.getKey(key);
|
|
2837
|
+
this.storage.removeItem(namespacedKey);
|
|
2838
|
+
return true;
|
|
2839
|
+
} catch (e) {
|
|
2840
|
+
console.warn("Failed to remove from localStorage:", e);
|
|
2841
|
+
return false;
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
/**
|
|
2845
|
+
* Clear all namespaced values
|
|
2846
|
+
*/
|
|
2847
|
+
clear() {
|
|
2848
|
+
if (!this.storage) return false;
|
|
2849
|
+
try {
|
|
2850
|
+
const keys = Object.keys(this.storage);
|
|
2851
|
+
keys.forEach((key) => {
|
|
2852
|
+
if (key.startsWith(this.namespace)) {
|
|
2853
|
+
this.storage.removeItem(key);
|
|
2854
|
+
}
|
|
2855
|
+
});
|
|
2856
|
+
return true;
|
|
2857
|
+
} catch (e) {
|
|
2858
|
+
console.warn("Failed to clear localStorage:", e);
|
|
2859
|
+
return false;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
/**
|
|
2863
|
+
* Save transcript preferences
|
|
2864
|
+
*/
|
|
2865
|
+
saveTranscriptPreferences(preferences) {
|
|
2866
|
+
return this.set("transcript_preferences", preferences);
|
|
2867
|
+
}
|
|
2868
|
+
/**
|
|
2869
|
+
* Get transcript preferences
|
|
2870
|
+
*/
|
|
2871
|
+
getTranscriptPreferences() {
|
|
2872
|
+
return this.get("transcript_preferences", null);
|
|
2873
|
+
}
|
|
2874
|
+
/**
|
|
2875
|
+
* Save caption preferences
|
|
2876
|
+
*/
|
|
2877
|
+
saveCaptionPreferences(preferences) {
|
|
2878
|
+
return this.set("caption_preferences", preferences);
|
|
2879
|
+
}
|
|
2880
|
+
/**
|
|
2881
|
+
* Get caption preferences
|
|
2882
|
+
*/
|
|
2883
|
+
getCaptionPreferences() {
|
|
2884
|
+
return this.get("caption_preferences", null);
|
|
2885
|
+
}
|
|
2886
|
+
/**
|
|
2887
|
+
* Save player preferences (volume, speed, etc.)
|
|
2888
|
+
*/
|
|
2889
|
+
savePlayerPreferences(preferences) {
|
|
2890
|
+
return this.set("player_preferences", preferences);
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Get player preferences
|
|
2894
|
+
*/
|
|
2895
|
+
getPlayerPreferences() {
|
|
2896
|
+
return this.get("player_preferences", null);
|
|
2897
|
+
}
|
|
2898
|
+
/**
|
|
2899
|
+
* Save sign language preferences (position and size)
|
|
2900
|
+
*/
|
|
2901
|
+
saveSignLanguagePreferences(preferences) {
|
|
2902
|
+
return this.set("sign_language_preferences", preferences);
|
|
2903
|
+
}
|
|
2904
|
+
/**
|
|
2905
|
+
* Get sign language preferences
|
|
2906
|
+
*/
|
|
2907
|
+
getSignLanguagePreferences() {
|
|
2908
|
+
return this.get("sign_language_preferences", null);
|
|
2909
|
+
}
|
|
2910
|
+
};
|
|
2911
|
+
|
|
2716
2912
|
// src/controls/CaptionManager.js
|
|
2717
2913
|
var CaptionManager = class {
|
|
2718
2914
|
constructor(player) {
|
|
@@ -2721,8 +2917,29 @@ var CaptionManager = class {
|
|
|
2721
2917
|
this.tracks = [];
|
|
2722
2918
|
this.currentTrack = null;
|
|
2723
2919
|
this.currentCue = null;
|
|
2920
|
+
this.storage = new StorageManager("vidply");
|
|
2921
|
+
this.loadSavedPreferences();
|
|
2724
2922
|
this.init();
|
|
2725
2923
|
}
|
|
2924
|
+
loadSavedPreferences() {
|
|
2925
|
+
const saved = this.storage.getCaptionPreferences();
|
|
2926
|
+
if (saved) {
|
|
2927
|
+
if (saved.fontSize) this.player.options.captionsFontSize = saved.fontSize;
|
|
2928
|
+
if (saved.fontFamily) this.player.options.captionsFontFamily = saved.fontFamily;
|
|
2929
|
+
if (saved.color) this.player.options.captionsColor = saved.color;
|
|
2930
|
+
if (saved.backgroundColor) this.player.options.captionsBackgroundColor = saved.backgroundColor;
|
|
2931
|
+
if (saved.opacity !== void 0) this.player.options.captionsOpacity = saved.opacity;
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
saveCaptionPreferences() {
|
|
2935
|
+
this.storage.saveCaptionPreferences({
|
|
2936
|
+
fontSize: this.player.options.captionsFontSize,
|
|
2937
|
+
fontFamily: this.player.options.captionsFontFamily,
|
|
2938
|
+
color: this.player.options.captionsColor,
|
|
2939
|
+
backgroundColor: this.player.options.captionsBackgroundColor,
|
|
2940
|
+
opacity: this.player.options.captionsOpacity
|
|
2941
|
+
});
|
|
2942
|
+
}
|
|
2726
2943
|
init() {
|
|
2727
2944
|
this.createElement();
|
|
2728
2945
|
this.loadTracks();
|
|
@@ -2871,6 +3088,7 @@ var CaptionManager = class {
|
|
|
2871
3088
|
break;
|
|
2872
3089
|
}
|
|
2873
3090
|
this.updateStyles();
|
|
3091
|
+
this.saveCaptionPreferences();
|
|
2874
3092
|
this.player.emit("captionschange");
|
|
2875
3093
|
}
|
|
2876
3094
|
getAvailableTracks() {
|
|
@@ -3081,11 +3299,36 @@ var TranscriptManager = class {
|
|
|
3081
3299
|
this.player = player;
|
|
3082
3300
|
this.transcriptWindow = null;
|
|
3083
3301
|
this.transcriptEntries = [];
|
|
3302
|
+
this.metadataCues = [];
|
|
3084
3303
|
this.currentActiveEntry = null;
|
|
3085
3304
|
this.isVisible = false;
|
|
3305
|
+
this.storage = new StorageManager("vidply");
|
|
3086
3306
|
this.isDragging = false;
|
|
3087
3307
|
this.dragOffsetX = 0;
|
|
3088
3308
|
this.dragOffsetY = 0;
|
|
3309
|
+
this.isResizing = false;
|
|
3310
|
+
this.resizeDirection = null;
|
|
3311
|
+
this.resizeStartX = 0;
|
|
3312
|
+
this.resizeStartY = 0;
|
|
3313
|
+
this.resizeStartWidth = 0;
|
|
3314
|
+
this.resizeStartHeight = 0;
|
|
3315
|
+
this.resizeEnabled = false;
|
|
3316
|
+
this.settingsMenuVisible = false;
|
|
3317
|
+
this.settingsMenu = null;
|
|
3318
|
+
this.settingsButton = null;
|
|
3319
|
+
this.settingsMenuJustOpened = false;
|
|
3320
|
+
this.keyboardDragMode = false;
|
|
3321
|
+
this.styleDialog = null;
|
|
3322
|
+
this.styleDialogVisible = false;
|
|
3323
|
+
this.styleDialogJustOpened = false;
|
|
3324
|
+
const savedPreferences = this.storage.getTranscriptPreferences();
|
|
3325
|
+
this.transcriptStyle = {
|
|
3326
|
+
fontSize: (savedPreferences == null ? void 0 : savedPreferences.fontSize) || this.player.options.transcriptFontSize || "100%",
|
|
3327
|
+
fontFamily: (savedPreferences == null ? void 0 : savedPreferences.fontFamily) || this.player.options.transcriptFontFamily || "sans-serif",
|
|
3328
|
+
color: (savedPreferences == null ? void 0 : savedPreferences.color) || this.player.options.transcriptColor || "#ffffff",
|
|
3329
|
+
backgroundColor: (savedPreferences == null ? void 0 : savedPreferences.backgroundColor) || this.player.options.transcriptBackgroundColor || "#1e1e1e",
|
|
3330
|
+
opacity: (savedPreferences == null ? void 0 : savedPreferences.opacity) ?? this.player.options.transcriptOpacity ?? 0.98
|
|
3331
|
+
};
|
|
3089
3332
|
this.handlers = {
|
|
3090
3333
|
timeupdate: () => this.updateActiveEntry(),
|
|
3091
3334
|
resize: null,
|
|
@@ -3095,7 +3338,11 @@ var TranscriptManager = class {
|
|
|
3095
3338
|
touchend: null,
|
|
3096
3339
|
mousedown: null,
|
|
3097
3340
|
touchstart: null,
|
|
3098
|
-
keydown: null
|
|
3341
|
+
keydown: null,
|
|
3342
|
+
settingsClick: null,
|
|
3343
|
+
settingsKeydown: null,
|
|
3344
|
+
documentClick: null,
|
|
3345
|
+
styleDialogKeydown: null
|
|
3099
3346
|
};
|
|
3100
3347
|
this.init();
|
|
3101
3348
|
}
|
|
@@ -3124,6 +3371,11 @@ var TranscriptManager = class {
|
|
|
3124
3371
|
if (this.transcriptWindow) {
|
|
3125
3372
|
this.transcriptWindow.style.display = "flex";
|
|
3126
3373
|
this.isVisible = true;
|
|
3374
|
+
setTimeout(() => {
|
|
3375
|
+
if (this.settingsButton) {
|
|
3376
|
+
this.settingsButton.focus();
|
|
3377
|
+
}
|
|
3378
|
+
}, 150);
|
|
3127
3379
|
return;
|
|
3128
3380
|
}
|
|
3129
3381
|
this.createTranscriptWindow();
|
|
@@ -3131,6 +3383,11 @@ var TranscriptManager = class {
|
|
|
3131
3383
|
if (this.transcriptWindow) {
|
|
3132
3384
|
this.transcriptWindow.style.display = "flex";
|
|
3133
3385
|
setTimeout(() => this.positionTranscript(), 0);
|
|
3386
|
+
setTimeout(() => {
|
|
3387
|
+
if (this.settingsButton) {
|
|
3388
|
+
this.settingsButton.focus();
|
|
3389
|
+
}
|
|
3390
|
+
}, 150);
|
|
3134
3391
|
}
|
|
3135
3392
|
this.isVisible = true;
|
|
3136
3393
|
}
|
|
@@ -3162,9 +3419,49 @@ var TranscriptManager = class {
|
|
|
3162
3419
|
"tabindex": "0"
|
|
3163
3420
|
}
|
|
3164
3421
|
});
|
|
3422
|
+
this.headerLeft = DOMUtils.createElement("div", {
|
|
3423
|
+
className: `${this.player.options.classPrefix}-transcript-header-left`
|
|
3424
|
+
});
|
|
3425
|
+
this.settingsButton = DOMUtils.createElement("button", {
|
|
3426
|
+
className: `${this.player.options.classPrefix}-transcript-settings`,
|
|
3427
|
+
attributes: {
|
|
3428
|
+
"type": "button",
|
|
3429
|
+
"aria-label": i18n.t("transcript.settings"),
|
|
3430
|
+
"aria-expanded": "false"
|
|
3431
|
+
}
|
|
3432
|
+
});
|
|
3433
|
+
this.settingsButton.appendChild(createIconElement("settings"));
|
|
3434
|
+
this.handlers.settingsClick = (e) => {
|
|
3435
|
+
e.preventDefault();
|
|
3436
|
+
e.stopPropagation();
|
|
3437
|
+
if (this.settingsMenuVisible) {
|
|
3438
|
+
this.hideSettingsMenu();
|
|
3439
|
+
} else {
|
|
3440
|
+
this.showSettingsMenu();
|
|
3441
|
+
}
|
|
3442
|
+
};
|
|
3443
|
+
this.settingsButton.addEventListener("click", this.handlers.settingsClick);
|
|
3444
|
+
this.handlers.settingsKeydown = (e) => {
|
|
3445
|
+
if (e.key === "d" || e.key === "D") {
|
|
3446
|
+
e.preventDefault();
|
|
3447
|
+
e.stopPropagation();
|
|
3448
|
+
this.toggleKeyboardDragMode();
|
|
3449
|
+
} else if (e.key === "r" || e.key === "R") {
|
|
3450
|
+
e.preventDefault();
|
|
3451
|
+
e.stopPropagation();
|
|
3452
|
+
this.toggleResizeMode();
|
|
3453
|
+
} else if (e.key === "Escape" && this.settingsMenuVisible) {
|
|
3454
|
+
e.preventDefault();
|
|
3455
|
+
e.stopPropagation();
|
|
3456
|
+
this.hideSettingsMenu();
|
|
3457
|
+
}
|
|
3458
|
+
};
|
|
3459
|
+
this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
|
|
3165
3460
|
const title = DOMUtils.createElement("h3", {
|
|
3166
3461
|
textContent: i18n.t("transcript.title")
|
|
3167
3462
|
});
|
|
3463
|
+
this.headerLeft.appendChild(this.settingsButton);
|
|
3464
|
+
this.headerLeft.appendChild(title);
|
|
3168
3465
|
const closeButton = DOMUtils.createElement("button", {
|
|
3169
3466
|
className: `${this.player.options.classPrefix}-transcript-close`,
|
|
3170
3467
|
attributes: {
|
|
@@ -3174,7 +3471,7 @@ var TranscriptManager = class {
|
|
|
3174
3471
|
});
|
|
3175
3472
|
closeButton.appendChild(createIconElement("close"));
|
|
3176
3473
|
closeButton.addEventListener("click", () => this.hideTranscript());
|
|
3177
|
-
this.transcriptHeader.appendChild(
|
|
3474
|
+
this.transcriptHeader.appendChild(this.headerLeft);
|
|
3178
3475
|
this.transcriptHeader.appendChild(closeButton);
|
|
3179
3476
|
this.transcriptContent = DOMUtils.createElement("div", {
|
|
3180
3477
|
className: `${this.player.options.classPrefix}-transcript-content`
|
|
@@ -3184,6 +3481,27 @@ var TranscriptManager = class {
|
|
|
3184
3481
|
this.player.container.appendChild(this.transcriptWindow);
|
|
3185
3482
|
this.positionTranscript();
|
|
3186
3483
|
this.setupDragAndDrop();
|
|
3484
|
+
this.handlers.documentClick = (e) => {
|
|
3485
|
+
if (this.settingsMenuJustOpened) {
|
|
3486
|
+
return;
|
|
3487
|
+
}
|
|
3488
|
+
if (this.styleDialogJustOpened) {
|
|
3489
|
+
return;
|
|
3490
|
+
}
|
|
3491
|
+
if (this.settingsButton && this.settingsButton.contains(e.target)) {
|
|
3492
|
+
return;
|
|
3493
|
+
}
|
|
3494
|
+
if (this.settingsMenu && this.settingsMenu.contains(e.target)) {
|
|
3495
|
+
return;
|
|
3496
|
+
}
|
|
3497
|
+
if (this.settingsMenuVisible) {
|
|
3498
|
+
this.hideSettingsMenu();
|
|
3499
|
+
}
|
|
3500
|
+
if (this.styleDialogVisible && this.styleDialog && !this.styleDialog.contains(e.target)) {
|
|
3501
|
+
this.hideStyleDialog();
|
|
3502
|
+
}
|
|
3503
|
+
};
|
|
3504
|
+
this.documentClickHandlerAdded = false;
|
|
3187
3505
|
let resizeTimeout;
|
|
3188
3506
|
this.handlers.resize = () => {
|
|
3189
3507
|
clearTimeout(resizeTimeout);
|
|
@@ -3264,54 +3582,133 @@ var TranscriptManager = class {
|
|
|
3264
3582
|
this.transcriptEntries = [];
|
|
3265
3583
|
this.transcriptContent.innerHTML = "";
|
|
3266
3584
|
const textTracks = Array.from(this.player.element.textTracks);
|
|
3267
|
-
const
|
|
3585
|
+
const captionTrack = textTracks.find(
|
|
3268
3586
|
(track) => track.kind === "captions" || track.kind === "subtitles"
|
|
3269
3587
|
);
|
|
3270
|
-
|
|
3588
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
3589
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3590
|
+
if (!captionTrack && !descriptionTrack && !metadataTrack) {
|
|
3271
3591
|
this.showNoTranscriptMessage();
|
|
3272
3592
|
return;
|
|
3273
3593
|
}
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3594
|
+
const tracksToLoad = [captionTrack, descriptionTrack, metadataTrack].filter(Boolean);
|
|
3595
|
+
tracksToLoad.forEach((track) => {
|
|
3596
|
+
if (track.mode === "disabled") {
|
|
3597
|
+
track.mode = "hidden";
|
|
3598
|
+
}
|
|
3599
|
+
});
|
|
3600
|
+
const needsLoading = tracksToLoad.some((track) => !track.cues || track.cues.length === 0);
|
|
3601
|
+
if (needsLoading) {
|
|
3278
3602
|
const loadingMessage = DOMUtils.createElement("div", {
|
|
3279
3603
|
className: `${this.player.options.classPrefix}-transcript-loading`,
|
|
3280
3604
|
textContent: i18n.t("transcript.loading")
|
|
3281
3605
|
});
|
|
3282
3606
|
this.transcriptContent.appendChild(loadingMessage);
|
|
3607
|
+
let loaded = 0;
|
|
3283
3608
|
const onLoad = () => {
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
transcriptTrack.addEventListener("load", onLoad, { once: true });
|
|
3287
|
-
setTimeout(() => {
|
|
3288
|
-
if (transcriptTrack.cues && transcriptTrack.cues.length > 0) {
|
|
3609
|
+
loaded++;
|
|
3610
|
+
if (loaded >= tracksToLoad.length) {
|
|
3289
3611
|
this.loadTranscriptData();
|
|
3290
3612
|
}
|
|
3613
|
+
};
|
|
3614
|
+
tracksToLoad.forEach((track) => {
|
|
3615
|
+
track.addEventListener("load", onLoad, { once: true });
|
|
3616
|
+
});
|
|
3617
|
+
setTimeout(() => {
|
|
3618
|
+
this.loadTranscriptData();
|
|
3291
3619
|
}, 500);
|
|
3292
3620
|
return;
|
|
3293
3621
|
}
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
|
|
3622
|
+
const allCues = [];
|
|
3623
|
+
if (captionTrack && captionTrack.cues) {
|
|
3624
|
+
Array.from(captionTrack.cues).forEach((cue) => {
|
|
3625
|
+
allCues.push({ cue, type: "caption" });
|
|
3626
|
+
});
|
|
3627
|
+
}
|
|
3628
|
+
if (descriptionTrack && descriptionTrack.cues) {
|
|
3629
|
+
Array.from(descriptionTrack.cues).forEach((cue) => {
|
|
3630
|
+
allCues.push({ cue, type: "description" });
|
|
3631
|
+
});
|
|
3632
|
+
}
|
|
3633
|
+
if (metadataTrack && metadataTrack.cues) {
|
|
3634
|
+
this.metadataCues = Array.from(metadataTrack.cues);
|
|
3635
|
+
this.setupMetadataHandling();
|
|
3636
|
+
}
|
|
3637
|
+
allCues.sort((a, b) => a.cue.startTime - b.cue.startTime);
|
|
3638
|
+
allCues.forEach((item, index) => {
|
|
3639
|
+
const entry = this.createTranscriptEntry(item.cue, index, item.type);
|
|
3297
3640
|
this.transcriptEntries.push({
|
|
3298
3641
|
element: entry,
|
|
3299
|
-
cue,
|
|
3300
|
-
|
|
3301
|
-
|
|
3642
|
+
cue: item.cue,
|
|
3643
|
+
type: item.type,
|
|
3644
|
+
startTime: item.cue.startTime,
|
|
3645
|
+
endTime: item.cue.endTime
|
|
3302
3646
|
});
|
|
3303
3647
|
this.transcriptContent.appendChild(entry);
|
|
3304
3648
|
});
|
|
3649
|
+
this.applyTranscriptStyles();
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* Setup metadata handling
|
|
3653
|
+
* Metadata cues are not displayed but can be used programmatically
|
|
3654
|
+
*/
|
|
3655
|
+
setupMetadataHandling() {
|
|
3656
|
+
if (!this.metadataCues || this.metadataCues.length === 0) {
|
|
3657
|
+
return;
|
|
3658
|
+
}
|
|
3659
|
+
const textTracks = Array.from(this.player.element.textTracks);
|
|
3660
|
+
const metadataTrack = textTracks.find((track) => track.kind === "metadata");
|
|
3661
|
+
if (metadataTrack) {
|
|
3662
|
+
metadataTrack.addEventListener("cuechange", () => {
|
|
3663
|
+
const activeCues = Array.from(metadataTrack.activeCues || []);
|
|
3664
|
+
activeCues.forEach((cue) => {
|
|
3665
|
+
this.handleMetadataCue(cue);
|
|
3666
|
+
});
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
/**
|
|
3671
|
+
* Handle individual metadata cues
|
|
3672
|
+
* Parses metadata text and emits events or triggers actions
|
|
3673
|
+
*/
|
|
3674
|
+
handleMetadataCue(cue) {
|
|
3675
|
+
const text = cue.text.trim();
|
|
3676
|
+
this.player.emit("metadata", {
|
|
3677
|
+
time: cue.startTime,
|
|
3678
|
+
endTime: cue.endTime,
|
|
3679
|
+
text,
|
|
3680
|
+
cue
|
|
3681
|
+
});
|
|
3682
|
+
if (text.includes("PAUSE")) {
|
|
3683
|
+
this.player.emit("metadata:pause", { time: cue.startTime, text });
|
|
3684
|
+
}
|
|
3685
|
+
const focusMatch = text.match(/FOCUS:([\w#-]+)/);
|
|
3686
|
+
if (focusMatch) {
|
|
3687
|
+
this.player.emit("metadata:focus", {
|
|
3688
|
+
time: cue.startTime,
|
|
3689
|
+
target: focusMatch[1],
|
|
3690
|
+
text
|
|
3691
|
+
});
|
|
3692
|
+
}
|
|
3693
|
+
const hashtags = text.match(/#[\w-]+/g);
|
|
3694
|
+
if (hashtags) {
|
|
3695
|
+
this.player.emit("metadata:hashtags", {
|
|
3696
|
+
time: cue.startTime,
|
|
3697
|
+
hashtags,
|
|
3698
|
+
text
|
|
3699
|
+
});
|
|
3700
|
+
}
|
|
3305
3701
|
}
|
|
3306
3702
|
/**
|
|
3307
3703
|
* Create a single transcript entry element
|
|
3308
3704
|
*/
|
|
3309
|
-
createTranscriptEntry(cue, index) {
|
|
3705
|
+
createTranscriptEntry(cue, index, type = "caption") {
|
|
3310
3706
|
const entry = DOMUtils.createElement("div", {
|
|
3311
|
-
className: `${this.player.options.classPrefix}-transcript-entry`,
|
|
3707
|
+
className: `${this.player.options.classPrefix}-transcript-entry ${this.player.options.classPrefix}-transcript-${type}`,
|
|
3312
3708
|
attributes: {
|
|
3313
3709
|
"data-start": String(cue.startTime),
|
|
3314
3710
|
"data-end": String(cue.endTime),
|
|
3711
|
+
"data-type": type,
|
|
3315
3712
|
"role": "button",
|
|
3316
3713
|
"tabindex": "0"
|
|
3317
3714
|
}
|
|
@@ -3408,6 +3805,15 @@ var TranscriptManager = class {
|
|
|
3408
3805
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3409
3806
|
return;
|
|
3410
3807
|
}
|
|
3808
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3812
|
+
return;
|
|
3813
|
+
}
|
|
3814
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3815
|
+
return;
|
|
3816
|
+
}
|
|
3411
3817
|
this.startDragging(e.clientX, e.clientY);
|
|
3412
3818
|
e.preventDefault();
|
|
3413
3819
|
};
|
|
@@ -3425,6 +3831,15 @@ var TranscriptManager = class {
|
|
|
3425
3831
|
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
|
|
3426
3832
|
return;
|
|
3427
3833
|
}
|
|
3834
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
|
|
3835
|
+
return;
|
|
3836
|
+
}
|
|
3837
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
|
|
3838
|
+
return;
|
|
3839
|
+
}
|
|
3840
|
+
if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
|
|
3841
|
+
return;
|
|
3842
|
+
}
|
|
3428
3843
|
const isMobile = window.innerWidth < 640;
|
|
3429
3844
|
const isFullscreen = this.player.state.fullscreen;
|
|
3430
3845
|
const touch = e.touches[0];
|
|
@@ -3451,49 +3866,64 @@ var TranscriptManager = class {
|
|
|
3451
3866
|
}
|
|
3452
3867
|
};
|
|
3453
3868
|
this.handlers.keydown = (e) => {
|
|
3454
|
-
if (
|
|
3869
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
3870
|
+
if (!this.keyboardDragMode) {
|
|
3871
|
+
return;
|
|
3872
|
+
}
|
|
3873
|
+
e.preventDefault();
|
|
3874
|
+
e.stopPropagation();
|
|
3875
|
+
const step = e.shiftKey ? 50 : 10;
|
|
3876
|
+
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3877
|
+
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3878
|
+
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3879
|
+
if (computedStyle.transform !== "none") {
|
|
3880
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3881
|
+
currentLeft = rect.left;
|
|
3882
|
+
currentTop = rect.top;
|
|
3883
|
+
this.transcriptWindow.style.transform = "none";
|
|
3884
|
+
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3885
|
+
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3886
|
+
}
|
|
3887
|
+
let newX = currentLeft;
|
|
3888
|
+
let newY = currentTop;
|
|
3889
|
+
switch (e.key) {
|
|
3890
|
+
case "ArrowLeft":
|
|
3891
|
+
newX -= step;
|
|
3892
|
+
break;
|
|
3893
|
+
case "ArrowRight":
|
|
3894
|
+
newX += step;
|
|
3895
|
+
break;
|
|
3896
|
+
case "ArrowUp":
|
|
3897
|
+
newY -= step;
|
|
3898
|
+
break;
|
|
3899
|
+
case "ArrowDown":
|
|
3900
|
+
newY += step;
|
|
3901
|
+
break;
|
|
3902
|
+
}
|
|
3903
|
+
this.transcriptWindow.style.left = `${newX}px`;
|
|
3904
|
+
this.transcriptWindow.style.top = `${newY}px`;
|
|
3455
3905
|
return;
|
|
3456
3906
|
}
|
|
3457
|
-
e.preventDefault();
|
|
3458
|
-
e.stopPropagation();
|
|
3459
3907
|
if (e.key === "Home") {
|
|
3908
|
+
e.preventDefault();
|
|
3909
|
+
e.stopPropagation();
|
|
3460
3910
|
this.resetPosition();
|
|
3461
3911
|
return;
|
|
3462
3912
|
}
|
|
3463
3913
|
if (e.key === "Escape") {
|
|
3464
|
-
|
|
3914
|
+
e.preventDefault();
|
|
3915
|
+
e.stopPropagation();
|
|
3916
|
+
if (this.styleDialogVisible) {
|
|
3917
|
+
this.hideStyleDialog();
|
|
3918
|
+
} else if (this.keyboardDragMode) {
|
|
3919
|
+
this.disableKeyboardDragMode();
|
|
3920
|
+
} else if (this.settingsMenuVisible) {
|
|
3921
|
+
this.hideSettingsMenu();
|
|
3922
|
+
} else {
|
|
3923
|
+
this.hideTranscript();
|
|
3924
|
+
}
|
|
3465
3925
|
return;
|
|
3466
3926
|
}
|
|
3467
|
-
const step = e.shiftKey ? 50 : 10;
|
|
3468
|
-
let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
3469
|
-
let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
3470
|
-
const computedStyle = window.getComputedStyle(this.transcriptWindow);
|
|
3471
|
-
if (computedStyle.transform !== "none") {
|
|
3472
|
-
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
3473
|
-
currentLeft = rect.left;
|
|
3474
|
-
currentTop = rect.top;
|
|
3475
|
-
this.transcriptWindow.style.transform = "none";
|
|
3476
|
-
this.transcriptWindow.style.left = `${currentLeft}px`;
|
|
3477
|
-
this.transcriptWindow.style.top = `${currentTop}px`;
|
|
3478
|
-
}
|
|
3479
|
-
let newX = currentLeft;
|
|
3480
|
-
let newY = currentTop;
|
|
3481
|
-
switch (e.key) {
|
|
3482
|
-
case "ArrowLeft":
|
|
3483
|
-
newX -= step;
|
|
3484
|
-
break;
|
|
3485
|
-
case "ArrowRight":
|
|
3486
|
-
newX += step;
|
|
3487
|
-
break;
|
|
3488
|
-
case "ArrowUp":
|
|
3489
|
-
newY -= step;
|
|
3490
|
-
break;
|
|
3491
|
-
case "ArrowDown":
|
|
3492
|
-
newY += step;
|
|
3493
|
-
break;
|
|
3494
|
-
}
|
|
3495
|
-
this.transcriptWindow.style.left = `${newX}px`;
|
|
3496
|
-
this.transcriptWindow.style.top = `${newY}px`;
|
|
3497
3927
|
};
|
|
3498
3928
|
this.transcriptHeader.addEventListener("mousedown", this.handlers.mousedown);
|
|
3499
3929
|
document.addEventListener("mousemove", this.handlers.mousemove);
|
|
@@ -3572,10 +4002,602 @@ var TranscriptManager = class {
|
|
|
3572
4002
|
this.transcriptWindow.style.top = "50%";
|
|
3573
4003
|
this.transcriptWindow.style.transform = "translate(-50%, -50%)";
|
|
3574
4004
|
}
|
|
4005
|
+
/**
|
|
4006
|
+
* Toggle keyboard drag mode
|
|
4007
|
+
*/
|
|
4008
|
+
toggleKeyboardDragMode() {
|
|
4009
|
+
if (this.keyboardDragMode) {
|
|
4010
|
+
this.disableKeyboardDragMode();
|
|
4011
|
+
} else {
|
|
4012
|
+
this.enableKeyboardDragMode();
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
/**
|
|
4016
|
+
* Enable keyboard drag mode
|
|
4017
|
+
*/
|
|
4018
|
+
enableKeyboardDragMode() {
|
|
4019
|
+
this.keyboardDragMode = true;
|
|
4020
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4021
|
+
if (this.settingsButton) {
|
|
4022
|
+
this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
|
|
4023
|
+
}
|
|
4024
|
+
const indicator = DOMUtils.createElement("div", {
|
|
4025
|
+
className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
|
|
4026
|
+
textContent: i18n.t("transcript.keyboardDragActive")
|
|
4027
|
+
});
|
|
4028
|
+
this.transcriptHeader.appendChild(indicator);
|
|
4029
|
+
if (this.settingsMenuVisible) {
|
|
4030
|
+
this.hideSettingsMenu();
|
|
4031
|
+
}
|
|
4032
|
+
this.transcriptHeader.focus();
|
|
4033
|
+
}
|
|
4034
|
+
/**
|
|
4035
|
+
* Disable keyboard drag mode
|
|
4036
|
+
*/
|
|
4037
|
+
disableKeyboardDragMode() {
|
|
4038
|
+
this.keyboardDragMode = false;
|
|
4039
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
|
|
4040
|
+
if (this.settingsButton) {
|
|
4041
|
+
this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
|
|
4042
|
+
}
|
|
4043
|
+
const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
|
|
4044
|
+
if (indicator) {
|
|
4045
|
+
indicator.remove();
|
|
4046
|
+
}
|
|
4047
|
+
if (this.settingsButton) {
|
|
4048
|
+
this.settingsButton.focus();
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
/**
|
|
4052
|
+
* Toggle settings menu visibility
|
|
4053
|
+
*/
|
|
4054
|
+
toggleSettingsMenu() {
|
|
4055
|
+
if (this.settingsMenuVisible) {
|
|
4056
|
+
this.hideSettingsMenu();
|
|
4057
|
+
} else {
|
|
4058
|
+
this.showSettingsMenu();
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
/**
|
|
4062
|
+
* Show settings menu
|
|
4063
|
+
*/
|
|
4064
|
+
showSettingsMenu() {
|
|
4065
|
+
this.settingsMenuJustOpened = true;
|
|
4066
|
+
setTimeout(() => {
|
|
4067
|
+
this.settingsMenuJustOpened = false;
|
|
4068
|
+
}, 350);
|
|
4069
|
+
if (!this.documentClickHandlerAdded) {
|
|
4070
|
+
setTimeout(() => {
|
|
4071
|
+
document.addEventListener("click", this.handlers.documentClick);
|
|
4072
|
+
this.documentClickHandlerAdded = true;
|
|
4073
|
+
}, 300);
|
|
4074
|
+
}
|
|
4075
|
+
if (this.settingsMenu) {
|
|
4076
|
+
this.settingsMenu.style.display = "block";
|
|
4077
|
+
this.settingsMenuVisible = true;
|
|
4078
|
+
return;
|
|
4079
|
+
}
|
|
4080
|
+
this.settingsMenu = DOMUtils.createElement("div", {
|
|
4081
|
+
className: `${this.player.options.classPrefix}-transcript-settings-menu`
|
|
4082
|
+
});
|
|
4083
|
+
const keyboardDragOption = DOMUtils.createElement("button", {
|
|
4084
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4085
|
+
attributes: {
|
|
4086
|
+
"type": "button",
|
|
4087
|
+
"aria-label": i18n.t("transcript.keyboardDragMode")
|
|
4088
|
+
}
|
|
4089
|
+
});
|
|
4090
|
+
const keyboardIcon = createIconElement("move");
|
|
4091
|
+
const keyboardText = DOMUtils.createElement("span", {
|
|
4092
|
+
textContent: i18n.t("transcript.keyboardDragMode")
|
|
4093
|
+
});
|
|
4094
|
+
keyboardDragOption.appendChild(keyboardIcon);
|
|
4095
|
+
keyboardDragOption.appendChild(keyboardText);
|
|
4096
|
+
keyboardDragOption.addEventListener("click", () => {
|
|
4097
|
+
this.toggleKeyboardDragMode();
|
|
4098
|
+
this.hideSettingsMenu();
|
|
4099
|
+
});
|
|
4100
|
+
const styleOption = DOMUtils.createElement("button", {
|
|
4101
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4102
|
+
attributes: {
|
|
4103
|
+
"type": "button",
|
|
4104
|
+
"aria-label": i18n.t("transcript.styleTranscript")
|
|
4105
|
+
}
|
|
4106
|
+
});
|
|
4107
|
+
const styleIcon = createIconElement("settings");
|
|
4108
|
+
const styleText = DOMUtils.createElement("span", {
|
|
4109
|
+
textContent: i18n.t("transcript.styleTranscript")
|
|
4110
|
+
});
|
|
4111
|
+
styleOption.appendChild(styleIcon);
|
|
4112
|
+
styleOption.appendChild(styleText);
|
|
4113
|
+
styleOption.addEventListener("click", (e) => {
|
|
4114
|
+
e.preventDefault();
|
|
4115
|
+
e.stopPropagation();
|
|
4116
|
+
this.hideSettingsMenu();
|
|
4117
|
+
setTimeout(() => {
|
|
4118
|
+
this.showStyleDialog();
|
|
4119
|
+
}, 50);
|
|
4120
|
+
});
|
|
4121
|
+
const resizeOption = DOMUtils.createElement("button", {
|
|
4122
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4123
|
+
attributes: {
|
|
4124
|
+
"type": "button",
|
|
4125
|
+
"aria-label": i18n.t("transcript.resizeWindow")
|
|
4126
|
+
}
|
|
4127
|
+
});
|
|
4128
|
+
const resizeIcon = createIconElement("resize");
|
|
4129
|
+
const resizeText = DOMUtils.createElement("span", {
|
|
4130
|
+
textContent: i18n.t("transcript.resizeWindow")
|
|
4131
|
+
});
|
|
4132
|
+
resizeOption.appendChild(resizeIcon);
|
|
4133
|
+
resizeOption.appendChild(resizeText);
|
|
4134
|
+
resizeOption.addEventListener("click", () => {
|
|
4135
|
+
this.toggleResizeMode();
|
|
4136
|
+
this.hideSettingsMenu();
|
|
4137
|
+
});
|
|
4138
|
+
const closeOption = DOMUtils.createElement("button", {
|
|
4139
|
+
className: `${this.player.options.classPrefix}-transcript-settings-item`,
|
|
4140
|
+
attributes: {
|
|
4141
|
+
"type": "button",
|
|
4142
|
+
"aria-label": i18n.t("transcript.closeMenu")
|
|
4143
|
+
}
|
|
4144
|
+
});
|
|
4145
|
+
const closeIcon = createIconElement("close");
|
|
4146
|
+
const closeText = DOMUtils.createElement("span", {
|
|
4147
|
+
textContent: i18n.t("transcript.closeMenu")
|
|
4148
|
+
});
|
|
4149
|
+
closeOption.appendChild(closeIcon);
|
|
4150
|
+
closeOption.appendChild(closeText);
|
|
4151
|
+
closeOption.addEventListener("click", () => {
|
|
4152
|
+
this.hideSettingsMenu();
|
|
4153
|
+
});
|
|
4154
|
+
this.settingsMenu.appendChild(keyboardDragOption);
|
|
4155
|
+
this.settingsMenu.appendChild(resizeOption);
|
|
4156
|
+
this.settingsMenu.appendChild(styleOption);
|
|
4157
|
+
this.settingsMenu.appendChild(closeOption);
|
|
4158
|
+
if (this.headerLeft) {
|
|
4159
|
+
this.headerLeft.appendChild(this.settingsMenu);
|
|
4160
|
+
} else {
|
|
4161
|
+
this.transcriptHeader.appendChild(this.settingsMenu);
|
|
4162
|
+
}
|
|
4163
|
+
this.settingsMenuVisible = true;
|
|
4164
|
+
this.settingsMenu.style.display = "block";
|
|
4165
|
+
if (this.settingsButton) {
|
|
4166
|
+
this.settingsButton.setAttribute("aria-expanded", "true");
|
|
4167
|
+
}
|
|
4168
|
+
setTimeout(() => {
|
|
4169
|
+
const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
|
|
4170
|
+
if (firstItem) {
|
|
4171
|
+
firstItem.focus();
|
|
4172
|
+
}
|
|
4173
|
+
}, 0);
|
|
4174
|
+
}
|
|
4175
|
+
/**
|
|
4176
|
+
* Hide settings menu
|
|
4177
|
+
*/
|
|
4178
|
+
hideSettingsMenu() {
|
|
4179
|
+
if (this.settingsMenu) {
|
|
4180
|
+
this.settingsMenu.style.display = "none";
|
|
4181
|
+
this.settingsMenuVisible = false;
|
|
4182
|
+
this.settingsMenuJustOpened = false;
|
|
4183
|
+
if (this.settingsButton) {
|
|
4184
|
+
this.settingsButton.setAttribute("aria-expanded", "false");
|
|
4185
|
+
this.settingsButton.focus();
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
/**
|
|
4190
|
+
* Enable move mode (gives visual feedback)
|
|
4191
|
+
*/
|
|
4192
|
+
enableMoveMode() {
|
|
4193
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4194
|
+
const tooltip = DOMUtils.createElement("div", {
|
|
4195
|
+
className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
|
|
4196
|
+
textContent: "Drag with mouse or press D for keyboard drag mode"
|
|
4197
|
+
});
|
|
4198
|
+
this.transcriptHeader.appendChild(tooltip);
|
|
4199
|
+
setTimeout(() => {
|
|
4200
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-move-mode`);
|
|
4201
|
+
if (tooltip.parentNode) {
|
|
4202
|
+
tooltip.remove();
|
|
4203
|
+
}
|
|
4204
|
+
}, 2e3);
|
|
4205
|
+
}
|
|
4206
|
+
/**
|
|
4207
|
+
* Toggle resize mode
|
|
4208
|
+
*/
|
|
4209
|
+
toggleResizeMode() {
|
|
4210
|
+
this.resizeEnabled = !this.resizeEnabled;
|
|
4211
|
+
if (this.resizeEnabled) {
|
|
4212
|
+
this.enableResizeHandles();
|
|
4213
|
+
} else {
|
|
4214
|
+
this.disableResizeHandles();
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
/**
|
|
4218
|
+
* Enable resize handles
|
|
4219
|
+
*/
|
|
4220
|
+
enableResizeHandles() {
|
|
4221
|
+
if (!this.transcriptWindow) return;
|
|
4222
|
+
const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
|
|
4223
|
+
directions.forEach((direction) => {
|
|
4224
|
+
const handle = DOMUtils.createElement("div", {
|
|
4225
|
+
className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
|
|
4226
|
+
attributes: {
|
|
4227
|
+
"data-direction": direction
|
|
4228
|
+
}
|
|
4229
|
+
});
|
|
4230
|
+
handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
|
|
4231
|
+
handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
|
|
4232
|
+
this.transcriptWindow.appendChild(handle);
|
|
4233
|
+
});
|
|
4234
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4235
|
+
this.handlers.resizeMove = (e) => {
|
|
4236
|
+
if (this.isResizing) {
|
|
4237
|
+
this.performResize(e.clientX, e.clientY);
|
|
4238
|
+
}
|
|
4239
|
+
};
|
|
4240
|
+
this.handlers.resizeEnd = () => {
|
|
4241
|
+
if (this.isResizing) {
|
|
4242
|
+
this.stopResize();
|
|
4243
|
+
}
|
|
4244
|
+
};
|
|
4245
|
+
this.handlers.resizeTouchMove = (e) => {
|
|
4246
|
+
if (this.isResizing) {
|
|
4247
|
+
this.performResize(e.touches[0].clientX, e.touches[0].clientY);
|
|
4248
|
+
e.preventDefault();
|
|
4249
|
+
}
|
|
4250
|
+
};
|
|
4251
|
+
document.addEventListener("mousemove", this.handlers.resizeMove);
|
|
4252
|
+
document.addEventListener("mouseup", this.handlers.resizeEnd);
|
|
4253
|
+
document.addEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4254
|
+
document.addEventListener("touchend", this.handlers.resizeEnd);
|
|
4255
|
+
}
|
|
4256
|
+
/**
|
|
4257
|
+
* Disable resize handles
|
|
4258
|
+
*/
|
|
4259
|
+
disableResizeHandles() {
|
|
4260
|
+
if (!this.transcriptWindow) return;
|
|
4261
|
+
const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
|
|
4262
|
+
handles.forEach((handle) => handle.remove());
|
|
4263
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
|
|
4264
|
+
if (this.handlers.resizeMove) {
|
|
4265
|
+
document.removeEventListener("mousemove", this.handlers.resizeMove);
|
|
4266
|
+
}
|
|
4267
|
+
if (this.handlers.resizeEnd) {
|
|
4268
|
+
document.removeEventListener("mouseup", this.handlers.resizeEnd);
|
|
4269
|
+
}
|
|
4270
|
+
if (this.handlers.resizeTouchMove) {
|
|
4271
|
+
document.removeEventListener("touchmove", this.handlers.resizeTouchMove);
|
|
4272
|
+
}
|
|
4273
|
+
document.removeEventListener("touchend", this.handlers.resizeEnd);
|
|
4274
|
+
}
|
|
4275
|
+
/**
|
|
4276
|
+
* Start resizing
|
|
4277
|
+
*/
|
|
4278
|
+
startResize(e, direction) {
|
|
4279
|
+
e.stopPropagation();
|
|
4280
|
+
e.preventDefault();
|
|
4281
|
+
this.isResizing = true;
|
|
4282
|
+
this.resizeDirection = direction;
|
|
4283
|
+
this.resizeStartX = e.clientX;
|
|
4284
|
+
this.resizeStartY = e.clientY;
|
|
4285
|
+
const rect = this.transcriptWindow.getBoundingClientRect();
|
|
4286
|
+
this.resizeStartWidth = rect.width;
|
|
4287
|
+
this.resizeStartHeight = rect.height;
|
|
4288
|
+
this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4289
|
+
document.body.style.cursor = this.getResizeCursor(direction);
|
|
4290
|
+
document.body.style.userSelect = "none";
|
|
4291
|
+
}
|
|
4292
|
+
/**
|
|
4293
|
+
* Perform resize
|
|
4294
|
+
*/
|
|
4295
|
+
performResize(clientX, clientY) {
|
|
4296
|
+
if (!this.isResizing) return;
|
|
4297
|
+
const deltaX = clientX - this.resizeStartX;
|
|
4298
|
+
const deltaY = clientY - this.resizeStartY;
|
|
4299
|
+
let newWidth = this.resizeStartWidth;
|
|
4300
|
+
let newHeight = this.resizeStartHeight;
|
|
4301
|
+
const direction = this.resizeDirection;
|
|
4302
|
+
if (direction.includes("e")) {
|
|
4303
|
+
newWidth = this.resizeStartWidth + deltaX;
|
|
4304
|
+
}
|
|
4305
|
+
if (direction.includes("w")) {
|
|
4306
|
+
newWidth = this.resizeStartWidth - deltaX;
|
|
4307
|
+
}
|
|
4308
|
+
if (direction.includes("s")) {
|
|
4309
|
+
newHeight = this.resizeStartHeight + deltaY;
|
|
4310
|
+
}
|
|
4311
|
+
if (direction.includes("n")) {
|
|
4312
|
+
newHeight = this.resizeStartHeight - deltaY;
|
|
4313
|
+
}
|
|
4314
|
+
const minWidth = 300;
|
|
4315
|
+
const minHeight = 200;
|
|
4316
|
+
const maxWidth = window.innerWidth - 40;
|
|
4317
|
+
const maxHeight = window.innerHeight - 40;
|
|
4318
|
+
newWidth = Math.max(minWidth, Math.min(newWidth, maxWidth));
|
|
4319
|
+
newHeight = Math.max(minHeight, Math.min(newHeight, maxHeight));
|
|
4320
|
+
this.transcriptWindow.style.width = `${newWidth}px`;
|
|
4321
|
+
this.transcriptWindow.style.height = `${newHeight}px`;
|
|
4322
|
+
this.transcriptWindow.style.maxWidth = `${newWidth}px`;
|
|
4323
|
+
this.transcriptWindow.style.maxHeight = `${newHeight}px`;
|
|
4324
|
+
if (direction.includes("w")) {
|
|
4325
|
+
const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
|
|
4326
|
+
this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
|
|
4327
|
+
}
|
|
4328
|
+
if (direction.includes("n")) {
|
|
4329
|
+
const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
|
|
4330
|
+
this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
/**
|
|
4334
|
+
* Stop resizing
|
|
4335
|
+
*/
|
|
4336
|
+
stopResize() {
|
|
4337
|
+
this.isResizing = false;
|
|
4338
|
+
this.resizeDirection = null;
|
|
4339
|
+
this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
|
|
4340
|
+
document.body.style.cursor = "";
|
|
4341
|
+
document.body.style.userSelect = "";
|
|
4342
|
+
}
|
|
4343
|
+
/**
|
|
4344
|
+
* Get cursor style for resize direction
|
|
4345
|
+
*/
|
|
4346
|
+
getResizeCursor(direction) {
|
|
4347
|
+
const cursors = {
|
|
4348
|
+
"n": "ns-resize",
|
|
4349
|
+
"s": "ns-resize",
|
|
4350
|
+
"e": "ew-resize",
|
|
4351
|
+
"w": "ew-resize",
|
|
4352
|
+
"ne": "nesw-resize",
|
|
4353
|
+
"nw": "nwse-resize",
|
|
4354
|
+
"se": "nwse-resize",
|
|
4355
|
+
"sw": "nesw-resize"
|
|
4356
|
+
};
|
|
4357
|
+
return cursors[direction] || "default";
|
|
4358
|
+
}
|
|
4359
|
+
/**
|
|
4360
|
+
* Show style dialog
|
|
4361
|
+
*/
|
|
4362
|
+
showStyleDialog() {
|
|
4363
|
+
if (this.styleDialog) {
|
|
4364
|
+
this.styleDialog.style.display = "block";
|
|
4365
|
+
this.styleDialogVisible = true;
|
|
4366
|
+
this.styleDialogJustOpened = true;
|
|
4367
|
+
setTimeout(() => {
|
|
4368
|
+
this.styleDialogJustOpened = false;
|
|
4369
|
+
}, 350);
|
|
4370
|
+
setTimeout(() => {
|
|
4371
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4372
|
+
if (firstSelect) {
|
|
4373
|
+
firstSelect.focus();
|
|
4374
|
+
}
|
|
4375
|
+
}, 0);
|
|
4376
|
+
return;
|
|
4377
|
+
}
|
|
4378
|
+
this.styleDialog = DOMUtils.createElement("div", {
|
|
4379
|
+
className: `${this.player.options.classPrefix}-transcript-style-dialog`
|
|
4380
|
+
});
|
|
4381
|
+
const title = DOMUtils.createElement("h4", {
|
|
4382
|
+
textContent: i18n.t("transcript.styleTitle"),
|
|
4383
|
+
className: `${this.player.options.classPrefix}-transcript-style-title`
|
|
4384
|
+
});
|
|
4385
|
+
this.styleDialog.appendChild(title);
|
|
4386
|
+
const fontSizeControl = this.createStyleSelectControl(
|
|
4387
|
+
i18n.t("captions.fontSize"),
|
|
4388
|
+
"fontSize",
|
|
4389
|
+
[
|
|
4390
|
+
{ label: i18n.t("fontSizes.small"), value: "87.5%" },
|
|
4391
|
+
{ label: i18n.t("fontSizes.normal"), value: "100%" },
|
|
4392
|
+
{ label: i18n.t("fontSizes.large"), value: "125%" },
|
|
4393
|
+
{ label: i18n.t("fontSizes.xlarge"), value: "150%" }
|
|
4394
|
+
]
|
|
4395
|
+
);
|
|
4396
|
+
this.styleDialog.appendChild(fontSizeControl);
|
|
4397
|
+
const fontFamilyControl = this.createStyleSelectControl(
|
|
4398
|
+
i18n.t("captions.fontFamily"),
|
|
4399
|
+
"fontFamily",
|
|
4400
|
+
[
|
|
4401
|
+
{ label: i18n.t("fontFamilies.sansSerif"), value: "sans-serif" },
|
|
4402
|
+
{ label: i18n.t("fontFamilies.serif"), value: "serif" },
|
|
4403
|
+
{ label: i18n.t("fontFamilies.monospace"), value: "monospace" }
|
|
4404
|
+
]
|
|
4405
|
+
);
|
|
4406
|
+
this.styleDialog.appendChild(fontFamilyControl);
|
|
4407
|
+
const colorControl = this.createStyleColorControl(i18n.t("captions.color"), "color");
|
|
4408
|
+
this.styleDialog.appendChild(colorControl);
|
|
4409
|
+
const bgColorControl = this.createStyleColorControl(i18n.t("captions.backgroundColor"), "backgroundColor");
|
|
4410
|
+
this.styleDialog.appendChild(bgColorControl);
|
|
4411
|
+
const opacityControl = this.createStyleOpacityControl(i18n.t("captions.opacity"), "opacity");
|
|
4412
|
+
this.styleDialog.appendChild(opacityControl);
|
|
4413
|
+
const closeBtn = DOMUtils.createElement("button", {
|
|
4414
|
+
className: `${this.player.options.classPrefix}-transcript-style-close`,
|
|
4415
|
+
textContent: i18n.t("settings.close"),
|
|
4416
|
+
attributes: {
|
|
4417
|
+
"type": "button"
|
|
4418
|
+
}
|
|
4419
|
+
});
|
|
4420
|
+
closeBtn.addEventListener("click", () => this.hideStyleDialog());
|
|
4421
|
+
this.styleDialog.appendChild(closeBtn);
|
|
4422
|
+
this.handlers.styleDialogKeydown = (e) => {
|
|
4423
|
+
if (e.key === "Escape") {
|
|
4424
|
+
e.preventDefault();
|
|
4425
|
+
e.stopPropagation();
|
|
4426
|
+
this.hideStyleDialog();
|
|
4427
|
+
}
|
|
4428
|
+
};
|
|
4429
|
+
this.styleDialog.addEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4430
|
+
if (this.headerLeft) {
|
|
4431
|
+
this.headerLeft.appendChild(this.styleDialog);
|
|
4432
|
+
} else {
|
|
4433
|
+
this.transcriptHeader.appendChild(this.styleDialog);
|
|
4434
|
+
}
|
|
4435
|
+
this.applyTranscriptStyles();
|
|
4436
|
+
this.styleDialogVisible = true;
|
|
4437
|
+
this.styleDialog.style.display = "block";
|
|
4438
|
+
this.styleDialogJustOpened = true;
|
|
4439
|
+
setTimeout(() => {
|
|
4440
|
+
this.styleDialogJustOpened = false;
|
|
4441
|
+
}, 350);
|
|
4442
|
+
setTimeout(() => {
|
|
4443
|
+
const firstSelect = this.styleDialog.querySelector("select, input");
|
|
4444
|
+
if (firstSelect) {
|
|
4445
|
+
firstSelect.focus();
|
|
4446
|
+
}
|
|
4447
|
+
}, 0);
|
|
4448
|
+
}
|
|
4449
|
+
/**
|
|
4450
|
+
* Hide style dialog
|
|
4451
|
+
*/
|
|
4452
|
+
hideStyleDialog() {
|
|
4453
|
+
if (this.styleDialog) {
|
|
4454
|
+
this.styleDialog.style.display = "none";
|
|
4455
|
+
this.styleDialogVisible = false;
|
|
4456
|
+
if (this.settingsButton) {
|
|
4457
|
+
this.settingsButton.focus();
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
/**
|
|
4462
|
+
* Create style select control
|
|
4463
|
+
*/
|
|
4464
|
+
createStyleSelectControl(label, property, options) {
|
|
4465
|
+
const group = DOMUtils.createElement("div", {
|
|
4466
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4467
|
+
});
|
|
4468
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4469
|
+
textContent: label
|
|
4470
|
+
});
|
|
4471
|
+
group.appendChild(labelEl);
|
|
4472
|
+
const select = DOMUtils.createElement("select", {
|
|
4473
|
+
className: `${this.player.options.classPrefix}-transcript-style-select`
|
|
4474
|
+
});
|
|
4475
|
+
options.forEach((opt) => {
|
|
4476
|
+
const option = DOMUtils.createElement("option", {
|
|
4477
|
+
textContent: opt.label,
|
|
4478
|
+
attributes: {
|
|
4479
|
+
"value": opt.value
|
|
4480
|
+
}
|
|
4481
|
+
});
|
|
4482
|
+
if (this.transcriptStyle[property] === opt.value) {
|
|
4483
|
+
option.selected = true;
|
|
4484
|
+
}
|
|
4485
|
+
select.appendChild(option);
|
|
4486
|
+
});
|
|
4487
|
+
select.addEventListener("change", (e) => {
|
|
4488
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4489
|
+
this.applyTranscriptStyles();
|
|
4490
|
+
this.savePreferences();
|
|
4491
|
+
});
|
|
4492
|
+
group.appendChild(select);
|
|
4493
|
+
return group;
|
|
4494
|
+
}
|
|
4495
|
+
/**
|
|
4496
|
+
* Create style color control
|
|
4497
|
+
*/
|
|
4498
|
+
createStyleColorControl(label, property) {
|
|
4499
|
+
const group = DOMUtils.createElement("div", {
|
|
4500
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4501
|
+
});
|
|
4502
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4503
|
+
textContent: label
|
|
4504
|
+
});
|
|
4505
|
+
group.appendChild(labelEl);
|
|
4506
|
+
const input = DOMUtils.createElement("input", {
|
|
4507
|
+
attributes: {
|
|
4508
|
+
"type": "color",
|
|
4509
|
+
"value": this.transcriptStyle[property]
|
|
4510
|
+
},
|
|
4511
|
+
className: `${this.player.options.classPrefix}-transcript-style-color`
|
|
4512
|
+
});
|
|
4513
|
+
input.addEventListener("input", (e) => {
|
|
4514
|
+
this.transcriptStyle[property] = e.target.value;
|
|
4515
|
+
this.applyTranscriptStyles();
|
|
4516
|
+
this.savePreferences();
|
|
4517
|
+
});
|
|
4518
|
+
group.appendChild(input);
|
|
4519
|
+
return group;
|
|
4520
|
+
}
|
|
4521
|
+
/**
|
|
4522
|
+
* Create style opacity control
|
|
4523
|
+
*/
|
|
4524
|
+
createStyleOpacityControl(label, property) {
|
|
4525
|
+
const group = DOMUtils.createElement("div", {
|
|
4526
|
+
className: `${this.player.options.classPrefix}-transcript-style-group`
|
|
4527
|
+
});
|
|
4528
|
+
const labelEl = DOMUtils.createElement("label", {
|
|
4529
|
+
textContent: label
|
|
4530
|
+
});
|
|
4531
|
+
group.appendChild(labelEl);
|
|
4532
|
+
const valueDisplay = DOMUtils.createElement("span", {
|
|
4533
|
+
textContent: Math.round(this.transcriptStyle[property] * 100) + "%",
|
|
4534
|
+
className: `${this.player.options.classPrefix}-transcript-style-value`
|
|
4535
|
+
});
|
|
4536
|
+
const input = DOMUtils.createElement("input", {
|
|
4537
|
+
attributes: {
|
|
4538
|
+
"type": "range",
|
|
4539
|
+
"min": "0",
|
|
4540
|
+
"max": "1",
|
|
4541
|
+
"step": "0.1",
|
|
4542
|
+
"value": String(this.transcriptStyle[property])
|
|
4543
|
+
},
|
|
4544
|
+
className: `${this.player.options.classPrefix}-transcript-style-range`
|
|
4545
|
+
});
|
|
4546
|
+
input.addEventListener("input", (e) => {
|
|
4547
|
+
const value = parseFloat(e.target.value);
|
|
4548
|
+
this.transcriptStyle[property] = value;
|
|
4549
|
+
valueDisplay.textContent = Math.round(value * 100) + "%";
|
|
4550
|
+
this.applyTranscriptStyles();
|
|
4551
|
+
this.savePreferences();
|
|
4552
|
+
});
|
|
4553
|
+
const inputContainer = DOMUtils.createElement("div", {
|
|
4554
|
+
className: `${this.player.options.classPrefix}-transcript-style-range-container`
|
|
4555
|
+
});
|
|
4556
|
+
inputContainer.appendChild(input);
|
|
4557
|
+
inputContainer.appendChild(valueDisplay);
|
|
4558
|
+
group.appendChild(labelEl);
|
|
4559
|
+
group.appendChild(inputContainer);
|
|
4560
|
+
return group;
|
|
4561
|
+
}
|
|
4562
|
+
/**
|
|
4563
|
+
* Save transcript preferences to localStorage
|
|
4564
|
+
*/
|
|
4565
|
+
savePreferences() {
|
|
4566
|
+
this.storage.saveTranscriptPreferences(this.transcriptStyle);
|
|
4567
|
+
}
|
|
4568
|
+
/**
|
|
4569
|
+
* Apply transcript styles
|
|
4570
|
+
*/
|
|
4571
|
+
applyTranscriptStyles() {
|
|
4572
|
+
if (!this.transcriptWindow) return;
|
|
4573
|
+
this.transcriptWindow.style.backgroundColor = this.transcriptStyle.backgroundColor;
|
|
4574
|
+
this.transcriptWindow.style.opacity = String(this.transcriptStyle.opacity);
|
|
4575
|
+
if (this.transcriptContent) {
|
|
4576
|
+
this.transcriptContent.style.fontSize = this.transcriptStyle.fontSize;
|
|
4577
|
+
this.transcriptContent.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4578
|
+
this.transcriptContent.style.color = this.transcriptStyle.color;
|
|
4579
|
+
}
|
|
4580
|
+
const textEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-text`);
|
|
4581
|
+
textEntries.forEach((entry) => {
|
|
4582
|
+
entry.style.fontSize = this.transcriptStyle.fontSize;
|
|
4583
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4584
|
+
entry.style.color = this.transcriptStyle.color;
|
|
4585
|
+
});
|
|
4586
|
+
const timeEntries = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-time`);
|
|
4587
|
+
timeEntries.forEach((entry) => {
|
|
4588
|
+
entry.style.fontFamily = this.transcriptStyle.fontFamily;
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
3575
4591
|
/**
|
|
3576
4592
|
* Cleanup
|
|
3577
4593
|
*/
|
|
3578
4594
|
destroy() {
|
|
4595
|
+
if (this.resizeEnabled) {
|
|
4596
|
+
this.disableResizeHandles();
|
|
4597
|
+
}
|
|
4598
|
+
if (this.keyboardDragMode) {
|
|
4599
|
+
this.disableKeyboardDragMode();
|
|
4600
|
+
}
|
|
3579
4601
|
if (this.handlers.timeupdate) {
|
|
3580
4602
|
this.player.off("timeupdate", this.handlers.timeupdate);
|
|
3581
4603
|
}
|
|
@@ -3590,6 +4612,17 @@ var TranscriptManager = class {
|
|
|
3590
4612
|
this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
|
|
3591
4613
|
}
|
|
3592
4614
|
}
|
|
4615
|
+
if (this.settingsButton) {
|
|
4616
|
+
if (this.handlers.settingsClick) {
|
|
4617
|
+
this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
|
|
4618
|
+
}
|
|
4619
|
+
if (this.handlers.settingsKeydown) {
|
|
4620
|
+
this.settingsButton.removeEventListener("keydown", this.handlers.settingsKeydown);
|
|
4621
|
+
}
|
|
4622
|
+
}
|
|
4623
|
+
if (this.styleDialog && this.handlers.styleDialogKeydown) {
|
|
4624
|
+
this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
|
|
4625
|
+
}
|
|
3593
4626
|
if (this.handlers.mousemove) {
|
|
3594
4627
|
document.removeEventListener("mousemove", this.handlers.mousemove);
|
|
3595
4628
|
}
|
|
@@ -3602,6 +4635,9 @@ var TranscriptManager = class {
|
|
|
3602
4635
|
if (this.handlers.touchend) {
|
|
3603
4636
|
document.removeEventListener("touchend", this.handlers.touchend);
|
|
3604
4637
|
}
|
|
4638
|
+
if (this.handlers.documentClick) {
|
|
4639
|
+
document.removeEventListener("click", this.handlers.documentClick);
|
|
4640
|
+
}
|
|
3605
4641
|
if (this.handlers.resize) {
|
|
3606
4642
|
window.removeEventListener("resize", this.handlers.resize);
|
|
3607
4643
|
}
|
|
@@ -3613,6 +4649,8 @@ var TranscriptManager = class {
|
|
|
3613
4649
|
this.transcriptHeader = null;
|
|
3614
4650
|
this.transcriptContent = null;
|
|
3615
4651
|
this.transcriptEntries = [];
|
|
4652
|
+
this.settingsMenu = null;
|
|
4653
|
+
this.styleDialog = null;
|
|
3616
4654
|
}
|
|
3617
4655
|
};
|
|
3618
4656
|
|
|
@@ -4312,6 +5350,8 @@ var Player = class extends EventEmitter {
|
|
|
4312
5350
|
playbackSpeed: 1,
|
|
4313
5351
|
preload: "metadata",
|
|
4314
5352
|
startTime: 0,
|
|
5353
|
+
playsInline: true,
|
|
5354
|
+
// Enable inline playback on iOS (prevents native fullscreen)
|
|
4315
5355
|
// Controls
|
|
4316
5356
|
controls: true,
|
|
4317
5357
|
hideControlsDelay: 3e3,
|
|
@@ -4328,7 +5368,7 @@ var Player = class extends EventEmitter {
|
|
|
4328
5368
|
captionsButton: true,
|
|
4329
5369
|
transcriptButton: true,
|
|
4330
5370
|
fullscreenButton: true,
|
|
4331
|
-
pipButton:
|
|
5371
|
+
pipButton: false,
|
|
4332
5372
|
// Seeking
|
|
4333
5373
|
seekInterval: 10,
|
|
4334
5374
|
seekIntervalLarge: 30,
|
|
@@ -4398,6 +5438,13 @@ var Player = class extends EventEmitter {
|
|
|
4398
5438
|
onError: null,
|
|
4399
5439
|
...options
|
|
4400
5440
|
};
|
|
5441
|
+
this.storage = new StorageManager("vidply");
|
|
5442
|
+
const savedPrefs = this.storage.getPlayerPreferences();
|
|
5443
|
+
if (savedPrefs) {
|
|
5444
|
+
if (savedPrefs.volume !== void 0) this.options.volume = savedPrefs.volume;
|
|
5445
|
+
if (savedPrefs.playbackSpeed !== void 0) this.options.playbackSpeed = savedPrefs.playbackSpeed;
|
|
5446
|
+
if (savedPrefs.muted !== void 0) this.options.muted = savedPrefs.muted;
|
|
5447
|
+
}
|
|
4401
5448
|
this.state = {
|
|
4402
5449
|
ready: false,
|
|
4403
5450
|
playing: false,
|
|
@@ -4527,6 +5574,11 @@ var Player = class extends EventEmitter {
|
|
|
4527
5574
|
this.element.setAttribute("tabindex", "-1");
|
|
4528
5575
|
this.element.style.width = "100%";
|
|
4529
5576
|
this.element.style.height = "100%";
|
|
5577
|
+
if (this.element.tagName === "VIDEO" && this.options.playsInline) {
|
|
5578
|
+
this.element.setAttribute("playsinline", "");
|
|
5579
|
+
this.element.setAttribute("webkit-playsinline", "");
|
|
5580
|
+
this.element.playsInline = true;
|
|
5581
|
+
}
|
|
4530
5582
|
if (this.options.width) {
|
|
4531
5583
|
this.container.style.width = typeof this.options.width === "number" ? `${this.options.width}px` : this.options.width;
|
|
4532
5584
|
}
|
|
@@ -4727,6 +5779,7 @@ var Player = class extends EventEmitter {
|
|
|
4727
5779
|
if (newVolume > 0 && this.state.muted) {
|
|
4728
5780
|
this.state.muted = false;
|
|
4729
5781
|
}
|
|
5782
|
+
this.savePlayerPreferences();
|
|
4730
5783
|
}
|
|
4731
5784
|
getVolume() {
|
|
4732
5785
|
return this.state.volume;
|
|
@@ -4736,6 +5789,7 @@ var Player = class extends EventEmitter {
|
|
|
4736
5789
|
this.renderer.setMuted(true);
|
|
4737
5790
|
}
|
|
4738
5791
|
this.state.muted = true;
|
|
5792
|
+
this.savePlayerPreferences();
|
|
4739
5793
|
this.emit("volumechange");
|
|
4740
5794
|
}
|
|
4741
5795
|
unmute() {
|
|
@@ -4743,6 +5797,7 @@ var Player = class extends EventEmitter {
|
|
|
4743
5797
|
this.renderer.setMuted(false);
|
|
4744
5798
|
}
|
|
4745
5799
|
this.state.muted = false;
|
|
5800
|
+
this.savePlayerPreferences();
|
|
4746
5801
|
this.emit("volumechange");
|
|
4747
5802
|
}
|
|
4748
5803
|
toggleMute() {
|
|
@@ -4759,11 +5814,20 @@ var Player = class extends EventEmitter {
|
|
|
4759
5814
|
this.renderer.setPlaybackSpeed(newSpeed);
|
|
4760
5815
|
}
|
|
4761
5816
|
this.state.playbackSpeed = newSpeed;
|
|
5817
|
+
this.savePlayerPreferences();
|
|
4762
5818
|
this.emit("playbackspeedchange", newSpeed);
|
|
4763
5819
|
}
|
|
4764
5820
|
getPlaybackSpeed() {
|
|
4765
5821
|
return this.state.playbackSpeed;
|
|
4766
5822
|
}
|
|
5823
|
+
// Save player preferences to localStorage
|
|
5824
|
+
savePlayerPreferences() {
|
|
5825
|
+
this.storage.savePlayerPreferences({
|
|
5826
|
+
volume: this.state.volume,
|
|
5827
|
+
muted: this.state.muted,
|
|
5828
|
+
playbackSpeed: this.state.playbackSpeed
|
|
5829
|
+
});
|
|
5830
|
+
}
|
|
4767
5831
|
// Fullscreen
|
|
4768
5832
|
enterFullscreen() {
|
|
4769
5833
|
const elem = this.container;
|
|
@@ -4888,10 +5952,24 @@ var Player = class extends EventEmitter {
|
|
|
4888
5952
|
this.emit("audiodescriptiondisabled");
|
|
4889
5953
|
}
|
|
4890
5954
|
async toggleAudioDescription() {
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
5955
|
+
const textTracks = Array.from(this.element.textTracks || []);
|
|
5956
|
+
const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
|
|
5957
|
+
if (descriptionTrack) {
|
|
5958
|
+
if (descriptionTrack.mode === "showing") {
|
|
5959
|
+
descriptionTrack.mode = "hidden";
|
|
5960
|
+
this.state.audioDescriptionEnabled = false;
|
|
5961
|
+
this.emit("audiodescriptiondisabled");
|
|
5962
|
+
} else {
|
|
5963
|
+
descriptionTrack.mode = "showing";
|
|
5964
|
+
this.state.audioDescriptionEnabled = true;
|
|
5965
|
+
this.emit("audiodescriptionenabled");
|
|
5966
|
+
}
|
|
5967
|
+
} else if (this.audioDescriptionSrc) {
|
|
5968
|
+
if (this.state.audioDescriptionEnabled) {
|
|
5969
|
+
await this.disableAudioDescription();
|
|
5970
|
+
} else {
|
|
5971
|
+
await this.enableAudioDescription();
|
|
5972
|
+
}
|
|
4895
5973
|
}
|
|
4896
5974
|
}
|
|
4897
5975
|
// Sign Language
|
|
@@ -4900,24 +5978,47 @@ var Player = class extends EventEmitter {
|
|
|
4900
5978
|
console.warn("No sign language video source provided");
|
|
4901
5979
|
return;
|
|
4902
5980
|
}
|
|
4903
|
-
if (this.
|
|
4904
|
-
this.
|
|
5981
|
+
if (this.signLanguageWrapper) {
|
|
5982
|
+
this.signLanguageWrapper.style.display = "block";
|
|
4905
5983
|
this.state.signLanguageEnabled = true;
|
|
4906
5984
|
this.emit("signlanguageenabled");
|
|
4907
5985
|
return;
|
|
4908
5986
|
}
|
|
5987
|
+
this.signLanguageWrapper = document.createElement("div");
|
|
5988
|
+
this.signLanguageWrapper.className = "vidply-sign-language-wrapper";
|
|
5989
|
+
this.signLanguageWrapper.setAttribute("tabindex", "0");
|
|
5990
|
+
this.signLanguageWrapper.setAttribute("aria-label", "Sign Language Video - Press D to drag with keyboard, R to resize");
|
|
4909
5991
|
this.signLanguageVideo = document.createElement("video");
|
|
4910
5992
|
this.signLanguageVideo.className = "vidply-sign-language-video";
|
|
4911
5993
|
this.signLanguageVideo.src = this.signLanguageSrc;
|
|
4912
5994
|
this.signLanguageVideo.setAttribute("aria-label", i18n.t("player.signLanguage"));
|
|
4913
|
-
const position = this.options.signLanguagePosition || "bottom-right";
|
|
4914
|
-
this.signLanguageVideo.classList.add(`vidply-sign-position-${position}`);
|
|
4915
5995
|
this.signLanguageVideo.muted = true;
|
|
5996
|
+
const resizeHandles = ["nw", "ne", "sw", "se"].map((dir) => {
|
|
5997
|
+
const handle = document.createElement("div");
|
|
5998
|
+
handle.className = `vidply-sign-resize-handle vidply-sign-resize-${dir}`;
|
|
5999
|
+
handle.setAttribute("data-direction", dir);
|
|
6000
|
+
handle.setAttribute("aria-label", `Resize ${dir.toUpperCase()}`);
|
|
6001
|
+
return handle;
|
|
6002
|
+
});
|
|
6003
|
+
this.signLanguageWrapper.appendChild(this.signLanguageVideo);
|
|
6004
|
+
resizeHandles.forEach((handle) => this.signLanguageWrapper.appendChild(handle));
|
|
6005
|
+
const saved = this.storage.getSignLanguagePreferences();
|
|
6006
|
+
if (saved && saved.size && saved.size.width) {
|
|
6007
|
+
this.signLanguageWrapper.style.width = saved.size.width;
|
|
6008
|
+
} else {
|
|
6009
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6010
|
+
}
|
|
6011
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6012
|
+
this.signLanguageDesiredPosition = this.options.signLanguagePosition || "bottom-right";
|
|
6013
|
+
this.container.appendChild(this.signLanguageWrapper);
|
|
6014
|
+
requestAnimationFrame(() => {
|
|
6015
|
+
this.constrainSignLanguagePosition();
|
|
6016
|
+
});
|
|
4916
6017
|
this.signLanguageVideo.currentTime = this.state.currentTime;
|
|
4917
6018
|
if (!this.state.paused) {
|
|
4918
6019
|
this.signLanguageVideo.play();
|
|
4919
6020
|
}
|
|
4920
|
-
this.
|
|
6021
|
+
this.setupSignLanguageInteraction();
|
|
4921
6022
|
this.signLanguageHandlers = {
|
|
4922
6023
|
play: () => {
|
|
4923
6024
|
if (this.signLanguageVideo) {
|
|
@@ -4948,8 +6049,8 @@ var Player = class extends EventEmitter {
|
|
|
4948
6049
|
this.emit("signlanguageenabled");
|
|
4949
6050
|
}
|
|
4950
6051
|
disableSignLanguage() {
|
|
4951
|
-
if (this.
|
|
4952
|
-
this.
|
|
6052
|
+
if (this.signLanguageWrapper) {
|
|
6053
|
+
this.signLanguageWrapper.style.display = "none";
|
|
4953
6054
|
}
|
|
4954
6055
|
this.state.signLanguageEnabled = false;
|
|
4955
6056
|
this.emit("signlanguagedisabled");
|
|
@@ -4961,6 +6062,237 @@ var Player = class extends EventEmitter {
|
|
|
4961
6062
|
this.enableSignLanguage();
|
|
4962
6063
|
}
|
|
4963
6064
|
}
|
|
6065
|
+
setupSignLanguageInteraction() {
|
|
6066
|
+
if (!this.signLanguageWrapper) return;
|
|
6067
|
+
let isDragging = false;
|
|
6068
|
+
let isResizing = false;
|
|
6069
|
+
let resizeDirection = null;
|
|
6070
|
+
let startX = 0;
|
|
6071
|
+
let startY = 0;
|
|
6072
|
+
let startLeft = 0;
|
|
6073
|
+
let startTop = 0;
|
|
6074
|
+
let startWidth = 0;
|
|
6075
|
+
let startHeight = 0;
|
|
6076
|
+
let dragMode = false;
|
|
6077
|
+
let resizeMode = false;
|
|
6078
|
+
const onMouseDownVideo = (e) => {
|
|
6079
|
+
if (e.target !== this.signLanguageVideo) return;
|
|
6080
|
+
e.preventDefault();
|
|
6081
|
+
isDragging = true;
|
|
6082
|
+
startX = e.clientX;
|
|
6083
|
+
startY = e.clientY;
|
|
6084
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6085
|
+
startLeft = rect.left;
|
|
6086
|
+
startTop = rect.top;
|
|
6087
|
+
this.signLanguageWrapper.classList.add("vidply-sign-dragging");
|
|
6088
|
+
};
|
|
6089
|
+
const onMouseDownHandle = (e) => {
|
|
6090
|
+
if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
|
|
6091
|
+
e.preventDefault();
|
|
6092
|
+
e.stopPropagation();
|
|
6093
|
+
isResizing = true;
|
|
6094
|
+
resizeDirection = e.target.getAttribute("data-direction");
|
|
6095
|
+
startX = e.clientX;
|
|
6096
|
+
startY = e.clientY;
|
|
6097
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6098
|
+
startLeft = rect.left;
|
|
6099
|
+
startTop = rect.top;
|
|
6100
|
+
startWidth = rect.width;
|
|
6101
|
+
startHeight = rect.height;
|
|
6102
|
+
this.signLanguageWrapper.classList.add("vidply-sign-resizing");
|
|
6103
|
+
};
|
|
6104
|
+
const onMouseMove = (e) => {
|
|
6105
|
+
if (isDragging) {
|
|
6106
|
+
const deltaX = e.clientX - startX;
|
|
6107
|
+
const deltaY = e.clientY - startY;
|
|
6108
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6109
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6110
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6111
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6112
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6113
|
+
let newLeft = startLeft + deltaX - containerRect.left;
|
|
6114
|
+
let newTop = startTop + deltaY - containerRect.top;
|
|
6115
|
+
const controlsHeight = 95;
|
|
6116
|
+
newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
|
|
6117
|
+
newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
|
|
6118
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6119
|
+
this.signLanguageWrapper.style.top = `${newTop}px`;
|
|
6120
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6121
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6122
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6123
|
+
} else if (isResizing) {
|
|
6124
|
+
const deltaX = e.clientX - startX;
|
|
6125
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6126
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6127
|
+
let newWidth = startWidth;
|
|
6128
|
+
let newLeft = startLeft - containerRect.left;
|
|
6129
|
+
if (resizeDirection.includes("e")) {
|
|
6130
|
+
newWidth = Math.max(150, startWidth + deltaX);
|
|
6131
|
+
const maxWidth = videoWrapperRect.right - startLeft;
|
|
6132
|
+
newWidth = Math.min(newWidth, maxWidth);
|
|
6133
|
+
}
|
|
6134
|
+
if (resizeDirection.includes("w")) {
|
|
6135
|
+
const proposedWidth = Math.max(150, startWidth - deltaX);
|
|
6136
|
+
const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
|
|
6137
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6138
|
+
if (proposedLeft >= videoWrapperLeft) {
|
|
6139
|
+
newWidth = proposedWidth;
|
|
6140
|
+
newLeft = proposedLeft;
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
this.signLanguageWrapper.style.width = `${newWidth}px`;
|
|
6144
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6145
|
+
if (resizeDirection.includes("w")) {
|
|
6146
|
+
this.signLanguageWrapper.style.left = `${newLeft}px`;
|
|
6147
|
+
}
|
|
6148
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6149
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6150
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6151
|
+
}
|
|
6152
|
+
};
|
|
6153
|
+
const onMouseUp = () => {
|
|
6154
|
+
if (isDragging || isResizing) {
|
|
6155
|
+
this.saveSignLanguagePreferences();
|
|
6156
|
+
}
|
|
6157
|
+
isDragging = false;
|
|
6158
|
+
isResizing = false;
|
|
6159
|
+
resizeDirection = null;
|
|
6160
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
|
|
6161
|
+
};
|
|
6162
|
+
const onKeyDown = (e) => {
|
|
6163
|
+
if (e.key === "d" || e.key === "D") {
|
|
6164
|
+
dragMode = !dragMode;
|
|
6165
|
+
resizeMode = false;
|
|
6166
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
|
|
6167
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
|
|
6168
|
+
e.preventDefault();
|
|
6169
|
+
return;
|
|
6170
|
+
}
|
|
6171
|
+
if (e.key === "r" || e.key === "R") {
|
|
6172
|
+
resizeMode = !resizeMode;
|
|
6173
|
+
dragMode = false;
|
|
6174
|
+
this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
|
|
6175
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
|
|
6176
|
+
e.preventDefault();
|
|
6177
|
+
return;
|
|
6178
|
+
}
|
|
6179
|
+
if (e.key === "Escape") {
|
|
6180
|
+
dragMode = false;
|
|
6181
|
+
resizeMode = false;
|
|
6182
|
+
this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
|
|
6183
|
+
e.preventDefault();
|
|
6184
|
+
return;
|
|
6185
|
+
}
|
|
6186
|
+
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
6187
|
+
const step = e.shiftKey ? 10 : 5;
|
|
6188
|
+
const rect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6189
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6190
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6191
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6192
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6193
|
+
if (dragMode) {
|
|
6194
|
+
let left = rect.left - containerRect.left;
|
|
6195
|
+
let top = rect.top - containerRect.top;
|
|
6196
|
+
if (e.key === "ArrowLeft") left -= step;
|
|
6197
|
+
if (e.key === "ArrowRight") left += step;
|
|
6198
|
+
if (e.key === "ArrowUp") top -= step;
|
|
6199
|
+
if (e.key === "ArrowDown") top += step;
|
|
6200
|
+
const controlsHeight = 95;
|
|
6201
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
|
|
6202
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
|
|
6203
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6204
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6205
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6206
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6207
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6208
|
+
this.saveSignLanguagePreferences();
|
|
6209
|
+
e.preventDefault();
|
|
6210
|
+
} else if (resizeMode) {
|
|
6211
|
+
let width = rect.width;
|
|
6212
|
+
if (e.key === "ArrowLeft") width -= step;
|
|
6213
|
+
if (e.key === "ArrowRight") width += step;
|
|
6214
|
+
if (e.key === "ArrowUp") width += step;
|
|
6215
|
+
if (e.key === "ArrowDown") width -= step;
|
|
6216
|
+
width = Math.max(150, width);
|
|
6217
|
+
width = Math.min(width, videoWrapperRect.width);
|
|
6218
|
+
this.signLanguageWrapper.style.width = `${width}px`;
|
|
6219
|
+
this.signLanguageWrapper.style.height = "auto";
|
|
6220
|
+
this.saveSignLanguagePreferences();
|
|
6221
|
+
e.preventDefault();
|
|
6222
|
+
}
|
|
6223
|
+
}
|
|
6224
|
+
};
|
|
6225
|
+
this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
|
|
6226
|
+
const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
|
|
6227
|
+
handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
|
|
6228
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
6229
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
6230
|
+
this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
|
|
6231
|
+
this.signLanguageInteractionHandlers = {
|
|
6232
|
+
mouseDownVideo: onMouseDownVideo,
|
|
6233
|
+
mouseDownHandle: onMouseDownHandle,
|
|
6234
|
+
mouseMove: onMouseMove,
|
|
6235
|
+
mouseUp: onMouseUp,
|
|
6236
|
+
keyDown: onKeyDown,
|
|
6237
|
+
handles
|
|
6238
|
+
};
|
|
6239
|
+
}
|
|
6240
|
+
constrainSignLanguagePosition() {
|
|
6241
|
+
if (!this.signLanguageWrapper || !this.videoWrapper) return;
|
|
6242
|
+
if (!this.signLanguageWrapper.style.width || this.signLanguageWrapper.style.width === "") {
|
|
6243
|
+
this.signLanguageWrapper.style.width = "280px";
|
|
6244
|
+
}
|
|
6245
|
+
const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
|
|
6246
|
+
const containerRect = this.container.getBoundingClientRect();
|
|
6247
|
+
const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
|
|
6248
|
+
const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
|
|
6249
|
+
const videoWrapperTop = videoWrapperRect.top - containerRect.top;
|
|
6250
|
+
const videoWrapperWidth = videoWrapperRect.width;
|
|
6251
|
+
const videoWrapperHeight = videoWrapperRect.height;
|
|
6252
|
+
let wrapperWidth = wrapperRect.width || 280;
|
|
6253
|
+
let wrapperHeight = wrapperRect.height || 280 * 9 / 16;
|
|
6254
|
+
let left, top;
|
|
6255
|
+
const margin = 16;
|
|
6256
|
+
const controlsHeight = 95;
|
|
6257
|
+
const position = this.signLanguageDesiredPosition || "bottom-right";
|
|
6258
|
+
switch (position) {
|
|
6259
|
+
case "bottom-right":
|
|
6260
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6261
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6262
|
+
break;
|
|
6263
|
+
case "bottom-left":
|
|
6264
|
+
left = videoWrapperLeft + margin;
|
|
6265
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6266
|
+
break;
|
|
6267
|
+
case "top-right":
|
|
6268
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6269
|
+
top = videoWrapperTop + margin;
|
|
6270
|
+
break;
|
|
6271
|
+
case "top-left":
|
|
6272
|
+
left = videoWrapperLeft + margin;
|
|
6273
|
+
top = videoWrapperTop + margin;
|
|
6274
|
+
break;
|
|
6275
|
+
default:
|
|
6276
|
+
left = videoWrapperLeft + videoWrapperWidth - wrapperWidth - margin;
|
|
6277
|
+
top = videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight;
|
|
6278
|
+
}
|
|
6279
|
+
left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperWidth - wrapperWidth));
|
|
6280
|
+
top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperHeight - wrapperHeight - controlsHeight));
|
|
6281
|
+
this.signLanguageWrapper.style.left = `${left}px`;
|
|
6282
|
+
this.signLanguageWrapper.style.top = `${top}px`;
|
|
6283
|
+
this.signLanguageWrapper.style.right = "auto";
|
|
6284
|
+
this.signLanguageWrapper.style.bottom = "auto";
|
|
6285
|
+
this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
|
|
6286
|
+
}
|
|
6287
|
+
saveSignLanguagePreferences() {
|
|
6288
|
+
if (!this.signLanguageWrapper) return;
|
|
6289
|
+
this.storage.saveSignLanguagePreferences({
|
|
6290
|
+
size: {
|
|
6291
|
+
width: this.signLanguageWrapper.style.width
|
|
6292
|
+
// Height is auto - maintained by aspect ratio
|
|
6293
|
+
}
|
|
6294
|
+
});
|
|
6295
|
+
}
|
|
4964
6296
|
cleanupSignLanguage() {
|
|
4965
6297
|
if (this.signLanguageHandlers) {
|
|
4966
6298
|
this.off("play", this.signLanguageHandlers.play);
|
|
@@ -4969,10 +6301,29 @@ var Player = class extends EventEmitter {
|
|
|
4969
6301
|
this.off("ratechange", this.signLanguageHandlers.ratechange);
|
|
4970
6302
|
this.signLanguageHandlers = null;
|
|
4971
6303
|
}
|
|
4972
|
-
if (this.
|
|
4973
|
-
this.signLanguageVideo
|
|
4974
|
-
|
|
4975
|
-
|
|
6304
|
+
if (this.signLanguageInteractionHandlers) {
|
|
6305
|
+
if (this.signLanguageVideo) {
|
|
6306
|
+
this.signLanguageVideo.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownVideo);
|
|
6307
|
+
}
|
|
6308
|
+
if (this.signLanguageInteractionHandlers.handles) {
|
|
6309
|
+
this.signLanguageInteractionHandlers.handles.forEach((handle) => {
|
|
6310
|
+
handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
|
|
6311
|
+
});
|
|
6312
|
+
}
|
|
6313
|
+
document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
|
|
6314
|
+
document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
|
|
6315
|
+
if (this.signLanguageWrapper) {
|
|
6316
|
+
this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
|
|
6317
|
+
}
|
|
6318
|
+
this.signLanguageInteractionHandlers = null;
|
|
6319
|
+
}
|
|
6320
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
|
|
6321
|
+
if (this.signLanguageVideo) {
|
|
6322
|
+
this.signLanguageVideo.pause();
|
|
6323
|
+
this.signLanguageVideo.src = "";
|
|
6324
|
+
}
|
|
6325
|
+
this.signLanguageWrapper.parentNode.removeChild(this.signLanguageWrapper);
|
|
6326
|
+
this.signLanguageWrapper = null;
|
|
4976
6327
|
this.signLanguageVideo = null;
|
|
4977
6328
|
}
|
|
4978
6329
|
}
|
|
@@ -5062,6 +6413,35 @@ var Player = class extends EventEmitter {
|
|
|
5062
6413
|
}
|
|
5063
6414
|
this.orientationQuery = orientationQuery;
|
|
5064
6415
|
}
|
|
6416
|
+
this.fullscreenChangeHandler = () => {
|
|
6417
|
+
const isFullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
|
|
6418
|
+
if (this.state.fullscreen !== isFullscreen) {
|
|
6419
|
+
this.state.fullscreen = isFullscreen;
|
|
6420
|
+
if (isFullscreen) {
|
|
6421
|
+
this.container.classList.add(`${this.options.classPrefix}-fullscreen`);
|
|
6422
|
+
} else {
|
|
6423
|
+
this.container.classList.remove(`${this.options.classPrefix}-fullscreen`);
|
|
6424
|
+
}
|
|
6425
|
+
this.emit("fullscreenchange", isFullscreen);
|
|
6426
|
+
if (this.controlBar) {
|
|
6427
|
+
this.controlBar.updateFullscreenButton();
|
|
6428
|
+
}
|
|
6429
|
+
if (this.signLanguageWrapper && this.signLanguageWrapper.style.display !== "none") {
|
|
6430
|
+
setTimeout(() => {
|
|
6431
|
+
requestAnimationFrame(() => {
|
|
6432
|
+
this.storage.saveSignLanguagePreferences({ size: null });
|
|
6433
|
+
this.signLanguageDesiredPosition = "bottom-right";
|
|
6434
|
+
this.signLanguageWrapper.style.width = isFullscreen ? "400px" : "280px";
|
|
6435
|
+
this.constrainSignLanguagePosition();
|
|
6436
|
+
});
|
|
6437
|
+
}, 500);
|
|
6438
|
+
}
|
|
6439
|
+
}
|
|
6440
|
+
};
|
|
6441
|
+
document.addEventListener("fullscreenchange", this.fullscreenChangeHandler);
|
|
6442
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenChangeHandler);
|
|
6443
|
+
document.addEventListener("mozfullscreenchange", this.fullscreenChangeHandler);
|
|
6444
|
+
document.addEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
|
|
5065
6445
|
}
|
|
5066
6446
|
// Cleanup
|
|
5067
6447
|
destroy() {
|
|
@@ -5103,6 +6483,13 @@ var Player = class extends EventEmitter {
|
|
|
5103
6483
|
this.orientationQuery = null;
|
|
5104
6484
|
this.orientationHandler = null;
|
|
5105
6485
|
}
|
|
6486
|
+
if (this.fullscreenChangeHandler) {
|
|
6487
|
+
document.removeEventListener("fullscreenchange", this.fullscreenChangeHandler);
|
|
6488
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenChangeHandler);
|
|
6489
|
+
document.removeEventListener("mozfullscreenchange", this.fullscreenChangeHandler);
|
|
6490
|
+
document.removeEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
|
|
6491
|
+
this.fullscreenChangeHandler = null;
|
|
6492
|
+
}
|
|
5106
6493
|
if (this.container && this.container.parentNode) {
|
|
5107
6494
|
this.container.parentNode.insertBefore(this.element, this.container);
|
|
5108
6495
|
this.container.parentNode.removeChild(this.container);
|