Comparar commits
37 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| c07fd862bb | |||
| 3bf01d9a41 | |||
| a88e311214 | |||
| fb5d0ce6ad | |||
| 7c169d417c | |||
| fdd133906c | |||
| a5758019e5 | |||
| 1ff361a825 | |||
| 27ee448e1f | |||
| 0ad43fd576 | |||
| 21edde8702 | |||
| 6b2dca32fc | |||
| 4007add5e5 | |||
| 7c5206eaf9 | |||
| 1bfe0b4fed | |||
| 5d550ffada | |||
| caf725a3d4 | |||
| 11d9d9afe8 | |||
| b2311c7664 | |||
| 1ffb13a799 | |||
| dc083f8cf4 | |||
| a8ff970d4a | |||
| 2bf0be72f3 | |||
| 349ff89541 | |||
| 2fc8968002 | |||
| 6128305cc3 | |||
| 0e63261db6 | |||
| c740115821 | |||
| d8e7d13fd0 | |||
| fbdb3f1ce2 | |||
| 4a62ebb042 | |||
| b87fb3ce32 | |||
| fd50bd0921 | |||
| b65bad8f20 | |||
| e5595b1e38 | |||
| de843affb7 | |||
| 9c99def186 |
@@ -12,6 +12,7 @@
|
||||
"undef" : true,
|
||||
"laxbreak" : true,
|
||||
"esnext" : true,
|
||||
"eqeqeq" : true,
|
||||
"predef" : [
|
||||
"_V_",
|
||||
"goog",
|
||||
|
||||
+13
-8
@@ -1,19 +1,24 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "iojs"
|
||||
- iojs
|
||||
before_script:
|
||||
- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then curl https://gist.githubusercontent.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash; fi
|
||||
- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then curl https://gist.githubusercontent.com/santiycr/5139565/raw/sauce_connect_setup.sh
|
||||
| bash; fi
|
||||
before_install:
|
||||
- export CHROME_BIN=chromium-browser
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- export CHROME_BIN=chromium-browser
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#videojs"
|
||||
- chat.freenode.net#videojs
|
||||
use_notice: true
|
||||
on_success: never
|
||||
webhooks:
|
||||
- http://pam.videojs.com/savage/travis
|
||||
env:
|
||||
global:
|
||||
- secure: K6JpKwMkfNaJix3Bb0tLjVMzHMJgtBXdd/dvfw1BMb9DCBpd81PqXbDs7yXCddUxnUPTBPxZCrQgWsw71Wn+qEoIG5MU3uOT5A2rBbx/yZonVAGv5ed/9w0xk0OzO383CmPMFqwqtp9YmdmqGjQBkYXVXJjTvNTOAExFSdhO+3U=
|
||||
- secure: GIbhjUJapvC70nIZVlhVyK+3KAD2TVKpiY/q412OO7V2izbvcM1tvU3LBoMZbROzrt5TT84tCoJDvHnrpL0OvxPwrzL5CUU7h4UTxhTOyQkEinbYAnWlW9wdrvtdczsEvANkFPqBZ53B3hVHZHMLOG8QRWaTBicF68vSHEJFqb4=
|
||||
- secure: K6JpKwMkfNaJix3Bb0tLjVMzHMJgtBXdd/dvfw1BMb9DCBpd81PqXbDs7yXCddUxnUPTBPxZCrQgWsw71Wn+qEoIG5MU3uOT5A2rBbx/yZonVAGv5ed/9w0xk0OzO383CmPMFqwqtp9YmdmqGjQBkYXVXJjTvNTOAExFSdhO+3U=
|
||||
- secure: GIbhjUJapvC70nIZVlhVyK+3KAD2TVKpiY/q412OO7V2izbvcM1tvU3LBoMZbROzrt5TT84tCoJDvHnrpL0OvxPwrzL5CUU7h4UTxhTOyQkEinbYAnWlW9wdrvtdczsEvANkFPqBZ53B3hVHZHMLOG8QRWaTBicF68vSHEJFqb4=
|
||||
- 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=
|
||||
|
||||
@@ -26,6 +26,18 @@ CHANGELOG
|
||||
* @gkatsev updated the component.js styles to match the new style guide ([view](https://github.com/videojs/video.js/pull/2105))
|
||||
* @gkatsev added error logging for bad JSON formatting ([view](https://github.com/videojs/video.js/pull/2113))
|
||||
* @gkatsev added a sensible toJSON function ([view](https://github.com/videojs/video.js/pull/2114))
|
||||
* @bc-bbay fixed instance where progress bars would go passed 100% ([view](https://github.com/videojs/video.js/pull/2040))
|
||||
* @eXon began Tech 2.0 work, improved how tech events are handled by the player ([view](https://github.com/videojs/video.js/pull/2057))
|
||||
* @gkatsev added get and set global options methods ([view](https://github.com/videojs/video.js/pull/2115))
|
||||
* @heff added support for fluid widths, aspect ratios, and metadata defaults ([view](https://github.com/videojs/video.js/pull/1952))
|
||||
* @heff reorganized all utility functions in the codebase ([view](https://github.com/videojs/video.js/pull/2139))
|
||||
* @eXon made additional tech 2.0 improvements listed in #2126 ([view](https://github.com/videojs/video.js/pull/2166))
|
||||
* @heff Cleaned up and documented src/js/video.js and DOM functions ([view](https://github.com/videojs/video.js/pull/2182))
|
||||
* @mmcc Changed to pure CSS slider handles ([view](https://github.com/videojs/video.js/pull/2132))
|
||||
* @mister-ben updated language support to handle language codes with regions ([view](https://github.com/videojs/video.js/pull/2177))
|
||||
* @heff changed the 'ready' event to always be asynchronous ([view](https://github.com/videojs/video.js/pull/2188))
|
||||
* @heff fixed instances of tabIndex that did not have a capital I ([view](https://github.com/videojs/video.js/pull/2204))
|
||||
* @heff fixed a number of IE8 and Flash related issues ([view](https://github.com/videojs/video.js/pull/2206))
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
+3
-7
@@ -1,15 +1,11 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "5.0.0-10",
|
||||
"main": [
|
||||
"dist/video-js/video.js",
|
||||
"dist/video-js/video-js.css",
|
||||
"dist/video-js/font/vjs.eot",
|
||||
"dist/video-js/font/vjs.svg",
|
||||
"dist/video-js/font/vjs.ttf",
|
||||
"dist/video-js/font/vjs.woff"
|
||||
"src/js/video.js",
|
||||
"src/css/video-js.scss"
|
||||
],
|
||||
"moduleType": "es6",
|
||||
"keywords": [
|
||||
"videojs",
|
||||
"html5",
|
||||
|
||||
@@ -12,19 +12,17 @@ module.exports = function(grunt) {
|
||||
|
||||
// I believe this was done originally because of security implications around running
|
||||
// Saucelabs automatically on PRs.
|
||||
if (process.env.TRAVIS_PULL_REQUEST !== 'false') {
|
||||
if (!process.env.SAUCE_ACCESS_KEY) {
|
||||
grunt.task.run(['karma:firefox']);
|
||||
} else {
|
||||
grunt.task.run(['karma:firefox']);
|
||||
//Disabling saucelabs until we figure out how to make it run reliably.
|
||||
//grunt.task.run([
|
||||
//'karma:chrome_sl',
|
||||
//'karma:firefox_sl',
|
||||
//'karma:safari_sl',
|
||||
//'karma:ipad_sl',
|
||||
//'karma:android_sl',
|
||||
//'karma:ie_sl'
|
||||
//]);
|
||||
grunt.task.run([
|
||||
'karma:chrome_sl',
|
||||
'karma:firefox_sl',
|
||||
'karma:safari_sl',
|
||||
'karma:ipad_sl',
|
||||
'karma:android_sl',
|
||||
'karma:ie_sl'
|
||||
]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "5.0.0-10",
|
||||
"version": "5.0.0-24",
|
||||
"keywords": [
|
||||
"videojs",
|
||||
"html5",
|
||||
|
||||
externo
+14802
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
BIN
Arquivo binário não exibido.
externo
+40
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Generated by IcoMoon</metadata>
|
||||
<defs>
|
||||
<font id="VideoJS" horiz-adv-x="512">
|
||||
<font-face units-per-em="512" ascent="480" descent="-32" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph unicode=" " d="" horiz-adv-x="256" />
|
||||
<glyph unicode="▶" d="M170.667 373.334v-298.666l234.667 149.333z" />
|
||||
<glyph unicode="" d="M405.334 373.334v-298.666h-298.666v298.666h298.666zM405.334 416h-298.666c-23.573 0-42.666-19.094-42.666-42.666v-298.666c0-23.574 19.093-42.666 42.666-42.666h298.666c23.574 0 42.666 19.094 42.666 42.666v298.666c0 23.574-19.094 42.666-42.666 42.666z" />
|
||||
<glyph unicode="" d="M256 330.667c-58.88 0-106.666-47.787-106.666-106.667s47.786-106.666 106.666-106.666 106.666 47.786 106.666 106.666-47.786 106.666-106.666 106.666zM256 437.334c-117.867 0-213.333-95.466-213.333-213.334s95.466-213.333 213.333-213.333 213.333 95.466 213.333 213.333-95.466 213.333-213.333 213.333zM256 53.334c-94.293 0-170.667 76.373-170.667 170.667s76.374 170.667 170.667 170.667 170.667-76.374 170.667-170.667-76.374-170.667-170.667-170.667z" />
|
||||
<glyph unicode="" d="M384 136.853c-16.214 0-30.827-6.293-41.92-16.426l-152 88.64c1.173 4.8 1.92 9.813 1.92 14.934s-0.746 10.133-1.92 14.934l150.4 87.786c11.413-10.666 26.666-17.28 43.52-17.28 35.307 0 64 28.693 64 64s-28.693 64-64 64-64-28.694-64-64c0-5.12 0.747-10.134 1.92-14.934l-150.4-87.786c-11.413 10.666-26.667 17.28-43.52 17.28-35.306 0-64-28.693-64-64s28.694-64 64-64c16.853 0 32.106 6.613 43.52 17.28l152-88.64c-1.067-4.48-1.707-9.173-1.707-13.974 0-34.346 27.84-62.187 62.187-62.187s62.187 27.84 62.187 62.187-27.84 62.187-62.187 62.187z" />
|
||||
<glyph unicode="" d="M149.333 181.334h-42.666v-106.666h106.666v42.666h-64v64zM106.666 266.667h42.666v64h64v42.666h-106.666v-106.666zM362.666 117.334h-64v-42.666h106.666v106.666h-42.666v-64zM298.666 373.334v-42.666h64v-64h42.666v106.666h-106.666z" />
|
||||
<glyph unicode="" d="M106.666 138.666h64v-64h42.666v106.666h-106.666v-42.666zM170.667 309.333h-64v-42.666h106.667v106.666h-42.666v-64zM298.666 74.666h42.666v64h64v42.666h-106.666v-106.666zM341.334 309.333v64h-42.666v-106.666h106.666v42.666h-64z" />
|
||||
<glyph unicode="" d="M376.534 344.534c-30.827 30.933-73.387 50.134-120.534 50.134-94.293 0-170.453-76.374-170.453-170.667s76.16-170.667 170.453-170.667c79.466 0 146.026 54.4 164.906 128h-44.373c-17.6-49.707-64.746-85.334-120.534-85.334-70.72 0-128 57.28-128 128s57.28 128 128 128c35.307 0 66.986-14.72 90.134-37.867l-68.8-68.8h149.334v149.333l-50.134-50.133z" />
|
||||
<glyph unicode="" d="M469.334 224c0-117.82-95.512-213.333-213.334-213.333s-213.333 95.512-213.333 213.333c0 117.821 95.513 213.333 213.333 213.333s213.333-95.512 213.333-213.333z" />
|
||||
<glyph unicode="" d="M256 437.334c-117.867 0-213.333-95.466-213.333-213.334s95.466-213.333 213.333-213.333 213.333 95.466 213.333 213.333-95.466 213.333-213.333 213.333z" />
|
||||
<glyph unicode="" d="M256 437.334c-117.867 0-213.333-95.466-213.333-213.334s95.466-213.333 213.333-213.333 213.333 95.466 213.333 213.333-95.466 213.333-213.333 213.333zM256 53.334c-94.080 0-170.667 76.587-170.667 170.667s76.587 170.667 170.667 170.667 170.667-76.587 170.667-170.667-76.587-170.667-170.667-170.667z" />
|
||||
<glyph unicode="" d="M448 416h-384c-23.573 0-42.666-19.094-42.666-42.666v-64h42.666v64h384v-298.666h-149.333v-42.666h149.333c23.574 0 42.666 19.094 42.666 42.666v298.666c0 23.574-19.094 42.666-42.666 42.666zM21.334 96v-64h64c0 35.307-28.694 64-64 64zM21.334 181.334v-42.666c58.88 0 106.666-47.786 106.666-106.666h42.666c0 82.454-66.88 149.334-149.333 149.334zM21.334 266.667v-42.667c106.026 0 192-85.974 192-192h42.666c0 129.6-105.067 234.667-234.667 234.667z" />
|
||||
<glyph unicode="" d="M426.666 394.666h-341.334c-23.573 0-42.666-19.094-42.666-42.666v-256c0-23.574 19.093-42.666 42.666-42.666h341.334c23.574 0 42.666 19.094 42.666 42.666v256c0 23.573-19.094 42.666-42.666 42.666zM85.334 224h85.334v-42.666h-85.334v42.666zM298.666 96h-213.333v42.666h213.333v-42.666zM426.666 96h-85.334v42.666h85.334v-42.666zM426.666 181.334h-213.333v42.666h213.333v-42.666z" />
|
||||
<glyph unicode="" d="M405.334 394.666h-298.666c-23.573 0-42.666-19.094-42.666-42.666v-256c0-23.574 19.093-42.666 42.666-42.666h298.666c23.574 0 42.666 19.094 42.666 42.666v256c0 23.573-19.094 42.666-42.666 42.666zM234.667 245.333h-32v10.667h-42.667v-64h42.666v10.666h32v-21.334c0-11.733-9.494-21.334-21.334-21.334h-64c-11.84 0-21.334 9.6-21.334 21.334v85.334c0 11.733 9.493 21.334 21.334 21.334h64c11.84 0 21.334-9.6 21.334-21.334v-21.334zM384 245.333h-32v10.667h-42.666v-64h42.666v10.666h32v-21.334c0-11.733-9.493-21.334-21.334-21.334h-64c-11.84 0-21.334 9.6-21.334 21.334v85.334c0 11.733 9.493 21.334 21.334 21.334h64c11.84 0 21.334-9.6 21.334-21.334v-21.334z" />
|
||||
<glyph unicode="" d="M85.334 96l181.333 128-181.333 128v-256zM277.334 352v-256l181.334 128-181.333 128z" />
|
||||
<glyph unicode="" d="M234.667 96v256l-181.333-128 181.333-128zM245.333 224l181.333-128v256l-181.333-128z" />
|
||||
<glyph unicode="" d="M405.334 394.666h-298.666c-23.573 0-42.666-19.094-42.666-42.666v-256c0-23.574 19.093-42.666 42.666-42.666h298.666c23.574 0 42.666 19.094 42.666 42.666v256c0 23.573-19.094 42.666-42.666 42.666zM234.667 160h-32v42.666h-42.667v-42.666h-32v128h32v-53.334h42.666v53.334h32v-128zM384 181.334c0-11.733-9.493-21.334-21.334-21.334h-16v-32h-32v32h-16c-11.84 0-21.334 9.6-21.334 21.334v85.334c0 11.733 9.493 21.334 21.334 21.334h64c11.84 0 21.334-9.6 21.334-21.334v-85.334zM309.334 192h42.666v64h-42.666v-64z" />
|
||||
<glyph unicode="" d="M128 74.666h85.334v298.666h-85.334v-298.666zM298.666 373.334v-298.666h85.334v298.666h-85.334z" />
|
||||
<glyph unicode="" d="M256 437.334c-117.867 0-213.333-95.466-213.333-213.334s95.466-213.333 213.333-213.333 213.333 95.466 213.333 213.333-95.466 213.333-213.333 213.333zM234.667 138.666h-42.667v170.666h42.666v-170.666zM320 138.666h-42.666v170.666h42.666v-170.666z" />
|
||||
<glyph unicode="" d="M192 138.666h42.666v170.666h-42.666v-170.666zM256 437.334c-117.867 0-213.333-95.466-213.333-213.334s95.466-213.333 213.333-213.333 213.333 95.466 213.333 213.333-95.466 213.333-213.333 213.333zM256 53.334c-94.080 0-170.667 76.587-170.667 170.667s76.587 170.667 170.667 170.667 170.667-76.587 170.667-170.667-76.587-170.667-170.667-170.667zM277.334 138.666h42.666v170.666h-42.666v-170.666z" />
|
||||
<glyph unicode="" d="M256 437.334c-117.867 0-213.333-95.466-213.333-213.334s95.466-213.333 213.333-213.333 213.333 95.466 213.333 213.333-95.466 213.333-213.333 213.333zM213.333 128v192l128-96-128-96z" />
|
||||
<glyph unicode="" d="M213.333 128l128 96-128 96v-192zM256 437.334c-117.867 0-213.333-95.466-213.333-213.334s95.466-213.333 213.333-213.333 213.333 95.466 213.333 213.333-95.466 213.333-213.333 213.333zM256 53.334c-94.080 0-170.667 76.587-170.667 170.667s76.587 170.667 170.667 170.667 170.667-76.587 170.667-170.667-76.587-170.667-170.667-170.667z" />
|
||||
<glyph unicode="" d="M128 96l181.333 128-181.333 128v-256zM341.334 352v-256h42.666v256h-42.666z" />
|
||||
<glyph unicode="" d="M128 352h42.666v-256h-42.666zM202.667 224l181.333-128v256z" />
|
||||
<glyph unicode="" d="M394.666 224c0 37.654-21.76 70.187-53.334 85.866v-171.84c31.574 15.786 53.334 48.32 53.334 85.974zM106.666 288v-128h85.334l106.666-106.666v341.334l-106.666-106.666h-85.334z" />
|
||||
<glyph unicode="" d="M149.333 288v-128h85.333l106.666-106.666v341.334l-106.666-106.666h-85.334z" />
|
||||
<glyph unicode="" d="M352 224c0 37.654-21.76 70.187-53.334 85.866v-47.146l52.373-52.374c0.64 4.48 0.96 9.067 0.96 13.654zM405.334 224c0-20.053-4.373-38.933-11.52-56.32l32.32-32.32c13.866 26.56 21.866 56.64 21.866 88.64 0 91.307-63.894 167.68-149.333 187.094v-44.053c61.654-18.347 106.666-75.413 106.666-143.040zM91.2 416l-27.2-27.2 100.8-100.8h-100.8v-128h85.334l106.666-106.666v143.466l90.774-90.774c-14.293-10.986-30.4-19.84-48.106-25.173v-44.053c29.334 6.72 56.106 20.16 78.613 38.613l43.52-43.413 27.2 27.2-356.8 356.8zM256 394.666l-44.587-44.587 44.587-44.587v89.173z" />
|
||||
<glyph unicode="" d="M64 288v-128h85.334l106.666-106.666v341.334l-106.666-106.666h-85.334zM352 224c0 37.654-21.76 70.187-53.334 85.866v-171.84c31.574 15.786 53.334 48.32 53.334 85.974zM298.666 411.094v-44.053c61.654-18.347 106.666-75.413 106.666-143.040s-45.014-124.693-106.666-143.040v-44.053c85.44 19.413 149.334 95.68 149.334 187.094s-63.894 167.68-149.333 187.094z" />
|
||||
<glyph unicode="" d="M256 352v-64l85.334 85.334-85.334 85.334v-64c-94.293 0-170.667-76.374-170.667-170.667 0-33.493 9.814-64.534 26.453-90.88l31.147 31.147c-9.494 17.813-14.933 38.080-14.933 59.733 0 70.72 57.28 128 128 128zM400.214 314.88l-31.147-31.147c9.493-17.814 14.933-38.080 14.933-59.733 0-70.72-57.28-128-128-128v64l-85.334-85.334 85.334-85.334v64c94.293 0 170.667 76.374 170.667 170.667 0 33.493-9.813 64.534-26.454 90.88z" />
|
||||
<glyph unicode="" d="M64 202.666h42.666v42.666h-42.666v-42.666zM64 117.334h42.666v42.666h-42.666v-42.666zM64 288h42.666v42.666h-42.666v-42.666zM149.333 202.666h298.667v42.666h-298.666v-42.666zM149.333 117.334h298.667v42.666h-298.666v-42.666zM149.333 330.667v-42.667h298.667v42.666h-298.666z" />
|
||||
<glyph unicode="" d="M414.507 203.2c0.853 6.827 1.493 13.76 1.493 20.8s-0.64 13.974-1.493 20.8l45.12 35.306c4.053 3.2 5.226 8.96 2.56 13.654l-42.666 73.92c-2.666 4.587-8.214 6.507-13.014 4.587l-53.12-21.44c-10.986 8.427-23.040 15.573-36.053 21.014l-8 56.533c-0.96 5.014-5.334 8.96-10.666 8.96h-85.334c-5.333 0-9.707-3.947-10.56-8.96l-8-56.533c-13.013-5.44-25.066-12.48-36.053-21.014l-53.12 21.44c-4.8 1.814-10.347 0-13.013-4.587l-42.666-73.92c-2.666-4.587-1.493-10.346 2.56-13.654l45.014-35.306c-0.853-6.827-1.493-13.76-1.493-20.8s0.64-13.974 1.493-20.8l-45.014-35.306c-4.053-3.2-5.227-8.96-2.56-13.654l42.666-73.92c2.666-4.587 8.213-6.507 13.013-4.587l53.12 21.44c10.987-8.426 23.040-15.574 36.053-21.014l8-56.534c0.853-5.014 5.226-8.96 10.56-8.96h85.334c5.334 0 9.707 3.947 10.56 8.96l8 56.534c13.014 5.44 25.067 12.48 36.053 21.014l53.12-21.44c4.8-1.813 10.346 0 13.014 4.587l42.666 73.92c2.666 4.587 1.493 10.346-2.56 13.654l-45.014 35.307zM256 149.334c-41.28 0-74.666 33.387-74.666 74.666s33.387 74.666 74.666 74.666 74.666-33.387 74.666-74.666-33.387-74.666-74.666-74.666z" />
|
||||
</font></defs></svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 10 KiB |
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("ar",{
|
||||
"Play": "تشغيل",
|
||||
"Pause": "ايقاف",
|
||||
"Current Time": "الوقت الحالي",
|
||||
"Duration Time": "Dauer",
|
||||
"Remaining Time": "الوقت المتبقي",
|
||||
"Stream Type": "نوع التيار",
|
||||
"LIVE": "مباشر",
|
||||
"Loaded": "تم التحميل",
|
||||
"Progress": "التقدم",
|
||||
"Fullscreen": "ملء الشاشة",
|
||||
"Non-Fullscreen": "غير ملء الشاشة",
|
||||
"Mute": "صامت",
|
||||
"Unmuted": "غير الصامت",
|
||||
"Playback Rate": "معدل التشغيل",
|
||||
"Subtitles": "الترجمة",
|
||||
"subtitles off": "ايقاف الترجمة",
|
||||
"Captions": "التعليقات",
|
||||
"captions off": "ايقاف التعليقات",
|
||||
"Chapters": "فصول",
|
||||
"You aborted the video playback": "لقد ألغيت تشغيل الفيديو",
|
||||
"A network error caused the video download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادم أو الشبكة ، أو فشل بسبب عدم امكانية قراءة تنسيق الفيديو.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "تم ايقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
|
||||
"No compatible source was found for this video.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("ba",{
|
||||
"Play": "Pusti",
|
||||
"Pause": "Pauza",
|
||||
"Current Time": "Trenutno vrijeme",
|
||||
"Duration Time": "Vrijeme trajanja",
|
||||
"Remaining Time": "Preostalo vrijeme",
|
||||
"Stream Type": "Način strimovanja",
|
||||
"LIVE": "UŽIVO",
|
||||
"Loaded": "Učitan",
|
||||
"Progress": "Progres",
|
||||
"Fullscreen": "Puni ekran",
|
||||
"Non-Fullscreen": "Mali ekran",
|
||||
"Mute": "Prigušen",
|
||||
"Unmuted": "Ne-prigušen",
|
||||
"Playback Rate": "Stopa reprodukcije",
|
||||
"Subtitles": "Podnaslov",
|
||||
"subtitles off": "Podnaslov deaktiviran",
|
||||
"Captions": "Titlovi",
|
||||
"captions off": "Titlovi deaktivirani",
|
||||
"Chapters": "Poglavlja",
|
||||
"You aborted the video playback": "Isključili ste reprodukciju videa.",
|
||||
"A network error caused the video download to fail part-way.": "Video se prestao preuzimati zbog greške na mreži.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Video se ne može reproducirati zbog servera, greške u mreži ili je format ne podržan.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Reprodukcija videa je zaustavljenja zbog greške u formatu ili zbog verzije vašeg pretraživača.",
|
||||
"No compatible source was found for this video.": "Nije nađen nijedan kompatibilan izvor ovog videa."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("bg",{
|
||||
"Play": "Възпроизвеждане",
|
||||
"Pause": "Пауза",
|
||||
"Current Time": "Текущо време",
|
||||
"Duration Time": "Продължителност",
|
||||
"Remaining Time": "Оставащо време",
|
||||
"Stream Type": "Тип на потока",
|
||||
"LIVE": "НА ЖИВО",
|
||||
"Loaded": "Заредено",
|
||||
"Progress": "Прогрес",
|
||||
"Fullscreen": "Цял екран",
|
||||
"Non-Fullscreen": "Спиране на цял екран",
|
||||
"Mute": "Без звук",
|
||||
"Unmuted": "Със звук",
|
||||
"Playback Rate": "Скорост на възпроизвеждане",
|
||||
"Subtitles": "Субтитри",
|
||||
"subtitles off": "Спряни субтитри",
|
||||
"Captions": "Аудио надписи",
|
||||
"captions off": "Спряни аудио надписи",
|
||||
"Chapters": "Глави",
|
||||
"You aborted the video playback": "Спряхте възпроизвеждането на видеото",
|
||||
"A network error caused the video download to fail part-way.": "Грешка в мрежата провали изтеглянето на видеото.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Видеото не може да бъде заредено заради проблем със сървъра или мрежата или защото този формат не е поддържан.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Възпроизвеждането на видеото беше прекъснато заради проблем с файла или защото видеото използва опции които браузърът Ви не поддържа.",
|
||||
"No compatible source was found for this video.": "Не беше намерен съвместим източник за това видео."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("ca",{
|
||||
"Play": "Reproducció",
|
||||
"Pause": "Pausa",
|
||||
"Current Time": "Temps reproduït",
|
||||
"Duration Time": "Durada total",
|
||||
"Remaining Time": "Temps restant",
|
||||
"Stream Type": "Tipus de seqüència",
|
||||
"LIVE": "EN DIRECTE",
|
||||
"Loaded": "Carregat",
|
||||
"Progress": "Progrés",
|
||||
"Fullscreen": "Pantalla completa",
|
||||
"Non-Fullscreen": "Pantalla no completa",
|
||||
"Mute": "Silencia",
|
||||
"Unmuted": "Amb so",
|
||||
"Playback Rate": "Velocitat de reproducció",
|
||||
"Subtitles": "Subtítols",
|
||||
"subtitles off": "Subtítols desactivats",
|
||||
"Captions": "Llegendes",
|
||||
"captions off": "Llegendes desactivades",
|
||||
"Chapters": "Capítols",
|
||||
"You aborted the video playback": "Heu interromput la reproducció del vídeo.",
|
||||
"A network error caused the video download to fail part-way.": "Un error de la xarxa ha interromput la baixada del vídeo.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "No s'ha pogut carregar el vídeo perquè el servidor o la xarxa han fallat, o bé perquè el seu format no és compatible.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "La reproducció de vídeo s'ha interrumput per un problema de corrupció de dades o bé perquè el vídeo demanava funcions que el vostre navegador no ofereix.",
|
||||
"No compatible source was found for this video.": "No s'ha trobat cap font compatible amb el vídeo."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("cs",{
|
||||
"Play": "Přehrát",
|
||||
"Pause": "Pauza",
|
||||
"Current Time": "Aktuální čas",
|
||||
"Duration Time": "Doba trvání",
|
||||
"Remaining Time": "Zbývající čas",
|
||||
"Stream Type": "Stream Type",
|
||||
"LIVE": "ŽIVĚ",
|
||||
"Loaded": "Načteno",
|
||||
"Progress": "Stav",
|
||||
"Fullscreen": "Celá obrazovka",
|
||||
"Non-Fullscreen": "Zmenšená obrazovka",
|
||||
"Mute": "Ztlumit zvuk",
|
||||
"Unmuted": "Přehrát zvuk",
|
||||
"Playback Rate": "Rychlost přehrávání",
|
||||
"Subtitles": "Titulky",
|
||||
"subtitles off": "Titulky vypnuty",
|
||||
"Captions": "Popisky",
|
||||
"captions off": "Popisky vypnuty",
|
||||
"Chapters": "Kapitoly",
|
||||
"You aborted the video playback": "Přehrávání videa je přerušeno.",
|
||||
"A network error caused the video download to fail part-way.": "Video nemohlo být načteno, kvůli chybě v síti.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Video nemohlo být načteno, buď kvůli chybě serveru nebo sítě nebo proto, že daný formát není podporován.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Váš prohlížeč nepodporuje formát videa.",
|
||||
"No compatible source was found for this video.": "Špatně zadaný zdroj videa."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("da",{
|
||||
"Play": "Afspil",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Aktuel tid",
|
||||
"Duration Time": "Varighed",
|
||||
"Remaining Time": "Resterende tid",
|
||||
"Stream Type": "Stream-type",
|
||||
"LIVE": "LIVE",
|
||||
"Loaded": "Indlæst",
|
||||
"Progress": "Status",
|
||||
"Fullscreen": "Fuldskærm",
|
||||
"Non-Fullscreen": "Luk fuldskærm",
|
||||
"Mute": "Uden lyd",
|
||||
"Unmuted": "Med lyd",
|
||||
"Playback Rate": "Afspilningsrate",
|
||||
"Subtitles": "Undertekster",
|
||||
"subtitles off": "Uden undertekster",
|
||||
"Captions": "Undertekster for hørehæmmede",
|
||||
"captions off": "Uden undertekster for hørehæmmede",
|
||||
"Chapters": "Kapitler",
|
||||
"You aborted the video playback": "Du afbrød videoafspilningen.",
|
||||
"A network error caused the video download to fail part-way.": "En netværksfejl fik download af videoen til at fejle.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Videoen kunne ikke indlæses, enten fordi serveren eller netværket fejlede, eller fordi formatet ikke er understøttet.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Videoafspilningen blev afbrudt på grund af ødelagte data eller fordi videoen benyttede faciliteter som din browser ikke understøtter.",
|
||||
"No compatible source was found for this video.": "Fandt ikke en kompatibel kilde for denne video."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("de",{
|
||||
"Play": "Wiedergabe",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Aktueller Zeitpunkt",
|
||||
"Duration Time": "Dauer",
|
||||
"Remaining Time": "Verbleibende Zeit",
|
||||
"Stream Type": "Streamtyp",
|
||||
"LIVE": "LIVE",
|
||||
"Loaded": "Geladen",
|
||||
"Progress": "Status",
|
||||
"Fullscreen": "Vollbild",
|
||||
"Non-Fullscreen": "Kein Vollbild",
|
||||
"Mute": "Ton aus",
|
||||
"Unmuted": "Ton ein",
|
||||
"Playback Rate": "Wiedergabegeschwindigkeit",
|
||||
"Subtitles": "Untertitel",
|
||||
"subtitles off": "Untertitel aus",
|
||||
"Captions": "Untertitel",
|
||||
"captions off": "Untertitel aus",
|
||||
"Chapters": "Kapitel",
|
||||
"You aborted the video playback": "Sie haben die Videowiedergabe abgebrochen.",
|
||||
"A network error caused the video download to fail part-way.": "Der Videodownload ist aufgrund eines Netzwerkfehlers fehlgeschlagen.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Die Videowiedergabe wurde entweder wegen eines Problems mit einem beschädigten Video oder wegen verwendeten Funktionen, die vom Browser nicht unterstützt werden, abgebrochen.",
|
||||
"No compatible source was found for this video.": "Für dieses Video wurde keine kompatible Quelle gefunden."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("es",{
|
||||
"Play": "Reproducción",
|
||||
"Pause": "Pausa",
|
||||
"Current Time": "Tiempo reproducido",
|
||||
"Duration Time": "Duración total",
|
||||
"Remaining Time": "Tiempo restante",
|
||||
"Stream Type": "Tipo de secuencia",
|
||||
"LIVE": "DIRECTO",
|
||||
"Loaded": "Cargado",
|
||||
"Progress": "Progreso",
|
||||
"Fullscreen": "Pantalla completa",
|
||||
"Non-Fullscreen": "Pantalla no completa",
|
||||
"Mute": "Silenciar",
|
||||
"Unmuted": "No silenciado",
|
||||
"Playback Rate": "Velocidad de reproducción",
|
||||
"Subtitles": "Subtítulos",
|
||||
"subtitles off": "Subtítulos desactivados",
|
||||
"Captions": "Subtítulos especiales",
|
||||
"captions off": "Subtítulos especiales desactivados",
|
||||
"Chapters": "Capítulos",
|
||||
"You aborted the video playback": "Ha interrumpido la reproducción del vídeo.",
|
||||
"A network error caused the video download to fail part-way.": "Un error de red ha interrumpido la descarga del vídeo.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "No se ha podido cargar el vídeo debido a un fallo de red o del servidor o porque el formato es incompatible.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "La reproducción de vídeo se ha interrumpido por un problema de corrupción de datos o porque el vídeo precisa funciones que su navegador no ofrece.",
|
||||
"No compatible source was found for this video.": "No se ha encontrado ninguna fuente compatible con este vídeo."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("fr",{
|
||||
"Play": "Lecture",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Temps actuel",
|
||||
"Duration Time": "Durée",
|
||||
"Remaining Time": "Temps restant",
|
||||
"Stream Type": "Type de flux",
|
||||
"LIVE": "EN DIRECT",
|
||||
"Loaded": "Chargé",
|
||||
"Progress": "Progression",
|
||||
"Fullscreen": "Plein écran",
|
||||
"Non-Fullscreen": "Fenêtré",
|
||||
"Mute": "Sourdine",
|
||||
"Unmuted": "Son activé",
|
||||
"Playback Rate": "Vitesse de lecture",
|
||||
"Subtitles": "Sous-titres",
|
||||
"subtitles off": "Sous-titres désactivés",
|
||||
"Captions": "Sous-titres",
|
||||
"captions off": "Sous-titres désactivés",
|
||||
"Chapters": "Chapitres",
|
||||
"You aborted the video playback": "Vous avez interrompu la lecture de la vidéo.",
|
||||
"A network error caused the video download to fail part-way.": "Une erreur de réseau a interrompu le téléchargement de la vidéo.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Cette vidéo n'a pas pu être chargée, soit parce que le serveur ou le réseau a échoué ou parce que le format n'est pas reconnu.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "La lecture de la vidéo a été interrompue à cause d'un problème de corruption ou parce que la vidéo utilise des fonctionnalités non prises en charge par votre navigateur.",
|
||||
"No compatible source was found for this video.": "Aucune source compatible n'a été trouvée pour cette vidéo."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("hr",{
|
||||
"Play": "Pusti",
|
||||
"Pause": "Pauza",
|
||||
"Current Time": "Trenutno vrijeme",
|
||||
"Duration Time": "Vrijeme trajanja",
|
||||
"Remaining Time": "Preostalo vrijeme",
|
||||
"Stream Type": "Način strimovanja",
|
||||
"LIVE": "UŽIVO",
|
||||
"Loaded": "Učitan",
|
||||
"Progress": "Progres",
|
||||
"Fullscreen": "Puni ekran",
|
||||
"Non-Fullscreen": "Mali ekran",
|
||||
"Mute": "Prigušen",
|
||||
"Unmuted": "Ne-prigušen",
|
||||
"Playback Rate": "Stopa reprodukcije",
|
||||
"Subtitles": "Podnaslov",
|
||||
"subtitles off": "Podnaslov deaktiviran",
|
||||
"Captions": "Titlovi",
|
||||
"captions off": "Titlovi deaktivirani",
|
||||
"Chapters": "Poglavlja",
|
||||
"You aborted the video playback": "Isključili ste reprodukciju videa.",
|
||||
"A network error caused the video download to fail part-way.": "Video se prestao preuzimati zbog greške na mreži.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Video se ne može reproducirati zbog servera, greške u mreži ili je format ne podržan.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Reprodukcija videa je zaustavljenja zbog greške u formatu ili zbog verzije vašeg pretraživača.",
|
||||
"No compatible source was found for this video.": "Nije nađen nijedan kompatibilan izvor ovog videa."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("hu",{
|
||||
"Play": "Lejátszás",
|
||||
"Pause": "Szünet",
|
||||
"Current Time": "Aktuális időpont",
|
||||
"Duration Time": "Hossz",
|
||||
"Remaining Time": "Hátralévő idő",
|
||||
"Stream Type": "Adatfolyam típusa",
|
||||
"LIVE": "ÉLŐ",
|
||||
"Loaded": "Betöltve",
|
||||
"Progress": "Állapot",
|
||||
"Fullscreen": "Teljes képernyő",
|
||||
"Non-Fullscreen": "Normál méret",
|
||||
"Mute": "Némítás",
|
||||
"Unmuted": "Némítás kikapcsolva",
|
||||
"Playback Rate": "Lejátszási sebesség",
|
||||
"Subtitles": "Feliratok",
|
||||
"subtitles off": "Feliratok kikapcsolva",
|
||||
"Captions": "Magyarázó szöveg",
|
||||
"captions off": "Magyarázó szöveg kikapcsolva",
|
||||
"Chapters": "Fejezetek",
|
||||
"You aborted the video playback": "Leállította a lejátszást",
|
||||
"A network error caused the video download to fail part-way.": "Hálózati hiba miatt a videó részlegesen töltődött le.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "A videó nem tölthető be hálózati vagy kiszolgálói hiba miatt, vagy a formátuma nem támogatott.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "A lejátszás adatsérülés miatt leállt, vagy a videó egyes tulajdonságait a böngészője nem támogatja.",
|
||||
"No compatible source was found for this video.": "Nincs kompatibilis forrás ehhez a videóhoz."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("it",{
|
||||
"Play": "Play",
|
||||
"Pause": "Pausa",
|
||||
"Current Time": "Orario attuale",
|
||||
"Duration Time": "Durata",
|
||||
"Remaining Time": "Tempo rimanente",
|
||||
"Stream Type": "Tipo del Streaming",
|
||||
"LIVE": "LIVE",
|
||||
"Loaded": "Caricato",
|
||||
"Progress": "Stato",
|
||||
"Fullscreen": "Schermo intero",
|
||||
"Non-Fullscreen": "Chiudi schermo intero",
|
||||
"Mute": "Muto",
|
||||
"Unmuted": "Audio",
|
||||
"Playback Rate": "Tasso di riproduzione",
|
||||
"Subtitles": "Sottotitoli",
|
||||
"subtitles off": "Senza sottotitoli",
|
||||
"Captions": "Sottotitoli non udenti",
|
||||
"captions off": "Senza sottotitoli non udenti",
|
||||
"Chapters": "Capitolo",
|
||||
"You aborted the video playback": "La riproduzione del filmato è stata interrotta.",
|
||||
"A network error caused the video download to fail part-way.": "Il download del filmato è stato interrotto a causa di un problema rete.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Il filmato non può essere caricato a causa di un errore nel server o nella rete o perché il formato non viene supportato.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "La riproduzione del filmato è stata interrotta a causa di un file danneggiato o per l’utilizzo di impostazioni non supportate dal browser.",
|
||||
"No compatible source was found for this video.": "Non ci sono fonti compatibili per questo filmato."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("ja",{
|
||||
"Play": "再生",
|
||||
"Pause": "一時停止",
|
||||
"Current Time": "現在の時間",
|
||||
"Duration Time": "長さ",
|
||||
"Remaining Time": "残りの時間",
|
||||
"Stream Type": "ストリームの種類",
|
||||
"LIVE": "ライブ",
|
||||
"Loaded": "ロード済み",
|
||||
"Progress": "進行状況",
|
||||
"Fullscreen": "フルスクリーン",
|
||||
"Non-Fullscreen": "フルスクリーン以外",
|
||||
"Mute": "ミュート",
|
||||
"Unmuted": "ミュート解除",
|
||||
"Playback Rate": "再生レート",
|
||||
"Subtitles": "サブタイトル",
|
||||
"subtitles off": "サブタイトル オフ",
|
||||
"Captions": "キャプション",
|
||||
"captions off": "キャプション オフ",
|
||||
"Chapters": "チャプター",
|
||||
"You aborted the video playback": "動画再生を中止しました",
|
||||
"A network error caused the video download to fail part-way.": "ネットワーク エラーにより動画のダウンロードが途中で失敗しました",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "サーバーまたはネットワークのエラー、またはフォーマットがサポートされていないため、動画をロードできませんでした",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "破損の問題、またはお使いのブラウザがサポートしていない機能が動画に使用されていたため、動画の再生が中止されました",
|
||||
"No compatible source was found for this video.": "この動画に対して互換性のあるソースが見つかりませんでした"
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("ko",{
|
||||
"Play": "재생",
|
||||
"Pause": "일시중지",
|
||||
"Current Time": "현재 시간",
|
||||
"Duration Time": "지정 기간",
|
||||
"Remaining Time": "남은 시간",
|
||||
"Stream Type": "스트리밍 유형",
|
||||
"LIVE": "라이브",
|
||||
"Loaded": "로드됨",
|
||||
"Progress": "진행",
|
||||
"Fullscreen": "전체 화면",
|
||||
"Non-Fullscreen": "전체 화면 해제",
|
||||
"Mute": "음소거",
|
||||
"Unmuted": "음소거 해제",
|
||||
"Playback Rate": "재생 비율",
|
||||
"Subtitles": "서브타이틀",
|
||||
"subtitles off": "서브타이틀 끄기",
|
||||
"Captions": "자막",
|
||||
"captions off": "자막 끄기",
|
||||
"Chapters": "챕터",
|
||||
"You aborted the video playback": "비디오 재생을 취소했습니다.",
|
||||
"A network error caused the video download to fail part-way.": "네트워크 오류로 인하여 비디오 일부를 다운로드하지 못 했습니다.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "비디오를 로드할 수 없습니다. 서버 혹은 네트워크 오류 때문이거나 지원되지 않는 형식 때문일 수 있습니다.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "비디오 재생이 취소됐습니다. 비디오가 손상되었거나 비디오가 사용하는 기능을 브라우저에서 지원하지 않는 것 같습니다.",
|
||||
"No compatible source was found for this video.": "비디오에 호환되지 않는 소스가 있습니다."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("nl",{
|
||||
"Play": "Afspelen",
|
||||
"Pause": "Pauze",
|
||||
"Current Time": "Huidige Tijd",
|
||||
"Duration Time": "Looptijd",
|
||||
"Remaining Time": "Resterende Tijd",
|
||||
"Stream Type": "Stream Type",
|
||||
"LIVE": "LIVE",
|
||||
"Loaded": "Geladen",
|
||||
"Progress": "Status",
|
||||
"Fullscreen": "Volledig scherm",
|
||||
"Non-Fullscreen": "Geen volledig scherm",
|
||||
"Mute": "Geluid Uit",
|
||||
"Unmuted": "Geluid Aan",
|
||||
"Playback Rate": "Weergave Rate",
|
||||
"Subtitles": "Ondertiteling",
|
||||
"subtitles off": "Ondertiteling uit",
|
||||
"Captions": "Onderschriften",
|
||||
"captions off": "Onderschriften uit",
|
||||
"Chapters": "Hoofdstukken",
|
||||
"You aborted the video playback": "Je hebt de video weergave afgebroken.",
|
||||
"A network error caused the video download to fail part-way.": "De video download is mislukt door een netwerkfout.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "De video kon niet worden geladen, veroorzaakt door een server of netwerkfout of het formaat word niet ondersteund.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "De video weergave is afgebroken omdat deze beschadigd is of de video gebruikt functionaliteit die niet door je browser word ondersteund.",
|
||||
"No compatible source was found for this video.": "Voor deze video is geen ondersteunde bron gevonden."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("pt-BR",{
|
||||
"Play": "Tocar",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Tempo",
|
||||
"Duration Time": "Duração",
|
||||
"Remaining Time": "Tempo Restante",
|
||||
"Stream Type": "Tipo de Stream",
|
||||
"LIVE": "AO VIVO",
|
||||
"Loaded": "Carregado",
|
||||
"Progress": "Progresso",
|
||||
"Fullscreen": "Tela Cheia",
|
||||
"Non-Fullscreen": "Tela Normal",
|
||||
"Mute": "Mudo",
|
||||
"Unmuted": "Habilitar Som",
|
||||
"Playback Rate": "Velocidade",
|
||||
"Subtitles": "Legendas",
|
||||
"subtitles off": "Sem Legendas",
|
||||
"Captions": "Anotações",
|
||||
"captions off": "Sem Anotações",
|
||||
"Chapters": "Capítulos",
|
||||
"You aborted the video playback": "Você parou a execução de vídeo.",
|
||||
"A network error caused the video download to fail part-way.": "Um erro na rede fez o vídeo parar parcialmente.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "O vídeo não pode ser carregado, ou porque houve um problema com sua rede ou pelo formato do vídeo não ser suportado.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "A Execução foi interrompida por um problema com o vídeo ou por seu navegador não dar suporte ao seu formato.",
|
||||
"No compatible source was found for this video.": "Não foi encontrada fonte de vídeo compatível."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("ru",{
|
||||
"Play": "Воспроизвести",
|
||||
"Pause": "Приостановить",
|
||||
"Current Time": "Текущее время",
|
||||
"Duration Time": "Продолжительность",
|
||||
"Remaining Time": "Оставшееся время",
|
||||
"Stream Type": "Тип потока",
|
||||
"LIVE": "ОНЛАЙН",
|
||||
"Loaded": "Загрузка",
|
||||
"Progress": "Прогресс",
|
||||
"Fullscreen": "Полноэкранный режим",
|
||||
"Non-Fullscreen": "Неполноэкранный режим",
|
||||
"Mute": "Без звука",
|
||||
"Unmuted": "Со звуком",
|
||||
"Playback Rate": "Скорость воспроизведения",
|
||||
"Subtitles": "Субтитры",
|
||||
"subtitles off": "Субтитры выкл.",
|
||||
"Captions": "Подписи",
|
||||
"captions off": "Подписи выкл.",
|
||||
"Chapters": "Главы",
|
||||
"You aborted the video playback": "Вы прервали воспроизведение видео",
|
||||
"A network error caused the video download to fail part-way.": "Ошибка сети вызвала сбой во время загрузки видео.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Невозможно загрузить видео из-за сетевого или серверного сбоя либо формат не поддерживается.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Воспроизведение видео было приостановлено из-за повреждения либо в связи с тем, что видео использует функции, неподдерживаемые вашим браузером.",
|
||||
"No compatible source was found for this video.": "Совместимые источники для этого видео отсутствуют."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("sr",{
|
||||
"Play": "Pusti",
|
||||
"Pause": "Pauza",
|
||||
"Current Time": "Trenutno vrijeme",
|
||||
"Duration Time": "Vrijeme trajanja",
|
||||
"Remaining Time": "Preostalo vrijeme",
|
||||
"Stream Type": "Način strimovanja",
|
||||
"LIVE": "UŽIVO",
|
||||
"Loaded": "Učitan",
|
||||
"Progress": "Progres",
|
||||
"Fullscreen": "Puni ekran",
|
||||
"Non-Fullscreen": "Mali ekran",
|
||||
"Mute": "Prigušen",
|
||||
"Unmuted": "Ne-prigušen",
|
||||
"Playback Rate": "Stopa reprodukcije",
|
||||
"Subtitles": "Podnaslov",
|
||||
"subtitles off": "Podnaslov deaktiviran",
|
||||
"Captions": "Titlovi",
|
||||
"captions off": "Titlovi deaktivirani",
|
||||
"Chapters": "Poglavlja",
|
||||
"You aborted the video playback": "Isključili ste reprodukciju videa.",
|
||||
"A network error caused the video download to fail part-way.": "Video se prestao preuzimati zbog greške na mreži.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Video se ne može reproducirati zbog servera, greške u mreži ili je format ne podržan.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Reprodukcija videa je zaustavljenja zbog greške u formatu ili zbog verzije vašeg pretraživača.",
|
||||
"No compatible source was found for this video.": "Nije nađen nijedan kompatibilan izvor ovog videa."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("tr",{
|
||||
"Play": "Oynat",
|
||||
"Pause": "Duraklat",
|
||||
"Current Time": "Süre",
|
||||
"Duration Time": "Toplam Süre",
|
||||
"Remaining Time": "Kalan Süre",
|
||||
"Stream Type": "Yayın Tipi",
|
||||
"LIVE": "CANLI",
|
||||
"Loaded": "Yüklendi",
|
||||
"Progress": "Yükleniyor",
|
||||
"Fullscreen": "Tam Ekran",
|
||||
"Non-Fullscreen": "Küçük Ekran",
|
||||
"Mute": "Ses Kapa",
|
||||
"Unmuted": "Ses Aç",
|
||||
"Playback Rate": "Oynatma Hızı",
|
||||
"Subtitles": "Altyazı",
|
||||
"subtitles off": "Altyazı Kapat",
|
||||
"Captions": "Ek Açıklamalar",
|
||||
"captions off": "Ek Açıklamalar Kapalı",
|
||||
"Chapters": "Bölümler",
|
||||
"You aborted the video playback": "Video oynatmayı iptal ettiniz",
|
||||
"A network error caused the video download to fail part-way.": "Video indirilirken bağlantı sorunu oluştu.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Video oynatılamadı, Ağ yada sunucu hattası veya belirtilen format desteklenmiyor.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Tarayıcınız desteklemediği için videoda hata oluştu.",
|
||||
"No compatible source was found for this video.": "Video için kaynak bulunamadı."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("uk",{
|
||||
"Play": "Відтворити",
|
||||
"Pause": "Призупинити",
|
||||
"Current Time": "Поточний час",
|
||||
"Duration Time": "Тривалість",
|
||||
"Remaining Time": "Час, що залишився",
|
||||
"Stream Type": "Тип потоку",
|
||||
"LIVE": "НАЖИВО",
|
||||
"Loaded": "Завантаження",
|
||||
"Progress": "Прогрес",
|
||||
"Fullscreen": "Повноекранний режим",
|
||||
"Non-Fullscreen": "Неповноекранний режим",
|
||||
"Mute": "Без звуку",
|
||||
"Unmuted": "Зі звуком",
|
||||
"Playback Rate": "Швидкість відтворення",
|
||||
"Subtitles": "Субтитри",
|
||||
"subtitles off": "Без субтитрів",
|
||||
"Captions": "Підписи",
|
||||
"captions off": "Без підписів",
|
||||
"Chapters": "Розділи",
|
||||
"You aborted the video playback": "Ви припинили відтворення відео",
|
||||
"A network error caused the video download to fail part-way.": "Помилка мережі викликала збій під час завантаження відео.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Неможливо завантажити відео через мережевий чи серверний збій або формат не підтримується.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Відтворення відео було припинено через пошкодження або у зв'язку з тим, що відео використовує функції, які не підтримуються вашим браузером.",
|
||||
"No compatible source was found for this video.": "Сумісні джерела для цього відео відсутні."
|
||||
});
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
videojs.addLanguage("vi",{
|
||||
"Play": "Phát",
|
||||
"Pause": "Tạm dừng",
|
||||
"Current Time": "Thời gian hiện tại",
|
||||
"Duration Time": "Độ dài",
|
||||
"Remaining Time": "Thời gian còn lại",
|
||||
"Stream Type": "Kiểu Stream",
|
||||
"LIVE": "TRỰC TIẾP",
|
||||
"Loaded": "Đã tải",
|
||||
"Progress": "Tiến trình",
|
||||
"Fullscreen": "Toàn màn hình",
|
||||
"Non-Fullscreen": "Thoát toàn màn hình",
|
||||
"Mute": "Tắt tiếng",
|
||||
"Unmuted": "Bật âm thanh",
|
||||
"Playback Rate": "Tốc độ phát",
|
||||
"Subtitles": "Phụ đề",
|
||||
"subtitles off": "Tắt phụ đề",
|
||||
"Captions": "Chú thích",
|
||||
"captions off": "Tắt chú thích",
|
||||
"Chapters": "Chương",
|
||||
"You aborted the video playback": "Bạn đã hủy việc phát video.",
|
||||
"A network error caused the video download to fail part-way.": "Một lỗi mạng dẫn đến việc tải video bị lỗi.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "Video không tải được, mạng hay server có lỗi hoặc định dạng không được hỗ trợ.",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Phát video đã bị hủy do một sai lỗi hoặc video sử dụng những tính năng trình duyệt không hỗ trợ.",
|
||||
"No compatible source was found for this video.": "Không có nguồn tương thích cho video này."
|
||||
});
|
||||
externo
+27
@@ -0,0 +1,27 @@
|
||||
videojs.addLanguage("zh-CN",{
|
||||
"Play": "播放",
|
||||
"Pause": "暂停",
|
||||
"Current Time": "当前时间",
|
||||
"Duration Time": "时长",
|
||||
"Remaining Time": "剩余时间",
|
||||
"Stream Type": "媒体流类型",
|
||||
"LIVE": "直播",
|
||||
"Loaded": "加载完毕",
|
||||
"Progress": "进度",
|
||||
"Fullscreen": "全屏",
|
||||
"Non-Fullscreen": "退出全屏",
|
||||
"Mute": "静音",
|
||||
"Unmuted": "取消静音",
|
||||
"Playback Rate": "播放码率",
|
||||
"Subtitles": "字幕",
|
||||
"subtitles off": "字幕关闭",
|
||||
"Captions": "内嵌字幕",
|
||||
"captions off": "内嵌字幕关闭",
|
||||
"Chapters": "节目段落",
|
||||
"You aborted the video playback": "视频播放被终止",
|
||||
"A network error caused the video download to fail part-way.": "网络错误导致视频下载中途失败。",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "视频因格式不支持或者服务器或网络的问题无法加载。",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "由于视频文件损坏或是该视频使用了你的浏览器不支持的功能,播放终止。",
|
||||
"No compatible source was found for this video.": "无法找到此视频兼容的源。",
|
||||
"The video is encrypted and we do not have the keys to decrypt it.": "视频已加密,无法解密。"
|
||||
});
|
||||
externo
+27
@@ -0,0 +1,27 @@
|
||||
videojs.addLanguage("zh-TW",{
|
||||
"Play": "播放",
|
||||
"Pause": "暫停",
|
||||
"Current Time": "目前時間",
|
||||
"Duration Time": "總共時間",
|
||||
"Remaining Time": "剩餘時間",
|
||||
"Stream Type": "串流類型",
|
||||
"LIVE": "直播",
|
||||
"Loaded": "載入完畢",
|
||||
"Progress": "進度",
|
||||
"Fullscreen": "全螢幕",
|
||||
"Non-Fullscreen": "退出全螢幕",
|
||||
"Mute": "靜音",
|
||||
"Unmuted": "取消靜音",
|
||||
"Playback Rate": " 播放速率",
|
||||
"Subtitles": "字幕",
|
||||
"subtitles off": "關閉字幕",
|
||||
"Captions": "內嵌字幕",
|
||||
"captions off": "關閉內嵌字幕",
|
||||
"Chapters": "章節",
|
||||
"You aborted the video playback": "影片播放已終止",
|
||||
"A network error caused the video download to fail part-way.": "網路錯誤導致影片下載失敗。",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "影片因格式不支援或者伺服器或網路的問題無法載入。",
|
||||
"The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "由於影片檔案損毀或是該影片使用了您的瀏覽器不支援的功能,播放終止。",
|
||||
"No compatible source was found for this video.": "無法找到相容此影片的來源。",
|
||||
"The video is encrypted and we do not have the keys to decrypt it.": "影片已加密,無法解密。"
|
||||
});
|
||||
externo
+16879
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
BIN
Arquivo binário não exibido.
externo
+946
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
BIN
Arquivo binário não exibido.
externo
+16755
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+211
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+22
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+28
-10
@@ -37,7 +37,7 @@ Video.js uses key/value object dictionaries in JSON form. A sample dictionary fo
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
- The file name should always be in the format `XX.json`, where `XX` is the two letter value of the language reported to the browser (for options see the bottom of this document).
|
||||
- For automatic inclusion at build time, add your language file to the `/lang` directory (see 'Adding Languages to Video.js below').
|
||||
|
||||
@@ -45,7 +45,7 @@ Adding Languages to Video.js
|
||||
----------------------------
|
||||
Additional language support can be added to Video.js in multiple ways.
|
||||
|
||||
1. Create language scripts out of your JSON objects by using our custom grunt task `vjslanguages`. This task is automatically run as part of the default grunt task in Video.JS, but can be configured to match your `src`/`dist` directories if different. Once these scripts are created, just add them to your DOM like any other script.
|
||||
1. Create language scripts out of your JSON objects by using our custom grunt task `vjslanguages`. This task is automatically run as part of the default grunt task in Video.JS, but can be configured to match your `src`/`dist` directories if different. Once these scripts are created, just add them to your DOM like any other script.
|
||||
|
||||
NOTE: These need to be added after the core Video.js script.
|
||||
|
||||
@@ -122,6 +122,24 @@ During a Video.js player instantiation you can force it to localize to a specifi
|
||||
</video>
|
||||
```
|
||||
|
||||
Determining Player Language
|
||||
---------------------------
|
||||
|
||||
The player language is set to one of the following in descending priority
|
||||
|
||||
* The language set in setup options as above
|
||||
* The document language (`lang` attribute of the `html` element)
|
||||
* Browser language preference
|
||||
* 'en'
|
||||
|
||||
That can be overridden after instantiation with `language('fr')`.
|
||||
|
||||
Language selection
|
||||
------------------
|
||||
|
||||
* Language codes are considered case-insensitively (`en-US` == `en-us`).
|
||||
* If there is no match for a language code with a subcode (`en-us`), a match for the primary code (`en`) is used if available.
|
||||
|
||||
Localization in Plugins
|
||||
-----------------------
|
||||
|
||||
@@ -133,7 +151,7 @@ var details = '<div class="vjs-errors-details">' + player.localize('Technical de
|
||||
|
||||
Language Codes
|
||||
--------------
|
||||
The following is a list of official language codes.
|
||||
The following is a list of official language codes.
|
||||
|
||||
**NOTE:** For supported language translations, please see the [Languages Folder (/lang)](../../lang) folder located in the project root.
|
||||
|
||||
@@ -180,10 +198,10 @@ The following is a list of official language codes.
|
||||
<tr><th>fj<th><td>Fiji</td></tr>
|
||||
<tr><th>fi<th><td>Finnish</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<table>
|
||||
<tr><th>fr<th><td>French</td></tr>
|
||||
<tr><th>fy<th><td>Frisian</td></tr>
|
||||
@@ -223,10 +241,10 @@ The following is a list of official language codes.
|
||||
<tr><th>lo<th><td>Laothian</td></tr>
|
||||
<tr><th>la<th><td>Latin</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<table>
|
||||
<tr><th>lv<th><td>Latvian (Lettish)</td></tr>
|
||||
<tr><th>li<th><td>Limburgish ( Limburger)</td></tr>
|
||||
@@ -266,10 +284,10 @@ The following is a list of official language codes.
|
||||
<tr><th>ii<th><td>Sichuan Yi</td></tr>
|
||||
<tr><th>sd<th><td>Sindhi</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<table>
|
||||
<tr><th>si<th><td>Sinhalese</td></tr>
|
||||
<tr><th>ss<th><td>Siswati</td></tr>
|
||||
@@ -307,7 +325,7 @@ The following is a list of official language codes.
|
||||
<tr><th>yo<th><td>Yoruba</td></tr>
|
||||
<tr><th>zu<th><td>Zulu</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
+6
-5
@@ -226,25 +226,25 @@ module.exports = function(grunt) {
|
||||
options: {
|
||||
release: 'major'
|
||||
},
|
||||
src: ['package.json', 'bower.json', 'component.json']
|
||||
src: ['package.json', 'component.json']
|
||||
},
|
||||
minor: {
|
||||
options: {
|
||||
release: 'minor'
|
||||
},
|
||||
src: ['package.json', 'bower.json', 'component.json']
|
||||
src: ['package.json', 'component.json']
|
||||
},
|
||||
patch: {
|
||||
options: {
|
||||
release: 'patch'
|
||||
},
|
||||
src: ['package.json', 'bower.json', 'component.json']
|
||||
src: ['package.json', 'component.json']
|
||||
},
|
||||
prerelease: {
|
||||
options: {
|
||||
release: 'prerelease'
|
||||
},
|
||||
src: ['package.json', 'bower.json', 'component.json']
|
||||
src: ['package.json', 'component.json']
|
||||
},
|
||||
css: {
|
||||
options: {
|
||||
@@ -286,7 +286,8 @@ module.exports = function(grunt) {
|
||||
],
|
||||
transform: [
|
||||
require('babelify').configure({
|
||||
sourceMapRelative: './src/js'
|
||||
sourceMapRelative: './src/js',
|
||||
loose: 'all'
|
||||
}),
|
||||
['browserify-versionify', {
|
||||
placeholder: '__VERSION__',
|
||||
|
||||
+7
-4
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "5.0.0-10",
|
||||
"version": "5.0.0-24",
|
||||
"copyright": "Copyright Brightcove, Inc. <https://www.brightcove.com/>",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
@@ -24,9 +24,10 @@
|
||||
"style": "./dist/video-js.css",
|
||||
"dependencies": {
|
||||
"global": "^4.3.0",
|
||||
"lodash.merge": "^3.2.1",
|
||||
"object.assign": "^2.0.1",
|
||||
"safe-json-parse": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"videojs-swf": "4.5.4",
|
||||
"videojs-swf": "4.7.0",
|
||||
"vtt.js": "git+https://github.com/gkatsev/vtt.js.git#shim-build"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -37,10 +38,12 @@
|
||||
"browserify-istanbul": "^0.2.1",
|
||||
"browserify-versionify": "^1.0.4",
|
||||
"chg": "~0.2.0",
|
||||
"css": "^2.2.0",
|
||||
"es5-shim": "^4.1.3",
|
||||
"grunt": "^0.4.4",
|
||||
"grunt-aws-s3": "^0.12.1",
|
||||
"grunt-banner": "^0.3.1",
|
||||
"grunt-browserify": "^3.5.0",
|
||||
"grunt-browserify": "3.5.1",
|
||||
"grunt-cli": "~0.1.0",
|
||||
"grunt-contrib-clean": "~0.4.0a",
|
||||
"grunt-contrib-concat": "^0.5.1",
|
||||
|
||||
@@ -4,13 +4,21 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>Video.js Sandbox</title>
|
||||
|
||||
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
|
||||
<!-- Add ES5 shim and sham for IE8 -->
|
||||
<script src="../node_modules/es5-shim/es5-shim.js"></script>
|
||||
<script src="../node_modules/es5-shim/es5-sham.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>
|
||||
|
||||
<!-- Set the location of the flash SWF -->
|
||||
<script>
|
||||
videojs.options.flash.swf = '../build/temp/video-js.swf';
|
||||
videojs.setGlobalOptions({
|
||||
flash: {
|
||||
swf: '../build/temp/video-js.swf'
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
.video-js {
|
||||
display: block;
|
||||
/* inline-block is as close as we get to the video el's display:inline */
|
||||
display: inline-block;
|
||||
/* Make video.js videos align top when next to video elements */
|
||||
vertical-align: top;
|
||||
box-sizing: border-box;
|
||||
|
||||
/* Default to the video element width/height. This will be overridden by
|
||||
* the source width height unless changed elsewhere. */
|
||||
width: 300px;
|
||||
height: 150px;
|
||||
|
||||
color: $primary-text;
|
||||
background-color: $primary-bg;
|
||||
position: relative;
|
||||
@@ -9,8 +17,6 @@
|
||||
/* Start with 10px for base font size so other dimensions can be em based and
|
||||
easily calculable. */
|
||||
font-size: $base-font-size;
|
||||
/* Allow poster to be vertially aligned. */
|
||||
vertical-align: middle;
|
||||
|
||||
/* Provide some basic defaults for fonts */
|
||||
font-weight: normal;
|
||||
@@ -37,6 +43,29 @@
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
/* Fill the width of the containing element and use padding to create the
|
||||
desired aspect ratio. Default to 16x9 unless another ratio is given. */
|
||||
@mixin apply-aspect-ratio($width, $height) {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 0;
|
||||
padding-top: 100% * ($height/$width);
|
||||
}
|
||||
|
||||
.video-js.vjs-fluid,
|
||||
.video-js.vjs-16-9 {
|
||||
@include apply-aspect-ratio(16, 9);
|
||||
}
|
||||
|
||||
.video-js.vjs-4-3 {
|
||||
@include apply-aspect-ratio(4, 3);
|
||||
}
|
||||
|
||||
.video-js.vjs-fill {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Playback technology elements expand to the width/height of the containing div
|
||||
<video> or <object> */
|
||||
.video-js .vjs-tech {
|
||||
@@ -65,6 +94,8 @@ body.vjs-full-window {
|
||||
right: 0;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
/* Undo any aspect ratio padding for fluid layouts */
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.video-js.vjs-fullscreen.vjs-user-inactive {
|
||||
cursor: none;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
.vjs-poster {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
background-size: contain;
|
||||
@@ -10,9 +12,11 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.vjs-poster img {
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
margin: 0 auto;
|
||||
max-height: 100%;
|
||||
padding: 0;
|
||||
|
||||
@@ -27,7 +27,17 @@
|
||||
|
||||
.video-js .vjs-play-progress {
|
||||
background-color: $primary-text;
|
||||
@extend .vjs-icon-circle;
|
||||
|
||||
// Progress handle
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: -0.35em;
|
||||
right: -0.5em;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.video-js .vjs-load-progress {
|
||||
background: rgb(100, 100, 100) /* IE8- Fallback */;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
@@ -39,12 +49,6 @@ specific time ranges that have been buffered */
|
||||
background: rgba($secondary-bg, 0.1);
|
||||
}
|
||||
|
||||
.video-js .vjs-slider-handle.vjs-seek-handle {
|
||||
width: 0.95em;
|
||||
height: 0.95em;
|
||||
}
|
||||
|
||||
|
||||
.video-js.vjs-no-flex .vjs-progress-control {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
@@ -12,28 +12,3 @@
|
||||
|
||||
@include box-shadow(0 0 1em $primary-text);
|
||||
}
|
||||
|
||||
.video-js .vjs-slider-handle {
|
||||
position: absolute;
|
||||
@extend .vjs-icon-circle;
|
||||
}
|
||||
|
||||
.video-js .vjs-slider-horizontal .vjs-slider-handle {
|
||||
left: 0;
|
||||
top: -0.34em;
|
||||
}
|
||||
|
||||
.video-js .vjs-slider-vertical .vjs-slider-handle {
|
||||
left: -0.3em;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.video-js .vjs-slider-handle:before {
|
||||
font-size: 1em;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@@ -41,27 +41,37 @@
|
||||
left: 0;
|
||||
|
||||
background-color: $primary-text;
|
||||
|
||||
@extend .vjs-icon-circle;
|
||||
|
||||
// Volume handle
|
||||
&:before {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.video-js .vjs-slider-vertical .vjs-volume-level { width: 0.3em; }
|
||||
.video-js .vjs-slider-horizontal .vjs-volume-level { height: 0.3em; }
|
||||
.video-js .vjs-slider-vertical .vjs-volume-level {
|
||||
width: 0.3em;
|
||||
|
||||
.video-js .vjs-volume-bar .vjs-volume-handle {
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
// Volume handle
|
||||
&:before {
|
||||
top: -0.5em;
|
||||
left: -0.35em;
|
||||
}
|
||||
}
|
||||
.video-js .vjs-slider-horizontal .vjs-volume-level {
|
||||
height: 0.3em;
|
||||
|
||||
// Volume handle
|
||||
&:before {
|
||||
top: -0.35em;
|
||||
right: -0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assumes volume starts at 1.0. If you change the size of the
|
||||
handle relative to the volume bar, you'll need to update this value
|
||||
too. */
|
||||
/* Assumes volume starts at 1.0. */
|
||||
.video-js .vjs-volume-bar.vjs-slider-vertical .vjs-volume-level { height: 100%; }
|
||||
.video-js .vjs-volume-bar.vjs-slider-vertical .vjs-volume-handle { bottom: 4.3em; }
|
||||
.video-js .vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level { width: 100%; }
|
||||
.video-js .vjs-volume-bar.vjs-slider-horizontal .vjs-volume-handle { left: 4.3em; }
|
||||
|
||||
.video-js .vjs-volume-handle:before {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* The volume menu button is like menu buttons (captions/subtitles) but works
|
||||
a little differently. It needs to be possible to tab to the volume slider
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Button from './button';
|
||||
import Button from './button.js';
|
||||
import Component from './component.js';
|
||||
|
||||
/* Big Play Button
|
||||
================================================================================ */
|
||||
@@ -26,5 +27,5 @@ class BigPlayButton extends Button {
|
||||
|
||||
}
|
||||
|
||||
Button.registerComponent('BigPlayButton', BigPlayButton);
|
||||
Component.registerComponent('BigPlayButton', BigPlayButton);
|
||||
export default BigPlayButton;
|
||||
|
||||
+10
-8
@@ -1,7 +1,9 @@
|
||||
import Component from './component';
|
||||
import * as Lib from './lib';
|
||||
import * as Events from './events';
|
||||
import * as Dom from './utils/dom.js';
|
||||
import * as Events from './utils/events.js';
|
||||
import * as Fn from './utils/fn.js';
|
||||
import document from 'global/document';
|
||||
import assign from 'object.assign';
|
||||
|
||||
/* Button - Base class for all buttons
|
||||
================================================================================ */
|
||||
@@ -27,7 +29,7 @@ class Button extends Component {
|
||||
|
||||
createEl(type, props) {
|
||||
// Add standard Aria and Tabindex info
|
||||
props = Lib.obj.merge({
|
||||
props = assign({
|
||||
className: this.buildCSSClass(),
|
||||
'role': 'button',
|
||||
'aria-live': 'polite', // let the screen reader user know that the text of the button may change
|
||||
@@ -38,11 +40,11 @@ class Button extends Component {
|
||||
|
||||
// if innerHTML hasn't been overridden (bigPlayButton), add content elements
|
||||
if (!props.innerHTML) {
|
||||
this.contentEl_ = Lib.createEl('div', {
|
||||
this.contentEl_ = Dom.createEl('div', {
|
||||
className: 'vjs-control-content'
|
||||
});
|
||||
|
||||
this.controlText_ = Lib.createEl('span', {
|
||||
this.controlText_ = Dom.createEl('span', {
|
||||
className: 'vjs-control-text',
|
||||
innerHTML: this.localize(this.buttonText) || 'Need Text'
|
||||
});
|
||||
@@ -63,13 +65,13 @@ class Button extends Component {
|
||||
|
||||
// Focus - Add keyboard functionality to element
|
||||
handleFocus() {
|
||||
Events.on(document, 'keydown', Lib.bind(this, this.handleKeyPress));
|
||||
Events.on(document, 'keydown', Fn.bind(this, this.handleKeyPress));
|
||||
}
|
||||
|
||||
// KeyPress (document level) - Trigger click when keys are pressed
|
||||
handleKeyPress(event) {
|
||||
// Check for space bar (32) or enter (13) keys
|
||||
if (event.which == 32 || event.which == 13) {
|
||||
if (event.which === 32 || event.which === 13) {
|
||||
event.preventDefault();
|
||||
this.handleClick();
|
||||
}
|
||||
@@ -77,7 +79,7 @@ class Button extends Component {
|
||||
|
||||
// Blur - Remove keyboard triggers
|
||||
handleBlur() {
|
||||
Events.off(document, 'keydown', Lib.bind(this, this.handleKeyPress));
|
||||
Events.off(document, 'keydown', Fn.bind(this, this.handleKeyPress));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+74
-62
@@ -3,10 +3,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import * as Lib from './lib.js';
|
||||
import * as VjsUtil from './util.js';
|
||||
import * as Events from './events.js';
|
||||
import window from 'global/window';
|
||||
import * as Dom from './utils/dom.js';
|
||||
import * as Fn from './utils/fn.js';
|
||||
import * as Guid from './utils/guid.js';
|
||||
import * as Events from './utils/events.js';
|
||||
import log from './utils/log.js';
|
||||
import toTitleCase from './utils/to-title-case.js';
|
||||
import assign from 'object.assign';
|
||||
import mergeOptions from './utils/merge-options.js';
|
||||
|
||||
|
||||
/**
|
||||
* Base UI Component class
|
||||
@@ -47,8 +53,8 @@ class Component {
|
||||
this.player_ = player;
|
||||
}
|
||||
|
||||
// Make a copy of prototype.options_ to protect against overriding global defaults
|
||||
this.options_ = Lib.obj.copy(this.options_);
|
||||
// Make a copy of prototype.options_ to protect against overriding defaults
|
||||
this.options_ = mergeOptions({}, this.options_);
|
||||
|
||||
// Updated options with supplied options
|
||||
options = this.options(options);
|
||||
@@ -59,9 +65,9 @@ class Component {
|
||||
// If there was no ID from the options, generate one
|
||||
if (!this.id_) {
|
||||
// Don't require the player ID function in the case of mock players
|
||||
let id = player.id && player.id() || 'no_player';
|
||||
let id = player && player.id && player.id() || 'no_player';
|
||||
|
||||
this.id_ = `${id}_component_${Lib.guid++}`;
|
||||
this.id_ = `${id}_component_${Guid.newGUID()}`;
|
||||
}
|
||||
|
||||
this.name_ = options.name || null;
|
||||
@@ -125,7 +131,7 @@ class Component {
|
||||
this.el_.parentNode.removeChild(this.el_);
|
||||
}
|
||||
|
||||
Lib.removeData(this.el_);
|
||||
Dom.removeElData(this.el_);
|
||||
this.el_ = null;
|
||||
}
|
||||
|
||||
@@ -142,7 +148,7 @@ class Component {
|
||||
* Deep merge of options objects
|
||||
*
|
||||
* Whenever a property is an object on both options objects
|
||||
* the two properties will be merged using Lib.obj.deepMerge.
|
||||
* the two properties will be merged using mergeOptions.
|
||||
*
|
||||
* This is used for merging options for child components. We
|
||||
* want it to be easy to override individual options on a child
|
||||
@@ -184,7 +190,7 @@ class Component {
|
||||
return this.options_;
|
||||
}
|
||||
|
||||
this.options_ = VjsUtil.mergeOptions(this.options_, obj);
|
||||
this.options_ = mergeOptions(this.options_, obj);
|
||||
return this.options_;
|
||||
}
|
||||
|
||||
@@ -207,15 +213,28 @@ class Component {
|
||||
* @return {Element}
|
||||
*/
|
||||
createEl(tagName, attributes) {
|
||||
return Lib.createEl(tagName, attributes);
|
||||
return Dom.createEl(tagName, attributes);
|
||||
}
|
||||
|
||||
localize(string) {
|
||||
let lang = this.player_.language();
|
||||
let languages = this.player_.languages();
|
||||
let code = this.player_.language && this.player_.language();
|
||||
let languages = this.player_.languages && this.player_.languages();
|
||||
|
||||
if (languages && languages[lang] && languages[lang][string]) {
|
||||
return languages[lang][string];
|
||||
if (!code || !languages) {
|
||||
return string;
|
||||
}
|
||||
|
||||
let language = languages[code];
|
||||
|
||||
if (language && language[string]) {
|
||||
return language[string];
|
||||
}
|
||||
|
||||
let primaryCode = code.split('-')[0];
|
||||
let primaryLang = languages[primaryCode];
|
||||
|
||||
if (primaryLang && primaryLang[string]) {
|
||||
return primaryLang[string];
|
||||
}
|
||||
|
||||
return string;
|
||||
@@ -325,13 +344,13 @@ class Component {
|
||||
|
||||
// Same as above, but true is deprecated so show a warning.
|
||||
if (options === true) {
|
||||
Lib.log.warn('Initializing a child component with `true` is deprecated. Children should be defined in an array when possible, but if necessary use an object instead of `true`.');
|
||||
log.warn('Initializing a child component with `true` is deprecated. Children should be defined in an array when possible, but if necessary use an object instead of `true`.');
|
||||
options = {};
|
||||
}
|
||||
|
||||
// If no componentClass in options, assume componentClass is the name lowercased
|
||||
// (e.g. playButton)
|
||||
let componentClassName = options.componentClass || Lib.capitalize(componentName);
|
||||
let componentClassName = options.componentClass || toTitleCase(componentName);
|
||||
|
||||
// Set name through options
|
||||
options.name = componentName;
|
||||
@@ -472,7 +491,7 @@ class Component {
|
||||
};
|
||||
|
||||
// Allow for an array of children details to passed in the options
|
||||
if (Lib.obj.isArray(children)) {
|
||||
if (Array.isArray(children)) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let child = children[i];
|
||||
let name;
|
||||
@@ -491,7 +510,9 @@ class Component {
|
||||
handleAdd(name, opts);
|
||||
}
|
||||
} else {
|
||||
Lib.obj.each(children, handleAdd);
|
||||
Object.getOwnPropertyNames(children).forEach(function(name){
|
||||
handleAdd(name, children[name]);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -540,14 +561,14 @@ class Component {
|
||||
* @return {Component} self
|
||||
*/
|
||||
on(first, second, third) {
|
||||
if (typeof first === 'string' || Lib.obj.isArray(first)) {
|
||||
Events.on(this.el_, first, Lib.bind(this, second));
|
||||
if (typeof first === 'string' || Array.isArray(first)) {
|
||||
Events.on(this.el_, first, Fn.bind(this, second));
|
||||
|
||||
// Targeting another component or element
|
||||
} else {
|
||||
const target = first;
|
||||
const type = second;
|
||||
const fn = Lib.bind(this, third);
|
||||
const fn = Fn.bind(this, third);
|
||||
|
||||
// When this component is disposed, remove the listener from the other component
|
||||
const removeOnDispose = () => this.off(target, type, fn);
|
||||
@@ -604,13 +625,13 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
off(first, second, third) {
|
||||
if (!first || typeof first === 'string' || Lib.obj.isArray(first)) {
|
||||
if (!first || typeof first === 'string' || Array.isArray(first)) {
|
||||
Events.off(this.el_, first, second);
|
||||
} else {
|
||||
const target = first;
|
||||
const type = second;
|
||||
// Ensure there's at least a guid, even if the function hasn't been used
|
||||
const fn = Lib.bind(this, third);
|
||||
const fn = Fn.bind(this, third);
|
||||
|
||||
// Remove the dispose listener on this component,
|
||||
// which was given the same guid as the event listener
|
||||
@@ -647,12 +668,12 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
one(first, second, third) {
|
||||
if (typeof first === 'string' || Lib.obj.isArray(first)) {
|
||||
Events.one(this.el_, first, Lib.bind(this, second));
|
||||
if (typeof first === 'string' || Array.isArray(first)) {
|
||||
Events.one(this.el_, first, Fn.bind(this, second));
|
||||
} else {
|
||||
const target = first;
|
||||
const type = second;
|
||||
const fn = Lib.bind(this, third);
|
||||
const fn = Fn.bind(this, third);
|
||||
|
||||
const newFunc = () => {
|
||||
this.off(target, type, newFunc);
|
||||
@@ -694,7 +715,8 @@ class Component {
|
||||
ready(fn) {
|
||||
if (fn) {
|
||||
if (this.isReady_) {
|
||||
fn.call(this);
|
||||
// Ensure function is always called asynchronously
|
||||
this.setTimeout(fn, 1);
|
||||
} else {
|
||||
this.readyQueue_ = this.readyQueue_ || [];
|
||||
this.readyQueue_.push(fn);
|
||||
@@ -711,20 +733,22 @@ class Component {
|
||||
triggerReady() {
|
||||
this.isReady_ = true;
|
||||
|
||||
let readyQueue = this.readyQueue_;
|
||||
// Ensure ready is triggerd asynchronously
|
||||
this.setTimeout(function(){
|
||||
let readyQueue = this.readyQueue_;
|
||||
|
||||
if (readyQueue && readyQueue.length > 0) {
|
||||
if (readyQueue && readyQueue.length > 0) {
|
||||
readyQueue.forEach(function(fn){
|
||||
fn.call(this);
|
||||
}, this);
|
||||
|
||||
for (let i = 0; i < readyQueue.length; i++) {
|
||||
readyQueue[i].call(this);
|
||||
// Reset Ready Queue
|
||||
this.readyQueue_ = [];
|
||||
}
|
||||
|
||||
// Reset Ready Queue
|
||||
this.readyQueue_ = [];
|
||||
|
||||
// Allow for using event listeners also, in case you want to do something everytime a source is ready.
|
||||
// Allow for using event listeners also
|
||||
this.trigger('ready');
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -734,7 +758,7 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
hasClass(classToCheck) {
|
||||
return Lib.hasClass(this.el_, classToCheck);
|
||||
return Dom.hasElClass(this.el_, classToCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -744,7 +768,7 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
addClass(classToAdd) {
|
||||
Lib.addClass(this.el_, classToAdd);
|
||||
Dom.addElClass(this.el_, classToAdd);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -755,7 +779,7 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
removeClass(classToRemove) {
|
||||
Lib.removeClass(this.el_, classToRemove);
|
||||
Dom.removeElClass(this.el_, classToRemove);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -910,20 +934,7 @@ class Component {
|
||||
// No px so using % or no style was set, so falling back to offsetWidth/height
|
||||
// If component has display:none, offset will return 0
|
||||
// TODO: handle display:none and no dimension style using px
|
||||
return parseInt(this.el_['offset' + Lib.capitalize(widthOrHeight)], 10);
|
||||
|
||||
// ComputedStyle version.
|
||||
// Only difference is if the element is hidden it will return
|
||||
// the percent value (e.g. '100%'')
|
||||
// instead of zero like offsetWidth returns.
|
||||
// var val = Lib.getComputedStyleValue(this.el_, widthOrHeight);
|
||||
// var pxIndex = val.indexOf('px');
|
||||
|
||||
// if (pxIndex !== -1) {
|
||||
// return val.slice(0, pxIndex);
|
||||
// } else {
|
||||
// return val;
|
||||
// }
|
||||
return parseInt(this.el_['offset' + toTitleCase(widthOrHeight)], 10);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -953,7 +964,8 @@ class Component {
|
||||
this.on('touchstart', function(event) {
|
||||
// If more than one finger, don't consider treating this as a click
|
||||
if (event.touches.length === 1) {
|
||||
firstTouch = Lib.obj.copy(event.touches[0]);
|
||||
// Copy the touches object to prevent modifying the original
|
||||
firstTouch = assign({}, event.touches[0]);
|
||||
// Record start time so we can detect a tap vs. "touch and hold"
|
||||
touchStart = new Date().getTime();
|
||||
// Reset couldBeTap tracking
|
||||
@@ -1002,7 +1014,7 @@ class Component {
|
||||
this.trigger('tap');
|
||||
// It may be good to copy the touchend event object and change the
|
||||
// type to tap, if the other event properties aren't exact after
|
||||
// Lib.fixEvent runs (e.g. event.target)
|
||||
// Events.fixEvent runs (e.g. event.target)
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1033,12 +1045,12 @@ class Component {
|
||||
*/
|
||||
enableTouchActivity() {
|
||||
// Don't continue if the root player doesn't support reporting user activity
|
||||
if (!this.player().reportUserActivity) {
|
||||
if (!this.player() || !this.player().reportUserActivity) {
|
||||
return;
|
||||
}
|
||||
|
||||
// listener for reporting that the user is active
|
||||
const report = Lib.bind(this.player(), this.player().reportUserActivity);
|
||||
const report = Fn.bind(this.player(), this.player().reportUserActivity);
|
||||
|
||||
let touchHolding;
|
||||
|
||||
@@ -1070,7 +1082,7 @@ class Component {
|
||||
* @return {Number} Returns the timeout ID
|
||||
*/
|
||||
setTimeout(fn, timeout) {
|
||||
fn = Lib.bind(this, fn);
|
||||
fn = Fn.bind(this, fn);
|
||||
|
||||
// window.setTimeout would be preferable here, but due to some bizarre issue with Sinon and/or Phantomjs, we can't.
|
||||
let timeoutId = window.setTimeout(fn, timeout);
|
||||
@@ -1110,7 +1122,7 @@ class Component {
|
||||
* @return {Number} Returns the interval ID
|
||||
*/
|
||||
setInterval(fn, interval) {
|
||||
fn = Lib.bind(this, fn);
|
||||
fn = Fn.bind(this, fn);
|
||||
|
||||
let intervalId = window.setInterval(fn, interval);
|
||||
|
||||
@@ -1157,7 +1169,7 @@ class Component {
|
||||
}
|
||||
|
||||
if (window && window.videojs && window.videojs[name]) {
|
||||
Lib.log.warn(`The ${name} component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)`);
|
||||
log.warn(`The ${name} component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)`);
|
||||
return window.videojs[name];
|
||||
}
|
||||
}
|
||||
@@ -1182,7 +1194,7 @@ class Component {
|
||||
};
|
||||
|
||||
// Inherit from this object's prototype
|
||||
subObj.prototype = Lib.obj.create(this.prototype);
|
||||
subObj.prototype = Object.create(this.prototype);
|
||||
// Reset the constructor property for subObj otherwise
|
||||
// instances of subObj would have the constructor of the parent Object
|
||||
subObj.prototype.constructor = subObj;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Component from '../component.js';
|
||||
import * as Lib from '../lib.js';
|
||||
|
||||
// Required children
|
||||
import PlayToggle from './play-toggle.js';
|
||||
@@ -29,7 +28,7 @@ import CustomControlSpacer from './spacer-controls/custom-control-spacer.js';
|
||||
*/
|
||||
class ControlBar extends Component {
|
||||
createEl() {
|
||||
return Lib.createEl('div', {
|
||||
return super.createEl('div', {
|
||||
className: 'vjs-control-bar'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Button from '../button';
|
||||
import Button from '../button.js';
|
||||
import Component from '../component.js';
|
||||
|
||||
/**
|
||||
* Toggle fullscreen video
|
||||
@@ -27,5 +28,5 @@ class FullscreenToggle extends Button {
|
||||
|
||||
FullscreenToggle.prototype.buttonText = 'Fullscreen';
|
||||
|
||||
Button.registerComponent('FullscreenToggle', FullscreenToggle);
|
||||
Component.registerComponent('FullscreenToggle', FullscreenToggle);
|
||||
export default FullscreenToggle;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Component from '../component';
|
||||
import * as Lib from '../lib';
|
||||
import * as Dom from '../utils/dom.js';
|
||||
|
||||
/**
|
||||
* Displays the live indicator
|
||||
@@ -15,7 +15,7 @@ class LiveDisplay extends Component {
|
||||
className: 'vjs-live-control vjs-control'
|
||||
});
|
||||
|
||||
this.contentEl_ = Lib.createEl('div', {
|
||||
this.contentEl_ = Dom.createEl('div', {
|
||||
className: 'vjs-live-display',
|
||||
innerHTML: `<span class="vjs-control-text">${this.localize('Stream Type')}</span>${this.localize('LIVE')}`,
|
||||
'aria-live': 'off'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Button from '../button';
|
||||
import Component from '../component';
|
||||
import * as Lib from '../lib';
|
||||
import * as Dom from '../utils/dom.js';
|
||||
|
||||
/**
|
||||
* A button component for muting the audio
|
||||
@@ -68,9 +68,9 @@ class MuteToggle extends Button {
|
||||
|
||||
/* TODO improve muted icon classes */
|
||||
for (var i = 0; i < 4; i++) {
|
||||
Lib.removeClass(this.el_, `vjs-vol-${i}`);
|
||||
Dom.removeElClass(this.el_, `vjs-vol-${i}`);
|
||||
}
|
||||
Lib.addClass(this.el_, `vjs-vol-${level}`);
|
||||
Dom.addElClass(this.el_, `vjs-vol-${level}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Button from '../button';
|
||||
import * as Lib from '../lib';
|
||||
import Button from '../button.js';
|
||||
import Component from '../component.js';
|
||||
|
||||
/**
|
||||
* Button to toggle between play and pause
|
||||
@@ -48,5 +48,5 @@ class PlayToggle extends Button {
|
||||
|
||||
PlayToggle.prototype.buttonText = 'Play';
|
||||
|
||||
Button.registerComponent('PlayToggle', PlayToggle);
|
||||
Component.registerComponent('PlayToggle', PlayToggle);
|
||||
export default PlayToggle;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import MenuButton from '../../menu/menu-button.js';
|
||||
import Menu from '../../menu/menu.js';
|
||||
import PlaybackRateMenuItem from './playback-rate-menu-item.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import Component from '../../component.js';
|
||||
import * as Dom from '../../utils/dom.js';
|
||||
|
||||
/**
|
||||
* The component for controlling the playback rate
|
||||
@@ -25,7 +26,7 @@ class PlaybackRateMenuButton extends MenuButton {
|
||||
createEl() {
|
||||
let el = super.createEl();
|
||||
|
||||
this.labelEl_ = Lib.createEl('div', {
|
||||
this.labelEl_ = Dom.createEl('div', {
|
||||
className: 'vjs-playback-rate-value',
|
||||
innerHTML: 1.0
|
||||
});
|
||||
@@ -104,5 +105,5 @@ class PlaybackRateMenuButton extends MenuButton {
|
||||
PlaybackRateMenuButton.prototype.buttonText = 'Playback Rate';
|
||||
PlaybackRateMenuButton.prototype.className = 'vjs-playback-rate';
|
||||
|
||||
MenuButton.registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);
|
||||
Component.registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);
|
||||
export default PlaybackRateMenuButton;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import MenuItem from '../../menu/menu-item.js';
|
||||
import Component from '../../component.js';
|
||||
|
||||
/**
|
||||
* The specific menu item type for selecting a playback rate
|
||||
@@ -28,12 +29,12 @@ class PlaybackRateMenuItem extends MenuItem {
|
||||
}
|
||||
|
||||
update() {
|
||||
this.selected(this.player().playbackRate() == this.rate);
|
||||
this.selected(this.player().playbackRate() === this.rate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PlaybackRateMenuItem.prototype.contentElType = 'button';
|
||||
|
||||
MenuItem.registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
|
||||
Component.registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
|
||||
export default PlaybackRateMenuItem;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Component from '../../component.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import * as Dom from '../../utils/dom.js';
|
||||
|
||||
/**
|
||||
* Shows load progress
|
||||
@@ -31,7 +31,7 @@ class LoadProgressBar extends Component {
|
||||
// get the percent width of a time compared to the total end
|
||||
let percentify = function (time, end){
|
||||
let percent = (time / end) || 0; // no NaN
|
||||
return (percent * 100) + '%';
|
||||
return ((percent >= 1 ? 1 : percent) * 100) + '%';
|
||||
};
|
||||
|
||||
// update the width of the progress bar
|
||||
@@ -44,7 +44,7 @@ class LoadProgressBar extends Component {
|
||||
let part = children[i];
|
||||
|
||||
if (!part) {
|
||||
part = this.el_.appendChild(Lib.createEl());
|
||||
part = this.el_.appendChild(Dom.createEl());
|
||||
}
|
||||
|
||||
// set the percent based on the width of the progress bar (bufferedEnd)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import Slider from '../../slider/slider.js';
|
||||
import Component from '../../component.js';
|
||||
import LoadProgressBar from './load-progress-bar.js';
|
||||
import PlayProgressBar from './play-progress-bar.js';
|
||||
import SeekHandle from './seek-handle.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import * as Fn from '../../utils/fn.js';
|
||||
import formatTime from '../../utils/format-time.js';
|
||||
import roundFloat from '../../utils/round-float.js';
|
||||
|
||||
/**
|
||||
* Seek Bar and holder for the progress bars
|
||||
@@ -16,7 +18,7 @@ class SeekBar extends Slider {
|
||||
constructor(player, options){
|
||||
super(player, options);
|
||||
this.on(player, 'timeupdate', this.updateARIAAttributes);
|
||||
player.ready(Lib.bind(this, this.updateARIAAttributes));
|
||||
player.ready(Fn.bind(this, this.updateARIAAttributes));
|
||||
}
|
||||
|
||||
createEl() {
|
||||
@@ -29,12 +31,13 @@ class SeekBar extends Slider {
|
||||
updateARIAAttributes() {
|
||||
// Allows for smooth scrubbing, when player can't keep up.
|
||||
let time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
|
||||
this.el_.setAttribute('aria-valuenow', Lib.round(this.getPercent()*100, 2)); // machine readable value of progress bar (percentage complete)
|
||||
this.el_.setAttribute('aria-valuetext', Lib.formatTime(time, this.player_.duration())); // human readable value of progress bar (time complete)
|
||||
this.el_.setAttribute('aria-valuenow', roundFloat(this.getPercent()*100, 2)); // machine readable value of progress bar (percentage complete)
|
||||
this.el_.setAttribute('aria-valuetext', formatTime(time, this.player_.duration())); // human readable value of progress bar (time complete)
|
||||
}
|
||||
|
||||
getPercent() {
|
||||
return this.player_.currentTime() / this.player_.duration();
|
||||
let percent = this.player_.currentTime() / this.player_.duration();
|
||||
return percent >= 1 ? 1 : percent;
|
||||
}
|
||||
|
||||
handleMouseDown(event) {
|
||||
@@ -50,7 +53,7 @@ class SeekBar extends Slider {
|
||||
let newTime = this.calculateDistance(event) * this.player_.duration();
|
||||
|
||||
// Don't let video end while scrubbing.
|
||||
if (newTime == this.player_.duration()) { newTime = newTime - 0.1; }
|
||||
if (newTime === this.player_.duration()) { newTime = newTime - 0.1; }
|
||||
|
||||
// Set new time (tell player to seek to new time)
|
||||
this.player_.currentTime(newTime);
|
||||
@@ -78,14 +81,12 @@ class SeekBar extends Slider {
|
||||
SeekBar.prototype.options_ = {
|
||||
children: {
|
||||
'loadProgressBar': {},
|
||||
'playProgressBar': {},
|
||||
'seekHandle': {}
|
||||
'playProgressBar': {}
|
||||
},
|
||||
'barName': 'playProgressBar',
|
||||
'handleName': 'seekHandle'
|
||||
'barName': 'playProgressBar'
|
||||
};
|
||||
|
||||
SeekBar.prototype.playerEvent = 'timeupdate';
|
||||
|
||||
Slider.registerComponent('SeekBar', SeekBar);
|
||||
Component.registerComponent('SeekBar', SeekBar);
|
||||
export default SeekBar;
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import SliderHandle from '../../slider/slider-handle.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
|
||||
/**
|
||||
* The Seek Handle shows the current position of the playhead during playback,
|
||||
* and can be dragged to adjust the playhead.
|
||||
*
|
||||
* @param {Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
class SeekHandle extends SliderHandle {
|
||||
|
||||
constructor(player, options) {
|
||||
super(player, options);
|
||||
this.on(player, 'timeupdate', this.updateContent);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
createEl() {
|
||||
return super.createEl('div', {
|
||||
className: 'vjs-seek-handle',
|
||||
'aria-live': 'off'
|
||||
});
|
||||
}
|
||||
|
||||
updateContent() {
|
||||
let time = (this.player_.scrubbing) ? this.player_.getCache().currentTime : this.player_.currentTime();
|
||||
this.el_.innerHTML = `<span class="vjs-control-text">${Lib.formatTime(time, this.player_.duration())}</span>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value for the handle content, which may be read by screen readers
|
||||
*
|
||||
* @type {String}
|
||||
* @private
|
||||
*/
|
||||
SeekHandle.prototype.defaultValue = '00:00';
|
||||
|
||||
SliderHandle.registerComponent('SeekHandle', SeekHandle);
|
||||
export default SeekHandle;
|
||||
@@ -1,4 +1,5 @@
|
||||
import Spacer from './spacer.js';
|
||||
import Component from '../../component.js';
|
||||
|
||||
/**
|
||||
* Spacer specifically meant to be used as an insertion point for new plugins, etc.
|
||||
@@ -18,6 +19,5 @@ class CustomControlSpacer extends Spacer {
|
||||
}
|
||||
}
|
||||
|
||||
Spacer.registerComponent('CustomControlSpacer', CustomControlSpacer);
|
||||
|
||||
Component.registerComponent('CustomControlSpacer', CustomControlSpacer);
|
||||
export default CustomControlSpacer;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import TextTrackMenuItem from './text-track-menu-item.js';
|
||||
import Component from '../../component.js';
|
||||
|
||||
class CaptionSettingsMenuItem extends TextTrackMenuItem {
|
||||
|
||||
@@ -21,5 +22,5 @@ class CaptionSettingsMenuItem extends TextTrackMenuItem {
|
||||
|
||||
}
|
||||
|
||||
TextTrackMenuItem.registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem);
|
||||
Component.registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem);
|
||||
export default CaptionSettingsMenuItem;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import TextTrackButton from './text-track-button.js';
|
||||
import Component from '../../component.js';
|
||||
import CaptionSettingsMenuItem from './caption-settings-menu-item.js';
|
||||
|
||||
/**
|
||||
@@ -45,5 +46,5 @@ CaptionsButton.prototype.kind_ = 'captions';
|
||||
CaptionsButton.prototype.buttonText = 'Captions';
|
||||
CaptionsButton.prototype.className = 'vjs-captions-button';
|
||||
|
||||
TextTrackButton.registerComponent('CaptionsButton', CaptionsButton);
|
||||
Component.registerComponent('CaptionsButton', CaptionsButton);
|
||||
export default CaptionsButton;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import TextTrackButton from './text-track-button.js';
|
||||
import Component from '../../component.js';
|
||||
import TextTrackMenuItem from './text-track-menu-item.js';
|
||||
import ChaptersTrackMenuItem from './chapters-track-menu-item.js';
|
||||
import Menu from '../../menu/menu.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import * as Dom from '../../utils/dom.js';
|
||||
import * as Fn from '../../utils/fn.js';
|
||||
import toTitleCase from '../../utils/to-title-case.js';
|
||||
import window from 'global/window';
|
||||
|
||||
// Chapters act much differently than other text tracks
|
||||
@@ -48,12 +51,12 @@ class ChaptersButton extends TextTrackButton {
|
||||
|
||||
for (let i = 0, l = tracks.length; i < l; i++) {
|
||||
let track = tracks[i];
|
||||
if (track['kind'] == this.kind_) {
|
||||
if (track['kind'] === this.kind_) {
|
||||
if (!track.cues) {
|
||||
track['mode'] = 'hidden';
|
||||
/* jshint loopfunc:true */
|
||||
// TODO see if we can figure out a better way of doing this https://github.com/videojs/video.js/issues/1864
|
||||
window.setTimeout(Lib.bind(this, function() {
|
||||
window.setTimeout(Fn.bind(this, function() {
|
||||
this.createMenu();
|
||||
}), 100);
|
||||
/* jshint loopfunc:false */
|
||||
@@ -67,10 +70,10 @@ class ChaptersButton extends TextTrackButton {
|
||||
let menu = this.menu;
|
||||
if (menu === undefined) {
|
||||
menu = new Menu(this.player_);
|
||||
menu.contentEl().appendChild(Lib.createEl('li', {
|
||||
menu.contentEl().appendChild(Dom.createEl('li', {
|
||||
className: 'vjs-menu-title',
|
||||
innerHTML: Lib.capitalize(this.kind_),
|
||||
tabindex: -1
|
||||
innerHTML: toTitleCase(this.kind_),
|
||||
tabIndex: -1
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -105,5 +108,5 @@ ChaptersButton.prototype.kind_ = 'chapters';
|
||||
ChaptersButton.prototype.buttonText = 'Chapters';
|
||||
ChaptersButton.prototype.className = 'vjs-chapters-button';
|
||||
|
||||
TextTrackButton.registerComponent('ChaptersButton', ChaptersButton);
|
||||
Component.registerComponent('ChaptersButton', ChaptersButton);
|
||||
export default ChaptersButton;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import MenuItem from '../../menu/menu-item.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import Component from '../../component.js';
|
||||
import * as Fn from '../../utils/fn.js';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
@@ -18,7 +19,7 @@ class ChaptersTrackMenuItem extends MenuItem {
|
||||
|
||||
this.track = track;
|
||||
this.cue = cue;
|
||||
track.addEventListener('cuechange', Lib.bind(this, this.update));
|
||||
track.addEventListener('cuechange', Fn.bind(this, this.update));
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
@@ -37,5 +38,5 @@ class ChaptersTrackMenuItem extends MenuItem {
|
||||
|
||||
}
|
||||
|
||||
MenuItem.registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem);
|
||||
Component.registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem);
|
||||
export default ChaptersTrackMenuItem;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import TextTrackMenuItem from './text-track-menu-item.js';
|
||||
import Component from '../../component.js';
|
||||
|
||||
/**
|
||||
* A special menu item for turning of a specific type of text track
|
||||
@@ -39,5 +40,5 @@ class OffTextTrackMenuItem extends TextTrackMenuItem {
|
||||
|
||||
}
|
||||
|
||||
TextTrackMenuItem.registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem);
|
||||
export default OffTextTrackMenuItem;
|
||||
Component.registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem);
|
||||
export default OffTextTrackMenuItem;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import TextTrackButton from './text-track-button.js';
|
||||
import Component from '../../component.js';
|
||||
|
||||
/**
|
||||
* The button component for toggling and selecting subtitles
|
||||
@@ -18,5 +19,5 @@ SubtitlesButton.prototype.kind_ = 'subtitles';
|
||||
SubtitlesButton.prototype.buttonText = 'Subtitles';
|
||||
SubtitlesButton.prototype.className = 'vjs-subtitles-button';
|
||||
|
||||
TextTrackButton.registerComponent('SubtitlesButton', SubtitlesButton);
|
||||
export default SubtitlesButton;
|
||||
Component.registerComponent('SubtitlesButton', SubtitlesButton);
|
||||
export default SubtitlesButton;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import MenuButton from '../../menu/menu-button.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
|
||||
import Component from '../../component.js';
|
||||
import * as Fn from '../../utils/fn.js';
|
||||
import TextTrackMenuItem from './text-track-menu-item.js';
|
||||
import OffTextTrackMenuItem from './off-text-track-menu-item.js';
|
||||
|
||||
@@ -24,7 +24,7 @@ class TextTrackButton extends MenuButton {
|
||||
return;
|
||||
}
|
||||
|
||||
let updateHandler = Lib.bind(this, this.update);
|
||||
let updateHandler = Fn.bind(this, this.update);
|
||||
tracks.addEventListener('removetrack', updateHandler);
|
||||
tracks.addEventListener('addtrack', updateHandler);
|
||||
|
||||
@@ -61,5 +61,5 @@ class TextTrackButton extends MenuButton {
|
||||
|
||||
}
|
||||
|
||||
MenuButton.registerComponent('TextTrackButton', TextTrackButton);
|
||||
export default TextTrackButton;
|
||||
Component.registerComponent('TextTrackButton', TextTrackButton);
|
||||
export default TextTrackButton;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import MenuItem from '../../menu/menu-item.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
|
||||
import Component from '../../component.js';
|
||||
import * as Fn from '../../utils/fn.js';
|
||||
import window from 'global/window';
|
||||
import document from 'global/document';
|
||||
|
||||
@@ -23,7 +23,7 @@ class TextTrackMenuItem extends MenuItem {
|
||||
this.track = track;
|
||||
|
||||
if (tracks) {
|
||||
let changeHandler = Lib.bind(this, this.handleTracksChange);
|
||||
let changeHandler = Fn.bind(this, this.handleTracksChange);
|
||||
|
||||
tracks.addEventListener('change', changeHandler);
|
||||
this.on('dispose', function() {
|
||||
@@ -87,5 +87,5 @@ class TextTrackMenuItem extends MenuItem {
|
||||
|
||||
}
|
||||
|
||||
MenuItem.registerComponent('TextTrackMenuItem', TextTrackMenuItem);
|
||||
Component.registerComponent('TextTrackMenuItem', TextTrackMenuItem);
|
||||
export default TextTrackMenuItem;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Component from '../../component.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import * as Dom from '../../utils/dom.js';
|
||||
import formatTime from '../../utils/format-time.js';
|
||||
|
||||
/**
|
||||
* Displays the current time
|
||||
@@ -20,7 +21,7 @@ class CurrentTimeDisplay extends Component {
|
||||
className: 'vjs-current-time vjs-time-control vjs-control'
|
||||
});
|
||||
|
||||
this.contentEl_ = Lib.createEl('div', {
|
||||
this.contentEl_ = Dom.createEl('div', {
|
||||
className: 'vjs-current-time-display',
|
||||
innerHTML: '<span class="vjs-control-text">Current Time </span>' + '0:00', // label the current time for screen reader users
|
||||
'aria-live': 'off' // tell screen readers not to automatically read the time as it changes
|
||||
@@ -34,7 +35,7 @@ class CurrentTimeDisplay extends Component {
|
||||
// Allows for smooth scrubbing, when player can't keep up.
|
||||
let time = (this.player_.scrubbing) ? this.player_.getCache().currentTime : this.player_.currentTime();
|
||||
let localizedText = this.localize('Current Time');
|
||||
let formattedTime = Lib.formatTime(time, this.player_.duration());
|
||||
let formattedTime = formatTime(time, this.player_.duration());
|
||||
this.contentEl_.innerHTML = `<span class="vjs-control-text">${localizedText}</span> ${formattedTime}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Component from '../../component.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import * as Dom from '../../utils/dom.js';
|
||||
import formatTime from '../../utils/format-time.js';
|
||||
|
||||
/**
|
||||
* Displays the duration
|
||||
@@ -25,7 +26,7 @@ class DurationDisplay extends Component {
|
||||
className: 'vjs-duration vjs-time-control vjs-control'
|
||||
});
|
||||
|
||||
this.contentEl_ = Lib.createEl('div', {
|
||||
this.contentEl_ = Dom.createEl('div', {
|
||||
className: 'vjs-duration-display',
|
||||
innerHTML: `<span class="vjs-control-text">${this.localize('Duration Time')}</span> 0:00`, // label the duration time for screen reader users
|
||||
'aria-live': 'off' // tell screen readers not to automatically read the time as it changes
|
||||
@@ -39,7 +40,7 @@ class DurationDisplay extends Component {
|
||||
let duration = this.player_.duration();
|
||||
if (duration) {
|
||||
let localizedText = this.localize('Duration Time');
|
||||
let formattedTime = Lib.formatTime(duration);
|
||||
let formattedTime = formatTime(duration);
|
||||
this.contentEl_.innerHTML = `<span class="vjs-control-text">${localizedText}</span> ${formattedTime}`; // label the duration time for screen reader users
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Component from '../../component.js';
|
||||
import * as Lib from '../../lib';
|
||||
import * as Dom from '../../utils/dom.js';
|
||||
import formatTime from '../../utils/format-time.js';
|
||||
|
||||
/**
|
||||
* Displays the time left in the video
|
||||
@@ -20,7 +21,7 @@ class RemainingTimeDisplay extends Component {
|
||||
className: 'vjs-remaining-time vjs-time-control vjs-control'
|
||||
});
|
||||
|
||||
this.contentEl_ = Lib.createEl('div', {
|
||||
this.contentEl_ = Dom.createEl('div', {
|
||||
className: 'vjs-remaining-time-display',
|
||||
innerHTML: `<span class="vjs-control-text">${this.localize('Remaining Time')}</span> -0:00`, // label the remaining time for screen reader users
|
||||
'aria-live': 'off' // tell screen readers not to automatically read the time as it changes
|
||||
@@ -33,7 +34,7 @@ class RemainingTimeDisplay extends Component {
|
||||
updateContent() {
|
||||
if (this.player_.duration()) {
|
||||
const localizedText = this.localize('Remaining Time');
|
||||
const formattedTime = Lib.formatTime(this.player_.remainingTime());
|
||||
const formattedTime = formatTime(this.player_.remainingTime());
|
||||
this.contentEl_.innerHTML = `<span class="vjs-control-text">${localizedText}</span> -${formattedTime}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import Slider from '../../slider/slider.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
import Component from '../../component.js';
|
||||
import * as Fn from '../../utils/fn.js';
|
||||
import roundFloat from '../../utils/round-float.js';
|
||||
|
||||
// Required children
|
||||
import VolumeHandle from './volume-handle.js';
|
||||
import VolumeLevel from './volume-level.js';
|
||||
|
||||
/**
|
||||
@@ -17,7 +18,7 @@ class VolumeBar extends Slider {
|
||||
constructor(player, options){
|
||||
super(player, options);
|
||||
this.on(player, 'volumechange', this.updateARIAAttributes);
|
||||
player.ready(Lib.bind(this, this.updateARIAAttributes));
|
||||
player.ready(Fn.bind(this, this.updateARIAAttributes));
|
||||
}
|
||||
|
||||
createEl() {
|
||||
@@ -53,22 +54,20 @@ class VolumeBar extends Slider {
|
||||
|
||||
updateARIAAttributes() {
|
||||
// Current value of volume bar as a percentage
|
||||
this.el_.setAttribute('aria-valuenow', Lib.round(this.player_.volume()*100, 2));
|
||||
this.el_.setAttribute('aria-valuetext', Lib.round(this.player_.volume()*100, 2)+'%');
|
||||
this.el_.setAttribute('aria-valuenow', roundFloat(this.player_.volume()*100, 2));
|
||||
this.el_.setAttribute('aria-valuetext', roundFloat(this.player_.volume()*100, 2)+'%');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VolumeBar.prototype.options_ = {
|
||||
children: {
|
||||
'volumeLevel': {},
|
||||
'volumeHandle': {}
|
||||
'volumeLevel': {}
|
||||
},
|
||||
'barName': 'volumeLevel',
|
||||
'handleName': 'volumeHandle'
|
||||
'barName': 'volumeLevel'
|
||||
};
|
||||
|
||||
VolumeBar.prototype.playerEvent = 'volumechange';
|
||||
|
||||
Slider.registerComponent('VolumeBar', VolumeBar);
|
||||
Component.registerComponent('VolumeBar', VolumeBar);
|
||||
export default VolumeBar;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Component from '../../component.js';
|
||||
import * as Lib from '../../lib.js';
|
||||
|
||||
// Required children
|
||||
import VolumeBar from './volume-bar.js';
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import SliderHandle from '../../slider/slider-handle.js';
|
||||
|
||||
/**
|
||||
* The volume handle can be dragged to adjust the volume level
|
||||
*
|
||||
* @param {Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
class VolumeHandle extends SliderHandle {
|
||||
|
||||
/** @inheritDoc */
|
||||
createEl() {
|
||||
return super.createEl('div', {
|
||||
className: 'vjs-volume-handle'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VolumeHandle.prototype.defaultValue = '00:00';
|
||||
|
||||
SliderHandle.registerComponent('VolumeHandle', VolumeHandle);
|
||||
export default VolumeHandle;
|
||||
@@ -1,8 +1,8 @@
|
||||
import Button from '../button.js';
|
||||
import Component from '../component.js';
|
||||
import Menu from '../menu/menu.js';
|
||||
import MenuButton from '../menu/menu-button.js';
|
||||
import MuteToggle from './mute-toggle.js';
|
||||
import * as Lib from '../lib.js';
|
||||
import VolumeBar from './volume-control/volume-bar.js';
|
||||
|
||||
/**
|
||||
@@ -68,5 +68,5 @@ class VolumeMenuButton extends MenuButton {
|
||||
|
||||
VolumeMenuButton.prototype.volumeUpdate = MuteToggle.prototype.update;
|
||||
|
||||
Button.registerComponent('VolumeMenuButton', VolumeMenuButton);
|
||||
Component.registerComponent('VolumeMenuButton', VolumeMenuButton);
|
||||
export default VolumeMenuButton;
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
import * as Lib from './lib';
|
||||
|
||||
/**
|
||||
* Core Object/Class for objects that use inheritance + constructors
|
||||
*
|
||||
* To create a class that can be subclassed itself, extend the CoreObject class.
|
||||
*
|
||||
* var Animal = CoreObject.extend();
|
||||
* var Horse = Animal.extend();
|
||||
*
|
||||
* The constructor can be defined through the init property of an object argument.
|
||||
*
|
||||
* var Animal = CoreObject.extend({
|
||||
* init: function(name, sound){
|
||||
* this.name = name;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Other methods and properties can be added the same way, or directly to the
|
||||
* prototype.
|
||||
*
|
||||
* var Animal = CoreObject.extend({
|
||||
* init: function(name){
|
||||
* this.name = name;
|
||||
* },
|
||||
* getName: function(){
|
||||
* return this.name;
|
||||
* },
|
||||
* sound: '...'
|
||||
* });
|
||||
*
|
||||
* Animal.prototype.makeSound = function(){
|
||||
* alert(this.sound);
|
||||
* };
|
||||
*
|
||||
* To create an instance of a class, use the create method.
|
||||
*
|
||||
* var fluffy = Animal.create('Fluffy');
|
||||
* fluffy.getName(); // -> Fluffy
|
||||
*
|
||||
* Methods and properties can be overridden in subclasses.
|
||||
*
|
||||
* var Horse = Animal.extend({
|
||||
* sound: 'Neighhhhh!'
|
||||
* });
|
||||
*
|
||||
* var horsey = Horse.create('Horsey');
|
||||
* horsey.getName(); // -> Horsey
|
||||
* horsey.makeSound(); // -> Alert: Neighhhhh!
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
*/
|
||||
var CoreObject = function(){};
|
||||
// Manually exporting vjs['CoreObject'] here for Closure Compiler
|
||||
// because of the use of the extend/create class methods
|
||||
// If we didn't do this, those functions would get flattened to something like
|
||||
// `a = ...` and `this.prototype` would refer to the global object instead of
|
||||
// CoreObject
|
||||
|
||||
/**
|
||||
* Create a new object that inherits from this Object
|
||||
*
|
||||
* var Animal = CoreObject.extend();
|
||||
* var Horse = Animal.extend();
|
||||
*
|
||||
* @param {Object} props Functions and properties to be applied to the
|
||||
* new object's prototype
|
||||
* @return {CoreObject} An object that inherits from CoreObject
|
||||
* @this {*}
|
||||
*/
|
||||
CoreObject.extend = function(props={}){
|
||||
// Set up the constructor using the supplied init method
|
||||
// or using the init of the parent object
|
||||
// Make sure to check the unobfuscated version for external libs
|
||||
let init = props['init'] || props.init || this.prototype['init'] || this.prototype.init || function(){};
|
||||
// In Resig's simple class inheritance (previously used) the constructor
|
||||
// is a function that calls `this.init.apply(arguments)`
|
||||
// However that would prevent us from using `ParentObject.call(this);`
|
||||
// in a Child constructor because the `this` in `this.init`
|
||||
// would still refer to the Child and cause an infinite loop.
|
||||
// We would instead have to do
|
||||
// `ParentObject.prototype.init.apply(this, arguments);`
|
||||
// Bleh. We're not creating a _super() function, so it's good to keep
|
||||
// the parent constructor reference simple.
|
||||
let subObj = function(){
|
||||
init.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Inherit from this object's prototype
|
||||
subObj.prototype = Lib.obj.create(this.prototype);
|
||||
// Reset the constructor property for subObj otherwise
|
||||
// instances of subObj would have the constructor of the parent Object
|
||||
subObj.prototype.constructor = subObj;
|
||||
|
||||
// Make the class extendable
|
||||
subObj.extend = CoreObject.extend;
|
||||
// Make a function for creating instances
|
||||
subObj.create = CoreObject.create;
|
||||
|
||||
// Extend subObj's prototype with functions and other properties from props
|
||||
for (var name in props) {
|
||||
if (props.hasOwnProperty(name)) {
|
||||
subObj.prototype[name] = props[name];
|
||||
}
|
||||
}
|
||||
|
||||
return subObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new instance of this Object class
|
||||
*
|
||||
* var myAnimal = Animal.create();
|
||||
*
|
||||
* @return {CoreObject} An instance of a CoreObject subclass
|
||||
* @this {*}
|
||||
*/
|
||||
CoreObject.create = function(){
|
||||
// Create a new object that inherits from this object's prototype
|
||||
var inst = Lib.obj.create(this.prototype);
|
||||
|
||||
// Apply this constructor function to the new object
|
||||
this.apply(inst, arguments);
|
||||
|
||||
// Return the new object
|
||||
return inst;
|
||||
};
|
||||
|
||||
export default CoreObject;
|
||||
@@ -1,125 +0,0 @@
|
||||
/**
|
||||
* @fileoverview Main function src.
|
||||
*/
|
||||
|
||||
import Player from './player';
|
||||
import Plugins from './plugins';
|
||||
import Options from './options';
|
||||
import * as Lib from './lib';
|
||||
import * as VjsUtil from './util';
|
||||
import CoreObject from './core-object';
|
||||
import document from 'global/document';
|
||||
|
||||
/**
|
||||
* Doubles as the main function for users to create a player instance and also
|
||||
* the main library object.
|
||||
*
|
||||
* **ALIASES** videojs, _V_ (deprecated)
|
||||
*
|
||||
* The `vjs` function can be used to initialize or retrieve a player.
|
||||
*
|
||||
* var myPlayer = vjs('my_video_id');
|
||||
*
|
||||
* @param {String|Element} id Video element or video element ID
|
||||
* @param {Object=} options Optional options object for config/settings
|
||||
* @param {Function=} ready Optional ready callback
|
||||
* @return {Player} A player instance
|
||||
* @namespace
|
||||
*/
|
||||
var videojs = function(id, options, ready){
|
||||
var tag; // Element of ID
|
||||
|
||||
// Allow for element or ID to be passed in
|
||||
// String ID
|
||||
if (typeof id === 'string') {
|
||||
|
||||
// Adjust for jQuery ID syntax
|
||||
if (id.indexOf('#') === 0) {
|
||||
id = id.slice(1);
|
||||
}
|
||||
|
||||
// If a player instance has already been created for this ID return it.
|
||||
if (Player.players[id]) {
|
||||
|
||||
// If options or ready funtion are passed, warn
|
||||
if (options) {
|
||||
Lib.log.warn(`Player "${id}" is already initialised. Options will not be applied.`);
|
||||
}
|
||||
|
||||
if (ready) {
|
||||
Player.players[id].ready(ready);
|
||||
}
|
||||
|
||||
return Player.players[id];
|
||||
|
||||
// Otherwise get element for ID
|
||||
} else {
|
||||
tag = Lib.el(id);
|
||||
}
|
||||
|
||||
// ID is a media element
|
||||
} else {
|
||||
tag = id;
|
||||
}
|
||||
|
||||
// Check for a useable element
|
||||
if (!tag || !tag.nodeName) { // re: nodeName, could be a box div also
|
||||
throw new TypeError('The element or ID supplied is not valid. (videojs)'); // Returns
|
||||
}
|
||||
|
||||
// Element may have a player attr referring to an already created player instance.
|
||||
// If not, set up a new player and return the instance.
|
||||
return tag['player'] || new Player(tag, options, ready);
|
||||
};
|
||||
|
||||
// CDN Version. Used to target right flash swf.
|
||||
videojs.CDN_VERSION = '__VERSION_NO_PATCH__';
|
||||
videojs.ACCESS_PROTOCOL = ('https:' == document.location.protocol ? 'https://' : 'http://');
|
||||
|
||||
/**
|
||||
* Full player version
|
||||
* @type {string}
|
||||
*/
|
||||
videojs['VERSION'] = '__VERSION__';
|
||||
|
||||
// Set CDN Version of swf
|
||||
// The added (+) blocks the replace from changing this _VERSION_NO_PATCH_ string
|
||||
if (videojs.CDN_VERSION !== '__VERSION_'+'NO_PATCH__') {
|
||||
Options['flash']['swf'] = `${videojs.ACCESS_PROTOCOL}vjs.zencdn.net/${videojs.CDN_VERSION}/video-js.swf`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for adding languages to the default options. Useful for
|
||||
* amending multiple language support at runtime.
|
||||
*
|
||||
* Example: videojs.addLanguage('es', {'Hello':'Hola'});
|
||||
*
|
||||
* @param {String} code The language code or dictionary property
|
||||
* @param {Object} data The data values to be translated
|
||||
* @return {Object} The resulting global languages dictionary object
|
||||
*/
|
||||
videojs.addLanguage = function(code, data){
|
||||
if(Options['languages'][code] !== undefined) {
|
||||
Options['languages'][code] = VjsUtil.mergeOptions(Options['languages'][code], data);
|
||||
} else {
|
||||
Options['languages'][code] = data;
|
||||
}
|
||||
return Options['languages'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom Universal Module Definition (UMD)
|
||||
*
|
||||
* Video.js will never be a non-browser lib so we can simplify UMD a bunch and
|
||||
* still support requirejs and browserify. This also needs to be closure
|
||||
* compiler compatible, so string keys are used.
|
||||
*/
|
||||
if (typeof define === 'function' && define['amd']) {
|
||||
define('videojs', [], function(){ return videojs; });
|
||||
|
||||
// checking that module is an object too because of umdjs/umd#35
|
||||
} else if (typeof exports === 'object' && typeof module === 'object') {
|
||||
module['exports'] = videojs;
|
||||
}
|
||||
|
||||
export default videojs;
|
||||
@@ -1,5 +1,5 @@
|
||||
import Component from './component';
|
||||
import * as Lib from './lib';
|
||||
import * as Dom from './utils/dom.js';
|
||||
|
||||
/**
|
||||
* Display that an error has occurred making the video unplayable
|
||||
@@ -21,7 +21,7 @@ class ErrorDisplay extends Component {
|
||||
className: 'vjs-error-display'
|
||||
});
|
||||
|
||||
this.contentEl_ = Lib.createEl('div');
|
||||
this.contentEl_ = Dom.createEl('div');
|
||||
el.appendChild(this.contentEl_);
|
||||
|
||||
return el;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as Events from './events';
|
||||
import * as Lib from './lib';
|
||||
import * as Events from './utils/events.js';
|
||||
|
||||
var EventEmitter = function() {};
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import * as Lib from './lib';
|
||||
|
||||
/**
|
||||
* A combination of node inherits and babel's inherits (after transpile).
|
||||
* Both work the same but node adds `super_` to the subClass
|
||||
|
||||
@@ -17,9 +17,6 @@ export default {
|
||||
'html5': {},
|
||||
'flash': {},
|
||||
|
||||
// Default of web browser is 300x150. Should rely on source width/height.
|
||||
'width': 300,
|
||||
'height': 150,
|
||||
// defaultVolume: 0.85,
|
||||
'defaultVolume': 0.00, // The freakin seaguls are driving me crazy!
|
||||
|
||||
-901
@@ -1,901 +0,0 @@
|
||||
import window from 'global/window';
|
||||
import document from 'global/document';
|
||||
let navigator = window.navigator;
|
||||
|
||||
let hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* Creates an element and applies properties.
|
||||
* @param {String=} tagName Name of tag to be created.
|
||||
* @param {Object=} properties Element properties to be applied.
|
||||
* @return {Element}
|
||||
* @private
|
||||
*/
|
||||
var createEl = function(tagName='div', properties={}){
|
||||
let el = document.createElement(tagName);
|
||||
|
||||
obj.each(properties, function(propName, val){
|
||||
// Not remembering why we were checking for dash
|
||||
// but using setAttribute means you have to use getAttribute
|
||||
|
||||
// The check for dash checks for the aria-* attributes, like aria-label, aria-valuemin.
|
||||
// The additional check for "role" is because the default method for adding attributes does not
|
||||
// add the attribute "role". My guess is because it's not a valid attribute in some namespaces, although
|
||||
// browsers handle the attribute just fine. The W3C allows for aria-* attributes to be used in pre-HTML5 docs.
|
||||
// http://www.w3.org/TR/wai-aria-primer/#ariahtml. Using setAttribute gets around this problem.
|
||||
if (propName.indexOf('aria-') !== -1 || propName == 'role') {
|
||||
el.setAttribute(propName, val);
|
||||
} else {
|
||||
el[propName] = val;
|
||||
}
|
||||
});
|
||||
|
||||
return el;
|
||||
};
|
||||
|
||||
/**
|
||||
* Uppercase the first letter of a string
|
||||
* @param {String} string String to be uppercased
|
||||
* @return {String}
|
||||
* @private
|
||||
*/
|
||||
var capitalize = function(string){
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Object functions container
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
var obj = {};
|
||||
|
||||
/**
|
||||
* Object.create shim for prototypal inheritance
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
|
||||
*
|
||||
* @function
|
||||
* @param {Object} obj Object to use as prototype
|
||||
* @private
|
||||
*/
|
||||
obj.create = Object.create || function(obj){
|
||||
//Create a new function called 'F' which is just an empty object.
|
||||
function F() {}
|
||||
|
||||
//the prototype of the 'F' function should point to the
|
||||
//parameter of the anonymous function.
|
||||
F.prototype = obj;
|
||||
|
||||
//create a new constructor function based off of the 'F' function.
|
||||
return new F();
|
||||
};
|
||||
|
||||
/**
|
||||
* Loop through each property in an object and call a function
|
||||
* whose arguments are (key,value)
|
||||
* @param {Object} obj Object of properties
|
||||
* @param {Function} fn Function to be called on each property.
|
||||
* @this {*}
|
||||
* @private
|
||||
*/
|
||||
obj.each = function(obj, fn, context){
|
||||
for (var key in obj) {
|
||||
if (hasOwnProp.call(obj, key)) {
|
||||
fn.call(context || this, key, obj[key]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge two objects together and return the original.
|
||||
* @param {Object} obj1
|
||||
* @param {Object} obj2
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
obj.merge = function(obj1, obj2){
|
||||
if (!obj2) { return obj1; }
|
||||
for (var key in obj2){
|
||||
if (hasOwnProp.call(obj2, key)) {
|
||||
obj1[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
return obj1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge two objects, and merge any properties that are objects
|
||||
* instead of just overwriting one. Uses to merge options hashes
|
||||
* where deeper default settings are important.
|
||||
* @param {Object} obj1 Object to override
|
||||
* @param {Object} obj2 Overriding object
|
||||
* @return {Object} New object. Obj1 and Obj2 will be untouched.
|
||||
* @private
|
||||
*/
|
||||
obj.deepMerge = function(obj1, obj2){
|
||||
var key, val1, val2;
|
||||
|
||||
// make a copy of obj1 so we're not overwriting original values.
|
||||
// like prototype.options_ and all sub options objects
|
||||
obj1 = obj.copy(obj1);
|
||||
|
||||
for (key in obj2){
|
||||
if (hasOwnProp.call(obj2, key)) {
|
||||
val1 = obj1[key];
|
||||
val2 = obj2[key];
|
||||
|
||||
// Check if both properties are pure objects and do a deep merge if so
|
||||
if (obj.isPlain(val1) && obj.isPlain(val2)) {
|
||||
obj1[key] = obj.deepMerge(val1, val2);
|
||||
} else {
|
||||
obj1[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a copy of the supplied object
|
||||
* @param {Object} obj Object to copy
|
||||
* @return {Object} Copy of object
|
||||
* @private
|
||||
*/
|
||||
obj.copy = function(objToCopy){
|
||||
return obj.merge({}, objToCopy);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an object is plain, and not a dom node or any object sub-instance
|
||||
* @param {Object} obj Object to check
|
||||
* @return {Boolean} True if plain, false otherwise
|
||||
* @private
|
||||
*/
|
||||
obj.isPlain = function(obj){
|
||||
return !!obj
|
||||
&& typeof obj === 'object'
|
||||
&& obj.toString() === '[object Object]'
|
||||
&& obj.constructor === Object;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an object is Array
|
||||
* Since instanceof Array will not work on arrays created in another frame we need to use Array.isArray, but since IE8 does not support Array.isArray we need this shim
|
||||
* @param {Object} obj Object to check
|
||||
* @return {Boolean} True if plain, false otherwise
|
||||
* @private
|
||||
*/
|
||||
obj.isArray = Array.isArray || function(arr) {
|
||||
return Object.prototype.toString.call(arr) === '[object Array]';
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind (a.k.a proxy or Context). A simple method for changing the context of a function
|
||||
It also stores a unique id on the function so it can be easily removed from events
|
||||
* @param {*} context The object to bind as scope
|
||||
* @param {Function} fn The function to be bound to a scope
|
||||
* @param {Number=} uid An optional unique ID for the function to be set
|
||||
* @return {Function}
|
||||
* @private
|
||||
*/
|
||||
var bind = function(context, fn, uid) {
|
||||
// Make sure the function has a unique ID
|
||||
if (!fn.guid) { fn.guid = guid++; }
|
||||
|
||||
// Create the new function that changes the context
|
||||
let ret = function() {
|
||||
return fn.apply(context, arguments);
|
||||
};
|
||||
|
||||
// Allow for the ability to individualize this function
|
||||
// Needed in the case where multiple objects might share the same prototype
|
||||
// IF both items add an event listener with the same function, then you try to remove just one
|
||||
// it will remove both because they both have the same guid.
|
||||
// when using this, you need to use the bind method when you remove the listener as well.
|
||||
// currently used in text tracks
|
||||
ret.guid = (uid) ? uid + '_' + fn.guid : fn.guid;
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Element Data Store. Allows for binding data to an element without putting it directly on the element.
|
||||
* Ex. Event listeners are stored here.
|
||||
* (also from jsninja.com, slightly modified and updated for closure compiler)
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Unique ID for an element or function
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
var guid = 1;
|
||||
|
||||
/**
|
||||
* Unique attribute name to store an element's guid in
|
||||
* @type {String}
|
||||
* @constant
|
||||
* @private
|
||||
*/
|
||||
var expando = 'vdata' + (new Date()).getTime();
|
||||
|
||||
/**
|
||||
* Returns the cache object where data for an element is stored
|
||||
* @param {Element} el Element to store data for.
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var getData = function(el){
|
||||
var id = el[expando];
|
||||
if (!id) {
|
||||
id = el[expando] = guid++;
|
||||
}
|
||||
if (!cache[id]) {
|
||||
cache[id] = {};
|
||||
}
|
||||
return cache[id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the cache object where data for an element is stored
|
||||
* @param {Element} el Element to store data for.
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var hasData = function(el){
|
||||
var id = el[expando];
|
||||
return !(!id || isEmpty(cache[id]));
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete data for the element from the cache and the guid attr from getElementById
|
||||
* @param {Element} el Remove data for an element
|
||||
* @private
|
||||
*/
|
||||
var removeData = function(el){
|
||||
var id = el[expando];
|
||||
if (!id) { return; }
|
||||
// Remove all stored data
|
||||
// Changed to = null
|
||||
// http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
|
||||
// cache[id] = null;
|
||||
delete cache[id];
|
||||
|
||||
// Remove the expando property from the DOM node
|
||||
try {
|
||||
delete el[expando];
|
||||
} catch(e) {
|
||||
if (el.removeAttribute) {
|
||||
el.removeAttribute(expando);
|
||||
} else {
|
||||
// IE doesn't appear to support removeAttribute on the document element
|
||||
el[expando] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an object is empty
|
||||
* @param {Object} obj The object to check for emptiness
|
||||
* @return {Boolean}
|
||||
* @private
|
||||
*/
|
||||
var isEmpty = function(obj) {
|
||||
for (var prop in obj) {
|
||||
// Inlude null properties as empty.
|
||||
if (obj[prop] !== null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an element has a CSS class
|
||||
* @param {Element} element Element to check
|
||||
* @param {String} classToCheck Classname to check
|
||||
* @private
|
||||
*/
|
||||
var hasClass = function(element, classToCheck){
|
||||
return ((' ' + element.className + ' ').indexOf(' ' + classToCheck + ' ') !== -1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a CSS class name to an element
|
||||
* @param {Element} element Element to add class name to
|
||||
* @param {String} classToAdd Classname to add
|
||||
* @private
|
||||
*/
|
||||
var addClass = function(element, classToAdd){
|
||||
if (!hasClass(element, classToAdd)) {
|
||||
element.className = element.className === '' ? classToAdd : element.className + ' ' + classToAdd;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a CSS class name from an element
|
||||
* @param {Element} element Element to remove from class name
|
||||
* @param {String} classToAdd Classname to remove
|
||||
* @private
|
||||
*/
|
||||
var removeClass = function(element, classToRemove){
|
||||
if (!hasClass(element, classToRemove)) {return;}
|
||||
|
||||
let classNames = element.className.split(' ');
|
||||
|
||||
// no arr.indexOf in ie8, and we don't want to add a big shim
|
||||
for (let i = classNames.length - 1; i >= 0; i--) {
|
||||
if (classNames[i] === classToRemove) {
|
||||
classNames.splice(i,1);
|
||||
}
|
||||
}
|
||||
|
||||
element.className = classNames.join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Element for testing browser HTML5 video capabilities
|
||||
* @type {Element}
|
||||
* @constant
|
||||
* @private
|
||||
*/
|
||||
var TEST_VID = createEl('video');
|
||||
let track = document.createElement('track');
|
||||
track.kind = 'captions';
|
||||
track.srclang = 'en';
|
||||
track.label = 'English';
|
||||
TEST_VID.appendChild(track);
|
||||
|
||||
/**
|
||||
* Useragent for browser testing.
|
||||
* @type {String}
|
||||
* @constant
|
||||
* @private
|
||||
*/
|
||||
var USER_AGENT = navigator.userAgent;
|
||||
|
||||
/**
|
||||
* Device is an iPhone
|
||||
* @type {Boolean}
|
||||
* @constant
|
||||
* @private
|
||||
*/
|
||||
var IS_IPHONE = (/iPhone/i).test(USER_AGENT);
|
||||
var IS_IPAD = (/iPad/i).test(USER_AGENT);
|
||||
var IS_IPOD = (/iPod/i).test(USER_AGENT);
|
||||
var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;
|
||||
|
||||
var IOS_VERSION = (function(){
|
||||
var match = USER_AGENT.match(/OS (\d+)_/i);
|
||||
if (match && match[1]) { return match[1]; }
|
||||
})();
|
||||
|
||||
var IS_ANDROID = (/Android/i).test(USER_AGENT);
|
||||
var ANDROID_VERSION = (function() {
|
||||
// This matches Android Major.Minor.Patch versions
|
||||
// ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
|
||||
var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i),
|
||||
major,
|
||||
minor;
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
major = match[1] && parseFloat(match[1]);
|
||||
minor = match[2] && parseFloat(match[2]);
|
||||
|
||||
if (major && minor) {
|
||||
return parseFloat(match[1] + '.' + match[2]);
|
||||
} else if (major) {
|
||||
return major;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
// Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser
|
||||
var IS_OLD_ANDROID = IS_ANDROID && (/webkit/i).test(USER_AGENT) && ANDROID_VERSION < 2.3;
|
||||
|
||||
var IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
|
||||
var IS_CHROME = (/Chrome/i).test(USER_AGENT);
|
||||
var IS_IE8 = (/MSIE\s8\.0/).test(USER_AGENT);
|
||||
|
||||
var TOUCH_ENABLED = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
|
||||
var BACKGROUND_SIZE_SUPPORTED = 'backgroundSize' in TEST_VID.style;
|
||||
|
||||
/**
|
||||
* Apply attributes to an HTML element.
|
||||
* @param {Element} el Target element.
|
||||
* @param {Object=} attributes Element attributes to be applied.
|
||||
* @private
|
||||
*/
|
||||
var setElementAttributes = function(el, attributes){
|
||||
obj.each(attributes, function(attrName, attrValue) {
|
||||
if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
|
||||
el.removeAttribute(attrName);
|
||||
} else {
|
||||
el.setAttribute(attrName, (attrValue === true ? '' : attrValue));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an element's attribute values, as defined on the HTML tag
|
||||
* Attributes are not the same as properties. They're defined on the tag
|
||||
* or with setAttribute (which shouldn't be used with HTML)
|
||||
* This will return true or false for boolean attributes.
|
||||
* @param {Element} tag Element from which to get tag attributes
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var getElementAttributes = function(tag){
|
||||
var obj, knownBooleans, attrs, attrName, attrVal;
|
||||
|
||||
obj = {};
|
||||
|
||||
// known boolean attributes
|
||||
// we can check for matching boolean properties, but older browsers
|
||||
// won't know about HTML5 boolean attributes that we still read from
|
||||
knownBooleans = ','+'autoplay,controls,loop,muted,default'+',';
|
||||
|
||||
if (tag && tag.attributes && tag.attributes.length > 0) {
|
||||
attrs = tag.attributes;
|
||||
|
||||
for (var i = attrs.length - 1; i >= 0; i--) {
|
||||
attrName = attrs[i].name;
|
||||
attrVal = attrs[i].value;
|
||||
|
||||
// check for known booleans
|
||||
// the matching element property will return a value for typeof
|
||||
if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(','+attrName+',') !== -1) {
|
||||
// the value of an included boolean attribute is typically an empty
|
||||
// string ('') which would equal false if we just check for a false value.
|
||||
// we also don't want support bad code like autoplay='false'
|
||||
attrVal = (attrVal !== null) ? true : false;
|
||||
}
|
||||
|
||||
obj[attrName] = attrVal;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the computed style value for an element
|
||||
* From http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
|
||||
* @param {Element} el Element to get style value for
|
||||
* @param {String} strCssRule Style name
|
||||
* @return {String} Style value
|
||||
* @private
|
||||
*/
|
||||
var getComputedDimension = function(el, strCssRule){
|
||||
var strValue = '';
|
||||
if(document.defaultView && document.defaultView.getComputedStyle){
|
||||
strValue = document.defaultView.getComputedStyle(el, '').getPropertyValue(strCssRule);
|
||||
|
||||
} else if(el.currentStyle){
|
||||
// IE8 Width/Height support
|
||||
let upperCasedRule = strCssRule.substr(0,1).toUpperCase() + strCssRule.substr(1);
|
||||
strValue = el[`client${upperCasedRule}`] + 'px';
|
||||
}
|
||||
return strValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert an element as the first child node of another
|
||||
* @param {Element} child Element to insert
|
||||
* @param {[type]} parent Element to insert child into
|
||||
* @private
|
||||
*/
|
||||
var insertFirst = function(child, parent){
|
||||
if (parent.firstChild) {
|
||||
parent.insertBefore(child, parent.firstChild);
|
||||
} else {
|
||||
parent.appendChild(child);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Object to hold browser support information
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
var browser = {};
|
||||
|
||||
/**
|
||||
* Shorthand for document.getElementById()
|
||||
* Also allows for CSS (jQuery) ID syntax. But nothing other than IDs.
|
||||
* @param {String} id Element ID
|
||||
* @return {Element} Element with supplied ID
|
||||
* @private
|
||||
*/
|
||||
var el = function(id){
|
||||
if (id.indexOf('#') === 0) {
|
||||
id = id.slice(1);
|
||||
}
|
||||
|
||||
return document.getElementById(id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Format seconds as a time string, H:MM:SS or M:SS
|
||||
* Supplying a guide (in seconds) will force a number of leading zeros
|
||||
* to cover the length of the guide
|
||||
* @param {Number} seconds Number of seconds to be turned into a string
|
||||
* @param {Number} guide Number (in seconds) to model the string after
|
||||
* @return {String} Time formatted as H:MM:SS or M:SS
|
||||
* @private
|
||||
*/
|
||||
var formatTime = function(seconds, guide=seconds) {
|
||||
let s = Math.floor(seconds % 60);
|
||||
let m = Math.floor(seconds / 60 % 60);
|
||||
let h = Math.floor(seconds / 3600);
|
||||
const gm = Math.floor(guide / 60 % 60);
|
||||
const gh = Math.floor(guide / 3600);
|
||||
|
||||
// handle invalid times
|
||||
if (isNaN(seconds) || seconds === Infinity) {
|
||||
// '-' is false for all relational operators (e.g. <, >=) so this setting
|
||||
// will add the minimum number of fields specified by the guide
|
||||
h = m = s = '-';
|
||||
}
|
||||
|
||||
// Check if we need to show hours
|
||||
h = (h > 0 || gh > 0) ? h + ':' : '';
|
||||
|
||||
// If hours are showing, we may need to add a leading zero.
|
||||
// Always show at least one digit of minutes.
|
||||
m = (((h || gm >= 10) && m < 10) ? '0' + m : m) + ':';
|
||||
|
||||
// Check if leading zero is need for seconds
|
||||
s = (s < 10) ? '0' + s : s;
|
||||
|
||||
return h + m + s;
|
||||
};
|
||||
|
||||
// Attempt to block the ability to select text while dragging controls
|
||||
var blockTextSelection = function(){
|
||||
document.body.focus();
|
||||
document.onselectstart = function () { return false; };
|
||||
};
|
||||
// Turn off text selection blocking
|
||||
var unblockTextSelection = function(){ document.onselectstart = function () { return true; }; };
|
||||
|
||||
/**
|
||||
* Trim whitespace from the ends of a string.
|
||||
* @param {String} string String to trim
|
||||
* @return {String} Trimmed string
|
||||
* @private
|
||||
*/
|
||||
var trim = function(str){
|
||||
return (str+'').replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
|
||||
/**
|
||||
* Should round off a number to a decimal place
|
||||
* @param {Number} num Number to round
|
||||
* @param {Number} dec Number of decimal places to round to
|
||||
* @return {Number} Rounded number
|
||||
* @private
|
||||
*/
|
||||
var round = function(num, dec=0) {
|
||||
return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
|
||||
};
|
||||
|
||||
/**
|
||||
* Should create a fake TimeRange object
|
||||
* Mimics an HTML5 time range instance, which has functions that
|
||||
* return the start and end times for a range
|
||||
* TimeRanges are returned by the buffered() method
|
||||
* @param {Number} start Start time in seconds
|
||||
* @param {Number} end End time in seconds
|
||||
* @return {Object} Fake TimeRange object
|
||||
* @private
|
||||
*/
|
||||
var createTimeRange = function(start, end){
|
||||
return {
|
||||
length: 1,
|
||||
start: function() { return start; },
|
||||
end: function() { return end; }
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Add to local storage (maybe removable)
|
||||
* @private
|
||||
*/
|
||||
var setLocalStorage = function(key, value){
|
||||
try {
|
||||
// IE was throwing errors referencing the var anywhere without this
|
||||
let localStorage = window.localStorage || false;
|
||||
if (!localStorage) { return; }
|
||||
localStorage[key] = value;
|
||||
} catch(e) {
|
||||
if (e.code == 22 || e.code == 1014) { // Webkit == 22 / Firefox == 1014
|
||||
log('LocalStorage Full (VideoJS)', e);
|
||||
} else {
|
||||
if (e.code == 18) {
|
||||
log('LocalStorage not allowed (VideoJS)', e);
|
||||
} else {
|
||||
log('LocalStorage Error (VideoJS)', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get absolute version of relative URL. Used to tell flash correct URL.
|
||||
* http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
|
||||
* @param {String} url URL to make absolute
|
||||
* @return {String} Absolute URL
|
||||
* @private
|
||||
*/
|
||||
var getAbsoluteURL = function(url){
|
||||
// Check if absolute URL
|
||||
if (!url.match(/^https?:\/\//)) {
|
||||
// Convert to absolute URL. Flash hosted off-site needs an absolute URL.
|
||||
url = createEl('div', {
|
||||
innerHTML: `<a href="${url}">x</a>`
|
||||
}).firstChild.href;
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve and parse the elements of a URL
|
||||
* @param {String} url The url to parse
|
||||
* @return {Object} An object of url details
|
||||
*/
|
||||
var parseUrl = function(url) {
|
||||
const props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host'];
|
||||
|
||||
// add the url to an anchor and let the browser parse the URL
|
||||
let a = createEl('a', { href: url });
|
||||
|
||||
// IE8 (and 9?) Fix
|
||||
// ie8 doesn't parse the URL correctly until the anchor is actually
|
||||
// added to the body, and an innerHTML is needed to trigger the parsing
|
||||
let addToBody = (a.host === '' && a.protocol !== 'file:');
|
||||
let div;
|
||||
if (addToBody) {
|
||||
div = createEl('div');
|
||||
div.innerHTML = `<a href="${url}"></a>`;
|
||||
a = div.firstChild;
|
||||
// prevent the div from affecting layout
|
||||
div.setAttribute('style', 'display:none; position:absolute;');
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
|
||||
// Copy the specific URL properties to a new object
|
||||
// This is also needed for IE8 because the anchor loses its
|
||||
// properties when it's removed from the dom
|
||||
let details = {};
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
details[props[i]] = a[props[i]];
|
||||
}
|
||||
|
||||
// IE9 adds the port to the host property unlike everyone else. If
|
||||
// a port identifier is added for standard ports, strip it.
|
||||
if (details.protocol === 'http:') {
|
||||
details.host = details.host.replace(/:80$/, '');
|
||||
}
|
||||
if (details.protocol === 'https:') {
|
||||
details.host = details.host.replace(/:443$/, '');
|
||||
}
|
||||
|
||||
if (addToBody) {
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
|
||||
return details;
|
||||
};
|
||||
|
||||
/**
|
||||
* Log messages to the console and history based on the type of message
|
||||
*
|
||||
* @param {String} type The type of message, or `null` for `log`
|
||||
* @param {[type]} args The args to be passed to the log
|
||||
* @private
|
||||
*/
|
||||
function _logType(type, args){
|
||||
// convert args to an array to get array functions
|
||||
let argsArray = Array.prototype.slice.call(args);
|
||||
// if there's no console then don't try to output messages
|
||||
// they will still be stored in Lib.log.history
|
||||
// Was setting these once outside of this function, but containing them
|
||||
// in the function makes it easier to test cases where console doesn't exist
|
||||
let noop = function(){};
|
||||
|
||||
let console = window['console'] || {
|
||||
'log': noop,
|
||||
'warn': noop,
|
||||
'error': noop
|
||||
};
|
||||
|
||||
if (type) {
|
||||
// add the type to the front of the message
|
||||
argsArray.unshift(type.toUpperCase()+':');
|
||||
} else {
|
||||
// default to log with no prefix
|
||||
type = 'log';
|
||||
}
|
||||
|
||||
// add to history
|
||||
log.history.push(argsArray);
|
||||
|
||||
// add console prefix after adding to history
|
||||
argsArray.unshift('VIDEOJS:');
|
||||
|
||||
// call appropriate log function
|
||||
if (console[type].apply) {
|
||||
console[type].apply(console, argsArray);
|
||||
} else {
|
||||
// ie8 doesn't allow error.apply, but it will just join() the array anyway
|
||||
console[type](argsArray.join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log plain debug messages
|
||||
*/
|
||||
var log = function(){
|
||||
_logType(null, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Keep a history of log messages
|
||||
* @type {Array}
|
||||
*/
|
||||
log.history = [];
|
||||
|
||||
/**
|
||||
* Log error messages
|
||||
*/
|
||||
log.error = function(){
|
||||
_logType('error', arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Log warning messages
|
||||
*/
|
||||
log.warn = function(){
|
||||
_logType('warn', arguments);
|
||||
};
|
||||
|
||||
// Offset Left
|
||||
// getBoundingClientRect technique from John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
|
||||
var findPosition = function(el) {
|
||||
let box;
|
||||
|
||||
if (el.getBoundingClientRect && el.parentNode) {
|
||||
box = el.getBoundingClientRect();
|
||||
}
|
||||
|
||||
if (!box) {
|
||||
return {
|
||||
left: 0,
|
||||
top: 0
|
||||
};
|
||||
}
|
||||
|
||||
const docEl = document.documentElement;
|
||||
const body = document.body;
|
||||
|
||||
const clientLeft = docEl.clientLeft || body.clientLeft || 0;
|
||||
const scrollLeft = window.pageXOffset || body.scrollLeft;
|
||||
const left = box.left + scrollLeft - clientLeft;
|
||||
|
||||
const clientTop = docEl.clientTop || body.clientTop || 0;
|
||||
const scrollTop = window.pageYOffset || body.scrollTop;
|
||||
const top = box.top + scrollTop - clientTop;
|
||||
|
||||
// Android sometimes returns slightly off decimal values, so need to round
|
||||
return {
|
||||
left: round(left),
|
||||
top: round(top)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Array functions container
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
var arr = {};
|
||||
|
||||
/*
|
||||
* Loops through an array and runs a function for each item inside it.
|
||||
* @param {Array} array The array
|
||||
* @param {Function} callback The function to be run for each item
|
||||
* @param {*} thisArg The `this` binding of callback
|
||||
* @returns {Array} The array
|
||||
* @private
|
||||
*/
|
||||
arr.forEach = function(array, callback, thisArg) {
|
||||
thisArg = thisArg || this;
|
||||
|
||||
if (obj.isArray(array) && callback instanceof Function) {
|
||||
for (var i = 0, len = array.length; i < len; ++i) {
|
||||
callback.call(thisArg, array[i], i, array);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the extension of the passed file name. It will return an empty string if you pass an invalid path
|
||||
*
|
||||
* @param {String} path The fileName path like '/path/to/file.mp4'
|
||||
* @returns {String} The extension in lower case or an empty string if no extension could be found.
|
||||
*/
|
||||
var getFileExtension = function(path) {
|
||||
if(typeof path === 'string'){
|
||||
let splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i;
|
||||
let pathParts = splitPathRe.exec(path);
|
||||
|
||||
if (pathParts) {
|
||||
return pathParts.pop().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
export {
|
||||
createEl,
|
||||
capitalize,
|
||||
obj,
|
||||
isNaN,
|
||||
bind,
|
||||
cache,
|
||||
guid,
|
||||
expando,
|
||||
getData,
|
||||
hasData,
|
||||
removeData,
|
||||
isEmpty,
|
||||
hasClass,
|
||||
addClass,
|
||||
removeClass,
|
||||
TEST_VID,
|
||||
USER_AGENT,
|
||||
IS_IPHONE,
|
||||
IS_IPAD,
|
||||
IS_IPOD,
|
||||
IS_IOS,
|
||||
IOS_VERSION,
|
||||
IS_ANDROID,
|
||||
ANDROID_VERSION,
|
||||
IS_OLD_ANDROID,
|
||||
IS_FIREFOX,
|
||||
IS_IE8,
|
||||
IS_CHROME,
|
||||
TOUCH_ENABLED,
|
||||
BACKGROUND_SIZE_SUPPORTED,
|
||||
setElementAttributes,
|
||||
getElementAttributes,
|
||||
getComputedDimension,
|
||||
insertFirst,
|
||||
browser,
|
||||
el,
|
||||
formatTime,
|
||||
blockTextSelection,
|
||||
unblockTextSelection,
|
||||
trim,
|
||||
round,
|
||||
createTimeRange,
|
||||
setLocalStorage,
|
||||
getAbsoluteURL,
|
||||
parseUrl,
|
||||
log,
|
||||
findPosition,
|
||||
arr,
|
||||
getFileExtension
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Lib from './lib';
|
||||
import assign from 'object.assign';
|
||||
|
||||
/**
|
||||
* Custom MediaError to mimic the HTML5 MediaError
|
||||
@@ -11,7 +11,7 @@ let MediaError = function(code){
|
||||
// default code is zero, so this is a custom error
|
||||
this.message = code;
|
||||
} else if (typeof code === 'object') { // object
|
||||
Lib.obj.merge(this, code);
|
||||
assign(this, code);
|
||||
}
|
||||
|
||||
if (!this.message) {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import Button from '../button.js';
|
||||
import Component from '../component.js';
|
||||
import Menu from './menu.js';
|
||||
import * as Lib from '../lib.js';
|
||||
import * as Dom from '../utils/dom.js';
|
||||
import * as Fn from '../utils/fn.js';
|
||||
import toTitleCase from '../utils/to-title-case.js';
|
||||
|
||||
/**
|
||||
* A button class with a popup menu
|
||||
@@ -49,10 +52,10 @@ class MenuButton extends Button {
|
||||
|
||||
// Add a title list item to the top
|
||||
if (this.options().title) {
|
||||
menu.contentEl().appendChild(Lib.createEl('li', {
|
||||
menu.contentEl().appendChild(Dom.createEl('li', {
|
||||
className: 'vjs-menu-title',
|
||||
innerHTML: Lib.capitalize(this.options().title),
|
||||
tabindex: -1
|
||||
innerHTML: toTitleCase(this.options().title),
|
||||
tabIndex: -1
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -91,7 +94,7 @@ class MenuButton extends Button {
|
||||
// When you click the button it adds focus, which will show the menu indefinitely.
|
||||
// So we'll remove focus when the mouse leaves the button.
|
||||
// Focus is needed for tab navigation.
|
||||
this.one('mouseout', Lib.bind(this, function(){
|
||||
this.one('mouseout', Fn.bind(this, function(){
|
||||
this.menu.unlockShowing();
|
||||
this.el_.blur();
|
||||
}));
|
||||
@@ -105,7 +108,7 @@ class MenuButton extends Button {
|
||||
handleKeyPress(event) {
|
||||
|
||||
// Check for space bar (32) or enter (13) keys
|
||||
if (event.which == 32 || event.which == 13) {
|
||||
if (event.which === 32 || event.which === 13) {
|
||||
if (this.buttonPressed_){
|
||||
this.unpressButton();
|
||||
} else {
|
||||
@@ -113,7 +116,7 @@ class MenuButton extends Button {
|
||||
}
|
||||
event.preventDefault();
|
||||
// Check for escape (27) key
|
||||
} else if (event.which == 27){
|
||||
} else if (event.which === 27){
|
||||
if (this.buttonPressed_){
|
||||
this.unpressButton();
|
||||
}
|
||||
@@ -137,5 +140,5 @@ class MenuButton extends Button {
|
||||
}
|
||||
}
|
||||
|
||||
Button.registerComponent('MenuButton', MenuButton);
|
||||
Component.registerComponent('MenuButton', MenuButton);
|
||||
export default MenuButton;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Button from '../button.js';
|
||||
import * as Lib from '../lib.js';
|
||||
import Component from '../component.js';
|
||||
import assign from 'object.assign';
|
||||
|
||||
/**
|
||||
* The component for a menu item. `<li>`
|
||||
@@ -18,7 +19,7 @@ class MenuItem extends Button {
|
||||
|
||||
/** @inheritDoc */
|
||||
createEl(type, props) {
|
||||
return super.createEl('li', Lib.obj.merge({
|
||||
return super.createEl('li', assign({
|
||||
className: 'vjs-menu-item',
|
||||
innerHTML: this.localize(this.options_['label'])
|
||||
}, props));
|
||||
@@ -47,5 +48,5 @@ class MenuItem extends Button {
|
||||
|
||||
}
|
||||
|
||||
Button.registerComponent('MenuItem', MenuItem);
|
||||
Component.registerComponent('MenuItem', MenuItem);
|
||||
export default MenuItem;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Component from '../component.js';
|
||||
import * as Lib from '../lib.js';
|
||||
import * as Events from '../events.js';
|
||||
import * as Dom from '../utils/dom.js';
|
||||
import * as Fn from '../utils/fn.js';
|
||||
import * as Events from '../utils/events.js';
|
||||
|
||||
/* Menu
|
||||
================================================================================ */
|
||||
@@ -21,14 +22,14 @@ class Menu extends Component {
|
||||
*/
|
||||
addItem(component) {
|
||||
this.addChild(component);
|
||||
component.on('click', Lib.bind(this, function(){
|
||||
component.on('click', Fn.bind(this, function(){
|
||||
this.unlockShowing();
|
||||
}));
|
||||
}
|
||||
|
||||
createEl() {
|
||||
let contentElType = this.options().contentElType || 'ul';
|
||||
this.contentEl_ = Lib.createEl(contentElType, {
|
||||
this.contentEl_ = Dom.createEl(contentElType, {
|
||||
className: 'vjs-menu-content'
|
||||
});
|
||||
var el = super.createEl('div', {
|
||||
|
||||
+586
-129
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+2
-2
@@ -1,7 +1,7 @@
|
||||
import Player from './player';
|
||||
import Player from './player.js';
|
||||
|
||||
/**
|
||||
* the method for registering a video.js plugin
|
||||
* The method for registering a video.js plugin
|
||||
*
|
||||
* @param {String} name The name of the plugin
|
||||
* @param {Function} init The function that is run when the player inits
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import Button from './button';
|
||||
import * as Lib from './lib';
|
||||
import Button from './button.js';
|
||||
import Component from './component.js';
|
||||
import * as Fn from './utils/fn.js';
|
||||
import * as Dom from './utils/dom.js';
|
||||
import * as browser from './utils/browser.js';
|
||||
|
||||
/* Poster Image
|
||||
================================================================================ */
|
||||
@@ -16,7 +19,7 @@ class PosterImage extends Button {
|
||||
super(player, options);
|
||||
|
||||
this.update();
|
||||
player.on('posterchange', Lib.bind(this, this.update));
|
||||
player.on('posterchange', Fn.bind(this, this.update));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +35,7 @@ class PosterImage extends Button {
|
||||
* @return {Element}
|
||||
*/
|
||||
createEl() {
|
||||
let el = Lib.createEl('div', {
|
||||
let el = Dom.createEl('div', {
|
||||
className: 'vjs-poster',
|
||||
|
||||
// Don't want poster to be tabbable.
|
||||
@@ -43,8 +46,8 @@ class PosterImage extends Button {
|
||||
// ratio, use a div with `background-size` when available. For browsers that
|
||||
// do not support `background-size` (e.g. IE8), fall back on using a regular
|
||||
// img element.
|
||||
if (!Lib.BACKGROUND_SIZE_SUPPORTED) {
|
||||
this.fallbackImg_ = Lib.createEl('img');
|
||||
if (!browser.BACKGROUND_SIZE_SUPPORTED) {
|
||||
this.fallbackImg_ = Dom.createEl('img');
|
||||
el.appendChild(this.fallbackImg_);
|
||||
}
|
||||
|
||||
@@ -101,5 +104,5 @@ class PosterImage extends Button {
|
||||
|
||||
}
|
||||
|
||||
Button.registerComponent('PosterImage', PosterImage);
|
||||
Component.registerComponent('PosterImage', PosterImage);
|
||||
export default PosterImage;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import * as Events from './events';
|
||||
import * as Events from './utils/events.js';
|
||||
import document from 'global/document';
|
||||
import window from 'global/window';
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import Component from '../component.js';
|
||||
import * as Lib from '../lib.js';
|
||||
|
||||
/**
|
||||
* SeekBar Behavior includes play progress bar, and seek handle
|
||||
* Needed so it can determine seek position based on handle position/size
|
||||
* @param {Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
class SliderHandle extends Component {
|
||||
|
||||
/** @inheritDoc */
|
||||
createEl(type, props) {
|
||||
props = props || {};
|
||||
// Add the slider element class to all sub classes
|
||||
props.className = props.className + ' vjs-slider-handle';
|
||||
props = Lib.obj.merge({
|
||||
innerHTML: `<span class="vjs-control-text">${this.defaultValue || 0}</span>`
|
||||
}, props);
|
||||
|
||||
return super.createEl('div', props);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Component.registerComponent('SliderHandle', SliderHandle);
|
||||
export default SliderHandle;
|
||||
+10
-56
@@ -1,6 +1,8 @@
|
||||
import Component from '../component.js';
|
||||
import * as Lib from '../lib.js';
|
||||
import * as Dom from '../utils/dom.js';
|
||||
import roundFloat from '../utils/round-float.js';
|
||||
import document from 'global/document';
|
||||
import assign from 'object.assign';
|
||||
|
||||
/* Slider
|
||||
================================================================================ */
|
||||
@@ -36,7 +38,7 @@ class Slider extends Component {
|
||||
createEl(type, props={}) {
|
||||
// Add the slider element class to all sub classes
|
||||
props.className = props.className + ' vjs-slider';
|
||||
props = Lib.obj.merge({
|
||||
props = assign({
|
||||
'role': 'slider',
|
||||
'aria-valuenow': 0,
|
||||
'aria-valuemin': 0,
|
||||
@@ -49,7 +51,7 @@ class Slider extends Component {
|
||||
|
||||
handleMouseDown(event) {
|
||||
event.preventDefault();
|
||||
Lib.blockTextSelection();
|
||||
Dom.blockTextSelection();
|
||||
this.addClass('vjs-sliding');
|
||||
|
||||
this.on(document, 'mousemove', this.handleMouseMove);
|
||||
@@ -64,7 +66,7 @@ class Slider extends Component {
|
||||
handleMouseMove() {}
|
||||
|
||||
handleMouseUp() {
|
||||
Lib.unblockTextSelection();
|
||||
Dom.unblockTextSelection();
|
||||
this.removeClass('vjs-sliding');
|
||||
|
||||
this.off(document, 'mousemove', this.handleMouseMove);
|
||||
@@ -97,12 +99,8 @@ class Slider extends Component {
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
// If there is a handle, we need to account for the handle in our calculation for progress bar
|
||||
// so that it doesn't fall short of or extend past the handle.
|
||||
let barProgress = this.updateHandlePosition(progress);
|
||||
|
||||
// Convert to a percentage for setting
|
||||
let percentage = Lib.round(barProgress * 100, 2) + '%';
|
||||
let percentage = roundFloat(progress * 100, 2) + '%';
|
||||
|
||||
// Set the new bar width or height
|
||||
if (this.vertical()) {
|
||||
@@ -112,53 +110,9 @@ class Slider extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the handle position.
|
||||
*/
|
||||
updateHandlePosition(progress) {
|
||||
let handle = this.handle;
|
||||
if (!handle) return;
|
||||
|
||||
let vertical = this.vertical();
|
||||
let box = this.el_;
|
||||
|
||||
let boxSize, handleSize;
|
||||
if (vertical) {
|
||||
boxSize = box.offsetHeight;
|
||||
handleSize = handle.el().offsetHeight;
|
||||
} else {
|
||||
boxSize = box.offsetWidth;
|
||||
handleSize = handle.el().offsetWidth;
|
||||
}
|
||||
|
||||
// The width of the handle in percent of the containing box
|
||||
// In IE, widths may not be ready yet causing NaN
|
||||
let handlePercent = (handleSize) ? handleSize / boxSize : 0;
|
||||
|
||||
// Get the adjusted size of the box, considering that the handle's center never touches the left or right side.
|
||||
// There is a margin of half the handle's width on both sides.
|
||||
let boxAdjustedPercent = 1 - handlePercent;
|
||||
|
||||
// Adjust the progress that we'll use to set widths to the new adjusted box width
|
||||
let adjustedProgress = progress * boxAdjustedPercent;
|
||||
|
||||
// The bar does reach the left side, so we need to account for this in the bar's width
|
||||
let barProgress = adjustedProgress + (handlePercent / 2);
|
||||
|
||||
let percentage = Lib.round(adjustedProgress * 100, 2) + '%';
|
||||
|
||||
if (vertical) {
|
||||
handle.el().style.bottom = percentage;
|
||||
} else {
|
||||
handle.el().style.left = percentage;
|
||||
}
|
||||
|
||||
return barProgress;
|
||||
}
|
||||
|
||||
calculateDistance(event){
|
||||
let el = this.el_;
|
||||
let box = Lib.findPosition(el);
|
||||
let box = Dom.findElPosition(el);
|
||||
let boxW = el.offsetWidth;
|
||||
let boxH = el.offsetHeight;
|
||||
let handle = this.handle;
|
||||
@@ -211,10 +165,10 @@ class Slider extends Component {
|
||||
}
|
||||
|
||||
handleKeyPress(event) {
|
||||
if (event.which == 37 || event.which == 40) { // Left and Down Arrows
|
||||
if (event.which === 37 || event.which === 40) { // Left and Down Arrows
|
||||
event.preventDefault();
|
||||
this.stepBack();
|
||||
} else if (event.which == 38 || event.which == 39) { // Up and Right Arrows
|
||||
} else if (event.which === 38 || event.which === 39) { // Up and Right Arrows
|
||||
event.preventDefault();
|
||||
this.stepForward();
|
||||
}
|
||||
|
||||
+76
-97
@@ -5,10 +5,13 @@
|
||||
*/
|
||||
|
||||
import Tech from './tech';
|
||||
import * as Lib from '../lib';
|
||||
import * as Dom from '../utils/dom.js';
|
||||
import * as Url from '../utils/url.js';
|
||||
import { createTimeRange } from '../utils/time-ranges.js';
|
||||
import FlashRtmpDecorator from './flash-rtmp';
|
||||
import Component from '../component';
|
||||
import window from 'global/window';
|
||||
import assign from 'object.assign';
|
||||
|
||||
let navigator = window.navigator;
|
||||
/**
|
||||
@@ -21,24 +24,45 @@ let navigator = window.navigator;
|
||||
*/
|
||||
class Flash extends Tech {
|
||||
|
||||
constructor(player, options, ready){
|
||||
super(player, options, ready);
|
||||
constructor(options, ready){
|
||||
super(options, ready);
|
||||
|
||||
let { source, parentEl } = options;
|
||||
// If source was supplied pass as a flash var.
|
||||
if (options.source) {
|
||||
this.ready(function(){
|
||||
this.setSource(options.source);
|
||||
});
|
||||
}
|
||||
|
||||
// Create a temporary element to be replaced by swf object
|
||||
let placeHolder = this.el_ = Lib.createEl('div', { id: player.id() + '_temp_flash' });
|
||||
// Having issues with Flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers
|
||||
// This allows resetting the playhead when we catch the reload
|
||||
if (options.startTime) {
|
||||
this.ready(function(){
|
||||
this.load();
|
||||
this.play();
|
||||
this.currentTime(options.startTime);
|
||||
});
|
||||
}
|
||||
|
||||
// Add global window functions that the swf expects
|
||||
// A 4.x workflow we weren't able to solve for in 5.0
|
||||
// because of the need to hard code these functions
|
||||
// into the swf for security reasons
|
||||
window.videojs = window.videojs || {};
|
||||
window.videojs.Flash = window.videojs.Flash || {};
|
||||
window.videojs.Flash.onReady = Flash.onReady;
|
||||
window.videojs.Flash.onEvent = Flash.onEvent;
|
||||
window.videojs.Flash.onError = Flash.onError;
|
||||
}
|
||||
|
||||
createEl() {
|
||||
let options = this.options();
|
||||
|
||||
// Generate ID for swf object
|
||||
let objId = player.id()+'_flash_api';
|
||||
|
||||
// Store player options in local var for optimization
|
||||
// TODO: switch to using player methods instead of options
|
||||
// e.g. player.autoplay();
|
||||
let playerOptions = player.options_;
|
||||
let objId = options.techId;
|
||||
|
||||
// Merge default flashvars with ones passed in to init
|
||||
let flashVars = Lib.obj.merge({
|
||||
let flashVars = assign({
|
||||
|
||||
// SWF Callback Functions
|
||||
'readyFunction': 'videojs.Flash.onReady',
|
||||
@@ -46,68 +70,30 @@ class Flash extends Tech {
|
||||
'errorEventProxyFunction': 'videojs.Flash.onError',
|
||||
|
||||
// Player Settings
|
||||
'autoplay': playerOptions.autoplay,
|
||||
'preload': playerOptions.preload,
|
||||
'loop': playerOptions.loop,
|
||||
'muted': playerOptions.muted
|
||||
'autoplay': options.autoplay,
|
||||
'preload': options.preload,
|
||||
'loop': options.loop,
|
||||
'muted': options.muted
|
||||
|
||||
}, options['flashVars']);
|
||||
}, options.flashVars);
|
||||
|
||||
// Merge default parames with ones passed in
|
||||
let params = Lib.obj.merge({
|
||||
let params = assign({
|
||||
'wmode': 'opaque', // Opaque is needed to overlay controls, but can affect playback performance
|
||||
'bgcolor': '#000000' // Using bgcolor prevents a white flash when the object is loading
|
||||
}, options['params']);
|
||||
}, options.params);
|
||||
|
||||
// Merge default attributes with ones passed in
|
||||
let attributes = Lib.obj.merge({
|
||||
let attributes = assign({
|
||||
'id': objId,
|
||||
'name': objId, // Both ID and Name needed or swf to identify itself
|
||||
'class': 'vjs-tech'
|
||||
}, options['attributes']);
|
||||
}, options.attributes);
|
||||
|
||||
// If source was supplied pass as a flash var.
|
||||
if (source) {
|
||||
this.ready(function(){
|
||||
this.setSource(source);
|
||||
});
|
||||
}
|
||||
this.el_ = Flash.embed(options.swf, flashVars, params, attributes);
|
||||
this.el_.tech = this;
|
||||
|
||||
// Add placeholder to player div
|
||||
Lib.insertFirst(placeHolder, parentEl);
|
||||
|
||||
// Having issues with Flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers
|
||||
// This allows resetting the playhead when we catch the reload
|
||||
if (options['startTime']) {
|
||||
this.ready(function(){
|
||||
this.load();
|
||||
this.play();
|
||||
this['currentTime'](options['startTime']);
|
||||
});
|
||||
}
|
||||
|
||||
// firefox doesn't bubble mousemove events to parent. videojs/video-js-swf#37
|
||||
// bugzilla bug: https://bugzilla.mozilla.org/show_bug.cgi?id=836786
|
||||
if (Lib.IS_FIREFOX) {
|
||||
this.ready(function(){
|
||||
this.on('mousemove', function(){
|
||||
// since it's a custom event, don't bubble higher than the player
|
||||
this.player().trigger({ 'type':'mousemove', 'bubbles': false });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// native click events on the SWF aren't triggered on IE11, Win8.1RT
|
||||
// use stageclick events triggered from inside the SWF instead
|
||||
player.on('stageclick', player.reportUserActivity);
|
||||
|
||||
window.videojs = window.videojs || {};
|
||||
window.videojs.Flash = window.videojs.Flash || {};
|
||||
window.videojs.Flash.onReady = Flash.onReady;
|
||||
window.videojs.Flash.onEvent = Flash.onEvent;
|
||||
window.videojs.Flash.onError = Flash.onError;
|
||||
|
||||
this.el_ = Flash.embed(options['swf'], placeHolder, flashVars, params, attributes);
|
||||
return this.el_;
|
||||
}
|
||||
|
||||
play() {
|
||||
@@ -120,7 +106,7 @@ class Flash extends Tech {
|
||||
|
||||
src(src) {
|
||||
if (src === undefined) {
|
||||
return this['currentSrc']();
|
||||
return this.currentSrc();
|
||||
}
|
||||
|
||||
// Setting src through `src` not `setSrc` will be deprecated
|
||||
@@ -129,12 +115,12 @@ class Flash extends Tech {
|
||||
|
||||
setSrc(src) {
|
||||
// Make sure source URL is absolute.
|
||||
src = Lib.getAbsoluteURL(src);
|
||||
src = Url.getAbsoluteURL(src);
|
||||
this.el_.vjs_src(src);
|
||||
|
||||
// Currently the SWF doesn't autoplay if you load a source later.
|
||||
// e.g. Load player w/ no source, wait 2s, set src.
|
||||
if (this.player_.autoplay()) {
|
||||
if (this.autoplay()) {
|
||||
var tech = this;
|
||||
this.setTimeout(function(){ tech.play(); }, 0);
|
||||
}
|
||||
@@ -175,7 +161,7 @@ class Flash extends Tech {
|
||||
setPoster() {}
|
||||
|
||||
buffered() {
|
||||
return Lib.createTimeRange(0, this.el_.vjs_getProperty('buffered'));
|
||||
return createTimeRange(0, this.el_.vjs_getProperty('buffered'));
|
||||
}
|
||||
|
||||
supportsFullScreen() {
|
||||
@@ -240,7 +226,7 @@ Flash.nativeSourceHandler.canHandleSource = function(source){
|
||||
var type;
|
||||
|
||||
function guessMimeType(src) {
|
||||
var ext = Lib.getFileExtension(src);
|
||||
var ext = Url.getFileExtension(src);
|
||||
if (ext) {
|
||||
return `video/${ext}`;
|
||||
}
|
||||
@@ -289,18 +275,14 @@ Flash.formats = {
|
||||
};
|
||||
|
||||
Flash.onReady = function(currSwf){
|
||||
let el = Lib.el(currSwf);
|
||||
let el = Dom.getEl(currSwf);
|
||||
let tech = el && el.tech;
|
||||
|
||||
// get player from the player div property
|
||||
const player = el && el.parentNode && el.parentNode['player'];
|
||||
|
||||
// if there is no el or player then the tech has been disposed
|
||||
// if there is no el then the tech has been disposed
|
||||
// and the tech element was removed from the player div
|
||||
if (player) {
|
||||
// reference player on tech element
|
||||
el['player'] = player;
|
||||
if (tech && tech.el()) {
|
||||
// check that the flash object is really ready
|
||||
Flash['checkReady'](player.tech);
|
||||
Flash.checkReady(tech);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -326,21 +308,21 @@ Flash.checkReady = function(tech){
|
||||
|
||||
// Trigger events from the swf on the player
|
||||
Flash.onEvent = function(swfID, eventName){
|
||||
let player = Lib.el(swfID)['player'];
|
||||
player.trigger(eventName);
|
||||
let tech = Dom.getEl(swfID).tech;
|
||||
tech.trigger(eventName);
|
||||
};
|
||||
|
||||
// Log errors from the swf
|
||||
Flash.onError = function(swfID, err){
|
||||
const player = Lib.el(swfID)['player'];
|
||||
const tech = Dom.getEl(swfID).tech;
|
||||
const msg = 'FLASH: '+err;
|
||||
|
||||
if (err == 'srcnotfound') {
|
||||
player.error({ code: 4, message: msg });
|
||||
if (err === 'srcnotfound') {
|
||||
tech.trigger('error', { code: 4, message: msg });
|
||||
|
||||
// errors we haven't categorized into the media errors
|
||||
} else {
|
||||
player.error(msg);
|
||||
tech.trigger('error', msg);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -364,15 +346,12 @@ Flash.version = function(){
|
||||
};
|
||||
|
||||
// Flash embedding method. Only used in non-iframe mode
|
||||
Flash.embed = function(swf, placeHolder, flashVars, params, attributes){
|
||||
Flash.embed = function(swf, flashVars, params, attributes){
|
||||
const code = Flash.getEmbedCode(swf, flashVars, params, attributes);
|
||||
|
||||
// Get element by embedding code and retrieving created element
|
||||
const obj = Lib.createEl('div', { innerHTML: code }).childNodes[0];
|
||||
const obj = Dom.createEl('div', { innerHTML: code }).childNodes[0];
|
||||
|
||||
const par = placeHolder.parentNode;
|
||||
|
||||
placeHolder.parentNode.replaceChild(obj, placeHolder);
|
||||
return obj;
|
||||
};
|
||||
|
||||
@@ -384,13 +363,13 @@ Flash.getEmbedCode = function(swf, flashVars, params, attributes){
|
||||
|
||||
// Convert flash vars to string
|
||||
if (flashVars) {
|
||||
Lib.obj.each(flashVars, function(key, val){
|
||||
flashVarsString += `${key}=${val}&`;
|
||||
Object.getOwnPropertyNames(flashVars).forEach(function(key){
|
||||
flashVarsString += `${key}=${flashVars[key]}&`;
|
||||
});
|
||||
}
|
||||
|
||||
// Add swf, flashVars, and other default params
|
||||
params = Lib.obj.merge({
|
||||
params = assign({
|
||||
'movie': swf,
|
||||
'flashvars': flashVarsString,
|
||||
'allowScriptAccess': 'always', // Required to talk to swf
|
||||
@@ -398,11 +377,11 @@ Flash.getEmbedCode = function(swf, flashVars, params, attributes){
|
||||
}, params);
|
||||
|
||||
// Create param tags string
|
||||
Lib.obj.each(params, function(key, val){
|
||||
paramsString += `<param name="${key}" value="${val}" />`;
|
||||
Object.getOwnPropertyNames(params).forEach(function(key){
|
||||
paramsString += `<param name="${key}" value="${params[key]}" />`;
|
||||
});
|
||||
|
||||
attributes = Lib.obj.merge({
|
||||
attributes = assign({
|
||||
// Add swf to attributes (need both for IE and Others to work)
|
||||
'data': swf,
|
||||
|
||||
@@ -413,8 +392,8 @@ Flash.getEmbedCode = function(swf, flashVars, params, attributes){
|
||||
}, attributes);
|
||||
|
||||
// Create Attributes string
|
||||
Lib.obj.each(attributes, function(key, val){
|
||||
attrsString += `${key}="${val}" `;
|
||||
Object.getOwnPropertyNames(attributes).forEach(function(key){
|
||||
attrsString += `${key}="${attributes[key]}" `;
|
||||
});
|
||||
|
||||
return `${objTag}${attrsString}>${paramsString}</object>`;
|
||||
@@ -423,5 +402,5 @@ Flash.getEmbedCode = function(swf, flashVars, params, attributes){
|
||||
// Run Flash through the RTMP decorator
|
||||
FlashRtmpDecorator(Flash);
|
||||
|
||||
Tech.registerComponent('Flash', Flash);
|
||||
Component.registerComponent('Flash', Flash);
|
||||
export default Flash;
|
||||
|
||||
+77
-137
@@ -4,9 +4,15 @@
|
||||
|
||||
import Tech from './tech.js';
|
||||
import Component from '../component';
|
||||
import * as Lib from '../lib';
|
||||
import * as VjsUtil from '../util';
|
||||
import * as Dom from '../utils/dom.js';
|
||||
import * as Url from '../utils/url.js';
|
||||
import * as Fn from '../utils/fn.js';
|
||||
import log from '../utils/log.js';
|
||||
import * as browser from '../utils/browser.js';
|
||||
import document from 'global/document';
|
||||
import window from 'global/window';
|
||||
import assign from 'object.assign';
|
||||
import mergeOptions from '../utils/merge-options.js';
|
||||
|
||||
/**
|
||||
* HTML5 Media Controller - Wrapper for HTML5 Media API
|
||||
@@ -17,18 +23,16 @@ import document from 'global/document';
|
||||
*/
|
||||
class Html5 extends Tech {
|
||||
|
||||
constructor(player, options, ready){
|
||||
super(player, options, ready);
|
||||
constructor(options, ready){
|
||||
super(options, ready);
|
||||
|
||||
this.setupTriggers();
|
||||
|
||||
const source = options['source'];
|
||||
const source = options.source;
|
||||
|
||||
// Set the source if one is provided
|
||||
// 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted)
|
||||
// 2) Check to see if the network state of the tag was failed at init, and if so, reset the source
|
||||
// anyway so the error gets fired.
|
||||
if (source && (this.el_.currentSrc !== source.src || (player.tag && player.tag.initNetworkState_ === 3))) {
|
||||
if (source && (this.el_.currentSrc !== source.src || (options.tag && options.tag.initNetworkState_ === 3))) {
|
||||
this.setSource(source);
|
||||
}
|
||||
|
||||
@@ -42,14 +46,14 @@ class Html5 extends Tech {
|
||||
let node = nodes[nodesLength];
|
||||
let nodeName = node.nodeName.toLowerCase();
|
||||
if (nodeName === 'track') {
|
||||
if (!this['featuresNativeTextTracks']) {
|
||||
if (!this.featuresNativeTextTracks) {
|
||||
// Empty video tag tracks so the built-in player doesn't use them also.
|
||||
// This may not be fast enough to stop HTML5 browsers from reading the tags
|
||||
// so we'll need to turn off any default tracks if we're manually doing
|
||||
// captions and subtitles. videoElement.textTracks
|
||||
removeNodes.push(node);
|
||||
} else {
|
||||
this.remoteTextTracks().addTrack_(node['track']);
|
||||
this.remoteTextTracks().addTrack_(node.track);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,29 +63,18 @@ class Html5 extends Tech {
|
||||
}
|
||||
}
|
||||
|
||||
if (this['featuresNativeTextTracks']) {
|
||||
this.on('loadstart', Lib.bind(this, this.hideCaptions));
|
||||
if (this.featuresNativeTextTracks) {
|
||||
this.on('loadstart', Fn.bind(this, this.hideCaptions));
|
||||
}
|
||||
|
||||
// Determine if native controls should be used
|
||||
// Our goal should be to get the custom controls on mobile solid everywhere
|
||||
// so we can remove this all together. Right now this will block custom
|
||||
// controls on touch enabled laptops like the Chrome Pixel
|
||||
if (Lib.TOUCH_ENABLED && player.options()['nativeControlsForTouch'] === true) {
|
||||
this.useNativeControls();
|
||||
if (browser.TOUCH_ENABLED && options.nativeControlsForTouch === true) {
|
||||
this.trigger('usenativecontrols');
|
||||
}
|
||||
|
||||
// Chrome and Safari both have issues with autoplay.
|
||||
// In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work.
|
||||
// In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays)
|
||||
// This fixes both issues. Need to wait for API, so it updates displays correctly
|
||||
player.ready(function(){
|
||||
if (this.tag && this.options_['autoplay'] && this.paused()) {
|
||||
delete this.tag['poster']; // Chrome Fix. Fixed in Chrome v16.
|
||||
this.play();
|
||||
}
|
||||
});
|
||||
|
||||
this.triggerReady();
|
||||
}
|
||||
|
||||
@@ -92,8 +85,7 @@ class Html5 extends Tech {
|
||||
}
|
||||
|
||||
createEl() {
|
||||
let player = this.player_;
|
||||
let el = player.tag;
|
||||
let el = this.options_.tag;
|
||||
|
||||
// Check if this browser supports moving the element into the box.
|
||||
// On the iPhone video will break if you move the element,
|
||||
@@ -105,29 +97,27 @@ class Html5 extends Tech {
|
||||
const clone = el.cloneNode(false);
|
||||
Html5.disposeMediaElement(el);
|
||||
el = clone;
|
||||
player.tag = null;
|
||||
} else {
|
||||
el = Lib.createEl('video');
|
||||
el = document.createElement('video');
|
||||
|
||||
// determine if native controls should be used
|
||||
let attributes = VjsUtil.mergeOptions({}, player.tagAttributes);
|
||||
if (!Lib.TOUCH_ENABLED || player.options()['nativeControlsForTouch'] !== true) {
|
||||
let tagAttributes = this.options_.tag && Dom.getElAttributes(this.options_.tag);
|
||||
let attributes = mergeOptions({}, tagAttributes);
|
||||
if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) {
|
||||
delete attributes.controls;
|
||||
}
|
||||
|
||||
Lib.setElementAttributes(el,
|
||||
Lib.obj.merge(attributes, {
|
||||
id: player.id() + '_html5_api',
|
||||
Dom.setElAttributes(el,
|
||||
assign(attributes, {
|
||||
id: this.options_.techId,
|
||||
class: 'vjs-tech'
|
||||
})
|
||||
);
|
||||
}
|
||||
// associate the player with the new tag
|
||||
el['player'] = player;
|
||||
|
||||
if (player.options_.tracks) {
|
||||
for (let i = 0; i < player.options_.tracks.length; i++) {
|
||||
const track = player.options_.tracks[i];
|
||||
if (this.options_.tracks) {
|
||||
for (let i = 0; i < this.options_.tracks.length; i++) {
|
||||
const track = this.options_.tracks[i];
|
||||
let trackEl = document.createElement('track');
|
||||
trackEl.kind = track.kind;
|
||||
trackEl.label = track.label;
|
||||
@@ -139,8 +129,6 @@ class Html5 extends Tech {
|
||||
el.appendChild(trackEl);
|
||||
}
|
||||
}
|
||||
|
||||
Lib.insertFirst(el, player.el());
|
||||
}
|
||||
|
||||
// Update specific tag settings, in case they were overridden
|
||||
@@ -148,10 +136,10 @@ class Html5 extends Tech {
|
||||
for (let i = settingsAttrs.length - 1; i >= 0; i--) {
|
||||
const attr = settingsAttrs[i];
|
||||
let overwriteAttrs = {};
|
||||
if (typeof player.options_[attr] !== 'undefined') {
|
||||
overwriteAttrs[attr] = player.options_[attr];
|
||||
if (typeof this.options_[attr] !== 'undefined') {
|
||||
overwriteAttrs[attr] = this.options_[attr];
|
||||
}
|
||||
Lib.setElementAttributes(el, overwriteAttrs);
|
||||
Dom.setElAttributes(el, overwriteAttrs);
|
||||
}
|
||||
|
||||
return el;
|
||||
@@ -176,62 +164,6 @@ class Html5 extends Tech {
|
||||
}
|
||||
}
|
||||
|
||||
// Make video events trigger player events
|
||||
// May seem verbose here, but makes other APIs possible.
|
||||
// Triggers removed using this.off when disposed
|
||||
setupTriggers() {
|
||||
for (let i = Html5.Events.length - 1; i >= 0; i--) {
|
||||
this.on(Html5.Events[i], this.eventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
eventHandler(evt) {
|
||||
// In the case of an error on the video element, set the error prop
|
||||
// on the player and let the player handle triggering the event. On
|
||||
// some platforms, error events fire that do not cause the error
|
||||
// property on the video element to be set. See #1465 for an example.
|
||||
if (evt.type == 'error' && this.error()) {
|
||||
this.player().error(this.error().code);
|
||||
|
||||
// in some cases we pass the event directly to the player
|
||||
} else {
|
||||
// No need for media events to bubble up.
|
||||
evt.bubbles = false;
|
||||
|
||||
this.player().trigger(evt);
|
||||
}
|
||||
}
|
||||
|
||||
useNativeControls() {
|
||||
let tech = this;
|
||||
let player = this.player();
|
||||
|
||||
// If the player controls are enabled turn on the native controls
|
||||
tech.setControls(player.controls());
|
||||
|
||||
// Update the native controls when player controls state is updated
|
||||
let controlsOn = function(){
|
||||
tech.setControls(true);
|
||||
};
|
||||
let controlsOff = function(){
|
||||
tech.setControls(false);
|
||||
};
|
||||
player.on('controlsenabled', controlsOn);
|
||||
player.on('controlsdisabled', controlsOff);
|
||||
|
||||
// Clean up when not using native controls anymore
|
||||
let cleanUp = function(){
|
||||
player.off('controlsenabled', controlsOn);
|
||||
player.off('controlsdisabled', controlsOff);
|
||||
};
|
||||
tech.on('dispose', cleanUp);
|
||||
player.on('usingcustomcontrols', cleanUp);
|
||||
|
||||
// Update the state of the player to using native controls
|
||||
player.usingNativeControls(true);
|
||||
}
|
||||
|
||||
|
||||
play() { this.el_.play(); }
|
||||
pause() { this.el_.pause(); }
|
||||
paused() { return this.el_.paused; }
|
||||
@@ -241,7 +173,7 @@ class Html5 extends Tech {
|
||||
try {
|
||||
this.el_.currentTime = seconds;
|
||||
} catch(e) {
|
||||
Lib.log(e, 'Video is not ready. (Video.js)');
|
||||
log(e, 'Video is not ready. (Video.js)');
|
||||
// this.warning(VideoJS.warnings.videoNotReady);
|
||||
}
|
||||
}
|
||||
@@ -260,10 +192,10 @@ class Html5 extends Tech {
|
||||
height() { return this.el_.offsetHeight; }
|
||||
|
||||
supportsFullScreen() {
|
||||
if (typeof this.el_.webkitEnterFullScreen == 'function') {
|
||||
|
||||
if (typeof this.el_.webkitEnterFullScreen === 'function') {
|
||||
let userAgent = window.navigator.userAgent;
|
||||
// Seems to be broken in Chromium/Chrome && Safari in Leopard
|
||||
if (/Android/.test(Lib.USER_AGENT) || !/Chrome|Mac OS X 10.5/.test(Lib.USER_AGENT)) {
|
||||
if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -275,14 +207,11 @@ class Html5 extends Tech {
|
||||
|
||||
if ('webkitDisplayingFullscreen' in video) {
|
||||
this.one('webkitbeginfullscreen', function() {
|
||||
this.player_.isFullscreen(true);
|
||||
|
||||
this.one('webkitendfullscreen', function() {
|
||||
this.player_.isFullscreen(false);
|
||||
this.player_.trigger('fullscreenchange');
|
||||
this.trigger('fullscreenchange');
|
||||
});
|
||||
|
||||
this.player_.trigger('fullscreenchange');
|
||||
this.trigger('fullscreenchange');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -347,6 +276,9 @@ class Html5 extends Tech {
|
||||
networkState() { return this.el_.networkState; }
|
||||
readyState() { return this.el_.readyState; }
|
||||
|
||||
videoWidth() { return this.el_.videoWidth; }
|
||||
videoHeight() { return this.el_.videoHeight; }
|
||||
|
||||
textTracks() {
|
||||
if (!this['featuresNativeTextTracks']) {
|
||||
return super.textTracks();
|
||||
@@ -437,6 +369,19 @@ class Html5 extends Tech {
|
||||
|
||||
/* HTML5 Support Testing ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Element for testing browser HTML5 video capabilities
|
||||
* @type {Element}
|
||||
* @constant
|
||||
* @private
|
||||
*/
|
||||
Html5.TEST_VID = document.createElement('video');
|
||||
let track = document.createElement('track');
|
||||
track.kind = 'captions';
|
||||
track.srclang = 'en';
|
||||
track.label = 'English';
|
||||
Html5.TEST_VID.appendChild(track);
|
||||
|
||||
/**
|
||||
* Check if HTML5 video is supported by this browser/device
|
||||
* @return {Boolean}
|
||||
@@ -444,12 +389,12 @@ class Html5 extends Tech {
|
||||
Html5.isSupported = function(){
|
||||
// IE9 with no Media Player is a LIAR! (#984)
|
||||
try {
|
||||
Lib.TEST_VID['volume'] = 0.5;
|
||||
Html5.TEST_VID['volume'] = 0.5;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!Lib.TEST_VID.canPlayType;
|
||||
return !!Html5.TEST_VID.canPlayType;
|
||||
};
|
||||
|
||||
// Add Source Handler pattern functions to this tech
|
||||
@@ -475,7 +420,7 @@ Html5.nativeSourceHandler.canHandleSource = function(source){
|
||||
// IE9 on Windows 7 without MediaPlayer throws an error here
|
||||
// https://github.com/videojs/video.js/issues/519
|
||||
try {
|
||||
return Lib.TEST_VID.canPlayType(type);
|
||||
return Html5.TEST_VID.canPlayType(type);
|
||||
} catch(e) {
|
||||
return '';
|
||||
}
|
||||
@@ -486,7 +431,7 @@ Html5.nativeSourceHandler.canHandleSource = function(source){
|
||||
return canPlayType(source.type);
|
||||
} else if (source.src) {
|
||||
// If no type, fall back to checking 'video/[EXTENSION]'
|
||||
ext = Lib.getFileExtension(source.src);
|
||||
ext = Url.getFileExtension(source.src);
|
||||
|
||||
return canPlayType(`video/${ext}`);
|
||||
}
|
||||
@@ -521,9 +466,9 @@ Html5.registerSourceHandler(Html5.nativeSourceHandler);
|
||||
* @return {Boolean}
|
||||
*/
|
||||
Html5.canControlVolume = function(){
|
||||
var volume = Lib.TEST_VID.volume;
|
||||
Lib.TEST_VID.volume = (volume / 2) + 0.1;
|
||||
return volume !== Lib.TEST_VID.volume;
|
||||
var volume = Html5.TEST_VID.volume;
|
||||
Html5.TEST_VID.volume = (volume / 2) + 0.1;
|
||||
return volume !== Html5.TEST_VID.volume;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -531,9 +476,9 @@ Html5.canControlVolume = function(){
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
Html5.canControlPlaybackRate = function(){
|
||||
var playbackRate = Lib.TEST_VID.playbackRate;
|
||||
Lib.TEST_VID.playbackRate = (playbackRate / 2) + 0.1;
|
||||
return playbackRate !== Lib.TEST_VID.playbackRate;
|
||||
var playbackRate = Html5.TEST_VID.playbackRate;
|
||||
Html5.TEST_VID.playbackRate = (playbackRate / 2) + 0.1;
|
||||
return playbackRate !== Html5.TEST_VID.playbackRate;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -548,11 +493,11 @@ Html5.supportsNativeTextTracks = function() {
|
||||
// Browsers with numeric modes include IE10 and older (<=2013) samsung android models.
|
||||
// Firefox isn't playing nice either with modifying the mode
|
||||
// TODO: Investigate firefox: https://github.com/videojs/video.js/issues/1862
|
||||
supportsTextTracks = !!Lib.TEST_VID.textTracks;
|
||||
if (supportsTextTracks && Lib.TEST_VID.textTracks.length > 0) {
|
||||
supportsTextTracks = typeof Lib.TEST_VID.textTracks[0]['mode'] !== 'number';
|
||||
supportsTextTracks = !!Html5.TEST_VID.textTracks;
|
||||
if (supportsTextTracks && Html5.TEST_VID.textTracks.length > 0) {
|
||||
supportsTextTracks = typeof Html5.TEST_VID.textTracks[0]['mode'] !== 'number';
|
||||
}
|
||||
if (supportsTextTracks && Lib.IS_FIREFOX) {
|
||||
if (supportsTextTracks && browser.IS_FIREFOX) {
|
||||
supportsTextTracks = false;
|
||||
}
|
||||
|
||||
@@ -576,7 +521,7 @@ Html5.prototype['featuresPlaybackRate'] = Html5.canControlPlaybackRate();
|
||||
* In iOS, if you move a video element in the DOM, it breaks video playback.
|
||||
* @type {Boolean}
|
||||
*/
|
||||
Html5.prototype['movingMediaElementInDOM'] = !Lib.IS_IOS;
|
||||
Html5.prototype['movingMediaElementInDOM'] = !browser.IS_IOS;
|
||||
|
||||
/**
|
||||
* Set the the tech's fullscreen resize support status.
|
||||
@@ -604,12 +549,12 @@ const mp4RE = /^video\/mp4/i;
|
||||
|
||||
Html5.patchCanPlayType = function() {
|
||||
// Android 4.0 and above can play HLS to some extent but it reports being unable to do so
|
||||
if (Lib.ANDROID_VERSION >= 4.0) {
|
||||
if (browser.ANDROID_VERSION >= 4.0) {
|
||||
if (!canPlayType) {
|
||||
canPlayType = Lib.TEST_VID.constructor.prototype.canPlayType;
|
||||
canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
}
|
||||
|
||||
Lib.TEST_VID.constructor.prototype.canPlayType = function(type) {
|
||||
Html5.TEST_VID.constructor.prototype.canPlayType = function(type) {
|
||||
if (type && mpegurlRE.test(type)) {
|
||||
return 'maybe';
|
||||
}
|
||||
@@ -618,12 +563,12 @@ Html5.patchCanPlayType = function() {
|
||||
}
|
||||
|
||||
// Override Android 2.2 and less canPlayType method which is broken
|
||||
if (Lib.IS_OLD_ANDROID) {
|
||||
if (browser.IS_OLD_ANDROID) {
|
||||
if (!canPlayType) {
|
||||
canPlayType = Lib.TEST_VID.constructor.prototype.canPlayType;
|
||||
canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
}
|
||||
|
||||
Lib.TEST_VID.constructor.prototype.canPlayType = function(type){
|
||||
Html5.TEST_VID.constructor.prototype.canPlayType = function(type){
|
||||
if (type && mp4RE.test(type)) {
|
||||
return 'maybe';
|
||||
}
|
||||
@@ -633,8 +578,8 @@ Html5.patchCanPlayType = function() {
|
||||
};
|
||||
|
||||
Html5.unpatchCanPlayType = function() {
|
||||
var r = Lib.TEST_VID.constructor.prototype.canPlayType;
|
||||
Lib.TEST_VID.constructor.prototype.canPlayType = canPlayType;
|
||||
var r = Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
|
||||
canPlayType = null;
|
||||
return r;
|
||||
};
|
||||
@@ -642,14 +587,9 @@ Html5.unpatchCanPlayType = function() {
|
||||
// by default, patch the video element
|
||||
Html5.patchCanPlayType();
|
||||
|
||||
// List of all HTML5 events (various uses).
|
||||
Html5.Events = 'loadstart,suspend,abort,error,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,playing,waiting,seeking,seeked,ended,durationchange,timeupdate,progress,play,pause,ratechange,volumechange'.split(',');
|
||||
|
||||
Html5.disposeMediaElement = function(el){
|
||||
if (!el) { return; }
|
||||
|
||||
el['player'] = null;
|
||||
|
||||
if (el.parentNode) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário