diff options
author | bors-servo <release+servo@mozilla.com> | 2013-10-11 07:51:59 -0700 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2013-10-11 07:51:59 -0700 |
commit | fc9fdf30a6b4b4437cfe7a624c52c9a8b5e5a645 (patch) | |
tree | 81e44e4c34830ca94d5dd7d21f4e5e19f85f43ad /src | |
parent | bc3eeb6f1c1b643df72b787ef772f20bcc094856 (diff) | |
parent | 9fe9145be4386ae38facc029946678fb0a54c2f7 (diff) | |
download | servo-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.conf | 7 | ||||
-rw-r--r-- | src/components/script/dom/bindings/codegen/Node.webidl | 4 | ||||
-rw-r--r-- | src/components/script/dom/bindings/codegen/NodeList.webidl | 16 | ||||
-rw-r--r-- | src/components/script/dom/element.rs | 14 | ||||
-rw-r--r-- | src/components/script/dom/htmldatalistelement.rs | 13 | ||||
-rw-r--r-- | src/components/script/dom/htmldocument.rs | 7 | ||||
-rw-r--r-- | src/components/script/dom/htmlfieldsetelement.rs | 14 | ||||
-rw-r--r-- | src/components/script/dom/htmlformelement.rs | 14 | ||||
-rw-r--r-- | src/components/script/dom/htmlmapelement.rs | 15 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 25 | ||||
-rw-r--r-- | src/components/script/dom/nodelist.rs | 91 | ||||
-rw-r--r-- | src/components/script/script.rc | 1 | ||||
-rw-r--r-- | src/test/html/content/test_childnodes.html | 31 |
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> |