From 1486862e8ae8094a0718fd43fea2875706d47a14 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 11 Aug 2017 14:24:13 -0400 Subject: [PATCH 1/7] fix: pull out boolean attributes and have them set/check both attribute and property --- src/js/tech/html5.js | 376 ++++++++++++++++++++++--------------------- 1 file changed, 194 insertions(+), 182 deletions(-) diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index d0f59cdc7e..067c69d5c8 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -673,43 +673,6 @@ class Html5 extends Tech { } } - /** - * Get the value of `playsinline` from the media element. `playsinline` indicates - * to the browser that non-fullscreen playback is preferred when fullscreen - * playback is the native default, such as in iOS Safari. - * - * @method Html5#playsinline - * @return {boolean} - * - The value of `playsinline` from the media element. - * - True indicates that the media should play inline. - * - False indicates that the media should not play inline. - * - * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} - */ - playsinline() { - return this.el_.hasAttribute('playsinline'); - } - - /** - * Set the value of `playsinline` from the media element. `playsinline` indicates - * to the browser that non-fullscreen playback is preferred when fullscreen - * playback is the native default, such as in iOS Safari. - * - * @method Html5#setPlaysinline - * @param {boolean} playsinline - * - True indicates that the media should play inline. - * - False indicates that the media should not play inline. - * - * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} - */ - setPlaysinline(value) { - if (value) { - this.el_.setAttribute('playsinline', 'playsinline'); - } else { - this.el_.removeAttribute('playsinline'); - } - } - /** * Gets available media playback quality metrics as specified by the W3C's Media * Playback Quality API. @@ -1094,8 +1057,198 @@ Html5.resetMediaElement = function(el) { } }; + /* Native HTML5 element property wrapping ----------------------------------- */ +// Wrap native boolean attributes with getters that check both property and attribute +// The list is as followed: +// muted, defaultMuted, autoplay, controls, loop, playsinline +[ + /** + * Get the value of `muted` from the media element. `muted` indicates + * that the volume for the media should be set to silent. This does not actually change + * the `volume` attribute. + * + * @method Html5#muted + * @return {boolean} + * - True if the value of `volume` should be ignored and the audio set to silent. + * - False if the value of `volume` should be used. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} + */ + 'muted', + + /** + * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. {@link Html5#muted} indicates the + * current state. + * + * @method Html5#defaultMuted + * @return {boolean} + * - The value of `defaultMuted` from the media element. + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} + */ + 'defaultMuted', + + /** + * Get the value of `autoplay` from the media element. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Html5#autoplay + * @return {boolean} + * - The value of `autoplay` from the media element. + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} + */ + 'autoplay', + + /** + * Get the value of `controls` from the media element. `controls` indicates + * whether the native media controls should be shown or hidden. + * + * @method Html5#controls + * @return {boolean} + * - The value of `controls` from the media element. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls} + */ + 'controls', + + /** + * Get the value of `loop` from the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Html5#loop + * @return {boolean} + * - The value of `loop` from the media element. + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} + */ + 'loop', + + /** + * Get the value of `playsinline` from the media element. `playsinline` indicates + * to the browser that non-fullscreen playback is preferred when fullscreen + * playback is the native default, such as in iOS Safari. + * + * @method Html5#playsinline + * @return {boolean} + * - The value of `playsinline` from the media element. + * - True indicates that the media should play inline. + * - False indicates that the media should not play inline. + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + 'playsinline' +].forEach(function(prop) { + Html5.prototype[prop] = function() { + return this.el_[prop] || this.el_.hasAttribute(prop); + }; +}); + +// Wrap native boolean attributes with setters that set both property and attribute +// The list is as followed: +// setMuted, setDefaultMuted, setAutoplay, setLoop, setPlaysinline +// setControls is special-cased above +[ + /** + * Set the value of `muted` on the media element. `muted` indicates that the current + * audio level should be silent. + * + * @method Html5#setMuted + * @param {boolean} muted + * - True if the audio should be set to silent + * - False otherwise + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} + */ + 'muted', + + /** + * Set the value of `defaultMuted` on the media element. `defaultMuted` indicates that the current + * audio level should be silent, but will only effect the muted level on intial playback.. + * + * @method Html5.prototype.setDefaultMuted + * @param {boolean} defaultMuted + * - True if the audio should be set to silent + * - False otherwise + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} + */ + 'defaultMuted', + + /** + * Set the value of `autoplay` on the media element. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Html5#setAutoplay + * @param {boolean} autoplay + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} + */ + 'autoplay', + + /** + * Set the value of `loop` on the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Html5#setLoop + * @param {boolean} loop + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} + */ + 'loop', + + /** + * Set the value of `playsinline` from the media element. `playsinline` indicates + * to the browser that non-fullscreen playback is preferred when fullscreen + * playback is the native default, such as in iOS Safari. + * + * @method Html5#setPlaysinline + * @param {boolean} playsinline + * - True indicates that the media should play inline. + * - False indicates that the media should not play inline. + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + 'playsinline' +].forEach(function(prop) { + Html5.prototype['set' + toTitleCase(prop)] = function(v) { + console.log(prop, v); + this.el_[prop] = v; + + if (v) { + this.el_.setAttribute(prop, prop); + } else { + this.el_.removeAttribute(prop); + } + }; +}); + // Wrap native properties with a getter +// The list is as followed +// paused, currentTime, buffered, volume, poster, preload, error, seeking +// seekable, ended, playbackRate, defaultPlaybackRate, played, networkState +// readyState, videoWidth, videoHeight [ /** * Get the value of `paused` from the media element. `paused` indicates whether the media element @@ -1147,35 +1300,6 @@ Html5.resetMediaElement = function(el) { */ 'volume', - /** - * Get the value of `muted` from the media element. `muted` indicates - * that the volume for the media should be set to silent. This does not actually change - * the `volume` attribute. - * - * @method Html5#muted - * @return {boolean} - * - True if the value of `volume` should be ignored and the audio set to silent. - * - False if the value of `volume` should be used. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} - */ - 'muted', - - /** - * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates - * that the volume for the media should be set to silent when the video first starts. - * This does not actually change the `volume` attribute. After playback has started `muted` - * will indicate the current status of the volume and `defaultMuted` will not. - * - * @method Html5.prototype.defaultMuted - * @return {boolean} - * - True if the value of `volume` should be ignored and the audio set to silent. - * - False if the value of `volume` should be used. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} - */ - 'defaultMuted', - /** * Get the value of `poster` from the media element. `poster` indicates * that the url of an image file that can/will be shown when no media data is available. @@ -1208,51 +1332,6 @@ Html5.resetMediaElement = function(el) { */ 'preload', - /** - * Get the value of `autoplay` from the media element. `autoplay` indicates - * that the media should start to play as soon as the page is ready. - * - * @method Html5#autoplay - * @return {boolean} - * - The value of `autoplay` from the media element. - * - True indicates that the media should start as soon as the page loads. - * - False indicates that the media should not start as soon as the page loads. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} - */ - 'autoplay', - - /** - * Get the value of `controls` from the media element. `controls` indicates - * whether the native media controls should be shown or hidden. - * - * @method Html5#controls - * @return {boolean} - * - The value of `controls` from the media element. - * - True indicates that native controls should be showing. - * - False indicates that native controls should be hidden. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls} - */ - 'controls', - - /** - * Get the value of `loop` from the media element. `loop` indicates - * that the media should return to the start of the media and continue playing once - * it reaches the end. - * - * @method Html5#loop - * @return {boolean} - * - The value of `loop` from the media element. - * - True indicates that playback should seek back to start once - * the end of a media is reached. - * - False indicates that playback should not loop back to the start when the - * end of the media is reached. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} - */ - 'loop', - /** * Get the value of the `error` from the media element. `error` indicates any * MediaError that may have occured during playback. If error returns null there is no @@ -1308,22 +1387,6 @@ Html5.resetMediaElement = function(el) { */ 'ended', - /** - * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates - * whether the media should start muted or not. Only changes the default state of the - * media. `muted` and `defaultMuted` can have different values. {@link Html5#muted} indicates the - * current state. - * - * @method Html5#defaultMuted - * @return {boolean} - * - The value of `defaultMuted` from the media element. - * - True indicates that the media should start muted. - * - False indicates that the media should not start muted - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} - */ - 'defaultMuted', - /** * Get the value of `playbackRate` from the media element. `playbackRate` indicates * the rate at which the media is currently playing back. Examples: @@ -1439,6 +1502,8 @@ Html5.resetMediaElement = function(el) { // Wrap native properties with a setter in this format: // set + toTitleCase(name) +// The list is as follows: +// setVolume, setSrc, setPoster, setPreload, setPlaybackRate, setDefaultPlaybackRate [ /** * Set the value of `volume` on the media element. `volume` indicates the current @@ -1453,32 +1518,6 @@ Html5.resetMediaElement = function(el) { */ 'volume', - /** - * Set the value of `muted` on the media element. `muted` indicates that the current - * audio level should be silent. - * - * @method Html5#setMuted - * @param {boolean} muted - * - True if the audio should be set to silent - * - False otherwise - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} - */ - 'muted', - - /** - * Set the value of `defaultMuted` on the media element. `defaultMuted` indicates that the current - * audio level should be silent, but will only effect the muted level on intial playback.. - * - * @method Html5.prototype.setDefaultMuted - * @param {boolean} defaultMuted - * - True if the audio should be set to silent - * - False otherwise - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} - */ - 'defaultMuted', - /** * Set the value of `src` on the media element. `src` indicates the current * {@link Tech~SourceObject} for the media. @@ -1523,35 +1562,6 @@ Html5.resetMediaElement = function(el) { */ 'preload', - /** - * Set the value of `autoplay` on the media element. `autoplay` indicates - * that the media should start to play as soon as the page is ready. - * - * @method Html5#setAutoplay - * @param {boolean} autoplay - * - True indicates that the media should start as soon as the page loads. - * - False indicates that the media should not start as soon as the page loads. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} - */ - 'autoplay', - - /** - * Set the value of `loop` on the media element. `loop` indicates - * that the media should return to the start of the media and continue playing once - * it reaches the end. - * - * @method Html5#setLoop - * @param {boolean} loop - * - True indicates that playback should seek back to start once - * the end of a media is reached. - * - False indicates that playback should not loop back to the start when the - * end of the media is reached. - * - * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} - */ - 'loop', - /** * Set the value of `playbackRate` on the media element. `playbackRate` indicates * the rate at which the media should play back. Examples: @@ -1592,6 +1602,8 @@ Html5.resetMediaElement = function(el) { }); // wrap native functions with a function +// The list is as follows: +// pause, load play [ /** * A wrapper around the media elements `pause` function. This will call the `HTML5` From 2c09ae9f3eccd2d23002b88cddef411c4231a038 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 11 Aug 2017 14:24:47 -0400 Subject: [PATCH 2/7] set initial attributes for both props and attrs in correct order --- src/js/tech/html5.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 067c69d5c8..f505ed7aae 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -233,17 +233,26 @@ class Html5 extends Tech { el.playerId = this.options_.playerId; } + + if (this.options_['preload'] !== 'undefined') { + Dom.setAttribute(el, 'preload', this.options_['preload']); + } + // Update specific tag settings, in case they were overridden - const settingsAttrs = ['autoplay', 'preload', 'loop', 'muted', 'playsinline']; + const settingsAttrs = ['loop', 'muted', 'playsinline', 'autoplay']; for (let i = settingsAttrs.length - 1; i >= 0; i--) { const attr = settingsAttrs[i]; - const overwriteAttrs = {}; + const value = this.options_[attr]; - if (typeof this.options_[attr] !== 'undefined') { - overwriteAttrs[attr] = this.options_[attr]; + if (typeof value !== 'undefined') { + if (value) { + Dom.setAttribute(el, attr, attr); + } else { + Dom.removeAttribute(el, attr); + } + el[attr] = value; } - Dom.setAttributes(el, overwriteAttrs); } return el; From 6035890bf1a93b7a0ef1609df0c07d4535c46b8f Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 11 Aug 2017 14:27:32 -0400 Subject: [PATCH 3/7] add a comment about settingsAttrs ordering --- src/js/tech/html5.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index f505ed7aae..e227751ecf 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -239,6 +239,8 @@ class Html5 extends Tech { } // Update specific tag settings, in case they were overridden + // `autoplay` has to be *last* so that `muted` and `playsinline` are present + // when iOS/Safari or other browsers attempt to autoplay. const settingsAttrs = ['loop', 'muted', 'playsinline', 'autoplay']; for (let i = settingsAttrs.length - 1; i >= 0; i--) { From ab10e4a2c3ab60dd16d2f73d850adf6650b44a59 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 11 Aug 2017 15:25:19 -0400 Subject: [PATCH 4/7] fix linting --- src/js/tech/html5.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index e227751ecf..bb7117e117 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -234,8 +234,8 @@ class Html5 extends Tech { } - if (this.options_['preload'] !== 'undefined') { - Dom.setAttribute(el, 'preload', this.options_['preload']); + if (this.options_.preload !== 'undefined') { + Dom.setAttribute(el, 'preload', this.options_.preload); } // Update specific tag settings, in case they were overridden @@ -1068,7 +1068,6 @@ Html5.resetMediaElement = function(el) { } }; - /* Native HTML5 element property wrapping ----------------------------------- */ // Wrap native boolean attributes with getters that check both property and attribute // The list is as followed: @@ -1244,7 +1243,6 @@ Html5.resetMediaElement = function(el) { 'playsinline' ].forEach(function(prop) { Html5.prototype['set' + toTitleCase(prop)] = function(v) { - console.log(prop, v); this.el_[prop] = v; if (v) { From 109c06332756ab864f5c5ceaaa82b7296b485448 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 11 Aug 2017 15:29:22 -0400 Subject: [PATCH 5/7] fix linting again --- src/js/tech/html5.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index bb7117e117..5543385076 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -233,7 +233,6 @@ class Html5 extends Tech { el.playerId = this.options_.playerId; } - if (this.options_.preload !== 'undefined') { Dom.setAttribute(el, 'preload', this.options_.preload); } From a53f362f2061cb887dc2be18d6bd40b74f20979b Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 11 Aug 2017 16:37:11 -0400 Subject: [PATCH 6/7] playsinline is a boolean attribute --- src/js/utils/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/utils/dom.js b/src/js/utils/dom.js index f48b1036ad..5a8610c4f6 100644 --- a/src/js/utils/dom.js +++ b/src/js/utils/dom.js @@ -375,7 +375,7 @@ export function getAttributes(tag) { // known boolean attributes // we can check for matching boolean properties, but older browsers // won't know about HTML5 boolean attributes that we still read from - const knownBooleans = ',' + 'autoplay,controls,loop,muted,default' + ','; + const knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default' + ','; if (tag && tag.attributes && tag.attributes.length > 0) { const attrs = tag.attributes; From 5d4f8821f4d9aeb2ddc638d89b3f9e7a34e5d5db Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Tue, 15 Aug 2017 11:35:51 -0400 Subject: [PATCH 7/7] add defaultMuted attribute as a known boolean --- src/js/utils/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/utils/dom.js b/src/js/utils/dom.js index 5a8610c4f6..b9a99a3c54 100644 --- a/src/js/utils/dom.js +++ b/src/js/utils/dom.js @@ -375,7 +375,7 @@ export function getAttributes(tag) { // known boolean attributes // we can check for matching boolean properties, but older browsers // won't know about HTML5 boolean attributes that we still read from - const knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default' + ','; + const knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ','; if (tag && tag.attributes && tag.attributes.length > 0) { const attrs = tag.attributes;