@brightspace-ui/labs 2.63.4 → 2.63.6

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.
@@ -2,7 +2,6 @@ import '@brightspace-ui/core/components/button/button-icon.js';
2
2
  import '@brightspace-ui/core/components/colors/colors.js';
3
3
  import '@brightspace-ui/core/components/dropdown/dropdown.js';
4
4
  import '@brightspace-ui/core/components/dropdown/dropdown-menu.js';
5
- import '@brightspace-ui/core/components/dropdown/dropdown-button-subtle.js';
6
5
  import '@brightspace-ui/core/components/icons/icon.js';
7
6
  import '@brightspace-ui/core/components/loading-spinner/loading-spinner.js';
8
7
  import '@brightspace-ui/core/components/menu/menu.js';
@@ -13,7 +12,7 @@ import './slider-bar.js';
13
12
  import 'webvtt-parser';
14
13
  import './media-player-audio-bars.js';
15
14
  import { AUDIO_DESCRIPTION_REPLAY_KEY, AUDIO_DESCRIPTION_SKIP_KEY, AUDIO_DESCRIPTION_TRACK_KIND, MediaPlayerAudioDescriptionsMixin } from './media-player-audio-descriptions.js';
16
- import { css, html, LitElement, unsafeCSS } from 'lit';
15
+ import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
17
16
  import { classMap } from 'lit/directives/class-map.js';
18
17
  import fullscreenApi from './fullscreen-api.js';
19
18
  import Fuse from 'fuse.js';
@@ -21,6 +20,9 @@ import { getFocusPseudoClass } from '@brightspace-ui/core/helpers/focus.js';
21
20
  import { ifDefined } from 'lit/directives/if-defined.js';
22
21
  import { labelStyles } from '@brightspace-ui/core/components/typography/styles.js';
23
22
  import { LocalizeLabsElement } from '../localize-labs-element.js';
23
+ import { MediaPlayerChaptersMixin } from './media-player-chapters.js';
24
+ import { MediaPlayerThumbnailsMixin } from './media-player-thumbnails.js';
25
+ import { MediaPlayerTranscriptMixin } from './media-player-transcript.js';
24
26
  import parseSRT from 'parse-srt/src/parse-srt.js';
25
27
  import { RtlMixin } from '@brightspace-ui/core/mixins/rtl-mixin.js';
26
28
  import { styleMap } from 'lit/directives/style-map.js';
@@ -61,8 +63,6 @@ const FUSE_OPTIONS = options => ({
61
63
  ...options
62
64
  });
63
65
  const SEARCH_CONTAINER_HOVER_CLASS = 'search-container-hover';
64
- const DEFAULT_PREVIEW_WIDTH = 160;
65
- const DEFAULT_PREVIEW_HEIGHT = 90;
66
66
 
67
67
  const SAFARI_EXPIRY_EARLY_SWAP_SECONDS = 10;
68
68
  const SAFARI_EXPIRY_MIN_ERROR_EMIT_SECONDS = 30;
@@ -76,7 +76,7 @@ const tryParseUrlExpiry = url => {
76
76
  }
77
77
  };
78
78
 
