ladybird/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp
Luke Wilde 5aacec65ab LibWeb: Rewrite EventTarget to more closely match the spec
This isn't perfect (especially the global object situation in
activate_event_handler), but I believe it's in a much more complete
state now :^)

This fixes the issue of crashing in prepare_for_ordinary_call with the
`i < m_size` crash, as it now uses the IDL callback functions which
requires the Environment Settings Object. The environment settings
object for the callback is fetched at the time the callback is created,
for example, WrapperGenerator gets the incumbent settings object for
the callback at the time of wrapping. This allows us to remove passing
in ScriptExecutionContext into EventTarget's constructor.

With this, we can now drop ScriptExecutionContext.
2022-02-08 17:47:44 +00:00

96 lines
2.9 KiB
C++

/*
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/MediaQueryListWrapper.h>
#include <LibWeb/CSS/MediaQueryList.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/EventDispatcher.h>
#include <LibWeb/DOM/EventListener.h>
#include <LibWeb/HTML/EventHandler.h>
namespace Web::CSS {
MediaQueryList::MediaQueryList(DOM::Document& document, NonnullRefPtrVector<MediaQuery>&& media)
: DOM::EventTarget()
, m_document(document)
, m_media(move(media))
{
evaluate();
}
MediaQueryList::~MediaQueryList()
{
}
// https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-media
String MediaQueryList::media() const
{
return serialize_a_media_query_list(m_media);
}
// https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-matches
bool MediaQueryList::matches() const
{
for (auto& media : m_media) {
if (media.matches())
return true;
}
return false;
}
bool MediaQueryList::evaluate()
{
if (!m_document)
return false;
bool now_matches = false;
for (auto& media : m_media) {
now_matches = now_matches || media.evaluate(m_document->window());
}
return now_matches;
}
JS::Object* MediaQueryList::create_wrapper(JS::GlobalObject& global_object)
{
return wrap(global_object, *this);
}
// https://www.w3.org/TR/cssom-view/#dom-mediaquerylist-addlistener
void MediaQueryList::add_listener(RefPtr<DOM::EventListener> listener)
{
// 1. If listener is null, terminate these steps.
if (!listener)
return;
// 2. Append an event listener to the associated list of event listeners with type set to change,
// callback set to listener, and capture set to false, unless there already is an event listener
// in that list with the same type, callback, and capture.
// (NOTE: capture is set to false by default)
add_event_listener(HTML::EventNames::change, listener);
}
// https://www.w3.org/TR/cssom-view/#dom-mediaquerylist-removelistener
void MediaQueryList::remove_listener(RefPtr<DOM::EventListener> listener)
{
// 1. Remove an event listener from the associated list of event listeners, whose type is change, callback is listener, and capture is false.
// NOTE: While the spec doesn't technically use remove_event_listener and instead manipulates the list directly, every major engine uses remove_event_listener.
// This means if an event listener removes another event listener that comes after it, the removed event listener will not be invoked.
remove_event_listener(HTML::EventNames::change, listener);
}
void MediaQueryList::set_onchange(Optional<Bindings::CallbackType> event_handler)
{
set_event_handler_attribute(HTML::EventNames::change, event_handler);
}
Bindings::CallbackType* MediaQueryList::onchange()
{
return event_handler_attribute(HTML::EventNames::change);
}
}