aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/js/config/defaults.js3
-rw-r--r--src/js/controls.js17
-rw-r--r--src/js/fullscreen.js2
-rw-r--r--src/js/html5.js70
-rw-r--r--src/js/listeners.js7
-rw-r--r--src/js/plugins/ads.js2
-rw-r--r--src/js/plugins/vimeo.js8
-rw-r--r--src/js/plugins/youtube.js6
-rw-r--r--src/js/plyr.d.ts560
-rw-r--r--src/js/plyr.js14
-rw-r--r--src/js/ui.js1
-rw-r--r--src/js/utils/events.js4
12 files changed, 641 insertions, 53 deletions
diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js
index c50a8900..969c78d1 100644
--- a/src/js/config/defaults.js
+++ b/src/js/config/defaults.js
@@ -70,6 +70,8 @@ const defaults = {
quality: {
default: 576,
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240],
+ forced: false,
+ onChange: null,
},
// Set loops
@@ -164,6 +166,7 @@ const defaults = {
frameTitle: 'Player for {title}',
captions: 'Captions',
settings: 'Settings',
+ pip: 'PIP',
menuBack: 'Go back to previous menu',
speed: 'Speed',
normal: 'Normal',
diff --git a/src/js/controls.js b/src/js/controls.js
index 76b15dda..7993dcb8 100644
--- a/src/js/controls.js
+++ b/src/js/controls.js
@@ -139,10 +139,7 @@ const controls = {
// Create hidden text label
createLabel(key, attr = {}) {
const text = i18n.get(key, this.config);
-
- const attributes = Object.assign({}, attr, {
- class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '),
- });
+ const attributes = { ...attr, class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '),};
return createElement('span', attributes, text);
},
@@ -402,7 +399,8 @@ const controls = {
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
bindMenuItemShortcuts(menuItem, type) {
// Navigate through menus via arrow keys and space
- on(
+ on.call(
+ this,
menuItem,
'keydown keyup',
event => {
@@ -452,7 +450,7 @@ const controls = {
// Enter will fire a `click` event but we still need to manage focus
// So we bind to keyup which fires after and set focus here
- on(menuItem, 'keyup', event => {
+ on.call(this, menuItem, 'keyup', event => {
if (event.which !== 13) {
return;
}
@@ -1463,7 +1461,7 @@ const controls = {
bindMenuItemShortcuts.call(this, menuItem, type);
// Show menu on click
- on(menuItem, 'click', () => {
+ on.call(this, menuItem, 'click', () => {
showMenuPanel.call(this, type, false);
});
@@ -1515,7 +1513,8 @@ const controls = {
);
// Go back via keyboard
- on(
+ on.call(
+ this,
pane,
'keydown',
event => {
@@ -1535,7 +1534,7 @@ const controls = {
);
// Go back via button click
- on(backButton, 'click', () => {
+ on.call(this, backButton, 'click', () => {
showMenuPanel.call(this, 'home', false);
});
diff --git a/src/js/fullscreen.js b/src/js/fullscreen.js
index 4de8da88..7ae3ff17 100644
--- a/src/js/fullscreen.js
+++ b/src/js/fullscreen.js
@@ -228,7 +228,7 @@ class Fullscreen {
} else if (!Fullscreen.native || this.forceFallback) {
toggleFallback.call(this, true);
} else if (!this.prefix) {
- this.target.requestFullscreen();
+ this.target.requestFullscreen({ navigationUI: "hide" });
} else if (!is.empty(this.prefix)) {
this.target[`${this.prefix}Request${this.property}`]();
}
diff --git a/src/js/html5.js b/src/js/html5.js
index b03e9c26..a0825cf6 100644
--- a/src/js/html5.js
+++ b/src/js/html5.js
@@ -30,6 +30,11 @@ const html5 = {
// Get quality levels
getQualityOptions() {
+ // Whether we're forcing all options (e.g. for streaming)
+ if (this.config.quality.forced) {
+ return this.config.quality.options;
+ }
+
// Get sizes from <source> elements
return html5.getSources
.call(this)
@@ -60,36 +65,41 @@ const html5 = {
return source && Number(source.getAttribute('size'));
},
set(input) {
- // Get sources
- const sources = html5.getSources.call(player);
- // Get first match for requested size
- const source = sources.find(s => Number(s.getAttribute('size')) === input);
-
- // No matching source found
- if (!source) {
- return;
- }
-
- // Get current state
- const { currentTime, paused, preload, readyState } = player.media;
-
- // Set new source
- player.media.src = source.getAttribute('src');
-
- // Prevent loading if preload="none" and the current source isn't loaded (#1044)
- if (preload !== 'none' || readyState) {
- // Restore time
- player.once('loadedmetadata', () => {
- player.currentTime = currentTime;
-
- // Resume playing
- if (!paused) {
- player.play();
- }
- });
-
- // Load new source
- player.media.load();
+ // If we're using an an external handler...
+ if (player.config.quality.forced && is.function(player.config.quality.onChange)) {
+ player.config.quality.onChange(input);
+ } else {
+ // Get sources
+ const sources = html5.getSources.call(player);
+ // Get first match for requested size
+ const source = sources.find(s => Number(s.getAttribute('size')) === input);
+
+ // No matching source found
+ if (!source) {
+ return;
+ }
+
+ // Get current state
+ const { currentTime, paused, preload, readyState } = player.media;
+
+ // Set new source
+ player.media.src = source.getAttribute('src');
+
+ // Prevent loading if preload="none" and the current source isn't loaded (#1044)
+ if (preload !== 'none' || readyState) {
+ // Restore time
+ player.once('loadedmetadata', () => {
+ player.currentTime = currentTime;
+
+ // Resume playing
+ if (!paused) {
+ player.play();
+ }
+ });
+
+ // Load new source
+ player.media.load();
+ }
}
// Trigger change event
diff --git a/src/js/listeners.js b/src/js/listeners.js
index c5076ff3..643b7dd3 100644
--- a/src/js/listeners.js
+++ b/src/js/listeners.js
@@ -390,6 +390,9 @@ class Listeners {
if (player.isHTML5 && player.isVideo && player.config.resetOnEnd) {
// Restart
player.restart();
+
+ // Call pause otherwise IE11 will start playing the video again
+ player.pause();
}
});
@@ -513,7 +516,7 @@ class Listeners {
}
// Only call default handler if not prevented in custom handler
- if (returned && is.function(defaultHandler)) {
+ if (returned !== false && is.function(defaultHandler)) {
defaultHandler.call(player, event);
}
}
@@ -663,7 +666,7 @@ class Listeners {
const code = event.keyCode ? event.keyCode : event.which;
const attribute = 'play-on-seeked';
- if (is.keyboardEvent(event) && (code !== 39 && code !== 37)) {
+ if (is.keyboardEvent(event) && code !== 39 && code !== 37) {
return;
}
diff --git a/src/js/plugins/ads.js b/src/js/plugins/ads.js
index db55e499..6b4fca10 100644
--- a/src/js/plugins/ads.js
+++ b/src/js/plugins/ads.js
@@ -136,7 +136,7 @@ class Ads {
cb: Date.now(),
AV_WIDTH: 640,
AV_HEIGHT: 480,
- AV_CDIM2: this.publisherId,
+ AV_CDIM2: config.publisherId,
};
const base = 'https://go.aniview.com/api/adserver6/vast/';
diff --git a/src/js/plugins/vimeo.js b/src/js/plugins/vimeo.js
index 91019abf..8df5ad15 100644
--- a/src/js/plugins/vimeo.js
+++ b/src/js/plugins/vimeo.js
@@ -335,6 +335,14 @@ const vimeo = {
}
});
+ player.embed.on('bufferstart', () => {
+ triggerEvent.call(player, player.media, 'waiting');
+ });
+
+ player.embed.on('bufferend', () => {
+ triggerEvent.call(player, player.media, 'playing');
+ });
+
player.embed.on('play', () => {
assurePlaybackState.call(player, true);
triggerEvent.call(player, player.media, 'playing');
diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js
index 31d22bb4..ba5d8de9 100644
--- a/src/js/plugins/youtube.js
+++ b/src/js/plugins/youtube.js
@@ -416,6 +416,12 @@ const youtube = {
break;
+ case 3:
+ // Trigger waiting event to add loading classes to container as the video buffers.
+ triggerEvent.call(player, player.media, 'waiting');
+
+ break;
+
default:
break;
}
diff --git a/src/js/plyr.d.ts b/src/js/plyr.d.ts
new file mode 100644
index 00000000..4f64898f
--- /dev/null
+++ b/src/js/plyr.d.ts
@@ -0,0 +1,560 @@
+// Type definitions for plyr 3.5
+// Project: https://plyr.io
+// Definitions by: ondratra <https://github.com/ondratra>
+// TypeScript Version: 3.0
+
+export = Plyr;
+export as namespace Plyr;
+
+
+declare class Plyr {
+ /**
+ * Setup a new instance
+ */
+ static setup(targets: NodeList | HTMLElement | HTMLElement[] | string, options?: Plyr.Options): Plyr[];
+
+ /**
+ * Check for support
+ * @param mediaType
+ * @param provider
+ * @param playsInline Whether the player has the playsinline attribute (only applicable to iOS 10+)
+ */
+ static supported(mediaType?: Plyr.MediaType, provider?: Plyr.Provider, playsInline?: boolean): Plyr.Support;
+
+ constructor(targets: NodeList | HTMLElement | HTMLElement[] | string, options?: Plyr.Options);
+
+ /**
+ * Indicates if the current player is HTML5.
+ */
+ readonly isHTML5: boolean;
+
+ /**
+ * Indicates if the current player is an embedded player.
+ */
+ readonly isEmbed: boolean;
+
+ /**
+ * Indicates if the current player is playing.
+ */
+ readonly playing: boolean;
+
+ /**
+ * Indicates if the current player is paused.
+ */
+ readonly paused: boolean;
+
+ /**
+ * Indicates if the current player is stopped.
+ */
+ readonly stopped: boolean;
+
+ /**
+ * Indicates if the current player has finished playback.
+ */
+ readonly ended: boolean;
+
+ /**
+ * Returns a float between 0 and 1 indicating how much of the media is buffered
+ */
+ readonly buffered: number;
+
+ /**
+ * Gets or sets the currentTime for the player. The setter accepts a float in seconds.
+ */
+ currentTime: number;
+
+ /**
+ * Indicates if the current player is seeking.
+ */
+ readonly seeking: boolean;
+
+ /**
+ * Returns the duration for the current media.
+ */
+ readonly duration: number;
+
+ /**
+ * Gets or sets the volume for the player. The setter accepts a float between 0 and 1.
+ */
+ volume: number;
+
+ /**
+ * Gets or sets the muted state of the player. The setter accepts a boolean.
+ */
+ muted: boolean;
+
+ /**
+ * Indicates if the current media has an audio track.
+ */
+ readonly hasAudio: boolean;
+
+ /**
+ * Gets or sets the speed for the player. The setter accepts a value in the options specified in your config. Generally the minimum should be 0.5.
+ */
+ speed: number;
+
+ /**
+ * Gets or sets the quality for the player. The setter accepts a value from the options specified in your config.
+ * Remarks: YouTube only. HTML5 will follow.
+ */
+ quality: string;
+
+ /**
+ * Gets or sets the current loop state of the player.
+ */
+ loop: boolean;
+
+ /**
+ * Gets or sets the current source for the player.
+ */
+ source: Plyr.SourceInfo;
+
+ /**
+ * Gets or sets the current poster image URL for the player.
+ */
+ poster: string;
+
+ /**
+ * Gets or sets the autoplay state of the player.
+ */
+ autoplay: boolean;
+
+ /**
+ * Gets or sets the caption track by index. 1 means the track is missing or captions is not active
+ */
+ currentTrack: number;
+
+ /**
+ * Gets or sets the preferred captions language for the player. The setter accepts an ISO twoletter language code. Support for the languages is dependent on the captions you include.
+ * If your captions don't have any language data, or if you have multiple tracks with the same language, you may want to use currentTrack instead.
+ */
+ language: string;
+
+ /**
+ * Gets or sets the picture-in-picture state of the player. This currently only supported on Safari 10+ on MacOS Sierra+ and iOS 10+.
+ */
+ pip: boolean;
+
+ readonly fullscreen: Plyr.FullscreenControl;
+
+ /**
+ * Start playback.
+ * For HTML5 players, play() will return a Promise in some browsers - WebKit and Mozilla according to MDN at time of writing.
+ */
+ play(): Promise<void> | void;
+
+ /**
+ * Pause playback.
+ */
+ pause(): void;
+
+ /**
+ * Toggle playback, if no parameters are passed, it will toggle based on current status.
+ */
+ togglePlay(toggle?: boolean): boolean;
+
+ /**
+ * Stop playback and reset to start.
+ */
+ stop(): void;
+
+ /**
+ * Restart playback.
+ */
+ restart(): void;
+
+ /**
+ * Rewind playback by the specified seek time. If no parameter is passed, the default seek time will be used.
+ */
+ rewind(seekTime?: number): void;
+
+ /**
+ * Fast forward by the specified seek time. If no parameter is passed, the default seek time will be used.
+ */
+ forward(seekTime?: number): void;
+
+ /**
+ * Increase volume by the specified step. If no parameter is passed, the default step will be used.
+ */
+ increaseVolume(step?: number): void;
+
+ /**
+ * Increase volume by the specified step. If no parameter is passed, the default step will be used.
+ */
+ decreaseVolume(step?: number): void;
+
+ /**
+ * Toggle captions display. If no parameter is passed, it will toggle based on current status.
+ */
+ toggleCaptions(toggle?: boolean): void;
+
+ /**
+ * Trigger the airplay dialog on supported devices.
+ */
+ airplay(): void;
+
+ /**
+ * Toggle the controls (video only). Takes optional truthy value to force it on/off.
+ */
+ toggleControls(toggle: boolean): void;
+
+ /**
+ * Add an event listener for the specified event.
+ */
+ on(event: Plyr.StandardEvent | Plyr.Html5Event | Plyr.YoutubeEvent, callback: (this: this, event: Plyr.PlyrEvent) => void): void;
+
+ /**
+ * Add an event listener for the specified event once.
+ */
+ once(event: Plyr.StandardEvent | Plyr.Html5Event | Plyr.YoutubeEvent, callback: (this: this, event: Plyr.PlyrEvent) => void): void;
+
+ /**
+ * Remove an event listener for the specified event.
+ */
+ off(event: Plyr.StandardEvent | Plyr.Html5Event | Plyr.YoutubeEvent, callback: (this: this, event: Plyr.PlyrEvent) => void): void;
+
+ /**
+ * Check support for a mime type.
+ */
+ supports(type: string): boolean;
+
+ /**
+ * Destroy lib instance
+ */
+ destroy(): void;
+}
+
+declare namespace Plyr {
+ type MediaType = "audio" | "video";
+ type Provider = "html5" | "youtube" | "vimeo";
+ type StandardEvent = "progress" | "playing" | "play" | "pause" | "timeupdate" | "volumechange" | "seeking" | "seeked" | "ratechange" | "ended" | "enterfullscreen" | "exitfullscreen"
+ | "captionsenabled" | "captionsdisabled" | "languagechange" | "controlshidden" | "controlsshown" | "ready";
+ type Html5Event = "loadstart" | "loadeddata" | "loadedmetadata" | "canplay" | "canplaythrough" | "stalled" | "waiting" | "emptied" | "cuechange" | "error";
+ type YoutubeEvent = "statechange" | "qualitychange" | "qualityrequested";
+
+ interface FullscreenControl {
+ /**
+ * Indicates if the current player is in fullscreen mode.
+ */
+ readonly active: boolean;
+
+ /**
+ * Indicates if the current player has fullscreen enabled.
+ */
+ readonly enabled: boolean;
+
+ /**
+ * Enter fullscreen. If fullscreen is not supported, a fallback ""full window/viewport"" is used instead.
+ */
+ enter(): void;
+
+ /**
+ * Exit fullscreen.
+ */
+ exit(): void;
+
+ /**
+ * Toggle fullscreen.
+ */
+ toggle(): void;
+ }
+
+ interface Options {
+ /**
+ * Completely disable Plyr. This would allow you to do a User Agent check or similar to programmatically enable or disable Plyr for a certain UA. Example below.
+ */
+ enabled?: boolean;
+
+ /**
+ * Display debugging information in the console
+ */
+ debug?: boolean;
+
+ /**
+ * If a function is passed, it is assumed your method will return either an element or HTML string for the controls. Three arguments will be passed to your function;
+ * id (the unique id for the player), seektime (the seektime step in seconds), and title (the media title). See controls.md for more info on how the html needs to be structured.
+ * Defaults to ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen']
+ */
+ controls?: string[] | ((id: string, seektime: number, title: string) => unknown) | Element;
+
+ /**
+ * If you're using the default controls are used then you can specify which settings to show in the menu
+ * Defaults to ['captions', 'quality', 'speed', 'loop']
+ */
+ settings?: string[];
+
+ /**
+ * Used for internationalization (i18n) of the text within the UI.
+ */
+ i18n?: any;
+
+ /**
+ * Load the SVG sprite specified as the iconUrl option (if a URL). If false, it is assumed you are handling sprite loading yourself.
+ */
+ loadSprite?: boolean;
+
+ /**
+ * Specify a URL or path to the SVG sprite. See the SVG section for more info.
+ */
+ iconUrl?: string;
+
+ /**
+ * Specify the id prefix for the icons used in the default controls (e.g. plyr-play would be plyr).
+ * This is to prevent clashes if you're using your own SVG sprite but with the default controls.
+ * Most people can ignore this option.
+ */
+ iconPrefix?: string;
+
+ /**
+ * Specify a URL or path to a blank video file used to properly cancel network requests.
+ */
+ blankUrl?: string;
+
+ /**
+ * Autoplay the media on load. This is generally advised against on UX grounds. It is also disabled by default in some browsers.
+ * If the autoplay attribute is present on a <video> or <audio> element, this will be automatically set to true.
+ */
+ autoplay?: boolean;
+
+ /**
+ * Only allow one player playing at once.
+ */
+ autopause?: boolean;
+
+ /**
+ * The time, in seconds, to seek when a user hits fast forward or rewind.
+ */
+ seekTime?: number;
+
+ /**
+ * A number, between 0 and 1, representing the initial volume of the player.
+ */
+ volume?: number;
+
+ /**
+ * Whether to start playback muted. If the muted attribute is present on a <video> or <audio> element, this will be automatically set to true.
+ */
+ muted?: boolean;
+
+ /**
+ * Click (or tap) of the video container will toggle play/pause.
+ */
+ clickToPlay?: boolean;
+
+ /**
+ * Disable right click menu on video to help as very primitive obfuscation to prevent downloads of content.
+ */
+ disableContextMenu?: boolean;
+
+ /**
+ * Hide video controls automatically after 2s of no mouse or focus movement, on control element blur (tab out), on playback start or entering fullscreen.
+ * As soon as the mouse is moved, a control element is focused or playback is paused, the controls reappear instantly.
+ */
+ hideControls?: boolean;
+
+ /**
+ * Reset the playback to the start once playback is complete.
+ */
+ resetOnEnd?: boolean;
+
+ /**
+ * Enable keyboard shortcuts for focused players only or globally
+ */
+ keyboard?: KeyboardOptions;
+
+ /**
+ * controls: Display control labels as tooltips on :hover & :focus (by default, the labels are screen reader only).
+ * seek: Display a seek tooltip to indicate on click where the media would seek to.
+ */
+ tooltips?: TooltipOptions;
+
+ /**
+ * Specify a custom duration for media.
+ */
+ duration?: number;
+
+ /**
+ * Displays the duration of the media on the metadataloaded event (on startup) in the current time display.
+ * This will only work if the preload attribute is not set to none (or is not set at all) and you choose not to display the duration (see controls option).
+ */
+ displayDuration?: boolean;
+
+ /**
+ * Display the current time as a countdown rather than an incremental counter.
+ */
+ invertTime?: boolean;
+
+ /**
+ * Allow users to click to toggle the above.
+ */
+ toggleInvert?: boolean;
+
+ /**
+ * Allows binding of event listeners to the controls before the default handlers. See the defaults.js for available listeners.
+ * If your handler prevents default on the event (event.preventDefault()), the default handler will not fire.
+ */
+ listeners?: {[key: string]: (error: PlyrEvent) => void};
+
+ /**
+ * active: Toggles if captions should be active by default. language: Sets the default language to load (if available). 'auto' uses the browser language.
+ * update: Listen to changes to tracks and update menu. This is needed for some streaming libraries, but can result in unselectable language options).
+ */
+ captions?: CaptionOptions;
+
+ /**
+ * enabled: Toggles whether fullscreen should be enabled. fallback: Allow fallback to a full-window solution.
+ * iosNative: whether to use native iOS fullscreen when entering fullscreen (no custom controls)
+ */
+ fullscreen?: FullScreenOptions;
+
+ /**
+ * The aspect ratio you want to use for embedded players.
+ */
+ ratio?: string;
+
+ /**
+ * enabled: Allow use of local storage to store user settings. key: The key name to use.
+ */
+ storage?: StorageOptions;
+
+ /**
+ * selected: The default speed for playback. options: Options to display in the menu. Most browsers will refuse to play slower than 0.5.
+ */
+ speed?: SpeedOptions;
+
+ /**
+ * Currently only supported by YouTube. default is the default quality level, determined by YouTube. options are the options to display.
+ */
+ quality?: QualityOptions;
+
+ /**
+ * active: Whether to loop the current video. If the loop attribute is present on a <video> or <audio> element,
+ * this will be automatically set to true This is an object to support future functionality.
+ */
+ loop?: LoopOptions;
+
+ /**
+ * enabled: Whether to enable vi.ai ads. publisherId: Your unique vi.ai publisher ID.
+ */
+ ads?: AdOptions;
+ }
+
+ interface QualityOptions {
+ default: string;
+ options: string[];
+ }
+
+ interface LoopOptions {
+ active: boolean;
+ }
+
+ interface AdOptions {
+ enabled: boolean;
+ publisherId: string;
+ }
+
+ interface SpeedOptions {
+ selected: number;
+ options: number[];
+ }
+
+ interface KeyboardOptions {
+ focused?: boolean;
+ global?: boolean;
+ }
+
+ interface TooltipOptions {
+ controls?: boolean;
+ seek?: boolean;
+ }
+
+ interface FullScreenOptions {
+ enabled?: boolean;
+ fallback?: boolean;
+ allowAudio?: boolean;
+ }
+
+ interface CaptionOptions {
+ active?: boolean;
+ language?: string;
+ update?: boolean;
+ }
+
+ interface StorageOptions {
+ enabled?: boolean;
+ key?: string;
+ }
+
+ interface SourceInfo {
+ /**
+ * Note: YouTube and Vimeo are currently not supported as audio sources.
+ */
+ type: MediaType;
+
+ /**
+ * Title of the new media. Used for the aria-label attribute on the play button, and outer container. YouTube and Vimeo are populated automatically.
+ */
+ title?: string;
+
+ /**
+ * This is an array of sources. For HTML5 media, the properties of this object are mapped directly to HTML attributes so more can be added to the object if required.
+ */
+ sources: Source[];
+
+ /**
+ * The URL for the poster image (HTML5 video only).
+ */
+ poster?: string;
+
+ /**
+ * An array of track objects. Each element in the array is mapped directly to a track element and any keys mapped directly to HTML attributes so as in the example above,
+ * it will render as <track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.0/example_captions_en.vtt" default> and similar for the French version.
+ * Booleans are converted to HTML5 value-less attributes.
+ */
+ tracks?: Track[];
+ }
+
+ interface Source {
+ /**
+ * The URL of the media file (or YouTube/Vimeo URL).
+ */
+ src: string;
+ /**
+ * The MIME type of the media file (if HTML5).
+ */
+ type?: string;
+ provider?: Provider;
+ size?: number;
+ }
+
+ type TrackKind = "subtitles" | "captions" | "descriptions" | "chapters" | "metadata";
+ interface Track {
+ /**
+ * Indicates how the text track is meant to be used
+ */
+ kind: TrackKind;
+ /**
+ * Indicates a user-readable title for the track
+ */
+ label: string;
+ /**
+ * The language of the track text data. It must be a valid BCP 47 language tag. If the kind attribute is set to subtitles, then srclang must be defined.
+ */
+ srcLang?: string;
+ /**
+ * The URL of the track (.vtt file).
+ */
+ src: string;
+
+ default?: boolean;
+ }
+
+ interface PlyrEvent extends CustomEvent {
+ readonly detail: { readonly plyr: Plyr; };
+ }
+
+ interface Support {
+ api: boolean;
+ ui: boolean;
+ }
+}
diff --git a/src/js/plyr.js b/src/js/plyr.js
index f30d334a..04f1b873 100644
--- a/src/js/plyr.js
+++ b/src/js/plyr.js
@@ -368,10 +368,10 @@ class Plyr {
*/
pause() {
if (!this.playing || !is.function(this.media.pause)) {
- return;
+ return null;
}
- this.media.pause();
+ return this.media.pause();
}
/**
@@ -411,10 +411,10 @@ class Plyr {
const toggle = is.boolean(input) ? input : !this.playing;
if (toggle) {
- this.play();
- } else {
- this.pause();
+ return this.play();
}
+
+ return this.pause();
}
/**
@@ -441,7 +441,7 @@ class Plyr {
* @param {Number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime
*/
rewind(seekTime) {
- this.currentTime = this.currentTime - (is.number(seekTime) ? seekTime : this.config.seekTime);
+ this.currentTime -= is.number(seekTime) ? seekTime : this.config.seekTime;
}
/**
@@ -449,7 +449,7 @@ class Plyr {
* @param {Number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime
*/
forward(seekTime) {
- this.currentTime = this.currentTime + (is.number(seekTime) ? seekTime : this.config.seekTime);
+ this.currentTime += is.number(seekTime) ? seekTime : this.config.seekTime;
}
/**
diff --git a/src/js/ui.js b/src/js/ui.js
index 953ecba2..9febab8b 100644
--- a/src/js/ui.js
+++ b/src/js/ui.js
@@ -214,6 +214,7 @@ const ui = {
// Set state
Array.from(this.elements.buttons.play || []).forEach(target => {
Object.assign(target, { pressed: this.playing });
+ target.setAttribute('aria-label', i18n.get(this.playing ? 'pause' : 'play', this.config));
});
// Only update controls on non timeupdate events
diff --git a/src/js/utils/events.js b/src/js/utils/events.js
index 87c35d26..31571b2d 100644
--- a/src/js/utils/events.js
+++ b/src/js/utils/events.js
@@ -90,9 +90,7 @@ export function triggerEvent(element, type = '', bubbles = false, detail = {}) {
// Create and dispatch the event
const event = new CustomEvent(type, {
bubbles,
- detail: Object.assign({}, detail, {
- plyr: this,
- }),
+ detail: { ...detail, plyr: this,},
});
// Dispatch the event