mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Implement the table section IDL attributes for HTML tables
This commit is contained in:
parent
dfb482a2b7
commit
5e3dcae71f
9 changed files with 285 additions and 66 deletions
|
@ -7,13 +7,15 @@ use dom::attr::{Attr, AttrValue};
|
||||||
use dom::bindings::codegen::Bindings::HTMLTableElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLTableElementBinding;
|
||||||
use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods;
|
||||||
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||||
|
use dom::bindings::error::{Error, ErrorResult};
|
||||||
use dom::bindings::inheritance::Castable;
|
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::document::Document;
|
||||||
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
|
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
|
||||||
use dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
use dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmltablecaptionelement::HTMLTableCaptionElement;
|
use dom::htmltablecaptionelement::HTMLTableCaptionElement;
|
||||||
|
use dom::htmltablecolelement::HTMLTableColElement;
|
||||||
use dom::htmltablerowelement::HTMLTableRowElement;
|
use dom::htmltablerowelement::HTMLTableRowElement;
|
||||||
use dom::htmltablesectionelement::HTMLTableSectionElement;
|
use dom::htmltablesectionelement::HTMLTableSectionElement;
|
||||||
use dom::node::{Node, document_from_node, window_from_node};
|
use dom::node::{Node, document_from_node, window_from_node};
|
||||||
|
@ -28,6 +30,7 @@ pub struct HTMLTableElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
border: Cell<Option<u32>>,
|
border: Cell<Option<u32>>,
|
||||||
cellspacing: Cell<Option<u32>>,
|
cellspacing: Cell<Option<u32>>,
|
||||||
|
tbodies: MutNullableHeap<JS<HTMLCollection>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableElement {
|
impl HTMLTableElement {
|
||||||
|
@ -37,6 +40,7 @@ impl HTMLTableElement {
|
||||||
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
|
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
|
||||||
border: Cell::new(None),
|
border: Cell::new(None),
|
||||||
cellspacing: Cell::new(None),
|
cellspacing: Cell::new(None),
|
||||||
|
tbodies: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +54,70 @@ impl HTMLTableElement {
|
||||||
pub fn get_border(&self) -> Option<u32> {
|
pub fn get_border(&self) -> Option<u32> {
|
||||||
self.border.get()
|
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(§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::<Node>().remove_self();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableElementMethods for HTMLTableElement {
|
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<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
|
// https://html.spec.whatwg.org/multipage/#dom-table-createtbody
|
||||||
fn CreateTBody(&self) -> Root<HTMLTableSectionElement> {
|
fn CreateTBody(&self) -> Root<HTMLTableSectionElement> {
|
||||||
let tbody = HTMLTableSectionElement::new(atom!("tbody"),
|
let tbody = HTMLTableSectionElement::new(atom!("tbody"),
|
||||||
|
|
|
@ -8,13 +8,15 @@ interface HTMLTableElement : HTMLElement {
|
||||||
attribute HTMLTableCaptionElement? caption;
|
attribute HTMLTableCaptionElement? caption;
|
||||||
HTMLElement createCaption();
|
HTMLElement createCaption();
|
||||||
void deleteCaption();
|
void deleteCaption();
|
||||||
// attribute HTMLTableSectionElement? tHead;
|
[SetterThrows]
|
||||||
//HTMLElement createTHead();
|
attribute HTMLTableSectionElement? tHead;
|
||||||
//void deleteTHead();
|
HTMLTableSectionElement createTHead();
|
||||||
// attribute HTMLTableSectionElement? tFoot;
|
void deleteTHead();
|
||||||
//HTMLElement createTFoot();
|
[SetterThrows]
|
||||||
//void deleteTFoot();
|
attribute HTMLTableSectionElement? tFoot;
|
||||||
//readonly attribute HTMLCollection tBodies;
|
HTMLTableSectionElement createTFoot();
|
||||||
|
void deleteTFoot();
|
||||||
|
readonly attribute HTMLCollection tBodies;
|
||||||
HTMLTableSectionElement createTBody();
|
HTMLTableSectionElement createTBody();
|
||||||
readonly attribute HTMLCollection rows;
|
readonly attribute HTMLCollection rows;
|
||||||
//HTMLElement insertRow(optional long index = -1);
|
//HTMLElement insertRow(optional long index = -1);
|
||||||
|
|
|
@ -35059,7 +35059,22 @@
|
||||||
},
|
},
|
||||||
"local_changes": {
|
"local_changes": {
|
||||||
"deleted": [],
|
"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": {}
|
||||||
},
|
},
|
||||||
"reftest_nodes": {
|
"reftest_nodes": {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[getElementsByClassName-20.htm]
|
|
||||||
type: testharness
|
|
||||||
[get elements in document then add element to collection]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[getElementsByClassName-22.htm]
|
|
||||||
type: testharness
|
|
||||||
[move item in collection order]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[getElementsByClassName-25.htm]
|
|
||||||
type: testharness
|
|
||||||
[verify spacing is handled correctly]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -4152,27 +4152,6 @@
|
||||||
[HTMLAreaElement interface: document.createElement("area") must inherit property "noHref" with the proper type (10)]
|
[HTMLAreaElement interface: document.createElement("area") must inherit property "noHref" with the proper type (10)]
|
||||||
expected: FAIL
|
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)]
|
[HTMLTableElement interface: operation insertRow(long)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -4206,27 +4185,6 @@
|
||||||
[HTMLTableElement interface: attribute cellSpacing]
|
[HTMLTableElement interface: attribute cellSpacing]
|
||||||
expected: FAIL
|
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)]
|
[HTMLTableElement interface: document.createElement("table") must inherit property "insertRow" with the proper type (12)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -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,0 +1,66 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>tHead tests</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<table id="t">
|
||||||
|
<caption id="tcaption"></caption><thead id="thead1"></thead><thead id="thead2"></thead><thead id="thead3"></thead><tbody id="tbody1"></tbody><tbody id="tbody2"></tbody><tfoot id="tfoot"></tfoot>
|
||||||
|
</table>
|
||||||
|
<table>
|
||||||
|
<thead id="t2thead">
|
||||||
|
<td>
|
||||||
|
<table id="t2">
|
||||||
|
</table>
|
||||||
|
</table>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
var t = document.getElementById("t");
|
||||||
|
var thead1 = document.getElementById("thead1");
|
||||||
|
|
||||||
|
assert_equals(t.tHead, thead1);
|
||||||
|
|
||||||
|
var thead2 = document.getElementById("thead2");
|
||||||
|
t.tHead = null;
|
||||||
|
|
||||||
|
assert_equals(t.tHead, thead2);
|
||||||
|
|
||||||
|
var thead3 = document.getElementById("thead3");
|
||||||
|
t.deleteTHead();
|
||||||
|
|
||||||
|
assert_equals(t.tHead, thead3);
|
||||||
|
|
||||||
|
var thead = t.createTHead();
|
||||||
|
assert_equals(t.tHead, thead);
|
||||||
|
assert_equals(thead, thead3);
|
||||||
|
|
||||||
|
t.deleteTHead();
|
||||||
|
assert_equals(t.tHead, null);
|
||||||
|
|
||||||
|
var tcaption = document.getElementById("tcaption");
|
||||||
|
var tbody1 = document.getElementById("tbody1");
|
||||||
|
|
||||||
|
thead = t.createTHead();
|
||||||
|
assert_equals(t.tHead, thead);
|
||||||
|
|
||||||
|
assert_equals(t.tHead.previousSibling, tcaption);
|
||||||
|
assert_equals(t.tHead.nextSibling, tbody1);
|
||||||
|
|
||||||
|
assert_throws(new TypeError(), function(){
|
||||||
|
t.tHead = document.createElement("div");
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_throws("HierarchyRequestError", function(){
|
||||||
|
t.tHead = document.createElement("tbody");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var t2 = document.getElementById("t2");
|
||||||
|
var t2thead = document.getElementById("t2thead");
|
||||||
|
|
||||||
|
assert_throws("HierarchyRequestError", function() {
|
||||||
|
t2.tHead = t2thead;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue