bitmovin-player-ui 4.3.0 → 4.4.0

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.
Files changed (218) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/css/bitmovinplayer-ui.css +1 -1
  3. package/dist/css/bitmovinplayer-ui.css.map +1 -1
  4. package/dist/js/bitmovinplayer-ui.js +1 -1
  5. package/dist/js/bitmovinplayer-ui.js.map +1 -1
  6. package/dist/js/framework/components/Icon.d.ts +2 -13
  7. package/dist/js/framework/components/Icon.js +2 -3
  8. package/dist/js/framework/components/RecommendationItem.js +1 -1
  9. package/dist/js/framework/components/buttons/Button.js +1 -1
  10. package/dist/js/framework/components/labels/Label.js +1 -1
  11. package/dist/js/framework/components/overlays/SubtitleOverlay.d.ts +6 -9
  12. package/dist/js/framework/components/overlays/SubtitleOverlay.js +121 -119
  13. package/dist/js/framework/components/seekbar/SeekBarLabel.js +2 -2
  14. package/dist/js/framework/components/settings/subtitlesettings/FontSizeSelectBox.js +5 -4
  15. package/dist/js/framework/main.d.ts +1 -1
  16. package/docs/assets/hierarchy.js +1 -1
  17. package/docs/assets/navigation.js +1 -1
  18. package/docs/assets/search.js +1 -1
  19. package/docs/classes/AdClickOverlay.html +28 -28
  20. package/docs/classes/AdControlBar.html +31 -31
  21. package/docs/classes/AdCounterLabel.html +31 -31
  22. package/docs/classes/AdMessageLabel.html +31 -31
  23. package/docs/classes/AdSkipButton.html +27 -27
  24. package/docs/classes/AdStatusOverlay.html +31 -31
  25. package/docs/classes/AirPlayToggleButton.html +35 -35
  26. package/docs/classes/AudioQualitySelectBox.html +38 -38
  27. package/docs/classes/AudioTrackListBox.html +39 -39
  28. package/docs/classes/AudioTrackSelectBox.html +38 -38
  29. package/docs/classes/BackgroundColorSelectBox.html +38 -38
  30. package/docs/classes/BackgroundOpacitySelectBox.html +38 -38
  31. package/docs/classes/BrowserUtils.html +2 -2
  32. package/docs/classes/BufferingOverlay.html +31 -31
  33. package/docs/classes/Button.html +27 -27
  34. package/docs/classes/CastStatusOverlay.html +31 -31
  35. package/docs/classes/CastToggleButton.html +35 -35
  36. package/docs/classes/CastUIContainer.html +31 -31
  37. package/docs/classes/CharacterEdgeSelectBox.html +38 -38
  38. package/docs/classes/ClickOverlay.html +28 -28
  39. package/docs/classes/CloseButton.html +27 -27
  40. package/docs/classes/Component.html +25 -25
  41. package/docs/classes/Container.html +31 -31
  42. package/docs/classes/ControlBar.html +31 -31
  43. package/docs/classes/DynamicSettingsPanelItem.html +33 -33
  44. package/docs/classes/ErrorMessageOverlay.html +31 -31
  45. package/docs/classes/FontColorSelectBox.html +38 -38
  46. package/docs/classes/FontFamilySelectBox.html +38 -38
  47. package/docs/classes/FontOpacitySelectBox.html +38 -38
  48. package/docs/classes/FontSizeSelectBox.html +38 -38
  49. package/docs/classes/FullscreenToggleButton.html +35 -35
  50. package/docs/classes/HugePlaybackToggleButton.html +35 -35
  51. package/docs/classes/HugeReplayButton.html +27 -27
  52. package/docs/classes/I18n.html +2 -2
  53. package/docs/classes/Icon.html +25 -25
  54. package/docs/classes/ItemSelectionList.html +38 -38
  55. package/docs/classes/Label.html +31 -31
  56. package/docs/classes/ListBox.html +39 -39
  57. package/docs/classes/ListSelector.html +38 -38
  58. package/docs/classes/MetadataLabel.html +31 -31
  59. package/docs/classes/NavigationGroup.html +10 -10
  60. package/docs/classes/PictureInPictureToggleButton.html +35 -35
  61. package/docs/classes/PlaybackSpeedSelectBox.html +38 -38
  62. package/docs/classes/PlaybackTimeLabel.html +32 -32
  63. package/docs/classes/PlaybackToggleButton.html +35 -35
  64. package/docs/classes/PlaybackToggleOverlay.html +31 -31
  65. package/docs/classes/PlayerUtils.LiveStreamDetector.html +2 -2
  66. package/docs/classes/PlayerUtils.TimeShiftAvailabilityDetector.html +2 -2
  67. package/docs/classes/PlayerWrapper.html +4 -4
  68. package/docs/classes/QuickSeekButton.html +27 -27
  69. package/docs/classes/RecommendationItem.html +25 -25
  70. package/docs/classes/RecommendationOverlay.html +31 -31
  71. package/docs/classes/ReplayButton.html +27 -27
  72. package/docs/classes/RootNavigationGroup.html +10 -10
  73. package/docs/classes/SeekBar.html +36 -36
  74. package/docs/classes/SeekBarLabel.html +35 -35
  75. package/docs/classes/SelectBox.html +38 -38
  76. package/docs/classes/SettingsPanel.html +39 -39
  77. package/docs/classes/SettingsPanelItem.html +33 -33
  78. package/docs/classes/SettingsPanelNavigationGroup.html +10 -10
  79. package/docs/classes/SettingsPanelNavigationGroupConfig.html +2 -2
  80. package/docs/classes/SettingsPanelPage.html +33 -33
  81. package/docs/classes/SettingsPanelPageBackButton.html +29 -29
  82. package/docs/classes/SettingsPanelPageOpenButton.html +29 -29
  83. package/docs/classes/SettingsToggleButton.html +35 -35
  84. package/docs/classes/Spacer.html +25 -25
  85. package/docs/classes/SpatialNavigation.html +4 -4
  86. package/docs/classes/SubtitleListBox.html +39 -39
  87. package/docs/classes/SubtitleOverlay.html +31 -34
  88. package/docs/classes/SubtitleSelectBox.html +38 -38
  89. package/docs/classes/SubtitleSettingSelectBox.html +38 -38
  90. package/docs/classes/SubtitleSettingsPanelPage.html +33 -33
  91. package/docs/classes/SubtitleSettingsResetButton.html +27 -27
  92. package/docs/classes/TitleBar.html +31 -31
  93. package/docs/classes/ToggleButton.html +35 -35
  94. package/docs/classes/UIContainer.html +31 -31
  95. package/docs/classes/UIInstanceManager.html +14 -14
  96. package/docs/classes/UIManager.html +14 -14
  97. package/docs/classes/VRToggleButton.html +35 -35
  98. package/docs/classes/VideoQualitySelectBox.html +39 -39
  99. package/docs/classes/VolumeControlButton.html +33 -33
  100. package/docs/classes/VolumeSlider.html +36 -36
  101. package/docs/classes/VolumeToggleButton.html +35 -35
  102. package/docs/classes/Watermark.html +28 -28
  103. package/docs/classes/WindowColorSelectBox.html +38 -38
  104. package/docs/classes/WindowOpacitySelectBox.html +38 -38
  105. package/docs/enums/ButtonStyle.html +5 -5
  106. package/docs/enums/LabelStyle.html +4 -4
  107. package/docs/enums/MetadataLabelContent.html +3 -3
  108. package/docs/enums/NavigationDirection.html +2 -2
  109. package/docs/enums/PlaybackTimeLabelMode.html +5 -5
  110. package/docs/enums/PlayerUtils.PlayerState.html +2 -2
  111. package/docs/enums/UIUtils.KeyCode.html +2 -2
  112. package/docs/enums/ViewMode.html +3 -3
  113. package/docs/functions/ArrayUtils.remove.html +1 -1
  114. package/docs/functions/ErrorUtils.defaultMobileV3ErrorMessageTranslator.html +1 -1
  115. package/docs/functions/PlayerUtils.clampValueToRange.html +1 -1
  116. package/docs/functions/PlayerUtils.getCurrentTimeRelativeToSeekableRange.html +1 -1
  117. package/docs/functions/PlayerUtils.getSeekableRangeRespectingLive.html +1 -1
  118. package/docs/functions/PlayerUtils.getSeekableRangeStart.html +1 -1
  119. package/docs/functions/PlayerUtils.getState.html +1 -1
  120. package/docs/functions/PlayerUtils.isTimeShiftAvailable.html +1 -1
  121. package/docs/functions/StorageUtils.getItem.html +1 -1
  122. package/docs/functions/StorageUtils.getObject.html +1 -1
  123. package/docs/functions/StorageUtils.setItem.html +1 -1
  124. package/docs/functions/StorageUtils.setObject.html +1 -1
  125. package/docs/functions/StorageUtils.setStorageApiDisabled.html +1 -1
  126. package/docs/functions/StringUtils.replaceAdMessagePlaceholders.html +1 -1
  127. package/docs/functions/StringUtils.secondsToText.html +1 -1
  128. package/docs/functions/StringUtils.secondsToTime.html +1 -1
  129. package/docs/functions/UIFactory.buildCastReceiverUI.html +1 -1
  130. package/docs/functions/UIFactory.buildSmallScreenUI.html +1 -1
  131. package/docs/functions/UIFactory.buildSubtitleUI.html +1 -1
  132. package/docs/functions/UIFactory.buildTvUI.html +1 -1
  133. package/docs/functions/UIFactory.buildUI.html +1 -1
  134. package/docs/functions/UIUtils.traverseTree.html +1 -1
  135. package/docs/hierarchy.html +1 -1
  136. package/docs/interfaces/ActiveUiChangedArgs.html +3 -3
  137. package/docs/interfaces/AdControlBarConfig.html +12 -12
  138. package/docs/interfaces/AdSkipButtonConfig.html +16 -16
  139. package/docs/interfaces/BufferingOverlayConfig.html +13 -13
  140. package/docs/interfaces/ButtonConfig.html +14 -14
  141. package/docs/interfaces/ClickOverlayConfig.html +15 -15
  142. package/docs/interfaces/CloseButtonConfig.html +15 -15
  143. package/docs/interfaces/ComponentConfig.html +11 -11
  144. package/docs/interfaces/ComponentFocusChangedEventArgs.html +2 -2
  145. package/docs/interfaces/ComponentHoverChangedEventArgs.html +2 -2
  146. package/docs/interfaces/ContainerConfig.html +12 -12
  147. package/docs/interfaces/ControlBarConfig.html +12 -12
  148. package/docs/interfaces/DynamicSettingsPanelItemConfig.html +19 -19
  149. package/docs/interfaces/ErrorMessageMap.html +1 -1
  150. package/docs/interfaces/ErrorMessageOverlayConfig.html +13 -13
  151. package/docs/interfaces/ErrorMessageTranslator.html +1 -1
  152. package/docs/interfaces/ExternalRecommendationLink.html +3 -3
  153. package/docs/interfaces/InternalUIConfig.html +15 -15
  154. package/docs/interfaces/LabelConfig.html +14 -14
  155. package/docs/interfaces/ListBoxConfig.html +17 -17
  156. package/docs/interfaces/ListItem.html +2 -2
  157. package/docs/interfaces/ListItemFilter.html +1 -1
  158. package/docs/interfaces/ListItemLabelTranslator.html +1 -1
  159. package/docs/interfaces/ListSelectorConfig.html +11 -11
  160. package/docs/interfaces/LocalizationConfig.html +3 -3
  161. package/docs/interfaces/MetadataLabelConfig.html +15 -15
  162. package/docs/interfaces/PlaybackTimeLabelConfig.html +16 -16
  163. package/docs/interfaces/PlaybackToggleButtonConfig.html +19 -19
  164. package/docs/interfaces/PlaybackToggleOverlayConfig.html +13 -13
  165. package/docs/interfaces/PlayerUtils.LiveStreamDetectorEventArgs.html +2 -2
  166. package/docs/interfaces/PlayerUtils.TimeShiftAvailabilityChangedArgs.html +2 -2
  167. package/docs/interfaces/QuickSeekButtonConfig.html +15 -15
  168. package/docs/interfaces/RecommendationConfig.html +4 -4
  169. package/docs/interfaces/RecommendationItemConfig.html +12 -12
  170. package/docs/interfaces/SeekBarConfig.html +19 -19
  171. package/docs/interfaces/SeekBarLabelConfig.html +12 -12
  172. package/docs/interfaces/SeekBarMarker.html +2 -2
  173. package/docs/interfaces/SeekPreviewArgs.html +3 -3
  174. package/docs/interfaces/SeekPreviewEventArgs.html +4 -4
  175. package/docs/interfaces/SettingsPanelConfig.html +15 -15
  176. package/docs/interfaces/SettingsPanelItemConfig.html +17 -17
  177. package/docs/interfaces/SettingsPanelPageConfig.html +13 -13
  178. package/docs/interfaces/SettingsToggleButtonConfig.html +20 -20
  179. package/docs/interfaces/SubtitleSettingSelectBoxConfig.html +11 -11
  180. package/docs/interfaces/SubtitleSettingsPanelPageConfig.html +13 -13
  181. package/docs/interfaces/TimelineMarker.html +6 -6
  182. package/docs/interfaces/TitleBarConfig.html +13 -13
  183. package/docs/interfaces/ToggleButtonConfig.html +18 -18
  184. package/docs/interfaces/UIConditionContext.html +10 -10
  185. package/docs/interfaces/UIConditionResolver.html +1 -1
  186. package/docs/interfaces/UIConfig.html +14 -14
  187. package/docs/interfaces/UIContainerConfig.html +17 -17
  188. package/docs/interfaces/UIUtils.TreeTraversalCallback.html +1 -1
  189. package/docs/interfaces/UIVariant.html +2 -2
  190. package/docs/interfaces/ViewModeChangedEventArgs.html +2 -2
  191. package/docs/interfaces/Vocabularies.html +1 -1
  192. package/docs/interfaces/Vocabulary.html +2 -2
  193. package/docs/interfaces/VolumeControlButtonConfig.html +14 -14
  194. package/docs/interfaces/VolumeSliderConfig.html +21 -21
  195. package/docs/interfaces/WatermarkConfig.html +15 -15
  196. package/docs/interfaces/WrappedPlayer.html +2 -2
  197. package/docs/media/CHANGELOG.md +9 -0
  198. package/docs/modules.html +1 -1
  199. package/docs/types/CustomVocabulary.html +1 -1
  200. package/docs/types/LocalizableText.html +1 -1
  201. package/docs/types/Localizer.html +1 -1
  202. package/docs/variables/ErrorUtils.defaultErrorMessages.html +1 -1
  203. package/docs/variables/ErrorUtils.defaultWebErrorMessageTranslator.html +1 -1
  204. package/docs/variables/StringUtils.FORMAT_HHMMSS.html +1 -1
  205. package/docs/variables/StringUtils.FORMAT_MMSS.html +1 -1
  206. package/docs/variables/i18n.html +1 -1
  207. package/docs/variables/version.html +1 -1
  208. package/package.json +1 -1
  209. package/src/scss/components/overlays/_subtitle-overlay.scss +4 -9
  210. package/src/ts/components/Icon.ts +4 -17
  211. package/src/ts/components/RecommendationItem.ts +1 -1
  212. package/src/ts/components/buttons/Button.ts +1 -1
  213. package/src/ts/components/labels/Label.ts +1 -1
  214. package/src/ts/components/overlays/SubtitleOverlay.ts +138 -131
  215. package/src/ts/components/seekbar/SeekBarLabel.ts +2 -2
  216. package/src/ts/components/settings/subtitlesettings/FontSizeSelectBox.ts +7 -6
  217. package/src/ts/main.ts +1 -1
  218. package/docs/interfaces/IconConfig.html +0 -29
