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.
@@ -497,11 +497,20 @@ var translations = {
497
497
  settings: "Transcript settings. Press Enter to open menu, or D to enable drag mode",
498
498
  keyboardDragMode: "Toggle keyboard drag mode with arrow keys. Shortcut: D key",
499
499
  keyboardDragActive: "\u2328\uFE0F Keyboard Drag Mode Active (Arrow keys to move, Shift+Arrows for large steps, D or ESC to exit)",
500
+ dragResizePrompt: "Press D to drag or R to resize. Use Home to reset position, Esc to close.",
501
+ dragModeEnabled: "Keyboard drag mode enabled. Use arrow keys to move, Shift+Arrow for larger steps. Press D or Esc to exit.",
502
+ dragModeDisabled: "Keyboard drag mode disabled.",
500
503
  resizeWindow: "Resize Window",
504
+ disableResizeWindow: "Disable Resize Mode",
505
+ resizeModeHint: "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
506
+ resizeModeEnabled: "Resize mode enabled. Drag edges or corners to adjust. Press Esc or R to exit.",
507
+ resizeModeDisabled: "Resize mode disabled.",
508
+ positionReset: "Transcript position reset.",
501
509
  styleTranscript: "Open transcript style settings",
502
510
  closeMenu: "Close Menu",
503
511
  styleTitle: "Transcript Style",
504
- autoscroll: "Autoscroll"
512
+ autoscroll: "Autoscroll",
513
+ settingsMenu: "Settings menu"
505
514
  },
