2020-01-18 09:38:21 +01:00
/*
2022-03-09 23:53:41 +01:00
* Copyright ( c ) 2018 - 2022 , Andreas Kling < kling @ serenityos . 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>
2020-11-11 09:46:53 +00:00
# include <LibWeb/DOM/Document.h>
2022-02-16 20:43:24 +01:00
# include <LibWeb/DOM/IDLEventListener.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>
2022-10-08 12:25:01 +02:00
# include <LibWeb/HTML/DOMStringMap.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>
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>
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>
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>
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-11-19 19:47:52 +01:00
JS_DECLARE_ALLOCATOR ( HTMLElement ) ;
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 ) ;
2023-11-22 12:55:21 +13:00
set_prototype ( & Bindings : : ensure_web_prototype < Bindings : : HTMLElementPrototype > ( realm , " HTMLElement " _fly_string ) ) ;
2023-01-10 06:28:20 -05:00
2023-08-13 13:05:26 +02:00
m_dataset = DOMStringMap : : create ( * this ) ;
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 ) ;
2022-08-28 13:42:07 +02:00
}
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.
2023-09-03 14:58:18 +12:00
auto dir = deprecated_attribute ( 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
}
}
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
}
2023-09-06 16:03:01 +12:00
return WebIDL : : SyntaxError : : create ( realm ( ) , " Invalid contentEditable value, must be 'true', 'false', or 'inherit' " _fly_string ) ;
2020-08-03 02:57:28 +01:00
}
2020-11-11 09:46:53 +00:00
void HTMLElement : : set_inner_text ( StringView text )
{
remove_all_children ( ) ;
2023-09-15 21:46:58 +12:00
MUST ( append_child ( document ( ) . create_text_node ( MUST ( String : : from_utf8 ( text ) ) ) ) ) ;
2020-11-11 09:46:53 +00:00
set_needs_style_update ( true ) ;
}
2023-09-03 16:42:25 +12:00
String HTMLElement : : inner_text ( )
2020-11-11 09:46:53 +00:00
{
StringBuilder builder ;
// innerText for element being rendered takes visibility into account, so force a layout and then walk the layout tree.
2020-12-14 10:39:39 +01:00
document ( ) . update_layout ( ) ;
2020-11-11 09:46:53 +00:00
if ( ! layout_node ( ) )
2023-09-17 10:51:43 +12:00
return text_content ( ) . value_or ( String { } ) ;
2020-11-11 09:46:53 +00:00
2022-04-01 20:58:27 +03:00
Function < void ( Layout : : Node const & ) > recurse = [ & ] ( auto & node ) {
2020-11-11 09:46:53 +00:00
for ( auto * child = node . first_child ( ) ; child ; child = child - > next_sibling ( ) ) {
2021-01-01 18:55:47 +01:00
if ( is < Layout : : TextNode > ( child ) )
2021-06-24 19:53:42 +02:00
builder . append ( verify_cast < Layout : : TextNode > ( * child ) . text_for_rendering ( ) ) ;
2021-01-01 18:55:47 +01:00
if ( is < Layout : : BreakNode > ( child ) )
2020-11-11 09:46:53 +00:00
builder . append ( ' \n ' ) ;
recurse ( * child ) ;
}
} ;
recurse ( * layout_node ( ) ) ;
2023-09-03 16:42:25 +12:00
return MUST ( builder . to_string ( ) ) ;
2020-11-11 09:46:53 +00:00
}
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 ) ;
}
VERIFY_NOT_REACHED ( ) ;
}
// 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
// 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 ( ) ) {
auto position = layout_node ( ) - > box_type_agnostic_position ( ) ;
return position . y ( ) . to_int ( ) ;
}
// 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.
auto offset_parent_position = offset_parent - > layout_node ( ) - > box_type_agnostic_position ( ) ;
2021-04-15 20:48:55 +03:00
auto position = layout_node ( ) - > box_type_agnostic_position ( ) ;
2023-12-10 13:47:16 +01:00
return position . y ( ) . to_int ( ) - offset_parent_position . y ( ) . 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
// 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 ( ) ) {
auto position = layout_node ( ) - > box_type_agnostic_position ( ) ;
return position . x ( ) . to_int ( ) ;
}
// 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.
auto offset_parent_position = offset_parent - > layout_node ( ) - > box_type_agnostic_position ( ) ;
2021-04-15 20:48:55 +03:00
auto position = layout_node ( ) - > box_type_agnostic_position ( ) ;
2023-12-10 13:47:16 +01:00
return position . x ( ) . to_int ( ) - offset_parent_position . x ( ) . 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 ( ) ;
}
2023-11-19 18:10:36 +13:00
void HTMLElement : : attribute_changed ( FlyString const & name , Optional < String > const & value )
2021-02-03 22:47:50 +01:00
{
2023-07-03 17:08:37 +02:00
Element : : attribute_changed ( name , 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.
// FIXME: Actually create a PointerEvent!
2023-08-13 13:05:26 +02:00
auto event = UIEvents : : MouseEvent : : 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
}
2022-02-15 00:25:51 +01:00
// https://html.spec.whatwg.org/multipage/interaction.html#dom-click
void HTMLElement : : click ( )
{
// FIXME: 1. If this element is a form control that is disabled, then return.
// 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 ;
// FIXME: 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
{
// 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 )
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-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 ;
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:
2023-09-03 14:58:18 +12:00
auto rel = deprecated_attribute ( HTML : : AttributeNames : : rel ) . to_lowercase ( ) ;
2023-06-18 16:22:10 +01:00
auto link_types = rel . view ( ) . split_view_if ( Infra : : is_ascii_whitespace ) ;
// 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 ;
}
2020-03-07 10:27:02 +01:00
}