Initial support for Document, EventTarget, NodeList and Iterator (#541)

* Adding document and node support

* Initial support for Document, EventTarget, NodeList and Iterator

* Add in support for output option type
This commit is contained in:
Jonathan Kingston 2018-07-24 15:00:46 +01:00 committed by Alex Crichton
parent 15d0fcfcf4
commit 4b4bed5ce2
9 changed files with 229 additions and 14 deletions

View File

@ -517,6 +517,10 @@ impl ToTokens for ast::ImportType {
fn none() -> Self::Abi { 0 }
}
impl<'a> ::wasm_bindgen::convert::OptionIntoWasmAbi for &'a #name {
fn none() -> Self::Abi { 0 }
}
impl ::wasm_bindgen::convert::FromWasmAbi for #name {
type Abi = <::wasm_bindgen::JsValue as
::wasm_bindgen::convert::FromWasmAbi>::Abi;

View File

@ -10,6 +10,20 @@ pub enum ImportedTypeKind {
Reference,
}
impl<T> ImportedTypes for Option<T>
where
T: ImportedTypes,
{
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
if let Some(inner) = self {
inner.imported_types(f);
}
}
}
/// Iterate over definitions of and references to imported types in the AST.
pub trait ImportedTypes {
fn imported_types<F>(&self, f: &mut F)
@ -147,19 +161,74 @@ impl ImportedTypes for syn::TypePath {
where
F: FnMut(&Ident, ImportedTypeKind),
{
if self.qself.is_some()
|| self.path.leading_colon.is_some()
|| self.path.segments.len() != 1
{
return;
self.qself.imported_types(f);
self.path.imported_types(f);
}
}
impl ImportedTypes for syn::QSelf {
fn imported_types<F>(&self, _: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
// TODO
}
}
impl ImportedTypes for syn::Path {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
for seg in self.segments.iter() {
seg.arguments.imported_types(f);
}
f(
&self.path.segments.last().unwrap().value().ident,
&self.segments.last().unwrap().value().ident,
ImportedTypeKind::Reference,
);
}
}
impl ImportedTypes for syn::PathArguments {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
match self {
syn::PathArguments::AngleBracketed(data) => {
for arg in data.args.iter() {
arg.imported_types(f);
}
}
//TOCHECK
syn::PathArguments::Parenthesized(data) => {
for input in data.inputs.iter() {
input.imported_types(f);
}
// TODO do we need to handle output here?
// https://docs.rs/syn/0.14.0/syn/struct.ParenthesizedGenericArguments.html
}
syn::PathArguments::None => {}
}
}
}
impl ImportedTypes for syn::GenericArgument {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
match self {
syn::GenericArgument::Lifetime(_) => {}
syn::GenericArgument::Type(ty) => ty.imported_types(f),
syn::GenericArgument::Binding(_) => {}, // TODO
syn::GenericArgument::Const(_) => {}, // TODO
}
}
}
impl ImportedTypes for ast::ImportFunction {
fn imported_types<F>(&self, f: &mut F)
where

View File

@ -13,7 +13,11 @@ fn element() {
#[wasm_bindgen]
pub fn test_element(element: &web_sys::Element) {
assert_eq!(element.local_name(), "div", "Shouldn't have a div local name");
/* Tests needed for:
namespace_uri
*/
assert_eq!(element.prefix(), None, "Shouldn't have a prefix");
assert_eq!(element.local_name(), "div", "Should have a div local name");
assert_eq!(element.tag_name(), "div", "Should be a div tag");
assert!(!element.has_attribute("id"), "Shouldn't have an id");
element.set_id("beep");
@ -27,7 +31,11 @@ fn element() {
assert_eq!(element.class_name(), "", "Shouldn't have a class name");
element.set_class_name("test thing");
assert_eq!(element.class_name(), "test thing", "Should have a class name");
assert_eq!(element.get_attribute("class").unwrap(), "test thing", "Should have a class name");
assert_eq!(element.remove_attribute("class").unwrap(), (), "Should return nothing if removed");
/* Tests needed for:
get_attribute_ns
*/
/*TODO should we enable toggle_attribute tests? (Firefox Nightly + Chrome canary only)
// TODO toggle_attribute should permit a single argument when optional arguments are supported
@ -44,11 +52,19 @@ fn element() {
// TODO check get_attribute here when supported
assert_eq!(element.remove_attribute("title").unwrap(), (), "Should return nothing if removed");
assert!(!element.has_attribute("title"), "Should not have a title");
/* Tests needed for:
set_attribute_ns
*/
assert!(!element.has_attributes(), "Should not have any attributes");
assert_eq!(element.set_attribute("title", "boop").unwrap(), (), "Should return nothing if set correctly");
assert!(element.has_attributes(), "Should have attributes");
assert_eq!(element.remove_attribute("title").unwrap(), (), "Should return nothing if removed");
/* Tests needed for:
remove_attribute_ns
has_attribure_ns
closest
*/
assert_eq!(element.matches(".this-is-a-thing").unwrap(), false, "Should not match selector");
assert_eq!(element.webkit_matches_selector(".this-is-a-thing").unwrap(), false, "Should not match selector");
@ -57,15 +73,53 @@ fn element() {
assert_eq!(element.webkit_matches_selector(".this-is-a-thing").unwrap(), true, "Should match selector");
assert_eq!(element.remove_attribute("class").unwrap(), (), "Should return nothing if removed");
// TODO non standard moz_matches_selector should we even support?
/* Tests needed for:
insert_adjacent_element
insert_adjacent_text
set_pointer_capture
release_pointer_capture
has_pointer_capture
set_capture
release_capture
scroll_top
set_scroll_top
scroll_left
set_scroll_left
scroll_width
scroll_height
scroll,
scroll_to
scroll_by
client_top
client_left
client_width
client_height
scroll_top_max
scroll_left_max
*/
assert_eq!(element.inner_html(), "", "Should return no content");
element.set_inner_html("<strong>Hey!</strong><em>Web!</em>");
assert_eq!(element.inner_html(), "<strong>Hey!</strong><em>Web!</em>", "Should return HTML conent");
assert_eq!(element.query_selector_all("strong").unwrap().length(), 1, "Should return one element");
assert!(element.query_selector("strong").unwrap().is_some(), "Should return an element");
element.set_inner_html("");
assert_eq!(element.inner_html(), "", "Should return no content");
/* Tests needed for:
outer_html
set_outer_html
insert_adjacent_html
*/
assert!(element.query_selector(".none-existant").unwrap().is_none(), "Should return no results");
assert_eq!(element.query_selector_all(".none-existant").unwrap().length(), 0, "Should return no results");
/* Tests needed for:
slot
set_slot
request_fullscreen
request_pointer_lock
*/
}
"#,

View File

@ -14,6 +14,7 @@
* https://drafts.csswg.org/cssom-view/#extensions-to-the-document-interface
*/
/*TODO
interface WindowProxy;
interface nsISupports;
interface URI;
@ -21,6 +22,7 @@ interface nsIDocShell;
interface nsILoadGroup;
enum VisibilityState { "hidden", "visible" };
*/
/* https://dom.spec.whatwg.org/#dictdef-elementcreationoptions */
dictionary ElementCreationOptions {
@ -33,8 +35,11 @@ dictionary ElementCreationOptions {
/* https://dom.spec.whatwg.org/#interface-document */
[Constructor]
interface Document : Node {
/*TODO
[Throws]
readonly attribute DOMImplementation implementation;
*/
[Pure, Throws, BinaryName="documentURIFromJS", NeedsCallerType]
readonly attribute DOMString URL;
[Pure, Throws, BinaryName="documentURIFromJS", NeedsCallerType]
@ -54,6 +59,7 @@ interface Document : Node {
readonly attribute DocumentType? doctype;
[Pure]
readonly attribute Element? documentElement;
[Pure]
HTMLCollection getElementsByTagName(DOMString localName);
[Pure, Throws]
@ -73,8 +79,10 @@ interface Document : Node {
Text createTextNode(DOMString data);
[NewObject]
Comment createComment(DOMString data);
/*TODO
[NewObject, Throws]
ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
*/
[CEReactions, Throws]
Node importNode(Node node, optional boolean deep = false);
@ -84,8 +92,10 @@ interface Document : Node {
[NewObject, Throws, NeedsCallerType]
Event createEvent(DOMString interface);
/*TODO
[NewObject, Throws]
Range createRange();
*/
// NodeFilter.SHOW_ALL = 0xFFFFFFFF
[NewObject, Throws]
@ -100,22 +110,26 @@ interface Document : Node {
// These are not in the spec, but leave them for now for backwards compat.
// So sort of like Gecko extensions
/*TODO
[NewObject, Throws]
CDATASection createCDATASection(DOMString data);
[NewObject, Throws]
Attr createAttribute(DOMString name);
[NewObject, Throws]
Attr createAttributeNS(DOMString? namespace, DOMString name);
*/
};
// https://html.spec.whatwg.org/multipage/dom.html#the-document-object
partial interface Document {
/*TODO
[PutForwards=href, Unforgeable] readonly attribute Location? location;
//(HTML only) attribute DOMString domain;
readonly attribute DOMString referrer;
//(HTML only) attribute DOMString cookie;
readonly attribute DOMString lastModified;
readonly attribute DOMString readyState;
*/
// DOM tree accessors
//(Not proxy yet)getter object (DOMString name);
@ -135,6 +149,7 @@ partial interface Document {
[SameObject] readonly attribute HTMLCollection scripts;
[Pure]
NodeList getElementsByName(DOMString elementName);
//(Not implemented)readonly attribute DOMElementMap cssElementMap;
// dynamic markup insertion
@ -174,7 +189,9 @@ partial interface Document {
* True if this document is synthetic : stand alone image, video, audio file,
* etc.
*/
/*Non standard
[Func="IsChromeOrXBL"] readonly attribute boolean mozSyntheticDocument;
*/
/**
* Returns the script element whose script is currently being processed.
*
@ -257,17 +274,23 @@ partial interface Document {
// versions have it uppercase.
[LenientSetter, Unscopable, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
readonly attribute boolean fullscreen;
/*Non standard
[BinaryName="fullscreen"]
readonly attribute boolean mozFullScreen;
*/
[LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled", NeedsCallerType]
readonly attribute boolean fullscreenEnabled;
/*Non standard
[BinaryName="fullscreenEnabled", NeedsCallerType]
readonly attribute boolean mozFullScreenEnabled;
*/
[Func="nsDocument::IsUnprefixedFullscreenEnabled"]
void exitFullscreen();
/*Non standard
[BinaryName="exitFullscreen"]
void mozCancelFullScreen();
*/
// Events handlers
[Func="nsDocument::IsUnprefixedFullscreenEnabled"]
@ -289,8 +312,11 @@ partial interface Document {
// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface
partial interface Document {
readonly attribute boolean hidden;
/*TODO
readonly attribute VisibilityState visibilityState;
attribute EventHandler onvisibilitychange;
*/
};
// https://drafts.csswg.org/cssom/#extensions-to-the-document-interface
@ -339,6 +365,7 @@ partial interface Document {
partial interface Document {
// XBL support. Wish we could make these [ChromeOnly], but
// that would likely break bindings running with the page principal.
/*Non standard
[Func="IsChromeOrXBL"]
NodeList? getAnonymousNodes(Element elt);
[Func="IsChromeOrXBL"]
@ -348,6 +375,7 @@ partial interface Document {
Element? getBindingParent(Node node);
[Throws, Func="IsChromeOrXBL", NeedsSubjectPrincipal]
void loadBindingDocument(DOMString documentURL);
*/
// Touch bits
// XXXbz I can't find the sane spec for this stuff, so just cribbing
@ -375,10 +403,12 @@ partial interface Document {
// XXXbz and another hack for the fact that we can't usefully have optional
// distinguishing arguments but need a working zero-arg form of
// createTouchList().
/*TODO
[NewObject, Func="nsGenericHTMLElement::TouchEventsEnabled"]
TouchList createTouchList();
[NewObject, Func="nsGenericHTMLElement::TouchEventsEnabled"]
TouchList createTouchList(sequence<Touch> touches);
*/
[ChromeOnly]
attribute boolean styleSheetChangeEventsEnabled;
@ -458,8 +488,10 @@ partial interface Document {
// http://w3c.github.io/selection-api/#extensions-to-document-interface
partial interface Document {
/*TODO
[Throws]
Selection? getSelection();
*/
};
// Extension to give chrome JS the ability to determine whether
@ -478,10 +510,12 @@ partial interface Document {
// Extension to give chrome and XBL JS the ability to determine whether
// the document is sandboxed without permission to run scripts
// and whether inline scripts are blocked by the document's CSP.
/*Non standard
partial interface Document {
[Func="IsChromeOrXBL"] readonly attribute boolean hasScriptsBlockedBySandbox;
[Func="IsChromeOrXBL"] readonly attribute boolean inlineScriptAllowedByCSP;
};
*/
// For more information on Flash classification, see
// toolkit/components/url-classifier/flash-block-lists.rst

View File

@ -29,8 +29,10 @@ interface Element : Node {
attribute DOMString id;
[CEReactions, Pure]
attribute DOMString className;
/*TODO
[Constant, PutForwards=value]
readonly attribute DOMTokenList classList;
*/
[SameObject]
readonly attribute NamedNodeMap attributes;
@ -248,10 +250,8 @@ partial interface Element {
partial interface Element {
[Throws, Pure]
Element? querySelector(DOMString selectors);
/*TODO
[Throws, Pure]
NodeList querySelectorAll(DOMString selectors);
*/
};
// https://dom.spec.whatwg.org/#dictdef-shadowrootinit

View File

@ -10,8 +10,10 @@
* liability, trademark and document use rules apply.
*/
/*TODO
interface Principal;
interface URI;
*/
interface Node : EventTarget {
const unsigned short ELEMENT_NODE = 1;
@ -38,8 +40,10 @@ interface Node : EventTarget {
readonly attribute boolean isConnected;
[Pure]
readonly attribute Document? ownerDocument;
/*TODO
[Pure]
Node getRootNode(optional GetRootNodeOptions options);
*/
[Pure]
readonly attribute Node? parentNode;
[Pure]
@ -207,12 +211,16 @@ interface Node : EventTarget {
[ChromeOnly, Throws]
Promise<void> localize(L10nCallback l10nCallback);
/*Unsupported ifdef
#ifdef ACCESSIBILITY
[Func="mozilla::dom::AccessibleNode::IsAOMEnabled", SameObject]
readonly attribute AccessibleNode? accessibleNode;
#endif
*/
};
/*TODO
dictionary GetRootNodeOptions {
boolean composed = false;
};
*/

View File

@ -27,11 +27,11 @@ mod util;
use std::collections::BTreeSet;
use std::fs;
use std::io::{self, Read};
use std::iter::FromIterator;
use std::iter::{self, FromIterator};
use std::path::Path;
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
use backend::util::{ident_ty, rust_ident, wrap_import_function};
use backend::util::{ident_ty, raw_ident, rust_ident, wrap_import_function};
use failure::ResultExt;
use heck::{CamelCase, ShoutySnakeCase};
use quote::ToTokens;
@ -82,7 +82,7 @@ fn compile_ast(mut ast: backend::ast::Program) -> String {
let mut defined = BTreeSet::from_iter(
vec![
"str", "char", "bool", "JsValue", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64",
"usize", "isize", "f32", "f64", "Result", "String", "Vec",
"usize", "isize", "f32", "f64", "Result", "String", "Vec", "Option",
].into_iter()
.map(|id| proc_macro2::Ident::new(id, proc_macro2::Span::call_site())),
);
@ -401,8 +401,10 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember {
webidl::ast::InterfaceMember::Const(cnst) => {
cnst.webidl_parse(program, first_pass, self_name)
}
webidl::ast::InterfaceMember::Iterable(iterable) => {
iterable.webidl_parse(program, first_pass, self_name)
}
// TODO
webidl::ast::InterfaceMember::Iterable(_)
| webidl::ast::InterfaceMember::Maplike(_)
| webidl::ast::InterfaceMember::Setlike(_) => {
warn!("Unsupported WebIDL interface member: {:?}", self);
@ -520,6 +522,50 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
}
}
impl<'a> WebidlParse<&'a str> for webidl::ast::Iterable {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>,
self_name: &'a str,
) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) {
return Ok(());
}
/* TODO
let throws = util::throws(&self.extended_attributes);
let return_value = webidl::ast::ReturnType::NonVoid(self.value_type.clone());
let args = [];
first_pass
.create_basic_method(
&args,
Some(&"values".to_string()),
&return_value,
self_name,
false,
false, // Should be false
)
.map(wrap_import_function)
.map(|import| program.imports.push(import));
first_pass
.create_basic_method(
&args,
Some(&"keys".to_string()),
&return_value, // Should be a number
self_name,
false,
false, // Should be false
)
.map(wrap_import_function)
.map(|import| program.imports.push(import));
*/
Ok(())
}
}
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
fn webidl_parse(
&self,