Adding in initial support for all HTML*Element interfaces. (#568)

* Adding in initial support for all HTML*Element interfaces.

* Fix camelcasing of short HTML interface names

* Disabling span test as breaks on taskcluster
This commit is contained in:
Jonathan Kingston
2018-07-27 17:57:24 +01:00
committed by Alex Crichton
parent 55e2ce9b53
commit 67b43ee389
80 changed files with 489 additions and 16 deletions

View File

@ -0,0 +1,83 @@
use super::websys_project;
#[test]
fn anchor_element() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_anchor_element(element: &web_sys::HtmlAnchorElement) {
assert_eq!(element.target(), "", "Shouldn't have a target");
element.set_target("_blank");
assert_eq!(element.target(), "_blank", "Should have a target");
assert_eq!(element.download(), "", "Shouldn't have a download");
element.set_download("boop.png");
assert_eq!(element.download(), "boop.png", "Should have a download");
assert_eq!(element.ping(), "", "Shouldn't have a ping");
element.set_ping("boop");
assert_eq!(element.ping(), "boop", "Should have a ping");
assert_eq!(element.rel(), "", "Shouldn't have a rel");
element.set_rel("boop");
assert_eq!(element.rel(), "boop", "Should have a rel");
assert_eq!(element.referrer_policy(), "", "Shouldn't have a referrer_policy");
element.set_referrer_policy("origin");
assert_eq!(element.referrer_policy(), "origin", "Should have a referrer_policy");
assert_eq!(element.hreflang(), "", "Shouldn't have a hreflang");
element.set_hreflang("en-us");
assert_eq!(element.hreflang(), "en-us", "Should have a hreflang");
assert_eq!(element.type_(), "", "Shouldn't have a type");
element.set_type("text/plain");
assert_eq!(element.type_(), "text/plain", "Should have a type");
assert_eq!(element.text().unwrap(), "", "Shouldn't have a text");
element.set_text("Click me!").unwrap();
assert_eq!(element.text().unwrap(), "Click me!", "Should have a text");
assert_eq!(element.coords(), "", "Shouldn't have a coords");
element.set_coords("1,2,3");
assert_eq!(element.coords(), "1,2,3", "Should have a coords");
assert_eq!(element.charset(), "", "Shouldn't have a charset");
element.set_charset("thing");
assert_eq!(element.charset(), "thing", "Should have a charset");
assert_eq!(element.name(), "", "Shouldn't have a name");
element.set_name("thing");
assert_eq!(element.name(), "thing", "Should have a name");
assert_eq!(element.rev(), "", "Shouldn't have a rev");
element.set_rev("thing");
assert_eq!(element.rev(), "thing", "Should have a rev");
assert_eq!(element.shape(), "", "Shouldn't have a shape");
element.set_shape("thing");
assert_eq!(element.shape(), "thing", "Should have a shape");
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let anchor = document.createElement("a");
wasm.test_anchor_element(anchor);
}
"#,
)
.test();
}

View File

@ -0,0 +1,56 @@
use super::websys_project;
#[test]
fn body_element() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_body_element(element: &web_sys::HtmlBodyElement) {
assert_eq!(element.text(), "", "Shouldn't have a text");
element.set_text("boop");
assert_eq!(element.text(), "boop", "Should have a text");
// Legacy color setting
assert_eq!(element.link(), "", "Shouldn't have a link");
element.set_link("blue");
assert_eq!(element.link(), "blue", "Should have a link");
assert_eq!(element.v_link(), "", "Shouldn't have a v_link");
element.set_v_link("purple");
assert_eq!(element.v_link(), "purple", "Should have a v_link");
assert_eq!(element.a_link(), "", "Shouldn't have a a_link");
element.set_a_link("purple");
assert_eq!(element.a_link(), "purple", "Should have a a_link");
assert_eq!(element.bg_color(), "", "Shouldn't have a bg_color");
element.set_bg_color("yellow");
assert_eq!(element.bg_color(), "yellow", "Should have a bg_color");
assert_eq!(element.background(), "", "Shouldn't have a background");
element.set_background("image");
assert_eq!(element.background(), "image", "Should have a background");
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let body = document.createElement("body");
wasm.test_body_element(body);
}
"#,
)
.test();
}