@@ -1,17 +1,6 @@
1
1
  import { Component, ComponentConfig } from './Component';
2
- import { LocalizableText } from '../localization/i18n';
3
2
  import { DOM } from '../DOM';
4
- export interface IconConfig extends ComponentConfig {
5
- /**
6
- * WCAG20 standard for defining info about the component (usually the name)
7
- */
8
- ariaLabel?: LocalizableText;
9
- /**
10
- * Alternative text for the icon, used for accessibility (e.g., screen readers).
11
- */
12
- altText?: LocalizableText;
13
- }
14
- export declare class Icon extends Component<IconConfig> {
15
- constructor(config: IconConfig);
3
+ export declare class Icon extends Component<ComponentConfig> {
4
+ constructor(config?: ComponentConfig);
16
5
  protected toDomElement(): DOM;
17
6
  }
@@ -17,11 +17,11 @@ var __extends = (this && this.__extends) || (function () {
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.Icon = void 0;
19
19
  var Component_1 = require("./Component");
20
- var i18n_1 = require("../localization/i18n");
21
20
  var DOM_1 = require("../DOM");
22
21
  var Icon = /** @class */ (function (_super) {
23
22
  __extends(Icon, _super);
24
23
  function Icon(config) {
24
+ if (config === void 0) { config = {}; }
25
25
  var _this = _super.call(this, config) || this;
26
26
  _this.config = _this.mergeConfig(config, {
27
27
  cssClass: 'ui-icon',
@@ -30,8 +30,7 @@ var Icon = /** @class */ (function (_super) {
30
30
  }
31
31
  Icon.prototype.toDomElement = function () {
32
32
  return new DOM_1.DOM('div', {
33
- class: this.getCssClasses(),
34
- 'aria-label': i18n_1.i18n.performLocalization(this.config.ariaLabel || this.config.altText),
33
+ class: this.getCssClasses()
35
34
  });
36
35
  };
37
36
  return Icon;
@@ -78,7 +78,7 @@ var RecommendationItem = /** @class */ (function (_super) {
78
78
  }
79
79
  var itemElement = new DOM_1.DOM(tagName, __assign(__assign({ id: this.config.id, class: this.getCssClasses() }, additionalAttributes), { tabindex: this.config.tabIndex.toString() }), this);
80
80
  if (posterUrl) {
81
- itemElement.css({ 'background-image': "url(".concat(posterUrl, ")") });
81
+ itemElement.css({ 'background-image': "url(\"".concat(posterUrl, "\")") });
82
82
  }
83
83
  var titleElement = new DOM_1.DOM('div', {
84
84
  class: this.prefixCss('title-container'),
@@ -81,7 +81,7 @@ var Button = /** @class */ (function (_super) {
81
81
  // Create the button element with the text label
82
82
  var buttonElement = new DOM_1.DOM('button', buttonElementAttributes, this);
83
83
  var addIconElement = function () {
84
- var icon = new Icon_1.Icon({ ariaLabel: _this.config.ariaLabel, altText: _this.config.text });
84
+ var icon = new Icon_1.Icon();
85
85
  buttonElement.append(icon.getDomElement());
86
86
  };
87
87
  var addLabelElement = function () {
@@ -85,7 +85,7 @@ var Label = /** @class */ (function (_super) {
85
85
  _this.onClickEvent();
86
86
  });
87
87
  if (this.config.labelStyle !== LabelStyle.Text) {
88
- var icon = new Icon_1.Icon({ ariaLabel: this.config.ariaLabel, altText: this.config.text });
88
+ var icon = new Icon_1.Icon();
89
89
  switch (this.config.labelStyle) {
90
90
  case LabelStyle.TextWithTrailingIcon:
91
91
  wrapperElement.append(icon.getDomElement());
@@ -24,24 +24,21 @@ export declare class SubtitleOverlay extends Container<ContainerConfig> {
24
24
  private subtitleContainerManager;
25
25
  private static readonly CLASS_CONTROLBAR_VISIBLE;
26
26
  private static readonly CLASS_CEA_608;
27
- private static readonly DEFAULT_CEA608_NUM_ROWS;
28
- private static readonly DEFAULT_CEA608_NUM_COLUMNS;
29
- private FONT_SIZE_FACTOR;
30
- private CEA608_NUM_ROWS;
31
- private CEA608_NUM_COLUMNS;
32
- private CEA608_COLUMN_OFFSET;
27
+ private static readonly CEA608_NUM_ROWS;
28
+ private static readonly CEA608_NUM_COLUMNS;
29
+ private static readonly CEA608_COLUMN_OFFSET;
30
+ private static readonly DEFAULT_CAPTION_LEFT_OFFSET;
33
31
  private cea608Enabled;
32
+ private cea608FontSizeFactor;
33
+ private ensureCea608GridSizeUpdated;
34
34
  constructor(config?: ContainerConfig);
35
35
  configure(player: PlayerAPI, uimanager: UIInstanceManager): void;
36
36
  setFontSizeFactor(factor: number): void;
37
- recalculateCEAGrid(): void;
38
37
  detectCroppedSubtitleLabel(labelElement: HTMLElement): SubtitleCropDetectionResult;
39
38
  handleSubtitleCropping(label: SubtitleLabel): void;
40
- resolveRowNumber(row: number): number;
41
39
  generateLabel(event: SubtitleCueEvent): SubtitleLabel;
42
40
  filterFontSizeOptions: ListItemFilter;
43
41
  resolveFontSizeFactor(value: string): number;
44
- updateRegionRowPosition(r: SubtitleRegionContainer): void;
45
42
  configureCea608Captions(player: PlayerAPI, uimanager: UIInstanceManager): void;
46
43
  enablePreviewSubtitleLabel(): void;
47
44
  removePreviewSubtitleLabel(): void;
@@ -34,14 +34,8 @@ var SubtitleOverlay = /** @class */ (function (_super) {
34
34
  if (config === void 0) { config = {}; }
35
35
  var _this = _super.call(this, config) || this;
36
36
  _this.preprocessLabelEventCallback = new EventDispatcher_1.EventDispatcher();
37
- _this.FONT_SIZE_FACTOR = 1;
38
- // The number of rows in a cea608 grid
39
- _this.CEA608_NUM_ROWS = SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS;
40
- // The number of columns in a cea608 grid
41
- _this.CEA608_NUM_COLUMNS = SubtitleOverlay.DEFAULT_CEA608_NUM_COLUMNS;
42
- // The offset in percent for one column (which is also the width of a column)
43
- _this.CEA608_COLUMN_OFFSET = 100 / _this.CEA608_NUM_COLUMNS;
44
37
  _this.cea608Enabled = false;
38
+ _this.cea608FontSizeFactor = 1;
45
39
  _this.filterFontSizeOptions = function (listItem) {
46
40
  if (_this.cea608Enabled && listItem.key !== null) {
47
41
  var percent = parseInt(listItem.key, 10);
@@ -49,7 +43,6 @@ var SubtitleOverlay = /** @class */ (function (_super) {
49
43
  }
50
44
  return true;
51
45
  };
52
- _this.recalculateCEAGrid();
53
46
  _this.previewSubtitleActive = false;
54
47
  _this.previewSubtitle = new SubtitleLabel({ text: i18n_1.i18n.getLocalizer('subtitle.example') });
55
48
  _this.config = _this.mergeConfig(config, {
@@ -116,6 +109,7 @@ var SubtitleOverlay = /** @class */ (function (_super) {
116
109
  removedActiveCues.forEach(function (toRemove) {
117
110
  _this.subtitleContainerManager.removeLabel(toRemove.label);
118
111
  });
112
+ _this.updateComponents();
119
113
  };
120
114
  player.on(player.exports.PlayerEvent.AudioChanged, subtitleClearHandler);
121
115
  player.on(player.exports.PlayerEvent.SubtitleDisabled, subtitleClearHandler);
@@ -126,11 +120,17 @@ var SubtitleOverlay = /** @class */ (function (_super) {
126
120
  uimanager.onComponentShow.subscribe(function (component) {
127
121
  if (component instanceof ControlBar_1.ControlBar) {
128
122
  _this.getDomElement().addClass(_this.prefixCss(SubtitleOverlay.CLASS_CONTROLBAR_VISIBLE));
123
+ if (_this.cea608Enabled && _this.ensureCea608GridSizeUpdated) {
124
+ awaitTransitionEnd(_this.getDomElement()).then(_this.ensureCea608GridSizeUpdated);
125
+ }
129
126
  }
130
127
  });
131
128
  uimanager.onComponentHide.subscribe(function (component) {
132
129
  if (component instanceof ControlBar_1.ControlBar) {
133
130
  _this.getDomElement().removeClass(_this.prefixCss(SubtitleOverlay.CLASS_CONTROLBAR_VISIBLE));
131
+ if (_this.cea608Enabled && _this.ensureCea608GridSizeUpdated) {
132
+ awaitTransitionEnd(_this.getDomElement()).then(_this.ensureCea608GridSizeUpdated);
133
+ }
134
134
  }
135
135
  });
136
136
  this.configureCea608Captions(player, uimanager);
@@ -140,15 +140,7 @@ var SubtitleOverlay = /** @class */ (function (_super) {
140
140
  SubtitleOverlay.prototype.setFontSizeFactor = function (factor) {
141
141
  // We only allow range from 50% to 200% as suggested by spec
142
142
  // https://www.ecfr.gov/current/title-47/part-79/section-79.103#p-79.103(c)(4)
143
- this.FONT_SIZE_FACTOR = Math.max(0.5, Math.min(2.0, factor));
144
- this.recalculateCEAGrid();
145
- };
146
- SubtitleOverlay.prototype.recalculateCEAGrid = function () {
147
- // Needs to get recalculated in case the font size will change also we need to floor this
148
- // to always align to the whole number represented in styles.
149
- this.CEA608_NUM_ROWS = Math.floor(SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS / Math.max(this.FONT_SIZE_FACTOR, 1));
150
- this.CEA608_NUM_COLUMNS = Math.floor(SubtitleOverlay.DEFAULT_CEA608_NUM_COLUMNS / this.FONT_SIZE_FACTOR);
151
- this.CEA608_COLUMN_OFFSET = 100 / this.CEA608_NUM_COLUMNS;
143
+ this.cea608FontSizeFactor = Math.max(0.5, Math.min(2, factor));
152
144
  };
153
145
  SubtitleOverlay.prototype.detectCroppedSubtitleLabel = function (labelElement) {
154
146
  var parent = this.getDomElement().get(0);
@@ -181,15 +173,6 @@ var SubtitleOverlay = /** @class */ (function (_super) {
181
173
  labelDomElement.removeCss('right');
182
174
  }
183
175
  };
184
- SubtitleOverlay.prototype.resolveRowNumber = function (row) {
185
- // In case there is a font size factor and the row from event would overflow
186
- // we need to apply an offset so it gets rendered to visible area.
187
- if (this.FONT_SIZE_FACTOR > 1 && row > this.CEA608_NUM_ROWS) {
188
- var rowDelta = SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS - this.CEA608_NUM_ROWS;
189
- return row - rowDelta;
190
- }
191
- return row;
192
- };
193
176
  SubtitleOverlay.prototype.generateLabel = function (event) {
194
177
  var _a;
195
178
  // Sanitize cue data (must be done before the cue ID is generated in subtitleManager.cueEnter / update)
@@ -197,8 +180,8 @@ var SubtitleOverlay = /** @class */ (function (_super) {
197
180
  // Sometimes the positions are undefined, we assume them to be zero.
198
181
  // We need to keep track of the original row position in case of recalculation.
199
182
  var originalRowNumber = ((_a = event.position) === null || _a === void 0 ? void 0 : _a.row) || 0;
200
- if (event.position) {
201
- event.position.row = this.resolveRowNumber(event.position.row) || 0;
183
+ if (isCea608SubtitleCue(event)) {
184
+ event.position.row = event.position.row || 0;
202
185
  event.position.column = event.position.column || 0;
203
186
  region = region || "cea608-row-".concat(event.position.row);
204
187
  }
@@ -216,39 +199,33 @@ var SubtitleOverlay = /** @class */ (function (_super) {
216
199
  SubtitleOverlay.prototype.resolveFontSizeFactor = function (value) {
217
200
  return parseInt(value) / 100;
218
201
  };
219
- SubtitleOverlay.prototype.updateRegionRowPosition = function (r) {
220
- var _a;
221
- var element = r.getDomElement().get()[0];
222
- var label = r.getComponents()[0];
223
- if (!element || !label) {
224
- return;
225
- }
226
- var rowClassList = element.classList;
227
- var originalRow = (_a = label.getConfig()) === null || _a === void 0 ? void 0 : _a.originalRowPosition;
228
- var rowClassRegex = /subtitle-position-cea608-row-(\d+)/;
229
- var currentClass = Array.from(rowClassList).find(function (cls) { return rowClassRegex.test(cls); });
230
- if (!currentClass) {
231
- return;
232
- }
233
- var match = rowClassRegex.exec(currentClass);
234
- var rowNumber = match ? parseInt(match[1], 10) : null;
235
- var newRowNum = this.resolveRowNumber(originalRow !== null && originalRow !== void 0 ? originalRow : rowNumber);
236
- var newClass = currentClass.replace(rowClassRegex, "subtitle-position-cea608-row-".concat(newRowNum));
237
- rowClassList.replace(currentClass, newClass);
238
- };
239
202
  SubtitleOverlay.prototype.configureCea608Captions = function (player, uimanager) {
240
203
  var _this = this;
241
- // The calculated font size
204
+ var _a;
205
+ /** The calculated row height in px */
206
+ var rowHeight = 0;
207
+ /** The calculated font size in px */
242
208
  var fontSize = 0;
243
- // The required letter spacing spread the text characters evenly across the grid
209
+ /**
210
+ * The ratio of the font size of 100% to the row height.
211
+ * e.g. font size 100% fills up 75% of the available row height
212
+ */
213
+ var fontSize100PercentRatio = 0.75;
214
+ /** The required letter spacing spread the text characters evenly across the grid */
244
215
  var fontLetterSpacing = 0;
245
- // Flag telling if a font size calculation is required of if the current values are valid
246
- var fontSizeCalculationRequired = true;
247
- // Flag telling if the CEA-608 mode is enabled
216
+ /** The ratio of the caption window/row height that is used as margin so that the window encloses the caption */
217
+ var windowMarginRatio = 0.2;
218
+ /** The calculated window margin in px */
219
+ var windowMargin;
220
+ /** Flag telling if the CEA-608 rendering mode is currently enabled */
248
221
  this.cea608Enabled = false;
222
+ /** Track last known grid params to avoid unnecessary recalculations */
223
+ var lastCeaGridRecalculation = { overlayWidth: 0, overlayHeight: 0, fontSizeFactor: 0 };
249
224
  var settingsManager = uimanager.getSubtitleSettingsManager();
250
- var fontSizeFactorSettings = this.resolveFontSizeFactor(settingsManager.fontSize.value);
251
- this.setFontSizeFactor(fontSizeFactorSettings);
225
+ if (settingsManager.fontSize.value != null) {
226
+ var fontSizeFactorSettings = this.resolveFontSizeFactor(settingsManager.fontSize.value);
227
+ this.setFontSizeFactor(fontSizeFactorSettings);
228
+ }
252
229
  settingsManager.fontSize.onChanged.subscribe(function (_sender, property) {
253
230
  if (property.isSet()) {
254
231
  // We need to convert from percent
@@ -258,9 +235,32 @@ var SubtitleOverlay = /** @class */ (function (_super) {
258
235
  else {
259
236
  _this.setFontSizeFactor(1);
260
237
  }
261
- updateCEA608FontSize();
238
+ if (_this.cea608Enabled) {
239
+ _this.ensureCea608GridSizeUpdated();
240
+ }
262
241
  });
263
- var updateCEA608FontSize = function () {
242
+ (_a = this.onShow) === null || _a === void 0 ? void 0 : _a.subscribe(function () {
243
+ // ensure CEA grid is updated whenever the overlay becomes visible
244
+ if (_this.cea608Enabled) {
245
+ _this.ensureCea608GridSizeUpdated();
246
+ }
247
+ });
248
+ this.ensureCea608GridSizeUpdated = function () {
249
+ var overlayElement = _this.getDomElement();
250
+ var currentWidth = overlayElement.width();
251
+ var currentHeight = overlayElement.height();
252
+ var hasOverlaySizeChanged = currentWidth !== lastCeaGridRecalculation.overlayWidth ||
253
+ currentHeight !== lastCeaGridRecalculation.overlayHeight;
254
+ var hasFontSizeFactorChanged = _this.cea608FontSizeFactor !== lastCeaGridRecalculation.fontSizeFactor;
255
+ if (!hasOverlaySizeChanged && !hasFontSizeFactorChanged) {
256
+ // none of the input variables changed, no need to recalculate
257
+ return;
258
+ }
259
+ lastCeaGridRecalculation = {
260
+ overlayWidth: currentWidth,
261
+ overlayHeight: currentHeight,
262
+ fontSizeFactor: _this.cea608FontSizeFactor,
263
+ };
264
264
  var dummyLabel = new SubtitleLabel({ text: 'X' });
265
265
  dummyLabel.getDomElement().css({
266
266
  // By using a large font size we do not need to use multiple letters and can get still an
@@ -272,8 +272,8 @@ var SubtitleOverlay = /** @class */ (function (_super) {
272
272
  _this.addComponent(dummyLabel);
273
273
  _this.updateComponents();
274
274
  _this.show();
275
- var dummyLabelCharWidth = dummyLabel.getDomElement().width() * _this.FONT_SIZE_FACTOR;
276
- var dummyLabelCharHeight = dummyLabel.getDomElement().height() * _this.FONT_SIZE_FACTOR;
275
+ var dummyLabelCharWidth = dummyLabel.getDomElement().width();
276
+ var dummyLabelCharHeight = dummyLabel.getDomElement().height();
277
277
  var fontSizeRatio = dummyLabelCharWidth / dummyLabelCharHeight;
278
278
  _this.removeComponent(dummyLabel);
279
279
  _this.updateComponents();
@@ -285,19 +285,22 @@ var SubtitleOverlay = /** @class */ (function (_super) {
285
285
  // layouting, but the actual reason could not be determined. Aiming for a target width - 1px would work in
286
286
  // most browsers, but Safari has a "quantized" font size rendering with huge steps in between so we need
287
287
  // to subtract some more pixels to avoid line breaks there as well.
288
- var overlayElement = _this.getDomElement();
289
- var subtitleOverlayWidth = overlayElement.width() - 10;
290
- var subtitleOverlayHeight = overlayElement.height();
288
+ var subtitleOverlayWidthUsableRatio = 1 - parseFloat(SubtitleOverlay.DEFAULT_CAPTION_LEFT_OFFSET) / 100;
289
+ var subtitleOverlayWidth = Math.floor(subtitleOverlayWidthUsableRatio * currentWidth) - 10;
290
+ var subtitleOverlayHeight = currentHeight;
291
291
  // The size ratio of the letter grid
292
- var fontGridSizeRatio = (dummyLabelCharWidth * _this.CEA608_NUM_COLUMNS) / (dummyLabelCharHeight * _this.CEA608_NUM_ROWS);
292
+ var fontGridSizeRatio = (dummyLabelCharWidth * SubtitleOverlay.CEA608_NUM_COLUMNS) /
293
+ (dummyLabelCharHeight * SubtitleOverlay.CEA608_NUM_ROWS);
293
294
  // The size ratio of the available space for the grid
294
295
  var subtitleOverlaySizeRatio = subtitleOverlayWidth / subtitleOverlayHeight;
295
296
  if (subtitleOverlaySizeRatio > fontGridSizeRatio) {
296
297
  // When the available space is wider than the text grid, the font size is simply
297
298
  // determined by the height of the available space.
298
- fontSize = subtitleOverlayHeight / _this.CEA608_NUM_ROWS;
299
+ rowHeight = subtitleOverlayHeight / SubtitleOverlay.CEA608_NUM_ROWS;
300
+ var fontSize100Percent = rowHeight * (1 - windowMarginRatio) * fontSize100PercentRatio;
301
+ fontSize = fontSize100Percent * _this.cea608FontSizeFactor;
299
302
  // Calculate the additional letter spacing required to evenly spread the text across the grid's width
300
- var gridSlotWidth = subtitleOverlayWidth / _this.CEA608_NUM_COLUMNS;
303
+ var gridSlotWidth = subtitleOverlayWidth / SubtitleOverlay.CEA608_NUM_COLUMNS;
301
304
  var fontCharWidth = fontSize * fontSizeRatio;
302
305
  fontLetterSpacing = Math.max(gridSlotWidth - fontCharWidth, 0);
303
306
  }
@@ -305,82 +308,67 @@ var SubtitleOverlay = /** @class */ (function (_super) {
305
308
  // When the available space is not wide enough, texts would vertically overlap if we take
306
309
  // the height as a base for the font size, so we need to limit the height. We do that
307
310
  // by determining the font size by the width of the available space.
308
- fontSize = subtitleOverlayWidth / _this.CEA608_NUM_COLUMNS / fontSizeRatio;
311
+ rowHeight = subtitleOverlayWidth / SubtitleOverlay.CEA608_NUM_COLUMNS / fontSizeRatio;
312
+ var fontSize100Percent = rowHeight * (1 - windowMarginRatio) * fontSize100PercentRatio;
313
+ fontSize = fontSize100Percent * _this.cea608FontSizeFactor;
309
314
  fontLetterSpacing = 0;
310
315
  }
311
- // After computing overlay dimensions:
312
- var newRowHeight = fontSize;
313
- // Update row position of regions
314
- var regions = _this.getComponents();
315
- regions.forEach(function (r) {
316
- if (r instanceof SubtitleRegionContainer) {
317
- _this.updateRegionRowPosition(r);
318
- }
319
- });
316
+ windowMargin = rowHeight * windowMarginRatio;
320
317
  // Update the CSS custom property on the overlay DOM element
321
318
  overlayElement.get().forEach(function (el) {
322
- el.style.setProperty('--cea608-row-height', "".concat(newRowHeight, "px"));
319
+ el.style.setProperty('--cea608-row-height', "".concat(rowHeight, "px"));
323
320
  });
324
321
  // Update font-size of all active subtitle labels
325
322
  var updateLabel = function (label) {
326
- var isLargerFontSize = _this.FONT_SIZE_FACTOR > 1;
327
323
  label.getDomElement().css({
328
324
  'font-size': "".concat(fontSize, "px"),
329
- 'line-height': "".concat(fontSize, "px"),
330
- 'letter-spacing': "".concat(isLargerFontSize ? 0 : fontLetterSpacing, "px"),
331
- 'white-space': "".concat(isLargerFontSize ? 'nowrap' : 'normal'),
332
- left: isLargerFontSize && '0%',
325
+ 'line-height': "".concat(rowHeight - windowMargin, "px"),
326
+ 'letter-spacing': "".concat(fontLetterSpacing, "px"),
333
327
  });
334
- label.regionStyle = "line-height: ".concat(fontSize, "px;");
328
+ label.regionStyle = "margin: ".concat(windowMargin / 2, "px; height: ").concat(rowHeight, "px");
335
329
  };
336
330
  for (var _i = 0, _a = _this.getComponents(); _i < _a.length; _i++) {
337
- var label = _a[_i];
338
- if (label instanceof SubtitleRegionContainer) {
339
- label.getComponents().forEach(function (l) {
331
+ var childComponent = _a[_i];
332
+ if (childComponent instanceof SubtitleRegionContainer) {
333
+ childComponent.getDomElement().css({
334
+ margin: "".concat(windowMargin / 2, "px"),
335
+ height: "".concat(rowHeight, "px"),
336
+ });
337
+ childComponent.getComponents().forEach(function (l) {
340
338
  updateLabel(l);
341
339
  });
342
340
  }
343
- if (label instanceof SubtitleLabel) {
344
- updateLabel(label);
341
+ if (childComponent instanceof SubtitleLabel) {
342
+ updateLabel(childComponent);
345
343
  }
346
344
  }
347
345
  };
348
346
  player.on(player.exports.PlayerEvent.PlayerResized, function () {
349
347
  if (_this.cea608Enabled) {
350
- updateCEA608FontSize();
351
- }
352
- else {
353
- fontSizeCalculationRequired = true;
348
+ _this.ensureCea608GridSizeUpdated();
354
349
  }
355
350
  });
356
351
  this.preprocessLabelEventCallback.subscribe(function (event, label) {
357
- var isCEA608 = event.position != null;
358
- if (!isCEA608) {
352
+ if (!isCea608SubtitleCue(event)) {
359
353
  // Skip all non-CEA608 cues
360
354
  return;
361
355
  }
362
356
  if (!_this.cea608Enabled) {
363
357
  _this.cea608Enabled = true;
364
358
  _this.getDomElement().addClass(_this.prefixCss(SubtitleOverlay.CLASS_CEA_608));
365
- // We conditionally update the font size by this flag here to avoid updating every time a subtitle
366
- // is added into an empty overlay. Because we reset the overlay when all subtitles are gone, this
367
- // would trigger an unnecessary update every time, but it's only required under certain conditions,
368
- // e.g. after the player size has changed.
369
- if (fontSizeCalculationRequired) {
370
- updateCEA608FontSize();
371
- fontSizeCalculationRequired = false;
372
- }
373
359
  }
374
- // We disable the grid and wrapping in case enlarged font size is used to prevent
375
- // line and characters overflows
376
- var isLargerFontSize = _this.FONT_SIZE_FACTOR > 1;
360
+ var leftOffset = event.position.column * SubtitleOverlay.CEA608_COLUMN_OFFSET + '%';
361
+ if (leftOffset === '0%') {
362
+ // ensure that a little of the window still shows for better readability
363
+ leftOffset = SubtitleOverlay.DEFAULT_CAPTION_LEFT_OFFSET;
364
+ }
377
365
  label.getDomElement().css({
378
- left: "".concat(isLargerFontSize ? 0 : event.position.column * _this.CEA608_COLUMN_OFFSET, "%"),
366
+ left: leftOffset,
379
367
  'font-size': "".concat(fontSize, "px"),
380
- 'letter-spacing': "".concat(isLargerFontSize ? 0 : fontLetterSpacing, "px"),
381
- 'white-space': "".concat(isLargerFontSize ? 'nowrap' : 'normal'),
368
+ 'letter-spacing': "".concat(fontLetterSpacing, "px"),
369
+ 'line-height': "".concat(rowHeight - windowMargin, "px"),
382
370
  });
383
- label.regionStyle = "line-height: ".concat(fontSize, "px;");
371
+ label.regionStyle = "margin: ".concat(windowMargin / 2, "px; height: ").concat(rowHeight, "px");
384
372
  });
385
373
  var reset = function () {
386
374
  _this.getDomElement().removeClass(_this.prefixCss(SubtitleOverlay.CLASS_CEA_608));
@@ -414,8 +402,10 @@ var SubtitleOverlay = /** @class */ (function (_super) {
414
402
  };
415
403
  SubtitleOverlay.CLASS_CONTROLBAR_VISIBLE = 'controlbar-visible';
416
404
  SubtitleOverlay.CLASS_CEA_608 = 'cea608';
417
- SubtitleOverlay.DEFAULT_CEA608_NUM_ROWS = 15;
418
- SubtitleOverlay.DEFAULT_CEA608_NUM_COLUMNS = 32;
405
+ SubtitleOverlay.CEA608_NUM_ROWS = 15;
406
+ SubtitleOverlay.CEA608_NUM_COLUMNS = 32;
407
+ SubtitleOverlay.CEA608_COLUMN_OFFSET = 100 / SubtitleOverlay.CEA608_NUM_COLUMNS;
408
+ SubtitleOverlay.DEFAULT_CAPTION_LEFT_OFFSET = '0.5%';
419
409
  return SubtitleOverlay;
420
410
  }(Container_1.Container));
421
411
  exports.SubtitleOverlay = SubtitleOverlay;
@@ -645,17 +635,11 @@ var SubtitleRegionContainerManager = /** @class */ (function () {
645
635
  if (label.regionStyle) {
646
636
  regionContainer.getDomElement().attr('style', label.regionStyle);
647
637
  }
648
- else if (label.vtt && !label.vtt.region) {
649
- /**
650
- * If there is no region present to wrap the Cue Box, the Cue box becomes the
651
- * region itself. Therefore the positioning values have to come from the box.
652
- */
638
+ if (label.vtt) {
653
639
  regionContainer.getDomElement().css('position', 'static');
654
640
  }
655
- else {
656
- // getDomElement needs to be called at least once to ensure the component exists
657
- regionContainer.getDomElement();
658
- }
641
+ // getDomElement needs to be called at least once to ensure the component exists
642
+ regionContainer.getDomElement();
659
643
  for (var regionContainerId_1 in this.subtitleRegionContainers) {
660
644
  this.subtitleOverlay.addComponent(this.subtitleRegionContainers[regionContainerId_1]);
661
645
  }
@@ -730,3 +714,21 @@ var SubtitleRegionContainer = /** @class */ (function (_super) {
730
714
  return SubtitleRegionContainer;
731
715
  }(Container_1.Container));
732
716
  exports.SubtitleRegionContainer = SubtitleRegionContainer;
717
+ function isCea608SubtitleCue(cue) {
718
+ return cue.position != null;
719
+ }
720
+ function awaitTransitionEnd(domElement) {
721
+ var hasTransition = getComputedStyle(domElement.get(0)).transitionProperty !== 'none';
722
+ if (!hasTransition) {
723
+ return Promise.resolve();
724
+ }
725
+ return new Promise(function (resolve) {
726
+ var transitionHandler = function () {
727
+ domElement.off('transitionend', transitionHandler);
728
+ domElement.off('transitioncancel', transitionHandler);
729
+ resolve();
730
+ };
731
+ domElement.on('transitionend', transitionHandler);
732
+ domElement.on('transitioncancel', transitionHandler);
733
+ });
734
+ }
@@ -196,7 +196,7 @@ var SeekBarLabel = /** @class */ (function (_super) {
196
196
  // A default value for width is set in the stylesheet and can be overwritten from there or anywhere else.
197
197
  return {
198
198
  display: 'inherit',
199
- 'background-image': "url(".concat(thumbnail.url, ")"),
199
+ 'background-image': "url(\"".concat(thumbnail.url, "\")"),
200
200
  'padding-bottom': "".concat(100 * aspectRatio, "%"),
201
201
  'background-size': "".concat(sizeX, "% ").concat(sizeY, "%"),
202
202
  'background-position': "-".concat(offsetX, "% -").concat(offsetY, "%"),
@@ -206,7 +206,7 @@ var SeekBarLabel = /** @class */ (function (_super) {
206
206
  var aspectRatio = (1 / width) * height;
207
207
  return {
208
208
  display: 'inherit',
209
- 'background-image': "url(".concat(thumbnail.url, ")"),
209
+ 'background-image': "url(\"".concat(thumbnail.url, "\")"),
210
210
  'padding-bottom': "".concat(100 * aspectRatio, "%"),
211
211
  'background-size': "100% 100%",
212
212
  'background-position': "0 0",
@@ -62,10 +62,6 @@ var FontSizeSelectBox = /** @class */ (function (_super) {
62
62
  FontSizeSelectBox.prototype.configure = function (player, uimanager) {
63
63
  var _this = this;
64
64
  _super.prototype.configure.call(this, player, uimanager);
65
- this.populateItemsWithFilter();
66
- this.onShow.subscribe(function () {
67
- _this.populateItemsWithFilter();
68
- });
69
65
  this.settingsManager.fontSize.onChanged.subscribe(function (sender, property) {
70
66
  if (property.isSet()) {
71
67
  _this.toggleOverlayClass('fontsize-' + property.value);
@@ -78,6 +74,11 @@ var FontSizeSelectBox = /** @class */ (function (_super) {
78
74
  this.onItemSelected.subscribe(function (sender, key) {
79
75
  _this.settingsManager.fontSize.value = key;
80
76
  });
77
+ this.onShow.subscribe(function () {
78
+ _this.populateItemsWithFilter();
79
+ });
80
+ // init
81
+ this.populateItemsWithFilter();
81
82
  };
82
83
  return FontSizeSelectBox;
83
84
  }(SubtitleSettingSelectBox_1.SubtitleSettingSelectBox));
@@ -87,4 +87,4 @@ export { ReplayButton } from './components/buttons/ReplayButton';
87
87
  export { QuickSeekButton, QuickSeekButtonConfig } from './components/buttons/QuickSeekButton';
88
88
  export { ListSelector, ListSelectorConfig, ListItem, ListItemFilter, ListItemLabelTranslator, } from './components/lists/ListSelector';
89
89
  export { AdStatusOverlay } from './components/ads/AdStatusOverlay';
90
- export { Icon, IconConfig } from './components/Icon';
90
+ export { Icon } from './components/Icon';
@@ -1 +1 @@
1
- window.hierarchyData = "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"
1
+ window.hierarchyData = "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"
@@ -1 +1 @@
1
- window.navigationData = "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"
1
+ window.navigationData = "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"