Add basic binding for HTMLCollection.

This commit is contained in:
Josh Matthews 2013-03-21 15:04:36 -04:00
parent 5f672775b2
commit 6660ea0278
14 changed files with 282 additions and 95 deletions

View file

@ -212,9 +212,9 @@ DOMInterfaces = {
'HTMLCollection': [
{
'nativeType': 'nsIHTMLCollection',
'prefable': True,
'resultNotAddRefed': [ 'item' ]
'nativeType': 'HTMLCollection',
#'prefable': True,
#'resultNotAddRefed': [ 'item' ]
}],
'HTMLOptionsCollection': [
@ -490,7 +490,7 @@ DOMInterfaces = {
}
# These are temporary, until they've been converted to use new DOM bindings
def addExternalIface(iface, nativeType=None, headerFile=None):
def addExternalIface(iface, nativeType=None, headerFile=None, pointerType=None):
domInterface = {
'concrete': False
}
@ -498,6 +498,8 @@ def addExternalIface(iface, nativeType=None, headerFile=None):
domInterface['nativeType'] = nativeType
if not headerFile is None:
domInterface['headerFile'] = headerFile
if not pointerType is None:
domInterface['pointerType'] = pointerType
DOMInterfaces[iface] = domInterface
# If you add one of these, you need to make sure nsDOMQS.h has the relevant
@ -519,7 +521,7 @@ addExternalIface('CSSRule')
addExternalIface('CSSValue')
addExternalIface('DOMStringList', nativeType='nsDOMStringList',
headerFile='nsDOMLists.h')
addExternalIface('Element', nativeType='nsGenericElement')
addExternalIface('Element', nativeType='AbstractNode', pointerType='')
addExternalIface('File')
addExternalIface('HitRegionOptions', nativeType='nsISupports')
addExternalIface('HTMLElement')

View file

@ -1041,10 +1041,16 @@ for (uint32_t i = 0; i < length; ++i) {
undefinedBehavior = treatAs[treatUndefinedAs]
def getConversionCode(varName):
#conversionCode = (
# "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
# " return false;\n"
# "}" % (nullBehavior, undefinedBehavior, varName))
conversionCode = (
"if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
" return false;\n"
"}" % (nullBehavior, undefinedBehavior, varName))
"let strval = jsval_to_str(cx, ${val});\n"
"if strval.is_err() {\n"
" return 0;\n"
"}\n"
"%s = str(strval.get());" % varName)
if defaultValue is None:
return conversionCode
@ -1072,15 +1078,15 @@ for (uint32_t i = 0; i < length; ++i) {
declType, None, isOptional)
if isOptional:
declType = "Optional<nsAString>"
declType = "Option<DOMString>"
else:
declType = "NonNull<nsAString>"
declType = "DOMString"
return (
"%s\n"
"const_cast<%s&>(${declName}) = &${holderName};" %
(getConversionCode("${holderName}"), declType),
CGGeneric("const " + declType), CGGeneric("FakeDependentString"),
"%s\n" %
#"const_cast<%s&>(${declName}) = &${holderName};" %
(getConversionCode("${declName}")),
CGGeneric(declType), None, #CGGeneric("FakeDependentString"),
# No need to deal with Optional here; we have handled it already
False)
@ -1441,7 +1447,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
"}\n" +
successCode)
else:
tail = "return JS_WrapValue(cx, ${jsvalPtr});"
tail = "return JS_WrapValue(cx, cast::transmute(${jsvalPtr}));"
return ("${jsvalRef} = %s;\n" +
tail) % (value)
@ -1511,7 +1517,8 @@ for (uint32_t i = 0; i < length; ++i) {
if type.nullable():
wrappingCode = ("if %s.is_none() {\n" % (result) +
CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
"}\n")
"}\n" +
"let mut %s = %s.get();\n" % (result, result))
else:
wrappingCode = ""
if (not descriptor.interface.isExternal() and
@ -1522,7 +1529,7 @@ for (uint32_t i = 0; i < length; ++i) {
if not isCreator:
raise MethodNotCreatorError(descriptor.interface.identifier.name)
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
wrap = "%s(cx, ${obj}, %s.get(), ${jsvalPtr})" % (wrapMethod, result)
wrap = "%s(cx, ${obj}, %s, ${jsvalPtr})" % (wrapMethod, result)
# We don't support prefable stuff in workers.
assert(not descriptor.prefable or not descriptor.workers)
if not descriptor.prefable:
@ -1544,7 +1551,8 @@ for (uint32_t i = 0; i < length; ++i) {
getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
else:
getIID = ""
wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
#wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
wrap = "%s.wrap(cx, ${obj}, %s${jsvalPtr})" % (result, getIID)
wrappingCode += wrapAndSetPtr(wrap)
return (wrappingCode, False)
@ -1587,7 +1595,7 @@ if (!%(resultStr)s) {
# See comments in WrapNewBindingObject explaining why we need
# to wrap here.
if type.nullable():
toValue = "JS::ObjectOrNullValue(%s)"
toValue = "RUST_OBJECT_TO_JSVAL(%s)"
else:
toValue = "JS::ObjectValue(*%s)"
# NB: setValue(..., True) calls JS_WrapValue(), so is fallible
@ -1690,10 +1698,11 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
raise TypeError("We don't support nullable enum return values")
return CGGeneric(returnType.inner.identifier.name), False
if returnType.isGeckoInterface():
result = CGGeneric(descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeType)
descriptor = descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name)
result = CGGeneric(descriptor.nativeType)
if resultAlreadyAddRefed:
result = CGWrapper(result, pre="Option<~", post=">")
result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">")
else:
result = CGWrapper(result, post="*")
return result, False
@ -2901,7 +2910,7 @@ class CGCallGenerator(CGThing):
if resultOutParam:
args.append(CGGeneric("result"))
if isFallible:
args.append(CGGeneric("rv"))
args.append(CGGeneric("&mut rv"))
needsCx = (typeNeedsCx(returnType, True) or
any(typeNeedsCx(a.type) for (a, _) in arguments) or
@ -2930,8 +2939,8 @@ class CGCallGenerator(CGThing):
self.cgRoot.append(call)
if isFallible:
self.cgRoot.prepend(CGGeneric("ErrorResult rv;"))
self.cgRoot.append(CGGeneric("if (rv.Failed()) {"))
self.cgRoot.prepend(CGGeneric("let mut rv: ErrorResult = Ok(());"))
self.cgRoot.append(CGGeneric("if (rv.is_err()) {"))
self.cgRoot.append(CGIndenter(errorReport))
self.cgRoot.append(CGGeneric("}"))
@ -3031,10 +3040,11 @@ class CGPerSignatureCall(CGThing):
self.idlNode.identifier.name))
def getErrorReport(self):
return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
% (toStringBool(not self.descriptor.workers),
self.descriptor.interface.identifier.name,
self.idlNode.identifier.name))
#return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
# % (toStringBool(not self.descriptor.workers),
# self.descriptor.interface.identifier.name,
# self.idlNode.identifier.name))
return CGGeneric('return 0'); #XXXjdm
def define(self):
return (self.cgRoot.define() + "\n" + self.wrap_return_value())
@ -3844,10 +3854,12 @@ class CGBindingRoot(CGThing):
'js::jsfriendapi::bindgen::*',
'js::glue::bindgen::*',
'js::glue::*',
'dom::node::AbstractNode',
'dom::bindings::utils::*',
'dom::bindings::conversions::*',
'dom::bindings::clientrect::*', #XXXjdm
'dom::bindings::clientrectlist::*', #XXXjdm
'dom::bindings::htmlcollection::*', #XXXjdm
'dom::bindings::proxyhandler::*',
'content::content_task::task_from_context'
],

