diff --git a/packages/cxl-ui/scss/jw-player/chapter.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-chapter-navigation.scss similarity index 100% rename from packages/cxl-ui/scss/jw-player/chapter.scss rename to packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-chapter-navigation.scss diff --git a/packages/cxl-ui/scss/jw-player/jw-player.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-shadow.scss similarity index 94% rename from packages/cxl-ui/scss/jw-player/jw-player.scss rename to packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-shadow.scss index 5868a2c64..54f4f6c4e 100644 --- a/packages/cxl-ui/scss/jw-player/jw-player.scss +++ b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-shadow.scss @@ -8,10 +8,6 @@ } } -:host([captions]) #container { - grid-template-rows: 1fr max-content 1fr; -} - .captions { h2, span { diff --git a/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-transcript-shadow.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-transcript-shadow.scss new file mode 100644 index 000000000..769714c22 --- /dev/null +++ b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-transcript-shadow.scss @@ -0,0 +1,3 @@ +:host(:not([hidden])) { + display: block; +} diff --git a/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-transcript.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-transcript.scss new file mode 100644 index 000000000..769714c22 --- /dev/null +++ b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-transcript.scss @@ -0,0 +1,3 @@ +:host(:not([hidden])) { + display: block; +} diff --git a/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player.scss new file mode 100644 index 000000000..3a387c1c1 --- /dev/null +++ b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player.scss @@ -0,0 +1,8 @@ +.jw-player-button { + width: 32px; + fill: rgba(255, 255, 255, 0.8); + + &:hover { + fill: rgba(255, 255, 255, 1); + } +} diff --git a/packages/cxl-ui/src/components/jw-player/README.md b/packages/cxl-ui/src/components/cxl-jw-player/README.md similarity index 96% rename from packages/cxl-ui/src/components/jw-player/README.md rename to packages/cxl-ui/src/components/cxl-jw-player/README.md index d8d40eb94..96d3b7815 100644 --- a/packages/cxl-ui/src/components/jw-player/README.md +++ b/packages/cxl-ui/src/components/cxl-jw-player/README.md @@ -1,15 +1,16 @@ -# JW Player +# CXL JW Player ## Usage ``` - + > ``` ## Features: diff --git a/packages/cxl-ui/src/components/cxl-jw-player/cxl-jw-player-transcript/index.js b/packages/cxl-ui/src/components/cxl-jw-player/cxl-jw-player-transcript/index.js new file mode 100644 index 000000000..5bbd17f44 --- /dev/null +++ b/packages/cxl-ui/src/components/cxl-jw-player/cxl-jw-player-transcript/index.js @@ -0,0 +1,21 @@ +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import style from '../../../styles/cxl-jw-player/cxl-jw-player-transcript-css'; +import shadowStyle from '../../../styles/cxl-jw-player/cxl-jw-player-transcript-shadow-css'; + +@customElement('cxl-jw-player-transcript') +export class CXLJWPlayerTranscriptElement extends LitElement { + static get styles() { + return [shadowStyle]; + } + + render() { + return html``; + } + + async __setup() { + await super.__setup(); + + this.__addStyle(style); + } +} diff --git a/packages/cxl-ui/src/components/jw-player/index.html.js b/packages/cxl-ui/src/components/cxl-jw-player/index.html.js similarity index 96% rename from packages/cxl-ui/src/components/jw-player/index.html.js rename to packages/cxl-ui/src/components/cxl-jw-player/index.html.js index fd37a2de1..0199e1eb3 100644 --- a/packages/cxl-ui/src/components/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/jw-player/index.js b/packages/cxl-ui/src/components/cxl-jw-player/index.js similarity index 50% rename from packages/cxl-ui/src/components/jw-player/index.js rename to packages/cxl-ui/src/components/cxl-jw-player/index.js index c0a80cb51..fd42ca9d0 100644 --- a/packages/cxl-ui/src/components/jw-player/index.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/index.js @@ -1,20 +1,20 @@ import { LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; -import { BaseMixin, CaptionMixin, ChapterMixin, SavePositionMixin } from './mixins'; -import style from '../../styles/jw-player/jw-player-css'; +import { BaseMixin, TranscriptMixin, ChapterNavigationMixin, SavePositionMixin } from './mixins'; +import style from '../../styles/cxl-jw-player/cxl-jw-player-css'; +import shadowStyle from '../../styles/cxl-jw-player/cxl-jw-player-shadow-css'; import { mixin } from './utility'; import { template } from './index.html'; -@customElement('jw-player') -export class JWPlayerElement extends mixin(LitElement, [ +@customElement('cxl-jw-player') +export class CXLJWPlayerElement extends mixin(LitElement, [ BaseMixin, - CaptionMixin, - ChapterMixin, + TranscriptMixin, + ChapterNavigationMixin, SavePositionMixin, ]) { config = { width: '100%', - height: '100%', playbackRateControls: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], plugins: { // 'http://192.168.0.101:8080/telemetry-8.20.0.js': {}, @@ -22,13 +22,20 @@ export class JWPlayerElement extends mixin(LitElement, [ skin: { name: 'cxl-institute', }, + stretching: 'uniform', }; static get styles() { - return [style]; + return [shadowStyle]; } render() { return template.bind(this)(); } + + async __setup() { + await super.__setup(); + + this.__addStyle(style); + } } diff --git a/packages/cxl-ui/src/components/jw-player/mixins/BaseMixin.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/BaseMixin.js similarity index 54% rename from packages/cxl-ui/src/components/jw-player/mixins/BaseMixin.js rename to packages/cxl-ui/src/components/cxl-jw-player/mixins/BaseMixin.js index 5f49c5e83..531233f97 100644 --- a/packages/cxl-ui/src/components/jw-player/mixins/BaseMixin.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/BaseMixin.js @@ -1,3 +1,4 @@ +import { render } from 'lit'; import { property } from 'lit/decorators.js'; import { throttle } from 'lodash-es'; import { parseSync } from 'subtitle'; @@ -16,10 +17,18 @@ export function BaseMixin(BaseClass) { @property({ attribute: 'media-id', type: String }) mediaId; - @property({ attribute: 'player-id', type: String }) playerId; + @property({ attribute: 'media-source', type: String }) mediaSource; + + @property({ attribute: 'is-public', type: String }) isPublic; + + @property({ attribute: 'library-id', type: String }) libraryId; + + @property({ attribute: 'library-source', type: String }) librarySource; @property({ attribute: 'playlist-id', type: String }) playlistId; + @property({ attribute: 'playlist-source', type: String }) playlistSource; + firstUpdated(_changedProperties) { super.firstUpdated(_changedProperties); @@ -34,33 +43,60 @@ export function BaseMixin(BaseClass) { } get __scriptUrl() { - return `https://content.jwplatform.com/libraries/${this.playerId}.js`; + let scriptUrl; + + if (this.libraryId && this.isPublic) { + scriptUrl = `https://content.jwplatform.com/libraries/${this.libraryId}.js`; + } else if (this.librarySource) { + scriptUrl = this.librarySource; + } else { + return false; + } + + return scriptUrl; + } + + __addStyle(style) { + const el = document.createElement('style'); + render(style, el); + this.appendChild(el); } async __getChapters() { const playlistItem = this.__jwPlayer.getPlaylistItem(); - const { file } = playlistItem.tracks.filter((track) => track.kind === 'chapters')[0]; + const chapters = playlistItem.tracks.filter((track) => track.kind === 'chapters'); + const { file } = chapters.length > 0 ? chapters[0] : ''; const response = await (await fetch(file)).text(); return parseSync(response); } async __getMedia() { - if (!this.mediaId) return false; - - const response = await fetch(`https://cdn.jwplayer.com/v2/media/${this.mediaId}`); - const result = await response.json(); + let response; + + if (this.mediaId && this.isPublic) { + response = await fetch(`https://cdn.jwplayer.com/v2/media/${this.mediaId}`); + } else if (this.mediaSource) { + response = await fetch(this.mediaSource); + } else { + return false; + } - return result; + return response.json(); } async __getPlaylist() { - if (!this.playlistId) return false; - - const response = await fetch(`https://cdn.jwplayer.com/v2/playlists/${this.playlistId}`); - const result = await response.json(); + let response; + + if (this.playlistId) { + response = await fetch(`https://cdn.jwplayer.com/v2/playlists/${this.playlistId}`); + } else if (this.playlistSource) { + response = await fetch(`https://cdn.jwplayer.com/v2/playlists/${this.playlistId}`); + } else { + return false; + } - return result; + return response.json(); } async __loadScript() { @@ -90,6 +126,15 @@ export function BaseMixin(BaseClass) { * Each mixin has the ability to hook onto this method. */ async __setup() { + + // Merge configs from `cxlJWPlayerData`. + if (typeof window.cxlJWPlayerData !== 'undefined') { + // eslint-disable-next-line camelcase + const { media_config } = window.cxlJWPlayerData[this.mediaId]; + // eslint-disable-next-line camelcase + this.config = { ...this.config, ...media_config }; + } + const jwPlayer = await this.__loadScript(); const el = document.createElement('div'); diff --git a/packages/cxl-ui/src/components/jw-player/mixins/SavePositionMixin.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/SavePositionMixin.js similarity index 81% rename from packages/cxl-ui/src/components/jw-player/mixins/SavePositionMixin.js rename to packages/cxl-ui/src/components/cxl-jw-player/mixins/SavePositionMixin.js index 6ae10b0b6..9ea091ba6 100644 --- a/packages/cxl-ui/src/components/jw-player/mixins/SavePositionMixin.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/SavePositionMixin.js @@ -1,6 +1,6 @@ export function SavePositionMixin(BaseClass) { class Mixin extends BaseClass { - __endpoint = ''; + __endpoint; __nonce; @@ -9,6 +9,12 @@ export function SavePositionMixin(BaseClass) { async __setup() { await super.__setup(); + this.__endpoint = `${window.ajaxurl}?action=jwplayer_save_position`; + + if ( typeof window.cxl_pum_vars !== 'undefined' ) { + this.__nonce = window.cxl_pum_vars.nonce; + } + this.__loadPosition(); } diff --git a/packages/cxl-ui/src/components/jw-player/mixins/CaptionMixin.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/TranscriptMixin.js similarity index 78% rename from packages/cxl-ui/src/components/jw-player/mixins/CaptionMixin.js rename to packages/cxl-ui/src/components/cxl-jw-player/mixins/TranscriptMixin.js index fbeb3f765..9ee8d35f2 100644 --- a/packages/cxl-ui/src/components/jw-player/mixins/CaptionMixin.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/TranscriptMixin.js @@ -3,13 +3,13 @@ import { debounce } from 'lodash-es'; import Mark from 'mark.js'; import { parseSync } from 'subtitle'; -export function CaptionMixin(BaseClass) { +export function TranscriptMixin(BaseClass) { class Mixin extends BaseClass { __debouncedSearch; __mark; - @property({ type: Boolean }) captions = false; + @property({ reflect: true, type: Boolean }) captions = false; @state() __currentCue = 0; @@ -117,12 +117,19 @@ export function CaptionMixin(BaseClass) { async __setup() { await super.__setup(); - this.__setupCaptions(); + this.__setupTranscript(); } - async __setupCaptions() { + async __setupTranscript() { if (!this.__jwPlayer) return; + this.__jwPlayer.addButton( + ``, + 'Transcript', + this.__toggleTranscript.bind(this), + 'toggle-transcript' + ); + if (this.captions) { this.__tracks = await this.__getTracks(); @@ -138,16 +145,26 @@ export function CaptionMixin(BaseClass) { if (changedProperties.has('captions')) { if (this.captions) { - this.__setupCaptions(); + this.__setupTranscript(); } else if (this.mark) { this.__mark.unmark(); } } } + __attachListeners() { + super.__attachListeners(); + } + __toggleShouldScroll() { this.shouldScroll = !this.shouldScroll; } + + __toggleTranscript() { + // this.dispatchEvent(new CustomEvent('toggle-transcript')); + + this.captions = !this.captions; + } } return Mixin; diff --git a/packages/cxl-ui/src/components/jw-player/mixins/chapter/index.html.js b/packages/cxl-ui/src/components/cxl-jw-player/mixins/chapter-navigation/index.html.js similarity index 89% rename from packages/cxl-ui/src/components/jw-player/mixins/chapter/index.html.js rename to packages/cxl-ui/src/components/cxl-jw-player/mixins/chapter-navigation/index.html.js index 88b64537d..6c1cb1f4d 100644 --- a/packages/cxl-ui/src/components/jw-player/mixins/chapter/index.html.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/mixins/chapter-navigation/index.html.js @@ -13,8 +13,7 @@ export const chapterNavigationTemplate = function (chapters) { theme="icon small primary" aria-label="Close" > - - ✕ +