79
- class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(RtlMixin(LitElement))) {
79
+ class MediaPlayer extends LocalizeLabsElement(MediaPlayerTranscriptMixin(MediaPlayerThumbnailsMixin(MediaPlayerChaptersMixin(MediaPlayerAudioDescriptionsMixin(RtlMixin(LitElement)))))) {
80
80
 
81
81
  static properties = {
82
82
  allowDownload: { type: Boolean, attribute: 'allow-download', reflect: true },
@@ -89,14 +89,10 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
89
89
  hideSeekBar: { type: Boolean, attribute: 'hide-seek-bar' },
90
90
  loop: { type: Boolean },
91
91
  mediaType: { type: String, attribute: 'media-type' },
92
- metadata: { type: Object },
93
92
  poster: { type: String },
94
93
  src: { type: String },
95
- thumbnails: { type: String },
96
94
  disableSetPreferences: { type: Boolean, attribute: 'disable-set-preferences' },
97
- transcriptViewerOn: { type: Boolean, attribute: 'transcript-viewer-on' },
98
95
  playInView: { type: Boolean, attribute: 'play-in-view' },
99
- _chapters: { state: true },
100
96
  _currentTime: { state: true },
101
97
  _duration: { state: true },
102
98
  _heightPixels: { state: true },
@@ -115,7 +111,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
115
111
  _selectedSpeed: { state: true },
116
112
  _selectedTrackIdentifier: { state: true },
117
113
  _sources: { state: true },
118
- _thumbnailsImage: { state: true },
119
114
  _timelinePreviewOffset: { state: true },
120
115
  _trackFontSizeRem: { state: true },
121
116
  _timeFontSizeRem: { state: true },
@@ -402,28 +397,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
402
397
  width: 2.75rem;
403
398
  }
404
399
 
405
- .chapter-marker, .chapter-marker-highlight {
406
- cursor: pointer;
407
- height: 6px;
408
- pointer-events: none;
409
- position: absolute;
410
- top: 4px;
411
- width: 3px;
412
- z-index: 2;
413
- }
414
-
415
- .chapter-marker {
416
- background-color: var(--d2l-color-ferrite);
417
- }
418
-
419
- .chapter-marker-highlight {
420
- background-color: var(--d2l-color-celestine-minus-1);
421
- }
422
-
423
- .chapter-marker[theme="dark"] {
424
- background-color: white;
425
- }
426
-
427
400
  #search-container {
428
401
  align-items: center;
429
402
  display: flex;
@@ -473,41 +446,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
473
446
  width: 100%;
474
447
  }
475
448
 
476
- #thumbnails-preview-container {
477
- bottom: 60px;
478
- position: absolute;
479
- transform: translateX(-50%);
480
- z-index: 2;
481
- }
482
-
483
- #thumbnails-preview-chapter {
484
- background: #00000072;
485
- position: absolute;
486
- text-align: center;
487
- text-shadow: 0 0 5px rgb(0 0 0 / 75%);
488
- width: 100%;
489
- z-index: 2;
490
- }
491
-
492
- #thumbnails-preview-time {
493
- background: #00000042;
494
- bottom: 3px;
495
- font-size: 14px;
496
- left: 0;
497
- position: absolute;
498
- text-align: center;
499
- text-shadow: 0 0 4px rgb(0 0 0 / 75%);
500
- width: 100%;
501
- z-index: 2;
502
- }
503
-
504
- #thumbnails-preview-image {
505
- background-repeat: no-repeat;
506
- position: relative;
507
- width: 100%;
508
- z-index: 2;
509
- }
510
-
511
449
  .search-marker {
512
450
  color: var(--d2l-color-ferrite);
513
451
  cursor: pointer;
@@ -550,73 +488,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
550
488
  font-size: 1rem;
551
489
  line-height: 2.1rem;
552
490
  }
