Small tweaks

This commit is contained in:
Sam Potts 2017-11-04 21:19:02 +11:00
parent 069c8093ae
commit d920de2a25
21 changed files with 234 additions and 167 deletions

2
demo/dist/demo.css vendored

File diff suppressed because one or more lines are too long

2
demo/dist/error.css vendored

File diff suppressed because one or more lines are too long

View File

@ -78,18 +78,18 @@
<ul>
<li class="plyr__cite plyr__cite--video" hidden>
<small>
<a href="http://viewfromabluemoon.com/" target="_blank">
<svg class="icon" title="HTML5">
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
</svg>View From A Blue Moon</a> &copy; Brainfarm
<svg class="icon" title="HTML5">
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
</svg>
<a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> &copy; Brainfarm
</small>
</li>
<li class="plyr__cite plyr__cite--audio" hidden>
<small>
<a href="http://www.kishibashi.com/" target="_blank">
<svg class="icon" title="HTML5">
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
</svg>Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; Kishi Bashi
<svg class="icon" title="HTML5">
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
</svg>
<a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; Kishi Bashi
</small>
</li>
<li class="plyr__cite plyr__cite--youtube" hidden>

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -83,7 +83,7 @@ const pkg = loadJSON(path.join(root, 'package.json'));
const sizeOptions = { showFiles: true, gzip: true };
// Browserlist
const browsers = ['> 1%', 'last 2 versions'];
const browsers = ['> 1%'];
// Babel config
const babelrc = {

View File

@ -65,5 +65,6 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Sam Potts <sam@potts.es>"
"author": "Sam Potts <sam@potts.es>",
"dependencies": {}
}

47
src/js/controls.js vendored
View File

