@playkit-js/transcript 3.1.0-canary.2-d22690c → 3.1.0-canary.4-372ac3f

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playkit-js/transcript",
3
- "version": "3.1.0-canary.2-d22690c",
3
+ "version": "3.1.0-canary.4-372ac3f",
4
4
  "main": "dist/playkit-transcript.js",
5
5
  "license": "AGPL-3.0",
6
6
  "private": false,
@@ -116,8 +116,8 @@ export class Caption extends Component<ExtendedCaptionProps> {
116
116
  <A11yWrapper onClick={this._handleKeyDown}>
117
117
  <div
118
118
  className={styles.caption}
119
- tabIndex={1}
120
- area-label={caption.text}
119
+ tabIndex={0}
120
+ aria-label={caption.text}
121
121
  ref={node => {
122
122
  this._hotspotRef = node;
123
123
  }}
@@ -16,7 +16,7 @@ interface CloseButtonProps {
16
16
 
17
17
  export const CloseButton = withText(translates)((props: CloseButtonProps) => (
18
18
  <A11yWrapper onClick={props.onClick}>
19
- <button className={styles.closeBtn} tabIndex={1} aria-label={props.closeLabel}>
19
+ <button className={styles.closeBtn} tabIndex={0} aria-label={props.closeLabel}>
20
20
  <Icon
21
21
  id="transcript-plugin-close-button"
22
22
  height={icons.BigSize}
@@ -167,14 +167,14 @@ class SearchComponent extends Component<SearchProps, SearchState> {
167
167
  onFocus={this._onFocus}
168
168
  onBlur={this._onBlur}
169
169
  onMouseDown={this._handleMouseDown}
170
- tabIndex={1}
170
+ tabIndex={0}
171
171
  ref={node => {
172
172
  this._inputRef = node;
173
173
  }}
174
174
  />
175
175
  {searchQuery && (
176
176
  <A11yWrapper onClick={this._onClear}>
177
- <button className={styles.clearIcon} tabIndex={1} aria-label={this.props.clearSearchLabel}>
177
+ <button className={styles.clearIcon} tabIndex={0} aria-label={this.props.clearSearchLabel}>
178
178
  <svg
179
179
  width="32px"
180
180
  height="32px"
@@ -201,7 +201,7 @@ class SearchComponent extends Component<SearchProps, SearchState> {
201
201
  {searchQuery && (
202
202
  <A11yWrapper onClick={this._goToPrevSearchResult}>
203
203
  <button
204
- tabIndex={1}
204
+ tabIndex={0}
205
205
  className={`${styles.prevNextButton} ${totalSearchResults === 0 ? styles.disabled : ''}`}
206
206
  aria-label={this.props.prevMatchLabel}>
207
207
  <svg
@@ -225,7 +225,7 @@ class SearchComponent extends Component<SearchProps, SearchState> {
225
225
  {searchQuery && (
226
226
  <A11yWrapper onClick={this._goToNextSearchResult}>
227
227
  <button
228
- tabIndex={1}
228
+ tabIndex={0}
229
229
  className={`${styles.prevNextButton} ${totalSearchResults === 0 ? styles.disabled : ''}`}
230
230
  aria-label={this.props.nextMatchLabel}>
231
231
  <svg
@@ -13,7 +13,10 @@ const {ENTER, SPACE, TAB, ESC} = KalturaPlayer.ui.utils.KeyMap;
13
13
  const {withText, Text} = KalturaPlayer.ui.preacti18n;
14
14
 
15
15
  const translates = {
16
- autoScrollLabel: <Text id="transcript.auto_scroll">Enable auto scroll</Text>
16
+ autoScrollLabel: <Text id="transcript.auto_scroll">Enable auto scroll</Text>,
17
+ errorTitle: <Text id="transcript.whoops">Whoops!</Text>,
18
+ errorDescripton: <Text id="transcript.load_failed">Failed to load transcript</Text>,
19
+ skipTranscript: <Text id="transcript.skip_transcript">Skip transcript</Text>
17
20
  };
18
21
 
19
22
  export interface TranscriptProps {
@@ -34,6 +37,9 @@ export interface TranscriptProps {
34
37
  highlightedMap: HighlightedMap;
35
38
  onItemClicked: (n: number) => void;
36
39
  autoScrollLabel?: string;
40
+ errorTitle?: string;
41
+ errorDescripton?: string;
42
+ skipTranscript?: string;
37
43
  }
38
44
 
39
45
  interface TranscriptState {
@@ -111,7 +117,7 @@ export class TranscriptComponent extends Component<TranscriptProps, TranscriptSt
111
117
  <div
112
118
  role="button"
113
119
  className={`${styles.autoscrollButton} ${isAutoScrollEnabled ? '' : styles.autoscrollButtonVisible}`}
114
- tabIndex={isAutoScrollEnabled ? -1 : 1}
120
+ tabIndex={isAutoScrollEnabled ? -1 : 0}
115
121
  aria-label={this.props.autoScrollLabel}
116
122
  ref={node => {
117
123
  this._autoscrollButtonRef = node;
@@ -238,8 +244,8 @@ export class TranscriptComponent extends Component<TranscriptProps, TranscriptSt
238
244
  className={styles.skipTranscriptButton}
239
245
  onKeyDown={this._handleKeyDown}
240
246
  onClick={this._handleClick}
241
- tabIndex={1}>
242
- Skip transcript
247
+ tabIndex={0}>
248
+ {this.props.skipTranscript}
243
249
  </div>
244
250
  );
245
251
  };
@@ -247,9 +253,6 @@ export class TranscriptComponent extends Component<TranscriptProps, TranscriptSt
247
253
  private _renderTranscript = () => {
248
254
  const {captions, hasError, onRetryLoad, showTime, videoDuration, highlightedMap} = this.props;
249
255
  const {isAutoScrollEnabled, searchMap, activeSearchIndex, searchLength} = this.state;
250
- if (!captions || !captions.length) {
251
- return null;
252
- }
253
256
 
254
257
  if (hasError) {
255
258
  return (
@@ -257,17 +260,16 @@ export class TranscriptComponent extends Component<TranscriptProps, TranscriptSt
257
260
  <div className={styles.errorIcon}>
258
261
  <ErrorIcon />
259
262
  </div>
260
- <p className={styles.errorMainText}>Whoops!</p>
261
- <p className={styles.errorDescriptionText}>
262
- Failed to get transcript, please try again
263
- <button className={styles.retryButton} onClick={onRetryLoad}>
264
- Retry
265
- </button>
266
- </p>
263
+ <p className={styles.errorMainText}>{this.props.errorTitle}</p>
264
+ <p className={styles.errorDescriptionText}>{this.props.errorDescripton}</p>
267
265
  </div>
268
266
  );
269
267
  }
270
268
 
269
+ if (!captions || !captions.length) {
270
+ return null;
271
+ }
272
+
271
273
  const captionProps = {
272
274
  showTime,
273
275
  searchLength,
@@ -369,8 +371,8 @@ export class TranscriptComponent extends Component<TranscriptProps, TranscriptSt
369
371
  };
370
372
 
371
373
  render(props: TranscriptProps) {
372
- const {isLoading, kitchenSinkActive} = props;
373
-
374
+ const {isLoading, kitchenSinkActive, hasError} = props;
375
+ const renderTranscriptButtons = !(isLoading || hasError);
374
376
  return (
375
377
  <div
376
378
  className={`${styles.root} ${kitchenSinkActive ? '' : styles.hidden}`}
@@ -383,7 +385,7 @@ export class TranscriptComponent extends Component<TranscriptProps, TranscriptSt
383
385
 
384
386
  <CloseButton onClick={this.props.onClose} />
385
387
 
386
- {!isLoading && this._renderSkipTranscriptButton()}
388
+ {renderTranscriptButtons && this._renderSkipTranscriptButton()}
387
389
  <div
388
390
  className={styles.body}
389
391
  onScroll={this._onScroll}
@@ -392,7 +394,7 @@ export class TranscriptComponent extends Component<TranscriptProps, TranscriptSt
392
394
  }}>
393
395
  {isLoading ? this._renderLoading() : this._renderTranscript()}
394
396
  </div>
395
- {this._renderScrollToButton()}
397
+ {renderTranscriptButtons && this._renderScrollToButton()}
396
398
  </div>
397
399
  </div>
398
400
  );
@@ -13,6 +13,8 @@ const {SidePanelModes, SidePanelPositions, ReservedPresetNames, ReservedPresetAr
13
13
  const {withText, Text} = KalturaPlayer.ui.preacti18n;
14
14
  const {get} = ObjectUtils;
15
15
 
16
+ const LOADING_TIMEOUT = 10000;
17
+
16
18
  interface TimedMetadataEvent {
17
19
  payload: {
18
20
  cues: Array<CuePoint>;
@@ -35,6 +37,7 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
35
37
  private _activeCuePointsMap: HighlightedMap = {};
36
38
  private _captionMap: Map<string, Array<CuePointData>> = new Map();
37
39
  private _isLoading = false;
40
+ private _loadingTimeoutId?: ReturnType<typeof setTimeout>;
38
41
  private _hasError = false;
39
42
  private _triggeredByKeyboard = false;
40
43
 
@@ -78,27 +81,39 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
78
81
  }
79
82
 
80
83
  private _initListeners(): void {
81
- this.eventManager.listen(this.player, this.player.Event.FIRST_PLAYING, () => {
82
- if ((this.player.getTracks(this.player.Track.TEXT) || []).length) {
83
- // check if captions already added in TextTrack
84
- if (!this._captionMap.size) {
85
- // turn on loading animation till captions added to TextTrack
86
- this._isLoading = true;
87
- }
84
+ this.eventManager.listenOnce(this.player, this.player.Event.TRACKS_CHANGED, () => {
85
+ if (this._getTextTracks().length) {
86
+ this.eventManager.listen(this.player, this.player.Event.TIMED_METADATA_CHANGE, this._onTimedMetadataChange);
87
+ this.eventManager.listen(this.player, this.player.Event.TIMED_METADATA_ADDED, this._onTimedMetadataAdded);
88
+ this.eventManager.listen(this.player, this.player.Event.TEXT_TRACK_CHANGED, this._handleLanguageChange);
88
89
  this._addDownloadIcon();
89
90
  this._addPrintIcon();
90
91
  this._addTranscriptItem();
92
+ this._initLoading();
91
93
  }
92
94
  });
93
- this.eventManager.listen(this.player, this.player.Event.TIMED_METADATA_CHANGE, this._onTimedMetadataChange);
94
- this.eventManager.listen(this.player, this.player.Event.TIMED_METADATA_ADDED, this._onTimedMetadataAdded);
95
- this.eventManager.listen(this.player, this.player.Event.TEXT_TRACK_CHANGED, this._handleLanguageChange);
96
95
  }
97
96
 
97
+ private _initLoading = () => {
98
+ clearTimeout(this._loadingTimeoutId);
99
+ this._isLoading = false;
100
+ this._hasError = false;
101
+ if (!this._captionMap.has(this._activeCaptionMapId)) {
102
+ // turn on loading animation till captions added to TextTrack
103
+ this._isLoading = true;
104
+ this._loadingTimeoutId = setTimeout(() => {
105
+ // display error slate
106
+ this._isLoading = false;
107
+ this._hasError = true;
108
+ this._updateTranscriptPanel();
109
+ }, LOADING_TIMEOUT);
110
+ }
111
+ this._updateTranscriptPanel();
112
+ };
113
+
98
114
  private _handleLanguageChange = () => {
99
115
  this._activeCaptionMapId = this._getCaptionMapId();
100
- this._isLoading = !this._captionMap.has(this._activeCaptionMapId);
101
- this._updateTranscriptPanel();
116
+ this._initLoading();
102
117
  };
103
118
 
104
119
  private _updateTranscriptPanel() {
@@ -140,11 +155,16 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
140
155
  this._activeCaptionMapId = this._getCaptionMapId();
141
156
  this._captionMap.set(this._activeCaptionMapId, newData);
142
157
  this._isLoading = false;
158
+ clearTimeout(this._loadingTimeoutId);
143
159
  this._updateTranscriptPanel();
144
160
  };
145
161
 
162
+ private _getTextTracks = () => {
163
+ return this.player.getTracks(this.player.Track.TEXT) || [];
164
+ };
165
+
146
166
  private _getCaptionMapId = (): string => {
147
- const allTextTracks = this.player.getTracks(this.player.Track.TEXT) || [];
167
+ const allTextTracks = this._getTextTracks();
148
168
  const activeTextTrack = allTextTracks.find(track => track.active);
149
169
  if (activeTextTrack?.language === 'off') {
150
170
  // use 1st captions from text-track list
@@ -219,9 +239,11 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
219
239
  }
220
240
 
221
241
  private _addTranscriptItem(): void {
222
- const {expandMode, position, expandOnFirstPlay} = this.config;
223
- const {showTime, scrollOffset, searchDebounceTimeout, searchNextPrevDebounceTimeout} = this.config;
242
+ if (this._transcriptPanel > 0) {
243
+ return;
244
+ }
224
245
 
246
+ const {expandMode, position, expandOnFirstPlay, showTime, scrollOffset, searchDebounceTimeout, searchNextPrevDebounceTimeout} = this.config;
225
247
  this._transcriptPanel = this.sidePanelsManager!.add({
226
248
  label: 'Transcript',
227
249
  panelComponent: () => {
@@ -320,6 +342,7 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
320
342
  this._captionMap = new Map();
321
343
  this._activeCaptionMapId = '';
322
344
  this._isLoading = false;
345
+ clearTimeout(this._loadingTimeoutId);
323
346
  this._hasError = false;
324
347
  this._triggeredByKeyboard = false;
325
348
  }