The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

HTML::Object::EventTarget - HTML Object Event Target Class

SYNOPSIS

    use HTML::Object::EventTarget;
    my $eh = HTML::Object::EventTarget->new(
        
    ) || die( HTML::Object::EventTarget->error, "\n" );

    $e->addEventListener( change => sub
    {
        my $event = shift( @_ ); # also available as $_
        # do something with that event (HTML::Object::Event)
    }, {capture => 0});

    $e->dispatchEvent( $event );

    my $event_handlers = $e->getEventListeners( 'click' );
    say "Found ", $Event_handlers->length, " event handlers";

    $e->handleEvent( $event );

    $e->on( click => sub
    {
        my $event = shift( @_ );
        # do something
    });
    # or
    sub onclick : lvalue { return( shift->on( 'click', @_ ) ); }
    $e->onclick = sub
    {
        my $event = shift( @_ );
        # do something
    };

    $e->removeEventListener( $event_listener_object );

VERSION

    v0.2.2

DESCRIPTION

This modules represents an event target and handler. This is implemented by HTML::Object::Document and HTML::Object::Element and its descendants.

Of course, being perl, there is only limited support for events.

CONSTRUCTOR

new

Creates a new HTML::Object::EventTarget object instance and returns it.

METHODS

addEventListener

Provided with a type, a callback and an optional hash or hash reference of options and this will register an event handler (i.e. a callback subroutine) of a specific event type on the EventTarget.

When an event is "fired", the callback is called, and the event object is passed as it sole argument. Also, $_ is set to the current element object on which the event got triggered.

It returns the newly created HTML::Object::EventListener upon success or "undef" in perlfunc upon error and sets an error

Possible options are:

capture

A boolean value indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.

Setting the capture flag controls whether an event listener is called in the Capture phase or Bubble phase.

For example:

    <div id="div1">
        <div id="div2"></div>
    </div>

    $div1->addEventListener('click', \&doSomething1, {capture => 1 });
    $div2->addEventListener('click', \&doSomething2, {capture => 0 });

Triggering a click event on div2 yields the following[1]:

    $div2->trigger('click');
1. The click event starts in the capturing phase. The event looks if any ancestor element of element2 has a onclick event handler for the capturing phase.
2. The event finds one on div1. doSomething1() is executed.
3. The event travels down to the target itself, no more event handlers for the capturing phase are found. The event moves to its bubbling phase and executes doSomething2(), which is registered to div2 for the bubbling phase.
4. The event travels upwards again and checks if any ancestor element of the target has an event handler for the bubbling phase. This is not the case, so nothing happens.

The reverse would be:

    $div1->addEventListener('click', \&doSomething1, {capture => 0 });
    $div2->addEventListener('click', \&doSomething2, {capture => 0 });
1. The click event starts in the capturing phase. The event looks if any ancestor element of div2 has a onclick event handler for the capturing phase and doesn’t find any.
2. The event travels down to the target itself. The event moves to its bubbling phase and executes doSomething2(), which is registered to div2 for the bubbling phase.
3. The event travels upwards again and checks if any ancestor element of the target has an event handler for the bubbling phase.
4. The event finds one on div1. Now doSomething1() is executed.

Setting an event listener like this:

    $div1->onclick = \&doSomething1;

would register it in the bubbling phase, i.e. equivalent to:

    $div1->addEventListener( click => \&doSomething1, { capture => 0 } );

[1] Koch, Peter-Paul "Event order" (Quirkcsmode) https://www.quirksmode.org/js/events_order.html

See for more information and this

once

A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.

passive

This, under perl, does nothing and thus always defaults to false.

Under JavaScript, this would be a boolean value that, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning. See Improving scrolling performance with passive listeners to learn more.

post_processing

This is a non-standard addition and is a code reference (i.e. a subroutine reference or an anonymous subroutine) passed that will be called once the event handler has been set. It is passed the newly created event listener object.

This is used by HTML::Object::DOM::List for example, to enable event listening on array or scalar only when an event listener is registered. So, upon adding an event listener, this post-processing callback is called and this callback takes the appropriate step to start listening to a specific array or scalar.

signal

A signal, such as ALRM, INT, or TERM. The listener will be removed when the given signal is called.

