#63535 Поддержка Chromecast
@@ -13,13 +13,13 @@ WORKDIR /usr/voka
|
||||
|
||||
COPY package*.json .
|
||||
COPY develop.sh .
|
||||
COPY vendors .
|
||||
|
||||
RUN <<EOF
|
||||
npm install;
|
||||
chmod +x develop.sh;
|
||||
EOF
|
||||
|
||||
#COPY vendors/videojs .
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
|
||||
<script language="JavaScript" src="./distribution/vokaPlayer.global.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Start nodemon
|
||||
nodemon --watch src -e ts --exec npm run build &
|
||||
nodemon --watch src --watch vendors -e ts --exec npm run build &
|
||||
|
||||
# Start lite-server
|
||||
lite-server -c configs/lite-server-config.json
|
||||
@@ -7,6 +7,7 @@
|
||||
"": {
|
||||
"name": "voka-player",
|
||||
"version": "0.0.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/node": "^22.10.10",
|
||||
@@ -6553,6 +6554,20 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
|
||||
"integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
}
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
@@ -6561,6 +6576,48 @@
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"vendors/@silvermine/videojs-chromecast": {
|
||||
"version": "1.5.0",
|
||||
"extraneous": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"webcomponents.js": "git+https://git@github.com/webcomponents/webcomponentsjs.git#v0.7.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.20.7",
|
||||
"@babel/preset-env": "7.20.2",
|
||||
"@commitlint/cli": "8.3.5",
|
||||
"@commitlint/travis-cli": "8.3.5",
|
||||
"@silvermine/eslint-config": "3.0.1",
|
||||
"@silvermine/standardization": "2.2.0",
|
||||
"autoprefixer": "8.6.5",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babelify": "10.0.0",
|
||||
"check-node-version": "4.0.3",
|
||||
"core-js": "3.11.0",
|
||||
"coveralls": "3.0.2",
|
||||
"eslint": "6.8.0",
|
||||
"expect.js": "0.3.1",
|
||||
"grunt": "1.4.0",
|
||||
"grunt-browserify": "5.3.0",
|
||||
"grunt-contrib-clean": "2.0.0",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-contrib-uglify": "3.0.1",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"grunt-postcss": "0.9.0",
|
||||
"grunt-sass": "3.1.0",
|
||||
"mocha": "8.4.0",
|
||||
"mocha-lcov-reporter": "1.3.0",
|
||||
"nyc": "15.1.0",
|
||||
"rewire": "2.5.2",
|
||||
"sass": "1.52.3",
|
||||
"silvermine-serverless-utils": "git+https://github.com/silvermine/serverless-utils.git#910f1149af824fc8d0fa840878079c7d3df0f414",
|
||||
"sinon": "2.3.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"video.js": ">= 6 < 9"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"scripts": {
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"build": "tsup --env.NODE_ENV development",
|
||||
"build-prod": "tsup --env.NODE_ENV production"
|
||||
"build-prod": "tsup --env.NODE_ENV production",
|
||||
"postinstall": "npm install ./vendors/@silvermine/videojs-chromecast --no-package-lock --no-save"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.ts": [
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
@use "../scss/mixins";
|
||||
@use "../scss/utilities";
|
||||
|
||||
// External Components
|
||||
@use "~@silvermine/videojs-chromecast/src/scss/videojs-chromecast";
|
||||
|
||||
// Components
|
||||
@use "../scss/components/layout";
|
||||
@use "../scss/components/svg";
|
||||
|
||||
@@ -40,6 +40,14 @@ class Skin extends Component {
|
||||
}
|
||||
|
||||
super(player, options_)
|
||||
|
||||
// Укажем controlBar явно, так как у нас кастомный скин, а controlBar используется
|
||||
// плагином chromecast для авто добавления кнопки
|
||||
const controlBar = this.getChild('BottomPanel');
|
||||
if (controlBar) {
|
||||
// Добавим в player для совместимости с плагинами и API
|
||||
(player as any).controlBar = controlBar;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import videojs from 'video.js'
|
||||
import Player from 'video.js/dist/types/player'
|
||||
import chromecastPlugin from '@silvermine/videojs-chromecast/'
|
||||
import { EventBus } from 'ts-bus'
|
||||
import { ITimeRange} from '@/public/IVokaPlayer'
|
||||
import { AutoplayChecker } from '@/internal/utils/AutoplayChecker'
|
||||
@@ -311,6 +312,9 @@ namespace VokaCorePlayer {
|
||||
playableContent['subtitlesUrl'] = content.subtitlesUrl
|
||||
|
||||
this.player.src(playableContent)
|
||||
// hls.js в процессе работы может менять исходник на blob, а такое
|
||||
// не подходит для хромкаст. Временное решение для сохранения исходника.
|
||||
this.player._originalSrc = playableContent
|
||||
this.bus.publish(VokaBusEvent.switchContent(content))
|
||||
this.bus.publish(
|
||||
VokaBusEvent.adsMarkersSet({
|
||||
@@ -360,6 +364,9 @@ namespace VokaCorePlayer {
|
||||
|
||||
videojs.log.level('debug')
|
||||
|
||||
// Явная регистрация плагина chromecast нужна из-за структуры плагина
|
||||
chromecastPlugin(videojs)
|
||||
|
||||
const playerOptions = this.initOptions(options)
|
||||
const player = videojs(
|
||||
playerContainer,
|
||||
@@ -422,7 +429,7 @@ namespace VokaCorePlayer {
|
||||
plugins.vokaMetricsPlugin = {
|
||||
bus: this.bus,
|
||||
}
|
||||
|
||||
plugins.chromecast = { buttonPositionIndex: -2, addCastLabelToButton: true }
|
||||
const childrenComponents = [
|
||||
// Non-visual component, not in UI layer list.
|
||||
'mediaLoader' // Required loader, that load tech list!
|
||||
@@ -444,6 +451,7 @@ namespace VokaCorePlayer {
|
||||
autoplay: options.autoplay == "muted" || options.autoplay == "true",
|
||||
bus: options.bus,
|
||||
techOrder: [
|
||||
'chromecast',
|
||||
VokaWebOSTech.TECH_NAME,
|
||||
VokaTizenTech.TECH_NAME,
|
||||
VokaAppleTech.TECH_NAME,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
name: CI
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history
|
||||
-
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- run: npm i -g npm@8.5.5
|
||||
- run: npm ci
|
||||
- run: npm run standards
|
||||
test:
|
||||
needs: [ build ]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [ 12, 14, 16, 'lts/*', 'latest' ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
-
|
||||
name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm i -g npm@8.5.5
|
||||
- run: npm ci # Reinstall the dependencies to ensure they install with the current version of node
|
||||
- run: npm test
|
||||
- name: Coveralls
|
||||
uses: coverallsapp/github-action@v1
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": [ "plugins/markdown" ]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
16.15.0
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"include": [
|
||||
"src/**/*.js"
|
||||
],
|
||||
"extension": [
|
||||
".js"
|
||||
],
|
||||
"reporter": [
|
||||
"text-summary",
|
||||
"html",
|
||||
"lcov"
|
||||
],
|
||||
"instrument": true,
|
||||
"sourceMap": true,
|
||||
"all": true
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
extends: ./node_modules/@silvermine/standardization/.stylelintrc.yml
|
||||
@@ -0,0 +1,42 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [our coding standards][commit-messages] for commit guidelines.
|
||||
|
||||
## [1.5.0](https://github.com/silvermine/videojs-chromecast/compare/v1.4.1...v1.5.0) (2023-11-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Allow modifying the load request ([#123](https://github.com/silvermine/videojs-chromecast/issues/123), [#141](https://github.com/silvermine/videojs-chromecast/issues/141)) ([7cee052](https://github.com/silvermine/videojs-chromecast/commit/7cee052dcd5473448f882d67bb5bc9d8e9a1763c))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Clear the close session timeout after new source starts playing ([4a8eb31](https://github.com/silvermine/videojs-chromecast/commit/4a8eb31faa241235c54c1f8dec897571360e7f19))
|
||||
|
||||
|
||||
### [1.4.1](https://github.com/silvermine/videojs-chromecast/compare/v1.4.0...v1.4.1) (2023-03-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove deprecated `.extend` method ([994b5b9](https://github.com/silvermine/videojs-chromecast/commit/994b5b9ae6df89f657e2ff4a920056826094b54f)), closes [#152](https://github.com/silvermine/videojs-chromecast/issues/152) [#147](https://github.com/silvermine/videojs-chromecast/issues/147)
|
||||
|
||||
|
||||
## [1.4.0](https://github.com/silvermine/videojs-chromecast/compare/v1.3.4...v1.4.0) (2023-03-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add optional "Cast" label to button component ([220c362](https://github.com/silvermine/videojs-chromecast/commit/220c36247c9ac992b757b97257e24e665ac3feb5))
|
||||
* Change label to "Disconnect Cast" when connected ([a7f495b](https://github.com/silvermine/videojs-chromecast/commit/a7f495b78d8472322079a75a834440fd20858b3c))
|
||||
* Set image on cast device if the video has a poster ([902464c](https://github.com/silvermine/videojs-chromecast/commit/902464cecf468c554fb062bd93d09bae9e303922))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Chromecast button with label styling breaking on cast/disconnect ([2a181de](https://github.com/silvermine/videojs-chromecast/commit/2a181dea847927050b57453f9474a2f47028fdca))
|
||||
|
||||
|
||||
[commit-messages]: https://github.com/silvermine/silvermine-info/blob/master/commit-history.md#commit-messages
|
||||
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2017 Jeremy Thomerson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,369 @@
|
||||
# Silvermine VideoJS Chromecast Plugin
|
||||
|
||||
<!-- markdownlint-disable line-length -->
|
||||
[](https://travis-ci.org/silvermine/videojs-chromecast)
|
||||
[](https://coveralls.io/github/silvermine/videojs-chromecast?branch=master)
|
||||
[](https://david-dm.org/silvermine/videojs-chromecast)
|
||||
[](https://david-dm.org/silvermine/videojs-chromecast#info=devDependencies&view=table)
|
||||
<!-- markdownlint-enable line-length -->
|
||||
|
||||
|
||||
## What is it?
|
||||
|
||||
A plugin for [videojs](http://videojs.com/) versions 6+ that adds a button to the control
|
||||
bar which will cast videos to a Chromecast.
|
||||
|
||||
|
||||
## How do I use it?
|
||||
|
||||
The `@silvermine/videojs-chromecast` plugin includes 3 types of assets: JavaScript, CSS,
|
||||
and images.
|
||||
|
||||
You can either build the plugin locally and use the assets that are output from the build
|
||||
process directly, or you can install the plugin as an NPM module, include the
|
||||
JavaScript and SCSS source in your project using a Common-JS module loader and SASS build
|
||||
process, and copy the images from the image source folder to your project.
|
||||
|
||||
Note that regardless of whether you are using this plugin via the pre-built JS or as a
|
||||
module, the Chromecast framework will need to be included after the plugin. For example:
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/video.js@6.1.0/dist/video.js"></script>
|
||||
<script src="./dist/silvermine-videojs-chromecast.min.js"></script>
|
||||
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
|
||||
```
|
||||
|
||||
### Building the plugin locally
|
||||
|
||||
1. Either clone this repository or install the `@silvermine/videojs-chromecast` module
|
||||
using `npm install @silvermine/videojs-chromecast`.
|
||||
2. Ensure that `@silvermine/videojs-chromecast`'s `devDependencies` are installed by
|
||||
running `npm install` from within the `videojs-chromecast` folder.
|
||||
3. Run `grunt build` to build and copy the JavaScript, CSS and image files to the
|
||||
`videojs-chromecast/dist` folder.
|
||||
4. Copy the plugin's files from the `dist` folder into your project as needed.
|
||||
5. Ensure that the images in the `dist/images` folder are accessible at `./images/`,
|
||||
relative to where the plugin's CSS is located. If, for example, your CSS is located
|
||||
at `https://example.com/plugins/silvermine-videojs-chromecast.css`, then the
|
||||
plugin's images should be located at `https://example.com/plugins/images/`.
|
||||
6. Follow the steps in the "Configuration" section below.
|
||||
|
||||
Note: when adding the plugin's JavaScript to your web page, include the
|
||||
`silvermine-videojs-chromecast.min.js` JavaScript file in your HTML *after* loading
|
||||
Video.js. The plugin's built JavaScript file expects there to be a reference to Video.js
|
||||
at `window.videojs` and will throw an error if it does not exist.
|
||||
|
||||
### Initialization options
|
||||
|
||||
* **`preloadWebComponents`** (default: `false`) - The Chromecast framework relies on
|
||||
the `webcomponents.js` polyfill when a browser does not have
|
||||
`document.registerElement` in order to create the `<google-cast-button>` custom
|
||||
component (which is not used by this plugin). If you are using jQuery, this polyfill
|
||||
must be loaded and initialized before jQuery is initialized. Unfortunately, the
|
||||
Chromecast framework loads the `webcomponents.js` polyfill via a dynamically created
|
||||
`<script>` tag. This causes a race condition (see #17). Also, including
|
||||
`webcomponents.js` anywhere on the page will break jQuery's fix for bubbling some
|
||||
events to `document` (e.g. `onchange` events for `<select>`, see #21). Setting
|
||||
`preloadWebComponents` to `true` will "fix" these 2 problems by (1) making this
|
||||
plugin add the `webcomponents` polyfill synchronously when the polyfill is needed and
|
||||
(2) using the `webcomponents-lite.js` version as it does not include the shadow DOM
|
||||
polyfills, but still provides the `registerElement` polyfill that the Chromecast
|
||||
framework needs. If you use the `preloadWebComponents: true` option, you should make
|
||||
sure that this plugin is loaded before jQuery. Then include the Chromecast framework
|
||||
after this plugin as you normally would.
|
||||
|
||||
**Note:** There is a caveat to using the `preloadWebComponents` setting. Because the
|
||||
Chromecast plugin uses the shadow DOM to create the `<google-cast-button>` custom
|
||||
component, **the `<google-cast-button>` custom component may partly render, but it
|
||||
will not be functional**. This tag is not used by this plugin. However if you must
|
||||
use this tag elsewhere, you should not use the `preloadWebComponents` flag.
|
||||
|
||||
tl;dr: if you use jQuery, you should use the `preloadWebComponents: true` option in
|
||||
this plugin.
|
||||
|
||||
#### Providing initialization options via `require()`
|
||||
|
||||
If requiring this plugin via NPM, any desired initialization options can be supplied to
|
||||
the constructor function exported by the module. For example:
|
||||
|
||||
```js
|
||||
require('@silvermine/videojs-chromecast')(videojs, { preloadWebComponents: true });
|
||||
```
|
||||
|
||||
#### Providing initialization options via `<script>`
|
||||
|
||||
If using the prebuilt JS, the initialization options can be provided via
|
||||
`window.SILVERMINE_VIDEOJS_CHROMECAST_CONFIG`. Note that these options need to be set
|
||||
before the `<script>` tag to include the plugin.
|
||||
|
||||
```html
|
||||
<script>
|
||||
window.SILVERMINE_VIDEOJS_CHROMECAST_CONFIG = {
|
||||
preloadWebComponents: true,
|
||||
};
|
||||
</script>
|
||||
<script src="path/to/silvermine-videojs-chromecast.js"></script>
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Once the plugin has been loaded and registered, configure it and add it to your Video.js
|
||||
player using Video.js' plugin configuration option (see the section under the heading
|
||||
"Setting up a Plugin" on [Video.js' plugin documentation page][videojs-docs].
|
||||
|
||||
**Important: In addition to defining plugin configuration, you are required to define the
|
||||
player's `techOrder` option, setting `'chromecast'` as the first Tech in the list.** Below
|
||||
is an example of the minimum required configuration for the Chromecast plugin to function:
|
||||
|
||||
```js
|
||||
var options;
|
||||
|
||||
options = {
|
||||
controls: true,
|
||||
techOrder: [ 'chromecast', 'html5' ], // You may have more Tech, such as Flash or HLS
|
||||
plugins: {
|
||||
chromecast: {}
|
||||
}
|
||||
};
|
||||
|
||||
videojs(document.getElementById('myVideoElement'), options);
|
||||
```
|
||||
|
||||
Please note that even if you choose not to use any of the configuration options, you must
|
||||
either provide a `chromecast` entry in the `plugins` option for Video.js to initialize the
|
||||
plugin for you:
|
||||
|
||||
```js
|
||||
options = {
|
||||
plugins: {
|
||||
chromecast: {}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
or you must initialize the plugin manually:
|
||||
|
||||
```js
|
||||
var player = videojs(document.getElementById('myVideoElement'));
|
||||
|
||||
player.chromecast(); // initializes the Chromecast plugin
|
||||
```
|
||||
|
||||
#### Configuration options
|
||||
|
||||
##### Plugin configuration
|
||||
|
||||
* **`plugins.chromecast.receiverAppID`** - the string ID of a custom [Chromecast
|
||||
receiver app][cast-receiver] to use. Defaults to the [default Media Receiver
|
||||
ID][def-cast-id].
|
||||
* **`plugins.chromecast.addButtonToControlBar`** - a `boolean` flag that tells the
|
||||
plugin whether or not it should automatically add the Chromecast button to the
|
||||
Video.js player's control bar component. Defaults to `true`.
|
||||
* **`plugins.chromecast.buttonPositionIndex`** - a zero-based number specifying the
|
||||
index of the Chromecast button among the control bar's child components (if
|
||||
`addButtonToControlBar` is set to `true`). By default the Chromecast Button is added
|
||||
as the last child of the control bar. A value less than 0 puts the button at the
|
||||
specified position from the end of the control bar. Note that it's likely not all
|
||||
child components of the control bar are visible.
|
||||
* **`plugins.chromecast.addCastLabelToButton`** (default: `false`) - by default, the
|
||||
Chromecast button component will display only an icon. Setting `addCastLabelToButton`
|
||||
to `true` will display a label titled `"Cast"` alongside the default icon.
|
||||
|
||||
##### Chromecast Tech configuration
|
||||
|
||||
* **`chromecast.requestTitleFn`** - a function that this plugin calls when it needs a
|
||||
string that will be the title shown in the UI that is shown when a Chromecast session
|
||||
is active and connected. When the this plugin calls the `requestTitleFn`, it passes
|
||||
it the [current `source` object][player-source] and expects a string in return. If
|
||||
nothing is returned or if this option is not defined, no title will be shown.
|
||||
* **`chromecast.requestSubtitleFn`** - a function that this plugin calls when it needs
|
||||
a string that will be the sub-title shown in the UI that is shown when a Chromecast
|
||||
session is active and connected. When the this plugin calls the `requestSubtitleFn`,
|
||||
it passes it the [current `source` object][player-source] and expects a string in
|
||||
return. If nothing is returned or if this option is not defined, no sub-title will be
|
||||
shown.
|
||||
* **`chromecast.requestCustomDataFn`** - a function that this plugin calls when it
|
||||
needs an object that contains custom information necessary for a Chromecast receiver
|
||||
app when a session is active and connected. When the this plugin calls the
|
||||
`requestCustomDataFn`, it passes it the [current `source` object][player-source] and
|
||||
expects an object in return. If nothing is returned or if this option is not defined,
|
||||
no custom data will be sent. This option is intended to be used with a [custom
|
||||
receiver][custom-receiver] application to extend its default capabilities.
|
||||
* **`chromecast.modifyLoadRequestFn`** - a function that this plugin calls before doing
|
||||
the request to [load media][chromecast-load-media]. The function gets called with
|
||||
the [LoadRequest][chromecast-load-request] object as argument and expects it in
|
||||
return.
|
||||
|
||||
Here is an example configuration object that makes full use of all required and optional
|
||||
configuration:
|
||||
|
||||
```js
|
||||
var titles, subtitles, customData, options;
|
||||
|
||||
titles = {
|
||||
'https://example.com/videos/video-1.mp4': 'Example Title',
|
||||
'https://example.com/videos/video-2.mp4': 'Example Title2',
|
||||
};
|
||||
|
||||
subtitles = {
|
||||
'https://example.com/videos/video-1.mp4': 'Subtitle',
|
||||
'https://example.com/videos/video-2.mp4': 'Subtitle2',
|
||||
};
|
||||
|
||||
customData = {
|
||||
'https://example.com/videos/video-1.mp4': { 'customColor': '#0099ee' },
|
||||
'https://example.com/videos/video-2.mp4': { 'customColor': '#000080' },
|
||||
};
|
||||
|
||||
options = {
|
||||
// Must specify the 'chromecast' Tech first
|
||||
techOrder: [ 'chromecast', 'html5' ], // Required
|
||||
// Configuration for the Chromecast Tech
|
||||
chromecast: {
|
||||
requestTitleFn: function(source) { // Not required
|
||||
return titles[source.url];
|
||||
},
|
||||
requestSubtitleFn: function(source) { // Not required
|
||||
return subtitles[source.url];
|
||||
},
|
||||
requestCustomDataFn: function(source) { // Not required
|
||||
return customData[source.url];
|
||||
},
|
||||
modifyLoadRequestFn: function (loadRequest) { // HLS support
|
||||
loadRequest.media.hlsSegmentFormat = 'fmp4';
|
||||
loadRequest.media.hlsVideoSegmentFormat = 'fmp4';
|
||||
return loadRequest;
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
chromecast: {
|
||||
receiverAppID: '1234' // Not required
|
||||
addButtonToControlBar: false, // Defaults to true
|
||||
},
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
##### Localization
|
||||
|
||||
The `ChromecastButton` component has two translated strings: "Open Chromecast menu" and
|
||||
"Cast".
|
||||
|
||||
* The "Open Chromecast menu" string appears in both of the standard places for Button
|
||||
component accessibility text: inside the `.vjs-control-text` span and as the
|
||||
`<button>` element's `title` attribute.
|
||||
* The "Cast" string appears in an optional label within the Button component: inside
|
||||
the `.vjs-chromecast-button-label` span.
|
||||
|
||||
To localize the Chromecast button strings, follow the steps in the [Video.js Languages
|
||||
tutorial][videojs-translation] to add `"Open Chromecast menu"` and `"Cast"` keys to the
|
||||
map of translation strings.
|
||||
|
||||
### Using the NPM module
|
||||
|
||||
If you are using a module loader such as Browserify or Webpack, first install
|
||||
`@silvermine/videojs-chromecast` using `npm install`. Then, use
|
||||
`require('@silvermine/videojs-chromecast')` to require `@silvermine/videojs-chromecast`
|
||||
into your project's source code. `require('@silvermine/videojs-chromecast')` returns a
|
||||
function that you can use to register the plugin with Video.js by passing in a reference
|
||||
to `videojs`:
|
||||
|
||||
```js
|
||||
var videojs = require('video.js');
|
||||
|
||||
// Initialize the Chromecast plugin
|
||||
require('@silvermine/videojs-chromecast')(videojs);
|
||||
```
|
||||
|
||||
Then, follow the steps in the "Configuration" section above.
|
||||
|
||||
This plugin's source code uses ES6+ syntax and keywords, such as `class` and `static`. If
|
||||
you need to support [browsers that do not support newer JavaScript
|
||||
syntax](https://caniuse.com/es6), you will need to use a tool like
|
||||
[Babel](https://babeljs.io/) to transpile and polyfill your code.
|
||||
|
||||
Alternatively, you can
|
||||
`require('@silvermine/videojs-chromecast/dist/silvermine-videojs-chromecast.js')` to use a
|
||||
JavaScript file that has already been polyfilled/transpiled down to ES5 compatibility.
|
||||
|
||||
### Using the CSS and images
|
||||
|
||||
If you are using SCSS in your project, you can simply reference the plugin's main SCSS
|
||||
file in your project's SCSS:
|
||||
|
||||
```scss
|
||||
@import "path/to/node_modules/@silvermine/videojs-chromecast/src/scss/videojs-chromecast";
|
||||
```
|
||||
|
||||
Optionally, you can override the SCSS variables that contain the paths to the icon image
|
||||
files:
|
||||
|
||||
* **`$icon-chromecast--default`** - the path to the icon image that is displayed when
|
||||
the Chromecast button is in its normal, default state. Defaults to
|
||||
`"images/ic_cast_white_24dp.png"`.
|
||||
* **`$icon-chromecast--hover`** - the path to the icon image that is displayed when the
|
||||
user hovers over the Chromecast button when it is in its normal, default state.
|
||||
Defaults to `"images/ic_cast_white_24dp.png"`.
|
||||
* **`$icon-chromecast-casting`** - the path to the icon image that is displayed when
|
||||
the Chromecast button is in the "casting" state (when a Chromecast session is active
|
||||
and connected). Defaults to `"images/ic_cast_connected_white_24dp.png"`.
|
||||
* **`$icon-chromecast-casting--hover`** - the path to the icon image that is displayed
|
||||
when the user hovers over the Chromecast button when it is in the "casting" state
|
||||
(when a Chromecast session is active and connected). Defaults to
|
||||
`"images/ic_cast_connected_white_24dp.png"`.
|
||||
* **`$chromecast-icon-size`** - the width and height of the icon (the button and icon
|
||||
is a square). Defaults to `12px`.
|
||||
* **`$chromecast-title-font-size`** - the font size of the title on the screen that is
|
||||
shown while a Chromecast session is active and connected. Defaults to `22px`.
|
||||
* **`$chromecast-subtitle-font-size`** - the font size of the sub-title on the screen
|
||||
that is shown while a Chromecast session is active and connected. Defaults to `18px`.
|
||||
* **`$chromecast-poster-width`** - the width of the poster image on the screen that
|
||||
that is shown while a Chromecast session is active and connected. Defaults to
|
||||
`100px`.
|
||||
* **`$chromecast-poster-max-height`** - the maximum height of the poster image on the
|
||||
screen that is shown while a Chromecast session is active and connected. Defaults to
|
||||
`180px`.
|
||||
|
||||
#### Images
|
||||
|
||||
The plugin's images are located at `videojs-chromecast/src/images`. If you have
|
||||
not overridden the icon image path variables in the SCSS, then copy the images from the
|
||||
`src/images` folder to a folder that is accessible at `./images/`, relative to where the
|
||||
plugin's CSS is located. If, for example, your CSS is located at
|
||||
`https://example.com/plugins/silvermine-videojs-chromecast.css`, then the plugin's images
|
||||
should be located at `https://example.com/plugins/images/`.
|
||||
|
||||
In addition, the `ic_cast_white_24dp.png` icon image that is used as the default icon for
|
||||
all four button states ("default", "default + hover", "casting", "casting + hover"), the
|
||||
`images` folder contains grey, black, and blue versions of the icons.
|
||||
|
||||
### Events
|
||||
|
||||
* `chromecastConnected` - Triggers when Chromecast connected
|
||||
* `chromecastDisconnected` - Triggers when Chromecast disconnected
|
||||
* `chromecastDevicesAvailable` - Triggers on state change when Chromecast devices are
|
||||
available
|
||||
* `chromecastDevicesUnavailable` - Triggers on state change when Chromecast devices are
|
||||
unavailable
|
||||
* `chromecastRequested`: Triggers when the user has requested Chromecast playback using
|
||||
this plugin's Chromecast button
|
||||
|
||||
## How do I contribute?
|
||||
|
||||
We genuinely appreciate external contributions. See [our extensive
|
||||
documentation][contributing] on how to contribute.
|
||||
|
||||
## License
|
||||
|
||||
This software is released under the MIT license. See [the license file](LICENSE) for more
|
||||
details.
|
||||
|
||||
[videojs-docs]: http://docs.videojs.com/tutorial-plugins.html
|
||||
[videojs-translation]: http://docs.videojs.com/tutorial-languages.html
|
||||
[cast-receiver]: https://developers.google.com/cast/docs/receiver_apps
|
||||
[def-cast-id]: https://developers.google.com/cast/docs/receiver_apps#default
|
||||
[player-source]: http://docs.videojs.com/Player.html#currentSource
|
||||
[custom-receiver]: https://developers.google.com/cast/docs/custom_receiver
|
||||
[contributing]: https://github.com/silvermine/silvermine-info#contributing
|
||||
[chromecast-load-media]: https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession#loadMedia
|
||||
[chromecast-load-request]: https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.LoadRequest
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
extends: [ '@silvermine/standardization/commitlint.js' ],
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8 />
|
||||
<title>silvermine-videojs-chromecast Demo</title>
|
||||
<link href="https://unpkg.com/video.js@6.1.0/dist/video-js.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/video.js@6.1.0/dist/video.js"></script>
|
||||
<script src="../../dist/silvermine-videojs-chromecast.min.js"></script>
|
||||
<link href="../../dist/silvermine-videojs-chromecast.css" rel="stylesheet">
|
||||
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Demo of <code>silvermine-videojs-chromecast</code></h1>
|
||||
|
||||
<video id="video_1" class="video-js vjs-default-skin" controls preload="auto">
|
||||
<source src="http://www.caminandes.com/download/03_caminandes_llamigos_1080p.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
<script>
|
||||
var options;
|
||||
|
||||
options = {
|
||||
fluid: true,
|
||||
techOrder: [ 'chromecast', 'html5' ],
|
||||
};
|
||||
|
||||
videojs('video_1', options, function() {
|
||||
var player = this;
|
||||
|
||||
player.chromecast();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "@silvermine/videojs-chromecast",
|
||||
"version": "1.5.0",
|
||||
"description": "video.js plugin for casting to chromecast",
|
||||
"main": "src/js/index.js",
|
||||
"scripts": {
|
||||
"commitlint": "commitlint --from 5ed6165",
|
||||
"test": "check-node-version --npm 8.5.5 && nyc mocha -- -R spec 'tests/**/*.test.js'",
|
||||
"stylelint": "stylelint './src/scss/**/*.scss'",
|
||||
"eslint": "eslint '{,!(node_modules|dist)/**/}*.js'",
|
||||
"markdownlint": "markdownlint-cli2",
|
||||
"standards": "npm run commitlint && npm run markdownlint && npm run stylelint && npm run eslint",
|
||||
"release:preview": "node ./node_modules/@silvermine/standardization/scripts/release.js preview",
|
||||
"release:prep-changelog": "node ./node_modules/@silvermine/standardization/scripts/release.js prep-changelog",
|
||||
"release:finalize": "node ./node_modules/@silvermine/standardization/scripts/release.js finalize",
|
||||
"prepublish": "grunt build"
|
||||
},
|
||||
"author": "Jeremy Thomerson",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/silvermine/videojs-chromecast.git"
|
||||
},
|
||||
"keywords": [
|
||||
"video.js",
|
||||
"videojs",
|
||||
"plugin",
|
||||
"google",
|
||||
"chromecast",
|
||||
"cast"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/silvermine/videojs-chromecast/issues"
|
||||
},
|
||||
"homepage": "https://github.com/silvermine/videojs-chromecast#readme",
|
||||
"dependencies": {
|
||||
"webcomponents.js": "git+https://git@github.com/webcomponents/webcomponentsjs.git#v0.7.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.20.7",
|
||||
"@babel/preset-env": "7.20.2",
|
||||
"@commitlint/cli": "8.3.5",
|
||||
"@commitlint/travis-cli": "8.3.5",
|
||||
"@silvermine/eslint-config": "3.0.1",
|
||||
"@silvermine/standardization": "2.2.0",
|
||||
"autoprefixer": "8.6.5",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babelify": "10.0.0",
|
||||
"check-node-version": "4.0.3",
|
||||
"core-js": "3.11.0",
|
||||
"coveralls": "3.0.2",
|
||||
"eslint": "6.8.0",
|
||||
"expect.js": "0.3.1",
|
||||
"grunt": "1.4.0",
|
||||
"grunt-browserify": "5.3.0",
|
||||
"grunt-contrib-clean": "2.0.0",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-contrib-uglify": "3.0.1",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"grunt-postcss": "0.9.0",
|
||||
"grunt-sass": "3.1.0",
|
||||
"mocha": "8.4.0",
|
||||
"mocha-lcov-reporter": "1.3.0",
|
||||
"nyc": "15.1.0",
|
||||
"rewire": "2.5.2",
|
||||
"sass": "1.52.3",
|
||||
"silvermine-serverless-utils": "git+https://github.com/silvermine/serverless-utils.git#910f1149af824fc8d0fa840878079c7d3df0f414",
|
||||
"sinon": "2.3.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"video.js": ">= 6 < 9"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 736 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 892 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1009 B |
|
After Width: | Height: | Size: 981 B |
|
After Width: | Height: | Size: 876 B |
|
After Width: | Height: | Size: 824 B |
@@ -0,0 +1,241 @@
|
||||
/** @lends ChromecastSessionManager.prototype **/
|
||||
class ChromecastSessionManager {
|
||||
|
||||
/**
|
||||
* Stores the state of the current Chromecast session and its associated objects such
|
||||
* as the
|
||||
* [RemotePlayerController](https://developers.google.com/cast/docs/reference/chrome/cast.framework.RemotePlayerController),
|
||||
* and the
|
||||
* [RemotePlayer](https://developers.google.com/cast/docs/reference/chrome/cast.framework.RemotePlayer).
|
||||
*
|
||||
* WARNING: Do not instantiate this class until the
|
||||
* [CastContext](https://developers.google.com/cast/docs/reference/chrome/cast.framework.CastContext)
|
||||
* has been configured.
|
||||
*
|
||||
* For an undocumented (and thus unknown) reason, RemotePlayer and
|
||||
* RemotePlayerController instances created before the cast context has been configured
|
||||
* or after requesting a session or loading media will not stay in sync with media
|
||||
* items that are loaded later.
|
||||
*
|
||||
* For example, the first item that you cast will work as expected: events on
|
||||
* RemotePlayerController will fire and the state (currentTime, duration, etc) of the
|
||||
* RemotePlayer instance will update as the media item plays. However, if a new media
|
||||
* item is loaded via a `loadMedia` request, the media item will play, but the
|
||||
* remotePlayer will be in a "media unloaded" state where the duration is 0, the
|
||||
* currentTime does not update, and no change events are fired (except, strangely,
|
||||
* displayStatus updates).
|
||||
*
|
||||
* @param player {object} Video.js Player
|
||||
* @constructs ChromecastSessionManager
|
||||
*/
|
||||
constructor(player) {
|
||||
this.player = player;
|
||||
|
||||
this._sessionListener = this._onSessionStateChange.bind(this);
|
||||
this._castListener = this._onCastStateChange.bind(this);
|
||||
|
||||
this._addCastContextEventListeners();
|
||||
|
||||
// Remove global event listeners when this player instance is destroyed to prevent
|
||||
// memory leaks.
|
||||
this.player.on('dispose', this._removeCastContextEventListeners.bind(this));
|
||||
|
||||
this._notifyPlayerOfDevicesAvailabilityChange(this.getCastContext().getCastState());
|
||||
|
||||
this.remotePlayer = new cast.framework.RemotePlayer();
|
||||
this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
|
||||
}
|
||||
|
||||
static hasConnected = false;
|
||||
|
||||
/**
|
||||
* Add event listeners for events triggered on the current CastContext.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_addCastContextEventListeners() {
|
||||
var sessionStateChangedEvt = cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
||||
castStateChangedEvt = cast.framework.CastContextEventType.CAST_STATE_CHANGED;
|
||||
|
||||
this.getCastContext().addEventListener(sessionStateChangedEvt, this._sessionListener);
|
||||
this.getCastContext().addEventListener(castStateChangedEvt, this._castListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove event listeners that were added in {@link
|
||||
* ChromecastSessionManager#_addCastContextEventListeners}.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_removeCastContextEventListeners() {
|
||||
var sessionStateChangedEvt = cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
||||
castStateChangedEvt = cast.framework.CastContextEventType.CAST_STATE_CHANGED;
|
||||
|
||||
this.getCastContext().removeEventListener(sessionStateChangedEvt, this._sessionListener);
|
||||
this.getCastContext().removeEventListener(castStateChangedEvt, this._castListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the CastContext's SessionState change event.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onSessionStateChange(event) {
|
||||
if (event.sessionState === cast.framework.SessionState.SESSION_ENDED) {
|
||||
this.player.trigger('chromecastDisconnected');
|
||||
this._reloadTech();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the CastContext's CastState change event.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onCastStateChange(event) {
|
||||
this._notifyPlayerOfDevicesAvailabilityChange(event.castState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers player events that notifies listeners that Chromecast devices are
|
||||
* either available or unavailable.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_notifyPlayerOfDevicesAvailabilityChange(castState) {
|
||||
if (this.hasAvailableDevices(castState)) {
|
||||
this.player.trigger('chromecastDevicesAvailable');
|
||||
} else {
|
||||
this.player.trigger('chromecastDevicesUnavailable');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not there are Chromecast devices available to cast to.
|
||||
*
|
||||
* @see https://developers.google.com/cast/docs/reference/chrome/cast.framework#.CastState
|
||||
* @param {String} castState
|
||||
* @return {boolean} true if there are Chromecast devices available to cast to.
|
||||
*/
|
||||
hasAvailableDevices(castState) {
|
||||
castState = castState || this.getCastContext().getCastState();
|
||||
|
||||
return castState === cast.framework.CastState.NOT_CONNECTED ||
|
||||
castState === cast.framework.CastState.CONNECTING ||
|
||||
castState === cast.framework.CastState.CONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Chromecast casting menu by requesting a CastSession. Does nothing if the
|
||||
* Video.js player does not have a source.
|
||||
*/
|
||||
openCastMenu() {
|
||||
var onSessionSuccess;
|
||||
|
||||
if (!this.player.currentSource()) {
|
||||
// Do not cast if there is no media item loaded in the player
|
||||
return;
|
||||
}
|
||||
onSessionSuccess = function() {
|
||||
ChromecastSessionManager.hasConnected = true;
|
||||
this.player.trigger('chromecastConnected');
|
||||
this._reloadTech();
|
||||
}.bind(this);
|
||||
|
||||
// It is the `requestSession` function call that actually causes the cast menu to
|
||||
// open.
|
||||
// The second parameter to `.then` is an error handler. We use a noop function here
|
||||
// because we handle errors in the ChromecastTech class and we do not want an
|
||||
// error to bubble up to the console. This error handler is also triggered when
|
||||
// the user closes out of the chromecast selector pop-up without choosing a
|
||||
// casting destination.
|
||||
this.getCastContext().requestSession()
|
||||
.then(onSessionSuccess, function() { /* noop */ });
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the Video.js player's Tech. This causes the player to re-evaluate which
|
||||
* Tech should be used for the current source by iterating over available Tech and
|
||||
* calling `Tech.isSupported` and `Tech.canPlaySource`. Video.js uses the first
|
||||
* Tech that returns true from both of those functions. This is what allows us to
|
||||
* switch back and forth between the Chromecast Tech and other available Tech when a
|
||||
* CastSession is connected or disconnected.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_reloadTech() {
|
||||
var player = this.player,
|
||||
currentTime = player.currentTime(),
|
||||
wasPaused = player.paused(),
|
||||
sources = player.currentSources();
|
||||
|
||||
// Reload the current source(s) to re-lookup and use the currently available Tech.
|
||||
// The chromecast Tech gets used if `ChromecastSessionManager.isChromecastConnected`
|
||||
// is true (effectively, if a chromecast session is currently in progress),
|
||||
// otherwise Video.js continues to search through the Tech list for other eligible
|
||||
// Tech to use, such as the HTML5 player.
|
||||
player.src(player._originalSrc);
|
||||
|
||||
player.ready(function() {
|
||||
if (wasPaused) {
|
||||
player.pause();
|
||||
} else {
|
||||
player.play();
|
||||
}
|
||||
player.currentTime(currentTime || 0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://developers.google.com/cast/docs/reference/chrome/cast.framework.CastContext
|
||||
* @returns {object} the current CastContext, if one exists
|
||||
*/
|
||||
|
||||
getCastContext() {
|
||||
return cast.framework.CastContext.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://developers.google.com/cast/docs/reference/chrome/cast.framework.RemotePlayer
|
||||
* @returns {object} the current RemotePlayer, if one exists
|
||||
*/
|
||||
getRemotePlayer() {
|
||||
return this.remotePlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://developers.google.com/cast/docs/reference/chrome/cast.framework.RemotePlayerController
|
||||
* @returns {object} the current RemotePlayerController, if one exists
|
||||
*/
|
||||
getRemotePlayerController() {
|
||||
return this.remotePlayerController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the current Chromecast API is available (that is,
|
||||
* `window.chrome`, `window.chrome.cast`, and `window.cast` exist).
|
||||
*
|
||||
* @static
|
||||
* @returns {boolean} true if the Chromecast API is available
|
||||
*/
|
||||
static isChromecastAPIAvailable() {
|
||||
return window.chrome && window.chrome.cast && window.cast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not there is a current CastSession and it is connected.
|
||||
*
|
||||
* @static
|
||||
* @returns {boolean} true if the current CastSession exists and is connected
|
||||
*/
|
||||
static isChromecastConnected() {
|
||||
// We must also check the `hasConnected` flag because
|
||||
// `getCastContext().getCastState()` returns `CONNECTED` even when the current
|
||||
// casting session was initiated by another tab in the browser or by another process
|
||||
return ChromecastSessionManager.isChromecastAPIAvailable() &&
|
||||
(cast.framework.CastContext.getInstance().getCastState() === cast.framework.CastState.CONNECTED) &&
|
||||
ChromecastSessionManager.hasConnected;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChromecastSessionManager;
|
||||
@@ -0,0 +1,181 @@
|
||||
module.exports = function(videojs) {
|
||||
|
||||
/**
|
||||
* Registers the ChromecastButton Component with Video.js. Calls
|
||||
* {@link http://docs.videojs.com/Component.html#.registerComponent}, which will add a
|
||||
* component called `chromecastButton` to the list of globally registered Video.js
|
||||
* components. The `chromecastButton` is added to the player's control bar UI
|
||||
* automatically once {@link module:enableChromecast} has been called. If you would
|
||||
* like to specify the order of the buttons that appear in the control bar, including
|
||||
* this button, you can do so in the options that you pass to the `videojs` function
|
||||
* when creating a player:
|
||||
*
|
||||
* ```
|
||||
* videojs('playerID', {
|
||||
* controlBar: {
|
||||
* children: [
|
||||
* 'playToggle',
|
||||
* 'progressControl',
|
||||
* 'volumePanel',
|
||||
* 'fullscreenToggle',
|
||||
* 'chromecastButton',
|
||||
* ],
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param videojs {object} A reference to {@link http://docs.videojs.com/module-videojs.html|Video.js}
|
||||
* @see http://docs.videojs.com/module-videojs.html#~registerPlugin
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Video.js Button class is the base class for UI button components.
|
||||
*
|
||||
* @external Button
|
||||
* @see {@link http://docs.videojs.com/Button.html|Button}
|
||||
*/
|
||||
const ButtonComponent = videojs.getComponent('Button');
|
||||
|
||||
/**
|
||||
* The ChromecastButton module contains both the ChromecastButton class definition and
|
||||
* the function used to register the button as a Video.js Component.
|
||||
* @module ChromecastButton
|
||||
*/
|
||||
|
||||
|
||||
/** @lends ChromecastButton.prototype **/
|
||||
class ChromecastButton extends ButtonComponent {
|
||||
|
||||
/**
|
||||
* This class is a button component designed to be displayed in the
|
||||
* player UI's control bar. It opens the Chromecast menu when clicked.
|
||||
*
|
||||
* @constructs
|
||||
* @extends external:Button
|
||||
* @param player {Player} the video.js player instance
|
||||
*/
|
||||
constructor(player, options) {
|
||||
super(player, options);
|
||||
|
||||
player.on('chromecastConnected', this._onChromecastConnected.bind(this));
|
||||
player.on('chromecastDisconnected', this._onChromecastDisconnected.bind(this));
|
||||
player.on('chromecastDevicesAvailable', this._onChromecastDevicesAvailable.bind(this));
|
||||
player.on('chromecastDevicesUnavailable', this._onChromecastDevicesUnavailable.bind(this));
|
||||
|
||||
// Use the initial state of `hasAvailableDevices` to call the corresponding event
|
||||
// handlers because the corresponding events may have already been emitted before
|
||||
// binding the listeners above.
|
||||
if (player.chromecastSessionManager && player.chromecastSessionManager.hasAvailableDevices()) {
|
||||
this._onChromecastDevicesAvailable();
|
||||
} else {
|
||||
this._onChromecastDevicesUnavailable();
|
||||
}
|
||||
|
||||
if (options.addCastLabelToButton) {
|
||||
this.el().classList.add('vjs-chromecast-button-lg');
|
||||
|
||||
this._labelEl = document.createElement('span');
|
||||
this._labelEl.classList.add('vjs-chromecast-button-label');
|
||||
this._updateCastLabelText();
|
||||
|
||||
this.el().appendChild(this._labelEl);
|
||||
} else {
|
||||
this.controlText('Open Chromecast menu');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Button#buildCSSClass to return the classes used on the button element.
|
||||
*
|
||||
* @param el {DOMElement}
|
||||
* @see {@link http://docs.videojs.com/Button.html#buildCSSClass|Button#buildCSSClass}
|
||||
*/
|
||||
buildCSSClass() {
|
||||
return 'vjs-chromecast-button ' +
|
||||
(this._isChromecastConnected ? 'vjs-chromecast-casting-state ' : '') +
|
||||
(this.options_.addCastLabelToButton ? 'vjs-chromecast-button-lg ' : '') +
|
||||
ButtonComponent.prototype.buildCSSClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Button#handleClick to handle button click events. Chromecast
|
||||
* functionality is handled outside of this class, which should be limited
|
||||
* to UI related logic. This function simply triggers an event on the player.
|
||||
*
|
||||
* @fires ChromecastButton#chromecastRequested
|
||||
* @param el {DOMElement}
|
||||
* @see {@link http://docs.videojs.com/Button.html#handleClick|Button#handleClick}
|
||||
*/
|
||||
handleClick() {
|
||||
this.player().trigger('chromecastRequested');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles `chromecastConnected` player events.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onChromecastConnected() {
|
||||
this._isChromecastConnected = true;
|
||||
this._reloadCSSClasses();
|
||||
this._updateCastLabelText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles `chromecastDisconnected` player events.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onChromecastDisconnected() {
|
||||
this._isChromecastConnected = false;
|
||||
this._reloadCSSClasses();
|
||||
this._updateCastLabelText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles `chromecastDevicesAvailable` player events.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onChromecastDevicesAvailable() {
|
||||
this.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles `chromecastDevicesUnavailable` player events.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onChromecastDevicesUnavailable() {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-calculates which CSS classes the button needs and sets them on the buttons'
|
||||
* DOMElement.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_reloadCSSClasses() {
|
||||
if (!this.el_) {
|
||||
return;
|
||||
}
|
||||
this.el_.className = this.buildCSSClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the optional cast label text based on whether the chromecast is connected
|
||||
* or disconnected.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_updateCastLabelText() {
|
||||
if (!this._labelEl) {
|
||||
return;
|
||||
}
|
||||
this._labelEl.textContent = this._isChromecastConnected ? this.localize('Disconnect Cast') : this.localize('Cast');
|
||||
}
|
||||
}
|
||||
|
||||
videojs.registerComponent('chromecastButton', ChromecastButton);
|
||||
};
|
||||
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* @module enableChromecast
|
||||
*/
|
||||
|
||||
var ChromecastSessionManager = require('./chromecast/ChromecastSessionManager'),
|
||||
CHECK_AVAILABILITY_INTERVAL = 1000, // milliseconds
|
||||
CHECK_AVAILABILITY_TIMEOUT = 30 * 1000; // milliseconds
|
||||
|
||||
|
||||
/**
|
||||
* Configures the Chromecast
|
||||
* [casting context](https://developers.google.com/cast/docs/reference/chrome/cast.framework.CastContext),
|
||||
* which is required before casting.
|
||||
*
|
||||
* @private
|
||||
* @param options {object} the plugin options
|
||||
*/
|
||||
function configureCastContext(options) {
|
||||
var context = cast.framework.CastContext.getInstance();
|
||||
|
||||
context.setOptions({
|
||||
receiverApplicationId: options.receiverAppID || chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
|
||||
// Setting autoJoinPolicy to ORIGIN_SCOPED prevents this plugin from automatically
|
||||
// trying to connect to a preexisting Chromecast session, if one exists. The user
|
||||
// must end any existing session before trying to cast from this player instance.
|
||||
autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the `chromecastRequested` event. Delegates to a `chromecastSessionManager`
|
||||
* instance.
|
||||
*
|
||||
* @private
|
||||
* @param player {object} a Video.js player instance
|
||||
*/
|
||||
function onChromecastRequested(player) {
|
||||
player.chromecastSessionManager.openCastMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Chromecast button to the player's control bar, if one does not already exist,
|
||||
* then starts listening for the `chromecastRequested` event.
|
||||
*
|
||||
* @private
|
||||
* @param player {object} a Video.js player instance
|
||||
* @param options {object} the plugin options
|
||||
*/
|
||||
function setUpChromecastButton(player, options) {
|
||||
var indexOpt;
|
||||
|
||||
// Ensure Chromecast button exists
|
||||
if (options.addButtonToControlBar && !player.controlBar.getChild('chromecastButton')) {
|
||||
// Figure out Chromecast button's index
|
||||
indexOpt = player.controlBar.children().length;
|
||||
if (typeof options.buttonPositionIndex !== 'undefined') {
|
||||
indexOpt = options.buttonPositionIndex >= 0
|
||||
? options.buttonPositionIndex
|
||||
: player.controlBar.children().length + options.buttonPositionIndex;
|
||||
}
|
||||
player.controlBar.addChild('chromecastButton', options, indexOpt);
|
||||
}
|
||||
// Respond to requests for casting. The ChromecastButton component triggers this event
|
||||
// when the user clicks the Chromecast button.
|
||||
player.on('chromecastRequested', onChromecastRequested.bind(null, player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ChromecastSessionManager} and assigns it to the player.
|
||||
*
|
||||
* @private
|
||||
* @param player {object} a Video.js player instance
|
||||
*/
|
||||
function createSessionManager(player) {
|
||||
if (!player.chromecastSessionManager) {
|
||||
player.chromecastSessionManager = new ChromecastSessionManager(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up and configures the casting context and Chromecast button.
|
||||
*
|
||||
* @private
|
||||
* @param options {object} the plugin options
|
||||
*/
|
||||
function enableChromecast(player, options) {
|
||||
configureCastContext(options);
|
||||
createSessionManager(player);
|
||||
setUpChromecastButton(player, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the Chromecast APIs to become available, then configures the casting context
|
||||
* and configures the Chromecast button. The Chromecast APIs are loaded asynchronously,
|
||||
* so we must wait until they are available before initializing the casting context and
|
||||
* Chromecast button.
|
||||
*
|
||||
* @private
|
||||
* @param player {object} a Video.js player instance
|
||||
* @param options {object} the plugin options
|
||||
*/
|
||||
function waitUntilChromecastAPIsAreAvailable(player, options) {
|
||||
var maxTries = CHECK_AVAILABILITY_TIMEOUT / CHECK_AVAILABILITY_INTERVAL,
|
||||
tries = 1,
|
||||
intervalID;
|
||||
|
||||
// The Chromecast APIs are loaded asynchronously, so they may not be loaded and
|
||||
// initialized at this point. The Chromecast APIs do provide a callback function that
|
||||
// is called after the framework has loaded, but it requires you to define the callback
|
||||
// function **before** loading the APIs. That would require us to expose some callback
|
||||
// function to `window` here, and would require users of this plugin to define a
|
||||
// Chromecast API callback on `window` that calls our callback function in their HTML
|
||||
// file. To avoid all of this, we simply check to see if the Chromecast API is
|
||||
// available periodically, and stop after a timeout threshold has passed.
|
||||
//
|
||||
// See https://developers.google.com/cast/docs/chrome_sender_integrate#initialization
|
||||
intervalID = setInterval(function() {
|
||||
if (tries > maxTries) {
|
||||
clearInterval(intervalID);
|
||||
return;
|
||||
}
|
||||
if (ChromecastSessionManager.isChromecastAPIAvailable()) {
|
||||
clearInterval(intervalID);
|
||||
enableChromecast(player, options);
|
||||
}
|
||||
tries = tries + 1;
|
||||
}, CHECK_AVAILABILITY_INTERVAL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the Chromecast plugin with Video.js. Calls
|
||||
* [videojs#registerPlugin](http://docs.videojs.com/module-videojs.html#~registerPlugin),
|
||||
* which will add a plugin function called `chromecast` to any instance of a Video.js
|
||||
* player that is created after calling this function. Call `player.chromecast(options)`,
|
||||
* passing in configuration options, to enable the Chromecast plugin on your Player
|
||||
* instance.
|
||||
*
|
||||
* Currently, there are only two configuration options:
|
||||
*
|
||||
* * **`receiverAppID`** - the string ID of a [Chromecast receiver
|
||||
* app](https://developers.google.com/cast/docs/receiver_apps) to use. Defaults to
|
||||
* the [default Media Receiver
|
||||
* ID](https://developers.google.com/cast/docs/receiver_apps#default).
|
||||
* * **`addButtonToControlBar`** - flag that tells the plugin
|
||||
* whether or not it should automatically add the Chromecast button the the Video.js
|
||||
* player's control bar component. Defaults to `true`.
|
||||
*
|
||||
* Other configuration options are set through the player's Chromecast Tech configuration:
|
||||
*
|
||||
* ```
|
||||
* var playerOptions, player, pluginOptions;
|
||||
*
|
||||
* playerOptions = {
|
||||
* chromecast: {
|
||||
* requestTitleFn: function(source) {
|
||||
* return titles[source.url];
|
||||
* },
|
||||
* requestSubtitleFn: function(source) {
|
||||
* return subtitles[source.url];
|
||||
* },
|
||||
* requestCustomDataFn: function(source) {
|
||||
* return customData[source.url];
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* pluginOptions = {
|
||||
* receiverAppID: '1234',
|
||||
* addButtonToControlBar: false,
|
||||
* };
|
||||
*
|
||||
* player = videojs(document.getElementById('myVideoElement'), playerOptions);
|
||||
* player.chromecast(pluginOptions); // initializes the Chromecast plugin
|
||||
* ```
|
||||
*
|
||||
* @param {object} videojs
|
||||
* @see http://docs.videojs.com/module-videojs.html#~registerPlugin
|
||||
*/
|
||||
module.exports = function(videojs) {
|
||||
videojs.registerPlugin('chromecast', function(options) {
|
||||
var pluginOptions = Object.assign({ addButtonToControlBar: true }, options || {});
|
||||
|
||||
// `this` is an instance of a Video.js Player.
|
||||
// Wait until the player is "ready" so that the player's control bar component has
|
||||
// been created.
|
||||
this.ready(function() {
|
||||
if (!this.controlBar) {
|
||||
return;
|
||||
}
|
||||
if (ChromecastSessionManager.isChromecastAPIAvailable()) {
|
||||
enableChromecast(this, pluginOptions);
|
||||
} else {
|
||||
waitUntilChromecastAPIsAreAvailable(this, pluginOptions);
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
/* eslint-disable global-require */
|
||||
var preloadWebComponents = require('./preloadWebComponents'),
|
||||
createChromecastButton = require('./components/ChromecastButton'),
|
||||
createChromecastTech = require('./tech/ChromecastTech'),
|
||||
enableChromecast = require('./enableChromecast');
|
||||
|
||||
/**
|
||||
* @module index
|
||||
*/
|
||||
|
||||
/**
|
||||
* Registers the Chromecast plugin and ChromecastButton Component with Video.js. See
|
||||
* {@link module:ChromecastButton} and {@link module:enableChromecast} for more details
|
||||
* about how the plugin and button are registered and configured.
|
||||
*
|
||||
* @param videojs {object} the videojs library. If `undefined`, this plugin
|
||||
* will look to `window.videojs`.
|
||||
* @param userOpts {object} the options to use for configuration
|
||||
* @see module:enableChromecast
|
||||
* @see module:ChromecastButton
|
||||
*/
|
||||
module.exports = function(videojs, userOpts) {
|
||||
var options = Object.assign({ preloadWebComponents: false }, userOpts);
|
||||
|
||||
if (options.preloadWebComponents) {
|
||||
preloadWebComponents();
|
||||
}
|
||||
|
||||
videojs = videojs || window.videojs;
|
||||
createChromecastButton(videojs);
|
||||
createChromecastTech(videojs);
|
||||
enableChromecast(videojs);
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
function doesUserAgentContainString(str) {
|
||||
return typeof window.navigator.userAgent === 'string' && window.navigator.userAgent.indexOf(str) >= 0;
|
||||
}
|
||||
|
||||
// For information as to why this is needed, please see:
|
||||
// https://github.com/silvermine/videojs-chromecast/issues/17
|
||||
// https://github.com/silvermine/videojs-chromecast/issues/22
|
||||
|
||||
module.exports = function() {
|
||||
var needsWebComponents = !document.registerElement,
|
||||
iosChrome = doesUserAgentContainString('CriOS'),
|
||||
androidChrome;
|
||||
|
||||
androidChrome = doesUserAgentContainString('Android')
|
||||
&& doesUserAgentContainString('Chrome/')
|
||||
&& window.navigator.presentation;
|
||||
|
||||
// These checks are based on the checks found in `cast_sender.js` which
|
||||
// determine if `cast_framework.js` needs to be loaded
|
||||
if ((androidChrome || iosChrome) && needsWebComponents) {
|
||||
// This is requiring webcomponents.js@0.7.24 because that's what was used
|
||||
// by the Chromecast framework at the time this was added.
|
||||
// We are using webcomponents-lite.js because it doesn't interfere with jQuery as
|
||||
// badly (e.g. it doesn't interfere with jQuery's fix for consistently bubbling
|
||||
// events, see #21). While the "lite" version does not include the shadow DOM
|
||||
// polyfills that the Chromecast framework may need for the <google-cast-button>
|
||||
// component to work properly, this plugin does not use the <google-cast-button>
|
||||
// component.
|
||||
require('webcomponents.js/webcomponents-lite.js'); // eslint-disable-line global-require
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file is used to create a standalone javascript file for use in a script tag. The
|
||||
// file that is output assumes that Video.js is available at `window.videojs`.
|
||||
|
||||
require('./index')(undefined, window.SILVERMINE_VIDEOJS_CHROMECAST_CONFIG);
|
||||
@@ -0,0 +1,788 @@
|
||||
var ChromecastSessionManager = require('../chromecast/ChromecastSessionManager'),
|
||||
ChromecastTechUI = require('./ChromecastTechUI');
|
||||
|
||||
/**
|
||||
* Registers the ChromecastTech Tech with Video.js. Calls {@link
|
||||
* http://docs.videojs.com/Tech.html#.registerTech}, which will add a Tech called
|
||||
* `chromecast` to the list of globally registered Video.js Tech implementations.
|
||||
*
|
||||
* [Video.js Tech](http://docs.videojs.com/Tech.html) are initialized and used
|
||||
* automatically by Video.js Player instances. Whenever a new source is set on the player,
|
||||
* the player iterates through the list of available Tech to determine which to use to
|
||||
* play the source.
|
||||
*
|
||||
* @param videojs {object} A reference to
|
||||
* {@link http://docs.videojs.com/module-videojs.html|Video.js}
|
||||
* @see http://docs.videojs.com/Tech.html#.registerTech
|
||||
*/
|
||||
module.exports = function(videojs) {
|
||||
var Tech = videojs.getComponent('Tech'),
|
||||
SESSION_TIMEOUT = 10 * 1000; // milliseconds
|
||||
|
||||
/**
|
||||
* @module ChomecastTech
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Video.js Tech class is the base class for classes that provide media playback
|
||||
* technology implementations to Video.js such as HTML5, Flash and HLS.
|
||||
*
|
||||
* @external Tech
|
||||
* @see {@link http://docs.videojs.com/Tech.html|Tech}
|
||||
*/
|
||||
|
||||
/** @lends ChromecastTech.prototype */
|
||||
class ChromecastTech extends Tech {
|
||||
|
||||
/**
|
||||
* Implements Video.js playback {@link http://docs.videojs.com/tutorial-tech_.html|Tech}
|
||||
* for {@link https://developers.google.com/cast/|Google's Chromecast}.
|
||||
*
|
||||
* @constructs ChromecastTech
|
||||
* @extends external:Tech
|
||||
* @param options {object} The options to use for configuration
|
||||
* @see {@link https://developers.google.com/cast/|Google Cast}
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.featuresVolumeControl = true;
|
||||
this.featuresPlaybackRate = false;
|
||||
this.movingMediaElementInDOM = false;
|
||||
this.featuresFullscreenResize = true;
|
||||
this.featuresTimeupdateEvents = true;
|
||||
this.featuresProgressEvents = false;
|
||||
// Text tracks are not supported in this version
|
||||
this.featuresNativeTextTracks = false;
|
||||
this.featuresNativeAudioTracks = false;
|
||||
this.featuresNativeVideoTracks = false;
|
||||
|
||||
// Give ChromecastTech class instances a reference to videojs
|
||||
this.videojs = videojs;
|
||||
this._eventListeners = [];
|
||||
|
||||
this.videojsPlayer = this.videojs(options.playerId);
|
||||
this._chromecastSessionManager = this.videojsPlayer.chromecastSessionManager;
|
||||
|
||||
this._ui.updatePoster(this.videojsPlayer.poster());
|
||||
|
||||
this._remotePlayer = this._chromecastSessionManager.getRemotePlayer();
|
||||
this._remotePlayerController = this._chromecastSessionManager.getRemotePlayerController();
|
||||
this._listenToPlayerControllerEvents();
|
||||
this.on('dispose', this._removeAllEventListeners.bind(this));
|
||||
|
||||
this._hasPlayedAnyItem = false;
|
||||
this._requestTitle = options.requestTitleFn || function() { /* noop */ };
|
||||
this._requestSubtitle = options.requestSubtitleFn || function() { /* noop */ };
|
||||
this._requestCustomData = options.requestCustomDataFn || function() { /* noop */ };
|
||||
this._modifyLoadRequestFn = options.modifyLoadRequestFn || function(request) {
|
||||
return request;
|
||||
};
|
||||
// See `currentTime` function
|
||||
this._initialStartTime = options.startTime || 0;
|
||||
|
||||
this._playSource(options.source, this._initialStartTime);
|
||||
this.ready(function() {
|
||||
this.setMuted(options.muted);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DOMElement that Video.js displays in its player UI while this Tech is
|
||||
* active.
|
||||
*
|
||||
* @returns {DOMElement}
|
||||
* @see {@link http://docs.videojs.com/Tech.html#createEl}
|
||||
*/
|
||||
createEl() {
|
||||
// We have to initialize the UI here, because the super.constructor
|
||||
// calls `createEl`, which references `this._ui`.
|
||||
this._ui = this._ui || new ChromecastTechUI();
|
||||
|
||||
return this._ui.getDOMElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes playback if a media item is paused or restarts an item from
|
||||
* its beginning if the item has played and ended.
|
||||
*
|
||||
* @see {@link http://docs.videojs.com/Player.html#play}
|
||||
*/
|
||||
play() {
|
||||
if (!this.paused()) {
|
||||
return;
|
||||
}
|
||||
if (this.ended() && !this._isMediaLoading) {
|
||||
// Restart the current item from the beginning
|
||||
this._playSource({ src: this.videojsPlayer.src() }, 0);
|
||||
} else {
|
||||
this._remotePlayerController.playOrPause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses playback if the player is not already paused and if the current media item
|
||||
* has not ended yet.
|
||||
*
|
||||
* @see {@link http://docs.videojs.com/Player.html#pause}
|
||||
*/
|
||||
pause() {
|
||||
if (!this.paused() && this._remotePlayer.canPause) {
|
||||
this._remotePlayerController.playOrPause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the player is "paused". Video.js'
|
||||
* definition of "paused" is "playback paused" OR "not playing".
|
||||
*
|
||||
* @returns {boolean} true if playback is paused
|
||||
* @see {@link http://docs.videojs.com/Player.html#paused}
|
||||
*/
|
||||
paused() {
|
||||
return this._remotePlayer.isPaused || this.ended() || this._remotePlayer.playerState === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given source and begins playback, starting at the beginning
|
||||
* of the media item.
|
||||
*
|
||||
* @param source {object} the source to store and play
|
||||
* @see {@link http://docs.videojs.com/Player.html#src}
|
||||
*/
|
||||
setSource(source) {
|
||||
if (this._currentSource && this._currentSource.src === source.src && this._currentSource.type === source.type) {
|
||||
// Skip setting the source if the `source` argument is the
|
||||
// same as what's already been set. This `setSource` function
|
||||
// calls `this._playSource` which sends a "load media" request
|
||||
// to the Chromecast PlayerController. Because this function
|
||||
// may be called multiple times in rapid succession with the same `source`
|
||||
// argument, we need to de-duplicate calls with the same `source` argument to
|
||||
// prevent overwhelming the Chromecast PlayerController with expensive "load
|
||||
// media" requests, which it itself does not de-duplicate.
|
||||
return;
|
||||
}
|
||||
// We cannot use `this.videojsPlayer.currentSource()` because the
|
||||
// value returned by that function is not the same as what's returned
|
||||
// by the Video.js Player's middleware after they are run. Also, simply
|
||||
// using `this.videojsPlayer.src()` does not include mimetype information
|
||||
// which we pass to the Chromecast player.
|
||||
this._currentSource = source;
|
||||
this._playSource(source, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the given source, beginning at an optional starting time.
|
||||
*
|
||||
* @private
|
||||
* @param source {object} the source to play
|
||||
* @param [startTime] The time to start playback at, in seconds
|
||||
* @see {@link http://docs.videojs.com/Player.html#src}
|
||||
*/
|
||||
_playSource(source, startTime) {
|
||||
var castSession = this._getCastSession(),
|
||||
mediaInfo = new chrome.cast.media.MediaInfo(source.src, source.type),
|
||||
title = this._requestTitle(source),
|
||||
subtitle = this._requestSubtitle(source),
|
||||
poster = this.poster(),
|
||||
customData = this._requestCustomData(source),
|
||||
request;
|
||||
|
||||
this.trigger('waiting');
|
||||
this._clearSessionTimeout();
|
||||
|
||||
mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
|
||||
mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
|
||||
mediaInfo.metadata.title = title;
|
||||
mediaInfo.metadata.subtitle = subtitle;
|
||||
mediaInfo.streamType = this.videojsPlayer.liveTracker && this.videojsPlayer.liveTracker.isLive()
|
||||
? chrome.cast.media.StreamType.LIVE
|
||||
: chrome.cast.media.StreamType.BUFFERED;
|
||||
|
||||
if (poster) {
|
||||
mediaInfo.metadata.images = [ { url: poster } ];
|
||||
}
|
||||
if (customData) {
|
||||
mediaInfo.customData = customData;
|
||||
}
|
||||
|
||||
this._ui.updateTitle(title);
|
||||
this._ui.updateSubtitle(subtitle);
|
||||
|
||||
request = new chrome.cast.media.LoadRequest(mediaInfo);
|
||||
request.autoplay = true;
|
||||
request.currentTime = startTime;
|
||||
request = this._modifyLoadRequestFn(request);
|
||||
|
||||
this._isMediaLoading = true;
|
||||
this._hasPlayedCurrentItem = false;
|
||||
castSession.loadMedia(request)
|
||||
.then(function() {
|
||||
this._clearSessionTimeout();
|
||||
|
||||
if (!this._hasPlayedAnyItem) {
|
||||
// `triggerReady` is required here to notify the Video.js
|
||||
// player that the Tech has been initialized and is ready.
|
||||
this.triggerReady();
|
||||
}
|
||||
|
||||
this.trigger('loadstart');
|
||||
this.trigger('loadeddata');
|
||||
this.trigger('play');
|
||||
this.trigger('playing');
|
||||
|
||||
this._hasPlayedAnyItem = true;
|
||||
this._isMediaLoading = false;
|
||||
|
||||
// 🔁 Добавлено отложенное выполнение
|
||||
setTimeout(() => {
|
||||
const mediaSession = this._getMediaSession();
|
||||
if (mediaSession) {
|
||||
mediaSession.addUpdateListener(this._onMediaSessionStatusChanged.bind(this));
|
||||
} else {
|
||||
console.warn('⚠️ MediaSession is still null after loadMedia');
|
||||
}
|
||||
}, 0);
|
||||
}.bind(this), this._triggerErrorEvent.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually updates the current time. The playback position will jump to
|
||||
* the given time and continue playing if the item was playing when `setCurrentTime`
|
||||
* was called, or remain paused if the item was paused.
|
||||
*
|
||||
* @param time {number} the playback time position to jump to
|
||||
* @see {@link http://docs.videojs.com/Tech.html#setCurrentTime}
|
||||
*/
|
||||
setCurrentTime(time) {
|
||||
var duration = this.duration();
|
||||
|
||||
if (time > duration || !this._remotePlayer.canSeek) {
|
||||
return;
|
||||
}
|
||||
// Seeking to any place within (approximately) 1 second of the end of the item
|
||||
// causes the Video.js player to get stuck in a BUFFERING state. To work around
|
||||
// this, we only allow seeking to within 1 second of the end of an item.
|
||||
this._remotePlayer.currentTime = Math.min(duration - 1, time);
|
||||
this._remotePlayerController.seek();
|
||||
this._triggerTimeUpdateEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current playback time position.
|
||||
*
|
||||
* @returns {number} the current playback time position
|
||||
* @see {@link http://docs.videojs.com/Player.html#currentTime}
|
||||
*/
|
||||
currentTime() {
|
||||
// There is a brief period of time when Video.js has switched to the chromecast
|
||||
// Tech, but chromecast has not yet loaded its first media item. During
|
||||
// that time, Video.js calls this `currentTime` function to update
|
||||
// its player UI. In that period, `this._remotePlayer.currentTime`
|
||||
// will be 0 because the media has not loaded yet. To prevent the
|
||||
// UI from using a 0 second currentTime, we use the currentTime passed
|
||||
// in to the first media item that was provided to the Tech until
|
||||
// chromecast plays its first item.
|
||||
if (!this._hasPlayedAnyItem) {
|
||||
return this._initialStartTime;
|
||||
}
|
||||
return this._remotePlayer.currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the current media item, or `0` if the source
|
||||
* is not set or if the duration of the item is not available from the
|
||||
* Chromecast API yet.
|
||||
*
|
||||
* @returns {number} the duration of the current media item
|
||||
* @see {@link http://docs.videojs.com/Player.html#duration}
|
||||
*/
|
||||
duration() {
|
||||
// There is a brief period of time when Video.js has switched to the chromecast
|
||||
// Tech, but chromecast has not yet loaded its first media item.
|
||||
// During that time, Video.js calls this `duration` function to update its player
|
||||
// UI. In that period, `this._remotePlayer.duration` will be 0 because the media
|
||||
// has not loaded yet. To prevent the UI from using a 0 second duration, we
|
||||
// use the duration passed in to the first media item that was provided to
|
||||
// the Tech until chromecast plays its first item.
|
||||
if (!this._hasPlayedAnyItem) {
|
||||
return this.videojsPlayer.duration();
|
||||
}
|
||||
return this._remotePlayer.duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the current media item has finished playing.
|
||||
* Returns `false` if a media item has not been loaded, has not been played,
|
||||
* or has not yet finished playing.
|
||||
*
|
||||
* @returns {boolean} true if the current media item has finished playing
|
||||
* @see {@link http://docs.videojs.com/Player.html#ended}
|
||||
*/
|
||||
ended() {
|
||||
var mediaSession = this._getMediaSession();
|
||||
|
||||
if (!mediaSession && this._hasMediaSessionEnded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mediaSession ? (mediaSession.idleReason === chrome.cast.media.IdleReason.FINISHED) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current volume level setting as a decimal number between `0` and `1`.
|
||||
*
|
||||
* @returns {number} the current volume level
|
||||
* @see {@link http://docs.videojs.com/Player.html#volume}
|
||||
*/
|
||||
volume() {
|
||||
return this._remotePlayer.volumeLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current volume level. Volume level is a decimal number
|
||||
* between `0` and `1`, where `0` is muted and `1` is the loudest volume level.
|
||||
*
|
||||
* @param volumeLevel {number}
|
||||
* @returns {number} the current volume level
|
||||
* @see {@link http://docs.videojs.com/Player.html#volume}
|
||||
*/
|
||||
setVolume(volumeLevel) {
|
||||
this._remotePlayer.volumeLevel = volumeLevel;
|
||||
this._remotePlayerController.setVolumeLevel();
|
||||
// This event is triggered by the listener on
|
||||
// `RemotePlayerEventType.VOLUME_LEVEL_CHANGED`, but waiting for
|
||||
// that event to fire in response to calls to `setVolume` introduces
|
||||
// noticeable lag in the updating of the player UI's volume slider bar,
|
||||
// which makes user interaction with the volume slider choppy.
|
||||
this._triggerVolumeChangeEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the player is currently muted.
|
||||
*
|
||||
* @returns {boolean} true if the player is currently muted
|
||||
* @see {@link http://docs.videojs.com/Player.html#muted}
|
||||
*/
|
||||
muted() {
|
||||
return this._remotePlayer.isMuted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes or un-mutes the player. Does nothing if the player is currently
|
||||
* muted and the `isMuted` parameter is true or if the player is not muted and
|
||||
* `isMuted` is false.
|
||||
*
|
||||
* @param isMuted {boolean} whether or not the player should be muted
|
||||
* @see {@link http://docs.videojs.com/Html5.html#setMuted} for an example
|
||||
*/
|
||||
setMuted(isMuted) {
|
||||
if ((this._remotePlayer.isMuted && !isMuted) || (!this._remotePlayer.isMuted && isMuted)) {
|
||||
this._remotePlayerController.muteOrUnmute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL to the current poster image.
|
||||
*
|
||||
* @returns {string} URL to the current poster image or `undefined` if none exists
|
||||
* @see {@link http://docs.videojs.com/Player.html#poster}
|
||||
*/
|
||||
poster() {
|
||||
return this._ui.getPoster();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL to the current poster image. The poster image shown
|
||||
* in the Chromecast Tech UI view is updated with this new URL.
|
||||
*
|
||||
* @param poster {string} the URL to the new poster image
|
||||
* @see {@link http://docs.videojs.com/Tech.html#setPoster}
|
||||
*/
|
||||
setPoster(poster) {
|
||||
this._ui.updatePoster(poster);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is "required" when implementing {@link external:Tech}
|
||||
* and is supposed to return a mock
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|TimeRanges}
|
||||
* object that represents the portions of the current media item that have been
|
||||
* buffered. However, the Chromecast API does not currently provide a way
|
||||
* to determine how much the media item has buffered, so we always
|
||||
* return `undefined`.
|
||||
*
|
||||
* Returning `undefined` is safe: the player will simply not display
|
||||
* the buffer amount indicator in the scrubber UI.
|
||||
*
|
||||
* @returns {undefined} always returns `undefined`
|
||||
* @see {@link http://docs.videojs.com/Player.html#buffered}
|
||||
*/
|
||||
buffered() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is "required" when implementing {@link external:Tech}
|
||||
* and is supposed to return a mock
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|TimeRanges}
|
||||
* object that represents the portions of the current media item that has playable
|
||||
* content. However, the Chromecast API does not currently provide a
|
||||
* way to determine how much the media item has playable content, so
|
||||
* we'll just assume the entire video is an available seek target.
|
||||
*
|
||||
* The risk here lies with live streaming, where there may exist a sliding window of
|
||||
* playable content and seeking is only possible within the last X number of
|
||||
* minutes, rather than for the entire video.
|
||||
*
|
||||
* Unfortunately we have no way of detecting when this is the case. Returning
|
||||
* anything other than the full range of the video means that we lose the ability
|
||||
* to seek during VOD.
|
||||
*
|
||||
* @returns {TimeRanges} always returns a `TimeRanges` object with one
|
||||
* `TimeRange` that starts at `0` and ends at the `duration` of the
|
||||
* current media item
|
||||
* @see {@link http://docs.videojs.com/Player.html#seekable}
|
||||
*/
|
||||
seekable() {
|
||||
// TODO Investigate if there's a way to detect
|
||||
// if the source is live, so that we can
|
||||
// possibly adjust the seekable `TimeRanges` accordingly.
|
||||
return this.videojs.createTimeRange(0, this.duration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the native media controls should be shown (`true`) or hidden
|
||||
* (`false`). Not applicable to this Tech.
|
||||
*
|
||||
* @returns {boolean} always returns `false`
|
||||
* @see {@link http://docs.videojs.com/Html5.html#controls} for an example
|
||||
*/
|
||||
controls() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the browser should show the player
|
||||
* "inline" (non-fullscreen) by default. This function always
|
||||
* returns true to tell the browser that non-fullscreen playback is preferred.
|
||||
*
|
||||
* @returns {boolean} always returns `true`
|
||||
* @see {@link http://docs.videojs.com/Html5.html#playsinline} for an example
|
||||
*/
|
||||
playsinline() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not fullscreen is supported by this Tech.
|
||||
* Always returns `true` because fullscreen is always supported.
|
||||
*
|
||||
* @returns {boolean} always returns `true`
|
||||
* @see {@link http://docs.videojs.com/Html5.html#supportsFullScreen} for an example
|
||||
*/
|
||||
supportsFullScreen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag that determines whether or not the media should automatically begin
|
||||
* playing on page load. This is not supported because a Chromecast session must be
|
||||
* initiated by casting via the casting menu and cannot autoplay.
|
||||
*
|
||||
* @see {@link http://docs.videojs.com/Html5.html#setAutoplay} for an example
|
||||
*/
|
||||
setAutoplay() {
|
||||
// Not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number} the chromecast player's playback rate, if available. Otherwise,
|
||||
* the return value defaults to `1`.
|
||||
*/
|
||||
playbackRate() {
|
||||
var mediaSession = this._getMediaSession();
|
||||
|
||||
return mediaSession ? mediaSession.playbackRate : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing. Changing the playback rate is not supported.
|
||||
*/
|
||||
setPlaybackRate() {
|
||||
// Not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing. Satisfies calls to the missing preload method.
|
||||
*/
|
||||
preload() {
|
||||
// Not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes the Tech to begin loading the current source. `load`
|
||||
* is not supported in this ChromecastTech because setting the
|
||||
* source on the `Chromecast` automatically causes it to begin loading.
|
||||
*/
|
||||
load() {
|
||||
// Not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Chromecast equivalent of HTML5 Media Element's `readyState`.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
|
||||
*/
|
||||
readyState() {
|
||||
if (this._remotePlayer.playerState === 'IDLE' || this._remotePlayer.playerState === 'BUFFERING') {
|
||||
return 0; // HAVE_NOTHING
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wires up event listeners for
|
||||
* [RemotePlayerController](https://developers.google.com/cast/docs/reference/chrome/cast.framework.RemotePlayerController)
|
||||
* events.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_listenToPlayerControllerEvents() {
|
||||
var eventTypes = cast.framework.RemotePlayerEventType;
|
||||
|
||||
this._addEventListener(this._remotePlayerController, eventTypes.PLAYER_STATE_CHANGED, this._onPlayerStateChanged, this);
|
||||
this._addEventListener(this._remotePlayerController, eventTypes.VOLUME_LEVEL_CHANGED, this._triggerVolumeChangeEvent, this);
|
||||
this._addEventListener(this._remotePlayerController, eventTypes.IS_MUTED_CHANGED, this._triggerVolumeChangeEvent, this);
|
||||
this._addEventListener(this._remotePlayerController, eventTypes.CURRENT_TIME_CHANGED, this._triggerTimeUpdateEvent, this);
|
||||
this._addEventListener(this._remotePlayerController, eventTypes.DURATION_CHANGED, this._triggerDurationChangeEvent, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an event listener on the given target object.
|
||||
* Because many objects in the Chromecast API are either singletons
|
||||
* or must be shared between instances of `ChromecastTech` for the
|
||||
* lifetime of the player, we must unbind the listeners when this Tech
|
||||
* instance is destroyed to prevent memory leaks. To do that, we need to keep
|
||||
* a reference to listeners that are added to global objects so that we can
|
||||
* use those references to remove the listener when this Tech is destroyed.
|
||||
*
|
||||
* @param target {object} the object to register the event listener on
|
||||
* @param type {string} the name of the event
|
||||
* @param callback {Function} the listener's callback function that
|
||||
* executes when the event is emitted
|
||||
* @param context {object} the `this` context to use when executing the `callback`
|
||||
* @private
|
||||
*/
|
||||
_addEventListener(target, type, callback, context) {
|
||||
var listener;
|
||||
|
||||
listener = {
|
||||
target: target,
|
||||
type: type,
|
||||
callback: callback,
|
||||
context: context,
|
||||
listener: callback.bind(context),
|
||||
};
|
||||
target.addEventListener(type, listener.listener);
|
||||
this._eventListeners.push(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all event listeners that were registered with global objects during the
|
||||
* lifetime of this Tech. See {@link _addEventListener} for more information
|
||||
* about why this is necessary.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_removeAllEventListeners() {
|
||||
while (this._eventListeners.length > 0) {
|
||||
this._removeEventListener(this._eventListeners[0]);
|
||||
}
|
||||
this._eventListeners = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a single event listener that was registered with global objects
|
||||
* during the lifetime of this Tech. See {@link _addEventListener} for
|
||||
* more information about why this is necessary.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_removeEventListener(listener) {
|
||||
var index = -1,
|
||||
pass = false,
|
||||
i;
|
||||
|
||||
listener.target.removeEventListener(listener.type, listener.listener);
|
||||
|
||||
for (i = 0; i < this._eventListeners.length; i++) {
|
||||
pass = this._eventListeners[i].target === listener.target &&
|
||||
this._eventListeners[i].type === listener.type &&
|
||||
this._eventListeners[i].callback === listener.callback &&
|
||||
this._eventListeners[i].context === listener.context;
|
||||
|
||||
if (pass) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index !== -1) {
|
||||
this._eventListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Chromecast player state change events. The player may "change state" when
|
||||
* paused, played, buffering, etc.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onPlayerStateChanged() {
|
||||
var states = chrome.cast.media.PlayerState,
|
||||
playerState = this._remotePlayer.playerState;
|
||||
|
||||
if (playerState === states.PLAYING) {
|
||||
this._hasPlayedCurrentItem = true;
|
||||
this.trigger('play');
|
||||
this.trigger('playing');
|
||||
} else if (playerState === states.PAUSED) {
|
||||
this.trigger('pause');
|
||||
} else if ((playerState === states.IDLE && this.ended()) || (playerState === null && this._hasPlayedCurrentItem)) {
|
||||
this._hasPlayedCurrentItem = false;
|
||||
this._closeSessionOnTimeout();
|
||||
this.trigger('ended');
|
||||
this._triggerTimeUpdateEvent();
|
||||
} else if (playerState === states.BUFFERING) {
|
||||
this.trigger('waiting');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Chromecast MediaSession state change events. The only property sent
|
||||
* to this event is whether the session is alive. This is useful for determining
|
||||
* if an item has ended as the MediaSession will fire this event with `false` then
|
||||
* be immediately destroyed. This means that we cannot trust `idleReason` to show
|
||||
* whether an item has ended since we may no longer have access to the MediaSession.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onMediaSessionStatusChanged(isAlive) {
|
||||
this._hasMediaSessionEnded = !!isAlive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the session after a certain number of seconds of inactivity.
|
||||
*
|
||||
* If the Chromecast player is in the "IDLE" state after an item has ended, and no
|
||||
* further items are queued up to play, the session is considered inactive. Once a
|
||||
* period of time (currently 10 seconds) has elapsed with no activity, we manually
|
||||
* end the session to prevent long periods of a blank Chromecast screen that is
|
||||
* shown at the end of item playback.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_closeSessionOnTimeout() {
|
||||
// Ensure that there's never more than one session timeout active
|
||||
this._clearSessionTimeout();
|
||||
this._sessionTimeoutID = setTimeout(function() {
|
||||
var castSession = this._getCastSession();
|
||||
|
||||
if (castSession) {
|
||||
castSession.endSession(true);
|
||||
}
|
||||
this._clearSessionTimeout();
|
||||
}.bind(this), SESSION_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the timeout that is waiting during a period of inactivity in order to close
|
||||
* the session.
|
||||
*
|
||||
* @private
|
||||
* @see _closeSessionOnTimeout
|
||||
*/
|
||||
_clearSessionTimeout() {
|
||||
if (this._sessionTimeoutID) {
|
||||
clearTimeout(this._sessionTimeoutID);
|
||||
this._sessionTimeoutID = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {object} the current CastContext, if one exists
|
||||
*/
|
||||
_getCastContext() {
|
||||
return this._chromecastSessionManager.getCastContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {object} the current CastSession, if one exists
|
||||
*/
|
||||
_getCastSession() {
|
||||
return this._getCastContext().getCurrentSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {object} the current MediaSession, if one exists
|
||||
* @see https://developers.google.com/cast/docs/reference/chrome/chrome.cast.media.Media
|
||||
*/
|
||||
_getMediaSession() {
|
||||
var castSession = this._getCastSession();
|
||||
|
||||
return castSession ? castSession.getMediaSession() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a 'volumechange' event
|
||||
* @private
|
||||
* @see http://docs.videojs.com/Player.html#event:volumechange
|
||||
*/
|
||||
_triggerVolumeChangeEvent() {
|
||||
this.trigger('volumechange');
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a 'timeupdate' event
|
||||
* @private
|
||||
* @see http://docs.videojs.com/Player.html#event:timeupdate
|
||||
*/
|
||||
_triggerTimeUpdateEvent() {
|
||||
this.trigger('timeupdate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a 'durationchange' event
|
||||
* @private
|
||||
* @see http://docs.videojs.com/Player.html#event:durationchange
|
||||
*/
|
||||
_triggerDurationChangeEvent() {
|
||||
this.trigger('durationchange');
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an 'error' event
|
||||
* @private
|
||||
* @see http://docs.videojs.com/Player.html#event:error
|
||||
*/
|
||||
_triggerErrorEvent() {
|
||||
this.trigger('error');
|
||||
}
|
||||
}
|
||||
|
||||
// Required for Video.js Tech implementations.
|
||||
// TODO Consider a more comprehensive check based on mimetype.
|
||||
ChromecastTech.canPlaySource = () => {
|
||||
return ChromecastSessionManager.isChromecastConnected();
|
||||
};
|
||||
|
||||
ChromecastTech.isSupported = () => {
|
||||
return ChromecastSessionManager.isChromecastConnected();
|
||||
};
|
||||
|
||||
videojs.registerTech('chromecast', ChromecastTech);
|
||||
};
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* This class represents the UI that is shown in the player while the Chromecast Tech is
|
||||
* active. The UI has a single root DOM element that displays the poster image of the
|
||||
* current item and title and subtitle. This class receives updates to the poster, title
|
||||
* and subtitle when the media item that the player is playing changes.
|
||||
*
|
||||
* @class ChromecastTechUI
|
||||
*/
|
||||
class ChromecastTechUI {
|
||||
constructor() {
|
||||
this._el = this._createDOMElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a single DOMElement that contains the UI. This implementation
|
||||
* of the Chromecast Tech's UI displays a poster image, a title and a subtitle.
|
||||
*
|
||||
* @private
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
_createDOMElement() {
|
||||
var el = this._createElement('div', 'vjs-tech vjs-tech-chromecast'),
|
||||
posterContainerEl = this._createElement('div', 'vjs-tech-chromecast-poster'),
|
||||
posterImageEl = this._createElement('img', 'vjs-tech-chromecast-poster-img'),
|
||||
titleEl = this._createElement('div', 'vjs-tech-chromecast-title'),
|
||||
subtitleEl = this._createElement('div', 'vjs-tech-chromecast-subtitle'),
|
||||
titleContainer = this._createElement('div', 'vjs-tech-chromecast-title-container');
|
||||
|
||||
posterContainerEl.appendChild(posterImageEl);
|
||||
titleContainer.appendChild(titleEl);
|
||||
titleContainer.appendChild(subtitleEl);
|
||||
|
||||
el.appendChild(titleContainer);
|
||||
el.appendChild(posterContainerEl);
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for creating DOMElements of the given type and with the given class
|
||||
* name(s).
|
||||
*
|
||||
* @param type {string} the kind of DOMElement to create (ex: 'div')
|
||||
* @param className {string} the class name(s) to give to the DOMElement. May also be
|
||||
* a space-delimited list of class names.
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
_createElement(type, className) {
|
||||
var el = document.createElement(type);
|
||||
|
||||
el.className = className;
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root DOMElement to be shown in the player's UI.
|
||||
*
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
getDOMElement() {
|
||||
return this._el;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the poster's DOMElement in the root UI element.
|
||||
*
|
||||
* @private
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
_findPosterEl() {
|
||||
return this._el.querySelector('.vjs-tech-chromecast-poster');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the poster's <img> DOMElement in the root UI element.
|
||||
*
|
||||
* @private
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
_findPosterImageEl() {
|
||||
return this._el.querySelector('.vjs-tech-chromecast-poster-img');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the title's DOMElement in the root UI element.
|
||||
*
|
||||
* @private
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
_findTitleEl() {
|
||||
return this._el.querySelector('.vjs-tech-chromecast-title');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the subtitle's DOMElement in the root UI element.
|
||||
*
|
||||
* @private
|
||||
* @returns {DOMElement}
|
||||
*/
|
||||
_findSubtitleEl() {
|
||||
return this._el.querySelector('.vjs-tech-chromecast-subtitle');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current poster image URL and updates the poster image DOMElement with the
|
||||
* new poster image URL.
|
||||
*
|
||||
* @param poster {string} a URL for a poster image
|
||||
*/
|
||||
updatePoster(poster) {
|
||||
var posterImageEl = this._findPosterImageEl();
|
||||
|
||||
this._poster = poster ? poster : null;
|
||||
if (poster) {
|
||||
posterImageEl.setAttribute('src', poster);
|
||||
posterImageEl.classList.remove('vjs-tech-chromecast-poster-img-empty');
|
||||
} else {
|
||||
posterImageEl.removeAttribute('src');
|
||||
posterImageEl.classList.add('vjs-tech-chromecast-poster-img-empty');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current poster image URL.
|
||||
*
|
||||
* @returns {string} the URL for th current poster image
|
||||
*/
|
||||
getPoster() {
|
||||
return this._poster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current title and updates the title's DOMElement with the new text.
|
||||
*
|
||||
* @param title {string} a title to show
|
||||
*/
|
||||
updateTitle(title) {
|
||||
var titleEl = this._findTitleEl();
|
||||
|
||||
this._title = title;
|
||||
if (title) {
|
||||
titleEl.innerHTML = title;
|
||||
titleEl.classList.remove('vjs-tech-chromecast-title-empty');
|
||||
} else {
|
||||
titleEl.classList.add('vjs-tech-chromecast-title-empty');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current subtitle and updates the subtitle's DOMElement with the new text.
|
||||
*
|
||||
* @param subtitle {string} a subtitle to show
|
||||
*/
|
||||
updateSubtitle(subtitle) {
|
||||
var subtitleEl = this._findSubtitleEl();
|
||||
|
||||
this._subtitle = subtitle;
|
||||
if (subtitle) {
|
||||
subtitleEl.innerHTML = subtitle;
|
||||
subtitleEl.classList.remove('vjs-tech-chromecast-subtitle-empty');
|
||||
} else {
|
||||
subtitleEl.classList.add('vjs-tech-chromecast-subtitle-empty');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChromecastTechUI;
|
||||
@@ -0,0 +1,48 @@
|
||||
// Images
|
||||
$icon-chromecast--default: 'images/ic_cast_white_24dp.png' !default;
|
||||
$icon-chromecast--hover: 'images/ic_cast_white_24dp.png' !default;
|
||||
$icon-chromecast-casting: 'images/ic_cast_connected_white_24dp.png' !default;
|
||||
$icon-chromecast-casting--hover: 'images/ic_cast_connected_white_24dp.png' !default;
|
||||
|
||||
// Sizes
|
||||
$chromecast-icon-size: 12px !default;
|
||||
$chromecast-button-spacing: 4px !default;
|
||||
|
||||
.vjs-chromecast-button {
|
||||
.vjs-icon-placeholder {
|
||||
background: url($icon-chromecast--default) center center no-repeat;
|
||||
background-size: contain;
|
||||
display: inline-block;
|
||||
width: $chromecast-icon-size;
|
||||
height: $chromecast-icon-size;
|
||||
}
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
.vjs-icon-placeholder {
|
||||
background-image: url($icon-chromecast--hover);
|
||||
}
|
||||
}
|
||||
&.vjs-chromecast-casting-state {
|
||||
.vjs-icon-placeholder {
|
||||
background-image: url($icon-chromecast-casting);
|
||||
}
|
||||
&:hover .vjs-icon-placeholder {
|
||||
background-image: url($icon-chromecast-casting--hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vjs-chromecast-button.vjs-chromecast-button-lg:not(.vjs-hidden) {
|
||||
// Fits both the icon and the label on the same control
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
padding: 0 $chromecast-button-spacing;
|
||||
.vjs-chromecast-button-label {
|
||||
flex-grow: 1;
|
||||
margin-left: $chromecast-button-spacing;
|
||||
}
|
||||
.vjs-icon-placeholder {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Colors
|
||||
$chromecast-color-main: #cccccc !default;
|
||||
|
||||
// Sizes
|
||||
$chromecast-title-font-size: 22px !default;
|
||||
$chromecast-subtitle-font-size: 18px !default;
|
||||
$chromecast-poster-width: 100px !default;
|
||||
$chromecast-poster-max-height: 180px !default;
|
||||
|
||||
.vjs-tech-chromecast {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
.vjs-tech-chromecast-poster {
|
||||
&::after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 2px;
|
||||
width: $chromecast-poster-width;
|
||||
background-color: $chromecast-color-main;
|
||||
position: absolute;
|
||||
left: calc(50% - #{$chromecast-poster-width * 0.5});
|
||||
}
|
||||
}
|
||||
.vjs-tech-chromecast-poster-img {
|
||||
max-height: $chromecast-poster-max-height;
|
||||
width: auto;
|
||||
border: 2px solid $chromecast-color-main;
|
||||
&.vjs-tech-chromecast-poster-img-empty {
|
||||
width: 160px;
|
||||
height: 90px;
|
||||
}
|
||||
}
|
||||
.vjs-tech-chromecast-title-container {
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
margin-bottom: 100px;
|
||||
color: $chromecast-color-main;
|
||||
text-align: center;
|
||||
}
|
||||
.vjs-tech-chromecast-title {
|
||||
font-size: $chromecast-title-font-size;
|
||||
&.vjs-tech-chromecast-title-empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.vjs-tech-chromecast-subtitle {
|
||||
font-size: $chromecast-subtitle-font-size;
|
||||
padding-top: 0.5em;
|
||||
&.vjs-tech-chromecast-subtitle-empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
@import 'chromecastButton';
|
||||
@import 'tech';
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": [
|
||||
"last 3 major versions",
|
||||
"Firefox ESR",
|
||||
"Chrome >= 53",
|
||||
"not dead",
|
||||
"not ie 11",
|
||||
"not baidu 7",
|
||||
"not and_qq 11",
|
||||
"not and_uc 12",
|
||||
"not op_mini all"
|
||||
],
|
||||
"bugfixes": true,
|
||||
"loose": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
# Browsers that we support
|
||||
|
||||
last 3 major versions
|
||||
Firefox ESR
|
||||
Chrome >= 53
|
||||
not dead
|
||||
not ie 11
|
||||
not baidu 7
|
||||
not and_qq 11
|
||||
not and_uc 12
|
||||
not op_mini all
|
||||
@@ -1,11 +0,0 @@
|
||||
# editorconfig.org - unify code style
|
||||
# plugins for text editors: editorconfig.org/#download
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
@@ -1,44 +0,0 @@
|
||||
.DS_Store
|
||||
build/files/*
|
||||
build/temp/*
|
||||
docs/api/*
|
||||
docs/apistyles
|
||||
dev.html
|
||||
projects
|
||||
.zenflow-log
|
||||
test/*.map
|
||||
.bunyipconfig.js
|
||||
.s3config.json
|
||||
.eslintcache
|
||||
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
|
||||
sandbox/*
|
||||
!sandbox/*.example
|
||||
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
*.orig
|
||||
|
||||
*results.xml
|
||||
*.log
|
||||
|
||||
test/dist/*
|
||||
.coveralls.yml
|
||||
.sass-cache
|
||||
|
||||
dist/*
|
||||
es5/*
|
||||
|
||||
.idea/
|
||||
|
||||
core.js
|
||||
core.es.js
|
||||
|
||||
# Ignore Chinese clones for now.
|
||||
lang/zh-Han*.json
|
||||
|
||||
# netlify deploy
|
||||
deploy/
|
||||
@@ -1,70 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const pkg = require('./package.json');
|
||||
|
||||
module.exports = {
|
||||
source: {
|
||||
include: ['src/js/'],
|
||||
includePattern: '.js$',
|
||||
},
|
||||
opts: {
|
||||
destination: 'docs/api',
|
||||
readme: 'docs/index.md',
|
||||
template: 'node_modules/clean-jsdoc-theme',
|
||||
package: '',
|
||||
recurse: true,
|
||||
encoding: 'utf8',
|
||||
theme_opts: {
|
||||
homepageTitle: 'Video.js API docs',
|
||||
menu: [
|
||||
{
|
||||
title: 'Video.js website',
|
||||
link: 'https://videojs.com',
|
||||
class: 'link-vjs',
|
||||
},
|
||||
{
|
||||
title: `v${pkg.version} source`,
|
||||
link: 'https://github.com/videojs/video.js',
|
||||
class: 'link-gh',
|
||||
},
|
||||
{
|
||||
title: 'Twitter',
|
||||
link: 'https://twitter.com/videojs',
|
||||
class: 'link-tw',
|
||||
},
|
||||
],
|
||||
favicon: 'https://videojs.com/favicon.ico',
|
||||
footer:
|
||||
'<span class="copyright"><a href="https://videojs.com">Video.js</a> is a free and open source HTML5 video player. © <a href="https://brightcove.com" target="_blank">Brightcove, Inc</a>. <a href="https://github.com/videojs/video.js/blob/master/LICENSE" class="button blue" target="_blank">View license</a></span>',
|
||||
include_css: ['./build/docs/styles/videojs.css'],
|
||||
displayModuleHeade: true,
|
||||
meta: [
|
||||
{
|
||||
name: 'name',
|
||||
content: 'Video.js API documentation',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
content:
|
||||
`Generated API documentation for the latest version of Video.js (${pkg.version}).`,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
templates: {
|
||||
default: {
|
||||
staticFiles: {
|
||||
include: ['build/docs/'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
'plugins/markdown',
|
||||
'build/jsdoc-typeof-plugin',
|
||||
'build/jsdoc-workarounds',
|
||||
],
|
||||
markdown: {
|
||||
tags: ['example'],
|
||||
idInHeadings: true,
|
||||
},
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
# Exclude everything but the contents of the dist directory.
|
||||
**/*
|
||||
!dist/**
|
||||
dist/video-js-*.zip
|
||||
!es5/**
|
||||
!src/css/**
|
||||
!core.js
|
||||
!core.es.js
|
||||
@@ -1 +0,0 @@
|
||||
14
|
||||
@@ -1 +0,0 @@
|
||||
CHANGELOG.md
|
||||
@@ -1,84 +0,0 @@
|
||||
var remarkrc = {
|
||||
settings: {
|
||||
bullet: '*',
|
||||
fence: '`',
|
||||
strong: '*',
|
||||
emphasis: '_',
|
||||
listItemIndent: 1,
|
||||
incrementListMarker: false
|
||||
},
|
||||
plugins: {
|
||||
'toc': {
|
||||
tight: true
|
||||
},
|
||||
}
|
||||
};
|
||||
var args = process.argv;
|
||||
|
||||
// only lint in non-output mode
|
||||
if (args.indexOf('-o') === -1 && args.indexOf('--output') === -1) {
|
||||
remarkrc['validate-links'] = {};
|
||||
remarkrc.plugins.lint = {
|
||||
'blockquote-indentation': ['error', 2],
|
||||
'checkbox-character-style': ['warn'],
|
||||
'checkbox-content-indent': ['error'],
|
||||
'code-block-style': ['error', 'fenced'],
|
||||
'definition-case': ['off'],
|
||||
'definition-spacing': ['error'],
|
||||
'emphasis-marker': ['error', '_'],
|
||||
'fenced-code-flag': ['error'],
|
||||
'fenced-code-marker': ['error', '`'],
|
||||
'file-extension': ['error'],
|
||||
'final-definition': ['error'],
|
||||
'final-newline': ['off'],
|
||||
'first-heading-level': ['warn', 1],
|
||||
'hard-break-spaces': ['off'],
|
||||
'heading-increment': ['error'],
|
||||
'heading-style': ['error', 'atx'],
|
||||
'link-title-style': ['warn', '"'],
|
||||
'list-item-bullet-indent': ['error'],
|
||||
'list-item-content-indent': ['warn'],
|
||||
'list-item-indent': ['error', 'space'],
|
||||
'list-item-spacing': ['off'],
|
||||
'maximum-heading-length': ['off'],
|
||||
'maximum-line-length': ['off'],
|
||||
'no-auto-link-without-protocol': ['error'],
|
||||
'no-blockquote-without-caret': ['error'],
|
||||
'no-consecutive-blank-lines': ['error'],
|
||||
'no-duplicate-definitions': ['error'],
|
||||
'no-duplicate-headings-in-section': ['error'],
|
||||
'no-duplicate-headings': ['off'],
|
||||
'no-emphasis-as-heading': ['error'],
|
||||
'no-file-name-articles': ['off'],
|
||||
'no-file-name-consecutive-dashes': ['off'],
|
||||
'no-file-name-irregular-characters': ['warn', '\\.a-zA-Z0-9-_'],
|
||||
'no-file-name-mixed-case': ['error'],
|
||||
'no-file-name-outer-dashes': ['error'],
|
||||
'no-heading-content-indent': ['error'],
|
||||
'no-heading-indent': ['error'],
|
||||
'no-heading-punctuation': ['off'],
|
||||
'no-html': ['off'],
|
||||
'no-inline-padding': ['error'],
|
||||
'no-literal-urls': ['off'],
|
||||
'no-missing-blank-lines': ['off'],
|
||||
'no-multiple-toplevel-headings': ['error'],
|
||||
'no-reference-like-url': ['error'],
|
||||
'no-shell-dollars': ['error'],
|
||||
'no-shortcut-reference-iamge': ['off'],
|
||||
'no-shortcut-reference-link': ['off'],
|
||||
'no-table-indentation': ['error'],
|
||||
'no-tabs': ['error'],
|
||||
'no-undefined-references': ['error'],
|
||||
'no-unused-definitions': ['error'],
|
||||
'ordered-list-marker-style': ['error', '.'],
|
||||
'ordered-list-marker-value': ['error', 'one'],
|
||||
'rule-style': ['error', '***'],
|
||||
'strong-marker': ['error', '*'],
|
||||
'table-cell-padding': ['warn', 'padded'],
|
||||
'table-cell-alignment': ['warn'],
|
||||
'table-pipes': ['warn'],
|
||||
'unordered-list-marker-style': ['warn', '*']
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = remarkrc;
|
||||
@@ -1,3 +0,0 @@
|
||||
# Video.js® Code of Conduct
|
||||
|
||||
Please refer to: <https://github.com/videojs/admin/blob/main/CODE_OF_CONDUCT.md>
|
||||
@@ -1,3 +0,0 @@
|
||||
# Video.js® Collaborator Guide
|
||||
|
||||
Please refer to: <https://github.com/videojs/admin/blob/main/COLLABORATOR_GUIDE.md>
|
||||
@@ -1,3 +0,0 @@
|
||||
# Video.js® Contributor Guide
|
||||
|
||||
Please refer to: <https://github.com/videojs/admin/blob/main/CONTRIBUTING.md>
|
||||
@@ -1,13 +0,0 @@
|
||||
Copyright Brightcove, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,142 +0,0 @@
|
||||
[![Video.js logo][logo]][vjs]
|
||||
|
||||
# Video.js® - Web Video Player
|
||||
|
||||
[![NPM][npm-icon]][npm-link]
|
||||
|
||||
Video.js is a full featured, open source video player for all web-based platforms.
|
||||
|
||||
Right out of the box, Video.js supports all common media formats used on the web including streaming formats like HLS and DASH. It works on desktops, mobile devices, tablets, and web-based Smart TVs. It can be further extended and customized by a robust ecosystem of [plugins][plugins].
|
||||
|
||||
Video.js was started in the middle of 2010 and is now used on over ~~50,000~~ ~~100,000~~ ~~200,000~~ ~~400,000~~ ~~700,000~~ [800,000 websites][builtwith].
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Quick Start](#quick-start)
|
||||
* [Contributing](#contributing)
|
||||
* [Code of Conduct](#code-of-conduct)
|
||||
* [License](#license)
|
||||
|
||||
## [Quick Start][getting-started]
|
||||
|
||||
Thanks to the awesome folks over at [Fastly][fastly], there's a free, CDN hosted version of Video.js that anyone can use. Add these tags to your document's `<head>`:
|
||||
|
||||
```html
|
||||
<link href="//vjs.zencdn.net/8.20.0/video-js.min.css" rel="stylesheet">
|
||||
<script src="//vjs.zencdn.net/8.20.0/video.min.js"></script>
|
||||
```
|
||||
|
||||
Alternatively, you can include Video.js by getting it from [npm](https://videojs.com/getting-started/#install-via-npm), downloading it from [GitHub releases](https://github.com/videojs/video.js/releases) or by including it via [unpkg](https://unpkg.com) or another JavaScript CDN, like CDNjs.
|
||||
|
||||
```html
|
||||
<!-- unpkg : use the latest version of Video.js -->
|
||||
<link href="https://unpkg.com/video.js/dist/video-js.min.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
|
||||
|
||||
<!-- unpkg : use a specific version of Video.js (change the version numbers as necessary) -->
|
||||
<link href="https://unpkg.com/video.js@8.20.0/dist/video-js.min.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/video.js@8.20.0/dist/video.min.js"></script>
|
||||
|
||||
<!-- cdnjs : use a specific version of Video.js (change the version numbers as necessary) -->
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/8.20.0/video-js.min.css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/8.20.0/video.min.js"></script>
|
||||
```
|
||||
|
||||
Next, using Video.js is as simple as creating a `<video>` element, but with an additional `data-setup` attribute. At a minimum, this attribute must have a value of `'{}'`, but it can include any Video.js [options][options] - just make sure it contains valid JSON!
|
||||
|
||||
```html
|
||||
<video
|
||||
id="my-player"
|
||||
class="video-js"
|
||||
controls
|
||||
preload="auto"
|
||||
poster="//vjs.zencdn.net/v/oceans.png"
|
||||
data-setup='{}'>
|
||||
<source src="//vjs.zencdn.net/v/oceans.mp4" type="video/mp4"></source>
|
||||
<source src="//vjs.zencdn.net/v/oceans.webm" type="video/webm"></source>
|
||||
<source src="//vjs.zencdn.net/v/oceans.ogv" type="video/ogg"></source>
|
||||
<p class="vjs-no-js">
|
||||
To view this video please enable JavaScript, and consider upgrading to a
|
||||
web browser that
|
||||
<a href="https://videojs.com/html5-video-support/" target="_blank">
|
||||
supports HTML5 video
|
||||
</a>
|
||||
</p>
|
||||
</video>
|
||||
```
|
||||
|
||||
When the page loads, Video.js will find this element and automatically setup a player in its place.
|
||||
|
||||
If you don't want to use automatic setup, you can leave off the `data-setup` attribute and initialize a `<video>` element manually using the `videojs` function:
|
||||
|
||||
```js
|
||||
var player = videojs('my-player');
|
||||
```
|
||||
|
||||
The `videojs` function also accepts an `options` object and a callback to be invoked when the player is ready:
|
||||
|
||||
```js
|
||||
var options = {};
|
||||
|
||||
var player = videojs('my-player', options, function onPlayerReady() {
|
||||
videojs.log('Your player is ready!');
|
||||
|
||||
// In this context, `this` is the player that was created by Video.js.
|
||||
this.play();
|
||||
|
||||
// How about an event listener?
|
||||
this.on('ended', function() {
|
||||
videojs.log('Awww...over so soon?!');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
If you're ready to dive in, the [Getting Started][getting-started] page and [documentation][docs] are the best places to go for more information. If you get stuck, head over to our [Slack][slack-link]!
|
||||
|
||||
## [Contributing][contributing]
|
||||
|
||||
Video.js is a free and open source library, and we appreciate any help you're willing to give - whether it's fixing bugs, improving documentation, or suggesting new features. Check out the [contributing guide][contributing] for more!
|
||||
|
||||
_Video.js uses [BrowserStack][browserstack] for compatibility testing._
|
||||
|
||||
## [Code of Conduct][coc]
|
||||
|
||||
Please note that this project is released with a [Contributor Code of Conduct][coc]. By participating in this project you agree to abide by its terms.
|
||||
|
||||
## [License][license]
|
||||
|
||||
Video.js is [licensed][license] under the Apache License, Version 2.0.
|
||||
|
||||
Video.js is a registered trademark of [Brightcove, Inc][bc].
|
||||
|
||||
[bc]: https://www.brightcove.com/
|
||||
|
||||
[browserstack]: https://browserstack.com
|
||||
|
||||
[builtwith]: https://trends.builtwith.com/media/VideoJS
|
||||
|
||||
[contributing]: https://github.com/videojs/admin/blob/main/CONTRIBUTING.md
|
||||
|
||||
[docs]: https://docs.videojs.com
|
||||
|
||||
[fastly]: https://www.fastly.com/
|
||||
|
||||
[getting-started]: https://videojs.com/getting-started/
|
||||
|
||||
[license]: LICENSE
|
||||
|
||||
[logo]: https://videojs.com/logo-white.png
|
||||
|
||||
[npm-icon]: https://nodei.co/npm/video.js.png?downloads=true&downloadRank=true
|
||||
|
||||
[npm-link]: https://nodei.co/npm/video.js/
|
||||
|
||||
[options]: https://videojs.com/guides/options/
|
||||
|
||||
[plugins]: https://videojs.com/plugins/
|
||||
|
||||
[slack-link]: https://slack.videojs.com
|
||||
|
||||
[vjs]: https://videojs.com
|
||||
|
||||
[coc]: https://github.com/videojs/admin/blob/main/CODE_OF_CONDUCT.md
|
||||
@@ -1,48 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
const fs = require('fs');
|
||||
const zlib = require('zlib');
|
||||
const filesize = require('filesize');
|
||||
const Table = require('cli-table');
|
||||
const path = require('path');
|
||||
const sh = require('shelljs');
|
||||
|
||||
// find all js/css files in the dist dir
|
||||
// but ignore any files in lang, example, or font directories
|
||||
const filepaths = sh
|
||||
.find(path.join(__dirname, '..', 'dist', '**', '*.{js,css}'))
|
||||
.filter((filepath) => !(/\/(lang|example|font)\//).test(filepath));
|
||||
|
||||
// map all files that we found into an array of
|
||||
// table entries the filepath, file size, and gzip size.
|
||||
Promise.all(filepaths.map(function(filepath) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const readStream = fs.createReadStream(filepath);
|
||||
const writeStream = fs.createWriteStream(filepath + '.gz');
|
||||
const gzip = zlib.createGzip();
|
||||
|
||||
readStream.pipe(gzip).pipe(writeStream).on('close', function() {
|
||||
const gzStat = fs.statSync(filepath + '.gz');
|
||||
const fileStat = fs.statSync(filepath);
|
||||
|
||||
fs.unlinkSync(filepath + '.gz');
|
||||
|
||||
resolve([filepath.split('dist/')[1], filesize(fileStat.size), filesize(gzStat.size)]);
|
||||
})
|
||||
.on('error', reject);
|
||||
});
|
||||
})).then(function(lines) {
|
||||
// log all the files and there sizes using a cli table
|
||||
const table = new Table({
|
||||
head: ['filename', 'size', 'gzipped'],
|
||||
colAligns: ['left', 'right', 'right'],
|
||||
style: {
|
||||
border: ['white']
|
||||
}
|
||||
});
|
||||
|
||||
table.push.apply(table, lines);
|
||||
console.log(table.toString());
|
||||
|
||||
}).catch(function(err) {
|
||||
console.error(err.stack);
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const unified = require('unified');
|
||||
const markdown = require('remark-parse');
|
||||
const stringify = require('remark-stringify');
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = function() {
|
||||
const processor = unified()
|
||||
.use(markdown, {commonmark: true})
|
||||
.use(stringify);
|
||||
|
||||
const ast = processor.parse(fs.readFileSync('./CHANGELOG.md'));
|
||||
const changelog = [];
|
||||
|
||||
changelog.push(processor.stringify(ast.children[0]));
|
||||
|
||||
// start at 1 so we get the first anchor tag
|
||||
// and can break on the second
|
||||
for (let i = 1; i < ast.children.length; i++) {
|
||||
let item = processor.stringify(ast.children[i]);
|
||||
|
||||
if (/^<a name="/.test(item)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (/^###/.test(item)) {
|
||||
item = '\n' + item + '\n';
|
||||
}
|
||||
|
||||
changelog.push(item);
|
||||
}
|
||||
|
||||
return changelog.join('\n');
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
const sh = require('shelljs');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function(commit, commitRange) {
|
||||
const SINGLE_COMMIT = `git diff-tree --no-commit-id --name-only -r ${commit}`;
|
||||
const COMMIT_RANGE = `git diff --name-only ${commitRange}`;
|
||||
|
||||
let command = SINGLE_COMMIT;
|
||||
|
||||
if (commitRange) {
|
||||
command = COMMIT_RANGE;
|
||||
}
|
||||
|
||||
const output = sh.exec(command, {async: false, silent: true}).stdout;
|
||||
|
||||
const files = output.split('\n').filter(Boolean);
|
||||
|
||||
return files.every((file) => file.startsWith('docs') || path.extname(file) === '.md');
|
||||
};
|
||||
@@ -1,66 +0,0 @@
|
||||
#resizer,
|
||||
footer {
|
||||
background-color: #ECEEF1;
|
||||
color: #868688;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
padding: 3px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
footer .copyright {
|
||||
float: left;
|
||||
}
|
||||
|
||||
footer .logo {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
background: center / contain no-repeat url(https://videojs.com/logo-white.png);
|
||||
text-indent: -999em;
|
||||
}
|
||||
|
||||
.light .sidebar-title,
|
||||
.dark .link-vjs a:before,
|
||||
.dark .link-gh a:before,
|
||||
.dark .link-tw a:before {
|
||||
-webkit-filter: invert(80%);
|
||||
filter: invert(80%);
|
||||
}
|
||||
|
||||
.link-vjs a:before,
|
||||
.link-gh a:before,
|
||||
.link-tw a:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 1.5em;
|
||||
height: 1em;
|
||||
position: relative;
|
||||
top: 0.1em;
|
||||
}
|
||||
|
||||
.link-vjs a:before {
|
||||
background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3e%3c!--! Font Awesome Free 6.2.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --%3e%3cpath d='M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L422.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C206.5 251.2 213 330 263 380c56.5 56.5 148 56.5 204.5 0L579.8 267.7zM60.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C74 372 74 321 105.5 289.5L217.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C433.5 260.8 427 182 377 132c-56.5-56.5-148-56.5-204.5 0L60.2 244.3z'/%3e%3c/svg%3e") no-repeat;
|
||||
}
|
||||
|
||||
.link-gh a:before {
|
||||
background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 480 512'%3e%3c!--! Font Awesome Free 6.2.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --%3e%3cpath d='M186.1 328.7c0 20.9-10.9 55.1-36.7 55.1s-36.7-34.2-36.7-55.1 10.9-55.1 36.7-55.1 36.7 34.2 36.7 55.1zM480 278.2c0 31.9-3.2 65.7-17.5 95-37.9 76.6-142.1 74.8-216.7 74.8-75.8 0-186.2 2.7-225.6-74.8-14.6-29-20.2-63.1-20.2-95 0-41.9 13.9-81.5 41.5-113.6-5.2-15.8-7.7-32.4-7.7-48.8 0-21.5 4.9-32.3 14.6-51.8 45.3 0 74.3 9 108.8 36 29-6.9 58.8-10 88.7-10 27 0 54.2 2.9 80.4 9.2 34-26.7 63-35.2 107.8-35.2 9.8 19.5 14.6 30.3 14.6 51.8 0 16.4-2.6 32.7-7.7 48.2 27.5 32.4 39 72.3 39 114.2zm-64.3 50.5c0-43.9-26.7-82.6-73.5-82.6-18.9 0-37 3.4-56 6-14.9 2.3-29.8 3.2-45.1 3.2-15.2 0-30.1-.9-45.1-3.2-18.7-2.6-37-6-56-6-46.8 0-73.5 38.7-73.5 82.6 0 87.8 80.4 101.3 150.4 101.3h48.2c70.3 0 150.6-13.4 150.6-101.3zm-82.6-55.1c-25.8 0-36.7 34.2-36.7 55.1s10.9 55.1 36.7 55.1 36.7-34.2 36.7-55.1-10.9-55.1-36.7-55.1z'/%3e%3c/svg%3e") no-repeat;
|
||||
}
|
||||
|
||||
.link-tw a:before {
|
||||
background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3c!--! Font Awesome Free 6.2.1 by %40fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --%3e%3cpath d='M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z'/%3e%3c/svg%3e") no-repeat;
|
||||
}
|
||||
|
||||
.light .navbar {
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 1rem;
|
||||
|
||||
}
|
||||
|
||||
.dark .navbar {
|
||||
background-color: #222;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
const replace = require('replace');
|
||||
const path = require('path');
|
||||
const apiPath = path.join(__dirname, '..', 'docs', 'api');
|
||||
|
||||
const replacements = [
|
||||
{find: /\/docs\/guides\/(.+)\.md/g, replace: 'tutorial-$1.html'},
|
||||
{find: /tutorial-tech.html/g, replace: 'tutorial-tech_.html'},
|
||||
{find: /\/docs\/guides\//g, replace: '#'},
|
||||
{find: /(\<h[1-6] id="(?:.*)?)video-js(.*)?"\>/g, replace: '$1videojs$2">'},
|
||||
{find: /(\<h[1-6] id="(?:.*)?)don-t(.*)?"\>/g, replace: '$1dont$2">'},
|
||||
{find: /(\<h[1-6] id="(?:.*)?)node-js(.*)?"\>/g, replace: '$1nodejs$2">'},
|
||||
{find: /(\<h[1-6] id="(?:.*)?)vtt-js(.*)?"\>/g, replace: '$1vttjs$2">'},
|
||||
{find: /(\<h[1-6] id=")-(.*)("\>)/g, replace: '$1$2$3'},
|
||||
{find: /(\<h[1-6] id=")(.*)-("\>)/g, replace: '$1$2$3'},
|
||||
{find: /(\<h[1-6] id=".*)-docs-guides-.*-md("\>)/g, replace: '$1$2'},
|
||||
// replace all children with children-1
|
||||
{find: /\<h3 id="children"\>/g, replace: '<h3 id="children-1">'},
|
||||
// remove the -1 from the first item
|
||||
{find: /\<h3 id="children-1"\>/, replace: '<h3 id="children">'},
|
||||
{find: '<h4 id="nativecontrolsfortouch">', replace: '<h4 id="nativecontrolsfortouch-1">'},
|
||||
{find: '<h3 id="videojs-(audio|video)track">', replace: '<h3 id="videojs$1track">'},
|
||||
{find: '<h3 id="text-tracks">', replace: '<h3 id="text-tracks-1">'},
|
||||
{find: '<h2 id="q-how-can-i-hide-the-links-to-my-video-subtitles-audio-tracks">',
|
||||
replace: '<h2 id="q-how-can-i-hide-the-links-to-my-videosubtitlesaudiotracks">'},
|
||||
{find: '<h3 id="dispose-http-docs-videojs-com-player-html-dispose">',
|
||||
replace: '<h3 id="dispose">'},
|
||||
{find: '<h4 id="effect-on-player-width-and-player-height">',
|
||||
replace: '<h4 id="effect-on-playerwidth-and-playerheight">'},
|
||||
{find: '<h4 id="i-want-to-have-a-single-source-and-dont-care-about-live-adaptive-streaming">',
|
||||
replace: '<h4 id="i-want-to-have-a-single-source-and-dont-care-about-liveadaptive-streaming">'},
|
||||
{find: '<h2 id="api-docs-api">', replace: '<h2 id="api-docs">'},
|
||||
{find: '<h2 id="guides-docs-guides">', replace: '<h2 id="guides">'}
|
||||
];
|
||||
|
||||
replacements.forEach(function(obj) {
|
||||
replace({
|
||||
regex: obj.find,
|
||||
replacement: obj.replace,
|
||||
paths: [apiPath],
|
||||
recursive: true,
|
||||
silent: true
|
||||
});
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* The jsdoc plugin that will convert types like {typeof ClassName} into {Class<ClassName>}
|
||||
*/
|
||||
exports.handlers = {
|
||||
jsdocCommentFound: event => {
|
||||
event.comment = (event.comment || '').replace(/\{.*typeof\s+([^\s\|]+).*\}/g, typeExpression => {
|
||||
return typeExpression.replace(/typeof\s+([^\s\|\}]+)/g, (expression, className) => {
|
||||
return 'Class<' + className + '>';
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* This jsdoc plugin works around some typescript-flavoured jsdoc that isn't actual jsdoc,
|
||||
* so docs:api doesn't fail
|
||||
*/
|
||||
exports.handlers = {
|
||||
jsdocCommentFound: event => {
|
||||
// Special case for media-error.js
|
||||
event.comment = (event.comment || '').replace(
|
||||
'@typedef {{errorType: string, [key: string]: any}} ErrorMetadata',
|
||||
'@typedef {Object} ErrorMetadata\n * @property {string} errorType Error type'
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Video.js <%= version %> <http://videojs.com/>
|
||||
* <%= copyright %>
|
||||
* Available under Apache License Version 2.0
|
||||
* <https://github.com/videojs/video.js/blob/main/LICENSE>
|
||||
<% if (includesVtt) { %> *
|
||||
* Includes vtt.js <https://github.com/mozilla/vtt.js>
|
||||
* Available under Apache License Version 2.0
|
||||
* <https://github.com/mozilla/vtt.js/blob/main/LICENSE>
|
||||
<% } %> */
|
||||
@@ -1,48 +0,0 @@
|
||||
/* eslint-disable no-console, camelcase */
|
||||
|
||||
const fs = require('fs');
|
||||
const uglify = require('uglify-js');
|
||||
const maxmin = require('maxmin');
|
||||
|
||||
const options = {
|
||||
nameCache: {},
|
||||
output: {
|
||||
comments: 'some'
|
||||
},
|
||||
mangle: true,
|
||||
compress: {
|
||||
sequences: true,
|
||||
dead_code: true,
|
||||
conditionals: true,
|
||||
booleans: true,
|
||||
unused: true,
|
||||
if_return: true,
|
||||
join_vars: true,
|
||||
drop_console: true,
|
||||
typeofs: false
|
||||
}
|
||||
};
|
||||
|
||||
const minify = (file, dest) => {
|
||||
const code = fs.readFileSync(file, 'utf8');
|
||||
const minified = uglify.minify(code, options);
|
||||
|
||||
if (minified.error) {
|
||||
console.error(minified.error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (minified.warnings) {
|
||||
console.warn(minified.warnings);
|
||||
}
|
||||
|
||||
fs.writeFileSync(dest, minified.code, 'utf8');
|
||||
console.log('File', dest, 'created:', maxmin(code, minified.code, true));
|
||||
};
|
||||
|
||||
console.log('Minifying files\n');
|
||||
|
||||
minify('dist/video.js', 'dist/video.min.js');
|
||||
minify('dist/alt/video.novtt.js', 'dist/alt/video.novtt.min.js');
|
||||
minify('dist/alt/video.core.js', 'dist/alt/video.core.min.js');
|
||||
minify('dist/alt/video.core.novtt.js', 'dist/alt/video.core.novtt.min.js');
|
||||
@@ -1,23 +0,0 @@
|
||||
const sh = require('shelljs');
|
||||
const semver = require('semver');
|
||||
const path = require('path');
|
||||
|
||||
const GIT_LOG = `git log --format=%B -n 1 ${process.env.COMMIT_REF}`;
|
||||
const output = sh.exec(GIT_LOG, {async: false, silent: true}).stdout;
|
||||
|
||||
// if we're on main branch and not on a tagged commit,
|
||||
// error the build so it doesn't redeploy the docs
|
||||
if (process.env.BRANCH === 'main' && semver.valid(output.trim()) === null) {
|
||||
process.exit(1);
|
||||
} else {
|
||||
sh.exec('npm run docs:api');
|
||||
sh.cp('-R', 'docs/legacy-docs', 'docs/api/docs');
|
||||
|
||||
// move docs/_redirects into the root of the docs site
|
||||
//
|
||||
// this is needed because the root of the docs site is docs/api, which is not
|
||||
// in version control.
|
||||
const docsPath = path.join(__dirname, '..', 'docs');
|
||||
|
||||
sh.cp(path.join(docsPath, '_redirects'), path.join(docsPath, 'api', '_redirects'));
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
const pkg = require('../package.json');
|
||||
const path = require('path');
|
||||
const sh = require('shelljs');
|
||||
|
||||
process.env.CI = true;
|
||||
// run build steps
|
||||
sh.exec('npm run build');
|
||||
sh.exec('npm run sandbox');
|
||||
sh.exec('npm run docs:api');
|
||||
|
||||
// copy the legacy docs over
|
||||
sh.cp('-R', 'docs/legacy-docs', 'docs/api/docs');
|
||||
|
||||
const deployDir = 'deploy';
|
||||
const files = [
|
||||
'node_modules/es5-shim/es5-shim.js',
|
||||
'node_modules/es6-shim/es6-shim.js'
|
||||
];
|
||||
|
||||
// cleanup previous deploy
|
||||
sh.rm('-rf', deployDir);
|
||||
// make sure the directory exists
|
||||
sh.mkdir('-p', deployDir);
|
||||
|
||||
// create sub-directory for images
|
||||
sh.mkdir('-p', `${deployDir}/src`);
|
||||
|
||||
// create nested directories
|
||||
files
|
||||
.map((file) => path.dirname(file))
|
||||
.forEach((dir) => sh.mkdir('-p', path.join(deployDir, dir)));
|
||||
|
||||
// copy files/folders to deploy dir
|
||||
files
|
||||
.concat('dist', 'index.html', 'sandbox', 'docs', 'src/images')
|
||||
.forEach((file) => sh.cp('-r', file, path.join(deployDir, file)));
|
||||
|
||||
sh.rm(path.join(deployDir, 'dist', `video-js-${pkg.version}.zip`));
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
Replaces the version number in the readme with the current package version.
|
||||
Looks for patterns like `/8.17.3/` and `/video.js@8.17.3/`
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const version = require('../package.json').version;
|
||||
|
||||
let doc = fs.readFileSync(path.join(__dirname, '..', 'README.md'), 'utf8');
|
||||
|
||||
doc = doc
|
||||
.replace(/\/video.js@\d\.\d+\.\d+\//g, `/video.js@${version}/`)
|
||||
.replace(/\/\d\.\d+\.\d+\//g, `/${version}/`);
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'README.md'), doc, 'utf8');
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Remove parts of files from outputs. Everything between a pair of `/* start-delete-from-build *\u002f`
|
||||
* and `/* end-delete-from-build *\u002f` comments
|
||||
*
|
||||
* Based on https://github.com/se-panfilov/rollup-plugin-strip-code
|
||||
*/
|
||||
|
||||
import { createFilter } from '@rollup/pluginutils';
|
||||
|
||||
const START_COMMENT = 'start-delete-from-build';
|
||||
const END_COMMENT = 'end-delete-from-build';
|
||||
|
||||
/**
|
||||
* Remove lines of code surrounded by comments
|
||||
*
|
||||
* @param {Object} [options] Options
|
||||
* @param {string} [options.include] Files to inlcude
|
||||
* @param {string} [options.exclude] Files to exclude
|
||||
* @param {string} [options.startComment] Starting keywork, default start-delete-from-build
|
||||
* @param {string} [options.endComment] Eding keywork, default end-delete-from-build
|
||||
* @param {RegExp} [options.pattern] Custom regex
|
||||
* @return void
|
||||
*/
|
||||
export default function excludeLines(options = {}) {
|
||||
// assume that the myPlugin accepts options of `options.include` and `options.exclude`
|
||||
const filter = createFilter(options.include, options.exclude);
|
||||
|
||||
return {
|
||||
transform(code, id) {
|
||||
if (!filter(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startComment = options.startComment || START_COMMENT;
|
||||
const endComment = options.endComment || END_COMMENT;
|
||||
const defaultPattern = new RegExp(`([\\t ]*\\/\\* ?${startComment} ?\\*\\/)[\\s\\S]*?(\\/\\* ?${endComment} ?\\*\\/[\\t ]*\\n?)`, 'g');
|
||||
|
||||
return code.replace(options.pattern || defaultPattern, '');
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sh = require('shelljs');
|
||||
|
||||
const files = sh.find(path.join(__dirname, '..', 'sandbox', '**', '*.*'))
|
||||
.filter((filepath) => path.extname(filepath) === '.example');
|
||||
|
||||
const changes = files.map(function(filepath) {
|
||||
const p = path.parse(filepath);
|
||||
const nonExample = path.join(p.dir, p.name);
|
||||
|
||||
return {
|
||||
file: filepath,
|
||||
copy: nonExample
|
||||
};
|
||||
}).filter(function(change) {
|
||||
return !fs.existsSync(change.copy);
|
||||
});
|
||||
|
||||
changes.forEach(function(change) {
|
||||
fs.copyFileSync(change.file, change.copy);
|
||||
});
|
||||
|
||||
if (changes.length) {
|
||||
console.log('Updated Sandbox files for:');
|
||||
console.log('\t' + changes.map((chg) => chg.copy).join('\n\t'));
|
||||
} else {
|
||||
console.log('No sandbox updates necessary');
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
const AccessSniff = require('access-sniff');
|
||||
const path = require('path');
|
||||
|
||||
const testFiles = [
|
||||
path.join(__dirname, '..', 'sandbox', 'descriptions.test-a11y.html')
|
||||
];
|
||||
|
||||
const options = {
|
||||
accessibilityLevel: 'WCAG2AA',
|
||||
reportLevels: {
|
||||
notice: false,
|
||||
warning: true,
|
||||
error: true
|
||||
},
|
||||
ignore: [
|
||||
// Ignore warning about contrast of the "vjs-no-js" fallback link
|
||||
'WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.BgImage'
|
||||
]
|
||||
};
|
||||
|
||||
AccessSniff.default(testFiles, options).then(function(report) {
|
||||
AccessSniff.report(report);
|
||||
}).catch(function() {
|
||||
|
||||
// there were errors, which are already reported, exit with an error
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,54 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sh = require('shelljs');
|
||||
|
||||
const source = require('../lang/en.json');
|
||||
const table = require('markdown-table');
|
||||
const tableRegex = /(<!-- START langtable -->)(.|\n)*(<!-- END langtable -->)/;
|
||||
|
||||
let doc = fs.readFileSync(path.join(__dirname, '..', 'docs', 'translations-needed.md'), 'utf8');
|
||||
const tableData = [['Language file', 'Missing translations']];
|
||||
|
||||
const filepaths = sh.find(path.join(__dirname, '..', 'lang', '**', '!(zh-Hans|zh-Hant)*.json'));
|
||||
|
||||
filepaths.forEach((filepath) => {
|
||||
const filename = path.basename(filepath);
|
||||
|
||||
if (filename === 'en.json') {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = require(filepath);
|
||||
|
||||
// Special case for English, the assumption being that since the keys are English only
|
||||
// a few strings need to be altered for regional differences, e.g. en-GB.
|
||||
if (filename.startsWith('en-')) {
|
||||
console.log(`${filename} English - should be manually checked.`);
|
||||
tableData.push([`${filename} (has ${Object.keys(target).length})`, 'Needs manual checking. Can safely use most default strings.']);
|
||||
return;
|
||||
}
|
||||
|
||||
const missing = [];
|
||||
|
||||
for (const string in source) {
|
||||
if (!target[string]) {
|
||||
console.log(`${filename} missing "${string}"`);
|
||||
missing.push(string);
|
||||
}
|
||||
}
|
||||
if (missing.length > 0) {
|
||||
console.error(`${filename} is missing ${missing.length} translations.`);
|
||||
tableData.push([`${filename} (missing ${missing.length})`, missing[0]]);
|
||||
for (let i = 1; i < missing.length; i++) {
|
||||
tableData.push(['', missing[i]]);
|
||||
}
|
||||
} else {
|
||||
console.log(`${filename} is up to date.`);
|
||||
tableData.push([`${filename} (Complete)`, '']);
|
||||
}
|
||||
});
|
||||
|
||||
doc = doc.replace(tableRegex, '$1\n' + table(tableData) + '\n$3');
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'docs', 'translations-needed.md'), doc, 'utf8');
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "videojs/video.js",
|
||||
"description": "An HTML5 video player.",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"videojs",
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"homepage": "https://www.videojs.com/",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# Netlify redirects to redirect old tutorial pages to new guide pages
|
||||
/tutorial-angular.html https://videojs.com/guides/angular/ 301!
|
||||
/tutorial-audio-tracks.html https://videojs.com/guides/audio-tracks/ 301!
|
||||
/tutorial-components.html https://videojs.com/guides/components/ 301!
|
||||
/tutorial-debugging.html https://videojs.com/guides/debugging/ 301!
|
||||
/tutorial-embeds.html https://videojs.com/guides/embeds/ 301!
|
||||
/tutorial-event-target.html https://videojs.com/guides/event-target/ 301!
|
||||
/tutorial-faq.html https://videojs.com/guides/faqs/ 301!
|
||||
/tutorial-hooks.html https://videojs.com/guides/hooks/ 301!
|
||||
/tutorial-languages.html https://videojs.com/guides/languages/ 301!
|
||||
/tutorial-layout.html https://videojs.com/guides/layout/ 301!
|
||||
/tutorial-live.html https://videojs.com/guides/live/ 301!
|
||||
/tutorial-middleware.html https://videojs.com/guides/middleware/ 301!
|
||||
/tutorial-modal-dialog.html https://videojs.com/guides/modal-dialog/ 301!
|
||||
/tutorial-options.html https://videojs.com/guides/options/ 301!
|
||||
/tutorial-player-workflows.html https://videojs.com/guides/player-workflows/ 301!
|
||||
/tutorial-plugins.html https://videojs.com/guides/plugins/ 301!
|
||||
/tutorial-react.html https://videojs.com/guides/react/ 301!
|
||||
/tutorial-setup.html https://videojs.com/guides/setup/ 301!
|
||||
/tutorial-skins.html https://videojs.com/guides/skins/ 301!
|
||||
/tutorial-tech.html https://videojs.com/guides/tech/ 301!
|
||||
/tutorial-text-tracks.html https://videojs.com/guides/text-tracks/ 301!
|
||||
/tutorial-troubleshooting.html https://videojs.com/guides/troubleshooting/ 301!
|
||||
/tutorial-video-tracks.html https://videojs.com/guides/video-tracks/ 301!
|
||||
/tutorial-videojs.html https://videojs.com/guides/videojs/ 301!
|
||||
/tutorial-vue.html https://videojs.com/guides/vue/ 301!
|
||||
/tutorial-webpack.html https://videojs.com/guides/webpack/ 301!
|
||||
@@ -1,330 +0,0 @@
|
||||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.042 --> 00:00:18.625
|
||||
...إلى... إلى الشمال يمكن أن نرى
|
||||
...يمكن أن نرى الـ
|
||||
|
||||
2
|
||||
00:00:18.750 --> 00:00:20.958
|
||||
...إلى اليمين يمكن أن نرى الـ
|
||||
|
||||
3
|
||||
00:00:21.000 --> 00:00:23.125
|
||||
طاحنات الرؤوس...
|
||||
|
||||
4
|
||||
00:00:23.208 --> 00:00:25.208
|
||||
كل شيئ آمن
|
||||
آمن كلية
|
||||
|
||||
5
|
||||
00:00:26.333 --> 00:00:28.333
|
||||
إيمو ؟
|
||||
|
||||
6
|
||||
00:00:28.875 --> 00:00:30.958
|
||||
! حذاري
|
||||
|
||||
7
|
||||
00:00:47.125 --> 00:00:49.167
|
||||
هل أصبت ؟
|
||||
|
||||
8
|
||||
00:00:52.125 --> 00:00:54.833
|
||||
...لا أظن ذلك
|
||||
وأنت ؟
|
||||
|
||||
9
|
||||
00:00:55.625 --> 00:00:57.625
|
||||
أنا بخير
|
||||
|
||||
10
|
||||
00:00:57.667 --> 00:01:01.667
|
||||
،قم يا إيمو
|
||||
المكان هنا غير آمن
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:04.083
|
||||
لنذهب
|
||||
|
||||
12
|
||||
00:01:04.167 --> 00:01:06.167
|
||||
وماذا بعد ؟
|
||||
|
||||
13
|
||||
00:01:06.167 --> 00:01:08.583
|
||||
...سترى... سترى
|
||||
|
||||
14
|
||||
00:01:16.167 --> 00:01:18.375
|
||||
إيمو، من هنا
|
||||
|
||||
15
|
||||
00:01:34.958 --> 00:01:37.000
|
||||
! إتبعني
|
||||
|
||||
16
|
||||
00:02:11.125 --> 00:02:13.625
|
||||
! أسرع يا إيمو
|
||||
|
||||
17
|
||||
00:02:48.375 --> 00:02:50.375
|
||||
! لست منتبها
|
||||
|
||||
18
|
||||
00:02:50.750 --> 00:02:54.500
|
||||
...أريد فقط أن أجيب الـ
|
||||
الهاتف...
|
||||
|
||||
19
|
||||
00:02:55.000 --> 00:02:58.500
|
||||
،إيمو، أنظر
|
||||
أقصد أنصت
|
||||
|
||||
20
|
||||
00:02:59.750 --> 00:03:03.292
|
||||
عليك أن تتعلم الإصغاء
|
||||
|
||||
21
|
||||
00:03:03.625 --> 00:03:05.917
|
||||
هذا ليس ضربا من اللهو
|
||||
|
||||
22
|
||||
00:03:06.083 --> 00:03:09.958
|
||||
...إنك
|
||||
أقصد إننا قد نموت بسهولة في هذا المكان
|
||||
|
||||
23
|
||||
00:03:10.208 --> 00:03:14.125
|
||||
...أنصت
|
||||
أنصت إلى أصوات الآلة
|
||||
|
||||
24
|
||||
00:03:18.333 --> 00:03:20.417
|
||||
أنصت إلى نَفَسِك
|
||||
|
||||
25
|
||||
00:04:27.208 --> 00:04:29.250
|
||||
ألا تمل أبدا من هذا ؟
|
||||
|
||||
26
|
||||
00:04:29.583 --> 00:04:31.583
|
||||
أمل ؟!؟
|
||||
نعم -
|
||||
|
||||
27
|
||||
00:04:31.750 --> 00:04:34.667
|
||||
إيمو؛ الآلة في دقتها... مثل الساعة
|
||||
|
||||
28
|
||||
00:04:35.500 --> 00:04:37.708
|
||||
...حركة ناشزة واحدة قد
|
||||
|
||||
29
|
||||
00:04:37.833 --> 00:04:39.875
|
||||
تطرحك معجونا
|
||||
|
||||
30
|
||||
00:04:41.042 --> 00:04:43.083
|
||||
...أو ليست
|
||||
|
||||
31
|
||||
00:04:43.125 --> 00:04:46.542
|
||||
! عجينة يا إيمو
|
||||
أ هذا ما تريد ؟ أن تصبح عجينة ؟
|
||||
|
||||
32
|
||||
00:04:48.083 --> 00:04:50.083
|
||||
أيمو، أ هذا هدفك في الحياة ؟
|
||||
|
||||
33
|
||||
00:04:50.583 --> 00:04:52.667
|
||||
أن تصير عجينة ؟
|
||||
|
||||
34
|
||||
00:05:41.833 --> 00:05:43.875
|
||||
إيمو، أغمض عينيك
|
||||
|
||||
35
|
||||
00:05:44.917 --> 00:05:47.000
|
||||
لماذا ؟
|
||||
! الآن -
|
||||
|
||||
36
|
||||
00:05:53.750 --> 00:05:56.042
|
||||
حسن
|
||||
|
||||
37
|
||||
00:05:59.542 --> 00:06:02.792
|
||||
ماذا ترى إلى شمالك يا إيمو ؟
|
||||
|
||||
38
|
||||
00:06:04.417 --> 00:06:06.500
|
||||
لا شيئ
|
||||
حقا ؟ -
|
||||
|
||||
39
|
||||
00:06:06.542 --> 00:06:08.625
|
||||
لا، لا شيئ البتة
|
||||
|
||||
40
|
||||
00:06:08.625 --> 00:06:12.417
|
||||
وماذا ترى إلى جهتك اليمنى يا إيمو ؟
|
||||
|
||||
41
|
||||
00:06:13.667 --> 00:06:17.833
|
||||
،نفس الشيئ يا بروغ
|
||||
! نفس الشيئ بالضبط؛ لا شيئ
|
||||
|
||||
42
|
||||
00:06:17.875 --> 00:06:19.917
|
||||
عظيم
|
||||
|
||||
43
|
||||
00:06:40.625 --> 00:06:42.958
|
||||
أنصت يا بروغ ! هل تسمع ذلك ؟
|
||||
|
||||
44
|
||||
00:06:43.625 --> 00:06:45.625
|
||||
هل نستطيع الذهاب إلى هناك ؟
|
||||
|
||||
45
|
||||
00:06:45.708 --> 00:06:47.792
|
||||
هناك ؟
|
||||
نعم -
|
||||
|
||||
46
|
||||
00:06:47.833 --> 00:06:49.833
|
||||
إنه غير آمن يا إيمو
|
||||
|
||||
47
|
||||
00:06:49.917 --> 00:06:52.500
|
||||
صدقني، إنه غير آمن
|
||||
|
||||
48
|
||||
00:06:53.292 --> 00:06:55.375
|
||||
...لكن لعلي أستطيع
|
||||
|
||||
49
|
||||
00:06:55.417 --> 00:06:57.417
|
||||
...لكن
|
||||
! لا -
|
||||
|
||||
50
|
||||
00:06:57.667 --> 00:06:59.667
|
||||
! لا
|
||||
|
||||
51
|
||||
00:07:00.875 --> 00:07:03.750
|
||||
هل من أسئلة أخرى يا إيمو ؟
|
||||
|
||||
52
|
||||
00:07:04.250 --> 00:07:06.333
|
||||
لا
|
||||
|
||||
53
|
||||
00:07:09.458 --> 00:07:11.542
|
||||
...إيمو
|
||||
نعم -
|
||||
|
||||
54
|
||||
00:07:11.875 --> 00:07:13.958
|
||||
...لماذا يا إيمو... لماذا
|
||||
|
||||
55
|
||||
00:07:15.292 --> 00:07:18.792
|
||||
لماذا لا تستطيع أن ترى حُسْن هذا المكان
|
||||
|
||||
56
|
||||
00:07:18.833 --> 00:07:20.833
|
||||
...والطريقة التي يعمل بها
|
||||
|
||||
57
|
||||
00:07:20.875 --> 00:07:24.000
|
||||
وكيف... وكيف أنه غاية في الكمال
|
||||
|
||||
58
|
||||
00:07:24.083 --> 00:07:27.417
|
||||
! لا يا بروغ، لا أرى ذلك
|
||||
|
||||
59
|
||||
00:07:27.542 --> 00:07:30.333
|
||||
لا أرى ذلك لأنه لا يوجد شيئ هناك
|
||||
|
||||
60
|
||||
00:07:31.500 --> 00:07:35.333
|
||||
ثم لماذا يجب علي أن أسلم حياتي
|
||||
لشيئ لا وجود له ؟
|
||||
|
||||
61
|
||||
00:07:35.583 --> 00:07:37.625
|
||||
هل يمكنك أن تخبرني ؟
|
||||
|
||||
62
|
||||
00:07:37.708 --> 00:07:39.750
|
||||
! أجبني
|
||||
|
||||
63
|
||||
00:07:43.208 --> 00:07:47.333
|
||||
...بروغ
|
||||
! أنت معتوه يا هذا
|
||||
|
||||
64
|
||||
00:07:47.375 --> 00:07:49.417
|
||||
! إبعد عني
|
||||
|
||||
65
|
||||
00:07:52.583 --> 00:07:55.083
|
||||
! لا يا إيمو ! إنه فخ
|
||||
|
||||
66
|
||||
00:07:55.833 --> 00:07:57.875
|
||||
...إنه فخ
|
||||
|
||||
67
|
||||
00:07:57.917 --> 00:08:01.750
|
||||
إلى جنبك الأيسر يمكنك أن ترى
|
||||
حدائق بابل المعلقة
|
||||
|
||||
68
|
||||
00:08:02.250 --> 00:08:04.292
|
||||
هل تعجبك كفخ ؟
|
||||
|
||||
69
|
||||
00:08:05.458 --> 00:08:07.542
|
||||
لا يا أيمو
|
||||
|
||||
70
|
||||
00:08:09.417 --> 00:08:12.792
|
||||
...إلى جنبك الأيمن يمكنك رؤية
|
||||
حزر ماذا ؟
|
||||
|
||||
71
|
||||
00:08:13.000 --> 00:08:15.042
|
||||
! عملاق رودس
|
||||
|
||||
72
|
||||
00:08:15.125 --> 00:08:16.417
|
||||
! لا
|
||||
|
||||
73
|
||||
00:08:16.458 --> 00:08:20.500
|
||||
،عملاق رودس
|
||||
وهو هنا خصيصا من أجلك يا بروغ
|
||||
|
||||
74
|
||||
00:08:20.583 --> 00:08:22.583
|
||||
فقط من أجلك
|
||||
|
||||
75
|
||||
00:08:51.333 --> 00:08:53.375
|
||||
إنه هناك
|
||||
|
||||
76
|
||||
00:08:53.417 --> 00:08:55.500
|
||||
أنا أؤكد لك... إيمو
|
||||
|
||||
77
|
||||
00:08:57.333 --> 00:09:00.000
|
||||
...إنه
|
||||
@@ -1,334 +0,0 @@
|
||||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.000 --> 00:00:17.951
|
||||
At the left we can see...
|
||||
|
||||
2
|
||||
00:00:18.166 --> 00:00:20.083
|
||||
At the right we can see the...
|
||||
|
||||
3
|
||||
00:00:20.119 --> 00:00:21.962
|
||||
...the head-snarlers
|
||||
|
||||
4
|
||||
00:00:21.999 --> 00:00:24.368
|
||||
Everything is safe.
|
||||
Perfectly safe.
|
||||
|
||||
5
|
||||
00:00:24.582 --> 00:00:27.035
|
||||
Emo?
|
||||
|
||||
6
|
||||
00:00:28.206 --> 00:00:29.996
|
||||
Watch out!
|
||||
|
||||
7
|
||||
00:00:47.037 --> 00:00:48.494
|
||||
Are you hurt?
|
||||
|
||||
8
|
||||
00:00:51.994 --> 00:00:53.949
|
||||
I don't think so.
|
||||
You?
|
||||
|
||||
9
|
||||
00:00:55.160 --> 00:00:56.985
|
||||
I'm Ok.
|
||||
|
||||
10
|
||||
00:00:57.118 --> 00:01:01.111
|
||||
Get up.
|
||||
Emo. it's not safe here.
|
||||
|
||||
11
|
||||
00:01:02.034 --> 00:01:03.573
|
||||
Let's go.
|
||||
|
||||
12
|
||||
00:01:03.610 --> 00:01:05.114
|
||||
What's next?
|
||||
|
||||
13
|
||||
00:01:05.200 --> 00:01:09.146
|
||||
You'll see!
|
||||
|
||||
14
|
||||
00:01:16.032 --> 00:01:18.022
|
||||
Emo.
|
||||
This way.
|
||||
|
||||
15
|
||||
00:01:34.237 --> 00:01:35.481
|
||||
Follow me!
|
||||
|
||||
16
|
||||
00:02:11.106 --> 00:02:12.480
|
||||
Hurry Emo!
|
||||
|
||||
17
|
||||
00:02:48.059 --> 00:02:49.930
|
||||
You're not paying attention!
|
||||
|
||||
18
|
||||
00:02:50.142 --> 00:02:54.052
|
||||
I just want to answer the...
|
||||
...phone.
|
||||
|
||||
19
|
||||
00:02:54.974 --> 00:02:57.972
|
||||
Emo. look.
|
||||
I mean listen.
|
||||
|
||||
20
|
||||
00:02:59.140 --> 00:03:02.008
|
||||
You have to learn to listen.
|
||||
|
||||
21
|
||||
00:03:03.140 --> 00:03:04.965
|
||||
This is not some game.
|
||||
|
||||
22
|
||||
00:03:05.056 --> 00:03:09.345
|
||||
You. I mean we.
|
||||
we could easily die out here.
|
||||
|
||||
23
|
||||
00:03:10.014 --> 00:03:13.959
|
||||
Listen.
|
||||
listen to the sounds of the machine.
|
||||
|
||||
24
|
||||
00:03:18.054 --> 00:03:20.009
|
||||
Listen to your breathing.
|
||||
|
||||
25
|
||||
00:04:27.001 --> 00:04:28.956
|
||||
Well. don't you ever get tired of this?
|
||||
|
||||
26
|
||||
00:04:29.084 --> 00:04:30.909
|
||||
Tired?!?
|
||||
|
||||
27
|
||||
00:04:31.126 --> 00:04:34.491
|
||||
Emo. the machine is like clockwork.
|
||||
|
||||
28
|
||||
00:04:35.083 --> 00:04:37.074
|
||||
One move out of place...
|
||||
|
||||
29
|
||||
00:04:37.166 --> 00:04:39.121
|
||||
...and you're ground to a pulp.
|
||||
|
||||
30
|
||||
00:04:40.958 --> 00:04:42.004
|
||||
But isn't it -
|
||||
|
||||
31
|
||||
00:04:42.041 --> 00:04:46.034
|
||||
Pulp. Emo!
|
||||
Is that what you want. pulp?
|
||||
|
||||
32
|
||||
00:04:47.040 --> 00:04:48.995
|
||||
Emo. your goal in life...
|
||||
|
||||
33
|
||||
00:04:50.081 --> 00:04:51.953
|
||||
...pulp?
|
||||
|
||||
34
|
||||
00:05:41.156 --> 00:05:43.028
|
||||
Emo. close your eyes.
|
||||
|
||||
35
|
||||
00:05:44.156 --> 00:05:46.027
|
||||
Why?
|
||||
- Now!
|
||||
|
||||
36
|
||||
00:05:51.155 --> 00:05:52.102
|
||||
Ok.
|
||||
|
||||
37
|
||||
00:05:53.113 --> 00:05:54.688
|
||||
Good.
|
||||
|
||||
38
|
||||
00:05:59.070 --> 00:06:02.103
|
||||
What do you see at your left side. Emo?
|
||||
|
||||
39
|
||||
00:06:04.028 --> 00:06:05.899
|
||||
Nothing.
|
||||
- Really?
|
||||
|
||||
40
|
||||
00:06:06.027 --> 00:06:07.105
|
||||
No. nothing at all.
|
||||
|
||||
41
|
||||
00:06:07.944 --> 00:06:11.984
|
||||
And at your right.
|
||||
what do you see at your right side. Emo?
|
||||
|
||||
42
|
||||
00:06:13.151 --> 00:06:16.102
|
||||
The same Proog. exactly the same...
|
||||
|
||||
43
|
||||
00:06:16.942 --> 00:06:19.098
|
||||
...nothing!
|
||||
- Great.
|
||||
|
||||
44
|
||||
00:06:40.105 --> 00:06:42.724
|
||||
Listen Proog! Do you hear that!
|
||||
|
||||
45
|
||||
00:06:43.105 --> 00:06:44.894
|
||||
Can we go here?
|
||||
|
||||
46
|
||||
00:06:44.979 --> 00:06:47.894
|
||||
There?
|
||||
It isn't safe. Emo.
|
||||
|
||||
47
|
||||
00:06:49.145 --> 00:06:52.013
|
||||
But...
|
||||
- Trust me. it's not.
|
||||
|
||||
48
|
||||
00:06:53.020 --> 00:06:54.145
|
||||
Maybe I could...
|
||||
|
||||
49
|
||||
00:06:54.181 --> 00:06:55.969
|
||||
No.
|
||||
|
||||
50
|
||||
00:06:57.102 --> 00:06:59.934
|
||||
NO!
|
||||
|
||||
51
|
||||
00:07:00.144 --> 00:07:03.058
|
||||
Any further questions. Emo?
|
||||
|
||||
52
|
||||
00:07:03.976 --> 00:07:05.090
|
||||
No.
|
||||
|
||||
53
|
||||
00:07:09.059 --> 00:07:10.089
|
||||
Emo?
|
||||
|
||||
54
|
||||
00:07:11.142 --> 00:07:13.058
|
||||
Emo. why...
|
||||
|
||||
55
|
||||
00:07:13.095 --> 00:07:14.022
|
||||
Emo...
|
||||
|
||||
56
|
||||
00:07:14.058 --> 00:07:18.003
|
||||
...why can't you see
|
||||
the beauty of this place?
|
||||
|
||||
57
|
||||
00:07:18.141 --> 00:07:20.048
|
||||
The way it works.
|
||||
|
||||
58
|
||||
00:07:20.140 --> 00:07:23.895
|
||||
How perfect it is.
|
||||
|
||||
59
|
||||
00:07:23.932 --> 00:07:26.964
|
||||
No. Proog. I don't see.
|
||||
|
||||
60
|
||||
00:07:27.056 --> 00:07:29.970
|
||||
I don't see because there's nothing there.
|
||||
|
||||
61
|
||||
00:07:31.055 --> 00:07:34.965
|
||||
And why should I trust my
|
||||
life to something that isn't there?
|
||||
|
||||
62
|
||||
00:07:35.055 --> 00:07:36.926
|
||||
Well can you tell me that?
|
||||
|
||||
63
|
||||
00:07:37.054 --> 00:07:38.926
|
||||
Answer me!
|
||||
|
||||
64
|
||||
00:07:42.970 --> 00:07:44.000
|
||||
Proog...
|
||||
|
||||
65
|
||||
00:07:45.053 --> 00:07:46.985
|
||||
...you're a sick man!
|
||||
|
||||
66
|
||||
00:07:47.022 --> 00:07:48.918
|
||||
Stay away from me!
|
||||
|
||||
67
|
||||
00:07:52.052 --> 00:07:54.884
|
||||
No! Emo! It's a trap!
|
||||
|
||||
68
|
||||
00:07:55.135 --> 00:07:56.931
|
||||
Hah. it's a trap.
|
||||
|
||||
69
|
||||
00:07:56.968 --> 00:08:01.043
|
||||
At the left side you can see
|
||||
the hanging gardens of Babylon!
|
||||
|
||||
70
|
||||
00:08:01.967 --> 00:08:03.957
|
||||
How's that for a trap?
|
||||
|
||||
71
|
||||
00:08:05.050 --> 00:08:06.922
|
||||
No. Emo.
|
||||
|
||||
72
|
||||
00:08:09.008 --> 00:08:12.088
|
||||
At the right side you can see...
|
||||
...well guess what...
|
||||
|
||||
73
|
||||
00:08:12.924 --> 00:08:14.665
|
||||
...the colossus of Rhodes!
|
||||
|
||||
74
|
||||
00:08:15.132 --> 00:08:16.053
|
||||
No!
|
||||
|
||||
75
|
||||
00:08:16.090 --> 00:08:21.919
|
||||
The colossus of Rhodes
|
||||
and it is here just for you Proog.
|
||||
|
||||
76
|
||||
00:08:51.001 --> 00:08:52.923
|
||||
It is there...
|
||||
|
||||
77
|
||||
00:08:52.959 --> 00:08:56.040
|
||||
I'm telling you.
|
||||
Emo...
|
||||
|
||||
78
|
||||
00:08:57.000 --> 00:08:59.867
|
||||
...it is.
|
||||
@@ -1,326 +0,0 @@
|
||||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.042 --> 00:00:18.042
|
||||
左に見えるのは…
|
||||
|
||||
2
|
||||
00:00:18.750 --> 00:00:20.333
|
||||
右に見えるのは…
|
||||
|
||||
3
|
||||
00:00:20.417 --> 00:00:21.917
|
||||
…首刈り機
|
||||
|
||||
4
|
||||
00:00:22.000 --> 00:00:24.625
|
||||
すべて安全
|
||||
完璧に安全だ
|
||||
|
||||
5
|
||||
00:00:26.333 --> 00:00:27.333
|
||||
イーモ?
|
||||
|
||||
6
|
||||
00:00:28.875 --> 00:00:30.250
|
||||
危ない!
|
||||
|
||||
7
|
||||
00:00:47.125 --> 00:00:48.250
|
||||
ケガはないか?
|
||||
|
||||
8
|
||||
00:00:51.917 --> 00:00:53.917
|
||||
ええ、多分…
|
||||
あなたは?
|
||||
|
||||
9
|
||||
00:00:55.625 --> 00:00:57.125
|
||||
わしは平気だ
|
||||
|
||||
10
|
||||
00:00:57.583 --> 00:01:01.667
|
||||
起きてくれイーモ
|
||||
ここは危ない
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:03.667
|
||||
行こう
|
||||
|
||||
12
|
||||
00:01:03.750 --> 00:01:04.917
|
||||
どこに?
|
||||
|
||||
13
|
||||
00:01:05.875 --> 00:01:07.875
|
||||
すぐにわかるさ!
|
||||
|
||||
14
|
||||
00:01:16.167 --> 00:01:18.375
|
||||
イーモ、こっちだ
|
||||
|
||||
15
|
||||
00:01:34.958 --> 00:01:36.958
|
||||
ついて来るんだ!
|
||||
|
||||
16
|
||||
00:02:11.583 --> 00:02:12.792
|
||||
イーモ、早く!
|
||||
|
||||
17
|
||||
00:02:48.375 --> 00:02:50.083
|
||||
むやみにさわるな!
|
||||
|
||||
18
|
||||
00:02:50.750 --> 00:02:54.500
|
||||
僕はただ、電話に
|
||||
…出ようと
|
||||
|
||||
19
|
||||
00:02:55.000 --> 00:02:58.208
|
||||
イーモ、見るんだ…
|
||||
いや、聞いてくれ
|
||||
|
||||
20
|
||||
00:02:59.750 --> 00:03:02.292
|
||||
君は「聞き方」を知る必要がある
|
||||
|
||||
21
|
||||
00:03:03.625 --> 00:03:05.125
|
||||
これは遊びじゃない
|
||||
|
||||
22
|
||||
00:03:06.167 --> 00:03:10.417
|
||||
我々はここでは
|
||||
たやすく死ぬ
|
||||
|
||||
23
|
||||
00:03:11.208 --> 00:03:14.125
|
||||
機械の声を聞くんだ
|
||||
|
||||
24
|
||||
00:03:18.333 --> 00:03:22.417
|
||||
君の息づかいを聞くんだ
|
||||
|
||||
25
|
||||
00:04:27.208 --> 00:04:29.250
|
||||
そんなことして疲れない?
|
||||
|
||||
26
|
||||
00:04:29.583 --> 00:04:31.083
|
||||
疲れる?!
|
||||
|
||||
27
|
||||
00:04:31.750 --> 00:04:34.667
|
||||
この機械は非常に正確で
|
||||
|
||||
28
|
||||
00:04:35.500 --> 00:04:37.708
|
||||
一つ間違えば…
|
||||
|
||||
29
|
||||
00:04:37.833 --> 00:04:40.792
|
||||
…地面に落ちてバラバラだ
|
||||
|
||||
30
|
||||
00:04:41.042 --> 00:04:42.375
|
||||
え、でも―
|
||||
|
||||
31
|
||||
00:04:42.417 --> 00:04:46.542
|
||||
バラバラだぞ、イーモ!
|
||||
それでいいのか?
|
||||
|
||||
32
|
||||
00:04:48.083 --> 00:04:50.000
|
||||
バラバラで死ぬんだぞ?
|
||||
|
||||
33
|
||||
00:04:50.583 --> 00:04:52.250
|
||||
バラバラだ!
|
||||
|
||||
34
|
||||
00:05:41.833 --> 00:05:43.458
|
||||
イーモ、目を閉じるんだ
|
||||
|
||||
35
|
||||
00:05:44.917 --> 00:05:46.583
|
||||
なぜ?
|
||||
―早く!
|
||||
|
||||
36
|
||||
00:05:53.750 --> 00:05:56.042
|
||||
それでいい
|
||||
|
||||
37
|
||||
00:05:59.542 --> 00:06:03.792
|
||||
左に見えるものは何だ、イーモ?
|
||||
|
||||
38
|
||||
00:06:04.417 --> 00:06:06.000
|
||||
え…何も
|
||||
―本当か?
|
||||
|
||||
39
|
||||
00:06:06.333 --> 00:06:07.917
|
||||
全く何も
|
||||
|
||||
40
|
||||
00:06:08.042 --> 00:06:12.833
|
||||
では右は
|
||||
何か見えるか、イーモ?
|
||||
|
||||
41
|
||||
00:06:13.875 --> 00:06:16.917
|
||||
同じだよプルーグ、全く同じ…
|
||||
|
||||
42
|
||||
00:06:17.083 --> 00:06:18.583
|
||||
何もない!
|
||||
|
||||
43
|
||||
00:06:40.625 --> 00:06:43.208
|
||||
プルーグ!何か聞こえない?
|
||||
|
||||
44
|
||||
00:06:43.625 --> 00:06:45.042
|
||||
あそこに行かないか?
|
||||
|
||||
45
|
||||
00:06:45.208 --> 00:06:48.042
|
||||
あそこ?
|
||||
…安全じゃない
|
||||
|
||||
46
|
||||
00:06:49.917 --> 00:06:52.500
|
||||
でも…
|
||||
―本当に危ないぞ
|
||||
|
||||
47
|
||||
00:06:53.292 --> 00:06:54.792
|
||||
大丈夫だよ…
|
||||
|
||||
48
|
||||
00:06:54.833 --> 00:06:56.333
|
||||
だめだ
|
||||
|
||||
49
|
||||
00:06:57.667 --> 00:07:00.167
|
||||
だめだ!
|
||||
|
||||
50
|
||||
00:07:00.875 --> 00:07:03.750
|
||||
まだ続ける気か、イーモ?
|
||||
|
||||
51
|
||||
00:07:04.250 --> 00:07:05.917
|
||||
いいえ…
|
||||
|
||||
52
|
||||
00:07:09.458 --> 00:07:10.833
|
||||
イーモ?
|
||||
|
||||
53
|
||||
00:07:11.875 --> 00:07:13.542
|
||||
イーモ、なぜ…
|
||||
|
||||
54
|
||||
00:07:13.583 --> 00:07:14.458
|
||||
イーモ…
|
||||
|
||||
55
|
||||
00:07:14.500 --> 00:07:18.500
|
||||
…なぜここの美しさが
|
||||
見えない?
|
||||
|
||||
56
|
||||
00:07:18.833 --> 00:07:20.750
|
||||
仕組みがこんなに…
|
||||
|
||||
57
|
||||
00:07:20.875 --> 00:07:24.000
|
||||
こんなに完全なのに
|
||||
|
||||
58
|
||||
00:07:24.083 --> 00:07:27.417
|
||||
もういいよ!プルーグ!
|
||||
|
||||
59
|
||||
00:07:27.542 --> 00:07:30.333
|
||||
そこには何もないんだから
|
||||
|
||||
60
|
||||
00:07:31.500 --> 00:07:35.333
|
||||
なぜ命を「ない」物に
|
||||
ゆだねなきゃ?
|
||||
|
||||
61
|
||||
00:07:35.583 --> 00:07:37.125
|
||||
教えてくれないか?
|
||||
|
||||
62
|
||||
00:07:37.500 --> 00:07:39.167
|
||||
さあ!
|
||||
|
||||
63
|
||||
00:07:43.208 --> 00:07:44.583
|
||||
プルーグ…
|
||||
|
||||
64
|
||||
00:07:45.500 --> 00:07:47.333
|
||||
あなたは病気なんだ
|
||||
|
||||
65
|
||||
00:07:47.375 --> 00:07:49.208
|
||||
僕から離れてくれ
|
||||
|
||||
66
|
||||
00:07:52.583 --> 00:07:55.083
|
||||
いかん!イーモ!ワナだ!
|
||||
|
||||
67
|
||||
00:07:55.833 --> 00:07:57.167
|
||||
ワナだ? ふーん
|
||||
|
||||
68
|
||||
00:07:57.208 --> 00:08:01.750
|
||||
左に何が見える?
|
||||
バビロンの空中庭園!
|
||||
|
||||
69
|
||||
00:08:02.250 --> 00:08:04.292
|
||||
これがワナとでも?
|
||||
|
||||
70
|
||||
00:08:05.458 --> 00:08:07.125
|
||||
だめだ、イーモ
|
||||
|
||||
71
|
||||
00:08:09.417 --> 00:08:12.792
|
||||
右にあるのは…
|
||||
…すごい!…
|
||||
|
||||
72
|
||||
00:08:13.000 --> 00:08:14.750
|
||||
…ロードス島の巨像だ!
|
||||
|
||||
73
|
||||
00:08:15.833 --> 00:08:16.708
|
||||
やめろ!
|
||||
|
||||
74
|
||||
00:08:16.750 --> 00:08:22.167
|
||||
この巨像はあなたの物
|
||||
プルーグ、あなたのだよ
|
||||
|
||||
75
|
||||
00:08:51.333 --> 00:08:53.167
|
||||
いってるじゃないか…
|
||||
|
||||
76
|
||||
00:08:53.208 --> 00:08:55.500
|
||||
そこにあるって、イーモ…
|
||||
|
||||
77
|
||||
00:08:57.333 --> 00:09:00.000
|
||||
…あるって
|
||||
@@ -1,356 +0,0 @@
|
||||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:14.958 --> 00:00:17.833
|
||||
Слева мы видим...
|
||||
|
||||
2
|
||||
00:00:18.458 --> 00:00:20.208
|
||||
справа мы видим...
|
||||
|
||||
3
|
||||
00:00:20.333 --> 00:00:21.875
|
||||
...голово-клацов.
|
||||
|
||||
4
|
||||
00:00:22.000 --> 00:00:24.583
|
||||
всё в порядке.
|
||||
в полном порядке.
|
||||
|
||||
5
|
||||
00:00:26.333 --> 00:00:27.333
|
||||
Имо?
|
||||
|
||||
6
|
||||
00:00:28.833 --> 00:00:30.250
|
||||
Осторожно!
|
||||
|
||||
7
|
||||
00:00:47.125 --> 00:00:48.250
|
||||
Ты не ранен?
|
||||
|
||||
8
|
||||
00:00:51.875 --> 00:00:53.875
|
||||
Вроде нет...
|
||||
а ты?
|
||||
|
||||
9
|
||||
00:00:55.583 --> 00:00:57.125
|
||||
Я в порядке.
|
||||
|
||||
10
|
||||
00:00:57.542 --> 00:01:01.625
|
||||
Вставай.
|
||||
Имо. здесь не безопасно.
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:03.625
|
||||
Пойдём.
|
||||
|
||||
12
|
||||
00:01:03.708 --> 00:01:05.708
|
||||
Что дальше?
|
||||
|
||||
13
|
||||
00:01:05.833 --> 00:01:07.833
|
||||
Ты увидишь!
|
||||
|
||||
14
|
||||
00:01:08.000 --> 00:01:08.833
|
||||
Ты увидишь...
|
||||
|
||||
15
|
||||
00:01:16.167 --> 00:01:18.375
|
||||
Имо. сюда.
|
||||
|
||||
16
|
||||
00:01:34.917 --> 00:01:35.750
|
||||
За мной!
|
||||
|
||||
17
|
||||
00:02:11.542 --> 00:02:12.750
|
||||
Имо. быстрее!
|
||||
|
||||
18
|
||||
00:02:48.375 --> 00:02:50.083
|
||||
Ты не обращаешь внимания!
|
||||
|
||||
19
|
||||
00:02:50.708 --> 00:02:54.500
|
||||
Я только хотел ответить на ...
|
||||
...звонок.
|
||||
|
||||
20
|
||||
00:02:55.000 --> 00:02:58.208
|
||||
Имо. смотри.
|
||||
то есть слушай...
|
||||
|
||||
21
|
||||
00:02:59.708 --> 00:03:02.292
|
||||
Ты должен учиться слушать.
|
||||
|
||||
22
|
||||
00:03:03.250 --> 00:03:05.333
|
||||
Это не какая-нибудь игра.
|
||||
|
||||
23
|
||||
00:03:06.000 --> 00:03:08.833
|
||||
Ты. вернее мы. легко можем погибнуть здесь.
|
||||
|
||||
24
|
||||
00:03:10.000 --> 00:03:11.167
|
||||
Слушай...
|
||||
|
||||
25
|
||||
00:03:11.667 --> 00:03:14.125
|
||||
слушай звуки машины.
|
||||
|
||||
26
|
||||
00:03:18.333 --> 00:03:20.417
|
||||
Слушай своё дыхание.
|
||||
|
||||
27
|
||||
00:04:27.208 --> 00:04:29.250
|
||||
И не надоест тебе это?
|
||||
|
||||
28
|
||||
00:04:29.542 --> 00:04:31.083
|
||||
Надоест?!?
|
||||
|
||||
29
|
||||
00:04:31.708 --> 00:04:34.625
|
||||
Имо! Машина -
|
||||
она как часовой механизм.
|
||||
|
||||
30
|
||||
00:04:35.500 --> 00:04:37.667
|
||||
Одно движение не туда...
|
||||
|
||||
31
|
||||
00:04:37.792 --> 00:04:39.750
|
||||
...и тебя размелют в месиво!
|
||||
|
||||
32
|
||||
00:04:41.042 --> 00:04:42.375
|
||||
А разве это не -
|
||||
|
||||
33
|
||||
00:04:42.417 --> 00:04:46.500
|
||||
Месиво. Имо!
|
||||
ты этого хочешь? месиво?
|
||||
|
||||
34
|
||||
00:04:48.083 --> 00:04:50.000
|
||||
Имо. твоя цель в жизни?
|
||||
|
||||
35
|
||||
00:04:50.542 --> 00:04:52.250
|
||||
Месиво!
|
||||
|
||||
36
|
||||
00:05:41.792 --> 00:05:43.458
|
||||
Имо. закрой глаза.
|
||||
|
||||
37
|
||||
00:05:44.875 --> 00:05:46.542
|
||||
Зачем?
|
||||
- Ну же!
|
||||
|
||||
38
|
||||
00:05:51.500 --> 00:05:52.333
|
||||
Ладно.
|
||||
|
||||
39
|
||||
00:05:53.708 --> 00:05:56.042
|
||||
Хорошо.
|
||||
|
||||
40
|
||||
00:05:59.500 --> 00:06:02.750
|
||||
Что ты видишь слева от себя. Имо?
|
||||
|
||||
41
|
||||
00:06:04.417 --> 00:06:06.000
|
||||
Ничего.
|
||||
- Точно?
|
||||
|
||||
42
|
||||
00:06:06.333 --> 00:06:07.875
|
||||
да. совсем ничего.
|
||||
|
||||
43
|
||||
00:06:08.042 --> 00:06:12.708
|
||||
А справа от себя.
|
||||
что ты видишь справа от себя. Имо?
|
||||
|
||||
44
|
||||
00:06:13.833 --> 00:06:16.875
|
||||
Да то же Пруг. в точности то же...
|
||||
|
||||
45
|
||||
00:06:17.042 --> 00:06:18.500
|
||||
Ничего!
|
||||
|
||||
46
|
||||
00:06:18.667 --> 00:06:19.500
|
||||
Прекрасно...
|
||||
|
||||
47
|
||||
00:06:40.583 --> 00:06:42.917
|
||||
Прислушайся. Пруг! Ты слышишь это?
|
||||
|
||||
48
|
||||
00:06:43.583 --> 00:06:45.042
|
||||
Может. мы пойдём туда?
|
||||
|
||||
49
|
||||
00:06:45.208 --> 00:06:48.042
|
||||
Туда?
|
||||
Это не безопасно. Имо.
|
||||
|
||||
50
|
||||
00:06:49.875 --> 00:06:52.500
|
||||
Но...
|
||||
- Поверь мне. это так.
|
||||
|
||||
51
|
||||
00:06:53.292 --> 00:06:54.750
|
||||
Может я бы ...
|
||||
|
||||
52
|
||||
00:06:54.792 --> 00:06:56.333
|
||||
Нет.
|
||||
|
||||
53
|
||||
00:06:57.625 --> 00:06:59.583
|
||||
- Но...
|
||||
- НЕТ!
|
||||
|
||||
54
|
||||
00:06:59.708 --> 00:07:00.833
|
||||
Нет!
|
||||
|
||||
55
|
||||
00:07:00.833 --> 00:07:03.708
|
||||
Ещё вопросы. Имо?
|
||||
|
||||
56
|
||||
00:07:04.250 --> 00:07:05.875
|
||||
Нет.
|
||||
|
||||
57
|
||||
00:07:09.458 --> 00:07:10.792
|
||||
Имо?
|
||||
|
||||
58
|
||||
00:07:11.833 --> 00:07:13.500
|
||||
Имо. почему...
|
||||
|
||||
59
|
||||
00:07:13.542 --> 00:07:14.458
|
||||
Имо...
|
||||
|
||||
60
|
||||
00:07:14.500 --> 00:07:18.500
|
||||
...почему? почему ты не видишь
|
||||
красоты этого места?
|
||||
|
||||
61
|
||||
00:07:18.792 --> 00:07:20.708
|
||||
То как оно работает.
|
||||
|
||||
62
|
||||
00:07:20.833 --> 00:07:24.000
|
||||
Как совершенно оно.
|
||||
|
||||
63
|
||||
00:07:24.083 --> 00:07:27.417
|
||||
Нет. Пруг. я не вижу.
|
||||
|
||||
64
|
||||
00:07:27.500 --> 00:07:30.333
|
||||
Я не вижу. потому что здесь ничего нет.
|
||||
|
||||
65
|
||||
00:07:31.375 --> 00:07:35.333
|
||||
И почему я должен доверять свою жизнь
|
||||
чему-то. чего здесь нет?
|
||||
|
||||
66
|
||||
00:07:35.542 --> 00:07:37.125
|
||||
это ты мне можешь сказать?
|
||||
|
||||
67
|
||||
00:07:37.500 --> 00:07:39.167
|
||||
Ответь мне!
|
||||
|
||||
68
|
||||
00:07:43.208 --> 00:07:44.542
|
||||
Пруг...
|
||||
|
||||
69
|
||||
00:07:45.500 --> 00:07:47.333
|
||||
Ты просто больной!
|
||||
|
||||
70
|
||||
00:07:47.375 --> 00:07:48.500
|
||||
Отстань от меня.
|
||||
|
||||
71
|
||||
00:07:48.625 --> 00:07:49.917
|
||||
Имо...
|
||||
|
||||
72
|
||||
00:07:52.542 --> 00:07:55.083
|
||||
Нет! Имо! Это ловушка!
|
||||
|
||||
73
|
||||
00:07:55.792 --> 00:07:57.167
|
||||
Это ловушка!
|
||||
|
||||
74
|
||||
00:07:57.208 --> 00:08:01.708
|
||||
Слева от себя вы можете увидеть
|
||||
Висящие сады Семирамиды!
|
||||
|
||||
75
|
||||
00:08:02.250 --> 00:08:04.292
|
||||
Сойдёт за ловушку?
|
||||
|
||||
76
|
||||
00:08:05.458 --> 00:08:07.125
|
||||
Нет. Имо.
|
||||
|
||||
77
|
||||
00:08:09.417 --> 00:08:12.750
|
||||
Справа от себя вы можете увидеть...
|
||||
...угадай кого...
|
||||
|
||||
78
|
||||
00:08:13.000 --> 00:08:14.708
|
||||
...Колосса Родосского!
|
||||
|
||||
79
|
||||
00:08:15.500 --> 00:08:16.625
|
||||
Нет!
|
||||
|
||||
80
|
||||
00:08:16.667 --> 00:08:21.125
|
||||
Колосс Родосский!
|
||||
И он здесь специально для тебя. Пруг.
|
||||
|
||||
81
|
||||
00:08:21.167 --> 00:08:22.208
|
||||
Специально для тебя...
|
||||
|
||||
82
|
||||
00:08:51.333 --> 00:08:53.167
|
||||
Она здесь есть!
|
||||
|
||||
83
|
||||
00:08:53.208 --> 00:08:55.500
|
||||
Говорю тебе.
|
||||
Имо...
|
||||
|
||||
84
|
||||
00:08:57.333 --> 00:09:00.000
|
||||
...она есть... есть...
|
||||
@@ -1,349 +0,0 @@
|
||||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.042 --> 00:00:18.250
|
||||
Till vänster kan vi se...
|
||||
Ser vi...
|
||||
|
||||
2
|
||||
00:00:18.708 --> 00:00:20.333
|
||||
Till höger ser vi...
|
||||
|
||||
3
|
||||
00:00:20.417 --> 00:00:21.958
|
||||
...huvudkaparna.
|
||||
|
||||
4
|
||||
00:00:22.000 --> 00:00:24.792
|
||||
Allt är säkert.
|
||||
alldeles ofarligt.
|
||||
|
||||
5
|
||||
00:00:24.917 --> 00:00:26.833
|
||||
Emo?
|
||||
|
||||
6
|
||||
00:00:28.750 --> 00:00:30.167
|
||||
Se upp!
|
||||
|
||||
7
|
||||
00:00:46.708 --> 00:00:48.750
|
||||
Är du skadad?
|
||||
|
||||
8
|
||||
00:00:51.875 --> 00:00:54.458
|
||||
Jag tror inte det...
|
||||
Är du?
|
||||
|
||||
9
|
||||
00:00:55.292 --> 00:00:57.333
|
||||
Jag är ok.
|
||||
|
||||
10
|
||||
00:00:57.542 --> 00:01:01.625
|
||||
Res dig upp Emo.
|
||||
Det är inte säkert här.
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:03.625
|
||||
Kom så går vi.
|
||||
|
||||
12
|
||||
00:01:03.708 --> 00:01:05.708
|
||||
Vad nu då?
|
||||
|
||||
13
|
||||
00:01:05.833 --> 00:01:07.833
|
||||
Du får se...
|
||||
|
||||
14
|
||||
00:01:08.042 --> 00:01:10.417
|
||||
Du får se.
|
||||
|
||||
15
|
||||
00:01:15.958 --> 00:01:18.375
|
||||
Emo. den här vägen.
|
||||
|
||||
16
|
||||
00:01:34.417 --> 00:01:36.750
|
||||
Följ efter mig!
|
||||
|
||||
17
|
||||
00:02:11.250 --> 00:02:13.250
|
||||
Skynda dig. Emo!
|
||||
|
||||
18
|
||||
00:02:48.375 --> 00:02:50.583
|
||||
Du är inte uppmärksam!
|
||||
|
||||
19
|
||||
00:02:50.708 --> 00:02:54.500
|
||||
Jag vill bara svara...
|
||||
... i telefonen.
|
||||
|
||||
20
|
||||
00:02:54.500 --> 00:02:58.208
|
||||
Emo. se här...
|
||||
Lyssna menar jag.
|
||||
|
||||
21
|
||||
00:02:59.708 --> 00:03:02.292
|
||||
Du måste lära dig att lyssna.
|
||||
|
||||
22
|
||||
00:03:03.292 --> 00:03:05.208
|
||||
Det här är ingen lek.
|
||||
|
||||
23
|
||||
00:03:05.250 --> 00:03:08.917
|
||||
Du... Jag menar vi.
|
||||
vi skulle kunna dö här ute.
|
||||
|
||||
24
|
||||
00:03:09.917 --> 00:03:11.417
|
||||
Lyssna...
|
||||
|
||||
25
|
||||
00:03:11.708 --> 00:03:14.833
|
||||
Lyssna på ljuden från maskinen.
|
||||
|
||||
26
|
||||
00:03:18.125 --> 00:03:21.417
|
||||
Lyssna på dina andetag.
|
||||
|
||||
27
|
||||
00:04:26.625 --> 00:04:29.250
|
||||
Tröttnar du aldrig på det här?
|
||||
|
||||
28
|
||||
00:04:29.542 --> 00:04:31.083
|
||||
Tröttnar!?
|
||||
|
||||
29
|
||||
00:04:31.208 --> 00:04:33.458
|
||||
Emo. maskinen är som...
|
||||
|
||||
30
|
||||
00:04:33.458 --> 00:04:35.333
|
||||
Som ett urverk.
|
||||
|
||||
31
|
||||
00:04:35.417 --> 00:04:37.167
|
||||
Ett felsteg...
|
||||
|
||||
32
|
||||
00:04:37.208 --> 00:04:39.750
|
||||
...och du blir krossad.
|
||||
|
||||
33
|
||||
00:04:41.042 --> 00:04:42.292
|
||||
Men är det inte -
|
||||
|
||||
34
|
||||
00:04:42.292 --> 00:04:47.000
|
||||
Krossad. Emo!
|
||||
Är det vad du vill bli? Krossad till mos?
|
||||
|
||||
35
|
||||
00:04:47.500 --> 00:04:50.542
|
||||
Emo. är det ditt mål i livet?
|
||||
|
||||
36
|
||||
00:04:50.667 --> 00:04:53.250
|
||||
Att bli mos!?
|
||||
|
||||
37
|
||||
00:05:41.375 --> 00:05:43.458
|
||||
Emo. blunda.
|
||||
|
||||
38
|
||||
00:05:44.375 --> 00:05:46.542
|
||||
Varför då?
|
||||
- Blunda!
|
||||
|
||||
39
|
||||
00:05:51.292 --> 00:05:55.042
|
||||
Ok.
|
||||
- Bra.
|
||||
|
||||
40
|
||||
00:05:59.500 --> 00:06:02.750
|
||||
Vad ser du till vänster om dig Emo?
|
||||
|
||||
41
|
||||
00:06:04.125 --> 00:06:06.292
|
||||
Ingenting.
|
||||
- Säker?
|
||||
|
||||
42
|
||||
00:06:06.333 --> 00:06:07.958
|
||||
Ingenting alls.
|
||||
|
||||
43
|
||||
00:06:08.042 --> 00:06:12.625
|
||||
Jaså. och till höger om dig...
|
||||
Vad ser du där. Emo?
|
||||
|
||||
44
|
||||
00:06:13.750 --> 00:06:15.583
|
||||
Samma där Proog...
|
||||
|
||||
45
|
||||
00:06:15.583 --> 00:06:18.083
|
||||
Exakt samma där. ingenting!
|
||||
|
||||
46
|
||||
00:06:18.083 --> 00:06:19.667
|
||||
Perfekt.
|
||||
|
||||
47
|
||||
00:06:40.500 --> 00:06:42.917
|
||||
Lyssna Proog! Hör du?
|
||||
|
||||
48
|
||||
00:06:43.500 --> 00:06:45.125
|
||||
Kan vi gå dit?
|
||||
|
||||
49
|
||||
00:06:45.208 --> 00:06:48.125
|
||||
Gå dit?
|
||||
Det är inte tryggt.
|
||||
|
||||
50
|
||||
00:06:49.583 --> 00:06:52.583
|
||||
Men. men...
|
||||
- Tro mig. det inte säkert.
|
||||
|
||||
51
|
||||
00:06:53.000 --> 00:06:54.292
|
||||
Men kanske om jag -
|
||||
|
||||
52
|
||||
00:06:54.292 --> 00:06:56.333
|
||||
Nej.
|
||||
|
||||
53
|
||||
00:06:57.208 --> 00:07:00.167
|
||||
Men -
|
||||
- Nej. NEJ!
|
||||
|
||||
54
|
||||
00:07:00.917 --> 00:07:03.792
|
||||
Några fler frågor Emo?
|
||||
|
||||
55
|
||||
00:07:04.250 --> 00:07:05.875
|
||||
Nej.
|
||||
|
||||
56
|
||||
00:07:09.542 --> 00:07:11.375
|
||||
Emo?
|
||||
- Ja?
|
||||
|
||||
57
|
||||
00:07:11.542 --> 00:07:15.667
|
||||
Emo. varför...
|
||||
|
||||
58
|
||||
00:07:15.792 --> 00:07:18.583
|
||||
Varför kan du inte se skönheten i det här?
|
||||
|
||||
59
|
||||
00:07:18.792 --> 00:07:21.708
|
||||
Hur det fungerar.
|
||||
|
||||
60
|
||||
00:07:21.833 --> 00:07:24.000
|
||||
Hur perfekt det är.
|
||||
|
||||
61
|
||||
00:07:24.083 --> 00:07:27.333
|
||||
Nej Proog. jag kan inte se det.
|
||||
|
||||
62
|
||||
00:07:27.333 --> 00:07:30.333
|
||||
Jag ser det inte. för det finns inget där.
|
||||
|
||||
63
|
||||
00:07:31.292 --> 00:07:35.333
|
||||
Och varför skulle jag lägga mitt liv
|
||||
i händerna på något som inte finns?
|
||||
|
||||
64
|
||||
00:07:35.333 --> 00:07:37.083
|
||||
Kan du berätta det för mig?
|
||||
- Emo...
|
||||
|
||||
65
|
||||
00:07:37.083 --> 00:07:39.167
|
||||
Svara mig!
|
||||
|
||||
66
|
||||
00:07:43.500 --> 00:07:45.208
|
||||
Proog...
|
||||
|
||||
67
|
||||
00:07:45.208 --> 00:07:47.083
|
||||
Du är inte frisk!
|
||||
|
||||
68
|
||||
00:07:47.167 --> 00:07:49.292
|
||||
Håll dig borta från mig!
|
||||
|
||||
69
|
||||
00:07:52.292 --> 00:07:55.083
|
||||
Nej! Emo!
|
||||
Det är en fälla!
|
||||
|
||||
70
|
||||
00:07:55.375 --> 00:07:57.208
|
||||
Heh. det är en fälla.
|
||||
|
||||
71
|
||||
00:07:57.208 --> 00:08:01.708
|
||||
På vänster sida ser vi...
|
||||
Babylons hängande trädgårdar!
|
||||
|
||||
72
|
||||
00:08:01.958 --> 00:08:04.000
|
||||
Vad sägs om den fällan?
|
||||
|
||||
73
|
||||
00:08:05.458 --> 00:08:07.333
|
||||
Nej. Emo.
|
||||
|
||||
74
|
||||
00:08:08.917 --> 00:08:12.667
|
||||
Till höger ser vi...
|
||||
Gissa!
|
||||
|
||||
75
|
||||
00:08:12.750 --> 00:08:15.125
|
||||
Rhodos koloss!
|
||||
|
||||
76
|
||||
00:08:15.375 --> 00:08:16.500
|
||||
Nej!
|
||||
|
||||
77
|
||||
00:08:16.500 --> 00:08:20.250
|
||||
Kolossen på Rhodos!
|
||||
Och den är här för din skull. Proog...
|
||||
|
||||
78
|
||||
00:08:20.250 --> 00:08:23.250
|
||||
Bara för din skull.
|
||||
|
||||
79
|
||||
00:08:50.917 --> 00:08:53.250
|
||||
Den är där...
|
||||
|
||||
80
|
||||
00:08:53.625 --> 00:08:56.417
|
||||
Tro mig.
|
||||
Emo...
|
||||
|
||||
81
|
||||
00:08:57.000 --> 00:09:00.000
|
||||
Det är den.
|
||||
Det är den...
|
||||
@@ -1,44 +0,0 @@
|
||||
WEBVTT
|
||||
|
||||
NOTE Created by Owen Edwards 2015. http://creativecommons.org/licenses/by/2.5/
|
||||
NOTE Based on 'finalbreakdown.rtf', part of the prepoduction notes, which are:
|
||||
NOTE (c) Copyright 2006, Blender Foundation /
|
||||
NOTE Netherlands Media Art Institute /
|
||||
NOTE www.elephantsdream.org
|
||||
|
||||
1
|
||||
00:00:00.000 --> 00:00:27.500
|
||||
Prologue
|
||||
|
||||
2
|
||||
00:00:27.500 --> 00:01:10.000
|
||||
Switchboard trap
|
||||
|
||||
3
|
||||
00:01:10.000 --> 00:03:25.000
|
||||
Telephone/Lecture
|
||||
|
||||
4
|
||||
00:03:25.000 --> 00:04:52.000
|
||||
Typewriter
|
||||
|
||||
5
|
||||
00:04:52.000 --> 00:06:19.500
|
||||
Proog shows Emo stuff
|
||||
|
||||
6
|
||||
00:06:19.500 --> 00:07:09.000
|
||||
Which way
|
||||
|
||||
7
|
||||
00:07:09.000 --> 00:07:45.000
|
||||
Emo flips out
|
||||
|
||||
8
|
||||
00:07:45.000 --> 00:09:25.000
|
||||
Emo creates
|
||||
|
||||
9
|
||||
00:09:25.000 --> 00:10:53.000
|
||||
Closing credits
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
WEBVTT
|
||||
License: CC BY 4.0 http://creativecommons.org/licenses/by/4.0/
|
||||
Author: Silvia Pfeiffer
|
||||
|
||||
1
|
||||
00:00:00.000 --> 00:00:05.000
|
||||
The orange open movie project presents
|
||||
|
||||
2
|
||||
00:00:05.010 --> 00:00:12.000
|
||||
Introductory titles are showing on the background of a water pool with fishes swimming and mechanical objects lying on a stone floor.
|
||||
|
||||
3
|
||||
00:00:12.010 --> 00:00:14.800
|
||||
elephants dream
|
||||
|
||||
4
|
||||
00:00:26.100 --> 00:00:28.206
|
||||
Two people stand on a small bridge.
|
||||
|
||||
5
|
||||
00:00:30.010 --> 00:00:40.000
|
||||
The old man, Proog, shoves the younger and less experienced Emo on the ground to save him from being mowed down by a barrage of jack plugs that whir back and forth between the two massive switch-board-like walls.
|
||||
|
||||
6
|
||||
00:00:40.000 --> 00:00:47.000
|
||||
The plugs are oblivious of the two, endlessly channeling streams of bizarre sounds and data.
|
||||
|
||||
7
|
||||
00:00:48.494 --> 00:00:51.994
|
||||
Emo sits on the bridge and checks his limbs.
|
||||
|
||||
8
|
||||
00:01:09.150 --> 00:01:16.030
|
||||
After the squealing plugs move on, Proog makes sure that Emo is unharmed and urges him onwards through a crack in one of the plug-walls.
|
||||
|
||||
9
|
||||
00:01:18.050 --> 00:01:24.000
|
||||
They walk through the narrow hall into a massive room that fades away into blackness on all sides.
|
||||
|
||||
10
|
||||
00:01:24.050 --> 00:01:34.200
|
||||
Only one path is visible, suspended in mid-air that runs between thousands of dangling electric cables on which sit crowds of robin-like robotic birds.
|
||||
|
||||
11
|
||||
00:01:36.000 --> 00:01:40.000
|
||||
As Proog and Emo enter the room, the birds begin to wake up and notice them.
|
||||
|
||||
12
|
||||
00:01:42.000 --> 00:01:50.000
|
||||
Realizing the danger, Proog grabs Emo by the arm.
|
||||
|
||||
13
|
||||
00:01:50.050 --> 00:02:00.000
|
||||
They run along the increasingly bizarre path as the birds begin to swarm.
|
||||
|
||||
14
|
||||
00:02:00.050 --> 00:02:11.000
|
||||
All sound is blocked out by the birds which are making the same noises as the jack-plugs, garbled screaming and obscure sentences and static.
|
||||
|
||||
15
|
||||
00:02:12.600 --> 00:02:17.000
|
||||
The path dead-ends, stopping in the middle of no-where above the infinite drop.
|
||||
|
||||
16
|
||||
00:02:17.600 --> 00:02:22.000
|
||||
Proog turns around as the birds reach them and begin to dive-bomb at them.
|
||||
|
||||
17
|
||||
00:02:22.600 --> 00:02:28.000
|
||||
At the last moment, Proog takes out an old candlestick phone and the birds dive into the speaker piece.
|
||||
|
||||
18
|
||||
00:02:28.600 --> 00:02:31.000
|
||||
The screen cuts to black.
|
||||
|
||||
19
|
||||
00:02:31.600 --> 00:02:38.000
|
||||
In the next scene, Proog stands at one end of a room, suspiciously watching what is probably the same candlestick phone, which is ringing.
|
||||
|
||||
20
|
||||
00:02:38.500 --> 00:02:41.000
|
||||
Emo watches from the other side of the room.
|
||||
|
||||
21
|
||||
00:02:41.500 --> 00:02:43.000
|
||||
The phone continues to ring.
|
||||
|
||||
22
|
||||
00:02:43.500 --> 00:02:48.000
|
||||
After a while Emo approaches it to answer it, but Proog slaps his hand away.
|
||||
|
||||
23
|
||||
00:02:57.972 --> 00:02:59.100
|
||||
Proog takes the ear-piece off the hook.
|
||||
|
||||
24
|
||||
00:03:13.500 --> 00:03:18.054
|
||||
The phone speaker revealed a mass of clawed, fleshy polyps which scream and gibber obscenely.
|
||||
|
||||
25
|
||||
00:03:25.000 --> 00:03:33.000
|
||||
There is a solemn silence as Emo looks around the room and the technical objects therein.
|
||||
|
||||
26
|
||||
00:03:38.000 --> 00:03:44.000
|
||||
Emo laughs disbelievingly and Proog walks away.
|
||||
|
||||
27
|
||||
00:03:46.000 --> 00:03:54.000
|
||||
In the next scene, the two enter another massive black room.
|
||||
|
||||
28
|
||||
00:03:54.500 --> 00:04:04.000
|
||||
There is no path, the entry platform is the only structure that seems to be there except for another exit, lit distantly at the far side.
|
||||
|
||||
29
|
||||
00:04:04.500 --> 00:04:14.000
|
||||
Proog takes a step forward into the void, and his feet are suddenly caught by giant typewriter arms that rocket up out of the blackness to catch his feet as he dances across mid-air.
|
||||
|
||||
30
|
||||
00:04:14.500 --> 00:04:22.000
|
||||
Emo follows Proog with somewhat less enthusiasm as the older man leads the way.
|
||||
|
||||
31
|
||||
00:04:52.000 --> 00:04:58.000
|
||||
They reach the end of the room and go through a hall into a small compartment.
|
||||
|
||||
32
|
||||
00:05:02.000 --> 00:05:06.000
|
||||
Proog presses a button, and the door shuts.
|
||||
|
||||
33
|
||||
00:05:06.500 --> 00:05:09.000
|
||||
It is an elevator.
|
||||
|
||||
34
|
||||
00:05:09.500 --> 00:05:24.000
|
||||
The elevator lurches suddenly as it is grabbed by a giant mechanical arm and thrown upwards, rushing up through an ever-widening tunnel.
|
||||
|
||||
35
|
||||
00:05:26.500 --> 00:05:32.000
|
||||
When it begins to slow down, another arm grabs the capsule and throws it even further up.
|
||||
|
||||
36
|
||||
00:05:32.500 --> 00:05:40.000
|
||||
As it moves up, the walls unlock and fall away, leaving only the floor with the two on it, rushing higher and higher.
|
||||
|
||||
37
|
||||
00:05:54.500 --> 00:05:59.000
|
||||
They exit the tunnel into a black sky and the platform reaches the peak of its arc.
|
||||
|
||||
38
|
||||
00:06:19.500 --> 00:06:26.000
|
||||
The elevator begins to drop down another shaft, coming to rest as it slams into the floor of another room and bringing the two to a level stop.
|
||||
|
||||
39
|
||||
00:06:26.500 --> 00:06:28.000
|
||||
A camera briefly illumiates.
|
||||
|
||||
40
|
||||
00:06:28.010 --> 00:06:34.000
|
||||
They are in a large, dingy room filled with strange, generator-like devices and dotted with boxy holographic projectors.
|
||||
|
||||
41
|
||||
00:06:34.500 --> 00:06:38.000
|
||||
One of them is projecting a portion of wall with a door in it right beside them.
|
||||
|
||||
42
|
||||
00:06:38.500 --> 00:06:40.000
|
||||
The door seems harmless enough.
|
||||
|
||||
43
|
||||
00:06:42.800 --> 00:06:45.100
|
||||
From behind the door comes light music.
|
||||
|
||||
44
|
||||
00:06:56.000 --> 00:07:00.100
|
||||
Proog presses a button on his cane, which changes the holograph to another wall.
|
||||
|
||||
45
|
||||
00:07:05.100 --> 00:07:11.000
|
||||
Proog finishes the wall, and boxes them into a Safe Room, out of the view of anything outside.
|
||||
|
||||
46
|
||||
00:07:39.000 --> 00:07:42.500
|
||||
Proog slaps him, trying to bring him to his senses.
|
||||
|
||||
47
|
||||
00:07:45.000 --> 00:07:52.000
|
||||
Emo storms away down the length of the room towards a wall he apparently cannot see and the wall begins to move, extending the length of the room.
|
||||
|
||||
48
|
||||
00:08:00.000 --> 00:08:07.000
|
||||
The walls begin to discolour and mechanical roots start tearing through the walls to his left.
|
||||
|
||||
49
|
||||
00:08:07.010 --> 00:08:09.000
|
||||
The roots move forwards toward Proog.
|
||||
|
||||
50
|
||||
00:08:22.000 --> 00:08:31.000
|
||||
The rest of the safety wall crumples away as a pair of massive hands heave out of the ground and begin to attack.
|
||||
|
||||
51
|
||||
00:08:31.010 --> 00:08:37.000
|
||||
Proog is knocked down by the shockwave, while Emo turns and begins to walk away, waving his finger around his temple in the 'crazy' sign.
|
||||
|
||||
52
|
||||
00:08:37.010 --> 00:08:44.000
|
||||
In a last effort, Proog extricates himself from the tentacle roots, and cracks Emo over the back of the head with his cane.
|
||||
|
||||
53
|
||||
00:08:44.500 --> 00:08:51.000
|
||||
As Emo collapses, everything falls away, and Proog and Emo are left in one tiny patch of light in the middle of blackness.
|
||||
|
||||
54
|
||||
00:09:00.000 --> 00:09:20.000
|
||||
The scene fades to black while panning over a pile of tentacle roots lying on the ground.
|
||||
|
||||
55
|
||||
00:09:26.000 --> 00:09:28.000
|
||||
Credits begin:
|
||||
|
||||
56
|
||||
00:09:28.500 --> 00:09:35.000
|
||||
Orange Open Movie Team
|
||||
Director: Bassum Kurdali
|
||||
Art Director: Andreas Goralczyk
|
||||
|
||||
57
|
||||
00:09:35.500 --> 00:09:39.000
|
||||
Music and Sound Design: Jan Morgenstern
|
||||
|
||||
58
|
||||
00:09:39.500 --> 00:09:44.000
|
||||
Emo: Cas Jansen
|
||||
Proog: Tygo Gernandt
|
||||
|
||||
59
|
||||
00:09:44.500 --> 00:09:50.000
|
||||
Screenplay: Pepijn Zwanenberg
|
||||
Original Concept & Scenario: Andreas Goralczyk, Bassam Kurdali, Ton Roosendaal
|
||||
|
||||
60
|
||||
00:09:50.500 --> 00:10:24.000
|
||||
More people for
|
||||
Additional Artwork and Animation
|
||||
Texture Photography
|
||||
Software Development
|
||||
3D Modelling, Animation, Rendering, Compiling Software
|
||||
Special Thanks to Open Source Projects
|
||||
Rendering Services Provided
|
||||
Hardware Sponsored
|
||||
Casting
|
||||
Sound FX, Foley, Dialogue Editing, Audio Mix and Post
|
||||
Voice Recording
|
||||
HDCam conversion
|
||||
Netherlands Media Art Institute Staff
|
||||
Blender Foundation Staff
|
||||
|
||||
61
|
||||
00:10:24.500 --> 00:10:30.000
|
||||
Many Thanks to our Donation and DVD sponsors
|
||||
|
||||
62
|
||||
00:10:30.500 --> 00:10:47.000
|
||||
Elephants Dream has been realised with financial support from
|
||||
The Netherlands Film Fund
|
||||
Mondriaan Foundation
|
||||
VSBfonds
|
||||
Uni-Verse / EU Sixth Framework Programme
|
||||
|
||||
63
|
||||
00:10:47.500 --> 00:10:53.000
|
||||
Produced By
|
||||
Ton Roosendaal
|
||||
Copyright 2006
|
||||
Netherlands Media Art Institute / Montevideo
|
||||
Blender Foundation
|
||||
@@ -1,41 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<title>Video.js Text Descriptions, Chapters & Captions Example</title>
|
||||
|
||||
<link href="https://vjs.zencdn.net/7.0/video-js.min.css" rel="stylesheet">
|
||||
<script src="https://vjs.zencdn.net/7.0/video.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NOTE: we have to disable native Text Track support for the HTML5 tech,
|
||||
since even HTML5 video players with native Text Track support
|
||||
don't currently support 'description' text tracks in any
|
||||
useful way! Currently this means that iOS will not display
|
||||
ANY text tracks -->
|
||||
<video id="example_video_1" class="video-js" controls preload="none" width="640" height="360"
|
||||
data-setup='{ "html5" : { "nativeTextTracks" : false } }'
|
||||
poster="http://d2zihajmogu5jn.cloudfront.net/elephantsdream/poster.png">
|
||||
|
||||
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.mp4" type="video/mp4">
|
||||
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.ogg" type="video/ogg">
|
||||
|
||||
<track kind="captions" src="captions.en.vtt" srclang="en" label="English" default>
|
||||
<track kind="captions" src="captions.sv.vtt" srclang="sv" label="Swedish">
|
||||
<track kind="captions" src="captions.ru.vtt" srclang="ru" label="Russian">
|
||||
<track kind="captions" src="captions.ja.vtt" srclang="ja" label="Japanese">
|
||||
<track kind="captions" src="captions.ar.vtt" srclang="ar" label="Arabic">
|
||||
|
||||
<track kind="descriptions" src="descriptions.en.vtt" srclang="en" label="English">
|
||||
|
||||
<track kind="chapters" src="chapters.en.vtt" srclang="en" label="English">
|
||||
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Index of video.js examples</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Index of video.js examples</h1>
|
||||
<ul>
|
||||
<li><a href="simple-embed">Video.js HTML5 video player simple example</a></li>
|
||||
<li><a href="elephantsdream">Elephants Dream video with text descriptions, chapters & captions example</a></li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,41 +0,0 @@
|
||||
WEBVTT
|
||||
|
||||
00:00.700 --> 00:04.110
|
||||
Captions describe all relevant audio for the hearing impaired.
|
||||
[ Heroic music playing for a seagull ]
|
||||
|
||||
00:04.500 --> 00:05.000
|
||||
[ Splash!!! ]
|
||||
|
||||
00:05.100 --> 00:06.000
|
||||
[ Sploosh!!! ]
|
||||
|
||||
00:08.000 --> 00:09.225
|
||||
[ Splash...splash...splash splash splash ]
|
||||
|
||||
00:10.525 --> 00:11.255
|
||||
[ Splash, Sploosh again ]
|
||||
|
||||
00:13.500 --> 00:14.984
|
||||
Dolphin: eeeEEEEEeeee!
|
||||
|
||||
00:14.984 --> 00:16.984
|
||||
Dolphin: Squawk! eeeEEE?
|
||||
|
||||
00:25.000 --> 00:28.284
|
||||
[ A whole ton of splashes ]
|
||||
|
||||
00:29.500 --> 00:31.000
|
||||
Mine. Mine. Mine.
|
||||
|
||||
00:34.300 --> 00:36.000
|
||||
Shark: Chomp
|
||||
|
||||
00:36.800 --> 00:37.900
|
||||
Shark: CHOMP!!!
|
||||
|
||||
00:37.861 --> 00:41.193
|
||||
EEEEEEOOOOOOOOOOWHALENOISE
|
||||
|
||||
00:42.593 --> 00:45.611
|
||||
[ BIG SPLASH ]
|
||||
@@ -1,23 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<title>Video.js | HTML5 Video Player</title>
|
||||
<link href="http://vjs.zencdn.net/7.0/video-js.min.css" rel="stylesheet">
|
||||
<script src="http://vjs.zencdn.net/7.0/video.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<video id="example_video_1" class="video-js" controls preload="none" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png" data-setup="{}">
|
||||
<source src="https://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<source src="https://vjs.zencdn.net/v/oceans.webm" type="video/webm">
|
||||
<source src="https://vjs.zencdn.net/v/oceans.ogv" type="video/ogg">
|
||||
<track kind="captions" src="../shared/example-captions.vtt" srclang="en" label="English">
|
||||
<track kind="subtitles" src="../shared/example-captions.vtt" srclang="en" label="English">
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,29 +0,0 @@
|
||||
# [Video.js][vjs-website] API Documentation
|
||||
|
||||
## Generated API docs
|
||||
|
||||
These [API docs][api] at [docs.videojs.com][vjs-docs] are automatically generated from the jsdoc comments in the code of the `main` branch of the [Video.js repository][vjs-gh]. You'll find specific details about functions, properties, and events.
|
||||
|
||||
The most useful API doc to start with is usually the [Player][api-player] class.
|
||||
|
||||
## Guides
|
||||
|
||||
More in-depth instructional [guides][vjs-guides] are found on the main [Video.js website][vjs-website]. The guides explain general topics and use cases (e.g. setup).
|
||||
|
||||
The full list of articles is on the [guides page][vjs-guides]. If you are looking for troubleshooting information, try the [FAQ][vjs-faq] and [troubleshooting][vjs-troubleshooting] pages.
|
||||
|
||||
[vjs-website]: https://videojs.com
|
||||
|
||||
[vjs-docs]: https://docs.videojs.com
|
||||
|
||||
[vjs-gh]: https://github.com/videojs/video.js
|
||||
|
||||
[vjs-guides]: https://videojs.com/guides/
|
||||
|
||||
[vjs-faq]: https://videojs.com/guides/faqs/
|
||||
|
||||
[vjs-troubleshooting]: https://videojs.com/guides/troubleshooting/
|
||||
|
||||
[api]: https://docs.videojs.com
|
||||
|
||||
[api-player]: https://docs.videojs.com/Player.html
|
||||
@@ -1 +0,0 @@
|
||||
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="//use.edgefonts.net/source-code-pro.js"></script> <link href="https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700" rel="stylesheet" type="text/css"> <!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js --> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css"> <link rel="stylesheet" type="text/css" href="css/api-docs.css"> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script> </head> <body> <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js"></script> <script src="js/doc-data.js"></script> <script src="js/api-docs.js"></script> </body> </html>
|
||||
@@ -1 +0,0 @@
|
||||
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="//use.edgefonts.net/source-code-pro.js"></script> <link href='https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700' rel='stylesheet' type='text/css'> <!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js --> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css"> <link rel="stylesheet" type="text/css" href="css/api-docs.css"> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script> </head> <body> <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js"></script> <script src="js/doc-data.js"></script> <script src="js/api-docs.js"></script> </body> </html>
|
||||
@@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title></title>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h4>Check the console for results</h4>
|
||||
<script src="../js/doc-data.js"></script>
|
||||
<script src="create-doc-files.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* get a subset of objects in array of objects
|
||||
* based on some property value
|
||||
*
|
||||
* @param {array} targetArray - array to search
|
||||
* @param {string} objProperty - object property to search
|
||||
* @param {string|number} value - value of the property to search for
|
||||
* @return {array} array of objects with matching property value
|
||||
*/
|
||||
function getSubArray(targetArray, objProperty, value) {
|
||||
var i, totalItems = targetArray.length, idxArr = [];
|
||||
for (i = 0; i < totalItems; i++) {
|
||||
if (targetArray[i][objProperty] === value) {
|
||||
idxArr.push(targetArray[i]);
|
||||
}
|
||||
}
|
||||
return idxArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* create the HTML files for the classes
|
||||
* @param {array} filenameArray - array of the filenames
|
||||
*/
|
||||
function createFiles(filenameArray) {
|
||||
var i,
|
||||
iMax = filenameArray.length,
|
||||
filename,
|
||||
contentStr = '<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="//use.edgefonts.net/source-code-pro.js"></script> <link href="https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700" rel="stylesheet" type="text/css"> <!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js --> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css"> <link rel="stylesheet" type="text/css" href="css/api-docs.css"> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script> </head> <body> <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js"></script> <script src="js/doc-data.js"></script> <script src="js/api-docs.js"></script> </body> </html>';
|
||||
for (i = 0; i < iMax; i++) {
|
||||
filename = filenameArray[i];
|
||||
// create file with name=filename and contents=contentStr
|
||||
}
|
||||
}
|
||||
|
||||
function createFilenameArray(classData) {
|
||||
var filenameArray = [],
|
||||
i,
|
||||
iMax = classData.length,
|
||||
item,
|
||||
str;
|
||||
// extract the filenames from the class items
|
||||
for (i = 0; i < iMax; i++) {
|
||||
item = classData[i];
|
||||
str = item.meta.filename;
|
||||
str = str.substr(str.lastIndexOf('/') + 1);
|
||||
str = str.replace('.js', '.html');
|
||||
filenameArray.push(str);
|
||||
}
|
||||
// videojs is special case
|
||||
filenameArray.push('video.html');
|
||||
filenameArray = filenameArray.sort();
|
||||
console.log('filenameArray', filenameArray);
|
||||
// now create the files
|
||||
createFiles(filenameArray);
|
||||
}
|
||||
/**
|
||||
* extracts class items from doc data
|
||||
* @param {array} docData JSON output from JSDoc
|
||||
*/
|
||||
function getClassData(docData) {
|
||||
var classData = [];
|
||||
// extract the class items from the doc data
|
||||
classData = getSubArray(docData, 'kind', 'class');
|
||||
// now create the array of filenames
|
||||
createFilenameArray(classData);
|
||||
}
|
||||
|
||||
getClassData(docData);
|
||||
@@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title></title>
|
||||
<script src="//use.edgefonts.net/source-code-pro.js"></script>
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700' rel='stylesheet' type='text/css'>
|
||||
<!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js -->
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/api-docs.css">
|
||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
|
||||
<link rel="canonical" href="https://docs.videojs.com">
|
||||
</head>
|
||||
<body>
|
||||
<p class="legacydocsnote">This documentation is for an outdated version of Video.js. See <a href="https://docs.videojs.com">documentation for the current release</a>.
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js"></script>
|
||||
<script src="js/doc-data.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title></title>
|
||||
<script src="//use.edgefonts.net/source-code-pro.js"></script>
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700' rel='stylesheet' type='text/css'>
|
||||
<!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js -->
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/api-docs.css">
|
||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
|
||||
<link rel="canonical" href="https://docs.videojs.com">
|
||||
</head>
|
||||
<body>
|
||||
<p class="legacydocsnote">This documentation is for an outdated version of Video.js. See <a href="https://docs.videojs.com">documentation for the current release</a>.
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js"></script>
|
||||
<script src="js/doc-data.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>CloseButton</title><script src="//use.edgefonts.net/source-code-pro.js">
|
||||
// font for code blocks
|
||||
</script><link href="https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700" rel="stylesheet" type="text/css"/> <!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js --><link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css"/><link rel="stylesheet" type="text/css" href="css/api-docs.css"/><link rel="canonical" href="https://docs.videojs.com/CloseButton.html">
|
||||
</head><body>
|
||||
<p class="legacydocsnote">This documentation is for an outdated version of Video.js. See <a href="https://docs.videojs.com/CloseButton.html">documentation for the current release</a>.
|
||||
<section id="index" class="side-nav"><h2 class="sideNavHeader"><a href="index.html">API Index</a></h2><div id="memberIndex" class="member-index"><h4>Inherited Methods from Button</h4><ul><li><a href="#MethodsaddChild">addChild</a></li><li><a href="#MethodscreateEl">createEl</a></li><li><a href="#MethodshandleKeyPress">handleKeyPress</a></li></ul><h4>Inherited Methods from ClickableComponent</h4><ul><li><a href="#MethodsbuildCSSClass">buildCSSClass</a></li><li><a href="#MethodscontrolText">controlText</a></li><li><a href="#MethodshandleBlur">handleBlur</a></li><li><a href="#MethodshandleClick">handleClick</a></li><li><a href="#MethodshandleFocus">handleFocus</a></li></ul><h4>Inherited Methods from Component</h4><ul><li><a href="#Methods$">$</a></li><li><a href="#Methods$$">$$</a></li><li><a href="#MethodsaddClass">addClass</a></li><li><a href="#Methodschildren">children</a></li><li><a href="#MethodsclearInterval">clearInterval</a></li><li><a href="#MethodsclearTimeout">clearTimeout</a></li><li><a href="#MethodscontentEl">contentEl</a></li><li><a href="#Methodsdimensions">dimensions</a></li><li><a href="#Methodsdispose">dispose</a></li><li><a href="#Methodsel">el</a></li><li><a href="#MethodsenableTouchActivity">enableTouchActivity</a></li><li><a href="#Methodsextend">extend</a></li><li><a href="#MethodsgetChild">getChild</a></li><li><a href="#MethodsgetChildById">getChildById</a></li><li><a href="#MethodsgetComponent">getComponent</a></li><li><a href="#MethodshasClass">hasClass</a></li><li><a href="#Methodsheight">height</a></li><li><a href="#Methodshide">hide</a></li><li><a href="#Methodsid">id</a></li><li><a href="#MethodsinitChildren">initChildren</a></li><li><a href="#Methodsname">name</a></li><li><a href="#Methodsoff">off</a></li><li><a href="#Methodson">on</a></li><li><a href="#Methodsone">one</a></li><li><a href="#Methodsoptions">options</a></li><li><a href="#Methodsplayer">player</a></li><li><a href="#Methodsready">ready</a></li><li><a href="#MethodsregisterComponent">registerComponent</a></li><li><a href="#MethodsremoveChild">removeChild</a></li><li><a href="#MethodsremoveClass">removeClass</a></li><li><a href="#MethodssetInterval">setInterval</a></li><li><a href="#MethodssetTimeout">setTimeout</a></li><li><a href="#Methodsshow">show</a></li><li><a href="#MethodstoggleClass">toggleClass</a></li><li><a href="#Methodstrigger">trigger</a></li><li><a href="#MethodstriggerReady">triggerReady</a></li><li><a href="#Methodswidth">width</a></li></ul></div></section><div id="main" class="section"><section id="top" class="section"><h1>CloseButton</h1><div style="border:none" id="classDescription" class="description"><p>The <code>CloseButton</code> component is a button which fires a "close" event
|
||||
when it is activated.</p></div><p>DEFINED IN: <a href="https://github.com/videojs/video.js/blob/master/src/js/close-button.js#L4">close-button.js line number: 4</a></p><p>EXTENDS: <a href="button.html">button.js</a></p><h3>Constructor</h3><pre><code>CloseButton()</code></pre></section></div><script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js">
|
||||
// syntax highlighter for code samples
|
||||
</script><script src="./js/highlight-syntax.js">
|
||||
// activates syntax highlighting
|
||||
</script></body></html>
|
||||
@@ -1,172 +0,0 @@
|
||||
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>Component</title><script src="//use.edgefonts.net/source-code-pro.js">
|
||||
// font for code blocks
|
||||
</script><link href="https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700" rel="stylesheet" type="text/css"/> <!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js --><link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css"/><link rel="stylesheet" type="text/css" href="css/api-docs.css"/><link rel="canonical" href="https://docs.videojs.com/Component.html">
|
||||
</head><body>
|
||||
<p class="legacydocsnote">This documentation is for an outdated version of Video.js. See <a href="https://docs.videojs.com/Component.html">documentation for the current release</a>.
|
||||
<section id="index" class="side-nav"><h2 class="sideNavHeader"><a href="index.html">API Index</a></h2><div id="memberIndex" class="member-index"><h3>Component Methods</h3><h4>Class Methods</h4><ul id="methodsList"><li><a href="#Methods$">$</a></li><li><a href="#Methods$$">$$</a></li><li><a href="#MethodsaddChild">addChild</a></li><li><a href="#MethodsaddClass">addClass</a></li><li><a href="#MethodsbuildCSSClass">buildCSSClass</a></li><li><a href="#Methodschildren">children</a></li><li><a href="#MethodsclearInterval">clearInterval</a></li><li><a href="#MethodsclearTimeout">clearTimeout</a></li><li><a href="#MethodscontentEl">contentEl</a></li><li><a href="#MethodscreateEl">createEl</a></li><li><a href="#Methodsdimensions">dimensions</a></li><li><a href="#Methodsdispose">dispose</a></li><li><a href="#Methodsel">el</a></li><li><a href="#MethodsenableTouchActivity">enableTouchActivity</a></li><li><a href="#Methodsextend">extend</a></li><li><a href="#MethodsgetChild">getChild</a></li><li><a href="#MethodsgetChildById">getChildById</a></li><li><a href="#MethodsgetComponent">getComponent</a></li><li><a href="#MethodshasClass">hasClass</a></li><li><a href="#Methodsheight">height</a></li><li><a href="#Methodshide">hide</a></li><li><a href="#Methodsid">id</a></li><li><a href="#MethodsinitChildren">initChildren</a></li><li><a href="#Methodsname">name</a></li><li><a href="#Methodsoff">off</a></li><li><a href="#Methodson">on</a></li><li><a href="#Methodsone">one</a></li><li><a href="#Methodsoptions">options</a></li><li><a href="#Methodsplayer">player</a></li><li><a href="#Methodsready">ready</a></li><li><a href="#MethodsregisterComponent">registerComponent</a></li><li><a href="#MethodsremoveChild">removeChild</a></li><li><a href="#MethodsremoveClass">removeClass</a></li><li><a href="#MethodssetInterval">setInterval</a></li><li><a href="#MethodssetTimeout">setTimeout</a></li><li><a href="#Methodsshow">show</a></li><li><a href="#MethodstoggleClass">toggleClass</a></li><li><a href="#Methodstrigger">trigger</a></li><li><a href="#MethodstriggerReady">triggerReady</a></li><li><a href="#Methodswidth">width</a></li></ul><h4>Inherited Methods from Button</h4><ul><li><a href="#MethodshandleKeyPress">handleKeyPress</a></li></ul><h4>Inherited Methods from ClickableComponent</h4><ul><li><a href="#MethodscontrolText">controlText</a></li><li><a href="#MethodshandleBlur">handleBlur</a></li><li><a href="#MethodshandleClick">handleClick</a></li><li><a href="#MethodshandleFocus">handleFocus</a></li></ul><h4>Inherited Methods from Component</h4><ul/></div></section><div id="main" class="section"><section id="top" class="section"><h1>Component</h1><div style="border:none" id="classDescription" class="description"><p>Base UI Component class
|
||||
Components are embeddable UI objects that are represented by both a
|
||||
javascript object and an element in the DOM. They can be children of other
|
||||
components, and can have many children themselves.</p>
|
||||
<pre class="prettyprint source lang-js"><code> // adding a button to the player
|
||||
var button = player.addChild('button');
|
||||
button.el(); // -> button element</code></pre><pre class="prettyprint source lang-html"><code> <div class="video-js">
|
||||
<div class="vjs-button">Button</div>
|
||||
</div></code></pre><p>Components are also event targets.</p>
|
||||
<pre class="prettyprint source lang-js"><code> button.on('click', function(){
|
||||
console.log('Button Clicked!');
|
||||
});
|
||||
button.trigger('customevent');</code></pre></div><p>DEFINED IN: <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L18">component.js line number: 18</a></p><p>EXTENDS: <a href="button.html">button.js</a></p><h3>Constructor</h3><pre><code>Component( player,[options],[ready] )</code></pre><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>player</td><td>Object</td><td>yes</td><td>Main Player</td></tr><tr><td>options</td><td>Object</td><td>no</td><td>Object of option names and values</td></tr><tr><td>ready</td><td>function</td><td>no</td><td>Ready callback function</td></tr></tbody></table></section><section id="methods" class="section"><h2>Methods</h2><div id="Methods$"><h3 id="$Header">$( selector, [context] )</h3><div id="$Description" class="description"><p>Finds a single DOM element matching <code>selector</code> within the component's
|
||||
<code>contentEl</code> or another custom context.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>selector</td><td>String</td><td>yes</td><td>A valid CSS selector, which will be passed to <code>querySelector</code>.</td></tr><tr><td>context</td><td>Element|String</td><td>no</td><td>A DOM element within which to query. Can also be a selector
|
||||
string in which case the first matching element will be used
|
||||
as context. If missing (or no element matches selector), falls
|
||||
back to <code>document</code>.</td></tr></tbody></table><p class="vjs-only"><em id="$Footer">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L841">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 841</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methods$$"><h3 id="$$Header">$$( selector, [context] )</h3><div id="$$Description" class="description"><p>Finds a all DOM elements matching <code>selector</code> within the component's
|
||||
<code>contentEl</code> or another custom context.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>selector</td><td>String</td><td>yes</td><td>A valid CSS selector, which will be passed to <code>querySelectorAll</code>.</td></tr><tr><td>context</td><td>Element|String</td><td>no</td><td>A DOM element within which to query. Can also be a selector
|
||||
string in which case the first matching element will be used
|
||||
as context. If missing (or no element matches selector), falls
|
||||
back to <code>document</code>.</td></tr></tbody></table><p class="vjs-only"><em id="$$Footer">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L861">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 861</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsaddChild"><h3 id="addChildHeader">addChild( child, [options] )</h3><div id="addChildDescription" class="description"><p>Adds a child component inside this component</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.el();
|
||||
// -> <div class='my-component'></div>
|
||||
myComponent.children();
|
||||
// [empty array]
|
||||
|
||||
var myButton = myComponent.addChild('MyButton');
|
||||
// -> <div class='my-component'><div class="my-button">myButton<div></div>
|
||||
// -> myButton === myComponent.children()[0];</code></pre><p>Pass in options for child constructors and options for children of the child</p>
|
||||
<pre class="prettyprint source lang-js"><code> var myButton = myComponent.addChild('MyButton', {
|
||||
text: 'Press Me',
|
||||
buttonChildExample: {
|
||||
buttonChildOption: true
|
||||
}
|
||||
});</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>child</td><td>String|Component</td><td>yes</td><td>The class name or instance of a child to add</td></tr><tr><td>options</td><td>Object</td><td>no</td><td>Options, including options to be passed to children of the child.</td></tr></tbody></table><p class="vjs-only"><em id="addChildFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L315">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 315</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsaddClass"><h3 id="addClassHeader">addClass( classToAdd )</h3><div id="addClassDescription" class="description"><p>Add a CSS class name to the component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToAdd</td><td>String</td><td>yes</td><td>Classname to add</td></tr></tbody></table><p class="vjs-only"><em id="addClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L892">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 892</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsbuildCSSClass"><h3 id="buildCSSClassHeader">buildCSSClass()</h3><div id="buildCSSClassDescription" class="description"><p>Allows sub components to stack CSS class names</p></div><p class="vjs-only"><em id="buildCSSClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L593">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 593</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodschildren"><h3 id="childrenHeader">children()</h3><div id="childrenDescription" class="description"><p>Get an array of all child components</p>
|
||||
<pre class="prettyprint source lang-js"><code> var kids = myComponent.children();</code></pre></div><p class="vjs-only"><em id="childrenFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L282">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 282</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsclearInterval"><h3 id="clearIntervalHeader">clearInterval( intervalId )</h3><div id="clearIntervalDescription" class="description"><p>Clears an interval and removes the associated dispose listener</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>intervalId</td><td>Number</td><td>yes</td><td>The id of the interval to clear</td></tr></tbody></table><p class="vjs-only"><em id="clearIntervalFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1295">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1295</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsclearTimeout"><h3 id="clearTimeoutHeader">clearTimeout( timeoutId )</h3><div id="clearTimeoutDescription" class="description"><p>Clears a timeout and removes the associated dispose listener</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>timeoutId</td><td>Number</td><td>yes</td><td>The id of the timeout to clear</td></tr></tbody></table><p class="vjs-only"><em id="clearTimeoutFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1252">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1252</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodscontentEl"><h3 id="contentElHeader">contentEl()</h3><div id="contentElDescription" class="description"><p>Return the component's DOM element where children are inserted.
|
||||
Will either be the same as el() or a new element defined in createEl().</p></div><p class="vjs-only"><em id="contentElFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L245">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 245</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodscreateEl"><h3 id="createElHeader">createEl( [tagName], [properties], [attributes] )</h3><div id="createElDescription" class="description"><p>Create the component's DOM element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>tagName</td><td>String</td><td>no</td><td>Element's node type. e.g. 'div'</td></tr><tr><td>properties</td><td>Object</td><td>no</td><td>An object of properties that should be set</td></tr><tr><td>attributes</td><td>Object</td><td>no</td><td>An object of attributes that should be set</td></tr></tbody></table><p class="vjs-only"><em id="createElFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L208">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 208</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsdimensions"><h3 id="dimensionsHeader">dimensions( width, height )</h3><div id="dimensionsDescription" class="description"><p>Set both width and height at the same time</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>width</td><td>Number|String</td><td>yes</td><td>Width of player</td></tr><tr><td>height</td><td>Number|String</td><td>yes</td><td>Height of player</td></tr></tbody></table><p class="vjs-only"><em id="dimensionsFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1015">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1015</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsdispose"><h3 id="disposeHeader">dispose()</h3><div id="disposeDescription" class="description"><p>Dispose of the component and all child components</p></div><p class="vjs-only"><em id="disposeFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L101">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 101</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsel"><h3 id="elHeader">el()</h3><div id="elDescription" class="description"><p>Get the component's DOM element</p>
|
||||
<pre class="prettyprint source lang-js"><code> var domEl = myComponent.el();</code></pre></div><p class="vjs-only"><em id="elFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L195">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 195</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsenableTouchActivity"><h3 id="enableTouchActivityHeader">enableTouchActivity()</h3><div id="enableTouchActivityDescription" class="description"><p>Report user touch activity when touch events occur
|
||||
User activity is used to determine when controls should show/hide. It's
|
||||
relatively simple when it comes to mouse events, because any mouse event
|
||||
should show the controls. So we capture mouse events that bubble up to the
|
||||
player and report activity when that happens.
|
||||
With touch events it isn't as easy. We can't rely on touch events at the
|
||||
player level, because a tap (touchstart + touchend) on the video itself on
|
||||
mobile devices is meant to turn controls off (and on). User activity is
|
||||
checked asynchronously, so what could happen is a tap event on the video
|
||||
turns the controls off, then the touchend event bubbles up to the player,
|
||||
which if it reported user activity, would turn the controls right back on.
|
||||
(We also don't want to completely block touch events from bubbling up)
|
||||
Also a touchmove, touch+hold, and anything other than a tap is not supposed
|
||||
to turn the controls back on on a mobile device.
|
||||
Here we're setting the default component behavior to report user activity
|
||||
whenever touch events happen, and this can be turned off by components that
|
||||
want touch events to act differently.</p></div><p class="vjs-only"><em id="enableTouchActivityFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1174">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1174</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsextend"><h3 id="extendHeader">static extend( props )<em class="deprecated"> (deprecated)</em></h3><div id="extendDescription" class="description"><p>Sets up the constructor using the supplied init method
|
||||
or uses the init of the parent object</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>props</td><td>Object</td><td>yes</td><td>An object of properties</td></tr></tbody></table><p class="vjs-only"><em id="extendFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1350">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1350</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsgetChild"><h3 id="getChildHeader">getChild()</h3><div id="getChildDescription" class="description"><p>Returns a child component with the provided name</p></div><p class="vjs-only"><em id="getChildFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L305">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 305</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsgetChildById"><h3 id="getChildByIdHeader">getChildById()</h3><div id="getChildByIdDescription" class="description"><p>Returns a child component with the provided ID</p></div><p class="vjs-only"><em id="getChildByIdFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L295">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 295</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsgetComponent"><h3 id="getComponentHeader">static getComponent( name )</h3><div id="getComponentDescription" class="description"><p>Gets a component by name</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td>String</td><td>yes</td><td>Name of the component to get</td></tr></tbody></table><p class="vjs-only"><em id="getComponentFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1331">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1331</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodshasClass"><h3 id="hasClassHeader">hasClass( classToCheck )</h3><div id="hasClassDescription" class="description"><p>Check if a component's element has a CSS class name</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToCheck</td><td>String</td><td>yes</td><td>Classname to check</td></tr></tbody></table><p class="vjs-only"><em id="hasClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L881">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 881</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsheight"><h3 id="heightHeader">height( num, [skipListeners] )</h3><div id="heightDescription" class="description"><p>Get or set the height of the component (CSS values)
|
||||
Setting the video tag dimension values only works with values in pixels.
|
||||
Percent values will not work.
|
||||
Some percents can be used, but width()/height() will return the number + %,
|
||||
not the actual computed width/height.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>num</td><td>Number|String</td><td>yes</td><td>New component height</td></tr><tr><td>skipListeners</td><td>Boolean</td><td>no</td><td>Skip the resize event trigger</td></tr></tbody></table><p class="vjs-only"><em id="heightFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L998">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 998</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodshide"><h3 id="hideHeader">hide()</h3><div id="hideDescription" class="description"><p>Hide the component element if currently showing</p></div><p class="vjs-only"><em id="hideFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L944">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 944</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsid"><h3 id="idHeader">id()</h3><div id="idDescription" class="description"><p>Get the component's ID</p>
|
||||
<pre class="prettyprint source lang-js"><code> var id = myComponent.id();</code></pre></div><p class="vjs-only"><em id="idFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L256">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 256</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsinitChildren"><h3 id="initChildrenHeader">initChildren()</h3><div id="initChildrenDescription" class="description"><p>Add and initialize default child components from options</p>
|
||||
<pre class="prettyprint source lang-js"><code> // when an instance of MyComponent is created, all children in options
|
||||
// will be added to the instance by their name strings and options
|
||||
MyComponent.prototype.options_ = {
|
||||
children: [
|
||||
'myChildComponent'
|
||||
],
|
||||
myChildComponent: {
|
||||
myChildOption: true
|
||||
}
|
||||
};
|
||||
|
||||
// Or when creating the component
|
||||
var myComp = new MyComponent(player, {
|
||||
children: [
|
||||
'myChildComponent'
|
||||
],
|
||||
myChildComponent: {
|
||||
myChildOption: true
|
||||
}
|
||||
});</code></pre><p>The children option can also be an array of
|
||||
child options objects (that also include a 'name' key).
|
||||
This can be used if you have two child components of the
|
||||
same type that need different options.</p>
|
||||
<pre class="prettyprint source lang-js"><code> var myComp = new MyComponent(player, {
|
||||
children: [
|
||||
'button',
|
||||
{
|
||||
name: 'button',
|
||||
someOtherOption: true
|
||||
},
|
||||
{
|
||||
name: 'button',
|
||||
someOtherOption: false
|
||||
}
|
||||
]
|
||||
});</code></pre></div><p class="vjs-only"><em id="initChildrenFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L455">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 455</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsname"><h3 id="nameHeader">name()</h3><div id="nameDescription" class="description"><p>Get the component's name. The name is often used to reference the component.</p>
|
||||
<pre class="prettyprint source lang-js"><code> var name = myComponent.name();</code></pre></div><p class="vjs-only"><em id="nameFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L269">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 269</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsoff"><h3 id="offHeader">off( first, second, [third] )</h3><div id="offDescription" class="description"><p>Remove an event listener from this component's element</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.off('eventType', myFunc);</code></pre><p>If myFunc is excluded, ALL listeners for the event type will be removed.
|
||||
If eventType is excluded, ALL listeners will be removed from the component.
|
||||
Alternatively you can use <code>off</code> to remove listeners that were added to other
|
||||
elements or components using <code>myComponent.on(otherComponent...</code>.
|
||||
In this case both the event type and listener function are REQUIRED.</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.off(otherElement, 'eventType', myFunc);
|
||||
myComponent.off(otherComponent, 'eventType', myFunc);</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>first</td><td>String|Component</td><td>yes</td><td>The event type or other component</td></tr><tr><td>second</td><td>function|String</td><td>yes</td><td>The listener function or event type</td></tr><tr><td>third</td><td>function</td><td>no</td><td>The listener for other component</td></tr></tbody></table><p class="vjs-only"><em id="offFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L680">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 680</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodson"><h3 id="onHeader">on( first, second, third )</h3><div id="onDescription" class="description"><p>Add an event listener to this component's element</p>
|
||||
<pre class="prettyprint source lang-js"><code> var myFunc = function(){
|
||||
var myComponent = this;
|
||||
// Do something when the event is fired
|
||||
};
|
||||
|
||||
myComponent.on('eventType', myFunc);</code></pre><p>The context of myFunc will be myComponent unless previously bound.
|
||||
Alternatively, you can add a listener to another element or component.</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.on(otherElement, 'eventName', myFunc);
|
||||
myComponent.on(otherComponent, 'eventName', myFunc);</code></pre><p>The benefit of using this over <code>VjsEvents.on(otherElement, 'eventName', myFunc)</code>
|
||||
and <code>otherComponent.on('eventName', myFunc)</code> is that this way the listeners
|
||||
will be automatically cleaned up when either component is disposed.
|
||||
It will also bind myComponent as the context of myFunc.
|
||||
<strong>NOTE</strong>: When using this on elements in the page other than window
|
||||
and document (both permanent), if you remove the element from the DOM
|
||||
you need to call <code>myComponent.trigger(el, 'dispose')</code> on it to clean up
|
||||
references to it and allow the browser to garbage collect it.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>first</td><td>String|Component</td><td>yes</td><td>The event type or other component</td></tr><tr><td>second</td><td>function|String</td><td>yes</td><td>The event handler or event type</td></tr><tr><td>third</td><td>function</td><td>yes</td><td>The event handler</td></tr></tbody></table><p class="vjs-only"><em id="onFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L605">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 605</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsone"><h3 id="oneHeader">one( first, second, [third] )</h3><div id="oneDescription" class="description"><p>Add an event listener to be triggered only once and then removed</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.one('eventName', myFunc);</code></pre><p>Alternatively you can add a listener to another element or component
|
||||
that will be triggered only once.</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.one(otherElement, 'eventName', myFunc);
|
||||
myComponent.one(otherComponent, 'eventName', myFunc);</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>first</td><td>String|Component</td><td>yes</td><td>The event type or other component</td></tr><tr><td>second</td><td>function|String</td><td>yes</td><td>The listener function or event type</td></tr><tr><td>third</td><td>function</td><td>no</td><td>The listener function for other component</td></tr></tbody></table><p class="vjs-only"><em id="oneFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L728">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 728</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsoptions"><h3 id="optionsHeader">options( obj )</h3><div id="optionsDescription" class="description"><p>Deep merge of options objects
|
||||
Whenever a property is an object on both options objects
|
||||
the two properties will be merged using mergeOptions.</p>
|
||||
<pre class="prettyprint source lang-js"><code> Parent.prototype.options_ = {
|
||||
optionSet: {
|
||||
'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
|
||||
'childTwo': {},
|
||||
'childThree': {}
|
||||
}
|
||||
}
|
||||
newOptions = {
|
||||
optionSet: {
|
||||
'childOne': { 'foo': 'baz', 'abc': '123' }
|
||||
'childTwo': null,
|
||||
'childFour': {}
|
||||
}
|
||||
}
|
||||
|
||||
this.options(newOptions);</code></pre><p>RESULT</p>
|
||||
<pre class="prettyprint source lang-js"><code> {
|
||||
optionSet: {
|
||||
'childOne': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' },
|
||||
'childTwo': null, // Disabled. Won't be initialized.
|
||||
'childThree': {},
|
||||
'childFour': {}
|
||||
}
|
||||
}</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>obj</td><td>Object</td><td>yes</td><td>Object of new option values</td></tr></tbody></table><p class="vjs-only"><em id="optionsFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L145">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 145</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsplayer"><h3 id="playerHeader">player()</h3><div id="playerDescription" class="description"><p>Return the component's player</p></div><p class="vjs-only"><em id="playerFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L135">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 135</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsready"><h3 id="readyHeader">ready( fn, sync )</h3><div id="readyDescription" class="description"><p>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.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>fn</td><td>function</td><td>yes</td><td>Ready listener</td></tr><tr><td>sync</td><td>Boolean</td><td>yes</td><td>Exec the listener synchronously if component is ready</td></tr></tbody></table><p class="vjs-only"><em id="readyFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L787">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 787</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsregisterComponent"><h3 id="registerComponentHeader">static registerComponent( name, comp )</h3><div id="registerComponentDescription" class="description"><p>Registers a component</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td>String</td><td>yes</td><td>Name of the component to register</td></tr><tr><td>comp</td><td>Object</td><td>yes</td><td>The component to register</td></tr></tbody></table><p class="vjs-only"><em id="registerComponentFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1314">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1314</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsremoveChild"><h3 id="removeChildHeader">removeChild( component )</h3><div id="removeChildDescription" class="description"><p>Remove a child component from this component's list of children, and the
|
||||
child component's element from this component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>component</td><td>Component</td><td>yes</td><td>Component to remove</td></tr></tbody></table><p class="vjs-only"><em id="removeChildFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L415">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 415</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsremoveClass"><h3 id="removeClassHeader">removeClass( classToRemove )</h3><div id="removeClassDescription" class="description"><p>Remove a CSS class name from the component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToRemove</td><td>String</td><td>yes</td><td>Classname to remove</td></tr></tbody></table><p class="vjs-only"><em id="removeClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L904">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 904</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodssetInterval"><h3 id="setIntervalHeader">setInterval( fn, interval )</h3><div id="setIntervalDescription" class="description"><p>Creates an interval and sets up disposal automatically.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>fn</td><td>function</td><td>yes</td><td>The function to run every N seconds.</td></tr><tr><td>interval</td><td>Number</td><td>yes</td><td>Number of ms to delay before executing specified function.</td></tr></tbody></table><p class="vjs-only"><em id="setIntervalFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1271">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1271</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodssetTimeout"><h3 id="setTimeoutHeader">setTimeout( fn, timeout )</h3><div id="setTimeoutDescription" class="description"><p>Creates timeout and sets up disposal automatically.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>fn</td><td>function</td><td>yes</td><td>The function to run after the timeout.</td></tr><tr><td>timeout</td><td>Number</td><td>yes</td><td>Number of ms to delay before executing specified function.</td></tr></tbody></table><p class="vjs-only"><em id="setTimeoutFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1227">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1227</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsshow"><h3 id="showHeader">show()</h3><div id="showDescription" class="description"><p>Show the component element if hidden</p></div><p class="vjs-only"><em id="showFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L933">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 933</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodstoggleClass"><h3 id="toggleClassHeader">toggleClass( classToToggle, [predicate] )</h3><div id="toggleClassDescription" class="description"><p>Add or remove a CSS class name from the component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToToggle</td><td>String</td></tr><tr><td>predicate</td><td>Boolean|function</td><td>no</td><td>Can be a function that returns a Boolean. If <code>true</code>, the class
|
||||
will be added; if <code>false</code>, the class will be removed. If not
|
||||
given, the class will be added if not present and vice versa.</td></tr></tbody></table><p class="vjs-only"><em id="toggleClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L916">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 916</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodstrigger"><h3 id="triggerHeader">trigger( event, [hash] )</h3><div id="triggerDescription" class="description"><p>Trigger an event on an element</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.trigger('eventName');
|
||||
myComponent.trigger({'type':'eventName'});
|
||||
myComponent.trigger('eventName', {data: 'some data'});
|
||||
myComponent.trigger({'type':'eventName'}, {data: 'some data'});</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>event</td><td>Event|Object|String</td><td>yes</td><td>A string (the type) or an event object with a type attribute</td></tr><tr><td>hash</td><td>Object</td><td>no</td><td>data hash to pass along with the event</td></tr></tbody></table><p class="vjs-only"><em id="triggerFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L768">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 768</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodstriggerReady"><h3 id="triggerReadyHeader">triggerReady()</h3><div id="triggerReadyDescription" class="description"><p>Trigger the ready listeners</p></div><p class="vjs-only"><em id="triggerReadyFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L814">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 814</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodswidth"><h3 id="widthHeader">width( num, skipListeners )</h3><div id="widthDescription" class="description"><p>Set or get the width of the component (CSS values)
|
||||
Setting the video tag dimension values only works with values in pixels.
|
||||
Percent values will not work.
|
||||
Some percents can be used, but width()/height() will return the number + %,
|
||||
not the actual computed width/height.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>num</td><td>Number|String</td><td>yes</td><td>Optional width number</td></tr><tr><td>skipListeners</td><td>Boolean</td><td>yes</td><td>Skip the 'resize' event trigger</td></tr></tbody></table><p class="vjs-only"><em id="widthFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L981">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 981</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodshandleKeyPress"><h3 id="handleKeyPressHeader">handleKeyPress()</h3><div id="handleKeyPressDescription" class="description"><p>Handle KeyPress (document level) - Extend with specific functionality for button</p></div><p class="vjs-only"><em id="handleKeyPressFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/button.js#L74">https://github.com/videojs/video.js/blob/master/src/js/button.js line number: 74</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodscontrolText"><h3 id="controlTextHeader">controlText( el )</h3><div id="controlTextDescription" class="description"><p>create control text</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>el</td><td>Element</td><td>yes</td><td>Parent element for the control text</td></tr></tbody></table><p class="vjs-only"><em id="controlTextFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js#L65">https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js line number: 65</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodshandleBlur"><h3 id="handleBlurHeader">handleBlur()</h3><div id="handleBlurDescription" class="description"><p>Handle Blur - Remove keyboard triggers</p></div><p class="vjs-only"><em id="handleBlurFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js#L163">https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js line number: 163</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodshandleClick"><h3 id="handleClickHeader">handleClick()</h3><div id="handleClickDescription" class="description"><p>Handle Click - Override with specific functionality for component</p></div><p class="vjs-only"><em id="handleClickFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js#L132">https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js line number: 132</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodshandleFocus"><h3 id="handleFocusHeader">handleFocus()</h3><div id="handleFocusDescription" class="description"><p>Handle Focus - Add keyboard functionality to element</p></div><p class="vjs-only"><em id="handleFocusFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js#L139">https://github.com/videojs/video.js/blob/master/src/js/clickable-component.js line number: 139</a></em></p><p><a href="#top">[back to top]</a></p></div></section></div><script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js">
|
||||
// syntax highlighter for code samples
|
||||
</script><script src="./js/highlight-syntax.js">
|
||||
// activates syntax highlighting
|
||||
</script></body></html>
|
||||
@@ -1,160 +0,0 @@
|
||||
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>ControlBar</title><script src="//use.edgefonts.net/source-code-pro.js">
|
||||
// font for code blocks
|
||||
</script><link href="https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700" rel="stylesheet" type="text/css"/> <!-- there are many other style for highlighted code here: https://cdnjs.com/libraries/highlight.js --><link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-forest.light.min.css"/><link rel="stylesheet" type="text/css" href="css/api-docs.css"/><link rel="canonical" href="https://docs.videojs.com/ControlBar.html">
|
||||
</head><body>
|
||||
<p class="legacydocsnote">This documentation is for an outdated version of Video.js. See <a href="https://docs.videojs.com/ControlBar.html">documentation for the current release</a>.
|
||||
<section id="index" class="side-nav"><h2 class="sideNavHeader"><a href="index.html">API Index</a></h2><div id="memberIndex" class="member-index"><h3>ControlBar Methods</h3><h4>Class Methods</h4><ul id="methodsList"><li><a href="#MethodscreateEl">createEl</a></li></ul><h4>Inherited Methods from Component</h4><ul><li><a href="#Methods$">$</a></li><li><a href="#Methods$$">$$</a></li><li><a href="#MethodsaddChild">addChild</a></li><li><a href="#MethodsaddClass">addClass</a></li><li><a href="#MethodsbuildCSSClass">buildCSSClass</a></li><li><a href="#Methodschildren">children</a></li><li><a href="#MethodsclearInterval">clearInterval</a></li><li><a href="#MethodsclearTimeout">clearTimeout</a></li><li><a href="#MethodscontentEl">contentEl</a></li><li><a href="#Methodsdimensions">dimensions</a></li><li><a href="#Methodsdispose">dispose</a></li><li><a href="#Methodsel">el</a></li><li><a href="#MethodsenableTouchActivity">enableTouchActivity</a></li><li><a href="#Methodsextend">extend</a></li><li><a href="#MethodsgetChild">getChild</a></li><li><a href="#MethodsgetChildById">getChildById</a></li><li><a href="#MethodsgetComponent">getComponent</a></li><li><a href="#MethodshasClass">hasClass</a></li><li><a href="#Methodsheight">height</a></li><li><a href="#Methodshide">hide</a></li><li><a href="#Methodsid">id</a></li><li><a href="#MethodsinitChildren">initChildren</a></li><li><a href="#Methodsname">name</a></li><li><a href="#Methodsoff">off</a></li><li><a href="#Methodson">on</a></li><li><a href="#Methodsone">one</a></li><li><a href="#Methodsoptions">options</a></li><li><a href="#Methodsplayer">player</a></li><li><a href="#Methodsready">ready</a></li><li><a href="#MethodsregisterComponent">registerComponent</a></li><li><a href="#MethodsremoveChild">removeChild</a></li><li><a href="#MethodsremoveClass">removeClass</a></li><li><a href="#MethodssetInterval">setInterval</a></li><li><a href="#MethodssetTimeout">setTimeout</a></li><li><a href="#Methodsshow">show</a></li><li><a href="#MethodstoggleClass">toggleClass</a></li><li><a href="#Methodstrigger">trigger</a></li><li><a href="#MethodstriggerReady">triggerReady</a></li><li><a href="#Methodswidth">width</a></li></ul></div></section><div id="main" class="section"><section id="top" class="section"><h1>ControlBar</h1><div style="border:none" id="classDescription" class="description"><p>Container of main controls</p></div><p>DEFINED IN: <a href="https://github.com/videojs/video.js/blob/master/src/js/control-bar/control-bar.js#L24">control-bar.js line number: 24</a></p><p>EXTENDS: <a href="component.html">component.js</a></p><h3>Constructor</h3><pre><code>ControlBar()</code></pre></section><section id="methods" class="section"><h2>Methods</h2><div id="MethodscreateEl"><h3 id="createElHeader">createEl()</h3><div id="createElDescription" class="description"><p>Create the component's DOM element</p></div><p class="vjs-only"><em id="createElFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/control-bar/control-bar.js#L32">https://github.com/videojs/video.js/blob/master/src/js/control-bar/control-bar.js line number: 32</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methods$"><h3 id="$Header">$( selector, [context] )</h3><div id="$Description" class="description"><p>Finds a single DOM element matching <code>selector</code> within the component's
|
||||
<code>contentEl</code> or another custom context.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>selector</td><td>String</td><td>yes</td><td>A valid CSS selector, which will be passed to <code>querySelector</code>.</td></tr><tr><td>context</td><td>Element|String</td><td>no</td><td>A DOM element within which to query. Can also be a selector
|
||||
string in which case the first matching element will be used
|
||||
as context. If missing (or no element matches selector), falls
|
||||
back to <code>document</code>.</td></tr></tbody></table><p class="vjs-only"><em id="$Footer">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L841">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 841</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methods$$"><h3 id="$$Header">$$( selector, [context] )</h3><div id="$$Description" class="description"><p>Finds a all DOM elements matching <code>selector</code> within the component's
|
||||
<code>contentEl</code> or another custom context.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>selector</td><td>String</td><td>yes</td><td>A valid CSS selector, which will be passed to <code>querySelectorAll</code>.</td></tr><tr><td>context</td><td>Element|String</td><td>no</td><td>A DOM element within which to query. Can also be a selector
|
||||
string in which case the first matching element will be used
|
||||
as context. If missing (or no element matches selector), falls
|
||||
back to <code>document</code>.</td></tr></tbody></table><p class="vjs-only"><em id="$$Footer">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L861">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 861</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsaddChild"><h3 id="addChildHeader">addChild( child, [options] )</h3><div id="addChildDescription" class="description"><p>Adds a child component inside this component</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.el();
|
||||
// -> <div class='my-component'></div>
|
||||
myComponent.children();
|
||||
// [empty array]
|
||||
|
||||
var myButton = myComponent.addChild('MyButton');
|
||||
// -> <div class='my-component'><div class="my-button">myButton<div></div>
|
||||
// -> myButton === myComponent.children()[0];</code></pre><p>Pass in options for child constructors and options for children of the child</p>
|
||||
<pre class="prettyprint source lang-js"><code> var myButton = myComponent.addChild('MyButton', {
|
||||
text: 'Press Me',
|
||||
buttonChildExample: {
|
||||
buttonChildOption: true
|
||||
}
|
||||
});</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>child</td><td>String|Component</td><td>yes</td><td>The class name or instance of a child to add</td></tr><tr><td>options</td><td>Object</td><td>no</td><td>Options, including options to be passed to children of the child.</td></tr></tbody></table><p class="vjs-only"><em id="addChildFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L315">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 315</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsaddClass"><h3 id="addClassHeader">addClass( classToAdd )</h3><div id="addClassDescription" class="description"><p>Add a CSS class name to the component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToAdd</td><td>String</td><td>yes</td><td>Classname to add</td></tr></tbody></table><p class="vjs-only"><em id="addClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L892">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 892</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsbuildCSSClass"><h3 id="buildCSSClassHeader">buildCSSClass()</h3><div id="buildCSSClassDescription" class="description"><p>Allows sub components to stack CSS class names</p></div><p class="vjs-only"><em id="buildCSSClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L593">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 593</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodschildren"><h3 id="childrenHeader">children()</h3><div id="childrenDescription" class="description"><p>Get an array of all child components</p>
|
||||
<pre class="prettyprint source lang-js"><code> var kids = myComponent.children();</code></pre></div><p class="vjs-only"><em id="childrenFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L282">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 282</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsclearInterval"><h3 id="clearIntervalHeader">clearInterval( intervalId )</h3><div id="clearIntervalDescription" class="description"><p>Clears an interval and removes the associated dispose listener</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>intervalId</td><td>Number</td><td>yes</td><td>The id of the interval to clear</td></tr></tbody></table><p class="vjs-only"><em id="clearIntervalFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1295">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1295</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsclearTimeout"><h3 id="clearTimeoutHeader">clearTimeout( timeoutId )</h3><div id="clearTimeoutDescription" class="description"><p>Clears a timeout and removes the associated dispose listener</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>timeoutId</td><td>Number</td><td>yes</td><td>The id of the timeout to clear</td></tr></tbody></table><p class="vjs-only"><em id="clearTimeoutFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1252">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1252</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodscontentEl"><h3 id="contentElHeader">contentEl()</h3><div id="contentElDescription" class="description"><p>Return the component's DOM element where children are inserted.
|
||||
Will either be the same as el() or a new element defined in createEl().</p></div><p class="vjs-only"><em id="contentElFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L245">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 245</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsdimensions"><h3 id="dimensionsHeader">dimensions( width, height )</h3><div id="dimensionsDescription" class="description"><p>Set both width and height at the same time</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>width</td><td>Number|String</td><td>yes</td><td>Width of player</td></tr><tr><td>height</td><td>Number|String</td><td>yes</td><td>Height of player</td></tr></tbody></table><p class="vjs-only"><em id="dimensionsFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1015">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1015</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsdispose"><h3 id="disposeHeader">dispose()</h3><div id="disposeDescription" class="description"><p>Dispose of the component and all child components</p></div><p class="vjs-only"><em id="disposeFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L101">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 101</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsel"><h3 id="elHeader">el()</h3><div id="elDescription" class="description"><p>Get the component's DOM element</p>
|
||||
<pre class="prettyprint source lang-js"><code> var domEl = myComponent.el();</code></pre></div><p class="vjs-only"><em id="elFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L195">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 195</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsenableTouchActivity"><h3 id="enableTouchActivityHeader">enableTouchActivity()</h3><div id="enableTouchActivityDescription" class="description"><p>Report user touch activity when touch events occur
|
||||
User activity is used to determine when controls should show/hide. It's
|
||||
relatively simple when it comes to mouse events, because any mouse event
|
||||
should show the controls. So we capture mouse events that bubble up to the
|
||||
player and report activity when that happens.
|
||||
With touch events it isn't as easy. We can't rely on touch events at the
|
||||
player level, because a tap (touchstart + touchend) on the video itself on
|
||||
mobile devices is meant to turn controls off (and on). User activity is
|
||||
checked asynchronously, so what could happen is a tap event on the video
|
||||
turns the controls off, then the touchend event bubbles up to the player,
|
||||
which if it reported user activity, would turn the controls right back on.
|
||||
(We also don't want to completely block touch events from bubbling up)
|
||||
Also a touchmove, touch+hold, and anything other than a tap is not supposed
|
||||
to turn the controls back on on a mobile device.
|
||||
Here we're setting the default component behavior to report user activity
|
||||
whenever touch events happen, and this can be turned off by components that
|
||||
want touch events to act differently.</p></div><p class="vjs-only"><em id="enableTouchActivityFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1174">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1174</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsextend"><h3 id="extendHeader">static extend( props )<em class="deprecated"> (deprecated)</em></h3><div id="extendDescription" class="description"><p>Sets up the constructor using the supplied init method
|
||||
or uses the init of the parent object</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>props</td><td>Object</td><td>yes</td><td>An object of properties</td></tr></tbody></table><p class="vjs-only"><em id="extendFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1350">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1350</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsgetChild"><h3 id="getChildHeader">getChild()</h3><div id="getChildDescription" class="description"><p>Returns a child component with the provided name</p></div><p class="vjs-only"><em id="getChildFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L305">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 305</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsgetChildById"><h3 id="getChildByIdHeader">getChildById()</h3><div id="getChildByIdDescription" class="description"><p>Returns a child component with the provided ID</p></div><p class="vjs-only"><em id="getChildByIdFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L295">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 295</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsgetComponent"><h3 id="getComponentHeader">static getComponent( name )</h3><div id="getComponentDescription" class="description"><p>Gets a component by name</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td>String</td><td>yes</td><td>Name of the component to get</td></tr></tbody></table><p class="vjs-only"><em id="getComponentFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1331">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1331</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodshasClass"><h3 id="hasClassHeader">hasClass( classToCheck )</h3><div id="hasClassDescription" class="description"><p>Check if a component's element has a CSS class name</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToCheck</td><td>String</td><td>yes</td><td>Classname to check</td></tr></tbody></table><p class="vjs-only"><em id="hasClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L881">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 881</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsheight"><h3 id="heightHeader">height( num, [skipListeners] )</h3><div id="heightDescription" class="description"><p>Get or set the height of the component (CSS values)
|
||||
Setting the video tag dimension values only works with values in pixels.
|
||||
Percent values will not work.
|
||||
Some percents can be used, but width()/height() will return the number + %,
|
||||
not the actual computed width/height.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>num</td><td>Number|String</td><td>yes</td><td>New component height</td></tr><tr><td>skipListeners</td><td>Boolean</td><td>no</td><td>Skip the resize event trigger</td></tr></tbody></table><p class="vjs-only"><em id="heightFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L998">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 998</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodshide"><h3 id="hideHeader">hide()</h3><div id="hideDescription" class="description"><p>Hide the component element if currently showing</p></div><p class="vjs-only"><em id="hideFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L944">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 944</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsid"><h3 id="idHeader">id()</h3><div id="idDescription" class="description"><p>Get the component's ID</p>
|
||||
<pre class="prettyprint source lang-js"><code> var id = myComponent.id();</code></pre></div><p class="vjs-only"><em id="idFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L256">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 256</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsinitChildren"><h3 id="initChildrenHeader">initChildren()</h3><div id="initChildrenDescription" class="description"><p>Add and initialize default child components from options</p>
|
||||
<pre class="prettyprint source lang-js"><code> // when an instance of MyComponent is created, all children in options
|
||||
// will be added to the instance by their name strings and options
|
||||
MyComponent.prototype.options_ = {
|
||||
children: [
|
||||
'myChildComponent'
|
||||
],
|
||||
myChildComponent: {
|
||||
myChildOption: true
|
||||
}
|
||||
};
|
||||
|
||||
// Or when creating the component
|
||||
var myComp = new MyComponent(player, {
|
||||
children: [
|
||||
'myChildComponent'
|
||||
],
|
||||
myChildComponent: {
|
||||
myChildOption: true
|
||||
}
|
||||
});</code></pre><p>The children option can also be an array of
|
||||
child options objects (that also include a 'name' key).
|
||||
This can be used if you have two child components of the
|
||||
same type that need different options.</p>
|
||||
<pre class="prettyprint source lang-js"><code> var myComp = new MyComponent(player, {
|
||||
children: [
|
||||
'button',
|
||||
{
|
||||
name: 'button',
|
||||
someOtherOption: true
|
||||
},
|
||||
{
|
||||
name: 'button',
|
||||
someOtherOption: false
|
||||
}
|
||||
]
|
||||
});</code></pre></div><p class="vjs-only"><em id="initChildrenFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L455">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 455</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsname"><h3 id="nameHeader">name()</h3><div id="nameDescription" class="description"><p>Get the component's name. The name is often used to reference the component.</p>
|
||||
<pre class="prettyprint source lang-js"><code> var name = myComponent.name();</code></pre></div><p class="vjs-only"><em id="nameFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L269">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 269</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsoff"><h3 id="offHeader">off( first, second, [third] )</h3><div id="offDescription" class="description"><p>Remove an event listener from this component's element</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.off('eventType', myFunc);</code></pre><p>If myFunc is excluded, ALL listeners for the event type will be removed.
|
||||
If eventType is excluded, ALL listeners will be removed from the component.
|
||||
Alternatively you can use <code>off</code> to remove listeners that were added to other
|
||||
elements or components using <code>myComponent.on(otherComponent...</code>.
|
||||
In this case both the event type and listener function are REQUIRED.</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.off(otherElement, 'eventType', myFunc);
|
||||
myComponent.off(otherComponent, 'eventType', myFunc);</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>first</td><td>String|Component</td><td>yes</td><td>The event type or other component</td></tr><tr><td>second</td><td>function|String</td><td>yes</td><td>The listener function or event type</td></tr><tr><td>third</td><td>function</td><td>no</td><td>The listener for other component</td></tr></tbody></table><p class="vjs-only"><em id="offFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L680">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 680</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodson"><h3 id="onHeader">on( first, second, third )</h3><div id="onDescription" class="description"><p>Add an event listener to this component's element</p>
|
||||
<pre class="prettyprint source lang-js"><code> var myFunc = function(){
|
||||
var myComponent = this;
|
||||
// Do something when the event is fired
|
||||
};
|
||||
|
||||
myComponent.on('eventType', myFunc);</code></pre><p>The context of myFunc will be myComponent unless previously bound.
|
||||
Alternatively, you can add a listener to another element or component.</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.on(otherElement, 'eventName', myFunc);
|
||||
myComponent.on(otherComponent, 'eventName', myFunc);</code></pre><p>The benefit of using this over <code>VjsEvents.on(otherElement, 'eventName', myFunc)</code>
|
||||
and <code>otherComponent.on('eventName', myFunc)</code> is that this way the listeners
|
||||
will be automatically cleaned up when either component is disposed.
|
||||
It will also bind myComponent as the context of myFunc.
|
||||
<strong>NOTE</strong>: When using this on elements in the page other than window
|
||||
and document (both permanent), if you remove the element from the DOM
|
||||
you need to call <code>myComponent.trigger(el, 'dispose')</code> on it to clean up
|
||||
references to it and allow the browser to garbage collect it.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>first</td><td>String|Component</td><td>yes</td><td>The event type or other component</td></tr><tr><td>second</td><td>function|String</td><td>yes</td><td>The event handler or event type</td></tr><tr><td>third</td><td>function</td><td>yes</td><td>The event handler</td></tr></tbody></table><p class="vjs-only"><em id="onFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L605">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 605</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsone"><h3 id="oneHeader">one( first, second, [third] )</h3><div id="oneDescription" class="description"><p>Add an event listener to be triggered only once and then removed</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.one('eventName', myFunc);</code></pre><p>Alternatively you can add a listener to another element or component
|
||||
that will be triggered only once.</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.one(otherElement, 'eventName', myFunc);
|
||||
myComponent.one(otherComponent, 'eventName', myFunc);</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>first</td><td>String|Component</td><td>yes</td><td>The event type or other component</td></tr><tr><td>second</td><td>function|String</td><td>yes</td><td>The listener function or event type</td></tr><tr><td>third</td><td>function</td><td>no</td><td>The listener function for other component</td></tr></tbody></table><p class="vjs-only"><em id="oneFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L728">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 728</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsoptions"><h3 id="optionsHeader">options( obj )</h3><div id="optionsDescription" class="description"><p>Deep merge of options objects
|
||||
Whenever a property is an object on both options objects
|
||||
the two properties will be merged using mergeOptions.</p>
|
||||
<pre class="prettyprint source lang-js"><code> Parent.prototype.options_ = {
|
||||
optionSet: {
|
||||
'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
|
||||
'childTwo': {},
|
||||
'childThree': {}
|
||||
}
|
||||
}
|
||||
newOptions = {
|
||||
optionSet: {
|
||||
'childOne': { 'foo': 'baz', 'abc': '123' }
|
||||
'childTwo': null,
|
||||
'childFour': {}
|
||||
}
|
||||
}
|
||||
|
||||
this.options(newOptions);</code></pre><p>RESULT</p>
|
||||
<pre class="prettyprint source lang-js"><code> {
|
||||
optionSet: {
|
||||
'childOne': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' },
|
||||
'childTwo': null, // Disabled. Won't be initialized.
|
||||
'childThree': {},
|
||||
'childFour': {}
|
||||
}
|
||||
}</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>obj</td><td>Object</td><td>yes</td><td>Object of new option values</td></tr></tbody></table><p class="vjs-only"><em id="optionsFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L145">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 145</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsplayer"><h3 id="playerHeader">player()</h3><div id="playerDescription" class="description"><p>Return the component's player</p></div><p class="vjs-only"><em id="playerFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L135">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 135</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsready"><h3 id="readyHeader">ready( fn, sync )</h3><div id="readyDescription" class="description"><p>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.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>fn</td><td>function</td><td>yes</td><td>Ready listener</td></tr><tr><td>sync</td><td>Boolean</td><td>yes</td><td>Exec the listener synchronously if component is ready</td></tr></tbody></table><p class="vjs-only"><em id="readyFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L787">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 787</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsregisterComponent"><h3 id="registerComponentHeader">static registerComponent( name, comp )</h3><div id="registerComponentDescription" class="description"><p>Registers a component</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td>String</td><td>yes</td><td>Name of the component to register</td></tr><tr><td>comp</td><td>Object</td><td>yes</td><td>The component to register</td></tr></tbody></table><p class="vjs-only"><em id="registerComponentFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1314">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1314</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsremoveChild"><h3 id="removeChildHeader">removeChild( component )</h3><div id="removeChildDescription" class="description"><p>Remove a child component from this component's list of children, and the
|
||||
child component's element from this component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>component</td><td>Component</td><td>yes</td><td>Component to remove</td></tr></tbody></table><p class="vjs-only"><em id="removeChildFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L415">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 415</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodsremoveClass"><h3 id="removeClassHeader">removeClass( classToRemove )</h3><div id="removeClassDescription" class="description"><p>Remove a CSS class name from the component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToRemove</td><td>String</td><td>yes</td><td>Classname to remove</td></tr></tbody></table><p class="vjs-only"><em id="removeClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L904">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 904</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodssetInterval"><h3 id="setIntervalHeader">setInterval( fn, interval )</h3><div id="setIntervalDescription" class="description"><p>Creates an interval and sets up disposal automatically.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>fn</td><td>function</td><td>yes</td><td>The function to run every N seconds.</td></tr><tr><td>interval</td><td>Number</td><td>yes</td><td>Number of ms to delay before executing specified function.</td></tr></tbody></table><p class="vjs-only"><em id="setIntervalFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1271">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1271</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodssetTimeout"><h3 id="setTimeoutHeader">setTimeout( fn, timeout )</h3><div id="setTimeoutDescription" class="description"><p>Creates timeout and sets up disposal automatically.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>fn</td><td>function</td><td>yes</td><td>The function to run after the timeout.</td></tr><tr><td>timeout</td><td>Number</td><td>yes</td><td>Number of ms to delay before executing specified function.</td></tr></tbody></table><p class="vjs-only"><em id="setTimeoutFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L1227">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 1227</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodsshow"><h3 id="showHeader">show()</h3><div id="showDescription" class="description"><p>Show the component element if hidden</p></div><p class="vjs-only"><em id="showFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L933">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 933</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodstoggleClass"><h3 id="toggleClassHeader">toggleClass( classToToggle, [predicate] )</h3><div id="toggleClassDescription" class="description"><p>Add or remove a CSS class name from the component's element</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>classToToggle</td><td>String</td></tr><tr><td>predicate</td><td>Boolean|function</td><td>no</td><td>Can be a function that returns a Boolean. If <code>true</code>, the class
|
||||
will be added; if <code>false</code>, the class will be removed. If not
|
||||
given, the class will be added if not present and vice versa.</td></tr></tbody></table><p class="vjs-only"><em id="toggleClassFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L916">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 916</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodstrigger"><h3 id="triggerHeader">trigger( event, [hash] )</h3><div id="triggerDescription" class="description"><p>Trigger an event on an element</p>
|
||||
<pre class="prettyprint source lang-js"><code> myComponent.trigger('eventName');
|
||||
myComponent.trigger({'type':'eventName'});
|
||||
myComponent.trigger('eventName', {data: 'some data'});
|
||||
myComponent.trigger({'type':'eventName'}, {data: 'some data'});</code></pre></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>event</td><td>Event|Object|String</td><td>yes</td><td>A string (the type) or an event object with a type attribute</td></tr><tr><td>hash</td><td>Object</td><td>no</td><td>data hash to pass along with the event</td></tr></tbody></table><p class="vjs-only"><em id="triggerFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L768">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 768</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="MethodstriggerReady"><h3 id="triggerReadyHeader">triggerReady()</h3><div id="triggerReadyDescription" class="description"><p>Trigger the ready listeners</p></div><p class="vjs-only"><em id="triggerReadyFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L814">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 814</a></em></p><p><a href="#top">[back to top]</a></p></div><div id="Methodswidth"><h3 id="widthHeader">width( num, skipListeners )</h3><div id="widthDescription" class="description"><p>Set or get the width of the component (CSS values)
|
||||
Setting the video tag dimension values only works with values in pixels.
|
||||
Percent values will not work.
|
||||
Some percents can be used, but width()/height() will return the number + %,
|
||||
not the actual computed width/height.</p></div><h4>Parameters</h4><table><thead><tr><th>name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>num</td><td>Number|String</td><td>yes</td><td>Optional width number</td></tr><tr><td>skipListeners</td><td>Boolean</td><td>yes</td><td>Skip the 'resize' event trigger</td></tr></tbody></table><p class="vjs-only"><em id="widthFooter">Defined in <a href="https://github.com/videojs/video.js/blob/master/src/js/component.js#L981">https://github.com/videojs/video.js/blob/master/src/js/component.js line number: 981</a></em></p><p><a href="#top">[back to top]</a></p></div></section></div><script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js">
|
||||
// syntax highlighter for code samples
|
||||
</script><script src="./js/highlight-syntax.js">
|
||||
// activates syntax highlighting
|
||||
</script></body></html>
|
||||