553
-
554
- .transcript-cue-container {
555
- padding-left: 10px;
556
- }
557
- .video-transcript-cue {
558
- padding-left: 5px;
559
- }
560
- .audio-transcript-cue {
561
- padding-left: 5px;
562
- }
563
- .video-transcript-cue[active] {
564
- background-color: gray;
565
- box-shadow: -5px 0 0 white;
566
- }
567
- .audio-transcript-cue[active] {
568
- background-color: lightgray;
569
- box-shadow: -5px 0 0 black;
570
- }
571
- #video-transcript-viewer {
572
- bottom: 55px;
573
- color: white;
574
- overflow-anchor: none;
575
- overflow-y: auto;
576
- position: absolute;
577
- right: 0;
578
- top: 50px;
579
- width: 65%;
580
- z-index: 1;
581
- }
582
- #audio-transcript-viewer {
583
- bottom: 60px;
584
- color: black;
585
- overflow-anchor: none;
586
- overflow-y: auto;
587
- position: absolute;
588
- right: 0;
589
- top: 45px;
590
- width: 100%;
591
- z-index: 1;
592
- }
593
- #close-transcript {
594
- position: absolute;
595
- right: 7px;
596
- top: 0;
597
- z-index: 1;
598
- }
599
- #video-transcript-download-button {
600
- left: 35%;
601
- position: absolute;
602
- top: 5px;
603
- z-index: 2;
604
- }
605
- #audio-transcript-download-button {
606
- left: 10px;
607
- position: absolute;
608
- top: 0;
609
- z-index: 2;
610
- }
611
- #audio-transcript-download-menu {
612
- left: 35px;
613
- }
614
- #video-close-transcript-icon {
615
- color: white;
616
- }
617
- #audio-close-transcript-icon {
618
- color: black;
619
- }
620
491
  `];
621
492
 
622
493
  constructor() {
@@ -627,7 +498,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
627
498
  this.loop = false;
628
499
  this.playInView = false;
629
500
 
630
- this._chapters = [];
631
501
  this._currentTime = 0;
632
502
  this._determiningSourceType = true;
633
503
  this._duration = this.durationHint || 1;
@@ -661,8 +531,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
661
531
  this._playRequested = false;
662
532
  this._mediaContainerAspectRatio = {
663
533
  };
664
- this.afterCaptions = [];
665
- this.beforeCaptions = [];
666
534
  this._iosVideoFullscreen = false;
667
535
  }
668
536
 
@@ -760,8 +628,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
760
628
  this._searchInput = this.shadowRoot.getElementById('search-input');
761
629
  this._searchContainer = this.shadowRoot.getElementById('search-container');
762
630
 
763
- this._getMetadata();
764
-
765
631
  this._startUpdatingCurrentTime();
766
632
  new ResizeObserver((entries) => {
767
633
  for (const entry of entries) {
@@ -830,7 +696,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
830
696
  icon="${fullscreenIcon}"
831
697
  text="${fullscreenTooltip}"
832
698
  theme="${ifDefined(theme)}"
833
- @click="${this._toggleFullscreen}"></d2l-button-icon>` : null;
699
+ @click="${this._toggleFullscreen}"></d2l-button-icon>` : nothing;
834
700
 
835
701
  return html`
836
702
  <slot @slotchange=${this._onSlotChange}></slot>
@@ -841,7 +707,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
841
707
  ${this.transcriptViewerOn ? this._renderTranscriptViewer() : ''}
842
708
  ${this._getMediaAreaView()}
843
709
 
844
- ${!this._trackText || this.transcriptViewerOn ? null : html`
710
+ ${!this._trackText || this.transcriptViewerOn ? nothing : html`
845
711
  <div id="track-container" style=${styleMap(trackContainerStyle)} @click=${this._onTrackContainerClick}>
846
712
  <div>
847
713
  <span style=${styleMap(trackSpanStyle)} role="status">${this._trackText}</span>
@@ -956,6 +822,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
956
822
  </d2l-menu-item>
957
823
  ${this._getTracksMenuView()}
958
824
  ${this._getQualityMenuView()}
825
+ ${this._renderTranscriptViewerMenuItem()}
959
826
  ${(this.allowDownload && this._getCurrentSource()) ? this._getDownloadButtonView() : ''}
960
827
  <slot name="settings-menu-item"></slot>
961
828
  </d2l-menu>
@@ -976,14 +843,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
976
843
  if (changedProperties.has('src') || changedProperties.has('mediaType')) {
977
844
  this._reloadSource();
978
845
  }
979
-
980
- if (changedProperties.has('metadata')) {
981
- this._getMetadata();
982
- }
983
-
984
- if (changedProperties.has('thumbnails')) {
985
- this._getThumbnails();
986
- }
987
846
  }
988
847
 
989
848
  exitFullscreen() {
@@ -1090,10 +949,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1090
949
  localStorage.removeItem(preferenceKey);
1091
950
  }
1092
951
 
1093
- _closeTranscript() {
1094
- this.dispatchEvent(new CustomEvent('close-transcript', { bubbles: true, composed: true }));
1095
- }
1096
-
1097
952
  _disableNativeCaptions() {
1098
953
  if (!this._media) return;
1099
954
  for (let i = 0; i < this._media.textTracks.length; i++) {
@@ -1107,14 +962,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1107
962
  }
1108
963
  }
1109
964
 
