#63535 Поддержка Chromecast

This commit is contained in:
Алексей Манаев
2025-07-10 16:13:36 +00:00
parent 207603c5ca
commit 95e48549d4
538 changed files with 2434 additions and 143925 deletions
+1 -1
View File
@@ -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
+1
View File
@@ -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 -1
View File
@@ -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
+57
View File
@@ -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"
}
}
}
}
+2 -1
View File
@@ -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
View File
@@ -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";
+8
View File
@@ -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;
}
}
/**
+9 -1
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
{
"plugins": [ "plugins/markdown" ]
}
+1
View File
@@ -0,0 +1 @@
16.15.0
+16
View File
@@ -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
+42
View File
@@ -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
+20
View File
@@ -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.
+369
View File
@@ -0,0 +1,369 @@
# Silvermine VideoJS Chromecast Plugin
<!-- markdownlint-disable line-length -->
[![Build Status](https://travis-ci.org/silvermine/videojs-chromecast.svg?branch=master)](https://travis-ci.org/silvermine/videojs-chromecast)
[![Coverage Status](https://coveralls.io/repos/github/silvermine/videojs-chromecast/badge.svg?branch=master)](https://coveralls.io/github/silvermine/videojs-chromecast?branch=master)
[![Dependency Status](https://david-dm.org/silvermine/videojs-chromecast.svg)](https://david-dm.org/silvermine/videojs-chromecast)
[![Dev Dependency Status](https://david-dm.org/silvermine/videojs-chromecast/dev-status.svg)](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>
+73
View File
@@ -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"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

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));
});
};
+33
View File
@@ -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';
-22
View File
@@ -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
}
]
]
}
-11
View File
@@ -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
-11
View File
@@ -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
-44
View File
@@ -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/
-70
View File
@@ -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,
},
};
-8
View File
@@ -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
View File
@@ -1 +0,0 @@
14
-1
View File
@@ -1 +0,0 @@
CHANGELOG.md
-84
View File
@@ -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;
-4398
View File
File diff suppressed because it is too large Load Diff
-3
View File
@@ -1,3 +0,0 @@
# Video.js® Code of Conduct
Please refer to: <https://github.com/videojs/admin/blob/main/CODE_OF_CONDUCT.md>
-3
View File
@@ -1,3 +0,0 @@
# Video.js® Collaborator Guide
Please refer to: <https://github.com/videojs/admin/blob/main/COLLABORATOR_GUIDE.md>
-3
View File
@@ -1,3 +0,0 @@
# Video.js® Contributor Guide
Please refer to: <https://github.com/videojs/admin/blob/main/CONTRIBUTING.md>
-13
View File
@@ -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.
-142
View File
@@ -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
-48
View File
@@ -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);
});
-35
View File
@@ -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');
};
-19
View File
@@ -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');
};
-66
View File
@@ -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;
}
-43
View File
@@ -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
});
});
-12
View File
@@ -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 + '>';
});
});
}
};
-13
View File
@@ -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'
);
}
};
-11
View File
@@ -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>
<% } %> */
-48
View File
@@ -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');
-23
View File
@@ -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'));
}
-38
View File
@@ -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`));
-16
View File
@@ -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');
-41
View File
@@ -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, '');
}
};
}
-31
View File
@@ -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');
}
-27
View File
@@ -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);
});
-54
View File
@@ -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');
-13
View File
@@ -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"
}
-27
View File
@@ -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
-41
View File
@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Video.js Text Descriptions, Chapters &amp; 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>
-18
View File
@@ -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 &amp; 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 ]
-23
View File
@@ -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>
-29
View File
@@ -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);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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>
File diff suppressed because one or more lines are too long
-11
View File
@@ -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>
-172
View File
@@ -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>
-160
View File
@@ -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>

Some files were not shown because too many files have changed in this diff Show More