diff --git a/src/generators/nodes/Attribute.ts b/src/generators/nodes/Attribute.ts
index 01b62d23da..08075efee2 100644
--- a/src/generators/nodes/Attribute.ts
+++ b/src/generators/nodes/Attribute.ts
@@ -540,6 +540,7 @@ const attributeLookup = {
'textarea',
],
},
+ volume: { appliesTo: ['audio', 'video'] },
width: {
appliesTo: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
},
diff --git a/src/generators/nodes/Binding.ts b/src/generators/nodes/Binding.ts
index 3ab5f79769..f1725a6d73 100644
--- a/src/generators/nodes/Binding.ts
+++ b/src/generators/nodes/Binding.ts
@@ -73,9 +73,11 @@ export default class Binding extends Node {
);
}
- if (this.name === 'currentTime') {
+ if (this.name === 'currentTime' || this.name === 'volume') {
updateCondition = `!isNaN(${snippet})`;
- initialUpdate = null;
+
+ if (this.name === 'currentTime')
+ initialUpdate = null;
}
if (this.name === 'paused') {
@@ -267,4 +269,4 @@ function isComputed(node: Node) {
}
return false;
-}
\ No newline at end of file
+}
diff --git a/src/generators/nodes/Element.ts b/src/generators/nodes/Element.ts
index d2b8ba658b..48852c27ea 100644
--- a/src/generators/nodes/Element.ts
+++ b/src/generators/nodes/Element.ts
@@ -760,5 +760,11 @@ const events = [
filter: (node: Element, name: string) =>
node.isMediaNode() &&
(name === 'buffered' || name === 'seekable')
+ },
+ {
+ eventNames: ['volumechange'],
+ filter: (node: Element, name: string) =>
+ node.isMediaNode() &&
+ name === 'volume'
}
];
diff --git a/src/validate/html/validateElement.ts b/src/validate/html/validateElement.ts
index 1156ebcea7..550f8d2ae7 100644
--- a/src/validate/html/validateElement.ts
+++ b/src/validate/html/validateElement.ts
@@ -139,7 +139,8 @@ export default function validateElement(
name === 'paused' ||
name === 'buffered' ||
name === 'seekable' ||
- name === 'played'
+ name === 'played' ||
+ name === 'volume'
) {
if (node.name !== 'audio' && node.name !== 'video') {
validator.error(
diff --git a/test/js/samples/media-bindings/expected-bundle.js b/test/js/samples/media-bindings/expected-bundle.js
index fdf8a4f755..bbd56d8123 100644
--- a/test/js/samples/media-bindings/expected-bundle.js
+++ b/test/js/samples/media-bindings/expected-bundle.js
@@ -226,6 +226,12 @@ function create_main_fragment(state, component) {
component.set({ buffered: timeRangesToArray(audio.buffered), seekable: timeRangesToArray(audio.seekable) });
}
+ function audio_volumechange_handler() {
+ audio_updating = true;
+ component.set({ volume: audio.volume });
+ audio_updating = false;
+ }
+
return {
c: function create() {
audio = createElement("audio");
@@ -243,15 +249,19 @@ function create_main_fragment(state, component) {
if (!('buffered' in state)) component.root._beforecreate.push(audio_progress_handler);
addListener(audio, "loadedmetadata", audio_loadedmetadata_handler);
if (!('buffered' in state && 'seekable' in state)) component.root._beforecreate.push(audio_loadedmetadata_handler);
+ addListener(audio, "volumechange", audio_volumechange_handler);
},
m: function mount(target, anchor) {
insertNode(audio, target, anchor);
+
+ audio.volume = state.volume;
},
p: function update(changed, state) {
if (!audio_updating && !isNaN(state.currentTime )) audio.currentTime = state.currentTime ;
- if (!audio_updating && audio_is_paused !== (audio_is_paused = state.paused)) audio[audio_is_paused ? "pause" : "play"]();
+ if (!audio_updating && audio_is_paused !== (audio_is_paused = state.paused )) audio[audio_is_paused ? "pause" : "play"]();
+ if (!audio_updating && !isNaN(state.volume)) audio.volume = state.volume;
},
u: function unmount() {
@@ -265,6 +275,7 @@ function create_main_fragment(state, component) {
removeListener(audio, "pause", audio_play_pause_handler);
removeListener(audio, "progress", audio_progress_handler);
removeListener(audio, "loadedmetadata", audio_loadedmetadata_handler);
+ removeListener(audio, "volumechange", audio_volumechange_handler);
}
};
}
diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js
index c1dd10c238..ae80f288f6 100644
--- a/test/js/samples/media-bindings/expected.js
+++ b/test/js/samples/media-bindings/expected.js
@@ -30,6 +30,12 @@ function create_main_fragment(state, component) {
component.set({ buffered: timeRangesToArray(audio.buffered), seekable: timeRangesToArray(audio.seekable) });
}
+ function audio_volumechange_handler() {
+ audio_updating = true;
+ component.set({ volume: audio.volume });
+ audio_updating = false;
+ }
+
return {
c: function create() {
audio = createElement("audio");
@@ -47,15 +53,19 @@ function create_main_fragment(state, component) {
if (!('buffered' in state)) component.root._beforecreate.push(audio_progress_handler);
addListener(audio, "loadedmetadata", audio_loadedmetadata_handler);
if (!('buffered' in state && 'seekable' in state)) component.root._beforecreate.push(audio_loadedmetadata_handler);
+ addListener(audio, "volumechange", audio_volumechange_handler);
},
m: function mount(target, anchor) {
insertNode(audio, target, anchor);
+
+ audio.volume = state.volume;
},
p: function update(changed, state) {
if (!audio_updating && !isNaN(state.currentTime )) audio.currentTime = state.currentTime ;
- if (!audio_updating && audio_is_paused !== (audio_is_paused = state.paused)) audio[audio_is_paused ? "pause" : "play"]();
+ if (!audio_updating && audio_is_paused !== (audio_is_paused = state.paused )) audio[audio_is_paused ? "pause" : "play"]();
+ if (!audio_updating && !isNaN(state.volume)) audio.volume = state.volume;
},
u: function unmount() {
@@ -69,6 +79,7 @@ function create_main_fragment(state, component) {
removeListener(audio, "pause", audio_play_pause_handler);
removeListener(audio, "progress", audio_progress_handler);
removeListener(audio, "loadedmetadata", audio_loadedmetadata_handler);
+ removeListener(audio, "volumechange", audio_volumechange_handler);
}
};
}
diff --git a/test/js/samples/media-bindings/input.html b/test/js/samples/media-bindings/input.html
index 07a5cc1bc1..e7fe359341 100644
--- a/test/js/samples/media-bindings/input.html
+++ b/test/js/samples/media-bindings/input.html
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/test/runtime/samples/binding-audio-currenttime-duration/_config.js b/test/runtime/samples/binding-audio-currenttime-duration-volume/_config.js
similarity index 80%
rename from test/runtime/samples/binding-audio-currenttime-duration/_config.js
rename to test/runtime/samples/binding-audio-currenttime-duration-volume/_config.js
index 793ca5d280..abb0eeaacb 100644
--- a/test/runtime/samples/binding-audio-currenttime-duration/_config.js
+++ b/test/runtime/samples/binding-audio-currenttime-duration-volume/_config.js
@@ -7,20 +7,25 @@ export default {
test ( assert, component, target, window ) {
assert.equal( component.get( 't' ), 0 );
assert.equal( component.get( 'd' ), 0 );
+ assert.equal( component.get( 'v' ), 0.5 );
assert.equal( component.get( 'paused' ), true );
const audio = target.querySelector( 'audio' );
const timeupdate = new window.Event( 'timeupdate' );
const durationchange = new window.Event( 'durationchange' );
+ const volumechange = new window.Event( 'volumechange' );
audio.currentTime = 10;
audio.duration = 20;
+ audio.volume = 0.75;
audio.dispatchEvent( timeupdate );
audio.dispatchEvent( durationchange );
+ audio.dispatchEvent( volumechange );
audio.play();
assert.equal( component.get( 't' ), 10 );
assert.equal( component.get( 'd' ), 0 ); // not 20, because read-only. Not sure how to test this!
+ assert.equal( component.get( 'v' ), 0.75 );
assert.equal( component.get( 'paused' ), true ); // ditto...
component.destroy();
}
diff --git a/test/runtime/samples/binding-audio-currenttime-duration-volume/main.html b/test/runtime/samples/binding-audio-currenttime-duration-volume/main.html
new file mode 100644
index 0000000000..c65c0af8b7
--- /dev/null
+++ b/test/runtime/samples/binding-audio-currenttime-duration-volume/main.html
@@ -0,0 +1,2 @@
+
diff --git a/test/runtime/samples/binding-audio-currenttime-duration/main.html b/test/runtime/samples/binding-audio-currenttime-duration/main.html
deleted file mode 100644
index dc3aac8afe..0000000000
--- a/test/runtime/samples/binding-audio-currenttime-duration/main.html
+++ /dev/null
@@ -1 +0,0 @@
-