View File

@ -0,0 +1,36 @@
use super::websys_project;
#[test]
fn br_element() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_br_element(element: &web_sys::HtmlBrElement) {
// Legacy clear method
assert_eq!(element.clear(), "", "Shouldn't have a clear");
element.set_clear("boop");
assert_eq!(element.clear(), "boop", "Should have a clear");
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let br = document.createElement("br");
wasm.test_br_element(br);
}
"#,
)
.test();
}

View File

@ -0,0 +1,35 @@
use super::websys_project;
#[test]
fn div_element() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_div_element(element: &web_sys::HtmlDivElement) {
assert_eq!(element.align(), "", "Shouldn't have a align");
element.set_align("right");
assert_eq!(element.align(), "right", "Should have a align");
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let div = document.createElement("div");
wasm.test_div_element(div);
}
"#,
)
.test();
}

View File

@ -0,0 +1,101 @@
use super::websys_project;
#[test]
fn html_element() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_html_element(element: &web_sys::HtmlElement) {
assert_eq!(element.title(), "", "Shouldn't have a title");
element.set_title("boop");
assert_eq!(element.title(), "boop", "Should have a title");
assert_eq!(element.lang(), "", "Shouldn't have a lang");
element.set_lang("en-us");
assert_eq!(element.lang(), "en-us", "Should have a lang");
assert_eq!(element.dir(), "", "Shouldn't have a dir");
element.set_dir("ltr");
assert_eq!(element.dir(), "ltr", "Should have a dir");
assert_eq!(element.inner_text(), "", "Shouldn't have inner_text");
element.set_inner_text("hey");
assert_eq!(element.inner_text(), "hey", "Should have inner_text");
assert!(!element.hidden(), "Shouldn't be hidden");
element.set_hidden(true);
assert!(element.hidden(), "Should be hidden");
// TODO add a click handler here
element.click();
assert_eq!(element.tab_index(), -1, "Shouldn't be tab_index");
element.set_tab_index(1);
assert_eq!(element.tab_index(), 1, "Should be tab_index");
// TODO add a focus handler here
assert_eq!(element.focus().unwrap(), (), "No result");
// TODO add a blur handler here
assert_eq!(element.blur().unwrap(), (), "No result");
assert_eq!(element.access_key(), "", "Shouldn't have a access_key");
element.set_access_key("a");
assert_eq!(element.access_key(), "a", "Should have a access_key");
// TODO add test for access_key_label
assert!(!element.draggable(), "Shouldn't be draggable");
element.set_draggable(true);
assert!(element.draggable(), "Should be draggable");
assert_eq!(element.content_editable(), "inherit", "Shouldn't have a content_editable");
element.set_content_editable("true");
assert_eq!(element.content_editable(), "true", "Should be content_editable");
assert!(element.is_content_editable(), "Should be content_editable");
// TODO verify case where menu is passed
match element.context_menu() {
None => assert!(true, "Shouldn't have a custom menu set"),
_ => assert!(false, "Shouldn't have a custom menu set")
};
assert!(!element.spellcheck(), "Shouldn't be spellchecked");
element.set_spellcheck(true);
assert!(element.spellcheck(), "Should be dragspellcheckedgable");
// TODO verify case where we have an offset_parent
match element.offset_parent() {
None => assert!(true, "Shouldn't have an offset_parent set"),
_ => assert!(false, "Shouldn't have a offset_parent set")
};
// TODO verify when we have offsets
assert_eq!(element.offset_top(), 0, "Shouldn't have an offset_top yet");
assert_eq!(element.offset_left(), 0, "Shouldn't have an offset_left yet");
assert_eq!(element.offset_width(), 0, "Shouldn't have an offset_width yet");
assert_eq!(element.offset_height(), 0, "Shouldn't have an offset_height yet");
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let html = document.createElement("html");
wasm.test_html_element(html);
}
"#,
)
.test();
}

