@@ -444,8 +444,6 @@ pub fn eventPreventDefault(evt: *Event) !void {
444444}
445445
446446// EventHandler
447- pub const EventHandler = fn (? * Event , ? * anyopaque ) callconv (.C ) void ;
448-
449447fn event_handler_cbk (data : * anyopaque ) * Callback {
450448 const ptr : * align (@alignOf (* Callback )) anyopaque = @alignCast (data );
451449 return @as (* Callback , @ptrCast (ptr ));
@@ -458,16 +456,16 @@ const event_handler = struct {
458456 func .call (.{event }) catch unreachable ;
459457 // NOTE: we can not call func.deinit here
460458 // b/c the handler can be called several times
461- // as the event goes through the ancestors
462- // TODO: check the event phase to call func.deinit and free func
459+ // either on this dispatch event or in anoter one
463460 }
464461 }
465462}.handle ;
466463
467464// EventListener
468465pub const EventListener = c .dom_event_listener ;
466+ const EventListenerEntry = c .listener_entry ;
469467
470- pub fn eventListenerGetData (lst : * EventListener ) ? * anyopaque {
468+ fn eventListenerGetData (lst : * EventListener ) ? * anyopaque {
471469 return c .dom_event_listener_get_data (lst );
472470}
473471
@@ -486,7 +484,6 @@ pub fn eventTargetHasListener(
486484) ! ? * EventListener {
487485 const str = try strFromData (typ );
488486
489- const EventListenerEntry = c .listener_entry ;
490487 var current : ? * EventListenerEntry = null ;
491488 var next : ? * EventListenerEntry = undefined ;
492489 var lst : ? * EventListener = undefined ;
@@ -504,14 +501,16 @@ pub fn eventTargetHasListener(
504501 try DOMErr (err );
505502
506503 if (lst ) | listener | {
507- // the EventTarget has a listener for this event type,
508- // let's check if the callback is the same
504+ // the EventTarget has a listener for this event type
505+ // and capture property,
506+ // let's check if the callback handler is the same
509507 defer c .dom_event_listener_unref (listener );
510508 const data = eventListenerGetData (listener );
511509 if (data ) | d | {
512510 const cbk = event_handler_cbk (d );
513- if (cbk_id == cbk .id ())
511+ if (cbk_id == cbk .id ()) {
514512 return lst ;
513+ }
515514 }
516515 }
517516
@@ -529,34 +528,91 @@ pub fn eventTargetHasListener(
529528
530529pub fn eventTargetAddEventListener (
531530 et : * EventTarget ,
531+ alloc : std.mem.Allocator ,
532532 typ : []const u8 ,
533- cbk_ptr : * Callback ,
533+ cbk : Callback ,
534534 capture : bool ,
535535) ! void {
536- const s = try strFromData (typ );
536+ // this allocation will be removed either on
537+ // eventTargetRemoveEventListener or eventTargetRemoveAllEventListeners
538+ const cbk_ptr = try alloc .create (Callback );
539+ cbk_ptr .* = cbk ;
540+
537541 const ctx = @as (* anyopaque , @ptrCast (cbk_ptr ));
538542 var listener : ? * EventListener = undefined ;
539543 const errLst = c .dom_event_listener_create (event_handler , ctx , & listener );
540544 try DOMErr (errLst );
545+ defer c .dom_event_listener_unref (listener );
546+
547+ const s = try strFromData (typ );
541548 const err = eventTargetVtable (et ).add_event_listener .? (et , s , listener , capture );
542549 try DOMErr (err );
543550}
544551
545552pub fn eventTargetRemoveEventListener (
546553 et : * EventTarget ,
554+ alloc : std.mem.Allocator ,
547555 typ : []const u8 ,
548556 lst : * EventListener ,
549557 capture : bool ,
550- ) ! ? * Callback {
558+ ) ! void {
551559 const data = eventListenerGetData (lst );
552- var cbk_ptr : ? * Callback = null ;
560+ // free cbk allocation made on eventTargetAddEventListener
553561 if (data ) | d | {
554- cbk_ptr = event_handler_cbk (d );
562+ const cbk_ptr = event_handler_cbk (d );
563+ cbk_ptr .deinit (alloc );
564+ alloc .destroy (cbk_ptr );
555565 }
566+
556567 const s = try strFromData (typ );
557568 const err = eventTargetVtable (et ).remove_event_listener .? (et , s , lst , capture );
558569 try DOMErr (err );
559- return cbk_ptr ;
570+ }
571+
572+ pub fn eventTargetRemoveAllEventListeners (
573+ et : * EventTarget ,
574+ alloc : std.mem.Allocator ,
575+ ) ! void {
576+ var next : ? * EventListenerEntry = undefined ;
577+ var lst : ? * EventListener = undefined ;
578+
579+ // iterate over the EventTarget's listeners
580+ while (true ) {
581+ const errIter = eventTargetVtable (et ).iter_event_listener .? (
582+ et ,
583+ null ,
584+ false ,
585+ null ,
586+ & next ,
587+ & lst ,
588+ );
589+ try DOMErr (errIter );
590+
591+ if (lst ) | listener | {
592+ defer c .dom_event_listener_unref (listener );
593+ const data = eventListenerGetData (listener );
594+ if (data ) | d | {
595+ // free cbk allocation made on eventTargetAddEventListener
596+ const cbk = event_handler_cbk (d );
597+ cbk .deinit (alloc );
598+ alloc .destroy (cbk );
599+ }
600+ const err = eventTargetVtable (et ).remove_event_listener .? (
601+ et ,
602+ null ,
603+ lst ,
604+ false ,
605+ );
606+ try DOMErr (err );
607+ }
608+
609+ if (next == null ) {
610+ // no more listeners, end of the iteration
611+ break ;
612+ }
613+
614+ // next iteration
615+ }
560616}
561617
562618pub fn eventTargetDispatchEvent (et : * EventTarget , event : * Event ) ! bool {
0 commit comments