506
515
  settings: {
507
516
  title: "Settings",
@@ -619,11 +628,20 @@ var translations = {
619
628
  settings: "Transkript-Einstellungen. Eingabetaste zum \xD6ffnen des Men\xFCs dr\xFCcken oder D zum Aktivieren des Verschiebemodus",
620
629
  keyboardDragMode: "Tastatur-Verschiebemodus mit Pfeiltasten umschalten. Tastenkombination: D-Taste",
621
630
  keyboardDragActive: "\u2328\uFE0F Tastatur-Verschiebemodus aktiv (Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gro\xDFe Schritte, D oder ESC zum Beenden)",
631
+ dragResizePrompt: "Dr\xFCcken Sie D zum Verschieben oder R zur Gr\xF6\xDFen\xE4nderung. Home setzt die Position zur\xFCck, Esc schlie\xDFt.",
632
+ dragModeEnabled: "Tastatur-Verschiebemodus aktiviert. Pfeiltasten zum Bewegen, Umschalt+Pfeiltasten f\xFCr gr\xF6\xDFere Schritte. D oder Esc zum Beenden.",
633
+ dragModeDisabled: "Tastatur-Verschiebemodus deaktiviert.",
622
634
  resizeWindow: "Fenster vergr\xF6\xDFern/verkleinern",
635
+ disableResizeWindow: "Resize-Modus deaktivieren",
636
+ resizeModeHint: "Griffe aktiviert. Ziehen Sie Kanten oder Ecken zum Anpassen. Esc oder R zum Beenden.",
637
+ resizeModeEnabled: "Resize-Modus aktiviert. Kanten oder Ecken ziehen; Esc oder R beendet.",
638
+ resizeModeDisabled: "Resize-Modus deaktiviert.",
639
+ positionReset: "Transkriptposition zur\xFCckgesetzt.",
623
640
  styleTranscript: "Transkript-Stileinstellungen \xF6ffnen",
624
641
  closeMenu: "Men\xFC schlie\xDFen",
625
642
  styleTitle: "Transkript-Stil",
626
- autoscroll: "Automatisches Scrollen"
643
+ autoscroll: "Automatisches Scrollen",
644
+ settingsMenu: "Einstellungsmen\xFC"
627
645
  },
628
646
  settings: {
629
647
  title: "Einstellungen",
@@ -741,11 +759,20 @@ var translations = {
741
759
  settings: "Configuraci\xF3n de transcripci\xF3n. Presione Enter para abrir el men\xFA o D para activar el modo de arrastre",
742
760
  keyboardDragMode: "Alternar modo de arrastre con teclado usando teclas de flecha. Atajo: tecla D",
743
761
  keyboardDragActive: "\u2328\uFE0F Modo de Arrastre con Teclado Activo (Teclas de flecha para mover, May\xFAs+Flechas para pasos grandes, D o ESC para salir)",
762
+ dragResizePrompt: "Pulsa D para mover o R para cambiar el tama\xF1o. Home restablece la posici\xF3n; Esc cierra.",
763
+ dragModeEnabled: "Modo de arrastre con teclado activado. Usa flechas para mover, May\xFAs+Flechas para pasos grandes. Pulsa D o Esc para salir.",
764
+ dragModeDisabled: "Modo de arrastre con teclado desactivado.",
744
765
  resizeWindow: "Cambiar tama\xF1o de ventana",
766
+ disableResizeWindow: "Desactivar modo de cambio de tama\xF1o",
767
+ resizeModeHint: "Controladores habilitados. Arrastra bordes o esquinas para ajustar. Pulsa Esc o R para salir.",
768
+ resizeModeEnabled: "Modo de cambio de tama\xF1o activado. Arrastra bordes o esquinas. Pulsa Esc o R para salir.",
769
+ resizeModeDisabled: "Modo de cambio de tama\xF1o desactivado.",
770
+ positionReset: "Posici\xF3n de la transcripci\xF3n restablecida.",
745
771
  styleTranscript: "Abrir configuraci\xF3n de estilo de transcripci\xF3n",
746
772
  closeMenu: "Cerrar men\xFA",
747
773
  styleTitle: "Estilo de Transcripci\xF3n",
748
- autoscroll: "Desplazamiento autom\xE1tico"
774
+ autoscroll: "Desplazamiento autom\xE1tico",
775
+ settingsMenu: "Men\xFA de configuraci\xF3n"
749
776
  },
750
777
  settings: {
751
778
  title: "Configuraci\xF3n",
@@ -863,11 +890,20 @@ var translations = {
863
890
  settings: "Param\xE8tres de transcription. Appuyez sur Entr\xE9e pour ouvrir le menu ou D pour activer le mode glissement",
864
891
  keyboardDragMode: "Basculer le mode glissement avec les touches fl\xE9ch\xE9es. Raccourci: touche D",
865
892
  keyboardDragActive: "\u2328\uFE0F Mode Glissement Clavier Actif (Touches fl\xE9ch\xE9es pour d\xE9placer, Maj+Fl\xE9ch\xE9es pour grands pas, D ou \xC9chap pour quitter)",
893
+ dragResizePrompt: "Appuyez sur D pour d\xE9placer ou R pour redimensionner. Home r\xE9initialise la position, \xC9chap ferme.",
894
+ dragModeEnabled: "Mode glissement clavier activ\xE9. Utilisez les fl\xE8ches pour d\xE9placer, Maj+Fl\xE8ches pour de grands pas. Appuyez sur D ou \xC9chap pour quitter.",
895
+ dragModeDisabled: "Mode glissement clavier d\xE9sactiv\xE9.",
866
896
  resizeWindow: "Redimensionner la fen\xEAtre",
897
+ disableResizeWindow: "D\xE9sactiver le mode de redimensionnement",
898
+ resizeModeHint: "Poign\xE9es activ\xE9es. Faites glisser les bords ou les coins pour ajuster. Appuyez sur \xC9chap ou R pour quitter.",
899
+ resizeModeEnabled: "Mode redimensionnement activ\xE9. Faites glisser les bords ou coins. Appuyez sur \xC9chap ou R pour quitter.",
900
+ resizeModeDisabled: "Mode redimensionnement d\xE9sactiv\xE9.",
901
+ positionReset: "Position de la transcription r\xE9initialis\xE9e.",
867
902
  styleTranscript: "Ouvrir les param\xE8tres de style de transcription",
868
903
  closeMenu: "Fermer le menu",
869
904
  styleTitle: "Style de Transcription",
870
- autoscroll: "D\xE9filement automatique"
905
+ autoscroll: "D\xE9filement automatique",
906
+ settingsMenu: "Menu des param\xE8tres"
871
907
  },
872
908
  settings: {
873
909
  title: "Param\xE8tres",
@@ -985,11 +1021,20 @@ var translations = {
985
1021
  settings: "\u6587\u5B57\u8D77\u3053\u3057\u8A2D\u5B9A\u3002Enter\u30AD\u30FC\u3067\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F\u3001\u307E\u305F\u306FD\u30AD\u30FC\u3067\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3059\u308B",
986
1022
  keyboardDragMode: "\u77E2\u5370\u30AD\u30FC\u3067\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u5207\u308A\u66FF\u3048\u3002\u30B7\u30E7\u30FC\u30C8\u30AB\u30C3\u30C8\uFF1AD\u30AD\u30FC",
987
1023
  keyboardDragActive: "\u2328\uFE0F \u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u6709\u52B9\uFF08\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Shift+\u77E2\u5370\u30AD\u30FC\u3067\u5927\u304D\u304F\u79FB\u52D5\u3001D\u307E\u305F\u306FESC\u3067\u7D42\u4E86\uFF09",
1024
+ dragResizePrompt: "D\u30AD\u30FC\u3067\u79FB\u52D5\u3001R\u30AD\u30FC\u3067\u30B5\u30A4\u30BA\u5909\u66F4\u3002Home\u3067\u4F4D\u7F6E\u3092\u30EA\u30BB\u30C3\u30C8\u3001Esc\u3067\u9589\u3058\u307E\u3059\u3002",
1025
+ dragModeEnabled: "\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u307E\u3057\u305F\u3002\u77E2\u5370\u30AD\u30FC\u3067\u79FB\u52D5\u3001Shift+\u77E2\u5370\u30AD\u30FC\u3067\u5927\u304D\u304F\u79FB\u52D5\u3067\u304D\u307E\u3059\u3002\u7D42\u4E86\u3059\u308B\u306B\u306F D \u307E\u305F\u306F Esc \u3092\u62BC\u3057\u307E\u3059\u3002",
1026
+ dragModeDisabled: "\u30AD\u30FC\u30DC\u30FC\u30C9\u30C9\u30E9\u30C3\u30B0\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
988
1027
  resizeWindow: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u30B5\u30A4\u30BA\u5909\u66F4",
1028
+ disableResizeWindow: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3059\u308B",
1029
+ resizeModeHint: "\u30EA\u30B5\u30A4\u30BA\u30CF\u30F3\u30C9\u30EB\u304C\u6709\u52B9\u306B\u306A\u308A\u307E\u3057\u305F\u3002\u8FBA\u3084\u89D2\u3092\u30C9\u30E9\u30C3\u30B0\u3057\u3066\u8ABF\u6574\u3057\u307E\u3059\u3002Esc \u307E\u305F\u306F R \u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
1030
+ resizeModeEnabled: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u307E\u3057\u305F\u3002\u8FBA\u3084\u89D2\u3092\u30C9\u30E9\u30C3\u30B0\u3057\u3066\u8ABF\u6574\u3057\u307E\u3059\u3002Esc \u307E\u305F\u306F R \u3067\u7D42\u4E86\u3057\u307E\u3059\u3002",
1031
+ resizeModeDisabled: "\u30B5\u30A4\u30BA\u5909\u66F4\u30E2\u30FC\u30C9\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002",
1032
+ positionReset: "\u6587\u5B57\u8D77\u3053\u3057\u306E\u4F4D\u7F6E\u3092\u30EA\u30BB\u30C3\u30C8\u3057\u307E\u3057\u305F\u3002",
989
1033
  styleTranscript: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB\u8A2D\u5B9A\u3092\u958B\u304F",
990
1034
  closeMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
991
1035
  styleTitle: "\u6587\u5B57\u8D77\u3053\u3057\u30B9\u30BF\u30A4\u30EB",
992
- autoscroll: "\u81EA\u52D5\u30B9\u30AF\u30ED\u30FC\u30EB"
1036
+ autoscroll: "\u81EA\u52D5\u30B9\u30AF\u30ED\u30FC\u30EB",
1037
+ settingsMenu: "\u8A2D\u5B9A\u30E1\u30CB\u30E5\u30FC"
993
1038
  },
994
1039
  settings: {
995
1040
  title: "\u8A2D\u5B9A",
@@ -1777,10 +1822,7 @@ var ControlBar = class {
1777
1822
  }
1778
1823
  });
1779
1824
  this.controls.currentTimeDisplay = DOMUtils.createElement("span", {
1780
- className: `${this.player.options.classPrefix}-current-time`,
1781
- attributes: {
1782
- "aria-label": i18n.t("time.seconds", { count: 0 })
1783
- }
1825
+ className: `${this.player.options.classPrefix}-current-time`
1784
1826
  });
1785
1827
  const currentTimeVisual = DOMUtils.createElement("span", {
1786
1828
  textContent: "00:00",
@@ -1788,8 +1830,14 @@ var ControlBar = class {
1788
1830
  "aria-hidden": "true"
1789
1831
  }
1790
1832
  });
1833
+ const currentTimeAccessible = DOMUtils.createElement("span", {
1834
+ className: "vidply-sr-only",
1835
+ textContent: i18n.t("time.seconds", { count: 0 })
1836
+ });
1791
1837
  this.controls.currentTimeDisplay.appendChild(currentTimeVisual);
1838
+ this.controls.currentTimeDisplay.appendChild(currentTimeAccessible);
1792
1839
  this.controls.currentTimeVisual = currentTimeVisual;
1840
+ this.controls.currentTimeAccessible = currentTimeAccessible;
1793
1841
  const separator = DOMUtils.createElement("span", {
1794
1842
  textContent: " / ",
1795
1843
  attributes: {
@@ -1797,10 +1845,7 @@ var ControlBar = class {
1797
1845
  }
1798
1846
  });
1799
1847
  this.controls.durationDisplay = DOMUtils.createElement("span", {
1800
- className: `${this.player.options.classPrefix}-duration`,
1801
- attributes: {
1802
- "aria-label": i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
1803
- }
1848
+ className: `${this.player.options.classPrefix}-duration`
1804
1849
  });
1805
1850
  const durationVisual = DOMUtils.createElement("span", {
1806
1851
  textContent: "00:00",
@@ -1808,8 +1853,14 @@ var ControlBar = class {
1808
1853
  "aria-hidden": "true"
1809
1854
  }
1810
1855
  });
1856
+ const durationAccessible = DOMUtils.createElement("span", {
1857
+ className: "vidply-sr-only",
1858
+ textContent: i18n.t("time.durationPrefix") + i18n.t("time.seconds", { count: 0 })
1859
+ });
1811
1860
  this.controls.durationDisplay.appendChild(durationVisual);
1861
+ this.controls.durationDisplay.appendChild(durationAccessible);
1812
1862
  this.controls.durationVisual = durationVisual;
1863
+ this.controls.durationAccessible = durationAccessible;
1813
1864
  container.appendChild(this.controls.currentTimeDisplay);
1814
1865
  container.appendChild(separator);
1815
1866
  container.appendChild(this.controls.durationDisplay);
@@ -2636,14 +2687,18 @@ var ControlBar = class {
2636
2687
  if (this.controls.currentTimeVisual) {
2637
2688
  const currentTime = this.player.state.currentTime;
2638
2689
  this.controls.currentTimeVisual.textContent = TimeUtils.formatTime(currentTime);
2639
- this.controls.currentTimeDisplay.setAttribute("aria-label", TimeUtils.formatDuration(currentTime));
2690
+ if (this.controls.currentTimeAccessible) {
2691
+ this.controls.currentTimeAccessible.textContent = TimeUtils.formatDuration(currentTime);
2692
+ }
2640
2693
  }
2641
2694
  }
2642
2695
  updateDuration() {
2643
2696
  if (this.controls.durationVisual) {
2644
2697
  const duration = this.player.state.duration;
2645
2698
  this.controls.durationVisual.textContent = TimeUtils.formatTime(duration);
2646
- this.controls.durationDisplay.setAttribute("aria-label", i18n.t("time.durationPrefix") + TimeUtils.formatDuration(duration));
2699
+ if (this.controls.durationAccessible) {
2700
+ this.controls.durationAccessible.textContent = i18n.t("time.durationPrefix") + TimeUtils.formatDuration(duration);
2701
+ }
2647
2702
  }
2648
2703
  }
2649
2704
  updateVolumeDisplay() {
@@ -3298,6 +3353,596 @@ var KeyboardManager = class {
3298
3353
  }
3299
3354
  };
3300
3355
 
3356
+ // src/utils/DraggableResizable.js
3357
+ var DraggableResizable = class {
3358
+ constructor(element, options = {}) {
3359
+ this.element = element;
3360
+ this.options = {
3361
+ dragHandle: null,
3362
+ // Element to use as drag handle (defaults to element itself)
3363
+ resizeHandles: [],
3364
+ // Array of resize handle elements
3365
+ onDragStart: null,
3366
+ onDrag: null,
3367
+ onDragEnd: null,
3368
+ onResizeStart: null,
3369
+ onResize: null,
3370
+ onResizeEnd: null,
3371
+ constrainToViewport: true,
3372
+ // Allow movement outside viewport?
3373
+ minWidth: 150,
3374
+ minHeight: 100,
3375
+ maintainAspectRatio: false,
3376
+ keyboardDragKey: "d",
3377
+ keyboardResizeKey: "r",
3378
+ keyboardStep: 5,
3379
+ keyboardStepLarge: 10,
3380
+ maxWidth: null,
3381
+ maxHeight: null,
3382
+ pointerResizeIndicatorText: null,
3383
+ onPointerResizeToggle: null,
3384
+ classPrefix: "draggable",
3385
+ storage: null,
3386
+ // StorageManager instance for saving position/size
3387
+ storageKey: null,
3388
+ // Key for localStorage (if storage is provided)
3389
+ ...options
3390
+ };
3391
+ this.isDragging = false;
3392
+ this.isResizing = false;
3393
+ this.resizeDirection = null;
3394
+ this.dragOffsetX = 0;
3395
+ this.dragOffsetY = 0;
3396
+ this.positionOffsetX = 0;
3397
+ this.positionOffsetY = 0;
3398
+ this.initialMouseX = 0;
3399
+ this.initialMouseY = 0;
3400
+ this.needsPositionConversion = false;
3401
+ this.resizeStartX = 0;
3402
+ this.resizeStartY = 0;
3403
+ this.resizeStartWidth = 0;
3404
+ this.resizeStartHeight = 0;
3405
+ this.resizeStartLeft = 0;
3406
+ this.resizeStartTop = 0;
3407
+ this.keyboardDragMode = false;
3408
+ this.keyboardResizeMode = false;
3409
+ this.pointerResizeMode = false;
3410
+ this.manuallyPositioned = false;
3411
+ this.resizeHandlesManaged = /* @__PURE__ */ new Map();
3412
+ this.resizeIndicatorElement = null;
3413
+ this.handlers = {
3414
+ mousedown: this.onMouseDown.bind(this),
3415
+ mousemove: this.onMouseMove.bind(this),
3416
+ mouseup: this.onMouseUp.bind(this),
3417
+ touchstart: this.onTouchStart.bind(this),
3418
+ touchmove: this.onTouchMove.bind(this),
3419
+ touchend: this.onTouchEnd.bind(this),
3420
+ keydown: this.onKeyDown.bind(this),
3421
+ resizeHandleMousedown: this.onResizeHandleMouseDown.bind(this)
3422
+ };
3423
+ this.init();
3424
+ }
3425
+ hasManagedResizeHandles() {
3426
+ return Array.from(this.resizeHandlesManaged.values()).some(Boolean);
3427
+ }
3428
+ storeOriginalHandleDisplay(handle) {
3429
+ if (!handle.dataset.originalDisplay) {
3430
+ handle.dataset.originalDisplay = handle.style.display || "";
3431
+ }
3432
+ }
3433
+ hideResizeHandle(handle) {
3434
+ handle.style.display = "none";
3435
+ handle.setAttribute("aria-hidden", "true");
3436
+ }
3437
+ showResizeHandle(handle) {
3438
+ const original = handle.dataset.originalDisplay !== void 0 ? handle.dataset.originalDisplay : "";
3439
+ handle.style.display = original;
3440
+ handle.removeAttribute("aria-hidden");
3441
+ }
3442
+ setManagedHandlesVisible(visible) {
3443
+ if (!this.options.resizeHandles || this.options.resizeHandles.length === 0) {
3444
+ return;
3445
+ }
3446
+ this.options.resizeHandles.forEach((handle) => {
3447
+ if (!this.resizeHandlesManaged.get(handle)) {
3448
+ return;
3449
+ }
3450
+ if (visible) {
3451
+ this.showResizeHandle(handle);
3452
+ } else {
3453
+ this.hideResizeHandle(handle);
3454
+ }
3455
+ });
3456
+ }
3457
+ init() {
3458
+ const dragHandle = this.options.dragHandle || this.element;
3459
+ dragHandle.addEventListener("mousedown", this.handlers.mousedown);
3460
+ dragHandle.addEventListener("touchstart", this.handlers.touchstart);
3461
+ document.addEventListener("mousemove", this.handlers.mousemove);
3462
+ document.addEventListener("mouseup", this.handlers.mouseup);
3463
+ document.addEventListener("touchmove", this.handlers.touchmove, { passive: false });
3464
+ document.addEventListener("touchend", this.handlers.touchend);
3465
+ this.element.addEventListener("keydown", this.handlers.keydown);
3466
+ if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
3467
+ this.options.resizeHandles.forEach((handle) => {
3468
+ handle.addEventListener("mousedown", this.handlers.resizeHandleMousedown);
3469
+ handle.addEventListener("touchstart", this.handlers.resizeHandleMousedown);
3470
+ const managed = handle.dataset.vidplyManagedResize === "true";
3471
+ this.resizeHandlesManaged.set(handle, managed);
3472
+ if (managed) {
3473
+ this.storeOriginalHandleDisplay(handle);
3474
+ this.hideResizeHandle(handle);
3475
+ }
3476
+ });
3477
+ }
3478
+ }
3479
+ onMouseDown(e) {
3480
+ if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
3481
+ return;
3482
+ }
3483
+ if (this.options.onDragStart && !this.options.onDragStart(e)) {
3484
+ return;
3485
+ }
3486
+ this.startDragging(e.clientX, e.clientY);
3487
+ e.preventDefault();
3488
+ }
3489
+ onTouchStart(e) {
3490
+ if (e.target.classList.contains(`${this.options.classPrefix}-resize-handle`)) {
3491
+ return;
3492
+ }
3493
+ if (this.options.onDragStart && !this.options.onDragStart(e)) {
3494
+ return;
3495
+ }
3496
+ const touch = e.touches[0];
3497
+ this.startDragging(touch.clientX, touch.clientY);
3498
+ }
3499
+ onResizeHandleMouseDown(e) {
3500
+ var _a, _b, _c, _d;
3501
+ e.preventDefault();
3502
+ e.stopPropagation();
3503
+ const handle = e.target;
3504
+ this.resizeDirection = handle.getAttribute("data-direction");
3505
+ const clientX = e.clientX || ((_b = (_a = e.touches) == null ? void 0 : _a[0]) == null ? void 0 : _b.clientX);
3506
+ const clientY = e.clientY || ((_d = (_c = e.touches) == null ? void 0 : _c[0]) == null ? void 0 : _d.clientY);
3507
+ this.startResizing(clientX, clientY);
3508
+ }
3509
+ onMouseMove(e) {
3510
+ if (this.isDragging) {
3511
+ this.drag(e.clientX, e.clientY);
3512
+ e.preventDefault();
3513
+ } else if (this.isResizing) {
3514
+ this.resize(e.clientX, e.clientY);
3515
+ e.preventDefault();
3516
+ }
3517
+ }
3518
+ onTouchMove(e) {
3519
+ if (this.isDragging || this.isResizing) {
3520
+ const touch = e.touches[0];
3521
+ if (this.isDragging) {
3522
+ this.drag(touch.clientX, touch.clientY);
3523
+ } else {
3524
+ this.resize(touch.clientX, touch.clientY);
3525
+ }
3526
+ e.preventDefault();
3527
+ }
3528
+ }
3529
+ onMouseUp() {
3530
+ if (this.isDragging) {
3531
+ this.stopDragging();
3532
+ } else if (this.isResizing) {
3533
+ this.stopResizing();
3534
+ }
3535
+ }
3536
+ onTouchEnd() {
3537
+ if (this.isDragging) {
3538
+ this.stopDragging();
3539
+ } else if (this.isResizing) {
3540
+ this.stopResizing();
3541
+ }
3542
+ }
3543
+ onKeyDown(e) {
3544
+ if (e.key.toLowerCase() === this.options.keyboardDragKey.toLowerCase()) {
3545
+ e.preventDefault();
3546
+ this.toggleKeyboardDragMode();
3547
+ return;
3548
+ }
3549
+ if (e.key.toLowerCase() === this.options.keyboardResizeKey.toLowerCase()) {
3550
+ e.preventDefault();
3551
+ if (this.hasManagedResizeHandles()) {
3552
+ this.togglePointerResizeMode();
3553
+ } else {
3554
+ this.toggleKeyboardResizeMode();
3555
+ }
3556
+ return;
3557
+ }
3558
+ if (e.key === "Escape") {
3559
+ if (this.pointerResizeMode) {
3560
+ e.preventDefault();
3561
+ this.disablePointerResizeMode();
3562
+ return;
3563
+ }
3564
+ if (this.keyboardDragMode || this.keyboardResizeMode) {
3565
+ e.preventDefault();
3566
+ this.disableKeyboardDragMode();
3567
+ this.disableKeyboardResizeMode();
3568
+ return;
3569
+ }
3570
+ }
3571
+ if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
3572
+ if (this.keyboardDragMode) {
3573
+ e.preventDefault();
3574
+ e.stopPropagation();
3575
+ this.keyboardDrag(e.key, e.shiftKey);
3576
+ } else if (this.keyboardResizeMode) {
3577
+ e.preventDefault();
3578
+ e.stopPropagation();
3579
+ this.keyboardResize(e.key, e.shiftKey);
3580
+ }
3581
+ }
3582
+ if (e.key === "Home" && (this.keyboardDragMode || this.keyboardResizeMode)) {
3583
+ e.preventDefault();
3584
+ this.resetPosition();
3585
+ }
3586
+ }
3587
+ startDragging(clientX, clientY) {
3588
+ const rect = this.element.getBoundingClientRect();
3589
+ const computedStyle = window.getComputedStyle(this.element);
3590
+ const needsConversion = computedStyle.right !== "auto" || computedStyle.bottom !== "auto" || computedStyle.transform !== "none";
3591
+ this.positionOffsetX = 0;
3592
+ this.positionOffsetY = 0;
3593
+ if (needsConversion) {
3594
+ let targetLeft, targetTop;
3595
+ if (computedStyle.position === "absolute") {
3596
+ const offsetParent = this.element.offsetParent || document.body;
3597
+ const parentRect = offsetParent.getBoundingClientRect();
3598
+ targetLeft = rect.left - parentRect.left;
3599
+ targetTop = rect.top - parentRect.top;
3600
+ this.positionOffsetX = parentRect.left;
3601
+ this.positionOffsetY = parentRect.top;
3602
+ } else if (computedStyle.position === "fixed") {
3603
+ const parsedLeft = parseFloat(computedStyle.left);
3604
+ const parsedTop = parseFloat(computedStyle.top);
3605
+ const hasLeft = Number.isFinite(parsedLeft);
3606
+ const hasTop = Number.isFinite(parsedTop);
3607
+ targetLeft = hasLeft ? parsedLeft : rect.left;
3608
+ targetTop = hasTop ? parsedTop : rect.top;
3609
+ this.positionOffsetX = rect.left - targetLeft;
3610
+ this.positionOffsetY = rect.top - targetTop;
3611
+ } else {
3612
+ targetLeft = rect.left;
3613
+ targetTop = rect.top;
3614
+ this.positionOffsetX = rect.left - targetLeft;
3615
+ this.positionOffsetY = rect.top - targetTop;
3616
+ }
3617
+ const currentCssText = this.element.style.cssText;
3618
+ let newCssText = currentCssText.split(";").filter((rule) => {
3619
+ const trimmed = rule.trim();
3620
+ return trimmed && !trimmed.startsWith("right:") && !trimmed.startsWith("bottom:") && !trimmed.startsWith("transform:") && !trimmed.startsWith("left:") && !trimmed.startsWith("top:") && !trimmed.startsWith("inset:");
3621
+ }).join("; ");
3622
+ if (newCssText) newCssText += "; ";
3623
+ newCssText += `left: ${targetLeft}px; top: ${targetTop}px; right: auto; bottom: auto; transform: none`;
3624
+ this.element.style.cssText = newCssText;
3625
+ }
3626
+ const finalRect = this.element.getBoundingClientRect();
3627
+ this.dragOffsetX = clientX - finalRect.left;
3628
+ this.dragOffsetY = clientY - finalRect.top;
3629
+ this.isDragging = true;
3630
+ this.element.classList.add(`${this.options.classPrefix}-dragging`);
3631
+ document.body.style.cursor = "grabbing";
3632
+ document.body.style.userSelect = "none";
3633
+ }
3634
+ drag(clientX, clientY) {
3635
+ if (!this.isDragging) return;
3636
+ let newX = clientX - this.dragOffsetX - this.positionOffsetX;
3637
+ let newY = clientY - this.dragOffsetY - this.positionOffsetY;
3638
+ if (this.options.constrainToViewport) {
3639
+ const rect = this.element.getBoundingClientRect();
3640
+ const viewportWidth = document.documentElement.clientWidth;
3641
+ const viewportHeight = document.documentElement.clientHeight;
3642
+ const minVisible = 100;
3643
+ const minX = -(rect.width - minVisible);
3644
+ const minY = -(rect.height - minVisible);
3645
+ const maxX = viewportWidth - minVisible;
3646
+ const maxY = viewportHeight - minVisible;
3647
+ newX = Math.max(minX, Math.min(newX, maxX));
3648
+ newY = Math.max(minY, Math.min(newY, maxY));
3649
+ }
3650
+ this.element.style.left = `${newX}px`;
3651
+ this.element.style.top = `${newY}px`;
3652
+ if (this.options.onDrag) {
3653
+ this.options.onDrag({ x: newX, y: newY });
3654
+ }
3655
+ }
3656
+ stopDragging() {
3657
+ this.isDragging = false;
3658
+ this.element.classList.remove(`${this.options.classPrefix}-dragging`);
3659
+ document.body.style.cursor = "";
3660
+ document.body.style.userSelect = "";
3661
+ this.manuallyPositioned = true;
3662
+ if (this.options.onDragEnd) {
3663
+ this.options.onDragEnd();
3664
+ }
3665
+ }
3666
+ startResizing(clientX, clientY) {
3667
+ this.isResizing = true;
3668
+ this.resizeStartX = clientX;
3669
+ this.resizeStartY = clientY;
3670
+ const rect = this.element.getBoundingClientRect();
3671
+ this.resizeStartWidth = rect.width;
3672
+ this.resizeStartHeight = rect.height;
3673
+ this.resizeStartLeft = rect.left;
3674
+ this.resizeStartTop = rect.top;
3675
+ this.element.classList.add(`${this.options.classPrefix}-resizing`);
3676
+ document.body.style.userSelect = "none";
3677
+ if (this.options.onResizeStart) {
3678
+ this.options.onResizeStart();
3679
+ }
3680
+ }
3681
+ resize(clientX, clientY) {
3682
+ if (!this.isResizing) return;
3683
+ const deltaX = clientX - this.resizeStartX;
3684
+ const deltaY = clientY - this.resizeStartY;
3685
+ let newWidth = this.resizeStartWidth;
3686
+ let newHeight = this.resizeStartHeight;
3687
+ let newLeft = this.resizeStartLeft;
3688
+ let newTop = this.resizeStartTop;
3689
+ if (this.resizeDirection.includes("e")) {
3690
+ newWidth = Math.max(this.options.minWidth, this.resizeStartWidth + deltaX);
3691
+ }
3692
+ if (this.resizeDirection.includes("w")) {
3693
+ const proposedWidth = Math.max(this.options.minWidth, this.resizeStartWidth - deltaX);
3694
+ newLeft = this.resizeStartLeft + (this.resizeStartWidth - proposedWidth);
3695
+ newWidth = proposedWidth;
3696
+ }
3697
+ const maxWidthOption = typeof this.options.maxWidth === "function" ? this.options.maxWidth() : this.options.maxWidth;
3698
+ if (Number.isFinite(maxWidthOption)) {
3699
+ const clampedWidth = Math.min(newWidth, maxWidthOption);
3700
+ if (clampedWidth !== newWidth && this.resizeDirection.includes("w")) {
3701
+ newLeft += newWidth - clampedWidth;
3702
+ }
3703
+ newWidth = clampedWidth;
3704
+ }
3705
+ if (!this.options.maintainAspectRatio) {
3706
+ if (this.resizeDirection.includes("s")) {
3707
+ newHeight = Math.max(this.options.minHeight, this.resizeStartHeight + deltaY);
3708
+ }
3709
+ if (this.resizeDirection.includes("n")) {
3710
+ const proposedHeight = Math.max(this.options.minHeight, this.resizeStartHeight - deltaY);
3711
+ newTop = this.resizeStartTop + (this.resizeStartHeight - proposedHeight);
3712
+ newHeight = proposedHeight;
3713
+ }
3714
+ const maxHeightOption = typeof this.options.maxHeight === "function" ? this.options.maxHeight() : this.options.maxHeight;
3715
+ if (Number.isFinite(maxHeightOption)) {
3716
+ const clampedHeight = Math.min(newHeight, maxHeightOption);
3717
+ if (clampedHeight !== newHeight && this.resizeDirection.includes("n")) {
3718
+ newTop += newHeight - clampedHeight;
3719
+ }
3720
+ newHeight = clampedHeight;
3721
+ }
3722
+ }
3723
+ this.element.style.width = `${newWidth}px`;
3724
+ if (!this.options.maintainAspectRatio) {
3725
+ this.element.style.height = `${newHeight}px`;
3726
+ } else {
3727
+ this.element.style.height = "auto";
3728
+ }
3729
+ if (this.resizeDirection.includes("w")) {
3730
+ this.element.style.left = `${newLeft}px`;
3731
+ }
3732
+ if (this.resizeDirection.includes("n") && !this.options.maintainAspectRatio) {
3733
+ this.element.style.top = `${newTop}px`;
3734
+ }
3735
+ if (this.options.onResize) {
3736
+ this.options.onResize({ width: newWidth, height: newHeight, left: newLeft, top: newTop });
3737
+ }
3738
+ }
3739
+ stopResizing() {
3740
+ this.isResizing = false;
3741
+ this.resizeDirection = null;
3742
+ this.element.classList.remove(`${this.options.classPrefix}-resizing`);
3743
+ document.body.style.userSelect = "";
3744
+ this.manuallyPositioned = true;
3745
+ if (this.options.onResizeEnd) {
3746
+ this.options.onResizeEnd();
3747
+ }
3748
+ }
3749
+ toggleKeyboardDragMode() {
3750
+ if (this.keyboardDragMode) {
3751
+ this.disableKeyboardDragMode();
3752
+ } else {
3753
+ this.enableKeyboardDragMode();
3754
+ }
3755
+ }
3756
+ enableKeyboardDragMode() {
3757
+ this.keyboardDragMode = true;
3758
+ this.keyboardResizeMode = false;
3759
+ this.element.classList.add(`${this.options.classPrefix}-keyboard-drag`);
3760
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
3761
+ this.focusElement();
3762
+ }
3763
+ disableKeyboardDragMode() {
3764
+ this.keyboardDragMode = false;
3765
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
3766
+ }
3767
+ toggleKeyboardResizeMode() {
3768
+ if (this.keyboardResizeMode) {
3769
+ this.disableKeyboardResizeMode();
3770
+ } else {
3771
+ this.enableKeyboardResizeMode();
3772
+ }
3773
+ }
3774
+ enableKeyboardResizeMode() {
3775
+ this.keyboardResizeMode = true;
3776
+ this.keyboardDragMode = false;
3777
+ this.element.classList.add(`${this.options.classPrefix}-keyboard-resize`);
3778
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-drag`);
3779
+ this.focusElement();
3780
+ }
3781
+ disableKeyboardResizeMode() {
3782
+ this.keyboardResizeMode = false;
3783
+ this.element.classList.remove(`${this.options.classPrefix}-keyboard-resize`);
3784
+ }
3785
+ enablePointerResizeMode({ focus = true } = {}) {
3786
+ if (!this.hasManagedResizeHandles()) {
3787
+ this.enableKeyboardResizeMode();
3788
+ return;
3789
+ }
3790
+ if (this.pointerResizeMode) {
3791
+ return;
3792
+ }
3793
+ this.pointerResizeMode = true;
3794
+ this.setManagedHandlesVisible(true);
3795
+ this.element.classList.add(`${this.options.classPrefix}-resizable`);
3796
+ this.enableKeyboardResizeMode();
3797
+ if (focus) {
3798
+ this.focusElement();
3799
+ }
3800
+ if (typeof this.options.onPointerResizeToggle === "function") {
3801
+ this.options.onPointerResizeToggle(true);
3802
+ }
3803
+ }
3804
+ disablePointerResizeMode({ focus = false } = {}) {
3805
+ if (!this.pointerResizeMode) {
3806
+ return;
3807
+ }
3808
+ this.pointerResizeMode = false;
3809
+ this.setManagedHandlesVisible(false);
3810
+ this.element.classList.remove(`${this.options.classPrefix}-resizable`);
3811
+ this.disableKeyboardResizeMode();
3812
+ if (focus) {
3813
+ this.focusElement();
3814
+ }
3815
+ if (typeof this.options.onPointerResizeToggle === "function") {
3816
+ this.options.onPointerResizeToggle(false);
3817
+ }
3818
+ }
3819
+ togglePointerResizeMode() {
3820
+ if (this.pointerResizeMode) {
3821
+ this.disablePointerResizeMode();
3822
+ } else {
3823
+ this.enablePointerResizeMode();
3824
+ }
3825
+ return this.pointerResizeMode;
3826
+ }
3827
+ focusElement() {
3828
+ if (typeof this.element.focus === "function") {
3829
+ try {
3830
+ this.element.focus({ preventScroll: true });
3831
+ } catch (e) {
3832
+ this.element.focus();
3833
+ }
3834
+ }
3835
+ }
3836
+ keyboardDrag(key, shiftKey) {
3837
+ const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
3838
+ let currentLeft = parseFloat(this.element.style.left) || 0;
3839
+ let currentTop = parseFloat(this.element.style.top) || 0;
3840
+ const computedStyle = window.getComputedStyle(this.element);
3841
+ if (computedStyle.transform !== "none") {
3842
+ const rect = this.element.getBoundingClientRect();
3843
+ currentLeft = rect.left;
3844
+ currentTop = rect.top;
3845
+ this.element.style.transform = "none";
3846
+ this.element.style.left = `${currentLeft}px`;
3847
+ this.element.style.top = `${currentTop}px`;
3848
+ }
3849
+ let newX = currentLeft;
3850
+ let newY = currentTop;
3851
+ switch (key) {
3852
+ case "ArrowLeft":
3853
+ newX -= step;
3854
+ break;
3855
+ case "ArrowRight":
3856
+ newX += step;
3857
+ break;
3858
+ case "ArrowUp":
3859
+ newY -= step;
3860
+ break;
3861
+ case "ArrowDown":
3862
+ newY += step;
3863
+ break;
3864
+ }
3865
+ this.element.style.left = `${newX}px`;
3866
+ this.element.style.top = `${newY}px`;
3867
+ if (this.options.onDrag) {
3868
+ this.options.onDrag({ x: newX, y: newY });
3869
+ }
3870
+ }
3871
+ keyboardResize(key, shiftKey) {
3872
+ const step = shiftKey ? this.options.keyboardStepLarge : this.options.keyboardStep;
3873
+ const rect = this.element.getBoundingClientRect();
3874
+ let width = rect.width;
3875
+ let height = rect.height;
3876
+ switch (key) {
3877
+ case "ArrowLeft":
3878
+ width -= step;
3879
+ break;
3880
+ case "ArrowRight":
3881
+ width += step;
3882
+ break;
3883
+ case "ArrowUp":
3884
+ if (this.options.maintainAspectRatio) {
3885
+ width += step;
3886
+ } else {
3887
+ height -= step;
3888
+ }
3889
+ break;
3890
+ case "ArrowDown":
3891
+ if (this.options.maintainAspectRatio) {
3892
+ width -= step;
3893
+ } else {
3894
+ height += step;
3895
+ }
3896
+ break;
3897
+ }
3898
+ width = Math.max(this.options.minWidth, width);
3899
+ height = Math.max(this.options.minHeight, height);
3900
+ this.element.style.width = `${width}px`;
3901
+ if (!this.options.maintainAspectRatio) {
3902
+ this.element.style.height = `${height}px`;
3903
+ } else {
3904
+ this.element.style.height = "auto";
3905
+ }
3906
+ if (this.options.onResize) {
3907
+ this.options.onResize({ width, height });
3908
+ }
3909
+ }
3910
+ resetPosition() {
3911
+ this.element.style.left = "50%";
3912
+ this.element.style.top = "50%";
3913
+ this.element.style.transform = "translate(-50%, -50%)";
3914
+ this.element.style.right = "";
3915
+ this.element.style.bottom = "";
3916
+ this.manuallyPositioned = false;
3917
+ if (this.options.onDrag) {
3918
+ this.options.onDrag({ centered: true });
3919
+ }
3920
+ }
3921
+ destroy() {
3922
+ const dragHandle = this.options.dragHandle || this.element;
3923
+ this.disablePointerResizeMode();
3924
+ dragHandle.removeEventListener("mousedown", this.handlers.mousedown);
3925
+ dragHandle.removeEventListener("touchstart", this.handlers.touchstart);
3926
+ document.removeEventListener("mousemove", this.handlers.mousemove);
3927
+ document.removeEventListener("mouseup", this.handlers.mouseup);
3928
+ document.removeEventListener("touchmove", this.handlers.touchmove);
3929
+ document.removeEventListener("touchend", this.handlers.touchend);
3930
+ this.element.removeEventListener("keydown", this.handlers.keydown);
3931
+ if (this.options.resizeHandles && this.options.resizeHandles.length > 0) {
3932
+ this.options.resizeHandles.forEach((handle) => {
3933
+ handle.removeEventListener("mousedown", this.handlers.resizeHandleMousedown);
3934
+ handle.removeEventListener("touchstart", this.handlers.resizeHandleMousedown);
3935
+ });
3936
+ }
3937
+ this.element.classList.remove(
3938
+ `${this.options.classPrefix}-dragging`,
3939
+ `${this.options.classPrefix}-resizing`,
3940
+ `${this.options.classPrefix}-keyboard-drag`,
3941
+ `${this.options.classPrefix}-keyboard-resize`
3942
+ );
3943
+ }
3944
+ };
3945
+
3301
3946
  // src/controls/TranscriptManager.js
3302
3947
  var TranscriptManager = class {
3303
3948
  constructor(player) {
@@ -3308,21 +3953,17 @@ var TranscriptManager = class {
3308
3953
  this.currentActiveEntry = null;
3309
3954
  this.isVisible = false;
3310
3955
  this.storage = new StorageManager("vidply");
3311
- this.isDragging = false;
3312
- this.dragOffsetX = 0;
3313
- this.dragOffsetY = 0;
3314
- this.isResizing = false;
3315
- this.resizeDirection = null;
3316
- this.resizeStartX = 0;
3317
- this.resizeStartY = 0;
3318
- this.resizeStartWidth = 0;
3319
- this.resizeStartHeight = 0;
3320
- this.resizeEnabled = false;
3956
+ this.draggableResizable = null;
3321
3957
  this.settingsMenuVisible = false;
3322
3958
  this.settingsMenu = null;
3323
3959
  this.settingsButton = null;
3324
3960
  this.settingsMenuJustOpened = false;
3325
- this.keyboardDragMode = false;
3961
+ this.resizeOptionButton = null;
3962
+ this.resizeOptionText = null;
3963
+ this.resizeModeIndicator = null;
3964
+ this.resizeModeIndicatorTimeout = null;
3965
+ this.transcriptResizeHandles = [];
3966
+ this.liveRegion = null;
3326
3967
  this.styleDialog = null;
3327
3968
  this.styleDialogVisible = false;
3328
3969
  this.styleDialogJustOpened = false;
@@ -3342,13 +3983,6 @@ var TranscriptManager = class {
3342
3983
  this.handlers = {
3343
3984
  timeupdate: () => this.updateActiveEntry(),
3344
3985
  resize: null,
3345
- mousemove: null,
3346
- mouseup: null,
3347
- touchmove: null,
3348
- touchend: null,
3349
- mousedown: null,
3350
- touchstart: null,
3351
- keydown: null,
3352
3986
  settingsClick: null,
3353
3987
  settingsKeydown: null,
3354
3988
  documentClick: null,
@@ -3362,7 +3996,9 @@ var TranscriptManager = class {
3362
3996
  this.player.on("timeupdate", this.handlers.timeupdate);
3363
3997
  this.player.on("fullscreenchange", () => {
3364
3998
  if (this.isVisible) {
3365
- this.setManagedTimeout(() => this.positionTranscript(), 100);
3999
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4000
+ this.setManagedTimeout(() => this.positionTranscript(), 100);
4001
+ }
3366
4002
  }
3367
4003
  });
3368
4004
  }
@@ -3383,9 +4019,12 @@ var TranscriptManager = class {
3383
4019
  if (this.transcriptWindow) {
3384
4020
  this.transcriptWindow.style.display = "flex";
3385
4021
  this.isVisible = true;
4022
+ if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
4023
+ this.player.controlBar.updateTranscriptButton();
4024
+ }
3386
4025
  this.setManagedTimeout(() => {
3387
- if (this.settingsButton) {
3388
- this.settingsButton.focus();
4026
+ if (this.transcriptHeader) {
4027
+ this.transcriptHeader.focus();
3389
4028
  }
3390
4029
  }, 150);
3391
4030
  return;
@@ -3394,10 +4033,12 @@ var TranscriptManager = class {
3394
4033
  this.loadTranscriptData();
3395
4034
  if (this.transcriptWindow) {
3396
4035
  this.transcriptWindow.style.display = "flex";
3397
- this.setManagedTimeout(() => this.positionTranscript(), 0);
4036
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4037
+ this.setManagedTimeout(() => this.positionTranscript(), 0);
4038
+ }
3398
4039
  this.setManagedTimeout(() => {
3399
- if (this.settingsButton) {
3400
- this.settingsButton.focus();
4040
+ if (this.transcriptHeader) {
4041
+ this.transcriptHeader.focus();
3401
4042
  }
3402
4043
  }, 150);
3403
4044
  }
@@ -3406,11 +4047,27 @@ var TranscriptManager = class {
3406
4047
  /**
3407
4048
  * Hide transcript window
3408
4049
  */
3409
- hideTranscript() {
4050
+ hideTranscript({ focusButton = false } = {}) {
4051
+ var _a, _b;
3410
4052
  if (this.transcriptWindow) {
3411
4053
  this.transcriptWindow.style.display = "none";
3412
4054
  this.isVisible = false;
3413
4055
  }
4056
+ if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
4057
+ this.draggableResizable.disablePointerResizeMode();
4058
+ this.updateResizeOptionState();
4059
+ }
4060
+ this.hideResizeModeIndicator();
4061
+ this.announceLive("");
4062
+ if (this.player.controlBar && typeof this.player.controlBar.updateTranscriptButton === "function") {
4063
+ this.player.controlBar.updateTranscriptButton();
4064
+ }
4065
+ if (focusButton) {
4066
+ const transcriptButton = (_b = (_a = this.player.controlBar) == null ? void 0 : _a.controls) == null ? void 0 : _b.transcript;
4067
+ if (transcriptButton && typeof transcriptButton.focus === "function") {
4068
+ transcriptButton.focus();
4069
+ }
4070
+ }
3414
4071
  }
3415
4072
  /**
3416
4073
  * Create the transcript window UI
@@ -3427,7 +4084,6 @@ var TranscriptManager = class {
3427
4084
  this.transcriptHeader = DOMUtils.createElement("div", {
3428
4085
  className: `${this.player.options.classPrefix}-transcript-header`,
3429
4086
  attributes: {
3430
- "aria-label": "Drag to reposition transcript. Use arrow keys to move, Home to reset position, Escape to close.",
3431
4087
  "tabindex": "0"
3432
4088
  }
3433
4089
  });
@@ -3438,7 +4094,7 @@ var TranscriptManager = class {
3438
4094
  className: `${this.player.options.classPrefix}-transcript-settings`,
3439
4095
  attributes: {
3440
4096
  "type": "button",
3441
- "aria-label": i18n.t("transcript.settings"),
4097
+ "aria-label": i18n.t("transcript.settingsMenu"),
3442
4098
  "aria-expanded": "false"
3443
4099
  }
3444
4100
  });
@@ -3470,7 +4126,7 @@ var TranscriptManager = class {
3470
4126
  };
3471
4127
  this.settingsButton.addEventListener("keydown", this.handlers.settingsKeydown);
3472
4128
  const title = DOMUtils.createElement("h3", {
3473
- textContent: i18n.t("transcript.title")
4129
+ textContent: `${i18n.t("transcript.title")}. ${i18n.t("transcript.dragResizePrompt")}`
3474
4130
  });
3475
4131
  const autoscrollLabel = DOMUtils.createElement("label", {
3476
4132
  className: `${this.player.options.classPrefix}-transcript-autoscroll-label`,
@@ -3495,8 +4151,8 @@ var TranscriptManager = class {
3495
4151
  this.autoscrollEnabled = e.target.checked;
3496
4152
  this.saveAutoscrollPreference();
3497
4153
  });
4154
+ this.transcriptHeader.appendChild(title);
3498
4155
  this.headerLeft.appendChild(this.settingsButton);
3499
- this.headerLeft.appendChild(title);
3500
4156
  this.headerLeft.appendChild(autoscrollLabel);
3501
4157
  this.languageSelector = DOMUtils.createElement("select", {
3502
4158
  className: `${this.player.options.classPrefix}-transcript-language-select`,
@@ -3515,7 +4171,7 @@ var TranscriptManager = class {
3515
4171
  }
3516
4172
  });
3517
4173
  closeButton.appendChild(createIconElement("close"));
3518
- closeButton.addEventListener("click", () => this.hideTranscript());
4174
+ closeButton.addEventListener("click", () => this.hideTranscript({ focusButton: true }));
3519
4175
  this.transcriptHeader.appendChild(this.headerLeft);
3520
4176
  this.transcriptHeader.appendChild(closeButton);
3521
4177
  this.transcriptContent = DOMUtils.createElement("div", {
@@ -3523,9 +4179,20 @@ var TranscriptManager = class {
3523
4179
  });
3524
4180
  this.transcriptWindow.appendChild(this.transcriptHeader);
3525
4181
  this.transcriptWindow.appendChild(this.transcriptContent);
4182
+ this.createResizeHandles();
4183
+ this.liveRegion = DOMUtils.createElement("div", {
4184
+ className: "vidply-sr-only",
4185
+ attributes: {
4186
+ "aria-live": "polite",
4187
+ "aria-atomic": "true"
4188
+ }
4189
+ });
4190
+ this.transcriptWindow.appendChild(this.liveRegion);
3526
4191
  this.player.container.appendChild(this.transcriptWindow);
3527
- this.positionTranscript();
3528
4192
  this.setupDragAndDrop();
4193
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4194
+ this.positionTranscript();
4195
+ }
3529
4196
  this.handlers.documentClick = (e) => {
3530
4197
  if (this.settingsMenuJustOpened) {
3531
4198
  return;
@@ -3552,15 +4219,39 @@ var TranscriptManager = class {
3552
4219
  if (resizeTimeout) {
3553
4220
  this.clearManagedTimeout(resizeTimeout);
3554
4221
  }
3555
- resizeTimeout = this.setManagedTimeout(() => this.positionTranscript(), 100);
4222
+ resizeTimeout = this.setManagedTimeout(() => {
4223
+ if (!this.draggableResizable || !this.draggableResizable.manuallyPositioned) {
4224
+ this.positionTranscript();
4225
+ }
4226
+ }, 100);
3556
4227
  };
3557
4228
  window.addEventListener("resize", this.handlers.resize);
3558
4229
  }
4230
+ createResizeHandles() {
4231
+ if (!this.transcriptWindow) return;
4232
+ const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
4233
+ this.transcriptResizeHandles = directions.map((direction) => {
4234
+ const handle = DOMUtils.createElement("div", {
4235
+ className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
4236
+ attributes: {
4237
+ "data-direction": direction,
4238
+ "data-vidply-managed-resize": "true",
4239
+ "aria-hidden": "true"
4240
+ }
4241
+ });
4242
+ handle.style.display = "none";
4243
+ this.transcriptWindow.appendChild(handle);
4244
+ return handle;
4245
+ });
4246
+ }
3559
4247
  /**
3560
4248
  * Position transcript window next to video
3561
4249
  */
3562
4250
  positionTranscript() {
3563
4251
  if (!this.transcriptWindow || !this.player.videoWrapper || !this.isVisible) return;
4252
+ if (this.draggableResizable && this.draggableResizable.manuallyPositioned) {
4253
+ return;
4254
+ }
3564
4255
  const isMobile = window.innerWidth < 640;
3565
4256
  const videoRect = this.player.videoWrapper.getBoundingClientRect();
3566
4257
  const isFullscreen = this.player.state.fullscreen;
@@ -3593,8 +4284,12 @@ var TranscriptManager = class {
3593
4284
  this.transcriptWindow.style.top = "auto";
3594
4285
  this.transcriptWindow.style.maxHeight = "calc(100vh - 180px)";
3595
4286
  this.transcriptWindow.style.height = "auto";
3596
- this.transcriptWindow.style.width = "400px";
3597
- this.transcriptWindow.style.maxWidth = "400px";
4287
+ const fullscreenMinWidth = 260;
4288
+ const fullscreenAvailable = Math.max(fullscreenMinWidth, window.innerWidth - 40);
4289
+ const fullscreenDesired = parseFloat(this.transcriptWindow.style.width) || 400;
4290
+ const fullscreenWidth = Math.max(fullscreenMinWidth, Math.min(fullscreenDesired, fullscreenAvailable));
4291
+ this.transcriptWindow.style.width = `${fullscreenWidth}px`;
4292
+ this.transcriptWindow.style.maxWidth = "none";
3598
4293
  this.transcriptWindow.style.borderRadius = "8px";
3599
4294
  this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
3600
4295
  this.transcriptWindow.style.borderTop = "";
@@ -3602,15 +4297,30 @@ var TranscriptManager = class {
3602
4297
  this.player.container.appendChild(this.transcriptWindow);
3603
4298
  }
3604
4299
  } else {
4300
+ const transcriptWidth = parseFloat(this.transcriptWindow.style.width) || 400;
4301
+ const padding = 20;
4302
+ const minWidth = 260;
4303
+ const containerRect = this.player.container.getBoundingClientRect();
4304
+ const ensureContainerPositioned = () => {
4305
+ const computed = window.getComputedStyle(this.player.container);
4306
+ if (computed.position === "static") {
4307
+ this.player.container.style.position = "relative";
4308
+ }
4309
+ };
4310
+ ensureContainerPositioned();
4311
+ const left = videoRect.right - containerRect.left + padding;
4312
+ const availableWidth = window.innerWidth - videoRect.right - padding;
4313
+ const appliedWidth = Math.max(minWidth, Math.min(transcriptWidth, availableWidth));
4314
+ const appliedHeight = videoRect.height;
3605
4315
  this.transcriptWindow.style.position = "absolute";
3606
- this.transcriptWindow.style.left = `${videoRect.width + 8}px`;
4316
+ this.transcriptWindow.style.left = `${left}px`;
3607
4317
  this.transcriptWindow.style.right = "auto";
3608
4318
  this.transcriptWindow.style.bottom = "auto";
3609
4319
  this.transcriptWindow.style.top = "0";
3610
- this.transcriptWindow.style.height = `${videoRect.height}px`;
4320
+ this.transcriptWindow.style.height = `${appliedHeight}px`;
3611
4321
  this.transcriptWindow.style.maxHeight = "none";
3612
- this.transcriptWindow.style.width = "400px";
3613
- this.transcriptWindow.style.maxWidth = "400px";
4322
+ this.transcriptWindow.style.width = `${appliedWidth}px`;
4323
+ this.transcriptWindow.style.maxWidth = "none";
3614
4324
  this.transcriptWindow.style.borderRadius = "8px";
3615
4325
  this.transcriptWindow.style.border = "1px solid var(--vidply-border)";
3616
4326
  this.transcriptWindow.style.borderTop = "";
@@ -3998,257 +4708,108 @@ var TranscriptManager = class {
3998
4708
  */
3999
4709
  setupDragAndDrop() {
4000
4710
  if (!this.transcriptHeader || !this.transcriptWindow) return;
4001
- this.handlers.mousedown = (e) => {
4002
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
4003
- return;
4004
- }
4005
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
4006
- return;
4007
- }
4008
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-language-select`)) {
4009
- return;
4010
- }
4011
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
4012
- return;
4013
- }
4014
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
4015
- return;
4016
- }
4017
- this.startDragging(e.clientX, e.clientY);
4018
- e.preventDefault();
4019
- };
4020
- this.handlers.mousemove = (e) => {
4021
- if (this.isDragging) {
4022
- this.drag(e.clientX, e.clientY);
4023
- }
4024
- };
4025
- this.handlers.mouseup = () => {
4026
- if (this.isDragging) {
4027
- this.stopDragging();
4028
- }
4029
- };
4030
- this.handlers.touchstart = (e) => {
4031
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-close`)) {
4032
- return;
4033
- }
4034
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings`)) {
4035
- return;
4036
- }
4037
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-language-select`)) {
4038
- return;
4039
- }
4040
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-settings-menu`)) {
4041
- return;
4042
- }
4043
- if (e.target.closest(`.${this.player.options.classPrefix}-transcript-style-dialog`)) {
4044
- return;
4045
- }
4046
- const isMobile = window.innerWidth < 640;
4047
- const isFullscreen = this.player.state.fullscreen;
4048
- const touch = e.touches[0];
4049
- if (isMobile && !isFullscreen) {
4050
- return;
4051
- } else {
4052
- this.startDragging(touch.clientX, touch.clientY);
4053
- }
4054
- };
4055
- this.handlers.touchmove = (e) => {
4056
- const isMobile = window.innerWidth < 640;
4057
- const isFullscreen = this.player.state.fullscreen;
4058
- if (isMobile && !isFullscreen) {
4059
- return;
4060
- } else if (this.isDragging) {
4061
- const touch = e.touches[0];
4062
- this.drag(touch.clientX, touch.clientY);
4063
- e.preventDefault();
4064
- }
4065
- };
4066
- this.handlers.touchend = () => {
4067
- if (this.isDragging) {
4068
- this.stopDragging();
4069
- }
4070
- };
4071
- this.handlers.keydown = (e) => {
4072
- if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
4073
- if (!this.keyboardDragMode) {
4074
- return;
4711
+ const isMobile = window.innerWidth < 640;
4712
+ const isFullscreen = this.player.state.fullscreen;
4713
+ if (isMobile && !isFullscreen) {
4714
+ return;
4715
+ }
4716
+ this.draggableResizable = new DraggableResizable(this.transcriptWindow, {
4717
+ dragHandle: this.transcriptHeader,
4718
+ resizeHandles: this.transcriptResizeHandles,
4719
+ constrainToViewport: true,
4720
+ classPrefix: `${this.player.options.classPrefix}-transcript`,
4721
+ keyboardDragKey: "d",
4722
+ keyboardResizeKey: "r",
4723
+ keyboardStep: 10,
4724
+ keyboardStepLarge: 50,
4725
+ minWidth: 300,
4726
+ minHeight: 200,
4727
+ maxWidth: () => Math.max(320, window.innerWidth - 40),
4728
+ maxHeight: () => Math.max(200, window.innerHeight - 120),
4729
+ pointerResizeIndicatorText: i18n.t("transcript.resizeModeHint"),
4730
+ onPointerResizeToggle: (enabled) => this.onPointerResizeModeChange(enabled),
4731
+ onDragStart: (e) => {
4732
+ const ignoreSelectors = [
4733
+ `.${this.player.options.classPrefix}-transcript-close`,
4734
+ `.${this.player.options.classPrefix}-transcript-settings`,
4735
+ `.${this.player.options.classPrefix}-transcript-language-select`,
4736
+ `.${this.player.options.classPrefix}-transcript-settings-menu`,
4737
+ `.${this.player.options.classPrefix}-transcript-style-dialog`
4738
+ ];
4739
+ for (const selector of ignoreSelectors) {
4740
+ if (e.target.closest(selector)) {
4741
+ return false;
4742
+ }
4075
4743
  }
4744
+ return true;
4745
+ }
4746
+ });
4747
+ this.customKeyHandler = (e) => {
4748
+ const key = e.key.toLowerCase();
4749
+ const alreadyPrevented = e.defaultPrevented;
4750
+ if (key === "home") {
4076
4751
  e.preventDefault();
4077
4752
  e.stopPropagation();
4078
- const step = e.shiftKey ? 50 : 10;
4079
- let currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
4080
- let currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
4081
- const computedStyle = window.getComputedStyle(this.transcriptWindow);
4082
- if (computedStyle.transform !== "none") {
4083
- const rect = this.transcriptWindow.getBoundingClientRect();
4084
- currentLeft = rect.left;
4085
- currentTop = rect.top;
4086
- this.transcriptWindow.style.transform = "none";
4087
- this.transcriptWindow.style.left = `${currentLeft}px`;
4088
- this.transcriptWindow.style.top = `${currentTop}px`;
4089
- }
4090
- let newX = currentLeft;
4091
- let newY = currentTop;
4092
- switch (e.key) {
4093
- case "ArrowLeft":
4094
- newX -= step;
4095
- break;
4096
- case "ArrowRight":
4097
- newX += step;
4098
- break;
4099
- case "ArrowUp":
4100
- newY -= step;
4101
- break;
4102
- case "ArrowDown":
4103
- newY += step;
4104
- break;
4753
+ if (this.draggableResizable) {
4754
+ if (this.draggableResizable.pointerResizeMode) {
4755
+ this.draggableResizable.disablePointerResizeMode();
4756
+ }
4757
+ this.draggableResizable.manuallyPositioned = false;
4758
+ this.positionTranscript();
4759
+ this.updateResizeOptionState();
4760
+ this.announceLive(i18n.t("transcript.positionReset"));
4105
4761
  }
4106
- this.transcriptWindow.style.left = `${newX}px`;
4107
- this.transcriptWindow.style.top = `${newY}px`;
4108
4762
  return;
4109
4763
  }
4110
- if (e.key === "Home") {
4764
+ if (key === "r") {
4765
+ if (alreadyPrevented) {
4766
+ return;
4767
+ }
4111
4768
  e.preventDefault();
4112
4769
  e.stopPropagation();
4113
- this.resetPosition();
4770
+ const enabled = this.toggleResizeMode();
4771
+ if (enabled) {
4772
+ this.transcriptWindow.focus();
4773
+ }
4114
4774
  return;
4115
4775
  }
4116
- if (e.key === "Escape") {
4776
+ if (key === "escape") {
4117
4777
  e.preventDefault();
4118
4778
  e.stopPropagation();
4779
+ if (this.draggableResizable && this.draggableResizable.pointerResizeMode) {
4780
+ this.draggableResizable.disablePointerResizeMode();
4781
+ return;
4782
+ }
4119
4783
  if (this.styleDialogVisible) {
4120
4784
  this.hideStyleDialog();
4121
- } else if (this.keyboardDragMode) {
4122
- this.disableKeyboardDragMode();
4785
+ } else if (this.draggableResizable && this.draggableResizable.keyboardDragMode) {
4786
+ this.draggableResizable.disableKeyboardDragMode();
4787
+ this.announceLive(i18n.t("transcript.dragModeDisabled"));
4123
4788
  } else if (this.settingsMenuVisible) {
4124
4789
  this.hideSettingsMenu();
4125
4790
  } else {
4126
- this.hideTranscript();
4791
+ this.hideTranscript({ focusButton: true });
4127
4792
  }
4128
4793
  return;
4129
4794
  }
4130
4795
  };
4131
- this.transcriptHeader.addEventListener("mousedown", this.handlers.mousedown);
4132
- document.addEventListener("mousemove", this.handlers.mousemove);
4133
- document.addEventListener("mouseup", this.handlers.mouseup);
4134
- this.transcriptHeader.addEventListener("touchstart", this.handlers.touchstart);
4135
- document.addEventListener("touchmove", this.handlers.touchmove);
4136
- document.addEventListener("touchend", this.handlers.touchend);
4137
- this.transcriptHeader.addEventListener("keydown", this.handlers.keydown);
4138
- }
4139
- /**
4140
- * Start dragging
4141
- */
4142
- startDragging(clientX, clientY) {
4143
- const rect = this.transcriptWindow.getBoundingClientRect();
4144
- const containerRect = this.player.container.getBoundingClientRect();
4145
- const relativeLeft = rect.left - containerRect.left;
4146
- const relativeTop = rect.top - containerRect.top;
4147
- const computedStyle = window.getComputedStyle(this.transcriptWindow);
4148
- if (computedStyle.transform !== "none") {
4149
- this.transcriptWindow.style.transform = "none";
4150
- this.transcriptWindow.style.left = `${relativeLeft}px`;
4151
- this.transcriptWindow.style.top = `${relativeTop}px`;
4152
- }
4153
- this.dragOffsetX = clientX - rect.left;
4154
- this.dragOffsetY = clientY - rect.top;
4155
- this.isDragging = true;
4156
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-dragging`);
4157
- document.body.style.cursor = "grabbing";
4158
- document.body.style.userSelect = "none";
4159
- }
4160
- /**
4161
- * Perform drag
4162
- */
4163
- drag(clientX, clientY) {
4164
- if (!this.isDragging) return;
4165
- const newViewportX = clientX - this.dragOffsetX;
4166
- const newViewportY = clientY - this.dragOffsetY;
4167
- const containerRect = this.player.container.getBoundingClientRect();
4168
- const newX = newViewportX - containerRect.left;
4169
- const newY = newViewportY - containerRect.top;
4170
- this.transcriptWindow.style.left = `${newX}px`;
4171
- this.transcriptWindow.style.top = `${newY}px`;
4172
- }
4173
- /**
4174
- * Stop dragging
4175
- */
4176
- stopDragging() {
4177
- this.isDragging = false;
4178
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-dragging`);
4179
- document.body.style.cursor = "";
4180
- document.body.style.userSelect = "";
4181
- }
4182
- /**
4183
- * Set window position with boundary constraints
4184
- */
4185
- setPosition(x, y) {
4186
- const rect = this.transcriptWindow.getBoundingClientRect();
4187
- const viewportWidth = document.documentElement.clientWidth;
4188
- const viewportHeight = document.documentElement.clientHeight;
4189
- const minVisible = 100;
4190
- const minX = -(rect.width - minVisible);
4191
- const minY = -(rect.height - minVisible);
4192
- const maxX = viewportWidth - minVisible;
4193
- const maxY = viewportHeight - minVisible;
4194
- x = Math.max(minX, Math.min(x, maxX));
4195
- y = Math.max(minY, Math.min(y, maxY));
4196
- this.transcriptWindow.style.left = `${x}px`;
4197
- this.transcriptWindow.style.top = `${y}px`;
4198
- this.transcriptWindow.style.transform = "none";
4199
- }
4200
- /**
4201
- * Reset position to center
4202
- */
4203
- resetPosition() {
4204
- this.transcriptWindow.style.left = "50%";
4205
- this.transcriptWindow.style.top = "50%";
4206
- this.transcriptWindow.style.transform = "translate(-50%, -50%)";
4796
+ this.transcriptWindow.addEventListener("keydown", this.customKeyHandler);
4207
4797
  }
4208
4798
  /**
4209
4799
  * Toggle keyboard drag mode
4210
4800
  */
4211
4801
  toggleKeyboardDragMode() {
4212
- if (this.keyboardDragMode) {
4213
- this.disableKeyboardDragMode();
4214
- } else {
4215
- this.enableKeyboardDragMode();
4216
- }
4217
- }
4218
- /**
4219
- * Enable keyboard drag mode
4220
- */
4221
- enableKeyboardDragMode() {
4222
- this.keyboardDragMode = true;
4223
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
4224
- if (this.settingsButton) {
4225
- this.settingsButton.setAttribute("aria-label", "Keyboard drag mode active. Use arrow keys to move window. Press D or Escape to exit.");
4226
- }
4227
- const indicator = DOMUtils.createElement("div", {
4228
- className: `${this.player.options.classPrefix}-transcript-drag-indicator`,
4229
- textContent: i18n.t("transcript.keyboardDragActive")
4230
- });
4231
- this.transcriptHeader.appendChild(indicator);
4232
- if (this.settingsMenuVisible) {
4233
- this.hideSettingsMenu();
4234
- }
4235
- this.transcriptHeader.focus();
4236
- }
4237
- /**
4238
- * Disable keyboard drag mode
4239
- */
4240
- disableKeyboardDragMode() {
4241
- this.keyboardDragMode = false;
4242
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-keyboard-drag`);
4243
- if (this.settingsButton) {
4244
- this.settingsButton.setAttribute("aria-label", "Transcript settings. Press Enter to open menu, or D to enable drag mode");
4245
- }
4246
- const indicator = this.transcriptHeader.querySelector(`.${this.player.options.classPrefix}-transcript-drag-indicator`);
4247
- if (indicator) {
4248
- indicator.remove();
4249
- }
4250
- if (this.settingsButton) {
4251
- this.settingsButton.focus();
4802
+ if (this.draggableResizable) {
4803
+ const wasEnabled = this.draggableResizable.keyboardDragMode;
4804
+ this.draggableResizable.toggleKeyboardDragMode();
4805
+ const isEnabled = this.draggableResizable.keyboardDragMode;
4806
+ if (!wasEnabled && isEnabled) {
4807
+ this.enableMoveMode();
4808
+ }
4809
+ if (this.settingsMenuVisible) {
4810
+ this.hideSettingsMenu();
4811
+ }
4812
+ this.transcriptWindow.focus();
4252
4813
  }
4253
4814
  }
4254
4815
  /**
@@ -4278,6 +4839,16 @@ var TranscriptManager = class {
4278
4839
  if (this.settingsMenu) {
4279
4840
  this.settingsMenu.style.display = "block";
4280
4841
  this.settingsMenuVisible = true;
4842
+ if (this.settingsButton) {
4843
+ this.settingsButton.setAttribute("aria-expanded", "true");
4844
+ }
4845
+ this.updateResizeOptionState();
4846
+ setTimeout(() => {
4847
+ const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
4848
+ if (firstItem) {
4849
+ firstItem.focus();
4850
+ }
4851
+ }, 0);
4281
4852
  return;
4282
4853
  }
4283
4854
  this.settingsMenu = DOMUtils.createElement("div", {
@@ -4325,19 +4896,35 @@ var TranscriptManager = class {
4325
4896
  className: `${this.player.options.classPrefix}-transcript-settings-item`,
4326
4897
  attributes: {
4327
4898
  "type": "button",
4328
- "aria-label": i18n.t("transcript.resizeWindow")
4899
+ "aria-label": i18n.t("transcript.resizeWindow"),
4900
+ "aria-pressed": "false"
4329
4901
  }
4330
4902
  });
4331
4903
  const resizeIcon = createIconElement("resize");
4332
4904
  const resizeText = DOMUtils.createElement("span", {
4905
+ className: `${this.player.options.classPrefix}-transcript-settings-text`,
4333
4906
  textContent: i18n.t("transcript.resizeWindow")
4334
4907
  });
4335
4908
  resizeOption.appendChild(resizeIcon);
4336
4909
  resizeOption.appendChild(resizeText);
4337
- resizeOption.addEventListener("click", () => {
4338
- this.toggleResizeMode();
4339
- this.hideSettingsMenu();
4910
+ resizeOption.addEventListener("click", (event) => {
4911
+ event.preventDefault();
4912
+ event.stopPropagation();
4913
+ const enabled = this.toggleResizeMode({ focus: false });
4914
+ if (enabled) {
4915
+ this.hideSettingsMenu({ focusButton: false });
4916
+ this.setManagedTimeout(() => {
4917
+ if (this.transcriptWindow) {
4918
+ this.transcriptWindow.focus();
4919
+ }
4920
+ }, 20);
4921
+ } else {
4922
+ this.hideSettingsMenu({ focusButton: true });
4923
+ }
4340
4924
  });
4925
+ this.resizeOptionButton = resizeOption;
4926
+ this.resizeOptionText = resizeText;
4927
+ this.updateResizeOptionState();
4341
4928
  const closeOption = DOMUtils.createElement("button", {
4342
4929
  className: `${this.player.options.classPrefix}-transcript-settings-item`,
4343
4930
  attributes: {
@@ -4368,6 +4955,7 @@ var TranscriptManager = class {
4368
4955
  if (this.settingsButton) {
4369
4956
  this.settingsButton.setAttribute("aria-expanded", "true");
4370
4957
  }
4958
+ this.updateResizeOptionState();
4371
4959
  setTimeout(() => {
4372
4960
  const firstItem = this.settingsMenu.querySelector(`.${this.player.options.classPrefix}-transcript-settings-item`);
4373
4961
  if (firstItem) {
@@ -4378,14 +4966,16 @@ var TranscriptManager = class {
4378
4966
  /**
4379
4967
  * Hide settings menu
4380
4968
  */
4381
- hideSettingsMenu() {
4969
+ hideSettingsMenu({ focusButton = true } = {}) {
4382
4970
  if (this.settingsMenu) {
4383
4971
  this.settingsMenu.style.display = "none";
4384
4972
  this.settingsMenuVisible = false;
4385
4973
  this.settingsMenuJustOpened = false;
4386
4974
  if (this.settingsButton) {
4387
4975
  this.settingsButton.setAttribute("aria-expanded", "false");
4388
- this.settingsButton.focus();
4976
+ if (focusButton) {
4977
+ this.settingsButton.focus();
4978
+ }
4389
4979
  }
4390
4980
  }
4391
4981
  }
@@ -4393,6 +4983,7 @@ var TranscriptManager = class {
4393
4983
  * Enable move mode (gives visual feedback)
4394
4984
  */
4395
4985
  enableMoveMode() {
4986
+ this.hideResizeModeIndicator();
4396
4987
  this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-move-mode`);
4397
4988
  const tooltip = DOMUtils.createElement("div", {
4398
4989
  className: `${this.player.options.classPrefix}-transcript-move-tooltip`,
@@ -4409,155 +5000,64 @@ var TranscriptManager = class {
4409
5000
  /**
4410
5001
  * Toggle resize mode
4411
5002
  */
4412
- toggleResizeMode() {
4413
- this.resizeEnabled = !this.resizeEnabled;
4414
- if (this.resizeEnabled) {
4415
- this.enableResizeHandles();
4416
- } else {
4417
- this.disableResizeHandles();
5003
+ toggleResizeMode({ focus = true } = {}) {
5004
+ if (!this.draggableResizable) {
5005
+ return false;
4418
5006
  }
4419
- }
4420
- /**
4421
- * Enable resize handles
4422
- */
4423
- enableResizeHandles() {
4424
- if (!this.transcriptWindow) return;
4425
- const directions = ["n", "s", "e", "w", "ne", "nw", "se", "sw"];
4426
- directions.forEach((direction) => {
4427
- const handle = DOMUtils.createElement("div", {
4428
- className: `${this.player.options.classPrefix}-transcript-resize-handle ${this.player.options.classPrefix}-transcript-resize-${direction}`,
4429
- attributes: {
4430
- "data-direction": direction
4431
- }
4432
- });
4433
- handle.addEventListener("mousedown", (e) => this.startResize(e, direction));
4434
- handle.addEventListener("touchstart", (e) => this.startResize(e.touches[0], direction));
4435
- this.transcriptWindow.appendChild(handle);
4436
- });
4437
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizable`);
4438
- this.handlers.resizeMove = (e) => {
4439
- if (this.isResizing) {
4440
- this.performResize(e.clientX, e.clientY);
4441
- }
4442
- };
4443
- this.handlers.resizeEnd = () => {
4444
- if (this.isResizing) {
4445
- this.stopResize();
4446
- }
4447
- };
4448
- this.handlers.resizeTouchMove = (e) => {
4449
- if (this.isResizing) {
4450
- this.performResize(e.touches[0].clientX, e.touches[0].clientY);
4451
- e.preventDefault();
4452
- }
4453
- };
4454
- document.addEventListener("mousemove", this.handlers.resizeMove);
4455
- document.addEventListener("mouseup", this.handlers.resizeEnd);
4456
- document.addEventListener("touchmove", this.handlers.resizeTouchMove);
4457
- document.addEventListener("touchend", this.handlers.resizeEnd);
4458
- }
4459
- /**
4460
- * Disable resize handles
4461
- */
4462
- disableResizeHandles() {
4463
- if (!this.transcriptWindow) return;
4464
- const handles = this.transcriptWindow.querySelectorAll(`.${this.player.options.classPrefix}-transcript-resize-handle`);
4465
- handles.forEach((handle) => handle.remove());
4466
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizable`);
4467
- if (this.handlers.resizeMove) {
4468
- document.removeEventListener("mousemove", this.handlers.resizeMove);
5007
+ if (this.draggableResizable.pointerResizeMode) {
5008
+ this.draggableResizable.disablePointerResizeMode({ focus });
5009
+ return false;
4469
5010
  }
4470
- if (this.handlers.resizeEnd) {
4471
- document.removeEventListener("mouseup", this.handlers.resizeEnd);
5011
+ this.draggableResizable.enablePointerResizeMode({ focus });
5012
+ return true;
5013
+ }
5014
+ updateResizeOptionState() {
5015
+ if (!this.resizeOptionButton) {
5016
+ return;
4472
5017
  }
4473
- if (this.handlers.resizeTouchMove) {
4474
- document.removeEventListener("touchmove", this.handlers.resizeTouchMove);
5018
+ const isEnabled = !!(this.draggableResizable && this.draggableResizable.pointerResizeMode);
5019
+ const label = isEnabled ? i18n.t("transcript.disableResizeWindow") || "Disable Resize Mode" : i18n.t("transcript.resizeWindow");
5020
+ this.resizeOptionButton.setAttribute("aria-pressed", isEnabled ? "true" : "false");
5021
+ this.resizeOptionButton.setAttribute("aria-label", label);
5022
+ this.resizeOptionButton.setAttribute("title", label);
5023
+ if (this.resizeOptionText) {
5024
+ this.resizeOptionText.textContent = label;
4475
5025
  }
4476
- document.removeEventListener("touchend", this.handlers.resizeEnd);
4477
- }
4478
- /**
4479
- * Start resizing
4480
- */
4481
- startResize(e, direction) {
4482
- e.stopPropagation();
4483
- e.preventDefault();
4484
- this.isResizing = true;
4485
- this.resizeDirection = direction;
4486
- this.resizeStartX = e.clientX;
4487
- this.resizeStartY = e.clientY;
4488
- const rect = this.transcriptWindow.getBoundingClientRect();
4489
- this.resizeStartWidth = rect.width;
4490
- this.resizeStartHeight = rect.height;
4491
- this.transcriptWindow.classList.add(`${this.player.options.classPrefix}-transcript-resizing`);
4492
- document.body.style.cursor = this.getResizeCursor(direction);
4493
- document.body.style.userSelect = "none";
4494
5026
  }
4495
- /**
4496
- * Perform resize
4497
- */
4498
- performResize(clientX, clientY) {
4499
- if (!this.isResizing) return;
4500
- const deltaX = clientX - this.resizeStartX;
4501
- const deltaY = clientY - this.resizeStartY;
4502
- let newWidth = this.resizeStartWidth;
4503
- let newHeight = this.resizeStartHeight;
4504
- const direction = this.resizeDirection;
4505
- if (direction.includes("e")) {
4506
- newWidth = this.resizeStartWidth + deltaX;
4507
- }
4508
- if (direction.includes("w")) {
4509
- newWidth = this.resizeStartWidth - deltaX;
4510
- }
4511
- if (direction.includes("s")) {
4512
- newHeight = this.resizeStartHeight + deltaY;
4513
- }
4514
- if (direction.includes("n")) {
4515
- newHeight = this.resizeStartHeight - deltaY;
4516
- }
4517
- const minWidth = 300;
4518
- const minHeight = 200;
4519
- const maxWidth = window.innerWidth - 40;
4520
- const maxHeight = window.innerHeight - 40;
4521
- newWidth = Math.max(minWidth, Math.min(newWidth, maxWidth));
4522
- newHeight = Math.max(minHeight, Math.min(newHeight, maxHeight));
4523
- this.transcriptWindow.style.width = `${newWidth}px`;
4524
- this.transcriptWindow.style.height = `${newHeight}px`;
4525
- this.transcriptWindow.style.maxWidth = `${newWidth}px`;
4526
- this.transcriptWindow.style.maxHeight = `${newHeight}px`;
4527
- if (direction.includes("w")) {
4528
- const currentLeft = parseFloat(this.transcriptWindow.style.left) || 0;
4529
- this.transcriptWindow.style.left = `${currentLeft + (this.resizeStartWidth - newWidth)}px`;
4530
- }
4531
- if (direction.includes("n")) {
4532
- const currentTop = parseFloat(this.transcriptWindow.style.top) || 0;
4533
- this.transcriptWindow.style.top = `${currentTop + (this.resizeStartHeight - newHeight)}px`;
5027
+ showResizeModeIndicator() {
5028
+ if (!this.transcriptHeader) {
5029
+ return;
5030
+ }
5031
+ this.hideResizeModeIndicator();
5032
+ const indicator = DOMUtils.createElement("div", {
5033
+ className: `${this.player.options.classPrefix}-transcript-resize-tooltip`,
5034
+ textContent: i18n.t("transcript.resizeModeHint") || "Resize handles enabled. Drag edges or corners to adjust. Press Esc or R to exit."
5035
+ });
5036
+ this.transcriptHeader.appendChild(indicator);
5037
+ this.resizeModeIndicator = indicator;
5038
+ this.resizeModeIndicatorTimeout = this.setManagedTimeout(() => {
5039
+ this.hideResizeModeIndicator();
5040
+ }, 3e3);
5041
+ }
5042
+ hideResizeModeIndicator() {
5043
+ if (this.resizeModeIndicatorTimeout) {
5044
+ this.clearManagedTimeout(this.resizeModeIndicatorTimeout);
5045
+ this.resizeModeIndicatorTimeout = null;
5046
+ }
5047
+ if (this.resizeModeIndicator && this.resizeModeIndicator.parentNode) {
5048
+ this.resizeModeIndicator.remove();
5049
+ }
5050
+ this.resizeModeIndicator = null;
5051
+ }
5052
+ onPointerResizeModeChange(enabled) {
5053
+ this.updateResizeOptionState();
5054
+ if (enabled) {
5055
+ this.showResizeModeIndicator();
5056
+ this.announceLive(i18n.t("transcript.resizeModeEnabled"));
5057
+ } else {
5058
+ this.hideResizeModeIndicator();
5059
+ this.announceLive(i18n.t("transcript.resizeModeDisabled"));
4534
5060
  }
4535
- }
4536
- /**
4537
- * Stop resizing
4538
- */
4539
- stopResize() {
4540
- this.isResizing = false;
4541
- this.resizeDirection = null;
4542
- this.transcriptWindow.classList.remove(`${this.player.options.classPrefix}-transcript-resizing`);
4543
- document.body.style.cursor = "";
4544
- document.body.style.userSelect = "";
4545
- }
4546
- /**
4547
- * Get cursor style for resize direction
4548
- */
4549
- getResizeCursor(direction) {
4550
- const cursors = {
4551
- "n": "ns-resize",
4552
- "s": "ns-resize",
4553
- "e": "ew-resize",
4554
- "w": "ew-resize",
4555
- "ne": "nesw-resize",
4556
- "nw": "nwse-resize",
4557
- "se": "nwse-resize",
4558
- "sw": "nesw-resize"
4559
- };
4560
- return cursors[direction] || "default";
4561
5061
  }
4562
5062
  /**
4563
5063
  * Show style dialog
@@ -4819,26 +5319,22 @@ var TranscriptManager = class {
4819
5319
  * Cleanup
4820
5320
  */
4821
5321
  destroy() {
4822
- if (this.resizeEnabled) {
4823
- this.disableResizeHandles();
5322
+ this.hideResizeModeIndicator();
5323
+ if (this.draggableResizable) {
5324
+ if (this.draggableResizable.pointerResizeMode) {
5325
+ this.draggableResizable.disablePointerResizeMode();
5326
+ this.updateResizeOptionState();
5327
+ }
5328
+ this.draggableResizable.destroy();
5329
+ this.draggableResizable = null;
4824
5330
  }
4825
- if (this.keyboardDragMode) {
4826
- this.disableKeyboardDragMode();
5331
+ if (this.transcriptWindow && this.customKeyHandler) {
5332
+ this.transcriptWindow.removeEventListener("keydown", this.customKeyHandler);
5333
+ this.customKeyHandler = null;
4827
5334
  }
4828
5335
  if (this.handlers.timeupdate) {
4829
5336
  this.player.off("timeupdate", this.handlers.timeupdate);
4830
5337
  }
4831
- if (this.transcriptHeader) {
4832
- if (this.handlers.mousedown) {
4833
- this.transcriptHeader.removeEventListener("mousedown", this.handlers.mousedown);
4834
- }
4835
- if (this.handlers.touchstart) {
4836
- this.transcriptHeader.removeEventListener("touchstart", this.handlers.touchstart);
4837
- }
4838
- if (this.handlers.keydown) {
4839
- this.transcriptHeader.removeEventListener("keydown", this.handlers.keydown);
4840
- }
4841
- }
4842
5338
  if (this.settingsButton) {
4843
5339
  if (this.handlers.settingsClick) {
4844
5340
  this.settingsButton.removeEventListener("click", this.handlers.settingsClick);
@@ -4850,18 +5346,6 @@ var TranscriptManager = class {
4850
5346
  if (this.styleDialog && this.handlers.styleDialogKeydown) {
4851
5347
  this.styleDialog.removeEventListener("keydown", this.handlers.styleDialogKeydown);
4852
5348
  }
4853
- if (this.handlers.mousemove) {
4854
- document.removeEventListener("mousemove", this.handlers.mousemove);
4855
- }
4856
- if (this.handlers.mouseup) {
4857
- document.removeEventListener("mouseup", this.handlers.mouseup);
4858
- }
4859
- if (this.handlers.touchmove) {
4860
- document.removeEventListener("touchmove", this.handlers.touchmove);
4861
- }
4862
- if (this.handlers.touchend) {
4863
- document.removeEventListener("touchend", this.handlers.touchend);
4864
- }
4865
5349
  if (this.handlers.documentClick) {
4866
5350
  document.removeEventListener("click", this.handlers.documentClick);
4867
5351
  }
@@ -4880,6 +5364,14 @@ var TranscriptManager = class {
4880
5364
  this.transcriptEntries = [];
4881
5365
  this.settingsMenu = null;
4882
5366
  this.styleDialog = null;
5367
+ this.transcriptResizeHandles = [];
5368
+ this.resizeOptionButton = null;
5369
+ this.resizeOptionText = null;
5370
+ this.liveRegion = null;
5371
+ }
5372
+ announceLive(message) {
5373
+ if (!this.liveRegion) return;
5374
+ this.liveRegion.textContent = message || "";
4883
5375
  }
4884
5376
  };
4885
5377
 
@@ -5705,6 +6197,7 @@ var Player = class _Player extends EventEmitter {
5705
6197
  this.audioDescriptionSourceElement = null;
5706
6198
  this.originalAudioDescriptionSource = null;
5707
6199
  this.audioDescriptionCaptionTracks = [];
6200
+ this._audioDescriptionDesiredState = false;
5708
6201
  this._textTracksCache = null;
5709
6202
  this._textTracksDirty = true;
5710
6203
  this._sourceElementsCache = null;
@@ -5822,7 +6315,6 @@ var Player = class _Player extends EventEmitter {
5822
6315
  this.element.style.height = "100%";
5823
6316
  if (this.element.tagName === "VIDEO" && this.options.playsInline) {
5824
6317
  this.element.setAttribute("playsinline", "");
5825
- this.element.setAttribute("webkit-playsinline", "");
5826
6318
  this.element.playsInline = true;
5827
6319
  }
5828
6320
  if (this.options.width) {
@@ -5845,6 +6337,14 @@ var Player = class _Player extends EventEmitter {
5845
6337
  this.toggle();
5846
6338
  }
5847
6339
  });
6340
+ this.on("play", () => {
6341
+ this.hidePosterOverlay();
6342
+ });
6343
+ this.on("timeupdate", () => {
6344
+ if (this.state.currentTime > 0) {
6345
+ this.hidePosterOverlay();
6346
+ }
6347
+ });
5848
6348
  }
5849
6349
  createPlayButtonOverlay() {
5850
6350
  this.playButtonOverlay = createPlayOverlay();
@@ -6011,6 +6511,24 @@ var Player = class _Player extends EventEmitter {
6011
6511
  findTrackElement(track) {
6012
6512
  return this.trackElements.find((el) => el.track === track);
6013
6513
  }
6514
+ showPosterOverlay() {
6515
+ if (!this.videoWrapper || this.element.tagName !== "VIDEO") {
6516
+ return;
6517
+ }
6518
+ const poster = this.element.getAttribute("poster") || this.element.poster || this.options.poster;
6519
+ if (!poster) {
6520
+ return;
6521
+ }
6522
+ this.videoWrapper.style.setProperty("--vidply-poster-image", `url("${poster}")`);
6523
+ this.videoWrapper.classList.add("vidply-forced-poster");
6524
+ }
6525
+ hidePosterOverlay() {
6526
+ if (!this.videoWrapper) {
6527
+ return;
6528
+ }
6529
+ this.videoWrapper.classList.remove("vidply-forced-poster");
6530
+ this.videoWrapper.style.removeProperty("--vidply-poster-image");
6531
+ }
6014
6532
  /**
6015
6533
  * Set a managed timeout that will be cleaned up on destroy
6016
6534
  * @param {Function} callback - Callback function
@@ -6327,6 +6845,10 @@ var Player = class _Player extends EventEmitter {
6327
6845
  }
6328
6846
  const currentTime = this.state.currentTime;
6329
6847
  const wasPlaying = this.state.playing;
6848
+ const shouldKeepPoster = !wasPlaying && currentTime === 0;
6849
+ if (shouldKeepPoster) {
6850
+ this.showPosterOverlay();
6851
+ }
6330
6852
  let swappedTracksForTranscript = [];
6331
6853
  if (this.audioDescriptionSourceElement) {
6332
6854
  const currentSrc = this.element.currentSrc || this.element.src;
@@ -6509,8 +7031,15 @@ var Player = class _Player extends EventEmitter {
6509
7031
  if (sourceInfo.descSrc) {
6510
7032
  newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
6511
7033
  }
6512
- this.element.appendChild(newSource);
7034
+ const firstTrack = this.element.querySelector("track");
7035
+ if (firstTrack) {
7036
+ this.element.insertBefore(newSource, firstTrack);
7037
+ } else {
7038
+ this.element.appendChild(newSource);
7039
+ }
6513
7040
  });
7041
+ this._sourceElementsDirty = true;
7042
+ this._sourceElementsCache = null;
6514
7043
  this.element.load();
6515
7044
  await new Promise((resolve) => {
6516
7045
  const onLoadedMetadata = () => {
@@ -6520,18 +7049,18 @@ var Player = class _Player extends EventEmitter {
6520
7049
  this.element.addEventListener("loadedmetadata", onLoadedMetadata);
6521
7050
  });
6522
7051
  await new Promise((resolve) => setTimeout(resolve, 300));
6523
- if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
6524
- if (this.element.readyState >= 1) {
6525
- this.element.currentTime = 1e-3;
6526
- setTimeout(() => {
6527
- this.element.currentTime = 0;
6528
- }, 10);
6529
- }
7052
+ if (currentTime > 0) {
7053
+ this.seek(currentTime);
6530
7054
  }
6531
- this.seek(currentTime);
6532
7055
  if (wasPlaying) {
6533
7056
  this.play();
6534
7057
  }
7058
+ if (!shouldKeepPoster) {
7059
+ this.hidePosterOverlay();
7060
+ }
7061
+ if (!this._audioDescriptionDesiredState) {
7062
+ return;
7063
+ }
6535
7064
  this.state.audioDescriptionEnabled = true;
6536
7065
  this.emit("audiodescriptionenabled");
6537
7066
  } else {
@@ -6711,7 +7240,9 @@ var Player = class _Player extends EventEmitter {
6711
7240
  }, 10);
6712
7241
  }
6713
7242
  }
6714
- this.seek(currentTime);
7243
+ if (currentTime > 0) {
7244
+ this.seek(currentTime);
7245
+ }
6715
7246
  if (wasPlaying) {
6716
7247
  this.play();
6717
7248
  }
@@ -6874,6 +7405,12 @@ var Player = class _Player extends EventEmitter {
6874
7405
  }, 800);
6875
7406
  }
6876
7407
  }
7408
+ if (!shouldKeepPoster) {
7409
+ this.hidePosterOverlay();
7410
+ }
7411
+ if (!this._audioDescriptionDesiredState) {
7412
+ return;
7413
+ }
6877
7414
  this.state.audioDescriptionEnabled = true;
6878
7415
  this.emit("audiodescriptionenabled");
6879
7416
  }
@@ -6933,24 +7470,40 @@ var Player = class _Player extends EventEmitter {
6933
7470
  if (sourceInfo.descSrc) {
6934
7471
  newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
6935
7472
  }
6936
- this.element.appendChild(newSource);
7473
+ const firstTrack = this.element.querySelector("track");
7474
+ if (firstTrack) {
7475
+ this.element.insertBefore(newSource, firstTrack);
7476
+ } else {
7477
+ this.element.appendChild(newSource);
7478
+ }
6937
7479
  });
7480
+ this._sourceElementsDirty = true;
7481
+ this._sourceElementsCache = null;
6938
7482
  this.element.load();
6939
7483
  } else {
6940
7484
  const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;
6941
7485
  this.element.src = originalSrcToUse;
6942
7486
  this.element.load();
6943
7487
  }
6944
- await new Promise((resolve) => {
6945
- const onLoadedMetadata = () => {
6946
- this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
6947
- resolve();
6948
- };
6949
- this.element.addEventListener("loadedmetadata", onLoadedMetadata);
6950
- });
6951
- this.seek(currentTime);
6952
- if (wasPlaying) {
6953
- this.play();
7488
+ if (currentTime > 0 || wasPlaying) {
7489
+ await new Promise((resolve) => {
7490
+ const onLoadedMetadata = () => {
7491
+ this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
7492
+ resolve();
7493
+ };
7494
+ this.element.addEventListener("loadedmetadata", onLoadedMetadata);
7495
+ });
7496
+ if (currentTime > 0) {
7497
+ this.seek(currentTime);
7498
+ }
7499
+ if (wasPlaying) {
7500
+ this.play();
7501
+ }
7502
+ }
7503
+ if (!wasPlaying && currentTime === 0) {
7504
+ this.showPosterOverlay();
7505
+ } else {
7506
+ this.hidePosterOverlay();
6954
7507
  }
6955
7508
  if (this.transcriptManager && this.transcriptManager.isVisible) {
6956
7509
  this.setManagedTimeout(() => {
@@ -6959,6 +7512,9 @@ var Player = class _Player extends EventEmitter {
6959
7512
  }
6960
7513
  }, 500);
6961
7514
  }
7515
+ if (this._audioDescriptionDesiredState) {
7516
+ return;
7517
+ }
6962
7518
  this.state.audioDescriptionEnabled = false;
6963
7519
  this.emit("audiodescriptiondisabled");
6964
7520
  }
@@ -6967,9 +7523,11 @@ var Player = class _Player extends EventEmitter {
6967
7523
  const hasAudioDescriptionSrc = this.audioDescriptionSrc || this.sourceElements.some((el) => el.getAttribute("data-desc-src"));
6968
7524
  if (descriptionTrack && hasAudioDescriptionSrc) {
6969
7525
  if (this.state.audioDescriptionEnabled) {
7526
+ this._audioDescriptionDesiredState = false;
6970
7527
  descriptionTrack.mode = "hidden";
6971
7528
  await this.disableAudioDescription();
6972
7529
  } else {
7530
+ this._audioDescriptionDesiredState = true;
6973
7531
  await this.enableAudioDescription();
6974
7532
  const enableDescriptionTrack = () => {
6975
7533
  this.invalidateTrackCache();
@@ -6997,18 +7555,22 @@ var Player = class _Player extends EventEmitter {
6997
7555
  }
6998
7556
  } else if (descriptionTrack) {
6999
7557
  if (descriptionTrack.mode === "showing") {
7558
+ this._audioDescriptionDesiredState = false;
7000
7559
  descriptionTrack.mode = "hidden";
7001
7560
  this.state.audioDescriptionEnabled = false;
7002
7561
  this.emit("audiodescriptiondisabled");
7003
7562
  } else {
7563
+ this._audioDescriptionDesiredState = true;
7004
7564
  descriptionTrack.mode = "showing";
7005
7565
  this.state.audioDescriptionEnabled = true;
7006
7566
  this.emit("audiodescriptionenabled");
7007
7567
  }
7008
7568
  } else if (hasAudioDescriptionSrc) {
7009
7569
  if (this.state.audioDescriptionEnabled) {
7570
+ this._audioDescriptionDesiredState = false;
7010
7571
  await this.disableAudioDescription();
7011
7572
  } else {
7573
+ this._audioDescriptionDesiredState = true;
7012
7574
  await this.enableAudioDescription();
7013
7575
  }
7014
7576
  }
@@ -7105,177 +7667,22 @@ var Player = class _Player extends EventEmitter {
7105
7667
  }
7106
7668
  setupSignLanguageInteraction() {
7107
7669
  if (!this.signLanguageWrapper) return;
7108
- let isDragging = false;
7109
- let isResizing = false;
7110
- let resizeDirection = null;
7111
- let startX = 0;
7112
- let startY = 0;
7113
- let startLeft = 0;
7114
- let startTop = 0;
7115
- let startWidth = 0;
7116
- let startHeight = 0;
7117
- let dragMode = false;
7118
- let resizeMode = false;
7119
- const onMouseDownVideo = (e) => {
7120
- if (e.target !== this.signLanguageVideo) return;
7121
- e.preventDefault();
7122
- isDragging = true;
7123
- startX = e.clientX;
7124
- startY = e.clientY;
7125
- const rect = this.signLanguageWrapper.getBoundingClientRect();
7126
- startLeft = rect.left;
7127
- startTop = rect.top;
7128
- this.signLanguageWrapper.classList.add("vidply-sign-dragging");
7129
- };
7130
- const onMouseDownHandle = (e) => {
7131
- if (!e.target.classList.contains("vidply-sign-resize-handle")) return;
7132
- e.preventDefault();
7133
- e.stopPropagation();
7134
- isResizing = true;
7135
- resizeDirection = e.target.getAttribute("data-direction");
7136
- startX = e.clientX;
7137
- startY = e.clientY;
7138
- const rect = this.signLanguageWrapper.getBoundingClientRect();
7139
- startLeft = rect.left;
7140
- startTop = rect.top;
7141
- startWidth = rect.width;
7142
- startHeight = rect.height;
7143
- this.signLanguageWrapper.classList.add("vidply-sign-resizing");
7144
- };
7145
- const onMouseMove = (e) => {
7146
- if (isDragging) {
7147
- const deltaX = e.clientX - startX;
7148
- const deltaY = e.clientY - startY;
7149
- const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
7150
- const containerRect = this.container.getBoundingClientRect();
7151
- const wrapperRect = this.signLanguageWrapper.getBoundingClientRect();
7152
- const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
7153
- const videoWrapperTop = videoWrapperRect.top - containerRect.top;
7154
- let newLeft = startLeft + deltaX - containerRect.left;
7155
- let newTop = startTop + deltaY - containerRect.top;
7156
- const controlsHeight = 95;
7157
- newLeft = Math.max(videoWrapperLeft, Math.min(newLeft, videoWrapperLeft + videoWrapperRect.width - wrapperRect.width));
7158
- newTop = Math.max(videoWrapperTop, Math.min(newTop, videoWrapperTop + videoWrapperRect.height - wrapperRect.height - controlsHeight));
7159
- this.signLanguageWrapper.style.left = `${newLeft}px`;
7160
- this.signLanguageWrapper.style.top = `${newTop}px`;
7161
- this.signLanguageWrapper.style.right = "auto";
7162
- this.signLanguageWrapper.style.bottom = "auto";
7163
- this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
7164
- } else if (isResizing) {
7165
- const deltaX = e.clientX - startX;
7166
- const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
7167
- const containerRect = this.container.getBoundingClientRect();
7168
- let newWidth = startWidth;
7169
- let newLeft = startLeft - containerRect.left;
7170
- if (resizeDirection.includes("e")) {
7171
- newWidth = Math.max(150, startWidth + deltaX);
7172
- const maxWidth = videoWrapperRect.right - startLeft;
7173
- newWidth = Math.min(newWidth, maxWidth);
7174
- }
7175
- if (resizeDirection.includes("w")) {
7176
- const proposedWidth = Math.max(150, startWidth - deltaX);
7177
- const proposedLeft = startLeft + (startWidth - proposedWidth) - containerRect.left;
7178
- const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
7179
- if (proposedLeft >= videoWrapperLeft) {
7180
- newWidth = proposedWidth;
7181
- newLeft = proposedLeft;
7182
- }
7183
- }
7184
- this.signLanguageWrapper.style.width = `${newWidth}px`;
7185
- this.signLanguageWrapper.style.height = "auto";
7186
- if (resizeDirection.includes("w")) {
7187
- this.signLanguageWrapper.style.left = `${newLeft}px`;
7188
- }
7189
- this.signLanguageWrapper.style.right = "auto";
7190
- this.signLanguageWrapper.style.bottom = "auto";
7191
- this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
7192
- }
7193
- };
7194
- const onMouseUp = () => {
7195
- if (isDragging || isResizing) {
7196
- this.saveSignLanguagePreferences();
7197
- }
7198
- isDragging = false;
7199
- isResizing = false;
7200
- resizeDirection = null;
7201
- this.signLanguageWrapper.classList.remove("vidply-sign-dragging", "vidply-sign-resizing");
7202
- };
7203
- const onKeyDown = (e) => {
7204
- if (e.key === "d" || e.key === "D") {
7205
- dragMode = !dragMode;
7206
- resizeMode = false;
7207
- this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-drag", dragMode);
7208
- this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-resize");
7209
- e.preventDefault();
7210
- return;
7211
- }
7212
- if (e.key === "r" || e.key === "R") {
7213
- resizeMode = !resizeMode;
7214
- dragMode = false;
7215
- this.signLanguageWrapper.classList.toggle("vidply-sign-keyboard-resize", resizeMode);
7216
- this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag");
7217
- e.preventDefault();
7218
- return;
7219
- }
7220
- if (e.key === "Escape") {
7221
- dragMode = false;
7222
- resizeMode = false;
7223
- this.signLanguageWrapper.classList.remove("vidply-sign-keyboard-drag", "vidply-sign-keyboard-resize");
7224
- e.preventDefault();
7225
- return;
7226
- }
7227
- if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
7228
- const step = e.shiftKey ? 10 : 5;
7229
- const rect = this.signLanguageWrapper.getBoundingClientRect();
7230
- const videoWrapperRect = this.videoWrapper.getBoundingClientRect();
7231
- const containerRect = this.container.getBoundingClientRect();
7232
- const videoWrapperLeft = videoWrapperRect.left - containerRect.left;
7233
- const videoWrapperTop = videoWrapperRect.top - containerRect.top;
7234
- if (dragMode) {
7235
- let left = rect.left - containerRect.left;
7236
- let top = rect.top - containerRect.top;
7237
- if (e.key === "ArrowLeft") left -= step;
7238
- if (e.key === "ArrowRight") left += step;
7239
- if (e.key === "ArrowUp") top -= step;
7240
- if (e.key === "ArrowDown") top += step;
7241
- const controlsHeight = 95;
7242
- left = Math.max(videoWrapperLeft, Math.min(left, videoWrapperLeft + videoWrapperRect.width - rect.width));
7243
- top = Math.max(videoWrapperTop, Math.min(top, videoWrapperTop + videoWrapperRect.height - rect.height - controlsHeight));
7244
- this.signLanguageWrapper.style.left = `${left}px`;
7245
- this.signLanguageWrapper.style.top = `${top}px`;
7246
- this.signLanguageWrapper.style.right = "auto";
7247
- this.signLanguageWrapper.style.bottom = "auto";
7248
- this.signLanguageWrapper.classList.remove(...Array.from(this.signLanguageWrapper.classList).filter((c) => c.startsWith("vidply-sign-position-")));
7249
- this.saveSignLanguagePreferences();
7250
- e.preventDefault();
7251
- } else if (resizeMode) {
7252
- let width = rect.width;
7253
- if (e.key === "ArrowLeft") width -= step;
7254
- if (e.key === "ArrowRight") width += step;
7255
- if (e.key === "ArrowUp") width += step;
7256
- if (e.key === "ArrowDown") width -= step;
7257
- width = Math.max(150, width);
7258
- width = Math.min(width, videoWrapperRect.width);
7259
- this.signLanguageWrapper.style.width = `${width}px`;
7260
- this.signLanguageWrapper.style.height = "auto";
7261
- this.saveSignLanguagePreferences();
7262
- e.preventDefault();
7263
- }
7264
- }
7265
- };
7266
- this.signLanguageVideo.addEventListener("mousedown", onMouseDownVideo);
7267
- const handles = this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle");
7268
- handles.forEach((handle) => handle.addEventListener("mousedown", onMouseDownHandle));
7269
- document.addEventListener("mousemove", onMouseMove);
7270
- document.addEventListener("mouseup", onMouseUp);
7271
- this.signLanguageWrapper.addEventListener("keydown", onKeyDown);
7670
+ const resizeHandles = Array.from(this.signLanguageWrapper.querySelectorAll(".vidply-sign-resize-handle"));
7671
+ this.signLanguageDraggable = new DraggableResizable(this.signLanguageWrapper, {
7672
+ dragHandle: this.signLanguageVideo,
7673
+ resizeHandles,
7674
+ constrainToViewport: true,
7675
+ maintainAspectRatio: true,
7676
+ minWidth: 150,
7677
+ minHeight: 100,
7678
+ classPrefix: "vidply-sign",
7679
+ keyboardDragKey: "d",
7680
+ keyboardResizeKey: "r",
7681
+ keyboardStep: 5,
7682
+ keyboardStepLarge: 10
7683
+ });
7272
7684
  this.signLanguageInteractionHandlers = {
7273
- mouseDownVideo: onMouseDownVideo,
7274
- mouseDownHandle: onMouseDownHandle,
7275
- mouseMove: onMouseMove,
7276
- mouseUp: onMouseUp,
7277
- keyDown: onKeyDown,
7278
- handles
7685
+ draggable: this.signLanguageDraggable
7279
7686
  };
7280
7687
  }
7281
7688
  constrainSignLanguagePosition() {
@@ -7342,22 +7749,11 @@ var Player = class _Player extends EventEmitter {
7342
7749
  this.off("ratechange", this.signLanguageHandlers.ratechange);
7343
7750
  this.signLanguageHandlers = null;
7344
7751
  }
7345
- if (this.signLanguageInteractionHandlers) {
7346
- if (this.signLanguageVideo) {
7347
- this.signLanguageVideo.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownVideo);
7348
- }
7349
- if (this.signLanguageInteractionHandlers.handles) {
7350
- this.signLanguageInteractionHandlers.handles.forEach((handle) => {
7351
- handle.removeEventListener("mousedown", this.signLanguageInteractionHandlers.mouseDownHandle);
7352
- });
7353
- }
7354
- document.removeEventListener("mousemove", this.signLanguageInteractionHandlers.mouseMove);
7355
- document.removeEventListener("mouseup", this.signLanguageInteractionHandlers.mouseUp);
7356
- if (this.signLanguageWrapper) {
7357
- this.signLanguageWrapper.removeEventListener("keydown", this.signLanguageInteractionHandlers.keyDown);
7358
- }
7359
- this.signLanguageInteractionHandlers = null;
7752
+ if (this.signLanguageDraggable) {
7753
+ this.signLanguageDraggable.destroy();
7754
+ this.signLanguageDraggable = null;
7360
7755
  }
7756
+ this.signLanguageInteractionHandlers = null;
7361
7757
  if (this.signLanguageWrapper && this.signLanguageWrapper.parentNode) {
7362
7758
  if (this.signLanguageVideo) {
7363
7759
  this.signLanguageVideo.pause();
@@ -7449,7 +7845,9 @@ var Player = class _Player extends EventEmitter {
7449
7845
  this.controlBar.updateControlsForViewport(width);
7450
7846
  }
7451
7847
  if (this.transcriptManager && this.transcriptManager.isVisible) {
7452
- this.transcriptManager.positionTranscript();
7848
+ if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
7849
+ this.transcriptManager.positionTranscript();
7850
+ }
7453
7851
  }
7454
7852
  };
7455
7853
  window.addEventListener("resize", this.resizeHandler);
@@ -7458,7 +7856,9 @@ var Player = class _Player extends EventEmitter {
7458
7856
  this.orientationHandler = (e) => {
7459
7857
  setTimeout(() => {
7460
7858
  if (this.transcriptManager && this.transcriptManager.isVisible) {
7461
- this.transcriptManager.positionTranscript();
7859
+ if (!this.transcriptManager.draggableResizable || !this.transcriptManager.draggableResizable.manuallyPositioned) {
7860
+ this.transcriptManager.positionTranscript();
7861
+ }
7462
7862
  }
7463
7863
  }, 100);
7464
7864
  };