Loop functionality

This commit is contained in:
Chrysa Papadopoulou 2017-02-01 19:16:39 +02:00
parent ea30ad9494
commit 45c0ded88c
4 changed files with 203 additions and 10 deletions

View File

@ -21,7 +21,7 @@
captions: {
defaultActive: true
},
controls: ['play', 'speed-up', 'speed-down', 'progress', 'volume', 'captions', 'settings', 'fullscreen', 'fast-forward']
controls: ['play', 'progress', 'volume', 'captions', 'settings', 'fullscreen', 'fast-forward']
});
plyr.loadSprite('dist/demo.svg');

4
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

View File

@ -257,7 +257,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
<tr>
<td><code>controls</code></td>
<td>Array</td>
<td><code>['play-large', 'play', 'speed-up', 'progress', 'current-time', 'mute', 'volume', 'captions', 'fullscreen']</code></td>
<td><code>['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'fullscreen']</code></td>
<td>Toggle which control elements you would like to display when using the default controls html. If you specify a <code>html</code> option, this is redundant. The default value is to display everything.</td>
</tr>
<tr>
@ -402,6 +402,12 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
<td>[1.0, 1.5, 2.0, 0.5]</td>
<td>Playback speed list.</td>
</tr>
<tr>
<td><code>loops</code></td>
<td>Array</td>
<td>[Loop All, Loop in, Loop out, No Loop]</td>
<td>Playback loop list.</td>
</tr>
</tbody>
</table>

View File

@ -38,6 +38,8 @@
debug: false,
autoplay: false,
loop: false,
loopin: 0,
loopout: null,
seekTime: 10,
volume: 10,
volumeMin: 0,
@ -86,7 +88,11 @@
settings: '[data-plyr="settings"]',
pip: '[data-plyr="pip"]',
airplay: '[data-plyr="airplay"]',
speed: '[data-plyr="speed"]'
speed: '[data-plyr="speed"]',
loopin: '[data-plyr="loopin"]',
loopout: '[data-plyr="loopout"]',
loopall: '[data-plyr="loopall"]',
loopclear: '[data-plyr="loopclear"]',
},
volume: {
input: '[data-plyr="volume"]',
@ -163,7 +169,12 @@
captions: 'Captions',
settings: 'Settings',
speed: 'Speed',
quality: 'Quality'
quality: 'Quality',
loop: 'Loop',
loopin: 'Loop in',
loopout: 'Loop out',
loopall: 'Loop all',
loopclear: 'No Loop',
},
types: {
embed: ['youtube', 'vimeo', 'soundcloud'],
@ -193,7 +204,11 @@
volume: null,
captions: null,
fullscreen: null,
speed: null
speed: null,
loopin: null,
loopout: null,
loopall: null,
loopclear: null
},
// Events to watch on HTML5 media elements
events: ['ready', 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied'],
@ -997,6 +1012,12 @@
'<span class="plyr__menu__value">Auto</span>',
'</button>',
'</li>',
'<li role="tab">',
'<button type="button" class="plyr__control plyr__control--forward" id="plyr-settings-{id}-loop-toggle" aria-haspopup="true" aria-controls="plyr-settings-{id}-loop" aria-expanded="false">',
config.i18n.loop +
'<span class="plyr__menu__value" data-menu="loop"></span>',
'</button>',
'</li>',
'</ul>',
'</div>',
'<div class="plyr__menu__secondary" id="plyr-settings-{id}-captions" aria-hidden="true" aria-labelled-by="plyr-settings-{id}-captions-toggle" role="tabpanel" tabindex="-1">',
@ -1104,6 +1125,38 @@
'</li>',
'</ul>',
'</div>',
'<div class="plyr__menu__secondary" id="plyr-settings-{id}-loop" aria-hidden="true" aria-labelled-by="plyr-settings-{id}-loop-toggle" role="tabpanel" tabindex="-1">',
'<ul>',
'<li role="tab">',
'<button type="button" class="plyr__control plyr__control--back" aria-haspopup="true" aria-controls="plyr-settings-{id}-primary" aria-expanded="false">',
config.i18n.loop,
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loopall">',
config.i18n.loopall,
'<span data-loop__value="loopall"></span>',
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loopin">',
config.i18n.loopin + ':&nbsp;',
'<span data-loop__value="loopin"></span>',
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loopout">',
config.i18n.loopout + ':&nbsp;',
'<span data-loop__value="loopout"></span>',
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loopclear">',
config.i18n.loopclear,
'</button>',
'</li>',
'</ul>',
'</div>',
'</div>',
'</div>',
'</div>'
@ -1278,6 +1331,35 @@
}
}
// Setup Loop
function setupLoop() {
if (!plyr.supported.full) {
return;
}
if ((plyr.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
// Check for native support
var nativeSupport = support.fullscreen;
if (nativeSupport || (config.fullscreen.fallback && !inFrame())) {
log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled');
// Add styling hook
toggleClass(plyr.container, config.classes.fullscreen.enabled, true);
} else {
log('Fullscreen not supported and fallback disabled');
}
// Toggle state
if (plyr.buttons && plyr.buttons.fullscreen) {
toggleState(plyr.buttons.fullscreen, false);
}
// Setup focus trap
focusTrap();
}
}
// Display active caption if it contains text
function setActiveCue(track) {
// Get the track from the event if needed
@ -1715,7 +1797,11 @@
fullscreen: getElement(config.selectors.buttons.fullscreen),
settings: getElement(config.selectors.buttons.settings),
pip: getElement(config.selectors.buttons.pip),
speed: document.querySelectorAll(config.selectors.buttons.speed)
speed: document.querySelectorAll(config.selectors.buttons.speed),
loopin: document.querySelectorAll(config.selectors.buttons.loopin),
loopout: document.querySelectorAll(config.selectors.buttons.loopout),
loopall: document.querySelectorAll(config.selectors.buttons.loopall),
loopclear: document.querySelectorAll(config.selectors.buttons.loopclear)
};
// Inputs
@ -2410,6 +2496,50 @@
return toggle;
}
// Toggle loop
function toggleLoop(toggle) {
if (['loopin', 'loopout', 'loopall'].indexOf(toggle) === -1) {
toggle = 'loopclear';
}
var currentTime = Number(plyr.media.currentTime);
switch(toggle) {
case 'loopin':
if (config.loopout && config.loopout <= currentTime) {
config.loopout = null;
}
config.loopin = currentTime;
break;
case 'loopout':
if (config.loopin >= currentTime) {
return;
}
config.loopout = currentTime;
break;
case 'loopall':
config.loopin = 0;
config.loopout = plyr.media.duration - 2;
break;
default:
config.loopin = 0;
config.loopout = null;
break;
}
//check if can loop
config.loop = is.number(config.loopin) && is.number(config.loopout);
var loopin = updateTimeDisplay(config.loopin, document.querySelector('[data-loop__value="loopin"]'));
var loopout = is.number(config.loopout) ? updateTimeDisplay(config.loopout, document.querySelector('[data-loop__value="loopout"]')) : null;
if (config.loop) {
document.querySelector('[data-menu="loop"]').innerHTML = loopin + ' - ' + loopout;
} else {
document.querySelector('[data-menu="loop"]').innerHTML = config.i18n.loopclear;
}
}
// Speed-up
function setSpeed(speed) {
// Load speed from storage or default value
@ -2776,6 +2906,36 @@
}
}
// Update volume UI and storage
function updateLoop() {
// Get the current volume
var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
// Update the <input type="range"> if present
if (plyr.supported.full) {
if (plyr.volume.input) {
plyr.volume.input.value = volume;
}
if (plyr.volume.display) {
plyr.volume.display.value = volume;
}
}
// Update the volume in storage
updateStorage({
volume: volume
});
// Toggle class if muted
toggleClass(plyr.container, config.classes.muted, (volume === 0));
// Update checkbox for mute state
if (plyr.supported.full && plyr.buttons.mute) {
toggleState(plyr.buttons.mute, (volume === 0));
}
}
// Toggle captions
function toggleCaptions(show) {
// If there's no full support, or there's no caption toggle
@ -2885,7 +3045,10 @@
}
}
// Set values
if (is.number(config.loopin) && is.number(config.loopout) && plyr.media.currentTime >= config.loopout) {
seek(config.loopin);
}
setProgress(progress, value);
}
@ -2945,8 +3108,10 @@
plyr.secs = ('0' + plyr.secs).slice(-2);
plyr.mins = ('0' + plyr.mins).slice(-2);
var txt = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs;
// Render
element.innerHTML = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs;
element.innerHTML = txt;
return txt;
}
// Show the duration on metadataloaded
@ -3577,6 +3742,20 @@
// Fullscreen
proxy(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, toggleFullscreen);
// Loop
proxy(plyr.buttons.loopall, 'click', config.listeners.loopall, function () {
toggleLoop('loopall');
});
proxy(plyr.buttons.loopin, 'click', config.listeners.loopin, function(){
toggleLoop('loopin');
});
proxy(plyr.buttons.loopout, 'click', config.listeners.loopout, function () {
toggleLoop('loopout');
});
proxy(plyr.buttons.loopclear, 'click', config.listeners.loopclear, function () {
toggleLoop('loopclear');
});
// Handle user exiting fullscreen by escaping etc
if (support.fullscreen) {
on(document, fullscreen.eventType, toggleFullscreen);
@ -4019,6 +4198,10 @@
// Set playback speed
setSpeed();
// Set loop
toggleLoop();
// Reset time display
timeUpdate();
@ -4061,12 +4244,16 @@
isPaused: function() {
return plyr.media.paused;
},
isLooping: function() {
return config.loopin && config.loopout;
},
on: function(event, callback) {
on(plyr.container, event, callback);
return this;
},
play: play,
pause: pause,
loop: toggleLoop,
stop: function() {
pause();
seek();