Skip to content

Commit

Permalink
Refactor video factory to display active video.
Browse files Browse the repository at this point in the history
Resolves #245.
  • Loading branch information
blueimp committed Jun 7, 2020
1 parent 911b1b4 commit 288b74e
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 65 deletions.
97 changes: 93 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
- [API methods](#api-methods)
- [Videos](#videos)
- [HTML5 video player](#html5-video-player)
- [Video controls](#video-controls)
- [Video preloading](#video-preloading)
- [Fullscreen video](#fullscreen-video)
- [Multiple video sources](#multiple-video-sources)
- [YouTube](#youtube)
- [Vimeo](#vimeo)
Expand All @@ -44,7 +47,6 @@
- [Browser support](#browser-support)
- [License](#license)
- [Credits](#credits)
- [Notable forks](#notable-forks)

## Description

Expand Down Expand Up @@ -165,8 +167,8 @@ the images in the Gallery lightbox on click of one of those links:

### Controls

To initialize the Gallery with visible controls, add the CSS class
`blueimp-gallery-controls` to the Gallery widget:
To initialize the Gallery with visible controls (previous slide, next slide,
etc.), add the CSS class `blueimp-gallery-controls` to the Gallery widget:

```html
<div
Expand All @@ -180,6 +182,10 @@ To initialize the Gallery with visible controls, add the CSS class
</div>
```

Please also note that by default, a click on an image slide or any Gallery
widget element with the `toggle` class will toggle the display of the Gallery
controls.

### Contain

To stretch smaller images to the dimensions of the Gallery container while
Expand Down Expand Up @@ -590,6 +596,12 @@ var videoFactoryOptions = {
videoLoadingClass: 'video-loading',
// The class for video when it is playing:
videoPlayingClass: 'video-playing',
// The class for video content displayed in an iframe:
videoIframeClass: 'video-iframe',
// The class for the video cover element:
videoCoverClass: 'video-cover',
// The class for the video play control:
videoPlayClass: 'video-play',
// Play videos inline by default:
videoPlaysInline: true,
// The list object property (or data attribute) for video preload:
Expand Down Expand Up @@ -828,10 +840,87 @@ if the browser supports the video content type.
For videos, the `poster` property defines the URL of the poster image to
display, before the video is started.

#### Video controls

To start video playback, you can either click on the video play icon or on the
video slide itself.
Starting the video playback enables the native HTML5 video
[controls](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-controls).

To toggle the Gallery controls (previous slide, next slide, etc.) instead of
starting video playback on click of a video slide, add the `toggle` class to the
video cover element using the `videoCoverClass` Gallery option:

```js
blueimp.Gallery(
[
{
title: 'Fruits',
type: 'video/mp4',
href: 'https://example.org/videos/fruits.mp4',
poster: 'https://example.org/images/fruits.jpg'
}
],
{
videoCoverClass: 'video-cover toggle'
}
)
```

#### Video preloading

You can set the `preload` property of a Gallery video object to a valid value
defined by the HTML5 video
[preload](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-preload)
attribute:

- `none`: Indicates that the video should not be preloaded.
- `metadata`: Indicates that only video metadata (e.g. length) is fetched.
- `auto`: Indicates that the whole video file can be preloaded.

```js
blueimp.Gallery([
{
title: 'Fruits',
type: 'video/mp4',
href: 'https://example.org/videos/fruits.mp4',
preload: 'auto'
}
])
```

#### Fullscreen video

By default, videos are displayed with the HTML5 video
[playsinline](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-playsinline)
attribute set, which indicates that the video is to be played inline.
To disable this behavior, you can set the Gallery option `videoPlaysInline` to
`false`:

```js
blueimp.Gallery(
[
{
title: 'Fruits',
type: 'video/mp4',
href: 'https://example.org/videos/fruits.mp4',
poster: 'https://example.org/images/fruits.jpg'
}
],
{
videoPlaysInline: false
}
)
```

Please note that this attribute only has an effect on some browsers, e.g. Safari
on iOS 10 and later.
However, most browser provide video controls to switch to fullscreen mode.

#### Multiple video sources

To provide multiple video formats, the `sources` property of a list object can
be set to an array of objects with `href` and `type` properties for each video
be set to an array of objects with `type` and `src` properties for each video
source. The first video format in the list that the browser can play will be
displayed:

Expand Down
48 changes: 18 additions & 30 deletions css/blueimp-gallery-video.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,25 @@
* https://opensource.org/licenses/MIT
*/

.blueimp-gallery > .slides > .slide > .video-content > video {
.blueimp-gallery > .slides > .slide > .video-content > video,
.blueimp-gallery > .slides > .slide > .video-content > iframe,
.blueimp-gallery > .slides > .slide > .video-content > .video-cover {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
}
.blueimp-gallery > .slides > .slide > .video-content > iframe {
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: 100%;
border: none;
}
.blueimp-gallery > .slides > .slide > .video-playing > iframe {
top: 0;
.blueimp-gallery > .slides > .slide > .video-content > .video-cover {
background: center no-repeat;
background-size: contain;
}
.blueimp-gallery > .slides > .slide > .video-iframe > .video-cover {
background-color: #000;
background-color: rgba(0, 0, 0, 0.7);
}
.blueimp-gallery > .slides > .slide > .video-content > a {
.blueimp-gallery > .slides > .slide > .video-content > .video-play {
position: absolute;
top: 50%;
right: 0;
Expand All @@ -41,41 +40,30 @@
opacity: 0.8;
cursor: pointer;
}
.blueimp-gallery-svgasimg > .slides > .slide > .video-content > a {
.blueimp-gallery-svgasimg > .slides > .slide > .video-content > .video-play {
background-image: url(../img/video-play.svg);
}
.blueimp-gallery > .slides > .slide > .video-playing > a,
.blueimp-gallery > .slides > .slide > .video-playing > img {
.blueimp-gallery > .slides > .slide > .video-playing > .video-play,
.blueimp-gallery > .slides > .slide > .video-playing > .video-cover {
display: none;
}
.blueimp-gallery > .slides > .slide > .video-playing > video {
display: block;
}
.blueimp-gallery > .slides > .slide > .video-loading > a {
.blueimp-gallery > .slides > .slide > .video-loading > .video-play {
background: url(../img/loading.gif) center no-repeat;
background-size: 64px 64px;
}
.blueimp-gallery-smil > .slides > .slide > .video-loading > a {
.blueimp-gallery-smil > .slides > .slide > .video-loading > .video-play {
background-image: url(../img/loading.svg);
}

/* IE7 fixes */
* + html .blueimp-gallery > .slides > .slide > .video-content {
height: 100%;
}
* + html .blueimp-gallery > .slides > .slide > .video-content > a {
* + html .blueimp-gallery > .slides > .slide > .video-content > .video-play {
left: 50%;
margin-left: -64px;
}

.blueimp-gallery > .slides > .slide > .video-content > a:hover {
.blueimp-gallery > .slides > .slide > .video-content > .video-play:hover {
opacity: 1;
}

@supports (object-fit: contain) {
.blueimp-gallery > .slides > .slide > .video-content > img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
84 changes: 53 additions & 31 deletions js/blueimp-gallery-video.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
videoLoadingClass: 'video-loading',
// The class for video when it is playing:
videoPlayingClass: 'video-playing',
// The class for video content displayed in an iframe:
videoIframeClass: 'video-iframe',
// The class for the video cover element:
videoCoverClass: 'video-cover',
// The class for the video play control:
videoPlayClass: 'video-play',
// Play videos inline by default:
videoPlaysInline: true,
// The list object property (or data attribute) for video preload:
Expand All @@ -45,9 +51,11 @@
$.extend(galleryPrototype, {
handleSlide: function (oldIndex, newIndex) {
handleSlide.call(this, oldIndex, newIndex)
if (this.playingVideo) {
this.playingVideo.pause()
}
this.setTimeout(function () {
if (this.activeVideo) {
this.activeVideo.pause()
}
})
},

videoFactory: function (obj, callback, videoInterface) {
Expand All @@ -62,34 +70,42 @@
}
]
var video = videoInterface || document.createElement('video')
var playMediaControl = document.createElement('a')
var coverElement = this.elementPrototype.cloneNode(false)
var playElement = document.createElement('a')
var url = this.getItemProperty(obj, options.urlProperty)
var sources = this.getItemProperty(obj, options.sourcesProperty)
var title = this.getItemProperty(obj, options.titleProperty)
var posterUrl = this.getItemProperty(obj, options.videoPosterProperty)
var posterImage
var playControls = [playElement]
var hasGalleryControls
var isLoading
var hasControls
var i
videoContainer.addClass(options.videoContentClass)
$(playElement).addClass(options.videoPlayClass)
if (
!$(coverElement)
.addClass(options.videoCoverClass)
.hasClass(options.toggleClass)
) {
playControls.push(coverElement)
}
coverElement.draggable = false
if (title) {
videoContainerNode.title = title
playMediaControl.setAttribute('aria-label', title)
playElement.setAttribute('aria-label', title)
}
if (posterUrl) {
video.poster = posterUrl
posterImage = this.imagePrototype.cloneNode(false)
$(posterImage).addClass(options.toggleClass)
posterImage.src = posterUrl
posterImage.draggable = false
posterImage.alt =
this.getItemProperty(obj, this.options.altTextProperty) || title
videoContainerNode.appendChild(posterImage)
// Set as background image instead of as poster video element property:
// - Is accessible for browsers that do not support the video element
// - Is accessible for both video element and iframe video players
// - Avoids visual artifacts in IE with the poster property set
coverElement.style.backgroundImage = 'url("' + posterUrl + '")'
}
if (video.setAttribute && options.videoPlaysInline) {
video.setAttribute('playsinline', '')
if (video.setAttribute) {
if (options.videoPlaysInline) video.setAttribute('playsinline', '')
} else {
videoContainer.addClass(options.videoIframeClass)
}
video.controls = true
video.preload =
this.getItemProperty(obj, options.videoPreloadProperty) || 'none'
if (this.support.source && sources) {
Expand All @@ -100,8 +116,7 @@
}
}
if (url) video.src = url
playMediaControl.href =
url || (sources && sources.length && sources[0].src)
playElement.href = url || (sources && sources.length && sources[0].src)
if (video.play && video.pause) {
;(videoInterface || $(video))
.on('error', function () {
Expand All @@ -113,34 +128,40 @@
videoContainer
.removeClass(that.options.videoLoadingClass)
.removeClass(that.options.videoPlayingClass)
if (hasControls) {
if (hasGalleryControls) {
that.container.addClass(that.options.controlsClass)
}
delete that.playingVideo
video.controls = false
if (video === that.activeVideo) delete that.activeVideo
if (that.interval) {
// Continue slideshow interval
that.play()
}
})
.on('playing', function () {
isLoading = false
coverElement.removeAttribute('style')
videoContainer
.removeClass(that.options.videoLoadingClass)
.addClass(that.options.videoPlayingClass)
if (that.container.hasClass(that.options.controlsClass)) {
hasControls = true
that.container.removeClass(that.options.controlsClass)
} else {
hasControls = false
}
})
.on('play', function () {
// Clear slideshow timeout:
window.clearTimeout(that.timeout)
isLoading = true
videoContainer.addClass(that.options.videoLoadingClass)
that.playingVideo = video
if (that.container.hasClass(that.options.controlsClass)) {
hasGalleryControls = true
that.container.removeClass(that.options.controlsClass)
} else {
hasGalleryControls = false
}
video.controls = true
that.activeVideo = video
})
$(playMediaControl).on('click', function (event) {
$(playControls).on('click', function (event) {
that.preventDefault(event)
that.activeVideo = video
if (isLoading) {
video.pause()
} else {
Expand All @@ -151,7 +172,8 @@
(videoInterface && videoInterface.element) || video
)
}
videoContainerNode.appendChild(playMediaControl)
videoContainerNode.appendChild(coverElement)
videoContainerNode.appendChild(playElement)
this.setTimeout(callback, [
{
type: 'load',
Expand Down

0 comments on commit 288b74e

Please sign in to comment.