View file

@ -139,7 +139,7 @@ class Descriptor(DescriptorProvider):
nativeTypeDefault = "mozilla::dom::" + ifaceName
self.nativeType = desc.get('nativeType', nativeTypeDefault)
self.pointerType = desc.get('pointerType', '@')
self.pointerType = desc.get('pointerType', '~')
self.hasInstanceInterface = desc.get('hasInstanceInterface', None)
# Do something sane for JSObject

View file

@ -0,0 +1,20 @@
/* -*- 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 Element;
interface HTMLCollection {
readonly attribute unsigned long length;
getter Element? item(unsigned long index);
[Throws]
getter object? namedItem(DOMString name); // only returns Element
};

View file

@ -1,5 +1,6 @@
#include "ClientRectBinding.h"
#include "ClientRectListBinding.h"
#include "HTMLCollectionBinding.h"
#include "nsScriptNameSpaceManager.h"
namespace mozilla {
@ -13,6 +14,7 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager)
REGISTER_PROTO(ClientRect, nullptr);
REGISTER_PROTO(ClientRectList, nullptr);
REGISTER_PROTO(HTMLCollection, nullptr);
#undef REGISTER_PROTO
}

View file

@ -2,7 +2,8 @@ use js::rust::{Compartment, jsobj};
use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED,
JSVAL_NULL, JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSFreeOp,
JSPropertySpec, JSPropertyOpWrapper, JSStrictPropertyOpWrapper};
JSPropertySpec, JSPropertyOpWrapper, JSStrictPropertyOpWrapper,
JSNativeWrapper, JSFunctionSpec};
use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
JS_DefineFunctions, JS_DefineProperty, JS_DefineProperties};
@ -12,58 +13,16 @@ use js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_Con
use core::ptr::null;
use core::libc::c_uint;
use dom::bindings::utils::{DOMString, domstring_to_jsval, rust_box, squirrel_away, str};
use dom::bindings::utils::{jsval_to_str, WrapNewBindingObject, CacheableWrapper};
use dom::bindings::utils::WrapperCache;
use dom::bindings::node::create;
use dom::document::Document;
use dom::bindings::htmlcollection::HTMLCollection;
use dom::bindings::node;
use dom::bindings::utils;
use dom::node::Node;
enum DOMException {
INVALID_CHARACTER_ERR
}
struct Element(int);
/*extern fn getElementById(cx: *JSContext, argc: c_uint, vp: *jsval) -> JSBool {
//XXX check if actually document object
if argc != 1 {
//XXX throw proper DOM exception
str::as_c_str("Not enough arguments", |s| {
JS_ReportError(cx, s);
});
return 0;
}
let id;
unsafe {
id = JS_ARGV(cx, vp)[0];
}
alt jsval_to_str(cx, id) {
ok(s) {
unsafe {
let doc: *Document = cast::reinterpret_cast(JS_GetContextPrivate(cx));
let elem = (*doc).getElementById(s);
}
//XXX wrap result
return 1;
}
err(_) {
str::as_c_str("???", |s| {
JS_ReportError(cx, s);
});
return 0;
}
}
}*/
/*extern fn getDocumentURI(cx: *JSContext, _argc: c_uint, vp: *jsval) -> JSBool {
unsafe {
let uri = (*unwrap(JS_THIS_OBJECT(cx, vp))).payload.getDocumentURI();
JS_SET_RVAL(cx, vp, domstring_to_jsval(cx, uri));
}
return 1;
}*/
extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
unsafe {
let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp));
@ -77,6 +36,34 @@ extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> J
}
}
extern fn getElementsByTagName(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
unsafe {
let obj = JS_THIS_OBJECT(cx, vp);
let argv = JS_ARGV(cx, cast::transmute(vp));
let arg0: DOMString;
let strval = jsval_to_str(cx, (*argv.offset(0)));
if strval.is_err() {
return 0;
}
arg0 = str(strval.get());
let doc = &mut (*unwrap(obj)).payload;
let rval: Option<~HTMLCollection>;
rval = doc.getElementsByTagName(arg0);
if rval.is_none() {
JS_SET_RVAL(cx, vp, JSVAL_NULL);
} else {
let cache = doc.get_wrappercache();
fail_unless!(WrapNewBindingObject(cx, cache.get_wrapper(),
rval.get(),
cast::transmute(vp)));
}
return 1;
}
}
unsafe fn unwrap(obj: *JSObject) -> *mut rust_box<Document> {
//TODO: some kind of check if this is a Document object
let val = JS_GetReservedSlot(obj, 0);
@ -112,11 +99,26 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
fail_unless!(JS_DefineProperties(compartment.cx.ptr, obj.ptr, specs) == 1);
});
let methods = @~[JSFunctionSpec {name: compartment.add_name(~"getElementsByTagName"),
call: JSNativeWrapper {op: getElementsByTagName, info: null()},
nargs: 0,
flags: 0,
selfHostedName: null()},
JSFunctionSpec {name: null(),
call: JSNativeWrapper {op: null(), info: null()},
nargs: 0,
flags: 0,
selfHostedName: null()}];
vec::as_imm_buf(*methods, |fns, _len| {
JS_DefineFunctions(compartment.cx.ptr, obj.ptr, fns);
});
compartment.register_class(utils::instance_jsclass(~"DocumentInstance", finalize));
let instance : jsobj = result::unwrap(
compartment.new_object_with_proto(~"DocumentInstance", ~"Document",
compartment.global_obj.ptr));
doc.wrapper.set_wrapper(instance.ptr);
unsafe {
let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(doc));
@ -128,3 +130,17 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
JSPROP_ENUMERATE);
}
impl CacheableWrapper for Document {
fn get_wrappercache(&mut self) -> &mut WrapperCache {
unsafe { cast::transmute(&self.wrapper) }
}
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
fail!(~"need to implement wrapping");
}
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
fail!(~"need to implement wrapping");
}
}

