feat: add readyState binding for media elements (#6843)

Closes #6666

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
pull/8342/head
Brad Dougherty 2 years ago committed by GitHub
parent c611f318d2
commit dd371f58fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -845,6 +845,7 @@ export interface HTMLMediaAttributes<T extends HTMLMediaElement> extends HTMLAtt
*/
volume?: number | undefined | null;
readonly 'bind:readyState'?: 0 | 1 | 2 | 3 | 4 | undefined | null;
readonly 'bind:duration'?: number | undefined | null;
readonly 'bind:buffered'?: SvelteMediaTimeRange[] | undefined | null;
readonly 'bind:played'?: SvelteMediaTimeRange[] | undefined | null;

@ -714,7 +714,7 @@ Elements with the `contenteditable` attribute support `innerHTML` and `textConte
---
Media elements (`<audio>` and `<video>`) have their own set of bindings — six *readonly* ones...
Media elements (`<audio>` and `<video>`) have their own set of bindings — seven *readonly* ones...
* `duration` (readonly) — the total duration of the video, in seconds
* `buffered` (readonly) — an array of `{start, end}` objects
@ -722,6 +722,7 @@ Media elements (`<audio>` and `<video>`) have their own set of bindings — six
* `seekable` (readonly) — ditto
* `seeking` (readonly) — boolean
* `ended` (readonly) — boolean
* `readyState` (readonly) — number between (and including) 0 and 4
...and five *two-way* bindings:
@ -742,6 +743,7 @@ Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
bind:seekable
bind:seeking
bind:ended
bind:readyState
bind:currentTime
bind:playbackRate
bind:paused

@ -24,7 +24,8 @@ const read_only_media_attributes = new Set([
'videoHeight',
'videoWidth',
'naturalWidth',
'naturalHeight'
'naturalHeight',
'readyState'
]);
export default class Binding extends Node {

@ -980,7 +980,8 @@ export default class Element extends Node {
name === 'muted' ||
name === 'playbackRate' ||
name === 'seeking' ||
name === 'ended'
name === 'ended' ||
name === 'readyState'
) {
if (this.name !== 'audio' && this.name !== 'video') {
return component.error(binding, compiler_errors.invalid_binding_element_with('audio> or <video>', name));

@ -63,13 +63,11 @@ const events = [
filter: (node: Element, _name: string) =>
node.name === 'input' && node.get_static_attribute_value('type') === 'range'
},
{
event_names: ['elementresize'],
filter: (_node: Element, name: string) =>
regex_dimensions.test(name)
},
// media events
{
event_names: ['timeupdate'],
@ -131,7 +129,14 @@ const events = [
node.is_media_node() &&
(name === 'videoHeight' || name === 'videoWidth')
},
{
// from https://html.spec.whatwg.org/multipage/media.html#ready-states
// and https://html.spec.whatwg.org/multipage/media.html#loading-the-media-resource
event_names: ['loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'emptied'],
filter: (node: Element, name: string) =>
node.is_media_node() &&
name === 'readyState'
},
// details event
{
event_names: ['toggle'],

@ -30,18 +30,19 @@ function create_fragment(ctx) {
audio_updating = true;
}
/*audio_timeupdate_handler*/ ctx[13].call(audio);
/*audio_timeupdate_handler*/ ctx[14].call(audio);
}
return {
c() {
audio = element("audio");
if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[11].call(audio));
if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[12].call(audio));
if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[12].call(audio));
if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[13].call(audio));
if (/*played*/ ctx[2] === void 0 || /*currentTime*/ ctx[3] === void 0 || /*ended*/ ctx[10] === void 0) add_render_callback(audio_timeupdate_handler);
if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[14].call(audio));
if (/*seeking*/ ctx[9] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[18].call(audio));
if (/*ended*/ ctx[10] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[19].call(audio));
if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[15].call(audio));
if (/*seeking*/ ctx[9] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[19].call(audio));
if (/*ended*/ ctx[10] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[20].call(audio));
if (/*readyState*/ ctx[11] === void 0) add_render_callback(() => /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21].call(audio));
},
m(target, anchor) {
insert(target, audio, anchor);
@ -58,17 +59,24 @@ function create_fragment(ctx) {
if (!mounted) {
dispose = [
listen(audio, "progress", /*audio_progress_handler*/ ctx[11]),
listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[12]),
listen(audio, "progress", /*audio_progress_handler*/ ctx[12]),
listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[13]),
listen(audio, "timeupdate", audio_timeupdate_handler),
listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[14]),
listen(audio, "play", /*audio_play_pause_handler*/ ctx[15]),
listen(audio, "pause", /*audio_play_pause_handler*/ ctx[15]),
listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[16]),
listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[17]),
listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[18]),
listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[18]),
listen(audio, "ended", /*audio_ended_handler*/ ctx[19])
listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[15]),
listen(audio, "play", /*audio_play_pause_handler*/ ctx[16]),
listen(audio, "pause", /*audio_play_pause_handler*/ ctx[16]),
listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[17]),
listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[18]),
listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[19]),
listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[19]),
listen(audio, "ended", /*audio_ended_handler*/ ctx[20]),
listen(audio, "loadedmetadata", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "loadeddata", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "canplay", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "canplaythrough", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "playing", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "waiting", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "emptied", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21])
];
mounted = true;
@ -119,6 +127,7 @@ function instance($$self, $$props, $$invalidate) {
let { playbackRate } = $$props;
let { seeking } = $$props;
let { ended } = $$props;
let { readyState } = $$props;
function audio_progress_handler() {
buffered = time_ranges_to_array(this.buffered);
@ -173,6 +182,11 @@ function instance($$self, $$props, $$invalidate) {
$$invalidate(10, ended);
}
function audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler() {
readyState = this.readyState;
$$invalidate(11, readyState);
}
$$self.$$set = $$props => {
if ('buffered' in $$props) $$invalidate(0, buffered = $$props.buffered);
if ('seekable' in $$props) $$invalidate(1, seekable = $$props.seekable);
@ -185,6 +199,7 @@ function instance($$self, $$props, $$invalidate) {
if ('playbackRate' in $$props) $$invalidate(8, playbackRate = $$props.playbackRate);
if ('seeking' in $$props) $$invalidate(9, seeking = $$props.seeking);
if ('ended' in $$props) $$invalidate(10, ended = $$props.ended);
if ('readyState' in $$props) $$invalidate(11, readyState = $$props.readyState);
};
return [
@ -199,6 +214,7 @@ function instance($$self, $$props, $$invalidate) {
playbackRate,
seeking,
ended,
readyState,
audio_progress_handler,
audio_loadedmetadata_handler,
audio_timeupdate_handler,
@ -207,7 +223,8 @@ function instance($$self, $$props, $$invalidate) {
audio_volumechange_handler,
audio_ratechange_handler,
audio_seeking_seeked_handler,
audio_ended_handler
audio_ended_handler,
audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler
];
}
@ -226,9 +243,10 @@ class Component extends SvelteComponent {
muted: 7,
playbackRate: 8,
seeking: 9,
ended: 10
ended: 10,
readyState: 11
});
}
}
export default Component;
export default Component;

@ -10,6 +10,7 @@
export let playbackRate;
export let seeking;
export let ended;
export let readyState;
</script>
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:muted bind:playbackRate bind:seeking bind:ended/>
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:muted bind:playbackRate bind:seeking bind:ended bind:readyState/>

@ -30,23 +30,31 @@ function create_fragment(ctx) {
video_updating = true;
}
/*video_timeupdate_handler*/ ctx[4].call(video);
/*video_timeupdate_handler*/ ctx[5].call(video);
}
return {
c() {
video = element("video");
if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[5].call(video));
add_render_callback(() => /*video_elementresize_handler*/ ctx[6].call(video));
if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[6].call(video));
add_render_callback(() => /*video_elementresize_handler*/ ctx[7].call(video));
if (/*readyState*/ ctx[4] === void 0) add_render_callback(() => /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8].call(video));
},
m(target, anchor) {
insert(target, video, anchor);
video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video));
video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[7].bind(video));
if (!mounted) {
dispose = [
listen(video, "timeupdate", video_timeupdate_handler),
listen(video, "resize", /*video_resize_handler*/ ctx[5])
listen(video, "resize", /*video_resize_handler*/ ctx[6]),
listen(video, "loadedmetadata", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "loadeddata", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "canplay", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "canplaythrough", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "playing", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "waiting", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "emptied", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8])
];
mounted = true;
@ -75,6 +83,7 @@ function instance($$self, $$props, $$invalidate) {
let { videoHeight } = $$props;
let { videoWidth } = $$props;
let { offsetWidth } = $$props;
let { readyState } = $$props;
function video_timeupdate_handler() {
currentTime = this.currentTime;
@ -93,11 +102,17 @@ function instance($$self, $$props, $$invalidate) {
$$invalidate(3, offsetWidth);
}
function video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler() {
readyState = this.readyState;
$$invalidate(4, readyState);
}
$$self.$$set = $$props => {
if ('currentTime' in $$props) $$invalidate(0, currentTime = $$props.currentTime);
if ('videoHeight' in $$props) $$invalidate(1, videoHeight = $$props.videoHeight);
if ('videoWidth' in $$props) $$invalidate(2, videoWidth = $$props.videoWidth);
if ('offsetWidth' in $$props) $$invalidate(3, offsetWidth = $$props.offsetWidth);
if ('readyState' in $$props) $$invalidate(4, readyState = $$props.readyState);
};
return [
@ -105,9 +120,11 @@ function instance($$self, $$props, $$invalidate) {
videoHeight,
videoWidth,
offsetWidth,
readyState,
video_timeupdate_handler,
video_resize_handler,
video_elementresize_handler
video_elementresize_handler,
video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler
];
}
@ -119,9 +136,10 @@ class Component extends SvelteComponent {
currentTime: 0,
videoHeight: 1,
videoWidth: 2,
offsetWidth: 3
offsetWidth: 3,
readyState: 4
});
}
}
export default Component;
export default Component;

@ -3,6 +3,7 @@
export let videoHeight;
export let videoWidth;
export let offsetWidth;
export let readyState;
</script>
<video bind:currentTime bind:videoHeight bind:videoWidth bind:offsetWidth/>
<video bind:currentTime bind:videoHeight bind:videoWidth bind:offsetWidth bind:readyState/>

Loading…
Cancel
Save