Comparar commits

..

7 Commits

Autor SHA1 Mensagem Data
Gary Katsevman d482e278d8 remove broken test as there's no need to duplicate it 2017-10-18 15:14:34 -04:00
Gary Katsevman 803777227b prettify separator comment 2017-10-17 15:51:02 -04:00
Gary Katsevman 30fa4813c6 copy our regular embed tests into div embed tests 2017-10-17 15:42:45 -04:00
Gary Katsevman c82b615f01 data-setup with divs as well 2017-10-12 17:51:21 -04:00
Gary Katsevman 0bc2a4d4d5 add an embeds page 2017-10-12 17:48:23 -04:00
Gary Katsevman d59769821d remove debugger statement 2017-10-02 23:08:10 -07:00
Gary Katsevman 2d01479fb5 WIP initial div embed PR 2017-10-02 18:46:33 -04:00
17 arquivos alterados com 512 adições e 546 exclusões
-37
Ver Arquivo
@@ -1,40 +1,3 @@
<a name="6.3.1"></a>
## [6.3.1](https://github.com/videojs/video.js/compare/v6.3.0...v6.3.1) (2017-10-03)
### Bug Fixes
* Make sure time displays use correctly-formatted time. ([#4643](https://github.com/videojs/video.js/issues/4643)) ([20f7fe9](https://github.com/videojs/video.js/commit/20f7fe9))
<a name="6.3.0"></a>
# [6.3.0](https://github.com/videojs/video.js/compare/v6.2.8...v6.3.0) (2017-10-03)
### Features
* Add remainingTimeDisplay method to Player ([#4620](https://github.com/videojs/video.js/issues/4620)) ([445eb26](https://github.com/videojs/video.js/commit/445eb26))
* display currentTime as duration and remainingTime as 0 on ended ([#4634](https://github.com/videojs/video.js/issues/4634)) ([f51d36b](https://github.com/videojs/video.js/commit/f51d36b))
* Do not set focus in sub-menus to prevent undesirable scrolling behavior in iOS ([#4607](https://github.com/videojs/video.js/issues/4607)) ([1ac8065](https://github.com/videojs/video.js/commit/1ac8065))
### Bug Fixes
* reset to a play/pause button when seeking after ended ([#4614](https://github.com/videojs/video.js/issues/4614)) ([335bcde](https://github.com/videojs/video.js/commit/335bcde))
### Chores
* alias rollup-dev to watch for development ([#4615](https://github.com/videojs/video.js/issues/4615)) ([edde614](https://github.com/videojs/video.js/commit/edde614))
* **lang:** Update Dutch ([#4588](https://github.com/videojs/video.js/issues/4588)) ([5ca0992](https://github.com/videojs/video.js/commit/5ca0992))
* **lang:** Update Vietnamese ([#4625](https://github.com/videojs/video.js/issues/4625)) ([ac58dbf](https://github.com/videojs/video.js/commit/ac58dbf))
* **package:** update grunt-browserify to version 5.2.0 ([#4578](https://github.com/videojs/video.js/issues/4578)) ([6cd785a](https://github.com/videojs/video.js/commit/6cd785a))
* **package:** update remark-validate-links to version 7.0.0 ([#4585](https://github.com/videojs/video.js/issues/4585)) ([7929677](https://github.com/videojs/video.js/commit/7929677))
### Code Refactoring
* Create a base time display class, and use it ([#4633](https://github.com/videojs/video.js/issues/4633)) ([fa6f884](https://github.com/videojs/video.js/commit/fa6f884))
### Documentation
* Document playbackRates ([#4602](https://github.com/videojs/video.js/issues/4602)) ([9d249bb](https://github.com/videojs/video.js/commit/9d249bb))
* update player reference in advanced plugins doc ([#4622](https://github.com/videojs/video.js/issues/4622)) ([d8ea23e](https://github.com/videojs/video.js/commit/d8ea23e))
<a name="6.2.8"></a>
## [6.2.8](https://github.com/videojs/video.js/compare/v6.2.7...v6.2.8) (2017-09-01)
+21 -68
Ver Arquivo
@@ -1,84 +1,37 @@
{
"Audio Player": "Audiospeler",
"Video Player": "Videospeler",
"Play": "Afspelen",
"Pause": "Pauzeren",
"Replay": "Opnieuw afspelen",
"Pause": "Pauze",
"Current Time": "Huidige tijd",
"Duration Time": "Tijdsduur",
"Duration Time": "Looptijd",
"Remaining Time": "Resterende tijd",
"Stream Type": "Streamtype",
"LIVE": "LIVE",
"Loaded": "Geladen",
"Progress": "Voortgang",
"Progress Bar": "Voortgangsbalk",
"progress bar timing: currentTime={1} duration={2}": "{1} van {2}",
"Progress": "Status",
"Fullscreen": "Volledig scherm",
"Non-Fullscreen": "Geen volledig scherm",
"Mute": "Dempen",
"Unmute": "Niet dempen",
"Playback Rate": "Afspeelsnelheid",
"Mute": "Geluid uit",
"Unmute": "Geluid aan",
"Playback Rate": "Weergavesnelheid",
"Subtitles": "Ondertiteling",
"subtitles off": "ondertiteling uit",
"Captions": "Bijschriften",
"captions off": "bijschriften uit",
"Chapters": "Hoofdstukken",
"Descriptions": "Beschrijvingen",
"descriptions off": "beschrijvingen uit",
"Audio Track": "Audiospoor",
"Volume Level": "Geluidsniveau",
"You aborted the media playback": "U heeft het afspelen van de media afgebroken",
"A network error caused the media download to fail part-way.": "Een netwerkfout heeft ervoor gezorgd dat het downloaden van de media halverwege is mislukt.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "De media kon niet worden geladen, dit komt doordat of de server of het netwerk mislukt of doordat het formaat niet wordt ondersteund.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Het afspelen van de media is afgebroken door een probleem met beschadeigde gegevens of doordat de media functies gebruikt die uw browser niet ondersteund.",
"No compatible source was found for this media.": "Er is geen geschikte bron voor deze media gevonden.",
"The media is encrypted and we do not have the keys to decrypt it.": "De media is versleuteld en we hebben de sleutels niet om deze te ontsleutelen.",
"Play Video": "Video afspelen",
"descriptions off": "beschrijvingen off",
"You aborted the media playback": "U hebt de mediaweergave afgebroken.",
"A network error caused the media download to fail part-way.": "De mediadownload is mislukt door een netwerkfout.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "De media kon niet worden geladen, vanwege een server- of netwerkfout of doordat het formaat niet wordt ondersteund.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "De mediaweergave is afgebroken vanwege beschadigde data of het mediabestand gebruikt functies die niet door uw browser worden ondersteund.",
"No compatible source was found for this media.": "Voor deze media is geen ondersteunde bron gevonden.",
"Play Video": "Video Afspelen",
"Close": "Sluiten",
"Close Modal Dialog": "Extra venster sluiten",
"Modal Window": "Extra venster",
"This is a modal window": "Dit is een extra venster",
"This modal can be closed by pressing the Escape key or activating the close button.": "Dit venster kan worden gesloten door op de Escape-toets te drukken of door de sluiten-knop te activeren.",
", opens captions settings dialog": ", opent instellingen-venster voor bijschriften",
", opens subtitles settings dialog": ", opent instellingen-venster voor ondertitelingen",
", opens descriptions settings dialog": ", opent instellingen-venster voor beschrijvingen",
", selected": ", geselecteerd",
"captions settings": "bijschriften-instellingen",
"subtitles settings": "ondertiteling-instellingen",
"descriptions settings": "beschrijvingen-instellingen",
"Text": "Tekst",
"White": "Wit",
"Black": "Zwart",
"Red": "Rood",
"Green": "Groen",
"Blue": "Blauw",
"Yellow": "Geel",
"Magenta": "Magenta",
"Cyan": "Cyaan",
"Background": "Achtergrond",
"Window": "Venster",
"Transparent": "Transparant",
"Semi-Transparent": "Semi-transparant",
"Opaque": "Ondoorzichtig",
"Font Size": "Lettergrootte",
"Text Edge Style": "Stijl tekstrand",
"None": "Geen",
"Raised": "Verhoogd",
"Depressed": "Ingedrukt",
"Uniform": "Uniform",
"Dropshadow": "Schaduw",
"Font Family": "Lettertype",
"Proportional Sans-Serif": "Proportioneel sans-serif",
"Monospace Sans-Serif": "Monospace sans-serif",
"Proportional Serif": "Proportioneel serif",
"Monospace Serif": "Monospace serif",
"Casual": "Luchtig",
"Script": "Script",
"Small Caps": "Kleine hoofdletters",
"Reset": "Herstellen",
"restore all settings to the default values": "alle instellingen naar de standaardwaarden herstellen",
"Done": "Klaar",
"Caption Settings Dialog": "Venster voor bijschriften-instellingen",
"Beginning of dialog window. Escape will cancel and close the window.": "Begin van dialoogvenster. Escape zal annuleren en het venster sluiten.",
"End of dialog window.": "Einde van dialoogvenster."
}
"Modal Window": "Modal Venster",
"This is a modal window": "Dit is een modaal venster",
"This modal can be closed by pressing the Escape key or activating the close button.": "Dit modaal venster kan gesloten worden door op Escape te drukken of de 'sluiten' knop te activeren.",
", opens captions settings dialog": ", opent bijschriften instellingen venster",
", opens subtitles settings dialog": ", opent ondertiteling instellingen venster",
", opens descriptions settings dialog": ", opent beschrijvingen instellingen venster",
", selected": ", selected"
}
+8 -51
Ver Arquivo
@@ -1,6 +1,4 @@
{
"Audio Player": "Trình phát Audio",
"Video Player": "Trình phát Video",
"Play": "Phát",
"Pause": "Tạm dừng",
"Replay": "Phát lại",
@@ -11,8 +9,6 @@
"LIVE": "TRỰC TIẾP",
"Loaded": "Đã tải",
"Progress": "Tiến trình",
"Progress Bar": "Thanh tiến trình",
"progress bar timing: currentTime={1} duration={2}": "{1} của {2}",
"Fullscreen": "Toàn màn hình",
"Non-Fullscreen": "Thoát toàn màn hình",
"Mute": "Tắt tiếng",
@@ -23,62 +19,23 @@
"Captions": "Chú thích",
"captions off": "tắt chú thích",
"Chapters": "Chương",
"Close Modal Dialog": "Đóng hộp thoại",
"Descriptions": "Mô tả",
"descriptions off": "tắt mô tả",
"Audio Track": "Track âm thanh",
"Volume Level": "Mức âm lượng",
"You aborted the media playback": "Bạn đã hủy việc phát lại media.",
"A network error caused the media download to fail part-way.": "Một lỗi mạng dẫn đến việc tải media bị lỗi.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Video không tải được, mạng hay server có lỗi hoặc định dạng không được hỗ trợ.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Phát media đã bị hủy do một sai lỗi hoặc media sử dụng những tính năng trình duyệt không hỗ trợ.",
"No compatible source was found for this media.": "Không có nguồn tương thích cho media này.",
"The media is encrypted and we do not have the keys to decrypt it.": "Media đã được mã hóa và chúng tôi không có để giải mã nó.",
"The media is encrypted and we do not have the keys to decrypt it.": "Media đã được mã hóa và chúng tôi không thể giải mã nó.",
"Play Video": "Phát Video",
"Close": "Đóng",
"Close Modal Dialog": "Đóng cửa sổ",
"Modal Window": "Cửa sổ",
"This is a modal window": "Đây là một cửa sổ",
"This modal can be closed by pressing the Escape key or activating the close button.": "Cửa sổ này có thể thoát bằng việc nhấn phím Esc hoặc kích hoạt nút đóng.",
", opens captions settings dialog": ", mở hộp thoại cài đặt chú thích",
", opens subtitles settings dialog": ", mở hộp thoại cài đặt phụ đề",
", opens descriptions settings dialog": ", mở hộp thoại cài đặt mô tả",
", selected": ", đã chọn",
"captions settings": "cài đặt chú thích",
"subtitles settings": "cài đặt phụ đề",
"descriptions settings": "cài đặt mô tả",
"Text": "Văn bản",
"White": "Trắng",
"Black": "Đen",
"Red": "Đỏ",
"Green": "Xanh lá cây",
"Blue": "Xanh da trời",
"Yellow": "Vàng",
"Magenta": "Đỏ tươi",
"Cyan": "Lam",
"Background": "Nền",
"Window": "Cửa sổ",
"Transparent": "Trong suốt",
"Semi-Transparent": "Bán trong suốt",
"Opaque": "Mờ",
"Font Size": "Kích cỡ phông chữ",
"Text Edge Style": "Dạng viền văn bản",
"None": "None",
"Raised": "Raised",
"Depressed": "Depressed",
"Uniform": "Uniform",
"Dropshadow": "Dropshadow",
"Font Family": "Phông chữ",
"Proportional Sans-Serif": "Proportional Sans-Serif",
"Monospace Sans-Serif": "Monospace Sans-Serif",
"Proportional Serif": "Proportional Serif",
"Monospace Serif": "Monospace Serif",
"Casual": "Casual",
"Script": "Script",
"Small Caps": "Small Caps",
"Reset": "Đặt lại",
"restore all settings to the default values": "khôi phục lại tất cả các cài đặt về giá trị mặc định",
"Done": "Xong",
"Caption Settings Dialog": "Hộp thoại cài đặt chú thích",
"Beginning of dialog window. Escape will cancel and close the window.": "Bắt đầu cửa sổ hộp thoại. Esc sẽ thoát và đóng cửa sổ.",
"End of dialog window.": "Kết thúc cửa sổ hộp thoại."
}
"This modal can be closed by pressing the Escape key or activating the close button.": "Cửa sổ này có thể đóng lại bằng việc nhấn phím Esc hoặc kích hoạt nút đóng.",
", opens captions settings dialog": ", mở hộp thoại thiết lập chú thích",
", opens subtitles settings dialog": ", mở hộp thoại thiết lập phụ đề",
", opens descriptions settings dialog": ", mở hộp thoại thiết lập mô tả",
", selected": ", đã chọn"
}
+1 -1
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
"version": "6.3.1",
"version": "6.2.8",
"main": "./dist/video.cjs.js",
"style": "./dist/video-js.css",
"copyright": "Copyright Brightcove, Inc. <https://www.brightcove.com/>",
+165
Ver Arquivo
@@ -0,0 +1,165 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Video.js Sandbox</title>
<script src='../node_modules/es5-shim/es5-shim.js'></script>
<script src='../node_modules/es6-shim/es6-shim.js'></script>
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../dist/video.js"></script>
<script src='../node_modules/videojs-flash/dist/videojs-flash.js'></script>
<script src="https://unpkg.com/videojs-contrib-hls@latest/dist/videojs-contrib-hls.js"></script>
<script src="../build/temp/lang/es.js"></script>
<!-- Set the location of the flash SWF -->
<script>
// videojs.options.flash.swf = 'http://vjs.zencdn.net/swf/5.3/video-js.swf';
videojs.options.flash.swf = 'http://localhost:8000/video-js-swf/dist/video-js.swf';
</script>
<style>
.source-el { background: #FF6961; }
.source-js { background: #77DD77; }
.options-src { background: #AEC6CF; }
.source-el.data-setup { background: red; }
.source-js.data-setup { background: green; }
.options-src.data-setup { background: blue; }
.video-js {
height: 150px;
width: 300px;
}
.wrapper {
display: grid;
margin: 0 auto;
grid-gap: 10px;
grid-template-columns: 300px 300px 300px;
}
.panel > p:first-child {
border-bottom: black 1px solid;
}
</style>
</head>
<body>
<p>All the various ways to embed and source video elements.</p>
<p>Pastel color background represent programmatic setup.</p>
<p>Vibrant color background represent data-setup.</p>
<div class="wrapper">
<div class="panel source-el">
<p>js setup with source element</p>
<p>Div embed, source element</p>
<div id="vid01" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png">
<source src="./oceans.mp4" type='video/mp4'>
</div>
<p>Video embed, source element</p>
<video id="vid11" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png">
<source src="./oceans.mp4" type='video/mp4'>
</video>
<p>injested div el, source element</p>
<div data-vjs-player>
<video id="vid21" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png">
<source src="./oceans.mp4" type='video/mp4'>
</video>
</div>
</div>
<div class="panel options-src">
<p>js setup with sources options</p>
<p>Div embed, js source</p>
<div id="vid05" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png">
</div>
<p>Video embed, js source</p>
<video id="vid15" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png">
</video>
<p>injested div el, js source</p>
<div data-vjs-player>
<video id="vid25" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png">
</video>
</div>
</div>
<div class="panel source-js">
<p>js setup with js method sources</p>
<p>Div embed, js source</p>
<div id="vid02" class="video-js" controls>
</div>
<p>Video embed, js source</p>
<video id="vid12" class="video-js" controls>
</video>
<p>injested div el, js source</p>
<div data-vjs-player>
<video id="vid22" class="video-js" controls>
</video>
</div>
</div>
<div class="panel source-el data-setup">
<p>data-setup with sourrce elements</p>
<p>Div embed, source element</p>
<div id="vid03" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}">
<source src="./oceans.mp4" type='video/mp4'>
</div>
<p>Video embed, source element</p>
<video id="vid13" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}">
<source src="./oceans.mp4" type='video/mp4'>
</video>
<p>injested div el, source element</p>
<div data-vjs-player>
<video id="vid23" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}">
<source src="./oceans.mp4" type='video/mp4'>
</video>
</div>
</div>
<div class="panel options-src data-setup">
<p>data-setup embeds with sources options</p>
<p>Div embed, source element</p>
<div id="vid04" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup='{"sources": [{"src":"./oceans.mp4", "type":"video/mp4"}]}'>
</div>
<p>Video embed, source element</p>
<video id="vid14" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup='{"sources": [{"src":"./oceans.mp4", "type":"video/mp4"}]}'>
</video>
<p>injested div el, source element</p>
<div data-vjs-player>
<video id="vid24" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup='{"sources": [{"src":"./oceans.mp4", "type":"video/mp4"}]}'>
</video>
</div>
</div>
<div class="panel source-js data-setup">
<p>js setup with js method sources</p>
<p>Div embed, js source</p>
<div id="vid06" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}">
</div>
<p>Video embed, js source</p>
<video id="vid16" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}">
</video>
<p>injested div el, js source</p>
<div data-vjs-player>
<video id="vid26" class="video-js" controls poster="//vjs.zencdn.net/v/oceans.png" data-setup="{}">
</video>
</div>
</div>
</div>
<script>
var player01 = videojs('vid01');
var player11 = videojs('vid11');
var player21 = videojs('vid21');
var player01 = videojs('vid02');
var player11 = videojs('vid12');
var player21 = videojs('vid22');
var player05 = videojs('vid05', {sources: [{src:'./oceans.mp4',type:'video/mp4'}]});
var player15 = videojs('vid15', {sources: [{src:'./oceans.mp4',type:'video/mp4'}]});
var player25 = videojs('vid25', {sources: [{src:'./oceans.mp4',type:'video/mp4'}]});
player01.src({src:'./oceans.mp4', type:'video/mp4'});
player11.src({src:'./oceans.mp4', type:'video/mp4'});
player21.src({src:'./oceans.mp4', type:'video/mp4'});
player01.poster('//vjs.zencdn.net/v/oceans.png');
player11.poster('//vjs.zencdn.net/v/oceans.png');
player21.poster('//vjs.zencdn.net/v/oceans.png');
setTimeout(function() {
videojs.players.vid06 && videojs.players.vid06.src({src:'./oceans.mp4', type:'video/mp4'});
videojs.players.vid16 && videojs.players.vid16.src({src:'./oceans.mp4', type:'video/mp4'});
videojs.players.vid26 && videojs.players.vid26.src({src:'./oceans.mp4', type:'video/mp4'});
});
</script>
</body>
</html>
+1 -27
Ver Arquivo
@@ -57,26 +57,6 @@ class PlayToggle extends Button {
}
}
/**
* This gets called once after the video has ended and the user seeks so that
* we can change the replay button back to a play button.
*
* @param {EventTarget~Event} [event]
* The event that caused this function to run.
*
* @listens Player#seeked
*/
handleSeeked(event) {
// remove the ended class
this.removeClass('vjs-ended');
if (this.player_.paused()) {
this.handlePause(event);
} else {
this.handlePlay(event);
}
}
/**
* Add the vjs-playing class to the element so it can change appearance.
*
@@ -86,6 +66,7 @@ class PlayToggle extends Button {
* @listens Player#play
*/
handlePlay(event) {
this.removeClass('vjs-ended');
this.removeClass('vjs-paused');
this.addClass('vjs-playing');
// change the button text to "Pause"
@@ -110,19 +91,12 @@ class PlayToggle extends Button {
/**
* Add the vjs-ended class to the element so it can change appearance
*
* @param {EventTarget~Event} [event]
* The event that caused this function to run.
*
* @listens Player#ended
*/
handleEnded(event) {
this.removeClass('vjs-playing');
this.addClass('vjs-ended');
// change the button text to "Replay"
this.controlText('Replay');
// on the next seek remove the replay button
this.one(this.player_, 'seeked', this.handleSeeked);
}
}
@@ -27,9 +27,10 @@ class ProgressControl extends Component {
constructor(player, options) {
super(player, options);
this.handleMouseMove = throttle(bind(this, this.handleMouseMove), 25);
this.throttledHandleMouseSeek = throttle(bind(this, this.handleMouseSeek), 25);
this.on(this.el_, 'mousemove', this.handleMouseMove);
this.enableControls();
this.throttledHandleMouseSeek = throttle(bind(this, this.handleMouseSeek), 25);
this.on(['mousedown', 'touchstart'], this.handleMouseDown);
}
/**
@@ -100,47 +101,6 @@ class ProgressControl extends Component {
seekBar.handleMouseMove(event);
}
/**
* Are controls are currently enabled for this progress control.
*
* @return {boolean}
* true if controls are enabled, false otherwise
*/
controlsEnabled() {
return this.controlsEnabled_;
}
/**
* Disable all controls on the progress control and its children
*/
disableControls() {
this.children().forEach((child) => child.disableControls && child.disableControls());
if (!this.controlsEnabled()) {
return;
}
this.off(['mousedown', 'touchstart'], this.handleMouseDown);
this.off(this.el_, 'mousemove', this.handleMouseMove);
this.handleMouseUp();
this.controlsEnabled_ = false;
}
/**
* Enable all controls on the progress control and its children
*/
enableControls() {
this.children().forEach((child) => child.enableControls && child.enableControls());
if (this.controlsEnabled()) {
return;
}
this.on(['mousedown', 'touchstart'], this.handleMouseDown);
this.on(this.el_, 'mousemove', this.handleMouseMove);
this.controlsEnabled_ = true;
}
/**
* Handle `mousedown` or `touchstart` events on the `ProgressControl`.
*
@@ -1,15 +1,18 @@
/**
* @file current-time-display.js
*/
import TimeDisplay from './time-display';
import document from 'global/document';
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import {bind, throttle} from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
/**
* Displays the current time
*
* @extends Component
*/
class CurrentTimeDisplay extends TimeDisplay {
class CurrentTimeDisplay extends Component {
/**
* Creates an instance of this class.
@@ -22,17 +25,48 @@ class CurrentTimeDisplay extends TimeDisplay {
*/
constructor(player, options) {
super(player, options);
this.on(player, 'ended', this.handleEnded);
this.throttledUpdateContent = throttle(bind(this, this.updateContent), 25);
this.on(player, 'timeupdate', this.throttledUpdateContent);
}
/**
* Builds the default DOM `className`.
* Create the `Component`'s DOM element
*
* @return {string}
* The DOM `className` for this object.
* @return {Element}
* The element that was created.
*/
buildCSSClass() {
return 'vjs-current-time';
createEl() {
const el = super.createEl('div', {
className: 'vjs-current-time vjs-time-control vjs-control'
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-current-time-display'
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
}, Dom.createEl('span', {
className: 'vjs-control-text',
textContent: this.localize('Current Time')
}));
this.updateTextNode_();
el.appendChild(this.contentEl_);
return el;
}
/**
* Updates the "current time" text node with new content using the
* contents of the `formattedTime_` property.
*
* @private
*/
updateTextNode_() {
if (this.textNode_) {
this.contentEl_.removeChild(this.textNode_);
}
this.textNode_ = document.createTextNode(` ${this.formattedTime_ || '0:00'}`);
this.contentEl_.appendChild(this.textNode_);
}
/**
@@ -46,36 +80,15 @@ class CurrentTimeDisplay extends TimeDisplay {
updateContent(event) {
// Allows for smooth scrubbing, when player can't keep up.
const time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
const formattedTime = formatTime(time, this.player_.duration());
this.updateFormattedTime_(time);
}
/**
* When the player fires ended there should be no time left. Sadly
* this is not always the case, lets make it seem like that is the case
* for users.
*
* @param {EventTarget~Event} [event]
* The `ended` event that caused this to run.
*
* @listens Player#ended
*/
handleEnded(event) {
if (!this.player_.duration()) {
return;
if (formattedTime !== this.formattedTime_) {
this.formattedTime_ = formattedTime;
this.requestAnimationFrame(this.updateTextNode_);
}
this.updateFormattedTime_(this.player.duration());
}
}
/**
* The text that should display over the `CurrentTimeDisplay`s controls. Added to for localization.
*
* @type {string}
* @private
*/
CurrentTimeDisplay.prototype.controlText_ = 'Current Time';
Component.registerComponent('CurrentTimeDisplay', CurrentTimeDisplay);
export default CurrentTimeDisplay;
@@ -1,15 +1,18 @@
/**
* @file duration-display.js
*/
import TimeDisplay from './time-display';
import document from 'global/document';
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import {bind, throttle} from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
/**
* Displays the duration
*
* @extends Component
*/
class DurationDisplay extends TimeDisplay {
class DurationDisplay extends Component {
/**
* Creates an instance of this class.
@@ -23,24 +26,57 @@ class DurationDisplay extends TimeDisplay {
constructor(player, options) {
super(player, options);
this.throttledUpdateContent = throttle(bind(this, this.updateContent), 25);
this.on(player, [
'durationchange',
// Also listen for timeupdate (in the parent) and loadedmetadata because removing those
// Also listen for timeupdate and loadedmetadata because removing those
// listeners could have broken dependent applications/libraries. These
// can likely be removed for 7.0.
'loadedmetadata'
'loadedmetadata',
'timeupdate'
], this.throttledUpdateContent);
}
/**
* Builds the default DOM `className`.
* Create the `Component`'s DOM element
*
* @return {string}
* The DOM `className` for this object.
* @return {Element}
* The element that was created.
*/
buildCSSClass() {
return 'vjs-duration';
createEl() {
const el = super.createEl('div', {
className: 'vjs-duration vjs-time-control vjs-control'
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-duration-display'
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
}, Dom.createEl('span', {
className: 'vjs-control-text',
textContent: this.localize('Duration Time')
}));
this.updateTextNode_();
el.appendChild(this.contentEl_);
return el;
}
/**
* Updates the "current time" text node with new content using the
* contents of the `formattedTime_` property.
*
* @private
*/
updateTextNode_() {
if (this.textNode_) {
this.contentEl_.removeChild(this.textNode_);
}
this.textNode_ = document.createTextNode(` ${this.formattedTime_ || '0:00'}`);
this.contentEl_.appendChild(this.textNode_);
}
/**
@@ -59,18 +95,11 @@ class DurationDisplay extends TimeDisplay {
if (duration && this.duration_ !== duration) {
this.duration_ = duration;
this.updateFormattedTime_(duration);
this.formattedTime_ = formatTime(duration);
this.requestAnimationFrame(this.updateTextNode_);
}
}
}
/**
* The text that should display over the `DurationDisplay`s controls. Added to for localization.
*
* @type {string}
* @private
*/
DurationDisplay.prototype.controlText_ = 'Duration Time';
Component.registerComponent('DurationDisplay', DurationDisplay);
export default DurationDisplay;
@@ -1,14 +1,18 @@
/**
* @file remaining-time-display.js
*/
import TimeDisplay from './time-display';
import document from 'global/document';
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import {bind, throttle} from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
/**
* Displays the time left in the video
*
* @extends Component
*/
class RemainingTimeDisplay extends TimeDisplay {
class RemainingTimeDisplay extends Component {
/**
* Creates an instance of this class.
@@ -21,33 +25,48 @@ class RemainingTimeDisplay extends TimeDisplay {
*/
constructor(player, options) {
super(player, options);
this.on(player, 'durationchange', this.throttledUpdateContent);
this.on(player, 'ended', this.handleEnded);
this.throttledUpdateContent = throttle(bind(this, this.updateContent), 25);
this.on(player, ['timeupdate', 'durationchange'], this.throttledUpdateContent);
}
/**
* Builds the default DOM `className`.
* Create the `Component`'s DOM element
*
* @return {string}
* The DOM `className` for this object.
* @return {Element}
* The element that was created.
*/
buildCSSClass() {
return 'vjs-remaining-time';
createEl() {
const el = super.createEl('div', {
className: 'vjs-remaining-time vjs-time-control vjs-control'
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-remaining-time-display'
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
}, Dom.createEl('span', {
className: 'vjs-control-text',
textContent: this.localize('Remaining Time')
}));
this.updateTextNode_();
el.appendChild(this.contentEl_);
return el;
}
/**
* The remaining time display prefixes numbers with a "minus" character.
*
* @param {number} time
* A numeric time, in seconds.
*
* @return {string}
* A formatted time
* Updates the "remaining time" text node with new content using the
* contents of the `formattedTime_` property.
*
* @private
*/
formatTime_(time) {
return '-' + super.formatTime_(time);
updateTextNode_() {
if (this.textNode_) {
this.contentEl_.removeChild(this.textNode_);
}
this.textNode_ = document.createTextNode(` -${this.formattedTime_ || '0:00'}`);
this.contentEl_.appendChild(this.textNode_);
}
/**
@@ -60,38 +79,16 @@ class RemainingTimeDisplay extends TimeDisplay {
* @listens Player#durationchange
*/
updateContent(event) {
if (!this.player_.duration()) {
return;
}
if (this.player_.duration()) {
const formattedTime = formatTime(this.player_.remainingTime());
this.updateFormattedTime_(this.player_.remainingTimeDisplay());
}
/**
* When the player fires ended there should be no time left. Sadly
* this is not always the case, lets make it seem like that is the case
* for users.
*
* @param {EventTarget~Event} [event]
* The `ended` event that caused this to run.
*
* @listens Player#ended
*/
handleEnded(event) {
if (!this.player_.duration()) {
return;
if (formattedTime !== this.formattedTime_) {
this.formattedTime_ = formattedTime;
this.requestAnimationFrame(this.updateTextNode_);
}
}
this.updateFormattedTime_(0);
}
}
/**
* The text that should display over the `RemainingTimeDisplay`s controls. Added to for localization.
*
* @type {string}
* @private
*/
RemainingTimeDisplay.prototype.controlText_ = 'Remaining Time';
Component.registerComponent('RemainingTimeDisplay', RemainingTimeDisplay);
export default RemainingTimeDisplay;
@@ -1,129 +0,0 @@
/**
* @file time-display.js
*/
import document from 'global/document';
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import {bind, throttle} from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
/**
* Displays the time left in the video
*
* @extends Component
*/
class TimeDisplay extends Component {
/**
* Creates an instance of this class.
*
* @param {Player} player
* The `Player` that this class should be attached to.
*
* @param {Object} [options]
* The key/value store of player options.
*/
constructor(player, options) {
super(player, options);
this.throttledUpdateContent = throttle(bind(this, this.updateContent), 25);
this.on(player, 'timeupdate', this.throttledUpdateContent);
}
/**
* Create the `Component`'s DOM element
*
* @return {Element}
* The element that was created.
*/
createEl(plainName) {
const className = this.buildCSSClass();
const el = super.createEl('div', {
className: `${className} vjs-time-control vjs-control`
});
this.contentEl_ = Dom.createEl('div', {
className: `${className}-display`
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
}, Dom.createEl('span', {
className: 'vjs-control-text',
textContent: this.localize(this.contentText_)
}));
this.updateTextNode_();
el.appendChild(this.contentEl_);
return el;
}
/**
* Updates the "remaining time" text node with new content using the
* contents of the `formattedTime_` property.
*
* @private
*/
updateTextNode_() {
if (this.textNode_) {
this.contentEl_.removeChild(this.textNode_);
}
this.textNode_ = document.createTextNode(this.formattedTime_ || '0:00');
this.contentEl_.appendChild(this.textNode_);
}
/**
* Generates a formatted time for this component to use in display.
*
* @param {number} time
* A numeric time, in seconds.
*
* @return {string}
* A formatted time
*
* @private
*/
formatTime_(time) {
return formatTime(time);
}
/**
* Updates the time display text node if it has what was passed in changed
* the formatted time.
*
* @param {number} time
* The time to update to
*
* @private
*/
updateFormattedTime_(time) {
const formattedTime = this.formatTime_(time);
if (formattedTime === this.formattedTime_) {
return;
}
this.formattedTime_ = formattedTime;
this.requestAnimationFrame(this.updateTextNode_);
}
/**
* To be filled out in the child class, should update the displayed time
* in accordance with the fact that the current time has changed.
*
* @param {EventTarget~Event} [event]
* The `timeupdate` event that caused this to run.
*
* @listens Player#timeupdate
*/
updateContent(event) {}
}
/**
* The text that should display over the `TimeDisplay`s controls. Added to for localization.
*
* @type {string}
* @private
*/
TimeDisplay.prototype.controlText_ = 'Time';
Component.registerComponent('TimeDisplay', TimeDisplay);
export default TimeDisplay;
+2 -7
Ver Arquivo
@@ -8,7 +8,6 @@ import * as Dom from '../utils/dom.js';
import * as Fn from '../utils/fn.js';
import * as Events from '../utils/events.js';
import toTitleCase from '../utils/to-title-case.js';
import { IS_IOS } from '../utils/browser.js';
import document from 'global/document';
/**
@@ -340,12 +339,8 @@ class MenuButton extends Component {
this.buttonPressed_ = true;
this.menu.lockShowing();
this.menuButton_.el_.setAttribute('aria-expanded', 'true');
// set the focus into the submenu, except on iOS where it is resulting in
// undesired scrolling behavior when the player is in an iframe
if (!IS_IOS && !Dom.isInFrame()) {
this.menu.focus();
}
// set the focus into the submenu
this.menu.focus();
}
}
+30 -18
Ver Arquivo
@@ -363,6 +363,7 @@ class Player extends Component {
// now remove immediately so native controls don't flash.
// May be turned back on by HTML5 tech if nativeControlsForTouch is true
tag.controls = false;
tag.removeAttribute('controls');
/*
* Store the internal state of scrubbing
@@ -508,16 +509,34 @@ class Player extends Component {
* The DOM element that gets created.
*/
createEl() {
const tag = this.tag;
let tag = this.tag;
let el;
const playerElIngest = this.playerElIngest_ = tag.parentNode && tag.parentNode.hasAttribute && tag.parentNode.hasAttribute('data-vjs-player');
let playerElIngest = this.playerElIngest_ = tag.parentNode && tag.parentNode.hasAttribute && tag.parentNode.hasAttribute('data-vjs-player');
const divEmbed = this.tag.tagName.toLowerCase() === 'div';
if (playerElIngest) {
el = this.el_ = tag.parentNode;
} else {
} else if (!divEmbed) {
el = this.el_ = super.createEl('div');
}
// Copy over all the attributes from the tag, including ID and class
// ID will now reference player box, not the video tag
const attrs = Dom.getAttributes(tag);
if (divEmbed) {
el = this.el_ = tag;
tag = this.tag = document.createElement('video');
while (el.children.length) {
tag.appendChild(el.firstChild);
el.removeChild(el.firstChild);
}
el.appendChild(tag);
playerElIngest = this.playerElIngest_ = el;
}
// set tabindex to -1 so we could focus on the player element
tag.setAttribute('tabindex', '-1');
@@ -525,17 +544,21 @@ class Player extends Component {
tag.removeAttribute('width');
tag.removeAttribute('height');
// Copy over all the attributes from the tag, including ID and class
// ID will now reference player box, not the video tag
const attrs = Dom.getAttributes(tag);
Object.getOwnPropertyNames(attrs).forEach(function(attr) {
// workaround so we don't totally break IE7
// http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7
if (attr === 'class') {
el.className += ' ' + attrs[attr];
if (divEmbed) {
tag.className += ' ' + attrs[attr];
}
} else {
el.setAttribute(attr, attrs[attr]);
if (divEmbed) {
tag.setAttribute(attr, attrs[attr]);
}
}
});
@@ -1787,17 +1810,6 @@ class Player extends Component {
return this.duration() - this.currentTime();
}
/**
* A remaining time function that is intented to be used when
* the time is to be displayed directly to the user.
*
* @return {number}
* The rounded time remaining in seconds
*/
remainingTimeDisplay() {
return Math.floor(this.duration()) - Math.floor(this.currentTime());
}
//
// Kind of like an array of portions of the video that have been downloaded.
+7
Ver Arquivo
@@ -31,6 +31,7 @@ const autoSetup = function() {
// through each list of elements to build up a new, combined list of elements.
const vids = document.getElementsByTagName('video');
const audios = document.getElementsByTagName('audio');
const divs = document.getElementsByTagName('div');
const mediaEls = [];
if (vids && vids.length > 0) {
@@ -45,6 +46,12 @@ const autoSetup = function() {
}
}
if (divs && divs.length > 0) {
for (let i = 0, e = divs.length; i < e; i++) {
mediaEls.push(divs[i]);
}
}
// Check if any media elements exist
if (mediaEls && mediaEls.length > 0) {
+2 -50
Ver Arquivo
@@ -31,65 +31,17 @@ class Slider extends Component {
// Set a horizontal or vertical class on the slider depending on the slider type
this.vertical(!!this.options_.vertical);
this.enableControls();
}
/**
* Are controls are currently enabled for this slider or not.
*
* @return {boolean}
* true if controls are enabled, false otherwise
*/
controlsEnabled() {
return this.controlsEnabled_;
}
/**
* Enable controls for this slider if they are disabled
*/
enableControls() {
if (this.controlsEnabled()) {
return;
}
this.on('mousedown', this.handleMouseDown);
this.on('touchstart', this.handleMouseDown);
this.on('focus', this.handleFocus);
this.on('blur', this.handleBlur);
this.on('click', this.handleClick);
this.on(this.player_, 'controlsvisible', this.update);
this.on(player, 'controlsvisible', this.update);
if (this.playerEvent) {
this.on(this.player_, this.playerEvent, this.update);
this.on(player, this.playerEvent, this.update);
}
this.controlsEnabled_ = true;
}
/**
* Disable controls for this slider if they are enabled
*/
disableControls() {
if (!this.controlsEnabled()) {
return;
}
const doc = this.bar.el_.ownerDocument;
this.off('mousedown', this.handleMouseDown);
this.off('touchstart', this.handleMouseDown);
this.off('focus', this.handleFocus);
this.off('blur', this.handleBlur);
this.off('click', this.handleClick);
this.off(this.player_, 'controlsvisible', this.update);
this.off(doc, 'mousemove', this.handleMouseMove);
this.off(doc, 'mouseup', this.handleMouseUp);
this.off(doc, 'touchmove', this.handleMouseMove);
this.off(doc, 'touchend', this.handleMouseUp);
if (this.playerEvent) {
this.off(this.player_, this.playerEvent, this.update);
}
this.controlsEnabled_ = false;
}
/**
-17
Ver Arquivo
@@ -85,23 +85,6 @@ export function isEl(value) {
return isObject(value) && value.nodeType === 1;
}
/**
* Determines if the current DOM is embedded in an iframe.
*
* @return {boolean}
*
*/
export function isInFrame() {
// We need a try/catch here because Safari will throw errors when attempting
// to get either `parent` or `self`
try {
return window.parent !== window.self;
} catch (x) {
return true;
}
}
/**
* Creates functions to query the DOM using a given method.
*
+136 -1
Ver Arquivo
@@ -17,7 +17,7 @@ QUnit.module('video.js', {
QUnit.test('should create a video tag and have access children in old IE', function(assert) {
const fixture = document.getElementById('qunit-fixture');
fixture.innerHTML += '<video id="test_vid_id"><source type="video/mp4"></video>';
fixture.innerHTML += '<video id="test_vid_id"><source type="video/mp4"></source></video>';
const vid = document.getElementById('test_vid_id');
@@ -331,3 +331,138 @@ QUnit.test('should create a new tag for movingMediaElementInDOM', function(asser
Html5.isSupported = oldIS;
Html5.nativeSourceHandler.canPlayType = oldCPT;
});
/* **************************************************** *
* div embed tests copied from video emebed tests above *
* **************************************************** */
QUnit.module('video.js div embed', {
beforeEach() {
this.clock = sinon.useFakeTimers();
},
afterEach() {
this.clock.restore();
}
});
QUnit.test('should return a video player instance', function(assert) {
const fixture = document.getElementById('qunit-fixture');
fixture.innerHTML += '<div id="test_vid_id"></div>' +
'<div id="test_vid_id2"></div>';
const player = videojs('test_vid_id', { techOrder: ['techFaker'] });
assert.ok(player, 'created player from tag');
assert.ok(player.id() === 'test_vid_id');
assert.ok(videojs.getPlayers().test_vid_id === player,
'added player to global reference');
const playerAgain = videojs('test_vid_id');
assert.ok(player === playerAgain, 'did not create a second player from same tag');
assert.equal(player, playerAgain, 'we did not make a new player');
const tag2 = document.getElementById('test_vid_id2');
const player2 = videojs(tag2, { techOrder: ['techFaker'] });
assert.ok(player2.id() === 'test_vid_id2', 'created player from element');
player.dispose();
player2.dispose();
});
QUnit.test('should log about already initalized players if options already passed',
function(assert) {
const origWarnLog = log.warn;
const fixture = document.getElementById('qunit-fixture');
const warnLogs = [];
log.warn = (args) => {
warnLogs.push(args);
};
fixture.innerHTML += '<div id="test_vid_id"></div>';
const player = videojs('test_vid_id', { techOrder: ['techFaker'] });
assert.ok(player, 'created player from tag');
assert.equal(player.id(), 'test_vid_id', 'player has the right ID');
assert.equal(warnLogs.length, 0, 'no warn logs');
const playerAgain = videojs('test_vid_id');
assert.equal(player, playerAgain, 'did not create a second player from same tag');
assert.equal(warnLogs.length, 0, 'no warn logs');
const playerAgainWithOptions = videojs('test_vid_id', { techOrder: ['techFaker'] });
assert.equal(player,
playerAgainWithOptions,
'did not create a second player from same tag');
assert.equal(warnLogs.length, 1, 'logged a warning');
assert.equal(warnLogs[0],
'Player "test_vid_id" is already initialised. Options will not be applied.',
'logged the right message');
log.warn = origWarnLog;
player.dispose();
});
QUnit.test('should return a video player instance from el html5 tech', function(assert) {
const fixture = document.getElementById('qunit-fixture');
fixture.innerHTML += '<div id="test_vid_id"></div>' +
'<div id="test_vid_id2"></div>';
const vid = document.querySelector('#test_vid_id');
const player = videojs(vid);
assert.ok(player, 'created player from tag');
assert.ok(player.id() === 'test_vid_id');
assert.ok(videojs.getPlayers().test_vid_id === player,
'added player to global reference');
const playerAgain = videojs(vid);
assert.ok(player === playerAgain, 'did not create a second player from same tag');
assert.equal(player, playerAgain, 'we did not make a new player');
const tag2 = document.getElementById('test_vid_id2');
const player2 = videojs(tag2, { techOrder: ['techFaker'] });
assert.ok(player2.id() === 'test_vid_id2', 'created player from element');
player.dispose();
player2.dispose();
});
QUnit.test('should return a video player instance from el techfaker', function(assert) {
const fixture = document.getElementById('qunit-fixture');
fixture.innerHTML += '<div id="test_vid_id"></div>' +
'<div id="test_vid_id2"></div>';
const vid = document.querySelector('#test_vid_id');
const player = videojs(vid, {techOrder: ['techFaker']});
assert.ok(player, 'created player from tag');
assert.ok(player.id() === 'test_vid_id');
assert.ok(videojs.getPlayers().test_vid_id === player,
'added player to global reference');
const playerAgain = videojs(vid);
assert.ok(player === playerAgain, 'did not create a second player from same tag');
assert.equal(player, playerAgain, 'we did not make a new player');
const tag2 = document.getElementById('test_vid_id2');
const player2 = videojs(tag2, { techOrder: ['techFaker'] });
assert.ok(player2.id() === 'test_vid_id2', 'created player from element');
player.dispose();
player2.dispose();
});