View file

@ -2,7 +2,6 @@ use content::content_task::{Content, task_from_context};
use dom::bindings::utils::{rust_box, squirrel_away_unique, get_compartment};
use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject};
use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT};
use dom::bindings::utils;
use dom::bindings::clientrectlist::ClientRectListImpl;
use dom::element::*;
use dom::node::{AbstractNode, Node, Element, ElementNodeTypeId};
@ -22,7 +21,7 @@ use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, J
use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
debug!("element finalize!");
debug!("element finalize: %?!", obj as uint);
unsafe {
let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32);
let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
@ -123,8 +122,7 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
let width = match node.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => {
let content = task_from_context(cx);
let node = Node::as_abstract_node(~*node);
match (*content).query_layout(layout_task::ContentBox(node)) {
match (*content).query_layout(layout_task::ContentBox(*node)) {
Ok(rect) => rect.width,
Err(()) => 0
}

View file

@ -0,0 +1,65 @@
use content::content_task::task_from_context;
use dom::element::Element;
use dom::node::AbstractNode;
use dom::bindings::codegen::HTMLCollectionBinding;
use dom::bindings::utils::{DOMString, ErrorResult, OpaqueBindingReference};
use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache};
use js::jsapi::{JSObject, JSContext};
pub struct HTMLCollection {
elements: ~[AbstractNode],
wrapper: WrapperCache
}
pub impl HTMLCollection {
static fn new(elements: ~[AbstractNode]) -> HTMLCollection {
HTMLCollection {
elements: elements,
wrapper: WrapperCache::new()
}
}
fn Length(&self) -> u32 {
self.elements.len() as u32
}
fn Item(&self, index: u32) -> Option<AbstractNode> {
if index < self.Length() {
Some(self.elements[index])
} else {
None
}
}
fn NamedItem(&self, cx: *JSContext, name: DOMString, rv: &mut ErrorResult) -> *JSObject {
*rv = Ok(());
ptr::null()
}
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<AbstractNode> {
*found = true;
self.Item(index)
}
}
impl BindingObject for HTMLCollection {
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
let content = task_from_context(cx);
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
}
}
impl CacheableWrapper for HTMLCollection {
fn get_wrappercache(&mut self) -> &mut WrapperCache {
unsafe { cast::transmute(&self.wrapper) }
}
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
HTMLCollectionBinding::Wrap(cx, scope, self, &mut unused)
}
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
fail!(~"nyi")
}
}