View File

@ -0,0 +1,35 @@
use super::websys_project;
#[test]
fn html_html_element() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_html_html_element(element: &web_sys::HtmlHtmlElement) {
assert_eq!(element.version(), "", "Shouldn't have a version");
element.set_version("4");
assert_eq!(element.version(), "4", "Should have a version");
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let html = document.createElement("html");
wasm.test_html_html_element(html);
}
"#,
)
.test();
}

View File

@ -3,9 +3,82 @@ use project_builder::{project, Project};
mod event;
mod headers;
mod anchor_element;
mod br_element;
mod body_element;
mod div_element;
mod html_element;
mod html_html_element;
// TODO fix on taskcluster
//mod span_element;
mod response;
mod element;
mod history;
/*TODO tests for:
web_sys::HtmlFontElement,
web_sys::HtmlMenuItemElement,
web_sys::HtmlSourceElement,
web_sys::HtmlAreaElement,
web_sys::HtmlFormElement,
web_sys::HtmlMetaElement,
web_sys::HtmlAudioElement,
web_sys::HtmlFrameElement,
web_sys::HtmlMeterElement,
web_sys::HtmlStyleElement,
web_sys::HtmlBaseElement,
web_sys::HtmlFrameSetElement,
web_sys::HtmlModElement,
web_sys::HtmlTableCaptionElement,
web_sys::HtmlHeadElement,
web_sys::HtmlObjectElement,
web_sys::HtmlTableCellElement,
web_sys::HtmlHeadingElement,
web_sys::HtmlOListElement,
web_sys::HtmlTableColElement,
web_sys::HtmlButtonElement,
web_sys::HtmlHRElement,
web_sys::HtmlOptGroupElement,
web_sys::HtmlTableElement,
web_sys::HtmlCanvasElement,
web_sys::HtmlOptionElement,
web_sys::HtmlTableRowElement,
web_sys::HtmlDataElement,
web_sys::HtmlIFrameElement,
web_sys::HtmlOutputElement,
web_sys::HtmlTableSectionElement,
web_sys::HtmlDataListElement,
web_sys::HtmlImageElement,
web_sys::HtmlParagraphElement,
web_sys::HtmlTemplateElement,
web_sys::HtmlDetailsElement,
web_sys::HtmlInputElement,
web_sys::HtmlParamElement,
web_sys::HtmlTextAreaElement,
web_sys::HtmlDialogElement,
web_sys::HtmlLabelElement,
web_sys::HtmlPictureElement,
web_sys::HtmlTimeElement,
web_sys::HtmlDirectoryElement,
web_sys::HtmlLegendElement,
web_sys::HtmlPreElement,
web_sys::HtmlTitleElement,
web_sys::HtmlLIElement,
web_sys::HtmlProgressElement,
web_sys::HtmlTrackElement,
web_sys::HtmlDListElement,
web_sys::HtmlLinkElement,
web_sys::HtmlQuoteElement,
web_sys::HtmlUListElement,
web_sys::HtmlMapElement,
web_sys::HtmlScriptElement,
web_sys::HtmlVideoElement,
web_sys::HtmlEmbedElement,
web_sys::HtmlMediaElement,
web_sys::HtmlSelectElement,
web_sys::HtmlFieldSetElement,
web_sys::HtmlMenuElement,
web_sys::HtmlSlotElement,
*/
fn websys_project() -> Project {
project()

View File

@ -0,0 +1,33 @@
use super::websys_project;
#[test]
fn span_element() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_span_element(_element: &web_sys::HtmlSpanElement) {
assert!(true, "Span doesn't have an interface");
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let span = document.createElement("span");
wasm.test_span_element(span);
}
"#,
)
.test();
}

