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