script/dom/html/
htmltablerowelement.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, QualName, local_name, ns};
7use js::rust::HandleObject;
8use style::attr::{AttrValue, LengthOrPercentageOrAuto};
9use style::color::AbsoluteColor;
10
11use crate::dom::attr::Attr;
12use crate::dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods;
13use crate::dom::bindings::codegen::Bindings::HTMLTableRowElementBinding::HTMLTableRowElementMethods;
14use crate::dom::bindings::codegen::Bindings::HTMLTableSectionElementBinding::HTMLTableSectionElementMethods;
15use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
16use crate::dom::bindings::error::{ErrorResult, Fallible};
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
19use crate::dom::bindings::str::DOMString;
20use crate::dom::document::Document;
21use crate::dom::element::{
22    CustomElementCreationMode, Element, ElementCreator, LayoutElementHelpers,
23};
24use crate::dom::html::htmlcollection::HTMLCollection;
25use crate::dom::html::htmlelement::HTMLElement;
26use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
27use crate::dom::html::htmltableelement::HTMLTableElement;
28use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
29use crate::dom::node::{Node, NodeTraits};
30use crate::dom::virtualmethods::VirtualMethods;
31use crate::script_runtime::CanGc;
32
33#[dom_struct]
34pub(crate) struct HTMLTableRowElement {
35    htmlelement: HTMLElement,
36    cells: MutNullableDom<HTMLCollection>,
37}
38
39impl HTMLTableRowElement {
40    fn new_inherited(
41        local_name: LocalName,
42        prefix: Option<Prefix>,
43        document: &Document,
44    ) -> HTMLTableRowElement {
45        HTMLTableRowElement {
46            htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
47            cells: Default::default(),
48        }
49    }
50
51    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
52    pub(crate) fn new(
53        local_name: LocalName,
54        prefix: Option<Prefix>,
55        document: &Document,
56        proto: Option<HandleObject>,
57        can_gc: CanGc,
58    ) -> DomRoot<HTMLTableRowElement> {
59        let n = Node::reflect_node_with_proto(
60            Box::new(HTMLTableRowElement::new_inherited(
61                local_name, prefix, document,
62            )),
63            document,
64            proto,
65            can_gc,
66        );
67
68        n.upcast::<Node>().set_weird_parser_insertion_mode();
69        n
70    }
71
72    /// Determine the index for this `HTMLTableRowElement` within the given
73    /// `HTMLCollection`. Returns `-1` if not found within collection.
74    fn row_index(&self, collection: DomRoot<HTMLCollection>) -> i32 {
75        collection
76            .elements_iter()
77            .position(|elem| (&elem as &Element) == self.upcast())
78            .map_or(-1, |i| i as i32)
79    }
80}
81
82impl HTMLTableRowElementMethods<crate::DomTypeHolder> for HTMLTableRowElement {
83    // https://html.spec.whatwg.org/multipage/#dom-tr-bgcolor
84    make_getter!(BgColor, "bgcolor");
85
86    // https://html.spec.whatwg.org/multipage/#dom-tr-bgcolor
87    make_legacy_color_setter!(SetBgColor, "bgcolor");
88
89    // https://html.spec.whatwg.org/multipage/#dom-tr-cells
90    fn Cells(&self) -> DomRoot<HTMLCollection> {
91        self.cells.or_init(|| {
92            HTMLCollection::new_with_filter_fn(
93                &self.owner_window(),
94                self.upcast(),
95                |element, root| {
96                    (element.is::<HTMLTableCellElement>()) &&
97                        element.upcast::<Node>().GetParentNode().as_deref() == Some(root)
98                },
99                CanGc::note(),
100            )
101        })
102    }
103
104    // https://html.spec.whatwg.org/multipage/#dom-tr-insertcell
105    fn InsertCell(&self, index: i32, can_gc: CanGc) -> Fallible<DomRoot<HTMLElement>> {
106        let node = self.upcast::<Node>();
107        node.insert_cell_or_row(
108            index,
109            || self.Cells(),
110            || {
111                let cell = Element::create(
112                    QualName::new(None, ns!(html), local_name!("td")),
113                    None,
114                    &node.owner_doc(),
115                    ElementCreator::ScriptCreated,
116                    CustomElementCreationMode::Asynchronous,
117                    None,
118                    can_gc,
119                );
120                DomRoot::downcast::<HTMLTableCellElement>(cell).unwrap()
121            },
122            can_gc,
123        )
124    }
125
126    // https://html.spec.whatwg.org/multipage/#dom-tr-deletecell
127    fn DeleteCell(&self, index: i32) -> ErrorResult {
128        let node = self.upcast::<Node>();
129        node.delete_cell_or_row(
130            index,
131            || self.Cells(),
132            |n| n.is::<HTMLTableCellElement>(),
133            CanGc::note(),
134        )
135    }
136
137    // https://html.spec.whatwg.org/multipage/#dom-tr-rowindex
138    fn RowIndex(&self) -> i32 {
139        let parent = match self.upcast::<Node>().GetParentNode() {
140            Some(parent) => parent,
141            None => return -1,
142        };
143        if let Some(table) = parent.downcast::<HTMLTableElement>() {
144            return self.row_index(table.Rows());
145        }
146        if !parent.is::<HTMLTableSectionElement>() {
147            return -1;
148        }
149        let grandparent = match parent.upcast::<Node>().GetParentNode() {
150            Some(parent) => parent,
151            None => return -1,
152        };
153        grandparent
154            .downcast::<HTMLTableElement>()
155            .map_or(-1, |table| self.row_index(table.Rows()))
156    }
157
158    // https://html.spec.whatwg.org/multipage/#dom-tr-sectionrowindex
159    fn SectionRowIndex(&self) -> i32 {
160        let parent = match self.upcast::<Node>().GetParentNode() {
161            Some(parent) => parent,
162            None => return -1,
163        };
164        let collection = if let Some(table) = parent.downcast::<HTMLTableElement>() {
165            table.Rows()
166        } else if let Some(table_section) = parent.downcast::<HTMLTableSectionElement>() {
167            table_section.Rows()
168        } else {
169            return -1;
170        };
171        self.row_index(collection)
172    }
173}
174
175pub(crate) trait HTMLTableRowElementLayoutHelpers {
176    fn get_background_color(self) -> Option<AbsoluteColor>;
177    fn get_height(self) -> LengthOrPercentageOrAuto;
178}
179
180impl HTMLTableRowElementLayoutHelpers for LayoutDom<'_, HTMLTableRowElement> {
181    fn get_background_color(self) -> Option<AbsoluteColor> {
182        self.upcast::<Element>()
183            .get_attr_for_layout(&ns!(), &local_name!("bgcolor"))
184            .and_then(AttrValue::as_color)
185            .cloned()
186    }
187
188    fn get_height(self) -> LengthOrPercentageOrAuto {
189        self.upcast::<Element>()
190            .get_attr_for_layout(&ns!(), &local_name!("height"))
191            .map(AttrValue::as_dimension)
192            .cloned()
193            .unwrap_or(LengthOrPercentageOrAuto::Auto)
194    }
195}
196
197impl VirtualMethods for HTMLTableRowElement {
198    fn super_type(&self) -> Option<&dyn VirtualMethods> {
199        Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
200    }
201
202    fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
203        match attr.local_name() {
204            &local_name!("height") => true,
205            _ => self
206                .super_type()
207                .unwrap()
208                .attribute_affects_presentational_hints(attr),
209        }
210    }
211
212    fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
213        match *local_name {
214            local_name!("bgcolor") => AttrValue::from_legacy_color(value.into()),
215            local_name!("height") => AttrValue::from_dimension(value.into()),
216            _ => self
217                .super_type()
218                .unwrap()
219                .parse_plain_attribute(local_name, value),
220        }
221    }
222}