mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Initial implementation of ownPropertyKeys proxy handler
Generates `SupportedPropertyNames` on DOM structs that should implement it. Most of them are unimplemented now (which can be implemented in later PRs), with the exception of `HTMLCollection`. Also added a couple relevant WPT tests. Closes #6390 Closes #2215
This commit is contained in:
parent
a5fbb2f2a6
commit
b11be4d253
13 changed files with 237 additions and 21 deletions
|
@ -2473,7 +2473,7 @@ let traps = ProxyTraps {
|
||||||
enter: None,
|
enter: None,
|
||||||
getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
|
getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
|
||||||
defineProperty: Some(%s),
|
defineProperty: Some(%s),
|
||||||
ownPropertyKeys: Some(proxyhandler::own_property_keys),
|
ownPropertyKeys: Some(own_property_keys),
|
||||||
delete_: Some(%s),
|
delete_: Some(%s),
|
||||||
enumerate: None,
|
enumerate: None,
|
||||||
preventExtensions: Some(proxyhandler::prevent_extensions),
|
preventExtensions: Some(proxyhandler::prevent_extensions),
|
||||||
|
@ -4178,6 +4178,59 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
|
||||||
return CGGeneric(self.getBody())
|
return CGGeneric(self.getBody())
|
||||||
|
|
||||||
|
|
||||||
|
class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
|
||||||
|
def __init__(self, descriptor):
|
||||||
|
args = [Argument('*mut JSContext', 'cx'),
|
||||||
|
Argument('HandleObject', 'proxy'),
|
||||||
|
Argument('*mut AutoIdVector', 'props')]
|
||||||
|
CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "u8", args)
|
||||||
|
self.descriptor = descriptor
|
||||||
|
|
||||||
|
def getBody(self):
|
||||||
|
body = dedent(
|
||||||
|
"""
|
||||||
|
let unwrapped_proxy = UnwrapProxy(proxy);
|
||||||
|
""")
|
||||||
|
|
||||||
|
if self.descriptor.operations['IndexedGetter']:
|
||||||
|
body += dedent(
|
||||||
|
"""
|
||||||
|
for i in 0..(*unwrapped_proxy).Length() {
|
||||||
|
let rooted_jsid = RootedId::new(cx, int_to_jsid(i as i32));
|
||||||
|
AppendToAutoIdVector(props, rooted_jsid.handle().get());
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
if self.descriptor.operations['NamedGetter']:
|
||||||
|
body += dedent(
|
||||||
|
"""
|
||||||
|
for name in (*unwrapped_proxy).SupportedPropertyNames() {
|
||||||
|
let cstring = CString::new(name).unwrap();
|
||||||
|
let jsstring = JS_InternString(cx, cstring.as_ptr());
|
||||||
|
let mut rooted = RootedString::new(cx, jsstring);
|
||||||
|
let jsid = INTERNED_STRING_TO_JSID(cx, rooted.handle().get());
|
||||||
|
let rooted_jsid = RootedId::new(cx, jsid);
|
||||||
|
AppendToAutoIdVector(props, rooted_jsid.handle().get());
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
body += dedent(
|
||||||
|
"""
|
||||||
|
let expando = get_expando_object(proxy);
|
||||||
|
if !expando.is_null() {
|
||||||
|
let rooted_expando = RootedObject::new(cx, expando);
|
||||||
|
GetPropertyKeys(cx, rooted_expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSTrue;
|
||||||
|
""")
|
||||||
|
|
||||||
|
return body
|
||||||
|
|
||||||
|
def definition_body(self):
|
||||||
|
return CGGeneric(self.getBody())
|
||||||
|
|
||||||
|
|
||||||
class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
|
class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
|
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
|
||||||
|
@ -4496,6 +4549,14 @@ class CGInterfaceTrait(CGThing):
|
||||||
infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
|
infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
|
||||||
if operation.isGetter():
|
if operation.isGetter():
|
||||||
arguments = method_arguments(descriptor, rettype, arguments, trailing=("found", "&mut bool"))
|
arguments = method_arguments(descriptor, rettype, arguments, trailing=("found", "&mut bool"))
|
||||||
|
|
||||||
|
# If this interface 'supports named properties', then we
|
||||||
|
# should be able to access 'supported property names'
|
||||||
|
#
|
||||||
|
# WebIDL, Second Draft, section 3.2.4.5
|
||||||
|
# https://heycam.github.io/webidl/#idl-named-properties
|
||||||
|
if operation.isNamed():
|
||||||
|
yield "SupportedPropertyNames", [], "Vec<DOMString>"
|
||||||
else:
|
else:
|
||||||
arguments = method_arguments(descriptor, rettype, arguments)
|
arguments = method_arguments(descriptor, rettype, arguments)
|
||||||
rettype = return_type(descriptor, rettype, infallible)
|
rettype = return_type(descriptor, rettype, infallible)
|
||||||
|
@ -4600,6 +4661,7 @@ class CGDescriptor(CGThing):
|
||||||
# cgThings.append(CGProxyIsProxy(descriptor))
|
# cgThings.append(CGProxyIsProxy(descriptor))
|
||||||
cgThings.append(CGProxyUnwrap(descriptor))
|
cgThings.append(CGProxyUnwrap(descriptor))
|
||||||
cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
|
cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
|
||||||
|
cgThings.append(CGDOMJSProxyHandler_ownPropertyKeys(descriptor))
|
||||||
cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor))
|
cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor))
|
||||||
cgThings.append(CGDOMJSProxyHandler_className(descriptor))
|
cgThings.append(CGDOMJSProxyHandler_className(descriptor))
|
||||||
cgThings.append(CGDOMJSProxyHandler_get(descriptor))
|
cgThings.append(CGDOMJSProxyHandler_get(descriptor))
|
||||||
|
@ -4958,6 +5020,7 @@ class CGBindingRoot(CGThing):
|
||||||
'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}',
|
'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}',
|
||||||
'js::{JSCLASS_RESERVED_SLOTS_MASK}',
|
'js::{JSCLASS_RESERVED_SLOTS_MASK}',
|
||||||
'js::{JSPROP_ENUMERATE, JSPROP_SHARED}',
|
'js::{JSPROP_ENUMERATE, JSPROP_SHARED}',
|
||||||
|
'js::{JSITER_OWNONLY, JSITER_HIDDEN, JSITER_SYMBOLS}',
|
||||||
'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}',
|
'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}',
|
||||||
'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
|
'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
|
||||||
'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}',
|
'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}',
|
||||||
|
@ -4967,20 +5030,22 @@ class CGBindingRoot(CGThing):
|
||||||
'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}',
|
'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}',
|
||||||
'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject}',
|
'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject}',
|
||||||
'js::jsapi::{RootedValue, JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}',
|
'js::jsapi::{RootedValue, JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}',
|
||||||
|
'js::jsapi::{RootedId, JS_InternString, RootedString, INTERNED_STRING_TO_JSID}',
|
||||||
'js::jsapi::{JSPropertySpec}',
|
'js::jsapi::{JSPropertySpec}',
|
||||||
'js::jsapi::{JSString, JSTracer, JSJitInfo, JSJitInfo_OpType, JSJitInfo_AliasSet}',
|
'js::jsapi::{JSString, JSTracer, JSJitInfo, JSJitInfo_OpType, JSJitInfo_AliasSet}',
|
||||||
'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}',
|
'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}',
|
||||||
'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}',
|
'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}',
|
||||||
'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}',
|
'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}',
|
||||||
'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}',
|
'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}',
|
||||||
'js::jsapi::GetGlobalForObjectCrossCompartment',
|
'js::jsapi::{GetGlobalForObjectCrossCompartment, AutoIdVector, GetPropertyKeys}',
|
||||||
'js::jsval::JSVal',
|
'js::jsval::JSVal',
|
||||||
'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}',
|
'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}',
|
||||||
'js::jsval::{NullValue, UndefinedValue}',
|
'js::jsval::{NullValue, UndefinedValue}',
|
||||||
'js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, CreateProxyHandler}',
|
'js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, CreateProxyHandler}',
|
||||||
'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}',
|
'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}',
|
||||||
'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
|
'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
|
||||||
'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}',
|
'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING, int_to_jsid}',
|
||||||
|
'js::glue::AppendToAutoIdVector',
|
||||||
'js::rust::GCMethods',
|
'js::rust::GCMethods',
|
||||||
'js::{JSTrue, JSFalse}',
|
'js::{JSTrue, JSFalse}',
|
||||||
'dom::bindings',
|
'dom::bindings',
|
||||||
|
|
|
@ -11,7 +11,6 @@ use dom::bindings::utils::delete_property_by_id;
|
||||||
use js::glue::GetProxyExtra;
|
use js::glue::GetProxyExtra;
|
||||||
use js::glue::InvokeGetOwnPropertyDescriptor;
|
use js::glue::InvokeGetOwnPropertyDescriptor;
|
||||||
use js::glue::{SetProxyExtra, GetProxyHandler};
|
use js::glue::{SetProxyExtra, GetProxyHandler};
|
||||||
use js::jsapi::AutoIdVector;
|
|
||||||
use js::jsapi::GetObjectProto;
|
use js::jsapi::GetObjectProto;
|
||||||
use js::jsapi::{Handle, HandleObject, HandleId, MutableHandle, RootedObject, ObjectOpResult};
|
use js::jsapi::{Handle, HandleObject, HandleId, MutableHandle, RootedObject, ObjectOpResult};
|
||||||
use js::jsapi::{JSContext, JSPropertyDescriptor, JSObject};
|
use js::jsapi::{JSContext, JSPropertyDescriptor, JSObject};
|
||||||
|
@ -83,15 +82,6 @@ pub unsafe extern fn delete(cx: *mut JSContext, proxy: HandleObject, id: HandleI
|
||||||
delete_property_by_id(cx, expando.handle(), id, bp)
|
delete_property_by_id(cx, expando.handle(), id, bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stub for ownPropertyKeys
|
|
||||||
pub unsafe extern fn own_property_keys(_cx: *mut JSContext,
|
|
||||||
_proxy: HandleObject,
|
|
||||||
_props: *mut AutoIdVector) -> u8 {
|
|
||||||
// FIXME: implement this
|
|
||||||
// https://github.com/servo/servo/issues/6390
|
|
||||||
JSTrue
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Controls whether the Extensible bit can be changed
|
/// Controls whether the Extensible bit can be changed
|
||||||
pub unsafe extern fn prevent_extensions(_cx: *mut JSContext,
|
pub unsafe extern fn prevent_extensions(_cx: *mut JSContext,
|
||||||
_proxy: HandleObject,
|
_proxy: HandleObject,
|
||||||
|
|
|
@ -1912,6 +1912,12 @@ impl<'a> DocumentMethods for &'a Document {
|
||||||
collection.r().reflector().get_jsobject().get()
|
collection.r().reflector().get_jsobject().get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/#document
|
||||||
|
fn SupportedPropertyNames(self) -> Vec<DOMString> {
|
||||||
|
// FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
global_event_handlers!();
|
global_event_handlers!();
|
||||||
event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange);
|
event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,5 +67,10 @@ impl<'a> DOMStringMapMethods for &'a DOMStringMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#domstringmap
|
||||||
|
fn SupportedPropertyNames(self) -> Vec<DOMString> {
|
||||||
|
// FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -227,5 +227,30 @@ impl<'a> HTMLCollectionMethods for &'a HTMLCollection {
|
||||||
*found = maybe_elem.is_some();
|
*found = maybe_elem.is_some();
|
||||||
maybe_elem
|
maybe_elem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#interface-htmlcollection
|
||||||
|
fn SupportedPropertyNames(self) -> Vec<DOMString> {
|
||||||
|
// Step 1
|
||||||
|
let mut result = vec![];
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
let ref filter = self.collection.1;
|
||||||
|
let root = self.collection.0.root();
|
||||||
|
let elems = HTMLCollection::traverse(root.r()).filter(|element| filter.filter(element.r(), root.r()));
|
||||||
|
for elem in elems {
|
||||||
|
// Step 2.1
|
||||||
|
let id_attr = elem.get_string_attribute(&atom!("id"));
|
||||||
|
if !id_attr.is_empty() && !result.contains(&id_attr) {
|
||||||
|
result.push(id_attr)
|
||||||
|
}
|
||||||
|
// Step 2.2
|
||||||
|
let name_attr = elem.get_string_attribute(&atom!("name"));
|
||||||
|
if !name_attr.is_empty() && !result.contains(&name_attr) && *elem.namespace() == ns!(HTML) {
|
||||||
|
result.push(name_attr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -105,5 +105,9 @@ impl<'a> NamedNodeMapMethods for &'a NamedNodeMap {
|
||||||
*found = item.is_some();
|
*found = item.is_some();
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fn SupportedPropertyNames(self) -> Vec<DOMString> {
|
||||||
|
// FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -134,6 +134,11 @@ impl<'a> StorageMethods for &'a Storage {
|
||||||
fn NamedDeleter(self, name: DOMString) {
|
fn NamedDeleter(self, name: DOMString) {
|
||||||
self.RemoveItem(name);
|
self.RemoveItem(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn SupportedPropertyNames(self) -> Vec<DOMString> {
|
||||||
|
// FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PrivateStorageHelpers {
|
trait PrivateStorageHelpers {
|
||||||
|
|
|
@ -16,7 +16,8 @@ pub struct TestBindingProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TestBindingProxyMethods for &'a TestBindingProxy {
|
impl<'a> TestBindingProxyMethods for &'a TestBindingProxy {
|
||||||
|
fn Length(self) -> u32 {0}
|
||||||
|
fn SupportedPropertyNames(self) -> Vec<DOMString> {vec![]}
|
||||||
fn GetNamedItem(self, _: DOMString) -> DOMString {"".to_owned()}
|
fn GetNamedItem(self, _: DOMString) -> DOMString {"".to_owned()}
|
||||||
fn SetNamedItem(self, _: DOMString, _: DOMString) -> () {}
|
fn SetNamedItem(self, _: DOMString, _: DOMString) -> () {}
|
||||||
fn GetItem(self, _: u32) -> DOMString {"".to_owned()}
|
fn GetItem(self, _: u32) -> DOMString {"".to_owned()}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// web pages.
|
// web pages.
|
||||||
|
|
||||||
interface TestBindingProxy : TestBinding {
|
interface TestBindingProxy : TestBinding {
|
||||||
|
readonly attribute unsigned long length;
|
||||||
|
|
||||||
getter DOMString getNamedItem(DOMString name);
|
getter DOMString getNamedItem(DOMString name);
|
||||||
|
|
||||||
|
|
|
@ -13071,6 +13071,10 @@
|
||||||
"path": "dom/collections/HTMLCollection-empty-name.html",
|
"path": "dom/collections/HTMLCollection-empty-name.html",
|
||||||
"url": "/dom/collections/HTMLCollection-empty-name.html"
|
"url": "/dom/collections/HTMLCollection-empty-name.html"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "dom/collections/HTMLCollection-supported-property-names.html",
|
||||||
|
"url": "/dom/collections/HTMLCollection-supported-property-names.html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "dom/events/Event-constants.html",
|
"path": "dom/events/Event-constants.html",
|
||||||
"url": "/dom/events/Event-constants.html"
|
"url": "/dom/events/Event-constants.html"
|
||||||
|
@ -18071,6 +18075,10 @@
|
||||||
"path": "js/builtins/Object.prototype.freeze.html",
|
"path": "js/builtins/Object.prototype.freeze.html",
|
||||||
"url": "/js/builtins/Object.prototype.freeze.html"
|
"url": "/js/builtins/Object.prototype.freeze.html"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "js/builtins/Object.prototype.getOwnPropertyNames.html",
|
||||||
|
"url": "/js/builtins/Object.prototype.getOwnPropertyNames.html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "js/builtins/Object.prototype.hasOwnProperty-order.html",
|
"path": "js/builtins/Object.prototype.hasOwnProperty-order.html",
|
||||||
"url": "/js/builtins/Object.prototype.hasOwnProperty-order.html"
|
"url": "/js/builtins/Object.prototype.hasOwnProperty-order.html"
|
||||||
|
|
|
@ -5,7 +5,3 @@
|
||||||
|
|
||||||
[document.forms iteration]
|
[document.forms iteration]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[document.forms getOwnPropertyNames]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<link rel=help href=https://dom.spec.whatwg.org/#interface-htmlcollection>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
|
||||||
|
<div id=log></div>
|
||||||
|
|
||||||
|
<!-- with no attribute -->
|
||||||
|
<span></span>
|
||||||
|
|
||||||
|
<!-- with `id` attribute -->
|
||||||
|
<span id=''></span>
|
||||||
|
<span id='some-id'></span>
|
||||||
|
<span id='some-id'></span><!-- to ensure no duplicates -->
|
||||||
|
|
||||||
|
<!-- with `name` attribute -->
|
||||||
|
<span name=''></span>
|
||||||
|
<span name='some-name'></span>
|
||||||
|
<span name='some-name'></span><!-- to ensure no duplicates -->
|
||||||
|
|
||||||
|
<!-- with `name` and `id` attribute -->
|
||||||
|
<span id='another-id' name='another-name'></span>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
test(function () {
|
||||||
|
var elements = document.getElementsByTagName("span");
|
||||||
|
assert_array_equals(
|
||||||
|
Object.getOwnPropertyNames(elements),
|
||||||
|
['0', '1', '2', '3', '4', '5', '6', '7', 'some-id', 'some-name', 'another-id', 'another-name']
|
||||||
|
);
|
||||||
|
}, 'Object.getOwnPropertyNames on HTMLCollection');
|
||||||
|
|
||||||
|
test(function () {
|
||||||
|
var elem = document.createElementNS('some-random-namespace', 'foo');
|
||||||
|
this.add_cleanup(function () {elem.remove();});
|
||||||
|
elem.setAttribute("name", "some-name");
|
||||||
|
document.body.appendChild(elem);
|
||||||
|
|
||||||
|
var elements = document.getElementsByTagName("foo");
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(elements), ['0']);
|
||||||
|
}, 'Object.getOwnPropertyNames on HTMLCollection with non-HTML namespace');
|
||||||
|
|
||||||
|
test(function () {
|
||||||
|
var elem = document.createElement('foo');
|
||||||
|
this.add_cleanup(function () {elem.remove();});
|
||||||
|
document.body.appendChild(elem);
|
||||||
|
|
||||||
|
var elements = document.getElementsByTagName("foo");
|
||||||
|
elements.someProperty = "some value";
|
||||||
|
|
||||||
|
assert_array_equals(Object.getOwnPropertyNames(elements), ['0', 'someProperty']);
|
||||||
|
}, 'Object.getOwnPropertyNames on HTMLCollection with expando object');
|
||||||
|
</script>
|
|
@ -0,0 +1,56 @@
|
||||||
|
<!doctype html>
|
||||||
|
<title>Object.prototype.getOwnPropertyNames</title>
|
||||||
|
<link rel=help href=http://es5.github.io/#x15.2.3.4>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
|
||||||
|
<div id=log></div>
|
||||||
|
<script>
|
||||||
|
test(function () {
|
||||||
|
var obj = {0: 'a', 1: 'b', 2: 'c'};
|
||||||
|
assert_array_equals(
|
||||||
|
Object.getOwnPropertyNames(obj).sort(),
|
||||||
|
['0', '1', '2']
|
||||||
|
);
|
||||||
|
}, "object");
|
||||||
|
|
||||||
|
test(function () {
|
||||||
|
var arr = ['a', 'b', 'c'];
|
||||||
|
assert_array_equals(
|
||||||
|
Object.getOwnPropertyNames(arr).sort(),
|
||||||
|
['0', '1', '2', 'length']
|
||||||
|
);
|
||||||
|
}, "array-like");
|
||||||
|
|
||||||
|
test(function () {
|
||||||
|
var obj = Object.create({}, {
|
||||||
|
getFoo: {
|
||||||
|
value: function() { return this.foo; },
|
||||||
|
enumerable: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
obj.foo = 1;
|
||||||
|
assert_array_equals(
|
||||||
|
Object.getOwnPropertyNames(obj).sort(),
|
||||||
|
['foo', 'getFoo']
|
||||||
|
);
|
||||||
|
}, "non-enumerable property");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
function ParentClass() {}
|
||||||
|
ParentClass.prototype.inheritedMethod = function() {};
|
||||||
|
|
||||||
|
function ChildClass() {
|
||||||
|
this.prop = 5;
|
||||||
|
this.method = function() {};
|
||||||
|
}
|
||||||
|
ChildClass.prototype = new ParentClass;
|
||||||
|
ChildClass.prototype.prototypeMethod = function() {};
|
||||||
|
|
||||||
|
var obj = new ChildClass;
|
||||||
|
assert_array_equals(
|
||||||
|
Object.getOwnPropertyNames(obj).sort(),
|
||||||
|
['method', 'prop']
|
||||||
|
);
|
||||||
|
}, 'items on the prototype chain are not listed');
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue