mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
LibWeb: Implement a simple version of Element.scrollIntoView()
We parse the arguments that come in, but since we don't yet track scrollable overflow, we can't do the full "scroll an element into view" algorithm. For now, we just call out to the PageClient and ask it to bring the nearest principal box into the visible viewport.
This commit is contained in:
parent
3ca44e2258
commit
162e4179fc
Notes:
sideshowbarker
2024-07-17 06:21:59 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/162e4179fc
3 changed files with 103 additions and 0 deletions
|
@ -7,6 +7,7 @@
|
|||
#include <AK/AnyOf.h>
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibWeb/Bindings/ElementPrototype.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/CSS/ResolvedCSSStyleDeclaration.h>
|
||||
|
@ -44,6 +45,7 @@
|
|||
#include <LibWeb/Layout/TableRowGroupBox.h>
|
||||
#include <LibWeb/Layout/TreeBuilder.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
#include <LibWeb/WebIDL/DOMException.h>
|
||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
|
@ -903,4 +905,76 @@ WebIDL::ExceptionOr<void> Element::insert_adjacent_text(String const& where, Str
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view-1/#scroll-an-element-into-view
|
||||
static void scroll_an_element_into_view(DOM::Element& element, Bindings::ScrollBehavior behavior, Bindings::ScrollLogicalPosition block, Bindings::ScrollLogicalPosition inline_)
|
||||
{
|
||||
// FIXME: The below is ad-hoc, since we don't yet have scrollable elements.
|
||||
// Return here and implement this according to spec once all overflow is made scrollable.
|
||||
|
||||
(void)behavior;
|
||||
(void)block;
|
||||
(void)inline_;
|
||||
|
||||
if (!element.document().browsing_context())
|
||||
return;
|
||||
|
||||
auto* page = element.document().browsing_context()->page();
|
||||
if (!page)
|
||||
return;
|
||||
|
||||
// If this element doesn't have a layout node, we can't scroll it into view.
|
||||
element.document().update_layout();
|
||||
if (!element.layout_node())
|
||||
return;
|
||||
|
||||
// Find the nearest layout node that is a box (since we need a box to get a usable rect)
|
||||
auto* layout_node = element.layout_node();
|
||||
while (layout_node && !layout_node->is_box())
|
||||
layout_node = layout_node->parent();
|
||||
|
||||
if (!layout_node)
|
||||
return;
|
||||
|
||||
page->client().page_did_request_scroll_into_view(verify_cast<Layout::Box>(*layout_node).paint_box()->absolute_padding_box_rect().to_rounded<int>());
|
||||
}
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view-1/#dom-element-scrollintoview
|
||||
void Element::scroll_into_view(Optional<Variant<bool, ScrollIntoViewOptions>> arg)
|
||||
{
|
||||
// 1. Let behavior be "auto".
|
||||
auto behavior = Bindings::ScrollBehavior::Auto;
|
||||
|
||||
// 2. Let block be "start".
|
||||
auto block = Bindings::ScrollLogicalPosition::Start;
|
||||
|
||||
// 3. Let inline be "nearest".
|
||||
auto inline_ = Bindings::ScrollLogicalPosition::Nearest;
|
||||
|
||||
// 4. If arg is a ScrollIntoViewOptions dictionary, then:
|
||||
if (arg.has_value() && arg->has<ScrollIntoViewOptions>()) {
|
||||
// 1. Set behavior to the behavior dictionary member of options.
|
||||
behavior = arg->get<ScrollIntoViewOptions>().behavior;
|
||||
|
||||
// 2. Set block to the block dictionary member of options.
|
||||
block = arg->get<ScrollIntoViewOptions>().block;
|
||||
|
||||
// 3. Set inline to the inline dictionary member of options.
|
||||
inline_ = arg->get<ScrollIntoViewOptions>().inline_;
|
||||
}
|
||||
// 5. Otherwise, if arg is false, then set block to "end".
|
||||
else if (arg.has_value() && arg->has<bool>() && arg->get<bool>() == false) {
|
||||
block = Bindings::ScrollLogicalPosition::End;
|
||||
}
|
||||
|
||||
// 6. If the element does not have any associated box, or is not available to user-agent features, then return.
|
||||
document().update_layout();
|
||||
if (!layout_node())
|
||||
return;
|
||||
|
||||
// 7. Scroll the element into view with behavior, block, and inline.
|
||||
scroll_an_element_into_view(*this, behavior, block, inline_);
|
||||
|
||||
// FIXME: 8. Optionally perform some other action that brings the element to the user’s attention.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/Bindings/ElementPrototype.h>
|
||||
#include <LibWeb/CSS/CSSStyleDeclaration.h>
|
||||
#include <LibWeb/CSS/StyleComputer.h>
|
||||
#include <LibWeb/DOM/Attr.h>
|
||||
|
@ -25,6 +26,17 @@
|
|||
|
||||
namespace Web::DOM {
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view-1/#dictdef-scrolloptions
|
||||
struct ScrollOptions {
|
||||
Bindings::ScrollBehavior behavior { Bindings::ScrollBehavior::Auto };
|
||||
};
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view-1/#dictdef-scrollintoviewoptions
|
||||
struct ScrollIntoViewOptions : public ScrollOptions {
|
||||
Bindings::ScrollLogicalPosition block { Bindings::ScrollLogicalPosition::Start };
|
||||
Bindings::ScrollLogicalPosition inline_ { Bindings::ScrollLogicalPosition::Nearest };
|
||||
};
|
||||
|
||||
class Element
|
||||
: public ParentNode
|
||||
, public ChildNode<Element>
|
||||
|
@ -147,6 +159,9 @@ public:
|
|||
WebIDL::ExceptionOr<JS::GCPtr<Element>> insert_adjacent_element(String const& where, JS::NonnullGCPtr<Element> element);
|
||||
WebIDL::ExceptionOr<void> insert_adjacent_text(String const& where, String const& data);
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view-1/#dom-element-scrollintoview
|
||||
void scroll_into_view(Optional<Variant<bool, ScrollIntoViewOptions>>);
|
||||
|
||||
protected:
|
||||
Element(Document&, DOM::QualifiedName);
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
|
|
@ -9,6 +9,17 @@
|
|||
#import <Geometry/DOMRect.idl>
|
||||
#import <Geometry/DOMRectList.idl>
|
||||
|
||||
enum ScrollBehavior { "auto", "smooth" };
|
||||
dictionary ScrollOptions {
|
||||
ScrollBehavior behavior = "auto";
|
||||
};
|
||||
|
||||
enum ScrollLogicalPosition { "start", "center", "end", "nearest" };
|
||||
dictionary ScrollIntoViewOptions : ScrollOptions {
|
||||
ScrollLogicalPosition block = "start";
|
||||
ScrollLogicalPosition inline = "nearest";
|
||||
};
|
||||
|
||||
// https://dom.spec.whatwg.org/#element
|
||||
interface Element : Node {
|
||||
readonly attribute DOMString? namespaceURI;
|
||||
|
@ -56,6 +67,9 @@ interface Element : Node {
|
|||
[CEReactions] Element? insertAdjacentElement(DOMString where, Element element);
|
||||
undefined insertAdjacentText(DOMString where, DOMString data);
|
||||
[CEReactions] undefined insertAdjacentHTML(DOMString position, DOMString text);
|
||||
|
||||
undefined scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg = {});
|
||||
|
||||
};
|
||||
|
||||
Element includes ParentNode;
|
||||
|
|
Loading…
Reference in a new issue