vidply 1.0.9 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vidply.js CHANGED
@@ -517,11 +517,20 @@ var VidPly = (() => {
517
517
  settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
518
518
  keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
519
519
  keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
520
+ dragResizePrompt: "Press D to drag or R to resize. Use Home to reset position, Esc to close.",
521
+ dragModeEnabled: "Keyboard drag mode enabled. Use arrow keys to move, Shift+Arrow for larger steps. Press D or Esc to exit.",
522
+ dragModeDisabled: "Keyboard drag mode disabled.",
520
523
  resizeWindow: "Resize Window",
524
+ disableResizeWindow: "Disable Resize Mode",
525
+ resizeModeHint: "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
526
+ resizeModeEnabled: "Resize mode enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
527
+ resizeModeDisabled: "Resize mode disabled.",
528
+ positionReset: "Transcript position reset.",
521
529
  styleTranscript: "Open transcript style settings",
522
530
  closeMenu: "Close Menu",
523
531
  styleTitle: "Transcript Style",
524
- autoscroll: "Autoscroll"
532
+ autoscroll: "Autoscroll",
533
+ settingsMenu: "Settings menu"
525
534
  },
526
535
  settings: {
527
536
  title: "Settings",
@@ -639,11 +648,20 @@ var VidPly = (() => {
639
648
  settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
640
649
  keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
641
650
  keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
651
+ dragResizePrompt: "Dr\xFCcken Sie D zum Verschieben oder R zur Gr\xF6\xDFen\xE4nderung. Home setzt die Position zur\xFCck, Esc schlie\xDFt.",
652
+ dragModeEnabled: "Tastatur-Verschiebemodus aktiviert. Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gr\xF6\xDFere Schritte. D oder Esc zum Beenden.",
653
+ dragModeDisabled: "Tastatur-Verschiebemodus deaktiviert.",
642
654
  resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
655
+ disableResizeWindow: "Resize-Modus deaktivieren",
656
+ resizeModeHint: "Griffe aktiviert. Ziehen Sie Kanten oder Ecken zum Anpassen. Esc oder R zum Beenden.",
657
+ resizeModeEnabled: "Resize-Modus aktiviert. Kanten oder Ecken ziehen; Esc oder R beendet.",
658
+ resizeModeDisabled: "Resize-Modus deaktiviert.",
659
+ positionReset: "Transkriptposition zur\xFCckgesetzt.",
643
660
  styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
644
661
  closeMenu: "Men\xFC schlie\xDFen",
645
662
  styleTitle: "Transkript-Stil",
646
- autoscroll: "Automatisches Scrollen"
663
+ autoscroll: "Automatisches Scrollen",
664
+ settingsMenu: "Einstellungsmen\xFC"
647
665
  },
648
666
  settings: {
649
667
  title: "Einstellungen",
@@ -761,11 +779,20 @@ var VidPly = (() => {
761
779
  settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
762
780
  keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
763
781
  keyboardDragActive: "\u2328\uFE0F Modo de Arrastre con Teclado Activo (Teclas de flecha para mover, May\xFAs+Flechas para pasos grandes, D o ESC para salir)",
782
+ dragResizePrompt: "Pulsa D para mover o R para cambiar el tama\xF1o. Home restablece la posici\xF3n; Esc cierra.",
783
+ dragModeEnabled: "Modo de arrastre con teclado activado. Usa flechas para mover, May\xFAs+Flechas para pasos grandes. Pulsa D o Esc para salir.",
784
+ dragModeDisabled: "Modo de arrastre con teclado desactivado.",
764
785
  resizeWindow: "Cambiar tama\xF1o de ventana",
786
+ disableResizeWindow: "Desactivar modo de cambio de tama\xF1o",
787
+ resizeModeHint: "Controladores habilitados. Arrastra bordes o esquinas para ajustar. Pulsa Esc o R para salir.",
788
+ resizeModeEnabled: "Modo de cambio de tama\xF1o activado. Arrastra bordes o esquinas. Pulsa Esc o R para salir.",
789
+ resizeModeDisabled: "Modo de cambio de tama\xF1o desactivado.",
790
+ positionReset: "Posici\xF3n de la transcripci\xF3n restablecida.",
765
791
  styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
766
792
  closeMenu: "Cerrar men\xFA",
767
793
  styleTitle: "Estilo de Transcripci\xF3n",
768
- autoscroll: "Desplazamiento autom\xE1tico"
794
+ autoscroll: "Desplazamiento autom\xE1tico",
795
+ settingsMenu: "Men\xFA de configuraci\xF3n"
769
796
  },
770
797
  settings: {
771
798
  title: "Configuraci\xF3n",
@@ -883,11 +910,20 @@ var VidPly = (() => {
883
910
  settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
884
911
  keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
885
912
  keyboardDragActive: "\u2328\uFE0F Mode Glissement Clavier Actif (Touches fl\xE9ch\xE9es pour d\xE9placer, Maj+Fl\xE9ch\xE9es pour grands pas, D ou \xC9chap pour quitter)",
913
+ dragResizePrompt: "Appuyez sur D pour d\xE9placer ou R pour redimensionner. Home r\xE9initialise la position, \xC9chap ferme.",
914
+ dragModeEnabled: "Mode glissement clavier activ\xE9. Utilisez les fl\xE8ches pour d\xE9placer, Maj+Fl\xE8ches pour de grands pas. Appuyez sur D ou \xC9chap pour quitter.",
915
+ dragModeDisabled: "Mode glissement clavier d\xE9sactiv\xE9.",
886
916
  resizeWindow: "Redimensionner la fen\xEAtre",
917
+ disableResizeWindow: "D\xE9sactiver le mode de redimensionnement",
918
+ resizeModeHint: "Poign\xE9es activ\xE9es. Faites glisser les bords ou les coins pour ajuster. Appuyez sur \xC9chap ou R pour quitter.",
919
+ resizeModeEnabled: "Mode redimensionnement activ\xE9. Faites glisser les bords ou coins. Appuyez sur \xC9chap ou R pour quitter.",
920
+ resizeModeDisabled: "Mode redimensionnement d\xE9sactiv\xE9.",
921
+ positionReset: "Position de la transcription r\xE9initialis\xE9e.",
887
922
  styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
888
923
  closeMenu: "Fermer le menu",
889
924
  styleTitle: "Style de Transcription",
890
- autoscroll: "D\xE9filement automatique"
925
+ autoscroll: "D\xE9filement automatique",
926
+ settingsMenu: "Menu des param\xE8tres"
891
927
  },
892
928
  settings: {
893
929
  title: "Param\xE8tres",
@@ -1005,11 +1041,20 @@ var VidPly = (() => {
1005
1041
  settings: "\u6587\u5B57\u8D77\u3053\u3057\u8A2D\u5B9A\u3002Enter\u30AD\u30FC\u3067\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F\u3001\u307E\u305F\u306FD\u30AD\u30FC\u3067\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3059\u308B",
1006
1042
  keyboardDragMode: "\u77E2\u5370\u30AD\u30FC\u3067\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u5207\u308A\u66FF\u3048\u3002\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8\uFF1AD\u30AD\u30FC",
1007
1043
  keyboardDragActive: "\u2328\uFE0F \u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u6709\u52B9\uFF08\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Shift+\u77E2\u5370\u30AD\u30FC\u3067\u5927\u304D\u304F\u79FB\u52D5\u3001D\u307E\u305F\u306FESC\u3067\u7D42\u4E86\uFF09",
1044
+ dragResizePrompt: "D\u30AD\u30FC\u3067\u79FB\u52D5\u3001R\u30AD\u30FC\u3067\u30B5\u30A4\u30BA\u5909\u66F4\u3002Home\u3067\u4F4D\u7F6E\u3092\u30EA\u30BB\u30C3\u30C8\u3001Esc\u3067\u9589\u3058\u307E\u3059\u3002",
1045
+ dragModeEnabled: "\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u307E\u3057\u305F\u3002\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Shift+\u77E2\u5370\u30AD\u30FC\u3067\u5927\u304D\u304F\u79FB\u52D5\u3067\u304D\u307E\u3059\u3002\u7D42\u4E86\u3059\u308B\u306B\u306F D \u307E\u305F\u306F Esc \u3092\u62BC\u3057\u307E\u3059\u3002",
1046
+ dragModeDisabled: "\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
1008
1047
  resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
1048
+ disableResizeWindow: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3059\u308B",
1049
+ resizeModeHint: "\u30EA\u30B5\u30A4\u30BA\u30CF\u30F3\u30C9\u30EB\u304C\u6709\u52B9\u306B\u306A\u308A\u307E\u3057\u305F\u3002\u8FBA\u3084\u89D2\u3092\u30C9\u30E9\u30C3\u30B0\u3057\u3066\u8ABF\u6574\u3057\u307E\u3059\u3002Esc \u307E\u305F\u306F R \u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
1050
+ resizeModeEnabled: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u307E\u3057\u305F\u3002\u8FBA\u3084\u89D2\u3092\u30C9\u30E9\u30C3\u30B0\u3057\u3066\u8ABF\u6574\u3057\u307E\u3059\u3002Esc \u307E\u305F\u306F R \u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
1051
+ resizeModeDisabled: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
1052
+ positionReset: "\u6587\u5B57\u8D77\u3053\u3057\u306E\u4F4D\u7F6E\u3092\u30EA\u30BB\u30C3\u30C8\u3057\u307E\u3057\u305F\u3002",
1009
1053
  styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
1010
1054
  closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
1011
1055
  styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB",
1012
- autoscroll: "\u81EA\u52D5\u30B9\u30AF\u30ED\u30FC\u30EB"
1056
+ autoscroll: "\u81EA\u52D5\u30B9\u30AF\u30ED\u30FC\u30EB",
1057
+ settingsMenu: "\u8A2D\u5B9A\u30E1\u30CB\u30E5\u30FC"
1013
1058
  },
1014
1059
  settings: {
1015
1060
  title: "\u8A2D\u5B9A",
@@ -1797,10 +1842,7 @@ var VidPly = (() => {
1797
1842
  }
1798
1843
  });
1799
1844
  this.controls.currentTimeDisplay = DOMUtils.createElement("span", {
1800
- className: `${this.player.options.classPrefix}-current-time`,
1801
- attributes: {
1802
- "aria-label": i18n.t("time.seconds", { count: 0 })
1803
- }
1845
+ className: `${this.player.options.classPrefix}-current-time`
1804
1846
  });
1805
1847
  const currentTimeVisual = DOMUtils.createElement("span", {
1806
1848
  textContent: "00:00",
@@ -1808,8 +1850,14 @@ var VidPly = (() => {
1808
1850
  "aria-hidden": "true"
1809
1851
  }
1810
1852
  });
1853
+ const currentTimeAccessible = DOMUtils.createElement("span", {
1854
+ className: "vidply-sr-only",
1855
+ textContent: i18n.t("time.seconds", { count: 0 })
1856
+ });
1811
1857
  this.controls.currentTimeDisplay.appendChild(currentTimeVisual);
1858
+ this.controls.currentTimeDisplay.appendChild(currentTimeAccessible);
1812
1859
  this.controls.currentTimeVisual = currentTimeVisual;
1860
+ this.controls.currentTimeAccessible = currentTimeAccessible;
1813
1861
  const separator = DOMUtils.createElement("span", {
1814
1862
  textContent: " / ",
1815
1863
  attributes: {
@@ -1817,10 +1865,7 @@ var VidPly = (() => {
1817
1865
  }
1818
1866
  });
1819
1867
  this.controls.durationDisplay = DOMUtils.createElement("span", {
1820
- className: `${this.player.options.classPrefix}-duration`,
1821
- attributes: {
1822
- "aria-label": i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
1823
- }
1868
+ className: `${this.player.options.classPrefix}-duration`
1824
1869
  });
1825
1870
  const durationVisual = DOMUtils.createElement("span", {
1826
1871
  textContent: "00:00",
@@ -1828,8 +1873,14 @@ var VidPly = (() => {
1828
1873
  "aria-hidden": "true"
1829
1874
  }
1830
1875
  });
1876
+ const durationAccessible = DOMUtils.createElement("span", {
1877
+ className: "vidply-sr-only",
1878
+ textContent: i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
1879
+ });
1831
1880
  this.controls.durationDisplay.appendChild(durationVisual);
1881
+ this.controls.durationDisplay.appendChild(durationAccessible);
1832
1882
  this.controls.durationVisual = durationVisual;
1883
+ this.controls.durationAccessible = durationAccessible;
1833
1884
  container.appendChild(this.controls.currentTimeDisplay);
1834
1885
  container.appendChild(separator);
1835
1886
  container.appendChild(this.controls.durationDisplay);
@@ -2656,14 +2707,18 @@ var VidPly = (() => {
2656
2707
  if (this.controls.currentTimeVisual) {
2657
2708
  const currentTime = this.player.state.currentTime;
2658
2709
  this.controls.currentTimeVisual.textContent = TimeUtils.formatTime(currentTime);
2659
- this.controls.currentTimeDisplay.setAttribute("aria-label", TimeUtils.formatDuration(currentTime));
2710
+ if (this.controls.currentTimeAccessible) {
2711
+ this.controls.currentTimeAccessible.textContent = TimeUtils.formatDuration(currentTime);
2712
+ }
2660
2713
  }
2661
2714
  }
2662
2715
  updateDuration() {
2663
2716
  if (this.controls.durationVisual) {
2664
2717
  const duration = this.player.state.duration;
2665
2718
  this.controls.durationVisual.textContent = TimeUtils.formatTime(duration);
2666
- this.controls.durationDisplay.setAttribute("aria-label", i18n.t("time.durationPrefix") + TimeUtils.formatDuration(duration));
2719
+ if (this.controls.durationAccessible) {
2720
+ this.controls.durationAccessible.textContent = i18n.t("time.durationPrefix") + TimeUtils.formatDuration(duration);
2721
+ }
2667
2722
  }
2668
2723
  }
2669
2724
  updateVolumeDisplay() {
@@ -3318,6 +3373,596 @@ var VidPly = (() => {
3318
3373
  }
3319
3374
  };
3320
3375
 
3376
+ // src/utils/DraggableResizable.js
3377
+ var DraggableResizable = class {
3378
+ constructor(element, options = {}) {
3379
+ this.element = element;
3380
+ this.options = {
3381
+ dragHandle: null,
3382
+ // Element to use as drag handle (defaults to element itself)
3383
+ resizeHandles: [],
3384
+ // Array of resize handle elements
3385
+ onDragStart: null,
3386
+ onDrag: null,
3387
+ onDragEnd: null,
3388
+ onResizeStart: null,
3389
+ onResize: null,
3390
+ onResizeEnd: null,
3391
+ constrainToViewport: true,
3392
+ // Allow movement outside viewport?
3393
+ minWidth: 150,
3394
+ minHeight: 100,
3395
+ maintainAspectRatio: false,
3396
+ keyboardDragKey: "d",
3397
+ keyboardResizeKey: "r",
3398
+ keyboardStep: 5,
3399
+ keyboardStepLarge: 10,
3400
+ maxWidth: null,
3401
+ maxHeight: null,
3402
+ pointerResizeIndicatorText: null,
3403
+ onPointerResizeToggle: null,
3404
+ classPrefix: "draggable",
3405
+ storage: null,
3406
+ // StorageManager instance for saving position/size
3407
+ storageKey: null,
3408
+ // Key for localStorage (if storage is provided)
3409
+ ...options
3410
+ };
3411
+ this.isDragging = false;
3412
+ this.isResizing = false;
3413
+ this.resizeDirection = null;
3414
+ this.dragOffsetX = 0;
3415
+ this.dragOffsetY = 0;
3416
+ this.positionOffsetX = 0;
3417
+ this.positionOffsetY = 0;
3418
+ this.initialMouseX = 0;
3419
+ this.initialMouseY = 0;
3420
+ this.needsPositionConversion = false;
3421
+ this.resizeStartX = 0;
3422
+ this.resizeStartY = 0;
3423
+ this.resizeStartWidth = 0;
3424
+ this.resizeStartHeight = 0;
3425
+ this.resizeStartLeft = 0;
3426
+ this.resizeStartTop = 0;
3427
+ this.keyboardDragMode = false;
3428
+ this.keyboardResizeMode = false;
3429
+ this.pointerResizeMode = false;
3430
+ this.manuallyPositioned = false;
3431
+ this.resizeHandlesManaged = /* @__PURE__ */ new Map();
3432
+ this.resizeIndicatorElement = null;
3433
+ this.handlers = {
3434
+ mousedown: this.onMouseDown.bind(this),
3435
+ mousemove: this.onMouseMove.bind(this),
3436
+ mouseup: this.onMouseUp.bind(this),
3437
+ touchstart: this.onTouchStart.bind(this),
3438
+ touchmove: this.onTouchMove.bind(this),
3439
+ touchend: this.onTouchEnd.bind(this),
3440
+ keydown: this.onKeyDown.bind(this),
3441
+ resizeHandleMousedown: this.onResizeHandleMouseDown.bind(this)
3442
+ };
3443
+ this.init();
3444
+ }
3445
+ hasManagedResizeHandles() {
3446
+ return Array.from(this.resizeHandlesManaged.values()).some(Boolean);
3447
+ }
3448
+ storeOriginalHandleDisplay(handle) {
3449
+ if (!handle.dataset.originalDisplay) {
3450
+ handle.dataset.originalDisplay = handle.style.display || "";
3451
+ }
3452
+ }
3453
+ hideResizeHandle(handle) {
3454
+ handle.style.display = "none";
3455
+ handle.setAttribute("aria-hidden", "true");
3456
+ }
3457
+ showResizeHandle(handle) {
3458
+ const original = handle.dataset.originalDisplay !== void 0 ? handle.dataset.originalDisplay : "";
3459
+ handle.style.display = original;
3460
+ handle.removeAttribute("aria-hidden");
3461
+ }
3462
+ setManagedHandlesVisible(visible) {
3463
+ if (!this.options.resizeHandles || this.options.resizeHandles.length === 0) {
3464
+ return;
3465
+ }
3466
+ this.options.resizeHandles.forEach((handle) => {
3467
+ if (!this.resizeHandlesManaged.get(handle)) {
3468
+ return;
3469
+ }
3470
+ if (visible) {
3471
+ this.showResizeHandle(handle);
3472
+ } else {
3473
+ this.hideResizeHandle(handle);
3474
+ }
3475
+ });
3476
+ }
3477
+ init() {
3478
+ const dragHandle = this.options.dragHandle || this.element;
3479
+ dragHandle.addEventListener("mousedown", this.handlers.mousedown);
3480
+ dragHandle.addEventListener("touchstart", this.handlers.touchstart);
3481
+ document.addEventListener("mousemove", this.handlers.mousemove);
3482
+ document.addEventListener("mouseup", this.handlers.mouseup);
3483
+ document.addEventListener("touchmove", this.handlers.touchmove, { passive: false });
3484
+ document.addEventListener("touchend", this.handlers.touchend);
3485
+ this.element.addEventListener("keydown", this.handlers.keydown);
3486
+ if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
3487
+ this.options.resizeHandles.forEach((handle) => {
3488
+ handle.addEventListener("mousedown", this.handlers.resizeHandleMousedown);
3489
+ handle.addEventListener("touchstart", this.handlers.resizeHandleMousedown);
3490
+ const managed = handle.dataset.vidplyManagedResize === "true";
3491
+ this.resizeHandlesManaged.set(handle, managed);
3492
+ if (managed) {
3493
+ this.storeOriginalHandleDisplay(handle);
3494
+ this.hideResizeHandle(handle);
3495
+ }
3496
+ });
3497
+ }
3498
+ }
3499
+ onMouseDown(e) {
3500
+ if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
3501
+ return;
3502
+ }
3503
+ if (this.options.onDragStart && !this.options.onDragStart(e)) {
3504
+ return;
3505
+ }
3506
+ this.startDragging(e.clientX, e.clientY);
3507
+ e.preventDefault();
3508
+ }
3509
+ onTouchStart(e) {
3510
+ if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
3511
+ return;
3512
+ }
3513
+ if (this.options.onDragStart && !this.options.onDragStart(e)) {
3514
+ return;
3515
+ }
3516
+ const touch = e.touches[0];
3517
+ this.startDragging(touch.clientX, touch.clientY);
3518
+ }
3519
+ onResizeHandleMouseDown(e) {
3520
+ var _a, _b, _c, _d;
3521
+ e.preventDefault();
3522
+ e.stopPropagation();
3523
+ const handle = e.target;
3524
+ this.resizeDirection = handle.getAttribute("data-direction");
3525
+ const clientX = e.clientX || ((_b = (_a = e.touches) == null ? void 0 : _a[0]) == null ? void 0 : _b.clientX);
3526
+ const clientY = e.clientY || ((_d = (_c = e.touches) == null ? void 0 : _c[0]) == null ? void 0 : _d.clientY);
3527
+ this.startResizing(clientX, clientY);
3528
+ }
3529
+ onMouseMove(e) {
3530
+ if (this.isDragging) {
3531
+ this.drag(e.clientX, e.clientY);
3532
+ e.preventDefault();
3533
+ } else if (this.isResizing) {
3534
+ this.resize(e.clientX, e.clientY);
3535
+ e.preventDefault();
3536
+ }
3537
+ }
3538
+ onTouchMove(e) {
3539
+ if (this.isDragging || this.isResizing) {
3540
+ const touch = e.touches[0];
3541
+ if (this.isDragging) {
3542
+ this.drag(touch.clientX, touch.clientY);
3543
+ } else {
3544
+ this.resize(touch.clientX, touch.clientY);
3545
+ }
3546
+ e.preventDefault();
3547
+ }
3548
+ }
3549
+ onMouseUp() {
3550
+ if (this.isDragging) {
3551
+ this.stopDragging();
3552
+ } else if (this.isResizing) {
3553
+ this.stopResizing();
3554
+ }
3555
+ }
3556
+ onTouchEnd() {
3557
+ if (this.isDragging) {
3558
+ this.stopDragging();
3559
+ } else if (this.isResizing) {
3560
+ this.stopResizing();
3561
+ }
3562
+ }
3563
+ onKeyDown(e) {
3564
+ if (e.key.toLowerCase() === this.options.keyboardDragKey.toLowerCase()) {
3565
+ e.preventDefault();
3566
+ this.toggleKeyboardDragMode();
3567
+ return;
3568
+ }
3569
+ if (e.key.toLowerCase() === this.options.keyboardResizeKey.toLowerCase()) {
3570
+ e.preventDefault();
3571
+ if (this.hasManagedResizeHandles()) {
3572
+ this.togglePointerResizeMode();
3573
+ } else {
3574
+ this.toggleKeyboardResizeMode();
3575
+ }
3576
+ return;
3577
+ }
3578
+ if (e.key === "Escape") {
3579
+ if (this.pointerResizeMode) {
3580
+ e.preventDefault();
3581
+ this.disablePointerResizeMode();
3582
+ return;
3583
+ }
3584
+ if (this.keyboardDragMode || this.keyboardResizeMode) {
3585
+ e.preventDefault();
3586
+ this.disableKeyboardDragMode();
3587
+ this.disableKeyboardResizeMode();
3588
+ return;
3589
+ }
3590
+ }
3591
+ if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
3592
+ if (this.keyboardDragMode) {
3593
+ e.preventDefault();
3594
+ e.stopPropagation();
3595
+ this.keyboardDrag(e.key, e.shiftKey);
3596
+ } else if (this.keyboardResizeMode) {
3597
+ e.preventDefault();
3598
+ e.stopPropagation();
3599
+ this.keyboardResize(e.key, e.shiftKey);
3600
+ }
3601
+ }
3602
+ if (e.key === "Home" && (this.keyboardDragMode || this.keyboardResizeMode)) {
3603
+ e.preventDefault();
3604
+ this.resetPosition();
3605
+ }
3606
+ }
3607
+ startDragging(clientX, clientY) {
3608
+ const rect = this.element.getBoundingClientRect();
3609
+ const computedStyle = window.getComputedStyle(this.element);
3610
+ const needsConversion = computedStyle.right !== "auto" || computedStyle.bottom !== "auto" || computedStyle.transform !== "none";
3611
+ this.positionOffsetX = 0;
3612
+ this.positionOffsetY = 0;
3613
+ if (needsConversion) {
3614
+ let targetLeft, targetTop;
3615
+ if (computedStyle.position === "absolute") {
3616
+ const offsetParent = this.element.offsetParent || document.body;
3617
+ const parentRect = offsetParent.getBoundingClientRect();
3618
+ targetLeft = rect.left - parentRect.left;
3619
+ targetTop = rect.top - parentRect.top;
3620
+ this.positionOffsetX = parentRect.left;
3621
+ this.positionOffsetY = parentRect.top;
3622
+ } else if (computedStyle.position === "fixed") {
3623
+ const parsedLeft = parseFloat(computedStyle.left);
3624
+ const parsedTop = parseFloat(computedStyle.top);
3625
+ const hasLeft = Number.isFinite(parsedLeft);
3626
+ const hasTop = Number.isFinite(parsedTop);
3627
+ targetLeft = hasLeft ? parsedLeft : rect.left;
3628
+ targetTop = hasTop ? parsedTop : rect.top;
3629
+ this.positionOffsetX = rect.left - targetLeft;
3630
+ this.positionOffsetY = rect.top - targetTop;
3631
+ } else {
3632
+ targetLeft = rect.left;
3633
+ targetTop = rect.top;
3634
+ this.positionOffsetX = rect.left - targetLeft;
3635
+ this.positionOffsetY = rect.top - targetTop;
3636
+ }
3637
+ const currentCssText = this.element.style.cssText;
3638
+ let newCssText = currentCssText.split(";").filter((rule) => {
3639
+ const trimmed = rule.trim();
3640
+ return trimmed && !trimmed.startsWith("right:") && !trimmed.startsWith("bottom:") && !trimmed.startsWith("transform:") && !trimmed.startsWith("left:") && !trimmed.startsWith("top:") && !trimmed.startsWith("inset:");
3641
+ }).join("; ");
3642
+ if (newCssText) newCssText += "; ";
3643
+ newCssText += `left: ${targetLeft}px; top: ${targetTop}px; right: auto; bottom: auto; transform: none`;
3644
+ this.element.style.cssText = newCssText;
3645
+ }
3646
+ const finalRect = this.element.getBoundingClientRect();
3647
+ this.dragOffsetX = clientX - finalRect.left;
3648
+ this.dragOffsetY = clientY - finalRect.top;
3649
+ this.isDragging = true;
3650
+ this.element.classList.add(`${this.options.classPrefix}-dragging`);
3651
+ document.body.style.cursor = "grabbing";
3652
+ document.body.style.userSelect = "none";
3653
+ }
3654
+ drag(clientX, clientY) {
3655
+ if (!this.isDragging) return;
3656
+ let newX = clientX - this.dragOffsetX - this.positionOffsetX;
3657
+ let newY = clientY - this.dragOffsetY - this.positionOffsetY;
3658
+ if (this.options.constrainToViewport) {
3659
+ const rect = this.element.getBoundingClientRect();
3660
+ const viewportWidth = document.documentElement.clientWidth;
3661
+ const viewportHeight = document.documentElement.clientHeight;
3662
+ const minVisible = 100;
3663
+ const minX = -(rect.width - minVisible);
3664
+ const minY = -(rect.height - minVisible);
3665
+ const maxX = viewportWidth - minVisible;
3666
+ const maxY = viewportHeight - minVisible;
3667
+ newX = Math.max(minX, Math.min(newX, maxX));
3668
+ newY = Math.max(minY, Math.min(newY, maxY));
3669
+ }
3670
+ this.element.style.left = `${newX}px`;
3671
+ this.element.style.top = `${newY}px`;
3672
+ if (this.options.onDrag) {
3673
+ this.options.onDrag({ x: newX, y: newY });
3674
+ }
3675
+ }
3676
+ stopDragging() {
3677
+ this.isDragging = false;
3678
+ this.element.classList.remove(`${this.options.classPrefix}-dragging`);
3679
+ document.body.style.cursor = "";
3680
+ document.body.style.userSelect = "";
3681
+ this.manuallyPositioned = true;
3682
+ if (this.options.onDragEnd) {
3683
+ this.options.onDragEnd();
3684
+ }
3685
+ }
3686
+ startResizing(clientX, clientY) {
3687
+ this.isResizing = true;
3688
+ this.resizeStartX = clientX;
3689
+ this.resizeStartY = clientY;
3690
+ const rect = this.element.getBoundingClientRect();
3691
+ this.resizeStartWidth = rect.width;
3692
+ this.resizeStartHeight = rect.height;
3693
+ this.resizeStartLeft = rect.left;
3694
+ this.resizeStartTop = rect.top;
3695
+ this.element.classList.add(`${this.options.classPrefix}-resizing`);
3696
+ document.body.style.userSelect = "none";
3697
+ if (this.options.onResizeStart) {
3698
+ this.options.onResizeStart();
3699
+ }
3700
+ }
3701
+ resize(clientX, clientY) {
3702
+ if (!this.isResizing) return;
3703
+ const deltaX = clientX - this.resizeStartX;
3704
+ const deltaY = clientY - this.resizeStartY;
3705
+ let newWidth = this.resizeStartWidth;
3706
+ let newHeight = this.resizeStartHeight;
3707
+ let newLeft = this.resizeStartLeft;
3708
+ let newTop = this.resizeStartTop;
3709
+ if (this.resizeDirection.includes("e")) {
3710
+ newWidth = Math.max(this.options.minWidth, this.resizeStartWidth + deltaX);
3711
+ }
3712
+ if (this.resizeDirection.includes("w")) {
3713
+ const proposedWidth = Math.max(this.options.minWidth, this.resizeStartWidth - deltaX);
3714
+ newLeft = this.resizeStartLeft + (this.resizeStartWidth - proposedWidth);
3715
+ newWidth = proposedWidth;
3716
+ }
3717
+ const maxWidthOption = typeof this.options.maxWidth === "function" ? this.options.maxWidth() : this.options.maxWidth;
3718
+ if (Number.isFinite(maxWidthOption)) {
3719
+ const clampedWidth = Math.min(newWidth, maxWidthOption);
3720
+ if (clampedWidth !== newWidth && this.resizeDirection.includes("w")) {
3721
+ newLeft += newWidth - clampedWidth;
3722
+ }
3723
+ newWidth = clampedWidth;
3724
+ }
3725
+ if (!this.options.maintainAspectRatio) {
3726
+ if (this.resizeDirection.includes("s")) {
3727
+ newHeight = Math.max(this.options.minHeight, this.resizeStartHeight + deltaY);
3728
+ }
3729
+ if (this.resizeDirection.includes("n")) {
3730
+ const proposedHeight = Math.max(this.options.minHeight, this.resizeStartHeight - deltaY);
3731
+ newTop = this.resizeStartTop + (this.resizeStartHeight - proposedHeight);
3732
+ newHeight = proposedHeight;
3733
+ }
3734
+ const maxHeightOption = typeof this.options.maxHeight === "function" ? this.options.maxHeight() : this.options.maxHeight;
3735
+ if (Number.isFinite(maxHeightOption)) {
3736
+ const clampedHeight = Math.min(newHeight, maxHeightOption);
3737
+ if (clampedHeight !== newHeight && this.resizeDirection.includes("n")) {
3738
+ newTop += newHeight - clampedHeight;
3739
+ }
3740
+ newHeight = clampedHeight;
3741
+ }
3742
+ }
3743
+ this.element.style.width = `${newWidth}px`;
3744
+ if (!this.options.maintainAspectRatio) {
3745
+ this.element.style.height = `${newHeight}px`;
3746
+ } else {
3747
+ this.element.style.height = "auto";
3748
+ }
3749
+ if (this.resizeDirection.includes("w")) {
3750
+ this.element.style.left = `${newLeft}px`;
3751
+ }
3752
+ if (this.resizeDirection.includes("n") && !this.options.maintainAspectRatio) {
3753
+ this.element.style.top = `${newTop}px`;
3754
+ }
3755
+ if (this.options.onResize) {
3756
+ this.options.onResize({ width: newWidth, height: newHeight, left: newLeft, top: newTop });
3757
+ }
3758
+ }
3759
+ stopResizing() {
3760
+ this.isResizing = false;
3761
+ this.resizeDirection = null;
3762
+ this.element.classList.remove(`${this.options.classPrefix}-resizing`);
3763
+ document.body.style.userSelect = "";
3764
+ this.manuallyPositioned = true;
3765
+ if (this.options.onResizeEnd) {
3766
+ this.options.onResizeEnd();
3767
+ }
3768
+ }
3769
+ toggleKeyboardDragMode() {
3770
+ if (this.keyboardDragMode) {
3771
+ this.disableKeyboardDragMode();
3772
+ } else {
3773
+ this.enableKeyboardDragMode();
3774
+ }
3775
+ }
3776
+ enableKeyboardDragMode() {
3777
+ this.keyboardDragMode = true;
3778
+ this.keyboardResizeMode = false;
3779
+ this.element.classList.add(`${this.options.classPrefix}-keyboard-drag`);
3780
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
3781
+ this.focusElement();
3782
+ }
3783
+ disableKeyboardDragMode() {
3784
+ this.keyboardDragMode = false;
3785
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
3786
+ }
3787
+ toggleKeyboardResizeMode() {
3788
+ if (this.keyboardResizeMode) {
3789
+ this.disableKeyboardResizeMode();
3790
+ } else {
3791
+ this.enableKeyboardResizeMode();
3792
+ }
3793
+ }
3794
+ enableKeyboardResizeMode() {
3795
+ this.keyboardResizeMode = true;
3796
+ this.keyboardDragMode = false;
3797
+ this.element.classList.add(`${this.options.classPrefix}-keyboard-resize`);
3798
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
3799
+ this.focusElement();
3800
+ }
3801
+ disableKeyboardResizeMode() {
3802
+ this.keyboardResizeMode = false;
3803
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
3804
+ }
3805
+ enablePointerResizeMode({ focus = true } = {}) {
3806
+ if (!this.hasManagedResizeHandles()) {
3807
+ this.enableKeyboardResizeMode();
3808
+ return;
3809
+ }
3810
+ if (this.pointerResizeMode) {
3811
+ return;
3812
+ }
3813
+ this.pointerResizeMode = true;
3814
+ this.setManagedHandlesVisible(true);
3815
+ this.element.classList.add(`${this.options.classPrefix}-resizable`);
3816
+ this.enableKeyboardResizeMode();
3817
+ if (focus) {
3818
+ this.focusElement();
3819
+ }
3820
+ if (typeof this.options.onPointerResizeToggle === "function") {
3821
+ this.options.onPointerResizeToggle(true);
3822
+ }
3823
+ }
3824
+ disablePointerResizeMode({ focus = false } = {}) {
3825
+ if (!this.pointerResizeMode) {
3826
+ return;
3827
+ }
3828
+ this.pointerResizeMode = false;
3829
+ this.setManagedHandlesVisible(false);
3830
+ this.element.classList.remove(`${this.options.classPrefix}-resizable`);
3831
+ this.disableKeyboardResizeMode();
3832
+ if (focus) {
3833
+ this.focusElement();
3834
+ }
3835
+ if (typeof this.options.onPointerResizeToggle === "function") {
3836
+ this.options.onPointerResizeToggle(false);
3837
+ }
3838
+ }
3839
+ togglePointerResizeMode() {
3840
+ if (this.pointerResizeMode) {
3841
+ this.disablePointerResizeMode();
3842
+ } else {
3843
+ this.enablePointerResizeMode();
3844
+ }
3845
+ return this.pointerResizeMode;
3846
+ }
3847
+ focusElement() {
3848
+ if (typeof this.element.focus === "function") {
3849
+ try {
3850
+ this.element.focus({ preventScroll: true });
3851
+ } catch (e) {
3852
+ this.element.focus();
3853
+ }
3854
+ }
3855
+ }
3856
+ keyboardDrag(key, shiftKey) {
3857
+ const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
3858
+ let currentLeft = parseFloat(this.element.style.left) || 0;
3859
+ let currentTop = parseFloat(this.element.style.top) || 0;
3860
+ const computedStyle = window.getComputedStyle(this.element);
3861
+ if (computedStyle.transform !== "none") {
3862
+ const rect = this.element.getBoundingClientRect();
3863
+ currentLeft = rect.left;
3864
+ currentTop = rect.top;
3865
+ this.element.style.transform = "none";
3866
+ this.element.style.left = `${currentLeft}px`;
3867
+ this.element.style.top = `${currentTop}px`;
3868
+ }
3869
+ let newX = currentLeft;
3870
+ let newY = currentTop;
3871
+ switch (key) {
3872
+ case "ArrowLeft":
3873
+ newX -= step;
3874
+ break;
3875
+ case "ArrowRight":
3876
+ newX += step;
3877
+ break;
3878
+ case "ArrowUp":
3879
+ newY -= step;
3880
+ break;
3881
+ case "ArrowDown":
3882
+ newY += step;
3883
+ break;
3884
+ }
3885
+ this.element.style.left = `${newX}px`;
3886
+ this.element.style.top = `${newY}px`;
3887
+ if (this.options.onDrag) {
3888
+ this.options.onDrag({ x: newX, y: newY });
3889
+ }
3890
+ }
3891
+ keyboardResize(key, shiftKey) {
3892
+ const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
3893
+ const rect = this.element.getBoundingClientRect();
3894
+ let width = rect.width;
3895
+ let height = rect.height;
3896
+ switch (key) {
3897
+ case "ArrowLeft":
3898
+ width -= step;
3899
+ break;
3900
+ case "ArrowRight":
3901
+ width += step;
3902
+ break;
3903
+ case "ArrowUp":
3904
+ if (this.options.maintainAspectRatio) {
3905
+ width += step;
3906
+ } else {
3907
+ height -= step;
3908
+ }
3909
+ break;
3910
+ case "ArrowDown":
3911
+ if (this.options.maintainAspectRatio) {
3912
+ width -= step;
3913
+ } else {
3914
+ height += step;
3915
+ }
3916
+ break;
3917
+ }
3918
+ width = Math.max(this.options.minWidth, width);
3919
+ height = Math.max(this.options.minHeight, height);
3920
+ this.element.style.width = `${width}px`;
3921
+ if (!this.options.maintainAspectRatio) {
3922
+ this.element.style.height = `${height}px`;
3923
+ } else {
3924
+ this.element.style.height = "auto";
3925
+ }
3926
+ if (this.options.onResize) {
3927
+ this.options.onResize({ width, height });
3928
+ }
3929
+ }
3930
+ resetPosition() {
3931
+ this.element.style.left = "50%";
3932
+ this.element.style.top = "50%";
3933
+ this.element.style.transform = "translate(-50%, -50%)";
3934
+ this.element.style.right = "";
3935
+ this.element.style.bottom = "";
3936
+ this.manuallyPositioned = false;
3937
+ if (this.options.onDrag) {
3938
+ this.options.onDrag({ centered: true });
3939
+ }
3940
+ }
3941
+ destroy() {
3942
+ const dragHandle = this.options.dragHandle || this.element;
3943
+ this.disablePointerResizeMode();
3944
+ dragHandle.removeEventListener("mousedown", this.handlers.mousedown);
3945
+ dragHandle.removeEventListener("touchstart", this.handlers.touchstart);
3946
+ document.removeEventListener("mousemove", this.handlers.mousemove);
3947
+ document.removeEventListener("mouseup", this.handlers.mouseup);
3948
+ document.removeEventListener("touchmove", this.handlers.touchmove);
3949
+ document.removeEventListener("touchend", this.handlers.touchend);
3950
+ this.element.removeEventListener("keydown", this.handlers.keydown);
3951
+ if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
3952
+ this.options.resizeHandles.forEach((handle) => {
3953
+ handle.removeEventListener("mousedown", this.handlers.resizeHandleMousedown);
3954
+ handle.removeEventListener("touchstart", this.handlers.resizeHandleMousedown);
3955
+ });
3956
+ }
3957
+ this.element.classList.remove(
3958
+ `${this.options.classPrefix}-dragging`,
3959
+ `${this.options.classPrefix}-resizing`,
3960
+ `${this.options.classPrefix}-keyboard-drag`,
3961
+ `${this.options.classPrefix}-keyboard-resize`
3962
+ );
3963
+ }
3964
+ };
3965
+
3321
3966
  // src/controls/TranscriptManager.js
3322
3967
  var TranscriptManager = class {
3323
3968
  constructor(player) {
@@ -3328,21 +3973,17 @@ var VidPly = (() => {
3328
3973
  this.currentActiveEntry = null;
3329
3974
  this.isVisible = false;
3330
3975
  this.storage = new StorageManager("vidply");
3331
- this.isDragging = false;
3332
- this.dragOffsetX = 0;
3333
- this.dragOffsetY = 0;
3334
- this.isResizing = false;
3335
- this.resizeDirection = null;
3336
- this.resizeStartX = 0;
3337
- this.resizeStartY = 0;
3338
- this.resizeStartWidth = 0;
3339
- this.resizeStartHeight = 0;
3340
- this.resizeEnabled = false;
3976
+ this.draggableResizable = null;
3341
3977
  this.settingsMenuVisible = false;
3342
3978
  this.settingsMenu = null;
3343
3979
  this.settingsButton = null;
3344
3980
  this.settingsMenuJustOpened = false;
3345
- this.keyboardDragMode = false;
3981
+ this.resizeOptionButton = null;
3982
+ this.resizeOptionText = null;
3983
+ this.resizeModeIndicator = null;
3984
+ this.resizeModeIndicatorTimeout = null;
3985
+ this.transcriptResizeHandles = [];
3986
+ this.liveRegion = null;
3346
3987
  this.styleDialog = null;
3347
3988
  this.styleDialogVisible = false;
3348
3989
  this.styleDialogJustOpened = false;
@@ -3362,13 +4003,6 @@ var VidPly = (() => {
3362
4003
  this.handlers = {
3363
4004
  timeupdate: () => this.updateActiveEntry(),
3364
4005
  resize: null,
3365
- mousemove: null,
3366
- mouseup: null,
3367
- touchmove: null,
3368
- touchend: null,
3369
- mousedown: null,
3370
- touchstart: null,
3371
- keydown: null,
3372
4006
  settingsClick: null,
3373
4007
  settingsKeydown: null,
3374
4008
  documentClick: null,
@@ -3382,7 +4016,9 @@ var VidPly = (() => {
3382
4016
  this.player.on("timeupdate", this.handlers.timeupdate);
3383
4017
  this.player.on("fullscreenchange", () => {
3384
4018
  if (this.isVisible) {
3385
- this.setManagedTimeout(() => this.positionTranscript(), 100);
4019
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4020
+ this.setManagedTimeout(() => this.positionTranscript(), 100);
4021
+ }
3386
4022
  }
3387
4023
  });
3388
4024
  }
@@ -3403,9 +4039,12 @@ var VidPly = (() => {
3403
4039
  if (this.transcriptWindow) {
3404
4040
  this.transcriptWindow.style.display = "flex";
3405
4041
  this.isVisible = true;
4042
+ if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
4043
+ this.player.controlBar.updateTranscriptButton();
4044
+ }
3406
4045
  this.setManagedTimeout(() => {
3407
- if (this.settingsButton) {
3408
- this.settingsButton.focus();
4046
+ if (this.transcriptHeader) {
4047
+ this.transcriptHeader.focus();
3409
4048
  }
3410
4049
  }, 150);
3411
4050
  return;
@@ -3414,10 +4053,12 @@ var VidPly = (() => {
3414
4053
  this.loadTranscriptData();
3415
4054
  if (this.transcriptWindow) {
3416
4055
  this.transcriptWindow.style.display = "flex";
3417
- this.setManagedTimeout(() => this.positionTranscript(), 0);
4056
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4057
+ this.setManagedTimeout(() => this.positionTranscript(), 0);
4058
+ }
3418
4059
  this.setManagedTimeout(() => {
3419
- if (this.settingsButton) {
3420
- this.settingsButton.focus();
4060
+ if (this.transcriptHeader) {
4061
+ this.transcriptHeader.focus();
3421
4062
  }
3422
4063
  }, 150);
3423
4064
  }
@@ -3426,11 +4067,27 @@ var VidPly = (() => {
3426
4067
  /**
3427
4068
  * Hide transcript window
3428
4069
  */
3429
- hideTranscript() {
4070
+ hideTranscript({ focusButton = false } = {}) {
4071
+ var _a, _b;
3430
4072
  if (this.transcriptWindow) {
3431
4073
  this.transcriptWindow.style.display = "none";
3432
4074
  this.isVisible = false;
3433
4075
  }
4076
+ if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
4077
+ this.draggableResizable.disablePointerResizeMode();
4078
+ this.updateResizeOptionState();
4079
+ }
4080
+ this.hideResizeModeIndicator();
4081
+ this.announceLive("");
4082
+ if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
4083
+ this.player.controlBar.updateTranscriptButton();
4084
+ }
4085
+ if (focusButton) {
4086
+ const transcriptButton = (_b = (_a = this.player.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.transcript;
4087
+ if (transcriptButton && typeof transcriptButton.focus === "function") {
4088
+ transcriptButton.focus();
4089
+ }
4090
+ }
3434
4091
  }
3435
4092
  /**
3436
4093
  * Create the transcript window UI
@@ -3447,7 +4104,6 @@ var VidPly = (() => {
3447
4104
  this.transcriptHeader = DOMUtils.createElement("div", {
3448
4105
  className: `${this.player.options.classPrefix}-transcript-header`,
3449
4106
  attributes: {
3450
- "aria-label": "Drag to reposition transcript. Use arrow keys to move, Home to reset position, Escape to close.",
3451
4107
  "tabindex": "0"
3452
4108
  }
3453
4109
  });
@@ -3458,7 +4114,7 @@ var VidPly = (() => {
3458
4114
  className: `${this.player.options.classPrefix}-transcript-settings`,
3459
4115
  attributes: {
3460
4116
  "type": "button",
3461
- "aria-label": i18n.t("transcript.settings"),
4117
+ "aria-label": i18n.t("transcript.settingsMenu"),
3462
4118
  "aria-expanded": "false"
3463
4119
  }
3464
4120
  });
@@ -3490,7 +4146,7 @@ var VidPly = (() => {
3490
4146
  };
3491
4147
  this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
3492
4148
  const title = DOMUtils.createElement("h3", {
3493
- textContent: i18n.t("transcript.title")
4149
+ textContent: `${i18n.t("transcript.title")}. ${i18n.t("transcript.dragResizePrompt")}`
3494
4150
  });
3495
4151
  const autoscrollLabel = DOMUtils.createElement("label", {
3496
4152
  className: `${this.player.options.classPrefix}-transcript-autoscroll-label`,
@@ -3515,8 +4171,8 @@ var VidPly = (() => {
3515
4171
  this.autoscrollEnabled = e.target.checked;
3516
4172
  this.saveAutoscrollPreference();
3517
4173
  });
4174
+ this.transcriptHeader.appendChild(title);
3518
4175
  this.headerLeft.appendChild(this.settingsButton);
3519
- this.headerLeft.appendChild(title);
3520
4176
  this.headerLeft.appendChild(autoscrollLabel);
3521
4177
  this.languageSelector = DOMUtils.createElement("select", {
3522
4178
  className: `${this.player.options.classPrefix}-transcript-language-select`,
@@ -3535,7 +4191,7 @@ var VidPly = (() => {
3535
4191
  }
3536
4192
  });
3537
4193
  closeButton.appendChild(createIconElement("close"));
3538
- closeButton.addEventListener("click", () => this.hideTranscript());
4194
+ closeButton.addEventListener("click", () => this.hideTranscript({ focusButton: true }));
3539
4195
  this.transcriptHeader.appendChild(this.headerLeft);
3540
4196
  this.transcriptHeader.appendChild(closeButton);
3541
4197
  this.transcriptContent = DOMUtils.createElement("div", {
@@ -3543,9 +4199,20 @@ var VidPly = (() => {
3543
4199
  });
3544
4200
  this.transcriptWindow.appendChild(this.transcriptHeader);
3545
4201
  this.transcriptWindow.appendChild(this.transcriptContent);
4202
+ this.createResizeHandles();
4203
+ this.liveRegion = DOMUtils.createElement("div", {
4204
+ className: "vidply-sr-only",
4205
+ attributes: {
4206
+ "aria-live": "polite",
4207
+ "aria-atomic": "true"
4208
+ }
4209
+ });
4210
+ this.transcriptWindow.appendChild(this.liveRegion);
3546
4211
  this.player.container.appendChild(this.transcriptWindow);
3547
- this.positionTranscript();
3548
4212
  this.setupDragAndDrop();
4213
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4214
+ this.positionTranscript();
4215
+ }
3549
4216
  this.handlers.documentClick = (e) => {
3550
4217
  if (this.settingsMenuJustOpened) {
3551
4218
  return;
@@ -3572,15 +4239,39 @@ var VidPly = (() => {
3572
4239
  if (resizeTimeout) {
3573
4240
  this.clearManagedTimeout(resizeTimeout);
3574
4241
  }
3575
- resizeTimeout = this.setManagedTimeout(() => this.positionTranscript(), 100);
4242
+ resizeTimeout = this.setManagedTimeout(() => {
4243
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4244
+ this.positionTranscript();
4245
+ }
4246
+ }, 100);
3576
4247
  };
3577
4248
  window.addEventListener("resize", this.handlers.resize);
3578
4249
  }
4250
+ createResizeHandles() {
4251
+ if (!this.transcriptWindow) return;
4252
+ const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
4253
+ this.transcriptResizeHandles = directions.map((direction) => {
4254
+ const handle = DOMUtils.createElement("div", {
4255
+ className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
4256
+ attributes: {
4257
+ "data-direction": direction,
4258
+ "data-vidply-managed-resize": "true",
4259
+ "aria-hidden": "true"
4260
+ }
4261
+ });
4262
+ handle.style.display = "none";
4263
+ this.transcriptWindow.appendChild(handle);
4264
+ return handle;
4265
+ });
4266
+ }
3579
4267
  /**
3580
4268
  * Position transcript window next to video
3581
4269
  */
3582
4270
  positionTranscript() {
3583
4271
  if (!this.transcriptWindow || !this.player.videoWrapper || !this.isVisible) return;
4272
+ if (this.draggableResizable && this.draggableResizable.manuallyPositioned) {
4273
+ return;
4274
+ }
3584
4275
  const isMobile = window.innerWidth < 640;
3585
4276
  const videoRect = this.player.videoWrapper.getBoundingClientRect();
3586
4277
  const isFullscreen = this.player.state.fullscreen;
@@ -3613,8 +4304,12 @@ var VidPly = (() => {
3613
4304
  this.transcriptWindow.style.top = "auto";
3614
4305
  this.transcriptWindow.style.maxHeight = "calc(100vh - 180px)";
3615
4306
  this.transcriptWindow.style.height = "auto";
3616
- this.transcriptWindow.style.width = "400px";
3617
- this.transcriptWindow.style.maxWidth = "400px";
4307
+ const fullscreenMinWidth = 260;
4308
+ const fullscreenAvailable = Math.max(fullscreenMinWidth, window.innerWidth - 40);
4309
+ const fullscreenDesired = parseFloat(this.transcriptWindow.style.width) || 400;
4310
+ const fullscreenWidth = Math.max(fullscreenMinWidth, Math.min(fullscreenDesired, fullscreenAvailable));
4311
+ this.transcriptWindow.style.width = `${fullscreenWidth}px`;
4312
+ this.transcriptWindow.style.maxWidth = "none";
3618
4313
  this.transcriptWindow.style.borderRadius = "8px";
3619
4314
  this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
3620
4315
  this.transcriptWindow.style.borderTop = "";
@@ -3622,15 +4317,30 @@ var VidPly = (() => {
3622
4317
  this.player.container.appendChild(this.transcriptWindow);
3623
4318
  }
3624
4319
  } else {
4320
+ const transcriptWidth = parseFloat(this.transcriptWindow.style.width) || 400;
4321
+ const padding = 20;
4322
+ const minWidth = 260;
4323
+ const containerRect = this.player.container.getBoundingClientRect();
4324
+ const ensureContainerPositioned = () => {
4325
+ const computed = window.getComputedStyle(this.player.container);
4326
+ if (computed.position === "static") {
4327
+ this.player.container.style.position = "relative";
4328
+ }
4329
+ };
4330
+ ensureContainerPositioned();
4331
+ const left = videoRect.right - containerRect.left + padding;
4332
+ const availableWidth = window.innerWidth - videoRect.right - padding;
4333
+ const appliedWidth = Math.max(minWidth, Math.min(transcriptWidth, availableWidth));
4334
+ const appliedHeight = videoRect.height;
3625
4335
  this.transcriptWindow.style.position = "absolute";
3626
- this.transcriptWindow.style.left = `${videoRect.width + 8}px`;
4336
+ this.transcriptWindow.style.left = `${left}px`;
3627
4337
  this.transcriptWindow.style.right = "auto";
3628
4338
  this.transcriptWindow.style.bottom = "auto";
3629
4339
  this.transcriptWindow.style.top = "0";
3630
- this.transcriptWindow.style.height = `${videoRect.height}px`;
4340
+ this.transcriptWindow.style.height = `${appliedHeight}px`;
3631
4341
  this.transcriptWindow.style.maxHeight = "none";
3632
- this.transcriptWindow.style.width = "400px";
3633
- this.transcriptWindow.style.maxWidth = "400px";
4342
+ this.transcriptWindow.style.width = `${appliedWidth}px`;
4343
+ this.transcriptWindow.style.maxWidth = "none";
3634
4344
  this.transcriptWindow.style.borderRadius = "8px";
3635
4345
  this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
3636
4346
  this.transcriptWindow.style.borderTop = "";
@@ -4018,257 +4728,108 @@ var VidPly = (() => {
4018
4728
  */
4019
4729
  setupDragAndDrop() {
4020
4730
  if (!this.transcriptHeader || !this.transcriptWindow) return;
4021
- this.handlers.mousedown = (e) => {
4022
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
4023
- return;
4024
- }
4025
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
4026
- return;
4027
- }
4028
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-language-select`)) {
4029
- return;
4030
- }
4031
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
4032
- return;
4033
- }
4034
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
4035
- return;
4036
- }
4037
- this.startDragging(e.clientX, e.clientY);
4038
- e.preventDefault();
4039
- };
4040
- this.handlers.mousemove = (e) => {
4041
- if (this.isDragging) {
4042
- this.drag(e.clientX, e.clientY);
4043
- }
4044
- };
4045
- this.handlers.mouseup = () => {
4046
- if (this.isDragging) {
4047
- this.stopDragging();
4048
- }
4049
- };
4050
- this.handlers.touchstart = (e) => {
4051
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
4052
- return;
4053
- }
4054
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
4055
- return;
4056
- }
4057
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-language-select`)) {
4058
- return;
4059
- }
4060
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
4061
- return;
4062
- }
4063
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
4064
- return;
4065
- }
4066
- const isMobile = window.innerWidth < 640;
4067
- const isFullscreen = this.player.state.fullscreen;
4068
- const touch = e.touches[0];
4069
- if (isMobile && !isFullscreen) {
4070
- return;
4071
- } else {
4072
- this.startDragging(touch.clientX, touch.clientY);
4073
- }
4074
- };
4075
- this.handlers.touchmove = (e) => {
4076
- const isMobile = window.innerWidth < 640;
4077
- const isFullscreen = this.player.state.fullscreen;
4078
- if (isMobile && !isFullscreen) {
4079
- return;
4080
- } else if (this.isDragging) {
4081
- const touch = e.touches[0];
4082
- this.drag(touch.clientX, touch.clientY);
4083
- e.preventDefault();
4084
- }
4085
- };
4086
- this.handlers.touchend = () => {
4087
- if (this.isDragging) {
4088
- this.stopDragging();
4089
- }
4090
- };
4091
- this.handlers.keydown = (e) => {
4092
- if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
4093
- if (!this.keyboardDragMode) {
4094
- return;
4731
+ const isMobile = window.innerWidth < 640;
4732
+ const isFullscreen = this.player.state.fullscreen;
4733
+ if (isMobile && !isFullscreen) {
4734
+ return;
4735
+ }
4736
+ this.draggableResizable = new DraggableResizable(this.transcriptWindow, {
4737
+ dragHandle: this.transcriptHeader,
4738
+ resizeHandles: this.transcriptResizeHandles,
4739
+ constrainToViewport: true,
4740
+ classPrefix: `${this.player.options.classPrefix}-transcript`,
4741
+ keyboardDragKey: "d",
4742
+ keyboardResizeKey: "r",
4743
+ keyboardStep: 10,
4744
+ keyboardStepLarge: 50,
4745
+ minWidth: 300,
4746
+ minHeight: 200,
4747
+ maxWidth: () => Math.max(320, window.innerWidth - 40),
4748
+ maxHeight: () => Math.max(200, window.innerHeight - 120),
4749
+ pointerResizeIndicatorText: i18n.t("transcript.resizeModeHint"),
4750
+ onPointerResizeToggle: (enabled) => this.onPointerResizeModeChange(enabled),
4751
+ onDragStart: (e) => {
4752
+ const ignoreSelectors = [
4753
+ `.${this.player.options.classPrefix}-transcript-close`,
4754
+ `.${this.player.options.classPrefix}-transcript-settings`,
4755
+ `.${this.player.options.classPrefix}-transcript-language-select`,
4756
+ `.${this.player.options.classPrefix}-transcript-settings-menu`,
4757
+ `.${this.player.options.classPrefix}-transcript-style-dialog`
4758
+ ];
4759
+ for (const selector of ignoreSelectors) {
4760
+ if (e.target.closest(selector)) {
4761
+ return false;
4762
+ }
4095
4763
  }
4764
+ return true;
4765
+ }
4766
+ });
4767
+ this.customKeyHandler = (e) => {
4768
+ const key = e.key.toLowerCase();
4769
+ const alreadyPrevented = e.defaultPrevented;
4770
+ if (key === "home") {
4096
4771
  e.preventDefault();
4097
4772
  e.stopPropagation();
4098
- const step = e.shiftKey ? 50 : 10;
4099
- let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
4100
- let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
4101
- const computedStyle = window.getComputedStyle(this.transcriptWindow);
4102
- if (computedStyle.transform !== "none") {
4103
- const rect = this.transcriptWindow.getBoundingClientRect();
4104
- currentLeft = rect.left;
4105
- currentTop = rect.top;
4106
- this.transcriptWindow.style.transform = "none";
4107
- this.transcriptWindow.style.left = `${currentLeft}px`;
4108
- this.transcriptWindow.style.top = `${currentTop}px`;
4109
- }
4110
- let newX = currentLeft;
4111
- let newY = currentTop;
4112
- switch (e.key) {
4113
- case "ArrowLeft":
4114
- newX -= step;
4115
- break;
4116
- case "ArrowRight":
4117
- newX += step;
4118
- break;
4119
- case "ArrowUp":
4120
- newY -= step;
4121
- break;
4122
- case "ArrowDown":
4123
- newY += step;
4124
- break;
4773
+ if (this.draggableResizable) {
4774
+ if (this.draggableResizable.pointerResizeMode) {
4775
+ this.draggableResizable.disablePointerResizeMode();
4776
+ }
4777
+ this.draggableResizable.manuallyPositioned = false;
4778
+ this.positionTranscript();
4779
+ this.updateResizeOptionState();
4780
+ this.announceLive(i18n.t("transcript.positionReset"));
4125
4781
  }
4126
- this.transcriptWindow.style.left = `${newX}px`;
4127
- this.transcriptWindow.style.top = `${newY}px`;
4128
4782
  return;
4129
4783
  }
4130
- if (e.key === "Home") {
4784
+ if (key === "r") {
4785
+ if (alreadyPrevented) {
4786
+ return;
4787
+ }
4131
4788
  e.preventDefault();
4132
4789
  e.stopPropagation();
4133
- this.resetPosition();
4790
+ const enabled = this.toggleResizeMode();
4791
+ if (enabled) {
4792
+ this.transcriptWindow.focus();
4793
+ }
4134
4794
  return;
4135
4795
  }
4136
- if (e.key === "Escape") {
4796
+ if (key === "escape") {
4137
4797
  e.preventDefault();
4138
4798
  e.stopPropagation();
4799
+ if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
4800
+ this.draggableResizable.disablePointerResizeMode();
4801
+ return;
4802
+ }
4139
4803
  if (this.styleDialogVisible) {
4140
4804
  this.hideStyleDialog();
4141
- } else if (this.keyboardDragMode) {
4142
- this.disableKeyboardDragMode();
4805
+ } else if (this.draggableResizable && this.draggableResizable.keyboardDragMode) {
4806
+ this.draggableResizable.disableKeyboardDragMode();
4807
+ this.announceLive(i18n.t("transcript.dragModeDisabled"));
4143
4808
  } else if (this.settingsMenuVisible) {
4144
4809
  this.hideSettingsMenu();
4145
4810
  } else {
4146
- this.hideTranscript();
4811
+ this.hideTranscript({ focusButton: true });
4147
4812
  }
4148
4813
  return;
4149
4814
  }
4150
4815
  };
4151
- this.transcriptHeader.addEventListener("mousedown", this.handlers.mousedown);
4152
- document.addEventListener("mousemove", this.handlers.mousemove);
4153
- document.addEventListener("mouseup", this.handlers.mouseup);
4154
- this.transcriptHeader.addEventListener("touchstart", this.handlers.touchstart);
4155
- document.addEventListener("touchmove", this.handlers.touchmove);
4156
- document.addEventListener("touchend", this.handlers.touchend);
4157
- this.transcriptHeader.addEventListener("keydown", this.handlers.keydown);
4158
- }
4159
- /**
4160
- * Start dragging
4161
- */
4162
- startDragging(clientX, clientY) {
4163
- const rect = this.transcriptWindow.getBoundingClientRect();
4164
- const containerRect = this.player.container.getBoundingClientRect();
4165
- const relativeLeft = rect.left - containerRect.left;
4166
- const relativeTop = rect.top - containerRect.top;
4167
- const computedStyle = window.getComputedStyle(this.transcriptWindow);
4168
- if (computedStyle.transform !== "none") {
4169
- this.transcriptWindow.style.transform = "none";
4170
- this.transcriptWindow.style.left = `${relativeLeft}px`;
4171
- this.transcriptWindow.style.top = `${relativeTop}px`;
4172
- }
4173
- this.dragOffsetX = clientX - rect.left;
4174
- this.dragOffsetY = clientY - rect.top;
4175
- this.isDragging = true;
4176
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-dragging`);
4177
- document.body.style.cursor = "grabbing";
4178
- document.body.style.userSelect = "none";
4179
- }
4180
- /**
4181
- * Perform drag
4182
- */
4183
- drag(clientX, clientY) {
4184
- if (!this.isDragging) return;
4185
- const newViewportX = clientX - this.dragOffsetX;
4186
- const newViewportY = clientY - this.dragOffsetY;
4187
- const containerRect = this.player.container.getBoundingClientRect();
4188
- const newX = newViewportX - containerRect.left;
4189
- const newY = newViewportY - containerRect.top;
4190
- this.transcriptWindow.style.left = `${newX}px`;
4191
- this.transcriptWindow.style.top = `${newY}px`;
4192
- }
4193
- /**
4194
- * Stop dragging
4195
- */
4196
- stopDragging() {
4197
- this.isDragging = false;
4198
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-dragging`);
4199
- document.body.style.cursor = "";
4200
- document.body.style.userSelect = "";
4201
- }
4202
- /**
4203
- * Set window position with boundary constraints
4204
- */
4205
- setPosition(x, y) {
4206
- const rect = this.transcriptWindow.getBoundingClientRect();
4207
- const viewportWidth = document.documentElement.clientWidth;
4208
- const viewportHeight = document.documentElement.clientHeight;
4209
- const minVisible = 100;
4210
- const minX = -(rect.width - minVisible);
4211
- const minY = -(rect.height - minVisible);
4212
- const maxX = viewportWidth - minVisible;
4213
- const maxY = viewportHeight - minVisible;
4214
- x = Math.max(minX, Math.min(x, maxX));
4215
- y = Math.max(minY, Math.min(y, maxY));
4216
- this.transcriptWindow.style.left = `${x}px`;
4217
- this.transcriptWindow.style.top = `${y}px`;
4218
- this.transcriptWindow.style.transform = "none";
4219
- }
4220
- /**
4221
- * Reset position to center
4222
- */
4223
- resetPosition() {
4224
- this.transcriptWindow.style.left = "50%";
4225
- this.transcriptWindow.style.top = "50%";
4226
- this.transcriptWindow.style.transform = "translate(-50%, -50%)";
4816
+ this.transcriptWindow.addEventListener("keydown", this.customKeyHandler);
4227
4817
  }
4228
4818
  /**
4229
4819
  * Toggle keyboard drag mode
4230
4820
  */
4231
4821
  toggleKeyboardDragMode() {
4232
- if (this.keyboardDragMode) {
4233
- this.disableKeyboardDragMode();
4234
- } else {
4235
- this.enableKeyboardDragMode();
4236
- }
4237
- }
4238
- /**
4239
- * Enable keyboard drag mode
4240
- */
4241
- enableKeyboardDragMode() {
4242
- this.keyboardDragMode = true;
4243
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
4244
- if (this.settingsButton) {
4245
- this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
4246
- }
4247
- const indicator = DOMUtils.createElement("div", {
4248
- className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
4249
- textContent: i18n.t("transcript.keyboardDragActive")
4250
- });
4251
- this.transcriptHeader.appendChild(indicator);
4252
- if (this.settingsMenuVisible) {
4253
- this.hideSettingsMenu();
4254
- }
4255
- this.transcriptHeader.focus();
4256
- }
4257
- /**
4258
- * Disable keyboard drag mode
4259
- */
4260
- disableKeyboardDragMode() {
4261
- this.keyboardDragMode = false;
4262
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
4263
- if (this.settingsButton) {
4264
- this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
4265
- }
4266
- const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
4267
- if (indicator) {
4268
- indicator.remove();
4269
- }
4270
- if (this.settingsButton) {
4271
- this.settingsButton.focus();
4822
+ if (this.draggableResizable) {
4823
+ const wasEnabled = this.draggableResizable.keyboardDragMode;
4824
+ this.draggableResizable.toggleKeyboardDragMode();
4825
+ const isEnabled = this.draggableResizable.keyboardDragMode;
4826
+ if (!wasEnabled && isEnabled) {
4827
+ this.enableMoveMode();
4828
+ }
4829
+ if (this.settingsMenuVisible) {
4830
+ this.hideSettingsMenu();
4831
+ }
4832
+ this.transcriptWindow.focus();
4272
4833
  }
4273
4834
  }
4274
4835
  /**
@@ -4298,6 +4859,16 @@ var VidPly = (() => {
4298
4859
  if (this.settingsMenu) {
4299
4860
  this.settingsMenu.style.display = "block";
4300
4861
  this.settingsMenuVisible = true;
4862
+ if (this.settingsButton) {
4863
+ this.settingsButton.setAttribute("aria-expanded", "true");
4864
+ }
4865
+ this.updateResizeOptionState();
4866
+ setTimeout(() => {
4867
+ const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
4868
+ if (firstItem) {
4869
+ firstItem.focus();
4870
+ }
4871
+ }, 0);
4301
4872
  return;
4302
4873
  }
4303
4874
  this.settingsMenu = DOMUtils.createElement("div", {
@@ -4345,19 +4916,35 @@ var VidPly = (() => {
4345
4916
  className: `${this.player.options.classPrefix}-transcript-settings-item`,
4346
4917
  attributes: {
4347
4918
  "type": "button",
4348
- "aria-label": i18n.t("transcript.resizeWindow")
4919
+ "aria-label": i18n.t("transcript.resizeWindow"),
4920
+ "aria-pressed": "false"
4349
4921
  }
4350
4922
  });
4351
4923
  const resizeIcon = createIconElement("resize");
4352
4924
  const resizeText = DOMUtils.createElement("span", {
4925
+ className: `${this.player.options.classPrefix}-transcript-settings-text`,
4353
4926
  textContent: i18n.t("transcript.resizeWindow")
4354
4927
  });
4355
4928
  resizeOption.appendChild(resizeIcon);
4356
4929
  resizeOption.appendChild(resizeText);
4357
- resizeOption.addEventListener("click", () => {
4358
- this.toggleResizeMode();
4359
- this.hideSettingsMenu();
4930
+ resizeOption.addEventListener("click", (event) => {
4931
+ event.preventDefault();
4932
+ event.stopPropagation();
4933
+ const enabled = this.toggleResizeMode({ focus: false });
4934
+ if (enabled) {
4935
+ this.hideSettingsMenu({ focusButton: false });
4936
+ this.setManagedTimeout(() => {
4937
+ if (this.transcriptWindow) {
4938
+ this.transcriptWindow.focus();
4939
+ }
4940
+ }, 20);
4941
+ } else {
4942
+ this.hideSettingsMenu({ focusButton: true });
4943
+ }
4360
4944
  });
4945
+ this.resizeOptionButton = resizeOption;
4946
+ this.resizeOptionText = resizeText;
4947
+ this.updateResizeOptionState();
4361
4948
  const closeOption = DOMUtils.createElement("button", {
4362
4949
  className: `${this.player.options.classPrefix}-transcript-settings-item`,
4363
4950
  attributes: {
@@ -4388,6 +4975,7 @@ var VidPly = (() => {
4388
4975
  if (this.settingsButton) {
4389
4976
  this.settingsButton.setAttribute("aria-expanded", "true");
4390
4977
  }
4978
+ this.updateResizeOptionState();
4391
4979
  setTimeout(() => {
4392
4980
  const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
4393
4981
  if (firstItem) {
@@ -4398,14 +4986,16 @@ var VidPly = (() => {
4398
4986
  /**
4399
4987
  * Hide settings menu
4400
4988
  */
4401
- hideSettingsMenu() {
4989
+ hideSettingsMenu({ focusButton = true } = {}) {
4402
4990
  if (this.settingsMenu) {
4403
4991
  this.settingsMenu.style.display = "none";
4404
4992
  this.settingsMenuVisible = false;
4405
4993
  this.settingsMenuJustOpened = false;
4406
4994
  if (this.settingsButton) {
4407
4995
  this.settingsButton.setAttribute("aria-expanded", "false");
4408
- this.settingsButton.focus();
4996
+ if (focusButton) {
4997
+ this.settingsButton.focus();
4998
+ }
4409
4999
  }
4410
5000
  }
4411
5001
  }
@@ -4413,6 +5003,7 @@ var VidPly = (() => {
4413
5003
  * Enable move mode (gives visual feedback)
4414
5004
  */
4415
5005
  enableMoveMode() {
5006
+ this.hideResizeModeIndicator();
4416
5007
  this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
4417
5008
  const tooltip = DOMUtils.createElement("div", {
4418
5009
  className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
@@ -4429,155 +5020,64 @@ var VidPly = (() => {
4429
5020
  /**
4430
5021
  * Toggle resize mode
4431
5022
  */
4432
- toggleResizeMode() {
4433
- this.resizeEnabled = !this.resizeEnabled;
4434
- if (this.resizeEnabled) {
4435
- this.enableResizeHandles();
4436
- } else {
4437
- this.disableResizeHandles();
5023
+ toggleResizeMode({ focus = true } = {}) {
5024
+ if (!this.draggableResizable) {
5025
+ return false;
4438
5026
  }
4439
- }
4440
- /**
4441
- * Enable resize handles
4442
- */
4443
- enableResizeHandles() {
4444
- if (!this.transcriptWindow) return;
4445
- const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
4446
- directions.forEach((direction) => {
4447
- const handle = DOMUtils.createElement("div", {
4448
- className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
4449
- attributes: {
4450
- "data-direction": direction
4451
- }
4452
- });
4453
- handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
4454
- handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
4455
- this.transcriptWindow.appendChild(handle);
4456
- });
4457
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
4458
- this.handlers.resizeMove = (e) => {
4459
- if (this.isResizing) {
4460
- this.performResize(e.clientX, e.clientY);
4461
- }
4462
- };
4463
- this.handlers.resizeEnd = () => {
4464
- if (this.isResizing) {
4465
- this.stopResize();
4466
- }
4467
- };
4468
- this.handlers.resizeTouchMove = (e) => {
4469
- if (this.isResizing) {
4470
- this.performResize(e.touches[0].clientX, e.touches[0].clientY);
4471
- e.preventDefault();
4472
- }
4473
- };
4474
- document.addEventListener("mousemove", this.handlers.resizeMove);
4475
- document.addEventListener("mouseup", this.handlers.resizeEnd);
4476
- document.addEventListener("touchmove", this.handlers.resizeTouchMove);
4477
- document.addEventListener("touchend", this.handlers.resizeEnd);
4478
- }
4479
- /**
4480
- * Disable resize handles
4481
- */
4482
- disableResizeHandles() {
4483
- if (!this.transcriptWindow) return;
4484
- const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
4485
- handles.forEach((handle) => handle.remove());
4486
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
4487
- if (this.handlers.resizeMove) {
4488
- document.removeEventListener("mousemove", this.handlers.resizeMove);
5027
+ if (this.draggableResizable.pointerResizeMode) {
5028
+ this.draggableResizable.disablePointerResizeMode({ focus });
5029
+ return false;
4489
5030
  }
4490
- if (this.handlers.resizeEnd) {
4491
- document.removeEventListener("mouseup", this.handlers.resizeEnd);
5031
+ this.draggableResizable.enablePointerResizeMode({ focus });
5032
+ return true;
5033
+ }
5034
+ updateResizeOptionState() {
5035
+ if (!this.resizeOptionButton) {
5036
+ return;
4492
5037
  }
4493
- if (this.handlers.resizeTouchMove) {
4494
- document.removeEventListener("touchmove", this.handlers.resizeTouchMove);
5038
+ const isEnabled = !!(this.draggableResizable && this.draggableResizable.pointerResizeMode);
5039
+ const label = isEnabled ? i18n.t("transcript.disableResizeWindow") || "Disable Resize Mode" : i18n.t("transcript.resizeWindow");
5040
+ this.resizeOptionButton.setAttribute("aria-pressed", isEnabled ? "true" : "false");
5041
+ this.resizeOptionButton.setAttribute("aria-label", label);
5042
+ this.resizeOptionButton.setAttribute("title", label);
5043
+ if (this.resizeOptionText) {
5044
+ this.resizeOptionText.textContent = label;
4495
5045
  }
4496
- document.removeEventListener("touchend", this.handlers.resizeEnd);
4497
- }
4498
- /**
4499
- * Start resizing
4500
- */
4501
- startResize(e, direction) {
4502
- e.stopPropagation();
4503
- e.preventDefault();
4504
- this.isResizing = true;
4505
- this.resizeDirection = direction;
4506
- this.resizeStartX = e.clientX;
4507
- this.resizeStartY = e.clientY;
4508
- const rect = this.transcriptWindow.getBoundingClientRect();
4509
- this.resizeStartWidth = rect.width;
4510
- this.resizeStartHeight = rect.height;
4511
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
4512
- document.body.style.cursor = this.getResizeCursor(direction);
4513
- document.body.style.userSelect = "none";
4514
5046
  }
4515
- /**
4516
- * Perform resize
4517
- */
4518
- performResize(clientX, clientY) {
4519
- if (!this.isResizing) return;
4520
- const deltaX = clientX - this.resizeStartX;
4521
- const deltaY = clientY - this.resizeStartY;
4522
- let newWidth = this.resizeStartWidth;
4523
- let newHeight = this.resizeStartHeight;
4524
- const direction = this.resizeDirection;
4525
- if (direction.includes("e")) {
4526
- newWidth = this.resizeStartWidth + deltaX;
4527
- }
4528
- if (direction.includes("w")) {
4529
- newWidth = this.resizeStartWidth - deltaX;
4530
- }
4531
- if (direction.includes("s")) {
4532
- newHeight = this.resizeStartHeight + deltaY;
4533
- }
4534
- if (direction.includes("n")) {
4535
- newHeight = this.resizeStartHeight - deltaY;
4536
- }
4537
- const minWidth = 300;
4538
- const minHeight = 200;
4539
- const maxWidth = window.innerWidth - 40;
4540
- const maxHeight = window.innerHeight - 40;
4541
- newWidth = Math.max(minWidth, Math.min(newWidth, maxWidth));
4542
- newHeight = Math.max(minHeight, Math.min(newHeight, maxHeight));
4543
- this.transcriptWindow.style.width = `${newWidth}px`;
4544
- this.transcriptWindow.style.height = `${newHeight}px`;
4545
- this.transcriptWindow.style.maxWidth = `${newWidth}px`;
4546
- this.transcriptWindow.style.maxHeight = `${newHeight}px`;
4547
- if (direction.includes("w")) {
4548
- const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
4549
- this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
4550
- }
4551
- if (direction.includes("n")) {
4552
- const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
4553
- this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
5047
+ showResizeModeIndicator() {
5048
+ if (!this.transcriptHeader) {
5049
+ return;
5050
+ }
5051
+ this.hideResizeModeIndicator();
5052
+ const indicator = DOMUtils.createElement("div", {
5053
+ className: `${this.player.options.classPrefix}-transcript-resize-tooltip`,
5054
+ textContent: i18n.t("transcript.resizeModeHint") || "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit."
5055
+ });
5056
+ this.transcriptHeader.appendChild(indicator);
5057
+ this.resizeModeIndicator = indicator;
5058
+ this.resizeModeIndicatorTimeout = this.setManagedTimeout(() => {
5059
+ this.hideResizeModeIndicator();
5060
+ }, 3e3);
5061
+ }
5062
+ hideResizeModeIndicator() {
5063
+ if (this.resizeModeIndicatorTimeout) {
5064
+ this.clearManagedTimeout(this.resizeModeIndicatorTimeout);
5065
+ this.resizeModeIndicatorTimeout = null;
5066
+ }
5067
+ if (this.resizeModeIndicator && this.resizeModeIndicator.parentNode) {
5068
+ this.resizeModeIndicator.remove();
5069
+ }
5070
+ this.resizeModeIndicator = null;
5071
+ }
5072
+ onPointerResizeModeChange(enabled) {
5073
+ this.updateResizeOptionState();
5074
+ if (enabled) {
5075
+ this.showResizeModeIndicator();
5076
+ this.announceLive(i18n.t("transcript.resizeModeEnabled"));
5077
+ } else {
5078
+ this.hideResizeModeIndicator();
5079
+ this.announceLive(i18n.t("transcript.resizeModeDisabled"));
4554
5080
  }
4555
- }
4556
- /**
4557
- * Stop resizing
4558
- */
4559
- stopResize() {
4560
- this.isResizing = false;
4561
- this.resizeDirection = null;
4562
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
4563
- document.body.style.cursor = "";
4564
- document.body.style.userSelect = "";
4565
- }
4566
- /**
4567
- * Get cursor style for resize direction
4568
- */
4569
- getResizeCursor(direction) {
4570
- const cursors = {
4571
- "n": "ns-resize",
4572
- "s": "ns-resize",
4573
- "e": "ew-resize",
4574
- "w": "ew-resize",
4575
- "ne": "nesw-resize",
4576
- "nw": "nwse-resize",
4577
- "se": "nwse-resize",
4578
- "sw": "nesw-resize"
4579
- };
4580
- return cursors[direction] || "default";
4581
5081
  }
4582
5082
  /**
4583
5083
  * Show style dialog
@@ -4839,26 +5339,22 @@ var VidPly = (() => {
4839
5339
  * Cleanup
4840
5340
  */
4841
5341
  destroy() {
4842
- if (this.resizeEnabled) {
4843
- this.disableResizeHandles();
5342
+ this.hideResizeModeIndicator();
5343
+ if (this.draggableResizable) {
5344
+ if (this.draggableResizable.pointerResizeMode) {
5345
+ this.draggableResizable.disablePointerResizeMode();
5346
+ this.updateResizeOptionState();
5347
+ }
5348
+ this.draggableResizable.destroy();
5349
+ this.draggableResizable = null;
4844
5350
  }
4845
- if (this.keyboardDragMode) {
4846
- this.disableKeyboardDragMode();
5351
+ if (this.transcriptWindow && this.customKeyHandler) {
5352
+ this.transcriptWindow.removeEventListener("keydown", this.customKeyHandler);
5353
+ this.customKeyHandler = null;
4847
5354
  }
4848
5355
  if (this.handlers.timeupdate) {
4849
5356
  this.player.off("timeupdate", this.handlers.timeupdate);
4850
5357
  }
4851
- if (this.transcriptHeader) {
4852
- if (this.handlers.mousedown) {
4853
- this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
4854
- }
4855
- if (this.handlers.touchstart) {
4856
- this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
4857
- }
4858
- if (this.handlers.keydown) {
4859
- this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
4860
- }
4861
- }
4862
5358
  if (this.settingsButton) {
4863
5359
  if (this.handlers.settingsClick) {
4864
5360
  this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
@@ -4870,18 +5366,6 @@ var VidPly = (() => {
4870
5366
  if (this.styleDialog && this.handlers.styleDialogKeydown) {
4871
5367
  this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
4872
5368
  }
4873
- if (this.handlers.mousemove) {
4874
- document.removeEventListener("mousemove", this.handlers.mousemove);
4875
- }
4876
- if (this.handlers.mouseup) {
4877
- document.removeEventListener("mouseup", this.handlers.mouseup);
4878
- }
4879
- if (this.handlers.touchmove) {
4880
- document.removeEventListener("touchmove", this.handlers.touchmove);
4881
- }
4882
- if (this.handlers.touchend) {
4883
- document.removeEventListener("touchend", this.handlers.touchend);
4884
- }
4885
5369
  if (this.handlers.documentClick) {
4886
5370
  document.removeEventListener("click", this.handlers.documentClick);
4887
5371
  }
@@ -4900,6 +5384,14 @@ var VidPly = (() => {
4900
5384
  this.transcriptEntries = [];
4901
5385
  this.settingsMenu = null;
4902
5386
  this.styleDialog = null;
5387
+ this.transcriptResizeHandles = [];
5388
+ this.resizeOptionButton = null;
5389
+ this.resizeOptionText = null;
5390
+ this.liveRegion = null;
5391
+ }
5392
+ announceLive(message) {
5393
+ if (!this.liveRegion) return;
5394
+ this.liveRegion.textContent = message || "";
4903
5395
  }
4904
5396
  };
4905
5397
 
@@ -5725,6 +6217,7 @@ var VidPly = (() => {
5725
6217
  this.audioDescriptionSourceElement = null;
5726
6218
  this.originalAudioDescriptionSource = null;
5727
6219
  this.audioDescriptionCaptionTracks = [];
6220
+ this._audioDescriptionDesiredState = false;
5728
6221
  this._textTracksCache = null;
5729
6222
  this._textTracksDirty = true;
5730
6223
  this._sourceElementsCache = null;
@@ -5842,7 +6335,6 @@ var VidPly = (() => {
5842
6335
  this.element.style.height = "100%";
5843
6336
  if (this.element.tagName === "VIDEO" && this.options.playsInline) {
5844
6337
  this.element.setAttribute("playsinline", "");
5845
- this.element.setAttribute("webkit-playsinline", "");
5846
6338
  this.element.playsInline = true;
5847
6339
  }
5848
6340
  if (this.options.width) {
@@ -5865,6 +6357,14 @@ var VidPly = (() => {
5865
6357
  this.toggle();
5866
6358
  }
5867
6359
  });
6360
+ this.on("play", () => {
6361
+ this.hidePosterOverlay();
6362
+ });
6363
+ this.on("timeupdate", () => {
6364
+ if (this.state.currentTime > 0) {
6365
+ this.hidePosterOverlay();
6366
+ }
6367
+ });
5868
6368
  }
5869
6369
  createPlayButtonOverlay() {
5870
6370
  this.playButtonOverlay = createPlayOverlay();
@@ -6031,6 +6531,24 @@ var VidPly = (() => {
6031
6531
  findTrackElement(track) {
6032
6532
  return this.trackElements.find((el) => el.track === track);
6033
6533
  }
6534
+ showPosterOverlay() {
6535
+ if (!this.videoWrapper || this.element.tagName !== "VIDEO") {
6536
+ return;
6537
+ }
6538
+ const poster = this.element.getAttribute("poster") || this.element.poster || this.options.poster;
6539
+ if (!poster) {
6540
+ return;
6541
+ }
6542
+ this.videoWrapper.style.setProperty("--vidply-poster-image", `url("${poster}")`);
6543
+ this.videoWrapper.classList.add("vidply-forced-poster");
6544
+ }
6545
+ hidePosterOverlay() {
6546
+ if (!this.videoWrapper) {
6547
+ return;
6548
+ }
6549
+ this.videoWrapper.classList.remove("vidply-forced-poster");
6550
+ this.videoWrapper.style.removeProperty("--vidply-poster-image");
6551
+ }
6034
6552
  /**
6035
6553
  * Set a managed timeout that will be cleaned up on destroy
6036
6554
  * @param {Function} callback - Callback function
@@ -6347,6 +6865,10 @@ var VidPly = (() => {
6347
6865
  }
6348
6866
  const currentTime = this.state.currentTime;
6349
6867
  const wasPlaying = this.state.playing;
6868
+ const shouldKeepPoster = !wasPlaying && currentTime === 0;
6869
+ if (shouldKeepPoster) {
6870
+ this.showPosterOverlay();
6871
+ }
6350
6872
  let swappedTracksForTranscript = [];
6351
6873
  if (this.audioDescriptionSourceElement) {
6352
6874
  const currentSrc = this.element.currentSrc || this.element.src;
@@ -6529,8 +7051,15 @@ var VidPly = (() => {
6529
7051
  if (sourceInfo.descSrc) {
6530
7052
  newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
6531
7053
  }
6532
- this.element.appendChild(newSource);
7054
+ const firstTrack = this.element.querySelector("track");
7055
+ if (firstTrack) {
7056
+ this.element.insertBefore(newSource, firstTrack);
7057
+ } else {
7058
+ this.element.appendChild(newSource);
7059
+ }
6533
7060
  });
7061
+ this._sourceElementsDirty = true;
7062
+ this._sourceElementsCache = null;
6534
7063
  this.element.load();
6535
7064
  await new Promise((resolve) => {
6536
7065
  const onLoadedMetadata = () => {
@@ -6540,18 +7069,18 @@ var VidPly = (() => {
6540
7069
  this.element.addEventListener("loadedmetadata", onLoadedMetadata);
6541
7070
  });
6542
7071
  await new Promise((resolve) => setTimeout(resolve, 300));
6543
- if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
6544
- if (this.element.readyState >= 1) {
6545
- this.element.currentTime = 1e-3;
6546
- setTimeout(() => {
6547
- this.element.currentTime = 0;
6548
- }, 10);
6549
- }
7072
+ if (currentTime > 0) {
7073
+ this.seek(currentTime);
6550
7074
  }
6551
- this.seek(currentTime);
6552
7075
  if (wasPlaying) {
6553
7076
  this.play();
6554
7077
  }
7078
+ if (!shouldKeepPoster) {
7079
+ this.hidePosterOverlay();
7080
+ }
7081
+ if (!this._audioDescriptionDesiredState) {
7082
+ return;
7083
+ }
6555
7084
  this.state.audioDescriptionEnabled = true;
6556
7085
  this.emit("audiodescriptionenabled");
6557
7086
  } else {
@@ -6731,7 +7260,9 @@ var VidPly = (() => {
6731
7260
  }, 10);
6732
7261
  }
6733
7262
  }
6734
- this.seek(currentTime);
7263
+ if (currentTime > 0) {
7264
+ this.seek(currentTime);
7265
+ }
6735
7266
  if (wasPlaying) {
6736
7267
  this.play();
6737
7268
  }
@@ -6894,6 +7425,12 @@ var VidPly = (() => {
6894
7425
  }, 800);
6895
7426
  }
6896
7427
  }
7428
+ if (!shouldKeepPoster) {
7429
+ this.hidePosterOverlay();
7430
+ }
7431
+ if (!this._audioDescriptionDesiredState) {
7432
+ return;
7433
+ }
6897
7434
  this.state.audioDescriptionEnabled = true;
6898
7435
  this.emit("audiodescriptionenabled");
6899
7436
  }
@@ -6953,24 +7490,40 @@ var VidPly = (() => {
6953
7490
  if (sourceInfo.descSrc) {
6954
7491
  newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
6955
7492
  }
6956
- this.element.appendChild(newSource);
7493
+ const firstTrack = this.element.querySelector("track");
7494
+ if (firstTrack) {
7495
+ this.element.insertBefore(newSource, firstTrack);
7496
+ } else {
7497
+ this.element.appendChild(newSource);
7498
+ }
6957
7499
  });
7500
+ this._sourceElementsDirty = true;
7501
+ this._sourceElementsCache = null;
6958
7502
  this.element.load();
6959
7503
  } else {
6960
7504
  const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;
6961
7505
  this.element.src = originalSrcToUse;
6962
7506
  this.element.load();
6963
7507
  }
6964
- await new Promise((resolve) => {
6965
- const onLoadedMetadata = () => {
6966
- this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
6967
- resolve();
6968
- };
6969
- this.element.addEventListener("loadedmetadata", onLoadedMetadata);
6970
- });
6971
- this.seek(currentTime);
6972
- if (wasPlaying) {
6973
- this.play();
7508
+ if (currentTime > 0 || wasPlaying) {
7509
+ await new Promise((resolve) => {
7510
+ const onLoadedMetadata = () => {
7511
+ this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
7512
+ resolve();
7513
+ };
7514
+ this.element.addEventListener("loadedmetadata", onLoadedMetadata);
7515
+ });
7516
+ if (currentTime > 0) {
7517
+ this.seek(currentTime);
7518
+ }
7519
+ if (wasPlaying) {
7520
+ this.play();
7521
+ }
7522
+ }
7523
+ if (!wasPlaying && currentTime === 0) {
7524
+ this.showPosterOverlay();
7525
+ } else {
7526
+ this.hidePosterOverlay();
6974
7527
  }
6975
7528
  if (this.transcriptManager && this.transcriptManager.isVisible) {
6976
7529
  this.setManagedTimeout(() => {
@@ -6979,6 +7532,9 @@ var VidPly = (() => {
6979
7532
  }
6980
7533
  }, 500);
6981
7534
  }
7535
+ if (this._audioDescriptionDesiredState) {
7536
+ return;
7537
+ }
6982
7538
  this.state.audioDescriptionEnabled = false;
6983
7539
  this.emit("audiodescriptiondisabled");
6984
7540
  }
@@ -6987,9 +7543,11 @@ var VidPly = (() => {
6987
7543
  const hasAudioDescriptionSrc = this.audioDescriptionSrc || this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
6988
7544
  if (descriptionTrack && hasAudioDescriptionSrc) {
6989
7545
  if (this.state.audioDescriptionEnabled) {
7546
+ this._audioDescriptionDesiredState = false;
6990
7547
  descriptionTrack.mode = "hidden";
6991
7548
  await this.disableAudioDescription();
6992
7549
  } else {
7550
+ this._audioDescriptionDesiredState = true;
6993
7551
  await this.enableAudioDescription();
6994
7552
  const enableDescriptionTrack = () => {
6995
7553
  this.invalidateTrackCache();
@@ -7017,18 +7575,22 @@ var VidPly = (() => {
7017
7575
  }
7018
7576
  } else if (descriptionTrack) {
7019
7577
  if (descriptionTrack.mode === "showing") {
7578
+ this._audioDescriptionDesiredState = false;
7020
7579
  descriptionTrack.mode = "hidden";
7021
7580
  this.state.audioDescriptionEnabled = false;
7022
7581
  this.emit("audiodescriptiondisabled");
7023
7582
  } else {
7583
+ this._audioDescriptionDesiredState = true;
7024
7584
  descriptionTrack.mode = "showing";
7025
7585
  this.state.audioDescriptionEnabled = true;
7026
7586
  this.emit("audiodescriptionenabled");
7027
7587
  }
7028
7588
  } else if (hasAudioDescriptionSrc) {
7029
7589
  if (this.state.audioDescriptionEnabled) {
7590
+ this._audioDescriptionDesiredState = false;
7030
7591
  await this.disableAudioDescription();
7031
7592
  } else {
7593
+ this._audioDescriptionDesiredState = true;
7032
7594
  await this.enableAudioDescription();
7033
7595
  }
7034
7596
  }
@@ -7125,177 +7687,22 @@ var VidPly = (() => {
7125
7687
  }
7126
7688
  setupSignLanguageInteraction() {
7127
7689
  if (!this.signLanguageWrapper) return;
7128
- let isDragging = false;
7129
- let isResizing = false;
7130
- let resizeDirection = null;
7131
- let startX = 0;
7132
- let startY = 0;
7133
- let startLeft = 0;
7134
- let startTop = 0;
7135
- let startWidth = 0;
7136
- let startHeight = 0;
7137
- let dragMode = false;
7138
- let resizeMode = false;
7139
- const onMouseDownVideo = (e) => {
7140
- if (e.target !== this.signLanguageVideo) return;
7141
- e.preventDefault();
7142
- isDragging = true;
7143
- startX = e.clientX;
7144
- startY = e.clientY;
7145
- const rect = this.signLanguageWrapper.getBoundingClientRect();
7146
- startLeft = rect.left;
7147
- startTop = rect.top;
7148
- this.signLanguageWrapper.classList.add("vidply-sign-dragging");
7149
- };
7150
- const onMouseDownHandle = (e) => {
7151
- if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
7152
- e.preventDefault();
7153
- e.stopPropagation();
7154
- isResizing = true;
7155
- resizeDirection = e.target.getAttribute("data-direction");
7156
- startX = e.clientX;
7157
- startY = e.clientY;
7158
- const rect = this.signLanguageWrapper.getBoundingClientRect();
7159
- startLeft = rect.left;
7160
- startTop = rect.top;
7161
- startWidth = rect.width;
7162
- startHeight = rect.height;
7163
- this.signLanguageWrapper.classList.add("vidply-sign-resizing");
7164
- };
7165
- const onMouseMove = (e) => {
7166
- if (isDragging) {
7167
- const deltaX = e.clientX - startX;
7168
- const deltaY = e.clientY - startY;
7169
- const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
7170
- const containerRect = this.container.getBoundingClientRect();
7171
- const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
7172
- const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
7173
- const videoWrapperTop = videoWrapperRect.top - containerRect.top;
7174
- let newLeft = startLeft + deltaX - containerRect.left;
7175
- let newTop = startTop + deltaY - containerRect.top;
7176
- const controlsHeight = 95;
7177
- newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
7178
- newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
7179
- this.signLanguageWrapper.style.left = `${newLeft}px`;
7180
- this.signLanguageWrapper.style.top = `${newTop}px`;
7181
- this.signLanguageWrapper.style.right = "auto";
7182
- this.signLanguageWrapper.style.bottom = "auto";
7183
- this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
7184
- } else if (isResizing) {
7185
- const deltaX = e.clientX - startX;
7186
- const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
7187
- const containerRect = this.container.getBoundingClientRect();
7188
- let newWidth = startWidth;
7189
- let newLeft = startLeft - containerRect.left;
7190
- if (resizeDirection.includes("e")) {
7191
- newWidth = Math.max(150, startWidth + deltaX);
7192
- const maxWidth = videoWrapperRect.right - startLeft;
7193
- newWidth = Math.min(newWidth, maxWidth);
7194
- }
7195
- if (resizeDirection.includes("w")) {
7196
- const proposedWidth = Math.max(150, startWidth - deltaX);
7197
- const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
7198
- const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
7199
- if (proposedLeft >= videoWrapperLeft) {
7200
- newWidth = proposedWidth;
7201
- newLeft = proposedLeft;
7202
- }
7203
- }
7204
- this.signLanguageWrapper.style.width = `${newWidth}px`;
7205
- this.signLanguageWrapper.style.height = "auto";
7206
- if (resizeDirection.includes("w")) {
7207
- this.signLanguageWrapper.style.left = `${newLeft}px`;
7208
- }
7209
- this.signLanguageWrapper.style.right = "auto";
7210
- this.signLanguageWrapper.style.bottom = "auto";
7211
- this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
7212
- }
7213
- };
7214
- const onMouseUp = () => {
7215
- if (isDragging || isResizing) {
7216
- this.saveSignLanguagePreferences();
7217
- }
7218
- isDragging = false;
7219
- isResizing = false;
7220
- resizeDirection = null;
7221
- this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
7222
- };
7223
- const onKeyDown = (e) => {
7224
- if (e.key === "d" || e.key === "D") {
7225
- dragMode = !dragMode;
7226
- resizeMode = false;
7227
- this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
7228
- this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
7229
- e.preventDefault();
7230
- return;
7231
- }
7232
- if (e.key === "r" || e.key === "R") {
7233
- resizeMode = !resizeMode;
7234
- dragMode = false;
7235
- this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
7236
- this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
7237
- e.preventDefault();
7238
- return;
7239
- }
7240
- if (e.key === "Escape") {
7241
- dragMode = false;
7242
- resizeMode = false;
7243
- this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
7244
- e.preventDefault();
7245
- return;
7246
- }
7247
- if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
7248
- const step = e.shiftKey ? 10 : 5;
7249
- const rect = this.signLanguageWrapper.getBoundingClientRect();
7250
- const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
7251
- const containerRect = this.container.getBoundingClientRect();
7252
- const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
7253
- const videoWrapperTop = videoWrapperRect.top - containerRect.top;
7254
- if (dragMode) {
7255
- let left = rect.left - containerRect.left;
7256
- let top = rect.top - containerRect.top;
7257
- if (e.key === "ArrowLeft") left -= step;
7258
- if (e.key === "ArrowRight") left += step;
7259
- if (e.key === "ArrowUp") top -= step;
7260
- if (e.key === "ArrowDown") top += step;
7261
- const controlsHeight = 95;
7262
- left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
7263
- top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
7264
- this.signLanguageWrapper.style.left = `${left}px`;
7265
- this.signLanguageWrapper.style.top = `${top}px`;
7266
- this.signLanguageWrapper.style.right = "auto";
7267
- this.signLanguageWrapper.style.bottom = "auto";
7268
- this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
7269
- this.saveSignLanguagePreferences();
7270
- e.preventDefault();
7271
- } else if (resizeMode) {
7272
- let width = rect.width;
7273
- if (e.key === "ArrowLeft") width -= step;
7274
- if (e.key === "ArrowRight") width += step;
7275
- if (e.key === "ArrowUp") width += step;
7276
- if (e.key === "ArrowDown") width -= step;
7277
- width = Math.max(150, width);
7278
- width = Math.min(width, videoWrapperRect.width);
7279
- this.signLanguageWrapper.style.width = `${width}px`;
7280
- this.signLanguageWrapper.style.height = "auto";
7281
- this.saveSignLanguagePreferences();
7282
- e.preventDefault();
7283
- }
7284
- }
7285
- };
7286
- this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
7287
- const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
7288
- handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
7289
- document.addEventListener("mousemove", onMouseMove);
7290
- document.addEventListener("mouseup", onMouseUp);
7291
- this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
7690
+ const resizeHandles = Array.from(this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle"));
7691
+ this.signLanguageDraggable = new DraggableResizable(this.signLanguageWrapper, {
7692
+ dragHandle: this.signLanguageVideo,
7693
+ resizeHandles,
7694
+ constrainToViewport: true,
7695
+ maintainAspectRatio: true,
7696
+ minWidth: 150,
7697
+ minHeight: 100,
7698
+ classPrefix: "vidply-sign",
7699
+ keyboardDragKey: "d",
7700
+ keyboardResizeKey: "r",
7701
+ keyboardStep: 5,
7702
+ keyboardStepLarge: 10
7703
+ });
7292
7704
  this.signLanguageInteractionHandlers = {
7293
- mouseDownVideo: onMouseDownVideo,
7294
- mouseDownHandle: onMouseDownHandle,
7295
- mouseMove: onMouseMove,
7296
- mouseUp: onMouseUp,
7297
- keyDown: onKeyDown,
7298
- handles
7705
+ draggable: this.signLanguageDraggable
7299
7706
  };
7300
7707
  }
7301
7708
  constrainSignLanguagePosition() {
@@ -7362,22 +7769,11 @@ var VidPly = (() => {
7362
7769
  this.off("ratechange", this.signLanguageHandlers.ratechange);
7363
7770
  this.signLanguageHandlers = null;
7364
7771
  }
7365
- if (this.signLanguageInteractionHandlers) {
7366
- if (this.signLanguageVideo) {
7367
- this.signLanguageVideo.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownVideo);
7368
- }
7369
- if (this.signLanguageInteractionHandlers.handles) {
7370
- this.signLanguageInteractionHandlers.handles.forEach((handle) => {
7371
- handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
7372
- });
7373
- }
7374
- document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
7375
- document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
7376
- if (this.signLanguageWrapper) {
7377
- this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
7378
- }
7379
- this.signLanguageInteractionHandlers = null;
7772
+ if (this.signLanguageDraggable) {
7773
+ this.signLanguageDraggable.destroy();
7774
+ this.signLanguageDraggable = null;
7380
7775
  }
7776
+ this.signLanguageInteractionHandlers = null;
7381
7777
  if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
7382
7778
  if (this.signLanguageVideo) {
7383
7779
  this.signLanguageVideo.pause();
@@ -7469,7 +7865,9 @@ var VidPly = (() => {
7469
7865
  this.controlBar.updateControlsForViewport(width);
7470
7866
  }
7471
7867
  if (this.transcriptManager && this.transcriptManager.isVisible) {
7472
- this.transcriptManager.positionTranscript();
7868
+ if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
7869
+ this.transcriptManager.positionTranscript();
7870
+ }
7473
7871
  }
7474
7872
  };
7475
7873
  window.addEventListener("resize", this.resizeHandler);
@@ -7478,7 +7876,9 @@ var VidPly = (() => {
7478
7876
  this.orientationHandler = (e) => {
7479
7877
  setTimeout(() => {
7480
7878
  if (this.transcriptManager && this.transcriptManager.isVisible) {
7481
- this.transcriptManager.positionTranscript();
7879
+ if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
7880
+ this.transcriptManager.positionTranscript();
7881
+ }
7482
7882
  }
7483
7883
  }, 100);
7484
7884
  };