diff --git a/.github/workflows/build_restreamer-ui_dev.yaml b/.github/workflows/build_restreamer-ui_dev.yaml index ae571a9..d900de7 100644 --- a/.github/workflows/build_restreamer-ui_dev.yaml +++ b/.github/workflows/build_restreamer-ui_dev.yaml @@ -3,6 +3,8 @@ name: 'Build dev restreamer-ui' on: workflow_dispatch: workflow_call: + schedule: + - cron: '37 4 * * *' push: branches: - dev @@ -13,6 +15,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + ref: dev - name: Set up Node.js uses: actions/setup-node@v4 diff --git a/.linguirc b/.linguirc index b4dc710..33d1b7d 100644 --- a/.linguirc +++ b/.linguirc @@ -22,7 +22,7 @@ "it", "ko", "pl", - "pt", + "pt-br", "ru", "sl", "tr", diff --git a/CHANGELOG.md b/CHANGELOG.md index e178447..9063096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Restreamer-UI +## v1.13.0 > v1.14.0 + +- Add wettercom service +- Add option to select which channels will be displayed on the playersite ([#392](https://github.com/datarhei/restreamer/issues/392), [#800](https://github.com/datarhei/restreamer/issues/800)) +- Mod updates public videojs >v8 +- Fix erroneous filter setting +- Fix encoded address +- Fix double -filter parameter when encoder sets filter +- Fix Docker build ([#64](https://github.com/datarhei/restreamer-ui/issues/64)) + +## v1.12.0 > v1.13.0 + +- Add to allow stream hints in case probing fails +- Mod enables ff-loglevel and prepares the logging component +- Mod uses official Instagram-RTMP target +- Mod Remove unused imports +- Mod Update translations +- Mod updates dep. +- Fix player position +- Fix missing stream URL, summarize streams in probe log, don't lock type for first stream + +## v1.11.0 > v1.12.0 + +- Add option to select different SRT stream in wizard +- Add option to select different RTMP stream in wizard +- Fix selecting other than first audio stream ([#710](https://github.com/datarhei/restreamer/issues/710)) +- Fix reset of previous audio settings when editing profile ([#730](https://github.com/datarhei/restreamer/issues/730)) +- Fix RTMP URL for receive mode + +## v1.10.0 > v1.11.0 + +- Add allow to stream HEVC and AV1 to Youtube via RTMP +- Add librav1e AV1 encoder +- Add support for AV1 CUDA decoding ([PR 46](https://github.com/datarhei/restreamer-ui/pull/46)) +- Add FFmpeg 6 support +- Add HEVC VideoToolbox encoder +- Fix anonymize error message ([#688](https://github.com/datarhei/restreamer/issues/688)) +- Fix chromecast config ([#37](https://github.com/datarhei/restreamer-ui/issues/37)) + ## v1.9.0 > v1.10.0 - Add resource usage and ffmpeg command to process details diff --git a/Dockerfile b/Dockerfile index c47ca90..aca1de7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,17 @@ -ARG NODE_IMAGE=node:21-alpine3.17 -ARG CADDY_IMAGE=caddy:2.7.5-alpine +ARG NODE_IMAGE=node:21-alpine3.20 +ARG CADDY_IMAGE=caddy:2.8.4-alpine -FROM $NODE_IMAGE as builder +FROM $NODE_IMAGE AS builder -ARG NODE_SPACE_SIZE=10240 -ENV NODE_OPTIONS="--openssl-legacy-provider --max-old-space-size=$NODE_SPACE_SIZE" - -ENV PUBLIC_URL "./" +ENV PUBLIC_URL="./" COPY . /ui WORKDIR /ui RUN cd /ui && \ - yarn set version berry && \ - yarn config set httpTimeout 600000 && \ - yarn install && \ - yarn run build + yarn install && \ + yarn build FROM $CADDY_IMAGE diff --git a/package.json b/package.json index cb4cea9..7bc9289 100644 --- a/package.json +++ b/package.json @@ -1,52 +1,52 @@ { "name": "restreamer-ui", - "version": "1.10.0", - "bundle": "restreamer-v2.8.0", + "version": "1.14.0", + "bundle": "restreamer-v2.12.0", "private": false, "license": "Apache-2.0", "dependencies": { "@auth0/auth0-spa-js": "^2.1.3", - "@babel/plugin-syntax-flow": "^7.23.3", - "@babel/plugin-transform-react-jsx": "^7.23.4", - "@emotion/react": "^11.11.3", - "@emotion/styled": "^11.11.0", - "@fontsource/dosis": "^5.0.18", - "@fontsource/roboto": "^5.0.8", - "@fortawesome/fontawesome-svg-core": "^6.5.1", - "@fortawesome/free-brands-svg-icons": "^6.5.1", - "@fortawesome/free-solid-svg-icons": "^6.5.1", - "@fortawesome/react-fontawesome": "^0.2.0", - "@lingui/core": "^4.7.0", - "@lingui/macro": "^4.7.0", - "@lingui/react": "^4.7.0", - "@mui/icons-material": "^5.15.6", - "@mui/lab": "^5.0.0-alpha.162", - "@mui/material": "^5.15.6", - "@mui/styles": "^5.15.6", - "@testing-library/dom": "^9.3.4", - "@testing-library/jest-dom": "^6.3.0", - "@testing-library/react": "^14.1.2", + "@babel/plugin-syntax-flow": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@fontsource/dosis": "^5.0.21", + "@fontsource/roboto": "^5.0.14", + "@fortawesome/fontawesome-svg-core": "^6.6.0", + "@fortawesome/free-brands-svg-icons": "^6.6.0", + "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/react-fontawesome": "^0.2.2", + "@lingui/core": "^4.11.4", + "@lingui/macro": "^4.11.4", + "@lingui/react": "^4.11.4", + "@mui/icons-material": "^6.0.1", + "@mui/lab": "^6.0.0-beta.8", + "@mui/material": "^6.0.1", + "@mui/styles": "^6.0.1", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", - "@types/react": "^18.2.48", + "@types/react": "^18.3.5", "babel-plugin-macros": "^3.1.0", - "eslint": "^8.56.0", + "eslint": "^9.9.1", "handlebars": "^4.7.8", "jwt-decode": "^4.0.0", - "make-plural": "^7.3.0", - "react": "^18.2.0", + "make-plural": "^7.4.0", + "react": "^18.3.1", "react-colorful": "^5.6.1", "react-device-detect": "^2.2.3", - "react-dom": "^18.2.0", + "react-dom": "^18.3.1", "react-markdown": "^9.0.1", - "react-router-dom": "^6.21.3", + "react-router-dom": "^6.26.1", "react-scripts": "^5.0.1", - "semver": "^7.5.4", - "serve": "^14.2.1", - "typescript": "^5.3.3", + "semver": "^7.6.3", + "serve": "^14.2.3", + "typescript": "^5.5.4", "url-parse": "^1.5.10", "util": "^0.12.5", - "uuid": "^9.0.1", - "video.js": "^8.10.0", + "uuid": "^10.0.0", + "video.js": "^8.17.3", "videojs-overlay": "^3.1.0" }, "scripts": { @@ -86,12 +86,12 @@ ] }, "devDependencies": { - "@babel/core": "^7.23.9", + "@babel/core": "^7.25.2", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@lingui/cli": "^4.7.0", + "@lingui/cli": "^4.11.4", "babel-core": "^6.26.3", "eslint-config-react-app": "^7.0.1", - "prettier": "^3.2.4", + "prettier": "^3.3.3", "react-error-overlay": "^6.0.11" }, "resolutions": {} diff --git a/public/_player/videojs/dist/video-js.css b/public/_player/videojs/dist/video-js.css index 0bc8016..a2996e0 100644 --- a/public/_player/videojs/dist/video-js.css +++ b/public/_player/videojs/dist/video-js.css @@ -1,4 +1,20 @@ -@charset "UTF-8"; +.vjs-svg-icon { + display: inline-block; + background-repeat: no-repeat; + background-position: center; + fill: currentColor; + height: 1.8em; + width: 1.8em; +} +.vjs-svg-icon:before { + content: none !important; +} + +.vjs-svg-icon:hover, +.vjs-control:focus .vjs-svg-icon { + filter: drop-shadow(0 0 0.25em #fff); +} + .vjs-modal-dialog .vjs-modal-dialog-content, .video-js .vjs-modal-dialog, .vjs-button > .vjs-icon-placeholder:before, .video-js .vjs-big-play-button .vjs-icon-placeholder:before { position: absolute; top: 0; @@ -13,7 +29,7 @@ @font-face { font-family: VideoJS; - src: url(data:application/font-woff;charset=utf-8;base64,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) format("woff"); + src: url(data:application/font-woff;charset=utf-8;base64,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) format("woff"); font-weight: normal; font-style: normal; } @@ -98,22 +114,13 @@ content: "\f109"; } -.vjs-icon-square { - font-family: VideoJS; - font-weight: normal; - font-style: normal; -} -.vjs-icon-square:before { - content: "\f10a"; -} - .vjs-icon-spinner { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-spinner:before { - content: "\f10b"; + content: "\f10a"; } .vjs-icon-subtitles, .video-js .vjs-subs-caps-button .vjs-icon-placeholder, @@ -130,7 +137,7 @@ .video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder:before, .video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder:before, .video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder:before, .video-js .vjs-subtitles-button .vjs-icon-placeholder:before { - content: "\f10c"; + content: "\f10b"; } .vjs-icon-captions, .video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder, @@ -141,6 +148,15 @@ } .vjs-icon-captions:before, .video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder:before, .video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder:before, .video-js .vjs-captions-button .vjs-icon-placeholder:before { + content: "\f10c"; +} + +.vjs-icon-hd { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-hd:before { content: "\f10d"; } @@ -153,13 +169,49 @@ content: "\f10e"; } +.vjs-icon-downloading { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-downloading:before { + content: "\f10f"; +} + +.vjs-icon-file-download { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-file-download:before { + content: "\f110"; +} + +.vjs-icon-file-download-done { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-file-download-done:before { + content: "\f111"; +} + +.vjs-icon-file-download-off { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-file-download-off:before { + content: "\f112"; +} + .vjs-icon-share { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-share:before { - content: "\f10f"; + content: "\f113"; } .vjs-icon-cog { @@ -168,7 +220,16 @@ font-style: normal; } .vjs-icon-cog:before { - content: "\f110"; + content: "\f114"; +} + +.vjs-icon-square { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-square:before { + content: "\f115"; } .vjs-icon-circle, .vjs-seek-to-live-control .vjs-icon-placeholder, .video-js .vjs-volume-level, .video-js .vjs-play-progress { @@ -177,7 +238,7 @@ font-style: normal; } .vjs-icon-circle:before, .vjs-seek-to-live-control .vjs-icon-placeholder:before, .video-js .vjs-volume-level:before, .video-js .vjs-play-progress:before { - content: "\f111"; + content: "\f116"; } .vjs-icon-circle-outline { @@ -186,7 +247,7 @@ font-style: normal; } .vjs-icon-circle-outline:before { - content: "\f112"; + content: "\f117"; } .vjs-icon-circle-inner-circle { @@ -195,16 +256,7 @@ font-style: normal; } .vjs-icon-circle-inner-circle:before { - content: "\f113"; -} - -.vjs-icon-hd { - font-family: VideoJS; - font-weight: normal; - font-style: normal; -} -.vjs-icon-hd:before { - content: "\f114"; + content: "\f118"; } .vjs-icon-cancel, .video-js .vjs-control.vjs-close-button .vjs-icon-placeholder { @@ -213,7 +265,16 @@ font-style: normal; } .vjs-icon-cancel:before, .video-js .vjs-control.vjs-close-button .vjs-icon-placeholder:before { - content: "\f115"; + content: "\f119"; +} + +.vjs-icon-repeat { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-repeat:before { + content: "\f11a"; } .vjs-icon-replay, .video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder { @@ -222,79 +283,70 @@ font-style: normal; } .vjs-icon-replay:before, .video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder:before { - content: "\f116"; -} - -.vjs-icon-facebook { - font-family: VideoJS; - font-weight: normal; - font-style: normal; -} -.vjs-icon-facebook:before { - content: "\f117"; -} - -.vjs-icon-gplus { - font-family: VideoJS; - font-weight: normal; - font-style: normal; -} -.vjs-icon-gplus:before { - content: "\f118"; -} - -.vjs-icon-linkedin { - font-family: VideoJS; - font-weight: normal; - font-style: normal; -} -.vjs-icon-linkedin:before { - content: "\f119"; -} - -.vjs-icon-twitter { - font-family: VideoJS; - font-weight: normal; - font-style: normal; -} -.vjs-icon-twitter:before { - content: "\f11a"; -} - -.vjs-icon-tumblr { - font-family: VideoJS; - font-weight: normal; - font-style: normal; -} -.vjs-icon-tumblr:before { content: "\f11b"; } -.vjs-icon-pinterest { +.vjs-icon-replay-5, .video-js .vjs-skip-backward-5 .vjs-icon-placeholder { font-family: VideoJS; font-weight: normal; font-style: normal; } -.vjs-icon-pinterest:before { +.vjs-icon-replay-5:before, .video-js .vjs-skip-backward-5 .vjs-icon-placeholder:before { content: "\f11c"; } -.vjs-icon-audio-description, .video-js .vjs-descriptions-button .vjs-icon-placeholder { +.vjs-icon-replay-10, .video-js .vjs-skip-backward-10 .vjs-icon-placeholder { font-family: VideoJS; font-weight: normal; font-style: normal; } -.vjs-icon-audio-description:before, .video-js .vjs-descriptions-button .vjs-icon-placeholder:before { +.vjs-icon-replay-10:before, .video-js .vjs-skip-backward-10 .vjs-icon-placeholder:before { content: "\f11d"; } +.vjs-icon-replay-30, .video-js .vjs-skip-backward-30 .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-replay-30:before, .video-js .vjs-skip-backward-30 .vjs-icon-placeholder:before { + content: "\f11e"; +} + +.vjs-icon-forward-5, .video-js .vjs-skip-forward-5 .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-forward-5:before, .video-js .vjs-skip-forward-5 .vjs-icon-placeholder:before { + content: "\f11f"; +} + +.vjs-icon-forward-10, .video-js .vjs-skip-forward-10 .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-forward-10:before, .video-js .vjs-skip-forward-10 .vjs-icon-placeholder:before { + content: "\f120"; +} + +.vjs-icon-forward-30, .video-js .vjs-skip-forward-30 .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-forward-30:before, .video-js .vjs-skip-forward-30 .vjs-icon-placeholder:before { + content: "\f121"; +} + .vjs-icon-audio, .video-js .vjs-audio-button .vjs-icon-placeholder { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-audio:before, .video-js .vjs-audio-button .vjs-icon-placeholder:before { - content: "\f11e"; + content: "\f122"; } .vjs-icon-next-item { @@ -303,7 +355,7 @@ font-style: normal; } .vjs-icon-next-item:before { - content: "\f11f"; + content: "\f123"; } .vjs-icon-previous-item { @@ -312,7 +364,25 @@ font-style: normal; } .vjs-icon-previous-item:before { - content: "\f120"; + content: "\f124"; +} + +.vjs-icon-shuffle { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-shuffle:before { + content: "\f125"; +} + +.vjs-icon-cast { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-cast:before { + content: "\f126"; } .vjs-icon-picture-in-picture-enter, .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder { @@ -321,7 +391,7 @@ font-style: normal; } .vjs-icon-picture-in-picture-enter:before, .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before { - content: "\f121"; + content: "\f127"; } .vjs-icon-picture-in-picture-exit, .video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder { @@ -330,11 +400,65 @@ font-style: normal; } .vjs-icon-picture-in-picture-exit:before, .video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder:before { - content: "\f122"; + content: "\f128"; +} + +.vjs-icon-facebook { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-facebook:before { + content: "\f129"; +} + +.vjs-icon-linkedin { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-linkedin:before { + content: "\f12a"; +} + +.vjs-icon-twitter { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-twitter:before { + content: "\f12b"; +} + +.vjs-icon-tumblr { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-tumblr:before { + content: "\f12c"; +} + +.vjs-icon-pinterest { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-pinterest:before { + content: "\f12d"; +} + +.vjs-icon-audio-description, .video-js .vjs-descriptions-button .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} +.vjs-icon-audio-description:before, .video-js .vjs-descriptions-button .vjs-icon-placeholder:before { + content: "\f12e"; } .video-js { - display: block; + display: inline-block; vertical-align: top; box-sizing: border-box; color: #fff; @@ -427,13 +551,15 @@ display: none; } -body.vjs-full-window { +body.vjs-full-window, +body.vjs-pip-window { padding: 0; margin: 0; height: 100%; } -.vjs-full-window .video-js.vjs-fullscreen { +.vjs-full-window .video-js.vjs-fullscreen, +body.vjs-pip-window .video-js { position: fixed; overflow: hidden; z-index: 1000; @@ -443,16 +569,35 @@ body.vjs-full-window { right: 0; } -.video-js.vjs-fullscreen:not(.vjs-ios-native-fs) { +.video-js.vjs-fullscreen:not(.vjs-ios-native-fs), +body.vjs-pip-window .video-js { width: 100% !important; height: 100% !important; padding-top: 0 !important; + display: block; } .video-js.vjs-fullscreen.vjs-user-inactive { cursor: none; } +.vjs-pip-container .vjs-pip-text { + position: absolute; + bottom: 10%; + font-size: 2em; + background-color: rgba(0, 0, 0, 0.7); + padding: 0.5em; + text-align: center; + width: 100%; +} + +.vjs-layout-tiny.vjs-pip-container .vjs-pip-text, +.vjs-layout-x-small.vjs-pip-container .vjs-pip-text, +.vjs-layout-small.vjs-pip-container .vjs-pip-text { + bottom: 0; + font-size: 1.4em; +} + .vjs-hidden { display: none !important; } @@ -500,9 +645,11 @@ body.vjs-full-window { width: 3em; display: block; position: absolute; - top: 10px; - left: 10px; + top: 50%; + left: 50%; padding: 0; + margin-top: -0.81666em; + margin-left: -1.5em; cursor: pointer; opacity: 1; border: 0.06666em solid #fff; @@ -511,11 +658,14 @@ body.vjs-full-window { border-radius: 0.3em; transition: all 0.4s; } -.vjs-big-play-centered .vjs-big-play-button { +.vjs-big-play-button .vjs-svg-icon { + width: 1em; + height: 1em; + position: absolute; top: 50%; left: 50%; - margin-top: -0.81666em; - margin-left: -1.5em; + line-height: 1; + transform: translate(-50%, -50%); } .video-js:hover .vjs-big-play-button, @@ -533,7 +683,7 @@ body.vjs-full-window { display: none; } -.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause .vjs-big-play-button { +.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause:not(.vjs-seeking, .vjs-scrubbing, .vjs-error) .vjs-big-play-button { display: block; } @@ -549,7 +699,12 @@ body.vjs-full-window { transition: none; -webkit-appearance: none; -moz-appearance: none; - appearance: none; + appearance: none; +} + +.video-js.vjs-spatial-navigation-enabled .vjs-button:focus { + outline: 0.0625em solid white; + box-shadow: none; } .vjs-control .vjs-button { @@ -611,6 +766,8 @@ body.vjs-full-window { } .vjs-menu li { + display: flex; + justify-content: center; list-style: none; margin: 0; padding: 0.2em 0; @@ -634,6 +791,12 @@ body.vjs-full-window { background-color: #fff; color: #2B333F; } +.vjs-menu li.vjs-selected .vjs-svg-icon, +.vjs-menu li.vjs-selected:focus .vjs-svg-icon, +.vjs-menu li.vjs-selected:hover .vjs-svg-icon, +.js-focus-visible .vjs-menu li.vjs-selected:hover .vjs-svg-icon { + fill: #000000; +} .video-js .vjs-menu *:not(.vjs-selected):focus:not(:focus-visible), .js-focus-visible .vjs-menu *:not(.vjs-selected):focus:not(.focus-visible) { @@ -662,6 +825,11 @@ body.vjs-full-window { border-top-color: rgba(43, 51, 63, 0.7); } +.vjs-pip-window .vjs-menu-button-popup .vjs-menu { + left: unset; + right: 1em; +} + .vjs-menu-button-popup .vjs-menu .vjs-menu-content { background-color: #2B333F; background-color: rgba(43, 51, 63, 0.7); @@ -706,8 +874,7 @@ body.vjs-full-window { .video-js .vjs-menu-button-inline:hover, .video-js .vjs-menu-button-inline:focus, -.video-js .vjs-menu-button-inline.vjs-slider-active, -.video-js.vjs-no-flex .vjs-menu-button-inline { +.video-js .vjs-menu-button-inline.vjs-slider-active { width: 12em; } @@ -730,19 +897,6 @@ body.vjs-full-window { opacity: 1; } -.vjs-no-flex .vjs-menu-button-inline .vjs-menu { - display: block; - opacity: 1; - position: relative; - width: auto; -} - -.vjs-no-flex .vjs-menu-button-inline:hover .vjs-menu, -.vjs-no-flex .vjs-menu-button-inline:focus .vjs-menu, -.vjs-no-flex .vjs-menu-button-inline.vjs-slider-active .vjs-menu { - width: auto; -} - .vjs-menu-button-inline .vjs-menu-content { width: auto; height: 100%; @@ -762,6 +916,14 @@ body.vjs-full-window { background-color: rgba(43, 51, 63, 0.7); } +.video-js.vjs-spatial-navigation-enabled .vjs-control-bar { + gap: 1px; +} + +.video-js:not(.vjs-controls-disabled, .vjs-using-native-controls, .vjs-error) .vjs-control-bar.vjs-lock-showing { + display: flex !important; +} + .vjs-has-started .vjs-control-bar, .vjs-audio-only-mode .vjs-control-bar { display: flex; @@ -787,10 +949,7 @@ body.vjs-full-window { .vjs-audio-only-mode.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { opacity: 1; visibility: visible; -} - -.vjs-has-started.vjs-no-flex .vjs-control-bar { - display: table; + pointer-events: auto; } .video-js .vjs-control { @@ -818,6 +977,10 @@ body.vjs-full-window { display: block; } +.vjs-button > .vjs-svg-icon { + display: inline-block; +} + .video-js .vjs-control:focus:before, .video-js .vjs-control:hover:before, .video-js .vjs-control:focus { @@ -834,11 +997,6 @@ body.vjs-full-window { width: 1px; } -.vjs-no-flex .vjs-control { - display: table-cell; - vertical-align: middle; -} - .video-js .vjs-custom-control-spacer { display: none; } @@ -865,10 +1023,6 @@ body.vjs-full-window { align-items: center; } -.vjs-no-flex .vjs-progress-control { - width: auto; -} - .video-js .vjs-progress-holder { flex: auto; transition: all 0.2s; @@ -905,7 +1059,22 @@ body.vjs-full-window { font-size: 0.9em; position: absolute; right: -0.5em; - top: -0.3333333333em; + line-height: 0.35em; + z-index: 1; +} + +.vjs-svg-icons-enabled .vjs-play-progress:before { + content: none !important; +} + +.vjs-play-progress .vjs-svg-icon { + position: absolute; + top: -0.35em; + right: -0.4em; + width: 0.9em; + height: 0.9em; + pointer-events: none; + line-height: 0.15em; z-index: 1; } @@ -957,10 +1126,6 @@ body.vjs-full-window { z-index: 1; } -.vjs-no-flex .vjs-progress-control .vjs-mouse-display { - z-index: 0; -} - .video-js .vjs-progress-control:hover .vjs-mouse-display { display: block; } @@ -971,10 +1136,6 @@ body.vjs-full-window { transition: visibility 1s, opacity 1s; } -.video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display { - display: none; -} - .vjs-mouse-display .vjs-time-tooltip { color: #fff; background-color: #000; @@ -988,15 +1149,11 @@ body.vjs-full-window { margin: 0 0.45em 0 0.45em; /* iOS Safari */ -webkit-touch-callout: none; - /* Safari */ + /* Safari, and Chrome 53 */ -webkit-user-select: none; - /* Konqueror HTML */ - /* Firefox */ - -moz-user-select: none; - /* Internet Explorer/Edge */ - -ms-user-select: none; /* Non-prefixed version, currently supported by Chrome and Opera */ - user-select: none; + -moz-user-select: none; + user-select: none; background-color: #73859f; background-color: rgba(115, 133, 159, 0.5); } @@ -1010,6 +1167,10 @@ body.vjs-full-window { box-shadow: 0 0 1em #fff; } +.video-js.vjs-spatial-navigation-enabled .vjs-slider:focus { + outline: 0.0625em solid white; +} + .video-js .vjs-mute-control { cursor: pointer; flex: none; @@ -1069,22 +1230,6 @@ body.vjs-full-window { transition: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s; } -.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal { - width: 5em; - height: 3em; - visibility: visible; - opacity: 1; - position: relative; - transition: none; -} - -.video-js.vjs-no-flex .vjs-volume-control.vjs-volume-vertical, -.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical { - position: absolute; - bottom: 3em; - left: 0.5em; -} - .video-js .vjs-volume-panel { display: flex; } @@ -1125,14 +1270,36 @@ body.vjs-full-window { z-index: 1; } +.vjs-svg-icons-enabled .vjs-volume-level:before { + content: none; +} + +.vjs-volume-level .vjs-svg-icon { + position: absolute; + width: 0.9em; + height: 0.9em; + pointer-events: none; + z-index: 1; +} + .vjs-slider-horizontal .vjs-volume-level { height: 0.3em; } .vjs-slider-horizontal .vjs-volume-level:before { - top: -0.3em; + line-height: 0.35em; right: -0.5em; } +.vjs-slider-horizontal .vjs-volume-level .vjs-svg-icon { + right: -0.3em; + transform: translateY(-50%); +} + +.vjs-slider-vertical .vjs-volume-level .vjs-svg-icon { + top: -0.55em; + transform: translateX(-50%); +} + .video-js .vjs-volume-panel.vjs-volume-panel-vertical { width: 4em; } @@ -1204,10 +1371,6 @@ body.vjs-full-window { height: 100%; } -.vjs-no-flex .vjs-volume-control .vjs-mouse-display { - z-index: 0; -} - .video-js .vjs-volume-control:hover .vjs-mouse-display { display: block; } @@ -1218,10 +1381,6 @@ body.vjs-full-window { transition: visibility 1s, opacity 1s; } -.video-js.vjs-user-inactive.vjs-no-flex .vjs-volume-control .vjs-mouse-display { - display: none; -} - .vjs-mouse-display .vjs-volume-tooltip { color: #fff; background-color: #000; @@ -1231,10 +1390,6 @@ body.vjs-full-window { .vjs-poster { display: inline-block; vertical-align: middle; - background-repeat: no-repeat; - background-position: 50% 50%; - background-size: contain; - background-color: #000000; cursor: pointer; margin: 0; padding: 0; @@ -1252,10 +1407,17 @@ body.vjs-full-window { } .vjs-audio.vjs-has-started .vjs-poster, -.vjs-has-started.vjs-audio-poster-mode .vjs-poster { +.vjs-has-started.vjs-audio-poster-mode .vjs-poster, +.vjs-pip-container.vjs-has-started .vjs-poster { display: block; } +.vjs-poster img { + width: 100%; + height: 100%; + object-fit: contain; +} + .video-js .vjs-live-control { display: flex; align-items: flex-start; @@ -1264,12 +1426,6 @@ body.vjs-full-window { line-height: 3em; } -.vjs-no-flex .vjs-live-control { - display: table-cell; - width: auto; - text-align: left; -} - .video-js:not(.vjs-live) .vjs-live-control, .video-js.vjs-liveui .vjs-live-control { display: none; @@ -1289,12 +1445,6 @@ body.vjs-full-window { min-width: 4em; } -.vjs-no-flex .vjs-seek-to-live-control { - display: table-cell; - width: auto; - text-align: left; -} - .video-js.vjs-live:not(.vjs-liveui) .vjs-seek-to-live-control, .video-js:not(.vjs-live) .vjs-seek-to-live-control { display: none; @@ -1309,10 +1459,25 @@ body.vjs-full-window { color: #888; } +.vjs-svg-icons-enabled .vjs-seek-to-live-control { + line-height: 0; +} + +.vjs-seek-to-live-control .vjs-svg-icon { + width: 1em; + height: 1em; + pointer-events: none; + fill: #888888; +} + .vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-icon-placeholder { color: red; } +.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-svg-icon { + fill: red; +} + .video-js .vjs-time-control { flex: none; font-size: 1em; @@ -1323,17 +1488,10 @@ body.vjs-full-window { padding-right: 1em; } -.vjs-live .vjs-time-control { - display: none; -} - +.vjs-live .vjs-time-control, +.vjs-live .vjs-time-divider, .video-js .vjs-current-time, -.vjs-no-flex .vjs-current-time { - display: none; -} - -.video-js .vjs-duration, -.vjs-no-flex .vjs-duration { +.video-js .vjs-duration { display: none; } @@ -1342,10 +1500,6 @@ body.vjs-full-window { line-height: 3em; } -.vjs-live .vjs-time-divider { - display: none; -} - .video-js .vjs-play-control { cursor: pointer; } @@ -1363,6 +1517,10 @@ body.vjs-full-window { pointer-events: none; } +.vjs-error .vjs-text-track-display { + display: none; +} + .video-js.vjs-controls-disabled .vjs-text-track-display, .video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display { bottom: 1em; @@ -1395,11 +1553,17 @@ video::-webkit-media-text-track-display { transform: translateY(-1.5em); } +.video-js.vjs-force-center-align-cues .vjs-text-track-cue { + text-align: center !important; + width: 80% !important; +} + .video-js .vjs-picture-in-picture-control { cursor: pointer; flex: none; } -.video-js.vjs-audio-only-mode .vjs-picture-in-picture-control { +.video-js.vjs-audio-only-mode .vjs-picture-in-picture-control, +.vjs-pip-window .vjs-picture-in-picture-control { display: none; } @@ -1407,7 +1571,8 @@ video::-webkit-media-text-track-display { cursor: pointer; flex: none; } -.video-js.vjs-audio-only-mode .vjs-fullscreen-control { +.video-js.vjs-audio-only-mode .vjs-fullscreen-control, +.vjs-pip-window .vjs-fullscreen-control { display: none; } @@ -1437,51 +1602,39 @@ video::-webkit-media-text-track-display { text-align: center; } -.vjs-error .vjs-error-display:before { - color: #fff; - content: "X"; - font-family: Arial, Helvetica, sans-serif; - font-size: 4em; - left: 0; - line-height: 1; - margin-top: -0.5em; - position: absolute; - text-shadow: 0.05em 0.05em 0.1em #000; - text-align: center; - top: 50%; - vertical-align: middle; - width: 100%; -} - .vjs-loading-spinner { display: none; position: absolute; top: 50%; left: 50%; - margin: -25px 0 0 -25px; + transform: translate(-50%, -50%); opacity: 0.85; text-align: left; - border: 6px solid rgba(43, 51, 63, 0.7); + border: 0.6em solid rgba(43, 51, 63, 0.7); box-sizing: border-box; background-clip: padding-box; - width: 50px; - height: 50px; - border-radius: 25px; + width: 5em; + height: 5em; + border-radius: 50%; visibility: hidden; } .vjs-seeking .vjs-loading-spinner, .vjs-waiting .vjs-loading-spinner { - display: block; - -webkit-animation: vjs-spinner-show 0s linear 0.3s forwards; - animation: vjs-spinner-show 0s linear 0.3s forwards; + display: flex; + justify-content: center; + align-items: center; + animation: vjs-spinner-show 0s linear 0.3s forwards; +} + +.vjs-error .vjs-loading-spinner { + display: none; } .vjs-loading-spinner:before, .vjs-loading-spinner:after { content: ""; position: absolute; - margin: -6px; box-sizing: inherit; width: inherit; height: inherit; @@ -1496,19 +1649,17 @@ video::-webkit-media-text-track-display { .vjs-seeking .vjs-loading-spinner:after, .vjs-waiting .vjs-loading-spinner:before, .vjs-waiting .vjs-loading-spinner:after { - -webkit-animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; } .vjs-seeking .vjs-loading-spinner:before, .vjs-waiting .vjs-loading-spinner:before { - border-top-color: white; + border-top-color: rgb(255, 255, 255); } .vjs-seeking .vjs-loading-spinner:after, .vjs-waiting .vjs-loading-spinner:after { - border-top-color: white; - -webkit-animation-delay: 0.44s; + border-top-color: rgb(255, 255, 255); animation-delay: 0.44s; } @@ -1517,21 +1668,11 @@ video::-webkit-media-text-track-display { visibility: visible; } } -@-webkit-keyframes vjs-spinner-show { - to { - visibility: visible; - } -} @keyframes vjs-spinner-spin { 100% { transform: rotate(360deg); } } -@-webkit-keyframes vjs-spinner-spin { - 100% { - -webkit-transform: rotate(360deg); - } -} @keyframes vjs-spinner-fade { 0% { border-top-color: #73859f; @@ -1549,23 +1690,6 @@ video::-webkit-media-text-track-display { border-top-color: #73859f; } } -@-webkit-keyframes vjs-spinner-fade { - 0% { - border-top-color: #73859f; - } - 20% { - border-top-color: #73859f; - } - 35% { - border-top-color: white; - } - 60% { - border-top-color: #73859f; - } - 100% { - border-top-color: #73859f; - } -} .video-js.vjs-audio-only-mode .vjs-captions-button { display: none; } @@ -1578,6 +1702,11 @@ video::-webkit-media-text-track-display { display: none; } +.vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-svg-icon { + width: 1.5em; + height: 1.5em; +} + .video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder { vertical-align: middle; display: inline-block; @@ -1586,7 +1715,7 @@ video::-webkit-media-text-track-display { .video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before { font-family: VideoJS; - content: ""; + content: "\f10c"; font-size: 1.5em; line-height: inherit; } @@ -1595,15 +1724,17 @@ video::-webkit-media-text-track-display { display: none; } +.video-js .vjs-audio-button + .vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder, .video-js .vjs-audio-button + .vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder { vertical-align: middle; display: inline-block; margin-bottom: -0.1em; } +.video-js .vjs-audio-button + .vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before, .video-js .vjs-audio-button + .vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before { font-family: VideoJS; - content: " "; + content: " \f12e"; font-size: 1.5em; line-height: inherit; } @@ -1637,9 +1768,6 @@ video::-webkit-media-text-track-display { flex: auto; display: block; } -.video-js.vjs-layout-x-small.vjs-no-flex .vjs-custom-control-spacer { - width: auto; -} .vjs-modal-dialog.vjs-text-track-settings { background-color: #2B333F; @@ -1647,6 +1775,13 @@ video::-webkit-media-text-track-display { color: #fff; height: 70%; } +.vjs-spatial-navigation-enabled .vjs-modal-dialog.vjs-text-track-settings { + height: 80%; +} + +.vjs-error .vjs-text-track-settings { + display: none; +} .vjs-text-track-settings .vjs-modal-dialog-content { display: table; @@ -1670,34 +1805,35 @@ video::-webkit-media-text-track-display { grid-template-rows: 1fr; padding: 20px 24px 0px 24px; } - .vjs-track-settings-controls .vjs-default-button { margin-bottom: 20px; } - .vjs-text-track-settings .vjs-track-settings-controls { grid-column: 1/-1; } - .vjs-layout-small .vjs-text-track-settings .vjs-modal-dialog-content, -.vjs-layout-x-small .vjs-text-track-settings .vjs-modal-dialog-content, -.vjs-layout-tiny .vjs-text-track-settings .vjs-modal-dialog-content { + .vjs-layout-x-small .vjs-text-track-settings .vjs-modal-dialog-content, + .vjs-layout-tiny .vjs-text-track-settings .vjs-modal-dialog-content { grid-template-columns: 1fr; } } +.vjs-text-track-settings select { + font-size: inherit; +} + .vjs-track-setting > select { margin-right: 1em; margin-bottom: 0.5em; } .vjs-text-track-settings fieldset { - margin: 5px; - padding: 3px; + margin: 10px; border: none; } .vjs-text-track-settings fieldset span { display: inline-block; + padding: 0 0.6em 0.8em; } .vjs-text-track-settings fieldset span > select { @@ -1706,20 +1842,12 @@ video::-webkit-media-text-track-display { .vjs-text-track-settings legend { color: #fff; - margin: 0 0 5px 0; + font-weight: bold; + font-size: 1.2em; } .vjs-text-track-settings .vjs-label { - position: absolute; - clip: rect(1px 1px 1px 1px); - clip: rect(1px, 1px, 1px, 1px); - display: block; - margin: 0 0 5px 0; - padding: 0; - border: 0; - height: 1px; - width: 1px; - overflow: hidden; + margin: 0 0.5em 0.5em 0; } .vjs-track-settings-controls button:focus, @@ -1745,6 +1873,108 @@ video::-webkit-media-text-track-display { margin-right: 1em; } +.vjs-title-bar { + background: rgba(0, 0, 0, 0.9); + background: linear-gradient(180deg, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.7) 60%, rgba(0, 0, 0, 0) 100%); + font-size: 1.2em; + line-height: 1.5; + transition: opacity 0.1s; + padding: 0.666em 1.333em 4em; + pointer-events: none; + position: absolute; + top: 0; + width: 100%; +} + +.vjs-error .vjs-title-bar { + display: none; +} + +.vjs-title-bar-title, +.vjs-title-bar-description { + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vjs-title-bar-title { + font-weight: bold; + margin-bottom: 0.333em; +} + +.vjs-playing.vjs-user-inactive .vjs-title-bar { + opacity: 0; + transition: opacity 1s; +} + +.video-js .vjs-skip-forward-5 { + cursor: pointer; +} +.video-js .vjs-skip-forward-10 { + cursor: pointer; +} +.video-js .vjs-skip-forward-30 { + cursor: pointer; +} +.video-js .vjs-skip-backward-5 { + cursor: pointer; +} +.video-js .vjs-skip-backward-10 { + cursor: pointer; +} +.video-js .vjs-skip-backward-30 { + cursor: pointer; +} +.video-js .vjs-transient-button { + position: absolute; + height: 3em; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(50, 50, 50, 0.5); + cursor: pointer; + opacity: 1; + transition: opacity 1s; +} + +.video-js:not(.vjs-has-started) .vjs-transient-button { + display: none; +} + +.video-js.not-hover .vjs-transient-button:not(.force-display), +.video-js.vjs-user-inactive .vjs-transient-button:not(.force-display) { + opacity: 0; +} + +.video-js .vjs-transient-button span { + padding: 0 0.5em; +} + +.video-js .vjs-transient-button.vjs-left { + left: 1em; +} + +.video-js .vjs-transient-button.vjs-right { + right: 1em; +} + +.video-js .vjs-transient-button.vjs-top { + top: 1em; +} + +.video-js .vjs-transient-button.vjs-near-top { + top: 4em; +} + +.video-js .vjs-transient-button.vjs-bottom { + bottom: 4em; +} + +.video-js .vjs-transient-button:hover { + background-color: rgba(50, 50, 50, 0.9); +} + @media print { .video-js > *:not(.vjs-tech):not(.vjs-poster) { visibility: hidden; diff --git a/public/_player/videojs/dist/video-js.min.css b/public/_player/videojs/dist/video-js.min.css index ef93643..e31bdcd 100644 --- a/public/_player/videojs/dist/video-js.min.css +++ b/public/_player/videojs/dist/video-js.min.css @@ -1 +1 @@ -@charset "UTF-8";.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-modal-dialog,.vjs-button>.vjs-icon-placeholder:before,.vjs-modal-dialog .vjs-modal-dialog-content{position:absolute;top:0;left:0;width:100%;height:100%}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.vjs-button>.vjs-icon-placeholder:before{text-align:center}@font-face{font-family:VideoJS;src:url(data:application/font-woff;charset=utf-8;base64,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) format("woff");font-weight:400;font-style:normal}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder,.vjs-icon-play{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder:before,.vjs-icon-play:before{content:"\f101"}.vjs-icon-play-circle{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-play-circle:before{content:"\f102"}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder,.vjs-icon-pause{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder:before,.vjs-icon-pause:before{content:"\f103"}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder,.vjs-icon-volume-mute{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder:before,.vjs-icon-volume-mute:before{content:"\f104"}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder,.vjs-icon-volume-low{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder:before,.vjs-icon-volume-low:before{content:"\f105"}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder,.vjs-icon-volume-mid{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder:before,.vjs-icon-volume-mid:before{content:"\f106"}.video-js .vjs-mute-control .vjs-icon-placeholder,.vjs-icon-volume-high{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control .vjs-icon-placeholder:before,.vjs-icon-volume-high:before{content:"\f107"}.video-js .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-enter{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-enter:before{content:"\f108"}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-exit{font-family:VideoJS;font-weight:400;font-style:normal}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-exit:before{content:"\f109"}.vjs-icon-square{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-square:before{content:"\f10a"}.vjs-icon-spinner{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-spinner:before{content:"\f10b"}.video-js .vjs-subs-caps-button .vjs-icon-placeholder,.video-js .vjs-subtitles-button .vjs-icon-placeholder,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-subtitles{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js .vjs-subtitles-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-subtitles:before{content:"\f10c"}.video-js .vjs-captions-button .vjs-icon-placeholder,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-captions{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-captions-button .vjs-icon-placeholder:before,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-captions:before{content:"\f10d"}.video-js .vjs-chapters-button .vjs-icon-placeholder,.vjs-icon-chapters{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-chapters-button .vjs-icon-placeholder:before,.vjs-icon-chapters:before{content:"\f10e"}.vjs-icon-share{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-share:before{content:"\f10f"}.vjs-icon-cog{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-cog:before{content:"\f110"}.video-js .vjs-play-progress,.video-js .vjs-volume-level,.vjs-icon-circle,.vjs-seek-to-live-control .vjs-icon-placeholder{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-progress:before,.video-js .vjs-volume-level:before,.vjs-icon-circle:before,.vjs-seek-to-live-control .vjs-icon-placeholder:before{content:"\f111"}.vjs-icon-circle-outline{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-circle-outline:before{content:"\f112"}.vjs-icon-circle-inner-circle{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-circle-inner-circle:before{content:"\f113"}.vjs-icon-hd{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-hd:before{content:"\f114"}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder,.vjs-icon-cancel{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder:before,.vjs-icon-cancel:before{content:"\f115"}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder,.vjs-icon-replay{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder:before,.vjs-icon-replay:before{content:"\f116"}.vjs-icon-facebook{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-facebook:before{content:"\f117"}.vjs-icon-gplus{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-gplus:before{content:"\f118"}.vjs-icon-linkedin{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-linkedin:before{content:"\f119"}.vjs-icon-twitter{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-twitter:before{content:"\f11a"}.vjs-icon-tumblr{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-tumblr:before{content:"\f11b"}.vjs-icon-pinterest{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-pinterest:before{content:"\f11c"}.video-js .vjs-descriptions-button .vjs-icon-placeholder,.vjs-icon-audio-description{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-descriptions-button .vjs-icon-placeholder:before,.vjs-icon-audio-description:before{content:"\f11d"}.video-js .vjs-audio-button .vjs-icon-placeholder,.vjs-icon-audio{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-audio-button .vjs-icon-placeholder:before,.vjs-icon-audio:before{content:"\f11e"}.vjs-icon-next-item{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-next-item:before{content:"\f11f"}.vjs-icon-previous-item{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-previous-item:before{content:"\f120"}.video-js .vjs-picture-in-picture-control .vjs-icon-placeholder,.vjs-icon-picture-in-picture-enter{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before,.vjs-icon-picture-in-picture-enter:before{content:"\f121"}.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder,.vjs-icon-picture-in-picture-exit{font-family:VideoJS;font-weight:400;font-style:normal}.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder:before,.vjs-icon-picture-in-picture-exit:before{content:"\f122"}.video-js{display:block;vertical-align:top;box-sizing:border-box;color:#fff;background-color:#000;position:relative;padding:0;font-size:10px;line-height:1;font-weight:400;font-style:normal;font-family:Arial,Helvetica,sans-serif;word-break:initial}.video-js:-moz-full-screen{position:absolute}.video-js:-webkit-full-screen{width:100%!important;height:100%!important}.video-js[tabindex="-1"]{outline:0}.video-js *,.video-js :after,.video-js :before{box-sizing:inherit}.video-js ul{font-family:inherit;font-size:inherit;line-height:inherit;list-style-position:outside;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.video-js.vjs-1-1,.video-js.vjs-16-9,.video-js.vjs-4-3,.video-js.vjs-9-16,.video-js.vjs-fluid{width:100%;max-width:100%}.video-js.vjs-1-1:not(.vjs-audio-only-mode),.video-js.vjs-16-9:not(.vjs-audio-only-mode),.video-js.vjs-4-3:not(.vjs-audio-only-mode),.video-js.vjs-9-16:not(.vjs-audio-only-mode),.video-js.vjs-fluid:not(.vjs-audio-only-mode){height:0}.video-js.vjs-16-9:not(.vjs-audio-only-mode){padding-top:56.25%}.video-js.vjs-4-3:not(.vjs-audio-only-mode){padding-top:75%}.video-js.vjs-9-16:not(.vjs-audio-only-mode){padding-top:177.7777777778%}.video-js.vjs-1-1:not(.vjs-audio-only-mode){padding-top:100%}.video-js.vjs-fill:not(.vjs-audio-only-mode){width:100%;height:100%}.video-js .vjs-tech{position:absolute;top:0;left:0;width:100%;height:100%}.video-js.vjs-audio-only-mode .vjs-tech{display:none}body.vjs-full-window{padding:0;margin:0;height:100%}.vjs-full-window .video-js.vjs-fullscreen{position:fixed;overflow:hidden;z-index:1000;left:0;top:0;bottom:0;right:0}.video-js.vjs-fullscreen:not(.vjs-ios-native-fs){width:100%!important;height:100%!important;padding-top:0!important}.video-js.vjs-fullscreen.vjs-user-inactive{cursor:none}.vjs-hidden{display:none!important}.vjs-disabled{opacity:.5;cursor:default}.video-js .vjs-offscreen{height:1px;left:-9999px;position:absolute;top:0;width:1px}.vjs-lock-showing{display:block!important;opacity:1!important;visibility:visible!important}.vjs-no-js{padding:20px;color:#fff;background-color:#000;font-size:18px;font-family:Arial,Helvetica,sans-serif;text-align:center;width:300px;height:150px;margin:0 auto}.vjs-no-js a,.vjs-no-js a:visited{color:#66a8cc}.video-js .vjs-big-play-button{font-size:3em;line-height:1.5em;height:1.63332em;width:3em;display:block;position:absolute;top:10px;left:10px;padding:0;cursor:pointer;opacity:1;border:.06666em solid #fff;background-color:#2b333f;background-color:rgba(43,51,63,.7);border-radius:.3em;transition:all .4s}.vjs-big-play-centered .vjs-big-play-button{top:50%;left:50%;margin-top:-.81666em;margin-left:-1.5em}.video-js .vjs-big-play-button:focus,.video-js:hover .vjs-big-play-button{border-color:#fff;background-color:#73859f;background-color:rgba(115,133,159,.5);transition:all 0s}.vjs-controls-disabled .vjs-big-play-button,.vjs-error .vjs-big-play-button,.vjs-has-started .vjs-big-play-button,.vjs-using-native-controls .vjs-big-play-button{display:none}.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause .vjs-big-play-button{display:block}.video-js button{background:0 0;border:none;color:inherit;display:inline-block;font-size:inherit;line-height:inherit;text-transform:none;text-decoration:none;transition:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.vjs-control .vjs-button{width:100%;height:100%}.video-js .vjs-control.vjs-close-button{cursor:pointer;height:3em;position:absolute;right:0;top:.5em;z-index:2}.video-js .vjs-modal-dialog{background:rgba(0,0,0,.8);background:linear-gradient(180deg,rgba(0,0,0,.8),rgba(255,255,255,0));overflow:auto}.video-js .vjs-modal-dialog>*{box-sizing:border-box}.vjs-modal-dialog .vjs-modal-dialog-content{font-size:1.2em;line-height:1.5;padding:20px 24px;z-index:1}.vjs-menu-button{cursor:pointer}.vjs-menu-button.vjs-disabled{cursor:default}.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu{display:none}.vjs-menu .vjs-menu-content{display:block;padding:0;margin:0;font-family:Arial,Helvetica,sans-serif;overflow:auto}.vjs-menu .vjs-menu-content>*{box-sizing:border-box}.vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu{display:none}.vjs-menu li{list-style:none;margin:0;padding:.2em 0;line-height:1.4em;font-size:1.2em;text-align:center;text-transform:lowercase}.js-focus-visible .vjs-menu li.vjs-menu-item:hover,.vjs-menu li.vjs-menu-item:focus,.vjs-menu li.vjs-menu-item:hover{background-color:#73859f;background-color:rgba(115,133,159,.5)}.js-focus-visible .vjs-menu li.vjs-selected:hover,.vjs-menu li.vjs-selected,.vjs-menu li.vjs-selected:focus,.vjs-menu li.vjs-selected:hover{background-color:#fff;color:#2b333f}.js-focus-visible .vjs-menu :not(.vjs-selected):focus:not(.focus-visible),.video-js .vjs-menu :not(.vjs-selected):focus:not(:focus-visible){background:0 0}.vjs-menu li.vjs-menu-title{text-align:center;text-transform:uppercase;font-size:1em;line-height:2em;padding:0;margin:0 0 .3em 0;font-weight:700;cursor:default}.vjs-menu-button-popup .vjs-menu{display:none;position:absolute;bottom:0;width:10em;left:-3em;height:0;margin-bottom:1.5em;border-top-color:rgba(43,51,63,.7)}.vjs-menu-button-popup .vjs-menu .vjs-menu-content{background-color:#2b333f;background-color:rgba(43,51,63,.7);position:absolute;width:100%;bottom:1.5em;max-height:15em}.vjs-layout-tiny .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-x-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:5em}.vjs-layout-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:10em}.vjs-layout-medium .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:14em}.vjs-layout-huge .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-x-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:25em}.vjs-menu-button-popup .vjs-menu.vjs-lock-showing,.vjs-workinghover .vjs-menu-button-popup.vjs-hover .vjs-menu{display:block}.video-js .vjs-menu-button-inline{transition:all .4s;overflow:hidden}.video-js .vjs-menu-button-inline:before{width:2.222222222em}.video-js .vjs-menu-button-inline.vjs-slider-active,.video-js .vjs-menu-button-inline:focus,.video-js .vjs-menu-button-inline:hover,.video-js.vjs-no-flex .vjs-menu-button-inline{width:12em}.vjs-menu-button-inline .vjs-menu{opacity:0;height:100%;width:auto;position:absolute;left:4em;top:0;padding:0;margin:0;transition:all .4s}.vjs-menu-button-inline.vjs-slider-active .vjs-menu,.vjs-menu-button-inline:focus .vjs-menu,.vjs-menu-button-inline:hover .vjs-menu{display:block;opacity:1}.vjs-no-flex .vjs-menu-button-inline .vjs-menu{display:block;opacity:1;position:relative;width:auto}.vjs-no-flex .vjs-menu-button-inline.vjs-slider-active .vjs-menu,.vjs-no-flex .vjs-menu-button-inline:focus .vjs-menu,.vjs-no-flex .vjs-menu-button-inline:hover .vjs-menu{width:auto}.vjs-menu-button-inline .vjs-menu-content{width:auto;height:100%;margin:0;overflow:hidden}.video-js .vjs-control-bar{display:none;width:100%;position:absolute;bottom:0;left:0;right:0;height:3em;background-color:#2b333f;background-color:rgba(43,51,63,.7)}.vjs-audio-only-mode .vjs-control-bar,.vjs-has-started .vjs-control-bar{display:flex;visibility:visible;opacity:1;transition:visibility .1s,opacity .1s}.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{visibility:visible;opacity:0;pointer-events:none;transition:visibility 1s,opacity 1s}.vjs-controls-disabled .vjs-control-bar,.vjs-error .vjs-control-bar,.vjs-using-native-controls .vjs-control-bar{display:none!important}.vjs-audio-only-mode.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar,.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{opacity:1;visibility:visible}.vjs-has-started.vjs-no-flex .vjs-control-bar{display:table}.video-js .vjs-control{position:relative;text-align:center;margin:0;padding:0;height:100%;width:4em;flex:none}.video-js .vjs-control.vjs-visible-text{width:auto;padding-left:1em;padding-right:1em}.vjs-button>.vjs-icon-placeholder:before{font-size:1.8em;line-height:1.67}.vjs-button>.vjs-icon-placeholder{display:block}.video-js .vjs-control:focus,.video-js .vjs-control:focus:before,.video-js .vjs-control:hover:before{text-shadow:0 0 1em #fff}.video-js :not(.vjs-visible-text)>.vjs-control-text{border:0;clip:rect(0 0 0 0);height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.vjs-no-flex .vjs-control{display:table-cell;vertical-align:middle}.video-js .vjs-custom-control-spacer{display:none}.video-js .vjs-progress-control{cursor:pointer;flex:auto;display:flex;align-items:center;min-width:4em;touch-action:none}.video-js .vjs-progress-control.disabled{cursor:default}.vjs-live .vjs-progress-control{display:none}.vjs-liveui .vjs-progress-control{display:flex;align-items:center}.vjs-no-flex .vjs-progress-control{width:auto}.video-js .vjs-progress-holder{flex:auto;transition:all .2s;height:.3em}.video-js .vjs-progress-control .vjs-progress-holder{margin:0 10px}.video-js .vjs-progress-control:hover .vjs-progress-holder{font-size:1.6666666667em}.video-js .vjs-progress-control:hover .vjs-progress-holder.disabled{font-size:1em}.video-js .vjs-progress-holder .vjs-load-progress,.video-js .vjs-progress-holder .vjs-load-progress div,.video-js .vjs-progress-holder .vjs-play-progress{position:absolute;display:block;height:100%;margin:0;padding:0;width:0}.video-js .vjs-play-progress{background-color:#fff}.video-js .vjs-play-progress:before{font-size:.9em;position:absolute;right:-.5em;top:-.3333333333em;z-index:1}.video-js .vjs-load-progress{background:rgba(115,133,159,.5)}.video-js .vjs-load-progress div{background:rgba(115,133,159,.75)}.video-js .vjs-time-tooltip{background-color:#fff;background-color:rgba(255,255,255,.8);border-radius:.3em;color:#000;float:right;font-family:Arial,Helvetica,sans-serif;font-size:1em;padding:6px 8px 8px 8px;pointer-events:none;position:absolute;top:-3.4em;visibility:hidden;z-index:1}.video-js .vjs-progress-holder:focus .vjs-time-tooltip{display:none}.video-js .vjs-progress-control:hover .vjs-progress-holder:focus .vjs-time-tooltip,.video-js .vjs-progress-control:hover .vjs-time-tooltip{display:block;font-size:.6em;visibility:visible}.video-js .vjs-progress-control.disabled:hover .vjs-time-tooltip{font-size:1em}.video-js .vjs-progress-control .vjs-mouse-display{display:none;position:absolute;width:1px;height:100%;background-color:#000;z-index:1}.vjs-no-flex .vjs-progress-control .vjs-mouse-display{z-index:0}.video-js .vjs-progress-control:hover .vjs-mouse-display{display:block}.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display{visibility:hidden;opacity:0;transition:visibility 1s,opacity 1s}.video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display{display:none}.vjs-mouse-display .vjs-time-tooltip{color:#fff;background-color:#000;background-color:rgba(0,0,0,.8)}.video-js .vjs-slider{position:relative;cursor:pointer;padding:0;margin:0 .45em 0 .45em;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#73859f;background-color:rgba(115,133,159,.5)}.video-js .vjs-slider.disabled{cursor:default}.video-js .vjs-slider:focus{text-shadow:0 0 1em #fff;box-shadow:0 0 1em #fff}.video-js .vjs-mute-control{cursor:pointer;flex:none}.video-js .vjs-volume-control{cursor:pointer;margin-right:1em;display:flex}.video-js .vjs-volume-control.vjs-volume-horizontal{width:5em}.video-js .vjs-volume-panel .vjs-volume-control{visibility:visible;opacity:0;width:1px;height:1px;margin-left:-1px}.video-js .vjs-volume-panel{transition:width 1s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active,.video-js .vjs-volume-panel .vjs-volume-control:active,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control,.video-js .vjs-volume-panel:active .vjs-volume-control,.video-js .vjs-volume-panel:focus .vjs-volume-control{visibility:visible;opacity:1;position:relative;transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal,.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal{width:5em;height:3em;margin-right:0}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-vertical,.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-vertical,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-vertical{left:-3.5em;transition:left 0s}.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active{width:10em;transition:width .1s}.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-mute-toggle-only{width:4em}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical{height:8em;width:3em;left:-3000em;transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal{transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s}.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal{width:5em;height:3em;visibility:visible;opacity:1;position:relative;transition:none}.video-js.vjs-no-flex .vjs-volume-control.vjs-volume-vertical,.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical{position:absolute;bottom:3em;left:.5em}.video-js .vjs-volume-panel{display:flex}.video-js .vjs-volume-bar{margin:1.35em .45em}.vjs-volume-bar.vjs-slider-horizontal{width:5em;height:.3em}.vjs-volume-bar.vjs-slider-vertical{width:.3em;height:5em;margin:1.35em auto}.video-js .vjs-volume-level{position:absolute;bottom:0;left:0;background-color:#fff}.video-js .vjs-volume-level:before{position:absolute;font-size:.9em;z-index:1}.vjs-slider-vertical .vjs-volume-level{width:.3em}.vjs-slider-vertical .vjs-volume-level:before{top:-.5em;left:-.3em;z-index:1}.vjs-slider-horizontal .vjs-volume-level{height:.3em}.vjs-slider-horizontal .vjs-volume-level:before{top:-.3em;right:-.5em}.video-js .vjs-volume-panel.vjs-volume-panel-vertical{width:4em}.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level{height:100%}.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level{width:100%}.video-js .vjs-volume-vertical{width:3em;height:8em;bottom:8em;background-color:#2b333f;background-color:rgba(43,51,63,.7)}.video-js .vjs-volume-horizontal .vjs-menu{left:-2em}.video-js .vjs-volume-tooltip{background-color:#fff;background-color:rgba(255,255,255,.8);border-radius:.3em;color:#000;float:right;font-family:Arial,Helvetica,sans-serif;font-size:1em;padding:6px 8px 8px 8px;pointer-events:none;position:absolute;top:-3.4em;visibility:hidden;z-index:1}.video-js .vjs-volume-control:hover .vjs-progress-holder:focus .vjs-volume-tooltip,.video-js .vjs-volume-control:hover .vjs-volume-tooltip{display:block;font-size:1em;visibility:visible}.video-js .vjs-volume-vertical:hover .vjs-progress-holder:focus .vjs-volume-tooltip,.video-js .vjs-volume-vertical:hover .vjs-volume-tooltip{left:1em;top:-12px}.video-js .vjs-volume-control.disabled:hover .vjs-volume-tooltip{font-size:1em}.video-js .vjs-volume-control .vjs-mouse-display{display:none;position:absolute;width:100%;height:1px;background-color:#000;z-index:1}.video-js .vjs-volume-horizontal .vjs-mouse-display{width:1px;height:100%}.vjs-no-flex .vjs-volume-control .vjs-mouse-display{z-index:0}.video-js .vjs-volume-control:hover .vjs-mouse-display{display:block}.video-js.vjs-user-inactive .vjs-volume-control .vjs-mouse-display{visibility:hidden;opacity:0;transition:visibility 1s,opacity 1s}.video-js.vjs-user-inactive.vjs-no-flex .vjs-volume-control .vjs-mouse-display{display:none}.vjs-mouse-display .vjs-volume-tooltip{color:#fff;background-color:#000;background-color:rgba(0,0,0,.8)}.vjs-poster{display:inline-block;vertical-align:middle;background-repeat:no-repeat;background-position:50% 50%;background-size:contain;background-color:#000;cursor:pointer;margin:0;padding:0;position:absolute;top:0;right:0;bottom:0;left:0;height:100%}.vjs-has-started .vjs-poster,.vjs-using-native-controls .vjs-poster{display:none}.vjs-audio.vjs-has-started .vjs-poster,.vjs-has-started.vjs-audio-poster-mode .vjs-poster{display:block}.video-js .vjs-live-control{display:flex;align-items:flex-start;flex:auto;font-size:1em;line-height:3em}.vjs-no-flex .vjs-live-control{display:table-cell;width:auto;text-align:left}.video-js.vjs-liveui .vjs-live-control,.video-js:not(.vjs-live) .vjs-live-control{display:none}.video-js .vjs-seek-to-live-control{align-items:center;cursor:pointer;flex:none;display:inline-flex;height:100%;padding-left:.5em;padding-right:.5em;font-size:1em;line-height:3em;width:auto;min-width:4em}.vjs-no-flex .vjs-seek-to-live-control{display:table-cell;width:auto;text-align:left}.video-js.vjs-live:not(.vjs-liveui) .vjs-seek-to-live-control,.video-js:not(.vjs-live) .vjs-seek-to-live-control{display:none}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge{cursor:auto}.vjs-seek-to-live-control .vjs-icon-placeholder{margin-right:.5em;color:#888}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-icon-placeholder{color:red}.video-js .vjs-time-control{flex:none;font-size:1em;line-height:3em;min-width:2em;width:auto;padding-left:1em;padding-right:1em}.vjs-live .vjs-time-control{display:none}.video-js .vjs-current-time,.vjs-no-flex .vjs-current-time{display:none}.video-js .vjs-duration,.vjs-no-flex .vjs-duration{display:none}.vjs-time-divider{display:none;line-height:3em}.vjs-live .vjs-time-divider{display:none}.video-js .vjs-play-control{cursor:pointer}.video-js .vjs-play-control .vjs-icon-placeholder{flex:none}.vjs-text-track-display{position:absolute;bottom:3em;left:0;right:0;top:0;pointer-events:none}.video-js.vjs-controls-disabled .vjs-text-track-display,.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display{bottom:1em}.video-js .vjs-text-track{font-size:1.4em;text-align:center;margin-bottom:.1em}.vjs-subtitles{color:#fff}.vjs-captions{color:#fc6}.vjs-tt-cue{display:block}video::-webkit-media-text-track-display{transform:translateY(-3em)}.video-js.vjs-controls-disabled video::-webkit-media-text-track-display,.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display{transform:translateY(-1.5em)}.video-js .vjs-picture-in-picture-control{cursor:pointer;flex:none}.video-js.vjs-audio-only-mode .vjs-picture-in-picture-control{display:none}.video-js .vjs-fullscreen-control{cursor:pointer;flex:none}.video-js.vjs-audio-only-mode .vjs-fullscreen-control{display:none}.vjs-playback-rate .vjs-playback-rate-value,.vjs-playback-rate>.vjs-menu-button{position:absolute;top:0;left:0;width:100%;height:100%}.vjs-playback-rate .vjs-playback-rate-value{pointer-events:none;font-size:1.5em;line-height:2;text-align:center}.vjs-playback-rate .vjs-menu{width:4em;left:0}.vjs-error .vjs-error-display .vjs-modal-dialog-content{font-size:1.4em;text-align:center}.vjs-error .vjs-error-display:before{color:#fff;content:"X";font-family:Arial,Helvetica,sans-serif;font-size:4em;left:0;line-height:1;margin-top:-.5em;position:absolute;text-shadow:.05em .05em .1em #000;text-align:center;top:50%;vertical-align:middle;width:100%}.vjs-loading-spinner{display:none;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;opacity:.85;text-align:left;border:6px solid rgba(43,51,63,.7);box-sizing:border-box;background-clip:padding-box;width:50px;height:50px;border-radius:25px;visibility:hidden}.vjs-seeking .vjs-loading-spinner,.vjs-waiting .vjs-loading-spinner{display:block;-webkit-animation:vjs-spinner-show 0s linear .3s forwards;animation:vjs-spinner-show 0s linear .3s forwards}.vjs-loading-spinner:after,.vjs-loading-spinner:before{content:"";position:absolute;margin:-6px;box-sizing:inherit;width:inherit;height:inherit;border-radius:inherit;opacity:1;border:inherit;border-color:transparent;border-top-color:#fff}.vjs-seeking .vjs-loading-spinner:after,.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:before{-webkit-animation:vjs-spinner-spin 1.1s cubic-bezier(.6,.2,0,.8) infinite,vjs-spinner-fade 1.1s linear infinite;animation:vjs-spinner-spin 1.1s cubic-bezier(.6,.2,0,.8) infinite,vjs-spinner-fade 1.1s linear infinite}.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:before{border-top-color:#fff}.vjs-seeking .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:after{border-top-color:#fff;-webkit-animation-delay:.44s;animation-delay:.44s}@keyframes vjs-spinner-show{to{visibility:visible}}@-webkit-keyframes vjs-spinner-show{to{visibility:visible}}@keyframes vjs-spinner-spin{100%{transform:rotate(360deg)}}@-webkit-keyframes vjs-spinner-spin{100%{-webkit-transform:rotate(360deg)}}@keyframes vjs-spinner-fade{0%{border-top-color:#73859f}20%{border-top-color:#73859f}35%{border-top-color:#fff}60%{border-top-color:#73859f}100%{border-top-color:#73859f}}@-webkit-keyframes vjs-spinner-fade{0%{border-top-color:#73859f}20%{border-top-color:#73859f}35%{border-top-color:#fff}60%{border-top-color:#73859f}100%{border-top-color:#73859f}}.video-js.vjs-audio-only-mode .vjs-captions-button{display:none}.vjs-chapters-button .vjs-menu ul{width:24em}.video-js.vjs-audio-only-mode .vjs-descriptions-button{display:none}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder{vertical-align:middle;display:inline-block;margin-bottom:-.1em}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before{font-family:VideoJS;content:"";font-size:1.5em;line-height:inherit}.video-js.vjs-audio-only-mode .vjs-subs-caps-button{display:none}.video-js .vjs-audio-button+.vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder{vertical-align:middle;display:inline-block;margin-bottom:-.1em}.video-js .vjs-audio-button+.vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before{font-family:VideoJS;content:" ";font-size:1.5em;line-height:inherit}.video-js.vjs-layout-small .vjs-current-time,.video-js.vjs-layout-small .vjs-duration,.video-js.vjs-layout-small .vjs-playback-rate,.video-js.vjs-layout-small .vjs-remaining-time,.video-js.vjs-layout-small .vjs-time-divider,.video-js.vjs-layout-small .vjs-volume-control,.video-js.vjs-layout-tiny .vjs-current-time,.video-js.vjs-layout-tiny .vjs-duration,.video-js.vjs-layout-tiny .vjs-playback-rate,.video-js.vjs-layout-tiny .vjs-remaining-time,.video-js.vjs-layout-tiny .vjs-time-divider,.video-js.vjs-layout-tiny .vjs-volume-control,.video-js.vjs-layout-x-small .vjs-current-time,.video-js.vjs-layout-x-small .vjs-duration,.video-js.vjs-layout-x-small .vjs-playback-rate,.video-js.vjs-layout-x-small .vjs-remaining-time,.video-js.vjs-layout-x-small .vjs-time-divider,.video-js.vjs-layout-x-small .vjs-volume-control{display:none}.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:hover,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover{width:auto;width:initial}.video-js.vjs-layout-tiny .vjs-progress-control,.video-js.vjs-layout-x-small .vjs-progress-control{display:none}.video-js.vjs-layout-x-small .vjs-custom-control-spacer{flex:auto;display:block}.video-js.vjs-layout-x-small.vjs-no-flex .vjs-custom-control-spacer{width:auto}.vjs-modal-dialog.vjs-text-track-settings{background-color:#2b333f;background-color:rgba(43,51,63,.75);color:#fff;height:70%}.vjs-text-track-settings .vjs-modal-dialog-content{display:table}.vjs-text-track-settings .vjs-track-settings-colors,.vjs-text-track-settings .vjs-track-settings-controls,.vjs-text-track-settings .vjs-track-settings-font{display:table-cell}.vjs-text-track-settings .vjs-track-settings-controls{text-align:right;vertical-align:bottom}@supports (display:grid){.vjs-text-track-settings .vjs-modal-dialog-content{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr;padding:20px 24px 0 24px}.vjs-track-settings-controls .vjs-default-button{margin-bottom:20px}.vjs-text-track-settings .vjs-track-settings-controls{grid-column:1/-1}.vjs-layout-small .vjs-text-track-settings .vjs-modal-dialog-content,.vjs-layout-tiny .vjs-text-track-settings .vjs-modal-dialog-content,.vjs-layout-x-small .vjs-text-track-settings .vjs-modal-dialog-content{grid-template-columns:1fr}}.vjs-track-setting>select{margin-right:1em;margin-bottom:.5em}.vjs-text-track-settings fieldset{margin:5px;padding:3px;border:none}.vjs-text-track-settings fieldset span{display:inline-block}.vjs-text-track-settings fieldset span>select{max-width:7.3em}.vjs-text-track-settings legend{color:#fff;margin:0 0 5px 0}.vjs-text-track-settings .vjs-label{position:absolute;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);display:block;margin:0 0 5px 0;padding:0;border:0;height:1px;width:1px;overflow:hidden}.vjs-track-settings-controls button:active,.vjs-track-settings-controls button:focus{outline-style:solid;outline-width:medium;background-image:linear-gradient(0deg,#fff 88%,#73859f 100%)}.vjs-track-settings-controls button:hover{color:rgba(43,51,63,.75)}.vjs-track-settings-controls button{background-color:#fff;background-image:linear-gradient(-180deg,#fff 88%,#73859f 100%);color:#2b333f;cursor:pointer;border-radius:2px}.vjs-track-settings-controls .vjs-default-button{margin-right:1em}@media print{.video-js>:not(.vjs-tech):not(.vjs-poster){visibility:hidden}}.vjs-resize-manager{position:absolute;top:0;left:0;width:100%;height:100%;border:none;z-index:-1000}.js-focus-visible .video-js :focus:not(.focus-visible){outline:0}.video-js :focus:not(:focus-visible){outline:0} \ No newline at end of file +.vjs-svg-icon{display:inline-block;background-repeat:no-repeat;background-position:center;fill:currentColor;height:1.8em;width:1.8em}.vjs-svg-icon:before{content:none!important}.vjs-control:focus .vjs-svg-icon,.vjs-svg-icon:hover{filter:drop-shadow(0 0 .25em #fff)}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-modal-dialog,.vjs-button>.vjs-icon-placeholder:before,.vjs-modal-dialog .vjs-modal-dialog-content{position:absolute;top:0;left:0;width:100%;height:100%}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.vjs-button>.vjs-icon-placeholder:before{text-align:center}@font-face{font-family:VideoJS;src:url(data:application/font-woff;charset=utf-8;base64,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) format("woff");font-weight:400;font-style:normal}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder,.vjs-icon-play{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder:before,.vjs-icon-play:before{content:"\f101"}.vjs-icon-play-circle{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-play-circle:before{content:"\f102"}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder,.vjs-icon-pause{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder:before,.vjs-icon-pause:before{content:"\f103"}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder,.vjs-icon-volume-mute{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder:before,.vjs-icon-volume-mute:before{content:"\f104"}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder,.vjs-icon-volume-low{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder:before,.vjs-icon-volume-low:before{content:"\f105"}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder,.vjs-icon-volume-mid{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder:before,.vjs-icon-volume-mid:before{content:"\f106"}.video-js .vjs-mute-control .vjs-icon-placeholder,.vjs-icon-volume-high{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control .vjs-icon-placeholder:before,.vjs-icon-volume-high:before{content:"\f107"}.video-js .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-enter{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-enter:before{content:"\f108"}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-exit{font-family:VideoJS;font-weight:400;font-style:normal}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-exit:before{content:"\f109"}.vjs-icon-spinner{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-spinner:before{content:"\f10a"}.video-js .vjs-subs-caps-button .vjs-icon-placeholder,.video-js .vjs-subtitles-button .vjs-icon-placeholder,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-subtitles{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js .vjs-subtitles-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-subtitles:before{content:"\f10b"}.video-js .vjs-captions-button .vjs-icon-placeholder,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-captions{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-captions-button .vjs-icon-placeholder:before,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-captions:before{content:"\f10c"}.vjs-icon-hd{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-hd:before{content:"\f10d"}.video-js .vjs-chapters-button .vjs-icon-placeholder,.vjs-icon-chapters{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-chapters-button .vjs-icon-placeholder:before,.vjs-icon-chapters:before{content:"\f10e"}.vjs-icon-downloading{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-downloading:before{content:"\f10f"}.vjs-icon-file-download{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-file-download:before{content:"\f110"}.vjs-icon-file-download-done{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-file-download-done:before{content:"\f111"}.vjs-icon-file-download-off{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-file-download-off:before{content:"\f112"}.vjs-icon-share{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-share:before{content:"\f113"}.vjs-icon-cog{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-cog:before{content:"\f114"}.vjs-icon-square{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-square:before{content:"\f115"}.video-js .vjs-play-progress,.video-js .vjs-volume-level,.vjs-icon-circle,.vjs-seek-to-live-control .vjs-icon-placeholder{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-progress:before,.video-js .vjs-volume-level:before,.vjs-icon-circle:before,.vjs-seek-to-live-control .vjs-icon-placeholder:before{content:"\f116"}.vjs-icon-circle-outline{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-circle-outline:before{content:"\f117"}.vjs-icon-circle-inner-circle{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-circle-inner-circle:before{content:"\f118"}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder,.vjs-icon-cancel{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder:before,.vjs-icon-cancel:before{content:"\f119"}.vjs-icon-repeat{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-repeat:before{content:"\f11a"}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder,.vjs-icon-replay{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder:before,.vjs-icon-replay:before{content:"\f11b"}.video-js .vjs-skip-backward-5 .vjs-icon-placeholder,.vjs-icon-replay-5{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-skip-backward-5 .vjs-icon-placeholder:before,.vjs-icon-replay-5:before{content:"\f11c"}.video-js .vjs-skip-backward-10 .vjs-icon-placeholder,.vjs-icon-replay-10{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-skip-backward-10 .vjs-icon-placeholder:before,.vjs-icon-replay-10:before{content:"\f11d"}.video-js .vjs-skip-backward-30 .vjs-icon-placeholder,.vjs-icon-replay-30{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-skip-backward-30 .vjs-icon-placeholder:before,.vjs-icon-replay-30:before{content:"\f11e"}.video-js .vjs-skip-forward-5 .vjs-icon-placeholder,.vjs-icon-forward-5{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-skip-forward-5 .vjs-icon-placeholder:before,.vjs-icon-forward-5:before{content:"\f11f"}.video-js .vjs-skip-forward-10 .vjs-icon-placeholder,.vjs-icon-forward-10{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-skip-forward-10 .vjs-icon-placeholder:before,.vjs-icon-forward-10:before{content:"\f120"}.video-js .vjs-skip-forward-30 .vjs-icon-placeholder,.vjs-icon-forward-30{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-skip-forward-30 .vjs-icon-placeholder:before,.vjs-icon-forward-30:before{content:"\f121"}.video-js .vjs-audio-button .vjs-icon-placeholder,.vjs-icon-audio{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-audio-button .vjs-icon-placeholder:before,.vjs-icon-audio:before{content:"\f122"}.vjs-icon-next-item{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-next-item:before{content:"\f123"}.vjs-icon-previous-item{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-previous-item:before{content:"\f124"}.vjs-icon-shuffle{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-shuffle:before{content:"\f125"}.vjs-icon-cast{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-cast:before{content:"\f126"}.video-js .vjs-picture-in-picture-control .vjs-icon-placeholder,.vjs-icon-picture-in-picture-enter{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before,.vjs-icon-picture-in-picture-enter:before{content:"\f127"}.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder,.vjs-icon-picture-in-picture-exit{font-family:VideoJS;font-weight:400;font-style:normal}.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder:before,.vjs-icon-picture-in-picture-exit:before{content:"\f128"}.vjs-icon-facebook{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-facebook:before{content:"\f129"}.vjs-icon-linkedin{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-linkedin:before{content:"\f12a"}.vjs-icon-twitter{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-twitter:before{content:"\f12b"}.vjs-icon-tumblr{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-tumblr:before{content:"\f12c"}.vjs-icon-pinterest{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-pinterest:before{content:"\f12d"}.video-js .vjs-descriptions-button .vjs-icon-placeholder,.vjs-icon-audio-description{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-descriptions-button .vjs-icon-placeholder:before,.vjs-icon-audio-description:before{content:"\f12e"}.video-js{display:inline-block;vertical-align:top;box-sizing:border-box;color:#fff;background-color:#000;position:relative;padding:0;font-size:10px;line-height:1;font-weight:400;font-style:normal;font-family:Arial,Helvetica,sans-serif;word-break:initial}.video-js:-moz-full-screen{position:absolute}.video-js:-webkit-full-screen{width:100%!important;height:100%!important}.video-js[tabindex="-1"]{outline:0}.video-js *,.video-js :after,.video-js :before{box-sizing:inherit}.video-js ul{font-family:inherit;font-size:inherit;line-height:inherit;list-style-position:outside;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.video-js.vjs-1-1,.video-js.vjs-16-9,.video-js.vjs-4-3,.video-js.vjs-9-16,.video-js.vjs-fluid{width:100%;max-width:100%}.video-js.vjs-1-1:not(.vjs-audio-only-mode),.video-js.vjs-16-9:not(.vjs-audio-only-mode),.video-js.vjs-4-3:not(.vjs-audio-only-mode),.video-js.vjs-9-16:not(.vjs-audio-only-mode),.video-js.vjs-fluid:not(.vjs-audio-only-mode){height:0}.video-js.vjs-16-9:not(.vjs-audio-only-mode){padding-top:56.25%}.video-js.vjs-4-3:not(.vjs-audio-only-mode){padding-top:75%}.video-js.vjs-9-16:not(.vjs-audio-only-mode){padding-top:177.7777777778%}.video-js.vjs-1-1:not(.vjs-audio-only-mode){padding-top:100%}.video-js.vjs-fill:not(.vjs-audio-only-mode){width:100%;height:100%}.video-js .vjs-tech{position:absolute;top:0;left:0;width:100%;height:100%}.video-js.vjs-audio-only-mode .vjs-tech{display:none}body.vjs-full-window,body.vjs-pip-window{padding:0;margin:0;height:100%}.vjs-full-window .video-js.vjs-fullscreen,body.vjs-pip-window .video-js{position:fixed;overflow:hidden;z-index:1000;left:0;top:0;bottom:0;right:0}.video-js.vjs-fullscreen:not(.vjs-ios-native-fs),body.vjs-pip-window .video-js{width:100%!important;height:100%!important;padding-top:0!important;display:block}.video-js.vjs-fullscreen.vjs-user-inactive{cursor:none}.vjs-pip-container .vjs-pip-text{position:absolute;bottom:10%;font-size:2em;background-color:rgba(0,0,0,.7);padding:.5em;text-align:center;width:100%}.vjs-layout-small.vjs-pip-container .vjs-pip-text,.vjs-layout-tiny.vjs-pip-container .vjs-pip-text,.vjs-layout-x-small.vjs-pip-container .vjs-pip-text{bottom:0;font-size:1.4em}.vjs-hidden{display:none!important}.vjs-disabled{opacity:.5;cursor:default}.video-js .vjs-offscreen{height:1px;left:-9999px;position:absolute;top:0;width:1px}.vjs-lock-showing{display:block!important;opacity:1!important;visibility:visible!important}.vjs-no-js{padding:20px;color:#fff;background-color:#000;font-size:18px;font-family:Arial,Helvetica,sans-serif;text-align:center;width:300px;height:150px;margin:0 auto}.vjs-no-js a,.vjs-no-js a:visited{color:#66a8cc}.video-js .vjs-big-play-button{font-size:3em;line-height:1.5em;height:1.63332em;width:3em;display:block;position:absolute;top:50%;left:50%;padding:0;margin-top:-.81666em;margin-left:-1.5em;cursor:pointer;opacity:1;border:.06666em solid #fff;background-color:#2b333f;background-color:rgba(43,51,63,.7);border-radius:.3em;transition:all .4s}.vjs-big-play-button .vjs-svg-icon{width:1em;height:1em;position:absolute;top:50%;left:50%;line-height:1;transform:translate(-50%,-50%)}.video-js .vjs-big-play-button:focus,.video-js:hover .vjs-big-play-button{border-color:#fff;background-color:#73859f;background-color:rgba(115,133,159,.5);transition:all 0s}.vjs-controls-disabled .vjs-big-play-button,.vjs-error .vjs-big-play-button,.vjs-has-started .vjs-big-play-button,.vjs-using-native-controls .vjs-big-play-button{display:none}.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause:not(.vjs-seeking,.vjs-scrubbing,.vjs-error) .vjs-big-play-button{display:block}.video-js button{background:0 0;border:none;color:inherit;display:inline-block;font-size:inherit;line-height:inherit;text-transform:none;text-decoration:none;transition:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.video-js.vjs-spatial-navigation-enabled .vjs-button:focus{outline:.0625em solid #fff;box-shadow:none}.vjs-control .vjs-button{width:100%;height:100%}.video-js .vjs-control.vjs-close-button{cursor:pointer;height:3em;position:absolute;right:0;top:.5em;z-index:2}.video-js .vjs-modal-dialog{background:rgba(0,0,0,.8);background:linear-gradient(180deg,rgba(0,0,0,.8),rgba(255,255,255,0));overflow:auto}.video-js .vjs-modal-dialog>*{box-sizing:border-box}.vjs-modal-dialog .vjs-modal-dialog-content{font-size:1.2em;line-height:1.5;padding:20px 24px;z-index:1}.vjs-menu-button{cursor:pointer}.vjs-menu-button.vjs-disabled{cursor:default}.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu{display:none}.vjs-menu .vjs-menu-content{display:block;padding:0;margin:0;font-family:Arial,Helvetica,sans-serif;overflow:auto}.vjs-menu .vjs-menu-content>*{box-sizing:border-box}.vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu{display:none}.vjs-menu li{display:flex;justify-content:center;list-style:none;margin:0;padding:.2em 0;line-height:1.4em;font-size:1.2em;text-align:center;text-transform:lowercase}.js-focus-visible .vjs-menu li.vjs-menu-item:hover,.vjs-menu li.vjs-menu-item:focus,.vjs-menu li.vjs-menu-item:hover{background-color:#73859f;background-color:rgba(115,133,159,.5)}.js-focus-visible .vjs-menu li.vjs-selected:hover,.vjs-menu li.vjs-selected,.vjs-menu li.vjs-selected:focus,.vjs-menu li.vjs-selected:hover{background-color:#fff;color:#2b333f}.js-focus-visible .vjs-menu li.vjs-selected:hover .vjs-svg-icon,.vjs-menu li.vjs-selected .vjs-svg-icon,.vjs-menu li.vjs-selected:focus .vjs-svg-icon,.vjs-menu li.vjs-selected:hover .vjs-svg-icon{fill:#000}.js-focus-visible .vjs-menu :not(.vjs-selected):focus:not(.focus-visible),.video-js .vjs-menu :not(.vjs-selected):focus:not(:focus-visible){background:0 0}.vjs-menu li.vjs-menu-title{text-align:center;text-transform:uppercase;font-size:1em;line-height:2em;padding:0;margin:0 0 .3em 0;font-weight:700;cursor:default}.vjs-menu-button-popup .vjs-menu{display:none;position:absolute;bottom:0;width:10em;left:-3em;height:0;margin-bottom:1.5em;border-top-color:rgba(43,51,63,.7)}.vjs-pip-window .vjs-menu-button-popup .vjs-menu{left:unset;right:1em}.vjs-menu-button-popup .vjs-menu .vjs-menu-content{background-color:#2b333f;background-color:rgba(43,51,63,.7);position:absolute;width:100%;bottom:1.5em;max-height:15em}.vjs-layout-tiny .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-x-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:5em}.vjs-layout-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:10em}.vjs-layout-medium .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:14em}.vjs-layout-huge .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content,.vjs-layout-x-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content{max-height:25em}.vjs-menu-button-popup .vjs-menu.vjs-lock-showing,.vjs-workinghover .vjs-menu-button-popup.vjs-hover .vjs-menu{display:block}.video-js .vjs-menu-button-inline{transition:all .4s;overflow:hidden}.video-js .vjs-menu-button-inline:before{width:2.222222222em}.video-js .vjs-menu-button-inline.vjs-slider-active,.video-js .vjs-menu-button-inline:focus,.video-js .vjs-menu-button-inline:hover{width:12em}.vjs-menu-button-inline .vjs-menu{opacity:0;height:100%;width:auto;position:absolute;left:4em;top:0;padding:0;margin:0;transition:all .4s}.vjs-menu-button-inline.vjs-slider-active .vjs-menu,.vjs-menu-button-inline:focus .vjs-menu,.vjs-menu-button-inline:hover .vjs-menu{display:block;opacity:1}.vjs-menu-button-inline .vjs-menu-content{width:auto;height:100%;margin:0;overflow:hidden}.video-js .vjs-control-bar{display:none;width:100%;position:absolute;bottom:0;left:0;right:0;height:3em;background-color:#2b333f;background-color:rgba(43,51,63,.7)}.video-js.vjs-spatial-navigation-enabled .vjs-control-bar{gap:1px}.video-js:not(.vjs-controls-disabled,.vjs-using-native-controls,.vjs-error) .vjs-control-bar.vjs-lock-showing{display:flex!important}.vjs-audio-only-mode .vjs-control-bar,.vjs-has-started .vjs-control-bar{display:flex;visibility:visible;opacity:1;transition:visibility .1s,opacity .1s}.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{visibility:visible;opacity:0;pointer-events:none;transition:visibility 1s,opacity 1s}.vjs-controls-disabled .vjs-control-bar,.vjs-error .vjs-control-bar,.vjs-using-native-controls .vjs-control-bar{display:none!important}.vjs-audio-only-mode.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar,.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{opacity:1;visibility:visible;pointer-events:auto}.video-js .vjs-control{position:relative;text-align:center;margin:0;padding:0;height:100%;width:4em;flex:none}.video-js .vjs-control.vjs-visible-text{width:auto;padding-left:1em;padding-right:1em}.vjs-button>.vjs-icon-placeholder:before{font-size:1.8em;line-height:1.67}.vjs-button>.vjs-icon-placeholder{display:block}.vjs-button>.vjs-svg-icon{display:inline-block}.video-js .vjs-control:focus,.video-js .vjs-control:focus:before,.video-js .vjs-control:hover:before{text-shadow:0 0 1em #fff}.video-js :not(.vjs-visible-text)>.vjs-control-text{border:0;clip:rect(0 0 0 0);height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.video-js .vjs-custom-control-spacer{display:none}.video-js .vjs-progress-control{cursor:pointer;flex:auto;display:flex;align-items:center;min-width:4em;touch-action:none}.video-js .vjs-progress-control.disabled{cursor:default}.vjs-live .vjs-progress-control{display:none}.vjs-liveui .vjs-progress-control{display:flex;align-items:center}.video-js .vjs-progress-holder{flex:auto;transition:all .2s;height:.3em}.video-js .vjs-progress-control .vjs-progress-holder{margin:0 10px}.video-js .vjs-progress-control:hover .vjs-progress-holder{font-size:1.6666666667em}.video-js .vjs-progress-control:hover .vjs-progress-holder.disabled{font-size:1em}.video-js .vjs-progress-holder .vjs-load-progress,.video-js .vjs-progress-holder .vjs-load-progress div,.video-js .vjs-progress-holder .vjs-play-progress{position:absolute;display:block;height:100%;margin:0;padding:0;width:0}.video-js .vjs-play-progress{background-color:#fff}.video-js .vjs-play-progress:before{font-size:.9em;position:absolute;right:-.5em;line-height:.35em;z-index:1}.vjs-svg-icons-enabled .vjs-play-progress:before{content:none!important}.vjs-play-progress .vjs-svg-icon{position:absolute;top:-.35em;right:-.4em;width:.9em;height:.9em;pointer-events:none;line-height:.15em;z-index:1}.video-js .vjs-load-progress{background:rgba(115,133,159,.5)}.video-js .vjs-load-progress div{background:rgba(115,133,159,.75)}.video-js .vjs-time-tooltip{background-color:#fff;background-color:rgba(255,255,255,.8);border-radius:.3em;color:#000;float:right;font-family:Arial,Helvetica,sans-serif;font-size:1em;padding:6px 8px 8px 8px;pointer-events:none;position:absolute;top:-3.4em;visibility:hidden;z-index:1}.video-js .vjs-progress-holder:focus .vjs-time-tooltip{display:none}.video-js .vjs-progress-control:hover .vjs-progress-holder:focus .vjs-time-tooltip,.video-js .vjs-progress-control:hover .vjs-time-tooltip{display:block;font-size:.6em;visibility:visible}.video-js .vjs-progress-control.disabled:hover .vjs-time-tooltip{font-size:1em}.video-js .vjs-progress-control .vjs-mouse-display{display:none;position:absolute;width:1px;height:100%;background-color:#000;z-index:1}.video-js .vjs-progress-control:hover .vjs-mouse-display{display:block}.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display{visibility:hidden;opacity:0;transition:visibility 1s,opacity 1s}.vjs-mouse-display .vjs-time-tooltip{color:#fff;background-color:#000;background-color:rgba(0,0,0,.8)}.video-js .vjs-slider{position:relative;cursor:pointer;padding:0;margin:0 .45em 0 .45em;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:#73859f;background-color:rgba(115,133,159,.5)}.video-js .vjs-slider.disabled{cursor:default}.video-js .vjs-slider:focus{text-shadow:0 0 1em #fff;box-shadow:0 0 1em #fff}.video-js.vjs-spatial-navigation-enabled .vjs-slider:focus{outline:.0625em solid #fff}.video-js .vjs-mute-control{cursor:pointer;flex:none}.video-js .vjs-volume-control{cursor:pointer;margin-right:1em;display:flex}.video-js .vjs-volume-control.vjs-volume-horizontal{width:5em}.video-js .vjs-volume-panel .vjs-volume-control{visibility:visible;opacity:0;width:1px;height:1px;margin-left:-1px}.video-js .vjs-volume-panel{transition:width 1s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active,.video-js .vjs-volume-panel .vjs-volume-control:active,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control,.video-js .vjs-volume-panel:active .vjs-volume-control,.video-js .vjs-volume-panel:focus .vjs-volume-control{visibility:visible;opacity:1;position:relative;transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal,.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal{width:5em;height:3em;margin-right:0}.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-vertical,.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-vertical,.video-js .vjs-volume-panel.vjs-hover .vjs-mute-control~.vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-vertical,.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-vertical{left:-3.5em;transition:left 0s}.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active{width:10em;transition:width .1s}.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-mute-toggle-only{width:4em}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical{height:8em;width:3em;left:-3000em;transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal{transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s}.video-js .vjs-volume-panel{display:flex}.video-js .vjs-volume-bar{margin:1.35em .45em}.vjs-volume-bar.vjs-slider-horizontal{width:5em;height:.3em}.vjs-volume-bar.vjs-slider-vertical{width:.3em;height:5em;margin:1.35em auto}.video-js .vjs-volume-level{position:absolute;bottom:0;left:0;background-color:#fff}.video-js .vjs-volume-level:before{position:absolute;font-size:.9em;z-index:1}.vjs-slider-vertical .vjs-volume-level{width:.3em}.vjs-slider-vertical .vjs-volume-level:before{top:-.5em;left:-.3em;z-index:1}.vjs-svg-icons-enabled .vjs-volume-level:before{content:none}.vjs-volume-level .vjs-svg-icon{position:absolute;width:.9em;height:.9em;pointer-events:none;z-index:1}.vjs-slider-horizontal .vjs-volume-level{height:.3em}.vjs-slider-horizontal .vjs-volume-level:before{line-height:.35em;right:-.5em}.vjs-slider-horizontal .vjs-volume-level .vjs-svg-icon{right:-.3em;transform:translateY(-50%)}.vjs-slider-vertical .vjs-volume-level .vjs-svg-icon{top:-.55em;transform:translateX(-50%)}.video-js .vjs-volume-panel.vjs-volume-panel-vertical{width:4em}.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level{height:100%}.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level{width:100%}.video-js .vjs-volume-vertical{width:3em;height:8em;bottom:8em;background-color:#2b333f;background-color:rgba(43,51,63,.7)}.video-js .vjs-volume-horizontal .vjs-menu{left:-2em}.video-js .vjs-volume-tooltip{background-color:#fff;background-color:rgba(255,255,255,.8);border-radius:.3em;color:#000;float:right;font-family:Arial,Helvetica,sans-serif;font-size:1em;padding:6px 8px 8px 8px;pointer-events:none;position:absolute;top:-3.4em;visibility:hidden;z-index:1}.video-js .vjs-volume-control:hover .vjs-progress-holder:focus .vjs-volume-tooltip,.video-js .vjs-volume-control:hover .vjs-volume-tooltip{display:block;font-size:1em;visibility:visible}.video-js .vjs-volume-vertical:hover .vjs-progress-holder:focus .vjs-volume-tooltip,.video-js .vjs-volume-vertical:hover .vjs-volume-tooltip{left:1em;top:-12px}.video-js .vjs-volume-control.disabled:hover .vjs-volume-tooltip{font-size:1em}.video-js .vjs-volume-control .vjs-mouse-display{display:none;position:absolute;width:100%;height:1px;background-color:#000;z-index:1}.video-js .vjs-volume-horizontal .vjs-mouse-display{width:1px;height:100%}.video-js .vjs-volume-control:hover .vjs-mouse-display{display:block}.video-js.vjs-user-inactive .vjs-volume-control .vjs-mouse-display{visibility:hidden;opacity:0;transition:visibility 1s,opacity 1s}.vjs-mouse-display .vjs-volume-tooltip{color:#fff;background-color:#000;background-color:rgba(0,0,0,.8)}.vjs-poster{display:inline-block;vertical-align:middle;cursor:pointer;margin:0;padding:0;position:absolute;top:0;right:0;bottom:0;left:0;height:100%}.vjs-has-started .vjs-poster,.vjs-using-native-controls .vjs-poster{display:none}.vjs-audio.vjs-has-started .vjs-poster,.vjs-has-started.vjs-audio-poster-mode .vjs-poster,.vjs-pip-container.vjs-has-started .vjs-poster{display:block}.vjs-poster img{width:100%;height:100%;object-fit:contain}.video-js .vjs-live-control{display:flex;align-items:flex-start;flex:auto;font-size:1em;line-height:3em}.video-js.vjs-liveui .vjs-live-control,.video-js:not(.vjs-live) .vjs-live-control{display:none}.video-js .vjs-seek-to-live-control{align-items:center;cursor:pointer;flex:none;display:inline-flex;height:100%;padding-left:.5em;padding-right:.5em;font-size:1em;line-height:3em;width:auto;min-width:4em}.video-js.vjs-live:not(.vjs-liveui) .vjs-seek-to-live-control,.video-js:not(.vjs-live) .vjs-seek-to-live-control{display:none}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge{cursor:auto}.vjs-seek-to-live-control .vjs-icon-placeholder{margin-right:.5em;color:#888}.vjs-svg-icons-enabled .vjs-seek-to-live-control{line-height:0}.vjs-seek-to-live-control .vjs-svg-icon{width:1em;height:1em;pointer-events:none;fill:#888}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-icon-placeholder{color:red}.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-svg-icon{fill:red}.video-js .vjs-time-control{flex:none;font-size:1em;line-height:3em;min-width:2em;width:auto;padding-left:1em;padding-right:1em}.video-js .vjs-current-time,.video-js .vjs-duration,.vjs-live .vjs-time-control,.vjs-live .vjs-time-divider{display:none}.vjs-time-divider{display:none;line-height:3em}.video-js .vjs-play-control{cursor:pointer}.video-js .vjs-play-control .vjs-icon-placeholder{flex:none}.vjs-text-track-display{position:absolute;bottom:3em;left:0;right:0;top:0;pointer-events:none}.vjs-error .vjs-text-track-display{display:none}.video-js.vjs-controls-disabled .vjs-text-track-display,.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display{bottom:1em}.video-js .vjs-text-track{font-size:1.4em;text-align:center;margin-bottom:.1em}.vjs-subtitles{color:#fff}.vjs-captions{color:#fc6}.vjs-tt-cue{display:block}video::-webkit-media-text-track-display{transform:translateY(-3em)}.video-js.vjs-controls-disabled video::-webkit-media-text-track-display,.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display{transform:translateY(-1.5em)}.video-js.vjs-force-center-align-cues .vjs-text-track-cue{text-align:center!important;width:80%!important}.video-js .vjs-picture-in-picture-control{cursor:pointer;flex:none}.video-js.vjs-audio-only-mode .vjs-picture-in-picture-control,.vjs-pip-window .vjs-picture-in-picture-control{display:none}.video-js .vjs-fullscreen-control{cursor:pointer;flex:none}.video-js.vjs-audio-only-mode .vjs-fullscreen-control,.vjs-pip-window .vjs-fullscreen-control{display:none}.vjs-playback-rate .vjs-playback-rate-value,.vjs-playback-rate>.vjs-menu-button{position:absolute;top:0;left:0;width:100%;height:100%}.vjs-playback-rate .vjs-playback-rate-value{pointer-events:none;font-size:1.5em;line-height:2;text-align:center}.vjs-playback-rate .vjs-menu{width:4em;left:0}.vjs-error .vjs-error-display .vjs-modal-dialog-content{font-size:1.4em;text-align:center}.vjs-loading-spinner{display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);opacity:.85;text-align:left;border:.6em solid rgba(43,51,63,.7);box-sizing:border-box;background-clip:padding-box;width:5em;height:5em;border-radius:50%;visibility:hidden}.vjs-seeking .vjs-loading-spinner,.vjs-waiting .vjs-loading-spinner{display:flex;justify-content:center;align-items:center;animation:vjs-spinner-show 0s linear .3s forwards}.vjs-error .vjs-loading-spinner{display:none}.vjs-loading-spinner:after,.vjs-loading-spinner:before{content:"";position:absolute;box-sizing:inherit;width:inherit;height:inherit;border-radius:inherit;opacity:1;border:inherit;border-color:transparent;border-top-color:#fff}.vjs-seeking .vjs-loading-spinner:after,.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:before{animation:vjs-spinner-spin 1.1s cubic-bezier(.6,.2,0,.8) infinite,vjs-spinner-fade 1.1s linear infinite}.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:before{border-top-color:#fff}.vjs-seeking .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:after{border-top-color:#fff;animation-delay:.44s}@keyframes vjs-spinner-show{to{visibility:visible}}@keyframes vjs-spinner-spin{100%{transform:rotate(360deg)}}@keyframes vjs-spinner-fade{0%{border-top-color:#73859f}20%{border-top-color:#73859f}35%{border-top-color:#fff}60%{border-top-color:#73859f}100%{border-top-color:#73859f}}.video-js.vjs-audio-only-mode .vjs-captions-button{display:none}.vjs-chapters-button .vjs-menu ul{width:24em}.video-js.vjs-audio-only-mode .vjs-descriptions-button{display:none}.vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-svg-icon{width:1.5em;height:1.5em}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder{vertical-align:middle;display:inline-block;margin-bottom:-.1em}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before{font-family:VideoJS;content:"\f10c";font-size:1.5em;line-height:inherit}.video-js.vjs-audio-only-mode .vjs-subs-caps-button{display:none}.video-js .vjs-audio-button+.vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder,.video-js .vjs-audio-button+.vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder{vertical-align:middle;display:inline-block;margin-bottom:-.1em}.video-js .vjs-audio-button+.vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before,.video-js .vjs-audio-button+.vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before{font-family:VideoJS;content:" \f12e";font-size:1.5em;line-height:inherit}.video-js.vjs-layout-small .vjs-current-time,.video-js.vjs-layout-small .vjs-duration,.video-js.vjs-layout-small .vjs-playback-rate,.video-js.vjs-layout-small .vjs-remaining-time,.video-js.vjs-layout-small .vjs-time-divider,.video-js.vjs-layout-small .vjs-volume-control,.video-js.vjs-layout-tiny .vjs-current-time,.video-js.vjs-layout-tiny .vjs-duration,.video-js.vjs-layout-tiny .vjs-playback-rate,.video-js.vjs-layout-tiny .vjs-remaining-time,.video-js.vjs-layout-tiny .vjs-time-divider,.video-js.vjs-layout-tiny .vjs-volume-control,.video-js.vjs-layout-x-small .vjs-current-time,.video-js.vjs-layout-x-small .vjs-duration,.video-js.vjs-layout-x-small .vjs-playback-rate,.video-js.vjs-layout-x-small .vjs-remaining-time,.video-js.vjs-layout-x-small .vjs-time-divider,.video-js.vjs-layout-x-small .vjs-volume-control{display:none}.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:hover,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js.vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover{width:auto;width:initial}.video-js.vjs-layout-tiny .vjs-progress-control,.video-js.vjs-layout-x-small .vjs-progress-control{display:none}.video-js.vjs-layout-x-small .vjs-custom-control-spacer{flex:auto;display:block}.vjs-modal-dialog.vjs-text-track-settings{background-color:#2b333f;background-color:rgba(43,51,63,.75);color:#fff;height:70%}.vjs-spatial-navigation-enabled .vjs-modal-dialog.vjs-text-track-settings{height:80%}.vjs-error .vjs-text-track-settings{display:none}.vjs-text-track-settings .vjs-modal-dialog-content{display:table}.vjs-text-track-settings .vjs-track-settings-colors,.vjs-text-track-settings .vjs-track-settings-controls,.vjs-text-track-settings .vjs-track-settings-font{display:table-cell}.vjs-text-track-settings .vjs-track-settings-controls{text-align:right;vertical-align:bottom}@supports (display:grid){.vjs-text-track-settings .vjs-modal-dialog-content{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr;padding:20px 24px 0 24px}.vjs-track-settings-controls .vjs-default-button{margin-bottom:20px}.vjs-text-track-settings .vjs-track-settings-controls{grid-column:1/-1}.vjs-layout-small .vjs-text-track-settings .vjs-modal-dialog-content,.vjs-layout-tiny .vjs-text-track-settings .vjs-modal-dialog-content,.vjs-layout-x-small .vjs-text-track-settings .vjs-modal-dialog-content{grid-template-columns:1fr}}.vjs-text-track-settings select{font-size:inherit}.vjs-track-setting>select{margin-right:1em;margin-bottom:.5em}.vjs-text-track-settings fieldset{margin:10px;border:none}.vjs-text-track-settings fieldset span{display:inline-block;padding:0 .6em .8em}.vjs-text-track-settings fieldset span>select{max-width:7.3em}.vjs-text-track-settings legend{color:#fff;font-weight:700;font-size:1.2em}.vjs-text-track-settings .vjs-label{margin:0 .5em .5em 0}.vjs-track-settings-controls button:active,.vjs-track-settings-controls button:focus{outline-style:solid;outline-width:medium;background-image:linear-gradient(0deg,#fff 88%,#73859f 100%)}.vjs-track-settings-controls button:hover{color:rgba(43,51,63,.75)}.vjs-track-settings-controls button{background-color:#fff;background-image:linear-gradient(-180deg,#fff 88%,#73859f 100%);color:#2b333f;cursor:pointer;border-radius:2px}.vjs-track-settings-controls .vjs-default-button{margin-right:1em}.vjs-title-bar{background:rgba(0,0,0,.9);background:linear-gradient(180deg,rgba(0,0,0,.9) 0,rgba(0,0,0,.7) 60%,rgba(0,0,0,0) 100%);font-size:1.2em;line-height:1.5;transition:opacity .1s;padding:.666em 1.333em 4em;pointer-events:none;position:absolute;top:0;width:100%}.vjs-error .vjs-title-bar{display:none}.vjs-title-bar-description,.vjs-title-bar-title{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vjs-title-bar-title{font-weight:700;margin-bottom:.333em}.vjs-playing.vjs-user-inactive .vjs-title-bar{opacity:0;transition:opacity 1s}.video-js .vjs-skip-forward-5{cursor:pointer}.video-js .vjs-skip-forward-10{cursor:pointer}.video-js .vjs-skip-forward-30{cursor:pointer}.video-js .vjs-skip-backward-5{cursor:pointer}.video-js .vjs-skip-backward-10{cursor:pointer}.video-js .vjs-skip-backward-30{cursor:pointer}.video-js .vjs-transient-button{position:absolute;height:3em;display:flex;align-items:center;justify-content:center;background-color:rgba(50,50,50,.5);cursor:pointer;opacity:1;transition:opacity 1s}.video-js:not(.vjs-has-started) .vjs-transient-button{display:none}.video-js.not-hover .vjs-transient-button:not(.force-display),.video-js.vjs-user-inactive .vjs-transient-button:not(.force-display){opacity:0}.video-js .vjs-transient-button span{padding:0 .5em}.video-js .vjs-transient-button.vjs-left{left:1em}.video-js .vjs-transient-button.vjs-right{right:1em}.video-js .vjs-transient-button.vjs-top{top:1em}.video-js .vjs-transient-button.vjs-near-top{top:4em}.video-js .vjs-transient-button.vjs-bottom{bottom:4em}.video-js .vjs-transient-button:hover{background-color:rgba(50,50,50,.9)}@media print{.video-js>:not(.vjs-tech):not(.vjs-poster){visibility:hidden}}.vjs-resize-manager{position:absolute;top:0;left:0;width:100%;height:100%;border:none;z-index:-1000}.js-focus-visible .video-js :focus:not(.focus-visible){outline:0}.video-js :focus:not(:focus-visible){outline:0} \ No newline at end of file diff --git a/public/_player/videojs/dist/video.js b/public/_player/videojs/dist/video.js index 66b2402..b545ecd 100644 --- a/public/_player/videojs/dist/video.js +++ b/public/_player/videojs/dist/video.js @@ -1,6 +1,6 @@ /** * @license - * Video.js 7.19.2 + * Video.js 8.17.3 * Copyright Brightcove, Inc. * Available under Apache License Version 2.0 * @@ -14,9 +14,9 @@ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.videojs = factory()); -}(this, (function () { 'use strict'; +})(this, (function () { 'use strict'; - var version$5 = "7.19.2"; + var version$5 = "8.17.3"; /** * An Object that contains lifecycle hooks as keys which point to an array @@ -24,12 +24,13 @@ * * @private */ - var hooks_ = {}; + const hooks_ = {}; + /** * Get a list of hooks for a specific lifecycle * * @param {string} type - * the lifecyle to get hooks from + * the lifecycle to get hooks from * * @param {Function|Function[]} [fn] * Optionally add a hook (or hooks) to the lifecycle that your are getting. @@ -37,16 +38,14 @@ * @return {Array} * an array of hooks, or an empty array if there are none. */ - - var hooks = function hooks(type, fn) { + const hooks = function (type, fn) { hooks_[type] = hooks_[type] || []; - if (fn) { hooks_[type] = hooks_[type].concat(fn); } - return hooks_[type]; }; + /** * Add a function hook to a specific videojs lifecycle. * @@ -56,11 +55,10 @@ * @param {Function|Function[]} * The function or array of functions to attach. */ - - - var hook = function hook(type, fn) { + const hook = function (type, fn) { hooks(type, fn); }; + /** * Remove a hook from a specific videojs lifecycle. * @@ -73,19 +71,16 @@ * @return {boolean} * The function that was removed or undef */ - - - var removeHook = function removeHook(type, fn) { - var index = hooks(type).indexOf(fn); - + const removeHook = function (type, fn) { + const index = hooks(type).indexOf(fn); if (index <= -1) { return false; } - hooks_[type] = hooks_[type].slice(); hooks_[type].splice(index, 1); return true; }; + /** * Add a function hook that will only run once to a specific videojs lifecycle. * @@ -95,15 +90,12 @@ * @param {Function|Function[]} * The function or array of functions to attach. */ - - - var hookOnce = function hookOnce(type, fn) { - hooks(type, [].concat(fn).map(function (original) { - var wrapper = function wrapper() { + const hookOnce = function (type, fn) { + hooks(type, [].concat(fn).map(original => { + const wrapper = (...args) => { removeHook(type, wrapper); - return original.apply(void 0, arguments); + return original(...args); }; - return wrapper; })); }; @@ -111,7 +103,6 @@ /** * @file fullscreen-api.js * @module fullscreen-api - * @private */ /** @@ -121,31 +112,31 @@ * @see [Specification]{@link https://fullscreen.spec.whatwg.org} * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js} */ - var FullscreenApi = { + const FullscreenApi = { prefixed: true - }; // browser API methods + }; - var apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror', 'fullscreen'], // WebKit - ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror', '-webkit-full-screen'], // Mozilla - ['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror', '-moz-full-screen'], // Microsoft - ['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError', '-ms-fullscreen']]; - var specApi = apiMap[0]; - var browserApi; // determine the supported set of functions + // browser API methods + const apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror', 'fullscreen'], + // WebKit + ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror', '-webkit-full-screen']]; + const specApi = apiMap[0]; + let browserApi; - for (var i = 0; i < apiMap.length; i++) { + // determine the supported set of functions + for (let i = 0; i < apiMap.length; i++) { // check for exitFullscreen function if (apiMap[i][1] in document) { browserApi = apiMap[i]; break; } - } // map the browser API names to the spec API names - + } + // map the browser API names to the spec API names if (browserApi) { - for (var _i = 0; _i < browserApi.length; _i++) { - FullscreenApi[specApi[_i]] = browserApi[_i]; + for (let i = 0; i < browserApi.length; i++) { + FullscreenApi[specApi[i]] = browserApi[i]; } - FullscreenApi.prefixed = browserApi[0] !== specApi[0]; } @@ -153,71 +144,78 @@ * @file create-logger.js * @module create-logger */ + // This is the private tracking variable for the logging history. - var history = []; + let history = []; + /** * Log messages to the console and history based on the type of message * * @private - * @param {string} type + * @param {string} name * The name of the console method to use. * - * @param {Array} args + * @param {Object} log * The arguments to be passed to the matching console method. + * + * @param {string} [styles] + * styles for name */ + const LogByTypeFactory = (name, log, styles) => (type, level, args) => { + const lvl = log.levels[level]; + const lvlRegExp = new RegExp(`^(${lvl})$`); + let resultName = name; + if (type !== 'log') { + // Add the type to the front of the message when it's not "log". + args.unshift(type.toUpperCase() + ':'); + } + if (styles) { + resultName = `%c${name}`; + args.unshift(styles); + } - var LogByTypeFactory = function LogByTypeFactory(name, log) { - return function (type, level, args) { - var lvl = log.levels[level]; - var lvlRegExp = new RegExp("^(" + lvl + ")$"); + // Add console prefix after adding to history. + args.unshift(resultName + ':'); - if (type !== 'log') { - // Add the type to the front of the message when it's not "log". - args.unshift(type.toUpperCase() + ':'); - } // Add console prefix after adding to history. + // Add a clone of the args at this point to history. + if (history) { + history.push([].concat(args)); + // only store 1000 history entries + const splice = history.length - 1000; + history.splice(0, splice > 0 ? splice : 0); + } - args.unshift(name + ':'); // Add a clone of the args at this point to history. + // If there's no console then don't try to output messages, but they will + // still be stored in history. + if (!window.console) { + return; + } - if (history) { - history.push([].concat(args)); // only store 1000 history entries + // Was setting these once outside of this function, but containing them + // in the function makes it easier to test cases where console doesn't exist + // when the module is executed. + let fn = window.console[type]; + if (!fn && type === 'debug') { + // Certain browsers don't have support for console.debug. For those, we + // should default to the closest comparable log. + fn = window.console.info || window.console.log; + } - var splice = history.length - 1000; - history.splice(0, splice > 0 ? splice : 0); - } // If there's no console then don't try to output messages, but they will - // still be stored in history. - - - if (!window.console) { - return; - } // Was setting these once outside of this function, but containing them - // in the function makes it easier to test cases where console doesn't exist - // when the module is executed. - - - var fn = window.console[type]; - - if (!fn && type === 'debug') { - // Certain browsers don't have support for console.debug. For those, we - // should default to the closest comparable log. - fn = window.console.info || window.console.log; - } // Bail out if there's no console or if this type is not allowed by the - // current logging level. - - - if (!fn || !lvl || !lvlRegExp.test(type)) { - return; - } - - fn[Array.isArray(args) ? 'apply' : 'call'](window.console, args); - }; + // Bail out if there's no console or if this type is not allowed by the + // current logging level. + if (!fn || !lvl || !lvlRegExp.test(type)) { + return; + } + fn[Array.isArray(args) ? 'apply' : 'call'](window.console, args); }; - - function createLogger$1(name) { + function createLogger$1(name, delimiter = ':', styles = '') { // This is the private tracking variable for logging level. - var level = 'info'; // the curried logByType bound to the specific log and history + let level = 'info'; + + // the curried logByType bound to the specific log and history + let logByType; - var logByType; /** * Logs plain debug messages. Similar to `console.log`. * @@ -227,7 +225,7 @@ * * #### Arguments * ##### *args - * Mixed[] + * *[] * * Any combination of values that could be passed to `console.log()`. * @@ -236,37 +234,55 @@ * `undefined` * * @namespace - * @param {Mixed[]} args + * @param {...*} args * One or more messages or objects that should be logged. */ - - var log = function log() { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - + function log(...args) { logByType('log', level, args); - }; // This is the logByType helper that the logging methods below use + } + // This is the logByType helper that the logging methods below use + logByType = LogByTypeFactory(name, log, styles); - logByType = LogByTypeFactory(name, log); /** - * Create a new sublogger which chains the old name to the new name. + * Create a new subLogger which chains the old name to the new name. * - * For example, doing `videojs.log.createLogger('player')` and then using that logger will log the following: + * For example, doing `mylogger = videojs.log.createLogger('player')` and then using that logger will log the following: * ```js * mylogger('foo'); * // > VIDEOJS: player: foo * ``` * - * @param {string} name + * @param {string} subName * The name to add call the new logger + * @param {string} [subDelimiter] + * Optional delimiter + * @param {string} [subStyles] + * Optional styles * @return {Object} */ - - log.createLogger = function (subname) { - return createLogger$1(name + ': ' + subname); + log.createLogger = (subName, subDelimiter, subStyles) => { + const resultDelimiter = subDelimiter !== undefined ? subDelimiter : delimiter; + const resultStyles = subStyles !== undefined ? subStyles : styles; + const resultName = `${name} ${resultDelimiter} ${subName}`; + return createLogger$1(resultName, resultDelimiter, resultStyles); }; + + /** + * Create a new logger. + * + * @param {string} newName + * The name for the new logger + * @param {string} [newDelimiter] + * Optional delimiter + * @param {string} [newStyles] + * Optional styles + * @return {Object} + */ + log.createNewLogger = (newName, newDelimiter, newStyles) => { + return createLogger$1(newName, newDelimiter, newStyles); + }; + /** * Enumeration of available logging levels, where the keys are the level names * and the values are `|`-separated strings containing logging methods allowed @@ -286,8 +302,6 @@ * * @type {Object} */ - - log.levels = { all: 'debug|log|warn|error', off: '', @@ -297,30 +311,29 @@ error: 'error', DEFAULT: level }; + /** * Get or set the current logging level. * * If a string matching a key from {@link module:log.levels} is provided, acts * as a setter. * - * @param {string} [lvl] + * @param {'all'|'debug'|'info'|'warn'|'error'|'off'} [lvl] * Pass a valid level to set a new logging level. * * @return {string} * The current logging level. */ - - log.level = function (lvl) { + log.level = lvl => { if (typeof lvl === 'string') { if (!log.levels.hasOwnProperty(lvl)) { - throw new Error("\"" + lvl + "\" in not a valid log level"); + throw new Error(`"${lvl}" in not a valid log level`); } - level = lvl; } - return level; }; + /** * Returns an array containing everything that has been logged to the history. * @@ -330,11 +343,8 @@ * * @return {Array} */ + log.history = () => history ? [].concat(history) : []; - - log.history = function () { - return history ? [].concat(history) : []; - }; /** * Allows you to filter the history by the given logger name * @@ -344,93 +354,66 @@ * @return {Array} * The filtered list to return */ - - - log.history.filter = function (fname) { - return (history || []).filter(function (historyItem) { + log.history.filter = fname => { + return (history || []).filter(historyItem => { // if the first item in each historyItem includes `fname`, then it's a match - return new RegExp(".*" + fname + ".*").test(historyItem[0]); + return new RegExp(`.*${fname}.*`).test(historyItem[0]); }); }; + /** * Clears the internal history tracking, but does not prevent further history * tracking. */ - - - log.history.clear = function () { + log.history.clear = () => { if (history) { history.length = 0; } }; + /** * Disable history tracking if it is currently enabled. */ - - - log.history.disable = function () { + log.history.disable = () => { if (history !== null) { history.length = 0; history = null; } }; + /** * Enable history tracking if it is currently disabled. */ - - - log.history.enable = function () { + log.history.enable = () => { if (history === null) { history = []; } }; + /** * Logs error messages. Similar to `console.error`. * - * @param {Mixed[]} args + * @param {...*} args * One or more messages or objects that should be logged as an error */ + log.error = (...args) => logByType('error', level, args); - - log.error = function () { - for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return logByType('error', level, args); - }; /** * Logs warning messages. Similar to `console.warn`. * - * @param {Mixed[]} args + * @param {...*} args * One or more messages or objects that should be logged as a warning. */ + log.warn = (...args) => logByType('warn', level, args); - - log.warn = function () { - for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; - } - - return logByType('warn', level, args); - }; /** * Logs debug messages. Similar to `console.debug`, but may also act as a comparable * log if `console.debug` is not available * - * @param {Mixed[]} args + * @param {...*} args * One or more messages or objects that should be logged as debug. */ - - - log.debug = function () { - for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - args[_key4] = arguments[_key4]; - } - - return logByType('debug', level, args); - }; - + log.debug = (...args) => logByType('debug', level, args); return log; } @@ -438,36 +421,8 @@ * @file log.js * @module log */ - var log$1 = createLogger$1('VIDEOJS'); - var createLogger = log$1.createLogger; - - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; - } - - var _extends_1 = createCommonjsModule(function (module) { - function _extends() { - module.exports = _extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; - }; - - return _extends.apply(this, arguments); - } - - module.exports = _extends; - }); + const log$1 = createLogger$1('VIDEOJS'); + const createLogger = log$1.createLogger; /** * @file obj.js @@ -477,7 +432,7 @@ /** * @callback obj:EachCallback * - * @param {Mixed} value + * @param {*} value * The current key for the object that is being iterated over. * * @param {string} key @@ -487,19 +442,20 @@ /** * @callback obj:ReduceCallback * - * @param {Mixed} accum + * @param {*} accum * The value that is accumulating over the reduce loop. * - * @param {Mixed} value + * @param {*} value * The current key for the object that is being iterated over. * * @param {string} key * The current key-value for object that is being iterated over * - * @return {Mixed} + * @return {*} * The new accumulated value. */ - var toString$1 = Object.prototype.toString; + const toString$1 = Object.prototype.toString; + /** * Get the keys of an Object * @@ -512,10 +468,10 @@ * * @private */ - - var keys = function keys(object) { + const keys = function (object) { return isObject$1(object) ? Object.keys(object) : []; }; + /** * Array-like iteration for objects. * @@ -525,13 +481,10 @@ * @param {obj:EachCallback} fn * The callback function which is called for each key in the object. */ - - function each(object, fn) { - keys(object).forEach(function (key) { - return fn(object[key], key); - }); + keys(object).forEach(key => fn(object[key], key)); } + /** * Array-like reduce for objects. * @@ -543,50 +496,16 @@ * receives the accumulated value and the per-iteration value and key * as arguments. * - * @param {Mixed} [initial = 0] + * @param {*} [initial = 0] * Starting value * - * @return {Mixed} + * @return {*} * The final accumulated value. */ - - function reduce(object, fn, initial) { - if (initial === void 0) { - initial = 0; - } - - return keys(object).reduce(function (accum, key) { - return fn(accum, object[key], key); - }, initial); + function reduce(object, fn, initial = 0) { + return keys(object).reduce((accum, key) => fn(accum, object[key], key), initial); } - /** - * Object.assign-style object shallow merge/extend. - * - * @param {Object} target - * @param {Object} ...sources - * @return {Object} - */ - function assign(target) { - for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - sources[_key - 1] = arguments[_key]; - } - - if (Object.assign) { - return _extends_1.apply(void 0, [target].concat(sources)); - } - - sources.forEach(function (source) { - if (!source) { - return; - } - - each(source, function (value, key) { - target[key] = value; - }); - }); - return target; - } /** * Returns whether a value is an object of any kind - including DOM nodes, * arrays, regular expressions, etc. Not functions, though. @@ -597,10 +516,10 @@ * @param {Object} value * @return {boolean} */ - function isObject$1(value) { return !!value && typeof value === 'object'; } + /** * Returns whether an object appears to be a "plain" object - that is, a * direct instance of `Object`. @@ -608,215 +527,276 @@ * @param {Object} value * @return {boolean} */ - function isPlain(value) { return isObject$1(value) && toString$1.call(value) === '[object Object]' && value.constructor === Object; } /** - * @file computed-style.js - * @module computed-style + * Merge two objects recursively. + * + * Performs a deep merge like + * {@link https://lodash.com/docs/4.17.10#merge|lodash.merge}, but only merges + * plain objects (not arrays, elements, or anything else). + * + * Non-plain object values will be copied directly from the right-most + * argument. + * + * @param {Object[]} sources + * One or more objects to merge into a new object. + * + * @return {Object} + * A new object that is the merged result of all sources. */ + function merge$2(...sources) { + const result = {}; + sources.forEach(source => { + if (!source) { + return; + } + each(source, (value, key) => { + if (!isPlain(value)) { + result[key] = value; + return; + } + if (!isPlain(result[key])) { + result[key] = {}; + } + result[key] = merge$2(result[key], value); + }); + }); + return result; + } /** - * A safe getComputedStyle. + * Returns an array of values for a given object * - * This is needed because in Firefox, if the player is loaded in an iframe with - * `display:none`, then `getComputedStyle` returns `null`, so, we do a - * null-check to make sure that the player doesn't break in these cases. - * - * @function - * @param {Element} el - * The element you want the computed style of - * - * @param {string} prop - * The property name you want - * - * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + * @param {Object} source - target object + * @return {Array} - object values */ - function computedStyle(el, prop) { - if (!el || !prop) { - return ''; - } - - if (typeof window.getComputedStyle === 'function') { - var computedStyleValue; - - try { - computedStyleValue = window.getComputedStyle(el); - } catch (e) { - return ''; + function values$1(source = {}) { + const result = []; + for (const key in source) { + if (source.hasOwnProperty(key)) { + const value = source[key]; + result.push(value); } - - return computedStyleValue ? computedStyleValue.getPropertyValue(prop) || computedStyleValue[prop] : ''; } - - return ''; + return result; } + /** + * Object.defineProperty but "lazy", which means that the value is only set after + * it is retrieved the first time, rather than being set right away. + * + * @param {Object} obj the object to set the property on + * @param {string} key the key for the property to set + * @param {Function} getValue the function used to get the value when it is needed. + * @param {boolean} setter whether a setter should be allowed or not + */ + function defineLazyProperty(obj, key, getValue, setter = true) { + const set = value => Object.defineProperty(obj, key, { + value, + enumerable: true, + writable: true + }); + const options = { + configurable: true, + enumerable: true, + get() { + const value = getValue(); + set(value); + return value; + } + }; + if (setter) { + options.set = set; + } + return Object.defineProperty(obj, key, options); + } + + var Obj = /*#__PURE__*/Object.freeze({ + __proto__: null, + each: each, + reduce: reduce, + isObject: isObject$1, + isPlain: isPlain, + merge: merge$2, + values: values$1, + defineLazyProperty: defineLazyProperty + }); + /** * @file browser.js * @module browser */ - var USER_AGENT = window.navigator && window.navigator.userAgent || ''; - var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT); - var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null; + /** * Whether or not this device is an iPod. * * @static - * @const * @type {Boolean} */ + let IS_IPOD = false; - var IS_IPOD = /iPod/i.test(USER_AGENT); /** * The detected iOS version - or `null`. * * @static - * @const * @type {string|null} */ + let IOS_VERSION = null; - var IOS_VERSION = function () { - var match = USER_AGENT.match(/OS (\d+)_/i); - - if (match && match[1]) { - return match[1]; - } - - return null; - }(); /** * Whether or not this is an Android device. * * @static - * @const * @type {Boolean} */ + let IS_ANDROID = false; - var IS_ANDROID = /Android/i.test(USER_AGENT); /** - * The detected Android version - or `null`. + * The detected Android version - or `null` if not Android or indeterminable. * * @static - * @const * @type {number|string|null} */ + let ANDROID_VERSION; - var ANDROID_VERSION = function () { - // This matches Android Major.Minor.Patch versions - // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned - var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i); - - if (!match) { - return null; - } - - var major = match[1] && parseFloat(match[1]); - var minor = match[2] && parseFloat(match[2]); - - if (major && minor) { - return parseFloat(match[1] + '.' + match[2]); - } else if (major) { - return major; - } - - return null; - }(); - /** - * Whether or not this is a native Android browser. - * - * @static - * @const - * @type {Boolean} - */ - - var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537; /** * Whether or not this is Mozilla Firefox. * * @static - * @const * @type {Boolean} */ + let IS_FIREFOX = false; - var IS_FIREFOX = /Firefox/i.test(USER_AGENT); /** * Whether or not this is Microsoft Edge. * * @static - * @const * @type {Boolean} */ + let IS_EDGE = false; - var IS_EDGE = /Edg/i.test(USER_AGENT); /** - * Whether or not this is Google Chrome. + * Whether or not this is any Chromium Browser + * + * @static + * @type {Boolean} + */ + let IS_CHROMIUM = false; + + /** + * Whether or not this is any Chromium browser that is not Edge. * * This will also be `true` for Chrome on iOS, which will have different support * as it is actually Safari under the hood. * - * @static - * @const - * @type {Boolean} - */ - - var IS_CHROME = !IS_EDGE && (/Chrome/i.test(USER_AGENT) || /CriOS/i.test(USER_AGENT)); - /** - * The detected Google Chrome version - or `null`. + * Deprecated, as the behaviour to not match Edge was to prevent Legacy Edge's UA matching. + * IS_CHROMIUM should be used instead. + * "Chromium but not Edge" could be explicitly tested with IS_CHROMIUM && !IS_EDGE + * + * @static + * @deprecated + * @type {Boolean} + */ + let IS_CHROME = false; + + /** + * The detected Chromium version - or `null`. * * @static - * @const * @type {number|null} */ + let CHROMIUM_VERSION = null; - var CHROME_VERSION = function () { - var match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/); + /** + * The detected Google Chrome version - or `null`. + * This has always been the _Chromium_ version, i.e. would return on Chromium Edge. + * Deprecated, use CHROMIUM_VERSION instead. + * + * @static + * @deprecated + * @type {number|null} + */ + let CHROME_VERSION = null; - if (match && match[2]) { - return parseFloat(match[2]); - } + /** + * Whether or not this is a Chromecast receiver application. + * + * @static + * @type {Boolean} + */ + const IS_CHROMECAST_RECEIVER = Boolean(window.cast && window.cast.framework && window.cast.framework.CastReceiverContext); - return null; - }(); /** * The detected Internet Explorer version - or `null`. * * @static - * @const + * @deprecated * @type {number|null} */ + let IE_VERSION = null; - var IE_VERSION = function () { - var result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT); - var version = result && parseFloat(result[1]); - - if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) { - // IE 11 has a different user agent string than other IE versions - version = 11.0; - } - - return version; - }(); /** * Whether or not this is desktop Safari. * * @static - * @const * @type {Boolean} */ + let IS_SAFARI = false; - var IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE; /** * Whether or not this is a Windows machine. * * @static - * @const * @type {Boolean} */ + let IS_WINDOWS = false; + + /** + * Whether or not this device is an iPad. + * + * @static + * @type {Boolean} + */ + let IS_IPAD = false; + + /** + * Whether or not this device is an iPhone. + * + * @static + * @type {Boolean} + */ + // The Facebook app's UIWebView identifies as both an iPhone and iPad, so + // to identify iPhones, we need to exclude iPads. + // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/ + let IS_IPHONE = false; + + /** + * Whether or not this is a Tizen device. + * + * @static + * @type {Boolean} + */ + let IS_TIZEN = false; + + /** + * Whether or not this is a WebOS device. + * + * @static + * @type {Boolean} + */ + let IS_WEBOS = false; + + /** + * Whether or not this is a Smart TV (Tizen or WebOS) device. + * + * @static + * @type {Boolean} + */ + let IS_SMART_TV = false; - var IS_WINDOWS = /Windows/i.test(USER_AGENT); /** * Whether or not this device is touch-enabled. * @@ -824,29 +804,80 @@ * @const * @type {Boolean} */ + const TOUCH_ENABLED = Boolean(isReal() && ('ontouchstart' in window || window.navigator.maxTouchPoints || window.DocumentTouch && window.document instanceof window.DocumentTouch)); + const UAD = window.navigator && window.navigator.userAgentData; + if (UAD && UAD.platform && UAD.brands) { + // If userAgentData is present, use it instead of userAgent to avoid warnings + // Currently only implemented on Chromium + // userAgentData does not expose Android version, so ANDROID_VERSION remains `null` - var TOUCH_ENABLED = Boolean(isReal() && ('ontouchstart' in window || window.navigator.maxTouchPoints || window.DocumentTouch && window.document instanceof window.DocumentTouch)); - /** - * Whether or not this device is an iPad. - * - * @static - * @const - * @type {Boolean} - */ + IS_ANDROID = UAD.platform === 'Android'; + IS_EDGE = Boolean(UAD.brands.find(b => b.brand === 'Microsoft Edge')); + IS_CHROMIUM = Boolean(UAD.brands.find(b => b.brand === 'Chromium')); + IS_CHROME = !IS_EDGE && IS_CHROMIUM; + CHROMIUM_VERSION = CHROME_VERSION = (UAD.brands.find(b => b.brand === 'Chromium') || {}).version || null; + IS_WINDOWS = UAD.platform === 'Windows'; + } - var IS_IPAD = /iPad/i.test(USER_AGENT) || IS_SAFARI && TOUCH_ENABLED && !/iPhone/i.test(USER_AGENT); - /** - * Whether or not this device is an iPhone. - * - * @static - * @const - * @type {Boolean} - */ - // The Facebook app's UIWebView identifies as both an iPhone and iPad, so - // to identify iPhones, we need to exclude iPads. - // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/ + // If the browser is not Chromium, either userAgentData is not present which could be an old Chromium browser, + // or it's a browser that has added userAgentData since that we don't have tests for yet. In either case, + // the checks need to be made agiainst the regular userAgent string. + if (!IS_CHROMIUM) { + const USER_AGENT = window.navigator && window.navigator.userAgent || ''; + IS_IPOD = /iPod/i.test(USER_AGENT); + IOS_VERSION = function () { + const match = USER_AGENT.match(/OS (\d+)_/i); + if (match && match[1]) { + return match[1]; + } + return null; + }(); + IS_ANDROID = /Android/i.test(USER_AGENT); + ANDROID_VERSION = function () { + // This matches Android Major.Minor.Patch versions + // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned + const match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i); + if (!match) { + return null; + } + const major = match[1] && parseFloat(match[1]); + const minor = match[2] && parseFloat(match[2]); + if (major && minor) { + return parseFloat(match[1] + '.' + match[2]); + } else if (major) { + return major; + } + return null; + }(); + IS_FIREFOX = /Firefox/i.test(USER_AGENT); + IS_EDGE = /Edg/i.test(USER_AGENT); + IS_CHROMIUM = /Chrome/i.test(USER_AGENT) || /CriOS/i.test(USER_AGENT); + IS_CHROME = !IS_EDGE && IS_CHROMIUM; + CHROMIUM_VERSION = CHROME_VERSION = function () { + const match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/); + if (match && match[2]) { + return parseFloat(match[2]); + } + return null; + }(); + IE_VERSION = function () { + const result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT); + let version = result && parseFloat(result[1]); + if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) { + // IE 11 has a different user agent string than other IE versions + version = 11.0; + } + return version; + }(); + IS_TIZEN = /Tizen/i.test(USER_AGENT); + IS_WEBOS = /Web0S/i.test(USER_AGENT); + IS_SMART_TV = IS_TIZEN || IS_WEBOS; + IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE && !IS_SMART_TV; + IS_WINDOWS = /Windows/i.test(USER_AGENT); + IS_IPAD = /iPad/i.test(USER_AGENT) || IS_SAFARI && TOUCH_ENABLED && !/iPhone/i.test(USER_AGENT); + IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD; + } - var IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD; /** * Whether or not this is an iOS device. * @@ -854,8 +885,8 @@ * @const * @type {Boolean} */ + const IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD; - var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD; /** * Whether or not this is any flavor of Safari - including iOS. * @@ -863,26 +894,30 @@ * @const * @type {Boolean} */ - - var IS_ANY_SAFARI = (IS_SAFARI || IS_IOS) && !IS_CHROME; + const IS_ANY_SAFARI = (IS_SAFARI || IS_IOS) && !IS_CHROME; var browser = /*#__PURE__*/Object.freeze({ __proto__: null, - IS_IPOD: IS_IPOD, - IOS_VERSION: IOS_VERSION, - IS_ANDROID: IS_ANDROID, - ANDROID_VERSION: ANDROID_VERSION, - IS_NATIVE_ANDROID: IS_NATIVE_ANDROID, - IS_FIREFOX: IS_FIREFOX, - IS_EDGE: IS_EDGE, - IS_CHROME: IS_CHROME, - CHROME_VERSION: CHROME_VERSION, - IE_VERSION: IE_VERSION, - IS_SAFARI: IS_SAFARI, - IS_WINDOWS: IS_WINDOWS, + get IS_IPOD () { return IS_IPOD; }, + get IOS_VERSION () { return IOS_VERSION; }, + get IS_ANDROID () { return IS_ANDROID; }, + get ANDROID_VERSION () { return ANDROID_VERSION; }, + get IS_FIREFOX () { return IS_FIREFOX; }, + get IS_EDGE () { return IS_EDGE; }, + get IS_CHROMIUM () { return IS_CHROMIUM; }, + get IS_CHROME () { return IS_CHROME; }, + get CHROMIUM_VERSION () { return CHROMIUM_VERSION; }, + get CHROME_VERSION () { return CHROME_VERSION; }, + IS_CHROMECAST_RECEIVER: IS_CHROMECAST_RECEIVER, + get IE_VERSION () { return IE_VERSION; }, + get IS_SAFARI () { return IS_SAFARI; }, + get IS_WINDOWS () { return IS_WINDOWS; }, + get IS_IPAD () { return IS_IPAD; }, + get IS_IPHONE () { return IS_IPHONE; }, + get IS_TIZEN () { return IS_TIZEN; }, + get IS_WEBOS () { return IS_WEBOS; }, + get IS_SMART_TV () { return IS_SMART_TV; }, TOUCH_ENABLED: TOUCH_ENABLED, - IS_IPAD: IS_IPAD, - IS_IPHONE: IS_IPHONE, IS_IOS: IS_IOS, IS_ANY_SAFARI: IS_ANY_SAFARI }); @@ -891,6 +926,7 @@ * @file dom.js * @module dom */ + /** * Detect if a value is a string with any non-whitespace characters. * @@ -902,7 +938,6 @@ * Will be `true` if the string is non-blank, `false` otherwise. * */ - function isNonBlankString(str) { // we use str.trim as it will trim any whitespace characters // from the front or back of non-whitespace characters. aka @@ -911,6 +946,7 @@ // will have a length of 0, failing this check. return typeof str === 'string' && Boolean(str.trim()); } + /** * Throws an error if the passed string has whitespace. This is used by * class methods to be relatively consistent with the classList API. @@ -922,55 +958,37 @@ * @throws {Error} * Throws an error if there is whitespace in the string. */ - - function throwIfWhitespace(str) { // str.indexOf instead of regex because str.indexOf is faster performance wise. if (str.indexOf(' ') >= 0) { throw new Error('class has illegal whitespace characters'); } } - /** - * Produce a regular expression for matching a className within an elements className. - * - * @private - * @param {string} className - * The className to generate the RegExp for. - * - * @return {RegExp} - * The RegExp that will check for a specific `className` in an elements - * className. - */ - - function classRegExp(className) { - return new RegExp('(^|\\s)' + className + '($|\\s)'); - } /** * Whether the current DOM interface appears to be real (i.e. not simulated). * * @return {boolean} * Will be `true` if the DOM appears to be real, `false` otherwise. */ - - function isReal() { // Both document and window will never be undefined thanks to `global`. return document === window.document; } + /** * Determines, via duck typing, whether or not a value is a DOM element. * - * @param {Mixed} value + * @param {*} value * The value to check. * * @return {boolean} * Will be `true` if the value is a DOM element, `false` otherwise. */ - function isEl(value) { return isObject$1(value) && value.nodeType === 1; } + /** * Determines if the current DOM is embedded in an iframe. * @@ -978,7 +996,6 @@ * Will be `true` if the DOM is embedded in an iframe, `false` * otherwise. */ - function isInFrame() { // We need a try/catch here because Safari will throw errors when attempting // to get either `parent` or `self` @@ -988,6 +1005,7 @@ return true; } } + /** * Creates functions to query the DOM using a given method. * @@ -998,21 +1016,19 @@ * @return {Function} * The query method */ - function createQuerier(method) { return function (selector, context) { if (!isNonBlankString(selector)) { return document[method](null); } - if (isNonBlankString(context)) { context = document.querySelector(context); } - - var ctx = isEl(context) ? context : document; + const ctx = isEl(context) ? context : document; return ctx[method] && ctx[method](selector); }; } + /** * Creates an element and applies properties, attributes, and inserts content. * @@ -1025,38 +1041,20 @@ * @param {Object} [attributes={}] * Element attributes to be applied. * - * @param {module:dom~ContentDescriptor} content + * @param {ContentDescriptor} [content] * A content descriptor object. * * @return {Element} * The element that was created. */ - - - function createEl(tagName, properties, attributes, content) { - if (tagName === void 0) { - tagName = 'div'; - } - - if (properties === void 0) { - properties = {}; - } - - if (attributes === void 0) { - attributes = {}; - } - - var el = document.createElement(tagName); + function createEl(tagName = 'div', properties = {}, attributes = {}, content) { + const el = document.createElement(tagName); Object.getOwnPropertyNames(properties).forEach(function (propName) { - var val = properties[propName]; // See #2176 - // We originally were accepting both properties and attributes in the - // same object, but that doesn't work so well. + const val = properties[propName]; - if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') { - log$1.warn('Setting attributes in the second argument of createEl()\n' + 'has been deprecated. Use the third argument instead.\n' + ("createEl(type, properties, attributes). Attempting to set " + propName + " to " + val + ".")); - el.setAttribute(propName, val); // Handle textContent since it's not supported everywhere and we have a - // method for it. - } else if (propName === 'textContent') { + // Handle textContent since it's not supported everywhere and we have a + // method for it. + if (propName === 'textContent') { textContent(el, val); } else if (el[propName] !== val || propName === 'tabIndex') { el[propName] = val; @@ -1065,17 +1063,16 @@ Object.getOwnPropertyNames(attributes).forEach(function (attrName) { el.setAttribute(attrName, attributes[attrName]); }); - if (content) { appendContent(el, content); } - return el; } + /** * Injects text into an element, replacing any existing contents entirely. * - * @param {Element} el + * @param {HTMLElement} el * The element to add text content into * * @param {string} text @@ -1084,16 +1081,15 @@ * @return {Element} * The element with added text content. */ - function textContent(el, text) { if (typeof el.textContent === 'undefined') { el.innerText = text; } else { el.textContent = text; } - return el; } + /** * Insert an element as the first child node of another * @@ -1103,7 +1099,6 @@ * @param {Element} parent * Element to insert child into */ - function prependTo(child, parent) { if (parent.firstChild) { parent.insertBefore(child, parent.firstChild); @@ -1111,6 +1106,7 @@ parent.appendChild(child); } } + /** * Check if an element has a class name. * @@ -1126,70 +1122,50 @@ * @throws {Error} * Throws an error if `classToCheck` has white space. */ - function hasClass(element, classToCheck) { throwIfWhitespace(classToCheck); - - if (element.classList) { - return element.classList.contains(classToCheck); - } - - return classRegExp(classToCheck).test(element.className); + return element.classList.contains(classToCheck); } + /** * Add a class name to an element. * * @param {Element} element * Element to add class name to. * - * @param {string} classToAdd - * Class name to add. + * @param {...string} classesToAdd + * One or more class name to add. * * @return {Element} * The DOM element with the added class name. */ - - function addClass(element, classToAdd) { - if (element.classList) { - element.classList.add(classToAdd); // Don't need to `throwIfWhitespace` here because `hasElClass` will do it - // in the case of classList not being supported. - } else if (!hasClass(element, classToAdd)) { - element.className = (element.className + ' ' + classToAdd).trim(); - } - + function addClass(element, ...classesToAdd) { + element.classList.add(...classesToAdd.reduce((prev, current) => prev.concat(current.split(/\s+/)), [])); return element; } + /** * Remove a class name from an element. * * @param {Element} element * Element to remove a class name from. * - * @param {string} classToRemove - * Class name to remove + * @param {...string} classesToRemove + * One or more class name to remove. * * @return {Element} * The DOM element with class name removed. */ - - function removeClass(element, classToRemove) { + function removeClass(element, ...classesToRemove) { // Protect in case the player gets disposed if (!element) { log$1.warn("removeClass was called with an element that doesn't exist"); return null; } - - if (element.classList) { - element.classList.remove(classToRemove); - } else { - throwIfWhitespace(classToRemove); - element.className = element.className.split(/\s+/).filter(function (c) { - return c !== classToRemove; - }).join(' '); - } - + element.classList.remove(...classesToRemove.reduce((prev, current) => prev.concat(current.split(/\s+/)), [])); return element; } + /** * The callback definition for toggleClass. * @@ -1222,35 +1198,17 @@ * @return {Element} * The element with a class that has been toggled. */ - function toggleClass(element, classToToggle, predicate) { - // This CANNOT use `classList` internally because IE11 does not support the - // second parameter to the `classList.toggle()` method! Which is fine because - // `classList` will be used by the add/remove functions. - var has = hasClass(element, classToToggle); - if (typeof predicate === 'function') { predicate = predicate(element, classToToggle); } - if (typeof predicate !== 'boolean') { - predicate = !has; - } // If the necessary class operation matches the current state of the - // element, no action is required. - - - if (predicate === has) { - return; + predicate = undefined; } - - if (predicate) { - addClass(element, classToToggle); - } else { - removeClass(element, classToToggle); - } - + classToToggle.split(/\s+/).forEach(className => element.classList.toggle(className, predicate)); return element; } + /** * Apply attributes to an HTML element. * @@ -1260,11 +1218,9 @@ * @param {Object} [attributes] * Attributes to be applied. */ - function setAttributes(el, attributes) { Object.getOwnPropertyNames(attributes).forEach(function (attrName) { - var attrValue = attributes[attrName]; - + const attrValue = attributes[attrName]; if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) { el.removeAttribute(attrName); } else { @@ -1272,6 +1228,7 @@ } }); } + /** * Get an element's attribute values, as defined on the HTML tag. * @@ -1285,35 +1242,34 @@ * All attributes of the element. Boolean attributes will be `true` or * `false`, others will be strings. */ - function getAttributes(tag) { - var obj = {}; // known boolean attributes + const obj = {}; + + // known boolean attributes // we can check for matching boolean properties, but not all browsers // and not all tags know about these attributes, so, we still want to check them manually - - var knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ','; - + const knownBooleans = ['autoplay', 'controls', 'playsinline', 'loop', 'muted', 'default', 'defaultMuted']; if (tag && tag.attributes && tag.attributes.length > 0) { - var attrs = tag.attributes; + const attrs = tag.attributes; + for (let i = attrs.length - 1; i >= 0; i--) { + const attrName = attrs[i].name; + /** @type {boolean|string} */ + let attrVal = attrs[i].value; - for (var i = attrs.length - 1; i >= 0; i--) { - var attrName = attrs[i].name; - var attrVal = attrs[i].value; // check for known booleans + // check for known booleans // the matching element property will return a value for typeof - - if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) { + if (knownBooleans.includes(attrName)) { // the value of an included boolean attribute is typically an empty // string ('') which would equal false if we just check for a false value. // we also don't want support bad code like autoplay='false' attrVal = attrVal !== null ? true : false; } - obj[attrName] = attrVal; } } - return obj; } + /** * Get the value of an element's attribute. * @@ -1326,10 +1282,10 @@ * @return {string} * The value of the attribute. */ - function getAttribute(el, attribute) { return el.getAttribute(attribute); } + /** * Set the value of an element's attribute. * @@ -1342,10 +1298,10 @@ * @param {string} value * Value to set the attribute to. */ - function setAttribute(el, attribute, value) { el.setAttribute(attribute, value); } + /** * Remove an element's attribute. * @@ -1355,30 +1311,29 @@ * @param {string} attribute * Attribute to remove. */ - function removeAttribute(el, attribute) { el.removeAttribute(attribute); } + /** * Attempt to block the ability to select text. */ - function blockTextSelection() { document.body.focus(); - document.onselectstart = function () { return false; }; } + /** * Turn off text selection blocking. */ - function unblockTextSelection() { document.onselectstart = function () { return true; }; } + /** * Identical to the native `getBoundingClientRect` function, but ensures that * the method is supported at all (it is in all browsers we claim to support) @@ -1398,28 +1353,25 @@ * @return {Object|undefined} * Always returns a plain object - or `undefined` if it cannot. */ - function getBoundingClientRect(el) { if (el && el.getBoundingClientRect && el.parentNode) { - var rect = el.getBoundingClientRect(); - var result = {}; - ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(function (k) { + const rect = el.getBoundingClientRect(); + const result = {}; + ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(k => { if (rect[k] !== undefined) { result[k] = rect[k]; } }); - if (!result.height) { result.height = parseFloat(computedStyle(el, 'height')); } - if (!result.width) { result.width = parseFloat(computedStyle(el, 'width')); } - return result; } } + /** * Represents the position of a DOM element on the page. * @@ -1445,7 +1397,6 @@ * @return {module:dom~Position} * The position of the element that was passed in. */ - function findPosition(el) { if (!el || el && !el.offsetParent) { return { @@ -1455,25 +1406,23 @@ height: 0 }; } - - var width = el.offsetWidth; - var height = el.offsetHeight; - var left = 0; - var top = 0; - + const width = el.offsetWidth; + const height = el.offsetHeight; + let left = 0; + let top = 0; while (el.offsetParent && el !== document[FullscreenApi.fullscreenElement]) { left += el.offsetLeft; top += el.offsetTop; el = el.offsetParent; } - return { - left: left, - top: top, - width: width, - height: height + left, + top, + width, + height }; } + /** * Represents x and y coordinates for a DOM element or mouse pointer. * @@ -1494,76 +1443,73 @@ * @param {Element} el * Element on which to get the pointer position on. * - * @param {EventTarget~Event} event + * @param {Event} event * Event object. * * @return {module:dom~Coordinates} * A coordinates object corresponding to the mouse position. * */ - function getPointerPosition(el, event) { - var translated = { + const translated = { x: 0, y: 0 }; - if (IS_IOS) { - var item = el; - + let item = el; while (item && item.nodeName.toLowerCase() !== 'html') { - var transform = computedStyle(item, 'transform'); - + const transform = computedStyle(item, 'transform'); if (/^matrix/.test(transform)) { - var values = transform.slice(7, -1).split(/,\s/).map(Number); + const values = transform.slice(7, -1).split(/,\s/).map(Number); translated.x += values[4]; translated.y += values[5]; } else if (/^matrix3d/.test(transform)) { - var _values = transform.slice(9, -1).split(/,\s/).map(Number); - - translated.x += _values[12]; - translated.y += _values[13]; + const values = transform.slice(9, -1).split(/,\s/).map(Number); + translated.x += values[12]; + translated.y += values[13]; } - - item = item.parentNode; + if (item.assignedSlot && item.assignedSlot.parentElement && window.WebKitCSSMatrix) { + const transformValue = window.getComputedStyle(item.assignedSlot.parentElement).transform; + const matrix = new window.WebKitCSSMatrix(transformValue); + translated.x += matrix.m41; + translated.y += matrix.m42; + } + item = item.parentNode || item.host; } } - - var position = {}; - var boxTarget = findPosition(event.target); - var box = findPosition(el); - var boxW = box.width; - var boxH = box.height; - var offsetY = event.offsetY - (box.top - boxTarget.top); - var offsetX = event.offsetX - (box.left - boxTarget.left); - + const position = {}; + const boxTarget = findPosition(event.target); + const box = findPosition(el); + const boxW = box.width; + const boxH = box.height; + let offsetY = event.offsetY - (box.top - boxTarget.top); + let offsetX = event.offsetX - (box.left - boxTarget.left); if (event.changedTouches) { offsetX = event.changedTouches[0].pageX - box.left; offsetY = event.changedTouches[0].pageY + box.top; - if (IS_IOS) { offsetX -= translated.x; offsetY -= translated.y; } } - position.y = 1 - Math.max(0, Math.min(1, offsetY / boxH)); position.x = Math.max(0, Math.min(1, offsetX / boxW)); return position; } + /** * Determines, via duck typing, whether or not a value is a text node. * - * @param {Mixed} value + * @param {*} value * Check if this value is a text node. * * @return {boolean} * Will be `true` if the value is a text node, `false` otherwise. */ - - function isTextNode(value) { + function isTextNode$1(value) { return isObject$1(value) && value.nodeType === 3; } + /** * Empties the contents of an element. * @@ -1573,14 +1519,13 @@ * @return {Element} * The element with no children */ - function emptyEl(el) { while (el.firstChild) { el.removeChild(el.firstChild); } - return el; } + /** * This is a mixed value that describes content to be injected into the DOM * via some method. It can be of the following types: @@ -1589,11 +1534,11 @@ * -----------|------------- * `string` | The value will be normalized into a text node. * `Element` | The value will be accepted as-is. - * `TextNode` | The value will be accepted as-is. + * `Text` | A TextNode. The value will be accepted as-is. * `Array` | A one-dimensional array of strings, elements, text nodes, or functions. These functions should return a string, element, or text node (any other return value, like an array, will be ignored). * `Function` | A function, which is expected to return a string, element, text node, or array - any of the other possible values described above. This means that a content descriptor could be a function that returns an array of functions, but those second-level functions must return strings, elements, or text nodes. * - * @typedef {string|Element|TextNode|Array|Function} module:dom~ContentDescriptor + * @typedef {string|Element|Text|Array|Function} ContentDescriptor */ /** @@ -1606,60 +1551,54 @@ * The content for an element can be passed in multiple types and * combinations, whose behavior is as follows: * - * @param {module:dom~ContentDescriptor} content + * @param {ContentDescriptor} content * A content descriptor value. * * @return {Array} * All of the content that was passed in, normalized to an array of * elements or text nodes. */ - function normalizeContent(content) { // First, invoke content if it is a function. If it produces an array, // that needs to happen before normalization. if (typeof content === 'function') { content = content(); - } // Next up, normalize to an array, so one or many items can be normalized, + } + + // Next up, normalize to an array, so one or many items can be normalized, // filtered, and returned. - - - return (Array.isArray(content) ? content : [content]).map(function (value) { + return (Array.isArray(content) ? content : [content]).map(value => { // First, invoke value if it is a function to produce a new value, // which will be subsequently normalized to a Node of some kind. if (typeof value === 'function') { value = value(); } - - if (isEl(value) || isTextNode(value)) { + if (isEl(value) || isTextNode$1(value)) { return value; } - if (typeof value === 'string' && /\S/.test(value)) { return document.createTextNode(value); } - }).filter(function (value) { - return value; - }); + }).filter(value => value); } + /** * Normalizes and appends content to an element. * * @param {Element} el * Element to append normalized content to. * - * @param {module:dom~ContentDescriptor} content + * @param {ContentDescriptor} content * A content descriptor value. * * @return {Element} * The element with appended normalized content. */ - function appendContent(el, content) { - normalizeContent(content).forEach(function (node) { - return el.appendChild(node); - }); + normalizeContent(content).forEach(node => el.appendChild(node)); return el; } + /** * Normalizes and inserts content into an element; this is identical to * `appendContent()`, except it empties the element first. @@ -1667,30 +1606,30 @@ * @param {Element} el * Element to insert normalized content into. * - * @param {module:dom~ContentDescriptor} content + * @param {ContentDescriptor} content * A content descriptor value. * * @return {Element} * The element with inserted normalized content. */ - function insertContent(el, content) { return appendContent(emptyEl(el), content); } + /** * Check if an event was a single left click. * - * @param {EventTarget~Event} event + * @param {MouseEvent} event * Event object. * * @return {boolean} * Will be `true` if a single left click, `false` otherwise. */ - function isSingleLeftClick(event) { // Note: if you create something draggable, be sure to // call it on both `mousedown` and `mousemove` event, // otherwise `mousedown` should be enough for a button + if (event.button === undefined && event.buttons === undefined) { // Why do we need `buttons` ? // Because, middle mouse sometimes have this: @@ -1699,34 +1638,41 @@ // HOLD middlemouse then left click, that would be // e.button === 0, e.buttons === 5 // just `button` is not gonna work + // Alright, then what this block does ? // this is for chrome `simulate mobile devices` // I want to support this as well + return true; } - if (event.button === 0 && event.buttons === undefined) { // Touch screen, sometimes on some specific device, `buttons` // doesn't have anything (safari on ios, blackberry...) + return true; - } // `mouseup` event on a single left click has + } + + // `mouseup` event on a single left click has // `button` and `buttons` equal to 0 - - if (event.type === 'mouseup' && event.button === 0 && event.buttons === 0) { return true; } + // MacOS Sonoma trackpad when "tap to click enabled" + if (event.type === 'mousedown' && event.button === 0 && event.buttons === 0) { + return true; + } if (event.button !== 0 || event.buttons !== 1) { // This is the reason we have those if else block above // if any special case we can catch and let it slide // we do it above, when get to here, this definitely // is-not-left-click + return false; } - return true; } + /** * Finds a single DOM element matching `selector` within the optional * `context` of another DOM element (defaulting to `document`). @@ -1743,8 +1689,8 @@ * @return {Element|null} * The element that was found or null. */ + const $ = createQuerier('querySelector'); - var $ = createQuerier('querySelector'); /** * Finds a all DOM elements matching `selector` within the optional * `context` of another DOM element (defaulting to `document`). @@ -1763,8 +1709,64 @@ * were found. * */ + const $$ = createQuerier('querySelectorAll'); - var $$ = createQuerier('querySelectorAll'); + /** + * A safe getComputedStyle. + * + * This is needed because in Firefox, if the player is loaded in an iframe with + * `display:none`, then `getComputedStyle` returns `null`, so, we do a + * null-check to make sure that the player doesn't break in these cases. + * + * @param {Element} el + * The element you want the computed style of + * + * @param {string} prop + * The property name you want + * + * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + */ + function computedStyle(el, prop) { + if (!el || !prop) { + return ''; + } + if (typeof window.getComputedStyle === 'function') { + let computedStyleValue; + try { + computedStyleValue = window.getComputedStyle(el); + } catch (e) { + return ''; + } + return computedStyleValue ? computedStyleValue.getPropertyValue(prop) || computedStyleValue[prop] : ''; + } + return ''; + } + + /** + * Copy document style sheets to another window. + * + * @param {Window} win + * The window element you want to copy the document style sheets to. + * + */ + function copyStyleSheetsToWindow(win) { + [...document.styleSheets].forEach(styleSheet => { + try { + const cssRules = [...styleSheet.cssRules].map(rule => rule.cssText).join(''); + const style = document.createElement('style'); + style.textContent = cssRules; + win.document.head.appendChild(style); + } catch (e) { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.type = styleSheet.type; + // For older Safari this has to be the string; on other browsers setting the MediaList works + link.media = styleSheet.media.mediaText; + link.href = styleSheet.href; + win.document.head.appendChild(link); + } + }); + } var Dom = /*#__PURE__*/Object.freeze({ __proto__: null, @@ -1788,14 +1790,16 @@ getBoundingClientRect: getBoundingClientRect, findPosition: findPosition, getPointerPosition: getPointerPosition, - isTextNode: isTextNode, + isTextNode: isTextNode$1, emptyEl: emptyEl, normalizeContent: normalizeContent, appendContent: appendContent, insertContent: insertContent, isSingleLeftClick: isSingleLeftClick, $: $, - $$: $$ + $$: $$, + computedStyle: computedStyle, + copyStyleSheetsToWindow: copyStyleSheetsToWindow }); /** @@ -1804,48 +1808,53 @@ * * @module setup */ - var _windowLoaded = false; - var videojs$1; + let _windowLoaded = false; + let videojs$1; + /** * Set up any tags that have a data-setup `attribute` when the player is started. */ - - var autoSetup = function autoSetup() { + const autoSetup = function () { if (videojs$1.options.autoSetup === false) { return; } + const vids = Array.prototype.slice.call(document.getElementsByTagName('video')); + const audios = Array.prototype.slice.call(document.getElementsByTagName('audio')); + const divs = Array.prototype.slice.call(document.getElementsByTagName('video-js')); + const mediaEls = vids.concat(audios, divs); - var vids = Array.prototype.slice.call(document.getElementsByTagName('video')); - var audios = Array.prototype.slice.call(document.getElementsByTagName('audio')); - var divs = Array.prototype.slice.call(document.getElementsByTagName('video-js')); - var mediaEls = vids.concat(audios, divs); // Check if any media elements exist - + // Check if any media elements exist if (mediaEls && mediaEls.length > 0) { - for (var i = 0, e = mediaEls.length; i < e; i++) { - var mediaEl = mediaEls[i]; // Check if element exists, has getAttribute func. + for (let i = 0, e = mediaEls.length; i < e; i++) { + const mediaEl = mediaEls[i]; + // Check if element exists, has getAttribute func. if (mediaEl && mediaEl.getAttribute) { // Make sure this player hasn't already been set up. if (mediaEl.player === undefined) { - var options = mediaEl.getAttribute('data-setup'); // Check if data-setup attr exists. - // We only auto-setup if they've added the data-setup attr. + const options = mediaEl.getAttribute('data-setup'); + // Check if data-setup attr exists. + // We only auto-setup if they've added the data-setup attr. if (options !== null) { // Create new video.js instance. videojs$1(mediaEl); } - } // If getAttribute isn't defined, we need to wait for the DOM. + } + // If getAttribute isn't defined, we need to wait for the DOM. } else { autoSetupTimeout(1); break; } - } // No videos were found, so keep looping unless page is finished loading. + } + // No videos were found, so keep looping unless page is finished loading. } else if (!_windowLoaded) { autoSetupTimeout(1); } }; + /** * Wait until the page is loaded before running autoSetup. This will be called in * autoSetup if `hasLoaded` returns false. @@ -1856,32 +1865,26 @@ * @param {module:videojs} [vjs] * The videojs library function */ - - function autoSetupTimeout(wait, vjs) { // Protect against breakage in non-browser environments if (!isReal()) { return; } - if (vjs) { videojs$1 = vjs; } - window.setTimeout(autoSetup, wait); } + /** * Used to set the internal tracking of window loaded state to true. * * @private */ - - function setWindowLoaded() { _windowLoaded = true; window.removeEventListener('load', setWindowLoaded); } - if (isReal()) { if (document.readyState === 'complete') { setWindowLoaded(); @@ -1904,7 +1907,7 @@ */ /** - * Create a DOM syle element given a className for it. + * Create a DOM style element given a className for it. * * @param {string} className * The className to add to the created style element. @@ -1912,11 +1915,12 @@ * @return {Element} * The element that was created. */ - var createStyleElement = function createStyleElement(className) { - var style = document.createElement('style'); + const createStyleElement = function (className) { + const style = document.createElement('style'); style.className = className; return style; }; + /** * Add text to a DOM element. * @@ -1926,8 +1930,7 @@ * @param {string} content * The text to add to the element. */ - - var setTextContent = function setTextContent(el, content) { + const setTextContent = function (el, content) { if (el.styleSheet) { el.styleSheet.cssText = content; } else { @@ -1935,91 +1938,11 @@ } }; - /** - * @file guid.js - * @module guid - */ - // Default value for GUIDs. This allows us to reset the GUID counter in tests. - // - // The initial GUID is 3 because some users have come to rely on the first - // default player ID ending up as `vjs_video_3`. - // - // See: https://github.com/videojs/video.js/pull/6216 - var _initialGuid = 3; - /** - * Unique ID for an element or function - * - * @type {Number} - */ - - var _guid = _initialGuid; - /** - * Get a unique auto-incrementing ID by number that has not been returned before. - * - * @return {number} - * A new unique ID. - */ - - function newGUID() { - return _guid++; - } - /** * @file dom-data.js * @module dom-data */ - var FakeWeakMap; - if (!window.WeakMap) { - FakeWeakMap = /*#__PURE__*/function () { - function FakeWeakMap() { - this.vdata = 'vdata' + Math.floor(window.performance && window.performance.now() || Date.now()); - this.data = {}; - } - - var _proto = FakeWeakMap.prototype; - - _proto.set = function set(key, value) { - var access = key[this.vdata] || newGUID(); - - if (!key[this.vdata]) { - key[this.vdata] = access; - } - - this.data[access] = value; - return this; - }; - - _proto.get = function get(key) { - var access = key[this.vdata]; // we have data, return it - - if (access) { - return this.data[access]; - } // we don't have data, return nothing. - // return undefined explicitly as that's the contract for this method - - - log$1('We have no data for this element', key); - return undefined; - }; - - _proto.has = function has(key) { - var access = key[this.vdata]; - return access in this.data; - }; - - _proto["delete"] = function _delete(key) { - var access = key[this.vdata]; - - if (access) { - delete this.data[access]; - delete key[this.vdata]; - } - }; - - return FakeWeakMap; - }(); - } /** * Element Data Store. * @@ -2030,9 +1953,37 @@ * @type {Object} * @private */ + var DomData = new WeakMap(); + /** + * @file guid.js + * @module guid + */ - var DomData = window.WeakMap ? new WeakMap() : new FakeWeakMap(); + // Default value for GUIDs. This allows us to reset the GUID counter in tests. + // + // The initial GUID is 3 because some users have come to rely on the first + // default player ID ending up as `vjs_video_3`. + // + // See: https://github.com/videojs/video.js/pull/6216 + const _initialGuid = 3; + + /** + * Unique ID for an element or function + * + * @type {Number} + */ + let _guid = _initialGuid; + + /** + * Get a unique auto-incrementing ID by number that has not been returned before. + * + * @return {number} + * A new unique ID. + */ + function newGUID() { + return _guid++; + } /** * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/) @@ -2043,6 +1994,7 @@ * @file events.js * @module events */ + /** * Clean up the listener cache and dispatchers * @@ -2052,38 +2004,39 @@ * @param {string} type * Type of event to clean up */ - function _cleanUpEvents(elem, type) { if (!DomData.has(elem)) { return; } + const data = DomData.get(elem); - var data = DomData.get(elem); // Remove the events of a particular type if there are none left - + // Remove the events of a particular type if there are none left if (data.handlers[type].length === 0) { - delete data.handlers[type]; // data.handlers[type] = null; + delete data.handlers[type]; + // data.handlers[type] = null; // Setting to null was causing an error with data.handlers - // Remove the meta-handler from the element + // Remove the meta-handler from the element if (elem.removeEventListener) { elem.removeEventListener(type, data.dispatcher, false); } else if (elem.detachEvent) { elem.detachEvent('on' + type, data.dispatcher); } - } // Remove the events object if there are no types left - + } + // Remove the events object if there are no types left if (Object.getOwnPropertyNames(data.handlers).length <= 0) { delete data.handlers; delete data.dispatcher; delete data.disabled; - } // Finally remove the element data if there is no data left - + } + // Finally remove the element data if there is no data left if (Object.getOwnPropertyNames(data).length === 0) { - DomData["delete"](elem); + DomData.delete(elem); } } + /** * Loops through an array of event types and calls the requested method for each type. * @@ -2093,20 +2046,19 @@ * @param {Element|Object} elem * Element or object to bind listeners to * - * @param {string} type + * @param {string[]} types * Type of event to bind to. * - * @param {EventTarget~EventListener} callback + * @param {Function} callback * Event listener. */ - - function _handleMultipleEvents(fn, elem, types, callback) { types.forEach(function (type) { // Call the event method for each one of the types fn(elem, type, callback); }); } + /** * Fix a native event to have standard property values * @@ -2116,148 +2068,141 @@ * @return {Object} * Fixed event object. */ - - function fixEvent(event) { if (event.fixed_) { return event; } - function returnTrue() { return true; } - function returnFalse() { return false; - } // Test if fixing up is needed + } + + // Test if fixing up is needed // Used to check if !event.stopPropagation instead of isPropagationStopped // But native events return true for stopPropagation, but don't have // other expected methods like isPropagationStopped. Seems to be a problem // with the Javascript Ninja code. So we're just overriding all events now. - - if (!event || !event.isPropagationStopped || !event.isImmediatePropagationStopped) { - var old = event || window.event; - event = {}; // Clone the old object so that we can modify the values event = {}; + const old = event || window.event; + event = {}; + // Clone the old object so that we can modify the values event = {}; // IE8 Doesn't like when you mess with native event properties // Firefox returns false for event.hasOwnProperty('type') and other props // which makes copying more difficult. - // TODO: Probably best to create a whitelist of event props - for (var key in old) { + // TODO: Probably best to create an allowlist of event props + const deprecatedProps = ['layerX', 'layerY', 'keyLocation', 'path', 'webkitMovementX', 'webkitMovementY', 'mozPressure', 'mozInputSource']; + for (const key in old) { // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation // and webkitMovementX/Y - if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') { + // Lighthouse complains if Event.path is copied + if (!deprecatedProps.includes(key)) { // Chrome 32+ warns if you try to copy deprecated returnValue, but // we still want to if preventDefault isn't supported (IE8). if (!(key === 'returnValue' && old.preventDefault)) { event[key] = old[key]; } } - } // The event occurred on this element - + } + // The event occurred on this element if (!event.target) { event.target = event.srcElement || document; - } // Handle which other element the event is related to - + } + // Handle which other element the event is related to if (!event.relatedTarget) { event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } // Stop the default browser action - + } + // Stop the default browser action event.preventDefault = function () { if (old.preventDefault) { old.preventDefault(); } - event.returnValue = false; old.returnValue = false; event.defaultPrevented = true; }; + event.defaultPrevented = false; - event.defaultPrevented = false; // Stop the event from bubbling - + // Stop the event from bubbling event.stopPropagation = function () { if (old.stopPropagation) { old.stopPropagation(); } - event.cancelBubble = true; old.cancelBubble = true; event.isPropagationStopped = returnTrue; }; + event.isPropagationStopped = returnFalse; - event.isPropagationStopped = returnFalse; // Stop the event from bubbling and executing other handlers - + // Stop the event from bubbling and executing other handlers event.stopImmediatePropagation = function () { if (old.stopImmediatePropagation) { old.stopImmediatePropagation(); } - event.isImmediatePropagationStopped = returnTrue; event.stopPropagation(); }; + event.isImmediatePropagationStopped = returnFalse; - event.isImmediatePropagationStopped = returnFalse; // Handle mouse position - + // Handle mouse position if (event.clientX !== null && event.clientX !== undefined) { - var doc = document.documentElement; - var body = document.body; + const doc = document.documentElement; + const body = document.body; event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } // Handle key presses + } + // Handle key presses + event.which = event.charCode || event.keyCode; - event.which = event.charCode || event.keyCode; // Fix button for mouse clicks: + // Fix button for mouse clicks: // 0 == left; 1 == middle; 2 == right - if (event.button !== null && event.button !== undefined) { // The following is disabled because it does not pass videojs-standard // and... yikes. - /* eslint-disable */ event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0; /* eslint-enable */ } } - - event.fixed_ = true; // Returns fixed-up instance - + event.fixed_ = true; + // Returns fixed-up instance return event; } + /** * Whether passive event listeners are supported */ - - var _supportsPassive; - - var supportsPassive = function supportsPassive() { + let _supportsPassive; + const supportsPassive = function () { if (typeof _supportsPassive !== 'boolean') { _supportsPassive = false; - try { - var opts = Object.defineProperty({}, 'passive', { - get: function get() { + const opts = Object.defineProperty({}, 'passive', { + get() { _supportsPassive = true; } }); window.addEventListener('test', null, opts); window.removeEventListener('test', null, opts); - } catch (e) {// disregard + } catch (e) { + // disregard } } - return _supportsPassive; }; + /** * Touch events Chrome expects to be passive */ + const passiveEvents = ['touchstart', 'touchmove']; - - var passiveEvents = ['touchstart', 'touchmove']; /** * Add an event listener to element * It stores the handler function in a separate cache object @@ -2270,51 +2215,41 @@ * @param {string|string[]} type * Type of event to bind to. * - * @param {EventTarget~EventListener} fn + * @param {Function} fn * Event listener. */ - function on(elem, type, fn) { if (Array.isArray(type)) { return _handleMultipleEvents(on, elem, type, fn); } - if (!DomData.has(elem)) { DomData.set(elem, {}); } + const data = DomData.get(elem); - var data = DomData.get(elem); // We need a place to store all our handler data - + // We need a place to store all our handler data if (!data.handlers) { data.handlers = {}; } - if (!data.handlers[type]) { data.handlers[type] = []; } - if (!fn.guid) { fn.guid = newGUID(); } - data.handlers[type].push(fn); - if (!data.dispatcher) { data.disabled = false; - data.dispatcher = function (event, hash) { if (data.disabled) { return; } - event = fixEvent(event); - var handlers = data.handlers[event.type]; - + const handlers = data.handlers[event.type]; if (handlers) { // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off. - var handlersCopy = handlers.slice(0); - - for (var m = 0, n = handlersCopy.length; m < n; m++) { + const handlersCopy = handlers.slice(0); + for (let m = 0, n = handlersCopy.length; m < n; m++) { if (event.isImmediatePropagationStopped()) { break; } else { @@ -2328,23 +2263,21 @@ } }; } - if (data.handlers[type].length === 1) { if (elem.addEventListener) { - var options = false; - + let options = false; if (supportsPassive() && passiveEvents.indexOf(type) > -1) { options = { passive: true }; } - elem.addEventListener(type, data.dispatcher, options); } else if (elem.attachEvent) { elem.attachEvent('on' + type, data.dispatcher); } } } + /** * Removes event listeners from an element * @@ -2354,68 +2287,64 @@ * @param {string|string[]} [type] * Type of listener to remove. Don't include to remove all events from element. * - * @param {EventTarget~EventListener} [fn] + * @param {Function} [fn] * Specific listener to remove. Don't include to remove listeners for an event * type. */ - function off(elem, type, fn) { // Don't want to add a cache object through getElData if not needed if (!DomData.has(elem)) { return; } + const data = DomData.get(elem); - var data = DomData.get(elem); // If no events exist, nothing to unbind - + // If no events exist, nothing to unbind if (!data.handlers) { return; } - if (Array.isArray(type)) { return _handleMultipleEvents(off, elem, type, fn); - } // Utility function + } - - var removeType = function removeType(el, t) { + // Utility function + const removeType = function (el, t) { data.handlers[t] = []; - _cleanUpEvents(el, t); - }; // Are we removing all bound events? - + }; + // Are we removing all bound events? if (type === undefined) { - for (var t in data.handlers) { + for (const t in data.handlers) { if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) { removeType(elem, t); } } + return; + } + const handlers = data.handlers[type]; + // If no handlers exist, nothing to unbind + if (!handlers) { return; } - var handlers = data.handlers[type]; // If no handlers exist, nothing to unbind - - if (!handlers) { - return; - } // If no listener was provided, remove all listeners for type - - + // If no listener was provided, remove all listeners for type if (!fn) { removeType(elem, type); return; - } // We're only removing a single handler - + } + // We're only removing a single handler if (fn.guid) { - for (var n = 0; n < handlers.length; n++) { + for (let n = 0; n < handlers.length; n++) { if (handlers[n].guid === fn.guid) { handlers.splice(n--, 1); } } } - _cleanUpEvents(elem, type); } + /** * Trigger an event for an element * @@ -2432,16 +2361,16 @@ * Returns the opposite of `defaultPrevented` if default was * prevented. Otherwise, returns `undefined` */ - function trigger(elem, event, hash) { // Fetches element data and a reference to the parent (for bubbling). // Don't want to add a data object to cache for every parent, // so checking hasElData first. - var elemData = DomData.has(elem) ? DomData.get(elem) : {}; - var parent = elem.parentNode || elem.ownerDocument; // type = event.type || event, + const elemData = DomData.has(elem) ? DomData.get(elem) : {}; + const parent = elem.parentNode || elem.ownerDocument; + // type = event.type || event, // handler; - // If an event name was passed as a string, creates an event out of it + // If an event name was passed as a string, creates an event out of it if (typeof event === 'string') { event = { type: event, @@ -2449,42 +2378,45 @@ }; } else if (!event.target) { event.target = elem; - } // Normalizes the event properties. + } + // Normalizes the event properties. + event = fixEvent(event); - event = fixEvent(event); // If the passed element has a dispatcher, executes the established handlers. - + // If the passed element has a dispatcher, executes the established handlers. if (elemData.dispatcher) { elemData.dispatcher.call(elem, event, hash); - } // Unless explicitly stopped or the event does not bubble (e.g. media events) + } + + // Unless explicitly stopped or the event does not bubble (e.g. media events) // recursively calls this function to bubble the event up the DOM. - - if (parent && !event.isPropagationStopped() && event.bubbles === true) { - trigger.call(null, parent, event, hash); // If at the top of the DOM, triggers the default action unless disabled. + trigger.call(null, parent, event, hash); + + // If at the top of the DOM, triggers the default action unless disabled. } else if (!parent && !event.defaultPrevented && event.target && event.target[event.type]) { if (!DomData.has(event.target)) { DomData.set(event.target, {}); } + const targetData = DomData.get(event.target); - var targetData = DomData.get(event.target); // Checks if the target has a default action for this event. - + // Checks if the target has a default action for this event. if (event.target[event.type]) { // Temporarily disables event dispatching on the target as we have already executed the handler. - targetData.disabled = true; // Executes the default action. - + targetData.disabled = true; + // Executes the default action. if (typeof event.target[event.type] === 'function') { event.target[event.type](); - } // Re-enables event dispatching. - - + } + // Re-enables event dispatching. targetData.disabled = false; } - } // Inform the triggerer if the default was prevented by returning false - + } + // Inform the triggerer if the default was prevented by returning false return !event.defaultPrevented; } + /** * Trigger a listener only once for an event. * @@ -2497,21 +2429,20 @@ * @param {Event~EventListener} fn * Event listener function */ - function one(elem, type, fn) { if (Array.isArray(type)) { return _handleMultipleEvents(one, elem, type, fn); } - - var func = function func() { + const func = function () { off(elem, type, func); fn.apply(this, arguments); - }; // copy the guid to the new function so it can removed using the original function's ID - + }; + // copy the guid to the new function so it can removed using the original function's ID func.guid = fn.guid = fn.guid || newGUID(); on(elem, type, func); } + /** * Trigger a listener only once and then turn if off for all * configured events @@ -2525,16 +2456,16 @@ * @param {Event~EventListener} fn * Event listener function */ - function any(elem, type, fn) { - var func = function func() { + const func = function () { off(elem, type, func); fn.apply(this, arguments); - }; // copy the guid to the new function so it can removed using the original function's ID + }; + // copy the guid to the new function so it can removed using the original function's ID + func.guid = fn.guid = fn.guid || newGUID(); - func.guid = fn.guid = fn.guid || newGUID(); // multiple ons, but one off for everything - + // multiple ons, but one off for everything on(elem, type, func); } @@ -2552,16 +2483,17 @@ * @file fn.js * @module fn */ - var UPDATE_REFRESH_INTERVAL = 30; + const UPDATE_REFRESH_INTERVAL = 30; + /** - * Bind (a.k.a proxy or context). A simple method for changing the context of - * a function. + * A private, internal-only function for changing the context of a function. * * It also stores a unique id on the function so it can be easily removed from * events. * + * @private * @function - * @param {Mixed} context + * @param {*} context * The object to bind as scope. * * @param {Function} fn @@ -2573,24 +2505,25 @@ * @return {Function} * The new function that will be bound into the context given */ - - var bind = function bind(context, fn, uid) { + const bind_ = function (context, fn, uid) { // Make sure the function has a unique ID if (!fn.guid) { fn.guid = newGUID(); - } // Create the new function that changes the context + } + // Create the new function that changes the context + const bound = fn.bind(context); - var bound = fn.bind(context); // Allow for the ability to individualize this function + // Allow for the ability to individualize this function // Needed in the case where multiple objects might share the same prototype // IF both items add an event listener with the same function, then you try to remove just one // it will remove both because they both have the same guid. // when using this, you need to use the bind method when you remove the listener as well. // currently used in text tracks - bound.guid = uid ? uid + '_' + fn.guid : fn.guid; return bound; }; + /** * Wraps the given function, `fn`, with a new function that only invokes `fn` * at most once per every `wait` milliseconds. @@ -2604,21 +2537,18 @@ * * @return {Function} */ - - var throttle = function throttle(fn, wait) { - var last = window.performance.now(); - - var throttled = function throttled() { - var now = window.performance.now(); - + const throttle = function (fn, wait) { + let last = window.performance.now(); + const throttled = function (...args) { + const now = window.performance.now(); if (now - last >= wait) { - fn.apply(void 0, arguments); + fn(...args); last = now; } }; - return throttled; }; + /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was @@ -2645,51 +2575,49 @@ * @return {Function} * A debounced function. */ - - var debounce = function debounce(func, wait, immediate, context) { - if (context === void 0) { - context = window; - } - - var timeout; - - var cancel = function cancel() { + const debounce = function (func, wait, immediate, context = window) { + let timeout; + const cancel = () => { context.clearTimeout(timeout); timeout = null; }; + /* eslint-disable consistent-this */ - - - var debounced = function debounced() { - var self = this; - var args = arguments; - - var _later = function later() { + const debounced = function () { + const self = this; + const args = arguments; + let later = function () { timeout = null; - _later = null; - + later = null; if (!immediate) { func.apply(self, args); } }; - if (!timeout && immediate) { func.apply(self, args); } - context.clearTimeout(timeout); - timeout = context.setTimeout(_later, wait); + timeout = context.setTimeout(later, wait); }; /* eslint-enable consistent-this */ - debounced.cancel = cancel; return debounced; }; + var Fn = /*#__PURE__*/Object.freeze({ + __proto__: null, + UPDATE_REFRESH_INTERVAL: UPDATE_REFRESH_INTERVAL, + bind_: bind_, + throttle: throttle, + debounce: debounce + }); + /** * @file src/js/event-target.js */ + let EVENT_MAP; + /** * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It * adds shorthand functions that wrap around lengthy functions. For example: @@ -2698,22 +2626,154 @@ * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget} * @class EventTarget */ + class EventTarget$2 { + /** + * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a + * function that will get called when an event with a certain name gets triggered. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} fn + * The function to call with `EventTarget`s + */ + on(type, fn) { + // Remove the addEventListener alias before calling Events.on + // so we don't get into an infinite type loop + const ael = this.addEventListener; + this.addEventListener = () => {}; + on(this, type, fn); + this.addEventListener = ael; + } + /** + * Removes an `event listener` for a specific event from an instance of `EventTarget`. + * This makes it so that the `event listener` will no longer get called when the + * named event happens. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} fn + * The function to remove. + */ + off(type, fn) { + off(this, type, fn); + } + /** + * This function will add an `event listener` that gets triggered only once. After the + * first trigger it will get removed. This is like adding an `event listener` + * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} fn + * The function to be called once for each event name. + */ + one(type, fn) { + // Remove the addEventListener aliasing Events.on + // so we don't get into an infinite type loop + const ael = this.addEventListener; + this.addEventListener = () => {}; + one(this, type, fn); + this.addEventListener = ael; + } + /** + * This function will add an `event listener` that gets triggered only once and is + * removed from all events. This is like adding an array of `event listener`s + * with {@link EventTarget#on} that calls {@link EventTarget#off} on all events the + * first time it is triggered. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} fn + * The function to be called once for each event name. + */ + any(type, fn) { + // Remove the addEventListener aliasing Events.on + // so we don't get into an infinite type loop + const ael = this.addEventListener; + this.addEventListener = () => {}; + any(this, type, fn); + this.addEventListener = ael; + } + /** + * This function causes an event to happen. This will then cause any `event listeners` + * that are waiting for that event, to get called. If there are no `event listeners` + * for an event then nothing will happen. + * + * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`. + * Trigger will also call the `on` + `uppercaseEventName` function. + * + * Example: + * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call + * `onClick` if it exists. + * + * @param {string|EventTarget~Event|Object} event + * The name of the event, an `Event`, or an object with a key of type set to + * an event name. + */ + trigger(event) { + const type = event.type || event; + + // deprecation + // In a future version we should default target to `this` + // similar to how we default the target to `elem` in + // `Events.trigger`. Right now the default `target` will be + // `document` due to the `Event.fixEvent` call. + if (typeof event === 'string') { + event = { + type + }; + } + event = fixEvent(event); + if (this.allowedEvents_[type] && this['on' + type]) { + this['on' + type](event); + } + trigger(this, event); + } + queueTrigger(event) { + // only set up EVENT_MAP if it'll be used + if (!EVENT_MAP) { + EVENT_MAP = new Map(); + } + const type = event.type || event; + let map = EVENT_MAP.get(this); + if (!map) { + map = new Map(); + EVENT_MAP.set(this, map); + } + const oldTimeout = map.get(type); + map.delete(type); + window.clearTimeout(oldTimeout); + const timeout = window.setTimeout(() => { + map.delete(type); + // if we cleared out all timeouts for the current target, delete its map + if (map.size === 0) { + map = null; + EVENT_MAP.delete(this); + } + this.trigger(event); + }, 0); + map.set(type, timeout); + } + } - var EventTarget$2 = function EventTarget() {}; /** * A Custom DOM event. * - * @typedef {Object} EventTarget~Event + * @typedef {CustomEvent} Event * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent} */ /** * All event listeners should follow the following format. * - * @callback EventTarget~EventListener + * @callback EventListener * @this {EventTarget} * - * @param {EventTarget~Event} event + * @param {Event} event * the event that triggered this function * * @param {Object} [hash] @@ -2727,32 +2787,10 @@ * will have extra functionality. See that function for more information. * * @property EventTarget.prototype.allowedEvents_ - * @private + * @protected */ - - EventTarget$2.prototype.allowedEvents_ = {}; - /** - * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a - * function that will get called when an event with a certain name gets triggered. - * - * @param {string|string[]} type - * An event name or an array of event names. - * - * @param {EventTarget~EventListener} fn - * The function to call with `EventTarget`s - */ - EventTarget$2.prototype.on = function (type, fn) { - // Remove the addEventListener alias before calling Events.on - // so we don't get into an infinite type loop - var ael = this.addEventListener; - - this.addEventListener = function () {}; - - on(this, type, fn); - this.addEventListener = ael; - }; /** * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic * the standard DOM API. @@ -2760,24 +2798,8 @@ * @function * @see {@link EventTarget#on} */ - - EventTarget$2.prototype.addEventListener = EventTarget$2.prototype.on; - /** - * Removes an `event listener` for a specific event from an instance of `EventTarget`. - * This makes it so that the `event listener` will no longer get called when the - * named event happens. - * - * @param {string|string[]} type - * An event name or an array of event names. - * - * @param {EventTarget~EventListener} fn - * The function to remove. - */ - EventTarget$2.prototype.off = function (type, fn) { - off(this, type, fn); - }; /** * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic * the standard DOM API. @@ -2785,81 +2807,8 @@ * @function * @see {@link EventTarget#off} */ - - EventTarget$2.prototype.removeEventListener = EventTarget$2.prototype.off; - /** - * This function will add an `event listener` that gets triggered only once. After the - * first trigger it will get removed. This is like adding an `event listener` - * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself. - * - * @param {string|string[]} type - * An event name or an array of event names. - * - * @param {EventTarget~EventListener} fn - * The function to be called once for each event name. - */ - EventTarget$2.prototype.one = function (type, fn) { - // Remove the addEventListener aliasing Events.on - // so we don't get into an infinite type loop - var ael = this.addEventListener; - - this.addEventListener = function () {}; - - one(this, type, fn); - this.addEventListener = ael; - }; - - EventTarget$2.prototype.any = function (type, fn) { - // Remove the addEventListener aliasing Events.on - // so we don't get into an infinite type loop - var ael = this.addEventListener; - - this.addEventListener = function () {}; - - any(this, type, fn); - this.addEventListener = ael; - }; - /** - * This function causes an event to happen. This will then cause any `event listeners` - * that are waiting for that event, to get called. If there are no `event listeners` - * for an event then nothing will happen. - * - * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`. - * Trigger will also call the `on` + `uppercaseEventName` function. - * - * Example: - * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call - * `onClick` if it exists. - * - * @param {string|EventTarget~Event|Object} event - * The name of the event, an `Event`, or an object with a key of type set to - * an event name. - */ - - - EventTarget$2.prototype.trigger = function (event) { - var type = event.type || event; // deprecation - // In a future version we should default target to `this` - // similar to how we default the target to `elem` in - // `Events.trigger`. Right now the default `target` will be - // `document` due to the `Event.fixEvent` call. - - if (typeof event === 'string') { - event = { - type: type - }; - } - - event = fixEvent(event); - - if (this.allowedEvents_[type] && this['on' + type]) { - this['on' + type](event); - } - - trigger(this, event); - }; /** * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic * the standard DOM API. @@ -2867,66 +2816,28 @@ * @function * @see {@link EventTarget#trigger} */ - - EventTarget$2.prototype.dispatchEvent = EventTarget$2.prototype.trigger; - var EVENT_MAP; - - EventTarget$2.prototype.queueTrigger = function (event) { - var _this = this; - - // only set up EVENT_MAP if it'll be used - if (!EVENT_MAP) { - EVENT_MAP = new Map(); - } - - var type = event.type || event; - var map = EVENT_MAP.get(this); - - if (!map) { - map = new Map(); - EVENT_MAP.set(this, map); - } - - var oldTimeout = map.get(type); - map["delete"](type); - window.clearTimeout(oldTimeout); - var timeout = window.setTimeout(function () { - // if we cleared out all timeouts for the current target, delete its map - if (map.size === 0) { - map = null; - EVENT_MAP["delete"](_this); - } - - _this.trigger(event); - }, 0); - map.set(type, timeout); - }; /** * @file mixins/evented.js * @module evented */ - - var objName = function objName(obj) { + const objName = obj => { if (typeof obj.name === 'function') { return obj.name(); } - if (typeof obj.name === 'string') { return obj.name; } - if (obj.name_) { return obj.name_; } - if (obj.constructor && obj.constructor.name) { return obj.constructor.name; } - return typeof obj; }; + /** * Returns whether or not an object has had the evented mixin applied. * @@ -2936,34 +2847,27 @@ * @return {boolean} * Whether or not the object appears to be evented. */ + const isEvented = object => object instanceof EventTarget$2 || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(k => typeof object[k] === 'function'); - - var isEvented = function isEvented(object) { - return object instanceof EventTarget$2 || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(function (k) { - return typeof object[k] === 'function'; - }); - }; /** * Adds a callback to run after the evented mixin applied. * - * @param {Object} object + * @param {Object} target * An object to Add * @param {Function} callback * The callback to run. */ - - - var addEventedCallback = function addEventedCallback(target, callback) { + const addEventedCallback = (target, callback) => { if (isEvented(target)) { callback(); } else { if (!target.eventedCallbacks) { target.eventedCallbacks = []; } - target.eventedCallbacks.push(callback); } }; + /** * Whether a value is a valid event type - non-empty string or array. * @@ -2974,14 +2878,11 @@ * @return {boolean} * Whether or not the type is a valid event type. */ + const isValidEventType = type => + // The regex here verifies that the `type` contains at least one non- + // whitespace character. + typeof type === 'string' && /\S/.test(type) || Array.isArray(type) && !!type.length; - - var isValidEventType = function isValidEventType(type) { - return (// The regex here verifies that the `type` contains at least one non- - // whitespace character. - typeof type === 'string' && /\S/.test(type) || Array.isArray(type) && !!type.length - ); - }; /** * Validates a value to determine if it is a valid event target. Throws if not. * @@ -2998,13 +2899,12 @@ * @param {string} fnName * The name of the evented mixin function that called this. */ - - - var validateTarget = function validateTarget(target, obj, fnName) { + const validateTarget = (target, obj, fnName) => { if (!target || !target.nodeName && !isEvented(target)) { - throw new Error("Invalid target for " + objName(obj) + "#" + fnName + "; must be a DOM node or evented object."); + throw new Error(`Invalid target for ${objName(obj)}#${fnName}; must be a DOM node or evented object.`); } }; + /** * Validates a value to determine if it is a valid event target. Throws if not. * @@ -3021,13 +2921,12 @@ * @param {string} fnName * The name of the evented mixin function that called this. */ - - - var validateEventType = function validateEventType(type, obj, fnName) { + const validateEventType = (type, obj, fnName) => { if (!isValidEventType(type)) { - throw new Error("Invalid event type for " + objName(obj) + "#" + fnName + "; must be a non-empty string or array."); + throw new Error(`Invalid event type for ${objName(obj)}#${fnName}; must be a non-empty string or array.`); } }; + /** * Validates a value to determine if it is a valid listener. Throws if not. * @@ -3044,13 +2943,12 @@ * @param {string} fnName * The name of the evented mixin function that called this. */ - - - var validateListener = function validateListener(listener, obj, fnName) { + const validateListener = (listener, obj, fnName) => { if (typeof listener !== 'function') { - throw new Error("Invalid listener for " + objName(obj) + "#" + fnName + "; must be a function."); + throw new Error(`Invalid listener for ${objName(obj)}#${fnName}; must be a function.`); } }; + /** * Takes an array of arguments given to `on()` or `one()`, validates them, and * normalizes them into an object. @@ -3069,43 +2967,42 @@ * @return {Object} * An object containing useful values for `on()` or `one()` calls. */ - - - var normalizeListenArgs = function normalizeListenArgs(self, args, fnName) { + const normalizeListenArgs = (self, args, fnName) => { // If the number of arguments is less than 3, the target is always the // evented object itself. - var isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_; - var target; - var type; - var listener; - + const isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_; + let target; + let type; + let listener; if (isTargetingSelf) { - target = self.eventBusEl_; // Deal with cases where we got 3 arguments, but we are still listening to - // the evented object itself. + target = self.eventBusEl_; + // Deal with cases where we got 3 arguments, but we are still listening to + // the evented object itself. if (args.length >= 3) { args.shift(); } - - type = args[0]; - listener = args[1]; + [type, listener] = args; } else { + // This was `[target, type, listener] = args;` but this block needs more than + // one statement to produce minified output compatible with Chrome 53. + // See https://github.com/videojs/video.js/pull/8810 target = args[0]; type = args[1]; listener = args[2]; } - validateTarget(target, self, fnName); validateEventType(type, self, fnName); validateListener(listener, self, fnName); - listener = bind(self, listener); + listener = bind_(self, listener); return { - isTargetingSelf: isTargetingSelf, - target: target, - type: type, - listener: listener + isTargetingSelf, + target, + type, + listener }; }; + /** * Adds the listener to the event type(s) on the target, normalizing for * the type of target. @@ -3123,26 +3020,22 @@ * @param {Function} listener * A listener function. */ - - - var listen = function listen(target, method, type, listener) { + const listen = (target, method, type, listener) => { validateTarget(target, target, method); - if (target.nodeName) { Events[method](target, type, listener); } else { target[method](type, listener); } }; + /** * Contains methods that provide event capabilities to an object which is passed * to {@link module:evented|evented}. * * @mixin EventedMixin */ - - - var EventedMixin = { + const EventedMixin = { /** * Add a listener to an event (or events) on this object or another evented * object. @@ -3166,45 +3059,36 @@ * If the first argument was another evented object, this will be * the listener function. */ - on: function on() { - var _this = this; - - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var _normalizeListenArgs = normalizeListenArgs(this, args, 'on'), - isTargetingSelf = _normalizeListenArgs.isTargetingSelf, - target = _normalizeListenArgs.target, - type = _normalizeListenArgs.type, - listener = _normalizeListenArgs.listener; - - listen(target, 'on', type, listener); // If this object is listening to another evented object. + on(...args) { + const { + isTargetingSelf, + target, + type, + listener + } = normalizeListenArgs(this, args, 'on'); + listen(target, 'on', type, listener); + // If this object is listening to another evented object. if (!isTargetingSelf) { // If this object is disposed, remove the listener. - var removeListenerOnDispose = function removeListenerOnDispose() { - return _this.off(target, type, listener); - }; // Use the same function ID as the listener so we can remove it later it + const removeListenerOnDispose = () => this.off(target, type, listener); + + // Use the same function ID as the listener so we can remove it later it // using the ID of the original listener. + removeListenerOnDispose.guid = listener.guid; - - removeListenerOnDispose.guid = listener.guid; // Add a listener to the target's dispose event as well. This ensures + // Add a listener to the target's dispose event as well. This ensures // that if the target is disposed BEFORE this object, we remove the // removal listener that was just added. Otherwise, we create a memory leak. + const removeRemoverOnTargetDispose = () => this.off('dispose', removeListenerOnDispose); - var removeRemoverOnTargetDispose = function removeRemoverOnTargetDispose() { - return _this.off('dispose', removeListenerOnDispose); - }; // Use the same function ID as the listener so we can remove it later + // Use the same function ID as the listener so we can remove it later // it using the ID of the original listener. - - removeRemoverOnTargetDispose.guid = listener.guid; listen(this, 'on', 'dispose', removeListenerOnDispose); listen(target, 'on', 'dispose', removeRemoverOnTargetDispose); } }, - /** * Add a listener to an event (or events) on this object or another evented * object. The listener will be called once per event and then removed. @@ -3228,44 +3112,35 @@ * If the first argument was another evented object, this will be * the listener function. */ - one: function one() { - var _this2 = this; - - for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - var _normalizeListenArgs2 = normalizeListenArgs(this, args, 'one'), - isTargetingSelf = _normalizeListenArgs2.isTargetingSelf, - target = _normalizeListenArgs2.target, - type = _normalizeListenArgs2.type, - listener = _normalizeListenArgs2.listener; // Targeting this evented object. - + one(...args) { + const { + isTargetingSelf, + target, + type, + listener + } = normalizeListenArgs(this, args, 'one'); + // Targeting this evented object. if (isTargetingSelf) { - listen(target, 'one', type, listener); // Targeting another evented object. + listen(target, 'one', type, listener); + + // Targeting another evented object. } else { // TODO: This wrapper is incorrect! It should only // remove the wrapper for the event type that called it. - // Instead all listners are removed on the first trigger! + // Instead all listeners are removed on the first trigger! // see https://github.com/videojs/video.js/issues/5962 - var wrapper = function wrapper() { - _this2.off(target, type, wrapper); - - for (var _len3 = arguments.length, largs = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - largs[_key3] = arguments[_key3]; - } - + const wrapper = (...largs) => { + this.off(target, type, wrapper); listener.apply(null, largs); - }; // Use the same function ID as the listener so we can remove it later + }; + + // Use the same function ID as the listener so we can remove it later // it using the ID of the original listener. - - wrapper.guid = listener.guid; listen(target, 'one', type, wrapper); } }, - /** * Add a listener to an event (or events) on this object or another evented * object. The listener will only be called once for the first event that is triggered @@ -3290,40 +3165,31 @@ * If the first argument was another evented object, this will be * the listener function. */ - any: function any() { - var _this3 = this; - - for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - args[_key4] = arguments[_key4]; - } - - var _normalizeListenArgs3 = normalizeListenArgs(this, args, 'any'), - isTargetingSelf = _normalizeListenArgs3.isTargetingSelf, - target = _normalizeListenArgs3.target, - type = _normalizeListenArgs3.type, - listener = _normalizeListenArgs3.listener; // Targeting this evented object. - + any(...args) { + const { + isTargetingSelf, + target, + type, + listener + } = normalizeListenArgs(this, args, 'any'); + // Targeting this evented object. if (isTargetingSelf) { - listen(target, 'any', type, listener); // Targeting another evented object. + listen(target, 'any', type, listener); + + // Targeting another evented object. } else { - var wrapper = function wrapper() { - _this3.off(target, type, wrapper); - - for (var _len5 = arguments.length, largs = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - largs[_key5] = arguments[_key5]; - } - + const wrapper = (...largs) => { + this.off(target, type, wrapper); listener.apply(null, largs); - }; // Use the same function ID as the listener so we can remove it later + }; + + // Use the same function ID as the listener so we can remove it later // it using the ID of the original listener. - - wrapper.guid = listener.guid; listen(target, 'any', type, wrapper); } }, - /** * Removes listener(s) from event(s) on an evented object. * @@ -3343,23 +3209,27 @@ * the listener function; otherwise, _all_ listeners bound to the * event type(s) will be removed. */ - off: function off$1(targetOrType, typeOrListener, listener) { + off(targetOrType, typeOrListener, listener) { // Targeting this evented object. if (!targetOrType || isValidEventType(targetOrType)) { - off(this.eventBusEl_, targetOrType, typeOrListener); // Targeting another evented object. - } else { - var target = targetOrType; - var type = typeOrListener; // Fail fast and in a meaningful way! + off(this.eventBusEl_, targetOrType, typeOrListener); + // Targeting another evented object. + } else { + const target = targetOrType; + const type = typeOrListener; + + // Fail fast and in a meaningful way! validateTarget(target, this, 'off'); validateEventType(type, this, 'off'); - validateListener(listener, this, 'off'); // Ensure there's at least a guid, even if the function hasn't been used + validateListener(listener, this, 'off'); - listener = bind(this, listener); // Remove the dispose listener on this evented object, which was given + // Ensure there's at least a guid, even if the function hasn't been used + listener = bind_(this, listener); + + // Remove the dispose listener on this evented object, which was given // the same guid as the event listener in on(). - this.off('dispose', listener); - if (target.nodeName) { off(target, type, listener); off(target, 'dispose', listener); @@ -3369,7 +3239,6 @@ } } }, - /** * Fire an event on this evented object, causing its listeners to be called. * @@ -3382,23 +3251,16 @@ * @return {boolean} * Whether or not the default behavior was prevented. */ - trigger: function trigger$1(event, hash) { + trigger(event, hash) { validateTarget(this.eventBusEl_, this, 'trigger'); - var type = event && typeof event !== 'string' ? event.type : event; - + const type = event && typeof event !== 'string' ? event.type : event; if (!isValidEventType(type)) { - var error = "Invalid event type for " + objName(this) + "#trigger; " + 'must be a non-empty string or object with a type key that has a non-empty value.'; - - if (event) { - (this.log || log$1).error(error); - } else { - throw new Error(error); - } + throw new Error(`Invalid event type for ${objName(this)}#trigger; ` + 'must be a non-empty string or object with a type key that has a non-empty value.'); } - return trigger(this.eventBusEl_, event, hash); } }; + /** * Applies {@link module:evented~EventedMixin|EventedMixin} to a target object. * @@ -3416,44 +3278,38 @@ * @return {Object} * The target object. */ + function evented(target, options = {}) { + const { + eventBusKey + } = options; - function evented(target, options) { - if (options === void 0) { - options = {}; - } - - var _options = options, - eventBusKey = _options.eventBusKey; // Set or create the eventBusEl_. - + // Set or create the eventBusEl_. if (eventBusKey) { if (!target[eventBusKey].nodeName) { - throw new Error("The eventBusKey \"" + eventBusKey + "\" does not refer to an element."); + throw new Error(`The eventBusKey "${eventBusKey}" does not refer to an element.`); } - target.eventBusEl_ = target[eventBusKey]; } else { target.eventBusEl_ = createEl('span', { className: 'vjs-event-bus' }); } - - assign(target, EventedMixin); - + Object.assign(target, EventedMixin); if (target.eventedCallbacks) { - target.eventedCallbacks.forEach(function (callback) { + target.eventedCallbacks.forEach(callback => { callback(); }); - } // When any evented object is disposed, it removes all its listeners. + } - - target.on('dispose', function () { + // When any evented object is disposed, it removes all its listeners. + target.on('dispose', () => { target.off(); [target, target.el_, target.eventBusEl_].forEach(function (val) { if (val && DomData.has(val)) { - DomData["delete"](val); + DomData.delete(val); } }); - window.setTimeout(function () { + window.setTimeout(() => { target.eventBusEl_ = null; }, 0); }); @@ -3464,14 +3320,14 @@ * @file mixins/stateful.js * @module stateful */ + /** * Contains methods that provide statefulness to an object which is passed * to {@link module:stateful}. * * @mixin StatefulMixin */ - - var StatefulMixin = { + const StatefulMixin = { /** * A hash containing arbitrary keys and values representing the state of * the object. @@ -3479,7 +3335,6 @@ * @type {Object} */ state: {}, - /** * Set the state of an object by mutating its * {@link module:stateful~StatefulMixin.state|state} object in place. @@ -3493,31 +3348,28 @@ * An object containing changes that occurred. If no changes * occurred, returns `undefined`. */ - setState: function setState(stateUpdates) { - var _this = this; - + setState(stateUpdates) { // Support providing the `stateUpdates` state as a function. if (typeof stateUpdates === 'function') { stateUpdates = stateUpdates(); } - - var changes; - each(stateUpdates, function (value, key) { + let changes; + each(stateUpdates, (value, key) => { // Record the change if the value is different from what's in the // current state. - if (_this.state[key] !== value) { + if (this.state[key] !== value) { changes = changes || {}; changes[key] = { - from: _this.state[key], + from: this.state[key], to: value }; } + this.state[key] = value; + }); - _this.state[key] = value; - }); // Only trigger "statechange" if there were changes AND we have a trigger + // Only trigger "statechange" if there were changes AND we have a trigger // function. This allows us to not require that the target object be an // evented object. - if (changes && isEvented(this)) { /** * An event triggered on an object that is both @@ -3531,14 +3383,14 @@ * the values they were changed `from` and `to`. */ this.trigger({ - changes: changes, + changes, type: 'statechanged' }); } - return changes; } }; + /** * Applies {@link module:stateful~StatefulMixin|StatefulMixin} to a target * object. @@ -3557,22 +3409,22 @@ * @return {Object} * Returns the `target`. */ - function stateful(target, defaultState) { - assign(target, StatefulMixin); // This happens after the mixing-in because we need to replace the `state` + Object.assign(target, StatefulMixin); + + // This happens after the mixing-in because we need to replace the `state` // added in that step. + target.state = Object.assign({}, target.state, defaultState); - target.state = assign({}, target.state, defaultState); // Auto-bind the `handleStateChanged` method of the target object if it exists. - + // Auto-bind the `handleStateChanged` method of the target object if it exists. if (typeof target.handleStateChanged === 'function' && isEvented(target)) { target.on('statechanged', target.handleStateChanged); } - return target; } /** - * @file string-cases.js + * @file str.js * @module to-lower-case */ @@ -3585,15 +3437,13 @@ * @return {string} * The string with a lowercased first letter */ - var toLowerCase = function toLowerCase(string) { + const toLowerCase = function (string) { if (typeof string !== 'string') { return string; } - - return string.replace(/./, function (w) { - return w.toLowerCase(); - }); + return string.replace(/./, w => w.toLowerCase()); }; + /** * Uppercase the first letter of a string. * @@ -3603,16 +3453,13 @@ * @return {string} * The string with an uppercased first letter */ - - var toTitleCase$1 = function toTitleCase(string) { + const toTitleCase$1 = function (string) { if (typeof string !== 'string') { return string; } - - return string.replace(/./, function (w) { - return w.toUpperCase(); - }); + return string.replace(/./, w => w.toUpperCase()); }; + /** * Compares the TitleCase versions of the two strings for equality. * @@ -3625,327 +3472,33 @@ * @return {boolean} * Whether the TitleCase versions of the strings are equal */ - - var titleCaseEquals = function titleCaseEquals(str1, str2) { + const titleCaseEquals = function (str1, str2) { return toTitleCase$1(str1) === toTitleCase$1(str2); }; - /** - * @file merge-options.js - * @module merge-options - */ - /** - * Merge two objects recursively. - * - * Performs a deep merge like - * {@link https://lodash.com/docs/4.17.10#merge|lodash.merge}, but only merges - * plain objects (not arrays, elements, or anything else). - * - * Non-plain object values will be copied directly from the right-most - * argument. - * - * @static - * @param {Object[]} sources - * One or more objects to merge into a new object. - * - * @return {Object} - * A new object that is the merged result of all sources. - */ - - function mergeOptions$3() { - var result = {}; - - for (var _len = arguments.length, sources = new Array(_len), _key = 0; _key < _len; _key++) { - sources[_key] = arguments[_key]; - } - - sources.forEach(function (source) { - if (!source) { - return; - } - - each(source, function (value, key) { - if (!isPlain(value)) { - result[key] = value; - return; - } - - if (!isPlain(result[key])) { - result[key] = {}; - } - - result[key] = mergeOptions$3(result[key], value); - }); - }); - return result; - } - - var MapSham = /*#__PURE__*/function () { - function MapSham() { - this.map_ = {}; - } - - var _proto = MapSham.prototype; - - _proto.has = function has(key) { - return key in this.map_; - }; - - _proto["delete"] = function _delete(key) { - var has = this.has(key); - delete this.map_[key]; - return has; - }; - - _proto.set = function set(key, value) { - this.map_[key] = value; - return this; - }; - - _proto.forEach = function forEach(callback, thisArg) { - for (var key in this.map_) { - callback.call(thisArg, this.map_[key], key, this); - } - }; - - return MapSham; - }(); - - var Map$1 = window.Map ? window.Map : MapSham; - - var SetSham = /*#__PURE__*/function () { - function SetSham() { - this.set_ = {}; - } - - var _proto = SetSham.prototype; - - _proto.has = function has(key) { - return key in this.set_; - }; - - _proto["delete"] = function _delete(key) { - var has = this.has(key); - delete this.set_[key]; - return has; - }; - - _proto.add = function add(key) { - this.set_[key] = 1; - return this; - }; - - _proto.forEach = function forEach(callback, thisArg) { - for (var key in this.set_) { - callback.call(thisArg, key, key, this); - } - }; - - return SetSham; - }(); - - var Set$1 = window.Set ? window.Set : SetSham; - - var keycode = createCommonjsModule(function (module, exports) { - // Source: http://jsfiddle.net/vWx8V/ - // http://stackoverflow.com/questions/5603195/full-list-of-javascript-keycodes - - /** - * Conenience method returns corresponding value for given keyName or keyCode. - * - * @param {Mixed} keyCode {Number} or keyName {String} - * @return {Mixed} - * @api public - */ - function keyCode(searchInput) { - // Keyboard Events - if (searchInput && 'object' === typeof searchInput) { - var hasKeyCode = searchInput.which || searchInput.keyCode || searchInput.charCode; - if (hasKeyCode) searchInput = hasKeyCode; - } // Numbers - - - if ('number' === typeof searchInput) return names[searchInput]; // Everything else (cast to string) - - var search = String(searchInput); // check codes - - var foundNamedKey = codes[search.toLowerCase()]; - if (foundNamedKey) return foundNamedKey; // check aliases - - var foundNamedKey = aliases[search.toLowerCase()]; - if (foundNamedKey) return foundNamedKey; // weird character? - - if (search.length === 1) return search.charCodeAt(0); - return undefined; - } - /** - * Compares a keyboard event with a given keyCode or keyName. - * - * @param {Event} event Keyboard event that should be tested - * @param {Mixed} keyCode {Number} or keyName {String} - * @return {Boolean} - * @api public - */ - - - keyCode.isEventKey = function isEventKey(event, nameOrCode) { - if (event && 'object' === typeof event) { - var keyCode = event.which || event.keyCode || event.charCode; - - if (keyCode === null || keyCode === undefined) { - return false; - } - - if (typeof nameOrCode === 'string') { - // check codes - var foundNamedKey = codes[nameOrCode.toLowerCase()]; - - if (foundNamedKey) { - return foundNamedKey === keyCode; - } // check aliases - - - var foundNamedKey = aliases[nameOrCode.toLowerCase()]; - - if (foundNamedKey) { - return foundNamedKey === keyCode; - } - } else if (typeof nameOrCode === 'number') { - return nameOrCode === keyCode; - } - - return false; - } - }; - - exports = module.exports = keyCode; - /** - * Get by name - * - * exports.code['enter'] // => 13 - */ - - var codes = exports.code = exports.codes = { - 'backspace': 8, - 'tab': 9, - 'enter': 13, - 'shift': 16, - 'ctrl': 17, - 'alt': 18, - 'pause/break': 19, - 'caps lock': 20, - 'esc': 27, - 'space': 32, - 'page up': 33, - 'page down': 34, - 'end': 35, - 'home': 36, - 'left': 37, - 'up': 38, - 'right': 39, - 'down': 40, - 'insert': 45, - 'delete': 46, - 'command': 91, - 'left command': 91, - 'right command': 93, - 'numpad *': 106, - 'numpad +': 107, - 'numpad -': 109, - 'numpad .': 110, - 'numpad /': 111, - 'num lock': 144, - 'scroll lock': 145, - 'my computer': 182, - 'my calculator': 183, - ';': 186, - '=': 187, - ',': 188, - '-': 189, - '.': 190, - '/': 191, - '`': 192, - '[': 219, - '\\': 220, - ']': 221, - "'": 222 - }; // Helper aliases - - var aliases = exports.aliases = { - 'windows': 91, - '⇧': 16, - '⌥': 18, - '⌃': 17, - '⌘': 91, - 'ctl': 17, - 'control': 17, - 'option': 18, - 'pause': 19, - 'break': 19, - 'caps': 20, - 'return': 13, - 'escape': 27, - 'spc': 32, - 'spacebar': 32, - 'pgup': 33, - 'pgdn': 34, - 'ins': 45, - 'del': 46, - 'cmd': 91 - }; - /*! - * Programatically add the following - */ - // lower case chars - - for (i = 97; i < 123; i++) { - codes[String.fromCharCode(i)] = i - 32; - } // numbers - - - for (var i = 48; i < 58; i++) { - codes[i - 48] = i; - } // function keys - - - for (i = 1; i < 13; i++) { - codes['f' + i] = i + 111; - } // numpad keys - - - for (i = 0; i < 10; i++) { - codes['numpad ' + i] = i + 96; - } - /** - * Get by code - * - * exports.name[13] // => 'Enter' - */ - - - var names = exports.names = exports.title = {}; // title for backward compat - // Create reverse mapping - - for (i in codes) { - names[codes[i]] = i; - } // Add aliases - - - for (var alias in aliases) { - codes[alias] = aliases[alias]; - } + var Str = /*#__PURE__*/Object.freeze({ + __proto__: null, + toLowerCase: toLowerCase, + toTitleCase: toTitleCase$1, + titleCaseEquals: titleCaseEquals }); - keycode.code; - keycode.codes; - keycode.aliases; - keycode.names; - keycode.title; /** * Player Component - Base class for all UI objects * * @file component.js */ + + /** @import Player from './player' */ + + /** + * A callback to be called if and when the component is ready. + * `this` will be the Component instance. + * + * @callback ReadyCallback + * @returns {void} + */ + /** * Base class for all UI Components. * Components are UI objects which represent both a javascript object and an element @@ -3954,16 +3507,7 @@ * * Components can also use methods from {@link EventTarget} */ - - var Component$1 = /*#__PURE__*/function () { - /** - * A callback that is called when a component is ready. Does not have any - * paramters and any callback value will be ignored. - * - * @callback Component~ReadyCallback - * @this Component - */ - + class Component$1 { /** * Creates an instance of this class. * @@ -3974,57 +3518,62 @@ * The key/value store of component options. * * @param {Object[]} [options.children] - * An array of children objects to intialize this component with. Children objects have + * An array of children objects to initialize this component with. Children objects have * a name property that will be used if more than one component of the same type needs to be * added. * * @param {string} [options.className] * A class or space separated list of classes to add the component * - * @param {Component~ReadyCallback} [ready] + * @param {ReadyCallback} [ready] * Function that gets called when the `Component` is ready. */ - function Component(player, options, ready) { - var _this = this; - + constructor(player, options, ready) { // The component might be the player itself and we can't pass `this` to super if (!player && this.play) { this.player_ = player = this; // eslint-disable-line } else { this.player_ = player; } + this.isDisposed_ = false; - this.isDisposed_ = false; // Hold the reference to the parent component via `addChild` method + // Hold the reference to the parent component via `addChild` method + this.parentComponent_ = null; - this.parentComponent_ = null; // Make a copy of prototype.options_ to protect against overriding defaults + // Make a copy of prototype.options_ to protect against overriding defaults + this.options_ = merge$2({}, this.options_); - this.options_ = mergeOptions$3({}, this.options_); // Updated options with supplied options + // Updated options with supplied options + options = this.options_ = merge$2(this.options_, options); - options = this.options_ = mergeOptions$3(this.options_, options); // Get ID from options or options element if one is supplied - - this.id_ = options.id || options.el && options.el.id; // If there was no ID from the options, generate one + // Get ID from options or options element if one is supplied + this.id_ = options.id || options.el && options.el.id; + // If there was no ID from the options, generate one if (!this.id_) { // Don't require the player ID function in the case of mock players - var id = player && player.id && player.id() || 'no_player'; - this.id_ = id + "_component_" + newGUID(); + const id = player && player.id && player.id() || 'no_player'; + this.id_ = `${id}_component_${newGUID()}`; } + this.name_ = options.name || null; - this.name_ = options.name || null; // Create element if one wasn't provided in options - + // Create element if one wasn't provided in options if (options.el) { this.el_ = options.el; } else if (options.createEl !== false) { this.el_ = this.createEl(); } - if (options.className && this.el_) { - options.className.split(' ').forEach(function (c) { - return _this.addClass(c); - }); - } // if evented is anything except false, we want to mixin in evented + options.className.split(' ').forEach(c => this.addClass(c)); + } + // Remove the placeholder event methods. If the component is evented, the + // real methods are added next + ['on', 'off', 'one', 'any', 'trigger'].forEach(fn => { + this[fn] = undefined; + }); + // if evented is anything except false, we want to mixin in evented if (options.evented !== false) { // Make this an evented object and use `el_`, if available, as its event bus evented(this, { @@ -4033,117 +3582,192 @@ this.handleLanguagechange = this.handleLanguagechange.bind(this); this.on(this.player_, 'languagechange', this.handleLanguagechange); } - stateful(this, this.constructor.defaultState); this.children_ = []; this.childIndex_ = {}; this.childNameIndex_ = {}; - this.setTimeoutIds_ = new Set$1(); - this.setIntervalIds_ = new Set$1(); - this.rafIds_ = new Set$1(); - this.namedRafs_ = new Map$1(); - this.clearingTimersOnDispose_ = false; // Add any child components in options + this.setTimeoutIds_ = new Set(); + this.setIntervalIds_ = new Set(); + this.rafIds_ = new Set(); + this.namedRafs_ = new Map(); + this.clearingTimersOnDispose_ = false; + // Add any child components in options if (options.initChildren !== false) { this.initChildren(); - } // Don't want to trigger ready here or it will go before init is actually + } + + // Don't want to trigger ready here or it will go before init is actually // finished for all children that run this constructor - - this.ready(ready); - if (options.reportTouchActivity !== false) { this.enableTouchActivity(); } } + + // `on`, `off`, `one`, `any` and `trigger` are here so tsc includes them in definitions. + // They are replaced or removed in the constructor + + /** + * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a + * function that will get called when an event with a certain name gets triggered. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} fn + * The function to call with `EventTarget`s + */ + on(type, fn) {} + + /** + * Removes an `event listener` for a specific event from an instance of `EventTarget`. + * This makes it so that the `event listener` will no longer get called when the + * named event happens. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} [fn] + * The function to remove. If not specified, all listeners managed by Video.js will be removed. + */ + off(type, fn) {} + + /** + * This function will add an `event listener` that gets triggered only once. After the + * first trigger it will get removed. This is like adding an `event listener` + * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} fn + * The function to be called once for each event name. + */ + one(type, fn) {} + + /** + * This function will add an `event listener` that gets triggered only once and is + * removed from all events. This is like adding an array of `event listener`s + * with {@link EventTarget#on} that calls {@link EventTarget#off} on all events the + * first time it is triggered. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {Function} fn + * The function to be called once for each event name. + */ + any(type, fn) {} + + /** + * This function causes an event to happen. This will then cause any `event listeners` + * that are waiting for that event, to get called. If there are no `event listeners` + * for an event then nothing will happen. + * + * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`. + * Trigger will also call the `on` + `uppercaseEventName` function. + * + * Example: + * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call + * `onClick` if it exists. + * + * @param {string|Event|Object} event + * The name of the event, an `Event`, or an object with a key of type set to + * an event name. + * + * @param {Object} [hash] + * Optionally extra argument to pass through to an event listener + */ + trigger(event, hash) {} + /** * Dispose of the `Component` and all child components. * * @fires Component#dispose + * + * @param {Object} options + * @param {Element} options.originalEl element with which to replace player element */ - - - var _proto = Component.prototype; - - _proto.dispose = function dispose() { + dispose(options = {}) { // Bail out if the component has already been disposed. if (this.isDisposed_) { return; } - if (this.readyQueue_) { this.readyQueue_.length = 0; } + /** * Triggered when a `Component` is disposed. * * @event Component#dispose - * @type {EventTarget~Event} + * @type {Event} * * @property {boolean} [bubbles=false] * set to false so that the dispose event does not * bubble up */ - - this.trigger({ type: 'dispose', bubbles: false }); - this.isDisposed_ = true; // Dispose all children. + this.isDisposed_ = true; + // Dispose all children. if (this.children_) { - for (var i = this.children_.length - 1; i >= 0; i--) { + for (let i = this.children_.length - 1; i >= 0; i--) { if (this.children_[i].dispose) { this.children_[i].dispose(); } } - } // Delete child references - + } + // Delete child references this.children_ = null; this.childIndex_ = null; this.childNameIndex_ = null; this.parentComponent_ = null; - if (this.el_) { // Remove element from DOM if (this.el_.parentNode) { - this.el_.parentNode.removeChild(this.el_); + if (options.restoreEl) { + this.el_.parentNode.replaceChild(options.restoreEl, this.el_); + } else { + this.el_.parentNode.removeChild(this.el_); + } } - this.el_ = null; - } // remove reference to the player after disposing of the element - + } + // remove reference to the player after disposing of the element this.player_ = null; } + /** * Determine whether or not this component has been disposed. * * @return {boolean} * If the component has been disposed, will be `true`. Otherwise, `false`. */ - ; - - _proto.isDisposed = function isDisposed() { + isDisposed() { return Boolean(this.isDisposed_); } + /** * Return the {@link Player} that the `Component` has attached to. * * @return {Player} * The player that this `Component` has attached to. */ - ; - - _proto.player = function player() { + player() { return this.player_; } + /** * Deep merge of options objects with new options. * > Note: When both `obj` and `options` contain properties whose values are objects. - * The two properties get merged using {@link module:mergeOptions} + * The two properties get merged using {@link module:obj.merge} * * @param {Object} obj * The object that contains new options. @@ -4151,27 +3775,24 @@ * @return {Object} * A new object of `this.options_` and `obj` merged together. */ - ; - - _proto.options = function options(obj) { + options(obj) { if (!obj) { return this.options_; } - - this.options_ = mergeOptions$3(this.options_, obj); + this.options_ = merge$2(this.options_, obj); return this.options_; } + /** * Get the `Component`s DOM element * * @return {Element} * The DOM element for this `Component`. */ - ; - - _proto.el = function el() { + el() { return this.el_; } + /** * Create the `Component`s DOM element. * @@ -4187,11 +3808,10 @@ * @return {Element} * The element that gets created. */ - ; - - _proto.createEl = function createEl$1(tagName, properties, attributes) { + createEl(tagName, properties, attributes) { return createEl(tagName, properties, attributes); } + /** * Localize a string given the string in english. * @@ -4230,49 +3850,38 @@ * @return {string} * The localized string or if no localization exists the english string. */ - ; - - _proto.localize = function localize(string, tokens, defaultValue) { - if (defaultValue === void 0) { - defaultValue = string; - } - - var code = this.player_.language && this.player_.language(); - var languages = this.player_.languages && this.player_.languages(); - var language = languages && languages[code]; - var primaryCode = code && code.split('-')[0]; - var primaryLang = languages && languages[primaryCode]; - var localizedString = defaultValue; - + localize(string, tokens, defaultValue = string) { + const code = this.player_.language && this.player_.language(); + const languages = this.player_.languages && this.player_.languages(); + const language = languages && languages[code]; + const primaryCode = code && code.split('-')[0]; + const primaryLang = languages && languages[primaryCode]; + let localizedString = defaultValue; if (language && language[string]) { localizedString = language[string]; } else if (primaryLang && primaryLang[string]) { localizedString = primaryLang[string]; } - if (tokens) { localizedString = localizedString.replace(/\{(\d+)\}/g, function (match, index) { - var value = tokens[index - 1]; - var ret = value; - + const value = tokens[index - 1]; + let ret = value; if (typeof value === 'undefined') { ret = match; } - return ret; }); } - return localizedString; } + /** - * Handles language change for the player in components. Should be overriden by sub-components. + * Handles language change for the player in components. Should be overridden by sub-components. * * @abstract */ - ; + handleLanguagechange() {} - _proto.handleLanguagechange = function handleLanguagechange() {} /** * Return the `Component`s DOM element. This is where children get inserted. * This will usually be the the same as the element returned in {@link Component#el}. @@ -4280,22 +3889,20 @@ * @return {Element} * The content element for this `Component`. */ - ; - - _proto.contentEl = function contentEl() { + contentEl() { return this.contentEl_ || this.el_; } + /** * Get this `Component`s ID * * @return {string} * The id of this `Component` */ - ; - - _proto.id = function id() { + id() { return this.id_; } + /** * Get the `Component`s name. The name gets used to reference the `Component` * and is set during registration. @@ -4303,22 +3910,20 @@ * @return {string} * The name of this `Component`. */ - ; - - _proto.name = function name() { + name() { return this.name_; } + /** * Get an array of all child components * * @return {Array} * The children */ - ; - - _proto.children = function children() { + children() { return this.children_; } + /** * Returns the child `Component` with the given `id`. * @@ -4328,11 +3933,10 @@ * @return {Component|undefined} * The child `Component` with the given `id` or undefined. */ - ; - - _proto.getChildById = function getChildById(id) { + getChildById(id) { return this.childIndex_[id]; } + /** * Returns the child `Component` with the given `name`. * @@ -4342,15 +3946,13 @@ * @return {Component|undefined} * The child `Component` with the given `name` or undefined. */ - ; - - _proto.getChild = function getChild(name) { + getChild(name) { if (!name) { return; } - return this.childNameIndex_[name]; } + /** * Returns the descendant `Component` following the givent * descendant `names`. For instance ['foo', 'bar', 'baz'] would @@ -4365,33 +3967,69 @@ * The descendant `Component` following the given descendant * `names` or undefined. */ - ; - - _proto.getDescendant = function getDescendant() { - for (var _len = arguments.length, names = new Array(_len), _key = 0; _key < _len; _key++) { - names[_key] = arguments[_key]; - } - + getDescendant(...names) { // flatten array argument into the main array - names = names.reduce(function (acc, n) { - return acc.concat(n); - }, []); - var currentChild = this; - - for (var i = 0; i < names.length; i++) { + names = names.reduce((acc, n) => acc.concat(n), []); + let currentChild = this; + for (let i = 0; i < names.length; i++) { currentChild = currentChild.getChild(names[i]); - if (!currentChild || !currentChild.getChild) { return; } } - return currentChild; } + + /** + * Adds an SVG icon element to another element or component. + * + * @param {string} iconName + * The name of icon. A list of all the icon names can be found at 'sandbox/svg-icons.html' + * + * @param {Element} [el=this.el()] + * Element to set the title on. Defaults to the current Component's element. + * + * @return {Element} + * The newly created icon element. + */ + setIcon(iconName, el = this.el()) { + // TODO: In v9 of video.js, we will want to remove font icons entirely. + // This means this check, as well as the others throughout the code, and + // the unecessary CSS for font icons, will need to be removed. + // See https://github.com/videojs/video.js/pull/8260 as to which components + // need updating. + if (!this.player_.options_.experimentalSvgIcons) { + return; + } + const xmlnsURL = 'http://www.w3.org/2000/svg'; + + // The below creates an element in the format of: + // .... + const iconContainer = createEl('span', { + className: 'vjs-icon-placeholder vjs-svg-icon' + }, { + 'aria-hidden': 'true' + }); + const svgEl = document.createElementNS(xmlnsURL, 'svg'); + svgEl.setAttributeNS(null, 'viewBox', '0 0 512 512'); + const useEl = document.createElementNS(xmlnsURL, 'use'); + svgEl.appendChild(useEl); + useEl.setAttributeNS(null, 'href', `#vjs-icon-${iconName}`); + iconContainer.appendChild(svgEl); + + // Replace a pre-existing icon if one exists. + if (this.iconIsSet_) { + el.replaceChild(iconContainer, el.querySelector('.vjs-icon-placeholder')); + } else { + el.appendChild(iconContainer); + } + this.iconIsSet_ = true; + return iconContainer; + } + /** * Add a child `Component` inside the current `Component`. * - * * @param {string|Component} child * The name or instance of a child to add. * @@ -4402,76 +4040,65 @@ * @param {number} [index=this.children_.length] * The index to attempt to add a child into. * + * * @return {Component} * The `Component` that gets added as a child. When using a string the * `Component` will get created by this process. */ - ; - - _proto.addChild = function addChild(child, options, index) { - if (options === void 0) { - options = {}; - } - - if (index === void 0) { - index = this.children_.length; - } - - var component; - var componentName; // If child is a string, create component with options + addChild(child, options = {}, index = this.children_.length) { + let component; + let componentName; + // If child is a string, create component with options if (typeof child === 'string') { componentName = toTitleCase$1(child); - var componentClassName = options.componentClass || componentName; // Set name through options + const componentClassName = options.componentClass || componentName; - options.name = componentName; // Create a new object & element for this controls set + // Set name through options + options.name = componentName; + + // Create a new object & element for this controls set // If there's no .player_, this is a player - - var ComponentClass = Component.getComponent(componentClassName); - + const ComponentClass = Component$1.getComponent(componentClassName); if (!ComponentClass) { - throw new Error("Component " + componentClassName + " does not exist"); - } // data stored directly on the videojs object may be + throw new Error(`Component ${componentClassName} does not exist`); + } + + // data stored directly on the videojs object may be // misidentified as a component to retain // backwards-compatibility with 4.x. check to make sure the // component class can be instantiated. - - if (typeof ComponentClass !== 'function') { return null; } + component = new ComponentClass(this.player_ || this, options); - component = new ComponentClass(this.player_ || this, options); // child is a component instance + // child is a component instance } else { component = child; } - if (component.parentComponent_) { component.parentComponent_.removeChild(component); } - this.children_.splice(index, 0, component); component.parentComponent_ = this; - if (typeof component.id === 'function') { this.childIndex_[component.id()] = component; - } // If a name wasn't used to create the component, check if we can use the + } + + // If a name wasn't used to create the component, check if we can use the // name function of the component - - componentName = componentName || component.name && toTitleCase$1(component.name()); - if (componentName) { this.childNameIndex_[componentName] = component; this.childNameIndex_[toLowerCase(componentName)] = component; - } // Add the UI object's element to the container div (box) + } + + // Add the UI object's element to the container div (box) // Having an element is not required - - if (typeof component.el === 'function' && component.el()) { // If inserting before a component, insert before that component's element - var refNode = null; - + let refNode = null; if (this.children_[index + 1]) { // Most children are components, but the video tech is an HTML element if (this.children_[index + 1].el_) { @@ -4480,13 +4107,13 @@ refNode = this.children_[index + 1]; } } - this.contentEl().insertBefore(component.el(), refNode); - } // Return so it can stored on parent object if desired. - + } + // Return so it can stored on parent object if desired. return component; } + /** * Remove a child `Component` from this `Component`s list of children. Also removes * the child `Component`s element from this `Component`s element. @@ -4494,177 +4121,153 @@ * @param {Component} component * The child `Component` to remove. */ - ; - - _proto.removeChild = function removeChild(component) { + removeChild(component) { if (typeof component === 'string') { component = this.getChild(component); } - if (!component || !this.children_) { return; } - - var childFound = false; - - for (var i = this.children_.length - 1; i >= 0; i--) { + let childFound = false; + for (let i = this.children_.length - 1; i >= 0; i--) { if (this.children_[i] === component) { childFound = true; this.children_.splice(i, 1); break; } } - if (!childFound) { return; } - component.parentComponent_ = null; this.childIndex_[component.id()] = null; this.childNameIndex_[toTitleCase$1(component.name())] = null; this.childNameIndex_[toLowerCase(component.name())] = null; - var compEl = component.el(); - + const compEl = component.el(); if (compEl && compEl.parentNode === this.contentEl()) { this.contentEl().removeChild(component.el()); } } + /** * Add and initialize default child `Component`s based upon options. */ - ; - - _proto.initChildren = function initChildren() { - var _this2 = this; - - var children = this.options_.children; - + initChildren() { + const children = this.options_.children; if (children) { // `this` is `parent` - var parentOptions = this.options_; + const parentOptions = this.options_; + const handleAdd = child => { + const name = child.name; + let opts = child.opts; - var handleAdd = function handleAdd(child) { - var name = child.name; - var opts = child.opts; // Allow options for children to be set at the parent options + // Allow options for children to be set at the parent options // e.g. videojs(id, { controlBar: false }); // instead of videojs(id, { children: { controlBar: false }); - if (parentOptions[name] !== undefined) { opts = parentOptions[name]; - } // Allow for disabling default components + } + + // Allow for disabling default components // e.g. options['children']['posterImage'] = false - - if (opts === false) { return; - } // Allow options to be passed as a simple boolean if no configuration + } + + // Allow options to be passed as a simple boolean if no configuration // is necessary. - - if (opts === true) { opts = {}; - } // We also want to pass the original player options + } + + // We also want to pass the original player options // to each component as well so they don't need to // reach back into the player for options later. + opts.playerOptions = this.options_.playerOptions; - - opts.playerOptions = _this2.options_.playerOptions; // Create and add the child component. + // Create and add the child component. // Add a direct reference to the child by name on the parent instance. // If two of the same component are used, different names should be supplied // for each - - var newChild = _this2.addChild(name, opts); - + const newChild = this.addChild(name, opts); if (newChild) { - _this2[name] = newChild; + this[name] = newChild; } - }; // Allow for an array of children details to passed in the options - - - var workingChildren; - var Tech = Component.getComponent('Tech'); + }; + // Allow for an array of children details to passed in the options + let workingChildren; + const Tech = Component$1.getComponent('Tech'); if (Array.isArray(children)) { workingChildren = children; } else { workingChildren = Object.keys(children); } - - workingChildren // children that are in this.options_ but also in workingChildren would + workingChildren + // children that are in this.options_ but also in workingChildren would // give us extra children we do not want. So, we want to filter them out. .concat(Object.keys(this.options_).filter(function (child) { return !workingChildren.some(function (wchild) { if (typeof wchild === 'string') { return child === wchild; } - return child === wchild.name; }); - })).map(function (child) { - var name; - var opts; - + })).map(child => { + let name; + let opts; if (typeof child === 'string') { name = child; - opts = children[name] || _this2.options_[name] || {}; + opts = children[name] || this.options_[name] || {}; } else { name = child.name; opts = child; } - return { - name: name, - opts: opts + name, + opts }; - }).filter(function (child) { + }).filter(child => { // we have to make sure that child.name isn't in the techOrder since - // techs are registerd as Components but can't aren't compatible + // techs are registered as Components but can't aren't compatible // See https://github.com/videojs/video.js/issues/2772 - var c = Component.getComponent(child.opts.componentClass || toTitleCase$1(child.name)); + const c = Component$1.getComponent(child.opts.componentClass || toTitleCase$1(child.name)); return c && !Tech.isTech(c); }).forEach(handleAdd); } } + /** - * Builds the default DOM class name. Should be overriden by sub-components. + * Builds the default DOM class name. Should be overridden by sub-components. * * @return {string} * The DOM class name for this object. * * @abstract */ - ; - - _proto.buildCSSClass = function buildCSSClass() { + buildCSSClass() { // Child classes can include a function that does: // return 'CLASS NAME' + this._super(); return ''; } + /** * Bind a listener to the component's ready state. * Different from event listeners in that if the ready event has already happened * it will trigger the function immediately. * - * @return {Component} - * Returns itself; method can be chained. + * @param {ReadyCallback} fn + * Function that gets called when the `Component` is ready. */ - ; - - _proto.ready = function ready(fn, sync) { - if (sync === void 0) { - sync = false; - } - + ready(fn, sync = false) { if (!fn) { return; } - if (!this.isReady_) { this.readyQueue_ = this.readyQueue_ || []; this.readyQueue_.push(fn); return; } - if (sync) { fn.call(this); } else { @@ -4672,38 +4275,38 @@ this.setTimeout(fn, 1); } } + /** * Trigger all the ready listeners for this `Component`. * * @fires Component#ready */ - ; - - _proto.triggerReady = function triggerReady() { - this.isReady_ = true; // Ensure ready is triggered asynchronously + triggerReady() { + this.isReady_ = true; + // Ensure ready is triggered asynchronously this.setTimeout(function () { - var readyQueue = this.readyQueue_; // Reset Ready Queue + const readyQueue = this.readyQueue_; + // Reset Ready Queue this.readyQueue_ = []; - if (readyQueue && readyQueue.length > 0) { readyQueue.forEach(function (fn) { fn.call(this); }, this); - } // Allow for using event listeners also + } + // Allow for using event listeners also /** * Triggered when a `Component` is ready. * * @event Component#ready - * @type {EventTarget~Event} + * @type {Event} */ - - this.trigger('ready'); }, 1); } + /** * Find a single DOM element matching a `selector`. This can be within the `Component`s * `contentEl()` or another custom context. @@ -4722,11 +4325,10 @@ * * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors) */ - ; - - _proto.$ = function $$1(selector, context) { + $(selector, context) { return $(selector, context || this.contentEl()); } + /** * Finds all DOM element matching a `selector`. This can be within the `Component`s * `contentEl()` or another custom context. @@ -4745,11 +4347,10 @@ * * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors) */ - ; - - _proto.$$ = function $$$1(selector, context) { + $$(selector, context) { return $$(selector, context || this.contentEl()); } + /** * Check if a component's element has a CSS class name. * @@ -4760,33 +4361,30 @@ * - True if the `Component` has the class. * - False if the `Component` does not have the class` */ - ; - - _proto.hasClass = function hasClass$1(classToCheck) { + hasClass(classToCheck) { return hasClass(this.el_, classToCheck); } + /** * Add a CSS class name to the `Component`s element. * - * @param {string} classToAdd - * CSS class name to add + * @param {...string} classesToAdd + * One or more CSS class name to add. */ - ; - - _proto.addClass = function addClass$1(classToAdd) { - addClass(this.el_, classToAdd); + addClass(...classesToAdd) { + addClass(this.el_, ...classesToAdd); } + /** * Remove a CSS class name from the `Component`s element. * - * @param {string} classToRemove - * CSS class name to remove + * @param {...string} classesToRemove + * One or more CSS class name to remove. */ - ; - - _proto.removeClass = function removeClass$1(classToRemove) { - removeClass(this.el_, classToRemove); + removeClass(...classesToRemove) { + removeClass(this.el_, ...classesToRemove); } + /** * Add or remove a CSS class name from the component's element. * - `classToToggle` gets added when {@link Component#hasClass} would return false. @@ -4798,51 +4396,46 @@ * @param {boolean|Dom~predicate} [predicate] * An {@link Dom~predicate} function or a boolean */ - ; - - _proto.toggleClass = function toggleClass$1(classToToggle, predicate) { + toggleClass(classToToggle, predicate) { toggleClass(this.el_, classToToggle, predicate); } + /** * Show the `Component`s element if it is hidden by removing the * 'vjs-hidden' class name from it. */ - ; - - _proto.show = function show() { + show() { this.removeClass('vjs-hidden'); } + /** * Hide the `Component`s element if it is currently showing by adding the * 'vjs-hidden` class name to it. */ - ; - - _proto.hide = function hide() { + hide() { this.addClass('vjs-hidden'); } + /** * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing' * class name to it. Used during fadeIn/fadeOut. * * @private */ - ; - - _proto.lockShowing = function lockShowing() { + lockShowing() { this.addClass('vjs-lock-showing'); } + /** * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing' * class name from it. Used during fadeIn/fadeOut. * * @private */ - ; - - _proto.unlockShowing = function unlockShowing() { + unlockShowing() { this.removeClass('vjs-lock-showing'); } + /** * Get the value of an attribute on the `Component`s element. * @@ -4853,16 +4446,15 @@ * - The value of the attribute that was asked for. * - Can be an empty string on some browsers if the attribute does not exist * or has no value - * - Most browsers will return null if the attibute does not exist or has + * - Most browsers will return null if the attribute does not exist or has * no value. * * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute} */ - ; - - _proto.getAttribute = function getAttribute$1(attribute) { + getAttribute(attribute) { return getAttribute(this.el_, attribute); } + /** * Set the value of an attribute on the `Component`'s element * @@ -4874,11 +4466,10 @@ * * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute} */ - ; - - _proto.setAttribute = function setAttribute$1(attribute, value) { + setAttribute(attribute, value) { setAttribute(this.el_, attribute, value); } + /** * Remove an attribute from the `Component`s element. * @@ -4887,11 +4478,10 @@ * * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute} */ - ; - - _proto.removeAttribute = function removeAttribute$1(attribute) { + removeAttribute(attribute) { removeAttribute(this.el_, attribute); } + /** * Get or set the width of the component based upon the CSS styles. * See {@link Component#dimension} for more detailed information. @@ -4902,15 +4492,13 @@ * @param {boolean} [skipListeners] * Skip the componentresize event trigger * - * @return {number|string} - * The width when getting, zero if there is no width. Can be a string - * postpixed with '%' or 'px'. + * @return {number|undefined} + * The width when getting, zero if there is no width */ - ; - - _proto.width = function width(num, skipListeners) { + width(num, skipListeners) { return this.dimension('width', num, skipListeners); } + /** * Get or set the height of the component based upon the CSS styles. * See {@link Component#dimension} for more detailed information. @@ -4921,15 +4509,13 @@ * @param {boolean} [skipListeners] * Skip the componentresize event trigger * - * @return {number|string} - * The width when getting, zero if there is no width. Can be a string - * postpixed with '%' or 'px'. + * @return {number|undefined} + * The height when getting, zero if there is no height */ - ; - - _proto.height = function height(num, skipListeners) { + height(num, skipListeners) { return this.dimension('height', num, skipListeners); } + /** * Set both the width and height of the `Component` element at the same time. * @@ -4939,13 +4525,12 @@ * @param {number|string} height * Height to set the `Component`s element to. */ - ; - - _proto.dimensions = function dimensions(width, height) { + dimensions(width, height) { // Skip componentresize listeners on width for optimization this.width(width, true); this.height(height); } + /** * Get or set width or height of the `Component` element. This is the shared code * for the {@link Component#width} and {@link Component#height}. @@ -4971,61 +4556,58 @@ * @param {boolean} [skipListeners] * Skip componentresize event trigger * - * @return {number} + * @return {number|undefined} * The dimension when getting or 0 if unset */ - ; - - _proto.dimension = function dimension(widthOrHeight, num, skipListeners) { + dimension(widthOrHeight, num, skipListeners) { if (num !== undefined) { // Set to zero if null or literally NaN (NaN !== NaN) if (num === null || num !== num) { num = 0; - } // Check if using css width/height (% or px) and adjust - + } + // Check if using css width/height (% or px) and adjust if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) { this.el_.style[widthOrHeight] = num; } else if (num === 'auto') { this.el_.style[widthOrHeight] = ''; } else { this.el_.style[widthOrHeight] = num + 'px'; - } // skipListeners allows us to avoid triggering the resize event when setting both width and height - + } + // skipListeners allows us to avoid triggering the resize event when setting both width and height if (!skipListeners) { /** * Triggered when a component is resized. * * @event Component#componentresize - * @type {EventTarget~Event} + * @type {Event} */ this.trigger('componentresize'); } - return; - } // Not setting a value, so getting it + } + + // Not setting a value, so getting it // Make sure element exists - - if (!this.el_) { return 0; - } // Get dimension value from style - - - var val = this.el_.style[widthOrHeight]; - var pxIndex = val.indexOf('px'); + } + // Get dimension value from style + const val = this.el_.style[widthOrHeight]; + const pxIndex = val.indexOf('px'); if (pxIndex !== -1) { // Return the pixel value with no 'px' return parseInt(val.slice(0, pxIndex), 10); - } // No px so using % or no style was set, so falling back to offsetWidth/height + } + + // No px so using % or no style was set, so falling back to offsetWidth/height // If component has display:none, offset will return 0 // TODO: handle display:none and no dimension style using px - - return parseInt(this.el_['offset' + toTitleCase$1(widthOrHeight)], 10); } + /** * Get the computed width or the height of the component's element. * @@ -5038,28 +4620,26 @@ * The dimension that gets asked for or 0 if nothing was set * for that dimension. */ - ; - - _proto.currentDimension = function currentDimension(widthOrHeight) { - var computedWidthOrHeight = 0; - + currentDimension(widthOrHeight) { + let computedWidthOrHeight = 0; if (widthOrHeight !== 'width' && widthOrHeight !== 'height') { throw new Error('currentDimension only accepts width or height value'); } + computedWidthOrHeight = computedStyle(this.el_, widthOrHeight); - computedWidthOrHeight = computedStyle(this.el_, widthOrHeight); // remove 'px' from variable and parse as integer + // remove 'px' from variable and parse as integer + computedWidthOrHeight = parseFloat(computedWidthOrHeight); - computedWidthOrHeight = parseFloat(computedWidthOrHeight); // if the computed value is still 0, it's possible that the browser is lying + // if the computed value is still 0, it's possible that the browser is lying // and we want to check the offset values. // This code also runs wherever getComputedStyle doesn't exist. - if (computedWidthOrHeight === 0 || isNaN(computedWidthOrHeight)) { - var rule = "offset" + toTitleCase$1(widthOrHeight); + const rule = `offset${toTitleCase$1(widthOrHeight)}`; computedWidthOrHeight = this.el_[rule]; } - return computedWidthOrHeight; } + /** * An object that contains width and height values of the `Component`s * computed style. Uses `window.getComputedStyle`. @@ -5082,14 +4662,13 @@ * @return {Component~DimensionObject} * The computed dimensions of the component's element. */ - ; - - _proto.currentDimensions = function currentDimensions() { + currentDimensions() { return { width: this.currentDimension('width'), height: this.currentDimension('height') }; } + /** * Get the computed width of the component's element. * @@ -5098,11 +4677,10 @@ * @return {number} * The computed width of the component's element. */ - ; - - _proto.currentWidth = function currentWidth() { + currentWidth() { return this.currentDimension('width'); } + /** * Get the computed height of the component's element. * @@ -5111,67 +4689,103 @@ * @return {number} * The computed height of the component's element. */ - ; - - _proto.currentHeight = function currentHeight() { + currentHeight() { return this.currentDimension('height'); } + + /** + * Retrieves the position and size information of the component's element. + * + * @return {Object} An object with `boundingClientRect` and `center` properties. + * - `boundingClientRect`: An object with properties `x`, `y`, `width`, + * `height`, `top`, `right`, `bottom`, and `left`, representing + * the bounding rectangle of the element. + * - `center`: An object with properties `x` and `y`, representing + * the center point of the element. `width` and `height` are set to 0. + */ + getPositions() { + const rect = this.el_.getBoundingClientRect(); + + // Creating objects that mirror DOMRectReadOnly for boundingClientRect and center + const boundingClientRect = { + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + top: rect.top, + right: rect.right, + bottom: rect.bottom, + left: rect.left + }; + + // Calculating the center position + const center = { + x: rect.left + rect.width / 2, + y: rect.top + rect.height / 2, + width: 0, + height: 0, + top: rect.top + rect.height / 2, + right: rect.left + rect.width / 2, + bottom: rect.top + rect.height / 2, + left: rect.left + rect.width / 2 + }; + return { + boundingClientRect, + center + }; + } + /** * Set the focus to this component */ - ; - - _proto.focus = function focus() { + focus() { this.el_.focus(); } + /** * Remove the focus from this component */ - ; - - _proto.blur = function blur() { + blur() { this.el_.blur(); } + /** * When this Component receives a `keydown` event which it does not process, * it passes the event to the Player for handling. * - * @param {EventTarget~Event} event + * @param {KeyboardEvent} event * The `keydown` event that caused this function to be called. */ - ; - - _proto.handleKeyDown = function handleKeyDown(event) { + handleKeyDown(event) { if (this.player_) { // We only stop propagation here because we want unhandled events to fall - // back to the browser. Exclude Tab for focus trapping. - if (!keycode.isEventKey(event, 'Tab')) { + // back to the browser. Exclude Tab for focus trapping, exclude also when spatialNavigation is enabled. + if (event.key !== 'Tab' && !(this.player_.options_.playerOptions.spatialNavigation && this.player_.options_.playerOptions.spatialNavigation.enabled)) { event.stopPropagation(); } - this.player_.handleKeyDown(event); } } + /** * Many components used to have a `handleKeyPress` method, which was poorly * named because it listened to a `keydown` event. This method name now * delegates to `handleKeyDown`. This means anyone calling `handleKeyPress` * will not see their method calls stop working. * - * @param {EventTarget~Event} event + * @param {KeyboardEvent} event * The event that caused this function to be called. */ - ; - - _proto.handleKeyPress = function handleKeyPress(event) { + handleKeyPress(event) { this.handleKeyDown(event); } + /** * Emit a 'tap' events when touch event support gets detected. This gets used to * support toggling the controls through a tap on the video. They get enabled * because every sub-component would have extra overhead otherwise. * - * @private + * @protected * @fires Component#tap * @listens Component#touchstart * @listens Component#touchmove @@ -5179,19 +4793,19 @@ * @listens Component#touchcancel * @listens Component#touchend */ - ; - - _proto.emitTapEvents = function emitTapEvents() { + emitTapEvents() { // Track the start time so we can determine how long the touch lasted - var touchStart = 0; - var firstTouch = null; // Maximum movement allowed during a touch event to still be considered a tap + let touchStart = 0; + let firstTouch = null; + + // Maximum movement allowed during a touch event to still be considered a tap // Other popular libs use anywhere from 2 (hammer.js) to 15, // so 10 seems like a nice, round number. + const tapMovementThreshold = 10; - var tapMovementThreshold = 10; // The maximum length a touch can be while still being considered a tap - - var touchTimeThreshold = 200; - var couldBeTap; + // The maximum length a touch can be while still being considered a tap + const touchTimeThreshold = 200; + let couldBeTap; this.on('touchstart', function (event) { // If more than one finger, don't consider treating this as a click if (event.touches.length === 1) { @@ -5199,10 +4813,10 @@ firstTouch = { pageX: event.touches[0].pageX, pageY: event.touches[0].pageY - }; // Record start time so we can detect a tap vs. "touch and hold" - - touchStart = window.performance.now(); // Reset couldBeTap tracking - + }; + // Record start time so we can detect a tap vs. "touch and hold" + touchStart = window.performance.now(); + // Reset couldBeTap tracking couldBeTap = true; } }); @@ -5213,32 +4827,32 @@ } else if (firstTouch) { // Some devices will throw touchmoves for all but the slightest of taps. // So, if we moved only a small distance, this could still be a tap - var xdiff = event.touches[0].pageX - firstTouch.pageX; - var ydiff = event.touches[0].pageY - firstTouch.pageY; - var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff); - + const xdiff = event.touches[0].pageX - firstTouch.pageX; + const ydiff = event.touches[0].pageY - firstTouch.pageY; + const touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff); if (touchDistance > tapMovementThreshold) { couldBeTap = false; } } }); - - var noTap = function noTap() { + const noTap = function () { couldBeTap = false; - }; // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s - + }; + // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s this.on('touchleave', noTap); - this.on('touchcancel', noTap); // When the touch ends, measure how long it took and trigger the appropriate + this.on('touchcancel', noTap); + + // When the touch ends, measure how long it took and trigger the appropriate // event - this.on('touchend', function (event) { - firstTouch = null; // Proceed only if the touchmove/leave/cancel event didn't happen - + firstTouch = null; + // Proceed only if the touchmove/leave/cancel event didn't happen if (couldBeTap === true) { // Measure how long the touch lasted - var touchTime = window.performance.now() - touchStart; // Make sure the touch was less than the threshold to be considered a tap + const touchTime = window.performance.now() - touchStart; + // Make sure the touch was less than the threshold to be considered a tap if (touchTime < touchTimeThreshold) { // Don't let browser turn this into a click event.preventDefault(); @@ -5246,16 +4860,17 @@ * Triggered when a `Component` is tapped. * * @event Component#tap - * @type {EventTarget~Event} + * @type {MouseEvent} */ - - this.trigger('tap'); // It may be good to copy the touchend event object and change the + this.trigger('tap'); + // It may be good to copy the touchend event object and change the // type to tap, if the other event properties aren't exact after // Events.fixEvent runs (e.g. event.target) } } }); } + /** * This function reports user activity whenever touch events happen. This can get * turned off by any sub-components that wants touch events to act another way. @@ -5279,37 +4894,34 @@ * @listens Component#touchend * @listens Component#touchcancel */ - ; - - _proto.enableTouchActivity = function enableTouchActivity() { + enableTouchActivity() { // Don't continue if the root player doesn't support reporting user activity if (!this.player() || !this.player().reportUserActivity) { return; - } // listener for reporting that the user is active + } - - var report = bind(this.player(), this.player().reportUserActivity); - var touchHolding; + // listener for reporting that the user is active + const report = bind_(this.player(), this.player().reportUserActivity); + let touchHolding; this.on('touchstart', function () { - report(); // For as long as the they are touching the device or have their mouse down, + report(); + // For as long as the they are touching the device or have their mouse down, // we consider them active even if they're not moving their finger or mouse. // So we want to continue to update that they are active - - this.clearInterval(touchHolding); // report at the same interval as activityCheck - + this.clearInterval(touchHolding); + // report at the same interval as activityCheck touchHolding = this.setInterval(report, 250); }); - - var touchEnd = function touchEnd(event) { - report(); // stop the interval that maintains activity if the touch is holding - + const touchEnd = function (event) { + report(); + // stop the interval that maintains activity if the touch is holding this.clearInterval(touchHolding); }; - this.on('touchmove', report); this.on('touchend', touchEnd); this.on('touchcancel', touchEnd); } + /** * A callback that has no parameters and is bound into `Component`s context. * @@ -5343,26 +4955,22 @@ * @listens Component#dispose * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout} */ - ; - - _proto.setTimeout = function setTimeout(fn, timeout) { - var _this3 = this; - + setTimeout(fn, timeout) { // declare as variables so they are properly available in timeout function // eslint-disable-next-line var timeoutId; - fn = bind(this, fn); + fn = bind_(this, fn); this.clearTimersOnDispose_(); - timeoutId = window.setTimeout(function () { - if (_this3.setTimeoutIds_.has(timeoutId)) { - _this3.setTimeoutIds_["delete"](timeoutId); + timeoutId = window.setTimeout(() => { + if (this.setTimeoutIds_.has(timeoutId)) { + this.setTimeoutIds_.delete(timeoutId); } - fn(); }, timeout); this.setTimeoutIds_.add(timeoutId); return timeoutId; } + /** * Clears a timeout that gets created via `window.setTimeout` or * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout} @@ -5378,16 +4986,14 @@ * * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout} */ - ; - - _proto.clearTimeout = function clearTimeout(timeoutId) { + clearTimeout(timeoutId) { if (this.setTimeoutIds_.has(timeoutId)) { - this.setTimeoutIds_["delete"](timeoutId); + this.setTimeoutIds_.delete(timeoutId); window.clearTimeout(timeoutId); } - return timeoutId; } + /** * Creates a function that gets run every `x` milliseconds. This function is a wrapper * around `window.setInterval`. There are a few reasons to use this one instead though. @@ -5408,18 +5014,17 @@ * @listens Component#dispose * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval} */ - ; - - _proto.setInterval = function setInterval(fn, interval) { - fn = bind(this, fn); + setInterval(fn, interval) { + fn = bind_(this, fn); this.clearTimersOnDispose_(); - var intervalId = window.setInterval(fn, interval); + const intervalId = window.setInterval(fn, interval); this.setIntervalIds_.add(intervalId); return intervalId; } + /** * Clears an interval that gets created via `window.setInterval` or - * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval} + * {@link Component#setInterval}. If you set an interval via {@link Component#setInterval} * use this function instead of `window.clearInterval`. If you don't your dispose * listener will not get cleaned up until {@link Component#dispose}! * @@ -5432,16 +5037,14 @@ * * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval} */ - ; - - _proto.clearInterval = function clearInterval(intervalId) { + clearInterval(intervalId) { if (this.setIntervalIds_.has(intervalId)) { - this.setIntervalIds_["delete"](intervalId); + this.setIntervalIds_.delete(intervalId); window.clearInterval(intervalId); } - return intervalId; } + /** * Queues up a callback to be passed to requestAnimationFrame (rAF), but * with a few extra bonuses: @@ -5467,31 +5070,23 @@ * @listens Component#dispose * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame} */ - ; + requestAnimationFrame(fn) { + this.clearTimersOnDispose_(); - _proto.requestAnimationFrame = function requestAnimationFrame(fn) { - var _this4 = this; - - // Fall back to using a timer. - if (!this.supportsRaf_) { - return this.setTimeout(fn, 1000 / 60); - } - - this.clearTimersOnDispose_(); // declare as variables so they are properly available in rAF function + // declare as variables so they are properly available in rAF function // eslint-disable-next-line - var id; - fn = bind(this, fn); - id = window.requestAnimationFrame(function () { - if (_this4.rafIds_.has(id)) { - _this4.rafIds_["delete"](id); + fn = bind_(this, fn); + id = window.requestAnimationFrame(() => { + if (this.rafIds_.has(id)) { + this.rafIds_.delete(id); } - fn(); }); this.rafIds_.add(id); return id; } + /** * Request an animation frame, but only one named animation * frame will be queued. Another will never be added until @@ -5504,43 +5099,36 @@ * A function that will be bound to this component and executed just * before the browser's next repaint. */ - ; - - _proto.requestNamedAnimationFrame = function requestNamedAnimationFrame(name, fn) { - var _this5 = this; - + requestNamedAnimationFrame(name, fn) { if (this.namedRafs_.has(name)) { return; } - this.clearTimersOnDispose_(); - fn = bind(this, fn); - var id = this.requestAnimationFrame(function () { + fn = bind_(this, fn); + const id = this.requestAnimationFrame(() => { fn(); - - if (_this5.namedRafs_.has(name)) { - _this5.namedRafs_["delete"](name); + if (this.namedRafs_.has(name)) { + this.namedRafs_.delete(name); } }); this.namedRafs_.set(name, id); return name; } + /** * Cancels a current named animation frame if it exists. * * @param {string} name * The name of the requestAnimationFrame to cancel. */ - ; - - _proto.cancelNamedAnimationFrame = function cancelNamedAnimationFrame(name) { + cancelNamedAnimationFrame(name) { if (!this.namedRafs_.has(name)) { return; } - this.cancelAnimationFrame(this.namedRafs_.get(name)); - this.namedRafs_["delete"](name); + this.namedRafs_.delete(name); } + /** * Cancels a queued callback passed to {@link Component#requestAnimationFrame} * (rAF). @@ -5557,21 +5145,14 @@ * * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/cancelAnimationFrame} */ - ; - - _proto.cancelAnimationFrame = function cancelAnimationFrame(id) { - // Fall back to using a timer. - if (!this.supportsRaf_) { - return this.clearTimeout(id); - } - + cancelAnimationFrame(id) { if (this.rafIds_.has(id)) { - this.rafIds_["delete"](id); + this.rafIds_.delete(id); window.cancelAnimationFrame(id); } - return id; } + /** * A function to setup `requestAnimationFrame`, `setTimeout`, * and `setInterval`, clearing on dispose. @@ -5582,31 +5163,166 @@ * * @private */ - ; - - _proto.clearTimersOnDispose_ = function clearTimersOnDispose_() { - var _this6 = this; - + clearTimersOnDispose_() { if (this.clearingTimersOnDispose_) { return; } - this.clearingTimersOnDispose_ = true; - this.one('dispose', function () { - [['namedRafs_', 'cancelNamedAnimationFrame'], ['rafIds_', 'cancelAnimationFrame'], ['setTimeoutIds_', 'clearTimeout'], ['setIntervalIds_', 'clearInterval']].forEach(function (_ref) { - var idName = _ref[0], - cancelName = _ref[1]; - + this.one('dispose', () => { + [['namedRafs_', 'cancelNamedAnimationFrame'], ['rafIds_', 'cancelAnimationFrame'], ['setTimeoutIds_', 'clearTimeout'], ['setIntervalIds_', 'clearInterval']].forEach(([idName, cancelName]) => { // for a `Set` key will actually be the value again // so forEach((val, val) =>` but for maps we want to use // the key. - _this6[idName].forEach(function (val, key) { - return _this6[cancelName](key); - }); + this[idName].forEach((val, key) => this[cancelName](key)); }); - _this6.clearingTimersOnDispose_ = false; + this.clearingTimersOnDispose_ = false; }); } + + /** + * Decide whether an element is actually disabled or not. + * + * @function isActuallyDisabled + * @param element {Node} + * @return {boolean} + * + * @see {@link https://html.spec.whatwg.org/multipage/semantics-other.html#concept-element-disabled} + */ + getIsDisabled() { + return Boolean(this.el_.disabled); + } + + /** + * Decide whether the element is expressly inert or not. + * + * @see {@link https://html.spec.whatwg.org/multipage/interaction.html#expressly-inert} + * @function isExpresslyInert + * @param element {Node} + * @return {boolean} + */ + getIsExpresslyInert() { + return this.el_.inert && !this.el_.ownerDocument.documentElement.inert; + } + + /** + * Determine whether or not this component can be considered as focusable component. + * + * @param {HTMLElement} el - The HTML element representing the component. + * @return {boolean} + * If the component can be focused, will be `true`. Otherwise, `false`. + */ + getIsFocusable(el) { + const element = el || this.el_; + return element.tabIndex >= 0 && !(this.getIsDisabled() || this.getIsExpresslyInert()); + } + + /** + * Determine whether or not this component is currently visible/enabled/etc... + * + * @param {HTMLElement} el - The HTML element representing the component. + * @return {boolean} + * If the component can is currently visible & enabled, will be `true`. Otherwise, `false`. + */ + getIsAvailableToBeFocused(el) { + /** + * Decide the style property of this element is specified whether it's visible or not. + * + * @function isVisibleStyleProperty + * @param element {CSSStyleDeclaration} + * @return {boolean} + */ + function isVisibleStyleProperty(element) { + const elementStyle = window.getComputedStyle(element, null); + const thisVisibility = elementStyle.getPropertyValue('visibility'); + const thisDisplay = elementStyle.getPropertyValue('display'); + const invisibleStyle = ['hidden', 'collapse']; + return thisDisplay !== 'none' && !invisibleStyle.includes(thisVisibility); + } + + /** + * Decide whether the element is being rendered or not. + * 1. If an element has the style as "visibility: hidden | collapse" or "display: none", it is not being rendered. + * 2. If an element has the style as "opacity: 0", it is not being rendered.(that is, invisible). + * 3. If width and height of an element are explicitly set to 0, it is not being rendered. + * 4. If a parent element is hidden, an element itself is not being rendered. + * (CSS visibility property and display property are inherited.) + * + * @see {@link https://html.spec.whatwg.org/multipage/rendering.html#being-rendered} + * @function isBeingRendered + * @param element {Node} + * @return {boolean} + */ + function isBeingRendered(element) { + if (!isVisibleStyleProperty(element.parentElement)) { + return false; + } + if (!isVisibleStyleProperty(element) || element.style.opacity === '0' || window.getComputedStyle(element).height === '0px' || window.getComputedStyle(element).width === '0px') { + return false; + } + return true; + } + + /** + * Determine if the element is visible for the user or not. + * 1. If an element sum of its offsetWidth, offsetHeight, height and width is less than 1 is not visible. + * 2. If elementCenter.x is less than is not visible. + * 3. If elementCenter.x is more than the document's width is not visible. + * 4. If elementCenter.y is less than 0 is not visible. + * 5. If elementCenter.y is the document's height is not visible. + * + * @function isVisible + * @param element {Node} + * @return {boolean} + */ + function isVisible(element) { + if (element.offsetWidth + element.offsetHeight + element.getBoundingClientRect().height + element.getBoundingClientRect().width === 0) { + return false; + } + + // Define elementCenter object with props of x and y + // x: Left position relative to the viewport plus element's width (no margin) divided between 2. + // y: Top position relative to the viewport plus element's height (no margin) divided between 2. + const elementCenter = { + x: element.getBoundingClientRect().left + element.offsetWidth / 2, + y: element.getBoundingClientRect().top + element.offsetHeight / 2 + }; + if (elementCenter.x < 0) { + return false; + } + if (elementCenter.x > (document.documentElement.clientWidth || window.innerWidth)) { + return false; + } + if (elementCenter.y < 0) { + return false; + } + if (elementCenter.y > (document.documentElement.clientHeight || window.innerHeight)) { + return false; + } + let pointContainer = document.elementFromPoint(elementCenter.x, elementCenter.y); + while (pointContainer) { + if (pointContainer === element) { + return true; + } + if (pointContainer.parentNode) { + pointContainer = pointContainer.parentNode; + } else { + return false; + } + } + } + + // If no DOM element was passed as argument use this component's element. + if (!el) { + el = this.el(); + } + + // If element is visible, is being rendered & either does not have a parent element or its tabIndex is not negative. + if (isVisible(el) && isBeingRendered(el) && (!el.parentElement || el.tabIndex >= 0)) { + return true; + } + return false; + } + /** * Register a `Component` with `videojs` given the name and the component. * @@ -5626,111 +5342,67 @@ * @return {Component} * The `Component` that was registered. */ - ; - - Component.registerComponent = function registerComponent(name, ComponentToRegister) { + static registerComponent(name, ComponentToRegister) { if (typeof name !== 'string' || !name) { - throw new Error("Illegal component name, \"" + name + "\"; must be a non-empty string."); + throw new Error(`Illegal component name, "${name}"; must be a non-empty string.`); } + const Tech = Component$1.getComponent('Tech'); - var Tech = Component.getComponent('Tech'); // We need to make sure this check is only done if Tech has been registered. - - var isTech = Tech && Tech.isTech(ComponentToRegister); - var isComp = Component === ComponentToRegister || Component.prototype.isPrototypeOf(ComponentToRegister.prototype); - + // We need to make sure this check is only done if Tech has been registered. + const isTech = Tech && Tech.isTech(ComponentToRegister); + const isComp = Component$1 === ComponentToRegister || Component$1.prototype.isPrototypeOf(ComponentToRegister.prototype); if (isTech || !isComp) { - var reason; - + let reason; if (isTech) { reason = 'techs must be registered using Tech.registerTech()'; } else { reason = 'must be a Component subclass'; } - - throw new Error("Illegal component, \"" + name + "\"; " + reason + "."); + throw new Error(`Illegal component, "${name}"; ${reason}.`); } - name = toTitleCase$1(name); - - if (!Component.components_) { - Component.components_ = {}; + if (!Component$1.components_) { + Component$1.components_ = {}; } - - var Player = Component.getComponent('Player'); - + const Player = Component$1.getComponent('Player'); if (name === 'Player' && Player && Player.players) { - var players = Player.players; - var playerNames = Object.keys(players); // If we have players that were disposed, then their name will still be + const players = Player.players; + const playerNames = Object.keys(players); + + // If we have players that were disposed, then their name will still be // in Players.players. So, we must loop through and verify that the value // for each item is not null. This allows registration of the Player component // after all players have been disposed or before any were created. - - if (players && playerNames.length > 0 && playerNames.map(function (pname) { - return players[pname]; - }).every(Boolean)) { + if (players && playerNames.length > 0 && playerNames.map(pname => players[pname]).every(Boolean)) { throw new Error('Can not register Player component after player has been created.'); } } - - Component.components_[name] = ComponentToRegister; - Component.components_[toLowerCase(name)] = ComponentToRegister; + Component$1.components_[name] = ComponentToRegister; + Component$1.components_[toLowerCase(name)] = ComponentToRegister; return ComponentToRegister; } + /** * Get a `Component` based on the name it was registered with. * * @param {string} name * The Name of the component to get. * - * @return {Component} + * @return {typeof Component} * The `Component` that got registered under the given name. */ - ; - - Component.getComponent = function getComponent(name) { - if (!name || !Component.components_) { + static getComponent(name) { + if (!name || !Component$1.components_) { return; } - - return Component.components_[name]; - }; - - return Component; - }(); - /** - * Whether or not this component supports `requestAnimationFrame`. - * - * This is exposed primarily for testing purposes. - * - * @private - * @type {Boolean} - */ - - - Component$1.prototype.supportsRaf_ = typeof window.requestAnimationFrame === 'function' && typeof window.cancelAnimationFrame === 'function'; + return Component$1.components_[name]; + } + } Component$1.registerComponent('Component', Component$1); - function _assertThisInitialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return self; - } - - var assertThisInitialized = _assertThisInitialized; - - function _inheritsLoose(subClass, superClass) { - subClass.prototype = Object.create(superClass.prototype); - subClass.prototype.constructor = subClass; - subClass.__proto__ = superClass; - } - - var inheritsLoose = _inheritsLoose; - /** - * @file time-ranges.js - * @module time-ranges + * @file time.js + * @module time */ /** @@ -5750,17 +5422,17 @@ */ /** - * An object that contains ranges of time. + * An object that contains ranges of time, which mimics {@link TimeRanges}. * * @typedef {Object} TimeRange * * @property {number} length * The number of time ranges represented by this object. * - * @property {module:time-ranges~TimeRangeIndex} start + * @property {module:time~TimeRangeIndex} start * Returns the time offset at which a specified time range begins. * - * @property {module:time-ranges~TimeRangeIndex} end + * @property {module:time~TimeRangeIndex} end * Returns the time offset at which a specified time range ends. * * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges @@ -5783,9 +5455,10 @@ */ function rangeCheck(fnName, index, maxIndex) { if (typeof index !== 'number' || index < 0 || index > maxIndex) { - throw new Error("Failed to execute '" + fnName + "' on 'TimeRanges': The index provided (" + index + ") is non-numeric or out of bounds (0-" + maxIndex + ")."); + throw new Error(`Failed to execute '${fnName}' on 'TimeRanges': The index provided (${index}) is non-numeric or out of bounds (0-${maxIndex}).`); } } + /** * Get the time for the specified index at the start or end * of a TimeRange object. @@ -5810,31 +5483,29 @@ * @deprecated rangeIndex must be set to a value, in the future this will throw an error. * @throws {Error} if rangeIndex is more than the length of ranges */ - - function getRange(fnName, valueIndex, ranges, rangeIndex) { rangeCheck(fnName, rangeIndex, ranges.length - 1); return ranges[rangeIndex][valueIndex]; } + /** * Create a time range object given ranges of time. * * @private * @param {Array} [ranges] * An array of time ranges. + * + * @return {TimeRange} */ - - function createTimeRangesObj(ranges) { - var timeRangesObj; - + let timeRangesObj; if (ranges === undefined || ranges.length === 0) { timeRangesObj = { length: 0, - start: function start() { + start() { throw new Error('This TimeRanges object is empty'); }, - end: function end() { + end() { throw new Error('This TimeRanges object is empty'); } }; @@ -5845,15 +5516,12 @@ end: getRange.bind(null, 'end', 1, ranges) }; } - if (window.Symbol && window.Symbol.iterator) { - timeRangesObj[window.Symbol.iterator] = function () { - return (ranges || []).values(); - }; + timeRangesObj[window.Symbol.iterator] = () => (ranges || []).values(); } - return timeRangesObj; } + /** * Create a `TimeRange` object which mimics an * {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|HTML5 TimeRanges instance}. @@ -5865,28 +5533,125 @@ * @param {number} end * The end of a single range. Cannot be used with the array form of * the `start` argument. + * + * @return {TimeRange} */ - - - function createTimeRanges(start, end) { + function createTimeRanges$1(start, end) { if (Array.isArray(start)) { return createTimeRangesObj(start); } else if (start === undefined || end === undefined) { return createTimeRangesObj(); } - return createTimeRangesObj([[start, end]]); } + /** + * Format seconds as a time string, H:MM:SS or M:SS. Supplying a guide (in + * seconds) will force a number of leading zeros to cover the length of the + * guide. + * + * @private + * @param {number} seconds + * Number of seconds to be turned into a string + * + * @param {number} guide + * Number (in seconds) to model the string after + * + * @return {string} + * Time formatted as H:MM:SS or M:SS + */ + const defaultImplementation = function (seconds, guide) { + seconds = seconds < 0 ? 0 : seconds; + let s = Math.floor(seconds % 60); + let m = Math.floor(seconds / 60 % 60); + let h = Math.floor(seconds / 3600); + const gm = Math.floor(guide / 60 % 60); + const gh = Math.floor(guide / 3600); + + // handle invalid times + if (isNaN(seconds) || seconds === Infinity) { + // '-' is false for all relational operators (e.g. <, >=) so this setting + // will add the minimum number of fields specified by the guide + h = m = s = '-'; + } + + // Check if we need to show hours + h = h > 0 || gh > 0 ? h + ':' : ''; + + // If hours are showing, we may need to add a leading zero. + // Always show at least one digit of minutes. + m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':'; + + // Check if leading zero is need for seconds + s = s < 10 ? '0' + s : s; + return h + m + s; + }; + + // Internal pointer to the current implementation. + let implementation = defaultImplementation; + + /** + * Replaces the default formatTime implementation with a custom implementation. + * + * @param {Function} customImplementation + * A function which will be used in place of the default formatTime + * implementation. Will receive the current time in seconds and the + * guide (in seconds) as arguments. + */ + function setFormatTime(customImplementation) { + implementation = customImplementation; + } + + /** + * Resets formatTime to the default implementation. + */ + function resetFormatTime() { + implementation = defaultImplementation; + } + + /** + * Delegates to either the default time formatting function or a custom + * function supplied via `setFormatTime`. + * + * Formats seconds as a time string (H:MM:SS or M:SS). Supplying a + * guide (in seconds) will force a number of leading zeros to cover the + * length of the guide. + * + * @example formatTime(125, 600) === "02:05" + * @param {number} seconds + * Number of seconds to be turned into a string + * + * @param {number} guide + * Number (in seconds) to model the string after + * + * @return {string} + * Time formatted as H:MM:SS or M:SS + */ + function formatTime(seconds, guide = seconds) { + return implementation(seconds, guide); + } + + var Time = /*#__PURE__*/Object.freeze({ + __proto__: null, + createTimeRanges: createTimeRanges$1, + createTimeRange: createTimeRanges$1, + setFormatTime: setFormatTime, + resetFormatTime: resetFormatTime, + formatTime: formatTime + }); + /** * @file buffer.js * @module buffer */ + + /** @import { TimeRange } from './time' */ + /** * Compute the percentage of the media that has been buffered. * * @param {TimeRange} buffered - * The current `TimeRange` object representing buffered time ranges + * The current `TimeRanges` object representing buffered time ranges * * @param {number} duration * Total duration of the media @@ -5894,37 +5659,33 @@ * @return {number} * Percent buffered of the total duration in decimal form. */ - function bufferedPercent(buffered, duration) { - var bufferedDuration = 0; - var start; - var end; - + let bufferedDuration = 0; + let start; + let end; if (!duration) { return 0; } - if (!buffered || !buffered.length) { - buffered = createTimeRanges(0, 0); + buffered = createTimeRanges$1(0, 0); } - - for (var i = 0; i < buffered.length; i++) { + for (let i = 0; i < buffered.length; i++) { start = buffered.start(i); - end = buffered.end(i); // buffered end can be bigger than duration by a very small fraction + end = buffered.end(i); + // buffered end can be bigger than duration by a very small fraction if (end > duration) { end = duration; } - bufferedDuration += end - start; } - return bufferedDuration / duration; } /** * @file media-error.js */ + /** * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class. * @@ -5942,14 +5703,12 @@ * * @class MediaError */ - function MediaError(value) { // Allow redundant calls to this constructor to avoid having `instanceof` // checks peppered around the code. if (value instanceof MediaError) { return value; } - if (typeof value === 'number') { this.code = value; } else if (typeof value === 'string') { @@ -5961,30 +5720,28 @@ if (typeof value.code === 'number') { this.code = value.code; } - - assign(this, value); + Object.assign(this, value); } - if (!this.message) { this.message = MediaError.defaultMessages[this.code] || ''; } } + /** * The error code that refers two one of the defined `MediaError` types * * @type {Number} */ - - MediaError.prototype.code = 0; + /** * An optional message that to show with the error. Message is not part of the HTML5 * video spec but allows for more informative custom errors. * * @type {String} */ - MediaError.prototype.message = ''; + /** * An optional status code that can be set by plugins to allow even more detail about * the error. For example a plugin might provide a specific HTTP status code and an @@ -5994,8 +5751,23 @@ * * @type {Array} */ - MediaError.prototype.status = null; + + /** + * An object containing an error type, as well as other information regarding the error. + * + * @typedef {{errorType: string, [key: string]: any}} ErrorMetadata + */ + + /** + * An optional object to give more detail about the error. This can be used to give + * a higher level of specificity to an error versus the more generic MediaError codes. + * `metadata` expects an `errorType` string that should align with the values from videojs.Error. + * + * @type {ErrorMetadata} + */ + MediaError.prototype.metadata = null; + /** * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the * specification listed under {@link MediaError} for more information. @@ -6009,42 +5781,139 @@ * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED * @property {string} 5 - MEDIA_ERR_ENCRYPTED */ - MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED']; + /** * The default `MediaError` messages based on the {@link MediaError.errorTypes}. * * @type {Array} * @constant */ - MediaError.defaultMessages = { 1: 'You aborted the media playback', 2: 'A network error caused the media download to fail part-way.', 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.', 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.', 5: 'The media is encrypted and we do not have the keys to decrypt it.' - }; // Add types as properties on MediaError - // e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; + }; - for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { - MediaError[MediaError.errorTypes[errNum]] = errNum; // values should be accessible on both the class and instance + /** + * W3C error code for any custom error. + * + * @member MediaError#MEDIA_ERR_CUSTOM + * @constant {number} + * @default 0 + */ + MediaError.MEDIA_ERR_CUSTOM = 0; - MediaError.prototype[MediaError.errorTypes[errNum]] = errNum; - } // jsdocs for instance/static members added above + /** + * W3C error code for any custom error. + * + * @member MediaError.MEDIA_ERR_CUSTOM + * @constant {number} + * @default 0 + */ + MediaError.prototype.MEDIA_ERR_CUSTOM = 0; + + /** + * W3C error code for media error aborted. + * + * @member MediaError#MEDIA_ERR_ABORTED + * @constant {number} + * @default 1 + */ + MediaError.MEDIA_ERR_ABORTED = 1; + + /** + * W3C error code for media error aborted. + * + * @member MediaError.MEDIA_ERR_ABORTED + * @constant {number} + * @default 1 + */ + MediaError.prototype.MEDIA_ERR_ABORTED = 1; + + /** + * W3C error code for any network error. + * + * @member MediaError#MEDIA_ERR_NETWORK + * @constant {number} + * @default 2 + */ + MediaError.MEDIA_ERR_NETWORK = 2; + + /** + * W3C error code for any network error. + * + * @member MediaError.MEDIA_ERR_NETWORK + * @constant {number} + * @default 2 + */ + MediaError.prototype.MEDIA_ERR_NETWORK = 2; + + /** + * W3C error code for any decoding error. + * + * @member MediaError#MEDIA_ERR_DECODE + * @constant {number} + * @default 3 + */ + MediaError.MEDIA_ERR_DECODE = 3; + + /** + * W3C error code for any decoding error. + * + * @member MediaError.MEDIA_ERR_DECODE + * @constant {number} + * @default 3 + */ + MediaError.prototype.MEDIA_ERR_DECODE = 3; + + /** + * W3C error code for any time that a source is not supported. + * + * @member MediaError#MEDIA_ERR_SRC_NOT_SUPPORTED + * @constant {number} + * @default 4 + */ + MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; + + /** + * W3C error code for any time that a source is not supported. + * + * @member MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED + * @constant {number} + * @default 4 + */ + MediaError.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; + + /** + * W3C error code for any time that a source is encrypted. + * + * @member MediaError#MEDIA_ERR_ENCRYPTED + * @constant {number} + * @default 5 + */ + MediaError.MEDIA_ERR_ENCRYPTED = 5; + + /** + * W3C error code for any time that a source is encrypted. + * + * @member MediaError.MEDIA_ERR_ENCRYPTED + * @constant {number} + * @default 5 + */ + MediaError.prototype.MEDIA_ERR_ENCRYPTED = 5; var tuple = SafeParseTuple; - function SafeParseTuple(obj, reviver) { var json; var error = null; - try { json = JSON.parse(obj, reviver); } catch (err) { error = err; } - return [error, json]; } @@ -6060,6 +5929,7 @@ function isPromise(value) { return value !== undefined && value !== null && typeof value.then === 'function'; } + /** * Silence a Promise-like object. * @@ -6069,10 +5939,9 @@ * @param {Object} value * An object that may or may not be `Promise`-like. */ - function silencePromise(value) { if (isPromise(value)) { - value.then(null, function (e) {}); + value.then(null, e => {}); } } @@ -6083,6 +5952,8 @@ * @module text-track-list-converter */ + /** @import Tech from '../tech/tech' */ + /** * Examine a single {@link TextTrack} and return a JSON-compatible javascript object that * represents the {@link TextTrack}'s state. @@ -6094,12 +5965,11 @@ * A serializable javascript representation of the TextTrack. * @private */ - var trackToJson_ = function trackToJson_(track) { - var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) { + const trackToJson_ = function (track) { + const ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce((acc, prop, i) => { if (track[prop]) { acc[prop] = track[prop]; } - return acc; }, { cues: track.cues && Array.prototype.map.call(track.cues, function (cue) { @@ -6113,6 +5983,7 @@ }); return ret; }; + /** * Examine a {@link Tech} and return a JSON-compatible javascript array that represents the * state of all {@link TextTrack}s currently configured. The return array is compatible with @@ -6125,26 +5996,21 @@ * A serializable javascript representation of the {@link Tech}s * {@link TextTrackList}. */ - - - var textTracksToJson = function textTracksToJson(tech) { - var trackEls = tech.$$('track'); - var trackObjs = Array.prototype.map.call(trackEls, function (t) { - return t.track; - }); - var tracks = Array.prototype.map.call(trackEls, function (trackEl) { - var json = trackToJson_(trackEl.track); - + const textTracksToJson = function (tech) { + const trackEls = tech.$$('track'); + const trackObjs = Array.prototype.map.call(trackEls, t => t.track); + const tracks = Array.prototype.map.call(trackEls, function (trackEl) { + const json = trackToJson_(trackEl.track); if (trackEl.src) { json.src = trackEl.src; } - return json; }); return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) { return trackObjs.indexOf(track) === -1; }).map(trackToJson_)); }; + /** * Create a set of remote {@link TextTrack}s on a {@link Tech} based on an array of javascript * object {@link TextTrack} representations. @@ -6156,28 +6022,30 @@ * @param {Tech} tech * The `Tech` to create the `TextTrack`s on. */ - - - var jsonToTextTracks = function jsonToTextTracks(json, tech) { + const jsonToTextTracks = function (json, tech) { json.forEach(function (track) { - var addedTrack = tech.addRemoteTextTrack(track).track; - + const addedTrack = tech.addRemoteTextTrack(track).track; if (!track.src && track.cues) { - track.cues.forEach(function (cue) { - return addedTrack.addCue(cue); - }); + track.cues.forEach(cue => addedTrack.addCue(cue)); } }); return tech.textTracks(); }; - var textTrackConverter = { - textTracksToJson: textTracksToJson, - jsonToTextTracks: jsonToTextTracks, - trackToJson_: trackToJson_ + textTracksToJson, + jsonToTextTracks, + trackToJson_ }; - var MODAL_CLASS_NAME = 'vjs-modal-dialog'; + /** + * @file modal-dialog.js + */ + + /** @import Player from './player' */ + /** @import { ContentDescriptor } from './utils/dom' */ + + const MODAL_CLASS_NAME = 'vjs-modal-dialog'; + /** * The `ModalDialog` displays over the video and its controls, which blocks * interaction with the player until it is closed. @@ -6187,12 +6055,9 @@ * * @extends Component */ - - var ModalDialog = /*#__PURE__*/function (_Component) { - inheritsLoose(ModalDialog, _Component); - + class ModalDialog extends Component$1 { /** - * Create an instance of this class. + * Creates an instance of this class. * * @param {Player} player * The `Player` that this class should be attached to. @@ -6200,7 +6065,7 @@ * @param {Object} [options] * The key/value store of player options. * - * @param {Mixed} [options.content=undefined] + * @param {ContentDescriptor} [options.content=undefined] * Provide customized content for this modal. * * @param {string} [options.description] @@ -6227,96 +6092,76 @@ * through the UI in the normal ways. Programmatic closing is * still possible. */ - function ModalDialog(player, options) { - var _this; + constructor(player, options) { + super(player, options); + this.handleKeyDown_ = e => this.handleKeyDown(e); + this.close_ = e => this.close(e); + this.opened_ = this.hasBeenOpened_ = this.hasBeenFilled_ = false; + this.closeable(!this.options_.uncloseable); + this.content(this.options_.content); - _this = _Component.call(this, player, options) || this; - - _this.handleKeyDown_ = function (e) { - return _this.handleKeyDown(e); - }; - - _this.close_ = function (e) { - return _this.close(e); - }; - - _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false; - - _this.closeable(!_this.options_.uncloseable); - - _this.content(_this.options_.content); // Make sure the contentEl is defined AFTER any children are initialized + // Make sure the contentEl is defined AFTER any children are initialized // because we only want the contents of the modal in the contentEl // (not the UI elements like the close button). - - - _this.contentEl_ = createEl('div', { - className: MODAL_CLASS_NAME + "-content" + this.contentEl_ = createEl('div', { + className: `${MODAL_CLASS_NAME}-content` }, { role: 'document' }); - _this.descEl_ = createEl('p', { - className: MODAL_CLASS_NAME + "-description vjs-control-text", - id: _this.el().getAttribute('aria-describedby') + this.descEl_ = createEl('p', { + className: `${MODAL_CLASS_NAME}-description vjs-control-text`, + id: this.el().getAttribute('aria-describedby') }); - textContent(_this.descEl_, _this.description()); - - _this.el_.appendChild(_this.descEl_); - - _this.el_.appendChild(_this.contentEl_); - - return _this; + textContent(this.descEl_, this.description()); + this.el_.appendChild(this.descEl_); + this.el_.appendChild(this.contentEl_); } + /** * Create the `ModalDialog`'s DOM element * * @return {Element} * The DOM element that gets created. */ - - - var _proto = ModalDialog.prototype; - - _proto.createEl = function createEl() { - return _Component.prototype.createEl.call(this, 'div', { + createEl() { + return super.createEl('div', { className: this.buildCSSClass(), tabIndex: -1 }, { - 'aria-describedby': this.id() + "_description", + 'aria-describedby': `${this.id()}_description`, 'aria-hidden': 'true', 'aria-label': this.label(), - 'role': 'dialog' + 'role': 'dialog', + 'aria-live': 'polite' }); - }; - - _proto.dispose = function dispose() { + } + dispose() { this.contentEl_ = null; this.descEl_ = null; this.previouslyActiveEl_ = null; - - _Component.prototype.dispose.call(this); + super.dispose(); } + /** * Builds the default DOM `className`. * * @return {string} * The DOM `className` for this object. */ - ; - - _proto.buildCSSClass = function buildCSSClass() { - return MODAL_CLASS_NAME + " vjs-hidden " + _Component.prototype.buildCSSClass.call(this); + buildCSSClass() { + return `${MODAL_CLASS_NAME} vjs-hidden ${super.buildCSSClass()}`; } + /** * Returns the label string for this modal. Primarily used for accessibility. * * @return {string} * the localized or raw label of this modal. */ - ; - - _proto.label = function label() { + label() { return this.localize(this.options_.label || 'Modal Window'); } + /** * Returns the description string for this modal. Primarily used for * accessibility. @@ -6324,69 +6169,71 @@ * @return {string} * The localized or raw description of this modal. */ - ; - - _proto.description = function description() { - var desc = this.options_.description || this.localize('This is a modal window.'); // Append a universal closeability message if the modal is closeable. + description() { + let desc = this.options_.description || this.localize('This is a modal window.'); + // Append a universal closeability message if the modal is closeable. if (this.closeable()) { desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.'); } - return desc; } + /** * Opens the modal. * * @fires ModalDialog#beforemodalopen * @fires ModalDialog#modalopen */ - ; - - _proto.open = function open() { - if (!this.opened_) { - var player = this.player(); - /** - * Fired just before a `ModalDialog` is opened. - * - * @event ModalDialog#beforemodalopen - * @type {EventTarget~Event} - */ - - this.trigger('beforemodalopen'); - this.opened_ = true; // Fill content if the modal has never opened before and - // never been filled. - - if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) { + open() { + if (this.opened_) { + if (this.options_.fillAlways) { this.fill(); - } // If the player was playing, pause it and take note of its previously - // playing state. - - - this.wasPlaying_ = !player.paused(); - - if (this.options_.pauseOnOpen && this.wasPlaying_) { - player.pause(); } - - this.on('keydown', this.handleKeyDown_); // Hide controls and note if they were enabled. - - this.hadControls_ = player.controls(); - player.controls(false); - this.show(); - this.conditionalFocus_(); - this.el().setAttribute('aria-hidden', 'false'); - /** - * Fired just after a `ModalDialog` is opened. - * - * @event ModalDialog#modalopen - * @type {EventTarget~Event} - */ - - this.trigger('modalopen'); - this.hasBeenOpened_ = true; + return; } + const player = this.player(); + + /** + * Fired just before a `ModalDialog` is opened. + * + * @event ModalDialog#beforemodalopen + * @type {Event} + */ + this.trigger('beforemodalopen'); + this.opened_ = true; + + // Fill content if the modal has never opened before and + // never been filled. + if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) { + this.fill(); + } + + // If the player was playing, pause it and take note of its previously + // playing state. + this.wasPlaying_ = !player.paused(); + if (this.options_.pauseOnOpen && this.wasPlaying_) { + player.pause(); + } + this.on('keydown', this.handleKeyDown_); + + // Hide controls and note if they were enabled. + this.hadControls_ = player.controls(); + player.controls(false); + this.show(); + this.conditionalFocus_(); + this.el().setAttribute('aria-hidden', 'false'); + + /** + * Fired just after a `ModalDialog` is opened. + * + * @event ModalDialog#modalopen + * @type {Event} + */ + this.trigger('modalopen'); + this.hasBeenOpened_ = true; } + /** * If the `ModalDialog` is currently open or closed. * @@ -6396,15 +6243,13 @@ * @return {boolean} * the current open state of the modaldialog */ - ; - - _proto.opened = function opened(value) { + opened(value) { if (typeof value === 'boolean') { this[value ? 'open' : 'close'](); } - return this.opened_; } + /** * Closes the modal, does nothing if the `ModalDialog` is * not open. @@ -6412,50 +6257,48 @@ * @fires ModalDialog#beforemodalclose * @fires ModalDialog#modalclose */ - ; - - _proto.close = function close() { + close() { if (!this.opened_) { return; } + const player = this.player(); - var player = this.player(); /** * Fired just before a `ModalDialog` is closed. * * @event ModalDialog#beforemodalclose - * @type {EventTarget~Event} + * @type {Event} */ - this.trigger('beforemodalclose'); this.opened_ = false; - if (this.wasPlaying_ && this.options_.pauseOnOpen) { player.play(); } - this.off('keydown', this.handleKeyDown_); - if (this.hadControls_) { player.controls(true); } - this.hide(); this.el().setAttribute('aria-hidden', 'true'); + /** * Fired just after a `ModalDialog` is closed. * * @event ModalDialog#modalclose - * @type {EventTarget~Event} + * @type {Event} + * + * @property {boolean} [bubbles=true] */ - - this.trigger('modalclose'); + this.trigger({ + type: 'modalclose', + bubbles: true + }); this.conditionalBlur_(); - if (this.options_.temporary) { this.dispose(); } } + /** * Check to see if the `ModalDialog` is closeable via the UI. * @@ -6465,44 +6308,42 @@ * @return {boolean} * Returns the final value of the closable option. */ - ; - - _proto.closeable = function closeable(value) { + closeable(value) { if (typeof value === 'boolean') { - var closeable = this.closeable_ = !!value; - var close = this.getChild('closeButton'); // If this is being made closeable and has no close button, add one. + const closeable = this.closeable_ = !!value; + let close = this.getChild('closeButton'); + // If this is being made closeable and has no close button, add one. if (closeable && !close) { // The close button should be a child of the modal - not its // content element, so temporarily change the content element. - var temp = this.contentEl_; + const temp = this.contentEl_; this.contentEl_ = this.el_; close = this.addChild('closeButton', { controlText: 'Close Modal Dialog' }); this.contentEl_ = temp; this.on(close, 'close', this.close_); - } // If this is being made uncloseable and has a close button, remove it. - + } + // If this is being made uncloseable and has a close button, remove it. if (!closeable && close) { this.off(close, 'close', this.close_); this.removeChild(close); close.dispose(); } } - return this.closeable_; } + /** * Fill the modal's content element with the modal's "content" option. * The content element will be emptied before this change takes place. */ - ; - - _proto.fill = function fill() { + fill() { this.fillWith(this.content()); } + /** * Fill the modal's content element with arbitrary content. * The content element will be emptied before this change takes place. @@ -6510,26 +6351,25 @@ * @fires ModalDialog#beforemodalfill * @fires ModalDialog#modalfill * - * @param {Mixed} [content] + * @param {ContentDescriptor} [content] * The same rules apply to this as apply to the `content` option. */ - ; + fillWith(content) { + const contentEl = this.contentEl(); + const parentEl = contentEl.parentNode; + const nextSiblingEl = contentEl.nextSibling; - _proto.fillWith = function fillWith(content) { - var contentEl = this.contentEl(); - var parentEl = contentEl.parentNode; - var nextSiblingEl = contentEl.nextSibling; /** * Fired just before a `ModalDialog` is filled with content. * * @event ModalDialog#beforemodalfill - * @type {EventTarget~Event} + * @type {Event} */ - this.trigger('beforemodalfill'); - this.hasBeenFilled_ = true; // Detach the content element from the DOM before performing - // manipulation to avoid modifying the live DOM multiple times. + this.hasBeenFilled_ = true; + // Detach the content element from the DOM before performing + // manipulation to avoid modifying the live DOM multiple times. parentEl.removeChild(contentEl); this.empty(); insertContent(contentEl, content); @@ -6537,50 +6377,57 @@ * Fired just after a `ModalDialog` is filled with content. * * @event ModalDialog#modalfill - * @type {EventTarget~Event} + * @type {Event} */ + this.trigger('modalfill'); - this.trigger('modalfill'); // Re-inject the re-filled content element. - + // Re-inject the re-filled content element. if (nextSiblingEl) { parentEl.insertBefore(contentEl, nextSiblingEl); } else { parentEl.appendChild(contentEl); - } // make sure that the close button is last in the dialog DOM - - - var closeButton = this.getChild('closeButton'); + } + // make sure that the close button is last in the dialog DOM + const closeButton = this.getChild('closeButton'); if (closeButton) { parentEl.appendChild(closeButton.el_); } + + /** + * Fired after `ModalDialog` is re-filled with content & close button is appended. + * + * @event ModalDialog#aftermodalfill + * @type {Event} + */ + this.trigger('aftermodalfill'); } + /** * Empties the content element. This happens anytime the modal is filled. * * @fires ModalDialog#beforemodalempty * @fires ModalDialog#modalempty */ - ; - - _proto.empty = function empty() { + empty() { /** * Fired just before a `ModalDialog` is emptied. * * @event ModalDialog#beforemodalempty - * @type {EventTarget~Event} + * @type {Event} */ this.trigger('beforemodalempty'); emptyEl(this.contentEl()); + /** * Fired just after a `ModalDialog` is emptied. * * @event ModalDialog#modalempty - * @type {EventTarget~Event} + * @type {Event} */ - this.trigger('modalempty'); } + /** * Gets or sets the modal content, which gets normalized before being * rendered into the DOM. @@ -6588,90 +6435,90 @@ * This does not update the DOM or fill the modal, but it is called during * that process. * - * @param {Mixed} [value] + * @param {ContentDescriptor} [value] * If defined, sets the internal content value to be used on the * next call(s) to `fill`. This value is normalized before being * inserted. To "clear" the internal content value, pass `null`. * - * @return {Mixed} + * @return {ContentDescriptor} * The current content of the modal dialog */ - ; - - _proto.content = function content(value) { + content(value) { if (typeof value !== 'undefined') { this.content_ = value; } - return this.content_; } + /** * conditionally focus the modal dialog if focus was previously on the player. * * @private */ - ; - - _proto.conditionalFocus_ = function conditionalFocus_() { - var activeEl = document.activeElement; - var playerEl = this.player_.el_; + conditionalFocus_() { + const activeEl = document.activeElement; + const playerEl = this.player_.el_; this.previouslyActiveEl_ = null; - if (playerEl.contains(activeEl) || playerEl === activeEl) { this.previouslyActiveEl_ = activeEl; this.focus(); } } + /** * conditionally blur the element and refocus the last focused element * * @private */ - ; - - _proto.conditionalBlur_ = function conditionalBlur_() { + conditionalBlur_() { if (this.previouslyActiveEl_) { this.previouslyActiveEl_.focus(); this.previouslyActiveEl_ = null; } } + /** * Keydown handler. Attached when modal is focused. * * @listens keydown */ - ; - - _proto.handleKeyDown = function handleKeyDown(event) { + handleKeyDown(event) { + /** + * Fired a custom keyDown event that bubbles. + * + * @event ModalDialog#modalKeydown + * @type {Event} + */ + this.trigger({ + type: 'modalKeydown', + originalEvent: event, + target: this, + bubbles: true + }); // Do not allow keydowns to reach out of the modal dialog. event.stopPropagation(); - - if (keycode.isEventKey(event, 'Escape') && this.closeable()) { + if (event.key === 'Escape' && this.closeable()) { event.preventDefault(); this.close(); return; - } // exit early if it isn't a tab key - - - if (!keycode.isEventKey(event, 'Tab')) { - return; } - var focusableEls = this.focusableEls_(); - var activeEl = this.el_.querySelector(':focus'); - var focusIndex; - - for (var i = 0; i < focusableEls.length; i++) { + // exit early if it isn't a tab key + if (event.key !== 'Tab') { + return; + } + const focusableEls = this.focusableEls_(); + const activeEl = this.el_.querySelector(':focus'); + let focusIndex; + for (let i = 0; i < focusableEls.length; i++) { if (activeEl === focusableEls[i]) { focusIndex = i; break; } } - if (document.activeElement === this.el_) { focusIndex = 0; } - if (event.shiftKey && focusIndex === 0) { focusableEls[focusableEls.length - 1].focus(); event.preventDefault(); @@ -6680,82 +6527,73 @@ event.preventDefault(); } } + /** * get all focusable elements * * @private */ - ; - - _proto.focusableEls_ = function focusableEls_() { - var allChildren = this.el_.querySelectorAll('*'); - return Array.prototype.filter.call(allChildren, function (child) { + focusableEls_() { + const allChildren = this.el_.querySelectorAll('*'); + return Array.prototype.filter.call(allChildren, child => { return (child instanceof window.HTMLAnchorElement || child instanceof window.HTMLAreaElement) && child.hasAttribute('href') || (child instanceof window.HTMLInputElement || child instanceof window.HTMLSelectElement || child instanceof window.HTMLTextAreaElement || child instanceof window.HTMLButtonElement) && !child.hasAttribute('disabled') || child instanceof window.HTMLIFrameElement || child instanceof window.HTMLObjectElement || child instanceof window.HTMLEmbedElement || child.hasAttribute('tabindex') && child.getAttribute('tabindex') !== -1 || child.hasAttribute('contenteditable'); }); - }; + } + } - return ModalDialog; - }(Component$1); /** * Default options for `ModalDialog` default options. * * @type {Object} * @private */ - - ModalDialog.prototype.options_ = { pauseOnOpen: true, temporary: true }; Component$1.registerComponent('ModalDialog', ModalDialog); + /** + * @file track-list.js + */ + + /** @import Track from './track' */ + /** * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and * {@link VideoTrackList} * * @extends EventTarget */ - - var TrackList = /*#__PURE__*/function (_EventTarget) { - inheritsLoose(TrackList, _EventTarget); - + class TrackList extends EventTarget$2 { /** * Create an instance of this class * - * @param {Track[]} tracks + * @param { Track[] } tracks * A list of tracks to initialize the list with. * * @abstract */ - function TrackList(tracks) { - var _this; + constructor(tracks = []) { + super(); + this.tracks_ = []; - if (tracks === void 0) { - tracks = []; - } - - _this = _EventTarget.call(this) || this; - _this.tracks_ = []; /** * @memberof TrackList * @member {number} length * The current number of `Track`s in the this Trackist. * @instance */ - - Object.defineProperty(assertThisInitialized(_this), 'length', { - get: function get() { + Object.defineProperty(this, 'length', { + get() { return this.tracks_.length; } }); - - for (var i = 0; i < tracks.length; i++) { - _this.addTrack(tracks[i]); + for (let i = 0; i < tracks.length; i++) { + this.addTrack(tracks[i]); } - - return _this; } + /** * Add a {@link Track} to the `TrackList` * @@ -6764,63 +6602,54 @@ * * @fires TrackList#addtrack */ - - - var _proto = TrackList.prototype; - - _proto.addTrack = function addTrack(track) { - var _this2 = this; - - var index = this.tracks_.length; - + addTrack(track) { + const index = this.tracks_.length; if (!('' + index in this)) { Object.defineProperty(this, index, { - get: function get() { + get() { return this.tracks_[index]; } }); - } // Do not add duplicate tracks - + } + // Do not add duplicate tracks if (this.tracks_.indexOf(track) === -1) { this.tracks_.push(track); /** * Triggered when a track is added to a track list. * * @event TrackList#addtrack - * @type {EventTarget~Event} + * @type {Event} * @property {Track} track * A reference to track that was added. */ - this.trigger({ - track: track, + track, type: 'addtrack', target: this }); } + /** * Triggered when a track label is changed. * * @event TrackList#addtrack - * @type {EventTarget~Event} + * @type {Event} * @property {Track} track * A reference to track that was added. */ - - - track.labelchange_ = function () { - _this2.trigger({ - track: track, + track.labelchange_ = () => { + this.trigger({ + track, type: 'labelchange', - target: _this2 + target: this }); }; - if (isEvented(track)) { track.addEventListener('labelchange', track.labelchange_); } } + /** * Remove a {@link Track} from the `TrackList` * @@ -6829,43 +6658,37 @@ * * @fires TrackList#removetrack */ - ; - - _proto.removeTrack = function removeTrack(rtrack) { - var track; - - for (var i = 0, l = this.length; i < l; i++) { + removeTrack(rtrack) { + let track; + for (let i = 0, l = this.length; i < l; i++) { if (this[i] === rtrack) { track = this[i]; - if (track.off) { track.off(); } - this.tracks_.splice(i, 1); break; } } - if (!track) { return; } + /** * Triggered when a track is removed from track list. * * @event TrackList#removetrack - * @type {EventTarget~Event} + * @type {Event} * @property {Track} track * A reference to track that was removed. */ - - this.trigger({ - track: track, + track, type: 'removetrack', target: this }); } + /** * Get a Track from the TrackList by a tracks id * @@ -6874,51 +6697,50 @@ * @return {Track} * @private */ - ; - - _proto.getTrackById = function getTrackById(id) { - var result = null; - - for (var i = 0, l = this.length; i < l; i++) { - var track = this[i]; - + getTrackById(id) { + let result = null; + for (let i = 0, l = this.length; i < l; i++) { + const track = this[i]; if (track.id === id) { result = track; break; } } - return result; - }; + } + } - return TrackList; - }(EventTarget$2); /** * Triggered when a different track is selected/enabled. * * @event TrackList#change - * @type {EventTarget~Event} + * @type {Event} */ /** * Events that can be called with on + eventName. See {@link EventHandler}. * * @property {Object} TrackList#allowedEvents_ - * @private + * @protected */ - - TrackList.prototype.allowedEvents_ = { change: 'change', addtrack: 'addtrack', removetrack: 'removetrack', labelchange: 'labelchange' - }; // emulate attribute EventHandler support to allow for feature detection + }; - for (var event in TrackList.prototype.allowedEvents_) { + // emulate attribute EventHandler support to allow for feature detection + for (const event in TrackList.prototype.allowedEvents_) { TrackList.prototype['on' + event] = null; } + /** + * @file audio-track-list.js + */ + + /** @import AudioTrack from './audio-track' */ + /** * Anywhere we call this function we diverge from the spec * as we only support one enabled audiotrack at a time @@ -6931,54 +6753,42 @@ * * @private */ - - var disableOthers$1 = function disableOthers(list, track) { - for (var i = 0; i < list.length; i++) { + const disableOthers$1 = function (list, track) { + for (let i = 0; i < list.length; i++) { if (!Object.keys(list[i]).length || track.id === list[i].id) { continue; - } // another audio track is enabled, disable it - - + } + // another audio track is enabled, disable it list[i].enabled = false; } }; + /** * The current list of {@link AudioTrack} for a media file. * * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist} * @extends TrackList */ - - - var AudioTrackList = /*#__PURE__*/function (_TrackList) { - inheritsLoose(AudioTrackList, _TrackList); - + class AudioTrackList extends TrackList { /** * Create an instance of this class. * * @param {AudioTrack[]} [tracks=[]] * A list of `AudioTrack` to instantiate the list with. */ - function AudioTrackList(tracks) { - var _this; - - if (tracks === void 0) { - tracks = []; - } - + constructor(tracks = []) { // make sure only 1 track is enabled // sorted from last index to first index - for (var i = tracks.length - 1; i >= 0; i--) { + for (let i = tracks.length - 1; i >= 0; i--) { if (tracks[i].enabled) { disableOthers$1(tracks, tracks[i]); break; } } - - _this = _TrackList.call(this, tracks) || this; - _this.changing_ = false; - return _this; + super(tracks); + this.changing_ = false; } + /** * Add an {@link AudioTrack} to the `AudioTrackList`. * @@ -6987,58 +6797,48 @@ * * @fires TrackList#addtrack */ - - - var _proto = AudioTrackList.prototype; - - _proto.addTrack = function addTrack(track) { - var _this2 = this; - + addTrack(track) { if (track.enabled) { disableOthers$1(this, track); } - - _TrackList.prototype.addTrack.call(this, track); // native tracks don't have this - - + super.addTrack(track); + // native tracks don't have this if (!track.addEventListener) { return; } - - track.enabledChange_ = function () { + track.enabledChange_ = () => { // when we are disabling other tracks (since we don't support // more than one track at a time) we will set changing_ // to true so that we don't trigger additional change events - if (_this2.changing_) { + if (this.changing_) { return; } - - _this2.changing_ = true; - disableOthers$1(_this2, track); - _this2.changing_ = false; - - _this2.trigger('change'); + this.changing_ = true; + disableOthers$1(this, track); + this.changing_ = false; + this.trigger('change'); }; + /** * @listens AudioTrack#enabledchange * @fires TrackList#change */ - - track.addEventListener('enabledchange', track.enabledChange_); - }; - - _proto.removeTrack = function removeTrack(rtrack) { - _TrackList.prototype.removeTrack.call(this, rtrack); - + } + removeTrack(rtrack) { + super.removeTrack(rtrack); if (rtrack.removeEventListener && rtrack.enabledChange_) { rtrack.removeEventListener('enabledchange', rtrack.enabledChange_); rtrack.enabledChange_ = null; } - }; + } + } - return AudioTrackList; - }(TrackList); + /** + * @file video-track-list.js + */ + + /** @import VideoTrack from './video-track' */ /** * Un-select all other {@link VideoTrack}s that are selected. @@ -7051,71 +6851,58 @@ * * @private */ - - var disableOthers = function disableOthers(list, track) { - for (var i = 0; i < list.length; i++) { + const disableOthers = function (list, track) { + for (let i = 0; i < list.length; i++) { if (!Object.keys(list[i]).length || track.id === list[i].id) { continue; - } // another video track is enabled, disable it - - + } + // another video track is enabled, disable it list[i].selected = false; } }; + /** * The current list of {@link VideoTrack} for a video. * * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist} * @extends TrackList */ - - - var VideoTrackList = /*#__PURE__*/function (_TrackList) { - inheritsLoose(VideoTrackList, _TrackList); - + class VideoTrackList extends TrackList { /** * Create an instance of this class. * * @param {VideoTrack[]} [tracks=[]] * A list of `VideoTrack` to instantiate the list with. */ - function VideoTrackList(tracks) { - var _this; - - if (tracks === void 0) { - tracks = []; - } - + constructor(tracks = []) { // make sure only 1 track is enabled // sorted from last index to first index - for (var i = tracks.length - 1; i >= 0; i--) { + for (let i = tracks.length - 1; i >= 0; i--) { if (tracks[i].selected) { disableOthers(tracks, tracks[i]); break; } } + super(tracks); + this.changing_ = false; - _this = _TrackList.call(this, tracks) || this; - _this.changing_ = false; /** * @member {number} VideoTrackList#selectedIndex * The current index of the selected {@link VideoTrack`}. */ - - Object.defineProperty(assertThisInitialized(_this), 'selectedIndex', { - get: function get() { - for (var _i = 0; _i < this.length; _i++) { - if (this[_i].selected) { - return _i; + Object.defineProperty(this, 'selectedIndex', { + get() { + for (let i = 0; i < this.length; i++) { + if (this[i].selected) { + return i; } } - return -1; }, - set: function set() {} + set() {} }); - return _this; } + /** * Add a {@link VideoTrack} to the `VideoTrackList`. * @@ -7124,55 +6911,45 @@ * * @fires TrackList#addtrack */ - - - var _proto = VideoTrackList.prototype; - - _proto.addTrack = function addTrack(track) { - var _this2 = this; - + addTrack(track) { if (track.selected) { disableOthers(this, track); } - - _TrackList.prototype.addTrack.call(this, track); // native tracks don't have this - - + super.addTrack(track); + // native tracks don't have this if (!track.addEventListener) { return; } - - track.selectedChange_ = function () { - if (_this2.changing_) { + track.selectedChange_ = () => { + if (this.changing_) { return; } - - _this2.changing_ = true; - disableOthers(_this2, track); - _this2.changing_ = false; - - _this2.trigger('change'); + this.changing_ = true; + disableOthers(this, track); + this.changing_ = false; + this.trigger('change'); }; + /** * @listens VideoTrack#selectedchange * @fires TrackList#change */ - - track.addEventListener('selectedchange', track.selectedChange_); - }; - - _proto.removeTrack = function removeTrack(rtrack) { - _TrackList.prototype.removeTrack.call(this, rtrack); - + } + removeTrack(rtrack) { + super.removeTrack(rtrack); if (rtrack.removeEventListener && rtrack.selectedChange_) { rtrack.removeEventListener('selectedchange', rtrack.selectedChange_); rtrack.selectedChange_ = null; } - }; + } + } - return VideoTrackList; - }(TrackList); + /** + * @file text-track-list.js + */ + + /** @import TextTrack from './text-track' */ /** * The current list of {@link TextTrack} for a media file. @@ -7180,16 +6957,7 @@ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist} * @extends TrackList */ - - var TextTrackList = /*#__PURE__*/function (_TrackList) { - inheritsLoose(TextTrackList, _TrackList); - - function TextTrackList() { - return _TrackList.apply(this, arguments) || this; - } - - var _proto = TextTrackList.prototype; - + class TextTrackList extends TrackList { /** * Add a {@link TextTrack} to the `TextTrackList` * @@ -7198,53 +6966,39 @@ * * @fires TrackList#addtrack */ - _proto.addTrack = function addTrack(track) { - var _this = this; - - _TrackList.prototype.addTrack.call(this, track); - + addTrack(track) { + super.addTrack(track); if (!this.queueChange_) { - this.queueChange_ = function () { - return _this.queueTrigger('change'); - }; + this.queueChange_ = () => this.queueTrigger('change'); + } + if (!this.triggerSelectedlanguagechange) { + this.triggerSelectedlanguagechange_ = () => this.trigger('selectedlanguagechange'); } - if (!this.triggerSelectedlanguagechange) { - this.triggerSelectedlanguagechange_ = function () { - return _this.trigger('selectedlanguagechange'); - }; - } /** * @listens TextTrack#modechange * @fires TrackList#change */ - - track.addEventListener('modechange', this.queueChange_); - var nonLanguageTextTrackKind = ['metadata', 'chapters']; - + const nonLanguageTextTrackKind = ['metadata', 'chapters']; if (nonLanguageTextTrackKind.indexOf(track.kind) === -1) { track.addEventListener('modechange', this.triggerSelectedlanguagechange_); } - }; - - _proto.removeTrack = function removeTrack(rtrack) { - _TrackList.prototype.removeTrack.call(this, rtrack); // manually remove the event handlers we added - + } + removeTrack(rtrack) { + super.removeTrack(rtrack); + // manually remove the event handlers we added if (rtrack.removeEventListener) { if (this.queueChange_) { rtrack.removeEventListener('modechange', this.queueChange_); } - if (this.selectedlanguagechange_) { rtrack.removeEventListener('modechange', this.triggerSelectedlanguagechange_); } } - }; - - return TextTrackList; - }(TrackList); + } + } /** * @file html-track-element-list.js @@ -7253,36 +7007,32 @@ /** * The current list of {@link HtmlTrackElement}s. */ - var HtmlTrackElementList = /*#__PURE__*/function () { + class HtmlTrackElementList { /** * Create an instance of this class. * * @param {HtmlTrackElement[]} [tracks=[]] * A list of `HtmlTrackElement` to instantiate the list with. */ - function HtmlTrackElementList(trackElements) { - if (trackElements === void 0) { - trackElements = []; - } - + constructor(trackElements = []) { this.trackElements_ = []; + /** * @memberof HtmlTrackElementList * @member {number} length * The current number of `Track`s in the this Trackist. * @instance */ - Object.defineProperty(this, 'length', { - get: function get() { + get() { return this.trackElements_.length; } }); - - for (var i = 0, length = trackElements.length; i < length; i++) { + for (let i = 0, length = trackElements.length; i < length; i++) { this.addTrackElement_(trackElements[i]); } } + /** * Add an {@link HtmlTrackElement} to the `HtmlTrackElementList` * @@ -7291,26 +7041,22 @@ * * @private */ - - - var _proto = HtmlTrackElementList.prototype; - - _proto.addTrackElement_ = function addTrackElement_(trackElement) { - var index = this.trackElements_.length; - + addTrackElement_(trackElement) { + const index = this.trackElements_.length; if (!('' + index in this)) { Object.defineProperty(this, index, { - get: function get() { + get() { return this.trackElements_[index]; } }); - } // Do not add duplicate elements - + } + // Do not add duplicate elements if (this.trackElements_.indexOf(trackElement) === -1) { this.trackElements_.push(trackElement); } } + /** * Get an {@link HtmlTrackElement} from the `HtmlTrackElementList` given an * {@link TextTrack}. @@ -7323,20 +7069,17 @@ * * @private */ - ; - - _proto.getTrackElementByTrack_ = function getTrackElementByTrack_(track) { - var trackElement_; - - for (var i = 0, length = this.trackElements_.length; i < length; i++) { + getTrackElementByTrack_(track) { + let trackElement_; + for (let i = 0, length = this.trackElements_.length; i < length; i++) { if (track === this.trackElements_[i].track) { trackElement_ = this.trackElements_[i]; break; } } - return trackElement_; } + /** * Remove a {@link HtmlTrackElement} from the `HtmlTrackElementList` * @@ -7345,27 +7088,21 @@ * * @private */ - ; - - _proto.removeTrackElement_ = function removeTrackElement_(trackElement) { - for (var i = 0, length = this.trackElements_.length; i < length; i++) { + removeTrackElement_(trackElement) { + for (let i = 0, length = this.trackElements_.length; i < length; i++) { if (trackElement === this.trackElements_[i]) { if (this.trackElements_[i].track && typeof this.trackElements_[i].track.off === 'function') { this.trackElements_[i].track.off(); } - if (typeof this.trackElements_[i].off === 'function') { this.trackElements_[i].off(); } - this.trackElements_.splice(i, 1); break; } } - }; - - return HtmlTrackElementList; - }(); + } + } /** * @file text-track-cue-list.js @@ -7394,28 +7131,29 @@ * * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist} */ - var TextTrackCueList = /*#__PURE__*/function () { + class TextTrackCueList { /** * Create an instance of this class.. * * @param {Array} cues * A list of cues to be initialized with */ - function TextTrackCueList(cues) { + constructor(cues) { TextTrackCueList.prototype.setCues_.call(this, cues); + /** * @memberof TextTrackCueList * @member {number} length * The current number of `TextTrackCue`s in the TextTrackCueList. * @instance */ - Object.defineProperty(this, 'length', { - get: function get() { + get() { return this.length_; } }); } + /** * A setter for cues in this list. Creates getters * an an index for the cues. @@ -7425,35 +7163,29 @@ * * @private */ - - - var _proto = TextTrackCueList.prototype; - - _proto.setCues_ = function setCues_(cues) { - var oldLength = this.length || 0; - var i = 0; - var l = cues.length; + setCues_(cues) { + const oldLength = this.length || 0; + let i = 0; + const l = cues.length; this.cues_ = cues; this.length_ = cues.length; - - var defineProp = function defineProp(index) { + const defineProp = function (index) { if (!('' + index in this)) { Object.defineProperty(this, '' + index, { - get: function get() { + get() { return this.cues_[index]; } }); } }; - if (oldLength < l) { i = oldLength; - for (; i < l; i++) { defineProp.call(this, i); } } } + /** * Get a `TextTrackCue` that is currently in the `TextTrackCueList` by id. * @@ -7463,25 +7195,18 @@ * @return {TextTrackCueList~TextTrackCue|null} * A single cue or null if none was found. */ - ; - - _proto.getCueById = function getCueById(id) { - var result = null; - - for (var i = 0, l = this.length; i < l; i++) { - var cue = this[i]; - + getCueById(id) { + let result = null; + for (let i = 0, l = this.length; i < l; i++) { + const cue = this[i]; if (cue.id === id) { result = cue; break; } } - return result; - }; - - return TextTrackCueList; - }(); + } + } /** * @file track-kinds.js @@ -7494,7 +7219,7 @@ * @typedef VideoTrack~Kind * @enum */ - var VideoTrackKind = { + const VideoTrackKind = { alternative: 'alternative', captions: 'captions', main: 'main', @@ -7502,6 +7227,7 @@ subtitles: 'subtitles', commentary: 'commentary' }; + /** * All possible `AudioTrackKind`s * @@ -7509,8 +7235,7 @@ * @typedef AudioTrack~Kind * @enum */ - - var AudioTrackKind = { + const AudioTrackKind = { 'alternative': 'alternative', 'descriptions': 'descriptions', 'main': 'main', @@ -7518,6 +7243,7 @@ 'translation': 'translation', 'commentary': 'commentary' }; + /** * All possible `TextTrackKind`s * @@ -7525,14 +7251,14 @@ * @typedef TextTrack~Kind * @enum */ - - var TextTrackKind = { + const TextTrackKind = { subtitles: 'subtitles', captions: 'captions', descriptions: 'descriptions', chapters: 'chapters', metadata: 'metadata' }; + /** * All possible `TextTrackMode`s * @@ -7540,13 +7266,16 @@ * @typedef TextTrack~Mode * @enum */ - - var TextTrackMode = { + const TextTrackMode = { disabled: 'disabled', hidden: 'hidden', showing: 'showing' }; + /** + * @file track.js + */ + /** * A Track class that contains all of the common functionality for {@link AudioTrack}, * {@link VideoTrack}, and {@link TextTrack}. @@ -7557,10 +7286,7 @@ * @extends EventTarget * @abstract */ - - var Track = /*#__PURE__*/function (_EventTarget) { - inheritsLoose(Track, _EventTarget); - + class Track extends EventTarget$2 { /** * Create an instance of this class. * @@ -7581,20 +7307,15 @@ * * @abstract */ - function Track(options) { - var _this; - - if (options === void 0) { - options = {}; - } - - _this = _EventTarget.call(this) || this; - var trackProps = { + constructor(options = {}) { + super(); + const trackProps = { id: options.id || 'vjs_track_' + newGUID(), kind: options.kind || '', language: options.language || '' }; - var label = options.label || ''; + let label = options.label || ''; + /** * @memberof Track * @member {string} id @@ -7623,18 +7344,15 @@ * @readonly */ - var _loop = function _loop(key) { - Object.defineProperty(assertThisInitialized(_this), key, { - get: function get() { + for (const key in trackProps) { + Object.defineProperty(this, key, { + get() { return trackProps[key]; }, - set: function set() {} + set() {} }); - }; - - for (var key in trackProps) { - _loop(key); } + /** * @memberof Track * @member {string} label @@ -7643,113 +7361,50 @@ * * @fires Track#labelchange */ - - - Object.defineProperty(assertThisInitialized(_this), 'label', { - get: function get() { + Object.defineProperty(this, 'label', { + get() { return label; }, - set: function set(newLabel) { + set(newLabel) { if (newLabel !== label) { label = newLabel; + /** * An event that fires when label changes on this track. * * > Note: This is not part of the spec! * * @event Track#labelchange - * @type {EventTarget~Event} + * @type {Event} */ - this.trigger('labelchange'); } } }); - return _this; } - - return Track; - }(EventTarget$2); + } /** * @file url.js * @module url */ - /** - * @typedef {Object} url:URLObject - * - * @property {string} protocol - * The protocol of the url that was parsed. - * - * @property {string} hostname - * The hostname of the url that was parsed. - * - * @property {string} port - * The port of the url that was parsed. - * - * @property {string} pathname - * The pathname of the url that was parsed. - * - * @property {string} search - * The search query of the url that was parsed. - * - * @property {string} hash - * The hash of the url that was parsed. - * - * @property {string} host - * The host of the url that was parsed. - */ - /** * Resolve and parse the elements of a URL. * * @function - * @param {String} url + * @param {string} url * The url to parse * - * @return {url:URLObject} + * @return {URL} * An object of url details */ - var parseUrl = function parseUrl(url) { - // This entire method can be replace with URL once we are able to drop IE11 - var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host']; // add the url to an anchor and let the browser parse the URL - - var a = document.createElement('a'); - a.href = url; // Copy the specific URL properties to a new object - // This is also needed for IE because the anchor loses its - // properties when it's removed from the dom - - var details = {}; - - for (var i = 0; i < props.length; i++) { - details[props[i]] = a[props[i]]; - } // IE adds the port to the host property unlike everyone else. If - // a port identifier is added for standard ports, strip it. - - - if (details.protocol === 'http:') { - details.host = details.host.replace(/:80$/, ''); - } - - if (details.protocol === 'https:') { - details.host = details.host.replace(/:443$/, ''); - } - - if (!details.protocol) { - details.protocol = window.location.protocol; - } - /* istanbul ignore if */ - - - if (!details.host) { - details.host = window.location.host; - } - - return details; + const parseUrl = function (url) { + return new URL(url, document.baseURI); }; + /** - * Get absolute version of relative URL. Used to tell Flash the correct URL. + * Get absolute version of relative URL. * * @function * @param {string} url @@ -7757,22 +7412,11 @@ * * @return {string} * Absolute URL - * - * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue */ - - var getAbsoluteURL = function getAbsoluteURL(url) { - // Check if absolute URL - if (!url.match(/^https?:\/\//)) { - // Convert to absolute URL. Flash hosted off-site needs an absolute URL. - // add the url to an anchor and let the browser parse the URL - var a = document.createElement('a'); - a.href = url; - url = a.href; - } - - return url; + const getAbsoluteURL = function (url) { + return new URL(url, document.baseURI).href; }; + /** * Returns the extension of the passed file name. It will return an empty string * if passed an invalid path. @@ -7785,19 +7429,17 @@ * The extension in lower case or an empty string if no * extension could be found. */ - - var getFileExtension = function getFileExtension(path) { + const getFileExtension = function (path) { if (typeof path === 'string') { - var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/; - var pathParts = splitPathRe.exec(path); - + const splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/; + const pathParts = splitPathRe.exec(path); if (pathParts) { return pathParts.pop().toLowerCase(); } } - return ''; }; + /** * Returns whether the url passed is a cross domain request or not. * @@ -7805,31 +7447,14 @@ * @param {string} url * The url to check. * - * @param {Object} [winLoc] + * @param {URL} [winLoc] * the domain to check the url against, defaults to window.location * - * @param {string} [winLoc.protocol] - * The window location protocol defaults to window.location.protocol - * - * @param {string} [winLoc.host] - * The window location host defaults to window.location.host - * * @return {boolean} * Whether it is a cross domain request or not. */ - - var isCrossOrigin = function isCrossOrigin(url, winLoc) { - if (winLoc === void 0) { - winLoc = window.location; - } - - var urlInfo = parseUrl(url); // IE8 protocol relative urls will return ':' for protocol - - var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol; // Check if url is for another domain/origin - // IE8 doesn't know location.origin, so we won't rely on it here - - var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host; - return crossOrigin; + const isCrossOrigin = function (url, winLoc = window.location) { + return parseUrl(url).origin !== winLoc.origin; }; var Url = /*#__PURE__*/Object.freeze({ @@ -7840,8 +7465,17 @@ isCrossOrigin: isCrossOrigin }); - var win; + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + function unwrapExports (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } + + function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; + } + + var win; if (typeof window !== "undefined") { win = window; } else if (typeof commonjsGlobal !== "undefined") { @@ -7851,27 +7485,249 @@ } else { win = {}; } - var window_1 = win; + var _extends_1 = createCommonjsModule(function (module) { + function _extends() { + return (module.exports = _extends = Object.assign ? Object.assign.bind() : function (n) { + for (var e = 1; e < arguments.length; e++) { + var t = arguments[e]; + for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); + } + return n; + }, module.exports.__esModule = true, module.exports["default"] = module.exports), _extends.apply(null, arguments); + } + module.exports = _extends, module.exports.__esModule = true, module.exports["default"] = module.exports; + }); + var _extends$1 = unwrapExports(_extends_1); + var isFunction_1 = isFunction; var toString = Object.prototype.toString; - function isFunction(fn) { if (!fn) { return false; } - var string = toString.call(fn); - return string === '[object Function]' || typeof fn === 'function' && string !== '[object RegExp]' || typeof window !== 'undefined' && ( // IE8 and below + return string === '[object Function]' || typeof fn === 'function' && string !== '[object RegExp]' || typeof window !== 'undefined' && ( + // IE8 and below fn === window.setTimeout || fn === window.alert || fn === window.confirm || fn === window.prompt); } + function _createForOfIteratorHelperLoose(o, allowArrayLike) { + var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; + if (it) return (it = it.call(o)).next.bind(it); + if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { + if (it) o = it; + var i = 0; + return function () { + if (i >= o.length) return { + done: true + }; + return { + done: false, + value: o[i++] + }; + }; + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); + } + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) { + arr2[i] = arr[i]; + } + return arr2; + } + var InterceptorsStorage = /*#__PURE__*/function () { + function InterceptorsStorage() { + this.typeToInterceptorsMap_ = new Map(); + this.enabled_ = false; + } + var _proto = InterceptorsStorage.prototype; + _proto.getIsEnabled = function getIsEnabled() { + return this.enabled_; + }; + _proto.enable = function enable() { + this.enabled_ = true; + }; + _proto.disable = function disable() { + this.enabled_ = false; + }; + _proto.reset = function reset() { + this.typeToInterceptorsMap_ = new Map(); + this.enabled_ = false; + }; + _proto.addInterceptor = function addInterceptor(type, interceptor) { + if (!this.typeToInterceptorsMap_.has(type)) { + this.typeToInterceptorsMap_.set(type, new Set()); + } + var interceptorsSet = this.typeToInterceptorsMap_.get(type); + if (interceptorsSet.has(interceptor)) { + // already have this interceptor + return false; + } + interceptorsSet.add(interceptor); + return true; + }; + _proto.removeInterceptor = function removeInterceptor(type, interceptor) { + var interceptorsSet = this.typeToInterceptorsMap_.get(type); + if (interceptorsSet && interceptorsSet.has(interceptor)) { + interceptorsSet.delete(interceptor); + return true; + } + return false; + }; + _proto.clearInterceptorsByType = function clearInterceptorsByType(type) { + var interceptorsSet = this.typeToInterceptorsMap_.get(type); + if (!interceptorsSet) { + return false; + } + this.typeToInterceptorsMap_.delete(type); + this.typeToInterceptorsMap_.set(type, new Set()); + return true; + }; + _proto.clear = function clear() { + if (!this.typeToInterceptorsMap_.size) { + return false; + } + this.typeToInterceptorsMap_ = new Map(); + return true; + }; + _proto.getForType = function getForType(type) { + return this.typeToInterceptorsMap_.get(type) || new Set(); + }; + _proto.execute = function execute(type, payload) { + var interceptors = this.getForType(type); + for (var _iterator = _createForOfIteratorHelperLoose(interceptors), _step; !(_step = _iterator()).done;) { + var interceptor = _step.value; + try { + payload = interceptor(payload); + } catch (e) {//ignore + } + } + return payload; + }; + return InterceptorsStorage; + }(); + var interceptors = InterceptorsStorage; + + var RetryManager = /*#__PURE__*/function () { + function RetryManager() { + this.maxAttempts_ = 1; + this.delayFactor_ = 0.1; + this.fuzzFactor_ = 0.1; + this.initialDelay_ = 1000; + this.enabled_ = false; + } + var _proto = RetryManager.prototype; + _proto.getIsEnabled = function getIsEnabled() { + return this.enabled_; + }; + _proto.enable = function enable() { + this.enabled_ = true; + }; + _proto.disable = function disable() { + this.enabled_ = false; + }; + _proto.reset = function reset() { + this.maxAttempts_ = 1; + this.delayFactor_ = 0.1; + this.fuzzFactor_ = 0.1; + this.initialDelay_ = 1000; + this.enabled_ = false; + }; + _proto.getMaxAttempts = function getMaxAttempts() { + return this.maxAttempts_; + }; + _proto.setMaxAttempts = function setMaxAttempts(maxAttempts) { + this.maxAttempts_ = maxAttempts; + }; + _proto.getDelayFactor = function getDelayFactor() { + return this.delayFactor_; + }; + _proto.setDelayFactor = function setDelayFactor(delayFactor) { + this.delayFactor_ = delayFactor; + }; + _proto.getFuzzFactor = function getFuzzFactor() { + return this.fuzzFactor_; + }; + _proto.setFuzzFactor = function setFuzzFactor(fuzzFactor) { + this.fuzzFactor_ = fuzzFactor; + }; + _proto.getInitialDelay = function getInitialDelay() { + return this.initialDelay_; + }; + _proto.setInitialDelay = function setInitialDelay(initialDelay) { + this.initialDelay_ = initialDelay; + }; + _proto.createRetry = function createRetry(_temp) { + var _ref = _temp === void 0 ? {} : _temp, + maxAttempts = _ref.maxAttempts, + delayFactor = _ref.delayFactor, + fuzzFactor = _ref.fuzzFactor, + initialDelay = _ref.initialDelay; + return new Retry({ + maxAttempts: maxAttempts || this.maxAttempts_, + delayFactor: delayFactor || this.delayFactor_, + fuzzFactor: fuzzFactor || this.fuzzFactor_, + initialDelay: initialDelay || this.initialDelay_ + }); + }; + return RetryManager; + }(); + var Retry = /*#__PURE__*/function () { + function Retry(options) { + this.maxAttempts_ = options.maxAttempts; + this.delayFactor_ = options.delayFactor; + this.fuzzFactor_ = options.fuzzFactor; + this.currentDelay_ = options.initialDelay; + this.currentAttempt_ = 1; + } + var _proto2 = Retry.prototype; + _proto2.moveToNextAttempt = function moveToNextAttempt() { + this.currentAttempt_++; + var delayDelta = this.currentDelay_ * this.delayFactor_; + this.currentDelay_ = this.currentDelay_ + delayDelta; + }; + _proto2.shouldRetry = function shouldRetry() { + return this.currentAttempt_ < this.maxAttempts_; + }; + _proto2.getCurrentDelay = function getCurrentDelay() { + return this.currentDelay_; + }; + _proto2.getCurrentMinPossibleDelay = function getCurrentMinPossibleDelay() { + return (1 - this.fuzzFactor_) * this.currentDelay_; + }; + _proto2.getCurrentMaxPossibleDelay = function getCurrentMaxPossibleDelay() { + return (1 + this.fuzzFactor_) * this.currentDelay_; + } + /** + * For example fuzzFactor is 0.1 + * This means ±10% deviation + * So if we have delay as 1000 + * This function can generate any value from 900 to 1100 + */; + _proto2.getCurrentFuzzedDelay = function getCurrentFuzzedDelay() { + var lowValue = this.getCurrentMinPossibleDelay(); + var highValue = this.getCurrentMaxPossibleDelay(); + return lowValue + Math.random() * (highValue - lowValue); + }; + return Retry; + }(); + var retry = RetryManager; + var httpResponseHandler = function httpResponseHandler(callback, decodeResponseBody) { if (decodeResponseBody === void 0) { decodeResponseBody = false; } - return function (err, response, responseBody) { // if the XHR failed, return that error if (err) { @@ -7879,14 +7735,11 @@ return; } // if the HTTP status code is 4xx or 5xx, the request also failed - if (response.statusCode >= 400 && response.statusCode <= 599) { var cause = responseBody; - if (decodeResponseBody) { if (window_1.TextDecoder) { var charset = getCharset(response.headers && response.headers['content-type']); - try { cause = new TextDecoder(charset).decode(responseBody); } catch (e) {} @@ -7894,39 +7747,35 @@ cause = String.fromCharCode.apply(null, new Uint8Array(responseBody)); } } - callback({ cause: cause }); return; } // otherwise, request succeeded - callback(null, responseBody); }; }; - function getCharset(contentTypeHeader) { if (contentTypeHeader === void 0) { contentTypeHeader = ''; } - return contentTypeHeader.toLowerCase().split(';').reduce(function (charset, contentType) { var _contentType$split = contentType.split('='), - type = _contentType$split[0], - value = _contentType$split[1]; - + type = _contentType$split[0], + value = _contentType$split[1]; if (type.trim() === 'charset') { return value.trim(); } - return charset; }, 'utf-8'); } - var httpHandler = httpResponseHandler; createXHR.httpHandler = httpHandler; + createXHR.requestInterceptorsStorage = new interceptors(); + createXHR.responseInterceptorsStorage = new interceptors(); + createXHR.retryManager = new retry(); /** * @license * slighly modified parse-headers 2.0.2 @@ -7937,16 +7786,13 @@ var parseHeaders = function parseHeaders(headers) { var result = {}; - if (!headers) { return result; } - headers.trim().split('\n').forEach(function (row) { var index = row.indexOf(':'); var key = row.slice(0, index).trim().toLowerCase(); var value = row.slice(index + 1).trim(); - if (typeof result[key] === 'undefined') { result[key] = value; } else if (Array.isArray(result[key])) { @@ -7957,7 +7803,6 @@ }); return result; }; - var lib = createXHR; // Allow use of default import syntax in TypeScript var default_1 = createXHR; @@ -7970,27 +7815,21 @@ return _createXHR(options); }; }); - function forEachArray(array, iterator) { for (var i = 0; i < array.length; i++) { iterator(array[i]); } } - function isEmpty(obj) { for (var i in obj) { if (obj.hasOwnProperty(i)) return false; } - return true; } - function initParams(uri, options, callback) { var params = uri; - if (isFunction_1(options)) { callback = options; - if (typeof uri === "string") { params = { uri: uri @@ -8001,82 +7840,109 @@ uri: uri }); } - params.callback = callback; return params; } - function createXHR(uri, options, callback) { options = initParams(uri, options, callback); return _createXHR(options); } - function _createXHR(options) { if (typeof options.callback === "undefined") { throw new Error("callback argument missing"); + } // call all registered request interceptors for a given request type: + + if (options.requestType && createXHR.requestInterceptorsStorage.getIsEnabled()) { + var requestInterceptorPayload = { + uri: options.uri || options.url, + headers: options.headers || {}, + body: options.body, + metadata: options.metadata || {}, + retry: options.retry, + timeout: options.timeout + }; + var updatedPayload = createXHR.requestInterceptorsStorage.execute(options.requestType, requestInterceptorPayload); + options.uri = updatedPayload.uri; + options.headers = updatedPayload.headers; + options.body = updatedPayload.body; + options.metadata = updatedPayload.metadata; + options.retry = updatedPayload.retry; + options.timeout = updatedPayload.timeout; } - var called = false; - var callback = function cbOnce(err, response, body) { if (!called) { called = true; options.callback(err, response, body); } }; - function readystatechange() { - if (xhr.readyState === 4) { + // do not call load 2 times when response interceptors are enabled + // why do we even need this 2nd load? + if (xhr.readyState === 4 && !createXHR.responseInterceptorsStorage.getIsEnabled()) { setTimeout(loadFunc, 0); } } - function getBody() { // Chrome with requestType=blob throws errors arround when even testing access to responseText var body = undefined; - if (xhr.response) { body = xhr.response; } else { body = xhr.responseText || getXml(xhr); } - if (isJson) { try { body = JSON.parse(body); } catch (e) {} } - return body; } - function errorFunc(evt) { clearTimeout(timeoutTimer); - + clearTimeout(options.retryTimeout); if (!(evt instanceof Error)) { evt = new Error("" + (evt || "Unknown XMLHttpRequest Error")); } + evt.statusCode = 0; // we would like to retry on error: - evt.statusCode = 0; + if (!aborted && createXHR.retryManager.getIsEnabled() && options.retry && options.retry.shouldRetry()) { + options.retryTimeout = setTimeout(function () { + options.retry.moveToNextAttempt(); // we want to re-use the same options and the same xhr object: + + options.xhr = xhr; + _createXHR(options); + }, options.retry.getCurrentFuzzedDelay()); + return; + } // call all registered response interceptors for a given request type: + + if (options.requestType && createXHR.responseInterceptorsStorage.getIsEnabled()) { + var responseInterceptorPayload = { + headers: failureResponse.headers || {}, + body: failureResponse.body, + responseUrl: xhr.responseURL, + responseType: xhr.responseType + }; + var _updatedPayload = createXHR.responseInterceptorsStorage.execute(options.requestType, responseInterceptorPayload); + failureResponse.body = _updatedPayload.body; + failureResponse.headers = _updatedPayload.headers; + } return callback(evt, failureResponse); } // will load the data & process the response in a special response object - function loadFunc() { if (aborted) return; var status; clearTimeout(timeoutTimer); - + clearTimeout(options.retryTimeout); if (options.useXDR && xhr.status === undefined) { //IE8 CORS GET successful response doesn't have a status field, but body is fine status = 200; } else { status = xhr.status === 1223 ? 204 : xhr.status; } - var response = failureResponse; var err = null; - if (status !== 0) { response = { body: getBody(), @@ -8086,20 +7952,28 @@ url: uri, rawRequest: xhr }; - if (xhr.getAllResponseHeaders) { //remember xhr can in fact be XDR for CORS in IE response.headers = parseHeaders(xhr.getAllResponseHeaders()); } } else { err = new Error("Internal XMLHttpRequest Error"); - } + } // call all registered response interceptors for a given request type: + if (options.requestType && createXHR.responseInterceptorsStorage.getIsEnabled()) { + var responseInterceptorPayload = { + headers: response.headers || {}, + body: response.body, + responseUrl: xhr.responseURL, + responseType: xhr.responseType + }; + var _updatedPayload2 = createXHR.responseInterceptorsStorage.execute(options.requestType, responseInterceptorPayload); + response.body = _updatedPayload2.body; + response.headers = _updatedPayload2.headers; + } return callback(err, response, response.body); } - var xhr = options.xhr || null; - if (!xhr) { if (options.cors || options.useXDR) { xhr = new createXHR.XDomainRequest(); @@ -8107,7 +7981,6 @@ xhr = new createXHR.XMLHttpRequest(); } } - var key; var aborted; var uri = xhr.url = options.uri || options.url; @@ -8125,7 +7998,6 @@ url: uri, rawRequest: xhr }; - if ("json" in options && options.json !== false) { isJson = true; headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json"); //Don't override existing accept header declared by user @@ -8136,18 +8008,16 @@ body = JSON.stringify(options.json === true ? body : options.json); } } - xhr.onreadystatechange = readystatechange; xhr.onload = loadFunc; xhr.onerror = errorFunc; // IE9 must have onprogress be set to a unique function. xhr.onprogress = function () {// IE must die }; - xhr.onabort = function () { aborted = true; + clearTimeout(options.retryTimeout); }; - xhr.ontimeout = errorFunc; xhr.open(method, uri, !sync, options.username, options.password); //has to be after open @@ -8157,7 +8027,6 @@ // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent - if (!sync && options.timeout > 0) { timeoutTimer = setTimeout(function () { if (aborted) return; @@ -8169,7 +8038,6 @@ errorFunc(e); }, options.timeout); } - if (xhr.setRequestHeader) { for (key in headers) { if (headers.hasOwnProperty(key)) { @@ -8179,22 +8047,18 @@ } else if (options.headers && !isEmpty(options.headers)) { throw new Error("Headers cannot be set on an XDomainRequest object"); } - if ("responseType" in options) { xhr.responseType = options.responseType; } - if ("beforeSend" in options && typeof options.beforeSend === "function") { options.beforeSend(xhr); } // Microsoft Edge browser sends "undefined" when send is called with undefined value. // XMLHttpRequest spec says to pass null as body to indicate no body // See https://github.com/naugtur/xhr/issues/100. - xhr.send(body || null); return xhr; } - function getXml(xhr) { // xhr.responseXML will throw Exception "InvalidStateError" or "DOMException" // See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML. @@ -8202,19 +8066,21 @@ if (xhr.responseType === "document") { return xhr.responseXML; } - var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"; - if (xhr.responseType === "" && !firefoxBugTakenEffect) { return xhr.responseXML; } } catch (e) {} - return null; } - function noop$1() {} - lib["default"] = default_1; + lib.default = default_1; + + /** + * @file text-track.js + */ + + /** @import Tech from '../tech/tech' */ /** * Takes a webvtt file contents and parses it into cues @@ -8227,44 +8093,34 @@ * * @private */ - - var parseCues = function parseCues(srcContent, track) { - var parser = new window.WebVTT.Parser(window, window.vttjs, window.WebVTT.StringDecoder()); - var errors = []; - + const parseCues = function (srcContent, track) { + const parser = new window.WebVTT.Parser(window, window.vttjs, window.WebVTT.StringDecoder()); + const errors = []; parser.oncue = function (cue) { track.addCue(cue); }; - parser.onparsingerror = function (error) { errors.push(error); }; - parser.onflush = function () { track.trigger({ type: 'loadeddata', target: track }); }; - parser.parse(srcContent); - if (errors.length > 0) { if (window.console && window.console.groupCollapsed) { - window.console.groupCollapsed("Text Track parsing errors for " + track.src); + window.console.groupCollapsed(`Text Track parsing errors for ${track.src}`); } - - errors.forEach(function (error) { - return log$1.error(error); - }); - + errors.forEach(error => log$1.error(error)); if (window.console && window.console.groupEnd) { window.console.groupEnd(); } } - parser.flush(); }; + /** * Load a `TextTrack` from a specified url. * @@ -8276,42 +8132,35 @@ * * @private */ - - - var loadTrack = function loadTrack(src, track) { - var opts = { + const loadTrack = function (src, track) { + const opts = { uri: src }; - var crossOrigin = isCrossOrigin(src); - + const crossOrigin = isCrossOrigin(src); if (crossOrigin) { opts.cors = crossOrigin; } - - var withCredentials = track.tech_.crossOrigin() === 'use-credentials'; - + const withCredentials = track.tech_.crossOrigin() === 'use-credentials'; if (withCredentials) { opts.withCredentials = withCredentials; } - - lib(opts, bind(this, function (err, response, responseBody) { + lib(opts, bind_(this, function (err, response, responseBody) { if (err) { return log$1.error(err, response); } + track.loaded_ = true; - track.loaded_ = true; // Make sure that vttjs has loaded, otherwise, wait till it finished loading + // Make sure that vttjs has loaded, otherwise, wait till it finished loading // NOTE: this is only used for the alt/video.novtt.js build - if (typeof window.WebVTT !== 'function') { if (track.tech_) { // to prevent use before define eslint error, we define loadHandler // as a let here - track.tech_.any(['vttjsloaded', 'vttjserror'], function (event) { + track.tech_.any(['vttjsloaded', 'vttjserror'], event => { if (event.type === 'vttjserror') { - log$1.error("vttjs failed to load, stopping trying to process " + track.src); + log$1.error(`vttjs failed to load, stopping trying to process ${track.src}`); return; } - return parseCues(responseBody, track); }); } @@ -8320,17 +8169,14 @@ } })); }; + /** * A representation of a single `TextTrack`. * * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack} * @extends Track */ - - - var TextTrack = /*#__PURE__*/function (_Track) { - inheritsLoose(TextTrack, _Track); - + class TextTrack extends Track { /** * Create an instance of this class. * @@ -8365,71 +8211,59 @@ * @param {boolean} [options.default] * If this track should default to on or off. */ - function TextTrack(options) { - var _this; - - if (options === void 0) { - options = {}; - } - + constructor(options = {}) { if (!options.tech) { throw new Error('A tech was not provided.'); } - - var settings = mergeOptions$3(options, { + const settings = merge$2(options, { kind: TextTrackKind[options.kind] || 'subtitles', language: options.language || options.srclang || '' }); - var mode = TextTrackMode[settings.mode] || 'disabled'; - var default_ = settings["default"]; - + let mode = TextTrackMode[settings.mode] || 'disabled'; + const default_ = settings.default; if (settings.kind === 'metadata' || settings.kind === 'chapters') { mode = 'hidden'; } - - _this = _Track.call(this, settings) || this; - _this.tech_ = settings.tech; - _this.cues_ = []; - _this.activeCues_ = []; - _this.preload_ = _this.tech_.preloadTextTracks !== false; - var cues = new TextTrackCueList(_this.cues_); - var activeCues = new TextTrackCueList(_this.activeCues_); - var changed = false; - _this.timeupdateHandler = bind(assertThisInitialized(_this), function () { + super(settings); + this.tech_ = settings.tech; + this.cues_ = []; + this.activeCues_ = []; + this.preload_ = this.tech_.preloadTextTracks !== false; + const cues = new TextTrackCueList(this.cues_); + const activeCues = new TextTrackCueList(this.activeCues_); + let changed = false; + this.timeupdateHandler = bind_(this, function (event = {}) { if (this.tech_.isDisposed()) { return; } - if (!this.tech_.isReady_) { - this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler); + if (event.type !== 'timeupdate') { + this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler); + } return; - } // Accessing this.activeCues for the side-effects of updating itself + } + + // Accessing this.activeCues for the side-effects of updating itself // due to its nature as a getter function. Do not remove or cues will // stop updating! // Use the setter to prevent deletion from uglify (pure_getters rule) - - this.activeCues = this.activeCues; - if (changed) { this.trigger('cuechange'); changed = false; } - - this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler); + if (event.type !== 'timeupdate') { + this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler); + } }); - - var disposeHandler = function disposeHandler() { - _this.stopTracking(); + const disposeHandler = () => { + this.stopTracking(); }; - - _this.tech_.one('dispose', disposeHandler); - + this.tech_.one('dispose', disposeHandler); if (mode !== 'disabled') { - _this.startTracking(); + this.startTracking(); } - - Object.defineProperties(assertThisInitialized(_this), { + Object.defineProperties(this, { /** * @memberof TextTrack * @member {boolean} default @@ -8439,13 +8273,12 @@ * * @readonly */ - "default": { - get: function get() { + default: { + get() { return default_; }, - set: function set() {} + set() {} }, - /** * @memberof TextTrack * @member {string} mode @@ -8456,27 +8289,22 @@ * @fires TextTrack#modechange */ mode: { - get: function get() { + get() { return mode; }, - set: function set(newMode) { + set(newMode) { if (!TextTrackMode[newMode]) { return; } - if (mode === newMode) { return; } - mode = newMode; - if (!this.preload_ && mode !== 'disabled' && this.cues.length === 0) { // On-demand load. loadTrack(this.src, this); } - this.stopTracking(); - if (mode !== 'disabled') { this.startTracking(); } @@ -8487,14 +8315,11 @@ * > Note: This is not part of the spec! * * @event TextTrack#modechange - * @type {EventTarget~Event} + * @type {Event} */ - - this.trigger('modechange'); } }, - /** * @memberof TextTrack * @member {TextTrackCueList} cues @@ -8502,16 +8327,14 @@ * @instance */ cues: { - get: function get() { + get() { if (!this.loaded_) { return null; } - return cues; }, - set: function set() {} + set() {} }, - /** * @memberof TextTrack * @member {TextTrackCueList} activeCues @@ -8519,146 +8342,125 @@ * @instance */ activeCues: { - get: function get() { + get() { if (!this.loaded_) { return null; - } // nothing to do - + } + // nothing to do if (this.cues.length === 0) { return activeCues; } - - var ct = this.tech_.currentTime(); - var active = []; - - for (var i = 0, l = this.cues.length; i < l; i++) { - var cue = this.cues[i]; - + const ct = this.tech_.currentTime(); + const active = []; + for (let i = 0, l = this.cues.length; i < l; i++) { + const cue = this.cues[i]; if (cue.startTime <= ct && cue.endTime >= ct) { active.push(cue); - } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) { - active.push(cue); } } - changed = false; - if (active.length !== this.activeCues_.length) { changed = true; } else { - for (var _i = 0; _i < active.length; _i++) { - if (this.activeCues_.indexOf(active[_i]) === -1) { + for (let i = 0; i < active.length; i++) { + if (this.activeCues_.indexOf(active[i]) === -1) { changed = true; } } } - this.activeCues_ = active; activeCues.setCues_(this.activeCues_); return activeCues; }, // /!\ Keep this setter empty (see the timeupdate handler above) - set: function set() {} + set() {} } }); - if (settings.src) { - _this.src = settings.src; - - if (!_this.preload_) { + this.src = settings.src; + if (!this.preload_) { // Tracks will load on-demand. // Act like we're loaded for other purposes. - _this.loaded_ = true; + this.loaded_ = true; } - - if (_this.preload_ || settings.kind !== 'subtitles' && settings.kind !== 'captions') { - loadTrack(_this.src, assertThisInitialized(_this)); + if (this.preload_ || settings.kind !== 'subtitles' && settings.kind !== 'captions') { + loadTrack(this.src, this); } } else { - _this.loaded_ = true; + this.loaded_ = true; } - - return _this; } - - var _proto = TextTrack.prototype; - - _proto.startTracking = function startTracking() { + startTracking() { + // More precise cues based on requestVideoFrameCallback with a requestAnimationFram fallback this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler); - }; - - _proto.stopTracking = function stopTracking() { + // Also listen to timeupdate in case rVFC/rAF stops (window in background, audio in video el) + this.tech_.on('timeupdate', this.timeupdateHandler); + } + stopTracking() { if (this.rvf_) { this.tech_.cancelVideoFrameCallback(this.rvf_); this.rvf_ = undefined; } + this.tech_.off('timeupdate', this.timeupdateHandler); } + /** * Add a cue to the internal list of cues. * * @param {TextTrack~Cue} cue * The cue to add to our internal list */ - ; + addCue(originalCue) { + let cue = originalCue; - _proto.addCue = function addCue(originalCue) { - var cue = originalCue; - - if (window.vttjs && !(originalCue instanceof window.vttjs.VTTCue)) { + // Testing if the cue is a VTTCue in a way that survives minification + if (!('getCueAsHTML' in cue)) { cue = new window.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text); - - for (var prop in originalCue) { + for (const prop in originalCue) { if (!(prop in cue)) { cue[prop] = originalCue[prop]; } - } // make sure that `id` is copied over - + } + // make sure that `id` is copied over cue.id = originalCue.id; cue.originalCue_ = originalCue; } - - var tracks = this.tech_.textTracks(); - - for (var i = 0; i < tracks.length; i++) { + const tracks = this.tech_.textTracks(); + for (let i = 0; i < tracks.length; i++) { if (tracks[i] !== this) { tracks[i].removeCue(cue); } } - this.cues_.push(cue); this.cues.setCues_(this.cues_); } + /** * Remove a cue from our internal list * * @param {TextTrack~Cue} removeCue * The cue to remove from our internal list */ - ; - - _proto.removeCue = function removeCue(_removeCue) { - var i = this.cues_.length; - + removeCue(removeCue) { + let i = this.cues_.length; while (i--) { - var cue = this.cues_[i]; - - if (cue === _removeCue || cue.originalCue_ && cue.originalCue_ === _removeCue) { + const cue = this.cues_[i]; + if (cue === removeCue || cue.originalCue_ && cue.originalCue_ === removeCue) { this.cues_.splice(i, 1); this.cues.setCues_(this.cues_); break; } } - }; + } + } - return TextTrack; - }(Track); /** * cuechange - One or more cues in the track have become active or stopped being active. + * + * @protected */ - - TextTrack.prototype.allowedEvents_ = { cuechange: 'cuechange' }; @@ -8670,10 +8472,7 @@ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack} * @extends Track */ - - var AudioTrack = /*#__PURE__*/function (_Track) { - inheritsLoose(AudioTrack, _Track); - + class AudioTrack extends Track { /** * Create an instance of this class. * @@ -8696,18 +8495,13 @@ * If this track is the one that is currently playing. If this track is part of * an {@link AudioTrackList}, only one {@link AudioTrack} will be enabled. */ - function AudioTrack(options) { - var _this; - - if (options === void 0) { - options = {}; - } - - var settings = mergeOptions$3(options, { + constructor(options = {}) { + const settings = merge$2(options, { kind: AudioTrackKind[options.kind] || '' }); - _this = _Track.call(this, settings) || this; - var enabled = false; + super(settings); + let enabled = false; + /** * @memberof AudioTrack * @member {boolean} enabled @@ -8717,18 +8511,17 @@ * * @fires VideoTrack#selectedchange */ - - Object.defineProperty(assertThisInitialized(_this), 'enabled', { - get: function get() { + Object.defineProperty(this, 'enabled', { + get() { return enabled; }, - set: function set(newEnabled) { + set(newEnabled) { // an invalid or unchanged value if (typeof newEnabled !== 'boolean' || newEnabled === enabled) { return; } - enabled = newEnabled; + /** * An event that fires when enabled changes on this track. This allows * the AudioTrackList that holds this track to act accordingly. @@ -8737,25 +8530,21 @@ * this internally without an event. * * @event AudioTrack#enabledchange - * @type {EventTarget~Event} + * @type {Event} */ - this.trigger('enabledchange'); } - }); // if the user sets this track to selected then + }); + + // if the user sets this track to selected then // set selected to that true value otherwise // we keep it false - if (settings.enabled) { - _this.enabled = settings.enabled; + this.enabled = settings.enabled; } - - _this.loaded_ = true; - return _this; + this.loaded_ = true; } - - return AudioTrack; - }(Track); + } /** * A representation of a single `VideoTrack`. @@ -8763,10 +8552,7 @@ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack} * @extends Track */ - - var VideoTrack = /*#__PURE__*/function (_Track) { - inheritsLoose(VideoTrack, _Track); - + class VideoTrack extends Track { /** * Create an instance of this class. * @@ -8788,18 +8574,13 @@ * @param {boolean} [options.selected] * If this track is the one that is currently playing. */ - function VideoTrack(options) { - var _this; - - if (options === void 0) { - options = {}; - } - - var settings = mergeOptions$3(options, { + constructor(options = {}) { + const settings = merge$2(options, { kind: VideoTrackKind[options.kind] || '' }); - _this = _Track.call(this, settings) || this; - var selected = false; + super(settings); + let selected = false; + /** * @memberof VideoTrack * @member {boolean} selected @@ -8809,18 +8590,17 @@ * * @fires VideoTrack#selectedchange */ - - Object.defineProperty(assertThisInitialized(_this), 'selected', { - get: function get() { + Object.defineProperty(this, 'selected', { + get() { return selected; }, - set: function set(newSelected) { + set(newSelected) { // an invalid or unchanged value if (typeof newSelected !== 'boolean' || newSelected === selected) { return; } - selected = newSelected; + /** * An event that fires when selected changes on this track. This allows * the VideoTrackList that holds this track to act accordingly. @@ -8829,45 +8609,34 @@ * this internally without an event. * * @event VideoTrack#selectedchange - * @type {EventTarget~Event} + * @type {Event} */ - this.trigger('selectedchange'); } - }); // if the user sets this track to selected then + }); + + // if the user sets this track to selected then // set selected to that true value otherwise // we keep it false - if (settings.selected) { - _this.selected = settings.selected; + this.selected = settings.selected; } - - return _this; } - - return VideoTrack; - }(Track); + } /** - * @memberof HTMLTrackElement - * @typedef {HTMLTrackElement~ReadyState} - * @enum {number} + * @file html-track-element.js */ - var NONE = 0; - var LOADING = 1; - var LOADED = 2; - var ERROR = 3; + /** @import Tech from '../tech/tech' */ + /** * A single track represented in the DOM. * * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement} * @extends EventTarget */ - - var HTMLTrackElement = /*#__PURE__*/function (_EventTarget) { - inheritsLoose(HTMLTrackElement, _EventTarget); - + class HTMLTrackElement extends EventTarget$2 { /** * Create an instance of this class. * @@ -8902,22 +8671,16 @@ * @param {boolean} [options.default] * If this track should default to on or off. */ - function HTMLTrackElement(options) { - var _this; - - if (options === void 0) { - options = {}; - } - - _this = _EventTarget.call(this) || this; - var readyState; - var track = new TextTrack(options); - _this.kind = track.kind; - _this.src = track.src; - _this.srclang = track.language; - _this.label = track.label; - _this["default"] = track["default"]; - Object.defineProperties(assertThisInitialized(_this), { + constructor(options = {}) { + super(); + let readyState; + const track = new TextTrack(options); + this.kind = track.kind; + this.src = track.src; + this.srclang = track.language; + this.label = track.label; + this.default = track.default; + Object.defineProperties(this, { /** * @memberof HTMLTrackElement * @member {HTMLTrackElement~ReadyState} readyState @@ -8925,11 +8688,10 @@ * @instance */ readyState: { - get: function get() { + get() { return readyState; } }, - /** * @memberof HTMLTrackElement * @member {TextTrack} track @@ -8938,45 +8700,72 @@ * */ track: { - get: function get() { + get() { return track; } } }); - readyState = NONE; + readyState = HTMLTrackElement.NONE; + /** * @listens TextTrack#loadeddata * @fires HTMLTrackElement#load */ - - track.addEventListener('loadeddata', function () { - readyState = LOADED; - - _this.trigger({ + track.addEventListener('loadeddata', () => { + readyState = HTMLTrackElement.LOADED; + this.trigger({ type: 'load', - target: assertThisInitialized(_this) + target: this }); }); - return _this; } + } - return HTMLTrackElement; - }(EventTarget$2); - + /** + * @protected + */ HTMLTrackElement.prototype.allowedEvents_ = { load: 'load' }; - HTMLTrackElement.NONE = NONE; - HTMLTrackElement.LOADING = LOADING; - HTMLTrackElement.LOADED = LOADED; - HTMLTrackElement.ERROR = ERROR; + + /** + * The text track not loaded state. + * + * @type {number} + * @static + */ + HTMLTrackElement.NONE = 0; + + /** + * The text track loading state. + * + * @type {number} + * @static + */ + HTMLTrackElement.LOADING = 1; + + /** + * The text track loaded state. + * + * @type {number} + * @static + */ + HTMLTrackElement.LOADED = 2; + + /** + * The text track failed to load state. + * + * @type {number} + * @static + */ + HTMLTrackElement.ERROR = 3; /* * This file contains all track properties that are used in * player.js, tech.js, html5.js and possibly other techs in the future. */ - var NORMAL = { + const NORMAL = { audio: { ListClass: AudioTrackList, TrackClass: AudioTrack, @@ -8994,10 +8783,10 @@ } }; Object.keys(NORMAL).forEach(function (type) { - NORMAL[type].getterName = type + "Tracks"; - NORMAL[type].privateName = type + "Tracks_"; + NORMAL[type].getterName = `${type}Tracks`; + NORMAL[type].privateName = `${type}Tracks_`; }); - var REMOTE = { + const REMOTE = { remoteText: { ListClass: TextTrackList, TrackClass: TextTrack, @@ -9013,9 +8802,7 @@ privateName: 'remoteTextTrackEls_' } }; - - var ALL = _extends_1({}, NORMAL, REMOTE); - + const ALL = Object.assign({}, NORMAL, REMOTE); REMOTE.names = Object.keys(REMOTE); NORMAL.names = Object.keys(NORMAL); ALL.names = [].concat(REMOTE.names).concat(NORMAL.names); @@ -9024,17 +8811,14 @@ var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof window !== 'undefined' ? window : {}; var doccy; - if (typeof document !== 'undefined') { doccy = document; } else { doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; - if (!doccy) { doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; } } - var document_1 = doccy; /** @@ -9054,35 +8838,32 @@ */ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ - /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ var _objCreate = Object.create || function () { function F() {} - return function (o) { if (arguments.length !== 1) { throw new Error('Object.create shim only accepts one parameter.'); } - F.prototype = o; return new F(); }; - }(); // Creates a new ParserError object from an errorData object. The errorData + }(); + + // Creates a new ParserError object from an errorData object. The errorData // object should have default code and message properties. The default message // property can be overriden by passing in a message parameter. // See ParsingError.Errors below for acceptable errors. - - function ParsingError(errorData, message) { this.name = "ParsingError"; this.code = errorData.code; this.message = message || errorData.message; } - ParsingError.prototype = _objCreate(Error.prototype); - ParsingError.prototype.constructor = ParsingError; // ParsingError metadata for acceptable ParsingErrors. + ParsingError.prototype.constructor = ParsingError; + // ParsingError metadata for acceptable ParsingErrors. ParsingError.Errors = { BadSignature: { code: 0, @@ -9092,19 +8873,17 @@ code: 1, message: "Malformed time stamp." } - }; // Try to parse input as a time stamp. + }; + // Try to parse input as a time stamp. function parseTimeStamp(input) { function computeSeconds(h, m, s, f) { return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000; } - var m = input.match(/^(\d+):(\d{1,2})(:\d{1,2})?\.(\d{3})/); - if (!m) { return null; } - if (m[3]) { // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds] return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]); @@ -9116,17 +8895,16 @@ // Timestamp takes the form of [minutes]:[seconds].[milliseconds] return computeSeconds(0, m[1], m[2], m[4]); } - } // A settings object holds key/value pairs and will ignore anything but the first + } + + // A settings object holds key/value pairs and will ignore anything but the first // assignment to a specific key. - - function Settings() { this.values = _objCreate(null); } - Settings.prototype = { // Only accept the first assignment to any key. - set: function set(k, v) { + set: function (k, v) { if (!this.get(k) && v !== "") { this.values[k] = v; } @@ -9136,19 +8914,18 @@ // a number of possible default values as properties where 'defaultKey' is // the key of the property that will be chosen; otherwise it's assumed to be // a single value. - get: function get(k, dflt, defaultKey) { + get: function (k, dflt, defaultKey) { if (defaultKey) { return this.has(k) ? this.values[k] : dflt[defaultKey]; } - return this.has(k) ? this.values[k] : dflt; }, // Check whether we have a value for a key. - has: function has(k) { + has: function (k) { return k in this.values; }, // Accept a setting if its one of the given alternatives. - alt: function alt(k, v, a) { + alt: function (k, v, a) { for (var n = 0; n < a.length; ++n) { if (v === a[n]) { this.set(k, v); @@ -9157,66 +8934,57 @@ } }, // Accept a setting if its a valid (signed) integer. - integer: function integer(k, v) { + integer: function (k, v) { if (/^-?\d+$/.test(v)) { // integer this.set(k, parseInt(v, 10)); } }, // Accept a setting if its a valid percentage. - percent: function percent(k, v) { - + percent: function (k, v) { if (v.match(/^([\d]{1,3})(\.[\d]*)?%$/)) { v = parseFloat(v); - if (v >= 0 && v <= 100) { this.set(k, v); return true; } } - return false; } - }; // Helper function to parse input into groups separated by 'groupDelim', and - // interprete each group as a key/value pair separated by 'keyValueDelim'. + }; + // Helper function to parse input into groups separated by 'groupDelim', and + // interprete each group as a key/value pair separated by 'keyValueDelim'. function parseOptions(input, callback, keyValueDelim, groupDelim) { var groups = groupDelim ? input.split(groupDelim) : [input]; - for (var i in groups) { if (typeof groups[i] !== "string") { continue; } - var kv = groups[i].split(keyValueDelim); - if (kv.length !== 2) { continue; } - - var k = kv[0]; - var v = kv[1]; + var k = kv[0].trim(); + var v = kv[1].trim(); callback(k, v); } } - function parseCue(input, cue, regionList) { // Remember the original input if we need to throw an error. - var oInput = input; // 4.1 WebVTT timestamp - + var oInput = input; + // 4.1 WebVTT timestamp function consumeTimeStamp() { var ts = parseTimeStamp(input); - if (ts === null) { throw new ParsingError(ParsingError.Errors.BadTimeStamp, "Malformed timestamp: " + oInput); - } // Remove time stamp from input. - - + } + // Remove time stamp from input. input = input.replace(/^[^\sa-zA-Z-]+/, ""); return ts; - } // 4.4.2 WebVTT cue settings - + } + // 4.4.2 WebVTT cue settings function consumeCueSettings(input, cue) { var settings = new Settings(); parseOptions(input, function (k, v) { @@ -9229,63 +8997,51 @@ break; } } - break; - case "vertical": settings.alt(k, v, ["rl", "lr"]); break; - case "line": var vals = v.split(","), - vals0 = vals[0]; + vals0 = vals[0]; settings.integer(k, vals0); settings.percent(k, vals0) ? settings.set("snapToLines", false) : null; settings.alt(k, vals0, ["auto"]); - if (vals.length === 2) { settings.alt("lineAlign", vals[1], ["start", "center", "end"]); } - break; - case "position": vals = v.split(","); settings.percent(k, vals[0]); - if (vals.length === 2) { settings.alt("positionAlign", vals[1], ["start", "center", "end"]); } - break; - case "size": settings.percent(k, v); break; - case "align": settings.alt(k, v, ["start", "center", "end", "left", "right"]); break; } - }, /:/, /\s/); // Apply default values for any missing fields. + }, /:/, /\s/); + // Apply default values for any missing fields. cue.region = settings.get("region", null); cue.vertical = settings.get("vertical", ""); - try { cue.line = settings.get("line", "auto"); } catch (e) {} - cue.lineAlign = settings.get("lineAlign", "start"); cue.snapToLines = settings.get("snapToLines", true); - cue.size = settings.get("size", 100); // Safari still uses the old middle value and won't accept center - + cue.size = settings.get("size", 100); + // Safari still uses the old middle value and won't accept center try { cue.align = settings.get("align", "center"); } catch (e) { cue.align = settings.get("align", "middle"); } - try { cue.position = settings.get("position", "auto"); } catch (e) { @@ -9298,7 +9054,6 @@ right: 100 }, cue.align); } - cue.positionAlign = settings.get("positionAlign", { start: "start", left: "start", @@ -9308,33 +9063,29 @@ right: "end" }, cue.align); } - function skipWhitespace() { input = input.replace(/^\s+/, ""); - } // 4.1 WebVTT cue timings. - + } + // 4.1 WebVTT cue timings. skipWhitespace(); cue.startTime = consumeTimeStamp(); // (1) collect cue start time - skipWhitespace(); - if (input.substr(0, 3) !== "-->") { // (3) next characters must match "-->" throw new ParsingError(ParsingError.Errors.BadTimeStamp, "Malformed time stamp (time stamps must be separated by '-->'): " + oInput); } - input = input.substr(3); skipWhitespace(); cue.endTime = consumeTimeStamp(); // (5) collect cue end time - // 4.1 WebVTT cue settings list. + // 4.1 WebVTT cue settings list. skipWhitespace(); consumeCueSettings(input, cue); - } // When evaluating this file as part of a Webpack bundle for server + } + + // When evaluating this file as part of a Webpack bundle for server // side rendering, `document` is an empty object. - - var TEXTAREA_ELEMENT = document_1.createElement && document_1.createElement("textarea"); var TAG_NAME = { c: "span", @@ -9345,9 +9096,10 @@ rt: "rt", v: "span", lang: "span" - }; // 5.1 default text color - // 5.2 default text background color is equivalent to text color with bg_ prefix + }; + // 5.1 default text color + // 5.2 default text background color is equivalent to text color with bg_ prefix var DEFAULT_COLOR_CLASS = { white: 'rgba(255,255,255,1)', lime: 'rgba(0,255,0,1)', @@ -9364,61 +9116,53 @@ }; var NEEDS_PARENT = { rt: "ruby" - }; // Parse content into a document fragment. + }; + // Parse content into a document fragment. function parseContent(window, input) { function nextToken() { // Check for end-of-string. if (!input) { return null; - } // Consume 'n' characters from the input. - + } + // Consume 'n' characters from the input. function consume(result) { input = input.substr(result.length); return result; } - - var m = input.match(/^([^<]*)(<[^>]*>?)?/); // If there is some text before the next tag, return it, otherwise return + var m = input.match(/^([^<]*)(<[^>]*>?)?/); + // If there is some text before the next tag, return it, otherwise return // the tag. - return consume(m[1] ? m[1] : m[2]); } - function unescape(s) { TEXTAREA_ELEMENT.innerHTML = s; s = TEXTAREA_ELEMENT.textContent; TEXTAREA_ELEMENT.textContent = ""; return s; } - function shouldAdd(current, element) { return !NEEDS_PARENT[element.localName] || NEEDS_PARENT[element.localName] === current.localName; - } // Create an element for this tag. - + } + // Create an element for this tag. function createElement(type, annotation) { var tagName = TAG_NAME[type]; - if (!tagName) { return null; } - var element = window.document.createElement(tagName); var name = TAG_ANNOTATION[type]; - if (name && annotation) { element[name] = annotation.trim(); } - return element; } - var rootDiv = window.document.createElement("div"), - current = rootDiv, - t, - tagStack = []; - + current = rootDiv, + t, + tagStack = []; while ((t = nextToken()) !== null) { if (t[0] === '<') { if (t[1] === "/") { @@ -9426,49 +9170,40 @@ if (tagStack.length && tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) { tagStack.pop(); current = current.parentNode; - } // Otherwise just ignore the end tag. - - + } + // Otherwise just ignore the end tag. continue; } - var ts = parseTimeStamp(t.substr(1, t.length - 2)); var node; - if (ts) { // Timestamps are lead nodes as well. node = window.document.createProcessingInstruction("timestamp", ts); current.appendChild(node); continue; } - - var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/); // If we can't parse the tag, skip to the next tag. - + var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/); + // If we can't parse the tag, skip to the next tag. if (!m) { continue; - } // Try to construct an element, and ignore the tag if we couldn't. - - + } + // Try to construct an element, and ignore the tag if we couldn't. node = createElement(m[1], m[3]); - if (!node) { continue; - } // Determine if the tag should be added based on the context of where it + } + // Determine if the tag should be added based on the context of where it // is placed in the cuetext. - - if (!shouldAdd(current, node)) { continue; - } // Set the class list (as a list of classes, separated by space). - - + } + // Set the class list (as a list of classes, separated by space). if (m[2]) { var classes = m[2].split('.'); classes.forEach(function (cl) { - var bgColor = /^bg_/.test(cl); // slice out `bg_` if it's a background color - + var bgColor = /^bg_/.test(cl); + // slice out `bg_` if it's a background color var colorName = bgColor ? cl.slice(3) : cl; - if (DEFAULT_COLOR_CLASS.hasOwnProperty(colorName)) { var propName = bgColor ? 'background-color' : 'color'; var propValue = DEFAULT_COLOR_CLASS[colorName]; @@ -9476,150 +9211,124 @@ } }); node.className = classes.join(' '); - } // Append the node to the current node, and enter the scope of the new + } + // Append the node to the current node, and enter the scope of the new // node. - - tagStack.push(m[1]); current.appendChild(node); current = node; continue; - } // Text nodes are leaf nodes. - + } + // Text nodes are leaf nodes. current.appendChild(window.document.createTextNode(unescape(t))); } - return rootDiv; - } // This is a list of all the Unicode characters that have a strong + } + + // This is a list of all the Unicode characters that have a strong // right-to-left category. What this means is that these characters are // written right-to-left for sure. It was generated by pulling all the strong // right-to-left characters out of the Unicode data table. That table can // found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt - - var strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6], [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d], [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6], [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5], [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815], [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858], [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f], [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c], [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1], [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc], [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808], [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855], [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f], [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13], [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58], [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72], [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f], [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32], [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42], [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f], [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59], [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62], [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77], [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b], [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]]; - function isStrongRTLChar(charCode) { for (var i = 0; i < strongRTLRanges.length; i++) { var currentRange = strongRTLRanges[i]; - if (charCode >= currentRange[0] && charCode <= currentRange[1]) { return true; } } - return false; } - function determineBidi(cueDiv) { var nodeStack = [], - text = "", - charCode; - + text = "", + charCode; if (!cueDiv || !cueDiv.childNodes) { return "ltr"; } - function pushNodes(nodeStack, node) { for (var i = node.childNodes.length - 1; i >= 0; i--) { nodeStack.push(node.childNodes[i]); } } - function nextTextNode(nodeStack) { if (!nodeStack || !nodeStack.length) { return null; } - var node = nodeStack.pop(), - text = node.textContent || node.innerText; - + text = node.textContent || node.innerText; if (text) { // TODO: This should match all unicode type B characters (paragraph // separator characters). See issue #115. var m = text.match(/^.*(\n|\r)/); - if (m) { nodeStack.length = 0; return m[0]; } - return text; } - if (node.tagName === "ruby") { return nextTextNode(nodeStack); } - if (node.childNodes) { pushNodes(nodeStack, node); return nextTextNode(nodeStack); } } - pushNodes(nodeStack, cueDiv); - while (text = nextTextNode(nodeStack)) { for (var i = 0; i < text.length; i++) { charCode = text.charCodeAt(i); - if (isStrongRTLChar(charCode)) { return "rtl"; } } } - return "ltr"; } - function computeLinePos(cue) { if (typeof cue.line === "number" && (cue.snapToLines || cue.line >= 0 && cue.line <= 100)) { return cue.line; } - if (!cue.track || !cue.track.textTrackList || !cue.track.textTrackList.mediaElement) { return -1; } - var track = cue.track, - trackList = track.textTrackList, - count = 0; - + trackList = track.textTrackList, + count = 0; for (var i = 0; i < trackList.length && trackList[i] !== track; i++) { if (trackList[i].mode === "showing") { count++; } } - return ++count * -1; } + function StyleBox() {} - function StyleBox() {} // Apply styles to a div. If there is no div passed then it defaults to the + // Apply styles to a div. If there is no div passed then it defaults to the // div on 'this'. - - StyleBox.prototype.applyStyles = function (styles, div) { div = div || this.div; - for (var prop in styles) { if (styles.hasOwnProperty(prop)) { div.style[prop] = styles[prop]; } } }; - StyleBox.prototype.formatStyle = function (val, unit) { return val === 0 ? 0 : val + unit; - }; // Constructs the computed display state of the cue (a div). Places the div + }; + + // Constructs the computed display state of the cue (a div). Places the div // into the overlay which should be a block level element (usually a div). - - function CueStyleBox(window, cue, styleOptions) { StyleBox.call(this); - this.cue = cue; // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will - // have inline positioning and will function as the cue background box. + this.cue = cue; + // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will + // have inline positioning and will function as the cue background box. this.cueDiv = parseContent(window, cue.text); var styles = { color: "rgba(255, 255, 255, 1)", @@ -9633,10 +9342,11 @@ writingMode: cue.vertical === "" ? "horizontal-tb" : cue.vertical === "lr" ? "vertical-lr" : "vertical-rl", unicodeBidi: "plaintext" }; - this.applyStyles(styles, this.cueDiv); // Create an absolutely positioned div that will be used to position the cue + this.applyStyles(styles, this.cueDiv); + + // Create an absolutely positioned div that will be used to position the cue // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS // mirrors of them except middle instead of center on Safari. - this.div = window.document.createElement("div"); styles = { direction: determineBidi(this.cueDiv), @@ -9648,34 +9358,35 @@ position: "absolute" }; this.applyStyles(styles); - this.div.appendChild(this.cueDiv); // Calculate the distance from the reference edge of the viewport to the text + this.div.appendChild(this.cueDiv); + + // Calculate the distance from the reference edge of the viewport to the text // position of the cue box. The reference edge will be resolved later when // the box orientation styles are applied. - var textPos = 0; - switch (cue.positionAlign) { case "start": + case "line-left": textPos = cue.position; break; - case "center": textPos = cue.position - cue.size / 2; break; - case "end": + case "line-right": textPos = cue.position - cue.size; break; - } // Horizontal box orientation; textPos is the distance from the left edge of the + } + + // Horizontal box orientation; textPos is the distance from the left edge of the // area to the left edge of the box and cue.size is the distance extending to // the right from there. - - if (cue.vertical === "") { this.applyStyles({ left: this.formatStyle(textPos, "%"), width: this.formatStyle(cue.size, "%") - }); // Vertical box orientation; textPos is the distance from the top edge of the + }); + // Vertical box orientation; textPos is the distance from the top edge of the // area to the top edge of the box and cue.size is the height extending // downwards from there. } else { @@ -9684,7 +9395,6 @@ height: this.formatStyle(cue.size, "%") }); } - this.move = function (box) { this.applyStyles({ top: this.formatStyle(box.top, "px"), @@ -9696,32 +9406,30 @@ }); }; } - CueStyleBox.prototype = _objCreate(StyleBox.prototype); - CueStyleBox.prototype.constructor = CueStyleBox; // Represents the co-ordinates of an Element in a way that we can easily + CueStyleBox.prototype.constructor = CueStyleBox; + + // Represents the co-ordinates of an Element in a way that we can easily // compute things with such as if it overlaps or intersects with another Element. // Can initialize it with either a StyleBox or another BoxPosition. - function BoxPosition(obj) { // Either a BoxPosition was passed in and we need to copy it, or a StyleBox // was passed in and we need to copy the results of 'getBoundingClientRect' // as the object returned is readonly. All co-ordinate values are in reference // to the viewport origin (top left). var lh, height, width, top; - if (obj.div) { height = obj.div.offsetHeight; width = obj.div.offsetWidth; top = obj.div.offsetTop; var rects = (rects = obj.div.childNodes) && (rects = rects[0]) && rects.getClientRects && rects.getClientRects(); - obj = obj.div.getBoundingClientRect(); // In certain cases the outter div will be slightly larger then the sum of + obj = obj.div.getBoundingClientRect(); + // In certain cases the outter div will be slightly larger then the sum of // the inner div's lines. This could be due to bold text, etc, on some platforms. // In this case we should get the average line height and use that. This will // result in the desired behaviour. - lh = rects ? Math.max(rects[0] && rects[0].height || 0, obj.height / rects.length) : 0; } - this.left = obj.left; this.right = obj.right; this.top = obj.top || top; @@ -9729,91 +9437,83 @@ this.bottom = obj.bottom || top + (obj.height || height); this.width = obj.width || width; this.lineHeight = lh !== undefined ? lh : obj.lineHeight; - } // Move the box along a particular axis. Optionally pass in an amount to move + } + + // Move the box along a particular axis. Optionally pass in an amount to move // the box. If no amount is passed then the default is the line height of the // box. - - BoxPosition.prototype.move = function (axis, toMove) { toMove = toMove !== undefined ? toMove : this.lineHeight; - switch (axis) { case "+x": this.left += toMove; this.right += toMove; break; - case "-x": this.left -= toMove; this.right -= toMove; break; - case "+y": this.top += toMove; this.bottom += toMove; break; - case "-y": this.top -= toMove; this.bottom -= toMove; break; } - }; // Check if this box overlaps another box, b2. - + }; + // Check if this box overlaps another box, b2. BoxPosition.prototype.overlaps = function (b2) { return this.left < b2.right && this.right > b2.left && this.top < b2.bottom && this.bottom > b2.top; - }; // Check if this box overlaps any other boxes in boxes. - + }; + // Check if this box overlaps any other boxes in boxes. BoxPosition.prototype.overlapsAny = function (boxes) { for (var i = 0; i < boxes.length; i++) { if (this.overlaps(boxes[i])) { return true; } } - return false; - }; // Check if this box is within another box. - + }; + // Check if this box is within another box. BoxPosition.prototype.within = function (container) { return this.top >= container.top && this.bottom <= container.bottom && this.left >= container.left && this.right <= container.right; - }; // Check if this box is entirely within the container or it is overlapping + }; + + // Check if this box is entirely within the container or it is overlapping // on the edge opposite of the axis direction passed. For example, if "+x" is // passed and the box is overlapping on the left edge of the container, then // return true. - - BoxPosition.prototype.overlapsOppositeAxis = function (container, axis) { switch (axis) { case "+x": return this.left < container.left; - case "-x": return this.right > container.right; - case "+y": return this.top < container.top; - case "-y": return this.bottom > container.bottom; } - }; // Find the percentage of the area that this box is overlapping with another + }; + + // Find the percentage of the area that this box is overlapping with another // box. - - BoxPosition.prototype.intersectPercentage = function (b2) { var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)), - y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)), - intersectArea = x * y; + y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)), + intersectArea = x * y; return intersectArea / (this.height * this.width); - }; // Convert the positions from this box to CSS compatible positions using + }; + + // Convert the positions from this box to CSS compatible positions using // the reference container's positions. This has to be done because this // box's positions are in reference to the viewport origin, whereas, CSS // values are in referecne to their respective edges. - - BoxPosition.prototype.toCSSCompatValues = function (reference) { return { top: this.top - reference.top, @@ -9823,10 +9523,10 @@ height: this.height, width: this.width }; - }; // Get an object that represents the box's position without anything extra. + }; + + // Get an object that represents the box's position without anything extra. // Can pass a StyleBox, HTMLElement, or another BoxPositon. - - BoxPosition.getSimpleBoxPosition = function (obj) { var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0; var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0; @@ -9841,11 +9541,11 @@ width: obj.width || width }; return ret; - }; // Move a StyleBox to its specified, or next best, position. The containerBox + }; + + // Move a StyleBox to its specified, or next best, position. The containerBox // is the box that contains the StyleBox, such as a div. boxPositions are // a list of other boxes that the styleBox can't overlap with. - - function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) { // Find the best position for a cue box, b, on the video. The axis parameter // is a list of axis, the order of which, it will move the box along. For example: @@ -9854,173 +9554,156 @@ // it along the x axis in the negative direction. function findBestPosition(b, axis) { var bestPosition, - specifiedPosition = new BoxPosition(b), - percentage = 1; // Highest possible so the first thing we get is better. + specifiedPosition = new BoxPosition(b), + percentage = 1; // Highest possible so the first thing we get is better. for (var i = 0; i < axis.length; i++) { while (b.overlapsOppositeAxis(containerBox, axis[i]) || b.within(containerBox) && b.overlapsAny(boxPositions)) { b.move(axis[i]); - } // We found a spot where we aren't overlapping anything. This is our + } + // We found a spot where we aren't overlapping anything. This is our // best position. - - if (b.within(containerBox)) { return b; } - - var p = b.intersectPercentage(containerBox); // If we're outside the container box less then we were on our last try + var p = b.intersectPercentage(containerBox); + // If we're outside the container box less then we were on our last try // then remember this position as the best position. - if (percentage > p) { bestPosition = new BoxPosition(b); percentage = p; - } // Reset the box position to the specified position. - - + } + // Reset the box position to the specified position. b = new BoxPosition(specifiedPosition); } - return bestPosition || specifiedPosition; } - var boxPosition = new BoxPosition(styleBox), - cue = styleBox.cue, - linePos = computeLinePos(cue), - axis = []; // If we have a line number to align the cue to. + cue = styleBox.cue, + linePos = computeLinePos(cue), + axis = []; + // If we have a line number to align the cue to. if (cue.snapToLines) { var size; - switch (cue.vertical) { case "": axis = ["+y", "-y"]; size = "height"; break; - case "rl": axis = ["+x", "-x"]; size = "width"; break; - case "lr": axis = ["-x", "+x"]; size = "width"; break; } - var step = boxPosition.lineHeight, - position = step * Math.round(linePos), - maxPosition = containerBox[size] + step, - initialAxis = axis[0]; // If the specified intial position is greater then the max position then + position = step * Math.round(linePos), + maxPosition = containerBox[size] + step, + initialAxis = axis[0]; + + // If the specified intial position is greater then the max position then // clamp the box to the amount of steps it would take for the box to // reach the max position. - if (Math.abs(position) > maxPosition) { position = position < 0 ? -1 : 1; position *= Math.ceil(maxPosition / step) * step; - } // If computed line position returns negative then line numbers are + } + + // If computed line position returns negative then line numbers are // relative to the bottom of the video instead of the top. Therefore, we // need to increase our initial position by the length or width of the // video, depending on the writing direction, and reverse our axis directions. - - if (linePos < 0) { position += cue.vertical === "" ? containerBox.height : containerBox.width; axis = axis.reverse(); - } // Move the box to the specified position. This may not be its best + } + + // Move the box to the specified position. This may not be its best // position. - - boxPosition.move(initialAxis, position); } else { // If we have a percentage line value for the cue. var calculatedPercentage = boxPosition.lineHeight / containerBox.height * 100; - switch (cue.lineAlign) { case "center": linePos -= calculatedPercentage / 2; break; - case "end": linePos -= calculatedPercentage; break; - } // Apply initial line position to the cue box. - + } + // Apply initial line position to the cue box. switch (cue.vertical) { case "": styleBox.applyStyles({ top: styleBox.formatStyle(linePos, "%") }); break; - case "rl": styleBox.applyStyles({ left: styleBox.formatStyle(linePos, "%") }); break; - case "lr": styleBox.applyStyles({ right: styleBox.formatStyle(linePos, "%") }); break; } + axis = ["+y", "-x", "+x", "-y"]; - axis = ["+y", "-x", "+x", "-y"]; // Get the box position again after we've applied the specified positioning + // Get the box position again after we've applied the specified positioning // to it. - boxPosition = new BoxPosition(styleBox); } - var bestPosition = findBestPosition(boxPosition, axis); styleBox.move(bestPosition.toCSSCompatValues(containerBox)); } + function WebVTT$1() { + // Nothing + } - function WebVTT$1() {// Nothing - } // Helper to allow strings to be decoded instead of the default binary utf8 data. - - + // Helper to allow strings to be decoded instead of the default binary utf8 data. WebVTT$1.StringDecoder = function () { return { - decode: function decode(data) { + decode: function (data) { if (!data) { return ""; } - if (typeof data !== "string") { throw new Error("Error - expected string data."); } - return decodeURIComponent(encodeURIComponent(data)); } }; }; - WebVTT$1.convertCueToDOMTree = function (window, cuetext) { if (!window || !cuetext) { return null; } - return parseContent(window, cuetext); }; - var FONT_SIZE_PERCENT = 0.05; var FONT_STYLE = "sans-serif"; - var CUE_BACKGROUND_PADDING = "1.5%"; // Runs the processing model over the cues and regions passed to it. + var CUE_BACKGROUND_PADDING = "1.5%"; + + // Runs the processing model over the cues and regions passed to it. // @param overlay A block level element (usually a div) that the computed cues // and regions will be placed into. - WebVTT$1.processCues = function (window, cues, overlay) { if (!window || !cues || !overlay) { return null; - } // Remove all previous children. - + } + // Remove all previous children. while (overlay.firstChild) { overlay.removeChild(overlay.firstChild); } - var paddedOverlay = window.document.createElement("div"); paddedOverlay.style.position = "absolute"; paddedOverlay.style.left = "0"; @@ -10028,64 +9711,60 @@ paddedOverlay.style.top = "0"; paddedOverlay.style.bottom = "0"; paddedOverlay.style.margin = CUE_BACKGROUND_PADDING; - overlay.appendChild(paddedOverlay); // Determine if we need to compute the display states of the cues. This could + overlay.appendChild(paddedOverlay); + + // Determine if we need to compute the display states of the cues. This could // be the case if a cue's state has been changed since the last computation or // if it has not been computed yet. - function shouldCompute(cues) { for (var i = 0; i < cues.length; i++) { if (cues[i].hasBeenReset || !cues[i].displayState) { return true; } } - return false; - } // We don't need to recompute the cues' display states. Just reuse them. - + } + // We don't need to recompute the cues' display states. Just reuse them. if (!shouldCompute(cues)) { for (var i = 0; i < cues.length; i++) { paddedOverlay.appendChild(cues[i].displayState); } - return; } - var boxPositions = [], - containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay), - fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100; + containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay), + fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100; var styleOptions = { font: fontSize + "px " + FONT_STYLE }; - (function () { var styleBox, cue; - for (var i = 0; i < cues.length; i++) { - cue = cues[i]; // Compute the intial position and styles of the cue div. + cue = cues[i]; + // Compute the intial position and styles of the cue div. styleBox = new CueStyleBox(window, cue, styleOptions); - paddedOverlay.appendChild(styleBox.div); // Move the cue div to it's correct line position. + paddedOverlay.appendChild(styleBox.div); - moveBoxToLinePosition(window, styleBox, containerBox, boxPositions); // Remember the computed div so that we don't have to recompute it later + // Move the cue div to it's correct line position. + moveBoxToLinePosition(window, styleBox, containerBox, boxPositions); + + // Remember the computed div so that we don't have to recompute it later // if we don't have too. - cue.displayState = styleBox.div; boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox)); } })(); }; - WebVTT$1.Parser = function (window, vttjs, decoder) { if (!decoder) { decoder = vttjs; vttjs = {}; } - if (!vttjs) { vttjs = {}; } - this.window = window; this.vttjs = vttjs; this.state = "INITIAL"; @@ -10093,52 +9772,47 @@ this.decoder = decoder || new TextDecoder("utf8"); this.regionList = []; }; - WebVTT$1.Parser.prototype = { // If the error is a ParsingError then report it to the consumer if // possible. If it's not a ParsingError then throw it like normal. - reportOrThrowError: function reportOrThrowError(e) { + reportOrThrowError: function (e) { if (e instanceof ParsingError) { this.onparsingerror && this.onparsingerror(e); } else { throw e; } }, - parse: function parse(data) { - var self = this; // If there is no data then we won't decode it, but will just try to parse + parse: function (data) { + var self = this; + + // If there is no data then we won't decode it, but will just try to parse // whatever is in buffer already. This may occur in circumstances, for // example when flush() is called. - if (data) { // Try to decode the data that we received. self.buffer += self.decoder.decode(data, { stream: true }); } - function collectNextLine() { var buffer = self.buffer; var pos = 0; - while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') { ++pos; } - - var line = buffer.substr(0, pos); // Advance the buffer early in case we fail below. - + var line = buffer.substr(0, pos); + // Advance the buffer early in case we fail below. if (buffer[pos] === '\r') { ++pos; } - if (buffer[pos] === '\n') { ++pos; } - self.buffer = buffer.substr(pos); return line; - } // 3.4 WebVTT region and WebVTT region settings syntax - + } + // 3.4 WebVTT region and WebVTT region settings syntax function parseRegion(input) { var settings = new Settings(); parseOptions(input, function (k, v) { @@ -10146,44 +9820,37 @@ case "id": settings.set(k, v); break; - case "width": settings.percent(k, v); break; - case "lines": settings.integer(k, v); break; - case "regionanchor": case "viewportanchor": var xy = v.split(','); - if (xy.length !== 2) { break; - } // We have to make sure both x and y parse, so use a temporary + } + // We have to make sure both x and y parse, so use a temporary // settings object here. - - var anchor = new Settings(); anchor.percent("x", xy[0]); anchor.percent("y", xy[1]); - if (!anchor.has("x") || !anchor.has("y")) { break; } - settings.set(k + "X", anchor.get("x")); settings.set(k + "Y", anchor.get("y")); break; - case "scroll": settings.alt(k, v, ["up"]); break; } - }, /=/, /\s/); // Create the region, using default values for any values that were not - // specified. + }, /=/, /\s/); + // Create the region, using default values for any values that were not + // specified. if (settings.has("id")) { var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)(); region.width = settings.get("width", 100); @@ -10192,21 +9859,21 @@ region.regionAnchorY = settings.get("regionanchorY", 100); region.viewportAnchorX = settings.get("viewportanchorX", 0); region.viewportAnchorY = settings.get("viewportanchorY", 100); - region.scroll = settings.get("scroll", ""); // Register the region. - - self.onregion && self.onregion(region); // Remember the VTTRegion for later in case we parse any VTTCues that + region.scroll = settings.get("scroll", ""); + // Register the region. + self.onregion && self.onregion(region); + // Remember the VTTRegion for later in case we parse any VTTCues that // reference it. - self.regionList.push({ id: settings.get("id"), region: region }); } - } // draft-pantos-http-live-streaming-20 + } + + // draft-pantos-http-live-streaming-20 // https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-3.5 // 3.5 WebVTT - - function parseTimestampMap(input) { var settings = new Settings(); parseOptions(input, function (k, v) { @@ -10214,7 +9881,6 @@ case "MPEGT": settings.integer(k + 'S', v); break; - case "LOCA": settings.set(k + 'L', parseTimeStamp(v)); break; @@ -10224,9 +9890,9 @@ "MPEGTS": settings.get("MPEGTS"), "LOCAL": settings.get("LOCAL") }); - } // 3.2 WebVTT metadata header syntax - + } + // 3.2 WebVTT metadata header syntax function parseHeader(input) { if (input.match(/X-TIMESTAMP-MAP/)) { // This line contains HLS X-TIMESTAMP-MAP metadata @@ -10247,42 +9913,34 @@ } }, /:/); } - } // 5.1 WebVTT file parsing. - + } + // 5.1 WebVTT file parsing. try { var line; - if (self.state === "INITIAL") { // We can't start parsing until we have the first line. if (!/\r\n|\n/.test(self.buffer)) { return this; } - line = collectNextLine(); var m = line.match(/^WEBVTT([ \t].*)?$/); - if (!m || !m[0]) { throw new ParsingError(ParsingError.Errors.BadSignature); } - self.state = "HEADER"; } - var alreadyCollectedLine = false; - while (self.buffer) { // We can't parse a line until we have the full line. if (!/\r\n|\n/.test(self.buffer)) { return this; } - if (!alreadyCollectedLine) { line = collectNextLine(); } else { alreadyCollectedLine = false; } - switch (self.state) { case "HEADER": // 13-18 - Allow a header (metadata) under the WEBVTT line. @@ -10292,69 +9950,57 @@ // An empty line terminates the header and starts the body (cues). self.state = "ID"; } - continue; - case "NOTE": // Ignore NOTE blocks. if (!line) { self.state = "ID"; } - continue; - case "ID": // Check for the start of NOTE blocks. if (/^NOTE($|[ \t])/.test(line)) { self.state = "NOTE"; break; - } // 19-29 - Allow any number of line terminators, then initialize new cue values. - - + } + // 19-29 - Allow any number of line terminators, then initialize new cue values. if (!line) { continue; } - - self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, ""); // Safari still uses the old middle value and won't accept center - + self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, ""); + // Safari still uses the old middle value and won't accept center try { self.cue.align = "center"; } catch (e) { self.cue.align = "middle"; } - - self.state = "CUE"; // 30-39 - Check if self line contains an optional identifier or timing data. - + self.state = "CUE"; + // 30-39 - Check if self line contains an optional identifier or timing data. if (line.indexOf("-->") === -1) { self.cue.id = line; continue; } - // Process line as start of a cue. - /*falls through*/ - case "CUE": // 40 - Collect cue timings and settings. try { parseCue(line, self.cue, self.regionList); } catch (e) { - self.reportOrThrowError(e); // In case of an error ignore rest of the cue. - + self.reportOrThrowError(e); + // In case of an error ignore rest of the cue. self.cue = null; self.state = "BADCUE"; continue; } - self.state = "CUETEXT"; continue; - case "CUETEXT": - var hasSubstring = line.indexOf("-->") !== -1; // 34 - If we have an empty line then report the cue. + var hasSubstring = line.indexOf("-->") !== -1; + // 34 - If we have an empty line then report the cue. // 35 - If we have the special substring '-->' then report the cue, // but do not collect the line as we need to process the current // one as a new cue. - if (!line || hasSubstring && (alreadyCollectedLine = true)) { // We are done parsing self cue. self.oncue && self.oncue(self.cue); @@ -10362,61 +10008,53 @@ self.state = "ID"; continue; } - if (self.cue.text) { self.cue.text += "\n"; } - self.cue.text += line.replace(/\u2028/g, '\n').replace(/u2029/g, '\n'); continue; - case "BADCUE": // BADCUE // 54-62 - Collect and discard the remaining cue. if (!line) { self.state = "ID"; } - continue; } } } catch (e) { - self.reportOrThrowError(e); // If we are currently parsing a cue, report what we have. + self.reportOrThrowError(e); + // If we are currently parsing a cue, report what we have. if (self.state === "CUETEXT" && self.cue && self.oncue) { self.oncue(self.cue); } - - self.cue = null; // Enter BADWEBVTT state if header was not parsed correctly otherwise + self.cue = null; + // Enter BADWEBVTT state if header was not parsed correctly otherwise // another exception occurred so enter BADCUE state. - self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE"; } - return this; }, - flush: function flush() { + flush: function () { var self = this; - try { // Finish decoding the stream. - self.buffer += self.decoder.decode(); // Synthesize the end of the current cue or region. - + self.buffer += self.decoder.decode(); + // Synthesize the end of the current cue or region. if (self.cue || self.state === "HEADER") { self.buffer += "\n\n"; self.parse(); - } // If we've flushed, parsed, and we're still on the INITIAL state then + } + // If we've flushed, parsed, and we're still on the INITIAL state then // that means we don't have enough of the stream to parse the first // line. - - if (self.state === "INITIAL") { throw new ParsingError(ParsingError.Errors.BadSignature); } } catch (e) { self.reportOrThrowError(e); } - self.onflush && self.onflush(); return this; } @@ -10438,6 +10076,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + var autoKeyword = "auto"; var directionSetting = { "": 1, @@ -10454,34 +10093,31 @@ "line-left": 1, "line-right": 1 }; - function findDirectionSetting(value) { if (typeof value !== "string") { return false; } - var dir = directionSetting[value.toLowerCase()]; return dir ? value.toLowerCase() : false; } - function findAlignSetting(value) { if (typeof value !== "string") { return false; } - var align = alignSetting[value.toLowerCase()]; return align ? value.toLowerCase() : false; } - function VTTCue(startTime, endTime, text) { /** * Shim implementation specific properties. These properties are not in * the spec. */ + // Lets us know when the VTTCue's data has changed in such a way that we need // to recompute its display state. This lets us compute its display state // lazily. this.hasBeenReset = false; + /** * VTTCue and TextTrackCue properties * http://dev.w3.org/html5/webvtt/#vttcue-interface @@ -10504,118 +10140,113 @@ Object.defineProperties(this, { "id": { enumerable: true, - get: function get() { + get: function () { return _id; }, - set: function set(value) { + set: function (value) { _id = "" + value; } }, "pauseOnExit": { enumerable: true, - get: function get() { + get: function () { return _pauseOnExit; }, - set: function set(value) { + set: function (value) { _pauseOnExit = !!value; } }, "startTime": { enumerable: true, - get: function get() { + get: function () { return _startTime; }, - set: function set(value) { + set: function (value) { if (typeof value !== "number") { throw new TypeError("Start time must be set to a number."); } - _startTime = value; this.hasBeenReset = true; } }, "endTime": { enumerable: true, - get: function get() { + get: function () { return _endTime; }, - set: function set(value) { + set: function (value) { if (typeof value !== "number") { throw new TypeError("End time must be set to a number."); } - _endTime = value; this.hasBeenReset = true; } }, "text": { enumerable: true, - get: function get() { + get: function () { return _text; }, - set: function set(value) { + set: function (value) { _text = "" + value; this.hasBeenReset = true; } }, "region": { enumerable: true, - get: function get() { + get: function () { return _region; }, - set: function set(value) { + set: function (value) { _region = value; this.hasBeenReset = true; } }, "vertical": { enumerable: true, - get: function get() { + get: function () { return _vertical; }, - set: function set(value) { - var setting = findDirectionSetting(value); // Have to check for false because the setting an be an empty string. - + set: function (value) { + var setting = findDirectionSetting(value); + // Have to check for false because the setting an be an empty string. if (setting === false) { throw new SyntaxError("Vertical: an invalid or illegal direction string was specified."); } - _vertical = setting; this.hasBeenReset = true; } }, "snapToLines": { enumerable: true, - get: function get() { + get: function () { return _snapToLines; }, - set: function set(value) { + set: function (value) { _snapToLines = !!value; this.hasBeenReset = true; } }, "line": { enumerable: true, - get: function get() { + get: function () { return _line; }, - set: function set(value) { + set: function (value) { if (typeof value !== "number" && value !== autoKeyword) { throw new SyntaxError("Line: an invalid number or illegal string was specified."); } - _line = value; this.hasBeenReset = true; } }, "lineAlign": { enumerable: true, - get: function get() { + get: function () { return _lineAlign; }, - set: function set(value) { + set: function (value) { var setting = findAlignSetting(value); - if (!setting) { console.warn("lineAlign: an invalid or illegal string was specified."); } else { @@ -10626,26 +10257,24 @@ }, "position": { enumerable: true, - get: function get() { + get: function () { return _position; }, - set: function set(value) { + set: function (value) { if (value < 0 || value > 100) { throw new Error("Position must be between 0 and 100."); } - _position = value; this.hasBeenReset = true; } }, "positionAlign": { enumerable: true, - get: function get() { + get: function () { return _positionAlign; }, - set: function set(value) { + set: function (value) { var setting = findAlignSetting(value); - if (!setting) { console.warn("positionAlign: an invalid or illegal string was specified."); } else { @@ -10656,52 +10285,49 @@ }, "size": { enumerable: true, - get: function get() { + get: function () { return _size; }, - set: function set(value) { + set: function (value) { if (value < 0 || value > 100) { throw new Error("Size must be between 0 and 100."); } - _size = value; this.hasBeenReset = true; } }, "align": { enumerable: true, - get: function get() { + get: function () { return _align; }, - set: function set(value) { + set: function (value) { var setting = findAlignSetting(value); - if (!setting) { throw new SyntaxError("align: an invalid or illegal alignment string was specified."); } - _align = setting; this.hasBeenReset = true; } } }); + /** * Other spec defined properties */ - // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state + // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state this.displayState = undefined; } + /** * VTTCue methods */ - VTTCue.prototype.getCueAsHTML = function () { // Assume WebVTT.convertCueToDOMTree is on the global. return WebVTT.convertCueToDOMTree(window, this.text); }; - var vttcue = VTTCue; /** @@ -10719,25 +10345,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + var scrollSetting = { "": true, "up": true }; - function findScrollSetting(value) { if (typeof value !== "string") { return false; } - var scroll = scrollSetting[value.toLowerCase()]; return scroll ? value.toLowerCase() : false; } - function isValidPercentValue(value) { return typeof value === "number" && value >= 0 && value <= 100; - } // VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface - + } + // VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface function VTTRegion() { var _width = 100; var _lines = 3; @@ -10749,90 +10373,84 @@ Object.defineProperties(this, { "width": { enumerable: true, - get: function get() { + get: function () { return _width; }, - set: function set(value) { + set: function (value) { if (!isValidPercentValue(value)) { throw new Error("Width must be between 0 and 100."); } - _width = value; } }, "lines": { enumerable: true, - get: function get() { + get: function () { return _lines; }, - set: function set(value) { + set: function (value) { if (typeof value !== "number") { throw new TypeError("Lines must be set to a number."); } - _lines = value; } }, "regionAnchorY": { enumerable: true, - get: function get() { + get: function () { return _regionAnchorY; }, - set: function set(value) { + set: function (value) { if (!isValidPercentValue(value)) { throw new Error("RegionAnchorX must be between 0 and 100."); } - _regionAnchorY = value; } }, "regionAnchorX": { enumerable: true, - get: function get() { + get: function () { return _regionAnchorX; }, - set: function set(value) { + set: function (value) { if (!isValidPercentValue(value)) { throw new Error("RegionAnchorY must be between 0 and 100."); } - _regionAnchorX = value; } }, "viewportAnchorY": { enumerable: true, - get: function get() { + get: function () { return _viewportAnchorY; }, - set: function set(value) { + set: function (value) { if (!isValidPercentValue(value)) { throw new Error("ViewportAnchorY must be between 0 and 100."); } - _viewportAnchorY = value; } }, "viewportAnchorX": { enumerable: true, - get: function get() { + get: function () { return _viewportAnchorX; }, - set: function set(value) { + set: function (value) { if (!isValidPercentValue(value)) { throw new Error("ViewportAnchorX must be between 0 and 100."); } - _viewportAnchorX = value; } }, "scroll": { enumerable: true, - get: function get() { + get: function () { return _scroll; }, - set: function set(value) { - var setting = findScrollSetting(value); // Have to check for false as an empty string is a legal value. - + set: function (value) { + var setting = findScrollSetting(value); + // Have to check for false as an empty string is a legal value. if (setting === false) { console.warn("Scroll: an invalid or illegal string was specified."); } else { @@ -10842,7 +10460,6 @@ } }); } - var vttregion = VTTRegion; var browserIndex = createCommonjsModule(function (module) { @@ -10861,10 +10478,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + // Default exports for Node. Export the extended versions of VTTCue and // VTTRegion in Node since we likely want the capability to convert back and // forth between JSON. If we don't then it's not that big of a deal since we're // off browser. + var vttjs = module.exports = { WebVTT: vtt, VTTCue: vttcue, @@ -10876,17 +10495,14 @@ var regionShim = vttjs.VTTRegion; var nativeVTTCue = window_1.VTTCue; var nativeVTTRegion = window_1.VTTRegion; - vttjs.shim = function () { window_1.VTTCue = cueShim; window_1.VTTRegion = regionShim; }; - vttjs.restore = function () { window_1.VTTCue = nativeVTTCue; window_1.VTTRegion = nativeVTTRegion; }; - if (!window_1.VTTCue) { vttjs.shim(); } @@ -10895,13 +10511,19 @@ browserIndex.VTTCue; browserIndex.VTTRegion; + /** + * @file tech.js + */ + + /** @import { TimeRange } from '../utils/time' */ + /** * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string * that just contains the src url alone. * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};` * `var SourceString = 'http://example.com/some-video.mp4';` * - * @typedef {Object|string} Tech~SourceObject + * @typedef {Object|string} SourceObject * * @property {string} src * The url to the source @@ -10933,146 +10555,100 @@ * @return {TextTrack} * The text track that was created. */ - - function createTrackHelper(self, kind, label, language, options) { - if (options === void 0) { - options = {}; - } - - var tracks = self.textTracks(); + function createTrackHelper(self, kind, label, language, options = {}) { + const tracks = self.textTracks(); options.kind = kind; - if (label) { options.label = label; } - if (language) { options.language = language; } - options.tech = self; - var track = new ALL.text.TrackClass(options); + const track = new ALL.text.TrackClass(options); tracks.addTrack(track); return track; } + /** * This is the base class for media playback technology controllers, such as * {@link HTML5} * * @extends Component */ - - - var Tech = /*#__PURE__*/function (_Component) { - inheritsLoose(Tech, _Component); - + class Tech extends Component$1 { /** * Create an instance of this Tech. * * @param {Object} [options] * The key/value store of player options. * - * @param {Component~ReadyCallback} ready + * @param {Function} [ready] * Callback function to call when the `HTML5` Tech is ready. */ - function Tech(options, ready) { - var _this; - - if (options === void 0) { - options = {}; - } - - if (ready === void 0) { - ready = function ready() {}; - } - + constructor(options = {}, ready = function () {}) { // we don't want the tech to report user activity automatically. // This is done manually in addControlsListeners options.reportTouchActivity = false; - _this = _Component.call(this, null, options, ready) || this; + super(null, options, ready); + this.onDurationChange_ = e => this.onDurationChange(e); + this.trackProgress_ = e => this.trackProgress(e); + this.trackCurrentTime_ = e => this.trackCurrentTime(e); + this.stopTrackingCurrentTime_ = e => this.stopTrackingCurrentTime(e); + this.disposeSourceHandler_ = e => this.disposeSourceHandler(e); + this.queuedHanders_ = new Set(); - _this.onDurationChange_ = function (e) { - return _this.onDurationChange(e); - }; - - _this.trackProgress_ = function (e) { - return _this.trackProgress(e); - }; - - _this.trackCurrentTime_ = function (e) { - return _this.trackCurrentTime(e); - }; - - _this.stopTrackingCurrentTime_ = function (e) { - return _this.stopTrackingCurrentTime(e); - }; - - _this.disposeSourceHandler_ = function (e) { - return _this.disposeSourceHandler(e); - }; - - _this.queuedHanders_ = new Set(); // keep track of whether the current source has played at all to + // keep track of whether the current source has played at all to // implement a very limited played() - - _this.hasStarted_ = false; - - _this.on('playing', function () { + this.hasStarted_ = false; + this.on('playing', function () { this.hasStarted_ = true; }); - - _this.on('loadstart', function () { + this.on('loadstart', function () { this.hasStarted_ = false; }); - - ALL.names.forEach(function (name) { - var props = ALL[name]; - + ALL.names.forEach(name => { + const props = ALL[name]; if (options && options[props.getterName]) { - _this[props.privateName] = options[props.getterName]; - } - }); // Manually track progress in cases where the browser/tech doesn't report it. - - if (!_this.featuresProgressEvents) { - _this.manualProgressOn(); - } // Manually track timeupdates in cases where the browser/tech doesn't report it. - - - if (!_this.featuresTimeupdateEvents) { - _this.manualTimeUpdatesOn(); - } - - ['Text', 'Audio', 'Video'].forEach(function (track) { - if (options["native" + track + "Tracks"] === false) { - _this["featuresNative" + track + "Tracks"] = false; + this[props.privateName] = options[props.getterName]; } }); + // Manually track progress in cases where the browser/tech doesn't report it. + if (!this.featuresProgressEvents) { + this.manualProgressOn(); + } + + // Manually track timeupdates in cases where the browser/tech doesn't report it. + if (!this.featuresTimeupdateEvents) { + this.manualTimeUpdatesOn(); + } + ['Text', 'Audio', 'Video'].forEach(track => { + if (options[`native${track}Tracks`] === false) { + this[`featuresNative${track}Tracks`] = false; + } + }); if (options.nativeCaptions === false || options.nativeTextTracks === false) { - _this.featuresNativeTextTracks = false; + this.featuresNativeTextTracks = false; } else if (options.nativeCaptions === true || options.nativeTextTracks === true) { - _this.featuresNativeTextTracks = true; + this.featuresNativeTextTracks = true; } - - if (!_this.featuresNativeTextTracks) { - _this.emulateTextTracks(); + if (!this.featuresNativeTextTracks) { + this.emulateTextTracks(); } + this.preloadTextTracks = options.preloadTextTracks !== false; + this.autoRemoteTextTracks_ = new ALL.text.ListClass(); + this.initTrackListeners(); - _this.preloadTextTracks = options.preloadTextTracks !== false; - _this.autoRemoteTextTracks_ = new ALL.text.ListClass(); - - _this.initTrackListeners(); // Turn on component tap events only if not using native controls - - + // Turn on component tap events only if not using native controls if (!options.nativeControlsForTouch) { - _this.emitTapEvents(); + this.emitTapEvents(); } - - if (_this.constructor) { - _this.name_ = _this.constructor.name || 'Unknown Tech'; + if (this.constructor) { + this.name_ = this.constructor.name || 'Unknown Tech'; } - - return _this; } + /** * A special function to trigger source set in a way that will allow player * to re-trigger if the player or tech are not ready yet. @@ -11080,37 +10656,27 @@ * @fires Tech#sourceset * @param {string} src The source string at the time of the source changing. */ - - - var _proto = Tech.prototype; - - _proto.triggerSourceset = function triggerSourceset(src) { - var _this2 = this; - + triggerSourceset(src) { if (!this.isReady_) { // on initial ready we have to trigger source set // 1ms after ready so that player can watch for it. - this.one('ready', function () { - return _this2.setTimeout(function () { - return _this2.triggerSourceset(src); - }, 1); - }); + this.one('ready', () => this.setTimeout(() => this.triggerSourceset(src), 1)); } + /** * Fired when the source is set on the tech causing the media element * to reload. * * @see {@link Player#event:sourceset} * @event Tech#sourceset - * @type {EventTarget~Event} + * @type {Event} */ - - this.trigger({ - src: src, + src, type: 'sourceset' }); } + /* Fallbacks for unsupported event types ================================================================================ */ @@ -11119,25 +10685,24 @@ * * @see {@link Tech#trackProgress} */ - ; - - _proto.manualProgressOn = function manualProgressOn() { + manualProgressOn() { this.on('durationchange', this.onDurationChange_); - this.manualProgress = true; // Trigger progress watching when a source begins loading + this.manualProgress = true; + // Trigger progress watching when a source begins loading this.one('ready', this.trackProgress_); } + /** * Turn off the polyfill for `progress` events that was created in * {@link Tech#manualProgressOn} */ - ; - - _proto.manualProgressOff = function manualProgressOff() { + manualProgressOff() { this.manualProgress = false; this.stopTrackingProgress(); this.off('durationchange', this.onDurationChange_); } + /** * This is used to trigger a `progress` event when the buffered percent changes. It * sets an interval function that will be called every 500 milliseconds to check if the @@ -11145,62 +10710,57 @@ * * > This function is called by {@link Tech#manualProgressOn} * - * @param {EventTarget~Event} event + * @param {Event} event * The `ready` event that caused this to run. * * @listens Tech#ready * @fires Tech#progress */ - ; - - _proto.trackProgress = function trackProgress(event) { + trackProgress(event) { this.stopTrackingProgress(); - this.progressInterval = this.setInterval(bind(this, function () { + this.progressInterval = this.setInterval(bind_(this, function () { // Don't trigger unless buffered amount is greater than last time - var numBufferedPercent = this.bufferedPercent(); + const numBufferedPercent = this.bufferedPercent(); if (this.bufferedPercent_ !== numBufferedPercent) { /** * See {@link Player#progress} * * @event Tech#progress - * @type {EventTarget~Event} + * @type {Event} */ this.trigger('progress'); } - this.bufferedPercent_ = numBufferedPercent; - if (numBufferedPercent === 1) { this.stopTrackingProgress(); } }), 500); } + /** * Update our internal duration on a `durationchange` event by calling * {@link Tech#duration}. * - * @param {EventTarget~Event} event + * @param {Event} event * The `durationchange` event that caused this to run. * * @listens Tech#durationchange */ - ; - - _proto.onDurationChange = function onDurationChange(event) { + onDurationChange(event) { this.duration_ = this.duration(); } + /** * Get and create a `TimeRange` object for buffering. * * @return {TimeRange} * The time range object that was created. */ - ; - - _proto.buffered = function buffered() { - return createTimeRanges(0, 0); + buffered() { + return createTimeRanges$1(0, 0); } + /** * Get the percentage of the current video that is currently buffered. * @@ -11209,46 +10769,42 @@ * video that is buffered. * */ - ; - - _proto.bufferedPercent = function bufferedPercent$1() { + bufferedPercent() { return bufferedPercent(this.buffered(), this.duration_); } + /** * Turn off the polyfill for `progress` events that was created in * {@link Tech#manualProgressOn} * Stop manually tracking progress events by clearing the interval that was set in * {@link Tech#trackProgress}. */ - ; - - _proto.stopTrackingProgress = function stopTrackingProgress() { + stopTrackingProgress() { this.clearInterval(this.progressInterval); } + /** * Polyfill the `timeupdate` event for browsers that don't support it. * * @see {@link Tech#trackCurrentTime} */ - ; - - _proto.manualTimeUpdatesOn = function manualTimeUpdatesOn() { + manualTimeUpdatesOn() { this.manualTimeUpdates = true; this.on('play', this.trackCurrentTime_); this.on('pause', this.stopTrackingCurrentTime_); } + /** * Turn off the polyfill for `timeupdate` events that was created in * {@link Tech#manualTimeUpdatesOn} */ - ; - - _proto.manualTimeUpdatesOff = function manualTimeUpdatesOff() { + manualTimeUpdatesOff() { this.manualTimeUpdates = false; this.stopTrackingCurrentTime(); this.off('play', this.trackCurrentTime_); this.off('pause', this.stopTrackingCurrentTime_); } + /** * Sets up an interval function to track current time and trigger `timeupdate` every * 250 milliseconds. @@ -11256,67 +10812,65 @@ * @listens Tech#play * @triggers Tech#timeupdate */ - ; - - _proto.trackCurrentTime = function trackCurrentTime() { + trackCurrentTime() { if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); } - this.currentTimeInterval = this.setInterval(function () { /** * Triggered at an interval of 250ms to indicated that time is passing in the video. * * @event Tech#timeupdate - * @type {EventTarget~Event} + * @type {Event} */ this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true - }); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 + }); + + // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 }, 250); } + /** * Stop the interval function created in {@link Tech#trackCurrentTime} so that the * `timeupdate` event is no longer triggered. * * @listens {Tech#pause} */ - ; + stopTrackingCurrentTime() { + this.clearInterval(this.currentTimeInterval); - _proto.stopTrackingCurrentTime = function stopTrackingCurrentTime() { - this.clearInterval(this.currentTimeInterval); // #1002 - if the video ends right before the next timeupdate would happen, + // #1002 - if the video ends right before the next timeupdate would happen, // the progress bar won't make it all the way to the end - this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); } + /** * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList}, * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech. * * @fires Component#dispose */ - ; - - _proto.dispose = function dispose() { + dispose() { // clear out all tracks because we can't reuse them between techs - this.clearTracks(NORMAL.names); // Turn off any manual progress or timeupdate tracking + this.clearTracks(NORMAL.names); + // Turn off any manual progress or timeupdate tracking if (this.manualProgress) { this.manualProgressOff(); } - if (this.manualTimeUpdates) { this.manualTimeUpdatesOff(); } - - _Component.prototype.dispose.call(this); + super.dispose(); } + /** * Clear out a single `TrackList` or an array of `TrackLists` given their names. * @@ -11327,51 +10881,42 @@ * TrackList names to clear, valid names are `video`, `audio`, and * `text`. */ - ; - - _proto.clearTracks = function clearTracks(types) { - var _this3 = this; - - types = [].concat(types); // clear out all tracks because we can't reuse them between techs - - types.forEach(function (type) { - var list = _this3[type + "Tracks"]() || []; - var i = list.length; - + clearTracks(types) { + types = [].concat(types); + // clear out all tracks because we can't reuse them between techs + types.forEach(type => { + const list = this[`${type}Tracks`]() || []; + let i = list.length; while (i--) { - var track = list[i]; - + const track = list[i]; if (type === 'text') { - _this3.removeRemoteTextTrack(track); + this.removeRemoteTextTrack(track); } - list.removeTrack(track); } }); } + /** * Remove any TextTracks added via addRemoteTextTrack that are * flagged for automatic garbage collection */ - ; - - _proto.cleanupAutoTextTracks = function cleanupAutoTextTracks() { - var list = this.autoRemoteTextTracks_ || []; - var i = list.length; - + cleanupAutoTextTracks() { + const list = this.autoRemoteTextTracks_ || []; + let i = list.length; while (i--) { - var track = list[i]; + const track = list[i]; this.removeRemoteTextTrack(track); } } + /** * Reset the tech, which will removes all sources and reset the internal readyState. * * @abstract */ - ; + reset() {} - _proto.reset = function reset() {} /** * Get the value of `crossOrigin` from the tech. * @@ -11379,9 +10924,8 @@ * * @see {Html5#crossOrigin} */ - ; + crossOrigin() {} - _proto.crossOrigin = function crossOrigin() {} /** * Set the value of `crossOrigin` on the tech. * @@ -11390,9 +10934,8 @@ * @param {string} crossOrigin the crossOrigin value * @see {Html5#setCrossOrigin} */ - ; + setCrossOrigin() {} - _proto.setCrossOrigin = function setCrossOrigin() {} /** * Get or set an error on the Tech. * @@ -11402,16 +10945,14 @@ * @return {MediaError|null} * The current error object on the tech, or null if there isn't one. */ - ; - - _proto.error = function error(err) { + error(err) { if (err !== undefined) { this.error_ = new MediaError(err); this.trigger('error'); } - return this.error_; } + /** * Returns the `TimeRange`s that have been played through for the current source. * @@ -11422,15 +10963,13 @@ * - A single time range if this video has played * - An empty set of ranges if not. */ - ; - - _proto.played = function played() { + played() { if (this.hasStarted_) { - return createTimeRanges(0, 0); + return createTimeRanges$1(0, 0); } - - return createTimeRanges(); + return createTimeRanges$1(); } + /** * Start playback * @@ -11438,19 +10977,20 @@ * * @see {Html5#play} */ - ; + play() {} - _proto.play = function play() {} /** * Set whether we are scrubbing or not * * @abstract + * @param {boolean} _isScrubbing + * - true for we are currently scrubbing + * - false for we are no longer scrubbing * * @see {Html5#setScrubbing} */ - ; + setScrubbing(_isScrubbing) {} - _proto.setScrubbing = function setScrubbing() {} /** * Get whether we are scrubbing or not * @@ -11458,25 +10998,24 @@ * * @see {Html5#scrubbing} */ - ; + scrubbing() {} - _proto.scrubbing = function scrubbing() {} /** * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was * previously called. * + * @param {number} _seconds + * Set the current time of the media to this. * @fires Tech#timeupdate */ - ; - - _proto.setCurrentTime = function setCurrentTime() { + setCurrentTime(_seconds) { // improve the accuracy of manual timeupdates if (this.manualTimeUpdates) { /** * A manual `timeupdate` event. * * @event Tech#timeupdate - * @type {EventTarget~Event} + * @type {Event} */ this.trigger({ type: 'timeupdate', @@ -11485,6 +11024,7 @@ }); } } + /** * Turn on listeners for {@link VideoTrackList}, {@link {AudioTrackList}, and * {@link TextTrackList} events. @@ -11495,67 +11035,56 @@ * @fires Tech#videotrackchange * @fires Tech#texttrackchange */ - ; - - _proto.initTrackListeners = function initTrackListeners() { - var _this4 = this; - + initTrackListeners() { /** * Triggered when tracks are added or removed on the Tech {@link AudioTrackList} * * @event Tech#audiotrackchange - * @type {EventTarget~Event} + * @type {Event} */ /** * Triggered when tracks are added or removed on the Tech {@link VideoTrackList} * * @event Tech#videotrackchange - * @type {EventTarget~Event} + * @type {Event} */ /** * Triggered when tracks are added or removed on the Tech {@link TextTrackList} * * @event Tech#texttrackchange - * @type {EventTarget~Event} + * @type {Event} */ - NORMAL.names.forEach(function (name) { - var props = NORMAL[name]; - - var trackListChanges = function trackListChanges() { - _this4.trigger(name + "trackchange"); + NORMAL.names.forEach(name => { + const props = NORMAL[name]; + const trackListChanges = () => { + this.trigger(`${name}trackchange`); }; - - var tracks = _this4[props.getterName](); - + const tracks = this[props.getterName](); tracks.addEventListener('removetrack', trackListChanges); tracks.addEventListener('addtrack', trackListChanges); - - _this4.on('dispose', function () { + this.on('dispose', () => { tracks.removeEventListener('removetrack', trackListChanges); tracks.removeEventListener('addtrack', trackListChanges); }); }); } + /** * Emulate TextTracks using vtt.js if necessary * * @fires Tech#vttjsloaded * @fires Tech#vttjserror */ - ; - - _proto.addWebVttScript_ = function addWebVttScript_() { - var _this5 = this; - + addWebVttScript_() { if (window.WebVTT) { return; - } // Initially, Tech.el_ is a child of a dummy-div wait until the Component system + } + + // Initially, Tech.el_ is a child of a dummy-div wait until the Component system // signals that the Tech is ready at which point Tech.el_ is part of the DOM // before inserting the WebVTT script - - if (document.body.contains(this.el())) { // load via require if available and vtt.js script location was not passed in // as an option. novtt builds will turn the above require call into an empty object @@ -11563,86 +11092,66 @@ if (!this.options_['vtt.js'] && isPlain(browserIndex) && Object.keys(browserIndex).length > 0) { this.trigger('vttjsloaded'); return; - } // load vtt.js via the script location option or the cdn of no location was + } + + // load vtt.js via the script location option or the cdn of no location was // passed in - - - var script = document.createElement('script'); + const script = document.createElement('script'); script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.14.1/vtt.min.js'; - - script.onload = function () { + script.onload = () => { /** * Fired when vtt.js is loaded. * * @event Tech#vttjsloaded - * @type {EventTarget~Event} + * @type {Event} */ - _this5.trigger('vttjsloaded'); + this.trigger('vttjsloaded'); }; - - script.onerror = function () { + script.onerror = () => { /** * Fired when vtt.js was not loaded due to an error * * @event Tech#vttjsloaded - * @type {EventTarget~Event} + * @type {Event} */ - _this5.trigger('vttjserror'); + this.trigger('vttjserror'); }; - - this.on('dispose', function () { + this.on('dispose', () => { script.onload = null; script.onerror = null; - }); // but have not loaded yet and we set it to true before the inject so that + }); + // but have not loaded yet and we set it to true before the inject so that // we don't overwrite the injected window.WebVTT if it loads right away - window.WebVTT = true; this.el().parentNode.appendChild(script); } else { this.ready(this.addWebVttScript_); } } + /** * Emulate texttracks * */ - ; - - _proto.emulateTextTracks = function emulateTextTracks() { - var _this6 = this; - - var tracks = this.textTracks(); - var remoteTracks = this.remoteTextTracks(); - - var handleAddTrack = function handleAddTrack(e) { - return tracks.addTrack(e.track); - }; - - var handleRemoveTrack = function handleRemoveTrack(e) { - return tracks.removeTrack(e.track); - }; - + emulateTextTracks() { + const tracks = this.textTracks(); + const remoteTracks = this.remoteTextTracks(); + const handleAddTrack = e => tracks.addTrack(e.track); + const handleRemoveTrack = e => tracks.removeTrack(e.track); remoteTracks.on('addtrack', handleAddTrack); remoteTracks.on('removetrack', handleRemoveTrack); this.addWebVttScript_(); - - var updateDisplay = function updateDisplay() { - return _this6.trigger('texttrackchange'); - }; - - var textTracksChanges = function textTracksChanges() { + const updateDisplay = () => this.trigger('texttrackchange'); + const textTracksChanges = () => { updateDisplay(); - - for (var i = 0; i < tracks.length; i++) { - var track = tracks[i]; + for (let i = 0; i < tracks.length; i++) { + const track = tracks[i]; track.removeEventListener('cuechange', updateDisplay); - if (track.mode === 'showing') { track.addEventListener('cuechange', updateDisplay); } } }; - textTracksChanges(); tracks.addEventListener('change', textTracksChanges); tracks.addEventListener('addtrack', textTracksChanges); @@ -11653,13 +11162,13 @@ tracks.removeEventListener('change', textTracksChanges); tracks.removeEventListener('addtrack', textTracksChanges); tracks.removeEventListener('removetrack', textTracksChanges); - - for (var i = 0; i < tracks.length; i++) { - var track = tracks[i]; + for (let i = 0; i < tracks.length; i++) { + const track = tracks[i]; track.removeEventListener('cuechange', updateDisplay); } }); } + /** * Create and returns a remote {@link TextTrack} object. * @@ -11675,15 +11184,13 @@ * @return {TextTrack} * The TextTrack that gets created. */ - ; - - _proto.addTextTrack = function addTextTrack(kind, label, language) { + addTextTrack(kind, label, language) { if (!kind) { throw new Error('TextTrack kind is required but was not provided'); } - return createTrackHelper(this, kind, label, language); } + /** * Create an emulated TextTrack for use by addRemoteTextTrack * @@ -11705,14 +11212,13 @@ * @return {HTMLTrackElement} * The track element that gets created. */ - ; - - _proto.createRemoteTextTrack = function createRemoteTextTrack(options) { - var track = mergeOptions$3(options, { + createRemoteTextTrack(options) { + const track = merge$2(options, { tech: this }); return new REMOTE.remoteTextEl.TrackClass(track); } + /** * Creates a remote text track object and returns an html track element. * @@ -11721,7 +11227,7 @@ * @param {Object} options * See {@link Tech#createRemoteTextTrack} for more detailed properties. * - * @param {boolean} [manualCleanup=true] + * @param {boolean} [manualCleanup=false] * - When false: the TextTrack will be automatically removed from the video * element whenever the source changes * - When True: The TextTrack will have to be cleaned up manually @@ -11729,55 +11235,38 @@ * @return {HTMLTrackElement} * An Html Track Element. * - * @deprecated The default functionality for this function will be equivalent - * to "manualCleanup=false" in the future. The manualCleanup parameter will - * also be removed. */ - ; - - _proto.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) { - var _this7 = this; - - if (options === void 0) { - options = {}; + addRemoteTextTrack(options = {}, manualCleanup) { + const htmlTrackElement = this.createRemoteTextTrack(options); + if (typeof manualCleanup !== 'boolean') { + manualCleanup = false; } - var htmlTrackElement = this.createRemoteTextTrack(options); - - if (manualCleanup !== true && manualCleanup !== false) { - // deprecation warning - log$1.warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js'); - manualCleanup = true; - } // store HTMLTrackElement and TextTrack to remote list - - + // store HTMLTrackElement and TextTrack to remote list this.remoteTextTrackEls().addTrackElement_(htmlTrackElement); this.remoteTextTracks().addTrack(htmlTrackElement.track); - - if (manualCleanup !== true) { + if (manualCleanup === false) { // create the TextTrackList if it doesn't exist - this.ready(function () { - return _this7.autoRemoteTextTracks_.addTrack(htmlTrackElement.track); - }); + this.ready(() => this.autoRemoteTextTracks_.addTrack(htmlTrackElement.track)); } - return htmlTrackElement; } + /** * Remove a remote text track from the remote `TextTrackList`. * * @param {TextTrack} track * `TextTrack` to remove from the `TextTrackList` */ - ; - - _proto.removeRemoteTextTrack = function removeRemoteTextTrack(track) { - var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); // remove HTMLTrackElement and TextTrack from remote list + removeRemoteTextTrack(track) { + const trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); + // remove HTMLTrackElement and TextTrack from remote list this.remoteTextTrackEls().removeTrackElement_(trackElement); this.remoteTextTracks().removeTrack(track); this.autoRemoteTextTracks_.removeTrack(track); } + /** * Gets available media playback quality metrics as specified by the W3C's Media * Playback Quality API. @@ -11789,11 +11278,10 @@ * * @abstract */ - ; - - _proto.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + getVideoPlaybackQuality() { return {}; } + /** * Attempt to create a floating video window always on top of other windows * so that users may continue consuming media while they interact with other @@ -11808,100 +11296,83 @@ * * @abstract */ - ; - - _proto.requestPictureInPicture = function requestPictureInPicture() { - var PromiseClass = this.options_.Promise || window.Promise; - - if (PromiseClass) { - return PromiseClass.reject(); - } + requestPictureInPicture() { + return Promise.reject(); } + /** * A method to check for the value of the 'disablePictureInPicture'