diff options
author | Drew DeVault <sir@cmpwn.com> | 2017-10-02 23:36:54 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2017-10-02 23:36:54 -0400 |
commit | cf8d3f6895ea0db85c848090471235f84ed51579 (patch) | |
tree | e829ca710a33a2af154d30115c8762ea2b0f1554 | |
parent | Update home page video (diff) | |
download | sway-cf8d3f6895ea0db85c848090471235f84ed51579.tar.gz sway-cf8d3f6895ea0db85c848090471235f84ed51579.tar.zst sway-cf8d3f6895ea0db85c848090471235f84ed51579.zip |
Rewrite website
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | _config.yml | 2 | ||||
-rw-r--r-- | _layouts/master.html | 89 | ||||
m--------- | _sass/bootstrap | 0 | ||||
-rw-r--r-- | assets/patreon.png | bin | 0 -> 3086 bytes | |||
-rw-r--r-- | css/master.scss | 45 | ||||
-rw-r--r-- | css/video-js.css | 1234 | ||||
-rw-r--r-- | index.html | 33 | ||||
-rw-r--r-- | js/video.js | 22383 |
10 files changed, 23717 insertions, 73 deletions
@@ -1 +1,2 @@ | |||
1 | _site/ | 1 | _site/ |
2 | .sass-cache | ||
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..6be3ac41 --- /dev/null +++ b/.gitmodules | |||
@@ -0,0 +1,3 @@ | |||
1 | [submodule "_sass/bootstrap"] | ||
2 | path = _sass/bootstrap | ||
3 | url = https://github.com/twbs/bootstrap | ||
diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..42f5e4da --- /dev/null +++ b/_config.yml | |||
@@ -0,0 +1,2 @@ | |||
1 | exclude: | ||
2 | - _sass/bootstrap/ | ||
diff --git a/_layouts/master.html b/_layouts/master.html index 3bd18e06..2c94a634 100644 --- a/_layouts/master.html +++ b/_layouts/master.html | |||
@@ -1,59 +1,38 @@ | |||
1 | <!doctype html> | 1 | <!doctype html> |
2 | <html> | 2 | <html> |
3 | <head> | 3 | <head> |
4 | <meta charset="utf-8" /> | 4 | <meta charset="utf-8" /> |
5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
6 | <link rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css" /> | 6 | <link rel="stylesheet" href="/css/master.css" /> |
7 | <link rel="stylesheet" href="/css/master.css" /> | 7 | <title>{{ page.title }}</title> |
8 | <title>{{ page.title }}</title> | 8 | </head> |
9 | </head> | 9 | <body> |
10 | <body> | 10 | <div class="container"> |
11 | <div class="container"> | 11 | <nav class="navbar navbar-toggleable-md navbar-light"> |
12 | <div class="row"> | 12 | <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> |
13 | <div class="col-md-4"> | 13 | <span class="navbar-toggler-icon"></span> |
14 | <h1> | 14 | </button> |
15 | <img src="/assets/logo.png" id="logo" alt="Sway" /> | 15 | <a class="navbar-brand" href="/">Sway</a> |
16 | </h1> | 16 | <div class="collapse navbar-collapse" id="navbarSupportedContent"> |
17 | <p> | 17 | <ul class="navbar-nav mr-auto"> |
18 | Sway is a drop-in replacement for the <a href="http://i3wm.org/">i3 | 18 | <li class="nav-item"> |
19 | window manager</a>, but for Wayland instead of X11. It works | 19 | <a class="nav-link" href="https://github.com/swaywm/sway/releases">Releases ≫</a> |
20 | with your existing i3 configuration and supports most of i3's features, | 20 | </li> |
21 | and a few extras. | 21 | <li class="nav-item"> |
22 | </p> | 22 | <a class="nav-link" href="https://github.com/swaywm/sway">Source Code ≫</a> |
23 | </div> | 23 | </li> |
24 | <div class="col-md-8"> | 24 | <li class="nav-item"> |
25 | {{ content }} | 25 | <a class="nav-link" href="https://github.com/SirCmpwn/sway/wiki">Wiki ≫</a> |
26 | </div> | 26 | </li> |
27 | </div> | 27 | <li class="nav-item"> |
28 | <a class="nav-link" href="http://webchat.freenode.net/?channels=sway&uio=d4">Support Chat ≫</a> | ||
29 | </li> | ||
30 | </ul> | ||
28 | </div> | 31 | </div> |
29 | <nav class="navbar navbar-dark navbar-fixed-bottom"> | 32 | </nav> |
30 | <div class="container"> | 33 | <div class="main"> |
31 | <a href="/" class="navbar-brand">Sway</span> | 34 | {{ content }} |
32 | <ul class="nav navbar-nav"> | 35 | </div> |
33 | <li class="nav-item"> | 36 | </div> |
34 | <a class="nav-link" | 37 | </body> |
35 | href="https://github.com/SirCmpwn/sway/releases">Releases</a> | ||
36 | </li> | ||
37 | <li class="nav-item"> | ||
38 | <a class="nav-link" | ||
39 | href="https://github.com/SirCmpwn/sway">Source code</a> | ||
40 | </li> | ||
41 | <li class="nav-item"> | ||
42 | <a class="nav-link" | ||
43 | href="/roadmap">Roadmap</a> | ||
44 | </li> | ||
45 | <li class="nav-item"> | ||
46 | <a class="nav-link" | ||
47 | href="https://github.com/SirCmpwn/sway/wiki">FAQ</a> | ||
48 | </li> | ||
49 | <li class="nav-item"> | ||
50 | <a class="nav-link" | ||
51 | href="http://webchat.freenode.net/?channels=sway&uio=d4">IRC channel</a> | ||
52 | </li> | ||
53 | </ul> | ||
54 | </div> | ||
55 | </nav> | ||
56 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> | ||
57 | <script src="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.js"></script> | ||
58 | </body> | ||
59 | </html> | 38 | </html> |
diff --git a/_sass/bootstrap b/_sass/bootstrap new file mode 160000 | |||
Subproject 65ffb1c3b6e94440812a2e228cb8e8be512652e | |||
diff --git a/assets/patreon.png b/assets/patreon.png new file mode 100644 index 00000000..291b7bcf --- /dev/null +++ b/assets/patreon.png | |||
Binary files differ | |||
diff --git a/css/master.scss b/css/master.scss index 2b837d96..cd3fd54f 100644 --- a/css/master.scss +++ b/css/master.scss | |||
@@ -1,35 +1,46 @@ | |||
1 | --- | 1 | --- |
2 | --- | 2 | --- |
3 | 3 | ||
4 | body { | 4 | @import "bootstrap/scss/bootstrap"; |
5 | background-color: #000; | 5 | |
6 | color: #fff; | 6 | html { |
7 | margin-top: 1rem; | 7 | height: 100%; |
8 | margin-bottom: 5rem; | ||
9 | } | 8 | } |
10 | 9 | ||
11 | video { | 10 | body { |
12 | max-width: 100%; | 11 | background: linear-gradient(to bottom right, #75d3e8, #3c84ac); |
12 | background-size: cover; | ||
13 | background-repeat: no-repeat; | ||
14 | background-attachment: fixed; | ||
15 | margin: 0; | ||
16 | height: 100%; | ||
13 | } | 17 | } |
14 | 18 | ||
15 | .text-center { | 19 | .navbar-light { |
16 | text-align: center; | 20 | margin-bottom: 1rem; |
21 | |||
22 | .navbar-nav .nav-link { | ||
23 | color: rgba(0, 0, 0, 0.8); | ||
24 | text-decoration: underline; | ||
25 | } | ||
17 | } | 26 | } |
18 | 27 | ||
19 | hr { | 28 | .main a { |
20 | border-color: white; | 29 | color: darken(#014c8c, 10); |
30 | text-decoration: underline; | ||
21 | } | 31 | } |
22 | 32 | ||
23 | .table-success { | 33 | video { |
24 | background-color: green; | 34 | max-width: 100%; |
35 | box-shadow: 0 0 3px 3px #444; | ||
25 | } | 36 | } |
26 | 37 | ||
27 | .table-danger { | 38 | .text-center { |
28 | background-color: darken(red, 10); | 39 | text-align: center; |
29 | } | 40 | } |
30 | 41 | ||
31 | nav { | 42 | hr { |
32 | background: black; | 43 | border-color: white; |
33 | } | 44 | } |
34 | 45 | ||
35 | #logo { | 46 | #logo { |
diff --git a/css/video-js.css b/css/video-js.css new file mode 100644 index 00000000..faedac77 --- /dev/null +++ b/css/video-js.css | |||
@@ -0,0 +1,1234 @@ | |||
1 | .video-js .vjs-big-play-button:before, .video-js .vjs-control:before, .video-js .vjs-modal-dialog, .vjs-modal-dialog .vjs-modal-dialog-content { | ||
2 | position: absolute; | ||
3 | top: 0; | ||
4 | left: 0; | ||
5 | width: 100%; | ||
6 | height: 100%; } | ||
7 | |||
8 | .video-js .vjs-big-play-button:before, .video-js .vjs-control:before { | ||
9 | text-align: center; } | ||
10 | |||
11 | @font-face { | ||
12 | font-family: VideoJS; | ||
13 | src: url("../font/1.5.1/VideoJS.eot?#iefix") format("eot"); } | ||
14 | |||
15 | @font-face { | ||
16 | font-family: VideoJS; | ||
17 | src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAA4wAAoAAAAAFfAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAD4AAABWUZFeBGNtYXAAAAE0AAAAOgAAAUriLxC2Z2x5ZgAAAXAAAAnnAAAO5OV/F/5oZWFkAAALWAAAACsAAAA2C4eUa2hoZWEAAAuEAAAAGAAAACQOogcfaG10eAAAC5wAAAAPAAAAeNIAAABsb2NhAAALrAAAAD4AAAA+MMgtQm1heHAAAAvsAAAAHwAAACABLwB5bmFtZQAADAwAAAElAAACCtXH9aBwb3N0AAANNAAAAPkAAAF5vawAenicY2BkZ2CcwMDKwMFSyPKMgYHhF4RmjmEIZzzHwMDEwMrMgBUEpLmmMDh8ZPwoyw7iLmSHCDOCCADu/Qo9AAB4nGNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZgYGD7K/v8PUvCREUTzM0DVAwEjG8OIBwCOWgbUAAB4nI1XfVBU1xV/574vlsUlj/14grDs48FuAgaR3X2LEnY3UZSgEkTwAySAgkIwI8bRfFDjTszYCWRMW9lNa4y2meokmq+2k5ia0dpkmknbkWgSSW3GyaaNf0RTx0wxX7A3Pe/tQmIgHXf3vXvvueeee+45v3POXQYY/PCD/CBDGAYkIE2sxg+OXSJmhmH1OaFX6MU5C5PDMCZi5Rg2i+ELGSthwM14NCbgYGSBIZfhFA1H6Zu0OS0NDkMVfg+npdFm+maCvigI0JBIQIMg0BdJGdTj9ylj7nr+b97+Hl8C1+H2xNAvjPqxjIgaKtItICkSnIISeo40QQls4xxjlzgHsnGGvi7BxQiMlSlkPMhfCh67rAUEUQ6CHxW2O7JARCkKnlUQ7UEIyAEQZe4MdDW9xr5OPFuKbubpRxcPDY8da4MOelDfAYJLW+sGKn/Vlmjfv5+NdB4oOfTazJn3tGxZtL9xFNZX7PPRUbjcRg/SMB2EL+gblXn7shbO/WUbF9u/H5XQ9eKO8iMMr9tY35qYoRi20wGuXV/CHaGDk2fdgHwCk5HUXQpCcgHfBV2NjV3jkq4PHTSUSBwuOQALvxPAps6fiftk6P6yJpcm5bB4dFkgoh195mbiSTnkL3jupq7jh4ZZdvjQRVB4PPx3SsVTu5D/6kd85RU66ttXAeuuXYN1E/Y2sMMzZkZiZNRZlRS/ynr9Xr8Cql2RVNbutXslYo7B9ngsFqcDbCQO22PxeIxcpgMxkh6PjUdwkvw6hvRpZeoCFKshDQzJVr++DWyLx+hAXJcGp3TJMV1ME45xCNvHLsWRrpOZSduOoG0zERuIIwuIkhNkBREglQKLiODD45FQE0BTiE214xE2wp8zOt9NjH3GRtDMk7Ehoq2tzCzGxdyMEQJuD0qGIrQ58ApoWQE3D2h1h6zwuB14wYFIDAA5CZ11jT+92gFZ7B7/p7+hV8jFxBl4aG03wLiVXtBbCylLfIJzkPUAvWAw0yvsVdKdBbC6nnruP/RFkHqWJLZ2Auxdtgy+6qTf7l1WswTJcJ6mGVxwXj92UtfU2WXUNX+qBUCxK6D4FR4f/cufG1sZbiSkMcwdMdoxBxTTEXIp4SCXMNhHoFjvTTFP4vkoPReNRmPRCTwa+3qY0DR7qn7Vjh612wRRTaI04HWCnZ+gIzvS/ZJP0+mynphCui4hzmG0id6+aLSv2BV3FQMYDTHrlGQ/SZ+q4ZdF8aLa5Ar8GW3tVNKEj13cF0buMaesx1i9CL/Uo1tM0h+74o9HjQ+UcPaxy8mH9ccwK8KpKA3rHdIUjTKpfIBxuokpxUGBIILm84ATvHh8tAIe2iZj8KvYwUOXawHMVNgxZvlwSa0z8Zkokkxn3ey2nYTsbMO3mPh8cji7zklsPLD9a9f2s2w/uSt/FgSytWzw5bmS3PielU1P56aGrlz6NzlnbT8h/Wtb+1OxIqxBbC9g7kINUbtAEDxsKWSCe46eltCPmaiUxy2IrODIB8EmixaQrU4IAQ6THg6BFpAdWsCquT16DkL9ccIC/FGeP5AuiDExe8bx+QtzWVsmHcm0kdzqecdn5IhRkTc/zfNPm3ns5sw4Pq86l9gyofh6jkTF5iFChjYbbzZQWFvYb8qZAWyGiV9ya+5bFgnzpuWt3FuX8KYMmsiYZepPseBgGhZcOMt0+4Q8fDOTftJjHIuhdaLsFXFM9AclTi9jbGRq8ZvIOykZei77kfo53eoppVPovbGiyV63p/p/dkWETTjmhjTIm8RP284b04bcNYlRsvO6Gp2JeaiIueVHsgJGF2aASlCQLuG8EsBomzb++/AXmwhaOoLhL7iQ4/uc449gWJ56/XWDARn74v/PL1bRBB4TBEyYrqezSkUPHaWjPWCm13ogAzJ66LVpbTEuXccDZlyXxBQ/IrzKOPS7gAkkIyZ0N6joE6M246aDsO1kgucTJ/EdFWA5pbAcTfoSP4hJeBCni7nEn5IclL4kpDgmMMuH8Kpk0+WrBUIeKCyWS0nPVz7NW86Hnl55GxR5KB3+9tszL+wVRulXNTUn6D8SJvIl3PzP46eZST/tQTllTDXTzmxCaTYna7eJAqcWuD1ulBXQsMz5fQEBCfowCF5FVDF/2yysB9OW5veVEtRAFOy41FoeJEiAOZhDiFstsKAwJ8Hijs72q1jWvWx+uKU5XFZDLx189OK8ojW1u0By5dtLHUN/rwkte68PnhnYVbt0bvWiub9w1+f4C0L3hIuXZ8+xlVSt0eb3tgQsmVZnem5R3U0uf/fmFdqiLTvY3nPnet5/v4f9pLB6QX2krnnFQ1tXtN+2ePlAaUNWcfiWwrncn4ca9ml3hFeHHm+u2bq4MhxUZs3bMH/3jgaPUtlVunFjg2/8yRzf3cHsssKZqlnOqyCWworWykW9lXnspk0ffrjpfCreIpjPWbwnFxt3PAkcQgkUuH1auUMf+txJQ0hK1k1zsNaqQdaLMxfoq9AGGxtJQ+fGw53cE/TY8pWhJruZHiMAcCexFS/eGDp6hntiXGE/gvI7163b29ExfiHxNsnqub/a6/QmPoAn4GpZ2c9cZRX5/57IWUNYuubiQBAddhuxAKe6PA5vuV5dkk0VXkMM3zk42W3Awrgka8LQgjZY+tQIffd5+vnHasnHL/cczldyS4r79i6su6Nu9oPQ8lbaid2Pt9/bXtTTynevq7bkPkITV47d+3NugOzo4M3y77Zxbnb2nhWrl0T/kO4u3H1ig33e1lD6JDYjiKkCHOioF0pZv6T6gxxipxLNhFc8xERA48vq5ZfXdL/QV6c8W3PfwjIsZyI3Csvo72e4FpTVwTv/UYNAKtY+8MB84vogZ1Xr5lW38iJdPZ74xunzO4Gk7BARIkytjlyCoPVoIb3IluMfAYRhEoAO2aGXKc2TNAJaSwdzQEeq7jC7TWYF2Y2jrEIXlyVEhunBs5t7K62a7Z6qB0923/+vPT2v7mwpqV/mTEsTiCB5zz735HOP9VbVWtKKZK08uDJ7vcQN02HogGegY5iNnKUHh12ti9/zzHvsauy+tx+e375j94LuA64MV/5MQbZVNT95/re7jlxZVaVuW5Nffsd9TXfOpXcv6m2Bn3x6FgXg/oz+P0h/ce8g2mTEWxVTzzQzrTruNCcRdbu6VY87gLVXc4uSjXfosak7XxWM4oyl+ockmzCFhJXaGwK8e6sCW2T3sLmPnh5qSZtx9JHFL6QBHGnsTjdtWQ8PFygWtQTIkrI84NILfQSC65FUMFsnOYFHEoSmUCD49a4rt3985PTsd8GzB/5KEnzmhhORgVOZPM+yb5KmpRu38jQqviH6826Lrdrxx6DZdFPo2fVbTiy9AUpDJ3SxGYvpK7u+Rhz8D4BCxssAeJxjYGRgYABi/vcdWfH8Nl8ZuNkZQODSliXbkWl2BrA4BwMTiAIAKDsJfgB4nGNgZGBgZwCChWASxGZkQAVyABOTANd4nGNnYGBgHwAMADNUANMAAAAAAAAOAFAAZgCyAMYA5gEeAUgBdAGcAfICLgKOAroDCgOOA7AD6gQ4BHwEuAToBQwFogXoBjYGbAbaB3IAAHicY2BkYGCQY8hlYGcAASYg5gJCBob/YD4DABa6AakAeJxdkE1qg0AYhl8Tk9AIoVDaVSmzahcF87PMARLIMoFAl0ZHY1BHdBJIT9AT9AQ9RQ9Qeqy+yteNMzDzfM+88w0K4BY/cNAMB6N2bUaPPBLukybCLvleeAAPj8JD+hfhMV7hC3u4wxs7OO4NzQSZcI/8Ltwnfwi75E/hAR7wJTyk/xYeY49fYQ/PztM+jbTZ7LY6OWdBJdX/pqs6NYWa+zMxa13oKrA6Uoerqi/JwtpYxZXJ1coUVmeZUWVlTjq0/tHacjmdxuL90OR8O0UEDYMNdtiSEpz5XQGqzlm30kzUdAYFFOb8R7NOZk0q2lwAyz1i7oAr1xoXvrOgtYhZx8wY5KRV269JZ5yGpmzPTjQhvY9je6vEElPOuJP3mWKnP5M3V+YAAAB4nG2P2XLCMAxFfYE4CWlZSveFP8hHOY4gHhw79VLav68hMNOH6kG60mg5YhM22pr9b1vGMMEUM2TgyFGgxBwVbnCLBZZYYY07bHCPBzziCc94wSve8I4PbGeDFj/VydVSOakpG0T0VH1ZHXuq+xhoftHaHq+yV+21o1P7brWLWnvpiExNJpBb/i18q8D9ZxSOcj8oY8iVPjZBBU2+kGIIypokuqTI+cx3qXMq7Z6PQIsx1DYGrQxtLul50YV50rVcCiNJc0enX4qdkNRYe8j2g46+SIMHapXJw1GFdIWH2DfalQknZeTDWsRW2bqlBK3ORIz9AqJUapQAAAA=) format("woff"), url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAAKAIAAAwAgT1MvMlGRXgQAAAEoAAAAVmNtYXDiLxC2AAAB+AAAAUpnbHlm5X8X/gAAA4QAAA7kaGVhZAuHlGsAAADQAAAANmhoZWEOogcfAAAArAAAACRobXR40gAAAAAAAYAAAAB4bG9jYTDILUIAAANEAAAAPm1heHABLwB5AAABCAAAACBuYW1l1cf1oAAAEmgAAAIKcG9zdL2sAHoAABR0AAABeQABAAAHAAAAAKEHAAAAAAAHAAABAAAAAAAAAAAAAAAAAAAAHgABAAAAAQAAD+/W/l8PPPUACwcAAAAAANK0pLcAAAAA0rSktwAAAAAHAAcAAAAACAACAAAAAAAAAAEAAAAeAG0ABwAAAAAAAgAAAAoACgAAAP8AAAAAAAAAAQcAAZAABQAIBHEE5gAAAPoEcQTmAAADXABXAc4AAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA8QHxHQcAAAAAoQcAAAAAAAABAAAAAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAAAAAAAwAAAAMAAAAcAAEAAAAAAEQAAwABAAAAHAAEACgAAAAGAAQAAQACAADxHf//AAAAAPEB//8AAA8AAAEAAAAAAAAAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AUABmALIAxgDmAR4BSAF0AZwB8gIuAo4CugMKA44DsAPqBDgEfAS4BOgFDAWiBegGNgZsBtoHcgAAAAEAAAAABYsFiwACAAABEQECVQM2BYv76gILAAADAAAAAAZrBmsAAgAOABoAAAkCEwQAAxIABSQAEwIAASYAJzYANxYAFwYAAusBwP5Alf7D/loICAGmAT0BPQGmCAj+Wv7D/f6uBgYBUv39AVIGBv6uAjABUAFQAZsI/lr+w/7D/loICAGmAT0BPQGm+sgGAVL9/QFSBgb+rv39/q4AAAACAAAAAAVABYsAAwAHAAABIREpAREhEQHAASv+1QJVASsBdQQW++oEFgAAAAQAAAAABiAGIAAGABMAJAAnAAABLgEnFRc2NwYHFz4BNSYAJxUWEgEHASERIQERAQYHFT4BNxc3AQcXBNABZVW4A7sCJ3ElKAX+3+Wlzvu3XwFh/p8BKwF1AT5MXU6KO5lf/WCcnAOAZJ4rpbgYGGpbcUacVPQBYziaNP70Aetf/p/+QP6LAfb+wjsdmhJEMZhfBJacnAAAAQAAAAAEqwXWAAUAAAERIQERAQILASoBdv6KBGD+QP6LBKr+iwAAAAIAAAAABWYF1gAGAAwAAAEuAScRPgEBESEBEQEFZQFlVFRl/BEBKwF1/osDgGSeK/2mK54BRP5A/osEqv6LAAADAAAAAAYgBg8ABQAMABoAABMRIQERAQUuAScRPgEDFRYSFwYCBxU2ADcmAOABKwF1/osCxQFlVVVluqXOAwPOpeUBIQUF/t8EYP5A/osEqv6L4GSeK/2mK54C85o0/vS1tf70NJo4AWL19QFiAAAABAAAAAAFiwWLAAUACwARABcAAAEjESE1IwMzNTM1IQEjFSERIwMVMxUzEQILlgF24JaW4P6KA4DgAXaW4OCWAuv+ipYCCuCW/ICWAXYCoJbgAXYABAAAAAAFiwWLAAUACwARABcAAAEzFTMRIRMjFSERIwEzNTM1IRM1IxEhNQF14Jb+iuDgAXaWAcCW4P6KlpYBdgJV4AF2AcCWAXb76uCWAcDg/oqWAAAAAAIAAAAABdYF1gAPABMAAAEhDgEHER4BFyE+ATcRLgEDIREhBUD8gD9VAQFVPwOAP1UBAVU//IADgAXVAVU//IA/VQEBVT8DgD9V++wDgAAABgAAAAAGawZrAAcADAATABsAIAAoAAAJASYnDgEHASUuAScBBSEBNhI3JgUBBgIHFhchBR4BFwEzARYXPgE3AQK+AWROVIfwYQESA4416aH+7gLl/dABelxoAQH8E/7dXGgBAQ4CMP3kNemhARJ4/t1OVIfwYf7uA/ACaBIBAVhQ/id3pfY+/idL/XNkAQGTTU0B+GT+/5NNSEul9j4B2f4IEgEBWFAB2QAAAAUAAAAABmsF1gAPABMAFwAbAB8AAAEhDgEHER4BFyE+ATcRLgEBIRUhASE1IQUhNSE1ITUhBdX7VkBUAgJUQASqQFQCAlT7FgEq/tYC6v0WAuoBwP7WASr9FgLqBdUBVT/8gD9VAQFVPwOAP1X9rJX+1ZWVlZaVAAMAAAAABiAF1gAPACcAPwAAASEOAQcRHgEXIT4BNxEuAQEjNSMVMzUzFRQGByMuAScRPgE3Mx4BFQUjNSMVMzUzFQ4BByMuATURNDY3Mx4BFwWL++o/VAICVD8EFj9UAgJU/WtwlZVwKiDgICoBASog4CAqAgtwlZVwASog4CAqKiDgICoBBdUBVT/8gD9VAQFVPwOAP1X99yXgJUogKgEBKiABKiAqAQEqIEol4CVKICoBASogASogKgEBKiAAAAYAAAAABiAE9gADAAcACwAPABMAFwAAEzM1IxEzNSMRMzUjASE1IREhNSERFSE14JWVlZWVlQErBBX76wQV++sEFQM1lv5AlQHAlf5Alv5AlQJVlZUAAAABAAAAAAYgBmwALgAAASIGBwE2NCcBHgEzPgE3LgEnDgEHFBcBLgEjDgEHHgEXMjY3AQYHHgEXPgE3LgEFQCtKHv3sBwcCDx5OLF9/AgJ/X19/Agf98R5OLF9/AgJ/XyxOHgIUBQEDe1xcewMDewJPHxsBNxk2GQE0HSACf19ffwICf18bGf7NHCACf19ffwIgHP7KFxpcewICe1xdewAAAgAAAAAGWQZrAEMATwAAATY0Jzc+AScDLgEPASYvAS4BJyEOAQ8BBgcnJgYHAwYWHwEGFBcHDgEXEx4BPwEWHwEeARchPgE/ATY3FxY2NxM2JicFLgEnPgE3HgEXDgEFqwUFngoGB5YHGQ26OkQcAxQP/tYPFAIcRTm6DRoHlQcFC50FBZ0LBQeVBxoNujlFHAIUDwEqDxQCHEU5ug0aB5UHBQv9OG+UAgKUb2+UAgKUAzckSiR7CRoNAQMMCQVLLRzGDhEBAREOxhwtSwUJDP79DBsJeyRKJHsJGg3+/QwJBUstHMYOEQEBEQ7GHC1LBQkMAQMMGwlBApRvb5QCApRvb5QAAAAAAQAAAAAGawZrAAsAABMSAAUkABMCACUEAJUIAaYBPQE9AaYICP5a/sP+w/5aA4D+w/5aCAgBpgE9AT0BpggI/loAAAACAAAAAAZrBmsACwAXAAABBAADEgAFJAATAgABJgAnNgA3FgAXBgADgP7D/loICAGmAT0BPQGmCAj+Wv7D/f6uBgYBUv39AVIGBv6uBmsI/lr+w/7D/loICAGmAT0BPQGm+sgGAVL9/QFSBgb+rv39/q4AAAMAAAAABmsGawALABcAIwAAAQQAAxIABSQAEwIAASYAJzYANxYAFwYAAw4BBy4BJz4BNx4BA4D+w/5aCAgBpgE9AT0BpggI/lr+w/3+rgYGAVL9/QFSBgb+rh0Cf19ffwICf19ffwZrCP5a/sP+w/5aCAgBpgE9AT0BpvrIBgFS/f0BUgYG/q79/f6uAk9ffwICf19ffwICfwAAAAQAAAAABiAGIAAPABsAJQApAAABIQ4BBxEeARchPgE3ES4BASM1IxUjETMVMzU7ASEeARcRDgEHITczNSMFi/vqP1QCAlQ/BBY/VAICVP1rcJVwcJVwlgEqICoBASog/tZwlZUGIAJUP/vqP1QCAlQ/BBY/VPyClZUBwLu7ASog/tYgKgFw4AACAAAAAAZrBmsACwAXAAABBAADEgAFJAATAgATBwkBJwkBNwkBFwEDgP7D/loICAGmAT0BPQGmCAj+Wjhp/vT+9GkBC/71aQEMAQxp/vUGawj+Wv7D/sP+WggIAaYBPQE9Aab8EWkBC/71aQEMAQxp/vUBC2n+9AABAAAAAAXWBrYAFgAAAREJAREeARcOAQcuAScjFgAXNgA3JgADgP6LAXW+/QUF/b6+/QWVBgFR/v4BUQYG/q8FiwEq/ov+iwEqBP2/vv0FBf2+/v6vBgYBUf7+AVEAAAABAAAAAAU/BwAAFAAAAREjIgYdASEDIxEhESMRMzU0NjMyBT+dVjwBJSf+/s7//9Ctkwb0/vhISL3+2P0JAvcBKNq6zQAAAAAEAAAAAAaOBwAAMABFAGAAbAAAARQeAxUUBwYEIyImJyY1NDY3NiUuATU0NwYjIiY1NDY3PgEzIQcjHgEVFA4DJzI2NzY1NC4CIyIGBwYVFB4DEzI+AjU0LgEvASYvAiYjIg4DFRQeAgEzFSMVIzUjNTM1MwMfQFtaQDBI/uqfhOU5JVlKgwERIB8VLhaUy0g/TdNwAaKKg0pMMUVGMZImUBo1Ij9qQCpRGS8UKz1ZNjprWzcODxMeChwlThAgNWhvUzZGcX0Da9XVadTUaQPkJEVDUIBOWlN6c1NgPEdRii5SEipAKSQxBMGUUpo2QkBYP4xaSHNHO0A+IRs5ZjqGfVInITtlLmdnUjT8lxo0Xj4ZMCQYIwsXHTgCDiQ4XTtGazsdA2xs29ts2QADAAAAAAaABmwAAwAOACoAAAERIREBFgYrASImNDYyFgERIRE0JiMiBgcGFREhEhAvASEVIz4DMzIWAd3+tgFfAWdUAlJkZ6ZkBI/+t1FWP1UVC/63AgEBAUkCFCpHZz+r0ASP/CED3wEySWJik2Fh/N39yAISaXdFMx4z/dcBjwHwMDCQIDA4H+MAAAEAAAAABpQGAAAxAAABBgcWFRQCDgEEIyAnFjMyNy4BJxYzMjcuAT0BFhcuATU0NxYEFyY1NDYzMhc2NwYHNgaUQ18BTJvW/tKs/vHhIyvhsGmmHyEcKypwk0ROQk4seQFbxgi9hoxgbWAlaV0FaGJFDhyC/v3ut22RBIoCfWEFCxexdQQmAyyOU1hLlbMKJiSGvWYVOXM/CgAAAAEAAAAABYAHAAAiAAABFw4BBwYuAzURIzU+BDc+ATsBESEVIREUHgI3NgUwUBewWWitcE4hqEhyRDAUBQEHBPQBTf6yDSBDME4Bz+0jPgECOFx4eDoCINcaV11vVy0FB/5Y/P36HjQ1HgECAAEAAAAABoAGgABKAAABFAIEIyInNj8BHgEzMj4BNTQuASMiDgMVFBYXFj8BNjc2JyY1NDYzMhYVFAYjIiY3PgI1NCYjIgYVFBcDBhcmAjU0EiQgBBIGgM7+n9FvazsTNhRqPXm+aHfijmm2f1srUE0eCAgGAgYRM9Gpl6mJaz1KDgglFzYyPlYZYxEEzv7OAWEBogFhzgOA0f6fziBdR9MnOYnwlnLIfjpgfYZDaJ4gDCAfGAYXFD1al9mkg6ruVz0jdVkfMkJyVUkx/l5Ga1sBfOnRAWHOzv6fAAAHAAAAAAcABM8ADgAXACoAPQBQAFoAXQAAARE2HgIHDgEHBiYjJyY3FjY3NiYHERQFFjY3PgE3LgEnIwYfAR4BFw4BFxY2Nz4BNy4BJyMGHwEeARcUBhcWNjc+ATcuAScjBh8BHgEXDgEFMz8BFTMRIwYDJRUnAxyEzZRbCA2rgketCAEBqlRoCglxYwF+IiEOIysBAkswHQEECiQ0AgE+YyIhDiIsAQJLMB4BBQokNAE/YyIhDiIsAQJLMB4BBQokNAEBPvmD7kHhqs0s0gEnjgHJAv0FD2a9gIrADwUFAwPDAlVMZ3MF/pUHwgc1HTyWV325PgsJED+oY3G9TAc1HTyWV325PgsJED+oY3G9TAc1HTyWV325PgsJED+oY3G9UmQBZQMMR/61g/kBAAAAAAAQAMYAAQAAAAAAAQAHAAAAAQAAAAAAAgAHAAcAAQAAAAAAAwAHAA4AAQAAAAAABAAHABUAAQAAAAAABQALABwAAQAAAAAABgAHACcAAQAAAAAACgArAC4AAQAAAAAACwATAFkAAwABBAkAAQAOAGwAAwABBAkAAgAOAHoAAwABBAkAAwAOAIgAAwABBAkABAAOAJYAAwABBAkABQAWAKQAAwABBAkABgAOALoAAwABBAkACgBWAMgAAwABBAkACwAmAR5WaWRlb0pTUmVndWxhclZpZGVvSlNWaWRlb0pTVmVyc2lvbiAxLjBWaWRlb0pTR2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20AVgBpAGQAZQBvAEoAUwBSAGUAZwB1AGwAYQByAFYAaQBkAGUAbwBKAFMAVgBpAGQAZQBvAEoAUwBWAGUAcgBzAGkAbwBuACAAMQAuADAAVgBpAGQAZQBvAEoAUwBHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAGgAdAB0AHAAOgAvAC8AZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AAAACAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4EcGxheQtwbGF5LWNpcmNsZQVwYXVzZQt2b2x1bWUtbXV0ZQp2b2x1bWUtbG93CnZvbHVtZS1taWQLdm9sdW1lLWhpZ2gQZnVsbHNjcmVlbi1lbnRlcg9mdWxsc2NyZWVuLWV4aXQGc3F1YXJlB3NwaW5uZXIJc3VidGl0bGVzCGNhcHRpb25zCGNoYXB0ZXJzBXNoYXJlA2NvZwZjaXJjbGUOY2lyY2xlLW91dGxpbmUTY2lyY2xlLWlubmVyLWNpcmNsZQJoZAZjYW5jZWwGcmVwbGF5CGZhY2Vib29rBWdwbHVzCGxpbmtlZGluB3R3aXR0ZXIGdHVtYmxyCXBpbnRlcmVzdBFhdWRpby1kZXNjcmlwdGlvbgAAAAAA) format("truetype"); | ||
18 | font-weight: normal; | ||
19 | font-style: normal; } | ||
20 | |||
21 | .vjs-icon-play, .video-js .vjs-big-play-button, .video-js .vjs-play-control { | ||
22 | font-family: VideoJS; | ||
23 | font-weight: normal; | ||
24 | font-style: normal; } | ||
25 | .vjs-icon-play:before, .video-js .vjs-big-play-button:before, .video-js .vjs-play-control:before { | ||
26 | content: '\f101'; } | ||
27 | |||
28 | .vjs-icon-play-circle { | ||
29 | font-family: VideoJS; | ||
30 | font-weight: normal; | ||
31 | font-style: normal; } | ||
32 | .vjs-icon-play-circle:before { | ||
33 | content: '\f102'; } | ||
34 | |||
35 | .vjs-icon-pause, .video-js .vjs-play-control.vjs-playing { | ||
36 | font-family: VideoJS; | ||
37 | font-weight: normal; | ||
38 | font-style: normal; } | ||
39 | .vjs-icon-pause:before, .video-js .vjs-play-control.vjs-playing:before { | ||
40 | content: '\f103'; } | ||
41 | |||
42 | .vjs-icon-volume-mute, .video-js .vjs-mute-control.vjs-vol-0, | ||
43 | .video-js .vjs-volume-menu-button.vjs-vol-0 { | ||
44 | font-family: VideoJS; | ||
45 | font-weight: normal; | ||
46 | font-style: normal; } | ||
47 | .vjs-icon-volume-mute:before, .video-js .vjs-mute-control.vjs-vol-0:before, | ||
48 | .video-js .vjs-volume-menu-button.vjs-vol-0:before { | ||
49 | content: '\f104'; } | ||
50 | |||
51 | .vjs-icon-volume-low, .video-js .vjs-mute-control.vjs-vol-1, | ||
52 | .video-js .vjs-volume-menu-button.vjs-vol-1 { | ||
53 | font-family: VideoJS; | ||
54 | font-weight: normal; | ||
55 | font-style: normal; } | ||
56 | .vjs-icon-volume-low:before, .video-js .vjs-mute-control.vjs-vol-1:before, | ||
57 | .video-js .vjs-volume-menu-button.vjs-vol-1:before { | ||
58 | content: '\f105'; } | ||
59 | |||
60 | .vjs-icon-volume-mid, .video-js .vjs-mute-control.vjs-vol-2, | ||
61 | .video-js .vjs-volume-menu-button.vjs-vol-2 { | ||
62 | font-family: VideoJS; | ||
63 | font-weight: normal; | ||
64 | font-style: normal; } | ||
65 | .vjs-icon-volume-mid:before, .video-js .vjs-mute-control.vjs-vol-2:before, | ||
66 | .video-js .vjs-volume-menu-button.vjs-vol-2:before { | ||
67 | content: '\f106'; } | ||
68 | |||
69 | .vjs-icon-volume-high, .video-js .vjs-mute-control, | ||
70 | .video-js .vjs-volume-menu-button { | ||
71 | font-family: VideoJS; | ||
72 | font-weight: normal; | ||
73 | font-style: normal; } | ||
74 | .vjs-icon-volume-high:before, .video-js .vjs-mute-control:before, | ||
75 | .video-js .vjs-volume-menu-button:before { | ||
76 | content: '\f107'; } | ||
77 | |||
78 | .vjs-icon-fullscreen-enter, .video-js .vjs-fullscreen-control { | ||
79 | font-family: VideoJS; | ||
80 | font-weight: normal; | ||
81 | font-style: normal; } | ||
82 | .vjs-icon-fullscreen-enter:before, .video-js .vjs-fullscreen-control:before { | ||
83 | content: '\f108'; } | ||
84 | |||
85 | .vjs-icon-fullscreen-exit, .video-js.vjs-fullscreen .vjs-fullscreen-control { | ||
86 | font-family: VideoJS; | ||
87 | font-weight: normal; | ||
88 | font-style: normal; } | ||
89 | .vjs-icon-fullscreen-exit:before, .video-js.vjs-fullscreen .vjs-fullscreen-control:before { | ||
90 | content: '\f109'; } | ||
91 | |||
92 | .vjs-icon-square { | ||
93 | font-family: VideoJS; | ||
94 | font-weight: normal; | ||
95 | font-style: normal; } | ||
96 | .vjs-icon-square:before { | ||
97 | content: '\f10a'; } | ||
98 | |||
99 | .vjs-icon-spinner { | ||
100 | font-family: VideoJS; | ||
101 | font-weight: normal; | ||
102 | font-style: normal; } | ||
103 | .vjs-icon-spinner:before { | ||
104 | content: '\f10b'; } | ||
105 | |||
106 | .vjs-icon-subtitles, .video-js .vjs-subtitles-button { | ||
107 | font-family: VideoJS; | ||
108 | font-weight: normal; | ||
109 | font-style: normal; } | ||
110 | .vjs-icon-subtitles:before, .video-js .vjs-subtitles-button:before { | ||
111 | content: '\f10c'; } | ||
112 | |||
113 | .vjs-icon-captions, .video-js .vjs-captions-button { | ||
114 | font-family: VideoJS; | ||
115 | font-weight: normal; | ||
116 | font-style: normal; } | ||
117 | .vjs-icon-captions:before, .video-js .vjs-captions-button:before { | ||
118 | content: '\f10d'; } | ||
119 | |||
120 | .vjs-icon-chapters, .video-js .vjs-chapters-button { | ||
121 | font-family: VideoJS; | ||
122 | font-weight: normal; | ||
123 | font-style: normal; } | ||
124 | .vjs-icon-chapters:before, .video-js .vjs-chapters-button:before { | ||
125 | content: '\f10e'; } | ||
126 | |||
127 | .vjs-icon-share { | ||
128 | font-family: VideoJS; | ||
129 | font-weight: normal; | ||
130 | font-style: normal; } | ||
131 | .vjs-icon-share:before { | ||
132 | content: '\f10f'; } | ||
133 | |||
134 | .vjs-icon-cog { | ||
135 | font-family: VideoJS; | ||
136 | font-weight: normal; | ||
137 | font-style: normal; } | ||
138 | .vjs-icon-cog:before { | ||
139 | content: '\f110'; } | ||
140 | |||
141 | .vjs-icon-circle, .video-js .vjs-mouse-display, .video-js .vjs-play-progress, .video-js .vjs-volume-level { | ||
142 | font-family: VideoJS; | ||
143 | font-weight: normal; | ||
144 | font-style: normal; } | ||
145 | .vjs-icon-circle:before, .video-js .vjs-mouse-display:before, .video-js .vjs-play-progress:before, .video-js .vjs-volume-level:before { | ||
146 | content: '\f111'; } | ||
147 | |||
148 | .vjs-icon-circle-outline { | ||
149 | font-family: VideoJS; | ||
150 | font-weight: normal; | ||
151 | font-style: normal; } | ||
152 | .vjs-icon-circle-outline:before { | ||
153 | content: '\f112'; } | ||
154 | |||
155 | .vjs-icon-circle-inner-circle { | ||
156 | font-family: VideoJS; | ||
157 | font-weight: normal; | ||
158 | font-style: normal; } | ||
159 | .vjs-icon-circle-inner-circle:before { | ||
160 | content: '\f113'; } | ||
161 | |||
162 | .vjs-icon-hd { | ||
163 | font-family: VideoJS; | ||
164 | font-weight: normal; | ||
165 | font-style: normal; } | ||
166 | .vjs-icon-hd:before { | ||
167 | content: '\f114'; } | ||
168 | |||
169 | .vjs-icon-cancel, .video-js .vjs-control.vjs-close-button { | ||
170 | font-family: VideoJS; | ||
171 | font-weight: normal; | ||
172 | font-style: normal; } | ||
173 | .vjs-icon-cancel:before, .video-js .vjs-control.vjs-close-button:before { | ||
174 | content: '\f115'; } | ||
175 | |||
176 | .vjs-icon-replay { | ||
177 | font-family: VideoJS; | ||
178 | font-weight: normal; | ||
179 | font-style: normal; } | ||
180 | .vjs-icon-replay:before { | ||
181 | content: '\f116'; } | ||
182 | |||
183 | .vjs-icon-facebook { | ||
184 | font-family: VideoJS; | ||
185 | font-weight: normal; | ||
186 | font-style: normal; } | ||
187 | .vjs-icon-facebook:before { | ||
188 | content: '\f117'; } | ||
189 | |||
190 | .vjs-icon-gplus { | ||
191 | font-family: VideoJS; | ||
192 | font-weight: normal; | ||
193 | font-style: normal; } | ||
194 | .vjs-icon-gplus:before { | ||
195 | content: '\f118'; } | ||
196 | |||
197 | .vjs-icon-linkedin { | ||
198 | font-family: VideoJS; | ||
199 | font-weight: normal; | ||
200 | font-style: normal; } | ||
201 | .vjs-icon-linkedin:before { | ||
202 | content: '\f119'; } | ||
203 | |||
204 | .vjs-icon-twitter { | ||
205 | font-family: VideoJS; | ||
206 | font-weight: normal; | ||
207 | font-style: normal; } | ||
208 | .vjs-icon-twitter:before { | ||
209 | content: '\f11a'; } | ||
210 | |||
211 | .vjs-icon-tumblr { | ||
212 | font-family: VideoJS; | ||
213 | font-weight: normal; | ||
214 | font-style: normal; } | ||
215 | .vjs-icon-tumblr:before { | ||
216 | content: '\f11b'; } | ||
217 | |||
218 | .vjs-icon-pinterest { | ||
219 | font-family: VideoJS; | ||
220 | font-weight: normal; | ||
221 | font-style: normal; } | ||
222 | .vjs-icon-pinterest:before { | ||
223 | content: '\f11c'; } | ||
224 | |||
225 | .vjs-icon-audio-description { | ||
226 | font-family: VideoJS; | ||
227 | font-weight: normal; | ||
228 | font-style: normal; } | ||
229 | .vjs-icon-audio-description:before { | ||
230 | content: '\f11d'; } | ||
231 | |||
232 | .video-js { | ||
233 | display: block; | ||
234 | vertical-align: top; | ||
235 | box-sizing: border-box; | ||
236 | color: #fff; | ||
237 | background-color: #000; | ||
238 | position: relative; | ||
239 | padding: 0; | ||
240 | font-size: 10px; | ||
241 | line-height: 1; | ||
242 | font-weight: normal; | ||
243 | font-style: normal; | ||
244 | font-family: Arial, Helvetica, sans-serif; | ||
245 | -webkit-user-select: none; | ||
246 | -moz-user-select: none; | ||
247 | -ms-user-select: none; | ||
248 | user-select: none; } | ||
249 | .video-js:-moz-full-screen { | ||
250 | position: absolute; } | ||
251 | .video-js:-webkit-full-screen { | ||
252 | width: 100% !important; | ||
253 | height: 100% !important; } | ||
254 | |||
255 | .video-js *, | ||
256 | .video-js *:before, | ||
257 | .video-js *:after { | ||
258 | box-sizing: inherit; } | ||
259 | |||
260 | .video-js ul { | ||
261 | font-family: inherit; | ||
262 | font-size: inherit; | ||
263 | line-height: inherit; | ||
264 | list-style-position: outside; | ||
265 | margin-left: 0; | ||
266 | margin-right: 0; | ||
267 | margin-top: 0; | ||
268 | margin-bottom: 0; } | ||
269 | |||
270 | .video-js.vjs-fluid, | ||
271 | .video-js.vjs-16-9, | ||
272 | .video-js.vjs-4-3 { | ||
273 | width: 100%; | ||
274 | max-width: 100%; | ||
275 | height: 0; } | ||
276 | |||
277 | .video-js.vjs-16-9 { | ||
278 | padding-top: 56.25%; } | ||
279 | |||
280 | .video-js.vjs-4-3 { | ||
281 | padding-top: 75%; } | ||
282 | |||
283 | .video-js.vjs-fill { | ||
284 | width: 100%; | ||
285 | height: 100%; } | ||
286 | |||
287 | .video-js .vjs-tech { | ||
288 | position: absolute; | ||
289 | top: 0; | ||
290 | left: 0; | ||
291 | width: 100%; | ||
292 | height: 100%; } | ||
293 | |||
294 | body.vjs-full-window { | ||
295 | padding: 0; | ||
296 | margin: 0; | ||
297 | height: 100%; | ||
298 | overflow-y: auto; } | ||
299 | |||
300 | .vjs-full-window .video-js.vjs-fullscreen { | ||
301 | position: fixed; | ||
302 | overflow: hidden; | ||
303 | z-index: 1000; | ||
304 | left: 0; | ||
305 | top: 0; | ||
306 | bottom: 0; | ||
307 | right: 0; } | ||
308 | |||
309 | .video-js.vjs-fullscreen { | ||
310 | width: 100% !important; | ||
311 | height: 100% !important; | ||
312 | padding-top: 0 !important; } | ||
313 | |||
314 | .video-js.vjs-fullscreen.vjs-user-inactive { | ||
315 | cursor: none; } | ||
316 | |||
317 | .vjs-hidden { | ||
318 | display: none !important; } | ||
319 | |||
320 | .video-js .vjs-offscreen { | ||
321 | height: 1px; | ||
322 | left: -9999px; | ||
323 | position: absolute; | ||
324 | top: 0; | ||
325 | width: 1px; } | ||
326 | |||
327 | .vjs-lock-showing { | ||
328 | display: block !important; | ||
329 | opacity: 1; | ||
330 | visibility: visible; } | ||
331 | |||
332 | .vjs-no-js { | ||
333 | padding: 20px; | ||
334 | color: #fff; | ||
335 | background-color: #000; | ||
336 | font-size: 18px; | ||
337 | font-family: Arial, Helvetica, sans-serif; | ||
338 | text-align: center; | ||
339 | width: 300px; | ||
340 | height: 150px; | ||
341 | margin: 0px auto; } | ||
342 | |||
343 | .vjs-no-js a, | ||
344 | .vjs-no-js a:visited { | ||
345 | color: #66A8CC; } | ||
346 | |||
347 | .video-js .vjs-big-play-button { | ||
348 | font-size: 3em; | ||
349 | line-height: 1.5em; | ||
350 | height: 1.5em; | ||
351 | width: 3em; | ||
352 | display: block; | ||
353 | position: absolute; | ||
354 | top: 10px; | ||
355 | left: 10px; | ||
356 | padding: 0; | ||
357 | cursor: pointer; | ||
358 | opacity: 1; | ||
359 | border: 0.06666em solid #fff; | ||
360 | background-color: #2B333F; | ||
361 | background-color: rgba(43, 51, 63, 0.7); | ||
362 | -webkit-border-radius: 0.3em; | ||
363 | -moz-border-radius: 0.3em; | ||
364 | border-radius: 0.3em; | ||
365 | -webkit-transition: all 0.4s; | ||
366 | -moz-transition: all 0.4s; | ||
367 | -o-transition: all 0.4s; | ||
368 | transition: all 0.4s; } | ||
369 | |||
370 | .vjs-big-play-centered .vjs-big-play-button { | ||
371 | top: 50%; | ||
372 | left: 50%; | ||
373 | margin-top: -0.75em; | ||
374 | margin-left: -1.5em; } | ||
375 | |||
376 | .video-js:hover .vjs-big-play-button, | ||
377 | .video-js .vjs-big-play-button:focus { | ||
378 | outline: 0; | ||
379 | border-color: #fff; | ||
380 | background-color: #73859f; | ||
381 | background-color: rgba(115, 133, 159, 0.5); | ||
382 | -webkit-transition: all 0s; | ||
383 | -moz-transition: all 0s; | ||
384 | -o-transition: all 0s; | ||
385 | transition: all 0s; } | ||
386 | |||
387 | .vjs-controls-disabled .vjs-big-play-button, | ||
388 | .vjs-has-started .vjs-big-play-button, | ||
389 | .vjs-using-native-controls .vjs-big-play-button, | ||
390 | .vjs-error .vjs-big-play-button { | ||
391 | display: none; } | ||
392 | |||
393 | .video-js button { | ||
394 | background: none; | ||
395 | border: none; | ||
396 | color: inherit; | ||
397 | display: inline-block; | ||
398 | overflow: visible; | ||
399 | font-size: inherit; | ||
400 | line-height: inherit; | ||
401 | text-transform: none; | ||
402 | text-decoration: none; | ||
403 | transition: none; | ||
404 | -webkit-appearance: none; | ||
405 | -moz-appearance: none; | ||
406 | appearance: none; } | ||
407 | |||
408 | .video-js .vjs-control.vjs-close-button { | ||
409 | cursor: pointer; | ||
410 | height: 3em; | ||
411 | position: absolute; | ||
412 | right: 0; | ||
413 | top: 0.5em; | ||
414 | z-index: 2; } | ||
415 | |||
416 | .vjs-menu-button { | ||
417 | cursor: pointer; } | ||
418 | |||
419 | .vjs-menu .vjs-menu-content { | ||
420 | display: block; | ||
421 | padding: 0; | ||
422 | margin: 0; | ||
423 | overflow: auto; } | ||
424 | |||
425 | .vjs-scrubbing .vjs-menu-button:hover .vjs-menu { | ||
426 | display: none; } | ||
427 | |||
428 | .vjs-menu li { | ||
429 | list-style: none; | ||
430 | margin: 0; | ||
431 | padding: 0.2em 0; | ||
432 | line-height: 1.4em; | ||
433 | font-size: 1.2em; | ||
434 | text-align: center; | ||
435 | text-transform: lowercase; } | ||
436 | |||
437 | .vjs-menu li:focus, | ||
438 | .vjs-menu li:hover { | ||
439 | outline: 0; | ||
440 | background-color: #73859f; | ||
441 | background-color: rgba(115, 133, 159, 0.5); } | ||
442 | |||
443 | .vjs-menu li.vjs-selected, | ||
444 | .vjs-menu li.vjs-selected:focus, | ||
445 | .vjs-menu li.vjs-selected:hover { | ||
446 | background-color: #fff; | ||
447 | color: #2B333F; } | ||
448 | |||
449 | .vjs-menu li.vjs-menu-title { | ||
450 | text-align: center; | ||
451 | text-transform: uppercase; | ||
452 | font-size: 1em; | ||
453 | line-height: 2em; | ||
454 | padding: 0; | ||
455 | margin: 0 0 0.3em 0; | ||
456 | font-weight: bold; | ||
457 | cursor: default; } | ||
458 | |||
459 | .vjs-menu-button-popup .vjs-menu { | ||
460 | display: none; | ||
461 | position: absolute; | ||
462 | bottom: 0; | ||
463 | width: 10em; | ||
464 | left: -3em; | ||
465 | height: 0em; | ||
466 | margin-bottom: 1.5em; | ||
467 | border-top-color: rgba(43, 51, 63, 0.7); } | ||
468 | |||
469 | .vjs-menu-button-popup .vjs-menu .vjs-menu-content { | ||
470 | background-color: #2B333F; | ||
471 | background-color: rgba(43, 51, 63, 0.7); | ||
472 | position: absolute; | ||
473 | width: 100%; | ||
474 | bottom: 1.5em; | ||
475 | max-height: 15em; } | ||
476 | |||
477 | .vjs-workinghover .vjs-menu-button-popup:hover .vjs-menu, | ||
478 | .vjs-menu-button-popup .vjs-menu.vjs-lock-showing { | ||
479 | display: block; } | ||
480 | |||
481 | .video-js .vjs-menu-button-inline { | ||
482 | -webkit-transition: all 0.4s; | ||
483 | -moz-transition: all 0.4s; | ||
484 | -o-transition: all 0.4s; | ||
485 | transition: all 0.4s; | ||
486 | overflow: hidden; } | ||
487 | |||
488 | .video-js .vjs-menu-button-inline:before { | ||
489 | width: 2.222222222em; } | ||
490 | |||
491 | .video-js .vjs-menu-button-inline:hover, | ||
492 | .video-js .vjs-menu-button-inline:focus, | ||
493 | .video-js .vjs-menu-button-inline.vjs-slider-active, | ||
494 | .video-js.vjs-no-flex .vjs-menu-button-inline { | ||
495 | width: 12em; } | ||
496 | |||
497 | .video-js .vjs-menu-button-inline.vjs-slider-active { | ||
498 | -webkit-transition: none; | ||
499 | -moz-transition: none; | ||
500 | -o-transition: none; | ||
501 | transition: none; } | ||
502 | |||
503 | .vjs-menu-button-inline .vjs-menu { | ||
504 | opacity: 0; | ||
505 | height: 100%; | ||
506 | width: auto; | ||
507 | position: absolute; | ||
508 | left: 4em; | ||
509 | top: 0; | ||
510 | padding: 0; | ||
511 | margin: 0; | ||
512 | -webkit-transition: all 0.4s; | ||
513 | -moz-transition: all 0.4s; | ||
514 | -o-transition: all 0.4s; | ||
515 | transition: all 0.4s; } | ||
516 | |||
517 | .vjs-menu-button-inline:hover .vjs-menu, | ||
518 | .vjs-menu-button-inline:focus .vjs-menu, | ||
519 | .vjs-menu-button-inline.vjs-slider-active .vjs-menu { | ||
520 | display: block; | ||
521 | opacity: 1; } | ||
522 | |||
523 | .vjs-no-flex .vjs-menu-button-inline .vjs-menu { | ||
524 | display: block; | ||
525 | opacity: 1; | ||
526 | position: relative; | ||
527 | width: auto; } | ||
528 | |||
529 | .vjs-no-flex .vjs-menu-button-inline:hover .vjs-menu, | ||
530 | .vjs-no-flex .vjs-menu-button-inline:focus .vjs-menu, | ||
531 | .vjs-no-flex .vjs-menu-button-inline.vjs-slider-active .vjs-menu { | ||
532 | width: auto; } | ||
533 | |||
534 | .vjs-menu-button-inline .vjs-menu-content { | ||
535 | width: auto; | ||
536 | height: 100%; | ||
537 | margin: 0; | ||
538 | overflow: hidden; } | ||
539 | |||
540 | .video-js .vjs-control-bar { | ||
541 | display: none; | ||
542 | width: 100%; | ||
543 | position: absolute; | ||
544 | bottom: 0; | ||
545 | left: 0; | ||
546 | right: 0; | ||
547 | height: 3.0em; | ||
548 | background-color: #2B333F; | ||
549 | background-color: rgba(43, 51, 63, 0.7); } | ||
550 | |||
551 | .vjs-has-started .vjs-control-bar { | ||
552 | display: -webkit-box; | ||
553 | display: -webkit-flex; | ||
554 | display: -ms-flexbox; | ||
555 | display: flex; | ||
556 | visibility: visible; | ||
557 | opacity: 1; | ||
558 | -webkit-transition: visibility 0.1s, opacity 0.1s; | ||
559 | -moz-transition: visibility 0.1s, opacity 0.1s; | ||
560 | -o-transition: visibility 0.1s, opacity 0.1s; | ||
561 | transition: visibility 0.1s, opacity 0.1s; } | ||
562 | |||
563 | .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { | ||
564 | visibility: hidden; | ||
565 | opacity: 0; | ||
566 | -webkit-transition: visibility 1s, opacity 1s; | ||
567 | -moz-transition: visibility 1s, opacity 1s; | ||
568 | -o-transition: visibility 1s, opacity 1s; | ||
569 | transition: visibility 1s, opacity 1s; } | ||
570 | |||
571 | .vjs-controls-disabled .vjs-control-bar, | ||
572 | .vjs-using-native-controls .vjs-control-bar, | ||
573 | .vjs-error .vjs-control-bar { | ||
574 | display: none !important; } | ||
575 | |||
576 | .vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { | ||
577 | opacity: 1; | ||
578 | visibility: visible; } | ||
579 | |||
580 | @media \0screen { | ||
581 | .vjs-user-inactive.vjs-playing .vjs-control-bar :before { | ||
582 | content: ""; } } | ||
583 | |||
584 | .vjs-has-started.vjs-no-flex .vjs-control-bar { | ||
585 | display: table; } | ||
586 | |||
587 | .video-js .vjs-control { | ||
588 | outline: none; | ||
589 | position: relative; | ||
590 | text-align: center; | ||
591 | margin: 0; | ||
592 | padding: 0; | ||
593 | height: 100%; | ||
594 | width: 4em; | ||
595 | -webkit-box-flex: none; | ||
596 | -moz-box-flex: none; | ||
597 | -webkit-flex: none; | ||
598 | -ms-flex: none; | ||
599 | flex: none; } | ||
600 | .video-js .vjs-control:before { | ||
601 | font-size: 1.8em; | ||
602 | line-height: 1.67; } | ||
603 | |||
604 | .video-js .vjs-control:focus:before, | ||
605 | .video-js .vjs-control:hover:before, | ||
606 | .video-js .vjs-control:focus { | ||
607 | text-shadow: 0em 0em 1em white; } | ||
608 | |||
609 | .video-js .vjs-control-text { | ||
610 | border: 0; | ||
611 | clip: rect(0 0 0 0); | ||
612 | height: 1px; | ||
613 | margin: -1px; | ||
614 | overflow: hidden; | ||
615 | padding: 0; | ||
616 | position: absolute; | ||
617 | width: 1px; } | ||
618 | |||
619 | .vjs-no-flex .vjs-control { | ||
620 | display: table-cell; | ||
621 | vertical-align: middle; } | ||
622 | |||
623 | .video-js .vjs-custom-control-spacer { | ||
624 | display: none; } | ||
625 | |||
626 | .video-js .vjs-progress-control { | ||
627 | -webkit-box-flex: auto; | ||
628 | -moz-box-flex: auto; | ||
629 | -webkit-flex: auto; | ||
630 | -ms-flex: auto; | ||
631 | flex: auto; | ||
632 | display: -webkit-box; | ||
633 | display: -webkit-flex; | ||
634 | display: -ms-flexbox; | ||
635 | display: flex; | ||
636 | -webkit-box-align: center; | ||
637 | -webkit-align-items: center; | ||
638 | -ms-flex-align: center; | ||
639 | align-items: center; | ||
640 | min-width: 4em; } | ||
641 | |||
642 | .vjs-live .vjs-progress-control { | ||
643 | display: none; } | ||
644 | |||
645 | .video-js .vjs-progress-holder { | ||
646 | -webkit-box-flex: auto; | ||
647 | -moz-box-flex: auto; | ||
648 | -webkit-flex: auto; | ||
649 | -ms-flex: auto; | ||
650 | flex: auto; | ||
651 | -webkit-transition: all 0.2s; | ||
652 | -moz-transition: all 0.2s; | ||
653 | -o-transition: all 0.2s; | ||
654 | transition: all 0.2s; | ||
655 | height: 0.3em; } | ||
656 | |||
657 | .video-js .vjs-progress-control:hover .vjs-progress-holder { | ||
658 | font-size: 1.666666666666666666em; } | ||
659 | |||
660 | /* If we let the font size grow as much as everything else, the current time tooltip ends up | ||
661 | ginormous. If you'd like to enable the current time tooltip all the time, this should be disabled | ||
662 | to avoid a weird hitch when you roll off the hover. */ | ||
663 | .video-js .vjs-progress-control:hover .vjs-mouse-display:after, | ||
664 | .video-js .vjs-progress-control:hover .vjs-play-progress:after { | ||
665 | display: block; | ||
666 | font-size: 0.6em; } | ||
667 | |||
668 | .video-js .vjs-progress-holder .vjs-play-progress, | ||
669 | .video-js .vjs-progress-holder .vjs-load-progress, | ||
670 | .video-js .vjs-progress-holder .vjs-load-progress div { | ||
671 | position: absolute; | ||
672 | display: block; | ||
673 | height: 0.3em; | ||
674 | margin: 0; | ||
675 | padding: 0; | ||
676 | width: 0; | ||
677 | left: 0; | ||
678 | top: 0; } | ||
679 | |||
680 | .video-js .vjs-mouse-display:before { | ||
681 | display: none; } | ||
682 | |||
683 | .video-js .vjs-play-progress { | ||
684 | background-color: #fff; } | ||
685 | .video-js .vjs-play-progress:before { | ||
686 | position: absolute; | ||
687 | top: -0.333333333333333em; | ||
688 | right: -0.5em; | ||
689 | font-size: 0.9em; } | ||
690 | |||
691 | .video-js .vjs-mouse-display:after, | ||
692 | .video-js .vjs-play-progress:after { | ||
693 | display: none; | ||
694 | position: absolute; | ||
695 | top: -3.4em; | ||
696 | right: -1.5em; | ||
697 | font-size: 0.9em; | ||
698 | color: #000; | ||
699 | content: attr(data-current-time); | ||
700 | padding: 6px 8px 8px 8px; | ||
701 | background-color: #fff; | ||
702 | background-color: rgba(255, 255, 255, 0.8); | ||
703 | -webkit-border-radius: 0.3em; | ||
704 | -moz-border-radius: 0.3em; | ||
705 | border-radius: 0.3em; } | ||
706 | |||
707 | .video-js .vjs-play-progress:before, | ||
708 | .video-js .vjs-play-progress:after { | ||
709 | z-index: 1; } | ||
710 | |||
711 | .video-js .vjs-load-progress { | ||
712 | background: #bfc7d3; | ||
713 | background: rgba(115, 133, 159, 0.5); } | ||
714 | |||
715 | .video-js .vjs-load-progress div { | ||
716 | background: white; | ||
717 | background: rgba(115, 133, 159, 0.75); } | ||
718 | |||
719 | .video-js.vjs-no-flex .vjs-progress-control { | ||
720 | width: auto; } | ||
721 | |||
722 | .video-js .vjs-progress-control .vjs-mouse-display { | ||
723 | display: none; | ||
724 | position: absolute; | ||
725 | width: 1px; | ||
726 | height: 100%; | ||
727 | background-color: #000; | ||
728 | z-index: 1; } | ||
729 | |||
730 | .vjs-no-flex .vjs-progress-control .vjs-mouse-display { | ||
731 | z-index: 0; } | ||
732 | |||
733 | .video-js .vjs-progress-control:hover .vjs-mouse-display { | ||
734 | display: block; } | ||
735 | |||
736 | .video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display, | ||
737 | .video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display:after { | ||
738 | visibility: hidden; | ||
739 | opacity: 0; | ||
740 | -webkit-transition: visibility 1s, opacity 1s; | ||
741 | -moz-transition: visibility 1s, opacity 1s; | ||
742 | -o-transition: visibility 1s, opacity 1s; | ||
743 | transition: visibility 1s, opacity 1s; } | ||
744 | |||
745 | .video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display, | ||
746 | .video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display:after { | ||
747 | display: none; } | ||
748 | |||
749 | .video-js .vjs-progress-control .vjs-mouse-display:after { | ||
750 | color: #fff; | ||
751 | background-color: #000; | ||
752 | background-color: rgba(0, 0, 0, 0.8); } | ||
753 | |||
754 | .video-js .vjs-slider { | ||
755 | outline: 0; | ||
756 | position: relative; | ||
757 | cursor: pointer; | ||
758 | padding: 0; | ||
759 | margin: 0 0.45em 0 0.45em; | ||
760 | background-color: #73859f; | ||
761 | background-color: rgba(115, 133, 159, 0.5); } | ||
762 | |||
763 | .video-js .vjs-slider:focus { | ||
764 | text-shadow: 0em 0em 1em white; | ||
765 | -webkit-box-shadow: 0 0 1em #fff; | ||
766 | -moz-box-shadow: 0 0 1em #fff; | ||
767 | box-shadow: 0 0 1em #fff; } | ||
768 | |||
769 | .video-js .vjs-mute-control, | ||
770 | .video-js .vjs-volume-menu-button { | ||
771 | cursor: pointer; | ||
772 | -webkit-box-flex: none; | ||
773 | -moz-box-flex: none; | ||
774 | -webkit-flex: none; | ||
775 | -ms-flex: none; | ||
776 | flex: none; } | ||
777 | |||
778 | .video-js .vjs-volume-control { | ||
779 | width: 5em; | ||
780 | -webkit-box-flex: none; | ||
781 | -moz-box-flex: none; | ||
782 | -webkit-flex: none; | ||
783 | -ms-flex: none; | ||
784 | flex: none; | ||
785 | display: -webkit-box; | ||
786 | display: -webkit-flex; | ||
787 | display: -ms-flexbox; | ||
788 | display: flex; | ||
789 | -webkit-box-align: center; | ||
790 | -webkit-align-items: center; | ||
791 | -ms-flex-align: center; | ||
792 | align-items: center; } | ||
793 | |||
794 | .video-js .vjs-volume-bar { | ||
795 | margin: 1.35em 0.45em; } | ||
796 | |||
797 | .vjs-volume-bar.vjs-slider-horizontal { | ||
798 | width: 5em; | ||
799 | height: 0.3em; } | ||
800 | |||
801 | .vjs-volume-bar.vjs-slider-vertical { | ||
802 | width: 0.3em; | ||
803 | height: 5em; | ||
804 | margin: 1.35em auto; } | ||
805 | |||
806 | .video-js .vjs-volume-level { | ||
807 | position: absolute; | ||
808 | bottom: 0; | ||
809 | left: 0; | ||
810 | background-color: #fff; } | ||
811 | .video-js .vjs-volume-level:before { | ||
812 | position: absolute; | ||
813 | font-size: 0.9em; } | ||
814 | |||
815 | .vjs-slider-vertical .vjs-volume-level { | ||
816 | width: 0.3em; } | ||
817 | .vjs-slider-vertical .vjs-volume-level:before { | ||
818 | top: -0.5em; | ||
819 | left: -0.3em; } | ||
820 | |||
821 | .vjs-slider-horizontal .vjs-volume-level { | ||
822 | height: 0.3em; } | ||
823 | .vjs-slider-horizontal .vjs-volume-level:before { | ||
824 | top: -0.3em; | ||
825 | right: -0.5em; } | ||
826 | |||
827 | .vjs-volume-bar.vjs-slider-vertical .vjs-volume-level { | ||
828 | height: 100%; } | ||
829 | |||
830 | .vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level { | ||
831 | width: 100%; } | ||
832 | |||
833 | .vjs-menu-button-popup.vjs-volume-menu-button .vjs-menu { | ||
834 | display: block; | ||
835 | width: 0; | ||
836 | height: 0; | ||
837 | border-top-color: transparent; } | ||
838 | |||
839 | .vjs-menu-button-popup.vjs-volume-menu-button-vertical .vjs-menu { | ||
840 | left: 0.5em; | ||
841 | height: 8em; } | ||
842 | |||
843 | .vjs-menu-button-popup.vjs-volume-menu-button-horizontal .vjs-menu { | ||
844 | left: -2em; } | ||
845 | |||
846 | .vjs-menu-button-popup.vjs-volume-menu-button .vjs-menu-content { | ||
847 | height: 0; | ||
848 | width: 0; | ||
849 | overflow-x: hidden; | ||
850 | overflow-y: hidden; } | ||
851 | |||
852 | .vjs-volume-menu-button-vertical:hover .vjs-menu-content, | ||
853 | .vjs-volume-menu-button-vertical:focus .vjs-menu-content, | ||
854 | .vjs-volume-menu-button-vertical.vjs-slider-active .vjs-menu-content, | ||
855 | .vjs-volume-menu-button-vertical .vjs-lock-showing .vjs-menu-content { | ||
856 | height: 8em; | ||
857 | width: 2.9em; } | ||
858 | |||
859 | .vjs-volume-menu-button-horizontal:hover .vjs-menu-content, | ||
860 | .vjs-volume-menu-button-horizontal:focus .vjs-menu-content, | ||
861 | .vjs-volume-menu-button-horizontal .vjs-slider-active .vjs-menu-content, | ||
862 | .vjs-volume-menu-button-horizontal .vjs-lock-showing .vjs-menu-content { | ||
863 | height: 2.9em; | ||
864 | width: 8em; } | ||
865 | |||
866 | .vjs-volume-menu-button.vjs-menu-button-inline .vjs-menu-content { | ||
867 | background-color: transparent !important; } | ||
868 | |||
869 | .vjs-poster { | ||
870 | display: inline-block; | ||
871 | vertical-align: middle; | ||
872 | background-repeat: no-repeat; | ||
873 | background-position: 50% 50%; | ||
874 | background-size: contain; | ||
875 | cursor: pointer; | ||
876 | margin: 0; | ||
877 | padding: 0; | ||
878 | position: absolute; | ||
879 | top: 0; | ||
880 | right: 0; | ||
881 | bottom: 0; | ||
882 | left: 0; | ||
883 | height: 100%; } | ||
884 | |||
885 | .vjs-poster img { | ||
886 | display: block; | ||
887 | vertical-align: middle; | ||
888 | margin: 0 auto; | ||
889 | max-height: 100%; | ||
890 | padding: 0; | ||
891 | width: 100%; } | ||
892 | |||
893 | .vjs-has-started .vjs-poster { | ||
894 | display: none; } | ||
895 | |||
896 | .vjs-audio.vjs-has-started .vjs-poster { | ||
897 | display: block; } | ||
898 | |||
899 | .vjs-controls-disabled .vjs-poster { | ||
900 | display: none; } | ||
901 | |||
902 | .vjs-using-native-controls .vjs-poster { | ||
903 | display: none; } | ||
904 | |||
905 | .video-js .vjs-live-control { | ||
906 | display: -webkit-box; | ||
907 | display: -webkit-flex; | ||
908 | display: -ms-flexbox; | ||
909 | display: flex; | ||
910 | -webkit-box-align: flex-start; | ||
911 | -webkit-align-items: flex-start; | ||
912 | -ms-flex-align: flex-start; | ||
913 | align-items: flex-start; | ||
914 | -webkit-box-flex: auto; | ||
915 | -moz-box-flex: auto; | ||
916 | -webkit-flex: auto; | ||
917 | -ms-flex: auto; | ||
918 | flex: auto; | ||
919 | font-size: 1em; | ||
920 | line-height: 3em; } | ||
921 | |||
922 | .vjs-no-flex .vjs-live-control { | ||
923 | display: table-cell; | ||
924 | width: auto; | ||
925 | text-align: left; } | ||
926 | |||
927 | .video-js .vjs-time-control { | ||
928 | -webkit-box-flex: none; | ||
929 | -moz-box-flex: none; | ||
930 | -webkit-flex: none; | ||
931 | -ms-flex: none; | ||
932 | flex: none; | ||
933 | font-size: 1em; | ||
934 | line-height: 3em; | ||
935 | min-width: 2em; | ||
936 | width: auto; | ||
937 | padding-left: 1em; | ||
938 | padding-right: 1em; } | ||
939 | |||
940 | .vjs-live .vjs-time-control { | ||
941 | display: none; } | ||
942 | |||
943 | .video-js .vjs-current-time, | ||
944 | .vjs-no-flex .vjs-current-time { | ||
945 | display: none; } | ||
946 | |||
947 | .video-js .vjs-duration, | ||
948 | .vjs-no-flex .vjs-duration { | ||
949 | display: none; } | ||
950 | |||
951 | .vjs-time-divider { | ||
952 | display: none; | ||
953 | line-height: 3em; } | ||
954 | |||
955 | .vjs-live .vjs-time-divider { | ||
956 | display: none; } | ||
957 | |||
958 | .video-js .vjs-play-control { | ||
959 | cursor: pointer; | ||
960 | -webkit-box-flex: none; | ||
961 | -moz-box-flex: none; | ||
962 | -webkit-flex: none; | ||
963 | -ms-flex: none; | ||
964 | flex: none; } | ||
965 | |||
966 | .vjs-text-track-display { | ||
967 | position: absolute; | ||
968 | bottom: 3em; | ||
969 | left: 0; | ||
970 | right: 0; | ||
971 | top: 0; | ||
972 | pointer-events: none; } | ||
973 | |||
974 | .video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display { | ||
975 | bottom: 1em; } | ||
976 | |||
977 | .video-js .vjs-text-track { | ||
978 | font-size: 1.4em; | ||
979 | text-align: center; | ||
980 | margin-bottom: 0.1em; | ||
981 | background-color: #000; | ||
982 | background-color: rgba(0, 0, 0, 0.5); } | ||
983 | |||
984 | .vjs-subtitles { | ||
985 | color: #fff; } | ||
986 | |||
987 | .vjs-captions { | ||
988 | color: #fc6; } | ||
989 | |||
990 | .vjs-tt-cue { | ||
991 | display: block; } | ||
992 | |||
993 | video::-webkit-media-text-track-display { | ||
994 | -moz-transform: translateY(-3em); | ||
995 | -ms-transform: translateY(-3em); | ||
996 | -o-transform: translateY(-3em); | ||
997 | -webkit-transform: translateY(-3em); | ||
998 | transform: translateY(-3em); } | ||
999 | |||
1000 | .video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display { | ||
1001 | -moz-transform: translateY(-1.5em); | ||
1002 | -ms-transform: translateY(-1.5em); | ||
1003 | -o-transform: translateY(-1.5em); | ||
1004 | -webkit-transform: translateY(-1.5em); | ||
1005 | transform: translateY(-1.5em); } | ||
1006 | |||
1007 | .video-js .vjs-fullscreen-control { | ||
1008 | cursor: pointer; | ||
1009 | -webkit-box-flex: none; | ||
1010 | -moz-box-flex: none; | ||
1011 | -webkit-flex: none; | ||
1012 | -ms-flex: none; | ||
1013 | flex: none; } | ||
1014 | |||
1015 | .vjs-playback-rate .vjs-playback-rate-value { | ||
1016 | font-size: 1.5em; | ||
1017 | line-height: 2; | ||
1018 | position: absolute; | ||
1019 | top: 0; | ||
1020 | left: 0; | ||
1021 | width: 100%; | ||
1022 | height: 100%; | ||
1023 | text-align: center; } | ||
1024 | |||
1025 | .vjs-playback-rate .vjs-menu { | ||
1026 | width: 4em; | ||
1027 | left: 0em; } | ||
1028 | |||
1029 | .vjs-error .vjs-error-display .vjs-modal-dialog-content { | ||
1030 | font-size: 1.4em; | ||
1031 | text-align: center; } | ||
1032 | |||
1033 | .vjs-error .vjs-error-display:before { | ||
1034 | color: #fff; | ||
1035 | content: 'X'; | ||
1036 | font-family: Arial, Helvetica, sans-serif; | ||
1037 | font-size: 4em; | ||
1038 | left: 0; | ||
1039 | line-height: 1; | ||
1040 | margin-top: -0.5em; | ||
1041 | position: absolute; | ||
1042 | text-shadow: 0.05em 0.05em 0.1em #000; | ||
1043 | text-align: center; | ||
1044 | top: 50%; | ||
1045 | vertical-align: middle; | ||
1046 | width: 100%; } | ||
1047 | |||
1048 | .vjs-loading-spinner { | ||
1049 | display: none; | ||
1050 | position: absolute; | ||
1051 | top: 50%; | ||
1052 | left: 50%; | ||
1053 | margin: -25px 0 0 -25px; | ||
1054 | opacity: 0.85; | ||
1055 | text-align: left; | ||
1056 | border: 6px solid rgba(43, 51, 63, 0.7); | ||
1057 | box-sizing: border-box; | ||
1058 | background-clip: padding-box; | ||
1059 | width: 50px; | ||
1060 | height: 50px; | ||
1061 | border-radius: 25px; } | ||
1062 | |||
1063 | .vjs-seeking .vjs-loading-spinner, | ||
1064 | .vjs-waiting .vjs-loading-spinner { | ||
1065 | display: block; } | ||
1066 | |||
1067 | .vjs-loading-spinner:before, | ||
1068 | .vjs-loading-spinner:after { | ||
1069 | content: ""; | ||
1070 | position: absolute; | ||
1071 | margin: -6px; | ||
1072 | box-sizing: inherit; | ||
1073 | width: inherit; | ||
1074 | height: inherit; | ||
1075 | border-radius: inherit; | ||
1076 | opacity: 1; | ||
1077 | border: inherit; | ||
1078 | border-color: transparent; | ||
1079 | border-top-color: white; } | ||
1080 | |||
1081 | .vjs-seeking .vjs-loading-spinner:before, | ||
1082 | .vjs-seeking .vjs-loading-spinner:after, | ||
1083 | .vjs-waiting .vjs-loading-spinner:before, | ||
1084 | .vjs-waiting .vjs-loading-spinner:after { | ||
1085 | -webkit-animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; | ||
1086 | animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; } | ||
1087 | |||
1088 | .vjs-seeking .vjs-loading-spinner:before, | ||
1089 | .vjs-waiting .vjs-loading-spinner:before { | ||
1090 | border-top-color: white; } | ||
1091 | |||
1092 | .vjs-seeking .vjs-loading-spinner:after, | ||
1093 | .vjs-waiting .vjs-loading-spinner:after { | ||
1094 | border-top-color: white; | ||
1095 | -webkit-animation-delay: 0.44s; | ||
1096 | animation-delay: 0.44s; } | ||
1097 | |||
1098 | @keyframes vjs-spinner-spin { | ||
1099 | 100% { | ||
1100 | transform: rotate(360deg); } } | ||
1101 | |||
1102 | @-webkit-keyframes vjs-spinner-spin { | ||
1103 | 100% { | ||
1104 | -webkit-transform: rotate(360deg); } } | ||
1105 | |||
1106 | @keyframes vjs-spinner-fade { | ||
1107 | 0% { | ||
1108 | border-top-color: #73859f; } | ||
1109 | 20% { | ||
1110 | border-top-color: #73859f; } | ||
1111 | 35% { | ||
1112 | border-top-color: white; } | ||
1113 | 60% { | ||
1114 | border-top-color: #73859f; } | ||
1115 | 100% { | ||
1116 | border-top-color: #73859f; } } | ||
1117 | |||
1118 | @-webkit-keyframes vjs-spinner-fade { | ||
1119 | 0% { | ||
1120 | border-top-color: #73859f; } | ||
1121 | 20% { | ||
1122 | border-top-color: #73859f; } | ||
1123 | 35% { | ||
1124 | border-top-color: white; } | ||
1125 | 60% { | ||
1126 | border-top-color: #73859f; } | ||
1127 | 100% { | ||
1128 | border-top-color: #73859f; } } | ||
1129 | |||
1130 | .vjs-chapters-button .vjs-menu ul { | ||
1131 | width: 24em; } | ||
1132 | |||
1133 | .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-custom-control-spacer { | ||
1134 | -webkit-box-flex: auto; | ||
1135 | -moz-box-flex: auto; | ||
1136 | -webkit-flex: auto; | ||
1137 | -ms-flex: auto; | ||
1138 | flex: auto; } | ||
1139 | |||
1140 | .video-js.vjs-layout-tiny:not(.vjs-fullscreen).vjs-no-flex .vjs-custom-control-spacer { | ||
1141 | width: auto; } | ||
1142 | |||
1143 | .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-remaining-time, | ||
1144 | .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-playback-rate, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-progress-control, | ||
1145 | .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-volume-control, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-volume-menu-button, | ||
1146 | .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-captions-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-subtitles-button { | ||
1147 | display: none; } | ||
1148 | |||
1149 | .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-remaining-time, | ||
1150 | .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-playback-rate, | ||
1151 | .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-volume-control, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-volume-menu-button, | ||
1152 | .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-captions-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-subtitles-button { | ||
1153 | display: none; } | ||
1154 | |||
1155 | .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-remaining-time, | ||
1156 | .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-playback-rate, | ||
1157 | .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-volume-control, | ||
1158 | .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-captions-button, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-subtitles-button { | ||
1159 | display: none; } | ||
1160 | |||
1161 | .vjs-caption-settings { | ||
1162 | position: relative; | ||
1163 | top: 1em; | ||
1164 | background-color: #2B333F; | ||
1165 | background-color: rgba(43, 51, 63, 0.75); | ||
1166 | color: #fff; | ||
1167 | margin: 0 auto; | ||
1168 | padding: 0.5em; | ||
1169 | height: 15em; | ||
1170 | font-size: 12px; | ||
1171 | width: 40em; } | ||
1172 | |||
1173 | .vjs-caption-settings .vjs-tracksettings { | ||
1174 | top: 0; | ||
1175 | bottom: 2em; | ||
1176 | left: 0; | ||
1177 | right: 0; | ||
1178 | position: absolute; | ||
1179 | overflow: auto; } | ||
1180 | |||
1181 | .vjs-caption-settings .vjs-tracksettings-colors, | ||
1182 | .vjs-caption-settings .vjs-tracksettings-font { | ||
1183 | float: left; } | ||
1184 | |||
1185 | .vjs-caption-settings .vjs-tracksettings-colors:after, | ||
1186 | .vjs-caption-settings .vjs-tracksettings-font:after, | ||
1187 | .vjs-caption-settings .vjs-tracksettings-controls:after { | ||
1188 | clear: both; } | ||
1189 | |||
1190 | .vjs-caption-settings .vjs-tracksettings-controls { | ||
1191 | position: absolute; | ||
1192 | bottom: 1em; | ||
1193 | right: 1em; } | ||
1194 | |||
1195 | .vjs-caption-settings .vjs-tracksetting { | ||
1196 | margin: 5px; | ||
1197 | padding: 3px; | ||
1198 | min-height: 40px; } | ||
1199 | |||
1200 | .vjs-caption-settings .vjs-tracksetting label { | ||
1201 | display: block; | ||
1202 | width: 100px; | ||
1203 | margin-bottom: 5px; } | ||
1204 | |||
1205 | .vjs-caption-settings .vjs-tracksetting span { | ||
1206 | display: inline; | ||
1207 | margin-left: 5px; } | ||
1208 | |||
1209 | .vjs-caption-settings .vjs-tracksetting > div { | ||
1210 | margin-bottom: 5px; | ||
1211 | min-height: 20px; } | ||
1212 | |||
1213 | .vjs-caption-settings .vjs-tracksetting > div:last-child { | ||
1214 | margin-bottom: 0; | ||
1215 | padding-bottom: 0; | ||
1216 | min-height: 0; } | ||
1217 | |||
1218 | .vjs-caption-settings label > input { | ||
1219 | margin-right: 10px; } | ||
1220 | |||
1221 | .vjs-caption-settings input[type="button"] { | ||
1222 | width: 40px; | ||
1223 | height: 40px; } | ||
1224 | |||
1225 | .video-js .vjs-modal-dialog { | ||
1226 | background: rgba(0, 0, 0, 0.8); | ||
1227 | background: -webkit-linear-gradient(-90deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0)); | ||
1228 | background: linear-gradient(180deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0)); } | ||
1229 | |||
1230 | .vjs-modal-dialog .vjs-modal-dialog-content { | ||
1231 | font-size: 1.2em; | ||
1232 | line-height: 1.5; | ||
1233 | padding: 20px 24px; | ||
1234 | z-index: 1; } | ||
@@ -3,4 +3,35 @@ title: Sway | |||
3 | layout: master | 3 | layout: master |
4 | --- | 4 | --- |
5 | 5 | ||
6 | <video src="https://sr.ht/-ssd.webm" controls></video> | 6 | <div class="row"> |
7 | <div class="col-md-4"> | ||
8 | <h1><img src="/assets/logo.png" id="logo" alt="Sway" /></h1> | ||
9 | <p> | ||
10 | Sway is tiling Wayland compositor and a drop-in replacement for the | ||
11 | <a href="http://i3wm.org/">i3 window manager</a> for X11. It works | ||
12 | with your existing i3 configuration and supports most of i3's | ||
13 | features, plus a few extras. | ||
14 | </p> | ||
15 | <p> | ||
16 | We also maintain the <a href="https://github.com/swaywm/wlroots">wlroots</a> | ||
17 | project to provide a modular basis for Sway and other Wayland compositors | ||
18 | to build upon, and we <a href="https://github.com/swaywm/sway-protocols"> | ||
19 | publish standards</a> for interopable Wayland desktops. | ||
20 | </p> | ||
21 | <a rel="noopener noreferrer" target="_blank" href="https://patreon.com/sircmpwn"> | ||
22 | <img src="/assets/patreon.png" alt="Support Sway on Patreon" /> | ||
23 | </a> | ||
24 | </div> | ||
25 | <div class="col-md-8"> | ||
26 | <link rel="stylesheet" href="/css/video-js.css"> | ||
27 | <script> | ||
28 | window.HELP_IMPROVE_VIDEOJS = false; | ||
29 | </script> | ||
30 | <script src="/js/video.js"></script> | ||
31 | |||
32 | <video class="video-js vjs-16-9" data-setup="{}" controls> | ||
33 | <source src="https://sr.ht/lJ9C.webm" type="video/webm"> | ||
34 | <p>Your browser does not support HTML5 video.</p> | ||
35 | </video> | ||
36 | </div> | ||
37 | </div> | ||
diff --git a/js/video.js b/js/video.js new file mode 100644 index 00000000..03daf688 --- /dev/null +++ b/js/video.js | |||
@@ -0,0 +1,22383 @@ | |||
1 | /** | ||
2 | * @license | ||
3 | * Video.js 5.8.8 <http://videojs.com/> | ||
4 | * Copyright Brightcove, Inc. <https://www.brightcove.com/> | ||
5 | * Available under Apache License Version 2.0 | ||
6 | * <https://github.com/videojs/video.js/blob/master/LICENSE> | ||
7 | * | ||
8 | * Includes vtt.js <https://github.com/mozilla/vtt.js> | ||
9 | * Available under Apache License Version 2.0 | ||
10 | * <https://github.com/mozilla/vtt.js/blob/master/LICENSE> | ||
11 | */ | ||
12 | |||
13 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | ||
14 | (function (global){ | ||
15 | var topLevel = typeof global !== 'undefined' ? global : | ||
16 | typeof window !== 'undefined' ? window : {} | ||
17 | var minDoc = _dereq_('min-document'); | ||
18 | |||
19 | if (typeof document !== 'undefined') { | ||
20 | module.exports = document; | ||
21 | } else { | ||
22 | var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; | ||
23 | |||
24 | if (!doccy) { | ||
25 | doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; | ||
26 | } | ||
27 | |||
28 | module.exports = doccy; | ||
29 | } | ||
30 | |||
31 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | ||
32 | //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9nbG9iYWwvZG9jdW1lbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgdG9wTGV2ZWwgPSB0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6XG4gICAgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB7fVxudmFyIG1pbkRvYyA9IHJlcXVpcmUoJ21pbi1kb2N1bWVudCcpO1xuXG5pZiAodHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJykge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZG9jdW1lbnQ7XG59IGVsc2Uge1xuICAgIHZhciBkb2NjeSA9IHRvcExldmVsWydfX0dMT0JBTF9ET0NVTUVOVF9DQUNIRUA0J107XG5cbiAgICBpZiAoIWRvY2N5KSB7XG4gICAgICAgIGRvY2N5ID0gdG9wTGV2ZWxbJ19fR0xPQkFMX0RPQ1VNRU5UX0NBQ0hFQDQnXSA9IG1pbkRvYztcbiAgICB9XG5cbiAgICBtb2R1bGUuZXhwb3J0cyA9IGRvY2N5O1xufVxuIl19 | ||
33 | },{"min-document":3}],2:[function(_dereq_,module,exports){ | ||
34 | (function (global){ | ||
35 | if (typeof window !== "undefined") { | ||
36 | module.exports = window; | ||
37 | } else if (typeof global !== "undefined") { | ||
38 | module.exports = global; | ||
39 | } else if (typeof self !== "undefined"){ | ||
40 | module.exports = self; | ||
41 | } else { | ||
42 | module.exports = {}; | ||
43 | } | ||
44 | |||
45 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | ||
46 | //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9nbG9iYWwvd2luZG93LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiaWYgKHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHdpbmRvdztcbn0gZWxzZSBpZiAodHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZ2xvYmFsO1xufSBlbHNlIGlmICh0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIil7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBzZWxmO1xufSBlbHNlIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHt9O1xufVxuIl19 | ||
47 | },{}],3:[function(_dereq_,module,exports){ | ||
48 | |||
49 | },{}],4:[function(_dereq_,module,exports){ | ||
50 | var getNative = _dereq_('../internal/getNative'); | ||
51 | |||
52 | /* Native method references for those with the same name as other `lodash` methods. */ | ||
53 | var nativeNow = getNative(Date, 'now'); | ||
54 | |||
55 | /** | ||
56 | * Gets the number of milliseconds that have elapsed since the Unix epoch | ||
57 | * (1 January 1970 00:00:00 UTC). | ||
58 | * | ||
59 | * @static | ||
60 | * @memberOf _ | ||
61 | * @category Date | ||
62 | * @example | ||
63 | * | ||
64 | * _.defer(function(stamp) { | ||
65 | * console.log(_.now() - stamp); | ||
66 | * }, _.now()); | ||
67 | * // => logs the number of milliseconds it took for the deferred function to be invoked | ||
68 | */ | ||
69 | var now = nativeNow || function() { | ||
70 | return new Date().getTime(); | ||
71 | }; | ||
72 | |||
73 | module.exports = now; | ||
74 | |||
75 | },{"../internal/getNative":20}],5:[function(_dereq_,module,exports){ | ||
76 | var isObject = _dereq_('../lang/isObject'), | ||
77 | now = _dereq_('../date/now'); | ||
78 | |||
79 | /** Used as the `TypeError` message for "Functions" methods. */ | ||
80 | var FUNC_ERROR_TEXT = 'Expected a function'; | ||
81 | |||
82 | /* Native method references for those with the same name as other `lodash` methods. */ | ||
83 | var nativeMax = Math.max; | ||
84 | |||
85 | /** | ||
86 | * Creates a debounced function that delays invoking `func` until after `wait` | ||
87 | * milliseconds have elapsed since the last time the debounced function was | ||
88 | * invoked. The debounced function comes with a `cancel` method to cancel | ||
89 | * delayed invocations. Provide an options object to indicate that `func` | ||
90 | * should be invoked on the leading and/or trailing edge of the `wait` timeout. | ||
91 | * Subsequent calls to the debounced function return the result of the last | ||
92 | * `func` invocation. | ||
93 | * | ||
94 | * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked | ||
95 | * on the trailing edge of the timeout only if the the debounced function is | ||
96 | * invoked more than once during the `wait` timeout. | ||
97 | * | ||
98 | * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) | ||
99 | * for details over the differences between `_.debounce` and `_.throttle`. | ||
100 | * | ||
101 | * @static | ||
102 | * @memberOf _ | ||
103 | * @category Function | ||
104 | * @param {Function} func The function to debounce. | ||
105 | * @param {number} [wait=0] The number of milliseconds to delay. | ||
106 | * @param {Object} [options] The options object. | ||
107 | * @param {boolean} [options.leading=false] Specify invoking on the leading | ||
108 | * edge of the timeout. | ||
109 | * @param {number} [options.maxWait] The maximum time `func` is allowed to be | ||
110 | * delayed before it's invoked. | ||
111 | * @param {boolean} [options.trailing=true] Specify invoking on the trailing | ||
112 | * edge of the timeout. | ||
113 | * @returns {Function} Returns the new debounced function. | ||
114 | * @example | ||
115 | * | ||
116 | * // avoid costly calculations while the window size is in flux | ||
117 | * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); | ||
118 | * | ||
119 | * // invoke `sendMail` when the click event is fired, debouncing subsequent calls | ||
120 | * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { | ||
121 | * 'leading': true, | ||
122 | * 'trailing': false | ||
123 | * })); | ||
124 | * | ||
125 | * // ensure `batchLog` is invoked once after 1 second of debounced calls | ||
126 | * var source = new EventSource('/stream'); | ||
127 | * jQuery(source).on('message', _.debounce(batchLog, 250, { | ||
128 | * 'maxWait': 1000 | ||
129 | * })); | ||
130 | * | ||
131 | * // cancel a debounced call | ||
132 | * var todoChanges = _.debounce(batchLog, 1000); | ||
133 | * Object.observe(models.todo, todoChanges); | ||
134 | * | ||
135 | * Object.observe(models, function(changes) { | ||
136 | * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { | ||
137 | * todoChanges.cancel(); | ||
138 | * } | ||
139 | * }, ['delete']); | ||
140 | * | ||
141 | * // ...at some point `models.todo` is changed | ||
142 | * models.todo.completed = true; | ||
143 | * | ||
144 | * // ...before 1 second has passed `models.todo` is deleted | ||
145 | * // which cancels the debounced `todoChanges` call | ||
146 | * delete models.todo; | ||
147 | */ | ||
148 | function debounce(func, wait, options) { | ||
149 | var args, | ||
150 | maxTimeoutId, | ||
151 | result, | ||
152 | stamp, | ||
153 | thisArg, | ||
154 | timeoutId, | ||
155 | trailingCall, | ||
156 | lastCalled = 0, | ||
157 | maxWait = false, | ||
158 | trailing = true; | ||
159 | |||
160 | if (typeof func != 'function') { | ||
161 | throw new TypeError(FUNC_ERROR_TEXT); | ||
162 | } | ||
163 | wait = wait < 0 ? 0 : (+wait || 0); | ||
164 | if (options === true) { | ||
165 | var leading = true; | ||
166 | trailing = false; | ||
167 | } else if (isObject(options)) { | ||
168 | leading = !!options.leading; | ||
169 | maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); | ||
170 | trailing = 'trailing' in options ? !!options.trailing : trailing; | ||
171 | } | ||
172 | |||
173 | function cancel() { | ||
174 | if (timeoutId) { | ||
175 | clearTimeout(timeoutId); | ||
176 | } | ||
177 | if (maxTimeoutId) { | ||
178 | clearTimeout(maxTimeoutId); | ||
179 | } | ||
180 | lastCalled = 0; | ||
181 | maxTimeoutId = timeoutId = trailingCall = undefined; | ||
182 | } | ||
183 | |||
184 | function complete(isCalled, id) { | ||
185 | if (id) { | ||
186 | clearTimeout(id); | ||
187 | } | ||
188 | maxTimeoutId = timeoutId = trailingCall = undefined; | ||
189 | if (isCalled) { | ||
190 | lastCalled = now(); | ||
191 | result = func.apply(thisArg, args); | ||
192 | if (!timeoutId && !maxTimeoutId) { | ||
193 | args = thisArg = undefined; | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | function delayed() { | ||
199 | var remaining = wait - (now() - stamp); | ||
200 | if (remaining <= 0 || remaining > wait) { | ||
201 | complete(trailingCall, maxTimeoutId); | ||
202 | } else { | ||
203 | timeoutId = setTimeout(delayed, remaining); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | function maxDelayed() { | ||
208 | complete(trailing, timeoutId); | ||
209 | } | ||
210 | |||
211 | function debounced() { | ||
212 | args = arguments; | ||
213 | stamp = now(); | ||
214 | thisArg = this; | ||
215 | trailingCall = trailing && (timeoutId || !leading); | ||
216 | |||
217 | if (maxWait === false) { | ||
218 | var leadingCall = leading && !timeoutId; | ||
219 | } else { | ||
220 | if (!maxTimeoutId && !leading) { | ||
221 | lastCalled = stamp; | ||
222 | } | ||
223 | var remaining = maxWait - (stamp - lastCalled), | ||
224 | isCalled = remaining <= 0 || remaining > maxWait; | ||
225 | |||
226 | if (isCalled) { | ||
227 | if (maxTimeoutId) { | ||
228 | maxTimeoutId = clearTimeout(maxTimeoutId); | ||
229 | } | ||
230 | lastCalled = stamp; | ||
231 | result = func.apply(thisArg, args); | ||
232 | } | ||
233 | else if (!maxTimeoutId) { | ||
234 | maxTimeoutId = setTimeout(maxDelayed, remaining); | ||
235 | } | ||
236 | } | ||
237 | if (isCalled && timeoutId) { | ||
238 | timeoutId = clearTimeout(timeoutId); | ||
239 | } | ||
240 | else if (!timeoutId && wait !== maxWait) { | ||
241 | timeoutId = setTimeout(delayed, wait); | ||
242 | } | ||
243 | if (leadingCall) { | ||
244 | isCalled = true; | ||
245 | result = func.apply(thisArg, args); | ||
246 | } | ||
247 | if (isCalled && !timeoutId && !maxTimeoutId) { | ||
248 | args = thisArg = undefined; | ||
249 | } | ||
250 | return result; | ||
251 | } | ||
252 | debounced.cancel = cancel; | ||
253 | return debounced; | ||
254 | } | ||
255 | |||
256 | module.exports = debounce; | ||
257 | |||
258 | },{"../date/now":4,"../lang/isObject":33}],6:[function(_dereq_,module,exports){ | ||
259 | /** Used as the `TypeError` message for "Functions" methods. */ | ||
260 | var FUNC_ERROR_TEXT = 'Expected a function'; | ||
261 | |||
262 | /* Native method references for those with the same name as other `lodash` methods. */ | ||
263 | var nativeMax = Math.max; | ||
264 | |||
265 | /** | ||
266 | * Creates a function that invokes `func` with the `this` binding of the | ||
267 | * created function and arguments from `start` and beyond provided as an array. | ||
268 | * | ||
269 | * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters). | ||
270 | * | ||
271 | * @static | ||
272 | * @memberOf _ | ||
273 | * @category Function | ||
274 | * @param {Function} func The function to apply a rest parameter to. | ||
275 | * @param {number} [start=func.length-1] The start position of the rest parameter. | ||
276 | * @returns {Function} Returns the new function. | ||
277 | * @example | ||
278 | * | ||
279 | * var say = _.restParam(function(what, names) { | ||
280 | * return what + ' ' + _.initial(names).join(', ') + | ||
281 | * (_.size(names) > 1 ? ', & ' : '') + _.last(names); | ||
282 | * }); | ||
283 | * | ||
284 | * say('hello', 'fred', 'barney', 'pebbles'); | ||
285 | * // => 'hello fred, barney, & pebbles' | ||
286 | */ | ||
287 | function restParam(func, start) { | ||
288 | if (typeof func != 'function') { | ||
289 | throw new TypeError(FUNC_ERROR_TEXT); | ||
290 | } | ||
291 | start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); | ||
292 | return function() { | ||
293 | var args = arguments, | ||
294 | index = -1, | ||
295 | length = nativeMax(args.length - start, 0), | ||
296 | rest = Array(length); | ||
297 | |||
298 | while (++index < length) { | ||
299 | rest[index] = args[start + index]; | ||
300 | } | ||
301 | switch (start) { | ||
302 | case 0: return func.call(this, rest); | ||
303 | case 1: return func.call(this, args[0], rest); | ||
304 | case 2: return func.call(this, args[0], args[1], rest); | ||
305 | } | ||
306 | var otherArgs = Array(start + 1); | ||
307 | index = -1; | ||
308 | while (++index < start) { | ||
309 | otherArgs[index] = args[index]; | ||
310 | } | ||
311 | otherArgs[start] = rest; | ||
312 | return func.apply(this, otherArgs); | ||
313 | }; | ||
314 | } | ||
315 | |||
316 | module.exports = restParam; | ||
317 | |||
318 | },{}],7:[function(_dereq_,module,exports){ | ||
319 | var debounce = _dereq_('./debounce'), | ||
320 | isObject = _dereq_('../lang/isObject'); | ||
321 | |||
322 | /** Used as the `TypeError` message for "Functions" methods. */ | ||
323 | var FUNC_ERROR_TEXT = 'Expected a function'; | ||
324 | |||
325 | /** | ||
326 | * Creates a throttled function that only invokes `func` at most once per | ||
327 | * every `wait` milliseconds. The throttled function comes with a `cancel` | ||
328 | * method to cancel delayed invocations. Provide an options object to indicate | ||
329 | * that `func` should be invoked on the leading and/or trailing edge of the | ||
330 | * `wait` timeout. Subsequent calls to the throttled function return the | ||
331 | * result of the last `func` call. | ||
332 | * | ||
333 | * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked | ||
334 | * on the trailing edge of the timeout only if the the throttled function is | ||
335 | * invoked more than once during the `wait` timeout. | ||
336 | * | ||
337 | * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) | ||
338 | * for details over the differences between `_.throttle` and `_.debounce`. | ||
339 | * | ||
340 | * @static | ||
341 | * @memberOf _ | ||
342 | * @category Function | ||
343 | * @param {Function} func The function to throttle. | ||
344 | * @param {number} [wait=0] The number of milliseconds to throttle invocations to. | ||
345 | * @param {Object} [options] The options object. | ||
346 | * @param {boolean} [options.leading=true] Specify invoking on the leading | ||
347 | * edge of the timeout. | ||
348 | * @param {boolean} [options.trailing=true] Specify invoking on the trailing | ||
349 | * edge of the timeout. | ||
350 | * @returns {Function} Returns the new throttled function. | ||
351 | * @example | ||
352 | * | ||
353 | * // avoid excessively updating the position while scrolling | ||
354 | * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); | ||
355 | * | ||
356 | * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes | ||
357 | * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { | ||
358 | * 'trailing': false | ||
359 | * })); | ||
360 | * | ||
361 | * // cancel a trailing throttled call | ||
362 | * jQuery(window).on('popstate', throttled.cancel); | ||
363 | */ | ||
364 | function throttle(func, wait, options) { | ||
365 | var leading = true, | ||
366 | trailing = true; | ||
367 | |||
368 | if (typeof func != 'function') { | ||
369 | throw new TypeError(FUNC_ERROR_TEXT); | ||
370 | } | ||
371 | if (options === false) { | ||
372 | leading = false; | ||
373 | } else if (isObject(options)) { | ||
374 | leading = 'leading' in options ? !!options.leading : leading; | ||
375 | trailing = 'trailing' in options ? !!options.trailing : trailing; | ||
376 | } | ||
377 | return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing }); | ||
378 | } | ||
379 | |||
380 | module.exports = throttle; | ||
381 | |||
382 | },{"../lang/isObject":33,"./debounce":5}],8:[function(_dereq_,module,exports){ | ||
383 | /** | ||
384 | * Copies the values of `source` to `array`. | ||
385 | * | ||
386 | * @private | ||
387 | * @param {Array} source The array to copy values from. | ||
388 | * @param {Array} [array=[]] The array to copy values to. | ||
389 | * @returns {Array} Returns `array`. | ||
390 | */ | ||
391 | function arrayCopy(source, array) { | ||
392 | var index = -1, | ||
393 | length = source.length; | ||
394 | |||
395 | array || (array = Array(length)); | ||
396 | while (++index < length) { | ||
397 | array[index] = source[index]; | ||
398 | } | ||
399 | return array; | ||
400 | } | ||
401 | |||
402 | module.exports = arrayCopy; | ||
403 | |||
404 | },{}],9:[function(_dereq_,module,exports){ | ||
405 | /** | ||
406 | * A specialized version of `_.forEach` for arrays without support for callback | ||
407 | * shorthands and `this` binding. | ||
408 | * | ||
409 | * @private | ||
410 | * @param {Array} array The array to iterate over. | ||
411 | * @param {Function} iteratee The function invoked per iteration. | ||
412 | * @returns {Array} Returns `array`. | ||
413 | */ | ||
414 | function arrayEach(array, iteratee) { | ||
415 | var index = -1, | ||
416 | length = array.length; | ||
417 | |||
418 | while (++index < length) { | ||
419 | if (iteratee(array[index], index, array) === false) { | ||
420 | break; | ||
421 | } | ||
422 | } | ||
423 | return array; | ||
424 | } | ||
425 | |||
426 | module.exports = arrayEach; | ||
427 | |||
428 | },{}],10:[function(_dereq_,module,exports){ | ||
429 | /** | ||
430 | * Copies properties of `source` to `object`. | ||
431 | * | ||
432 | * @private | ||
433 | * @param {Object} source The object to copy properties from. | ||
434 | * @param {Array} props The property names to copy. | ||
435 | * @param {Object} [object={}] The object to copy properties to. | ||
436 | * @returns {Object} Returns `object`. | ||
437 | */ | ||
438 | function baseCopy(source, props, object) { | ||
439 | object || (object = {}); | ||
440 | |||
441 | var index = -1, | ||
442 | length = props.length; | ||
443 | |||
444 | while (++index < length) { | ||
445 | var key = props[index]; | ||
446 | object[key] = source[key]; | ||
447 | } | ||
448 | return object; | ||
449 | } | ||
450 | |||
451 | module.exports = baseCopy; | ||
452 | |||
453 | },{}],11:[function(_dereq_,module,exports){ | ||
454 | var createBaseFor = _dereq_('./createBaseFor'); | ||
455 | |||
456 | /** | ||
457 | * The base implementation of `baseForIn` and `baseForOwn` which iterates | ||
458 | * over `object` properties returned by `keysFunc` invoking `iteratee` for | ||
459 | * each property. Iteratee functions may exit iteration early by explicitly | ||
460 | * returning `false`. | ||
461 | * | ||
462 | * @private | ||
463 | * @param {Object} object The object to iterate over. | ||
464 | * @param {Function} iteratee The function invoked per iteration. | ||
465 | * @param {Function} keysFunc The function to get the keys of `object`. | ||
466 | * @returns {Object} Returns `object`. | ||
467 | */ | ||
468 | var baseFor = createBaseFor(); | ||
469 | |||
470 | module.exports = baseFor; | ||
471 | |||
472 | },{"./createBaseFor":18}],12:[function(_dereq_,module,exports){ | ||
473 | var baseFor = _dereq_('./baseFor'), | ||
474 | keysIn = _dereq_('../object/keysIn'); | ||
475 | |||
476 | /** | ||
477 | * The base implementation of `_.forIn` without support for callback | ||
478 | * shorthands and `this` binding. | ||
479 | * | ||
480 | * @private | ||
481 | * @param {Object} object The object to iterate over. | ||
482 | * @param {Function} iteratee The function invoked per iteration. | ||
483 | * @returns {Object} Returns `object`. | ||
484 | */ | ||
485 | function baseForIn(object, iteratee) { | ||
486 | return baseFor(object, iteratee, keysIn); | ||
487 | } | ||
488 | |||
489 | module.exports = baseForIn; | ||
490 | |||
491 | },{"../object/keysIn":39,"./baseFor":11}],13:[function(_dereq_,module,exports){ | ||
492 | var arrayEach = _dereq_('./arrayEach'), | ||
493 | baseMergeDeep = _dereq_('./baseMergeDeep'), | ||
494 | isArray = _dereq_('../lang/isArray'), | ||
495 | isArrayLike = _dereq_('./isArrayLike'), | ||
496 | isObject = _dereq_('../lang/isObject'), | ||
497 | isObjectLike = _dereq_('./isObjectLike'), | ||
498 | isTypedArray = _dereq_('../lang/isTypedArray'), | ||
499 | keys = _dereq_('../object/keys'); | ||
500 | |||
501 | /** | ||
502 | * The base implementation of `_.merge` without support for argument juggling, | ||
503 | * multiple sources, and `this` binding `customizer` functions. | ||
504 | * | ||
505 | * @private | ||
506 | * @param {Object} object The destination object. | ||
507 | * @param {Object} source The source object. | ||
508 | * @param {Function} [customizer] The function to customize merged values. | ||
509 | * @param {Array} [stackA=[]] Tracks traversed source objects. | ||
510 | * @param {Array} [stackB=[]] Associates values with source counterparts. | ||
511 | * @returns {Object} Returns `object`. | ||
512 | */ | ||
513 | function baseMerge(object, source, customizer, stackA, stackB) { | ||
514 | if (!isObject(object)) { | ||
515 | return object; | ||
516 | } | ||
517 | var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), | ||
518 | props = isSrcArr ? undefined : keys(source); | ||
519 | |||
520 | arrayEach(props || source, function(srcValue, key) { | ||
521 | if (props) { | ||
522 | key = srcValue; | ||
523 | srcValue = source[key]; | ||
524 | } | ||
525 | if (isObjectLike(srcValue)) { | ||
526 | stackA || (stackA = []); | ||
527 | stackB || (stackB = []); | ||
528 | baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); | ||
529 | } | ||
530 | else { | ||
531 | var value = object[key], | ||
532 | result = customizer ? customizer(value, srcValue, key, object, source) : undefined, | ||
533 | isCommon = result === undefined; | ||
534 | |||
535 | if (isCommon) { | ||
536 | result = srcValue; | ||
537 | } | ||
538 | if ((result !== undefined || (isSrcArr && !(key in object))) && | ||
539 | (isCommon || (result === result ? (result !== value) : (value === value)))) { | ||
540 | object[key] = result; | ||
541 | } | ||
542 | } | ||
543 | }); | ||
544 | return object; | ||
545 | } | ||
546 | |||
547 | module.exports = baseMerge; | ||
548 | |||
549 | },{"../lang/isArray":30,"../lang/isObject":33,"../lang/isTypedArray":36,"../object/keys":38,"./arrayEach":9,"./baseMergeDeep":14,"./isArrayLike":21,"./isObjectLike":26}],14:[function(_dereq_,module,exports){ | ||
550 | var arrayCopy = _dereq_('./arrayCopy'), | ||
551 | isArguments = _dereq_('../lang/isArguments'), | ||
552 | isArray = _dereq_('../lang/isArray'), | ||
553 | isArrayLike = _dereq_('./isArrayLike'), | ||
554 | isPlainObject = _dereq_('../lang/isPlainObject'), | ||
555 | isTypedArray = _dereq_('../lang/isTypedArray'), | ||
556 | toPlainObject = _dereq_('../lang/toPlainObject'); | ||
557 | |||
558 | /** | ||
559 | * A specialized version of `baseMerge` for arrays and objects which performs | ||
560 | * deep merges and tracks traversed objects enabling objects with circular | ||
561 | * references to be merged. | ||
562 | * | ||
563 | * @private | ||
564 | * @param {Object} object The destination object. | ||
565 | * @param {Object} source The source object. | ||
566 | * @param {string} key The key of the value to merge. | ||
567 | * @param {Function} mergeFunc The function to merge values. | ||
568 | * @param {Function} [customizer] The function to customize merged values. | ||
569 | * @param {Array} [stackA=[]] Tracks traversed source objects. | ||
570 | * @param {Array} [stackB=[]] Associates values with source counterparts. | ||
571 | * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. | ||
572 | */ | ||
573 | function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { | ||
574 | var length = stackA.length, | ||
575 | srcValue = source[key]; | ||
576 | |||
577 | while (length--) { | ||
578 | if (stackA[length] == srcValue) { | ||
579 | object[key] = stackB[length]; | ||
580 | return; | ||
581 | } | ||
582 | } | ||
583 | var value = object[key], | ||
584 | result = customizer ? customizer(value, srcValue, key, object, source) : undefined, | ||
585 | isCommon = result === undefined; | ||
586 | |||
587 | if (isCommon) { | ||
588 | result = srcValue; | ||
589 | if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { | ||
590 | result = isArray(value) | ||
591 | ? value | ||
592 | : (isArrayLike(value) ? arrayCopy(value) : []); | ||
593 | } | ||
594 | else if (isPlainObject(srcValue) || isArguments(srcValue)) { | ||
595 | result = isArguments(value) | ||
596 | ? toPlainObject(value) | ||
597 | : (isPlainObject(value) ? value : {}); | ||
598 | } | ||
599 | else { | ||
600 | isCommon = false; | ||
601 | } | ||
602 | } | ||
603 | // Add the source value to the stack of traversed objects and associate | ||
604 | // it with its merged value. | ||
605 | stackA.push(srcValue); | ||
606 | stackB.push(result); | ||
607 | |||
608 | if (isCommon) { | ||
609 | // Recursively merge objects and arrays (susceptible to call stack limits). | ||
610 | object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); | ||
611 | } else if (result === result ? (result !== value) : (value === value)) { | ||
612 | object[key] = result; | ||
613 | } | ||
614 | } | ||
615 | |||
616 | module.exports = baseMergeDeep; | ||
617 | |||
618 | },{"../lang/isArguments":29,"../lang/isArray":30,"../lang/isPlainObject":34,"../lang/isTypedArray":36,"../lang/toPlainObject":37,"./arrayCopy":8,"./isArrayLike":21}],15:[function(_dereq_,module,exports){ | ||
619 | var toObject = _dereq_('./toObject'); | ||
620 | |||
621 | /** | ||
622 | * The base implementation of `_.property` without support for deep paths. | ||
623 | * | ||
624 | * @private | ||
625 | * @param {string} key The key of the property to get. | ||
626 | * @returns {Function} Returns the new function. | ||
627 | */ | ||
628 | function baseProperty(key) { | ||
629 | return function(object) { | ||
630 | return object == null ? undefined : toObject(object)[key]; | ||
631 | }; | ||
632 | } | ||
633 | |||
634 | module.exports = baseProperty; | ||
635 | |||
636 | },{"./toObject":28}],16:[function(_dereq_,module,exports){ | ||
637 | var identity = _dereq_('../utility/identity'); | ||
638 | |||
639 | /** | ||
640 | * A specialized version of `baseCallback` which only supports `this` binding | ||
641 | * and specifying the number of arguments to provide to `func`. | ||
642 | * | ||
643 | * @private | ||
644 | * @param {Function} func The function to bind. | ||
645 | * @param {*} thisArg The `this` binding of `func`. | ||
646 | * @param {number} [argCount] The number of arguments to provide to `func`. | ||
647 | * @returns {Function} Returns the callback. | ||
648 | */ | ||
649 | function bindCallback(func, thisArg, argCount) { | ||
650 | if (typeof func != 'function') { | ||
651 | return identity; | ||
652 | } | ||
653 | if (thisArg === undefined) { | ||
654 | return func; | ||
655 | } | ||
656 | switch (argCount) { | ||
657 | case 1: return function(value) { | ||
658 | return func.call(thisArg, value); | ||
659 | }; | ||
660 | case 3: return function(value, index, collection) { | ||
661 | return func.call(thisArg, value, index, collection); | ||
662 | }; | ||
663 | case 4: return function(accumulator, value, index, collection) { | ||
664 | return func.call(thisArg, accumulator, value, index, collection); | ||
665 | }; | ||
666 | case 5: return function(value, other, key, object, source) { | ||
667 | return func.call(thisArg, value, other, key, object, source); | ||
668 | }; | ||
669 | } | ||
670 | return function() { | ||
671 | return func.apply(thisArg, arguments); | ||
672 | }; | ||
673 | } | ||
674 | |||
675 | module.exports = bindCallback; | ||
676 | |||
677 | },{"../utility/identity":42}],17:[function(_dereq_,module,exports){ | ||
678 | var bindCallback = _dereq_('./bindCallback'), | ||
679 | isIterateeCall = _dereq_('./isIterateeCall'), | ||
680 | restParam = _dereq_('../function/restParam'); | ||
681 | |||
682 | /** | ||
683 | * Creates a `_.assign`, `_.defaults`, or `_.merge` function. | ||
684 | * | ||
685 | * @private | ||
686 | * @param {Function} assigner The function to assign values. | ||
687 | * @returns {Function} Returns the new assigner function. | ||
688 | */ | ||
689 | function createAssigner(assigner) { | ||
690 | return restParam(function(object, sources) { | ||
691 | var index = -1, | ||
692 | length = object == null ? 0 : sources.length, | ||
693 | customizer = length > 2 ? sources[length - 2] : undefined, | ||
694 | guard = length > 2 ? sources[2] : undefined, | ||
695 | thisArg = length > 1 ? sources[length - 1] : undefined; | ||
696 | |||
697 | if (typeof customizer == 'function') { | ||
698 | customizer = bindCallback(customizer, thisArg, 5); | ||
699 | length -= 2; | ||
700 | } else { | ||
701 | customizer = typeof thisArg == 'function' ? thisArg : undefined; | ||
702 | length -= (customizer ? 1 : 0); | ||
703 | } | ||
704 | if (guard && isIterateeCall(sources[0], sources[1], guard)) { | ||
705 | customizer = length < 3 ? undefined : customizer; | ||
706 | length = 1; | ||
707 | } | ||
708 | while (++index < length) { | ||
709 | var source = sources[index]; | ||
710 | if (source) { | ||
711 | assigner(object, source, customizer); | ||
712 | } | ||
713 | } | ||
714 | return object; | ||
715 | }); | ||
716 | } | ||
717 | |||
718 | module.exports = createAssigner; | ||
719 | |||
720 | },{"../function/restParam":6,"./bindCallback":16,"./isIterateeCall":24}],18:[function(_dereq_,module,exports){ | ||
721 | var toObject = _dereq_('./toObject'); | ||
722 | |||
723 | /** | ||
724 | * Creates a base function for `_.forIn` or `_.forInRight`. | ||
725 | * | ||
726 | * @private | ||
727 | * @param {boolean} [fromRight] Specify iterating from right to left. | ||
728 | * @returns {Function} Returns the new base function. | ||
729 | */ | ||
730 | function createBaseFor(fromRight) { | ||
731 | return function(object, iteratee, keysFunc) { | ||
732 | var iterable = toObject(object), | ||
733 | props = keysFunc(object), | ||
734 | length = props.length, | ||
735 | index = fromRight ? length : -1; | ||
736 | |||
737 | while ((fromRight ? index-- : ++index < length)) { | ||
738 | var key = props[index]; | ||
739 | if (iteratee(iterable[key], key, iterable) === false) { | ||
740 | break; | ||
741 | } | ||
742 | } | ||
743 | return object; | ||
744 | }; | ||
745 | } | ||
746 | |||
747 | module.exports = createBaseFor; | ||
748 | |||
749 | },{"./toObject":28}],19:[function(_dereq_,module,exports){ | ||
750 | var baseProperty = _dereq_('./baseProperty'); | ||
751 | |||
752 | /** | ||
753 | * Gets the "length" property value of `object`. | ||
754 | * | ||
755 | * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) | ||
756 | * that affects Safari on at least iOS 8.1-8.3 ARM64. | ||
757 | * | ||
758 | * @private | ||
759 | * @param {Object} object The object to query. | ||
760 | * @returns {*} Returns the "length" value. | ||
761 | */ | ||
762 | var getLength = baseProperty('length'); | ||
763 | |||
764 | module.exports = getLength; | ||
765 | |||
766 | },{"./baseProperty":15}],20:[function(_dereq_,module,exports){ | ||
767 | var isNative = _dereq_('../lang/isNative'); | ||
768 | |||
769 | /** | ||
770 | * Gets the native function at `key` of `object`. | ||
771 | * | ||
772 | * @private | ||
773 | * @param {Object} object The object to query. | ||
774 | * @param {string} key The key of the method to get. | ||
775 | * @returns {*} Returns the function if it's native, else `undefined`. | ||
776 | */ | ||
777 | function getNative(object, key) { | ||
778 | var value = object == null ? undefined : object[key]; | ||
779 | return isNative(value) ? value : undefined; | ||
780 | } | ||
781 | |||
782 | module.exports = getNative; | ||
783 | |||
784 | },{"../lang/isNative":32}],21:[function(_dereq_,module,exports){ | ||
785 | var getLength = _dereq_('./getLength'), | ||
786 | isLength = _dereq_('./isLength'); | ||
787 | |||
788 | /** | ||
789 | * Checks if `value` is array-like. | ||
790 | * | ||
791 | * @private | ||
792 | * @param {*} value The value to check. | ||
793 | * @returns {boolean} Returns `true` if `value` is array-like, else `false`. | ||
794 | */ | ||
795 | function isArrayLike(value) { | ||
796 | return value != null && isLength(getLength(value)); | ||
797 | } | ||
798 | |||
799 | module.exports = isArrayLike; | ||
800 | |||
801 | },{"./getLength":19,"./isLength":25}],22:[function(_dereq_,module,exports){ | ||
802 | /** | ||
803 | * Checks if `value` is a host object in IE < 9. | ||
804 | * | ||
805 | * @private | ||
806 | * @param {*} value The value to check. | ||
807 | * @returns {boolean} Returns `true` if `value` is a host object, else `false`. | ||
808 | */ | ||
809 | var isHostObject = (function() { | ||
810 | try { | ||
811 | Object({ 'toString': 0 } + ''); | ||
812 | } catch(e) { | ||
813 | return function() { return false; }; | ||
814 | } | ||
815 | return function(value) { | ||
816 | // IE < 9 presents many host objects as `Object` objects that can coerce | ||
817 | // to strings despite having improperly defined `toString` methods. | ||
818 | return typeof value.toString != 'function' && typeof (value + '') == 'string'; | ||
819 | }; | ||
820 | }()); | ||
821 | |||
822 | module.exports = isHostObject; | ||
823 | |||
824 | },{}],23:[function(_dereq_,module,exports){ | ||
825 | /** Used to detect unsigned integer values. */ | ||
826 | var reIsUint = /^\d+$/; | ||
827 | |||
828 | /** | ||
829 | * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) | ||
830 | * of an array-like value. | ||
831 | */ | ||
832 | var MAX_SAFE_INTEGER = 9007199254740991; | ||
833 | |||
834 | /** | ||
835 | * Checks if `value` is a valid array-like index. | ||
836 | * | ||
837 | * @private | ||
838 | * @param {*} value The value to check. | ||
839 | * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. | ||
840 | * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. | ||
841 | */ | ||
842 | function isIndex(value, length) { | ||
843 | value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; | ||
844 | length = length == null ? MAX_SAFE_INTEGER : length; | ||
845 | return value > -1 && value % 1 == 0 && value < length; | ||
846 | } | ||
847 | |||
848 | module.exports = isIndex; | ||
849 | |||
850 | },{}],24:[function(_dereq_,module,exports){ | ||
851 | var isArrayLike = _dereq_('./isArrayLike'), | ||
852 | isIndex = _dereq_('./isIndex'), | ||
853 | isObject = _dereq_('../lang/isObject'); | ||
854 | |||
855 | /** | ||
856 | * Checks if the provided arguments are from an iteratee call. | ||
857 | * | ||
858 | * @private | ||
859 | * @param {*} value The potential iteratee value argument. | ||
860 | * @param {*} index The potential iteratee index or key argument. | ||
861 | * @param {*} object The potential iteratee object argument. | ||
862 | * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. | ||
863 | */ | ||
864 | function isIterateeCall(value, index, object) { | ||
865 | if (!isObject(object)) { | ||
866 | return false; | ||
867 | } | ||
868 | var type = typeof index; | ||
869 | if (type == 'number' | ||
870 | ? (isArrayLike(object) && isIndex(index, object.length)) | ||
871 | : (type == 'string' && index in object)) { | ||
872 | var other = object[index]; | ||
873 | return value === value ? (value === other) : (other !== other); | ||
874 | } | ||
875 | return false; | ||
876 | } | ||
877 | |||
878 | module.exports = isIterateeCall; | ||
879 | |||
880 | },{"../lang/isObject":33,"./isArrayLike":21,"./isIndex":23}],25:[function(_dereq_,module,exports){ | ||
881 | /** | ||
882 | * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) | ||
883 | * of an array-like value. | ||
884 | */ | ||
885 | var MAX_SAFE_INTEGER = 9007199254740991; | ||
886 | |||
887 | /** | ||
888 | * Checks if `value` is a valid array-like length. | ||
889 | * | ||
890 | * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). | ||
891 | * | ||
892 | * @private | ||
893 | * @param {*} value The value to check. | ||
894 | * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. | ||
895 | */ | ||
896 | function isLength(value) { | ||
897 | return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; | ||
898 | } | ||
899 | |||
900 | module.exports = isLength; | ||
901 | |||
902 | },{}],26:[function(_dereq_,module,exports){ | ||
903 | /** | ||
904 | * Checks if `value` is object-like. | ||
905 | * | ||
906 | * @private | ||
907 | * @param {*} value The value to check. | ||
908 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`. | ||
909 | */ | ||
910 | function isObjectLike(value) { | ||
911 | return !!value && typeof value == 'object'; | ||
912 | } | ||
913 | |||
914 | module.exports = isObjectLike; | ||
915 | |||
916 | },{}],27:[function(_dereq_,module,exports){ | ||
917 | var isArguments = _dereq_('../lang/isArguments'), | ||
918 | isArray = _dereq_('../lang/isArray'), | ||
919 | isIndex = _dereq_('./isIndex'), | ||
920 | isLength = _dereq_('./isLength'), | ||
921 | isString = _dereq_('../lang/isString'), | ||
922 | keysIn = _dereq_('../object/keysIn'); | ||
923 | |||
924 | /** Used for native method references. */ | ||
925 | var objectProto = Object.prototype; | ||
926 | |||
927 | /** Used to check objects for own properties. */ | ||
928 | var hasOwnProperty = objectProto.hasOwnProperty; | ||
929 | |||
930 | /** | ||
931 | * A fallback implementation of `Object.keys` which creates an array of the | ||
932 | * own enumerable property names of `object`. | ||
933 | * | ||
934 | * @private | ||
935 | * @param {Object} object The object to query. | ||
936 | * @returns {Array} Returns the array of property names. | ||
937 | */ | ||
938 | function shimKeys(object) { | ||
939 | var props = keysIn(object), | ||
940 | propsLength = props.length, | ||
941 | length = propsLength && object.length; | ||
942 | |||
943 | var allowIndexes = !!length && isLength(length) && | ||
944 | (isArray(object) || isArguments(object) || isString(object)); | ||
945 | |||
946 | var index = -1, | ||
947 | result = []; | ||
948 | |||
949 | while (++index < propsLength) { | ||
950 | var key = props[index]; | ||
951 | if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { | ||
952 | result.push(key); | ||
953 | } | ||
954 | } | ||
955 | return result; | ||
956 | } | ||
957 | |||
958 | module.exports = shimKeys; | ||
959 | |||
960 | },{"../lang/isArguments":29,"../lang/isArray":30,"../lang/isString":35,"../object/keysIn":39,"./isIndex":23,"./isLength":25}],28:[function(_dereq_,module,exports){ | ||
961 | var isObject = _dereq_('../lang/isObject'), | ||
962 | isString = _dereq_('../lang/isString'), | ||
963 | support = _dereq_('../support'); | ||
964 | |||
965 | /** | ||
966 | * Converts `value` to an object if it's not one. | ||
967 | * | ||
968 | * @private | ||
969 | * @param {*} value The value to process. | ||
970 | * @returns {Object} Returns the object. | ||
971 | */ | ||
972 | function toObject(value) { | ||
973 | if (support.unindexedChars && isString(value)) { | ||
974 | var index = -1, | ||
975 | length = value.length, | ||
976 | result = Object(value); | ||
977 | |||
978 | while (++index < length) { | ||
979 | result[index] = value.charAt(index); | ||
980 | } | ||
981 | return result; | ||
982 | } | ||
983 | return isObject(value) ? value : Object(value); | ||
984 | } | ||
985 | |||
986 | module.exports = toObject; | ||
987 | |||
988 | },{"../lang/isObject":33,"../lang/isString":35,"../support":41}],29:[function(_dereq_,module,exports){ | ||
989 | var isArrayLike = _dereq_('../internal/isArrayLike'), | ||
990 | isObjectLike = _dereq_('../internal/isObjectLike'); | ||
991 | |||
992 | /** Used for native method references. */ | ||
993 | var objectProto = Object.prototype; | ||
994 | |||
995 | /** Used to check objects for own properties. */ | ||
996 | var hasOwnProperty = objectProto.hasOwnProperty; | ||
997 | |||
998 | /** Native method references. */ | ||
999 | var propertyIsEnumerable = objectProto.propertyIsEnumerable; | ||
1000 | |||
1001 | /** | ||
1002 | * Checks if `value` is classified as an `arguments` object. | ||
1003 | * | ||
1004 | * @static | ||
1005 | * @memberOf _ | ||
1006 | * @category Lang | ||
1007 | * @param {*} value The value to check. | ||
1008 | * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. | ||
1009 | * @example | ||
1010 | * | ||
1011 | * _.isArguments(function() { return arguments; }()); | ||
1012 | * // => true | ||
1013 | * | ||
1014 | * _.isArguments([1, 2, 3]); | ||
1015 | * // => false | ||
1016 | */ | ||
1017 | function isArguments(value) { | ||
1018 | return isObjectLike(value) && isArrayLike(value) && | ||
1019 | hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); | ||
1020 | } | ||
1021 | |||
1022 | module.exports = isArguments; | ||
1023 | |||
1024 | },{"../internal/isArrayLike":21,"../internal/isObjectLike":26}],30:[function(_dereq_,module,exports){ | ||
1025 | var getNative = _dereq_('../internal/getNative'), | ||
1026 | isLength = _dereq_('../internal/isLength'), | ||
1027 | isObjectLike = _dereq_('../internal/isObjectLike'); | ||
1028 | |||
1029 | /** `Object#toString` result references. */ | ||
1030 | var arrayTag = '[object Array]'; | ||
1031 | |||
1032 | /** Used for native method references. */ | ||
1033 | var objectProto = Object.prototype; | ||
1034 | |||
1035 | /** | ||
1036 | * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) | ||
1037 | * of values. | ||
1038 | */ | ||
1039 | var objToString = objectProto.toString; | ||
1040 | |||
1041 | /* Native method references for those with the same name as other `lodash` methods. */ | ||
1042 | var nativeIsArray = getNative(Array, 'isArray'); | ||
1043 | |||
1044 | /** | ||
1045 | * Checks if `value` is classified as an `Array` object. | ||
1046 | * | ||
1047 | * @static | ||
1048 | * @memberOf _ | ||
1049 | * @category Lang | ||
1050 | * @param {*} value The value to check. | ||
1051 | * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. | ||
1052 | * @example | ||
1053 | * | ||
1054 | * _.isArray([1, 2, 3]); | ||
1055 | * // => true | ||
1056 | * | ||
1057 | * _.isArray(function() { return arguments; }()); | ||
1058 | * // => false | ||
1059 | */ | ||
1060 | var isArray = nativeIsArray || function(value) { | ||
1061 | return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; | ||
1062 | }; | ||
1063 | |||
1064 | module.exports = isArray; | ||
1065 | |||
1066 | },{"../internal/getNative":20,"../internal/isLength":25,"../internal/isObjectLike":26}],31:[function(_dereq_,module,exports){ | ||
1067 | var isObject = _dereq_('./isObject'); | ||
1068 | |||
1069 | /** `Object#toString` result references. */ | ||
1070 | var funcTag = '[object Function]'; | ||
1071 | |||
1072 | /** Used for native method references. */ | ||
1073 | var objectProto = Object.prototype; | ||
1074 | |||
1075 | /** | ||
1076 | * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) | ||
1077 | * of values. | ||
1078 | */ | ||
1079 | var objToString = objectProto.toString; | ||
1080 | |||
1081 | /** | ||
1082 | * Checks if `value` is classified as a `Function` object. | ||
1083 | * | ||
1084 | * @static | ||
1085 | * @memberOf _ | ||
1086 | * @category Lang | ||
1087 | * @param {*} value The value to check. | ||
1088 | * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. | ||
1089 | * @example | ||
1090 | * | ||
1091 | * _.isFunction(_); | ||
1092 | * // => true | ||
1093 | * | ||
1094 | * _.isFunction(/abc/); | ||
1095 | * // => false | ||
1096 | */ | ||
1097 | function isFunction(value) { | ||
1098 | // The use of `Object#toString` avoids issues with the `typeof` operator | ||
1099 | // in older versions of Chrome and Safari which return 'function' for regexes | ||
1100 | // and Safari 8 which returns 'object' for typed array constructors. | ||
1101 | return isObject(value) && objToString.call(value) == funcTag; | ||
1102 | } | ||
1103 | |||
1104 | module.exports = isFunction; | ||
1105 | |||
1106 | },{"./isObject":33}],32:[function(_dereq_,module,exports){ | ||
1107 | var isFunction = _dereq_('./isFunction'), | ||
1108 | isHostObject = _dereq_('../internal/isHostObject'), | ||
1109 | isObjectLike = _dereq_('../internal/isObjectLike'); | ||
1110 | |||
1111 | /** Used to detect host constructors (Safari > 5). */ | ||
1112 | var reIsHostCtor = /^\[object .+?Constructor\]$/; | ||
1113 | |||
1114 | /** Used for native method references. */ | ||
1115 | var objectProto = Object.prototype; | ||
1116 | |||
1117 | /** Used to resolve the decompiled source of functions. */ | ||
1118 | var fnToString = Function.prototype.toString; | ||
1119 | |||
1120 | /** Used to check objects for own properties. */ | ||
1121 | var hasOwnProperty = objectProto.hasOwnProperty; | ||
1122 | |||
1123 | /** Used to detect if a method is native. */ | ||
1124 | var reIsNative = RegExp('^' + | ||
1125 | fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') | ||
1126 | .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' | ||
1127 | ); | ||
1128 | |||
1129 | /** | ||
1130 | * Checks if `value` is a native function. | ||
1131 | * | ||
1132 | * @static | ||
1133 | * @memberOf _ | ||
1134 | * @category Lang | ||
1135 | * @param {*} value The value to check. | ||
1136 | * @returns {boolean} Returns `true` if `value` is a native function, else `false`. | ||
1137 | * @example | ||
1138 | * | ||
1139 | * _.isNative(Array.prototype.push); | ||
1140 | * // => true | ||
1141 | * | ||
1142 | * _.isNative(_); | ||
1143 | * // => false | ||
1144 | */ | ||
1145 | function isNative(value) { | ||
1146 | if (value == null) { | ||
1147 | return false; | ||
1148 | } | ||
1149 | if (isFunction(value)) { | ||
1150 | return reIsNative.test(fnToString.call(value)); | ||
1151 | } | ||
1152 | return isObjectLike(value) && (isHostObject(value) ? reIsNative : reIsHostCtor).test(value); | ||
1153 | } | ||
1154 | |||
1155 | module.exports = isNative; | ||
1156 | |||
1157 | },{"../internal/isHostObject":22,"../internal/isObjectLike":26,"./isFunction":31}],33:[function(_dereq_,module,exports){ | ||
1158 | /** | ||
1159 | * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. | ||
1160 | * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) | ||
1161 | * | ||
1162 | * @static | ||
1163 | * @memberOf _ | ||
1164 | * @category Lang | ||
1165 | * @param {*} value The value to check. | ||
1166 | * @returns {boolean} Returns `true` if `value` is an object, else `false`. | ||
1167 | * @example | ||
1168 | * | ||
1169 | * _.isObject({}); | ||
1170 | * // => true | ||
1171 | * | ||
1172 | * _.isObject([1, 2, 3]); | ||
1173 | * // => true | ||
1174 | * | ||
1175 | * _.isObject(1); | ||
1176 | * // => false | ||
1177 | */ | ||
1178 | function isObject(value) { | ||
1179 | // Avoid a V8 JIT bug in Chrome 19-20. | ||
1180 | // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. | ||
1181 | var type = typeof value; | ||
1182 | return !!value && (type == 'object' || type == 'function'); | ||
1183 | } | ||
1184 | |||
1185 | module.exports = isObject; | ||
1186 | |||
1187 | },{}],34:[function(_dereq_,module,exports){ | ||
1188 | var baseForIn = _dereq_('../internal/baseForIn'), | ||
1189 | isArguments = _dereq_('./isArguments'), | ||
1190 | isHostObject = _dereq_('../internal/isHostObject'), | ||
1191 | isObjectLike = _dereq_('../internal/isObjectLike'), | ||
1192 | support = _dereq_('../support'); | ||
1193 | |||
1194 | /** `Object#toString` result references. */ | ||
1195 | var objectTag = '[object Object]'; | ||
1196 | |||
1197 | /** Used for native method references. */ | ||
1198 | var objectProto = Object.prototype; | ||
1199 | |||
1200 | /** Used to check objects for own properties. */ | ||
1201 | var hasOwnProperty = objectProto.hasOwnProperty; | ||
1202 | |||
1203 | /** | ||
1204 | * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) | ||
1205 | * of values. | ||
1206 | */ | ||
1207 | var objToString = objectProto.toString; | ||
1208 | |||
1209 | /** | ||
1210 | * Checks if `value` is a plain object, that is, an object created by the | ||
1211 | * `Object` constructor or one with a `[[Prototype]]` of `null`. | ||
1212 | * | ||
1213 | * **Note:** This method assumes objects created by the `Object` constructor | ||
1214 | * have no inherited enumerable properties. | ||
1215 | * | ||
1216 | * @static | ||
1217 | * @memberOf _ | ||
1218 | * @category Lang | ||
1219 | * @param {*} value The value to check. | ||
1220 | * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. | ||
1221 | * @example | ||
1222 | * | ||
1223 | * function Foo() { | ||
1224 | * this.a = 1; | ||
1225 | * } | ||
1226 | * | ||
1227 | * _.isPlainObject(new Foo); | ||
1228 | * // => false | ||
1229 | * | ||
1230 | * _.isPlainObject([1, 2, 3]); | ||
1231 | * // => false | ||
1232 | * | ||
1233 | * _.isPlainObject({ 'x': 0, 'y': 0 }); | ||
1234 | * // => true | ||
1235 | * | ||
1236 | * _.isPlainObject(Object.create(null)); | ||
1237 | * // => true | ||
1238 | */ | ||
1239 | function isPlainObject(value) { | ||
1240 | var Ctor; | ||
1241 | |||
1242 | // Exit early for non `Object` objects. | ||
1243 | if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value) && !isArguments(value)) || | ||
1244 | (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { | ||
1245 | return false; | ||
1246 | } | ||
1247 | // IE < 9 iterates inherited properties before own properties. If the first | ||
1248 | // iterated property is an object's own property then there are no inherited | ||
1249 | // enumerable properties. | ||
1250 | var result; | ||
1251 | if (support.ownLast) { | ||
1252 | baseForIn(value, function(subValue, key, object) { | ||
1253 | result = hasOwnProperty.call(object, key); | ||
1254 | return false; | ||
1255 | }); | ||
1256 | return result !== false; | ||
1257 | } | ||
1258 | // In most environments an object's own properties are iterated before | ||
1259 | // its inherited properties. If the last iterated property is an object's | ||
1260 | // own property then there are no inherited enumerable properties. | ||
1261 | baseForIn(value, function(subValue, key) { | ||
1262 | result = key; | ||
1263 | }); | ||
1264 | return result === undefined || hasOwnProperty.call(value, result); | ||
1265 | } | ||
1266 | |||
1267 | module.exports = isPlainObject; | ||
1268 | |||
1269 | },{"../internal/baseForIn":12,"../internal/isHostObject":22,"../internal/isObjectLike":26,"../support":41,"./isArguments":29}],35:[function(_dereq_,module,exports){ | ||
1270 | var isObjectLike = _dereq_('../internal/isObjectLike'); | ||
1271 | |||
1272 | /** `Object#toString` result references. */ | ||
1273 | var stringTag = '[object String]'; | ||
1274 | |||
1275 | /** Used for native method references. */ | ||
1276 | var objectProto = Object.prototype; | ||
1277 | |||
1278 | /** | ||
1279 | * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) | ||
1280 | * of values. | ||
1281 | */ | ||
1282 | var objToString = objectProto.toString; | ||
1283 | |||
1284 | /** | ||
1285 | * Checks if `value` is classified as a `String` primitive or object. | ||
1286 | * | ||
1287 | * @static | ||
1288 | * @memberOf _ | ||
1289 | * @category Lang | ||
1290 | * @param {*} value The value to check. | ||
1291 | * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. | ||
1292 | * @example | ||
1293 | * | ||
1294 | * _.isString('abc'); | ||
1295 | * // => true | ||
1296 | * | ||
1297 | * _.isString(1); | ||
1298 | * // => false | ||
1299 | */ | ||
1300 | function isString(value) { | ||
1301 | return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); | ||
1302 | } | ||
1303 | |||
1304 | module.exports = isString; | ||
1305 | |||
1306 | },{"../internal/isObjectLike":26}],36:[function(_dereq_,module,exports){ | ||
1307 | var isLength = _dereq_('../internal/isLength'), | ||
1308 | isObjectLike = _dereq_('../internal/isObjectLike'); | ||
1309 | |||
1310 | /** `Object#toString` result references. */ | ||
1311 | var argsTag = '[object Arguments]', | ||
1312 | arrayTag = '[object Array]', | ||
1313 | boolTag = '[object Boolean]', | ||
1314 | dateTag = '[object Date]', | ||
1315 | errorTag = '[object Error]', | ||
1316 | funcTag = '[object Function]', | ||
1317 | mapTag = '[object Map]', | ||
1318 | numberTag = '[object Number]', | ||
1319 | objectTag = '[object Object]', | ||
1320 | regexpTag = '[object RegExp]', | ||
1321 | setTag = '[object Set]', | ||
1322 | stringTag = '[object String]', | ||
1323 | weakMapTag = '[object WeakMap]'; | ||
1324 | |||
1325 | var arrayBufferTag = '[object ArrayBuffer]', | ||
1326 | float32Tag = '[object Float32Array]', | ||
1327 | float64Tag = '[object Float64Array]', | ||
1328 | int8Tag = '[object Int8Array]', | ||
1329 | int16Tag = '[object Int16Array]', | ||
1330 | int32Tag = '[object Int32Array]', | ||
1331 | uint8Tag = '[object Uint8Array]', | ||
1332 | uint8ClampedTag = '[object Uint8ClampedArray]', | ||
1333 | uint16Tag = '[object Uint16Array]', | ||
1334 | uint32Tag = '[object Uint32Array]'; | ||
1335 | |||
1336 | /** Used to identify `toStringTag` values of typed arrays. */ | ||
1337 | var typedArrayTags = {}; | ||
1338 | typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = | ||
1339 | typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = | ||
1340 | typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = | ||
1341 | typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = | ||
1342 | typedArrayTags[uint32Tag] = true; | ||
1343 | typedArrayTags[argsTag] = typedArrayTags[arrayTag] = | ||
1344 | typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = | ||
1345 | typedArrayTags[dateTag] = typedArrayTags[errorTag] = | ||
1346 | typedArrayTags[funcTag] = typedArrayTags[mapTag] = | ||
1347 | typedArrayTags[numberTag] = typedArrayTags[objectTag] = | ||
1348 | typedArrayTags[regexpTag] = typedArrayTags[setTag] = | ||
1349 | typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; | ||
1350 | |||
1351 | /** Used for native method references. */ | ||
1352 | var objectProto = Object.prototype; | ||
1353 | |||
1354 | /** | ||
1355 | * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) | ||
1356 | * of values. | ||
1357 | */ | ||
1358 | var objToString = objectProto.toString; | ||
1359 | |||
1360 | /** | ||
1361 | * Checks if `value` is classified as a typed array. | ||
1362 | * | ||
1363 | * @static | ||
1364 | * @memberOf _ | ||
1365 | * @category Lang | ||
1366 | * @param {*} value The value to check. | ||
1367 | * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. | ||
1368 | * @example | ||
1369 | * | ||
1370 | * _.isTypedArray(new Uint8Array); | ||
1371 | * // => true | ||
1372 | * | ||
1373 | * _.isTypedArray([]); | ||
1374 | * // => false | ||
1375 | */ | ||
1376 | function isTypedArray(value) { | ||
1377 | return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; | ||
1378 | } | ||
1379 | |||
1380 | module.exports = isTypedArray; | ||
1381 | |||
1382 | },{"../internal/isLength":25,"../internal/isObjectLike":26}],37:[function(_dereq_,module,exports){ | ||
1383 | var baseCopy = _dereq_('../internal/baseCopy'), | ||
1384 | keysIn = _dereq_('../object/keysIn'); | ||
1385 | |||
1386 | /** | ||
1387 | * Converts `value` to a plain object flattening inherited enumerable | ||
1388 | * properties of `value` to own properties of the plain object. | ||
1389 | * | ||
1390 | * @static | ||
1391 | * @memberOf _ | ||
1392 | * @category Lang | ||
1393 | * @param {*} value The value to convert. | ||
1394 | * @returns {Object} Returns the converted plain object. | ||
1395 | * @example | ||
1396 | * | ||
1397 | * function Foo() { | ||
1398 | * this.b = 2; | ||
1399 | * } | ||
1400 | * | ||
1401 | * Foo.prototype.c = 3; | ||
1402 | * | ||
1403 | * _.assign({ 'a': 1 }, new Foo); | ||
1404 | * // => { 'a': 1, 'b': 2 } | ||
1405 | * | ||
1406 | * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); | ||
1407 | * // => { 'a': 1, 'b': 2, 'c': 3 } | ||
1408 | */ | ||
1409 | function toPlainObject(value) { | ||
1410 | return baseCopy(value, keysIn(value)); | ||
1411 | } | ||
1412 | |||
1413 | module.exports = toPlainObject; | ||
1414 | |||
1415 | },{"../internal/baseCopy":10,"../object/keysIn":39}],38:[function(_dereq_,module,exports){ | ||
1416 | var getNative = _dereq_('../internal/getNative'), | ||
1417 | isArrayLike = _dereq_('../internal/isArrayLike'), | ||
1418 | isObject = _dereq_('../lang/isObject'), | ||
1419 | shimKeys = _dereq_('../internal/shimKeys'), | ||
1420 | support = _dereq_('../support'); | ||
1421 | |||
1422 | /* Native method references for those with the same name as other `lodash` methods. */ | ||
1423 | var nativeKeys = getNative(Object, 'keys'); | ||
1424 | |||
1425 | /** | ||
1426 | * Creates an array of the own enumerable property names of `object`. | ||
1427 | * | ||
1428 | * **Note:** Non-object values are coerced to objects. See the | ||
1429 | * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) | ||
1430 | * for more details. | ||
1431 | * | ||
1432 | * @static | ||
1433 | * @memberOf _ | ||
1434 | * @category Object | ||
1435 | * @param {Object} object The object to query. | ||
1436 | * @returns {Array} Returns the array of property names. | ||
1437 | * @example | ||
1438 | * | ||
1439 | * function Foo() { | ||
1440 | * this.a = 1; | ||
1441 | * this.b = 2; | ||
1442 | * } | ||
1443 | * | ||
1444 | * Foo.prototype.c = 3; | ||
1445 | * | ||
1446 | * _.keys(new Foo); | ||
1447 | * // => ['a', 'b'] (iteration order is not guaranteed) | ||
1448 | * | ||
1449 | * _.keys('hi'); | ||
1450 | * // => ['0', '1'] | ||
1451 | */ | ||
1452 | var keys = !nativeKeys ? shimKeys : function(object) { | ||
1453 | var Ctor = object == null ? undefined : object.constructor; | ||
1454 | if ((typeof Ctor == 'function' && Ctor.prototype === object) || | ||
1455 | (typeof object == 'function' ? support.enumPrototypes : isArrayLike(object))) { | ||
1456 | return shimKeys(object); | ||
1457 | } | ||
1458 | return isObject(object) ? nativeKeys(object) : []; | ||
1459 | }; | ||
1460 | |||
1461 | module.exports = keys; | ||
1462 | |||
1463 | },{"../internal/getNative":20,"../internal/isArrayLike":21,"../internal/shimKeys":27,"../lang/isObject":33,"../support":41}],39:[function(_dereq_,module,exports){ | ||
1464 | var arrayEach = _dereq_('../internal/arrayEach'), | ||
1465 | isArguments = _dereq_('../lang/isArguments'), | ||
1466 | isArray = _dereq_('../lang/isArray'), | ||
1467 | isFunction = _dereq_('../lang/isFunction'), | ||
1468 | isIndex = _dereq_('../internal/isIndex'), | ||
1469 | isLength = _dereq_('../internal/isLength'), | ||
1470 | isObject = _dereq_('../lang/isObject'), | ||
1471 | isString = _dereq_('../lang/isString'), | ||
1472 | support = _dereq_('../support'); | ||
1473 | |||
1474 | /** `Object#toString` result references. */ | ||
1475 | var arrayTag = '[object Array]', | ||
1476 | boolTag = '[object Boolean]', | ||
1477 | dateTag = '[object Date]', | ||
1478 | errorTag = '[object Error]', | ||
1479 | funcTag = '[object Function]', | ||
1480 | numberTag = '[object Number]', | ||
1481 | objectTag = '[object Object]', | ||
1482 | regexpTag = '[object RegExp]', | ||
1483 | stringTag = '[object String]'; | ||
1484 | |||
1485 | /** Used to fix the JScript `[[DontEnum]]` bug. */ | ||
1486 | var shadowProps = [ | ||
1487 | 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', | ||
1488 | 'toLocaleString', 'toString', 'valueOf' | ||
1489 | ]; | ||
1490 | |||
1491 | /** Used for native method references. */ | ||
1492 | var errorProto = Error.prototype, | ||
1493 | objectProto = Object.prototype, | ||
1494 | stringProto = String.prototype; | ||
1495 | |||
1496 | /** Used to check objects for own properties. */ | ||
1497 | var hasOwnProperty = objectProto.hasOwnProperty; | ||
1498 | |||
1499 | /** | ||
1500 | * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) | ||
1501 | * of values. | ||
1502 | */ | ||
1503 | var objToString = objectProto.toString; | ||
1504 | |||
1505 | /** Used to avoid iterating over non-enumerable properties in IE < 9. */ | ||
1506 | var nonEnumProps = {}; | ||
1507 | nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true }; | ||
1508 | nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true }; | ||
1509 | nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true }; | ||
1510 | nonEnumProps[objectTag] = { 'constructor': true }; | ||
1511 | |||
1512 | arrayEach(shadowProps, function(key) { | ||
1513 | for (var tag in nonEnumProps) { | ||
1514 | if (hasOwnProperty.call(nonEnumProps, tag)) { | ||
1515 | var props = nonEnumProps[tag]; | ||
1516 | props[key] = hasOwnProperty.call(props, key); | ||
1517 | } | ||
1518 | } | ||
1519 | }); | ||
1520 | |||
1521 | /** | ||
1522 | * Creates an array of the own and inherited enumerable property names of `object`. | ||
1523 | * | ||
1524 | * **Note:** Non-object values are coerced to objects. | ||
1525 | * | ||
1526 | * @static | ||
1527 | * @memberOf _ | ||
1528 | * @category Object | ||
1529 | * @param {Object} object The object to query. | ||
1530 | * @returns {Array} Returns the array of property names. | ||
1531 | * @example | ||
1532 | * | ||
1533 | * function Foo() { | ||
1534 | * this.a = 1; | ||
1535 | * this.b = 2; | ||
1536 | * } | ||
1537 | * | ||
1538 | * Foo.prototype.c = 3; | ||
1539 | * | ||
1540 | * _.keysIn(new Foo); | ||
1541 | * // => ['a', 'b', 'c'] (iteration order is not guaranteed) | ||
1542 | */ | ||
1543 | function keysIn(object) { | ||
1544 | if (object == null) { | ||
1545 | return []; | ||
1546 | } | ||
1547 | if (!isObject(object)) { | ||
1548 | object = Object(object); | ||
1549 | } | ||
1550 | var length = object.length; | ||
1551 | |||
1552 | length = (length && isLength(length) && | ||
1553 | (isArray(object) || isArguments(object) || isString(object)) && length) || 0; | ||
1554 | |||
1555 | var Ctor = object.constructor, | ||
1556 | index = -1, | ||
1557 | proto = (isFunction(Ctor) && Ctor.prototype) || objectProto, | ||
1558 | isProto = proto === object, | ||
1559 | result = Array(length), | ||
1560 | skipIndexes = length > 0, | ||
1561 | skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error), | ||
1562 | skipProto = support.enumPrototypes && isFunction(object); | ||
1563 | |||
1564 | while (++index < length) { | ||
1565 | result[index] = (index + ''); | ||
1566 | } | ||
1567 | // lodash skips the `constructor` property when it infers it's iterating | ||
1568 | // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]` | ||
1569 | // attribute of an existing property and the `constructor` property of a | ||
1570 | // prototype defaults to non-enumerable. | ||
1571 | for (var key in object) { | ||
1572 | if (!(skipProto && key == 'prototype') && | ||
1573 | !(skipErrorProps && (key == 'message' || key == 'name')) && | ||
1574 | !(skipIndexes && isIndex(key, length)) && | ||
1575 | !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { | ||
1576 | result.push(key); | ||
1577 | } | ||
1578 | } | ||
1579 | if (support.nonEnumShadows && object !== objectProto) { | ||
1580 | var tag = object === stringProto ? stringTag : (object === errorProto ? errorTag : objToString.call(object)), | ||
1581 | nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag]; | ||
1582 | |||
1583 | if (tag == objectTag) { | ||
1584 | proto = objectProto; | ||
1585 | } | ||
1586 | length = shadowProps.length; | ||
1587 | while (length--) { | ||
1588 | key = shadowProps[length]; | ||
1589 | var nonEnum = nonEnums[key]; | ||
1590 | if (!(isProto && nonEnum) && | ||
1591 | (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) { | ||
1592 | result.push(key); | ||
1593 | } | ||
1594 | } | ||
1595 | } | ||
1596 | return result; | ||
1597 | } | ||
1598 | |||
1599 | module.exports = keysIn; | ||
1600 | |||
1601 | },{"../internal/arrayEach":9,"../internal/isIndex":23,"../internal/isLength":25,"../lang/isArguments":29,"../lang/isArray":30,"../lang/isFunction":31,"../lang/isObject":33,"../lang/isString":35,"../support":41}],40:[function(_dereq_,module,exports){ | ||
1602 | var baseMerge = _dereq_('../internal/baseMerge'), | ||
1603 | createAssigner = _dereq_('../internal/createAssigner'); | ||
1604 | |||
1605 | /** | ||
1606 | * Recursively merges own enumerable properties of the source object(s), that | ||
1607 | * don't resolve to `undefined` into the destination object. Subsequent sources | ||
1608 | * overwrite property assignments of previous sources. If `customizer` is | ||
1609 | * provided it's invoked to produce the merged values of the destination and | ||
1610 | * source properties. If `customizer` returns `undefined` merging is handled | ||
1611 | * by the method instead. The `customizer` is bound to `thisArg` and invoked | ||
1612 | * with five arguments: (objectValue, sourceValue, key, object, source). | ||
1613 | * | ||
1614 | * @static | ||
1615 | * @memberOf _ | ||
1616 | * @category Object | ||
1617 | * @param {Object} object The destination object. | ||
1618 | * @param {...Object} [sources] The source objects. | ||
1619 | * @param {Function} [customizer] The function to customize assigned values. | ||
1620 | * @param {*} [thisArg] The `this` binding of `customizer`. | ||
1621 | * @returns {Object} Returns `object`. | ||
1622 | * @example | ||
1623 | * | ||
1624 | * var users = { | ||
1625 | * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] | ||
1626 | * }; | ||
1627 | * | ||
1628 | * var ages = { | ||
1629 | * 'data': [{ 'age': 36 }, { 'age': 40 }] | ||
1630 | * }; | ||
1631 | * | ||
1632 | * _.merge(users, ages); | ||
1633 | * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } | ||
1634 | * | ||
1635 | * // using a customizer callback | ||
1636 | * var object = { | ||
1637 | * 'fruits': ['apple'], | ||
1638 | * 'vegetables': ['beet'] | ||
1639 | * }; | ||
1640 | * | ||
1641 | * var other = { | ||
1642 | * 'fruits': ['banana'], | ||
1643 | * 'vegetables': ['carrot'] | ||
1644 | * }; | ||
1645 | * | ||
1646 | * _.merge(object, other, function(a, b) { | ||
1647 | * if (_.isArray(a)) { | ||
1648 | * return a.concat(b); | ||
1649 | * } | ||
1650 | * }); | ||
1651 | * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } | ||
1652 | */ | ||
1653 | var merge = createAssigner(baseMerge); | ||
1654 | |||
1655 | module.exports = merge; | ||
1656 | |||
1657 | },{"../internal/baseMerge":13,"../internal/createAssigner":17}],41:[function(_dereq_,module,exports){ | ||
1658 | /** Used for native method references. */ | ||
1659 | var arrayProto = Array.prototype, | ||
1660 | errorProto = Error.prototype, | ||
1661 | objectProto = Object.prototype; | ||
1662 | |||
1663 | /** Native method references. */ | ||
1664 | var propertyIsEnumerable = objectProto.propertyIsEnumerable, | ||
1665 | splice = arrayProto.splice; | ||
1666 | |||
1667 | /** | ||
1668 | * An object environment feature flags. | ||
1669 | * | ||
1670 | * @static | ||
1671 | * @memberOf _ | ||
1672 | * @type Object | ||
1673 | */ | ||
1674 | var support = {}; | ||
1675 | |||
1676 | (function(x) { | ||
1677 | var Ctor = function() { this.x = x; }, | ||
1678 | object = { '0': x, 'length': x }, | ||
1679 | props = []; | ||
1680 | |||
1681 | Ctor.prototype = { 'valueOf': x, 'y': x }; | ||
1682 | for (var key in new Ctor) { props.push(key); } | ||
1683 | |||
1684 | /** | ||
1685 | * Detect if `name` or `message` properties of `Error.prototype` are | ||
1686 | * enumerable by default (IE < 9, Safari < 5.1). | ||
1687 | * | ||
1688 | * @memberOf _.support | ||
1689 | * @type boolean | ||
1690 | */ | ||
1691 | support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || | ||
1692 | propertyIsEnumerable.call(errorProto, 'name'); | ||
1693 | |||
1694 | /** | ||
1695 | * Detect if `prototype` properties are enumerable by default. | ||
1696 | * | ||
1697 | * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 | ||
1698 | * (if the prototype or a property on the prototype has been set) | ||
1699 | * incorrectly set the `[[Enumerable]]` value of a function's `prototype` | ||
1700 | * property to `true`. | ||
1701 | * | ||
1702 | * @memberOf _.support | ||
1703 | * @type boolean | ||
1704 | */ | ||
1705 | support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype'); | ||
1706 | |||
1707 | /** | ||
1708 | * Detect if properties shadowing those on `Object.prototype` are non-enumerable. | ||
1709 | * | ||
1710 | * In IE < 9 an object's own properties, shadowing non-enumerable ones, | ||
1711 | * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug). | ||
1712 | * | ||
1713 | * @memberOf _.support | ||
1714 | * @type boolean | ||
1715 | */ | ||
1716 | support.nonEnumShadows = !/valueOf/.test(props); | ||
1717 | |||
1718 | /** | ||
1719 | * Detect if own properties are iterated after inherited properties (IE < 9). | ||
1720 | * | ||
1721 | * @memberOf _.support | ||
1722 | * @type boolean | ||
1723 | */ | ||
1724 | support.ownLast = props[0] != 'x'; | ||
1725 | |||
1726 | /** | ||
1727 | * Detect if `Array#shift` and `Array#splice` augment array-like objects | ||
1728 | * correctly. | ||
1729 | * | ||
1730 | * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array | ||
1731 | * `shift()` and `splice()` functions that fail to remove the last element, | ||
1732 | * `value[0]`, of array-like objects even though the "length" property is | ||
1733 | * set to `0`. The `shift()` method is buggy in compatibility modes of IE 8, | ||
1734 | * while `splice()` is buggy regardless of mode in IE < 9. | ||
1735 | * | ||
1736 | * @memberOf _.support | ||
1737 | * @type boolean | ||
1738 | */ | ||
1739 | support.spliceObjects = (splice.call(object, 0, 1), !object[0]); | ||
1740 | |||
1741 | /** | ||
1742 | * Detect lack of support for accessing string characters by index. | ||
1743 | * | ||
1744 | * IE < 8 can't access characters by index. IE 8 can only access characters | ||
1745 | * by index on string literals, not string objects. | ||
1746 | * | ||
1747 | * @memberOf _.support | ||
1748 | * @type boolean | ||
1749 | */ | ||
1750 | support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx'; | ||
1751 | }(1, 0)); | ||
1752 | |||
1753 | module.exports = support; | ||
1754 | |||
1755 | },{}],42:[function(_dereq_,module,exports){ | ||
1756 | /** | ||
1757 | * This method returns the first argument provided to it. | ||
1758 | * | ||
1759 | * @static | ||
1760 | * @memberOf _ | ||
1761 | * @category Utility | ||
1762 | * @param {*} value Any value. | ||
1763 | * @returns {*} Returns `value`. | ||
1764 | * @example | ||
1765 | * | ||
1766 | * var object = { 'user': 'fred' }; | ||
1767 | * | ||
1768 | * _.identity(object) === object; | ||
1769 | * // => true | ||
1770 | */ | ||
1771 | function identity(value) { | ||
1772 | return value; | ||
1773 | } | ||
1774 | |||
1775 | module.exports = identity; | ||
1776 | |||
1777 | },{}],43:[function(_dereq_,module,exports){ | ||
1778 | 'use strict'; | ||
1779 | |||
1780 | var keys = _dereq_('object-keys'); | ||
1781 | |||
1782 | module.exports = function hasSymbols() { | ||
1783 | if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } | ||
1784 | if (typeof Symbol.iterator === 'symbol') { return true; } | ||
1785 | |||
1786 | var obj = {}; | ||
1787 | var sym = Symbol('test'); | ||
1788 | if (typeof sym === 'string') { return false; } | ||
1789 | |||
1790 | // temp disabled per https://github.com/ljharb/object.assign/issues/17 | ||
1791 | // if (sym instanceof Symbol) { return false; } | ||
1792 | // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 | ||
1793 | // if (!(Object(sym) instanceof Symbol)) { return false; } | ||
1794 | |||
1795 | var symVal = 42; | ||
1796 | obj[sym] = symVal; | ||
1797 | for (sym in obj) { return false; } | ||
1798 | if (keys(obj).length !== 0) { return false; } | ||
1799 | if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } | ||
1800 | |||
1801 | if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } | ||
1802 | |||
1803 | var syms = Object.getOwnPropertySymbols(obj); | ||
1804 | if (syms.length !== 1 || syms[0] !== sym) { return false; } | ||
1805 | |||
1806 | if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } | ||
1807 | |||
1808 | if (typeof Object.getOwnPropertyDescriptor === 'function') { | ||
1809 | var descriptor = Object.getOwnPropertyDescriptor(obj, sym); | ||
1810 | if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } | ||
1811 | } | ||
1812 | |||
1813 | return true; | ||
1814 | }; | ||
1815 | |||
1816 | },{"object-keys":50}],44:[function(_dereq_,module,exports){ | ||
1817 | 'use strict'; | ||
1818 | |||
1819 | // modified from https://github.com/es-shims/es6-shim | ||
1820 | var keys = _dereq_('object-keys'); | ||
1821 | var bind = _dereq_('function-bind'); | ||
1822 | var canBeObject = function (obj) { | ||
1823 | return typeof obj !== 'undefined' && obj !== null; | ||
1824 | }; | ||
1825 | var hasSymbols = _dereq_('./hasSymbols')(); | ||
1826 | var toObject = Object; | ||
1827 | var push = bind.call(Function.call, Array.prototype.push); | ||
1828 | var propIsEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable); | ||
1829 | |||
1830 | module.exports = function assign(target, source1) { | ||
1831 | if (!canBeObject(target)) { throw new TypeError('target must be an object'); } | ||
1832 | var objTarget = toObject(target); | ||
1833 | var s, source, i, props, syms, value, key; | ||
1834 | for (s = 1; s < arguments.length; ++s) { | ||
1835 | source = toObject(arguments[s]); | ||
1836 | props = keys(source); | ||
1837 | if (hasSymbols && Object.getOwnPropertySymbols) { | ||
1838 | syms = Object.getOwnPropertySymbols(source); | ||
1839 | for (i = 0; i < syms.length; ++i) { | ||
1840 | key = syms[i]; | ||
1841 | if (propIsEnumerable(source, key)) { | ||
1842 | push(props, key); | ||
1843 | } | ||
1844 | } | ||
1845 | } | ||
1846 | for (i = 0; i < props.length; ++i) { | ||
1847 | key = props[i]; | ||
1848 | value = source[key]; | ||
1849 | if (propIsEnumerable(source, key)) { | ||
1850 | objTarget[key] = value; | ||
1851 | } | ||
1852 | } | ||
1853 | } | ||
1854 | return objTarget; | ||
1855 | }; | ||
1856 | |||
1857 | },{"./hasSymbols":43,"function-bind":49,"object-keys":50}],45:[function(_dereq_,module,exports){ | ||
1858 | 'use strict'; | ||
1859 | |||
1860 | var defineProperties = _dereq_('define-properties'); | ||
1861 | |||
1862 | var implementation = _dereq_('./implementation'); | ||
1863 | var getPolyfill = _dereq_('./polyfill'); | ||
1864 | var shim = _dereq_('./shim'); | ||
1865 | |||
1866 | defineProperties(implementation, { | ||
1867 | implementation: implementation, | ||
1868 | getPolyfill: getPolyfill, | ||
1869 | shim: shim | ||
1870 | }); | ||
1871 | |||
1872 | module.exports = implementation; | ||
1873 | |||
1874 | },{"./implementation":44,"./polyfill":52,"./shim":53,"define-properties":46}],46:[function(_dereq_,module,exports){ | ||
1875 | 'use strict'; | ||
1876 | |||
1877 | var keys = _dereq_('object-keys'); | ||
1878 | var foreach = _dereq_('foreach'); | ||
1879 | var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol'; | ||
1880 | |||
1881 | var toStr = Object.prototype.toString; | ||
1882 | |||
1883 | var isFunction = function (fn) { | ||
1884 | return typeof fn === 'function' && toStr.call(fn) === '[object Function]'; | ||
1885 | }; | ||
1886 | |||
1887 | var arePropertyDescriptorsSupported = function () { | ||
1888 | var obj = {}; | ||
1889 | try { | ||
1890 | Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); | ||
1891 | /* eslint-disable no-unused-vars, no-restricted-syntax */ | ||
1892 | for (var _ in obj) { return false; } | ||
1893 | /* eslint-enable no-unused-vars, no-restricted-syntax */ | ||
1894 | return obj.x === obj; | ||
1895 | } catch (e) { /* this is IE 8. */ | ||
1896 | return false; | ||
1897 | } | ||
1898 | }; | ||
1899 | var supportsDescriptors = Object.defineProperty && arePropertyDescriptorsSupported(); | ||
1900 | |||
1901 | var defineProperty = function (object, name, value, predicate) { | ||
1902 | if (name in object && (!isFunction(predicate) || !predicate())) { | ||
1903 | return; | ||
1904 | } | ||
1905 | if (supportsDescriptors) { | ||
1906 | Object.defineProperty(object, name, { | ||
1907 | configurable: true, | ||
1908 | enumerable: false, | ||
1909 | value: value, | ||
1910 | writable: true | ||
1911 | }); | ||
1912 | } else { | ||
1913 | object[name] = value; | ||
1914 | } | ||
1915 | }; | ||
1916 | |||
1917 | var defineProperties = function (object, map) { | ||
1918 | var predicates = arguments.length > 2 ? arguments[2] : {}; | ||
1919 | var props = keys(map); | ||
1920 | if (hasSymbols) { | ||
1921 | props = props.concat(Object.getOwnPropertySymbols(map)); | ||
1922 | } | ||
1923 | foreach(props, function (name) { | ||
1924 | defineProperty(object, name, map[name], predicates[name]); | ||
1925 | }); | ||
1926 | }; | ||
1927 | |||
1928 | defineProperties.supportsDescriptors = !!supportsDescriptors; | ||
1929 | |||
1930 | module.exports = defineProperties; | ||
1931 | |||
1932 | },{"foreach":47,"object-keys":50}],47:[function(_dereq_,module,exports){ | ||
1933 | |||
1934 | var hasOwn = Object.prototype.hasOwnProperty; | ||
1935 | var toString = Object.prototype.toString; | ||
1936 | |||
1937 | module.exports = function forEach (obj, fn, ctx) { | ||
1938 | if (toString.call(fn) !== '[object Function]') { | ||
1939 | throw new TypeError('iterator must be a function'); | ||
1940 | } | ||
1941 | var l = obj.length; | ||
1942 | if (l === +l) { | ||
1943 | for (var i = 0; i < l; i++) { | ||
1944 | fn.call(ctx, obj[i], i, obj); | ||
1945 | } | ||
1946 | } else { | ||
1947 | for (var k in obj) { | ||
1948 | if (hasOwn.call(obj, k)) { | ||
1949 | fn.call(ctx, obj[k], k, obj); | ||
1950 | } | ||
1951 | } | ||
1952 | } | ||
1953 | }; | ||
1954 | |||
1955 | |||
1956 | },{}],48:[function(_dereq_,module,exports){ | ||
1957 | var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; | ||
1958 | var slice = Array.prototype.slice; | ||
1959 | var toStr = Object.prototype.toString; | ||
1960 | var funcType = '[object Function]'; | ||
1961 | |||
1962 | module.exports = function bind(that) { | ||
1963 | var target = this; | ||
1964 | if (typeof target !== 'function' || toStr.call(target) !== funcType) { | ||
1965 | throw new TypeError(ERROR_MESSAGE + target); | ||
1966 | } | ||
1967 | var args = slice.call(arguments, 1); | ||
1968 | |||
1969 | var bound; | ||
1970 | var binder = function () { | ||
1971 | if (this instanceof bound) { | ||
1972 | var result = target.apply( | ||
1973 | this, | ||
1974 | args.concat(slice.call(arguments)) | ||
1975 | ); | ||
1976 | if (Object(result) === result) { | ||
1977 | return result; | ||
1978 | } | ||
1979 | return this; | ||
1980 | } else { | ||
1981 | return target.apply( | ||
1982 | that, | ||
1983 | args.concat(slice.call(arguments)) | ||
1984 | ); | ||
1985 | } | ||
1986 | }; | ||
1987 | |||
1988 | var boundLength = Math.max(0, target.length - args.length); | ||
1989 | var boundArgs = []; | ||
1990 | for (var i = 0; i < boundLength; i++) { | ||
1991 | boundArgs.push('$' + i); | ||
1992 | } | ||
1993 | |||
1994 | bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); | ||
1995 | |||
1996 | if (target.prototype) { | ||
1997 | var Empty = function Empty() {}; | ||
1998 | Empty.prototype = target.prototype; | ||
1999 | bound.prototype = new Empty(); | ||
2000 | Empty.prototype = null; | ||
2001 | } | ||
2002 | |||
2003 | return bound; | ||
2004 | }; | ||
2005 | |||
2006 | },{}],49:[function(_dereq_,module,exports){ | ||
2007 | var implementation = _dereq_('./implementation'); | ||
2008 | |||
2009 | module.exports = Function.prototype.bind || implementation; | ||
2010 | |||
2011 | },{"./implementation":48}],50:[function(_dereq_,module,exports){ | ||
2012 | 'use strict'; | ||
2013 | |||
2014 | // modified from https://github.com/es-shims/es5-shim | ||
2015 | var has = Object.prototype.hasOwnProperty; | ||
2016 | var toStr = Object.prototype.toString; | ||
2017 | var slice = Array.prototype.slice; | ||
2018 | var isArgs = _dereq_('./isArguments'); | ||
2019 | var hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'); | ||
2020 | var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'); | ||
2021 | var dontEnums = [ | ||
2022 | 'toString', | ||
2023 | 'toLocaleString', | ||
2024 | 'valueOf', | ||
2025 | 'hasOwnProperty', | ||
2026 | 'isPrototypeOf', | ||
2027 | 'propertyIsEnumerable', | ||
2028 | 'constructor' | ||
2029 | ]; | ||
2030 | var equalsConstructorPrototype = function (o) { | ||
2031 | var ctor = o.constructor; | ||
2032 | return ctor && ctor.prototype === o; | ||
2033 | }; | ||
2034 | var blacklistedKeys = { | ||
2035 | $console: true, | ||
2036 | $frame: true, | ||
2037 | $frameElement: true, | ||
2038 | $frames: true, | ||
2039 | $parent: true, | ||
2040 | $self: true, | ||
2041 | $webkitIndexedDB: true, | ||
2042 | $webkitStorageInfo: true, | ||
2043 | $window: true | ||
2044 | }; | ||
2045 | var hasAutomationEqualityBug = (function () { | ||
2046 | /* global window */ | ||
2047 | if (typeof window === 'undefined') { return false; } | ||
2048 | for (var k in window) { | ||
2049 | try { | ||
2050 | if (!blacklistedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { | ||
2051 | try { | ||
2052 | equalsConstructorPrototype(window[k]); | ||
2053 | } catch (e) { | ||
2054 | return true; | ||
2055 | } | ||
2056 | } | ||
2057 | } catch (e) { | ||
2058 | return true; | ||
2059 | } | ||
2060 | } | ||
2061 | return false; | ||
2062 | }()); | ||
2063 | var equalsConstructorPrototypeIfNotBuggy = function (o) { | ||
2064 | /* global window */ | ||
2065 | if (typeof window === 'undefined' || !hasAutomationEqualityBug) { | ||
2066 | return equalsConstructorPrototype(o); | ||
2067 | } | ||
2068 | try { | ||
2069 | return equalsConstructorPrototype(o); | ||
2070 | } catch (e) { | ||
2071 | return false; | ||
2072 | } | ||
2073 | }; | ||
2074 | |||
2075 | var keysShim = function keys(object) { | ||
2076 | var isObject = object !== null && typeof object === 'object'; | ||
2077 | var isFunction = toStr.call(object) === '[object Function]'; | ||
2078 | var isArguments = isArgs(object); | ||
2079 | var isString = isObject && toStr.call(object) === '[object String]'; | ||
2080 | var theKeys = []; | ||
2081 | |||
2082 | if (!isObject && !isFunction && !isArguments) { | ||
2083 | throw new TypeError('Object.keys called on a non-object'); | ||
2084 | } | ||
2085 | |||
2086 | var skipProto = hasProtoEnumBug && isFunction; | ||
2087 | if (isString && object.length > 0 && !has.call(object, 0)) { | ||
2088 | for (var i = 0; i < object.length; ++i) { | ||
2089 | theKeys.push(String(i)); | ||
2090 | } | ||
2091 | } | ||
2092 | |||
2093 | if (isArguments && object.length > 0) { | ||
2094 | for (var j = 0; j < object.length; ++j) { | ||
2095 | theKeys.push(String(j)); | ||
2096 | } | ||
2097 | } else { | ||
2098 | for (var name in object) { | ||
2099 | if (!(skipProto && name === 'prototype') && has.call(object, name)) { | ||
2100 | theKeys.push(String(name)); | ||
2101 | } | ||
2102 | } | ||
2103 | } | ||
2104 | |||
2105 | if (hasDontEnumBug) { | ||
2106 | var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); | ||
2107 | |||
2108 | for (var k = 0; k < dontEnums.length; ++k) { | ||
2109 | if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { | ||
2110 | theKeys.push(dontEnums[k]); | ||
2111 | } | ||
2112 | } | ||
2113 | } | ||
2114 | return theKeys; | ||
2115 | }; | ||
2116 | |||
2117 | keysShim.shim = function shimObjectKeys() { | ||
2118 | if (Object.keys) { | ||
2119 | var keysWorksWithArguments = (function () { | ||
2120 | // Safari 5.0 bug | ||
2121 | return (Object.keys(arguments) || '').length === 2; | ||
2122 | }(1, 2)); | ||
2123 | if (!keysWorksWithArguments) { | ||
2124 | var originalKeys = Object.keys; | ||
2125 | Object.keys = function keys(object) { | ||
2126 | if (isArgs(object)) { | ||
2127 | return originalKeys(slice.call(object)); | ||
2128 | } else { | ||
2129 | return originalKeys(object); | ||
2130 | } | ||
2131 | }; | ||
2132 | } | ||
2133 | } else { | ||
2134 | Object.keys = keysShim; | ||
2135 | } | ||
2136 | return Object.keys || keysShim; | ||
2137 | }; | ||
2138 | |||
2139 | module.exports = keysShim; | ||
2140 | |||
2141 | },{"./isArguments":51}],51:[function(_dereq_,module,exports){ | ||
2142 | 'use strict'; | ||
2143 | |||
2144 | var toStr = Object.prototype.toString; | ||
2145 | |||
2146 | module.exports = function isArguments(value) { | ||
2147 | var str = toStr.call(value); | ||
2148 | var isArgs = str === '[object Arguments]'; | ||
2149 | if (!isArgs) { | ||
2150 | isArgs = str !== '[object Array]' && | ||
2151 | value !== null && | ||
2152 | typeof value === 'object' && | ||
2153 | typeof value.length === 'number' && | ||
2154 | value.length >= 0 && | ||
2155 | toStr.call(value.callee) === '[object Function]'; | ||
2156 | } | ||
2157 | return isArgs; | ||
2158 | }; | ||
2159 | |||
2160 | },{}],52:[function(_dereq_,module,exports){ | ||
2161 | 'use strict'; | ||
2162 | |||
2163 | var implementation = _dereq_('./implementation'); | ||
2164 | |||
2165 | var lacksProperEnumerationOrder = function () { | ||
2166 | if (!Object.assign) { | ||
2167 | return false; | ||
2168 | } | ||
2169 | // v8, specifically in node 4.x, has a bug with incorrect property enumeration order | ||
2170 | // note: this does not detect the bug unless there's 20 characters | ||
2171 | var str = 'abcdefghijklmnopqrst'; | ||
2172 | var letters = str.split(''); | ||
2173 | var map = {}; | ||
2174 | for (var i = 0; i < letters.length; ++i) { | ||
2175 | map[letters[i]] = letters[i]; | ||
2176 | } | ||
2177 | var obj = Object.assign({}, map); | ||
2178 | var actual = ''; | ||
2179 | for (var k in obj) { | ||
2180 | actual += k; | ||
2181 | } | ||
2182 | return str !== actual; | ||
2183 | }; | ||
2184 | |||
2185 | var assignHasPendingExceptions = function () { | ||
2186 | if (!Object.assign || !Object.preventExtensions) { | ||
2187 | return false; | ||
2188 | } | ||
2189 | // Firefox 37 still has "pending exception" logic in its Object.assign implementation, | ||
2190 | // which is 72% slower than our shim, and Firefox 40's native implementation. | ||
2191 | var thrower = Object.preventExtensions({ 1: 2 }); | ||
2192 | try { | ||
2193 | Object.assign(thrower, 'xy'); | ||
2194 | } catch (e) { | ||
2195 | return thrower[1] === 'y'; | ||
2196 | } | ||
2197 | }; | ||
2198 | |||
2199 | module.exports = function getPolyfill() { | ||
2200 | if (!Object.assign) { | ||
2201 | return implementation; | ||
2202 | } | ||
2203 | if (lacksProperEnumerationOrder()) { | ||
2204 | return implementation; | ||
2205 | } | ||
2206 | if (assignHasPendingExceptions()) { | ||
2207 | return implementation; | ||
2208 | } | ||
2209 | return Object.assign; | ||
2210 | }; | ||
2211 | |||
2212 | },{"./implementation":44}],53:[function(_dereq_,module,exports){ | ||
2213 | 'use strict'; | ||
2214 | |||
2215 | var define = _dereq_('define-properties'); | ||
2216 | var getPolyfill = _dereq_('./polyfill'); | ||
2217 | |||
2218 | module.exports = function shimAssign() { | ||
2219 | var polyfill = getPolyfill(); | ||
2220 | define( | ||
2221 | Object, | ||
2222 | { assign: polyfill }, | ||
2223 | { assign: function () { return Object.assign !== polyfill; } } | ||
2224 | ); | ||
2225 | return polyfill; | ||
2226 | }; | ||
2227 | |||
2228 | },{"./polyfill":52,"define-properties":46}],54:[function(_dereq_,module,exports){ | ||
2229 | module.exports = SafeParseTuple | ||
2230 | |||
2231 | function SafeParseTuple(obj, reviver) { | ||
2232 | var json | ||
2233 | var error = null | ||
2234 | |||
2235 | try { | ||
2236 | json = JSON.parse(obj, reviver) | ||
2237 | } catch (err) { | ||
2238 | error = err | ||
2239 | } | ||
2240 | |||
2241 | return [error, json] | ||
2242 | } | ||
2243 | |||
2244 | },{}],55:[function(_dereq_,module,exports){ | ||
2245 | function clean (s) { | ||
2246 | return s.replace(/\n\r?\s*/g, '') | ||
2247 | } | ||
2248 | |||
2249 | |||
2250 | module.exports = function tsml (sa) { | ||
2251 | var s = '' | ||
2252 | , i = 0 | ||
2253 | |||
2254 | for (; i < arguments.length; i++) | ||
2255 | s += clean(sa[i]) + (arguments[i + 1] || '') | ||
2256 | |||
2257 | return s | ||
2258 | } | ||
2259 | },{}],56:[function(_dereq_,module,exports){ | ||
2260 | "use strict"; | ||
2261 | var window = _dereq_("global/window") | ||
2262 | var once = _dereq_("once") | ||
2263 | var isFunction = _dereq_("is-function") | ||
2264 | var parseHeaders = _dereq_("parse-headers") | ||
2265 | var xtend = _dereq_("xtend") | ||
2266 | |||
2267 | module.exports = createXHR | ||
2268 | createXHR.XMLHttpRequest = window.XMLHttpRequest || noop | ||
2269 | createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest | ||
2270 | |||
2271 | forEachArray(["get", "put", "post", "patch", "head", "delete"], function(method) { | ||
2272 | createXHR[method === "delete" ? "del" : method] = function(uri, options, callback) { | ||
2273 | options = initParams(uri, options, callback) | ||
2274 | options.method = method.toUpperCase() | ||
2275 | return _createXHR(options) | ||
2276 | } | ||
2277 | }) | ||
2278 | |||
2279 | function forEachArray(array, iterator) { | ||
2280 | for (var i = 0; i < array.length; i++) { | ||
2281 | iterator(array[i]) | ||
2282 | } | ||
2283 | } | ||
2284 | |||
2285 | function isEmpty(obj){ | ||
2286 | for(var i in obj){ | ||
2287 | if(obj.hasOwnProperty(i)) return false | ||
2288 | } | ||
2289 | return true | ||
2290 | } | ||
2291 | |||
2292 | function initParams(uri, options, callback) { | ||
2293 | var params = uri | ||
2294 | |||
2295 | if (isFunction(options)) { | ||
2296 | callback = options | ||
2297 | if (typeof uri === "string") { | ||
2298 | params = {uri:uri} | ||
2299 | } | ||
2300 | } else { | ||
2301 | params = xtend(options, {uri: uri}) | ||
2302 | } | ||
2303 | |||
2304 | params.callback = callback | ||
2305 | return params | ||
2306 | } | ||
2307 | |||
2308 | function createXHR(uri, options, callback) { | ||
2309 | options = initParams(uri, options, callback) | ||
2310 | return _createXHR(options) | ||
2311 | } | ||
2312 | |||
2313 | function _createXHR(options) { | ||
2314 | var callback = options.callback | ||
2315 | if(typeof callback === "undefined"){ | ||
2316 | throw new Error("callback argument missing") | ||
2317 | } | ||
2318 | callback = once(callback) | ||
2319 | |||
2320 | function readystatechange() { | ||
2321 | if (xhr.readyState === 4) { | ||
2322 | loadFunc() | ||
2323 | } | ||
2324 | } | ||
2325 | |||
2326 | function getBody() { | ||
2327 | // Chrome with requestType=blob throws errors arround when even testing access to responseText | ||
2328 | var body = undefined | ||
2329 | |||
2330 | if (xhr.response) { | ||
2331 | body = xhr.response | ||
2332 | } else if (xhr.responseType === "text" || !xhr.responseType) { | ||
2333 | body = xhr.responseText || xhr.responseXML | ||
2334 | } | ||
2335 | |||
2336 | if (isJson) { | ||
2337 | try { | ||
2338 | body = JSON.parse(body) | ||
2339 | } catch (e) {} | ||
2340 | } | ||
2341 | |||
2342 | return body | ||
2343 | } | ||
2344 | |||
2345 | var failureResponse = { | ||
2346 | body: undefined, | ||
2347 | headers: {}, | ||
2348 | statusCode: 0, | ||
2349 | method: method, | ||
2350 | url: uri, | ||
2351 | rawRequest: xhr | ||
2352 | } | ||
2353 | |||
2354 | function errorFunc(evt) { | ||
2355 | clearTimeout(timeoutTimer) | ||
2356 | if(!(evt instanceof Error)){ | ||
2357 | evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") ) | ||
2358 | } | ||
2359 | evt.statusCode = 0 | ||
2360 | callback(evt, failureResponse) | ||
2361 | } | ||
2362 | |||
2363 | // will load the data & process the response in a special response object | ||
2364 | function loadFunc() { | ||
2365 | if (aborted) return | ||
2366 | var status | ||
2367 | clearTimeout(timeoutTimer) | ||
2368 | if(options.useXDR && xhr.status===undefined) { | ||
2369 | //IE8 CORS GET successful response doesn't have a status field, but body is fine | ||
2370 | status = 200 | ||
2371 | } else { | ||
2372 | status = (xhr.status === 1223 ? 204 : xhr.status) | ||
2373 | } | ||
2374 | var response = failureResponse | ||
2375 | var err = null | ||
2376 | |||
2377 | if (status !== 0){ | ||
2378 | response = { | ||
2379 | body: getBody(), | ||
2380 | statusCode: status, | ||
2381 | method: method, | ||
2382 | headers: {}, | ||
2383 | url: uri, | ||
2384 | rawRequest: xhr | ||
2385 | } | ||
2386 | if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE | ||
2387 | response.headers = parseHeaders(xhr.getAllResponseHeaders()) | ||
2388 | } | ||
2389 | } else { | ||
2390 | err = new Error("Internal XMLHttpRequest Error") | ||
2391 | } | ||
2392 | callback(err, response, response.body) | ||
2393 | |||
2394 | } | ||
2395 | |||
2396 | var xhr = options.xhr || null | ||
2397 | |||
2398 | if (!xhr) { | ||
2399 | if (options.cors || options.useXDR) { | ||
2400 | xhr = new createXHR.XDomainRequest() | ||
2401 | }else{ | ||
2402 | xhr = new createXHR.XMLHttpRequest() | ||
2403 | } | ||
2404 | } | ||
2405 | |||
2406 | var key | ||
2407 | var aborted | ||
2408 | var uri = xhr.url = options.uri || options.url | ||
2409 | var method = xhr.method = options.method || "GET" | ||
2410 | var body = options.body || options.data || null | ||
2411 | var headers = xhr.headers = options.headers || {} | ||
2412 | var sync = !!options.sync | ||
2413 | var isJson = false | ||
2414 | var timeoutTimer | ||
2415 | |||
2416 | if ("json" in options) { | ||
2417 | isJson = true | ||
2418 | headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user | ||
2419 | if (method !== "GET" && method !== "HEAD") { | ||
2420 | headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user | ||
2421 | body = JSON.stringify(options.json) | ||
2422 | } | ||
2423 | } | ||
2424 | |||
2425 | xhr.onreadystatechange = readystatechange | ||
2426 | xhr.onload = loadFunc | ||
2427 | xhr.onerror = errorFunc | ||
2428 | // IE9 must have onprogress be set to a unique function. | ||
2429 | xhr.onprogress = function () { | ||
2430 | // IE must die | ||
2431 | } | ||
2432 | xhr.ontimeout = errorFunc | ||
2433 | xhr.open(method, uri, !sync, options.username, options.password) | ||
2434 | //has to be after open | ||
2435 | if(!sync) { | ||
2436 | xhr.withCredentials = !!options.withCredentials | ||
2437 | } | ||
2438 | // Cannot set timeout with sync request | ||
2439 | // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly | ||
2440 | // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent | ||
2441 | if (!sync && options.timeout > 0 ) { | ||
2442 | timeoutTimer = setTimeout(function(){ | ||
2443 | aborted=true//IE9 may still call readystatechange | ||
2444 | xhr.abort("timeout") | ||
2445 | var e = new Error("XMLHttpRequest timeout") | ||
2446 | e.code = "ETIMEDOUT" | ||
2447 | errorFunc(e) | ||
2448 | }, options.timeout ) | ||
2449 | } | ||
2450 | |||
2451 | if (xhr.setRequestHeader) { | ||
2452 | for(key in headers){ | ||
2453 | if(headers.hasOwnProperty(key)){ | ||
2454 | xhr.setRequestHeader(key, headers[key]) | ||
2455 | } | ||
2456 | } | ||
2457 | } else if (options.headers && !isEmpty(options.headers)) { | ||
2458 | throw new Error("Headers cannot be set on an XDomainRequest object") | ||
2459 | } | ||
2460 | |||
2461 | if ("responseType" in options) { | ||
2462 | xhr.responseType = options.responseType | ||
2463 | } | ||
2464 | |||
2465 | if ("beforeSend" in options && | ||
2466 | typeof options.beforeSend === "function" | ||
2467 | ) { | ||
2468 | options.beforeSend(xhr) | ||
2469 | } | ||
2470 | |||
2471 | xhr.send(body) | ||
2472 | |||
2473 | return xhr | ||
2474 | |||
2475 | |||
2476 | } | ||
2477 | |||
2478 | function noop() {} | ||
2479 | |||
2480 | },{"global/window":2,"is-function":57,"once":58,"parse-headers":61,"xtend":62}],57:[function(_dereq_,module,exports){ | ||
2481 | module.exports = isFunction | ||
2482 | |||
2483 | var toString = Object.prototype.toString | ||
2484 | |||
2485 | function isFunction (fn) { | ||
2486 | var string = toString.call(fn) | ||
2487 | return string === '[object Function]' || | ||
2488 | (typeof fn === 'function' && string !== '[object RegExp]') || | ||
2489 | (typeof window !== 'undefined' && | ||
2490 | // IE8 and below | ||
2491 | (fn === window.setTimeout || | ||
2492 | fn === window.alert || | ||
2493 | fn === window.confirm || | ||
2494 | fn === window.prompt)) | ||
2495 | }; | ||
2496 | |||
2497 | },{}],58:[function(_dereq_,module,exports){ | ||
2498 | module.exports = once | ||
2499 | |||
2500 | once.proto = once(function () { | ||
2501 | Object.defineProperty(Function.prototype, 'once', { | ||
2502 | value: function () { | ||
2503 | return once(this) | ||
2504 | }, | ||
2505 | configurable: true | ||
2506 | }) | ||
2507 | }) | ||
2508 | |||
2509 | function once (fn) { | ||
2510 | var called = false | ||
2511 | return function () { | ||
2512 | if (called) return | ||
2513 | called = true | ||
2514 | return fn.apply(this, arguments) | ||
2515 | } | ||
2516 | } | ||
2517 | |||
2518 | },{}],59:[function(_dereq_,module,exports){ | ||
2519 | var isFunction = _dereq_('is-function') | ||
2520 | |||
2521 | module.exports = forEach | ||
2522 | |||
2523 | var toString = Object.prototype.toString | ||
2524 | var hasOwnProperty = Object.prototype.hasOwnProperty | ||
2525 | |||
2526 | function forEach(list, iterator, context) { | ||
2527 | if (!isFunction(iterator)) { | ||
2528 | throw new TypeError('iterator must be a function') | ||
2529 | } | ||
2530 | |||
2531 | if (arguments.length < 3) { | ||
2532 | context = this | ||
2533 | } | ||
2534 | |||
2535 | if (toString.call(list) === '[object Array]') | ||
2536 | forEachArray(list, iterator, context) | ||
2537 | else if (typeof list === 'string') | ||
2538 | forEachString(list, iterator, context) | ||
2539 | else | ||
2540 | forEachObject(list, iterator, context) | ||
2541 | } | ||
2542 | |||
2543 | function forEachArray(array, iterator, context) { | ||
2544 | for (var i = 0, len = array.length; i < len; i++) { | ||
2545 | if (hasOwnProperty.call(array, i)) { | ||
2546 | iterator.call(context, array[i], i, array) | ||
2547 | } | ||
2548 | } | ||
2549 | } | ||
2550 | |||
2551 | function forEachString(string, iterator, context) { | ||
2552 | for (var i = 0, len = string.length; i < len; i++) { | ||
2553 | // no such thing as a sparse string. | ||
2554 | iterator.call(context, string.charAt(i), i, string) | ||
2555 | } | ||
2556 | } | ||
2557 | |||
2558 | function forEachObject(object, iterator, context) { | ||
2559 | for (var k in object) { | ||
2560 | if (hasOwnProperty.call(object, k)) { | ||
2561 | iterator.call(context, object[k], k, object) | ||
2562 | } | ||
2563 | } | ||
2564 | } | ||
2565 | |||
2566 | },{"is-function":57}],60:[function(_dereq_,module,exports){ | ||
2567 | |||
2568 | exports = module.exports = trim; | ||
2569 | |||
2570 | function trim(str){ | ||
2571 | return str.replace(/^\s*|\s*$/g, ''); | ||
2572 | } | ||
2573 | |||
2574 | exports.left = function(str){ | ||
2575 | return str.replace(/^\s*/, ''); | ||
2576 | }; | ||
2577 | |||
2578 | exports.right = function(str){ | ||
2579 | return str.replace(/\s*$/, ''); | ||
2580 | }; | ||
2581 | |||
2582 | },{}],61:[function(_dereq_,module,exports){ | ||
2583 | var trim = _dereq_('trim') | ||
2584 | , forEach = _dereq_('for-each') | ||
2585 | , isArray = function(arg) { | ||
2586 | return Object.prototype.toString.call(arg) === '[object Array]'; | ||
2587 | } | ||
2588 | |||
2589 | module.exports = function (headers) { | ||
2590 | if (!headers) | ||
2591 | return {} | ||
2592 | |||
2593 | var result = {} | ||
2594 | |||
2595 | forEach( | ||
2596 | trim(headers).split('\n') | ||
2597 | , function (row) { | ||
2598 | var index = row.indexOf(':') | ||
2599 | , key = trim(row.slice(0, index)).toLowerCase() | ||
2600 | , value = trim(row.slice(index + 1)) | ||
2601 | |||
2602 | if (typeof(result[key]) === 'undefined') { | ||
2603 | result[key] = value | ||
2604 | } else if (isArray(result[key])) { | ||
2605 | result[key].push(value) | ||
2606 | } else { | ||
2607 | result[key] = [ result[key], value ] | ||
2608 | } | ||
2609 | } | ||
2610 | ) | ||
2611 | |||
2612 | return result | ||
2613 | } | ||
2614 | },{"for-each":59,"trim":60}],62:[function(_dereq_,module,exports){ | ||
2615 | module.exports = extend | ||
2616 | |||
2617 | var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
2618 | |||
2619 | function extend() { | ||
2620 | var target = {} | ||
2621 | |||
2622 | for (var i = 0; i < arguments.length; i++) { | ||
2623 | var source = arguments[i] | ||
2624 | |||
2625 | for (var key in source) { | ||
2626 | if (hasOwnProperty.call(source, key)) { | ||
2627 | target[key] = source[key] | ||
2628 | } | ||
2629 | } | ||
2630 | } | ||
2631 | |||
2632 | return target | ||
2633 | } | ||
2634 | |||
2635 | },{}],63:[function(_dereq_,module,exports){ | ||
2636 | /** | ||
2637 | * @file big-play-button.js | ||
2638 | */ | ||
2639 | 'use strict'; | ||
2640 | |||
2641 | exports.__esModule = true; | ||
2642 | |||
2643 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
2644 | |||
2645 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
2646 | |||
2647 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
2648 | |||
2649 | var _buttonJs = _dereq_('./button.js'); | ||
2650 | |||
2651 | var _buttonJs2 = _interopRequireDefault(_buttonJs); | ||
2652 | |||
2653 | var _componentJs = _dereq_('./component.js'); | ||
2654 | |||
2655 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
2656 | |||
2657 | /** | ||
2658 | * Initial play button. Shows before the video has played. The hiding of the | ||
2659 | * big play button is done via CSS and player states. | ||
2660 | * | ||
2661 | * @param {Object} player Main Player | ||
2662 | * @param {Object=} options Object of option names and values | ||
2663 | * @extends Button | ||
2664 | * @class BigPlayButton | ||
2665 | */ | ||
2666 | |||
2667 | var BigPlayButton = (function (_Button) { | ||
2668 | _inherits(BigPlayButton, _Button); | ||
2669 | |||
2670 | function BigPlayButton(player, options) { | ||
2671 | _classCallCheck(this, BigPlayButton); | ||
2672 | |||
2673 | _Button.call(this, player, options); | ||
2674 | } | ||
2675 | |||
2676 | /** | ||
2677 | * Allow sub components to stack CSS class names | ||
2678 | * | ||
2679 | * @return {String} The constructed class name | ||
2680 | * @method buildCSSClass | ||
2681 | */ | ||
2682 | |||
2683 | BigPlayButton.prototype.buildCSSClass = function buildCSSClass() { | ||
2684 | return 'vjs-big-play-button'; | ||
2685 | }; | ||
2686 | |||
2687 | /** | ||
2688 | * Handles click for play | ||
2689 | * | ||
2690 | * @method handleClick | ||
2691 | */ | ||
2692 | |||
2693 | BigPlayButton.prototype.handleClick = function handleClick() { | ||
2694 | this.player_.play(); | ||
2695 | }; | ||
2696 | |||
2697 | return BigPlayButton; | ||
2698 | })(_buttonJs2['default']); | ||
2699 | |||
2700 | BigPlayButton.prototype.controlText_ = 'Play Video'; | ||
2701 | |||
2702 | _componentJs2['default'].registerComponent('BigPlayButton', BigPlayButton); | ||
2703 | exports['default'] = BigPlayButton; | ||
2704 | module.exports = exports['default']; | ||
2705 | |||
2706 | },{"./button.js":64,"./component.js":67}],64:[function(_dereq_,module,exports){ | ||
2707 | /** | ||
2708 | * @file button.js | ||
2709 | */ | ||
2710 | 'use strict'; | ||
2711 | |||
2712 | exports.__esModule = true; | ||
2713 | |||
2714 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
2715 | |||
2716 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
2717 | |||
2718 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
2719 | |||
2720 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
2721 | |||
2722 | var _clickableComponentJs = _dereq_('./clickable-component.js'); | ||
2723 | |||
2724 | var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); | ||
2725 | |||
2726 | var _component = _dereq_('./component'); | ||
2727 | |||
2728 | var _component2 = _interopRequireDefault(_component); | ||
2729 | |||
2730 | var _utilsEventsJs = _dereq_('./utils/events.js'); | ||
2731 | |||
2732 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
2733 | |||
2734 | var _utilsFnJs = _dereq_('./utils/fn.js'); | ||
2735 | |||
2736 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
2737 | |||
2738 | var _utilsLogJs = _dereq_('./utils/log.js'); | ||
2739 | |||
2740 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
2741 | |||
2742 | var _globalDocument = _dereq_('global/document'); | ||
2743 | |||
2744 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
2745 | |||
2746 | var _objectAssign = _dereq_('object.assign'); | ||
2747 | |||
2748 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
2749 | |||
2750 | /** | ||
2751 | * Base class for all buttons | ||
2752 | * | ||
2753 | * @param {Object} player Main Player | ||
2754 | * @param {Object=} options Object of option names and values | ||
2755 | * @extends ClickableComponent | ||
2756 | * @class Button | ||
2757 | */ | ||
2758 | |||
2759 | var Button = (function (_ClickableComponent) { | ||
2760 | _inherits(Button, _ClickableComponent); | ||
2761 | |||
2762 | function Button(player, options) { | ||
2763 | _classCallCheck(this, Button); | ||
2764 | |||
2765 | _ClickableComponent.call(this, player, options); | ||
2766 | } | ||
2767 | |||
2768 | /** | ||
2769 | * Create the component's DOM element | ||
2770 | * | ||
2771 | * @param {String=} type Element's node type. e.g. 'div' | ||
2772 | * @param {Object=} props An object of properties that should be set on the element | ||
2773 | * @param {Object=} attributes An object of attributes that should be set on the element | ||
2774 | * @return {Element} | ||
2775 | * @method createEl | ||
2776 | */ | ||
2777 | |||
2778 | Button.prototype.createEl = function createEl() { | ||
2779 | var tag = arguments.length <= 0 || arguments[0] === undefined ? 'button' : arguments[0]; | ||
2780 | var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
2781 | var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; | ||
2782 | |||
2783 | props = _objectAssign2['default']({ | ||
2784 | className: this.buildCSSClass() | ||
2785 | }, props); | ||
2786 | |||
2787 | if (tag !== 'button') { | ||
2788 | _utilsLogJs2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.'); | ||
2789 | } | ||
2790 | |||
2791 | // Add attributes for button element | ||
2792 | attributes = _objectAssign2['default']({ | ||
2793 | type: 'button', // Necessary since the default button type is "submit" | ||
2794 | 'aria-live': 'polite' // let the screen reader user know that the text of the button may change | ||
2795 | }, attributes); | ||
2796 | |||
2797 | var el = _component2['default'].prototype.createEl.call(this, tag, props, attributes); | ||
2798 | |||
2799 | this.createControlTextEl(el); | ||
2800 | |||
2801 | return el; | ||
2802 | }; | ||
2803 | |||
2804 | /** | ||
2805 | * Adds a child component inside this button | ||
2806 | * | ||
2807 | * @param {String|Component} child The class name or instance of a child to add | ||
2808 | * @param {Object=} options Options, including options to be passed to children of the child. | ||
2809 | * @return {Component} The child component (created by this process if a string was used) | ||
2810 | * @deprecated | ||
2811 | * @method addChild | ||
2812 | */ | ||
2813 | |||
2814 | Button.prototype.addChild = function addChild(child) { | ||
2815 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
2816 | |||
2817 | var className = this.constructor.name; | ||
2818 | _utilsLogJs2['default'].warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.'); | ||
2819 | |||
2820 | // Avoid the error message generated by ClickableComponent's addChild method | ||
2821 | return _component2['default'].prototype.addChild.call(this, child, options); | ||
2822 | }; | ||
2823 | |||
2824 | /** | ||
2825 | * Handle KeyPress (document level) - Extend with specific functionality for button | ||
2826 | * | ||
2827 | * @method handleKeyPress | ||
2828 | */ | ||
2829 | |||
2830 | Button.prototype.handleKeyPress = function handleKeyPress(event) { | ||
2831 | // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button. | ||
2832 | if (event.which === 32 || event.which === 13) {} else { | ||
2833 | _ClickableComponent.prototype.handleKeyPress.call(this, event); // Pass keypress handling up for unsupported keys | ||
2834 | } | ||
2835 | }; | ||
2836 | |||
2837 | return Button; | ||
2838 | })(_clickableComponentJs2['default']); | ||
2839 | |||
2840 | _component2['default'].registerComponent('Button', Button); | ||
2841 | exports['default'] = Button; | ||
2842 | module.exports = exports['default']; | ||
2843 | |||
2844 | },{"./clickable-component.js":65,"./component":67,"./utils/events.js":133,"./utils/fn.js":134,"./utils/log.js":137,"global/document":1,"object.assign":45}],65:[function(_dereq_,module,exports){ | ||
2845 | /** | ||
2846 | * @file button.js | ||
2847 | */ | ||
2848 | 'use strict'; | ||
2849 | |||
2850 | exports.__esModule = true; | ||
2851 | |||
2852 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
2853 | |||
2854 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
2855 | |||
2856 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
2857 | |||
2858 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
2859 | |||
2860 | var _component = _dereq_('./component'); | ||
2861 | |||
2862 | var _component2 = _interopRequireDefault(_component); | ||
2863 | |||
2864 | var _utilsDomJs = _dereq_('./utils/dom.js'); | ||
2865 | |||
2866 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
2867 | |||
2868 | var _utilsEventsJs = _dereq_('./utils/events.js'); | ||
2869 | |||
2870 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
2871 | |||
2872 | var _utilsFnJs = _dereq_('./utils/fn.js'); | ||
2873 | |||
2874 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
2875 | |||
2876 | var _utilsLogJs = _dereq_('./utils/log.js'); | ||
2877 | |||
2878 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
2879 | |||
2880 | var _globalDocument = _dereq_('global/document'); | ||
2881 | |||
2882 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
2883 | |||
2884 | var _objectAssign = _dereq_('object.assign'); | ||
2885 | |||
2886 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
2887 | |||
2888 | /** | ||
2889 | * Clickable Component which is clickable or keyboard actionable, but is not a native HTML button | ||
2890 | * | ||
2891 | * @param {Object} player Main Player | ||
2892 | * @param {Object=} options Object of option names and values | ||
2893 | * @extends Component | ||
2894 | * @class ClickableComponent | ||
2895 | */ | ||
2896 | |||
2897 | var ClickableComponent = (function (_Component) { | ||
2898 | _inherits(ClickableComponent, _Component); | ||
2899 | |||
2900 | function ClickableComponent(player, options) { | ||
2901 | _classCallCheck(this, ClickableComponent); | ||
2902 | |||
2903 | _Component.call(this, player, options); | ||
2904 | |||
2905 | this.emitTapEvents(); | ||
2906 | |||
2907 | this.on('tap', this.handleClick); | ||
2908 | this.on('click', this.handleClick); | ||
2909 | this.on('focus', this.handleFocus); | ||
2910 | this.on('blur', this.handleBlur); | ||
2911 | } | ||
2912 | |||
2913 | /** | ||
2914 | * Create the component's DOM element | ||
2915 | * | ||
2916 | * @param {String=} type Element's node type. e.g. 'div' | ||
2917 | * @param {Object=} props An object of properties that should be set on the element | ||
2918 | * @param {Object=} attributes An object of attributes that should be set on the element | ||
2919 | * @return {Element} | ||
2920 | * @method createEl | ||
2921 | */ | ||
2922 | |||
2923 | ClickableComponent.prototype.createEl = function createEl() { | ||
2924 | var tag = arguments.length <= 0 || arguments[0] === undefined ? 'div' : arguments[0]; | ||
2925 | var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
2926 | var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; | ||
2927 | |||
2928 | props = _objectAssign2['default']({ | ||
2929 | className: this.buildCSSClass(), | ||
2930 | tabIndex: 0 | ||
2931 | }, props); | ||
2932 | |||
2933 | if (tag === 'button') { | ||
2934 | _utilsLogJs2['default'].error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.'); | ||
2935 | } | ||
2936 | |||
2937 | // Add ARIA attributes for clickable element which is not a native HTML button | ||
2938 | attributes = _objectAssign2['default']({ | ||
2939 | role: 'button', | ||
2940 | 'aria-live': 'polite' // let the screen reader user know that the text of the element may change | ||
2941 | }, attributes); | ||
2942 | |||
2943 | var el = _Component.prototype.createEl.call(this, tag, props, attributes); | ||
2944 | |||
2945 | this.createControlTextEl(el); | ||
2946 | |||
2947 | return el; | ||
2948 | }; | ||
2949 | |||
2950 | /** | ||
2951 | * create control text | ||
2952 | * | ||
2953 | * @param {Element} el Parent element for the control text | ||
2954 | * @return {Element} | ||
2955 | * @method controlText | ||
2956 | */ | ||
2957 | |||
2958 | ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) { | ||
2959 | this.controlTextEl_ = Dom.createEl('span', { | ||
2960 | className: 'vjs-control-text' | ||
2961 | }); | ||
2962 | |||
2963 | if (el) { | ||
2964 | el.appendChild(this.controlTextEl_); | ||
2965 | } | ||
2966 | |||
2967 | this.controlText(this.controlText_); | ||
2968 | |||
2969 | return this.controlTextEl_; | ||
2970 | }; | ||
2971 | |||
2972 | /** | ||
2973 | * Controls text - both request and localize | ||
2974 | * | ||
2975 | * @param {String} text Text for element | ||
2976 | * @return {String} | ||
2977 | * @method controlText | ||
2978 | */ | ||
2979 | |||
2980 | ClickableComponent.prototype.controlText = function controlText(text) { | ||
2981 | if (!text) return this.controlText_ || 'Need Text'; | ||
2982 | |||
2983 | this.controlText_ = text; | ||
2984 | this.controlTextEl_.innerHTML = this.localize(this.controlText_); | ||
2985 | |||
2986 | return this; | ||
2987 | }; | ||
2988 | |||
2989 | /** | ||
2990 | * Allows sub components to stack CSS class names | ||
2991 | * | ||
2992 | * @return {String} | ||
2993 | * @method buildCSSClass | ||
2994 | */ | ||
2995 | |||
2996 | ClickableComponent.prototype.buildCSSClass = function buildCSSClass() { | ||
2997 | return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this); | ||
2998 | }; | ||
2999 | |||
3000 | /** | ||
3001 | * Adds a child component inside this clickable-component | ||
3002 | * | ||
3003 | * @param {String|Component} child The class name or instance of a child to add | ||
3004 | * @param {Object=} options Options, including options to be passed to children of the child. | ||
3005 | * @return {Component} The child component (created by this process if a string was used) | ||
3006 | * @method addChild | ||
3007 | */ | ||
3008 | |||
3009 | ClickableComponent.prototype.addChild = function addChild(child) { | ||
3010 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
3011 | |||
3012 | // TODO: Fix adding an actionable child to a ClickableComponent; currently | ||
3013 | // it will cause issues with assistive technology (e.g. screen readers) | ||
3014 | // which support ARIA, since an element with role="button" cannot have | ||
3015 | // actionable child elements. | ||
3016 | |||
3017 | //let className = this.constructor.name; | ||
3018 | //log.warn(`Adding a child to a ClickableComponent (${className}) can cause issues with assistive technology which supports ARIA, since an element with role="button" cannot have actionable child elements.`); | ||
3019 | |||
3020 | return _Component.prototype.addChild.call(this, child, options); | ||
3021 | }; | ||
3022 | |||
3023 | /** | ||
3024 | * Handle Click - Override with specific functionality for component | ||
3025 | * | ||
3026 | * @method handleClick | ||
3027 | */ | ||
3028 | |||
3029 | ClickableComponent.prototype.handleClick = function handleClick() {}; | ||
3030 | |||
3031 | /** | ||
3032 | * Handle Focus - Add keyboard functionality to element | ||
3033 | * | ||
3034 | * @method handleFocus | ||
3035 | */ | ||
3036 | |||
3037 | ClickableComponent.prototype.handleFocus = function handleFocus() { | ||
3038 | Events.on(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); | ||
3039 | }; | ||
3040 | |||
3041 | /** | ||
3042 | * Handle KeyPress (document level) - Trigger click when Space or Enter key is pressed | ||
3043 | * | ||
3044 | * @method handleKeyPress | ||
3045 | */ | ||
3046 | |||
3047 | ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) { | ||
3048 | // Support Space (32) or Enter (13) key operation to fire a click event | ||
3049 | if (event.which === 32 || event.which === 13) { | ||
3050 | event.preventDefault(); | ||
3051 | this.handleClick(event); | ||
3052 | } else if (_Component.prototype.handleKeyPress) { | ||
3053 | _Component.prototype.handleKeyPress.call(this, event); // Pass keypress handling up for unsupported keys | ||
3054 | } | ||
3055 | }; | ||
3056 | |||
3057 | /** | ||
3058 | * Handle Blur - Remove keyboard triggers | ||
3059 | * | ||
3060 | * @method handleBlur | ||
3061 | */ | ||
3062 | |||
3063 | ClickableComponent.prototype.handleBlur = function handleBlur() { | ||
3064 | Events.off(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); | ||
3065 | }; | ||
3066 | |||
3067 | return ClickableComponent; | ||
3068 | })(_component2['default']); | ||
3069 | |||
3070 | _component2['default'].registerComponent('ClickableComponent', ClickableComponent); | ||
3071 | exports['default'] = ClickableComponent; | ||
3072 | module.exports = exports['default']; | ||
3073 | |||
3074 | },{"./component":67,"./utils/dom.js":132,"./utils/events.js":133,"./utils/fn.js":134,"./utils/log.js":137,"global/document":1,"object.assign":45}],66:[function(_dereq_,module,exports){ | ||
3075 | 'use strict'; | ||
3076 | |||
3077 | exports.__esModule = true; | ||
3078 | |||
3079 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
3080 | |||
3081 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
3082 | |||
3083 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
3084 | |||
3085 | var _button = _dereq_('./button'); | ||
3086 | |||
3087 | var _button2 = _interopRequireDefault(_button); | ||
3088 | |||
3089 | var _component = _dereq_('./component'); | ||
3090 | |||
3091 | var _component2 = _interopRequireDefault(_component); | ||
3092 | |||
3093 | /** | ||
3094 | * The `CloseButton` component is a button which fires a "close" event | ||
3095 | * when it is activated. | ||
3096 | * | ||
3097 | * @extends Button | ||
3098 | * @class CloseButton | ||
3099 | */ | ||
3100 | |||
3101 | var CloseButton = (function (_Button) { | ||
3102 | _inherits(CloseButton, _Button); | ||
3103 | |||
3104 | function CloseButton(player, options) { | ||
3105 | _classCallCheck(this, CloseButton); | ||
3106 | |||
3107 | _Button.call(this, player, options); | ||
3108 | this.controlText(options && options.controlText || this.localize('Close')); | ||
3109 | } | ||
3110 | |||
3111 | CloseButton.prototype.buildCSSClass = function buildCSSClass() { | ||
3112 | return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this); | ||
3113 | }; | ||
3114 | |||
3115 | CloseButton.prototype.handleClick = function handleClick() { | ||
3116 | this.trigger({ type: 'close', bubbles: false }); | ||
3117 | }; | ||
3118 | |||
3119 | return CloseButton; | ||
3120 | })(_button2['default']); | ||
3121 | |||
3122 | _component2['default'].registerComponent('CloseButton', CloseButton); | ||
3123 | exports['default'] = CloseButton; | ||
3124 | module.exports = exports['default']; | ||
3125 | |||
3126 | },{"./button":64,"./component":67}],67:[function(_dereq_,module,exports){ | ||
3127 | /** | ||
3128 | * @file component.js | ||
3129 | * | ||
3130 | * Player Component - Base class for all UI objects | ||
3131 | */ | ||
3132 | |||
3133 | 'use strict'; | ||
3134 | |||
3135 | exports.__esModule = true; | ||
3136 | |||
3137 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
3138 | |||
3139 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
3140 | |||
3141 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
3142 | |||
3143 | var _globalWindow = _dereq_('global/window'); | ||
3144 | |||
3145 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
3146 | |||
3147 | var _utilsDomJs = _dereq_('./utils/dom.js'); | ||
3148 | |||
3149 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
3150 | |||
3151 | var _utilsFnJs = _dereq_('./utils/fn.js'); | ||
3152 | |||
3153 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
3154 | |||
3155 | var _utilsGuidJs = _dereq_('./utils/guid.js'); | ||
3156 | |||
3157 | var Guid = _interopRequireWildcard(_utilsGuidJs); | ||
3158 | |||
3159 | var _utilsEventsJs = _dereq_('./utils/events.js'); | ||
3160 | |||
3161 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
3162 | |||
3163 | var _utilsLogJs = _dereq_('./utils/log.js'); | ||
3164 | |||
3165 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
3166 | |||
3167 | var _utilsToTitleCaseJs = _dereq_('./utils/to-title-case.js'); | ||
3168 | |||
3169 | var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); | ||
3170 | |||
3171 | var _objectAssign = _dereq_('object.assign'); | ||
3172 | |||
3173 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
3174 | |||
3175 | var _utilsMergeOptionsJs = _dereq_('./utils/merge-options.js'); | ||
3176 | |||
3177 | var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); | ||
3178 | |||
3179 | /** | ||
3180 | * Base UI Component class | ||
3181 | * Components are embeddable UI objects that are represented by both a | ||
3182 | * javascript object and an element in the DOM. They can be children of other | ||
3183 | * components, and can have many children themselves. | ||
3184 | * ```js | ||
3185 | * // adding a button to the player | ||
3186 | * var button = player.addChild('button'); | ||
3187 | * button.el(); // -> button element | ||
3188 | * ``` | ||
3189 | * ```html | ||
3190 | * <div class="video-js"> | ||
3191 | * <div class="vjs-button">Button</div> | ||
3192 | * </div> | ||
3193 | * ``` | ||
3194 | * Components are also event targets. | ||
3195 | * ```js | ||
3196 | * button.on('click', function(){ | ||
3197 | * console.log('Button Clicked!'); | ||
3198 | * }); | ||
3199 | * button.trigger('customevent'); | ||
3200 | * ``` | ||
3201 | * | ||
3202 | * @param {Object} player Main Player | ||
3203 | * @param {Object=} options Object of option names and values | ||
3204 | * @param {Function=} ready Ready callback function | ||
3205 | * @class Component | ||
3206 | */ | ||
3207 | |||
3208 | var Component = (function () { | ||
3209 | function Component(player, options, ready) { | ||
3210 | _classCallCheck(this, Component); | ||
3211 | |||
3212 | // The component might be the player itself and we can't pass `this` to super | ||
3213 | if (!player && this.play) { | ||
3214 | this.player_ = player = this; // eslint-disable-line | ||
3215 | } else { | ||
3216 | this.player_ = player; | ||
3217 | } | ||
3218 | |||
3219 | // Make a copy of prototype.options_ to protect against overriding defaults | ||
3220 | this.options_ = _utilsMergeOptionsJs2['default']({}, this.options_); | ||
3221 | |||
3222 | // Updated options with supplied options | ||
3223 | options = this.options_ = _utilsMergeOptionsJs2['default'](this.options_, options); | ||
3224 | |||
3225 | // Get ID from options or options element if one is supplied | ||
3226 | this.id_ = options.id || options.el && options.el.id; | ||
3227 | |||
3228 | // If there was no ID from the options, generate one | ||
3229 | if (!this.id_) { | ||
3230 | // Don't require the player ID function in the case of mock players | ||
3231 | var id = player && player.id && player.id() || 'no_player'; | ||
3232 | |||
3233 | this.id_ = id + '_component_' + Guid.newGUID(); | ||
3234 | } | ||
3235 | |||
3236 | this.name_ = options.name || null; | ||
3237 | |||
3238 | // Create element if one wasn't provided in options | ||
3239 | if (options.el) { | ||
3240 | this.el_ = options.el; | ||
3241 | } else if (options.createEl !== false) { | ||
3242 | this.el_ = this.createEl(); | ||
3243 | } | ||
3244 | |||
3245 | this.children_ = []; | ||
3246 | this.childIndex_ = {}; | ||
3247 | this.childNameIndex_ = {}; | ||
3248 | |||
3249 | // Add any child components in options | ||
3250 | if (options.initChildren !== false) { | ||
3251 | this.initChildren(); | ||
3252 | } | ||
3253 | |||
3254 | this.ready(ready); | ||
3255 | // Don't want to trigger ready here or it will before init is actually | ||
3256 | // finished for all children that run this constructor | ||
3257 | |||
3258 | if (options.reportTouchActivity !== false) { | ||
3259 | this.enableTouchActivity(); | ||
3260 | } | ||
3261 | } | ||
3262 | |||
3263 | /** | ||
3264 | * Dispose of the component and all child components | ||
3265 | * | ||
3266 | * @method dispose | ||
3267 | */ | ||
3268 | |||
3269 | Component.prototype.dispose = function dispose() { | ||
3270 | this.trigger({ type: 'dispose', bubbles: false }); | ||
3271 | |||
3272 | // Dispose all children. | ||
3273 | if (this.children_) { | ||
3274 | for (var i = this.children_.length - 1; i >= 0; i--) { | ||
3275 | if (this.children_[i].dispose) { | ||
3276 | this.children_[i].dispose(); | ||
3277 | } | ||
3278 | } | ||
3279 | } | ||
3280 | |||
3281 | // Delete child references | ||
3282 | this.children_ = null; | ||
3283 | this.childIndex_ = null; | ||
3284 | this.childNameIndex_ = null; | ||
3285 | |||
3286 | // Remove all event listeners. | ||
3287 | this.off(); | ||
3288 | |||
3289 | // Remove element from DOM | ||
3290 | if (this.el_.parentNode) { | ||
3291 | this.el_.parentNode.removeChild(this.el_); | ||
3292 | } | ||
3293 | |||
3294 | Dom.removeElData(this.el_); | ||
3295 | this.el_ = null; | ||
3296 | }; | ||
3297 | |||
3298 | /** | ||
3299 | * Return the component's player | ||
3300 | * | ||
3301 | * @return {Player} | ||
3302 | * @method player | ||
3303 | */ | ||
3304 | |||
3305 | Component.prototype.player = function player() { | ||
3306 | return this.player_; | ||
3307 | }; | ||
3308 | |||
3309 | /** | ||
3310 | * Deep merge of options objects | ||
3311 | * Whenever a property is an object on both options objects | ||
3312 | * the two properties will be merged using mergeOptions. | ||
3313 | * | ||
3314 | * ```js | ||
3315 | * Parent.prototype.options_ = { | ||
3316 | * optionSet: { | ||
3317 | * 'childOne': { 'foo': 'bar', 'asdf': 'fdsa' }, | ||
3318 | * 'childTwo': {}, | ||
3319 | * 'childThree': {} | ||
3320 | * } | ||
3321 | * } | ||
3322 | * newOptions = { | ||
3323 | * optionSet: { | ||
3324 | * 'childOne': { 'foo': 'baz', 'abc': '123' } | ||
3325 | * 'childTwo': null, | ||
3326 | * 'childFour': {} | ||
3327 | * } | ||
3328 | * } | ||
3329 | * | ||
3330 | * this.options(newOptions); | ||
3331 | * ``` | ||
3332 | * RESULT | ||
3333 | * ```js | ||
3334 | * { | ||
3335 | * optionSet: { | ||
3336 | * 'childOne': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' }, | ||
3337 | * 'childTwo': null, // Disabled. Won't be initialized. | ||
3338 | * 'childThree': {}, | ||
3339 | * 'childFour': {} | ||
3340 | * } | ||
3341 | * } | ||
3342 | * ``` | ||
3343 | * | ||
3344 | * @param {Object} obj Object of new option values | ||
3345 | * @return {Object} A NEW object of this.options_ and obj merged | ||
3346 | * @method options | ||
3347 | */ | ||
3348 | |||
3349 | Component.prototype.options = function options(obj) { | ||
3350 | _utilsLogJs2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0'); | ||
3351 | |||
3352 | if (!obj) { | ||
3353 | return this.options_; | ||
3354 | } | ||
3355 | |||
3356 | this.options_ = _utilsMergeOptionsJs2['default'](this.options_, obj); | ||
3357 | return this.options_; | ||
3358 | }; | ||
3359 | |||
3360 | /** | ||
3361 | * Get the component's DOM element | ||
3362 | * ```js | ||
3363 | * var domEl = myComponent.el(); | ||
3364 | * ``` | ||
3365 | * | ||
3366 | * @return {Element} | ||
3367 | * @method el | ||
3368 | */ | ||
3369 | |||
3370 | Component.prototype.el = function el() { | ||
3371 | return this.el_; | ||
3372 | }; | ||
3373 | |||
3374 | /** | ||
3375 | * Create the component's DOM element | ||
3376 | * | ||
3377 | * @param {String=} tagName Element's node type. e.g. 'div' | ||
3378 | * @param {Object=} properties An object of properties that should be set | ||
3379 | * @param {Object=} attributes An object of attributes that should be set | ||
3380 | * @return {Element} | ||
3381 | * @method createEl | ||
3382 | */ | ||
3383 | |||
3384 | Component.prototype.createEl = function createEl(tagName, properties, attributes) { | ||
3385 | return Dom.createEl(tagName, properties, attributes); | ||
3386 | }; | ||
3387 | |||
3388 | Component.prototype.localize = function localize(string) { | ||
3389 | var code = this.player_.language && this.player_.language(); | ||
3390 | var languages = this.player_.languages && this.player_.languages(); | ||
3391 | |||
3392 | if (!code || !languages) { | ||
3393 | return string; | ||
3394 | } | ||
3395 | |||
3396 | var language = languages[code]; | ||
3397 | |||
3398 | if (language && language[string]) { | ||
3399 | return language[string]; | ||
3400 | } | ||
3401 | |||
3402 | var primaryCode = code.split('-')[0]; | ||
3403 | var primaryLang = languages[primaryCode]; | ||
3404 | |||
3405 | if (primaryLang && primaryLang[string]) { | ||
3406 | return primaryLang[string]; | ||
3407 | } | ||
3408 | |||
3409 | return string; | ||
3410 | }; | ||
3411 | |||
3412 | /** | ||
3413 | * Return the component's DOM element where children are inserted. | ||
3414 | * Will either be the same as el() or a new element defined in createEl(). | ||
3415 | * | ||
3416 | * @return {Element} | ||
3417 | * @method contentEl | ||
3418 | */ | ||
3419 | |||
3420 | Component.prototype.contentEl = function contentEl() { | ||
3421 | return this.contentEl_ || this.el_; | ||
3422 | }; | ||
3423 | |||
3424 | /** | ||
3425 | * Get the component's ID | ||
3426 | * ```js | ||
3427 | * var id = myComponent.id(); | ||
3428 | * ``` | ||
3429 | * | ||
3430 | * @return {String} | ||
3431 | * @method id | ||
3432 | */ | ||
3433 | |||
3434 | Component.prototype.id = function id() { | ||
3435 | return this.id_; | ||
3436 | }; | ||
3437 | |||
3438 | /** | ||
3439 | * Get the component's name. The name is often used to reference the component. | ||
3440 | * ```js | ||
3441 | * var name = myComponent.name(); | ||
3442 | * ``` | ||
3443 | * | ||
3444 | * @return {String} | ||
3445 | * @method name | ||
3446 | */ | ||
3447 | |||
3448 | Component.prototype.name = function name() { | ||
3449 | return this.name_; | ||
3450 | }; | ||
3451 | |||
3452 | /** | ||
3453 | * Get an array of all child components | ||
3454 | * ```js | ||
3455 | * var kids = myComponent.children(); | ||
3456 | * ``` | ||
3457 | * | ||
3458 | * @return {Array} The children | ||
3459 | * @method children | ||
3460 | */ | ||
3461 | |||
3462 | Component.prototype.children = function children() { | ||
3463 | return this.children_; | ||
3464 | }; | ||
3465 | |||
3466 | /** | ||
3467 | * Returns a child component with the provided ID | ||
3468 | * | ||
3469 | * @return {Component} | ||
3470 | * @method getChildById | ||
3471 | */ | ||
3472 | |||
3473 | Component.prototype.getChildById = function getChildById(id) { | ||
3474 | return this.childIndex_[id]; | ||
3475 | }; | ||
3476 | |||
3477 | /** | ||
3478 | * Returns a child component with the provided name | ||
3479 | * | ||
3480 | * @return {Component} | ||
3481 | * @method getChild | ||
3482 | */ | ||
3483 | |||
3484 | Component.prototype.getChild = function getChild(name) { | ||
3485 | return this.childNameIndex_[name]; | ||
3486 | }; | ||
3487 | |||
3488 | /** | ||
3489 | * Adds a child component inside this component | ||
3490 | * ```js | ||
3491 | * myComponent.el(); | ||
3492 | * // -> <div class='my-component'></div> | ||
3493 | * myComponent.children(); | ||
3494 | * // [empty array] | ||
3495 | * | ||
3496 | * var myButton = myComponent.addChild('MyButton'); | ||
3497 | * // -> <div class='my-component'><div class="my-button">myButton<div></div> | ||
3498 | * // -> myButton === myComponent.children()[0]; | ||
3499 | * ``` | ||
3500 | * Pass in options for child constructors and options for children of the child | ||
3501 | * ```js | ||
3502 | * var myButton = myComponent.addChild('MyButton', { | ||
3503 | * text: 'Press Me', | ||
3504 | * buttonChildExample: { | ||
3505 | * buttonChildOption: true | ||
3506 | * } | ||
3507 | * }); | ||
3508 | * ``` | ||
3509 | * | ||
3510 | * @param {String|Component} child The class name or instance of a child to add | ||
3511 | * @param {Object=} options Options, including options to be passed to children of the child. | ||
3512 | * @param {Number} index into our children array to attempt to add the child | ||
3513 | * @return {Component} The child component (created by this process if a string was used) | ||
3514 | * @method addChild | ||
3515 | */ | ||
3516 | |||
3517 | Component.prototype.addChild = function addChild(child) { | ||
3518 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
3519 | var index = arguments.length <= 2 || arguments[2] === undefined ? this.children_.length : arguments[2]; | ||
3520 | |||
3521 | var component = undefined; | ||
3522 | var componentName = undefined; | ||
3523 | |||
3524 | // If child is a string, create nt with options | ||
3525 | if (typeof child === 'string') { | ||
3526 | componentName = child; | ||
3527 | |||
3528 | // Options can also be specified as a boolean, so convert to an empty object if false. | ||
3529 | if (!options) { | ||
3530 | options = {}; | ||
3531 | } | ||
3532 | |||
3533 | // Same as above, but true is deprecated so show a warning. | ||
3534 | if (options === true) { | ||
3535 | _utilsLogJs2['default'].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`.'); | ||
3536 | options = {}; | ||
3537 | } | ||
3538 | |||
3539 | // If no componentClass in options, assume componentClass is the name lowercased | ||
3540 | // (e.g. playButton) | ||
3541 | var componentClassName = options.componentClass || _utilsToTitleCaseJs2['default'](componentName); | ||
3542 | |||
3543 | // Set name through options | ||
3544 | options.name = componentName; | ||
3545 | |||
3546 | // Create a new object & element for this controls set | ||
3547 | // If there's no .player_, this is a player | ||
3548 | var ComponentClass = Component.getComponent(componentClassName); | ||
3549 | |||
3550 | if (!ComponentClass) { | ||
3551 | throw new Error('Component ' + componentClassName + ' does not exist'); | ||
3552 | } | ||
3553 | |||
3554 | // data stored directly on the videojs object may be | ||
3555 | // misidentified as a component to retain | ||
3556 | // backwards-compatibility with 4.x. check to make sure the | ||
3557 | // component class can be instantiated. | ||
3558 | if (typeof ComponentClass !== 'function') { | ||
3559 | return null; | ||
3560 | } | ||
3561 | |||
3562 | component = new ComponentClass(this.player_ || this, options); | ||
3563 | |||
3564 | // child is a component instance | ||
3565 | } else { | ||
3566 | component = child; | ||
3567 | } | ||
3568 | |||
3569 | this.children_.splice(index, 0, component); | ||
3570 | |||
3571 | if (typeof component.id === 'function') { | ||
3572 | this.childIndex_[component.id()] = component; | ||
3573 | } | ||
3574 | |||
3575 | // If a name wasn't used to create the component, check if we can use the | ||
3576 | // name function of the component | ||
3577 | componentName = componentName || component.name && component.name(); | ||
3578 | |||
3579 | if (componentName) { | ||
3580 | this.childNameIndex_[componentName] = component; | ||
3581 | } | ||
3582 | |||
3583 | // Add the UI object's element to the container div (box) | ||
3584 | // Having an element is not required | ||
3585 | if (typeof component.el === 'function' && component.el()) { | ||
3586 | var childNodes = this.contentEl().children; | ||
3587 | var refNode = childNodes[index] || null; | ||
3588 | this.contentEl().insertBefore(component.el(), refNode); | ||
3589 | } | ||
3590 | |||
3591 | // Return so it can stored on parent object if desired. | ||
3592 | return component; | ||
3593 | }; | ||
3594 | |||
3595 | /** | ||
3596 | * Remove a child component from this component's list of children, and the | ||
3597 | * child component's element from this component's element | ||
3598 | * | ||
3599 | * @param {Component} component Component to remove | ||
3600 | * @method removeChild | ||
3601 | */ | ||
3602 | |||
3603 | Component.prototype.removeChild = function removeChild(component) { | ||
3604 | if (typeof component === 'string') { | ||
3605 | component = this.getChild(component); | ||
3606 | } | ||
3607 | |||
3608 | if (!component || !this.children_) { | ||
3609 | return; | ||
3610 | } | ||
3611 | |||
3612 | var childFound = false; | ||
3613 | |||
3614 | for (var i = this.children_.length - 1; i >= 0; i--) { | ||
3615 | if (this.children_[i] === component) { | ||
3616 | childFound = true; | ||
3617 | this.children_.splice(i, 1); | ||
3618 | break; | ||
3619 | } | ||
3620 | } | ||
3621 | |||
3622 | if (!childFound) { | ||
3623 | return; | ||
3624 | } | ||
3625 | |||
3626 | this.childIndex_[component.id()] = null; | ||
3627 | this.childNameIndex_[component.name()] = null; | ||
3628 | |||
3629 | var compEl = component.el(); | ||
3630 | |||
3631 | if (compEl && compEl.parentNode === this.contentEl()) { | ||
3632 | this.contentEl().removeChild(component.el()); | ||
3633 | } | ||
3634 | }; | ||
3635 | |||
3636 | /** | ||
3637 | * Add and initialize default child components from options | ||
3638 | * ```js | ||
3639 | * // when an instance of MyComponent is created, all children in options | ||
3640 | * // will be added to the instance by their name strings and options | ||
3641 | * MyComponent.prototype.options_ = { | ||
3642 | * children: [ | ||
3643 | * 'myChildComponent' | ||
3644 | * ], | ||
3645 | * myChildComponent: { | ||
3646 | * myChildOption: true | ||
3647 | * } | ||
3648 | * }; | ||
3649 | * | ||
3650 | * // Or when creating the component | ||
3651 | * var myComp = new MyComponent(player, { | ||
3652 | * children: [ | ||
3653 | * 'myChildComponent' | ||
3654 | * ], | ||
3655 | * myChildComponent: { | ||
3656 | * myChildOption: true | ||
3657 | * } | ||
3658 | * }); | ||
3659 | * ``` | ||
3660 | * The children option can also be an array of | ||
3661 | * child options objects (that also include a 'name' key). | ||
3662 | * This can be used if you have two child components of the | ||
3663 | * same type that need different options. | ||
3664 | * ```js | ||
3665 | * var myComp = new MyComponent(player, { | ||
3666 | * children: [ | ||
3667 | * 'button', | ||
3668 | * { | ||
3669 | * name: 'button', | ||
3670 | * someOtherOption: true | ||
3671 | * }, | ||
3672 | * { | ||
3673 | * name: 'button', | ||
3674 | * someOtherOption: false | ||
3675 | * } | ||
3676 | * ] | ||
3677 | * }); | ||
3678 | * ``` | ||
3679 | * | ||
3680 | * @method initChildren | ||
3681 | */ | ||
3682 | |||
3683 | Component.prototype.initChildren = function initChildren() { | ||
3684 | var _this = this; | ||
3685 | |||
3686 | var children = this.options_.children; | ||
3687 | |||
3688 | if (children) { | ||
3689 | (function () { | ||
3690 | // `this` is `parent` | ||
3691 | var parentOptions = _this.options_; | ||
3692 | |||
3693 | var handleAdd = function handleAdd(child) { | ||
3694 | var name = child.name; | ||
3695 | var opts = child.opts; | ||
3696 | |||
3697 | // Allow options for children to be set at the parent options | ||
3698 | // e.g. videojs(id, { controlBar: false }); | ||
3699 | // instead of videojs(id, { children: { controlBar: false }); | ||
3700 | if (parentOptions[name] !== undefined) { | ||
3701 | opts = parentOptions[name]; | ||
3702 | } | ||
3703 | |||
3704 | // Allow for disabling default components | ||
3705 | // e.g. options['children']['posterImage'] = false | ||
3706 | if (opts === false) { | ||
3707 | return; | ||
3708 | } | ||
3709 | |||
3710 | // Allow options to be passed as a simple boolean if no configuration | ||
3711 | // is necessary. | ||
3712 | if (opts === true) { | ||
3713 | opts = {}; | ||
3714 | } | ||
3715 | |||
3716 | // We also want to pass the original player options to each component as well so they don't need to | ||
3717 | // reach back into the player for options later. | ||
3718 | opts.playerOptions = _this.options_.playerOptions; | ||
3719 | |||
3720 | // Create and add the child component. | ||
3721 | // Add a direct reference to the child by name on the parent instance. | ||
3722 | // If two of the same component are used, different names should be supplied | ||
3723 | // for each | ||
3724 | var newChild = _this.addChild(name, opts); | ||
3725 | if (newChild) { | ||
3726 | _this[name] = newChild; | ||
3727 | } | ||
3728 | }; | ||
3729 | |||
3730 | // Allow for an array of children details to passed in the options | ||
3731 | var workingChildren = undefined; | ||
3732 | var Tech = Component.getComponent('Tech'); | ||
3733 | |||
3734 | if (Array.isArray(children)) { | ||
3735 | workingChildren = children; | ||
3736 | } else { | ||
3737 | workingChildren = Object.keys(children); | ||
3738 | } | ||
3739 | |||
3740 | workingChildren | ||
3741 | // children that are in this.options_ but also in workingChildren would | ||
3742 | // give us extra children we do not want. So, we want to filter them out. | ||
3743 | .concat(Object.keys(_this.options_).filter(function (child) { | ||
3744 | return !workingChildren.some(function (wchild) { | ||
3745 | if (typeof wchild === 'string') { | ||
3746 | return child === wchild; | ||
3747 | } else { | ||
3748 | return child === wchild.name; | ||
3749 | } | ||
3750 | }); | ||
3751 | })).map(function (child) { | ||
3752 | var name = undefined, | ||
3753 | opts = undefined; | ||
3754 | |||
3755 | if (typeof child === 'string') { | ||
3756 | name = child; | ||
3757 | opts = children[name] || _this.options_[name] || {}; | ||
3758 | } else { | ||
3759 | name = child.name; | ||
3760 | opts = child; | ||
3761 | } | ||
3762 | |||
3763 | return { name: name, opts: opts }; | ||
3764 | }).filter(function (child) { | ||
3765 | // we have to make sure that child.name isn't in the techOrder since | ||
3766 | // techs are registerd as Components but can't aren't compatible | ||
3767 | // See https://github.com/videojs/video.js/issues/2772 | ||
3768 | var c = Component.getComponent(child.opts.componentClass || _utilsToTitleCaseJs2['default'](child.name)); | ||
3769 | return c && !Tech.isTech(c); | ||
3770 | }).forEach(handleAdd); | ||
3771 | })(); | ||
3772 | } | ||
3773 | }; | ||
3774 | |||
3775 | /** | ||
3776 | * Allows sub components to stack CSS class names | ||
3777 | * | ||
3778 | * @return {String} The constructed class name | ||
3779 | * @method buildCSSClass | ||
3780 | */ | ||
3781 | |||
3782 | Component.prototype.buildCSSClass = function buildCSSClass() { | ||
3783 | // Child classes can include a function that does: | ||
3784 | // return 'CLASS NAME' + this._super(); | ||
3785 | return ''; | ||
3786 | }; | ||
3787 | |||
3788 | /** | ||
3789 | * Add an event listener to this component's element | ||
3790 | * ```js | ||
3791 | * var myFunc = function(){ | ||
3792 | * var myComponent = this; | ||
3793 | * // Do something when the event is fired | ||
3794 | * }; | ||
3795 | * | ||
3796 | * myComponent.on('eventType', myFunc); | ||
3797 | * ``` | ||
3798 | * The context of myFunc will be myComponent unless previously bound. | ||
3799 | * Alternatively, you can add a listener to another element or component. | ||
3800 | * ```js | ||
3801 | * myComponent.on(otherElement, 'eventName', myFunc); | ||
3802 | * myComponent.on(otherComponent, 'eventName', myFunc); | ||
3803 | * ``` | ||
3804 | * The benefit of using this over `VjsEvents.on(otherElement, 'eventName', myFunc)` | ||
3805 | * and `otherComponent.on('eventName', myFunc)` is that this way the listeners | ||
3806 | * will be automatically cleaned up when either component is disposed. | ||
3807 | * It will also bind myComponent as the context of myFunc. | ||
3808 | * **NOTE**: When using this on elements in the page other than window | ||
3809 | * and document (both permanent), if you remove the element from the DOM | ||
3810 | * you need to call `myComponent.trigger(el, 'dispose')` on it to clean up | ||
3811 | * references to it and allow the browser to garbage collect it. | ||
3812 | * | ||
3813 | * @param {String|Component} first The event type or other component | ||
3814 | * @param {Function|String} second The event handler or event type | ||
3815 | * @param {Function} third The event handler | ||
3816 | * @return {Component} | ||
3817 | * @method on | ||
3818 | */ | ||
3819 | |||
3820 | Component.prototype.on = function on(first, second, third) { | ||
3821 | var _this2 = this; | ||
3822 | |||
3823 | if (typeof first === 'string' || Array.isArray(first)) { | ||
3824 | Events.on(this.el_, first, Fn.bind(this, second)); | ||
3825 | |||
3826 | // Targeting another component or element | ||
3827 | } else { | ||
3828 | (function () { | ||
3829 | var target = first; | ||
3830 | var type = second; | ||
3831 | var fn = Fn.bind(_this2, third); | ||
3832 | |||
3833 | // When this component is disposed, remove the listener from the other component | ||
3834 | var removeOnDispose = function removeOnDispose() { | ||
3835 | return _this2.off(target, type, fn); | ||
3836 | }; | ||
3837 | |||
3838 | // Use the same function ID so we can remove it later it using the ID | ||
3839 | // of the original listener | ||
3840 | removeOnDispose.guid = fn.guid; | ||
3841 | _this2.on('dispose', removeOnDispose); | ||
3842 | |||
3843 | // If the other component is disposed first we need to clean the reference | ||
3844 | // to the other component in this component's removeOnDispose listener | ||
3845 | // Otherwise we create a memory leak. | ||
3846 | var cleanRemover = function cleanRemover() { | ||
3847 | return _this2.off('dispose', removeOnDispose); | ||
3848 | }; | ||
3849 | |||
3850 | // Add the same function ID so we can easily remove it later | ||
3851 | cleanRemover.guid = fn.guid; | ||
3852 | |||
3853 | // Check if this is a DOM node | ||
3854 | if (first.nodeName) { | ||
3855 | // Add the listener to the other element | ||
3856 | Events.on(target, type, fn); | ||
3857 | Events.on(target, 'dispose', cleanRemover); | ||
3858 | |||
3859 | // Should be a component | ||
3860 | // Not using `instanceof Component` because it makes mock players difficult | ||
3861 | } else if (typeof first.on === 'function') { | ||
3862 | // Add the listener to the other component | ||
3863 | target.on(type, fn); | ||
3864 | target.on('dispose', cleanRemover); | ||
3865 | } | ||
3866 | })(); | ||
3867 | } | ||
3868 | |||
3869 | return this; | ||
3870 | }; | ||
3871 | |||
3872 | /** | ||
3873 | * Remove an event listener from this component's element | ||
3874 | * ```js | ||
3875 | * myComponent.off('eventType', myFunc); | ||
3876 | * ``` | ||
3877 | * If myFunc is excluded, ALL listeners for the event type will be removed. | ||
3878 | * If eventType is excluded, ALL listeners will be removed from the component. | ||
3879 | * Alternatively you can use `off` to remove listeners that were added to other | ||
3880 | * elements or components using `myComponent.on(otherComponent...`. | ||
3881 | * In this case both the event type and listener function are REQUIRED. | ||
3882 | * ```js | ||
3883 | * myComponent.off(otherElement, 'eventType', myFunc); | ||
3884 | * myComponent.off(otherComponent, 'eventType', myFunc); | ||
3885 | * ``` | ||
3886 | * | ||
3887 | * @param {String=|Component} first The event type or other component | ||
3888 | * @param {Function=|String} second The listener function or event type | ||
3889 | * @param {Function=} third The listener for other component | ||
3890 | * @return {Component} | ||
3891 | * @method off | ||
3892 | */ | ||
3893 | |||
3894 | Component.prototype.off = function off(first, second, third) { | ||
3895 | if (!first || typeof first === 'string' || Array.isArray(first)) { | ||
3896 | Events.off(this.el_, first, second); | ||
3897 | } else { | ||
3898 | var target = first; | ||
3899 | var type = second; | ||
3900 | // Ensure there's at least a guid, even if the function hasn't been used | ||
3901 | var fn = Fn.bind(this, third); | ||
3902 | |||
3903 | // Remove the dispose listener on this component, | ||
3904 | // which was given the same guid as the event listener | ||
3905 | this.off('dispose', fn); | ||
3906 | |||
3907 | if (first.nodeName) { | ||
3908 | // Remove the listener | ||
3909 | Events.off(target, type, fn); | ||
3910 | // Remove the listener for cleaning the dispose listener | ||
3911 | Events.off(target, 'dispose', fn); | ||
3912 | } else { | ||
3913 | target.off(type, fn); | ||
3914 | target.off('dispose', fn); | ||
3915 | } | ||
3916 | } | ||
3917 | |||
3918 | return this; | ||
3919 | }; | ||
3920 | |||
3921 | /** | ||
3922 | * Add an event listener to be triggered only once and then removed | ||
3923 | * ```js | ||
3924 | * myComponent.one('eventName', myFunc); | ||
3925 | * ``` | ||
3926 | * Alternatively you can add a listener to another element or component | ||
3927 | * that will be triggered only once. | ||
3928 | * ```js | ||
3929 | * myComponent.one(otherElement, 'eventName', myFunc); | ||
3930 | * myComponent.one(otherComponent, 'eventName', myFunc); | ||
3931 | * ``` | ||
3932 | * | ||
3933 | * @param {String|Component} first The event type or other component | ||
3934 | * @param {Function|String} second The listener function or event type | ||
3935 | * @param {Function=} third The listener function for other component | ||
3936 | * @return {Component} | ||
3937 | * @method one | ||
3938 | */ | ||
3939 | |||
3940 | Component.prototype.one = function one(first, second, third) { | ||
3941 | var _this3 = this, | ||
3942 | _arguments = arguments; | ||
3943 | |||
3944 | if (typeof first === 'string' || Array.isArray(first)) { | ||
3945 | Events.one(this.el_, first, Fn.bind(this, second)); | ||
3946 | } else { | ||
3947 | (function () { | ||
3948 | var target = first; | ||
3949 | var type = second; | ||
3950 | var fn = Fn.bind(_this3, third); | ||
3951 | |||
3952 | var newFunc = function newFunc() { | ||
3953 | _this3.off(target, type, newFunc); | ||
3954 | fn.apply(null, _arguments); | ||
3955 | }; | ||
3956 | |||
3957 | // Keep the same function ID so we can remove it later | ||
3958 | newFunc.guid = fn.guid; | ||
3959 | |||
3960 | _this3.on(target, type, newFunc); | ||
3961 | })(); | ||
3962 | } | ||
3963 | |||
3964 | return this; | ||
3965 | }; | ||
3966 | |||
3967 | /** | ||
3968 | * Trigger an event on an element | ||
3969 | * ```js | ||
3970 | * myComponent.trigger('eventName'); | ||
3971 | * myComponent.trigger({'type':'eventName'}); | ||
3972 | * myComponent.trigger('eventName', {data: 'some data'}); | ||
3973 | * myComponent.trigger({'type':'eventName'}, {data: 'some data'}); | ||
3974 | * ``` | ||
3975 | * | ||
3976 | * @param {Event|Object|String} event A string (the type) or an event object with a type attribute | ||
3977 | * @param {Object} [hash] data hash to pass along with the event | ||
3978 | * @return {Component} self | ||
3979 | * @method trigger | ||
3980 | */ | ||
3981 | |||
3982 | Component.prototype.trigger = function trigger(event, hash) { | ||
3983 | Events.trigger(this.el_, event, hash); | ||
3984 | return this; | ||
3985 | }; | ||
3986 | |||
3987 | /** | ||
3988 | * Bind a listener to the component's ready state. | ||
3989 | * Different from event listeners in that if the ready event has already happened | ||
3990 | * it will trigger the function immediately. | ||
3991 | * | ||
3992 | * @param {Function} fn Ready listener | ||
3993 | * @param {Boolean} sync Exec the listener synchronously if component is ready | ||
3994 | * @return {Component} | ||
3995 | * @method ready | ||
3996 | */ | ||
3997 | |||
3998 | Component.prototype.ready = function ready(fn) { | ||
3999 | var sync = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; | ||
4000 | |||
4001 | if (fn) { | ||
4002 | if (this.isReady_) { | ||
4003 | if (sync) { | ||
4004 | fn.call(this); | ||
4005 | } else { | ||
4006 | // Call the function asynchronously by default for consistency | ||
4007 | this.setTimeout(fn, 1); | ||
4008 | } | ||
4009 | } else { | ||
4010 | this.readyQueue_ = this.readyQueue_ || []; | ||
4011 | this.readyQueue_.push(fn); | ||
4012 | } | ||
4013 | } | ||
4014 | return this; | ||
4015 | }; | ||
4016 | |||
4017 | /** | ||
4018 | * Trigger the ready listeners | ||
4019 | * | ||
4020 | * @return {Component} | ||
4021 | * @method triggerReady | ||
4022 | */ | ||
4023 | |||
4024 | Component.prototype.triggerReady = function triggerReady() { | ||
4025 | this.isReady_ = true; | ||
4026 | |||
4027 | // Ensure ready is triggerd asynchronously | ||
4028 | this.setTimeout(function () { | ||
4029 | var readyQueue = this.readyQueue_; | ||
4030 | |||
4031 | // Reset Ready Queue | ||
4032 | this.readyQueue_ = []; | ||
4033 | |||
4034 | if (readyQueue && readyQueue.length > 0) { | ||
4035 | readyQueue.forEach(function (fn) { | ||
4036 | fn.call(this); | ||
4037 | }, this); | ||
4038 | } | ||
4039 | |||
4040 | // Allow for using event listeners also | ||
4041 | this.trigger('ready'); | ||
4042 | }, 1); | ||
4043 | }; | ||
4044 | |||
4045 | /** | ||
4046 | * Finds a single DOM element matching `selector` within the component's | ||
4047 | * `contentEl` or another custom context. | ||
4048 | * | ||
4049 | * @method $ | ||
4050 | * @param {String} selector | ||
4051 | * A valid CSS selector, which will be passed to `querySelector`. | ||
4052 | * | ||
4053 | * @param {Element|String} [context=document] | ||
4054 | * A DOM element within which to query. Can also be a selector | ||
4055 | * string in which case the first matching element will be used | ||
4056 | * as context. If missing (or no element matches selector), falls | ||
4057 | * back to `document`. | ||
4058 | * | ||
4059 | * @return {Element|null} | ||
4060 | */ | ||
4061 | |||
4062 | Component.prototype.$ = function $(selector, context) { | ||
4063 | return Dom.$(selector, context || this.contentEl()); | ||
4064 | }; | ||
4065 | |||
4066 | /** | ||
4067 | * Finds a all DOM elements matching `selector` within the component's | ||
4068 | * `contentEl` or another custom context. | ||
4069 | * | ||
4070 | * @method $$ | ||
4071 | * @param {String} selector | ||
4072 | * A valid CSS selector, which will be passed to `querySelectorAll`. | ||
4073 | * | ||
4074 | * @param {Element|String} [context=document] | ||
4075 | * A DOM element within which to query. Can also be a selector | ||
4076 | * string in which case the first matching element will be used | ||
4077 | * as context. If missing (or no element matches selector), falls | ||
4078 | * back to `document`. | ||
4079 | * | ||
4080 | * @return {NodeList} | ||
4081 | */ | ||
4082 | |||
4083 | Component.prototype.$$ = function $$(selector, context) { | ||
4084 | return Dom.$$(selector, context || this.contentEl()); | ||
4085 | }; | ||
4086 | |||
4087 | /** | ||
4088 | * Check if a component's element has a CSS class name | ||
4089 | * | ||
4090 | * @param {String} classToCheck Classname to check | ||
4091 | * @return {Component} | ||
4092 | * @method hasClass | ||
4093 | */ | ||
4094 | |||
4095 | Component.prototype.hasClass = function hasClass(classToCheck) { | ||
4096 | return Dom.hasElClass(this.el_, classToCheck); | ||
4097 | }; | ||
4098 | |||
4099 | /** | ||
4100 | * Add a CSS class name to the component's element | ||
4101 | * | ||
4102 | * @param {String} classToAdd Classname to add | ||
4103 | * @return {Component} | ||
4104 | * @method addClass | ||
4105 | */ | ||
4106 | |||
4107 | Component.prototype.addClass = function addClass(classToAdd) { | ||
4108 | Dom.addElClass(this.el_, classToAdd); | ||
4109 | return this; | ||
4110 | }; | ||
4111 | |||
4112 | /** | ||
4113 | * Remove a CSS class name from the component's element | ||
4114 | * | ||
4115 | * @param {String} classToRemove Classname to remove | ||
4116 | * @return {Component} | ||
4117 | * @method removeClass | ||
4118 | */ | ||
4119 | |||
4120 | Component.prototype.removeClass = function removeClass(classToRemove) { | ||
4121 | Dom.removeElClass(this.el_, classToRemove); | ||
4122 | return this; | ||
4123 | }; | ||
4124 | |||
4125 | /** | ||
4126 | * Add or remove a CSS class name from the component's element | ||
4127 | * | ||
4128 | * @param {String} classToToggle | ||
4129 | * @param {Boolean|Function} [predicate] | ||
4130 | * Can be a function that returns a Boolean. If `true`, the class | ||
4131 | * will be added; if `false`, the class will be removed. If not | ||
4132 | * given, the class will be added if not present and vice versa. | ||
4133 | * | ||
4134 | * @return {Component} | ||
4135 | * @method toggleClass | ||
4136 | */ | ||
4137 | |||
4138 | Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) { | ||
4139 | Dom.toggleElClass(this.el_, classToToggle, predicate); | ||
4140 | return this; | ||
4141 | }; | ||
4142 | |||
4143 | /** | ||
4144 | * Show the component element if hidden | ||
4145 | * | ||
4146 | * @return {Component} | ||
4147 | * @method show | ||
4148 | */ | ||
4149 | |||
4150 | Component.prototype.show = function show() { | ||
4151 | this.removeClass('vjs-hidden'); | ||
4152 | return this; | ||
4153 | }; | ||
4154 | |||
4155 | /** | ||
4156 | * Hide the component element if currently showing | ||
4157 | * | ||
4158 | * @return {Component} | ||
4159 | * @method hide | ||
4160 | */ | ||
4161 | |||
4162 | Component.prototype.hide = function hide() { | ||
4163 | this.addClass('vjs-hidden'); | ||
4164 | return this; | ||
4165 | }; | ||
4166 | |||
4167 | /** | ||
4168 | * Lock an item in its visible state | ||
4169 | * To be used with fadeIn/fadeOut. | ||
4170 | * | ||
4171 | * @return {Component} | ||
4172 | * @private | ||
4173 | * @method lockShowing | ||
4174 | */ | ||
4175 | |||
4176 | Component.prototype.lockShowing = function lockShowing() { | ||
4177 | this.addClass('vjs-lock-showing'); | ||
4178 | return this; | ||
4179 | }; | ||
4180 | |||
4181 | /** | ||
4182 | * Unlock an item to be hidden | ||
4183 | * To be used with fadeIn/fadeOut. | ||
4184 | * | ||
4185 | * @return {Component} | ||
4186 | * @private | ||
4187 | * @method unlockShowing | ||
4188 | */ | ||
4189 | |||
4190 | Component.prototype.unlockShowing = function unlockShowing() { | ||
4191 | this.removeClass('vjs-lock-showing'); | ||
4192 | return this; | ||
4193 | }; | ||
4194 | |||
4195 | /** | ||
4196 | * Set or get the width of the component (CSS values) | ||
4197 | * Setting the video tag dimension values only works with values in pixels. | ||
4198 | * Percent values will not work. | ||
4199 | * Some percents can be used, but width()/height() will return the number + %, | ||
4200 | * not the actual computed width/height. | ||
4201 | * | ||
4202 | * @param {Number|String=} num Optional width number | ||
4203 | * @param {Boolean} skipListeners Skip the 'resize' event trigger | ||
4204 | * @return {Component} This component, when setting the width | ||
4205 | * @return {Number|String} The width, when getting | ||
4206 | * @method width | ||
4207 | */ | ||
4208 | |||
4209 | Component.prototype.width = function width(num, skipListeners) { | ||
4210 | return this.dimension('width', num, skipListeners); | ||
4211 | }; | ||
4212 | |||
4213 | /** | ||
4214 | * Get or set the height of the component (CSS values) | ||
4215 | * Setting the video tag dimension values only works with values in pixels. | ||
4216 | * Percent values will not work. | ||
4217 | * Some percents can be used, but width()/height() will return the number + %, | ||
4218 | * not the actual computed width/height. | ||
4219 | * | ||
4220 | * @param {Number|String=} num New component height | ||
4221 | * @param {Boolean=} skipListeners Skip the resize event trigger | ||
4222 | * @return {Component} This component, when setting the height | ||
4223 | * @return {Number|String} The height, when getting | ||
4224 | * @method height | ||
4225 | */ | ||
4226 | |||
4227 | Component.prototype.height = function height(num, skipListeners) { | ||
4228 | return this.dimension('height', num, skipListeners); | ||
4229 | }; | ||
4230 | |||
4231 | /** | ||
4232 | * Set both width and height at the same time | ||
4233 | * | ||
4234 | * @param {Number|String} width Width of player | ||
4235 | * @param {Number|String} height Height of player | ||
4236 | * @return {Component} The component | ||
4237 | * @method dimensions | ||
4238 | */ | ||
4239 | |||
4240 | Component.prototype.dimensions = function dimensions(width, height) { | ||
4241 | // Skip resize listeners on width for optimization | ||
4242 | return this.width(width, true).height(height); | ||
4243 | }; | ||
4244 | |||
4245 | /** | ||
4246 | * Get or set width or height | ||
4247 | * This is the shared code for the width() and height() methods. | ||
4248 | * All for an integer, integer + 'px' or integer + '%'; | ||
4249 | * Known issue: Hidden elements officially have a width of 0. We're defaulting | ||
4250 | * to the style.width value and falling back to computedStyle which has the | ||
4251 | * hidden element issue. Info, but probably not an efficient fix: | ||
4252 | * http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/ | ||
4253 | * | ||
4254 | * @param {String} widthOrHeight 'width' or 'height' | ||
4255 | * @param {Number|String=} num New dimension | ||
4256 | * @param {Boolean=} skipListeners Skip resize event trigger | ||
4257 | * @return {Component} The component if a dimension was set | ||
4258 | * @return {Number|String} The dimension if nothing was set | ||
4259 | * @private | ||
4260 | * @method dimension | ||
4261 | */ | ||
4262 | |||
4263 | Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) { | ||
4264 | if (num !== undefined) { | ||
4265 | // Set to zero if null or literally NaN (NaN !== NaN) | ||
4266 | if (num === null || num !== num) { | ||
4267 | num = 0; | ||
4268 | } | ||
4269 | |||
4270 | // Check if using css width/height (% or px) and adjust | ||
4271 | if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) { | ||
4272 | this.el_.style[widthOrHeight] = num; | ||
4273 | } else if (num === 'auto') { | ||
4274 | this.el_.style[widthOrHeight] = ''; | ||
4275 | } else { | ||
4276 | this.el_.style[widthOrHeight] = num + 'px'; | ||
4277 | } | ||
4278 | |||
4279 | // skipListeners allows us to avoid triggering the resize event when setting both width and height | ||
4280 | if (!skipListeners) { | ||
4281 | this.trigger('resize'); | ||
4282 | } | ||
4283 | |||
4284 | // Return component | ||
4285 | return this; | ||
4286 | } | ||
4287 | |||
4288 | // Not setting a value, so getting it | ||
4289 | // Make sure element exists | ||
4290 | if (!this.el_) { | ||
4291 | return 0; | ||
4292 | } | ||
4293 | |||
4294 | // Get dimension value from style | ||
4295 | var val = this.el_.style[widthOrHeight]; | ||
4296 | var pxIndex = val.indexOf('px'); | ||
4297 | |||
4298 | if (pxIndex !== -1) { | ||
4299 | // Return the pixel value with no 'px' | ||
4300 | return parseInt(val.slice(0, pxIndex), 10); | ||
4301 | } | ||
4302 | |||
4303 | // No px so using % or no style was set, so falling back to offsetWidth/height | ||
4304 | // If component has display:none, offset will return 0 | ||
4305 | // TODO: handle display:none and no dimension style using px | ||
4306 | return parseInt(this.el_['offset' + _utilsToTitleCaseJs2['default'](widthOrHeight)], 10); | ||
4307 | }; | ||
4308 | |||
4309 | /** | ||
4310 | * Emit 'tap' events when touch events are supported | ||
4311 | * This is used to support toggling the controls through a tap on the video. | ||
4312 | * We're requiring them to be enabled because otherwise every component would | ||
4313 | * have this extra overhead unnecessarily, on mobile devices where extra | ||
4314 | * overhead is especially bad. | ||
4315 | * | ||
4316 | * @private | ||
4317 | * @method emitTapEvents | ||
4318 | */ | ||
4319 | |||
4320 | Component.prototype.emitTapEvents = function emitTapEvents() { | ||
4321 | // Track the start time so we can determine how long the touch lasted | ||
4322 | var touchStart = 0; | ||
4323 | var firstTouch = null; | ||
4324 | |||
4325 | // Maximum movement allowed during a touch event to still be considered a tap | ||
4326 | // Other popular libs use anywhere from 2 (hammer.js) to 15, so 10 seems like a nice, round number. | ||
4327 | var tapMovementThreshold = 10; | ||
4328 | |||
4329 | // The maximum length a touch can be while still being considered a tap | ||
4330 | var touchTimeThreshold = 200; | ||
4331 | |||
4332 | var couldBeTap = undefined; | ||
4333 | |||
4334 | this.on('touchstart', function (event) { | ||
4335 | // If more than one finger, don't consider treating this as a click | ||
4336 | if (event.touches.length === 1) { | ||
4337 | // Copy the touches object to prevent modifying the original | ||
4338 | firstTouch = _objectAssign2['default']({}, event.touches[0]); | ||
4339 | // Record start time so we can detect a tap vs. "touch and hold" | ||
4340 | touchStart = new Date().getTime(); | ||
4341 | // Reset couldBeTap tracking | ||
4342 | couldBeTap = true; | ||
4343 | } | ||
4344 | }); | ||
4345 | |||
4346 | this.on('touchmove', function (event) { | ||
4347 | // If more than one finger, don't consider treating this as a click | ||
4348 | if (event.touches.length > 1) { | ||
4349 | couldBeTap = false; | ||
4350 | } else if (firstTouch) { | ||
4351 | // Some devices will throw touchmoves for all but the slightest of taps. | ||
4352 | // So, if we moved only a small distance, this could still be a tap | ||
4353 | var xdiff = event.touches[0].pageX - firstTouch.pageX; | ||
4354 | var ydiff = event.touches[0].pageY - firstTouch.pageY; | ||
4355 | var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff); | ||
4356 | |||
4357 | if (touchDistance > tapMovementThreshold) { | ||
4358 | couldBeTap = false; | ||
4359 | } | ||
4360 | } | ||
4361 | }); | ||
4362 | |||
4363 | var noTap = function noTap() { | ||
4364 | couldBeTap = false; | ||
4365 | }; | ||
4366 | |||
4367 | // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s | ||
4368 | this.on('touchleave', noTap); | ||
4369 | this.on('touchcancel', noTap); | ||
4370 | |||
4371 | // When the touch ends, measure how long it took and trigger the appropriate | ||
4372 | // event | ||
4373 | this.on('touchend', function (event) { | ||
4374 | firstTouch = null; | ||
4375 | // Proceed only if the touchmove/leave/cancel event didn't happen | ||
4376 | if (couldBeTap === true) { | ||
4377 | // Measure how long the touch lasted | ||
4378 | var touchTime = new Date().getTime() - touchStart; | ||
4379 | |||
4380 | // Make sure the touch was less than the threshold to be considered a tap | ||
4381 | if (touchTime < touchTimeThreshold) { | ||
4382 | // Don't let browser turn this into a click | ||
4383 | event.preventDefault(); | ||
4384 | this.trigger('tap'); | ||
4385 | // It may be good to copy the touchend event object and change the | ||
4386 | // type to tap, if the other event properties aren't exact after | ||
4387 | // Events.fixEvent runs (e.g. event.target) | ||
4388 | } | ||
4389 | } | ||
4390 | }); | ||
4391 | }; | ||
4392 | |||
4393 | /** | ||
4394 | * Report user touch activity when touch events occur | ||
4395 | * User activity is used to determine when controls should show/hide. It's | ||
4396 | * relatively simple when it comes to mouse events, because any mouse event | ||
4397 | * should show the controls. So we capture mouse events that bubble up to the | ||
4398 | * player and report activity when that happens. | ||
4399 | * With touch events it isn't as easy. We can't rely on touch events at the | ||
4400 | * player level, because a tap (touchstart + touchend) on the video itself on | ||
4401 | * mobile devices is meant to turn controls off (and on). User activity is | ||
4402 | * checked asynchronously, so what could happen is a tap event on the video | ||
4403 | * turns the controls off, then the touchend event bubbles up to the player, | ||
4404 | * which if it reported user activity, would turn the controls right back on. | ||
4405 | * (We also don't want to completely block touch events from bubbling up) | ||
4406 | * Also a touchmove, touch+hold, and anything other than a tap is not supposed | ||
4407 | * to turn the controls back on on a mobile device. | ||
4408 | * Here we're setting the default component behavior to report user activity | ||
4409 | * whenever touch events happen, and this can be turned off by components that | ||
4410 | * want touch events to act differently. | ||
4411 | * | ||
4412 | * @method enableTouchActivity | ||
4413 | */ | ||
4414 | |||
4415 | Component.prototype.enableTouchActivity = function enableTouchActivity() { | ||
4416 | // Don't continue if the root player doesn't support reporting user activity | ||
4417 | if (!this.player() || !this.player().reportUserActivity) { | ||
4418 | return; | ||
4419 | } | ||
4420 | |||
4421 | // listener for reporting that the user is active | ||
4422 | var report = Fn.bind(this.player(), this.player().reportUserActivity); | ||
4423 | |||
4424 | var touchHolding = undefined; | ||
4425 | |||
4426 | this.on('touchstart', function () { | ||
4427 | report(); | ||
4428 | // For as long as the they are touching the device or have their mouse down, | ||
4429 | // we consider them active even if they're not moving their finger or mouse. | ||
4430 | // So we want to continue to update that they are active | ||
4431 | this.clearInterval(touchHolding); | ||
4432 | // report at the same interval as activityCheck | ||
4433 | touchHolding = this.setInterval(report, 250); | ||
4434 | }); | ||
4435 | |||
4436 | var touchEnd = function touchEnd(event) { | ||
4437 | report(); | ||
4438 | // stop the interval that maintains activity if the touch is holding | ||
4439 | this.clearInterval(touchHolding); | ||
4440 | }; | ||
4441 | |||
4442 | this.on('touchmove', report); | ||
4443 | this.on('touchend', touchEnd); | ||
4444 | this.on('touchcancel', touchEnd); | ||
4445 | }; | ||
4446 | |||
4447 | /** | ||
4448 | * Creates timeout and sets up disposal automatically. | ||
4449 | * | ||
4450 | * @param {Function} fn The function to run after the timeout. | ||
4451 | * @param {Number} timeout Number of ms to delay before executing specified function. | ||
4452 | * @return {Number} Returns the timeout ID | ||
4453 | * @method setTimeout | ||
4454 | */ | ||
4455 | |||
4456 | Component.prototype.setTimeout = function setTimeout(fn, timeout) { | ||
4457 | fn = Fn.bind(this, fn); | ||
4458 | |||
4459 | // window.setTimeout would be preferable here, but due to some bizarre issue with Sinon and/or Phantomjs, we can't. | ||
4460 | var timeoutId = _globalWindow2['default'].setTimeout(fn, timeout); | ||
4461 | |||
4462 | var disposeFn = function disposeFn() { | ||
4463 | this.clearTimeout(timeoutId); | ||
4464 | }; | ||
4465 | |||
4466 | disposeFn.guid = 'vjs-timeout-' + timeoutId; | ||
4467 | |||
4468 | this.on('dispose', disposeFn); | ||
4469 | |||
4470 | return timeoutId; | ||
4471 | }; | ||
4472 | |||
4473 | /** | ||
4474 | * Clears a timeout and removes the associated dispose listener | ||
4475 | * | ||
4476 | * @param {Number} timeoutId The id of the timeout to clear | ||
4477 | * @return {Number} Returns the timeout ID | ||
4478 | * @method clearTimeout | ||
4479 | */ | ||
4480 | |||
4481 | Component.prototype.clearTimeout = function clearTimeout(timeoutId) { | ||
4482 | _globalWindow2['default'].clearTimeout(timeoutId); | ||
4483 | |||
4484 | var disposeFn = function disposeFn() {}; | ||
4485 | |||
4486 | disposeFn.guid = 'vjs-timeout-' + timeoutId; | ||
4487 | |||
4488 | this.off('dispose', disposeFn); | ||
4489 | |||
4490 | return timeoutId; | ||
4491 | }; | ||
4492 | |||
4493 | /** | ||
4494 | * Creates an interval and sets up disposal automatically. | ||
4495 | * | ||
4496 | * @param {Function} fn The function to run every N seconds. | ||
4497 | * @param {Number} interval Number of ms to delay before executing specified function. | ||
4498 | * @return {Number} Returns the interval ID | ||
4499 | * @method setInterval | ||
4500 | */ | ||
4501 | |||
4502 | Component.prototype.setInterval = function setInterval(fn, interval) { | ||
4503 | fn = Fn.bind(this, fn); | ||
4504 | |||
4505 | var intervalId = _globalWindow2['default'].setInterval(fn, interval); | ||
4506 | |||
4507 | var disposeFn = function disposeFn() { | ||
4508 | this.clearInterval(intervalId); | ||
4509 | }; | ||
4510 | |||
4511 | disposeFn.guid = 'vjs-interval-' + intervalId; | ||
4512 | |||
4513 | this.on('dispose', disposeFn); | ||
4514 | |||
4515 | return intervalId; | ||
4516 | }; | ||
4517 | |||
4518 | /** | ||
4519 | * Clears an interval and removes the associated dispose listener | ||
4520 | * | ||
4521 | * @param {Number} intervalId The id of the interval to clear | ||
4522 | * @return {Number} Returns the interval ID | ||
4523 | * @method clearInterval | ||
4524 | */ | ||
4525 | |||
4526 | Component.prototype.clearInterval = function clearInterval(intervalId) { | ||
4527 | _globalWindow2['default'].clearInterval(intervalId); | ||
4528 | |||
4529 | var disposeFn = function disposeFn() {}; | ||
4530 | |||
4531 | disposeFn.guid = 'vjs-interval-' + intervalId; | ||
4532 | |||
4533 | this.off('dispose', disposeFn); | ||
4534 | |||
4535 | return intervalId; | ||
4536 | }; | ||
4537 | |||
4538 | /** | ||
4539 | * Registers a component | ||
4540 | * | ||
4541 | * @param {String} name Name of the component to register | ||
4542 | * @param {Object} comp The component to register | ||
4543 | * @static | ||
4544 | * @method registerComponent | ||
4545 | */ | ||
4546 | |||
4547 | Component.registerComponent = function registerComponent(name, comp) { | ||
4548 | if (!Component.components_) { | ||
4549 | Component.components_ = {}; | ||
4550 | } | ||
4551 | |||
4552 | Component.components_[name] = comp; | ||
4553 | return comp; | ||
4554 | }; | ||
4555 | |||
4556 | /** | ||
4557 | * Gets a component by name | ||
4558 | * | ||
4559 | * @param {String} name Name of the component to get | ||
4560 | * @return {Component} | ||
4561 | * @static | ||
4562 | * @method getComponent | ||
4563 | */ | ||
4564 | |||
4565 | Component.getComponent = function getComponent(name) { | ||
4566 | if (Component.components_ && Component.components_[name]) { | ||
4567 | return Component.components_[name]; | ||
4568 | } | ||
4569 | |||
4570 | if (_globalWindow2['default'] && _globalWindow2['default'].videojs && _globalWindow2['default'].videojs[name]) { | ||
4571 | _utilsLogJs2['default'].warn('The ' + name + ' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)'); | ||
4572 | return _globalWindow2['default'].videojs[name]; | ||
4573 | } | ||
4574 | }; | ||
4575 | |||
4576 | /** | ||
4577 | * Sets up the constructor using the supplied init method | ||
4578 | * or uses the init of the parent object | ||
4579 | * | ||
4580 | * @param {Object} props An object of properties | ||
4581 | * @static | ||
4582 | * @deprecated | ||
4583 | * @method extend | ||
4584 | */ | ||
4585 | |||
4586 | Component.extend = function extend(props) { | ||
4587 | props = props || {}; | ||
4588 | |||
4589 | _utilsLogJs2['default'].warn('Component.extend({}) has been deprecated, use videojs.extend(Component, {}) instead'); | ||
4590 | |||
4591 | // Set up the constructor using the supplied init method | ||
4592 | // or using the init of the parent object | ||
4593 | // Make sure to check the unobfuscated version for external libs | ||
4594 | var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {}; | ||
4595 | // In Resig's simple class inheritance (previously used) the constructor | ||
4596 | // is a function that calls `this.init.apply(arguments)` | ||
4597 | // However that would prevent us from using `ParentObject.call(this);` | ||
4598 | // in a Child constructor because the `this` in `this.init` | ||
4599 | // would still refer to the Child and cause an infinite loop. | ||
4600 | // We would instead have to do | ||
4601 | // `ParentObject.prototype.init.apply(this, arguments);` | ||
4602 | // Bleh. We're not creating a _super() function, so it's good to keep | ||
4603 | // the parent constructor reference simple. | ||
4604 | var subObj = function subObj() { | ||
4605 | init.apply(this, arguments); | ||
4606 | }; | ||
4607 | |||
4608 | // Inherit from this object's prototype | ||
4609 | subObj.prototype = Object.create(this.prototype); | ||
4610 | // Reset the constructor property for subObj otherwise | ||
4611 | // instances of subObj would have the constructor of the parent Object | ||
4612 | subObj.prototype.constructor = subObj; | ||
4613 | |||
4614 | // Make the class extendable | ||
4615 | subObj.extend = Component.extend; | ||
4616 | |||
4617 | // Extend subObj's prototype with functions and other properties from props | ||
4618 | for (var _name in props) { | ||
4619 | if (props.hasOwnProperty(_name)) { | ||
4620 | subObj.prototype[_name] = props[_name]; | ||
4621 | } | ||
4622 | } | ||
4623 | |||
4624 | return subObj; | ||
4625 | }; | ||
4626 | |||
4627 | return Component; | ||
4628 | })(); | ||
4629 | |||
4630 | Component.registerComponent('Component', Component); | ||
4631 | exports['default'] = Component; | ||
4632 | module.exports = exports['default']; | ||
4633 | |||
4634 | },{"./utils/dom.js":132,"./utils/events.js":133,"./utils/fn.js":134,"./utils/guid.js":136,"./utils/log.js":137,"./utils/merge-options.js":138,"./utils/to-title-case.js":141,"global/window":2,"object.assign":45}],68:[function(_dereq_,module,exports){ | ||
4635 | /** | ||
4636 | * @file control-bar.js | ||
4637 | */ | ||
4638 | 'use strict'; | ||
4639 | |||
4640 | exports.__esModule = true; | ||
4641 | |||
4642 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
4643 | |||
4644 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
4645 | |||
4646 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
4647 | |||
4648 | var _componentJs = _dereq_('../component.js'); | ||
4649 | |||
4650 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
4651 | |||
4652 | // Required children | ||
4653 | |||
4654 | var _playToggleJs = _dereq_('./play-toggle.js'); | ||
4655 | |||
4656 | var _playToggleJs2 = _interopRequireDefault(_playToggleJs); | ||
4657 | |||
4658 | var _timeControlsCurrentTimeDisplayJs = _dereq_('./time-controls/current-time-display.js'); | ||
4659 | |||
4660 | var _timeControlsCurrentTimeDisplayJs2 = _interopRequireDefault(_timeControlsCurrentTimeDisplayJs); | ||
4661 | |||
4662 | var _timeControlsDurationDisplayJs = _dereq_('./time-controls/duration-display.js'); | ||
4663 | |||
4664 | var _timeControlsDurationDisplayJs2 = _interopRequireDefault(_timeControlsDurationDisplayJs); | ||
4665 | |||
4666 | var _timeControlsTimeDividerJs = _dereq_('./time-controls/time-divider.js'); | ||
4667 | |||
4668 | var _timeControlsTimeDividerJs2 = _interopRequireDefault(_timeControlsTimeDividerJs); | ||
4669 | |||
4670 | var _timeControlsRemainingTimeDisplayJs = _dereq_('./time-controls/remaining-time-display.js'); | ||
4671 | |||
4672 | var _timeControlsRemainingTimeDisplayJs2 = _interopRequireDefault(_timeControlsRemainingTimeDisplayJs); | ||
4673 | |||
4674 | var _liveDisplayJs = _dereq_('./live-display.js'); | ||
4675 | |||
4676 | var _liveDisplayJs2 = _interopRequireDefault(_liveDisplayJs); | ||
4677 | |||
4678 | var _progressControlProgressControlJs = _dereq_('./progress-control/progress-control.js'); | ||
4679 | |||
4680 | var _progressControlProgressControlJs2 = _interopRequireDefault(_progressControlProgressControlJs); | ||
4681 | |||
4682 | var _fullscreenToggleJs = _dereq_('./fullscreen-toggle.js'); | ||
4683 | |||
4684 | var _fullscreenToggleJs2 = _interopRequireDefault(_fullscreenToggleJs); | ||
4685 | |||
4686 | var _volumeControlVolumeControlJs = _dereq_('./volume-control/volume-control.js'); | ||
4687 | |||
4688 | var _volumeControlVolumeControlJs2 = _interopRequireDefault(_volumeControlVolumeControlJs); | ||
4689 | |||
4690 | var _volumeMenuButtonJs = _dereq_('./volume-menu-button.js'); | ||
4691 | |||
4692 | var _volumeMenuButtonJs2 = _interopRequireDefault(_volumeMenuButtonJs); | ||
4693 | |||
4694 | var _muteToggleJs = _dereq_('./mute-toggle.js'); | ||
4695 | |||
4696 | var _muteToggleJs2 = _interopRequireDefault(_muteToggleJs); | ||
4697 | |||
4698 | var _textTrackControlsChaptersButtonJs = _dereq_('./text-track-controls/chapters-button.js'); | ||
4699 | |||
4700 | var _textTrackControlsChaptersButtonJs2 = _interopRequireDefault(_textTrackControlsChaptersButtonJs); | ||
4701 | |||
4702 | var _textTrackControlsSubtitlesButtonJs = _dereq_('./text-track-controls/subtitles-button.js'); | ||
4703 | |||
4704 | var _textTrackControlsSubtitlesButtonJs2 = _interopRequireDefault(_textTrackControlsSubtitlesButtonJs); | ||
4705 | |||
4706 | var _textTrackControlsCaptionsButtonJs = _dereq_('./text-track-controls/captions-button.js'); | ||
4707 | |||
4708 | var _textTrackControlsCaptionsButtonJs2 = _interopRequireDefault(_textTrackControlsCaptionsButtonJs); | ||
4709 | |||
4710 | var _playbackRateMenuPlaybackRateMenuButtonJs = _dereq_('./playback-rate-menu/playback-rate-menu-button.js'); | ||
4711 | |||
4712 | var _playbackRateMenuPlaybackRateMenuButtonJs2 = _interopRequireDefault(_playbackRateMenuPlaybackRateMenuButtonJs); | ||
4713 | |||
4714 | var _spacerControlsCustomControlSpacerJs = _dereq_('./spacer-controls/custom-control-spacer.js'); | ||
4715 | |||
4716 | var _spacerControlsCustomControlSpacerJs2 = _interopRequireDefault(_spacerControlsCustomControlSpacerJs); | ||
4717 | |||
4718 | /** | ||
4719 | * Container of main controls | ||
4720 | * | ||
4721 | * @extends Component | ||
4722 | * @class ControlBar | ||
4723 | */ | ||
4724 | |||
4725 | var ControlBar = (function (_Component) { | ||
4726 | _inherits(ControlBar, _Component); | ||
4727 | |||
4728 | function ControlBar() { | ||
4729 | _classCallCheck(this, ControlBar); | ||
4730 | |||
4731 | _Component.apply(this, arguments); | ||
4732 | } | ||
4733 | |||
4734 | /** | ||
4735 | * Create the component's DOM element | ||
4736 | * | ||
4737 | * @return {Element} | ||
4738 | * @method createEl | ||
4739 | */ | ||
4740 | |||
4741 | ControlBar.prototype.createEl = function createEl() { | ||
4742 | return _Component.prototype.createEl.call(this, 'div', { | ||
4743 | className: 'vjs-control-bar', | ||
4744 | dir: 'ltr' | ||
4745 | }, { | ||
4746 | 'role': 'group' // The control bar is a group, so it can contain menuitems | ||
4747 | }); | ||
4748 | }; | ||
4749 | |||
4750 | return ControlBar; | ||
4751 | })(_componentJs2['default']); | ||
4752 | |||
4753 | ControlBar.prototype.options_ = { | ||
4754 | loadEvent: 'play', | ||
4755 | children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'subtitlesButton', 'captionsButton', 'fullscreenToggle'] | ||
4756 | }; | ||
4757 | |||
4758 | _componentJs2['default'].registerComponent('ControlBar', ControlBar); | ||
4759 | exports['default'] = ControlBar; | ||
4760 | module.exports = exports['default']; | ||
4761 | |||
4762 | },{"../component.js":67,"./fullscreen-toggle.js":69,"./live-display.js":70,"./mute-toggle.js":71,"./play-toggle.js":72,"./playback-rate-menu/playback-rate-menu-button.js":73,"./progress-control/progress-control.js":78,"./spacer-controls/custom-control-spacer.js":80,"./text-track-controls/captions-button.js":83,"./text-track-controls/chapters-button.js":84,"./text-track-controls/subtitles-button.js":87,"./time-controls/current-time-display.js":90,"./time-controls/duration-display.js":91,"./time-controls/remaining-time-display.js":92,"./time-controls/time-divider.js":93,"./volume-control/volume-control.js":95,"./volume-menu-button.js":97}],69:[function(_dereq_,module,exports){ | ||
4763 | /** | ||
4764 | * @file fullscreen-toggle.js | ||
4765 | */ | ||
4766 | 'use strict'; | ||
4767 | |||
4768 | exports.__esModule = true; | ||
4769 | |||
4770 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
4771 | |||
4772 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
4773 | |||
4774 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
4775 | |||
4776 | var _buttonJs = _dereq_('../button.js'); | ||
4777 | |||
4778 | var _buttonJs2 = _interopRequireDefault(_buttonJs); | ||
4779 | |||
4780 | var _componentJs = _dereq_('../component.js'); | ||
4781 | |||
4782 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
4783 | |||
4784 | /** | ||
4785 | * Toggle fullscreen video | ||
4786 | * | ||
4787 | * @extends Button | ||
4788 | * @class FullscreenToggle | ||
4789 | */ | ||
4790 | |||
4791 | var FullscreenToggle = (function (_Button) { | ||
4792 | _inherits(FullscreenToggle, _Button); | ||
4793 | |||
4794 | function FullscreenToggle() { | ||
4795 | _classCallCheck(this, FullscreenToggle); | ||
4796 | |||
4797 | _Button.apply(this, arguments); | ||
4798 | } | ||
4799 | |||
4800 | /** | ||
4801 | * Allow sub components to stack CSS class names | ||
4802 | * | ||
4803 | * @return {String} The constructed class name | ||
4804 | * @method buildCSSClass | ||
4805 | */ | ||
4806 | |||
4807 | FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() { | ||
4808 | return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this); | ||
4809 | }; | ||
4810 | |||
4811 | /** | ||
4812 | * Handles click for full screen | ||
4813 | * | ||
4814 | * @method handleClick | ||
4815 | */ | ||
4816 | |||
4817 | FullscreenToggle.prototype.handleClick = function handleClick() { | ||
4818 | if (!this.player_.isFullscreen()) { | ||
4819 | this.player_.requestFullscreen(); | ||
4820 | this.controlText('Non-Fullscreen'); | ||
4821 | } else { | ||
4822 | this.player_.exitFullscreen(); | ||
4823 | this.controlText('Fullscreen'); | ||
4824 | } | ||
4825 | }; | ||
4826 | |||
4827 | return FullscreenToggle; | ||
4828 | })(_buttonJs2['default']); | ||
4829 | |||
4830 | FullscreenToggle.prototype.controlText_ = 'Fullscreen'; | ||
4831 | |||
4832 | _componentJs2['default'].registerComponent('FullscreenToggle', FullscreenToggle); | ||
4833 | exports['default'] = FullscreenToggle; | ||
4834 | module.exports = exports['default']; | ||
4835 | |||
4836 | },{"../button.js":64,"../component.js":67}],70:[function(_dereq_,module,exports){ | ||
4837 | /** | ||
4838 | * @file live-display.js | ||
4839 | */ | ||
4840 | 'use strict'; | ||
4841 | |||
4842 | exports.__esModule = true; | ||
4843 | |||
4844 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
4845 | |||
4846 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
4847 | |||
4848 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
4849 | |||
4850 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
4851 | |||
4852 | var _component = _dereq_('../component'); | ||
4853 | |||
4854 | var _component2 = _interopRequireDefault(_component); | ||
4855 | |||
4856 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
4857 | |||
4858 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
4859 | |||
4860 | /** | ||
4861 | * Displays the live indicator | ||
4862 | * TODO - Future make it click to snap to live | ||
4863 | * | ||
4864 | * @extends Component | ||
4865 | * @class LiveDisplay | ||
4866 | */ | ||
4867 | |||
4868 | var LiveDisplay = (function (_Component) { | ||
4869 | _inherits(LiveDisplay, _Component); | ||
4870 | |||
4871 | function LiveDisplay(player, options) { | ||
4872 | _classCallCheck(this, LiveDisplay); | ||
4873 | |||
4874 | _Component.call(this, player, options); | ||
4875 | |||
4876 | this.updateShowing(); | ||
4877 | this.on(this.player(), 'durationchange', this.updateShowing); | ||
4878 | } | ||
4879 | |||
4880 | /** | ||
4881 | * Create the component's DOM element | ||
4882 | * | ||
4883 | * @return {Element} | ||
4884 | * @method createEl | ||
4885 | */ | ||
4886 | |||
4887 | LiveDisplay.prototype.createEl = function createEl() { | ||
4888 | var el = _Component.prototype.createEl.call(this, 'div', { | ||
4889 | className: 'vjs-live-control vjs-control' | ||
4890 | }); | ||
4891 | |||
4892 | this.contentEl_ = Dom.createEl('div', { | ||
4893 | className: 'vjs-live-display', | ||
4894 | innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '</span>' + this.localize('LIVE') | ||
4895 | }, { | ||
4896 | 'aria-live': 'off' | ||
4897 | }); | ||
4898 | |||
4899 | el.appendChild(this.contentEl_); | ||
4900 | return el; | ||
4901 | }; | ||
4902 | |||
4903 | LiveDisplay.prototype.updateShowing = function updateShowing() { | ||
4904 | if (this.player().duration() === Infinity) { | ||
4905 | this.show(); | ||
4906 | } else { | ||
4907 | this.hide(); | ||
4908 | } | ||
4909 | }; | ||
4910 | |||
4911 | return LiveDisplay; | ||
4912 | })(_component2['default']); | ||
4913 | |||
4914 | _component2['default'].registerComponent('LiveDisplay', LiveDisplay); | ||
4915 | exports['default'] = LiveDisplay; | ||
4916 | module.exports = exports['default']; | ||
4917 | |||
4918 | },{"../component":67,"../utils/dom.js":132}],71:[function(_dereq_,module,exports){ | ||
4919 | /** | ||
4920 | * @file mute-toggle.js | ||
4921 | */ | ||
4922 | 'use strict'; | ||
4923 | |||
4924 | exports.__esModule = true; | ||
4925 | |||
4926 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
4927 | |||
4928 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
4929 | |||
4930 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
4931 | |||
4932 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
4933 | |||
4934 | var _button = _dereq_('../button'); | ||
4935 | |||
4936 | var _button2 = _interopRequireDefault(_button); | ||
4937 | |||
4938 | var _component = _dereq_('../component'); | ||
4939 | |||
4940 | var _component2 = _interopRequireDefault(_component); | ||
4941 | |||
4942 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
4943 | |||
4944 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
4945 | |||
4946 | /** | ||
4947 | * A button component for muting the audio | ||
4948 | * | ||
4949 | * @param {Player|Object} player | ||
4950 | * @param {Object=} options | ||
4951 | * @extends Button | ||
4952 | * @class MuteToggle | ||
4953 | */ | ||
4954 | |||
4955 | var MuteToggle = (function (_Button) { | ||
4956 | _inherits(MuteToggle, _Button); | ||
4957 | |||
4958 | function MuteToggle(player, options) { | ||
4959 | _classCallCheck(this, MuteToggle); | ||
4960 | |||
4961 | _Button.call(this, player, options); | ||
4962 | |||
4963 | this.on(player, 'volumechange', this.update); | ||
4964 | |||
4965 | // hide mute toggle if the current tech doesn't support volume control | ||
4966 | if (player.tech_ && player.tech_['featuresVolumeControl'] === false) { | ||
4967 | this.addClass('vjs-hidden'); | ||
4968 | } | ||
4969 | |||
4970 | this.on(player, 'loadstart', function () { | ||
4971 | this.update(); // We need to update the button to account for a default muted state. | ||
4972 | |||
4973 | if (player.tech_['featuresVolumeControl'] === false) { | ||
4974 | this.addClass('vjs-hidden'); | ||
4975 | } else { | ||
4976 | this.removeClass('vjs-hidden'); | ||
4977 | } | ||
4978 | }); | ||
4979 | } | ||
4980 | |||
4981 | /** | ||
4982 | * Allow sub components to stack CSS class names | ||
4983 | * | ||
4984 | * @return {String} The constructed class name | ||
4985 | * @method buildCSSClass | ||
4986 | */ | ||
4987 | |||
4988 | MuteToggle.prototype.buildCSSClass = function buildCSSClass() { | ||
4989 | return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this); | ||
4990 | }; | ||
4991 | |||
4992 | /** | ||
4993 | * Handle click on mute | ||
4994 | * | ||
4995 | * @method handleClick | ||
4996 | */ | ||
4997 | |||
4998 | MuteToggle.prototype.handleClick = function handleClick() { | ||
4999 | this.player_.muted(this.player_.muted() ? false : true); | ||
5000 | }; | ||
5001 | |||
5002 | /** | ||
5003 | * Update volume | ||
5004 | * | ||
5005 | * @method update | ||
5006 | */ | ||
5007 | |||
5008 | MuteToggle.prototype.update = function update() { | ||
5009 | var vol = this.player_.volume(), | ||
5010 | level = 3; | ||
5011 | |||
5012 | if (vol === 0 || this.player_.muted()) { | ||
5013 | level = 0; | ||
5014 | } else if (vol < 0.33) { | ||
5015 | level = 1; | ||
5016 | } else if (vol < 0.67) { | ||
5017 | level = 2; | ||
5018 | } | ||
5019 | |||
5020 | // Don't rewrite the button text if the actual text doesn't change. | ||
5021 | // This causes unnecessary and confusing information for screen reader users. | ||
5022 | // This check is needed because this function gets called every time the volume level is changed. | ||
5023 | var toMute = this.player_.muted() ? 'Unmute' : 'Mute'; | ||
5024 | if (this.controlText() !== toMute) { | ||
5025 | this.controlText(toMute); | ||
5026 | } | ||
5027 | |||
5028 | /* TODO improve muted icon classes */ | ||
5029 | for (var i = 0; i < 4; i++) { | ||
5030 | Dom.removeElClass(this.el_, 'vjs-vol-' + i); | ||
5031 | } | ||
5032 | Dom.addElClass(this.el_, 'vjs-vol-' + level); | ||
5033 | }; | ||
5034 | |||
5035 | return MuteToggle; | ||
5036 | })(_button2['default']); | ||
5037 | |||
5038 | MuteToggle.prototype.controlText_ = 'Mute'; | ||
5039 | |||
5040 | _component2['default'].registerComponent('MuteToggle', MuteToggle); | ||
5041 | exports['default'] = MuteToggle; | ||
5042 | module.exports = exports['default']; | ||
5043 | |||
5044 | },{"../button":64,"../component":67,"../utils/dom.js":132}],72:[function(_dereq_,module,exports){ | ||
5045 | /** | ||
5046 | * @file play-toggle.js | ||
5047 | */ | ||
5048 | 'use strict'; | ||
5049 | |||
5050 | exports.__esModule = true; | ||
5051 | |||
5052 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5053 | |||
5054 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5055 | |||
5056 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5057 | |||
5058 | var _buttonJs = _dereq_('../button.js'); | ||
5059 | |||
5060 | var _buttonJs2 = _interopRequireDefault(_buttonJs); | ||
5061 | |||
5062 | var _componentJs = _dereq_('../component.js'); | ||
5063 | |||
5064 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5065 | |||
5066 | /** | ||
5067 | * Button to toggle between play and pause | ||
5068 | * | ||
5069 | * @param {Player|Object} player | ||
5070 | * @param {Object=} options | ||
5071 | * @extends Button | ||
5072 | * @class PlayToggle | ||
5073 | */ | ||
5074 | |||
5075 | var PlayToggle = (function (_Button) { | ||
5076 | _inherits(PlayToggle, _Button); | ||
5077 | |||
5078 | function PlayToggle(player, options) { | ||
5079 | _classCallCheck(this, PlayToggle); | ||
5080 | |||
5081 | _Button.call(this, player, options); | ||
5082 | |||
5083 | this.on(player, 'play', this.handlePlay); | ||
5084 | this.on(player, 'pause', this.handlePause); | ||
5085 | } | ||
5086 | |||
5087 | /** | ||
5088 | * Allow sub components to stack CSS class names | ||
5089 | * | ||
5090 | * @return {String} The constructed class name | ||
5091 | * @method buildCSSClass | ||
5092 | */ | ||
5093 | |||
5094 | PlayToggle.prototype.buildCSSClass = function buildCSSClass() { | ||
5095 | return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this); | ||
5096 | }; | ||
5097 | |||
5098 | /** | ||
5099 | * Handle click to toggle between play and pause | ||
5100 | * | ||
5101 | * @method handleClick | ||
5102 | */ | ||
5103 | |||
5104 | PlayToggle.prototype.handleClick = function handleClick() { | ||
5105 | if (this.player_.paused()) { | ||
5106 | this.player_.play(); | ||
5107 | } else { | ||
5108 | this.player_.pause(); | ||
5109 | } | ||
5110 | }; | ||
5111 | |||
5112 | /** | ||
5113 | * Add the vjs-playing class to the element so it can change appearance | ||
5114 | * | ||
5115 | * @method handlePlay | ||
5116 | */ | ||
5117 | |||
5118 | PlayToggle.prototype.handlePlay = function handlePlay() { | ||
5119 | this.removeClass('vjs-paused'); | ||
5120 | this.addClass('vjs-playing'); | ||
5121 | this.controlText('Pause'); // change the button text to "Pause" | ||
5122 | }; | ||
5123 | |||
5124 | /** | ||
5125 | * Add the vjs-paused class to the element so it can change appearance | ||
5126 | * | ||
5127 | * @method handlePause | ||
5128 | */ | ||
5129 | |||
5130 | PlayToggle.prototype.handlePause = function handlePause() { | ||
5131 | this.removeClass('vjs-playing'); | ||
5132 | this.addClass('vjs-paused'); | ||
5133 | this.controlText('Play'); // change the button text to "Play" | ||
5134 | }; | ||
5135 | |||
5136 | return PlayToggle; | ||
5137 | })(_buttonJs2['default']); | ||
5138 | |||
5139 | PlayToggle.prototype.controlText_ = 'Play'; | ||
5140 | |||
5141 | _componentJs2['default'].registerComponent('PlayToggle', PlayToggle); | ||
5142 | exports['default'] = PlayToggle; | ||
5143 | module.exports = exports['default']; | ||
5144 | |||
5145 | },{"../button.js":64,"../component.js":67}],73:[function(_dereq_,module,exports){ | ||
5146 | /** | ||
5147 | * @file playback-rate-menu-button.js | ||
5148 | */ | ||
5149 | 'use strict'; | ||
5150 | |||
5151 | exports.__esModule = true; | ||
5152 | |||
5153 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
5154 | |||
5155 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5156 | |||
5157 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5158 | |||
5159 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5160 | |||
5161 | var _menuMenuButtonJs = _dereq_('../../menu/menu-button.js'); | ||
5162 | |||
5163 | var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); | ||
5164 | |||
5165 | var _menuMenuJs = _dereq_('../../menu/menu.js'); | ||
5166 | |||
5167 | var _menuMenuJs2 = _interopRequireDefault(_menuMenuJs); | ||
5168 | |||
5169 | var _playbackRateMenuItemJs = _dereq_('./playback-rate-menu-item.js'); | ||
5170 | |||
5171 | var _playbackRateMenuItemJs2 = _interopRequireDefault(_playbackRateMenuItemJs); | ||
5172 | |||
5173 | var _componentJs = _dereq_('../../component.js'); | ||
5174 | |||
5175 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5176 | |||
5177 | var _utilsDomJs = _dereq_('../../utils/dom.js'); | ||
5178 | |||
5179 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
5180 | |||
5181 | /** | ||
5182 | * The component for controlling the playback rate | ||
5183 | * | ||
5184 | * @param {Player|Object} player | ||
5185 | * @param {Object=} options | ||
5186 | * @extends MenuButton | ||
5187 | * @class PlaybackRateMenuButton | ||
5188 | */ | ||
5189 | |||
5190 | var PlaybackRateMenuButton = (function (_MenuButton) { | ||
5191 | _inherits(PlaybackRateMenuButton, _MenuButton); | ||
5192 | |||
5193 | function PlaybackRateMenuButton(player, options) { | ||
5194 | _classCallCheck(this, PlaybackRateMenuButton); | ||
5195 | |||
5196 | _MenuButton.call(this, player, options); | ||
5197 | |||
5198 | this.updateVisibility(); | ||
5199 | this.updateLabel(); | ||
5200 | |||
5201 | this.on(player, 'loadstart', this.updateVisibility); | ||
5202 | this.on(player, 'ratechange', this.updateLabel); | ||
5203 | } | ||
5204 | |||
5205 | /** | ||
5206 | * Create the component's DOM element | ||
5207 | * | ||
5208 | * @return {Element} | ||
5209 | * @method createEl | ||
5210 | */ | ||
5211 | |||
5212 | PlaybackRateMenuButton.prototype.createEl = function createEl() { | ||
5213 | var el = _MenuButton.prototype.createEl.call(this); | ||
5214 | |||
5215 | this.labelEl_ = Dom.createEl('div', { | ||
5216 | className: 'vjs-playback-rate-value', | ||
5217 | innerHTML: 1.0 | ||
5218 | }); | ||
5219 | |||
5220 | el.appendChild(this.labelEl_); | ||
5221 | |||
5222 | return el; | ||
5223 | }; | ||
5224 | |||
5225 | /** | ||
5226 | * Allow sub components to stack CSS class names | ||
5227 | * | ||
5228 | * @return {String} The constructed class name | ||
5229 | * @method buildCSSClass | ||
5230 | */ | ||
5231 | |||
5232 | PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() { | ||
5233 | return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this); | ||
5234 | }; | ||
5235 | |||
5236 | /** | ||
5237 | * Create the playback rate menu | ||
5238 | * | ||
5239 | * @return {Menu} Menu object populated with items | ||
5240 | * @method createMenu | ||
5241 | */ | ||
5242 | |||
5243 | PlaybackRateMenuButton.prototype.createMenu = function createMenu() { | ||
5244 | var menu = new _menuMenuJs2['default'](this.player()); | ||
5245 | var rates = this.playbackRates(); | ||
5246 | |||
5247 | if (rates) { | ||
5248 | for (var i = rates.length - 1; i >= 0; i--) { | ||
5249 | menu.addChild(new _playbackRateMenuItemJs2['default'](this.player(), { 'rate': rates[i] + 'x' })); | ||
5250 | } | ||
5251 | } | ||
5252 | |||
5253 | return menu; | ||
5254 | }; | ||
5255 | |||
5256 | /** | ||
5257 | * Updates ARIA accessibility attributes | ||
5258 | * | ||
5259 | * @method updateARIAAttributes | ||
5260 | */ | ||
5261 | |||
5262 | PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() { | ||
5263 | // Current playback rate | ||
5264 | this.el().setAttribute('aria-valuenow', this.player().playbackRate()); | ||
5265 | }; | ||
5266 | |||
5267 | /** | ||
5268 | * Handle menu item click | ||
5269 | * | ||
5270 | * @method handleClick | ||
5271 | */ | ||
5272 | |||
5273 | PlaybackRateMenuButton.prototype.handleClick = function handleClick() { | ||
5274 | // select next rate option | ||
5275 | var currentRate = this.player().playbackRate(); | ||
5276 | var rates = this.playbackRates(); | ||
5277 | |||
5278 | // this will select first one if the last one currently selected | ||
5279 | var newRate = rates[0]; | ||
5280 | for (var i = 0; i < rates.length; i++) { | ||
5281 | if (rates[i] > currentRate) { | ||
5282 | newRate = rates[i]; | ||
5283 | break; | ||
5284 | } | ||
5285 | } | ||
5286 | this.player().playbackRate(newRate); | ||
5287 | }; | ||
5288 | |||
5289 | /** | ||
5290 | * Get possible playback rates | ||
5291 | * | ||
5292 | * @return {Array} Possible playback rates | ||
5293 | * @method playbackRates | ||
5294 | */ | ||
5295 | |||
5296 | PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() { | ||
5297 | return this.options_['playbackRates'] || this.options_.playerOptions && this.options_.playerOptions['playbackRates']; | ||
5298 | }; | ||
5299 | |||
5300 | /** | ||
5301 | * Get supported playback rates | ||
5302 | * | ||
5303 | * @return {Array} Supported playback rates | ||
5304 | * @method playbackRateSupported | ||
5305 | */ | ||
5306 | |||
5307 | PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() { | ||
5308 | return this.player().tech_ && this.player().tech_['featuresPlaybackRate'] && this.playbackRates() && this.playbackRates().length > 0; | ||
5309 | }; | ||
5310 | |||
5311 | /** | ||
5312 | * Hide playback rate controls when they're no playback rate options to select | ||
5313 | * | ||
5314 | * @method updateVisibility | ||
5315 | */ | ||
5316 | |||
5317 | PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility() { | ||
5318 | if (this.playbackRateSupported()) { | ||
5319 | this.removeClass('vjs-hidden'); | ||
5320 | } else { | ||
5321 | this.addClass('vjs-hidden'); | ||
5322 | } | ||
5323 | }; | ||
5324 | |||
5325 | /** | ||
5326 | * Update button label when rate changed | ||
5327 | * | ||
5328 | * @method updateLabel | ||
5329 | */ | ||
5330 | |||
5331 | PlaybackRateMenuButton.prototype.updateLabel = function updateLabel() { | ||
5332 | if (this.playbackRateSupported()) { | ||
5333 | this.labelEl_.innerHTML = this.player().playbackRate() + 'x'; | ||
5334 | } | ||
5335 | }; | ||
5336 | |||
5337 | return PlaybackRateMenuButton; | ||
5338 | })(_menuMenuButtonJs2['default']); | ||
5339 | |||
5340 | PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate'; | ||
5341 | |||
5342 | _componentJs2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton); | ||
5343 | exports['default'] = PlaybackRateMenuButton; | ||
5344 | module.exports = exports['default']; | ||
5345 | |||
5346 | },{"../../component.js":67,"../../menu/menu-button.js":104,"../../menu/menu.js":106,"../../utils/dom.js":132,"./playback-rate-menu-item.js":74}],74:[function(_dereq_,module,exports){ | ||
5347 | /** | ||
5348 | * @file playback-rate-menu-item.js | ||
5349 | */ | ||
5350 | 'use strict'; | ||
5351 | |||
5352 | exports.__esModule = true; | ||
5353 | |||
5354 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5355 | |||
5356 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5357 | |||
5358 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5359 | |||
5360 | var _menuMenuItemJs = _dereq_('../../menu/menu-item.js'); | ||
5361 | |||
5362 | var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); | ||
5363 | |||
5364 | var _componentJs = _dereq_('../../component.js'); | ||
5365 | |||
5366 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5367 | |||
5368 | /** | ||
5369 | * The specific menu item type for selecting a playback rate | ||
5370 | * | ||
5371 | * @param {Player|Object} player | ||
5372 | * @param {Object=} options | ||
5373 | * @extends MenuItem | ||
5374 | * @class PlaybackRateMenuItem | ||
5375 | */ | ||
5376 | |||
5377 | var PlaybackRateMenuItem = (function (_MenuItem) { | ||
5378 | _inherits(PlaybackRateMenuItem, _MenuItem); | ||
5379 | |||
5380 | function PlaybackRateMenuItem(player, options) { | ||
5381 | _classCallCheck(this, PlaybackRateMenuItem); | ||
5382 | |||
5383 | var label = options['rate']; | ||
5384 | var rate = parseFloat(label, 10); | ||
5385 | |||
5386 | // Modify options for parent MenuItem class's init. | ||
5387 | options['label'] = label; | ||
5388 | options['selected'] = rate === 1; | ||
5389 | _MenuItem.call(this, player, options); | ||
5390 | |||
5391 | this.label = label; | ||
5392 | this.rate = rate; | ||
5393 | |||
5394 | this.on(player, 'ratechange', this.update); | ||
5395 | } | ||
5396 | |||
5397 | /** | ||
5398 | * Handle click on menu item | ||
5399 | * | ||
5400 | * @method handleClick | ||
5401 | */ | ||
5402 | |||
5403 | PlaybackRateMenuItem.prototype.handleClick = function handleClick() { | ||
5404 | _MenuItem.prototype.handleClick.call(this); | ||
5405 | this.player().playbackRate(this.rate); | ||
5406 | }; | ||
5407 | |||
5408 | /** | ||
5409 | * Update playback rate with selected rate | ||
5410 | * | ||
5411 | * @method update | ||
5412 | */ | ||
5413 | |||
5414 | PlaybackRateMenuItem.prototype.update = function update() { | ||
5415 | this.selected(this.player().playbackRate() === this.rate); | ||
5416 | }; | ||
5417 | |||
5418 | return PlaybackRateMenuItem; | ||
5419 | })(_menuMenuItemJs2['default']); | ||
5420 | |||
5421 | PlaybackRateMenuItem.prototype.contentElType = 'button'; | ||
5422 | |||
5423 | _componentJs2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem); | ||
5424 | exports['default'] = PlaybackRateMenuItem; | ||
5425 | module.exports = exports['default']; | ||
5426 | |||
5427 | },{"../../component.js":67,"../../menu/menu-item.js":105}],75:[function(_dereq_,module,exports){ | ||
5428 | /** | ||
5429 | * @file load-progress-bar.js | ||
5430 | */ | ||
5431 | 'use strict'; | ||
5432 | |||
5433 | exports.__esModule = true; | ||
5434 | |||
5435 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
5436 | |||
5437 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5438 | |||
5439 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5440 | |||
5441 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5442 | |||
5443 | var _componentJs = _dereq_('../../component.js'); | ||
5444 | |||
5445 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5446 | |||
5447 | var _utilsDomJs = _dereq_('../../utils/dom.js'); | ||
5448 | |||
5449 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
5450 | |||
5451 | /** | ||
5452 | * Shows load progress | ||
5453 | * | ||
5454 | * @param {Player|Object} player | ||
5455 | * @param {Object=} options | ||
5456 | * @extends Component | ||
5457 | * @class LoadProgressBar | ||
5458 | */ | ||
5459 | |||
5460 | var LoadProgressBar = (function (_Component) { | ||
5461 | _inherits(LoadProgressBar, _Component); | ||
5462 | |||
5463 | function LoadProgressBar(player, options) { | ||
5464 | _classCallCheck(this, LoadProgressBar); | ||
5465 | |||
5466 | _Component.call(this, player, options); | ||
5467 | this.on(player, 'progress', this.update); | ||
5468 | } | ||
5469 | |||
5470 | /** | ||
5471 | * Create the component's DOM element | ||
5472 | * | ||
5473 | * @return {Element} | ||
5474 | * @method createEl | ||
5475 | */ | ||
5476 | |||
5477 | LoadProgressBar.prototype.createEl = function createEl() { | ||
5478 | return _Component.prototype.createEl.call(this, 'div', { | ||
5479 | className: 'vjs-load-progress', | ||
5480 | innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Loaded') + '</span>: 0%</span>' | ||
5481 | }); | ||
5482 | }; | ||
5483 | |||
5484 | /** | ||
5485 | * Update progress bar | ||
5486 | * | ||
5487 | * @method update | ||
5488 | */ | ||
5489 | |||
5490 | LoadProgressBar.prototype.update = function update() { | ||
5491 | var buffered = this.player_.buffered(); | ||
5492 | var duration = this.player_.duration(); | ||
5493 | var bufferedEnd = this.player_.bufferedEnd(); | ||
5494 | var children = this.el_.children; | ||
5495 | |||
5496 | // get the percent width of a time compared to the total end | ||
5497 | var percentify = function percentify(time, end) { | ||
5498 | var percent = time / end || 0; // no NaN | ||
5499 | return (percent >= 1 ? 1 : percent) * 100 + '%'; | ||
5500 | }; | ||
5501 | |||
5502 | // update the width of the progress bar | ||
5503 | this.el_.style.width = percentify(bufferedEnd, duration); | ||
5504 | |||
5505 | // add child elements to represent the individual buffered time ranges | ||
5506 | for (var i = 0; i < buffered.length; i++) { | ||
5507 | var start = buffered.start(i); | ||
5508 | var end = buffered.end(i); | ||
5509 | var part = children[i]; | ||
5510 | |||
5511 | if (!part) { | ||
5512 | part = this.el_.appendChild(Dom.createEl()); | ||
5513 | } | ||
5514 | |||
5515 | // set the percent based on the width of the progress bar (bufferedEnd) | ||
5516 | part.style.left = percentify(start, bufferedEnd); | ||
5517 | part.style.width = percentify(end - start, bufferedEnd); | ||
5518 | } | ||
5519 | |||
5520 | // remove unused buffered range elements | ||
5521 | for (var i = children.length; i > buffered.length; i--) { | ||
5522 | this.el_.removeChild(children[i - 1]); | ||
5523 | } | ||
5524 | }; | ||
5525 | |||
5526 | return LoadProgressBar; | ||
5527 | })(_componentJs2['default']); | ||
5528 | |||
5529 | _componentJs2['default'].registerComponent('LoadProgressBar', LoadProgressBar); | ||
5530 | exports['default'] = LoadProgressBar; | ||
5531 | module.exports = exports['default']; | ||
5532 | |||
5533 | },{"../../component.js":67,"../../utils/dom.js":132}],76:[function(_dereq_,module,exports){ | ||
5534 | /** | ||
5535 | * @file mouse-time-display.js | ||
5536 | */ | ||
5537 | 'use strict'; | ||
5538 | |||
5539 | exports.__esModule = true; | ||
5540 | |||
5541 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
5542 | |||
5543 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5544 | |||
5545 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5546 | |||
5547 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5548 | |||
5549 | var _componentJs = _dereq_('../../component.js'); | ||
5550 | |||
5551 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5552 | |||
5553 | var _utilsDomJs = _dereq_('../../utils/dom.js'); | ||
5554 | |||
5555 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
5556 | |||
5557 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
5558 | |||
5559 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
5560 | |||
5561 | var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); | ||
5562 | |||
5563 | var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); | ||
5564 | |||
5565 | var _lodashCompatFunctionThrottle = _dereq_('lodash-compat/function/throttle'); | ||
5566 | |||
5567 | var _lodashCompatFunctionThrottle2 = _interopRequireDefault(_lodashCompatFunctionThrottle); | ||
5568 | |||
5569 | /** | ||
5570 | * The Mouse Time Display component shows the time you will seek to | ||
5571 | * when hovering over the progress bar | ||
5572 | * | ||
5573 | * @param {Player|Object} player | ||
5574 | * @param {Object=} options | ||
5575 | * @extends Component | ||
5576 | * @class MouseTimeDisplay | ||
5577 | */ | ||
5578 | |||
5579 | var MouseTimeDisplay = (function (_Component) { | ||
5580 | _inherits(MouseTimeDisplay, _Component); | ||
5581 | |||
5582 | function MouseTimeDisplay(player, options) { | ||
5583 | var _this = this; | ||
5584 | |||
5585 | _classCallCheck(this, MouseTimeDisplay); | ||
5586 | |||
5587 | _Component.call(this, player, options); | ||
5588 | |||
5589 | this.update(0, 0); | ||
5590 | |||
5591 | player.on('ready', function () { | ||
5592 | _this.on(player.controlBar.progressControl.el(), 'mousemove', _lodashCompatFunctionThrottle2['default'](Fn.bind(_this, _this.handleMouseMove), 25)); | ||
5593 | }); | ||
5594 | } | ||
5595 | |||
5596 | /** | ||
5597 | * Create the component's DOM element | ||
5598 | * | ||
5599 | * @return {Element} | ||
5600 | * @method createEl | ||
5601 | */ | ||
5602 | |||
5603 | MouseTimeDisplay.prototype.createEl = function createEl() { | ||
5604 | return _Component.prototype.createEl.call(this, 'div', { | ||
5605 | className: 'vjs-mouse-display' | ||
5606 | }); | ||
5607 | }; | ||
5608 | |||
5609 | MouseTimeDisplay.prototype.handleMouseMove = function handleMouseMove(event) { | ||
5610 | var duration = this.player_.duration(); | ||
5611 | var newTime = this.calculateDistance(event) * duration; | ||
5612 | var position = event.pageX - Dom.findElPosition(this.el().parentNode).left; | ||
5613 | |||
5614 | this.update(newTime, position); | ||
5615 | }; | ||
5616 | |||
5617 | MouseTimeDisplay.prototype.update = function update(newTime, position) { | ||
5618 | var time = _utilsFormatTimeJs2['default'](newTime, this.player_.duration()); | ||
5619 | |||
5620 | this.el().style.left = position + 'px'; | ||
5621 | this.el().setAttribute('data-current-time', time); | ||
5622 | }; | ||
5623 | |||
5624 | MouseTimeDisplay.prototype.calculateDistance = function calculateDistance(event) { | ||
5625 | return Dom.getPointerPosition(this.el().parentNode, event).x; | ||
5626 | }; | ||
5627 | |||
5628 | return MouseTimeDisplay; | ||
5629 | })(_componentJs2['default']); | ||
5630 | |||
5631 | _componentJs2['default'].registerComponent('MouseTimeDisplay', MouseTimeDisplay); | ||
5632 | exports['default'] = MouseTimeDisplay; | ||
5633 | module.exports = exports['default']; | ||
5634 | |||
5635 | },{"../../component.js":67,"../../utils/dom.js":132,"../../utils/fn.js":134,"../../utils/format-time.js":135,"lodash-compat/function/throttle":7}],77:[function(_dereq_,module,exports){ | ||
5636 | /** | ||
5637 | * @file play-progress-bar.js | ||
5638 | */ | ||
5639 | 'use strict'; | ||
5640 | |||
5641 | exports.__esModule = true; | ||
5642 | |||
5643 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
5644 | |||
5645 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5646 | |||
5647 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5648 | |||
5649 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5650 | |||
5651 | var _componentJs = _dereq_('../../component.js'); | ||
5652 | |||
5653 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5654 | |||
5655 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
5656 | |||
5657 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
5658 | |||
5659 | var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); | ||
5660 | |||
5661 | var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); | ||
5662 | |||
5663 | /** | ||
5664 | * Shows play progress | ||
5665 | * | ||
5666 | * @param {Player|Object} player | ||
5667 | * @param {Object=} options | ||
5668 | * @extends Component | ||
5669 | * @class PlayProgressBar | ||
5670 | */ | ||
5671 | |||
5672 | var PlayProgressBar = (function (_Component) { | ||
5673 | _inherits(PlayProgressBar, _Component); | ||
5674 | |||
5675 | function PlayProgressBar(player, options) { | ||
5676 | _classCallCheck(this, PlayProgressBar); | ||
5677 | |||
5678 | _Component.call(this, player, options); | ||
5679 | this.updateDataAttr(); | ||
5680 | this.on(player, 'timeupdate', this.updateDataAttr); | ||
5681 | player.ready(Fn.bind(this, this.updateDataAttr)); | ||
5682 | } | ||
5683 | |||
5684 | /** | ||
5685 | * Create the component's DOM element | ||
5686 | * | ||
5687 | * @return {Element} | ||
5688 | * @method createEl | ||
5689 | */ | ||
5690 | |||
5691 | PlayProgressBar.prototype.createEl = function createEl() { | ||
5692 | return _Component.prototype.createEl.call(this, 'div', { | ||
5693 | className: 'vjs-play-progress vjs-slider-bar', | ||
5694 | innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>' | ||
5695 | }); | ||
5696 | }; | ||
5697 | |||
5698 | PlayProgressBar.prototype.updateDataAttr = function updateDataAttr() { | ||
5699 | var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); | ||
5700 | this.el_.setAttribute('data-current-time', _utilsFormatTimeJs2['default'](time, this.player_.duration())); | ||
5701 | }; | ||
5702 | |||
5703 | return PlayProgressBar; | ||
5704 | })(_componentJs2['default']); | ||
5705 | |||
5706 | _componentJs2['default'].registerComponent('PlayProgressBar', PlayProgressBar); | ||
5707 | exports['default'] = PlayProgressBar; | ||
5708 | module.exports = exports['default']; | ||
5709 | |||
5710 | },{"../../component.js":67,"../../utils/fn.js":134,"../../utils/format-time.js":135}],78:[function(_dereq_,module,exports){ | ||
5711 | /** | ||
5712 | * @file progress-control.js | ||
5713 | */ | ||
5714 | 'use strict'; | ||
5715 | |||
5716 | exports.__esModule = true; | ||
5717 | |||
5718 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5719 | |||
5720 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5721 | |||
5722 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5723 | |||
5724 | var _componentJs = _dereq_('../../component.js'); | ||
5725 | |||
5726 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5727 | |||
5728 | var _seekBarJs = _dereq_('./seek-bar.js'); | ||
5729 | |||
5730 | var _seekBarJs2 = _interopRequireDefault(_seekBarJs); | ||
5731 | |||
5732 | var _mouseTimeDisplayJs = _dereq_('./mouse-time-display.js'); | ||
5733 | |||
5734 | var _mouseTimeDisplayJs2 = _interopRequireDefault(_mouseTimeDisplayJs); | ||
5735 | |||
5736 | /** | ||
5737 | * The Progress Control component contains the seek bar, load progress, | ||
5738 | * and play progress | ||
5739 | * | ||
5740 | * @param {Player|Object} player | ||
5741 | * @param {Object=} options | ||
5742 | * @extends Component | ||
5743 | * @class ProgressControl | ||
5744 | */ | ||
5745 | |||
5746 | var ProgressControl = (function (_Component) { | ||
5747 | _inherits(ProgressControl, _Component); | ||
5748 | |||
5749 | function ProgressControl() { | ||
5750 | _classCallCheck(this, ProgressControl); | ||
5751 | |||
5752 | _Component.apply(this, arguments); | ||
5753 | } | ||
5754 | |||
5755 | /** | ||
5756 | * Create the component's DOM element | ||
5757 | * | ||
5758 | * @return {Element} | ||
5759 | * @method createEl | ||
5760 | */ | ||
5761 | |||
5762 | ProgressControl.prototype.createEl = function createEl() { | ||
5763 | return _Component.prototype.createEl.call(this, 'div', { | ||
5764 | className: 'vjs-progress-control vjs-control' | ||
5765 | }); | ||
5766 | }; | ||
5767 | |||
5768 | return ProgressControl; | ||
5769 | })(_componentJs2['default']); | ||
5770 | |||
5771 | ProgressControl.prototype.options_ = { | ||
5772 | children: ['seekBar'] | ||
5773 | }; | ||
5774 | |||
5775 | _componentJs2['default'].registerComponent('ProgressControl', ProgressControl); | ||
5776 | exports['default'] = ProgressControl; | ||
5777 | module.exports = exports['default']; | ||
5778 | |||
5779 | },{"../../component.js":67,"./mouse-time-display.js":76,"./seek-bar.js":79}],79:[function(_dereq_,module,exports){ | ||
5780 | /** | ||
5781 | * @file seek-bar.js | ||
5782 | */ | ||
5783 | 'use strict'; | ||
5784 | |||
5785 | exports.__esModule = true; | ||
5786 | |||
5787 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
5788 | |||
5789 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5790 | |||
5791 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5792 | |||
5793 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5794 | |||
5795 | var _sliderSliderJs = _dereq_('../../slider/slider.js'); | ||
5796 | |||
5797 | var _sliderSliderJs2 = _interopRequireDefault(_sliderSliderJs); | ||
5798 | |||
5799 | var _componentJs = _dereq_('../../component.js'); | ||
5800 | |||
5801 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5802 | |||
5803 | var _loadProgressBarJs = _dereq_('./load-progress-bar.js'); | ||
5804 | |||
5805 | var _loadProgressBarJs2 = _interopRequireDefault(_loadProgressBarJs); | ||
5806 | |||
5807 | var _playProgressBarJs = _dereq_('./play-progress-bar.js'); | ||
5808 | |||
5809 | var _playProgressBarJs2 = _interopRequireDefault(_playProgressBarJs); | ||
5810 | |||
5811 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
5812 | |||
5813 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
5814 | |||
5815 | var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); | ||
5816 | |||
5817 | var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); | ||
5818 | |||
5819 | var _objectAssign = _dereq_('object.assign'); | ||
5820 | |||
5821 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
5822 | |||
5823 | /** | ||
5824 | * Seek Bar and holder for the progress bars | ||
5825 | * | ||
5826 | * @param {Player|Object} player | ||
5827 | * @param {Object=} options | ||
5828 | * @extends Slider | ||
5829 | * @class SeekBar | ||
5830 | */ | ||
5831 | |||
5832 | var SeekBar = (function (_Slider) { | ||
5833 | _inherits(SeekBar, _Slider); | ||
5834 | |||
5835 | function SeekBar(player, options) { | ||
5836 | _classCallCheck(this, SeekBar); | ||
5837 | |||
5838 | _Slider.call(this, player, options); | ||
5839 | this.on(player, 'timeupdate', this.updateARIAAttributes); | ||
5840 | player.ready(Fn.bind(this, this.updateARIAAttributes)); | ||
5841 | } | ||
5842 | |||
5843 | /** | ||
5844 | * Create the component's DOM element | ||
5845 | * | ||
5846 | * @return {Element} | ||
5847 | * @method createEl | ||
5848 | */ | ||
5849 | |||
5850 | SeekBar.prototype.createEl = function createEl() { | ||
5851 | return _Slider.prototype.createEl.call(this, 'div', { | ||
5852 | className: 'vjs-progress-holder' | ||
5853 | }, { | ||
5854 | 'aria-label': 'video progress bar' | ||
5855 | }); | ||
5856 | }; | ||
5857 | |||
5858 | /** | ||
5859 | * Update ARIA accessibility attributes | ||
5860 | * | ||
5861 | * @method updateARIAAttributes | ||
5862 | */ | ||
5863 | |||
5864 | SeekBar.prototype.updateARIAAttributes = function updateARIAAttributes() { | ||
5865 | // Allows for smooth scrubbing, when player can't keep up. | ||
5866 | var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); | ||
5867 | this.el_.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2)); // machine readable value of progress bar (percentage complete) | ||
5868 | this.el_.setAttribute('aria-valuetext', _utilsFormatTimeJs2['default'](time, this.player_.duration())); // human readable value of progress bar (time complete) | ||
5869 | }; | ||
5870 | |||
5871 | /** | ||
5872 | * Get percentage of video played | ||
5873 | * | ||
5874 | * @return {Number} Percentage played | ||
5875 | * @method getPercent | ||
5876 | */ | ||
5877 | |||
5878 | SeekBar.prototype.getPercent = function getPercent() { | ||
5879 | var percent = this.player_.currentTime() / this.player_.duration(); | ||
5880 | return percent >= 1 ? 1 : percent; | ||
5881 | }; | ||
5882 | |||
5883 | /** | ||
5884 | * Handle mouse down on seek bar | ||
5885 | * | ||
5886 | * @method handleMouseDown | ||
5887 | */ | ||
5888 | |||
5889 | SeekBar.prototype.handleMouseDown = function handleMouseDown(event) { | ||
5890 | _Slider.prototype.handleMouseDown.call(this, event); | ||
5891 | |||
5892 | this.player_.scrubbing(true); | ||
5893 | |||
5894 | this.videoWasPlaying = !this.player_.paused(); | ||
5895 | this.player_.pause(); | ||
5896 | }; | ||
5897 | |||
5898 | /** | ||
5899 | * Handle mouse move on seek bar | ||
5900 | * | ||
5901 | * @method handleMouseMove | ||
5902 | */ | ||
5903 | |||
5904 | SeekBar.prototype.handleMouseMove = function handleMouseMove(event) { | ||
5905 | var newTime = this.calculateDistance(event) * this.player_.duration(); | ||
5906 | |||
5907 | // Don't let video end while scrubbing. | ||
5908 | if (newTime === this.player_.duration()) { | ||
5909 | newTime = newTime - 0.1; | ||
5910 | } | ||
5911 | |||
5912 | // Set new time (tell player to seek to new time) | ||
5913 | this.player_.currentTime(newTime); | ||
5914 | }; | ||
5915 | |||
5916 | /** | ||
5917 | * Handle mouse up on seek bar | ||
5918 | * | ||
5919 | * @method handleMouseUp | ||
5920 | */ | ||
5921 | |||
5922 | SeekBar.prototype.handleMouseUp = function handleMouseUp(event) { | ||
5923 | _Slider.prototype.handleMouseUp.call(this, event); | ||
5924 | |||
5925 | this.player_.scrubbing(false); | ||
5926 | if (this.videoWasPlaying) { | ||
5927 | this.player_.play(); | ||
5928 | } | ||
5929 | }; | ||
5930 | |||
5931 | /** | ||
5932 | * Move more quickly fast forward for keyboard-only users | ||
5933 | * | ||
5934 | * @method stepForward | ||
5935 | */ | ||
5936 | |||
5937 | SeekBar.prototype.stepForward = function stepForward() { | ||
5938 | this.player_.currentTime(this.player_.currentTime() + 5); // more quickly fast forward for keyboard-only users | ||
5939 | }; | ||
5940 | |||
5941 | /** | ||
5942 | * Move more quickly rewind for keyboard-only users | ||
5943 | * | ||
5944 | * @method stepBack | ||
5945 | */ | ||
5946 | |||
5947 | SeekBar.prototype.stepBack = function stepBack() { | ||
5948 | this.player_.currentTime(this.player_.currentTime() - 5); // more quickly rewind for keyboard-only users | ||
5949 | }; | ||
5950 | |||
5951 | return SeekBar; | ||
5952 | })(_sliderSliderJs2['default']); | ||
5953 | |||
5954 | SeekBar.prototype.options_ = { | ||
5955 | children: ['loadProgressBar', 'mouseTimeDisplay', 'playProgressBar'], | ||
5956 | 'barName': 'playProgressBar' | ||
5957 | }; | ||
5958 | |||
5959 | SeekBar.prototype.playerEvent = 'timeupdate'; | ||
5960 | |||
5961 | _componentJs2['default'].registerComponent('SeekBar', SeekBar); | ||
5962 | exports['default'] = SeekBar; | ||
5963 | module.exports = exports['default']; | ||
5964 | |||
5965 | },{"../../component.js":67,"../../slider/slider.js":114,"../../utils/fn.js":134,"../../utils/format-time.js":135,"./load-progress-bar.js":75,"./play-progress-bar.js":77,"object.assign":45}],80:[function(_dereq_,module,exports){ | ||
5966 | /** | ||
5967 | * @file custom-control-spacer.js | ||
5968 | */ | ||
5969 | 'use strict'; | ||
5970 | |||
5971 | exports.__esModule = true; | ||
5972 | |||
5973 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
5974 | |||
5975 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
5976 | |||
5977 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
5978 | |||
5979 | var _spacerJs = _dereq_('./spacer.js'); | ||
5980 | |||
5981 | var _spacerJs2 = _interopRequireDefault(_spacerJs); | ||
5982 | |||
5983 | var _componentJs = _dereq_('../../component.js'); | ||
5984 | |||
5985 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
5986 | |||
5987 | /** | ||
5988 | * Spacer specifically meant to be used as an insertion point for new plugins, etc. | ||
5989 | * | ||
5990 | * @extends Spacer | ||
5991 | * @class CustomControlSpacer | ||
5992 | */ | ||
5993 | |||
5994 | var CustomControlSpacer = (function (_Spacer) { | ||
5995 | _inherits(CustomControlSpacer, _Spacer); | ||
5996 | |||
5997 | function CustomControlSpacer() { | ||
5998 | _classCallCheck(this, CustomControlSpacer); | ||
5999 | |||
6000 | _Spacer.apply(this, arguments); | ||
6001 | } | ||
6002 | |||
6003 | /** | ||
6004 | * Allow sub components to stack CSS class names | ||
6005 | * | ||
6006 | * @return {String} The constructed class name | ||
6007 | * @method buildCSSClass | ||
6008 | */ | ||
6009 | |||
6010 | CustomControlSpacer.prototype.buildCSSClass = function buildCSSClass() { | ||
6011 | return 'vjs-custom-control-spacer ' + _Spacer.prototype.buildCSSClass.call(this); | ||
6012 | }; | ||
6013 | |||
6014 | /** | ||
6015 | * Create the component's DOM element | ||
6016 | * | ||
6017 | * @return {Element} | ||
6018 | * @method createEl | ||
6019 | */ | ||
6020 | |||
6021 | CustomControlSpacer.prototype.createEl = function createEl() { | ||
6022 | var el = _Spacer.prototype.createEl.call(this, { | ||
6023 | className: this.buildCSSClass() | ||
6024 | }); | ||
6025 | |||
6026 | // No-flex/table-cell mode requires there be some content | ||
6027 | // in the cell to fill the remaining space of the table. | ||
6028 | el.innerHTML = ' '; | ||
6029 | return el; | ||
6030 | }; | ||
6031 | |||
6032 | return CustomControlSpacer; | ||
6033 | })(_spacerJs2['default']); | ||
6034 | |||
6035 | _componentJs2['default'].registerComponent('CustomControlSpacer', CustomControlSpacer); | ||
6036 | exports['default'] = CustomControlSpacer; | ||
6037 | module.exports = exports['default']; | ||
6038 | |||
6039 | },{"../../component.js":67,"./spacer.js":81}],81:[function(_dereq_,module,exports){ | ||
6040 | /** | ||
6041 | * @file spacer.js | ||
6042 | */ | ||
6043 | 'use strict'; | ||
6044 | |||
6045 | exports.__esModule = true; | ||
6046 | |||
6047 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6048 | |||
6049 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6050 | |||
6051 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6052 | |||
6053 | var _componentJs = _dereq_('../../component.js'); | ||
6054 | |||
6055 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6056 | |||
6057 | /** | ||
6058 | * Just an empty spacer element that can be used as an append point for plugins, etc. | ||
6059 | * Also can be used to create space between elements when necessary. | ||
6060 | * | ||
6061 | * @extends Component | ||
6062 | * @class Spacer | ||
6063 | */ | ||
6064 | |||
6065 | var Spacer = (function (_Component) { | ||
6066 | _inherits(Spacer, _Component); | ||
6067 | |||
6068 | function Spacer() { | ||
6069 | _classCallCheck(this, Spacer); | ||
6070 | |||
6071 | _Component.apply(this, arguments); | ||
6072 | } | ||
6073 | |||
6074 | /** | ||
6075 | * Allow sub components to stack CSS class names | ||
6076 | * | ||
6077 | * @return {String} The constructed class name | ||
6078 | * @method buildCSSClass | ||
6079 | */ | ||
6080 | |||
6081 | Spacer.prototype.buildCSSClass = function buildCSSClass() { | ||
6082 | return 'vjs-spacer ' + _Component.prototype.buildCSSClass.call(this); | ||
6083 | }; | ||
6084 | |||
6085 | /** | ||
6086 | * Create the component's DOM element | ||
6087 | * | ||
6088 | * @return {Element} | ||
6089 | * @method createEl | ||
6090 | */ | ||
6091 | |||
6092 | Spacer.prototype.createEl = function createEl() { | ||
6093 | return _Component.prototype.createEl.call(this, 'div', { | ||
6094 | className: this.buildCSSClass() | ||
6095 | }); | ||
6096 | }; | ||
6097 | |||
6098 | return Spacer; | ||
6099 | })(_componentJs2['default']); | ||
6100 | |||
6101 | _componentJs2['default'].registerComponent('Spacer', Spacer); | ||
6102 | |||
6103 | exports['default'] = Spacer; | ||
6104 | module.exports = exports['default']; | ||
6105 | |||
6106 | },{"../../component.js":67}],82:[function(_dereq_,module,exports){ | ||
6107 | /** | ||
6108 | * @file caption-settings-menu-item.js | ||
6109 | */ | ||
6110 | 'use strict'; | ||
6111 | |||
6112 | exports.__esModule = true; | ||
6113 | |||
6114 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6115 | |||
6116 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6117 | |||
6118 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6119 | |||
6120 | var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); | ||
6121 | |||
6122 | var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); | ||
6123 | |||
6124 | var _componentJs = _dereq_('../../component.js'); | ||
6125 | |||
6126 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6127 | |||
6128 | /** | ||
6129 | * The menu item for caption track settings menu | ||
6130 | * | ||
6131 | * @param {Player|Object} player | ||
6132 | * @param {Object=} options | ||
6133 | * @extends TextTrackMenuItem | ||
6134 | * @class CaptionSettingsMenuItem | ||
6135 | */ | ||
6136 | |||
6137 | var CaptionSettingsMenuItem = (function (_TextTrackMenuItem) { | ||
6138 | _inherits(CaptionSettingsMenuItem, _TextTrackMenuItem); | ||
6139 | |||
6140 | function CaptionSettingsMenuItem(player, options) { | ||
6141 | _classCallCheck(this, CaptionSettingsMenuItem); | ||
6142 | |||
6143 | options['track'] = { | ||
6144 | 'kind': options['kind'], | ||
6145 | 'player': player, | ||
6146 | 'label': options['kind'] + ' settings', | ||
6147 | 'selectable': false, | ||
6148 | 'default': false, | ||
6149 | mode: 'disabled' | ||
6150 | }; | ||
6151 | |||
6152 | // CaptionSettingsMenuItem has no concept of 'selected' | ||
6153 | options['selectable'] = false; | ||
6154 | |||
6155 | _TextTrackMenuItem.call(this, player, options); | ||
6156 | this.addClass('vjs-texttrack-settings'); | ||
6157 | this.controlText(', opens ' + options['kind'] + ' settings dialog'); | ||
6158 | } | ||
6159 | |||
6160 | /** | ||
6161 | * Handle click on menu item | ||
6162 | * | ||
6163 | * @method handleClick | ||
6164 | */ | ||
6165 | |||
6166 | CaptionSettingsMenuItem.prototype.handleClick = function handleClick() { | ||
6167 | this.player().getChild('textTrackSettings').show(); | ||
6168 | this.player().getChild('textTrackSettings').el_.focus(); | ||
6169 | }; | ||
6170 | |||
6171 | return CaptionSettingsMenuItem; | ||
6172 | })(_textTrackMenuItemJs2['default']); | ||
6173 | |||
6174 | _componentJs2['default'].registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem); | ||
6175 | exports['default'] = CaptionSettingsMenuItem; | ||
6176 | module.exports = exports['default']; | ||
6177 | |||
6178 | },{"../../component.js":67,"./text-track-menu-item.js":89}],83:[function(_dereq_,module,exports){ | ||
6179 | /** | ||
6180 | * @file captions-button.js | ||
6181 | */ | ||
6182 | 'use strict'; | ||
6183 | |||
6184 | exports.__esModule = true; | ||
6185 | |||
6186 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6187 | |||
6188 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6189 | |||
6190 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6191 | |||
6192 | var _textTrackButtonJs = _dereq_('./text-track-button.js'); | ||
6193 | |||
6194 | var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); | ||
6195 | |||
6196 | var _componentJs = _dereq_('../../component.js'); | ||
6197 | |||
6198 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6199 | |||
6200 | var _captionSettingsMenuItemJs = _dereq_('./caption-settings-menu-item.js'); | ||
6201 | |||
6202 | var _captionSettingsMenuItemJs2 = _interopRequireDefault(_captionSettingsMenuItemJs); | ||
6203 | |||
6204 | /** | ||
6205 | * The button component for toggling and selecting captions | ||
6206 | * | ||
6207 | * @param {Object} player Player object | ||
6208 | * @param {Object=} options Object of option names and values | ||
6209 | * @param {Function=} ready Ready callback function | ||
6210 | * @extends TextTrackButton | ||
6211 | * @class CaptionsButton | ||
6212 | */ | ||
6213 | |||
6214 | var CaptionsButton = (function (_TextTrackButton) { | ||
6215 | _inherits(CaptionsButton, _TextTrackButton); | ||
6216 | |||
6217 | function CaptionsButton(player, options, ready) { | ||
6218 | _classCallCheck(this, CaptionsButton); | ||
6219 | |||
6220 | _TextTrackButton.call(this, player, options, ready); | ||
6221 | this.el_.setAttribute('aria-label', 'Captions Menu'); | ||
6222 | } | ||
6223 | |||
6224 | /** | ||
6225 | * Allow sub components to stack CSS class names | ||
6226 | * | ||
6227 | * @return {String} The constructed class name | ||
6228 | * @method buildCSSClass | ||
6229 | */ | ||
6230 | |||
6231 | CaptionsButton.prototype.buildCSSClass = function buildCSSClass() { | ||
6232 | return 'vjs-captions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); | ||
6233 | }; | ||
6234 | |||
6235 | /** | ||
6236 | * Update caption menu items | ||
6237 | * | ||
6238 | * @method update | ||
6239 | */ | ||
6240 | |||
6241 | CaptionsButton.prototype.update = function update() { | ||
6242 | var threshold = 2; | ||
6243 | _TextTrackButton.prototype.update.call(this); | ||
6244 | |||
6245 | // if native, then threshold is 1 because no settings button | ||
6246 | if (this.player().tech_ && this.player().tech_['featuresNativeTextTracks']) { | ||
6247 | threshold = 1; | ||
6248 | } | ||
6249 | |||
6250 | if (this.items && this.items.length > threshold) { | ||
6251 | this.show(); | ||
6252 | } else { | ||
6253 | this.hide(); | ||
6254 | } | ||
6255 | }; | ||
6256 | |||
6257 | /** | ||
6258 | * Create caption menu items | ||
6259 | * | ||
6260 | * @return {Array} Array of menu items | ||
6261 | * @method createItems | ||
6262 | */ | ||
6263 | |||
6264 | CaptionsButton.prototype.createItems = function createItems() { | ||
6265 | var items = []; | ||
6266 | |||
6267 | if (!(this.player().tech_ && this.player().tech_['featuresNativeTextTracks'])) { | ||
6268 | items.push(new _captionSettingsMenuItemJs2['default'](this.player_, { 'kind': this.kind_ })); | ||
6269 | } | ||
6270 | |||
6271 | return _TextTrackButton.prototype.createItems.call(this, items); | ||
6272 | }; | ||
6273 | |||
6274 | return CaptionsButton; | ||
6275 | })(_textTrackButtonJs2['default']); | ||
6276 | |||
6277 | CaptionsButton.prototype.kind_ = 'captions'; | ||
6278 | CaptionsButton.prototype.controlText_ = 'Captions'; | ||
6279 | |||
6280 | _componentJs2['default'].registerComponent('CaptionsButton', CaptionsButton); | ||
6281 | exports['default'] = CaptionsButton; | ||
6282 | module.exports = exports['default']; | ||
6283 | |||
6284 | },{"../../component.js":67,"./caption-settings-menu-item.js":82,"./text-track-button.js":88}],84:[function(_dereq_,module,exports){ | ||
6285 | /** | ||
6286 | * @file chapters-button.js | ||
6287 | */ | ||
6288 | 'use strict'; | ||
6289 | |||
6290 | exports.__esModule = true; | ||
6291 | |||
6292 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
6293 | |||
6294 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6295 | |||
6296 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6297 | |||
6298 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6299 | |||
6300 | var _textTrackButtonJs = _dereq_('./text-track-button.js'); | ||
6301 | |||
6302 | var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); | ||
6303 | |||
6304 | var _componentJs = _dereq_('../../component.js'); | ||
6305 | |||
6306 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6307 | |||
6308 | var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); | ||
6309 | |||
6310 | var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); | ||
6311 | |||
6312 | var _chaptersTrackMenuItemJs = _dereq_('./chapters-track-menu-item.js'); | ||
6313 | |||
6314 | var _chaptersTrackMenuItemJs2 = _interopRequireDefault(_chaptersTrackMenuItemJs); | ||
6315 | |||
6316 | var _menuMenuJs = _dereq_('../../menu/menu.js'); | ||
6317 | |||
6318 | var _menuMenuJs2 = _interopRequireDefault(_menuMenuJs); | ||
6319 | |||
6320 | var _utilsDomJs = _dereq_('../../utils/dom.js'); | ||
6321 | |||
6322 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
6323 | |||
6324 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
6325 | |||
6326 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
6327 | |||
6328 | var _utilsToTitleCaseJs = _dereq_('../../utils/to-title-case.js'); | ||
6329 | |||
6330 | var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); | ||
6331 | |||
6332 | var _globalWindow = _dereq_('global/window'); | ||
6333 | |||
6334 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
6335 | |||
6336 | /** | ||
6337 | * The button component for toggling and selecting chapters | ||
6338 | * Chapters act much differently than other text tracks | ||
6339 | * Cues are navigation vs. other tracks of alternative languages | ||
6340 | * | ||
6341 | * @param {Object} player Player object | ||
6342 | * @param {Object=} options Object of option names and values | ||
6343 | * @param {Function=} ready Ready callback function | ||
6344 | * @extends TextTrackButton | ||
6345 | * @class ChaptersButton | ||
6346 | */ | ||
6347 | |||
6348 | var ChaptersButton = (function (_TextTrackButton) { | ||
6349 | _inherits(ChaptersButton, _TextTrackButton); | ||
6350 | |||
6351 | function ChaptersButton(player, options, ready) { | ||
6352 | _classCallCheck(this, ChaptersButton); | ||
6353 | |||
6354 | _TextTrackButton.call(this, player, options, ready); | ||
6355 | this.el_.setAttribute('aria-label', 'Chapters Menu'); | ||
6356 | } | ||
6357 | |||
6358 | /** | ||
6359 | * Allow sub components to stack CSS class names | ||
6360 | * | ||
6361 | * @return {String} The constructed class name | ||
6362 | * @method buildCSSClass | ||
6363 | */ | ||
6364 | |||
6365 | ChaptersButton.prototype.buildCSSClass = function buildCSSClass() { | ||
6366 | return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); | ||
6367 | }; | ||
6368 | |||
6369 | /** | ||
6370 | * Create a menu item for each text track | ||
6371 | * | ||
6372 | * @return {Array} Array of menu items | ||
6373 | * @method createItems | ||
6374 | */ | ||
6375 | |||
6376 | ChaptersButton.prototype.createItems = function createItems() { | ||
6377 | var items = []; | ||
6378 | |||
6379 | var tracks = this.player_.textTracks(); | ||
6380 | |||
6381 | if (!tracks) { | ||
6382 | return items; | ||
6383 | } | ||
6384 | |||
6385 | for (var i = 0; i < tracks.length; i++) { | ||
6386 | var track = tracks[i]; | ||
6387 | if (track['kind'] === this.kind_) { | ||
6388 | items.push(new _textTrackMenuItemJs2['default'](this.player_, { | ||
6389 | 'track': track | ||
6390 | })); | ||
6391 | } | ||
6392 | } | ||
6393 | |||
6394 | return items; | ||
6395 | }; | ||
6396 | |||
6397 | /** | ||
6398 | * Create menu from chapter buttons | ||
6399 | * | ||
6400 | * @return {Menu} Menu of chapter buttons | ||
6401 | * @method createMenu | ||
6402 | */ | ||
6403 | |||
6404 | ChaptersButton.prototype.createMenu = function createMenu() { | ||
6405 | var _this = this; | ||
6406 | |||
6407 | var tracks = this.player_.textTracks() || []; | ||
6408 | var chaptersTrack = undefined; | ||
6409 | var items = this.items = []; | ||
6410 | |||
6411 | for (var i = 0, _length = tracks.length; i < _length; i++) { | ||
6412 | var track = tracks[i]; | ||
6413 | |||
6414 | if (track['kind'] === this.kind_) { | ||
6415 | chaptersTrack = track; | ||
6416 | |||
6417 | break; | ||
6418 | } | ||
6419 | } | ||
6420 | |||
6421 | var menu = this.menu; | ||
6422 | if (menu === undefined) { | ||
6423 | menu = new _menuMenuJs2['default'](this.player_); | ||
6424 | var title = Dom.createEl('li', { | ||
6425 | className: 'vjs-menu-title', | ||
6426 | innerHTML: _utilsToTitleCaseJs2['default'](this.kind_), | ||
6427 | tabIndex: -1 | ||
6428 | }); | ||
6429 | menu.children_.unshift(title); | ||
6430 | Dom.insertElFirst(title, menu.contentEl()); | ||
6431 | } | ||
6432 | |||
6433 | if (chaptersTrack && chaptersTrack.cues == null) { | ||
6434 | chaptersTrack['mode'] = 'hidden'; | ||
6435 | |||
6436 | var remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(chaptersTrack); | ||
6437 | |||
6438 | if (remoteTextTrackEl) { | ||
6439 | remoteTextTrackEl.addEventListener('load', function (event) { | ||
6440 | return _this.update(); | ||
6441 | }); | ||
6442 | } | ||
6443 | } | ||
6444 | |||
6445 | if (chaptersTrack && chaptersTrack.cues && chaptersTrack.cues.length > 0) { | ||
6446 | var cues = chaptersTrack['cues'], | ||
6447 | cue = undefined; | ||
6448 | |||
6449 | for (var i = 0, l = cues.length; i < l; i++) { | ||
6450 | cue = cues[i]; | ||
6451 | |||
6452 | var mi = new _chaptersTrackMenuItemJs2['default'](this.player_, { | ||
6453 | 'track': chaptersTrack, | ||
6454 | 'cue': cue | ||
6455 | }); | ||
6456 | |||
6457 | items.push(mi); | ||
6458 | |||
6459 | menu.addChild(mi); | ||
6460 | } | ||
6461 | |||
6462 | this.addChild(menu); | ||
6463 | } | ||
6464 | |||
6465 | if (this.items.length > 0) { | ||
6466 | this.show(); | ||
6467 | } | ||
6468 | |||
6469 | return menu; | ||
6470 | }; | ||
6471 | |||
6472 | return ChaptersButton; | ||
6473 | })(_textTrackButtonJs2['default']); | ||
6474 | |||
6475 | ChaptersButton.prototype.kind_ = 'chapters'; | ||
6476 | ChaptersButton.prototype.controlText_ = 'Chapters'; | ||
6477 | |||
6478 | _componentJs2['default'].registerComponent('ChaptersButton', ChaptersButton); | ||
6479 | exports['default'] = ChaptersButton; | ||
6480 | module.exports = exports['default']; | ||
6481 | |||
6482 | },{"../../component.js":67,"../../menu/menu.js":106,"../../utils/dom.js":132,"../../utils/fn.js":134,"../../utils/to-title-case.js":141,"./chapters-track-menu-item.js":85,"./text-track-button.js":88,"./text-track-menu-item.js":89,"global/window":2}],85:[function(_dereq_,module,exports){ | ||
6483 | /** | ||
6484 | * @file chapters-track-menu-item.js | ||
6485 | */ | ||
6486 | 'use strict'; | ||
6487 | |||
6488 | exports.__esModule = true; | ||
6489 | |||
6490 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
6491 | |||
6492 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6493 | |||
6494 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6495 | |||
6496 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6497 | |||
6498 | var _menuMenuItemJs = _dereq_('../../menu/menu-item.js'); | ||
6499 | |||
6500 | var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); | ||
6501 | |||
6502 | var _componentJs = _dereq_('../../component.js'); | ||
6503 | |||
6504 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6505 | |||
6506 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
6507 | |||
6508 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
6509 | |||
6510 | /** | ||
6511 | * The chapter track menu item | ||
6512 | * | ||
6513 | * @param {Player|Object} player | ||
6514 | * @param {Object=} options | ||
6515 | * @extends MenuItem | ||
6516 | * @class ChaptersTrackMenuItem | ||
6517 | */ | ||
6518 | |||
6519 | var ChaptersTrackMenuItem = (function (_MenuItem) { | ||
6520 | _inherits(ChaptersTrackMenuItem, _MenuItem); | ||
6521 | |||
6522 | function ChaptersTrackMenuItem(player, options) { | ||
6523 | _classCallCheck(this, ChaptersTrackMenuItem); | ||
6524 | |||
6525 | var track = options['track']; | ||
6526 | var cue = options['cue']; | ||
6527 | var currentTime = player.currentTime(); | ||
6528 | |||
6529 | // Modify options for parent MenuItem class's init. | ||
6530 | options['label'] = cue.text; | ||
6531 | options['selected'] = cue['startTime'] <= currentTime && currentTime < cue['endTime']; | ||
6532 | _MenuItem.call(this, player, options); | ||
6533 | |||
6534 | this.track = track; | ||
6535 | this.cue = cue; | ||
6536 | track.addEventListener('cuechange', Fn.bind(this, this.update)); | ||
6537 | } | ||
6538 | |||
6539 | /** | ||
6540 | * Handle click on menu item | ||
6541 | * | ||
6542 | * @method handleClick | ||
6543 | */ | ||
6544 | |||
6545 | ChaptersTrackMenuItem.prototype.handleClick = function handleClick() { | ||
6546 | _MenuItem.prototype.handleClick.call(this); | ||
6547 | this.player_.currentTime(this.cue.startTime); | ||
6548 | this.update(this.cue.startTime); | ||
6549 | }; | ||
6550 | |||
6551 | /** | ||
6552 | * Update chapter menu item | ||
6553 | * | ||
6554 | * @method update | ||
6555 | */ | ||
6556 | |||
6557 | ChaptersTrackMenuItem.prototype.update = function update() { | ||
6558 | var cue = this.cue; | ||
6559 | var currentTime = this.player_.currentTime(); | ||
6560 | |||
6561 | // vjs.log(currentTime, cue.startTime); | ||
6562 | this.selected(cue['startTime'] <= currentTime && currentTime < cue['endTime']); | ||
6563 | }; | ||
6564 | |||
6565 | return ChaptersTrackMenuItem; | ||
6566 | })(_menuMenuItemJs2['default']); | ||
6567 | |||
6568 | _componentJs2['default'].registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem); | ||
6569 | exports['default'] = ChaptersTrackMenuItem; | ||
6570 | module.exports = exports['default']; | ||
6571 | |||
6572 | },{"../../component.js":67,"../../menu/menu-item.js":105,"../../utils/fn.js":134}],86:[function(_dereq_,module,exports){ | ||
6573 | /** | ||
6574 | * @file off-text-track-menu-item.js | ||
6575 | */ | ||
6576 | 'use strict'; | ||
6577 | |||
6578 | exports.__esModule = true; | ||
6579 | |||
6580 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6581 | |||
6582 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6583 | |||
6584 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6585 | |||
6586 | var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); | ||
6587 | |||
6588 | var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); | ||
6589 | |||
6590 | var _componentJs = _dereq_('../../component.js'); | ||
6591 | |||
6592 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6593 | |||
6594 | /** | ||
6595 | * A special menu item for turning of a specific type of text track | ||
6596 | * | ||
6597 | * @param {Player|Object} player | ||
6598 | * @param {Object=} options | ||
6599 | * @extends TextTrackMenuItem | ||
6600 | * @class OffTextTrackMenuItem | ||
6601 | */ | ||
6602 | |||
6603 | var OffTextTrackMenuItem = (function (_TextTrackMenuItem) { | ||
6604 | _inherits(OffTextTrackMenuItem, _TextTrackMenuItem); | ||
6605 | |||
6606 | function OffTextTrackMenuItem(player, options) { | ||
6607 | _classCallCheck(this, OffTextTrackMenuItem); | ||
6608 | |||
6609 | // Create pseudo track info | ||
6610 | // Requires options['kind'] | ||
6611 | options['track'] = { | ||
6612 | 'kind': options['kind'], | ||
6613 | 'player': player, | ||
6614 | 'label': options['kind'] + ' off', | ||
6615 | 'default': false, | ||
6616 | 'mode': 'disabled' | ||
6617 | }; | ||
6618 | |||
6619 | // MenuItem is selectable | ||
6620 | options['selectable'] = true; | ||
6621 | |||
6622 | _TextTrackMenuItem.call(this, player, options); | ||
6623 | this.selected(true); | ||
6624 | } | ||
6625 | |||
6626 | /** | ||
6627 | * Handle text track change | ||
6628 | * | ||
6629 | * @param {Object} event Event object | ||
6630 | * @method handleTracksChange | ||
6631 | */ | ||
6632 | |||
6633 | OffTextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { | ||
6634 | var tracks = this.player().textTracks(); | ||
6635 | var selected = true; | ||
6636 | |||
6637 | for (var i = 0, l = tracks.length; i < l; i++) { | ||
6638 | var track = tracks[i]; | ||
6639 | if (track['kind'] === this.track['kind'] && track['mode'] === 'showing') { | ||
6640 | selected = false; | ||
6641 | break; | ||
6642 | } | ||
6643 | } | ||
6644 | |||
6645 | this.selected(selected); | ||
6646 | }; | ||
6647 | |||
6648 | return OffTextTrackMenuItem; | ||
6649 | })(_textTrackMenuItemJs2['default']); | ||
6650 | |||
6651 | _componentJs2['default'].registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem); | ||
6652 | exports['default'] = OffTextTrackMenuItem; | ||
6653 | module.exports = exports['default']; | ||
6654 | |||
6655 | },{"../../component.js":67,"./text-track-menu-item.js":89}],87:[function(_dereq_,module,exports){ | ||
6656 | /** | ||
6657 | * @file subtitles-button.js | ||
6658 | */ | ||
6659 | 'use strict'; | ||
6660 | |||
6661 | exports.__esModule = true; | ||
6662 | |||
6663 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6664 | |||
6665 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6666 | |||
6667 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6668 | |||
6669 | var _textTrackButtonJs = _dereq_('./text-track-button.js'); | ||
6670 | |||
6671 | var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); | ||
6672 | |||
6673 | var _componentJs = _dereq_('../../component.js'); | ||
6674 | |||
6675 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6676 | |||
6677 | /** | ||
6678 | * The button component for toggling and selecting subtitles | ||
6679 | * | ||
6680 | * @param {Object} player Player object | ||
6681 | * @param {Object=} options Object of option names and values | ||
6682 | * @param {Function=} ready Ready callback function | ||
6683 | * @extends TextTrackButton | ||
6684 | * @class SubtitlesButton | ||
6685 | */ | ||
6686 | |||
6687 | var SubtitlesButton = (function (_TextTrackButton) { | ||
6688 | _inherits(SubtitlesButton, _TextTrackButton); | ||
6689 | |||
6690 | function SubtitlesButton(player, options, ready) { | ||
6691 | _classCallCheck(this, SubtitlesButton); | ||
6692 | |||
6693 | _TextTrackButton.call(this, player, options, ready); | ||
6694 | this.el_.setAttribute('aria-label', 'Subtitles Menu'); | ||
6695 | } | ||
6696 | |||
6697 | /** | ||
6698 | * Allow sub components to stack CSS class names | ||
6699 | * | ||
6700 | * @return {String} The constructed class name | ||
6701 | * @method buildCSSClass | ||
6702 | */ | ||
6703 | |||
6704 | SubtitlesButton.prototype.buildCSSClass = function buildCSSClass() { | ||
6705 | return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); | ||
6706 | }; | ||
6707 | |||
6708 | return SubtitlesButton; | ||
6709 | })(_textTrackButtonJs2['default']); | ||
6710 | |||
6711 | SubtitlesButton.prototype.kind_ = 'subtitles'; | ||
6712 | SubtitlesButton.prototype.controlText_ = 'Subtitles'; | ||
6713 | |||
6714 | _componentJs2['default'].registerComponent('SubtitlesButton', SubtitlesButton); | ||
6715 | exports['default'] = SubtitlesButton; | ||
6716 | module.exports = exports['default']; | ||
6717 | |||
6718 | },{"../../component.js":67,"./text-track-button.js":88}],88:[function(_dereq_,module,exports){ | ||
6719 | /** | ||
6720 | * @file text-track-button.js | ||
6721 | */ | ||
6722 | 'use strict'; | ||
6723 | |||
6724 | exports.__esModule = true; | ||
6725 | |||
6726 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
6727 | |||
6728 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6729 | |||
6730 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6731 | |||
6732 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6733 | |||
6734 | var _menuMenuButtonJs = _dereq_('../../menu/menu-button.js'); | ||
6735 | |||
6736 | var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); | ||
6737 | |||
6738 | var _componentJs = _dereq_('../../component.js'); | ||
6739 | |||
6740 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6741 | |||
6742 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
6743 | |||
6744 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
6745 | |||
6746 | var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); | ||
6747 | |||
6748 | var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); | ||
6749 | |||
6750 | var _offTextTrackMenuItemJs = _dereq_('./off-text-track-menu-item.js'); | ||
6751 | |||
6752 | var _offTextTrackMenuItemJs2 = _interopRequireDefault(_offTextTrackMenuItemJs); | ||
6753 | |||
6754 | /** | ||
6755 | * The base class for buttons that toggle specific text track types (e.g. subtitles) | ||
6756 | * | ||
6757 | * @param {Player|Object} player | ||
6758 | * @param {Object=} options | ||
6759 | * @extends MenuButton | ||
6760 | * @class TextTrackButton | ||
6761 | */ | ||
6762 | |||
6763 | var TextTrackButton = (function (_MenuButton) { | ||
6764 | _inherits(TextTrackButton, _MenuButton); | ||
6765 | |||
6766 | function TextTrackButton(player, options) { | ||
6767 | _classCallCheck(this, TextTrackButton); | ||
6768 | |||
6769 | _MenuButton.call(this, player, options); | ||
6770 | |||
6771 | var tracks = this.player_.textTracks(); | ||
6772 | |||
6773 | if (this.items.length <= 1) { | ||
6774 | this.hide(); | ||
6775 | } | ||
6776 | |||
6777 | if (!tracks) { | ||
6778 | return; | ||
6779 | } | ||
6780 | |||
6781 | var updateHandler = Fn.bind(this, this.update); | ||
6782 | tracks.addEventListener('removetrack', updateHandler); | ||
6783 | tracks.addEventListener('addtrack', updateHandler); | ||
6784 | |||
6785 | this.player_.on('dispose', function () { | ||
6786 | tracks.removeEventListener('removetrack', updateHandler); | ||
6787 | tracks.removeEventListener('addtrack', updateHandler); | ||
6788 | }); | ||
6789 | } | ||
6790 | |||
6791 | // Create a menu item for each text track | ||
6792 | |||
6793 | TextTrackButton.prototype.createItems = function createItems() { | ||
6794 | var items = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; | ||
6795 | |||
6796 | // Add an OFF menu item to turn all tracks off | ||
6797 | items.push(new _offTextTrackMenuItemJs2['default'](this.player_, { 'kind': this.kind_ })); | ||
6798 | |||
6799 | var tracks = this.player_.textTracks(); | ||
6800 | |||
6801 | if (!tracks) { | ||
6802 | return items; | ||
6803 | } | ||
6804 | |||
6805 | for (var i = 0; i < tracks.length; i++) { | ||
6806 | var track = tracks[i]; | ||
6807 | |||
6808 | // only add tracks that are of the appropriate kind and have a label | ||
6809 | if (track['kind'] === this.kind_) { | ||
6810 | items.push(new _textTrackMenuItemJs2['default'](this.player_, { | ||
6811 | // MenuItem is selectable | ||
6812 | 'selectable': true, | ||
6813 | 'track': track | ||
6814 | })); | ||
6815 | } | ||
6816 | } | ||
6817 | |||
6818 | return items; | ||
6819 | }; | ||
6820 | |||
6821 | return TextTrackButton; | ||
6822 | })(_menuMenuButtonJs2['default']); | ||
6823 | |||
6824 | _componentJs2['default'].registerComponent('TextTrackButton', TextTrackButton); | ||
6825 | exports['default'] = TextTrackButton; | ||
6826 | module.exports = exports['default']; | ||
6827 | |||
6828 | },{"../../component.js":67,"../../menu/menu-button.js":104,"../../utils/fn.js":134,"./off-text-track-menu-item.js":86,"./text-track-menu-item.js":89}],89:[function(_dereq_,module,exports){ | ||
6829 | /** | ||
6830 | * @file text-track-menu-item.js | ||
6831 | */ | ||
6832 | 'use strict'; | ||
6833 | |||
6834 | exports.__esModule = true; | ||
6835 | |||
6836 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
6837 | |||
6838 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6839 | |||
6840 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6841 | |||
6842 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6843 | |||
6844 | var _menuMenuItemJs = _dereq_('../../menu/menu-item.js'); | ||
6845 | |||
6846 | var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); | ||
6847 | |||
6848 | var _componentJs = _dereq_('../../component.js'); | ||
6849 | |||
6850 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6851 | |||
6852 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
6853 | |||
6854 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
6855 | |||
6856 | var _globalWindow = _dereq_('global/window'); | ||
6857 | |||
6858 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
6859 | |||
6860 | var _globalDocument = _dereq_('global/document'); | ||
6861 | |||
6862 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
6863 | |||
6864 | /** | ||
6865 | * The specific menu item type for selecting a language within a text track kind | ||
6866 | * | ||
6867 | * @param {Player|Object} player | ||
6868 | * @param {Object=} options | ||
6869 | * @extends MenuItem | ||
6870 | * @class TextTrackMenuItem | ||
6871 | */ | ||
6872 | |||
6873 | var TextTrackMenuItem = (function (_MenuItem) { | ||
6874 | _inherits(TextTrackMenuItem, _MenuItem); | ||
6875 | |||
6876 | function TextTrackMenuItem(player, options) { | ||
6877 | var _this = this; | ||
6878 | |||
6879 | _classCallCheck(this, TextTrackMenuItem); | ||
6880 | |||
6881 | var track = options['track']; | ||
6882 | var tracks = player.textTracks(); | ||
6883 | |||
6884 | // Modify options for parent MenuItem class's init. | ||
6885 | options['label'] = track['label'] || track['language'] || 'Unknown'; | ||
6886 | options['selected'] = track['default'] || track['mode'] === 'showing'; | ||
6887 | |||
6888 | _MenuItem.call(this, player, options); | ||
6889 | |||
6890 | this.track = track; | ||
6891 | |||
6892 | if (tracks) { | ||
6893 | (function () { | ||
6894 | var changeHandler = Fn.bind(_this, _this.handleTracksChange); | ||
6895 | |||
6896 | tracks.addEventListener('change', changeHandler); | ||
6897 | _this.on('dispose', function () { | ||
6898 | tracks.removeEventListener('change', changeHandler); | ||
6899 | }); | ||
6900 | })(); | ||
6901 | } | ||
6902 | |||
6903 | // iOS7 doesn't dispatch change events to TextTrackLists when an | ||
6904 | // associated track's mode changes. Without something like | ||
6905 | // Object.observe() (also not present on iOS7), it's not | ||
6906 | // possible to detect changes to the mode attribute and polyfill | ||
6907 | // the change event. As a poor substitute, we manually dispatch | ||
6908 | // change events whenever the controls modify the mode. | ||
6909 | if (tracks && tracks.onchange === undefined) { | ||
6910 | (function () { | ||
6911 | var event = undefined; | ||
6912 | |||
6913 | _this.on(['tap', 'click'], function () { | ||
6914 | if (typeof _globalWindow2['default'].Event !== 'object') { | ||
6915 | // Android 2.3 throws an Illegal Constructor error for window.Event | ||
6916 | try { | ||
6917 | event = new _globalWindow2['default'].Event('change'); | ||
6918 | } catch (err) {} | ||
6919 | } | ||
6920 | |||
6921 | if (!event) { | ||
6922 | event = _globalDocument2['default'].createEvent('Event'); | ||
6923 | event.initEvent('change', true, true); | ||
6924 | } | ||
6925 | |||
6926 | tracks.dispatchEvent(event); | ||
6927 | }); | ||
6928 | })(); | ||
6929 | } | ||
6930 | } | ||
6931 | |||
6932 | /** | ||
6933 | * Handle click on text track | ||
6934 | * | ||
6935 | * @method handleClick | ||
6936 | */ | ||
6937 | |||
6938 | TextTrackMenuItem.prototype.handleClick = function handleClick(event) { | ||
6939 | var kind = this.track['kind']; | ||
6940 | var tracks = this.player_.textTracks(); | ||
6941 | |||
6942 | _MenuItem.prototype.handleClick.call(this, event); | ||
6943 | |||
6944 | if (!tracks) return; | ||
6945 | |||
6946 | for (var i = 0; i < tracks.length; i++) { | ||
6947 | var track = tracks[i]; | ||
6948 | |||
6949 | if (track['kind'] !== kind) { | ||
6950 | continue; | ||
6951 | } | ||
6952 | |||
6953 | if (track === this.track) { | ||
6954 | track['mode'] = 'showing'; | ||
6955 | } else { | ||
6956 | track['mode'] = 'disabled'; | ||
6957 | } | ||
6958 | } | ||
6959 | }; | ||
6960 | |||
6961 | /** | ||
6962 | * Handle text track change | ||
6963 | * | ||
6964 | * @method handleTracksChange | ||
6965 | */ | ||
6966 | |||
6967 | TextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { | ||
6968 | this.selected(this.track['mode'] === 'showing'); | ||
6969 | }; | ||
6970 | |||
6971 | return TextTrackMenuItem; | ||
6972 | })(_menuMenuItemJs2['default']); | ||
6973 | |||
6974 | _componentJs2['default'].registerComponent('TextTrackMenuItem', TextTrackMenuItem); | ||
6975 | exports['default'] = TextTrackMenuItem; | ||
6976 | module.exports = exports['default']; | ||
6977 | |||
6978 | },{"../../component.js":67,"../../menu/menu-item.js":105,"../../utils/fn.js":134,"global/document":1,"global/window":2}],90:[function(_dereq_,module,exports){ | ||
6979 | /** | ||
6980 | * @file current-time-display.js | ||
6981 | */ | ||
6982 | 'use strict'; | ||
6983 | |||
6984 | exports.__esModule = true; | ||
6985 | |||
6986 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
6987 | |||
6988 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
6989 | |||
6990 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
6991 | |||
6992 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
6993 | |||
6994 | var _componentJs = _dereq_('../../component.js'); | ||
6995 | |||
6996 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
6997 | |||
6998 | var _utilsDomJs = _dereq_('../../utils/dom.js'); | ||
6999 | |||
7000 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
7001 | |||
7002 | var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); | ||
7003 | |||
7004 | var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); | ||
7005 | |||
7006 | /** | ||
7007 | * Displays the current time | ||
7008 | * | ||
7009 | * @param {Player|Object} player | ||
7010 | * @param {Object=} options | ||
7011 | * @extends Component | ||
7012 | * @class CurrentTimeDisplay | ||
7013 | */ | ||
7014 | |||
7015 | var CurrentTimeDisplay = (function (_Component) { | ||
7016 | _inherits(CurrentTimeDisplay, _Component); | ||
7017 | |||
7018 | function CurrentTimeDisplay(player, options) { | ||
7019 | _classCallCheck(this, CurrentTimeDisplay); | ||
7020 | |||
7021 | _Component.call(this, player, options); | ||
7022 | |||
7023 | this.on(player, 'timeupdate', this.updateContent); | ||
7024 | } | ||
7025 | |||
7026 | /** | ||
7027 | * Create the component's DOM element | ||
7028 | * | ||
7029 | * @return {Element} | ||
7030 | * @method createEl | ||
7031 | */ | ||
7032 | |||
7033 | CurrentTimeDisplay.prototype.createEl = function createEl() { | ||
7034 | var el = _Component.prototype.createEl.call(this, 'div', { | ||
7035 | className: 'vjs-current-time vjs-time-control vjs-control' | ||
7036 | }); | ||
7037 | |||
7038 | this.contentEl_ = Dom.createEl('div', { | ||
7039 | className: 'vjs-current-time-display', | ||
7040 | // label the current time for screen reader users | ||
7041 | innerHTML: '<span class="vjs-control-text">Current Time </span>' + '0:00' | ||
7042 | }, { | ||
7043 | // tell screen readers not to automatically read the time as it changes | ||
7044 | 'aria-live': 'off' | ||
7045 | }); | ||
7046 | |||
7047 | el.appendChild(this.contentEl_); | ||
7048 | return el; | ||
7049 | }; | ||
7050 | |||
7051 | /** | ||
7052 | * Update current time display | ||
7053 | * | ||
7054 | * @method updateContent | ||
7055 | */ | ||
7056 | |||
7057 | CurrentTimeDisplay.prototype.updateContent = function updateContent() { | ||
7058 | // Allows for smooth scrubbing, when player can't keep up. | ||
7059 | var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); | ||
7060 | var localizedText = this.localize('Current Time'); | ||
7061 | var formattedTime = _utilsFormatTimeJs2['default'](time, this.player_.duration()); | ||
7062 | if (formattedTime !== this.formattedTime_) { | ||
7063 | this.formattedTime_ = formattedTime; | ||
7064 | this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> ' + formattedTime; | ||
7065 | } | ||
7066 | }; | ||
7067 | |||
7068 | return CurrentTimeDisplay; | ||
7069 | })(_componentJs2['default']); | ||
7070 | |||
7071 | _componentJs2['default'].registerComponent('CurrentTimeDisplay', CurrentTimeDisplay); | ||
7072 | exports['default'] = CurrentTimeDisplay; | ||
7073 | module.exports = exports['default']; | ||
7074 | |||
7075 | },{"../../component.js":67,"../../utils/dom.js":132,"../../utils/format-time.js":135}],91:[function(_dereq_,module,exports){ | ||
7076 | /** | ||
7077 | * @file duration-display.js | ||
7078 | */ | ||
7079 | 'use strict'; | ||
7080 | |||
7081 | exports.__esModule = true; | ||
7082 | |||
7083 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
7084 | |||
7085 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7086 | |||
7087 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7088 | |||
7089 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7090 | |||
7091 | var _componentJs = _dereq_('../../component.js'); | ||
7092 | |||
7093 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
7094 | |||
7095 | var _utilsDomJs = _dereq_('../../utils/dom.js'); | ||
7096 | |||
7097 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
7098 | |||
7099 | var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); | ||
7100 | |||
7101 | var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); | ||
7102 | |||
7103 | /** | ||
7104 | * Displays the duration | ||
7105 | * | ||
7106 | * @param {Player|Object} player | ||
7107 | * @param {Object=} options | ||
7108 | * @extends Component | ||
7109 | * @class DurationDisplay | ||
7110 | */ | ||
7111 | |||
7112 | var DurationDisplay = (function (_Component) { | ||
7113 | _inherits(DurationDisplay, _Component); | ||
7114 | |||
7115 | function DurationDisplay(player, options) { | ||
7116 | _classCallCheck(this, DurationDisplay); | ||
7117 | |||
7118 | _Component.call(this, player, options); | ||
7119 | |||
7120 | // this might need to be changed to 'durationchange' instead of 'timeupdate' eventually, | ||
7121 | // however the durationchange event fires before this.player_.duration() is set, | ||
7122 | // so the value cannot be written out using this method. | ||
7123 | // Once the order of durationchange and this.player_.duration() being set is figured out, | ||
7124 | // this can be updated. | ||
7125 | this.on(player, 'timeupdate', this.updateContent); | ||
7126 | this.on(player, 'loadedmetadata', this.updateContent); | ||
7127 | } | ||
7128 | |||
7129 | /** | ||
7130 | * Create the component's DOM element | ||
7131 | * | ||
7132 | * @return {Element} | ||
7133 | * @method createEl | ||
7134 | */ | ||
7135 | |||
7136 | DurationDisplay.prototype.createEl = function createEl() { | ||
7137 | var el = _Component.prototype.createEl.call(this, 'div', { | ||
7138 | className: 'vjs-duration vjs-time-control vjs-control' | ||
7139 | }); | ||
7140 | |||
7141 | this.contentEl_ = Dom.createEl('div', { | ||
7142 | className: 'vjs-duration-display', | ||
7143 | // label the duration time for screen reader users | ||
7144 | innerHTML: '<span class="vjs-control-text">' + this.localize('Duration Time') + '</span> 0:00' | ||
7145 | }, { | ||
7146 | // tell screen readers not to automatically read the time as it changes | ||
7147 | 'aria-live': 'off' | ||
7148 | }); | ||
7149 | |||
7150 | el.appendChild(this.contentEl_); | ||
7151 | return el; | ||
7152 | }; | ||
7153 | |||
7154 | /** | ||
7155 | * Update duration time display | ||
7156 | * | ||
7157 | * @method updateContent | ||
7158 | */ | ||
7159 | |||
7160 | DurationDisplay.prototype.updateContent = function updateContent() { | ||
7161 | var duration = this.player_.duration(); | ||
7162 | if (duration && this.duration_ !== duration) { | ||
7163 | this.duration_ = duration; | ||
7164 | var localizedText = this.localize('Duration Time'); | ||
7165 | var formattedTime = _utilsFormatTimeJs2['default'](duration); | ||
7166 | this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> ' + formattedTime; // label the duration time for screen reader users | ||
7167 | } | ||
7168 | }; | ||
7169 | |||
7170 | return DurationDisplay; | ||
7171 | })(_componentJs2['default']); | ||
7172 | |||
7173 | _componentJs2['default'].registerComponent('DurationDisplay', DurationDisplay); | ||
7174 | exports['default'] = DurationDisplay; | ||
7175 | module.exports = exports['default']; | ||
7176 | |||
7177 | },{"../../component.js":67,"../../utils/dom.js":132,"../../utils/format-time.js":135}],92:[function(_dereq_,module,exports){ | ||
7178 | /** | ||
7179 | * @file remaining-time-display.js | ||
7180 | */ | ||
7181 | 'use strict'; | ||
7182 | |||
7183 | exports.__esModule = true; | ||
7184 | |||
7185 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
7186 | |||
7187 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7188 | |||
7189 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7190 | |||
7191 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7192 | |||
7193 | var _componentJs = _dereq_('../../component.js'); | ||
7194 | |||
7195 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
7196 | |||
7197 | var _utilsDomJs = _dereq_('../../utils/dom.js'); | ||
7198 | |||
7199 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
7200 | |||
7201 | var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); | ||
7202 | |||
7203 | var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); | ||
7204 | |||
7205 | /** | ||
7206 | * Displays the time left in the video | ||
7207 | * | ||
7208 | * @param {Player|Object} player | ||
7209 | * @param {Object=} options | ||
7210 | * @extends Component | ||
7211 | * @class RemainingTimeDisplay | ||
7212 | */ | ||
7213 | |||
7214 | var RemainingTimeDisplay = (function (_Component) { | ||
7215 | _inherits(RemainingTimeDisplay, _Component); | ||
7216 | |||
7217 | function RemainingTimeDisplay(player, options) { | ||
7218 | _classCallCheck(this, RemainingTimeDisplay); | ||
7219 | |||
7220 | _Component.call(this, player, options); | ||
7221 | |||
7222 | this.on(player, 'timeupdate', this.updateContent); | ||
7223 | } | ||
7224 | |||
7225 | /** | ||
7226 | * Create the component's DOM element | ||
7227 | * | ||
7228 | * @return {Element} | ||
7229 | * @method createEl | ||
7230 | */ | ||
7231 | |||
7232 | RemainingTimeDisplay.prototype.createEl = function createEl() { | ||
7233 | var el = _Component.prototype.createEl.call(this, 'div', { | ||
7234 | className: 'vjs-remaining-time vjs-time-control vjs-control' | ||
7235 | }); | ||
7236 | |||
7237 | this.contentEl_ = Dom.createEl('div', { | ||
7238 | className: 'vjs-remaining-time-display', | ||
7239 | // label the remaining time for screen reader users | ||
7240 | innerHTML: '<span class="vjs-control-text">' + this.localize('Remaining Time') + '</span> -0:00' | ||
7241 | }, { | ||
7242 | // tell screen readers not to automatically read the time as it changes | ||
7243 | 'aria-live': 'off' | ||
7244 | }); | ||
7245 | |||
7246 | el.appendChild(this.contentEl_); | ||
7247 | return el; | ||
7248 | }; | ||
7249 | |||
7250 | /** | ||
7251 | * Update remaining time display | ||
7252 | * | ||
7253 | * @method updateContent | ||
7254 | */ | ||
7255 | |||
7256 | RemainingTimeDisplay.prototype.updateContent = function updateContent() { | ||
7257 | if (this.player_.duration()) { | ||
7258 | var localizedText = this.localize('Remaining Time'); | ||
7259 | var formattedTime = _utilsFormatTimeJs2['default'](this.player_.remainingTime()); | ||
7260 | if (formattedTime !== this.formattedTime_) { | ||
7261 | this.formattedTime_ = formattedTime; | ||
7262 | this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> -' + formattedTime; | ||
7263 | } | ||
7264 | } | ||
7265 | |||
7266 | // Allows for smooth scrubbing, when player can't keep up. | ||
7267 | // var time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime(); | ||
7268 | // this.contentEl_.innerHTML = vjs.formatTime(time, this.player_.duration()); | ||
7269 | }; | ||
7270 | |||
7271 | return RemainingTimeDisplay; | ||
7272 | })(_componentJs2['default']); | ||
7273 | |||
7274 | _componentJs2['default'].registerComponent('RemainingTimeDisplay', RemainingTimeDisplay); | ||
7275 | exports['default'] = RemainingTimeDisplay; | ||
7276 | module.exports = exports['default']; | ||
7277 | |||
7278 | },{"../../component.js":67,"../../utils/dom.js":132,"../../utils/format-time.js":135}],93:[function(_dereq_,module,exports){ | ||
7279 | /** | ||
7280 | * @file time-divider.js | ||
7281 | */ | ||
7282 | 'use strict'; | ||
7283 | |||
7284 | exports.__esModule = true; | ||
7285 | |||
7286 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7287 | |||
7288 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7289 | |||
7290 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7291 | |||
7292 | var _componentJs = _dereq_('../../component.js'); | ||
7293 | |||
7294 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
7295 | |||
7296 | /** | ||
7297 | * The separator between the current time and duration. | ||
7298 | * Can be hidden if it's not needed in the design. | ||
7299 | * | ||
7300 | * @param {Player|Object} player | ||
7301 | * @param {Object=} options | ||
7302 | * @extends Component | ||
7303 | * @class TimeDivider | ||
7304 | */ | ||
7305 | |||
7306 | var TimeDivider = (function (_Component) { | ||
7307 | _inherits(TimeDivider, _Component); | ||
7308 | |||
7309 | function TimeDivider() { | ||
7310 | _classCallCheck(this, TimeDivider); | ||
7311 | |||
7312 | _Component.apply(this, arguments); | ||
7313 | } | ||
7314 | |||
7315 | /** | ||
7316 | * Create the component's DOM element | ||
7317 | * | ||
7318 | * @return {Element} | ||
7319 | * @method createEl | ||
7320 | */ | ||
7321 | |||
7322 | TimeDivider.prototype.createEl = function createEl() { | ||
7323 | return _Component.prototype.createEl.call(this, 'div', { | ||
7324 | className: 'vjs-time-control vjs-time-divider', | ||
7325 | innerHTML: '<div><span>/</span></div>' | ||
7326 | }); | ||
7327 | }; | ||
7328 | |||
7329 | return TimeDivider; | ||
7330 | })(_componentJs2['default']); | ||
7331 | |||
7332 | _componentJs2['default'].registerComponent('TimeDivider', TimeDivider); | ||
7333 | exports['default'] = TimeDivider; | ||
7334 | module.exports = exports['default']; | ||
7335 | |||
7336 | },{"../../component.js":67}],94:[function(_dereq_,module,exports){ | ||
7337 | /** | ||
7338 | * @file volume-bar.js | ||
7339 | */ | ||
7340 | 'use strict'; | ||
7341 | |||
7342 | exports.__esModule = true; | ||
7343 | |||
7344 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
7345 | |||
7346 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7347 | |||
7348 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7349 | |||
7350 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7351 | |||
7352 | var _sliderSliderJs = _dereq_('../../slider/slider.js'); | ||
7353 | |||
7354 | var _sliderSliderJs2 = _interopRequireDefault(_sliderSliderJs); | ||
7355 | |||
7356 | var _componentJs = _dereq_('../../component.js'); | ||
7357 | |||
7358 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
7359 | |||
7360 | var _utilsFnJs = _dereq_('../../utils/fn.js'); | ||
7361 | |||
7362 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
7363 | |||
7364 | // Required children | ||
7365 | |||
7366 | var _volumeLevelJs = _dereq_('./volume-level.js'); | ||
7367 | |||
7368 | var _volumeLevelJs2 = _interopRequireDefault(_volumeLevelJs); | ||
7369 | |||
7370 | /** | ||
7371 | * The bar that contains the volume level and can be clicked on to adjust the level | ||
7372 | * | ||
7373 | * @param {Player|Object} player | ||
7374 | * @param {Object=} options | ||
7375 | * @extends Slider | ||
7376 | * @class VolumeBar | ||
7377 | */ | ||
7378 | |||
7379 | var VolumeBar = (function (_Slider) { | ||
7380 | _inherits(VolumeBar, _Slider); | ||
7381 | |||
7382 | function VolumeBar(player, options) { | ||
7383 | _classCallCheck(this, VolumeBar); | ||
7384 | |||
7385 | _Slider.call(this, player, options); | ||
7386 | this.on(player, 'volumechange', this.updateARIAAttributes); | ||
7387 | player.ready(Fn.bind(this, this.updateARIAAttributes)); | ||
7388 | } | ||
7389 | |||
7390 | /** | ||
7391 | * Create the component's DOM element | ||
7392 | * | ||
7393 | * @return {Element} | ||
7394 | * @method createEl | ||
7395 | */ | ||
7396 | |||
7397 | VolumeBar.prototype.createEl = function createEl() { | ||
7398 | return _Slider.prototype.createEl.call(this, 'div', { | ||
7399 | className: 'vjs-volume-bar vjs-slider-bar' | ||
7400 | }, { | ||
7401 | 'aria-label': 'volume level' | ||
7402 | }); | ||
7403 | }; | ||
7404 | |||
7405 | /** | ||
7406 | * Handle mouse move on volume bar | ||
7407 | * | ||
7408 | * @method handleMouseMove | ||
7409 | */ | ||
7410 | |||
7411 | VolumeBar.prototype.handleMouseMove = function handleMouseMove(event) { | ||
7412 | this.checkMuted(); | ||
7413 | this.player_.volume(this.calculateDistance(event)); | ||
7414 | }; | ||
7415 | |||
7416 | VolumeBar.prototype.checkMuted = function checkMuted() { | ||
7417 | if (this.player_.muted()) { | ||
7418 | this.player_.muted(false); | ||
7419 | } | ||
7420 | }; | ||
7421 | |||
7422 | /** | ||
7423 | * Get percent of volume level | ||
7424 | * | ||
7425 | * @retun {Number} Volume level percent | ||
7426 | * @method getPercent | ||
7427 | */ | ||
7428 | |||
7429 | VolumeBar.prototype.getPercent = function getPercent() { | ||
7430 | if (this.player_.muted()) { | ||
7431 | return 0; | ||
7432 | } else { | ||
7433 | return this.player_.volume(); | ||
7434 | } | ||
7435 | }; | ||
7436 | |||
7437 | /** | ||
7438 | * Increase volume level for keyboard users | ||
7439 | * | ||
7440 | * @method stepForward | ||
7441 | */ | ||
7442 | |||
7443 | VolumeBar.prototype.stepForward = function stepForward() { | ||
7444 | this.checkMuted(); | ||
7445 | this.player_.volume(this.player_.volume() + 0.1); | ||
7446 | }; | ||
7447 | |||
7448 | /** | ||
7449 | * Decrease volume level for keyboard users | ||
7450 | * | ||
7451 | * @method stepBack | ||
7452 | */ | ||
7453 | |||
7454 | VolumeBar.prototype.stepBack = function stepBack() { | ||
7455 | this.checkMuted(); | ||
7456 | this.player_.volume(this.player_.volume() - 0.1); | ||
7457 | }; | ||
7458 | |||
7459 | /** | ||
7460 | * Update ARIA accessibility attributes | ||
7461 | * | ||
7462 | * @method updateARIAAttributes | ||
7463 | */ | ||
7464 | |||
7465 | VolumeBar.prototype.updateARIAAttributes = function updateARIAAttributes() { | ||
7466 | // Current value of volume bar as a percentage | ||
7467 | var volume = (this.player_.volume() * 100).toFixed(2); | ||
7468 | this.el_.setAttribute('aria-valuenow', volume); | ||
7469 | this.el_.setAttribute('aria-valuetext', volume + '%'); | ||
7470 | }; | ||
7471 | |||
7472 | return VolumeBar; | ||
7473 | })(_sliderSliderJs2['default']); | ||
7474 | |||
7475 | VolumeBar.prototype.options_ = { | ||
7476 | children: ['volumeLevel'], | ||
7477 | 'barName': 'volumeLevel' | ||
7478 | }; | ||
7479 | |||
7480 | VolumeBar.prototype.playerEvent = 'volumechange'; | ||
7481 | |||
7482 | _componentJs2['default'].registerComponent('VolumeBar', VolumeBar); | ||
7483 | exports['default'] = VolumeBar; | ||
7484 | module.exports = exports['default']; | ||
7485 | |||
7486 | },{"../../component.js":67,"../../slider/slider.js":114,"../../utils/fn.js":134,"./volume-level.js":96}],95:[function(_dereq_,module,exports){ | ||
7487 | /** | ||
7488 | * @file volume-control.js | ||
7489 | */ | ||
7490 | 'use strict'; | ||
7491 | |||
7492 | exports.__esModule = true; | ||
7493 | |||
7494 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7495 | |||
7496 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7497 | |||
7498 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7499 | |||
7500 | var _componentJs = _dereq_('../../component.js'); | ||
7501 | |||
7502 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
7503 | |||
7504 | // Required children | ||
7505 | |||
7506 | var _volumeBarJs = _dereq_('./volume-bar.js'); | ||
7507 | |||
7508 | var _volumeBarJs2 = _interopRequireDefault(_volumeBarJs); | ||
7509 | |||
7510 | /** | ||
7511 | * The component for controlling the volume level | ||
7512 | * | ||
7513 | * @param {Player|Object} player | ||
7514 | * @param {Object=} options | ||
7515 | * @extends Component | ||
7516 | * @class VolumeControl | ||
7517 | */ | ||
7518 | |||
7519 | var VolumeControl = (function (_Component) { | ||
7520 | _inherits(VolumeControl, _Component); | ||
7521 | |||
7522 | function VolumeControl(player, options) { | ||
7523 | _classCallCheck(this, VolumeControl); | ||
7524 | |||
7525 | _Component.call(this, player, options); | ||
7526 | |||
7527 | // hide volume controls when they're not supported by the current tech | ||
7528 | if (player.tech_ && player.tech_['featuresVolumeControl'] === false) { | ||
7529 | this.addClass('vjs-hidden'); | ||
7530 | } | ||
7531 | this.on(player, 'loadstart', function () { | ||
7532 | if (player.tech_['featuresVolumeControl'] === false) { | ||
7533 | this.addClass('vjs-hidden'); | ||
7534 | } else { | ||
7535 | this.removeClass('vjs-hidden'); | ||
7536 | } | ||
7537 | }); | ||
7538 | } | ||
7539 | |||
7540 | /** | ||
7541 | * Create the component's DOM element | ||
7542 | * | ||
7543 | * @return {Element} | ||
7544 | * @method createEl | ||
7545 | */ | ||
7546 | |||
7547 | VolumeControl.prototype.createEl = function createEl() { | ||
7548 | return _Component.prototype.createEl.call(this, 'div', { | ||
7549 | className: 'vjs-volume-control vjs-control' | ||
7550 | }); | ||
7551 | }; | ||
7552 | |||
7553 | return VolumeControl; | ||
7554 | })(_componentJs2['default']); | ||
7555 | |||
7556 | VolumeControl.prototype.options_ = { | ||
7557 | children: ['volumeBar'] | ||
7558 | }; | ||
7559 | |||
7560 | _componentJs2['default'].registerComponent('VolumeControl', VolumeControl); | ||
7561 | exports['default'] = VolumeControl; | ||
7562 | module.exports = exports['default']; | ||
7563 | |||
7564 | },{"../../component.js":67,"./volume-bar.js":94}],96:[function(_dereq_,module,exports){ | ||
7565 | /** | ||
7566 | * @file volume-level.js | ||
7567 | */ | ||
7568 | 'use strict'; | ||
7569 | |||
7570 | exports.__esModule = true; | ||
7571 | |||
7572 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7573 | |||
7574 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7575 | |||
7576 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7577 | |||
7578 | var _componentJs = _dereq_('../../component.js'); | ||
7579 | |||
7580 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
7581 | |||
7582 | /** | ||
7583 | * Shows volume level | ||
7584 | * | ||
7585 | * @param {Player|Object} player | ||
7586 | * @param {Object=} options | ||
7587 | * @extends Component | ||
7588 | * @class VolumeLevel | ||
7589 | */ | ||
7590 | |||
7591 | var VolumeLevel = (function (_Component) { | ||
7592 | _inherits(VolumeLevel, _Component); | ||
7593 | |||
7594 | function VolumeLevel() { | ||
7595 | _classCallCheck(this, VolumeLevel); | ||
7596 | |||
7597 | _Component.apply(this, arguments); | ||
7598 | } | ||
7599 | |||
7600 | /** | ||
7601 | * Create the component's DOM element | ||
7602 | * | ||
7603 | * @return {Element} | ||
7604 | * @method createEl | ||
7605 | */ | ||
7606 | |||
7607 | VolumeLevel.prototype.createEl = function createEl() { | ||
7608 | return _Component.prototype.createEl.call(this, 'div', { | ||
7609 | className: 'vjs-volume-level', | ||
7610 | innerHTML: '<span class="vjs-control-text"></span>' | ||
7611 | }); | ||
7612 | }; | ||
7613 | |||
7614 | return VolumeLevel; | ||
7615 | })(_componentJs2['default']); | ||
7616 | |||
7617 | _componentJs2['default'].registerComponent('VolumeLevel', VolumeLevel); | ||
7618 | exports['default'] = VolumeLevel; | ||
7619 | module.exports = exports['default']; | ||
7620 | |||
7621 | },{"../../component.js":67}],97:[function(_dereq_,module,exports){ | ||
7622 | /** | ||
7623 | * @file volume-menu-button.js | ||
7624 | */ | ||
7625 | 'use strict'; | ||
7626 | |||
7627 | exports.__esModule = true; | ||
7628 | |||
7629 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7630 | |||
7631 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
7632 | |||
7633 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7634 | |||
7635 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7636 | |||
7637 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
7638 | |||
7639 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
7640 | |||
7641 | var _componentJs = _dereq_('../component.js'); | ||
7642 | |||
7643 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
7644 | |||
7645 | var _popupPopupJs = _dereq_('../popup/popup.js'); | ||
7646 | |||
7647 | var _popupPopupJs2 = _interopRequireDefault(_popupPopupJs); | ||
7648 | |||
7649 | var _popupPopupButtonJs = _dereq_('../popup/popup-button.js'); | ||
7650 | |||
7651 | var _popupPopupButtonJs2 = _interopRequireDefault(_popupPopupButtonJs); | ||
7652 | |||
7653 | var _muteToggleJs = _dereq_('./mute-toggle.js'); | ||
7654 | |||
7655 | var _muteToggleJs2 = _interopRequireDefault(_muteToggleJs); | ||
7656 | |||
7657 | var _volumeControlVolumeBarJs = _dereq_('./volume-control/volume-bar.js'); | ||
7658 | |||
7659 | var _volumeControlVolumeBarJs2 = _interopRequireDefault(_volumeControlVolumeBarJs); | ||
7660 | |||
7661 | var _globalDocument = _dereq_('global/document'); | ||
7662 | |||
7663 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
7664 | |||
7665 | /** | ||
7666 | * Button for volume popup | ||
7667 | * | ||
7668 | * @param {Player|Object} player | ||
7669 | * @param {Object=} options | ||
7670 | * @extends PopupButton | ||
7671 | * @class VolumeMenuButton | ||
7672 | */ | ||
7673 | |||
7674 | var VolumeMenuButton = (function (_PopupButton) { | ||
7675 | _inherits(VolumeMenuButton, _PopupButton); | ||
7676 | |||
7677 | function VolumeMenuButton(player) { | ||
7678 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
7679 | |||
7680 | _classCallCheck(this, VolumeMenuButton); | ||
7681 | |||
7682 | // Default to inline | ||
7683 | if (options.inline === undefined) { | ||
7684 | options.inline = true; | ||
7685 | } | ||
7686 | |||
7687 | // If the vertical option isn't passed at all, default to true. | ||
7688 | if (options.vertical === undefined) { | ||
7689 | // If an inline volumeMenuButton is used, we should default to using | ||
7690 | // a horizontal slider for obvious reasons. | ||
7691 | if (options.inline) { | ||
7692 | options.vertical = false; | ||
7693 | } else { | ||
7694 | options.vertical = true; | ||
7695 | } | ||
7696 | } | ||
7697 | |||
7698 | // The vertical option needs to be set on the volumeBar as well, | ||
7699 | // since that will need to be passed along to the VolumeBar constructor | ||
7700 | options.volumeBar = options.volumeBar || {}; | ||
7701 | options.volumeBar.vertical = !!options.vertical; | ||
7702 | |||
7703 | _PopupButton.call(this, player, options); | ||
7704 | |||
7705 | // Same listeners as MuteToggle | ||
7706 | this.on(player, 'volumechange', this.volumeUpdate); | ||
7707 | this.on(player, 'loadstart', this.volumeUpdate); | ||
7708 | |||
7709 | // hide mute toggle if the current tech doesn't support volume control | ||
7710 | function updateVisibility() { | ||
7711 | if (player.tech_ && player.tech_['featuresVolumeControl'] === false) { | ||
7712 | this.addClass('vjs-hidden'); | ||
7713 | } else { | ||
7714 | this.removeClass('vjs-hidden'); | ||
7715 | } | ||
7716 | } | ||
7717 | |||
7718 | updateVisibility.call(this); | ||
7719 | this.on(player, 'loadstart', updateVisibility); | ||
7720 | |||
7721 | this.on(this.volumeBar, ['slideractive', 'focus'], function () { | ||
7722 | this.addClass('vjs-slider-active'); | ||
7723 | }); | ||
7724 | |||
7725 | this.on(this.volumeBar, ['sliderinactive', 'blur'], function () { | ||
7726 | this.removeClass('vjs-slider-active'); | ||
7727 | }); | ||
7728 | |||
7729 | this.on(this.volumeBar, ['focus'], function () { | ||
7730 | this.addClass('vjs-lock-showing'); | ||
7731 | }); | ||
7732 | |||
7733 | this.on(this.volumeBar, ['blur'], function () { | ||
7734 | this.removeClass('vjs-lock-showing'); | ||
7735 | }); | ||
7736 | } | ||
7737 | |||
7738 | /** | ||
7739 | * Allow sub components to stack CSS class names | ||
7740 | * | ||
7741 | * @return {String} The constructed class name | ||
7742 | * @method buildCSSClass | ||
7743 | */ | ||
7744 | |||
7745 | VolumeMenuButton.prototype.buildCSSClass = function buildCSSClass() { | ||
7746 | var orientationClass = ''; | ||
7747 | if (!!this.options_.vertical) { | ||
7748 | orientationClass = 'vjs-volume-menu-button-vertical'; | ||
7749 | } else { | ||
7750 | orientationClass = 'vjs-volume-menu-button-horizontal'; | ||
7751 | } | ||
7752 | |||
7753 | return 'vjs-volume-menu-button ' + _PopupButton.prototype.buildCSSClass.call(this) + ' ' + orientationClass; | ||
7754 | }; | ||
7755 | |||
7756 | /** | ||
7757 | * Allow sub components to stack CSS class names | ||
7758 | * | ||
7759 | * @return {Popup} The volume popup button | ||
7760 | * @method createPopup | ||
7761 | */ | ||
7762 | |||
7763 | VolumeMenuButton.prototype.createPopup = function createPopup() { | ||
7764 | var popup = new _popupPopupJs2['default'](this.player_, { | ||
7765 | contentElType: 'div' | ||
7766 | }); | ||
7767 | |||
7768 | var vb = new _volumeControlVolumeBarJs2['default'](this.player_, this.options_.volumeBar); | ||
7769 | |||
7770 | popup.addChild(vb); | ||
7771 | |||
7772 | this.menuContent = popup; | ||
7773 | this.volumeBar = vb; | ||
7774 | |||
7775 | this.attachVolumeBarEvents(); | ||
7776 | |||
7777 | return popup; | ||
7778 | }; | ||
7779 | |||
7780 | /** | ||
7781 | * Handle click on volume popup and calls super | ||
7782 | * | ||
7783 | * @method handleClick | ||
7784 | */ | ||
7785 | |||
7786 | VolumeMenuButton.prototype.handleClick = function handleClick() { | ||
7787 | _muteToggleJs2['default'].prototype.handleClick.call(this); | ||
7788 | _PopupButton.prototype.handleClick.call(this); | ||
7789 | }; | ||
7790 | |||
7791 | VolumeMenuButton.prototype.attachVolumeBarEvents = function attachVolumeBarEvents() { | ||
7792 | this.menuContent.on(['mousedown', 'touchdown'], Fn.bind(this, this.handleMouseDown)); | ||
7793 | }; | ||
7794 | |||
7795 | VolumeMenuButton.prototype.handleMouseDown = function handleMouseDown(event) { | ||
7796 | this.on(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove)); | ||
7797 | this.on(_globalDocument2['default'], ['mouseup', 'touchend'], this.handleMouseUp); | ||
7798 | }; | ||
7799 | |||
7800 | VolumeMenuButton.prototype.handleMouseUp = function handleMouseUp(event) { | ||
7801 | this.off(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove)); | ||
7802 | }; | ||
7803 | |||
7804 | return VolumeMenuButton; | ||
7805 | })(_popupPopupButtonJs2['default']); | ||
7806 | |||
7807 | VolumeMenuButton.prototype.volumeUpdate = _muteToggleJs2['default'].prototype.update; | ||
7808 | VolumeMenuButton.prototype.controlText_ = 'Mute'; | ||
7809 | |||
7810 | _componentJs2['default'].registerComponent('VolumeMenuButton', VolumeMenuButton); | ||
7811 | exports['default'] = VolumeMenuButton; | ||
7812 | module.exports = exports['default']; | ||
7813 | |||
7814 | },{"../component.js":67,"../popup/popup-button.js":110,"../popup/popup.js":111,"../utils/fn.js":134,"./mute-toggle.js":71,"./volume-control/volume-bar.js":94,"global/document":1}],98:[function(_dereq_,module,exports){ | ||
7815 | /** | ||
7816 | * @file error-display.js | ||
7817 | */ | ||
7818 | 'use strict'; | ||
7819 | |||
7820 | exports.__esModule = true; | ||
7821 | |||
7822 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
7823 | |||
7824 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7825 | |||
7826 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
7827 | |||
7828 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
7829 | |||
7830 | var _component = _dereq_('./component'); | ||
7831 | |||
7832 | var _component2 = _interopRequireDefault(_component); | ||
7833 | |||
7834 | var _modalDialog = _dereq_('./modal-dialog'); | ||
7835 | |||
7836 | var _modalDialog2 = _interopRequireDefault(_modalDialog); | ||
7837 | |||
7838 | var _utilsDom = _dereq_('./utils/dom'); | ||
7839 | |||
7840 | var Dom = _interopRequireWildcard(_utilsDom); | ||
7841 | |||
7842 | var _utilsMergeOptions = _dereq_('./utils/merge-options'); | ||
7843 | |||
7844 | var _utilsMergeOptions2 = _interopRequireDefault(_utilsMergeOptions); | ||
7845 | |||
7846 | /** | ||
7847 | * Display that an error has occurred making the video unplayable. | ||
7848 | * | ||
7849 | * @extends ModalDialog | ||
7850 | * @class ErrorDisplay | ||
7851 | */ | ||
7852 | |||
7853 | var ErrorDisplay = (function (_ModalDialog) { | ||
7854 | _inherits(ErrorDisplay, _ModalDialog); | ||
7855 | |||
7856 | /** | ||
7857 | * Constructor for error display modal. | ||
7858 | * | ||
7859 | * @param {Player} player | ||
7860 | * @param {Object} [options] | ||
7861 | */ | ||
7862 | |||
7863 | function ErrorDisplay(player, options) { | ||
7864 | _classCallCheck(this, ErrorDisplay); | ||
7865 | |||
7866 | _ModalDialog.call(this, player, options); | ||
7867 | this.on(player, 'error', this.open); | ||
7868 | } | ||
7869 | |||
7870 | /** | ||
7871 | * Include the old class for backward-compatibility. | ||
7872 | * | ||
7873 | * This can be removed in 6.0. | ||
7874 | * | ||
7875 | * @method buildCSSClass | ||
7876 | * @deprecated | ||
7877 | * @return {String} | ||
7878 | */ | ||
7879 | |||
7880 | ErrorDisplay.prototype.buildCSSClass = function buildCSSClass() { | ||
7881 | return 'vjs-error-display ' + _ModalDialog.prototype.buildCSSClass.call(this); | ||
7882 | }; | ||
7883 | |||
7884 | /** | ||
7885 | * Generates the modal content based on the player error. | ||
7886 | * | ||
7887 | * @return {String|Null} | ||
7888 | */ | ||
7889 | |||
7890 | ErrorDisplay.prototype.content = function content() { | ||
7891 | var error = this.player().error(); | ||
7892 | return error ? this.localize(error.message) : ''; | ||
7893 | }; | ||
7894 | |||
7895 | return ErrorDisplay; | ||
7896 | })(_modalDialog2['default']); | ||
7897 | |||
7898 | ErrorDisplay.prototype.options_ = _utilsMergeOptions2['default'](_modalDialog2['default'].prototype.options_, { | ||
7899 | fillAlways: true, | ||
7900 | temporary: false, | ||
7901 | uncloseable: true | ||
7902 | }); | ||
7903 | |||
7904 | _component2['default'].registerComponent('ErrorDisplay', ErrorDisplay); | ||
7905 | exports['default'] = ErrorDisplay; | ||
7906 | module.exports = exports['default']; | ||
7907 | |||
7908 | },{"./component":67,"./modal-dialog":107,"./utils/dom":132,"./utils/merge-options":138}],99:[function(_dereq_,module,exports){ | ||
7909 | /** | ||
7910 | * @file event-target.js | ||
7911 | */ | ||
7912 | 'use strict'; | ||
7913 | |||
7914 | exports.__esModule = true; | ||
7915 | |||
7916 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
7917 | |||
7918 | var _utilsEventsJs = _dereq_('./utils/events.js'); | ||
7919 | |||
7920 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
7921 | |||
7922 | var EventTarget = function EventTarget() {}; | ||
7923 | |||
7924 | EventTarget.prototype.allowedEvents_ = {}; | ||
7925 | |||
7926 | EventTarget.prototype.on = function (type, fn) { | ||
7927 | // Remove the addEventListener alias before calling Events.on | ||
7928 | // so we don't get into an infinite type loop | ||
7929 | var ael = this.addEventListener; | ||
7930 | this.addEventListener = Function.prototype; | ||
7931 | Events.on(this, type, fn); | ||
7932 | this.addEventListener = ael; | ||
7933 | }; | ||
7934 | EventTarget.prototype.addEventListener = EventTarget.prototype.on; | ||
7935 | |||
7936 | EventTarget.prototype.off = function (type, fn) { | ||
7937 | Events.off(this, type, fn); | ||
7938 | }; | ||
7939 | EventTarget.prototype.removeEventListener = EventTarget.prototype.off; | ||
7940 | |||
7941 | EventTarget.prototype.one = function (type, fn) { | ||
7942 | Events.one(this, type, fn); | ||
7943 | }; | ||
7944 | |||
7945 | EventTarget.prototype.trigger = function (event) { | ||
7946 | var type = event.type || event; | ||
7947 | |||
7948 | if (typeof event === 'string') { | ||
7949 | event = { | ||
7950 | type: type | ||
7951 | }; | ||
7952 | } | ||
7953 | event = Events.fixEvent(event); | ||
7954 | |||
7955 | if (this.allowedEvents_[type] && this['on' + type]) { | ||
7956 | this['on' + type](event); | ||
7957 | } | ||
7958 | |||
7959 | Events.trigger(this, event); | ||
7960 | }; | ||
7961 | // The standard DOM EventTarget.dispatchEvent() is aliased to trigger() | ||
7962 | EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger; | ||
7963 | |||
7964 | exports['default'] = EventTarget; | ||
7965 | module.exports = exports['default']; | ||
7966 | |||
7967 | },{"./utils/events.js":133}],100:[function(_dereq_,module,exports){ | ||
7968 | 'use strict'; | ||
7969 | |||
7970 | exports.__esModule = true; | ||
7971 | |||
7972 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
7973 | |||
7974 | var _utilsLog = _dereq_('./utils/log'); | ||
7975 | |||
7976 | var _utilsLog2 = _interopRequireDefault(_utilsLog); | ||
7977 | |||
7978 | /* | ||
7979 | * @file extend.js | ||
7980 | * | ||
7981 | * A combination of node inherits and babel's inherits (after transpile). | ||
7982 | * Both work the same but node adds `super_` to the subClass | ||
7983 | * and Bable adds the superClass as __proto__. Both seem useful. | ||
7984 | */ | ||
7985 | var _inherits = function _inherits(subClass, superClass) { | ||
7986 | if (typeof superClass !== 'function' && superClass !== null) { | ||
7987 | throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); | ||
7988 | } | ||
7989 | |||
7990 | subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
7991 | constructor: { | ||
7992 | value: subClass, | ||
7993 | enumerable: false, | ||
7994 | writable: true, | ||
7995 | configurable: true | ||
7996 | } | ||
7997 | }); | ||
7998 | |||
7999 | if (superClass) { | ||
8000 | // node | ||
8001 | subClass.super_ = superClass; | ||
8002 | } | ||
8003 | }; | ||
8004 | |||
8005 | /* | ||
8006 | * Function for subclassing using the same inheritance that | ||
8007 | * videojs uses internally | ||
8008 | * ```js | ||
8009 | * var Button = videojs.getComponent('Button'); | ||
8010 | * ``` | ||
8011 | * ```js | ||
8012 | * var MyButton = videojs.extend(Button, { | ||
8013 | * constructor: function(player, options) { | ||
8014 | * Button.call(this, player, options); | ||
8015 | * }, | ||
8016 | * onClick: function() { | ||
8017 | * // doSomething | ||
8018 | * } | ||
8019 | * }); | ||
8020 | * ``` | ||
8021 | */ | ||
8022 | var extendFn = function extendFn(superClass) { | ||
8023 | var subClassMethods = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
8024 | |||
8025 | var subClass = function subClass() { | ||
8026 | superClass.apply(this, arguments); | ||
8027 | }; | ||
8028 | var methods = {}; | ||
8029 | |||
8030 | if (typeof subClassMethods === 'object') { | ||
8031 | if (typeof subClassMethods.init === 'function') { | ||
8032 | _utilsLog2['default'].warn('Constructor logic via init() is deprecated; please use constructor() instead.'); | ||
8033 | subClassMethods.constructor = subClassMethods.init; | ||
8034 | } | ||
8035 | if (subClassMethods.constructor !== Object.prototype.constructor) { | ||
8036 | subClass = subClassMethods.constructor; | ||
8037 | } | ||
8038 | methods = subClassMethods; | ||
8039 | } else if (typeof subClassMethods === 'function') { | ||
8040 | subClass = subClassMethods; | ||
8041 | } | ||
8042 | |||
8043 | _inherits(subClass, superClass); | ||
8044 | |||
8045 | // Extend subObj's prototype with functions and other properties from props | ||
8046 | for (var name in methods) { | ||
8047 | if (methods.hasOwnProperty(name)) { | ||
8048 | subClass.prototype[name] = methods[name]; | ||
8049 | } | ||
8050 | } | ||
8051 | |||
8052 | return subClass; | ||
8053 | }; | ||
8054 | |||
8055 | exports['default'] = extendFn; | ||
8056 | module.exports = exports['default']; | ||
8057 | |||
8058 | },{"./utils/log":137}],101:[function(_dereq_,module,exports){ | ||
8059 | /** | ||
8060 | * @file fullscreen-api.js | ||
8061 | */ | ||
8062 | 'use strict'; | ||
8063 | |||
8064 | exports.__esModule = true; | ||
8065 | |||
8066 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
8067 | |||
8068 | var _globalDocument = _dereq_('global/document'); | ||
8069 | |||
8070 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
8071 | |||
8072 | /* | ||
8073 | * Store the browser-specific methods for the fullscreen API | ||
8074 | * @type {Object|undefined} | ||
8075 | * @private | ||
8076 | */ | ||
8077 | var FullscreenApi = {}; | ||
8078 | |||
8079 | // browser API methods | ||
8080 | // map approach from Screenful.js - https://github.com/sindresorhus/screenfull.js | ||
8081 | var apiMap = [ | ||
8082 | // Spec: https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html | ||
8083 | ['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'], | ||
8084 | // WebKit | ||
8085 | ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], | ||
8086 | // Old WebKit (Safari 5.1) | ||
8087 | ['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], | ||
8088 | // Mozilla | ||
8089 | ['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'], | ||
8090 | // Microsoft | ||
8091 | ['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']]; | ||
8092 | |||
8093 | var specApi = apiMap[0]; | ||
8094 | var browserApi = undefined; | ||
8095 | |||
8096 | // determine the supported set of functions | ||
8097 | for (var i = 0; i < apiMap.length; i++) { | ||
8098 | // check for exitFullscreen function | ||
8099 | if (apiMap[i][1] in _globalDocument2['default']) { | ||
8100 | browserApi = apiMap[i]; | ||
8101 | break; | ||
8102 | } | ||
8103 | } | ||
8104 | |||
8105 | // map the browser API names to the spec API names | ||
8106 | if (browserApi) { | ||
8107 | for (var i = 0; i < browserApi.length; i++) { | ||
8108 | FullscreenApi[specApi[i]] = browserApi[i]; | ||
8109 | } | ||
8110 | } | ||
8111 | |||
8112 | exports['default'] = FullscreenApi; | ||
8113 | module.exports = exports['default']; | ||
8114 | |||
8115 | },{"global/document":1}],102:[function(_dereq_,module,exports){ | ||
8116 | /** | ||
8117 | * @file loading-spinner.js | ||
8118 | */ | ||
8119 | 'use strict'; | ||
8120 | |||
8121 | exports.__esModule = true; | ||
8122 | |||
8123 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
8124 | |||
8125 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
8126 | |||
8127 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
8128 | |||
8129 | var _component = _dereq_('./component'); | ||
8130 | |||
8131 | var _component2 = _interopRequireDefault(_component); | ||
8132 | |||
8133 | /* Loading Spinner | ||
8134 | ================================================================================ */ | ||
8135 | /** | ||
8136 | * Loading spinner for waiting events | ||
8137 | * | ||
8138 | * @extends Component | ||
8139 | * @class LoadingSpinner | ||
8140 | */ | ||
8141 | |||
8142 | var LoadingSpinner = (function (_Component) { | ||
8143 | _inherits(LoadingSpinner, _Component); | ||
8144 | |||
8145 | function LoadingSpinner() { | ||
8146 | _classCallCheck(this, LoadingSpinner); | ||
8147 | |||
8148 | _Component.apply(this, arguments); | ||
8149 | } | ||
8150 | |||
8151 | /** | ||
8152 | * Create the component's DOM element | ||
8153 | * | ||
8154 | * @method createEl | ||
8155 | */ | ||
8156 | |||
8157 | LoadingSpinner.prototype.createEl = function createEl() { | ||
8158 | return _Component.prototype.createEl.call(this, 'div', { | ||
8159 | className: 'vjs-loading-spinner', | ||
8160 | dir: 'ltr' | ||
8161 | }); | ||
8162 | }; | ||
8163 | |||
8164 | return LoadingSpinner; | ||
8165 | })(_component2['default']); | ||
8166 | |||
8167 | _component2['default'].registerComponent('LoadingSpinner', LoadingSpinner); | ||
8168 | exports['default'] = LoadingSpinner; | ||
8169 | module.exports = exports['default']; | ||
8170 | |||
8171 | },{"./component":67}],103:[function(_dereq_,module,exports){ | ||
8172 | /** | ||
8173 | * @file media-error.js | ||
8174 | */ | ||
8175 | 'use strict'; | ||
8176 | |||
8177 | exports.__esModule = true; | ||
8178 | |||
8179 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
8180 | |||
8181 | var _objectAssign = _dereq_('object.assign'); | ||
8182 | |||
8183 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
8184 | |||
8185 | /* | ||
8186 | * Custom MediaError to mimic the HTML5 MediaError | ||
8187 | * | ||
8188 | * @param {Number} code The media error code | ||
8189 | */ | ||
8190 | var MediaError = function MediaError(code) { | ||
8191 | if (typeof code === 'number') { | ||
8192 | this.code = code; | ||
8193 | } else if (typeof code === 'string') { | ||
8194 | // default code is zero, so this is a custom error | ||
8195 | this.message = code; | ||
8196 | } else if (typeof code === 'object') { | ||
8197 | // object | ||
8198 | _objectAssign2['default'](this, code); | ||
8199 | } | ||
8200 | |||
8201 | if (!this.message) { | ||
8202 | this.message = MediaError.defaultMessages[this.code] || ''; | ||
8203 | } | ||
8204 | }; | ||
8205 | |||
8206 | /* | ||
8207 | * The error code that refers two one of the defined | ||
8208 | * MediaError types | ||
8209 | * | ||
8210 | * @type {Number} | ||
8211 | */ | ||
8212 | MediaError.prototype.code = 0; | ||
8213 | |||
8214 | /* | ||
8215 | * An optional message to be shown with the error. | ||
8216 | * Message is not part of the HTML5 video spec | ||
8217 | * but allows for more informative custom errors. | ||
8218 | * | ||
8219 | * @type {String} | ||
8220 | */ | ||
8221 | MediaError.prototype.message = ''; | ||
8222 | |||
8223 | /* | ||
8224 | * An optional status code that can be set by plugins | ||
8225 | * to allow even more detail about the error. | ||
8226 | * For example the HLS plugin might provide the specific | ||
8227 | * HTTP status code that was returned when the error | ||
8228 | * occurred, then allowing a custom error overlay | ||
8229 | * to display more information. | ||
8230 | * | ||
8231 | * @type {Array} | ||
8232 | */ | ||
8233 | MediaError.prototype.status = null; | ||
8234 | |||
8235 | MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', // = 0 | ||
8236 | 'MEDIA_ERR_ABORTED', // = 1 | ||
8237 | 'MEDIA_ERR_NETWORK', // = 2 | ||
8238 | 'MEDIA_ERR_DECODE', // = 3 | ||
8239 | 'MEDIA_ERR_SRC_NOT_SUPPORTED', // = 4 | ||
8240 | 'MEDIA_ERR_ENCRYPTED' // = 5 | ||
8241 | ]; | ||
8242 | |||
8243 | MediaError.defaultMessages = { | ||
8244 | 1: 'You aborted the media playback', | ||
8245 | 2: 'A network error caused the media download to fail part-way.', | ||
8246 | 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.', | ||
8247 | 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.', | ||
8248 | 5: 'The media is encrypted and we do not have the keys to decrypt it.' | ||
8249 | }; | ||
8250 | |||
8251 | // Add types as properties on MediaError | ||
8252 | // e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; | ||
8253 | for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { | ||
8254 | MediaError[MediaError.errorTypes[errNum]] = errNum; | ||
8255 | // values should be accessible on both the class and instance | ||
8256 | MediaError.prototype[MediaError.errorTypes[errNum]] = errNum; | ||
8257 | } | ||
8258 | |||
8259 | exports['default'] = MediaError; | ||
8260 | module.exports = exports['default']; | ||
8261 | |||
8262 | },{"object.assign":45}],104:[function(_dereq_,module,exports){ | ||
8263 | /** | ||
8264 | * @file menu-button.js | ||
8265 | */ | ||
8266 | 'use strict'; | ||
8267 | |||
8268 | exports.__esModule = true; | ||
8269 | |||
8270 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
8271 | |||
8272 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
8273 | |||
8274 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
8275 | |||
8276 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
8277 | |||
8278 | var _clickableComponentJs = _dereq_('../clickable-component.js'); | ||
8279 | |||
8280 | var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); | ||
8281 | |||
8282 | var _componentJs = _dereq_('../component.js'); | ||
8283 | |||
8284 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
8285 | |||
8286 | var _menuJs = _dereq_('./menu.js'); | ||
8287 | |||
8288 | var _menuJs2 = _interopRequireDefault(_menuJs); | ||
8289 | |||
8290 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
8291 | |||
8292 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
8293 | |||
8294 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
8295 | |||
8296 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
8297 | |||
8298 | var _utilsToTitleCaseJs = _dereq_('../utils/to-title-case.js'); | ||
8299 | |||
8300 | var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); | ||
8301 | |||
8302 | /** | ||
8303 | * A button class with a popup menu | ||
8304 | * | ||
8305 | * @param {Player|Object} player | ||
8306 | * @param {Object=} options | ||
8307 | * @extends Button | ||
8308 | * @class MenuButton | ||
8309 | */ | ||
8310 | |||
8311 | var MenuButton = (function (_ClickableComponent) { | ||
8312 | _inherits(MenuButton, _ClickableComponent); | ||
8313 | |||
8314 | function MenuButton(player) { | ||
8315 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
8316 | |||
8317 | _classCallCheck(this, MenuButton); | ||
8318 | |||
8319 | _ClickableComponent.call(this, player, options); | ||
8320 | |||
8321 | this.update(); | ||
8322 | |||
8323 | this.el_.setAttribute('aria-haspopup', true); | ||
8324 | this.el_.setAttribute('role', 'menuitem'); | ||
8325 | this.on('keydown', this.handleSubmenuKeyPress); | ||
8326 | } | ||
8327 | |||
8328 | /** | ||
8329 | * Update menu | ||
8330 | * | ||
8331 | * @method update | ||
8332 | */ | ||
8333 | |||
8334 | MenuButton.prototype.update = function update() { | ||
8335 | var menu = this.createMenu(); | ||
8336 | |||
8337 | if (this.menu) { | ||
8338 | this.removeChild(this.menu); | ||
8339 | } | ||
8340 | |||
8341 | this.menu = menu; | ||
8342 | this.addChild(menu); | ||
8343 | |||
8344 | /** | ||
8345 | * Track the state of the menu button | ||
8346 | * | ||
8347 | * @type {Boolean} | ||
8348 | * @private | ||
8349 | */ | ||
8350 | this.buttonPressed_ = false; | ||
8351 | this.el_.setAttribute('aria-expanded', false); | ||
8352 | |||
8353 | if (this.items && this.items.length === 0) { | ||
8354 | this.hide(); | ||
8355 | } else if (this.items && this.items.length > 1) { | ||
8356 | this.show(); | ||
8357 | } | ||
8358 | }; | ||
8359 | |||
8360 | /** | ||
8361 | * Create menu | ||
8362 | * | ||
8363 | * @return {Menu} The constructed menu | ||
8364 | * @method createMenu | ||
8365 | */ | ||
8366 | |||
8367 | MenuButton.prototype.createMenu = function createMenu() { | ||
8368 | var menu = new _menuJs2['default'](this.player_); | ||
8369 | |||
8370 | // Add a title list item to the top | ||
8371 | if (this.options_.title) { | ||
8372 | var title = Dom.createEl('li', { | ||
8373 | className: 'vjs-menu-title', | ||
8374 | innerHTML: _utilsToTitleCaseJs2['default'](this.options_.title), | ||
8375 | tabIndex: -1 | ||
8376 | }); | ||
8377 | menu.children_.unshift(title); | ||
8378 | Dom.insertElFirst(title, menu.contentEl()); | ||
8379 | } | ||
8380 | |||
8381 | this.items = this['createItems'](); | ||
8382 | |||
8383 | if (this.items) { | ||
8384 | // Add menu items to the menu | ||
8385 | for (var i = 0; i < this.items.length; i++) { | ||
8386 | menu.addItem(this.items[i]); | ||
8387 | } | ||
8388 | } | ||
8389 | |||
8390 | return menu; | ||
8391 | }; | ||
8392 | |||
8393 | /** | ||
8394 | * Create the list of menu items. Specific to each subclass. | ||
8395 | * | ||
8396 | * @method createItems | ||
8397 | */ | ||
8398 | |||
8399 | MenuButton.prototype.createItems = function createItems() {}; | ||
8400 | |||
8401 | /** | ||
8402 | * Create the component's DOM element | ||
8403 | * | ||
8404 | * @return {Element} | ||
8405 | * @method createEl | ||
8406 | */ | ||
8407 | |||
8408 | MenuButton.prototype.createEl = function createEl() { | ||
8409 | return _ClickableComponent.prototype.createEl.call(this, 'div', { | ||
8410 | className: this.buildCSSClass() | ||
8411 | }); | ||
8412 | }; | ||
8413 | |||
8414 | /** | ||
8415 | * Allow sub components to stack CSS class names | ||
8416 | * | ||
8417 | * @return {String} The constructed class name | ||
8418 | * @method buildCSSClass | ||
8419 | */ | ||
8420 | |||
8421 | MenuButton.prototype.buildCSSClass = function buildCSSClass() { | ||
8422 | var menuButtonClass = 'vjs-menu-button'; | ||
8423 | |||
8424 | // If the inline option is passed, we want to use different styles altogether. | ||
8425 | if (this.options_.inline === true) { | ||
8426 | menuButtonClass += '-inline'; | ||
8427 | } else { | ||
8428 | menuButtonClass += '-popup'; | ||
8429 | } | ||
8430 | |||
8431 | return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this); | ||
8432 | }; | ||
8433 | |||
8434 | /** | ||
8435 | * When you click the button it adds focus, which | ||
8436 | * will show the menu indefinitely. | ||
8437 | * So we'll remove focus when the mouse leaves the button. | ||
8438 | * Focus is needed for tab navigation. | ||
8439 | * Allow sub components to stack CSS class names | ||
8440 | * | ||
8441 | * @method handleClick | ||
8442 | */ | ||
8443 | |||
8444 | MenuButton.prototype.handleClick = function handleClick() { | ||
8445 | this.one('mouseout', Fn.bind(this, function () { | ||
8446 | this.menu.unlockShowing(); | ||
8447 | this.el_.blur(); | ||
8448 | })); | ||
8449 | if (this.buttonPressed_) { | ||
8450 | this.unpressButton(); | ||
8451 | } else { | ||
8452 | this.pressButton(); | ||
8453 | } | ||
8454 | }; | ||
8455 | |||
8456 | /** | ||
8457 | * Handle key press on menu | ||
8458 | * | ||
8459 | * @param {Object} event Key press event | ||
8460 | * @method handleKeyPress | ||
8461 | */ | ||
8462 | |||
8463 | MenuButton.prototype.handleKeyPress = function handleKeyPress(event) { | ||
8464 | |||
8465 | // Escape (27) key or Tab (9) key unpress the 'button' | ||
8466 | if (event.which === 27 || event.which === 9) { | ||
8467 | if (this.buttonPressed_) { | ||
8468 | this.unpressButton(); | ||
8469 | } | ||
8470 | // Don't preventDefault for Tab key - we still want to lose focus | ||
8471 | if (event.which !== 9) { | ||
8472 | event.preventDefault(); | ||
8473 | } | ||
8474 | // Up (38) key or Down (40) key press the 'button' | ||
8475 | } else if (event.which === 38 || event.which === 40) { | ||
8476 | if (!this.buttonPressed_) { | ||
8477 | this.pressButton(); | ||
8478 | event.preventDefault(); | ||
8479 | } | ||
8480 | } else { | ||
8481 | _ClickableComponent.prototype.handleKeyPress.call(this, event); | ||
8482 | } | ||
8483 | }; | ||
8484 | |||
8485 | /** | ||
8486 | * Handle key press on submenu | ||
8487 | * | ||
8488 | * @param {Object} event Key press event | ||
8489 | * @method handleSubmenuKeyPress | ||
8490 | */ | ||
8491 | |||
8492 | MenuButton.prototype.handleSubmenuKeyPress = function handleSubmenuKeyPress(event) { | ||
8493 | |||
8494 | // Escape (27) key or Tab (9) key unpress the 'button' | ||
8495 | if (event.which === 27 || event.which === 9) { | ||
8496 | if (this.buttonPressed_) { | ||
8497 | this.unpressButton(); | ||
8498 | } | ||
8499 | // Don't preventDefault for Tab key - we still want to lose focus | ||
8500 | if (event.which !== 9) { | ||
8501 | event.preventDefault(); | ||
8502 | } | ||
8503 | } | ||
8504 | }; | ||
8505 | |||
8506 | /** | ||
8507 | * Makes changes based on button pressed | ||
8508 | * | ||
8509 | * @method pressButton | ||
8510 | */ | ||
8511 | |||
8512 | MenuButton.prototype.pressButton = function pressButton() { | ||
8513 | this.buttonPressed_ = true; | ||
8514 | this.menu.lockShowing(); | ||
8515 | this.el_.setAttribute('aria-expanded', true); | ||
8516 | this.menu.focus(); // set the focus into the submenu | ||
8517 | }; | ||
8518 | |||
8519 | /** | ||
8520 | * Makes changes based on button unpressed | ||
8521 | * | ||
8522 | * @method unpressButton | ||
8523 | */ | ||
8524 | |||
8525 | MenuButton.prototype.unpressButton = function unpressButton() { | ||
8526 | this.buttonPressed_ = false; | ||
8527 | this.menu.unlockShowing(); | ||
8528 | this.el_.setAttribute('aria-expanded', false); | ||
8529 | this.el_.focus(); // Set focus back to this menu button | ||
8530 | }; | ||
8531 | |||
8532 | return MenuButton; | ||
8533 | })(_clickableComponentJs2['default']); | ||
8534 | |||
8535 | _componentJs2['default'].registerComponent('MenuButton', MenuButton); | ||
8536 | exports['default'] = MenuButton; | ||
8537 | module.exports = exports['default']; | ||
8538 | |||
8539 | },{"../clickable-component.js":65,"../component.js":67,"../utils/dom.js":132,"../utils/fn.js":134,"../utils/to-title-case.js":141,"./menu.js":106}],105:[function(_dereq_,module,exports){ | ||
8540 | /** | ||
8541 | * @file menu-item.js | ||
8542 | */ | ||
8543 | 'use strict'; | ||
8544 | |||
8545 | exports.__esModule = true; | ||
8546 | |||
8547 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
8548 | |||
8549 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
8550 | |||
8551 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
8552 | |||
8553 | var _clickableComponentJs = _dereq_('../clickable-component.js'); | ||
8554 | |||
8555 | var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); | ||
8556 | |||
8557 | var _componentJs = _dereq_('../component.js'); | ||
8558 | |||
8559 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
8560 | |||
8561 | var _objectAssign = _dereq_('object.assign'); | ||
8562 | |||
8563 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
8564 | |||
8565 | /** | ||
8566 | * The component for a menu item. `<li>` | ||
8567 | * | ||
8568 | * @param {Player|Object} player | ||
8569 | * @param {Object=} options | ||
8570 | * @extends Button | ||
8571 | * @class MenuItem | ||
8572 | */ | ||
8573 | |||
8574 | var MenuItem = (function (_ClickableComponent) { | ||
8575 | _inherits(MenuItem, _ClickableComponent); | ||
8576 | |||
8577 | function MenuItem(player, options) { | ||
8578 | _classCallCheck(this, MenuItem); | ||
8579 | |||
8580 | _ClickableComponent.call(this, player, options); | ||
8581 | |||
8582 | this.selectable = options['selectable']; | ||
8583 | |||
8584 | this.selected(options['selected']); | ||
8585 | |||
8586 | if (this.selectable) { | ||
8587 | // TODO: May need to be either menuitemcheckbox or menuitemradio, | ||
8588 | // and may need logical grouping of menu items. | ||
8589 | this.el_.setAttribute('role', 'menuitemcheckbox'); | ||
8590 | } else { | ||
8591 | this.el_.setAttribute('role', 'menuitem'); | ||
8592 | } | ||
8593 | } | ||
8594 | |||
8595 | /** | ||
8596 | * Create the component's DOM element | ||
8597 | * | ||
8598 | * @param {String=} type Desc | ||
8599 | * @param {Object=} props Desc | ||
8600 | * @return {Element} | ||
8601 | * @method createEl | ||
8602 | */ | ||
8603 | |||
8604 | MenuItem.prototype.createEl = function createEl(type, props, attrs) { | ||
8605 | return _ClickableComponent.prototype.createEl.call(this, 'li', _objectAssign2['default']({ | ||
8606 | className: 'vjs-menu-item', | ||
8607 | innerHTML: this.localize(this.options_['label']), | ||
8608 | tabIndex: -1 | ||
8609 | }, props), attrs); | ||
8610 | }; | ||
8611 | |||
8612 | /** | ||
8613 | * Handle a click on the menu item, and set it to selected | ||
8614 | * | ||
8615 | * @method handleClick | ||
8616 | */ | ||
8617 | |||
8618 | MenuItem.prototype.handleClick = function handleClick() { | ||
8619 | this.selected(true); | ||
8620 | }; | ||
8621 | |||
8622 | /** | ||
8623 | * Set this menu item as selected or not | ||
8624 | * | ||
8625 | * @param {Boolean} selected | ||
8626 | * @method selected | ||
8627 | */ | ||
8628 | |||
8629 | MenuItem.prototype.selected = function selected(_selected) { | ||
8630 | if (this.selectable) { | ||
8631 | if (_selected) { | ||
8632 | this.addClass('vjs-selected'); | ||
8633 | this.el_.setAttribute('aria-checked', true); | ||
8634 | // aria-checked isn't fully supported by browsers/screen readers, | ||
8635 | // so indicate selected state to screen reader in the control text. | ||
8636 | this.controlText(', selected'); | ||
8637 | } else { | ||
8638 | this.removeClass('vjs-selected'); | ||
8639 | this.el_.setAttribute('aria-checked', false); | ||
8640 | // Indicate un-selected state to screen reader | ||
8641 | // Note that a space clears out the selected state text | ||
8642 | this.controlText(' '); | ||
8643 | } | ||
8644 | } | ||
8645 | }; | ||
8646 | |||
8647 | return MenuItem; | ||
8648 | })(_clickableComponentJs2['default']); | ||
8649 | |||
8650 | _componentJs2['default'].registerComponent('MenuItem', MenuItem); | ||
8651 | exports['default'] = MenuItem; | ||
8652 | module.exports = exports['default']; | ||
8653 | |||
8654 | },{"../clickable-component.js":65,"../component.js":67,"object.assign":45}],106:[function(_dereq_,module,exports){ | ||
8655 | /** | ||
8656 | * @file menu.js | ||
8657 | */ | ||
8658 | 'use strict'; | ||
8659 | |||
8660 | exports.__esModule = true; | ||
8661 | |||
8662 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
8663 | |||
8664 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
8665 | |||
8666 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
8667 | |||
8668 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
8669 | |||
8670 | var _componentJs = _dereq_('../component.js'); | ||
8671 | |||
8672 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
8673 | |||
8674 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
8675 | |||
8676 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
8677 | |||
8678 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
8679 | |||
8680 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
8681 | |||
8682 | var _utilsEventsJs = _dereq_('../utils/events.js'); | ||
8683 | |||
8684 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
8685 | |||
8686 | /** | ||
8687 | * The Menu component is used to build pop up menus, including subtitle and | ||
8688 | * captions selection menus. | ||
8689 | * | ||
8690 | * @extends Component | ||
8691 | * @class Menu | ||
8692 | */ | ||
8693 | |||
8694 | var Menu = (function (_Component) { | ||
8695 | _inherits(Menu, _Component); | ||
8696 | |||
8697 | function Menu(player, options) { | ||
8698 | _classCallCheck(this, Menu); | ||
8699 | |||
8700 | _Component.call(this, player, options); | ||
8701 | |||
8702 | this.focusedChild_ = -1; | ||
8703 | |||
8704 | this.on('keydown', this.handleKeyPress); | ||
8705 | } | ||
8706 | |||
8707 | /** | ||
8708 | * Add a menu item to the menu | ||
8709 | * | ||
8710 | * @param {Object|String} component Component or component type to add | ||
8711 | * @method addItem | ||
8712 | */ | ||
8713 | |||
8714 | Menu.prototype.addItem = function addItem(component) { | ||
8715 | this.addChild(component); | ||
8716 | component.on('click', Fn.bind(this, function () { | ||
8717 | this.unlockShowing(); | ||
8718 | //TODO: Need to set keyboard focus back to the menuButton | ||
8719 | })); | ||
8720 | }; | ||
8721 | |||
8722 | /** | ||
8723 | * Create the component's DOM element | ||
8724 | * | ||
8725 | * @return {Element} | ||
8726 | * @method createEl | ||
8727 | */ | ||
8728 | |||
8729 | Menu.prototype.createEl = function createEl() { | ||
8730 | var contentElType = this.options_.contentElType || 'ul'; | ||
8731 | this.contentEl_ = Dom.createEl(contentElType, { | ||
8732 | className: 'vjs-menu-content' | ||
8733 | }); | ||
8734 | this.contentEl_.setAttribute('role', 'menu'); | ||
8735 | var el = _Component.prototype.createEl.call(this, 'div', { | ||
8736 | append: this.contentEl_, | ||
8737 | className: 'vjs-menu' | ||
8738 | }); | ||
8739 | el.setAttribute('role', 'presentation'); | ||
8740 | el.appendChild(this.contentEl_); | ||
8741 | |||
8742 | // Prevent clicks from bubbling up. Needed for Menu Buttons, | ||
8743 | // where a click on the parent is significant | ||
8744 | Events.on(el, 'click', function (event) { | ||
8745 | event.preventDefault(); | ||
8746 | event.stopImmediatePropagation(); | ||
8747 | }); | ||
8748 | |||
8749 | return el; | ||
8750 | }; | ||
8751 | |||
8752 | /** | ||
8753 | * Handle key press for menu | ||
8754 | * | ||
8755 | * @param {Object} event Event object | ||
8756 | * @method handleKeyPress | ||
8757 | */ | ||
8758 | |||
8759 | Menu.prototype.handleKeyPress = function handleKeyPress(event) { | ||
8760 | if (event.which === 37 || event.which === 40) { | ||
8761 | // Left and Down Arrows | ||
8762 | event.preventDefault(); | ||
8763 | this.stepForward(); | ||
8764 | } else if (event.which === 38 || event.which === 39) { | ||
8765 | // Up and Right Arrows | ||
8766 | event.preventDefault(); | ||
8767 | this.stepBack(); | ||
8768 | } | ||
8769 | }; | ||
8770 | |||
8771 | /** | ||
8772 | * Move to next (lower) menu item for keyboard users | ||
8773 | * | ||
8774 | * @method stepForward | ||
8775 | */ | ||
8776 | |||
8777 | Menu.prototype.stepForward = function stepForward() { | ||
8778 | var stepChild = 0; | ||
8779 | |||
8780 | if (this.focusedChild_ !== undefined) { | ||
8781 | stepChild = this.focusedChild_ + 1; | ||
8782 | } | ||
8783 | this.focus(stepChild); | ||
8784 | }; | ||
8785 | |||
8786 | /** | ||
8787 | * Move to previous (higher) menu item for keyboard users | ||
8788 | * | ||
8789 | * @method stepBack | ||
8790 | */ | ||
8791 | |||
8792 | Menu.prototype.stepBack = function stepBack() { | ||
8793 | var stepChild = 0; | ||
8794 | |||
8795 | if (this.focusedChild_ !== undefined) { | ||
8796 | stepChild = this.focusedChild_ - 1; | ||
8797 | } | ||
8798 | this.focus(stepChild); | ||
8799 | }; | ||
8800 | |||
8801 | /** | ||
8802 | * Set focus on a menu item in the menu | ||
8803 | * | ||
8804 | * @param {Object|String} item Index of child item set focus on | ||
8805 | * @method focus | ||
8806 | */ | ||
8807 | |||
8808 | Menu.prototype.focus = function focus() { | ||
8809 | var item = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0]; | ||
8810 | |||
8811 | var children = this.children().slice(); | ||
8812 | var haveTitle = children.length && children[0].className && /vjs-menu-title/.test(children[0].className); | ||
8813 | |||
8814 | if (haveTitle) { | ||
8815 | children.shift(); | ||
8816 | } | ||
8817 | |||
8818 | if (children.length > 0) { | ||
8819 | if (item < 0) { | ||
8820 | item = 0; | ||
8821 | } else if (item >= children.length) { | ||
8822 | item = children.length - 1; | ||
8823 | } | ||
8824 | |||
8825 | this.focusedChild_ = item; | ||
8826 | |||
8827 | children[item].el_.focus(); | ||
8828 | } | ||
8829 | }; | ||
8830 | |||
8831 | return Menu; | ||
8832 | })(_componentJs2['default']); | ||
8833 | |||
8834 | _componentJs2['default'].registerComponent('Menu', Menu); | ||
8835 | exports['default'] = Menu; | ||
8836 | module.exports = exports['default']; | ||
8837 | |||
8838 | },{"../component.js":67,"../utils/dom.js":132,"../utils/events.js":133,"../utils/fn.js":134}],107:[function(_dereq_,module,exports){ | ||
8839 | /** | ||
8840 | * @file modal-dialog.js | ||
8841 | */ | ||
8842 | 'use strict'; | ||
8843 | |||
8844 | exports.__esModule = true; | ||
8845 | |||
8846 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
8847 | |||
8848 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
8849 | |||
8850 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
8851 | |||
8852 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
8853 | |||
8854 | var _globalDocument = _dereq_('global/document'); | ||
8855 | |||
8856 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
8857 | |||
8858 | var _utilsDom = _dereq_('./utils/dom'); | ||
8859 | |||
8860 | var Dom = _interopRequireWildcard(_utilsDom); | ||
8861 | |||
8862 | var _utilsFn = _dereq_('./utils/fn'); | ||
8863 | |||
8864 | var Fn = _interopRequireWildcard(_utilsFn); | ||
8865 | |||
8866 | var _utilsLog = _dereq_('./utils/log'); | ||
8867 | |||
8868 | var _utilsLog2 = _interopRequireDefault(_utilsLog); | ||
8869 | |||
8870 | var _component = _dereq_('./component'); | ||
8871 | |||
8872 | var _component2 = _interopRequireDefault(_component); | ||
8873 | |||
8874 | var _closeButton = _dereq_('./close-button'); | ||
8875 | |||
8876 | var _closeButton2 = _interopRequireDefault(_closeButton); | ||
8877 | |||
8878 | var MODAL_CLASS_NAME = 'vjs-modal-dialog'; | ||
8879 | var ESC = 27; | ||
8880 | |||
8881 | /** | ||
8882 | * The `ModalDialog` displays over the video and its controls, which blocks | ||
8883 | * interaction with the player until it is closed. | ||
8884 | * | ||
8885 | * Modal dialogs include a "Close" button and will close when that button | ||
8886 | * is activated - or when ESC is pressed anywhere. | ||
8887 | * | ||
8888 | * @extends Component | ||
8889 | * @class ModalDialog | ||
8890 | */ | ||
8891 | |||
8892 | var ModalDialog = (function (_Component) { | ||
8893 | _inherits(ModalDialog, _Component); | ||
8894 | |||
8895 | /** | ||
8896 | * Constructor for modals. | ||
8897 | * | ||
8898 | * @param {Player} player | ||
8899 | * @param {Object} [options] | ||
8900 | * @param {Mixed} [options.content=undefined] | ||
8901 | * Provide customized content for this modal. | ||
8902 | * | ||
8903 | * @param {String} [options.description] | ||
8904 | * A text description for the modal, primarily for accessibility. | ||
8905 | * | ||
8906 | * @param {Boolean} [options.fillAlways=false] | ||
8907 | * Normally, modals are automatically filled only the first time | ||
8908 | * they open. This tells the modal to refresh its content | ||
8909 | * every time it opens. | ||
8910 | * | ||
8911 | * @param {String} [options.label] | ||
8912 | * A text label for the modal, primarily for accessibility. | ||
8913 | * | ||
8914 | * @param {Boolean} [options.temporary=true] | ||
8915 | * If `true`, the modal can only be opened once; it will be | ||
8916 | * disposed as soon as it's closed. | ||
8917 | * | ||
8918 | * @param {Boolean} [options.uncloseable=false] | ||
8919 | * If `true`, the user will not be able to close the modal | ||
8920 | * through the UI in the normal ways. Programmatic closing is | ||
8921 | * still possible. | ||
8922 | * | ||
8923 | */ | ||
8924 | |||
8925 | function ModalDialog(player, options) { | ||
8926 | _classCallCheck(this, ModalDialog); | ||
8927 | |||
8928 | _Component.call(this, player, options); | ||
8929 | this.opened_ = this.hasBeenOpened_ = this.hasBeenFilled_ = false; | ||
8930 | |||
8931 | this.closeable(!this.options_.uncloseable); | ||
8932 | this.content(this.options_.content); | ||
8933 | |||
8934 | // Make sure the contentEl is defined AFTER any children are initialized | ||
8935 | // because we only want the contents of the modal in the contentEl | ||
8936 | // (not the UI elements like the close button). | ||
8937 | this.contentEl_ = Dom.createEl('div', { | ||
8938 | className: MODAL_CLASS_NAME + '-content' | ||
8939 | }, { | ||
8940 | role: 'document' | ||
8941 | }); | ||
8942 | |||
8943 | this.descEl_ = Dom.createEl('p', { | ||
8944 | className: MODAL_CLASS_NAME + '-description vjs-offscreen', | ||
8945 | id: this.el().getAttribute('aria-describedby') | ||
8946 | }); | ||
8947 | |||
8948 | Dom.textContent(this.descEl_, this.description()); | ||
8949 | this.el_.appendChild(this.descEl_); | ||
8950 | this.el_.appendChild(this.contentEl_); | ||
8951 | } | ||
8952 | |||
8953 | /* | ||
8954 | * Modal dialog default options. | ||
8955 | * | ||
8956 | * @type {Object} | ||
8957 | * @private | ||
8958 | */ | ||
8959 | |||
8960 | /** | ||
8961 | * Create the modal's DOM element | ||
8962 | * | ||
8963 | * @method createEl | ||
8964 | * @return {Element} | ||
8965 | */ | ||
8966 | |||
8967 | ModalDialog.prototype.createEl = function createEl() { | ||
8968 | return _Component.prototype.createEl.call(this, 'div', { | ||
8969 | className: this.buildCSSClass(), | ||
8970 | tabIndex: -1 | ||
8971 | }, { | ||
8972 | 'aria-describedby': this.id() + '_description', | ||
8973 | 'aria-hidden': 'true', | ||
8974 | 'aria-label': this.label(), | ||
8975 | role: 'dialog' | ||
8976 | }); | ||
8977 | }; | ||
8978 | |||
8979 | /** | ||
8980 | * Build the modal's CSS class. | ||
8981 | * | ||
8982 | * @method buildCSSClass | ||
8983 | * @return {String} | ||
8984 | */ | ||
8985 | |||
8986 | ModalDialog.prototype.buildCSSClass = function buildCSSClass() { | ||
8987 | return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this); | ||
8988 | }; | ||
8989 | |||
8990 | /** | ||
8991 | * Handles key presses on the document, looking for ESC, which closes | ||
8992 | * the modal. | ||
8993 | * | ||
8994 | * @method handleKeyPress | ||
8995 | * @param {Event} e | ||
8996 | */ | ||
8997 | |||
8998 | ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) { | ||
8999 | if (e.which === ESC && this.closeable()) { | ||
9000 | this.close(); | ||
9001 | } | ||
9002 | }; | ||
9003 | |||
9004 | /** | ||
9005 | * Returns the label string for this modal. Primarily used for accessibility. | ||
9006 | * | ||
9007 | * @return {String} | ||
9008 | */ | ||
9009 | |||
9010 | ModalDialog.prototype.label = function label() { | ||
9011 | return this.options_.label || this.localize('Modal Window'); | ||
9012 | }; | ||
9013 | |||
9014 | /** | ||
9015 | * Returns the description string for this modal. Primarily used for | ||
9016 | * accessibility. | ||
9017 | * | ||
9018 | * @return {String} | ||
9019 | */ | ||
9020 | |||
9021 | ModalDialog.prototype.description = function description() { | ||
9022 | var desc = this.options_.description || this.localize('This is a modal window.'); | ||
9023 | |||
9024 | // Append a universal closeability message if the modal is closeable. | ||
9025 | if (this.closeable()) { | ||
9026 | desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.'); | ||
9027 | } | ||
9028 | |||
9029 | return desc; | ||
9030 | }; | ||
9031 | |||
9032 | /** | ||
9033 | * Opens the modal. | ||
9034 | * | ||
9035 | * @method open | ||
9036 | * @return {ModalDialog} | ||
9037 | */ | ||
9038 | |||
9039 | ModalDialog.prototype.open = function open() { | ||
9040 | if (!this.opened_) { | ||
9041 | var player = this.player(); | ||
9042 | |||
9043 | this.trigger('beforemodalopen'); | ||
9044 | this.opened_ = true; | ||
9045 | |||
9046 | // Fill content if the modal has never opened before and | ||
9047 | // never been filled. | ||
9048 | if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) { | ||
9049 | this.fill(); | ||
9050 | } | ||
9051 | |||
9052 | // If the player was playing, pause it and take note of its previously | ||
9053 | // playing state. | ||
9054 | this.wasPlaying_ = !player.paused(); | ||
9055 | |||
9056 | if (this.wasPlaying_) { | ||
9057 | player.pause(); | ||
9058 | } | ||
9059 | |||
9060 | if (this.closeable()) { | ||
9061 | this.on(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); | ||
9062 | } | ||
9063 | |||
9064 | player.controls(false); | ||
9065 | this.show(); | ||
9066 | this.el().setAttribute('aria-hidden', 'false'); | ||
9067 | this.trigger('modalopen'); | ||
9068 | this.hasBeenOpened_ = true; | ||
9069 | } | ||
9070 | return this; | ||
9071 | }; | ||
9072 | |||
9073 | /** | ||
9074 | * Whether or not the modal is opened currently. | ||
9075 | * | ||
9076 | * @method opened | ||
9077 | * @param {Boolean} [value] | ||
9078 | * If given, it will open (`true`) or close (`false`) the modal. | ||
9079 | * | ||
9080 | * @return {Boolean} | ||
9081 | */ | ||
9082 | |||
9083 | ModalDialog.prototype.opened = function opened(value) { | ||
9084 | if (typeof value === 'boolean') { | ||
9085 | this[value ? 'open' : 'close'](); | ||
9086 | } | ||
9087 | return this.opened_; | ||
9088 | }; | ||
9089 | |||
9090 | /** | ||
9091 | * Closes the modal. | ||
9092 | * | ||
9093 | * @method close | ||
9094 | * @return {ModalDialog} | ||
9095 | */ | ||
9096 | |||
9097 | ModalDialog.prototype.close = function close() { | ||
9098 | if (this.opened_) { | ||
9099 | var player = this.player(); | ||
9100 | |||
9101 | this.trigger('beforemodalclose'); | ||
9102 | this.opened_ = false; | ||
9103 | |||
9104 | if (this.wasPlaying_) { | ||
9105 | player.play(); | ||
9106 | } | ||
9107 | |||
9108 | if (this.closeable()) { | ||
9109 | this.off(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); | ||
9110 | } | ||
9111 | |||
9112 | player.controls(true); | ||
9113 | this.hide(); | ||
9114 | this.el().setAttribute('aria-hidden', 'true'); | ||
9115 | this.trigger('modalclose'); | ||
9116 | |||
9117 | if (this.options_.temporary) { | ||
9118 | this.dispose(); | ||
9119 | } | ||
9120 | } | ||
9121 | return this; | ||
9122 | }; | ||
9123 | |||
9124 | /** | ||
9125 | * Whether or not the modal is closeable via the UI. | ||
9126 | * | ||
9127 | * @method closeable | ||
9128 | * @param {Boolean} [value] | ||
9129 | * If given as a Boolean, it will set the `closeable` option. | ||
9130 | * | ||
9131 | * @return {Boolean} | ||
9132 | */ | ||
9133 | |||
9134 | ModalDialog.prototype.closeable = function closeable(value) { | ||
9135 | if (typeof value === 'boolean') { | ||
9136 | var closeable = this.closeable_ = !!value; | ||
9137 | var _close = this.getChild('closeButton'); | ||
9138 | |||
9139 | // If this is being made closeable and has no close button, add one. | ||
9140 | if (closeable && !_close) { | ||
9141 | |||
9142 | // The close button should be a child of the modal - not its | ||
9143 | // content element, so temporarily change the content element. | ||
9144 | var temp = this.contentEl_; | ||
9145 | this.contentEl_ = this.el_; | ||
9146 | _close = this.addChild('closeButton'); | ||
9147 | this.contentEl_ = temp; | ||
9148 | this.on(_close, 'close', this.close); | ||
9149 | } | ||
9150 | |||
9151 | // If this is being made uncloseable and has a close button, remove it. | ||
9152 | if (!closeable && _close) { | ||
9153 | this.off(_close, 'close', this.close); | ||
9154 | this.removeChild(_close); | ||
9155 | _close.dispose(); | ||
9156 | } | ||
9157 | } | ||
9158 | return this.closeable_; | ||
9159 | }; | ||
9160 | |||
9161 | /** | ||
9162 | * Fill the modal's content element with the modal's "content" option. | ||
9163 | * | ||
9164 | * The content element will be emptied before this change takes place. | ||
9165 | * | ||
9166 | * @method fill | ||
9167 | * @return {ModalDialog} | ||
9168 | */ | ||
9169 | |||
9170 | ModalDialog.prototype.fill = function fill() { | ||
9171 | return this.fillWith(this.content()); | ||
9172 | }; | ||
9173 | |||
9174 | /** | ||
9175 | * Fill the modal's content element with arbitrary content. | ||
9176 | * | ||
9177 | * The content element will be emptied before this change takes place. | ||
9178 | * | ||
9179 | * @method fillWith | ||
9180 | * @param {Mixed} [content] | ||
9181 | * The same rules apply to this as apply to the `content` option. | ||
9182 | * | ||
9183 | * @return {ModalDialog} | ||
9184 | */ | ||
9185 | |||
9186 | ModalDialog.prototype.fillWith = function fillWith(content) { | ||
9187 | var contentEl = this.contentEl(); | ||
9188 | var parentEl = contentEl.parentNode; | ||
9189 | var nextSiblingEl = contentEl.nextSibling; | ||
9190 | |||
9191 | this.trigger('beforemodalfill'); | ||
9192 | this.hasBeenFilled_ = true; | ||
9193 | |||
9194 | // Detach the content element from the DOM before performing | ||
9195 | // manipulation to avoid modifying the live DOM multiple times. | ||
9196 | parentEl.removeChild(contentEl); | ||
9197 | this.empty(); | ||
9198 | Dom.insertContent(contentEl, content); | ||
9199 | this.trigger('modalfill'); | ||
9200 | |||
9201 | // Re-inject the re-filled content element. | ||
9202 | if (nextSiblingEl) { | ||
9203 | parentEl.insertBefore(contentEl, nextSiblingEl); | ||
9204 | } else { | ||
9205 | parentEl.appendChild(contentEl); | ||
9206 | } | ||
9207 | |||
9208 | return this; | ||
9209 | }; | ||
9210 | |||
9211 | /** | ||
9212 | * Empties the content element. | ||
9213 | * | ||
9214 | * This happens automatically anytime the modal is filled. | ||
9215 | * | ||
9216 | * @method empty | ||
9217 | * @return {ModalDialog} | ||
9218 | */ | ||
9219 | |||
9220 | ModalDialog.prototype.empty = function empty() { | ||
9221 | this.trigger('beforemodalempty'); | ||
9222 | Dom.emptyEl(this.contentEl()); | ||
9223 | this.trigger('modalempty'); | ||
9224 | return this; | ||
9225 | }; | ||
9226 | |||
9227 | /** | ||
9228 | * Gets or sets the modal content, which gets normalized before being | ||
9229 | * rendered into the DOM. | ||
9230 | * | ||
9231 | * This does not update the DOM or fill the modal, but it is called during | ||
9232 | * that process. | ||
9233 | * | ||
9234 | * @method content | ||
9235 | * @param {Mixed} [value] | ||
9236 | * If defined, sets the internal content value to be used on the | ||
9237 | * next call(s) to `fill`. This value is normalized before being | ||
9238 | * inserted. To "clear" the internal content value, pass `null`. | ||
9239 | * | ||
9240 | * @return {Mixed} | ||
9241 | */ | ||
9242 | |||
9243 | ModalDialog.prototype.content = function content(value) { | ||
9244 | if (typeof value !== 'undefined') { | ||
9245 | this.content_ = value; | ||
9246 | } | ||
9247 | return this.content_; | ||
9248 | }; | ||
9249 | |||
9250 | return ModalDialog; | ||
9251 | })(_component2['default']); | ||
9252 | |||
9253 | ModalDialog.prototype.options_ = { | ||
9254 | temporary: true | ||
9255 | }; | ||
9256 | |||
9257 | _component2['default'].registerComponent('ModalDialog', ModalDialog); | ||
9258 | exports['default'] = ModalDialog; | ||
9259 | module.exports = exports['default']; | ||
9260 | |||
9261 | },{"./close-button":66,"./component":67,"./utils/dom":132,"./utils/fn":134,"./utils/log":137,"global/document":1}],108:[function(_dereq_,module,exports){ | ||
9262 | /** | ||
9263 | * @file player.js | ||
9264 | */ | ||
9265 | // Subclasses Component | ||
9266 | 'use strict'; | ||
9267 | |||
9268 | exports.__esModule = true; | ||
9269 | |||
9270 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
9271 | |||
9272 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
9273 | |||
9274 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
9275 | |||
9276 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
9277 | |||
9278 | var _componentJs = _dereq_('./component.js'); | ||
9279 | |||
9280 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
9281 | |||
9282 | var _globalDocument = _dereq_('global/document'); | ||
9283 | |||
9284 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
9285 | |||
9286 | var _globalWindow = _dereq_('global/window'); | ||
9287 | |||
9288 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
9289 | |||
9290 | var _utilsEventsJs = _dereq_('./utils/events.js'); | ||
9291 | |||
9292 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
9293 | |||
9294 | var _utilsDomJs = _dereq_('./utils/dom.js'); | ||
9295 | |||
9296 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
9297 | |||
9298 | var _utilsFnJs = _dereq_('./utils/fn.js'); | ||
9299 | |||
9300 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
9301 | |||
9302 | var _utilsGuidJs = _dereq_('./utils/guid.js'); | ||
9303 | |||
9304 | var Guid = _interopRequireWildcard(_utilsGuidJs); | ||
9305 | |||
9306 | var _utilsBrowserJs = _dereq_('./utils/browser.js'); | ||
9307 | |||
9308 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
9309 | |||
9310 | var _utilsLogJs = _dereq_('./utils/log.js'); | ||
9311 | |||
9312 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
9313 | |||
9314 | var _utilsToTitleCaseJs = _dereq_('./utils/to-title-case.js'); | ||
9315 | |||
9316 | var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); | ||
9317 | |||
9318 | var _utilsTimeRangesJs = _dereq_('./utils/time-ranges.js'); | ||
9319 | |||
9320 | var _utilsBufferJs = _dereq_('./utils/buffer.js'); | ||
9321 | |||
9322 | var _utilsStylesheetJs = _dereq_('./utils/stylesheet.js'); | ||
9323 | |||
9324 | var stylesheet = _interopRequireWildcard(_utilsStylesheetJs); | ||
9325 | |||
9326 | var _fullscreenApiJs = _dereq_('./fullscreen-api.js'); | ||
9327 | |||
9328 | var _fullscreenApiJs2 = _interopRequireDefault(_fullscreenApiJs); | ||
9329 | |||
9330 | var _mediaErrorJs = _dereq_('./media-error.js'); | ||
9331 | |||
9332 | var _mediaErrorJs2 = _interopRequireDefault(_mediaErrorJs); | ||
9333 | |||
9334 | var _safeJsonParseTuple = _dereq_('safe-json-parse/tuple'); | ||
9335 | |||
9336 | var _safeJsonParseTuple2 = _interopRequireDefault(_safeJsonParseTuple); | ||
9337 | |||
9338 | var _objectAssign = _dereq_('object.assign'); | ||
9339 | |||
9340 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
9341 | |||
9342 | var _utilsMergeOptionsJs = _dereq_('./utils/merge-options.js'); | ||
9343 | |||
9344 | var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); | ||
9345 | |||
9346 | var _tracksTextTrackListConverterJs = _dereq_('./tracks/text-track-list-converter.js'); | ||
9347 | |||
9348 | var _tracksTextTrackListConverterJs2 = _interopRequireDefault(_tracksTextTrackListConverterJs); | ||
9349 | |||
9350 | // Include required child components (importing also registers them) | ||
9351 | |||
9352 | var _techLoaderJs = _dereq_('./tech/loader.js'); | ||
9353 | |||
9354 | var _techLoaderJs2 = _interopRequireDefault(_techLoaderJs); | ||
9355 | |||
9356 | var _posterImageJs = _dereq_('./poster-image.js'); | ||
9357 | |||
9358 | var _posterImageJs2 = _interopRequireDefault(_posterImageJs); | ||
9359 | |||
9360 | var _tracksTextTrackDisplayJs = _dereq_('./tracks/text-track-display.js'); | ||
9361 | |||
9362 | var _tracksTextTrackDisplayJs2 = _interopRequireDefault(_tracksTextTrackDisplayJs); | ||
9363 | |||
9364 | var _loadingSpinnerJs = _dereq_('./loading-spinner.js'); | ||
9365 | |||
9366 | var _loadingSpinnerJs2 = _interopRequireDefault(_loadingSpinnerJs); | ||
9367 | |||
9368 | var _bigPlayButtonJs = _dereq_('./big-play-button.js'); | ||
9369 | |||
9370 | var _bigPlayButtonJs2 = _interopRequireDefault(_bigPlayButtonJs); | ||
9371 | |||
9372 | var _controlBarControlBarJs = _dereq_('./control-bar/control-bar.js'); | ||
9373 | |||
9374 | var _controlBarControlBarJs2 = _interopRequireDefault(_controlBarControlBarJs); | ||
9375 | |||
9376 | var _errorDisplayJs = _dereq_('./error-display.js'); | ||
9377 | |||
9378 | var _errorDisplayJs2 = _interopRequireDefault(_errorDisplayJs); | ||
9379 | |||
9380 | var _tracksTextTrackSettingsJs = _dereq_('./tracks/text-track-settings.js'); | ||
9381 | |||
9382 | var _tracksTextTrackSettingsJs2 = _interopRequireDefault(_tracksTextTrackSettingsJs); | ||
9383 | |||
9384 | var _modalDialog = _dereq_('./modal-dialog'); | ||
9385 | |||
9386 | var _modalDialog2 = _interopRequireDefault(_modalDialog); | ||
9387 | |||
9388 | // Require html5 tech, at least for disposing the original video tag | ||
9389 | |||
9390 | var _techTechJs = _dereq_('./tech/tech.js'); | ||
9391 | |||
9392 | var _techTechJs2 = _interopRequireDefault(_techTechJs); | ||
9393 | |||
9394 | var _techHtml5Js = _dereq_('./tech/html5.js'); | ||
9395 | |||
9396 | var _techHtml5Js2 = _interopRequireDefault(_techHtml5Js); | ||
9397 | |||
9398 | /** | ||
9399 | * An instance of the `Player` class is created when any of the Video.js setup methods are used to initialize a video. | ||
9400 | * ```js | ||
9401 | * var myPlayer = videojs('example_video_1'); | ||
9402 | * ``` | ||
9403 | * In the following example, the `data-setup` attribute tells the Video.js library to create a player instance when the library is ready. | ||
9404 | * ```html | ||
9405 | * <video id="example_video_1" data-setup='{}' controls> | ||
9406 | * <source src="my-source.mp4" type="video/mp4"> | ||
9407 | * </video> | ||
9408 | * ``` | ||
9409 | * After an instance has been created it can be accessed globally using `Video('example_video_1')`. | ||
9410 | * | ||
9411 | * @param {Element} tag The original video tag used for configuring options | ||
9412 | * @param {Object=} options Object of option names and values | ||
9413 | * @param {Function=} ready Ready callback function | ||
9414 | * @extends Component | ||
9415 | * @class Player | ||
9416 | */ | ||
9417 | |||
9418 | var Player = (function (_Component) { | ||
9419 | _inherits(Player, _Component); | ||
9420 | |||
9421 | /** | ||
9422 | * player's constructor function | ||
9423 | * | ||
9424 | * @constructs | ||
9425 | * @method init | ||
9426 | * @param {Element} tag The original video tag used for configuring options | ||
9427 | * @param {Object=} options Player options | ||
9428 | * @param {Function=} ready Ready callback function | ||
9429 | */ | ||
9430 | |||
9431 | function Player(tag, options, ready) { | ||
9432 | var _this = this; | ||
9433 | |||
9434 | _classCallCheck(this, Player); | ||
9435 | |||
9436 | // Make sure tag ID exists | ||
9437 | tag.id = tag.id || 'vjs_video_' + Guid.newGUID(); | ||
9438 | |||
9439 | // Set Options | ||
9440 | // The options argument overrides options set in the video tag | ||
9441 | // which overrides globally set options. | ||
9442 | // This latter part coincides with the load order | ||
9443 | // (tag must exist before Player) | ||
9444 | options = _objectAssign2['default'](Player.getTagSettings(tag), options); | ||
9445 | |||
9446 | // Delay the initialization of children because we need to set up | ||
9447 | // player properties first, and can't use `this` before `super()` | ||
9448 | options.initChildren = false; | ||
9449 | |||
9450 | // Same with creating the element | ||
9451 | options.createEl = false; | ||
9452 | |||
9453 | // we don't want the player to report touch activity on itself | ||
9454 | // see enableTouchActivity in Component | ||
9455 | options.reportTouchActivity = false; | ||
9456 | |||
9457 | // Run base component initializing with new options | ||
9458 | _Component.call(this, null, options, ready); | ||
9459 | |||
9460 | // if the global option object was accidentally blown away by | ||
9461 | // someone, bail early with an informative error | ||
9462 | if (!this.options_ || !this.options_.techOrder || !this.options_.techOrder.length) { | ||
9463 | throw new Error('No techOrder specified. Did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?'); | ||
9464 | } | ||
9465 | |||
9466 | this.tag = tag; // Store the original tag used to set options | ||
9467 | |||
9468 | // Store the tag attributes used to restore html5 element | ||
9469 | this.tagAttributes = tag && Dom.getElAttributes(tag); | ||
9470 | |||
9471 | // Update current language | ||
9472 | this.language(this.options_.language); | ||
9473 | |||
9474 | // Update Supported Languages | ||
9475 | if (options.languages) { | ||
9476 | (function () { | ||
9477 | // Normalise player option languages to lowercase | ||
9478 | var languagesToLower = {}; | ||
9479 | |||
9480 | Object.getOwnPropertyNames(options.languages).forEach(function (name) { | ||
9481 | languagesToLower[name.toLowerCase()] = options.languages[name]; | ||
9482 | }); | ||
9483 | _this.languages_ = languagesToLower; | ||
9484 | })(); | ||
9485 | } else { | ||
9486 | this.languages_ = Player.prototype.options_.languages; | ||
9487 | } | ||
9488 | |||
9489 | // Cache for video property values. | ||
9490 | this.cache_ = {}; | ||
9491 | |||
9492 | // Set poster | ||
9493 | this.poster_ = options.poster || ''; | ||
9494 | |||
9495 | // Set controls | ||
9496 | this.controls_ = !!options.controls; | ||
9497 | |||
9498 | // Original tag settings stored in options | ||
9499 | // now remove immediately so native controls don't flash. | ||
9500 | // May be turned back on by HTML5 tech if nativeControlsForTouch is true | ||
9501 | tag.controls = false; | ||
9502 | |||
9503 | /* | ||
9504 | * Store the internal state of scrubbing | ||
9505 | * | ||
9506 | * @private | ||
9507 | * @return {Boolean} True if the user is scrubbing | ||
9508 | */ | ||
9509 | this.scrubbing_ = false; | ||
9510 | |||
9511 | this.el_ = this.createEl(); | ||
9512 | |||
9513 | // We also want to pass the original player options to each component and plugin | ||
9514 | // as well so they don't need to reach back into the player for options later. | ||
9515 | // We also need to do another copy of this.options_ so we don't end up with | ||
9516 | // an infinite loop. | ||
9517 | var playerOptionsCopy = _utilsMergeOptionsJs2['default'](this.options_); | ||
9518 | |||
9519 | // Load plugins | ||
9520 | if (options.plugins) { | ||
9521 | (function () { | ||
9522 | var plugins = options.plugins; | ||
9523 | |||
9524 | Object.getOwnPropertyNames(plugins).forEach(function (name) { | ||
9525 | if (typeof this[name] === 'function') { | ||
9526 | this[name](plugins[name]); | ||
9527 | } else { | ||
9528 | _utilsLogJs2['default'].error('Unable to find plugin:', name); | ||
9529 | } | ||
9530 | }, _this); | ||
9531 | })(); | ||
9532 | } | ||
9533 | |||
9534 | this.options_.playerOptions = playerOptionsCopy; | ||
9535 | |||
9536 | this.initChildren(); | ||
9537 | |||
9538 | // Set isAudio based on whether or not an audio tag was used | ||
9539 | this.isAudio(tag.nodeName.toLowerCase() === 'audio'); | ||
9540 | |||
9541 | // Update controls className. Can't do this when the controls are initially | ||
9542 | // set because the element doesn't exist yet. | ||
9543 | if (this.controls()) { | ||
9544 | this.addClass('vjs-controls-enabled'); | ||
9545 | } else { | ||
9546 | this.addClass('vjs-controls-disabled'); | ||
9547 | } | ||
9548 | |||
9549 | if (this.isAudio()) { | ||
9550 | this.addClass('vjs-audio'); | ||
9551 | } | ||
9552 | |||
9553 | if (this.flexNotSupported_()) { | ||
9554 | this.addClass('vjs-no-flex'); | ||
9555 | } | ||
9556 | |||
9557 | // TODO: Make this smarter. Toggle user state between touching/mousing | ||
9558 | // using events, since devices can have both touch and mouse events. | ||
9559 | // if (browser.TOUCH_ENABLED) { | ||
9560 | // this.addClass('vjs-touch-enabled'); | ||
9561 | // } | ||
9562 | |||
9563 | // iOS Safari has broken hover handling | ||
9564 | if (!browser.IS_IOS) { | ||
9565 | this.addClass('vjs-workinghover'); | ||
9566 | } | ||
9567 | |||
9568 | // Make player easily findable by ID | ||
9569 | Player.players[this.id_] = this; | ||
9570 | |||
9571 | // When the player is first initialized, trigger activity so components | ||
9572 | // like the control bar show themselves if needed | ||
9573 | this.userActive(true); | ||
9574 | this.reportUserActivity(); | ||
9575 | this.listenForUserActivity_(); | ||
9576 | |||
9577 | this.on('fullscreenchange', this.handleFullscreenChange_); | ||
9578 | this.on('stageclick', this.handleStageClick_); | ||
9579 | } | ||
9580 | |||
9581 | /* | ||
9582 | * Global player list | ||
9583 | * | ||
9584 | * @type {Object} | ||
9585 | */ | ||
9586 | |||
9587 | /** | ||
9588 | * Destroys the video player and does any necessary cleanup | ||
9589 | * ```js | ||
9590 | * myPlayer.dispose(); | ||
9591 | * ``` | ||
9592 | * This is especially helpful if you are dynamically adding and removing videos | ||
9593 | * to/from the DOM. | ||
9594 | * | ||
9595 | * @method dispose | ||
9596 | */ | ||
9597 | |||
9598 | Player.prototype.dispose = function dispose() { | ||
9599 | this.trigger('dispose'); | ||
9600 | // prevent dispose from being called twice | ||
9601 | this.off('dispose'); | ||
9602 | |||
9603 | if (this.styleEl_ && this.styleEl_.parentNode) { | ||
9604 | this.styleEl_.parentNode.removeChild(this.styleEl_); | ||
9605 | } | ||
9606 | |||
9607 | // Kill reference to this player | ||
9608 | Player.players[this.id_] = null; | ||
9609 | if (this.tag && this.tag.player) { | ||
9610 | this.tag.player = null; | ||
9611 | } | ||
9612 | if (this.el_ && this.el_.player) { | ||
9613 | this.el_.player = null; | ||
9614 | } | ||
9615 | |||
9616 | if (this.tech_) { | ||
9617 | this.tech_.dispose(); | ||
9618 | } | ||
9619 | |||
9620 | _Component.prototype.dispose.call(this); | ||
9621 | }; | ||
9622 | |||
9623 | /** | ||
9624 | * Create the component's DOM element | ||
9625 | * | ||
9626 | * @return {Element} | ||
9627 | * @method createEl | ||
9628 | */ | ||
9629 | |||
9630 | Player.prototype.createEl = function createEl() { | ||
9631 | var el = this.el_ = _Component.prototype.createEl.call(this, 'div'); | ||
9632 | var tag = this.tag; | ||
9633 | |||
9634 | // Remove width/height attrs from tag so CSS can make it 100% width/height | ||
9635 | tag.removeAttribute('width'); | ||
9636 | tag.removeAttribute('height'); | ||
9637 | |||
9638 | // Copy over all the attributes from the tag, including ID and class | ||
9639 | // ID will now reference player box, not the video tag | ||
9640 | var attrs = Dom.getElAttributes(tag); | ||
9641 | |||
9642 | Object.getOwnPropertyNames(attrs).forEach(function (attr) { | ||
9643 | // workaround so we don't totally break IE7 | ||
9644 | // http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7 | ||
9645 | if (attr === 'class') { | ||
9646 | el.className = attrs[attr]; | ||
9647 | } else { | ||
9648 | el.setAttribute(attr, attrs[attr]); | ||
9649 | } | ||
9650 | }); | ||
9651 | |||
9652 | // Update tag id/class for use as HTML5 playback tech | ||
9653 | // Might think we should do this after embedding in container so .vjs-tech class | ||
9654 | // doesn't flash 100% width/height, but class only applies with .video-js parent | ||
9655 | tag.playerId = tag.id; | ||
9656 | tag.id += '_html5_api'; | ||
9657 | tag.className = 'vjs-tech'; | ||
9658 | |||
9659 | // Make player findable on elements | ||
9660 | tag.player = el.player = this; | ||
9661 | // Default state of video is paused | ||
9662 | this.addClass('vjs-paused'); | ||
9663 | |||
9664 | // Add a style element in the player that we'll use to set the width/height | ||
9665 | // of the player in a way that's still overrideable by CSS, just like the | ||
9666 | // video element | ||
9667 | this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions'); | ||
9668 | var defaultsStyleEl = Dom.$('.vjs-styles-defaults'); | ||
9669 | var head = Dom.$('head'); | ||
9670 | head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild); | ||
9671 | |||
9672 | // Pass in the width/height/aspectRatio options which will update the style el | ||
9673 | this.width(this.options_.width); | ||
9674 | this.height(this.options_.height); | ||
9675 | this.fluid(this.options_.fluid); | ||
9676 | this.aspectRatio(this.options_.aspectRatio); | ||
9677 | |||
9678 | // insertElFirst seems to cause the networkState to flicker from 3 to 2, so | ||
9679 | // keep track of the original for later so we can know if the source originally failed | ||
9680 | tag.initNetworkState_ = tag.networkState; | ||
9681 | |||
9682 | // Wrap video tag in div (el/box) container | ||
9683 | if (tag.parentNode) { | ||
9684 | tag.parentNode.insertBefore(el, tag); | ||
9685 | } | ||
9686 | |||
9687 | // insert the tag as the first child of the player element | ||
9688 | // then manually add it to the children array so that this.addChild | ||
9689 | // will work properly for other components | ||
9690 | Dom.insertElFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup. | ||
9691 | this.children_.unshift(tag); | ||
9692 | |||
9693 | this.el_ = el; | ||
9694 | |||
9695 | return el; | ||
9696 | }; | ||
9697 | |||
9698 | /** | ||
9699 | * Get/set player width | ||
9700 | * | ||
9701 | * @param {Number=} value Value for width | ||
9702 | * @return {Number} Width when getting | ||
9703 | * @method width | ||
9704 | */ | ||
9705 | |||
9706 | Player.prototype.width = function width(value) { | ||
9707 | return this.dimension('width', value); | ||
9708 | }; | ||
9709 | |||
9710 | /** | ||
9711 | * Get/set player height | ||
9712 | * | ||
9713 | * @param {Number=} value Value for height | ||
9714 | * @return {Number} Height when getting | ||
9715 | * @method height | ||
9716 | */ | ||
9717 | |||
9718 | Player.prototype.height = function height(value) { | ||
9719 | return this.dimension('height', value); | ||
9720 | }; | ||
9721 | |||
9722 | /** | ||
9723 | * Get/set dimension for player | ||
9724 | * | ||
9725 | * @param {String} dimension Either width or height | ||
9726 | * @param {Number=} value Value for dimension | ||
9727 | * @return {Component} | ||
9728 | * @method dimension | ||
9729 | */ | ||
9730 | |||
9731 | Player.prototype.dimension = function dimension(_dimension, value) { | ||
9732 | var privDimension = _dimension + '_'; | ||
9733 | |||
9734 | if (value === undefined) { | ||
9735 | return this[privDimension] || 0; | ||
9736 | } | ||
9737 | |||
9738 | if (value === '') { | ||
9739 | // If an empty string is given, reset the dimension to be automatic | ||
9740 | this[privDimension] = undefined; | ||
9741 | } else { | ||
9742 | var parsedVal = parseFloat(value); | ||
9743 | |||
9744 | if (isNaN(parsedVal)) { | ||
9745 | _utilsLogJs2['default'].error('Improper value "' + value + '" supplied for for ' + _dimension); | ||
9746 | return this; | ||
9747 | } | ||
9748 | |||
9749 | this[privDimension] = parsedVal; | ||
9750 | } | ||
9751 | |||
9752 | this.updateStyleEl_(); | ||
9753 | return this; | ||
9754 | }; | ||
9755 | |||
9756 | /** | ||
9757 | * Add/remove the vjs-fluid class | ||
9758 | * | ||
9759 | * @param {Boolean} bool Value of true adds the class, value of false removes the class | ||
9760 | * @method fluid | ||
9761 | */ | ||
9762 | |||
9763 | Player.prototype.fluid = function fluid(bool) { | ||
9764 | if (bool === undefined) { | ||
9765 | return !!this.fluid_; | ||
9766 | } | ||
9767 | |||
9768 | this.fluid_ = !!bool; | ||
9769 | |||
9770 | if (bool) { | ||
9771 | this.addClass('vjs-fluid'); | ||
9772 | } else { | ||
9773 | this.removeClass('vjs-fluid'); | ||
9774 | } | ||
9775 | }; | ||
9776 | |||
9777 | /** | ||
9778 | * Get/Set the aspect ratio | ||
9779 | * | ||
9780 | * @param {String=} ratio Aspect ratio for player | ||
9781 | * @return aspectRatio | ||
9782 | * @method aspectRatio | ||
9783 | */ | ||
9784 | |||
9785 | Player.prototype.aspectRatio = function aspectRatio(ratio) { | ||
9786 | if (ratio === undefined) { | ||
9787 | return this.aspectRatio_; | ||
9788 | } | ||
9789 | |||
9790 | // Check for width:height format | ||
9791 | if (!/^\d+\:\d+$/.test(ratio)) { | ||
9792 | throw new Error('Improper value supplied for aspect ratio. The format should be width:height, for example 16:9.'); | ||
9793 | } | ||
9794 | this.aspectRatio_ = ratio; | ||
9795 | |||
9796 | // We're assuming if you set an aspect ratio you want fluid mode, | ||
9797 | // because in fixed mode you could calculate width and height yourself. | ||
9798 | this.fluid(true); | ||
9799 | |||
9800 | this.updateStyleEl_(); | ||
9801 | }; | ||
9802 | |||
9803 | /** | ||
9804 | * Update styles of the player element (height, width and aspect ratio) | ||
9805 | * | ||
9806 | * @method updateStyleEl_ | ||
9807 | */ | ||
9808 | |||
9809 | Player.prototype.updateStyleEl_ = function updateStyleEl_() { | ||
9810 | var width = undefined; | ||
9811 | var height = undefined; | ||
9812 | var aspectRatio = undefined; | ||
9813 | var idClass = undefined; | ||
9814 | |||
9815 | // The aspect ratio is either used directly or to calculate width and height. | ||
9816 | if (this.aspectRatio_ !== undefined && this.aspectRatio_ !== 'auto') { | ||
9817 | // Use any aspectRatio that's been specifically set | ||
9818 | aspectRatio = this.aspectRatio_; | ||
9819 | } else if (this.videoWidth()) { | ||
9820 | // Otherwise try to get the aspect ratio from the video metadata | ||
9821 | aspectRatio = this.videoWidth() + ':' + this.videoHeight(); | ||
9822 | } else { | ||
9823 | // Or use a default. The video element's is 2:1, but 16:9 is more common. | ||
9824 | aspectRatio = '16:9'; | ||
9825 | } | ||
9826 | |||
9827 | // Get the ratio as a decimal we can use to calculate dimensions | ||
9828 | var ratioParts = aspectRatio.split(':'); | ||
9829 | var ratioMultiplier = ratioParts[1] / ratioParts[0]; | ||
9830 | |||
9831 | if (this.width_ !== undefined) { | ||
9832 | // Use any width that's been specifically set | ||
9833 | width = this.width_; | ||
9834 | } else if (this.height_ !== undefined) { | ||
9835 | // Or calulate the width from the aspect ratio if a height has been set | ||
9836 | width = this.height_ / ratioMultiplier; | ||
9837 | } else { | ||
9838 | // Or use the video's metadata, or use the video el's default of 300 | ||
9839 | width = this.videoWidth() || 300; | ||
9840 | } | ||
9841 | |||
9842 | if (this.height_ !== undefined) { | ||
9843 | // Use any height that's been specifically set | ||
9844 | height = this.height_; | ||
9845 | } else { | ||
9846 | // Otherwise calculate the height from the ratio and the width | ||
9847 | height = width * ratioMultiplier; | ||
9848 | } | ||
9849 | |||
9850 | // Ensure the CSS class is valid by starting with an alpha character | ||
9851 | if (/^[^a-zA-Z]/.test(this.id())) { | ||
9852 | idClass = 'dimensions-' + this.id(); | ||
9853 | } else { | ||
9854 | idClass = this.id() + '-dimensions'; | ||
9855 | } | ||
9856 | |||
9857 | // Ensure the right class is still on the player for the style element | ||
9858 | this.addClass(idClass); | ||
9859 | |||
9860 | stylesheet.setTextContent(this.styleEl_, '\n .' + idClass + ' {\n width: ' + width + 'px;\n height: ' + height + 'px;\n }\n\n .' + idClass + '.vjs-fluid {\n padding-top: ' + ratioMultiplier * 100 + '%;\n }\n '); | ||
9861 | }; | ||
9862 | |||
9863 | /** | ||
9864 | * Load the Media Playback Technology (tech) | ||
9865 | * Load/Create an instance of playback technology including element and API methods | ||
9866 | * And append playback element in player div. | ||
9867 | * | ||
9868 | * @param {String} techName Name of the playback technology | ||
9869 | * @param {String} source Video source | ||
9870 | * @method loadTech_ | ||
9871 | * @private | ||
9872 | */ | ||
9873 | |||
9874 | Player.prototype.loadTech_ = function loadTech_(techName, source) { | ||
9875 | |||
9876 | // Pause and remove current playback technology | ||
9877 | if (this.tech_) { | ||
9878 | this.unloadTech_(); | ||
9879 | } | ||
9880 | |||
9881 | // get rid of the HTML5 video tag as soon as we are using another tech | ||
9882 | if (techName !== 'Html5' && this.tag) { | ||
9883 | _techTechJs2['default'].getTech('Html5').disposeMediaElement(this.tag); | ||
9884 | this.tag.player = null; | ||
9885 | this.tag = null; | ||
9886 | } | ||
9887 | |||
9888 | this.techName_ = techName; | ||
9889 | |||
9890 | // Turn off API access because we're loading a new tech that might load asynchronously | ||
9891 | this.isReady_ = false; | ||
9892 | |||
9893 | // Grab tech-specific options from player options and add source and parent element to use. | ||
9894 | var techOptions = _objectAssign2['default']({ | ||
9895 | 'nativeControlsForTouch': this.options_.nativeControlsForTouch, | ||
9896 | 'source': source, | ||
9897 | 'playerId': this.id(), | ||
9898 | 'techId': this.id() + '_' + techName + '_api', | ||
9899 | 'textTracks': this.textTracks_, | ||
9900 | 'autoplay': this.options_.autoplay, | ||
9901 | 'preload': this.options_.preload, | ||
9902 | 'loop': this.options_.loop, | ||
9903 | 'muted': this.options_.muted, | ||
9904 | 'poster': this.poster(), | ||
9905 | 'language': this.language(), | ||
9906 | 'vtt.js': this.options_['vtt.js'] | ||
9907 | }, this.options_[techName.toLowerCase()]); | ||
9908 | |||
9909 | if (this.tag) { | ||
9910 | techOptions.tag = this.tag; | ||
9911 | } | ||
9912 | |||
9913 | if (source) { | ||
9914 | this.currentType_ = source.type; | ||
9915 | if (source.src === this.cache_.src && this.cache_.currentTime > 0) { | ||
9916 | techOptions.startTime = this.cache_.currentTime; | ||
9917 | } | ||
9918 | |||
9919 | this.cache_.src = source.src; | ||
9920 | } | ||
9921 | |||
9922 | // Initialize tech instance | ||
9923 | var techComponent = _techTechJs2['default'].getTech(techName); | ||
9924 | // Support old behavior of techs being registered as components. | ||
9925 | // Remove once that deprecated behavior is removed. | ||
9926 | if (!techComponent) { | ||
9927 | techComponent = _componentJs2['default'].getComponent(techName); | ||
9928 | } | ||
9929 | this.tech_ = new techComponent(techOptions); | ||
9930 | |||
9931 | // player.triggerReady is always async, so don't need this to be async | ||
9932 | this.tech_.ready(Fn.bind(this, this.handleTechReady_), true); | ||
9933 | |||
9934 | _tracksTextTrackListConverterJs2['default'].jsonToTextTracks(this.textTracksJson_ || [], this.tech_); | ||
9935 | |||
9936 | // Listen to all HTML5-defined events and trigger them on the player | ||
9937 | this.on(this.tech_, 'loadstart', this.handleTechLoadStart_); | ||
9938 | this.on(this.tech_, 'waiting', this.handleTechWaiting_); | ||
9939 | this.on(this.tech_, 'canplay', this.handleTechCanPlay_); | ||
9940 | this.on(this.tech_, 'canplaythrough', this.handleTechCanPlayThrough_); | ||
9941 | this.on(this.tech_, 'playing', this.handleTechPlaying_); | ||
9942 | this.on(this.tech_, 'ended', this.handleTechEnded_); | ||
9943 | this.on(this.tech_, 'seeking', this.handleTechSeeking_); | ||
9944 | this.on(this.tech_, 'seeked', this.handleTechSeeked_); | ||
9945 | this.on(this.tech_, 'play', this.handleTechPlay_); | ||
9946 | this.on(this.tech_, 'firstplay', this.handleTechFirstPlay_); | ||
9947 | this.on(this.tech_, 'pause', this.handleTechPause_); | ||
9948 | this.on(this.tech_, 'progress', this.handleTechProgress_); | ||
9949 | this.on(this.tech_, 'durationchange', this.handleTechDurationChange_); | ||
9950 | this.on(this.tech_, 'fullscreenchange', this.handleTechFullscreenChange_); | ||
9951 | this.on(this.tech_, 'error', this.handleTechError_); | ||
9952 | this.on(this.tech_, 'suspend', this.handleTechSuspend_); | ||
9953 | this.on(this.tech_, 'abort', this.handleTechAbort_); | ||
9954 | this.on(this.tech_, 'emptied', this.handleTechEmptied_); | ||
9955 | this.on(this.tech_, 'stalled', this.handleTechStalled_); | ||
9956 | this.on(this.tech_, 'loadedmetadata', this.handleTechLoadedMetaData_); | ||
9957 | this.on(this.tech_, 'loadeddata', this.handleTechLoadedData_); | ||
9958 | this.on(this.tech_, 'timeupdate', this.handleTechTimeUpdate_); | ||
9959 | this.on(this.tech_, 'ratechange', this.handleTechRateChange_); | ||
9960 | this.on(this.tech_, 'volumechange', this.handleTechVolumeChange_); | ||
9961 | this.on(this.tech_, 'texttrackchange', this.handleTechTextTrackChange_); | ||
9962 | this.on(this.tech_, 'loadedmetadata', this.updateStyleEl_); | ||
9963 | this.on(this.tech_, 'posterchange', this.handleTechPosterChange_); | ||
9964 | |||
9965 | this.usingNativeControls(this.techGet_('controls')); | ||
9966 | |||
9967 | if (this.controls() && !this.usingNativeControls()) { | ||
9968 | this.addTechControlsListeners_(); | ||
9969 | } | ||
9970 | |||
9971 | // Add the tech element in the DOM if it was not already there | ||
9972 | // Make sure to not insert the original video element if using Html5 | ||
9973 | if (this.tech_.el().parentNode !== this.el() && (techName !== 'Html5' || !this.tag)) { | ||
9974 | Dom.insertElFirst(this.tech_.el(), this.el()); | ||
9975 | } | ||
9976 | |||
9977 | // Get rid of the original video tag reference after the first tech is loaded | ||
9978 | if (this.tag) { | ||
9979 | this.tag.player = null; | ||
9980 | this.tag = null; | ||
9981 | } | ||
9982 | }; | ||
9983 | |||
9984 | /** | ||
9985 | * Unload playback technology | ||
9986 | * | ||
9987 | * @method unloadTech_ | ||
9988 | * @private | ||
9989 | */ | ||
9990 | |||
9991 | Player.prototype.unloadTech_ = function unloadTech_() { | ||
9992 | // Save the current text tracks so that we can reuse the same text tracks with the next tech | ||
9993 | this.textTracks_ = this.textTracks(); | ||
9994 | this.textTracksJson_ = _tracksTextTrackListConverterJs2['default'].textTracksToJson(this.tech_); | ||
9995 | |||
9996 | this.isReady_ = false; | ||
9997 | |||
9998 | this.tech_.dispose(); | ||
9999 | |||
10000 | this.tech_ = false; | ||
10001 | }; | ||
10002 | |||
10003 | /** | ||
10004 | * Return a reference to the current tech. | ||
10005 | * It will only return a reference to the tech if given an object with the | ||
10006 | * `IWillNotUseThisInPlugins` property on it. This is try and prevent misuse | ||
10007 | * of techs by plugins. | ||
10008 | * | ||
10009 | * @param {Object} | ||
10010 | * @return {Object} The Tech | ||
10011 | * @method tech | ||
10012 | */ | ||
10013 | |||
10014 | Player.prototype.tech = function tech(safety) { | ||
10015 | if (safety && safety.IWillNotUseThisInPlugins) { | ||
10016 | return this.tech_; | ||
10017 | } | ||
10018 | var errorText = '\n Please make sure that you are not using this inside of a plugin.\n To disable this alert and error, please pass in an object with\n `IWillNotUseThisInPlugins` to the `tech` method. See\n https://github.com/videojs/video.js/issues/2617 for more info.\n '; | ||
10019 | _globalWindow2['default'].alert(errorText); | ||
10020 | throw new Error(errorText); | ||
10021 | }; | ||
10022 | |||
10023 | /** | ||
10024 | * Set up click and touch listeners for the playback element | ||
10025 | * | ||
10026 | * On desktops, a click on the video itself will toggle playback, | ||
10027 | * on a mobile device a click on the video toggles controls. | ||
10028 | * (toggling controls is done by toggling the user state between active and | ||
10029 | * inactive) | ||
10030 | * A tap can signal that a user has become active, or has become inactive | ||
10031 | * e.g. a quick tap on an iPhone movie should reveal the controls. Another | ||
10032 | * quick tap should hide them again (signaling the user is in an inactive | ||
10033 | * viewing state) | ||
10034 | * In addition to this, we still want the user to be considered inactive after | ||
10035 | * a few seconds of inactivity. | ||
10036 | * Note: the only part of iOS interaction we can't mimic with this setup | ||
10037 | * is a touch and hold on the video element counting as activity in order to | ||
10038 | * keep the controls showing, but that shouldn't be an issue. A touch and hold | ||
10039 | * on any controls will still keep the user active | ||
10040 | * | ||
10041 | * @private | ||
10042 | * @method addTechControlsListeners_ | ||
10043 | */ | ||
10044 | |||
10045 | Player.prototype.addTechControlsListeners_ = function addTechControlsListeners_() { | ||
10046 | // Make sure to remove all the previous listeners in case we are called multiple times. | ||
10047 | this.removeTechControlsListeners_(); | ||
10048 | |||
10049 | // Some browsers (Chrome & IE) don't trigger a click on a flash swf, but do | ||
10050 | // trigger mousedown/up. | ||
10051 | // http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object | ||
10052 | // Any touch events are set to block the mousedown event from happening | ||
10053 | this.on(this.tech_, 'mousedown', this.handleTechClick_); | ||
10054 | |||
10055 | // If the controls were hidden we don't want that to change without a tap event | ||
10056 | // so we'll check if the controls were already showing before reporting user | ||
10057 | // activity | ||
10058 | this.on(this.tech_, 'touchstart', this.handleTechTouchStart_); | ||
10059 | this.on(this.tech_, 'touchmove', this.handleTechTouchMove_); | ||
10060 | this.on(this.tech_, 'touchend', this.handleTechTouchEnd_); | ||
10061 | |||
10062 | // The tap listener needs to come after the touchend listener because the tap | ||
10063 | // listener cancels out any reportedUserActivity when setting userActive(false) | ||
10064 | this.on(this.tech_, 'tap', this.handleTechTap_); | ||
10065 | }; | ||
10066 | |||
10067 | /** | ||
10068 | * Remove the listeners used for click and tap controls. This is needed for | ||
10069 | * toggling to controls disabled, where a tap/touch should do nothing. | ||
10070 | * | ||
10071 | * @method removeTechControlsListeners_ | ||
10072 | * @private | ||
10073 | */ | ||
10074 | |||
10075 | Player.prototype.removeTechControlsListeners_ = function removeTechControlsListeners_() { | ||
10076 | // We don't want to just use `this.off()` because there might be other needed | ||
10077 | // listeners added by techs that extend this. | ||
10078 | this.off(this.tech_, 'tap', this.handleTechTap_); | ||
10079 | this.off(this.tech_, 'touchstart', this.handleTechTouchStart_); | ||
10080 | this.off(this.tech_, 'touchmove', this.handleTechTouchMove_); | ||
10081 | this.off(this.tech_, 'touchend', this.handleTechTouchEnd_); | ||
10082 | this.off(this.tech_, 'mousedown', this.handleTechClick_); | ||
10083 | }; | ||
10084 | |||
10085 | /** | ||
10086 | * Player waits for the tech to be ready | ||
10087 | * | ||
10088 | * @method handleTechReady_ | ||
10089 | * @private | ||
10090 | */ | ||
10091 | |||
10092 | Player.prototype.handleTechReady_ = function handleTechReady_() { | ||
10093 | this.triggerReady(); | ||
10094 | |||
10095 | // Keep the same volume as before | ||
10096 | if (this.cache_.volume) { | ||
10097 | this.techCall_('setVolume', this.cache_.volume); | ||
10098 | } | ||
10099 | |||
10100 | // Look if the tech found a higher resolution poster while loading | ||
10101 | this.handleTechPosterChange_(); | ||
10102 | |||
10103 | // Update the duration if available | ||
10104 | this.handleTechDurationChange_(); | ||
10105 | |||
10106 | // Chrome and Safari both have issues with autoplay. | ||
10107 | // In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work. | ||
10108 | // In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays) | ||
10109 | // This fixes both issues. Need to wait for API, so it updates displays correctly | ||
10110 | if (this.src() && this.tag && this.options_.autoplay && this.paused()) { | ||
10111 | delete this.tag.poster; // Chrome Fix. Fixed in Chrome v16. | ||
10112 | this.play(); | ||
10113 | } | ||
10114 | }; | ||
10115 | |||
10116 | /** | ||
10117 | * Fired when the user agent begins looking for media data | ||
10118 | * | ||
10119 | * @private | ||
10120 | * @method handleTechLoadStart_ | ||
10121 | */ | ||
10122 | |||
10123 | Player.prototype.handleTechLoadStart_ = function handleTechLoadStart_() { | ||
10124 | // TODO: Update to use `emptied` event instead. See #1277. | ||
10125 | |||
10126 | this.removeClass('vjs-ended'); | ||
10127 | |||
10128 | // reset the error state | ||
10129 | this.error(null); | ||
10130 | |||
10131 | // If it's already playing we want to trigger a firstplay event now. | ||
10132 | // The firstplay event relies on both the play and loadstart events | ||
10133 | // which can happen in any order for a new source | ||
10134 | if (!this.paused()) { | ||
10135 | this.trigger('loadstart'); | ||
10136 | this.trigger('firstplay'); | ||
10137 | } else { | ||
10138 | // reset the hasStarted state | ||
10139 | this.hasStarted(false); | ||
10140 | this.trigger('loadstart'); | ||
10141 | } | ||
10142 | }; | ||
10143 | |||
10144 | /** | ||
10145 | * Add/remove the vjs-has-started class | ||
10146 | * | ||
10147 | * @param {Boolean} hasStarted The value of true adds the class the value of false remove the class | ||
10148 | * @return {Boolean} Boolean value if has started | ||
10149 | * @private | ||
10150 | * @method hasStarted | ||
10151 | */ | ||
10152 | |||
10153 | Player.prototype.hasStarted = function hasStarted(_hasStarted) { | ||
10154 | if (_hasStarted !== undefined) { | ||
10155 | // only update if this is a new value | ||
10156 | if (this.hasStarted_ !== _hasStarted) { | ||
10157 | this.hasStarted_ = _hasStarted; | ||
10158 | if (_hasStarted) { | ||
10159 | this.addClass('vjs-has-started'); | ||
10160 | // trigger the firstplay event if this newly has played | ||
10161 | this.trigger('firstplay'); | ||
10162 | } else { | ||
10163 | this.removeClass('vjs-has-started'); | ||
10164 | } | ||
10165 | } | ||
10166 | return this; | ||
10167 | } | ||
10168 | return !!this.hasStarted_; | ||
10169 | }; | ||
10170 | |||
10171 | /** | ||
10172 | * Fired whenever the media begins or resumes playback | ||
10173 | * | ||
10174 | * @private | ||
10175 | * @method handleTechPlay_ | ||
10176 | */ | ||
10177 | |||
10178 | Player.prototype.handleTechPlay_ = function handleTechPlay_() { | ||
10179 | this.removeClass('vjs-ended'); | ||
10180 | this.removeClass('vjs-paused'); | ||
10181 | this.addClass('vjs-playing'); | ||
10182 | |||
10183 | // hide the poster when the user hits play | ||
10184 | // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play | ||
10185 | this.hasStarted(true); | ||
10186 | |||
10187 | this.trigger('play'); | ||
10188 | }; | ||
10189 | |||
10190 | /** | ||
10191 | * Fired whenever the media begins waiting | ||
10192 | * | ||
10193 | * @private | ||
10194 | * @method handleTechWaiting_ | ||
10195 | */ | ||
10196 | |||
10197 | Player.prototype.handleTechWaiting_ = function handleTechWaiting_() { | ||
10198 | var _this2 = this; | ||
10199 | |||
10200 | this.addClass('vjs-waiting'); | ||
10201 | this.trigger('waiting'); | ||
10202 | this.one('timeupdate', function () { | ||
10203 | return _this2.removeClass('vjs-waiting'); | ||
10204 | }); | ||
10205 | }; | ||
10206 | |||
10207 | /** | ||
10208 | * A handler for events that signal that waiting has ended | ||
10209 | * which is not consistent between browsers. See #1351 | ||
10210 | * | ||
10211 | * @private | ||
10212 | * @method handleTechCanPlay_ | ||
10213 | */ | ||
10214 | |||
10215 | Player.prototype.handleTechCanPlay_ = function handleTechCanPlay_() { | ||
10216 | this.removeClass('vjs-waiting'); | ||
10217 | this.trigger('canplay'); | ||
10218 | }; | ||
10219 | |||
10220 | /** | ||
10221 | * A handler for events that signal that waiting has ended | ||
10222 | * which is not consistent between browsers. See #1351 | ||
10223 | * | ||
10224 | * @private | ||
10225 | * @method handleTechCanPlayThrough_ | ||
10226 | */ | ||
10227 | |||
10228 | Player.prototype.handleTechCanPlayThrough_ = function handleTechCanPlayThrough_() { | ||
10229 | this.removeClass('vjs-waiting'); | ||
10230 | this.trigger('canplaythrough'); | ||
10231 | }; | ||
10232 | |||
10233 | /** | ||
10234 | * A handler for events that signal that waiting has ended | ||
10235 | * which is not consistent between browsers. See #1351 | ||
10236 | * | ||
10237 | * @private | ||
10238 | * @method handleTechPlaying_ | ||
10239 | */ | ||
10240 | |||
10241 | Player.prototype.handleTechPlaying_ = function handleTechPlaying_() { | ||
10242 | this.removeClass('vjs-waiting'); | ||
10243 | this.trigger('playing'); | ||
10244 | }; | ||
10245 | |||
10246 | /** | ||
10247 | * Fired whenever the player is jumping to a new time | ||
10248 | * | ||
10249 | * @private | ||
10250 | * @method handleTechSeeking_ | ||
10251 | */ | ||
10252 | |||
10253 | Player.prototype.handleTechSeeking_ = function handleTechSeeking_() { | ||
10254 | this.addClass('vjs-seeking'); | ||
10255 | this.trigger('seeking'); | ||
10256 | }; | ||
10257 | |||
10258 | /** | ||
10259 | * Fired when the player has finished jumping to a new time | ||
10260 | * | ||
10261 | * @private | ||
10262 | * @method handleTechSeeked_ | ||
10263 | */ | ||
10264 | |||
10265 | Player.prototype.handleTechSeeked_ = function handleTechSeeked_() { | ||
10266 | this.removeClass('vjs-seeking'); | ||
10267 | this.trigger('seeked'); | ||
10268 | }; | ||
10269 | |||
10270 | /** | ||
10271 | * Fired the first time a video is played | ||
10272 | * Not part of the HLS spec, and we're not sure if this is the best | ||
10273 | * implementation yet, so use sparingly. If you don't have a reason to | ||
10274 | * prevent playback, use `myPlayer.one('play');` instead. | ||
10275 | * | ||
10276 | * @private | ||
10277 | * @method handleTechFirstPlay_ | ||
10278 | */ | ||
10279 | |||
10280 | Player.prototype.handleTechFirstPlay_ = function handleTechFirstPlay_() { | ||
10281 | //If the first starttime attribute is specified | ||
10282 | //then we will start at the given offset in seconds | ||
10283 | if (this.options_.starttime) { | ||
10284 | this.currentTime(this.options_.starttime); | ||
10285 | } | ||
10286 | |||
10287 | this.addClass('vjs-has-started'); | ||
10288 | this.trigger('firstplay'); | ||
10289 | }; | ||
10290 | |||
10291 | /** | ||
10292 | * Fired whenever the media has been paused | ||
10293 | * | ||
10294 | * @private | ||
10295 | * @method handleTechPause_ | ||
10296 | */ | ||
10297 | |||
10298 | Player.prototype.handleTechPause_ = function handleTechPause_() { | ||
10299 | this.removeClass('vjs-playing'); | ||
10300 | this.addClass('vjs-paused'); | ||
10301 | this.trigger('pause'); | ||
10302 | }; | ||
10303 | |||
10304 | /** | ||
10305 | * Fired while the user agent is downloading media data | ||
10306 | * | ||
10307 | * @private | ||
10308 | * @method handleTechProgress_ | ||
10309 | */ | ||
10310 | |||
10311 | Player.prototype.handleTechProgress_ = function handleTechProgress_() { | ||
10312 | this.trigger('progress'); | ||
10313 | }; | ||
10314 | |||
10315 | /** | ||
10316 | * Fired when the end of the media resource is reached (currentTime == duration) | ||
10317 | * | ||
10318 | * @private | ||
10319 | * @method handleTechEnded_ | ||
10320 | */ | ||
10321 | |||
10322 | Player.prototype.handleTechEnded_ = function handleTechEnded_() { | ||
10323 | this.addClass('vjs-ended'); | ||
10324 | if (this.options_.loop) { | ||
10325 | this.currentTime(0); | ||
10326 | this.play(); | ||
10327 | } else if (!this.paused()) { | ||
10328 | this.pause(); | ||
10329 | } | ||
10330 | |||
10331 | this.trigger('ended'); | ||
10332 | }; | ||
10333 | |||
10334 | /** | ||
10335 | * Fired when the duration of the media resource is first known or changed | ||
10336 | * | ||
10337 | * @private | ||
10338 | * @method handleTechDurationChange_ | ||
10339 | */ | ||
10340 | |||
10341 | Player.prototype.handleTechDurationChange_ = function handleTechDurationChange_() { | ||
10342 | this.duration(this.techGet_('duration')); | ||
10343 | }; | ||
10344 | |||
10345 | /** | ||
10346 | * Handle a click on the media element to play/pause | ||
10347 | * | ||
10348 | * @param {Object=} event Event object | ||
10349 | * @private | ||
10350 | * @method handleTechClick_ | ||
10351 | */ | ||
10352 | |||
10353 | Player.prototype.handleTechClick_ = function handleTechClick_(event) { | ||
10354 | // We're using mousedown to detect clicks thanks to Flash, but mousedown | ||
10355 | // will also be triggered with right-clicks, so we need to prevent that | ||
10356 | if (event.button !== 0) return; | ||
10357 | |||
10358 | // When controls are disabled a click should not toggle playback because | ||
10359 | // the click is considered a control | ||
10360 | if (this.controls()) { | ||
10361 | if (this.paused()) { | ||
10362 | this.play(); | ||
10363 | } else { | ||
10364 | this.pause(); | ||
10365 | } | ||
10366 | } | ||
10367 | }; | ||
10368 | |||
10369 | /** | ||
10370 | * Handle a tap on the media element. It will toggle the user | ||
10371 | * activity state, which hides and shows the controls. | ||
10372 | * | ||
10373 | * @private | ||
10374 | * @method handleTechTap_ | ||
10375 | */ | ||
10376 | |||
10377 | Player.prototype.handleTechTap_ = function handleTechTap_() { | ||
10378 | this.userActive(!this.userActive()); | ||
10379 | }; | ||
10380 | |||
10381 | /** | ||
10382 | * Handle touch to start | ||
10383 | * | ||
10384 | * @private | ||
10385 | * @method handleTechTouchStart_ | ||
10386 | */ | ||
10387 | |||
10388 | Player.prototype.handleTechTouchStart_ = function handleTechTouchStart_() { | ||
10389 | this.userWasActive = this.userActive(); | ||
10390 | }; | ||
10391 | |||
10392 | /** | ||
10393 | * Handle touch to move | ||
10394 | * | ||
10395 | * @private | ||
10396 | * @method handleTechTouchMove_ | ||
10397 | */ | ||
10398 | |||
10399 | Player.prototype.handleTechTouchMove_ = function handleTechTouchMove_() { | ||
10400 | if (this.userWasActive) { | ||
10401 | this.reportUserActivity(); | ||
10402 | } | ||
10403 | }; | ||
10404 | |||
10405 | /** | ||
10406 | * Handle touch to end | ||
10407 | * | ||
10408 | * @private | ||
10409 | * @method handleTechTouchEnd_ | ||
10410 | */ | ||
10411 | |||
10412 | Player.prototype.handleTechTouchEnd_ = function handleTechTouchEnd_(event) { | ||
10413 | // Stop the mouse events from also happening | ||
10414 | event.preventDefault(); | ||
10415 | }; | ||
10416 | |||
10417 | /** | ||
10418 | * Fired when the player switches in or out of fullscreen mode | ||
10419 | * | ||
10420 | * @private | ||
10421 | * @method handleFullscreenChange_ | ||
10422 | */ | ||
10423 | |||
10424 | Player.prototype.handleFullscreenChange_ = function handleFullscreenChange_() { | ||
10425 | if (this.isFullscreen()) { | ||
10426 | this.addClass('vjs-fullscreen'); | ||
10427 | } else { | ||
10428 | this.removeClass('vjs-fullscreen'); | ||
10429 | } | ||
10430 | }; | ||
10431 | |||
10432 | /** | ||
10433 | * native click events on the SWF aren't triggered on IE11, Win8.1RT | ||
10434 | * use stageclick events triggered from inside the SWF instead | ||
10435 | * | ||
10436 | * @private | ||
10437 | * @method handleStageClick_ | ||
10438 | */ | ||
10439 | |||
10440 | Player.prototype.handleStageClick_ = function handleStageClick_() { | ||
10441 | this.reportUserActivity(); | ||
10442 | }; | ||
10443 | |||
10444 | /** | ||
10445 | * Handle Tech Fullscreen Change | ||
10446 | * | ||
10447 | * @private | ||
10448 | * @method handleTechFullscreenChange_ | ||
10449 | */ | ||
10450 | |||
10451 | Player.prototype.handleTechFullscreenChange_ = function handleTechFullscreenChange_(event, data) { | ||
10452 | if (data) { | ||
10453 | this.isFullscreen(data.isFullscreen); | ||
10454 | } | ||
10455 | this.trigger('fullscreenchange'); | ||
10456 | }; | ||
10457 | |||
10458 | /** | ||
10459 | * Fires when an error occurred during the loading of an audio/video | ||
10460 | * | ||
10461 | * @private | ||
10462 | * @method handleTechError_ | ||
10463 | */ | ||
10464 | |||
10465 | Player.prototype.handleTechError_ = function handleTechError_() { | ||
10466 | var error = this.tech_.error(); | ||
10467 | this.error(error && error.code); | ||
10468 | }; | ||
10469 | |||
10470 | /** | ||
10471 | * Fires when the browser is intentionally not getting media data | ||
10472 | * | ||
10473 | * @private | ||
10474 | * @method handleTechSuspend_ | ||
10475 | */ | ||
10476 | |||
10477 | Player.prototype.handleTechSuspend_ = function handleTechSuspend_() { | ||
10478 | this.trigger('suspend'); | ||
10479 | }; | ||
10480 | |||
10481 | /** | ||
10482 | * Fires when the loading of an audio/video is aborted | ||
10483 | * | ||
10484 | * @private | ||
10485 | * @method handleTechAbort_ | ||
10486 | */ | ||
10487 | |||
10488 | Player.prototype.handleTechAbort_ = function handleTechAbort_() { | ||
10489 | this.trigger('abort'); | ||
10490 | }; | ||
10491 | |||
10492 | /** | ||
10493 | * Fires when the current playlist is empty | ||
10494 | * | ||
10495 | * @private | ||
10496 | * @method handleTechEmptied_ | ||
10497 | */ | ||
10498 | |||
10499 | Player.prototype.handleTechEmptied_ = function handleTechEmptied_() { | ||
10500 | this.trigger('emptied'); | ||
10501 | }; | ||
10502 | |||
10503 | /** | ||
10504 | * Fires when the browser is trying to get media data, but data is not available | ||
10505 | * | ||
10506 | * @private | ||
10507 | * @method handleTechStalled_ | ||
10508 | */ | ||
10509 | |||
10510 | Player.prototype.handleTechStalled_ = function handleTechStalled_() { | ||
10511 | this.trigger('stalled'); | ||
10512 | }; | ||
10513 | |||
10514 | /** | ||
10515 | * Fires when the browser has loaded meta data for the audio/video | ||
10516 | * | ||
10517 | * @private | ||
10518 | * @method handleTechLoadedMetaData_ | ||
10519 | */ | ||
10520 | |||
10521 | Player.prototype.handleTechLoadedMetaData_ = function handleTechLoadedMetaData_() { | ||
10522 | this.trigger('loadedmetadata'); | ||
10523 | }; | ||
10524 | |||
10525 | /** | ||
10526 | * Fires when the browser has loaded the current frame of the audio/video | ||
10527 | * | ||
10528 | * @private | ||
10529 | * @method handleTechLoadedData_ | ||
10530 | */ | ||
10531 | |||
10532 | Player.prototype.handleTechLoadedData_ = function handleTechLoadedData_() { | ||
10533 | this.trigger('loadeddata'); | ||
10534 | }; | ||
10535 | |||
10536 | /** | ||
10537 | * Fires when the current playback position has changed | ||
10538 | * | ||
10539 | * @private | ||
10540 | * @method handleTechTimeUpdate_ | ||
10541 | */ | ||
10542 | |||
10543 | Player.prototype.handleTechTimeUpdate_ = function handleTechTimeUpdate_() { | ||
10544 | this.trigger('timeupdate'); | ||
10545 | }; | ||
10546 | |||
10547 | /** | ||
10548 | * Fires when the playing speed of the audio/video is changed | ||
10549 | * | ||
10550 | * @private | ||
10551 | * @method handleTechRateChange_ | ||
10552 | */ | ||
10553 | |||
10554 | Player.prototype.handleTechRateChange_ = function handleTechRateChange_() { | ||
10555 | this.trigger('ratechange'); | ||
10556 | }; | ||
10557 | |||
10558 | /** | ||
10559 | * Fires when the volume has been changed | ||
10560 | * | ||
10561 | * @private | ||
10562 | * @method handleTechVolumeChange_ | ||
10563 | */ | ||
10564 | |||
10565 | Player.prototype.handleTechVolumeChange_ = function handleTechVolumeChange_() { | ||
10566 | this.trigger('volumechange'); | ||
10567 | }; | ||
10568 | |||
10569 | /** | ||
10570 | * Fires when the text track has been changed | ||
10571 | * | ||
10572 | * @private | ||
10573 | * @method handleTechTextTrackChange_ | ||
10574 | */ | ||
10575 | |||
10576 | Player.prototype.handleTechTextTrackChange_ = function handleTechTextTrackChange_() { | ||
10577 | this.trigger('texttrackchange'); | ||
10578 | }; | ||
10579 | |||
10580 | /** | ||
10581 | * Get object for cached values. | ||
10582 | * | ||
10583 | * @return {Object} | ||
10584 | * @method getCache | ||
10585 | */ | ||
10586 | |||
10587 | Player.prototype.getCache = function getCache() { | ||
10588 | return this.cache_; | ||
10589 | }; | ||
10590 | |||
10591 | /** | ||
10592 | * Pass values to the playback tech | ||
10593 | * | ||
10594 | * @param {String=} method Method | ||
10595 | * @param {Object=} arg Argument | ||
10596 | * @private | ||
10597 | * @method techCall_ | ||
10598 | */ | ||
10599 | |||
10600 | Player.prototype.techCall_ = function techCall_(method, arg) { | ||
10601 | // If it's not ready yet, call method when it is | ||
10602 | if (this.tech_ && !this.tech_.isReady_) { | ||
10603 | this.tech_.ready(function () { | ||
10604 | this[method](arg); | ||
10605 | }, true); | ||
10606 | |||
10607 | // Otherwise call method now | ||
10608 | } else { | ||
10609 | try { | ||
10610 | this.tech_[method](arg); | ||
10611 | } catch (e) { | ||
10612 | _utilsLogJs2['default'](e); | ||
10613 | throw e; | ||
10614 | } | ||
10615 | } | ||
10616 | }; | ||
10617 | |||
10618 | /** | ||
10619 | * Get calls can't wait for the tech, and sometimes don't need to. | ||
10620 | * | ||
10621 | * @param {String} method Tech method | ||
10622 | * @return {Method} | ||
10623 | * @private | ||
10624 | * @method techGet_ | ||
10625 | */ | ||
10626 | |||
10627 | Player.prototype.techGet_ = function techGet_(method) { | ||
10628 | if (this.tech_ && this.tech_.isReady_) { | ||
10629 | |||
10630 | // Flash likes to die and reload when you hide or reposition it. | ||
10631 | // In these cases the object methods go away and we get errors. | ||
10632 | // When that happens we'll catch the errors and inform tech that it's not ready any more. | ||
10633 | try { | ||
10634 | return this.tech_[method](); | ||
10635 | } catch (e) { | ||
10636 | // When building additional tech libs, an expected method may not be defined yet | ||
10637 | if (this.tech_[method] === undefined) { | ||
10638 | _utilsLogJs2['default']('Video.js: ' + method + ' method not defined for ' + this.techName_ + ' playback technology.', e); | ||
10639 | } else { | ||
10640 | // When a method isn't available on the object it throws a TypeError | ||
10641 | if (e.name === 'TypeError') { | ||
10642 | _utilsLogJs2['default']('Video.js: ' + method + ' unavailable on ' + this.techName_ + ' playback technology element.', e); | ||
10643 | this.tech_.isReady_ = false; | ||
10644 | } else { | ||
10645 | _utilsLogJs2['default'](e); | ||
10646 | } | ||
10647 | } | ||
10648 | throw e; | ||
10649 | } | ||
10650 | } | ||
10651 | |||
10652 | return; | ||
10653 | }; | ||
10654 | |||
10655 | /** | ||
10656 | * start media playback | ||
10657 | * ```js | ||
10658 | * myPlayer.play(); | ||
10659 | * ``` | ||
10660 | * | ||
10661 | * @return {Player} self | ||
10662 | * @method play | ||
10663 | */ | ||
10664 | |||
10665 | Player.prototype.play = function play() { | ||
10666 | this.techCall_('play'); | ||
10667 | return this; | ||
10668 | }; | ||
10669 | |||
10670 | /** | ||
10671 | * Pause the video playback | ||
10672 | * ```js | ||
10673 | * myPlayer.pause(); | ||
10674 | * ``` | ||
10675 | * | ||
10676 | * @return {Player} self | ||
10677 | * @method pause | ||
10678 | */ | ||
10679 | |||
10680 | Player.prototype.pause = function pause() { | ||
10681 | this.techCall_('pause'); | ||
10682 | return this; | ||
10683 | }; | ||
10684 | |||
10685 | /** | ||
10686 | * Check if the player is paused | ||
10687 | * ```js | ||
10688 | * var isPaused = myPlayer.paused(); | ||
10689 | * var isPlaying = !myPlayer.paused(); | ||
10690 | * ``` | ||
10691 | * | ||
10692 | * @return {Boolean} false if the media is currently playing, or true otherwise | ||
10693 | * @method paused | ||
10694 | */ | ||
10695 | |||
10696 | Player.prototype.paused = function paused() { | ||
10697 | // The initial state of paused should be true (in Safari it's actually false) | ||
10698 | return this.techGet_('paused') === false ? false : true; | ||
10699 | }; | ||
10700 | |||
10701 | /** | ||
10702 | * Returns whether or not the user is "scrubbing". Scrubbing is when the user | ||
10703 | * has clicked the progress bar handle and is dragging it along the progress bar. | ||
10704 | * | ||
10705 | * @param {Boolean} isScrubbing True/false the user is scrubbing | ||
10706 | * @return {Boolean} The scrubbing status when getting | ||
10707 | * @return {Object} The player when setting | ||
10708 | * @method scrubbing | ||
10709 | */ | ||
10710 | |||
10711 | Player.prototype.scrubbing = function scrubbing(isScrubbing) { | ||
10712 | if (isScrubbing !== undefined) { | ||
10713 | this.scrubbing_ = !!isScrubbing; | ||
10714 | |||
10715 | if (isScrubbing) { | ||
10716 | this.addClass('vjs-scrubbing'); | ||
10717 | } else { | ||
10718 | this.removeClass('vjs-scrubbing'); | ||
10719 | } | ||
10720 | |||
10721 | return this; | ||
10722 | } | ||
10723 | |||
10724 | return this.scrubbing_; | ||
10725 | }; | ||
10726 | |||
10727 | /** | ||
10728 | * Get or set the current time (in seconds) | ||
10729 | * ```js | ||
10730 | * // get | ||
10731 | * var whereYouAt = myPlayer.currentTime(); | ||
10732 | * // set | ||
10733 | * myPlayer.currentTime(120); // 2 minutes into the video | ||
10734 | * ``` | ||
10735 | * | ||
10736 | * @param {Number|String=} seconds The time to seek to | ||
10737 | * @return {Number} The time in seconds, when not setting | ||
10738 | * @return {Player} self, when the current time is set | ||
10739 | * @method currentTime | ||
10740 | */ | ||
10741 | |||
10742 | Player.prototype.currentTime = function currentTime(seconds) { | ||
10743 | if (seconds !== undefined) { | ||
10744 | |||
10745 | this.techCall_('setCurrentTime', seconds); | ||
10746 | |||
10747 | return this; | ||
10748 | } | ||
10749 | |||
10750 | // cache last currentTime and return. default to 0 seconds | ||
10751 | // | ||
10752 | // Caching the currentTime is meant to prevent a massive amount of reads on the tech's | ||
10753 | // currentTime when scrubbing, but may not provide much performance benefit afterall. | ||
10754 | // Should be tested. Also something has to read the actual current time or the cache will | ||
10755 | // never get updated. | ||
10756 | return this.cache_.currentTime = this.techGet_('currentTime') || 0; | ||
10757 | }; | ||
10758 | |||
10759 | /** | ||
10760 | * Get the length in time of the video in seconds | ||
10761 | * ```js | ||
10762 | * var lengthOfVideo = myPlayer.duration(); | ||
10763 | * ``` | ||
10764 | * **NOTE**: The video must have started loading before the duration can be | ||
10765 | * known, and in the case of Flash, may not be known until the video starts | ||
10766 | * playing. | ||
10767 | * | ||
10768 | * @param {Number} seconds Duration when setting | ||
10769 | * @return {Number} The duration of the video in seconds when getting | ||
10770 | * @method duration | ||
10771 | */ | ||
10772 | |||
10773 | Player.prototype.duration = function duration(seconds) { | ||
10774 | if (seconds === undefined) { | ||
10775 | return this.cache_.duration || 0; | ||
10776 | } | ||
10777 | |||
10778 | seconds = parseFloat(seconds) || 0; | ||
10779 | |||
10780 | // Standardize on Inifity for signaling video is live | ||
10781 | if (seconds < 0) { | ||
10782 | seconds = Infinity; | ||
10783 | } | ||
10784 | |||
10785 | if (seconds !== this.cache_.duration) { | ||
10786 | // Cache the last set value for optimized scrubbing (esp. Flash) | ||
10787 | this.cache_.duration = seconds; | ||
10788 | |||
10789 | if (seconds === Infinity) { | ||
10790 | this.addClass('vjs-live'); | ||
10791 | } else { | ||
10792 | this.removeClass('vjs-live'); | ||
10793 | } | ||
10794 | |||
10795 | this.trigger('durationchange'); | ||
10796 | } | ||
10797 | |||
10798 | return this; | ||
10799 | }; | ||
10800 | |||
10801 | /** | ||
10802 | * Calculates how much time is left. | ||
10803 | * ```js | ||
10804 | * var timeLeft = myPlayer.remainingTime(); | ||
10805 | * ``` | ||
10806 | * Not a native video element function, but useful | ||
10807 | * | ||
10808 | * @return {Number} The time remaining in seconds | ||
10809 | * @method remainingTime | ||
10810 | */ | ||
10811 | |||
10812 | Player.prototype.remainingTime = function remainingTime() { | ||
10813 | return this.duration() - this.currentTime(); | ||
10814 | }; | ||
10815 | |||
10816 | // http://dev.w3.org/html5/spec/video.html#dom-media-buffered | ||
10817 | // Buffered returns a timerange object. | ||
10818 | // Kind of like an array of portions of the video that have been downloaded. | ||
10819 | |||
10820 | /** | ||
10821 | * Get a TimeRange object with the times of the video that have been downloaded | ||
10822 | * If you just want the percent of the video that's been downloaded, | ||
10823 | * use bufferedPercent. | ||
10824 | * ```js | ||
10825 | * // Number of different ranges of time have been buffered. Usually 1. | ||
10826 | * numberOfRanges = bufferedTimeRange.length, | ||
10827 | * // Time in seconds when the first range starts. Usually 0. | ||
10828 | * firstRangeStart = bufferedTimeRange.start(0), | ||
10829 | * // Time in seconds when the first range ends | ||
10830 | * firstRangeEnd = bufferedTimeRange.end(0), | ||
10831 | * // Length in seconds of the first time range | ||
10832 | * firstRangeLength = firstRangeEnd - firstRangeStart; | ||
10833 | * ``` | ||
10834 | * | ||
10835 | * @return {Object} A mock TimeRange object (following HTML spec) | ||
10836 | * @method buffered | ||
10837 | */ | ||
10838 | |||
10839 | Player.prototype.buffered = function buffered() { | ||
10840 | var buffered = this.techGet_('buffered'); | ||
10841 | |||
10842 | if (!buffered || !buffered.length) { | ||
10843 | buffered = _utilsTimeRangesJs.createTimeRange(0, 0); | ||
10844 | } | ||
10845 | |||
10846 | return buffered; | ||
10847 | }; | ||
10848 | |||
10849 | /** | ||
10850 | * Get the percent (as a decimal) of the video that's been downloaded | ||
10851 | * ```js | ||
10852 | * var howMuchIsDownloaded = myPlayer.bufferedPercent(); | ||
10853 | * ``` | ||
10854 | * 0 means none, 1 means all. | ||
10855 | * (This method isn't in the HTML5 spec, but it's very convenient) | ||
10856 | * | ||
10857 | * @return {Number} A decimal between 0 and 1 representing the percent | ||
10858 | * @method bufferedPercent | ||
10859 | */ | ||
10860 | |||
10861 | Player.prototype.bufferedPercent = function bufferedPercent() { | ||
10862 | return _utilsBufferJs.bufferedPercent(this.buffered(), this.duration()); | ||
10863 | }; | ||
10864 | |||
10865 | /** | ||
10866 | * Get the ending time of the last buffered time range | ||
10867 | * This is used in the progress bar to encapsulate all time ranges. | ||
10868 | * | ||
10869 | * @return {Number} The end of the last buffered time range | ||
10870 | * @method bufferedEnd | ||
10871 | */ | ||
10872 | |||
10873 | Player.prototype.bufferedEnd = function bufferedEnd() { | ||
10874 | var buffered = this.buffered(), | ||
10875 | duration = this.duration(), | ||
10876 | end = buffered.end(buffered.length - 1); | ||
10877 | |||
10878 | if (end > duration) { | ||
10879 | end = duration; | ||
10880 | } | ||
10881 | |||
10882 | return end; | ||
10883 | }; | ||
10884 | |||
10885 | /** | ||
10886 | * Get or set the current volume of the media | ||
10887 | * ```js | ||
10888 | * // get | ||
10889 | * var howLoudIsIt = myPlayer.volume(); | ||
10890 | * // set | ||
10891 | * myPlayer.volume(0.5); // Set volume to half | ||
10892 | * ``` | ||
10893 | * 0 is off (muted), 1.0 is all the way up, 0.5 is half way. | ||
10894 | * | ||
10895 | * @param {Number} percentAsDecimal The new volume as a decimal percent | ||
10896 | * @return {Number} The current volume when getting | ||
10897 | * @return {Player} self when setting | ||
10898 | * @method volume | ||
10899 | */ | ||
10900 | |||
10901 | Player.prototype.volume = function volume(percentAsDecimal) { | ||
10902 | var vol = undefined; | ||
10903 | |||
10904 | if (percentAsDecimal !== undefined) { | ||
10905 | vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1 | ||
10906 | this.cache_.volume = vol; | ||
10907 | this.techCall_('setVolume', vol); | ||
10908 | |||
10909 | return this; | ||
10910 | } | ||
10911 | |||
10912 | // Default to 1 when returning current volume. | ||
10913 | vol = parseFloat(this.techGet_('volume')); | ||
10914 | return isNaN(vol) ? 1 : vol; | ||
10915 | }; | ||
10916 | |||
10917 | /** | ||
10918 | * Get the current muted state, or turn mute on or off | ||
10919 | * ```js | ||
10920 | * // get | ||
10921 | * var isVolumeMuted = myPlayer.muted(); | ||
10922 | * // set | ||
10923 | * myPlayer.muted(true); // mute the volume | ||
10924 | * ``` | ||
10925 | * | ||
10926 | * @param {Boolean=} muted True to mute, false to unmute | ||
10927 | * @return {Boolean} True if mute is on, false if not when getting | ||
10928 | * @return {Player} self when setting mute | ||
10929 | * @method muted | ||
10930 | */ | ||
10931 | |||
10932 | Player.prototype.muted = function muted(_muted) { | ||
10933 | if (_muted !== undefined) { | ||
10934 | this.techCall_('setMuted', _muted); | ||
10935 | return this; | ||
10936 | } | ||
10937 | return this.techGet_('muted') || false; // Default to false | ||
10938 | }; | ||
10939 | |||
10940 | // Check if current tech can support native fullscreen | ||
10941 | // (e.g. with built in controls like iOS, so not our flash swf) | ||
10942 | /** | ||
10943 | * Check to see if fullscreen is supported | ||
10944 | * | ||
10945 | * @return {Boolean} | ||
10946 | * @method supportsFullScreen | ||
10947 | */ | ||
10948 | |||
10949 | Player.prototype.supportsFullScreen = function supportsFullScreen() { | ||
10950 | return this.techGet_('supportsFullScreen') || false; | ||
10951 | }; | ||
10952 | |||
10953 | /** | ||
10954 | * Check if the player is in fullscreen mode | ||
10955 | * ```js | ||
10956 | * // get | ||
10957 | * var fullscreenOrNot = myPlayer.isFullscreen(); | ||
10958 | * // set | ||
10959 | * myPlayer.isFullscreen(true); // tell the player it's in fullscreen | ||
10960 | * ``` | ||
10961 | * NOTE: As of the latest HTML5 spec, isFullscreen is no longer an official | ||
10962 | * property and instead document.fullscreenElement is used. But isFullscreen is | ||
10963 | * still a valuable property for internal player workings. | ||
10964 | * | ||
10965 | * @param {Boolean=} isFS Update the player's fullscreen state | ||
10966 | * @return {Boolean} true if fullscreen false if not when getting | ||
10967 | * @return {Player} self when setting | ||
10968 | * @method isFullscreen | ||
10969 | */ | ||
10970 | |||
10971 | Player.prototype.isFullscreen = function isFullscreen(isFS) { | ||
10972 | if (isFS !== undefined) { | ||
10973 | this.isFullscreen_ = !!isFS; | ||
10974 | return this; | ||
10975 | } | ||
10976 | return !!this.isFullscreen_; | ||
10977 | }; | ||
10978 | |||
10979 | /** | ||
10980 | * Increase the size of the video to full screen | ||
10981 | * ```js | ||
10982 | * myPlayer.requestFullscreen(); | ||
10983 | * ``` | ||
10984 | * In some browsers, full screen is not supported natively, so it enters | ||
10985 | * "full window mode", where the video fills the browser window. | ||
10986 | * In browsers and devices that support native full screen, sometimes the | ||
10987 | * browser's default controls will be shown, and not the Video.js custom skin. | ||
10988 | * This includes most mobile devices (iOS, Android) and older versions of | ||
10989 | * Safari. | ||
10990 | * | ||
10991 | * @return {Player} self | ||
10992 | * @method requestFullscreen | ||
10993 | */ | ||
10994 | |||
10995 | Player.prototype.requestFullscreen = function requestFullscreen() { | ||
10996 | var fsApi = _fullscreenApiJs2['default']; | ||
10997 | |||
10998 | this.isFullscreen(true); | ||
10999 | |||
11000 | if (fsApi.requestFullscreen) { | ||
11001 | // the browser supports going fullscreen at the element level so we can | ||
11002 | // take the controls fullscreen as well as the video | ||
11003 | |||
11004 | // Trigger fullscreenchange event after change | ||
11005 | // We have to specifically add this each time, and remove | ||
11006 | // when canceling fullscreen. Otherwise if there's multiple | ||
11007 | // players on a page, they would all be reacting to the same fullscreen | ||
11008 | // events | ||
11009 | Events.on(_globalDocument2['default'], fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e) { | ||
11010 | this.isFullscreen(_globalDocument2['default'][fsApi.fullscreenElement]); | ||
11011 | |||
11012 | // If cancelling fullscreen, remove event listener. | ||
11013 | if (this.isFullscreen() === false) { | ||
11014 | Events.off(_globalDocument2['default'], fsApi.fullscreenchange, documentFullscreenChange); | ||
11015 | } | ||
11016 | |||
11017 | this.trigger('fullscreenchange'); | ||
11018 | })); | ||
11019 | |||
11020 | this.el_[fsApi.requestFullscreen](); | ||
11021 | } else if (this.tech_.supportsFullScreen()) { | ||
11022 | // we can't take the video.js controls fullscreen but we can go fullscreen | ||
11023 | // with native controls | ||
11024 | this.techCall_('enterFullScreen'); | ||
11025 | } else { | ||
11026 | // fullscreen isn't supported so we'll just stretch the video element to | ||
11027 | // fill the viewport | ||
11028 | this.enterFullWindow(); | ||
11029 | this.trigger('fullscreenchange'); | ||
11030 | } | ||
11031 | |||
11032 | return this; | ||
11033 | }; | ||
11034 | |||
11035 | /** | ||
11036 | * Return the video to its normal size after having been in full screen mode | ||
11037 | * ```js | ||
11038 | * myPlayer.exitFullscreen(); | ||
11039 | * ``` | ||
11040 | * | ||
11041 | * @return {Player} self | ||
11042 | * @method exitFullscreen | ||
11043 | */ | ||
11044 | |||
11045 | Player.prototype.exitFullscreen = function exitFullscreen() { | ||
11046 | var fsApi = _fullscreenApiJs2['default']; | ||
11047 | this.isFullscreen(false); | ||
11048 | |||
11049 | // Check for browser element fullscreen support | ||
11050 | if (fsApi.requestFullscreen) { | ||
11051 | _globalDocument2['default'][fsApi.exitFullscreen](); | ||
11052 | } else if (this.tech_.supportsFullScreen()) { | ||
11053 | this.techCall_('exitFullScreen'); | ||
11054 | } else { | ||
11055 | this.exitFullWindow(); | ||
11056 | this.trigger('fullscreenchange'); | ||
11057 | } | ||
11058 | |||
11059 | return this; | ||
11060 | }; | ||
11061 | |||
11062 | /** | ||
11063 | * When fullscreen isn't supported we can stretch the video container to as wide as the browser will let us. | ||
11064 | * | ||
11065 | * @method enterFullWindow | ||
11066 | */ | ||
11067 | |||
11068 | Player.prototype.enterFullWindow = function enterFullWindow() { | ||
11069 | this.isFullWindow = true; | ||
11070 | |||
11071 | // Storing original doc overflow value to return to when fullscreen is off | ||
11072 | this.docOrigOverflow = _globalDocument2['default'].documentElement.style.overflow; | ||
11073 | |||
11074 | // Add listener for esc key to exit fullscreen | ||
11075 | Events.on(_globalDocument2['default'], 'keydown', Fn.bind(this, this.fullWindowOnEscKey)); | ||
11076 | |||
11077 | // Hide any scroll bars | ||
11078 | _globalDocument2['default'].documentElement.style.overflow = 'hidden'; | ||
11079 | |||
11080 | // Apply fullscreen styles | ||
11081 | Dom.addElClass(_globalDocument2['default'].body, 'vjs-full-window'); | ||
11082 | |||
11083 | this.trigger('enterFullWindow'); | ||
11084 | }; | ||
11085 | |||
11086 | /** | ||
11087 | * Check for call to either exit full window or full screen on ESC key | ||
11088 | * | ||
11089 | * @param {String} event Event to check for key press | ||
11090 | * @method fullWindowOnEscKey | ||
11091 | */ | ||
11092 | |||
11093 | Player.prototype.fullWindowOnEscKey = function fullWindowOnEscKey(event) { | ||
11094 | if (event.keyCode === 27) { | ||
11095 | if (this.isFullscreen() === true) { | ||
11096 | this.exitFullscreen(); | ||
11097 | } else { | ||
11098 | this.exitFullWindow(); | ||
11099 | } | ||
11100 | } | ||
11101 | }; | ||
11102 | |||
11103 | /** | ||
11104 | * Exit full window | ||
11105 | * | ||
11106 | * @method exitFullWindow | ||
11107 | */ | ||
11108 | |||
11109 | Player.prototype.exitFullWindow = function exitFullWindow() { | ||
11110 | this.isFullWindow = false; | ||
11111 | Events.off(_globalDocument2['default'], 'keydown', this.fullWindowOnEscKey); | ||
11112 | |||
11113 | // Unhide scroll bars. | ||
11114 | _globalDocument2['default'].documentElement.style.overflow = this.docOrigOverflow; | ||
11115 | |||
11116 | // Remove fullscreen styles | ||
11117 | Dom.removeElClass(_globalDocument2['default'].body, 'vjs-full-window'); | ||
11118 | |||
11119 | // Resize the box, controller, and poster to original sizes | ||
11120 | // this.positionAll(); | ||
11121 | this.trigger('exitFullWindow'); | ||
11122 | }; | ||
11123 | |||
11124 | /** | ||
11125 | * Check whether the player can play a given mimetype | ||
11126 | * | ||
11127 | * @param {String} type The mimetype to check | ||
11128 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
11129 | * @method canPlayType | ||
11130 | */ | ||
11131 | |||
11132 | Player.prototype.canPlayType = function canPlayType(type) { | ||
11133 | var can = undefined; | ||
11134 | |||
11135 | // Loop through each playback technology in the options order | ||
11136 | for (var i = 0, j = this.options_.techOrder; i < j.length; i++) { | ||
11137 | var techName = _utilsToTitleCaseJs2['default'](j[i]); | ||
11138 | var tech = _techTechJs2['default'].getTech(techName); | ||
11139 | |||
11140 | // Support old behavior of techs being registered as components. | ||
11141 | // Remove once that deprecated behavior is removed. | ||
11142 | if (!tech) { | ||
11143 | tech = _componentJs2['default'].getComponent(techName); | ||
11144 | } | ||
11145 | |||
11146 | // Check if the current tech is defined before continuing | ||
11147 | if (!tech) { | ||
11148 | _utilsLogJs2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); | ||
11149 | continue; | ||
11150 | } | ||
11151 | |||
11152 | // Check if the browser supports this technology | ||
11153 | if (tech.isSupported()) { | ||
11154 | can = tech.canPlayType(type); | ||
11155 | |||
11156 | if (can) { | ||
11157 | return can; | ||
11158 | } | ||
11159 | } | ||
11160 | } | ||
11161 | |||
11162 | return ''; | ||
11163 | }; | ||
11164 | |||
11165 | /** | ||
11166 | * Select source based on tech-order or source-order | ||
11167 | * Uses source-order selection if `options.sourceOrder` is truthy. Otherwise, | ||
11168 | * defaults to tech-order selection | ||
11169 | * | ||
11170 | * @param {Array} sources The sources for a media asset | ||
11171 | * @return {Object|Boolean} Object of source and tech order, otherwise false | ||
11172 | * @method selectSource | ||
11173 | */ | ||
11174 | |||
11175 | Player.prototype.selectSource = function selectSource(sources) { | ||
11176 | // Get only the techs specified in `techOrder` that exist and are supported by the | ||
11177 | // current platform | ||
11178 | var techs = this.options_.techOrder.map(_utilsToTitleCaseJs2['default']).map(function (techName) { | ||
11179 | // `Component.getComponent(...)` is for support of old behavior of techs | ||
11180 | // being registered as components. | ||
11181 | // Remove once that deprecated behavior is removed. | ||
11182 | return [techName, _techTechJs2['default'].getTech(techName) || _componentJs2['default'].getComponent(techName)]; | ||
11183 | }).filter(function (_ref) { | ||
11184 | var techName = _ref[0]; | ||
11185 | var tech = _ref[1]; | ||
11186 | |||
11187 | // Check if the current tech is defined before continuing | ||
11188 | if (tech) { | ||
11189 | // Check if the browser supports this technology | ||
11190 | return tech.isSupported(); | ||
11191 | } | ||
11192 | |||
11193 | _utilsLogJs2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); | ||
11194 | return false; | ||
11195 | }); | ||
11196 | |||
11197 | // Iterate over each `innerArray` element once per `outerArray` element and execute | ||
11198 | // `tester` with both. If `tester` returns a non-falsy value, exit early and return | ||
11199 | // that value. | ||
11200 | var findFirstPassingTechSourcePair = function findFirstPassingTechSourcePair(outerArray, innerArray, tester) { | ||
11201 | var found = undefined; | ||
11202 | |||
11203 | outerArray.some(function (outerChoice) { | ||
11204 | return innerArray.some(function (innerChoice) { | ||
11205 | found = tester(outerChoice, innerChoice); | ||
11206 | |||
11207 | if (found) { | ||
11208 | return true; | ||
11209 | } | ||
11210 | }); | ||
11211 | }); | ||
11212 | |||
11213 | return found; | ||
11214 | }; | ||
11215 | |||
11216 | var foundSourceAndTech = undefined; | ||
11217 | var flip = function flip(fn) { | ||
11218 | return function (a, b) { | ||
11219 | return fn(b, a); | ||
11220 | }; | ||
11221 | }; | ||
11222 | var finder = function finder(_ref2, source) { | ||
11223 | var techName = _ref2[0]; | ||
11224 | var tech = _ref2[1]; | ||
11225 | |||
11226 | if (tech.canPlaySource(source)) { | ||
11227 | return { source: source, tech: techName }; | ||
11228 | } | ||
11229 | }; | ||
11230 | |||
11231 | // Depending on the truthiness of `options.sourceOrder`, we swap the order of techs and sources | ||
11232 | // to select from them based on their priority. | ||
11233 | if (this.options_.sourceOrder) { | ||
11234 | // Source-first ordering | ||
11235 | foundSourceAndTech = findFirstPassingTechSourcePair(sources, techs, flip(finder)); | ||
11236 | } else { | ||
11237 | // Tech-first ordering | ||
11238 | foundSourceAndTech = findFirstPassingTechSourcePair(techs, sources, finder); | ||
11239 | } | ||
11240 | |||
11241 | return foundSourceAndTech || false; | ||
11242 | }; | ||
11243 | |||
11244 | /** | ||
11245 | * The source function updates the video source | ||
11246 | * There are three types of variables you can pass as the argument. | ||
11247 | * **URL String**: A URL to the the video file. Use this method if you are sure | ||
11248 | * the current playback technology (HTML5/Flash) can support the source you | ||
11249 | * provide. Currently only MP4 files can be used in both HTML5 and Flash. | ||
11250 | * ```js | ||
11251 | * myPlayer.src("http://www.example.com/path/to/video.mp4"); | ||
11252 | * ``` | ||
11253 | * **Source Object (or element):* * A javascript object containing information | ||
11254 | * about the source file. Use this method if you want the player to determine if | ||
11255 | * it can support the file using the type information. | ||
11256 | * ```js | ||
11257 | * myPlayer.src({ type: "video/mp4", src: "http://www.example.com/path/to/video.mp4" }); | ||
11258 | * ``` | ||
11259 | * **Array of Source Objects:* * To provide multiple versions of the source so | ||
11260 | * that it can be played using HTML5 across browsers you can use an array of | ||
11261 | * source objects. Video.js will detect which version is supported and load that | ||
11262 | * file. | ||
11263 | * ```js | ||
11264 | * myPlayer.src([ | ||
11265 | * { type: "video/mp4", src: "http://www.example.com/path/to/video.mp4" }, | ||
11266 | * { type: "video/webm", src: "http://www.example.com/path/to/video.webm" }, | ||
11267 | * { type: "video/ogg", src: "http://www.example.com/path/to/video.ogv" } | ||
11268 | * ]); | ||
11269 | * ``` | ||
11270 | * | ||
11271 | * @param {String|Object|Array=} source The source URL, object, or array of sources | ||
11272 | * @return {String} The current video source when getting | ||
11273 | * @return {String} The player when setting | ||
11274 | * @method src | ||
11275 | */ | ||
11276 | |||
11277 | Player.prototype.src = function src(source) { | ||
11278 | if (source === undefined) { | ||
11279 | return this.techGet_('src'); | ||
11280 | } | ||
11281 | |||
11282 | var currentTech = _techTechJs2['default'].getTech(this.techName_); | ||
11283 | // Support old behavior of techs being registered as components. | ||
11284 | // Remove once that deprecated behavior is removed. | ||
11285 | if (!currentTech) { | ||
11286 | currentTech = _componentJs2['default'].getComponent(this.techName_); | ||
11287 | } | ||
11288 | |||
11289 | // case: Array of source objects to choose from and pick the best to play | ||
11290 | if (Array.isArray(source)) { | ||
11291 | this.sourceList_(source); | ||
11292 | |||
11293 | // case: URL String (http://myvideo...) | ||
11294 | } else if (typeof source === 'string') { | ||
11295 | // create a source object from the string | ||
11296 | this.src({ src: source }); | ||
11297 | |||
11298 | // case: Source object { src: '', type: '' ... } | ||
11299 | } else if (source instanceof Object) { | ||
11300 | // check if the source has a type and the loaded tech cannot play the source | ||
11301 | // if there's no type we'll just try the current tech | ||
11302 | if (source.type && !currentTech.canPlaySource(source)) { | ||
11303 | // create a source list with the current source and send through | ||
11304 | // the tech loop to check for a compatible technology | ||
11305 | this.sourceList_([source]); | ||
11306 | } else { | ||
11307 | this.cache_.src = source.src; | ||
11308 | this.currentType_ = source.type || ''; | ||
11309 | |||
11310 | // wait until the tech is ready to set the source | ||
11311 | this.ready(function () { | ||
11312 | |||
11313 | // The setSource tech method was added with source handlers | ||
11314 | // so older techs won't support it | ||
11315 | // We need to check the direct prototype for the case where subclasses | ||
11316 | // of the tech do not support source handlers | ||
11317 | if (currentTech.prototype.hasOwnProperty('setSource')) { | ||
11318 | this.techCall_('setSource', source); | ||
11319 | } else { | ||
11320 | this.techCall_('src', source.src); | ||
11321 | } | ||
11322 | |||
11323 | if (this.options_.preload === 'auto') { | ||
11324 | this.load(); | ||
11325 | } | ||
11326 | |||
11327 | if (this.options_.autoplay) { | ||
11328 | this.play(); | ||
11329 | } | ||
11330 | |||
11331 | // Set the source synchronously if possible (#2326) | ||
11332 | }, true); | ||
11333 | } | ||
11334 | } | ||
11335 | |||
11336 | return this; | ||
11337 | }; | ||
11338 | |||
11339 | /** | ||
11340 | * Handle an array of source objects | ||
11341 | * | ||
11342 | * @param {Array} sources Array of source objects | ||
11343 | * @private | ||
11344 | * @method sourceList_ | ||
11345 | */ | ||
11346 | |||
11347 | Player.prototype.sourceList_ = function sourceList_(sources) { | ||
11348 | var sourceTech = this.selectSource(sources); | ||
11349 | |||
11350 | if (sourceTech) { | ||
11351 | if (sourceTech.tech === this.techName_) { | ||
11352 | // if this technology is already loaded, set the source | ||
11353 | this.src(sourceTech.source); | ||
11354 | } else { | ||
11355 | // load this technology with the chosen source | ||
11356 | this.loadTech_(sourceTech.tech, sourceTech.source); | ||
11357 | } | ||
11358 | } else { | ||
11359 | // We need to wrap this in a timeout to give folks a chance to add error event handlers | ||
11360 | this.setTimeout(function () { | ||
11361 | this.error({ code: 4, message: this.localize(this.options_.notSupportedMessage) }); | ||
11362 | }, 0); | ||
11363 | |||
11364 | // we could not find an appropriate tech, but let's still notify the delegate that this is it | ||
11365 | // this needs a better comment about why this is needed | ||
11366 | this.triggerReady(); | ||
11367 | } | ||
11368 | }; | ||
11369 | |||
11370 | /** | ||
11371 | * Begin loading the src data. | ||
11372 | * | ||
11373 | * @return {Player} Returns the player | ||
11374 | * @method load | ||
11375 | */ | ||
11376 | |||
11377 | Player.prototype.load = function load() { | ||
11378 | this.techCall_('load'); | ||
11379 | return this; | ||
11380 | }; | ||
11381 | |||
11382 | /** | ||
11383 | * Reset the player. Loads the first tech in the techOrder, | ||
11384 | * and calls `reset` on the tech`. | ||
11385 | * | ||
11386 | * @return {Player} Returns the player | ||
11387 | * @method reset | ||
11388 | */ | ||
11389 | |||
11390 | Player.prototype.reset = function reset() { | ||
11391 | this.loadTech_(_utilsToTitleCaseJs2['default'](this.options_.techOrder[0]), null); | ||
11392 | this.techCall_('reset'); | ||
11393 | return this; | ||
11394 | }; | ||
11395 | |||
11396 | /** | ||
11397 | * Returns the fully qualified URL of the current source value e.g. http://mysite.com/video.mp4 | ||
11398 | * Can be used in conjuction with `currentType` to assist in rebuilding the current source object. | ||
11399 | * | ||
11400 | * @return {String} The current source | ||
11401 | * @method currentSrc | ||
11402 | */ | ||
11403 | |||
11404 | Player.prototype.currentSrc = function currentSrc() { | ||
11405 | return this.techGet_('currentSrc') || this.cache_.src || ''; | ||
11406 | }; | ||
11407 | |||
11408 | /** | ||
11409 | * Get the current source type e.g. video/mp4 | ||
11410 | * This can allow you rebuild the current source object so that you could load the same | ||
11411 | * source and tech later | ||
11412 | * | ||
11413 | * @return {String} The source MIME type | ||
11414 | * @method currentType | ||
11415 | */ | ||
11416 | |||
11417 | Player.prototype.currentType = function currentType() { | ||
11418 | return this.currentType_ || ''; | ||
11419 | }; | ||
11420 | |||
11421 | /** | ||
11422 | * Get or set the preload attribute | ||
11423 | * | ||
11424 | * @param {Boolean} value Boolean to determine if preload should be used | ||
11425 | * @return {String} The preload attribute value when getting | ||
11426 | * @return {Player} Returns the player when setting | ||
11427 | * @method preload | ||
11428 | */ | ||
11429 | |||
11430 | Player.prototype.preload = function preload(value) { | ||
11431 | if (value !== undefined) { | ||
11432 | this.techCall_('setPreload', value); | ||
11433 | this.options_.preload = value; | ||
11434 | return this; | ||
11435 | } | ||
11436 | return this.techGet_('preload'); | ||
11437 | }; | ||
11438 | |||
11439 | /** | ||
11440 | * Get or set the autoplay attribute. | ||
11441 | * | ||
11442 | * @param {Boolean} value Boolean to determine if video should autoplay | ||
11443 | * @return {String} The autoplay attribute value when getting | ||
11444 | * @return {Player} Returns the player when setting | ||
11445 | * @method autoplay | ||
11446 | */ | ||
11447 | |||
11448 | Player.prototype.autoplay = function autoplay(value) { | ||
11449 | if (value !== undefined) { | ||
11450 | this.techCall_('setAutoplay', value); | ||
11451 | this.options_.autoplay = value; | ||
11452 | return this; | ||
11453 | } | ||
11454 | return this.techGet_('autoplay', value); | ||
11455 | }; | ||
11456 | |||
11457 | /** | ||
11458 | * Get or set the loop attribute on the video element. | ||
11459 | * | ||
11460 | * @param {Boolean} value Boolean to determine if video should loop | ||
11461 | * @return {String} The loop attribute value when getting | ||
11462 | * @return {Player} Returns the player when setting | ||
11463 | * @method loop | ||
11464 | */ | ||
11465 | |||
11466 | Player.prototype.loop = function loop(value) { | ||
11467 | if (value !== undefined) { | ||
11468 | this.techCall_('setLoop', value); | ||
11469 | this.options_['loop'] = value; | ||
11470 | return this; | ||
11471 | } | ||
11472 | return this.techGet_('loop'); | ||
11473 | }; | ||
11474 | |||
11475 | /** | ||
11476 | * Get or set the poster image source url | ||
11477 | * | ||
11478 | * ##### EXAMPLE: | ||
11479 | * ```js | ||
11480 | * // get | ||
11481 | * var currentPoster = myPlayer.poster(); | ||
11482 | * // set | ||
11483 | * myPlayer.poster('http://example.com/myImage.jpg'); | ||
11484 | * ``` | ||
11485 | * | ||
11486 | * @param {String=} src Poster image source URL | ||
11487 | * @return {String} poster URL when getting | ||
11488 | * @return {Player} self when setting | ||
11489 | * @method poster | ||
11490 | */ | ||
11491 | |||
11492 | Player.prototype.poster = function poster(src) { | ||
11493 | if (src === undefined) { | ||
11494 | return this.poster_; | ||
11495 | } | ||
11496 | |||
11497 | // The correct way to remove a poster is to set as an empty string | ||
11498 | // other falsey values will throw errors | ||
11499 | if (!src) { | ||
11500 | src = ''; | ||
11501 | } | ||
11502 | |||
11503 | // update the internal poster variable | ||
11504 | this.poster_ = src; | ||
11505 | |||
11506 | // update the tech's poster | ||
11507 | this.techCall_('setPoster', src); | ||
11508 | |||
11509 | // alert components that the poster has been set | ||
11510 | this.trigger('posterchange'); | ||
11511 | |||
11512 | return this; | ||
11513 | }; | ||
11514 | |||
11515 | /** | ||
11516 | * Some techs (e.g. YouTube) can provide a poster source in an | ||
11517 | * asynchronous way. We want the poster component to use this | ||
11518 | * poster source so that it covers up the tech's controls. | ||
11519 | * (YouTube's play button). However we only want to use this | ||
11520 | * soruce if the player user hasn't set a poster through | ||
11521 | * the normal APIs. | ||
11522 | * | ||
11523 | * @private | ||
11524 | * @method handleTechPosterChange_ | ||
11525 | */ | ||
11526 | |||
11527 | Player.prototype.handleTechPosterChange_ = function handleTechPosterChange_() { | ||
11528 | if (!this.poster_ && this.tech_ && this.tech_.poster) { | ||
11529 | this.poster_ = this.tech_.poster() || ''; | ||
11530 | |||
11531 | // Let components know the poster has changed | ||
11532 | this.trigger('posterchange'); | ||
11533 | } | ||
11534 | }; | ||
11535 | |||
11536 | /** | ||
11537 | * Get or set whether or not the controls are showing. | ||
11538 | * | ||
11539 | * @param {Boolean} bool Set controls to showing or not | ||
11540 | * @return {Boolean} Controls are showing | ||
11541 | * @method controls | ||
11542 | */ | ||
11543 | |||
11544 | Player.prototype.controls = function controls(bool) { | ||
11545 | if (bool !== undefined) { | ||
11546 | bool = !!bool; // force boolean | ||
11547 | // Don't trigger a change event unless it actually changed | ||
11548 | if (this.controls_ !== bool) { | ||
11549 | this.controls_ = bool; | ||
11550 | |||
11551 | if (this.usingNativeControls()) { | ||
11552 | this.techCall_('setControls', bool); | ||
11553 | } | ||
11554 | |||
11555 | if (bool) { | ||
11556 | this.removeClass('vjs-controls-disabled'); | ||
11557 | this.addClass('vjs-controls-enabled'); | ||
11558 | this.trigger('controlsenabled'); | ||
11559 | |||
11560 | if (!this.usingNativeControls()) { | ||
11561 | this.addTechControlsListeners_(); | ||
11562 | } | ||
11563 | } else { | ||
11564 | this.removeClass('vjs-controls-enabled'); | ||
11565 | this.addClass('vjs-controls-disabled'); | ||
11566 | this.trigger('controlsdisabled'); | ||
11567 | |||
11568 | if (!this.usingNativeControls()) { | ||
11569 | this.removeTechControlsListeners_(); | ||
11570 | } | ||
11571 | } | ||
11572 | } | ||
11573 | return this; | ||
11574 | } | ||
11575 | return !!this.controls_; | ||
11576 | }; | ||
11577 | |||
11578 | /** | ||
11579 | * Toggle native controls on/off. Native controls are the controls built into | ||
11580 | * devices (e.g. default iPhone controls), Flash, or other techs | ||
11581 | * (e.g. Vimeo Controls) | ||
11582 | * **This should only be set by the current tech, because only the tech knows | ||
11583 | * if it can support native controls** | ||
11584 | * | ||
11585 | * @param {Boolean} bool True signals that native controls are on | ||
11586 | * @return {Player} Returns the player | ||
11587 | * @private | ||
11588 | * @method usingNativeControls | ||
11589 | */ | ||
11590 | |||
11591 | Player.prototype.usingNativeControls = function usingNativeControls(bool) { | ||
11592 | if (bool !== undefined) { | ||
11593 | bool = !!bool; // force boolean | ||
11594 | // Don't trigger a change event unless it actually changed | ||
11595 | if (this.usingNativeControls_ !== bool) { | ||
11596 | this.usingNativeControls_ = bool; | ||
11597 | if (bool) { | ||
11598 | this.addClass('vjs-using-native-controls'); | ||
11599 | |||
11600 | /** | ||
11601 | * player is using the native device controls | ||
11602 | * | ||
11603 | * @event usingnativecontrols | ||
11604 | * @memberof Player | ||
11605 | * @instance | ||
11606 | * @private | ||
11607 | */ | ||
11608 | this.trigger('usingnativecontrols'); | ||
11609 | } else { | ||
11610 | this.removeClass('vjs-using-native-controls'); | ||
11611 | |||
11612 | /** | ||
11613 | * player is using the custom HTML controls | ||
11614 | * | ||
11615 | * @event usingcustomcontrols | ||
11616 | * @memberof Player | ||
11617 | * @instance | ||
11618 | * @private | ||
11619 | */ | ||
11620 | this.trigger('usingcustomcontrols'); | ||
11621 | } | ||
11622 | } | ||
11623 | return this; | ||
11624 | } | ||
11625 | return !!this.usingNativeControls_; | ||
11626 | }; | ||
11627 | |||
11628 | /** | ||
11629 | * Set or get the current MediaError | ||
11630 | * | ||
11631 | * @param {*} err A MediaError or a String/Number to be turned into a MediaError | ||
11632 | * @return {MediaError|null} when getting | ||
11633 | * @return {Player} when setting | ||
11634 | * @method error | ||
11635 | */ | ||
11636 | |||
11637 | Player.prototype.error = function error(err) { | ||
11638 | if (err === undefined) { | ||
11639 | return this.error_ || null; | ||
11640 | } | ||
11641 | |||
11642 | // restoring to default | ||
11643 | if (err === null) { | ||
11644 | this.error_ = err; | ||
11645 | this.removeClass('vjs-error'); | ||
11646 | this.errorDisplay.close(); | ||
11647 | return this; | ||
11648 | } | ||
11649 | |||
11650 | // error instance | ||
11651 | if (err instanceof _mediaErrorJs2['default']) { | ||
11652 | this.error_ = err; | ||
11653 | } else { | ||
11654 | this.error_ = new _mediaErrorJs2['default'](err); | ||
11655 | } | ||
11656 | |||
11657 | // add the vjs-error classname to the player | ||
11658 | this.addClass('vjs-error'); | ||
11659 | |||
11660 | // log the name of the error type and any message | ||
11661 | // ie8 just logs "[object object]" if you just log the error object | ||
11662 | _utilsLogJs2['default'].error('(CODE:' + this.error_.code + ' ' + _mediaErrorJs2['default'].errorTypes[this.error_.code] + ')', this.error_.message, this.error_); | ||
11663 | |||
11664 | // fire an error event on the player | ||
11665 | this.trigger('error'); | ||
11666 | |||
11667 | return this; | ||
11668 | }; | ||
11669 | |||
11670 | /** | ||
11671 | * Returns whether or not the player is in the "ended" state. | ||
11672 | * | ||
11673 | * @return {Boolean} True if the player is in the ended state, false if not. | ||
11674 | * @method ended | ||
11675 | */ | ||
11676 | |||
11677 | Player.prototype.ended = function ended() { | ||
11678 | return this.techGet_('ended'); | ||
11679 | }; | ||
11680 | |||
11681 | /** | ||
11682 | * Returns whether or not the player is in the "seeking" state. | ||
11683 | * | ||
11684 | * @return {Boolean} True if the player is in the seeking state, false if not. | ||
11685 | * @method seeking | ||
11686 | */ | ||
11687 | |||
11688 | Player.prototype.seeking = function seeking() { | ||
11689 | return this.techGet_('seeking'); | ||
11690 | }; | ||
11691 | |||
11692 | /** | ||
11693 | * Returns the TimeRanges of the media that are currently available | ||
11694 | * for seeking to. | ||
11695 | * | ||
11696 | * @return {TimeRanges} the seekable intervals of the media timeline | ||
11697 | * @method seekable | ||
11698 | */ | ||
11699 | |||
11700 | Player.prototype.seekable = function seekable() { | ||
11701 | return this.techGet_('seekable'); | ||
11702 | }; | ||
11703 | |||
11704 | /** | ||
11705 | * Report user activity | ||
11706 | * | ||
11707 | * @param {Object} event Event object | ||
11708 | * @method reportUserActivity | ||
11709 | */ | ||
11710 | |||
11711 | Player.prototype.reportUserActivity = function reportUserActivity(event) { | ||
11712 | this.userActivity_ = true; | ||
11713 | }; | ||
11714 | |||
11715 | /** | ||
11716 | * Get/set if user is active | ||
11717 | * | ||
11718 | * @param {Boolean} bool Value when setting | ||
11719 | * @return {Boolean} Value if user is active user when getting | ||
11720 | * @method userActive | ||
11721 | */ | ||
11722 | |||
11723 | Player.prototype.userActive = function userActive(bool) { | ||
11724 | if (bool !== undefined) { | ||
11725 | bool = !!bool; | ||
11726 | if (bool !== this.userActive_) { | ||
11727 | this.userActive_ = bool; | ||
11728 | if (bool) { | ||
11729 | // If the user was inactive and is now active we want to reset the | ||
11730 | // inactivity timer | ||
11731 | this.userActivity_ = true; | ||
11732 | this.removeClass('vjs-user-inactive'); | ||
11733 | this.addClass('vjs-user-active'); | ||
11734 | this.trigger('useractive'); | ||
11735 | } else { | ||
11736 | // We're switching the state to inactive manually, so erase any other | ||
11737 | // activity | ||
11738 | this.userActivity_ = false; | ||
11739 | |||
11740 | // Chrome/Safari/IE have bugs where when you change the cursor it can | ||
11741 | // trigger a mousemove event. This causes an issue when you're hiding | ||
11742 | // the cursor when the user is inactive, and a mousemove signals user | ||
11743 | // activity. Making it impossible to go into inactive mode. Specifically | ||
11744 | // this happens in fullscreen when we really need to hide the cursor. | ||
11745 | // | ||
11746 | // When this gets resolved in ALL browsers it can be removed | ||
11747 | // https://code.google.com/p/chromium/issues/detail?id=103041 | ||
11748 | if (this.tech_) { | ||
11749 | this.tech_.one('mousemove', function (e) { | ||
11750 | e.stopPropagation(); | ||
11751 | e.preventDefault(); | ||
11752 | }); | ||
11753 | } | ||
11754 | |||
11755 | this.removeClass('vjs-user-active'); | ||
11756 | this.addClass('vjs-user-inactive'); | ||
11757 | this.trigger('userinactive'); | ||
11758 | } | ||
11759 | } | ||
11760 | return this; | ||
11761 | } | ||
11762 | return this.userActive_; | ||
11763 | }; | ||
11764 | |||
11765 | /** | ||
11766 | * Listen for user activity based on timeout value | ||
11767 | * | ||
11768 | * @private | ||
11769 | * @method listenForUserActivity_ | ||
11770 | */ | ||
11771 | |||
11772 | Player.prototype.listenForUserActivity_ = function listenForUserActivity_() { | ||
11773 | var mouseInProgress = undefined, | ||
11774 | lastMoveX = undefined, | ||
11775 | lastMoveY = undefined; | ||
11776 | |||
11777 | var handleActivity = Fn.bind(this, this.reportUserActivity); | ||
11778 | |||
11779 | var handleMouseMove = function handleMouseMove(e) { | ||
11780 | // #1068 - Prevent mousemove spamming | ||
11781 | // Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970 | ||
11782 | if (e.screenX !== lastMoveX || e.screenY !== lastMoveY) { | ||
11783 | lastMoveX = e.screenX; | ||
11784 | lastMoveY = e.screenY; | ||
11785 | handleActivity(); | ||
11786 | } | ||
11787 | }; | ||
11788 | |||
11789 | var handleMouseDown = function handleMouseDown() { | ||
11790 | handleActivity(); | ||
11791 | // For as long as the they are touching the device or have their mouse down, | ||
11792 | // we consider them active even if they're not moving their finger or mouse. | ||
11793 | // So we want to continue to update that they are active | ||
11794 | this.clearInterval(mouseInProgress); | ||
11795 | // Setting userActivity=true now and setting the interval to the same time | ||
11796 | // as the activityCheck interval (250) should ensure we never miss the | ||
11797 | // next activityCheck | ||
11798 | mouseInProgress = this.setInterval(handleActivity, 250); | ||
11799 | }; | ||
11800 | |||
11801 | var handleMouseUp = function handleMouseUp(event) { | ||
11802 | handleActivity(); | ||
11803 | // Stop the interval that maintains activity if the mouse/touch is down | ||
11804 | this.clearInterval(mouseInProgress); | ||
11805 | }; | ||
11806 | |||
11807 | // Any mouse movement will be considered user activity | ||
11808 | this.on('mousedown', handleMouseDown); | ||
11809 | this.on('mousemove', handleMouseMove); | ||
11810 | this.on('mouseup', handleMouseUp); | ||
11811 | |||
11812 | // Listen for keyboard navigation | ||
11813 | // Shouldn't need to use inProgress interval because of key repeat | ||
11814 | this.on('keydown', handleActivity); | ||
11815 | this.on('keyup', handleActivity); | ||
11816 | |||
11817 | // Run an interval every 250 milliseconds instead of stuffing everything into | ||
11818 | // the mousemove/touchmove function itself, to prevent performance degradation. | ||
11819 | // `this.reportUserActivity` simply sets this.userActivity_ to true, which | ||
11820 | // then gets picked up by this loop | ||
11821 | // http://ejohn.org/blog/learning-from-twitter/ | ||
11822 | var inactivityTimeout = undefined; | ||
11823 | var activityCheck = this.setInterval(function () { | ||
11824 | // Check to see if mouse/touch activity has happened | ||
11825 | if (this.userActivity_) { | ||
11826 | // Reset the activity tracker | ||
11827 | this.userActivity_ = false; | ||
11828 | |||
11829 | // If the user state was inactive, set the state to active | ||
11830 | this.userActive(true); | ||
11831 | |||
11832 | // Clear any existing inactivity timeout to start the timer over | ||
11833 | this.clearTimeout(inactivityTimeout); | ||
11834 | |||
11835 | var timeout = this.options_['inactivityTimeout']; | ||
11836 | if (timeout > 0) { | ||
11837 | // In <timeout> milliseconds, if no more activity has occurred the | ||
11838 | // user will be considered inactive | ||
11839 | inactivityTimeout = this.setTimeout(function () { | ||
11840 | // Protect against the case where the inactivityTimeout can trigger just | ||
11841 | // before the next user activity is picked up by the activityCheck loop | ||
11842 | // causing a flicker | ||
11843 | if (!this.userActivity_) { | ||
11844 | this.userActive(false); | ||
11845 | } | ||
11846 | }, timeout); | ||
11847 | } | ||
11848 | } | ||
11849 | }, 250); | ||
11850 | }; | ||
11851 | |||
11852 | /** | ||
11853 | * Gets or sets the current playback rate. A playback rate of | ||
11854 | * 1.0 represents normal speed and 0.5 would indicate half-speed | ||
11855 | * playback, for instance. | ||
11856 | * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate | ||
11857 | * | ||
11858 | * @param {Number} rate New playback rate to set. | ||
11859 | * @return {Number} Returns the new playback rate when setting | ||
11860 | * @return {Number} Returns the current playback rate when getting | ||
11861 | * @method playbackRate | ||
11862 | */ | ||
11863 | |||
11864 | Player.prototype.playbackRate = function playbackRate(rate) { | ||
11865 | if (rate !== undefined) { | ||
11866 | this.techCall_('setPlaybackRate', rate); | ||
11867 | return this; | ||
11868 | } | ||
11869 | |||
11870 | if (this.tech_ && this.tech_['featuresPlaybackRate']) { | ||
11871 | return this.techGet_('playbackRate'); | ||
11872 | } else { | ||
11873 | return 1.0; | ||
11874 | } | ||
11875 | }; | ||
11876 | |||
11877 | /** | ||
11878 | * Gets or sets the audio flag | ||
11879 | * | ||
11880 | * @param {Boolean} bool True signals that this is an audio player. | ||
11881 | * @return {Boolean} Returns true if player is audio, false if not when getting | ||
11882 | * @return {Player} Returns the player if setting | ||
11883 | * @private | ||
11884 | * @method isAudio | ||
11885 | */ | ||
11886 | |||
11887 | Player.prototype.isAudio = function isAudio(bool) { | ||
11888 | if (bool !== undefined) { | ||
11889 | this.isAudio_ = !!bool; | ||
11890 | return this; | ||
11891 | } | ||
11892 | |||
11893 | return !!this.isAudio_; | ||
11894 | }; | ||
11895 | |||
11896 | /** | ||
11897 | * Returns the current state of network activity for the element, from | ||
11898 | * the codes in the list below. | ||
11899 | * - NETWORK_EMPTY (numeric value 0) | ||
11900 | * The element has not yet been initialised. All attributes are in | ||
11901 | * their initial states. | ||
11902 | * - NETWORK_IDLE (numeric value 1) | ||
11903 | * The element's resource selection algorithm is active and has | ||
11904 | * selected a resource, but it is not actually using the network at | ||
11905 | * this time. | ||
11906 | * - NETWORK_LOADING (numeric value 2) | ||
11907 | * The user agent is actively trying to download data. | ||
11908 | * - NETWORK_NO_SOURCE (numeric value 3) | ||
11909 | * The element's resource selection algorithm is active, but it has | ||
11910 | * not yet found a resource to use. | ||
11911 | * | ||
11912 | * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states | ||
11913 | * @return {Number} the current network activity state | ||
11914 | * @method networkState | ||
11915 | */ | ||
11916 | |||
11917 | Player.prototype.networkState = function networkState() { | ||
11918 | return this.techGet_('networkState'); | ||
11919 | }; | ||
11920 | |||
11921 | /** | ||
11922 | * Returns a value that expresses the current state of the element | ||
11923 | * with respect to rendering the current playback position, from the | ||
11924 | * codes in the list below. | ||
11925 | * - HAVE_NOTHING (numeric value 0) | ||
11926 | * No information regarding the media resource is available. | ||
11927 | * - HAVE_METADATA (numeric value 1) | ||
11928 | * Enough of the resource has been obtained that the duration of the | ||
11929 | * resource is available. | ||
11930 | * - HAVE_CURRENT_DATA (numeric value 2) | ||
11931 | * Data for the immediate current playback position is available. | ||
11932 | * - HAVE_FUTURE_DATA (numeric value 3) | ||
11933 | * Data for the immediate current playback position is available, as | ||
11934 | * well as enough data for the user agent to advance the current | ||
11935 | * playback position in the direction of playback. | ||
11936 | * - HAVE_ENOUGH_DATA (numeric value 4) | ||
11937 | * The user agent estimates that enough data is available for | ||
11938 | * playback to proceed uninterrupted. | ||
11939 | * | ||
11940 | * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate | ||
11941 | * @return {Number} the current playback rendering state | ||
11942 | * @method readyState | ||
11943 | */ | ||
11944 | |||
11945 | Player.prototype.readyState = function readyState() { | ||
11946 | return this.techGet_('readyState'); | ||
11947 | }; | ||
11948 | |||
11949 | /* | ||
11950 | * Text tracks are tracks of timed text events. | ||
11951 | * Captions - text displayed over the video for the hearing impaired | ||
11952 | * Subtitles - text displayed over the video for those who don't understand language in the video | ||
11953 | * Chapters - text displayed in a menu allowing the user to jump to particular points (chapters) in the video | ||
11954 | * Descriptions (not supported yet) - audio descriptions that are read back to the user by a screen reading device | ||
11955 | */ | ||
11956 | |||
11957 | /** | ||
11958 | * Get an array of associated text tracks. captions, subtitles, chapters, descriptions | ||
11959 | * http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks | ||
11960 | * | ||
11961 | * @return {Array} Array of track objects | ||
11962 | * @method textTracks | ||
11963 | */ | ||
11964 | |||
11965 | Player.prototype.textTracks = function textTracks() { | ||
11966 | // cannot use techGet_ directly because it checks to see whether the tech is ready. | ||
11967 | // Flash is unlikely to be ready in time but textTracks should still work. | ||
11968 | return this.tech_ && this.tech_['textTracks'](); | ||
11969 | }; | ||
11970 | |||
11971 | /** | ||
11972 | * Get an array of remote text tracks | ||
11973 | * | ||
11974 | * @return {Array} | ||
11975 | * @method remoteTextTracks | ||
11976 | */ | ||
11977 | |||
11978 | Player.prototype.remoteTextTracks = function remoteTextTracks() { | ||
11979 | return this.tech_ && this.tech_['remoteTextTracks'](); | ||
11980 | }; | ||
11981 | |||
11982 | /** | ||
11983 | * Get an array of remote html track elements | ||
11984 | * | ||
11985 | * @return {HTMLTrackElement[]} | ||
11986 | * @method remoteTextTrackEls | ||
11987 | */ | ||
11988 | |||
11989 | Player.prototype.remoteTextTrackEls = function remoteTextTrackEls() { | ||
11990 | return this.tech_ && this.tech_['remoteTextTrackEls'](); | ||
11991 | }; | ||
11992 | |||
11993 | /** | ||
11994 | * Add a text track | ||
11995 | * In addition to the W3C settings we allow adding additional info through options. | ||
11996 | * http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack | ||
11997 | * | ||
11998 | * @param {String} kind Captions, subtitles, chapters, descriptions, or metadata | ||
11999 | * @param {String=} label Optional label | ||
12000 | * @param {String=} language Optional language | ||
12001 | * @method addTextTrack | ||
12002 | */ | ||
12003 | |||
12004 | Player.prototype.addTextTrack = function addTextTrack(kind, label, language) { | ||
12005 | return this.tech_ && this.tech_['addTextTrack'](kind, label, language); | ||
12006 | }; | ||
12007 | |||
12008 | /** | ||
12009 | * Add a remote text track | ||
12010 | * | ||
12011 | * @param {Object} options Options for remote text track | ||
12012 | * @method addRemoteTextTrack | ||
12013 | */ | ||
12014 | |||
12015 | Player.prototype.addRemoteTextTrack = function addRemoteTextTrack(options) { | ||
12016 | return this.tech_ && this.tech_['addRemoteTextTrack'](options); | ||
12017 | }; | ||
12018 | |||
12019 | /** | ||
12020 | * Remove a remote text track | ||
12021 | * | ||
12022 | * @param {Object} track Remote text track to remove | ||
12023 | * @method removeRemoteTextTrack | ||
12024 | */ | ||
12025 | |||
12026 | Player.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { | ||
12027 | this.tech_ && this.tech_['removeRemoteTextTrack'](track); | ||
12028 | }; | ||
12029 | |||
12030 | /** | ||
12031 | * Get video width | ||
12032 | * | ||
12033 | * @return {Number} Video width | ||
12034 | * @method videoWidth | ||
12035 | */ | ||
12036 | |||
12037 | Player.prototype.videoWidth = function videoWidth() { | ||
12038 | return this.tech_ && this.tech_.videoWidth && this.tech_.videoWidth() || 0; | ||
12039 | }; | ||
12040 | |||
12041 | /** | ||
12042 | * Get video height | ||
12043 | * | ||
12044 | * @return {Number} Video height | ||
12045 | * @method videoHeight | ||
12046 | */ | ||
12047 | |||
12048 | Player.prototype.videoHeight = function videoHeight() { | ||
12049 | return this.tech_ && this.tech_.videoHeight && this.tech_.videoHeight() || 0; | ||
12050 | }; | ||
12051 | |||
12052 | // Methods to add support for | ||
12053 | // initialTime: function(){ return this.techCall_('initialTime'); }, | ||
12054 | // startOffsetTime: function(){ return this.techCall_('startOffsetTime'); }, | ||
12055 | // played: function(){ return this.techCall_('played'); }, | ||
12056 | // videoTracks: function(){ return this.techCall_('videoTracks'); }, | ||
12057 | // audioTracks: function(){ return this.techCall_('audioTracks'); }, | ||
12058 | // defaultPlaybackRate: function(){ return this.techCall_('defaultPlaybackRate'); }, | ||
12059 | // defaultMuted: function(){ return this.techCall_('defaultMuted'); } | ||
12060 | |||
12061 | /** | ||
12062 | * The player's language code | ||
12063 | * NOTE: The language should be set in the player options if you want the | ||
12064 | * the controls to be built with a specific language. Changing the lanugage | ||
12065 | * later will not update controls text. | ||
12066 | * | ||
12067 | * @param {String} code The locale string | ||
12068 | * @return {String} The locale string when getting | ||
12069 | * @return {Player} self when setting | ||
12070 | * @method language | ||
12071 | */ | ||
12072 | |||
12073 | Player.prototype.language = function language(code) { | ||
12074 | if (code === undefined) { | ||
12075 | return this.language_; | ||
12076 | } | ||
12077 | |||
12078 | this.language_ = ('' + code).toLowerCase(); | ||
12079 | return this; | ||
12080 | }; | ||
12081 | |||
12082 | /** | ||
12083 | * Get the player's language dictionary | ||
12084 | * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time | ||
12085 | * Languages specified directly in the player options have precedence | ||
12086 | * | ||
12087 | * @return {Array} Array of languages | ||
12088 | * @method languages | ||
12089 | */ | ||
12090 | |||
12091 | Player.prototype.languages = function languages() { | ||
12092 | return _utilsMergeOptionsJs2['default'](Player.prototype.options_.languages, this.languages_); | ||
12093 | }; | ||
12094 | |||
12095 | /** | ||
12096 | * Converts track info to JSON | ||
12097 | * | ||
12098 | * @return {Object} JSON object of options | ||
12099 | * @method toJSON | ||
12100 | */ | ||
12101 | |||
12102 | Player.prototype.toJSON = function toJSON() { | ||
12103 | var options = _utilsMergeOptionsJs2['default'](this.options_); | ||
12104 | var tracks = options.tracks; | ||
12105 | |||
12106 | options.tracks = []; | ||
12107 | |||
12108 | for (var i = 0; i < tracks.length; i++) { | ||
12109 | var track = tracks[i]; | ||
12110 | |||
12111 | // deep merge tracks and null out player so no circular references | ||
12112 | track = _utilsMergeOptionsJs2['default'](track); | ||
12113 | track.player = undefined; | ||
12114 | options.tracks[i] = track; | ||
12115 | } | ||
12116 | |||
12117 | return options; | ||
12118 | }; | ||
12119 | |||
12120 | /** | ||
12121 | * Creates a simple modal dialog (an instance of the `ModalDialog` | ||
12122 | * component) that immediately overlays the player with arbitrary | ||
12123 | * content and removes itself when closed. | ||
12124 | * | ||
12125 | * @param {String|Function|Element|Array|Null} content | ||
12126 | * Same as `ModalDialog#content`'s param of the same name. | ||
12127 | * | ||
12128 | * The most straight-forward usage is to provide a string or DOM | ||
12129 | * element. | ||
12130 | * | ||
12131 | * @param {Object} [options] | ||
12132 | * Extra options which will be passed on to the `ModalDialog`. | ||
12133 | * | ||
12134 | * @return {ModalDialog} | ||
12135 | */ | ||
12136 | |||
12137 | Player.prototype.createModal = function createModal(content, options) { | ||
12138 | var player = this; | ||
12139 | |||
12140 | options = options || {}; | ||
12141 | options.content = content || ''; | ||
12142 | |||
12143 | var modal = new _modalDialog2['default'](player, options); | ||
12144 | |||
12145 | player.addChild(modal); | ||
12146 | modal.on('dispose', function () { | ||
12147 | player.removeChild(modal); | ||
12148 | }); | ||
12149 | |||
12150 | return modal.open(); | ||
12151 | }; | ||
12152 | |||
12153 | /** | ||
12154 | * Gets tag settings | ||
12155 | * | ||
12156 | * @param {Element} tag The player tag | ||
12157 | * @return {Array} An array of sources and track objects | ||
12158 | * @static | ||
12159 | * @method getTagSettings | ||
12160 | */ | ||
12161 | |||
12162 | Player.getTagSettings = function getTagSettings(tag) { | ||
12163 | var baseOptions = { | ||
12164 | 'sources': [], | ||
12165 | 'tracks': [] | ||
12166 | }; | ||
12167 | |||
12168 | var tagOptions = Dom.getElAttributes(tag); | ||
12169 | var dataSetup = tagOptions['data-setup']; | ||
12170 | |||
12171 | // Check if data-setup attr exists. | ||
12172 | if (dataSetup !== null) { | ||
12173 | // Parse options JSON | ||
12174 | |||
12175 | var _safeParseTuple = _safeJsonParseTuple2['default'](dataSetup || '{}'); | ||
12176 | |||
12177 | var err = _safeParseTuple[0]; | ||
12178 | var data = _safeParseTuple[1]; | ||
12179 | |||
12180 | if (err) { | ||
12181 | _utilsLogJs2['default'].error(err); | ||
12182 | } | ||
12183 | _objectAssign2['default'](tagOptions, data); | ||
12184 | } | ||
12185 | |||
12186 | _objectAssign2['default'](baseOptions, tagOptions); | ||
12187 | |||
12188 | // Get tag children settings | ||
12189 | if (tag.hasChildNodes()) { | ||
12190 | var children = tag.childNodes; | ||
12191 | |||
12192 | for (var i = 0, j = children.length; i < j; i++) { | ||
12193 | var child = children[i]; | ||
12194 | // Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/ | ||
12195 | var childName = child.nodeName.toLowerCase(); | ||
12196 | if (childName === 'source') { | ||
12197 | baseOptions.sources.push(Dom.getElAttributes(child)); | ||
12198 | } else if (childName === 'track') { | ||
12199 | baseOptions.tracks.push(Dom.getElAttributes(child)); | ||
12200 | } | ||
12201 | } | ||
12202 | } | ||
12203 | |||
12204 | return baseOptions; | ||
12205 | }; | ||
12206 | |||
12207 | return Player; | ||
12208 | })(_componentJs2['default']); | ||
12209 | |||
12210 | Player.players = {}; | ||
12211 | |||
12212 | var navigator = _globalWindow2['default'].navigator; | ||
12213 | /* | ||
12214 | * Player instance options, surfaced using options | ||
12215 | * options = Player.prototype.options_ | ||
12216 | * Make changes in options, not here. | ||
12217 | * | ||
12218 | * @type {Object} | ||
12219 | * @private | ||
12220 | */ | ||
12221 | Player.prototype.options_ = { | ||
12222 | // Default order of fallback technology | ||
12223 | techOrder: ['html5', 'flash'], | ||
12224 | // techOrder: ['flash','html5'], | ||
12225 | |||
12226 | html5: {}, | ||
12227 | flash: {}, | ||
12228 | |||
12229 | // defaultVolume: 0.85, | ||
12230 | defaultVolume: 0.00, // The freakin seaguls are driving me crazy! | ||
12231 | |||
12232 | // default inactivity timeout | ||
12233 | inactivityTimeout: 2000, | ||
12234 | |||
12235 | // default playback rates | ||
12236 | playbackRates: [], | ||
12237 | // Add playback rate selection by adding rates | ||
12238 | // 'playbackRates': [0.5, 1, 1.5, 2], | ||
12239 | |||
12240 | // Included control sets | ||
12241 | children: ['mediaLoader', 'posterImage', 'textTrackDisplay', 'loadingSpinner', 'bigPlayButton', 'controlBar', 'errorDisplay', 'textTrackSettings'], | ||
12242 | |||
12243 | language: _globalDocument2['default'].getElementsByTagName('html')[0].getAttribute('lang') || navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language || 'en', | ||
12244 | |||
12245 | // locales and their language translations | ||
12246 | languages: {}, | ||
12247 | |||
12248 | // Default message to show when a video cannot be played. | ||
12249 | notSupportedMessage: 'No compatible source was found for this media.' | ||
12250 | }; | ||
12251 | |||
12252 | /** | ||
12253 | * Fired when the player has initial duration and dimension information | ||
12254 | * | ||
12255 | * @event loadedmetadata | ||
12256 | */ | ||
12257 | Player.prototype.handleLoadedMetaData_; | ||
12258 | |||
12259 | /** | ||
12260 | * Fired when the player has downloaded data at the current playback position | ||
12261 | * | ||
12262 | * @event loadeddata | ||
12263 | */ | ||
12264 | Player.prototype.handleLoadedData_; | ||
12265 | |||
12266 | /** | ||
12267 | * Fired when the user is active, e.g. moves the mouse over the player | ||
12268 | * | ||
12269 | * @event useractive | ||
12270 | */ | ||
12271 | Player.prototype.handleUserActive_; | ||
12272 | |||
12273 | /** | ||
12274 | * Fired when the user is inactive, e.g. a short delay after the last mouse move or control interaction | ||
12275 | * | ||
12276 | * @event userinactive | ||
12277 | */ | ||
12278 | Player.prototype.handleUserInactive_; | ||
12279 | |||
12280 | /** | ||
12281 | * Fired when the current playback position has changed * | ||
12282 | * During playback this is fired every 15-250 milliseconds, depending on the | ||
12283 | * playback technology in use. | ||
12284 | * | ||
12285 | * @event timeupdate | ||
12286 | */ | ||
12287 | Player.prototype.handleTimeUpdate_; | ||
12288 | |||
12289 | /** | ||
12290 | * Fired when video playback ends | ||
12291 | * | ||
12292 | * @event ended | ||
12293 | */ | ||
12294 | Player.prototype.handleTechEnded_; | ||
12295 | |||
12296 | /** | ||
12297 | * Fired when the volume changes | ||
12298 | * | ||
12299 | * @event volumechange | ||
12300 | */ | ||
12301 | Player.prototype.handleVolumeChange_; | ||
12302 | |||
12303 | /** | ||
12304 | * Fired when an error occurs | ||
12305 | * | ||
12306 | * @event error | ||
12307 | */ | ||
12308 | Player.prototype.handleError_; | ||
12309 | |||
12310 | Player.prototype.flexNotSupported_ = function () { | ||
12311 | var elem = _globalDocument2['default'].createElement('i'); | ||
12312 | |||
12313 | // Note: We don't actually use flexBasis (or flexOrder), but it's one of the more | ||
12314 | // common flex features that we can rely on when checking for flex support. | ||
12315 | return !('flexBasis' in elem.style || 'webkitFlexBasis' in elem.style || 'mozFlexBasis' in elem.style || 'msFlexBasis' in elem.style || 'msFlexOrder' in elem.style) /* IE10-specific (2012 flex spec) */; | ||
12316 | }; | ||
12317 | |||
12318 | _componentJs2['default'].registerComponent('Player', Player); | ||
12319 | exports['default'] = Player; | ||
12320 | module.exports = exports['default']; | ||
12321 | // If empty string, make it a parsable json object. | ||
12322 | |||
12323 | },{"./big-play-button.js":63,"./component.js":67,"./control-bar/control-bar.js":68,"./error-display.js":98,"./fullscreen-api.js":101,"./loading-spinner.js":102,"./media-error.js":103,"./modal-dialog":107,"./poster-image.js":112,"./tech/html5.js":117,"./tech/loader.js":118,"./tech/tech.js":119,"./tracks/text-track-display.js":123,"./tracks/text-track-list-converter.js":125,"./tracks/text-track-settings.js":127,"./utils/browser.js":129,"./utils/buffer.js":130,"./utils/dom.js":132,"./utils/events.js":133,"./utils/fn.js":134,"./utils/guid.js":136,"./utils/log.js":137,"./utils/merge-options.js":138,"./utils/stylesheet.js":139,"./utils/time-ranges.js":140,"./utils/to-title-case.js":141,"global/document":1,"global/window":2,"object.assign":45,"safe-json-parse/tuple":54}],109:[function(_dereq_,module,exports){ | ||
12324 | /** | ||
12325 | * @file plugins.js | ||
12326 | */ | ||
12327 | 'use strict'; | ||
12328 | |||
12329 | exports.__esModule = true; | ||
12330 | |||
12331 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
12332 | |||
12333 | var _playerJs = _dereq_('./player.js'); | ||
12334 | |||
12335 | var _playerJs2 = _interopRequireDefault(_playerJs); | ||
12336 | |||
12337 | /** | ||
12338 | * The method for registering a video.js plugin | ||
12339 | * | ||
12340 | * @param {String} name The name of the plugin | ||
12341 | * @param {Function} init The function that is run when the player inits | ||
12342 | * @method plugin | ||
12343 | */ | ||
12344 | var plugin = function plugin(name, init) { | ||
12345 | _playerJs2['default'].prototype[name] = init; | ||
12346 | }; | ||
12347 | |||
12348 | exports['default'] = plugin; | ||
12349 | module.exports = exports['default']; | ||
12350 | |||
12351 | },{"./player.js":108}],110:[function(_dereq_,module,exports){ | ||
12352 | /** | ||
12353 | * @file popup-button.js | ||
12354 | */ | ||
12355 | 'use strict'; | ||
12356 | |||
12357 | exports.__esModule = true; | ||
12358 | |||
12359 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
12360 | |||
12361 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
12362 | |||
12363 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
12364 | |||
12365 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
12366 | |||
12367 | var _clickableComponentJs = _dereq_('../clickable-component.js'); | ||
12368 | |||
12369 | var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); | ||
12370 | |||
12371 | var _componentJs = _dereq_('../component.js'); | ||
12372 | |||
12373 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
12374 | |||
12375 | var _popupJs = _dereq_('./popup.js'); | ||
12376 | |||
12377 | var _popupJs2 = _interopRequireDefault(_popupJs); | ||
12378 | |||
12379 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
12380 | |||
12381 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
12382 | |||
12383 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
12384 | |||
12385 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
12386 | |||
12387 | var _utilsToTitleCaseJs = _dereq_('../utils/to-title-case.js'); | ||
12388 | |||
12389 | var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); | ||
12390 | |||
12391 | /** | ||
12392 | * A button class with a popup control | ||
12393 | * | ||
12394 | * @param {Player|Object} player | ||
12395 | * @param {Object=} options | ||
12396 | * @extends ClickableComponent | ||
12397 | * @class PopupButton | ||
12398 | */ | ||
12399 | |||
12400 | var PopupButton = (function (_ClickableComponent) { | ||
12401 | _inherits(PopupButton, _ClickableComponent); | ||
12402 | |||
12403 | function PopupButton(player) { | ||
12404 | var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
12405 | |||
12406 | _classCallCheck(this, PopupButton); | ||
12407 | |||
12408 | _ClickableComponent.call(this, player, options); | ||
12409 | |||
12410 | this.update(); | ||
12411 | } | ||
12412 | |||
12413 | /** | ||
12414 | * Update popup | ||
12415 | * | ||
12416 | * @method update | ||
12417 | */ | ||
12418 | |||
12419 | PopupButton.prototype.update = function update() { | ||
12420 | var popup = this.createPopup(); | ||
12421 | |||
12422 | if (this.popup) { | ||
12423 | this.removeChild(this.popup); | ||
12424 | } | ||
12425 | |||
12426 | this.popup = popup; | ||
12427 | this.addChild(popup); | ||
12428 | |||
12429 | if (this.items && this.items.length === 0) { | ||
12430 | this.hide(); | ||
12431 | } else if (this.items && this.items.length > 1) { | ||
12432 | this.show(); | ||
12433 | } | ||
12434 | }; | ||
12435 | |||
12436 | /** | ||
12437 | * Create popup - Override with specific functionality for component | ||
12438 | * | ||
12439 | * @return {Popup} The constructed popup | ||
12440 | * @method createPopup | ||
12441 | */ | ||
12442 | |||
12443 | PopupButton.prototype.createPopup = function createPopup() {}; | ||
12444 | |||
12445 | /** | ||
12446 | * Create the component's DOM element | ||
12447 | * | ||
12448 | * @return {Element} | ||
12449 | * @method createEl | ||
12450 | */ | ||
12451 | |||
12452 | PopupButton.prototype.createEl = function createEl() { | ||
12453 | return _ClickableComponent.prototype.createEl.call(this, 'div', { | ||
12454 | className: this.buildCSSClass() | ||
12455 | }); | ||
12456 | }; | ||
12457 | |||
12458 | /** | ||
12459 | * Allow sub components to stack CSS class names | ||
12460 | * | ||
12461 | * @return {String} The constructed class name | ||
12462 | * @method buildCSSClass | ||
12463 | */ | ||
12464 | |||
12465 | PopupButton.prototype.buildCSSClass = function buildCSSClass() { | ||
12466 | var menuButtonClass = 'vjs-menu-button'; | ||
12467 | |||
12468 | // If the inline option is passed, we want to use different styles altogether. | ||
12469 | if (this.options_.inline === true) { | ||
12470 | menuButtonClass += '-inline'; | ||
12471 | } else { | ||
12472 | menuButtonClass += '-popup'; | ||
12473 | } | ||
12474 | |||
12475 | return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this); | ||
12476 | }; | ||
12477 | |||
12478 | return PopupButton; | ||
12479 | })(_clickableComponentJs2['default']); | ||
12480 | |||
12481 | _componentJs2['default'].registerComponent('PopupButton', PopupButton); | ||
12482 | exports['default'] = PopupButton; | ||
12483 | module.exports = exports['default']; | ||
12484 | |||
12485 | },{"../clickable-component.js":65,"../component.js":67,"../utils/dom.js":132,"../utils/fn.js":134,"../utils/to-title-case.js":141,"./popup.js":111}],111:[function(_dereq_,module,exports){ | ||
12486 | /** | ||
12487 | * @file popup.js | ||
12488 | */ | ||
12489 | 'use strict'; | ||
12490 | |||
12491 | exports.__esModule = true; | ||
12492 | |||
12493 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
12494 | |||
12495 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
12496 | |||
12497 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
12498 | |||
12499 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
12500 | |||
12501 | var _componentJs = _dereq_('../component.js'); | ||
12502 | |||
12503 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
12504 | |||
12505 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
12506 | |||
12507 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
12508 | |||
12509 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
12510 | |||
12511 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
12512 | |||
12513 | var _utilsEventsJs = _dereq_('../utils/events.js'); | ||
12514 | |||
12515 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
12516 | |||
12517 | /** | ||
12518 | * The Popup component is used to build pop up controls. | ||
12519 | * | ||
12520 | * @extends Component | ||
12521 | * @class Popup | ||
12522 | */ | ||
12523 | |||
12524 | var Popup = (function (_Component) { | ||
12525 | _inherits(Popup, _Component); | ||
12526 | |||
12527 | function Popup() { | ||
12528 | _classCallCheck(this, Popup); | ||
12529 | |||
12530 | _Component.apply(this, arguments); | ||
12531 | } | ||
12532 | |||
12533 | /** | ||
12534 | * Add a popup item to the popup | ||
12535 | * | ||
12536 | * @param {Object|String} component Component or component type to add | ||
12537 | * @method addItem | ||
12538 | */ | ||
12539 | |||
12540 | Popup.prototype.addItem = function addItem(component) { | ||
12541 | this.addChild(component); | ||
12542 | component.on('click', Fn.bind(this, function () { | ||
12543 | this.unlockShowing(); | ||
12544 | })); | ||
12545 | }; | ||
12546 | |||
12547 | /** | ||
12548 | * Create the component's DOM element | ||
12549 | * | ||
12550 | * @return {Element} | ||
12551 | * @method createEl | ||
12552 | */ | ||
12553 | |||
12554 | Popup.prototype.createEl = function createEl() { | ||
12555 | var contentElType = this.options_.contentElType || 'ul'; | ||
12556 | this.contentEl_ = Dom.createEl(contentElType, { | ||
12557 | className: 'vjs-menu-content' | ||
12558 | }); | ||
12559 | var el = _Component.prototype.createEl.call(this, 'div', { | ||
12560 | append: this.contentEl_, | ||
12561 | className: 'vjs-menu' | ||
12562 | }); | ||
12563 | el.appendChild(this.contentEl_); | ||
12564 | |||
12565 | // Prevent clicks from bubbling up. Needed for Popup Buttons, | ||
12566 | // where a click on the parent is significant | ||
12567 | Events.on(el, 'click', function (event) { | ||
12568 | event.preventDefault(); | ||
12569 | event.stopImmediatePropagation(); | ||
12570 | }); | ||
12571 | |||
12572 | return el; | ||
12573 | }; | ||
12574 | |||
12575 | return Popup; | ||
12576 | })(_componentJs2['default']); | ||
12577 | |||
12578 | _componentJs2['default'].registerComponent('Popup', Popup); | ||
12579 | exports['default'] = Popup; | ||
12580 | module.exports = exports['default']; | ||
12581 | |||
12582 | },{"../component.js":67,"../utils/dom.js":132,"../utils/events.js":133,"../utils/fn.js":134}],112:[function(_dereq_,module,exports){ | ||
12583 | /** | ||
12584 | * @file poster-image.js | ||
12585 | */ | ||
12586 | 'use strict'; | ||
12587 | |||
12588 | exports.__esModule = true; | ||
12589 | |||
12590 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
12591 | |||
12592 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
12593 | |||
12594 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
12595 | |||
12596 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
12597 | |||
12598 | var _clickableComponentJs = _dereq_('./clickable-component.js'); | ||
12599 | |||
12600 | var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); | ||
12601 | |||
12602 | var _componentJs = _dereq_('./component.js'); | ||
12603 | |||
12604 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
12605 | |||
12606 | var _utilsFnJs = _dereq_('./utils/fn.js'); | ||
12607 | |||
12608 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
12609 | |||
12610 | var _utilsDomJs = _dereq_('./utils/dom.js'); | ||
12611 | |||
12612 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
12613 | |||
12614 | var _utilsBrowserJs = _dereq_('./utils/browser.js'); | ||
12615 | |||
12616 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
12617 | |||
12618 | /** | ||
12619 | * The component that handles showing the poster image. | ||
12620 | * | ||
12621 | * @param {Player|Object} player | ||
12622 | * @param {Object=} options | ||
12623 | * @extends Button | ||
12624 | * @class PosterImage | ||
12625 | */ | ||
12626 | |||
12627 | var PosterImage = (function (_ClickableComponent) { | ||
12628 | _inherits(PosterImage, _ClickableComponent); | ||
12629 | |||
12630 | function PosterImage(player, options) { | ||
12631 | _classCallCheck(this, PosterImage); | ||
12632 | |||
12633 | _ClickableComponent.call(this, player, options); | ||
12634 | |||
12635 | this.update(); | ||
12636 | player.on('posterchange', Fn.bind(this, this.update)); | ||
12637 | } | ||
12638 | |||
12639 | /** | ||
12640 | * Clean up the poster image | ||
12641 | * | ||
12642 | * @method dispose | ||
12643 | */ | ||
12644 | |||
12645 | PosterImage.prototype.dispose = function dispose() { | ||
12646 | this.player().off('posterchange', this.update); | ||
12647 | _ClickableComponent.prototype.dispose.call(this); | ||
12648 | }; | ||
12649 | |||
12650 | /** | ||
12651 | * Create the poster's image element | ||
12652 | * | ||
12653 | * @return {Element} | ||
12654 | * @method createEl | ||
12655 | */ | ||
12656 | |||
12657 | PosterImage.prototype.createEl = function createEl() { | ||
12658 | var el = Dom.createEl('div', { | ||
12659 | className: 'vjs-poster', | ||
12660 | |||
12661 | // Don't want poster to be tabbable. | ||
12662 | tabIndex: -1 | ||
12663 | }); | ||
12664 | |||
12665 | // To ensure the poster image resizes while maintaining its original aspect | ||
12666 | // ratio, use a div with `background-size` when available. For browsers that | ||
12667 | // do not support `background-size` (e.g. IE8), fall back on using a regular | ||
12668 | // img element. | ||
12669 | if (!browser.BACKGROUND_SIZE_SUPPORTED) { | ||
12670 | this.fallbackImg_ = Dom.createEl('img'); | ||
12671 | el.appendChild(this.fallbackImg_); | ||
12672 | } | ||
12673 | |||
12674 | return el; | ||
12675 | }; | ||
12676 | |||
12677 | /** | ||
12678 | * Event handler for updates to the player's poster source | ||
12679 | * | ||
12680 | * @method update | ||
12681 | */ | ||
12682 | |||
12683 | PosterImage.prototype.update = function update() { | ||
12684 | var url = this.player().poster(); | ||
12685 | |||
12686 | this.setSrc(url); | ||
12687 | |||
12688 | // If there's no poster source we should display:none on this component | ||
12689 | // so it's not still clickable or right-clickable | ||
12690 | if (url) { | ||
12691 | this.show(); | ||
12692 | } else { | ||
12693 | this.hide(); | ||
12694 | } | ||
12695 | }; | ||
12696 | |||
12697 | /** | ||
12698 | * Set the poster source depending on the display method | ||
12699 | * | ||
12700 | * @param {String} url The URL to the poster source | ||
12701 | * @method setSrc | ||
12702 | */ | ||
12703 | |||
12704 | PosterImage.prototype.setSrc = function setSrc(url) { | ||
12705 | if (this.fallbackImg_) { | ||
12706 | this.fallbackImg_.src = url; | ||
12707 | } else { | ||
12708 | var backgroundImage = ''; | ||
12709 | // Any falsey values should stay as an empty string, otherwise | ||
12710 | // this will throw an extra error | ||
12711 | if (url) { | ||
12712 | backgroundImage = 'url("' + url + '")'; | ||
12713 | } | ||
12714 | |||
12715 | this.el_.style.backgroundImage = backgroundImage; | ||
12716 | } | ||
12717 | }; | ||
12718 | |||
12719 | /** | ||
12720 | * Event handler for clicks on the poster image | ||
12721 | * | ||
12722 | * @method handleClick | ||
12723 | */ | ||
12724 | |||
12725 | PosterImage.prototype.handleClick = function handleClick() { | ||
12726 | // We don't want a click to trigger playback when controls are disabled | ||
12727 | // but CSS should be hiding the poster to prevent that from happening | ||
12728 | if (this.player_.paused()) { | ||
12729 | this.player_.play(); | ||
12730 | } else { | ||
12731 | this.player_.pause(); | ||
12732 | } | ||
12733 | }; | ||
12734 | |||
12735 | return PosterImage; | ||
12736 | })(_clickableComponentJs2['default']); | ||
12737 | |||
12738 | _componentJs2['default'].registerComponent('PosterImage', PosterImage); | ||
12739 | exports['default'] = PosterImage; | ||
12740 | module.exports = exports['default']; | ||
12741 | |||
12742 | },{"./clickable-component.js":65,"./component.js":67,"./utils/browser.js":129,"./utils/dom.js":132,"./utils/fn.js":134}],113:[function(_dereq_,module,exports){ | ||
12743 | /** | ||
12744 | * @file setup.js | ||
12745 | * | ||
12746 | * Functions for automatically setting up a player | ||
12747 | * based on the data-setup attribute of the video tag | ||
12748 | */ | ||
12749 | 'use strict'; | ||
12750 | |||
12751 | exports.__esModule = true; | ||
12752 | |||
12753 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
12754 | |||
12755 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
12756 | |||
12757 | var _utilsEventsJs = _dereq_('./utils/events.js'); | ||
12758 | |||
12759 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
12760 | |||
12761 | var _globalDocument = _dereq_('global/document'); | ||
12762 | |||
12763 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
12764 | |||
12765 | var _globalWindow = _dereq_('global/window'); | ||
12766 | |||
12767 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
12768 | |||
12769 | var _windowLoaded = false; | ||
12770 | var videojs = undefined; | ||
12771 | |||
12772 | // Automatically set up any tags that have a data-setup attribute | ||
12773 | var autoSetup = function autoSetup() { | ||
12774 | // One day, when we stop supporting IE8, go back to this, but in the meantime...*hack hack hack* | ||
12775 | // var vids = Array.prototype.slice.call(document.getElementsByTagName('video')); | ||
12776 | // var audios = Array.prototype.slice.call(document.getElementsByTagName('audio')); | ||
12777 | // var mediaEls = vids.concat(audios); | ||
12778 | |||
12779 | // Because IE8 doesn't support calling slice on a node list, we need to loop through each list of elements | ||
12780 | // to build up a new, combined list of elements. | ||
12781 | var vids = _globalDocument2['default'].getElementsByTagName('video'); | ||
12782 | var audios = _globalDocument2['default'].getElementsByTagName('audio'); | ||
12783 | var mediaEls = []; | ||
12784 | if (vids && vids.length > 0) { | ||
12785 | for (var i = 0, e = vids.length; i < e; i++) { | ||
12786 | mediaEls.push(vids[i]); | ||
12787 | } | ||
12788 | } | ||
12789 | if (audios && audios.length > 0) { | ||
12790 | for (var i = 0, e = audios.length; i < e; i++) { | ||
12791 | mediaEls.push(audios[i]); | ||
12792 | } | ||
12793 | } | ||
12794 | |||
12795 | // Check if any media elements exist | ||
12796 | if (mediaEls && mediaEls.length > 0) { | ||
12797 | |||
12798 | for (var i = 0, e = mediaEls.length; i < e; i++) { | ||
12799 | var mediaEl = mediaEls[i]; | ||
12800 | |||
12801 | // Check if element exists, has getAttribute func. | ||
12802 | // IE seems to consider typeof el.getAttribute == 'object' instead of 'function' like expected, at least when loading the player immediately. | ||
12803 | if (mediaEl && mediaEl.getAttribute) { | ||
12804 | |||
12805 | // Make sure this player hasn't already been set up. | ||
12806 | if (mediaEl['player'] === undefined) { | ||
12807 | var options = mediaEl.getAttribute('data-setup'); | ||
12808 | |||
12809 | // Check if data-setup attr exists. | ||
12810 | // We only auto-setup if they've added the data-setup attr. | ||
12811 | if (options !== null) { | ||
12812 | // Create new video.js instance. | ||
12813 | var player = videojs(mediaEl); | ||
12814 | } | ||
12815 | } | ||
12816 | |||
12817 | // If getAttribute isn't defined, we need to wait for the DOM. | ||
12818 | } else { | ||
12819 | autoSetupTimeout(1); | ||
12820 | break; | ||
12821 | } | ||
12822 | } | ||
12823 | |||
12824 | // No videos were found, so keep looping unless page is finished loading. | ||
12825 | } else if (!_windowLoaded) { | ||
12826 | autoSetupTimeout(1); | ||
12827 | } | ||
12828 | }; | ||
12829 | |||
12830 | // Pause to let the DOM keep processing | ||
12831 | var autoSetupTimeout = function autoSetupTimeout(wait, vjs) { | ||
12832 | if (vjs) { | ||
12833 | videojs = vjs; | ||
12834 | } | ||
12835 | |||
12836 | setTimeout(autoSetup, wait); | ||
12837 | }; | ||
12838 | |||
12839 | if (_globalDocument2['default'].readyState === 'complete') { | ||
12840 | _windowLoaded = true; | ||
12841 | } else { | ||
12842 | Events.one(_globalWindow2['default'], 'load', function () { | ||
12843 | _windowLoaded = true; | ||
12844 | }); | ||
12845 | } | ||
12846 | |||
12847 | var hasLoaded = function hasLoaded() { | ||
12848 | return _windowLoaded; | ||
12849 | }; | ||
12850 | |||
12851 | exports.autoSetup = autoSetup; | ||
12852 | exports.autoSetupTimeout = autoSetupTimeout; | ||
12853 | exports.hasLoaded = hasLoaded; | ||
12854 | |||
12855 | },{"./utils/events.js":133,"global/document":1,"global/window":2}],114:[function(_dereq_,module,exports){ | ||
12856 | /** | ||
12857 | * @file slider.js | ||
12858 | */ | ||
12859 | 'use strict'; | ||
12860 | |||
12861 | exports.__esModule = true; | ||
12862 | |||
12863 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
12864 | |||
12865 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
12866 | |||
12867 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
12868 | |||
12869 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
12870 | |||
12871 | var _componentJs = _dereq_('../component.js'); | ||
12872 | |||
12873 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
12874 | |||
12875 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
12876 | |||
12877 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
12878 | |||
12879 | var _globalDocument = _dereq_('global/document'); | ||
12880 | |||
12881 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
12882 | |||
12883 | var _objectAssign = _dereq_('object.assign'); | ||
12884 | |||
12885 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
12886 | |||
12887 | /** | ||
12888 | * The base functionality for sliders like the volume bar and seek bar | ||
12889 | * | ||
12890 | * @param {Player|Object} player | ||
12891 | * @param {Object=} options | ||
12892 | * @extends Component | ||
12893 | * @class Slider | ||
12894 | */ | ||
12895 | |||
12896 | var Slider = (function (_Component) { | ||
12897 | _inherits(Slider, _Component); | ||
12898 | |||
12899 | function Slider(player, options) { | ||
12900 | _classCallCheck(this, Slider); | ||
12901 | |||
12902 | _Component.call(this, player, options); | ||
12903 | |||
12904 | // Set property names to bar to match with the child Slider class is looking for | ||
12905 | this.bar = this.getChild(this.options_.barName); | ||
12906 | |||
12907 | // Set a horizontal or vertical class on the slider depending on the slider type | ||
12908 | this.vertical(!!this.options_.vertical); | ||
12909 | |||
12910 | this.on('mousedown', this.handleMouseDown); | ||
12911 | this.on('touchstart', this.handleMouseDown); | ||
12912 | this.on('focus', this.handleFocus); | ||
12913 | this.on('blur', this.handleBlur); | ||
12914 | this.on('click', this.handleClick); | ||
12915 | |||
12916 | this.on(player, 'controlsvisible', this.update); | ||
12917 | this.on(player, this.playerEvent, this.update); | ||
12918 | } | ||
12919 | |||
12920 | /** | ||
12921 | * Create the component's DOM element | ||
12922 | * | ||
12923 | * @param {String} type Type of element to create | ||
12924 | * @param {Object=} props List of properties in Object form | ||
12925 | * @return {Element} | ||
12926 | * @method createEl | ||
12927 | */ | ||
12928 | |||
12929 | Slider.prototype.createEl = function createEl(type) { | ||
12930 | var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
12931 | var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; | ||
12932 | |||
12933 | // Add the slider element class to all sub classes | ||
12934 | props.className = props.className + ' vjs-slider'; | ||
12935 | props = _objectAssign2['default']({ | ||
12936 | tabIndex: 0 | ||
12937 | }, props); | ||
12938 | |||
12939 | attributes = _objectAssign2['default']({ | ||
12940 | 'role': 'slider', | ||
12941 | 'aria-valuenow': 0, | ||
12942 | 'aria-valuemin': 0, | ||
12943 | 'aria-valuemax': 100, | ||
12944 | tabIndex: 0 | ||
12945 | }, attributes); | ||
12946 | |||
12947 | return _Component.prototype.createEl.call(this, type, props, attributes); | ||
12948 | }; | ||
12949 | |||
12950 | /** | ||
12951 | * Handle mouse down on slider | ||
12952 | * | ||
12953 | * @param {Object} event Mouse down event object | ||
12954 | * @method handleMouseDown | ||
12955 | */ | ||
12956 | |||
12957 | Slider.prototype.handleMouseDown = function handleMouseDown(event) { | ||
12958 | event.preventDefault(); | ||
12959 | Dom.blockTextSelection(); | ||
12960 | |||
12961 | this.addClass('vjs-sliding'); | ||
12962 | this.trigger('slideractive'); | ||
12963 | |||
12964 | this.on(_globalDocument2['default'], 'mousemove', this.handleMouseMove); | ||
12965 | this.on(_globalDocument2['default'], 'mouseup', this.handleMouseUp); | ||
12966 | this.on(_globalDocument2['default'], 'touchmove', this.handleMouseMove); | ||
12967 | this.on(_globalDocument2['default'], 'touchend', this.handleMouseUp); | ||
12968 | |||
12969 | this.handleMouseMove(event); | ||
12970 | }; | ||
12971 | |||
12972 | /** | ||
12973 | * To be overridden by a subclass | ||
12974 | * | ||
12975 | * @method handleMouseMove | ||
12976 | */ | ||
12977 | |||
12978 | Slider.prototype.handleMouseMove = function handleMouseMove() {}; | ||
12979 | |||
12980 | /** | ||
12981 | * Handle mouse up on Slider | ||
12982 | * | ||
12983 | * @method handleMouseUp | ||
12984 | */ | ||
12985 | |||
12986 | Slider.prototype.handleMouseUp = function handleMouseUp() { | ||
12987 | Dom.unblockTextSelection(); | ||
12988 | |||
12989 | this.removeClass('vjs-sliding'); | ||
12990 | this.trigger('sliderinactive'); | ||
12991 | |||
12992 | this.off(_globalDocument2['default'], 'mousemove', this.handleMouseMove); | ||
12993 | this.off(_globalDocument2['default'], 'mouseup', this.handleMouseUp); | ||
12994 | this.off(_globalDocument2['default'], 'touchmove', this.handleMouseMove); | ||
12995 | this.off(_globalDocument2['default'], 'touchend', this.handleMouseUp); | ||
12996 | |||
12997 | this.update(); | ||
12998 | }; | ||
12999 | |||
13000 | /** | ||
13001 | * Update slider | ||
13002 | * | ||
13003 | * @method update | ||
13004 | */ | ||
13005 | |||
13006 | Slider.prototype.update = function update() { | ||
13007 | // In VolumeBar init we have a setTimeout for update that pops and update to the end of the | ||
13008 | // execution stack. The player is destroyed before then update will cause an error | ||
13009 | if (!this.el_) return; | ||
13010 | |||
13011 | // If scrubbing, we could use a cached value to make the handle keep up with the user's mouse. | ||
13012 | // On HTML5 browsers scrubbing is really smooth, but some flash players are slow, so we might want to utilize this later. | ||
13013 | // var progress = (this.player_.scrubbing()) ? this.player_.getCache().currentTime / this.player_.duration() : this.player_.currentTime() / this.player_.duration(); | ||
13014 | var progress = this.getPercent(); | ||
13015 | var bar = this.bar; | ||
13016 | |||
13017 | // If there's no bar... | ||
13018 | if (!bar) return; | ||
13019 | |||
13020 | // Protect against no duration and other division issues | ||
13021 | if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === Infinity) { | ||
13022 | progress = 0; | ||
13023 | } | ||
13024 | |||
13025 | // Convert to a percentage for setting | ||
13026 | var percentage = (progress * 100).toFixed(2) + '%'; | ||
13027 | |||
13028 | // Set the new bar width or height | ||
13029 | if (this.vertical()) { | ||
13030 | bar.el().style.height = percentage; | ||
13031 | } else { | ||
13032 | bar.el().style.width = percentage; | ||
13033 | } | ||
13034 | }; | ||
13035 | |||
13036 | /** | ||
13037 | * Calculate distance for slider | ||
13038 | * | ||
13039 | * @param {Object} event Event object | ||
13040 | * @method calculateDistance | ||
13041 | */ | ||
13042 | |||
13043 | Slider.prototype.calculateDistance = function calculateDistance(event) { | ||
13044 | var position = Dom.getPointerPosition(this.el_, event); | ||
13045 | if (this.vertical()) { | ||
13046 | return position.y; | ||
13047 | } | ||
13048 | return position.x; | ||
13049 | }; | ||
13050 | |||
13051 | /** | ||
13052 | * Handle on focus for slider | ||
13053 | * | ||
13054 | * @method handleFocus | ||
13055 | */ | ||
13056 | |||
13057 | Slider.prototype.handleFocus = function handleFocus() { | ||
13058 | this.on(_globalDocument2['default'], 'keydown', this.handleKeyPress); | ||
13059 | }; | ||
13060 | |||
13061 | /** | ||
13062 | * Handle key press for slider | ||
13063 | * | ||
13064 | * @param {Object} event Event object | ||
13065 | * @method handleKeyPress | ||
13066 | */ | ||
13067 | |||
13068 | Slider.prototype.handleKeyPress = function handleKeyPress(event) { | ||
13069 | if (event.which === 37 || event.which === 40) { | ||
13070 | // Left and Down Arrows | ||
13071 | event.preventDefault(); | ||
13072 | this.stepBack(); | ||
13073 | } else if (event.which === 38 || event.which === 39) { | ||
13074 | // Up and Right Arrows | ||
13075 | event.preventDefault(); | ||
13076 | this.stepForward(); | ||
13077 | } | ||
13078 | }; | ||
13079 | |||
13080 | /** | ||
13081 | * Handle on blur for slider | ||
13082 | * | ||
13083 | * @method handleBlur | ||
13084 | */ | ||
13085 | |||
13086 | Slider.prototype.handleBlur = function handleBlur() { | ||
13087 | this.off(_globalDocument2['default'], 'keydown', this.handleKeyPress); | ||
13088 | }; | ||
13089 | |||
13090 | /** | ||
13091 | * Listener for click events on slider, used to prevent clicks | ||
13092 | * from bubbling up to parent elements like button menus. | ||
13093 | * | ||
13094 | * @param {Object} event Event object | ||
13095 | * @method handleClick | ||
13096 | */ | ||
13097 | |||
13098 | Slider.prototype.handleClick = function handleClick(event) { | ||
13099 | event.stopImmediatePropagation(); | ||
13100 | event.preventDefault(); | ||
13101 | }; | ||
13102 | |||
13103 | /** | ||
13104 | * Get/set if slider is horizontal for vertical | ||
13105 | * | ||
13106 | * @param {Boolean} bool True if slider is vertical, false is horizontal | ||
13107 | * @return {Boolean} True if slider is vertical, false is horizontal | ||
13108 | * @method vertical | ||
13109 | */ | ||
13110 | |||
13111 | Slider.prototype.vertical = function vertical(bool) { | ||
13112 | if (bool === undefined) { | ||
13113 | return this.vertical_ || false; | ||
13114 | } | ||
13115 | |||
13116 | this.vertical_ = !!bool; | ||
13117 | |||
13118 | if (this.vertical_) { | ||
13119 | this.addClass('vjs-slider-vertical'); | ||
13120 | } else { | ||
13121 | this.addClass('vjs-slider-horizontal'); | ||
13122 | } | ||
13123 | |||
13124 | return this; | ||
13125 | }; | ||
13126 | |||
13127 | return Slider; | ||
13128 | })(_componentJs2['default']); | ||
13129 | |||
13130 | _componentJs2['default'].registerComponent('Slider', Slider); | ||
13131 | exports['default'] = Slider; | ||
13132 | module.exports = exports['default']; | ||
13133 | |||
13134 | },{"../component.js":67,"../utils/dom.js":132,"global/document":1,"object.assign":45}],115:[function(_dereq_,module,exports){ | ||
13135 | /** | ||
13136 | * @file flash-rtmp.js | ||
13137 | */ | ||
13138 | 'use strict'; | ||
13139 | |||
13140 | exports.__esModule = true; | ||
13141 | function FlashRtmpDecorator(Flash) { | ||
13142 | Flash.streamingFormats = { | ||
13143 | 'rtmp/mp4': 'MP4', | ||
13144 | 'rtmp/flv': 'FLV' | ||
13145 | }; | ||
13146 | |||
13147 | Flash.streamFromParts = function (connection, stream) { | ||
13148 | return connection + '&' + stream; | ||
13149 | }; | ||
13150 | |||
13151 | Flash.streamToParts = function (src) { | ||
13152 | var parts = { | ||
13153 | connection: '', | ||
13154 | stream: '' | ||
13155 | }; | ||
13156 | |||
13157 | if (!src) return parts; | ||
13158 | |||
13159 | // Look for the normal URL separator we expect, '&'. | ||
13160 | // If found, we split the URL into two pieces around the | ||
13161 | // first '&'. | ||
13162 | var connEnd = src.search(/&(?!\w+=)/); | ||
13163 | var streamBegin = undefined; | ||
13164 | if (connEnd !== -1) { | ||
13165 | streamBegin = connEnd + 1; | ||
13166 | } else { | ||
13167 | // If there's not a '&', we use the last '/' as the delimiter. | ||
13168 | connEnd = streamBegin = src.lastIndexOf('/') + 1; | ||
13169 | if (connEnd === 0) { | ||
13170 | // really, there's not a '/'? | ||
13171 | connEnd = streamBegin = src.length; | ||
13172 | } | ||
13173 | } | ||
13174 | parts.connection = src.substring(0, connEnd); | ||
13175 | parts.stream = src.substring(streamBegin, src.length); | ||
13176 | |||
13177 | return parts; | ||
13178 | }; | ||
13179 | |||
13180 | Flash.isStreamingType = function (srcType) { | ||
13181 | return srcType in Flash.streamingFormats; | ||
13182 | }; | ||
13183 | |||
13184 | // RTMP has four variations, any string starting | ||
13185 | // with one of these protocols should be valid | ||
13186 | Flash.RTMP_RE = /^rtmp[set]?:\/\//i; | ||
13187 | |||
13188 | Flash.isStreamingSrc = function (src) { | ||
13189 | return Flash.RTMP_RE.test(src); | ||
13190 | }; | ||
13191 | |||
13192 | /** | ||
13193 | * A source handler for RTMP urls | ||
13194 | * @type {Object} | ||
13195 | */ | ||
13196 | Flash.rtmpSourceHandler = {}; | ||
13197 | |||
13198 | /** | ||
13199 | * Check if Flash can play the given videotype | ||
13200 | * @param {String} type The mimetype to check | ||
13201 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
13202 | */ | ||
13203 | Flash.rtmpSourceHandler.canPlayType = function (type) { | ||
13204 | if (Flash.isStreamingType(type)) { | ||
13205 | return 'maybe'; | ||
13206 | } | ||
13207 | |||
13208 | return ''; | ||
13209 | }; | ||
13210 | |||
13211 | /** | ||
13212 | * Check if Flash can handle the source natively | ||
13213 | * @param {Object} source The source object | ||
13214 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
13215 | */ | ||
13216 | Flash.rtmpSourceHandler.canHandleSource = function (source) { | ||
13217 | var can = Flash.rtmpSourceHandler.canPlayType(source.type); | ||
13218 | |||
13219 | if (can) { | ||
13220 | return can; | ||
13221 | } | ||
13222 | |||
13223 | if (Flash.isStreamingSrc(source.src)) { | ||
13224 | return 'maybe'; | ||
13225 | } | ||
13226 | |||
13227 | return ''; | ||
13228 | }; | ||
13229 | |||
13230 | /** | ||
13231 | * Pass the source to the flash object | ||
13232 | * Adaptive source handlers will have more complicated workflows before passing | ||
13233 | * video data to the video element | ||
13234 | * @param {Object} source The source object | ||
13235 | * @param {Flash} tech The instance of the Flash tech | ||
13236 | */ | ||
13237 | Flash.rtmpSourceHandler.handleSource = function (source, tech) { | ||
13238 | var srcParts = Flash.streamToParts(source.src); | ||
13239 | |||
13240 | tech['setRtmpConnection'](srcParts.connection); | ||
13241 | tech['setRtmpStream'](srcParts.stream); | ||
13242 | }; | ||
13243 | |||
13244 | // Register the native source handler | ||
13245 | Flash.registerSourceHandler(Flash.rtmpSourceHandler); | ||
13246 | |||
13247 | return Flash; | ||
13248 | } | ||
13249 | |||
13250 | exports['default'] = FlashRtmpDecorator; | ||
13251 | module.exports = exports['default']; | ||
13252 | |||
13253 | },{}],116:[function(_dereq_,module,exports){ | ||
13254 | /** | ||
13255 | * @file flash.js | ||
13256 | * VideoJS-SWF - Custom Flash Player with HTML5-ish API | ||
13257 | * https://github.com/zencoder/video-js-swf | ||
13258 | * Not using setupTriggers. Using global onEvent func to distribute events | ||
13259 | */ | ||
13260 | |||
13261 | 'use strict'; | ||
13262 | |||
13263 | exports.__esModule = true; | ||
13264 | |||
13265 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
13266 | |||
13267 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
13268 | |||
13269 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
13270 | |||
13271 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
13272 | |||
13273 | var _tech = _dereq_('./tech'); | ||
13274 | |||
13275 | var _tech2 = _interopRequireDefault(_tech); | ||
13276 | |||
13277 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
13278 | |||
13279 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
13280 | |||
13281 | var _utilsUrlJs = _dereq_('../utils/url.js'); | ||
13282 | |||
13283 | var Url = _interopRequireWildcard(_utilsUrlJs); | ||
13284 | |||
13285 | var _utilsTimeRangesJs = _dereq_('../utils/time-ranges.js'); | ||
13286 | |||
13287 | var _flashRtmp = _dereq_('./flash-rtmp'); | ||
13288 | |||
13289 | var _flashRtmp2 = _interopRequireDefault(_flashRtmp); | ||
13290 | |||
13291 | var _component = _dereq_('../component'); | ||
13292 | |||
13293 | var _component2 = _interopRequireDefault(_component); | ||
13294 | |||
13295 | var _globalWindow = _dereq_('global/window'); | ||
13296 | |||
13297 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
13298 | |||
13299 | var _objectAssign = _dereq_('object.assign'); | ||
13300 | |||
13301 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
13302 | |||
13303 | var navigator = _globalWindow2['default'].navigator; | ||
13304 | /** | ||
13305 | * Flash Media Controller - Wrapper for fallback SWF API | ||
13306 | * | ||
13307 | * @param {Object=} options Object of option names and values | ||
13308 | * @param {Function=} ready Ready callback function | ||
13309 | * @extends Tech | ||
13310 | * @class Flash | ||
13311 | */ | ||
13312 | |||
13313 | var Flash = (function (_Tech) { | ||
13314 | _inherits(Flash, _Tech); | ||
13315 | |||
13316 | function Flash(options, ready) { | ||
13317 | _classCallCheck(this, Flash); | ||
13318 | |||
13319 | _Tech.call(this, options, ready); | ||
13320 | |||
13321 | // Set the source when ready | ||
13322 | if (options.source) { | ||
13323 | this.ready(function () { | ||
13324 | this.setSource(options.source); | ||
13325 | }, true); | ||
13326 | } | ||
13327 | |||
13328 | // Having issues with Flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers | ||
13329 | // This allows resetting the playhead when we catch the reload | ||
13330 | if (options.startTime) { | ||
13331 | this.ready(function () { | ||
13332 | this.load(); | ||
13333 | this.play(); | ||
13334 | this.currentTime(options.startTime); | ||
13335 | }, true); | ||
13336 | } | ||
13337 | |||
13338 | // Add global window functions that the swf expects | ||
13339 | // A 4.x workflow we weren't able to solve for in 5.0 | ||
13340 | // because of the need to hard code these functions | ||
13341 | // into the swf for security reasons | ||
13342 | _globalWindow2['default'].videojs = _globalWindow2['default'].videojs || {}; | ||
13343 | _globalWindow2['default'].videojs.Flash = _globalWindow2['default'].videojs.Flash || {}; | ||
13344 | _globalWindow2['default'].videojs.Flash.onReady = Flash.onReady; | ||
13345 | _globalWindow2['default'].videojs.Flash.onEvent = Flash.onEvent; | ||
13346 | _globalWindow2['default'].videojs.Flash.onError = Flash.onError; | ||
13347 | |||
13348 | this.on('seeked', function () { | ||
13349 | this.lastSeekTarget_ = undefined; | ||
13350 | }); | ||
13351 | } | ||
13352 | |||
13353 | // Create setters and getters for attributes | ||
13354 | |||
13355 | /** | ||
13356 | * Create the component's DOM element | ||
13357 | * | ||
13358 | * @return {Element} | ||
13359 | * @method createEl | ||
13360 | */ | ||
13361 | |||
13362 | Flash.prototype.createEl = function createEl() { | ||
13363 | var options = this.options_; | ||
13364 | |||
13365 | // If video.js is hosted locally you should also set the location | ||
13366 | // for the hosted swf, which should be relative to the page (not video.js) | ||
13367 | // Otherwise this adds a CDN url. | ||
13368 | // The CDN also auto-adds a swf URL for that specific version. | ||
13369 | if (!options.swf) { | ||
13370 | options.swf = '//vjs.zencdn.net/swf/5.0.1/video-js.swf'; | ||
13371 | } | ||
13372 | |||
13373 | // Generate ID for swf object | ||
13374 | var objId = options.techId; | ||
13375 | |||
13376 | // Merge default flashvars with ones passed in to init | ||
13377 | var flashVars = _objectAssign2['default']({ | ||
13378 | |||
13379 | // SWF Callback Functions | ||
13380 | 'readyFunction': 'videojs.Flash.onReady', | ||
13381 | 'eventProxyFunction': 'videojs.Flash.onEvent', | ||
13382 | 'errorEventProxyFunction': 'videojs.Flash.onError', | ||
13383 | |||
13384 | // Player Settings | ||
13385 | 'autoplay': options.autoplay, | ||
13386 | 'preload': options.preload, | ||
13387 | 'loop': options.loop, | ||
13388 | 'muted': options.muted | ||
13389 | |||
13390 | }, options.flashVars); | ||
13391 | |||
13392 | // Merge default parames with ones passed in | ||
13393 | var params = _objectAssign2['default']({ | ||
13394 | 'wmode': 'opaque', // Opaque is needed to overlay controls, but can affect playback performance | ||
13395 | 'bgcolor': '#000000' // Using bgcolor prevents a white flash when the object is loading | ||
13396 | }, options.params); | ||
13397 | |||
13398 | // Merge default attributes with ones passed in | ||
13399 | var attributes = _objectAssign2['default']({ | ||
13400 | 'id': objId, | ||
13401 | 'name': objId, // Both ID and Name needed or swf to identify itself | ||
13402 | 'class': 'vjs-tech' | ||
13403 | }, options.attributes); | ||
13404 | |||
13405 | this.el_ = Flash.embed(options.swf, flashVars, params, attributes); | ||
13406 | this.el_.tech = this; | ||
13407 | |||
13408 | return this.el_; | ||
13409 | }; | ||
13410 | |||
13411 | /** | ||
13412 | * Play for flash tech | ||
13413 | * | ||
13414 | * @method play | ||
13415 | */ | ||
13416 | |||
13417 | Flash.prototype.play = function play() { | ||
13418 | if (this.ended()) { | ||
13419 | this.setCurrentTime(0); | ||
13420 | } | ||
13421 | this.el_.vjs_play(); | ||
13422 | }; | ||
13423 | |||
13424 | /** | ||
13425 | * Pause for flash tech | ||
13426 | * | ||
13427 | * @method pause | ||
13428 | */ | ||
13429 | |||
13430 | Flash.prototype.pause = function pause() { | ||
13431 | this.el_.vjs_pause(); | ||
13432 | }; | ||
13433 | |||
13434 | /** | ||
13435 | * Get/set video | ||
13436 | * | ||
13437 | * @param {Object=} src Source object | ||
13438 | * @return {Object} | ||
13439 | * @method src | ||
13440 | */ | ||
13441 | |||
13442 | Flash.prototype.src = function src(_src) { | ||
13443 | if (_src === undefined) { | ||
13444 | return this.currentSrc(); | ||
13445 | } | ||
13446 | |||
13447 | // Setting src through `src` not `setSrc` will be deprecated | ||
13448 | return this.setSrc(_src); | ||
13449 | }; | ||
13450 | |||
13451 | /** | ||
13452 | * Set video | ||
13453 | * | ||
13454 | * @param {Object=} src Source object | ||
13455 | * @deprecated | ||
13456 | * @method setSrc | ||
13457 | */ | ||
13458 | |||
13459 | Flash.prototype.setSrc = function setSrc(src) { | ||
13460 | // Make sure source URL is absolute. | ||
13461 | src = Url.getAbsoluteURL(src); | ||
13462 | this.el_.vjs_src(src); | ||
13463 | |||
13464 | // Currently the SWF doesn't autoplay if you load a source later. | ||
13465 | // e.g. Load player w/ no source, wait 2s, set src. | ||
13466 | if (this.autoplay()) { | ||
13467 | var tech = this; | ||
13468 | this.setTimeout(function () { | ||
13469 | tech.play(); | ||
13470 | }, 0); | ||
13471 | } | ||
13472 | }; | ||
13473 | |||
13474 | /** | ||
13475 | * Returns true if the tech is currently seeking. | ||
13476 | * @return {boolean} true if seeking | ||
13477 | */ | ||
13478 | |||
13479 | Flash.prototype.seeking = function seeking() { | ||
13480 | return this.lastSeekTarget_ !== undefined; | ||
13481 | }; | ||
13482 | |||
13483 | /** | ||
13484 | * Set current time | ||
13485 | * | ||
13486 | * @param {Number} time Current time of video | ||
13487 | * @method setCurrentTime | ||
13488 | */ | ||
13489 | |||
13490 | Flash.prototype.setCurrentTime = function setCurrentTime(time) { | ||
13491 | var seekable = this.seekable(); | ||
13492 | if (seekable.length) { | ||
13493 | // clamp to the current seekable range | ||
13494 | time = time > seekable.start(0) ? time : seekable.start(0); | ||
13495 | time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1); | ||
13496 | |||
13497 | this.lastSeekTarget_ = time; | ||
13498 | this.trigger('seeking'); | ||
13499 | this.el_.vjs_setProperty('currentTime', time); | ||
13500 | _Tech.prototype.setCurrentTime.call(this); | ||
13501 | } | ||
13502 | }; | ||
13503 | |||
13504 | /** | ||
13505 | * Get current time | ||
13506 | * | ||
13507 | * @param {Number=} time Current time of video | ||
13508 | * @return {Number} Current time | ||
13509 | * @method currentTime | ||
13510 | */ | ||
13511 | |||
13512 | Flash.prototype.currentTime = function currentTime(time) { | ||
13513 | // when seeking make the reported time keep up with the requested time | ||
13514 | // by reading the time we're seeking to | ||
13515 | if (this.seeking()) { | ||
13516 | return this.lastSeekTarget_ || 0; | ||
13517 | } | ||
13518 | return this.el_.vjs_getProperty('currentTime'); | ||
13519 | }; | ||
13520 | |||
13521 | /** | ||
13522 | * Get current source | ||
13523 | * | ||
13524 | * @method currentSrc | ||
13525 | */ | ||
13526 | |||
13527 | Flash.prototype.currentSrc = function currentSrc() { | ||
13528 | if (this.currentSource_) { | ||
13529 | return this.currentSource_.src; | ||
13530 | } else { | ||
13531 | return this.el_.vjs_getProperty('currentSrc'); | ||
13532 | } | ||
13533 | }; | ||
13534 | |||
13535 | /** | ||
13536 | * Load media into player | ||
13537 | * | ||
13538 | * @method load | ||
13539 | */ | ||
13540 | |||
13541 | Flash.prototype.load = function load() { | ||
13542 | this.el_.vjs_load(); | ||
13543 | }; | ||
13544 | |||
13545 | /** | ||
13546 | * Get poster | ||
13547 | * | ||
13548 | * @method poster | ||
13549 | */ | ||
13550 | |||
13551 | Flash.prototype.poster = function poster() { | ||
13552 | this.el_.vjs_getProperty('poster'); | ||
13553 | }; | ||
13554 | |||
13555 | /** | ||
13556 | * Poster images are not handled by the Flash tech so make this a no-op | ||
13557 | * | ||
13558 | * @method setPoster | ||
13559 | */ | ||
13560 | |||
13561 | Flash.prototype.setPoster = function setPoster() {}; | ||
13562 | |||
13563 | /** | ||
13564 | * Determine if can seek in media | ||
13565 | * | ||
13566 | * @return {TimeRangeObject} | ||
13567 | * @method seekable | ||
13568 | */ | ||
13569 | |||
13570 | Flash.prototype.seekable = function seekable() { | ||
13571 | var duration = this.duration(); | ||
13572 | if (duration === 0) { | ||
13573 | return _utilsTimeRangesJs.createTimeRange(); | ||
13574 | } | ||
13575 | return _utilsTimeRangesJs.createTimeRange(0, duration); | ||
13576 | }; | ||
13577 | |||
13578 | /** | ||
13579 | * Get buffered time range | ||
13580 | * | ||
13581 | * @return {TimeRangeObject} | ||
13582 | * @method buffered | ||
13583 | */ | ||
13584 | |||
13585 | Flash.prototype.buffered = function buffered() { | ||
13586 | var ranges = this.el_.vjs_getProperty('buffered'); | ||
13587 | if (ranges.length === 0) { | ||
13588 | return _utilsTimeRangesJs.createTimeRange(); | ||
13589 | } | ||
13590 | return _utilsTimeRangesJs.createTimeRange(ranges[0][0], ranges[0][1]); | ||
13591 | }; | ||
13592 | |||
13593 | /** | ||
13594 | * Get fullscreen support - | ||
13595 | * Flash does not allow fullscreen through javascript | ||
13596 | * so always returns false | ||
13597 | * | ||
13598 | * @return {Boolean} false | ||
13599 | * @method supportsFullScreen | ||
13600 | */ | ||
13601 | |||
13602 | Flash.prototype.supportsFullScreen = function supportsFullScreen() { | ||
13603 | return false; // Flash does not allow fullscreen through javascript | ||
13604 | }; | ||
13605 | |||
13606 | /** | ||
13607 | * Request to enter fullscreen | ||
13608 | * Flash does not allow fullscreen through javascript | ||
13609 | * so always returns false | ||
13610 | * | ||
13611 | * @return {Boolean} false | ||
13612 | * @method enterFullScreen | ||
13613 | */ | ||
13614 | |||
13615 | Flash.prototype.enterFullScreen = function enterFullScreen() { | ||
13616 | return false; | ||
13617 | }; | ||
13618 | |||
13619 | return Flash; | ||
13620 | })(_tech2['default']); | ||
13621 | |||
13622 | var _api = Flash.prototype; | ||
13623 | var _readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(','); | ||
13624 | var _readOnly = 'networkState,readyState,initialTime,duration,startOffsetTime,paused,ended,videoTracks,audioTracks,videoWidth,videoHeight'.split(','); | ||
13625 | |||
13626 | function _createSetter(attr) { | ||
13627 | var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1); | ||
13628 | _api['set' + attrUpper] = function (val) { | ||
13629 | return this.el_.vjs_setProperty(attr, val); | ||
13630 | }; | ||
13631 | } | ||
13632 | function _createGetter(attr) { | ||
13633 | _api[attr] = function () { | ||
13634 | return this.el_.vjs_getProperty(attr); | ||
13635 | }; | ||
13636 | } | ||
13637 | |||
13638 | // Create getter and setters for all read/write attributes | ||
13639 | for (var i = 0; i < _readWrite.length; i++) { | ||
13640 | _createGetter(_readWrite[i]); | ||
13641 | _createSetter(_readWrite[i]); | ||
13642 | } | ||
13643 | |||
13644 | // Create getters for read-only attributes | ||
13645 | for (var i = 0; i < _readOnly.length; i++) { | ||
13646 | _createGetter(_readOnly[i]); | ||
13647 | } | ||
13648 | |||
13649 | /* Flash Support Testing -------------------------------------------------------- */ | ||
13650 | |||
13651 | Flash.isSupported = function () { | ||
13652 | return Flash.version()[0] >= 10; | ||
13653 | // return swfobject.hasFlashPlayerVersion('10'); | ||
13654 | }; | ||
13655 | |||
13656 | // Add Source Handler pattern functions to this tech | ||
13657 | _tech2['default'].withSourceHandlers(Flash); | ||
13658 | |||
13659 | /* | ||
13660 | * The default native source handler. | ||
13661 | * This simply passes the source to the video element. Nothing fancy. | ||
13662 | * | ||
13663 | * @param {Object} source The source object | ||
13664 | * @param {Flash} tech The instance of the Flash tech | ||
13665 | */ | ||
13666 | Flash.nativeSourceHandler = {}; | ||
13667 | |||
13668 | /** | ||
13669 | * Check if Flash can play the given videotype | ||
13670 | * @param {String} type The mimetype to check | ||
13671 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
13672 | */ | ||
13673 | Flash.nativeSourceHandler.canPlayType = function (type) { | ||
13674 | if (type in Flash.formats) { | ||
13675 | return 'maybe'; | ||
13676 | } | ||
13677 | |||
13678 | return ''; | ||
13679 | }; | ||
13680 | |||
13681 | /* | ||
13682 | * Check Flash can handle the source natively | ||
13683 | * | ||
13684 | * @param {Object} source The source object | ||
13685 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
13686 | */ | ||
13687 | Flash.nativeSourceHandler.canHandleSource = function (source) { | ||
13688 | var type; | ||
13689 | |||
13690 | function guessMimeType(src) { | ||
13691 | var ext = Url.getFileExtension(src); | ||
13692 | if (ext) { | ||
13693 | return 'video/' + ext; | ||
13694 | } | ||
13695 | return ''; | ||
13696 | } | ||
13697 | |||
13698 | if (!source.type) { | ||
13699 | type = guessMimeType(source.src); | ||
13700 | } else { | ||
13701 | // Strip code information from the type because we don't get that specific | ||
13702 | type = source.type.replace(/;.*/, '').toLowerCase(); | ||
13703 | } | ||
13704 | |||
13705 | return Flash.nativeSourceHandler.canPlayType(type); | ||
13706 | }; | ||
13707 | |||
13708 | /* | ||
13709 | * Pass the source to the flash object | ||
13710 | * Adaptive source handlers will have more complicated workflows before passing | ||
13711 | * video data to the video element | ||
13712 | * | ||
13713 | * @param {Object} source The source object | ||
13714 | * @param {Flash} tech The instance of the Flash tech | ||
13715 | */ | ||
13716 | Flash.nativeSourceHandler.handleSource = function (source, tech) { | ||
13717 | tech.setSrc(source.src); | ||
13718 | }; | ||
13719 | |||
13720 | /* | ||
13721 | * Clean up the source handler when disposing the player or switching sources.. | ||
13722 | * (no cleanup is needed when supporting the format natively) | ||
13723 | */ | ||
13724 | Flash.nativeSourceHandler.dispose = function () {}; | ||
13725 | |||
13726 | // Register the native source handler | ||
13727 | Flash.registerSourceHandler(Flash.nativeSourceHandler); | ||
13728 | |||
13729 | Flash.formats = { | ||
13730 | 'video/flv': 'FLV', | ||
13731 | 'video/x-flv': 'FLV', | ||
13732 | 'video/mp4': 'MP4', | ||
13733 | 'video/m4v': 'MP4' | ||
13734 | }; | ||
13735 | |||
13736 | Flash.onReady = function (currSwf) { | ||
13737 | var el = Dom.getEl(currSwf); | ||
13738 | var tech = el && el.tech; | ||
13739 | |||
13740 | // if there is no el then the tech has been disposed | ||
13741 | // and the tech element was removed from the player div | ||
13742 | if (tech && tech.el()) { | ||
13743 | // check that the flash object is really ready | ||
13744 | Flash.checkReady(tech); | ||
13745 | } | ||
13746 | }; | ||
13747 | |||
13748 | // The SWF isn't always ready when it says it is. Sometimes the API functions still need to be added to the object. | ||
13749 | // If it's not ready, we set a timeout to check again shortly. | ||
13750 | Flash.checkReady = function (tech) { | ||
13751 | // stop worrying if the tech has been disposed | ||
13752 | if (!tech.el()) { | ||
13753 | return; | ||
13754 | } | ||
13755 | |||
13756 | // check if API property exists | ||
13757 | if (tech.el().vjs_getProperty) { | ||
13758 | // tell tech it's ready | ||
13759 | tech.triggerReady(); | ||
13760 | } else { | ||
13761 | // wait longer | ||
13762 | this.setTimeout(function () { | ||
13763 | Flash['checkReady'](tech); | ||
13764 | }, 50); | ||
13765 | } | ||
13766 | }; | ||
13767 | |||
13768 | // Trigger events from the swf on the player | ||
13769 | Flash.onEvent = function (swfID, eventName) { | ||
13770 | var tech = Dom.getEl(swfID).tech; | ||
13771 | tech.trigger(eventName); | ||
13772 | }; | ||
13773 | |||
13774 | // Log errors from the swf | ||
13775 | Flash.onError = function (swfID, err) { | ||
13776 | var tech = Dom.getEl(swfID).tech; | ||
13777 | |||
13778 | // trigger MEDIA_ERR_SRC_NOT_SUPPORTED | ||
13779 | if (err === 'srcnotfound') { | ||
13780 | return tech.error(4); | ||
13781 | } | ||
13782 | |||
13783 | // trigger a custom error | ||
13784 | tech.error('FLASH: ' + err); | ||
13785 | }; | ||
13786 | |||
13787 | // Flash Version Check | ||
13788 | Flash.version = function () { | ||
13789 | var version = '0,0,0'; | ||
13790 | |||
13791 | // IE | ||
13792 | try { | ||
13793 | version = new _globalWindow2['default'].ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; | ||
13794 | |||
13795 | // other browsers | ||
13796 | } catch (e) { | ||
13797 | try { | ||
13798 | if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) { | ||
13799 | version = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; | ||
13800 | } | ||
13801 | } catch (err) {} | ||
13802 | } | ||
13803 | return version.split(','); | ||
13804 | }; | ||
13805 | |||
13806 | // Flash embedding method. Only used in non-iframe mode | ||
13807 | Flash.embed = function (swf, flashVars, params, attributes) { | ||
13808 | var code = Flash.getEmbedCode(swf, flashVars, params, attributes); | ||
13809 | |||
13810 | // Get element by embedding code and retrieving created element | ||
13811 | var obj = Dom.createEl('div', { innerHTML: code }).childNodes[0]; | ||
13812 | |||
13813 | return obj; | ||
13814 | }; | ||
13815 | |||
13816 | Flash.getEmbedCode = function (swf, flashVars, params, attributes) { | ||
13817 | var objTag = '<object type="application/x-shockwave-flash" '; | ||
13818 | var flashVarsString = ''; | ||
13819 | var paramsString = ''; | ||
13820 | var attrsString = ''; | ||
13821 | |||
13822 | // Convert flash vars to string | ||
13823 | if (flashVars) { | ||
13824 | Object.getOwnPropertyNames(flashVars).forEach(function (key) { | ||
13825 | flashVarsString += key + '=' + flashVars[key] + '&'; | ||
13826 | }); | ||
13827 | } | ||
13828 | |||
13829 | // Add swf, flashVars, and other default params | ||
13830 | params = _objectAssign2['default']({ | ||
13831 | 'movie': swf, | ||
13832 | 'flashvars': flashVarsString, | ||
13833 | 'allowScriptAccess': 'always', // Required to talk to swf | ||
13834 | 'allowNetworking': 'all' // All should be default, but having security issues. | ||
13835 | }, params); | ||
13836 | |||
13837 | // Create param tags string | ||
13838 | Object.getOwnPropertyNames(params).forEach(function (key) { | ||
13839 | paramsString += '<param name="' + key + '" value="' + params[key] + '" />'; | ||
13840 | }); | ||
13841 | |||
13842 | attributes = _objectAssign2['default']({ | ||
13843 | // Add swf to attributes (need both for IE and Others to work) | ||
13844 | 'data': swf, | ||
13845 | |||
13846 | // Default to 100% width/height | ||
13847 | 'width': '100%', | ||
13848 | 'height': '100%' | ||
13849 | |||
13850 | }, attributes); | ||
13851 | |||
13852 | // Create Attributes string | ||
13853 | Object.getOwnPropertyNames(attributes).forEach(function (key) { | ||
13854 | attrsString += key + '="' + attributes[key] + '" '; | ||
13855 | }); | ||
13856 | |||
13857 | return '' + objTag + attrsString + '>' + paramsString + '</object>'; | ||
13858 | }; | ||
13859 | |||
13860 | // Run Flash through the RTMP decorator | ||
13861 | _flashRtmp2['default'](Flash); | ||
13862 | |||
13863 | _component2['default'].registerComponent('Flash', Flash); | ||
13864 | _tech2['default'].registerTech('Flash', Flash); | ||
13865 | exports['default'] = Flash; | ||
13866 | module.exports = exports['default']; | ||
13867 | |||
13868 | },{"../component":67,"../utils/dom.js":132,"../utils/time-ranges.js":140,"../utils/url.js":142,"./flash-rtmp":115,"./tech":119,"global/window":2,"object.assign":45}],117:[function(_dereq_,module,exports){ | ||
13869 | /** | ||
13870 | * @file html5.js | ||
13871 | * HTML5 Media Controller - Wrapper for HTML5 Media API | ||
13872 | */ | ||
13873 | |||
13874 | 'use strict'; | ||
13875 | |||
13876 | exports.__esModule = true; | ||
13877 | |||
13878 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
13879 | |||
13880 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
13881 | |||
13882 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
13883 | |||
13884 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
13885 | |||
13886 | var _techJs = _dereq_('./tech.js'); | ||
13887 | |||
13888 | var _techJs2 = _interopRequireDefault(_techJs); | ||
13889 | |||
13890 | var _component = _dereq_('../component'); | ||
13891 | |||
13892 | var _component2 = _interopRequireDefault(_component); | ||
13893 | |||
13894 | var _utilsDomJs = _dereq_('../utils/dom.js'); | ||
13895 | |||
13896 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
13897 | |||
13898 | var _utilsUrlJs = _dereq_('../utils/url.js'); | ||
13899 | |||
13900 | var Url = _interopRequireWildcard(_utilsUrlJs); | ||
13901 | |||
13902 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
13903 | |||
13904 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
13905 | |||
13906 | var _utilsLogJs = _dereq_('../utils/log.js'); | ||
13907 | |||
13908 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
13909 | |||
13910 | var _utilsBrowserJs = _dereq_('../utils/browser.js'); | ||
13911 | |||
13912 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
13913 | |||
13914 | var _globalDocument = _dereq_('global/document'); | ||
13915 | |||
13916 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
13917 | |||
13918 | var _globalWindow = _dereq_('global/window'); | ||
13919 | |||
13920 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
13921 | |||
13922 | var _objectAssign = _dereq_('object.assign'); | ||
13923 | |||
13924 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
13925 | |||
13926 | var _utilsMergeOptionsJs = _dereq_('../utils/merge-options.js'); | ||
13927 | |||
13928 | var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); | ||
13929 | |||
13930 | /** | ||
13931 | * HTML5 Media Controller - Wrapper for HTML5 Media API | ||
13932 | * | ||
13933 | * @param {Object=} options Object of option names and values | ||
13934 | * @param {Function=} ready Ready callback function | ||
13935 | * @extends Tech | ||
13936 | * @class Html5 | ||
13937 | */ | ||
13938 | |||
13939 | var Html5 = (function (_Tech) { | ||
13940 | _inherits(Html5, _Tech); | ||
13941 | |||
13942 | function Html5(options, ready) { | ||
13943 | _classCallCheck(this, Html5); | ||
13944 | |||
13945 | _Tech.call(this, options, ready); | ||
13946 | |||
13947 | var source = options.source; | ||
13948 | |||
13949 | // Set the source if one is provided | ||
13950 | // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted) | ||
13951 | // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source | ||
13952 | // anyway so the error gets fired. | ||
13953 | if (source && (this.el_.currentSrc !== source.src || options.tag && options.tag.initNetworkState_ === 3)) { | ||
13954 | this.setSource(source); | ||
13955 | } else { | ||
13956 | this.handleLateInit_(this.el_); | ||
13957 | } | ||
13958 | |||
13959 | if (this.el_.hasChildNodes()) { | ||
13960 | |||
13961 | var nodes = this.el_.childNodes; | ||
13962 | var nodesLength = nodes.length; | ||
13963 | var removeNodes = []; | ||
13964 | |||
13965 | while (nodesLength--) { | ||
13966 | var node = nodes[nodesLength]; | ||
13967 | var nodeName = node.nodeName.toLowerCase(); | ||
13968 | |||
13969 | if (nodeName === 'track') { | ||
13970 | if (!this.featuresNativeTextTracks) { | ||
13971 | // Empty video tag tracks so the built-in player doesn't use them also. | ||
13972 | // This may not be fast enough to stop HTML5 browsers from reading the tags | ||
13973 | // so we'll need to turn off any default tracks if we're manually doing | ||
13974 | // captions and subtitles. videoElement.textTracks | ||
13975 | removeNodes.push(node); | ||
13976 | } else { | ||
13977 | // store HTMLTrackElement and TextTrack to remote list | ||
13978 | this.remoteTextTrackEls().addTrackElement_(node); | ||
13979 | this.remoteTextTracks().addTrack_(node.track); | ||
13980 | } | ||
13981 | } | ||
13982 | } | ||
13983 | |||
13984 | for (var i = 0; i < removeNodes.length; i++) { | ||
13985 | this.el_.removeChild(removeNodes[i]); | ||
13986 | } | ||
13987 | } | ||
13988 | |||
13989 | if (this.featuresNativeTextTracks) { | ||
13990 | this.handleTextTrackChange_ = Fn.bind(this, this.handleTextTrackChange); | ||
13991 | this.handleTextTrackAdd_ = Fn.bind(this, this.handleTextTrackAdd); | ||
13992 | this.handleTextTrackRemove_ = Fn.bind(this, this.handleTextTrackRemove); | ||
13993 | this.proxyNativeTextTracks_(); | ||
13994 | } | ||
13995 | |||
13996 | // Determine if native controls should be used | ||
13997 | // Our goal should be to get the custom controls on mobile solid everywhere | ||
13998 | // so we can remove this all together. Right now this will block custom | ||
13999 | // controls on touch enabled laptops like the Chrome Pixel | ||
14000 | if (browser.TOUCH_ENABLED && options.nativeControlsForTouch === true || browser.IS_IPHONE || browser.IS_NATIVE_ANDROID) { | ||
14001 | this.setControls(true); | ||
14002 | } | ||
14003 | |||
14004 | this.triggerReady(); | ||
14005 | } | ||
14006 | |||
14007 | /* HTML5 Support Testing ---------------------------------------------------- */ | ||
14008 | |||
14009 | /* | ||
14010 | * Element for testing browser HTML5 video capabilities | ||
14011 | * | ||
14012 | * @type {Element} | ||
14013 | * @constant | ||
14014 | * @private | ||
14015 | */ | ||
14016 | |||
14017 | /** | ||
14018 | * Dispose of html5 media element | ||
14019 | * | ||
14020 | * @method dispose | ||
14021 | */ | ||
14022 | |||
14023 | Html5.prototype.dispose = function dispose() { | ||
14024 | var tt = this.el().textTracks; | ||
14025 | var emulatedTt = this.textTracks(); | ||
14026 | |||
14027 | // remove native event listeners | ||
14028 | if (tt && tt.removeEventListener) { | ||
14029 | tt.removeEventListener('change', this.handleTextTrackChange_); | ||
14030 | tt.removeEventListener('addtrack', this.handleTextTrackAdd_); | ||
14031 | tt.removeEventListener('removetrack', this.handleTextTrackRemove_); | ||
14032 | } | ||
14033 | |||
14034 | // clearout the emulated text track list. | ||
14035 | var i = emulatedTt.length; | ||
14036 | |||
14037 | while (i--) { | ||
14038 | emulatedTt.removeTrack_(emulatedTt[i]); | ||
14039 | } | ||
14040 | |||
14041 | Html5.disposeMediaElement(this.el_); | ||
14042 | _Tech.prototype.dispose.call(this); | ||
14043 | }; | ||
14044 | |||
14045 | /** | ||
14046 | * Create the component's DOM element | ||
14047 | * | ||
14048 | * @return {Element} | ||
14049 | * @method createEl | ||
14050 | */ | ||
14051 | |||
14052 | Html5.prototype.createEl = function createEl() { | ||
14053 | var el = this.options_.tag; | ||
14054 | |||
14055 | // Check if this browser supports moving the element into the box. | ||
14056 | // On the iPhone video will break if you move the element, | ||
14057 | // So we have to create a brand new element. | ||
14058 | if (!el || this['movingMediaElementInDOM'] === false) { | ||
14059 | |||
14060 | // If the original tag is still there, clone and remove it. | ||
14061 | if (el) { | ||
14062 | var clone = el.cloneNode(true); | ||
14063 | el.parentNode.insertBefore(clone, el); | ||
14064 | Html5.disposeMediaElement(el); | ||
14065 | el = clone; | ||
14066 | } else { | ||
14067 | el = _globalDocument2['default'].createElement('video'); | ||
14068 | |||
14069 | // determine if native controls should be used | ||
14070 | var tagAttributes = this.options_.tag && Dom.getElAttributes(this.options_.tag); | ||
14071 | var attributes = _utilsMergeOptionsJs2['default']({}, tagAttributes); | ||
14072 | if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) { | ||
14073 | delete attributes.controls; | ||
14074 | } | ||
14075 | |||
14076 | Dom.setElAttributes(el, _objectAssign2['default'](attributes, { | ||
14077 | id: this.options_.techId, | ||
14078 | 'class': 'vjs-tech' | ||
14079 | })); | ||
14080 | } | ||
14081 | } | ||
14082 | |||
14083 | // Update specific tag settings, in case they were overridden | ||
14084 | var settingsAttrs = ['autoplay', 'preload', 'loop', 'muted']; | ||
14085 | for (var i = settingsAttrs.length - 1; i >= 0; i--) { | ||
14086 | var attr = settingsAttrs[i]; | ||
14087 | var overwriteAttrs = {}; | ||
14088 | if (typeof this.options_[attr] !== 'undefined') { | ||
14089 | overwriteAttrs[attr] = this.options_[attr]; | ||
14090 | } | ||
14091 | Dom.setElAttributes(el, overwriteAttrs); | ||
14092 | } | ||
14093 | |||
14094 | return el; | ||
14095 | // jenniisawesome = true; | ||
14096 | }; | ||
14097 | |||
14098 | // If we're loading the playback object after it has started loading | ||
14099 | // or playing the video (often with autoplay on) then the loadstart event | ||
14100 | // has already fired and we need to fire it manually because many things | ||
14101 | // rely on it. | ||
14102 | |||
14103 | Html5.prototype.handleLateInit_ = function handleLateInit_(el) { | ||
14104 | var _this = this; | ||
14105 | |||
14106 | if (el.networkState === 0 || el.networkState === 3) { | ||
14107 | // The video element hasn't started loading the source yet | ||
14108 | // or didn't find a source | ||
14109 | return; | ||
14110 | } | ||
14111 | |||
14112 | if (el.readyState === 0) { | ||
14113 | var _ret = (function () { | ||
14114 | // NetworkState is set synchronously BUT loadstart is fired at the | ||
14115 | // end of the current stack, usually before setInterval(fn, 0). | ||
14116 | // So at this point we know loadstart may have already fired or is | ||
14117 | // about to fire, and either way the player hasn't seen it yet. | ||
14118 | // We don't want to fire loadstart prematurely here and cause a | ||
14119 | // double loadstart so we'll wait and see if it happens between now | ||
14120 | // and the next loop, and fire it if not. | ||
14121 | // HOWEVER, we also want to make sure it fires before loadedmetadata | ||
14122 | // which could also happen between now and the next loop, so we'll | ||
14123 | // watch for that also. | ||
14124 | var loadstartFired = false; | ||
14125 | var setLoadstartFired = function setLoadstartFired() { | ||
14126 | loadstartFired = true; | ||
14127 | }; | ||
14128 | _this.on('loadstart', setLoadstartFired); | ||
14129 | |||
14130 | var triggerLoadstart = function triggerLoadstart() { | ||
14131 | // We did miss the original loadstart. Make sure the player | ||
14132 | // sees loadstart before loadedmetadata | ||
14133 | if (!loadstartFired) { | ||
14134 | this.trigger('loadstart'); | ||
14135 | } | ||
14136 | }; | ||
14137 | _this.on('loadedmetadata', triggerLoadstart); | ||
14138 | |||
14139 | _this.ready(function () { | ||
14140 | this.off('loadstart', setLoadstartFired); | ||
14141 | this.off('loadedmetadata', triggerLoadstart); | ||
14142 | |||
14143 | if (!loadstartFired) { | ||
14144 | // We did miss the original native loadstart. Fire it now. | ||
14145 | this.trigger('loadstart'); | ||
14146 | } | ||
14147 | }); | ||
14148 | |||
14149 | return { | ||
14150 | v: undefined | ||
14151 | }; | ||
14152 | })(); | ||
14153 | |||
14154 | if (typeof _ret === 'object') return _ret.v; | ||
14155 | } | ||
14156 | |||
14157 | // From here on we know that loadstart already fired and we missed it. | ||
14158 | // The other readyState events aren't as much of a problem if we double | ||
14159 | // them, so not going to go to as much trouble as loadstart to prevent | ||
14160 | // that unless we find reason to. | ||
14161 | var eventsToTrigger = ['loadstart']; | ||
14162 | |||
14163 | // loadedmetadata: newly equal to HAVE_METADATA (1) or greater | ||
14164 | eventsToTrigger.push('loadedmetadata'); | ||
14165 | |||
14166 | // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater | ||
14167 | if (el.readyState >= 2) { | ||
14168 | eventsToTrigger.push('loadeddata'); | ||
14169 | } | ||
14170 | |||
14171 | // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater | ||
14172 | if (el.readyState >= 3) { | ||
14173 | eventsToTrigger.push('canplay'); | ||
14174 | } | ||
14175 | |||
14176 | // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4) | ||
14177 | if (el.readyState >= 4) { | ||
14178 | eventsToTrigger.push('canplaythrough'); | ||
14179 | } | ||
14180 | |||
14181 | // We still need to give the player time to add event listeners | ||
14182 | this.ready(function () { | ||
14183 | eventsToTrigger.forEach(function (type) { | ||
14184 | this.trigger(type); | ||
14185 | }, this); | ||
14186 | }); | ||
14187 | }; | ||
14188 | |||
14189 | Html5.prototype.proxyNativeTextTracks_ = function proxyNativeTextTracks_() { | ||
14190 | var tt = this.el().textTracks; | ||
14191 | |||
14192 | if (tt) { | ||
14193 | // Add tracks - if player is initialised after DOM loaded, textTracks | ||
14194 | // will not trigger addtrack | ||
14195 | for (var i = 0; i < tt.length; i++) { | ||
14196 | this.textTracks().addTrack_(tt[i]); | ||
14197 | } | ||
14198 | |||
14199 | if (tt.addEventListener) { | ||
14200 | tt.addEventListener('change', this.handleTextTrackChange_); | ||
14201 | tt.addEventListener('addtrack', this.handleTextTrackAdd_); | ||
14202 | tt.addEventListener('removetrack', this.handleTextTrackRemove_); | ||
14203 | } | ||
14204 | } | ||
14205 | }; | ||
14206 | |||
14207 | Html5.prototype.handleTextTrackChange = function handleTextTrackChange(e) { | ||
14208 | var tt = this.textTracks(); | ||
14209 | this.textTracks().trigger({ | ||
14210 | type: 'change', | ||
14211 | target: tt, | ||
14212 | currentTarget: tt, | ||
14213 | srcElement: tt | ||
14214 | }); | ||
14215 | }; | ||
14216 | |||
14217 | Html5.prototype.handleTextTrackAdd = function handleTextTrackAdd(e) { | ||
14218 | this.textTracks().addTrack_(e.track); | ||
14219 | }; | ||
14220 | |||
14221 | Html5.prototype.handleTextTrackRemove = function handleTextTrackRemove(e) { | ||
14222 | this.textTracks().removeTrack_(e.track); | ||
14223 | }; | ||
14224 | |||
14225 | /** | ||
14226 | * Play for html5 tech | ||
14227 | * | ||
14228 | * @method play | ||
14229 | */ | ||
14230 | |||
14231 | Html5.prototype.play = function play() { | ||
14232 | this.el_.play(); | ||
14233 | }; | ||
14234 | |||
14235 | /** | ||
14236 | * Pause for html5 tech | ||
14237 | * | ||
14238 | * @method pause | ||
14239 | */ | ||
14240 | |||
14241 | Html5.prototype.pause = function pause() { | ||
14242 | this.el_.pause(); | ||
14243 | }; | ||
14244 | |||
14245 | /** | ||
14246 | * Paused for html5 tech | ||
14247 | * | ||
14248 | * @return {Boolean} | ||
14249 | * @method paused | ||
14250 | */ | ||
14251 | |||
14252 | Html5.prototype.paused = function paused() { | ||
14253 | return this.el_.paused; | ||
14254 | }; | ||
14255 | |||
14256 | /** | ||
14257 | * Get current time | ||
14258 | * | ||
14259 | * @return {Number} | ||
14260 | * @method currentTime | ||
14261 | */ | ||
14262 | |||
14263 | Html5.prototype.currentTime = function currentTime() { | ||
14264 | return this.el_.currentTime; | ||
14265 | }; | ||
14266 | |||
14267 | /** | ||
14268 | * Set current time | ||
14269 | * | ||
14270 | * @param {Number} seconds Current time of video | ||
14271 | * @method setCurrentTime | ||
14272 | */ | ||
14273 | |||
14274 | Html5.prototype.setCurrentTime = function setCurrentTime(seconds) { | ||
14275 | try { | ||
14276 | this.el_.currentTime = seconds; | ||
14277 | } catch (e) { | ||
14278 | _utilsLogJs2['default'](e, 'Video is not ready. (Video.js)'); | ||
14279 | // this.warning(VideoJS.warnings.videoNotReady); | ||
14280 | } | ||
14281 | }; | ||
14282 | |||
14283 | /** | ||
14284 | * Get duration | ||
14285 | * | ||
14286 | * @return {Number} | ||
14287 | * @method duration | ||
14288 | */ | ||
14289 | |||
14290 | Html5.prototype.duration = function duration() { | ||
14291 | return this.el_.duration || 0; | ||
14292 | }; | ||
14293 | |||
14294 | /** | ||
14295 | * Get a TimeRange object that represents the intersection | ||
14296 | * of the time ranges for which the user agent has all | ||
14297 | * relevant media | ||
14298 | * | ||
14299 | * @return {TimeRangeObject} | ||
14300 | * @method buffered | ||
14301 | */ | ||
14302 | |||
14303 | Html5.prototype.buffered = function buffered() { | ||
14304 | return this.el_.buffered; | ||
14305 | }; | ||
14306 | |||
14307 | /** | ||
14308 | * Get volume level | ||
14309 | * | ||
14310 | * @return {Number} | ||
14311 | * @method volume | ||
14312 | */ | ||
14313 | |||
14314 | Html5.prototype.volume = function volume() { | ||
14315 | return this.el_.volume; | ||
14316 | }; | ||
14317 | |||
14318 | /** | ||
14319 | * Set volume level | ||
14320 | * | ||
14321 | * @param {Number} percentAsDecimal Volume percent as a decimal | ||
14322 | * @method setVolume | ||
14323 | */ | ||
14324 | |||
14325 | Html5.prototype.setVolume = function setVolume(percentAsDecimal) { | ||
14326 | this.el_.volume = percentAsDecimal; | ||
14327 | }; | ||
14328 | |||
14329 | /** | ||
14330 | * Get if muted | ||
14331 | * | ||
14332 | * @return {Boolean} | ||
14333 | * @method muted | ||
14334 | */ | ||
14335 | |||
14336 | Html5.prototype.muted = function muted() { | ||
14337 | return this.el_.muted; | ||
14338 | }; | ||
14339 | |||
14340 | /** | ||
14341 | * Set muted | ||
14342 | * | ||
14343 | * @param {Boolean} If player is to be muted or note | ||
14344 | * @method setMuted | ||
14345 | */ | ||
14346 | |||
14347 | Html5.prototype.setMuted = function setMuted(muted) { | ||
14348 | this.el_.muted = muted; | ||
14349 | }; | ||
14350 | |||
14351 | /** | ||
14352 | * Get player width | ||
14353 | * | ||
14354 | * @return {Number} | ||
14355 | * @method width | ||
14356 | */ | ||
14357 | |||
14358 | Html5.prototype.width = function width() { | ||
14359 | return this.el_.offsetWidth; | ||
14360 | }; | ||
14361 | |||
14362 | /** | ||
14363 | * Get player height | ||
14364 | * | ||
14365 | * @return {Number} | ||
14366 | * @method height | ||
14367 | */ | ||
14368 | |||
14369 | Html5.prototype.height = function height() { | ||
14370 | return this.el_.offsetHeight; | ||
14371 | }; | ||
14372 | |||
14373 | /** | ||
14374 | * Get if there is fullscreen support | ||
14375 | * | ||
14376 | * @return {Boolean} | ||
14377 | * @method supportsFullScreen | ||
14378 | */ | ||
14379 | |||
14380 | Html5.prototype.supportsFullScreen = function supportsFullScreen() { | ||
14381 | if (typeof this.el_.webkitEnterFullScreen === 'function') { | ||
14382 | var userAgent = _globalWindow2['default'].navigator.userAgent; | ||
14383 | // Seems to be broken in Chromium/Chrome && Safari in Leopard | ||
14384 | if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) { | ||
14385 | return true; | ||
14386 | } | ||
14387 | } | ||
14388 | return false; | ||
14389 | }; | ||
14390 | |||
14391 | /** | ||
14392 | * Request to enter fullscreen | ||
14393 | * | ||
14394 | * @method enterFullScreen | ||
14395 | */ | ||
14396 | |||
14397 | Html5.prototype.enterFullScreen = function enterFullScreen() { | ||
14398 | var video = this.el_; | ||
14399 | |||
14400 | if ('webkitDisplayingFullscreen' in video) { | ||
14401 | this.one('webkitbeginfullscreen', function () { | ||
14402 | this.one('webkitendfullscreen', function () { | ||
14403 | this.trigger('fullscreenchange', { isFullscreen: false }); | ||
14404 | }); | ||
14405 | |||
14406 | this.trigger('fullscreenchange', { isFullscreen: true }); | ||
14407 | }); | ||
14408 | } | ||
14409 | |||
14410 | if (video.paused && video.networkState <= video.HAVE_METADATA) { | ||
14411 | // attempt to prime the video element for programmatic access | ||
14412 | // this isn't necessary on the desktop but shouldn't hurt | ||
14413 | this.el_.play(); | ||
14414 | |||
14415 | // playing and pausing synchronously during the transition to fullscreen | ||
14416 | // can get iOS ~6.1 devices into a play/pause loop | ||
14417 | this.setTimeout(function () { | ||
14418 | video.pause(); | ||
14419 | video.webkitEnterFullScreen(); | ||
14420 | }, 0); | ||
14421 | } else { | ||
14422 | video.webkitEnterFullScreen(); | ||
14423 | } | ||
14424 | }; | ||
14425 | |||
14426 | /** | ||
14427 | * Request to exit fullscreen | ||
14428 | * | ||
14429 | * @method exitFullScreen | ||
14430 | */ | ||
14431 | |||
14432 | Html5.prototype.exitFullScreen = function exitFullScreen() { | ||
14433 | this.el_.webkitExitFullScreen(); | ||
14434 | }; | ||
14435 | |||
14436 | /** | ||
14437 | * Get/set video | ||
14438 | * | ||
14439 | * @param {Object=} src Source object | ||
14440 | * @return {Object} | ||
14441 | * @method src | ||
14442 | */ | ||
14443 | |||
14444 | Html5.prototype.src = function src(_src) { | ||
14445 | if (_src === undefined) { | ||
14446 | return this.el_.src; | ||
14447 | } else { | ||
14448 | // Setting src through `src` instead of `setSrc` will be deprecated | ||
14449 | this.setSrc(_src); | ||
14450 | } | ||
14451 | }; | ||
14452 | |||
14453 | /** | ||
14454 | * Set video | ||
14455 | * | ||
14456 | * @param {Object} src Source object | ||
14457 | * @deprecated | ||
14458 | * @method setSrc | ||
14459 | */ | ||
14460 | |||
14461 | Html5.prototype.setSrc = function setSrc(src) { | ||
14462 | this.el_.src = src; | ||
14463 | }; | ||
14464 | |||
14465 | /** | ||
14466 | * Load media into player | ||
14467 | * | ||
14468 | * @method load | ||
14469 | */ | ||
14470 | |||
14471 | Html5.prototype.load = function load() { | ||
14472 | this.el_.load(); | ||
14473 | }; | ||
14474 | |||
14475 | /** | ||
14476 | * Reset the tech. Removes all sources and calls `load`. | ||
14477 | * | ||
14478 | * @method reset | ||
14479 | */ | ||
14480 | |||
14481 | Html5.prototype.reset = function reset() { | ||
14482 | Html5.resetMediaElement(this.el_); | ||
14483 | }; | ||
14484 | |||
14485 | /** | ||
14486 | * Get current source | ||
14487 | * | ||
14488 | * @return {Object} | ||
14489 | * @method currentSrc | ||
14490 | */ | ||
14491 | |||
14492 | Html5.prototype.currentSrc = function currentSrc() { | ||
14493 | if (this.currentSource_) { | ||
14494 | return this.currentSource_.src; | ||
14495 | } else { | ||
14496 | return this.el_.currentSrc; | ||
14497 | } | ||
14498 | }; | ||
14499 | |||
14500 | /** | ||
14501 | * Get poster | ||
14502 | * | ||
14503 | * @return {String} | ||
14504 | * @method poster | ||
14505 | */ | ||
14506 | |||
14507 | Html5.prototype.poster = function poster() { | ||
14508 | return this.el_.poster; | ||
14509 | }; | ||
14510 | |||
14511 | /** | ||
14512 | * Set poster | ||
14513 | * | ||
14514 | * @param {String} val URL to poster image | ||
14515 | * @method | ||
14516 | */ | ||
14517 | |||
14518 | Html5.prototype.setPoster = function setPoster(val) { | ||
14519 | this.el_.poster = val; | ||
14520 | }; | ||
14521 | |||
14522 | /** | ||
14523 | * Get preload attribute | ||
14524 | * | ||
14525 | * @return {String} | ||
14526 | * @method preload | ||
14527 | */ | ||
14528 | |||
14529 | Html5.prototype.preload = function preload() { | ||
14530 | return this.el_.preload; | ||
14531 | }; | ||
14532 | |||
14533 | /** | ||
14534 | * Set preload attribute | ||
14535 | * | ||
14536 | * @param {String} val Value for preload attribute | ||
14537 | * @method setPreload | ||
14538 | */ | ||
14539 | |||
14540 | Html5.prototype.setPreload = function setPreload(val) { | ||
14541 | this.el_.preload = val; | ||
14542 | }; | ||
14543 | |||
14544 | /** | ||
14545 | * Get autoplay attribute | ||
14546 | * | ||
14547 | * @return {String} | ||
14548 | * @method autoplay | ||
14549 | */ | ||
14550 | |||
14551 | Html5.prototype.autoplay = function autoplay() { | ||
14552 | return this.el_.autoplay; | ||
14553 | }; | ||
14554 | |||
14555 | /** | ||
14556 | * Set autoplay attribute | ||
14557 | * | ||
14558 | * @param {String} val Value for preload attribute | ||
14559 | * @method setAutoplay | ||
14560 | */ | ||
14561 | |||
14562 | Html5.prototype.setAutoplay = function setAutoplay(val) { | ||
14563 | this.el_.autoplay = val; | ||
14564 | }; | ||
14565 | |||
14566 | /** | ||
14567 | * Get controls attribute | ||
14568 | * | ||
14569 | * @return {String} | ||
14570 | * @method controls | ||
14571 | */ | ||
14572 | |||
14573 | Html5.prototype.controls = function controls() { | ||
14574 | return this.el_.controls; | ||
14575 | }; | ||
14576 | |||
14577 | /** | ||
14578 | * Set controls attribute | ||
14579 | * | ||
14580 | * @param {String} val Value for controls attribute | ||
14581 | * @method setControls | ||
14582 | */ | ||
14583 | |||
14584 | Html5.prototype.setControls = function setControls(val) { | ||
14585 | this.el_.controls = !!val; | ||
14586 | }; | ||
14587 | |||
14588 | /** | ||
14589 | * Get loop attribute | ||
14590 | * | ||
14591 | * @return {String} | ||
14592 | * @method loop | ||
14593 | */ | ||
14594 | |||
14595 | Html5.prototype.loop = function loop() { | ||
14596 | return this.el_.loop; | ||
14597 | }; | ||
14598 | |||
14599 | /** | ||
14600 | * Set loop attribute | ||
14601 | * | ||
14602 | * @param {String} val Value for loop attribute | ||
14603 | * @method setLoop | ||
14604 | */ | ||
14605 | |||
14606 | Html5.prototype.setLoop = function setLoop(val) { | ||
14607 | this.el_.loop = val; | ||
14608 | }; | ||
14609 | |||
14610 | /** | ||
14611 | * Get error value | ||
14612 | * | ||
14613 | * @return {String} | ||
14614 | * @method error | ||
14615 | */ | ||
14616 | |||
14617 | Html5.prototype.error = function error() { | ||
14618 | return this.el_.error; | ||
14619 | }; | ||
14620 | |||
14621 | /** | ||
14622 | * Get whether or not the player is in the "seeking" state | ||
14623 | * | ||
14624 | * @return {Boolean} | ||
14625 | * @method seeking | ||
14626 | */ | ||
14627 | |||
14628 | Html5.prototype.seeking = function seeking() { | ||
14629 | return this.el_.seeking; | ||
14630 | }; | ||
14631 | |||
14632 | /** | ||
14633 | * Get a TimeRanges object that represents the | ||
14634 | * ranges of the media resource to which it is possible | ||
14635 | * for the user agent to seek. | ||
14636 | * | ||
14637 | * @return {TimeRangeObject} | ||
14638 | * @method seekable | ||
14639 | */ | ||
14640 | |||
14641 | Html5.prototype.seekable = function seekable() { | ||
14642 | return this.el_.seekable; | ||
14643 | }; | ||
14644 | |||
14645 | /** | ||
14646 | * Get if video ended | ||
14647 | * | ||
14648 | * @return {Boolean} | ||
14649 | * @method ended | ||
14650 | */ | ||
14651 | |||
14652 | Html5.prototype.ended = function ended() { | ||
14653 | return this.el_.ended; | ||
14654 | }; | ||
14655 | |||
14656 | /** | ||
14657 | * Get the value of the muted content attribute | ||
14658 | * This attribute has no dynamic effect, it only | ||
14659 | * controls the default state of the element | ||
14660 | * | ||
14661 | * @return {Boolean} | ||
14662 | * @method defaultMuted | ||
14663 | */ | ||
14664 | |||
14665 | Html5.prototype.defaultMuted = function defaultMuted() { | ||
14666 | return this.el_.defaultMuted; | ||
14667 | }; | ||
14668 | |||
14669 | /** | ||
14670 | * Get desired speed at which the media resource is to play | ||
14671 | * | ||
14672 | * @return {Number} | ||
14673 | * @method playbackRate | ||
14674 | */ | ||
14675 | |||
14676 | Html5.prototype.playbackRate = function playbackRate() { | ||
14677 | return this.el_.playbackRate; | ||
14678 | }; | ||
14679 | |||
14680 | /** | ||
14681 | * Returns a TimeRanges object that represents the ranges of the | ||
14682 | * media resource that the user agent has played. | ||
14683 | * @return {TimeRangeObject} the range of points on the media | ||
14684 | * timeline that has been reached through normal playback | ||
14685 | * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-played | ||
14686 | */ | ||
14687 | |||
14688 | Html5.prototype.played = function played() { | ||
14689 | return this.el_.played; | ||
14690 | }; | ||
14691 | |||
14692 | /** | ||
14693 | * Set desired speed at which the media resource is to play | ||
14694 | * | ||
14695 | * @param {Number} val Speed at which the media resource is to play | ||
14696 | * @method setPlaybackRate | ||
14697 | */ | ||
14698 | |||
14699 | Html5.prototype.setPlaybackRate = function setPlaybackRate(val) { | ||
14700 | this.el_.playbackRate = val; | ||
14701 | }; | ||
14702 | |||
14703 | /** | ||
14704 | * Get the current state of network activity for the element, from | ||
14705 | * the list below | ||
14706 | * NETWORK_EMPTY (numeric value 0) | ||
14707 | * NETWORK_IDLE (numeric value 1) | ||
14708 | * NETWORK_LOADING (numeric value 2) | ||
14709 | * NETWORK_NO_SOURCE (numeric value 3) | ||
14710 | * | ||
14711 | * @return {Number} | ||
14712 | * @method networkState | ||
14713 | */ | ||
14714 | |||
14715 | Html5.prototype.networkState = function networkState() { | ||
14716 | return this.el_.networkState; | ||
14717 | }; | ||
14718 | |||
14719 | /** | ||
14720 | * Get a value that expresses the current state of the element | ||
14721 | * with respect to rendering the current playback position, from | ||
14722 | * the codes in the list below | ||
14723 | * HAVE_NOTHING (numeric value 0) | ||
14724 | * HAVE_METADATA (numeric value 1) | ||
14725 | * HAVE_CURRENT_DATA (numeric value 2) | ||
14726 | * HAVE_FUTURE_DATA (numeric value 3) | ||
14727 | * HAVE_ENOUGH_DATA (numeric value 4) | ||
14728 | * | ||
14729 | * @return {Number} | ||
14730 | * @method readyState | ||
14731 | */ | ||
14732 | |||
14733 | Html5.prototype.readyState = function readyState() { | ||
14734 | return this.el_.readyState; | ||
14735 | }; | ||
14736 | |||
14737 | /** | ||
14738 | * Get width of video | ||
14739 | * | ||
14740 | * @return {Number} | ||
14741 | * @method videoWidth | ||
14742 | */ | ||
14743 | |||
14744 | Html5.prototype.videoWidth = function videoWidth() { | ||
14745 | return this.el_.videoWidth; | ||
14746 | }; | ||
14747 | |||
14748 | /** | ||
14749 | * Get height of video | ||
14750 | * | ||
14751 | * @return {Number} | ||
14752 | * @method videoHeight | ||
14753 | */ | ||
14754 | |||
14755 | Html5.prototype.videoHeight = function videoHeight() { | ||
14756 | return this.el_.videoHeight; | ||
14757 | }; | ||
14758 | |||
14759 | /** | ||
14760 | * Get text tracks | ||
14761 | * | ||
14762 | * @return {TextTrackList} | ||
14763 | * @method textTracks | ||
14764 | */ | ||
14765 | |||
14766 | Html5.prototype.textTracks = function textTracks() { | ||
14767 | return _Tech.prototype.textTracks.call(this); | ||
14768 | }; | ||
14769 | |||
14770 | /** | ||
14771 | * Creates and returns a text track object | ||
14772 | * | ||
14773 | * @param {String} kind Text track kind (subtitles, captions, descriptions | ||
14774 | * chapters and metadata) | ||
14775 | * @param {String=} label Label to identify the text track | ||
14776 | * @param {String=} language Two letter language abbreviation | ||
14777 | * @return {TextTrackObject} | ||
14778 | * @method addTextTrack | ||
14779 | */ | ||
14780 | |||
14781 | Html5.prototype.addTextTrack = function addTextTrack(kind, label, language) { | ||
14782 | if (!this['featuresNativeTextTracks']) { | ||
14783 | return _Tech.prototype.addTextTrack.call(this, kind, label, language); | ||
14784 | } | ||
14785 | |||
14786 | return this.el_.addTextTrack(kind, label, language); | ||
14787 | }; | ||
14788 | |||
14789 | /** | ||
14790 | * Creates a remote text track object and returns a html track element | ||
14791 | * | ||
14792 | * @param {Object} options The object should contain values for | ||
14793 | * kind, language, label and src (location of the WebVTT file) | ||
14794 | * @return {HTMLTrackElement} | ||
14795 | * @method addRemoteTextTrack | ||
14796 | */ | ||
14797 | |||
14798 | Html5.prototype.addRemoteTextTrack = function addRemoteTextTrack() { | ||
14799 | var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
14800 | |||
14801 | if (!this['featuresNativeTextTracks']) { | ||
14802 | return _Tech.prototype.addRemoteTextTrack.call(this, options); | ||
14803 | } | ||
14804 | |||
14805 | var htmlTrackElement = _globalDocument2['default'].createElement('track'); | ||
14806 | |||
14807 | if (options.kind) { | ||
14808 | htmlTrackElement.kind = options.kind; | ||
14809 | } | ||
14810 | if (options.label) { | ||
14811 | htmlTrackElement.label = options.label; | ||
14812 | } | ||
14813 | if (options.language || options.srclang) { | ||
14814 | htmlTrackElement.srclang = options.language || options.srclang; | ||
14815 | } | ||
14816 | if (options['default']) { | ||
14817 | htmlTrackElement['default'] = options['default']; | ||
14818 | } | ||
14819 | if (options.id) { | ||
14820 | htmlTrackElement.id = options.id; | ||
14821 | } | ||
14822 | if (options.src) { | ||
14823 | htmlTrackElement.src = options.src; | ||
14824 | } | ||
14825 | |||
14826 | this.el().appendChild(htmlTrackElement); | ||
14827 | |||
14828 | // store HTMLTrackElement and TextTrack to remote list | ||
14829 | this.remoteTextTrackEls().addTrackElement_(htmlTrackElement); | ||
14830 | this.remoteTextTracks().addTrack_(htmlTrackElement.track); | ||
14831 | |||
14832 | return htmlTrackElement; | ||
14833 | }; | ||
14834 | |||
14835 | /** | ||
14836 | * Remove remote text track from TextTrackList object | ||
14837 | * | ||
14838 | * @param {TextTrackObject} track Texttrack object to remove | ||
14839 | * @method removeRemoteTextTrack | ||
14840 | */ | ||
14841 | |||
14842 | Html5.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { | ||
14843 | if (!this['featuresNativeTextTracks']) { | ||
14844 | return _Tech.prototype.removeRemoteTextTrack.call(this, track); | ||
14845 | } | ||
14846 | |||
14847 | var tracks = undefined, | ||
14848 | i = undefined; | ||
14849 | |||
14850 | var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); | ||
14851 | |||
14852 | // remove HTMLTrackElement and TextTrack from remote list | ||
14853 | this.remoteTextTrackEls().removeTrackElement_(trackElement); | ||
14854 | this.remoteTextTracks().removeTrack_(track); | ||
14855 | |||
14856 | tracks = this.$$('track'); | ||
14857 | |||
14858 | i = tracks.length; | ||
14859 | while (i--) { | ||
14860 | if (track === tracks[i] || track === tracks[i].track) { | ||
14861 | this.el().removeChild(tracks[i]); | ||
14862 | } | ||
14863 | } | ||
14864 | }; | ||
14865 | |||
14866 | return Html5; | ||
14867 | })(_techJs2['default']); | ||
14868 | |||
14869 | Html5.TEST_VID = _globalDocument2['default'].createElement('video'); | ||
14870 | var track = _globalDocument2['default'].createElement('track'); | ||
14871 | track.kind = 'captions'; | ||
14872 | track.srclang = 'en'; | ||
14873 | track.label = 'English'; | ||
14874 | Html5.TEST_VID.appendChild(track); | ||
14875 | |||
14876 | /* | ||
14877 | * Check if HTML5 video is supported by this browser/device | ||
14878 | * | ||
14879 | * @return {Boolean} | ||
14880 | */ | ||
14881 | Html5.isSupported = function () { | ||
14882 | // IE9 with no Media Player is a LIAR! (#984) | ||
14883 | try { | ||
14884 | Html5.TEST_VID['volume'] = 0.5; | ||
14885 | } catch (e) { | ||
14886 | return false; | ||
14887 | } | ||
14888 | |||
14889 | return !!Html5.TEST_VID.canPlayType; | ||
14890 | }; | ||
14891 | |||
14892 | // Add Source Handler pattern functions to this tech | ||
14893 | _techJs2['default'].withSourceHandlers(Html5); | ||
14894 | |||
14895 | /* | ||
14896 | * The default native source handler. | ||
14897 | * This simply passes the source to the video element. Nothing fancy. | ||
14898 | * | ||
14899 | * @param {Object} source The source object | ||
14900 | * @param {Html5} tech The instance of the HTML5 tech | ||
14901 | */ | ||
14902 | Html5.nativeSourceHandler = {}; | ||
14903 | |||
14904 | /* | ||
14905 | * Check if the video element can play the given videotype | ||
14906 | * | ||
14907 | * @param {String} type The mimetype to check | ||
14908 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
14909 | */ | ||
14910 | Html5.nativeSourceHandler.canPlayType = function (type) { | ||
14911 | // IE9 on Windows 7 without MediaPlayer throws an error here | ||
14912 | // https://github.com/videojs/video.js/issues/519 | ||
14913 | try { | ||
14914 | return Html5.TEST_VID.canPlayType(type); | ||
14915 | } catch (e) { | ||
14916 | return ''; | ||
14917 | } | ||
14918 | }; | ||
14919 | |||
14920 | /* | ||
14921 | * Check if the video element can handle the source natively | ||
14922 | * | ||
14923 | * @param {Object} source The source object | ||
14924 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
14925 | */ | ||
14926 | Html5.nativeSourceHandler.canHandleSource = function (source) { | ||
14927 | var match, ext; | ||
14928 | |||
14929 | // If a type was provided we should rely on that | ||
14930 | if (source.type) { | ||
14931 | return Html5.nativeSourceHandler.canPlayType(source.type); | ||
14932 | } else if (source.src) { | ||
14933 | // If no type, fall back to checking 'video/[EXTENSION]' | ||
14934 | ext = Url.getFileExtension(source.src); | ||
14935 | |||
14936 | return Html5.nativeSourceHandler.canPlayType('video/' + ext); | ||
14937 | } | ||
14938 | |||
14939 | return ''; | ||
14940 | }; | ||
14941 | |||
14942 | /* | ||
14943 | * Pass the source to the video element | ||
14944 | * Adaptive source handlers will have more complicated workflows before passing | ||
14945 | * video data to the video element | ||
14946 | * | ||
14947 | * @param {Object} source The source object | ||
14948 | * @param {Html5} tech The instance of the Html5 tech | ||
14949 | */ | ||
14950 | Html5.nativeSourceHandler.handleSource = function (source, tech) { | ||
14951 | tech.setSrc(source.src); | ||
14952 | }; | ||
14953 | |||
14954 | /* | ||
14955 | * Clean up the source handler when disposing the player or switching sources.. | ||
14956 | * (no cleanup is needed when supporting the format natively) | ||
14957 | */ | ||
14958 | Html5.nativeSourceHandler.dispose = function () {}; | ||
14959 | |||
14960 | // Register the native source handler | ||
14961 | Html5.registerSourceHandler(Html5.nativeSourceHandler); | ||
14962 | |||
14963 | /* | ||
14964 | * Check if the volume can be changed in this browser/device. | ||
14965 | * Volume cannot be changed in a lot of mobile devices. | ||
14966 | * Specifically, it can't be changed from 1 on iOS. | ||
14967 | * | ||
14968 | * @return {Boolean} | ||
14969 | */ | ||
14970 | Html5.canControlVolume = function () { | ||
14971 | var volume = Html5.TEST_VID.volume; | ||
14972 | Html5.TEST_VID.volume = volume / 2 + 0.1; | ||
14973 | return volume !== Html5.TEST_VID.volume; | ||
14974 | }; | ||
14975 | |||
14976 | /* | ||
14977 | * Check if playbackRate is supported in this browser/device. | ||
14978 | * | ||
14979 | * @return {Number} [description] | ||
14980 | */ | ||
14981 | Html5.canControlPlaybackRate = function () { | ||
14982 | var playbackRate = Html5.TEST_VID.playbackRate; | ||
14983 | Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1; | ||
14984 | return playbackRate !== Html5.TEST_VID.playbackRate; | ||
14985 | }; | ||
14986 | |||
14987 | /* | ||
14988 | * Check to see if native text tracks are supported by this browser/device | ||
14989 | * | ||
14990 | * @return {Boolean} | ||
14991 | */ | ||
14992 | Html5.supportsNativeTextTracks = function () { | ||
14993 | var supportsTextTracks; | ||
14994 | |||
14995 | // Figure out native text track support | ||
14996 | // If mode is a number, we cannot change it because it'll disappear from view. | ||
14997 | // Browsers with numeric modes include IE10 and older (<=2013) samsung android models. | ||
14998 | // Firefox isn't playing nice either with modifying the mode | ||
14999 | // TODO: Investigate firefox: https://github.com/videojs/video.js/issues/1862 | ||
15000 | supportsTextTracks = !!Html5.TEST_VID.textTracks; | ||
15001 | if (supportsTextTracks && Html5.TEST_VID.textTracks.length > 0) { | ||
15002 | supportsTextTracks = typeof Html5.TEST_VID.textTracks[0]['mode'] !== 'number'; | ||
15003 | } | ||
15004 | if (supportsTextTracks && browser.IS_FIREFOX) { | ||
15005 | supportsTextTracks = false; | ||
15006 | } | ||
15007 | if (supportsTextTracks && !('onremovetrack' in Html5.TEST_VID.textTracks)) { | ||
15008 | supportsTextTracks = false; | ||
15009 | } | ||
15010 | |||
15011 | return supportsTextTracks; | ||
15012 | }; | ||
15013 | |||
15014 | /** | ||
15015 | * An array of events available on the Html5 tech. | ||
15016 | * | ||
15017 | * @private | ||
15018 | * @type {Array} | ||
15019 | */ | ||
15020 | Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange']; | ||
15021 | |||
15022 | /* | ||
15023 | * Set the tech's volume control support status | ||
15024 | * | ||
15025 | * @type {Boolean} | ||
15026 | */ | ||
15027 | Html5.prototype['featuresVolumeControl'] = Html5.canControlVolume(); | ||
15028 | |||
15029 | /* | ||
15030 | * Set the tech's playbackRate support status | ||
15031 | * | ||
15032 | * @type {Boolean} | ||
15033 | */ | ||
15034 | Html5.prototype['featuresPlaybackRate'] = Html5.canControlPlaybackRate(); | ||
15035 | |||
15036 | /* | ||
15037 | * Set the tech's status on moving the video element. | ||
15038 | * In iOS, if you move a video element in the DOM, it breaks video playback. | ||
15039 | * | ||
15040 | * @type {Boolean} | ||
15041 | */ | ||
15042 | Html5.prototype['movingMediaElementInDOM'] = !browser.IS_IOS; | ||
15043 | |||
15044 | /* | ||
15045 | * Set the the tech's fullscreen resize support status. | ||
15046 | * HTML video is able to automatically resize when going to fullscreen. | ||
15047 | * (No longer appears to be used. Can probably be removed.) | ||
15048 | */ | ||
15049 | Html5.prototype['featuresFullscreenResize'] = true; | ||
15050 | |||
15051 | /* | ||
15052 | * Set the tech's progress event support status | ||
15053 | * (this disables the manual progress events of the Tech) | ||
15054 | */ | ||
15055 | Html5.prototype['featuresProgressEvents'] = true; | ||
15056 | |||
15057 | /* | ||
15058 | * Sets the tech's status on native text track support | ||
15059 | * | ||
15060 | * @type {Boolean} | ||
15061 | */ | ||
15062 | Html5.prototype['featuresNativeTextTracks'] = Html5.supportsNativeTextTracks(); | ||
15063 | |||
15064 | // HTML5 Feature detection and Device Fixes --------------------------------- // | ||
15065 | var canPlayType = undefined; | ||
15066 | var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; | ||
15067 | var mp4RE = /^video\/mp4/i; | ||
15068 | |||
15069 | Html5.patchCanPlayType = function () { | ||
15070 | // Android 4.0 and above can play HLS to some extent but it reports being unable to do so | ||
15071 | if (browser.ANDROID_VERSION >= 4.0) { | ||
15072 | if (!canPlayType) { | ||
15073 | canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType; | ||
15074 | } | ||
15075 | |||
15076 | Html5.TEST_VID.constructor.prototype.canPlayType = function (type) { | ||
15077 | if (type && mpegurlRE.test(type)) { | ||
15078 | return 'maybe'; | ||
15079 | } | ||
15080 | return canPlayType.call(this, type); | ||
15081 | }; | ||
15082 | } | ||
15083 | |||
15084 | // Override Android 2.2 and less canPlayType method which is broken | ||
15085 | if (browser.IS_OLD_ANDROID) { | ||
15086 | if (!canPlayType) { | ||
15087 | canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType; | ||
15088 | } | ||
15089 | |||
15090 | Html5.TEST_VID.constructor.prototype.canPlayType = function (type) { | ||
15091 | if (type && mp4RE.test(type)) { | ||
15092 | return 'maybe'; | ||
15093 | } | ||
15094 | return canPlayType.call(this, type); | ||
15095 | }; | ||
15096 | } | ||
15097 | }; | ||
15098 | |||
15099 | Html5.unpatchCanPlayType = function () { | ||
15100 | var r = Html5.TEST_VID.constructor.prototype.canPlayType; | ||
15101 | Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType; | ||
15102 | canPlayType = null; | ||
15103 | return r; | ||
15104 | }; | ||
15105 | |||
15106 | // by default, patch the video element | ||
15107 | Html5.patchCanPlayType(); | ||
15108 | |||
15109 | Html5.disposeMediaElement = function (el) { | ||
15110 | if (!el) { | ||
15111 | return; | ||
15112 | } | ||
15113 | |||
15114 | if (el.parentNode) { | ||
15115 | el.parentNode.removeChild(el); | ||
15116 | } | ||
15117 | |||
15118 | // remove any child track or source nodes to prevent their loading | ||
15119 | while (el.hasChildNodes()) { | ||
15120 | el.removeChild(el.firstChild); | ||
15121 | } | ||
15122 | |||
15123 | // remove any src reference. not setting `src=''` because that causes a warning | ||
15124 | // in firefox | ||
15125 | el.removeAttribute('src'); | ||
15126 | |||
15127 | // force the media element to update its loading state by calling load() | ||
15128 | // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793) | ||
15129 | if (typeof el.load === 'function') { | ||
15130 | // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) | ||
15131 | (function () { | ||
15132 | try { | ||
15133 | el.load(); | ||
15134 | } catch (e) { | ||
15135 | // not supported | ||
15136 | } | ||
15137 | })(); | ||
15138 | } | ||
15139 | }; | ||
15140 | |||
15141 | Html5.resetMediaElement = function (el) { | ||
15142 | if (!el) { | ||
15143 | return; | ||
15144 | } | ||
15145 | |||
15146 | var sources = el.querySelectorAll('source'); | ||
15147 | var i = sources.length; | ||
15148 | while (i--) { | ||
15149 | el.removeChild(sources[i]); | ||
15150 | } | ||
15151 | |||
15152 | // remove any src reference. | ||
15153 | // not setting `src=''` because that throws an error | ||
15154 | el.removeAttribute('src'); | ||
15155 | |||
15156 | if (typeof el.load === 'function') { | ||
15157 | // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) | ||
15158 | (function () { | ||
15159 | try { | ||
15160 | el.load(); | ||
15161 | } catch (e) {} | ||
15162 | })(); | ||
15163 | } | ||
15164 | }; | ||
15165 | |||
15166 | _component2['default'].registerComponent('Html5', Html5); | ||
15167 | _techJs2['default'].registerTech('Html5', Html5); | ||
15168 | exports['default'] = Html5; | ||
15169 | module.exports = exports['default']; | ||
15170 | |||
15171 | },{"../component":67,"../utils/browser.js":129,"../utils/dom.js":132,"../utils/fn.js":134,"../utils/log.js":137,"../utils/merge-options.js":138,"../utils/url.js":142,"./tech.js":119,"global/document":1,"global/window":2,"object.assign":45}],118:[function(_dereq_,module,exports){ | ||
15172 | /** | ||
15173 | * @file loader.js | ||
15174 | */ | ||
15175 | 'use strict'; | ||
15176 | |||
15177 | exports.__esModule = true; | ||
15178 | |||
15179 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
15180 | |||
15181 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
15182 | |||
15183 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
15184 | |||
15185 | var _componentJs = _dereq_('../component.js'); | ||
15186 | |||
15187 | var _componentJs2 = _interopRequireDefault(_componentJs); | ||
15188 | |||
15189 | var _techJs = _dereq_('./tech.js'); | ||
15190 | |||
15191 | var _techJs2 = _interopRequireDefault(_techJs); | ||
15192 | |||
15193 | var _globalWindow = _dereq_('global/window'); | ||
15194 | |||
15195 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
15196 | |||
15197 | var _utilsToTitleCaseJs = _dereq_('../utils/to-title-case.js'); | ||
15198 | |||
15199 | var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); | ||
15200 | |||
15201 | /** | ||
15202 | * The Media Loader is the component that decides which playback technology to load | ||
15203 | * when the player is initialized. | ||
15204 | * | ||
15205 | * @param {Object} player Main Player | ||
15206 | * @param {Object=} options Object of option names and values | ||
15207 | * @param {Function=} ready Ready callback function | ||
15208 | * @extends Component | ||
15209 | * @class MediaLoader | ||
15210 | */ | ||
15211 | |||
15212 | var MediaLoader = (function (_Component) { | ||
15213 | _inherits(MediaLoader, _Component); | ||
15214 | |||
15215 | function MediaLoader(player, options, ready) { | ||
15216 | _classCallCheck(this, MediaLoader); | ||
15217 | |||
15218 | _Component.call(this, player, options, ready); | ||
15219 | |||
15220 | // If there are no sources when the player is initialized, | ||
15221 | // load the first supported playback technology. | ||
15222 | |||
15223 | if (!options.playerOptions['sources'] || options.playerOptions['sources'].length === 0) { | ||
15224 | for (var i = 0, j = options.playerOptions['techOrder']; i < j.length; i++) { | ||
15225 | var techName = _utilsToTitleCaseJs2['default'](j[i]); | ||
15226 | var tech = _techJs2['default'].getTech(techName); | ||
15227 | // Support old behavior of techs being registered as components. | ||
15228 | // Remove once that deprecated behavior is removed. | ||
15229 | if (!techName) { | ||
15230 | tech = _componentJs2['default'].getComponent(techName); | ||
15231 | } | ||
15232 | |||
15233 | // Check if the browser supports this technology | ||
15234 | if (tech && tech.isSupported()) { | ||
15235 | player.loadTech_(techName); | ||
15236 | break; | ||
15237 | } | ||
15238 | } | ||
15239 | } else { | ||
15240 | // // Loop through playback technologies (HTML5, Flash) and check for support. | ||
15241 | // // Then load the best source. | ||
15242 | // // A few assumptions here: | ||
15243 | // // All playback technologies respect preload false. | ||
15244 | player.src(options.playerOptions['sources']); | ||
15245 | } | ||
15246 | } | ||
15247 | |||
15248 | return MediaLoader; | ||
15249 | })(_componentJs2['default']); | ||
15250 | |||
15251 | _componentJs2['default'].registerComponent('MediaLoader', MediaLoader); | ||
15252 | exports['default'] = MediaLoader; | ||
15253 | module.exports = exports['default']; | ||
15254 | |||
15255 | },{"../component.js":67,"../utils/to-title-case.js":141,"./tech.js":119,"global/window":2}],119:[function(_dereq_,module,exports){ | ||
15256 | /** | ||
15257 | * @file tech.js | ||
15258 | * Media Technology Controller - Base class for media playback | ||
15259 | * technology controllers like Flash and HTML5 | ||
15260 | */ | ||
15261 | |||
15262 | 'use strict'; | ||
15263 | |||
15264 | exports.__esModule = true; | ||
15265 | |||
15266 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
15267 | |||
15268 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
15269 | |||
15270 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
15271 | |||
15272 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
15273 | |||
15274 | var _component = _dereq_('../component'); | ||
15275 | |||
15276 | var _component2 = _interopRequireDefault(_component); | ||
15277 | |||
15278 | var _tracksHtmlTrackElement = _dereq_('../tracks/html-track-element'); | ||
15279 | |||
15280 | var _tracksHtmlTrackElement2 = _interopRequireDefault(_tracksHtmlTrackElement); | ||
15281 | |||
15282 | var _tracksHtmlTrackElementList = _dereq_('../tracks/html-track-element-list'); | ||
15283 | |||
15284 | var _tracksHtmlTrackElementList2 = _interopRequireDefault(_tracksHtmlTrackElementList); | ||
15285 | |||
15286 | var _utilsMergeOptionsJs = _dereq_('../utils/merge-options.js'); | ||
15287 | |||
15288 | var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); | ||
15289 | |||
15290 | var _tracksTextTrack = _dereq_('../tracks/text-track'); | ||
15291 | |||
15292 | var _tracksTextTrack2 = _interopRequireDefault(_tracksTextTrack); | ||
15293 | |||
15294 | var _tracksTextTrackList = _dereq_('../tracks/text-track-list'); | ||
15295 | |||
15296 | var _tracksTextTrackList2 = _interopRequireDefault(_tracksTextTrackList); | ||
15297 | |||
15298 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
15299 | |||
15300 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
15301 | |||
15302 | var _utilsLogJs = _dereq_('../utils/log.js'); | ||
15303 | |||
15304 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
15305 | |||
15306 | var _utilsTimeRangesJs = _dereq_('../utils/time-ranges.js'); | ||
15307 | |||
15308 | var _utilsBufferJs = _dereq_('../utils/buffer.js'); | ||
15309 | |||
15310 | var _mediaErrorJs = _dereq_('../media-error.js'); | ||
15311 | |||
15312 | var _mediaErrorJs2 = _interopRequireDefault(_mediaErrorJs); | ||
15313 | |||
15314 | var _globalWindow = _dereq_('global/window'); | ||
15315 | |||
15316 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
15317 | |||
15318 | var _globalDocument = _dereq_('global/document'); | ||
15319 | |||
15320 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
15321 | |||
15322 | /** | ||
15323 | * Base class for media (HTML5 Video, Flash) controllers | ||
15324 | * | ||
15325 | * @param {Object=} options Options object | ||
15326 | * @param {Function=} ready Ready callback function | ||
15327 | * @extends Component | ||
15328 | * @class Tech | ||
15329 | */ | ||
15330 | |||
15331 | var Tech = (function (_Component) { | ||
15332 | _inherits(Tech, _Component); | ||
15333 | |||
15334 | function Tech() { | ||
15335 | var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
15336 | var ready = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1]; | ||
15337 | |||
15338 | _classCallCheck(this, Tech); | ||
15339 | |||
15340 | // we don't want the tech to report user activity automatically. | ||
15341 | // This is done manually in addControlsListeners | ||
15342 | options.reportTouchActivity = false; | ||
15343 | _Component.call(this, null, options, ready); | ||
15344 | |||
15345 | // keep track of whether the current source has played at all to | ||
15346 | // implement a very limited played() | ||
15347 | this.hasStarted_ = false; | ||
15348 | this.on('playing', function () { | ||
15349 | this.hasStarted_ = true; | ||
15350 | }); | ||
15351 | this.on('loadstart', function () { | ||
15352 | this.hasStarted_ = false; | ||
15353 | }); | ||
15354 | |||
15355 | this.textTracks_ = options.textTracks; | ||
15356 | |||
15357 | // Manually track progress in cases where the browser/flash player doesn't report it. | ||
15358 | if (!this.featuresProgressEvents) { | ||
15359 | this.manualProgressOn(); | ||
15360 | } | ||
15361 | |||
15362 | // Manually track timeupdates in cases where the browser/flash player doesn't report it. | ||
15363 | if (!this.featuresTimeupdateEvents) { | ||
15364 | this.manualTimeUpdatesOn(); | ||
15365 | } | ||
15366 | |||
15367 | if (options.nativeCaptions === false || options.nativeTextTracks === false) { | ||
15368 | this.featuresNativeTextTracks = false; | ||
15369 | } | ||
15370 | |||
15371 | if (!this.featuresNativeTextTracks) { | ||
15372 | this.on('ready', this.emulateTextTracks); | ||
15373 | } | ||
15374 | |||
15375 | this.initTextTrackListeners(); | ||
15376 | |||
15377 | // Turn on component tap events | ||
15378 | this.emitTapEvents(); | ||
15379 | } | ||
15380 | |||
15381 | /* | ||
15382 | * List of associated text tracks | ||
15383 | * | ||
15384 | * @type {Array} | ||
15385 | * @private | ||
15386 | */ | ||
15387 | |||
15388 | /* Fallbacks for unsupported event types | ||
15389 | ================================================================================ */ | ||
15390 | // Manually trigger progress events based on changes to the buffered amount | ||
15391 | // Many flash players and older HTML5 browsers don't send progress or progress-like events | ||
15392 | /** | ||
15393 | * Turn on progress events | ||
15394 | * | ||
15395 | * @method manualProgressOn | ||
15396 | */ | ||
15397 | |||
15398 | Tech.prototype.manualProgressOn = function manualProgressOn() { | ||
15399 | this.on('durationchange', this.onDurationChange); | ||
15400 | |||
15401 | this.manualProgress = true; | ||
15402 | |||
15403 | // Trigger progress watching when a source begins loading | ||
15404 | this.one('ready', this.trackProgress); | ||
15405 | }; | ||
15406 | |||
15407 | /** | ||
15408 | * Turn off progress events | ||
15409 | * | ||
15410 | * @method manualProgressOff | ||
15411 | */ | ||
15412 | |||
15413 | Tech.prototype.manualProgressOff = function manualProgressOff() { | ||
15414 | this.manualProgress = false; | ||
15415 | this.stopTrackingProgress(); | ||
15416 | |||
15417 | this.off('durationchange', this.onDurationChange); | ||
15418 | }; | ||
15419 | |||
15420 | /** | ||
15421 | * Track progress | ||
15422 | * | ||
15423 | * @method trackProgress | ||
15424 | */ | ||
15425 | |||
15426 | Tech.prototype.trackProgress = function trackProgress() { | ||
15427 | this.stopTrackingProgress(); | ||
15428 | this.progressInterval = this.setInterval(Fn.bind(this, function () { | ||
15429 | // Don't trigger unless buffered amount is greater than last time | ||
15430 | |||
15431 | var numBufferedPercent = this.bufferedPercent(); | ||
15432 | |||
15433 | if (this.bufferedPercent_ !== numBufferedPercent) { | ||
15434 | this.trigger('progress'); | ||
15435 | } | ||
15436 | |||
15437 | this.bufferedPercent_ = numBufferedPercent; | ||
15438 | |||
15439 | if (numBufferedPercent === 1) { | ||
15440 | this.stopTrackingProgress(); | ||
15441 | } | ||
15442 | }), 500); | ||
15443 | }; | ||
15444 | |||
15445 | /** | ||
15446 | * Update duration | ||
15447 | * | ||
15448 | * @method onDurationChange | ||
15449 | */ | ||
15450 | |||
15451 | Tech.prototype.onDurationChange = function onDurationChange() { | ||
15452 | this.duration_ = this.duration(); | ||
15453 | }; | ||
15454 | |||
15455 | /** | ||
15456 | * Create and get TimeRange object for buffering | ||
15457 | * | ||
15458 | * @return {TimeRangeObject} | ||
15459 | * @method buffered | ||
15460 | */ | ||
15461 | |||
15462 | Tech.prototype.buffered = function buffered() { | ||
15463 | return _utilsTimeRangesJs.createTimeRange(0, 0); | ||
15464 | }; | ||
15465 | |||
15466 | /** | ||
15467 | * Get buffered percent | ||
15468 | * | ||
15469 | * @return {Number} | ||
15470 | * @method bufferedPercent | ||
15471 | */ | ||
15472 | |||
15473 | Tech.prototype.bufferedPercent = function bufferedPercent() { | ||
15474 | return _utilsBufferJs.bufferedPercent(this.buffered(), this.duration_); | ||
15475 | }; | ||
15476 | |||
15477 | /** | ||
15478 | * Stops tracking progress by clearing progress interval | ||
15479 | * | ||
15480 | * @method stopTrackingProgress | ||
15481 | */ | ||
15482 | |||
15483 | Tech.prototype.stopTrackingProgress = function stopTrackingProgress() { | ||
15484 | this.clearInterval(this.progressInterval); | ||
15485 | }; | ||
15486 | |||
15487 | /*! Time Tracking -------------------------------------------------------------- */ | ||
15488 | /** | ||
15489 | * Set event listeners for on play and pause and tracking current time | ||
15490 | * | ||
15491 | * @method manualTimeUpdatesOn | ||
15492 | */ | ||
15493 | |||
15494 | Tech.prototype.manualTimeUpdatesOn = function manualTimeUpdatesOn() { | ||
15495 | this.manualTimeUpdates = true; | ||
15496 | |||
15497 | this.on('play', this.trackCurrentTime); | ||
15498 | this.on('pause', this.stopTrackingCurrentTime); | ||
15499 | }; | ||
15500 | |||
15501 | /** | ||
15502 | * Remove event listeners for on play and pause and tracking current time | ||
15503 | * | ||
15504 | * @method manualTimeUpdatesOff | ||
15505 | */ | ||
15506 | |||
15507 | Tech.prototype.manualTimeUpdatesOff = function manualTimeUpdatesOff() { | ||
15508 | this.manualTimeUpdates = false; | ||
15509 | this.stopTrackingCurrentTime(); | ||
15510 | this.off('play', this.trackCurrentTime); | ||
15511 | this.off('pause', this.stopTrackingCurrentTime); | ||
15512 | }; | ||
15513 | |||
15514 | /** | ||
15515 | * Tracks current time | ||
15516 | * | ||
15517 | * @method trackCurrentTime | ||
15518 | */ | ||
15519 | |||
15520 | Tech.prototype.trackCurrentTime = function trackCurrentTime() { | ||
15521 | if (this.currentTimeInterval) { | ||
15522 | this.stopTrackingCurrentTime(); | ||
15523 | } | ||
15524 | this.currentTimeInterval = this.setInterval(function () { | ||
15525 | this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); | ||
15526 | }, 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 | ||
15527 | }; | ||
15528 | |||
15529 | /** | ||
15530 | * Turn off play progress tracking (when paused or dragging) | ||
15531 | * | ||
15532 | * @method stopTrackingCurrentTime | ||
15533 | */ | ||
15534 | |||
15535 | Tech.prototype.stopTrackingCurrentTime = function stopTrackingCurrentTime() { | ||
15536 | this.clearInterval(this.currentTimeInterval); | ||
15537 | |||
15538 | // #1002 - if the video ends right before the next timeupdate would happen, | ||
15539 | // the progress bar won't make it all the way to the end | ||
15540 | this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); | ||
15541 | }; | ||
15542 | |||
15543 | /** | ||
15544 | * Turn off any manual progress or timeupdate tracking | ||
15545 | * | ||
15546 | * @method dispose | ||
15547 | */ | ||
15548 | |||
15549 | Tech.prototype.dispose = function dispose() { | ||
15550 | // clear out text tracks because we can't reuse them between techs | ||
15551 | var textTracks = this.textTracks(); | ||
15552 | |||
15553 | if (textTracks) { | ||
15554 | var i = textTracks.length; | ||
15555 | while (i--) { | ||
15556 | this.removeRemoteTextTrack(textTracks[i]); | ||
15557 | } | ||
15558 | } | ||
15559 | |||
15560 | // Turn off any manual progress or timeupdate tracking | ||
15561 | if (this.manualProgress) { | ||
15562 | this.manualProgressOff(); | ||
15563 | } | ||
15564 | |||
15565 | if (this.manualTimeUpdates) { | ||
15566 | this.manualTimeUpdatesOff(); | ||
15567 | } | ||
15568 | |||
15569 | _Component.prototype.dispose.call(this); | ||
15570 | }; | ||
15571 | |||
15572 | /** | ||
15573 | * Reset the tech. Removes all sources and resets readyState. | ||
15574 | * | ||
15575 | * @method reset | ||
15576 | */ | ||
15577 | |||
15578 | Tech.prototype.reset = function reset() {}; | ||
15579 | |||
15580 | /** | ||
15581 | * When invoked without an argument, returns a MediaError object | ||
15582 | * representing the current error state of the player or null if | ||
15583 | * there is no error. When invoked with an argument, set the current | ||
15584 | * error state of the player. | ||
15585 | * @param {MediaError=} err Optional an error object | ||
15586 | * @return {MediaError} the current error object or null | ||
15587 | * @method error | ||
15588 | */ | ||
15589 | |||
15590 | Tech.prototype.error = function error(err) { | ||
15591 | if (err !== undefined) { | ||
15592 | if (err instanceof _mediaErrorJs2['default']) { | ||
15593 | this.error_ = err; | ||
15594 | } else { | ||
15595 | this.error_ = new _mediaErrorJs2['default'](err); | ||
15596 | } | ||
15597 | this.trigger('error'); | ||
15598 | } | ||
15599 | return this.error_; | ||
15600 | }; | ||
15601 | |||
15602 | /** | ||
15603 | * Return the time ranges that have been played through for the | ||
15604 | * current source. This implementation is incomplete. It does not | ||
15605 | * track the played time ranges, only whether the source has played | ||
15606 | * at all or not. | ||
15607 | * @return {TimeRangeObject} a single time range if this video has | ||
15608 | * played or an empty set of ranges if not. | ||
15609 | * @method played | ||
15610 | */ | ||
15611 | |||
15612 | Tech.prototype.played = function played() { | ||
15613 | if (this.hasStarted_) { | ||
15614 | return _utilsTimeRangesJs.createTimeRange(0, 0); | ||
15615 | } | ||
15616 | return _utilsTimeRangesJs.createTimeRange(); | ||
15617 | }; | ||
15618 | |||
15619 | /** | ||
15620 | * Set current time | ||
15621 | * | ||
15622 | * @method setCurrentTime | ||
15623 | */ | ||
15624 | |||
15625 | Tech.prototype.setCurrentTime = function setCurrentTime() { | ||
15626 | // improve the accuracy of manual timeupdates | ||
15627 | if (this.manualTimeUpdates) { | ||
15628 | this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); | ||
15629 | } | ||
15630 | }; | ||
15631 | |||
15632 | /** | ||
15633 | * Initialize texttrack listeners | ||
15634 | * | ||
15635 | * @method initTextTrackListeners | ||
15636 | */ | ||
15637 | |||
15638 | Tech.prototype.initTextTrackListeners = function initTextTrackListeners() { | ||
15639 | var textTrackListChanges = Fn.bind(this, function () { | ||
15640 | this.trigger('texttrackchange'); | ||
15641 | }); | ||
15642 | |||
15643 | var tracks = this.textTracks(); | ||
15644 | |||
15645 | if (!tracks) return; | ||
15646 | |||
15647 | tracks.addEventListener('removetrack', textTrackListChanges); | ||
15648 | tracks.addEventListener('addtrack', textTrackListChanges); | ||
15649 | |||
15650 | this.on('dispose', Fn.bind(this, function () { | ||
15651 | tracks.removeEventListener('removetrack', textTrackListChanges); | ||
15652 | tracks.removeEventListener('addtrack', textTrackListChanges); | ||
15653 | })); | ||
15654 | }; | ||
15655 | |||
15656 | /** | ||
15657 | * Emulate texttracks | ||
15658 | * | ||
15659 | * @method emulateTextTracks | ||
15660 | */ | ||
15661 | |||
15662 | Tech.prototype.emulateTextTracks = function emulateTextTracks() { | ||
15663 | var _this = this; | ||
15664 | |||
15665 | var tracks = this.textTracks(); | ||
15666 | if (!tracks) { | ||
15667 | return; | ||
15668 | } | ||
15669 | |||
15670 | if (!_globalWindow2['default']['WebVTT'] && this.el().parentNode != null) { | ||
15671 | (function () { | ||
15672 | var script = _globalDocument2['default'].createElement('script'); | ||
15673 | script.src = _this.options_['vtt.js'] || 'https://cdn.rawgit.com/gkatsev/vtt.js/vjs-v0.12.1/dist/vtt.min.js'; | ||
15674 | script.onload = function () { | ||
15675 | _this.trigger('vttjsloaded'); | ||
15676 | }; | ||
15677 | script.onerror = function () { | ||
15678 | _this.trigger('vttjserror'); | ||
15679 | }; | ||
15680 | _this.on('dispose', function () { | ||
15681 | script.onload = null; | ||
15682 | script.onerror = null; | ||
15683 | }); | ||
15684 | _this.el().parentNode.appendChild(script); | ||
15685 | _globalWindow2['default']['WebVTT'] = true; | ||
15686 | })(); | ||
15687 | } | ||
15688 | |||
15689 | var updateDisplay = function updateDisplay() { | ||
15690 | return _this.trigger('texttrackchange'); | ||
15691 | }; | ||
15692 | var textTracksChanges = function textTracksChanges() { | ||
15693 | updateDisplay(); | ||
15694 | |||
15695 | for (var i = 0; i < tracks.length; i++) { | ||
15696 | var track = tracks[i]; | ||
15697 | track.removeEventListener('cuechange', updateDisplay); | ||
15698 | if (track.mode === 'showing') { | ||
15699 | track.addEventListener('cuechange', updateDisplay); | ||
15700 | } | ||
15701 | } | ||
15702 | }; | ||
15703 | |||
15704 | textTracksChanges(); | ||
15705 | tracks.addEventListener('change', textTracksChanges); | ||
15706 | |||
15707 | this.on('dispose', function () { | ||
15708 | tracks.removeEventListener('change', textTracksChanges); | ||
15709 | }); | ||
15710 | }; | ||
15711 | |||
15712 | /* | ||
15713 | * Provide default methods for text tracks. | ||
15714 | * | ||
15715 | * Html5 tech overrides these. | ||
15716 | */ | ||
15717 | |||
15718 | /** | ||
15719 | * Get texttracks | ||
15720 | * | ||
15721 | * @returns {TextTrackList} | ||
15722 | * @method textTracks | ||
15723 | */ | ||
15724 | |||
15725 | Tech.prototype.textTracks = function textTracks() { | ||
15726 | this.textTracks_ = this.textTracks_ || new _tracksTextTrackList2['default'](); | ||
15727 | return this.textTracks_; | ||
15728 | }; | ||
15729 | |||
15730 | /** | ||
15731 | * Get remote texttracks | ||
15732 | * | ||
15733 | * @returns {TextTrackList} | ||
15734 | * @method remoteTextTracks | ||
15735 | */ | ||
15736 | |||
15737 | Tech.prototype.remoteTextTracks = function remoteTextTracks() { | ||
15738 | this.remoteTextTracks_ = this.remoteTextTracks_ || new _tracksTextTrackList2['default'](); | ||
15739 | return this.remoteTextTracks_; | ||
15740 | }; | ||
15741 | |||
15742 | /** | ||
15743 | * Get remote htmltrackelements | ||
15744 | * | ||
15745 | * @returns {HTMLTrackElementList} | ||
15746 | * @method remoteTextTrackEls | ||
15747 | */ | ||
15748 | |||
15749 | Tech.prototype.remoteTextTrackEls = function remoteTextTrackEls() { | ||
15750 | this.remoteTextTrackEls_ = this.remoteTextTrackEls_ || new _tracksHtmlTrackElementList2['default'](); | ||
15751 | return this.remoteTextTrackEls_; | ||
15752 | }; | ||
15753 | |||
15754 | /** | ||
15755 | * Creates and returns a remote text track object | ||
15756 | * | ||
15757 | * @param {String} kind Text track kind (subtitles, captions, descriptions | ||
15758 | * chapters and metadata) | ||
15759 | * @param {String=} label Label to identify the text track | ||
15760 | * @param {String=} language Two letter language abbreviation | ||
15761 | * @return {TextTrackObject} | ||
15762 | * @method addTextTrack | ||
15763 | */ | ||
15764 | |||
15765 | Tech.prototype.addTextTrack = function addTextTrack(kind, label, language) { | ||
15766 | if (!kind) { | ||
15767 | throw new Error('TextTrack kind is required but was not provided'); | ||
15768 | } | ||
15769 | |||
15770 | return createTrackHelper(this, kind, label, language); | ||
15771 | }; | ||
15772 | |||
15773 | /** | ||
15774 | * Creates a remote text track object and returns a emulated html track element | ||
15775 | * | ||
15776 | * @param {Object} options The object should contain values for | ||
15777 | * kind, language, label and src (location of the WebVTT file) | ||
15778 | * @return {HTMLTrackElement} | ||
15779 | * @method addRemoteTextTrack | ||
15780 | */ | ||
15781 | |||
15782 | Tech.prototype.addRemoteTextTrack = function addRemoteTextTrack(options) { | ||
15783 | var track = _utilsMergeOptionsJs2['default'](options, { | ||
15784 | tech: this | ||
15785 | }); | ||
15786 | |||
15787 | var htmlTrackElement = new _tracksHtmlTrackElement2['default'](track); | ||
15788 | |||
15789 | // store HTMLTrackElement and TextTrack to remote list | ||
15790 | this.remoteTextTrackEls().addTrackElement_(htmlTrackElement); | ||
15791 | this.remoteTextTracks().addTrack_(htmlTrackElement.track); | ||
15792 | |||
15793 | // must come after remoteTextTracks() | ||
15794 | this.textTracks().addTrack_(htmlTrackElement.track); | ||
15795 | |||
15796 | return htmlTrackElement; | ||
15797 | }; | ||
15798 | |||
15799 | /** | ||
15800 | * Remove remote texttrack | ||
15801 | * | ||
15802 | * @param {TextTrackObject} track Texttrack to remove | ||
15803 | * @method removeRemoteTextTrack | ||
15804 | */ | ||
15805 | |||
15806 | Tech.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { | ||
15807 | this.textTracks().removeTrack_(track); | ||
15808 | |||
15809 | var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); | ||
15810 | |||
15811 | // remove HTMLTrackElement and TextTrack from remote list | ||
15812 | this.remoteTextTrackEls().removeTrackElement_(trackElement); | ||
15813 | this.remoteTextTracks().removeTrack_(track); | ||
15814 | }; | ||
15815 | |||
15816 | /** | ||
15817 | * Provide a default setPoster method for techs | ||
15818 | * Poster support for techs should be optional, so we don't want techs to | ||
15819 | * break if they don't have a way to set a poster. | ||
15820 | * | ||
15821 | * @method setPoster | ||
15822 | */ | ||
15823 | |||
15824 | Tech.prototype.setPoster = function setPoster() {}; | ||
15825 | |||
15826 | /* | ||
15827 | * Check if the tech can support the given type | ||
15828 | * | ||
15829 | * The base tech does not support any type, but source handlers might | ||
15830 | * overwrite this. | ||
15831 | * | ||
15832 | * @param {String} type The mimetype to check | ||
15833 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
15834 | */ | ||
15835 | |||
15836 | Tech.prototype.canPlayType = function canPlayType() { | ||
15837 | return ''; | ||
15838 | }; | ||
15839 | |||
15840 | /* | ||
15841 | * Return whether the argument is a Tech or not. | ||
15842 | * Can be passed either a Class like `Html5` or a instance like `player.tech_` | ||
15843 | * | ||
15844 | * @param {Object} component An item to check | ||
15845 | * @return {Boolean} Whether it is a tech or not | ||
15846 | */ | ||
15847 | |||
15848 | Tech.isTech = function isTech(component) { | ||
15849 | return component.prototype instanceof Tech || component instanceof Tech || component === Tech; | ||
15850 | }; | ||
15851 | |||
15852 | /** | ||
15853 | * Registers a Tech | ||
15854 | * | ||
15855 | * @param {String} name Name of the Tech to register | ||
15856 | * @param {Object} tech The tech to register | ||
15857 | * @static | ||
15858 | * @method registerComponent | ||
15859 | */ | ||
15860 | |||
15861 | Tech.registerTech = function registerTech(name, tech) { | ||
15862 | if (!Tech.techs_) { | ||
15863 | Tech.techs_ = {}; | ||
15864 | } | ||
15865 | |||
15866 | if (!Tech.isTech(tech)) { | ||
15867 | throw new Error('Tech ' + name + ' must be a Tech'); | ||
15868 | } | ||
15869 | |||
15870 | Tech.techs_[name] = tech; | ||
15871 | return tech; | ||
15872 | }; | ||
15873 | |||
15874 | /** | ||
15875 | * Gets a component by name | ||
15876 | * | ||
15877 | * @param {String} name Name of the component to get | ||
15878 | * @return {Component} | ||
15879 | * @static | ||
15880 | * @method getComponent | ||
15881 | */ | ||
15882 | |||
15883 | Tech.getTech = function getTech(name) { | ||
15884 | if (Tech.techs_ && Tech.techs_[name]) { | ||
15885 | return Tech.techs_[name]; | ||
15886 | } | ||
15887 | |||
15888 | if (_globalWindow2['default'] && _globalWindow2['default'].videojs && _globalWindow2['default'].videojs[name]) { | ||
15889 | _utilsLogJs2['default'].warn('The ' + name + ' tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)'); | ||
15890 | return _globalWindow2['default'].videojs[name]; | ||
15891 | } | ||
15892 | }; | ||
15893 | |||
15894 | return Tech; | ||
15895 | })(_component2['default']); | ||
15896 | |||
15897 | Tech.prototype.textTracks_; | ||
15898 | |||
15899 | var createTrackHelper = function createTrackHelper(self, kind, label, language) { | ||
15900 | var options = arguments.length <= 4 || arguments[4] === undefined ? {} : arguments[4]; | ||
15901 | |||
15902 | var tracks = self.textTracks(); | ||
15903 | |||
15904 | options.kind = kind; | ||
15905 | |||
15906 | if (label) { | ||
15907 | options.label = label; | ||
15908 | } | ||
15909 | if (language) { | ||
15910 | options.language = language; | ||
15911 | } | ||
15912 | options.tech = self; | ||
15913 | |||
15914 | var track = new _tracksTextTrack2['default'](options); | ||
15915 | tracks.addTrack_(track); | ||
15916 | |||
15917 | return track; | ||
15918 | }; | ||
15919 | |||
15920 | Tech.prototype.featuresVolumeControl = true; | ||
15921 | |||
15922 | // Resizing plugins using request fullscreen reloads the plugin | ||
15923 | Tech.prototype.featuresFullscreenResize = false; | ||
15924 | Tech.prototype.featuresPlaybackRate = false; | ||
15925 | |||
15926 | // Optional events that we can manually mimic with timers | ||
15927 | // currently not triggered by video-js-swf | ||
15928 | Tech.prototype.featuresProgressEvents = false; | ||
15929 | Tech.prototype.featuresTimeupdateEvents = false; | ||
15930 | |||
15931 | Tech.prototype.featuresNativeTextTracks = false; | ||
15932 | |||
15933 | /* | ||
15934 | * A functional mixin for techs that want to use the Source Handler pattern. | ||
15935 | * | ||
15936 | * ##### EXAMPLE: | ||
15937 | * | ||
15938 | * Tech.withSourceHandlers.call(MyTech); | ||
15939 | * | ||
15940 | */ | ||
15941 | Tech.withSourceHandlers = function (_Tech) { | ||
15942 | /* | ||
15943 | * Register a source handler | ||
15944 | * Source handlers are scripts for handling specific formats. | ||
15945 | * The source handler pattern is used for adaptive formats (HLS, DASH) that | ||
15946 | * manually load video data and feed it into a Source Buffer (Media Source Extensions) | ||
15947 | * @param {Function} handler The source handler | ||
15948 | * @param {Boolean} first Register it before any existing handlers | ||
15949 | */ | ||
15950 | _Tech.registerSourceHandler = function (handler, index) { | ||
15951 | var handlers = _Tech.sourceHandlers; | ||
15952 | |||
15953 | if (!handlers) { | ||
15954 | handlers = _Tech.sourceHandlers = []; | ||
15955 | } | ||
15956 | |||
15957 | if (index === undefined) { | ||
15958 | // add to the end of the list | ||
15959 | index = handlers.length; | ||
15960 | } | ||
15961 | |||
15962 | handlers.splice(index, 0, handler); | ||
15963 | }; | ||
15964 | |||
15965 | /* | ||
15966 | * Check if the tech can support the given type | ||
15967 | * @param {String} type The mimetype to check | ||
15968 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
15969 | */ | ||
15970 | _Tech.canPlayType = function (type) { | ||
15971 | var handlers = _Tech.sourceHandlers || []; | ||
15972 | var can = undefined; | ||
15973 | |||
15974 | for (var i = 0; i < handlers.length; i++) { | ||
15975 | can = handlers[i].canPlayType(type); | ||
15976 | |||
15977 | if (can) { | ||
15978 | return can; | ||
15979 | } | ||
15980 | } | ||
15981 | |||
15982 | return ''; | ||
15983 | }; | ||
15984 | |||
15985 | /* | ||
15986 | * Return the first source handler that supports the source | ||
15987 | * TODO: Answer question: should 'probably' be prioritized over 'maybe' | ||
15988 | * @param {Object} source The source object | ||
15989 | * @returns {Object} The first source handler that supports the source | ||
15990 | * @returns {null} Null if no source handler is found | ||
15991 | */ | ||
15992 | _Tech.selectSourceHandler = function (source) { | ||
15993 | var handlers = _Tech.sourceHandlers || []; | ||
15994 | var can = undefined; | ||
15995 | |||
15996 | for (var i = 0; i < handlers.length; i++) { | ||
15997 | can = handlers[i].canHandleSource(source); | ||
15998 | |||
15999 | if (can) { | ||
16000 | return handlers[i]; | ||
16001 | } | ||
16002 | } | ||
16003 | |||
16004 | return null; | ||
16005 | }; | ||
16006 | |||
16007 | /* | ||
16008 | * Check if the tech can support the given source | ||
16009 | * @param {Object} srcObj The source object | ||
16010 | * @return {String} 'probably', 'maybe', or '' (empty string) | ||
16011 | */ | ||
16012 | _Tech.canPlaySource = function (srcObj) { | ||
16013 | var sh = _Tech.selectSourceHandler(srcObj); | ||
16014 | |||
16015 | if (sh) { | ||
16016 | return sh.canHandleSource(srcObj); | ||
16017 | } | ||
16018 | |||
16019 | return ''; | ||
16020 | }; | ||
16021 | |||
16022 | /* | ||
16023 | * When using a source handler, prefer its implementation of | ||
16024 | * any function normally provided by the tech. | ||
16025 | */ | ||
16026 | var deferrable = ['seekable', 'duration']; | ||
16027 | |||
16028 | deferrable.forEach(function (fnName) { | ||
16029 | var originalFn = this[fnName]; | ||
16030 | |||
16031 | if (typeof originalFn !== 'function') { | ||
16032 | return; | ||
16033 | } | ||
16034 | |||
16035 | this[fnName] = function () { | ||
16036 | if (this.sourceHandler_ && this.sourceHandler_[fnName]) { | ||
16037 | return this.sourceHandler_[fnName].apply(this.sourceHandler_, arguments); | ||
16038 | } | ||
16039 | return originalFn.apply(this, arguments); | ||
16040 | }; | ||
16041 | }, _Tech.prototype); | ||
16042 | |||
16043 | /* | ||
16044 | * Create a function for setting the source using a source object | ||
16045 | * and source handlers. | ||
16046 | * Should never be called unless a source handler was found. | ||
16047 | * @param {Object} source A source object with src and type keys | ||
16048 | * @return {Tech} self | ||
16049 | */ | ||
16050 | _Tech.prototype.setSource = function (source) { | ||
16051 | var sh = _Tech.selectSourceHandler(source); | ||
16052 | |||
16053 | if (!sh) { | ||
16054 | // Fall back to a native source hander when unsupported sources are | ||
16055 | // deliberately set | ||
16056 | if (_Tech.nativeSourceHandler) { | ||
16057 | sh = _Tech.nativeSourceHandler; | ||
16058 | } else { | ||
16059 | _utilsLogJs2['default'].error('No source hander found for the current source.'); | ||
16060 | } | ||
16061 | } | ||
16062 | |||
16063 | // Dispose any existing source handler | ||
16064 | this.disposeSourceHandler(); | ||
16065 | this.off('dispose', this.disposeSourceHandler); | ||
16066 | |||
16067 | this.currentSource_ = source; | ||
16068 | this.sourceHandler_ = sh.handleSource(source, this); | ||
16069 | this.on('dispose', this.disposeSourceHandler); | ||
16070 | |||
16071 | return this; | ||
16072 | }; | ||
16073 | |||
16074 | /* | ||
16075 | * Clean up any existing source handler | ||
16076 | */ | ||
16077 | _Tech.prototype.disposeSourceHandler = function () { | ||
16078 | if (this.sourceHandler_ && this.sourceHandler_.dispose) { | ||
16079 | this.sourceHandler_.dispose(); | ||
16080 | } | ||
16081 | }; | ||
16082 | }; | ||
16083 | |||
16084 | _component2['default'].registerComponent('Tech', Tech); | ||
16085 | // Old name for Tech | ||
16086 | _component2['default'].registerComponent('MediaTechController', Tech); | ||
16087 | Tech.registerTech('Tech', Tech); | ||
16088 | exports['default'] = Tech; | ||
16089 | module.exports = exports['default']; | ||
16090 | |||
16091 | },{"../component":67,"../media-error.js":103,"../tracks/html-track-element":121,"../tracks/html-track-element-list":120,"../tracks/text-track":128,"../tracks/text-track-list":126,"../utils/buffer.js":130,"../utils/fn.js":134,"../utils/log.js":137,"../utils/merge-options.js":138,"../utils/time-ranges.js":140,"global/document":1,"global/window":2}],120:[function(_dereq_,module,exports){ | ||
16092 | /** | ||
16093 | * @file html-track-element-list.js | ||
16094 | */ | ||
16095 | |||
16096 | 'use strict'; | ||
16097 | |||
16098 | exports.__esModule = true; | ||
16099 | |||
16100 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
16101 | |||
16102 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
16103 | |||
16104 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
16105 | |||
16106 | var _utilsBrowserJs = _dereq_('../utils/browser.js'); | ||
16107 | |||
16108 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
16109 | |||
16110 | var _globalDocument = _dereq_('global/document'); | ||
16111 | |||
16112 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
16113 | |||
16114 | var HtmlTrackElementList = (function () { | ||
16115 | function HtmlTrackElementList() { | ||
16116 | var trackElements = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; | ||
16117 | |||
16118 | _classCallCheck(this, HtmlTrackElementList); | ||
16119 | |||
16120 | var list = this; | ||
16121 | |||
16122 | if (browser.IS_IE8) { | ||
16123 | list = _globalDocument2['default'].createElement('custom'); | ||
16124 | |||
16125 | for (var prop in HtmlTrackElementList.prototype) { | ||
16126 | if (prop !== 'constructor') { | ||
16127 | list[prop] = HtmlTrackElementList.prototype[prop]; | ||
16128 | } | ||
16129 | } | ||
16130 | } | ||
16131 | |||
16132 | list.trackElements_ = []; | ||
16133 | |||
16134 | Object.defineProperty(list, 'length', { | ||
16135 | get: function get() { | ||
16136 | return this.trackElements_.length; | ||
16137 | } | ||
16138 | }); | ||
16139 | |||
16140 | for (var i = 0, _length = trackElements.length; i < _length; i++) { | ||
16141 | list.addTrackElement_(trackElements[i]); | ||
16142 | } | ||
16143 | |||
16144 | if (browser.IS_IE8) { | ||
16145 | return list; | ||
16146 | } | ||
16147 | } | ||
16148 | |||
16149 | HtmlTrackElementList.prototype.addTrackElement_ = function addTrackElement_(trackElement) { | ||
16150 | this.trackElements_.push(trackElement); | ||
16151 | }; | ||
16152 | |||
16153 | HtmlTrackElementList.prototype.getTrackElementByTrack_ = function getTrackElementByTrack_(track) { | ||
16154 | var trackElement_ = undefined; | ||
16155 | |||
16156 | for (var i = 0, _length2 = this.trackElements_.length; i < _length2; i++) { | ||
16157 | if (track === this.trackElements_[i].track) { | ||
16158 | trackElement_ = this.trackElements_[i]; | ||
16159 | |||
16160 | break; | ||
16161 | } | ||
16162 | } | ||
16163 | |||
16164 | return trackElement_; | ||
16165 | }; | ||
16166 | |||
16167 | HtmlTrackElementList.prototype.removeTrackElement_ = function removeTrackElement_(trackElement) { | ||
16168 | for (var i = 0, _length3 = this.trackElements_.length; i < _length3; i++) { | ||
16169 | if (trackElement === this.trackElements_[i]) { | ||
16170 | this.trackElements_.splice(i, 1); | ||
16171 | |||
16172 | break; | ||
16173 | } | ||
16174 | } | ||
16175 | }; | ||
16176 | |||
16177 | return HtmlTrackElementList; | ||
16178 | })(); | ||
16179 | |||
16180 | exports['default'] = HtmlTrackElementList; | ||
16181 | module.exports = exports['default']; | ||
16182 | |||
16183 | },{"../utils/browser.js":129,"global/document":1}],121:[function(_dereq_,module,exports){ | ||
16184 | /** | ||
16185 | * @file html-track-element.js | ||
16186 | */ | ||
16187 | |||
16188 | 'use strict'; | ||
16189 | |||
16190 | exports.__esModule = true; | ||
16191 | |||
16192 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
16193 | |||
16194 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
16195 | |||
16196 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
16197 | |||
16198 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
16199 | |||
16200 | var _utilsBrowserJs = _dereq_('../utils/browser.js'); | ||
16201 | |||
16202 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
16203 | |||
16204 | var _globalDocument = _dereq_('global/document'); | ||
16205 | |||
16206 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
16207 | |||
16208 | var _eventTarget = _dereq_('../event-target'); | ||
16209 | |||
16210 | var _eventTarget2 = _interopRequireDefault(_eventTarget); | ||
16211 | |||
16212 | var _tracksTextTrack = _dereq_('../tracks/text-track'); | ||
16213 | |||
16214 | var _tracksTextTrack2 = _interopRequireDefault(_tracksTextTrack); | ||
16215 | |||
16216 | var NONE = 0; | ||
16217 | var LOADING = 1; | ||
16218 | var LOADED = 2; | ||
16219 | var ERROR = 3; | ||
16220 | |||
16221 | /** | ||
16222 | * https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement | ||
16223 | * | ||
16224 | * interface HTMLTrackElement : HTMLElement { | ||
16225 | * attribute DOMString kind; | ||
16226 | * attribute DOMString src; | ||
16227 | * attribute DOMString srclang; | ||
16228 | * attribute DOMString label; | ||
16229 | * attribute boolean default; | ||
16230 | * | ||
16231 | * const unsigned short NONE = 0; | ||
16232 | * const unsigned short LOADING = 1; | ||
16233 | * const unsigned short LOADED = 2; | ||
16234 | * const unsigned short ERROR = 3; | ||
16235 | * readonly attribute unsigned short readyState; | ||
16236 | * | ||
16237 | * readonly attribute TextTrack track; | ||
16238 | * }; | ||
16239 | * | ||
16240 | * @param {Object} options TextTrack configuration | ||
16241 | * @class HTMLTrackElement | ||
16242 | */ | ||
16243 | |||
16244 | var HTMLTrackElement = (function (_EventTarget) { | ||
16245 | _inherits(HTMLTrackElement, _EventTarget); | ||
16246 | |||
16247 | function HTMLTrackElement() { | ||
16248 | var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
16249 | |||
16250 | _classCallCheck(this, HTMLTrackElement); | ||
16251 | |||
16252 | _EventTarget.call(this); | ||
16253 | |||
16254 | var readyState = undefined, | ||
16255 | trackElement = this; | ||
16256 | |||
16257 | if (browser.IS_IE8) { | ||
16258 | trackElement = _globalDocument2['default'].createElement('custom'); | ||
16259 | |||
16260 | for (var prop in HTMLTrackElement.prototype) { | ||
16261 | if (prop !== 'constructor') { | ||
16262 | trackElement[prop] = HTMLTrackElement.prototype[prop]; | ||
16263 | } | ||
16264 | } | ||
16265 | } | ||
16266 | |||
16267 | var track = new _tracksTextTrack2['default'](options); | ||
16268 | |||
16269 | trackElement.kind = track.kind; | ||
16270 | trackElement.src = track.src; | ||
16271 | trackElement.srclang = track.language; | ||
16272 | trackElement.label = track.label; | ||
16273 | trackElement['default'] = track['default']; | ||
16274 | |||
16275 | Object.defineProperty(trackElement, 'readyState', { | ||
16276 | get: function get() { | ||
16277 | return readyState; | ||
16278 | } | ||
16279 | }); | ||
16280 | |||
16281 | Object.defineProperty(trackElement, 'track', { | ||
16282 | get: function get() { | ||
16283 | return track; | ||
16284 | } | ||
16285 | }); | ||
16286 | |||
16287 | readyState = NONE; | ||
16288 | |||
16289 | track.addEventListener('loadeddata', function () { | ||
16290 | readyState = LOADED; | ||
16291 | |||
16292 | trackElement.trigger({ | ||
16293 | type: 'load', | ||
16294 | target: trackElement | ||
16295 | }); | ||
16296 | }); | ||
16297 | |||
16298 | if (browser.IS_IE8) { | ||
16299 | return trackElement; | ||
16300 | } | ||
16301 | } | ||
16302 | |||
16303 | return HTMLTrackElement; | ||
16304 | })(_eventTarget2['default']); | ||
16305 | |||
16306 | HTMLTrackElement.prototype.allowedEvents_ = { | ||
16307 | load: 'load' | ||
16308 | }; | ||
16309 | |||
16310 | HTMLTrackElement.NONE = NONE; | ||
16311 | HTMLTrackElement.LOADING = LOADING; | ||
16312 | HTMLTrackElement.LOADED = LOADED; | ||
16313 | HTMLTrackElement.ERROR = ERROR; | ||
16314 | |||
16315 | exports['default'] = HTMLTrackElement; | ||
16316 | module.exports = exports['default']; | ||
16317 | |||
16318 | },{"../event-target":99,"../tracks/text-track":128,"../utils/browser.js":129,"global/document":1}],122:[function(_dereq_,module,exports){ | ||
16319 | /** | ||
16320 | * @file text-track-cue-list.js | ||
16321 | */ | ||
16322 | 'use strict'; | ||
16323 | |||
16324 | exports.__esModule = true; | ||
16325 | |||
16326 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
16327 | |||
16328 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
16329 | |||
16330 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
16331 | |||
16332 | var _utilsBrowserJs = _dereq_('../utils/browser.js'); | ||
16333 | |||
16334 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
16335 | |||
16336 | var _globalDocument = _dereq_('global/document'); | ||
16337 | |||
16338 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
16339 | |||
16340 | /** | ||
16341 | * A List of text track cues as defined in: | ||
16342 | * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist | ||
16343 | * | ||
16344 | * interface TextTrackCueList { | ||
16345 | * readonly attribute unsigned long length; | ||
16346 | * getter TextTrackCue (unsigned long index); | ||
16347 | * TextTrackCue? getCueById(DOMString id); | ||
16348 | * }; | ||
16349 | * | ||
16350 | * @param {Array} cues A list of cues to be initialized with | ||
16351 | * @class TextTrackCueList | ||
16352 | */ | ||
16353 | |||
16354 | var TextTrackCueList = (function () { | ||
16355 | function TextTrackCueList(cues) { | ||
16356 | _classCallCheck(this, TextTrackCueList); | ||
16357 | |||
16358 | var list = this; | ||
16359 | |||
16360 | if (browser.IS_IE8) { | ||
16361 | list = _globalDocument2['default'].createElement('custom'); | ||
16362 | |||
16363 | for (var prop in TextTrackCueList.prototype) { | ||
16364 | if (prop !== 'constructor') { | ||
16365 | list[prop] = TextTrackCueList.prototype[prop]; | ||
16366 | } | ||
16367 | } | ||
16368 | } | ||
16369 | |||
16370 | TextTrackCueList.prototype.setCues_.call(list, cues); | ||
16371 | |||
16372 | Object.defineProperty(list, 'length', { | ||
16373 | get: function get() { | ||
16374 | return this.length_; | ||
16375 | } | ||
16376 | }); | ||
16377 | |||
16378 | if (browser.IS_IE8) { | ||
16379 | return list; | ||
16380 | } | ||
16381 | } | ||
16382 | |||
16383 | /** | ||
16384 | * A setter for cues in this list | ||
16385 | * | ||
16386 | * @param {Array} cues an array of cues | ||
16387 | * @method setCues_ | ||
16388 | * @private | ||
16389 | */ | ||
16390 | |||
16391 | TextTrackCueList.prototype.setCues_ = function setCues_(cues) { | ||
16392 | var oldLength = this.length || 0; | ||
16393 | var i = 0; | ||
16394 | var l = cues.length; | ||
16395 | |||
16396 | this.cues_ = cues; | ||
16397 | this.length_ = cues.length; | ||
16398 | |||
16399 | var defineProp = function defineProp(index) { | ||
16400 | if (!('' + index in this)) { | ||
16401 | Object.defineProperty(this, '' + index, { | ||
16402 | get: function get() { | ||
16403 | return this.cues_[index]; | ||
16404 | } | ||
16405 | }); | ||
16406 | } | ||
16407 | }; | ||
16408 | |||
16409 | if (oldLength < l) { | ||
16410 | i = oldLength; | ||
16411 | |||
16412 | for (; i < l; i++) { | ||
16413 | defineProp.call(this, i); | ||
16414 | } | ||
16415 | } | ||
16416 | }; | ||
16417 | |||
16418 | /** | ||
16419 | * Get a cue that is currently in the Cue list by id | ||
16420 | * | ||
16421 | * @param {String} id | ||
16422 | * @method getCueById | ||
16423 | * @return {Object} a single cue | ||
16424 | */ | ||
16425 | |||
16426 | TextTrackCueList.prototype.getCueById = function getCueById(id) { | ||
16427 | var result = null; | ||
16428 | |||
16429 | for (var i = 0, l = this.length; i < l; i++) { | ||
16430 | var cue = this[i]; | ||
16431 | |||
16432 | if (cue.id === id) { | ||
16433 | result = cue; | ||
16434 | break; | ||
16435 | } | ||
16436 | } | ||
16437 | |||
16438 | return result; | ||
16439 | }; | ||
16440 | |||
16441 | return TextTrackCueList; | ||
16442 | })(); | ||
16443 | |||
16444 | exports['default'] = TextTrackCueList; | ||
16445 | module.exports = exports['default']; | ||
16446 | |||
16447 | },{"../utils/browser.js":129,"global/document":1}],123:[function(_dereq_,module,exports){ | ||
16448 | /** | ||
16449 | * @file text-track-display.js | ||
16450 | */ | ||
16451 | 'use strict'; | ||
16452 | |||
16453 | exports.__esModule = true; | ||
16454 | |||
16455 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
16456 | |||
16457 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
16458 | |||
16459 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
16460 | |||
16461 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
16462 | |||
16463 | var _component = _dereq_('../component'); | ||
16464 | |||
16465 | var _component2 = _interopRequireDefault(_component); | ||
16466 | |||
16467 | var _menuMenuJs = _dereq_('../menu/menu.js'); | ||
16468 | |||
16469 | var _menuMenuJs2 = _interopRequireDefault(_menuMenuJs); | ||
16470 | |||
16471 | var _menuMenuItemJs = _dereq_('../menu/menu-item.js'); | ||
16472 | |||
16473 | var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); | ||
16474 | |||
16475 | var _menuMenuButtonJs = _dereq_('../menu/menu-button.js'); | ||
16476 | |||
16477 | var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); | ||
16478 | |||
16479 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
16480 | |||
16481 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
16482 | |||
16483 | var _globalDocument = _dereq_('global/document'); | ||
16484 | |||
16485 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
16486 | |||
16487 | var _globalWindow = _dereq_('global/window'); | ||
16488 | |||
16489 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
16490 | |||
16491 | var darkGray = '#222'; | ||
16492 | var lightGray = '#ccc'; | ||
16493 | var fontMap = { | ||
16494 | monospace: 'monospace', | ||
16495 | sansSerif: 'sans-serif', | ||
16496 | serif: 'serif', | ||
16497 | monospaceSansSerif: '"Andale Mono", "Lucida Console", monospace', | ||
16498 | monospaceSerif: '"Courier New", monospace', | ||
16499 | proportionalSansSerif: 'sans-serif', | ||
16500 | proportionalSerif: 'serif', | ||
16501 | casual: '"Comic Sans MS", Impact, fantasy', | ||
16502 | script: '"Monotype Corsiva", cursive', | ||
16503 | smallcaps: '"Andale Mono", "Lucida Console", monospace, sans-serif' | ||
16504 | }; | ||
16505 | |||
16506 | /** | ||
16507 | * The component for displaying text track cues | ||
16508 | * | ||
16509 | * @param {Object} player Main Player | ||
16510 | * @param {Object=} options Object of option names and values | ||
16511 | * @param {Function=} ready Ready callback function | ||
16512 | * @extends Component | ||
16513 | * @class TextTrackDisplay | ||
16514 | */ | ||
16515 | |||
16516 | var TextTrackDisplay = (function (_Component) { | ||
16517 | _inherits(TextTrackDisplay, _Component); | ||
16518 | |||
16519 | function TextTrackDisplay(player, options, ready) { | ||
16520 | _classCallCheck(this, TextTrackDisplay); | ||
16521 | |||
16522 | _Component.call(this, player, options, ready); | ||
16523 | |||
16524 | player.on('loadstart', Fn.bind(this, this.toggleDisplay)); | ||
16525 | player.on('texttrackchange', Fn.bind(this, this.updateDisplay)); | ||
16526 | |||
16527 | // This used to be called during player init, but was causing an error | ||
16528 | // if a track should show by default and the display hadn't loaded yet. | ||
16529 | // Should probably be moved to an external track loader when we support | ||
16530 | // tracks that don't need a display. | ||
16531 | player.ready(Fn.bind(this, function () { | ||
16532 | if (player.tech_ && player.tech_['featuresNativeTextTracks']) { | ||
16533 | this.hide(); | ||
16534 | return; | ||
16535 | } | ||
16536 | |||
16537 | player.on('fullscreenchange', Fn.bind(this, this.updateDisplay)); | ||
16538 | |||
16539 | var tracks = this.options_.playerOptions['tracks'] || []; | ||
16540 | for (var i = 0; i < tracks.length; i++) { | ||
16541 | var track = tracks[i]; | ||
16542 | this.player_.addRemoteTextTrack(track); | ||
16543 | } | ||
16544 | })); | ||
16545 | } | ||
16546 | |||
16547 | /** | ||
16548 | * Add cue HTML to display | ||
16549 | * | ||
16550 | * @param {Number} color Hex number for color, like #f0e | ||
16551 | * @param {Number} opacity Value for opacity,0.0 - 1.0 | ||
16552 | * @return {RGBAColor} In the form 'rgba(255, 0, 0, 0.3)' | ||
16553 | * @method constructColor | ||
16554 | */ | ||
16555 | |||
16556 | /** | ||
16557 | * Toggle display texttracks | ||
16558 | * | ||
16559 | * @method toggleDisplay | ||
16560 | */ | ||
16561 | |||
16562 | TextTrackDisplay.prototype.toggleDisplay = function toggleDisplay() { | ||
16563 | if (this.player_.tech_ && this.player_.tech_['featuresNativeTextTracks']) { | ||
16564 | this.hide(); | ||
16565 | } else { | ||
16566 | this.show(); | ||
16567 | } | ||
16568 | }; | ||
16569 | |||
16570 | /** | ||
16571 | * Create the component's DOM element | ||
16572 | * | ||
16573 | * @return {Element} | ||
16574 | * @method createEl | ||
16575 | */ | ||
16576 | |||
16577 | TextTrackDisplay.prototype.createEl = function createEl() { | ||
16578 | return _Component.prototype.createEl.call(this, 'div', { | ||
16579 | className: 'vjs-text-track-display' | ||
16580 | }); | ||
16581 | }; | ||
16582 | |||
16583 | /** | ||
16584 | * Clear display texttracks | ||
16585 | * | ||
16586 | * @method clearDisplay | ||
16587 | */ | ||
16588 | |||
16589 | TextTrackDisplay.prototype.clearDisplay = function clearDisplay() { | ||
16590 | if (typeof _globalWindow2['default']['WebVTT'] === 'function') { | ||
16591 | _globalWindow2['default']['WebVTT']['processCues'](_globalWindow2['default'], [], this.el_); | ||
16592 | } | ||
16593 | }; | ||
16594 | |||
16595 | /** | ||
16596 | * Update display texttracks | ||
16597 | * | ||
16598 | * @method updateDisplay | ||
16599 | */ | ||
16600 | |||
16601 | TextTrackDisplay.prototype.updateDisplay = function updateDisplay() { | ||
16602 | var tracks = this.player_.textTracks(); | ||
16603 | |||
16604 | this.clearDisplay(); | ||
16605 | |||
16606 | if (!tracks) { | ||
16607 | return; | ||
16608 | } | ||
16609 | |||
16610 | for (var i = 0; i < tracks.length; i++) { | ||
16611 | var track = tracks[i]; | ||
16612 | if (track['mode'] === 'showing') { | ||
16613 | this.updateForTrack(track); | ||
16614 | } | ||
16615 | } | ||
16616 | }; | ||
16617 | |||
16618 | /** | ||
16619 | * Add texttrack to texttrack list | ||
16620 | * | ||
16621 | * @param {TextTrackObject} track Texttrack object to be added to list | ||
16622 | * @method updateForTrack | ||
16623 | */ | ||
16624 | |||
16625 | TextTrackDisplay.prototype.updateForTrack = function updateForTrack(track) { | ||
16626 | if (typeof _globalWindow2['default']['WebVTT'] !== 'function' || !track['activeCues']) { | ||
16627 | return; | ||
16628 | } | ||
16629 | |||
16630 | var overrides = this.player_['textTrackSettings'].getValues(); | ||
16631 | |||
16632 | var cues = []; | ||
16633 | for (var _i = 0; _i < track['activeCues'].length; _i++) { | ||
16634 | cues.push(track['activeCues'][_i]); | ||
16635 | } | ||
16636 | |||
16637 | _globalWindow2['default']['WebVTT']['processCues'](_globalWindow2['default'], track['activeCues'], this.el_); | ||
16638 | |||
16639 | var i = cues.length; | ||
16640 | while (i--) { | ||
16641 | var cue = cues[i]; | ||
16642 | if (!cue) { | ||
16643 | continue; | ||
16644 | } | ||
16645 | |||
16646 | var cueDiv = cue.displayState; | ||
16647 | if (overrides.color) { | ||
16648 | cueDiv.firstChild.style.color = overrides.color; | ||
16649 | } | ||
16650 | if (overrides.textOpacity) { | ||
16651 | tryUpdateStyle(cueDiv.firstChild, 'color', constructColor(overrides.color || '#fff', overrides.textOpacity)); | ||
16652 | } | ||
16653 | if (overrides.backgroundColor) { | ||
16654 | cueDiv.firstChild.style.backgroundColor = overrides.backgroundColor; | ||
16655 | } | ||
16656 | if (overrides.backgroundOpacity) { | ||
16657 | tryUpdateStyle(cueDiv.firstChild, 'backgroundColor', constructColor(overrides.backgroundColor || '#000', overrides.backgroundOpacity)); | ||
16658 | } | ||
16659 | if (overrides.windowColor) { | ||
16660 | if (overrides.windowOpacity) { | ||
16661 | tryUpdateStyle(cueDiv, 'backgroundColor', constructColor(overrides.windowColor, overrides.windowOpacity)); | ||
16662 | } else { | ||
16663 | cueDiv.style.backgroundColor = overrides.windowColor; | ||
16664 | } | ||
16665 | } | ||
16666 | if (overrides.edgeStyle) { | ||
16667 | if (overrides.edgeStyle === 'dropshadow') { | ||
16668 | cueDiv.firstChild.style.textShadow = '2px 2px 3px ' + darkGray + ', 2px 2px 4px ' + darkGray + ', 2px 2px 5px ' + darkGray; | ||
16669 | } else if (overrides.edgeStyle === 'raised') { | ||
16670 | cueDiv.firstChild.style.textShadow = '1px 1px ' + darkGray + ', 2px 2px ' + darkGray + ', 3px 3px ' + darkGray; | ||
16671 | } else if (overrides.edgeStyle === 'depressed') { | ||
16672 | cueDiv.firstChild.style.textShadow = '1px 1px ' + lightGray + ', 0 1px ' + lightGray + ', -1px -1px ' + darkGray + ', 0 -1px ' + darkGray; | ||
16673 | } else if (overrides.edgeStyle === 'uniform') { | ||
16674 | cueDiv.firstChild.style.textShadow = '0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray; | ||
16675 | } | ||
16676 | } | ||
16677 | if (overrides.fontPercent && overrides.fontPercent !== 1) { | ||
16678 | var fontSize = _globalWindow2['default'].parseFloat(cueDiv.style.fontSize); | ||
16679 | cueDiv.style.fontSize = fontSize * overrides.fontPercent + 'px'; | ||
16680 | cueDiv.style.height = 'auto'; | ||
16681 | cueDiv.style.top = 'auto'; | ||
16682 | cueDiv.style.bottom = '2px'; | ||
16683 | } | ||
16684 | if (overrides.fontFamily && overrides.fontFamily !== 'default') { | ||
16685 | if (overrides.fontFamily === 'small-caps') { | ||
16686 | cueDiv.firstChild.style.fontVariant = 'small-caps'; | ||
16687 | } else { | ||
16688 | cueDiv.firstChild.style.fontFamily = fontMap[overrides.fontFamily]; | ||
16689 | } | ||
16690 | } | ||
16691 | } | ||
16692 | }; | ||
16693 | |||
16694 | return TextTrackDisplay; | ||
16695 | })(_component2['default']); | ||
16696 | |||
16697 | function constructColor(color, opacity) { | ||
16698 | return 'rgba(' + | ||
16699 | // color looks like "#f0e" | ||
16700 | parseInt(color[1] + color[1], 16) + ',' + parseInt(color[2] + color[2], 16) + ',' + parseInt(color[3] + color[3], 16) + ',' + opacity + ')'; | ||
16701 | } | ||
16702 | |||
16703 | /** | ||
16704 | * Try to update style | ||
16705 | * Some style changes will throw an error, particularly in IE8. Those should be noops. | ||
16706 | * | ||
16707 | * @param {Element} el The element to be styles | ||
16708 | * @param {CSSProperty} style The CSS property to be styled | ||
16709 | * @param {CSSStyle} rule The actual style to be applied to the property | ||
16710 | * @method tryUpdateStyle | ||
16711 | */ | ||
16712 | function tryUpdateStyle(el, style, rule) { | ||
16713 | // | ||
16714 | try { | ||
16715 | el.style[style] = rule; | ||
16716 | } catch (e) {} | ||
16717 | } | ||
16718 | |||
16719 | _component2['default'].registerComponent('TextTrackDisplay', TextTrackDisplay); | ||
16720 | exports['default'] = TextTrackDisplay; | ||
16721 | module.exports = exports['default']; | ||
16722 | |||
16723 | },{"../component":67,"../menu/menu-button.js":104,"../menu/menu-item.js":105,"../menu/menu.js":106,"../utils/fn.js":134,"global/document":1,"global/window":2}],124:[function(_dereq_,module,exports){ | ||
16724 | /** | ||
16725 | * @file text-track-enums.js | ||
16726 | */ | ||
16727 | |||
16728 | /** | ||
16729 | * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode | ||
16730 | * | ||
16731 | * enum TextTrackMode { "disabled", "hidden", "showing" }; | ||
16732 | */ | ||
16733 | 'use strict'; | ||
16734 | |||
16735 | exports.__esModule = true; | ||
16736 | var TextTrackMode = { | ||
16737 | disabled: 'disabled', | ||
16738 | hidden: 'hidden', | ||
16739 | showing: 'showing' | ||
16740 | }; | ||
16741 | |||
16742 | /** | ||
16743 | * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackkind | ||
16744 | * | ||
16745 | * enum TextTrackKind { | ||
16746 | * "subtitles", | ||
16747 | * "captions", | ||
16748 | * "descriptions", | ||
16749 | * "chapters", | ||
16750 | * "metadata" | ||
16751 | * }; | ||
16752 | */ | ||
16753 | var TextTrackKind = { | ||
16754 | subtitles: 'subtitles', | ||
16755 | captions: 'captions', | ||
16756 | descriptions: 'descriptions', | ||
16757 | chapters: 'chapters', | ||
16758 | metadata: 'metadata' | ||
16759 | }; | ||
16760 | |||
16761 | /* jshint ignore:start */ | ||
16762 | // we ignore jshint here because it does not see | ||
16763 | // TextTrackMode or TextTrackKind as defined here somehow... | ||
16764 | exports.TextTrackMode = TextTrackMode; | ||
16765 | exports.TextTrackKind = TextTrackKind; | ||
16766 | |||
16767 | /* jshint ignore:end */ | ||
16768 | |||
16769 | },{}],125:[function(_dereq_,module,exports){ | ||
16770 | /** | ||
16771 | * Utilities for capturing text track state and re-creating tracks | ||
16772 | * based on a capture. | ||
16773 | * | ||
16774 | * @file text-track-list-converter.js | ||
16775 | */ | ||
16776 | |||
16777 | /** | ||
16778 | * Examine a single text track and return a JSON-compatible javascript | ||
16779 | * object that represents the text track's state. | ||
16780 | * @param track {TextTrackObject} the text track to query | ||
16781 | * @return {Object} a serializable javascript representation of the | ||
16782 | * @private | ||
16783 | */ | ||
16784 | 'use strict'; | ||
16785 | |||
16786 | exports.__esModule = true; | ||
16787 | var trackToJson_ = function trackToJson_(track) { | ||
16788 | var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) { | ||
16789 | if (track[prop]) { | ||
16790 | acc[prop] = track[prop]; | ||
16791 | } | ||
16792 | |||
16793 | return acc; | ||
16794 | }, { | ||
16795 | cues: track.cues && Array.prototype.map.call(track.cues, function (cue) { | ||
16796 | return { | ||
16797 | startTime: cue.startTime, | ||
16798 | endTime: cue.endTime, | ||
16799 | text: cue.text, | ||
16800 | id: cue.id | ||
16801 | }; | ||
16802 | }) | ||
16803 | }); | ||
16804 | |||
16805 | return ret; | ||
16806 | }; | ||
16807 | |||
16808 | /** | ||
16809 | * Examine a tech and return a JSON-compatible javascript array that | ||
16810 | * represents the state of all text tracks currently configured. The | ||
16811 | * return array is compatible with `jsonToTextTracks`. | ||
16812 | * @param tech {tech} the tech object to query | ||
16813 | * @return {Array} a serializable javascript representation of the | ||
16814 | * @function textTracksToJson | ||
16815 | */ | ||
16816 | var textTracksToJson = function textTracksToJson(tech) { | ||
16817 | |||
16818 | var trackEls = tech.$$('track'); | ||
16819 | |||
16820 | var trackObjs = Array.prototype.map.call(trackEls, function (t) { | ||
16821 | return t.track; | ||
16822 | }); | ||
16823 | var tracks = Array.prototype.map.call(trackEls, function (trackEl) { | ||
16824 | var json = trackToJson_(trackEl.track); | ||
16825 | if (trackEl.src) { | ||
16826 | json.src = trackEl.src; | ||
16827 | } | ||
16828 | return json; | ||
16829 | }); | ||
16830 | |||
16831 | return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) { | ||
16832 | return trackObjs.indexOf(track) === -1; | ||
16833 | }).map(trackToJson_)); | ||
16834 | }; | ||
16835 | |||
16836 | /** | ||
16837 | * Creates a set of remote text tracks on a tech based on an array of | ||
16838 | * javascript text track representations. | ||
16839 | * @param json {Array} an array of text track representation objects, | ||
16840 | * like those that would be produced by `textTracksToJson` | ||
16841 | * @param tech {tech} the tech to create text tracks on | ||
16842 | * @function jsonToTextTracks | ||
16843 | */ | ||
16844 | var jsonToTextTracks = function jsonToTextTracks(json, tech) { | ||
16845 | json.forEach(function (track) { | ||
16846 | var addedTrack = tech.addRemoteTextTrack(track).track; | ||
16847 | if (!track.src && track.cues) { | ||
16848 | track.cues.forEach(function (cue) { | ||
16849 | return addedTrack.addCue(cue); | ||
16850 | }); | ||
16851 | } | ||
16852 | }); | ||
16853 | |||
16854 | return tech.textTracks(); | ||
16855 | }; | ||
16856 | |||
16857 | exports['default'] = { textTracksToJson: textTracksToJson, jsonToTextTracks: jsonToTextTracks, trackToJson_: trackToJson_ }; | ||
16858 | module.exports = exports['default']; | ||
16859 | |||
16860 | },{}],126:[function(_dereq_,module,exports){ | ||
16861 | /** | ||
16862 | * @file text-track-list.js | ||
16863 | */ | ||
16864 | 'use strict'; | ||
16865 | |||
16866 | exports.__esModule = true; | ||
16867 | |||
16868 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
16869 | |||
16870 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
16871 | |||
16872 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
16873 | |||
16874 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
16875 | |||
16876 | var _eventTarget = _dereq_('../event-target'); | ||
16877 | |||
16878 | var _eventTarget2 = _interopRequireDefault(_eventTarget); | ||
16879 | |||
16880 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
16881 | |||
16882 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
16883 | |||
16884 | var _utilsBrowserJs = _dereq_('../utils/browser.js'); | ||
16885 | |||
16886 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
16887 | |||
16888 | var _globalDocument = _dereq_('global/document'); | ||
16889 | |||
16890 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
16891 | |||
16892 | /** | ||
16893 | * A text track list as defined in: | ||
16894 | * https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist | ||
16895 | * | ||
16896 | * interface TextTrackList : EventTarget { | ||
16897 | * readonly attribute unsigned long length; | ||
16898 | * getter TextTrack (unsigned long index); | ||
16899 | * TextTrack? getTrackById(DOMString id); | ||
16900 | * | ||
16901 | * attribute EventHandler onchange; | ||
16902 | * attribute EventHandler onaddtrack; | ||
16903 | * attribute EventHandler onremovetrack; | ||
16904 | * }; | ||
16905 | * | ||
16906 | * @param {Track[]} tracks A list of tracks to initialize the list with | ||
16907 | * @extends EventTarget | ||
16908 | * @class TextTrackList | ||
16909 | */ | ||
16910 | |||
16911 | var TextTrackList = (function (_EventTarget) { | ||
16912 | _inherits(TextTrackList, _EventTarget); | ||
16913 | |||
16914 | function TextTrackList() { | ||
16915 | var tracks = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; | ||
16916 | |||
16917 | _classCallCheck(this, TextTrackList); | ||
16918 | |||
16919 | _EventTarget.call(this); | ||
16920 | var list = this; | ||
16921 | |||
16922 | if (browser.IS_IE8) { | ||
16923 | list = _globalDocument2['default'].createElement('custom'); | ||
16924 | |||
16925 | for (var prop in TextTrackList.prototype) { | ||
16926 | if (prop !== 'constructor') { | ||
16927 | list[prop] = TextTrackList.prototype[prop]; | ||
16928 | } | ||
16929 | } | ||
16930 | } | ||
16931 | |||
16932 | list.tracks_ = []; | ||
16933 | |||
16934 | Object.defineProperty(list, 'length', { | ||
16935 | get: function get() { | ||
16936 | return this.tracks_.length; | ||
16937 | } | ||
16938 | }); | ||
16939 | |||
16940 | for (var i = 0; i < tracks.length; i++) { | ||
16941 | list.addTrack_(tracks[i]); | ||
16942 | } | ||
16943 | |||
16944 | if (browser.IS_IE8) { | ||
16945 | return list; | ||
16946 | } | ||
16947 | } | ||
16948 | |||
16949 | /** | ||
16950 | * change - One or more tracks in the track list have been enabled or disabled. | ||
16951 | * addtrack - A track has been added to the track list. | ||
16952 | * removetrack - A track has been removed from the track list. | ||
16953 | */ | ||
16954 | |||
16955 | /** | ||
16956 | * Add TextTrack from TextTrackList | ||
16957 | * | ||
16958 | * @param {TextTrack} track | ||
16959 | * @method addTrack_ | ||
16960 | * @private | ||
16961 | */ | ||
16962 | |||
16963 | TextTrackList.prototype.addTrack_ = function addTrack_(track) { | ||
16964 | var index = this.tracks_.length; | ||
16965 | |||
16966 | if (!('' + index in this)) { | ||
16967 | Object.defineProperty(this, index, { | ||
16968 | get: function get() { | ||
16969 | return this.tracks_[index]; | ||
16970 | } | ||
16971 | }); | ||
16972 | } | ||
16973 | |||
16974 | track.addEventListener('modechange', Fn.bind(this, function () { | ||
16975 | this.trigger('change'); | ||
16976 | })); | ||
16977 | |||
16978 | // Do not add duplicate tracks | ||
16979 | if (this.tracks_.indexOf(track) === -1) { | ||
16980 | this.tracks_.push(track); | ||
16981 | this.trigger({ | ||
16982 | track: track, | ||
16983 | type: 'addtrack' | ||
16984 | }); | ||
16985 | } | ||
16986 | }; | ||
16987 | |||
16988 | /** | ||
16989 | * Remove TextTrack from TextTrackList | ||
16990 | * NOTE: Be mindful of what is passed in as it may be a HTMLTrackElement | ||
16991 | * | ||
16992 | * @param {TextTrack} rtrack | ||
16993 | * @method removeTrack_ | ||
16994 | * @private | ||
16995 | */ | ||
16996 | |||
16997 | TextTrackList.prototype.removeTrack_ = function removeTrack_(rtrack) { | ||
16998 | var track = undefined; | ||
16999 | |||
17000 | for (var i = 0, l = this.length; i < l; i++) { | ||
17001 | if (this[i] === rtrack) { | ||
17002 | track = this[i]; | ||
17003 | if (track.off) { | ||
17004 | track.off(); | ||
17005 | } | ||
17006 | |||
17007 | this.tracks_.splice(i, 1); | ||
17008 | |||
17009 | break; | ||
17010 | } | ||
17011 | } | ||
17012 | |||
17013 | if (!track) { | ||
17014 | return; | ||
17015 | } | ||
17016 | |||
17017 | this.trigger({ | ||
17018 | track: track, | ||
17019 | type: 'removetrack' | ||
17020 | }); | ||
17021 | }; | ||
17022 | |||
17023 | /** | ||
17024 | * Get a TextTrack from TextTrackList by a tracks id | ||
17025 | * | ||
17026 | * @param {String} id - the id of the track to get | ||
17027 | * @method getTrackById | ||
17028 | * @return {TextTrack} | ||
17029 | * @private | ||
17030 | */ | ||
17031 | |||
17032 | TextTrackList.prototype.getTrackById = function getTrackById(id) { | ||
17033 | var result = null; | ||
17034 | |||
17035 | for (var i = 0, l = this.length; i < l; i++) { | ||
17036 | var track = this[i]; | ||
17037 | |||
17038 | if (track.id === id) { | ||
17039 | result = track; | ||
17040 | break; | ||
17041 | } | ||
17042 | } | ||
17043 | |||
17044 | return result; | ||
17045 | }; | ||
17046 | |||
17047 | return TextTrackList; | ||
17048 | })(_eventTarget2['default']); | ||
17049 | |||
17050 | TextTrackList.prototype.allowedEvents_ = { | ||
17051 | change: 'change', | ||
17052 | addtrack: 'addtrack', | ||
17053 | removetrack: 'removetrack' | ||
17054 | }; | ||
17055 | |||
17056 | // emulate attribute EventHandler support to allow for feature detection | ||
17057 | for (var _event in TextTrackList.prototype.allowedEvents_) { | ||
17058 | TextTrackList.prototype['on' + _event] = null; | ||
17059 | } | ||
17060 | |||
17061 | exports['default'] = TextTrackList; | ||
17062 | module.exports = exports['default']; | ||
17063 | |||
17064 | },{"../event-target":99,"../utils/browser.js":129,"../utils/fn.js":134,"global/document":1}],127:[function(_dereq_,module,exports){ | ||
17065 | /** | ||
17066 | * @file text-track-settings.js | ||
17067 | */ | ||
17068 | 'use strict'; | ||
17069 | |||
17070 | exports.__esModule = true; | ||
17071 | |||
17072 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
17073 | |||
17074 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
17075 | |||
17076 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
17077 | |||
17078 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
17079 | |||
17080 | var _component = _dereq_('../component'); | ||
17081 | |||
17082 | var _component2 = _interopRequireDefault(_component); | ||
17083 | |||
17084 | var _utilsEventsJs = _dereq_('../utils/events.js'); | ||
17085 | |||
17086 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
17087 | |||
17088 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
17089 | |||
17090 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
17091 | |||
17092 | var _utilsLogJs = _dereq_('../utils/log.js'); | ||
17093 | |||
17094 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
17095 | |||
17096 | var _safeJsonParseTuple = _dereq_('safe-json-parse/tuple'); | ||
17097 | |||
17098 | var _safeJsonParseTuple2 = _interopRequireDefault(_safeJsonParseTuple); | ||
17099 | |||
17100 | var _globalWindow = _dereq_('global/window'); | ||
17101 | |||
17102 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
17103 | |||
17104 | /** | ||
17105 | * Manipulate settings of texttracks | ||
17106 | * | ||
17107 | * @param {Object} player Main Player | ||
17108 | * @param {Object=} options Object of option names and values | ||
17109 | * @extends Component | ||
17110 | * @class TextTrackSettings | ||
17111 | */ | ||
17112 | |||
17113 | var TextTrackSettings = (function (_Component) { | ||
17114 | _inherits(TextTrackSettings, _Component); | ||
17115 | |||
17116 | function TextTrackSettings(player, options) { | ||
17117 | _classCallCheck(this, TextTrackSettings); | ||
17118 | |||
17119 | _Component.call(this, player, options); | ||
17120 | this.hide(); | ||
17121 | |||
17122 | // Grab `persistTextTrackSettings` from the player options if not passed in child options | ||
17123 | if (options.persistTextTrackSettings === undefined) { | ||
17124 | this.options_.persistTextTrackSettings = this.options_.playerOptions.persistTextTrackSettings; | ||
17125 | } | ||
17126 | |||
17127 | Events.on(this.$('.vjs-done-button'), 'click', Fn.bind(this, function () { | ||
17128 | this.saveSettings(); | ||
17129 | this.hide(); | ||
17130 | })); | ||
17131 | |||
17132 | Events.on(this.$('.vjs-default-button'), 'click', Fn.bind(this, function () { | ||
17133 | this.$('.vjs-fg-color > select').selectedIndex = 0; | ||
17134 | this.$('.vjs-bg-color > select').selectedIndex = 0; | ||
17135 | this.$('.window-color > select').selectedIndex = 0; | ||
17136 | this.$('.vjs-text-opacity > select').selectedIndex = 0; | ||
17137 | this.$('.vjs-bg-opacity > select').selectedIndex = 0; | ||
17138 | this.$('.vjs-window-opacity > select').selectedIndex = 0; | ||
17139 | this.$('.vjs-edge-style select').selectedIndex = 0; | ||
17140 | this.$('.vjs-font-family select').selectedIndex = 0; | ||
17141 | this.$('.vjs-font-percent select').selectedIndex = 2; | ||
17142 | this.updateDisplay(); | ||
17143 | })); | ||
17144 | |||
17145 | Events.on(this.$('.vjs-fg-color > select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17146 | Events.on(this.$('.vjs-bg-color > select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17147 | Events.on(this.$('.window-color > select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17148 | Events.on(this.$('.vjs-text-opacity > select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17149 | Events.on(this.$('.vjs-bg-opacity > select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17150 | Events.on(this.$('.vjs-window-opacity > select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17151 | Events.on(this.$('.vjs-font-percent select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17152 | Events.on(this.$('.vjs-edge-style select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17153 | Events.on(this.$('.vjs-font-family select'), 'change', Fn.bind(this, this.updateDisplay)); | ||
17154 | |||
17155 | if (this.options_.persistTextTrackSettings) { | ||
17156 | this.restoreSettings(); | ||
17157 | } | ||
17158 | } | ||
17159 | |||
17160 | /** | ||
17161 | * Create the component's DOM element | ||
17162 | * | ||
17163 | * @return {Element} | ||
17164 | * @method createEl | ||
17165 | */ | ||
17166 | |||
17167 | TextTrackSettings.prototype.createEl = function createEl() { | ||
17168 | return _Component.prototype.createEl.call(this, 'div', { | ||
17169 | className: 'vjs-caption-settings vjs-modal-overlay', | ||
17170 | innerHTML: captionOptionsMenuTemplate() | ||
17171 | }); | ||
17172 | }; | ||
17173 | |||
17174 | /** | ||
17175 | * Get texttrack settings | ||
17176 | * Settings are | ||
17177 | * .vjs-edge-style | ||
17178 | * .vjs-font-family | ||
17179 | * .vjs-fg-color | ||
17180 | * .vjs-text-opacity | ||
17181 | * .vjs-bg-color | ||
17182 | * .vjs-bg-opacity | ||
17183 | * .window-color | ||
17184 | * .vjs-window-opacity | ||
17185 | * | ||
17186 | * @return {Object} | ||
17187 | * @method getValues | ||
17188 | */ | ||
17189 | |||
17190 | TextTrackSettings.prototype.getValues = function getValues() { | ||
17191 | var textEdge = getSelectedOptionValue(this.$('.vjs-edge-style select')); | ||
17192 | var fontFamily = getSelectedOptionValue(this.$('.vjs-font-family select')); | ||
17193 | var fgColor = getSelectedOptionValue(this.$('.vjs-fg-color > select')); | ||
17194 | var textOpacity = getSelectedOptionValue(this.$('.vjs-text-opacity > select')); | ||
17195 | var bgColor = getSelectedOptionValue(this.$('.vjs-bg-color > select')); | ||
17196 | var bgOpacity = getSelectedOptionValue(this.$('.vjs-bg-opacity > select')); | ||
17197 | var windowColor = getSelectedOptionValue(this.$('.window-color > select')); | ||
17198 | var windowOpacity = getSelectedOptionValue(this.$('.vjs-window-opacity > select')); | ||
17199 | var fontPercent = _globalWindow2['default']['parseFloat'](getSelectedOptionValue(this.$('.vjs-font-percent > select'))); | ||
17200 | |||
17201 | var result = { | ||
17202 | 'backgroundOpacity': bgOpacity, | ||
17203 | 'textOpacity': textOpacity, | ||
17204 | 'windowOpacity': windowOpacity, | ||
17205 | 'edgeStyle': textEdge, | ||
17206 | 'fontFamily': fontFamily, | ||
17207 | 'color': fgColor, | ||
17208 | 'backgroundColor': bgColor, | ||
17209 | 'windowColor': windowColor, | ||
17210 | 'fontPercent': fontPercent | ||
17211 | }; | ||
17212 | for (var _name in result) { | ||
17213 | if (result[_name] === '' || result[_name] === 'none' || _name === 'fontPercent' && result[_name] === 1.00) { | ||
17214 | delete result[_name]; | ||
17215 | } | ||
17216 | } | ||
17217 | return result; | ||
17218 | }; | ||
17219 | |||
17220 | /** | ||
17221 | * Set texttrack settings | ||
17222 | * Settings are | ||
17223 | * .vjs-edge-style | ||
17224 | * .vjs-font-family | ||
17225 | * .vjs-fg-color | ||
17226 | * .vjs-text-opacity | ||
17227 | * .vjs-bg-color | ||
17228 | * .vjs-bg-opacity | ||
17229 | * .window-color | ||
17230 | * .vjs-window-opacity | ||
17231 | * | ||
17232 | * @param {Object} values Object with texttrack setting values | ||
17233 | * @method setValues | ||
17234 | */ | ||
17235 | |||
17236 | TextTrackSettings.prototype.setValues = function setValues(values) { | ||
17237 | setSelectedOption(this.$('.vjs-edge-style select'), values.edgeStyle); | ||
17238 | setSelectedOption(this.$('.vjs-font-family select'), values.fontFamily); | ||
17239 | setSelectedOption(this.$('.vjs-fg-color > select'), values.color); | ||
17240 | setSelectedOption(this.$('.vjs-text-opacity > select'), values.textOpacity); | ||
17241 | setSelectedOption(this.$('.vjs-bg-color > select'), values.backgroundColor); | ||
17242 | setSelectedOption(this.$('.vjs-bg-opacity > select'), values.backgroundOpacity); | ||
17243 | setSelectedOption(this.$('.window-color > select'), values.windowColor); | ||
17244 | setSelectedOption(this.$('.vjs-window-opacity > select'), values.windowOpacity); | ||
17245 | |||
17246 | var fontPercent = values.fontPercent; | ||
17247 | |||
17248 | if (fontPercent) { | ||
17249 | fontPercent = fontPercent.toFixed(2); | ||
17250 | } | ||
17251 | |||
17252 | setSelectedOption(this.$('.vjs-font-percent > select'), fontPercent); | ||
17253 | }; | ||
17254 | |||
17255 | /** | ||
17256 | * Restore texttrack settings | ||
17257 | * | ||
17258 | * @method restoreSettings | ||
17259 | */ | ||
17260 | |||
17261 | TextTrackSettings.prototype.restoreSettings = function restoreSettings() { | ||
17262 | var err = undefined, | ||
17263 | values = undefined; | ||
17264 | |||
17265 | try { | ||
17266 | var _safeParseTuple = _safeJsonParseTuple2['default'](_globalWindow2['default'].localStorage.getItem('vjs-text-track-settings')); | ||
17267 | |||
17268 | err = _safeParseTuple[0]; | ||
17269 | values = _safeParseTuple[1]; | ||
17270 | |||
17271 | if (err) { | ||
17272 | _utilsLogJs2['default'].error(err); | ||
17273 | } | ||
17274 | } catch (e) { | ||
17275 | _utilsLogJs2['default'].warn(e); | ||
17276 | } | ||
17277 | |||
17278 | if (values) { | ||
17279 | this.setValues(values); | ||
17280 | } | ||
17281 | }; | ||
17282 | |||
17283 | /** | ||
17284 | * Save texttrack settings to local storage | ||
17285 | * | ||
17286 | * @method saveSettings | ||
17287 | */ | ||
17288 | |||
17289 | TextTrackSettings.prototype.saveSettings = function saveSettings() { | ||
17290 | if (!this.options_.persistTextTrackSettings) { | ||
17291 | return; | ||
17292 | } | ||
17293 | |||
17294 | var values = this.getValues(); | ||
17295 | try { | ||
17296 | if (Object.getOwnPropertyNames(values).length > 0) { | ||
17297 | _globalWindow2['default'].localStorage.setItem('vjs-text-track-settings', JSON.stringify(values)); | ||
17298 | } else { | ||
17299 | _globalWindow2['default'].localStorage.removeItem('vjs-text-track-settings'); | ||
17300 | } | ||
17301 | } catch (e) { | ||
17302 | _utilsLogJs2['default'].warn(e); | ||
17303 | } | ||
17304 | }; | ||
17305 | |||
17306 | /** | ||
17307 | * Update display of texttrack settings | ||
17308 | * | ||
17309 | * @method updateDisplay | ||
17310 | */ | ||
17311 | |||
17312 | TextTrackSettings.prototype.updateDisplay = function updateDisplay() { | ||
17313 | var ttDisplay = this.player_.getChild('textTrackDisplay'); | ||
17314 | if (ttDisplay) { | ||
17315 | ttDisplay.updateDisplay(); | ||
17316 | } | ||
17317 | }; | ||
17318 | |||
17319 | return TextTrackSettings; | ||
17320 | })(_component2['default']); | ||
17321 | |||
17322 | _component2['default'].registerComponent('TextTrackSettings', TextTrackSettings); | ||
17323 | |||
17324 | function getSelectedOptionValue(target) { | ||
17325 | var selectedOption = undefined; | ||
17326 | // not all browsers support selectedOptions, so, fallback to options | ||
17327 | if (target.selectedOptions) { | ||
17328 | selectedOption = target.selectedOptions[0]; | ||
17329 | } else if (target.options) { | ||
17330 | selectedOption = target.options[target.options.selectedIndex]; | ||
17331 | } | ||
17332 | |||
17333 | return selectedOption.value; | ||
17334 | } | ||
17335 | |||
17336 | function setSelectedOption(target, value) { | ||
17337 | if (!value) { | ||
17338 | return; | ||
17339 | } | ||
17340 | |||
17341 | var i = undefined; | ||
17342 | for (i = 0; i < target.options.length; i++) { | ||
17343 | var option = target.options[i]; | ||
17344 | if (option.value === value) { | ||
17345 | break; | ||
17346 | } | ||
17347 | } | ||
17348 | |||
17349 | target.selectedIndex = i; | ||
17350 | } | ||
17351 | |||
17352 | function captionOptionsMenuTemplate() { | ||
17353 | var template = '<div class="vjs-tracksettings">\n <div class="vjs-tracksettings-colors">\n <div class="vjs-fg-color vjs-tracksetting">\n <label class="vjs-label">Foreground</label>\n <select>\n <option value="">---</option>\n <option value="#FFF">White</option>\n <option value="#000">Black</option>\n <option value="#F00">Red</option>\n <option value="#0F0">Green</option>\n <option value="#00F">Blue</option>\n <option value="#FF0">Yellow</option>\n <option value="#F0F">Magenta</option>\n <option value="#0FF">Cyan</option>\n </select>\n <span class="vjs-text-opacity vjs-opacity">\n <select>\n <option value="">---</option>\n <option value="1">Opaque</option>\n <option value="0.5">Semi-Opaque</option>\n </select>\n </span>\n </div> <!-- vjs-fg-color -->\n <div class="vjs-bg-color vjs-tracksetting">\n <label class="vjs-label">Background</label>\n <select>\n <option value="">---</option>\n <option value="#FFF">White</option>\n <option value="#000">Black</option>\n <option value="#F00">Red</option>\n <option value="#0F0">Green</option>\n <option value="#00F">Blue</option>\n <option value="#FF0">Yellow</option>\n <option value="#F0F">Magenta</option>\n <option value="#0FF">Cyan</option>\n </select>\n <span class="vjs-bg-opacity vjs-opacity">\n <select>\n <option value="">---</option>\n <option value="1">Opaque</option>\n <option value="0.5">Semi-Transparent</option>\n <option value="0">Transparent</option>\n </select>\n </span>\n </div> <!-- vjs-bg-color -->\n <div class="window-color vjs-tracksetting">\n <label class="vjs-label">Window</label>\n <select>\n <option value="">---</option>\n <option value="#FFF">White</option>\n <option value="#000">Black</option>\n <option value="#F00">Red</option>\n <option value="#0F0">Green</option>\n <option value="#00F">Blue</option>\n <option value="#FF0">Yellow</option>\n <option value="#F0F">Magenta</option>\n <option value="#0FF">Cyan</option>\n </select>\n <span class="vjs-window-opacity vjs-opacity">\n <select>\n <option value="">---</option>\n <option value="1">Opaque</option>\n <option value="0.5">Semi-Transparent</option>\n <option value="0">Transparent</option>\n </select>\n </span>\n </div> <!-- vjs-window-color -->\n </div> <!-- vjs-tracksettings -->\n <div class="vjs-tracksettings-font">\n <div class="vjs-font-percent vjs-tracksetting">\n <label class="vjs-label">Font Size</label>\n <select>\n <option value="0.50">50%</option>\n <option value="0.75">75%</option>\n <option value="1.00" selected>100%</option>\n <option value="1.25">125%</option>\n <option value="1.50">150%</option>\n <option value="1.75">175%</option>\n <option value="2.00">200%</option>\n <option value="3.00">300%</option>\n <option value="4.00">400%</option>\n </select>\n </div> <!-- vjs-font-percent -->\n <div class="vjs-edge-style vjs-tracksetting">\n <label class="vjs-label">Text Edge Style</label>\n <select>\n <option value="none">None</option>\n <option value="raised">Raised</option>\n <option value="depressed">Depressed</option>\n <option value="uniform">Uniform</option>\n <option value="dropshadow">Dropshadow</option>\n </select>\n </div> <!-- vjs-edge-style -->\n <div class="vjs-font-family vjs-tracksetting">\n <label class="vjs-label">Font Family</label>\n <select>\n <option value="">Default</option>\n <option value="monospaceSerif">Monospace Serif</option>\n <option value="proportionalSerif">Proportional Serif</option>\n <option value="monospaceSansSerif">Monospace Sans-Serif</option>\n <option value="proportionalSansSerif">Proportional Sans-Serif</option>\n <option value="casual">Casual</option>\n <option value="script">Script</option>\n <option value="small-caps">Small Caps</option>\n </select>\n </div> <!-- vjs-font-family -->\n </div>\n </div>\n <div class="vjs-tracksettings-controls">\n <button class="vjs-default-button">Defaults</button>\n <button class="vjs-done-button">Done</button>\n </div>'; | ||
17354 | |||
17355 | return template; | ||
17356 | } | ||
17357 | |||
17358 | exports['default'] = TextTrackSettings; | ||
17359 | module.exports = exports['default']; | ||
17360 | |||
17361 | },{"../component":67,"../utils/events.js":133,"../utils/fn.js":134,"../utils/log.js":137,"global/window":2,"safe-json-parse/tuple":54}],128:[function(_dereq_,module,exports){ | ||
17362 | /** | ||
17363 | * @file text-track.js | ||
17364 | */ | ||
17365 | 'use strict'; | ||
17366 | |||
17367 | exports.__esModule = true; | ||
17368 | |||
17369 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
17370 | |||
17371 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
17372 | |||
17373 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
17374 | |||
17375 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
17376 | |||
17377 | var _textTrackCueList = _dereq_('./text-track-cue-list'); | ||
17378 | |||
17379 | var _textTrackCueList2 = _interopRequireDefault(_textTrackCueList); | ||
17380 | |||
17381 | var _utilsFnJs = _dereq_('../utils/fn.js'); | ||
17382 | |||
17383 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
17384 | |||
17385 | var _utilsGuidJs = _dereq_('../utils/guid.js'); | ||
17386 | |||
17387 | var Guid = _interopRequireWildcard(_utilsGuidJs); | ||
17388 | |||
17389 | var _utilsBrowserJs = _dereq_('../utils/browser.js'); | ||
17390 | |||
17391 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
17392 | |||
17393 | var _textTrackEnums = _dereq_('./text-track-enums'); | ||
17394 | |||
17395 | var TextTrackEnum = _interopRequireWildcard(_textTrackEnums); | ||
17396 | |||
17397 | var _utilsLogJs = _dereq_('../utils/log.js'); | ||
17398 | |||
17399 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
17400 | |||
17401 | var _eventTarget = _dereq_('../event-target'); | ||
17402 | |||
17403 | var _eventTarget2 = _interopRequireDefault(_eventTarget); | ||
17404 | |||
17405 | var _globalDocument = _dereq_('global/document'); | ||
17406 | |||
17407 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
17408 | |||
17409 | var _globalWindow = _dereq_('global/window'); | ||
17410 | |||
17411 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
17412 | |||
17413 | var _utilsUrlJs = _dereq_('../utils/url.js'); | ||
17414 | |||
17415 | var _xhr = _dereq_('xhr'); | ||
17416 | |||
17417 | var _xhr2 = _interopRequireDefault(_xhr); | ||
17418 | |||
17419 | /** | ||
17420 | * takes a webvtt file contents and parses it into cues | ||
17421 | * | ||
17422 | * @param {String} srcContent webVTT file contents | ||
17423 | * @param {Track} track track to addcues to | ||
17424 | */ | ||
17425 | var parseCues = function parseCues(srcContent, track) { | ||
17426 | var parser = new _globalWindow2['default'].WebVTT.Parser(_globalWindow2['default'], _globalWindow2['default'].vttjs, _globalWindow2['default'].WebVTT.StringDecoder()); | ||
17427 | |||
17428 | parser.oncue = function (cue) { | ||
17429 | track.addCue(cue); | ||
17430 | }; | ||
17431 | |||
17432 | parser.onparsingerror = function (error) { | ||
17433 | _utilsLogJs2['default'].error(error); | ||
17434 | }; | ||
17435 | |||
17436 | parser.onflush = function () { | ||
17437 | track.trigger({ | ||
17438 | type: 'loadeddata', | ||
17439 | target: track | ||
17440 | }); | ||
17441 | }; | ||
17442 | |||
17443 | parser.parse(srcContent); | ||
17444 | parser.flush(); | ||
17445 | }; | ||
17446 | |||
17447 | /** | ||
17448 | * load a track from a specifed url | ||
17449 | * | ||
17450 | * @param {String} src url to load track from | ||
17451 | * @param {Track} track track to addcues to | ||
17452 | */ | ||
17453 | var loadTrack = function loadTrack(src, track) { | ||
17454 | var opts = { | ||
17455 | uri: src | ||
17456 | }; | ||
17457 | var crossOrigin = _utilsUrlJs.isCrossOrigin(src); | ||
17458 | |||
17459 | if (crossOrigin) { | ||
17460 | opts.cors = crossOrigin; | ||
17461 | } | ||
17462 | |||
17463 | _xhr2['default'](opts, Fn.bind(this, function (err, response, responseBody) { | ||
17464 | if (err) { | ||
17465 | return _utilsLogJs2['default'].error(err, response); | ||
17466 | } | ||
17467 | |||
17468 | track.loaded_ = true; | ||
17469 | |||
17470 | // Make sure that vttjs has loaded, otherwise, wait till it finished loading | ||
17471 | // NOTE: this is only used for the alt/video.novtt.js build | ||
17472 | if (typeof _globalWindow2['default'].WebVTT !== 'function') { | ||
17473 | if (track.tech_) { | ||
17474 | (function () { | ||
17475 | var loadHandler = function loadHandler() { | ||
17476 | return parseCues(responseBody, track); | ||
17477 | }; | ||
17478 | track.tech_.on('vttjsloaded', loadHandler); | ||
17479 | track.tech_.on('vttjserror', function () { | ||
17480 | _utilsLogJs2['default'].error('vttjs failed to load, stopping trying to process ' + track.src); | ||
17481 | track.tech_.off('vttjsloaded', loadHandler); | ||
17482 | }); | ||
17483 | })(); | ||
17484 | } | ||
17485 | } else { | ||
17486 | parseCues(responseBody, track); | ||
17487 | } | ||
17488 | })); | ||
17489 | }; | ||
17490 | |||
17491 | /** | ||
17492 | * A single text track as defined in: | ||
17493 | * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack | ||
17494 | * | ||
17495 | * interface TextTrack : EventTarget { | ||
17496 | * readonly attribute TextTrackKind kind; | ||
17497 | * readonly attribute DOMString label; | ||
17498 | * readonly attribute DOMString language; | ||
17499 | * | ||
17500 | * readonly attribute DOMString id; | ||
17501 | * readonly attribute DOMString inBandMetadataTrackDispatchType; | ||
17502 | * | ||
17503 | * attribute TextTrackMode mode; | ||
17504 | * | ||
17505 | * readonly attribute TextTrackCueList? cues; | ||
17506 | * readonly attribute TextTrackCueList? activeCues; | ||
17507 | * | ||
17508 | * void addCue(TextTrackCue cue); | ||
17509 | * void removeCue(TextTrackCue cue); | ||
17510 | * | ||
17511 | * attribute EventHandler oncuechange; | ||
17512 | * }; | ||
17513 | * | ||
17514 | * @param {Object=} options Object of option names and values | ||
17515 | * @extends EventTarget | ||
17516 | * @class TextTrack | ||
17517 | */ | ||
17518 | |||
17519 | var TextTrack = (function (_EventTarget) { | ||
17520 | _inherits(TextTrack, _EventTarget); | ||
17521 | |||
17522 | function TextTrack() { | ||
17523 | var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
17524 | |||
17525 | _classCallCheck(this, TextTrack); | ||
17526 | |||
17527 | _EventTarget.call(this); | ||
17528 | if (!options.tech) { | ||
17529 | throw new Error('A tech was not provided.'); | ||
17530 | } | ||
17531 | |||
17532 | var tt = this; | ||
17533 | |||
17534 | if (browser.IS_IE8) { | ||
17535 | tt = _globalDocument2['default'].createElement('custom'); | ||
17536 | |||
17537 | for (var prop in TextTrack.prototype) { | ||
17538 | if (prop !== 'constructor') { | ||
17539 | tt[prop] = TextTrack.prototype[prop]; | ||
17540 | } | ||
17541 | } | ||
17542 | } | ||
17543 | |||
17544 | tt.tech_ = options.tech; | ||
17545 | |||
17546 | var mode = TextTrackEnum.TextTrackMode[options.mode] || 'disabled'; | ||
17547 | var kind = TextTrackEnum.TextTrackKind[options.kind] || 'subtitles'; | ||
17548 | var label = options.label || ''; | ||
17549 | var language = options.language || options.srclang || ''; | ||
17550 | var id = options.id || 'vjs_text_track_' + Guid.newGUID(); | ||
17551 | |||
17552 | if (kind === 'metadata' || kind === 'chapters') { | ||
17553 | mode = 'hidden'; | ||
17554 | } | ||
17555 | |||
17556 | tt.cues_ = []; | ||
17557 | tt.activeCues_ = []; | ||
17558 | |||
17559 | var cues = new _textTrackCueList2['default'](tt.cues_); | ||
17560 | var activeCues = new _textTrackCueList2['default'](tt.activeCues_); | ||
17561 | var changed = false; | ||
17562 | var timeupdateHandler = Fn.bind(tt, function () { | ||
17563 | this.activeCues; | ||
17564 | if (changed) { | ||
17565 | this.trigger('cuechange'); | ||
17566 | changed = false; | ||
17567 | } | ||
17568 | }); | ||
17569 | |||
17570 | if (mode !== 'disabled') { | ||
17571 | tt.tech_.on('timeupdate', timeupdateHandler); | ||
17572 | } | ||
17573 | |||
17574 | Object.defineProperty(tt, 'kind', { | ||
17575 | get: function get() { | ||
17576 | return kind; | ||
17577 | }, | ||
17578 | set: function set() {} | ||
17579 | }); | ||
17580 | |||
17581 | Object.defineProperty(tt, 'label', { | ||
17582 | get: function get() { | ||
17583 | return label; | ||
17584 | }, | ||
17585 | set: function set() {} | ||
17586 | }); | ||
17587 | |||
17588 | Object.defineProperty(tt, 'language', { | ||
17589 | get: function get() { | ||
17590 | return language; | ||
17591 | }, | ||
17592 | set: function set() {} | ||
17593 | }); | ||
17594 | |||
17595 | Object.defineProperty(tt, 'id', { | ||
17596 | get: function get() { | ||
17597 | return id; | ||
17598 | }, | ||
17599 | set: function set() {} | ||
17600 | }); | ||
17601 | |||
17602 | Object.defineProperty(tt, 'mode', { | ||
17603 | get: function get() { | ||
17604 | return mode; | ||
17605 | }, | ||
17606 | set: function set(newMode) { | ||
17607 | if (!TextTrackEnum.TextTrackMode[newMode]) { | ||
17608 | return; | ||
17609 | } | ||
17610 | mode = newMode; | ||
17611 | if (mode === 'showing') { | ||
17612 | this.tech_.on('timeupdate', timeupdateHandler); | ||
17613 | } | ||
17614 | this.trigger('modechange'); | ||
17615 | } | ||
17616 | }); | ||
17617 | |||
17618 | Object.defineProperty(tt, 'cues', { | ||
17619 | get: function get() { | ||
17620 | if (!this.loaded_) { | ||
17621 | return null; | ||
17622 | } | ||
17623 | |||
17624 | return cues; | ||
17625 | }, | ||
17626 | set: function set() {} | ||
17627 | }); | ||
17628 | |||
17629 | Object.defineProperty(tt, 'activeCues', { | ||
17630 | get: function get() { | ||
17631 | if (!this.loaded_) { | ||
17632 | return null; | ||
17633 | } | ||
17634 | |||
17635 | // nothing to do | ||
17636 | if (this.cues.length === 0) { | ||
17637 | return activeCues; | ||
17638 | } | ||
17639 | |||
17640 | var ct = this.tech_.currentTime(); | ||
17641 | var active = []; | ||
17642 | |||
17643 | for (var i = 0, l = this.cues.length; i < l; i++) { | ||
17644 | var cue = this.cues[i]; | ||
17645 | |||
17646 | if (cue.startTime <= ct && cue.endTime >= ct) { | ||
17647 | active.push(cue); | ||
17648 | } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) { | ||
17649 | active.push(cue); | ||
17650 | } | ||
17651 | } | ||
17652 | |||
17653 | changed = false; | ||
17654 | |||
17655 | if (active.length !== this.activeCues_.length) { | ||
17656 | changed = true; | ||
17657 | } else { | ||
17658 | for (var i = 0; i < active.length; i++) { | ||
17659 | if (this.activeCues_.indexOf(active[i]) === -1) { | ||
17660 | changed = true; | ||
17661 | } | ||
17662 | } | ||
17663 | } | ||
17664 | |||
17665 | this.activeCues_ = active; | ||
17666 | activeCues.setCues_(this.activeCues_); | ||
17667 | |||
17668 | return activeCues; | ||
17669 | }, | ||
17670 | set: function set() {} | ||
17671 | }); | ||
17672 | |||
17673 | if (options.src) { | ||
17674 | tt.src = options.src; | ||
17675 | loadTrack(options.src, tt); | ||
17676 | } else { | ||
17677 | tt.loaded_ = true; | ||
17678 | } | ||
17679 | |||
17680 | if (browser.IS_IE8) { | ||
17681 | return tt; | ||
17682 | } | ||
17683 | } | ||
17684 | |||
17685 | /** | ||
17686 | * cuechange - One or more cues in the track have become active or stopped being active. | ||
17687 | */ | ||
17688 | |||
17689 | /** | ||
17690 | * add a cue to the internal list of cues | ||
17691 | * | ||
17692 | * @param {Object} cue the cue to add to our internal list | ||
17693 | * @method addCue | ||
17694 | */ | ||
17695 | |||
17696 | TextTrack.prototype.addCue = function addCue(cue) { | ||
17697 | var tracks = this.tech_.textTracks(); | ||
17698 | |||
17699 | if (tracks) { | ||
17700 | for (var i = 0; i < tracks.length; i++) { | ||
17701 | if (tracks[i] !== this) { | ||
17702 | tracks[i].removeCue(cue); | ||
17703 | } | ||
17704 | } | ||
17705 | } | ||
17706 | |||
17707 | this.cues_.push(cue); | ||
17708 | this.cues.setCues_(this.cues_); | ||
17709 | }; | ||
17710 | |||
17711 | /** | ||
17712 | * remvoe a cue from our internal list | ||
17713 | * | ||
17714 | * @param {Object} removeCue the cue to remove from our internal list | ||
17715 | * @method removeCue | ||
17716 | */ | ||
17717 | |||
17718 | TextTrack.prototype.removeCue = function removeCue(_removeCue) { | ||
17719 | var removed = false; | ||
17720 | |||
17721 | for (var i = 0, l = this.cues_.length; i < l; i++) { | ||
17722 | var cue = this.cues_[i]; | ||
17723 | |||
17724 | if (cue === _removeCue) { | ||
17725 | this.cues_.splice(i, 1); | ||
17726 | removed = true; | ||
17727 | } | ||
17728 | } | ||
17729 | |||
17730 | if (removed) { | ||
17731 | this.cues.setCues_(this.cues_); | ||
17732 | } | ||
17733 | }; | ||
17734 | |||
17735 | return TextTrack; | ||
17736 | })(_eventTarget2['default']); | ||
17737 | |||
17738 | TextTrack.prototype.allowedEvents_ = { | ||
17739 | cuechange: 'cuechange' | ||
17740 | }; | ||
17741 | |||
17742 | exports['default'] = TextTrack; | ||
17743 | module.exports = exports['default']; | ||
17744 | |||
17745 | },{"../event-target":99,"../utils/browser.js":129,"../utils/fn.js":134,"../utils/guid.js":136,"../utils/log.js":137,"../utils/url.js":142,"./text-track-cue-list":122,"./text-track-enums":124,"global/document":1,"global/window":2,"xhr":56}],129:[function(_dereq_,module,exports){ | ||
17746 | /** | ||
17747 | * @file browser.js | ||
17748 | */ | ||
17749 | 'use strict'; | ||
17750 | |||
17751 | exports.__esModule = true; | ||
17752 | |||
17753 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
17754 | |||
17755 | var _globalDocument = _dereq_('global/document'); | ||
17756 | |||
17757 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
17758 | |||
17759 | var _globalWindow = _dereq_('global/window'); | ||
17760 | |||
17761 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
17762 | |||
17763 | var USER_AGENT = _globalWindow2['default'].navigator.userAgent; | ||
17764 | var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT); | ||
17765 | var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null; | ||
17766 | |||
17767 | /* | ||
17768 | * Device is an iPhone | ||
17769 | * | ||
17770 | * @type {Boolean} | ||
17771 | * @constant | ||
17772 | * @private | ||
17773 | */ | ||
17774 | var IS_IPAD = /iPad/i.test(USER_AGENT); | ||
17775 | |||
17776 | exports.IS_IPAD = IS_IPAD; | ||
17777 | // The Facebook app's UIWebView identifies as both an iPhone and iPad, so | ||
17778 | // to identify iPhones, we need to exclude iPads. | ||
17779 | // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/ | ||
17780 | var IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD; | ||
17781 | exports.IS_IPHONE = IS_IPHONE; | ||
17782 | var IS_IPOD = /iPod/i.test(USER_AGENT); | ||
17783 | exports.IS_IPOD = IS_IPOD; | ||
17784 | var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD; | ||
17785 | |||
17786 | exports.IS_IOS = IS_IOS; | ||
17787 | var IOS_VERSION = (function () { | ||
17788 | var match = USER_AGENT.match(/OS (\d+)_/i); | ||
17789 | if (match && match[1]) { | ||
17790 | return match[1]; | ||
17791 | } | ||
17792 | })(); | ||
17793 | |||
17794 | exports.IOS_VERSION = IOS_VERSION; | ||
17795 | var IS_ANDROID = /Android/i.test(USER_AGENT); | ||
17796 | exports.IS_ANDROID = IS_ANDROID; | ||
17797 | var ANDROID_VERSION = (function () { | ||
17798 | // This matches Android Major.Minor.Patch versions | ||
17799 | // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned | ||
17800 | var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i), | ||
17801 | major, | ||
17802 | minor; | ||
17803 | |||
17804 | if (!match) { | ||
17805 | return null; | ||
17806 | } | ||
17807 | |||
17808 | major = match[1] && parseFloat(match[1]); | ||
17809 | minor = match[2] && parseFloat(match[2]); | ||
17810 | |||
17811 | if (major && minor) { | ||
17812 | return parseFloat(match[1] + '.' + match[2]); | ||
17813 | } else if (major) { | ||
17814 | return major; | ||
17815 | } else { | ||
17816 | return null; | ||
17817 | } | ||
17818 | })(); | ||
17819 | exports.ANDROID_VERSION = ANDROID_VERSION; | ||
17820 | // Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser | ||
17821 | var IS_OLD_ANDROID = IS_ANDROID && /webkit/i.test(USER_AGENT) && ANDROID_VERSION < 2.3; | ||
17822 | exports.IS_OLD_ANDROID = IS_OLD_ANDROID; | ||
17823 | var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537; | ||
17824 | |||
17825 | exports.IS_NATIVE_ANDROID = IS_NATIVE_ANDROID; | ||
17826 | var IS_FIREFOX = /Firefox/i.test(USER_AGENT); | ||
17827 | exports.IS_FIREFOX = IS_FIREFOX; | ||
17828 | var IS_CHROME = /Chrome/i.test(USER_AGENT); | ||
17829 | exports.IS_CHROME = IS_CHROME; | ||
17830 | var IS_IE8 = /MSIE\s8\.0/.test(USER_AGENT); | ||
17831 | |||
17832 | exports.IS_IE8 = IS_IE8; | ||
17833 | var TOUCH_ENABLED = !!('ontouchstart' in _globalWindow2['default'] || _globalWindow2['default'].DocumentTouch && _globalDocument2['default'] instanceof _globalWindow2['default'].DocumentTouch); | ||
17834 | exports.TOUCH_ENABLED = TOUCH_ENABLED; | ||
17835 | var BACKGROUND_SIZE_SUPPORTED = ('backgroundSize' in _globalDocument2['default'].createElement('video').style); | ||
17836 | exports.BACKGROUND_SIZE_SUPPORTED = BACKGROUND_SIZE_SUPPORTED; | ||
17837 | |||
17838 | },{"global/document":1,"global/window":2}],130:[function(_dereq_,module,exports){ | ||
17839 | /** | ||
17840 | * @file buffer.js | ||
17841 | */ | ||
17842 | 'use strict'; | ||
17843 | |||
17844 | exports.__esModule = true; | ||
17845 | exports.bufferedPercent = bufferedPercent; | ||
17846 | |||
17847 | var _timeRangesJs = _dereq_('./time-ranges.js'); | ||
17848 | |||
17849 | /** | ||
17850 | * Compute how much your video has been buffered | ||
17851 | * | ||
17852 | * @param {Object} Buffered object | ||
17853 | * @param {Number} Total duration | ||
17854 | * @return {Number} Percent buffered of the total duration | ||
17855 | * @private | ||
17856 | * @function bufferedPercent | ||
17857 | */ | ||
17858 | |||
17859 | function bufferedPercent(buffered, duration) { | ||
17860 | var bufferedDuration = 0, | ||
17861 | start, | ||
17862 | end; | ||
17863 | |||
17864 | if (!duration) { | ||
17865 | return 0; | ||
17866 | } | ||
17867 | |||
17868 | if (!buffered || !buffered.length) { | ||
17869 | buffered = _timeRangesJs.createTimeRange(0, 0); | ||
17870 | } | ||
17871 | |||
17872 | for (var i = 0; i < buffered.length; i++) { | ||
17873 | start = buffered.start(i); | ||
17874 | end = buffered.end(i); | ||
17875 | |||
17876 | // buffered end can be bigger than duration by a very small fraction | ||
17877 | if (end > duration) { | ||
17878 | end = duration; | ||
17879 | } | ||
17880 | |||
17881 | bufferedDuration += end - start; | ||
17882 | } | ||
17883 | |||
17884 | return bufferedDuration / duration; | ||
17885 | } | ||
17886 | |||
17887 | },{"./time-ranges.js":140}],131:[function(_dereq_,module,exports){ | ||
17888 | 'use strict'; | ||
17889 | |||
17890 | exports.__esModule = true; | ||
17891 | |||
17892 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
17893 | |||
17894 | var _logJs = _dereq_('./log.js'); | ||
17895 | |||
17896 | var _logJs2 = _interopRequireDefault(_logJs); | ||
17897 | |||
17898 | /** | ||
17899 | * Object containing the default behaviors for available handler methods. | ||
17900 | * | ||
17901 | * @private | ||
17902 | * @type {Object} | ||
17903 | */ | ||
17904 | var defaultBehaviors = { | ||
17905 | get: function get(obj, key) { | ||
17906 | return obj[key]; | ||
17907 | }, | ||
17908 | set: function set(obj, key, value) { | ||
17909 | obj[key] = value; | ||
17910 | return true; | ||
17911 | } | ||
17912 | }; | ||
17913 | |||
17914 | /** | ||
17915 | * Expose private objects publicly using a Proxy to log deprecation warnings. | ||
17916 | * | ||
17917 | * Browsers that do not support Proxy objects will simply return the `target` | ||
17918 | * object, so it can be directly exposed. | ||
17919 | * | ||
17920 | * @param {Object} target The target object. | ||
17921 | * @param {Object} messages Messages to display from a Proxy. Only operations | ||
17922 | * with an associated message will be proxied. | ||
17923 | * @param {String} [messages.get] | ||
17924 | * @param {String} [messages.set] | ||
17925 | * @return {Object} A Proxy if supported or the `target` argument. | ||
17926 | */ | ||
17927 | |||
17928 | exports['default'] = function (target) { | ||
17929 | var messages = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
17930 | |||
17931 | if (typeof Proxy === 'function') { | ||
17932 | var _ret = (function () { | ||
17933 | var handler = {}; | ||
17934 | |||
17935 | // Build a handler object based on those keys that have both messages | ||
17936 | // and default behaviors. | ||
17937 | Object.keys(messages).forEach(function (key) { | ||
17938 | if (defaultBehaviors.hasOwnProperty(key)) { | ||
17939 | handler[key] = function () { | ||
17940 | _logJs2['default'].warn(messages[key]); | ||
17941 | return defaultBehaviors[key].apply(this, arguments); | ||
17942 | }; | ||
17943 | } | ||
17944 | }); | ||
17945 | |||
17946 | return { | ||
17947 | v: new Proxy(target, handler) | ||
17948 | }; | ||
17949 | })(); | ||
17950 | |||
17951 | if (typeof _ret === 'object') return _ret.v; | ||
17952 | } | ||
17953 | return target; | ||
17954 | }; | ||
17955 | |||
17956 | module.exports = exports['default']; | ||
17957 | |||
17958 | },{"./log.js":137}],132:[function(_dereq_,module,exports){ | ||
17959 | /** | ||
17960 | * @file dom.js | ||
17961 | */ | ||
17962 | 'use strict'; | ||
17963 | |||
17964 | exports.__esModule = true; | ||
17965 | exports.getEl = getEl; | ||
17966 | exports.createEl = createEl; | ||
17967 | exports.textContent = textContent; | ||
17968 | exports.insertElFirst = insertElFirst; | ||
17969 | exports.getElData = getElData; | ||
17970 | exports.hasElData = hasElData; | ||
17971 | exports.removeElData = removeElData; | ||
17972 | exports.hasElClass = hasElClass; | ||
17973 | exports.addElClass = addElClass; | ||
17974 | exports.removeElClass = removeElClass; | ||
17975 | exports.toggleElClass = toggleElClass; | ||
17976 | exports.setElAttributes = setElAttributes; | ||
17977 | exports.getElAttributes = getElAttributes; | ||
17978 | exports.blockTextSelection = blockTextSelection; | ||
17979 | exports.unblockTextSelection = unblockTextSelection; | ||
17980 | exports.findElPosition = findElPosition; | ||
17981 | exports.getPointerPosition = getPointerPosition; | ||
17982 | exports.isEl = isEl; | ||
17983 | exports.isTextNode = isTextNode; | ||
17984 | exports.emptyEl = emptyEl; | ||
17985 | exports.normalizeContent = normalizeContent; | ||
17986 | exports.appendContent = appendContent; | ||
17987 | exports.insertContent = insertContent; | ||
17988 | |||
17989 | var _templateObject = _taggedTemplateLiteralLoose(['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.'], ['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.']); | ||
17990 | |||
17991 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
17992 | |||
17993 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
17994 | |||
17995 | function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; } | ||
17996 | |||
17997 | var _globalDocument = _dereq_('global/document'); | ||
17998 | |||
17999 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
18000 | |||
18001 | var _globalWindow = _dereq_('global/window'); | ||
18002 | |||
18003 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
18004 | |||
18005 | var _guidJs = _dereq_('./guid.js'); | ||
18006 | |||
18007 | var Guid = _interopRequireWildcard(_guidJs); | ||
18008 | |||
18009 | var _logJs = _dereq_('./log.js'); | ||
18010 | |||
18011 | var _logJs2 = _interopRequireDefault(_logJs); | ||
18012 | |||
18013 | var _tsml = _dereq_('tsml'); | ||
18014 | |||
18015 | var _tsml2 = _interopRequireDefault(_tsml); | ||
18016 | |||
18017 | /** | ||
18018 | * Detect if a value is a string with any non-whitespace characters. | ||
18019 | * | ||
18020 | * @param {String} str | ||
18021 | * @return {Boolean} | ||
18022 | */ | ||
18023 | function isNonBlankString(str) { | ||
18024 | return typeof str === 'string' && /\S/.test(str); | ||
18025 | } | ||
18026 | |||
18027 | /** | ||
18028 | * Throws an error if the passed string has whitespace. This is used by | ||
18029 | * class methods to be relatively consistent with the classList API. | ||
18030 | * | ||
18031 | * @param {String} str | ||
18032 | * @return {Boolean} | ||
18033 | */ | ||
18034 | function throwIfWhitespace(str) { | ||
18035 | if (/\s/.test(str)) { | ||
18036 | throw new Error('class has illegal whitespace characters'); | ||
18037 | } | ||
18038 | } | ||
18039 | |||
18040 | /** | ||
18041 | * Produce a regular expression for matching a class name. | ||
18042 | * | ||
18043 | * @param {String} className | ||
18044 | * @return {RegExp} | ||
18045 | */ | ||
18046 | function classRegExp(className) { | ||
18047 | return new RegExp('(^|\\s)' + className + '($|\\s)'); | ||
18048 | } | ||
18049 | |||
18050 | /** | ||
18051 | * Creates functions to query the DOM using a given method. | ||
18052 | * | ||
18053 | * @function createQuerier | ||
18054 | * @private | ||
18055 | * @param {String} method | ||
18056 | * @return {Function} | ||
18057 | */ | ||
18058 | function createQuerier(method) { | ||
18059 | return function (selector, context) { | ||
18060 | if (!isNonBlankString(selector)) { | ||
18061 | return _globalDocument2['default'][method](null); | ||
18062 | } | ||
18063 | if (isNonBlankString(context)) { | ||
18064 | context = _globalDocument2['default'].querySelector(context); | ||
18065 | } | ||
18066 | return (isEl(context) ? context : _globalDocument2['default'])[method](selector); | ||
18067 | }; | ||
18068 | } | ||
18069 | |||
18070 | /** | ||
18071 | * Shorthand for document.getElementById() | ||
18072 | * Also allows for CSS (jQuery) ID syntax. But nothing other than IDs. | ||
18073 | * | ||
18074 | * @param {String} id Element ID | ||
18075 | * @return {Element} Element with supplied ID | ||
18076 | * @function getEl | ||
18077 | */ | ||
18078 | |||
18079 | function getEl(id) { | ||
18080 | if (id.indexOf('#') === 0) { | ||
18081 | id = id.slice(1); | ||
18082 | } | ||
18083 | |||
18084 | return _globalDocument2['default'].getElementById(id); | ||
18085 | } | ||
18086 | |||
18087 | /** | ||
18088 | * Creates an element and applies properties. | ||
18089 | * | ||
18090 | * @param {String} [tagName='div'] Name of tag to be created. | ||
18091 | * @param {Object} [properties={}] Element properties to be applied. | ||
18092 | * @param {Object} [attributes={}] Element attributes to be applied. | ||
18093 | * @return {Element} | ||
18094 | * @function createEl | ||
18095 | */ | ||
18096 | |||
18097 | function createEl() { | ||
18098 | var tagName = arguments.length <= 0 || arguments[0] === undefined ? 'div' : arguments[0]; | ||
18099 | var properties = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
18100 | var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; | ||
18101 | |||
18102 | var el = _globalDocument2['default'].createElement(tagName); | ||
18103 | |||
18104 | Object.getOwnPropertyNames(properties).forEach(function (propName) { | ||
18105 | var val = properties[propName]; | ||
18106 | |||
18107 | // See #2176 | ||
18108 | // We originally were accepting both properties and attributes in the | ||
18109 | // same object, but that doesn't work so well. | ||
18110 | if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') { | ||
18111 | _logJs2['default'].warn(_tsml2['default'](_templateObject, propName, val)); | ||
18112 | el.setAttribute(propName, val); | ||
18113 | } else { | ||
18114 | el[propName] = val; | ||
18115 | } | ||
18116 | }); | ||
18117 | |||
18118 | Object.getOwnPropertyNames(attributes).forEach(function (attrName) { | ||
18119 | var val = attributes[attrName]; | ||
18120 | el.setAttribute(attrName, attributes[attrName]); | ||
18121 | }); | ||
18122 | |||
18123 | return el; | ||
18124 | } | ||
18125 | |||
18126 | /** | ||
18127 | * Injects text into an element, replacing any existing contents entirely. | ||
18128 | * | ||
18129 | * @param {Element} el | ||
18130 | * @param {String} text | ||
18131 | * @return {Element} | ||
18132 | * @function textContent | ||
18133 | */ | ||
18134 | |||
18135 | function textContent(el, text) { | ||
18136 | if (typeof el.textContent === 'undefined') { | ||
18137 | el.innerText = text; | ||
18138 | } else { | ||
18139 | el.textContent = text; | ||
18140 | } | ||
18141 | } | ||
18142 | |||
18143 | /** | ||
18144 | * Insert an element as the first child node of another | ||
18145 | * | ||
18146 | * @param {Element} child Element to insert | ||
18147 | * @param {Element} parent Element to insert child into | ||
18148 | * @private | ||
18149 | * @function insertElFirst | ||
18150 | */ | ||
18151 | |||
18152 | function insertElFirst(child, parent) { | ||
18153 | if (parent.firstChild) { | ||
18154 | parent.insertBefore(child, parent.firstChild); | ||
18155 | } else { | ||
18156 | parent.appendChild(child); | ||
18157 | } | ||
18158 | } | ||
18159 | |||
18160 | /** | ||
18161 | * Element Data Store. Allows for binding data to an element without putting it directly on the element. | ||
18162 | * Ex. Event listeners are stored here. | ||
18163 | * (also from jsninja.com, slightly modified and updated for closure compiler) | ||
18164 | * | ||
18165 | * @type {Object} | ||
18166 | * @private | ||
18167 | */ | ||
18168 | var elData = {}; | ||
18169 | |||
18170 | /* | ||
18171 | * Unique attribute name to store an element's guid in | ||
18172 | * | ||
18173 | * @type {String} | ||
18174 | * @constant | ||
18175 | * @private | ||
18176 | */ | ||
18177 | var elIdAttr = 'vdata' + new Date().getTime(); | ||
18178 | |||
18179 | /** | ||
18180 | * Returns the cache object where data for an element is stored | ||
18181 | * | ||
18182 | * @param {Element} el Element to store data for. | ||
18183 | * @return {Object} | ||
18184 | * @function getElData | ||
18185 | */ | ||
18186 | |||
18187 | function getElData(el) { | ||
18188 | var id = el[elIdAttr]; | ||
18189 | |||
18190 | if (!id) { | ||
18191 | id = el[elIdAttr] = Guid.newGUID(); | ||
18192 | } | ||
18193 | |||
18194 | if (!elData[id]) { | ||
18195 | elData[id] = {}; | ||
18196 | } | ||
18197 | |||
18198 | return elData[id]; | ||
18199 | } | ||
18200 | |||
18201 | /** | ||
18202 | * Returns whether or not an element has cached data | ||
18203 | * | ||
18204 | * @param {Element} el A dom element | ||
18205 | * @return {Boolean} | ||
18206 | * @private | ||
18207 | * @function hasElData | ||
18208 | */ | ||
18209 | |||
18210 | function hasElData(el) { | ||
18211 | var id = el[elIdAttr]; | ||
18212 | |||
18213 | if (!id) { | ||
18214 | return false; | ||
18215 | } | ||
18216 | |||
18217 | return !!Object.getOwnPropertyNames(elData[id]).length; | ||
18218 | } | ||
18219 | |||
18220 | /** | ||
18221 | * Delete data for the element from the cache and the guid attr from getElementById | ||
18222 | * | ||
18223 | * @param {Element} el Remove data for an element | ||
18224 | * @private | ||
18225 | * @function removeElData | ||
18226 | */ | ||
18227 | |||
18228 | function removeElData(el) { | ||
18229 | var id = el[elIdAttr]; | ||
18230 | |||
18231 | if (!id) { | ||
18232 | return; | ||
18233 | } | ||
18234 | |||
18235 | // Remove all stored data | ||
18236 | delete elData[id]; | ||
18237 | |||
18238 | // Remove the elIdAttr property from the DOM node | ||
18239 | try { | ||
18240 | delete el[elIdAttr]; | ||
18241 | } catch (e) { | ||
18242 | if (el.removeAttribute) { | ||
18243 | el.removeAttribute(elIdAttr); | ||
18244 | } else { | ||
18245 | // IE doesn't appear to support removeAttribute on the document element | ||
18246 | el[elIdAttr] = null; | ||
18247 | } | ||
18248 | } | ||
18249 | } | ||
18250 | |||
18251 | /** | ||
18252 | * Check if an element has a CSS class | ||
18253 | * | ||
18254 | * @function hasElClass | ||
18255 | * @param {Element} element Element to check | ||
18256 | * @param {String} classToCheck Classname to check | ||
18257 | */ | ||
18258 | |||
18259 | function hasElClass(element, classToCheck) { | ||
18260 | if (element.classList) { | ||
18261 | return element.classList.contains(classToCheck); | ||
18262 | } else { | ||
18263 | throwIfWhitespace(classToCheck); | ||
18264 | return classRegExp(classToCheck).test(element.className); | ||
18265 | } | ||
18266 | } | ||
18267 | |||
18268 | /** | ||
18269 | * Add a CSS class name to an element | ||
18270 | * | ||
18271 | * @function addElClass | ||
18272 | * @param {Element} element Element to add class name to | ||
18273 | * @param {String} classToAdd Classname to add | ||
18274 | */ | ||
18275 | |||
18276 | function addElClass(element, classToAdd) { | ||
18277 | if (element.classList) { | ||
18278 | element.classList.add(classToAdd); | ||
18279 | |||
18280 | // Don't need to `throwIfWhitespace` here because `hasElClass` will do it | ||
18281 | // in the case of classList not being supported. | ||
18282 | } else if (!hasElClass(element, classToAdd)) { | ||
18283 | element.className = (element.className + ' ' + classToAdd).trim(); | ||
18284 | } | ||
18285 | |||
18286 | return element; | ||
18287 | } | ||
18288 | |||
18289 | /** | ||
18290 | * Remove a CSS class name from an element | ||
18291 | * | ||
18292 | * @function removeElClass | ||
18293 | * @param {Element} element Element to remove from class name | ||
18294 | * @param {String} classToRemove Classname to remove | ||
18295 | */ | ||
18296 | |||
18297 | function removeElClass(element, classToRemove) { | ||
18298 | if (element.classList) { | ||
18299 | element.classList.remove(classToRemove); | ||
18300 | } else { | ||
18301 | throwIfWhitespace(classToRemove); | ||
18302 | element.className = element.className.split(/\s+/).filter(function (c) { | ||
18303 | return c !== classToRemove; | ||
18304 | }).join(' '); | ||
18305 | } | ||
18306 | |||
18307 | return element; | ||
18308 | } | ||
18309 | |||
18310 | /** | ||
18311 | * Adds or removes a CSS class name on an element depending on an optional | ||
18312 | * condition or the presence/absence of the class name. | ||
18313 | * | ||
18314 | * @function toggleElClass | ||
18315 | * @param {Element} element | ||
18316 | * @param {String} classToToggle | ||
18317 | * @param {Boolean|Function} [predicate] | ||
18318 | * Can be a function that returns a Boolean. If `true`, the class | ||
18319 | * will be added; if `false`, the class will be removed. If not | ||
18320 | * given, the class will be added if not present and vice versa. | ||
18321 | */ | ||
18322 | |||
18323 | function toggleElClass(element, classToToggle, predicate) { | ||
18324 | |||
18325 | // This CANNOT use `classList` internally because IE does not support the | ||
18326 | // second parameter to the `classList.toggle()` method! Which is fine because | ||
18327 | // `classList` will be used by the add/remove functions. | ||
18328 | var has = hasElClass(element, classToToggle); | ||
18329 | |||
18330 | if (typeof predicate === 'function') { | ||
18331 | predicate = predicate(element, classToToggle); | ||
18332 | } | ||
18333 | |||
18334 | if (typeof predicate !== 'boolean') { | ||
18335 | predicate = !has; | ||
18336 | } | ||
18337 | |||
18338 | // If the necessary class operation matches the current state of the | ||
18339 | // element, no action is required. | ||
18340 | if (predicate === has) { | ||
18341 | return; | ||
18342 | } | ||
18343 | |||
18344 | if (predicate) { | ||
18345 | addElClass(element, classToToggle); | ||
18346 | } else { | ||
18347 | removeElClass(element, classToToggle); | ||
18348 | } | ||
18349 | |||
18350 | return element; | ||
18351 | } | ||
18352 | |||
18353 | /** | ||
18354 | * Apply attributes to an HTML element. | ||
18355 | * | ||
18356 | * @param {Element} el Target element. | ||
18357 | * @param {Object=} attributes Element attributes to be applied. | ||
18358 | * @private | ||
18359 | * @function setElAttributes | ||
18360 | */ | ||
18361 | |||
18362 | function setElAttributes(el, attributes) { | ||
18363 | Object.getOwnPropertyNames(attributes).forEach(function (attrName) { | ||
18364 | var attrValue = attributes[attrName]; | ||
18365 | |||
18366 | if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) { | ||
18367 | el.removeAttribute(attrName); | ||
18368 | } else { | ||
18369 | el.setAttribute(attrName, attrValue === true ? '' : attrValue); | ||
18370 | } | ||
18371 | }); | ||
18372 | } | ||
18373 | |||
18374 | /** | ||
18375 | * Get an element's attribute values, as defined on the HTML tag | ||
18376 | * Attributes are not the same as properties. They're defined on the tag | ||
18377 | * or with setAttribute (which shouldn't be used with HTML) | ||
18378 | * This will return true or false for boolean attributes. | ||
18379 | * | ||
18380 | * @param {Element} tag Element from which to get tag attributes | ||
18381 | * @return {Object} | ||
18382 | * @private | ||
18383 | * @function getElAttributes | ||
18384 | */ | ||
18385 | |||
18386 | function getElAttributes(tag) { | ||
18387 | var obj, knownBooleans, attrs, attrName, attrVal; | ||
18388 | |||
18389 | obj = {}; | ||
18390 | |||
18391 | // known boolean attributes | ||
18392 | // we can check for matching boolean properties, but older browsers | ||
18393 | // won't know about HTML5 boolean attributes that we still read from | ||
18394 | knownBooleans = ',' + 'autoplay,controls,loop,muted,default' + ','; | ||
18395 | |||
18396 | if (tag && tag.attributes && tag.attributes.length > 0) { | ||
18397 | attrs = tag.attributes; | ||
18398 | |||
18399 | for (var i = attrs.length - 1; i >= 0; i--) { | ||
18400 | attrName = attrs[i].name; | ||
18401 | attrVal = attrs[i].value; | ||
18402 | |||
18403 | // check for known booleans | ||
18404 | // the matching element property will return a value for typeof | ||
18405 | if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) { | ||
18406 | // the value of an included boolean attribute is typically an empty | ||
18407 | // string ('') which would equal false if we just check for a false value. | ||
18408 | // we also don't want support bad code like autoplay='false' | ||
18409 | attrVal = attrVal !== null ? true : false; | ||
18410 | } | ||
18411 | |||
18412 | obj[attrName] = attrVal; | ||
18413 | } | ||
18414 | } | ||
18415 | |||
18416 | return obj; | ||
18417 | } | ||
18418 | |||
18419 | /** | ||
18420 | * Attempt to block the ability to select text while dragging controls | ||
18421 | * | ||
18422 | * @return {Boolean} | ||
18423 | * @function blockTextSelection | ||
18424 | */ | ||
18425 | |||
18426 | function blockTextSelection() { | ||
18427 | _globalDocument2['default'].body.focus(); | ||
18428 | _globalDocument2['default'].onselectstart = function () { | ||
18429 | return false; | ||
18430 | }; | ||
18431 | } | ||
18432 | |||
18433 | /** | ||
18434 | * Turn off text selection blocking | ||
18435 | * | ||
18436 | * @return {Boolean} | ||
18437 | * @function unblockTextSelection | ||
18438 | */ | ||
18439 | |||
18440 | function unblockTextSelection() { | ||
18441 | _globalDocument2['default'].onselectstart = function () { | ||
18442 | return true; | ||
18443 | }; | ||
18444 | } | ||
18445 | |||
18446 | /** | ||
18447 | * Offset Left | ||
18448 | * getBoundingClientRect technique from | ||
18449 | * John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/ | ||
18450 | * | ||
18451 | * @function findElPosition | ||
18452 | * @param {Element} el Element from which to get offset | ||
18453 | * @return {Object} | ||
18454 | */ | ||
18455 | |||
18456 | function findElPosition(el) { | ||
18457 | var box = undefined; | ||
18458 | |||
18459 | if (el.getBoundingClientRect && el.parentNode) { | ||
18460 | box = el.getBoundingClientRect(); | ||
18461 | } | ||
18462 | |||
18463 | if (!box) { | ||
18464 | return { | ||
18465 | left: 0, | ||
18466 | top: 0 | ||
18467 | }; | ||
18468 | } | ||
18469 | |||
18470 | var docEl = _globalDocument2['default'].documentElement; | ||
18471 | var body = _globalDocument2['default'].body; | ||
18472 | |||
18473 | var clientLeft = docEl.clientLeft || body.clientLeft || 0; | ||
18474 | var scrollLeft = _globalWindow2['default'].pageXOffset || body.scrollLeft; | ||
18475 | var left = box.left + scrollLeft - clientLeft; | ||
18476 | |||
18477 | var clientTop = docEl.clientTop || body.clientTop || 0; | ||
18478 | var scrollTop = _globalWindow2['default'].pageYOffset || body.scrollTop; | ||
18479 | var top = box.top + scrollTop - clientTop; | ||
18480 | |||
18481 | // Android sometimes returns slightly off decimal values, so need to round | ||
18482 | return { | ||
18483 | left: Math.round(left), | ||
18484 | top: Math.round(top) | ||
18485 | }; | ||
18486 | } | ||
18487 | |||
18488 | /** | ||
18489 | * Get pointer position in element | ||
18490 | * Returns an object with x and y coordinates. | ||
18491 | * The base on the coordinates are the bottom left of the element. | ||
18492 | * | ||
18493 | * @function getPointerPosition | ||
18494 | * @param {Element} el Element on which to get the pointer position on | ||
18495 | * @param {Event} event Event object | ||
18496 | * @return {Object} This object will have x and y coordinates corresponding to the mouse position | ||
18497 | */ | ||
18498 | |||
18499 | function getPointerPosition(el, event) { | ||
18500 | var position = {}; | ||
18501 | var box = findElPosition(el); | ||
18502 | var boxW = el.offsetWidth; | ||
18503 | var boxH = el.offsetHeight; | ||
18504 | |||
18505 | var boxY = box.top; | ||
18506 | var boxX = box.left; | ||
18507 | var pageY = event.pageY; | ||
18508 | var pageX = event.pageX; | ||
18509 | |||
18510 | if (event.changedTouches) { | ||
18511 | pageX = event.changedTouches[0].pageX; | ||
18512 | pageY = event.changedTouches[0].pageY; | ||
18513 | } | ||
18514 | |||
18515 | position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH)); | ||
18516 | position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW)); | ||
18517 | |||
18518 | return position; | ||
18519 | } | ||
18520 | |||
18521 | /** | ||
18522 | * Determines, via duck typing, whether or not a value is a DOM element. | ||
18523 | * | ||
18524 | * @function isEl | ||
18525 | * @param {Mixed} value | ||
18526 | * @return {Boolean} | ||
18527 | */ | ||
18528 | |||
18529 | function isEl(value) { | ||
18530 | return !!value && typeof value === 'object' && value.nodeType === 1; | ||
18531 | } | ||
18532 | |||
18533 | /** | ||
18534 | * Determines, via duck typing, whether or not a value is a text node. | ||
18535 | * | ||
18536 | * @param {Mixed} value | ||
18537 | * @return {Boolean} | ||
18538 | */ | ||
18539 | |||
18540 | function isTextNode(value) { | ||
18541 | return !!value && typeof value === 'object' && value.nodeType === 3; | ||
18542 | } | ||
18543 | |||
18544 | /** | ||
18545 | * Empties the contents of an element. | ||
18546 | * | ||
18547 | * @function emptyEl | ||
18548 | * @param {Element} el | ||
18549 | * @return {Element} | ||
18550 | */ | ||
18551 | |||
18552 | function emptyEl(el) { | ||
18553 | while (el.firstChild) { | ||
18554 | el.removeChild(el.firstChild); | ||
18555 | } | ||
18556 | return el; | ||
18557 | } | ||
18558 | |||
18559 | /** | ||
18560 | * Normalizes content for eventual insertion into the DOM. | ||
18561 | * | ||
18562 | * This allows a wide range of content definition methods, but protects | ||
18563 | * from falling into the trap of simply writing to `innerHTML`, which is | ||
18564 | * an XSS concern. | ||
18565 | * | ||
18566 | * The content for an element can be passed in multiple types and | ||
18567 | * combinations, whose behavior is as follows: | ||
18568 | * | ||
18569 | * - String | ||
18570 | * Normalized into a text node. | ||
18571 | * | ||
18572 | * - Element, TextNode | ||
18573 | * Passed through. | ||
18574 | * | ||
18575 | * - Array | ||
18576 | * A one-dimensional array of strings, elements, nodes, or functions (which | ||
18577 | * return single strings, elements, or nodes). | ||
18578 | * | ||
18579 | * - Function | ||
18580 | * If the sole argument, is expected to produce a string, element, | ||
18581 | * node, or array. | ||
18582 | * | ||
18583 | * @function normalizeContent | ||
18584 | * @param {String|Element|TextNode|Array|Function} content | ||
18585 | * @return {Array} | ||
18586 | */ | ||
18587 | |||
18588 | function normalizeContent(content) { | ||
18589 | |||
18590 | // First, invoke content if it is a function. If it produces an array, | ||
18591 | // that needs to happen before normalization. | ||
18592 | if (typeof content === 'function') { | ||
18593 | content = content(); | ||
18594 | } | ||
18595 | |||
18596 | // Next up, normalize to an array, so one or many items can be normalized, | ||
18597 | // filtered, and returned. | ||
18598 | return (Array.isArray(content) ? content : [content]).map(function (value) { | ||
18599 | |||
18600 | // First, invoke value if it is a function to produce a new value, | ||
18601 | // which will be subsequently normalized to a Node of some kind. | ||
18602 | if (typeof value === 'function') { | ||
18603 | value = value(); | ||
18604 | } | ||
18605 | |||
18606 | if (isEl(value) || isTextNode(value)) { | ||
18607 | return value; | ||
18608 | } | ||
18609 | |||
18610 | if (typeof value === 'string' && /\S/.test(value)) { | ||
18611 | return _globalDocument2['default'].createTextNode(value); | ||
18612 | } | ||
18613 | }).filter(function (value) { | ||
18614 | return value; | ||
18615 | }); | ||
18616 | } | ||
18617 | |||
18618 | /** | ||
18619 | * Normalizes and appends content to an element. | ||
18620 | * | ||
18621 | * @function appendContent | ||
18622 | * @param {Element} el | ||
18623 | * @param {String|Element|TextNode|Array|Function} content | ||
18624 | * See: `normalizeContent` | ||
18625 | * @return {Element} | ||
18626 | */ | ||
18627 | |||
18628 | function appendContent(el, content) { | ||
18629 | normalizeContent(content).forEach(function (node) { | ||
18630 | return el.appendChild(node); | ||
18631 | }); | ||
18632 | return el; | ||
18633 | } | ||
18634 | |||
18635 | /** | ||
18636 | * Normalizes and inserts content into an element; this is identical to | ||
18637 | * `appendContent()`, except it empties the element first. | ||
18638 | * | ||
18639 | * @function insertContent | ||
18640 | * @param {Element} el | ||
18641 | * @param {String|Element|TextNode|Array|Function} content | ||
18642 | * See: `normalizeContent` | ||
18643 | * @return {Element} | ||
18644 | */ | ||
18645 | |||
18646 | function insertContent(el, content) { | ||
18647 | return appendContent(emptyEl(el), content); | ||
18648 | } | ||
18649 | |||
18650 | /** | ||
18651 | * Finds a single DOM element matching `selector` within the optional | ||
18652 | * `context` of another DOM element (defaulting to `document`). | ||
18653 | * | ||
18654 | * @function $ | ||
18655 | * @param {String} selector | ||
18656 | * A valid CSS selector, which will be passed to `querySelector`. | ||
18657 | * | ||
18658 | * @param {Element|String} [context=document] | ||
18659 | * A DOM element within which to query. Can also be a selector | ||
18660 | * string in which case the first matching element will be used | ||
18661 | * as context. If missing (or no element matches selector), falls | ||
18662 | * back to `document`. | ||
18663 | * | ||
18664 | * @return {Element|null} | ||
18665 | */ | ||
18666 | var $ = createQuerier('querySelector'); | ||
18667 | |||
18668 | exports.$ = $; | ||
18669 | /** | ||
18670 | * Finds a all DOM elements matching `selector` within the optional | ||
18671 | * `context` of another DOM element (defaulting to `document`). | ||
18672 | * | ||
18673 | * @function $$ | ||
18674 | * @param {String} selector | ||
18675 | * A valid CSS selector, which will be passed to `querySelectorAll`. | ||
18676 | * | ||
18677 | * @param {Element|String} [context=document] | ||
18678 | * A DOM element within which to query. Can also be a selector | ||
18679 | * string in which case the first matching element will be used | ||
18680 | * as context. If missing (or no element matches selector), falls | ||
18681 | * back to `document`. | ||
18682 | * | ||
18683 | * @return {NodeList} | ||
18684 | */ | ||
18685 | var $$ = createQuerier('querySelectorAll'); | ||
18686 | exports.$$ = $$; | ||
18687 | |||
18688 | },{"./guid.js":136,"./log.js":137,"global/document":1,"global/window":2,"tsml":55}],133:[function(_dereq_,module,exports){ | ||
18689 | /** | ||
18690 | * @file events.js | ||
18691 | * | ||
18692 | * Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/) | ||
18693 | * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible) | ||
18694 | * This should work very similarly to jQuery's events, however it's based off the book version which isn't as | ||
18695 | * robust as jquery's, so there's probably some differences. | ||
18696 | */ | ||
18697 | |||
18698 | 'use strict'; | ||
18699 | |||
18700 | exports.__esModule = true; | ||
18701 | exports.on = on; | ||
18702 | exports.off = off; | ||
18703 | exports.trigger = trigger; | ||
18704 | exports.one = one; | ||
18705 | exports.fixEvent = fixEvent; | ||
18706 | |||
18707 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
18708 | |||
18709 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
18710 | |||
18711 | var _domJs = _dereq_('./dom.js'); | ||
18712 | |||
18713 | var Dom = _interopRequireWildcard(_domJs); | ||
18714 | |||
18715 | var _guidJs = _dereq_('./guid.js'); | ||
18716 | |||
18717 | var Guid = _interopRequireWildcard(_guidJs); | ||
18718 | |||
18719 | var _globalWindow = _dereq_('global/window'); | ||
18720 | |||
18721 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
18722 | |||
18723 | var _globalDocument = _dereq_('global/document'); | ||
18724 | |||
18725 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
18726 | |||
18727 | /** | ||
18728 | * Add an event listener to element | ||
18729 | * It stores the handler function in a separate cache object | ||
18730 | * and adds a generic handler to the element's event, | ||
18731 | * along with a unique id (guid) to the element. | ||
18732 | * | ||
18733 | * @param {Element|Object} elem Element or object to bind listeners to | ||
18734 | * @param {String|Array} type Type of event to bind to. | ||
18735 | * @param {Function} fn Event listener. | ||
18736 | * @method on | ||
18737 | */ | ||
18738 | |||
18739 | function on(elem, type, fn) { | ||
18740 | if (Array.isArray(type)) { | ||
18741 | return _handleMultipleEvents(on, elem, type, fn); | ||
18742 | } | ||
18743 | |||
18744 | var data = Dom.getElData(elem); | ||
18745 | |||
18746 | // We need a place to store all our handler data | ||
18747 | if (!data.handlers) data.handlers = {}; | ||
18748 | |||
18749 | if (!data.handlers[type]) data.handlers[type] = []; | ||
18750 | |||
18751 | if (!fn.guid) fn.guid = Guid.newGUID(); | ||
18752 | |||
18753 | data.handlers[type].push(fn); | ||
18754 | |||
18755 | if (!data.dispatcher) { | ||
18756 | data.disabled = false; | ||
18757 | |||
18758 | data.dispatcher = function (event, hash) { | ||
18759 | |||
18760 | if (data.disabled) return; | ||
18761 | event = fixEvent(event); | ||
18762 | |||
18763 | var handlers = data.handlers[event.type]; | ||
18764 | |||
18765 | if (handlers) { | ||
18766 | // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off. | ||
18767 | var handlersCopy = handlers.slice(0); | ||
18768 | |||
18769 | for (var m = 0, n = handlersCopy.length; m < n; m++) { | ||
18770 | if (event.isImmediatePropagationStopped()) { | ||
18771 | break; | ||
18772 | } else { | ||
18773 | handlersCopy[m].call(elem, event, hash); | ||
18774 | } | ||
18775 | } | ||
18776 | } | ||
18777 | }; | ||
18778 | } | ||
18779 | |||
18780 | if (data.handlers[type].length === 1) { | ||
18781 | if (elem.addEventListener) { | ||
18782 | elem.addEventListener(type, data.dispatcher, false); | ||
18783 | } else if (elem.attachEvent) { | ||
18784 | elem.attachEvent('on' + type, data.dispatcher); | ||
18785 | } | ||
18786 | } | ||
18787 | } | ||
18788 | |||
18789 | /** | ||
18790 | * Removes event listeners from an element | ||
18791 | * | ||
18792 | * @param {Element|Object} elem Object to remove listeners from | ||
18793 | * @param {String|Array=} type Type of listener to remove. Don't include to remove all events from element. | ||
18794 | * @param {Function} fn Specific listener to remove. Don't include to remove listeners for an event type. | ||
18795 | * @method off | ||
18796 | */ | ||
18797 | |||
18798 | function off(elem, type, fn) { | ||
18799 | // Don't want to add a cache object through getElData if not needed | ||
18800 | if (!Dom.hasElData(elem)) return; | ||
18801 | |||
18802 | var data = Dom.getElData(elem); | ||
18803 | |||
18804 | // If no events exist, nothing to unbind | ||
18805 | if (!data.handlers) { | ||
18806 | return; | ||
18807 | } | ||
18808 | |||
18809 | if (Array.isArray(type)) { | ||
18810 | return _handleMultipleEvents(off, elem, type, fn); | ||
18811 | } | ||
18812 | |||
18813 | // Utility function | ||
18814 | var removeType = function removeType(t) { | ||
18815 | data.handlers[t] = []; | ||
18816 | _cleanUpEvents(elem, t); | ||
18817 | }; | ||
18818 | |||
18819 | // Are we removing all bound events? | ||
18820 | if (!type) { | ||
18821 | for (var t in data.handlers) { | ||
18822 | removeType(t); | ||
18823 | }return; | ||
18824 | } | ||
18825 | |||
18826 | var handlers = data.handlers[type]; | ||
18827 | |||
18828 | // If no handlers exist, nothing to unbind | ||
18829 | if (!handlers) return; | ||
18830 | |||
18831 | // If no listener was provided, remove all listeners for type | ||
18832 | if (!fn) { | ||
18833 | removeType(type); | ||
18834 | return; | ||
18835 | } | ||
18836 | |||
18837 | // We're only removing a single handler | ||
18838 | if (fn.guid) { | ||
18839 | for (var n = 0; n < handlers.length; n++) { | ||
18840 | if (handlers[n].guid === fn.guid) { | ||
18841 | handlers.splice(n--, 1); | ||
18842 | } | ||
18843 | } | ||
18844 | } | ||
18845 | |||
18846 | _cleanUpEvents(elem, type); | ||
18847 | } | ||
18848 | |||
18849 | /** | ||
18850 | * Trigger an event for an element | ||
18851 | * | ||
18852 | * @param {Element|Object} elem Element to trigger an event on | ||
18853 | * @param {Event|Object|String} event A string (the type) or an event object with a type attribute | ||
18854 | * @param {Object} [hash] data hash to pass along with the event | ||
18855 | * @return {Boolean=} Returned only if default was prevented | ||
18856 | * @method trigger | ||
18857 | */ | ||
18858 | |||
18859 | function trigger(elem, event, hash) { | ||
18860 | // Fetches element data and a reference to the parent (for bubbling). | ||
18861 | // Don't want to add a data object to cache for every parent, | ||
18862 | // so checking hasElData first. | ||
18863 | var elemData = Dom.hasElData(elem) ? Dom.getElData(elem) : {}; | ||
18864 | var parent = elem.parentNode || elem.ownerDocument; | ||
18865 | // type = event.type || event, | ||
18866 | // handler; | ||
18867 | |||
18868 | // If an event name was passed as a string, creates an event out of it | ||
18869 | if (typeof event === 'string') { | ||
18870 | event = { type: event, target: elem }; | ||
18871 | } | ||
18872 | // Normalizes the event properties. | ||
18873 | event = fixEvent(event); | ||
18874 | |||
18875 | // If the passed element has a dispatcher, executes the established handlers. | ||
18876 | if (elemData.dispatcher) { | ||
18877 | elemData.dispatcher.call(elem, event, hash); | ||
18878 | } | ||
18879 | |||
18880 | // Unless explicitly stopped or the event does not bubble (e.g. media events) | ||
18881 | // recursively calls this function to bubble the event up the DOM. | ||
18882 | if (parent && !event.isPropagationStopped() && event.bubbles === true) { | ||
18883 | trigger.call(null, parent, event, hash); | ||
18884 | |||
18885 | // If at the top of the DOM, triggers the default action unless disabled. | ||
18886 | } else if (!parent && !event.defaultPrevented) { | ||
18887 | var targetData = Dom.getElData(event.target); | ||
18888 | |||
18889 | // Checks if the target has a default action for this event. | ||
18890 | if (event.target[event.type]) { | ||
18891 | // Temporarily disables event dispatching on the target as we have already executed the handler. | ||
18892 | targetData.disabled = true; | ||
18893 | // Executes the default action. | ||
18894 | if (typeof event.target[event.type] === 'function') { | ||
18895 | event.target[event.type](); | ||
18896 | } | ||
18897 | // Re-enables event dispatching. | ||
18898 | targetData.disabled = false; | ||
18899 | } | ||
18900 | } | ||
18901 | |||
18902 | // Inform the triggerer if the default was prevented by returning false | ||
18903 | return !event.defaultPrevented; | ||
18904 | } | ||
18905 | |||
18906 | /** | ||
18907 | * Trigger a listener only once for an event | ||
18908 | * | ||
18909 | * @param {Element|Object} elem Element or object to | ||
18910 | * @param {String|Array} type Name/type of event | ||
18911 | * @param {Function} fn Event handler function | ||
18912 | * @method one | ||
18913 | */ | ||
18914 | |||
18915 | function one(elem, type, fn) { | ||
18916 | if (Array.isArray(type)) { | ||
18917 | return _handleMultipleEvents(one, elem, type, fn); | ||
18918 | } | ||
18919 | var func = function func() { | ||
18920 | off(elem, type, func); | ||
18921 | fn.apply(this, arguments); | ||
18922 | }; | ||
18923 | // copy the guid to the new function so it can removed using the original function's ID | ||
18924 | func.guid = fn.guid = fn.guid || Guid.newGUID(); | ||
18925 | on(elem, type, func); | ||
18926 | } | ||
18927 | |||
18928 | /** | ||
18929 | * Fix a native event to have standard property values | ||
18930 | * | ||
18931 | * @param {Object} event Event object to fix | ||
18932 | * @return {Object} | ||
18933 | * @private | ||
18934 | * @method fixEvent | ||
18935 | */ | ||
18936 | |||
18937 | function fixEvent(event) { | ||
18938 | |||
18939 | function returnTrue() { | ||
18940 | return true; | ||
18941 | } | ||
18942 | function returnFalse() { | ||
18943 | return false; | ||
18944 | } | ||
18945 | |||
18946 | // Test if fixing up is needed | ||
18947 | // Used to check if !event.stopPropagation instead of isPropagationStopped | ||
18948 | // But native events return true for stopPropagation, but don't have | ||
18949 | // other expected methods like isPropagationStopped. Seems to be a problem | ||
18950 | // with the Javascript Ninja code. So we're just overriding all events now. | ||
18951 | if (!event || !event.isPropagationStopped) { | ||
18952 | var old = event || _globalWindow2['default'].event; | ||
18953 | |||
18954 | event = {}; | ||
18955 | // Clone the old object so that we can modify the values event = {}; | ||
18956 | // IE8 Doesn't like when you mess with native event properties | ||
18957 | // Firefox returns false for event.hasOwnProperty('type') and other props | ||
18958 | // which makes copying more difficult. | ||
18959 | // TODO: Probably best to create a whitelist of event props | ||
18960 | for (var key in old) { | ||
18961 | // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y | ||
18962 | // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation | ||
18963 | // and webkitMovementX/Y | ||
18964 | if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') { | ||
18965 | // Chrome 32+ warns if you try to copy deprecated returnValue, but | ||
18966 | // we still want to if preventDefault isn't supported (IE8). | ||
18967 | if (!(key === 'returnValue' && old.preventDefault)) { | ||
18968 | event[key] = old[key]; | ||
18969 | } | ||
18970 | } | ||
18971 | } | ||
18972 | |||
18973 | // The event occurred on this element | ||
18974 | if (!event.target) { | ||
18975 | event.target = event.srcElement || _globalDocument2['default']; | ||
18976 | } | ||
18977 | |||
18978 | // Handle which other element the event is related to | ||
18979 | if (!event.relatedTarget) { | ||
18980 | event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; | ||
18981 | } | ||
18982 | |||
18983 | // Stop the default browser action | ||
18984 | event.preventDefault = function () { | ||
18985 | if (old.preventDefault) { | ||
18986 | old.preventDefault(); | ||
18987 | } | ||
18988 | event.returnValue = false; | ||
18989 | old.returnValue = false; | ||
18990 | event.defaultPrevented = true; | ||
18991 | }; | ||
18992 | |||
18993 | event.defaultPrevented = false; | ||
18994 | |||
18995 | // Stop the event from bubbling | ||
18996 | event.stopPropagation = function () { | ||
18997 | if (old.stopPropagation) { | ||
18998 | old.stopPropagation(); | ||
18999 | } | ||
19000 | event.cancelBubble = true; | ||
19001 | old.cancelBubble = true; | ||
19002 | event.isPropagationStopped = returnTrue; | ||
19003 | }; | ||
19004 | |||
19005 | event.isPropagationStopped = returnFalse; | ||
19006 | |||
19007 | // Stop the event from bubbling and executing other handlers | ||
19008 | event.stopImmediatePropagation = function () { | ||
19009 | if (old.stopImmediatePropagation) { | ||
19010 | old.stopImmediatePropagation(); | ||
19011 | } | ||
19012 | event.isImmediatePropagationStopped = returnTrue; | ||
19013 | event.stopPropagation(); | ||
19014 | }; | ||
19015 | |||
19016 | event.isImmediatePropagationStopped = returnFalse; | ||
19017 | |||
19018 | // Handle mouse position | ||
19019 | if (event.clientX != null) { | ||
19020 | var doc = _globalDocument2['default'].documentElement, | ||
19021 | body = _globalDocument2['default'].body; | ||
19022 | |||
19023 | event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); | ||
19024 | event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); | ||
19025 | } | ||
19026 | |||
19027 | // Handle key presses | ||
19028 | event.which = event.charCode || event.keyCode; | ||
19029 | |||
19030 | // Fix button for mouse clicks: | ||
19031 | // 0 == left; 1 == middle; 2 == right | ||
19032 | if (event.button != null) { | ||
19033 | event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0; | ||
19034 | } | ||
19035 | } | ||
19036 | |||
19037 | // Returns fixed-up instance | ||
19038 | return event; | ||
19039 | } | ||
19040 | |||
19041 | /** | ||
19042 | * Clean up the listener cache and dispatchers | ||
19043 | * | ||
19044 | * @param {Element|Object} elem Element to clean up | ||
19045 | * @param {String} type Type of event to clean up | ||
19046 | * @private | ||
19047 | * @method _cleanUpEvents | ||
19048 | */ | ||
19049 | function _cleanUpEvents(elem, type) { | ||
19050 | var data = Dom.getElData(elem); | ||
19051 | |||
19052 | // Remove the events of a particular type if there are none left | ||
19053 | if (data.handlers[type].length === 0) { | ||
19054 | delete data.handlers[type]; | ||
19055 | // data.handlers[type] = null; | ||
19056 | // Setting to null was causing an error with data.handlers | ||
19057 | |||
19058 | // Remove the meta-handler from the element | ||
19059 | if (elem.removeEventListener) { | ||
19060 | elem.removeEventListener(type, data.dispatcher, false); | ||
19061 | } else if (elem.detachEvent) { | ||
19062 | elem.detachEvent('on' + type, data.dispatcher); | ||
19063 | } | ||
19064 | } | ||
19065 | |||
19066 | // Remove the events object if there are no types left | ||
19067 | if (Object.getOwnPropertyNames(data.handlers).length <= 0) { | ||
19068 | delete data.handlers; | ||
19069 | delete data.dispatcher; | ||
19070 | delete data.disabled; | ||
19071 | } | ||
19072 | |||
19073 | // Finally remove the element data if there is no data left | ||
19074 | if (Object.getOwnPropertyNames(data).length === 0) { | ||
19075 | Dom.removeElData(elem); | ||
19076 | } | ||
19077 | } | ||
19078 | |||
19079 | /** | ||
19080 | * Loops through an array of event types and calls the requested method for each type. | ||
19081 | * | ||
19082 | * @param {Function} fn The event method we want to use. | ||
19083 | * @param {Element|Object} elem Element or object to bind listeners to | ||
19084 | * @param {String} type Type of event to bind to. | ||
19085 | * @param {Function} callback Event listener. | ||
19086 | * @private | ||
19087 | * @function _handleMultipleEvents | ||
19088 | */ | ||
19089 | function _handleMultipleEvents(fn, elem, types, callback) { | ||
19090 | types.forEach(function (type) { | ||
19091 | //Call the event method for each one of the types | ||
19092 | fn(elem, type, callback); | ||
19093 | }); | ||
19094 | } | ||
19095 | |||
19096 | },{"./dom.js":132,"./guid.js":136,"global/document":1,"global/window":2}],134:[function(_dereq_,module,exports){ | ||
19097 | /** | ||
19098 | * @file fn.js | ||
19099 | */ | ||
19100 | 'use strict'; | ||
19101 | |||
19102 | exports.__esModule = true; | ||
19103 | |||
19104 | var _guidJs = _dereq_('./guid.js'); | ||
19105 | |||
19106 | /** | ||
19107 | * Bind (a.k.a proxy or Context). A simple method for changing the context of a function | ||
19108 | * It also stores a unique id on the function so it can be easily removed from events | ||
19109 | * | ||
19110 | * @param {*} context The object to bind as scope | ||
19111 | * @param {Function} fn The function to be bound to a scope | ||
19112 | * @param {Number=} uid An optional unique ID for the function to be set | ||
19113 | * @return {Function} | ||
19114 | * @private | ||
19115 | * @method bind | ||
19116 | */ | ||
19117 | var bind = function bind(context, fn, uid) { | ||
19118 | // Make sure the function has a unique ID | ||
19119 | if (!fn.guid) { | ||
19120 | fn.guid = _guidJs.newGUID(); | ||
19121 | } | ||
19122 | |||
19123 | // Create the new function that changes the context | ||
19124 | var ret = function ret() { | ||
19125 | return fn.apply(context, arguments); | ||
19126 | }; | ||
19127 | |||
19128 | // Allow for the ability to individualize this function | ||
19129 | // Needed in the case where multiple objects might share the same prototype | ||
19130 | // IF both items add an event listener with the same function, then you try to remove just one | ||
19131 | // it will remove both because they both have the same guid. | ||
19132 | // when using this, you need to use the bind method when you remove the listener as well. | ||
19133 | // currently used in text tracks | ||
19134 | ret.guid = uid ? uid + '_' + fn.guid : fn.guid; | ||
19135 | |||
19136 | return ret; | ||
19137 | }; | ||
19138 | exports.bind = bind; | ||
19139 | |||
19140 | },{"./guid.js":136}],135:[function(_dereq_,module,exports){ | ||
19141 | /** | ||
19142 | * @file format-time.js | ||
19143 | * | ||
19144 | * Format seconds as a time string, H:MM:SS or M:SS | ||
19145 | * Supplying a guide (in seconds) will force a number of leading zeros | ||
19146 | * to cover the length of the guide | ||
19147 | * | ||
19148 | * @param {Number} seconds Number of seconds to be turned into a string | ||
19149 | * @param {Number} guide Number (in seconds) to model the string after | ||
19150 | * @return {String} Time formatted as H:MM:SS or M:SS | ||
19151 | * @private | ||
19152 | * @function formatTime | ||
19153 | */ | ||
19154 | 'use strict'; | ||
19155 | |||
19156 | exports.__esModule = true; | ||
19157 | function formatTime(seconds) { | ||
19158 | var guide = arguments.length <= 1 || arguments[1] === undefined ? seconds : arguments[1]; | ||
19159 | return (function () { | ||
19160 | seconds = seconds < 0 ? 0 : seconds; | ||
19161 | var s = Math.floor(seconds % 60); | ||
19162 | var m = Math.floor(seconds / 60 % 60); | ||
19163 | var h = Math.floor(seconds / 3600); | ||
19164 | var gm = Math.floor(guide / 60 % 60); | ||
19165 | var gh = Math.floor(guide / 3600); | ||
19166 | |||
19167 | // handle invalid times | ||
19168 | if (isNaN(seconds) || seconds === Infinity) { | ||
19169 | // '-' is false for all relational operators (e.g. <, >=) so this setting | ||
19170 | // will add the minimum number of fields specified by the guide | ||
19171 | h = m = s = '-'; | ||
19172 | } | ||
19173 | |||
19174 | // Check if we need to show hours | ||
19175 | h = h > 0 || gh > 0 ? h + ':' : ''; | ||
19176 | |||
19177 | // If hours are showing, we may need to add a leading zero. | ||
19178 | // Always show at least one digit of minutes. | ||
19179 | m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':'; | ||
19180 | |||
19181 | // Check if leading zero is need for seconds | ||
19182 | s = s < 10 ? '0' + s : s; | ||
19183 | |||
19184 | return h + m + s; | ||
19185 | })(); | ||
19186 | } | ||
19187 | |||
19188 | exports['default'] = formatTime; | ||
19189 | module.exports = exports['default']; | ||
19190 | |||
19191 | },{}],136:[function(_dereq_,module,exports){ | ||
19192 | /** | ||
19193 | * @file guid.js | ||
19194 | * | ||
19195 | * Unique ID for an element or function | ||
19196 | * @type {Number} | ||
19197 | * @private | ||
19198 | */ | ||
19199 | "use strict"; | ||
19200 | |||
19201 | exports.__esModule = true; | ||
19202 | exports.newGUID = newGUID; | ||
19203 | var _guid = 1; | ||
19204 | |||
19205 | /** | ||
19206 | * Get the next unique ID | ||
19207 | * | ||
19208 | * @return {String} | ||
19209 | * @function newGUID | ||
19210 | */ | ||
19211 | |||
19212 | function newGUID() { | ||
19213 | return _guid++; | ||
19214 | } | ||
19215 | |||
19216 | },{}],137:[function(_dereq_,module,exports){ | ||
19217 | /** | ||
19218 | * @file log.js | ||
19219 | */ | ||
19220 | 'use strict'; | ||
19221 | |||
19222 | exports.__esModule = true; | ||
19223 | |||
19224 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
19225 | |||
19226 | var _globalWindow = _dereq_('global/window'); | ||
19227 | |||
19228 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
19229 | |||
19230 | /** | ||
19231 | * Log plain debug messages | ||
19232 | */ | ||
19233 | var log = function log() { | ||
19234 | _logType(null, arguments); | ||
19235 | }; | ||
19236 | |||
19237 | /** | ||
19238 | * Keep a history of log messages | ||
19239 | * @type {Array} | ||
19240 | */ | ||
19241 | log.history = []; | ||
19242 | |||
19243 | /** | ||
19244 | * Log error messages | ||
19245 | */ | ||
19246 | log.error = function () { | ||
19247 | _logType('error', arguments); | ||
19248 | }; | ||
19249 | |||
19250 | /** | ||
19251 | * Log warning messages | ||
19252 | */ | ||
19253 | log.warn = function () { | ||
19254 | _logType('warn', arguments); | ||
19255 | }; | ||
19256 | |||
19257 | /** | ||
19258 | * Log messages to the console and history based on the type of message | ||
19259 | * | ||
19260 | * @param {String} type The type of message, or `null` for `log` | ||
19261 | * @param {Object} args The args to be passed to the log | ||
19262 | * @private | ||
19263 | * @method _logType | ||
19264 | */ | ||
19265 | function _logType(type, args) { | ||
19266 | // convert args to an array to get array functions | ||
19267 | var argsArray = Array.prototype.slice.call(args); | ||
19268 | // if there's no console then don't try to output messages | ||
19269 | // they will still be stored in log.history | ||
19270 | // Was setting these once outside of this function, but containing them | ||
19271 | // in the function makes it easier to test cases where console doesn't exist | ||
19272 | var noop = function noop() {}; | ||
19273 | |||
19274 | var console = _globalWindow2['default']['console'] || { | ||
19275 | 'log': noop, | ||
19276 | 'warn': noop, | ||
19277 | 'error': noop | ||
19278 | }; | ||
19279 | |||
19280 | if (type) { | ||
19281 | // add the type to the front of the message | ||
19282 | argsArray.unshift(type.toUpperCase() + ':'); | ||
19283 | } else { | ||
19284 | // default to log with no prefix | ||
19285 | type = 'log'; | ||
19286 | } | ||
19287 | |||
19288 | // add to history | ||
19289 | log.history.push(argsArray); | ||
19290 | |||
19291 | // add console prefix after adding to history | ||
19292 | argsArray.unshift('VIDEOJS:'); | ||
19293 | |||
19294 | // call appropriate log function | ||
19295 | if (console[type].apply) { | ||
19296 | console[type].apply(console, argsArray); | ||
19297 | } else { | ||
19298 | // ie8 doesn't allow error.apply, but it will just join() the array anyway | ||
19299 | console[type](argsArray.join(' ')); | ||
19300 | } | ||
19301 | } | ||
19302 | |||
19303 | exports['default'] = log; | ||
19304 | module.exports = exports['default']; | ||
19305 | |||
19306 | },{"global/window":2}],138:[function(_dereq_,module,exports){ | ||
19307 | /** | ||
19308 | * @file merge-options.js | ||
19309 | */ | ||
19310 | 'use strict'; | ||
19311 | |||
19312 | exports.__esModule = true; | ||
19313 | exports['default'] = mergeOptions; | ||
19314 | |||
19315 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
19316 | |||
19317 | var _lodashCompatObjectMerge = _dereq_('lodash-compat/object/merge'); | ||
19318 | |||
19319 | var _lodashCompatObjectMerge2 = _interopRequireDefault(_lodashCompatObjectMerge); | ||
19320 | |||
19321 | function isPlain(obj) { | ||
19322 | return !!obj && typeof obj === 'object' && obj.toString() === '[object Object]' && obj.constructor === Object; | ||
19323 | } | ||
19324 | |||
19325 | /** | ||
19326 | * Merge customizer. video.js simply overwrites non-simple objects | ||
19327 | * (like arrays) instead of attempting to overlay them. | ||
19328 | * @see https://lodash.com/docs#merge | ||
19329 | */ | ||
19330 | var customizer = function customizer(destination, source) { | ||
19331 | // If we're not working with a plain object, copy the value as is | ||
19332 | // If source is an array, for instance, it will replace destination | ||
19333 | if (!isPlain(source)) { | ||
19334 | return source; | ||
19335 | } | ||
19336 | |||
19337 | // If the new value is a plain object but the first object value is not | ||
19338 | // we need to create a new object for the first object to merge with. | ||
19339 | // This makes it consistent with how merge() works by default | ||
19340 | // and also protects from later changes the to first object affecting | ||
19341 | // the second object's values. | ||
19342 | if (!isPlain(destination)) { | ||
19343 | return mergeOptions(source); | ||
19344 | } | ||
19345 | }; | ||
19346 | |||
19347 | /** | ||
19348 | * Merge one or more options objects, recursively merging **only** | ||
19349 | * plain object properties. Previously `deepMerge`. | ||
19350 | * | ||
19351 | * @param {...Object} source One or more objects to merge | ||
19352 | * @returns {Object} a new object that is the union of all | ||
19353 | * provided objects | ||
19354 | * @function mergeOptions | ||
19355 | */ | ||
19356 | |||
19357 | function mergeOptions() { | ||
19358 | // contruct the call dynamically to handle the variable number of | ||
19359 | // objects to merge | ||
19360 | var args = Array.prototype.slice.call(arguments); | ||
19361 | |||
19362 | // unshift an empty object into the front of the call as the target | ||
19363 | // of the merge | ||
19364 | args.unshift({}); | ||
19365 | |||
19366 | // customize conflict resolution to match our historical merge behavior | ||
19367 | args.push(customizer); | ||
19368 | |||
19369 | _lodashCompatObjectMerge2['default'].apply(null, args); | ||
19370 | |||
19371 | // return the mutated result object | ||
19372 | return args[0]; | ||
19373 | } | ||
19374 | |||
19375 | module.exports = exports['default']; | ||
19376 | |||
19377 | },{"lodash-compat/object/merge":40}],139:[function(_dereq_,module,exports){ | ||
19378 | 'use strict'; | ||
19379 | |||
19380 | exports.__esModule = true; | ||
19381 | |||
19382 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
19383 | |||
19384 | var _globalDocument = _dereq_('global/document'); | ||
19385 | |||
19386 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
19387 | |||
19388 | var createStyleElement = function createStyleElement(className) { | ||
19389 | var style = _globalDocument2['default'].createElement('style'); | ||
19390 | style.className = className; | ||
19391 | |||
19392 | return style; | ||
19393 | }; | ||
19394 | |||
19395 | exports.createStyleElement = createStyleElement; | ||
19396 | var setTextContent = function setTextContent(el, content) { | ||
19397 | if (el.styleSheet) { | ||
19398 | el.styleSheet.cssText = content; | ||
19399 | } else { | ||
19400 | el.textContent = content; | ||
19401 | } | ||
19402 | }; | ||
19403 | exports.setTextContent = setTextContent; | ||
19404 | |||
19405 | },{"global/document":1}],140:[function(_dereq_,module,exports){ | ||
19406 | 'use strict'; | ||
19407 | |||
19408 | exports.__esModule = true; | ||
19409 | exports.createTimeRanges = createTimeRanges; | ||
19410 | |||
19411 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
19412 | |||
19413 | var _logJs = _dereq_('./log.js'); | ||
19414 | |||
19415 | var _logJs2 = _interopRequireDefault(_logJs); | ||
19416 | |||
19417 | /** | ||
19418 | * @file time-ranges.js | ||
19419 | * | ||
19420 | * Should create a fake TimeRange object | ||
19421 | * Mimics an HTML5 time range instance, which has functions that | ||
19422 | * return the start and end times for a range | ||
19423 | * TimeRanges are returned by the buffered() method | ||
19424 | * | ||
19425 | * @param {(Number|Array)} Start of a single range or an array of ranges | ||
19426 | * @param {Number} End of a single range | ||
19427 | * @private | ||
19428 | * @method createTimeRanges | ||
19429 | */ | ||
19430 | |||
19431 | function createTimeRanges(start, end) { | ||
19432 | if (Array.isArray(start)) { | ||
19433 | return createTimeRangesObj(start); | ||
19434 | } else if (start === undefined || end === undefined) { | ||
19435 | return createTimeRangesObj(); | ||
19436 | } | ||
19437 | return createTimeRangesObj([[start, end]]); | ||
19438 | } | ||
19439 | |||
19440 | exports.createTimeRange = createTimeRanges; | ||
19441 | |||
19442 | function createTimeRangesObj(ranges) { | ||
19443 | if (ranges === undefined || ranges.length === 0) { | ||
19444 | return { | ||
19445 | length: 0, | ||
19446 | start: function start() { | ||
19447 | throw new Error('This TimeRanges object is empty'); | ||
19448 | }, | ||
19449 | end: function end() { | ||
19450 | throw new Error('This TimeRanges object is empty'); | ||
19451 | } | ||
19452 | }; | ||
19453 | } | ||
19454 | return { | ||
19455 | length: ranges.length, | ||
19456 | start: getRange.bind(null, 'start', 0, ranges), | ||
19457 | end: getRange.bind(null, 'end', 1, ranges) | ||
19458 | }; | ||
19459 | } | ||
19460 | |||
19461 | function getRange(fnName, valueIndex, ranges, rangeIndex) { | ||
19462 | if (rangeIndex === undefined) { | ||
19463 | _logJs2['default'].warn('DEPRECATED: Function \'' + fnName + '\' on \'TimeRanges\' called without an index argument.'); | ||
19464 | rangeIndex = 0; | ||
19465 | } | ||
19466 | rangeCheck(fnName, rangeIndex, ranges.length - 1); | ||
19467 | return ranges[rangeIndex][valueIndex]; | ||
19468 | } | ||
19469 | |||
19470 | function rangeCheck(fnName, index, maxIndex) { | ||
19471 | if (index < 0 || index > maxIndex) { | ||
19472 | throw new Error('Failed to execute \'' + fnName + '\' on \'TimeRanges\': The index provided (' + index + ') is greater than or equal to the maximum bound (' + maxIndex + ').'); | ||
19473 | } | ||
19474 | } | ||
19475 | |||
19476 | },{"./log.js":137}],141:[function(_dereq_,module,exports){ | ||
19477 | /** | ||
19478 | * @file to-title-case.js | ||
19479 | * | ||
19480 | * Uppercase the first letter of a string | ||
19481 | * | ||
19482 | * @param {String} string String to be uppercased | ||
19483 | * @return {String} | ||
19484 | * @private | ||
19485 | * @method toTitleCase | ||
19486 | */ | ||
19487 | "use strict"; | ||
19488 | |||
19489 | exports.__esModule = true; | ||
19490 | function toTitleCase(string) { | ||
19491 | return string.charAt(0).toUpperCase() + string.slice(1); | ||
19492 | } | ||
19493 | |||
19494 | exports["default"] = toTitleCase; | ||
19495 | module.exports = exports["default"]; | ||
19496 | |||
19497 | },{}],142:[function(_dereq_,module,exports){ | ||
19498 | /** | ||
19499 | * @file url.js | ||
19500 | */ | ||
19501 | 'use strict'; | ||
19502 | |||
19503 | exports.__esModule = true; | ||
19504 | |||
19505 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
19506 | |||
19507 | var _globalDocument = _dereq_('global/document'); | ||
19508 | |||
19509 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
19510 | |||
19511 | var _globalWindow = _dereq_('global/window'); | ||
19512 | |||
19513 | var _globalWindow2 = _interopRequireDefault(_globalWindow); | ||
19514 | |||
19515 | /** | ||
19516 | * Resolve and parse the elements of a URL | ||
19517 | * | ||
19518 | * @param {String} url The url to parse | ||
19519 | * @return {Object} An object of url details | ||
19520 | * @method parseUrl | ||
19521 | */ | ||
19522 | var parseUrl = function parseUrl(url) { | ||
19523 | var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host']; | ||
19524 | |||
19525 | // add the url to an anchor and let the browser parse the URL | ||
19526 | var a = _globalDocument2['default'].createElement('a'); | ||
19527 | a.href = url; | ||
19528 | |||
19529 | // IE8 (and 9?) Fix | ||
19530 | // ie8 doesn't parse the URL correctly until the anchor is actually | ||
19531 | // added to the body, and an innerHTML is needed to trigger the parsing | ||
19532 | var addToBody = a.host === '' && a.protocol !== 'file:'; | ||
19533 | var div = undefined; | ||
19534 | if (addToBody) { | ||
19535 | div = _globalDocument2['default'].createElement('div'); | ||
19536 | div.innerHTML = '<a href="' + url + '"></a>'; | ||
19537 | a = div.firstChild; | ||
19538 | // prevent the div from affecting layout | ||
19539 | div.setAttribute('style', 'display:none; position:absolute;'); | ||
19540 | _globalDocument2['default'].body.appendChild(div); | ||
19541 | } | ||
19542 | |||
19543 | // Copy the specific URL properties to a new object | ||
19544 | // This is also needed for IE8 because the anchor loses its | ||
19545 | // properties when it's removed from the dom | ||
19546 | var details = {}; | ||
19547 | for (var i = 0; i < props.length; i++) { | ||
19548 | details[props[i]] = a[props[i]]; | ||
19549 | } | ||
19550 | |||
19551 | // IE9 adds the port to the host property unlike everyone else. If | ||
19552 | // a port identifier is added for standard ports, strip it. | ||
19553 | if (details.protocol === 'http:') { | ||
19554 | details.host = details.host.replace(/:80$/, ''); | ||
19555 | } | ||
19556 | if (details.protocol === 'https:') { | ||
19557 | details.host = details.host.replace(/:443$/, ''); | ||
19558 | } | ||
19559 | |||
19560 | if (addToBody) { | ||
19561 | _globalDocument2['default'].body.removeChild(div); | ||
19562 | } | ||
19563 | |||
19564 | return details; | ||
19565 | }; | ||
19566 | |||
19567 | exports.parseUrl = parseUrl; | ||
19568 | /** | ||
19569 | * Get absolute version of relative URL. Used to tell flash correct URL. | ||
19570 | * http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue | ||
19571 | * | ||
19572 | * @param {String} url URL to make absolute | ||
19573 | * @return {String} Absolute URL | ||
19574 | * @private | ||
19575 | * @method getAbsoluteURL | ||
19576 | */ | ||
19577 | var getAbsoluteURL = function getAbsoluteURL(url) { | ||
19578 | // Check if absolute URL | ||
19579 | if (!url.match(/^https?:\/\//)) { | ||
19580 | // Convert to absolute URL. Flash hosted off-site needs an absolute URL. | ||
19581 | var div = _globalDocument2['default'].createElement('div'); | ||
19582 | div.innerHTML = '<a href="' + url + '">x</a>'; | ||
19583 | url = div.firstChild.href; | ||
19584 | } | ||
19585 | |||
19586 | return url; | ||
19587 | }; | ||
19588 | |||
19589 | exports.getAbsoluteURL = getAbsoluteURL; | ||
19590 | /** | ||
19591 | * Returns the extension of the passed file name. It will return an empty string if you pass an invalid path | ||
19592 | * | ||
19593 | * @param {String} path The fileName path like '/path/to/file.mp4' | ||
19594 | * @returns {String} The extension in lower case or an empty string if no extension could be found. | ||
19595 | * @method getFileExtension | ||
19596 | */ | ||
19597 | var getFileExtension = function getFileExtension(path) { | ||
19598 | if (typeof path === 'string') { | ||
19599 | var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i; | ||
19600 | var pathParts = splitPathRe.exec(path); | ||
19601 | |||
19602 | if (pathParts) { | ||
19603 | return pathParts.pop().toLowerCase(); | ||
19604 | } | ||
19605 | } | ||
19606 | |||
19607 | return ''; | ||
19608 | }; | ||
19609 | |||
19610 | exports.getFileExtension = getFileExtension; | ||
19611 | /** | ||
19612 | * Returns whether the url passed is a cross domain request or not. | ||
19613 | * | ||
19614 | * @param {String} url The url to check | ||
19615 | * @return {Boolean} Whether it is a cross domain request or not | ||
19616 | * @method isCrossOrigin | ||
19617 | */ | ||
19618 | var isCrossOrigin = function isCrossOrigin(url) { | ||
19619 | var winLoc = _globalWindow2['default'].location; | ||
19620 | var urlInfo = parseUrl(url); | ||
19621 | |||
19622 | // IE8 protocol relative urls will return ':' for protocol | ||
19623 | var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol; | ||
19624 | |||
19625 | // Check if url is for another domain/origin | ||
19626 | // IE8 doesn't know location.origin, so we won't rely on it here | ||
19627 | var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host; | ||
19628 | |||
19629 | return crossOrigin; | ||
19630 | }; | ||
19631 | exports.isCrossOrigin = isCrossOrigin; | ||
19632 | |||
19633 | },{"global/document":1,"global/window":2}],143:[function(_dereq_,module,exports){ | ||
19634 | /** | ||
19635 | * @file video.js | ||
19636 | */ | ||
19637 | 'use strict'; | ||
19638 | |||
19639 | exports.__esModule = true; | ||
19640 | |||
19641 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
19642 | |||
19643 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
19644 | |||
19645 | var _globalDocument = _dereq_('global/document'); | ||
19646 | |||
19647 | var _globalDocument2 = _interopRequireDefault(_globalDocument); | ||
19648 | |||
19649 | var _setup = _dereq_('./setup'); | ||
19650 | |||
19651 | var setup = _interopRequireWildcard(_setup); | ||
19652 | |||
19653 | var _utilsStylesheetJs = _dereq_('./utils/stylesheet.js'); | ||
19654 | |||
19655 | var stylesheet = _interopRequireWildcard(_utilsStylesheetJs); | ||
19656 | |||
19657 | var _component = _dereq_('./component'); | ||
19658 | |||
19659 | var _component2 = _interopRequireDefault(_component); | ||
19660 | |||
19661 | var _eventTarget = _dereq_('./event-target'); | ||
19662 | |||
19663 | var _eventTarget2 = _interopRequireDefault(_eventTarget); | ||
19664 | |||
19665 | var _utilsEventsJs = _dereq_('./utils/events.js'); | ||
19666 | |||
19667 | var Events = _interopRequireWildcard(_utilsEventsJs); | ||
19668 | |||
19669 | var _player = _dereq_('./player'); | ||
19670 | |||
19671 | var _player2 = _interopRequireDefault(_player); | ||
19672 | |||
19673 | var _pluginsJs = _dereq_('./plugins.js'); | ||
19674 | |||
19675 | var _pluginsJs2 = _interopRequireDefault(_pluginsJs); | ||
19676 | |||
19677 | var _srcJsUtilsMergeOptionsJs = _dereq_('../../src/js/utils/merge-options.js'); | ||
19678 | |||
19679 | var _srcJsUtilsMergeOptionsJs2 = _interopRequireDefault(_srcJsUtilsMergeOptionsJs); | ||
19680 | |||
19681 | var _utilsFnJs = _dereq_('./utils/fn.js'); | ||
19682 | |||
19683 | var Fn = _interopRequireWildcard(_utilsFnJs); | ||
19684 | |||
19685 | var _tracksTextTrackJs = _dereq_('./tracks/text-track.js'); | ||
19686 | |||
19687 | var _tracksTextTrackJs2 = _interopRequireDefault(_tracksTextTrackJs); | ||
19688 | |||
19689 | var _objectAssign = _dereq_('object.assign'); | ||
19690 | |||
19691 | var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
19692 | |||
19693 | var _utilsTimeRangesJs = _dereq_('./utils/time-ranges.js'); | ||
19694 | |||
19695 | var _utilsFormatTimeJs = _dereq_('./utils/format-time.js'); | ||
19696 | |||
19697 | var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); | ||
19698 | |||
19699 | var _utilsLogJs = _dereq_('./utils/log.js'); | ||
19700 | |||
19701 | var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); | ||
19702 | |||
19703 | var _utilsDomJs = _dereq_('./utils/dom.js'); | ||
19704 | |||
19705 | var Dom = _interopRequireWildcard(_utilsDomJs); | ||
19706 | |||
19707 | var _utilsBrowserJs = _dereq_('./utils/browser.js'); | ||
19708 | |||
19709 | var browser = _interopRequireWildcard(_utilsBrowserJs); | ||
19710 | |||
19711 | var _utilsUrlJs = _dereq_('./utils/url.js'); | ||
19712 | |||
19713 | var Url = _interopRequireWildcard(_utilsUrlJs); | ||
19714 | |||
19715 | var _extendJs = _dereq_('./extend.js'); | ||
19716 | |||
19717 | var _extendJs2 = _interopRequireDefault(_extendJs); | ||
19718 | |||
19719 | var _lodashCompatObjectMerge = _dereq_('lodash-compat/object/merge'); | ||
19720 | |||
19721 | var _lodashCompatObjectMerge2 = _interopRequireDefault(_lodashCompatObjectMerge); | ||
19722 | |||
19723 | var _utilsCreateDeprecationProxyJs = _dereq_('./utils/create-deprecation-proxy.js'); | ||
19724 | |||
19725 | var _utilsCreateDeprecationProxyJs2 = _interopRequireDefault(_utilsCreateDeprecationProxyJs); | ||
19726 | |||
19727 | var _xhr = _dereq_('xhr'); | ||
19728 | |||
19729 | var _xhr2 = _interopRequireDefault(_xhr); | ||
19730 | |||
19731 | // Include the built-in techs | ||
19732 | |||
19733 | var _techTechJs = _dereq_('./tech/tech.js'); | ||
19734 | |||
19735 | var _techTechJs2 = _interopRequireDefault(_techTechJs); | ||
19736 | |||
19737 | var _techHtml5Js = _dereq_('./tech/html5.js'); | ||
19738 | |||
19739 | var _techHtml5Js2 = _interopRequireDefault(_techHtml5Js); | ||
19740 | |||
19741 | var _techFlashJs = _dereq_('./tech/flash.js'); | ||
19742 | |||
19743 | var _techFlashJs2 = _interopRequireDefault(_techFlashJs); | ||
19744 | |||
19745 | // HTML5 Element Shim for IE8 | ||
19746 | if (typeof HTMLVideoElement === 'undefined') { | ||
19747 | _globalDocument2['default'].createElement('video'); | ||
19748 | _globalDocument2['default'].createElement('audio'); | ||
19749 | _globalDocument2['default'].createElement('track'); | ||
19750 | } | ||
19751 | |||
19752 | /** | ||
19753 | * Doubles as the main function for users to create a player instance and also | ||
19754 | * the main library object. | ||
19755 | * The `videojs` function can be used to initialize or retrieve a player. | ||
19756 | * ```js | ||
19757 | * var myPlayer = videojs('my_video_id'); | ||
19758 | * ``` | ||
19759 | * | ||
19760 | * @param {String|Element} id Video element or video element ID | ||
19761 | * @param {Object=} options Optional options object for config/settings | ||
19762 | * @param {Function=} ready Optional ready callback | ||
19763 | * @return {Player} A player instance | ||
19764 | * @mixes videojs | ||
19765 | * @method videojs | ||
19766 | */ | ||
19767 | var videojs = function videojs(id, options, ready) { | ||
19768 | var tag = undefined; // Element of ID | ||
19769 | |||
19770 | // Allow for element or ID to be passed in | ||
19771 | // String ID | ||
19772 | if (typeof id === 'string') { | ||
19773 | |||
19774 | // Adjust for jQuery ID syntax | ||
19775 | if (id.indexOf('#') === 0) { | ||
19776 | id = id.slice(1); | ||
19777 | } | ||
19778 | |||
19779 | // If a player instance has already been created for this ID return it. | ||
19780 | if (videojs.getPlayers()[id]) { | ||
19781 | |||
19782 | // If options or ready funtion are passed, warn | ||
19783 | if (options) { | ||
19784 | _utilsLogJs2['default'].warn('Player "' + id + '" is already initialised. Options will not be applied.'); | ||
19785 | } | ||
19786 | |||
19787 | if (ready) { | ||
19788 | videojs.getPlayers()[id].ready(ready); | ||
19789 | } | ||
19790 | |||
19791 | return videojs.getPlayers()[id]; | ||
19792 | |||
19793 | // Otherwise get element for ID | ||
19794 | } else { | ||
19795 | tag = Dom.getEl(id); | ||
19796 | } | ||
19797 | |||
19798 | // ID is a media element | ||
19799 | } else { | ||
19800 | tag = id; | ||
19801 | } | ||
19802 | |||
19803 | // Check for a useable element | ||
19804 | if (!tag || !tag.nodeName) { | ||
19805 | // re: nodeName, could be a box div also | ||
19806 | throw new TypeError('The element or ID supplied is not valid. (videojs)'); // Returns | ||
19807 | } | ||
19808 | |||
19809 | // Element may have a player attr referring to an already created player instance. | ||
19810 | // If not, set up a new player and return the instance. | ||
19811 | return tag['player'] || _player2['default'].players[tag.playerId] || new _player2['default'](tag, options, ready); | ||
19812 | }; | ||
19813 | |||
19814 | // Add default styles | ||
19815 | var style = Dom.$('.vjs-styles-defaults'); | ||
19816 | if (!style) { | ||
19817 | style = stylesheet.createStyleElement('vjs-styles-defaults'); | ||
19818 | var head = Dom.$('head'); | ||
19819 | head.insertBefore(style, head.firstChild); | ||
19820 | stylesheet.setTextContent(style, '\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n '); | ||
19821 | } | ||
19822 | |||
19823 | // Run Auto-load players | ||
19824 | // You have to wait at least once in case this script is loaded after your video in the DOM (weird behavior only with minified version) | ||
19825 | setup.autoSetupTimeout(1, videojs); | ||
19826 | |||
19827 | /* | ||
19828 | * Current software version (semver) | ||
19829 | * | ||
19830 | * @type {String} | ||
19831 | */ | ||
19832 | videojs.VERSION = '5.8.8'; | ||
19833 | |||
19834 | /** | ||
19835 | * The global options object. These are the settings that take effect | ||
19836 | * if no overrides are specified when the player is created. | ||
19837 | * | ||
19838 | * ```js | ||
19839 | * videojs.options.autoplay = true | ||
19840 | * // -> all players will autoplay by default | ||
19841 | * ``` | ||
19842 | * | ||
19843 | * @type {Object} | ||
19844 | */ | ||
19845 | videojs.options = _player2['default'].prototype.options_; | ||
19846 | |||
19847 | /** | ||
19848 | * Get an object with the currently created players, keyed by player ID | ||
19849 | * | ||
19850 | * @return {Object} The created players | ||
19851 | * @mixes videojs | ||
19852 | * @method getPlayers | ||
19853 | */ | ||
19854 | videojs.getPlayers = function () { | ||
19855 | return _player2['default'].players; | ||
19856 | }; | ||
19857 | |||
19858 | /** | ||
19859 | * For backward compatibility, expose players object. | ||
19860 | * | ||
19861 | * @deprecated | ||
19862 | * @memberOf videojs | ||
19863 | * @property {Object|Proxy} players | ||
19864 | */ | ||
19865 | videojs.players = _utilsCreateDeprecationProxyJs2['default'](_player2['default'].players, { | ||
19866 | get: 'Access to videojs.players is deprecated; use videojs.getPlayers instead', | ||
19867 | set: 'Modification of videojs.players is deprecated' | ||
19868 | }); | ||
19869 | |||
19870 | /** | ||
19871 | * Get a component class object by name | ||
19872 | * ```js | ||
19873 | * var VjsButton = videojs.getComponent('Button'); | ||
19874 | * // Create a new instance of the component | ||
19875 | * var myButton = new VjsButton(myPlayer); | ||
19876 | * ``` | ||
19877 | * | ||
19878 | * @return {Component} Component identified by name | ||
19879 | * @mixes videojs | ||
19880 | * @method getComponent | ||
19881 | */ | ||
19882 | videojs.getComponent = _component2['default'].getComponent; | ||
19883 | |||
19884 | /** | ||
19885 | * Register a component so it can referred to by name | ||
19886 | * Used when adding to other | ||
19887 | * components, either through addChild | ||
19888 | * `component.addChild('myComponent')` | ||
19889 | * or through default children options | ||
19890 | * `{ children: ['myComponent'] }`. | ||
19891 | * ```js | ||
19892 | * // Get a component to subclass | ||
19893 | * var VjsButton = videojs.getComponent('Button'); | ||
19894 | * // Subclass the component (see 'extend' doc for more info) | ||
19895 | * var MySpecialButton = videojs.extend(VjsButton, {}); | ||
19896 | * // Register the new component | ||
19897 | * VjsButton.registerComponent('MySepcialButton', MySepcialButton); | ||
19898 | * // (optionally) add the new component as a default player child | ||
19899 | * myPlayer.addChild('MySepcialButton'); | ||
19900 | * ``` | ||
19901 | * NOTE: You could also just initialize the component before adding. | ||
19902 | * `component.addChild(new MyComponent());` | ||
19903 | * | ||
19904 | * @param {String} The class name of the component | ||
19905 | * @param {Component} The component class | ||
19906 | * @return {Component} The newly registered component | ||
19907 | * @mixes videojs | ||
19908 | * @method registerComponent | ||
19909 | */ | ||
19910 | videojs.registerComponent = function (name, comp) { | ||
19911 | if (_techTechJs2['default'].isTech(comp)) { | ||
19912 | _utilsLogJs2['default'].warn('The ' + name + ' tech was registered as a component. It should instead be registered using videojs.registerTech(name, tech)'); | ||
19913 | } | ||
19914 | |||
19915 | _component2['default'].registerComponent.call(_component2['default'], name, comp); | ||
19916 | }; | ||
19917 | |||
19918 | /** | ||
19919 | * Get a Tech class object by name | ||
19920 | * ```js | ||
19921 | * var Html5 = videojs.getTech('Html5'); | ||
19922 | * // Create a new instance of the component | ||
19923 | * var html5 = new Html5(options); | ||
19924 | * ``` | ||
19925 | * | ||
19926 | * @return {Tech} Tech identified by name | ||
19927 | * @mixes videojs | ||
19928 | * @method getComponent | ||
19929 | */ | ||
19930 | videojs.getTech = _techTechJs2['default'].getTech; | ||
19931 | |||
19932 | /** | ||
19933 | * Register a Tech so it can referred to by name. | ||
19934 | * This is used in the tech order for the player. | ||
19935 | * | ||
19936 | * ```js | ||
19937 | * // get the Html5 Tech | ||
19938 | * var Html5 = videojs.getTech('Html5'); | ||
19939 | * var MyTech = videojs.extend(Html5, {}); | ||
19940 | * // Register the new Tech | ||
19941 | * VjsButton.registerTech('Tech', MyTech); | ||
19942 | * var player = videojs('myplayer', { | ||
19943 | * techOrder: ['myTech', 'html5'] | ||
19944 | * }); | ||
19945 | * ``` | ||
19946 | * | ||
19947 | * @param {String} The class name of the tech | ||
19948 | * @param {Tech} The tech class | ||
19949 | * @return {Tech} The newly registered Tech | ||
19950 | * @mixes videojs | ||
19951 | * @method registerTech | ||
19952 | */ | ||
19953 | videojs.registerTech = _techTechJs2['default'].registerTech; | ||
19954 | |||
19955 | /** | ||
19956 | * A suite of browser and device tests | ||
19957 | * | ||
19958 | * @type {Object} | ||
19959 | * @private | ||
19960 | */ | ||
19961 | videojs.browser = browser; | ||
19962 | |||
19963 | /** | ||
19964 | * Whether or not the browser supports touch events. Included for backward | ||
19965 | * compatibility with 4.x, but deprecated. Use `videojs.browser.TOUCH_ENABLED` | ||
19966 | * instead going forward. | ||
19967 | * | ||
19968 | * @deprecated | ||
19969 | * @type {Boolean} | ||
19970 | */ | ||
19971 | videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED; | ||
19972 | |||
19973 | /** | ||
19974 | * Subclass an existing class | ||
19975 | * Mimics ES6 subclassing with the `extend` keyword | ||
19976 | * ```js | ||
19977 | * // Create a basic javascript 'class' | ||
19978 | * function MyClass(name){ | ||
19979 | * // Set a property at initialization | ||
19980 | * this.myName = name; | ||
19981 | * } | ||
19982 | * // Create an instance method | ||
19983 | * MyClass.prototype.sayMyName = function(){ | ||
19984 | * alert(this.myName); | ||
19985 | * }; | ||
19986 | * // Subclass the exisitng class and change the name | ||
19987 | * // when initializing | ||
19988 | * var MySubClass = videojs.extend(MyClass, { | ||
19989 | * constructor: function(name) { | ||
19990 | * // Call the super class constructor for the subclass | ||
19991 | * MyClass.call(this, name) | ||
19992 | * } | ||
19993 | * }); | ||
19994 | * // Create an instance of the new sub class | ||
19995 | * var myInstance = new MySubClass('John'); | ||
19996 | * myInstance.sayMyName(); // -> should alert "John" | ||
19997 | * ``` | ||
19998 | * | ||
19999 | * @param {Function} The Class to subclass | ||
20000 | * @param {Object} An object including instace methods for the new class | ||
20001 | * Optionally including a `constructor` function | ||
20002 | * @return {Function} The newly created subclass | ||
20003 | * @mixes videojs | ||
20004 | * @method extend | ||
20005 | */ | ||
20006 | videojs.extend = _extendJs2['default']; | ||
20007 | |||
20008 | /** | ||
20009 | * Merge two options objects recursively | ||
20010 | * Performs a deep merge like lodash.merge but **only merges plain objects** | ||
20011 | * (not arrays, elements, anything else) | ||
20012 | * Other values will be copied directly from the second object. | ||
20013 | * ```js | ||
20014 | * var defaultOptions = { | ||
20015 | * foo: true, | ||
20016 | * bar: { | ||
20017 | * a: true, | ||
20018 | * b: [1,2,3] | ||
20019 | * } | ||
20020 | * }; | ||
20021 | * var newOptions = { | ||
20022 | * foo: false, | ||
20023 | * bar: { | ||
20024 | * b: [4,5,6] | ||
20025 | * } | ||
20026 | * }; | ||
20027 | * var result = videojs.mergeOptions(defaultOptions, newOptions); | ||
20028 | * // result.foo = false; | ||
20029 | * // result.bar.a = true; | ||
20030 | * // result.bar.b = [4,5,6]; | ||
20031 | * ``` | ||
20032 | * | ||
20033 | * @param {Object} defaults The options object whose values will be overriden | ||
20034 | * @param {Object} overrides The options object with values to override the first | ||
20035 | * @param {Object} etc Any number of additional options objects | ||
20036 | * | ||
20037 | * @return {Object} a new object with the merged values | ||
20038 | * @mixes videojs | ||
20039 | * @method mergeOptions | ||
20040 | */ | ||
20041 | videojs.mergeOptions = _srcJsUtilsMergeOptionsJs2['default']; | ||
20042 | |||
20043 | /** | ||
20044 | * Change the context (this) of a function | ||
20045 | * | ||
20046 | * videojs.bind(newContext, function(){ | ||
20047 | * this === newContext | ||
20048 | * }); | ||
20049 | * | ||
20050 | * NOTE: as of v5.0 we require an ES5 shim, so you should use the native | ||
20051 | * `function(){}.bind(newContext);` instead of this. | ||
20052 | * | ||
20053 | * @param {*} context The object to bind as scope | ||
20054 | * @param {Function} fn The function to be bound to a scope | ||
20055 | * @param {Number=} uid An optional unique ID for the function to be set | ||
20056 | * @return {Function} | ||
20057 | */ | ||
20058 | videojs.bind = Fn.bind; | ||
20059 | |||
20060 | /** | ||
20061 | * Create a Video.js player plugin | ||
20062 | * Plugins are only initialized when options for the plugin are included | ||
20063 | * in the player options, or the plugin function on the player instance is | ||
20064 | * called. | ||
20065 | * **See the plugin guide in the docs for a more detailed example** | ||
20066 | * ```js | ||
20067 | * // Make a plugin that alerts when the player plays | ||
20068 | * videojs.plugin('myPlugin', function(myPluginOptions) { | ||
20069 | * myPluginOptions = myPluginOptions || {}; | ||
20070 | * | ||
20071 | * var player = this; | ||
20072 | * var alertText = myPluginOptions.text || 'Player is playing!' | ||
20073 | * | ||
20074 | * player.on('play', function(){ | ||
20075 | * alert(alertText); | ||
20076 | * }); | ||
20077 | * }); | ||
20078 | * // USAGE EXAMPLES | ||
20079 | * // EXAMPLE 1: New player with plugin options, call plugin immediately | ||
20080 | * var player1 = videojs('idOne', { | ||
20081 | * myPlugin: { | ||
20082 | * text: 'Custom text!' | ||
20083 | * } | ||
20084 | * }); | ||
20085 | * // Click play | ||
20086 | * // --> Should alert 'Custom text!' | ||
20087 | * // EXAMPLE 3: New player, initialize plugin later | ||
20088 | * var player3 = videojs('idThree'); | ||
20089 | * // Click play | ||
20090 | * // --> NO ALERT | ||
20091 | * // Click pause | ||
20092 | * // Initialize plugin using the plugin function on the player instance | ||
20093 | * player3.myPlugin({ | ||
20094 | * text: 'Plugin added later!' | ||
20095 | * }); | ||
20096 | * // Click play | ||
20097 | * // --> Should alert 'Plugin added later!' | ||
20098 | * ``` | ||
20099 | * | ||
20100 | * @param {String} name The plugin name | ||
20101 | * @param {Function} fn The plugin function that will be called with options | ||
20102 | * @mixes videojs | ||
20103 | * @method plugin | ||
20104 | */ | ||
20105 | videojs.plugin = _pluginsJs2['default']; | ||
20106 | |||
20107 | /** | ||
20108 | * Adding languages so that they're available to all players. | ||
20109 | * ```js | ||
20110 | * videojs.addLanguage('es', { 'Hello': 'Hola' }); | ||
20111 | * ``` | ||
20112 | * | ||
20113 | * @param {String} code The language code or dictionary property | ||
20114 | * @param {Object} data The data values to be translated | ||
20115 | * @return {Object} The resulting language dictionary object | ||
20116 | * @mixes videojs | ||
20117 | * @method addLanguage | ||
20118 | */ | ||
20119 | videojs.addLanguage = function (code, data) { | ||
20120 | var _merge; | ||
20121 | |||
20122 | code = ('' + code).toLowerCase(); | ||
20123 | return _lodashCompatObjectMerge2['default'](videojs.options.languages, (_merge = {}, _merge[code] = data, _merge))[code]; | ||
20124 | }; | ||
20125 | |||
20126 | /** | ||
20127 | * Log debug messages. | ||
20128 | * | ||
20129 | * @param {...Object} messages One or more messages to log | ||
20130 | */ | ||
20131 | videojs.log = _utilsLogJs2['default']; | ||
20132 | |||
20133 | /** | ||
20134 | * Creates an emulated TimeRange object. | ||
20135 | * | ||
20136 | * @param {Number|Array} start Start time in seconds or an array of ranges | ||
20137 | * @param {Number} end End time in seconds | ||
20138 | * @return {Object} Fake TimeRange object | ||
20139 | * @method createTimeRange | ||
20140 | */ | ||
20141 | videojs.createTimeRange = videojs.createTimeRanges = _utilsTimeRangesJs.createTimeRanges; | ||
20142 | |||
20143 | /** | ||
20144 | * Format seconds as a time string, H:MM:SS or M:SS | ||
20145 | * Supplying a guide (in seconds) will force a number of leading zeros | ||
20146 | * to cover the length of the guide | ||
20147 | * | ||
20148 | * @param {Number} seconds Number of seconds to be turned into a string | ||
20149 | * @param {Number} guide Number (in seconds) to model the string after | ||
20150 | * @return {String} Time formatted as H:MM:SS or M:SS | ||
20151 | * @method formatTime | ||
20152 | */ | ||
20153 | videojs.formatTime = _utilsFormatTimeJs2['default']; | ||
20154 | |||
20155 | /** | ||
20156 | * Resolve and parse the elements of a URL | ||
20157 | * | ||
20158 | * @param {String} url The url to parse | ||
20159 | * @return {Object} An object of url details | ||
20160 | * @method parseUrl | ||
20161 | */ | ||
20162 | videojs.parseUrl = Url.parseUrl; | ||
20163 | |||
20164 | /** | ||
20165 | * Returns whether the url passed is a cross domain request or not. | ||
20166 | * | ||
20167 | * @param {String} url The url to check | ||
20168 | * @return {Boolean} Whether it is a cross domain request or not | ||
20169 | * @method isCrossOrigin | ||
20170 | */ | ||
20171 | videojs.isCrossOrigin = Url.isCrossOrigin; | ||
20172 | |||
20173 | /** | ||
20174 | * Event target class. | ||
20175 | * | ||
20176 | * @type {Function} | ||
20177 | */ | ||
20178 | videojs.EventTarget = _eventTarget2['default']; | ||
20179 | |||
20180 | /** | ||
20181 | * Add an event listener to element | ||
20182 | * It stores the handler function in a separate cache object | ||
20183 | * and adds a generic handler to the element's event, | ||
20184 | * along with a unique id (guid) to the element. | ||
20185 | * | ||
20186 | * @param {Element|Object} elem Element or object to bind listeners to | ||
20187 | * @param {String|Array} type Type of event to bind to. | ||
20188 | * @param {Function} fn Event listener. | ||
20189 | * @method on | ||
20190 | */ | ||
20191 | videojs.on = Events.on; | ||
20192 | |||
20193 | /** | ||
20194 | * Trigger a listener only once for an event | ||
20195 | * | ||
20196 | * @param {Element|Object} elem Element or object to | ||
20197 | * @param {String|Array} type Name/type of event | ||
20198 | * @param {Function} fn Event handler function | ||
20199 | * @method one | ||
20200 | */ | ||
20201 | videojs.one = Events.one; | ||
20202 | |||
20203 | /** | ||
20204 | * Removes event listeners from an element | ||
20205 | * | ||
20206 | * @param {Element|Object} elem Object to remove listeners from | ||
20207 | * @param {String|Array=} type Type of listener to remove. Don't include to remove all events from element. | ||
20208 | * @param {Function} fn Specific listener to remove. Don't include to remove listeners for an event type. | ||
20209 | * @method off | ||
20210 | */ | ||
20211 | videojs.off = Events.off; | ||
20212 | |||
20213 | /** | ||
20214 | * Trigger an event for an element | ||
20215 | * | ||
20216 | * @param {Element|Object} elem Element to trigger an event on | ||
20217 | * @param {Event|Object|String} event A string (the type) or an event object with a type attribute | ||
20218 | * @param {Object} [hash] data hash to pass along with the event | ||
20219 | * @return {Boolean=} Returned only if default was prevented | ||
20220 | * @method trigger | ||
20221 | */ | ||
20222 | videojs.trigger = Events.trigger; | ||
20223 | |||
20224 | /** | ||
20225 | * A cross-browser XMLHttpRequest wrapper. Here's a simple example: | ||
20226 | * | ||
20227 | * videojs.xhr({ | ||
20228 | * body: someJSONString, | ||
20229 | * uri: "/foo", | ||
20230 | * headers: { | ||
20231 | * "Content-Type": "application/json" | ||
20232 | * } | ||
20233 | * }, function (err, resp, body) { | ||
20234 | * // check resp.statusCode | ||
20235 | * }); | ||
20236 | * | ||
20237 | * Check out the [full | ||
20238 | * documentation](https://github.com/Raynos/xhr/blob/v2.1.0/README.md) | ||
20239 | * for more options. | ||
20240 | * | ||
20241 | * @param {Object} options settings for the request. | ||
20242 | * @return {XMLHttpRequest|XDomainRequest} the request object. | ||
20243 | * @see https://github.com/Raynos/xhr | ||
20244 | */ | ||
20245 | videojs.xhr = _xhr2['default']; | ||
20246 | |||
20247 | /** | ||
20248 | * TextTrack class | ||
20249 | * | ||
20250 | * @type {Function} | ||
20251 | */ | ||
20252 | videojs.TextTrack = _tracksTextTrackJs2['default']; | ||
20253 | |||
20254 | /** | ||
20255 | * Determines, via duck typing, whether or not a value is a DOM element. | ||
20256 | * | ||
20257 | * @method isEl | ||
20258 | * @param {Mixed} value | ||
20259 | * @return {Boolean} | ||
20260 | */ | ||
20261 | videojs.isEl = Dom.isEl; | ||
20262 | |||
20263 | /** | ||
20264 | * Determines, via duck typing, whether or not a value is a text node. | ||
20265 | * | ||
20266 | * @method isTextNode | ||
20267 | * @param {Mixed} value | ||
20268 | * @return {Boolean} | ||
20269 | */ | ||
20270 | videojs.isTextNode = Dom.isTextNode; | ||
20271 | |||
20272 | /** | ||
20273 | * Creates an element and applies properties. | ||
20274 | * | ||
20275 | * @method createEl | ||
20276 | * @param {String} [tagName='div'] Name of tag to be created. | ||
20277 | * @param {Object} [properties={}] Element properties to be applied. | ||
20278 | * @param {Object} [attributes={}] Element attributes to be applied. | ||
20279 | * @return {Element} | ||
20280 | */ | ||
20281 | videojs.createEl = Dom.createEl; | ||
20282 | |||
20283 | /** | ||
20284 | * Check if an element has a CSS class | ||
20285 | * | ||
20286 | * @method hasClass | ||
20287 | * @param {Element} element Element to check | ||
20288 | * @param {String} classToCheck Classname to check | ||
20289 | */ | ||
20290 | videojs.hasClass = Dom.hasElClass; | ||
20291 | |||
20292 | /** | ||
20293 | * Add a CSS class name to an element | ||
20294 | * | ||
20295 | * @method addClass | ||
20296 | * @param {Element} element Element to add class name to | ||
20297 | * @param {String} classToAdd Classname to add | ||
20298 | */ | ||
20299 | videojs.addClass = Dom.addElClass; | ||
20300 | |||
20301 | /** | ||
20302 | * Remove a CSS class name from an element | ||
20303 | * | ||
20304 | * @method removeClass | ||
20305 | * @param {Element} element Element to remove from class name | ||
20306 | * @param {String} classToRemove Classname to remove | ||
20307 | */ | ||
20308 | videojs.removeClass = Dom.removeElClass; | ||
20309 | |||
20310 | /** | ||
20311 | * Adds or removes a CSS class name on an element depending on an optional | ||
20312 | * condition or the presence/absence of the class name. | ||
20313 | * | ||
20314 | * @method toggleElClass | ||
20315 | * @param {Element} element | ||
20316 | * @param {String} classToToggle | ||
20317 | * @param {Boolean|Function} [predicate] | ||
20318 | * Can be a function that returns a Boolean. If `true`, the class | ||
20319 | * will be added; if `false`, the class will be removed. If not | ||
20320 | * given, the class will be added if not present and vice versa. | ||
20321 | */ | ||
20322 | videojs.toggleClass = Dom.toggleElClass; | ||
20323 | |||
20324 | /** | ||
20325 | * Apply attributes to an HTML element. | ||
20326 | * | ||
20327 | * @method setAttributes | ||
20328 | * @param {Element} el Target element. | ||
20329 | * @param {Object=} attributes Element attributes to be applied. | ||
20330 | */ | ||
20331 | videojs.setAttributes = Dom.setElAttributes; | ||
20332 | |||
20333 | /** | ||
20334 | * Get an element's attribute values, as defined on the HTML tag | ||
20335 | * Attributes are not the same as properties. They're defined on the tag | ||
20336 | * or with setAttribute (which shouldn't be used with HTML) | ||
20337 | * This will return true or false for boolean attributes. | ||
20338 | * | ||
20339 | * @method getAttributes | ||
20340 | * @param {Element} tag Element from which to get tag attributes | ||
20341 | * @return {Object} | ||
20342 | */ | ||
20343 | videojs.getAttributes = Dom.getElAttributes; | ||
20344 | |||
20345 | /** | ||
20346 | * Empties the contents of an element. | ||
20347 | * | ||
20348 | * @method emptyEl | ||
20349 | * @param {Element} el | ||
20350 | * @return {Element} | ||
20351 | */ | ||
20352 | videojs.emptyEl = Dom.emptyEl; | ||
20353 | |||
20354 | /** | ||
20355 | * Normalizes and appends content to an element. | ||
20356 | * | ||
20357 | * The content for an element can be passed in multiple types and | ||
20358 | * combinations, whose behavior is as follows: | ||
20359 | * | ||
20360 | * - String | ||
20361 | * Normalized into a text node. | ||
20362 | * | ||
20363 | * - Element, TextNode | ||
20364 | * Passed through. | ||
20365 | * | ||
20366 | * - Array | ||
20367 | * A one-dimensional array of strings, elements, nodes, or functions (which | ||
20368 | * return single strings, elements, or nodes). | ||
20369 | * | ||
20370 | * - Function | ||
20371 | * If the sole argument, is expected to produce a string, element, | ||
20372 | * node, or array. | ||
20373 | * | ||
20374 | * @method appendContent | ||
20375 | * @param {Element} el | ||
20376 | * @param {String|Element|TextNode|Array|Function} content | ||
20377 | * @return {Element} | ||
20378 | */ | ||
20379 | videojs.appendContent = Dom.appendContent; | ||
20380 | |||
20381 | /** | ||
20382 | * Normalizes and inserts content into an element; this is identical to | ||
20383 | * `appendContent()`, except it empties the element first. | ||
20384 | * | ||
20385 | * The content for an element can be passed in multiple types and | ||
20386 | * combinations, whose behavior is as follows: | ||
20387 | * | ||
20388 | * - String | ||
20389 | * Normalized into a text node. | ||
20390 | * | ||
20391 | * - Element, TextNode | ||
20392 | * Passed through. | ||
20393 | * | ||
20394 | * - Array | ||
20395 | * A one-dimensional array of strings, elements, nodes, or functions (which | ||
20396 | * return single strings, elements, or nodes). | ||
20397 | * | ||
20398 | * - Function | ||
20399 | * If the sole argument, is expected to produce a string, element, | ||
20400 | * node, or array. | ||
20401 | * | ||
20402 | * @method insertContent | ||
20403 | * @param {Element} el | ||
20404 | * @param {String|Element|TextNode|Array|Function} content | ||
20405 | * @return {Element} | ||
20406 | */ | ||
20407 | videojs.insertContent = Dom.insertContent; | ||
20408 | |||
20409 | /* | ||
20410 | * Custom Universal Module Definition (UMD) | ||
20411 | * | ||
20412 | * Video.js will never be a non-browser lib so we can simplify UMD a bunch and | ||
20413 | * still support requirejs and browserify. This also needs to be closure | ||
20414 | * compiler compatible, so string keys are used. | ||
20415 | */ | ||
20416 | if (typeof define === 'function' && define['amd']) { | ||
20417 | define('videojs', [], function () { | ||
20418 | return videojs; | ||
20419 | }); | ||
20420 | |||
20421 | // checking that module is an object too because of umdjs/umd#35 | ||
20422 | } else if (typeof exports === 'object' && typeof module === 'object') { | ||
20423 | module['exports'] = videojs; | ||
20424 | } | ||
20425 | |||
20426 | exports['default'] = videojs; | ||
20427 | module.exports = exports['default']; | ||
20428 | |||
20429 | },{"../../src/js/utils/merge-options.js":138,"./component":67,"./event-target":99,"./extend.js":100,"./player":108,"./plugins.js":109,"./setup":113,"./tech/flash.js":116,"./tech/html5.js":117,"./tech/tech.js":119,"./tracks/text-track.js":128,"./utils/browser.js":129,"./utils/create-deprecation-proxy.js":131,"./utils/dom.js":132,"./utils/events.js":133,"./utils/fn.js":134,"./utils/format-time.js":135,"./utils/log.js":137,"./utils/stylesheet.js":139,"./utils/time-ranges.js":140,"./utils/url.js":142,"global/document":1,"lodash-compat/object/merge":40,"object.assign":45,"xhr":56}]},{},[143])(143) | ||
20430 | }); | ||
20431 | |||
20432 | |||
20433 | //# sourceMappingURL=video.js.map | ||
20434 | /* vtt.js - v0.12.1 (https://github.com/mozilla/vtt.js) built on 08-07-2015 */ | ||
20435 | |||
20436 | (function(root) { | ||
20437 | var vttjs = root.vttjs = {}; | ||
20438 | var cueShim = vttjs.VTTCue; | ||
20439 | var regionShim = vttjs.VTTRegion; | ||
20440 | var oldVTTCue = root.VTTCue; | ||
20441 | var oldVTTRegion = root.VTTRegion; | ||
20442 | |||
20443 | vttjs.shim = function() { | ||
20444 | vttjs.VTTCue = cueShim; | ||
20445 | vttjs.VTTRegion = regionShim; | ||
20446 | }; | ||
20447 | |||
20448 | vttjs.restore = function() { | ||
20449 | vttjs.VTTCue = oldVTTCue; | ||
20450 | vttjs.VTTRegion = oldVTTRegion; | ||
20451 | }; | ||
20452 | }(this)); | ||
20453 | |||
20454 | /** | ||
20455 | * Copyright 2013 vtt.js Contributors | ||
20456 | * | ||
20457 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
20458 | * you may not use this file except in compliance with the License. | ||
20459 | * You may obtain a copy of the License at | ||
20460 | * | ||
20461 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
20462 | * | ||
20463 | * Unless required by applicable law or agreed to in writing, software | ||
20464 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
20465 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
20466 | * See the License for the specific language governing permissions and | ||
20467 | * limitations under the License. | ||
20468 | */ | ||
20469 | |||
20470 | (function(root, vttjs) { | ||
20471 | |||
20472 | var autoKeyword = "auto"; | ||
20473 | var directionSetting = { | ||
20474 | "": true, | ||
20475 | "lr": true, | ||
20476 | "rl": true | ||
20477 | }; | ||
20478 | var alignSetting = { | ||
20479 | "start": true, | ||
20480 | "middle": true, | ||
20481 | "end": true, | ||
20482 | "left": true, | ||
20483 | "right": true | ||
20484 | }; | ||
20485 | |||
20486 | function findDirectionSetting(value) { | ||
20487 | if (typeof value !== "string") { | ||
20488 | return false; | ||
20489 | } | ||
20490 | var dir = directionSetting[value.toLowerCase()]; | ||
20491 | return dir ? value.toLowerCase() : false; | ||
20492 | } | ||
20493 | |||
20494 | function findAlignSetting(value) { | ||
20495 | if (typeof value !== "string") { | ||
20496 | return false; | ||
20497 | } | ||
20498 | var align = alignSetting[value.toLowerCase()]; | ||
20499 | return align ? value.toLowerCase() : false; | ||
20500 | } | ||
20501 | |||
20502 | function extend(obj) { | ||
20503 | var i = 1; | ||
20504 | for (; i < arguments.length; i++) { | ||
20505 | var cobj = arguments[i]; | ||
20506 | for (var p in cobj) { | ||
20507 | obj[p] = cobj[p]; | ||
20508 | } | ||
20509 | } | ||
20510 | |||
20511 | return obj; | ||
20512 | } | ||
20513 | |||
20514 | function VTTCue(startTime, endTime, text) { | ||
20515 | var cue = this; | ||
20516 | var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); | ||
20517 | var baseObj = {}; | ||
20518 | |||
20519 | if (isIE8) { | ||
20520 | cue = document.createElement('custom'); | ||
20521 | } else { | ||
20522 | baseObj.enumerable = true; | ||
20523 | } | ||
20524 | |||
20525 | /** | ||
20526 | * Shim implementation specific properties. These properties are not in | ||
20527 | * the spec. | ||
20528 | */ | ||
20529 | |||
20530 | // Lets us know when the VTTCue's data has changed in such a way that we need | ||
20531 | // to recompute its display state. This lets us compute its display state | ||
20532 | // lazily. | ||
20533 | cue.hasBeenReset = false; | ||
20534 | |||
20535 | /** | ||
20536 | * VTTCue and TextTrackCue properties | ||
20537 | * http://dev.w3.org/html5/webvtt/#vttcue-interface | ||
20538 | */ | ||
20539 | |||
20540 | var _id = ""; | ||
20541 | var _pauseOnExit = false; | ||
20542 | var _startTime = startTime; | ||
20543 | var _endTime = endTime; | ||
20544 | var _text = text; | ||
20545 | var _region = null; | ||
20546 | var _vertical = ""; | ||
20547 | var _snapToLines = true; | ||
20548 | var _line = "auto"; | ||
20549 | var _lineAlign = "start"; | ||
20550 | var _position = 50; | ||
20551 | var _positionAlign = "middle"; | ||
20552 | var _size = 50; | ||
20553 | var _align = "middle"; | ||
20554 | |||
20555 | Object.defineProperty(cue, | ||
20556 | "id", extend({}, baseObj, { | ||
20557 | get: function() { | ||
20558 | return _id; | ||
20559 | }, | ||
20560 | set: function(value) { | ||
20561 | _id = "" + value; | ||
20562 | } | ||
20563 | })); | ||
20564 | |||
20565 | Object.defineProperty(cue, | ||
20566 | "pauseOnExit", extend({}, baseObj, { | ||
20567 | get: function() { | ||
20568 | return _pauseOnExit; | ||
20569 | }, | ||
20570 | set: function(value) { | ||
20571 | _pauseOnExit = !!value; | ||
20572 | } | ||
20573 | })); | ||
20574 | |||
20575 | Object.defineProperty(cue, | ||
20576 | "startTime", extend({}, baseObj, { | ||
20577 | get: function() { | ||
20578 | return _startTime; | ||
20579 | }, | ||
20580 | set: function(value) { | ||
20581 | if (typeof value !== "number") { | ||
20582 | throw new TypeError("Start time must be set to a number."); | ||
20583 | } | ||
20584 | _startTime = value; | ||
20585 | this.hasBeenReset = true; | ||
20586 | } | ||
20587 | })); | ||
20588 | |||
20589 | Object.defineProperty(cue, | ||
20590 | "endTime", extend({}, baseObj, { | ||
20591 | get: function() { | ||
20592 | return _endTime; | ||
20593 | }, | ||
20594 | set: function(value) { | ||
20595 | if (typeof value !== "number") { | ||
20596 | throw new TypeError("End time must be set to a number."); | ||
20597 | } | ||
20598 | _endTime = value; | ||
20599 | this.hasBeenReset = true; | ||
20600 | } | ||
20601 | })); | ||
20602 | |||
20603 | Object.defineProperty(cue, | ||
20604 | "text", extend({}, baseObj, { | ||
20605 | get: function() { | ||
20606 | return _text; | ||
20607 | }, | ||
20608 | set: function(value) { | ||
20609 | _text = "" + value; | ||
20610 | this.hasBeenReset = true; | ||
20611 | } | ||
20612 | })); | ||
20613 | |||
20614 | Object.defineProperty(cue, | ||
20615 | "region", extend({}, baseObj, { | ||
20616 | get: function() { | ||
20617 | return _region; | ||
20618 | }, | ||
20619 | set: function(value) { | ||
20620 | _region = value; | ||
20621 | this.hasBeenReset = true; | ||
20622 | } | ||
20623 | })); | ||
20624 | |||
20625 | Object.defineProperty(cue, | ||
20626 | "vertical", extend({}, baseObj, { | ||
20627 | get: function() { | ||
20628 | return _vertical; | ||
20629 | }, | ||
20630 | set: function(value) { | ||
20631 | var setting = findDirectionSetting(value); | ||
20632 | // Have to check for false because the setting an be an empty string. | ||
20633 | if (setting === false) { | ||
20634 | throw new SyntaxError("An invalid or illegal string was specified."); | ||
20635 | } | ||
20636 | _vertical = setting; | ||
20637 | this.hasBeenReset = true; | ||
20638 | } | ||
20639 | })); | ||
20640 | |||
20641 | Object.defineProperty(cue, | ||
20642 | "snapToLines", extend({}, baseObj, { | ||
20643 | get: function() { | ||
20644 | return _snapToLines; | ||
20645 | }, | ||
20646 | set: function(value) { | ||
20647 | _snapToLines = !!value; | ||
20648 | this.hasBeenReset = true; | ||
20649 | } | ||
20650 | })); | ||
20651 | |||
20652 | Object.defineProperty(cue, | ||
20653 | "line", extend({}, baseObj, { | ||
20654 | get: function() { | ||
20655 | return _line; | ||
20656 | }, | ||
20657 | set: function(value) { | ||
20658 | if (typeof value !== "number" && value !== autoKeyword) { | ||
20659 | throw new SyntaxError("An invalid number or illegal string was specified."); | ||
20660 | } | ||
20661 | _line = value; | ||
20662 | this.hasBeenReset = true; | ||
20663 | } | ||
20664 | })); | ||
20665 | |||
20666 | Object.defineProperty(cue, | ||
20667 | "lineAlign", extend({}, baseObj, { | ||
20668 | get: function() { | ||
20669 | return _lineAlign; | ||
20670 | }, | ||
20671 | set: function(value) { | ||
20672 | var setting = findAlignSetting(value); | ||
20673 | if (!setting) { | ||
20674 | throw new SyntaxError("An invalid or illegal string was specified."); | ||
20675 | } | ||
20676 | _lineAlign = setting; | ||
20677 | this.hasBeenReset = true; | ||
20678 | } | ||
20679 | })); | ||
20680 | |||
20681 | Object.defineProperty(cue, | ||
20682 | "position", extend({}, baseObj, { | ||
20683 | get: function() { | ||
20684 | return _position; | ||
20685 | }, | ||
20686 | set: function(value) { | ||
20687 | if (value < 0 || value > 100) { | ||
20688 | throw new Error("Position must be between 0 and 100."); | ||
20689 | } | ||
20690 | _position = value; | ||
20691 | this.hasBeenReset = true; | ||
20692 | } | ||
20693 | })); | ||
20694 | |||
20695 | Object.defineProperty(cue, | ||
20696 | "positionAlign", extend({}, baseObj, { | ||
20697 | get: function() { | ||
20698 | return _positionAlign; | ||
20699 | }, | ||
20700 | set: function(value) { | ||
20701 | var setting = findAlignSetting(value); | ||
20702 | if (!setting) { | ||
20703 | throw new SyntaxError("An invalid or illegal string was specified."); | ||
20704 | } | ||
20705 | _positionAlign = setting; | ||
20706 | this.hasBeenReset = true; | ||
20707 | } | ||
20708 | })); | ||
20709 | |||
20710 | Object.defineProperty(cue, | ||
20711 | "size", extend({}, baseObj, { | ||
20712 | get: function() { | ||
20713 | return _size; | ||
20714 | }, | ||
20715 | set: function(value) { | ||
20716 | if (value < 0 || value > 100) { | ||
20717 | throw new Error("Size must be between 0 and 100."); | ||
20718 | } | ||
20719 | _size = value; | ||
20720 | this.hasBeenReset = true; | ||
20721 | } | ||
20722 | })); | ||
20723 | |||
20724 | Object.defineProperty(cue, | ||
20725 | "align", extend({}, baseObj, { | ||
20726 | get: function() { | ||
20727 | return _align; | ||
20728 | }, | ||
20729 | set: function(value) { | ||
20730 | var setting = findAlignSetting(value); | ||
20731 | if (!setting) { | ||
20732 | throw new SyntaxError("An invalid or illegal string was specified."); | ||
20733 | } | ||
20734 | _align = setting; | ||
20735 | this.hasBeenReset = true; | ||
20736 | } | ||
20737 | })); | ||
20738 | |||
20739 | /** | ||
20740 | * Other <track> spec defined properties | ||
20741 | */ | ||
20742 | |||
20743 | // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state | ||
20744 | cue.displayState = undefined; | ||
20745 | |||
20746 | if (isIE8) { | ||
20747 | return cue; | ||
20748 | } | ||
20749 | } | ||
20750 | |||
20751 | /** | ||
20752 | * VTTCue methods | ||
20753 | */ | ||
20754 | |||
20755 | VTTCue.prototype.getCueAsHTML = function() { | ||
20756 | // Assume WebVTT.convertCueToDOMTree is on the global. | ||
20757 | return WebVTT.convertCueToDOMTree(window, this.text); | ||
20758 | }; | ||
20759 | |||
20760 | root.VTTCue = root.VTTCue || VTTCue; | ||
20761 | vttjs.VTTCue = VTTCue; | ||
20762 | }(this, (this.vttjs || {}))); | ||
20763 | |||
20764 | /** | ||
20765 | * Copyright 2013 vtt.js Contributors | ||
20766 | * | ||
20767 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
20768 | * you may not use this file except in compliance with the License. | ||
20769 | * You may obtain a copy of the License at | ||
20770 | * | ||
20771 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
20772 | * | ||
20773 | * Unless required by applicable law or agreed to in writing, software | ||
20774 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
20775 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
20776 | * See the License for the specific language governing permissions and | ||
20777 | * limitations under the License. | ||
20778 | */ | ||
20779 | |||
20780 | (function(root, vttjs) { | ||
20781 | |||
20782 | var scrollSetting = { | ||
20783 | "": true, | ||
20784 | "up": true | ||
20785 | }; | ||
20786 | |||
20787 | function findScrollSetting(value) { | ||
20788 | if (typeof value !== "string") { | ||
20789 | return false; | ||
20790 | } | ||
20791 | var scroll = scrollSetting[value.toLowerCase()]; | ||
20792 | return scroll ? value.toLowerCase() : false; | ||
20793 | } | ||
20794 | |||
20795 | function isValidPercentValue(value) { | ||
20796 | return typeof value === "number" && (value >= 0 && value <= 100); | ||
20797 | } | ||
20798 | |||
20799 | // VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface | ||
20800 | function VTTRegion() { | ||
20801 | var _width = 100; | ||
20802 | var _lines = 3; | ||
20803 | var _regionAnchorX = 0; | ||
20804 | var _regionAnchorY = 100; | ||
20805 | var _viewportAnchorX = 0; | ||
20806 | var _viewportAnchorY = 100; | ||
20807 | var _scroll = ""; | ||
20808 | |||
20809 | Object.defineProperties(this, { | ||
20810 | "width": { | ||
20811 | enumerable: true, | ||
20812 | get: function() { | ||
20813 | return _width; | ||
20814 | }, | ||
20815 | set: function(value) { | ||
20816 | if (!isValidPercentValue(value)) { | ||
20817 | throw new Error("Width must be between 0 and 100."); | ||
20818 | } | ||
20819 | _width = value; | ||
20820 | } | ||
20821 | }, | ||
20822 | "lines": { | ||
20823 | enumerable: true, | ||
20824 | get: function() { | ||
20825 | return _lines; | ||
20826 | }, | ||
20827 | set: function(value) { | ||
20828 | if (typeof value !== "number") { | ||
20829 | throw new TypeError("Lines must be set to a number."); | ||
20830 | } | ||
20831 | _lines = value; | ||
20832 | } | ||
20833 | }, | ||
20834 | "regionAnchorY": { | ||
20835 | enumerable: true, | ||
20836 | get: function() { | ||
20837 | return _regionAnchorY; | ||
20838 | }, | ||
20839 | set: function(value) { | ||
20840 | if (!isValidPercentValue(value)) { | ||
20841 | throw new Error("RegionAnchorX must be between 0 and 100."); | ||
20842 | } | ||
20843 | _regionAnchorY = value; | ||
20844 | } | ||
20845 | }, | ||
20846 | "regionAnchorX": { | ||
20847 | enumerable: true, | ||
20848 | get: function() { | ||
20849 | return _regionAnchorX; | ||
20850 | }, | ||
20851 | set: function(value) { | ||
20852 | if(!isValidPercentValue(value)) { | ||
20853 | throw new Error("RegionAnchorY must be between 0 and 100."); | ||
20854 | } | ||
20855 | _regionAnchorX = value; | ||
20856 | } | ||
20857 | }, | ||
20858 | "viewportAnchorY": { | ||
20859 | enumerable: true, | ||
20860 | get: function() { | ||
20861 | return _viewportAnchorY; | ||
20862 | }, | ||
20863 | set: function(value) { | ||
20864 | if (!isValidPercentValue(value)) { | ||
20865 | throw new Error("ViewportAnchorY must be between 0 and 100."); | ||
20866 | } | ||
20867 | _viewportAnchorY = value; | ||
20868 | } | ||
20869 | }, | ||
20870 | "viewportAnchorX": { | ||
20871 | enumerable: true, | ||
20872 | get: function() { | ||
20873 | return _viewportAnchorX; | ||
20874 | }, | ||
20875 | set: function(value) { | ||
20876 | if (!isValidPercentValue(value)) { | ||
20877 | throw new Error("ViewportAnchorX must be between 0 and 100."); | ||
20878 | } | ||
20879 | _viewportAnchorX = value; | ||
20880 | } | ||
20881 | }, | ||
20882 | "scroll": { | ||
20883 | enumerable: true, | ||
20884 | get: function() { | ||
20885 | return _scroll; | ||
20886 | }, | ||
20887 | set: function(value) { | ||
20888 | var setting = findScrollSetting(value); | ||
20889 | // Have to check for false as an empty string is a legal value. | ||
20890 | if (setting === false) { | ||
20891 | throw new SyntaxError("An invalid or illegal string was specified."); | ||
20892 | } | ||
20893 | _scroll = setting; | ||
20894 | } | ||
20895 | } | ||
20896 | }); | ||
20897 | } | ||
20898 | |||
20899 | root.VTTRegion = root.VTTRegion || VTTRegion; | ||
20900 | vttjs.VTTRegion = VTTRegion; | ||
20901 | }(this, (this.vttjs || {}))); | ||
20902 | |||
20903 | /** | ||
20904 | * Copyright 2013 vtt.js Contributors | ||
20905 | * | ||
20906 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
20907 | * you may not use this file except in compliance with the License. | ||
20908 | * You may obtain a copy of the License at | ||
20909 | * | ||
20910 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
20911 | * | ||
20912 | * Unless required by applicable law or agreed to in writing, software | ||
20913 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
20914 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
20915 | * See the License for the specific language governing permissions and | ||
20916 | * limitations under the License. | ||
20917 | */ | ||
20918 | |||
20919 | /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
20920 | /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ | ||
20921 | |||
20922 | (function(global) { | ||
20923 | |||
20924 | var _objCreate = Object.create || (function() { | ||
20925 | function F() {} | ||
20926 | return function(o) { | ||
20927 | if (arguments.length !== 1) { | ||
20928 | throw new Error('Object.create shim only accepts one parameter.'); | ||
20929 | } | ||
20930 | F.prototype = o; | ||
20931 | return new F(); | ||
20932 | }; | ||
20933 | })(); | ||
20934 | |||
20935 | // Creates a new ParserError object from an errorData object. The errorData | ||
20936 | // object should have default code and message properties. The default message | ||
20937 | // property can be overriden by passing in a message parameter. | ||
20938 | // See ParsingError.Errors below for acceptable errors. | ||
20939 | function ParsingError(errorData, message) { | ||
20940 | this.name = "ParsingError"; | ||
20941 | this.code = errorData.code; | ||
20942 | this.message = message || errorData.message; | ||
20943 | } | ||
20944 | ParsingError.prototype = _objCreate(Error.prototype); | ||
20945 | ParsingError.prototype.constructor = ParsingError; | ||
20946 | |||
20947 | // ParsingError metadata for acceptable ParsingErrors. | ||
20948 | ParsingError.Errors = { | ||
20949 | BadSignature: { | ||
20950 | code: 0, | ||
20951 | message: "Malformed WebVTT signature." | ||
20952 | }, | ||
20953 | BadTimeStamp: { | ||
20954 | code: 1, | ||
20955 | message: "Malformed time stamp." | ||
20956 | } | ||
20957 | }; | ||
20958 | |||
20959 | // Try to parse input as a time stamp. | ||
20960 | function parseTimeStamp(input) { | ||
20961 | |||
20962 | function computeSeconds(h, m, s, f) { | ||
20963 | return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000; | ||
20964 | } | ||
20965 | |||
20966 | var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/); | ||
20967 | if (!m) { | ||
20968 | return null; | ||
20969 | } | ||
20970 | |||
20971 | if (m[3]) { | ||
20972 | // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds] | ||
20973 | return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]); | ||
20974 | } else if (m[1] > 59) { | ||
20975 | // Timestamp takes the form of [hours]:[minutes].[milliseconds] | ||
20976 | // First position is hours as it's over 59. | ||
20977 | return computeSeconds(m[1], m[2], 0, m[4]); | ||
20978 | } else { | ||
20979 | // Timestamp takes the form of [minutes]:[seconds].[milliseconds] | ||
20980 | return computeSeconds(0, m[1], m[2], m[4]); | ||
20981 | } | ||
20982 | } | ||
20983 | |||
20984 | // A settings object holds key/value pairs and will ignore anything but the first | ||
20985 | // assignment to a specific key. | ||
20986 | function Settings() { | ||
20987 | this.values = _objCreate(null); | ||
20988 | } | ||
20989 | |||
20990 | Settings.prototype = { | ||
20991 | // Only accept the first assignment to any key. | ||
20992 | set: function(k, v) { | ||
20993 | if (!this.get(k) && v !== "") { | ||
20994 | this.values[k] = v; | ||
20995 | } | ||
20996 | }, | ||
20997 | // Return the value for a key, or a default value. | ||
20998 | // If 'defaultKey' is passed then 'dflt' is assumed to be an object with | ||
20999 | // a number of possible default values as properties where 'defaultKey' is | ||
21000 | // the key of the property that will be chosen; otherwise it's assumed to be | ||
21001 | // a single value. | ||
21002 | get: function(k, dflt, defaultKey) { | ||
21003 | if (defaultKey) { | ||
21004 | return this.has(k) ? this.values[k] : dflt[defaultKey]; | ||
21005 | } | ||
21006 | return this.has(k) ? this.values[k] : dflt; | ||
21007 | }, | ||
21008 | // Check whether we have a value for a key. | ||
21009 | has: function(k) { | ||
21010 | return k in this.values; | ||
21011 | }, | ||
21012 | // Accept a setting if its one of the given alternatives. | ||
21013 | alt: function(k, v, a) { | ||
21014 | for (var n = 0; n < a.length; ++n) { | ||
21015 | if (v === a[n]) { | ||
21016 | this.set(k, v); | ||
21017 | break; | ||
21018 | } | ||
21019 | } | ||
21020 | }, | ||
21021 | // Accept a setting if its a valid (signed) integer. | ||
21022 | integer: function(k, v) { | ||
21023 | if (/^-?\d+$/.test(v)) { // integer | ||
21024 | this.set(k, parseInt(v, 10)); | ||
21025 | } | ||
21026 | }, | ||
21027 | // Accept a setting if its a valid percentage. | ||
21028 | percent: function(k, v) { | ||
21029 | var m; | ||
21030 | if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) { | ||
21031 | v = parseFloat(v); | ||
21032 | if (v >= 0 && v <= 100) { | ||
21033 | this.set(k, v); | ||
21034 | return true; | ||
21035 | } | ||
21036 | } | ||
21037 | return false; | ||
21038 | } | ||
21039 | }; | ||
21040 | |||
21041 | // Helper function to parse input into groups separated by 'groupDelim', and | ||
21042 | // interprete each group as a key/value pair separated by 'keyValueDelim'. | ||
21043 | function parseOptions(input, callback, keyValueDelim, groupDelim) { | ||
21044 | var groups = groupDelim ? input.split(groupDelim) : [input]; | ||
21045 | for (var i in groups) { | ||
21046 | if (typeof groups[i] !== "string") { | ||
21047 | continue; | ||
21048 | } | ||
21049 | var kv = groups[i].split(keyValueDelim); | ||
21050 | if (kv.length !== 2) { | ||
21051 | continue; | ||
21052 | } | ||
21053 | var k = kv[0]; | ||
21054 | var v = kv[1]; | ||
21055 | callback(k, v); | ||
21056 | } | ||
21057 | } | ||
21058 | |||
21059 | function parseCue(input, cue, regionList) { | ||
21060 | // Remember the original input if we need to throw an error. | ||
21061 | var oInput = input; | ||
21062 | // 4.1 WebVTT timestamp | ||
21063 | function consumeTimeStamp() { | ||
21064 | var ts = parseTimeStamp(input); | ||
21065 | if (ts === null) { | ||
21066 | throw new ParsingError(ParsingError.Errors.BadTimeStamp, | ||
21067 | "Malformed timestamp: " + oInput); | ||
21068 | } | ||
21069 | // Remove time stamp from input. | ||
21070 | input = input.replace(/^[^\sa-zA-Z-]+/, ""); | ||
21071 | return ts; | ||
21072 | } | ||
21073 | |||
21074 | // 4.4.2 WebVTT cue settings | ||
21075 | function consumeCueSettings(input, cue) { | ||
21076 | var settings = new Settings(); | ||
21077 | |||
21078 | parseOptions(input, function (k, v) { | ||
21079 | switch (k) { | ||
21080 | case "region": | ||
21081 | // Find the last region we parsed with the same region id. | ||
21082 | for (var i = regionList.length - 1; i >= 0; i--) { | ||
21083 | if (regionList[i].id === v) { | ||
21084 | settings.set(k, regionList[i].region); | ||
21085 | break; | ||
21086 | } | ||
21087 | } | ||
21088 | break; | ||
21089 | case "vertical": | ||
21090 | settings.alt(k, v, ["rl", "lr"]); | ||
21091 | break; | ||
21092 | case "line": | ||
21093 | var vals = v.split(","), | ||
21094 | vals0 = vals[0]; | ||
21095 | settings.integer(k, vals0); | ||
21096 | settings.percent(k, vals0) ? settings.set("snapToLines", false) : null; | ||
21097 | settings.alt(k, vals0, ["auto"]); | ||
21098 | if (vals.length === 2) { | ||
21099 | settings.alt("lineAlign", vals[1], ["start", "middle", "end"]); | ||
21100 | } | ||
21101 | break; | ||
21102 | case "position": | ||
21103 | vals = v.split(","); | ||
21104 | settings.percent(k, vals[0]); | ||
21105 | if (vals.length === 2) { | ||
21106 | settings.alt("positionAlign", vals[1], ["start", "middle", "end"]); | ||
21107 | } | ||
21108 | break; | ||
21109 | case "size": | ||
21110 | settings.percent(k, v); | ||
21111 | break; | ||
21112 | case "align": | ||
21113 | settings.alt(k, v, ["start", "middle", "end", "left", "right"]); | ||
21114 | break; | ||
21115 | } | ||
21116 | }, /:/, /\s/); | ||
21117 | |||
21118 | // Apply default values for any missing fields. | ||
21119 | cue.region = settings.get("region", null); | ||
21120 | cue.vertical = settings.get("vertical", ""); | ||
21121 | cue.line = settings.get("line", "auto"); | ||
21122 | cue.lineAlign = settings.get("lineAlign", "start"); | ||
21123 | cue.snapToLines = settings.get("snapToLines", true); | ||
21124 | cue.size = settings.get("size", 100); | ||
21125 | cue.align = settings.get("align", "middle"); | ||
21126 | cue.position = settings.get("position", { | ||
21127 | start: 0, | ||
21128 | left: 0, | ||
21129 | middle: 50, | ||
21130 | end: 100, | ||
21131 | right: 100 | ||
21132 | }, cue.align); | ||
21133 | cue.positionAlign = settings.get("positionAlign", { | ||
21134 | start: "start", | ||
21135 | left: "start", | ||
21136 | middle: "middle", | ||
21137 | end: "end", | ||
21138 | right: "end" | ||
21139 | }, cue.align); | ||
21140 | } | ||
21141 | |||
21142 | function skipWhitespace() { | ||
21143 | input = input.replace(/^\s+/, ""); | ||
21144 | } | ||
21145 | |||
21146 | // 4.1 WebVTT cue timings. | ||
21147 | skipWhitespace(); | ||
21148 | cue.startTime = consumeTimeStamp(); // (1) collect cue start time | ||
21149 | skipWhitespace(); | ||
21150 | if (input.substr(0, 3) !== "-->") { // (3) next characters must match "-->" | ||
21151 | throw new ParsingError(ParsingError.Errors.BadTimeStamp, | ||
21152 | "Malformed time stamp (time stamps must be separated by '-->'): " + | ||
21153 | oInput); | ||
21154 | } | ||
21155 | input = input.substr(3); | ||
21156 | skipWhitespace(); | ||
21157 | cue.endTime = consumeTimeStamp(); // (5) collect cue end time | ||
21158 | |||
21159 | // 4.1 WebVTT cue settings list. | ||
21160 | skipWhitespace(); | ||
21161 | consumeCueSettings(input, cue); | ||
21162 | } | ||
21163 | |||
21164 | var ESCAPE = { | ||
21165 | "&": "&", | ||
21166 | "<": "<", | ||
21167 | ">": ">", | ||
21168 | "‎": "\u200e", | ||
21169 | "‏": "\u200f", | ||
21170 | " ": "\u00a0" | ||
21171 | }; | ||
21172 | |||
21173 | var TAG_NAME = { | ||
21174 | c: "span", | ||
21175 | i: "i", | ||
21176 | b: "b", | ||
21177 | u: "u", | ||
21178 | ruby: "ruby", | ||
21179 | rt: "rt", | ||
21180 | v: "span", | ||
21181 | lang: "span" | ||
21182 | }; | ||
21183 | |||
21184 | var TAG_ANNOTATION = { | ||
21185 | v: "title", | ||
21186 | lang: "lang" | ||
21187 | }; | ||
21188 | |||
21189 | var NEEDS_PARENT = { | ||
21190 | rt: "ruby" | ||
21191 | }; | ||
21192 | |||
21193 | // Parse content into a document fragment. | ||
21194 | function parseContent(window, input) { | ||
21195 | function nextToken() { | ||
21196 | // Check for end-of-string. | ||
21197 | if (!input) { | ||
21198 | return null; | ||
21199 | } | ||
21200 | |||
21201 | // Consume 'n' characters from the input. | ||
21202 | function consume(result) { | ||
21203 | input = input.substr(result.length); | ||
21204 | return result; | ||
21205 | } | ||
21206 | |||
21207 | var m = input.match(/^([^<]*)(<[^>]+>?)?/); | ||
21208 | // If there is some text before the next tag, return it, otherwise return | ||
21209 | // the tag. | ||
21210 | return consume(m[1] ? m[1] : m[2]); | ||
21211 | } | ||
21212 | |||
21213 | // Unescape a string 's'. | ||
21214 | function unescape1(e) { | ||
21215 | return ESCAPE[e]; | ||
21216 | } | ||
21217 | function unescape(s) { | ||
21218 | while ((m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/))) { | ||
21219 | s = s.replace(m[0], unescape1); | ||
21220 | } | ||
21221 | return s; | ||
21222 | } | ||
21223 | |||
21224 | function shouldAdd(current, element) { | ||
21225 | return !NEEDS_PARENT[element.localName] || | ||
21226 | NEEDS_PARENT[element.localName] === current.localName; | ||
21227 | } | ||
21228 | |||
21229 | // Create an element for this tag. | ||
21230 | function createElement(type, annotation) { | ||
21231 | var tagName = TAG_NAME[type]; | ||
21232 | if (!tagName) { | ||
21233 | return null; | ||
21234 | } | ||
21235 | var element = window.document.createElement(tagName); | ||
21236 | element.localName = tagName; | ||
21237 | var name = TAG_ANNOTATION[type]; | ||
21238 | if (name && annotation) { | ||
21239 | element[name] = annotation.trim(); | ||
21240 | } | ||
21241 | return element; | ||
21242 | } | ||
21243 | |||
21244 | var rootDiv = window.document.createElement("div"), | ||
21245 | current = rootDiv, | ||
21246 | t, | ||
21247 | tagStack = []; | ||
21248 | |||
21249 | while ((t = nextToken()) !== null) { | ||
21250 | if (t[0] === '<') { | ||
21251 | if (t[1] === "/") { | ||
21252 | // If the closing tag matches, move back up to the parent node. | ||
21253 | if (tagStack.length && | ||
21254 | tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) { | ||
21255 | tagStack.pop(); | ||
21256 | current = current.parentNode; | ||
21257 | } | ||
21258 | // Otherwise just ignore the end tag. | ||
21259 | continue; | ||
21260 | } | ||
21261 | var ts = parseTimeStamp(t.substr(1, t.length - 2)); | ||
21262 | var node; | ||
21263 | if (ts) { | ||
21264 | // Timestamps are lead nodes as well. | ||
21265 | node = window.document.createProcessingInstruction("timestamp", ts); | ||
21266 | current.appendChild(node); | ||
21267 | continue; | ||
21268 | } | ||
21269 | var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/); | ||
21270 | // If we can't parse the tag, skip to the next tag. | ||
21271 | if (!m) { | ||
21272 | continue; | ||
21273 | } | ||
21274 | // Try to construct an element, and ignore the tag if we couldn't. | ||
21275 | node = createElement(m[1], m[3]); | ||
21276 | if (!node) { | ||
21277 | continue; | ||
21278 | } | ||
21279 | // Determine if the tag should be added based on the context of where it | ||
21280 | // is placed in the cuetext. | ||
21281 | if (!shouldAdd(current, node)) { | ||
21282 | continue; | ||
21283 | } | ||
21284 | // Set the class list (as a list of classes, separated by space). | ||
21285 | if (m[2]) { | ||
21286 | node.className = m[2].substr(1).replace('.', ' '); | ||
21287 | } | ||
21288 | // Append the node to the current node, and enter the scope of the new | ||
21289 | // node. | ||
21290 | tagStack.push(m[1]); | ||
21291 | current.appendChild(node); | ||
21292 | current = node; | ||
21293 | continue; | ||
21294 | } | ||
21295 | |||
21296 | // Text nodes are leaf nodes. | ||
21297 | current.appendChild(window.document.createTextNode(unescape(t))); | ||
21298 | } | ||
21299 | |||
21300 | return rootDiv; | ||
21301 | } | ||
21302 | |||
21303 | // This is a list of all the Unicode characters that have a strong | ||
21304 | // right-to-left category. What this means is that these characters are | ||
21305 | // written right-to-left for sure. It was generated by pulling all the strong | ||
21306 | // right-to-left characters out of the Unicode data table. That table can | ||
21307 | // found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt | ||
21308 | var strongRTLChars = [0x05BE, 0x05C0, 0x05C3, 0x05C6, 0x05D0, 0x05D1, | ||
21309 | 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, | ||
21310 | 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, | ||
21311 | 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05F0, 0x05F1, | ||
21312 | 0x05F2, 0x05F3, 0x05F4, 0x0608, 0x060B, 0x060D, 0x061B, 0x061E, 0x061F, | ||
21313 | 0x0620, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, | ||
21314 | 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, | ||
21315 | 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, | ||
21316 | 0x063B, 0x063C, 0x063D, 0x063E, 0x063F, 0x0640, 0x0641, 0x0642, 0x0643, | ||
21317 | 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x066D, 0x066E, | ||
21318 | 0x066F, 0x0671, 0x0672, 0x0673, 0x0674, 0x0675, 0x0676, 0x0677, 0x0678, | ||
21319 | 0x0679, 0x067A, 0x067B, 0x067C, 0x067D, 0x067E, 0x067F, 0x0680, 0x0681, | ||
21320 | 0x0682, 0x0683, 0x0684, 0x0685, 0x0686, 0x0687, 0x0688, 0x0689, 0x068A, | ||
21321 | 0x068B, 0x068C, 0x068D, 0x068E, 0x068F, 0x0690, 0x0691, 0x0692, 0x0693, | ||
21322 | 0x0694, 0x0695, 0x0696, 0x0697, 0x0698, 0x0699, 0x069A, 0x069B, 0x069C, | ||
21323 | 0x069D, 0x069E, 0x069F, 0x06A0, 0x06A1, 0x06A2, 0x06A3, 0x06A4, 0x06A5, | ||
21324 | 0x06A6, 0x06A7, 0x06A8, 0x06A9, 0x06AA, 0x06AB, 0x06AC, 0x06AD, 0x06AE, | ||
21325 | 0x06AF, 0x06B0, 0x06B1, 0x06B2, 0x06B3, 0x06B4, 0x06B5, 0x06B6, 0x06B7, | ||
21326 | 0x06B8, 0x06B9, 0x06BA, 0x06BB, 0x06BC, 0x06BD, 0x06BE, 0x06BF, 0x06C0, | ||
21327 | 0x06C1, 0x06C2, 0x06C3, 0x06C4, 0x06C5, 0x06C6, 0x06C7, 0x06C8, 0x06C9, | ||
21328 | 0x06CA, 0x06CB, 0x06CC, 0x06CD, 0x06CE, 0x06CF, 0x06D0, 0x06D1, 0x06D2, | ||
21329 | 0x06D3, 0x06D4, 0x06D5, 0x06E5, 0x06E6, 0x06EE, 0x06EF, 0x06FA, 0x06FB, | ||
21330 | 0x06FC, 0x06FD, 0x06FE, 0x06FF, 0x0700, 0x0701, 0x0702, 0x0703, 0x0704, | ||
21331 | 0x0705, 0x0706, 0x0707, 0x0708, 0x0709, 0x070A, 0x070B, 0x070C, 0x070D, | ||
21332 | 0x070F, 0x0710, 0x0712, 0x0713, 0x0714, 0x0715, 0x0716, 0x0717, 0x0718, | ||
21333 | 0x0719, 0x071A, 0x071B, 0x071C, 0x071D, 0x071E, 0x071F, 0x0720, 0x0721, | ||
21334 | 0x0722, 0x0723, 0x0724, 0x0725, 0x0726, 0x0727, 0x0728, 0x0729, 0x072A, | ||
21335 | 0x072B, 0x072C, 0x072D, 0x072E, 0x072F, 0x074D, 0x074E, 0x074F, 0x0750, | ||
21336 | 0x0751, 0x0752, 0x0753, 0x0754, 0x0755, 0x0756, 0x0757, 0x0758, 0x0759, | ||
21337 | 0x075A, 0x075B, 0x075C, 0x075D, 0x075E, 0x075F, 0x0760, 0x0761, 0x0762, | ||
21338 | 0x0763, 0x0764, 0x0765, 0x0766, 0x0767, 0x0768, 0x0769, 0x076A, 0x076B, | ||
21339 | 0x076C, 0x076D, 0x076E, 0x076F, 0x0770, 0x0771, 0x0772, 0x0773, 0x0774, | ||
21340 | 0x0775, 0x0776, 0x0777, 0x0778, 0x0779, 0x077A, 0x077B, 0x077C, 0x077D, | ||
21341 | 0x077E, 0x077F, 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0786, | ||
21342 | 0x0787, 0x0788, 0x0789, 0x078A, 0x078B, 0x078C, 0x078D, 0x078E, 0x078F, | ||
21343 | 0x0790, 0x0791, 0x0792, 0x0793, 0x0794, 0x0795, 0x0796, 0x0797, 0x0798, | ||
21344 | 0x0799, 0x079A, 0x079B, 0x079C, 0x079D, 0x079E, 0x079F, 0x07A0, 0x07A1, | ||
21345 | 0x07A2, 0x07A3, 0x07A4, 0x07A5, 0x07B1, 0x07C0, 0x07C1, 0x07C2, 0x07C3, | ||
21346 | 0x07C4, 0x07C5, 0x07C6, 0x07C7, 0x07C8, 0x07C9, 0x07CA, 0x07CB, 0x07CC, | ||
21347 | 0x07CD, 0x07CE, 0x07CF, 0x07D0, 0x07D1, 0x07D2, 0x07D3, 0x07D4, 0x07D5, | ||
21348 | 0x07D6, 0x07D7, 0x07D8, 0x07D9, 0x07DA, 0x07DB, 0x07DC, 0x07DD, 0x07DE, | ||
21349 | 0x07DF, 0x07E0, 0x07E1, 0x07E2, 0x07E3, 0x07E4, 0x07E5, 0x07E6, 0x07E7, | ||
21350 | 0x07E8, 0x07E9, 0x07EA, 0x07F4, 0x07F5, 0x07FA, 0x0800, 0x0801, 0x0802, | ||
21351 | 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809, 0x080A, 0x080B, | ||
21352 | 0x080C, 0x080D, 0x080E, 0x080F, 0x0810, 0x0811, 0x0812, 0x0813, 0x0814, | ||
21353 | 0x0815, 0x081A, 0x0824, 0x0828, 0x0830, 0x0831, 0x0832, 0x0833, 0x0834, | ||
21354 | 0x0835, 0x0836, 0x0837, 0x0838, 0x0839, 0x083A, 0x083B, 0x083C, 0x083D, | ||
21355 | 0x083E, 0x0840, 0x0841, 0x0842, 0x0843, 0x0844, 0x0845, 0x0846, 0x0847, | ||
21356 | 0x0848, 0x0849, 0x084A, 0x084B, 0x084C, 0x084D, 0x084E, 0x084F, 0x0850, | ||
21357 | 0x0851, 0x0852, 0x0853, 0x0854, 0x0855, 0x0856, 0x0857, 0x0858, 0x085E, | ||
21358 | 0x08A0, 0x08A2, 0x08A3, 0x08A4, 0x08A5, 0x08A6, 0x08A7, 0x08A8, 0x08A9, | ||
21359 | 0x08AA, 0x08AB, 0x08AC, 0x200F, 0xFB1D, 0xFB1F, 0xFB20, 0xFB21, 0xFB22, | ||
21360 | 0xFB23, 0xFB24, 0xFB25, 0xFB26, 0xFB27, 0xFB28, 0xFB2A, 0xFB2B, 0xFB2C, | ||
21361 | 0xFB2D, 0xFB2E, 0xFB2F, 0xFB30, 0xFB31, 0xFB32, 0xFB33, 0xFB34, 0xFB35, | ||
21362 | 0xFB36, 0xFB38, 0xFB39, 0xFB3A, 0xFB3B, 0xFB3C, 0xFB3E, 0xFB40, 0xFB41, | ||
21363 | 0xFB43, 0xFB44, 0xFB46, 0xFB47, 0xFB48, 0xFB49, 0xFB4A, 0xFB4B, 0xFB4C, | ||
21364 | 0xFB4D, 0xFB4E, 0xFB4F, 0xFB50, 0xFB51, 0xFB52, 0xFB53, 0xFB54, 0xFB55, | ||
21365 | 0xFB56, 0xFB57, 0xFB58, 0xFB59, 0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D, 0xFB5E, | ||
21366 | 0xFB5F, 0xFB60, 0xFB61, 0xFB62, 0xFB63, 0xFB64, 0xFB65, 0xFB66, 0xFB67, | ||
21367 | 0xFB68, 0xFB69, 0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D, 0xFB6E, 0xFB6F, 0xFB70, | ||
21368 | 0xFB71, 0xFB72, 0xFB73, 0xFB74, 0xFB75, 0xFB76, 0xFB77, 0xFB78, 0xFB79, | ||
21369 | 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D, 0xFB7E, 0xFB7F, 0xFB80, 0xFB81, 0xFB82, | ||
21370 | 0xFB83, 0xFB84, 0xFB85, 0xFB86, 0xFB87, 0xFB88, 0xFB89, 0xFB8A, 0xFB8B, | ||
21371 | 0xFB8C, 0xFB8D, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91, 0xFB92, 0xFB93, 0xFB94, | ||
21372 | 0xFB95, 0xFB96, 0xFB97, 0xFB98, 0xFB99, 0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D, | ||
21373 | 0xFB9E, 0xFB9F, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3, 0xFBA4, 0xFBA5, 0xFBA6, | ||
21374 | 0xFBA7, 0xFBA8, 0xFBA9, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD, 0xFBAE, 0xFBAF, | ||
21375 | 0xFBB0, 0xFBB1, 0xFBB2, 0xFBB3, 0xFBB4, 0xFBB5, 0xFBB6, 0xFBB7, 0xFBB8, | ||
21376 | 0xFBB9, 0xFBBA, 0xFBBB, 0xFBBC, 0xFBBD, 0xFBBE, 0xFBBF, 0xFBC0, 0xFBC1, | ||
21377 | 0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6, 0xFBD7, 0xFBD8, 0xFBD9, 0xFBDA, 0xFBDB, | ||
21378 | 0xFBDC, 0xFBDD, 0xFBDE, 0xFBDF, 0xFBE0, 0xFBE1, 0xFBE2, 0xFBE3, 0xFBE4, | ||
21379 | 0xFBE5, 0xFBE6, 0xFBE7, 0xFBE8, 0xFBE9, 0xFBEA, 0xFBEB, 0xFBEC, 0xFBED, | ||
21380 | 0xFBEE, 0xFBEF, 0xFBF0, 0xFBF1, 0xFBF2, 0xFBF3, 0xFBF4, 0xFBF5, 0xFBF6, | ||
21381 | 0xFBF7, 0xFBF8, 0xFBF9, 0xFBFA, 0xFBFB, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF, | ||
21382 | 0xFC00, 0xFC01, 0xFC02, 0xFC03, 0xFC04, 0xFC05, 0xFC06, 0xFC07, 0xFC08, | ||
21383 | 0xFC09, 0xFC0A, 0xFC0B, 0xFC0C, 0xFC0D, 0xFC0E, 0xFC0F, 0xFC10, 0xFC11, | ||
21384 | 0xFC12, 0xFC13, 0xFC14, 0xFC15, 0xFC16, 0xFC17, 0xFC18, 0xFC19, 0xFC1A, | ||
21385 | 0xFC1B, 0xFC1C, 0xFC1D, 0xFC1E, 0xFC1F, 0xFC20, 0xFC21, 0xFC22, 0xFC23, | ||
21386 | 0xFC24, 0xFC25, 0xFC26, 0xFC27, 0xFC28, 0xFC29, 0xFC2A, 0xFC2B, 0xFC2C, | ||
21387 | 0xFC2D, 0xFC2E, 0xFC2F, 0xFC30, 0xFC31, 0xFC32, 0xFC33, 0xFC34, 0xFC35, | ||
21388 | 0xFC36, 0xFC37, 0xFC38, 0xFC39, 0xFC3A, 0xFC3B, 0xFC3C, 0xFC3D, 0xFC3E, | ||
21389 | 0xFC3F, 0xFC40, 0xFC41, 0xFC42, 0xFC43, 0xFC44, 0xFC45, 0xFC46, 0xFC47, | ||
21390 | 0xFC48, 0xFC49, 0xFC4A, 0xFC4B, 0xFC4C, 0xFC4D, 0xFC4E, 0xFC4F, 0xFC50, | ||
21391 | 0xFC51, 0xFC52, 0xFC53, 0xFC54, 0xFC55, 0xFC56, 0xFC57, 0xFC58, 0xFC59, | ||
21392 | 0xFC5A, 0xFC5B, 0xFC5C, 0xFC5D, 0xFC5E, 0xFC5F, 0xFC60, 0xFC61, 0xFC62, | ||
21393 | 0xFC63, 0xFC64, 0xFC65, 0xFC66, 0xFC67, 0xFC68, 0xFC69, 0xFC6A, 0xFC6B, | ||
21394 | 0xFC6C, 0xFC6D, 0xFC6E, 0xFC6F, 0xFC70, 0xFC71, 0xFC72, 0xFC73, 0xFC74, | ||
21395 | 0xFC75, 0xFC76, 0xFC77, 0xFC78, 0xFC79, 0xFC7A, 0xFC7B, 0xFC7C, 0xFC7D, | ||
21396 | 0xFC7E, 0xFC7F, 0xFC80, 0xFC81, 0xFC82, 0xFC83, 0xFC84, 0xFC85, 0xFC86, | ||
21397 | 0xFC87, 0xFC88, 0xFC89, 0xFC8A, 0xFC8B, 0xFC8C, 0xFC8D, 0xFC8E, 0xFC8F, | ||
21398 | 0xFC90, 0xFC91, 0xFC92, 0xFC93, 0xFC94, 0xFC95, 0xFC96, 0xFC97, 0xFC98, | ||
21399 | 0xFC99, 0xFC9A, 0xFC9B, 0xFC9C, 0xFC9D, 0xFC9E, 0xFC9F, 0xFCA0, 0xFCA1, | ||
21400 | 0xFCA2, 0xFCA3, 0xFCA4, 0xFCA5, 0xFCA6, 0xFCA7, 0xFCA8, 0xFCA9, 0xFCAA, | ||
21401 | 0xFCAB, 0xFCAC, 0xFCAD, 0xFCAE, 0xFCAF, 0xFCB0, 0xFCB1, 0xFCB2, 0xFCB3, | ||
21402 | 0xFCB4, 0xFCB5, 0xFCB6, 0xFCB7, 0xFCB8, 0xFCB9, 0xFCBA, 0xFCBB, 0xFCBC, | ||
21403 | 0xFCBD, 0xFCBE, 0xFCBF, 0xFCC0, 0xFCC1, 0xFCC2, 0xFCC3, 0xFCC4, 0xFCC5, | ||
21404 | 0xFCC6, 0xFCC7, 0xFCC8, 0xFCC9, 0xFCCA, 0xFCCB, 0xFCCC, 0xFCCD, 0xFCCE, | ||
21405 | 0xFCCF, 0xFCD0, 0xFCD1, 0xFCD2, 0xFCD3, 0xFCD4, 0xFCD5, 0xFCD6, 0xFCD7, | ||
21406 | 0xFCD8, 0xFCD9, 0xFCDA, 0xFCDB, 0xFCDC, 0xFCDD, 0xFCDE, 0xFCDF, 0xFCE0, | ||
21407 | 0xFCE1, 0xFCE2, 0xFCE3, 0xFCE4, 0xFCE5, 0xFCE6, 0xFCE7, 0xFCE8, 0xFCE9, | ||
21408 | 0xFCEA, 0xFCEB, 0xFCEC, 0xFCED, 0xFCEE, 0xFCEF, 0xFCF0, 0xFCF1, 0xFCF2, | ||
21409 | 0xFCF3, 0xFCF4, 0xFCF5, 0xFCF6, 0xFCF7, 0xFCF8, 0xFCF9, 0xFCFA, 0xFCFB, | ||
21410 | 0xFCFC, 0xFCFD, 0xFCFE, 0xFCFF, 0xFD00, 0xFD01, 0xFD02, 0xFD03, 0xFD04, | ||
21411 | 0xFD05, 0xFD06, 0xFD07, 0xFD08, 0xFD09, 0xFD0A, 0xFD0B, 0xFD0C, 0xFD0D, | ||
21412 | 0xFD0E, 0xFD0F, 0xFD10, 0xFD11, 0xFD12, 0xFD13, 0xFD14, 0xFD15, 0xFD16, | ||
21413 | 0xFD17, 0xFD18, 0xFD19, 0xFD1A, 0xFD1B, 0xFD1C, 0xFD1D, 0xFD1E, 0xFD1F, | ||
21414 | 0xFD20, 0xFD21, 0xFD22, 0xFD23, 0xFD24, 0xFD25, 0xFD26, 0xFD27, 0xFD28, | ||
21415 | 0xFD29, 0xFD2A, 0xFD2B, 0xFD2C, 0xFD2D, 0xFD2E, 0xFD2F, 0xFD30, 0xFD31, | ||
21416 | 0xFD32, 0xFD33, 0xFD34, 0xFD35, 0xFD36, 0xFD37, 0xFD38, 0xFD39, 0xFD3A, | ||
21417 | 0xFD3B, 0xFD3C, 0xFD3D, 0xFD50, 0xFD51, 0xFD52, 0xFD53, 0xFD54, 0xFD55, | ||
21418 | 0xFD56, 0xFD57, 0xFD58, 0xFD59, 0xFD5A, 0xFD5B, 0xFD5C, 0xFD5D, 0xFD5E, | ||
21419 | 0xFD5F, 0xFD60, 0xFD61, 0xFD62, 0xFD63, 0xFD64, 0xFD65, 0xFD66, 0xFD67, | ||
21420 | 0xFD68, 0xFD69, 0xFD6A, 0xFD6B, 0xFD6C, 0xFD6D, 0xFD6E, 0xFD6F, 0xFD70, | ||
21421 | 0xFD71, 0xFD72, 0xFD73, 0xFD74, 0xFD75, 0xFD76, 0xFD77, 0xFD78, 0xFD79, | ||
21422 | 0xFD7A, 0xFD7B, 0xFD7C, 0xFD7D, 0xFD7E, 0xFD7F, 0xFD80, 0xFD81, 0xFD82, | ||
21423 | 0xFD83, 0xFD84, 0xFD85, 0xFD86, 0xFD87, 0xFD88, 0xFD89, 0xFD8A, 0xFD8B, | ||
21424 | 0xFD8C, 0xFD8D, 0xFD8E, 0xFD8F, 0xFD92, 0xFD93, 0xFD94, 0xFD95, 0xFD96, | ||
21425 | 0xFD97, 0xFD98, 0xFD99, 0xFD9A, 0xFD9B, 0xFD9C, 0xFD9D, 0xFD9E, 0xFD9F, | ||
21426 | 0xFDA0, 0xFDA1, 0xFDA2, 0xFDA3, 0xFDA4, 0xFDA5, 0xFDA6, 0xFDA7, 0xFDA8, | ||
21427 | 0xFDA9, 0xFDAA, 0xFDAB, 0xFDAC, 0xFDAD, 0xFDAE, 0xFDAF, 0xFDB0, 0xFDB1, | ||
21428 | 0xFDB2, 0xFDB3, 0xFDB4, 0xFDB5, 0xFDB6, 0xFDB7, 0xFDB8, 0xFDB9, 0xFDBA, | ||
21429 | 0xFDBB, 0xFDBC, 0xFDBD, 0xFDBE, 0xFDBF, 0xFDC0, 0xFDC1, 0xFDC2, 0xFDC3, | ||
21430 | 0xFDC4, 0xFDC5, 0xFDC6, 0xFDC7, 0xFDF0, 0xFDF1, 0xFDF2, 0xFDF3, 0xFDF4, | ||
21431 | 0xFDF5, 0xFDF6, 0xFDF7, 0xFDF8, 0xFDF9, 0xFDFA, 0xFDFB, 0xFDFC, 0xFE70, | ||
21432 | 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, | ||
21433 | 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F, 0xFE80, 0xFE81, 0xFE82, 0xFE83, | ||
21434 | 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, | ||
21435 | 0xFE8D, 0xFE8E, 0xFE8F, 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, | ||
21436 | 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, | ||
21437 | 0xFE9F, 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, | ||
21438 | 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF, 0xFEB0, | ||
21439 | 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, | ||
21440 | 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0, 0xFEC1, 0xFEC2, | ||
21441 | 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, | ||
21442 | 0xFECC, 0xFECD, 0xFECE, 0xFECF, 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, | ||
21443 | 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, | ||
21444 | 0xFEDE, 0xFEDF, 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, | ||
21445 | 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF, | ||
21446 | 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, | ||
21447 | 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0x10800, 0x10801, 0x10802, 0x10803, | ||
21448 | 0x10804, 0x10805, 0x10808, 0x1080A, 0x1080B, 0x1080C, 0x1080D, 0x1080E, | ||
21449 | 0x1080F, 0x10810, 0x10811, 0x10812, 0x10813, 0x10814, 0x10815, 0x10816, | ||
21450 | 0x10817, 0x10818, 0x10819, 0x1081A, 0x1081B, 0x1081C, 0x1081D, 0x1081E, | ||
21451 | 0x1081F, 0x10820, 0x10821, 0x10822, 0x10823, 0x10824, 0x10825, 0x10826, | ||
21452 | 0x10827, 0x10828, 0x10829, 0x1082A, 0x1082B, 0x1082C, 0x1082D, 0x1082E, | ||
21453 | 0x1082F, 0x10830, 0x10831, 0x10832, 0x10833, 0x10834, 0x10835, 0x10837, | ||
21454 | 0x10838, 0x1083C, 0x1083F, 0x10840, 0x10841, 0x10842, 0x10843, 0x10844, | ||
21455 | 0x10845, 0x10846, 0x10847, 0x10848, 0x10849, 0x1084A, 0x1084B, 0x1084C, | ||
21456 | 0x1084D, 0x1084E, 0x1084F, 0x10850, 0x10851, 0x10852, 0x10853, 0x10854, | ||
21457 | 0x10855, 0x10857, 0x10858, 0x10859, 0x1085A, 0x1085B, 0x1085C, 0x1085D, | ||
21458 | 0x1085E, 0x1085F, 0x10900, 0x10901, 0x10902, 0x10903, 0x10904, 0x10905, | ||
21459 | 0x10906, 0x10907, 0x10908, 0x10909, 0x1090A, 0x1090B, 0x1090C, 0x1090D, | ||
21460 | 0x1090E, 0x1090F, 0x10910, 0x10911, 0x10912, 0x10913, 0x10914, 0x10915, | ||
21461 | 0x10916, 0x10917, 0x10918, 0x10919, 0x1091A, 0x1091B, 0x10920, 0x10921, | ||
21462 | 0x10922, 0x10923, 0x10924, 0x10925, 0x10926, 0x10927, 0x10928, 0x10929, | ||
21463 | 0x1092A, 0x1092B, 0x1092C, 0x1092D, 0x1092E, 0x1092F, 0x10930, 0x10931, | ||
21464 | 0x10932, 0x10933, 0x10934, 0x10935, 0x10936, 0x10937, 0x10938, 0x10939, | ||
21465 | 0x1093F, 0x10980, 0x10981, 0x10982, 0x10983, 0x10984, 0x10985, 0x10986, | ||
21466 | 0x10987, 0x10988, 0x10989, 0x1098A, 0x1098B, 0x1098C, 0x1098D, 0x1098E, | ||
21467 | 0x1098F, 0x10990, 0x10991, 0x10992, 0x10993, 0x10994, 0x10995, 0x10996, | ||
21468 | 0x10997, 0x10998, 0x10999, 0x1099A, 0x1099B, 0x1099C, 0x1099D, 0x1099E, | ||
21469 | 0x1099F, 0x109A0, 0x109A1, 0x109A2, 0x109A3, 0x109A4, 0x109A5, 0x109A6, | ||
21470 | 0x109A7, 0x109A8, 0x109A9, 0x109AA, 0x109AB, 0x109AC, 0x109AD, 0x109AE, | ||
21471 | 0x109AF, 0x109B0, 0x109B1, 0x109B2, 0x109B3, 0x109B4, 0x109B5, 0x109B6, | ||
21472 | 0x109B7, 0x109BE, 0x109BF, 0x10A00, 0x10A10, 0x10A11, 0x10A12, 0x10A13, | ||
21473 | 0x10A15, 0x10A16, 0x10A17, 0x10A19, 0x10A1A, 0x10A1B, 0x10A1C, 0x10A1D, | ||
21474 | 0x10A1E, 0x10A1F, 0x10A20, 0x10A21, 0x10A22, 0x10A23, 0x10A24, 0x10A25, | ||
21475 | 0x10A26, 0x10A27, 0x10A28, 0x10A29, 0x10A2A, 0x10A2B, 0x10A2C, 0x10A2D, | ||
21476 | 0x10A2E, 0x10A2F, 0x10A30, 0x10A31, 0x10A32, 0x10A33, 0x10A40, 0x10A41, | ||
21477 | 0x10A42, 0x10A43, 0x10A44, 0x10A45, 0x10A46, 0x10A47, 0x10A50, 0x10A51, | ||
21478 | 0x10A52, 0x10A53, 0x10A54, 0x10A55, 0x10A56, 0x10A57, 0x10A58, 0x10A60, | ||
21479 | 0x10A61, 0x10A62, 0x10A63, 0x10A64, 0x10A65, 0x10A66, 0x10A67, 0x10A68, | ||
21480 | 0x10A69, 0x10A6A, 0x10A6B, 0x10A6C, 0x10A6D, 0x10A6E, 0x10A6F, 0x10A70, | ||
21481 | 0x10A71, 0x10A72, 0x10A73, 0x10A74, 0x10A75, 0x10A76, 0x10A77, 0x10A78, | ||
21482 | 0x10A79, 0x10A7A, 0x10A7B, 0x10A7C, 0x10A7D, 0x10A7E, 0x10A7F, 0x10B00, | ||
21483 | 0x10B01, 0x10B02, 0x10B03, 0x10B04, 0x10B05, 0x10B06, 0x10B07, 0x10B08, | ||
21484 | 0x10B09, 0x10B0A, 0x10B0B, 0x10B0C, 0x10B0D, 0x10B0E, 0x10B0F, 0x10B10, | ||
21485 | 0x10B11, 0x10B12, 0x10B13, 0x10B14, 0x10B15, 0x10B16, 0x10B17, 0x10B18, | ||
21486 | 0x10B19, 0x10B1A, 0x10B1B, 0x10B1C, 0x10B1D, 0x10B1E, 0x10B1F, 0x10B20, | ||
21487 | 0x10B21, 0x10B22, 0x10B23, 0x10B24, 0x10B25, 0x10B26, 0x10B27, 0x10B28, | ||
21488 | 0x10B29, 0x10B2A, 0x10B2B, 0x10B2C, 0x10B2D, 0x10B2E, 0x10B2F, 0x10B30, | ||
21489 | 0x10B31, 0x10B32, 0x10B33, 0x10B34, 0x10B35, 0x10B40, 0x10B41, 0x10B42, | ||
21490 | 0x10B43, 0x10B44, 0x10B45, 0x10B46, 0x10B47, 0x10B48, 0x10B49, 0x10B4A, | ||
21491 | 0x10B4B, 0x10B4C, 0x10B4D, 0x10B4E, 0x10B4F, 0x10B50, 0x10B51, 0x10B52, | ||
21492 | 0x10B53, 0x10B54, 0x10B55, 0x10B58, 0x10B59, 0x10B5A, 0x10B5B, 0x10B5C, | ||
21493 | 0x10B5D, 0x10B5E, 0x10B5F, 0x10B60, 0x10B61, 0x10B62, 0x10B63, 0x10B64, | ||
21494 | 0x10B65, 0x10B66, 0x10B67, 0x10B68, 0x10B69, 0x10B6A, 0x10B6B, 0x10B6C, | ||
21495 | 0x10B6D, 0x10B6E, 0x10B6F, 0x10B70, 0x10B71, 0x10B72, 0x10B78, 0x10B79, | ||
21496 | 0x10B7A, 0x10B7B, 0x10B7C, 0x10B7D, 0x10B7E, 0x10B7F, 0x10C00, 0x10C01, | ||
21497 | 0x10C02, 0x10C03, 0x10C04, 0x10C05, 0x10C06, 0x10C07, 0x10C08, 0x10C09, | ||
21498 | 0x10C0A, 0x10C0B, 0x10C0C, 0x10C0D, 0x10C0E, 0x10C0F, 0x10C10, 0x10C11, | ||
21499 | 0x10C12, 0x10C13, 0x10C14, 0x10C15, 0x10C16, 0x10C17, 0x10C18, 0x10C19, | ||
21500 | 0x10C1A, 0x10C1B, 0x10C1C, 0x10C1D, 0x10C1E, 0x10C1F, 0x10C20, 0x10C21, | ||
21501 | 0x10C22, 0x10C23, 0x10C24, 0x10C25, 0x10C26, 0x10C27, 0x10C28, 0x10C29, | ||
21502 | 0x10C2A, 0x10C2B, 0x10C2C, 0x10C2D, 0x10C2E, 0x10C2F, 0x10C30, 0x10C31, | ||
21503 | 0x10C32, 0x10C33, 0x10C34, 0x10C35, 0x10C36, 0x10C37, 0x10C38, 0x10C39, | ||
21504 | 0x10C3A, 0x10C3B, 0x10C3C, 0x10C3D, 0x10C3E, 0x10C3F, 0x10C40, 0x10C41, | ||
21505 | 0x10C42, 0x10C43, 0x10C44, 0x10C45, 0x10C46, 0x10C47, 0x10C48, 0x1EE00, | ||
21506 | 0x1EE01, 0x1EE02, 0x1EE03, 0x1EE05, 0x1EE06, 0x1EE07, 0x1EE08, 0x1EE09, | ||
21507 | 0x1EE0A, 0x1EE0B, 0x1EE0C, 0x1EE0D, 0x1EE0E, 0x1EE0F, 0x1EE10, 0x1EE11, | ||
21508 | 0x1EE12, 0x1EE13, 0x1EE14, 0x1EE15, 0x1EE16, 0x1EE17, 0x1EE18, 0x1EE19, | ||
21509 | 0x1EE1A, 0x1EE1B, 0x1EE1C, 0x1EE1D, 0x1EE1E, 0x1EE1F, 0x1EE21, 0x1EE22, | ||
21510 | 0x1EE24, 0x1EE27, 0x1EE29, 0x1EE2A, 0x1EE2B, 0x1EE2C, 0x1EE2D, 0x1EE2E, | ||
21511 | 0x1EE2F, 0x1EE30, 0x1EE31, 0x1EE32, 0x1EE34, 0x1EE35, 0x1EE36, 0x1EE37, | ||
21512 | 0x1EE39, 0x1EE3B, 0x1EE42, 0x1EE47, 0x1EE49, 0x1EE4B, 0x1EE4D, 0x1EE4E, | ||
21513 | 0x1EE4F, 0x1EE51, 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, 0x1EE5D, | ||
21514 | 0x1EE5F, 0x1EE61, 0x1EE62, 0x1EE64, 0x1EE67, 0x1EE68, 0x1EE69, 0x1EE6A, | ||
21515 | 0x1EE6C, 0x1EE6D, 0x1EE6E, 0x1EE6F, 0x1EE70, 0x1EE71, 0x1EE72, 0x1EE74, | ||
21516 | 0x1EE75, 0x1EE76, 0x1EE77, 0x1EE79, 0x1EE7A, 0x1EE7B, 0x1EE7C, 0x1EE7E, | ||
21517 | 0x1EE80, 0x1EE81, 0x1EE82, 0x1EE83, 0x1EE84, 0x1EE85, 0x1EE86, 0x1EE87, | ||
21518 | 0x1EE88, 0x1EE89, 0x1EE8B, 0x1EE8C, 0x1EE8D, 0x1EE8E, 0x1EE8F, 0x1EE90, | ||
21519 | 0x1EE91, 0x1EE92, 0x1EE93, 0x1EE94, 0x1EE95, 0x1EE96, 0x1EE97, 0x1EE98, | ||
21520 | 0x1EE99, 0x1EE9A, 0x1EE9B, 0x1EEA1, 0x1EEA2, 0x1EEA3, 0x1EEA5, 0x1EEA6, | ||
21521 | 0x1EEA7, 0x1EEA8, 0x1EEA9, 0x1EEAB, 0x1EEAC, 0x1EEAD, 0x1EEAE, 0x1EEAF, | ||
21522 | 0x1EEB0, 0x1EEB1, 0x1EEB2, 0x1EEB3, 0x1EEB4, 0x1EEB5, 0x1EEB6, 0x1EEB7, | ||
21523 | 0x1EEB8, 0x1EEB9, 0x1EEBA, 0x1EEBB, 0x10FFFD]; | ||
21524 | |||
21525 | function determineBidi(cueDiv) { | ||
21526 | var nodeStack = [], | ||
21527 | text = "", | ||
21528 | charCode; | ||
21529 | |||
21530 | if (!cueDiv || !cueDiv.childNodes) { | ||
21531 | return "ltr"; | ||
21532 | } | ||
21533 | |||
21534 | function pushNodes(nodeStack, node) { | ||
21535 | for (var i = node.childNodes.length - 1; i >= 0; i--) { | ||
21536 | nodeStack.push(node.childNodes[i]); | ||
21537 | } | ||
21538 | } | ||
21539 | |||
21540 | function nextTextNode(nodeStack) { | ||
21541 | if (!nodeStack || !nodeStack.length) { | ||
21542 | return null; | ||
21543 | } | ||
21544 | |||
21545 | var node = nodeStack.pop(), | ||
21546 | text = node.textContent || node.innerText; | ||
21547 | if (text) { | ||
21548 | // TODO: This should match all unicode type B characters (paragraph | ||
21549 | // separator characters). See issue #115. | ||
21550 | var m = text.match(/^.*(\n|\r)/); | ||
21551 | if (m) { | ||
21552 | nodeStack.length = 0; | ||
21553 | return m[0]; | ||
21554 | } | ||
21555 | return text; | ||
21556 | } | ||
21557 | if (node.tagName === "ruby") { | ||
21558 | return nextTextNode(nodeStack); | ||
21559 | } | ||
21560 | if (node.childNodes) { | ||
21561 | pushNodes(nodeStack, node); | ||
21562 | return nextTextNode(nodeStack); | ||
21563 | } | ||
21564 | } | ||
21565 | |||
21566 | pushNodes(nodeStack, cueDiv); | ||
21567 | while ((text = nextTextNode(nodeStack))) { | ||
21568 | for (var i = 0; i < text.length; i++) { | ||
21569 | charCode = text.charCodeAt(i); | ||
21570 | for (var j = 0; j < strongRTLChars.length; j++) { | ||
21571 | if (strongRTLChars[j] === charCode) { | ||
21572 | return "rtl"; | ||
21573 | } | ||
21574 | } | ||
21575 | } | ||
21576 | } | ||
21577 | return "ltr"; | ||
21578 | } | ||
21579 | |||
21580 | function computeLinePos(cue) { | ||
21581 | if (typeof cue.line === "number" && | ||
21582 | (cue.snapToLines || (cue.line >= 0 && cue.line <= 100))) { | ||
21583 | return cue.line; | ||
21584 | } | ||
21585 | if (!cue.track || !cue.track.textTrackList || | ||
21586 | !cue.track.textTrackList.mediaElement) { | ||
21587 | return -1; | ||
21588 | } | ||
21589 | var track = cue.track, | ||
21590 | trackList = track.textTrackList, | ||
21591 | count = 0; | ||
21592 | for (var i = 0; i < trackList.length && trackList[i] !== track; i++) { | ||
21593 | if (trackList[i].mode === "showing") { | ||
21594 | count++; | ||
21595 | } | ||
21596 | } | ||
21597 | return ++count * -1; | ||
21598 | } | ||
21599 | |||
21600 | function StyleBox() { | ||
21601 | } | ||
21602 | |||
21603 | // Apply styles to a div. If there is no div passed then it defaults to the | ||
21604 | // div on 'this'. | ||
21605 | StyleBox.prototype.applyStyles = function(styles, div) { | ||
21606 | div = div || this.div; | ||
21607 | for (var prop in styles) { | ||
21608 | if (styles.hasOwnProperty(prop)) { | ||
21609 | div.style[prop] = styles[prop]; | ||
21610 | } | ||
21611 | } | ||
21612 | }; | ||
21613 | |||
21614 | StyleBox.prototype.formatStyle = function(val, unit) { | ||
21615 | return val === 0 ? 0 : val + unit; | ||
21616 | }; | ||
21617 | |||
21618 | // Constructs the computed display state of the cue (a div). Places the div | ||
21619 | // into the overlay which should be a block level element (usually a div). | ||
21620 | function CueStyleBox(window, cue, styleOptions) { | ||
21621 | var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); | ||
21622 | var color = "rgba(255, 255, 255, 1)"; | ||
21623 | var backgroundColor = "rgba(0, 0, 0, 0.8)"; | ||
21624 | |||
21625 | if (isIE8) { | ||
21626 | color = "rgb(255, 255, 255)"; | ||
21627 | backgroundColor = "rgb(0, 0, 0)"; | ||
21628 | } | ||
21629 | |||
21630 | StyleBox.call(this); | ||
21631 | this.cue = cue; | ||
21632 | |||
21633 | // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will | ||
21634 | // have inline positioning and will function as the cue background box. | ||
21635 | this.cueDiv = parseContent(window, cue.text); | ||
21636 | var styles = { | ||
21637 | color: color, | ||
21638 | backgroundColor: backgroundColor, | ||
21639 | position: "relative", | ||
21640 | left: 0, | ||
21641 | right: 0, | ||
21642 | top: 0, | ||
21643 | bottom: 0, | ||
21644 | display: "inline" | ||
21645 | }; | ||
21646 | |||
21647 | if (!isIE8) { | ||
21648 | styles.writingMode = cue.vertical === "" ? "horizontal-tb" | ||
21649 | : cue.vertical === "lr" ? "vertical-lr" | ||
21650 | : "vertical-rl"; | ||
21651 | styles.unicodeBidi = "plaintext"; | ||
21652 | } | ||
21653 | this.applyStyles(styles, this.cueDiv); | ||
21654 | |||
21655 | // Create an absolutely positioned div that will be used to position the cue | ||
21656 | // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS | ||
21657 | // mirrors of them except "middle" which is "center" in CSS. | ||
21658 | this.div = window.document.createElement("div"); | ||
21659 | styles = { | ||
21660 | textAlign: cue.align === "middle" ? "center" : cue.align, | ||
21661 | font: styleOptions.font, | ||
21662 | whiteSpace: "pre-line", | ||
21663 | position: "absolute" | ||
21664 | }; | ||
21665 | |||
21666 | if (!isIE8) { | ||
21667 | styles.direction = determineBidi(this.cueDiv); | ||
21668 | styles.writingMode = cue.vertical === "" ? "horizontal-tb" | ||
21669 | : cue.vertical === "lr" ? "vertical-lr" | ||
21670 | : "vertical-rl". | ||
21671 | stylesunicodeBidi = "plaintext"; | ||
21672 | } | ||
21673 | |||
21674 | this.applyStyles(styles); | ||
21675 | |||
21676 | this.div.appendChild(this.cueDiv); | ||
21677 | |||
21678 | // Calculate the distance from the reference edge of the viewport to the text | ||
21679 | // position of the cue box. The reference edge will be resolved later when | ||
21680 | // the box orientation styles are applied. | ||
21681 | var textPos = 0; | ||
21682 | switch (cue.positionAlign) { | ||
21683 | case "start": | ||
21684 | textPos = cue.position; | ||
21685 | break; | ||
21686 | case "middle": | ||
21687 | textPos = cue.position - (cue.size / 2); | ||
21688 | break; | ||
21689 | case "end": | ||
21690 | textPos = cue.position - cue.size; | ||
21691 | break; | ||
21692 | } | ||
21693 | |||
21694 | // Horizontal box orientation; textPos is the distance from the left edge of the | ||
21695 | // area to the left edge of the box and cue.size is the distance extending to | ||
21696 | // the right from there. | ||
21697 | if (cue.vertical === "") { | ||
21698 | this.applyStyles({ | ||
21699 | left: this.formatStyle(textPos, "%"), | ||
21700 | width: this.formatStyle(cue.size, "%") | ||
21701 | }); | ||
21702 | // Vertical box orientation; textPos is the distance from the top edge of the | ||
21703 | // area to the top edge of the box and cue.size is the height extending | ||
21704 | // downwards from there. | ||
21705 | } else { | ||
21706 | this.applyStyles({ | ||
21707 | top: this.formatStyle(textPos, "%"), | ||
21708 | height: this.formatStyle(cue.size, "%") | ||
21709 | }); | ||
21710 | } | ||
21711 | |||
21712 | this.move = function(box) { | ||
21713 | this.applyStyles({ | ||
21714 | top: this.formatStyle(box.top, "px"), | ||
21715 | bottom: this.formatStyle(box.bottom, "px"), | ||
21716 | left: this.formatStyle(box.left, "px"), | ||
21717 | right: this.formatStyle(box.right, "px"), | ||
21718 | height: this.formatStyle(box.height, "px"), | ||
21719 | width: this.formatStyle(box.width, "px") | ||
21720 | }); | ||
21721 | }; | ||
21722 | } | ||
21723 | CueStyleBox.prototype = _objCreate(StyleBox.prototype); | ||
21724 | CueStyleBox.prototype.constructor = CueStyleBox; | ||
21725 | |||
21726 | // Represents the co-ordinates of an Element in a way that we can easily | ||
21727 | // compute things with such as if it overlaps or intersects with another Element. | ||
21728 | // Can initialize it with either a StyleBox or another BoxPosition. | ||
21729 | function BoxPosition(obj) { | ||
21730 | var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); | ||
21731 | |||
21732 | // Either a BoxPosition was passed in and we need to copy it, or a StyleBox | ||
21733 | // was passed in and we need to copy the results of 'getBoundingClientRect' | ||
21734 | // as the object returned is readonly. All co-ordinate values are in reference | ||
21735 | // to the viewport origin (top left). | ||
21736 | var lh, height, width, top; | ||
21737 | if (obj.div) { | ||
21738 | height = obj.div.offsetHeight; | ||
21739 | width = obj.div.offsetWidth; | ||
21740 | top = obj.div.offsetTop; | ||
21741 | |||
21742 | var rects = (rects = obj.div.childNodes) && (rects = rects[0]) && | ||
21743 | rects.getClientRects && rects.getClientRects(); | ||
21744 | obj = obj.div.getBoundingClientRect(); | ||
21745 | // In certain cases the outter div will be slightly larger then the sum of | ||
21746 | // the inner div's lines. This could be due to bold text, etc, on some platforms. | ||
21747 | // In this case we should get the average line height and use that. This will | ||
21748 | // result in the desired behaviour. | ||
21749 | lh = rects ? Math.max((rects[0] && rects[0].height) || 0, obj.height / rects.length) | ||
21750 | : 0; | ||
21751 | |||
21752 | } | ||
21753 | this.left = obj.left; | ||
21754 | this.right = obj.right; | ||
21755 | this.top = obj.top || top; | ||
21756 | this.height = obj.height || height; | ||
21757 | this.bottom = obj.bottom || (top + (obj.height || height)); | ||
21758 | this.width = obj.width || width; | ||
21759 | this.lineHeight = lh !== undefined ? lh : obj.lineHeight; | ||
21760 | |||
21761 | if (isIE8 && !this.lineHeight) { | ||
21762 | this.lineHeight = 13; | ||
21763 | } | ||
21764 | } | ||
21765 | |||
21766 | // Move the box along a particular axis. Optionally pass in an amount to move | ||
21767 | // the box. If no amount is passed then the default is the line height of the | ||
21768 | // box. | ||
21769 | BoxPosition.prototype.move = function(axis, toMove) { | ||
21770 | toMove = toMove !== undefined ? toMove : this.lineHeight; | ||
21771 | switch (axis) { | ||
21772 | case "+x": | ||
21773 | this.left += toMove; | ||
21774 | this.right += toMove; | ||
21775 | break; | ||
21776 | case "-x": | ||
21777 | this.left -= toMove; | ||
21778 | this.right -= toMove; | ||
21779 | break; | ||
21780 | case "+y": | ||
21781 | this.top += toMove; | ||
21782 | this.bottom += toMove; | ||
21783 | break; | ||
21784 | case "-y": | ||
21785 | this.top -= toMove; | ||
21786 | this.bottom -= toMove; | ||
21787 | break; | ||
21788 | } | ||
21789 | }; | ||
21790 | |||
21791 | // Check if this box overlaps another box, b2. | ||
21792 | BoxPosition.prototype.overlaps = function(b2) { | ||
21793 | return this.left < b2.right && | ||
21794 | this.right > b2.left && | ||
21795 | this.top < b2.bottom && | ||
21796 | this.bottom > b2.top; | ||
21797 | }; | ||
21798 | |||
21799 | // Check if this box overlaps any other boxes in boxes. | ||
21800 | BoxPosition.prototype.overlapsAny = function(boxes) { | ||
21801 | for (var i = 0; i < boxes.length; i++) { | ||
21802 | if (this.overlaps(boxes[i])) { | ||
21803 | return true; | ||
21804 | } | ||
21805 | } | ||
21806 | return false; | ||
21807 | }; | ||
21808 | |||
21809 | // Check if this box is within another box. | ||
21810 | BoxPosition.prototype.within = function(container) { | ||
21811 | return this.top >= container.top && | ||
21812 | this.bottom <= container.bottom && | ||
21813 | this.left >= container.left && | ||
21814 | this.right <= container.right; | ||
21815 | }; | ||
21816 | |||
21817 | // Check if this box is entirely within the container or it is overlapping | ||
21818 | // on the edge opposite of the axis direction passed. For example, if "+x" is | ||
21819 | // passed and the box is overlapping on the left edge of the container, then | ||
21820 | // return true. | ||
21821 | BoxPosition.prototype.overlapsOppositeAxis = function(container, axis) { | ||
21822 | switch (axis) { | ||
21823 | case "+x": | ||
21824 | return this.left < container.left; | ||
21825 | case "-x": | ||
21826 | return this.right > container.right; | ||
21827 | case "+y": | ||
21828 | return this.top < container.top; | ||
21829 | case "-y": | ||
21830 | return this.bottom > container.bottom; | ||
21831 | } | ||
21832 | }; | ||
21833 | |||
21834 | // Find the percentage of the area that this box is overlapping with another | ||
21835 | // box. | ||
21836 | BoxPosition.prototype.intersectPercentage = function(b2) { | ||
21837 | var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)), | ||
21838 | y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)), | ||
21839 | intersectArea = x * y; | ||
21840 | return intersectArea / (this.height * this.width); | ||
21841 | }; | ||
21842 | |||
21843 | // Convert the positions from this box to CSS compatible positions using | ||
21844 | // the reference container's positions. This has to be done because this | ||
21845 | // box's positions are in reference to the viewport origin, whereas, CSS | ||
21846 | // values are in referecne to their respective edges. | ||
21847 | BoxPosition.prototype.toCSSCompatValues = function(reference) { | ||
21848 | return { | ||
21849 | top: this.top - reference.top, | ||
21850 | bottom: reference.bottom - this.bottom, | ||
21851 | left: this.left - reference.left, | ||
21852 | right: reference.right - this.right, | ||
21853 | height: this.height, | ||
21854 | width: this.width | ||
21855 | }; | ||
21856 | }; | ||
21857 | |||
21858 | // Get an object that represents the box's position without anything extra. | ||
21859 | // Can pass a StyleBox, HTMLElement, or another BoxPositon. | ||
21860 | BoxPosition.getSimpleBoxPosition = function(obj) { | ||
21861 | var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0; | ||
21862 | var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0; | ||
21863 | var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0; | ||
21864 | |||
21865 | obj = obj.div ? obj.div.getBoundingClientRect() : | ||
21866 | obj.tagName ? obj.getBoundingClientRect() : obj; | ||
21867 | var ret = { | ||
21868 | left: obj.left, | ||
21869 | right: obj.right, | ||
21870 | top: obj.top || top, | ||
21871 | height: obj.height || height, | ||
21872 | bottom: obj.bottom || (top + (obj.height || height)), | ||
21873 | width: obj.width || width | ||
21874 | }; | ||
21875 | return ret; | ||
21876 | }; | ||
21877 | |||
21878 | // Move a StyleBox to its specified, or next best, position. The containerBox | ||
21879 | // is the box that contains the StyleBox, such as a div. boxPositions are | ||
21880 | // a list of other boxes that the styleBox can't overlap with. | ||
21881 | function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) { | ||
21882 | |||
21883 | // Find the best position for a cue box, b, on the video. The axis parameter | ||
21884 | // is a list of axis, the order of which, it will move the box along. For example: | ||
21885 | // Passing ["+x", "-x"] will move the box first along the x axis in the positive | ||
21886 | // direction. If it doesn't find a good position for it there it will then move | ||
21887 | // it along the x axis in the negative direction. | ||
21888 | function findBestPosition(b, axis) { | ||
21889 | var bestPosition, | ||
21890 | specifiedPosition = new BoxPosition(b), | ||
21891 | percentage = 1; // Highest possible so the first thing we get is better. | ||
21892 | |||
21893 | for (var i = 0; i < axis.length; i++) { | ||
21894 | while (b.overlapsOppositeAxis(containerBox, axis[i]) || | ||
21895 | (b.within(containerBox) && b.overlapsAny(boxPositions))) { | ||
21896 | b.move(axis[i]); | ||
21897 | } | ||
21898 | // We found a spot where we aren't overlapping anything. This is our | ||
21899 | // best position. | ||
21900 | if (b.within(containerBox)) { | ||
21901 | return b; | ||
21902 | } | ||
21903 | var p = b.intersectPercentage(containerBox); | ||
21904 | // If we're outside the container box less then we were on our last try | ||
21905 | // then remember this position as the best position. | ||
21906 | if (percentage > p) { | ||
21907 | bestPosition = new BoxPosition(b); | ||
21908 | percentage = p; | ||
21909 | } | ||
21910 | // Reset the box position to the specified position. | ||
21911 | b = new BoxPosition(specifiedPosition); | ||
21912 | } | ||
21913 | return bestPosition || specifiedPosition; | ||
21914 | } | ||
21915 | |||
21916 | var boxPosition = new BoxPosition(styleBox), | ||
21917 | cue = styleBox.cue, | ||
21918 | linePos = computeLinePos(cue), | ||
21919 | axis = []; | ||
21920 | |||
21921 | // If we have a line number to align the cue to. | ||
21922 | if (cue.snapToLines) { | ||
21923 | var size; | ||
21924 | switch (cue.vertical) { | ||
21925 | case "": | ||
21926 | axis = [ "+y", "-y" ]; | ||
21927 | size = "height"; | ||
21928 | break; | ||
21929 | case "rl": | ||
21930 | axis = [ "+x", "-x" ]; | ||
21931 | size = "width"; | ||
21932 | break; | ||
21933 | case "lr": | ||
21934 | axis = [ "-x", "+x" ]; | ||
21935 | size = "width"; | ||
21936 | break; | ||
21937 | } | ||
21938 | |||
21939 | var step = boxPosition.lineHeight, | ||
21940 | position = step * Math.round(linePos), | ||
21941 | maxPosition = containerBox[size] + step, | ||
21942 | initialAxis = axis[0]; | ||
21943 | |||
21944 | // If the specified intial position is greater then the max position then | ||
21945 | // clamp the box to the amount of steps it would take for the box to | ||
21946 | // reach the max position. | ||
21947 | if (Math.abs(position) > maxPosition) { | ||
21948 | position = position < 0 ? -1 : 1; | ||
21949 | position *= Math.ceil(maxPosition / step) * step; | ||
21950 | } | ||
21951 | |||
21952 | // If computed line position returns negative then line numbers are | ||
21953 | // relative to the bottom of the video instead of the top. Therefore, we | ||
21954 | // need to increase our initial position by the length or width of the | ||
21955 | // video, depending on the writing direction, and reverse our axis directions. | ||
21956 | if (linePos < 0) { | ||
21957 | position += cue.vertical === "" ? containerBox.height : containerBox.width; | ||
21958 | axis = axis.reverse(); | ||
21959 | } | ||
21960 | |||
21961 | // Move the box to the specified position. This may not be its best | ||
21962 | // position. | ||
21963 | boxPosition.move(initialAxis, position); | ||
21964 | |||
21965 | } else { | ||
21966 | // If we have a percentage line value for the cue. | ||
21967 | var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100; | ||
21968 | |||
21969 | switch (cue.lineAlign) { | ||
21970 | case "middle": | ||
21971 | linePos -= (calculatedPercentage / 2); | ||
21972 | break; | ||
21973 | case "end": | ||
21974 | linePos -= calculatedPercentage; | ||
21975 | break; | ||
21976 | } | ||
21977 | |||
21978 | // Apply initial line position to the cue box. | ||
21979 | switch (cue.vertical) { | ||
21980 | case "": | ||
21981 | styleBox.applyStyles({ | ||
21982 | top: styleBox.formatStyle(linePos, "%") | ||
21983 | }); | ||
21984 | break; | ||
21985 | case "rl": | ||
21986 | styleBox.applyStyles({ | ||
21987 | left: styleBox.formatStyle(linePos, "%") | ||
21988 | }); | ||
21989 | break; | ||
21990 | case "lr": | ||
21991 | styleBox.applyStyles({ | ||
21992 | right: styleBox.formatStyle(linePos, "%") | ||
21993 | }); | ||
21994 | break; | ||
21995 | } | ||
21996 | |||
21997 | axis = [ "+y", "-x", "+x", "-y" ]; | ||
21998 | |||
21999 | // Get the box position again after we've applied the specified positioning | ||
22000 | // to it. | ||
22001 | boxPosition = new BoxPosition(styleBox); | ||
22002 | } | ||
22003 | |||
22004 | var bestPosition = findBestPosition(boxPosition, axis); | ||
22005 | styleBox.move(bestPosition.toCSSCompatValues(containerBox)); | ||
22006 | } | ||
22007 | |||
22008 | function WebVTT() { | ||
22009 | // Nothing | ||
22010 | } | ||
22011 | |||
22012 | // Helper to allow strings to be decoded instead of the default binary utf8 data. | ||
22013 | WebVTT.StringDecoder = function() { | ||
22014 | return { | ||
22015 | decode: function(data) { | ||
22016 | if (!data) { | ||
22017 | return ""; | ||
22018 | } | ||
22019 | if (typeof data !== "string") { | ||
22020 | throw new Error("Error - expected string data."); | ||
22021 | } | ||
22022 | return decodeURIComponent(encodeURIComponent(data)); | ||
22023 | } | ||
22024 | }; | ||
22025 | }; | ||
22026 | |||
22027 | WebVTT.convertCueToDOMTree = function(window, cuetext) { | ||
22028 | if (!window || !cuetext) { | ||
22029 | return null; | ||
22030 | } | ||
22031 | return parseContent(window, cuetext); | ||
22032 | }; | ||
22033 | |||
22034 | var FONT_SIZE_PERCENT = 0.05; | ||
22035 | var FONT_STYLE = "sans-serif"; | ||
22036 | var CUE_BACKGROUND_PADDING = "1.5%"; | ||
22037 | |||
22038 | // Runs the processing model over the cues and regions passed to it. | ||
22039 | // @param overlay A block level element (usually a div) that the computed cues | ||
22040 | // and regions will be placed into. | ||
22041 | WebVTT.processCues = function(window, cues, overlay) { | ||
22042 | if (!window || !cues || !overlay) { | ||
22043 | return null; | ||
22044 | } | ||
22045 | |||
22046 | // Remove all previous children. | ||
22047 | while (overlay.firstChild) { | ||
22048 | overlay.removeChild(overlay.firstChild); | ||
22049 | } | ||
22050 | |||
22051 | var paddedOverlay = window.document.createElement("div"); | ||
22052 | paddedOverlay.style.position = "absolute"; | ||
22053 | paddedOverlay.style.left = "0"; | ||
22054 | paddedOverlay.style.right = "0"; | ||
22055 | paddedOverlay.style.top = "0"; | ||
22056 | paddedOverlay.style.bottom = "0"; | ||
22057 | paddedOverlay.style.margin = CUE_BACKGROUND_PADDING; | ||
22058 | overlay.appendChild(paddedOverlay); | ||
22059 | |||
22060 | // Determine if we need to compute the display states of the cues. This could | ||
22061 | // be the case if a cue's state has been changed since the last computation or | ||
22062 | // if it has not been computed yet. | ||
22063 | function shouldCompute(cues) { | ||
22064 | for (var i = 0; i < cues.length; i++) { | ||
22065 | if (cues[i].hasBeenReset || !cues[i].displayState) { | ||
22066 | return true; | ||
22067 | } | ||
22068 | } | ||
22069 | return false; | ||
22070 | } | ||
22071 | |||
22072 | // We don't need to recompute the cues' display states. Just reuse them. | ||
22073 | if (!shouldCompute(cues)) { | ||
22074 | for (var i = 0; i < cues.length; i++) { | ||
22075 | paddedOverlay.appendChild(cues[i].displayState); | ||
22076 | } | ||
22077 | return; | ||
22078 | } | ||
22079 | |||
22080 | var boxPositions = [], | ||
22081 | containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay), | ||
22082 | fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100; | ||
22083 | var styleOptions = { | ||
22084 | font: fontSize + "px " + FONT_STYLE | ||
22085 | }; | ||
22086 | |||
22087 | (function() { | ||
22088 | var styleBox, cue; | ||
22089 | |||
22090 | for (var i = 0; i < cues.length; i++) { | ||
22091 | cue = cues[i]; | ||
22092 | |||
22093 | // Compute the intial position and styles of the cue div. | ||
22094 | styleBox = new CueStyleBox(window, cue, styleOptions); | ||
22095 | paddedOverlay.appendChild(styleBox.div); | ||
22096 | |||
22097 | // Move the cue div to it's correct line position. | ||
22098 | moveBoxToLinePosition(window, styleBox, containerBox, boxPositions); | ||
22099 | |||
22100 | // Remember the computed div so that we don't have to recompute it later | ||
22101 | // if we don't have too. | ||
22102 | cue.displayState = styleBox.div; | ||
22103 | |||
22104 | boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox)); | ||
22105 | } | ||
22106 | })(); | ||
22107 | }; | ||
22108 | |||
22109 | WebVTT.Parser = function(window, vttjs, decoder) { | ||
22110 | if (!decoder) { | ||
22111 | decoder = vttjs; | ||
22112 | vttjs = {}; | ||
22113 | } | ||
22114 | if (!vttjs) { | ||
22115 | vttjs = {}; | ||
22116 | } | ||
22117 | |||
22118 | this.window = window; | ||
22119 | this.vttjs = vttjs; | ||
22120 | this.state = "INITIAL"; | ||
22121 | this.buffer = ""; | ||
22122 | this.decoder = decoder || new TextDecoder("utf8"); | ||
22123 | this.regionList = []; | ||
22124 | }; | ||
22125 | |||
22126 | WebVTT.Parser.prototype = { | ||
22127 | // If the error is a ParsingError then report it to the consumer if | ||
22128 | // possible. If it's not a ParsingError then throw it like normal. | ||
22129 | reportOrThrowError: function(e) { | ||
22130 | if (e instanceof ParsingError) { | ||
22131 | this.onparsingerror && this.onparsingerror(e); | ||
22132 | } else { | ||
22133 | throw e; | ||
22134 | } | ||
22135 | }, | ||
22136 | parse: function (data) { | ||
22137 | var self = this; | ||
22138 | |||
22139 | // If there is no data then we won't decode it, but will just try to parse | ||
22140 | // whatever is in buffer already. This may occur in circumstances, for | ||
22141 | // example when flush() is called. | ||
22142 | if (data) { | ||
22143 | // Try to decode the data that we received. | ||
22144 | self.buffer += self.decoder.decode(data, {stream: true}); | ||
22145 | } | ||
22146 | |||
22147 | function collectNextLine() { | ||
22148 | var buffer = self.buffer; | ||
22149 | var pos = 0; | ||
22150 | while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') { | ||
22151 | ++pos; | ||
22152 | } | ||
22153 | var line = buffer.substr(0, pos); | ||
22154 | // Advance the buffer early in case we fail below. | ||
22155 | if (buffer[pos] === '\r') { | ||
22156 | ++pos; | ||
22157 | } | ||
22158 | if (buffer[pos] === '\n') { | ||
22159 | ++pos; | ||
22160 | } | ||
22161 | self.buffer = buffer.substr(pos); | ||
22162 | return line; | ||
22163 | } | ||
22164 | |||
22165 | // 3.4 WebVTT region and WebVTT region settings syntax | ||
22166 | function parseRegion(input) { | ||
22167 | var settings = new Settings(); | ||
22168 | |||
22169 | parseOptions(input, function (k, v) { | ||
22170 | switch (k) { | ||
22171 | case "id": | ||
22172 | settings.set(k, v); | ||
22173 | break; | ||
22174 | case "width": | ||
22175 | settings.percent(k, v); | ||
22176 | break; | ||
22177 | case "lines": | ||
22178 | settings.integer(k, v); | ||
22179 | break; | ||
22180 | case "regionanchor": | ||
22181 | case "viewportanchor": | ||
22182 | var xy = v.split(','); | ||
22183 | if (xy.length !== 2) { | ||
22184 | break; | ||
22185 | } | ||
22186 | // We have to make sure both x and y parse, so use a temporary | ||
22187 | // settings object here. | ||
22188 | var anchor = new Settings(); | ||
22189 | anchor.percent("x", xy[0]); | ||
22190 | anchor.percent("y", xy[1]); | ||
22191 | if (!anchor.has("x") || !anchor.has("y")) { | ||
22192 | break; | ||
22193 | } | ||
22194 | settings.set(k + "X", anchor.get("x")); | ||
22195 | settings.set(k + "Y", anchor.get("y")); | ||
22196 | break; | ||
22197 | case "scroll": | ||
22198 | settings.alt(k, v, ["up"]); | ||
22199 | break; | ||
22200 | } | ||
22201 | }, /=/, /\s/); | ||
22202 | |||
22203 | // Create the region, using default values for any values that were not | ||
22204 | // specified. | ||
22205 | if (settings.has("id")) { | ||
22206 | var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)(); | ||
22207 | region.width = settings.get("width", 100); | ||
22208 | region.lines = settings.get("lines", 3); | ||
22209 | region.regionAnchorX = settings.get("regionanchorX", 0); | ||
22210 | region.regionAnchorY = settings.get("regionanchorY", 100); | ||
22211 | region.viewportAnchorX = settings.get("viewportanchorX", 0); | ||
22212 | region.viewportAnchorY = settings.get("viewportanchorY", 100); | ||
22213 | region.scroll = settings.get("scroll", ""); | ||
22214 | // Register the region. | ||
22215 | self.onregion && self.onregion(region); | ||
22216 | // Remember the VTTRegion for later in case we parse any VTTCues that | ||
22217 | // reference it. | ||
22218 | self.regionList.push({ | ||
22219 | id: settings.get("id"), | ||
22220 | region: region | ||
22221 | }); | ||
22222 | } | ||
22223 | } | ||
22224 | |||
22225 | // 3.2 WebVTT metadata header syntax | ||
22226 | function parseHeader(input) { | ||
22227 | parseOptions(input, function (k, v) { | ||
22228 | switch (k) { | ||
22229 | case "Region": | ||
22230 | // 3.3 WebVTT region metadata header syntax | ||
22231 | parseRegion(v); | ||
22232 | break; | ||
22233 | } | ||
22234 | }, /:/); | ||
22235 | } | ||
22236 | |||
22237 | // 5.1 WebVTT file parsing. | ||
22238 | try { | ||
22239 | var line; | ||
22240 | if (self.state === "INITIAL") { | ||
22241 | // We can't start parsing until we have the first line. | ||
22242 | if (!/\r\n|\n/.test(self.buffer)) { | ||
22243 | return this; | ||
22244 | } | ||
22245 | |||
22246 | line = collectNextLine(); | ||
22247 | |||
22248 | var m = line.match(/^WEBVTT([ \t].*)?$/); | ||
22249 | if (!m || !m[0]) { | ||
22250 | throw new ParsingError(ParsingError.Errors.BadSignature); | ||
22251 | } | ||
22252 | |||
22253 | self.state = "HEADER"; | ||
22254 | } | ||
22255 | |||
22256 | var alreadyCollectedLine = false; | ||
22257 | while (self.buffer) { | ||
22258 | // We can't parse a line until we have the full line. | ||
22259 | if (!/\r\n|\n/.test(self.buffer)) { | ||
22260 | return this; | ||
22261 | } | ||
22262 | |||
22263 | if (!alreadyCollectedLine) { | ||
22264 | line = collectNextLine(); | ||
22265 | } else { | ||
22266 | alreadyCollectedLine = false; | ||
22267 | } | ||
22268 | |||
22269 | switch (self.state) { | ||
22270 | case "HEADER": | ||
22271 | // 13-18 - Allow a header (metadata) under the WEBVTT line. | ||
22272 | if (/:/.test(line)) { | ||
22273 | parseHeader(line); | ||
22274 | } else if (!line) { | ||
22275 | // An empty line terminates the header and starts the body (cues). | ||
22276 | self.state = "ID"; | ||
22277 | } | ||
22278 | continue; | ||
22279 | case "NOTE": | ||
22280 | // Ignore NOTE blocks. | ||
22281 | if (!line) { | ||
22282 | self.state = "ID"; | ||
22283 | } | ||
22284 | continue; | ||
22285 | case "ID": | ||
22286 | // Check for the start of NOTE blocks. | ||
22287 | if (/^NOTE($|[ \t])/.test(line)) { | ||
22288 | self.state = "NOTE"; | ||
22289 | break; | ||
22290 | } | ||
22291 | // 19-29 - Allow any number of line terminators, then initialize new cue values. | ||
22292 | if (!line) { | ||
22293 | continue; | ||
22294 | } | ||
22295 | self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, ""); | ||
22296 | self.state = "CUE"; | ||
22297 | // 30-39 - Check if self line contains an optional identifier or timing data. | ||
22298 | if (line.indexOf("-->") === -1) { | ||
22299 | self.cue.id = line; | ||
22300 | continue; | ||
22301 | } | ||
22302 | // Process line as start of a cue. | ||
22303 | /*falls through*/ | ||
22304 | case "CUE": | ||
22305 | // 40 - Collect cue timings and settings. | ||
22306 | try { | ||
22307 | parseCue(line, self.cue, self.regionList); | ||
22308 | } catch (e) { | ||
22309 | self.reportOrThrowError(e); | ||
22310 | // In case of an error ignore rest of the cue. | ||
22311 | self.cue = null; | ||
22312 | self.state = "BADCUE"; | ||
22313 | continue; | ||
22314 | } | ||
22315 | self.state = "CUETEXT"; | ||
22316 | continue; | ||
22317 | case "CUETEXT": | ||
22318 | var hasSubstring = line.indexOf("-->") !== -1; | ||
22319 | // 34 - If we have an empty line then report the cue. | ||
22320 | // 35 - If we have the special substring '-->' then report the cue, | ||
22321 | // but do not collect the line as we need to process the current | ||
22322 | // one as a new cue. | ||
22323 | if (!line || hasSubstring && (alreadyCollectedLine = true)) { | ||
22324 | // We are done parsing self cue. | ||
22325 | self.oncue && self.oncue(self.cue); | ||
22326 | self.cue = null; | ||
22327 | self.state = "ID"; | ||
22328 | continue; | ||
22329 | } | ||
22330 | if (self.cue.text) { | ||
22331 | self.cue.text += "\n"; | ||
22332 | } | ||
22333 | self.cue.text += line; | ||
22334 | continue; | ||
22335 | case "BADCUE": // BADCUE | ||
22336 | // 54-62 - Collect and discard the remaining cue. | ||
22337 | if (!line) { | ||
22338 | self.state = "ID"; | ||
22339 | } | ||
22340 | continue; | ||
22341 | } | ||
22342 | } | ||
22343 | } catch (e) { | ||
22344 | self.reportOrThrowError(e); | ||
22345 | |||
22346 | // If we are currently parsing a cue, report what we have. | ||
22347 | if (self.state === "CUETEXT" && self.cue && self.oncue) { | ||
22348 | self.oncue(self.cue); | ||
22349 | } | ||
22350 | self.cue = null; | ||
22351 | // Enter BADWEBVTT state if header was not parsed correctly otherwise | ||
22352 | // another exception occurred so enter BADCUE state. | ||
22353 | self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE"; | ||
22354 | } | ||
22355 | return this; | ||
22356 | }, | ||
22357 | flush: function () { | ||
22358 | var self = this; | ||
22359 | try { | ||
22360 | // Finish decoding the stream. | ||
22361 | self.buffer += self.decoder.decode(); | ||
22362 | // Synthesize the end of the current cue or region. | ||
22363 | if (self.cue || self.state === "HEADER") { | ||
22364 | self.buffer += "\n\n"; | ||
22365 | self.parse(); | ||
22366 | } | ||
22367 | // If we've flushed, parsed, and we're still on the INITIAL state then | ||
22368 | // that means we don't have enough of the stream to parse the first | ||
22369 | // line. | ||
22370 | if (self.state === "INITIAL") { | ||
22371 | throw new ParsingError(ParsingError.Errors.BadSignature); | ||
22372 | } | ||
22373 | } catch(e) { | ||
22374 | self.reportOrThrowError(e); | ||
22375 | } | ||
22376 | self.onflush && self.onflush(); | ||
22377 | return this; | ||
22378 | } | ||
22379 | }; | ||
22380 | |||
22381 | global.WebVTT = WebVTT; | ||
22382 | |||
22383 | }(this, (this.vttjs || {}))); | ||