Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

feat: add bindings for HTMLFormControlsCollection, HTMLOptionsCollection, RadioNodeList, etc #195

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
### 0.20.0

* Added bindings for `HTMLFormControlsCollection`
* Added binding for `HTMLOptionsCollection`
* Added bindings for `RadioNodeList`
* Added binding for `Document.forms`
* Added binding for `HTMLFormElement.elements`

### 0.19.1

* Removed dev dependency on `bsdoc` to allow smooth installs on non-Mac
Expand Down
186 changes: 185 additions & 1 deletion lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,193 @@
'use strict';

var Js_exn = require("bs-platform/lib/js/js_exn.js");
var Belt_Option = require("bs-platform/lib/js/belt_Option.js");
var Caml_option = require("bs-platform/lib/js/caml_option.js");
var TestHelpers = require("../../testHelpers.js");
var Webapi__Dom__Document = require("../../../src/Webapi/Dom/Webapi__Dom__Document.js");
var Webapi__Dom__HtmlFormElement = require("../../../src/Webapi/Dom/Webapi__Dom__HtmlFormElement.js");
var Webapi__Dom__HtmlFormControlsCollection = require("../../../src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.js");

var form = TestHelpers.unsafelyUnwrapOption(Webapi__Dom__HtmlFormElement.asFormElement(document.createElement("form")));

var usernameInput = document.createElement("input");

usernameInput.setAttribute("type", "text");

usernameInput.setAttribute("name", "username");

var usernameLabel = document.createElement("label");

var usernameText = document.createTextNode("Username:");

usernameLabel.appendChild(usernameText);

usernameLabel.appendChild(usernameInput);

var passwordInput = document.createElement("input");

passwordInput.setAttribute("type", "password");

passwordInput.setAttribute("name", "password");

var passwordLabel = document.createElement("label");

var passwordText = document.createTextNode("Password:");

passwordLabel.appendChild(passwordText);

passwordLabel.appendChild(passwordInput);

var radioInput1 = document.createElement("input");

radioInput1.setAttribute("type", "radio");

radioInput1.setAttribute("name", "radiogroup");

radioInput1.setAttribute("value", "one");

radioInput1.setAttribute("checked", "true");

var radioLabel1 = document.createElement("label");

var radioText1 = document.createTextNode("Choice 1:");

radioLabel1.appendChild(radioText1);

radioLabel1.appendChild(radioInput1);

var radioInput2 = document.createElement("input");

radioInput2.setAttribute("type", "radio");

radioInput2.setAttribute("name", "radiogroup");

radioInput2.setAttribute("value", "two");

var radioLabel2 = document.createElement("label");

var radioText2 = document.createTextNode("Choice 2:");

radioLabel2.appendChild(radioText2);

radioLabel2.appendChild(radioInput2);

var usernameContainer = document.createElement("div");

var passwordContainer = document.createElement("div");

var radioContainer = document.createElement("div");

usernameContainer.appendChild(usernameLabel);

passwordContainer.appendChild(passwordLabel);

radioContainer.appendChild(radioLabel1);

radioContainer.appendChild(radioLabel2);

form.appendChild(usernameContainer);

form.appendChild(passwordContainer);

form.appendChild(radioContainer);

var body = TestHelpers.unsafelyUnwrapOption(Belt_Option.flatMap(Webapi__Dom__Document.asHtmlDocument(document), (function (prim) {
return Caml_option.nullable_to_opt(prim.body);
})));

body.appendChild(form);

var collection = form.elements;

console.log("HtmlFormElement.elements:", collection);

var len = collection.length;

console.log("HtmlFormControlsCollection.length:", len);

var el0 = collection.item(0);

console.log("HtmlFormControlsCollection.item:", (el0 == null) ? undefined : Caml_option.some(el0));

var el0$1 = Webapi__Dom__HtmlFormControlsCollection.namedItem("username", collection);

console.log("HtmlFormControlsCollection.namedItem:", el0$1);

var el1 = collection.item(1);

console.log("HtmlFormControlsCollection.length:", (el1 == null) ? undefined : Caml_option.some(el1));

var el1$1 = Webapi__Dom__HtmlFormControlsCollection.namedItem("password", collection);

console.log("HtmlFormControlsCollection.namedItem:", el1$1);

var radioNodeList = collection.item(2);

console.log("HtmlFormControlsCollection.namedItem:", (radioNodeList == null) ? undefined : Caml_option.some(radioNodeList));

var radioNodeList$1 = Webapi__Dom__HtmlFormControlsCollection.namedItem("radiogroup", collection);

console.log("HtmlFormControlsCollection.namedItem:", radioNodeList$1);

var match = TestHelpers.unsafelyUnwrapOption(radioNodeList$1);

