@haxtheweb/a11y-media-player
Version:
A feature rich, highly accessible video player
1,425 lines (1,319 loc) • 107 kB
JavaScript
/**
* Copyright 2019 The Pennsylvania State University
* @license Apache-2.0, see License.md for full text.
*/
import { LitElement, html, css } from "lit";
import { DDD } from "@haxtheweb/d-d-d/d-d-d.js";
import { FullscreenBehaviors } from "@haxtheweb/fullscreen-behaviors/fullscreen-behaviors.js";
import "@haxtheweb/anchor-behaviors/anchor-behaviors.js";
import "@haxtheweb/responsive-utility/responsive-utility.js";
import { normalizeEventPath } from "@haxtheweb/utils/utils.js";
import "@haxtheweb/absolute-position-behavior/absolute-position-behavior.js";
import "@haxtheweb/simple-tooltip/simple-tooltip.js";
import "@haxtheweb/simple-search/simple-search.js";
import "@haxtheweb/simple-range-input/simple-range-input.js";
import "@haxtheweb/simple-fields/lib/simple-fields-field.js";
import "./lib/a11y-media-play-button.js";
import "./lib/a11y-media-state-manager.js";
import "./lib/a11y-media-button.js";
import "./lib/a11y-media-transcript-cue.js";
import "./lib/a11y-media-youtube.js";
/**
* `a11y-media-player`
* an accessible video player
*
### Styling
`<a11y-media-player>` provides the following basic custom properties
for styling:
#### Basic Styling
Custom property | Description | Default
----------------|-------------|----------
`--a11y-media-color` | default text color | `--simple-colors-default-theme-grey-11`
`--a11y-media-bg-color` | default background color | `--simple-colors-default-theme-grey-2`
`--a11y-media-border-color` | default border color | `--simple-colors-default-theme-grey-3`
`--a11y-media-hover-color` | text color when hovering | `--simple-colors-default-theme-grey-12`
`--a11y-media-hover-bg-color` | background color when hovering | `--simple-colors-default-theme-grey-2`
`--a11y-media-accent-color` | accent color | `--simple-colors-default-theme-accent-9`
`--a11y-media-faded-accent-color` | accent color when faded | `--simple-colors-default-theme-accent-8`
`--a11y-media-disabled-color` | color for disabled items | `--simple-colors-default-theme-grey-5`
`--a11y-media-transcript-color` | default text color of transcript | `--simple-colors-default-theme-grey-7`
`--a11y-media-transcript-bg-color` | default background color of transcript | `--simple-colors-default-theme-grey-1`
`--a11y-media-transcript-accent-color` | default accent color of transcript | `--simple-colors-default-theme-accent-8`
`--a11y-media-transcript-faded-accent-color` | accent color of transcript, faded | `--simple-colors-default-theme-accent-10`
`--a11y-media-transcript-cue-color` | text color of transcript cue | `--simple-colors-fixed-theme-grey-12`
`--a11y-media-transcript-cue-bg-color` | background color of transcript cue | `--simple-colors-fixed-theme-grey-1`
`--a11y-media-transcript-active-cue-color` | text color of active transcript cue | `--simple-colors-fixed-theme-grey-12`
`--a11y-media-transcript-active-cue-bg-color` | background color of active transcript cue | `--simple-colors-fixed-theme-accent-1`
`--a11y-media-transcript-focused-cue-color` | text color of focused transcript cue | `--simple-colors-fixed-theme-grey-12`
`--a11y-media-transcript-focused-cue-bg-color` | background color of focused transcript cue | `--simple-colors-fixed-theme-grey-2`
`--a11y-media-transcript-match-color` | text color of matched term in transcript search | `--simple-colors-fixed-theme-grey-1`
`--a11y-media-transcript-match-bg-color` | background color of matched term in transcript search | `--simple-colors-fixed-theme-accent-10`
`--a11y-media-transcript-match-border-color` | border color of matched term in transcript search | `--simple-colors-fixed-theme-accent-12`
#### Controls
Custom property | Description | Default
----------------|-------------|----------
`--a11y-media-scrollbar-width` | default width of scrollbars | `5px`
`--a11y-media-controls-font-family` | font-family of controls
#### Buttons
Custom property | Description | Default
----------------|-------------|----------
`--a11y-media-button-color` | button text color | `--a11y-media-color`
`--a11y-media-button-bg-color` | button background color | `--a11y-media-bg-color`
`--a11y-media-button-hover-color` | button text color when hovering | `--a11y-media-accent-color`
`--a11y-media-button-hover-bg-color` | button background color when hovering | `--a11y-media-hover-bg-color`
`--a11y-media-button-disabled-color` | button text color when disabled | `--a11y-media-disabled-color`
`--a11y-media-button-toggle-color` | button text color when toggled | `--a11y-media-faded-accent-color`
#### Sliders
Custom property | Description | Default
----------------|-------------|----------
`--simple-range-input-active-color` | slider color when active | `--a11y-media-accent-color`
`--simple-range-input-secondary-color` | slider color for buffering | `--a11y-media-faded-accent-color`
`--simple-range-input-pin-color` | slider pin color | `--a11y-media-bg-color`
`--simple-range-input-pin-start-color` | slider pin color in start position | `--a11y-media-bg-color`
`--simple-range-input-pin-end-color` | slider pin color in end position | `--a11y-media-bg-color`
`--simple-range-input-knob-color` | slider knob color | `--a11y-media-accent-color`
`--simple-range-input-knob-start-color` | slider knob color in start position | `--a11y-media-accent-color`
`--simple-range-input-knob-end-color` | slider knob color in end position | `--a11y-media-bg-accent-color`
`--simple-range-input-knob-border-color` | slider knob border color | `--a11y-media-accent-color`
`--simple-range-input-knob-start-border-color` | slider knob border color in start position | `--a11y-media-bg-color`
`--simple-range-input-knob-end-border-color` | slider knob border color in end position | `--a11y-media-bg-color`
#### Settings Menu
Custom property | Description | Default
----------------|-------------|----------
`--a11y-media-settings-menu-color` | settings menu text color | `--a11y-media-color`
`--a11y-media-settings-menu-bg-color` | settings menu background color | `--a11y-media-bg-color`
`--a11y-media-settings-menu-hover-color` | settings menu text color when hovering | `--a11y-media-hover-color`
`--a11y-media-settings-menu-hover-bg-color` | settings menu background color when hovering | `--a11y-media-hover-bg-color`
#### Link Sharing Toast
Custom property | Description | Default
----------------|-------------|----------
`--simple-toast-color` | toast text color | `--a11y-media-color`
`--simple-toast-background-color` | toast background color | `--a11y-media-bg-color`
*
* @element a11y-media-player
* @extends DDD
* @demo ./demo/index.html video demo
* @demo ./demo/audio.html audio demo
* @demo ./demo/youtube.html YouTube demo
*/
class A11yMediaPlayer extends FullscreenBehaviors(DDD) {
//styles function
static get styles() {
return [
super.styles,
css`
:host {
display: block;
overflow: hidden;
width: calc(100% - 2px);
font-family: var(--ddd-font-navigation);
--a11y-media-controls-font-family: var(--ddd-font-navigation);
--a11y-media-player-height: unset;
--a11y-media-color: var(
--simple-colors-default-theme-grey-11,
#111111
);
--a11y-media-bg-color: var(
--simple-colors-default-theme-grey-2,
#eeeeee
);
--a11y-media-border-color: var(
--simple-colors-default-theme-grey-3,
#dddddd
);
--a11y-media-hover-color: var(
--simple-colors-default-theme-grey-12,
#000000
);
--a11y-media-hover-bg-color: var(
--simple-colors-default-theme-grey-2,
#eeeeee
);
--a11y-media-accent-color: var(
--simple-colors-default-theme-accent-9,
#333333
);
--a11y-media-faded-accent-color: var(
--simple-colors-default-theme-accent-8,
#444444
);
--a11y-media-disabled-color: var(
--simple-colors-default-theme-grey-5,
#bbbbbb
);
border: 1px solid
var(
--a11y-media-border-color,
var(--simple-colors-default-theme-grey-3)
);
--a11y-media-settings-menu-color: var(--a11y-media-color);
--a11y-media-settings-menu-bg-color: var(--a11y-media-bg-color);
--a11y-media-settings-menu-hover-color: var(--a11y-media-hover-color);
--a11y-media-settings-menu-hover-bg-color: var(
--a11y-media-hover-bg-color
);
--simple-fields-accent-color: var(--a11y-media-accent-color);
--simple-fields-background-color: var(--a11y-media-bg-color);
--simple-fields-color: var(--a11y-media-color);
--simple-fields-border-color: var(--a11y-media-border-color);
--simple-fields-border-color-light: var(
--a11y-media-border-color-light,
var(--a11y-media-border-color)
);
--a11y-media-button-color: var(--a11y-media-color);
--a11y-media-button-bg-color: var(--a11y-media-bg-color);
--a11y-media-button-hover-color: var(--a11y-media-accent-color);
--a11y-media-button-hover-bg-color: var(--a11y-media-hover-bg-color);
--a11y-media-button-disabled-color: var(--a11y-media-disabled-color);
--a11y-media-button-toggle-color: var(
--a11y-media-faded-accent-color
);
--simple-range-input-bg: var(--a11y-media-accent-color);
--simple-range-input-color: var(--a11y-media-color);
--simple-range-input-track-height: 4px;
--simple-range-input-pin-height: 10px;
--simple-toast-color: var(--a11y-media-color);
--simple-toast-background-color: var(--a11y-media-bg-color);
--a11y-media-transcript-color: var(
--simple-colors-default-theme-grey-7,
#666666
);
--a11y-media-transcript-bg-color: var(
--simple-colors-default-theme-grey-1,
#ffffff
);
--a11y-media-transcript-accent-color: var(
--simple-colors-default-theme-accent-8,
#444444
);
--a11y-media-transcript-faded-accent-color: var(
--simple-colors-default-theme-accent-10,
#222222
);
--a11y-media-transcript-cue-color: var(
--simple-colors-fixed-theme-grey-12,
#000000
);
--a11y-media-transcript-cue-bg-color: var(
--simple-colors-fixed-theme-grey-1,
#ffffff
);
--a11y-media-transcript-active-cue-color: var(
--simple-colors-fixed-theme-grey-12,
#000000
);
--a11y-media-transcript-active-cue-bg-color: var(
--simple-colors-fixed-theme-accent-1,
#ffffff
);
--a11y-media-transcript-focused-cue-color: var(
--simple-colors-fixed-theme-grey-12,
#000000
);
--a11y-media-transcript-focused-cue-bg-color: var(
--simple-colors-fixed-theme-grey-2,
#eeeeee
);
--a11y-media-transcript-match-color: var(
--simple-colors-fixed-theme-grey-1,
#ffffff
);
--a11y-media-transcript-match-bg-color: var(
--simple-colors-fixed-theme-accent-10,
#222222
);
--a11y-media-transcript-match-border-color: var(
--simple-colors-fixed-theme-accent-12,
#000000
);
}
:host([dark]) {
border: 1px solid var(--simple-colors-default-theme-grey-1, #000000);
}
:host([dark-transcript]) {
--a11y-media-transcript-bg-color: var(
--simple-colors-dark-theme-grey-1,
#000000
);
--a11y-media-transcript-cue-color: var(
--simple-colors-dark-theme-grey-12,
#ffffff
);
--a11y-media-transcript-cue-bg-color: var(
--simple-colors-dark-theme-grey-1,
#000000
);
--a11y-media-transcript-active-cue-color: var(
--simple-colors-dark-theme-accent-10,
#dddddd
);
--a11y-media-transcript-active-cue-bg-color: var(
--simple-colors-dark-theme-grey-1,
#000000
);
--a11y-media-transcript-match-color: var(
--simple-colors-dark-theme-grey-1,
#000000
);
--a11y-media-transcript-match-bg-color: var(
--simple-colors-dark-theme-accent-10,
#dddddd
);
--a11y-media-transcript-match-border-color: var(
--simple-colors-dark-theme-accent-12,
#ffffff
);
--a11y-media-transcript-focused-cue-color: var(
--simple-colors-dark-theme-grey-12,
#ffffff
);
--a11y-media-transcript-focused-cue-bg-color: var(
--simple-colors-dark-theme-grey-2,
#111111
);
}
:host *::-webkit-scrollbar {
width: var(--a11y-media-scrollbar-width, 5px);
}
:host([hidden]),
*[hidden] {
display: none !important;
}
:host([height]) {
height: calc(var(--a11y-media-player-height) - 2px);
max-height: calc(var(--a11y-media-player-height) - 2px);
overflow: unset;
}
:host([height]) #player-section {
max-height: var(--a11y-media-player-height);
}
:host([height]) #player-and-controls {
max-height: calc(100% - 32px - 44px);
}
:host([height]) #player {
height: calc(100% - 32px - 44px);
padding-top: unset;
}
:host,
#player-section {
color: var(--a11y-media-hover-color);
background-color: var(--a11y-media-bg-color);
}
:host > * {
transition: all 0.5s;
}
:host,
#player-section,
#player,
#transcript-section,
#transcript-and-controls {
display: flex;
flex-flow: column;
align-items: stretch;
align-content: stretch;
}
#captionlink:link {
text-decoration: none;
}
#player-and-controls,
#player,
#player > *,
#cc-custom,
#cc-text,
#slider,
#controls,
#player-section,
#transcript-section,
#transcript-and-controls {
width: 100%;
}
#transcript-and-controls > * {
width: calc(100% - 1px);
}
:host > *,
#player-and-controls,
#player,
#player > *,
#cc-text {
flex: 1 1 auto;
}
#controls,
#searchbar {
flex: 0 0 44px;
}
#player-and-controls {
margin: 0 auto;
display: flex;
}
#player {
height: 400px;
position: relative;
background-size: cover;
background-position: center;
}
#player > * {
position: absolute;
top: 0;
left: 0;
height: 100%;
}
#playbutton,
#slider,
#controls {
z-index: 2;
}
#html5 {
min-width: 100px;
display: flex;
align-items: stretch;
}
:host([audio-only]) #playbutton {
opacity: 0;
}
#slider {
flex: 0 0 32px;
height: 32px;
background-color: var(--a11y-media-bg-color);
--simple-range-input-pin-height: 15px;
}
a11y-media-youtube {
opacity: 1;
transition: opacity 0.5s;
}
a11y-media-youtube.hidden {
opacity: 0;
}
#cc-custom:not([hidden]) {
font-size: 20px;
transition: font-size 0.25s;
display: flex;
}
#cc-text {
align-self: flex-end;
font-family: sans-serif;
color: white;
margin: 4px 10px;
padding: 0.15em 4px;
background-color: black;
background-color: rgba(0, 0, 0, 0.8);
transition: all 0.5s;
}
#player-and-controls[audio-no-thumb] #cc-text {
align-self: center;
color: var(--a11y-media-color);
background-color: transparent;
}
#controls {
display: block;
width: 100%;
max-width: 100%;
height: 44px;
max-height: 44px;
position: relative;
color: var(--a11y-media-color);
background-color: var(--a11y-media-bg-color);
--primary-text-color: var(--a11y-media-settings-menu-color);
}
#controls-left {
position: absolute;
left: 0;
min-width: 200px;
}
#controls-right {
position: absolute;
right: 0;
top: 0;
}
absolute-position-behavior {
background-color: var(--a11y-media-settings-menu-bg-color);
color: var(--a11y-media-settings-menu-color);
border: 1px solid
var(
--a11y-media-border-color,
var(--simple-colors-default-theme-grey-3)
);
max-height: 200px;
overflow-y: scroll;
overflow-x: hidden;
}
absolute-position-behavior::-webkit-scrollbar-track {
background-color: var(--a11y-media-settings-menu-bg-color);
}
absolute-position-behavior::-webkit-scrollbar-thumb {
background-color: var(--a11y-media-settings-menu-color);
}
absolute-position-behavior .setting {
min-height: 42px;
padding: 2px 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
absolute-position-behavior simple-field-field {
margin-top: 0 !important;
margin-bottom: 0 !important;
background-color: var(--a11y-media-settings-menu-bg-color);
color: var(--a11y-media-settings-menu-color);
}
.setting-text {
margin-right: 1em;
font-family: var(--a11y-media-controls-font-family);
}
.setting-control {
max-width: 110px;
}
.setting-slider {
flex: 0 0 110px;
margin-left: -15px;
margin-right: -15px;
}
#loop {
flex: 0 0 40px;
}
#loop-label {
flex: 1 1 auto;
}
.play-status {
border: none;
position: relative;
font-size: 85%;
font-family: var(--a11y-media-controls-font-family);
}
.play-status.control-bar {
padding: 8px 13px 8px;
}
:host([hide-play-status]) .play-status {
display: none;
}
#volume-and-mute {
display: inline-block;
position: relative;
}
#volume {
position: absolute;
left: 30px;
top: 0px;
width: 0;
height: 40px;
overflow: hidden;
transition: width 0.5s;
z-index: 3;
border-radius: 4px;
background-color: var(--a11y-media-bg-color);
}
#volume:active,
#volume:focus,
#volume:hover,
#volume.focus,
#volume-and-mute:active #volume,
#volume-and-mute:focus #volume,
#volume-and-mute:hover #volume {
overflow: visible;
width: 100px;
}
:host([responsive-size="xs"]) #volume:active,
:host([responsive-size="xs"]) #volume:focus,
:host([responsive-size="xs"]) #volume:hover,
:host([responsive-size="xs"]) #volume.focus,
:host([responsive-size="xs"]) #volume-and-mute:active #volume,
:host([responsive-size="xs"]) #volume-and-mute:focus #volume,
:host([responsive-size="xs"]) #volume-and-mute:hover #volume,
:host([width]) #volume:active,
:host([width]) #volume:focus,
:host([width]) #volume:hover,
:host([width]) #volume.focus,
:host([width]) #volume-and-mute:active #volume,
:host([width]) #volume-and-mute:focus #volume,
:host([width]) #volume-and-mute:hover #volume {
top: 0px;
}
#print-thumbnail {
width: 100%;
margin: 0;
display: block;
border-top: 1px solid #aaaaaa;
}
.media-caption:not(:empty) {
padding: var(--ddd-spacing-2) var(--ddd-spacing-4);
font-size: var(--ddd-font-size-xs);
font-weight: bold;
}
.media-type {
font-style: italic;
}
#searchbar {
display: flex;
align-items: stretch;
justify-content: space-between;
height: 44px;
max-height: 44px;
min-height: 44px;
width: 100%;
color: var(--a11y-media-color);
background-color: var(--a11y-media-transcript-bg-color);
--simple-fields-color: var(--a11y-media-color);
--a11y-media-button-bg-color: var(--a11y-media-transcript-bg-color);
--a11y-media-button-hover-bg-color: var(
--a11y-media-transcript-bg-color
);
--simple-search-input-background-color: var(
--a11y-media-transcript-bg-color
);
--simple-search-input-text-color: var(--a11y-media-color);
--simple-search-input-line-color: var(--a11y-media-accent-color);
--simple-search-input-placeholder-color: var(--a11y-media-color);
--simple-search-button-color: var(--a11y-media-accent-color);
--simple-search-button-hover-color: var(
--a11y-media-faded-accent-color
);
--simple-search-button-bg-color: var(
--a11y-media-transcript-bg-color
);
--simple-search-button-border-color: var(
--a11y-media-transcript-bg-color
);
--simple-search-button-hover-border-color: var(
--a11y-media-transcript-bg-color
);
--simple-search-button-disabled-color: var(
--a11y-media-disabled-color
);
--simple-search-button-disabled-bg-color: var(
--a11y-media-transcript-bg-color
);
--simple-search-button-disabled-border-color: var(
--a11y-media-border-color
);
--simple-search-padding: 0 15px;
}
:host([dark]) #searchbar {
background-color: var(--a11y-media-bg-color);
--a11y-media-button-bg-color: var(--a11y-media-bg-color);
--a11y-media-button-hover-bg-color: var(--a11y-media-bg-color);
--simple-search-input-background-color: var(--a11y-media-bg-color);
--simple-search-button-bg-color: var(--a11y-media-bg-color);
--simple-search-button-border-color: var(--a11y-media-bg-color);
--simple-search-button-hover-border-color: var(--a11y-media-bg-color);
--simple-search-button-disabled-bg-color: var(--a11y-media-bg-color);
}
#searching {
flex-grow: 2;
}
#autoscroll {
padding-right: 8px;
}
#scrolling,
#printing {
display: flex;
align-items: center;
}
#transcript-section {
padding: 0 1px 0 0;
}
#transcript-and-controls {
flex: 1 0 194px;
}
#transcript {
flex: 1 0 150px;
max-height: var(--a11y-media-transcript-max-height, unset);
overflow-y: scroll;
color: var(--a11y-media-transcript-cue-color);
background-color: var(--a11y-media-transcript-cue-bg-color);
border-left: 1px solid var(--a11y-media-transcript-bg-color);
}
#transcript::-webkit-scrollbar-track {
background-color: var(--a11y-media-transcript-cue-bg-color);
}
#transcript::-webkit-scrollbar-thumb {
background-color: var(--a11y-media-transcript-cue-color);
}
.transcript-from-track {
display: table;
width: calc(100% - 30px);
padding: 0 15px 15px;
color: var(--a11y-media-transcript-cue-color);
background-color: var(--a11y-media-transcript-cue-bg-color);
font-size: var(--a11y-media-transcript-cue-font-size, 14px);
line-height: var(--a11y-media-transcript-cue-line-height, 28px);
}
.transcript-from-track[hideTimestamps] {
display: block;
}
.sr-only {
position: absolute;
left: -9999px;
font-size: 0;
height: 0;
width: 0;
overflow: hidden;
}
absolute-position-behavior:not(:defined),
simple-tooltip:not(:defined) {
display: none;
}
::slotted(iframe) {
display: none;
}
@media screen {
:host([full-flex]) {
flex-flow: row;
padding: 0;
}
:host([full-flex]) #player-section {
max-width: 50%;
flex: 1 0 auto;
}
:host([full-flex]) #transcript-section {
min-width: 50%;
flex: 0 1 auto;
}
:host([full-flex]) #transcript {
position: absolute;
top: 44px;
left: 0;
right: 0;
bottom: 0;
overflow-y: scroll;
}
#transcript-and-controls {
position: relative;
}
:host([sticky-mode]) #player-section {
position: fixed;
top: 5px;
right: 5px;
width: 200px;
max-width: 200px;
z-index: 999999;
border: 1px solid var(--a11y-media-bg-color);
box-shadow: 1px 1px 20px 1px rgba(125, 125, 125);
border-radius: 3.2px;
}
:host([fullscreen]) #player-section {
width: 100%;
height: 100vh;
max-width: 100vw;
position: absolute;
position: sticky;
left: 0;
top: 0;
z-index: 100000;
transition: all 0.5s;
}
:host([dark][sticky-mode]) #player-section {
border: 1px solid var(--a11y-media-bg-color);
}
:host([sticky][sticky-corner="top-left"]) #player-section {
right: unset;
left: 5px;
}
:host(
:not([no-height]):not([stacked-layout]):not(
[responsive-size="xs"]
):not([responsive-size="sm"])
)
#player-and-controls.totop {
position: absolute;
top: 0;
left: 0;
width: 200px !important;
z-index: 9999;
}
:host([sticky][sticky-corner="bottom-left"]) #player-and-controls {
top: unset;
right: unset;
bottom: 5px;
}
:host([sticky][sticky-corner="bottom-right"]) #player-and-controls {
top: unset;
bottom: 5px;
}
:host([sticky-mode]) .screen-only.media-caption,
:host([responsive-size="xs"]) .screen-only.media-caption {
display: none;
}
:host([sticky-mode]) #player-and-controls[audio-no-thumb] {
max-height: 0px;
overflow: hidden;
}
:host([sticky-mode]) .hide-sticky,
:host([sticky-mode]) .hide-full-xs,
:host([sticky-mode]) .hide-full-sm,
:host([sticky-mode]) .hide-flex,
:host([width]) .hide-full-xs,
:host([width]) .hide-full-sm,
:host([width]) .hide-full-flex,
:host([responsive-size="xs"]) .hide-full-xs,
:host([responsive-size="xs"]) .hide-full-sm,
:host([responsive-size="xs"]) .hide-full-flex,
:host([responsive-size="sm"]) .hide-full-sm,
:host([responsive-size="sm"]) .hide-full-flex,
:host([flex-layout]) .hide-flex {
display: none;
}
:host([responsive-size="xl"]) #cc-custom {
font-size: 16px;
}
:host([responsive-size="lg"]) #cc-custom,
:host([flex-layout][responsive-size="xl"]) #cc-custom {
font-size: 14px;
}
:host([responsive-size="md"]) #cc-custom,
:host([flex-layout][responsive-size="lg"]) #cc-custom {
font-size: 12px;
}
:host([responsive-size="xs"]) #cc-custom,
:host([width]) #cc-custom,
:host([flex-layout][responsive-size="md"]) #cc-custom,
:host([flex-layout][responsive-size="sm"]) #cc-custom {
font-size: 10px;
}
:host([sticky-mode]) #cc-custom,
:host([flex-layout][width]) #cc-custom,
:host([flex-layout][responsive-size="xs"]) #cc-custom {
display: none;
}
.media-caption {
color: var(--a11y-media-caption-color, var(--a11y-media-bg-color));
background-color: var(--a11y-media-accent-color);
}
#audio-only {
text-align: center;
font-style: italic;
width: 100%;
line-height: 160%;
}
#print-thumbnail,
.print-only {
width: 0;
display: none;
}
}
@media print {
:host,
:host([dark]) {
outline: 1px solid #aaaaaa;
background-color: #ffffff;
}
.screen-only,
#searchbar,
#print-thumbnail:not([src]),
:host(:not([thumbnail-src])) #player {
display: none;
}
.media-caption {
background-color: #cccccc;
color: #000000;
font-size: 120%;
}
#transcript {
padding: 0 15px 5px;
color: #000;
background-color: #ffffff;
border-top: 1px solid #aaa;
}
}
`,
];
}
// render function
render() {
return html` <div class="sr-only" ?hidden="${!this.mediaCaption}">
${this.mediaCaption}
</div>
<div id="player-section">
<div
id="player-and-controls"
.style="${this.mediaMaxWidth}"
?audio-no-thumb="${this.audioNoThumb}"
>
<div id="player" .style="${this.playerStyle}">
<a11y-media-play-button
id="playbutton"
action="${this.__playing ? "pause" : "play"}"
label="${this._getLocal(
this.localization,
this.__playing ? "pause" : "play",
"label",
)}"
@button-click="${this.togglePlay}"
?audio-only="${this.audioOnly}"
?disabled="${this.audioNoThumb}"
youtube-id="${this.youtubeId}"
>
</a11y-media-play-button>
<div id="html5">
<slot></slot>
</div>
${this.videoId && this.__playerReady
? html`
<a11y-media-youtube
id="youtube-${this.id}"
class="${this.__currentTime > 0.3 || this.__seeking
? ``
: `hidden`}"
lang="${this.mediaLang}"
preload="${this.t ? "auto" : this.preload}"
.t="${this.t}"
video-id="${this.videoId}"
playback-rate="${this.playbackRate}"
@timeupdate="${this._handleTimeUpdate}"
?hidden=${!this.isYoutube}
>
</a11y-media-youtube>
`
: ``}
${Object.keys(this.captionCues || []).length === 0 ||
!this.showCustomCaptions
? html``
: html`
<div id="cc-custom" aria-live="polite" class="screen-only">
<div id="cc-text">
${!this.captionCues
? ``
: Object.keys(this.captionCues).map(
(key) =>
html`${this.captionCues[key].text
? this.captionCues[key].text
: ""}`,
)}
</div>
</div>
`}
</div>
</div>
<div id="progresslabel" class="sr-only">
${this._getLocal(this.localization, "seekSlider", "label")}
</div>
<simple-range-input
id="slider"
class="screen-only"
aria-labelledby="progresslabel"
min="0"
.max="${this.duration}"
step="1"
@value-changed="${this._handleSliderChanged}"
@immediate-value-changed="${this._handleSliderDragging}"
.value="${this.__currentTime}"
?disabled="${this.disableSeek}"
>
</simple-range-input>
<div id="controls" controls="innerplayer">
<div id="controls-left">
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
icon="${this._getLocal(
this.localization,
this.__playing ? "pause" : "play",
"icon",
)}"
label="${this._getLocal(
this.localization,
this.__playing ? "pause" : "play",
"label",
)}"
@click="${this.togglePlay}"
></a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
class="hide-flex hide-full-xs"
icon="${this._getLocal(this.localization, "rewind", "icon")}"
label="${this._getLocal(this.localization, "rewind", "label")}"
?disabled="${this.disableSeek || this.currentTime <= 0}"
?hidden="${this.disableSeek}"
@click="${(e) => {
this.rewind();
}}"
></a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
class="hide-flex hide-full-xs"
icon="${this._getLocal(this.localization, "forward", "icon")}"
label="${this._getLocal(this.localization, "forward", "label")}"
?disabled="${this.disableSeek ||
this.currentTime >= this.duration}"
?hidden="${this.disableSeek}"
@click="${(e) => {
this.forward();
}}"
></a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
class="hide-flex"
icon="${this._getLocal(this.localization, "restart", "icon")}"
label="${this._getLocal(this.localization, "restart", "label")}"
?disabled="${this.disableSeek}"
?hidden="${this.responsiveSize === "xs" ||
this.responsiveSize === "sm" ||
this.disableSeek}"
@click="${this.restart}"
></a11y-media-button>
<div
id="volume-and-mute"
@focus="${(e) => (this.__volumeSlider = true)}"
@blur="${(e) => (this.__volumeSlider = false)}"
>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
id="mute"
icon="${this._getLocal(
this.localization,
this.muted ? "unmute" : "mute",
"icon",
)}"
label="${this._getLocal(
this.localization,
this.muted ? "unmute" : "mute",
"label",
)}"
@click="${(e) => {
this.toggleMute();
}}"
></a11y-media-button>
<simple-range-input
id="volume"
accent-color="${this.accentColor}"
?dark="${this.dark}"
aria-labelledby="volume-slider-label"
label="${this._getLocal(this.localization, "volume", "label")}"
min="0"
max="100"
pin
step="10"
value="${this.muted ? 0 : this.volume}"
@value-changed="${this._handleVolumeChanged}"
?hidden="${this.responsiveSize === "xs"}"
></simple-range-input>
</div>
<span
aria-live="polite"
class="play-status control-bar hide-full-xs"
>
<span id="statbar">${this.status}</span>
</span>
</div>
<div id="controls-right">
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
icon="${this._getLocal(this.localization, "captions", "icon")}"
label="${this._getLocal(this.localization, "captions", "label")}"
?disabled="${!this.hasCaptions}"
?hidden="${!this.hasCaptions}"
?toggle="${this.captionsTrackKey > -1}"
@click="${(e) => this.toggleCC()}"
>
</a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
class="hide-full-xs"
controls="transcript"
icon="${this._getLocal(this.localization, "transcript", "icon")}"
label="${this._getLocal(
this.localization,
"transcript",
"label",
)}"
?disabled="${!this.hasCaptions || this.learningMode}"
?hidden="${!this.hasCaptions ||
this.standAlone ||
(this.height && this.responsiveSize.indexOf("s") > -1) ||
this.learningMode}"
?toggle="${this.transcriptTrackKey > -1}"
@click="${(e) => this.toggleTranscript()}"
>
</a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
class="hide-full-sm"
icon="${this._getLocal(this.localization, "copyLink", "icon")}"
label="${this._getLocal(this.localization, "copyLink", "label")}"
?disabled="${!this.linkable || this.learningMode}"
?hidden="${!this.linkable || this.learningMode}"
@click="${this._handleCopyLink}"
></a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
icon="${this._getLocal(this.localization, "fullscreen", "icon")}"
label="${this._getLocal(
this.localization,
"fullscreen",
"label",
)}"
?hidden="${this.audioNoThumb || !this.fullscreenButton}"
?toggle="${this.fullscreen}"
@click="${(e) => this.toggleFullscreen()}"
>
</a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
id="settings-button"
class="hide-sticky"
controls="settings"
icon="${this._getLocal(this.localization, "settings", "icon")}"
label="${this._getLocal(this.localization, "settings", "label")}"
@click="${(e) => this.toggleSettings()}"
></a11y-media-button>
${this.isYoutube
? html` <a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
class="hide-sticky"
icon="mdi-social:youtube"
label="Open on YouTube"
?hidden="${this.learningMode || this.hideYoutubeLink}"
@click="${this.goToYoutube}"
></a11y-media-button>`
: ``}
</div>
<absolute-position-behavior
id="settings"
auto
fit-to-visible-bounds
for="settings-button"
offset="10"
position-align="end"
position="top"
?hidden="${!this.__settingsOpen}"
>
<div class="setting" ?hidden="${!this.hasCaptions}">
<div class="setting-text">
${this._getLocal(this.localization, "captions", "label")}
</div>
<simple-fields-field
id="cc_tracks"
class="setting-control"
value="${this.captionsTrackKey}"
.options="${this.captionsPicker}"
?hidden="${!this.hasCaptions}"
?disabled="${!this.hasCaptions}"
@value-changed="${this.selectCaptionByKeyEvent}"
type="select"
>
</simple-fields-field>
</div>
<div
class="setting"
?hidden="${!this.hasCaptions || this.learningMode}"
>
<div class="setting-text">
${this._getLocal(this.localization, "transcript", "label")}
</div>
<simple-fields-field
id="transcript_tracks"
class="setting-control"
.value="${this.transcriptTrackKey}"
.options="${this.transcriptPicker}"
?hidden="${!this.hasCaptions || this.learningMode}"
?disabled="${!this.hasCaptions || this.learningMode}"
@value-changed="${this.selectTranscriptByKeyEvent}"
type="select"
>
</simple-fields-field>
</div>
<div
class="setting"
?hidden="${!this.hasCaptions || this.learningMode}"
>
<div id="print-label" class="setting-text">
${this._getLocal(this.localization, "print", "label")}
</div>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
aria-labelledby="print-label"
class="setting-control"
icon="${this._getLocal(this.localization, "print", "icon")}"
?disabled="${this.noPrinting || this.learningMode}"
?hidden="${this.noPrinting || this.learningMode}"
@click="${this.print}"
>
</a11y-media-button>
</div>
<div
class="setting"
?hidden="${!this.hasCaptions || this.learningMode}"
>
<div id="download-label" class="setting-text">
${this._getLocal(this.localization, "download", "label")}
</div>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
aria-labelledby="download-label"
class="setting-control"
icon="${this._getLocal(this.localization, "download", "icon")}"
?disabled="${this.noPrinting || this.learningMode}"
?hidden="${this.noPrinting || this.learningMode}"
@click="${this.download}"
>
</a11y-media-button>
</div>
<div class="setting">
<div id="loop-label" class="setting-text">
${this._getLocal(this.localization, "loop", "label")}
</div>
<simple-fields-field
type="checkbox"
id="loop"
class="setting-control"
aria-labelledby="loop-label"
@value-change="${this.toggleLoop}"
?value="${this.loop}"
>
</simple-fields-field>
</div>
<div class="setting">
<div id="speed-label" class="setting-text">
${this._getLocal(this.localization, "speed", "label")}
</div>
<simple-range-input
id="speed"
aria-labelledby="speed-label"
class="setting-slider setting-control"
min="0.5"
max="2.5"
pin
step="0.25"
value="${this.playbackRate}"
@value-changed="${this._handleSpeedChanged}"
>
</simple-range-input>
</div>
</absolute-position-behavior>
</div>
<div
aria-hidden="true"
class="screen-only media-caption"
?hidden="${!this.mediaCaption}"
>
${this.mediaCaption}
</div>
<div class="print-only media-caption">${this.printCaption}</div>
</div>
${this.poster
? html`<img
id="print-thumbnail"
aria-hidden="true"
.src="${this.poster}"
/>`
: ``}
<div
id="transcript-section"
?hidden="${this.standAlone || !this.hasCaptions}"
>
<div id="transcript-and-controls" ?hidden="${this.hideTranscript}">
<div id="searchbar">
<div id="searching">
<simple-search
id="simplesearch"
controls="transcript"
next-button-icon="${this._getLocal(
this.localization,
"nextResult",
"icon",
)}"
next-button-label="${this._getLocal(
this.localization,
"nextResult",
"label",
)}"
prev-button-icon="${this._getLocal(
this.localization,
"prevResult",
"icon",
)}"
prev-button-label="${this._getLocal(
this.localization,
"prevResult",
"label",
)}"
search-input-icon="${this._getLocal(
this.localization,
"search",
"icon",
)}"
search-input-label="${this._getLocal(
this.localization,
"search",
"label",
)}"
selector=".searchable"
?disabled="${this.disableSearch}"
?hidden="${this.disableSearch}"
>
</simple-search>
</div>
<div id="scrolling">
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
id="scroll"
controls="transcript"
icon="${this._getLocal(
this.localization,
"autoScroll",
"icon",
)}"
label="${this._getLocal(
this.localization,
"autoScroll",
"label",
)}"
?toggle="${!this.disableScroll}"
@click="${(e) => (this.disableScroll = !this.disableScroll)}"
>
</a11y-media-button>
</div>
<div
id="printing"
?hidden="${this.disablePrintButton}"
?disabled="${this.disablePrintButton}"
>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
id="download"
controls="transcript"
icon="${this._getLocal(this.localization, "download", "icon")}"
label="${this._getLocal(
this.localization,
"download",
"label",
)}"
@click="${this.download}"
>
</a11y-media-button>
<a11y-media-button
accent-color="${this.accentColor}"
?dark="${this.dark}"
id="print"
controls="transcript"
icon="${this._getLocal(this.localization, "print", "icon")}"
label="${this._getLocal(this.localization, "print", "label")}"
@click="${this.print}"
>
</a11y-media-button>
</div>
</div>
<div id="transcript" aria-live="polite">
<a id="transcript-desc" class="sr-only" href="#bottom">
${this._getLocal(this.localization, "transcript", "skip")}
</a>
${this.transcriptCues.length > 0
? html`
<div class="transcript-from-track">
${this.transcriptCues.map((cue, index) => {
return html`
<a11y-media-transcript-cue
controls="html5"
end="