View file

@ -13,9 +13,10 @@ use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_Repor
JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject,
JS_GetInternedStringCharsAndLength, JS_DefineProperties,
JS_WrapValue, JS_GetObjectPrototype, JS_ForwardGetPropertyTo,
JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject,
JS_EncodeString, JS_free};
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass};
use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
RESOLVE_STUB};
use js::glue::bindgen::*;
@ -25,6 +26,9 @@ use content::content_task::{Content, task_from_context};
use core::hashmap::linear;
use dom::bindings::node;
use dom::node::AbstractNode;
const TOSTRING_CLASS_RESERVED_SLOT: u64 = 0;
const TOSTRING_NAME_RESERVED_SLOT: u64 = 1;
@ -131,15 +135,11 @@ pub fn jsval_to_str(cx: *JSContext, v: JSVal) -> Result<~str, ()> {
}
}
let len = 0;
let chars = JS_GetStringCharsZAndLength(cx, jsstr, ptr::to_unsafe_ptr(&len));
return if chars.is_null() {
Err(())
} else {
unsafe {
let buf = vec::raw::from_buf_raw(chars as *u8, len as uint);
Ok(str::from_bytes(buf))
}
unsafe {
let strbuf = JS_EncodeString(cx, jsstr);
let buf = str::raw::from_buf(strbuf as *u8);
JS_free(cx, strbuf as *libc::c_void);
Ok(buf)
}
}
@ -330,7 +330,7 @@ pub struct ConstantSpec {
pub struct DOMClass {
// A list of interfaces that this object implements, in order of decreasing
// derivedness.
interface_chain: [prototypes::id::Prototype * 2 /*prototypes::id::_ID_Count*/],
interface_chain: [prototypes::id::Prototype * 2 /*max prototype chain length*/],
unused: bool, // DOMObjectIsISupports (always false)
native_hooks: *NativePropertyHooks
@ -353,6 +353,7 @@ pub mod prototypes {
pub enum Prototype {
ClientRect,
ClientRectList,
HTMLCollection,
_ID_Count
}
}
@ -540,7 +541,7 @@ pub extern fn ThrowingConstructor(cx: *JSContext, argc: uint, vp: *JSVal) -> JSB
}
pub fn initialize_global(global: *JSObject) {
let protoArray = @mut [0 as *JSObject, ..2]; //XXXjdm number of constructors
let protoArray = @mut [0 as *JSObject, ..3]; //XXXjdm prototypes::_ID_COUNT
unsafe {
//XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray);
@ -777,4 +778,27 @@ pub fn InitIds(cx: *JSContext, specs: &[JSPropertySpec], ids: &mut [jsid]) -> bo
}
}
rval
}
}
pub trait DerivedWrapper {
fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32;
}
impl DerivedWrapper for AbstractNode {
fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
let cache = self.get_wrappercache();
let wrapper = cache.get_wrapper();
if wrapper.is_not_null() {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
return 1;
}
unsafe { *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, self).ptr) };
return 1;
}
}
pub enum Error {
FailureUnknown
}
pub type ErrorResult = Result<(), Error>;

