mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30: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::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<Option<u32>>,
|
||||
cellspacing: Cell<Option<u32>>,
|
||||
tbodies: MutNullableHeap<JS<HTMLCollection>>,
|
||||
}
|
||||
|
||||
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<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(§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 {
|
||||
|
@ -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"),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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)]
|
||||
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
|
||||
|
||||
|
|
|
@ -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