aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorbors-servo <release+servo@mozilla.com>2013-10-11 07:51:59 -0700
committerbors-servo <release+servo@mozilla.com>2013-10-11 07:51:59 -0700
commitfc9fdf30a6b4b4437cfe7a624c52c9a8b5e5a645 (patch)
tree81e44e4c34830ca94d5dd7d21f4e5e19f85f43ad /src
parentbc3eeb6f1c1b643df72b787ef772f20bcc094856 (diff)
parent9fe9145be4386ae38facc029946678fb0a54c2f7 (diff)
downloadservo-fc9fdf30a6b4b4437cfe7a624c52c9a8b5e5a645.tar.gz
servo-fc9fdf30a6b4b4437cfe7a624c52c9a8b5e5a645.zip
auto merge of #1018 : ttaubert/servo/nodelist, r=jdm
This should fix #652 and #775. I'm not sure if that's all that is needed to properly implement NodeList? Should we add tests somewhere? Sorry for any stupid stuff I might have done :) r? @jdm
Diffstat (limited to 'src')
-rw-r--r--src/components/script/dom/bindings/codegen/Bindings.conf7
-rw-r--r--src/components/script/dom/bindings/codegen/Node.webidl4
-rw-r--r--src/components/script/dom/bindings/codegen/NodeList.webidl16
-rw-r--r--src/components/script/dom/element.rs14
-rw-r--r--src/components/script/dom/htmldatalistelement.rs13
-rw-r--r--src/components/script/dom/htmldocument.rs7
-rw-r--r--src/components/script/dom/htmlfieldsetelement.rs14
-rw-r--r--src/components/script/dom/htmlformelement.rs14
-rw-r--r--src/components/script/dom/htmlmapelement.rs15
-rw-r--r--src/components/script/dom/node.rs25
-rw-r--r--src/components/script/dom/nodelist.rs91
-rw-r--r--src/components/script/script.rc1
-rw-r--r--src/test/html/content/test_childnodes.html31
13 files changed, 180 insertions, 72 deletions
diff --git a/src/components/script/dom/bindings/codegen/Bindings.conf b/src/components/script/dom/bindings/codegen/Bindings.conf
index 691611e870e..7fb32fec79a 100644
--- a/src/components/script/dom/bindings/codegen/Bindings.conf
+++ b/src/components/script/dom/bindings/codegen/Bindings.conf
@@ -300,14 +300,15 @@ DOMInterfaces = {
'nodeValue',
'removeChild',
'textContent',
+ 'childNodes'
]
},
'NodeList': [
{
- 'nativeType': 'nsINodeList',
- 'prefable': True,
- 'resultNotAddRefed': [ 'item' ]
+ 'nativeType': 'NodeList',
+ 'pointerType': '@mut ',
+ 'resultNotAddRefed': ['item']
}],
'PaintRequestList': [
diff --git a/src/components/script/dom/bindings/codegen/Node.webidl b/src/components/script/dom/bindings/codegen/Node.webidl
index 92dc40eee34..5e099c217a4 100644
--- a/src/components/script/dom/bindings/codegen/Node.webidl
+++ b/src/components/script/dom/bindings/codegen/Node.webidl
@@ -42,8 +42,8 @@ interface Node /*: EventTarget*/ {
[Pure]
readonly attribute Element? parentElement;
boolean hasChildNodes();
- /*[Constant]
- readonly attribute NodeList childNodes;*/
+ [Constant]
+ readonly attribute NodeList childNodes;
[Pure]
readonly attribute Node? firstChild;
[Pure]
diff --git a/src/components/script/dom/bindings/codegen/NodeList.webidl b/src/components/script/dom/bindings/codegen/NodeList.webidl
new file mode 100644
index 00000000000..9b7d9dc3a7e
--- /dev/null
+++ b/src/components/script/dom/bindings/codegen/NodeList.webidl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/TR/2012/WD-dom-20120105/
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+interface NodeList {
+ readonly attribute unsigned long length;
+ getter Node? item(unsigned long index);
+};
diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs
index 7f0857894b9..51d7c609c98 100644
--- a/src/components/script/dom/element.rs
+++ b/src/components/script/dom/element.rs
@@ -192,14 +192,6 @@ impl<'self> Element {
}
}
}
-
- fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
- let doc = self.node.owner_doc;
- let win = doc.with_base(|doc| doc.window.unwrap());
- let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
- let scope = win.reflector().get_jsobject();
- (scope, cx)
- }
}
impl Element {
@@ -251,17 +243,17 @@ impl Element {
}
pub fn GetElementsByTagName(&self, _localname: &DOMString) -> @mut HTMLCollection {
- let (scope, cx) = self.get_scope_and_cx();
+ let (scope, cx) = self.node.get_scope_and_cx();
HTMLCollection::new(~[], cx, scope)
}
pub fn GetElementsByTagNameNS(&self, _namespace: &DOMString, _localname: &DOMString) -> Fallible<@mut HTMLCollection> {
- let (scope, cx) = self.get_scope_and_cx();
+ let (scope, cx) = self.node.get_scope_and_cx();
Ok(HTMLCollection::new(~[], cx, scope))
}
pub fn GetElementsByClassName(&self, _names: &DOMString) -> @mut HTMLCollection {
- let (scope, cx) = self.get_scope_and_cx();
+ let (scope, cx) = self.node.get_scope_and_cx();
HTMLCollection::new(~[], cx, scope)
}
diff --git a/src/components/script/dom/htmldatalistelement.rs b/src/components/script/dom/htmldatalistelement.rs
index 7123e4d6229..91203657312 100644
--- a/src/components/script/dom/htmldatalistelement.rs
+++ b/src/components/script/dom/htmldatalistelement.rs
@@ -2,27 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use dom::bindings::utils::Reflectable;
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
-use js::jsapi::{JSObject, JSContext};
-
pub struct HTMLDataListElement {
htmlelement: HTMLElement
}
impl HTMLDataListElement {
- fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
- let doc = self.htmlelement.element.node.owner_doc;
- let win = doc.with_base(|doc| doc.window.unwrap());
- let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
- let scope = win.reflector().get_jsobject();
- (scope, cx)
- }
-
pub fn Options(&self) -> @mut HTMLCollection {
- let (scope, cx) = self.get_scope_and_cx();
+ let (scope, cx) = self.htmlelement.element.node.get_scope_and_cx();
HTMLCollection::new(~[], cx, scope)
}
}
diff --git a/src/components/script/dom/htmldocument.rs b/src/components/script/dom/htmldocument.rs
index b81b4886aff..5d9641d81a0 100644
--- a/src/components/script/dom/htmldocument.rs
+++ b/src/components/script/dom/htmldocument.rs
@@ -32,13 +32,6 @@ impl HTMLDocument {
let compartment = window.get_ref().page.js_info.get_ref().js_compartment;
AbstractDocument::as_abstract(compartment.cx.ptr, doc)
}
-
- fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
- let win = self.parent.window.get_ref();
- let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
- let scope = win.reflector().get_jsobject();
- (scope, cx)
- }
}
impl ReflectableDocument for HTMLDocument {
diff --git a/src/components/script/dom/htmlfieldsetelement.rs b/src/components/script/dom/htmlfieldsetelement.rs
index 9a9d543fdef..e109ccb9d32 100644
--- a/src/components/script/dom/htmlfieldsetelement.rs
+++ b/src/components/script/dom/htmlfieldsetelement.rs
@@ -2,14 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use dom::bindings::utils::{DOMString, ErrorResult, Reflectable};
+use dom::bindings::utils::{DOMString, ErrorResult};
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
use dom::node::{AbstractNode, ScriptView};
use dom::validitystate::ValidityState;
-use js::jsapi::{JSContext, JSObject};
-
pub struct HTMLFieldSetElement {
htmlelement: HTMLElement
}
@@ -39,16 +37,8 @@ impl HTMLFieldSetElement {
None
}
- fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
- let doc = self.htmlelement.element.node.owner_doc;
- let win = doc.with_base(|doc| doc.window.unwrap());
- let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
- let scope = win.reflector().get_jsobject();
- (scope, cx)
- }
-
pub fn Elements(&self) -> @mut HTMLCollection {
- let (scope, cx) = self.get_scope_and_cx();
+ let (scope, cx) = self.htmlelement.element.node.get_scope_and_cx();
HTMLCollection::new(~[], cx, scope)
}
diff --git a/src/components/script/dom/htmlformelement.rs b/src/components/script/dom/htmlformelement.rs
index eba85672a6e..fe2aa34accb 100644
--- a/src/components/script/dom/htmlformelement.rs
+++ b/src/components/script/dom/htmlformelement.rs
@@ -2,26 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use dom::bindings::utils::{Reflectable, DOMString, ErrorResult};
+use dom::bindings::utils::{DOMString, ErrorResult};
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
use dom::node::{AbstractNode, ScriptView};
-use js::jsapi::{JSObject, JSContext};
-
pub struct HTMLFormElement {
htmlelement: HTMLElement
}
impl HTMLFormElement {
- fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
- let doc = self.htmlelement.element.node.owner_doc;
- let win = doc.with_base(|doc| doc.window.unwrap());
- let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
- let scope = win.reflector().get_jsobject();
- (scope, cx)
- }
-
pub fn AcceptCharset(&self) -> DOMString {
None
}
@@ -95,7 +85,7 @@ impl HTMLFormElement {
}
pub fn Elements(&self) -> @mut HTMLCollection {
- let (scope, cx) = self.get_scope_and_cx();
+ let (scope, cx) = self.htmlelement.element.node.get_scope_and_cx();
HTMLCollection::new(~[], cx, scope)
}
diff --git a/src/components/script/dom/htmlmapelement.rs b/src/components/script/dom/htmlmapelement.rs
index 4a924e96a0b..124cafc98fb 100644
--- a/src/components/script/dom/htmlmapelement.rs
+++ b/src/components/script/dom/htmlmapelement.rs
@@ -2,10 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use dom::bindings::utils::{DOMString, ErrorResult, Reflectable};
+use dom::bindings::utils::{DOMString, ErrorResult};
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
-use js::jsapi::{JSObject, JSContext};
pub struct HTMLMapElement {
htmlelement: HTMLElement
@@ -20,16 +19,8 @@ impl HTMLMapElement {
Ok(())
}
- fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
- let doc = self.htmlelement.element.node.owner_doc;
- let win = doc.with_base(|doc| doc.window.unwrap());
- let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
- let scope = win.reflector().get_jsobject();
- (scope, cx)
- }
-
pub fn Areas(&self) -> @mut HTMLCollection {
- let (scope, cx) = self.get_scope_and_cx();
- HTMLCollection::new(~[], cx, scope)
+ let (scope, cx) = self.htmlelement.element.node.get_scope_and_cx();
+ HTMLCollection::new(~[], cx, scope)
}
}
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 1743c1acabe..46ddc57ec36 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -12,6 +12,7 @@ use dom::document::AbstractDocument;
use dom::documenttype::DocumentType;
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId};
use dom::element::{HTMLStyleElementTypeId};
+use dom::nodelist::{NodeList};
use dom::htmlimageelement::HTMLImageElement;
use dom::htmliframeelement::HTMLIFrameElement;
use dom::text::Text;
@@ -89,6 +90,9 @@ pub struct Node<View> {
/// The document that this node belongs to.
owner_doc: AbstractDocument,
+ /// The live list of children return by .childNodes.
+ child_list: Option<@mut NodeList>,
+
/// Layout information. Only the layout task may touch this data.
priv layout_data: LayoutData,
}
@@ -496,6 +500,7 @@ impl Node<ScriptView> {
prev_sibling: None,
owner_doc: doc,
+ child_list: None,
layout_data: LayoutData::new(),
}
@@ -570,7 +575,7 @@ impl Node<ScriptView> {
}
pub fn HasChildNodes(&self) -> bool {
- false
+ self.first_child.is_some()
}
pub fn GetFirstChild(&self) -> Option<AbstractNode<ScriptView>> {
@@ -632,6 +637,24 @@ impl Node<ScriptView> {
}
}
+ pub fn ChildNodes(&mut self, abstract_self: AbstractNode<ScriptView>) -> @mut NodeList {
+ match self.child_list {
+ None => {
+ let (scope, cx) = self.get_scope_and_cx();
+ let list = NodeList::new_child_list(abstract_self, cx, scope);
+ self.child_list = Some(list);
+ list
+ }
+ Some(list) => list
+ }
+ }
+
+ pub fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
+ let win = self.owner_doc.with_base(|doc| doc.window.unwrap());
+ let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
+ (win.reflector().get_jsobject(), cx)
+ }
+
// http://dom.spec.whatwg.org/#concept-node-replace-all
pub fn replace_all(&mut self,
abstract_self: AbstractNode<ScriptView>,
diff --git a/src/components/script/dom/nodelist.rs b/src/components/script/dom/nodelist.rs
new file mode 100644
index 00000000000..8781dc4b72a
--- /dev/null
+++ b/src/components/script/dom/nodelist.rs
@@ -0,0 +1,91 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::NodeListBinding;
+use dom::bindings::utils::{Reflectable, BindingObject, Reflector};
+use dom::node::{AbstractNode, ScriptView};
+use script_task::page_from_context;
+
+use js::jsapi::{JSObject, JSContext};
+
+enum NodeListType {
+ Simple(~[AbstractNode<ScriptView>]),
+ Children(AbstractNode<ScriptView>)
+}
+
+pub struct NodeList {
+ list_type: NodeListType,
+ reflector_: Reflector
+}
+
+impl NodeList {
+ pub fn new_simple_list(elements: ~[AbstractNode<ScriptView>], cx: *JSContext, scope: *JSObject) -> @mut NodeList {
+ let list = @mut NodeList {
+ list_type: Simple(elements),
+ reflector_: Reflector::new()
+ };
+
+ list.init_wrapper(cx, scope);
+ list
+ }
+
+ pub fn new_child_list(node: AbstractNode<ScriptView>, cx: *JSContext, scope: *JSObject) -> @mut NodeList {
+ let list = @mut NodeList {
+ list_type: Children(node),
+ reflector_: Reflector::new()
+ };
+
+ list.init_wrapper(cx, scope);
+ list
+ }
+
+ fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
+ self.wrap_object_shared(cx, scope);
+ }
+
+ pub fn Length(&self) -> u32 {
+ match self.list_type {
+ Simple(ref elems) => elems.len() as u32,
+ Children(ref node) => node.children().len() as u32
+ }
+ }
+
+ pub fn Item(&self, index: u32) -> Option<AbstractNode<ScriptView>> {
+ match self.list_type {
+ _ if index >= self.Length() => None,
+ Simple(ref elems) => Some(elems[index]),
+ Children(ref node) => node.children().nth(index as uint)
+ }
+ }
+
+ pub fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<AbstractNode<ScriptView>> {
+ let item = self.Item(index);
+ *found = item.is_some();
+ item
+ }
+}
+
+impl BindingObject for NodeList {
+ fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
+ let page = page_from_context(cx);
+ unsafe {
+ Some((*page).frame.get_ref().window as @mut Reflectable)
+ }
+ }
+}
+
+impl Reflectable for NodeList {
+ fn reflector<'a>(&'a self) -> &'a Reflector {
+ &self.reflector_
+ }
+
+ fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
+ &mut self.reflector_
+ }
+
+ fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
+ let mut unused = false;
+ NodeListBinding::Wrap(cx, scope, self, &mut unused)
+ }
+}
diff --git a/src/components/script/script.rc b/src/components/script/script.rc
index 422a013d932..42d2d031b52 100644
--- a/src/components/script/script.rc
+++ b/src/components/script/script.rc
@@ -127,6 +127,7 @@ pub mod dom {
pub mod mouseevent;
pub mod navigator;
pub mod node;
+ pub mod nodelist;
pub mod uievent;
pub mod text;
pub mod validitystate;
diff --git a/src/test/html/content/test_childnodes.html b/src/test/html/content/test_childnodes.html
new file mode 100644
index 00000000000..f8a4d9797c6
--- /dev/null
+++ b/src/test/html/content/test_childnodes.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <title></title>
+ <script src="harness.js"></script>
+</head>
+<body>
+ <script>
+ var elem = document.createElement("p");
+ is(elem.childNodes.length, 0);
+
+ var children = elem.childNodes;
+ var child = document.createElement("p");
+ elem.appendChild(child);
+
+ is(elem.childNodes.length, 1);
+ is(elem.childNodes[0], child);
+
+ var child2 = document.createElement("p");
+ elem.appendChild(child2);
+
+ is(1 in children, true);
+ is(children.length, 2);
+ is(children.item(1), child2);
+
+ is(!(2 in children), true);
+ is(children.item(2), null);
+
+ finish();
+ </script>
+</body>
+</html>