diff --git a/packages/cxl-ui/package.json b/packages/cxl-ui/package.json index f72719bdc..0726e86fc 100644 --- a/packages/cxl-ui/package.json +++ b/packages/cxl-ui/package.json @@ -17,6 +17,7 @@ "@pika/plugin-build-web": "^0.9.2", "@pika/plugin-bundle-web": "^0.9.2", "@pika/plugin-standard-pkg": "^0.9.2", + "@polymer/polymer": "^3.5.1", "@vaadin/accordion": "^23.2.0", "@vaadin/button": "^23.2.0", "@vaadin/checkbox": "^23.2.0", 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/cxl-jw-player/cxl-jw-player-feedback-shadow.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-feedback-shadow.scss new file mode 100644 index 000000000..769714c22 --- /dev/null +++ b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-feedback-shadow.scss @@ -0,0 +1,3 @@ +:host(:not([hidden])) { + display: block; +} diff --git a/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-feedback.scss b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-feedback.scss new file mode 100644 index 000000000..769714c22 --- /dev/null +++ b/packages/cxl-ui/scss/cxl-jw-player/cxl-jw-player-feedback.scss @@ -0,0 +1,3 @@ +:host(:not([hidden])) { + display: block; +} 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 100% 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 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/cxl-dialog/cxl-dialog-overlay.js b/packages/cxl-ui/src/components/cxl-dialog/cxl-dialog-overlay.js new file mode 100644 index 000000000..481a8a36e --- /dev/null +++ b/packages/cxl-ui/src/components/cxl-dialog/cxl-dialog-overlay.js @@ -0,0 +1,61 @@ +import { DialogOverlay } from '@vaadin/dialog'; +import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; + +registerStyles( + 'cxl-dialog-overlay', + css` + :host { + position: absolute; + } + + [part='backdrop'] { + position: absolute; + } + `, + { moduleId: 'cxl-dialog-overlay-styles' } +); + +export class CXLDialogOverlay extends DialogOverlay { + static get is() { + return 'cxl-dialog-overlay'; + } + + static get properties() { + return { + container: Object, + }; + } + + /** @protected */ + _attachOverlay() { + if(!this.container) return super._attachOverlay(); + + this._placeholder = document.createComment('vaadin-overlay-placeholder'); + this.parentNode.insertBefore(this._placeholder, this); + this.container.appendChild(this); + this.bringToFront(); + } + + /** @protected */ + _enterModalState() { + if(!this.container) return super._enterModalState(); + + if (document.body.style.pointerEvents !== 'none') { + // Set body pointer-events to 'none' to disable mouse interactions with + // other document nodes. + this._previousDocumentPointerEvents = document.body.style.pointerEvents; + + // Don't set pointer-events + // document.body.style.pointerEvents = 'none'; + } + + // Disable pointer events in other attached overlays + CXLDialogOverlay.__attachedInstances.forEach((el) => { + if (el !== this) { + el.shadowRoot.querySelector('[part="overlay"]').style.pointerEvents = 'none'; + } + }); + } +} + +customElements.define(CXLDialogOverlay.is, CXLDialogOverlay); diff --git a/packages/cxl-ui/src/components/cxl-dialog/cxl-dialog.js b/packages/cxl-ui/src/components/cxl-dialog/cxl-dialog.js new file mode 100644 index 000000000..55cab26b2 --- /dev/null +++ b/packages/cxl-ui/src/components/cxl-dialog/cxl-dialog.js @@ -0,0 +1,85 @@ +import { html } from '@polymer/polymer/polymer-element.js'; +import { Dialog } from '@vaadin/dialog'; +import './cxl-dialog-overlay.js'; + +export class CXLDialog extends Dialog { + static get template() { + /* eslint-disable lit/no-legacy-template-syntax */ + return html` + + + `; + /* eslint-enable lit/no-legacy-template-syntax */ + } + + static get is() { + return 'cxl-dialog'; + } + + static get properties() { + return { + contained: Boolean, + container: Object, + }; + } + + constructor() { + super(); + + if (this.hasAttribute('contained')) { + this.container = this.parentNode; + } + } + + connectedCallback() { + super.connectedCallback(); + + if (this.hasAttribute('contained')) { + this.container = this.parentNode; + } + } + + ready() { + super.ready(); + + if (this.contained) { + this.container = this.parentNode; + this.$.overlay.addEventListener('click', this.onClick.bind(this)); + this.$.overlay.addEventListener('keydown', this.onKeyDown.bind(this)); + } + } + + onClick(event) { + const { overlay } = this.$; + const overlayPart = overlay.shadowRoot.querySelector('[part="overlay"]'); + const composedPath = event.composedPath(); + + if (!composedPath.includes(overlayPart)) { + this.opened = false; + } + } + + onKeyDown(e) { + if (e.key === 'Escape') { + this.opened = false; + } + } +} + +customElements.define(CXLDialog.is, CXLDialog); 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 95% 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..d6fdbcbf1 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,17 @@ -# JW Player +# CXL JW Player ## Usage ``` - + > + ...PHP + ``` ## Features: @@ -22,6 +24,7 @@ - [x] Captions search and highlight - [x] Save position - [ ] Theater mode +- [X] Feedback form ## Dependencies: diff --git a/packages/cxl-ui/src/components/cxl-jw-player/cxl-jw-player-feedback/index.js b/packages/cxl-ui/src/components/cxl-jw-player/cxl-jw-player-feedback/index.js new file mode 100644 index 000000000..6ea439bb1 --- /dev/null +++ b/packages/cxl-ui/src/components/cxl-jw-player/cxl-jw-player-feedback/index.js @@ -0,0 +1,23 @@ +import { html, LitElement } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import style from '../../../styles/cxl-jw-player/cxl-jw-player-feedback-css'; +import shadowStyle from '../../../styles/cxl-jw-player/cxl-jw-player-feedback-shadow-css'; + +@customElement('cxl-jw-player-feedback') +export class CXLJWPlayerFeedbackElement extends LitElement { + @property({ reflect: true, type: Boolean }) hidden = true; + + static get styles() { + return [shadowStyle]; + } + + render() { + return html``; + } + + async __setup() { + await super.__setup(); + + this.__addStyle(style); + } +} 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 100% 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 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 51% 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..d10aa910d 100644 --- a/packages/cxl-ui/src/components/jw-player/index.js +++ b/packages/cxl-ui/src/components/cxl-jw-player/index.js @@ -1,15 +1,17 @@ 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, FeedbackMixin, 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, + FeedbackMixin, SavePositionMixin, ]) { config = { @@ -25,10 +27,16 @@ export class JWPlayerElement extends mixin(LitElement, [ }; 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 94% 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..986147623 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'; @@ -37,6 +38,12 @@ export function BaseMixin(BaseClass) { return `https://content.jwplatform.com/libraries/${this.playerId}.js`; } + __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]; 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 100% 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 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" > - - ✕ +