Implement HTMLTableRowElement insertCell and deleteCell

This commit is contained in:
Corey Farwell 2015-10-11 23:37:01 -04:00
parent e31ad01103
commit 1f58169263
8 changed files with 108 additions and 106 deletions

View file

@ -8,11 +8,13 @@ use dom::bindings::codegen::Bindings::HTMLTableRowElementBinding::{self, HTMLTab
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableDataCellElementDerived}; use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableDataCellElementDerived};
use dom::bindings::codegen::InheritTypes::{HTMLTableHeaderCellElementDerived, NodeCast}; use dom::bindings::codegen::InheritTypes::{HTMLTableHeaderCellElementDerived, NodeCast};
use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference}; use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::document::Document; use dom::document::Document;
use dom::element::{AttributeMutation, Element}; use dom::element::{AttributeMutation, Element};
use dom::htmlcollection::{CollectionFilter, HTMLCollection}; use dom::htmlcollection::{CollectionFilter, HTMLCollection};
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::htmltabledatacellelement::HTMLTableDataCellElement;
use dom::node::{Node, window_from_node}; use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use std::cell::Cell; use std::cell::Cell;
@ -73,6 +75,24 @@ impl HTMLTableRowElementMethods for HTMLTableRowElement {
HTMLCollection::create(window.r(), NodeCast::from_ref(self), filter) HTMLCollection::create(window.r(), NodeCast::from_ref(self), filter)
}) })
} }
// https://html.spec.whatwg.org/multipage/#dom-tr-insertcell
fn InsertCell(&self, index: i32) -> Fallible<Root<HTMLElement>> {
let node = NodeCast::from_ref(self);
node.insert_cell_or_row(
index,
|| self.Cells(),
|| HTMLTableDataCellElement::new("td".to_owned(), None, node.owner_doc().r()))
}
// https://html.spec.whatwg.org/multipage/#dom-tr-deletecell
fn DeleteCell(&self, index: i32) -> ErrorResult {
let node = NodeCast::from_ref(self);
node.delete_cell_or_row(
index,
|| self.Cells(),
|n| n.is_htmltabledatacellelement())
}
} }
impl VirtualMethods for HTMLTableRowElement { impl VirtualMethods for HTMLTableRowElement {

View file

@ -4,12 +4,9 @@
use cssparser::RGBA; use cssparser::RGBA;
use dom::attr::Attr; use dom::attr::Attr;
use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use dom::bindings::codegen::Bindings::HTMLTableSectionElementBinding::{self, HTMLTableSectionElementMethods}; use dom::bindings::codegen::Bindings::HTMLTableSectionElementBinding::{self, HTMLTableSectionElementMethods};
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableRowElementDerived, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, NodeCast};
use dom::bindings::error::Error;
use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::js::{Root, RootedReference}; use dom::bindings::js::{Root, RootedReference};
use dom::document::Document; use dom::document::Document;
@ -20,7 +17,6 @@ use dom::htmltablerowelement::HTMLTableRowElement;
use dom::node::{Node, window_from_node}; use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use std::cell::Cell; use std::cell::Cell;
use std::iter;
use util::str::{self, DOMString}; use util::str::{self, DOMString};
#[dom_struct] #[dom_struct]
@ -67,57 +63,20 @@ impl HTMLTableSectionElementMethods for HTMLTableSectionElement {
// https://html.spec.whatwg.org/multipage/#dom-tbody-insertrow // https://html.spec.whatwg.org/multipage/#dom-tbody-insertrow
fn InsertRow(&self, index: i32) -> Fallible<Root<HTMLElement>> { fn InsertRow(&self, index: i32) -> Fallible<Root<HTMLElement>> {
if index < -1 {
return Err(Error::IndexSize);
}
let node = NodeCast::from_ref(self); let node = NodeCast::from_ref(self);
let tr = HTMLTableRowElement::new("tr".to_owned(), None, node.owner_doc().r()); node.insert_cell_or_row(
index,
let after_node = if index == -1 { || self.Rows(),
None || HTMLTableRowElement::new("tr".to_owned(), None, node.owner_doc().r()))
} else {
match self.Rows()
.elements_iter()
.map(NodeCast::from_root)
.map(Some)
.chain(iter::once(None))
.nth(index as usize) {
None => return Err(Error::IndexSize),
Some(node) => node,
}
};
{
let tr_node = NodeCast::from_ref(tr.r());
try!(node.InsertBefore(tr_node, after_node.r()));
}
Ok(HTMLElementCast::from_root(tr))
} }
// https://html.spec.whatwg.org/multipage/#dom-tbody-deleterow // https://html.spec.whatwg.org/multipage/#dom-tbody-deleterow
fn DeleteRow(&self, index: i32) -> ErrorResult { fn DeleteRow(&self, index: i32) -> ErrorResult {
let element = match index { let node = NodeCast::from_ref(self);
index if index < -1 => return Err(Error::IndexSize), node.delete_cell_or_row(
-1 => { index,
let last_child = NodeCast::from_ref(self).GetLastChild(); || self.Rows(),
match last_child.and_then(|node| node.inclusively_preceding_siblings() |n| n.is_htmltablerowelement())
.filter_map(ElementCast::to_root)
.filter(|n| n.is_htmltablerowelement())
.next()) {
Some(element) => element,
None => return Ok(()),
}
},
index => match self.Rows().Item(index as u32) {
Some(element) => element,
None => return Err(Error::IndexSize),
},
};
NodeCast::from_ref(element.r()).remove_self();
Ok(())
} }
} }

