diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index ab611716b900..4ea908675b1e 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -7,13 +7,15 @@ use dom::attr::{Attr, AttrValue}; use dom::bindings::codegen::Bindings::HTMLTableElementBinding; use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::inheritance::Castable; -use dom::bindings::js::{JS, LayoutJS, Root, RootedReference}; +use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root, RootedReference}; use dom::document::Document; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use dom::htmlcollection::{CollectionFilter, HTMLCollection}; use dom::htmlelement::HTMLElement; use dom::htmltablecaptionelement::HTMLTableCaptionElement; +use dom::htmltablecolelement::HTMLTableColElement; use dom::htmltablerowelement::HTMLTableRowElement; use dom::htmltablesectionelement::HTMLTableSectionElement; use dom::node::{Node, document_from_node, window_from_node}; @@ -28,6 +30,7 @@ pub struct HTMLTableElement { htmlelement: HTMLElement, border: Cell>, cellspacing: Cell>, + tbodies: MutNullableHeap>, } impl HTMLTableElement { @@ -37,6 +40,7 @@ impl HTMLTableElement { htmlelement: HTMLElement::new_inherited(localName, prefix, document), border: Cell::new(None), cellspacing: Cell::new(None), + tbodies: Default::default(), } } @@ -50,6 +54,70 @@ impl HTMLTableElement { pub fn get_border(&self) -> Option { self.border.get() } + + // https://html.spec.whatwg.org/multipage/#dom-table-thead + // https://html.spec.whatwg.org/multipage/#dom-table-tfoot + fn get_first_section_of_type(&self, atom: &Atom) -> Option> { + self.upcast::() + .child_elements() + .find(|n| n.is::() && n.local_name() == atom) + .and_then(|n| n.downcast().map(Root::from_ref)) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-thead + // https://html.spec.whatwg.org/multipage/#dom-table-tfoot + fn set_first_section_of_type

(&self, + atom: &Atom, + section: Option<&HTMLTableSectionElement>, + reference_predicate: P) + -> ErrorResult + where P: FnMut(&Root) -> bool { + if let Some(e) = section { + if e.upcast::().local_name() != atom { + return Err(Error::HierarchyRequest) + } + } + + self.delete_first_section_of_type(atom); + + let node = self.upcast::(); + + if let Some(section) = section { + let reference_element = node.child_elements().find(reference_predicate); + let reference_node = reference_element.r().map(|e| e.upcast()); + + try!(node.InsertBefore(section.upcast(), reference_node)); + } + + Ok(()) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-createthead + // https://html.spec.whatwg.org/multipage/#dom-table-createtfoot + fn create_section_of_type(&self, atom: &Atom) -> Root { + if let Some(section) = self.get_first_section_of_type(atom) { + return section + } + + let section = HTMLTableSectionElement::new(atom.clone(), + None, + document_from_node(self).r()); + match atom { + &atom!("thead") => self.SetTHead(Some(§ion)), + &atom!("tfoot") => self.SetTFoot(Some(§ion)), + _ => unreachable!("unexpected section type") + }.expect("unexpected section type"); + + section + } + + // https://html.spec.whatwg.org/multipage/#dom-table-deletethead + // https://html.spec.whatwg.org/multipage/#dom-table-deletetfoot + fn delete_first_section_of_type(&self, atom: &Atom) { + if let Some(thead) = self.get_first_section_of_type(atom) { + thead.upcast::().remove_self(); + } + } } impl HTMLTableElementMethods for HTMLTableElement { @@ -119,6 +187,83 @@ impl HTMLTableElementMethods for HTMLTableElement { } } + + // https://html.spec.whatwg.org/multipage/#dom-table-thead + fn GetTHead(&self) -> Option> { + self.get_first_section_of_type(&atom!("thead")) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-thead + fn SetTHead(&self, thead: Option<&HTMLTableSectionElement>) -> ErrorResult { + self.set_first_section_of_type(&atom!("thead"), thead, |n| { + !n.is::() && !n.is::() + }) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-createthead + fn CreateTHead(&self) -> Root { + self.create_section_of_type(&atom!("thead")) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-deletethead + fn DeleteTHead(&self) { + self.delete_first_section_of_type(&atom!("thead")) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-tfoot + fn GetTFoot(&self) -> Option> { + self.get_first_section_of_type(&atom!("tfoot")) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-tfoot + fn SetTFoot(&self, tfoot: Option<&HTMLTableSectionElement>) -> ErrorResult { + self.set_first_section_of_type(&atom!("tfoot"), tfoot, |n| { + if n.is::() || n.is::() { + return false; + } + + if n.is::() { + let name = n.local_name(); + if name == &atom!("thead") || name == &atom!("tbody") { + return false; + } + + } + + true + }) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-createtfoot + fn CreateTFoot(&self) -> Root { + self.create_section_of_type(&atom!("tfoot")) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-deletetfoot + fn DeleteTFoot(&self) { + self.delete_first_section_of_type(&atom!("tfoot")) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-tbodies + fn TBodies(&self) -> Root { + #[derive(JSTraceable)] + struct TBodiesFilter; + impl CollectionFilter for TBodiesFilter { + fn filter(&self, elem: &Element, root: &Node) -> bool { + elem.is::() + && elem.local_name() == &atom!("tbody") + && elem.upcast::().GetParentNode().r() == Some(root) + } + } + + self.tbodies.or_init(|| { + let window = window_from_node(self); + let filter = box TBodiesFilter; + HTMLCollection::create(window.r(), self.upcast(), filter) + }) + } + + // https://html.spec.whatwg.org/multipage/#dom-table-createtbody fn CreateTBody(&self) -> Root { let tbody = HTMLTableSectionElement::new(atom!("tbody"), diff --git a/components/script/dom/webidls/HTMLTableElement.webidl b/components/script/dom/webidls/HTMLTableElement.webidl index 2697f4c1e931..af95685b5b59 100644 --- a/components/script/dom/webidls/HTMLTableElement.webidl +++ b/components/script/dom/webidls/HTMLTableElement.webidl @@ -8,13 +8,15 @@ interface HTMLTableElement : HTMLElement { attribute HTMLTableCaptionElement? caption; HTMLElement createCaption(); void deleteCaption(); - // attribute HTMLTableSectionElement? tHead; - //HTMLElement createTHead(); - //void deleteTHead(); - // attribute HTMLTableSectionElement? tFoot; - //HTMLElement createTFoot(); - //void deleteTFoot(); - //readonly attribute HTMLCollection tBodies; + [SetterThrows] + attribute HTMLTableSectionElement? tHead; + HTMLTableSectionElement createTHead(); + void deleteTHead(); + [SetterThrows] + attribute HTMLTableSectionElement? tFoot; + HTMLTableSectionElement createTFoot(); + void deleteTFoot(); + readonly attribute HTMLCollection tBodies; HTMLTableSectionElement createTBody(); readonly attribute HTMLCollection rows; //HTMLElement insertRow(optional long index = -1); diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 02e777e3aa77..213cb9b5e5c0 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -35059,7 +35059,22 @@ }, "local_changes": { "deleted": [], - "items": {}, + "items": { + "testharness": { + "html/semantics/tabular-data/the-table-element/tFoot.html": [ + { + "path": "html/semantics/tabular-data/the-table-element/tFoot.html", + "url": "/html/semantics/tabular-data/the-table-element/tFoot.html" + } + ], + "html/semantics/tabular-data/the-table-element/tHead.html": [ + { + "path": "html/semantics/tabular-data/the-table-element/tHead.html", + "url": "/html/semantics/tabular-data/the-table-element/tHead.html" + } + ] + } + }, "reftest_nodes": {} }, "reftest_nodes": { diff --git a/tests/wpt/metadata/dom/nodes/getElementsByClassName-20.htm.ini b/tests/wpt/metadata/dom/nodes/getElementsByClassName-20.htm.ini deleted file mode 100644 index b3ae75b2960a..000000000000 --- a/tests/wpt/metadata/dom/nodes/getElementsByClassName-20.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[getElementsByClassName-20.htm] - type: testharness - [get elements in document then add element to collection] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/getElementsByClassName-22.htm.ini b/tests/wpt/metadata/dom/nodes/getElementsByClassName-22.htm.ini deleted file mode 100644 index edb0b18eec8b..000000000000 --- a/tests/wpt/metadata/dom/nodes/getElementsByClassName-22.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[getElementsByClassName-22.htm] - type: testharness - [move item in collection order] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/getElementsByClassName-25.htm.ini b/tests/wpt/metadata/dom/nodes/getElementsByClassName-25.htm.ini deleted file mode 100644 index b75ced052c31..000000000000 --- a/tests/wpt/metadata/dom/nodes/getElementsByClassName-25.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[getElementsByClassName-25.htm] - type: testharness - [verify spacing is handled correctly] - expected: FAIL - diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index ba5f8cadb8f0..9b2d7668ea7f 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -4152,27 +4152,6 @@ [HTMLAreaElement interface: document.createElement("area") must inherit property "noHref" with the proper type (10)] expected: FAIL - [HTMLTableElement interface: attribute tHead] - expected: FAIL - - [HTMLTableElement interface: operation createTHead()] - expected: FAIL - - [HTMLTableElement interface: operation deleteTHead()] - expected: FAIL - - [HTMLTableElement interface: attribute tFoot] - expected: FAIL - - [HTMLTableElement interface: operation createTFoot()] - expected: FAIL - - [HTMLTableElement interface: operation deleteTFoot()] - expected: FAIL - - [HTMLTableElement interface: attribute tBodies] - expected: FAIL - [HTMLTableElement interface: operation insertRow(long)] expected: FAIL @@ -4206,27 +4185,6 @@ [HTMLTableElement interface: attribute cellSpacing] expected: FAIL - [HTMLTableElement interface: document.createElement("table") must inherit property "tHead" with the proper type (3)] - expected: FAIL - - [HTMLTableElement interface: document.createElement("table") must inherit property "createTHead" with the proper type (4)] - expected: FAIL - - [HTMLTableElement interface: document.createElement("table") must inherit property "deleteTHead" with the proper type (5)] - expected: FAIL - - [HTMLTableElement interface: document.createElement("table") must inherit property "tFoot" with the proper type (6)] - expected: FAIL - - [HTMLTableElement interface: document.createElement("table") must inherit property "createTFoot" with the proper type (7)] - expected: FAIL - - [HTMLTableElement interface: document.createElement("table") must inherit property "deleteTFoot" with the proper type (8)] - expected: FAIL - - [HTMLTableElement interface: document.createElement("table") must inherit property "tBodies" with the proper type (9)] - expected: FAIL - [HTMLTableElement interface: document.createElement("table") must inherit property "insertRow" with the proper type (12)] expected: FAIL diff --git a/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/tFoot.html b/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/tFoot.html new file mode 100644 index 000000000000..52c6972fefd0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/tFoot.html @@ -0,0 +1,48 @@ + + +tFoot tests + + + +
+ diff --git a/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/tHead.html b/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/tHead.html new file mode 100644 index 000000000000..ea2ebf1281da --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/tHead.html @@ -0,0 +1,66 @@ + + +tHead tests + + + + +
+ + +
+ +
+
+