forked from LadybirdBrowser/ladybird
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHTMLTableRowElement.cpp
More file actions
196 lines (171 loc) · 8.67 KB
/
HTMLTableRowElement.cpp
File metadata and controls
196 lines (171 loc) · 8.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*
* Copyright (c) 2020-2022, Andreas Kling <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/HTMLTableRowElementPrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/ComputedProperties.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
#include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
#include <LibWeb/CSS/StyleValues/KeywordStyleValue.h>
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/ElementFactory.h>
#include <LibWeb/DOM/HTMLCollection.h>
#include <LibWeb/HTML/HTMLTableCellElement.h>
#include <LibWeb/HTML/HTMLTableElement.h>
#include <LibWeb/HTML/HTMLTableRowElement.h>
#include <LibWeb/HTML/HTMLTableSectionElement.h>
#include <LibWeb/HTML/Parser/HTMLParser.h>
#include <LibWeb/Namespace.h>
namespace Web::HTML {
GC_DEFINE_ALLOCATOR(HTMLTableRowElement);
HTMLTableRowElement::HTMLTableRowElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: HTMLElement(document, move(qualified_name))
{
}
HTMLTableRowElement::~HTMLTableRowElement() = default;
void HTMLTableRowElement::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(HTMLTableRowElement);
Base::initialize(realm);
}
bool HTMLTableRowElement::is_presentational_hint(FlyString const& name) const
{
if (Base::is_presentational_hint(name))
return true;
return first_is_one_of(name,
HTML::AttributeNames::bgcolor,
HTML::AttributeNames::background,
HTML::AttributeNames::height,
HTML::AttributeNames::valign);
}
void HTMLTableRowElement::apply_presentational_hints(GC::Ref<CSS::CascadedProperties> cascaded_properties) const
{
Base::apply_presentational_hints(cascaded_properties);
for_each_attribute([&](auto& name, auto& value) {
if (name == HTML::AttributeNames::bgcolor) {
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:rules-for-parsing-a-legacy-colour-value
auto color = parse_legacy_color_value(value);
if (color.has_value())
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::ColorStyleValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
} else if (name == HTML::AttributeNames::background) {
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:encoding-parsing-and-serializing-a-url
if (auto parsed_value = document().encoding_parse_url(value); parsed_value.has_value())
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::StyleValueList::from_single_value(CSS::ImageStyleValue::create(*parsed_value)));
} else if (name == HTML::AttributeNames::height) {
if (auto parsed_value = parse_dimension_value(value))
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Height, *parsed_value);
} else if (name == HTML::AttributeNames::valign) {
if (auto parsed_value = parse_css_value(CSS::Parser::ParsingParams { document() }, value, CSS::PropertyID::VerticalAlign))
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::VerticalAlign, parsed_value.release_nonnull());
}
});
}
void HTMLTableRowElement::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_cells);
}
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-cells
GC::Ref<DOM::HTMLCollection> HTMLTableRowElement::cells() const
{
// The cells attribute must return an HTMLCollection rooted at this tr element,
// whose filter matches only td and th elements that are children of the tr element.
if (!m_cells) {
m_cells = DOM::HTMLCollection::create(const_cast<HTMLTableRowElement&>(*this), DOM::HTMLCollection::Scope::Children, [](Element const& element) {
return is<HTMLTableCellElement>(element);
});
}
return *m_cells;
}
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-rowindex
int HTMLTableRowElement::row_index() const
{
// The rowIndex attribute must, if this element has a parent table element,
// or a parent tbody, thead, or tfoot element and a grandparent table element,
// return the index of this tr element in that table element's rows collection.
// If there is no such table element, then the attribute must return −1.
auto rows_collection = [&]() -> GC::Ptr<DOM::HTMLCollection> {
if (!parent())
return nullptr;
if (is<HTMLTableElement>(*parent()))
return const_cast<HTMLTableElement&>(static_cast<HTMLTableElement const&>(*parent())).rows();
if (is<HTMLTableSectionElement>(*parent()) && parent()->parent() && is<HTMLTableElement>(*parent()->parent()))
return const_cast<HTMLTableElement&>(static_cast<HTMLTableElement const&>(*parent()->parent())).rows();
return nullptr;
}();
if (!rows_collection)
return -1;
auto rows = rows_collection->collect_matching_elements();
for (size_t i = 0; i < rows.size(); ++i) {
if (rows[i] == this)
return i;
}
return -1;
}
int HTMLTableRowElement::section_row_index() const
{
// The sectionRowIndex attribute must, if this element has a parent table, tbody, thead, or tfoot element,
// return the index of the tr element in the parent element's rows collection
// (for tables, that's HTMLTableElement's rows collection; for table sections, that's HTMLTableSectionElement's rows collection).
// If there is no such parent element, then the attribute must return −1.
auto rows_collection = [&]() -> GC::Ptr<DOM::HTMLCollection> {
if (!parent())
return nullptr;
if (is<HTMLTableElement>(*parent()))
return const_cast<HTMLTableElement&>(static_cast<HTMLTableElement const&>(*parent())).rows();
if (is<HTMLTableSectionElement>(*parent()))
return static_cast<HTMLTableSectionElement const&>(*parent()).rows();
return nullptr;
}();
if (!rows_collection)
return -1;
auto rows = rows_collection->collect_matching_elements();
for (size_t i = 0; i < rows.size(); ++i) {
if (rows[i] == this)
return i;
}
return -1;
}
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-insertcell
WebIDL::ExceptionOr<GC::Ref<HTMLTableCellElement>> HTMLTableRowElement::insert_cell(i32 index)
{
auto cells_collection = cells();
auto cells_collection_size = static_cast<i32>(cells_collection->length());
// 1. If index is less than −1 or greater than the number of elements in the cells collection, then throw an "IndexSizeError" DOMException.
if (index < -1 || index > cells_collection_size)
return WebIDL::IndexSizeError::create(realm(), "Index is negative or greater than the number of cells"_utf16);
// 2. Let table cell be the result of creating an element given this tr element's node document, "td", and the HTML namespace.
auto& table_cell = static_cast<HTMLTableCellElement&>(*TRY(DOM::create_element(document(), HTML::TagNames::td, Namespace::HTML)));
// 3. If index is equal to −1 or equal to the number of items in cells collection, then append table cell to this tr element.
if (index == -1 || index == cells_collection_size)
TRY(append_child(table_cell));
// 4. Otherwise, insert table cell as a child of this tr element, immediately before the indexth td or th element in the cells collection.
else
insert_before(table_cell, cells_collection->item(index));
// 5. Return table cell.
return GC::Ref(table_cell);
}
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-deletecell
WebIDL::ExceptionOr<void> HTMLTableRowElement::delete_cell(i32 index)
{
auto cells_collection = cells();
auto cells_collection_size = static_cast<i32>(cells_collection->length());
// 1. If index is less than −1 or greater than or equal to the number of elements in the cells collection, then throw an "IndexSizeError" DOMException.
if (index < -1 || index >= cells_collection_size)
return WebIDL::IndexSizeError::create(realm(), "Index is negative or greater than or equal to the number of cells"_utf16);
// 2. If index is −1, then remove the last element in the cells collection from its parent, or do nothing if the cells collection is empty.
if (index == -1) {
if (cells_collection_size > 0)
cells_collection->item(cells_collection_size - 1)->remove();
}
// 3. Otherwise, remove the indexth element in the cells collection from its parent.
else {
cells_collection->item(index)->remove();
}
return {};
}
}