mirror of
https://github.com/videojs/video.js.git
synced 2025-02-02 11:34:50 +02:00
feat: Add breakpoints option to support toggling classes based on player width. (#5471)
This adds a breakpoints option. By default, this option is false meaning this is an opt-in feature. When passing true, it will use a default set of breakpoints. Or custom breakpoints can be passed if users do not like our breakpoints (or previously-existing style decisions). - Add breakpoints option. - Adds some new (currently unused) classes: vjs-layout-medium, vjs-layout-large, vjs-layout-x-large, and vjs-layout-huge. - Add updateCurrentBreakpoint and currentBreakpoint methods to the player. - Update css/components/_adaptive.scss - Add sandbox/responsive.html.example Closes videojs/video.js#4371
This commit is contained in:
parent
7292253fe0
commit
51bd49f4bc
@ -16,7 +16,7 @@
|
||||
don't currently support 'description' text tracks in any
|
||||
useful way! Currently this means that iOS will not display
|
||||
ANY text tracks -->
|
||||
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="360"
|
||||
<video id="example_video_1" class="video-js" controls preload="none" width="640" height="360"
|
||||
data-setup='{ "html5" : { "nativeTextTracks" : false } }'
|
||||
poster="http://d2zihajmogu5jn.cloudfront.net/elephantsdream/poster.png">
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png" data-setup="{}">
|
||||
<video id="example_video_1" class="video-js" controls preload="none" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png" data-setup="{}">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg">
|
||||
|
@ -163,6 +163,48 @@ Prevents the player from running the autoSetup for media elements with `data-set
|
||||
|
||||
> **Note**: this must be set globally with `videojs.options.autoSetup = false` in the same tick as videojs source is loaded to take effect.
|
||||
|
||||
### `breakpoints`
|
||||
|
||||
> Type: `boolean|Array`, Default: `false`
|
||||
|
||||
Set layout breakpoints that will configure how class names are toggled on the player to adjust the UI based on the player's dimensions.
|
||||
|
||||
By default, no breakpoints are supported, but passing `true` will set some sensible default breakpoints:
|
||||
|
||||
Class Name | Width Range
|
||||
---------------------|------------
|
||||
`vjs-layout-tiny` | 0-210
|
||||
`vjs-layout-x-small` | 211-320
|
||||
`vjs-layout-small` | 321-425
|
||||
`vjs-layout-medium` | 426-768
|
||||
`vjs-layout-large` | 769-1440
|
||||
`vjs-layout-x-large` | 1441-2560
|
||||
`vjs-layout-huge` | 2561+
|
||||
|
||||
While the class names cannot be changed, the width ranges can be configured via an object like this:
|
||||
|
||||
```js
|
||||
breakpoints: {
|
||||
tiny: 300,
|
||||
xsmall: 400,
|
||||
small: 500,
|
||||
medium: 600,
|
||||
large: 700,
|
||||
xlarge: 800,
|
||||
huge: 900
|
||||
}
|
||||
```
|
||||
|
||||
* The _keys_ of the `breakpoints` object are derived from the associated class names by removing the `vjs-layout-` prefix and any `-` characters.
|
||||
* The _values_ of the `breakpoints` object define the max width for a range.
|
||||
* Not all keys need to be defined. You can easily override a single breakpoint by passing an object with one key/value pair! Customized breakpoints will be merged with default breakpoints when the player is created.
|
||||
|
||||
When the player's size changes, the merged breakpoints will be inspected in the size order until a matching breakpoint is found.
|
||||
|
||||
That breakpoint's associated class name will be added as a class to the player. The previous breakpoint's class will be removed.
|
||||
|
||||
See the file `sandbox/responsive.html.example` for an example of a fluid/responsive player using the default breakpoints.
|
||||
|
||||
### `children`
|
||||
|
||||
> Type: `Array|Object`
|
||||
|
@ -22,7 +22,7 @@
|
||||
<pre>open http://localhost:9999/sandbox/index.html</pre>
|
||||
</div>
|
||||
|
||||
<video id="vid1" class="video-js vjs-default-skin" lang="en" controls preload="auto" width="640" height="360" poster="//d2zihajmogu5jn.cloudfront.net/elephantsdream/poster.png">
|
||||
<video id="vid1" class="video-js" lang="en" controls preload="auto" width="640" height="360" poster="//d2zihajmogu5jn.cloudfront.net/elephantsdream/poster.png">
|
||||
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.mp4" type="video/mp4">
|
||||
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.ogg" type="video/ogg">
|
||||
<track kind="captions" src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/captions.en.vtt" srclang="en" label="English">
|
||||
|
@ -21,7 +21,7 @@
|
||||
don't currently support 'description' text tracks in any
|
||||
useful way! Currently this means that iOS will not display
|
||||
ANY text tracks -->
|
||||
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="360"
|
||||
<video id="example_video_1" class="video-js" controls preload="none" width="640" height="360"
|
||||
data-setup='{ "html5" : { "nativeTextTracks" : false } }'
|
||||
poster="http://d2zihajmogu5jn.cloudfront.net/elephantsdream/poster.png">
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
<pre>open http://localhost:9999/sandbox/flash.html</pre>
|
||||
</div>
|
||||
|
||||
<video id="vid1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264"
|
||||
<video id="vid1" class="video-js" controls preload="auto" width="640" height="264"
|
||||
poster="http://vjs.zencdn.net/v/oceans.png"
|
||||
data-setup=''>
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
|
@ -3,17 +3,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Video.js Sandbox</title>
|
||||
|
||||
<!-- Load the source files -->
|
||||
<link href="../dist/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>
|
||||
|
||||
<!-- Set the location of the flash SWF -->
|
||||
<script>
|
||||
videojs.options.flash.swf = '../node_modules/videojs-flash/node_modules/videojs-swf/dist/video-js.swf';
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div style="background-color:#eee; border: 1px solid #777; padding: 10px; margin-bottom: 20px; font-size: .8em; line-height: 1.5em; font-family: Verdana, sans-serif;">
|
||||
@ -23,20 +14,23 @@
|
||||
<pre>open http://localhost:9999/sandbox/index.html</pre>
|
||||
</div>
|
||||
|
||||
<video id="vid1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264"
|
||||
poster="http://vjs.zencdn.net/v/oceans.png"
|
||||
data-setup='{}'>
|
||||
<video-js
|
||||
id="vid1"
|
||||
controls
|
||||
preload="auto"
|
||||
width="640"
|
||||
height="264"
|
||||
poster="http://vjs.zencdn.net/v/oceans.png">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg">
|
||||
<track kind="captions" src="../docs/examples/shared/example-captions.vtt" srclang="en" label="English">
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
</video-js>
|
||||
|
||||
<script>
|
||||
var vid = document.getElementById("vid1");
|
||||
var vid = document.getElementById('vid1');
|
||||
var player = videojs(vid);
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<video id="vid1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264" data-setup=''>
|
||||
<video id="vid1" class="video-js" controls preload="auto" width="640" height="264" data-setup=''>
|
||||
<!--
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4'>
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm'>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<body>
|
||||
<p style="background-color:#eee; border: 1px solid #777; padding: 10px; font-size: .8em; line-height: 1.5em; font-family: Verdana, sans-serif;">This page shows you how to create, register and initialize a Video.js plugin.</p>
|
||||
|
||||
<video id="vid1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png">
|
||||
<video id="vid1" class="video-js" controls preload="auto" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg">
|
||||
|
160
sandbox/responsive.html.example
Normal file
160
sandbox/responsive.html.example
Normal file
@ -0,0 +1,160 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Video.js Sandbox - Responsive</title>
|
||||
<link href="../dist/video-js.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/video.js"></script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breakpoints, .video-js, table {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ccc;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
tbody tr:first-child {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.breakpoints div {
|
||||
background-color: red;
|
||||
color: white;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
@media (max-width: 210px) {
|
||||
.breakpoints .tiny {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 211px) and (max-width: 320px) {
|
||||
.breakpoints .x-small {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 321px) and (max-width: 425px) {
|
||||
.breakpoints .small {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 426px) and (max-width: 768px) {
|
||||
.breakpoints .medium {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 769px) and (max-width: 1440px) {
|
||||
.breakpoints .large {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1441px) and (max-width: 2560px) {
|
||||
.breakpoints .x-large {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 2561px) {
|
||||
.breakpoints .huge {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
The following boxes indicate which breakpoint should be applied to the
|
||||
player when it fills the width of its containing viewport.
|
||||
</p>
|
||||
<p>
|
||||
Use these to validate that the default breakpoints match up with how
|
||||
CSS media queries work.
|
||||
</p>
|
||||
<p>
|
||||
<b>Because these bars are updated by CSS, they will change before the <code>playerresize</code> event occurs!</b>
|
||||
</p>
|
||||
<div class="breakpoints">
|
||||
<div class="tiny">vjs-layout-tiny (0px-210px)</div>
|
||||
<div class="x-small">vjs-layout-x-small (211px-320px)</div>
|
||||
<div class="small">vjs-layout-small (321px-425px)</div>
|
||||
<div class="medium">vjs-layout-medium (426px-768px)</div>
|
||||
<div class="large">vjs-layout-large (769px-1440px)</div>
|
||||
<div class="x-large">vjs-layout-x-large (1441px-2560px)</div>
|
||||
<div class="huge">vjs-layout-huge (2561px+)</div>
|
||||
</div>
|
||||
|
||||
<video-js
|
||||
class="vjs-fluid"
|
||||
controls
|
||||
preload="auto"
|
||||
poster="http://vjs.zencdn.net/v/oceans.png">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg">
|
||||
<track kind="captions" src="../docs/examples/shared/example-captions.vtt" srclang="en" label="English">
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video-js>
|
||||
|
||||
<p>
|
||||
Each time the player size changes, a row is prepended to this table.
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
<th>Player Width</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
var vid = document.querySelector('video-js');
|
||||
var player = videojs(vid, {breakpoints: true});
|
||||
var tbody = document.querySelector('table tbody');
|
||||
|
||||
player.on('playerresize', function() {
|
||||
var values = {
|
||||
breakpoint: player.currentBreakpoint(),
|
||||
className: player.el().className.match(/vjs-layout-([a-z\-]+)/)[0],
|
||||
playerWidth: player.currentWidth()
|
||||
};
|
||||
|
||||
videojs.log('playerresize', values);
|
||||
|
||||
var tr = document.createElement('tr');
|
||||
|
||||
tr.innerHTML = '<td>' +
|
||||
values.className +
|
||||
'</td><td>' +
|
||||
values.playerWidth +
|
||||
'</td>';
|
||||
|
||||
tbody.insertBefore(tr, tbody.firstChild);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -2,14 +2,18 @@
|
||||
// - Play button
|
||||
// - Fullscreen Button
|
||||
.video-js.vjs-layout-tiny:not(.vjs-fullscreen) {
|
||||
.vjs-custom-control-spacer { @include flex(auto); }
|
||||
.vjs-custom-control-spacer {
|
||||
@include flex(auto);
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.vjs-no-flex .vjs-custom-control-spacer { width: auto; }
|
||||
|
||||
.vjs-current-time, .vjs-time-divider, .vjs-duration, .vjs-remaining-time,
|
||||
.vjs-playback-rate, .vjs-progress-control,
|
||||
.vjs-mute-control, .vjs-volume-control,
|
||||
.vjs-mute-control, .vjs-volume-control, .vjs-volume-panel,
|
||||
.vjs-chapters-button, .vjs-descriptions-button, .vjs-captions-button,
|
||||
.vjs-subtitles-button, .vjs-audio-button { display: none; }
|
||||
.vjs-subtitles-button, .vjs-subs-caps-button, .vjs-audio-button { display: none; }
|
||||
}
|
||||
|
||||
// When the player is x-small, display nothing but:
|
||||
@ -19,9 +23,9 @@
|
||||
.video-js.vjs-layout-x-small:not(.vjs-fullscreen) {
|
||||
.vjs-current-time, .vjs-time-divider, .vjs-duration, .vjs-remaining-time,
|
||||
.vjs-playback-rate,
|
||||
.vjs-mute-control, .vjs-volume-control,
|
||||
.vjs-mute-control, .vjs-volume-control, .vjs-volume-panel,
|
||||
.vjs-chapters-button, .vjs-descriptions-button, .vjs-captions-button,
|
||||
.vjs-subtitles-button, .vjs-audio-button { display: none; }
|
||||
.vjs-subtitles-button, .vjs-subs-caps-button, .vjs-audio-button { display: none; }
|
||||
}
|
||||
|
||||
|
||||
@ -29,12 +33,12 @@
|
||||
// - Play button
|
||||
// - Progress bar
|
||||
// - Volume menu button
|
||||
// - Captions Button
|
||||
// - Subs-Caps Button
|
||||
// - Fullscreen button
|
||||
.video-js.vjs-layout-small:not(.vjs-fullscreen) {
|
||||
.vjs-current-time, .vjs-time-divider, .vjs-duration, .vjs-remaining-time,
|
||||
.vjs-playback-rate,
|
||||
.vjs-mute-control, .vjs-volume-control,
|
||||
.vjs-mute-control, .vjs-volume-control, .vjs-volume-panel,
|
||||
.vjs-chapters-button, .vjs-descriptions-button, .vjs-captions-button,
|
||||
.vjs-subtitles-button .vjs-audio-button { display: none; }
|
||||
.vjs-subtitles-button, .vjs-audio-button { display: none; }
|
||||
}
|
||||
|
@ -960,8 +960,9 @@ class Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width or the height of the `Component` elements computed style. Uses
|
||||
* `window.getComputedStyle`.
|
||||
* Get the computed width or the height of the component's element.
|
||||
*
|
||||
* Uses `window.getComputedStyle`.
|
||||
*
|
||||
* @param {string} widthOrHeight
|
||||
* A string containing 'width' or 'height'. Whichever one you want to get.
|
||||
@ -1012,11 +1013,13 @@ class Component {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get an object that contains width and height values of the `Component`s
|
||||
* computed style.
|
||||
* Get an object that contains computed width and height values of the
|
||||
* component's element.
|
||||
*
|
||||
* Uses `window.getComputedStyle`.
|
||||
*
|
||||
* @return {Component~DimensionObject}
|
||||
* The dimensions of the components element
|
||||
* The computed dimensions of the component's element.
|
||||
*/
|
||||
currentDimensions() {
|
||||
return {
|
||||
@ -1026,20 +1029,24 @@ class Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the `Component`s computed style. Uses `window.getComputedStyle`.
|
||||
* Get the computed width of the component's element.
|
||||
*
|
||||
* @return {number} width
|
||||
* The width of the `Component`s computed style.
|
||||
* Uses `window.getComputedStyle`.
|
||||
*
|
||||
* @return {number}
|
||||
* The computed width of the component's element.
|
||||
*/
|
||||
currentWidth() {
|
||||
return this.currentDimension('width');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the `Component`s computed style. Uses `window.getComputedStyle`.
|
||||
* Get the computed height of the component's element.
|
||||
*
|
||||
* @return {number} height
|
||||
* The height of the `Component`s computed style.
|
||||
* Uses `window.getComputedStyle`.
|
||||
*
|
||||
* @return {number}
|
||||
* The computed height of the component's element.
|
||||
*/
|
||||
currentHeight() {
|
||||
return this.currentDimension('height');
|
||||
|
133
src/js/player.js
133
src/js/player.js
@ -22,7 +22,7 @@ import * as stylesheet from './utils/stylesheet.js';
|
||||
import FullscreenApi from './fullscreen-api.js';
|
||||
import MediaError from './media-error.js';
|
||||
import safeParseTuple from 'safe-json-parse/tuple';
|
||||
import {assign} from './utils/obj';
|
||||
import {assign, isObject} from './utils/obj';
|
||||
import mergeOptions from './utils/merge-options.js';
|
||||
import {silencePromise} from './utils/promise';
|
||||
import textTrackConverter from './tracks/text-track-list-converter.js';
|
||||
@ -240,6 +240,41 @@ const TECH_EVENTS_QUEUE = {
|
||||
seeked: 'Seeked'
|
||||
};
|
||||
|
||||
const BREAKPOINT_ORDER = [
|
||||
'tiny',
|
||||
'xsmall',
|
||||
'small',
|
||||
'medium',
|
||||
'large',
|
||||
'xlarge',
|
||||
'huge'
|
||||
];
|
||||
|
||||
const BREAKPOINT_CLASSES = {};
|
||||
|
||||
// grep: vjs-layout-tiny
|
||||
// grep: vjs-layout-x-small
|
||||
// grep: vjs-layout-small
|
||||
// grep: vjs-layout-medium
|
||||
// grep: vjs-layout-large
|
||||
// grep: vjs-layout-x-large
|
||||
// grep: vjs-layout-huge
|
||||
BREAKPOINT_ORDER.forEach(k => {
|
||||
const v = k.charAt(0) === 'x' ? `x-${k.substring(1)}` : k;
|
||||
|
||||
BREAKPOINT_CLASSES[k] = `vjs-layout-${v}`;
|
||||
});
|
||||
|
||||
const DEFAULT_BREAKPOINTS = {
|
||||
tiny: 210,
|
||||
xsmall: 320,
|
||||
small: 425,
|
||||
medium: 768,
|
||||
large: 1440,
|
||||
xlarge: 2560,
|
||||
huge: Infinity
|
||||
};
|
||||
|
||||
/**
|
||||
* An instance of the `Player` class is created when any of the Video.js setup methods
|
||||
* are used to initialize a video.
|
||||
@ -487,6 +522,8 @@ class Player extends Component {
|
||||
this.on('fullscreenchange', this.handleFullscreenChange_);
|
||||
this.on('stageclick', this.handleStageClick_);
|
||||
|
||||
this.setBreakpoints(this.options_.breakpoints);
|
||||
|
||||
this.changingSrc_ = false;
|
||||
this.playWaitingForReady_ = false;
|
||||
this.playOnLoadstart_ = null;
|
||||
@ -3675,6 +3712,96 @@ class Player extends Component {
|
||||
return modal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change layout breakpoint classes when the player resizes.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updateCurrentBreakpoint_() {
|
||||
if (!this.breakpoints_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentBreakpoint = this.currentBreakpoint();
|
||||
const currentWidth = this.currentWidth();
|
||||
|
||||
for (let i = 0; i < BREAKPOINT_ORDER.length; i++) {
|
||||
const candidateBreakpoint = BREAKPOINT_ORDER[i];
|
||||
const maxWidth = this.breakpoints_[candidateBreakpoint];
|
||||
|
||||
if (currentWidth <= maxWidth) {
|
||||
|
||||
// The current breakpoint did not change, nothing to do.
|
||||
if (currentBreakpoint === candidateBreakpoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only remove a class if there is a current breakpoint.
|
||||
if (currentBreakpoint) {
|
||||
this.removeClass(BREAKPOINT_CLASSES[currentBreakpoint]);
|
||||
}
|
||||
|
||||
this.addClass(BREAKPOINT_CLASSES[candidateBreakpoint]);
|
||||
this.breakpoint_ = candidateBreakpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set layout breakpoints on the player.
|
||||
*
|
||||
* @param {boolean|Object} breakpoints
|
||||
* A boolean indicating whether breakpoints should or should not be
|
||||
* used - or an object describing custom max widths for the supported
|
||||
* breakpoints.
|
||||
*/
|
||||
setBreakpoints(breakpoints) {
|
||||
const hadBps = Boolean(this.breakpoints_);
|
||||
|
||||
if (!breakpoints) {
|
||||
this.breakpoint_ = null;
|
||||
this.breakpoints_ = null;
|
||||
this.off('playerresize', this.updateCurrentBreakpoint_);
|
||||
return;
|
||||
}
|
||||
|
||||
this.breakpoints_ = assign({}, DEFAULT_BREAKPOINTS);
|
||||
|
||||
if (isObject(breakpoints)) {
|
||||
assign(this.breakpoints_, breakpoints);
|
||||
}
|
||||
|
||||
this.updateCurrentBreakpoint_();
|
||||
|
||||
// If we were not previously supporting breakpoints, add a listener.
|
||||
if (!hadBps) {
|
||||
this.on('playerresize', this.updateCurrentBreakpoint_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current layout breakpoints for the player.
|
||||
*
|
||||
* @return {Object}
|
||||
* An object describing the current layout breakpoints and their
|
||||
* max widths.
|
||||
*/
|
||||
getBreakpoints() {
|
||||
return this.breakpoints_ && assign(this.breakpoints_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current layout breakpoint name, if any.
|
||||
*
|
||||
* @return {string|null}
|
||||
* If there is currently a layout breakpoint set, returns a the key
|
||||
* from the breakpoints object matching it. Otherwise, returns `null`.
|
||||
*/
|
||||
currentBreakpoint() {
|
||||
return this.breakpoint_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tag settings
|
||||
*
|
||||
@ -3874,7 +4001,9 @@ Player.prototype.options_ = {
|
||||
languages: {},
|
||||
|
||||
// Default message to show when a video cannot be played.
|
||||
notSupportedMessage: 'No compatible source was found for this media.'
|
||||
notSupportedMessage: 'No compatible source was found for this media.',
|
||||
|
||||
breakpoints: false
|
||||
};
|
||||
|
||||
[
|
||||
|
@ -265,7 +265,7 @@ function testHelperMakeTag() {
|
||||
const videoTag = document.createElement('video');
|
||||
|
||||
videoTag.id = 'example_1';
|
||||
videoTag.className = 'video-js vjs-default-skin';
|
||||
videoTag.className = 'video-js';
|
||||
return videoTag;
|
||||
}
|
||||
|
||||
|
92
test/unit/player-breakpoints.test.js
Normal file
92
test/unit/player-breakpoints.test.js
Normal file
@ -0,0 +1,92 @@
|
||||
/* eslint-env qunit */
|
||||
import sinon from 'sinon';
|
||||
import TestHelpers from './test-helpers';
|
||||
import {assign} from '../../src/js/utils/obj';
|
||||
|
||||
const getExpectedBreakpoints = (o) => assign({}, {
|
||||
tiny: 210,
|
||||
xsmall: 320,
|
||||
small: 425,
|
||||
medium: 768,
|
||||
large: 1440,
|
||||
xlarge: 2560,
|
||||
huge: Infinity
|
||||
}, o);
|
||||
|
||||
QUnit.module('Player: Breakpoints', {
|
||||
|
||||
beforeEach() {
|
||||
this.clock = sinon.useFakeTimers();
|
||||
this.player = TestHelpers.makePlayer({});
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
this.player.dispose();
|
||||
this.clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('breakpoints are disabled by default', function(assert) {
|
||||
assert.strictEqual(this.player.getBreakpoints(), null, 'no breakpoints defined');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), null, 'no current breakpoint set');
|
||||
});
|
||||
|
||||
QUnit.test('setting default breakpoints', function(assert) {
|
||||
this.player.setBreakpoints(true);
|
||||
assert.deepEqual(this.player.getBreakpoints(), getExpectedBreakpoints(), 'breakpoints defined');
|
||||
|
||||
// Player should be 300x150 by default.
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'xsmall', 'current breakpoint set');
|
||||
});
|
||||
|
||||
QUnit.test('setting custom breakpoints', function(assert) {
|
||||
this.player.setBreakpoints({tiny: 300});
|
||||
assert.deepEqual(this.player.getBreakpoints(), getExpectedBreakpoints({tiny: 300}), 'breakpoints defined');
|
||||
|
||||
// Player should be 300x150 by default.
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'tiny', 'current breakpoint set');
|
||||
});
|
||||
|
||||
QUnit.test('setting breakpoints via option', function(assert) {
|
||||
const player = TestHelpers.makePlayer({breakpoints: {tiny: 300}});
|
||||
|
||||
assert.deepEqual(player.getBreakpoints(), getExpectedBreakpoints({tiny: 300}), 'breakpoints defined');
|
||||
|
||||
// Player should be 300x150 by default.
|
||||
assert.strictEqual(player.currentBreakpoint(), 'tiny', 'current breakpoint set');
|
||||
});
|
||||
|
||||
QUnit.test('changing the player size triggers breakpoints', function(assert) {
|
||||
let currentWidth;
|
||||
|
||||
this.player.setBreakpoints(true);
|
||||
this.player.currentWidth = () => currentWidth;
|
||||
|
||||
currentWidth = 200;
|
||||
this.player.trigger('playerresize');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'tiny', 'current breakpoint is correct');
|
||||
|
||||
currentWidth = 300;
|
||||
this.player.trigger('playerresize');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'xsmall', 'current breakpoint is correct');
|
||||
|
||||
currentWidth = 400;
|
||||
this.player.trigger('playerresize');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'small', 'current breakpoint is correct');
|
||||
|
||||
currentWidth = 600;
|
||||
this.player.trigger('playerresize');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'medium', 'current breakpoint is correct');
|
||||
|
||||
currentWidth = 900;
|
||||
this.player.trigger('playerresize');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'large', 'current breakpoint is correct');
|
||||
|
||||
currentWidth = 1600;
|
||||
this.player.trigger('playerresize');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'xlarge', 'current breakpoint is correct');
|
||||
|
||||
currentWidth = 3000;
|
||||
this.player.trigger('playerresize');
|
||||
assert.strictEqual(this.player.currentBreakpoint(), 'huge', 'current breakpoint is correct');
|
||||
});
|
@ -7,7 +7,7 @@ const TestHelpers = {
|
||||
const videoTag = document.createElement('video');
|
||||
|
||||
videoTag.id = 'example_1';
|
||||
videoTag.className = 'video-js vjs-default-skin';
|
||||
videoTag.className = 'video-js';
|
||||
return videoTag;
|
||||
},
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user