From cb0ba18e4b8c051ef754c0b76d7bdd2cbbc68298 Mon Sep 17 00:00:00 2001 From: Serhii Date: Mon, 18 Mar 2024 11:29:04 +0200 Subject: [PATCH] feat(FEC-13664): Add the ability to configure default alignment of captions on the player # (#769) ### Description of the Changes 1. Add `textAlign`: string (left/right/center) property to `config.text.textStyle`; 2. Remove `align` option form `config.text.textTrackDisplaySetting`; 3. Remove `forceCenter` option from `config.text` 4. upd documentation; 5. handle caption alignment based on `config.text.textStyle.textAlign` configuration; 6. upd tests; image ### CheckLists - [ ] changes have been done against master branch, and PR does not conflict - [ ] new unit / functional tests have been added (whenever applicable) - [ ] test are passing in local environment - [ ] Travis tests are passing (or test results are not worse than on master branch :)) - [ ] Docs have been updated --------- Co-authored-by: Sergey Marchenko --- docs/configuration.md | 23 ++---- flow-typed/types/text-config.js | 1 - .../types/text-track-display-setting.js | 1 - src/engines/html5/html5.ts | 9 +++ .../media-source/base-media-source-adapter.ts | 6 ++ src/player-config.js | 1 - src/player.ts | 70 ++++++++++--------- src/track/external-captions-handler.ts | 7 ++ src/track/text-style.ts | 25 ++++++- src/track/text-track-display.ts | 13 ++-- src/track/track.ts | 2 +- src/types/interfaces/engine.ts | 2 + src/types/interfaces/media-source-adapter.ts | 21 +++--- src/types/text-config.ts | 1 - src/types/text-style.ts | 18 ++--- src/types/text-track-display-setting.ts | 1 - src/utils/index.ts | 7 +- src/utils/styles.ts | 24 +++++++ tests/e2e/player.spec.js | 40 ++++------- 19 files changed, 158 insertions(+), 114 deletions(-) create mode 100644 src/utils/styles.ts diff --git a/docs/configuration.md b/docs/configuration.md index 9271e4221..cd135f7e5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -36,7 +36,6 @@ var config = { text: { enableCEA708Captions: true, useNativeTextTrack: false, - forceCenter: false, captionsTextTrack1Label: 'English', captionsTextTrack1LanguageCode: 'en', captionsTextTrack2Label: 'Spanish', @@ -544,7 +543,6 @@ var config = { > { > useNativeTextTrack: boolean, > enableCEA708Captions: boolean, -> forceCenter: boolean, > textTrackDisplaySetting: PKTextTrackDisplaySettingObject, > textStyle: TextStyle, > captionsTextTrack1Label: string, @@ -560,7 +558,6 @@ var config = { > { > useNativeTextTrack: false, > enableCEA708Captions: true, -> forceCenter: false, > captionsTextTrack1Label: "English", > captionsTextTrack1LanguageCode: "en", > captionsTextTrack2Label: "Spanish", @@ -592,16 +589,6 @@ var config = { > > ## > -> > ### config.text.forceCenter -> > -> > ##### Type: `Object` -> > -> > ##### Default: `false` -> > -> > ##### Description: set the forceCenter to true will override the position, align and size in textTrackDisplaySetting -> -> ## -> > > ### config.text.textTrackDisplaySetting > > > > ##### Type: `PKTextTrackDisplaySettingObject` @@ -616,7 +603,6 @@ var config = { > { > line: string | number, // [-16 .. 16] > lineAlign: string, // ['start', 'center', 'end'] -> align: string, // ['start', 'center', 'end', 'left', 'right'] > position: number, //[0 .. 100] > positionAlign: string, // ['line-left', 'center', 'line-right'] > snapToLines: boolean, // [true, false] @@ -633,10 +619,6 @@ var config = { > > > > An alignment for the cue box’s line, one of start/center/end alignment > > -> > ##### align -> > -> > An alignment for all lines of text within the cue box, in the dimension of the writing direction -> > > > ##### snapToLines > > > > is a boolean indicating whether the line is an integer number of lines (using the line dimensions of the first line of the cue), or whether it is a percentage of the dimension of the video. The flag is set to true when lines are counted, and false otherwise. @@ -678,6 +660,7 @@ var config = { > > ```js > > { > > fontSize?: '50%' | '75%' | '100%' | '200%' | '300%' | '400%' +> > textAlign?: string, // ['center', 'left', 'right'] > > fontScale?: -2 | -1 | 0 | 2 | 3 | 4 > > fontFamily?: string, // font family available in browser > > fontColor?: [number, number, number], // RGB @@ -693,6 +676,10 @@ var config = { > > } > > ``` > > +> > ##### textAlign +> > +> > An alignment for all lines of text within the cue box, in the dimension of the writing direction +> > > > ##### fontSize > > > > Percentage unit relative to the parent element's font diff --git a/flow-typed/types/text-config.js b/flow-typed/types/text-config.js index 32a042624..899697010 100644 --- a/flow-typed/types/text-config.js +++ b/flow-typed/types/text-config.js @@ -7,7 +7,6 @@ declare type PKTextConfigObject = { useNativeTextTrack: boolean, textTrackDisplaySetting: PKTextTrackDisplaySettingObject, textStyle: PKTextStyleObject, - forceCenter: boolean, captionsTextTrack1Label: string, captionsTextTrack1LanguageCode: string, captionsTextTrack2Label: string, diff --git a/flow-typed/types/text-track-display-setting.js b/flow-typed/types/text-track-display-setting.js index 78ef5c47c..493d34c72 100644 --- a/flow-typed/types/text-track-display-setting.js +++ b/flow-typed/types/text-track-display-setting.js @@ -2,7 +2,6 @@ declare type PKTextTrackDisplaySettingObject = { line: string | number, lineAlign: string, - align: string, position: number, positionAlign: string, snapToLines: boolean, diff --git a/src/engines/html5/html5.ts b/src/engines/html5/html5.ts index 34efcfabb..37c26d602 100644 --- a/src/engines/html5/html5.ts +++ b/src/engines/html5/html5.ts @@ -262,6 +262,15 @@ export default class Html5 extends FakeEventTarget implements IEngine { } } + /** + * Get the engine mediaSourceAdapter + * @public + * @returns {IMediaSourceAdapter | null} + */ + public get mediaSourceAdapter(): IMediaSourceAdapter | null { + return this._mediaSourceAdapter; + } + /** * Get the engine's id * @public diff --git a/src/engines/html5/media-source/base-media-source-adapter.ts b/src/engines/html5/media-source/base-media-source-adapter.ts index a532dbd94..07b6a43ab 100644 --- a/src/engines/html5/media-source/base-media-source-adapter.ts +++ b/src/engines/html5/media-source/base-media-source-adapter.ts @@ -4,6 +4,7 @@ import Error from '../../../error/error'; import { CustomEventType, Html5EventType } from '../../../event/event-type'; import getLogger from '../../../utils/logger'; import Track from '../../../track/track'; +import TextStyle from '../../../track/text-style'; import VideoTrack from '../../../track/video-track'; import AudioTrack from '../../../track/audio-track'; import PKTextTrack from '../../../track/text-track'; @@ -177,6 +178,11 @@ export default class BaseMediaSourceAdapter extends FakeEventTarget implements I return BaseMediaSourceAdapter._throwNotImplementedError('static canPlayType'); } + // eslint-disable-next-line + public applyTextTrackStyles(sheet: CSSStyleSheet, styles: TextStyle, containerId: string, engineClassName?: string): void { + return BaseMediaSourceAdapter._throwNotImplementedError('applyTextTrackStyles'); + } + public load(): Promise<{ tracks: Track[] }> { return BaseMediaSourceAdapter._throwNotImplementedError('load'); } diff --git a/src/player-config.js b/src/player-config.js index 4e712ef45..98082a23e 100644 --- a/src/player-config.js +++ b/src/player-config.js @@ -7,7 +7,6 @@ const DefaultConfig = { text: { enableCEA708Captions: true, useNativeTextTrack: false, - forceCenter: false, captionsTextTrack1Label: 'English', captionsTextTrack1LanguageCode: 'en', captionsTextTrack2Label: 'Spanish', diff --git a/src/player.ts b/src/player.ts index 275641c58..3c01a113d 100644 --- a/src/player.ts +++ b/src/player.ts @@ -30,7 +30,7 @@ import {EngineProvider} from './engines/engine-provider'; import {ExternalCaptionsHandler} from './track/external-captions-handler'; import {AdBreakType} from './ads/ad-break-type'; import {AdTagType} from './ads/ad-tag-type'; -import {ResizeWatcher} from './utils'; +import {ResizeWatcher, getSubtitleStyleSheet, resetSubtitleStyleSheet} from './utils'; import {FullscreenController} from './fullscreen/fullscreen-controller'; import {EngineDecorator, EngineDecoratorType} from './engines/engine-decorator'; import {LabelOptions} from './track/label-options'; @@ -78,13 +78,6 @@ const POSTER_CLASS_NAME: string = 'playkit-poster'; */ const ENGINE_CLASS_NAME: string = 'playkit-engine'; -/** - * The text style class name. - * @type {string} - * @const - */ -const SUBTITLES_STYLE_CLASS_NAME: string = 'playkit-subtitles-style'; - /** * The subtitles class name. * @type {string} @@ -471,7 +464,7 @@ export default class Player extends FakeEventTarget { public configure(config: any = {}): void { this._setConfigLogLevel(config); Utils.Object.mergeDeep(this._config, config); - this._applyTextTrackConfig(config); + this._applyTextTrackConfig(); this._applyABRRestriction(config); } @@ -1473,24 +1466,24 @@ export default class Player extends FakeEventTarget { * @param {Object} config - new config which configure for checking if it relevant config has changed * @private */ - private _applyTextTrackConfig(config: any): void { - if (Utils.Object.hasPropertyPath(config, 'text.textTrackDisplaySetting') || Utils.Object.getPropertyPath(config, 'text.forceCenter')) { - let textDisplaySettings: any = {}; - if (Utils.Object.hasPropertyPath(this._config, 'text.textTrackDisplaySetting')) { - textDisplaySettings = Utils.Object.mergeDeep(textDisplaySettings, this._config.text.textTrackDisplaySetting); - } + private _applyTextTrackConfig(): void { + const textTrackDisplaySetting = Utils.Object.getPropertyPath(this._config, 'text.textTrackDisplaySetting'); + const textStyle = Utils.Object.getPropertyPath(this._config, 'text.textStyle'); + if (textTrackDisplaySetting) { + const textDisplaySettings: any = Utils.Object.mergeDeep({}, textTrackDisplaySetting, { + position: 'auto', + // align - backward compatibility || new caption alignment API || default value + align: textTrackDisplaySetting?.align || textStyle?.textAlign || 'center' + }); + // backward compatibility for `text.forceCenter` if (Utils.Object.getPropertyPath(this._config, 'text.forceCenter')) { - textDisplaySettings = Utils.Object.mergeDeep(textDisplaySettings, { - position: 'auto', - align: 'center', - size: '100' - }); + textDisplaySettings.align = 'center'; } this.setTextDisplaySettings(textDisplaySettings); } try { - if (Utils.Object.hasPropertyPath(config, 'text.textStyle')) { - this.textStyle = TextStyle.fromJson(this._config.text.textStyle); + if (textStyle) { + this.textStyle = TextStyle.fromJson(textStyle); } } catch (e) { Player._logger.warn(e); @@ -1542,23 +1535,13 @@ export default class Player extends FakeEventTarget { if (!(style instanceof TextStyle)) { throw new Error('Style must be instance of TextStyle'); } - let element = Utils.Dom.getElementBySelector(`.${this._playerId}.${SUBTITLES_STYLE_CLASS_NAME}`); - if (!element) { - element = Utils.Dom.createElement('style'); - Utils.Dom.addClassName(element, this._playerId); - Utils.Dom.addClassName(element, SUBTITLES_STYLE_CLASS_NAME); - Utils.Dom.appendChild(document.head, element); - } - const sheet = element.sheet; - while (sheet.cssRules.length) { - sheet.deleteRule(0); - } + resetSubtitleStyleSheet(this._playerId); try { this._textStyle = style; if (this._config.text.useNativeTextTrack) { - sheet.insertRule(`#${this._playerId} video.${ENGINE_CLASS_NAME}::cue { ${style.toCSS()} }`, 0); + this._applyCustomSubtitleStyles(); } else if (this._engine) { this._engine.resetAllCues(); this._externalCaptionsHandler.resetAllCues(); @@ -1716,6 +1699,22 @@ export default class Player extends FakeEventTarget { return this._engine.getDrmInfo(); } + private _applyCustomSubtitleStyles(): void { + try { + const containerId = this._el?.parentElement?.id || this._playerId; + if (this._config.text.useNativeTextTrack && !this._config.text.useShakaTextTrackDisplay) { + const sheet = getSubtitleStyleSheet(this._playerId); + ExternalCaptionsHandler.applyNativeTextTrackStyles(sheet, this._textStyle, containerId, ENGINE_CLASS_NAME); + } else if (this._config.text.useShakaTextTrackDisplay) { + resetSubtitleStyleSheet(this._playerId); + const sheet = getSubtitleStyleSheet(this._playerId); + this._engine.mediaSourceAdapter?.applyTextTrackStyles?.(sheet, this._textStyle, containerId); + } + } catch (e) { + Player._logger.error(`Failed to add custom text style: ${e.message}`); + } + } + /** * Remove the current text track from the player view. * @returns {void} @@ -2564,6 +2563,9 @@ export default class Player extends FakeEventTarget { * @returns {void} */ private _updateTextDisplay(cues: Array): void { + if (this._config.text.useShakaTextTrackDisplay) { + this._applyCustomSubtitleStyles(); + } if (!this._config.text.useNativeTextTrack && !this._config.text.useShakaTextTrackDisplay) { processCues(window, cues, this._textDisplayEl, this._textStyle); } diff --git a/src/track/external-captions-handler.ts b/src/track/external-captions-handler.ts index d3977f442..53f25764c 100644 --- a/src/track/external-captions-handler.ts +++ b/src/track/external-captions-handler.ts @@ -2,6 +2,7 @@ import Error from '../error/error'; import * as Utils from '../utils/util'; import {Parser, StringDecoder} from './text-track-display'; import TextTrack, {getActiveCues} from './text-track'; +import TextStyle from './text-style'; import Track from './track'; import {CustomEventType, Html5EventType} from '../event/event-type'; import { FakeEvent } from '../event/fake-event'; @@ -29,6 +30,12 @@ const SRT_POSTFIX: string = 'srt'; const VTT_POSTFIX: string = 'vtt'; class ExternalCaptionsHandler extends FakeEventTarget { + + public static applyNativeTextTrackStyles(sheet: CSSStyleSheet, styles: TextStyle, containerId: string, engineClassName: string): void { + sheet.insertRule(`#${containerId} video.${engineClassName}::-webkit-media-text-track-display { text-align: ${styles.textAlign}!important; }`, 0); + sheet.insertRule(`#${containerId} video.${engineClassName}::cue { ${styles.toCSS()} }`, 0); + } + /** * The external captions handler class logger. * @type {any} diff --git a/src/track/text-style.ts b/src/track/text-style.ts index b67a30ac3..1bbacd767 100644 --- a/src/track/text-style.ts +++ b/src/track/text-style.ts @@ -6,7 +6,7 @@ * font size. * @type {number} */ -import {FontScaleOptions, FontSizeOptions, PKTextStyleObject} from '../types'; +import { FontScaleOptions, FontSizeOptions, PKTextStyleObject, FontAlignmentOptions } from '../types'; const IMPLICIT_SCALE_PERCENTAGE: number = 0.25; @@ -130,6 +130,24 @@ class TextStyle { } ]; + /** + * Possible font alignments are left, center, right + */ + public static FontAlignment: { label: string; value: FontAlignmentOptions }[] = [ + { + label: 'Left', + value: 'left' + }, + { + label: 'Center', + value: 'center' + }, + { + label: 'Right', + value: 'right' + } + ]; + /** * Creates a CSS RGBA sctring for a given color and opacity values * @param {TextStyle.StandardColors} color - color value in RGB @@ -149,6 +167,7 @@ class TextStyle { const textStyle = new TextStyle(); textStyle.fontEdge = getValue(setting.fontEdge, textStyle.fontEdge); textStyle.fontSize = getValue(setting.fontSize, textStyle.fontSize); + textStyle.textAlign = getValue(setting.textAlign, textStyle.textAlign); textStyle.fontScale = getValue(setting.fontScale, textStyle.fontScale); textStyle.fontColor = getValue(setting.fontColor, textStyle.fontColor); textStyle.fontOpacity = getValue(setting.fontOpacity, textStyle.fontOpacity); @@ -162,6 +181,7 @@ class TextStyle { return { fontEdge: text.fontEdge, fontSize: text.fontSize, + textAlign: text.textAlign, fontScale: text.fontScale, fontColor: text.fontColor, fontOpacity: text.fontOpacity, @@ -180,6 +200,8 @@ class TextStyle { } } + public textAlign: FontAlignmentOptions = TextStyle.FontAlignment[1].value; + /** * Percentage string matching a FontSizes entry */ @@ -254,6 +276,7 @@ class TextStyle { */ public toCSS(): string { const attributes: Array = []; + attributes.push('text-align: ' + this.textAlign); attributes.push('font-family: ' + this.fontFamily); attributes.push('color: ' + TextStyle.toRGBA(this.fontColor, this.fontOpacity)); attributes.push('background-color: ' + TextStyle.toRGBA(this.backgroundColor, this.backgroundOpacity)); diff --git a/src/track/text-track-display.ts b/src/track/text-track-display.ts index 2c97483e0..e3ed88335 100644 --- a/src/track/text-track-display.ts +++ b/src/track/text-track-display.ts @@ -212,7 +212,7 @@ function parseCue(input, cue, regionList) { settings.percent(k, v); break; case 'align': - settings.alt(k, v, ['start', 'center', 'end', 'left', 'right']); + settings.alt(k, v, ['center', 'left', 'right']); break; } }, @@ -641,7 +641,7 @@ class CueStyleBox extends StyleBox { // mirrors of them except "middle" which is "center" in CSS. this.div = window.document.createElement('div'); styles = { - textAlign: cue.align === 'middle' ? 'center' : cue.align, + textAlign: styleOptions.textAlign, font: styleOptions.font, whiteSpace: 'pre-line', position: 'absolute' @@ -661,19 +661,14 @@ class CueStyleBox extends StyleBox { // position of the cue box. The reference edge will be resolved later when // the box orientation styles are applied. let textPos = 0; - let align = cue.positionAlign || cue.align; - switch (align) { - case 'start': + switch (styleOptions.textAlign) { case 'left': - case 'line-left': textPos = cue.position; break; case 'center': textPos = cue.position - cue.size / 2; break; - case 'end': case 'right': - case 'line-right': textPos = cue.position - cue.size; break; } @@ -982,7 +977,6 @@ function convertCueToDOMTree(window, cuetext) { } const FONT_SIZE_PERCENT = 0.058; -const FONT_STYLE = 'sans-serif'; const CUE_BACKGROUND_PADDING = '1.5%'; // Runs the processing model over the cues and regions passed to it. @@ -1033,6 +1027,7 @@ function processCues(window, cues, overlay, style) { fontSize = Math.round(dimensionSize * FONT_SIZE_PERCENT * 100) / 100; let styleOptions = { font: fontSize * fontScale * style.implicitFontScale + 'px ' + style.fontFamily, + textAlign: style.textAlign, color: TextStyle.toRGBA(style.fontColor, style.fontOpacity), backgroundColor: TextStyle.toRGBA(style.backgroundColor, style.backgroundOpacity), textShadow: style.getTextShadow() diff --git a/src/track/track.ts b/src/track/track.ts index 2e5adcbd2..48bb3f6a3 100644 --- a/src/track/track.ts +++ b/src/track/track.ts @@ -30,7 +30,7 @@ export default class Track { private static _langComparer(inputLanguages: [string, (string | undefined)], trackLang: string, equal?: boolean): boolean { //first check is there is a complete match for(const language of inputLanguages) { - if(language?.trim() !== "") { + if(language?.trim() !== '') { if (equal) { if(this._isLangEqual(language, trackLang)) return true; diff --git a/src/types/interfaces/engine.ts b/src/types/interfaces/engine.ts index 05cb6128b..ef1ac4b2c 100644 --- a/src/types/interfaces/engine.ts +++ b/src/types/interfaces/engine.ts @@ -10,6 +10,7 @@ import {PKDrmDataObject} from '../drm-data'; import {PKABRRestrictionObject} from '../restrictions-types'; import Track from '../../track/track'; import {PKTextTrack} from '../../track/text-track'; +import {IMediaSourceAdapter} from '../../types'; export interface IEngineStatic { id: string; @@ -86,4 +87,5 @@ export interface IEngine extends FakeEventTarget { crossOrigin: string | null targetBuffer: number; availableBuffer: number; + mediaSourceAdapter: IMediaSourceAdapter | null; } diff --git a/src/types/interfaces/media-source-adapter.ts b/src/types/interfaces/media-source-adapter.ts index 492b12932..ced420fa3 100644 --- a/src/types/interfaces/media-source-adapter.ts +++ b/src/types/interfaces/media-source-adapter.ts @@ -1,16 +1,16 @@ - import VideoTrack from '../../track/video-track'; import AudioTrack from '../../track/audio-track'; -import { PKTextTrack} from '../../track/text-track'; -import {PKDrmConfigObject} from '../drm-config'; -import {PKMediaSourceCapabilities} from '../media-source-capabilities'; -import {PKMediaSourceObject} from '../media-source'; +import { PKTextTrack } from '../../track/text-track'; +import { PKDrmConfigObject } from '../drm-config'; +import { PKMediaSourceCapabilities } from '../media-source-capabilities'; +import { PKMediaSourceObject } from '../media-source'; import ImageTrack from '../../track/image-track'; -import {PKDrmDataObject} from '../drm-data'; +import { PKDrmDataObject } from '../drm-data'; import { FakeEventTarget } from '../../event/fake-event-target'; -import {ThumbnailInfo} from '../../thumbnail/thumbnail-info'; +import { ThumbnailInfo } from '../../thumbnail/thumbnail-info'; import Track from '../../track/track'; -import {PKABRRestrictionObject} from '../restrictions-types'; +import TextStyle from '../../track/text-style'; +import { PKABRRestrictionObject } from '../restrictions-types'; export interface IMediaSourceAdapterStatic { id: string; @@ -26,7 +26,7 @@ export interface IMediaSourceAdapter extends FakeEventTarget { liveDuration: number; capabilities: PKMediaSourceCapabilities; targetBuffer: number; - load(startTime?: number): Promise<{tracks: Track[]}>; + load(startTime?: number): Promise<{ tracks: Track[] }>; handleMediaError(error?: MediaError): boolean; destroy(): Promise; selectVideoTrack(videoTrack: VideoTrack): void; @@ -45,7 +45,8 @@ export interface IMediaSourceAdapter extends FakeEventTarget { detachMediaSource(): void; getSegmentDuration(): number; disableNativeTextTracks(): void; - getThumbnail(time: number): ThumbnailInfo | null + getThumbnail(time: number): ThumbnailInfo | null; getDrmInfo(): PKDrmDataObject | null; applyABRRestriction(restriction: PKABRRestrictionObject): void; + applyTextTrackStyles(sheet: CSSStyleSheet, styles: TextStyle, containerId: string, engineClassName?: string): void; } diff --git a/src/types/text-config.ts b/src/types/text-config.ts index d5bfd3c1a..b3e1023a9 100644 --- a/src/types/text-config.ts +++ b/src/types/text-config.ts @@ -7,7 +7,6 @@ export interface PKTextConfigObject { useNativeTextTrack: boolean; textTrackDisplaySetting: PKTextTrackDisplaySettingObject; textStyle: PKTextStyleObject; - forceCenter: boolean; captionsTextTrack1Label: string; captionsTextTrack1LanguageCode: string; captionsTextTrack2Label: string; diff --git a/src/types/text-style.ts b/src/types/text-style.ts index 03446c535..523062f01 100644 --- a/src/types/text-style.ts +++ b/src/types/text-style.ts @@ -1,4 +1,5 @@ export type FontSizeOptions = '50%' | '75%' | '100%' | '200%' | '300%' | '400%'; +export type FontAlignmentOptions = 'left' | 'center' | 'right'; export type FontScaleOptions = -2 | -1 | 0 | 2 | 3 | 4; /** * @typedef {Object} PKTextStyleObject @@ -12,12 +13,13 @@ export type FontScaleOptions = -2 | -1 | 0 | 2 | 3 | 4; * @property {number} backgroundOpacity=1 */ export type PKTextStyleObject = { - fontSize: FontSizeOptions, - fontScale: FontScaleOptions, - fontFamily: string, - fontColor: [number, number, number], - fontOpacity: number, - fontEdge: Array<[number, number, number, number, number, number]>, - backgroundColor: [number, number, number], - backgroundOpacity: number + fontSize: FontSizeOptions; + textAlign: FontAlignmentOptions; + fontScale: FontScaleOptions; + fontFamily: string; + fontColor: [number, number, number]; + fontOpacity: number; + fontEdge: Array<[number, number, number, number, number, number]>; + backgroundColor: [number, number, number]; + backgroundOpacity: number; }; diff --git a/src/types/text-track-display-setting.ts b/src/types/text-track-display-setting.ts index f6467ebe0..c6f886d5d 100644 --- a/src/types/text-track-display-setting.ts +++ b/src/types/text-track-display-setting.ts @@ -1,7 +1,6 @@ export type PKTextTrackDisplaySettingObject = { line: string | number, lineAlign: string, - align: string, position: number, positionAlign: string, snapToLines: boolean, diff --git a/src/utils/index.ts b/src/utils/index.ts index dab5ab10f..669539b7b 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,5 @@ export * from './util'; -export {ResizeWatcher} from './resize-watcher'; -export {MultiMap} from './multi-map'; -export {binarySearch} from './binary-search'; +export { ResizeWatcher } from './resize-watcher'; +export { MultiMap } from './multi-map'; +export { binarySearch } from './binary-search'; +export * from './styles'; diff --git a/src/utils/styles.ts b/src/utils/styles.ts new file mode 100644 index 000000000..d8c741232 --- /dev/null +++ b/src/utils/styles.ts @@ -0,0 +1,24 @@ +import * as Utils from './util'; + +/** + * The text style class name. + * @type {string} + * @const + */ +const SUBTITLES_STYLE_CLASS_NAME: string = 'playkit-subtitles-style'; + +export const getSubtitleStyleSheet = (playerId: string): CSSStyleSheet => { + let element = Utils.Dom.getElementBySelector(`.${playerId}.${SUBTITLES_STYLE_CLASS_NAME}`); + if (!element) { + element = Utils.Dom.createElement('style'); + Utils.Dom.addClassName(element, playerId); + Utils.Dom.addClassName(element, SUBTITLES_STYLE_CLASS_NAME); + Utils.Dom.appendChild(document.head, element); + } + return element.sheet; +}; + +export const resetSubtitleStyleSheet = (playerId: string): void => { + const element = Utils.Dom.getElementBySelector(`.${playerId}.${SUBTITLES_STYLE_CLASS_NAME}`); + element?.remove(); +}; diff --git a/tests/e2e/player.spec.js b/tests/e2e/player.spec.js index 73a3861ea..96b4b6571 100644 --- a/tests/e2e/player.spec.js +++ b/tests/e2e/player.spec.js @@ -1667,6 +1667,7 @@ describe('Player', function () { const settings = { fontEdge: TextStyle.EdgeStyles.RAISED, fontSize: '75%', + textAlign: "center", fontScale: -1, fontColor: TextStyle.StandardColors.CYAN, fontOpacity: TextStyle.StandardOpacities.SEMI_LOW, @@ -1724,36 +1725,25 @@ describe('Player', function () { describe('configure text track display', () => { it('should change textDisplay settings by config', () => { - const settings = {line: -4}; - player = new Player({text: {textTrackDisplaySetting: settings}}); - player._textDisplaySettings.should.deep.equal(settings); - }); - - it('should forceCenter override textTrackDisplaySetting', () => { - const settings = {position: '10%', align: 'left', size: '10'}; - player = new Player({text: {forceCenter: true, textTrackDisplaySetting: settings}}); - player._textDisplaySettings.should.deep.equal({position: 'auto', align: 'center', size: '100'}); - }); - - it('should forceCenter keep the other values from textTrackDisplaySetting', () => { - const settings = {line: '-4', lineAlign: 'end', position: '10%'}; - player = new Player({text: {forceCenter: true, textTrackDisplaySetting: settings}}); - player._textDisplaySettings.should.deep.equal(Utils.Object.mergeDeep(settings, {position: 'auto', align: 'center', size: '100'})); - }); - - it('should configure change of textTrackDisplaySetting will apply forceCenter', () => { - const settings = {position: '10%', align: 'left', size: '10'}; - player = new Player({text: {forceCenter: true, textTrackDisplaySetting: settings}}); - player.configure({text: {textTrackDisplaySetting: settings}}); - player._textDisplaySettings.should.deep.equal({position: 'auto', align: 'center', size: '100'}); + const textTrackDisplaySetting = {line: -4}; + player = new Player({text: {textTrackDisplaySetting}}); + player._textDisplaySettings.should.deep.equal({ + ...textTrackDisplaySetting, + align: "center", + position: "auto" + }); }); it('should empty configure will not take the previous config and change the values from setTextDisplaySettings', () => { - const settings = {position: '10%', align: 'left', size: '10'}; - player = new Player({text: {forceCenter: true, textTrackDisplaySetting: settings}}); + const settings = {position: '10%', size: '10'}; + player = new Player({text: {textTrackDisplaySetting: settings}}); player.setTextDisplaySettings(settings); player.configure({text: {}}); - player._textDisplaySettings.should.deep.equal(settings); + player._textDisplaySettings.should.deep.equal({ + ...settings, + align: "center", + position: "auto" + }); }); it('should keep the current setting for empty config', () => {