View file

@ -1,3 +1,5 @@
use dom::bindings::htmlcollection::HTMLCollection;
use dom::bindings::utils::{DOMString, WrapperCache, str};
use dom::node::AbstractNode;
use newcss::stylesheet::Stylesheet;
@ -5,10 +7,32 @@ use std::arc::ARC;
pub struct Document {
root: AbstractNode,
wrapper: WrapperCache
}
pub fn Document(root: AbstractNode) -> Document {
Document {
root: root,
wrapper: WrapperCache::new()
}
}
pub impl Document {
fn getElementsByTagName(&self, tag: DOMString) -> Option<~HTMLCollection> {
let mut elements = ~[];
let tag = match tag {
str(s) => s,
_ => ~""
};
let _ = for self.root.traverse_preorder |child| {
if child.is_element() {
do child.with_imm_element |elem| {
if elem.tag_name == tag {
elements.push(child);
}
}
}
};
Some(~HTMLCollection::new(elements))
}
}

View file

@ -390,4 +390,7 @@ pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @
fail_unless!(codegen::ClientRectListBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
fail_unless!(codegen::HTMLCollectionBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
}

View file

@ -49,9 +49,11 @@ pub mod dom {
pub mod proxyhandler;
pub mod clientrect;
pub mod clientrectlist;
pub mod htmlcollection;
pub mod codegen {
pub mod ClientRectBinding;
pub mod ClientRectListBinding;
pub mod HTMLCollectionBinding;
}
}
pub mod document;

View file

@ -1 +1,11 @@
<script src="test_bindings.js"></script>
<html>
<head>
<script src="test_bindings.js"></script>
</head>
<body>
<div id="first"></div>
<div id="second"></div>
<span id="third"></div>
<div id="fourth"></div>
</body>
</html>

View file

@ -23,3 +23,12 @@ window.alert(rect.right);
window.alert(rect.width);
window.alert(rect.height);
window.alert("HTMLCollection:");
let tags = document.getElementsByTagName("head");
//let tag = tags[0];
window.alert(tags);
window.alert(tags.length);
window.alert(tags[0]);
window.alert(tags[1]);
window.alert(tags[2]);
window.alert(tags[3]);