HTMLTableElement.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/CSS/Parser/DeprecatedCSSParser.h>
  7. #include <LibWeb/DOM/ElementFactory.h>
  8. #include <LibWeb/DOM/HTMLCollection.h>
  9. #include <LibWeb/HTML/HTMLTableElement.h>
  10. #include <LibWeb/HTML/HTMLTableRowElement.h>
  11. #include <LibWeb/Namespace.h>
  12. namespace Web::HTML {
  13. HTMLTableElement::HTMLTableElement(DOM::Document& document, QualifiedName qualified_name)
  14. : HTMLElement(document, move(qualified_name))
  15. {
  16. }
  17. HTMLTableElement::~HTMLTableElement()
  18. {
  19. }
  20. void HTMLTableElement::apply_presentational_hints(CSS::StyleProperties& style) const
  21. {
  22. for_each_attribute([&](auto& name, auto& value) {
  23. if (name == HTML::AttributeNames::width) {
  24. if (auto parsed_value = parse_html_length(document(), value))
  25. style.set_property(CSS::PropertyID::Width, parsed_value.release_nonnull());
  26. return;
  27. }
  28. if (name == HTML::AttributeNames::height) {
  29. if (auto parsed_value = parse_html_length(document(), value))
  30. style.set_property(CSS::PropertyID::Height, parsed_value.release_nonnull());
  31. return;
  32. }
  33. if (name == HTML::AttributeNames::bgcolor) {
  34. auto color = Color::from_string(value);
  35. if (color.has_value())
  36. style.set_property(CSS::PropertyID::BackgroundColor, CSS::ColorStyleValue::create(color.value()));
  37. return;
  38. }
  39. });
  40. }
  41. RefPtr<HTMLTableCaptionElement> HTMLTableElement::caption()
  42. {
  43. return first_child_of_type<HTMLTableCaptionElement>();
  44. }
  45. void HTMLTableElement::set_caption(HTMLTableCaptionElement& caption)
  46. {
  47. // FIXME: The spec requires deleting the current caption if caption is null
  48. // Currently the wrapper generator doesn't send us a nullable value
  49. delete_caption();
  50. pre_insert(caption, first_child());
  51. }
  52. NonnullRefPtr<HTMLTableCaptionElement> HTMLTableElement::create_caption()
  53. {
  54. auto maybe_caption = caption();
  55. if (maybe_caption) {
  56. return *maybe_caption;
  57. }
  58. auto caption = DOM::create_element(document(), TagNames::caption, Namespace::HTML);
  59. pre_insert(caption, first_child());
  60. return caption;
  61. }
  62. void HTMLTableElement::delete_caption()
  63. {
  64. auto maybe_caption = caption();
  65. if (maybe_caption) {
  66. maybe_caption->remove(false);
  67. }
  68. }
  69. NonnullRefPtr<DOM::HTMLCollection> HTMLTableElement::rows()
  70. {
  71. HTMLTableElement* table_node = this;
  72. // FIXME: The elements in the collection must be ordered such that those elements whose parent is a thead are
  73. // included first, in tree order, followed by those elements whose parent is either a table or tbody
  74. // element, again in tree order, followed finally by those elements whose parent is a tfoot element,
  75. // still in tree order.
  76. // How do you sort HTMLCollection?
  77. return DOM::HTMLCollection::create(*this, [table_node](DOM::Element const& element) {
  78. // Only match TR elements which are:
  79. // * children of the table element
  80. // * children of the thead, tbody, or tfoot elements that are themselves children of the table element
  81. if (!is<HTMLTableRowElement>(element)) {
  82. return false;
  83. }
  84. if (element.parent_element() == table_node)
  85. return true;
  86. if (element.parent_element() && (element.parent_element()->tag_name() == TagNames::thead || element.parent_element()->tag_name() == TagNames::tbody || element.parent_element()->tag_name() == TagNames::tfoot)
  87. && element.parent()->parent() == table_node) {
  88. return true;
  89. }
  90. return false;
  91. });
  92. }
  93. DOM::ExceptionOr<NonnullRefPtr<HTMLTableRowElement>> HTMLTableElement::insert_row(long index)
  94. {
  95. auto rows = this->rows();
  96. auto rows_length = rows->length();
  97. if (index < -1 || index >= (long)rows_length) {
  98. return DOM::IndexSizeError::create("Index is negative or greater than the number of rows");
  99. }
  100. auto tr = static_cast<NonnullRefPtr<HTMLTableRowElement>>(DOM::create_element(document(), TagNames::tr, Namespace::HTML));
  101. if (rows_length == 0 && !has_child_of_type<HTMLTableRowElement>()) {
  102. auto tbody = DOM::create_element(document(), TagNames::tbody, Namespace::HTML);
  103. tbody->append_child(tr);
  104. append_child(tbody);
  105. } else if (rows_length == 0) {
  106. auto tbody = last_child_of_type<HTMLTableRowElement>();
  107. tbody->append_child(tr);
  108. } else if (index == -1 || index == (long)rows_length) {
  109. auto parent_of_last_tr = rows->item(rows_length - 1)->parent_element();
  110. parent_of_last_tr->append_child(tr);
  111. } else {
  112. rows->item(index)->parent_element()->insert_before(tr, rows->item(index));
  113. }
  114. return tr;
  115. }
  116. DOM::ExceptionOr<void> HTMLTableElement::delete_row(long index)
  117. {
  118. auto rows = this->rows();
  119. auto rows_length = rows->length();
  120. if (index < -1 || index >= (long)rows_length) {
  121. return DOM::IndexSizeError::create("Index is negative or greater than the number of rows");
  122. }
  123. if (index == -1 && rows_length > 0) {
  124. auto row_to_remove = rows->item(rows_length - 1);
  125. row_to_remove->remove(false);
  126. } else {
  127. auto row_to_remove = rows->item(index);
  128. row_to_remove->remove(false);
  129. }
  130. return {};
  131. }
  132. }