2020-01-18 09:38:21 +01:00
/*
2024-10-24 19:21:55 +02:00
* Copyright ( c ) 2018 - 2024 , Andreas Kling < andreas @ ladybird . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2020-11-11 09:46:53 +00:00
# include <AK/StringBuilder.h>
2023-01-28 22:23:16 +00:00
# include <LibWeb/ARIA/Roles.h>
2023-02-15 19:18:58 +01:00
# include <LibWeb/Bindings/ExceptionOrUtils.h>
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/HTMLElementPrototype.h>
2020-11-11 09:46:53 +00:00
# include <LibWeb/DOM/Document.h>
2024-10-20 00:12:05 +02:00
# include <LibWeb/DOM/ElementFactory.h>
2022-02-16 20:43:24 +01:00
# include <LibWeb/DOM/IDLEventListener.h>
2024-05-18 14:10:00 +01:00
# include <LibWeb/DOM/LiveNodeList.h>
2022-10-02 14:42:47 -06:00
# include <LibWeb/DOM/ShadowRoot.h>
2022-02-06 18:46:26 +01:00
# include <LibWeb/HTML/BrowsingContext.h>
2024-06-24 21:54:42 +01:00
# include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
2022-10-08 12:25:01 +02:00
# include <LibWeb/HTML/DOMStringMap.h>
2024-06-24 21:54:42 +01:00
# include <LibWeb/HTML/ElementInternals.h>
2021-02-03 22:47:50 +01:00
# include <LibWeb/HTML/EventHandler.h>
2022-11-05 14:30:49 +00:00
# include <LibWeb/HTML/Focus.h>
2020-11-21 21:53:18 +00:00
# include <LibWeb/HTML/HTMLAnchorElement.h>
2022-10-02 14:42:47 -06:00
# include <LibWeb/HTML/HTMLAreaElement.h>
2024-10-24 19:21:55 +02:00
# include <LibWeb/HTML/HTMLBRElement.h>
2023-06-18 16:22:10 +01:00
# include <LibWeb/HTML/HTMLBaseElement.h>
2021-04-15 20:48:55 +03:00
# include <LibWeb/HTML/HTMLBodyElement.h>
2020-07-26 15:08:16 +02:00
# include <LibWeb/HTML/HTMLElement.h>
2024-05-18 14:10:00 +01:00
# include <LibWeb/HTML/HTMLLabelElement.h>
2024-10-24 19:21:55 +02:00
# include <LibWeb/HTML/HTMLParagraphElement.h>
2022-12-12 12:20:02 +01:00
# include <LibWeb/HTML/NavigableContainer.h>
2022-10-02 14:42:47 -06:00
# include <LibWeb/HTML/VisibilityState.h>
2022-03-07 23:08:26 +01:00
# include <LibWeb/HTML/Window.h>
2023-06-18 16:22:10 +01:00
# include <LibWeb/Infra/CharacterTypes.h>
# include <LibWeb/Infra/Strings.h>
2021-09-30 01:35:19 +02:00
# include <LibWeb/Layout/Box.h>
2021-01-01 18:55:47 +01:00
# include <LibWeb/Layout/BreakNode.h>
2020-11-22 15:53:01 +01:00
# include <LibWeb/Layout/TextNode.h>
2024-10-20 00:12:05 +02:00
# include <LibWeb/Namespace.h>
2022-03-10 23:13:37 +01:00
# include <LibWeb/Painting/PaintableBox.h>
2021-02-03 22:47:50 +01:00
# include <LibWeb/UIEvents/EventNames.h>
2022-02-07 00:04:10 +01:00
# include <LibWeb/UIEvents/FocusEvent.h>
2022-03-15 00:50:19 +00:00
# include <LibWeb/UIEvents/MouseEvent.h>
2024-04-07 19:51:02 +02:00
# include <LibWeb/UIEvents/PointerEvent.h>
2022-09-25 17:28:46 +01:00
# include <LibWeb/WebIDL/DOMException.h>
2022-09-25 17:03:42 +01:00
# include <LibWeb/WebIDL/ExceptionOr.h>
2019-09-29 11:59:38 +02:00
2020-07-28 18:20:36 +02:00
namespace Web : : HTML {
2020-03-07 10:27:02 +01:00
2023-12-23 15:15:27 +01:00
JS_DEFINE_ALLOCATOR ( HTMLElement ) ;
2023-11-19 19:47:52 +01:00
2022-02-18 21:00:52 +01:00
HTMLElement : : HTMLElement ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2021-02-07 11:20:15 +01:00
: Element ( document , move ( qualified_name ) )
2019-09-29 11:59:38 +02:00
{
}
2022-03-14 13:21:51 -06:00
HTMLElement : : ~ HTMLElement ( ) = default ;
2020-03-07 10:27:02 +01:00
2023-08-07 08:41:28 +02:00
void HTMLElement : : initialize ( JS : : Realm & realm )
2022-09-03 18:49:56 +02:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( HTMLElement ) ;
2022-09-03 18:49:56 +02:00
}
2022-08-28 13:42:07 +02:00
void HTMLElement : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
2023-11-19 16:18:00 +13:00
visitor . visit ( m_dataset ) ;
2024-05-18 17:21:30 +01:00
visitor . visit ( m_labels ) ;
2024-06-24 21:54:42 +01:00
visitor . visit ( m_attached_internals ) ;
2022-08-28 13:42:07 +02:00
}
2024-04-24 14:56:26 +02:00
JS : : NonnullGCPtr < DOMStringMap > HTMLElement : : dataset ( )
{
if ( ! m_dataset )
m_dataset = DOMStringMap : : create ( * this ) ;
return * m_dataset ;
}
2022-11-04 22:56:42 -03:00
// https://html.spec.whatwg.org/multipage/dom.html#dom-dir
2023-09-03 16:42:25 +12:00
StringView HTMLElement : : dir ( ) const
2022-11-04 22:56:42 -03:00
{
2023-09-03 16:42:25 +12:00
// FIXME: This should probably be `Reflect` in the IDL.
// The dir IDL attribute on an element must reflect the dir content attribute of that element, limited to only known values.
2024-01-16 19:04:45 +01:00
auto dir = get_attribute_value ( HTML : : AttributeNames : : dir ) ;
2022-11-04 22:56:42 -03:00
# define __ENUMERATE_HTML_ELEMENT_DIR_ATTRIBUTE(keyword) \
2023-03-10 08:48:54 +01:00
if ( dir . equals_ignoring_ascii_case ( # keyword # # sv ) ) \
2022-11-04 22:56:42 -03:00
return # keyword # # sv ;
ENUMERATE_HTML_ELEMENT_DIR_ATTRIBUTES
# undef __ENUMERATE_HTML_ELEMENT_DIR_ATTRIBUTE
return { } ;
}
2023-09-03 16:42:25 +12:00
void HTMLElement : : set_dir ( String const & dir )
2022-11-04 22:56:42 -03:00
{
MUST ( set_attribute ( HTML : : AttributeNames : : dir , dir ) ) ;
}
2020-08-03 02:57:28 +01:00
bool HTMLElement : : is_editable ( ) const
{
2023-05-15 10:08:13 +02:00
switch ( m_content_editable_state ) {
2020-08-03 02:57:28 +01:00
case ContentEditableState : : True :
return true ;
case ContentEditableState : : False :
return false ;
case ContentEditableState : : Inherit :
return parent ( ) & & parent ( ) - > is_editable ( ) ;
default :
2021-02-23 20:42:32 +01:00
VERIFY_NOT_REACHED ( ) ;
2020-08-03 02:57:28 +01:00
}
}
2024-02-23 21:29:43 +01:00
bool HTMLElement : : is_focusable ( ) const
{
return m_content_editable_state = = ContentEditableState : : True ;
}
2024-02-25 07:00:04 +01:00
// https://html.spec.whatwg.org/multipage/interaction.html#dom-iscontenteditable
bool HTMLElement : : is_content_editable ( ) const
{
// The isContentEditable IDL attribute, on getting, must return true if the element is either an editing host or
// editable, and false otherwise.
return is_editable ( ) ;
}
2023-09-03 16:42:25 +12:00
StringView HTMLElement : : content_editable ( ) const
2020-08-03 02:57:28 +01:00
{
2023-05-15 10:08:13 +02:00
switch ( m_content_editable_state ) {
2020-08-03 02:57:28 +01:00
case ContentEditableState : : True :
2023-09-03 16:42:25 +12:00
return " true " sv ;
2020-08-03 02:57:28 +01:00
case ContentEditableState : : False :
2023-09-03 16:42:25 +12:00
return " false " sv ;
2020-08-03 02:57:28 +01:00
case ContentEditableState : : Inherit :
2023-09-03 16:42:25 +12:00
return " inherit " sv ;
2020-08-03 02:57:28 +01:00
}
2023-09-03 16:42:25 +12:00
VERIFY_NOT_REACHED ( ) ;
2020-08-03 02:57:28 +01:00
}
2021-02-20 00:43:08 +01:00
// https://html.spec.whatwg.org/multipage/interaction.html#contenteditable
2023-09-03 16:42:25 +12:00
WebIDL : : ExceptionOr < void > HTMLElement : : set_content_editable ( StringView content_editable )
2020-08-03 02:57:28 +01:00
{
2023-03-10 08:48:54 +01:00
if ( content_editable . equals_ignoring_ascii_case ( " inherit " sv ) ) {
2020-08-03 02:57:28 +01:00
remove_attribute ( HTML : : AttributeNames : : contenteditable ) ;
2021-02-20 00:43:08 +01:00
return { } ;
2020-08-03 02:57:28 +01:00
}
2023-03-10 08:48:54 +01:00
if ( content_editable . equals_ignoring_ascii_case ( " true " sv ) ) {
2023-10-08 11:42:00 +13:00
MUST ( set_attribute ( HTML : : AttributeNames : : contenteditable , " true " _string ) ) ;
2021-02-20 00:43:08 +01:00
return { } ;
2020-08-03 02:57:28 +01:00
}
2023-03-10 08:48:54 +01:00
if ( content_editable . equals_ignoring_ascii_case ( " false " sv ) ) {
2023-10-08 11:42:00 +13:00
MUST ( set_attribute ( HTML : : AttributeNames : : contenteditable , " false " _string ) ) ;
2021-02-20 00:43:08 +01:00
return { } ;
2020-08-03 02:57:28 +01:00
}
2024-10-12 20:56:21 +02:00
return WebIDL : : SyntaxError : : create ( realm ( ) , " Invalid contentEditable value, must be 'true', 'false', or 'inherit' " _string ) ;
2020-08-03 02:57:28 +01:00
}
2024-10-20 00:12:05 +02:00
// https://html.spec.whatwg.org/multipage/dom.html#set-the-inner-text-steps
2020-11-11 09:46:53 +00:00
void HTMLElement : : set_inner_text ( StringView text )
{
2024-10-20 00:12:05 +02:00
// 1. Let fragment be the rendered text fragment for value given element's node document.
// 2. Replace all with fragment within element.
2020-11-11 09:46:53 +00:00
remove_all_children ( ) ;
2024-10-20 00:12:05 +02:00
append_rendered_text_fragment ( text ) ;
2020-11-11 09:46:53 +00:00
set_needs_style_update ( true ) ;
}
2024-04-14 18:26:44 +02:00
// https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute:dom-outertext-2
WebIDL : : ExceptionOr < void > HTMLElement : : set_outer_text ( String )
2020-11-11 09:46:53 +00:00
{
2024-04-14 18:26:44 +02:00
dbgln ( " FIXME: Implement HTMLElement::set_outer_text() " ) ;
return { } ;
}
2024-10-20 00:12:05 +02:00
// https://html.spec.whatwg.org/multipage/dom.html#rendered-text-fragment
void HTMLElement : : append_rendered_text_fragment ( StringView input )
{
// FIXME: 1. Let fragment be a new DocumentFragment whose node document is document.
// Instead of creating a DocumentFragment the nodes are appended directly.
// 2. Let position be a position variable for input, initially pointing at the start of input.
// 3. Let text be the empty string.
// 4. While position is not past the end of input:
while ( ! input . is_empty ( ) ) {
// 1. Collect a sequence of code points that are not U+000A LF or U+000D CR from input given position, and set text to the result.
auto newline_index = input . find_any_of ( " \n \r " sv ) ;
size_t const sequence_end_index = newline_index . value_or ( input . length ( ) ) ;
StringView const text = input . substring_view ( 0 , sequence_end_index ) ;
input = input . substring_view_starting_after_substring ( text ) ;
// 2. If text is not the empty string, then append a new Text node whose data is text and node document is document to fragment.
if ( ! text . is_empty ( ) ) {
MUST ( append_child ( document ( ) . create_text_node ( MUST ( String : : from_utf8 ( text ) ) ) ) ) ;
}
// 3. While position is not past the end of input, and the code point at position is either U+000A LF or U+000D CR:
while ( input . starts_with ( ' \n ' ) | | input . starts_with ( ' \r ' ) ) {
// 1. If the code point at position is U+000D CR and the next code point is U+000A LF, then advance position to the next code point in input.
if ( input . starts_with ( " \r \n " sv ) ) {
// 2. Advance position to the next code point in input.
input = input . substring_view ( 2 ) ;
} else {
// 2. Advance position to the next code point in input.
input = input . substring_view ( 1 ) ;
}
// 3. Append the result of creating an element given document, br, and the HTML namespace to fragment.
auto br_element = DOM : : create_element ( document ( ) , HTML : : TagNames : : br , Namespace : : HTML ) . release_value ( ) ;
MUST ( append_child ( br_element ) ) ;
}
}
}
2024-10-24 19:21:55 +02:00
struct RequiredLineBreakCount {
int count { 0 } ;
} ;
// https://html.spec.whatwg.org/multipage/dom.html#rendered-text-collection-steps
static Vector < Variant < String , RequiredLineBreakCount > > rendered_text_collection_steps ( DOM : : Node const & node )
2024-04-14 18:26:44 +02:00
{
2024-10-24 19:21:55 +02:00
// 1. Let items be the result of running the rendered text collection steps with each child node of node in tree order, and then concatenating the results to a single list.
Vector < Variant < String , RequiredLineBreakCount > > items ;
node . for_each_child ( [ & ] ( auto const & child ) {
auto child_items = rendered_text_collection_steps ( child ) ;
items . extend ( move ( child_items ) ) ;
return IterationDecision : : Continue ;
} ) ;
// NOTE: Steps are re-ordered here a bit.
// 3. If node is not being rendered, then return items.
// For the purpose of this step, the following elements must act as described
// if the computed value of the 'display' property is not 'none':
// FIXME: - select elements have an associated non-replaced inline CSS box whose child boxes include only those of optgroup and option element child nodes;
// FIXME: - optgroup elements have an associated non-replaced block-level CSS box whose child boxes include only those of option element child nodes; and
// FIXME: - option element have an associated non-replaced block-level CSS box whose child boxes are as normal for non-replaced block-level CSS boxes.
auto * layout_node = node . layout_node ( ) ;
if ( ! layout_node )
return items ;
auto const & computed_values = layout_node - > computed_values ( ) ;
// 2. If node's computed value of 'visibility' is not 'visible', then return items.
if ( computed_values . visibility ( ) ! = CSS : : Visibility : : Visible )
return items ;
// AD-HOC: If node's computed value of 'content-visibility' is 'hidden', then return items.
if ( computed_values . content_visibility ( ) = = CSS : : ContentVisibility : : Hidden )
return items ;
// 4. If node is a Text node, then for each CSS text box produced by node, in content order,
// compute the text of the box after application of the CSS 'white-space' processing rules
// and 'text-transform' rules, set items to the list of the resulting strings, and return items.
// FIXME: The CSS 'white-space' processing rules are slightly modified:
// collapsible spaces at the end of lines are always collapsed,
// but they are only removed if the line is the last line of the block,
// or it ends with a br element. Soft hyphens should be preserved. [CSSTEXT]
if ( is < DOM : : Text > ( node ) ) {
auto const * layout_text_node = verify_cast < Layout : : TextNode > ( layout_node ) ;
items . append ( layout_text_node - > text_for_rendering ( ) ) ;
return items ;
}
2024-04-14 18:26:44 +02:00
2024-10-24 19:21:55 +02:00
// 5. If node is a br element, then append a string containing a single U+000A LF code point to items.
if ( is < HTML : : HTMLBRElement > ( node ) ) {
items . append ( " \n " _string ) ;
return items ;
}
auto display = computed_values . display ( ) ;
// 6. If node's computed value of 'display' is 'table-cell', and node's CSS box is not the last 'table-cell' box of its enclosing 'table-row' box, then append a string containing a single U+0009 TAB code point to items.
if ( display . is_table_cell ( ) & & node . next_sibling ( ) )
items . append ( " \t " _string ) ;
// 7. If node's computed value of 'display' is 'table-row', and node's CSS box is not the last 'table-row' box of the nearest ancestor 'table' box, then append a string containing a single U+000A LF code point to items.
if ( display . is_table_row ( ) & & node . next_sibling ( ) )
items . append ( " \n " _string ) ;
// 8. If node is a p element, then append 2 (a required line break count) at the beginning and end of items.
if ( is < HTML : : HTMLParagraphElement > ( node ) ) {
items . prepend ( RequiredLineBreakCount { 2 } ) ;
items . append ( RequiredLineBreakCount { 2 } ) ;
}
2020-11-11 09:46:53 +00:00
2024-10-24 19:21:55 +02:00
// 9. If node's used value of 'display' is block-level or 'table-caption', then append 1 (a required line break count) at the beginning and end of items. [CSSDISPLAY]
if ( display . is_block_outside ( ) | | display . is_table_caption ( ) ) {
items . prepend ( RequiredLineBreakCount { 1 } ) ;
items . append ( RequiredLineBreakCount { 1 } ) ;
}
// 10. Return items.
return items ;
}
// https://html.spec.whatwg.org/multipage/dom.html#get-the-text-steps
String HTMLElement : : get_the_text_steps ( )
{
// 1. If element is not being rendered or if the user agent is a non-CSS user agent, then return element's descendant text content.
2020-12-14 10:39:39 +01:00
document ( ) . update_layout ( ) ;
2020-11-11 09:46:53 +00:00
if ( ! layout_node ( ) )
2024-10-24 19:21:55 +02:00
return descendant_text_content ( ) ;
// 2. Let results be a new empty list.
Vector < Variant < String , RequiredLineBreakCount > > results ;
// 3. For each child node node of element:
for_each_child ( [ & ] ( Node const & node ) {
// 1. Let current be the list resulting in running the rendered text collection steps with node.
// Each item in results will either be a string or a positive integer (a required line break count).
auto current = rendered_text_collection_steps ( node ) ;
// 2. For each item item in current, append item to results.
results . extend ( move ( current ) ) ;
return IterationDecision : : Continue ;
} ) ;
// 4. Remove any items from results that are the empty string.
results . remove_all_matching ( [ ] ( auto & item ) {
return item . visit (
[ ] ( String const & string ) { return string . is_empty ( ) ; } ,
[ ] ( RequiredLineBreakCount const & ) { return false ; } ) ;
} ) ;
// 5. Remove any runs of consecutive required line break count items at the start or end of results.
while ( ! results . is_empty ( ) & & results . first ( ) . has < RequiredLineBreakCount > ( ) )
results . take_first ( ) ;
while ( ! results . is_empty ( ) & & results . last ( ) . has < RequiredLineBreakCount > ( ) )
results . take_last ( ) ;
// 6. Replace each remaining run of consecutive required line break count items
// with a string consisting of as many U+000A LF code points as the maximum of the values
// in the required line break count items.
for ( size_t i = 0 ; i < results . size ( ) ; + + i ) {
if ( ! results [ i ] . has < RequiredLineBreakCount > ( ) )
continue ;
int max_line_breaks = results [ i ] . get < RequiredLineBreakCount > ( ) . count ;
size_t j = i + 1 ;
while ( j < results . size ( ) & & results [ j ] . has < RequiredLineBreakCount > ( ) ) {
max_line_breaks = max ( max_line_breaks , results [ j ] . get < RequiredLineBreakCount > ( ) . count ) ;
+ + j ;
2020-11-11 09:46:53 +00:00
}
2024-10-24 19:21:55 +02:00
results . remove ( i , j - i ) ;
results . insert ( i , MUST ( String : : repeated ( ' \n ' , max_line_breaks ) ) ) ;
}
// 7. Return the concatenation of the string items in results.
StringBuilder builder ;
for ( auto & item : results ) {
item . visit (
[ & ] ( String const & string ) { builder . append ( string ) ; } ,
[ & ] ( RequiredLineBreakCount const & ) { } ) ;
}
return builder . to_string_without_validation ( ) ;
2020-11-11 09:46:53 +00:00
}
2024-04-14 18:26:44 +02:00
// https://html.spec.whatwg.org/multipage/dom.html#dom-innertext
String HTMLElement : : inner_text ( )
{
// The innerText and outerText getter steps are to return the result of running get the text steps with this.
return get_the_text_steps ( ) ;
}
// https://html.spec.whatwg.org/multipage/dom.html#dom-outertext
String HTMLElement : : outer_text ( )
{
// The innerText and outerText getter steps are to return the result of running get the text steps with this.
return get_the_text_steps ( ) ;
}
2023-12-10 13:47:16 +01:00
// https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetparent
JS : : GCPtr < DOM : : Element > HTMLElement : : offset_parent ( ) const
{
const_cast < DOM : : Document & > ( document ( ) ) . update_layout ( ) ;
// 1. If any of the following holds true return null and terminate this algorithm:
// - The element does not have an associated CSS layout box.
// - The element is the root element.
// - The element is the HTML body element.
// - The element’ s computed value of the position property is fixed.
if ( ! layout_node ( ) )
return nullptr ;
if ( is_document_element ( ) )
return nullptr ;
if ( is < HTML : : HTMLBodyElement > ( * this ) )
return nullptr ;
if ( layout_node ( ) - > is_fixed_position ( ) )
return nullptr ;
// 2. Return the nearest ancestor element of the element for which at least one of the following is true
// and terminate this algorithm if such an ancestor is found:
// - The computed value of the position property is not static.
// - It is the HTML body element.
// - The computed value of the position property of the element is static
// and the ancestor is one of the following HTML elements: td, th, or table.
for ( auto * ancestor = parent_element ( ) ; ancestor ; ancestor = ancestor - > parent_element ( ) ) {
if ( ! ancestor - > layout_node ( ) )
continue ;
if ( ancestor - > layout_node ( ) - > is_positioned ( ) )
return const_cast < Element * > ( ancestor ) ;
if ( is < HTML : : HTMLBodyElement > ( * ancestor ) )
return const_cast < Element * > ( ancestor ) ;
if ( ! ancestor - > layout_node ( ) - > is_positioned ( ) & & ancestor - > local_name ( ) . is_one_of ( HTML : : TagNames : : td , HTML : : TagNames : : th , HTML : : TagNames : : table ) )
return const_cast < Element * > ( ancestor ) ;
}
2024-02-29 21:53:58 +00:00
// 3. Return null.
return nullptr ;
2023-12-10 13:47:16 +01:00
}
// https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsettop
2021-09-30 01:35:19 +02:00
int HTMLElement : : offset_top ( ) const
2021-04-15 20:48:55 +03:00
{
2023-12-10 13:47:16 +01:00
// 1. If the element is the HTML body element or does not have any associated CSS layout box
// return zero and terminate this algorithm.
if ( is < HTML : : HTMLBodyElement > ( * this ) )
return 0 ;
2022-09-17 16:10:08 +02:00
// NOTE: Ensure that layout is up-to-date before looking at metrics.
const_cast < DOM : : Document & > ( document ( ) ) . update_layout ( ) ;
2023-12-10 13:47:16 +01:00
if ( ! layout_node ( ) )
2021-04-15 20:48:55 +03:00
return 0 ;
2023-12-10 13:47:16 +01:00
2024-07-25 17:01:16 +02:00
CSSPixels top_border_edge_of_element ;
if ( paintable ( ) - > is_paintable_box ( ) ) {
top_border_edge_of_element = paintable_box ( ) - > absolute_border_box_rect ( ) . y ( ) ;
} else {
top_border_edge_of_element = paintable ( ) - > box_type_agnostic_position ( ) . y ( ) ;
}
2023-12-10 13:47:16 +01:00
// 2. If the offsetParent of the element is null
// return the y-coordinate of the top border edge of the first CSS layout box associated with the element,
// relative to the initial containing block origin,
// ignoring any transforms that apply to the element and its ancestors, and terminate this algorithm.
auto offset_parent = this - > offset_parent ( ) ;
if ( ! offset_parent | | ! offset_parent - > layout_node ( ) ) {
2024-07-25 17:01:16 +02:00
return top_border_edge_of_element . to_int ( ) ;
2023-12-10 13:47:16 +01:00
}
// 3. Return the result of subtracting the y-coordinate of the top padding edge
// of the first box associated with the offsetParent of the element
// from the y-coordinate of the top border edge of the first box associated with the element,
// relative to the initial containing block origin,
// ignoring any transforms that apply to the element and its ancestors.
2024-07-25 17:01:16 +02:00
// NOTE: We give special treatment to the body element to match other browsers.
// Spec bug: https://github.com/w3c/csswg-drafts/issues/10549
CSSPixels top_padding_edge_of_offset_parent ;
if ( offset_parent - > is_html_body_element ( ) & & ! offset_parent - > paintable ( ) - > is_positioned ( ) ) {
top_padding_edge_of_offset_parent = 0 ;
} else if ( offset_parent - > paintable ( ) - > is_paintable_box ( ) ) {
top_padding_edge_of_offset_parent = offset_parent - > paintable_box ( ) - > absolute_padding_box_rect ( ) . y ( ) ;
} else {
top_padding_edge_of_offset_parent = offset_parent - > paintable ( ) - > box_type_agnostic_position ( ) . y ( ) ;
}
return ( top_border_edge_of_element - top_padding_edge_of_offset_parent ) . to_int ( ) ;
2021-04-15 20:48:55 +03:00
}
2023-12-10 13:47:16 +01:00
// https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetleft
2021-09-30 01:35:19 +02:00
int HTMLElement : : offset_left ( ) const
2021-04-15 20:48:55 +03:00
{
2023-12-10 13:47:16 +01:00
// 1. If the element is the HTML body element or does not have any associated CSS layout box return zero and terminate this algorithm.
if ( is < HTML : : HTMLBodyElement > ( * this ) )
return 0 ;
2022-09-17 16:10:08 +02:00
// NOTE: Ensure that layout is up-to-date before looking at metrics.
const_cast < DOM : : Document & > ( document ( ) ) . update_layout ( ) ;
2023-12-10 13:47:16 +01:00
if ( ! layout_node ( ) )
2021-04-15 20:48:55 +03:00
return 0 ;
2023-12-10 13:47:16 +01:00
2024-07-25 17:01:16 +02:00
CSSPixels left_border_edge_of_element ;
if ( paintable ( ) - > is_paintable_box ( ) ) {
left_border_edge_of_element = paintable_box ( ) - > absolute_border_box_rect ( ) . x ( ) ;
} else {
left_border_edge_of_element = paintable ( ) - > box_type_agnostic_position ( ) . x ( ) ;
}
2023-12-10 13:47:16 +01:00
// 2. If the offsetParent of the element is null
// return the x-coordinate of the left border edge of the first CSS layout box associated with the element,
// relative to the initial containing block origin,
// ignoring any transforms that apply to the element and its ancestors, and terminate this algorithm.
auto offset_parent = this - > offset_parent ( ) ;
if ( ! offset_parent | | ! offset_parent - > layout_node ( ) ) {
2024-07-25 17:01:16 +02:00
return left_border_edge_of_element . to_int ( ) ;
2023-12-10 13:47:16 +01:00
}
// 3. Return the result of subtracting the x-coordinate of the left padding edge
// of the first CSS layout box associated with the offsetParent of the element
// from the x-coordinate of the left border edge of the first CSS layout box associated with the element,
// relative to the initial containing block origin,
// ignoring any transforms that apply to the element and its ancestors.
2024-07-25 17:01:16 +02:00
// NOTE: We give special treatment to the body element to match other browsers.
// Spec bug: https://github.com/w3c/csswg-drafts/issues/10549
CSSPixels left_padding_edge_of_offset_parent ;
if ( offset_parent - > is_html_body_element ( ) & & ! offset_parent - > paintable ( ) - > is_positioned ( ) ) {
left_padding_edge_of_offset_parent = 0 ;
} else if ( offset_parent - > paintable ( ) - > is_paintable_box ( ) ) {
left_padding_edge_of_offset_parent = offset_parent - > paintable_box ( ) - > absolute_padding_box_rect ( ) . x ( ) ;
} else {
left_padding_edge_of_offset_parent = offset_parent - > paintable ( ) - > box_type_agnostic_position ( ) . x ( ) ;
}
return ( left_border_edge_of_element - left_padding_edge_of_offset_parent ) . to_int ( ) ;
2021-04-15 20:48:55 +03:00
}
2021-09-30 01:35:19 +02:00
// https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetwidth
int HTMLElement : : offset_width ( ) const
{
2022-04-10 20:38:16 +02:00
// NOTE: Ensure that layout is up-to-date before looking at metrics.
const_cast < DOM : : Document & > ( document ( ) ) . update_layout ( ) ;
// 1. If the element does not have any associated CSS layout box return zero and terminate this algorithm.
2023-04-20 16:01:16 +01:00
if ( ! paintable_box ( ) )
2022-04-10 20:38:16 +02:00
return 0 ;
// 2. Return the width of the axis-aligned bounding box of the border boxes of all fragments generated by the element’ s principal box,
// ignoring any transforms that apply to the element and its ancestors.
// FIXME: Account for inline boxes.
2023-06-12 21:37:35 +03:00
return paintable_box ( ) - > border_box_width ( ) . to_int ( ) ;
2021-09-30 01:35:19 +02:00
}
// https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetheight
int HTMLElement : : offset_height ( ) const
{
2022-04-10 20:38:16 +02:00
// NOTE: Ensure that layout is up-to-date before looking at metrics.
const_cast < DOM : : Document & > ( document ( ) ) . update_layout ( ) ;
// 1. If the element does not have any associated CSS layout box return zero and terminate this algorithm.
2023-04-20 16:01:16 +01:00
if ( ! paintable_box ( ) )
2022-04-10 20:38:16 +02:00
return 0 ;
// 2. Return the height of the axis-aligned bounding box of the border boxes of all fragments generated by the element’ s principal box,
// ignoring any transforms that apply to the element and its ancestors.
// FIXME: Account for inline boxes.
2023-06-12 21:37:35 +03:00
return paintable_box ( ) - > border_box_height ( ) . to_int ( ) ;
2021-09-30 01:35:19 +02:00
}
2022-09-18 10:29:53 +02:00
// https://html.spec.whatwg.org/multipage/links.html#cannot-navigate
2020-11-21 21:53:18 +00:00
bool HTMLElement : : cannot_navigate ( ) const
{
2022-09-18 10:29:53 +02:00
// An element element cannot navigate if one of the following is true:
// - element's node document is not fully active
if ( ! document ( ) . is_fully_active ( ) )
return true ;
// - element is not an a element and is not connected.
2020-11-21 21:53:18 +00:00
return ! is < HTML : : HTMLAnchorElement > ( this ) & & ! is_connected ( ) ;
}
2024-07-09 20:18:41 +01:00
void HTMLElement : : attribute_changed ( FlyString const & name , Optional < String > const & old_value , Optional < String > const & value )
2021-02-03 22:47:50 +01:00
{
2024-07-09 20:18:41 +01:00
Element : : attribute_changed ( name , old_value , value ) ;
2021-02-03 22:47:50 +01:00
2023-05-15 10:08:13 +02:00
if ( name = = HTML : : AttributeNames : : contenteditable ) {
2023-10-10 15:00:58 +03:30
if ( ! value . has_value ( ) ) {
2023-05-15 10:08:13 +02:00
m_content_editable_state = ContentEditableState : : Inherit ;
2023-07-03 17:31:17 +02:00
} else {
2023-10-10 15:00:58 +03:30
if ( value - > is_empty ( ) | | value - > equals_ignoring_ascii_case ( " true " sv ) ) {
2023-07-03 17:31:17 +02:00
// "true", an empty string or a missing value map to the "true" state.
m_content_editable_state = ContentEditableState : : True ;
2023-10-10 15:00:58 +03:30
} else if ( value - > equals_ignoring_ascii_case ( " false " sv ) ) {
2023-07-03 17:31:17 +02:00
// "false" maps to the "false" state.
m_content_editable_state = ContentEditableState : : False ;
} else {
// Having no such attribute or an invalid value maps to the "inherit" state.
m_content_editable_state = ContentEditableState : : Inherit ;
}
2023-05-15 10:08:13 +02:00
}
}
2021-10-14 18:03:08 +01:00
// 1. If namespace is not null, or localName is not the name of an event handler content attribute on element, then return.
// FIXME: Add the namespace part once we support attribute namespaces.
2021-02-03 22:47:50 +01:00
# undef __ENUMERATE
2023-11-19 18:10:36 +13:00
# define __ENUMERATE(attribute_name, event_name) \
if ( name = = HTML : : AttributeNames : : attribute_name ) { \
element_event_handler_attribute_changed ( event_name , value ) ; \
2021-02-03 22:47:50 +01:00
}
ENUMERATE_GLOBAL_EVENT_HANDLERS ( __ENUMERATE )
# undef __ENUMERATE
}
2022-02-06 18:46:26 +01:00
// https://html.spec.whatwg.org/multipage/interaction.html#dom-focus
void HTMLElement : : focus ( )
{
// 1. If the element is marked as locked for focus, then return.
if ( m_locked_for_focus )
return ;
// 2. Mark the element as locked for focus.
m_locked_for_focus = true ;
// 3. Run the focusing steps for the element.
run_focusing_steps ( this ) ;
// FIXME: 4. If the value of the preventScroll dictionary member of options is false,
// then scroll the element into view with scroll behavior "auto",
// block flow direction position set to an implementation-defined value,
// and inline base direction position set to an implementation-defined value.
// 5. Unmark the element as locked for focus.
m_locked_for_focus = false ;
}
2022-02-15 00:25:51 +01:00
2022-02-25 20:45:19 +01:00
// https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-synthetic-pointer-event
2023-04-09 11:26:59 +02:00
bool HTMLElement : : fire_a_synthetic_pointer_event ( FlyString const & type , DOM : : Element & target , bool not_trusted )
2022-02-25 20:45:19 +01:00
{
// 1. Let event be the result of creating an event using PointerEvent.
// 2. Initialize event's type attribute to e.
2024-04-07 19:52:39 +02:00
auto event = UIEvents : : PointerEvent : : create ( realm ( ) , type ) ;
2022-02-25 20:45:19 +01:00
// 3. Initialize event's bubbles and cancelable attributes to true.
event - > set_bubbles ( true ) ;
event - > set_cancelable ( true ) ;
// 4. Set event's composed flag.
event - > set_composed ( true ) ;
// 5. If the not trusted flag is set, initialize event's isTrusted attribute to false.
if ( not_trusted ) {
event - > set_is_trusted ( false ) ;
}
// FIXME: 6. Initialize event's ctrlKey, shiftKey, altKey, and metaKey attributes according to the current state
// of the key input device, if any (false for any keys that are not available).
// FIXME: 7. Initialize event's view attribute to target's node document's Window object, if any, and null otherwise.
// FIXME: 8. event's getModifierState() method is to return values appropriately describing the current state of the key input device.
// 9. Return the result of dispatching event at target.
2023-02-14 22:43:17 +01:00
return target . dispatch_event ( event ) ;
2022-02-25 20:45:19 +01:00
}
2024-05-18 14:10:00 +01:00
// https://html.spec.whatwg.org/multipage/forms.html#dom-lfe-labels-dev
JS : : GCPtr < DOM : : NodeList > HTMLElement : : labels ( )
{
// Labelable elements and all input elements have a live NodeList object associated with them that represents the list of label elements, in tree order,
// whose labeled control is the element in question. The labels IDL attribute of labelable elements that are not form-associated custom elements,
// and the labels IDL attribute of input elements, on getting, must return that NodeList object, and that same value must always be returned,
// unless this element is an input element whose type attribute is in the Hidden state, in which case it must instead return null.
if ( ! is_labelable ( ) )
return { } ;
if ( ! m_labels ) {
m_labels = DOM : : LiveNodeList : : create ( realm ( ) , root ( ) , DOM : : LiveNodeList : : Scope : : Descendants , [ & ] ( auto & node ) {
return is < HTMLLabelElement > ( node ) & & verify_cast < HTMLLabelElement > ( node ) . control ( ) = = this ;
} ) ;
}
return m_labels ;
}
2022-02-15 00:25:51 +01:00
// https://html.spec.whatwg.org/multipage/interaction.html#dom-click
void HTMLElement : : click ( )
{
2024-07-26 10:31:19 +02:00
// 1. If this element is a form control that is disabled, then return.
if ( auto * form_control = dynamic_cast < FormAssociatedElement * > ( this ) ) {
if ( ! form_control - > enabled ( ) )
return ;
}
2022-02-15 00:25:51 +01:00
// 2. If this element's click in progress flag is set, then return.
if ( m_click_in_progress )
return ;
// 3. Set this element's click in progress flag.
m_click_in_progress = true ;
2024-04-07 19:52:39 +02:00
// 4. Fire a synthetic pointer event named click at this element, with the not trusted flag set.
2023-04-09 11:26:59 +02:00
fire_a_synthetic_pointer_event ( HTML : : EventNames : : click , * this , true ) ;
2022-02-15 00:25:51 +01:00
// 5. Unset this element's click in progress flag.
m_click_in_progress = false ;
}
2022-10-02 14:42:47 -06:00
// https://html.spec.whatwg.org/multipage/interaction.html#dom-blur
void HTMLElement : : blur ( )
{
// The blur() method, when invoked, should run the unfocusing steps for the element on which the method was called.
run_unfocusing_steps ( this ) ;
// User agents may selectively or uniformly ignore calls to this method for usability reasons.
}
2023-01-28 22:23:16 +00:00
Optional < ARIA : : Role > HTMLElement : : default_role ( ) const
2022-11-28 17:58:13 -06:00
{
2024-10-26 23:46:18 +02:00
// https://www.w3.org/TR/html-aria/#el-address
if ( local_name ( ) = = TagNames : : address )
return ARIA : : Role : : group ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-article
if ( local_name ( ) = = TagNames : : article )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : article ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-aside
if ( local_name ( ) = = TagNames : : aside )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : complementary ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-b
if ( local_name ( ) = = TagNames : : b )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-bdi
if ( local_name ( ) = = TagNames : : bdi )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-bdo
if ( local_name ( ) = = TagNames : : bdo )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-code
if ( local_name ( ) = = TagNames : : code )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : code ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-dfn
if ( local_name ( ) = = TagNames : : dfn )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : term ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-em
if ( local_name ( ) = = TagNames : : em )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : emphasis ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-figure
if ( local_name ( ) = = TagNames : : figure )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : figure ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-footer
if ( local_name ( ) = = TagNames : : footer ) {
// TODO: If not a descendant of an article, aside, main, nav or section element, or an element with role=article, complementary, main, navigation or region then role=contentinfo
// Otherwise, role=generic
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
}
// https://www.w3.org/TR/html-aria/#el-header
if ( local_name ( ) = = TagNames : : header ) {
// TODO: If not a descendant of an article, aside, main, nav or section element, or an element with role=article, complementary, main, navigation or region then role=banner
// Otherwise, role=generic
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
}
// https://www.w3.org/TR/html-aria/#el-hgroup
if ( local_name ( ) = = TagNames : : hgroup )
2024-10-26 23:46:18 +02:00
return ARIA : : Role : : group ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-i
if ( local_name ( ) = = TagNames : : i )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-main
if ( local_name ( ) = = TagNames : : main )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : main ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-nav
if ( local_name ( ) = = TagNames : : nav )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : navigation ;
2024-10-26 23:46:18 +02:00
// https://www.w3.org/TR/html-aria/#el-s
if ( local_name ( ) = = TagNames : : s )
return ARIA : : Role : : deletion ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-samp
if ( local_name ( ) = = TagNames : : samp )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-section
if ( local_name ( ) = = TagNames : : section ) {
// TODO: role=region if the section element has an accessible name
// Otherwise, no corresponding role
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : region ;
2022-11-28 17:58:13 -06:00
}
// https://www.w3.org/TR/html-aria/#el-small
if ( local_name ( ) = = TagNames : : small )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-strong
if ( local_name ( ) = = TagNames : : strong )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : strong ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-sub
if ( local_name ( ) = = TagNames : : sub )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : subscript ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-summary
if ( local_name ( ) = = TagNames : : summary )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : button ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-sup
if ( local_name ( ) = = TagNames : : sup )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : superscript ;
2022-11-28 17:58:13 -06:00
// https://www.w3.org/TR/html-aria/#el-u
if ( local_name ( ) = = TagNames : : u )
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : generic ;
2022-11-28 17:58:13 -06:00
return { } ;
}
2023-06-18 16:22:10 +01:00
// https://html.spec.whatwg.org/multipage/semantics.html#get-an-element's-target
2023-11-20 13:34:37 +13:00
String HTMLElement : : get_an_elements_target ( ) const
2023-06-18 16:22:10 +01:00
{
// To get an element's target, given an a, area, or form element element, run these steps:
// 1. If element has a target attribute, then return that attribute's value.
2023-11-20 13:34:37 +13:00
auto maybe_target = attribute ( AttributeNames : : target ) ;
if ( maybe_target . has_value ( ) )
return maybe_target . release_value ( ) ;
2023-06-18 16:22:10 +01:00
// FIXME: 2. If element's node document contains a base element with a
// target attribute, then return the value of the target attribute of the
// first such base element.
// 3. Return the empty string.
2023-11-20 13:34:37 +13:00
return String { } ;
2023-06-18 16:22:10 +01:00
}
// https://html.spec.whatwg.org/multipage/links.html#get-an-element's-noopener
TokenizedFeature : : NoOpener HTMLElement : : get_an_elements_noopener ( StringView target ) const
{
// To get an element's noopener, given an a, area, or form element element and a string target:
2024-01-16 19:04:45 +01:00
auto rel = MUST ( get_attribute_value ( HTML : : AttributeNames : : rel ) . to_lowercase ( ) ) ;
auto link_types = rel . bytes_as_string_view ( ) . split_view_if ( Infra : : is_ascii_whitespace ) ;
2023-06-18 16:22:10 +01:00
// 1. If element's link types include the noopener or noreferrer keyword, then return true.
if ( link_types . contains_slow ( " noopener " sv ) | | link_types . contains_slow ( " noreferrer " sv ) )
return TokenizedFeature : : NoOpener : : Yes ;
// 2. If element's link types do not include the opener keyword and
// target is an ASCII case-insensitive match for "_blank", then return true.
if ( ! link_types . contains_slow ( " opener " sv ) & & Infra : : is_ascii_case_insensitive_match ( target , " _blank " sv ) )
return TokenizedFeature : : NoOpener : : Yes ;
// 3. Return false.
return TokenizedFeature : : NoOpener : : No ;
}
2024-06-24 21:54:42 +01:00
WebIDL : : ExceptionOr < JS : : NonnullGCPtr < ElementInternals > > HTMLElement : : attach_internals ( )
{
// 1. If this's is value is not null, then throw a "NotSupportedError" DOMException.
if ( is_value ( ) . has_value ( ) )
2024-10-12 20:56:21 +02:00
return WebIDL : : NotSupportedError : : create ( realm ( ) , " ElementInternals cannot be attached to a customized build-in element " _string ) ;
2024-06-24 21:54:42 +01:00
// 2. Let definition be the result of looking up a custom element definition given this's node document, its namespace, its local name, and null as the is value.
auto definition = document ( ) . lookup_custom_element_definition ( namespace_uri ( ) , local_name ( ) , is_value ( ) ) ;
// 3. If definition is null, then throw an "NotSupportedError" DOMException.
if ( ! definition )
2024-10-12 20:56:21 +02:00
return WebIDL : : NotSupportedError : : create ( realm ( ) , " ElementInternals cannot be attached to an element that is not a custom element " _string ) ;
2024-06-24 21:54:42 +01:00
// 4. If definition's disable internals is true, then throw a "NotSupportedError" DOMException.
if ( definition - > disable_internals ( ) )
2024-10-12 20:56:21 +02:00
return WebIDL : : NotSupportedError : : create ( realm ( ) , " ElementInternals are disabled for this custom element " _string ) ;
2024-06-24 21:54:42 +01:00
// 5. If this's attached internals is non-null, then throw an "NotSupportedError" DOMException.
if ( m_attached_internals )
2024-10-12 20:56:21 +02:00
return WebIDL : : NotSupportedError : : create ( realm ( ) , " ElementInternals already attached " _string ) ;
2024-06-24 21:54:42 +01:00
// 6. If this's custom element state is not "precustomized" or "custom", then throw a "NotSupportedError" DOMException.
if ( ! first_is_one_of ( custom_element_state ( ) , DOM : : CustomElementState : : Precustomized , DOM : : CustomElementState : : Custom ) )
2024-10-12 20:56:21 +02:00
return WebIDL : : NotSupportedError : : create ( realm ( ) , " Custom element is in an invalid state to attach ElementInternals " _string ) ;
2024-06-24 21:54:42 +01:00
// 7. Set this's attached internals to a new ElementInternals instance whose target element is this.
auto internals = ElementInternals : : create ( realm ( ) , * this ) ;
m_attached_internals = internals ;
// 8. Return this's attached internals.
return { internals } ;
}
2024-07-01 19:55:33 +01:00
// https://html.spec.whatwg.org/multipage/popover.html#dom-popover
Optional < String > HTMLElement : : popover ( ) const
{
// FIXME: This should probably be `Reflect` in the IDL.
// The popover IDL attribute must reflect the popover attribute, limited to only known values.
auto value = get_attribute ( HTML : : AttributeNames : : popover ) ;
if ( ! value . has_value ( ) )
return { } ;
if ( value . value ( ) . is_empty ( ) | | value . value ( ) . equals_ignoring_ascii_case ( " auto " sv ) )
return " auto " _string ;
return " manual " _string ;
}
// https://html.spec.whatwg.org/multipage/popover.html#dom-popover
WebIDL : : ExceptionOr < void > HTMLElement : : set_popover ( Optional < String > value )
{
// FIXME: This should probably be `Reflect` in the IDL.
// The popover IDL attribute must reflect the popover attribute, limited to only known values.
if ( value . has_value ( ) )
return set_attribute ( HTML : : AttributeNames : : popover , value . release_value ( ) ) ;
remove_attribute ( HTML : : AttributeNames : : popover ) ;
return { } ;
}
2024-02-24 02:43:57 +01:00
void HTMLElement : : did_receive_focus ( )
{
if ( m_content_editable_state ! = ContentEditableState : : True )
return ;
2024-10-20 16:11:20 +02:00
DOM : : Text * text = nullptr ;
for_each_in_inclusive_subtree_of_type < DOM : : Text > ( [ & ] ( auto & node ) {
text = & node ;
return TraversalDecision : : Continue ;
} ) ;
if ( ! text ) {
document ( ) . set_cursor_position ( DOM : : Position : : create ( realm ( ) , * this , 0 ) ) ;
return ;
}
document ( ) . set_cursor_position ( DOM : : Position : : create ( realm ( ) , * text , text - > length ( ) ) ) ;
2024-02-24 02:43:57 +01:00
}
2024-04-14 17:55:48 +02:00
// https://html.spec.whatwg.org/multipage/interaction.html#dom-accesskeylabel
String HTMLElement : : access_key_label ( ) const
{
dbgln ( " FIXME: Implement HTMLElement::access_key_label() " ) ;
return String { } ;
}
2020-03-07 10:27:02 +01:00
}