View file

@ -14,10 +14,13 @@ use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods; use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods; use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
use dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods}; use dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods};
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods; use dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
use dom::bindings::codegen::InheritTypes::HTMLElementBase;
use dom::bindings::codegen::InheritTypes::HTMLElementCast;
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, CharacterDataTypeId}; use dom::bindings::codegen::InheritTypes::{CharacterDataCast, CharacterDataTypeId};
use dom::bindings::codegen::InheritTypes::{DocumentCast, DocumentDerived, DocumentTypeCast}; use dom::bindings::codegen::InheritTypes::{DocumentCast, DocumentDerived, DocumentTypeCast};
use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, ElementTypeId}; use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, ElementTypeId};
@ -43,6 +46,8 @@ use dom::documentfragment::DocumentFragment;
use dom::documenttype::DocumentType; use dom::documenttype::DocumentType;
use dom::element::{Element, ElementCreator}; use dom::element::{Element, ElementCreator};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
use dom::nodelist::NodeList; use dom::nodelist::NodeList;
use dom::processinginstruction::ProcessingInstruction; use dom::processinginstruction::ProcessingInstruction;
use dom::text::Text; use dom::text::Text;
@ -60,7 +65,7 @@ use selectors::parser::parse_author_origin_selector_list_from_str;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::{Cell, Ref, RefCell, RefMut}; use std::cell::{Cell, Ref, RefCell, RefMut};
use std::default::Default; use std::default::Default;
use std::iter::{FilterMap, Peekable}; use std::iter::{self, FilterMap, Peekable};
use std::mem; use std::mem;
use std::slice::ref_slice; use std::slice::ref_slice;
use std::sync::Arc; use std::sync::Arc;
@ -918,6 +923,66 @@ impl Node {
} }
Ok(fragment) Ok(fragment)
} }
/// Used by `HTMLTableSectionElement::InsertRow` and `HTMLTableRowElement::InsertCell`
pub fn insert_cell_or_row<F, G, I>(&self, index: i32, get_items: F, new_child: G) -> Fallible<Root<HTMLElement>>
where F: Fn() -> Root<HTMLCollection>,
G: Fn() -> Root<I>,
I: NodeBase + HTMLElementBase + Reflectable,
{
if index < -1 {
return Err(Error::IndexSize);
}
let tr = new_child();
let after_node = if index == -1 {
None
} else {
match get_items().elements_iter()
.map(NodeCast::from_root)
.map(Some)
.chain(iter::once(None))
.nth(index as usize) {
None => return Err(Error::IndexSize),
Some(node) => node,
}
};
{
let tr_node = NodeCast::from_ref(tr.r());
try!(self.InsertBefore(tr_node, after_node.r()));
}
Ok(HTMLElementCast::from_root(tr))
}
/// Used by `HTMLTableSectionElement::DeleteRow` and `HTMLTableRowElement::DeleteCell`
pub fn delete_cell_or_row<F, G>(&self, index: i32, get_items: F, is_delete_type: G) -> ErrorResult
where F: Fn() -> Root<HTMLCollection>,
G: Fn(&Element) -> bool
{
let element = match index {
index if index < -1 => return Err(Error::IndexSize),
-1 => {
let last_child = NodeCast::from_ref(self).GetLastChild();
match last_child.and_then(|node| node.inclusively_preceding_siblings()
.filter_map(ElementCast::to_root)
.filter(|elem| is_delete_type(elem))
.next()) {
Some(element) => element,
None => return Ok(()),
}
},
index => match get_items().Item(index as u32) {
Some(element) => element,
None => return Err(Error::IndexSize),
},
};
NodeCast::from_ref(element.r()).remove_self();
Ok(())
}
} }

