Comparar commits

...

37 Commits

Autor SHA1 Mensagem Data
heff c07fd862bb v5.0.0-24 dist 2015-05-28 18:06:05 +00:00
heff 3bf01d9a41 v5.0.0-24 2015-05-28 18:05:09 +00:00
heff a88e311214 Fixed a number of IE8 and Flash issues from 5.0 changes
IE8 compatiblity fixes - Babel loose mode and ES5-shim

Reverted to old isPlainObject to fix IE8

Lodash.isplainobject was throwing a "Member not found error" on elements,
specifically the 'custom' track element being passed in options.

(turned out to be that we were using lodash modern, not compat)

Fixed full-window mode in IE8 by fixing fullscreen API check

Fixed the swf events by creating the object in component.createEl
fixes #2184

Added es5 shim and sham to the sandbox example
related to #1687
2015-05-28 11:00:08 -07:00
heff fb5d0ce6ad v5.0.0-23 2015-05-27 18:44:33 +00:00
heff 7c169d417c Fixed instances of tabIndex that did not have a capital I [#2176] 2015-05-27 11:42:01 -07:00
heff fdd133906c v5.0.0-22 2015-05-23 00:29:46 +00:00
heff a5758019e5 Updated the ready event to always be async
closes #1667

Fix text track tests.
Now that ready is async, we need to tick the clock so the ready handler
fires.

Remove unneeded ready test
2015-05-22 17:27:15 -07:00
heff 1ff361a825 Reverted an error in src() from the default args update 2015-05-21 20:42:25 -07:00
David 27ee448e1f v5.0.0-21 2015-05-22 02:50:34 +00:00
David LaPalomento 0ad43fd576 update the swf to v4.7 2015-05-21 19:47:44 -07:00
45aff0062cf1b0e55a6532b0a513db6be3952d17 21edde8702 v5.0.0-20 2015-05-22 00:09:43 +00:00
45aff0062cf1b0e55a6532b0a513db6be3952d17 6b2dca32fc Normalise lang codes to lowercase for insensitive match
Use primary code ('en') if specific code ('en-us') doesn not match
Always re-merge languages

closes #2177

Updated language function to lowercase internally

Updated component.localize to not require stubbing
2015-05-21 17:07:13 -07:00
Matthew McClure 4007add5e5 Moved to pure css slider handles
closes #2132

removed slider handle classes

Got rid of left-over handle styles
2015-05-21 13:43:53 -07:00
heff 7c5206eaf9 v5.0.0-19 2015-05-21 18:36:46 +00:00
heff 1bfe0b4fed Clean up and documentation of src/js/video.js and DOM functions
Preparing to export utility functions on the videojs object

closes #2182

Change el() to getEl() for consistency

Cleaned up DOM functions library

Clean up and document videojs object API

Fixed mergeOptions to modify the first object instead of a copy

More cleanup of the main video.js file and documentation

Fixed issues with mergeOptions

Cleaned up the addLanguage function

Removed unnecessary underscores in private module vars
2015-05-21 11:33:12 -07:00
eXon 5d550ffada Additional tech 2.0 improvements from #2126
closes #2166
closes #2126

this.tech.emitTapEvents(); should be handled by the tech

De-dupe the bufferedPercent code in both Tech and Player

Have the player generate the tech ID

Added autoplay/preload/loop/muted to tech option

Remove the watch for native timeupdates

Fixed the JSDoc for bufferedPercent

Removed the unit test for native timeupdate

Added cute whitespaces

buffer should always return a TimeRange
2015-05-21 11:19:33 -07:00
Matthew caf725a3d4 v5.0.0-18 2015-05-19 18:25:29 +00:00
Matthew McClure 11d9d9afe8 last use of inherited registerComponent removed 2015-05-19 11:10:17 -07:00
heff b2311c7664 v5.0.0-17 2015-05-19 00:57:10 +00:00
heff 1ffb13a799 Fixed all uses of registerComponent that relied on __proto__ inheritance 2015-05-18 17:35:21 -07:00
heff dc083f8cf4 v5.0.0-16 2015-05-16 01:25:32 +00:00
heff a8ff970d4a Broke up Lib and Util into smaller libraries of functions
Broke out bind, guid, and element data functions from Lib

Separated out more dom functions in to dom.js

Broke out URL functions into url.js

Removed setLocalStorage since it wasn't being used

Moved browser tests out of lib

Moved log functions into their own file

Removed trim() since it wasn't being used

Moved formatTime into its own file

Moved round into its own file and renamed roundFloat()

Moved capitalize into its own file and renamed as toTitleCase()

Moved createTimeRange into its own file

Removed Lib.arr.forEach infavor of the native forEach

Removed Lib.obj.create in favor of native Object.create (ES6-sham)

Removed obj.each in favor of native Object.getOwnPropertyNames().forEach()

Removed obj.merge and copy. Using lodash.assign instead.

Replaced Lib.obj.isPlain with lodash.isPlainObject

Removed Lib.obj.isArray in favor of the native Array.isArray

Also removed the lib.js tests file as all tests have been moved
or removed.

Removed Lib.isEmpty in favor of !Object.getOwnPropertyNames().length

Switched Util.mergeOptions and deepMerge to use new mergeOptions()

Moved Lib.TEST_VID to Html5.TEST_VID

Removed Lib references everywhere. Woo!

Attempting to fix sourcemap test errors by setting grunt-browserify version

Switched to object.assign from lodash.assign

Removed unused 'inherits' dependency

Reorganzied test files and added '.test' to file names

Combined js/core.js and js/video.js

Moved events.js into the utils directory
2015-05-15 18:20:35 -07:00
Chris Rebert 2bf0be72f3 build: bower.json: remove moot version field
Per https://github.com/bower/bower.json-spec/commit/a325da3d79baab018c572d75dc1781b12322f6cd

closes #2144

bower.json: main: fix path to video.js

bower.json: main: video-js.css => video-js.scss

Per https://github.com/bower/bower.json-spec/pull/43 :
> Use source files with module exports and imports over pre-built distribution files.

Also, the example in that PR includes
/sass/motion.scss in and excludes
/dist/movement.css & /dist/movement.min.css
from its `main`.

bower.json: Set moduleType & use non-dist video.js

Again, see https://github.com/bower/bower.json-spec/pull/43
2015-05-13 22:59:22 -07:00
heff 349ff89541 v5.0.0-15 2015-05-14 05:47:16 +00:00
heff 2fc8968002 @heff added support for fluid widths, aspect ratios, and metadata defaults. closes #1952 2015-05-13 22:45:01 -07:00
Matthew 6128305cc3 v5.0.0-14 2015-05-13 05:02:43 +00:00
Matthew McClure 0e63261db6 Merge pull request #2145 from cvrebert/patch-3
bower.json: Remove font files from `main`
2015-05-12 22:00:53 -07:00
Chris Rebert c740115821 bower.json: Remove font files from main
Per https://github.com/bower/bower.json-spec/pull/43 :
> font files [...] are not `main` files as they are not entry-points.

(See also the new example in the spec)
2015-05-12 19:30:50 -07:00
heff d8e7d13fd0 build: Updated test configuration for new Savage testing 2015-05-12 14:05:08 -07:00
heff fbdb3f1ce2 v5.0.0-13 2015-05-12 20:17:33 +00:00
heff 4a62ebb042 Added travis vars for sauce testing 2015-05-12 13:15:24 -07:00
heff b87fb3ce32 v5.0.0-12 2015-05-12 19:42:16 +00:00
heff fd50bd0921 Update travis yml for Savage pull request testing 2015-05-12 12:39:57 -07:00
Gary Katsevman b65bad8f20 @gkatsev added get and set global options methods. closes #2115 2015-05-06 14:12:17 -04:00
eXon e5595b1e38 @eXon began Tech 2.0 work, improved how tech events are handled by the player. closes #2057
closes #1485
2015-05-06 14:02:01 -04:00
Brandon de843affb7 v5.0.0-11 2015-05-06 16:12:56 +00:00
Brandon Bay 9c99def186 @bc-bbay fixed instance where progress bars would go passed 100%. closes #2040 2015-05-06 12:10:57 -04:00
159 arquivos alterados com 53427 adições e 3291 exclusões
+1
Ver Arquivo
@@ -12,6 +12,7 @@
"undef" : true,
"laxbreak" : true,
"esnext" : true,
"eqeqeq" : true,
"predef" : [
"_V_",
"goog",
+13 -8
Ver Arquivo
@@ -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=
+12
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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",
+9 -11
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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",
+14802
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
BIN
Ver Arquivo
Arquivo binário não exibido.
+40
Ver Arquivo
@@ -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="&#x20;" d="" horiz-adv-x="256" />
<glyph unicode="&#x25b6;" d="M170.667 373.334v-298.666l234.667 149.333z" />
<glyph unicode="&#xe601;" 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="&#xe603;" 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="&#xe61a;" 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="&#xe64b;" 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="&#xe64c;" 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="&#xe650;" 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="&#xe692;" 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="&#xe6e2;" 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="&#xe6f2;" 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="&#xe713;" 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="&#xe80d;" 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="&#xe81e;" 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="&#xe821;" d="M85.334 96l181.333 128-181.333 128v-256zM277.334 352v-256l181.334 128-181.333 128z" />
<glyph unicode="&#xe822;" d="M234.667 96v256l-181.333-128 181.333-128zM245.333 224l181.333-128v256l-181.333-128z" />
<glyph unicode="&#xe825;" 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="&#xe830;" d="M128 74.666h85.334v298.666h-85.334v-298.666zM298.666 373.334v-298.666h85.334v298.666h-85.334z" />
<glyph unicode="&#xe831;" 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="&#xe832;" 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="&#xe834;" 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="&#xe835;" 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="&#xe840;" d="M128 96l181.333 128-181.333 128v-256zM341.334 352v-256h42.666v256h-42.666z" />
<glyph unicode="&#xe841;" d="M128 352h42.666v-256h-42.666zM202.667 224l181.333-128v256z" />
<glyph unicode="&#xe849;" 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="&#xe84a;" d="M149.333 288v-128h85.333l106.666-106.666v341.334l-106.666-106.666h-85.334z" />
<glyph unicode="&#xe84b;" 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="&#xe84c;" 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="&#xe866;" 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="&#xe891;" 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="&#xe8b1;" 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

BIN
Ver Arquivo
Arquivo binário não exibido.
BIN
Ver Arquivo
Arquivo binário não exibido.
+26
Ver Arquivo
@@ -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.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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.": "Не беше намерен съвместим източник за това видео."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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 lutilizzo di impostazioni non supportate dal browser.",
"No compatible source was found for this video.": "Non ci sono fonti compatibili per questo filmato."
});
+26
Ver Arquivo
@@ -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.": "この動画に対して互換性のあるソースが見つかりませんでした"
});
+26
Ver Arquivo
@@ -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.": "비디오에 호환되지 않는 소스가 있습니다."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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.": "Совместимые источники для этого видео отсутствуют."
});
+26
Ver Arquivo
@@ -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."
});
+26
Ver Arquivo
@@ -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ı."
});
+26
Ver Arquivo
@@ -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.": "Сумісні джерела для цього відео відсутні."
});
+26
Ver Arquivo
@@ -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."
});
+27
Ver Arquivo
@@ -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.": "视频已加密,无法解密。"
});
+27
Ver Arquivo
@@ -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.": "影片已加密,無法解密。"
});
+16879
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
BIN
Ver Arquivo
Arquivo binário não exibido.
+946
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+1
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
BIN
Ver Arquivo
Arquivo binário não exibido.
+16755
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+211
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+22
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+1
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+28 -10
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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",
+10 -2
Ver Arquivo
@@ -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>
+34 -3
Ver Arquivo
@@ -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;
+4
Ver Arquivo
@@ -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;
+10 -6
Ver Arquivo
@@ -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;
}
-25
Ver Arquivo
@@ -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;
}
+24 -14
Ver Arquivo
@@ -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
+3 -2
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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 -2
Ver Arquivo
@@ -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'
});
}
+3 -2
Ver Arquivo
@@ -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;
+2 -2
Ver Arquivo
@@ -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'
+3 -3
Ver Arquivo
@@ -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}`);
}
}
+3 -3
Ver Arquivo
@@ -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)
+13 -12
Ver Arquivo
@@ -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}`;
}
+9 -10
Ver Arquivo
@@ -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;
+2 -2
Ver Arquivo
@@ -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;
-130
Ver Arquivo
@@ -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;
-125
Ver Arquivo
@@ -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;
+2 -2
Ver Arquivo
@@ -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 -2
Ver Arquivo
@@ -1,5 +1,4 @@
import * as Events from './events';
import * as Lib from './lib';
import * as Events from './utils/events.js';
var EventEmitter = function() {};
-2
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
};
+2 -2
Ver Arquivo
@@ -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) {
+11 -8
Ver Arquivo
@@ -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;
+4 -3
Ver Arquivo
@@ -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;
+5 -4
Ver Arquivo
@@ -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
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+2 -2
Ver Arquivo
@@ -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
+10 -7
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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';
-28
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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}&amp;`;
Object.getOwnPropertyNames(flashVars).forEach(function(key){
flashVarsString += `${key}=${flashVars[key]}&amp;`;
});
}
// 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
Ver Arquivo
@@ -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