Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add named arguments to various Node apis #89

Merged
merged 2 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

### Breaking Changes
* Change all `send.pipe` externals to `send`, making the whole project "t-first" (#8)
* Some `Node` APIs do not trigger compile errors due to the argument swap, because both arguments were `Node` instances. This logic error can cause severe migration headaches; the following methods had named arguments added to highlight places migration is necessary (#89)
* `appendChild`
* `compareDocumentPosition`
* `contains`
* `insertBefore`
* `removeChild`
* `replaceChild`
* Imported `bs-fetch` as `Webapi.Fetch` and converted it to "t-first" (#31)
* Removed deprecated APIs (#16)
* Removed `preview` from File bindings. It doesn't seem to be in any specifications. (#56)
Expand Down Expand Up @@ -31,10 +38,12 @@
* `HTMLFormControlsCollection`, `HTMLOptionsCollection`, `HTMLFieldSetElement`, `Document.forms`, `HTMLFormElement.elements`, `HTMLObjectElement`, `HTMLOptGroupElement`, `HTMLOptionElement`, `HTMLOutputElement`, `HTMLSelectElement`, `HTMLTextAreaElement`, and `RadioNodeList` bindings (#73)
* `Canvas2d` bindings `drawImage`, `drawImageScale`, and `drawImageFull` added (#83)
* `InputEvent` bindings for `inputType`, `dataTransfer` and `getTargetRanges` (#90)
* `Node.insertAtEnd` binding (which does `parent.insertBefore(child, null)`) (#89)

### Fixed
* `ofElement` was incorrectly returning `Dom.htmlElement` type instead of the enclosing element type (#60)

### Miscellaneous
* Converted project to rescript syntax (#18)
* Added explicit values to all externals instead of using `= ""` (#40)
* Deprecated `Node.isSameNode` (MDN recommends using `===` instead) (#89)
2 changes: 1 addition & 1 deletion examples/dom_example.res
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ let _ =
document
->Document.asHtmlDocument
->flatMap(HtmlDocument.body)
->map(body => body->Element.appendChild(el))
->map(body => body->Element.appendChild(~child=el))

/*
/*
Expand Down
4 changes: 2 additions & 2 deletions lib/js/tests/Webapi/Dom/Webapi__Dom__Node__test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ node.hasChildNodes();

node.insertBefore(node2, node3);

node.insertBefore(node2, null);

node.isDefaultNamespace("http://...");

node.isEqualNode(node2);

node.isSameNode(node2);

node.lookupPrefix();

node.lookupNamespaceURI("https://...");
Expand Down
15 changes: 9 additions & 6 deletions src/Webapi/Dom/Webapi__Dom__Node.res
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,33 @@ module Impl = (
@get external textContent: T.t => string = "textContent"
@set external setTextContent: (T.t, string) => unit = "textContent"

@send external appendChild: (T.t, Dom.node_like<'a>) => unit = "appendChild"
@send external appendChild: (T.t, ~child: Dom.node_like<'a>) => unit = "appendChild"
@send external cloneNode: T.t => T.t = "cloneNode"
@send external cloneNodeDeep: (T.t, @as(json`true`) _) => T.t = "cloneNode"
@send
external compareDocumentPosition: (T.t, Dom.node_like<'a>) => int = "compareDocumentPosition" /* returns a bitmask which could also be represeneted as an enum, see https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition */
@send external contains: (T.t, Dom.node_like<'a>) => bool = "contains"
external compareDocumentPosition: (T.t, ~other: Dom.node_like<'a>) => int = "compareDocumentPosition" /* returns a bitmask which could also be represeneted as an enum, see https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition */
@send external contains: (T.t, ~child: Dom.node_like<'a>) => bool = "contains"
@send external getRootNode: T.t => Dom.node = "getRootNode"
@send
external getRootNodeComposed: (T.t, @as(json`{ "composed": true }`) _) => Dom.node = "getRootNode"
@send external hasChildNodes: T.t => bool = "hasChildNodes"
@send
external insertBefore: (T.t, Dom.node_like<'a>, Dom.node_like<'b>) => Dom.node_like<'a> = "insertBefore"
external insertBefore: (T.t, ~new: Dom.node_like<'a>, ~before: Dom.node_like<'b>) => Dom.node_like<'a> = "insertBefore"
@send
external insertAtEnd: (T.t, ~new: Dom.node_like<'a>, @as(json`null`) _) => Dom.node_like<'a> = "insertBefore"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird didn't know you could do that seems like the same thing as appendChild.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I didn't know this existed either, until I was reading the specs while working on the branch. Maybe it doesn't make sense to have both bindings but who knows, maybe some developers prefer to use parent.insertBefore(child, null) 🤷‍♂️

@send external isDefaultNamespace: (T.t, string) => bool = "isDefaultNamespace"
@send external isEqualNode: (T.t, Dom.node_like<'a>) => bool = "isEqualNode"
@deprecated("There is no need to use isSameNode(); instead use the === strict equality operator.")
@send external isSameNode: (T.t, Dom.node_like<'a>) => bool = "isSameNode"
@send @return(nullable) external lookupNamespaceURI: (T.t, string) => option<string> = "lookupNamespaceURI"
@send @return(nullable)
external lookupDefaultNamespaceURI: (T.t, @as(json`null`) _) => option<string> =
"lookupNamespaceURI"
@send external lookupPrefix: T.t => string = "lookupPrefix"
@send external normalize: T.t => unit = "normalize"
@send external removeChild: (T.t, Dom.node_like<'a>) => Dom.node_like<'a> = "removeChild"
@send external removeChild: (T.t, ~child: Dom.node_like<'a>) => Dom.node_like<'a> = "removeChild"

@send external replaceChild: (T.t, Dom.node_like<'a>, Dom.node_like<'b>) => Dom.node_like<'b> = "replaceChild"
@send external replaceChild: (T.t, ~new: Dom.node_like<'a>, ~child: Dom.node_like<'b>) => Dom.node_like<'b> = "replaceChild"
}

type t = Dom.node
Expand Down
44 changes: 22 additions & 22 deletions tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.res
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let createInput = () => createElement("input")
let createLabelWithText = text => {
let el = createElement("label")
let textNode = createTextNode(text)
Element.appendChild(el, textNode)
Element.appendChild(el, ~child=textNode)
el
}

Expand All @@ -25,15 +25,15 @@ Element.setAttribute(usernameInput, "name", "username")
Element.setAttribute(usernameInput, "value", "username")

let usernameLabel = createLabelWithText("Username:")
Element.appendChild(usernameLabel, usernameInput)
Element.appendChild(usernameLabel, ~child=usernameInput)

let passwordInput = createInput()
Element.setAttribute(passwordInput, "type", "password")
Element.setAttribute(passwordInput, "name", "password")
Element.setAttribute(passwordInput, "value", "password")

let passwordLabel = createLabelWithText("Password:")
Element.appendChild(passwordLabel, passwordInput)
Element.appendChild(passwordLabel, ~child=passwordInput)

let radioInput1 = createInput()
Element.setAttribute(radioInput1, "type", "radio")
Expand All @@ -42,7 +42,7 @@ Element.setAttribute(radioInput1, "value", "one")
Element.setAttribute(radioInput1, "checked", "true")

let radioLabel1 = createLabelWithText("Choice 1:")
Element.appendChild(radioLabel1, radioInput1)
Element.appendChild(radioLabel1, ~child=radioInput1)

let radioInput2 = createInput()
Element.setAttribute(radioInput2, "type", "radio")
Expand All @@ -51,34 +51,34 @@ Element.setAttribute(radioInput2, "value", "two")
// Element.setAttribute(radioInput2, "checked", "true");

let radioLabel2 = createLabelWithText("Choice 2:")
Element.appendChild(radioLabel2, radioInput2)
Element.appendChild(radioLabel2, ~child=radioInput2)

let select = createElement("select")
Element.setAttribute(select, "name", "select")
let selectLabel = createLabelWithText("Select:")
Element.appendChild(selectLabel, select)
Element.appendChild(selectLabel, ~child=select)

let usernameContainer = createElement("div")
let passwordContainer = createElement("div")
let radioContainer = createElement("div")
let selectContainer = createElement("div")

Element.appendChild(usernameContainer, usernameLabel)
Element.appendChild(passwordContainer, passwordLabel)
Element.appendChild(radioContainer, radioLabel1)
Element.appendChild(radioContainer, radioLabel2)
Element.appendChild(selectContainer, selectLabel)
Element.appendChild(formEl, usernameContainer)
Element.appendChild(formEl, passwordContainer)
Element.appendChild(formEl, radioContainer)
Element.appendChild(formEl, selectContainer)
Element.appendChild(usernameContainer, ~child=usernameLabel)
Element.appendChild(passwordContainer, ~child=passwordLabel)
Element.appendChild(radioContainer, ~child=radioLabel1)
Element.appendChild(radioContainer, ~child=radioLabel2)
Element.appendChild(selectContainer, ~child=selectLabel)
Element.appendChild(formEl, ~child=usernameContainer)
Element.appendChild(formEl, ~child=passwordContainer)
Element.appendChild(formEl, ~child=radioContainer)
Element.appendChild(formEl, ~child=selectContainer)

let body =
Document.asHtmlDocument(document)
->Belt.Option.flatMap(HtmlDocument.body)
->TestHelpers.unsafelyUnwrapOption

Element.appendChild(body, formEl)
Element.appendChild(body, ~child=formEl)

let collection = elements(form)

Expand Down Expand Up @@ -151,7 +151,7 @@ HtmlOptionsCollection.setLength(opts, 0)

let opt1 = createElement("option")
Element.setAttribute(opt1, "value", "1")
Element.appendChild(opt1, createTextNode("opt1"))
Element.appendChild(opt1, ~child=createTextNode("opt1"))

HtmlOptionsCollection.add(
opts,
Expand All @@ -164,7 +164,7 @@ Js.log2("collection length:", HtmlOptionsCollection.length(opts))

let opt2 = createElement("option")
Element.setAttribute(opt2, "value", "2")
Element.appendChild(opt2, createTextNode("opt2"))
Element.appendChild(opt2, ~child=createTextNode("opt2"))

let item = HtmlOptionsCollection.item(opts, 0)
jsAssert(Belt.Option.isSome(item), "HtmlOptionsCollection.item should return an item")
Expand All @@ -189,7 +189,7 @@ jsAssert(HtmlOptionsCollection.selectedIndex(opts) == -1, "HtmlOptionsCollection

let opt3 = createElement("option")
Element.setAttribute(opt3, "value", "3")
Element.appendChild(opt3, createTextNode("opt3"))
Element.appendChild(opt3, ~child=createTextNode("opt3"))

HtmlOptionsCollection.add(
opts,
Expand Down Expand Up @@ -230,7 +230,7 @@ HtmlSelectElement.setLength(select, 0)

let opt1 = createElement("option")
Element.setAttribute(opt1, "value", "1")
Element.appendChild(opt1, createTextNode("opt1"))
Element.appendChild(opt1, ~child=createTextNode("opt1"))

HtmlSelectElement.add(
select,
Expand All @@ -243,7 +243,7 @@ Js.log2("collection length:", HtmlSelectElement.length(select))

let opt2 = createElement("option")
Element.setAttribute(opt2, "value", "2")
Element.appendChild(opt2, createTextNode("opt2"))
Element.appendChild(opt2, ~child=createTextNode("opt2"))

let item = HtmlSelectElement.item(select, 0)
jsAssert(Belt.Option.isSome(item), "HtmlSelectElement.item should return an item")
Expand All @@ -268,7 +268,7 @@ jsAssert(HtmlSelectElement.selectedIndex(select) == -1, "HtmlSelectElement.clear

let opt3 = createElement("option")
Element.setAttribute(opt3, "value", "3")
Element.appendChild(opt3, createTextNode("opt3"))
Element.appendChild(opt3, ~child=createTextNode("opt3"))

HtmlSelectElement.add(
select,
Expand Down
15 changes: 7 additions & 8 deletions tests/Webapi/Dom/Webapi__Dom__Node__test.res
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,21 @@ let _ = node->rootNode
let _ = node->textContent
let _ = node->setTextContent("foo")

let _ = node->appendChild(node2)
let _ = node->appendChild(~child=node2)
let _ = node->cloneNode
let _ = node->cloneNodeDeep
let _ = node->compareDocumentPosition(node2)
let _ = node->contains(node2)
let _ = node->compareDocumentPosition(~other=node2)
let _ = node->contains(~child=node2)
let _ = node->getRootNode
let _ = node->getRootNodeComposed
let _ = node->hasChildNodes
let _ = node->insertBefore(node2, node3)
/* **let _ node->= insertBefore(node2, None); */
let _ = node->insertBefore(~new=node2, ~before=node3)
let _ = node->insertAtEnd(~new=node2)
let _ = node->isDefaultNamespace("http://...")
let _ = node->isEqualNode(node2)
let _ = node->isSameNode(node2)
let _ = node->lookupPrefix
let _ = node->lookupNamespaceURI("https://...")
let _ = node->lookupDefaultNamespaceURI
let _ = node->normalize
let _ = node->removeChild(node2)
let _ = node->replaceChild(node3, node2)
let _ = node->removeChild(~child=node2)
let _ = node->replaceChild(~new=node3, ~child=node2)
2 changes: 1 addition & 1 deletion tests/Webapi/Webapi__IntersectionObserver__test.res
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let body =

Webapi.Dom.Element.setInnerText(el, "Hello There")
Webapi.Dom.Element.setAttribute(el, "style", "margin-top: 800px; margin-bottom: 800px")
Webapi.Dom.Element.appendChild(body, el)
Webapi.Dom.Element.appendChild(body, ~child=el)

let handler = (entries, observer) => {
Js.Array.forEach(entry => {
Expand Down