if (typeof match !== "number") {
var variant = match[0];
if (variant >= 96709417) {
if (variant >= 488741627) {
if (variant !== 516394780) {
if (variant !== 942443387) {

} else {
console.log("RadioNodeList.value", match[1].value);
}
} else {
Js_exn.raiseError("incorrect namedItem return value");
}
} else if (variant !== 242538002 && variant < 488741626) {

} else {
Js_exn.raiseError("incorrect namedItem return value");
}
} else if (variant >= -908856608) {
if (variant !== -783600662 && variant < 96709416) {

} else {
Js_exn.raiseError("incorrect namedItem return value");
}
} else if (variant !== -1055554783 && variant < -908856609) {

} else {
Js_exn.raiseError("incorrect namedItem return value");
}
}

function test_data(formElement) {
return new FormData(formElement).get("foo");
}

exports.form = form;
exports.usernameInput = usernameInput;
exports.usernameLabel = usernameLabel;
exports.usernameText = usernameText;
exports.passwordInput = passwordInput;
exports.passwordLabel = passwordLabel;
exports.passwordText = passwordText;
exports.radioInput1 = radioInput1;
exports.radioLabel1 = radioLabel1;
exports.radioText1 = radioText1;
exports.radioInput2 = radioInput2;
exports.radioLabel2 = radioLabel2;
exports.radioText2 = radioText2;
exports.usernameContainer = usernameContainer;
exports.passwordContainer = passwordContainer;
exports.radioContainer = radioContainer;
exports.body = body;
exports.collection = collection;
exports.len = len;
exports.el0 = el0$1;
exports.el1 = el1$1;
exports.radioNodeList = radioNodeList$1;
exports.test_data = test_data;
/* No side effect */
/* form Not a pure module */
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bs-webapi",
"version": "0.19.1",
"version": "0.20.0",
"description": "Reason + BuckleScript bindings to DOM",
"repository": {
"type": "git",
Expand Down
2 changes: 2 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__Document.re
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ module Impl = (T: {type t;}) => {
[@bs.get] external implementation : T.t => Dom.domImplementation = "";
[@bs.get] external lastStyleSheetSet : T.t => string = "";
[@bs.get] [@bs.return nullable] external pointerLockElement : T.t => option(Dom.element) = ""; /* experimental */
/** @since 0.20.0 */
[@bs.get] external forms : T.t => Dom.htmlCollection = "";
illusionalsagacity marked this conversation as resolved.
Show resolved Hide resolved

[@bs.get] external preferredStyleSheetSet : T.t => string = "";
[@bs.get] [@bs.return nullable] external scrollingElement : T.t => option(Dom.element) = "";
Expand Down
16 changes: 16 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__HtmlButtonElement.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Spec: https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element
*/
module Impl = (T: {type t;}) => {
type t_htmlButtonElement = T.t;

// TODO
};

type t; // TODO: Dom.htmlButtonElement

include Webapi__Dom__EventTarget.Impl({ type nonrec t = t; });
include Webapi__Dom__Node.Impl({ type nonrec t = t; });
include Webapi__Dom__Element.Impl({ type nonrec t = t; });
include Webapi__Dom__HtmlElement.Impl({ type nonrec t = t; });
include Impl({ type nonrec t = t; });
15 changes: 10 additions & 5 deletions src/Webapi/Dom/Webapi__Dom__HtmlCollection.re
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
type t = Dom.htmlCollection;
module Impl = (T: { type t;}) => {
type t_htmlCollection = T.t;
[@bs.val] [@bs.scope ("Array", "prototype", "slice")] external toArray : t_htmlCollection => array(Dom.element) = "call";

[@bs.get] external length : t_htmlCollection => int = "";
[@bs.send.pipe : t_htmlCollection] [@bs.return nullable] external item : int => option(Dom.element) = "";
[@bs.send.pipe : t_htmlCollection] [@bs.return nullable] external namedItem : string => option(Dom.element) = "";
};

[@bs.val] [@bs.scope ("Array", "prototype", "slice")] external toArray : t => array(Dom.element) = "call";
type t = Dom.htmlCollection;

[@bs.get] external length : t => int = "";
[@bs.send.pipe : t] [@bs.return nullable] external item : int => option(Dom.element) = "";
[@bs.send.pipe : t] [@bs.return nullable] external namedItem : string => option(Dom.element) = "";
include Impl({ type nonrec t = t; });
16 changes: 16 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__HtmlFieldSetElement.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Spec: https://html.spec.whatwg.org/multipage/form-elements.html#the-fieldset-element
*/
module Impl = (T: {type t;}) => {
type t_htmlFieldSetElement = T.t;

// TODO
};

type t; // TODO: Dom.htmlFieldSetElement

include Webapi__Dom__EventTarget.Impl({ type nonrec t = t; });
include Webapi__Dom__Node.Impl({ type nonrec t = t; });
include Webapi__Dom__Element.Impl({ type nonrec t = t; });
include Webapi__Dom__HtmlElement.Impl({ type nonrec t = t; });
include Impl({ type nonrec t = t; });
43 changes: 43 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Spec: https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#htmlformcontrolscollection
*/
type t; // TODO: Dom.htmlFormControlsCollection

type t_namedItem = [
| `RadioNodeList(Webapi__Dom__RadioNodeList.t)
| `Button(Webapi__Dom__HtmlButtonElement.t)
| `FieldSet(Webapi__Dom__HtmlFieldSetElement.t)
| `Input(Webapi__Dom__HtmlInputElement.t)
| `Object(Webapi__Dom__HtmlObjectElement.t)
| `Output(Webapi__Dom__HtmlOutputElement.t)
| `Select(Webapi__Dom__HtmlSelectElement.t)
| `TextArea(Webapi__Dom__HtmlTextAreaElement.t)
];

include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; });

