From 84f1ba6abcecb97cbe149f04567dfdbf3b55842c Mon Sep 17 00:00:00 2001 From: Andrew Noblet Date: Tue, 7 Mar 2023 10:26:52 -0500 Subject: [PATCH] feat(cxl-ui): [cxl-jw-player] add separate mobile CTA feat(cxl-ui): [cxl-jw-player] fix chapter navigation when using playlists feat(cxl-ui): [cxl-jw-player] fix CTA pointer events feat(cxl-ui): [cxl-jw-player] fix saving position when using a playlist feat(cxl-ui): cxl-jw-player update component references feat(cxl-ui): [cxl-jw-player] fix poor refactoring --- .../cxl-jw-player/cxl-jw-player-shadow.scss | 9 ++- .../cxl-jw-player/cxl-jw-player-nextup.scss | 27 +++++++-- .../src/components/cxl-course-dialog.js | 6 +- .../components/cxl-jw-player/index.html.js | 2 +- .../src/components/cxl-jw-player/index.js | 1 + .../cxl-jw-player/mixins/BaseMixin.js | 27 ++++++++- .../cxl-jw-player/mixins/NextUpMixin.js | 29 ++++++--- .../cxl-jw-player/mixins/StateMixin.js | 60 ++++++++++--------- .../cxl-jw-player/mixins/TranscriptMixin.js | 4 +- .../mixins/chapter-navigation/index.js | 28 ++++++--- 10 files changed, 134 insertions(+), 59 deletions(-) diff --git a/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-shadow.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-shadow.scss index 22d930f3e..47d442925 100644 --- a/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-shadow.scss +++ b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-shadow.scss @@ -2,11 +2,16 @@ :host { box-sizing: border-box; + + [active] { + background-color: var(--lumo-shade-10pct); + } } -:host([has-captions]) { - .cxl-jw-player-container { +:host([captions]) { + #container { display: grid; + grid-template-rows: 1fr max-content 1fr; } } diff --git a/packages/cxl-ui/scss/global/cxl-jw-player/cxl-jw-player-nextup.scss b/packages/cxl-ui/scss/global/cxl-jw-player/cxl-jw-player-nextup.scss index 1587b92c9..3a1eb4ef2 100644 --- a/packages/cxl-ui/scss/global/cxl-jw-player/cxl-jw-player-nextup.scss +++ b/packages/cxl-ui/scss/global/cxl-jw-player/cxl-jw-player-nextup.scss @@ -1,19 +1,34 @@ cxl-jw-player { + &[wide] { + .jw-nextup-cta-mobile { + display: none; + } + } + + &:not([wide]) { + .jw-nextup-cta { + display: none; + } + } + .jw-nextup-container { display: flex; flex-direction: column; align-items: flex-end; + .jw-nextup-cta, + .jw-nextup-cta-mobile { + a { + pointer-events: all; + } + } + .jw-nextup-cta { max-width: 400px; width: 64%; - a { - pointer-events: all; - - vaadin-button { - width: 100%; - } + vaadin-button { + width: 100%; } } } diff --git a/packages/cxl-ui/src/components/cxl-course-dialog.js b/packages/cxl-ui/src/components/cxl-course-dialog.js index 45e8b063c..6f0cc5386 100644 --- a/packages/cxl-ui/src/components/cxl-course-dialog.js +++ b/packages/cxl-ui/src/components/cxl-course-dialog.js @@ -5,7 +5,7 @@ import { registerGlobalStyles } from '@conversionxl/cxl-lumo-styles/src/utils'; import '@vaadin/button'; import '@vaadin/dialog'; import './cxl-time.js'; -import './jw-player/index.js'; +import './cxl-jw-player/index.js'; import { dialogFooterRenderer, dialogRenderer } from '@vaadin/dialog/lit.js'; import cxlCourseDialogGlobalStyles from '../styles/global/cxl-course-dialog-css.js'; @@ -64,14 +64,14 @@ export class CXLCourseDialogElement extends LitElement {
${this.video - ? html` ` + >` : ''}

${this.course.description}

diff --git a/packages/cxl-ui/src/components/cxl-jw-player/index.html.js b/packages/cxl-ui/src/components/cxl-jw-player/index.html.js index 57f840bfa..c248e1a3e 100644 --- a/packages/cxl-ui/src/components/cxl-jw-player/index.html.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/index.html.js @@ -5,7 +5,7 @@ import '@vaadin/text-field'; // eslint-disable-next-line func-names export const template = function () { return html` -
+
${this.captions ? html` diff --git a/packages/cxl-ui/src/components/cxl-jw-player/index.js b/packages/cxl-ui/src/components/cxl-jw-player/index.js index 5504602a4..1feb2ec0b 100644 --- a/packages/cxl-ui/src/components/cxl-jw-player/index.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/index.js @@ -21,6 +21,7 @@ export class CXLJWPlayerElement extends mixin(LitElement, [ StateMixin, ]) { config = { + height: '100%', width: '100%', playbackRateControls: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], plugins: { diff --git a/packages/cxl-ui/src/components/cxl-jw-player/mixins/BaseMixin.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/BaseMixin.js index 3fc218bcd..6068c042a 100644 --- a/packages/cxl-ui/src/components/cxl-jw-player/mixins/BaseMixin.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/BaseMixin.js @@ -4,6 +4,7 @@ import { property } from 'lit/decorators.js'; import { throttle } from 'lodash-es'; import { parseSync } from 'subtitle'; import { MD5 } from 'crypto-js'; +import { MediaQueryController } from '@vaadin/component-base/src/media-query-controller.js'; export function BaseMixin(BaseClass) { class Mixin extends BaseClass { @@ -15,6 +16,9 @@ export function BaseMixin(BaseClass) { _jwPlayerContainer; + // Device Detector media query. + _wideMediaQuery = '(min-width: 750px)'; + @property({ attribute: 'api-secret', type: String }) apiSecret = ''; @property({ attribute: 'is-public', type: Boolean }) isPublic; @@ -31,6 +35,20 @@ export function BaseMixin(BaseClass) { @property({ attribute: 'playlist-source', type: String }) playlistSource; + // MediaQueryController. + @property({ type: Boolean, reflect: true }) + wide; + + constructor() { + super(); + + this.addController( + new MediaQueryController(this._wideMediaQuery, (matches) => { + this.wide = matches; + }) + ); + } + async firstUpdated(_changedProperties) { await super.firstUpdated(_changedProperties); @@ -143,6 +161,9 @@ export function BaseMixin(BaseClass) { * Each mixin has the ability to hook onto this method. */ + // eslint-disable-next-line class-methods-use-this, no-unused-vars, no-empty-function + async _onReadyListener() {} + // eslint-disable-next-line class-methods-use-this, no-unused-vars, no-empty-function async _onTimeListener(event) {} @@ -175,7 +196,11 @@ export function BaseMixin(BaseClass) { }); await new Promise((resolve) => { - this._jwPlayer.on('ready', resolve); + this._jwPlayer.on('ready', async () => { + await this._onReadyListener(); + + resolve(); + }); }); this._jwPlayerContainer = this._jwPlayer.getContainer(); diff --git a/packages/cxl-ui/src/components/cxl-jw-player/mixins/NextUpMixin.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/NextUpMixin.js index 011264f7d..b654ccc58 100644 --- a/packages/cxl-ui/src/components/cxl-jw-player/mixins/NextUpMixin.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/NextUpMixin.js @@ -3,7 +3,8 @@ import { property } from 'lit/decorators.js'; import style from '../../../styles/global/cxl-jw-player/cxl-jw-player-nextup-css'; export function NextUpMixin(BaseClass) { class Mixin extends BaseClass { - _nextUpCTA; + _nextupCTA; + _nextupCTAMobile; @property({ attribute: 'nextupoffset', type: String }) nextupoffset = '-100%`'; @@ -18,11 +19,15 @@ export function NextUpMixin(BaseClass) { this._addStyle(style); - this._nextUpCTA = document.createElement('div'); - this._nextUpCTA.classList.add('jw-nextup-cta'); + this._nextupCTA = document.createElement('div'); + this._nextupCTA.classList.add('jw-nextup-cta'); + + this._nextupCTAMobile = document.createElement('div'); + this._nextupCTAMobile.classList.add('jw-nextup-cta-mobile'); const container = this.querySelector('.jw-nextup-container'); - container.insertBefore(this._nextUpCTA, container.firstChild); + container.insertBefore(this._nextupCTA, container.firstChild); + container.insertBefore(this._nextupCTAMobile, container.firstChild); this._updateNextUp(); this._jwPlayer.on('playlistItem', this._updateNextUp.bind(this)); @@ -32,17 +37,25 @@ export function NextUpMixin(BaseClass) { const playlistItem = this._jwPlayer.getPlaylistItem(); if (playlistItem && playlistItem.coursePage) { - render(this._getTemplate(playlistItem), this._nextUpCTA); + render(this._getTemplate(playlistItem), this._nextupCTA); + render(this._getMobileTemplate(playlistItem), this._nextupCTAMobile); } } + // eslint-disable-next-line class-methods-use-this + _getMobileTemplate(playlistItem) { + return html` + + Go to course + + `; + } + // eslint-disable-next-line class-methods-use-this _getTemplate(playlistItem) { return html` - Click here to continue this course + Go to course `; } diff --git a/packages/cxl-ui/src/components/cxl-jw-player/mixins/StateMixin.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/StateMixin.js index 14eef3ca9..1046210a7 100644 --- a/packages/cxl-ui/src/components/cxl-jw-player/mixins/StateMixin.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/StateMixin.js @@ -6,6 +6,26 @@ export function StateMixin(BaseClass) { _userId; + async _index() { + if (this.playlistId) { + const index = + localStorage.getItem(`cxl-jw-player-${this.playlistId}-index`) || + this._jwPlayer.getPlaylistIndex(); + + this._jwPlayer.playlistItem(index); + + this._jwPlayer.on('playlistItem', async ({ index }) => { + localStorage.setItem(`cxl-jw-player-${this.playlistId}-index`, index); + }); + } + } + + async _onReadyListener() { + await this._index(); + this._position(); + this._playbackRate(); + } + async _setup() { await super._setup(); @@ -14,9 +34,6 @@ export function StateMixin(BaseClass) { if (typeof window.cxl_pum_vars !== 'undefined') { this._nonce = window.cxl_pum_vars.nonce; } - - this._playbackRate(); - this._position(); } _playbackRate() { @@ -32,39 +49,28 @@ export function StateMixin(BaseClass) { } _position() { - const mediaId = this.mediaId || this._jwPlayer.getPlaylistItem().mediaId; - - const position = localStorage.getItem(`cxl-jw-player-${mediaId}-position`); + if (this.mediaId) { + this._setPosition(); + } - if (position) { - if (this.mediaId) { - this._setPosition(position); - } else { - this._jwPlayer.on('playlistItem', ({ index }) => { - localStorage.setItem(`cxl-jw-player-${this.playlistId}-index`, index); - - // Wait for the player to load the new playlist item - setTimeout(() => { - this._setPosition(position); - }, 1000); - }); - - const index = - localStorage.getItem(`cxl-jw-player-${this.playlistId}-index`) || - this._jwPlayer.getPlaylistIndex(); - - this._jwPlayer.playlistItem(index); - } + if (this.playlistId) { + this._jwPlayer.on('playlistItem', async ({ index }) => { + await jwplayer().getPlaylistItemPromise(index); + this._setPosition(); + }); } this._jwPlayer.on('seek time', ({ position }) => { + const mediaId = this.mediaId || this._jwPlayer.getPlaylistItem().mediaid; localStorage.setItem(`cxl-jw-player-${mediaId}-position`, position); }); } - _setPosition(position) { + _setPosition() { + const mediaId = this.mediaId || this._jwPlayer.getPlaylistItem().mediaid; + const position = localStorage.getItem(`cxl-jw-player-${mediaId}-position`); + this._jwPlayer.seek(Number(position)); - this._jwPlayer.pause(); } } diff --git a/packages/cxl-ui/src/components/cxl-jw-player/mixins/TranscriptMixin.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/TranscriptMixin.js index 49b03c624..9f72c6f90 100644 --- a/packages/cxl-ui/src/components/cxl-jw-player/mixins/TranscriptMixin.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/TranscriptMixin.js @@ -141,7 +141,7 @@ export function TranscriptMixin(BaseClass) { } if (this._tracks.length) { - this.hasCaptions = true; + this.captions = true; // Make sure the DOM is up to date await this.updateComplete; @@ -155,7 +155,7 @@ export function TranscriptMixin(BaseClass) { 'toggle-transcript' ); } else { - this.hasCaptions = false; + this.captions = false; this._jwPlayer.removeButton('toggle-transcript'); } } diff --git a/packages/cxl-ui/src/components/cxl-jw-player/mixins/chapter-navigation/index.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/chapter-navigation/index.js index 4e9df2514..009a4c0aa 100644 --- a/packages/cxl-ui/src/components/cxl-jw-player/mixins/chapter-navigation/index.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/chapter-navigation/index.js @@ -5,25 +5,21 @@ import { chapterNavigationTemplate } from './index.html'; export function ChapterNavigationMixin(BaseClass) { class Mixin extends BaseClass { + _chapterNavigation; + @property({ attribute: 'plugin-path', type: String }) pluginPath; async _setupChapterNavigation() { const chapters = await this._getChapters(); if (!chapters.length) { - this._jwPlayer.removeButton('chapter-navigation'); + this._jwPlayer.removeButton('toggle-chapters'); return; } - this._chapterNavigation = document.createElement('div'); - this._chapterNavigation.classList.add('chapter-navigation'); - this._chapterNavigation.hidden = true; - render(chapterNavigationTemplate.bind(this)(chapters), this._chapterNavigation); - this._jwPlayerContainer.appendChild(this._chapterNavigation); - this._jwPlayer.addButton( ``, 'Show Chapters', @@ -39,9 +35,23 @@ export function ChapterNavigationMixin(BaseClass) { async _setup() { await super._setup(); - + this._addStyle(style); - this._setupChapterNavigation(); + + this._chapterNavigation = document.createElement('div'); + this._chapterNavigation.classList.add('chapter-navigation'); + this._chapterNavigation.hidden = true; + this._jwPlayerContainer.appendChild(this._chapterNavigation); + + if (this.mediaId) { + this._setupChapterNavigation(); + } + + if (this.playlistId) { + this._jwPlayer.on('playlistItem', () => { + this._setupChapterNavigation(); + }); + } } _toggleChapterNavigation() {