bitmovin-player-ui 4.2.0 → 4.3.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.
- package/CHANGELOG.md +20 -0
- package/dist/js/bitmovinplayer-ui.js +1 -1
- package/dist/js/bitmovinplayer-ui.js.map +1 -1
- package/dist/js/framework/UIFactory.js +1 -2
- package/dist/js/framework/components/Container.d.ts +1 -1
- package/dist/js/framework/components/UIContainer.d.ts +7 -1
- package/dist/js/framework/components/UIContainer.js +33 -2
- package/dist/js/framework/components/ads/AdMessageLabel.d.ts +22 -3
- package/dist/js/framework/components/ads/AdMessageLabel.js +40 -17
- package/dist/js/framework/components/overlays/DismissClickOverlay.js +7 -1
- package/dist/js/framework/components/settings/SettingsPanel.d.ts +28 -1
- package/dist/js/framework/components/settings/SettingsPanel.js +103 -7
- package/dist/js/framework/utils/StringUtils.d.ts +2 -2
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/AdClickOverlay.html +28 -28
- package/docs/classes/AdControlBar.html +31 -31
- package/docs/classes/AdCounterLabel.html +31 -31
- package/docs/classes/AdMessageLabel.html +51 -32
- package/docs/classes/AdSkipButton.html +27 -27
- package/docs/classes/AdStatusOverlay.html +31 -31
- package/docs/classes/AirPlayToggleButton.html +35 -35
- package/docs/classes/AudioQualitySelectBox.html +38 -38
- package/docs/classes/AudioTrackListBox.html +40 -39
- package/docs/classes/AudioTrackSelectBox.html +38 -38
- package/docs/classes/BackgroundColorSelectBox.html +38 -38
- package/docs/classes/BackgroundOpacitySelectBox.html +38 -38
- package/docs/classes/BrowserUtils.html +2 -2
- package/docs/classes/BufferingOverlay.html +31 -31
- package/docs/classes/Button.html +27 -27
- package/docs/classes/CastStatusOverlay.html +31 -31
- package/docs/classes/CastToggleButton.html +35 -35
- package/docs/classes/CastUIContainer.html +31 -31
- package/docs/classes/CharacterEdgeSelectBox.html +38 -38
- package/docs/classes/ClickOverlay.html +28 -28
- package/docs/classes/CloseButton.html +27 -27
- package/docs/classes/Component.html +25 -25
- package/docs/classes/Container.html +31 -31
- package/docs/classes/ControlBar.html +31 -31
- package/docs/classes/DynamicSettingsPanelItem.html +33 -33
- package/docs/classes/ErrorMessageOverlay.html +31 -31
- package/docs/classes/FontColorSelectBox.html +38 -38
- package/docs/classes/FontFamilySelectBox.html +38 -38
- package/docs/classes/FontOpacitySelectBox.html +38 -38
- package/docs/classes/FontSizeSelectBox.html +38 -38
- package/docs/classes/FullscreenToggleButton.html +35 -35
- package/docs/classes/HugePlaybackToggleButton.html +35 -35
- package/docs/classes/HugeReplayButton.html +27 -27
- package/docs/classes/I18n.html +2 -2
- package/docs/classes/Icon.html +25 -25
- package/docs/classes/ItemSelectionList.html +38 -38
- package/docs/classes/Label.html +31 -31
- package/docs/classes/ListBox.html +40 -39
- package/docs/classes/ListSelector.html +38 -38
- package/docs/classes/MetadataLabel.html +31 -31
- package/docs/classes/NavigationGroup.html +10 -10
- package/docs/classes/PictureInPictureToggleButton.html +35 -35
- package/docs/classes/PlaybackSpeedSelectBox.html +38 -38
- package/docs/classes/PlaybackTimeLabel.html +32 -32
- package/docs/classes/PlaybackToggleButton.html +35 -35
- package/docs/classes/PlaybackToggleOverlay.html +31 -31
- package/docs/classes/PlayerUtils.LiveStreamDetector.html +2 -2
- package/docs/classes/PlayerUtils.TimeShiftAvailabilityDetector.html +2 -2
- package/docs/classes/PlayerWrapper.html +4 -4
- package/docs/classes/QuickSeekButton.html +27 -27
- package/docs/classes/RecommendationItem.html +25 -25
- package/docs/classes/RecommendationOverlay.html +31 -31
- package/docs/classes/ReplayButton.html +27 -27
- package/docs/classes/RootNavigationGroup.html +10 -10
- package/docs/classes/SeekBar.html +36 -36
- package/docs/classes/SeekBarLabel.html +35 -35
- package/docs/classes/SelectBox.html +38 -38
- package/docs/classes/SettingsPanel.html +40 -39
- package/docs/classes/SettingsPanelItem.html +33 -33
- package/docs/classes/SettingsPanelNavigationGroup.html +10 -10
- package/docs/classes/SettingsPanelNavigationGroupConfig.html +2 -2
- package/docs/classes/SettingsPanelPage.html +33 -33
- package/docs/classes/SettingsPanelPageBackButton.html +29 -29
- package/docs/classes/SettingsPanelPageOpenButton.html +29 -29
- package/docs/classes/SettingsToggleButton.html +35 -35
- package/docs/classes/Spacer.html +25 -25
- package/docs/classes/SpatialNavigation.html +4 -4
- package/docs/classes/SubtitleListBox.html +40 -39
- package/docs/classes/SubtitleOverlay.html +31 -31
- package/docs/classes/SubtitleSelectBox.html +38 -38
- package/docs/classes/SubtitleSettingSelectBox.html +38 -38
- package/docs/classes/SubtitleSettingsPanelPage.html +33 -33
- package/docs/classes/SubtitleSettingsResetButton.html +27 -27
- package/docs/classes/TitleBar.html +31 -31
- package/docs/classes/ToggleButton.html +35 -35
- package/docs/classes/UIContainer.html +31 -31
- package/docs/classes/UIInstanceManager.html +14 -14
- package/docs/classes/UIManager.html +14 -14
- package/docs/classes/VRToggleButton.html +35 -35
- package/docs/classes/VideoQualitySelectBox.html +39 -39
- package/docs/classes/VolumeControlButton.html +33 -33
- package/docs/classes/VolumeSlider.html +36 -36
- package/docs/classes/VolumeToggleButton.html +35 -35
- package/docs/classes/Watermark.html +28 -28
- package/docs/classes/WindowColorSelectBox.html +38 -38
- package/docs/classes/WindowOpacitySelectBox.html +38 -38
- package/docs/enums/ButtonStyle.html +5 -5
- package/docs/enums/LabelStyle.html +4 -4
- package/docs/enums/MetadataLabelContent.html +3 -3
- package/docs/enums/NavigationDirection.html +2 -2
- package/docs/enums/PlaybackTimeLabelMode.html +5 -5
- package/docs/enums/PlayerUtils.PlayerState.html +2 -2
- package/docs/enums/UIUtils.KeyCode.html +2 -2
- package/docs/enums/ViewMode.html +3 -3
- package/docs/functions/ArrayUtils.remove.html +1 -1
- package/docs/functions/ErrorUtils.defaultMobileV3ErrorMessageTranslator.html +1 -1
- package/docs/functions/PlayerUtils.clampValueToRange.html +1 -1
- package/docs/functions/PlayerUtils.getCurrentTimeRelativeToSeekableRange.html +1 -1
- package/docs/functions/PlayerUtils.getSeekableRangeRespectingLive.html +1 -1
- package/docs/functions/PlayerUtils.getSeekableRangeStart.html +1 -1
- package/docs/functions/PlayerUtils.getState.html +1 -1
- package/docs/functions/PlayerUtils.isTimeShiftAvailable.html +1 -1
- package/docs/functions/StorageUtils.getItem.html +1 -1
- package/docs/functions/StorageUtils.getObject.html +1 -1
- package/docs/functions/StorageUtils.setItem.html +1 -1
- package/docs/functions/StorageUtils.setObject.html +1 -1
- package/docs/functions/StorageUtils.setStorageApiDisabled.html +1 -1
- package/docs/functions/StringUtils.replaceAdMessagePlaceholders.html +1 -1
- package/docs/functions/StringUtils.secondsToText.html +1 -1
- package/docs/functions/StringUtils.secondsToTime.html +1 -1
- package/docs/functions/UIFactory.buildCastReceiverUI.html +1 -1
- package/docs/functions/UIFactory.buildSmallScreenUI.html +1 -1
- package/docs/functions/UIFactory.buildSubtitleUI.html +1 -1
- package/docs/functions/UIFactory.buildTvUI.html +1 -1
- package/docs/functions/UIFactory.buildUI.html +1 -1
- package/docs/functions/UIUtils.traverseTree.html +1 -1
- package/docs/hierarchy.html +1 -1
- package/docs/interfaces/ActiveUiChangedArgs.html +3 -3
- package/docs/interfaces/AdControlBarConfig.html +12 -12
- package/docs/interfaces/AdSkipButtonConfig.html +16 -16
- package/docs/interfaces/BufferingOverlayConfig.html +13 -13
- package/docs/interfaces/ButtonConfig.html +14 -14
- package/docs/interfaces/ClickOverlayConfig.html +15 -15
- package/docs/interfaces/CloseButtonConfig.html +15 -15
- package/docs/interfaces/ComponentConfig.html +11 -11
- package/docs/interfaces/ComponentFocusChangedEventArgs.html +2 -2
- package/docs/interfaces/ComponentHoverChangedEventArgs.html +2 -2
- package/docs/interfaces/ContainerConfig.html +12 -12
- package/docs/interfaces/ControlBarConfig.html +12 -12
- package/docs/interfaces/DynamicSettingsPanelItemConfig.html +19 -19
- package/docs/interfaces/ErrorMessageMap.html +1 -1
- package/docs/interfaces/ErrorMessageOverlayConfig.html +13 -13
- package/docs/interfaces/ErrorMessageTranslator.html +1 -1
- package/docs/interfaces/ExternalRecommendationLink.html +3 -3
- package/docs/interfaces/IconConfig.html +12 -12
- package/docs/interfaces/InternalUIConfig.html +15 -15
- package/docs/interfaces/LabelConfig.html +14 -14
- package/docs/interfaces/ListBoxConfig.html +22 -17
- package/docs/interfaces/ListItem.html +2 -2
- package/docs/interfaces/ListItemFilter.html +1 -1
- package/docs/interfaces/ListItemLabelTranslator.html +1 -1
- package/docs/interfaces/ListSelectorConfig.html +11 -11
- package/docs/interfaces/LocalizationConfig.html +3 -3
- package/docs/interfaces/MetadataLabelConfig.html +15 -15
- package/docs/interfaces/PlaybackTimeLabelConfig.html +16 -16
- package/docs/interfaces/PlaybackToggleButtonConfig.html +19 -19
- package/docs/interfaces/PlaybackToggleOverlayConfig.html +13 -13
- package/docs/interfaces/PlayerUtils.LiveStreamDetectorEventArgs.html +2 -2
- package/docs/interfaces/PlayerUtils.TimeShiftAvailabilityChangedArgs.html +2 -2
- package/docs/interfaces/QuickSeekButtonConfig.html +15 -15
- package/docs/interfaces/RecommendationConfig.html +4 -4
- package/docs/interfaces/RecommendationItemConfig.html +12 -12
- package/docs/interfaces/SeekBarConfig.html +19 -19
- package/docs/interfaces/SeekBarLabelConfig.html +12 -12
- package/docs/interfaces/SeekBarMarker.html +2 -2
- package/docs/interfaces/SeekPreviewArgs.html +3 -3
- package/docs/interfaces/SeekPreviewEventArgs.html +4 -4
- package/docs/interfaces/SettingsPanelConfig.html +20 -15
- package/docs/interfaces/SettingsPanelItemConfig.html +17 -17
- package/docs/interfaces/SettingsPanelPageConfig.html +13 -13
- package/docs/interfaces/SettingsToggleButtonConfig.html +20 -20
- package/docs/interfaces/SubtitleSettingSelectBoxConfig.html +11 -11
- package/docs/interfaces/SubtitleSettingsPanelPageConfig.html +13 -13
- package/docs/interfaces/TimelineMarker.html +6 -6
- package/docs/interfaces/TitleBarConfig.html +13 -13
- package/docs/interfaces/ToggleButtonConfig.html +18 -18
- package/docs/interfaces/UIConditionContext.html +10 -10
- package/docs/interfaces/UIConditionResolver.html +1 -1
- package/docs/interfaces/UIConfig.html +14 -14
- package/docs/interfaces/UIContainerConfig.html +20 -16
- package/docs/interfaces/UIUtils.TreeTraversalCallback.html +1 -1
- package/docs/interfaces/UIVariant.html +2 -2
- package/docs/interfaces/ViewModeChangedEventArgs.html +2 -2
- package/docs/interfaces/Vocabularies.html +1 -1
- package/docs/interfaces/Vocabulary.html +2 -2
- package/docs/interfaces/VolumeControlButtonConfig.html +14 -14
- package/docs/interfaces/VolumeSliderConfig.html +21 -21
- package/docs/interfaces/WatermarkConfig.html +15 -15
- package/docs/interfaces/WrappedPlayer.html +2 -2
- package/docs/media/CHANGELOG.md +20 -0
- package/docs/types/CustomVocabulary.html +1 -1
- package/docs/types/LocalizableText.html +1 -1
- package/docs/types/Localizer.html +1 -1
- package/docs/variables/ErrorUtils.defaultErrorMessages.html +1 -1
- package/docs/variables/ErrorUtils.defaultWebErrorMessageTranslator.html +1 -1
- package/docs/variables/StringUtils.FORMAT_HHMMSS.html +1 -1
- package/docs/variables/StringUtils.FORMAT_MMSS.html +1 -1
- package/docs/variables/i18n.html +1 -1
- package/docs/variables/version.html +1 -1
- package/package.json +1 -1
- package/src/ts/DOM.ts +18 -18
- package/src/ts/EventDispatcher.ts +5 -5
- package/src/ts/UIFactory.ts +8 -9
- package/src/ts/UIManager.ts +29 -29
- package/src/ts/components/CastUIContainer.ts +6 -6
- package/src/ts/components/Component.ts +3 -3
- package/src/ts/components/Container.ts +5 -5
- package/src/ts/components/RecommendationItem.ts +2 -2
- package/src/ts/components/TvNoiseCanvas.ts +3 -3
- package/src/ts/components/UIContainer.ts +57 -14
- package/src/ts/components/ads/AdClickOverlay.ts +2 -2
- package/src/ts/components/ads/AdMessageLabel.ts +47 -20
- package/src/ts/components/ads/AdSkipButton.ts +5 -5
- package/src/ts/components/buttons/Button.ts +1 -1
- package/src/ts/components/buttons/CastToggleButton.ts +1 -1
- package/src/ts/components/buttons/CloseButton.ts +1 -1
- package/src/ts/components/buttons/HugePlaybackToggleButton.ts +3 -3
- package/src/ts/components/buttons/PlaybackToggleButton.ts +3 -3
- package/src/ts/components/buttons/QuickSeekButton.ts +1 -1
- package/src/ts/components/buttons/SmallCenteredPlaybackToggleButton.ts +1 -1
- package/src/ts/components/buttons/VRToggleButton.ts +4 -4
- package/src/ts/components/buttons/VolumeControlButton.ts +2 -2
- package/src/ts/components/labels/Label.ts +1 -1
- package/src/ts/components/labels/MetadataLabel.ts +4 -4
- package/src/ts/components/labels/PlaybackTimeLabel.ts +13 -13
- package/src/ts/components/lists/ItemSelectionList.ts +3 -3
- package/src/ts/components/lists/ListSelector.ts +4 -4
- package/src/ts/components/overlays/CastStatusOverlay.ts +2 -2
- package/src/ts/components/overlays/ClickOverlay.ts +1 -1
- package/src/ts/components/overlays/DismissClickOverlay.ts +7 -2
- package/src/ts/components/overlays/ErrorMessageOverlay.ts +2 -2
- package/src/ts/components/overlays/RecommendationOverlay.ts +2 -2
- package/src/ts/components/overlays/SubtitleOverlay.ts +10 -10
- package/src/ts/components/seekbar/SeekBar.ts +37 -37
- package/src/ts/components/seekbar/SeekBarLabel.ts +15 -15
- package/src/ts/components/seekbar/VolumeSlider.ts +1 -1
- package/src/ts/components/settings/AudioQualitySelectBox.ts +4 -4
- package/src/ts/components/settings/DynamicSettingsPanelItem.ts +3 -3
- package/src/ts/components/settings/SelectBox.ts +3 -3
- package/src/ts/components/settings/SettingsPanel.ts +137 -10
- package/src/ts/components/settings/SettingsPanelItem.ts +1 -1
- package/src/ts/components/settings/SettingsPanelPage.ts +4 -4
- package/src/ts/components/settings/SettingsPanelSelectOption.ts +1 -1
- package/src/ts/components/settings/SettingsToggleButton.ts +3 -3
- package/src/ts/components/settings/VideoQualitySelectBox.ts +4 -4
- package/src/ts/components/settings/subtitlesettings/BackgroundColorSelectBox.ts +1 -1
- package/src/ts/components/settings/subtitlesettings/FontColorSelectBox.ts +1 -1
- package/src/ts/components/settings/subtitlesettings/WindowColorSelectBox.ts +1 -1
- package/src/ts/main.ts +2 -2
- package/src/ts/spatialnavigation/NavigationGroup.ts +2 -2
- package/src/ts/spatialnavigation/SettingsPanelNavigationGroup.ts +1 -1
- package/src/ts/utils/ArrayUtils.ts +1 -1
- package/src/ts/utils/AudioTrackUtils.ts +1 -1
- package/src/ts/utils/ImageLoader.ts +2 -2
- package/src/ts/utils/PlayerUtils.ts +4 -4
- package/src/ts/utils/StorageUtils.ts +3 -3
- package/src/ts/utils/StringUtils.ts +17 -17
- package/src/ts/utils/SubtitleSettingsManager.ts +3 -3
- package/src/ts/utils/SubtitleUtils.ts +1 -1
- package/src/ts/utils/UIUtils.ts +2 -2
package/src/ts/UIManager.ts
CHANGED
|
@@ -158,8 +158,8 @@ export class UIManager {
|
|
|
158
158
|
constructor(player: PlayerAPI, playerUiOrUiVariants: UIContainer | UIVariant[], uiconfig: UIConfig = {}) {
|
|
159
159
|
if (playerUiOrUiVariants instanceof UIContainer) {
|
|
160
160
|
// Single-UI constructor has been called, transform arguments to UIVariant[] signature
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
const playerUi = <UIContainer>playerUiOrUiVariants;
|
|
162
|
+
const uiVariants = [];
|
|
163
163
|
|
|
164
164
|
// Add the default player UI
|
|
165
165
|
uiVariants.push({ ui: playerUi });
|
|
@@ -252,8 +252,8 @@ export class UIManager {
|
|
|
252
252
|
// Create UI instance managers for the UI variants
|
|
253
253
|
// The instance managers map to the corresponding UI variants by their array index
|
|
254
254
|
this.uiInstanceManagers = [];
|
|
255
|
-
|
|
256
|
-
for (
|
|
255
|
+
const uiVariantsWithoutCondition = [];
|
|
256
|
+
for (const uiVariant of this.uiVariants) {
|
|
257
257
|
if (uiVariant.condition == null) {
|
|
258
258
|
// Collect variants without conditions for error checking
|
|
259
259
|
uiVariantsWithoutCondition.push(uiVariant);
|
|
@@ -296,7 +296,7 @@ export class UIManager {
|
|
|
296
296
|
});
|
|
297
297
|
|
|
298
298
|
// Dynamically select a UI variant that matches the current UI condition.
|
|
299
|
-
|
|
299
|
+
const resolveUiVariant = (event: PlayerEventBase) => {
|
|
300
300
|
// Make sure that the AdStarted event data is persisted through ad playback in case other events happen
|
|
301
301
|
// in the meantime, e.g. player resize. We need to store this data because there is no other way to find out
|
|
302
302
|
// ad details while an ad is playing (in v8.0 at least; from v8.1 there will be ads.getActiveAd()).
|
|
@@ -338,13 +338,13 @@ export class UIManager {
|
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
// Detect if an ad has started
|
|
341
|
-
|
|
341
|
+
const isAd = adStartedEvent != null;
|
|
342
342
|
let adRequiresUi = false;
|
|
343
343
|
if (isAd) {
|
|
344
|
-
|
|
344
|
+
const ad = adStartedEvent.ad;
|
|
345
345
|
// for now only linear ads can request a UI
|
|
346
346
|
if (ad.isLinear) {
|
|
347
|
-
|
|
347
|
+
const linearAd = ad as LinearAd;
|
|
348
348
|
adRequiresUi = (linearAd.uiConfig && linearAd.uiConfig.requestsUi) || false;
|
|
349
349
|
}
|
|
350
350
|
}
|
|
@@ -436,7 +436,7 @@ export class UIManager {
|
|
|
436
436
|
* @param {() => void} onShow a callback that is executed just before the new UI variant is shown
|
|
437
437
|
*/
|
|
438
438
|
switchToUiVariant(uiVariant: UIVariant, onShow?: () => void): void {
|
|
439
|
-
|
|
439
|
+
const uiVariantIndex = this.uiVariants.indexOf(uiVariant);
|
|
440
440
|
|
|
441
441
|
const previousUi = this.currentUi;
|
|
442
442
|
const nextUi: InternalUIInstanceManager = this.uiInstanceManagers[uiVariantIndex];
|
|
@@ -508,7 +508,7 @@ export class UIManager {
|
|
|
508
508
|
|
|
509
509
|
// Select new UI variant
|
|
510
510
|
// If no variant condition is fulfilled, we switch to *no* UI
|
|
511
|
-
for (
|
|
511
|
+
for (const uiVariant of this.uiVariants) {
|
|
512
512
|
const matchesCondition = uiVariant.condition == null || uiVariant.condition(switchingContext) === true;
|
|
513
513
|
if (nextUiVariant == null && matchesCondition) {
|
|
514
514
|
nextUiVariant = uiVariant;
|
|
@@ -526,8 +526,8 @@ export class UIManager {
|
|
|
526
526
|
}
|
|
527
527
|
|
|
528
528
|
private addUi(ui: InternalUIInstanceManager): void {
|
|
529
|
-
|
|
530
|
-
|
|
529
|
+
const dom = ui.getUI().getDomElement();
|
|
530
|
+
const player = ui.getWrappedPlayer();
|
|
531
531
|
|
|
532
532
|
ui.configureControls();
|
|
533
533
|
/* Append the UI DOM after configuration to avoid CSS transitions at initialization
|
|
@@ -567,7 +567,7 @@ export class UIManager {
|
|
|
567
567
|
}
|
|
568
568
|
|
|
569
569
|
release(): void {
|
|
570
|
-
for (
|
|
570
|
+
for (const uiInstanceManager of this.uiInstanceManagers) {
|
|
571
571
|
this.releaseUi(uiInstanceManager);
|
|
572
572
|
}
|
|
573
573
|
this.managerPlayerWrapper.clearEventHandlers();
|
|
@@ -799,9 +799,9 @@ export class UIInstanceManager {
|
|
|
799
799
|
protected clearEventHandlers(): void {
|
|
800
800
|
this.playerWrapper.clearEventHandlers();
|
|
801
801
|
|
|
802
|
-
|
|
803
|
-
for (
|
|
804
|
-
|
|
802
|
+
const events = <any>this.events; // avoid TS7017
|
|
803
|
+
for (const event in events) {
|
|
804
|
+
const dispatcher = <EventDispatcher<Object, Object>>events[event];
|
|
805
805
|
dispatcher.unsubscribeAll();
|
|
806
806
|
}
|
|
807
807
|
}
|
|
@@ -832,7 +832,7 @@ class InternalUIInstanceManager extends UIInstanceManager {
|
|
|
832
832
|
}
|
|
833
833
|
|
|
834
834
|
private configureControlsTree(component: Component<ComponentConfig>) {
|
|
835
|
-
|
|
835
|
+
const configuredComponents: Component<ComponentConfig>[] = [];
|
|
836
836
|
|
|
837
837
|
UIUtils.traverseTree(component, component => {
|
|
838
838
|
// First, check if we have already configured a component, and throw an error if we did. Multiple configuration
|
|
@@ -840,7 +840,7 @@ class InternalUIInstanceManager extends UIInstanceManager {
|
|
|
840
840
|
// times hints at a wrong UI structure.
|
|
841
841
|
// We could just skip configuration in such a case and not throw an exception, but enforcing a clean UI tree
|
|
842
842
|
// seems like the better choice.
|
|
843
|
-
for (
|
|
843
|
+
for (const configuredComponent of configuredComponents) {
|
|
844
844
|
if (configuredComponent === component) {
|
|
845
845
|
// Write the component to the console to simplify identification of the culprit
|
|
846
846
|
// (e.g. by inspecting the config)
|
|
@@ -878,7 +878,7 @@ class InternalUIInstanceManager extends UIInstanceManager {
|
|
|
878
878
|
component.release();
|
|
879
879
|
|
|
880
880
|
if (component instanceof Container) {
|
|
881
|
-
for (
|
|
881
|
+
for (const childComponent of component.getComponents()) {
|
|
882
882
|
this.releaseControlsTree(childComponent);
|
|
883
883
|
}
|
|
884
884
|
}
|
|
@@ -921,10 +921,10 @@ export class PlayerWrapper {
|
|
|
921
921
|
const namesToIgnore = ['constructor', ...objectProtoPropertyNames];
|
|
922
922
|
const members = getAllPropertyNames(player).filter(name => namesToIgnore.indexOf(name) === -1);
|
|
923
923
|
// Split the members into methods and properties
|
|
924
|
-
|
|
925
|
-
|
|
924
|
+
const methods = <any[]>[];
|
|
925
|
+
const properties = <any[]>[];
|
|
926
926
|
|
|
927
|
-
for (
|
|
927
|
+
for (const member of members) {
|
|
928
928
|
if (typeof (<any>player)[member] === 'function') {
|
|
929
929
|
methods.push(member);
|
|
930
930
|
} else {
|
|
@@ -933,10 +933,10 @@ export class PlayerWrapper {
|
|
|
933
933
|
}
|
|
934
934
|
|
|
935
935
|
// Create wrapper object
|
|
936
|
-
|
|
936
|
+
const wrapper = <any>{};
|
|
937
937
|
|
|
938
938
|
// Add function wrappers for all API methods that do nothing but calling the base method on the player
|
|
939
|
-
for (
|
|
939
|
+
for (const method of methods) {
|
|
940
940
|
wrapper[method] = function () {
|
|
941
941
|
// console.log('called ' + member); // track method calls on the player
|
|
942
942
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
@@ -945,7 +945,7 @@ export class PlayerWrapper {
|
|
|
945
945
|
}
|
|
946
946
|
|
|
947
947
|
// Add all public properties of the player to the wrapper
|
|
948
|
-
for (
|
|
948
|
+
for (const property of properties) {
|
|
949
949
|
// Get an eventually existing property descriptor to differentiate between plain properties and properties with
|
|
950
950
|
// getters/setters.
|
|
951
951
|
const propertyDescriptor = ((target: PlayerAPI) => {
|
|
@@ -1000,7 +1000,7 @@ export class PlayerWrapper {
|
|
|
1000
1000
|
if (this.eventHandlers[event]) {
|
|
1001
1001
|
// check if there are handlers for this event registered
|
|
1002
1002
|
// Extend the data object with default values to convert it to a {@link PlayerEventBase} object.
|
|
1003
|
-
|
|
1003
|
+
const playerEventData = <PlayerEventBase>Object.assign(
|
|
1004
1004
|
{},
|
|
1005
1005
|
{
|
|
1006
1006
|
timestamp: Date.now(),
|
|
@@ -1012,7 +1012,7 @@ export class PlayerWrapper {
|
|
|
1012
1012
|
);
|
|
1013
1013
|
|
|
1014
1014
|
// Execute the registered callbacks
|
|
1015
|
-
for (
|
|
1015
|
+
for (const callback of this.eventHandlers[event]) {
|
|
1016
1016
|
callback(playerEventData);
|
|
1017
1017
|
}
|
|
1018
1018
|
}
|
|
@@ -1045,8 +1045,8 @@ export class PlayerWrapper {
|
|
|
1045
1045
|
}
|
|
1046
1046
|
}
|
|
1047
1047
|
|
|
1048
|
-
for (
|
|
1049
|
-
for (
|
|
1048
|
+
for (const eventType in this.eventHandlers) {
|
|
1049
|
+
for (const callback of this.eventHandlers[eventType]) {
|
|
1050
1050
|
this.player.off(eventType as PlayerEvent, callback);
|
|
1051
1051
|
}
|
|
1052
1052
|
}
|
|
@@ -19,7 +19,7 @@ export class CastUIContainer extends UIContainer {
|
|
|
19
19
|
configure(player: PlayerAPI, uimanager: UIInstanceManager): void {
|
|
20
20
|
super.configure(player, uimanager);
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
const config = this.getConfig();
|
|
23
23
|
|
|
24
24
|
/*
|
|
25
25
|
* Show UI on Cast devices at certain playback events
|
|
@@ -33,31 +33,31 @@ export class CastUIContainer extends UIContainer {
|
|
|
33
33
|
|
|
34
34
|
let isUiShown = false;
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
const hideUi = () => {
|
|
37
37
|
uimanager.onControlsHide.dispatch(this);
|
|
38
38
|
isUiShown = false;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
this.castUiHideTimeout = new Timeout(config.hideDelay, hideUi);
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
const showUi = () => {
|
|
44
44
|
if (!isUiShown) {
|
|
45
45
|
uimanager.onControlsShow.dispatch(this);
|
|
46
46
|
isUiShown = true;
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
const showUiPermanently = () => {
|
|
51
51
|
showUi();
|
|
52
52
|
this.castUiHideTimeout.clear();
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
const showUiWithTimeout = () => {
|
|
56
56
|
showUi();
|
|
57
57
|
this.castUiHideTimeout.start();
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
const showUiAfterSeek = () => {
|
|
61
61
|
if (player.isPlaying()) {
|
|
62
62
|
showUiWithTimeout();
|
|
63
63
|
} else {
|
|
@@ -308,7 +308,7 @@ export class Component<Config extends ComponentConfig> {
|
|
|
308
308
|
* Subclasses usually overwrite this method to extend or replace the DOM element with their own design.
|
|
309
309
|
*/
|
|
310
310
|
protected toDomElement(): DOM {
|
|
311
|
-
|
|
311
|
+
const element = new DOM(
|
|
312
312
|
this.config.tag,
|
|
313
313
|
{
|
|
314
314
|
id: this.config.id,
|
|
@@ -365,7 +365,7 @@ export class Component<Config extends ComponentConfig> {
|
|
|
365
365
|
*/
|
|
366
366
|
protected mergeConfig<Config>(config: Config, defaults: Partial<Config>, base: Config): Config {
|
|
367
367
|
// Extend default config with supplied config
|
|
368
|
-
|
|
368
|
+
const merged = Object.assign({}, base, defaults, config);
|
|
369
369
|
|
|
370
370
|
// Return the extended config
|
|
371
371
|
return merged;
|
|
@@ -384,7 +384,7 @@ export class Component<Config extends ComponentConfig> {
|
|
|
384
384
|
return this.prefixCss(css);
|
|
385
385
|
});
|
|
386
386
|
// Join array values into a string
|
|
387
|
-
|
|
387
|
+
const flattenedString = flattenedArray.join(' ');
|
|
388
388
|
// Return trimmed string to prevent whitespace at the end from the join operation
|
|
389
389
|
return flattenedString.trim();
|
|
390
390
|
}
|
|
@@ -40,7 +40,7 @@ export class Container<Config extends ContainerConfig> extends Component<Config>
|
|
|
40
40
|
/**
|
|
41
41
|
* A reference to the inner element that contains the components of the container.
|
|
42
42
|
*/
|
|
43
|
-
|
|
43
|
+
protected innerContainerElement: DOM;
|
|
44
44
|
private componentsToAppend: Component<ComponentConfig>[];
|
|
45
45
|
private componentsToPrepend: Component<ComponentConfig>[];
|
|
46
46
|
private componentsToRemove: Component<ComponentConfig>[];
|
|
@@ -108,7 +108,7 @@ export class Container<Config extends ContainerConfig> extends Component<Config>
|
|
|
108
108
|
* Removes all child components from the container.
|
|
109
109
|
*/
|
|
110
110
|
removeComponents(): void {
|
|
111
|
-
for (
|
|
111
|
+
for (const component of this.getComponents().slice()) {
|
|
112
112
|
this.removeComponent(component);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
@@ -144,7 +144,7 @@ export class Container<Config extends ContainerConfig> extends Component<Config>
|
|
|
144
144
|
|
|
145
145
|
protected toDomElement(): DOM {
|
|
146
146
|
// Create the container element (the outer <div>)
|
|
147
|
-
|
|
147
|
+
const containerElement = new DOM(
|
|
148
148
|
this.config.tag,
|
|
149
149
|
{
|
|
150
150
|
id: this.config.id,
|
|
@@ -160,12 +160,12 @@ export class Container<Config extends ContainerConfig> extends Component<Config>
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
// Create the inner container element (the inner <div>) that will contain the components
|
|
163
|
-
|
|
163
|
+
const innerContainer = new DOM(this.config.tag, {
|
|
164
164
|
class: this.prefixCss('container-wrapper'),
|
|
165
165
|
});
|
|
166
166
|
this.innerContainerElement = innerContainer;
|
|
167
167
|
|
|
168
|
-
for (
|
|
168
|
+
for (const initialComponent of this.config.components) {
|
|
169
169
|
this.componentsToAppend.push(initialComponent);
|
|
170
170
|
}
|
|
171
171
|
this.updateComponents();
|
|
@@ -91,12 +91,12 @@ export class RecommendationItem extends Component<RecommendationItemConfig> {
|
|
|
91
91
|
this,
|
|
92
92
|
);
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
const innerTitleElement = new Label({ text: recommendationConfig.title, cssClass: 'title' });
|
|
95
95
|
titleElement.append(innerTitleElement.getDomElement());
|
|
96
96
|
itemElement.append(titleElement);
|
|
97
97
|
|
|
98
98
|
if (recommendationConfig.duration != null) {
|
|
99
|
-
|
|
99
|
+
const timeElement = new Label({
|
|
100
100
|
text: recommendationConfig.duration ? StringUtils.secondsToTime(recommendationConfig.duration) : '',
|
|
101
101
|
cssClass: 'duration',
|
|
102
102
|
});
|
|
@@ -66,11 +66,11 @@ export class TvNoiseCanvas extends Component<ComponentConfig> {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
let currentPixelOffset;
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
const canvasWidth = this.canvasWidth;
|
|
70
|
+
const canvasHeight = this.canvasHeight;
|
|
71
71
|
|
|
72
72
|
// Create texture
|
|
73
|
-
|
|
73
|
+
const noiseImage = this.canvasContext.createImageData(canvasWidth, canvasHeight);
|
|
74
74
|
|
|
75
75
|
// Fill texture with noise
|
|
76
76
|
for (let y = 0; y < canvasHeight; y++) {
|
|
@@ -8,6 +8,8 @@ import { PlayerAPI, PlayerResizedEvent } from 'bitmovin-player';
|
|
|
8
8
|
import { i18n } from '../localization/i18n';
|
|
9
9
|
import { Button, ButtonConfig } from './buttons/Button';
|
|
10
10
|
import { TouchControlOverlay, TouchControlOverlayConfig } from './overlays/TouchControlOverlay';
|
|
11
|
+
import { Component, ComponentConfig } from './Component';
|
|
12
|
+
import { SettingsPanel } from './settings/SettingsPanel';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Configuration interface for a {@link UIContainer}.
|
|
@@ -38,6 +40,13 @@ export interface UIContainerConfig extends ContainerConfig {
|
|
|
38
40
|
* Default: true
|
|
39
41
|
*/
|
|
40
42
|
hideImmediatelyOnMouseLeave?: boolean;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* When true, suspend the UIContainer's hide timer while a SettingsPanel is open,
|
|
46
|
+
* and resume it when the panel closes.
|
|
47
|
+
* Default: true
|
|
48
|
+
*/
|
|
49
|
+
deferUiHideWhileSettingsOpen?: boolean;
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/**
|
|
@@ -62,7 +71,7 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
62
71
|
private userInteractionEvents: { name: string; handler: EventListenerOrEventListenerObject }[];
|
|
63
72
|
private hidingPrevented: () => boolean;
|
|
64
73
|
|
|
65
|
-
public hideUi: () => void = () => {};
|
|
74
|
+
public hideUi: (force?: boolean) => void = () => {};
|
|
66
75
|
public showUi: () => void = () => {};
|
|
67
76
|
public toggleUiShown: () => void = () => {};
|
|
68
77
|
|
|
@@ -77,6 +86,7 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
77
86
|
ariaLabel: i18n.getLocalizer('player'),
|
|
78
87
|
hideDelay: 2000,
|
|
79
88
|
hideImmediatelyOnMouseLeave: true,
|
|
89
|
+
deferUiHideWhileSettingsOpen: true,
|
|
80
90
|
},
|
|
81
91
|
this.config,
|
|
82
92
|
);
|
|
@@ -101,8 +111,10 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
private configureUIShowHide(player: PlayerAPI, uimanager: UIInstanceManager): void {
|
|
104
|
-
|
|
114
|
+
const config = this.getConfig();
|
|
105
115
|
let isUiShown = false;
|
|
116
|
+
let isSettingsPanelShown = false;
|
|
117
|
+
let isHideUiPending = false;
|
|
106
118
|
|
|
107
119
|
uimanager.onConfigured.subscribe(() => {
|
|
108
120
|
if (isUiShown) {
|
|
@@ -121,11 +133,31 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
121
133
|
let isFirstTouch = true;
|
|
122
134
|
let playerState: PlayerUtils.PlayerState;
|
|
123
135
|
|
|
136
|
+
if (config.deferUiHideWhileSettingsOpen) {
|
|
137
|
+
uimanager.onComponentShow.subscribe((component: Component<ComponentConfig>) => {
|
|
138
|
+
if (component instanceof SettingsPanel) {
|
|
139
|
+
isSettingsPanelShown = true;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
uimanager.onComponentHide.subscribe((component: Component<ComponentConfig>) => {
|
|
143
|
+
if (component instanceof SettingsPanel) {
|
|
144
|
+
isSettingsPanelShown = false;
|
|
145
|
+
|
|
146
|
+
if (isHideUiPending) {
|
|
147
|
+
this.hideUi(true);
|
|
148
|
+
isHideUiPending = false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
124
154
|
this.hidingPrevented = (): boolean => {
|
|
125
155
|
return config.hidePlayerStateExceptions && config.hidePlayerStateExceptions.indexOf(playerState) > -1;
|
|
126
156
|
};
|
|
127
157
|
|
|
128
158
|
this.showUi = () => {
|
|
159
|
+
isHideUiPending = false;
|
|
160
|
+
|
|
129
161
|
if (!isUiShown) {
|
|
130
162
|
// Let subscribers know that they should reveal themselves
|
|
131
163
|
uimanager.onControlsShow.dispatch(this);
|
|
@@ -137,11 +169,22 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
137
169
|
}
|
|
138
170
|
};
|
|
139
171
|
|
|
140
|
-
this.hideUi = () => {
|
|
172
|
+
this.hideUi = (force: boolean = false) => {
|
|
141
173
|
// Hide the UI only if it is shown, and if not casting
|
|
142
174
|
if (isUiShown && !player.isCasting()) {
|
|
175
|
+
if (force) {
|
|
176
|
+
uimanager.onControlsHide.dispatch(this);
|
|
177
|
+
isUiShown = false;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (config.deferUiHideWhileSettingsOpen && isSettingsPanelShown) {
|
|
182
|
+
isHideUiPending = true;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
143
186
|
// Issue a preview event to check if we are good to hide the controls
|
|
144
|
-
|
|
187
|
+
const previewHideEventArgs = <CancelEventArgs>{};
|
|
145
188
|
uimanager.onPreviewControlsHide.dispatch(this, previewHideEventArgs);
|
|
146
189
|
|
|
147
190
|
if (!previewHideEventArgs.cancel) {
|
|
@@ -271,7 +314,7 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
271
314
|
// hide the UI in such cases
|
|
272
315
|
if (!isSeeking && !this.hidingPrevented()) {
|
|
273
316
|
if (this.config.hideImmediatelyOnMouseLeave) {
|
|
274
|
-
this.hideUi();
|
|
317
|
+
this.hideUi(true);
|
|
275
318
|
} else {
|
|
276
319
|
this.uiHideTimeout.start();
|
|
277
320
|
}
|
|
@@ -330,20 +373,20 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
330
373
|
}
|
|
331
374
|
|
|
332
375
|
private configurePlayerStates(player: PlayerAPI, uimanager: UIInstanceManager): void {
|
|
333
|
-
|
|
376
|
+
const container = this.getDomElement();
|
|
334
377
|
|
|
335
378
|
// Convert player states into CSS class names
|
|
336
|
-
|
|
337
|
-
for (
|
|
379
|
+
const stateClassNames = <any>[];
|
|
380
|
+
for (const state in PlayerUtils.PlayerState) {
|
|
338
381
|
if (isNaN(Number(state))) {
|
|
339
|
-
|
|
382
|
+
const enumName = PlayerUtils.PlayerState[<any>PlayerUtils.PlayerState[state]];
|
|
340
383
|
stateClassNames[PlayerUtils.PlayerState[state]] = this.prefixCss(
|
|
341
384
|
UIContainer.STATE_PREFIX + enumName.toLowerCase(),
|
|
342
385
|
);
|
|
343
386
|
}
|
|
344
387
|
}
|
|
345
388
|
|
|
346
|
-
|
|
389
|
+
const removeStates = () => {
|
|
347
390
|
container.removeClass(stateClassNames[PlayerUtils.PlayerState.Idle]);
|
|
348
391
|
container.removeClass(stateClassNames[PlayerUtils.PlayerState.Prepared]);
|
|
349
392
|
container.removeClass(stateClassNames[PlayerUtils.PlayerState.Playing]);
|
|
@@ -427,7 +470,7 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
427
470
|
});
|
|
428
471
|
|
|
429
472
|
// Layout size classes
|
|
430
|
-
|
|
473
|
+
const updateLayoutSizeClasses = (width: number, height: number) => {
|
|
431
474
|
container.removeClass(this.prefixCss('layout-max-width-400'));
|
|
432
475
|
container.removeClass(this.prefixCss('layout-max-width-600'));
|
|
433
476
|
container.removeClass(this.prefixCss('layout-max-width-800'));
|
|
@@ -445,8 +488,8 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
445
488
|
};
|
|
446
489
|
player.on(player.exports.PlayerEvent.PlayerResized, (e: PlayerResizedEvent) => {
|
|
447
490
|
// Convert strings (with "px" suffix) to ints
|
|
448
|
-
|
|
449
|
-
|
|
491
|
+
const width = Math.round(Number(e.width.substring(0, e.width.length - 2)));
|
|
492
|
+
const height = Math.round(Number(e.height.substring(0, e.height.length - 2)));
|
|
450
493
|
|
|
451
494
|
updateLayoutSizeClasses(width, height);
|
|
452
495
|
});
|
|
@@ -481,7 +524,7 @@ export class UIContainer extends Container<UIContainerConfig> {
|
|
|
481
524
|
}
|
|
482
525
|
|
|
483
526
|
protected toDomElement(): DOM {
|
|
484
|
-
|
|
527
|
+
const container = super.toDomElement();
|
|
485
528
|
|
|
486
529
|
// Detect flexbox support (not supported in IE9)
|
|
487
530
|
if (document && typeof document.createElement('p').style.flex !== 'undefined') {
|
|
@@ -26,13 +26,13 @@ export class AdClickOverlay extends ClickOverlay {
|
|
|
26
26
|
let clickThroughCallback: () => void = null;
|
|
27
27
|
|
|
28
28
|
player.on(player.exports.PlayerEvent.AdStarted, (event: AdEvent) => {
|
|
29
|
-
|
|
29
|
+
const ad = event.ad;
|
|
30
30
|
this.setUrl(ad.clickThroughUrl);
|
|
31
31
|
clickThroughCallback = ad.clickThroughUrlOpened;
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
// Clear click-through URL when ad has finished
|
|
35
|
-
|
|
35
|
+
const adFinishedHandler = () => {
|
|
36
36
|
this.setUrl(null);
|
|
37
37
|
};
|
|
38
38
|
|
|
@@ -1,9 +1,30 @@
|
|
|
1
|
-
import { UIInstanceManager } from '../../UIManager';
|
|
2
|
-
import { AdEvent, LinearAd, PlayerAPI } from 'bitmovin-player';
|
|
3
1
|
import { Label, LabelConfig } from '../labels/Label';
|
|
2
|
+
import { i18n } from '../../localization/i18n';
|
|
3
|
+
import { AdEvent, LinearAd, PlayerAPI } from 'bitmovin-player';
|
|
4
|
+
import { UIInstanceManager } from '../../UIManager';
|
|
5
|
+
import { StringUtils } from '../../utils/StringUtils';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* A label that displays a message
|
|
8
|
+
* A label that displays a message about a running ad, optionally with a countdown.
|
|
9
|
+
*
|
|
10
|
+
* The message text supports placeholders that are dynamically replaced with ad timing information:
|
|
11
|
+
* - `{remainingTime[formatString]}` - Remaining time until the ad ends
|
|
12
|
+
* - `{playedTime[formatString]}` - Current playback time of the ad
|
|
13
|
+
* - `{adDuration[formatString]}` - Total duration of the current ad
|
|
14
|
+
* - `{adBreakRemainingTime[formatString]}` - Remaining time for the entire ad break (including all remaining ads)
|
|
15
|
+
*
|
|
16
|
+
* Format string options (optional):
|
|
17
|
+
* - `%d` - Integer (e.g., `{remainingTime%d}` → `100`)
|
|
18
|
+
* - `%0Nd` - Integer with N leading zeros (e.g., `{remainingTime%03d}` → `100`)
|
|
19
|
+
* - `%f` - Float (e.g., `{remainingTime%f}` → `100.0`)
|
|
20
|
+
* - `%0Nf` - Float with leading zeros (e.g., `{remainingTime%05f}` → `100.0`)
|
|
21
|
+
* - `%.Mf` - Float with M decimal places (e.g., `{remainingTime%.2f}` → `100.00`)
|
|
22
|
+
* - `%hh:mm:ss` - Time format with hours (e.g., `{remainingTime%hh:mm:ss}` → `00:01:40`)
|
|
23
|
+
* - `%mm:ss` - Time format without hours (e.g., `{remainingTime%mm:ss}` → `01:40`)
|
|
24
|
+
*
|
|
25
|
+
* Example: `{ text: 'Ad: {remainingTime%mm:ss}' }` displays "Ad: 01:40" for 100 seconds remaining.
|
|
26
|
+
*
|
|
27
|
+
* Note: If a LinearAd has a `uiConfig.message` property, it takes precedence over the configured `text`.
|
|
7
28
|
*
|
|
8
29
|
* @category Labels
|
|
9
30
|
*/
|
|
@@ -23,24 +44,30 @@ export class AdMessageLabel extends Label<LabelConfig> {
|
|
|
23
44
|
configure(player: PlayerAPI, uimanager: UIInstanceManager): void {
|
|
24
45
|
super.configure(player, uimanager);
|
|
25
46
|
|
|
26
|
-
const
|
|
27
|
-
|
|
47
|
+
const config = this.getConfig();
|
|
48
|
+
let text = config.text;
|
|
49
|
+
|
|
50
|
+
const updateMessageHandler = () => {
|
|
51
|
+
this.setText(StringUtils.replaceAdMessagePlaceholders(i18n.performLocalization(text), null, player));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const adStartHandler = (event: AdEvent) => {
|
|
55
|
+
const uiConfig = (event.ad as LinearAd).uiConfig;
|
|
56
|
+
text = uiConfig?.message || config.text;
|
|
57
|
+
|
|
58
|
+
updateMessageHandler();
|
|
59
|
+
|
|
60
|
+
player.on(player.exports.PlayerEvent.TimeChanged, updateMessageHandler);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const adEndHandler = () => {
|
|
64
|
+
player.off(player.exports.PlayerEvent.TimeChanged, updateMessageHandler);
|
|
28
65
|
};
|
|
29
66
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
player.on(player.exports.PlayerEvent.
|
|
33
|
-
player.on(player.exports.PlayerEvent.
|
|
34
|
-
player.on(player.exports.PlayerEvent.
|
|
35
|
-
player.on(player.exports.PlayerEvent.AdFinished, clearText);
|
|
36
|
-
player.on(player.exports.PlayerEvent.AdStarted, event => {
|
|
37
|
-
const ad = (event as AdEvent).ad;
|
|
38
|
-
if (!ad.isLinear) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const linearAd = ad as LinearAd;
|
|
43
|
-
this.setText(linearAd.uiConfig?.message ?? '');
|
|
44
|
-
});
|
|
67
|
+
player.on(player.exports.PlayerEvent.AdStarted, adStartHandler);
|
|
68
|
+
player.on(player.exports.PlayerEvent.AdSkipped, adEndHandler);
|
|
69
|
+
player.on(player.exports.PlayerEvent.AdError, adEndHandler);
|
|
70
|
+
player.on(player.exports.PlayerEvent.AdFinished, adEndHandler);
|
|
71
|
+
player.on(player.exports.PlayerEvent.SourceUnloaded, adEndHandler);
|
|
45
72
|
}
|
|
46
73
|
}
|
|
@@ -46,12 +46,12 @@ export class AdSkipButton extends Button<AdSkipButtonConfig> {
|
|
|
46
46
|
configure(player: PlayerAPI, uimanager: UIInstanceManager): void {
|
|
47
47
|
super.configure(player, uimanager);
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
const config = this.getConfig();
|
|
50
50
|
let untilSkippableMessage = config.untilSkippableMessage;
|
|
51
51
|
let skippableMessage = config.skippableMessage;
|
|
52
52
|
let skipOffset = -1;
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
const updateSkipMessageHandler = () => {
|
|
55
55
|
this.show();
|
|
56
56
|
|
|
57
57
|
// Update the skip message on the button
|
|
@@ -64,8 +64,8 @@ export class AdSkipButton extends Button<AdSkipButtonConfig> {
|
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
const adStartHandler = (event: AdEvent) => {
|
|
68
|
+
const ad = event.ad as LinearAd;
|
|
69
69
|
skipOffset = ad.skippableAfter;
|
|
70
70
|
untilSkippableMessage = (ad.uiConfig && ad.uiConfig.untilSkippableMessage) || config.untilSkippableMessage;
|
|
71
71
|
skippableMessage = (ad.uiConfig && ad.uiConfig.skippableMessage) || config.skippableMessage;
|
|
@@ -80,7 +80,7 @@ export class AdSkipButton extends Button<AdSkipButtonConfig> {
|
|
|
80
80
|
}
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
const adEndHandler = () => {
|
|
84
84
|
player.off(player.exports.PlayerEvent.TimeChanged, updateSkipMessageHandler);
|
|
85
85
|
};
|
|
86
86
|
|
|
@@ -99,7 +99,7 @@ export class Button<Config extends ButtonConfig> extends Component<Config> {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
// Create the button element with the text label
|
|
102
|
-
|
|
102
|
+
const buttonElement = new DOM('button', buttonElementAttributes, this);
|
|
103
103
|
|
|
104
104
|
const addIconElement = () => {
|
|
105
105
|
const icon = new Icon({ ariaLabel: this.config.ariaLabel, altText: this.config.text });
|
|
@@ -38,7 +38,7 @@ export class CloseButton extends Button<CloseButtonConfig> {
|
|
|
38
38
|
configure(player: PlayerAPI, uimanager: UIInstanceManager): void {
|
|
39
39
|
super.configure(player, uimanager);
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const config = this.getConfig();
|
|
42
42
|
|
|
43
43
|
this.onClick.subscribe(() => {
|
|
44
44
|
config.target.hide();
|