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::{
23    CustomElementCreationMode, Element, ElementCreator, LayoutElementHelpers,
24};
25use crate::dom::html::htmlcollection::HTMLCollection;
26use crate::dom::html::htmlelement::HTMLElement;
27use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
28use crate::dom::html::htmltableelement::HTMLTableElement;
29use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
30use crate::dom::node::{Node, NodeTraits};
31use crate::dom::virtualmethods::VirtualMethods;
32use crate::script_runtime::CanGc;
33
34#[dom_struct]
35pub(crate) struct HTMLTableRowElement {
36    htmlelement: HTMLElement,
37    cells: MutNullableDom<HTMLCollection>,
38}
39
40impl HTMLTableRowElement {
41    fn new_inherited(
42        local_name: LocalName,
43        prefix: Option<Prefix>,
44        document: &Document,
45    ) -> HTMLTableRowElement {
46        HTMLTableRowElement {
47            htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
48            cells: Default::default(),
49        }
50    }
51
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, cx: &mut JSContext, index: i32) -> Fallible<DomRoot<HTMLElement>> {
106        let node = self.upcast::<Node>();
107        node.insert_cell_or_row(
108            cx,
109            index,
110            || self.Cells(),
111            |cx| {
112                let cell = Element::create(
113                    QualName::new(None, ns!(html), local_name!("td")),
114                    None,
115                    &node.owner_doc(),
116                    ElementCreator::ScriptCreated,
117                    CustomElementCreationMode::Asynchronous,
118                    None,
119                    CanGc::from_cx(cx),
120                );
121                DomRoot::downcast::<HTMLTableCellElement>(cell).unwrap()
122            },
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}