Skip to content

Commit

Permalink
Implement the table section IDL attributes for HTML tables
Browse files Browse the repository at this point in the history
  • Loading branch information
yoava333 committed Apr 12, 2016
1 parent dfb482a commit 5e3dcae
Show file tree
Hide file tree
Showing 9 changed files with 285 additions and 66 deletions.
147 changes: 146 additions & 1 deletion components/script/dom/htmltableelement.rs
Expand Up @@ -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};
Expand All @@ -28,6 +30,7 @@ pub struct HTMLTableElement {
htmlelement: HTMLElement,
border: Cell<Option<u32>>,
cellspacing: Cell<Option<u32>>,
tbodies: MutNullableHeap<JS<HTMLCollection>>,
}

impl HTMLTableElement {
Expand All @@ -37,6 +40,7 @@ impl HTMLTableElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
border: Cell::new(None),
cellspacing: Cell::new(None),
tbodies: Default::default(),
}
}

Expand All @@ -50,6 +54,70 @@ impl HTMLTableElement {
pub fn get_border(&self) -> Option<u32> {
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<Root<HTMLTableSectionElement>> {
self.upcast::<Node>()
.child_elements()
.find(|n| n.is::<HTMLTableSectionElement>() && 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<P>(&self,
atom: &Atom,
section: Option<&HTMLTableSectionElement>,
reference_predicate: P)
-> ErrorResult
where P: FnMut(&Root<Element>) -> bool {
if let Some(e) = section {
if e.upcast::<Element>().local_name() != atom {
return Err(Error::HierarchyRequest)
}
}

self.delete_first_section_of_type(atom);

let node = self.upcast::<Node>();

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<HTMLTableSectionElement> {
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(&section)),
&atom!("tfoot") => self.SetTFoot(Some(&section)),
_ => 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::<Node>().remove_self();
}
}
}

impl HTMLTableElementMethods for HTMLTableElement {
Expand Down Expand Up @@ -119,6 +187,83 @@ impl HTMLTableElementMethods for HTMLTableElement {
}
}


// https://html.spec.whatwg.org/multipage/#dom-table-thead
fn GetTHead(&self) -> Option<Root<HTMLTableSectionElement>> {
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::<HTMLTableCaptionElement>() && !n.is::<HTMLTableColElement>()
})
}

// https://html.spec.whatwg.org/multipage/#dom-table-createthead
fn CreateTHead(&self) -> Root<HTMLTableSectionElement> {
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<Root<HTMLTableSectionElement>> {
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::<HTMLTableCaptionElement>() || n.is::<HTMLTableColElement>() {
return false;
}

if n.is::<HTMLTableSectionElement>() {
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<HTMLTableSectionElement> {
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<HTMLCollection> {
#[derive(JSTraceable)]
struct TBodiesFilter;
impl CollectionFilter for TBodiesFilter {
fn filter(&self, elem: &Element, root: &Node) -> bool {
elem.is::<HTMLTableSectionElement>()
&& elem.local_name() == &atom!("tbody")
&& elem.upcast::<Node>().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<HTMLTableSectionElement> {
let tbody = HTMLTableSectionElement::new(atom!("tbody"),
Expand Down
16 changes: 9 additions & 7 deletions components/script/dom/webidls/HTMLTableElement.webidl
Expand Up @@ -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);
Expand Down
17 changes: 16 additions & 1 deletion tests/wpt/metadata/MANIFEST.json
Expand Up @@ -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": {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

42 changes: 0 additions & 42 deletions tests/wpt/metadata/html/dom/interfaces.html.ini
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
@@ -0,0 +1,48 @@
<!doctype html>
<meta charset="utf-8">
<title>tFoot tests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<table id="t">
<caption id="tcaption"></caption><thead id="thead"></thead><tbody id="tbody1"></tbody><tbody id="tbody2"></tbody><tfoot id="tfoot1"></tfoot><tfoot id="tfoot2"></tfoot><tfoot id="tfoot3"></tfoot></table>
<script>
test(function() {
var t = document.getElementById("t");
var tfoot1 = document.getElementById("tfoot1");

assert_equals(t.tFoot, tfoot1);

var tfoot2 = document.getElementById("tfoot2");
t.tFoot = null;

assert_equals(t.tFoot, tfoot2);

var tfoot3 = document.getElementById("tfoot3");
t.deleteTFoot();

assert_equals(t.tFoot, tfoot3);

var tfoot = t.createTFoot();
assert_equals(t.tFoot, tfoot);
assert_equals(tfoot, tfoot3);

t.deleteTFoot();
assert_equals(t.tFoot, null);

var tbody2 = document.getElementById("tbody2");

tfoot = t.createTFoot();
assert_equals(t.tFoot, tfoot);

assert_equals(t.tFoot.previousSibling, tbody2);
assert_equals(t.tFoot.nextSibling, null);

assert_throws(new TypeError(), function(){
t.tFoot = document.createElement("div");
});

assert_throws("HierarchyRequestError", function(){
t.tFoot = document.createElement("thead");
});
})
</script>

0 comments on commit 5e3dcae

Please sign in to comment.