let isRadioNodeList: 'a => bool = [%raw {|
function(x) { return x instanceof RadioNodeList; }
|}];

[@bs.send.pipe : t] [@bs.return nullable] external _namedItem: string => option('a) = "namedItem";
let namedItem = (name, t) =>
switch (_namedItem(name, t)) {
| Some(el) =>
if (Webapi__Dom__RadioNodeList.unsafeAsRadioNodeList(el)->isRadioNodeList) {
el->Obj.magic->`RadioNodeList->Some;
} else {
switch (Webapi__Dom__Element.tagName(el)) {
// fixme: this should be a classify function in Webapi__Dom__HtmlElement
| "BUTTON" => el->Obj.magic->`Button->Some
| "FIELDSET" => el->Obj.magic->`FieldSet->Some
| "INPUT" => el->Obj.magic->`Input->Some
| "OBJECT" => el->Obj.magic->`Object->Some
| "OUTPUT" => el->Obj.magic->`Output->Some
| "SELECT" => el->Obj.magic->`Select->Some
| "TEXTAREA" => el->Obj.magic->`TextArea->Some
| _ => None
};
}
| None => None
};
11 changes: 10 additions & 1 deletion src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@
module Impl = (T: {type t;}) => {
type t_htmlFormElement = T.t;

/* TODO: elements: HTMLFormControlsCollection */
external unsafeAsFormElement: Dom.element => t_htmlFormElement = "%identity";
external asElement: t_htmlFormElement => Dom.element = "%identity";

let asFormElement = (el): option(t_htmlFormElement) => switch(Webapi__Dom__Element.tagName(el)) {
| "FORM" => el->unsafeAsFormElement->Some
| _ => None
};

/** @since 0.20.0 */
[@bs.get] external elements : t_htmlFormElement => Webapi__Dom__HtmlFormControlsCollection.t = "elements";
[@bs.get] external length : t_htmlFormElement => int = "";
[@bs.get] external name : t_htmlFormElement => string = "";
[@bs.set] external setName : (t_htmlFormElement, string) => unit = "name";
Expand Down
16 changes: 16 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__HtmlObjectElement.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element
*/
module Impl = (T: {type t;}) => {
type t_htmlObjectElement = T.t;

// TODO
};

type t; // TODO: Dom.htmlObjectElement

include Webapi__Dom__EventTarget.Impl({ type nonrec t = t; });
include Webapi__Dom__Node.Impl({ type nonrec t = t; });
include Webapi__Dom__Element.Impl({ type nonrec t = t; });
include Webapi__Dom__HtmlElement.Impl({ type nonrec t = t; });
include Impl({ type nonrec t = t; });
5 changes: 5 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Spec: https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#htmloptionscollection
*/
type t; // TODO: Dom.htmlOptionsCollection;
include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; });
16 changes: 16 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__HtmlOutputElement.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Spec: https://html.spec.whatwg.org/multipage/form-elements.html#the-output-element
*/
module Impl = (T: {type t;}) => {
type t_htmlOutputElement = T.t;

// TODO
};

type t; // TODO: Dom.htmlOutputElement

include Webapi__Dom__EventTarget.Impl({ type nonrec t = t; });
include Webapi__Dom__Node.Impl({ type nonrec t = t; });
include Webapi__Dom__Element.Impl({ type nonrec t = t; });
include Webapi__Dom__HtmlElement.Impl({ type nonrec t = t; });
include Impl({ type nonrec t = t; });
16 changes: 16 additions & 0 deletions src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Spec: https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element
*/
module Impl = (T: {type t;}) => {
type t_htmlSelectElement = T.t;

// TODO
};

type t; // TODO: Dom.htmlSelectElement

include Webapi__Dom__EventTarget.Impl({ type nonrec t = t; });
include Webapi__Dom__Node.Impl({ type nonrec t = t; });
include Webapi__Dom__Element.Impl({ type nonrec t = t; });
include Webapi__Dom__HtmlElement.Impl({ type nonrec t = t; });
include Impl({ type nonrec t = t; });
Loading