1110
- _downloadCaptions() {
1111
- this.dispatchEvent(new CustomEvent('download-captions', { bubbles: true, composed: true }));
1112
- }
1113
-
1114
- _downloadTranscript() {
1115
- this.dispatchEvent(new CustomEvent('download-transcript', { bubbles: true, composed: true }));
1116
- }
1117
-
1118
965
  _endIOSVideoFullscreen() {
1119
966
  this._iosVideoFullscreen = false;
1120
967
  }
@@ -1154,57 +1001,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1154
1001
  return a.href;
1155
1002
  }
1156
1003
 
1157
- _getChapterMarkersView() {
1158
- if (this._chapters.length === 0) return;
1159
-
1160
- let start, end;
1161
- if (this._chapters[this._chapters.length - 1].time === Math.floor(this._duration)) this._chapters.pop();
1162
-
1163
- for (let i = 0; i < this._chapters.length; i++) {
1164
- if (i === this._chapters.length - 1) {
1165
- start = this._chapters[i].time;
1166
- break;
1167
- }
1168
- else if (this._hoverTime >= this._chapters[i].time && this._hoverTime < this._chapters[i + 1].time) {
1169
- start = this._chapters[i].time;
1170
- end = this._chapters[i + 1].time;
1171
- break;
1172
- }
1173
- }
1174
-
1175
- return this._chapters.map(chapter => {
1176
- const highlight = this._hovering && this._hoverTime >= this._chapters[0].time && (chapter.time === start || chapter.time === end);
1177
- return chapter.time > 0 ? html`
1178
- <div
1179
- class=${highlight ? 'chapter-marker-highlight' : 'chapter-marker'}
1180
- theme="${ifDefined(this._getTheme())}"
1181
- style=${styleMap({ left: `${this._getPercentageTime(chapter.time)}%` })}
1182
- ></div>
1183
- ` : null;
1184
- });
1185
- }
1186
-
1187
- _getChapterTitle() {
1188
- if (!(this._chapters.length > 0 && this._hoverTime >= this._chapters[0].time)) return;
1189
-
1190
- const chapter = this._chapters.find((_chapter, index, chapters) => (
1191
- index === chapters.length - 1 || (this._hoverTime >= chapters[0].time && this._hoverTime < chapters[index + 1].time)
1192
- ));
1193
- const chapterTitle = chapter && chapter.title;
1194
-
1195
- if (!chapterTitle) return;
1196
-
1197
- if (typeof chapterTitle === 'string') {
1198
- return chapterTitle;
1199
- }
1200
-
1201
- for (const locale in chapterTitle) {
1202
- if (locale.split('-')[0] === 'en') {
1203
- return chapterTitle[locale];
1204
- }
1205
- }
1206
- }
1207
-
1208
1004
  _getCurrentSource() {
1209
1005
  return this.src || this._sources[this._selectedQuality];
1210
1006
  }
@@ -1239,7 +1035,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1239
1035
  <div class="full-area-centered">
1240
1036
  <d2l-loading-spinner size="100"></d2l-loading-spinner>
1241
1037
  </div>
1242
- ` : null;
1038
+ ` : nothing;
1243
1039
  }
1244
1040
 
1245
1041
  _getMediaAreaView() {
@@ -1299,7 +1095,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1299
1095
  >
1300
1096
  <source @error=${this._onError}></source>
1301
1097
  </audio>
1302
- ${this.transcriptViewerOn ? null : html`
1098
+ ${this.transcriptViewerOn ? nothing : html`
1303
1099
  <div id="audio-bars-container">
1304
1100
  <div id="audio-play-button-container">
1305
1101
  <button id="audio-play-button" title="${playTooltip}" aria-label="${playTooltip}" @click=${this._togglePlay}>
@@ -1311,65 +1107,10 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1311
1107
  </div>`}
1312
1108
  `;
1313
1109
  default:
1314
- return null;
1110
+ return nothing;
1315
1111
  }
1316
1112
  }
1317
1113
 