@ -4,6 +4,7 @@
import support from './support';
import utils from './utils';
import ui from './ui';
const controls = {
// Webkit polyfill for lower fill range
@ -300,6 +301,52 @@ const controls = {
return container;
},
// Update hover tooltip for seeking
updateSeekTooltip(event) {
// Bail if setting not true
if (
!this.config.tooltips.seek ||
!utils.is.htmlElement(this.elements.inputs.seek) ||
!utils.is.htmlElement(this.elements.display.seekTooltip) ||
this.duration === 0
) {
return;
}
// Calculate percentage
let percent = 0;
const clientRect = this.elements.inputs.seek.getBoundingClientRect();
const visible = `${this.config.classNames.tooltip}--visible`;
// Determine percentage, if already visible
if (utils.is.event(event)) {
percent = 100 / clientRect.width * (event.pageX - clientRect.left);
} else if (utils.hasClass(this.elements.display.seekTooltip, visible)) {
percent = this.elements.display.seekTooltip.style.left.replace('%', '');
} else {
return;
}
// Set bounds
if (percent < 0) {
percent = 0;
} else if (percent > 100) {
percent = 100;
}
// Display the time a click would seek to
ui.updateTimeDisplay.call(this, this.duration / 100 * percent, this.elements.display.seekTooltip);
// Set position
this.elements.display.seekTooltip.style.left = `${percent}%`;
// Show/hide the tooltip
// If the event is a moues in/out and percentage is inside bounds
if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {
utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter');
}
},
// Hide/show a tab
toggleTab(setting, toggle) {
const tab = this.elements.settings.tabs[setting];

View File

@ -360,61 +360,81 @@ const listeners = {
});
// Trigger custom and default handlers
const handlerProxy = (event, customHandler, defaultHandler) => {
const proxy = (event, handlerKey, defaultHandler) => {
const customHandler = this.config.listeners[handleKey];
// Execute custom handler
if (utils.is.function(customHandler)) {
customHandler.call(this, event);
}
if (utils.is.function(defaultHandler)) {
// Only call default handler if not prevented in custom handler
if (!event.defaultPrevented && utils.is.function(defaultHandler)) {
defaultHandler.call(this, event);
}
};
// Play
utils.proxy(this.elements.buttons.play, 'click', this.config.listeners.play, togglePlay);
utils.proxy(this.elements.buttons.playLarge, 'click', this.config.listeners.play, togglePlay);
utils.on(this.elements.buttons.play, 'click', event => proxy(event, 'play', togglePlay));
// Pause
utils.proxy(this.elements.buttons.pause, 'click', this.config.listeners.pause, togglePlay);
utils.on(this.elements.buttons.pause, 'click', event => proxy(event, 'pause', togglePlay));
// Pause
utils.proxy(this.elements.buttons.restart, 'click', this.config.listeners.restart, () => {
this.restart();
});
utils.on(this.elements.buttons.restart, 'click', event =>
proxy(event, 'restart', () => {
this.restart();
})
);
// Rewind
utils.proxy(this.elements.buttons.rewind, 'click', this.config.listeners.rewind, () => {
this.rewind();
});
utils.on(this.elements.buttons.rewind, 'click', event =>
proxy(event, 'rewind', () => {
this.rewind();
})
);
// Rewind
utils.proxy(this.elements.buttons.forward, 'click', this.config.listeners.forward, () => {
this.forward();
});
utils.on(this.elements.buttons.forward, 'click', event =>
proxy(event, 'forward', () => {
this.forward();
})
);
// Mute
utils.proxy(this.elements.buttons.mute, 'click', this.config.listeners.mute, () => {
this.toggleMute();
});
utils.on(this.elements.buttons.mute, 'click', event =>
proxy(event, 'mute', () => {
this.toggleMute();
})
);
// Captions
utils.proxy(this.elements.buttons.captions, 'click', this.config.listeners.captions, () => {
this.toggleCaptions();
});
utils.on(this.elements.buttons.captions, 'click', event =>
proxy(event, 'captions', () => {
this.toggleCaptions();
})
);
// Fullscreen
utils.proxy(this.elements.buttons.fullscreen, 'click', this.config.listeners.fullscreen, () => {
this.toggleFullscreen();
});
utils.on(this.elements.buttons.fullscreen, 'click', event =>
proxy(event, 'fullscreen', () => {
this.toggleFullscreen();
})
);
// Picture-in-Picture
utils.proxy(this.elements.buttons.pip, 'click', this.config.listeners.pip, () => {
this.togglePictureInPicture();
});
utils.on(this.elements.buttons.pip, 'click', event =>
proxy(event, 'pip', () => {
this.togglePictureInPicture();
})
);
// Airplay
utils.proxy(this.elements.buttons.airplay, 'click', this.config.listeners.airplay, () => {
this.airPlay();
});
utils.on(this.elements.buttons.airplay, 'click', event =>
proxy(event, 'airplay', () => {
this.airPlay();
})
);
// Settings menu
utils.on(this.elements.buttons.settings, 'click', event => {
@ -434,24 +454,24 @@ const listeners = {
// Settings menu items - use event delegation as items are added/removed
// Settings - Language
if (utils.matches(event.target, this.config.selectors.inputs.language)) {
handlerProxy.call(this, event, this.config.listeners.language, () => {
proxy(event, 'language', () => {
this.toggleCaptions(true);
this.language = event.target.value.toLowerCase();
});
} else if (utils.matches(event.target, this.config.selectors.inputs.quality)) {
// Settings - Quality
handlerProxy.call(this, event, this.config.listeners.quality, () => {
proxy(event, 'quality', () => {
this.quality = event.target.value;
});
} else if (utils.matches(event.target, this.config.selectors.inputs.speed)) {
// Settings - Speed
handlerProxy.call(this, event, this.config.listeners.speed, () => {
proxy(event, 'speed', () => {
this.speed = parseFloat(event.target.value);
});
} else if (utils.matches(event.target, this.config.selectors.buttons.loop)) {
// Settings - Looping
// TODO: use toggle buttons
handlerProxy.call(this, event, this.config.listeners.loop, () => {
proxy(event, 'loop', () => {
// TODO: This should be done in the method itself I think
// var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type');
@ -461,14 +481,18 @@ const listeners = {
});
// Seek
utils.proxy(this.elements.inputs.seek, inputEvent, this.config.listeners.seek, event => {
this.currentTime = event.target.value / event.target.max * this.duration;
});
utils.on(this.elements.inputs.seek, inputEvent, event =>
proxy(event, 'seek', () => {
this.currentTime = event.target.value / event.target.max * this.duration;
})
);
// Volume
utils.proxy(this.elements.inputs.volume, inputEvent, this.config.listeners.volume, event => {
this.volume = event.target.value;
});
utils.on(this.elements.inputs.volume, inputEvent, event =>
proxy(event, 'volume', () => {
this.volume = event.target.value;
})
);
// Polyfill for lower fill in <input type="range"> for webkit
if (this.browser.isWebkit) {
@ -479,7 +503,7 @@ const listeners = {
// Seek tooltip
utils.on(this.elements.progress, 'mouseenter mouseleave mousemove', event =>
ui.updateSeekTooltip.call(this, event)
controls.updateSeekTooltip.call(this, event)
);
// Toggle controls visibility based on mouse movement
@ -516,44 +540,44 @@ const listeners = {
}
// Mouse wheel for volume
utils.proxy(
utils.on(
this.elements.inputs.volume,
'wheel',
this.config.listeners.volume,
event => {
// Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves
const inverted = event.webkitDirectionInvertedFromDevice;
const step = 1 / 50;
let direction = 0;
event =>
proxy(event, 'volume', () => {
// Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves
const inverted = event.webkitDirectionInvertedFromDevice;
const step = 1 / 50;
let direction = 0;
// Scroll down (or up on natural) to decrease
if (event.deltaY < 0 || event.deltaX > 0) {
if (inverted) {
this.decreaseVolume(step);
direction = -1;
} else {
this.increaseVolume(step);
direction = 1;
// Scroll down (or up on natural) to decrease
if (event.deltaY < 0 || event.deltaX > 0) {
if (inverted) {
this.decreaseVolume(step);
direction = -1;
} else {
this.increaseVolume(step);
direction = 1;
}
}
}
// Scroll up (or down on natural) to increase
if (event.deltaY > 0 || event.deltaX < 0) {
if (inverted) {
this.increaseVolume(step);
direction = 1;
} else {
this.decreaseVolume(step);
direction = -1;
// Scroll up (or down on natural) to increase
if (event.deltaY > 0 || event.deltaX < 0) {
if (inverted) {
this.increaseVolume(step);
direction = 1;
} else {
this.decreaseVolume(step);
direction = -1;
}
}
}
// Don't break page scrolling at max and min
if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) {
event.preventDefault();
}
},
// Don't break page scrolling at max and min
if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) {
event.preventDefault();
}
}),
false
);

View File

@ -77,6 +77,34 @@ const vimeo = {
player.media.paused = true;
player.media.currentTime = 0;
let { currentTime } = player.media;
// Seeking
Object.defineProperty(player.media, 'currentTime', {
get() {
return currentTime;
},
set(time) {
// Get current paused state
const { paused } = player.media;
player.warn('called');
// Set seeking flag
player.media.seeking = true;
// Trigger seeking
utils.dispatchEvent.call(player, player.media, 'seeking');
// Seek after events
player.embed.setCurrentTime(time);
// Restore pause state
if (paused) {
this.pause();
}
},
});
// Playback speed
// Not currently supported in Vimeo
@ -88,10 +116,10 @@ const vimeo = {
});
// Rebuild UI
ui.build.call(player);
window.setTimeout(() => ui.build.call(player), 0);
player.embed.getCurrentTime().then(value => {
player.media.currentTime = value;
currentTime = value;
utils.dispatchEvent.call(this, this.media, 'timeupdate');
});
@ -103,7 +131,6 @@ const vimeo = {
// Get captions
player.embed.getTextTracks().then(tracks => {
player.captions.tracks = tracks;
captions.setup.call(player);
});
@ -121,10 +148,6 @@ const vimeo = {
if (utils.is.htmlElement(player.embed.element) && player.supported.ui) {
const frame = player.embed.element;
// Fix Vimeo controls issue
// https://github.com/sampotts/plyr/issues/697
// frame.src = `${frame.src}&transparent=0`;
// Fix keyboard focus issues
// https://github.com/sampotts/plyr/issues/317
frame.setAttribute('tabindex', -1);
@ -144,7 +167,7 @@ const vimeo = {
this.embed.on('timeupdate', data => {
this.media.seeking = false;
this.media.currentTime = data.seconds;
currentTime = data.seconds;
utils.dispatchEvent.call(this, this.media, 'timeupdate');
});

View File

@ -118,6 +118,23 @@ const youtube = {
player.media.muted = instance.isMuted();
player.media.currentTime = 0;
// Seeking
Object.defineProperty(player.media, 'currentTime', {
get() {
return Number(instance.getCurrentTime());
},
set(time) {
// Set seeking flag
player.media.seeking = true;
// Trigger seeking
utils.dispatchEvent.call(player, player.media, 'seeking');
// Seek after events sent
instance.seekTo(time);
},
});
// Playback speed
Object.defineProperty(player.media, 'playbackRate', {
get() {
@ -142,7 +159,7 @@ const youtube = {
}
// Rebuild UI
ui.build.call(player);
window.setTimeout(() => ui.build.call(player), 0);
utils.dispatchEvent.call(player, player.media, 'timeupdate');
utils.dispatchEvent.call(player, player.media, 'durationchange');
@ -218,7 +235,7 @@ const youtube = {
// Poll to get playback progress
player.timers.playing = window.setInterval(() => {
player.media.currentTime = instance.getCurrentTime();
// player.media.currentTime = instance.getCurrentTime();
utils.dispatchEvent.call(player, player.media, 'timeupdate');
}, 100);

View File

@ -323,7 +323,7 @@ class Plyr {
// Set the current time
// TODO: This should be included in the "adapters"
// Embeds
if (this.isEmbed) {
/* if (this.isEmbed) {
// Get current paused state
const { paused } = this.media;
@ -351,8 +351,10 @@ class Plyr {
// Trigger seeking
utils.dispatchEvent.call(this, this.media, 'seeking');
} else {
this.media.currentTime = targetTime.toFixed(4);
}
} */
this.media.currentTime = targetTime.toFixed(4);
// Logging
this.log(`Seeking to ${this.currentTime} seconds`);
@ -408,6 +410,7 @@ class Plyr {
this.media.volume = volume;
// Trigger volumechange for embeds
// TODO: Do in adapters
if (this.isEmbed) {
// Set media volume
switch (this.type) {

View File

@ -16,8 +16,6 @@ const source = {
src: attributes,
});
} else if (utils.is.array(attributes)) {
this.warn(attributes);
attributes.forEach(attribute => {
utils.insertElement(type, this.media, attribute);
});

View File

@ -114,7 +114,7 @@ const ui = {
}
// Update the tooltip (if visible)
ui.updateSeekTooltip.call(this);
controls.updateSeekTooltip.call(this);
},
// Setup aria attribute for play and iframe title
@ -330,52 +330,6 @@ const ui = {
// Playing progress
ui.updateProgress.call(this, event);
},
// Update hover tooltip for seeking
updateSeekTooltip(event) {
// Bail if setting not true
if (
!this.config.tooltips.seek ||
!utils.is.htmlElement(this.elements.inputs.seek) ||
!utils.is.htmlElement(this.elements.display.seekTooltip) ||
this.duration === 0
) {
return;
}
// Calculate percentage
const clientRect = this.elements.inputs.seek.getBoundingClientRect();
let percent = 0;
const visible = `${this.config.classNames.tooltip}--visible`;
// Determine percentage, if already visible
if (utils.is.event(event)) {
percent = 100 / clientRect.width * (event.pageX - clientRect.left);
} else if (utils.hasClass(this.elements.display.seekTooltip, visible)) {
percent = this.elements.display.seekTooltip.style.left.replace('%', '');
} else {
return;
}
// Set bounds
if (percent < 0) {
percent = 0;
} else if (percent > 100) {
percent = 100;
}
// Display the time a click would seek to
ui.updateTimeDisplay.call(this, this.duration / 100 * percent, this.elements.display.seekTooltip);
// Set position
this.elements.display.seekTooltip.style.left = `${percent}%`;
// Show/hide the tooltip
// If the event is a moues in/out and percentage is inside bounds
if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {
utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter');
}
},
};
export default ui;

View File

@ -391,22 +391,6 @@ const utils = {
);
},
// Bind along with custom handler
proxy(element, eventName, customListener, defaultListener, passive, capture) {
utils.on(
element,
eventName,
event => {
if (customListener) {
customListener.apply(element, [event]);
}
defaultListener.apply(element, [event]);
},
passive,
capture
);
},
// Toggle event listener
toggleListener(elements, event, callback, toggle, passive, capture) {
// Bail if no elements
@ -415,7 +399,7 @@ const utils = {
}
// If a nodelist is passed, call itself on each node
if (elements instanceof NodeList) {
if (utils.is.nodeList(elements)) {
// Create listener for each node
Array.from(elements).forEach(element => {
if (element instanceof Node) {

View File

@ -9,8 +9,10 @@
min-width: 200px;
font-family: @plyr-font-family;
font-weight: @plyr-font-weight-normal;
line-height: @plyr-line-height;
direction: ltr;
text-shadow: none;
.plyr-font-smoothing(off);
// Media elements
video,

View File

@ -8,4 +8,5 @@
background: @plyr-menu-color;
color: @plyr-menu-bg;
font-size: @plyr-font-size-tiny;
.plyr-font-smoothing(on);
}

View File

@ -15,10 +15,11 @@
width: 100%;
padding: @plyr-control-spacing;
transform: translateY(-(@plyr-control-spacing * 4));
transition: transform 0.3s ease;
transition: transform 0.4s ease-in-out;
color: @plyr-captions-color;
font-size: @plyr-font-size-captions-small;
text-align: center;
.plyr-font-smoothing(on);
span {
border-radius: 2px;

View File

@ -3,6 +3,17 @@
// https://github.com/sampotts/plyr
// ==========================================================================
// Font smoothing
// ---------------------------------------
.plyr-font-smoothing(@mode: on) when(@mode = on) {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
.plyr-font-smoothing(@mode: on) when(@mode = off) {
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: subpixel-antialiased;
}
// <input type="range"> styling
.plyr-range-track() {
height: @plyr-range-track-height;

View File

@ -12,12 +12,13 @@
@plyr-color-main: #1aafff;
// Font
@plyr-font-family: inherit; //Avenir, 'Avenir Next', 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif;
@plyr-font-family: Avenir, 'Avenir Next', 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif;
@plyr-font-size-base: 16px;
@plyr-font-size-small: 14px;
@plyr-font-size-tiny: 10px;
@plyr-font-weight-normal: 500;
@plyr-font-weight-bold: 600;
@plyr-line-height: 1.7;
// Captions
@plyr-captions-bg: fade(#000, 80%);