View File

@ -9,9 +9,10 @@
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
/* TODO
interface nsISupports;
interface Variant;
*/
[HTMLConstructor]
interface HTMLCanvasElement : HTMLElement {

View File

@ -11,10 +11,12 @@
* and create derivative works of this document.
*/
/* TODO
interface imgINotificationObserver;
interface imgIRequest;
interface URI;
interface nsIStreamListener;
*/
[HTMLConstructor,
NamedConstructor=Image(optional unsigned long width, optional unsigned long height)]

View File

@ -12,6 +12,7 @@
* and create derivative works of this document.
*/
/*TODO
enum SelectionMode {
"select",
"start",
@ -20,6 +21,7 @@ enum SelectionMode {
};
interface XULControllers;
*/
[HTMLConstructor]
interface HTMLInputElement : HTMLElement {
@ -97,11 +99,12 @@ interface HTMLInputElement : HTMLElement {
attribute unrestricted double valueAsNumber;
[CEReactions, SetterThrows]
attribute unsigned long width;
/* TODO
[Throws]
void stepUp(optional long n = 1);
[Throws]
void stepDown(optional long n = 1);
*/
[Pure]
readonly attribute boolean willValidate;
@ -117,14 +120,17 @@ interface HTMLInputElement : HTMLElement {
void select();
/* TODO optional u32 not supported
[Throws]
attribute unsigned long? selectionStart;
[Throws]
attribute unsigned long? selectionEnd;
*/
[Throws]
attribute DOMString? selectionDirection;
[Throws]
void setRangeText(DOMString replacement);
[Throws]
void setRangeText(DOMString replacement, unsigned long start,
unsigned long end, optional SelectionMode selectionMode = "preserve");

View File

@ -12,7 +12,9 @@
* and create derivative works of this document.
*/
/* TODO
interface MenuBuilder;
*/
// http://www.whatwg.org/specs/web-apps/current-work/#the-menu-element
[HTMLConstructor]

View File

@ -37,8 +37,10 @@ interface HTMLSelectElement : HTMLElement {
HTMLOptionElement? namedItem(DOMString name);
[CEReactions, Throws]
void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
/* TODO not permitted multiple functions with the same name
[CEReactions]
void remove(long index);
*/
[CEReactions, Throws]
setter void (unsigned long index, HTMLOptionElement? option);
@ -64,7 +66,6 @@ interface HTMLSelectElement : HTMLElement {
};
// Chrome only interface
partial interface HTMLSelectElement {
[ChromeOnly]
attribute boolean openInParentProcess;

View File

@ -10,9 +10,10 @@
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
/* TODO
interface nsIEditor;
interface XULControllers;
*/
[HTMLConstructor]
interface HTMLTextAreaElement : HTMLElement {
@ -63,10 +64,12 @@ interface HTMLTextAreaElement : HTMLElement {
readonly attribute NodeList labels;
void select();
/* TODO Optional u32 not supported
[Throws]
attribute unsigned long? selectionStart;
[Throws]
attribute unsigned long? selectionEnd;
*/
[Throws]
attribute DOMString? selectionDirection;
[Throws]

View File

@ -36,11 +36,11 @@ use std::path::Path;
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
use backend::util::{ident_ty, rust_ident, wrap_import_function};
use failure::{ResultExt, Fail};
use heck::{CamelCase, ShoutySnakeCase};
use heck::{ShoutySnakeCase};
use quote::ToTokens;
use first_pass::{FirstPass, FirstPassRecord};
use util::{public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, TypePosition};
use util::{public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident};
pub use error::{Error, ErrorKind, Result};
@ -235,7 +235,7 @@ impl WebidlParse<()> for webidl::ast::Typedef {
return Ok(());
}
let dest = rust_ident(self.name.to_camel_case().as_str());
let dest = rust_ident(camel_case_ident(&self.name).as_str());
let src = match first_pass.webidl_ty_to_syn_ty(&self.type_, TypePosition::Return) {
Some(src) => src,
None => {
@ -278,7 +278,7 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface {
js_namespace: None,
kind: backend::ast::ImportKind::Type(backend::ast::ImportType {
vis: public(),
name: rust_ident(self.name.to_camel_case().as_str()),
name: rust_ident(camel_case_ident(&self.name).as_str()),
attrs: Vec::new(),
}),
});
@ -329,7 +329,7 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
interface: &'a webidl::ast::NonPartialInterface,
) -> Result<()> {
let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| {
let self_ty = ident_ty(rust_ident(interface.name.to_camel_case().as_str()));
let self_ty = ident_ty(rust_ident(camel_case_ident(&interface.name).as_str()));
let kind = backend::ast::ImportFunctionKind::Method {
class: class.to_string(),
@ -702,11 +702,11 @@ impl<'a> WebidlParse<()> for webidl::ast::Enum {
js_namespace: None,
kind: backend::ast::ImportKind::Enum(backend::ast::ImportEnum {
vis: public(),
name: rust_ident(self.name.to_camel_case().as_str()),
name: rust_ident(camel_case_ident(&self.name).as_str()),
variants: self
.variants
.iter()
.map(|v| rust_ident(v.to_camel_case().as_str()))
.map(|v| rust_ident(camel_case_ident(&v).as_str()))
.collect(),
variant_values: self.variants.clone(),
rust_attrs: vec![parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])],
@ -729,7 +729,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Const {
program.consts.push(backend::ast::Const {
vis: public(),
name: rust_ident(self.name.to_shouty_snake_case().as_str()),
class: Some(rust_ident(self_name.to_camel_case().as_str())),
class: Some(rust_ident(camel_case_ident(&self_name).as_str())),
ty,
value: webidl_const_v_to_backend_const_v(&self.value),
});

View File

@ -20,6 +20,12 @@ fn shared_ref(ty: syn::Type) -> syn::Type {
}.into()
}
/// Fix camelcase of identifiers like HTMLBRElement
pub fn camel_case_ident(identifier: &str) -> String {
identifier.replace("HTML", "HTML_").to_camel_case()
}
/// For a webidl const type node, get the corresponding syn type node.
pub fn webidl_const_ty_to_syn_ty(ty: &webidl::ast::ConstType) -> syn::Type {
use webidl::ast::ConstType::*;
@ -157,7 +163,7 @@ impl<'a> FirstPassRecord<'a> {
// A reference to a type by name becomes the same thing in the
// bindings.
webidl::ast::TypeKind::Identifier(ref id) => {
let ty = ident_ty(rust_ident(id.to_camel_case().as_str()));
let ty = ident_ty(rust_ident(camel_case_ident(&id).as_str()));
if self.interfaces.contains(id) {
if pos == TypePosition::Argument {
shared_ref(ty)
@ -372,7 +378,7 @@ impl<'a> FirstPassRecord<'a> {
let kind = backend::ast::ImportFunctionKind::Method {
class: self_name.to_string(),
ty: ident_ty(rust_ident(self_name.to_camel_case().as_str())),
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
is_static,
kind: backend::ast::OperationKind::Regular,
@ -424,7 +430,7 @@ impl<'a> FirstPassRecord<'a> {
let kind = backend::ast::ImportFunctionKind::Method {
class: self_name.to_string(),
ty: ident_ty(rust_ident(self_name.to_camel_case().as_str())),
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
is_static,
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
@ -446,7 +452,7 @@ impl<'a> FirstPassRecord<'a> {
) -> Option<backend::ast::ImportFunction> {
let kind = backend::ast::ImportFunctionKind::Method {
class: self_name.to_string(),
ty: ident_ty(rust_ident(self_name.to_camel_case().as_str())),
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
is_static,
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),