aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/js/controls.js33
-rw-r--r--src/js/defaults.js7
-rw-r--r--src/js/fullscreen.js6
-rw-r--r--src/js/i18n.js31
-rw-r--r--src/js/listeners.js209
-rw-r--r--src/js/plugins/ads.js3
-rw-r--r--src/js/plyr.js2
-rw-r--r--src/js/ui.js5
-rw-r--r--src/js/utils.js52
9 files changed, 217 insertions, 131 deletions
diff --git a/src/js/controls.js b/src/js/controls.js
index b0159115..295a2eef 100644
--- a/src/js/controls.js
+++ b/src/js/controls.js
@@ -5,6 +5,7 @@
import support from './support';
import utils from './utils';
import ui from './ui';
+import i18n from './i18n';
import captions from './captions';
// Sniff out the browser
@@ -74,7 +75,7 @@ const controls = {
// Create hidden text label
createLabel(type, attr) {
- let text = this.config.i18n[type];
+ let text = i18n.get(type, this.config);
const attributes = Object.assign({}, attr);
switch (type) {
@@ -126,7 +127,7 @@ const controls = {
createButton(buttonType, attr) {
const button = utils.createElement('button');
const attributes = Object.assign({}, attr);
- let type = buttonType;
+ let type = utils.toCamelCase(buttonType);
let toggle = false;
let label;
@@ -147,7 +148,7 @@ const controls = {
}
// Large play button
- switch (type) {
+ switch (buttonType) {
case 'play':
toggle = true;
label = 'play';
@@ -189,7 +190,7 @@ const controls = {
default:
label = type;
- icon = type;
+ icon = buttonType;
}
// Setup toggle icon and labels
@@ -204,7 +205,7 @@ const controls = {
// Add aria attributes
attributes['aria-pressed'] = false;
- attributes['aria-label'] = this.config.i18n[label];
+ attributes['aria-label'] = i18n.get(label, this.config);
} else {
button.appendChild(controls.createIcon.call(this, icon));
button.appendChild(controls.createLabel.call(this, label));
@@ -238,7 +239,7 @@ const controls = {
for: attributes.id,
class: this.config.classNames.hidden,
},
- this.config.i18n[type],
+ i18n.get(type, this.config),
);
// Seek input
@@ -291,11 +292,11 @@ const controls = {
let suffix = '';
switch (type) {
case 'played':
- suffix = this.config.i18n.played;
+ suffix = i18n.get('played', this.config);
break;
case 'buffer':
- suffix = this.config.i18n.buffered;
+ suffix = i18n.get('buffered', this.config);
break;
default:
@@ -322,7 +323,7 @@ const controls = {
{
class: this.config.classNames.hidden,
},
- this.config.i18n[type],
+ i18n.get(type, this.config),
),
);
@@ -617,7 +618,7 @@ const controls = {
class: this.config.classNames.control,
'data-plyr-loop-action': option,
}),
- this.config.i18n[option]
+ i18n.get(option, this.config)
);
if (['start', 'end'].includes(option)) {
@@ -638,7 +639,7 @@ const controls = {
}
if (!support.textTracks || !captions.getTracks.call(this).length) {
- return this.config.i18n.none;
+ return i18n.get('none', this.config);
}
if (this.captions.active) {
@@ -649,7 +650,7 @@ const controls = {
}
}
- return this.config.i18n.disabled;
+ return i18n.get('disabled', this.config);
},
// Set a list of available captions languages
@@ -679,7 +680,7 @@ const controls = {
// Add the "None" option to turn off captions
tracks.unshift({
language: '',
- label: this.config.i18n.none,
+ label: i18n.get('none', this.config),
});
// Generate options
@@ -927,7 +928,7 @@ const controls = {
// Fast forward button
if (this.config.controls.includes('fast-forward')) {
- container.appendChild(controls.createButton.call(this, 'fastForward'));
+ container.appendChild(controls.createButton.call(this, 'fast-forward'));
}
// Progress
@@ -1069,7 +1070,7 @@ const controls = {
'aria-controls': `plyr-settings-${data.id}-${type}`,
'aria-expanded': false,
}),
- this.config.i18n[type],
+ i18n.get(type, this.config),
);
const value = utils.createElement('span', {
@@ -1109,7 +1110,7 @@ const controls = {
'aria-controls': `plyr-settings-${data.id}-home`,
'aria-expanded': false,
},
- this.config.i18n[type],
+ i18n.get(type, this.config),
);
pane.appendChild(back);
diff --git a/src/js/defaults.js b/src/js/defaults.js
index e8b9e187..56a45539 100644
--- a/src/js/defaults.js
+++ b/src/js/defaults.js
@@ -132,7 +132,10 @@ const defaults = {
// Default controls
controls: [
'play-large',
+ // 'restart',
+ // 'rewind',
'play',
+ // 'fast-forward',
'progress',
'current-time',
'mute',
@@ -155,7 +158,7 @@ const defaults = {
rewind: 'Rewind {seektime} secs',
play: 'Play',
pause: 'Pause',
- forward: 'Forward {seektime} secs',
+ fastForward: 'Forward {seektime} secs',
seek: 'Seek',
played: 'Played',
buffered: 'Buffered',
@@ -203,7 +206,7 @@ const defaults = {
pause: null,
restart: null,
rewind: null,
- forward: null,
+ fastForward: null,
mute: null,
volume: null,
captions: null,
diff --git a/src/js/fullscreen.js b/src/js/fullscreen.js
index ffed442f..2e898042 100644
--- a/src/js/fullscreen.js
+++ b/src/js/fullscreen.js
@@ -161,6 +161,8 @@ class Fullscreen {
return;
}
+ console.warn(this.prefix);
+
// iOS native fullscreen doesn't need the request step
if (browser.isIos && this.player.config.fullscreen.iosNative) {
if (this.player.playing) {
@@ -169,7 +171,7 @@ class Fullscreen {
} else if (!Fullscreen.native) {
toggleFallback.call(this, true);
} else if (!this.prefix) {
- this.target.requestFullScreen();
+ this.target.requestFullscreen();
} else if (!utils.is.empty(this.prefix)) {
this.target[`${this.prefix}Request${this.name}`]();
}
@@ -197,6 +199,8 @@ class Fullscreen {
// Toggle state
toggle() {
+ console.warn('TOGGLE');
+
if (!this.active) {
this.enter();
} else {
diff --git a/src/js/i18n.js b/src/js/i18n.js
new file mode 100644
index 00000000..58c3e7cf
--- /dev/null
+++ b/src/js/i18n.js
@@ -0,0 +1,31 @@
+// ==========================================================================
+// Plyr internationalization
+// ==========================================================================
+
+import utils from './utils';
+
+const i18n = {
+ get(key = '', config = {}) {
+ if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
+ return '';
+ }
+
+ let string = config.i18n[key];
+
+ const replace = {
+ '{seektime}': config.seekTime,
+ '{title}': config.title,
+ };
+
+ Object.entries(replace).forEach(([
+ key,
+ value,
+ ]) => {
+ string = utils.replaceAll(string, key, value);
+ });
+
+ return string;
+ },
+};
+
+export default i18n;
diff --git a/src/js/listeners.js b/src/js/listeners.js
index a543bfcd..9f4400d6 100644
--- a/src/js/listeners.js
+++ b/src/js/listeners.js
@@ -128,7 +128,7 @@ class Listeners {
case 39:
// Arrow forward
- this.player.forward();
+ this.player.fastForward();
break;
case 37:
@@ -379,12 +379,13 @@ class Listeners {
// IE doesn't support input event, so we fallback to change
const inputEvent = browser.isIE ? 'change' : 'input';
- // Trigger custom and default handlers
- const proxy = (event, handlerKey, defaultHandler) => {
- const customHandler = this.player.config.listeners[handlerKey];
+ // Run default and custom handlers
+ const proxy = (event, defaultHandler, customHandlerKey) => {
+ const customHandler = this.player.config.listeners[customHandlerKey];
+ const hasCustomHandler = utils.is.function(customHandler);
// Execute custom handler
- if (utils.is.function(customHandler)) {
+ if (hasCustomHandler) {
customHandler.call(this.player, event);
}
@@ -394,107 +395,110 @@ class Listeners {
}
};
+ // Trigger custom and default handlers
+ const on = (element, type, defaultHandler, customHandlerKey, passive = true) => {
+ const customHandler = this.player.config.listeners[customHandlerKey];
+ const hasCustomHandler = utils.is.function(customHandler);
+
+ utils.on(element, type, event => proxy(event, defaultHandler, customHandlerKey), passive && !hasCustomHandler);
+ };
+
// Play/pause toggle
- utils.on(this.player.elements.buttons.play, 'click', event =>
- proxy(event, 'play', () => {
- this.player.togglePlay();
- }),
- );
+ on(this.player.elements.buttons.play, 'click', this.player.togglePlay, 'play');
// Pause
- utils.on(this.player.elements.buttons.restart, 'click', event =>
- proxy(event, 'restart', () => {
- this.player.restart();
- }),
- );
+ on(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart');
// Rewind
- utils.on(this.player.elements.buttons.rewind, 'click', event =>
- proxy(event, 'rewind', () => {
- this.player.rewind();
- }),
- );
+ on(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind');
// Rewind
- utils.on(this.player.elements.buttons.forward, 'click', event =>
- proxy(event, 'forward', () => {
- this.player.forward();
- }),
- );
+ on(this.player.elements.buttons.fastForward, 'click', this.player.fastForward, 'fastForward');
// Mute toggle
- utils.on(this.player.elements.buttons.mute, 'click', event =>
- proxy(event, 'mute', () => {
+ on(
+ this.player.elements.buttons.mute,
+ 'click',
+ () => {
this.player.muted = !this.player.muted;
- }),
+ },
+ 'mute',
);
// Captions toggle
- utils.on(this.player.elements.buttons.captions, 'click', event =>
- proxy(event, 'captions', () => {
- this.player.toggleCaptions();
- }),
- );
+ on(this.player.elements.buttons.captions, 'click', this.player.toggleCaptions);
// Fullscreen toggle
- utils.on(this.player.elements.buttons.fullscreen, 'click', event =>
- proxy(event, 'fullscreen', () => {
+ on(
+ this.player.elements.buttons.fullscreen,
+ 'click',
+ () => {
this.player.fullscreen.toggle();
- }),
+ },
+ 'fullscreen',
);
// Picture-in-Picture
- utils.on(this.player.elements.buttons.pip, 'click', event =>
- proxy(event, 'pip', () => {
+ on(
+ this.player.elements.buttons.pip,
+ 'click',
+ () => {
this.player.pip = 'toggle';
- }),
+ },
+ 'pip',
);
// Airplay
- utils.on(this.player.elements.buttons.airplay, 'click', event =>
- proxy(event, 'airplay', () => {
- this.player.airplay();
- }),
- );
+ on(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay');
// Settings menu
- utils.on(this.player.elements.buttons.settings, 'click', event => {
+ on(this.player.elements.buttons.settings, 'click', event => {
controls.toggleMenu.call(this.player, event);
});
// Settings menu
- utils.on(this.player.elements.settings.form, 'click', event => {
+ on(this.player.elements.settings.form, 'click', event => {
event.stopPropagation();
// Settings menu items - use event delegation as items are added/removed
if (utils.matches(event.target, this.player.config.selectors.inputs.language)) {
- proxy(event, 'language', () => {
- this.player.language = event.target.value;
- });
+ proxy(
+ event,
+ () => {
+ this.player.language = event.target.value;
+ },
+ 'language',
+ );
} else if (utils.matches(event.target, this.player.config.selectors.inputs.quality)) {
- proxy(event, 'quality', () => {
- this.player.quality = event.target.value;
- });
+ proxy(
+ event,
+ () => {
+ this.player.quality = event.target.value;
+ },
+ 'quality',
+ );
} else if (utils.matches(event.target, this.player.config.selectors.inputs.speed)) {
- proxy(event, 'speed', () => {
- this.player.speed = parseFloat(event.target.value);
- });
+ proxy(
+ event,
+ () => {
+ this.player.speed = parseFloat(event.target.value);
+ },
+ 'speed',
+ );
} else {
controls.showTab.call(this.player, event);
}
});
// Seek
- utils.on(this.player.elements.inputs.seek, inputEvent, event =>
- proxy(event, 'seek', () => {
- this.player.currentTime = event.target.value / event.target.max * this.player.duration;
- }),
- );
+ on(this.player.elements.inputs.seek, inputEvent, 'seek', event => {
+ this.player.currentTime = event.target.value / event.target.max * this.player.duration;
+ });
// Current time invert
// Only if one time element is used for both currentTime and duration
if (this.player.config.toggleInvert && !utils.is.element(this.player.elements.display.duration)) {
- utils.on(this.player.elements.display.currentTime, 'click', () => {
+ on(this.player.elements.display.currentTime, 'click', () => {
// Do nothing if we're at the start
if (this.player.currentTime === 0) {
return;
@@ -506,31 +510,34 @@ class Listeners {
}
// Volume
- utils.on(this.player.elements.inputs.volume, inputEvent, event =>
- proxy(event, 'volume', () => {
+ on(
+ this.player.elements.inputs.volume,
+ inputEvent,
+ event => {
this.player.volume = event.target.value;
- }),
+ },
+ 'volume',
);
// Polyfill for lower fill in <input type="range"> for webkit
if (browser.isWebkit) {
- utils.on(utils.getElements.call(this.player, 'input[type="range"]'), 'input', event => {
+ on(utils.getElements.call(this.player, 'input[type="range"]'), 'input', event => {
controls.updateRangeFill.call(this.player, event.target);
});
}
// Seek tooltip
- utils.on(this.player.elements.progress, 'mouseenter mouseleave mousemove', event => controls.updateSeekTooltip.call(this.player, event));
+ on(this.player.elements.progress, 'mouseenter mouseleave mousemove', event => controls.updateSeekTooltip.call(this.player, event));
// Toggle controls visibility based on mouse movement
if (this.player.config.hideControls) {
// Watch for cursor over controls so they don't hide when trying to interact
- utils.on(this.player.elements.controls, 'mouseenter mouseleave', event => {
+ on(this.player.elements.controls, 'mouseenter mouseleave', event => {
this.player.elements.controls.hover = event.type === 'mouseenter';
});
// Watch for cursor over controls so they don't hide when trying to interact
- utils.on(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {
+ on(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {
this.player.elements.controls.pressed = [
'mousedown',
'touchstart',
@@ -538,50 +545,50 @@ class Listeners {
});
// Focus in/out on controls
- utils.on(this.player.elements.controls, 'focusin focusout', event => {
+ on(this.player.elements.controls, 'focusin focusout', event => {
this.player.toggleControls(event);
});
}
// Mouse wheel for volume
- utils.on(
+ on(
this.player.elements.inputs.volume,
'wheel',
- 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.player.decreaseVolume(step);
- direction = -1;
- } else {
- this.player.increaseVolume(step);
- direction = 1;
- }
+ 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;
+
+ // Scroll down (or up on natural) to decrease
+ if (event.deltaY < 0 || event.deltaX > 0) {
+ if (inverted) {
+ this.player.decreaseVolume(step);
+ direction = -1;
+ } else {
+ this.player.increaseVolume(step);
+ direction = 1;
}
+ }
- // Scroll up (or down on natural) to increase
- if (event.deltaY > 0 || event.deltaX < 0) {
- if (inverted) {
- this.player.increaseVolume(step);
- direction = 1;
- } else {
- this.player.decreaseVolume(step);
- direction = -1;
- }
+ // Scroll up (or down on natural) to increase
+ if (event.deltaY > 0 || event.deltaX < 0) {
+ if (inverted) {
+ this.player.increaseVolume(step);
+ direction = 1;
+ } else {
+ this.player.decreaseVolume(step);
+ direction = -1;
}
+ }
- // Don't break page scrolling at max and min
- if ((direction === 1 && this.player.media.volume < 1) || (direction === -1 && this.player.media.volume > 0)) {
- event.preventDefault();
- }
- }),
+ // Don't break page scrolling at max and min
+ if ((direction === 1 && this.player.media.volume < 1) || (direction === -1 && this.player.media.volume > 0)) {
+ event.preventDefault();
+ }
+ },
+ 'volume',
false,
);
}
diff --git a/src/js/plugins/ads.js b/src/js/plugins/ads.js
index 31a797c2..3e8f0923 100644
--- a/src/js/plugins/ads.js
+++ b/src/js/plugins/ads.js
@@ -7,6 +7,7 @@
/* global google */
import utils from '../utils';
+import i18n from '../i18n';
class Ads {
/**
@@ -178,7 +179,7 @@ class Ads {
const update = () => {
const time = utils.formatTime(Math.max(this.manager.getRemainingTime(), 0));
- const label = `${this.player.config.i18n.advertisement} - ${time}`;
+ const label = `${i18n.get('advertisement', this.player.config)} - ${time}`;
this.elements.container.setAttribute('data-badge-text', label);
};
diff --git a/src/js/plyr.js b/src/js/plyr.js
index 061ac25c..3a6090ae 100644
--- a/src/js/plyr.js
+++ b/src/js/plyr.js
@@ -405,7 +405,7 @@ class Plyr {
* Fast forward
* @param {number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime
*/
- forward(seekTime) {
+ fastForward(seekTime) {
this.currentTime = this.currentTime + (utils.is.number(seekTime) ? seekTime : this.config.seekTime);
}
diff --git a/src/js/ui.js b/src/js/ui.js
index a4f22413..a3b3754a 100644
--- a/src/js/ui.js
+++ b/src/js/ui.js
@@ -5,6 +5,7 @@
import utils from './utils';
import captions from './captions';
import controls from './controls';
+import i18n from './i18n';
const ui = {
addStyleHook() {
@@ -94,7 +95,7 @@ const ui = {
// Setup aria attribute for play and iframe title
setTitle() {
// Find the current text
- let label = this.config.i18n.play;
+ let label = i18n.get('play', this.config);
// If there's a media title set, use that for the label
if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {
@@ -123,7 +124,7 @@ const ui = {
// Default to media type
const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';
- iframe.setAttribute('title', this.config.i18n.frameTitle.replace('{title}', title));
+ iframe.setAttribute('title', i18n.get('frameTitle', this.config));
}
},
diff --git a/src/js/utils.js b/src/js/utils.js
index 493fb15e..172e29ca 100644
--- a/src/js/utils.js
+++ b/src/js/utils.js
@@ -540,7 +540,7 @@ const utils = {
},
// Toggle event listener
- toggleListener(elements, event, callback, toggle, passive, capture) {
+ toggleListener(elements, event, callback, toggle = false, passive = true, capture = false) {
// Bail if no elemetns, event, or callback
if (utils.is.empty(elements) || utils.is.empty(event) || !utils.is.function(callback)) {
return;
@@ -562,16 +562,16 @@ const utils = {
const events = event.split(' ');
// Build options
- // Default to just capture boolean
- let options = utils.is.boolean(capture) ? capture : false;
+ // Default to just the capture boolean for browsers with no passive listener support
+ let options = capture;
// If passive events listeners are supported
if (support.passiveListeners) {
options = {
// Whether the listener can be passive (i.e. default never prevented)
- passive: utils.is.boolean(passive) ? passive : true,
+ passive,
// Whether the listener is a capturing listener or not
- capture: utils.is.boolean(capture) ? capture : false,
+ capture,
};
}
@@ -582,12 +582,12 @@ const utils = {
},
// Bind event handler
- on(element, events, callback, passive, capture) {
+ on(element, events = '', callback, passive = true, capture = false) {
utils.toggleListener(element, events, callback, true, passive, capture);
},
// Unbind event handler
- off(element, events, callback, passive, capture) {
+ off(element, events = '', callback, passive = true, capture = false) {
utils.toggleListener(element, events, callback, false, passive, capture);
},
@@ -678,6 +678,44 @@ const utils = {
return `${inverted ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;
},
+ // Replace all occurances of a string in a string
+ replaceAll(input = '', find = '', replace = '') {
+ return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString());
+ },
+
+ // Convert to title case
+ toTitleCase(input = '') {
+ return input.toString().replace(/\w\S*/g, text => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase());
+ },
+
+ // Convert string to pascalCase
+ toPascalCase(input = '') {
+ let string = input.toString();
+
+ // Convert kebab case
+ string = utils.replaceAll(string, '-', ' ');
+
+ // Convert snake case
+ string = utils.replaceAll(string, '_', ' ');
+
+ // Convert to title case
+ string = utils.toTitleCase(string);
+
+ // Convert to pascal case
+ return utils.replaceAll(string, ' ', '');
+ },
+
+ // Convert string to pascalCase
+ toCamelCase(input = '') {
+ let string = input.toString();
+
+ // Convert to pascal case
+ string = utils.toPascalCase(string);
+
+ // Convert first character to lowercase
+ return string.charAt(0).toLowerCase() + string.slice(1);
+ },
+
// Deep extend destination object with N more objects
extend(target = {}, ...sources) {
if (!sources.length) {