diff --git a/TimedMediaHandler.hooks.php b/TimedMediaHandler.hooks.php index 32f98bdf2..ddfcdc2b6 100644 --- a/TimedMediaHandler.hooks.php +++ b/TimedMediaHandler.hooks.php @@ -101,6 +101,7 @@ public static function resourceLoaderRegisterModules( &$resourceLoader ) { 'cs' => 'resources/videojs/lang/cs.js', 'da' => 'resources/videojs/lang/da.js', 'de' => 'resources/videojs/lang/de.js', + 'el' => 'resources/videojs/lang/el.js', 'en' => 'resources/videojs/lang/en.js', 'es' => 'resources/videojs/lang/es.js', 'fa' => 'resources/videojs/lang/fa.js', @@ -114,6 +115,7 @@ public static function resourceLoaderRegisterModules( &$resourceLoader ) { 'nb' => 'resources/videojs/lang/nb.js', 'nl' => 'resources/videojs/lang/nl.js', 'nn' => 'resources/videojs/lang/nn.js', + 'pl' => 'resources/videojs/lang/pl.js', 'pt-BR' => 'resources/videojs/lang/pt-BR.js', 'ru' => 'resources/videojs/lang/ru.js', 'sr' => 'resources/videojs/lang/sr.js', diff --git a/package.json b/package.json index c1ca7280e..8280e2b0e 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "grunt-jsonlint": "1.0.7", "grunt-patch": "^0.1.7", "jscs-preset-wikimedia": "~1.0.0", - "video.js": "^5.8.8", + "video.js": "^5.10.1", "videojs-ogvjs": "^1.1.0", "videojs-resolution-switcher": "^0.4.2", "videojs-responsive-layout": "^1.1.0" diff --git a/patches/videojs.defaults.patch b/patches/videojs.defaults.patch index 732a7f312..64d02a733 100644 --- a/patches/videojs.defaults.patch +++ b/patches/videojs.defaults.patch @@ -1,18 +1,21 @@ diff --git a/resources/videojs/video.js b/resources/videojs/video.js -index 03daf68..473c1f9 100644 +index c8882bf..cafa0e6 100644 --- a/resources/videojs/video.js +++ b/resources/videojs/video.js -@@ -19811,15 +19811,6 @@ var videojs = function videojs(id, options, ready) { +@@ -21692,18 +21692,6 @@ var videojs = function videojs(id, options, ready) { return tag['player'] || _player2['default'].players[tag.playerId] || new _player2['default'](tag, options, ready); }; -// Add default styles --var style = Dom.$('.vjs-styles-defaults'); --if (!style) { -- style = stylesheet.createStyleElement('vjs-styles-defaults'); -- var head = Dom.$('head'); -- head.insertBefore(style, head.firstChild); -- stylesheet.setTextContent(style, '\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n '); +-if (_globalWindow2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true) { +- var style = Dom.$('.vjs-styles-defaults'); +- +- if (!style) { +- style = stylesheet.createStyleElement('vjs-styles-defaults'); +- var head = Dom.$('head'); +- head.insertBefore(style, head.firstChild); +- stylesheet.setTextContent(style, '\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n '); +- } -} - // Run Auto-load players diff --git a/resources/videojs/font/VideoJS.eot b/resources/videojs/font/VideoJS.eot index a47889f93..cbdd2a20c 100644 Binary files a/resources/videojs/font/VideoJS.eot and b/resources/videojs/font/VideoJS.eot differ diff --git a/resources/videojs/font/VideoJS.svg b/resources/videojs/font/VideoJS.svg index 7741c6778..49af73ab8 100644 --- a/resources/videojs/font/VideoJS.svg +++ b/resources/videojs/font/VideoJS.svg @@ -94,6 +94,9 @@ + diff --git a/resources/videojs/font/VideoJS.ttf b/resources/videojs/font/VideoJS.ttf index 6ddd3f26d..e23d02a49 100644 Binary files a/resources/videojs/font/VideoJS.ttf and b/resources/videojs/font/VideoJS.ttf differ diff --git a/resources/videojs/font/VideoJS.woff b/resources/videojs/font/VideoJS.woff index a85d38e87..dc9d85047 100644 Binary files a/resources/videojs/font/VideoJS.woff and b/resources/videojs/font/VideoJS.woff differ diff --git a/resources/videojs/lang/el.js b/resources/videojs/lang/el.js new file mode 100644 index 000000000..e95433da7 --- /dev/null +++ b/resources/videojs/lang/el.js @@ -0,0 +1,34 @@ +videojs.addLanguage("el",{ + "Play": "Aναπαραγωγή", + "Pause": "Παύση", + "Current Time": "Τρέχων χρόνος", + "Duration Time": "Συνολικός χρόνος", + "Remaining Time": "Υπολοιπόμενος χρόνος", + "Stream Type": "Τύπος ροής", + "LIVE": "ΖΩΝΤΑΝΑ", + "Loaded": "Φόρτωση επιτυχής", + "Progress": "Πρόοδος", + "Fullscreen": "Πλήρης οθόνη", + "Non-Fullscreen": "Έξοδος από πλήρη οθόνη", + "Mute": "Σίγαση", + "Unmute": "Kατάργηση σίγασης", + "Playback Rate": "Ρυθμός αναπαραγωγής", + "Subtitles": "Υπότιτλοι", + "subtitles off": "απόκρυψη υπότιτλων", + "Captions": "Λεζάντες", + "captions off": "απόκρυψη λεζάντων", + "Chapters": "Κεφάλαια", + "You aborted the media playback": "Ακυρώσατε την αναπαραγωγή", + "A network error caused the media download to fail part-way.": "Ένα σφάλμα δικτύου προκάλεσε την αποτυχία μεταφόρτωσης του αρχείου προς αναπαραγωγή.", + "The media could not be loaded, either because the server or network failed or because the format is not supported.": "Το αρχείο προς αναπαραγωγή δεν ήταν δυνατό να φορτωθεί είτε γιατί υπήρξε σφάλμα στον διακομιστή ή το δίκτυο, είτε γιατί ο τύπος του αρχείου δεν υποστηρίζεται.", + "The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Η αναπαραγωγή ακυρώθηκε είτε λόγω κατεστραμμένου αρχείου, είτε γιατί το αρχείο απαιτεί λειτουργίες που δεν υποστηρίζονται από το πρόγραμμα περιήγησης που χρησιμοποιείτε.", + "No compatible source was found for this media.": "Δεν βρέθηκε συμβατή πηγή αναπαραγωγής για το συγκεκριμένο αρχείο.", + "Play video": "Αναπαραγωγή βίντεο", + "Close": "Κλείσιμο", + "Modal Window": "Aναδυόμενο παράθυρο", + "This is a modal window": "Το παρών είναι ένα αναδυόμενο παράθυρο", + "This modal can be closed by pressing the Escape key or activating the close button.": "Αυτό το παράθυρο μπορεί να εξαφανιστεί πατώντας το πλήκτρο Escape ή πατώντας το κουμπί κλεισίματος.", + ", opens captions settings dialog": ", εμφανίζει τις ρυθμίσεις για τις λεζάντες", + ", opens subtitles settings dialog": ", εμφανίζει τις ρυθμίσεις για τους υπότιτλους", + ", selected": ", επιλεγμένο" +}); \ No newline at end of file diff --git a/resources/videojs/lang/en.js b/resources/videojs/lang/en.js index c7f5e8a53..ad896756f 100644 --- a/resources/videojs/lang/en.js +++ b/resources/videojs/lang/en.js @@ -18,6 +18,8 @@ videojs.addLanguage("en",{ "Captions": "Captions", "captions off": "captions off", "Chapters": "Chapters", + "Descriptions": "Descriptions", + "descriptions off": "descriptions off", "You aborted the media playback": "You aborted the media playback", "A network error caused the media download to fail part-way.": "A network error caused the media download to fail part-way.", "The media could not be loaded, either because the server or network failed or because the format is not supported.": "The media could not be loaded, either because the server or network failed or because the format is not supported.", @@ -30,5 +32,6 @@ videojs.addLanguage("en",{ "This modal can be closed by pressing the Escape key or activating the close button.": "This modal can be closed by pressing the Escape key or activating the close button.", ", opens captions settings dialog": ", opens captions settings dialog", ", opens subtitles settings dialog": ", opens subtitles settings dialog", + ", opens descriptions settings dialog": ", opens descriptions settings dialog", ", selected": ", selected" }); \ No newline at end of file diff --git a/resources/videojs/lang/pl.js b/resources/videojs/lang/pl.js new file mode 100644 index 000000000..19467283a --- /dev/null +++ b/resources/videojs/lang/pl.js @@ -0,0 +1,34 @@ +videojs.addLanguage("pl",{ + "Play": "Odtwarzaj", + "Pause": "Pauza", + "Current Time": "Aktualny czas", + "Duration Time": "Czas trwania", + "Remaining Time": "Pozostały czas", + "Stream Type": "Typ strumienia", + "LIVE": "NA ŻYWO", + "Loaded": "Załadowany", + "Progress": "Status", + "Fullscreen": "Pełny ekran", + "Non-Fullscreen": "Pełny ekran niedostępny", + "Mute": "Wyłącz dźwięk", + "Unmute": "Włącz dźwięk", + "Playback Rate": "Szybkość odtwarzania", + "Subtitles": "Napisy", + "subtitles off": "Napisy wyłączone", + "Captions": "Transkrypcja", + "captions off": "Transkrypcja wyłączona", + "Chapters": "Rozdziały", + "You aborted the media playback": "Odtwarzanie zostało przerwane", + "A network error caused the media download to fail part-way.": "Problemy z siecią spowodowały błąd przy pobieraniu materiału wideo.", + "The media could not be loaded, either because the server or network failed or because the format is not supported.": "Materiał wideo nie może być załadowany, ponieważ wystąpił problem z siecią lub format nie jest obsługiwany", + "The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Odtwarzanie materiału wideo zostało przerwane z powodu uszkodzonego pliku wideo lub z powodu błędu funkcji, które nie są wspierane przez przeglądarkę.", + "No compatible source was found for this media.": "Dla tego materiału wideo nie znaleziono kompatybilnego źródła.", + "Play video": "Odtwarzaj wideo", + "Close": "Zamknij", + "Modal Window": "Okno Modala", + "This is a modal window": "To jest okno modala", + "This modal can be closed by pressing the Escape key or activating the close button.": "Ten modal możesz zamknąć naciskając przycisk Escape albo wybierając przycisk Zamknij.", + ", opens captions settings dialog": ", otwiera okno dialogowe ustawień transkrypcji", + ", opens subtitles settings dialog": ", otwiera okno dialogowe napisów", + ", selected": ", zaznaczone" +}); \ No newline at end of file diff --git a/resources/videojs/video-js.css b/resources/videojs/video-js.css index 916dd357e..c37653104 100644 --- a/resources/videojs/video-js.css +++ b/resources/videojs/video-js.css @@ -14,7 +14,7 @@ @font-face { font-family: VideoJS; - src: url(data:application/font-woff;charset=utf-8;base64,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) format("woff"), url(data:application/x-font-ttf;charset=utf-8;base64,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ATcuAScjBh8BHgEXDgEFMz8BFTMRIwYDJRUnAxyEzZRbCA2rgketCAEBqlRoCglxYwF+IiEOIysBAkswHQEECiQ0AgE+YyIhDiIsAQJLMB4BBQokNAE/YyIhDiIsAQJLMB4BBQokNAEBPvmD7kHhqs0s0gEnjgHJAv0FD2a9gIrADwUFAwPDAlVMZ3MF/pUHwgc1HTyWV325PgsJED+oY3G9TAc1HTyWV325PgsJED+oY3G9TAc1HTyWV325PgsJED+oY3G9UmQBZQMMR/61g/kBAAAAAAAQAMYAAQAAAAAAAQAHAAAAAQAAAAAAAgAHAAcAAQAAAAAAAwAHAA4AAQAAAAAABAAHABUAAQAAAAAABQALABwAAQAAAAAABgAHACcAAQAAAAAACgArAC4AAQAAAAAACwATAFkAAwABBAkAAQAOAGwAAwABBAkAAgAOAHoAAwABBAkAAwAOAIgAAwABBAkABAAOAJYAAwABBAkABQAWAKQAAwABBAkABgAOALoAAwABBAkACgBWAMgAAwABBAkACwAmAR5WaWRlb0pTUmVndWxhclZpZGVvSlNWaWRlb0pTVmVyc2lvbiAxLjBWaWRlb0pTR2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20AVgBpAGQAZQBvAEoAUwBSAGUAZwB1AGwAYQByAFYAaQBkAGUAbwBKAFMAVgBpAGQAZQBvAEoAUwBWAGUAcgBzAGkAbwBuACAAMQAuADAAVgBpAGQAZQBvAEoAUwBHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAGgAdAB0AHAAOgAvAC8AZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AAAACAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4EcGxheQtwbGF5LWNpcmNsZQVwYXVzZQt2b2x1bWUtbXV0ZQp2b2x1bWUtbG93CnZvbHVtZS1taWQLdm9sdW1lLWhpZ2gQZnVsbHNjcmVlbi1lbnRlcg9mdWxsc2NyZWVuLWV4aXQGc3F1YXJlB3NwaW5uZXIJc3VidGl0bGVzCGNhcHRpb25zCGNoYXB0ZXJzBXNoYXJlA2NvZwZjaXJjbGUOY2lyY2xlLW91dGxpbmUTY2lyY2xlLWlubmVyLWNpcmNsZQJoZAZjYW5jZWwGcmVwbGF5CGZhY2Vib29rBWdwbHVzCGxpbmtlZGluB3R3aXR0ZXIGdHVtYmxyCXBpbnRlcmVzdBFhdWRpby1kZXNjcmlwdGlvbgAAAAAA) format("truetype"); + src: url(data:application/font-woff;charset=utf-8;base64,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) format("woff"), url(data:application/x-font-ttf;charset=utf-8;base64,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FjY3PgE3LgEnIwYfAR4BFw4BBTM/ARUzESMGAyUVJwMchM2UWwgNq4JHrQgBAapUaAoJcWMBfiIhDiMrAQJLMB0BBAokNAIBPmMiIQ4iLAECSzAeAQUKJDQBP2MiIQ4iLAECSzAeAQUKJDQBAT75g+5B4arNLNIBJ44ByQL9BQ9mvYCKwA8FBQMDwwJVTGdzBf6VB8IHNR08lld9uT4LCRA/qGNxvUwHNR08lld9uT4LCRA/qGNxvUwHNR08lld9uT4LCRA/qGNxvVJkAWUDDEf+tYP5AQAAAAEAAAAABiAGtgAbAAABBAADER4BFzMRITU2ADcWABcVIREzPgE3EQIAA4D+4v6FBwJ/X+D+1QYBJ97eAScG/tXgX38CB/6FBrUH/oX+4v32X38CAlWV3gEnBgb+2d6V/asCf18CCgEeAXsAAAAAEADGAAEAAAAAAAEABwAAAAEAAAAAAAIABwAHAAEAAAAAAAMABwAOAAEAAAAAAAQABwAVAAEAAAAAAAUACwAcAAEAAAAAAAYABwAnAAEAAAAAAAoAKwAuAAEAAAAAAAsAEwBZAAMAAQQJAAEADgBsAAMAAQQJAAIADgB6AAMAAQQJAAMADgCIAAMAAQQJAAQADgCWAAMAAQQJAAUAFgCkAAMAAQQJAAYADgC6AAMAAQQJAAoAVgDIAAMAAQQJAAsAJgEeVmlkZW9KU1JlZ3VsYXJWaWRlb0pTVmlkZW9KU1ZlcnNpb24gMS4wVmlkZW9KU0dlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC5odHRwOi8vZm9udGVsbG8uY29tAFYAaQBkAGUAbwBKAFMAUgBlAGcAdQBsAGEAcgBWAGkAZABlAG8ASgBTAFYAaQBkAGUAbwBKAFMAVgBlAHIAcwBpAG8AbgAgADEALgAwAFYAaQBkAGUAbwBKAFMARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAAAAgAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAABAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8EcGxheQtwbGF5LWNpcmNsZQVwYXVzZQt2b2x1bWUtbXV0ZQp2b2x1bWUtbG93CnZvbHVtZS1taWQLdm9sdW1lLWhpZ2gQZnVsbHNjcmVlbi1lbnRlcg9mdWxsc2NyZWVuLWV4aXQGc3F1YXJlB3NwaW5uZXIJc3VidGl0bGVzCGNhcHRpb25zCGNoYXB0ZXJzBXNoYXJlA2NvZwZjaXJjbGUOY2lyY2xlLW91dGxpbmUTY2lyY2xlLWlubmVyLWNpcmNsZQJoZAZjYW5jZWwGcmVwbGF5CGZhY2Vib29rBWdwbHVzCGxpbmtlZGluB3R3aXR0ZXIGdHVtYmxyCXBpbnRlcmVzdBFhdWRpby1kZXNjcmlwdGlvbgVhdWRpbwAAAAAA) format("truetype"); font-weight: normal; font-style: normal; } @@ -23,21 +23,21 @@ font-weight: normal; font-style: normal; } .vjs-icon-play:before, .video-js .vjs-big-play-button:before, .video-js .vjs-play-control:before { - content: '\f101'; } + content: "\f101"; } .vjs-icon-play-circle { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-play-circle:before { - content: '\f102'; } + content: "\f102"; } .vjs-icon-pause, .video-js .vjs-play-control.vjs-playing { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-pause:before, .video-js .vjs-play-control.vjs-playing:before { - content: '\f103'; } + content: "\f103"; } .vjs-icon-volume-mute, .video-js .vjs-mute-control.vjs-vol-0, .video-js .vjs-volume-menu-button.vjs-vol-0 { @@ -46,7 +46,7 @@ font-style: normal; } .vjs-icon-volume-mute:before, .video-js .vjs-mute-control.vjs-vol-0:before, .video-js .vjs-volume-menu-button.vjs-vol-0:before { - content: '\f104'; } + content: "\f104"; } .vjs-icon-volume-low, .video-js .vjs-mute-control.vjs-vol-1, .video-js .vjs-volume-menu-button.vjs-vol-1 { @@ -55,7 +55,7 @@ font-style: normal; } .vjs-icon-volume-low:before, .video-js .vjs-mute-control.vjs-vol-1:before, .video-js .vjs-volume-menu-button.vjs-vol-1:before { - content: '\f105'; } + content: "\f105"; } .vjs-icon-volume-mid, .video-js .vjs-mute-control.vjs-vol-2, .video-js .vjs-volume-menu-button.vjs-vol-2 { @@ -64,7 +64,7 @@ font-style: normal; } .vjs-icon-volume-mid:before, .video-js .vjs-mute-control.vjs-vol-2:before, .video-js .vjs-volume-menu-button.vjs-vol-2:before { - content: '\f106'; } + content: "\f106"; } .vjs-icon-volume-high, .video-js .vjs-mute-control, .video-js .vjs-volume-menu-button { @@ -73,161 +73,168 @@ font-style: normal; } .vjs-icon-volume-high:before, .video-js .vjs-mute-control:before, .video-js .vjs-volume-menu-button:before { - content: '\f107'; } + content: "\f107"; } .vjs-icon-fullscreen-enter, .video-js .vjs-fullscreen-control { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-fullscreen-enter:before, .video-js .vjs-fullscreen-control:before { - content: '\f108'; } + content: "\f108"; } .vjs-icon-fullscreen-exit, .video-js.vjs-fullscreen .vjs-fullscreen-control { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-fullscreen-exit:before, .video-js.vjs-fullscreen .vjs-fullscreen-control:before { - content: '\f109'; } + content: "\f109"; } .vjs-icon-square { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-square:before { - content: '\f10a'; } + content: "\f10a"; } .vjs-icon-spinner { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-spinner:before { - content: '\f10b'; } + content: "\f10b"; } .vjs-icon-subtitles, .video-js .vjs-subtitles-button { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-subtitles:before, .video-js .vjs-subtitles-button:before { - content: '\f10c'; } + content: "\f10c"; } .vjs-icon-captions, .video-js .vjs-captions-button { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-captions:before, .video-js .vjs-captions-button:before { - content: '\f10d'; } + content: "\f10d"; } .vjs-icon-chapters, .video-js .vjs-chapters-button { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-chapters:before, .video-js .vjs-chapters-button:before { - content: '\f10e'; } + content: "\f10e"; } .vjs-icon-share { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-share:before { - content: '\f10f'; } + content: "\f10f"; } .vjs-icon-cog { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-cog:before { - content: '\f110'; } + content: "\f110"; } .vjs-icon-circle, .video-js .vjs-mouse-display, .video-js .vjs-play-progress, .video-js .vjs-volume-level { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-circle:before, .video-js .vjs-mouse-display:before, .video-js .vjs-play-progress:before, .video-js .vjs-volume-level:before { - content: '\f111'; } + content: "\f111"; } .vjs-icon-circle-outline { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-circle-outline:before { - content: '\f112'; } + content: "\f112"; } .vjs-icon-circle-inner-circle { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-circle-inner-circle:before { - content: '\f113'; } + content: "\f113"; } .vjs-icon-hd { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-hd:before { - content: '\f114'; } + content: "\f114"; } .vjs-icon-cancel, .video-js .vjs-control.vjs-close-button { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-cancel:before, .video-js .vjs-control.vjs-close-button:before { - content: '\f115'; } + content: "\f115"; } .vjs-icon-replay { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-replay:before { - content: '\f116'; } + content: "\f116"; } .vjs-icon-facebook { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-facebook:before { - content: '\f117'; } + content: "\f117"; } .vjs-icon-gplus { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-gplus:before { - content: '\f118'; } + content: "\f118"; } .vjs-icon-linkedin { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-linkedin:before { - content: '\f119'; } + content: "\f119"; } .vjs-icon-twitter { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-twitter:before { - content: '\f11a'; } + content: "\f11a"; } .vjs-icon-tumblr { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-tumblr:before { - content: '\f11b'; } + content: "\f11b"; } .vjs-icon-pinterest { font-family: VideoJS; font-weight: normal; font-style: normal; } .vjs-icon-pinterest:before { - content: '\f11c'; } + content: "\f11c"; } -.vjs-icon-audio-description { +.vjs-icon-audio-description, .video-js .vjs-descriptions-button { font-family: VideoJS; font-weight: normal; font-style: normal; } - .vjs-icon-audio-description:before { - content: '\f11d'; } + .vjs-icon-audio-description:before, .video-js .vjs-descriptions-button:before { + content: "\f11d"; } + +.vjs-icon-audio, .video-js .vjs-audio-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-audio:before, .video-js .vjs-audio-button:before { + content: "\f11e"; } .video-js { display: block; @@ -317,6 +324,10 @@ body.vjs-full-window { .vjs-hidden { display: none !important; } +.vjs-disabled { + opacity: 0.5; + cursor: default; } + .video-js .vjs-offscreen { height: 1px; left: -9999px; @@ -416,6 +427,12 @@ body.vjs-full-window { .vjs-menu-button { cursor: pointer; } +.vjs-menu-button.vjs-disabled { + cursor: default; } + +.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu { + display: none; } + .vjs-menu .vjs-menu-content { display: block; padding: 0; @@ -561,12 +578,15 @@ body.vjs-full-window { transition: visibility 0.1s, opacity 0.1s; } .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { - visibility: hidden; + visibility: visible; opacity: 0; -webkit-transition: visibility 1s, opacity 1s; -moz-transition: visibility 1s, opacity 1s; -o-transition: visibility 1s, opacity 1s; transition: visibility 1s, opacity 1s; } + @media \0screen { + .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { + visibility: hidden; } } .vjs-controls-disabled .vjs-control-bar, .vjs-using-native-controls .vjs-control-bar, @@ -660,13 +680,16 @@ body.vjs-full-window { /* If we let the font size grow as much as everything else, the current time tooltip ends up ginormous. If you'd like to enable the current time tooltip all the time, this should be disabled to avoid a weird hitch when you roll off the hover. */ +.video-js .vjs-progress-control:hover .vjs-time-tooltip, .video-js .vjs-progress-control:hover .vjs-mouse-display:after, .video-js .vjs-progress-control:hover .vjs-play-progress:after { - display: block; + font-family: Arial, Helvetica, sans-serif; + visibility: visible; font-size: 0.6em; } .video-js .vjs-progress-holder .vjs-play-progress, .video-js .vjs-progress-holder .vjs-load-progress, +.video-js .vjs-progress-holder .vjs-tooltip-progress-bar, .video-js .vjs-progress-holder .vjs-load-progress div { position: absolute; display: block; @@ -688,12 +711,14 @@ body.vjs-full-window { right: -0.5em; font-size: 0.9em; } +.video-js .vjs-time-tooltip, .video-js .vjs-mouse-display:after, .video-js .vjs-play-progress:after { - display: none; + visibility: hidden; + pointer-events: none; position: absolute; top: -3.4em; - right: -1.5em; + right: -1.9em; font-size: 0.9em; color: #000; content: attr(data-current-time); @@ -704,10 +729,14 @@ body.vjs-full-window { -moz-border-radius: 0.3em; border-radius: 0.3em; } +.video-js .vjs-time-tooltip, .video-js .vjs-play-progress:before, .video-js .vjs-play-progress:after { z-index: 1; } +.video-js .vjs-progress-control .vjs-keep-tooltips-inside:after { + display: none; } + .video-js .vjs-load-progress { background: #bfc7d3; background: rgba(115, 133, 159, 0.5); } @@ -719,6 +748,16 @@ body.vjs-full-window { .video-js.vjs-no-flex .vjs-progress-control { width: auto; } +.video-js .vjs-time-tooltip { + display: inline-block; + height: 2.4em; + position: relative; + float: right; + right: -1.9em; } + +.vjs-tooltip-progress-bar { + visibility: hidden; } + .video-js .vjs-progress-control .vjs-mouse-display { display: none; position: absolute; @@ -746,6 +785,7 @@ body.vjs-full-window { .video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display:after { display: none; } +.vjs-mouse-display .vjs-time-tooltip, .video-js .vjs-progress-control .vjs-mouse-display:after { color: #fff; background-color: #000; @@ -872,6 +912,7 @@ body.vjs-full-window { background-repeat: no-repeat; background-position: 50% 50%; background-size: contain; + background-color: #000000; cursor: pointer; margin: 0; padding: 0; diff --git a/resources/videojs/video.js b/resources/videojs/video.js index 473c1f9c7..cafa0e65b 100644 --- a/resources/videojs/video.js +++ b/resources/videojs/video.js @@ -1,6 +1,6 @@ /** * @license - * Video.js 5.8.8 + * Video.js 5.10.1 * Copyright Brightcove, Inc. * Available under Apache License Version 2.0 * @@ -2786,6 +2786,16 @@ var Button = (function (_ClickableComponent) { if (tag !== 'button') { _utilsLogJs2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.'); + + // Add properties for clickable element which is not a native HTML button + props = _objectAssign2['default']({ + tabIndex: 0 + }, props); + + // Add ARIA attributes for clickable element which is not a native HTML button + attributes = _objectAssign2['default']({ + role: 'button' + }, attributes); } // Add attributes for button element @@ -2841,7 +2851,7 @@ _component2['default'].registerComponent('Button', Button); exports['default'] = Button; module.exports = exports['default']; -},{"./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){ +},{"./clickable-component.js":65,"./component":67,"./utils/events.js":144,"./utils/fn.js":145,"./utils/log.js":148,"global/document":1,"object.assign":45}],65:[function(_dereq_,module,exports){ /** * @file button.js */ @@ -3020,6 +3030,32 @@ var ClickableComponent = (function (_Component) { return _Component.prototype.addChild.call(this, child, options); }; + /** + * Enable the component element + * + * @return {Component} + * @method enable + */ + + ClickableComponent.prototype.enable = function enable() { + this.removeClass('vjs-disabled'); + this.el_.setAttribute('aria-disabled', 'false'); + return this; + }; + + /** + * Disable the component element + * + * @return {Component} + * @method disable + */ + + ClickableComponent.prototype.disable = function disable() { + this.addClass('vjs-disabled'); + this.el_.setAttribute('aria-disabled', 'true'); + return this; + }; + /** * Handle Click - Override with specific functionality for component * @@ -3071,7 +3107,7 @@ _component2['default'].registerComponent('ClickableComponent', ClickableComponen exports['default'] = ClickableComponent; module.exports = exports['default']; -},{"./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){ +},{"./component":67,"./utils/dom.js":143,"./utils/events.js":144,"./utils/fn.js":145,"./utils/log.js":148,"global/document":1,"object.assign":45}],66:[function(_dereq_,module,exports){ 'use strict'; exports.__esModule = true; @@ -4306,6 +4342,68 @@ var Component = (function () { return parseInt(this.el_['offset' + _utilsToTitleCaseJs2['default'](widthOrHeight)], 10); }; + /** + * Get width or height of computed style + * @param {String} widthOrHeight 'width' or 'height' + * @return {Number|Boolean} The bolean false if nothing was set + * @method currentDimension + */ + + Component.prototype.currentDimension = function currentDimension(widthOrHeight) { + var computedWidthOrHeight = 0; + + if (widthOrHeight !== 'width' && widthOrHeight !== 'height') { + throw new Error('currentDimension only accepts width or height value'); + } + + if (typeof _globalWindow2['default'].getComputedStyle === 'function') { + var computedStyle = _globalWindow2['default'].getComputedStyle(this.el_); + computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight]; + } else if (this.el_.currentStyle) { + // ie 8 doesn't support computed style, shim it + // return clientWidth or clientHeight instead for better accuracy + var rule = 'offset' + _utilsToTitleCaseJs2['default'](widthOrHeight); + computedWidthOrHeight = this.el_[rule]; + } + + // remove 'px' from variable and parse as integer + computedWidthOrHeight = parseFloat(computedWidthOrHeight); + return computedWidthOrHeight; + }; + + /** + * Get an object which contains width and height values of computed style + * @return {Object} The dimensions of element + * @method currentDimensions + */ + + Component.prototype.currentDimensions = function currentDimensions() { + return { + width: this.currentDimension('width'), + height: this.currentDimension('height') + }; + }; + + /** + * Get width of computed style + * @return {Integer} + * @method currentWidth + */ + + Component.prototype.currentWidth = function currentWidth() { + return this.currentDimension('width'); + }; + + /** + * Get height of computed style + * @return {Integer} + * @method currentHeight + */ + + Component.prototype.currentHeight = function currentHeight() { + return this.currentDimension('height'); + }; + /** * Emit 'tap' events when touch events are supported * This is used to support toggling the controls through a tap on the video. @@ -4631,7 +4729,217 @@ Component.registerComponent('Component', Component); exports['default'] = Component; module.exports = exports['default']; -},{"./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){ +},{"./utils/dom.js":143,"./utils/events.js":144,"./utils/fn.js":145,"./utils/guid.js":147,"./utils/log.js":148,"./utils/merge-options.js":149,"./utils/to-title-case.js":152,"global/window":2,"object.assign":45}],68:[function(_dereq_,module,exports){ +/** + * @file audio-track-button.js + */ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _trackButtonJs = _dereq_('../track-button.js'); + +var _trackButtonJs2 = _interopRequireDefault(_trackButtonJs); + +var _componentJs = _dereq_('../../component.js'); + +var _componentJs2 = _interopRequireDefault(_componentJs); + +var _utilsFnJs = _dereq_('../../utils/fn.js'); + +var Fn = _interopRequireWildcard(_utilsFnJs); + +var _audioTrackMenuItemJs = _dereq_('./audio-track-menu-item.js'); + +var _audioTrackMenuItemJs2 = _interopRequireDefault(_audioTrackMenuItemJs); + +/** + * The base class for buttons that toggle specific text track types (e.g. subtitles) + * + * @param {Player|Object} player + * @param {Object=} options + * @extends TrackButton + * @class AudioTrackButton + */ + +var AudioTrackButton = (function (_TrackButton) { + _inherits(AudioTrackButton, _TrackButton); + + function AudioTrackButton(player) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + _classCallCheck(this, AudioTrackButton); + + options.tracks = player.audioTracks && player.audioTracks(); + + _TrackButton.call(this, player, options); + + this.el_.setAttribute('aria-label', 'Audio Menu'); + } + + /** + * Allow sub components to stack CSS class names + * + * @return {String} The constructed class name + * @method buildCSSClass + */ + + AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this); + }; + + /** + * Create a menu item for each audio track + * + * @return {Array} Array of menu items + * @method createItems + */ + + AudioTrackButton.prototype.createItems = function createItems() { + var items = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; + + var tracks = this.player_.audioTracks && this.player_.audioTracks(); + + if (!tracks) { + return items; + } + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + items.push(new _audioTrackMenuItemJs2['default'](this.player_, { + // MenuItem is selectable + 'selectable': true, + 'track': track + })); + } + + return items; + }; + + return AudioTrackButton; +})(_trackButtonJs2['default']); + +_componentJs2['default'].registerComponent('AudioTrackButton', AudioTrackButton); +exports['default'] = AudioTrackButton; +module.exports = exports['default']; + +},{"../../component.js":67,"../../utils/fn.js":145,"../track-button.js":98,"./audio-track-menu-item.js":69}],69:[function(_dereq_,module,exports){ +/** + * @file audio-track-menu-item.js + */ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _menuMenuItemJs = _dereq_('../../menu/menu-item.js'); + +var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); + +var _componentJs = _dereq_('../../component.js'); + +var _componentJs2 = _interopRequireDefault(_componentJs); + +var _utilsFnJs = _dereq_('../../utils/fn.js'); + +var Fn = _interopRequireWildcard(_utilsFnJs); + +/** + * The audio track menu item + * + * @param {Player|Object} player + * @param {Object=} options + * @extends MenuItem + * @class AudioTrackMenuItem + */ + +var AudioTrackMenuItem = (function (_MenuItem) { + _inherits(AudioTrackMenuItem, _MenuItem); + + function AudioTrackMenuItem(player, options) { + var _this = this; + + _classCallCheck(this, AudioTrackMenuItem); + + var track = options.track; + var tracks = player.audioTracks(); + + // Modify options for parent MenuItem class's init. + options.label = track.label || track.language || 'Unknown'; + options.selected = track.enabled; + + _MenuItem.call(this, player, options); + + this.track = track; + + if (tracks) { + (function () { + var changeHandler = Fn.bind(_this, _this.handleTracksChange); + + tracks.addEventListener('change', changeHandler); + _this.on('dispose', function () { + tracks.removeEventListener('change', changeHandler); + }); + })(); + } + } + + /** + * Handle click on audio track + * + * @method handleClick + */ + + AudioTrackMenuItem.prototype.handleClick = function handleClick(event) { + var tracks = this.player_.audioTracks(); + + _MenuItem.prototype.handleClick.call(this, event); + + if (!tracks) return; + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + if (track === this.track) { + track.enabled = true; + } + } + }; + + /** + * Handle audio track change + * + * @method handleTracksChange + */ + + AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { + this.selected(this.track.enabled); + }; + + return AudioTrackMenuItem; +})(_menuMenuItemJs2['default']); + +_componentJs2['default'].registerComponent('AudioTrackMenuItem', AudioTrackMenuItem); +exports['default'] = AudioTrackMenuItem; +module.exports = exports['default']; + +},{"../../component.js":67,"../../menu/menu-item.js":110,"../../utils/fn.js":145}],70:[function(_dereq_,module,exports){ /** * @file control-bar.js */ @@ -4699,6 +5007,10 @@ var _textTrackControlsChaptersButtonJs = _dereq_('./text-track-controls/chapters var _textTrackControlsChaptersButtonJs2 = _interopRequireDefault(_textTrackControlsChaptersButtonJs); +var _textTrackControlsDescriptionsButtonJs = _dereq_('./text-track-controls/descriptions-button.js'); + +var _textTrackControlsDescriptionsButtonJs2 = _interopRequireDefault(_textTrackControlsDescriptionsButtonJs); + var _textTrackControlsSubtitlesButtonJs = _dereq_('./text-track-controls/subtitles-button.js'); var _textTrackControlsSubtitlesButtonJs2 = _interopRequireDefault(_textTrackControlsSubtitlesButtonJs); @@ -4707,6 +5019,10 @@ var _textTrackControlsCaptionsButtonJs = _dereq_('./text-track-controls/captions var _textTrackControlsCaptionsButtonJs2 = _interopRequireDefault(_textTrackControlsCaptionsButtonJs); +var _audioTrackControlsAudioTrackButtonJs = _dereq_('./audio-track-controls/audio-track-button.js'); + +var _audioTrackControlsAudioTrackButtonJs2 = _interopRequireDefault(_audioTrackControlsAudioTrackButtonJs); + var _playbackRateMenuPlaybackRateMenuButtonJs = _dereq_('./playback-rate-menu/playback-rate-menu-button.js'); var _playbackRateMenuPlaybackRateMenuButtonJs2 = _interopRequireDefault(_playbackRateMenuPlaybackRateMenuButtonJs); @@ -4752,14 +5068,14 @@ var ControlBar = (function (_Component) { ControlBar.prototype.options_ = { loadEvent: 'play', - children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'subtitlesButton', 'captionsButton', 'fullscreenToggle'] + children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subtitlesButton', 'captionsButton', 'audioTrackButton', 'fullscreenToggle'] }; _componentJs2['default'].registerComponent('ControlBar', ControlBar); exports['default'] = ControlBar; module.exports = exports['default']; -},{"../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){ +},{"../component.js":67,"./audio-track-controls/audio-track-button.js":68,"./fullscreen-toggle.js":71,"./live-display.js":72,"./mute-toggle.js":73,"./play-toggle.js":74,"./playback-rate-menu/playback-rate-menu-button.js":75,"./progress-control/progress-control.js":80,"./spacer-controls/custom-control-spacer.js":83,"./text-track-controls/captions-button.js":86,"./text-track-controls/chapters-button.js":87,"./text-track-controls/descriptions-button.js":89,"./text-track-controls/subtitles-button.js":91,"./time-controls/current-time-display.js":94,"./time-controls/duration-display.js":95,"./time-controls/remaining-time-display.js":96,"./time-controls/time-divider.js":97,"./volume-control/volume-control.js":100,"./volume-menu-button.js":102}],71:[function(_dereq_,module,exports){ /** * @file fullscreen-toggle.js */ @@ -4833,7 +5149,7 @@ _componentJs2['default'].registerComponent('FullscreenToggle', FullscreenToggle) exports['default'] = FullscreenToggle; module.exports = exports['default']; -},{"../button.js":64,"../component.js":67}],70:[function(_dereq_,module,exports){ +},{"../button.js":64,"../component.js":67}],72:[function(_dereq_,module,exports){ /** * @file live-display.js */ @@ -4915,7 +5231,7 @@ _component2['default'].registerComponent('LiveDisplay', LiveDisplay); exports['default'] = LiveDisplay; module.exports = exports['default']; -},{"../component":67,"../utils/dom.js":132}],71:[function(_dereq_,module,exports){ +},{"../component":67,"../utils/dom.js":143}],73:[function(_dereq_,module,exports){ /** * @file mute-toggle.js */ @@ -5041,7 +5357,7 @@ _component2['default'].registerComponent('MuteToggle', MuteToggle); exports['default'] = MuteToggle; module.exports = exports['default']; -},{"../button":64,"../component":67,"../utils/dom.js":132}],72:[function(_dereq_,module,exports){ +},{"../button":64,"../component":67,"../utils/dom.js":143}],74:[function(_dereq_,module,exports){ /** * @file play-toggle.js */ @@ -5142,7 +5458,7 @@ _componentJs2['default'].registerComponent('PlayToggle', PlayToggle); exports['default'] = PlayToggle; module.exports = exports['default']; -},{"../button.js":64,"../component.js":67}],73:[function(_dereq_,module,exports){ +},{"../button.js":64,"../component.js":67}],75:[function(_dereq_,module,exports){ /** * @file playback-rate-menu-button.js */ @@ -5298,9 +5614,10 @@ var PlaybackRateMenuButton = (function (_MenuButton) { }; /** - * Get supported playback rates + * Get whether playback rates is supported by the tech + * and an array of playback rates exists * - * @return {Array} Supported playback rates + * @return {Boolean} Whether changing playback rate is supported * @method playbackRateSupported */ @@ -5343,7 +5660,7 @@ _componentJs2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRat exports['default'] = PlaybackRateMenuButton; module.exports = exports['default']; -},{"../../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){ +},{"../../component.js":67,"../../menu/menu-button.js":109,"../../menu/menu.js":111,"../../utils/dom.js":143,"./playback-rate-menu-item.js":76}],76:[function(_dereq_,module,exports){ /** * @file playback-rate-menu-item.js */ @@ -5424,7 +5741,7 @@ _componentJs2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateM exports['default'] = PlaybackRateMenuItem; module.exports = exports['default']; -},{"../../component.js":67,"../../menu/menu-item.js":105}],75:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../menu/menu-item.js":110}],77:[function(_dereq_,module,exports){ /** * @file load-progress-bar.js */ @@ -5530,7 +5847,7 @@ _componentJs2['default'].registerComponent('LoadProgressBar', LoadProgressBar); exports['default'] = LoadProgressBar; module.exports = exports['default']; -},{"../../component.js":67,"../../utils/dom.js":132}],76:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../utils/dom.js":143}],78:[function(_dereq_,module,exports){ /** * @file mouse-time-display.js */ @@ -5546,6 +5863,10 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons 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; } +var _globalWindow = _dereq_('global/window'); + +var _globalWindow2 = _interopRequireDefault(_globalWindow); + var _componentJs = _dereq_('../../component.js'); var _componentJs2 = _interopRequireDefault(_componentJs); @@ -5586,6 +5907,16 @@ var MouseTimeDisplay = (function (_Component) { _Component.call(this, player, options); + if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { + this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; + } + + if (this.keepTooltipsInside) { + this.tooltip = Dom.createEl('div', { className: 'vjs-time-tooltip' }); + this.el().appendChild(this.tooltip); + this.addClass('vjs-keep-tooltips-inside'); + } + this.update(0, 0); player.on('ready', function () { @@ -5619,12 +5950,52 @@ var MouseTimeDisplay = (function (_Component) { this.el().style.left = position + 'px'; this.el().setAttribute('data-current-time', time); + + if (this.keepTooltipsInside) { + var clampedPosition = this.clampPosition_(position); + var difference = position - clampedPosition + 1; + var tooltipWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.tooltip).width); + var tooltipWidthHalf = tooltipWidth / 2; + + this.tooltip.innerHTML = time; + this.tooltip.style.right = '-' + (tooltipWidthHalf - difference) + 'px'; + } }; MouseTimeDisplay.prototype.calculateDistance = function calculateDistance(event) { return Dom.getPointerPosition(this.el().parentNode, event).x; }; + /** + * This takes in a horizontal position for the bar and returns a clamped position. + * Clamped position means that it will keep the position greater than half the width + * of the tooltip and smaller than the player width minus half the width o the tooltip. + * It will only clamp the position if `keepTooltipsInside` option is set. + * + * @param {Number} position the position the bar wants to be + * @return {Number} newPosition the (potentially) clamped position + * @method clampPosition_ + */ + + MouseTimeDisplay.prototype.clampPosition_ = function clampPosition_(position) { + if (!this.keepTooltipsInside) { + return position; + } + + var playerWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.player().el()).width); + var tooltipWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.tooltip).width); + var tooltipWidthHalf = tooltipWidth / 2; + var actualPosition = position; + + if (position < tooltipWidthHalf) { + actualPosition = Math.ceil(tooltipWidthHalf); + } else if (position > playerWidth - tooltipWidthHalf) { + actualPosition = Math.floor(playerWidth - tooltipWidthHalf); + } + + return actualPosition; + }; + return MouseTimeDisplay; })(_componentJs2['default']); @@ -5632,7 +6003,7 @@ _componentJs2['default'].registerComponent('MouseTimeDisplay', MouseTimeDisplay) exports['default'] = MouseTimeDisplay; module.exports = exports['default']; -},{"../../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){ +},{"../../component.js":67,"../../utils/dom.js":143,"../../utils/fn.js":145,"../../utils/format-time.js":146,"global/window":2,"lodash-compat/function/throttle":7}],79:[function(_dereq_,module,exports){ /** * @file play-progress-bar.js */ @@ -5656,6 +6027,10 @@ var _utilsFnJs = _dereq_('../../utils/fn.js'); var Fn = _interopRequireWildcard(_utilsFnJs); +var _utilsDomJs = _dereq_('../../utils/dom.js'); + +var Dom = _interopRequireWildcard(_utilsDomJs); + var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); @@ -5679,6 +6054,14 @@ var PlayProgressBar = (function (_Component) { this.updateDataAttr(); this.on(player, 'timeupdate', this.updateDataAttr); player.ready(Fn.bind(this, this.updateDataAttr)); + + if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { + this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; + } + + if (this.keepTooltipsInside) { + this.addClass('vjs-keep-tooltips-inside'); + } } /** @@ -5707,7 +6090,7 @@ _componentJs2['default'].registerComponent('PlayProgressBar', PlayProgressBar); exports['default'] = PlayProgressBar; module.exports = exports['default']; -},{"../../component.js":67,"../../utils/fn.js":134,"../../utils/format-time.js":135}],78:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../utils/dom.js":143,"../../utils/fn.js":145,"../../utils/format-time.js":146}],80:[function(_dereq_,module,exports){ /** * @file progress-control.js */ @@ -5776,7 +6159,7 @@ _componentJs2['default'].registerComponent('ProgressControl', ProgressControl); exports['default'] = ProgressControl; module.exports = exports['default']; -},{"../../component.js":67,"./mouse-time-display.js":76,"./seek-bar.js":79}],79:[function(_dereq_,module,exports){ +},{"../../component.js":67,"./mouse-time-display.js":78,"./seek-bar.js":81}],81:[function(_dereq_,module,exports){ /** * @file seek-bar.js */ @@ -5792,6 +6175,10 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons 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; } +var _globalWindow = _dereq_('global/window'); + +var _globalWindow2 = _interopRequireDefault(_globalWindow); + var _sliderSliderJs = _dereq_('../../slider/slider.js'); var _sliderSliderJs2 = _interopRequireDefault(_sliderSliderJs); @@ -5808,6 +6195,10 @@ var _playProgressBarJs = _dereq_('./play-progress-bar.js'); var _playProgressBarJs2 = _interopRequireDefault(_playProgressBarJs); +var _tooltipProgressBarJs = _dereq_('./tooltip-progress-bar.js'); + +var _tooltipProgressBarJs2 = _interopRequireDefault(_tooltipProgressBarJs); + var _utilsFnJs = _dereq_('../../utils/fn.js'); var Fn = _interopRequireWildcard(_utilsFnJs); @@ -5836,8 +6227,17 @@ var SeekBar = (function (_Slider) { _classCallCheck(this, SeekBar); _Slider.call(this, player, options); - this.on(player, 'timeupdate', this.updateARIAAttributes); - player.ready(Fn.bind(this, this.updateARIAAttributes)); + this.on(player, 'timeupdate', this.updateProgress); + this.on(player, 'ended', this.updateProgress); + player.ready(Fn.bind(this, this.updateProgress)); + + if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { + this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; + } + + if (this.keepTooltipsInside) { + this.tooltipProgressBar = this.addChild('TooltipProgressBar'); + } } /** @@ -5851,7 +6251,7 @@ var SeekBar = (function (_Slider) { return _Slider.prototype.createEl.call(this, 'div', { className: 'vjs-progress-holder' }, { - 'aria-label': 'video progress bar' + 'aria-label': 'progress bar' }); }; @@ -5861,11 +6261,27 @@ var SeekBar = (function (_Slider) { * @method updateARIAAttributes */ - SeekBar.prototype.updateARIAAttributes = function updateARIAAttributes() { + SeekBar.prototype.updateProgress = function updateProgress() { + this.updateAriaAttributes(this.el_); + + if (this.keepTooltipsInside) { + this.updateAriaAttributes(this.tooltipProgressBar.el_); + this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width; + + var playerWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.player().el()).width); + var tooltipWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.tooltipProgressBar.tooltip).width); + var tooltipStyle = this.tooltipProgressBar.el().style; + tooltipStyle.maxWidth = Math.floor(playerWidth - tooltipWidth / 2) + 'px'; + tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px'; + tooltipStyle.right = '-' + tooltipWidth / 2 + 'px'; + } + }; + + SeekBar.prototype.updateAriaAttributes = function updateAriaAttributes(el) { // Allows for smooth scrubbing, when player can't keep up. var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); - this.el_.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2)); // machine readable value of progress bar (percentage complete) - this.el_.setAttribute('aria-valuetext', _utilsFormatTimeJs2['default'](time, this.player_.duration())); // human readable value of progress bar (time complete) + el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2)); // machine readable value of progress bar (percentage complete) + el.setAttribute('aria-valuetext', _utilsFormatTimeJs2['default'](time, this.player_.duration())); // human readable value of progress bar (time complete) }; /** @@ -5962,7 +6378,92 @@ _componentJs2['default'].registerComponent('SeekBar', SeekBar); exports['default'] = SeekBar; module.exports = exports['default']; -},{"../../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){ +},{"../../component.js":67,"../../slider/slider.js":119,"../../utils/fn.js":145,"../../utils/format-time.js":146,"./load-progress-bar.js":77,"./play-progress-bar.js":79,"./tooltip-progress-bar.js":82,"global/window":2,"object.assign":45}],82:[function(_dereq_,module,exports){ +/** + * @file play-progress-bar.js + */ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _componentJs = _dereq_('../../component.js'); + +var _componentJs2 = _interopRequireDefault(_componentJs); + +var _utilsFnJs = _dereq_('../../utils/fn.js'); + +var Fn = _interopRequireWildcard(_utilsFnJs); + +var _utilsDomJs = _dereq_('../../utils/dom.js'); + +var Dom = _interopRequireWildcard(_utilsDomJs); + +var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); + +var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); + +/** + * Shows play progress + * + * @param {Player|Object} player + * @param {Object=} options + * @extends Component + * @class PlayProgressBar + */ + +var TooltipProgressBar = (function (_Component) { + _inherits(TooltipProgressBar, _Component); + + function TooltipProgressBar(player, options) { + _classCallCheck(this, TooltipProgressBar); + + _Component.call(this, player, options); + this.updateDataAttr(); + this.on(player, 'timeupdate', this.updateDataAttr); + player.ready(Fn.bind(this, this.updateDataAttr)); + } + + /** + * Create the component's DOM element + * + * @return {Element} + * @method createEl + */ + + TooltipProgressBar.prototype.createEl = function createEl() { + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-tooltip-progress-bar vjs-slider-bar', + innerHTML: '
\n ' + this.localize('Progress') + ': 0%' + }); + + this.tooltip = el.querySelector('.vjs-time-tooltip'); + + return el; + }; + + TooltipProgressBar.prototype.updateDataAttr = function updateDataAttr() { + var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); + var formattedTime = _utilsFormatTimeJs2['default'](time, this.player_.duration()); + this.el_.setAttribute('data-current-time', formattedTime); + this.tooltip.innerHTML = formattedTime; + }; + + return TooltipProgressBar; +})(_componentJs2['default']); + +_componentJs2['default'].registerComponent('TooltipProgressBar', TooltipProgressBar); +exports['default'] = TooltipProgressBar; +module.exports = exports['default']; + +},{"../../component.js":67,"../../utils/dom.js":143,"../../utils/fn.js":145,"../../utils/format-time.js":146}],83:[function(_dereq_,module,exports){ /** * @file custom-control-spacer.js */ @@ -6036,7 +6537,7 @@ _componentJs2['default'].registerComponent('CustomControlSpacer', CustomControlS exports['default'] = CustomControlSpacer; module.exports = exports['default']; -},{"../../component.js":67,"./spacer.js":81}],81:[function(_dereq_,module,exports){ +},{"../../component.js":67,"./spacer.js":84}],84:[function(_dereq_,module,exports){ /** * @file spacer.js */ @@ -6103,7 +6604,7 @@ _componentJs2['default'].registerComponent('Spacer', Spacer); exports['default'] = Spacer; module.exports = exports['default']; -},{"../../component.js":67}],82:[function(_dereq_,module,exports){ +},{"../../component.js":67}],85:[function(_dereq_,module,exports){ /** * @file caption-settings-menu-item.js */ @@ -6175,7 +6676,7 @@ _componentJs2['default'].registerComponent('CaptionSettingsMenuItem', CaptionSet exports['default'] = CaptionSettingsMenuItem; module.exports = exports['default']; -},{"../../component.js":67,"./text-track-menu-item.js":89}],83:[function(_dereq_,module,exports){ +},{"../../component.js":67,"./text-track-menu-item.js":93}],86:[function(_dereq_,module,exports){ /** * @file captions-button.js */ @@ -6281,7 +6782,7 @@ _componentJs2['default'].registerComponent('CaptionsButton', CaptionsButton); exports['default'] = CaptionsButton; module.exports = exports['default']; -},{"../../component.js":67,"./caption-settings-menu-item.js":82,"./text-track-button.js":88}],84:[function(_dereq_,module,exports){ +},{"../../component.js":67,"./caption-settings-menu-item.js":85,"./text-track-button.js":92}],87:[function(_dereq_,module,exports){ /** * @file chapters-button.js */ @@ -6479,7 +6980,7 @@ _componentJs2['default'].registerComponent('ChaptersButton', ChaptersButton); exports['default'] = ChaptersButton; module.exports = exports['default']; -},{"../../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){ +},{"../../component.js":67,"../../menu/menu.js":111,"../../utils/dom.js":143,"../../utils/fn.js":145,"../../utils/to-title-case.js":152,"./chapters-track-menu-item.js":88,"./text-track-button.js":92,"./text-track-menu-item.js":93,"global/window":2}],88:[function(_dereq_,module,exports){ /** * @file chapters-track-menu-item.js */ @@ -6569,7 +7070,118 @@ _componentJs2['default'].registerComponent('ChaptersTrackMenuItem', ChaptersTrac exports['default'] = ChaptersTrackMenuItem; module.exports = exports['default']; -},{"../../component.js":67,"../../menu/menu-item.js":105,"../../utils/fn.js":134}],86:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../menu/menu-item.js":110,"../../utils/fn.js":145}],89:[function(_dereq_,module,exports){ +/** + * @file descriptions-button.js + */ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _textTrackButtonJs = _dereq_('./text-track-button.js'); + +var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); + +var _componentJs = _dereq_('../../component.js'); + +var _componentJs2 = _interopRequireDefault(_componentJs); + +var _utilsFnJs = _dereq_('../../utils/fn.js'); + +var Fn = _interopRequireWildcard(_utilsFnJs); + +/** + * The button component for toggling and selecting descriptions + * + * @param {Object} player Player object + * @param {Object=} options Object of option names and values + * @param {Function=} ready Ready callback function + * @extends TextTrackButton + * @class DescriptionsButton + */ + +var DescriptionsButton = (function (_TextTrackButton) { + _inherits(DescriptionsButton, _TextTrackButton); + + function DescriptionsButton(player, options, ready) { + var _this = this; + + _classCallCheck(this, DescriptionsButton); + + _TextTrackButton.call(this, player, options, ready); + this.el_.setAttribute('aria-label', 'Descriptions Menu'); + + var tracks = player.textTracks(); + + if (tracks) { + (function () { + var changeHandler = Fn.bind(_this, _this.handleTracksChange); + + tracks.addEventListener('change', changeHandler); + _this.on('dispose', function () { + tracks.removeEventListener('change', changeHandler); + }); + })(); + } + } + + /** + * Handle text track change + * + * @method handleTracksChange + */ + + DescriptionsButton.prototype.handleTracksChange = function handleTracksChange(event) { + var tracks = this.player().textTracks(); + var disabled = false; + + // Check whether a track of a different kind is showing + for (var i = 0, l = tracks.length; i < l; i++) { + var track = tracks[i]; + if (track['kind'] !== this.kind_ && track['mode'] === 'showing') { + disabled = true; + break; + } + } + + // If another track is showing, disable this menu button + if (disabled) { + this.disable(); + } else { + this.enable(); + } + }; + + /** + * Allow sub components to stack CSS class names + * + * @return {String} The constructed class name + * @method buildCSSClass + */ + + DescriptionsButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + return DescriptionsButton; +})(_textTrackButtonJs2['default']); + +DescriptionsButton.prototype.kind_ = 'descriptions'; +DescriptionsButton.prototype.controlText_ = 'Descriptions'; + +_componentJs2['default'].registerComponent('DescriptionsButton', DescriptionsButton); +exports['default'] = DescriptionsButton; +module.exports = exports['default']; + +},{"../../component.js":67,"../../utils/fn.js":145,"./text-track-button.js":92}],90:[function(_dereq_,module,exports){ /** * @file off-text-track-menu-item.js */ @@ -6652,7 +7264,7 @@ _componentJs2['default'].registerComponent('OffTextTrackMenuItem', OffTextTrackM exports['default'] = OffTextTrackMenuItem; module.exports = exports['default']; -},{"../../component.js":67,"./text-track-menu-item.js":89}],87:[function(_dereq_,module,exports){ +},{"../../component.js":67,"./text-track-menu-item.js":93}],91:[function(_dereq_,module,exports){ /** * @file subtitles-button.js */ @@ -6715,7 +7327,7 @@ _componentJs2['default'].registerComponent('SubtitlesButton', SubtitlesButton); exports['default'] = SubtitlesButton; module.exports = exports['default']; -},{"../../component.js":67,"./text-track-button.js":88}],88:[function(_dereq_,module,exports){ +},{"../../component.js":67,"./text-track-button.js":92}],92:[function(_dereq_,module,exports){ /** * @file text-track-button.js */ @@ -6731,9 +7343,9 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons 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; } -var _menuMenuButtonJs = _dereq_('../../menu/menu-button.js'); +var _trackButtonJs = _dereq_('../track-button.js'); -var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); +var _trackButtonJs2 = _interopRequireDefault(_trackButtonJs); var _componentJs = _dereq_('../../component.js'); @@ -6760,35 +7372,25 @@ var _offTextTrackMenuItemJs2 = _interopRequireDefault(_offTextTrackMenuItemJs); * @class TextTrackButton */ -var TextTrackButton = (function (_MenuButton) { - _inherits(TextTrackButton, _MenuButton); - - function TextTrackButton(player, options) { - _classCallCheck(this, TextTrackButton); - - _MenuButton.call(this, player, options); - - var tracks = this.player_.textTracks(); +var TextTrackButton = (function (_TrackButton) { + _inherits(TextTrackButton, _TrackButton); - if (this.items.length <= 1) { - this.hide(); - } + function TextTrackButton(player) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - if (!tracks) { - return; - } + _classCallCheck(this, TextTrackButton); - var updateHandler = Fn.bind(this, this.update); - tracks.addEventListener('removetrack', updateHandler); - tracks.addEventListener('addtrack', updateHandler); + options.tracks = player.textTracks(); - this.player_.on('dispose', function () { - tracks.removeEventListener('removetrack', updateHandler); - tracks.removeEventListener('addtrack', updateHandler); - }); + _TrackButton.call(this, player, options); } - // Create a menu item for each text track + /** + * Create a menu item for each text track + * + * @return {Array} Array of menu items + * @method createItems + */ TextTrackButton.prototype.createItems = function createItems() { var items = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; @@ -6819,13 +7421,13 @@ var TextTrackButton = (function (_MenuButton) { }; return TextTrackButton; -})(_menuMenuButtonJs2['default']); +})(_trackButtonJs2['default']); _componentJs2['default'].registerComponent('TextTrackButton', TextTrackButton); exports['default'] = TextTrackButton; module.exports = exports['default']; -},{"../../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){ +},{"../../component.js":67,"../../utils/fn.js":145,"../track-button.js":98,"./off-text-track-menu-item.js":90,"./text-track-menu-item.js":93}],93:[function(_dereq_,module,exports){ /** * @file text-track-menu-item.js */ @@ -6975,7 +7577,7 @@ _componentJs2['default'].registerComponent('TextTrackMenuItem', TextTrackMenuIte exports['default'] = TextTrackMenuItem; module.exports = exports['default']; -},{"../../component.js":67,"../../menu/menu-item.js":105,"../../utils/fn.js":134,"global/document":1,"global/window":2}],90:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../menu/menu-item.js":110,"../../utils/fn.js":145,"global/document":1,"global/window":2}],94:[function(_dereq_,module,exports){ /** * @file current-time-display.js */ @@ -7072,7 +7674,7 @@ _componentJs2['default'].registerComponent('CurrentTimeDisplay', CurrentTimeDisp exports['default'] = CurrentTimeDisplay; module.exports = exports['default']; -},{"../../component.js":67,"../../utils/dom.js":132,"../../utils/format-time.js":135}],91:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../utils/dom.js":143,"../../utils/format-time.js":146}],95:[function(_dereq_,module,exports){ /** * @file duration-display.js */ @@ -7174,7 +7776,7 @@ _componentJs2['default'].registerComponent('DurationDisplay', DurationDisplay); exports['default'] = DurationDisplay; module.exports = exports['default']; -},{"../../component.js":67,"../../utils/dom.js":132,"../../utils/format-time.js":135}],92:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../utils/dom.js":143,"../../utils/format-time.js":146}],96:[function(_dereq_,module,exports){ /** * @file remaining-time-display.js */ @@ -7275,7 +7877,7 @@ _componentJs2['default'].registerComponent('RemainingTimeDisplay', RemainingTime exports['default'] = RemainingTimeDisplay; module.exports = exports['default']; -},{"../../component.js":67,"../../utils/dom.js":132,"../../utils/format-time.js":135}],93:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../utils/dom.js":143,"../../utils/format-time.js":146}],97:[function(_dereq_,module,exports){ /** * @file time-divider.js */ @@ -7333,7 +7935,79 @@ _componentJs2['default'].registerComponent('TimeDivider', TimeDivider); exports['default'] = TimeDivider; module.exports = exports['default']; -},{"../../component.js":67}],94:[function(_dereq_,module,exports){ +},{"../../component.js":67}],98:[function(_dereq_,module,exports){ +/** + * @file track-button.js + */ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _menuMenuButtonJs = _dereq_('../menu/menu-button.js'); + +var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); + +var _componentJs = _dereq_('../component.js'); + +var _componentJs2 = _interopRequireDefault(_componentJs); + +var _utilsFnJs = _dereq_('../utils/fn.js'); + +var Fn = _interopRequireWildcard(_utilsFnJs); + +/** + * The base class for buttons that toggle specific text track types (e.g. subtitles) + * + * @param {Player|Object} player + * @param {Object=} options + * @extends MenuButton + * @class TrackButton + */ + +var TrackButton = (function (_MenuButton) { + _inherits(TrackButton, _MenuButton); + + function TrackButton(player, options) { + _classCallCheck(this, TrackButton); + + var tracks = options.tracks; + + _MenuButton.call(this, player, options); + + if (this.items.length <= 1) { + this.hide(); + } + + if (!tracks) { + return; + } + + var updateHandler = Fn.bind(this, this.update); + tracks.addEventListener('removetrack', updateHandler); + tracks.addEventListener('addtrack', updateHandler); + + this.player_.on('dispose', function () { + tracks.removeEventListener('removetrack', updateHandler); + tracks.removeEventListener('addtrack', updateHandler); + }); + } + + return TrackButton; +})(_menuMenuButtonJs2['default']); + +_componentJs2['default'].registerComponent('TrackButton', TrackButton); +exports['default'] = TrackButton; +module.exports = exports['default']; + +},{"../component.js":67,"../menu/menu-button.js":109,"../utils/fn.js":145}],99:[function(_dereq_,module,exports){ /** * @file volume-bar.js */ @@ -7483,7 +8157,7 @@ _componentJs2['default'].registerComponent('VolumeBar', VolumeBar); exports['default'] = VolumeBar; module.exports = exports['default']; -},{"../../component.js":67,"../../slider/slider.js":114,"../../utils/fn.js":134,"./volume-level.js":96}],95:[function(_dereq_,module,exports){ +},{"../../component.js":67,"../../slider/slider.js":119,"../../utils/fn.js":145,"./volume-level.js":101}],100:[function(_dereq_,module,exports){ /** * @file volume-control.js */ @@ -7561,7 +8235,7 @@ _componentJs2['default'].registerComponent('VolumeControl', VolumeControl); exports['default'] = VolumeControl; module.exports = exports['default']; -},{"../../component.js":67,"./volume-bar.js":94}],96:[function(_dereq_,module,exports){ +},{"../../component.js":67,"./volume-bar.js":99}],101:[function(_dereq_,module,exports){ /** * @file volume-level.js */ @@ -7618,7 +8292,7 @@ _componentJs2['default'].registerComponent('VolumeLevel', VolumeLevel); exports['default'] = VolumeLevel; module.exports = exports['default']; -},{"../../component.js":67}],97:[function(_dereq_,module,exports){ +},{"../../component.js":67}],102:[function(_dereq_,module,exports){ /** * @file volume-menu-button.js */ @@ -7658,10 +8332,6 @@ var _volumeControlVolumeBarJs = _dereq_('./volume-control/volume-bar.js'); var _volumeControlVolumeBarJs2 = _interopRequireDefault(_volumeControlVolumeBarJs); -var _globalDocument = _dereq_('global/document'); - -var _globalDocument2 = _interopRequireDefault(_globalDocument); - /** * Button for volume popup * @@ -7794,7 +8464,7 @@ var VolumeMenuButton = (function (_PopupButton) { VolumeMenuButton.prototype.handleMouseDown = function handleMouseDown(event) { this.on(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove)); - this.on(_globalDocument2['default'], ['mouseup', 'touchend'], this.handleMouseUp); + this.on(this.el_.ownerDocument, ['mouseup', 'touchend'], this.handleMouseUp); }; VolumeMenuButton.prototype.handleMouseUp = function handleMouseUp(event) { @@ -7811,7 +8481,7 @@ _componentJs2['default'].registerComponent('VolumeMenuButton', VolumeMenuButton) exports['default'] = VolumeMenuButton; module.exports = exports['default']; -},{"../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){ +},{"../component.js":67,"../popup/popup-button.js":115,"../popup/popup.js":116,"../utils/fn.js":145,"./mute-toggle.js":73,"./volume-control/volume-bar.js":99}],103:[function(_dereq_,module,exports){ /** * @file error-display.js */ @@ -7905,7 +8575,7 @@ _component2['default'].registerComponent('ErrorDisplay', ErrorDisplay); exports['default'] = ErrorDisplay; module.exports = exports['default']; -},{"./component":67,"./modal-dialog":107,"./utils/dom":132,"./utils/merge-options":138}],99:[function(_dereq_,module,exports){ +},{"./component":67,"./modal-dialog":112,"./utils/dom":143,"./utils/merge-options":149}],104:[function(_dereq_,module,exports){ /** * @file event-target.js */ @@ -7927,7 +8597,7 @@ EventTarget.prototype.on = function (type, fn) { // Remove the addEventListener alias before calling Events.on // so we don't get into an infinite type loop var ael = this.addEventListener; - this.addEventListener = Function.prototype; + this.addEventListener = function () {}; Events.on(this, type, fn); this.addEventListener = ael; }; @@ -7939,7 +8609,12 @@ EventTarget.prototype.off = function (type, fn) { EventTarget.prototype.removeEventListener = EventTarget.prototype.off; EventTarget.prototype.one = function (type, fn) { + // Remove the addEventListener alias before calling Events.on + // so we don't get into an infinite type loop + var ael = this.addEventListener; + this.addEventListener = function () {}; Events.one(this, type, fn); + this.addEventListener = ael; }; EventTarget.prototype.trigger = function (event) { @@ -7964,7 +8639,7 @@ EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger; exports['default'] = EventTarget; module.exports = exports['default']; -},{"./utils/events.js":133}],100:[function(_dereq_,module,exports){ +},{"./utils/events.js":144}],105:[function(_dereq_,module,exports){ 'use strict'; exports.__esModule = true; @@ -8055,7 +8730,7 @@ var extendFn = function extendFn(superClass) { exports['default'] = extendFn; module.exports = exports['default']; -},{"./utils/log":137}],101:[function(_dereq_,module,exports){ +},{"./utils/log":148}],106:[function(_dereq_,module,exports){ /** * @file fullscreen-api.js */ @@ -8112,7 +8787,7 @@ if (browserApi) { exports['default'] = FullscreenApi; module.exports = exports['default']; -},{"global/document":1}],102:[function(_dereq_,module,exports){ +},{"global/document":1}],107:[function(_dereq_,module,exports){ /** * @file loading-spinner.js */ @@ -8168,7 +8843,7 @@ _component2['default'].registerComponent('LoadingSpinner', LoadingSpinner); exports['default'] = LoadingSpinner; module.exports = exports['default']; -},{"./component":67}],103:[function(_dereq_,module,exports){ +},{"./component":67}],108:[function(_dereq_,module,exports){ /** * @file media-error.js */ @@ -8259,7 +8934,7 @@ for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { exports['default'] = MediaError; module.exports = exports['default']; -},{"object.assign":45}],104:[function(_dereq_,module,exports){ +},{"object.assign":45}],109:[function(_dereq_,module,exports){ /** * @file menu-button.js */ @@ -8320,7 +8995,9 @@ var MenuButton = (function (_ClickableComponent) { this.update(); - this.el_.setAttribute('aria-haspopup', true); + this.enabled_ = true; + + this.el_.setAttribute('aria-haspopup', 'true'); this.el_.setAttribute('role', 'menuitem'); this.on('keydown', this.handleSubmenuKeyPress); } @@ -8348,7 +9025,7 @@ var MenuButton = (function (_ClickableComponent) { * @private */ this.buttonPressed_ = false; - this.el_.setAttribute('aria-expanded', false); + this.el_.setAttribute('aria-expanded', 'false'); if (this.items && this.items.length === 0) { this.hide(); @@ -8510,10 +9187,12 @@ var MenuButton = (function (_ClickableComponent) { */ MenuButton.prototype.pressButton = function pressButton() { - this.buttonPressed_ = true; - this.menu.lockShowing(); - this.el_.setAttribute('aria-expanded', true); - this.menu.focus(); // set the focus into the submenu + if (this.enabled_) { + this.buttonPressed_ = true; + this.menu.lockShowing(); + this.el_.setAttribute('aria-expanded', 'true'); + this.menu.focus(); // set the focus into the submenu + } }; /** @@ -8523,10 +9202,43 @@ var MenuButton = (function (_ClickableComponent) { */ MenuButton.prototype.unpressButton = function unpressButton() { + if (this.enabled_) { + this.buttonPressed_ = false; + this.menu.unlockShowing(); + this.el_.setAttribute('aria-expanded', 'false'); + this.el_.focus(); // Set focus back to this menu button + } + }; + + /** + * Disable the menu button + * + * @return {Component} + * @method disable + */ + + MenuButton.prototype.disable = function disable() { + // Unpress, but don't force focus on this button this.buttonPressed_ = false; this.menu.unlockShowing(); - this.el_.setAttribute('aria-expanded', false); - this.el_.focus(); // Set focus back to this menu button + this.el_.setAttribute('aria-expanded', 'false'); + + this.enabled_ = false; + + return _ClickableComponent.prototype.disable.call(this); + }; + + /** + * Enable the menu button + * + * @return {Component} + * @method disable + */ + + MenuButton.prototype.enable = function enable() { + this.enabled_ = true; + + return _ClickableComponent.prototype.enable.call(this); }; return MenuButton; @@ -8536,7 +9248,7 @@ _componentJs2['default'].registerComponent('MenuButton', MenuButton); exports['default'] = MenuButton; module.exports = exports['default']; -},{"../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){ +},{"../clickable-component.js":65,"../component.js":67,"../utils/dom.js":143,"../utils/fn.js":145,"../utils/to-title-case.js":152,"./menu.js":111}],110:[function(_dereq_,module,exports){ /** * @file menu-item.js */ @@ -8630,13 +9342,13 @@ var MenuItem = (function (_ClickableComponent) { if (this.selectable) { if (_selected) { this.addClass('vjs-selected'); - this.el_.setAttribute('aria-checked', true); + this.el_.setAttribute('aria-checked', 'true'); // aria-checked isn't fully supported by browsers/screen readers, // so indicate selected state to screen reader in the control text. this.controlText(', selected'); } else { this.removeClass('vjs-selected'); - this.el_.setAttribute('aria-checked', false); + this.el_.setAttribute('aria-checked', 'false'); // Indicate un-selected state to screen reader // Note that a space clears out the selected state text this.controlText(' '); @@ -8651,7 +9363,7 @@ _componentJs2['default'].registerComponent('MenuItem', MenuItem); exports['default'] = MenuItem; module.exports = exports['default']; -},{"../clickable-component.js":65,"../component.js":67,"object.assign":45}],106:[function(_dereq_,module,exports){ +},{"../clickable-component.js":65,"../component.js":67,"object.assign":45}],111:[function(_dereq_,module,exports){ /** * @file menu.js */ @@ -8835,7 +9547,7 @@ _componentJs2['default'].registerComponent('Menu', Menu); exports['default'] = Menu; module.exports = exports['default']; -},{"../component.js":67,"../utils/dom.js":132,"../utils/events.js":133,"../utils/fn.js":134}],107:[function(_dereq_,module,exports){ +},{"../component.js":67,"../utils/dom.js":143,"../utils/events.js":144,"../utils/fn.js":145}],112:[function(_dereq_,module,exports){ /** * @file modal-dialog.js */ @@ -8843,18 +9555,14 @@ module.exports = exports['default']; exports.__esModule = true; -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; } } - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } +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; } } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 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; } -var _globalDocument = _dereq_('global/document'); - -var _globalDocument2 = _interopRequireDefault(_globalDocument); - var _utilsDom = _dereq_('./utils/dom'); var Dom = _interopRequireWildcard(_utilsDom); @@ -9058,7 +9766,7 @@ var ModalDialog = (function (_Component) { } if (this.closeable()) { - this.on(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); + this.on(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress)); } player.controls(false); @@ -9106,7 +9814,7 @@ var ModalDialog = (function (_Component) { } if (this.closeable()) { - this.off(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); + this.off(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress)); } player.controls(true); @@ -9258,7 +9966,7 @@ _component2['default'].registerComponent('ModalDialog', ModalDialog); exports['default'] = ModalDialog; module.exports = exports['default']; -},{"./close-button":66,"./component":67,"./utils/dom":132,"./utils/fn":134,"./utils/log":137,"global/document":1}],108:[function(_dereq_,module,exports){ +},{"./close-button":66,"./component":67,"./utils/dom":143,"./utils/fn":145,"./utils/log":148}],113:[function(_dereq_,module,exports){ /** * @file player.js */ @@ -9347,6 +10055,14 @@ var _tracksTextTrackListConverterJs = _dereq_('./tracks/text-track-list-converte var _tracksTextTrackListConverterJs2 = _interopRequireDefault(_tracksTextTrackListConverterJs); +var _tracksAudioTrackListJs = _dereq_('./tracks/audio-track-list.js'); + +var _tracksAudioTrackListJs2 = _interopRequireDefault(_tracksAudioTrackListJs); + +var _tracksVideoTrackListJs = _dereq_('./tracks/video-track-list.js'); + +var _tracksVideoTrackListJs2 = _interopRequireDefault(_tracksVideoTrackListJs); + // Include required child components (importing also registers them) var _techLoaderJs = _dereq_('./tech/loader.js'); @@ -9546,6 +10262,14 @@ var Player = (function (_Component) { this.addClass('vjs-controls-disabled'); } + // Set ARIA label and region role depending on player type + this.el_.setAttribute('role', 'region'); + if (this.isAudio()) { + this.el_.setAttribute('aria-label', 'audio player'); + } else { + this.el_.setAttribute('aria-label', 'video player'); + } + if (this.isAudio()) { this.addClass('vjs-audio'); } @@ -9664,10 +10388,12 @@ var Player = (function (_Component) { // Add a style element in the player that we'll use to set the width/height // of the player in a way that's still overrideable by CSS, just like the // video element - this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions'); - var defaultsStyleEl = Dom.$('.vjs-styles-defaults'); - var head = Dom.$('head'); - head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild); + if (_globalWindow2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true) { + this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions'); + var defaultsStyleEl = Dom.$('.vjs-styles-defaults'); + var head = Dom.$('head'); + head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild); + } // Pass in the width/height/aspectRatio options which will update the style el this.width(this.options_.width); @@ -9675,6 +10401,14 @@ var Player = (function (_Component) { this.fluid(this.options_.fluid); this.aspectRatio(this.options_.aspectRatio); + // Hide any links within the video/audio tag, because IE doesn't hide them completely. + var links = tag.getElementsByTagName('a'); + for (var i = 0; i < links.length; i++) { + var linkEl = links.item(i); + Dom.addElClass(linkEl, 'vjs-hidden'); + linkEl.setAttribute('hidden', 'hidden'); + } + // insertElFirst seems to cause the networkState to flicker from 3 to 2, so // keep track of the original for later so we can know if the source originally failed tag.initNetworkState_ = tag.networkState; @@ -9807,6 +10541,23 @@ var Player = (function (_Component) { */ Player.prototype.updateStyleEl_ = function updateStyleEl_() { + if (_globalWindow2['default'].VIDEOJS_NO_DYNAMIC_STYLE === true) { + var _width = typeof this.width_ === 'number' ? this.width_ : this.options_.width; + var _height = typeof this.height_ === 'number' ? this.height_ : this.options_.height; + var techEl = this.tech_ && this.tech_.el(); + + if (techEl) { + if (_width >= 0) { + techEl.width = _width; + } + if (_height >= 0) { + techEl.height = _height; + } + } + + return; + } + var width = undefined; var height = undefined; var aspectRatio = undefined; @@ -9896,7 +10647,9 @@ var Player = (function (_Component) { 'source': source, 'playerId': this.id(), 'techId': this.id() + '_' + techName + '_api', + 'videoTracks': this.videoTracks_, 'textTracks': this.textTracks_, + 'audioTracks': this.audioTracks_, 'autoplay': this.options_.autoplay, 'preload': this.options_.preload, 'loop': this.options_.loop, @@ -9990,7 +10743,9 @@ var Player = (function (_Component) { Player.prototype.unloadTech_ = function unloadTech_() { // Save the current text tracks so that we can reuse the same text tracks with the next tech + this.videoTracks_ = this.videoTracks(); this.textTracks_ = this.textTracks(); + this.audioTracks_ = this.audioTracks(); this.textTracksJson_ = _tracksTextTrackListConverterJs2['default'].textTracksToJson(this.tech_); this.isReady_ = false; @@ -11946,6 +12701,44 @@ var Player = (function (_Component) { return this.techGet_('readyState'); }; + /** + * Get a video track list + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist + * + * @return {VideoTrackList} thes current video track list + * @method videoTracks + */ + + Player.prototype.videoTracks = function videoTracks() { + // if we have not yet loadTech_, we create videoTracks_ + // these will be passed to the tech during loading + if (!this.tech_) { + this.videoTracks_ = this.videoTracks_ || new _tracksVideoTrackListJs2['default'](); + return this.videoTracks_; + } + + return this.tech_.videoTracks(); + }; + + /** + * Get an audio track list + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist + * + * @return {AudioTrackList} thes current audio track list + * @method audioTracks + */ + + Player.prototype.audioTracks = function audioTracks() { + // if we have not yet loadTech_, we create videoTracks_ + // these will be passed to the tech during loading + if (!this.tech_) { + this.audioTracks_ = this.audioTracks_ || new _tracksAudioTrackListJs2['default'](); + return this.audioTracks_; + } + + return this.tech_.audioTracks(); + }; + /* * Text tracks are tracks of timed text events. * Captions - text displayed over the video for the hearing impaired @@ -12022,8 +12815,15 @@ var Player = (function (_Component) { * @param {Object} track Remote text track to remove * @method removeRemoteTextTrack */ + // destructure the input into an object with a track argument, defaulting to arguments[0] + // default the whole argument to an empty object if nothing was passed in + + Player.prototype.removeRemoteTextTrack = function removeRemoteTextTrack() { + var _ref3 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - Player.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { + var _ref3$track = _ref3.track; + var track = _ref3$track === undefined ? arguments[0] : _ref3$track; + // jshint ignore:line this.tech_ && this.tech_['removeRemoteTextTrack'](track); }; @@ -12053,8 +12853,6 @@ var Player = (function (_Component) { // initialTime: function(){ return this.techCall_('initialTime'); }, // startOffsetTime: function(){ return this.techCall_('startOffsetTime'); }, // played: function(){ return this.techCall_('played'); }, - // videoTracks: function(){ return this.techCall_('videoTracks'); }, - // audioTracks: function(){ return this.techCall_('audioTracks'); }, // defaultPlaybackRate: function(){ return this.techCall_('defaultPlaybackRate'); }, // defaultMuted: function(){ return this.techCall_('defaultMuted'); } @@ -12320,7 +13118,7 @@ exports['default'] = Player; module.exports = exports['default']; // If empty string, make it a parsable json object. -},{"./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){ +},{"./big-play-button.js":63,"./component.js":67,"./control-bar/control-bar.js":70,"./error-display.js":103,"./fullscreen-api.js":106,"./loading-spinner.js":107,"./media-error.js":108,"./modal-dialog":112,"./poster-image.js":117,"./tech/html5.js":122,"./tech/loader.js":123,"./tech/tech.js":124,"./tracks/audio-track-list.js":125,"./tracks/text-track-display.js":130,"./tracks/text-track-list-converter.js":131,"./tracks/text-track-settings.js":133,"./tracks/video-track-list.js":138,"./utils/browser.js":140,"./utils/buffer.js":141,"./utils/dom.js":143,"./utils/events.js":144,"./utils/fn.js":145,"./utils/guid.js":147,"./utils/log.js":148,"./utils/merge-options.js":149,"./utils/stylesheet.js":150,"./utils/time-ranges.js":151,"./utils/to-title-case.js":152,"global/document":1,"global/window":2,"object.assign":45,"safe-json-parse/tuple":54}],114:[function(_dereq_,module,exports){ /** * @file plugins.js */ @@ -12348,7 +13146,7 @@ var plugin = function plugin(name, init) { exports['default'] = plugin; module.exports = exports['default']; -},{"./player.js":108}],110:[function(_dereq_,module,exports){ +},{"./player.js":113}],115:[function(_dereq_,module,exports){ /** * @file popup-button.js */ @@ -12482,7 +13280,7 @@ _componentJs2['default'].registerComponent('PopupButton', PopupButton); exports['default'] = PopupButton; module.exports = exports['default']; -},{"../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){ +},{"../clickable-component.js":65,"../component.js":67,"../utils/dom.js":143,"../utils/fn.js":145,"../utils/to-title-case.js":152,"./popup.js":116}],116:[function(_dereq_,module,exports){ /** * @file popup.js */ @@ -12579,7 +13377,7 @@ _componentJs2['default'].registerComponent('Popup', Popup); exports['default'] = Popup; module.exports = exports['default']; -},{"../component.js":67,"../utils/dom.js":132,"../utils/events.js":133,"../utils/fn.js":134}],112:[function(_dereq_,module,exports){ +},{"../component.js":67,"../utils/dom.js":143,"../utils/events.js":144,"../utils/fn.js":145}],117:[function(_dereq_,module,exports){ /** * @file poster-image.js */ @@ -12739,7 +13537,7 @@ _componentJs2['default'].registerComponent('PosterImage', PosterImage); exports['default'] = PosterImage; module.exports = exports['default']; -},{"./clickable-component.js":65,"./component.js":67,"./utils/browser.js":129,"./utils/dom.js":132,"./utils/fn.js":134}],113:[function(_dereq_,module,exports){ +},{"./clickable-component.js":65,"./component.js":67,"./utils/browser.js":140,"./utils/dom.js":143,"./utils/fn.js":145}],118:[function(_dereq_,module,exports){ /** * @file setup.js * @@ -12852,7 +13650,7 @@ exports.autoSetup = autoSetup; exports.autoSetupTimeout = autoSetupTimeout; exports.hasLoaded = hasLoaded; -},{"./utils/events.js":133,"global/document":1,"global/window":2}],114:[function(_dereq_,module,exports){ +},{"./utils/events.js":144,"global/document":1,"global/window":2}],119:[function(_dereq_,module,exports){ /** * @file slider.js */ @@ -12876,10 +13674,6 @@ var _utilsDomJs = _dereq_('../utils/dom.js'); var Dom = _interopRequireWildcard(_utilsDomJs); -var _globalDocument = _dereq_('global/document'); - -var _globalDocument2 = _interopRequireDefault(_globalDocument); - var _objectAssign = _dereq_('object.assign'); var _objectAssign2 = _interopRequireDefault(_objectAssign); @@ -12955,16 +13749,18 @@ var Slider = (function (_Component) { */ Slider.prototype.handleMouseDown = function handleMouseDown(event) { + var doc = this.bar.el_.ownerDocument; + event.preventDefault(); Dom.blockTextSelection(); this.addClass('vjs-sliding'); this.trigger('slideractive'); - this.on(_globalDocument2['default'], 'mousemove', this.handleMouseMove); - this.on(_globalDocument2['default'], 'mouseup', this.handleMouseUp); - this.on(_globalDocument2['default'], 'touchmove', this.handleMouseMove); - this.on(_globalDocument2['default'], 'touchend', this.handleMouseUp); + this.on(doc, 'mousemove', this.handleMouseMove); + this.on(doc, 'mouseup', this.handleMouseUp); + this.on(doc, 'touchmove', this.handleMouseMove); + this.on(doc, 'touchend', this.handleMouseUp); this.handleMouseMove(event); }; @@ -12984,15 +13780,17 @@ var Slider = (function (_Component) { */ Slider.prototype.handleMouseUp = function handleMouseUp() { + var doc = this.bar.el_.ownerDocument; + Dom.unblockTextSelection(); this.removeClass('vjs-sliding'); this.trigger('sliderinactive'); - this.off(_globalDocument2['default'], 'mousemove', this.handleMouseMove); - this.off(_globalDocument2['default'], 'mouseup', this.handleMouseUp); - this.off(_globalDocument2['default'], 'touchmove', this.handleMouseMove); - this.off(_globalDocument2['default'], 'touchend', this.handleMouseUp); + this.off(doc, 'mousemove', this.handleMouseMove); + this.off(doc, 'mouseup', this.handleMouseUp); + this.off(doc, 'touchmove', this.handleMouseMove); + this.off(doc, 'touchend', this.handleMouseUp); this.update(); }; @@ -13055,7 +13853,7 @@ var Slider = (function (_Component) { */ Slider.prototype.handleFocus = function handleFocus() { - this.on(_globalDocument2['default'], 'keydown', this.handleKeyPress); + this.on(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); }; /** @@ -13084,7 +13882,7 @@ var Slider = (function (_Component) { */ Slider.prototype.handleBlur = function handleBlur() { - this.off(_globalDocument2['default'], 'keydown', this.handleKeyPress); + this.off(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); }; /** @@ -13131,7 +13929,7 @@ _componentJs2['default'].registerComponent('Slider', Slider); exports['default'] = Slider; module.exports = exports['default']; -},{"../component.js":67,"../utils/dom.js":132,"global/document":1,"object.assign":45}],115:[function(_dereq_,module,exports){ +},{"../component.js":67,"../utils/dom.js":143,"object.assign":45}],120:[function(_dereq_,module,exports){ /** * @file flash-rtmp.js */ @@ -13231,10 +14029,11 @@ function FlashRtmpDecorator(Flash) { * Pass the source to the flash object * Adaptive source handlers will have more complicated workflows before passing * video data to the video element - * @param {Object} source The source object - * @param {Flash} tech The instance of the Flash tech + * @param {Object} source The source object + * @param {Flash} tech The instance of the Flash tech + * @param {Object} options The options to pass to the source */ - Flash.rtmpSourceHandler.handleSource = function (source, tech) { + Flash.rtmpSourceHandler.handleSource = function (source, tech, options) { var srcParts = Flash.streamToParts(source.src); tech['setRtmpConnection'](srcParts.connection); @@ -13250,7 +14049,7 @@ function FlashRtmpDecorator(Flash) { exports['default'] = FlashRtmpDecorator; module.exports = exports['default']; -},{}],116:[function(_dereq_,module,exports){ +},{}],121:[function(_dereq_,module,exports){ /** * @file flash.js * VideoJS-SWF - Custom Flash Player with HTML5-ish API @@ -13621,7 +14420,7 @@ var Flash = (function (_Tech) { var _api = Flash.prototype; var _readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(','); -var _readOnly = 'networkState,readyState,initialTime,duration,startOffsetTime,paused,ended,videoTracks,audioTracks,videoWidth,videoHeight'.split(','); +var _readOnly = 'networkState,readyState,initialTime,duration,startOffsetTime,paused,ended,videoWidth,videoHeight'.split(','); function _createSetter(attr) { var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1); @@ -13710,10 +14509,11 @@ Flash.nativeSourceHandler.canHandleSource = function (source) { * Adaptive source handlers will have more complicated workflows before passing * video data to the video element * - * @param {Object} source The source object - * @param {Flash} tech The instance of the Flash tech + * @param {Object} source The source object + * @param {Flash} tech The instance of the Flash tech + * @param {Object} options The options to pass to the source */ -Flash.nativeSourceHandler.handleSource = function (source, tech) { +Flash.nativeSourceHandler.handleSource = function (source, tech, options) { tech.setSrc(source.src); }; @@ -13865,7 +14665,7 @@ _tech2['default'].registerTech('Flash', Flash); exports['default'] = Flash; module.exports = exports['default']; -},{"../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){ +},{"../component":67,"../utils/dom.js":143,"../utils/time-ranges.js":151,"../utils/url.js":153,"./flash-rtmp":120,"./tech":124,"global/window":2,"object.assign":45}],122:[function(_dereq_,module,exports){ /** * @file html5.js * HTML5 Media Controller - Wrapper for HTML5 Media API @@ -13875,6 +14675,8 @@ module.exports = exports['default']; exports.__esModule = true; +var _templateObject = _taggedTemplateLiteralLoose(['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used. \n This may prevent text tracks from loading.'], ['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used. \n This may prevent text tracks from loading.']); + 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; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } @@ -13883,6 +14685,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons 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; } +function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; } + var _techJs = _dereq_('./tech.js'); var _techJs2 = _interopRequireDefault(_techJs); @@ -13907,6 +14711,14 @@ var _utilsLogJs = _dereq_('../utils/log.js'); var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); +var _tsml = _dereq_('tsml'); + +var _tsml2 = _interopRequireDefault(_tsml); + +var _srcJsTracksTextTrackJs = _dereq_('../../../src/js/tracks/text-track.js'); + +var _srcJsTracksTextTrackJs2 = _interopRequireDefault(_srcJsTracksTextTrackJs); + var _utilsBrowserJs = _dereq_('../utils/browser.js'); var browser = _interopRequireWildcard(_utilsBrowserJs); @@ -13927,6 +14739,10 @@ var _utilsMergeOptionsJs = _dereq_('../utils/merge-options.js'); var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); +var _utilsToTitleCaseJs = _dereq_('../utils/to-title-case.js'); + +var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); + /** * HTML5 Media Controller - Wrapper for HTML5 Media API * @@ -13940,11 +14756,14 @@ var Html5 = (function (_Tech) { _inherits(Html5, _Tech); function Html5(options, ready) { + var _this = this; + _classCallCheck(this, Html5); _Tech.call(this, options, ready); var source = options.source; + var crossoriginTracks = false; // Set the source if one is provided // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted) @@ -13977,6 +14796,9 @@ var Html5 = (function (_Tech) { // store HTMLTrackElement and TextTrack to remote list this.remoteTextTrackEls().addTrackElement_(node); this.remoteTextTracks().addTrack_(node.track); + if (!crossoriginTracks && !this.el_.hasAttribute('crossorigin') && Url.isCrossOrigin(node.src)) { + crossoriginTracks = true; + } } } } @@ -13986,7 +14808,29 @@ var Html5 = (function (_Tech) { } } + var trackTypes = ['audio', 'video']; + + // ProxyNativeTextTracks + trackTypes.forEach(function (type) { + var capitalType = _utilsToTitleCaseJs2['default'](type); + + if (!_this['featuresNative' + capitalType + 'Tracks']) { + return; + } + var tl = _this.el()[type + 'Tracks']; + + if (tl && tl.addEventListener) { + tl.addEventListener('change', Fn.bind(_this, _this['handle' + capitalType + 'TrackChange_'])); + tl.addEventListener('addtrack', Fn.bind(_this, _this['handle' + capitalType + 'TrackAdd_'])); + tl.addEventListener('removetrack', Fn.bind(_this, _this['handle' + capitalType + 'TrackRemove_'])); + } + }); + if (this.featuresNativeTextTracks) { + if (crossoriginTracks) { + _utilsLogJs2['default'].warn(_tsml2['default'](_templateObject)); + } + this.handleTextTrackChange_ = Fn.bind(this, this.handleTextTrackChange); this.handleTextTrackAdd_ = Fn.bind(this, this.handleTextTrackAdd); this.handleTextTrackRemove_ = Fn.bind(this, this.handleTextTrackRemove); @@ -14021,24 +14865,22 @@ var Html5 = (function (_Tech) { */ Html5.prototype.dispose = function dispose() { - var tt = this.el().textTracks; - var emulatedTt = this.textTracks(); - - // remove native event listeners - if (tt && tt.removeEventListener) { - tt.removeEventListener('change', this.handleTextTrackChange_); - tt.removeEventListener('addtrack', this.handleTextTrackAdd_); - tt.removeEventListener('removetrack', this.handleTextTrackRemove_); - } + var _this2 = this; - // clearout the emulated text track list. - var i = emulatedTt.length; + // Un-ProxyNativeTracks + ['audio', 'video', 'text'].forEach(function (type) { + var capitalType = _utilsToTitleCaseJs2['default'](type); + var tl = _this2.el_[type + 'Tracks']; - while (i--) { - emulatedTt.removeTrack_(emulatedTt[i]); - } + if (tl && tl.removeEventListener) { + tl.removeEventListener('change', _this2['handle' + capitalType + 'TrackChange_']); + tl.removeEventListener('addtrack', _this2['handle' + capitalType + 'TrackAdd_']); + tl.removeEventListener('removetrack', _this2['handle' + capitalType + 'TrackRemove_']); + } + }); Html5.disposeMediaElement(this.el_); + // tech will handle clearing of the emulated track list _Tech.prototype.dispose.call(this); }; @@ -14101,7 +14943,7 @@ var Html5 = (function (_Tech) { // rely on it. Html5.prototype.handleLateInit_ = function handleLateInit_(el) { - var _this = this; + var _this3 = this; if (el.networkState === 0 || el.networkState === 3) { // The video element hasn't started loading the source yet @@ -14125,7 +14967,7 @@ var Html5 = (function (_Tech) { var setLoadstartFired = function setLoadstartFired() { loadstartFired = true; }; - _this.on('loadstart', setLoadstartFired); + _this3.on('loadstart', setLoadstartFired); var triggerLoadstart = function triggerLoadstart() { // We did miss the original loadstart. Make sure the player @@ -14134,9 +14976,9 @@ var Html5 = (function (_Tech) { this.trigger('loadstart'); } }; - _this.on('loadedmetadata', triggerLoadstart); + _this3.on('loadedmetadata', triggerLoadstart); - _this.ready(function () { + _this3.ready(function () { this.off('loadstart', setLoadstartFired); this.off('loadedmetadata', triggerLoadstart); @@ -14222,6 +15064,42 @@ var Html5 = (function (_Tech) { this.textTracks().removeTrack_(e.track); }; + Html5.prototype.handleVideoTrackChange_ = function handleVideoTrackChange_(e) { + var vt = this.videoTracks(); + this.videoTracks().trigger({ + type: 'change', + target: vt, + currentTarget: vt, + srcElement: vt + }); + }; + + Html5.prototype.handleVideoTrackAdd_ = function handleVideoTrackAdd_(e) { + this.videoTracks().addTrack_(e.track); + }; + + Html5.prototype.handleVideoTrackRemove_ = function handleVideoTrackRemove_(e) { + this.videoTracks().removeTrack_(e.track); + }; + + Html5.prototype.handleAudioTrackChange_ = function handleAudioTrackChange_(e) { + var audioTrackList = this.audioTracks(); + this.audioTracks().trigger({ + type: 'change', + target: audioTrackList, + currentTarget: audioTrackList, + srcElement: audioTrackList + }); + }; + + Html5.prototype.handleAudioTrackAdd_ = function handleAudioTrackAdd_(e) { + this.audioTracks().addTrack_(e.track); + }; + + Html5.prototype.handleAudioTrackRemove_ = function handleAudioTrackRemove_(e) { + this.audioTracks().removeTrack_(e.track); + }; + /** * Play for html5 tech * @@ -14944,10 +15822,11 @@ Html5.nativeSourceHandler.canHandleSource = function (source) { * Adaptive source handlers will have more complicated workflows before passing * video data to the video element * - * @param {Object} source The source object - * @param {Html5} tech The instance of the Html5 tech + * @param {Object} source The source object + * @param {Html5} tech The instance of the Html5 tech + * @param {Object} options The options to pass to the source */ -Html5.nativeSourceHandler.handleSource = function (source, tech) { +Html5.nativeSourceHandler.handleSource = function (source, tech, options) { tech.setSrc(source.src); }; @@ -14976,9 +15855,14 @@ Html5.canControlVolume = function () { /* * Check if playbackRate is supported in this browser/device. * - * @return {Number} [description] + * @return {Boolean} */ Html5.canControlPlaybackRate = function () { + // Playback rate API is implemented in Android Chrome, but doesn't do anything + // https://github.com/videojs/video.js/issues/3180 + if (browser.IS_ANDROID && browser.IS_CHROME) { + return false; + } var playbackRate = Html5.TEST_VID.playbackRate; Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1; return playbackRate !== Html5.TEST_VID.playbackRate; @@ -15011,6 +15895,26 @@ Html5.supportsNativeTextTracks = function () { return supportsTextTracks; }; +/* + * Check to see if native video tracks are supported by this browser/device + * + * @return {Boolean} + */ +Html5.supportsNativeVideoTracks = function () { + var supportsVideoTracks = !!Html5.TEST_VID.videoTracks; + return supportsVideoTracks; +}; + +/* + * Check to see if native audio tracks are supported by this browser/device + * + * @return {Boolean} + */ +Html5.supportsNativeAudioTracks = function () { + var supportsAudioTracks = !!Html5.TEST_VID.audioTracks; + return supportsAudioTracks; +}; + /** * An array of events available on the Html5 tech. * @@ -15061,6 +15965,20 @@ Html5.prototype['featuresProgressEvents'] = true; */ Html5.prototype['featuresNativeTextTracks'] = Html5.supportsNativeTextTracks(); +/** + * Sets the tech's status on native text track support + * + * @type {Boolean} + */ +Html5.prototype['featuresNativeVideoTracks'] = Html5.supportsNativeVideoTracks(); + +/** + * Sets the tech's status on native audio track support + * + * @type {Boolean} + */ +Html5.prototype['featuresNativeAudioTracks'] = Html5.supportsNativeAudioTracks(); + // HTML5 Feature detection and Device Fixes --------------------------------- // var canPlayType = undefined; var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; @@ -15168,7 +16086,7 @@ _techJs2['default'].registerTech('Html5', Html5); exports['default'] = Html5; module.exports = exports['default']; -},{"../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){ +},{"../../../src/js/tracks/text-track.js":134,"../component":67,"../utils/browser.js":140,"../utils/dom.js":143,"../utils/fn.js":145,"../utils/log.js":148,"../utils/merge-options.js":149,"../utils/to-title-case.js":152,"../utils/url.js":153,"./tech.js":124,"global/document":1,"global/window":2,"object.assign":45,"tsml":55}],123:[function(_dereq_,module,exports){ /** * @file loader.js */ @@ -15252,7 +16170,7 @@ _componentJs2['default'].registerComponent('MediaLoader', MediaLoader); exports['default'] = MediaLoader; module.exports = exports['default']; -},{"../component.js":67,"../utils/to-title-case.js":141,"./tech.js":119,"global/window":2}],119:[function(_dereq_,module,exports){ +},{"../component.js":67,"../utils/to-title-case.js":152,"./tech.js":124,"global/window":2}],124:[function(_dereq_,module,exports){ /** * @file tech.js * Media Technology Controller - Base class for media playback @@ -15295,6 +16213,22 @@ var _tracksTextTrackList = _dereq_('../tracks/text-track-list'); var _tracksTextTrackList2 = _interopRequireDefault(_tracksTextTrackList); +var _tracksVideoTrack = _dereq_('../tracks/video-track'); + +var _tracksVideoTrack2 = _interopRequireDefault(_tracksVideoTrack); + +var _tracksVideoTrackList = _dereq_('../tracks/video-track-list'); + +var _tracksVideoTrackList2 = _interopRequireDefault(_tracksVideoTrackList); + +var _tracksAudioTrackList = _dereq_('../tracks/audio-track-list'); + +var _tracksAudioTrackList2 = _interopRequireDefault(_tracksAudioTrackList); + +var _tracksAudioTrack = _dereq_('../tracks/audio-track'); + +var _tracksAudioTrack2 = _interopRequireDefault(_tracksAudioTrack); + var _utilsFnJs = _dereq_('../utils/fn.js'); var Fn = _interopRequireWildcard(_utilsFnJs); @@ -15353,6 +16287,8 @@ var Tech = (function (_Component) { }); this.textTracks_ = options.textTracks; + this.videoTracks_ = options.videoTracks; + this.audioTracks_ = options.audioTracks; // Manually track progress in cases where the browser/flash player doesn't report it. if (!this.featuresProgressEvents) { @@ -15373,15 +16309,16 @@ var Tech = (function (_Component) { } this.initTextTrackListeners(); + this.initTrackListeners(); // Turn on component tap events this.emitTapEvents(); } - /* + /** * List of associated text tracks * - * @type {Array} + * @type {TextTrackList} * @private */ @@ -15547,15 +16484,9 @@ var Tech = (function (_Component) { */ Tech.prototype.dispose = function dispose() { - // clear out text tracks because we can't reuse them between techs - var textTracks = this.textTracks(); - if (textTracks) { - var i = textTracks.length; - while (i--) { - this.removeRemoteTextTrack(textTracks[i]); - } - } + // clear out all tracks because we can't reuse them between techs + this.clearTracks(['audio', 'video', 'text']); // Turn off any manual progress or timeupdate tracking if (this.manualProgress) { @@ -15569,6 +16500,36 @@ var Tech = (function (_Component) { _Component.prototype.dispose.call(this); }; + /** + * clear out a track list, or multiple track lists + * + * Note: Techs without source handlers should call this between + * sources for video & audio tracks, as usually you don't want + * to use them between tracks and we have no automatic way to do + * it for you + * + * @method clearTracks + * @param {Array|String} types type(s) of track lists to empty + */ + + Tech.prototype.clearTracks = function clearTracks(types) { + var _this = this; + + types = [].concat(types); + // clear out all tracks because we can't reuse them between techs + types.forEach(function (type) { + var list = _this[type + 'Tracks']() || []; + var i = list.length; + while (i--) { + var track = list[i]; + if (type === 'text') { + _this.removeRemoteTextTrack(track); + } + list.removeTrack_(track); + } + }); + }; + /** * Reset the tech. Removes all sources and resets readyState. * @@ -15653,6 +16614,34 @@ var Tech = (function (_Component) { })); }; + /** + * Initialize audio and video track listeners + * + * @method initTrackListeners + */ + + Tech.prototype.initTrackListeners = function initTrackListeners() { + var _this2 = this; + + var trackTypes = ['video', 'audio']; + + trackTypes.forEach(function (type) { + var trackListChanges = function trackListChanges() { + _this2.trigger(type + 'trackchange'); + }; + + var tracks = _this2[type + 'Tracks'](); + + tracks.addEventListener('removetrack', trackListChanges); + tracks.addEventListener('addtrack', trackListChanges); + + _this2.on('dispose', function () { + tracks.removeEventListener('removetrack', trackListChanges); + tracks.removeEventListener('addtrack', trackListChanges); + }); + }); + }; + /** * Emulate texttracks * @@ -15660,7 +16649,7 @@ var Tech = (function (_Component) { */ Tech.prototype.emulateTextTracks = function emulateTextTracks() { - var _this = this; + var _this3 = this; var tracks = this.textTracks(); if (!tracks) { @@ -15670,24 +16659,26 @@ var Tech = (function (_Component) { if (!_globalWindow2['default']['WebVTT'] && this.el().parentNode != null) { (function () { var script = _globalDocument2['default'].createElement('script'); - script.src = _this.options_['vtt.js'] || 'https://cdn.rawgit.com/gkatsev/vtt.js/vjs-v0.12.1/dist/vtt.min.js'; + script.src = _this3.options_['vtt.js'] || 'https://cdn.rawgit.com/gkatsev/vtt.js/vjs-v0.12.1/dist/vtt.min.js'; script.onload = function () { - _this.trigger('vttjsloaded'); + _this3.trigger('vttjsloaded'); }; script.onerror = function () { - _this.trigger('vttjserror'); + _this3.trigger('vttjserror'); }; - _this.on('dispose', function () { + _this3.on('dispose', function () { script.onload = null; script.onerror = null; }); - _this.el().parentNode.appendChild(script); + // but have not loaded yet and we set it to true before the inject so that + // we don't overwrite the injected window.WebVTT if it loads right away _globalWindow2['default']['WebVTT'] = true; + _this3.el().parentNode.appendChild(script); })(); } var updateDisplay = function updateDisplay() { - return _this.trigger('texttrackchange'); + return _this3.trigger('texttrackchange'); }; var textTracksChanges = function textTracksChanges() { updateDisplay(); @@ -15709,6 +16700,30 @@ var Tech = (function (_Component) { }); }; + /** + * Get videotracks + * + * @returns {VideoTrackList} + * @method videoTracks + */ + + Tech.prototype.videoTracks = function videoTracks() { + this.videoTracks_ = this.videoTracks_ || new _tracksVideoTrackList2['default'](); + return this.videoTracks_; + }; + + /** + * Get audiotracklist + * + * @returns {AudioTrackList} + * @method audioTracks + */ + + Tech.prototype.audioTracks = function audioTracks() { + this.audioTracks_ = this.audioTracks_ || new _tracksAudioTrackList2['default'](); + return this.audioTracks_; + }; + /* * Provide default methods for text tracks. * @@ -15896,6 +16911,22 @@ var Tech = (function (_Component) { Tech.prototype.textTracks_; +/** + * List of associated audio tracks + * + * @type {AudioTrackList} + * @private + */ +Tech.prototype.audioTracks_; + +/** + * List of associated video tracks + * + * @type {VideoTrackList} + * @private + */ +Tech.prototype.videoTracks_; + var createTrackHelper = function createTrackHelper(self, kind, label, language) { var options = arguments.length <= 4 || arguments[4] === undefined ? {} : arguments[4]; @@ -16064,18 +17095,49 @@ Tech.withSourceHandlers = function (_Tech) { this.disposeSourceHandler(); this.off('dispose', this.disposeSourceHandler); - this.currentSource_ = source; - this.sourceHandler_ = sh.handleSource(source, this); + // if we have a source and get another one + // then we are loading something new + // than clear all of our current tracks + if (this.currentSource_) { + this.clearTracks(['audio', 'video']); + } + + if (sh !== _Tech.nativeSourceHandler) { + + this.currentSource_ = source; + + // Catch if someone replaced the src without calling setSource. + // If they do, set currentSource_ to null and dispose our source handler. + this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_); + this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); + this.one(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_); + } + + this.sourceHandler_ = sh.handleSource(source, this, this.options_); this.on('dispose', this.disposeSourceHandler); return this; }; + // On the first loadstart after setSource + _Tech.prototype.firstLoadStartListener_ = function () { + this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); + }; + + // On successive loadstarts when setSource has not been called again + _Tech.prototype.successiveLoadStartListener_ = function () { + this.currentSource_ = null; + this.disposeSourceHandler(); + this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); + }; + /* * Clean up any existing source handler */ _Tech.prototype.disposeSourceHandler = function () { if (this.sourceHandler_ && this.sourceHandler_.dispose) { + this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_); + this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); this.sourceHandler_.dispose(); } }; @@ -16088,21 +17150,26 @@ Tech.registerTech('Tech', Tech); exports['default'] = Tech; module.exports = exports['default']; -},{"../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){ +},{"../component":67,"../media-error.js":108,"../tracks/audio-track":126,"../tracks/audio-track-list":125,"../tracks/html-track-element":128,"../tracks/html-track-element-list":127,"../tracks/text-track":134,"../tracks/text-track-list":132,"../tracks/video-track":139,"../tracks/video-track-list":138,"../utils/buffer.js":141,"../utils/fn.js":145,"../utils/log.js":148,"../utils/merge-options.js":149,"../utils/time-ranges.js":151,"global/document":1,"global/window":2}],125:[function(_dereq_,module,exports){ /** - * @file html-track-element-list.js + * @file audio-track-list.js */ - 'use strict'; exports.__esModule = true; -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - 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; } } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } +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; } + +var _trackList = _dereq_('./track-list'); + +var _trackList2 = _interopRequireDefault(_trackList); + var _utilsBrowserJs = _dereq_('../utils/browser.js'); var browser = _interopRequireWildcard(_utilsBrowserJs); @@ -16111,11 +17178,250 @@ var _globalDocument = _dereq_('global/document'); var _globalDocument2 = _interopRequireDefault(_globalDocument); -var HtmlTrackElementList = (function () { - function HtmlTrackElementList() { - var trackElements = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; +/** + * anywhere we call this function we diverge from the spec + * as we only support one enabled audiotrack at a time + * + * @param {Array|AudioTrackList} list list to work on + * @param {AudioTrack} track the track to skip + */ +var disableOthers = function disableOthers(list, track) { + for (var i = 0; i < list.length; i++) { + if (track.id === list[i].id) { + continue; + } + // another audio track is enabled, disable it + list[i].enabled = false; + } +}; +/** + * A list of possible audio tracks. All functionality is in the + * base class Tracklist and the spec for AudioTrackList is located at: + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist + * + * interface AudioTrackList : EventTarget { + * readonly attribute unsigned long length; + * getter AudioTrack (unsigned long index); + * AudioTrack? getTrackById(DOMString id); + * + * attribute EventHandler onchange; + * attribute EventHandler onaddtrack; + * attribute EventHandler onremovetrack; + * }; + * + * @param {AudioTrack[]} tracks a list of audio tracks to instantiate the list with + * @extends TrackList + * @class AudioTrackList + */ - _classCallCheck(this, HtmlTrackElementList); +var AudioTrackList = (function (_TrackList) { + _inherits(AudioTrackList, _TrackList); + + function AudioTrackList() { + var tracks = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; + + _classCallCheck(this, AudioTrackList); + + var list = undefined; + + // make sure only 1 track is enabled + // sorted from last index to first index + for (var i = tracks.length - 1; i >= 0; i--) { + if (tracks[i].enabled) { + disableOthers(tracks, tracks[i]); + break; + } + } + + // IE8 forces us to implement inheritance ourselves + // as it does not support Object.defineProperty properly + if (browser.IS_IE8) { + list = _globalDocument2['default'].createElement('custom'); + for (var prop in _trackList2['default'].prototype) { + if (prop !== 'constructor') { + list[prop] = _trackList2['default'].prototype[prop]; + } + } + for (var prop in AudioTrackList.prototype) { + if (prop !== 'constructor') { + list[prop] = AudioTrackList.prototype[prop]; + } + } + } + + list = _TrackList.call(this, tracks, list); + list.changing_ = false; + + return list; + } + + AudioTrackList.prototype.addTrack_ = function addTrack_(track) { + var _this = this; + + if (track.enabled) { + disableOthers(this, track); + } + + _TrackList.prototype.addTrack_.call(this, track); + // native tracks don't have this + if (!track.addEventListener) { + return; + } + + track.addEventListener('enabledchange', function () { + // when we are disabling other tracks (since we don't support + // more than one track at a time) we will set changing_ + // to true so that we don't trigger additional change events + if (_this.changing_) { + return; + } + _this.changing_ = true; + disableOthers(_this, track); + _this.changing_ = false; + _this.trigger('change'); + }); + }; + + AudioTrackList.prototype.addTrack = function addTrack(track) { + this.addTrack_(track); + }; + + AudioTrackList.prototype.removeTrack = function removeTrack(track) { + _TrackList.prototype.removeTrack_.call(this, track); + }; + + return AudioTrackList; +})(_trackList2['default']); + +exports['default'] = AudioTrackList; +module.exports = exports['default']; + +},{"../utils/browser.js":140,"./track-list":136,"global/document":1}],126:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _trackEnums = _dereq_('./track-enums'); + +var _track = _dereq_('./track'); + +var _track2 = _interopRequireDefault(_track); + +var _utilsMergeOptions = _dereq_('../utils/merge-options'); + +var _utilsMergeOptions2 = _interopRequireDefault(_utilsMergeOptions); + +var _utilsBrowserJs = _dereq_('../utils/browser.js'); + +var browser = _interopRequireWildcard(_utilsBrowserJs); + +/** + * A single audio text track as defined in: + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack + * + * interface AudioTrack { + * readonly attribute DOMString id; + * readonly attribute DOMString kind; + * readonly attribute DOMString label; + * readonly attribute DOMString language; + * attribute boolean enabled; + * }; + * + * @param {Object=} options Object of option names and values + * @class AudioTrack + */ + +var AudioTrack = (function (_Track) { + _inherits(AudioTrack, _Track); + + function AudioTrack() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + _classCallCheck(this, AudioTrack); + + var settings = _utilsMergeOptions2['default'](options, { + kind: _trackEnums.AudioTrackKind[options.kind] || '' + }); + // on IE8 this will be a document element + // for every other browser this will be a normal object + var track = _Track.call(this, settings); + var enabled = false; + + if (browser.IS_IE8) { + for (var prop in AudioTrack.prototype) { + if (prop !== 'constructor') { + track[prop] = AudioTrack.prototype[prop]; + } + } + } + + Object.defineProperty(track, 'enabled', { + get: function get() { + return enabled; + }, + set: function set(newEnabled) { + // an invalid or unchanged value + if (typeof newEnabled !== 'boolean' || newEnabled === enabled) { + return; + } + enabled = newEnabled; + this.trigger('enabledchange'); + } + }); + + // if the user sets this track to selected then + // set selected to that true value otherwise + // we keep it false + if (settings.enabled) { + track.enabled = settings.enabled; + } + track.loaded_ = true; + + return track; + } + + return AudioTrack; +})(_track2['default']); + +exports['default'] = AudioTrack; +module.exports = exports['default']; + +},{"../utils/browser.js":140,"../utils/merge-options":149,"./track":137,"./track-enums":135}],127:[function(_dereq_,module,exports){ +/** + * @file html-track-element-list.js + */ + +'use strict'; + +exports.__esModule = true; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +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; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var _utilsBrowserJs = _dereq_('../utils/browser.js'); + +var browser = _interopRequireWildcard(_utilsBrowserJs); + +var _globalDocument = _dereq_('global/document'); + +var _globalDocument2 = _interopRequireDefault(_globalDocument); + +var HtmlTrackElementList = (function () { + function HtmlTrackElementList() { + var trackElements = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; + + _classCallCheck(this, HtmlTrackElementList); var list = this; @@ -16180,7 +17486,7 @@ var HtmlTrackElementList = (function () { exports['default'] = HtmlTrackElementList; module.exports = exports['default']; -},{"../utils/browser.js":129,"global/document":1}],121:[function(_dereq_,module,exports){ +},{"../utils/browser.js":140,"global/document":1}],128:[function(_dereq_,module,exports){ /** * @file html-track-element.js */ @@ -16315,7 +17621,7 @@ HTMLTrackElement.ERROR = ERROR; exports['default'] = HTMLTrackElement; module.exports = exports['default']; -},{"../event-target":99,"../tracks/text-track":128,"../utils/browser.js":129,"global/document":1}],122:[function(_dereq_,module,exports){ +},{"../event-target":104,"../tracks/text-track":134,"../utils/browser.js":140,"global/document":1}],129:[function(_dereq_,module,exports){ /** * @file text-track-cue-list.js */ @@ -16444,7 +17750,7 @@ var TextTrackCueList = (function () { exports['default'] = TextTrackCueList; module.exports = exports['default']; -},{"../utils/browser.js":129,"global/document":1}],123:[function(_dereq_,module,exports){ +},{"../utils/browser.js":140,"global/document":1}],130:[function(_dereq_,module,exports){ /** * @file text-track-display.js */ @@ -16541,6 +17847,34 @@ var TextTrackDisplay = (function (_Component) { var track = tracks[i]; this.player_.addRemoteTextTrack(track); } + + var modes = { 'captions': 1, 'subtitles': 1 }; + var trackList = this.player_.textTracks(); + var firstDesc = undefined; + var firstCaptions = undefined; + + if (trackList) { + for (var i = 0; i < trackList.length; i++) { + var track = trackList[i]; + if (track['default']) { + if (track.kind === 'descriptions' && !firstDesc) { + firstDesc = track; + } else if (track.kind in modes && !firstCaptions) { + firstCaptions = track; + } + } + } + + // We want to show the first default track but captions and subtitles + // take precedence over descriptions. + // So, display the first default captions or subtitles track + // and otherwise the first default descriptions track. + if (firstCaptions) { + firstCaptions.mode = 'showing'; + } else if (firstDesc) { + firstDesc.mode = 'showing'; + } + } })); } @@ -16577,6 +17911,9 @@ var TextTrackDisplay = (function (_Component) { TextTrackDisplay.prototype.createEl = function createEl() { return _Component.prototype.createEl.call(this, 'div', { className: 'vjs-text-track-display' + }, { + 'aria-live': 'assertive', + 'aria-atomic': 'true' }); }; @@ -16607,12 +17944,30 @@ var TextTrackDisplay = (function (_Component) { return; } - for (var i = 0; i < tracks.length; i++) { + // Track display prioritization model: if multiple tracks are 'showing', + // display the first 'subtitles' or 'captions' track which is 'showing', + // otherwise display the first 'descriptions' track which is 'showing' + + var descriptionsTrack = null; + var captionsSubtitlesTrack = null; + + var i = tracks.length; + while (i--) { var track = tracks[i]; if (track['mode'] === 'showing') { - this.updateForTrack(track); + if (track['kind'] === 'descriptions') { + descriptionsTrack = track; + } else { + captionsSubtitlesTrack = track; + } } } + + if (captionsSubtitlesTrack) { + this.updateForTrack(captionsSubtitlesTrack); + } else if (descriptionsTrack) { + this.updateForTrack(descriptionsTrack); + } }; /** @@ -16634,7 +17989,7 @@ var TextTrackDisplay = (function (_Component) { cues.push(track['activeCues'][_i]); } - _globalWindow2['default']['WebVTT']['processCues'](_globalWindow2['default'], track['activeCues'], this.el_); + _globalWindow2['default']['WebVTT']['processCues'](_globalWindow2['default'], cues, this.el_); var i = cues.length; while (i--) { @@ -16720,53 +18075,7 @@ _component2['default'].registerComponent('TextTrackDisplay', TextTrackDisplay); exports['default'] = TextTrackDisplay; module.exports = exports['default']; -},{"../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){ -/** - * @file text-track-enums.js - */ - -/** - * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode - * - * enum TextTrackMode { "disabled", "hidden", "showing" }; - */ -'use strict'; - -exports.__esModule = true; -var TextTrackMode = { - disabled: 'disabled', - hidden: 'hidden', - showing: 'showing' -}; - -/** - * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackkind - * - * enum TextTrackKind { - * "subtitles", - * "captions", - * "descriptions", - * "chapters", - * "metadata" - * }; - */ -var TextTrackKind = { - subtitles: 'subtitles', - captions: 'captions', - descriptions: 'descriptions', - chapters: 'chapters', - metadata: 'metadata' -}; - -/* jshint ignore:start */ -// we ignore jshint here because it does not see -// TextTrackMode or TextTrackKind as defined here somehow... -exports.TextTrackMode = TextTrackMode; -exports.TextTrackKind = TextTrackKind; - -/* jshint ignore:end */ - -},{}],125:[function(_dereq_,module,exports){ +},{"../component":67,"../menu/menu-button.js":109,"../menu/menu-item.js":110,"../menu/menu.js":111,"../utils/fn.js":145,"global/document":1,"global/window":2}],131:[function(_dereq_,module,exports){ /** * Utilities for capturing text track state and re-creating tracks * based on a capture. @@ -16857,7 +18166,7 @@ var jsonToTextTracks = function jsonToTextTracks(json, tech) { exports['default'] = { textTracksToJson: textTracksToJson, jsonToTextTracks: jsonToTextTracks, trackToJson_: trackToJson_ }; module.exports = exports['default']; -},{}],126:[function(_dereq_,module,exports){ +},{}],132:[function(_dereq_,module,exports){ /** * @file text-track-list.js */ @@ -16873,9 +18182,9 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons 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; } -var _eventTarget = _dereq_('../event-target'); +var _trackList = _dereq_('./track-list'); -var _eventTarget2 = _interopRequireDefault(_eventTarget); +var _trackList2 = _interopRequireDefault(_trackList); var _utilsFnJs = _dereq_('../utils/fn.js'); @@ -16890,8 +18199,9 @@ var _globalDocument = _dereq_('global/document'); var _globalDocument2 = _interopRequireDefault(_globalDocument); /** - * A text track list as defined in: - * https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist + * A list of possible text tracks. All functionality is in the + * base class TrackList. The spec for TextTrackList is located at: + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist * * interface TextTrackList : EventTarget { * readonly attribute unsigned long length; @@ -16903,25 +18213,30 @@ var _globalDocument2 = _interopRequireDefault(_globalDocument); * attribute EventHandler onremovetrack; * }; * - * @param {Track[]} tracks A list of tracks to initialize the list with - * @extends EventTarget + * @param {TextTrack[]} tracks A list of tracks to initialize the list with + * @extends TrackList * @class TextTrackList */ -var TextTrackList = (function (_EventTarget) { - _inherits(TextTrackList, _EventTarget); +var TextTrackList = (function (_TrackList) { + _inherits(TextTrackList, _TrackList); function TextTrackList() { var tracks = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; _classCallCheck(this, TextTrackList); - _EventTarget.call(this); - var list = this; + var list = undefined; + // IE8 forces us to implement inheritance ourselves + // as it does not support Object.defineProperty properly if (browser.IS_IE8) { list = _globalDocument2['default'].createElement('custom'); - + for (var prop in _trackList2['default'].prototype) { + if (prop !== 'constructor') { + list[prop] = _trackList2['default'].prototype[prop]; + } + } for (var prop in TextTrackList.prototype) { if (prop !== 'constructor') { list[prop] = TextTrackList.prototype[prop]; @@ -16929,60 +18244,15 @@ var TextTrackList = (function (_EventTarget) { } } - list.tracks_ = []; - - Object.defineProperty(list, 'length', { - get: function get() { - return this.tracks_.length; - } - }); - - for (var i = 0; i < tracks.length; i++) { - list.addTrack_(tracks[i]); - } - - if (browser.IS_IE8) { - return list; - } + list = _TrackList.call(this, tracks, list); + return list; } - /** - * change - One or more tracks in the track list have been enabled or disabled. - * addtrack - A track has been added to the track list. - * removetrack - A track has been removed from the track list. - */ - - /** - * Add TextTrack from TextTrackList - * - * @param {TextTrack} track - * @method addTrack_ - * @private - */ - TextTrackList.prototype.addTrack_ = function addTrack_(track) { - var index = this.tracks_.length; - - if (!('' + index in this)) { - Object.defineProperty(this, index, { - get: function get() { - return this.tracks_[index]; - } - }); - } - + _TrackList.prototype.addTrack_.call(this, track); track.addEventListener('modechange', Fn.bind(this, function () { this.trigger('change'); })); - - // Do not add duplicate tracks - if (this.tracks_.indexOf(track) === -1) { - this.tracks_.push(track); - this.trigger({ - track: track, - type: 'addtrack' - }); - } }; /** @@ -17045,23 +18315,12 @@ var TextTrackList = (function (_EventTarget) { }; return TextTrackList; -})(_eventTarget2['default']); - -TextTrackList.prototype.allowedEvents_ = { - change: 'change', - addtrack: 'addtrack', - removetrack: 'removetrack' -}; - -// emulate attribute EventHandler support to allow for feature detection -for (var _event in TextTrackList.prototype.allowedEvents_) { - TextTrackList.prototype['on' + _event] = null; -} +})(_trackList2['default']); exports['default'] = TextTrackList; module.exports = exports['default']; -},{"../event-target":99,"../utils/browser.js":129,"../utils/fn.js":134,"global/document":1}],127:[function(_dereq_,module,exports){ +},{"../utils/browser.js":140,"../utils/fn.js":145,"./track-list":136,"global/document":1}],133:[function(_dereq_,module,exports){ /** * @file text-track-settings.js */ @@ -17358,7 +18617,7 @@ function captionOptionsMenuTemplate() { exports['default'] = TextTrackSettings; module.exports = exports['default']; -},{"../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){ +},{"../component":67,"../utils/events.js":144,"../utils/fn.js":145,"../utils/log.js":148,"global/window":2,"safe-json-parse/tuple":54}],134:[function(_dereq_,module,exports){ /** * @file text-track.js */ @@ -17382,27 +18641,13 @@ var _utilsFnJs = _dereq_('../utils/fn.js'); var Fn = _interopRequireWildcard(_utilsFnJs); -var _utilsGuidJs = _dereq_('../utils/guid.js'); +var _trackEnums = _dereq_('./track-enums'); -var Guid = _interopRequireWildcard(_utilsGuidJs); +var _utilsLogJs = _dereq_('../utils/log.js'); -var _utilsBrowserJs = _dereq_('../utils/browser.js'); +var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); -var browser = _interopRequireWildcard(_utilsBrowserJs); - -var _textTrackEnums = _dereq_('./text-track-enums'); - -var TextTrackEnum = _interopRequireWildcard(_textTrackEnums); - -var _utilsLogJs = _dereq_('../utils/log.js'); - -var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); - -var _eventTarget = _dereq_('../event-target'); - -var _eventTarget2 = _interopRequireDefault(_eventTarget); - -var _globalDocument = _dereq_('global/document'); +var _globalDocument = _dereq_('global/document'); var _globalDocument2 = _interopRequireDefault(_globalDocument); @@ -17410,12 +18655,24 @@ var _globalWindow = _dereq_('global/window'); var _globalWindow2 = _interopRequireDefault(_globalWindow); +var _trackJs = _dereq_('./track.js'); + +var _trackJs2 = _interopRequireDefault(_trackJs); + var _utilsUrlJs = _dereq_('../utils/url.js'); var _xhr = _dereq_('xhr'); var _xhr2 = _interopRequireDefault(_xhr); +var _utilsMergeOptions = _dereq_('../utils/merge-options'); + +var _utilsMergeOptions2 = _interopRequireDefault(_utilsMergeOptions); + +var _utilsBrowserJs = _dereq_('../utils/browser.js'); + +var browser = _interopRequireWildcard(_utilsBrowserJs); + /** * takes a webvtt file contents and parses it into cues * @@ -17424,13 +18681,14 @@ var _xhr2 = _interopRequireDefault(_xhr); */ var parseCues = function parseCues(srcContent, track) { var parser = new _globalWindow2['default'].WebVTT.Parser(_globalWindow2['default'], _globalWindow2['default'].vttjs, _globalWindow2['default'].WebVTT.StringDecoder()); + var errors = []; parser.oncue = function (cue) { track.addCue(cue); }; parser.onparsingerror = function (error) { - _utilsLogJs2['default'].error(error); + errors.push(error); }; parser.onflush = function () { @@ -17441,6 +18699,18 @@ var parseCues = function parseCues(srcContent, track) { }; parser.parse(srcContent); + if (errors.length > 0) { + if (console.groupCollapsed) { + console.groupCollapsed('Text Track parsing errors for ' + track.src); + } + errors.forEach(function (error) { + return _utilsLogJs2['default'].error(error); + }); + if (console.groupEnd) { + console.groupEnd(); + } + } + parser.flush(); }; @@ -17485,264 +18755,861 @@ var loadTrack = function loadTrack(src, track) { } else { parseCues(responseBody, track); } - })); + })); +}; + +/** + * A single text track as defined in: + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack + * + * interface TextTrack : EventTarget { + * readonly attribute TextTrackKind kind; + * readonly attribute DOMString label; + * readonly attribute DOMString language; + * + * readonly attribute DOMString id; + * readonly attribute DOMString inBandMetadataTrackDispatchType; + * + * attribute TextTrackMode mode; + * + * readonly attribute TextTrackCueList? cues; + * readonly attribute TextTrackCueList? activeCues; + * + * void addCue(TextTrackCue cue); + * void removeCue(TextTrackCue cue); + * + * attribute EventHandler oncuechange; + * }; + * + * @param {Object=} options Object of option names and values + * @extends Track + * @class TextTrack + */ + +var TextTrack = (function (_Track) { + _inherits(TextTrack, _Track); + + function TextTrack() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + _classCallCheck(this, TextTrack); + + if (!options.tech) { + throw new Error('A tech was not provided.'); + } + + var settings = _utilsMergeOptions2['default'](options, { + kind: _trackEnums.TextTrackKind[options.kind] || 'subtitles', + language: options.language || options.srclang || '' + }); + var mode = _trackEnums.TextTrackMode[settings.mode] || 'disabled'; + var default_ = settings['default']; + + if (settings.kind === 'metadata' || settings.kind === 'chapters') { + mode = 'hidden'; + } + // on IE8 this will be a document element + // for every other browser this will be a normal object + var tt = _Track.call(this, settings); + tt.tech_ = settings.tech; + + if (browser.IS_IE8) { + for (var prop in TextTrack.prototype) { + if (prop !== 'constructor') { + tt[prop] = TextTrack.prototype[prop]; + } + } + } + + tt.cues_ = []; + tt.activeCues_ = []; + + var cues = new _textTrackCueList2['default'](tt.cues_); + var activeCues = new _textTrackCueList2['default'](tt.activeCues_); + var changed = false; + var timeupdateHandler = Fn.bind(tt, function () { + this.activeCues; + if (changed) { + this.trigger('cuechange'); + changed = false; + } + }); + + if (mode !== 'disabled') { + tt.tech_.on('timeupdate', timeupdateHandler); + } + + Object.defineProperty(tt, 'default', { + get: function get() { + return default_; + }, + set: function set() {} + }); + + Object.defineProperty(tt, 'mode', { + get: function get() { + return mode; + }, + set: function set(newMode) { + if (!_trackEnums.TextTrackMode[newMode]) { + return; + } + mode = newMode; + if (mode === 'showing') { + this.tech_.on('timeupdate', timeupdateHandler); + } + this.trigger('modechange'); + } + }); + + Object.defineProperty(tt, 'cues', { + get: function get() { + if (!this.loaded_) { + return null; + } + + return cues; + }, + set: function set() {} + }); + + Object.defineProperty(tt, 'activeCues', { + get: function get() { + if (!this.loaded_) { + return null; + } + + // nothing to do + if (this.cues.length === 0) { + return activeCues; + } + + var ct = this.tech_.currentTime(); + var active = []; + + for (var i = 0, l = this.cues.length; i < l; i++) { + var cue = this.cues[i]; + + if (cue.startTime <= ct && cue.endTime >= ct) { + active.push(cue); + } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) { + active.push(cue); + } + } + + changed = false; + + if (active.length !== this.activeCues_.length) { + changed = true; + } else { + for (var i = 0; i < active.length; i++) { + if (this.activeCues_.indexOf(active[i]) === -1) { + changed = true; + } + } + } + + this.activeCues_ = active; + activeCues.setCues_(this.activeCues_); + + return activeCues; + }, + set: function set() {} + }); + + if (settings.src) { + tt.src = settings.src; + loadTrack(settings.src, tt); + } else { + tt.loaded_ = true; + } + + return tt; + } + + /** + * cuechange - One or more cues in the track have become active or stopped being active. + */ + + /** + * add a cue to the internal list of cues + * + * @param {Object} cue the cue to add to our internal list + * @method addCue + */ + + TextTrack.prototype.addCue = function addCue(cue) { + var tracks = this.tech_.textTracks(); + + if (tracks) { + for (var i = 0; i < tracks.length; i++) { + if (tracks[i] !== this) { + tracks[i].removeCue(cue); + } + } + } + + this.cues_.push(cue); + this.cues.setCues_(this.cues_); + }; + + /** + * remvoe a cue from our internal list + * + * @param {Object} removeCue the cue to remove from our internal list + * @method removeCue + */ + + TextTrack.prototype.removeCue = function removeCue(_removeCue) { + var removed = false; + + for (var i = 0, l = this.cues_.length; i < l; i++) { + var cue = this.cues_[i]; + + if (cue === _removeCue) { + this.cues_.splice(i, 1); + removed = true; + } + } + + if (removed) { + this.cues.setCues_(this.cues_); + } + }; + + return TextTrack; +})(_trackJs2['default']); + +TextTrack.prototype.allowedEvents_ = { + cuechange: 'cuechange' +}; + +exports['default'] = TextTrack; +module.exports = exports['default']; + +},{"../utils/browser.js":140,"../utils/fn.js":145,"../utils/log.js":148,"../utils/merge-options":149,"../utils/url.js":153,"./text-track-cue-list":129,"./track-enums":135,"./track.js":137,"global/document":1,"global/window":2,"xhr":56}],135:[function(_dereq_,module,exports){ +/** + * @file track-kinds.js + */ + +/** + * https://html.spec.whatwg.org/multipage/embedded-content.html#dom-videotrack-kind + * + * enum VideoTrackKind { + * "alternative", + * "captions", + * "main", + * "sign", + * "subtitles", + * "commentary", + * "", + * }; + */ +'use strict'; + +exports.__esModule = true; +var VideoTrackKind = { + alternative: 'alternative', + captions: 'captions', + main: 'main', + sign: 'sign', + subtitles: 'subtitles', + commentary: 'commentary' +}; + +/** + * https://html.spec.whatwg.org/multipage/embedded-content.html#dom-audiotrack-kind + * + * enum AudioTrackKind { + * "alternative", + * "descriptions", + * "main", + * "main-desc", + * "translation", + * "commentary", + * "", + * }; + */ +var AudioTrackKind = { + alternative: 'alternative', + descriptions: 'descriptions', + main: 'main', + 'main-desc': 'main-desc', + translation: 'translation', + commentary: 'commentary' +}; + +/** + * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackkind + * + * enum TextTrackKind { + * "subtitles", + * "captions", + * "descriptions", + * "chapters", + * "metadata" + * }; + */ +var TextTrackKind = { + subtitles: 'subtitles', + captions: 'captions', + descriptions: 'descriptions', + chapters: 'chapters', + metadata: 'metadata' +}; + +/** + * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode + * + * enum TextTrackMode { "disabled", "hidden", "showing" }; + */ +var TextTrackMode = { + disabled: 'disabled', + hidden: 'hidden', + showing: 'showing' +}; + +/* jshint ignore:start */ +// we ignore jshint here because it does not see +// AudioTrackKind as defined here +exports['default'] = { VideoTrackKind: VideoTrackKind, AudioTrackKind: AudioTrackKind, TextTrackKind: TextTrackKind, TextTrackMode: TextTrackMode }; + +/* jshint ignore:end */ +module.exports = exports['default']; + +},{}],136:[function(_dereq_,module,exports){ +/** + * @file track-list.js + */ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _eventTarget = _dereq_('../event-target'); + +var _eventTarget2 = _interopRequireDefault(_eventTarget); + +var _utilsFnJs = _dereq_('../utils/fn.js'); + +var Fn = _interopRequireWildcard(_utilsFnJs); + +var _utilsBrowserJs = _dereq_('../utils/browser.js'); + +var browser = _interopRequireWildcard(_utilsBrowserJs); + +var _globalDocument = _dereq_('global/document'); + +var _globalDocument2 = _interopRequireDefault(_globalDocument); + +/** + * Common functionaliy between Text, Audio, and Video TrackLists + * Interfaces defined in the following spec: + * @link https://html.spec.whatwg.org/multipage/embedded-content.html + * + * @param {Track[]} tracks A list of tracks to initialize the list with + * @param {Object} list the child object with inheritance done manually for ie8 + * @extends EventTarget + * @class TrackList + */ + +var TrackList = (function (_EventTarget) { + _inherits(TrackList, _EventTarget); + + function TrackList() { + var tracks = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; + var list = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; + + _classCallCheck(this, TrackList); + + _EventTarget.call(this); + if (!list) { + list = this; + if (browser.IS_IE8) { + list = _globalDocument2['default'].createElement('custom'); + for (var prop in TrackList.prototype) { + if (prop !== 'constructor') { + list[prop] = TrackList.prototype[prop]; + } + } + } + } + + list.tracks_ = []; + Object.defineProperty(list, 'length', { + get: function get() { + return this.tracks_.length; + } + }); + + for (var i = 0; i < tracks.length; i++) { + list.addTrack_(tracks[i]); + } + + return list; + } + + /** + * change - One or more tracks in the track list have been enabled or disabled. + * addtrack - A track has been added to the track list. + * removetrack - A track has been removed from the track list. + */ + + /** + * Add a Track from TrackList + * + * @param {Mixed} track + * @method addTrack_ + * @private + */ + + TrackList.prototype.addTrack_ = function addTrack_(track) { + var index = this.tracks_.length; + + if (!('' + index in this)) { + Object.defineProperty(this, index, { + get: function get() { + return this.tracks_[index]; + } + }); + } + + // Do not add duplicate tracks + if (this.tracks_.indexOf(track) === -1) { + this.tracks_.push(track); + this.trigger({ + track: track, + type: 'addtrack' + }); + } + }; + + /** + * Remove a Track from TrackList + * + * @param {Track} rtrack track to be removed + * @method removeTrack_ + * @private + */ + + TrackList.prototype.removeTrack_ = function removeTrack_(rtrack) { + var track = undefined; + + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === rtrack) { + track = this[i]; + if (track.off) { + track.off(); + } + + this.tracks_.splice(i, 1); + + break; + } + } + + if (!track) { + return; + } + + this.trigger({ + track: track, + type: 'removetrack' + }); + }; + + /** + * Get a Track from the TrackList by a tracks id + * + * @param {String} id - the id of the track to get + * @method getTrackById + * @return {Track} + * @private + */ + + TrackList.prototype.getTrackById = function getTrackById(id) { + var result = null; + + for (var i = 0, l = this.length; i < l; i++) { + var track = this[i]; + if (track.id === id) { + result = track; + break; + } + } + + return result; + }; + + return TrackList; +})(_eventTarget2['default']); + +TrackList.prototype.allowedEvents_ = { + change: 'change', + addtrack: 'addtrack', + removetrack: 'removetrack' +}; + +// emulate attribute EventHandler support to allow for feature detection +for (var _event in TrackList.prototype.allowedEvents_) { + TrackList.prototype['on' + _event] = null; +} + +exports['default'] = TrackList; +module.exports = exports['default']; + +},{"../event-target":104,"../utils/browser.js":140,"../utils/fn.js":145,"global/document":1}],137:[function(_dereq_,module,exports){ +/** + * @file track.js + */ +'use strict'; + +exports.__esModule = true; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +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; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _utilsBrowserJs = _dereq_('../utils/browser.js'); + +var browser = _interopRequireWildcard(_utilsBrowserJs); + +var _globalDocument = _dereq_('global/document'); + +var _globalDocument2 = _interopRequireDefault(_globalDocument); + +var _utilsGuidJs = _dereq_('../utils/guid.js'); + +var Guid = _interopRequireWildcard(_utilsGuidJs); + +var _eventTarget = _dereq_('../event-target'); + +var _eventTarget2 = _interopRequireDefault(_eventTarget); + +/** + * setup the common parts of an audio, video, or text track + * @link https://html.spec.whatwg.org/multipage/embedded-content.html + * + * @param {String} type The type of track we are dealing with audio|video|text + * @param {Object=} options Object of option names and values + * @extends EventTarget + * @class Track + */ + +var Track = (function (_EventTarget) { + _inherits(Track, _EventTarget); + + function Track() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + _classCallCheck(this, Track); + + _EventTarget.call(this); + + var track = this; + if (browser.IS_IE8) { + track = _globalDocument2['default'].createElement('custom'); + for (var prop in Track.prototype) { + if (prop !== 'constructor') { + track[prop] = Track.prototype[prop]; + } + } + } + + var trackProps = { + id: options.id || 'vjs_track_' + Guid.newGUID(), + kind: options.kind || '', + label: options.label || '', + language: options.language || '' + }; + + var _loop = function (key) { + Object.defineProperty(track, key, { + get: function get() { + return trackProps[key]; + }, + set: function set() {} + }); + }; + + for (var key in trackProps) { + _loop(key); + } + + return track; + } + + return Track; +})(_eventTarget2['default']); + +exports['default'] = Track; +module.exports = exports['default']; + +},{"../event-target":104,"../utils/browser.js":140,"../utils/guid.js":147,"global/document":1}],138:[function(_dereq_,module,exports){ +/** + * @file video-track-list.js + */ +'use strict'; + +exports.__esModule = true; + +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; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +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; } + +var _trackList = _dereq_('./track-list'); + +var _trackList2 = _interopRequireDefault(_trackList); + +var _utilsBrowserJs = _dereq_('../utils/browser.js'); + +var browser = _interopRequireWildcard(_utilsBrowserJs); + +var _globalDocument = _dereq_('global/document'); + +var _globalDocument2 = _interopRequireDefault(_globalDocument); + +/** + * disable other video tracks before selecting the new one + * + * @param {Array|VideoTrackList} list list to work on + * @param {VideoTrack} track the track to skip + */ +var disableOthers = function disableOthers(list, track) { + for (var i = 0; i < list.length; i++) { + if (track.id === list[i].id) { + continue; + } + // another audio track is enabled, disable it + list[i].selected = false; + } }; /** - * A single text track as defined in: - * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack - * - * interface TextTrack : EventTarget { - * readonly attribute TextTrackKind kind; - * readonly attribute DOMString label; - * readonly attribute DOMString language; +* A list of possiblee video tracks. Most functionality is in the + * base class Tracklist and the spec for VideoTrackList is located at: + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist * - * readonly attribute DOMString id; - * readonly attribute DOMString inBandMetadataTrackDispatchType; - * - * attribute TextTrackMode mode; - * - * readonly attribute TextTrackCueList? cues; - * readonly attribute TextTrackCueList? activeCues; - * - * void addCue(TextTrackCue cue); - * void removeCue(TextTrackCue cue); + * interface VideoTrackList : EventTarget { + * readonly attribute unsigned long length; + * getter VideoTrack (unsigned long index); + * VideoTrack? getTrackById(DOMString id); + * readonly attribute long selectedIndex; * - * attribute EventHandler oncuechange; + * attribute EventHandler onchange; + * attribute EventHandler onaddtrack; + * attribute EventHandler onremovetrack; * }; * - * @param {Object=} options Object of option names and values - * @extends EventTarget - * @class TextTrack + * @param {VideoTrack[]} tracks a list of video tracks to instantiate the list with + # @extends TrackList + * @class VideoTrackList */ -var TextTrack = (function (_EventTarget) { - _inherits(TextTrack, _EventTarget); +var VideoTrackList = (function (_TrackList) { + _inherits(VideoTrackList, _TrackList); - function TextTrack() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + function VideoTrackList() { + var tracks = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; - _classCallCheck(this, TextTrack); + _classCallCheck(this, VideoTrackList); - _EventTarget.call(this); - if (!options.tech) { - throw new Error('A tech was not provided.'); - } + var list = undefined; - var tt = this; + // make sure only 1 track is enabled + // sorted from last index to first index + for (var i = tracks.length - 1; i >= 0; i--) { + if (tracks[i].selected) { + disableOthers(tracks, tracks[i]); + break; + } + } + // IE8 forces us to implement inheritance ourselves + // as it does not support Object.defineProperty properly if (browser.IS_IE8) { - tt = _globalDocument2['default'].createElement('custom'); - - for (var prop in TextTrack.prototype) { + list = _globalDocument2['default'].createElement('custom'); + for (var prop in _trackList2['default'].prototype) { if (prop !== 'constructor') { - tt[prop] = TextTrack.prototype[prop]; + list[prop] = _trackList2['default'].prototype[prop]; } } - } - - tt.tech_ = options.tech; - - var mode = TextTrackEnum.TextTrackMode[options.mode] || 'disabled'; - var kind = TextTrackEnum.TextTrackKind[options.kind] || 'subtitles'; - var label = options.label || ''; - var language = options.language || options.srclang || ''; - var id = options.id || 'vjs_text_track_' + Guid.newGUID(); - - if (kind === 'metadata' || kind === 'chapters') { - mode = 'hidden'; - } - - tt.cues_ = []; - tt.activeCues_ = []; - - var cues = new _textTrackCueList2['default'](tt.cues_); - var activeCues = new _textTrackCueList2['default'](tt.activeCues_); - var changed = false; - var timeupdateHandler = Fn.bind(tt, function () { - this.activeCues; - if (changed) { - this.trigger('cuechange'); - changed = false; + for (var prop in VideoTrackList.prototype) { + if (prop !== 'constructor') { + list[prop] = VideoTrackList.prototype[prop]; + } } - }); - - if (mode !== 'disabled') { - tt.tech_.on('timeupdate', timeupdateHandler); } - Object.defineProperty(tt, 'kind', { - get: function get() { - return kind; - }, - set: function set() {} - }); + list = _TrackList.call(this, tracks, list); + list.changing_ = false; - Object.defineProperty(tt, 'label', { + Object.defineProperty(list, 'selectedIndex', { get: function get() { - return label; + for (var i = 0; i < this.length; i++) { + if (this[i].selected) { + return i; + } + } + return -1; }, set: function set() {} }); - Object.defineProperty(tt, 'language', { - get: function get() { - return language; - }, - set: function set() {} - }); + return list; + } - Object.defineProperty(tt, 'id', { - get: function get() { - return id; - }, - set: function set() {} - }); + VideoTrackList.prototype.addTrack_ = function addTrack_(track) { + var _this = this; - Object.defineProperty(tt, 'mode', { - get: function get() { - return mode; - }, - set: function set(newMode) { - if (!TextTrackEnum.TextTrackMode[newMode]) { - return; - } - mode = newMode; - if (mode === 'showing') { - this.tech_.on('timeupdate', timeupdateHandler); - } - this.trigger('modechange'); + if (track.selected) { + disableOthers(this, track); + } + + _TrackList.prototype.addTrack_.call(this, track); + // native tracks don't have this + if (!track.addEventListener) { + return; + } + track.addEventListener('selectedchange', function () { + if (_this.changing_) { + return; } + _this.changing_ = true; + disableOthers(_this, track); + _this.changing_ = false; + _this.trigger('change'); }); + }; - Object.defineProperty(tt, 'cues', { - get: function get() { - if (!this.loaded_) { - return null; - } + VideoTrackList.prototype.addTrack = function addTrack(track) { + this.addTrack_(track); + }; - return cues; - }, - set: function set() {} - }); + VideoTrackList.prototype.removeTrack = function removeTrack(track) { + _TrackList.prototype.removeTrack_.call(this, track); + }; - Object.defineProperty(tt, 'activeCues', { - get: function get() { - if (!this.loaded_) { - return null; - } + return VideoTrackList; +})(_trackList2['default']); - // nothing to do - if (this.cues.length === 0) { - return activeCues; - } +exports['default'] = VideoTrackList; +module.exports = exports['default']; - var ct = this.tech_.currentTime(); - var active = []; +},{"../utils/browser.js":140,"./track-list":136,"global/document":1}],139:[function(_dereq_,module,exports){ +'use strict'; - for (var i = 0, l = this.cues.length; i < l; i++) { - var cue = this.cues[i]; +exports.__esModule = true; - if (cue.startTime <= ct && cue.endTime >= ct) { - active.push(cue); - } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) { - active.push(cue); - } - } +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; } } - changed = false; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - if (active.length !== this.activeCues_.length) { - changed = true; - } else { - for (var i = 0; i < active.length; i++) { - if (this.activeCues_.indexOf(active[i]) === -1) { - changed = true; - } - } - } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - this.activeCues_ = active; - activeCues.setCues_(this.activeCues_); +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; } - return activeCues; - }, - set: function set() {} - }); +var _trackEnums = _dereq_('./track-enums'); - if (options.src) { - tt.src = options.src; - loadTrack(options.src, tt); - } else { - tt.loaded_ = true; - } +var _track = _dereq_('./track'); - if (browser.IS_IE8) { - return tt; - } - } +var _track2 = _interopRequireDefault(_track); - /** - * cuechange - One or more cues in the track have become active or stopped being active. - */ +var _utilsMergeOptions = _dereq_('../utils/merge-options'); - /** - * add a cue to the internal list of cues - * - * @param {Object} cue the cue to add to our internal list - * @method addCue - */ +var _utilsMergeOptions2 = _interopRequireDefault(_utilsMergeOptions); - TextTrack.prototype.addCue = function addCue(cue) { - var tracks = this.tech_.textTracks(); +var _utilsBrowserJs = _dereq_('../utils/browser.js'); - if (tracks) { - for (var i = 0; i < tracks.length; i++) { - if (tracks[i] !== this) { - tracks[i].removeCue(cue); - } - } - } +var browser = _interopRequireWildcard(_utilsBrowserJs); - this.cues_.push(cue); - this.cues.setCues_(this.cues_); - }; +/** + * A single video text track as defined in: + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack + * + * interface VideoTrack { + * readonly attribute DOMString id; + * readonly attribute DOMString kind; + * readonly attribute DOMString label; + * readonly attribute DOMString language; + * attribute boolean selected; + * }; + * + * @param {Object=} options Object of option names and values + * @class VideoTrack + */ - /** - * remvoe a cue from our internal list - * - * @param {Object} removeCue the cue to remove from our internal list - * @method removeCue - */ +var VideoTrack = (function (_Track) { + _inherits(VideoTrack, _Track); - TextTrack.prototype.removeCue = function removeCue(_removeCue) { - var removed = false; + function VideoTrack() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - for (var i = 0, l = this.cues_.length; i < l; i++) { - var cue = this.cues_[i]; + _classCallCheck(this, VideoTrack); - if (cue === _removeCue) { - this.cues_.splice(i, 1); - removed = true; + var settings = _utilsMergeOptions2['default'](options, { + kind: _trackEnums.VideoTrackKind[options.kind] || '' + }); + + // on IE8 this will be a document element + // for every other browser this will be a normal object + var track = _Track.call(this, settings); + var selected = false; + + if (browser.IS_IE8) { + for (var prop in VideoTrack.prototype) { + if (prop !== 'constructor') { + track[prop] = VideoTrack.prototype[prop]; + } } } - if (removed) { - this.cues.setCues_(this.cues_); + Object.defineProperty(track, 'selected', { + get: function get() { + return selected; + }, + set: function set(newSelected) { + // an invalid or unchanged value + if (typeof newSelected !== 'boolean' || newSelected === selected) { + return; + } + selected = newSelected; + this.trigger('selectedchange'); + } + }); + + // if the user sets this track to selected then + // set selected to that true value otherwise + // we keep it false + if (settings.selected) { + track.selected = settings.selected; } - }; - return TextTrack; -})(_eventTarget2['default']); + return track; + } -TextTrack.prototype.allowedEvents_ = { - cuechange: 'cuechange' -}; + return VideoTrack; +})(_track2['default']); -exports['default'] = TextTrack; +exports['default'] = VideoTrack; module.exports = exports['default']; -},{"../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){ +},{"../utils/browser.js":140,"../utils/merge-options":149,"./track":137,"./track-enums":135}],140:[function(_dereq_,module,exports){ /** * @file browser.js */ @@ -17825,7 +19692,9 @@ var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion exports.IS_NATIVE_ANDROID = IS_NATIVE_ANDROID; var IS_FIREFOX = /Firefox/i.test(USER_AGENT); exports.IS_FIREFOX = IS_FIREFOX; -var IS_CHROME = /Chrome/i.test(USER_AGENT); +var IS_EDGE = /Edge/i.test(USER_AGENT); +exports.IS_EDGE = IS_EDGE; +var IS_CHROME = !IS_EDGE && /Chrome/i.test(USER_AGENT); exports.IS_CHROME = IS_CHROME; var IS_IE8 = /MSIE\s8\.0/.test(USER_AGENT); @@ -17835,7 +19704,7 @@ exports.TOUCH_ENABLED = TOUCH_ENABLED; var BACKGROUND_SIZE_SUPPORTED = ('backgroundSize' in _globalDocument2['default'].createElement('video').style); exports.BACKGROUND_SIZE_SUPPORTED = BACKGROUND_SIZE_SUPPORTED; -},{"global/document":1,"global/window":2}],130:[function(_dereq_,module,exports){ +},{"global/document":1,"global/window":2}],141:[function(_dereq_,module,exports){ /** * @file buffer.js */ @@ -17884,7 +19753,7 @@ function bufferedPercent(buffered, duration) { return bufferedDuration / duration; } -},{"./time-ranges.js":140}],131:[function(_dereq_,module,exports){ +},{"./time-ranges.js":151}],142:[function(_dereq_,module,exports){ 'use strict'; exports.__esModule = true; @@ -17955,7 +19824,7 @@ exports['default'] = function (target) { module.exports = exports['default']; -},{"./log.js":137}],132:[function(_dereq_,module,exports){ +},{"./log.js":148}],143:[function(_dereq_,module,exports){ /** * @file dom.js */ @@ -18685,7 +20554,7 @@ exports.$ = $; var $$ = createQuerier('querySelectorAll'); exports.$$ = $$; -},{"./guid.js":136,"./log.js":137,"global/document":1,"global/window":2,"tsml":55}],133:[function(_dereq_,module,exports){ +},{"./guid.js":147,"./log.js":148,"global/document":1,"global/window":2,"tsml":55}],144:[function(_dereq_,module,exports){ /** * @file events.js * @@ -19093,7 +20962,7 @@ function _handleMultipleEvents(fn, elem, types, callback) { }); } -},{"./dom.js":132,"./guid.js":136,"global/document":1,"global/window":2}],134:[function(_dereq_,module,exports){ +},{"./dom.js":143,"./guid.js":147,"global/document":1,"global/window":2}],145:[function(_dereq_,module,exports){ /** * @file fn.js */ @@ -19137,7 +21006,7 @@ var bind = function bind(context, fn, uid) { }; exports.bind = bind; -},{"./guid.js":136}],135:[function(_dereq_,module,exports){ +},{"./guid.js":147}],146:[function(_dereq_,module,exports){ /** * @file format-time.js * @@ -19188,7 +21057,7 @@ function formatTime(seconds) { exports['default'] = formatTime; module.exports = exports['default']; -},{}],136:[function(_dereq_,module,exports){ +},{}],147:[function(_dereq_,module,exports){ /** * @file guid.js * @@ -19213,7 +21082,7 @@ function newGUID() { return _guid++; } -},{}],137:[function(_dereq_,module,exports){ +},{}],148:[function(_dereq_,module,exports){ /** * @file log.js */ @@ -19303,7 +21172,7 @@ function _logType(type, args) { exports['default'] = log; module.exports = exports['default']; -},{"global/window":2}],138:[function(_dereq_,module,exports){ +},{"global/window":2}],149:[function(_dereq_,module,exports){ /** * @file merge-options.js */ @@ -19374,7 +21243,7 @@ function mergeOptions() { module.exports = exports['default']; -},{"lodash-compat/object/merge":40}],139:[function(_dereq_,module,exports){ +},{"lodash-compat/object/merge":40}],150:[function(_dereq_,module,exports){ 'use strict'; exports.__esModule = true; @@ -19402,7 +21271,7 @@ var setTextContent = function setTextContent(el, content) { }; exports.setTextContent = setTextContent; -},{"global/document":1}],140:[function(_dereq_,module,exports){ +},{"global/document":1}],151:[function(_dereq_,module,exports){ 'use strict'; exports.__esModule = true; @@ -19473,7 +21342,7 @@ function rangeCheck(fnName, index, maxIndex) { } } -},{"./log.js":137}],141:[function(_dereq_,module,exports){ +},{"./log.js":148}],152:[function(_dereq_,module,exports){ /** * @file to-title-case.js * @@ -19494,7 +21363,7 @@ function toTitleCase(string) { exports["default"] = toTitleCase; module.exports = exports["default"]; -},{}],142:[function(_dereq_,module,exports){ +},{}],153:[function(_dereq_,module,exports){ /** * @file url.js */ @@ -19630,7 +21499,7 @@ var isCrossOrigin = function isCrossOrigin(url) { }; exports.isCrossOrigin = isCrossOrigin; -},{"global/document":1,"global/window":2}],143:[function(_dereq_,module,exports){ +},{"global/document":1,"global/window":2}],154:[function(_dereq_,module,exports){ /** * @file video.js */ @@ -19642,6 +21511,10 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } +var _globalWindow = _dereq_('global/window'); + +var _globalWindow2 = _interopRequireDefault(_globalWindow); + var _globalDocument = _dereq_('global/document'); var _globalDocument2 = _interopRequireDefault(_globalDocument); @@ -19686,6 +21559,14 @@ var _tracksTextTrackJs = _dereq_('./tracks/text-track.js'); var _tracksTextTrackJs2 = _interopRequireDefault(_tracksTextTrackJs); +var _tracksAudioTrackJs = _dereq_('./tracks/audio-track.js'); + +var _tracksAudioTrackJs2 = _interopRequireDefault(_tracksAudioTrackJs); + +var _tracksVideoTrackJs = _dereq_('./tracks/video-track.js'); + +var _tracksVideoTrackJs2 = _interopRequireDefault(_tracksVideoTrackJs); + var _objectAssign = _dereq_('object.assign'); var _objectAssign2 = _interopRequireDefault(_objectAssign); @@ -19820,7 +21701,7 @@ setup.autoSetupTimeout(1, videojs); * * @type {String} */ -videojs.VERSION = '5.8.8'; +videojs.VERSION = '5.10.1'; /** * The global options object. These are the settings that take effect @@ -20242,6 +22123,22 @@ videojs.xhr = _xhr2['default']; */ videojs.TextTrack = _tracksTextTrackJs2['default']; +/** + * export the AudioTrack class so that source handlers can create + * AudioTracks and then add them to the players AudioTrackList + * + * @type {Function} + */ +videojs.AudioTrack = _tracksAudioTrackJs2['default']; + +/** + * export the VideoTrack class so that source handlers can create + * VideoTracks and then add them to the players VideoTrackList + * + * @type {Function} + */ +videojs.VideoTrack = _tracksVideoTrackJs2['default']; + /** * Determines, via duck typing, whether or not a value is a DOM element. * @@ -20417,7 +22314,7 @@ if (typeof define === 'function' && define['amd']) { exports['default'] = videojs; module.exports = exports['default']; -},{"../../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) +},{"../../src/js/utils/merge-options.js":149,"./component":67,"./event-target":104,"./extend.js":105,"./player":113,"./plugins.js":114,"./setup":118,"./tech/flash.js":121,"./tech/html5.js":122,"./tech/tech.js":124,"./tracks/audio-track.js":126,"./tracks/text-track.js":134,"./tracks/video-track.js":139,"./utils/browser.js":140,"./utils/create-deprecation-proxy.js":142,"./utils/dom.js":143,"./utils/events.js":144,"./utils/fn.js":145,"./utils/format-time.js":146,"./utils/log.js":148,"./utils/stylesheet.js":150,"./utils/time-ranges.js":151,"./utils/url.js":153,"global/document":1,"global/window":2,"lodash-compat/object/merge":40,"object.assign":45,"xhr":56}]},{},[154])(154) });