Comparar commits

...

61 Commits

Autor SHA1 Mensagem Data
Gary Katsevman 14ae1e9658 6.2.3 2017-07-14 15:41:59 -04:00
Gary Katsevman b1ac2e0249 chore(gh-release): add prerelease flag and find right zip (#4488)
Add a --prerelease flag so we can run gh-release.js manually and mark releases as prerelease.
Also, get the correct zip file.
2017-07-14 15:27:48 -04:00
Gary Katsevman 269e504d26 6.2.2 2017-07-14 14:56:58 -04:00
Gary Katsevman 971f633c73 chore(package): update rollup to version 0.45.2 (#4487)
Closes #4475
2017-07-14 14:43:58 -04:00
Gary Katsevman 03fd402ea9 docs: make jsdoc generate anchor names so ToC links work (#4471)
Also, run some more explicit replacement queries so all ToC links work if they're generated differently from gfm.
2017-07-14 14:22:02 -04:00
Gary Katsevman 3a600d0eea chore: add automatic github release (#4466)
This will automatically do a github release with the correct changelog entry and the built zip file.
If a publish is made with `--tag next` it will mark the release as a pre-release.

To use, just add `VJS_GITHUB_USER` and `VJS_GITHUB_TOKEN` env variables as part of the publish command:
```sh
$ VJS_GITHUB_USER=gkatsev VJS_GITHUB_TOKEN=test_token npm publish --tag next
```
2017-07-14 14:21:07 -04:00
Alex Barstow 1e80e59614 test: add unit tests for player.duration() (#4459)
Unit tests for https://github.com/videojs/video.js/pull/4443
2017-07-14 14:20:37 -04:00
Pat O'Neill 7579fc1800 docs: Fix Player#src API documentation. (#4454) 2017-07-14 14:20:00 -04:00
Gary Katsevman 4f43616160 fix(playback rate menu): cycling rates via click (#4486)
In 6.0, we changed the way that Menu Buttons were being created by
wrapping an actual button with a menu sibling in a container. The
playback rate menu also had a rate value display. In 6.x, this rate
value display ended up coming on top of the button itself and capturing
it's clicks. So, we want to remove pointer-events from the rate-value
display and resize the actual button to be the size of the control.
2017-07-14 14:18:23 -04:00
Gary Katsevman 687aae50ff chore: switch to using chrome for testing PRs on travis (#4462) 2017-07-05 09:44:43 +10:00
Aeoril 6986dbb851 chore(build): remove unused var in build/version.js (#4458) 2017-07-04 11:11:29 +10:00
Gary Katsevman 39ff0f4fb6 6.2.1 2017-06-28 16:58:10 +10:00
Gary Katsevman 82c8b80548 fix: auto-removal remote text tracks being removed when not supposed to (#4450)
We added a feature so that remote text tracks can auto-removed when a source changes. However, in 6.x we changed the source behavior to be asynchronous meaning that some text tracks were accidentally being removed when they weren't supposed to be.
For example:
```js
var player = videojs('my-player');
player.src({src: 'video.mp4', type: 'video/mp4'});
 // set second arg to false so that they get auto-removed on source change
player.addRemoteTextTrack({kind: 'captions', src: 'text.vtt', srclang: 'en'}, false);
```
Now when the player loads, this captions track is actually missing because it was removed.

Instead of adding auto-removal tracks immediately to the list, wait until we've selected a source before adding them in.


Fixes #4403 and #4315.
2017-06-28 16:38:29 +10:00
Alex Barstow f5cc165cad fix: player.duration() should return NaN if duration is not known (#4443)
player.duration() currently returns 0 if the duration is not known, when it should return NaN. The problem is that if NaN is passed to player.duration() as an argument, we set the duration to 0. If player.cache_.duration was set to NaN by other means, player.duration() would still return 0.

Modify the player duration() method so that it will 1.) set the cached duration to NaN if it is passed in as an argument, and 2.) return the proper value when called without an argument.
2017-06-28 16:37:00 +10:00
mister-ben b4dc4f85b0 fix: Use passive event listeners for touchstart/touchmove (#4440)
If passive event listening is supported, we should use it.

Fixes #4432.
2017-06-28 16:36:06 +10:00
mister-ben b63666379d fix: Safari picture-in-picture triggers fullscreenchange (#4437)
When picture-in-picture mode is entered on Safari, `webkitbeginfullscreen` is triggered which results in a proxied `fullscreenchange` event and adding the fullscreen class to the player. That causes the tech element to collapse to zero height so that the "this video is playing in picture in picture" placeholder is not visible.
On `webkitbeginfullscreen` check whether the presentation mode is `picture-in-picture` before proxying `fullscreenchange` event.
2017-06-28 16:35:01 +10:00
Pat O'Neill 77ba3d13d9 perf: Various small performance improvements. (#4426)
These are a few performance improvements.

* Use textContent instead of innerHTML for text content.
* Construct TextTrackSettings content with HTML strings where possible because it's a bit faster than manual DOM construction.
* Do minimal DOM updates to time controls. This reduces our timeupdate footprint from ~2-2.5ms to ~1ms!
2017-06-28 16:32:58 +10:00
Jet Fontanilla 7f7ea70cb7 fix: IE10 issue for disableOthers when property access results in "permission denied" (#4395)
Fixes #4378
2017-06-28 16:32:04 +10:00
mister-ben e0824c8294 fix: Update translations to match correct string (#4383)
The lang files were translating "all settings to the default values" instead of "restore all settings to the default values".
2017-06-28 16:31:44 +10:00
Pat O'Neill cc6e82442f docs: Fix links in API docs for several Player events. (#4427) 2017-06-27 09:53:08 +10:00
Caley Shem-Crumrine 97021554cd docs: Update name of FullscreenToggle in documentation (#4410) 2017-06-27 09:52:05 +10:00
Pat O'Neill c4bbe5d120 chore(sandbox): Fix paths in sandbox files. (#4416) 2017-06-27 09:51:05 +10:00
Gary Katsevman 66a0d23e05 chore(package): update husky to version 0.14.1 (#4444)
Closes #4436
2017-06-27 09:44:28 +10:00
greenkeeper[bot] 4bce4a2954 chore(package): update rollup-watch to version 4.0.0 (#4396) 2017-06-27 09:43:42 +10:00
greenkeeper[bot] f87b12c3af chore(package): update rollup to version 0.42.0 (#4392) 2017-06-27 09:43:18 +10:00
ldayananda 9329e3ef8e docs: Fixing player.remoteTextTracks jsdoc (#4417)
Fixes the sidebar link on the docs site for remoteTextTracks.
2017-06-19 16:01:01 -04:00
Gary Katsevman 546bef5321 6.2.0 2017-05-30 15:25:58 -04:00
Gary Katsevman c31836c30c feat: Use Rollup to generate dist files (#4301) 2017-05-25 19:40:35 -04:00
Gary Katsevman a5a68e819a chore: update translations needed (#4380) 2017-05-25 18:32:17 -04:00
greenkeeper[bot] 98160700e5 chore(package): update videojs-flash to version 2.0.0 (#4375) 2017-05-25 18:16:31 -04:00
h0lysl4y3r e5e1c7f269 feat(lang): Create sk.json (#4374) 2017-05-25 18:16:23 -04:00
Hollton 0c16c5f3cf feat(lang): Update zh-CN.json (#4370) 2017-05-25 18:16:01 -04:00
greenkeeper[bot] d57f09f7cf chore(package): update grunt-contrib-cssmin to version 2.2.0 (#4345) 2017-05-25 18:15:42 -04:00
Adrian P. Blunier 2a26c7f87b feat(lang): Adding galician (#4334) 2017-05-25 18:15:33 -04:00
ldayananda eade52e174 test(TextTrackDisplay): Removing incorrect test techOrder (#4379) 2017-05-25 18:05:45 -04:00
ldayananda 188ead1c81 feat: Persist caption/description choice over source changes in emulated tracks (#4295) 2017-05-25 14:09:00 -04:00
Gary Katsevman 8f67b4fc54 6.1.0 2017-05-15 14:35:23 -04:00
Gary Katsevman cb6005eca4 fix: only disable user-selection on sliders (#4354) 2017-05-15 12:04:42 -04:00
Alex Barstow 8d80a5846e feat: add 'playsinline' player option (#4348)
Video.js players can accept a number of standard <video> element options (autoplay, muted, loop, etc), but not currently playsinline, which is now part of the [HTML spec](https://html.spec.whatwg.org/multipage/embedded-content.html#attr-video-playsinline). We should add it to the list of <video> attributes that can be provided to the player as options.
2017-05-12 16:39:37 -04:00
Gary Katsevman 35df35143f feat: deprecate firstplay event (#4353) 2017-05-12 16:38:48 -04:00
Martin Bachwerk 3087830ed7 fix: Only update text track mode if changed (#4298) 2017-05-12 16:35:39 -04:00
Garrett 483e5a2ca5 feat: Add getVideoPlaybackQuality API (#4338)
Provides a tech getter for getVideoPlaybackQuality as specified by the W3C's Media Playback Quality API: https://wicg.github.io/media-playback-quality/.
2017-05-12 15:22:02 -04:00
Gary Katsevman 3dcfa9568a fix: TextTrackButton on Safari and iOS (#4350)
On Safari and iOS, we use native text tracks, so, during text track
button creation, textTracks() is populated. However, `this.kinds_` isn't
necessarily set and ends up throwing.

Instead, we want to move the fallback for `this.kinds_` from the
constructor and right above the usage of `this.kinds_`.
2017-05-12 14:51:12 -04:00
greenkeeper[bot] b5c60f339b fix(package): update global to version 4.3.2 (#4291)
https://greenkeeper.io/
2017-05-11 17:52:30 -04:00
mister-ben 03bab83dde fix: prevent dupe events on enabled ClickableComponents (#4316)
Prevent ClickableComponents re-adding event listeners each time enabled() is called.

* Keeps track of enabled state (this.enabled_)
* enable() doesn't do anything if the component is enabled, so the event handlers are not re-added

Fixes #4312
2017-05-11 17:32:20 -04:00
Owen Edwards f773c473f9 chore: Fix examples and docs and some links (#4279)
* Fix the doc/example/elephantsdream/index.html file, add an index of doc/examples, and update CDN links to use video.js v5.19.
* Add poster from CDN to Elephants Dream examples.
2017-05-11 17:16:12 -04:00
mister-ben ae423df4f5 feat: Add a version class to the player (#4320)
Adds `vjs-v6` class so you can target that version of Video.js.
2017-05-11 17:15:12 -04:00
Pat O'Neill 0a19cf0d6a feat: Add 'beforepluginsetup' event and named plugin setup events (e.g. 'pluginsetup:foo') (#4255)
This adds a beforepluginsetup event as well as beforepluginsetup:$name and pluginsetup:$name events.

The drive behind this is improving the ability for people to make cross-plugin dependencies in a more robust manner.
2017-05-11 17:13:22 -04:00
Stéphane Roucheray da1d8613d7 chore: typo soruce -> source (#4307) 2017-05-11 17:00:59 -04:00
mister-ben da0f1ee681 feat: remove playbackRate blacklist for recent Android Chrome (#4321)
Android Chrome now supports playbackRate properly, so removes the blacklist added in #3246 for newer Chrome versions.
Adds `browser.CHROME_VERSION` as a necessary evil.
No longer blacklists for Chrome 58+ -- this could possibly be fixed since 52, but 58 is all I've been able to test on and most users should keep Chrome up to date.
2017-05-11 16:59:22 -04:00
Dave Kiss cff2e503ef docs(react-guide): Use a React component as a VJS component (#4287) 2017-05-11 16:33:28 -04:00
Brandon Casey 561d5ddf76 fix a comment typo (#4293) 2017-04-19 23:56:07 -04:00
Gary Katsevman d6e56e9222 6.0.1 2017-04-13 16:58:11 -04:00
Gary Katsevman 7490a499ce chore: add slack travis notifications (#4282) 2017-04-13 12:23:31 -04:00
Matthew Neil 1ea00419c9 fix: set IE_VERSION correctly for IE11 (#4281)
videojs.browser.IE_VERSION is null in IE11 because IE11 uses a different user agent string than other IE versions

Fixes #4278
2017-04-13 11:28:03 -04:00
Aaron Chamberlain 230743ecb1 docs: add a Webpack usage guide (#4261) 2017-04-12 18:16:41 -04:00
Garrett 39fd73f781 docs: remove mentions of bower support (#4274)
Since video.js 6 no longer officially supports bower (#4012), remove some old mentions in the docs of bower.
2017-04-12 18:15:54 -04:00
Gary Katsevman 92e5d9fb5a fix: techOrder names can be camelCased. (#4277)
In the new middleware work, the way that new sources were loaded was refactored. We also recently made techs and components work either TitleCased or camelcased. There was one comparison that didn't do the proper check and cause the tech to be reloaded, even if the two techs were the same.
2017-04-12 17:17:33 -04:00
Dennis JongHyuck Won 083f643e63 chore: gitignore all npm-debug.log.* (#4252) 2017-04-07 13:41:30 -04:00
Alex Barstow 02721c7c03 docs(component): Replace VolumeMenuButton with VolumePanel in component tree (#4267)
Video.js 6 has switch to using the VolumePanel instead of the VolumeMenuButton.

Fixes #4266
2017-04-07 13:39:57 -04:00
Gary Katsevman c20ca5cc97 chore(changelog): Update CHANGELOG with v5 changes (#4257) 2017-04-07 13:38:39 -04:00
75 arquivos alterados com 2486 adições e 509 exclusões
+6 -2
Ver Arquivo
@@ -1,4 +1,8 @@
{
"presets": [ "es3", ["es2015", {"loose": true}] ],
"plugins": ["inline-json"]
"presets": [
"es3",
["es2015", {
"loose": true
}]
]
}
+1 -1
Ver Arquivo
@@ -10,7 +10,7 @@ test/*.map
.s3config.json
node_modules
npm-debug.log
npm-debug.log*
sandbox/*
!sandbox/*.example
+2 -1
Ver Arquivo
@@ -35,6 +35,7 @@
},
"plugins": ["plugins/markdown"],
"markdown": {
"tags": ["example"]
"tags": ["example"],
"idInHeadings": true
}
}
+11 -1
Ver Arquivo
@@ -2,9 +2,13 @@ language: node_js
node_js:
- 4.4
before_install:
- export CHROME_BIN=chromium-browser
- export CHROME_BIN=/usr/bin/google-chrome
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
after_failure:
- npm ls --depth=1
after_success:
- npm run assets
notifications:
irc:
channels:
@@ -13,6 +17,8 @@ notifications:
on_success: never
webhooks:
- http://pam.videojs.com/savage/travis
slack:
secure: LrF8K6mCYWlUt6SvdbGHazyQZSk/opKoiB/wgoGYaGc9+3wYXkVexY0WkO1m6wBKhUqXRAMVMFszr1wqKgdcxtItmFMMj8HqTLI1MVqgKqYX4Ux3CnEHJQiwxIk0aVL7lHLsZTXV/2Y0QIOYmAnCrgy46klETrk0ZuXf5okpu2Q=
env:
global:
- secure: K6JpKwMkfNaJix3Bb0tLjVMzHMJgtBXdd/dvfw1BMb9DCBpd81PqXbDs7yXCddUxnUPTBPxZCrQgWsw71Wn+qEoIG5MU3uOT5A2rBbx/yZonVAGv5ed/9w0xk0OzO383CmPMFqwqtp9YmdmqGjQBkYXVXJjTvNTOAExFSdhO+3U=
@@ -20,8 +26,12 @@ env:
- secure: gglh7xDnURKfXp9T543DD7NG1pQ8HeWh1XtRspBAwr0H7RqJBVDqqODSYSPRFhfld7M6sYmvQIXgil7XlyefnKNTXqCarvaoTg3lbip8kSltXMiNw2V6AVpsQGuja7+XbaM0do70ETTKjW4Kw6wnxEHb78BvGN/hXIeqizUAjanlDAjd7fouaxpTBIbMESe2rI+WRHPis1cmnv8v70Mrh/8Un/NO4gkebGyvA47LTDNIaVqIVjonsndr8WjMv1/PNxQ8LyCO6D64MufrobS7Sec+VuN30apwEsBw8v82MK/MZ3qXu0lUp4+ERTbuc/rymh2wDFTQeG20Kf/NTauSaH6f414KNzIRFj0/xyLAzVZKIscXM2DKXMuskkZuvHLZvaspnZWcPYTjPZl0P88N0RBqnoLdR80dR5bDljNwU2QnSBeol/q1wXNEr6I1VTRFOB+qsHrD1blVMB1I5W3I0ti1aQ7XtgMOGi1kcPb4oFcJdl+3dLFDnyRyaNfdMOnOZYBBHdQCo19Mj/L+nqPGWeeYiEAM6JsuhNjHn5Za5nGf1ztXTimVPOQjyATin0x9kST3soLWSVmdW2dBHUGDVSMhvoLLR+nKSdNQ0KfpqtgrzeLxoVnRYHVBlih41tapM9IG/6BMYnDMaRcc0i54YeUP4oxlxGSyASIenkAgC6w=
- secure: WtIEOSnqDkCZuTlBsxwlVwaRpVTbz7ol8+XSJIZb0aFo1lLisF9cz6s9WrAfX36MaxIcDN9LFZkpXzMvNrNkZWQa1kacGWH1rbx0SiiQ8LMweAcKdnZ5uXlSplBxbJ8bZfXKB1sIHsOsYw/vWhHKkcsDUkAEzQrIiMOhuoUV3s0uKM0knKXIAfNIF0EbDzLIojm+nm+F0n5vM60LRdKesaSt/o2p2LKxdZVoFGrg48D7bdA9VEfMWWRL/evDxJmnX4p+AjBc7mklqZ5F2pYsY6XXQuuS+2Sy+lnxz01kLg+RC4Cpv5dyYfK3h0j8KeyK8IuixycVONWVe9rANq8UaIsMrRN+6uDSC8zXiH4P+h6UDMm3jetc2ZyAfhBA8OyIs5QEShae2Rd7Y3WFJxBp6UVgyj6SkXGxrEdb1ZJgTTl4dyqiP0bYrLePNP2qSJ6OTfNdG791HF077uzXI96ABdMG54Wv9N9T/hmxKwV2Lajx/GZJMmHuwT9tkHKhkcxWea1HYam9QYSFUyJ5THfNk2A9u/r8DkL62MZ85zIQBisrlFjbPAGRejq6qyirBJPAy+FCjhM+oO/i2f2bGkkAfHGT0Og1BcrWVXs54yWdO7UZgie2F+Rmdwinb/GxebZJ+21ZQ4OkVr2t1Skr/PRni9+U7q/6xCLwUJgx45XJ0FE=
sudo: false
dist: trusty
cache:
directories:
- node_modules
addons:
firefox: latest
apt:
packages:
- google-chrome-stable
+211
Ver Arquivo
@@ -1,3 +1,132 @@
<a name="6.2.3"></a>
## [6.2.3](https://github.com/videojs/video.js/compare/v6.2.2...v6.2.3) (2017-07-14)
### Chores
* **gh-release:** add prerelease flag and find right zip ([#4488](https://github.com/videojs/video.js/issues/4488)) ([b1ac2e0](https://github.com/videojs/video.js/commit/b1ac2e0))
<a name="6.2.2"></a>
## [6.2.2](https://github.com/videojs/video.js/compare/v6.2.1...v6.2.2) (2017-07-14)
### Bug Fixes
* **playback rate menu:** cycling rates via click ([#4486](https://github.com/videojs/video.js/issues/4486)) ([4f43616](https://github.com/videojs/video.js/commit/4f43616))
### Chores
* **build:** remove unused var in build/version.js ([#4458](https://github.com/videojs/video.js/issues/4458)) ([6986dbb](https://github.com/videojs/video.js/commit/6986dbb))
* add automatic github release ([#4466](https://github.com/videojs/video.js/issues/4466)) ([3a600d0](https://github.com/videojs/video.js/commit/3a600d0))
* switch to using chrome for testing PRs on travis ([#4462](https://github.com/videojs/video.js/issues/4462)) ([687aae5](https://github.com/videojs/video.js/commit/687aae5))
* **package:** update rollup to version 0.45.2 ([#4487](https://github.com/videojs/video.js/issues/4487)) ([971f633](https://github.com/videojs/video.js/commit/971f633)), closes [#4475](https://github.com/videojs/video.js/issues/4475)
### Documentation
* Fix Player#src API documentation. ([#4454](https://github.com/videojs/video.js/issues/4454)) ([7579fc1](https://github.com/videojs/video.js/commit/7579fc1))
* make jsdoc generate anchor names so ToC links work ([#4471](https://github.com/videojs/video.js/issues/4471)) ([03fd402](https://github.com/videojs/video.js/commit/03fd402))
### Tests
* add unit tests for player.duration() ([#4459](https://github.com/videojs/video.js/issues/4459)) ([1e80e59](https://github.com/videojs/video.js/commit/1e80e59))
<a name="6.2.1"></a>
## [6.2.1](https://github.com/videojs/video.js/compare/v6.2.0...v6.2.1) (2017-06-28)
### Bug Fixes
* auto-removal remote text tracks being removed when not supposed to ([#4450](https://github.com/videojs/video.js/issues/4450)) ([82c8b80](https://github.com/videojs/video.js/commit/82c8b80)), closes [#4403](https://github.com/videojs/video.js/issues/4403) [#4315](https://github.com/videojs/video.js/issues/4315)
* IE10 issue for disableOthers when property access results in "permission denied" ([#4395](https://github.com/videojs/video.js/issues/4395)) ([7f7ea70](https://github.com/videojs/video.js/commit/7f7ea70)), closes [#4378](https://github.com/videojs/video.js/issues/4378)
* player.duration() should return NaN if duration is not known ([#4443](https://github.com/videojs/video.js/issues/4443)) ([f5cc165](https://github.com/videojs/video.js/commit/f5cc165))
* Safari picture-in-picture triggers fullscreenchange ([#4437](https://github.com/videojs/video.js/issues/4437)) ([b636663](https://github.com/videojs/video.js/commit/b636663))
* Update translations to match correct string ([#4383](https://github.com/videojs/video.js/issues/4383)) ([e0824c8](https://github.com/videojs/video.js/commit/e0824c8))
* Use passive event listeners for touchstart/touchmove ([#4440](https://github.com/videojs/video.js/issues/4440)) ([b4dc4f8](https://github.com/videojs/video.js/commit/b4dc4f8)), closes [#4432](https://github.com/videojs/video.js/issues/4432)
### Chores
* **package:** update husky to version 0.14.1 ([#4444](https://github.com/videojs/video.js/issues/4444)) ([66a0d23](https://github.com/videojs/video.js/commit/66a0d23)), closes [#4436](https://github.com/videojs/video.js/issues/4436)
* **package:** update rollup to version 0.42.0 ([#4392](https://github.com/videojs/video.js/issues/4392)) ([f87b12c](https://github.com/videojs/video.js/commit/f87b12c))
* **package:** update rollup-watch to version 4.0.0 ([#4396](https://github.com/videojs/video.js/issues/4396)) ([4bce4a2](https://github.com/videojs/video.js/commit/4bce4a2))
* **sandbox:** Fix paths in sandbox files. ([#4416](https://github.com/videojs/video.js/issues/4416)) ([c4bbe5d](https://github.com/videojs/video.js/commit/c4bbe5d))
### Documentation
* Fix links in API docs for several Player events. ([#4427](https://github.com/videojs/video.js/issues/4427)) ([cc6e824](https://github.com/videojs/video.js/commit/cc6e824))
* Fixing player.remoteTextTracks jsdoc ([#4417](https://github.com/videojs/video.js/issues/4417)) ([9329e3e](https://github.com/videojs/video.js/commit/9329e3e))
* Update name of FullscreenToggle in documentation ([#4410](https://github.com/videojs/video.js/issues/4410)) ([9702155](https://github.com/videojs/video.js/commit/9702155))
### Performance Improvements
* Various small performance improvements. ([#4426](https://github.com/videojs/video.js/issues/4426)) ([77ba3d1](https://github.com/videojs/video.js/commit/77ba3d1))
<a name="6.2.0"></a>
# [6.2.0](https://github.com/videojs/video.js/compare/v6.1.0...v6.2.0) (2017-05-30)
### Features
* Persist caption/description choice over source changes in emulated tracks ([#4295](https://github.com/videojs/video.js/issues/4295)) ([188ead1](https://github.com/videojs/video.js/commit/188ead1))
* **lang:** Adding galician ([#4334](https://github.com/videojs/video.js/issues/4334)) ([2a26c7f](https://github.com/videojs/video.js/commit/2a26c7f))
* **lang:** Create sk.json ([#4374](https://github.com/videojs/video.js/issues/4374)) ([e5e1c7f](https://github.com/videojs/video.js/commit/e5e1c7f))
* **lang:** Update zh-CN.json ([#4370](https://github.com/videojs/video.js/issues/4370)) ([0c16c5f](https://github.com/videojs/video.js/commit/0c16c5f))
* Use Rollup to generate dist files ([#4301](https://github.com/videojs/video.js/issues/4301)) ([c31836c](https://github.com/videojs/video.js/commit/c31836c))
### Chores
* **package:** update grunt-contrib-cssmin to version 2.2.0 ([#4345](https://github.com/videojs/video.js/issues/4345)) ([d57f09f](https://github.com/videojs/video.js/commit/d57f09f))
* **package:** update videojs-flash to version 2.0.0 ([#4375](https://github.com/videojs/video.js/issues/4375)) ([9816070](https://github.com/videojs/video.js/commit/9816070))
* update translations needed ([#4380](https://github.com/videojs/video.js/issues/4380)) ([a5a68e8](https://github.com/videojs/video.js/commit/a5a68e8))
### Tests
* **TextTrackDisplay:** Removing incorrect test techOrder ([#4379](https://github.com/videojs/video.js/issues/4379)) ([eade52e](https://github.com/videojs/video.js/commit/eade52e))
<a name="6.1.0"></a>
# [6.1.0](https://github.com/videojs/video.js/compare/v6.0.1...v6.1.0) (2017-05-15)
### Features
* Add 'beforepluginsetup' event and named plugin setup events (e.g. 'pluginsetup:foo') ([#4255](https://github.com/videojs/video.js/issues/4255)) ([0a19cf0](https://github.com/videojs/video.js/commit/0a19cf0))
* add 'playsinline' player option ([#4348](https://github.com/videojs/video.js/issues/4348)) ([8d80a58](https://github.com/videojs/video.js/commit/8d80a58))
* Add a version class to the player ([#4320](https://github.com/videojs/video.js/issues/4320)) ([ae423df](https://github.com/videojs/video.js/commit/ae423df))
* Add getVideoPlaybackQuality API ([#4338](https://github.com/videojs/video.js/issues/4338)) ([483e5a2](https://github.com/videojs/video.js/commit/483e5a2))
* deprecate firstplay event ([#4353](https://github.com/videojs/video.js/issues/4353)) ([35df351](https://github.com/videojs/video.js/commit/35df351))
* remove playbackRate blacklist for recent Android Chrome ([#4321](https://github.com/videojs/video.js/issues/4321)) ([da0f1ee](https://github.com/videojs/video.js/commit/da0f1ee))
### Bug Fixes
* **package:** update global to version 4.3.2 ([#4291](https://github.com/videojs/video.js/issues/4291)) ([b5c60f3](https://github.com/videojs/video.js/commit/b5c60f3))
* only disable user-selection on sliders ([#4354](https://github.com/videojs/video.js/issues/4354)) ([cb6005e](https://github.com/videojs/video.js/commit/cb6005e))
* Only update text track mode if changed ([#4298](https://github.com/videojs/video.js/issues/4298)) ([3087830](https://github.com/videojs/video.js/commit/3087830))
* prevent dupe events on enabled ClickableComponents ([#4316](https://github.com/videojs/video.js/issues/4316)) ([03bab83](https://github.com/videojs/video.js/commit/03bab83)), closes [#4312](https://github.com/videojs/video.js/issues/4312)
* TextTrackButton on Safari and iOS ([#4350](https://github.com/videojs/video.js/issues/4350)) ([3dcfa95](https://github.com/videojs/video.js/commit/3dcfa95))
### Chores
* Fix examples and docs and some links ([#4279](https://github.com/videojs/video.js/issues/4279)) ([f773c47](https://github.com/videojs/video.js/commit/f773c47))
* typo soruce -> source ([#4307](https://github.com/videojs/video.js/issues/4307)) ([da1d861](https://github.com/videojs/video.js/commit/da1d861))
### Documentation
* **react-guide:** Use a React component as a VJS component ([#4287](https://github.com/videojs/video.js/issues/4287)) ([cff2e50](https://github.com/videojs/video.js/commit/cff2e50))
<a name="6.0.1"></a>
## [6.0.1](https://github.com/videojs/video.js/compare/v6.0.0...v6.0.1) (2017-04-13)
### Bug Fixes
* set IE_VERSION correctly for IE11 ([#4281](https://github.com/videojs/video.js/issues/4281)) ([1ea0041](https://github.com/videojs/video.js/commit/1ea0041)), closes [#4278](https://github.com/videojs/video.js/issues/4278)
* techOrder names can be camelCased. ([#4277](https://github.com/videojs/video.js/issues/4277)) ([92e5d9f](https://github.com/videojs/video.js/commit/92e5d9f))
### Chores
* **changelog:** Update CHANGELOG with v5 changes ([#4257](https://github.com/videojs/video.js/issues/4257)) ([c20ca5c](https://github.com/videojs/video.js/commit/c20ca5c))
* add slack travis notifications ([#4282](https://github.com/videojs/video.js/issues/4282)) ([7490a49](https://github.com/videojs/video.js/commit/7490a49))
* gitignore all npm-debug.log.* ([#4252](https://github.com/videojs/video.js/issues/4252)) ([083f643](https://github.com/videojs/video.js/commit/083f643))
### Documentation
* **component:** Replace VolumeMenuButton with VolumePanel in component tree ([#4267](https://github.com/videojs/video.js/issues/4267)) ([02721c7](https://github.com/videojs/video.js/commit/02721c7)), closes [#4266](https://github.com/videojs/video.js/issues/4266)
* add a Webpack usage guide ([#4261](https://github.com/videojs/video.js/issues/4261)) ([230743e](https://github.com/videojs/video.js/commit/230743e))
* remove mentions of bower support ([#4274](https://github.com/videojs/video.js/issues/4274)) ([39fd73f](https://github.com/videojs/video.js/commit/39fd73f))
<a name="6.0.0"></a>
# [6.0.0](https://github.com/videojs/video.js/compare/v5.16.0...v6.0.0) (2017-04-03)
@@ -183,6 +312,88 @@
* button component will always use a button element.
* `play()` no longer returns the player object but instead the native Promise or nothing.
<a name="5.19.1"></a>
## [5.19.1](https://github.com/videojs/video.js/compare/v5.19.0...v5.19.1) (2017-03-27)
### Bug Fixes
* not showing default text tracks over video ([#4217](https://github.com/videojs/video.js/issues/4217)) ([4653922](https://github.com/videojs/video.js/commit/4653922))
* removeCue should work with native passed in cue ([#4209](https://github.com/videojs/video.js/issues/4209)) ([3974944](https://github.com/videojs/video.js/commit/3974944))
### Chores
* **package:** update videojs-vtt.js to 0.12.3 ([#4223](https://github.com/videojs/video.js/issues/4223)) ([ad770fb](https://github.com/videojs/video.js/commit/ad770fb))
<a name="5.19.0"></a>
# [5.19.0](https://github.com/videojs/video.js/compare/v5.18.4...v5.19.0) (2017-03-15)
### Features
* Make pause on open optional for ModalDialog via options ([#4187](https://github.com/videojs/video.js/issues/4187)) ([4ec3b56](https://github.com/videojs/video.js/commit/4ec3b56))
### Bug Fixes
* make load progress buffered regions height 100% ([#4191](https://github.com/videojs/video.js/issues/4191)) ([398c6e9](https://github.com/videojs/video.js/commit/398c6e9))
* make sure audio track hides with one item ([#4203](https://github.com/videojs/video.js/issues/4203)) ([c069655](https://github.com/videojs/video.js/commit/c069655))
<a name="5.18.4"></a>
## [5.18.4](https://github.com/videojs/video.js/compare/v5.18.3...v5.18.4) (2017-03-08)
### Bug Fixes
* **vttjs:** wait till tech el in DOM before loading vttjs ([#4176](https://github.com/videojs/video.js/issues/4176)) ([ad86eec](https://github.com/videojs/video.js/commit/ad86eec))
<a name="5.18.3"></a>
## [5.18.3](https://github.com/videojs/video.js/compare/v5.18.2...v5.18.3) (2017-03-06)
<a name="5.18.1"></a>
## [5.18.1](https://github.com/videojs/video.js/compare/v5.18.0...v5.18.1) (2017-03-03)
### Bug Fixes
* **cues:** only copy cue props that don't exist ([#4146](https://github.com/videojs/video.js/issues/4146)) ([de08669](https://github.com/videojs/video.js/commit/de08669))
* cue-points with a startTime of 0 ([#4148](https://github.com/videojs/video.js/issues/4148)) ([e7d4b47](https://github.com/videojs/video.js/commit/e7d4b47))
* make sure that cues copy over their id ([#4154](https://github.com/videojs/video.js/issues/4154)) ([072c277](https://github.com/videojs/video.js/commit/072c277))
* **MenuButton:** Unify behavior of showing/hiding ([#3993](https://github.com/videojs/video.js/issues/3993)) ([4367c69](https://github.com/videojs/video.js/commit/4367c69))
* **playback rate menu:** playback rate menu items should be selectable ([#4150](https://github.com/videojs/video.js/issues/4150)) ([288edd1](https://github.com/videojs/video.js/commit/288edd1))
### Chores
* **build:** lint errors only and silence webpack ([#4153](https://github.com/videojs/video.js/issues/4153)) ([b1ca344](https://github.com/videojs/video.js/commit/b1ca344))
* **package:** update video-js-swf to 5.3.0 ([#4161](https://github.com/videojs/video.js/issues/4161)) ([2bcfe21](https://github.com/videojs/video.js/commit/2bcfe21))
<a name="5.18.0"></a>
# [5.18.0](https://github.com/videojs/video.js/compare/v5.17.0...v5.18.0) (2017-02-27)
### Features
* focus play toggle from Big Play Btn on play ([#4132](https://github.com/videojs/video.js/issues/4132)) ([dcc615a](https://github.com/videojs/video.js/commit/dcc615a)), closes [#2729](https://github.com/videojs/video.js/issues/2729)
* update videojs-vtt.js and wrap native cues in TextTrack ([#4131](https://github.com/videojs/video.js/issues/4131)) ([3d4aebc](https://github.com/videojs/video.js/commit/3d4aebc)), closes [#4093](https://github.com/videojs/video.js/issues/4093)
### Bug Fixes
* **sass:** import path has cwd once again ([#4076](https://github.com/videojs/video.js/issues/4076)) ([c02c6c6](https://github.com/videojs/video.js/commit/c02c6c6))
* addChild instance names should be toTitleCased ([#4117](https://github.com/videojs/video.js/issues/4117)) ([fa97309](https://github.com/videojs/video.js/commit/fa97309))
* make mergeOptions behave the same across browsers ([#4090](https://github.com/videojs/video.js/issues/4090)) ([ce19ed5](https://github.com/videojs/video.js/commit/ce19ed5))
* synchronously shim vtt.js when possible ([#4082](https://github.com/videojs/video.js/issues/4082)) ([b5727a6](https://github.com/videojs/video.js/commit/b5727a6))
<a name="5.17.0"></a>
# [5.17.0](https://github.com/videojs/video.js/compare/v5.16.0...v5.17.0) (2017-02-07)
### Bug Fixes
* Patch a memory leak caused by un-removed track listener(s). ([#3975](https://github.com/videojs/video.js/issues/3975)) ([bca44c0](https://github.com/videojs/video.js/commit/bca44c0))
* remove title attribute on menu items, fixes [#3699](https://github.com/videojs/video.js/issues/3699) ([#4009](https://github.com/videojs/video.js/issues/4009)) ([91874a3](https://github.com/videojs/video.js/commit/91874a3))
### Chores
* change accessibility test in grunt.js to remove unnecessary warning message. ([#4008](https://github.com/videojs/video.js/issues/4008)) ([daad492](https://github.com/videojs/video.js/commit/daad492))
* **package:** update swf to 5.2.0 ([#4040](https://github.com/videojs/video.js/issues/4040)) ([dab893b](https://github.com/videojs/video.js/commit/dab893b))
### Documentation
* minor fix to currentTime() comment: "setting" not "getting" ([#3944](https://github.com/videojs/video.js/issues/3944)) ([6578ed9](https://github.com/videojs/video.js/commit/6578ed9))
<a name="5.16.0"></a>
# [5.16.0](https://github.com/videojs/video.js/compare/v5.15.1...v5.16.0) (2017-01-12)
+2 -1
Ver Arquivo
@@ -261,7 +261,8 @@ git reset --hard upstream/master
Releasing video.js is partially automated through [`conrib.json`](/contrib.json) scripts. To do a release, you need a couple of things: npm access, GitHub personal access token.
Releases in video.js are done on npm and bower and GitHub and eventually posted on the CDN. This is the instruction for the npm/bower/GitHub releases.
Releases in video.js are done on npm and GitHub and eventually posted on the CDN. These
are the instructions for the npm/GitHub releases.
When we do a release, we release it as a `next` tag on npm first and then at least a week later, we promote this release to `latest` on npm.
+3 -3
Ver Arquivo
@@ -22,11 +22,11 @@
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/5.11/video-js.min.css" rel="stylesheet">
<script src="//vjs.zencdn.net/5.11/video.min.js"></script>
<link href="//vjs.zencdn.net/5.19/video-js.min.css" rel="stylesheet">
<script src="//vjs.zencdn.net/5.19/video.min.js"></script>
```
> For the latest URLs, check out the [Getting Started][getting-started] page on our website.
> For the latest version of video.js and URLs to use, check out the [Getting Started][getting-started] page on our website.
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!
+65
Ver Arquivo
@@ -0,0 +1,65 @@
const fs = require('fs');
const zlib = require('zlib');
const Promise = require('bluebird');
const klawSync = require('klaw-sync');
const filesize = require('filesize');
const Table = require('cli-table');
const files = klawSync('dist/', {
ignore: ['examples', 'lang', 'font', 'ie8', '*.zip', '*.gz'],
nodir: true
});
Promise.all(files.map(gzipAndStat))
.then(mapFiles)
.then(function(files) {
logTable(files);
return files;
})
.then(cleanup)
.catch(function(err) {
console.error(err.stack);
});
function cleanup(files) {
files.forEach(function(file) {
fs.unlinkSync('dist/' + file[0] + '.gz');
});
}
function mapFiles(files) {
return files.map(function(file) {
const path = file[0].path;
const fileStat = file[0].stats;
const gzStat = file[1];
return [file[0].path.split('dist/')[1], filesize(fileStat.size), filesize(gzStat.size)];
});
}
function gzipAndStat(file) {
return new Promise(function(resolve, reject) {
const readStream = fs.createReadStream(file.path);
const writeStream = fs.createWriteStream(file.path + '.gz');
const gzip = zlib.createGzip();
readStream.pipe(gzip).pipe(writeStream).on('close', function() {
const gzStat = fs.statSync(file.path + '.gz');
resolve([file, gzStat]);
})
.on('error', reject);
});
}
function logTable(files) {
const table = new Table({
head: ['filename', 'size', 'gzipped'],
colAligns: ['left', 'right', 'right'],
style: {
border: ['white']
}
});
table.push.apply(table, files);
console.log(table.toString());
}
+33
Ver Arquivo
@@ -0,0 +1,33 @@
var unified = require('unified');
var markdown = require('remark-parse');
var stringify = require('remark-stringify');
var fs = require('fs');
module.exports = function() {
var processor = unified()
.use(markdown, {commonmark: true})
.use(stringify);
var ast = processor.parse(fs.readFileSync('./CHANGELOG.md'));
var 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 (var i = 1; i < ast.children.length; i++) {
var 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');
};
+25 -1
Ver Arquivo
@@ -5,7 +5,31 @@ var apiPath = path.join(__dirname, '..', 'docs', 'api');
var 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: /\/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">'}
];
+44
Ver Arquivo
@@ -0,0 +1,44 @@
var ghrelease = require('gh-release');
var currentChangelog = require('./current-changelog.js');
var safeParse = require('safe-json-parse/tuple');
var pkg = require('../package.json')
var minimist = require('minimist');
var args = minimist(process.argv.slice(2), {
boolean: ['prerelease'],
default: {
prerelease: false
},
alias: {
p: 'prerelease'
}
}
var options = {
owner: 'videojs',
repo: 'video.js',
body: currentChangelog(),
assets: ['./dist/video-js-'+pkg.version+'.zip'],
endpoint: 'https://api.github.com',
auth: {
username: process.env.VJS_GITHUB_USER,
password: process.env.VJS_GITHUB_TOKEN
}
};
var tuple = safeParse(process.env.npm_config_argv);
var npmargs = tuple[0] ? [] : tuple[1].cooked;
if (args.prerelease || npmargs.some(function(arg) { return /next/.test(arg); })) {
options.prerelease = true;
}
ghrelease(options, function(err, result) {
if (err) {
console.log('Unable to publish release to github');
console.log(err);
} else {
console.log('Publish release to github!');
console.log(result);
}
});
+20 -8
Ver Arquivo
@@ -408,8 +408,7 @@ module.exports = function(grunt) {
],
dev: [
'shell:babel',
'browserify:watch',
'browserify:watchnovtt',
'shell:rollupwatch',
'browserify:tests',
'watch:skin',
'watch:lang',
@@ -448,6 +447,24 @@ module.exports = function(grunt) {
}
},
shell: {
rollup: {
command: 'npm run rollup',
options: {
preferLocal: true
}
},
rollupall: {
command: 'npm run rollup -- --no-progress && npm run rollup-minify -- --no-progress',
options: {
preferLocal: true
}
},
rollupwatch: {
command: 'npm run rollup-dev',
optoins: {
preferLocal: true
}
},
babel: {
command: 'npm run babel -- --watch',
options: {
@@ -509,12 +526,7 @@ module.exports = function(grunt) {
'shell:lint',
'clean:build',
'babel:es5',
'browserify:build',
'browserify:buildnovtt',
'usebanner:novtt',
'usebanner:vtt',
'uglify',
'shell:rollupall',
'skin',
'version:css',
+205
Ver Arquivo
@@ -0,0 +1,205 @@
import { rollup } from 'rollup';
import duration from 'humanize-duration';
import watch from 'rollup-watch';
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import filesize from 'rollup-plugin-filesize';
import progress from 'rollup-plugin-progress';
import ignore from 'rollup-plugin-ignore';
import uglify from 'rollup-plugin-uglify';
import minimist from 'minimist';
import _ from 'lodash';
import pkg from '../package.json';
import fs from 'fs';
const args = minimist(process.argv.slice(2), {
boolean: ['watch', 'minify', 'progress'],
default: {
progress: true
},
alias: {
w: 'watch',
m: 'minify',
p: 'progress'
}
});
const compiledLicense = _.template(fs.readFileSync('./build/license-header.txt', 'utf8'));
const bannerData = _.pick(pkg, ['version', 'copyright']);
const primedResolve = resolve({
jsnext: true,
main: true,
browser: true
});
const primedCjs = commonjs({
sourceMap: false
});
const primedBabel = babel({
babelrc: false,
exclude: 'node_modules/**',
presets: [
'es3',
['es2015', {
loose: true,
modules: false
}]
],
plugins: ['external-helpers']
});
const es = {
options: {
entry: 'src/js/video.js',
plugins: [
json(),
primedBabel,
args.progress ? progress() : {},
filesize()
],
onwarn(warning) {
if (warning.code === 'UNUSED_EXTERNAL_IMPORT' ||
warning.code === 'UNRESOLVED_IMPORT') {
return;
}
// eslint-disable-next-line no-console
console.warn(warning.message);
},
legacy: true
},
banner: compiledLicense(Object.assign({includesVtt: true}, bannerData)),
format: 'es',
dest: 'dist/video.es.js'
};
const cjs = Object.assign({}, es, {
format: 'cjs',
dest: 'dist/video.cjs.js'
});
const umd = {
options: {
entry: 'src/js/video.js',
plugins: [
primedResolve,
json(),
primedCjs,
primedBabel,
args.progress ? progress() : {},
filesize()
],
legacy: true
},
banner: compiledLicense(Object.assign({includesVtt: true}, bannerData)),
format: 'umd',
dest: 'dist/video.js'
};
const minifiedUmd = Object.assign({}, _.cloneDeep(umd), {
dest: 'dist/video.min.js'
});
minifiedUmd.options.plugins.splice(4, 0, uglify({
preserveComments: 'some',
screwIE8: false,
mangle: true,
compress: {
/* eslint-disable camelcase */
sequences: true,
dead_code: true,
conditionals: true,
booleans: true,
unused: true,
if_return: true,
join_vars: true,
drop_console: true
/* eslint-enable camelcase */
}
}));
const novttUmd = Object.assign({}, _.cloneDeep(umd), {
banner: compiledLicense(Object.assign({includesVtt: false}, bannerData)),
dest: 'dist/alt/video.novtt.js'
});
novttUmd.options.plugins.unshift(ignore(['videojs-vtt.js']));
const minifiedNovttUmd = Object.assign({}, _.cloneDeep(minifiedUmd), {
banner: compiledLicense(Object.assign({includesVtt: false}, bannerData)),
dest: 'dist/alt/video.novtt.min.js'
});
minifiedNovttUmd.options.plugins.unshift(ignore(['videojs-vtt.js']));
function runRollup({options, format, dest, banner}) {
rollup(options)
.then(function(bundle) {
bundle.write({
format,
dest,
banner,
moduleName: 'videojs',
sourceMap: false
});
}, function(err) {
// eslint-disable-next-line no-console
console.error(err);
});
}
if (!args.watch) {
if (args.minify) {
runRollup(minifiedUmd);
runRollup(minifiedNovttUmd);
} else {
runRollup(es);
runRollup(cjs);
runRollup(umd);
runRollup(novttUmd);
}
} else {
const props = ['format', 'dest', 'banner'];
const watchers = [
['es', watch({rollup},
Object.assign({},
es.options,
_.pick(es, props)))],
['cjs', watch({rollup},
Object.assign({},
cjs.options,
_.pick(cjs, props)))],
['umd', watch({rollup},
Object.assign({moduleName: 'videojs'},
umd.options,
_.pick(umd, props)))],
['novtt', watch({rollup},
Object.assign({moduleName: 'videojs'},
novttUmd.options,
_.pick(novttUmd, props)))]
];
watchers.forEach(function([type, watcher]) {
watcher.on('event', (details) => {
if (details.code === 'BUILD_START') {
// eslint-disable-next-line no-console
console.log(`Bundling ${type}...`);
return;
}
if (details.code === 'BUILD_END') {
// eslint-disable-next-line no-console
console.log(`Bundled ${type} in %s`, duration(details.duration));
return;
}
if (details.code === 'ERROR') {
// eslint-disable-next-line no-console
console.error(details.error.toString());
return;
}
});
});
}
-1
Ver Arquivo
@@ -7,7 +7,6 @@ if (tuple[0]) {
}
var sh = require('shelljs');
var version = process.env.npm_package_version;
var prereleaseType = npm_config_argv['remain'][0];
var approvedTypes = {
'major': 1,
+11 -15
Ver Arquivo
@@ -1,32 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Video.js Text Descriptions, Chapters &amp; Captions Example</title>
<link href="../../video-js.css" rel="stylesheet" type="text/css">
<script src="../../video.js"></script>
<!-- Set the location of the flash SWF -->
<script>
videojs.setGlobalOptions({
flash: {
swf: '../../video-js.swf'
}
});
</script>
<link href="http://vjs.zencdn.net/5.19/video-js.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/ie8/1.1/videojs-ie8.min.js"></script>
<script src="http://vjs.zencdn.net/5.19/video.js"></script>
</head>
<body>
<p style="background-color:#eee; border: 1px solid #777; padding: 10px; font-size: .8em; line-height: 1.5em; font-family: Verdana, sans-serif;">This page demonstrates a text descriptions track (intended primarily for blind and visually impaired consumers of visual media)</p>
<!-- 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! -->
useful way! Currently this means that iOS will not display
ANY text tracks -->
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="360"
data-setup='{ "html5" : { "nativeTextTracks" : false } }'>
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">
@@ -42,5 +36,7 @@
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
</video>
</body>
</html>
+18
Ver Arquivo
@@ -0,0 +1,18 @@
<!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>
+4 -5
Ver Arquivo
@@ -1,15 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Video.js | HTML5 Video Player</title>
<link href="http://vjs.zencdn.net/5.0.2/video-js.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/ie8/1.1.0/videojs-ie8.min.js"></script>
<script src="http://vjs.zencdn.net/5.0.2/video.js"></script>
<link href="http://vjs.zencdn.net/5.19/video-js.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/ie8/1.1/videojs-ie8.min.js"></script>
<script src="http://vjs.zencdn.net/5.19/video.js"></script>
</head>
<body>
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png" data-setup="{}">
@@ -22,6 +20,7 @@
<!-- Tracks need an ending tag thanks to IE9 -->
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
</video>
</body>
</html>
+1 -1
Ver Arquivo
@@ -292,7 +292,7 @@ Player
├── BigPlayButton
├─┬ ControlBar
│ ├── PlayToggle
│ ├── VolumeMenuButton
│ ├── VolumePanel
│ ├── CurrentTimeDisplay (hidden by default)
│ ├── TimeDivider (hidden by default)
│ ├── DurationDisplay (hidden by default)
+52 -49
Ver Arquivo
@@ -59,13 +59,15 @@ video.js is an extendable framework/library around the native video element. It
## Q: How do I install video.js?
Currently video.js can be installed using bower, npm, serving a release file from
Currently video.js can be installed using npm, serving a release file from
a github tag, or even using a CDN hosted version. For information on doing any of those
see the [install guide][install-guide].
## Q: Is video.js on bower?
Yes! See the [install guide][install-guide] for more information.
Versions prior to video.js 6 do support bower, however, as of video.js 6, bower is no
longer officially supported. Please see https://github.com/videojs/video.js/issues/4012
for more information.
## Q: What do video.js version numbers mean?
@@ -266,67 +268,68 @@ Yes! Please [submit an issue or open a pull request][pr-issue-question] if this
Yes! Please [submit an issue or open a pull request][pr-issue-question] if this does not work.
Be sure to use `require('!style-loader!css-loader!video.js/dist/video-js.css')` to inject video.js CSS.
We have a short guide that deals with small configurations that you will need to do. [Webpack and Videojs Configuration][webpack-guide].
## Q: Does video.js work with react?
Yes! See [ReactJS integration example][react-guide].
[reduced-test-case]: https://css-tricks.com/reduced-test-cases/
[react-guide]: /docs/guides/react.md
[plugin-guide]: /docs/guides/plugins.md
[install-guide]: http://videojs.com/getting-started/
[troubleshooting]: /docs/guides/troubleshooting.md
[video-tracks]: /docs/guides/video-tracks.md
[audio-tracks]: /docs/guides/audio-tracks.md
[text-tracks]: /docs/guides/text-tracks.md
[debug-guide]: /docs/guides/debugging.md
[pr-issue-question]: #q-i-think-i-found-a-bug-with-videojs-or-i-want-to-add-a-feature-what-should-i-do
[hls]: http://github.com/videojs/videojs-contrib-hls
[flash]: https://github.com/videojs/videojs-flash
[dash]: http://github.com/videojs/videojs-contrib-dash
[eme]: https://github.com/videojs/videojs-contrib-eme
[generator]: https://github.com/videojs/generator-videojs-plugin
[youtube]: https://github.com/videojs/videojs-youtube
[vimeo]: https://github.com/videojs/videojs-vimeo
[ads]: https://github.com/videojs/videojs-contrib-ads
[pr-template]: http://github.com/videojs/video.js/blob/master/.github/PULL_REQUEST_TEMPLATE.md
[issue-template]: http://github.com/videojs/video.js/blob/master/.github/ISSUE_TEMPLATE.md
[plugin-list]: http://videojs.com/plugins
[skins-list]: https://github.com/videojs/video.js/wiki/Skins
[audio-tracks]: /docs/guides/audio-tracks.md
[contributing-issues]: http://github.com/videojs/video.js/blob/master/CONTRIBUTING.md#filing-issues
[contributing-prs]: http://github.com/videojs/video.js/blob/master/CONTRIBUTING.md#contributing-code
[dash]: http://github.com/videojs/videojs-contrib-dash
[debug-guide]: /docs/guides/debugging.md
[eme]: https://github.com/videojs/videojs-contrib-eme
[flash]: https://github.com/videojs/videojs-flash
[generator]: https://github.com/videojs/generator-videojs-plugin
[hls]: http://github.com/videojs/videojs-contrib-hls
[install-guide]: http://videojs.com/getting-started/
[issue-template]: http://github.com/videojs/video.js/blob/master/.github/ISSUE_TEMPLATE.md
[npm-keywords]: https://docs.npmjs.com/files/package.json#keywords
[plugin-guide]: /docs/guides/plugins.md
[plugin-list]: http://videojs.com/plugins
[pr-issue-question]: #q-i-think-i-found-a-bug-with-videojs-or-i-want-to-add-a-feature-what-should-i-do
[pr-template]: http://github.com/videojs/video.js/blob/master/.github/PULL_REQUEST_TEMPLATE.md
[react-guide]: /docs/guides/react.md
[reduced-test-case]: https://css-tricks.com/reduced-test-cases/
[semver]: http://semver.org/
[skins-list]: https://github.com/videojs/video.js/wiki/Skins
[starter-example]: http://jsbin.com/axedog/edit?html,output
[text-tracks]: /docs/guides/text-tracks.md
[troubleshooting]: /docs/guides/troubleshooting.md
[video-tracks]: /docs/guides/video-tracks.md
[vimeo]: https://github.com/videojs/videojs-vimeo
[vjs-issues]: https://github.com/videojs/video.js/issues
[vjs-prs]: https://github.com/videojs/video.js/pulls
[npm-keywords]: https://docs.npmjs.com/files/package.json#keywords
[semver]: http://semver.org/
[starter-example]: http://jsbin.com/axedog/edit?html,output
[webpack-guide]: /docs/guides/webpack.md
[youtube]: https://github.com/videojs/videojs-youtube
+2 -2
Ver Arquivo
@@ -318,7 +318,7 @@ The `children` options can also be passed as an `Object`. In this case, it is us
videojs('my-player', {
children: {
controlBar: {
fullscreenControl: false
fullscreenToggle: false
}
}
});
@@ -333,7 +333,7 @@ Components can be given custom options via the _lower-camel-case variant of the
```js
videojs('my-player', {
controlBar: {
fullscreenControl: false
fullscreenToggle: false
}
});
```
+21
Ver Arquivo
@@ -176,6 +176,14 @@ Like components, advanced plugins offer an implementation of events. This includ
By offering a built-in events system, advanced plugins offer a wider range of options for code structure with a pattern familiar to most web developers.
##### Extra Event Data
All events triggered by plugins include an additional data object as a second argument. This object has three properties:
- `name`: The name of the plugin (e.g. `"examplePlugin"`) as a string.
- `plugin`: The plugin constructor (e.g. `ExamplePlugin`).
- `instance`: The plugin constructor instance.
#### Statefulness
A new concept introduced for advanced plugins is _statefulness_. This is similar to React components' `state` property and `setState` method.
@@ -307,6 +315,19 @@ player.examplePlugin({customClass: 'example-class'});
These two methods are functionally identical - use whichever you prefer!
### Plugin Setup Events
Occasionally, a use-case arises where some code needs to wait for a plugin to be initialized. As of Video.js 6, this can be achieved by listening for `pluginsetup` events on the player.
For any given plugin initialization, there are four events to be aware of:
- `beforepluginsetup`: Triggered immediately before any plugin is initialized.
- `beforepluginsetup:examplePlugin` Triggered immediately before the `examplePlugin` is initialized.
- `pluginsetup`: Triggered after any plugin is initialized.
- `pluginsetup:examplePlugin`: Triggered after he `examplePlugin` is initialized.
These events work for both basic and advanced plugins. They are triggered on the player and each includes an object of [extra event data](#extra-event-data) as a second argument to its listeners.
## References
* [Player API][api-player]
+91
Ver Arquivo
@@ -54,3 +54,94 @@ return <VideoPlayer { ...videoJsOptions } />
Dont forget to include the video.js CSS, located at `video.js/dist/video-js.css`.
[options]: /docs/guides/options.md
## Using a React Component as a Video JS Component
```jsx
/**
* EpisodeList.js
*
* This is just a plain ol' React component.
* the vjsComponent methods, player methods etc. are available via
* the vjsComponent prop (`this.props.vjsComponent`)
*/
import React, { Component, PropTypes } from 'react';
class EpisodeList extends Component {
render() {
return (
<div>
<h1>{this.props.body}</h1>
</div>
);
}
}
/**
* vjsEpisodeList.js
*
* Here is where we register a Video JS Component and
* mount the React component to it when the player is ready.
*/
import EpisodeList from './EpisodeList';
import ReactDOM from 'react-dom';
import videojs from 'video.js';
const vjsComponent = videojs.getComponent('Component');
class vjsEpisodeList extends vjsComponent {
constructor(player, options) {
super(player, options);
/* Bind the current class context to the mount method */
this.mount = this.mount.bind(this);
/* When player is ready, call method to mount React component */
player.ready(() => {
this.mount();
});
}
/**
* We will render out the React EpisodeList component into the DOM element
* generated automatically by the VideoJS createEl() method.
*
* We fetch that generated element using `this.el()`, a method provided by the
* vjsComponent class that this class is extending.
*/
mount() {
ReactDOM.render(<EpisodeList vjsComponent={this} body="Episodes" />, this.el() );
}
}
/**
* Make sure to register the vjsComponent so Video JS knows it exists
*/
vjsComponent.registerComponent('vjsEpisodeList', vjsEpisodeList);
export default vjsEpisodeList;
/**
* VideoPlayer.js
* Check the above example for how to integrate the rest of this class.
*/
// ...
componentDidMount() {
// instantiate video.js
this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
console.log('onPlayerReady', this)
});
/**
* Fetch the controlBar component and add the new vjsEpisodeList component as a child
* You can pass options here if desired in the second object.
*/
this.player.getChild('controlBar').addChild('vjsEpisodeList', {});
}
// ...
```
+1 -1
Ver Arquivo
@@ -14,7 +14,7 @@
## Getting Video.js
Video.js is officially available via CDN, npm, and Bower.
Video.js is officially available via CDN and npm.
Video.js works out of the box with not only HTML `<script>` and `<link>` tags, but also all major bundlers/packagers/builders, such as Browserify, Node, WebPack, etc.
+37
Ver Arquivo
@@ -0,0 +1,37 @@
# Using Webpack with Video.js
video.js, and the playback technologies such as videojs-contrib-hls all work in a Webpack based build environment. Here are several configuration changes specific to Webpack that will get you up and running.
## Video.js CSS:
To add the CSS that the player requires, simply add
`require('!style-loader!css-loader!video.js/dist/video-js.css')` to the file where the player is also included or initialized.
## Handling .eot files in Webpack
In addition to this, you may run into a problem where Webpack does not know how to load .eot files required for IE8 support by default. This can be solved by installing the file-loader and url-loader packages. Install them by running:
`npm install --save-dev file-loader url-loader`
With both packages installed, simply add the following to you webpack.config file in the 'loaders' section:
```
{
loader: 'url-loader?limit=100000',
test: /\.(png|woff|woff2|eot|ttf|svg)$/
}
```
## Using Webpack with videojs-contrib-hls
Import the HLS library with a line such as:
`import * as HLS from 'videojs-contrib-hls';`
In order to use the tech, we must also introduce webworkers with the package 'webworkify-webpack-dropin', run:
`npm install --save-dev webworkify-webpack-dropin`
To utilize this in your page, simply create an alias in your webpack.config.js file with:
```
resolve: {
alias: {
webworkify: 'webworkify-webpack-dropin'
}
}
```
Source maps that use the 'eval' tag are not compatible with webworkify, so this may need to be changed also. Source maps such as 'cheap-eval-module-source-map' should be changed to 'cheap-source-map' or anything else that fits your build without using 'eval' source maps.
+89 -53
Ver Arquivo
@@ -13,7 +13,6 @@ This default value is hardcoded as a default to the localize method in the SeekB
## Status of translations
<!-- START langtable -->
| Language file | Missing translations |
| ----------------------- | ----------------------------------------------------------------------------------- |
| ar.json (missing 50) | Audio Player |
@@ -61,7 +60,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -119,7 +118,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -177,7 +176,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -235,7 +234,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -293,7 +292,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -351,19 +350,12 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
| | End of dialog window. |
| de.json (missing 8) | Audio Player |
| | Video Player |
| | Progress Bar |
| | progress bar timing: currentTime={1} duration={2} |
| | Volume Level |
| | Reset |
| | all settings to the default values |
| | End of dialog window. |
| de.json (Complete) | |
| el.json (missing 44) | Audio Player |
| | Video Player |
| | Replay |
@@ -403,7 +395,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -460,7 +452,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -518,7 +510,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -576,12 +568,69 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
| | End of dialog window. |
| fr.json (Complete) | |
| gl.json (missing 57) | Audio Player |
| | Video Player |
| | Replay |
| | Progress Bar |
| | progress bar timing: currentTime={1} duration={2} |
| | Descriptions |
| | descriptions off |
| | Audio Track |
| | Volume Level |
| | The media is encrypted and we do not have the keys to decrypt it. |
| | Close |
| | Close Modal Dialog |
| | Modal Window |
| | This is a modal window |
| | This modal can be closed by pressing the Escape key or activating the close button. |
| | , opens captions settings dialog |
| | , opens subtitles settings dialog |
| | , opens descriptions settings dialog |
| | , selected |
| | captions settings |
| | subtitles settings |
| | descriptions settings |
| | Text |
| | White |
| | Black |
| | Red |
| | Green |
| | Blue |
| | Yellow |
| | Magenta |
| | Cyan |
| | Background |
| | Window |
| | Transparent |
| | Semi-Transparent |
| | Opaque |
| | Font Size |
| | Text Edge Style |
| | None |
| | Raised |
| | Depressed |
| | Uniform |
| | Dropshadow |
| | Font Family |
| | Proportional Sans-Serif |
| | Monospace Sans-Serif |
| | Proportional Serif |
| | Monospace Serif |
| | Casual |
| | Script |
| | Small Caps |
| | Reset |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
| | End of dialog window. |
| hr.json (missing 58) | Audio Player |
| | Video Player |
| | Replay |
@@ -635,7 +684,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -693,7 +742,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -751,7 +800,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -809,7 +858,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -867,7 +916,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -925,7 +974,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -972,7 +1021,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1030,7 +1079,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1081,7 +1130,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1139,7 +1188,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1182,7 +1231,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1226,11 +1275,12 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
| | End of dialog window. |
| sk.json (Complete) | |
| sr.json (missing 58) | Audio Player |
| | Video Player |
| | Replay |
@@ -1284,7 +1334,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1342,7 +1392,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1353,7 +1403,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | progress bar timing: currentTime={1} duration={2} |
| | Volume Level |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | End of dialog window. |
| uk.json (missing 44) | Audio Player |
| | Video Player |
@@ -1394,7 +1444,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1437,30 +1487,17 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
| | End of dialog window. |
| zh-CN.json (missing 57) | Audio Player |
| zh-CN.json (missing 44) | Audio Player |
| | Video Player |
| | Replay |
| | Progress Bar |
| | progress bar timing: currentTime={1} duration={2} |
| | Descriptions |
| | descriptions off |
| | Audio Track |
| | Volume Level |
| | Play Video |
| | Close |
| | Close Modal Dialog |
| | Modal Window |
| | This is a modal window |
| | This modal can be closed by pressing the Escape key or activating the close button. |
| | , opens captions settings dialog |
| | , opens subtitles settings dialog |
| | , opens descriptions settings dialog |
| | , selected |
| | captions settings |
| | subtitles settings |
| | descriptions settings |
@@ -1494,7 +1531,7 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
@@ -1538,10 +1575,9 @@ This default value is hardcoded as a default to the localize method in the SeekB
| | Script |
| | Small Caps |
| | Reset |
| | all settings to the default values |
| | restore all settings to the default values |
| | Done |
| | Caption Settings Dialog |
| | Beginning of dialog window. Escape will cancel and close the window. |
| | End of dialog window. |
<!-- END langtable -->
+9 -1
Ver Arquivo
@@ -70,7 +70,15 @@
"Casual": "Zwanglos",
"Script": "Schreibeschrift",
"Small Caps": "Small-Caps",
"Reset": "Zurücksetzen",
"restore all settings to the default values": "Alle Einstellungen auf die Standardwerte zurücksetzen",
"Done": "Fertig",
"Caption Settings Dialog": "Einstellungsdialog für Untertitel",
"Beginning of dialog window. Escape will cancel and close the window.": "Anfang des Dialogfensters. Esc bricht ab und schließt das Fenster."
"Beginning of dialog window. Escape will cancel and close the window.": "Anfang des Dialogfensters. Esc bricht ab und schließt das Fenster.",
"End of dialog window.": "Ende des Dialogfensters.",
"Audio Player": "Audio-Player",
"Video Player": "Video-Player",
"Progress Bar": "Forschrittsbalken",
"progress bar timing: currentTime={1} duration={2}": "{1} von {2}",
"Volume Level": "Lautstärkestufe"
}
+1 -1
Ver Arquivo
@@ -76,7 +76,7 @@
"Script": "Script",
"Small Caps": "Small Caps",
"Reset": "Reset",
"all settings to the default values": "all settings to the default values",
"restore all settings to the default values": "restore all settings to the default values",
"Done": "Done",
"Caption Settings Dialog": "Caption Settings Dialog",
"Beginning of dialog window. Escape will cancel and close the window.": "Beginning of dialog window. Escape will cancel and close the window.",
+1 -1
Ver Arquivo
@@ -76,7 +76,7 @@
"Script": "Scripte",
"Small Caps": "Petites capitales",
"Reset": "Réinitialiser",
"all settings to the default values": "tous les paramètres aux valeurs par défaut",
"restore all settings to the default values": "Restaurer tous les paramètres aux valeurs par défaut",
"Done": "Terminé",
"Caption Settings Dialog": "Boîte de dialogue des paramètres des sous-titres transcrits",
"Beginning of dialog window. Escape will cancel and close the window.": "Début de la fenêtre de dialogue. La touche d'échappement annulera et fermera la fenêtre.",
+27
Ver Arquivo
@@ -0,0 +1,27 @@
{
"Play": "Reprodución",
"Play Video": "Reprodución Vídeo",
"Pause": "Pausa",
"Current Time": "Tempo reproducido",
"Duration Time": "Duración total",
"Remaining Time": "Tempo restante",
"Stream Type": "Tipo de secuencia",
"LIVE": "DIRECTO",
"Loaded": "Cargado",
"Progress": "Progreso",
"Fullscreen": "Pantalla completa",
"Non-Fullscreen": "Pantalla non completa",
"Mute": "Silenciar",
"Unmute": "Non silenciado",
"Playback Rate": "Velocidade de reprodución",
"Subtitles": "Subtítulos",
"subtitles off": "Subtítulos desactivados",
"Captions": "Subtítulos con lenda",
"captions off": "Subtítulos con lenda desactivados",
"Chapters": "Capítulos",
"You aborted the media playback": "Interrompeches a reprodución do vídeo.",
"A network error caused the media download to fail part-way.": "Un erro de rede interrompeu a descarga do vídeo.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Non se puido cargar o vídeo debido a un fallo de rede ou do servidor ou porque o formato é incompatible.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "A reproducción de vídeo interrompeuse por un problema de corrupción de datos ou porque o vídeo precisa funcións que o teu navegador non ofrece.",
"No compatible source was found for this media.": "Non se atopou ningunha fonte compatible con este vídeo."
}
+84
Ver Arquivo
@@ -0,0 +1,84 @@
{
"Audio Player": "Zvukový prehrávač",
"Video Player": "Video prehrávač",
"Play": "Prehrať",
"Pause": "Pozastaviť",
"Replay": "Prehrať znova",
"Current Time": "Aktuálny čas",
"Duration Time": "Čas trvania",
"Remaining Time": "Zostávajúci čas",
"Stream Type": "Typ stopy",
"LIVE": "NAŽIVO",
"Loaded": "Načítané",
"Progress": "Priebeh",
"Progress Bar": "Ukazovateľ priebehu",
"progress bar timing: currentTime={1} duration={2}": "časovanie ukazovateľa priebehu: currentTime={1} duration={2}",
"Fullscreen": "Režim celej obrazovky",
"Non-Fullscreen": "Režim normálnej obrazovky",
"Mute": "Stlmiť",
"Unmute": "Zrušiť stlmenie",
"Playback Rate": "Rýchlosť prehrávania",
"Subtitles": "Titulky",
"subtitles off": "titulky vypnuté",
"Captions": "Popisky",
"captions off": "popisky vypnuté",
"Chapters": "Kapitoly",
"Descriptions": "Opisy",
"descriptions off": "opisy vypnuté",
"Audio Track": "Zvuková stopa",
"Volume Level": "Úroveň hlasitosti",
"You aborted the media playback": "Prerušili ste prehrávanie",
"A network error caused the media download to fail part-way.": "Sťahovanie súboru bolo zrušené pre chybu na sieti.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Súbor sa nepodarilo načítať pre chybu servera, sieťového pripojenia, alebo je formát súboru nepodporovaný.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Prehrávanie súboru bolo prerušené pre poškodené dáta, alebo súbor používa vlastnosti, ktoré váš prehliadač nepodporuje.",
"No compatible source was found for this media.": "Nebol nájdený žiaden kompatibilný zdroj pre tento súbor.",
"The media is encrypted and we do not have the keys to decrypt it.": "Súbor je zašifrovaný a nie je k dispozícii kľúč na rozšifrovanie.",
"Play Video": "Prehrať video",
"Close": "Zatvoriť",
"Close Modal Dialog": "Zatvoriť modálne okno",
"Modal Window": "Modálne okno",
"This is a modal window": "Toto je modálne okno",
"This modal can be closed by pressing the Escape key or activating the close button.": "Toto modálne okno je možné zatvoriť stlačením klávesy Escape, alebo aktivovaním tlačidla na zatvorenie.",
", opens captions settings dialog": ", otvorí okno nastavení popiskov",
", opens subtitles settings dialog": ", otvorí okno nastavení titulkov",
", opens descriptions settings dialog": ", otvorí okno nastavení opisov",
", selected": ", označené",
"captions settings": "nastavenia popiskov",
"subtitles settings": "nastavenia titulkov",
"descriptions settings": "nastavenia opisov",
"Text": "Text",
"White": "Biela",
"Black": "Čierna",
"Red": "Červená",
"Green": "Zelená",
"Blue": "Modrá",
"Yellow": "Žltá",
"Magenta": "Ružová",
"Cyan": "Tyrkysová",
"Background": "Pozadie",
"Window": "Okno",
"Transparent": "Priesvitné",
"Semi-Transparent": "Polopriesvitné",
"Opaque": "Plné",
"Font Size": "Veľkosť písma",
"Text Edge Style": "Typ okrajov písma",
"None": "Žiadne",
"Raised": "Zvýšené",
"Depressed": "Znížené",
"Uniform": "Pravidelné",
"Dropshadow": "S tieňom",
"Font Family": "Typ písma",
"Proportional Sans-Serif": "Proporčné bezpätkové",
"Monospace Sans-Serif": "Pravidelné, bezpätkové",
"Proportional Serif": "Proporčné pätkové",
"Monospace Serif": "Pravidelné pätkové",
"Casual": "Bežné",
"Script": "Písané",
"Small Caps": "Malé kapitálky",
"Reset": "Resetovať",
"restore all settings to the default values": "všetky nastavenia na základné hodnoty",
"Done": "Hotovo",
"Caption Settings Dialog": "Okno nastavení popiskov",
"Beginning of dialog window. Escape will cancel and close the window.": "Začiatok okna. Klávesa Escape zruší a zavrie okno.",
"End of dialog window.": "Koniec okna."
}
+17 -4
Ver Arquivo
@@ -12,16 +12,29 @@
"Non-Fullscreen": "退出全屏",
"Mute": "静音",
"Unmute": "取消静音",
"Playback Rate": "播放码率",
"Playback Rate": "播放速度",
"Subtitles": "字幕",
"subtitles off": "字幕关闭",
"subtitles off": "关闭字幕",
"Captions": "内嵌字幕",
"captions off": "内嵌字幕关闭",
"captions off": "关闭内嵌字幕",
"Chapters": "节目段落",
"Close Modal Dialog": "关闭弹窗",
"Descriptions": "描述",
"descriptions off": "关闭描述",
"Audio Track": "音轨",
"You aborted the media playback": "视频播放被终止",
"A network error caused the media download to fail part-way.": "网络错误导致视频下载中途失败。",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "视频因格式不支持或者服务器或网络的问题无法加载。",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "由于视频文件损坏或是该视频使用了你的浏览器不支持的功能,播放终止。",
"No compatible source was found for this media.": "无法找到此视频兼容的源。",
"The media is encrypted and we do not have the keys to decrypt it.": "视频已加密,无法解密。"
"The media is encrypted and we do not have the keys to decrypt it.": "视频已加密,无法解密。",
"Play Video": "播放视频",
"Close": "关闭",
"Modal Window": "弹窗",
"This is a modal window": "这是一个弹窗",
"This modal can be closed by pressing the Escape key or activating the close button.": "可以按ESC按键或启用关闭按钮来关闭此弹窗。",
", opens captions settings dialog": ", 开启标题设置弹窗",
", opens subtitles settings dialog": ", 开启字幕设置弹窗",
", opens descriptions settings dialog": ", 开启描述设置弹窗",
", selected": ", 选择"
}
+37 -9
Ver Arquivo
@@ -1,8 +1,9 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
"version": "6.0.0",
"main": "./es5/video.js",
"version": "6.2.3",
"main": "./dist/video.cjs.js",
"module": "./dist/video.es.js",
"style": "./dist/video-js.css",
"copyright": "Copyright Brightcove, Inc. <https://www.brightcove.com/>",
"license": "Apache-2.0",
@@ -18,6 +19,11 @@
"scripts": {
"changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s",
"build": "grunt dist",
"rollup-all": "npm run rollup && npm run rollup-minify",
"rollup": "babel-node build/rollup.js",
"rollup-minify": "babel-node build/rollup.js --minify",
"rollup-dev": "babel-node build/rollup.js --watch",
"assets": "node build/assets.js",
"change": "grunt chg-add",
"clean": "grunt clean",
"grunt": "grunt",
@@ -33,6 +39,7 @@
"docs:fix": "remark --output -- './**/*.md'",
"babel": "babel src/js -d es5",
"prepublish": "not-in-install && run-p docs:api build || in-install",
"publish": "node build/gh-release.js",
"prepush": "npm run lint -- --errors",
"version": "node build/version.js && git add CHANGELOG.md"
},
@@ -42,33 +49,37 @@
},
"dependencies": {
"babel-runtime": "^6.9.2",
"global": "4.3.0",
"global": "4.3.2",
"safe-json-parse": "4.0.0",
"tsml": "1.0.1",
"videojs-font": "2.0.0",
"videojs-ie8": "1.1.2",
"videojs-vtt.js": "0.12.3",
"videojs-vtt.js": "0.12.4",
"xhr": "2.4.0"
},
"devDependencies": {
"aliasify": "^2.1.0",
"babel-cli": "^6.11.4",
"babel-plugin-inline-json": "^1.1.1",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-preset-es2015": "^6.14.0",
"babel-preset-es3": "^1.0.1",
"babel-register": "^6.9.0",
"babelify": "^7.3.0",
"blanket": "^1.1.6",
"bluebird": "^3.5.0",
"browserify-derequire": "^0.9.4",
"browserify-istanbul": "^2.0.0",
"browserify-versionify": "^1.0.4",
"bundle-collapser": "^1.2.1",
"chg": "^0.3.2",
"cli-table": "^0.3.1",
"conventional-changelog-cli": "^1.2.0",
"conventional-changelog-videojs": "^3.0.0",
"es5-shim": "^4.1.3",
"es6-shim": "^0.35.1",
"filesize": "^3.5.6",
"gh-release": "^3.0.0",
"grunt": "^0.4.5",
"grunt-accessibility": "^5.0.0",
"grunt-babel": "^6.0.0",
@@ -80,7 +91,7 @@
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-connect": "~1.0.2",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-cssmin": "~1.0.2",
"grunt-contrib-cssmin": "~2.2.0",
"grunt-contrib-uglify": "^2.0.0",
"grunt-contrib-watch": "~1.0.0",
"grunt-coveralls": "^1.0.0",
@@ -92,7 +103,8 @@
"grunt-version": "~1.1.1",
"grunt-videojs-languages": "0.0.4",
"grunt-zip": "0.17.1",
"husky": "^0.13.1",
"humanize-duration": "^3.10.0",
"husky": "^0.14.1",
"in-publish": "^2.0.0",
"istanbul": "^0.4.5",
"jsdoc": "^3.4.2",
@@ -108,33 +120,49 @@
"karma-qunit": "^1.2.0",
"karma-safari-launcher": "^1.0.0",
"karma-sinon": "^1.0.5",
"klaw-sync": "^1.1.2",
"load-grunt-tasks": "^3.1.0",
"lodash": "^4.16.6",
"markdown-table": "^1.0.0",
"minimist": "^1.2.0",
"npm-run": "^4.1.0",
"npm-run-all": "^4.0.2",
"proxyquireify": "^3.0.0",
"qunitjs": "1.23.1",
"remark-cli": "^3.0.0",
"remark-lint": "^6.0.0",
"remark-parse": "^3.0.1",
"remark-stringify": "^3.0.1",
"remark-toc": "^4.0.0",
"remark-validate-links": "^6.0.0",
"replace": "^0.3.0",
"rollup": "^0.45.2",
"rollup-plugin-babel": "^2.7.1",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-filesize": "^1.2.1",
"rollup-plugin-ignore": "^1.0.3",
"rollup-plugin-json": "^2.1.1",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-plugin-progress": "^0.2.1",
"rollup-plugin-uglify": "^1.0.2",
"rollup-watch": "^4.0.0",
"shelljs": "^0.7.5",
"sinon": "^1.16.1",
"time-grunt": "^1.1.1",
"tui-jsdoc-template": "^1.1.0",
"uglify-js": "~2.8.8",
"unified": "^6.1.5",
"videojs-doc-generator": "0.0.1",
"videojs-flash": "^1.0.0-RC.0",
"videojs-flash": "^2.0.0",
"videojs-standard": "^6.0.1",
"webpack": "^2.3.0"
"webpack": "^1.15.0"
},
"vjsstandard": {
"ignore": [
"**/Gruntfile.js",
"**/es5/**",
"**/build/**",
"!build/rollup.js",
"**/dist/**",
"**/docs/**",
"**/lang/**",
+3 -3
Ver Arquivo
@@ -5,16 +5,16 @@
<title>Video.js Sandbox</title>
<!-- Add ES5 shim and sham for IE8 -->
<script src="../build/temp/ie8/videojs-ie8.js"></script>
<script src="../dist/ie8/videojs-ie8.js"></script>
<!-- Load the source files -->
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../build/temp/video.js"></script>
<script src="../dist/video.js"></script>
<script src="../node_modules/videojs-flash/dist/videojs-flash.js"></script>
<!-- Set the location of the flash SWF -->
<script>
videojs.options.flash.swf = '../build/temp/video-js.swf';
videojs.options.flash.swf = '../node_modules/videojs-flash/node_modules/videojs-swf/dist/video-js.swf';
</script>
</head>
<body>
+10 -5
Ver Arquivo
@@ -5,25 +5,29 @@
<title>Video.js Text Descriptions, Chapters &amp; Captions Example</title>
<!-- Add ES5 shim and sham for IE8 -->
<script src="../build/temp/ie8/videojs-ie8.js"></script>
<script src="../dist/ie8/videojs-ie8.js"></script>
<!-- Load the source files -->
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../build/temp/video.js"></script>
<script src="../dist/video.js"></script>
<!-- Set the location of the flash SWF -->
<script>
videojs.options.flash.swf = '../build/temp/video-js.swf';
videojs.options.flash.swf = '../node_modules/videojs-flash/node_modules/videojs-swf/dist/video-js.swf';
</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! -->
useful way! Currently this means that iOS will not display
ANY text tracks -->
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="360"
data-setup='{ "html5" : { "nativeTextTracks" : false } }'>
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">
@@ -39,5 +43,6 @@
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
</video>
</body>
</html>
+3 -3
Ver Arquivo
@@ -5,16 +5,16 @@
<title>Video.js Sandbox</title>
<!-- Add ES5 shim and sham for IE8 -->
<script src="../build/temp/ie8/videojs-ie8.js"></script>
<script src="../dist/ie8/videojs-ie8.js"></script>
<!-- Load the source files -->
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../build/temp/video.js"></script>
<script src="../dist/video.js"></script>
<script src="../node_modules/videojs-flash/dist/videojs-flash.js"></script>
<!-- Set the location of the flash SWF -->
<script>
videojs.options.flash.swf = '../build/temp/video-js.swf';
videojs.options.flash.swf = '../node_modules/videojs-flash/node_modules/videojs-swf/dist/video-js.swf';
</script>
</head>
+3 -3
Ver Arquivo
@@ -5,16 +5,16 @@
<title>Video.js Sandbox</title>
<!-- Add ES5 shim and sham for IE8 -->
<script src="../build/temp/ie8/videojs-ie8.js"></script>
<script src="../dist/ie8/videojs-ie8.js"></script>
<!-- Load the source files -->
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../build/temp/video.js"></script>
<script src="../dist/video.js"></script>
<script src="../node_modules/videojs-flash/dist/videojs-flash.js"></script>
<!-- Set the location of the flash SWF -->
<script>
videojs.options.flash.swf = '../build/temp/video-js.swf';
videojs.options.flash.swf = '../node_modules/videojs-flash/node_modules/videojs-swf/dist/video-js.swf';
</script>
</head>
+3 -3
Ver Arquivo
@@ -6,15 +6,15 @@
<title>VideoJS Languages Demo</title>
<!-- Add ES5 shim and sham for IE8 -->
<script src="../build/temp/ie8/videojs-ie8.js"></script>
<script src="../dist/ie8/videojs-ie8.js"></script>
<!-- Load the source files -->
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../build/temp/video.js"></script>
<script src="../dist/video.js"></script>
<!-- Set the location of the flash SWF -->
<script>
videojs.options.flash.swf = '../build/temp/video-js.swf';
videojs.options.flash.swf = '../node_modules/videojs-flash/node_modules/videojs-swf/dist/video-js.swf';
</script>
<!-- Add support for Spanish 'es' -->
+3 -3
Ver Arquivo
@@ -5,15 +5,15 @@
<title>Video.js Plugin Example</title>
<!-- Add ES5 shim and sham for IE8 -->
<script src="../build/temp/ie8/videojs-ie8.js"></script>
<script src="../dist/ie8/videojs-ie8.js"></script>
<!-- Load the source files -->
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../build/temp/video.js"></script>
<script src="../dist/video.js"></script>
<!-- Set the location of the flash SWF -->
<script>
videojs.options.flash.swf = '../build/temp/video-js.swf';
videojs.options.flash.swf = '../node_modules/videojs-flash/node_modules/videojs-swf/dist/video-js.swf';
</script>
</head>
-2
Ver Arquivo
@@ -21,8 +21,6 @@
// Avoiding helvetica: issue #376
font-family: $text-font-family;
@include user-select(none);
// Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
// checking fullScreenEnabled.
&:-moz-full-screen { position: absolute; }
+7 -2
Ver Arquivo
@@ -1,12 +1,17 @@
// TODO: I feel like this should be a generic menu. Research later.
.vjs-playback-rate > .vjs-menu-button,
.vjs-playback-rate .vjs-playback-rate-value {
font-size: 1.5em;
line-height: 2;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.vjs-playback-rate .vjs-playback-rate-value {
pointer-events: none;
font-size: 1.5em;
line-height: 2;
text-align: center;
}
+2
Ver Arquivo
@@ -4,6 +4,8 @@
padding: 0;
margin: 0 0.45em 0 0.45em;
@include user-select(none);
@include background-color-with-alpha($secondary-background-color, $secondary-background-transparency);
}
+13 -11
Ver Arquivo
@@ -120,7 +120,7 @@ class ClickableComponent extends Component {
const localizedText = this.localize(text);
this.controlText_ = text;
this.controlTextEl_.innerHTML = localizedText;
Dom.textContent(this.controlTextEl_, localizedText);
if (!this.nonIconControl) {
// Set title attribute if only an icon is shown
el.setAttribute('title', localizedText);
@@ -141,28 +141,30 @@ class ClickableComponent extends Component {
* Enable this `Component`s element.
*/
enable() {
this.removeClass('vjs-disabled');
this.el_.setAttribute('aria-disabled', 'false');
if (typeof this.tabIndex_ !== 'undefined') {
this.el_.setAttribute('tabIndex', this.tabIndex_);
if (!this.enabled_) {
this.enabled_ = true;
this.removeClass('vjs-disabled');
this.el_.setAttribute('aria-disabled', 'false');
if (typeof this.tabIndex_ !== 'undefined') {
this.el_.setAttribute('tabIndex', this.tabIndex_);
}
this.on(['tap', 'click'], this.handleClick);
this.on('focus', this.handleFocus);
this.on('blur', this.handleBlur);
}
this.on('tap', this.handleClick);
this.on('click', this.handleClick);
this.on('focus', this.handleFocus);
this.on('blur', this.handleBlur);
}
/**
* Disable this `Component`s element.
*/
disable() {
this.enabled_ = false;
this.addClass('vjs-disabled');
this.el_.setAttribute('aria-disabled', 'true');
if (typeof this.tabIndex_ !== 'undefined') {
this.el_.removeAttribute('tabIndex');
}
this.off('tap', this.handleClick);
this.off('click', this.handleClick);
this.off(['tap', 'click'], this.handleClick);
this.off('focus', this.handleFocus);
this.off('blur', this.handleBlur);
}
+1 -1
Ver Arquivo
@@ -40,7 +40,7 @@ class Component {
*
* @param {Object} [options]
* The key/value store of player options.
#
*
* @param {Object[]} [options.children]
* An array of children objects to intialize this component with. Children objects have
* a name property that will be used if more than one component of the same type needs to be
@@ -70,6 +70,26 @@ class OffTextTrackMenuItem extends TextTrackMenuItem {
this.selected(selected);
}
handleSelectedLanguageChange(event) {
const tracks = this.player().textTracks();
let allHidden = true;
for (let i = 0, l = tracks.length; i < l; i++) {
const track = tracks[i];
if ((['captions', 'descriptions', 'subtitles'].indexOf(track.kind) > -1) && track.mode === 'showing') {
allHidden = false;
break;
}
}
if (allHidden) {
this.player_.cache_.selectedLanguage = {
enabled: false
};
}
}
}
Component.registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem);
@@ -26,10 +26,6 @@ class TextTrackButton extends TrackButton {
options.tracks = player.textTracks();
super(player, options);
if (!Array.isArray(this.kinds_)) {
this.kinds_ = [this.kind_];
}
}
/**
@@ -61,11 +57,16 @@ class TextTrackButton extends TrackButton {
const tracks = this.player_.textTracks();
if (!Array.isArray(this.kinds_)) {
this.kinds_ = [this.kind_];
}
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
// only add tracks that are of an appropriate kind and have a label
if (this.kinds_.indexOf(track.kind) > -1) {
const item = new TrackMenuItem(this.player_, {
track,
// MenuItem is selectable
@@ -29,17 +29,20 @@ class TextTrackMenuItem extends MenuItem {
// Modify options for parent MenuItem class's init.
options.label = track.label || track.language || 'Unknown';
options.selected = track.default || track.mode === 'showing';
options.selected = track.mode === 'showing';
super(player, options);
this.track = track;
const changeHandler = Fn.bind(this, this.handleTracksChange);
const selectedLanguageChangeHandler = Fn.bind(this, this.handleSelectedLanguageChange);
player.on(['loadstart', 'texttrackchange'], changeHandler);
tracks.addEventListener('change', changeHandler);
tracks.addEventListener('selectedlanguagechange', selectedLanguageChangeHandler);
this.on('dispose', function() {
tracks.removeEventListener('change', changeHandler);
tracks.removeEventListener('selectedlanguagechange', selectedLanguageChangeHandler);
});
// iOS7 doesn't dispatch change events to TextTrackLists when an
@@ -101,8 +104,10 @@ class TextTrackMenuItem extends MenuItem {
const track = tracks[i];
if (track === this.track && (kinds.indexOf(track.kind) > -1)) {
track.mode = 'showing';
} else {
if (track.mode !== 'showing') {
track.mode = 'showing';
}
} else if (track.mode !== 'disabled') {
track.mode = 'disabled';
}
}
@@ -120,6 +125,25 @@ class TextTrackMenuItem extends MenuItem {
this.selected(this.track.mode === 'showing');
}
handleSelectedLanguageChange(event) {
if (this.track.mode === 'showing') {
const selectedLanguage = this.player_.cache_.selectedLanguage;
// Don't replace the kind of track across the same language
if (selectedLanguage && selectedLanguage.enabled &&
selectedLanguage.language === this.track.language &&
selectedLanguage.kind !== this.track.kind) {
return;
}
this.player_.cache_.selectedLanguage = {
enabled: true,
language: this.track.language,
kind: this.track.kind
};
}
}
}
Component.registerComponent('TextTrackMenuItem', TextTrackMenuItem);
@@ -1,8 +1,10 @@
/**
* @file current-time-display.js
*/
import document from 'global/document';
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import {bind, throttle} from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
/**
@@ -23,8 +25,8 @@ class CurrentTimeDisplay extends Component {
*/
constructor(player, options) {
super(player, options);
this.on(player, 'timeupdate', this.updateContent);
this.throttledUpdateContent = throttle(bind(this, this.updateContent), 25);
this.on(player, 'timeupdate', this.throttledUpdateContent);
}
/**
@@ -39,18 +41,34 @@ class CurrentTimeDisplay extends Component {
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-current-time-display',
// label the current time for screen reader users
innerHTML: '<span class="vjs-control-text">Current Time </span>' + '0:00'
className: 'vjs-current-time-display'
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
});
}, Dom.createEl('span', {
className: 'vjs-control-text',
textContent: this.localize('Current Time')
}));
this.updateTextNode_();
el.appendChild(this.contentEl_);
return el;
}
/**
* Updates the "current time" text node with new content using the
* contents of the `formattedTime_` property.
*
* @private
*/
updateTextNode_() {
if (this.textNode_) {
this.contentEl_.removeChild(this.textNode_);
}
this.textNode_ = document.createTextNode(` ${this.formattedTime_ || '0:00'}`);
this.contentEl_.appendChild(this.textNode_);
}
/**
* Update current time display
*
@@ -62,12 +80,11 @@ class CurrentTimeDisplay extends Component {
updateContent(event) {
// Allows for smooth scrubbing, when player can't keep up.
const time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
const localizedText = this.localize('Current Time');
const formattedTime = formatTime(time, this.player_.duration());
if (formattedTime !== this.formattedTime_) {
this.formattedTime_ = formattedTime;
this.contentEl_.innerHTML = `<span class="vjs-control-text">${localizedText}</span> ${formattedTime}`;
this.requestAnimationFrame(this.updateTextNode_);
}
}
@@ -1,8 +1,10 @@
/**
* @file duration-display.js
*/
import document from 'global/document';
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import {bind, throttle} from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
/**
@@ -24,13 +26,17 @@ class DurationDisplay extends Component {
constructor(player, options) {
super(player, options);
this.on(player, 'durationchange', this.updateContent);
this.throttledUpdateContent = throttle(bind(this, this.updateContent), 25);
// Also listen for timeupdate and loadedmetadata because removing those
// listeners could have broken dependent applications/libraries. These
// can likely be removed for 6.0.
this.on(player, 'timeupdate', this.updateContent);
this.on(player, 'loadedmetadata', this.updateContent);
this.on(player, [
'durationchange',
// Also listen for timeupdate and loadedmetadata because removing those
// listeners could have broken dependent applications/libraries. These
// can likely be removed for 7.0.
'loadedmetadata',
'timeupdate'
], this.throttledUpdateContent);
}
/**
@@ -45,18 +51,34 @@ class DurationDisplay extends Component {
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-duration-display',
// label the duration time for screen reader users
innerHTML: `<span class="vjs-control-text">${this.localize('Duration Time')}</span> 0:00`
className: 'vjs-duration-display'
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
});
}, Dom.createEl('span', {
className: 'vjs-control-text',
textContent: this.localize('Duration Time')
}));
this.updateTextNode_();
el.appendChild(this.contentEl_);
return el;
}
/**
* Updates the "current time" text node with new content using the
* contents of the `formattedTime_` property.
*
* @private
*/
updateTextNode_() {
if (this.textNode_) {
this.contentEl_.removeChild(this.textNode_);
}
this.textNode_ = document.createTextNode(` ${this.formattedTime_ || '0:00'}`);
this.contentEl_.appendChild(this.textNode_);
}
/**
* Update duration time display.
*
@@ -73,14 +95,10 @@ class DurationDisplay extends Component {
if (duration && this.duration_ !== duration) {
this.duration_ = duration;
const localizedText = this.localize('Duration Time');
const formattedTime = formatTime(duration);
// label the duration time for screen reader users
this.contentEl_.innerHTML = `<span class="vjs-control-text">${localizedText}</span> ${formattedTime}`;
this.formattedTime_ = formatTime(duration);
this.requestAnimationFrame(this.updateTextNode_);
}
}
}
Component.registerComponent('DurationDisplay', DurationDisplay);
@@ -1,8 +1,10 @@
/**
* @file remaining-time-display.js
*/
import document from 'global/document';
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import {bind, throttle} from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
/**
@@ -23,9 +25,8 @@ class RemainingTimeDisplay extends Component {
*/
constructor(player, options) {
super(player, options);
this.on(player, 'timeupdate', this.updateContent);
this.on(player, 'durationchange', this.updateContent);
this.throttledUpdateContent = throttle(bind(this, this.updateContent), 25);
this.on(player, ['timeupdate', 'durationchange'], this.throttledUpdateContent);
}
/**
@@ -40,18 +41,34 @@ class RemainingTimeDisplay extends Component {
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-remaining-time-display',
// label the remaining time for screen reader users
innerHTML: `<span class="vjs-control-text">${this.localize('Remaining Time')}</span> -0:00`
className: 'vjs-remaining-time-display'
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
});
}, Dom.createEl('span', {
className: 'vjs-control-text',
textContent: this.localize('Remaining Time')
}));
this.updateTextNode_();
el.appendChild(this.contentEl_);
return el;
}
/**
* Updates the "remaining time" text node with new content using the
* contents of the `formattedTime_` property.
*
* @private
*/
updateTextNode_() {
if (this.textNode_) {
this.contentEl_.removeChild(this.textNode_);
}
this.textNode_ = document.createTextNode(` -${this.formattedTime_ || '0:00'}`);
this.contentEl_.appendChild(this.textNode_);
}
/**
* Update remaining time display.
*
@@ -63,20 +80,14 @@ class RemainingTimeDisplay extends Component {
*/
updateContent(event) {
if (this.player_.duration()) {
const localizedText = this.localize('Remaining Time');
const formattedTime = formatTime(this.player_.remainingTime());
if (formattedTime !== this.formattedTime_) {
this.formattedTime_ = formattedTime;
this.contentEl_.innerHTML = `<span class="vjs-control-text">${localizedText}</span> -${formattedTime}`;
this.requestAnimationFrame(this.updateTextNode_);
}
}
// Allows for smooth scrubbing, when player can't keep up.
// var time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
// this.contentEl_.innerHTML = vjs.formatTime(time, this.player_.duration());
}
}
Component.registerComponent('RemainingTimeDisplay', RemainingTimeDisplay);
+72 -21
Ver Arquivo
@@ -4,6 +4,7 @@
// Subclasses Component
import Component from './component.js';
import {version} from '../../package.json';
import document from 'global/document';
import window from 'global/window';
import tsml from 'tsml';
@@ -14,7 +15,7 @@ import * as Fn from './utils/fn.js';
import * as Guid from './utils/guid.js';
import * as browser from './utils/browser.js';
import log from './utils/log.js';
import toTitleCase from './utils/to-title-case.js';
import toTitleCase, { titleCaseEquals } from './utils/to-title-case.js';
import { createTimeRange } from './utils/time-ranges.js';
import { bufferedPercent } from './utils/buffer.js';
import * as stylesheet from './utils/stylesheet.js';
@@ -147,7 +148,7 @@ const TECH_EVENTS_RETRIGGER = [
/**
* Fires when the browser has loaded the current frame of the audio/video.
*
* @event player#loadeddata
* @event Player#loadeddata
* @type {event}
*/
/**
@@ -163,7 +164,7 @@ const TECH_EVENTS_RETRIGGER = [
/**
* Fires when the current playback position has changed.
*
* @event player#timeupdate
* @event Player#timeupdate
* @type {event}
*/
/**
@@ -179,7 +180,7 @@ const TECH_EVENTS_RETRIGGER = [
/**
* Fires when the playing speed of the audio/video is changed
*
* @event player#ratechange
* @event Player#ratechange
* @type {event}
*/
/**
@@ -211,7 +212,7 @@ const TECH_EVENTS_RETRIGGER = [
/**
* Fires when the volume has been changed
*
* @event player#volumechange
* @event Player#volumechange
* @type {event}
*/
/**
@@ -227,7 +228,7 @@ const TECH_EVENTS_RETRIGGER = [
/**
* Fires when the text track has been changed
*
* @event player#texttrackchange
* @event Player#texttrackchange
* @type {event}
*/
/**
@@ -442,6 +443,11 @@ class Player extends Component {
// Make player easily findable by ID
Player.players[this.id_] = this;
// Add a major version class to aid css in plugins
const majorVersion = version.split('.')[0];
this.addClass(`vjs-v${majorVersion}`);
// When the player is first initialized, trigger activity so components
// like the control bar show themselves if needed
this.userActive(true);
@@ -855,6 +861,7 @@ class Player extends Component {
'playerId': this.id(),
'techId': `${this.id()}_${titleTechName}_api`,
'autoplay': this.options_.autoplay,
'playsinline': this.options_.playsinline,
'preload': this.options_.preload,
'loop': this.options_.loop,
'muted': this.options_.muted,
@@ -1282,7 +1289,8 @@ class Player extends Component {
*
* @fires Player#firstplay
* @listens Tech#firstplay
* @deprecated As of 6.0 passing the `starttime` option to the player will be deprecated
* @deprecated As of 6.0 firstplay event is deprecated.
* @deprecated As of 6.0 passing the `starttime` option to the player and the firstplay event are deprecated.
* @private
*/
handleTechFirstPlay_() {
@@ -1300,6 +1308,7 @@ class Player extends Component {
* reason to prevent playback, use `myPlayer.one('play');` instead.
*
* @event Player#firstplay
* @deprecated As of 6.0 firstplay event is deprecated.
* @type {EventTarget~Event}
*/
this.trigger('firstplay');
@@ -1738,10 +1747,11 @@ class Player extends Component {
*/
duration(seconds) {
if (seconds === undefined) {
return this.cache_.duration || 0;
// return NaN if the duration is not known
return this.cache_.duration !== undefined ? this.cache_.duration : NaN;
}
seconds = parseFloat(seconds) || 0;
seconds = parseFloat(seconds);
// Standardize on Inifity for signaling video is live
if (seconds < 0) {
@@ -2237,17 +2247,19 @@ class Player extends Component {
}
/**
* The source function updates the video source
* There are three types of variables you can pass as the argument.
* **URL string**: A URL to the the video file. Use this method if you are sure
* the current playback technology (HTML5/Flash) can support the source you
* provide. Currently only MP4 files can be used in both HTML5 and Flash.
* Get or set the video source.
*
* @param {Tech~SourceObject|Tech~SourceObject[]} [source]
* One SourceObject or an array of SourceObjects
* @param {Tech~SourceObject|Tech~SourceObject[]|string} [source]
* A SourceObject, an array of SourceObjects, or a string referencing
* a URL to a media source. It is _highly recommended_ that an object
* or array of objects is used here, so that source selection
* algorithms can take the `type` into account.
*
* @return {string}
* The current video source when getting
* If not provided, this method acts as a getter.
*
* @return {string|undefined}
* If the `source` argument is missing, returns the current source
* URL. Otherwise, returns nothing/undefined.
*/
src(source) {
// getter usage
@@ -2326,7 +2338,7 @@ class Player extends Component {
return true;
}
if (sourceTech.tech !== this.techName_) {
if (!titleCaseEquals(sourceTech.tech, this.techName_)) {
this.changingSrc_ = true;
// load this technology with the chosen source
@@ -2466,6 +2478,31 @@ class Player extends Component {
return this.techGet_('autoplay', value);
}
/**
* Set or unset the playsinline attribute.
* Playsinline tells the browser that non-fullscreen playback is preferred.
*
* @param {boolean} [value]
* - true means that we should try to play inline by default
* - false means that we should use the browser's default playback mode,
* which in most cases is inline. iOS Safari is a notable exception
* and plays fullscreen by default.
*
* @return {string|Player}
* - the current value of playsinline
* - the player when setting
*
* @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
*/
playsinline(value) {
if (value !== undefined) {
this.techCall_('setPlaysinline', value);
this.options_.playsinline = value;
return this;
}
return this.techGet_('playsinline');
}
/**
* Get or set the loop attribute on the video element.
*
@@ -2528,7 +2565,7 @@ class Player extends Component {
* asynchronous way. We want the poster component to use this
* poster source so that it covers up the tech's controls.
* (YouTube's play button). However we only want to use this
* soruce if the player user hasn't set a poster through
* source if the player user hasn't set a poster through
* the normal APIs.
*
* @fires Player#posterchange
@@ -2995,6 +3032,20 @@ class Player extends Component {
}
}
/**
* Gets available media playback quality metrics as specified by the W3C's Media
* Playback Quality API.
*
* @see [Spec]{@link https://wicg.github.io/media-playback-quality}
*
* @return {Object|undefined}
* An object with supported media playback quality metrics or undefined if there
* is no tech or the tech does not support it.
*/
getVideoPlaybackQuality() {
return this.techGet_('getVideoPlaybackQuality');
}
/**
* Get video width
*
@@ -3218,7 +3269,7 @@ class Player extends Component {
* @return {TextTrackList}
* The current remote text track list
*
* @method Player.prototype.textTracks
* @method Player.prototype.remoteTextTracks
*/
/**
+63 -8
Ver Arquivo
@@ -75,6 +75,27 @@ const markPluginAsActive = (player, name) => {
player[PLUGIN_CACHE_KEY][name] = true;
};
/**
* Triggers a pair of plugin setup events.
*
* @private
* @param {Player} player
* A Video.js player instance.
*
* @param {Plugin~PluginEventHash} hash
* A plugin event hash.
*
* @param {Boolean} [before]
* If true, prefixes the event name with "before". In other words,
* use this to trigger "beforepluginsetup" instead of "pluginsetup".
*/
const triggerSetupEvent = (player, hash, before) => {
const eventName = (before ? 'before' : '') + 'pluginsetup';
player.trigger(eventName, hash);
player.trigger(eventName + ':' + hash.name, hash);
};
/**
* Takes a basic plugin function and returns a wrapper function which marks
* on the player that the plugin has been activated.
@@ -91,15 +112,20 @@ const markPluginAsActive = (player, name) => {
*/
const createBasicPlugin = function(name, plugin) {
const basicPluginWrapper = function() {
// We trigger the "beforepluginsetup" and "pluginsetup" events on the player
// regardless, but we want the hash to be consistent with the hash provided
// for advanced plugins.
//
// The only potentially counter-intuitive thing here is the `instance` in
// the "pluginsetup" event is the value returned by the `plugin` function.
triggerSetupEvent(this, {name, plugin, instance: null}, true);
const instance = plugin.apply(this, arguments);
markPluginAsActive(this, name);
triggerSetupEvent(this, {name, plugin, instance});
// We trigger the "pluginsetup" event on the player regardless, but we want
// the hash to be consistent with the hash provided for advanced plugins.
// The only potentially counter-intuitive thing here is the `instance` is the
// value returned by the `plugin` function.
this.trigger('pluginsetup', {name, plugin, instance});
return instance;
};
@@ -133,11 +159,15 @@ const createPluginFactory = (name, PluginSubClass) => {
PluginSubClass.prototype.name = name;
return function(...args) {
triggerSetupEvent(this, {name, plugin: PluginSubClass, instance: null}, true);
const instance = new PluginSubClass(...[this, ...args]);
// The plugin is replaced by a function that returns the current instance.
this[name] = () => instance;
triggerSetupEvent(this, instance.getEventHash());
return instance;
};
};
@@ -147,7 +177,10 @@ const createPluginFactory = (name, PluginSubClass) => {
*
* @mixes module:evented~EventedMixin
* @mixes module:stateful~StatefulMixin
* @fires Player#beforepluginsetup
* @fires Player#beforepluginsetup:$name
* @fires Player#pluginsetup
* @fires Player#pluginsetup:$name
* @listens Player#dispose
* @throws {Error}
* If attempting to instantiate the base {@link Plugin} class
@@ -164,12 +197,12 @@ class Plugin {
* A Video.js player instance.
*/
constructor(player) {
this.player = player;
if (this.constructor === Plugin) {
throw new Error('Plugin must be sub-classed; not directly instantiated.');
}
this.player = player;
// Make this object evented, but remove the added `trigger` method so we
// use the prototype version instead.
evented(this);
@@ -184,7 +217,6 @@ class Plugin {
// If the player is disposed, dispose the plugin.
player.on('dispose', this.dispose);
player.trigger('pluginsetup', this.getEventHash());
}
/**
@@ -432,6 +464,21 @@ Player.prototype.hasPlugin = function(name) {
export default Plugin;
/**
* Signals that a plugin is about to be set up on a player.
*
* @event Player#beforepluginsetup
* @type {Plugin~PluginEventHash}
*/
/**
* Signals that a plugin is about to be set up on a player - by name. The name
* is the name of the plugin.
*
* @event Player#beforepluginsetup:$name
* @type {Plugin~PluginEventHash}
*/
/**
* Signals that a plugin has just been set up on a player.
*
@@ -439,6 +486,14 @@ export default Plugin;
* @type {Plugin~PluginEventHash}
*/
/**
* Signals that a plugin has just been set up on a player - by name. The name
* is the name of the plugin.
*
* @event Player#pluginsetup:$name
* @type {Plugin~PluginEventHash}
*/
/**
* @typedef {Object} Plugin~PluginEventHash
*
+96 -20
Ver Arquivo
@@ -234,7 +234,7 @@ class Html5 extends Tech {
}
// Update specific tag settings, in case they were overridden
const settingsAttrs = ['autoplay', 'preload', 'loop', 'muted'];
const settingsAttrs = ['autoplay', 'preload', 'loop', 'muted', 'playsinline'];
for (let i = settingsAttrs.length - 1; i >= 0; i--) {
const attr = settingsAttrs[i];
@@ -368,24 +368,26 @@ class Html5 extends Tech {
// playback has started, which triggers the live display erroneously.
// Return NaN if playback has not started and trigger a durationupdate once
// the duration can be reliably known.
if (this.el_.duration === Infinity &&
browser.IS_ANDROID && browser.IS_CHROME) {
if (this.el_.currentTime === 0) {
// Wait for the first `timeupdate` with currentTime > 0 - there may be
// several with 0
const checkProgress = () => {
if (this.el_.currentTime > 0) {
// Trigger durationchange for genuinely live video
if (this.el_.duration === Infinity) {
this.trigger('durationchange');
}
this.off('timeupdate', checkProgress);
if (
this.el_.duration === Infinity &&
browser.IS_ANDROID &&
browser.IS_CHROME &&
this.el_.currentTime === 0
) {
// Wait for the first `timeupdate` with currentTime > 0 - there may be
// several with 0
const checkProgress = () => {
if (this.el_.currentTime > 0) {
// Trigger durationchange for genuinely live video
if (this.el_.duration === Infinity) {
this.trigger('durationchange');
}
};
this.off('timeupdate', checkProgress);
}
};
this.on('timeupdate', checkProgress);
return NaN;
}
this.on('timeupdate', checkProgress);
return NaN;
}
return this.el_.duration || NaN;
}
@@ -430,9 +432,12 @@ class Html5 extends Tech {
};
const beginFn = function() {
this.one('webkitendfullscreen', endFn);
if ('webkitPresentationMode' in this.el_ &&
this.el_.webkitPresentationMode !== 'picture-in-picture') {
this.one('webkitendfullscreen', endFn);
this.trigger('fullscreenchange', { isFullscreen: true });
this.trigger('fullscreenchange', { isFullscreen: true });
}
};
this.on('webkitbeginfullscreen', beginFn);
@@ -667,6 +672,77 @@ class Html5 extends Tech {
}
}
}
/**
* Get the value of `playsinline` from the media element. `playsinline` indicates
* to the browser that non-fullscreen playback is preferred when fullscreen
* playback is the native default, such as in iOS Safari.
*
* @method Html5#playsinline
* @return {boolean}
* - The value of `playsinline` from the media element.
* - True indicates that the media should play inline.
* - False indicates that the media should not play inline.
*
* @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
*/
playsinline() {
return this.el_.hasAttribute('playsinline');
}
/**
* Set the value of `playsinline` from the media element. `playsinline` indicates
* to the browser that non-fullscreen playback is preferred when fullscreen
* playback is the native default, such as in iOS Safari.
*
* @method Html5#setPlaysinline
* @param {boolean} playsinline
* - True indicates that the media should play inline.
* - False indicates that the media should not play inline.
*
* @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
*/
setPlaysinline(value) {
if (value) {
this.el_.setAttribute('playsinline', 'playsinline');
} else {
this.el_.removeAttribute('playsinline');
}
}
/**
* Gets available media playback quality metrics as specified by the W3C's Media
* Playback Quality API.
*
* @see [Spec]{@link https://wicg.github.io/media-playback-quality}
*
* @return {Object}
* An object with supported media playback quality metrics
*/
getVideoPlaybackQuality() {
if (typeof this.el().getVideoPlaybackQuality === 'function') {
return this.el().getVideoPlaybackQuality();
}
const videoPlaybackQuality = {};
if (typeof this.el().webkitDroppedFrameCount !== 'undefined' &&
typeof this.el().webkitDecodedFrameCount !== 'undefined') {
videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount;
videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount;
}
if (window.performance && typeof window.performance.now === 'function') {
videoPlaybackQuality.creationTime = window.performance.now();
} else if (window.performance &&
window.performance.timing &&
typeof window.performance.timing.navigationStart === 'number') {
videoPlaybackQuality.creationTime =
window.Date.now() - window.performance.timing.navigationStart;
}
return videoPlaybackQuality;
}
}
/* HTML5 Support Testing ---------------------------------------------------- */
@@ -761,7 +837,7 @@ Html5.canControlVolume = function() {
Html5.canControlPlaybackRate = function() {
// Playback rate API is implemented in Android Chrome, but doesn't do anything
// https://github.com/videojs/video.js/issues/3180
if (browser.IS_ANDROID && browser.IS_CHROME) {
if (browser.IS_ANDROID && browser.IS_CHROME && browser.CHROME_VERSION < 58) {
return false;
}
// IE will error if Windows Media Player not installed #3315
+32 -3
Ver Arquivo
@@ -14,6 +14,7 @@ import document from 'global/document';
import {isPlain} from '../utils/obj';
import * as TRACK_TYPES from '../tracks/track-types';
import toTitleCase from '../utils/to-title-case';
import vtt from 'videojs-vtt.js';
/**
* An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string
@@ -516,7 +517,6 @@ class Tech extends Component {
// signals that the Tech is ready at which point Tech.el_ is part of the DOM
// before inserting the WebVTT script
if (document.body.contains(this.el())) {
const vtt = require('videojs-vtt.js');
// load via require if available and vtt.js script location was not passed in
// as an option. novtt builds will turn the above require call into an empty object
@@ -530,7 +530,7 @@ class Tech extends Component {
// passed in
const script = document.createElement('script');
script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.3/vtt.min.js';
script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.4/vtt.min.js';
script.onload = () => {
/**
* Fired when vtt.js is loaded.
@@ -700,7 +700,7 @@ class Tech extends Component {
if (manualCleanup !== true) {
// create the TextTrackList if it doesn't exist
this.autoRemoteTextTracks_.addTrack(htmlTrackElement.track);
this.ready(() => this.autoRemoteTextTracks_.addTrack(htmlTrackElement.track));
}
return htmlTrackElement;
@@ -721,6 +721,21 @@ class Tech extends Component {
this.autoRemoteTextTracks_.removeTrack(track);
}
/**
* Gets available media playback quality metrics as specified by the W3C's Media
* Playback Quality API.
*
* @see [Spec]{@link https://wicg.github.io/media-playback-quality}
*
* @return {Object}
* An object with supported media playback quality metrics
*
* @abstract
*/
getVideoPlaybackQuality() {
return {};
}
/**
* A method to set a poster from a `Tech`.
*
@@ -728,6 +743,20 @@ class Tech extends Component {
*/
setPoster() {}
/**
* A method to check for the presence of the 'playsinine' <video> attribute.
*
* @abstract
*/
playsinline() {}
/**
* A method to set or unset the 'playsinine' <video> attribute.
*
* @abstract
*/
setPlaysinline() {}
/*
* Check if the tech can support the given mime-type.
*
+1 -1
Ver Arquivo
@@ -19,7 +19,7 @@ import document from 'global/document';
*/
const disableOthers = function(list, track) {
for (let i = 0; i < list.length; i++) {
if (track.id === list[i].id) {
if (!Object.keys(list[i]).length || track.id === list[i].id) {
continue;
}
// another audio track is enabled, disable it
+56 -22
Ver Arquivo
@@ -92,6 +92,7 @@ class TextTrackDisplay extends Component {
player.on('loadstart', Fn.bind(this, this.toggleDisplay));
player.on('texttrackchange', Fn.bind(this, this.updateDisplay));
player.on('loadstart', Fn.bind(this, this.preselectTrack));
// This used to be called during player init, but was causing an error
// if a track should show by default and the display hadn't loaded yet.
@@ -111,33 +112,66 @@ class TextTrackDisplay extends Component {
this.player_.addRemoteTextTrack(tracks[i], true);
}
const modes = {captions: 1, subtitles: 1};
const trackList = this.player_.textTracks();
let firstDesc;
let firstCaptions;
this.preselectTrack();
}));
}
for (let i = 0; i < trackList.length; i++) {
const track = trackList[i];
/**
* Preselect a track following this precedence:
* - matches the previously selected {@link TextTrack}'s language and kind
* - matches the previously selected {@link TextTrack}'s language only
* - is the first default captions track
* - is the first default descriptions track
*
* @listens Player#loadstart
*/
preselectTrack() {
const modes = {captions: 1, subtitles: 1};
const trackList = this.player_.textTracks();
const userPref = this.player_.cache_.selectedLanguage;
let firstDesc;
let firstCaptions;
let preferredTrack;
if (track.default) {
if (track.kind === 'descriptions' && !firstDesc) {
firstDesc = track;
} else if (track.kind in modes && !firstCaptions) {
firstCaptions = track;
}
for (let i = 0; i < trackList.length; i++) {
const track = trackList[i];
if (userPref && userPref.enabled &&
userPref.language === track.language) {
// Always choose the track that matches both language and kind
if (track.kind === userPref.kind) {
preferredTrack = track;
// or choose the first track that matches language
} else if (!preferredTrack) {
preferredTrack = track;
}
// clear everything if offTextTrackMenuItem was clicked
} else if (userPref && !userPref.enabled) {
preferredTrack = null;
firstDesc = null;
firstCaptions = null;
} else if (track.default) {
if (track.kind === 'descriptions' && !firstDesc) {
firstDesc = track;
} else if (track.kind in modes && !firstCaptions) {
firstCaptions = track;
}
}
}
// We want to show the first default track but captions and subtitles
// take precedence over descriptions.
// So, display the first default captions or subtitles track
// and otherwise the first default descriptions track.
if (firstCaptions) {
firstCaptions.mode = 'showing';
} else if (firstDesc) {
firstDesc.mode = 'showing';
}
}));
// The preferredTrack matches the user preference and takes
// precendence over all the other tracks.
// So, display the preferredTrack before the first default track
// and the subtitles/captions track before the descriptions track
if (preferredTrack) {
preferredTrack.mode = 'showing';
} else if (firstCaptions) {
firstCaptions.mode = 'showing';
} else if (firstDesc) {
firstDesc.mode = 'showing';
}
}
/**
+8
Ver Arquivo
@@ -61,6 +61,14 @@ class TextTrackList extends TrackList {
track.addEventListener('modechange', Fn.bind(this, function() {
this.trigger('change');
}));
const nonLanguageTextTrackKind = ['metadata', 'chapters'];
if (nonLanguageTextTrackKind.indexOf(track.kind) === -1) {
track.addEventListener('modechange', Fn.bind(this, function() {
this.trigger('selectedlanguagechange');
}));
}
}
}
export default TextTrackList;
+88 -107
Ver Arquivo
@@ -299,8 +299,9 @@ class TextTrackSettings extends ModalDialog {
* @param {string} key
* Configuration key to use during creation.
*
* @return {Element}
* The DOM element that gets created.
* @return {string}
* An HTML string.
*
* @private
*/
createElSelect_(key, legendId = '', type = 'label') {
@@ -308,101 +309,94 @@ class TextTrackSettings extends ModalDialog {
const id = config.id.replace('%s', this.id_);
return [
createEl(type, {
id,
className: type === 'label' ? 'vjs-label' : '',
textContent: this.localize(config.label)
}, {
}),
createEl('select', {}, {
'aria-labelledby': `${legendId} ${id}`
}, config.options.map(o => {
`<${type} id="${id}" class="${type === 'label' ? 'vjs-label' : ''}">`,
this.localize(config.label),
`</${type}>`,
`<select aria-labelledby="${legendId} ${id}">`
].
concat(config.options.map(o => {
const optionId = id + '-' + o[1];
return createEl('option', {
id: optionId,
textContent: this.localize(o[1]),
value: o[0]
}, {
'aria-labelledby': `${legendId} ${id} ${optionId}`
});
}))
];
return [
`<option id="${optionId}" value="${o[0]}" `,
`aria-labelledby="${legendId} ${id} ${optionId}">`,
this.localize(o[1]),
'</option>'
].join('');
})).
concat('</select>').join('');
}
/**
* Create foreground color element for the component
*
* @return {Element}
* The element that was created.
* @return {string}
* An HTML string.
*
* @private
*/
createElFgColor_() {
const legend = createEl('legend', {
id: `captions-text-legend-${this.id_}`,
textContent: this.localize('Text')
});
const legendId = `captions-text-legend-${this.id_}`;
const select = this.createElSelect_('color', legend.id);
const opacity = createEl('span', {
className: 'vjs-text-opacity vjs-opacity'
}, undefined, this.createElSelect_('textOpacity', legend.id));
return createEl('fieldset', {
className: 'vjs-fg-color vjs-track-setting'
}, undefined, [legend].concat(select, opacity));
return [
'<fieldset class="vjs-fg-color vjs-track-setting">',
`<legend id="${legendId}">`,
this.localize('Text'),
'</legend>',
this.createElSelect_('color', legendId),
'<span class="vjs-text-opacity vjs-opacity">',
this.createElSelect_('textOpacity', legendId),
'</span>',
'</fieldset>'
].join('');
}
/**
* Create background color element for the component
*
* @return {Element}
* The element that was created
* @return {string}
* An HTML string.
*
* @private
*/
createElBgColor_() {
const legend = createEl('legend', {
id: `captions-background-${this.id_}`,
textContent: this.localize('Background')
});
const legendId = `captions-background-${this.id_}`;
const select = this.createElSelect_('backgroundColor', legend.id);
const opacity = createEl('span', {
className: 'vjs-bg-opacity vjs-opacity'
}, undefined, this.createElSelect_('backgroundOpacity', legend.id));
return createEl('fieldset', {
className: 'vjs-bg-color vjs-track-setting'
}, undefined, [legend].concat(select, opacity));
return [
'<fieldset class="vjs-bg-color vjs-track-setting">',
`<legend id="${legendId}">`,
this.localize('Background'),
'</legend>',
this.createElSelect_('backgroundColor', legendId),
'<span class="vjs-bg-opacity vjs-opacity">',
this.createElSelect_('backgroundOpacity', legendId),
'</span>',
'</fieldset>'
].join('');
}
/**
* Create window color element for the component
*
* @return {Element}
* The element that was created
* @return {string}
* An HTML string.
*
* @private
*/
createElWinColor_() {
const legend = createEl('legend', {
id: `captions-window-${this.id_}`,
textContent: this.localize('Window')
});
const legendId = `captions-window-${this.id_}`;
const select = this.createElSelect_('windowColor', legend.id);
const opacity = createEl('span', {
className: 'vjs-window-opacity vjs-opacity'
}, undefined, this.createElSelect_('windowOpacity', legend.id));
return createEl('fieldset', {
className: 'vjs-window-color vjs-track-setting'
}, undefined, [legend].concat(select, opacity));
return [
'<fieldset class="vjs-window-color vjs-track-setting">',
`<legend id="${legendId}">`,
this.localize('Window'),
'</legend>',
this.createElSelect_('windowColor', legendId),
'<span class="vjs-window-opacity vjs-opacity">',
this.createElSelect_('windowOpacity', legendId),
'</span>',
'</fieldset>'
].join('');
}
/**
@@ -415,12 +409,13 @@ class TextTrackSettings extends ModalDialog {
*/
createElColors_() {
return createEl('div', {
className: 'vjs-track-settings-colors'
}, undefined, [
this.createElFgColor_(),
this.createElBgColor_(),
this.createElWinColor_()
]);
className: 'vjs-track-settings-colors',
innerHTML: [
this.createElFgColor_(),
this.createElBgColor_(),
this.createElWinColor_()
].join('')
});
}
/**
@@ -432,21 +427,20 @@ class TextTrackSettings extends ModalDialog {
* @private
*/
createElFont_() {
const fontPercent = createEl('fieldset', {
className: 'vjs-font-percent vjs-track-setting'
}, undefined, this.createElSelect_('fontPercent', '', 'legend'));
const edgeStyle = createEl('fieldset', {
className: 'vjs-edge-style vjs-track-setting'
}, undefined, this.createElSelect_('edgeStyle', '', 'legend'));
const fontFamily = createEl('fieldset', {
className: 'vjs-font-family vjs-track-setting'
}, undefined, this.createElSelect_('fontFamily', '', 'legend'));
return createEl('div', {
className: 'vjs-track-settings-font'
}, undefined, [fontPercent, edgeStyle, fontFamily]);
className: 'vjs-track-settings-font">',
innerHTML: [
'<fieldset class="vjs-font-percent vjs-track-setting">',
this.createElSelect_('fontPercent', '', 'legend'),
'</fieldset>',
'<fieldset class="vjs-edge-style vjs-track-setting">',
this.createElSelect_('edgeStyle', '', 'legend'),
'</fieldset>',
'<fieldset class="vjs-font-family vjs-track-setting">',
this.createElSelect_('fontFamily', '', 'legend'),
'</fieldset>'
].join('')
});
}
/**
@@ -459,30 +453,17 @@ class TextTrackSettings extends ModalDialog {
*/
createElControls_() {
const defaultsDescription = this.localize('restore all settings to the default values');
const defaultsButton = createEl('button', {
className: 'vjs-default-button',
title: defaultsDescription,
innerHTML: `${this.localize('Reset')}<span class='vjs-control-text'> ${defaultsDescription}</span>`
});
const doneButton = createEl('button', {
className: 'vjs-done-button',
textContent: this.localize('Done')
});
return createEl('div', {
className: 'vjs-track-settings-controls'
}, undefined, [defaultsButton, doneButton]);
}
/**
* Create the component's DOM element
*
* @return {Element}
* The element that was created.
*/
createEl() {
return super.createEl();
className: 'vjs-track-settings-controls',
innerHTML: [
`<button class="vjs-default-button" title="${defaultsDescription}">`,
this.localize('Reset'),
`<span class="vjs-control-text"> ${defaultsDescription}</span>`,
'</button>',
`<button class="vjs-done-button">${this.localize('Done')}</button>`
].join('')
});
}
content() {
+1
Ver Arquivo
@@ -253,6 +253,7 @@ class TextTrack extends Track {
* @type {EventTarget~Event}
*/
this.trigger('modechange');
}
});
+1 -1
Ver Arquivo
@@ -18,7 +18,7 @@ import document from 'global/document';
*/
const disableOthers = function(list, track) {
for (let i = 0; i < list.length; i++) {
if (track.id === list[i].id) {
if (!Object.keys(list[i]).length || track.id === list[i].id) {
continue;
}
// another video track is enabled, disable it
+19 -3
Ver Arquivo
@@ -62,10 +62,26 @@ export const IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebki
export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
export const IS_EDGE = (/Edge/i).test(USER_AGENT);
export const IS_CHROME = !IS_EDGE && (/Chrome/i).test(USER_AGENT);
export const CHROME_VERSION = (function() {
const match = USER_AGENT.match(/Chrome\/(\d+)/);
if (match && match[1]) {
return parseFloat(match[1]);
}
return null;
}());
export const IS_IE8 = (/MSIE\s8\.0/).test(USER_AGENT);
export const IE_VERSION = (function(result) {
return result && parseFloat(result[1]);
}((/MSIE\s(\d+)\.\d/).exec(USER_AGENT)));
export const IE_VERSION = (function() {
const result = (/MSIE\s(\d+)\.\d/).exec(USER_AGENT);
let version = result && parseFloat(result[1]);
if (!version && (/Trident\/7.0/i).test(USER_AGENT) && (/rv:11.0/).test(USER_AGENT)) {
// IE 11 has a different user agent string than other IE versions
version = 11.0;
}
return version;
}());
export const IS_SAFARI = (/Safari/i).test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
export const IS_ANY_SAFARI = IS_SAFARI || IS_IOS;
+34 -1
Ver Arquivo
@@ -202,6 +202,33 @@ export function fixEvent(event) {
return event;
}
/**
* Whether passive event listeners are supported
*/
let _supportsPassive = false;
(function() {
try {
const opts = Object.defineProperty({}, 'passive', {
get() {
_supportsPassive = true;
}
});
window.addEventListener('test', null, opts);
} catch (e) {
// disregard
}
})();
/**
* Touch events Chrome expects to be passive
*/
const passiveEvents = [
'touchstart',
'touchmove'
];
/**
* Add an event listener to element
* It stores the handler function in a separate cache object
@@ -273,7 +300,13 @@ export function on(elem, type, fn) {
if (data.handlers[type].length === 1) {
if (elem.addEventListener) {
elem.addEventListener(type, data.dispatcher, false);
let options = false;
if (_supportsPassive &&
passiveEvents.indexOf(type) > -1) {
options = {passive: true};
}
elem.addEventListener(type, data.dispatcher, options);
} else if (elem.attachEvent) {
elem.attachEvent('on' + type, data.dispatcher);
}
+16
Ver Arquivo
@@ -21,3 +21,19 @@ function toTitleCase(string) {
}
export default toTitleCase;
/**
* Compares the TitleCase versions of the two strings for equality.
*
* @param {string} str1
* The first string to compare
*
* @param {string} str2
* The second string to compare
*
* @return {boolean}
* Whether the TitleCase versions of the strings are equal
*/
export function titleCaseEquals(str1, str2) {
return toTitleCase(str1) === toTitleCase(str2);
}
+3 -4
Ver Arquivo
@@ -2,6 +2,7 @@
* @file video.js
* @module videojs
*/
import {version} from '../../package.json';
import window from 'global/window';
import document from 'global/document';
import * as setup from './setup';
@@ -225,7 +226,7 @@ setup.autoSetupTimeout(1, videojs);
*
* @type {string}
*/
videojs.VERSION = require('../../package.json').version;
videojs.VERSION = version;
/**
* The global options object. These are the settings that take effect
@@ -722,7 +723,5 @@ videojs.dom = Dom;
*/
videojs.url = Url;
// We use Node-style module.exports here instead of ES6 because it is more
// compatible with different module systems.
module.exports = videojs;
export default videojs;
+1
Ver Arquivo
@@ -59,6 +59,7 @@ QUnit.test('should be able to access expected player API methods', function(asse
assert.ok(player.userActive, 'userActive exists');
assert.ok(player.usingNativeControls, 'usingNativeControls exists');
assert.ok(player.isFullscreen, 'isFullscreen exists');
assert.ok(player.getVideoPlaybackQuality, 'getVideoPlaybackQuality exists');
// Track methods
assert.ok(player.audioTracks, 'audioTracks exists');
+7 -2
Ver Arquivo
@@ -10,7 +10,7 @@ module.exports = function(config) {
// Compling tests here
files: [
'../build/temp/video-js.css',
'../build/temp/ie8/videojs-ie8.min.js',
'../build/temp/ie8/videojs-ie8.js',
'../test/globals-shim.js',
'../test/unit/**/*.js',
'../build/temp/browserify.js',
@@ -124,7 +124,7 @@ module.exports = function(config) {
'ie8_bs'
];
} else {
settings.browsers = ['Firefox'];
settings.browsers = ['chrome_travis'];
}
}
@@ -133,6 +133,11 @@ module.exports = function(config) {
function getCustomLaunchers(){
return {
chrome_travis: {
base: 'Chrome',
flags: ['--no-sandbox']
},
chrome_bs: {
base: 'BrowserStack',
browser: 'chrome',
+22
Ver Arquivo
@@ -71,3 +71,25 @@ QUnit.test('handleClick should not be triggered when disabled', function() {
testClickableComponent.dispose();
player.dispose();
});
QUnit.test('handleClick should not be triggered more than once when enabled', function() {
let clicks = 0;
class TestClickableComponent extends ClickableComponent {
handleClick() {
clicks++;
}
}
const player = TestHelpers.makePlayer({});
const testClickableComponent = new TestClickableComponent(player);
const el = testClickableComponent.el();
testClickableComponent.enable();
// Click should still be handled just once
Events.trigger(el, 'click');
QUnit.equal(clicks, 1, 'no additional click handler when already enabled ClickableComponent has been enabled again');
testClickableComponent.dispose();
player.dispose();
});
+86
Ver Arquivo
@@ -791,6 +791,35 @@ QUnit.test('should restore attributes from the original video tag when creating
assert.equal(el.getAttribute('webkit-playsinline'), '', 'webkit-playsinline attribute was set properly');
});
if (Html5.isSupported()) {
QUnit.test('player.playsinline() should be able to get/set playsinline attribute', function(assert) {
assert.expect(5);
const video = document.createElement('video');
const player = TestHelpers.makePlayer({techOrder: ['html5']}, video);
// test setter
assert.ok(!player.tech_.el().hasAttribute('playsinline'), 'playsinline has not yet been added');
player.playsinline(true);
assert.ok(player.tech_.el().hasAttribute('playsinline'), 'playsinline attribute added');
player.playsinline(false);
assert.ok(!player.tech_.el().hasAttribute('playsinline'), 'playsinline attribute removed');
// test getter
player.tech_.el().setAttribute('playsinline', 'playsinline');
assert.ok(player.playsinline(), 'correctly detects playsinline attribute');
player.tech_.el().removeAttribute('playsinline');
assert.ok(!player.playsinline(), 'correctly detects absence of playsinline attribute');
});
}
QUnit.test('if tag exists and movingMediaElementInDOM, re-use the tag', function(assert) {
// simulate attributes stored from the original tag
const tag = Dom.createEl('video');
@@ -1564,6 +1593,26 @@ QUnit.test('src selects tech based on middleware', function(assert) {
});
QUnit.test('src_ does not call loadTech is name is titleCaseEquals', function(assert) {
let loadTechCalled = 0;
const playerProxy = {
selectSource() {
return {
tech: 'html5'
};
},
techName_: 'Html5',
ready() {},
loadTech_() {
loadTechCalled++;
}
};
Player.prototype.src_.call(playerProxy);
assert.equal(loadTechCalled, 0, 'loadTech was not called');
});
QUnit.test('options: plugins', function(assert) {
const optionsSpy = sinon.spy();
@@ -1597,3 +1646,40 @@ QUnit.test('options: plugins', function(assert) {
player.dispose();
Plugin.deregisterPlugin('foo');
});
QUnit.test('should add a class with major version', function(assert) {
const majorVersion = require('../../package.json').version.split('.')[0];
const player = TestHelpers.makePlayer();
assert.ok(player.hasClass('vjs-v' + majorVersion), 'the version class should be added to the player');
player.dispose();
});
QUnit.test('player.duration() returns NaN if player.cache_.duration is undefined', function(assert) {
const player = TestHelpers.makePlayer();
player.cache_.duration = undefined;
assert.ok(Number.isNaN(player.duration()), 'returned NaN for unkown duration');
});
QUnit.test('player.duration() returns player.cache_.duration if it is defined', function(assert) {
const player = TestHelpers.makePlayer();
player.cache_.duration = 200;
assert.equal(player.duration(), 200, 'returned correct integer duration');
player.cache_.duration = 942;
assert.equal(player.duration(), 942, 'returned correct integer duration');
});
QUnit.test('player.duration() sets the value of player.cache_.duration', function(assert) {
const player = TestHelpers.makePlayer();
// set an arbitrary initial cached duration value for testing the setter functionality
player.cache_.duration = 1;
player.duration(NaN);
assert.ok(Number.isNaN(player.duration()), 'duration() set and get NaN duration value');
player.duration(200);
assert.equal(player.duration(), 200, 'duration() set and get integer duration value');
});
+23 -12
Ver Arquivo
@@ -67,24 +67,35 @@ QUnit.test('setup', function(assert) {
);
});
QUnit.test('"pluginsetup" event', function(assert) {
QUnit.test('all "pluginsetup" events', function(assert) {
const setupSpy = sinon.spy();
const events = [
'beforepluginsetup',
'beforepluginsetup:mock',
'pluginsetup',
'pluginsetup:mock'
];
this.player.on('pluginsetup', setupSpy);
this.player.on(events, setupSpy);
const instance = this.player.mock();
const event = setupSpy.firstCall.args[0];
const hash = setupSpy.firstCall.args[1];
assert.strictEqual(setupSpy.callCount, 1, 'the "pluginsetup" event was triggered');
assert.strictEqual(event.type, 'pluginsetup', 'the event has the correct type');
assert.strictEqual(event.target, this.player.el_, 'the event has the correct target');
events.forEach((type, i) => {
const event = setupSpy.getCall(i).args[0];
const hash = setupSpy.getCall(i).args[1];
assert.deepEqual(hash, {
name: 'mock',
instance,
plugin: this.MockPlugin
}, 'the event hash object is correct');
assert.strictEqual(event.type, type, `the "${type}" event was triggered`);
assert.strictEqual(event.target, this.player.el_, 'the event has the correct target');
assert.deepEqual(hash, {
name: 'mock',
// The "before" events have a `null` instance and the others have the
// return value of the plugin factory.
instance: i < 2 ? null : instance,
plugin: this.MockPlugin
}, 'the event hash object is correct');
});
});
QUnit.test('defaultState static property is used to populate state', function(assert) {
+23 -11
Ver Arquivo
@@ -47,23 +47,35 @@ QUnit.test('setup', function(assert) {
assert.ok(this.player.hasPlugin('basic'), 'player has the plugin available');
});
QUnit.test('"pluginsetup" event', function(assert) {
QUnit.test('all "pluginsetup" events', function(assert) {
const setupSpy = sinon.spy();
const events = [
'beforepluginsetup',
'beforepluginsetup:basic',
'pluginsetup',
'pluginsetup:basic'
];
this.player.on('pluginsetup', setupSpy);
this.player.on(events, setupSpy);
const instance = this.player.basic();
const event = setupSpy.firstCall.args[0];
const hash = setupSpy.firstCall.args[1];
assert.strictEqual(setupSpy.callCount, 1, 'the "pluginsetup" event was triggered');
assert.strictEqual(event.type, 'pluginsetup', 'the event has the correct type');
events.forEach((type, i) => {
const event = setupSpy.getCall(i).args[0];
const hash = setupSpy.getCall(i).args[1];
assert.deepEqual(hash, {
name: 'basic',
instance,
plugin: this.basic
}, 'the event hash object is correct');
assert.strictEqual(event.type, type, `the "${type}" event was triggered`);
assert.strictEqual(event.target, this.player.el_, 'the event has the correct target');
assert.deepEqual(hash, {
name: 'basic',
// The "before" events have a `null` instance and the others have the
// return value of the plugin factory.
instance: i < 2 ? null : instance,
plugin: this.basic
}, 'the event hash object is correct');
});
});
QUnit.test('properties are copied', function(assert) {
+2 -1
Ver Arquivo
@@ -7,12 +7,13 @@ QUnit.test('should set options from data-setup even if autoSetup is not called b
const el = TestHelpers.makeTag();
el.setAttribute('data-setup',
'{"controls": true, "autoplay": false, "preload": "auto"}');
'{"controls": true, "autoplay": false, "preload": "auto", "playsinline": true}');
const player = TestHelpers.makePlayer({}, el);
assert.ok(player.options_.controls === true);
assert.ok(player.options_.autoplay === false);
assert.ok(player.options_.preload === 'auto');
assert.ok(player.options_.playsinline === true);
player.dispose();
});
+119
Ver Arquivo
@@ -50,6 +50,19 @@ QUnit.module('HTML5', {
}
});
QUnit.test('should be able to set playsinline attribute', function(assert) {
assert.expect(2);
tech.createEl();
tech.setPlaysinline(true);
assert.ok(tech.el().hasAttribute('playsinline'), 'playsinline attribute was added');
tech.setPlaysinline(false);
assert.ok(!tech.el().hasAttribute('playsinline'), 'playsinline attribute was removed');
});
QUnit.test('should detect whether the volume can be changed', function(assert) {
if (!{}.__defineSetter__) {
@@ -100,6 +113,32 @@ QUnit.test('test defaultPlaybackRate', function(assert) {
assert.strictEqual(tech.defaultPlaybackRate(), 0.75, 'can be changed from the API');
});
QUnit.test('blacklist playbackRate support on older verisons of Chrome on Android', function(assert) {
if (!Html5.canControlPlaybackRate()) {
assert.ok(true, 'playbackRate is not supported');
return;
}
// Reset playbackrate - Firefox's rounding of playbackRate causes the rate not to change in canControlPlaybackRate() after a few instances
Html5.TEST_VID.playbackRate = 1;
const oldIsAndroid = browser.IS_ANDROID;
const oldIsChrome = browser.IS_CHROME;
const oldChromeVersion = browser.CHROME_VERSION;
browser.IS_ANDROID = true;
browser.IS_CHROME = true;
browser.CHROME_VERSION = 50;
assert.strictEqual(Html5.canControlPlaybackRate(), false, 'canControlPlaybackRate should return false on older Chrome');
browser.CHROME_VERSION = 58;
assert.strictEqual(Html5.canControlPlaybackRate(), true, 'canControlPlaybackRate should return true on newer Chrome');
browser.IS_ANDROID = oldIsAndroid;
browser.IS_CHROME = oldIsChrome;
browser.CHROME_VERSION = oldChromeVersion;
});
QUnit.test('test volume', function(assert) {
if (!Html5.canControlVolume()) {
assert.ok(true, 'Volume is not supported');
@@ -665,3 +704,83 @@ test('When Android Chrome reports Infinity duration with currentTime 0, return N
browser.IS_CHROME = oldIsChrome;
tech.el_ = oldEl;
});
QUnit.test('supports getting available media playback quality metrics', function(assert) {
const origPerformance = window.performance;
const origDate = window.Date;
const oldEl = tech.el_;
const videoPlaybackQuality = {
creationTime: 1,
corruptedVideoFrames: 2,
droppedVideoFrames: 3,
totalVideoFrames: 5
};
tech.el_ = {
getVideoPlaybackQuality: () => videoPlaybackQuality
};
assert.deepEqual(tech.getVideoPlaybackQuality(),
videoPlaybackQuality,
'uses native implementation when supported');
tech.el_ = {
webkitDroppedFrameCount: 1,
webkitDecodedFrameCount: 2
};
window.performance = {
now: () => 4
};
assert.deepEqual(tech.getVideoPlaybackQuality(),
{ droppedVideoFrames: 1, totalVideoFrames: 2, creationTime: 4 },
'uses webkit prefixed metrics and performance.now when supported');
tech.el_ = {
webkitDroppedFrameCount: 1,
webkitDecodedFrameCount: 2
};
window.Date = {
now: () => 10
};
window.performance = {
timing: {
navigationStart: 3
}
};
assert.deepEqual(tech.getVideoPlaybackQuality(),
{ droppedVideoFrames: 1, totalVideoFrames: 2, creationTime: 7 },
'uses webkit prefixed metrics and Date.now() - navigationStart when ' +
'supported');
tech.el_ = {};
window.performance = void 0;
assert.deepEqual(tech.getVideoPlaybackQuality(), {}, 'empty object when not supported');
window.performance = {
now: () => 5
};
assert.deepEqual(tech.getVideoPlaybackQuality(),
{ creationTime: 5 },
'only creation time when it\'s the only piece available');
window.performance = {
timing: {
navigationStart: 3
}
};
assert.deepEqual(tech.getVideoPlaybackQuality(),
{ creationTime: 7 },
'only creation time when it\'s the only piece available');
tech.el_ = {
getVideoPlaybackQuality: () => videoPlaybackQuality,
webkitDroppedFrameCount: 1,
webkitDecodedFrameCount: 2
};
assert.deepEqual(tech.getVideoPlaybackQuality(),
videoPlaybackQuality,
'prefers native implementation when supported');
tech.el_ = oldEl;
window.performance = origPerformance;
window.Date = origDate;
});
+11
Ver Arquivo
@@ -214,11 +214,14 @@ QUnit.test('switching sources should clear all remote tracks that are added with
const tech = new MyTech();
tech.triggerReady();
// set the initial source
tech.setSource({src: 'foo.mp4', type: 'mp4'});
// default value for manualCleanup is true
tech.addRemoteTextTrack({});
this.clock.tick(1);
assert.equal(warning,
'Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js',
@@ -226,6 +229,7 @@ QUnit.test('switching sources should clear all remote tracks that are added with
// should be automatically cleaned up when source changes
tech.addRemoteTextTrack({}, false);
this.clock.tick(1);
assert.equal(tech.textTracks().length, 2, 'should have two text tracks at the start');
assert.equal(tech.remoteTextTrackEls().length,
@@ -238,6 +242,7 @@ QUnit.test('switching sources should clear all remote tracks that are added with
// change source to force cleanup of auto remote text tracks
tech.setSource({src: 'bar.mp4', type: 'mp4'});
this.clock.tick(1);
assert.equal(tech.textTracks().length,
1,
@@ -601,3 +606,9 @@ QUnit.test('setSource after previous setSource should dispose source handler onc
assert.equal(disposeCount, 2, 'did dispose for third setSource');
});
QUnit.test('returns an empty object for getVideoPlaybackQuality', function(assert) {
const tech = new Tech();
assert.deepEqual(tech.getVideoPlaybackQuality(), {}, 'returns an empty object');
});
+322
Ver Arquivo
@@ -0,0 +1,322 @@
/* eslint-env qunit */
import Html5 from '../../../src/js/tech/html5.js';
import Component from '../../../src/js/component.js';
import * as browser from '../../../src/js/utils/browser.js';
import TestHelpers from '../test-helpers.js';
import document from 'global/document';
import sinon from 'sinon';
QUnit.module('Text Track Display', {
beforeEach(assert) {
this.clock = sinon.useFakeTimers();
},
afterEach(assert) {
this.clock.restore();
}
});
const getMenuItemByLanguage = function(items, language) {
for (let i = items.length - 1; i > 0; i--) {
const captionMenuItem = items[i];
const trackLanguage = captionMenuItem.track.language;
if (trackLanguage && trackLanguage === language) {
return captionMenuItem;
}
}
};
QUnit.test('if native text tracks are not supported, create a texttrackdisplay', function(assert) {
const oldTestVid = Html5.TEST_VID;
const oldIsFirefox = browser.IS_FIREFOX;
const oldTextTrackDisplay = Component.getComponent('TextTrackDisplay');
const tag = document.createElement('video');
const track1 = document.createElement('track');
const track2 = document.createElement('track');
track1.kind = 'captions';
track1.label = 'en';
track1.language = 'English';
track1.src = 'en.vtt';
tag.appendChild(track1);
track2.kind = 'captions';
track2.label = 'es';
track2.language = 'Spanish';
track2.src = 'es.vtt';
tag.appendChild(track2);
Html5.TEST_VID = {
textTracks: []
};
browser.IS_FIREFOX = true;
const fakeTTDSpy = sinon.spy();
class FakeTTD extends Component {
constructor() {
super();
fakeTTDSpy();
}
}
Component.registerComponent('TextTrackDisplay', FakeTTD);
const player = TestHelpers.makePlayer({}, tag);
assert.strictEqual(fakeTTDSpy.callCount, 1, 'text track display was created');
Html5.TEST_VID = oldTestVid;
browser.IS_FIREFOX = oldIsFirefox;
Component.registerComponent('TextTrackDisplay', oldTextTrackDisplay);
player.dispose();
});
QUnit.test('shows the default caption track first', function(assert) {
const player = TestHelpers.makePlayer();
const track1 = {
kind: 'captions',
label: 'English',
language: 'en',
src: 'en.vtt',
default: true
};
const track2 = {
kind: 'captions',
label: 'Spanish',
language: 'es',
src: 'es.vtt'
};
// Add the text tracks
const englishTrack = player.addRemoteTextTrack(track1).track;
const spanishTrack = player.addRemoteTextTrack(track2).track;
// Make sure the ready handler runs
this.clock.tick(1);
assert.ok(englishTrack.mode === 'showing', 'English track should be showing');
assert.ok(spanishTrack.mode === 'disabled', 'Spanish track should not be showing');
player.dispose();
});
if (!Html5.supportsNativeTextTracks()) {
QUnit.test('selectedlanguagechange is triggered by a track mode change', function(assert) {
const player = TestHelpers.makePlayer();
const track1 = {
kind: 'captions',
label: 'English',
language: 'en',
src: 'en.vtt'
};
const spy = sinon.spy();
const selectedLanguageHandler = function(event) {
spy();
};
const englishTrack = player.addRemoteTextTrack(track1).track;
player.textTracks().addEventListener('selectedlanguagechange', selectedLanguageHandler);
englishTrack.mode = 'showing';
assert.strictEqual(spy.callCount, 1, 'selectedlanguagechange event was fired');
player.dispose();
});
QUnit.test("if user-selected language is unavailable, don't pick a track to show", function(assert) {
// The video has no default language but has English captions only
const player = TestHelpers.makePlayer();
const track1 = {
kind: 'captions',
label: 'English',
language: 'en',
src: 'en.vtt'
};
const captionsButton = player.controlBar.getChild('SubsCapsButton');
player.src({type: 'video/mp4', src: 'http://google.com'});
// manualCleanUp = true by default
const englishTrack = player.addRemoteTextTrack(track1).track;
// Force 'es' as user-selected track
player.cache_.selectedLanguage = { language: 'es', kind: 'captions' };
this.clock.tick(1);
player.play();
assert.ok(!captionsButton.hasClass('vjs-hidden'), 'The captions button is shown');
assert.ok(englishTrack.mode === 'disabled', 'English track should be disabled');
player.dispose();
});
QUnit.test('the user-selected language takes priority over default language', function(assert) {
// The video has English captions as default, but has Spanish captions also
const player = TestHelpers.makePlayer();
const track1 = {
kind: 'captions',
label: 'English',
language: 'en',
src: 'en.vtt',
default: true
};
const track2 = {
kind: 'captions',
label: 'Spanish',
language: 'es',
src: 'es.vtt'
};
player.src({type: 'video/mp4', src: 'http://google.com'});
// manualCleanUp = true by default
const englishTrack = player.addRemoteTextTrack(track1).track;
const spanishTrack = player.addRemoteTextTrack(track2).track;
// Force 'es' as user-selected track
player.cache_.selectedLanguage = { enabled: true, language: 'es', kind: 'captions' };
this.clock.tick(1);
assert.ok(spanishTrack.mode === 'showing', 'Spanish captions should be shown');
assert.ok(englishTrack.mode === 'disabled', 'English captions should be hidden');
player.dispose();
});
QUnit.test("matching both the selectedLanguage's language and kind takes priority over just matching the language", function(assert) {
const player = TestHelpers.makePlayer();
const track1 = {
kind: 'captions',
label: 'English',
language: 'en',
src: 'en.vtt'
};
const track2 = {
kind: 'subtitles',
label: 'English',
language: 'en',
src: 'en.vtt'
};
player.src({type: 'video/mp4', src: 'http://google.com'});
// manualCleanUp = true by default
const captionTrack = player.addRemoteTextTrack(track1).track;
const subsTrack = player.addRemoteTextTrack(track2).track;
// Force English captions as user-selected track
player.cache_.selectedLanguage = { enabled: true, language: 'en', kind: 'captions' };
this.clock.tick(1);
assert.ok(captionTrack.mode === 'showing', 'Captions track should be preselected');
assert.ok(subsTrack.mode === 'disabled', 'Subtitles track should remain disabled');
player.dispose();
});
QUnit.test('the user-selected language is used for subsequent source changes', function(assert) {
// Start with two captions tracks: English and Spanish
const player = TestHelpers.makePlayer();
const track1 = {
kind: 'captions',
label: 'English',
language: 'en',
src: 'en.vtt'
};
const track2 = {
kind: 'captions',
label: 'Spanish',
language: 'es',
src: 'es.vtt'
};
const tracks = player.tech_.remoteTextTracks();
const captionsButton = player.controlBar.getChild('SubsCapsButton');
let esCaptionMenuItem;
let enCaptionMenuItem;
player.src({type: 'video/mp4', src: 'http://google.com'});
// manualCleanUp = true by default
player.addRemoteTextTrack(track1);
player.addRemoteTextTrack(track2);
// Keep track of menu items
esCaptionMenuItem = getMenuItemByLanguage(captionsButton.items, 'es');
enCaptionMenuItem = getMenuItemByLanguage(captionsButton.items, 'en');
// The user chooses Spanish
player.play();
esCaptionMenuItem.trigger('click');
// Track mode changes on user-selection
assert.ok(esCaptionMenuItem.track.mode === 'showing',
'Spanish should be showing after selection');
assert.ok(enCaptionMenuItem.track.mode === 'disabled',
'English should be disabled after selecting Spanish');
assert.deepEqual(player.cache_.selectedLanguage,
{ enabled: true, language: 'es', kind: 'captions' });
// Switch source and remove old tracks
player.tech_.src({type: 'video/mp4', src: 'http://example.com'});
while (tracks.length > 0) {
player.removeRemoteTextTrack(tracks[0]);
}
// Add tracks for the new source
// change the kind of track to subtitles
track1.kind = 'subtitles';
track2.kind = 'subtitles';
const englishTrack = player.addRemoteTextTrack(track1).track;
const spanishTrack = player.addRemoteTextTrack(track2).track;
// Make sure player ready handler runs
this.clock.tick(1);
// Keep track of menu items
esCaptionMenuItem = getMenuItemByLanguage(captionsButton.items, 'es');
enCaptionMenuItem = getMenuItemByLanguage(captionsButton.items, 'en');
// The user-selection should have persisted
assert.ok(esCaptionMenuItem.track.mode === 'showing',
'Spanish should remain showing');
assert.ok(enCaptionMenuItem.track.mode === 'disabled',
'English should remain disabled');
assert.deepEqual(player.cache_.selectedLanguage,
{ enabled: true, language: 'es', kind: 'captions' });
assert.ok(spanishTrack.mode === 'showing', 'Spanish track remains showing');
assert.ok(englishTrack.mode === 'disabled', 'English track remains disabled');
player.dispose();
});
QUnit.test('the user-selected language is cleared on turning off captions', function(assert) {
const player = TestHelpers.makePlayer();
const track1 = {
kind: 'captions',
label: 'English',
language: 'en',
src: 'en.vtt'
};
const captionsButton = player.controlBar.getChild('SubsCapsButton');
// we know the postition of the OffTextTrackMenuItem
const offMenuItem = captionsButton.items[1];
player.src({type: 'video/mp4', src: 'http://google.com'});
// manualCleanUp = true by default
const englishTrack = player.addRemoteTextTrack(track1).track;
// Keep track of menu items
const enCaptionMenuItem = getMenuItemByLanguage(captionsButton.items, 'en');
// Select English initially
player.play();
enCaptionMenuItem.trigger('click');
assert.deepEqual(player.cache_.selectedLanguage,
{ enabled: true, language: 'en', kind: 'captions' }, 'English track is selected');
assert.ok(englishTrack.mode === 'showing', 'English track should be showing');
// Select the off button
offMenuItem.trigger('click');
assert.deepEqual(player.cache_.selectedLanguage,
{ enabled: false }, 'selectedLanguage is cleared');
assert.ok(englishTrack.mode === 'disabled', 'English track is disabled');
player.dispose();
});
}
+52 -49
Ver Arquivo
@@ -9,7 +9,6 @@ import TextTrack from '../../../src/js/tracks/text-track.js';
import TextTrackDisplay from '../../../src/js/tracks/text-track-display.js';
import Html5 from '../../../src/js/tech/html5.js';
import Tech from '../../../src/js/tech/tech.js';
import Component from '../../../src/js/component.js';
import * as browser from '../../../src/js/utils/browser.js';
import TestHelpers from '../test-helpers.js';
@@ -221,54 +220,6 @@ QUnit.test('update texttrack buttons on removetrack or addtrack', function(asser
player.dispose();
});
QUnit.test('if native text tracks are not supported, create a texttrackdisplay', function(assert) {
const oldTestVid = Html5.TEST_VID;
const oldIsFirefox = browser.IS_FIREFOX;
const oldTextTrackDisplay = Component.getComponent('TextTrackDisplay');
const tag = document.createElement('video');
const track1 = document.createElement('track');
const track2 = document.createElement('track');
track1.kind = 'captions';
track1.label = 'en';
track1.language = 'English';
track1.src = 'en.vtt';
tag.appendChild(track1);
track2.kind = 'captions';
track2.label = 'es';
track2.language = 'Spanish';
track2.src = 'es.vtt';
tag.appendChild(track2);
Html5.TEST_VID = {
textTracks: []
};
browser.IS_FIREFOX = true;
const fakeTTDSpy = sinon.spy();
class FakeTTD extends Component {
constructor() {
super();
fakeTTDSpy();
}
}
Component.registerComponent('TextTrackDisplay', FakeTTD);
const player = TestHelpers.makePlayer({}, tag);
assert.strictEqual(fakeTTDSpy.callCount, 1, 'text track display was created');
Html5.TEST_VID = oldTestVid;
browser.IS_FIREFOX = oldIsFirefox;
Component.registerComponent('TextTrackDisplay', oldTextTrackDisplay);
player.dispose();
});
QUnit.test('emulated tracks are always used, except in safari', function(assert) {
const oldTestVid = Html5.TEST_VID;
const oldIsAnySafari = browser.IS_ANY_SAFARI;
@@ -577,3 +528,55 @@ QUnit.test('removeRemoteTextTrack should be able to take both a track and the re
'the track element was removed correctly');
player.dispose();
});
if (Html5.isSupported()) {
QUnit.test('auto remove tracks should not clean up tracks added while source is being added', function(assert) {
const player = TestHelpers.makePlayer({
techOrder: ['html5'],
html5: {
nativeTextTracks: false
}
});
const track = {
kind: 'kind',
src: 'src',
language: 'language',
label: 'label',
default: 'default'
};
player.src({src: 'example.mp4', type: 'video/mp4'});
player.addRemoteTextTrack(track, false);
this.clock.tick(1);
assert.equal(player.textTracks().length, 1, 'we have one text track');
player.dispose();
});
QUnit.test('auto remove tracks added right before a source change will be cleaned up', function(assert) {
const player = TestHelpers.makePlayer({
techOrder: ['html5'],
html5: {
nativeTextTracks: false
}
});
const track = {
kind: 'kind',
src: 'src',
language: 'language',
label: 'label',
default: 'default'
};
player.addRemoteTextTrack(track, false);
player.src({src: 'example.mp4', type: 'video/mp4'});
this.clock.tick(1);
assert.equal(player.textTracks().length, 0, 'we do not have any tracks left');
player.dispose();
});
}
+13 -1
Ver Arquivo
@@ -1,5 +1,5 @@
/* eslint-env qunit */
import toTitleCase from '../../../src/js/utils/to-title-case.js';
import toTitleCase, { titleCaseEquals } from '../../../src/js/utils/to-title-case.js';
QUnit.module('to-title-case');
@@ -8,3 +8,15 @@ QUnit.test('should make a string start with an uppercase letter', function(asser
assert.ok(foo === 'Bar');
});
QUnit.test('titleCaseEquals compares whether the TitleCase of two strings is equal', function(assert) {
assert.ok(titleCaseEquals('foo', 'foo'), 'foo equals foo');
assert.ok(titleCaseEquals('foo', 'Foo'), 'foo equals Foo');
assert.ok(titleCaseEquals('Foo', 'foo'), 'Foo equals foo');
assert.ok(titleCaseEquals('Foo', 'Foo'), 'Foo equals Foo');
assert.ok(titleCaseEquals('fooBar', 'fooBar'), 'fooBar equals fooBar');
assert.notOk(titleCaseEquals('fooBAR', 'fooBar'), 'fooBAR does not equal fooBar');
assert.notOk(titleCaseEquals('foobar', 'fooBar'), 'foobar does not equal fooBar');
assert.notOk(titleCaseEquals('fooBar', 'FOOBAR'), 'fooBar does not equal fooBAR');
});