Example:

    <table id="outside">
        <tr><td id="t1">one</td></tr>
        <tr><td id="t2">two</td></tr>
    </table>

    # Subroutine to change the content of $t2
    sub modifyText
    {
        my $t2 = $doc->getElementById("t2");
        if( $t2->firstChild->nodeValue eq "three" )
        {
            $t2->firstChild->nodeValue = "two";
        }
        else
        {
            $t2->firstChild->nodeValue = "three";
        }
    }

    # Add event listener to table
    my $el = $doc->getElementById("outside");
    $el->addEventListener("click", \&modifyText, { capture => 0 } );

Then, do:

    $el->trigger( 'click' );

You can also pass subroutine name that is in your package, or a fully qualified subroutine name. For example:

Assuming you are calling from the package My::Module, the following will search for a subroutine My::Module::my_callback

    $el->addEventListener("click", 'my_callback', { capture => 0 } );

Or

    $el->addEventListener("click", 'My:Module::my_callback', { capture => 0 } );

If it does not exists, it will return undef and set an error.

See for more information

dispatchEvent

Provided with an event, and this dispatches the event to this EventTarget.

It will first call "composedPath" to get the branch from this current element to the top one, and will start from the top in the capture phase, checking every element from top up to the current one and calls "handleEvent", which, in turn, will check if there are any listeners registered in this capture phase, and if there are calls each listener's "handleEvent" in HTML::Object::EventListener.

Then once the capture phase is done, it executes the event listeners on the current element, if any.

Then finally, if the event "bubbles" in HTML::Object::Event property is true, it calls "handleEvent" on each of the element starting from the current element's parent to the top one. "handleEvent", in turn, will check if there are any event listeners registereed for the element in question for the bubbling phase and call their event handler.

If the event property "cancelable" in HTML::Object::Event is set to true and a handler cancelled it at any point, then this whole process is interrupted.

The event current element is set each time, so you can check that to find out which one has cancelled it.

See for more information

See also

event_listeners

Sets or gets an hash reference of all the event listeners registered.

getEventListeners

Provided with an event type, such as click, and this returns all the event listener objects registere for that event type in their order of registration. It returns an array object

    my $listeners = $e->getEventListeners( 'click' );
    say "Found ", $listeners->length, " event listeners.";

handleEvent

Provided with an event and this will process it via all the registered event listeners in the order they were registered.

It returns the current element object upon success, and upon error, it returns undef and sets an error

hasEventListener

Provided with an optional event type and this returns the number of event listeners registered for the given type, if provided, or the total number of event listeners registered for all types.

on

This is a convenient method to set event listeners. It is to be called by a class, such as:

    sub onclick : lvalue { return( shift->on( 'click' @_ ) ); }

Then, you can set a click event listener for this element:

    $e->onclick = sub
    {
        my $event = shift( @_ ); # Also available with $_
        # Do some work
    };
    # or
    $e->onclick(sub
    {
        my $event = shift( @_ ); # Also available with $_
        # Do some work
    });

removeEventListener

Provided with a event type, a callback code reference or a subroutine name (possibly including its package like MyPackage::my_sub), or an event listener object, and an hash or hash reference of options and this removes an event listener from the EventTarget.

It returns the HTML::Object::EventListener thus removed upon success or "undef" in perlfunc upon error and sets an error

Possible options, to identify the event handler to remove, are:

capture

A boolean value indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.

For example:

    my $eh = $e->addEventListener( click => sub{ # do something }, { capture => 1, once => 1 });
    $eh->remove;
    # or
    $e->removeEventListener( click => $same_code_ref, { capture => 1 });

However, if the options provided differ from the ones initially set, it will not uniquely find the event handler. Only the capture option is used to uniquely find the handler. For example:

This will fail to remove the handler, because the capture parameter does not have the same value.

    $e->removeEventListener( click => $same_code, { capture => 0 });

This will fail to remove the handler, because the callback value is not the same as the original.

    $e->removeEventListener( click => $some_other_code_ref, { capture => 1 });

See for more information

AUTHOR

Jacques Deguest <jack@deguest.jp>

SEE ALSO

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget

https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers

https://developer.mozilla.org/en-US/docs/Web/API/Event

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events

https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers

https://domevents.dev/ a very useful interactive playground app that enables learning about the behavior of the DOM Event system through exploration.

https://www.quirksmode.org/js/events_order.html discussion of capturing and bubbling — an excellently detailed piece by Peter-Paul Koch.

https://www.quirksmode.org/js/events_access.html discussion of the event object — another excellently detailed piece by Peter-Paul Koch.

COPYRIGHT & LICENSE

Copyright(c) 2021 DEGUEST Pte. Ltd.

All rights reserved This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.