From ba09bc32d3bcd8002abe1ae4f629fc11ff55a7fc Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Sun, 20 Dec 2020 20:11:41 +1100 Subject: fix: use bound arrow functions in classes --- src/js/fullscreen.js | 30 ++++++------ src/js/listeners.js | 32 ++++++------- src/js/plugins/ads.js | 76 ++++++++++++++--------------- src/js/plugins/preview-thumbnails.js | 92 ++++++++++++++++++------------------ src/js/plyr.js | 64 ++++++++++++------------- src/js/storage.js | 8 ++-- 6 files changed, 151 insertions(+), 151 deletions(-) (limited to 'src/js') diff --git a/src/js/fullscreen.js b/src/js/fullscreen.js index 7bb22391..76acbd06 100644 --- a/src/js/fullscreen.js +++ b/src/js/fullscreen.js @@ -57,6 +57,8 @@ class Fullscreen { // Update the UI this.update(); + + // this.toggle = this.toggle.bind(this); } // Determine if native supported @@ -134,7 +136,7 @@ class Fullscreen { : this.player.elements.fullscreen || this.player.elements.container; } - onChange() { + onChange = () => { if (!this.enabled) { return; } @@ -149,9 +151,9 @@ class Fullscreen { const target = this.target === this.player.media ? this.target : this.player.elements.container; // Trigger an event triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true); - } + }; - toggleFallback(toggle = false) { + toggleFallback = (toggle = false) => { // Store or restore scroll position if (toggle) { this.scrollPosition = { @@ -198,10 +200,10 @@ class Fullscreen { // Toggle button and fire events this.onChange(); - } + }; // Trap focus inside container - trapFocus(event) { + trapFocus = (event) => { // Bail if iOS, not active, not the tab key if (browser.isIos || !this.active || event.key !== 'Tab' || event.keyCode !== 9) { return; @@ -222,10 +224,10 @@ class Fullscreen { last.focus(); event.preventDefault(); } - } + }; // Update UI - update() { + update = () => { if (this.enabled) { let mode; @@ -244,10 +246,10 @@ class Fullscreen { // Add styling hook to show button toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled); - } + }; // Make an element fullscreen - enter() { + enter = () => { if (!this.enabled) { return; } @@ -262,10 +264,10 @@ class Fullscreen { } else if (!is.empty(this.prefix)) { this.target[`${this.prefix}Request${this.property}`](); } - } + }; // Bail from fullscreen - exit() { + exit = () => { if (!this.enabled) { return; } @@ -282,16 +284,16 @@ class Fullscreen { const action = this.prefix === 'moz' ? 'Cancel' : 'Exit'; document[`${this.prefix}${action}${this.property}`](); } - } + }; // Toggle state - toggle() { + toggle = () => { if (!this.active) { this.enter(); } else { this.exit(); } - } + }; } export default Fullscreen; diff --git a/src/js/listeners.js b/src/js/listeners.js index 48734bcf..3d1f8ef0 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -183,7 +183,7 @@ class Listeners { } // Device is touch enabled - firstTouch() { + firstTouch = () => { const { player } = this; const { elements } = player; @@ -191,9 +191,9 @@ class Listeners { // Add touch class toggleClass(elements.container, player.config.classNames.isTouch, true); - } + }; - setTabFocus(event) { + setTabFocus = (event) => { const { player } = this; const { elements } = player; @@ -241,10 +241,10 @@ class Listeners { toggleClass(document.activeElement, player.config.classNames.tabFocus, true); }, 10); } - } + }; // Global window & document listeners - global(toggle = true) { + global = (toggle = true) => { const { player } = this; // Keyboard shortcuts @@ -260,10 +260,10 @@ class Listeners { // Tab focus detection toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true); - } + }; // Container listeners - container() { + container = () => { const { player } = this; const { config, elements, timers } = player; @@ -370,10 +370,10 @@ class Listeners { } } }); - } + }; // Listen for media events - media() { + media = () => { const { player } = this; const { elements } = player; @@ -514,10 +514,10 @@ class Listeners { triggerEvent.call(player, elements.container, event.type, true, detail); }); - } + }; // Run default and custom handlers - proxy(event, defaultHandler, customHandlerKey) { + proxy = (event, defaultHandler, customHandlerKey) => { const { player } = this; const customHandler = player.config.listeners[customHandlerKey]; const hasCustomHandler = is.function(customHandler); @@ -532,10 +532,10 @@ class Listeners { if (returned !== false && is.function(defaultHandler)) { defaultHandler.call(player, event); } - } + }; // Trigger custom and default handlers - bind(element, type, defaultHandler, customHandlerKey, passive = true) { + bind = (element, type, defaultHandler, customHandlerKey, passive = true) => { const { player } = this; const customHandler = player.config.listeners[customHandlerKey]; const hasCustomHandler = is.function(customHandler); @@ -547,10 +547,10 @@ class Listeners { (event) => this.proxy(event, defaultHandler, customHandlerKey), passive && !hasCustomHandler, ); - } + }; // Listen for control events - controls() { + controls = () => { const { player } = this; const { elements } = player; // IE doesn't support input event, so we fallback to change @@ -905,7 +905,7 @@ class Listeners { 'volume', false, ); - } + }; } export default Listeners; diff --git a/src/js/plugins/ads.js b/src/js/plugins/ads.js index 12b5cc31..5d9406d1 100644 --- a/src/js/plugins/ads.js +++ b/src/js/plugins/ads.js @@ -77,7 +77,7 @@ class Ads { /** * Load the IMA SDK */ - load() { + load = () => { if (!this.enabled) { return; } @@ -95,12 +95,12 @@ class Ads { } else { this.ready(); } - } + }; /** * Get the ads instance ready */ - ready() { + ready = () => { // Double check we're enabled if (!this.enabled) { destroy(this); @@ -120,7 +120,7 @@ class Ads { // Setup the IMA SDK this.setupIMA(); - } + }; // Build the tag URL get tagUrl() { @@ -153,7 +153,7 @@ class Ads { * properly place mid-rolls. After we create the ad display container, we initialize it. On * mobile devices, this initialization is done as the result of a user action. */ - setupIMA() { + setupIMA = () => { // Create the container for our advertisements this.elements.container = createElement('div', { class: this.player.config.classNames.ads, @@ -186,12 +186,12 @@ class Ads { // Request video ads to be pre-loaded this.requestAds(); - } + }; /** * Request advertisements */ - requestAds() { + requestAds = () => { const { container } = this.player.elements; try { @@ -216,13 +216,13 @@ class Ads { } catch (e) { this.onAdError(e); } - } + }; /** * Update the ad countdown * @param {Boolean} start */ - pollCountdown(start = false) { + pollCountdown = (start = false) => { if (!start) { clearInterval(this.countdownTimer); this.elements.container.removeAttribute('data-badge-text'); @@ -236,13 +236,13 @@ class Ads { }; this.countdownTimer = setInterval(update, 100); - } + }; /** * This method is called whenever the ads are ready inside the AdDisplayContainer * @param {Event} adsManagerLoadedEvent */ - onAdsManagerLoaded(event) { + onAdsManagerLoaded = (event) => { // Load could occur after a source change (race condition) if (!this.enabled) { return; @@ -273,9 +273,9 @@ class Ads { // Resolve our adsManager this.trigger('loaded'); - } + }; - addCuePoints() { + addCuePoints = () => { // Add advertisement cue's within the time line if available if (!is.empty(this.cuePoints)) { this.cuePoints.forEach((cuePoint) => { @@ -294,7 +294,7 @@ class Ads { } }); } - } + }; /** * This is where all the event handling takes place. Retrieve the ad from the event. Some @@ -302,7 +302,7 @@ class Ads { * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type * @param {Event} event */ - onAdEvent(event) { + onAdEvent = (event) => { const { container } = this.player.elements; // Retrieve the ad from the event. Some events (e.g. ALL_ADS_COMPLETED) // don't have ad object associated @@ -410,23 +410,23 @@ class Ads { default: break; } - } + }; /** * Any ad error handling comes through here * @param {Event} event */ - onAdError(event) { + onAdError = (event) => { this.cancel(); this.player.debug.warn('Ads error', event); - } + }; /** * Setup hooks for Plyr and window events. This ensures * the mid- and post-roll launch at the correct time. And * resize the advertisement when the player resizes */ - listeners() { + listeners = () => { const { container } = this.player.elements; let time; @@ -464,12 +464,12 @@ class Ads { this.manager.resize(container.offsetWidth, container.offsetHeight, google.ima.ViewMode.NORMAL); } }); - } + }; /** * Initialize the adsManager and start playing advertisements */ - play() { + play = () => { const { container } = this.player.elements; if (!this.managerPromise) { @@ -503,12 +503,12 @@ class Ads { } }) .catch(() => {}); - } + }; /** * Resume our video */ - resumeContent() { + resumeContent = () => { // Hide the advertisement container this.elements.container.style.zIndex = ''; @@ -517,12 +517,12 @@ class Ads { // Play video silencePromise(this.player.media.play()); - } + }; /** * Pause our video */ - pauseContent() { + pauseContent = () => { // Show the advertisement container this.elements.container.style.zIndex = 3; @@ -531,7 +531,7 @@ class Ads { // Pause our video. this.player.media.pause(); - } + }; /** * Destroy the adsManager so we can grab new ads after this. If we don't then we're not @@ -539,7 +539,7 @@ class Ads { * video requests. https://developers.google.com/interactive- * media-ads/docs/sdks/android/faq#8 */ - cancel() { + cancel = () => { // Pause our video if (this.initialized) { this.resumeContent(); @@ -550,12 +550,12 @@ class Ads { // Re-create our adsManager this.loadAds(); - } + }; /** * Re-create our adsManager */ - loadAds() { + loadAds = () => { // Tell our adsManager to go bye bye this.managerPromise .then(() => { @@ -576,13 +576,13 @@ class Ads { this.requestAds(); }) .catch(() => {}); - } + }; /** * Handles callbacks after an ad event was invoked * @param {String} event - Event type */ - trigger(event, ...args) { + trigger = (event, ...args) => { const handlers = this.events[event]; if (is.array(handlers)) { @@ -592,7 +592,7 @@ class Ads { } }); } - } + }; /** * Add event listeners @@ -600,7 +600,7 @@ class Ads { * @param {Function} callback - Callback for when event occurs * @return {Ads} */ - on(event, callback) { + on = (event, callback) => { if (!is.array(this.events[event])) { this.events[event] = []; } @@ -608,7 +608,7 @@ class Ads { this.events[event].push(callback); return this; - } + }; /** * Setup a safety timer for when the ad network doesn't respond for whatever reason. @@ -618,27 +618,27 @@ class Ads { * @param {Number} time * @param {String} from */ - startSafetyTimer(time, from) { + startSafetyTimer = (time, from) => { this.player.debug.log(`Safety timer invoked from: ${from}`); this.safetyTimer = setTimeout(() => { this.cancel(); this.clearSafetyTimer('startSafetyTimer()'); }, time); - } + }; /** * Clear our safety timer(s) * @param {String} from */ - clearSafetyTimer(from) { + clearSafetyTimer = (from) => { if (!is.nullOrUndefined(this.safetyTimer)) { this.player.debug.log(`Safety timer cleared from: ${from}`); clearTimeout(this.safetyTimer); this.safetyTimer = null; } - } + }; } export default Ads; diff --git a/src/js/plugins/preview-thumbnails.js b/src/js/plugins/preview-thumbnails.js index 16167247..80e8cd4a 100644 --- a/src/js/plugins/preview-thumbnails.js +++ b/src/js/plugins/preview-thumbnails.js @@ -103,7 +103,7 @@ class PreviewThumbnails { return this.player.isHTML5 && this.player.isVideo && this.player.config.previewThumbnails.enabled; } - load() { + load = () => { // Toggle the regular seek tooltip if (this.player.elements.display.seekTooltip) { this.player.elements.display.seekTooltip.hidden = this.enabled; @@ -126,10 +126,10 @@ class PreviewThumbnails { this.loaded = true; }); - } + }; // Download VTT files and parse them - getThumbnails() { + getThumbnails = () => { return new Promise((resolve) => { const { src } = this.player.config.previewThumbnails; @@ -164,10 +164,10 @@ class PreviewThumbnails { Promise.all(promises).then(sortAndResolve); } }); - } + }; // Process individual VTT file - getThumbnail(url) { + getThumbnail = (url) => { return new Promise((resolve) => { fetch(url).then((response) => { const thumbnail = { @@ -202,9 +202,9 @@ class PreviewThumbnails { tempImage.src = thumbnail.urlPrefix + thumbnail.frames[0].text; }); }); - } + }; - startMove(event) { + startMove = (event) => { if (!this.loaded) { return; } @@ -245,13 +245,13 @@ class PreviewThumbnails { // Download and show image this.showImageAtCurrentTime(); - } + }; - endMove() { + endMove = () => { this.toggleThumbContainer(false, true); - } + }; - startScrubbing(event) { + startScrubbing = (event) => { // Only act on left mouse button (0), or touch device (event.button does not exist or is false) if (is.nullOrUndefined(event.button) || event.button === false || event.button === 0) { this.mouseDown = true; @@ -265,9 +265,9 @@ class PreviewThumbnails { this.showImageAtCurrentTime(); } } - } + }; - endScrubbing() { + endScrubbing = () => { this.mouseDown = false; // Hide scrubbing preview. But wait until the video has successfully seeked before hiding the scrubbing preview @@ -283,12 +283,12 @@ class PreviewThumbnails { } }); } - } + }; /** * Setup hooks for Plyr and window events */ - listeners() { + listeners = () => { // Hide thumbnail preview - on mouse click, mouse leave (in listeners.js for now), and video play/seek. All four are required, e.g., for buffering this.player.on('play', () => { this.toggleThumbContainer(false, true); @@ -301,12 +301,12 @@ class PreviewThumbnails { this.player.on('timeupdate', () => { this.lastTime = this.player.media.currentTime; }); - } + }; /** * Create HTML elements for image containers */ - render() { + render = () => { // Create HTML element: plyr__preview-thumbnail-container this.elements.thumb.container = createElement('div', { class: this.player.config.classNames.previewThumbnails.thumbContainer, @@ -339,18 +339,18 @@ class PreviewThumbnails { }); this.player.elements.wrapper.appendChild(this.elements.scrubbing.container); - } + }; - destroy() { + destroy = () => { if (this.elements.thumb.container) { this.elements.thumb.container.remove(); } if (this.elements.scrubbing.container) { this.elements.scrubbing.container.remove(); } - } + }; - showImageAtCurrentTime() { + showImageAtCurrentTime = () => { if (this.mouseDown) { this.setScrubbingContainerSize(); } else { @@ -387,10 +387,10 @@ class PreviewThumbnails { this.showingThumb = thumbNum; this.loadImage(qualityIndex); } - } + }; // Show the image that's currently specified in this.showingThumb - loadImage(qualityIndex = 0) { + loadImage = (qualityIndex = 0) => { const thumbNum = this.showingThumb; const thumbnail = this.thumbnails[qualityIndex]; const { urlPrefix } = thumbnail; @@ -426,9 +426,9 @@ class PreviewThumbnails { this.currentImageElement.dataset.index = thumbNum; this.removeOldImages(this.currentImageElement); } - } + }; - showImage(previewImage, frame, qualityIndex, thumbNum, thumbFilename, newImage = true) { + showImage = (previewImage, frame, qualityIndex, thumbNum, thumbFilename, newImage = true) => { this.player.debug.log( `Showing thumb: ${thumbFilename}. num: ${thumbNum}. qual: ${qualityIndex}. newimg: ${newImage}`, ); @@ -449,10 +449,10 @@ class PreviewThumbnails { this.preloadNearby(thumbNum, true) .then(this.preloadNearby(thumbNum, false)) .then(this.getHigherQuality(qualityIndex, previewImage, frame, thumbFilename)); - } + }; // Remove all preview images that aren't the designated current image - removeOldImages(currentImage) { + removeOldImages = (currentImage) => { // Get a list of all images, convert it from a DOM list to an array Array.from(this.currentImageContainer.children).forEach((image) => { if (image.tagName.toLowerCase() !== 'img') { @@ -476,11 +476,11 @@ class PreviewThumbnails { }, removeDelay); } }); - } + }; // Preload images before and after the current one. Only if the user is still hovering/seeking the same frame // This will only preload the lowest quality - preloadNearby(thumbNum, forward = true) { + preloadNearby = (thumbNum, forward = true) => { return new Promise((resolve) => { setTimeout(() => { const oldThumbFilename = this.thumbnails[0].frames[thumbNum].text; @@ -527,10 +527,10 @@ class PreviewThumbnails { } }, 300); }); - } + }; // If user has been hovering current image for half a second, look for a higher quality one - getHigherQuality(currentQualityIndex, previewImage, frame, thumbFilename) { + getHigherQuality = (currentQualityIndex, previewImage, frame, thumbFilename) => { if (currentQualityIndex < this.thumbnails.length - 1) { // Only use the higher quality version if it's going to look any better - if the current thumb is of a lower pixel density than the thumbnail container let previewImageHeight = previewImage.naturalHeight; @@ -550,7 +550,7 @@ class PreviewThumbnails { }, 300); } } - } + }; get currentImageContainer() { if (this.mouseDown) { @@ -605,7 +605,7 @@ class PreviewThumbnails { } } - toggleThumbContainer(toggle = false, clearShowing = false) { + toggleThumbContainer = (toggle = false, clearShowing = false) => { const className = this.player.config.classNames.previewThumbnails.thumbContainerShown; this.elements.thumb.container.classList.toggle(className, toggle); @@ -613,9 +613,9 @@ class PreviewThumbnails { this.showingThumb = null; this.showingThumbFilename = null; } - } + }; - toggleScrubbingContainer(toggle = false) { + toggleScrubbingContainer = (toggle = false) => { const className = this.player.config.classNames.previewThumbnails.scrubbingContainerShown; this.elements.scrubbing.container.classList.toggle(className, toggle); @@ -623,17 +623,17 @@ class PreviewThumbnails { this.showingThumb = null; this.showingThumbFilename = null; } - } + }; - determineContainerAutoSizing() { + determineContainerAutoSizing = () => { if (this.elements.thumb.imageContainer.clientHeight > 20 || this.elements.thumb.imageContainer.clientWidth > 20) { // This will prevent auto sizing in this.setThumbContainerSizeAndPos() this.sizeSpecifiedInCSS = true; } - } + }; // Set the size to be about a quarter of the size of video. Unless option dynamicSize === false, in which case it needs to be set in CSS - setThumbContainerSizeAndPos() { + setThumbContainerSizeAndPos = () => { if (!this.sizeSpecifiedInCSS) { const thumbWidth = Math.floor(this.thumbContainerHeight * this.thumbAspectRatio); this.elements.thumb.imageContainer.style.height = `${this.thumbContainerHeight}px`; @@ -653,9 +653,9 @@ class PreviewThumbnails { } this.setThumbContainerPos(); - } + }; - setThumbContainerPos() { + setThumbContainerPos = () => { const seekbarRect = this.player.elements.progress.getBoundingClientRect(); const plyrRect = this.player.elements.container.getBoundingClientRect(); const { container } = this.elements.thumb; @@ -674,20 +674,20 @@ class PreviewThumbnails { } container.style.left = `${previewPos}px`; - } + }; // Can't use 100% width, in case the video is a different aspect ratio to the video container - setScrubbingContainerSize() { + setScrubbingContainerSize = () => { const { width, height } = fitRatio(this.thumbAspectRatio, { width: this.player.media.clientWidth, height: this.player.media.clientHeight, }); this.elements.scrubbing.container.style.width = `${width}px`; this.elements.scrubbing.container.style.height = `${height}px`; - } + }; // Sprites need to be offset to the correct location - setImageSizeAndOffset(previewImage, frame) { + setImageSizeAndOffset = (previewImage, frame) => { if (!this.usingSprites) { return; } @@ -703,7 +703,7 @@ class PreviewThumbnails { previewImage.style.left = `-${frame.x * multiplier}px`; // eslint-disable-next-line no-param-reassign previewImage.style.top = `-${frame.y * multiplier}px`; - } + }; } export default PreviewThumbnails; diff --git a/src/js/plyr.js b/src/js/plyr.js index 6c507893..b37893bc 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -355,7 +355,7 @@ class Plyr { /** * Play the media, or play the advertisement (if they are not blocked) */ - play() { + play = () => { if (!is.function(this.media.play)) { return null; } @@ -367,18 +367,18 @@ class Plyr { // Return the promise (for HTML5) return this.media.play(); - } + }; /** * Pause the media */ - pause() { + pause = () => { if (!this.playing || !is.function(this.media.pause)) { return null; } return this.media.pause(); - } + }; /** * Get playing state @@ -412,7 +412,7 @@ class Plyr { * Toggle playback based on current status * @param {Boolean} input */ - togglePlay(input) { + togglePlay = (input) => { // Toggle based on current state if nothing passed const toggle = is.boolean(input) ? input : !this.playing; @@ -421,42 +421,42 @@ class Plyr { } return this.pause(); - } + }; /** * Stop playback */ - stop() { + stop = () => { if (this.isHTML5) { this.pause(); this.restart(); } else if (is.function(this.media.stop)) { this.media.stop(); } - } + }; /** * Restart playback */ - restart() { + restart = () => { this.currentTime = 0; - } + }; /** * Rewind * @param {Number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime */ - rewind(seekTime) { + rewind = (seekTime) => { this.currentTime -= is.number(seekTime) ? seekTime : this.config.seekTime; - } + }; /** * Fast forward * @param {Number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime */ - forward(seekTime) { + forward = (seekTime) => { this.currentTime += is.number(seekTime) ? seekTime : this.config.seekTime; - } + }; /** * Seek to a time @@ -582,18 +582,18 @@ class Plyr { * Increase volume * @param {Boolean} step - How much to decrease by (between 0 and 1) */ - increaseVolume(step) { + increaseVolume = (step) => { const volume = this.media.muted ? 0 : this.volume; this.volume = volume + (is.number(step) ? step : 0); - } + }; /** * Decrease volume * @param {Boolean} step - How much to decrease by (between 0 and 1) */ - decreaseVolume(step) { + decreaseVolume = (step) => { this.increaseVolume(-step); - } + }; /** * Set muted state @@ -1033,18 +1033,18 @@ class Plyr { * Trigger the airplay dialog * TODO: update player with state, support, enabled */ - airplay() { + airplay = () => { // Show dialog if supported if (support.airplay) { this.media.webkitShowPlaybackTargetPicker(); } - } + }; /** * Toggle the player controls * @param {Boolean} [toggle] - Whether to show the controls */ - toggleControls(toggle) { + toggleControls = (toggle) => { // Don't toggle if missing UI support or if it's audio if (this.supported.ui && !this.isAudio) { // Get state before change @@ -1074,34 +1074,34 @@ class Plyr { } return false; - } + }; /** * Add event listeners * @param {String} event - Event type * @param {Function} callback - Callback for when event occurs */ - on(event, callback) { + on = (event, callback) => { on.call(this, this.elements.container, event, callback); - } + }; /** * Add event listeners once * @param {String} event - Event type * @param {Function} callback - Callback for when event occurs */ - once(event, callback) { + once = (event, callback) => { once.call(this, this.elements.container, event, callback); - } + }; /** * Remove event listeners * @param {String} event - Event type * @param {Function} callback - Callback for when event occurs */ - off(event, callback) { + off = (event, callback) => { off(this.elements.container, event, callback); - } + }; /** * Destroy an instance @@ -1110,7 +1110,7 @@ class Plyr { * @param {Function} callback - Callback for when destroy is complete * @param {Boolean} soft - Whether it's a soft destroy (for source changes etc) */ - destroy(callback, soft = false) { + destroy = (callback, soft = false) => { if (!this.ready) { return; } @@ -1208,15 +1208,13 @@ class Plyr { // Vimeo does not always return setTimeout(done, 200); } - } + }; /** * Check for support for a mime type (HTML5 only) * @param {String} type - Mime type */ - supports(type) { - return support.mime.call(this, type); - } + supports = (type) => support.mime.call(this, type); /** * Check for support diff --git a/src/js/storage.js b/src/js/storage.js index 85b5e2b5..323a6d25 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -31,7 +31,7 @@ class Storage { } } - get(key) { + get = (key) => { if (!Storage.supported || !this.enabled) { return null; } @@ -45,9 +45,9 @@ class Storage { const json = JSON.parse(store); return is.string(key) && key.length ? json[key] : json; - } + }; - set(object) { + set = (object) => { // Bail if we don't have localStorage support or it's disabled if (!Storage.supported || !this.enabled) { return; @@ -71,7 +71,7 @@ class Storage { // Update storage window.localStorage.setItem(this.key, JSON.stringify(storage)); - } + }; } export default Storage; -- cgit v1.2.3 From aa3378fd7303c42059728155719ff57952bb0fcc Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Fri, 29 Jan 2021 23:14:02 +1100 Subject: v3.6.4 (#2089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * force fullscreen events to trigger on plyr element (media element in iOS) and not fullscreen container * Fixing "missing code in detail" for PlyrEvent type When using typescript and listening for youtube statechange event, it is missing the code property definition inside the event (even though it is provided in the code). By making events a map of key-value, we can add easily custom event type for specific event name. Since YouTube "statechange" event differs from the basic PlyrEvent, I added a new Event Type "PlyrStateChangeEvent" having a code property corresponding to a YoutubeState enum defined by the YouTube API documentation. This pattern follows how addEventListener in the lib.dom.d.ts is defined. * Update link to working dash.js demo (was broken) * Fix PreviewThumbnailsOptions type According to the docs, the `src` should also accept an array of strings. * fix issue #1872 * Check if key is a string before attempt --plyr checking * Fix for Slow loading videos not autoplaying * Fix for Slow loading videos not autoplaying * Network requests are not cancelled after the player is destroyed * Fix for apect ratio problem when using Vimeo player on mobile devices (issue #1940) * chore: update packages and linting * Invoke custom listener on triggering fullscreen via double-click * Fix volume when unmuting from volume 0 * adding a nice Svelte plugin that I found * Add missing unit to calc in media query * Assigning player's lastSeekTime on rewind/fast forward to prevent immediate controls hide on mobile * Fix youtube not working when player is inside shadow dom * v3.6.2 * ESLint to use common config * add BitChute to users list * Fix aspect ratio issue * Revert noCookie change * feat: demo radius tweaks * fix: poster image shouldn’t receive click events * chore: package updates * chore: linting * feat: custom controls option for embedded players * Package upgrades * ESLint to use common config * Linting changes * Update README.md * chore: formatting * fix: revert pointer events change for poster * fix: hack for Safari 14 not repainting Vimeo embed on entering fullscreen * fix: demo using custom controls for YouTube * doc: Add STROLLÿN among the list of Plyr users * Fixes #2005 * fix: overflowing volume slider * chore: clean up CSS * fix: hide poster when not using custom controls * Package upgrades * ESLint to use common config * Linting changes * chore: revert customControls default option (to prevent breaking change) * docs: changelog for v3.6.3 * Remove unnecessary calc from media query (#2049) * Enhance types (#1841) * 🏷️(type) enhance QualityOptions type Some optional properties in the QualityOptions were missing. The forced and onChange property allwoing to use an external handler. * ♻️(type) use Plyr.Provider for the readonly provider property A type exists to define all available providers. This type isn't used in the Plyr class definition and the same provider list is also defined. This code is refactored to use the Plyr.Provider type * 🏷️(type) add missing elements property in Plyr class In Plyr class, you can access elements set in cache. This property is missing in the class definition. The Plyr.Elements is for now incomplete. * FIX - object values for the providers must be used (#2053) To make use of the provider configuration, the objects values must be used. * Fix to work inside iframes. (#2069) * Fix to work inside iframes. Right now Plyr fails to load inside iframes because the selectors are not instances of Element (iframes have their own, separate globals). This is an alternative method to check isElement that will work inside iframes. This is battle-tested fallback code used before browsers supported HTMLElement. * Update is.js * Added --plyr-video-background for having control over the background of a video with alpha channel (webm) or a poster image with alpha channel. (#2076) * Fix issue with not entering iosfullscreen of vimeo videos with playsi… (#2038) * Fix issue with not entering iosfullscreen of vimeo videos with playsinline=true * Use isVimeo-function instead of hardcoded value Co-authored-by: Julian Frosch * fix: use new syntax for iframe allow attribute * Bump ini from 1.3.5 to 1.3.7 (#2044) Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7. - [Release notes](https://github.com/isaacs/ini/releases) - [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: package updates * chore: add @babel/plugin-proposal-class-properties * fix: use bound arrow functions in classes * chore: cleanup commented out code * chore: release Co-authored-by: Som Meaden Co-authored-by: akuma06 Co-authored-by: Jonathan Arbely Co-authored-by: Takeshi Co-authored-by: Hex Co-authored-by: Syed Husain Co-authored-by: Danielh112 Co-authored-by: Danil Stoyanov Co-authored-by: Guru Prasad Srinivasa Co-authored-by: Stephane Fortin Bouchard Co-authored-by: Zev Averbach Co-authored-by: Vincent Orback Co-authored-by: trafium Co-authored-by: xansen <27698939+xansen@users.noreply.github.com> Co-authored-by: zoomerdev <59863739+zoomerdev@users.noreply.github.com> Co-authored-by: Mikaël Castellani Co-authored-by: dirkjf Co-authored-by: Naomi Co-authored-by: Manuel Raynaud Co-authored-by: syteknet-core Co-authored-by: Andre Gagnon Co-authored-by: Nepomuk Leutschacher <864660+nepomuc@users.noreply.github.com> Co-authored-by: Elias Saalmann Co-authored-by: Julian Frosch Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/js/fullscreen.js | 6 +++++- src/js/plugins/vimeo.js | 2 +- src/js/plyr.d.ts | 30 +++++++++++++++++++++++++++++- src/js/plyr.js | 2 +- src/js/utils/is.js | 8 +++++++- 5 files changed, 43 insertions(+), 5 deletions(-) (limited to 'src/js') diff --git a/src/js/fullscreen.js b/src/js/fullscreen.js index 76acbd06..20e958fc 100644 --- a/src/js/fullscreen.js +++ b/src/js/fullscreen.js @@ -256,7 +256,11 @@ class Fullscreen { // iOS native fullscreen doesn't need the request step if (browser.isIos && this.player.config.fullscreen.iosNative) { - this.target.webkitEnterFullscreen(); + if (this.player.isVimeo) { + this.player.embed.requestFullscreen(); + } else { + this.target.webkitEnterFullscreen(); + } } else if (!Fullscreen.native || this.forceFallback) { this.toggleFallback(true); } else if (!this.prefix) { diff --git a/src/js/plugins/vimeo.js b/src/js/plugins/vimeo.js index b050cc53..5fe41aba 100644 --- a/src/js/plugins/vimeo.js +++ b/src/js/plugins/vimeo.js @@ -104,7 +104,7 @@ const vimeo = { const src = format(player.config.urls.vimeo.iframe, id, params); iframe.setAttribute('src', src); iframe.setAttribute('allowfullscreen', ''); - iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); + iframe.setAttribute('allow', ['autoplay', 'fullscreen', 'picture-in-picture'].join('; ')); // Set the referrer policy if required if (!is.empty(referrerPolicy)) { diff --git a/src/js/plyr.d.ts b/src/js/plyr.d.ts index 4b332aeb..479cfa98 100644 --- a/src/js/plyr.d.ts +++ b/src/js/plyr.d.ts @@ -138,10 +138,15 @@ declare class Plyr { */ ratio?: string; + /** + * Access Elements cache + */ + elements: Plyr.Elements; + /** * Returns the current video Provider */ - readonly provider: 'html5' | 'vimeo' | 'youtube'; + readonly provider: Plyr.Provider; /** * Returns the native API for Vimeo or Youtube players @@ -510,6 +515,8 @@ declare namespace Plyr { interface QualityOptions { default: number; + forced?: boolean; + onChange?: (quality: number) => void; options: number[]; } @@ -560,6 +567,27 @@ declare namespace Plyr { src?: string | string[]; } + export interface Elements { + buttons: { + airplay?: HTMLButtonElement; + captions?: HTMLButtonElement; + download?: HTMLButtonElement; + fastForward?: HTMLButtonElement; + fullscreen?: HTMLButtonElement; + mute?: HTMLButtonElement; + pip?: HTMLButtonElement; + play?: HTMLButtonElement | HTMLButtonElement[]; + restart?: HTMLButtonElement; + rewind?: HTMLButtonElement; + settings?: HTMLButtonElement; + }; + captions: HTMLElement | null; + container: HTMLElement | null; + controls: HTMLElement | null; + fullscreen: HTMLElement | null; + wrapper: HTMLElement | null; + } + interface SourceInfo { /** * Note: YouTube and Vimeo are currently not supported as audio sources. diff --git a/src/js/plyr.js b/src/js/plyr.js index b37893bc..e67e29d4 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -206,7 +206,7 @@ class Plyr { } // Unsupported or missing provider - if (is.empty(this.provider) || !Object.keys(providers).includes(this.provider)) { + if (is.empty(this.provider) || !Object.values(providers).includes(this.provider)) { this.debug.error('Setup failed: Invalid provider'); return; } diff --git a/src/js/utils/is.js b/src/js/utils/is.js index 3bb50a00..5a60da06 100644 --- a/src/js/utils/is.js +++ b/src/js/utils/is.js @@ -13,7 +13,6 @@ const isFunction = (input) => getConstructor(input) === Function; const isArray = (input) => Array.isArray(input); const isWeakMap = (input) => instanceOf(input, WeakMap); const isNodeList = (input) => instanceOf(input, NodeList); -const isElement = (input) => instanceOf(input, Element); const isTextNode = (input) => getConstructor(input) === Text; const isEvent = (input) => instanceOf(input, Event); const isKeyboardEvent = (input) => instanceOf(input, KeyboardEvent); @@ -21,6 +20,13 @@ const isCue = (input) => instanceOf(input, window.TextTrackCue) || instanceOf(in const isTrack = (input) => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind)); const isPromise = (input) => instanceOf(input, Promise) && isFunction(input.then); +const isElement = (input) => + input !== null && + (typeof input === "object") && + (input.nodeType === 1) && + (typeof input.style === "object") && + (typeof input.ownerDocument === "object"); + const isEmpty = (input) => isNullOrUndefined(input) || ((isString(input) || isArray(input) || isNodeList(input)) && !input.length) || -- cgit v1.2.3 From a187d07807415a833baf340793e988f81751478e Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Fri, 29 Jan 2021 23:28:02 +1100 Subject: chore: linting fix --- src/js/utils/is.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/js') diff --git a/src/js/utils/is.js b/src/js/utils/is.js index 5a60da06..28f0c1a4 100644 --- a/src/js/utils/is.js +++ b/src/js/utils/is.js @@ -21,11 +21,11 @@ const isTrack = (input) => instanceOf(input, TextTrack) || (!isNullOrUndefined(i const isPromise = (input) => instanceOf(input, Promise) && isFunction(input.then); const isElement = (input) => - input !== null && - (typeof input === "object") && - (input.nodeType === 1) && - (typeof input.style === "object") && - (typeof input.ownerDocument === "object"); + input !== null && + typeof input === 'object' && + input.nodeType === 1 && + typeof input.style === 'object' && + typeof input.ownerDocument === 'object'; const isEmpty = (input) => isNullOrUndefined(input) || -- cgit v1.2.3 From 1aee8f53a725df3c6f93e8a8c890a2e8bb9d03bf Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Fri, 29 Jan 2021 23:40:34 +1100 Subject: chore: publish 3.6.4 --- src/js/config/defaults.js | 2 +- src/js/plyr.js | 2 +- src/js/plyr.polyfilled.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/js') diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index 74083e53..7a73c318 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -61,7 +61,7 @@ const defaults = { // Sprite (for icons) loadSprite: true, iconPrefix: 'plyr', - iconUrl: 'https://cdn.plyr.io/3.6.3/plyr.svg', + iconUrl: 'https://cdn.plyr.io/3.6.4/plyr.svg', // Blank video (used to prevent errors on source change) blankVideo: 'https://cdn.plyr.io/static/blank.mp4', diff --git a/src/js/plyr.js b/src/js/plyr.js index e67e29d4..b40f5c5a 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -1,6 +1,6 @@ // ========================================================================== // Plyr -// plyr.js v3.6.3 +// plyr.js v3.6.4 // https://github.com/sampotts/plyr // License: The MIT License (MIT) // ========================================================================== diff --git a/src/js/plyr.polyfilled.js b/src/js/plyr.polyfilled.js index 79a58a31..f8f613e7 100644 --- a/src/js/plyr.polyfilled.js +++ b/src/js/plyr.polyfilled.js @@ -1,6 +1,6 @@ // ========================================================================== // Plyr Polyfilled Build -// plyr.js v3.6.3 +// plyr.js v3.6.4 // https://github.com/sampotts/plyr // License: The MIT License (MIT) // ========================================================================== -- cgit v1.2.3