1318
- _getMetadata() {
1319
- if (!this.metadata) return;
1320
-
1321
- const data = (typeof this.metadata === 'string' || this.metadata instanceof String) ? JSON.parse(this.metadata) : this.metadata;
1322
- if (!(data && data.chapters && data.chapters.length > 0)) return;
1323
- let chapters = data.chapters.map(({ time, title }) => {
1324
- return {
1325
- time: parseInt(time),
1326
- title
1327
- };
1328
- }).sort((a, b) => a.time - b.time);
1329
-
1330
- if (!data.cuts) {
1331
- data.cuts = [];
1332
- }
1333
-
1334
- // updating the chapter times based on the cuts, loops over all chapters per cut because it can change multiple chapters
1335
- let cutDiff = 0;
1336
- for (const cut of data.cuts) {
1337
- const cutIn = cut.in - cutDiff;
1338
-
1339
- const newChapters = new Map(); // using map to preserve sort ordering
1340
-
1341
- if (!cut.out) { // if cut is until the end of the video
1342
- for (const chapter of chapters) {
1343
- if (chapter.time < cutIn) {
1344
- newChapters.set(chapter.time, chapter.title);
1345
- }
1346
- }
1347
- } else {
1348
- const cutOut = cut.out - cutDiff;
1349
- const cutLength = cutOut - cutIn;
1350
-
1351
- for (const chapter of chapters) {
1352
- let newTime = chapter.time;
1353
- if (chapter.time > cutIn && chapter.time <= cutOut) {
1354
- newTime = cutIn;
1355
- } else if (chapter.time > cutOut) {
1356
- newTime = chapter.time - cutLength;
1357
- }
1358
-
1359
- newChapters.set(newTime, chapter.title);
1360
- }
1361
-
1362
- cutDiff += cutLength;
1363
- }
1364
-
1365
- chapters = [...newChapters].map(([chapterTime, chapterTitle]) => ({
1366
- time: chapterTime,
1367
- title: chapterTitle
1368
- }));
1369
- }
1370
- this._chapters = chapters;
1371
- }
1372
-
1373
1114
  _getPercentageTime(time) {
1374
1115
  if (this._media) return (time / this.duration) * 100;
1375
1116
  }
@@ -1382,7 +1123,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1382
1123
  @click=${this._onVideoClick}>
1383
1124
  <d2l-icon icon="tier1:play" theme="${ifDefined(this._getTheme())}"></d2l-icon>
1384
1125
  </button>
1385
- ` : null;
1126
+ ` : nothing;
1386
1127
 
1387
1128
  return html`
1388
1129
  ${playIcon}
@@ -1416,7 +1157,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1416
1157
  `)}
1417
1158
  </d2l-menu>
1418
1159
  </d2l-menu-item>
1419
- ` : null;
1160
+ ` : nothing;
1420
1161
  }
1421
1162
 
1422
1163
  _getSearchResultsView() {
@@ -1460,63 +1201,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1460
1201
  return this.mediaType === SOURCE_TYPES.video ? 'dark' : undefined;
1461
1202
  }
1462
1203
 