View file

@ -8,8 +8,10 @@ interface HTMLTableRowElement : HTMLElement {
//readonly attribute long rowIndex; //readonly attribute long rowIndex;
//readonly attribute long sectionRowIndex; //readonly attribute long sectionRowIndex;
readonly attribute HTMLCollection cells; readonly attribute HTMLCollection cells;
//HTMLElement insertCell(optional long index = -1); [Throws]
//void deleteCell(long index); HTMLElement insertCell(optional long index = -1);
[Throws]
void deleteCell(long index);
// also has obsolete members // also has obsolete members
}; };

View file

@ -4707,12 +4707,6 @@
[HTMLTableRowElement interface: attribute sectionRowIndex] [HTMLTableRowElement interface: attribute sectionRowIndex]
expected: FAIL expected: FAIL
[HTMLTableRowElement interface: operation insertCell(long)]
expected: FAIL
[HTMLTableRowElement interface: operation deleteCell(long)]
expected: FAIL
[HTMLTableRowElement interface: attribute align] [HTMLTableRowElement interface: attribute align]
expected: FAIL expected: FAIL
@ -4731,18 +4725,6 @@
[HTMLTableRowElement interface: document.createElement("tr") must inherit property "sectionRowIndex" with the proper type (1)] [HTMLTableRowElement interface: document.createElement("tr") must inherit property "sectionRowIndex" with the proper type (1)]
expected: FAIL expected: FAIL
[HTMLTableRowElement interface: document.createElement("tr") must inherit property "insertCell" with the proper type (3)]
expected: FAIL
[HTMLTableRowElement interface: calling insertCell(long) on document.createElement("tr") with too few arguments must throw TypeError]
expected: FAIL
[HTMLTableRowElement interface: document.createElement("tr") must inherit property "deleteCell" with the proper type (4)]
expected: FAIL
[HTMLTableRowElement interface: calling deleteCell(long) on document.createElement("tr") with too few arguments must throw TypeError]
expected: FAIL
[HTMLTableRowElement interface: document.createElement("tr") must inherit property "align" with the proper type (5)] [HTMLTableRowElement interface: document.createElement("tr") must inherit property "align" with the proper type (5)]
expected: FAIL expected: FAIL

View file

@ -1,14 +0,0 @@
[deleteCell.html]
type: testharness
[HTMLTableRowElement deleteCell(0)]
expected: FAIL
[HTMLTableRowElement deleteCell(-1)]
expected: FAIL
[HTMLTableRowElement deleteCell(-2)]
expected: FAIL
[HTMLTableRowElement deleteCell(cells.length)]
expected: FAIL

View file

@ -1,20 +0,0 @@
[insertCell.html]
type: testharness
[HTMLTableRowElement insertCell(0)]
expected: FAIL
[HTMLTableRowElement insertCell(-1)]
expected: FAIL
[HTMLTableRowElement insertCell(cells.length)]
expected: FAIL
[HTMLTableRowElement insertCell()]
expected: FAIL
[HTMLTableRowElement insertCell(-2)]
expected: FAIL
[HTMLTableRowElement insertCell(cells.length + 1)]
expected: FAIL

View file

@ -43,4 +43,12 @@ test(function () {
}); });
}, "HTMLTableRowElement deleteCell(cells.length)"); }, "HTMLTableRowElement deleteCell(cells.length)");
test(function () {
assert_equals(tr.cells.length, 1);
tr.deleteCell(-1);
assert_equals(tr.cells.length, 0);
tr.deleteCell(-1);
assert_equals(tr.cells.length, 0);
}, "HTMLTableRowElement deleteCell(-1) with no cells");
</script> </script>