Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more bindings for media element properties #3650

Merged
merged 4 commits into from
Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/>