Merge pull request #1570 from egrs/media-play-pause-events

Dispatch play, pause, and emptied events from HTMLMediaElement
This commit is contained in:
Pierre Tachoire
2026-02-18 11:46:28 +01:00
committed by GitHub
2 changed files with 64 additions and 7 deletions

View File

@@ -50,6 +50,50 @@
}
</script>
<script id="play_pause_events">
{
const audio = document.createElement('audio');
const events = [];
audio.addEventListener('play', () => events.push('play'));
audio.addEventListener('playing', () => events.push('playing'));
audio.addEventListener('pause', () => events.push('pause'));
audio.addEventListener('emptied', () => events.push('emptied'));
// First play: paused -> playing, fires play + playing
audio.play();
testing.expectEqual('play,playing', events.join(','));
// Second play: already playing, no events
audio.play();
testing.expectEqual('play,playing', events.join(','));
// Pause: playing -> paused, fires pause
audio.pause();
testing.expectEqual('play,playing,pause', events.join(','));
// Second pause: already paused, no event
audio.pause();
testing.expectEqual('play,playing,pause', events.join(','));
// Third play: resume from pause, fires play + playing (verified in Chrome)
audio.play();
testing.expectEqual('play,playing,pause,play,playing', events.join(','));
// Pause again
audio.pause();
testing.expectEqual('play,playing,pause,play,playing,pause', events.join(','));
// Load: resets state, fires emptied
audio.load();
testing.expectEqual('play,playing,pause,play,playing,pause,emptied', events.join(','));
// Play after load: fires play + playing
audio.play();
testing.expectEqual('play,playing,pause,play,playing,pause,emptied,play,playing', events.join(','));
}
</script>
<script id="volume_muted">
{
const audio = document.getElementById('audio1');

View File

@@ -23,6 +23,7 @@ const Page = @import("../../../Page.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const HtmlElement = @import("../Html.zig");
const Event = @import("../../Event.zig");
pub const Audio = @import("Audio.zig");
pub const Video = @import("Video.zig");
const MediaError = @import("../../media/MediaError.zig");
@@ -136,25 +137,37 @@ fn isMaybeSupported(mime_type: []const u8) bool {
return false;
}
pub fn play(self: *Media) void {
pub fn play(self: *Media, page: *Page) !void {
const was_paused = self._paused;
self._paused = false;
self._ready_state = .HAVE_ENOUGH_DATA;
self._network_state = .NETWORK_IDLE;
// TODO: Could dispatch 'play' and 'playing' events
if (was_paused) {
try self.dispatchEvent("play", page);
try self.dispatchEvent("playing", page);
}
}
pub fn pause(self: *Media) void {
self._paused = true;
// TODO: Could dispatch 'pause' event
pub fn pause(self: *Media, page: *Page) !void {
if (!self._paused) {
self._paused = true;
try self.dispatchEvent("pause", page);
}
}
pub fn load(self: *Media) void {
pub fn load(self: *Media, page: *Page) !void {
self._paused = true;
self._current_time = 0;
self._ready_state = .HAVE_NOTHING;
self._network_state = .NETWORK_LOADING;
self._error = null;
// TODO: Could dispatch events
try self.dispatchEvent("emptied", page);
}
fn dispatchEvent(self: *Media, name: []const u8, page: *Page) !void {
const event = try Event.init(name, .{ .bubbles = false, .cancelable = false }, page);
defer if (!event._v8_handoff) event.deinit(false);
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
}
pub fn getPaused(self: *const Media) bool {