Skip to content

Commit

Permalink
Merge pull request #3650 from MattiasBuelens/more-media-bindings
Browse files Browse the repository at this point in the history
Add more bindings for media element properties
  • Loading branch information
Rich-Harris authored Nov 14, 2019
2 parents ca474fc + ed4f89d commit 004faf6
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 17 deletions.
4 changes: 3 additions & 1 deletion src/compiler/compile/nodes/Binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ const read_only_media_attributes = new Set([
'duration',
'buffered',
'seekable',
'played'
'played',
'seeking',
'ended'
]);

export default class Binding extends Node {
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/compile/nodes/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,9 @@ export default class Element extends Node {
name === 'seekable' ||
name === 'played' ||
name === 'volume' ||
name === 'playbackRate'
name === 'playbackRate' ||
name === 'seeking' ||
name === 'ended'
) {
if (this.name !== 'audio' && this.name !== 'video') {
component.error(binding, {
Expand Down
30 changes: 23 additions & 7 deletions src/compiler/compile/render_dom/wrappers/Element/Binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export default class BindingWrapper {
const { parent } = this;

const update_conditions: any[] = this.needs_lock ? [x`!${lock}`] : [];
const mount_conditions: any[] = [];

const dependency_array = [...this.node.expression.dependencies];

Expand All @@ -103,6 +104,7 @@ export default class BindingWrapper {

// model to view
let update_dom = get_dom_updater(parent, this);
let mount_dom = update_dom;

// special cases
switch (this.node.name) {
Expand All @@ -122,16 +124,23 @@ export default class BindingWrapper {

case 'textContent':
update_conditions.push(x`${this.snippet} !== ${parent.var}.textContent`);
mount_conditions.push(x`${this.snippet} !== void 0`);
break;

case 'innerHTML':
update_conditions.push(x`${this.snippet} !== ${parent.var}.innerHTML`);
mount_conditions.push(x`${this.snippet} !== void 0`);
break;

case 'currentTime':
update_conditions.push(x`!@_isNaN(${this.snippet})`);
mount_dom = null;
break;

case 'playbackRate':
case 'volume':
update_conditions.push(x`!@_isNaN(${this.snippet})`);
mount_conditions.push(x`!@_isNaN(${this.snippet})`);
break;

case 'paused':
Expand All @@ -142,12 +151,14 @@ export default class BindingWrapper {

update_conditions.push(x`${last} !== (${last} = ${this.snippet})`);
update_dom = b`${parent.var}[${last} ? "pause" : "play"]();`;
mount_dom = null;
break;
}

case 'value':
if (parent.node.get_static_attribute_value('type') === 'file') {
update_dom = null;
mount_dom = null;
}
}

Expand All @@ -165,13 +176,18 @@ export default class BindingWrapper {
}
}

if (this.node.name === 'innerHTML' || this.node.name === 'textContent') {
block.chunks.mount.push(b`
if (${this.snippet} !== void 0) {
${update_dom}
}`);
} else if (!/(currentTime|paused)/.test(this.node.name)) {
block.chunks.mount.push(update_dom);
if (mount_dom) {
if (mount_conditions.length > 0) {
const condition = mount_conditions.reduce((lhs, rhs) => x`${lhs} && ${rhs}`);

block.chunks.mount.push(b`
if (${condition}) {
${mount_dom}
}
`);
} else {
block.chunks.mount.push(mount_dom);
}
}
}
}
Expand Down
14 changes: 13 additions & 1 deletion src/compiler/compile/render_dom/wrappers/Element/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const events = [
event_names: ['timeupdate'],
filter: (node: Element, name: string) =>
node.is_media_node() &&
(name === 'currentTime' || name === 'played')
(name === 'currentTime' || name === 'played' || name === 'ended')
},
{
event_names: ['durationchange'],
Expand Down Expand Up @@ -100,6 +100,18 @@ const events = [
node.is_media_node() &&
name === 'playbackRate'
},
{
event_names: ['seeking', 'seeked'],
filter: (node: Element, name: string) =>
node.is_media_node() &&
(name === 'seeking')
},
{
event_names: ['ended'],
filter: (node: Element, name: string) =>
node.is_media_node() &&
name === 'ended'
},

// details event
{
Expand Down
45 changes: 39 additions & 6 deletions test/js/samples/media-bindings/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ function create_fragment(ctx) {
return {
c() {
audio = element("audio");
if (ctx.played === void 0 || ctx.currentTime === void 0) add_render_callback(audio_timeupdate_handler);
if (ctx.played === void 0 || ctx.currentTime === void 0 || ctx.ended === void 0) add_render_callback(audio_timeupdate_handler);
if (ctx.duration === void 0) add_render_callback(() => ctx.audio_durationchange_handler.call(audio));
if (ctx.buffered === void 0) add_render_callback(() => ctx.audio_progress_handler.call(audio));
if (ctx.buffered === void 0 || ctx.seekable === void 0) add_render_callback(() => ctx.audio_loadedmetadata_handler.call(audio));
if (ctx.seeking === void 0) add_render_callback(() => ctx.audio_seeking_seeked_handler.call(audio));
if (ctx.ended === void 0) add_render_callback(() => ctx.audio_ended_handler.call(audio));

dispose = [
listen(audio, "timeupdate", audio_timeupdate_handler),
Expand All @@ -48,13 +50,22 @@ function create_fragment(ctx) {
listen(audio, "progress", ctx.audio_progress_handler),
listen(audio, "loadedmetadata", ctx.audio_loadedmetadata_handler),
listen(audio, "volumechange", ctx.audio_volumechange_handler),
listen(audio, "ratechange", ctx.audio_ratechange_handler)
listen(audio, "ratechange", ctx.audio_ratechange_handler),
listen(audio, "seeking", ctx.audio_seeking_seeked_handler),
listen(audio, "seeked", ctx.audio_seeking_seeked_handler),
listen(audio, "ended", ctx.audio_ended_handler)
];
},
m(target, anchor) {
insert(target, audio, anchor);
audio.volume = ctx.volume;
audio.playbackRate = ctx.playbackRate;

if (!isNaN(ctx.volume)) {
audio.volume = ctx.volume;
}

if (!isNaN(ctx.playbackRate)) {
audio.playbackRate = ctx.playbackRate;
}
},
p(changed, ctx) {
if (!audio_updating && changed.currentTime && !isNaN(ctx.currentTime)) {
Expand Down Expand Up @@ -93,12 +104,16 @@ function instance($$self, $$props, $$invalidate) {
let { paused } = $$props;
let { volume } = $$props;
let { playbackRate } = $$props;
let { seeking } = $$props;
let { ended } = $$props;

function audio_timeupdate_handler() {
played = time_ranges_to_array(this.played);
currentTime = this.currentTime;
ended = this.ended;
$$invalidate("played", played);
$$invalidate("currentTime", currentTime);
$$invalidate("ended", ended);
}

function audio_durationchange_handler() {
Expand Down Expand Up @@ -133,6 +148,16 @@ function instance($$self, $$props, $$invalidate) {
$$invalidate("playbackRate", playbackRate);
}

function audio_seeking_seeked_handler() {
seeking = this.seeking;
$$invalidate("seeking", seeking);
}

function audio_ended_handler() {
ended = this.ended;
$$invalidate("ended", ended);
}

$$self.$set = $$props => {
if ("buffered" in $$props) $$invalidate("buffered", buffered = $$props.buffered);
if ("seekable" in $$props) $$invalidate("seekable", seekable = $$props.seekable);
Expand All @@ -142,6 +167,8 @@ function instance($$self, $$props, $$invalidate) {
if ("paused" in $$props) $$invalidate("paused", paused = $$props.paused);
if ("volume" in $$props) $$invalidate("volume", volume = $$props.volume);
if ("playbackRate" in $$props) $$invalidate("playbackRate", playbackRate = $$props.playbackRate);
if ("seeking" in $$props) $$invalidate("seeking", seeking = $$props.seeking);
if ("ended" in $$props) $$invalidate("ended", ended = $$props.ended);
};

return {
Expand All @@ -153,13 +180,17 @@ function instance($$self, $$props, $$invalidate) {
paused,
volume,
playbackRate,
seeking,
ended,
audio_timeupdate_handler,
audio_durationchange_handler,
audio_play_pause_handler,
audio_progress_handler,
audio_loadedmetadata_handler,
audio_volumechange_handler,
audio_ratechange_handler
audio_ratechange_handler,
audio_seeking_seeked_handler,
audio_ended_handler
};
}

Expand All @@ -175,7 +206,9 @@ class Component extends SvelteComponent {
duration: 0,
paused: 0,
volume: 0,
playbackRate: 0
playbackRate: 0,
seeking: 0,
ended: 0
});
}
}
Expand Down
4 changes: 3 additions & 1 deletion test/js/samples/media-bindings/input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
export let paused;
export let volume;
export let playbackRate;
export let seeking;
export let ended;
</script>

<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:playbackRate/>
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:playbackRate bind:seeking bind:ended/>

0 comments on commit 004faf6

Please sign in to comment.