1463
- _getThumbnails() {
1464
- if (!this.thumbnails) return;
1465
- this._thumbnailsImage = new Image();
1466
- this._thumbnailsImage.src = this.thumbnails;
1467
- }
1468
-
1469
- _getTimelinePreview() {
1470
- if (!this._hovering) return;
1471
- const chapterTitleLabel = this._getChapterTitle();
1472
-
1473
- if (!(this.thumbnails && this._thumbnailsImage))
1474
- return html`
1475
- <div id="thumbnails-preview-container"
1476
- style="width: ${DEFAULT_PREVIEW_WIDTH}px; left: clamp(${DEFAULT_PREVIEW_WIDTH / 2}px, ${this._timelinePreviewOffset}%, calc(100% - ${DEFAULT_PREVIEW_WIDTH / 2}px));">
1477
- <div
1478
- id="thumbnails-preview-image"
1479
- >
1480
- <span id="thumbnails-preview-time">${MediaPlayer._formatTime(this._hoverTime)}</span>
1481
- </div>
1482
- ${chapterTitleLabel &&
1483
- html`<span class="d2l-label-text" id="thumbnails-preview-chapter" style="bottom: ${DEFAULT_PREVIEW_HEIGHT - 60}px">${chapterTitleLabel}</span>`}
1484
- </div>
1485
- `;
1486
-
1487
- // format of the thumbnail is either [url]/timelineThumbnails-h<height>w<height>i<interval>-<hash>.[png|jpg]
1488
- // or [url]/th<height>w<height>i<interval>-<hash>.[png|jpg]
1489
- const matches = this.thumbnails.match(/(timelineThumbnails-|t)h(\d+)w(\d+)i(\d+)[^/]*$/i);
1490
- if (matches && matches.length !== 5) return; // no matches
1491
- const [ , , thumbHeight, thumbWidth, interval] = matches;
1492
-
1493
- const width = this._thumbnailsImage.width;
1494
- const height = this._thumbnailsImage.height;
1495
-
1496
- const rows = height / thumbHeight;
1497
- const columns = width / thumbWidth;
1498
-
1499
- let thumbNum = Math.floor(this._hoverTime / interval);
1500
- if (thumbNum >= rows * columns) thumbNum = rows * columns - 1;
1501
-
1502
- const row = Math.floor(thumbNum / columns);
1503
- const column = thumbNum % columns;
1504
-
1505
- return html`
1506
- <div id="thumbnails-preview-container"
1507
- style="width: ${thumbWidth}px; left: clamp(${thumbWidth / 2}px, ${this._timelinePreviewOffset}%, calc(100% - ${thumbWidth / 2}px));">
1508
- <div
1509
- id="thumbnails-preview-image"
1510
- style="height: ${thumbHeight}px; background: url(${this._thumbnailsImage.src}) ${-column * thumbWidth}px ${-row * thumbHeight}px / ${width}px ${height}px;"
1511
- >
1512
- <span id="thumbnails-preview-time">${MediaPlayer._formatTime(this._hoverTime)}</span>
1513
- </div>
1514
- ${chapterTitleLabel &&
1515
- html`<span class="d2l-label-text" id="thumbnails-preview-chapter" style="bottom: ${thumbHeight}px">${chapterTitleLabel}</span>`}
1516
- </div>
1517
- `;
1518
- }
1519
-
1520
1204
  _getTrackIdentifier(srclang, kind) {
1521
1205
  return JSON.stringify({
1522
1206
  kind,
@@ -1546,7 +1230,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1546
1230
  `)}
1547
1231
  </d2l-menu>
1548
1232
  </d2l-menu-item>
1549
- ` : null;
1233
+ ` : nothing;
1550
1234
  }
1551
1235
 
1552
1236
  _hidingCustomControls() {
@@ -1601,13 +1285,7 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
1601
1285
 
1602
1286
  async _onCueChange() {
1603
1287
  if (this.transcriptViewerOn) {
1604
- if (!this._transcriptViewer) {
1605
- this._transcriptViewer = this.shadowRoot.getElementById('video-transcript-viewer')
1606
- || this.shadowRoot.getElementById('audio-transcript-viewer');
1607
- }
1608
- this._updateTranscriptViewerCues();
1609
- await this.requestUpdate();
1610
- this._scrollTranscriptViewer();
1288
+ await this._onTranscriptCueChange();
1611
1289
  }
1612
1290
  for (let i = 0; i < this._media.textTracks.length; i++) {
1613
1291
  if (this._media.textTracks[i].mode === 'hidden') {
@@ -2151,82 +1829,10 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
2151
1829
  }
2152
1830
  }
2153
1831
 
2154
- _renderTranscriptViewer() {
2155
- if (!this._media) {
2156
- return;
2157
- }
2158
- const captionsMenu = this.shadowRoot.getElementById('captions-menu');
2159
- if (captionsMenu) {
2160
- this._captionsMenuReturnItem = captionsMenu.shadowRoot.querySelector('d2l-menu-item-return');
2161
- this._captionsMenuReturnItem?.setAttribute('text', this.localize('components:mediaPlayer:language'));
2162
- }
2163
-
2164
- if (!this._transcriptViewer) {
2165
- this._onCueChange();
2166
- }
2167
-
2168
- const isVideo = this.mediaType === SOURCE_TYPES.video;
2169
- const captionsToHtml = (item) => {
2170
- const updateTime = async() => {
2171
- this.currentTime = item.startTime;
2172
- this._media.currentTime = item.startTime;
2173
- };
2174
- return html`
2175
- <div class=${isVideo ? 'video-transcript-cue' : 'audio-transcript-cue'}
2176
- @click=${updateTime}>
2177
- ${item.text}<br>
2178
- </div>`;
2179
- };
2180
-
2181
- return html`
2182
- <span id="close-transcript"
2183
- @click=${this._closeTranscript}>
2184
- <d2l-icon class="d2l-button-icon"
2185
- id=${isVideo ? 'video-close-transcript-icon' : 'audio-close-transcript-icon'}
2186
- icon="tier1:close-small"></d2l-icon>
2187
- </span>
2188
- <div
2189
- id=${isVideo ? 'video-transcript-viewer' : 'audio-transcript-viewer'}
2190
- >
2191
- <div class="transcript-cue-container">
2192
- ${this.beforeCaptions.map(captionsToHtml)}
2193
- <div class=${isVideo ? 'video-transcript-cue' : 'audio-transcript-cue'} active
2194
- id="transcript-viewer-active-cue">
2195
- ${this.transcriptActiveCue?.text}
2196
- </div>
2197
- ${this.afterCaptions.map(captionsToHtml)}
2198
- </div>
2199
- </div>
2200
- <d2l-dropdown-button-subtle
2201
- id=${isVideo ? 'video-transcript-download-button' : 'audio-transcript-download-button'}
2202
- text="${this.localize('components:mediaPlayer:download')}">
2203
- <d2l-dropdown-menu id=${isVideo ? 'video-transcript-download-menu' : 'audio-transcript-download-menu'}>
2204
- <d2l-menu>
2205
- <d2l-menu-item @click=${this._downloadTranscript} text="${this.localize('components:mediaPlayer:transcriptTxt')}"></d2l-menu-item>
2206
- <d2l-menu-item @click=${this._downloadCaptions} text="${this.localize('components:mediaPlayer:captionsVtt')}"></d2l-menu-item>
2207
- </d2l-menu>
2208
- </d2l-dropdown-menu>
2209
- </d2l-dropdown-button-subtle>
2210
- `;
2211
- }
2212
-
2213
1832
  _sanitizeText(text) {
2214
1833
  return text.replace(/<br \/>/g, '\n');
2215
1834
  }
2216
1835
 
2217
- _scrollTranscriptViewer() {
2218
- const cue = this.shadowRoot.getElementById('transcript-viewer-active-cue');
2219
- const cueRect = cue?.getBoundingClientRect();
2220
- const transcriptRect = this._transcriptViewer?.getBoundingClientRect();
2221
- if (cue && cueRect && transcriptRect) {
2222
- if (cueRect.bottom > transcriptRect.bottom && cueRect.height <= transcriptRect.height) {
2223
- this._transcriptViewer.scrollBy({ top: cueRect.bottom - transcriptRect.bottom + transcriptRect.height - cueRect.height, left: 0, behavior: 'smooth' });
2224
- } else if (cueRect.top < transcriptRect.top) {
2225
- this._transcriptViewer.scrollBy({ top: cueRect.top - transcriptRect.top, left: 0, behavior: 'smooth' });
2226
- }
2227
- }
2228
- }
2229
-
2230
1836
  _setPreference(preferenceKey, value) {
2231
1837
  if (!this.disableSetPreferences) {
2232
1838
  localStorage.setItem(preferenceKey, value);
@@ -2354,49 +1960,6 @@ class MediaPlayer extends LocalizeLabsElement(MediaPlayerAudioDescriptionsMixin(
2354
1960
  });
2355
1961
  }
2356
1962
 
2357
- _updateTranscriptViewerCues() {
2358
- let cues = null;
2359
- const lang = this._getSrclangFromTrackIdentifier(this._selectedTrackIdentifier);
2360
- for (let i = 0; i < this._media.textTracks.length; i += 1) {
2361
- const currTrack = this._media.textTracks[i];
2362
- if (currTrack?.cues) {
2363
- const activeCues = currTrack.activeCues;
2364
- if (lang === currTrack.language) {
2365
- this.transcriptActiveCue = activeCues?.[activeCues?.length - 1];
2366
- cues = currTrack.cues;
2367
- break;
2368
- }
2369
- }
2370
- }
2371
- if (!cues) {
2372
- let defaultTrack;
2373
- for (let i = 0; i < this._media.textTracks.length; i++) {
2374
- if (this._media.textTracks[i].default) {
2375
- defaultTrack = this._media.textTracks[i];
2376
- break;
2377
- }
2378
- }
2379
- defaultTrack = defaultTrack || this._media.textTracks[0];
2380
- if (defaultTrack) defaultTrack.mode = 'hidden';
2381
- this._selectedTrackIdentifier = { kind: defaultTrack?.kind, srclang: defaultTrack?.language };
2382
- this.requestUpdate();
2383
- return;
2384
- }
2385
-
2386
- this.beforeCaptions = [];
2387
- this.afterCaptions = [];
2388
- for (let i = 0; i < cues.length; i += 1) {
2389
- const currCue = cues[i];
2390
- const currTime = this._media?.currentTime;
2391
- const before = currCue !== this.transcriptActiveCue && (currCue.endTime < currTime || currCue.endTime <= this.transcriptActiveCue?.endTime);
2392
- if (before) {
2393
- this.beforeCaptions.push(currCue);
2394
- } else if (currCue !== this.transcriptActiveCue) {
2395
- this.afterCaptions.push(currCue);
2396
- }
2397
- }
2398
- }
2399
-
2400
1963
  #getOpenDropdowns() {
2401
1964
  return [...(this.shadowRoot?.querySelectorAll('d2l-dropdown-menu[opened], d2l-dropdown-content[opened]') ?? [])];
2402
1965
  }
package/src/lang/ar.js CHANGED
@@ -30,15 +30,18 @@ export default {
30
30
  "components:gradeResult:overallGrade": "العلامة الإجمالية",
31
31
  "components:gradeResult:studentGradePreviewLabel": "عرض المتعلّم للعلامات",
32
32
  "components:gradeResult:studentGradePreviewNotShown": "العلامة لا تظهر للمتعلّمين",
33
+ "components:mediaPlayer:aboutExtendedAudioDescriptions": "About Extended Audio Descriptions",
34
+ "components:mediaPlayer:aboutExtendedAudioDescriptionsText": "The video will pause when descriptions play. Options to Replay (r) and Skip (s) the description will be available during that time. Keyboard shortcuts work while focus is in the player.",
33
35
  "components:mediaPlayer:audioDescription": "Audio Description",
36
+ "components:mediaPlayer:audioDescriptions": "Audio Descriptions",
34
37
  "components:mediaPlayer:captions": "التسميات التوضيحية",
35
38
  "components:mediaPlayer:captionsVtt": "التسميات التوضيحية (‎.vtt)",
36
39
  "components:mediaPlayer:closedCaptionsAcronym": "التسميات التوضيحية المغلقة",
37
40
  "components:mediaPlayer:default": "افتراضي",
38
41
  "components:mediaPlayer:download": "تنزيل",
39
42
  "components:mediaPlayer:exitFullscreen": "الخروج من وضع ملء الشاشة",
40
- "components:mediaPlayer:extendedAudioDescription": "Extended Audio Description",
41
43
  "components:mediaPlayer:fullscreen": "ملء الشاشة",
44
+ "components:mediaPlayer:hideTranscript": "Hide transcript",
42
45
  "components:mediaPlayer:language": "اللغة",
43
46
  "components:mediaPlayer:loadErrorMessage": "عذرًا، حدثت مشكلة أثناء تحميل ملف الوسائط هذا",
44
47
  "components:mediaPlayer:loadSuccessMessage": "تم تحميل الوسائط بنجاح",
@@ -63,6 +66,7 @@ export default {
63
66
  "components:mediaPlayer:transcriptTxt": "النص (‎.txt)",
64
67
  "components:mediaPlayer:unableToDownload": "لا يمكن التنزيل. يُرجى تحديث الصفحة والمحاولة مرة أخرى.",
65
68
  "components:mediaPlayer:unmute": "إلغاء كتم الصوت",
69
+ "components:mediaPlayer:viewTranscript": "View transcript",
66
70
  "components:mediaPlayer:volumeSlider": "شريط تمرير مستوى الصوت",
67
71
  "components:navigation:back": "العودة",
68
72
  "components:navigation:next": "التالي",