From 7f2387a339406ee288935a9ae5102a17c071bc43 Mon Sep 17 00:00:00 2001 From: rob Date: Mon, 17 Aug 2020 21:34:12 -0400 Subject: [PATCH 01/14] feat: add bindings for HTMLFormControlsCollection, RadioNodeList, etc --- CHANGELOG.md | 10 +++++ lib/js/tests/Webapi/Webapi__Blob__test.js | 12 +++--- .../Webapi/Webapi__ReadableStream__test.js | 28 ++++++------- .../Webapi/Webapi__ResizeObserver__test.js | 2 +- lib/js/tests/Webapi/Webapi__Url__test.js | 8 ++-- package.json | 4 +- src/Webapi/Dom/Webapi__Dom__Document.re | 2 + src/Webapi/Dom/Webapi__Dom__HtmlCollection.re | 15 ++++--- ...Webapi__Dom__HtmlFormControlsCollection.re | 40 +++++++++++++++++++ .../Dom/Webapi__Dom__HtmlFormElement.re | 3 +- .../Dom/Webapi__Dom__HtmlOptionsCollection.re | 2 + src/Webapi/Dom/Webapi__Dom__NodeList.re | 16 +++++--- src/Webapi/Dom/Webapi__Dom__RadioNodeList.re | 11 +++++ ...pi__ResizeObserver__ResizeObserverEntry.re | 2 +- src/Webapi/Webapi__Dom.re | 3 ++ src/Webapi/Webapi__ResizeObserver.re | 2 +- 16 files changed, 120 insertions(+), 40 deletions(-) create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re create mode 100644 src/Webapi/Dom/Webapi__Dom__RadioNodeList.re diff --git a/CHANGELOG.md b/CHANGELOG.md index 42842ca1..442fde02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +### 0.20.0 + +* Upgraded to bs-platform@8.2.0 +* Added bindings for `HTMLFormControlsCollection` +* Added binding for `HTMLOptionsCollection` +* Added bindings for `RadioNodeList` +* Added binding for `Document.forms` +* Added binding for `HTMLFormElement.elements` +* ResizeObserver and ResizeObserverEntry now use the rescript Dom phantom type + ### 0.19.1 * Removed dev dependency on `bsdoc` to allow smooth installs on non-Mac diff --git a/lib/js/tests/Webapi/Webapi__Blob__test.js b/lib/js/tests/Webapi/Webapi__Blob__test.js index 0f891a1a..41b57ad9 100644 --- a/lib/js/tests/Webapi/Webapi__Blob__test.js +++ b/lib/js/tests/Webapi/Webapi__Blob__test.js @@ -2,9 +2,9 @@ function test_arrayBuffer(blob) { - return blob.arrayBuffer().then((function (buffer) { - return Promise.resolve((console.log(buffer.byteLength), undefined)); - })); + return blob.arrayBuffer().then(function (buffer) { + return Promise.resolve((console.log(buffer.byteLength), undefined)); + }); } function test_size(blob) { @@ -23,9 +23,9 @@ function test_stream(blob) { } function test_text(blob) { - return blob.text().then((function (string) { - return Promise.resolve((console.log(string), undefined)); - })); + return blob.text().then(function (string) { + return Promise.resolve((console.log(string), undefined)); + }); } function test_type(blob) { diff --git a/lib/js/tests/Webapi/Webapi__ReadableStream__test.js b/lib/js/tests/Webapi/Webapi__ReadableStream__test.js index aa3b329c..a8507bbe 100644 --- a/lib/js/tests/Webapi/Webapi__ReadableStream__test.js +++ b/lib/js/tests/Webapi/Webapi__ReadableStream__test.js @@ -8,15 +8,15 @@ function test_closed(reader) { } function test_cancel(reader) { - return reader.cancel().then((function (param) { - return Promise.resolve((console.log("cancelled"), undefined)); - })); + return reader.cancel().then(function (param) { + return Promise.resolve((console.log("cancelled"), undefined)); + }); } function test_cancelWith(reader) { - return reader.cancel("reason").then((function (reason) { - return Promise.resolve((console.log(reason), undefined)); - })); + return reader.cancel("reason").then(function (reason) { + return Promise.resolve((console.log(reason), undefined)); + }); } function test_releaseLock(reader) { @@ -25,13 +25,13 @@ function test_releaseLock(reader) { } function test_read(reader) { - return reader.read().then((function (next) { - var __x = next.value; - return Promise.resolve(Belt_Option.forEach((__x == null) ? undefined : Caml_option.some(__x), (function (prim) { - console.log(prim); - - }))); - })); + return reader.read().then(function (next) { + var __x = next.value; + return Promise.resolve(Belt_Option.forEach((__x == null) ? undefined : Caml_option.some(__x), (function (prim) { + console.log(prim); + + }))); + }); } var DefaultReader__test = { @@ -59,7 +59,7 @@ function test_getReader(stream) { } function test_getReaderBYOB(stream) { - return stream.getReader(({"mode": "byob"})); + return stream.getReader({"mode": "byob"}); } function test_tee(stream) { diff --git a/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js b/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js index 335207ea..94af5356 100644 --- a/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js +++ b/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js @@ -5,7 +5,7 @@ var Caml_array = require("bs-platform/lib/js/caml_array.js"); var el = document.createElement("strong"); function handler(entries) { - var entry = Caml_array.caml_array_get(entries, 0); + var entry = Caml_array.get(entries, 0); entry.contentRect; entry.target; diff --git a/lib/js/tests/Webapi/Webapi__Url__test.js b/lib/js/tests/Webapi/Webapi__Url__test.js index 73977e83..1374748a 100644 --- a/lib/js/tests/Webapi/Webapi__Url__test.js +++ b/lib/js/tests/Webapi/Webapi__Url__test.js @@ -3,10 +3,10 @@ var params = new URLSearchParams("key1=value1&key2=value2"); -params.forEach((function (prim, prim$1) { - console.log(prim, prim$1); - - })); +params.forEach(function (prim, prim$1) { + console.log(prim, prim$1); + + }); function test_entries(params) { return Array.from(params.entries()); diff --git a/package.json b/package.json index 610bb5f0..fd547f71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bs-webapi", - "version": "0.19.1", + "version": "0.20.0", "description": "Reason + BuckleScript bindings to DOM", "repository": { "type": "git", @@ -26,7 +26,7 @@ "author": "chenglou", "license": "MIT", "devDependencies": { - "bs-platform": "^7.1.0" + "bs-platform": "^8.2.0" }, "dependencies": { "bs-fetch": "^0.6.2" diff --git a/src/Webapi/Dom/Webapi__Dom__Document.re b/src/Webapi/Dom/Webapi__Dom__Document.re index b6a2c9b4..1b8dd2e9 100644 --- a/src/Webapi/Dom/Webapi__Dom__Document.re +++ b/src/Webapi/Dom/Webapi__Dom__Document.re @@ -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 = ""; [@bs.get] external preferredStyleSheetSet : T.t => string = ""; [@bs.get] [@bs.return nullable] external scrollingElement : T.t => option(Dom.element) = ""; diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlCollection.re index b57d911d..196f140e 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlCollection.re @@ -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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re new file mode 100644 index 00000000..977bda99 --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re @@ -0,0 +1,40 @@ +type t = Dom.htmlFormControlsCollection; + +type t_namedItem = [ + | `RadioNodeList(Dom.radioNodeList) + | `Button(Dom.htmlButtonElement) + | `Fieldset(Dom.htmlFieldSetElement) + | `Input(Dom.htmlInputElement) + | `Object(Dom.htmlObjectElement) + | `Output(Dom.htmlOutputElement) + | `Select(Dom.htmlSelectElement) + | `Textarea(Dom.htmlTextAreaElement) +]; + +include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; }); + +let isRadioNodeList: 'a => bool = [%raw {| + function(x) { return x instanceof RadioNodeList; } +|}]; + +[@bs.send] [@bs.return nullable] external _namedItem: (t, string) => option('a) = "namedItem"; +let namedItem = (t, string) => + switch (_namedItem(t, string)) { + | 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 + }; diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re index fabae957..88bfd9e3 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re @@ -6,7 +6,8 @@ module Impl = (T: {type t;}) => { type t_htmlFormElement = T.t; - /* TODO: elements: HTMLFormControlsCollection */ + /** @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"; diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re new file mode 100644 index 00000000..74015ba8 --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re @@ -0,0 +1,2 @@ +type t = Dom.htmlOptionsCollection; +include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; }); diff --git a/src/Webapi/Dom/Webapi__Dom__NodeList.re b/src/Webapi/Dom/Webapi__Dom__NodeList.re index 90cf9e54..5d466042 100644 --- a/src/Webapi/Dom/Webapi__Dom__NodeList.re +++ b/src/Webapi/Dom/Webapi__Dom__NodeList.re @@ -1,9 +1,15 @@ -type t = Dom.nodeList; +module Impl = (T: {type t;}) => { + type t_nodeList = T.t; + + [@bs.val] external toArray : t_nodeList => array(Dom.node) = "Array.prototype.slice.call"; -[@bs.val] external toArray : t => array(Dom.node) = "Array.prototype.slice.call"; + [@bs.send.pipe : t_nodeList] external forEach : ((Dom.node, int) => unit) => unit = ""; -[@bs.send.pipe : t] external forEach : ((Dom.node, int) => unit) => unit = ""; + [@bs.get] external length : t_nodeList => int = ""; -[@bs.get] external length : t => int = ""; + [@bs.send.pipe : t_nodeList] [@bs.return nullable] external item : int => option(Dom.node) = ""; +}; + +type t = Dom.nodeList; -[@bs.send.pipe : t] [@bs.return nullable] external item : int => option(Dom.node) = ""; +include Impl({ type nonrec t = t; }); diff --git a/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re b/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re new file mode 100644 index 00000000..3178c0f8 --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re @@ -0,0 +1,11 @@ +module Impl = (T: {type t;}) => { + type t_radioNodeList = T.t; + [@bs.get] external value: t_radioNodeList => string = "value"; + + external unsafeAsRadioNodeList: 'a => t_radioNodeList = "%identity"; +}; + +type t = Dom.radioNodeList; + +include Webapi__Dom__NodeList.Impl({type nonrec t = t;}); +include Impl({type nonrec t = t;}); diff --git a/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re b/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re index ca235441..bc9fb27a 100644 --- a/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re +++ b/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re @@ -1,4 +1,4 @@ -type t; +type t = Dom.resizeObserverEntry; [@bs.get] external contentRect: t => Dom.domRect = ""; [@bs.get] external target: t => Dom.element = ""; diff --git a/src/Webapi/Webapi__Dom.re b/src/Webapi/Webapi__Dom.re index 8d658660..844c8c5b 100644 --- a/src/Webapi/Webapi__Dom.re +++ b/src/Webapi/Webapi__Dom.re @@ -24,6 +24,8 @@ module EventTarget = Webapi__Dom__EventTarget; module FocusEvent = Webapi__Dom__FocusEvent; module History = Webapi__Dom__History; module HtmlCollection = Webapi__Dom__HtmlCollection; +module HtmlFormControlsCollection = Webapi__Dom__HtmlFormControlsCollection; +module HtmlOptionsCollection = Webapi__Dom__HtmlOptionsCollection; module HtmlDocument = Webapi__Dom__HtmlDocument; module HtmlElement = Webapi__Dom__HtmlElement; module HtmlFormElement = Webapi__Dom__HtmlFormElement; @@ -42,6 +44,7 @@ module Node = Webapi__Dom__Node; module NodeFilter = Webapi__Dom__NodeFilter; module NodeIterator = Webapi__Dom__NodeIterator; module NodeList = Webapi__Dom__NodeList; +module RadioNodeList = Webapi__Dom__RadioNodeList; module PageTransitionEvent = Webapi__Dom__PageTransitionEvent; module PointerEvent = Webapi__Dom__PointerEvent; module PopStateEvent = Webapi__Dom__PopStateEvent; diff --git a/src/Webapi/Webapi__ResizeObserver.re b/src/Webapi/Webapi__ResizeObserver.re index 7ea6f104..25bdba64 100644 --- a/src/Webapi/Webapi__ResizeObserver.re +++ b/src/Webapi/Webapi__ResizeObserver.re @@ -1,6 +1,6 @@ module ResizeObserverEntry = Webapi__ResizeObserver__ResizeObserverEntry; -type t; +type t = Dom.resizeObserver; [@bs.new] external make: (array(ResizeObserverEntry.t) => unit) => t = "ResizeObserver"; From cfe78cfc16d23417815ef09bed1a13b9e4f7bea7 Mon Sep 17 00:00:00 2001 From: rob Date: Mon, 17 Aug 2020 22:34:18 -0400 Subject: [PATCH 02/14] chore: remove TODOs --- src/Webapi/Webapi__Dom.re | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Webapi/Webapi__Dom.re b/src/Webapi/Webapi__Dom.re index 844c8c5b..d4f4550e 100644 --- a/src/Webapi/Webapi__Dom.re +++ b/src/Webapi/Webapi__Dom.re @@ -178,11 +178,7 @@ include Webapi__Dom__Types; CanvasPixelArray NotifyAudioAvailableEvent HTMLAllCollection - HTMLFormControlsCollection - HTMLOptionsCollection HTMLPropertiesCollection - DOMStringMap - RadioNodeList MediaError /* SVG Element interfaces */ From 3173662436b1ac858c3bd285703839310ca2a9f2 Mon Sep 17 00:00:00 2001 From: rob Date: Mon, 17 Aug 2020 22:50:22 -0400 Subject: [PATCH 03/14] chore: cleanup --- lib/js/tests/Webapi/Webapi__Blob__test.js | 12 ++++---- .../Webapi/Webapi__ReadableStream__test.js | 28 +++++++++---------- .../Webapi/Webapi__ResizeObserver__test.js | 2 +- lib/js/tests/Webapi/Webapi__Url__test.js | 8 +++--- package.json | 2 +- ...Webapi__Dom__HtmlFormControlsCollection.re | 18 ++++++------ .../Dom/Webapi__Dom__HtmlOptionsCollection.re | 2 +- src/Webapi/Dom/Webapi__Dom__RadioNodeList.re | 2 +- ...pi__ResizeObserver__ResizeObserverEntry.re | 2 +- src/Webapi/Webapi__ResizeObserver.re | 2 +- 10 files changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/js/tests/Webapi/Webapi__Blob__test.js b/lib/js/tests/Webapi/Webapi__Blob__test.js index 41b57ad9..0f891a1a 100644 --- a/lib/js/tests/Webapi/Webapi__Blob__test.js +++ b/lib/js/tests/Webapi/Webapi__Blob__test.js @@ -2,9 +2,9 @@ function test_arrayBuffer(blob) { - return blob.arrayBuffer().then(function (buffer) { - return Promise.resolve((console.log(buffer.byteLength), undefined)); - }); + return blob.arrayBuffer().then((function (buffer) { + return Promise.resolve((console.log(buffer.byteLength), undefined)); + })); } function test_size(blob) { @@ -23,9 +23,9 @@ function test_stream(blob) { } function test_text(blob) { - return blob.text().then(function (string) { - return Promise.resolve((console.log(string), undefined)); - }); + return blob.text().then((function (string) { + return Promise.resolve((console.log(string), undefined)); + })); } function test_type(blob) { diff --git a/lib/js/tests/Webapi/Webapi__ReadableStream__test.js b/lib/js/tests/Webapi/Webapi__ReadableStream__test.js index a8507bbe..aa3b329c 100644 --- a/lib/js/tests/Webapi/Webapi__ReadableStream__test.js +++ b/lib/js/tests/Webapi/Webapi__ReadableStream__test.js @@ -8,15 +8,15 @@ function test_closed(reader) { } function test_cancel(reader) { - return reader.cancel().then(function (param) { - return Promise.resolve((console.log("cancelled"), undefined)); - }); + return reader.cancel().then((function (param) { + return Promise.resolve((console.log("cancelled"), undefined)); + })); } function test_cancelWith(reader) { - return reader.cancel("reason").then(function (reason) { - return Promise.resolve((console.log(reason), undefined)); - }); + return reader.cancel("reason").then((function (reason) { + return Promise.resolve((console.log(reason), undefined)); + })); } function test_releaseLock(reader) { @@ -25,13 +25,13 @@ function test_releaseLock(reader) { } function test_read(reader) { - return reader.read().then(function (next) { - var __x = next.value; - return Promise.resolve(Belt_Option.forEach((__x == null) ? undefined : Caml_option.some(__x), (function (prim) { - console.log(prim); - - }))); - }); + return reader.read().then((function (next) { + var __x = next.value; + return Promise.resolve(Belt_Option.forEach((__x == null) ? undefined : Caml_option.some(__x), (function (prim) { + console.log(prim); + + }))); + })); } var DefaultReader__test = { @@ -59,7 +59,7 @@ function test_getReader(stream) { } function test_getReaderBYOB(stream) { - return stream.getReader({"mode": "byob"}); + return stream.getReader(({"mode": "byob"})); } function test_tee(stream) { diff --git a/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js b/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js index 94af5356..335207ea 100644 --- a/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js +++ b/lib/js/tests/Webapi/Webapi__ResizeObserver__test.js @@ -5,7 +5,7 @@ var Caml_array = require("bs-platform/lib/js/caml_array.js"); var el = document.createElement("strong"); function handler(entries) { - var entry = Caml_array.get(entries, 0); + var entry = Caml_array.caml_array_get(entries, 0); entry.contentRect; entry.target; diff --git a/lib/js/tests/Webapi/Webapi__Url__test.js b/lib/js/tests/Webapi/Webapi__Url__test.js index 1374748a..73977e83 100644 --- a/lib/js/tests/Webapi/Webapi__Url__test.js +++ b/lib/js/tests/Webapi/Webapi__Url__test.js @@ -3,10 +3,10 @@ var params = new URLSearchParams("key1=value1&key2=value2"); -params.forEach(function (prim, prim$1) { - console.log(prim, prim$1); - - }); +params.forEach((function (prim, prim$1) { + console.log(prim, prim$1); + + })); function test_entries(params) { return Array.from(params.entries()); diff --git a/package.json b/package.json index fd547f71..3ae2f5a1 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "author": "chenglou", "license": "MIT", "devDependencies": { - "bs-platform": "^8.2.0" + "bs-platform": "^7.1.0" }, "dependencies": { "bs-fetch": "^0.6.2" diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re index 977bda99..4db2c773 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re @@ -1,14 +1,14 @@ -type t = Dom.htmlFormControlsCollection; +type t; // TODO: Dom.htmlFormControlsCollection type t_namedItem = [ - | `RadioNodeList(Dom.radioNodeList) - | `Button(Dom.htmlButtonElement) - | `Fieldset(Dom.htmlFieldSetElement) - | `Input(Dom.htmlInputElement) - | `Object(Dom.htmlObjectElement) - | `Output(Dom.htmlOutputElement) - | `Select(Dom.htmlSelectElement) - | `Textarea(Dom.htmlTextAreaElement) + | `RadioNodeList(Webapi__Dom__RadioNodeList.t) + | `Button(Dom.element) + | `Fieldset(Dom.element) + | `Input(Webapi__Dom__HtmlInputElement.t) + | `Object(Dom.element) + | `Output(Dom.element) + | `Select(Dom.element) + | `Textarea(Dom.element) ]; include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re index 74015ba8..5f1a2238 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re @@ -1,2 +1,2 @@ -type t = Dom.htmlOptionsCollection; +type t; // TODO: Dom.htmlOptionsCollection; include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; }); diff --git a/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re b/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re index 3178c0f8..aa88bab1 100644 --- a/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re +++ b/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re @@ -5,7 +5,7 @@ module Impl = (T: {type t;}) => { external unsafeAsRadioNodeList: 'a => t_radioNodeList = "%identity"; }; -type t = Dom.radioNodeList; +type t; // TODO: Dom.radioNodeList include Webapi__Dom__NodeList.Impl({type nonrec t = t;}); include Impl({type nonrec t = t;}); diff --git a/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re b/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re index bc9fb27a..4b1acceb 100644 --- a/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re +++ b/src/Webapi/ResizeObserver/Webapi__ResizeObserver__ResizeObserverEntry.re @@ -1,4 +1,4 @@ -type t = Dom.resizeObserverEntry; +type t; // TODO: Dom.resizeObserverEntry; [@bs.get] external contentRect: t => Dom.domRect = ""; [@bs.get] external target: t => Dom.element = ""; diff --git a/src/Webapi/Webapi__ResizeObserver.re b/src/Webapi/Webapi__ResizeObserver.re index 25bdba64..d44c59a3 100644 --- a/src/Webapi/Webapi__ResizeObserver.re +++ b/src/Webapi/Webapi__ResizeObserver.re @@ -1,6 +1,6 @@ module ResizeObserverEntry = Webapi__ResizeObserver__ResizeObserverEntry; -type t = Dom.resizeObserver; +type t; // TODO: Dom.resizeObserver; [@bs.new] external make: (array(ResizeObserverEntry.t) => unit) => t = "ResizeObserver"; From 185a75351bce9ae56e1d969a968aa6db1f6981f0 Mon Sep 17 00:00:00 2001 From: rob Date: Mon, 17 Aug 2020 22:51:35 -0400 Subject: [PATCH 04/14] chore: update CHANGELOG.md --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 442fde02..4879394a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,10 @@ ### 0.20.0 -* Upgraded to bs-platform@8.2.0 * Added bindings for `HTMLFormControlsCollection` * Added binding for `HTMLOptionsCollection` * Added bindings for `RadioNodeList` * Added binding for `Document.forms` * Added binding for `HTMLFormElement.elements` -* ResizeObserver and ResizeObserverEntry now use the rescript Dom phantom type ### 0.19.1 From b9a2328fc3fef250b69b6add3b7b80b2efae3958 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 19 Aug 2020 23:32:14 -0400 Subject: [PATCH 05/14] fix: match HtmlCollection.namedItem signature --- src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re index 4db2c773..d70f4664 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re @@ -17,9 +17,9 @@ let isRadioNodeList: 'a => bool = [%raw {| function(x) { return x instanceof RadioNodeList; } |}]; -[@bs.send] [@bs.return nullable] external _namedItem: (t, string) => option('a) = "namedItem"; -let namedItem = (t, string) => - switch (_namedItem(t, string)) { +[@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; From 22976bc7ae81aa46b3caccf79676898b388a5e3a Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 19 Aug 2020 23:32:46 -0400 Subject: [PATCH 06/14] fix: tagName output is all uppercase --- .../Dom/Webapi__Dom__HtmlFormControlsCollection.re | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re index d70f4664..908fef13 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re @@ -26,13 +26,13 @@ let namedItem = (name, t) => } 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 + | "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 }; } From 2b311c6984b1f7b52f19362c3c3d8b2f00363fac Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 19 Aug 2020 23:33:16 -0400 Subject: [PATCH 07/14] feat: add helper methods, and test fixture --- .../Dom/Webapi__Dom__HtmlFormElement__test.js | 186 +++++++++++++++++- .../Dom/Webapi__Dom__HtmlFormElement.re | 8 + .../Dom/Webapi__Dom__HtmlFormElement__test.re | 97 +++++++++ 3 files changed, 290 insertions(+), 1 deletion(-) diff --git a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js index 28900af1..18e3a451 100644 --- a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js +++ b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js @@ -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 >= 98300745) { + if (variant >= 516394781) { + if (variant !== 843607770) { + if (variant !== 942443387) { + + } else { + console.log("RadioNodeList.value", match[1].value); + } + } else { + Js_exn.raiseError("incorrect namedItem return value"); + } + } else if (variant !== 242538002 && variant < 516394780) { + + } else { + Js_exn.raiseError("incorrect namedItem return value"); + } + } else if (variant >= -908856608) { + if (variant !== -783600662 && variant < 98300744) { + + } 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 */ diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re index 88bfd9e3..e0c9accf 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormElement.re @@ -6,6 +6,14 @@ module Impl = (T: {type t;}) => { type t_htmlFormElement = T.t; + 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 = ""; diff --git a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re index fe0ab98e..b2439c58 100644 --- a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re +++ b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re @@ -1,4 +1,101 @@ +open Webapi.Dom; open Webapi.FormData; open Webapi.Dom.HtmlFormElement; +let form = Document.createElement("form", document) |> asFormElement |> TestHelpers.unsafelyUnwrapOption; + +let usernameInput = Document.createElement("input", document); +Element.setAttribute("type", "text", usernameInput); +Element.setAttribute("name", "username", usernameInput); + +let usernameLabel = Document.createElement("label", document); +let usernameText = Document.createTextNode("Username:", document); +Element.appendChild(usernameText, usernameLabel); +Element.appendChild(usernameInput, usernameLabel); + +let passwordInput = Document.createElement("input", document); +Element.setAttribute("type", "password", passwordInput); +Element.setAttribute("name", "password", passwordInput); + +let passwordLabel = Document.createElement("label", document); +let passwordText = Document.createTextNode("Password:", document); +Element.appendChild(passwordText, passwordLabel); +Element.appendChild(passwordInput, passwordLabel); + +let radioInput1 = Document.createElement("input", document); +Element.setAttribute("type", "radio", radioInput1); +Element.setAttribute("name", "radiogroup", radioInput1); +Element.setAttribute("value", "one", radioInput1); +Element.setAttribute("checked", "true", radioInput1); + +let radioLabel1 = Document.createElement("label", document); +let radioText1 = Document.createTextNode("Choice 1:", document); +Element.appendChild(radioText1, radioLabel1); +Element.appendChild(radioInput1, radioLabel1); + +let radioInput2 = Document.createElement("input", document); +Element.setAttribute("type", "radio", radioInput2); +Element.setAttribute("name", "radiogroup", radioInput2); +Element.setAttribute("value", "two", radioInput2); +// Element.setAttribute("checked", "true", radioInput2); + +let radioLabel2 = Document.createElement("label", document); +let radioText2 = Document.createTextNode("Choice 2:", document); +Element.appendChild(radioText2, radioLabel2); +Element.appendChild(radioInput2, radioLabel2); + +let usernameContainer = Document.createElement("div", document); +let passwordContainer = Document.createElement("div", document); +let radioContainer = Document.createElement("div", document); + +Element.appendChild(usernameLabel, usernameContainer); +Element.appendChild(passwordLabel, passwordContainer); +Element.appendChild(radioLabel1, radioContainer); +Element.appendChild(radioLabel2, radioContainer); +Element.appendChild(usernameContainer, form->asElement); +Element.appendChild(passwordContainer, form->asElement); +Element.appendChild(radioContainer, form->asElement); + +let body = + Document.asHtmlDocument(document)->Belt.Option.flatMap(HtmlDocument.body)->TestHelpers.unsafelyUnwrapOption; + +Element.appendChild(form->asElement, body); + +let collection = elements(form); + +Js.log2("HtmlFormElement.elements:", collection); + +let len = HtmlFormControlsCollection.length(collection); +Js.log2("HtmlFormControlsCollection.length:", len); + +let el0 = HtmlFormControlsCollection.item(0, collection); +Js.log2("HtmlFormControlsCollection.item:", el0); + +let el0 = HtmlFormControlsCollection.namedItem("username", collection); +Js.log2("HtmlFormControlsCollection.namedItem:", el0); + +let el1 = HtmlFormControlsCollection.item(1, collection); +Js.log2("HtmlFormControlsCollection.length:", el1); + +let el1 = HtmlFormControlsCollection.namedItem("password", collection); +Js.log2("HtmlFormControlsCollection.namedItem:", el1); + +let radioNodeList = HtmlFormControlsCollection.item(2, collection); +Js.log2("HtmlFormControlsCollection.namedItem:", radioNodeList); + +let radioNodeList = HtmlFormControlsCollection.namedItem("radiogroup", collection); +Js.log2("HtmlFormControlsCollection.namedItem:", radioNodeList); + +switch (TestHelpers.unsafelyUnwrapOption(radioNodeList)) { +| `Button(_) +| `Fieldset(_) +| `Input(_) +| `Object(_) +| `Output(_) +| `Select(_) +| `Textarea(_) => Js.Exn.raiseError("incorrect namedItem return value") +| `RadioNodeList(radioNodeList) => Js.log2("RadioNodeList.value", RadioNodeList.value(radioNodeList)) +| _ => () +}; + let test_data = formElement => formElement |> data |> get("foo"); From c77f5208686b01fade1744295576b4f8ef236ccd Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 19 Aug 2020 23:56:10 -0400 Subject: [PATCH 08/14] chore: add spec header to files --- src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re | 3 +++ src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re | 3 +++ src/Webapi/Dom/Webapi__Dom__RadioNodeList.re | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re index 908fef13..e5afe414 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re @@ -1,3 +1,6 @@ +/** + * Spec: https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#htmlformcontrolscollection + */ type t; // TODO: Dom.htmlFormControlsCollection type t_namedItem = [ diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re index 5f1a2238..d7c79cbe 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re @@ -1,2 +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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re b/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re index aa88bab1..a28e4fd5 100644 --- a/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re +++ b/src/Webapi/Dom/Webapi__Dom__RadioNodeList.re @@ -1,3 +1,6 @@ +/** + * Spec: https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#radionodelist + */ module Impl = (T: {type t;}) => { type t_radioNodeList = T.t; [@bs.get] external value: t_radioNodeList => string = "value"; From 93d673575929eb7e7d6b96416f2555b76028ac87 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 19 Aug 2020 23:57:49 -0400 Subject: [PATCH 09/14] fix: typo --- .../Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js | 10 +++++----- .../Dom/Webapi__Dom__HtmlFormControlsCollection.re | 8 ++++---- tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js index 18e3a451..d641b8ef 100644 --- a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js +++ b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js @@ -134,9 +134,9 @@ var match = TestHelpers.unsafelyUnwrapOption(radioNodeList$1); if (typeof match !== "number") { var variant = match[0]; - if (variant >= 98300745) { - if (variant >= 516394781) { - if (variant !== 843607770) { + if (variant >= 96709417) { + if (variant >= 488741627) { + if (variant !== 516394780) { if (variant !== 942443387) { } else { @@ -145,13 +145,13 @@ if (typeof match !== "number") { } else { Js_exn.raiseError("incorrect namedItem return value"); } - } else if (variant !== 242538002 && variant < 516394780) { + } else if (variant !== 242538002 && variant < 488741626) { } else { Js_exn.raiseError("incorrect namedItem return value"); } } else if (variant >= -908856608) { - if (variant !== -783600662 && variant < 98300744) { + if (variant !== -783600662 && variant < 96709416) { } else { Js_exn.raiseError("incorrect namedItem return value"); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re index e5afe414..2696c8be 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re @@ -6,12 +6,12 @@ type t; // TODO: Dom.htmlFormControlsCollection type t_namedItem = [ | `RadioNodeList(Webapi__Dom__RadioNodeList.t) | `Button(Dom.element) - | `Fieldset(Dom.element) + | `FieldSet(Dom.element) | `Input(Webapi__Dom__HtmlInputElement.t) | `Object(Dom.element) | `Output(Dom.element) | `Select(Dom.element) - | `Textarea(Dom.element) + | `TextArea(Dom.element) ]; include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; }); @@ -30,12 +30,12 @@ let namedItem = (name, t) => 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 + | "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 + | "TEXTAREA" => el->Obj.magic->`TextArea->Some | _ => None }; } diff --git a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re index b2439c58..7e2ccfee 100644 --- a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re +++ b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re @@ -88,12 +88,12 @@ Js.log2("HtmlFormControlsCollection.namedItem:", radioNodeList); switch (TestHelpers.unsafelyUnwrapOption(radioNodeList)) { | `Button(_) -| `Fieldset(_) +| `FieldSet(_) | `Input(_) | `Object(_) | `Output(_) | `Select(_) -| `Textarea(_) => Js.Exn.raiseError("incorrect namedItem return value") +| `TextArea(_) => Js.Exn.raiseError("incorrect namedItem return value") | `RadioNodeList(radioNodeList) => Js.log2("RadioNodeList.value", RadioNodeList.value(radioNodeList)) | _ => () }; From 1a0ee42ddd73e9b3c4fed1a76db975579289b040 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 19 Aug 2020 23:59:32 -0400 Subject: [PATCH 10/14] feat: add stubs for Button, FieldSet, Object, Output, Select, & TextArea --- src/Webapi/Dom/Webapi__Dom__HtmlButtonElement.re | 16 ++++++++++++++++ .../Dom/Webapi__Dom__HtmlFieldSetElement.re | 16 ++++++++++++++++ .../Webapi__Dom__HtmlFormControlsCollection.re | 12 ++++++------ src/Webapi/Dom/Webapi__Dom__HtmlObjectElement.re | 16 ++++++++++++++++ src/Webapi/Dom/Webapi__Dom__HtmlOutputElement.re | 16 ++++++++++++++++ src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re | 16 ++++++++++++++++ .../Dom/Webapi__Dom__HtmlTextAreaElement.re | 16 ++++++++++++++++ 7 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlButtonElement.re create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlFieldSetElement.re create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlObjectElement.re create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlOutputElement.re create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re create mode 100644 src/Webapi/Dom/Webapi__Dom__HtmlTextAreaElement.re diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlButtonElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlButtonElement.re new file mode 100644 index 00000000..b8ddb71e --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlButtonElement.re @@ -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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFieldSetElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlFieldSetElement.re new file mode 100644 index 00000000..ceb44e6b --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFieldSetElement.re @@ -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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re index 2696c8be..57684c03 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.re @@ -5,13 +5,13 @@ type t; // TODO: Dom.htmlFormControlsCollection type t_namedItem = [ | `RadioNodeList(Webapi__Dom__RadioNodeList.t) - | `Button(Dom.element) - | `FieldSet(Dom.element) + | `Button(Webapi__Dom__HtmlButtonElement.t) + | `FieldSet(Webapi__Dom__HtmlFieldSetElement.t) | `Input(Webapi__Dom__HtmlInputElement.t) - | `Object(Dom.element) - | `Output(Dom.element) - | `Select(Dom.element) - | `TextArea(Dom.element) + | `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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlObjectElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlObjectElement.re new file mode 100644 index 00000000..629d0594 --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlObjectElement.re @@ -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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlOutputElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlOutputElement.re new file mode 100644 index 00000000..1130fcf0 --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlOutputElement.re @@ -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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re new file mode 100644 index 00000000..f63532a7 --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re @@ -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; }); diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlTextAreaElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlTextAreaElement.re new file mode 100644 index 00000000..949ec69b --- /dev/null +++ b/src/Webapi/Dom/Webapi__Dom__HtmlTextAreaElement.re @@ -0,0 +1,16 @@ +/** + * Spec: https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element + */ +module Impl = (T: {type t;}) => { + type t_htmlTextAreaElement = T.t; + + // TODO +}; + +type t; // TODO: Dom.htmlTextAreaElement + +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; }); From 0bb5fbbd4cc91d71fc1cd174fe65753039905e84 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 20 Aug 2020 02:01:03 -0400 Subject: [PATCH 11/14] chore: add module aliases --- src/Webapi/Webapi__Dom.re | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Webapi/Webapi__Dom.re b/src/Webapi/Webapi__Dom.re index d4f4550e..3e2e13d5 100644 --- a/src/Webapi/Webapi__Dom.re +++ b/src/Webapi/Webapi__Dom.re @@ -28,9 +28,15 @@ module HtmlFormControlsCollection = Webapi__Dom__HtmlFormControlsCollection; module HtmlOptionsCollection = Webapi__Dom__HtmlOptionsCollection; module HtmlDocument = Webapi__Dom__HtmlDocument; module HtmlElement = Webapi__Dom__HtmlElement; +module HtmlButtonElement = Webapi__Dom__HtmlButtonElement; +module HtmlFieldSetElement = Webapi__Dom__HtmlFieldSetElement; module HtmlFormElement = Webapi__Dom__HtmlFormElement; module HtmlImageElement = Webapi__Dom__HtmlImageElement; module HtmlInputElement = Webapi__Dom__HtmlInputElement; +module HtmlObjectElement = Webapi__Dom__HtmlObjectElement; +module HtmlOutputElement = Webapi__Dom__HtmlOutputElement; +module HtmlSelectElement = Webapi__Dom__HtmlSelectElement; +module HtmlTextAreaElement = Webapi__Dom__HtmlTextAreaElement; module IdbVersionChangeEvent = Webapi__Dom__IdbVersionChangeEvent; module Image = Webapi__Dom__Image; module InputEvent = Webapi__Dom__InputEvent; From f37916154f89f812229a50bc6203e3f08024e9f2 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 20 Aug 2020 02:01:41 -0400 Subject: [PATCH 12/14] feat: HtmlOptionsCollection implementation, HtmlSelectElement.options --- .../Dom/Webapi__Dom__HtmlFormElement__test.js | 164 +++++++++++++++--- .../Dom/Webapi__Dom__HtmlOptionsCollection.re | 20 +++ .../Dom/Webapi__Dom__HtmlSelectElement.re | 12 ++ .../Dom/Webapi__Dom__HtmlFormElement__test.re | 119 ++++++++++--- 4 files changed, 268 insertions(+), 47 deletions(-) diff --git a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js index d641b8ef..ea644cac 100644 --- a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js +++ b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js @@ -6,8 +6,28 @@ 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__HtmlSelectElement = require("../../../src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.js"); var Webapi__Dom__HtmlFormControlsCollection = require("../../../src/Webapi/Dom/Webapi__Dom__HtmlFormControlsCollection.js"); +function createElement(__x) { + return document.createElement(__x); +} + +function createTextNode(__x) { + return document.createTextNode(__x); +} + +function createInput(param) { + return document.createElement("input"); +} + +function createLabelWithText(text) { + var el = document.createElement("label"); + var textNode = document.createTextNode(text); + el.appendChild(textNode); + return el; +} + var form = TestHelpers.unsafelyUnwrapOption(Webapi__Dom__HtmlFormElement.asFormElement(document.createElement("form"))); var usernameInput = document.createElement("input"); @@ -16,11 +36,7 @@ usernameInput.setAttribute("type", "text"); usernameInput.setAttribute("name", "username"); -var usernameLabel = document.createElement("label"); - -var usernameText = document.createTextNode("Username:"); - -usernameLabel.appendChild(usernameText); +var usernameLabel = createLabelWithText("Username:"); usernameLabel.appendChild(usernameInput); @@ -30,11 +46,7 @@ passwordInput.setAttribute("type", "password"); passwordInput.setAttribute("name", "password"); -var passwordLabel = document.createElement("label"); - -var passwordText = document.createTextNode("Password:"); - -passwordLabel.appendChild(passwordText); +var passwordLabel = createLabelWithText("Password:"); passwordLabel.appendChild(passwordInput); @@ -48,11 +60,7 @@ radioInput1.setAttribute("value", "one"); radioInput1.setAttribute("checked", "true"); -var radioLabel1 = document.createElement("label"); - -var radioText1 = document.createTextNode("Choice 1:"); - -radioLabel1.appendChild(radioText1); +var radioLabel1 = createLabelWithText("Choice 1:"); radioLabel1.appendChild(radioInput1); @@ -64,13 +72,17 @@ radioInput2.setAttribute("name", "radiogroup"); radioInput2.setAttribute("value", "two"); -var radioLabel2 = document.createElement("label"); +var radioLabel2 = createLabelWithText("Choice 2:"); + +radioLabel2.appendChild(radioInput2); -var radioText2 = document.createTextNode("Choice 2:"); +var select = document.createElement("select"); -radioLabel2.appendChild(radioText2); +select.setAttribute("name", "select"); -radioLabel2.appendChild(radioInput2); +var selectLabel = createLabelWithText("Select:"); + +selectLabel.appendChild(select); var usernameContainer = document.createElement("div"); @@ -78,6 +90,8 @@ var passwordContainer = document.createElement("div"); var radioContainer = document.createElement("div"); +var selectContainer = document.createElement("div"); + usernameContainer.appendChild(usernameLabel); passwordContainer.appendChild(passwordLabel); @@ -86,12 +100,16 @@ radioContainer.appendChild(radioLabel1); radioContainer.appendChild(radioLabel2); +selectContainer.appendChild(selectLabel); + form.appendChild(usernameContainer); form.appendChild(passwordContainer); form.appendChild(radioContainer); +form.appendChild(selectContainer); + var body = TestHelpers.unsafelyUnwrapOption(Belt_Option.flatMap(Webapi__Dom__Document.asHtmlDocument(document), (function (prim) { return Caml_option.nullable_to_opt(prim.body); }))); @@ -163,31 +181,131 @@ if (typeof match !== "number") { } } +var select$1 = TestHelpers.unsafelyUnwrapOption(Webapi__Dom__HtmlSelectElement.asSelectElement(select)); + +var opts = select$1.options; + +console.log("HtmlSelectElement.options:", opts); + +opts.length = 3; + +console.log("collection length:", opts.length); + +opts[0] = null; + +console.log("collection length:", opts.length); + +opts[2] = document.createElement("option"); + +console.log("collection length:", opts.length); + +opts.length = 0; + +var opt1 = document.createElement("option"); + +opt1.setAttribute("value", "1"); + +opt1.appendChild(document.createTextNode("opt1")); + +opts.add(opt1); + +var selectedIndex = opts.selectedIndex = 0; + +console.log("collection length:", opts.length); + +console.log("HtmlOptionsCollection.setSelectedIndex", selectedIndex); + +var opt2 = document.createElement("option"); + +opt2.setAttribute("value", "2"); + +opt2.appendChild(document.createTextNode("opt2")); + +var item = opts.item(0); + +console.log("HtmlOptionsCollection.item:", (item == null) ? undefined : Caml_option.some(item)); + +console.log("collection length:", opts.length); + +opts.add(opt2, 0); + +opts.selectedIndex = opt2; + +var item$1 = opts.item(0); + +console.log("HtmlOptionsCollection.addBefore:", (item$1 == null) ? undefined : Caml_option.some(item$1)); + +console.log("collection length:", opts.length); + +console.log("selected index", opts.selectedIndex); + +var opt3 = document.createElement("option"); + +opt3.setAttribute("value", "3"); + +opt3.appendChild(document.createTextNode("opt3")); + +opts.add(opt3, opt2); + +var item$2 = opts.item(0); + +console.log("HtmlOptionsCollection.addBeforeElement:", (item$2 == null) ? undefined : Caml_option.some(item$2)); + +console.log("collection length:", opts.length); + +var item$3 = opts.selectedIndex; + +console.log("HtmlOptionsCollection.selectedIndex:", item$3); + +var item$4 = opts.selectedIndex = opt3; + +console.log("HtmlOptionsCollection.setSelectedElement:", item$4); + +var item$5 = opts.selectedIndex; + +console.log("HtmlOptionsCollection.selectedIndex:", item$5); + +opts.remove(0); + +console.log("collection length:", opts.length); + function test_data(formElement) { return new FormData(formElement).get("foo"); } +var formEl = form; + +exports.createElement = createElement; +exports.createTextNode = createTextNode; +exports.createInput = createInput; +exports.createLabelWithText = createLabelWithText; 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.selectLabel = selectLabel; exports.usernameContainer = usernameContainer; exports.passwordContainer = passwordContainer; exports.radioContainer = radioContainer; +exports.selectContainer = selectContainer; +exports.formEl = formEl; exports.body = body; exports.collection = collection; exports.len = len; exports.el0 = el0$1; exports.el1 = el1$1; exports.radioNodeList = radioNodeList$1; +exports.select = select$1; +exports.opts = opts; +exports.opt1 = opt1; +exports.selectedIndex = selectedIndex; +exports.opt2 = opt2; +exports.opt3 = opt3; +exports.item = item$5; exports.test_data = test_data; /* form Not a pure module */ diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re index d7c79cbe..ec9e8d1b 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlOptionsCollection.re @@ -3,3 +3,23 @@ */ type t; // TODO: Dom.htmlOptionsCollection; include Webapi__Dom__HtmlCollection.Impl({ type nonrec t = t; }); + +/** Properties */ + +[@bs.set] external setLength: (t, int) => unit = "length"; +[@bs.set_index] external setItem: (t, int, Dom.element) => unit = ""; +[@bs.set_index] external clearItem: (t, int, Js.null('a)) => unit = ""; + +[@bs.get] external selectedIndex: t => int = "selectedIndex"; +[@bs.set] external setSelectedIndex: (t, int) => int = "selectedIndex"; +[@bs.set] external setSelectedElement: (t, Dom.element) => Dom.element = "selectedIndex"; + +/** Methods */ + +/** + * This method will throw a "HierarchyRequestError" DOMException if element is an ancestor of the element into which it is to be inserted. + */ +[@bs.send.pipe: t] external add: (Dom.element) => unit = "add"; +[@bs.send.pipe: t] external addBefore: (Dom.element, int) => unit = "add"; +[@bs.send.pipe: t] external addBeforeElement: (Dom.element, Dom.element) => unit = "add"; +[@bs.send.pipe: t] external remove: int => unit = "remove"; diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re index f63532a7..8d3d4249 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re @@ -4,7 +4,19 @@ module Impl = (T: {type t;}) => { type t_htmlSelectElement = T.t; + external unsafeAsSelectElement: Dom.element => t_htmlSelectElement = "%identity"; + external asElement: t_htmlSelectElement => Dom.element = "%identity"; + + let asSelectElement = (el): option(t_htmlSelectElement) => switch(Webapi__Dom__Element.tagName(el)) { + | "SELECT" => el->unsafeAsSelectElement->Some + | _ => None + }; + // TODO + + /** Properties */ + + [@bs.get] external options: t_htmlSelectElement => Webapi__Dom__HtmlOptionsCollection.t = "options"; }; type t; // TODO: Dom.htmlSelectElement diff --git a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re index 7e2ccfee..a4e1e89f 100644 --- a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re +++ b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re @@ -2,64 +2,76 @@ open Webapi.Dom; open Webapi.FormData; open Webapi.Dom.HtmlFormElement; -let form = Document.createElement("form", document) |> asFormElement |> TestHelpers.unsafelyUnwrapOption; +let createElement = Document.createElement(_, document); +let createTextNode = Document.createTextNode(_, document); +let createInput = () => createElement("input"); +let createLabelWithText = (text) => { + let el = createElement("label"); + let textNode = createTextNode(text); + Element.appendChild(textNode, el); + el; +}; + +let form = createElement("form") |> asFormElement |> TestHelpers.unsafelyUnwrapOption; -let usernameInput = Document.createElement("input", document); +let usernameInput = createInput(); Element.setAttribute("type", "text", usernameInput); Element.setAttribute("name", "username", usernameInput); -let usernameLabel = Document.createElement("label", document); -let usernameText = Document.createTextNode("Username:", document); -Element.appendChild(usernameText, usernameLabel); +let usernameLabel = createLabelWithText("Username:"); Element.appendChild(usernameInput, usernameLabel); -let passwordInput = Document.createElement("input", document); +let passwordInput = createInput(); Element.setAttribute("type", "password", passwordInput); Element.setAttribute("name", "password", passwordInput); -let passwordLabel = Document.createElement("label", document); -let passwordText = Document.createTextNode("Password:", document); -Element.appendChild(passwordText, passwordLabel); +let passwordLabel = createLabelWithText("Password:"); Element.appendChild(passwordInput, passwordLabel); -let radioInput1 = Document.createElement("input", document); +let radioInput1 = createInput(); Element.setAttribute("type", "radio", radioInput1); Element.setAttribute("name", "radiogroup", radioInput1); Element.setAttribute("value", "one", radioInput1); Element.setAttribute("checked", "true", radioInput1); -let radioLabel1 = Document.createElement("label", document); -let radioText1 = Document.createTextNode("Choice 1:", document); -Element.appendChild(radioText1, radioLabel1); +let radioLabel1 = createLabelWithText("Choice 1:"); Element.appendChild(radioInput1, radioLabel1); -let radioInput2 = Document.createElement("input", document); +let radioInput2 = createInput(); Element.setAttribute("type", "radio", radioInput2); Element.setAttribute("name", "radiogroup", radioInput2); Element.setAttribute("value", "two", radioInput2); // Element.setAttribute("checked", "true", radioInput2); -let radioLabel2 = Document.createElement("label", document); -let radioText2 = Document.createTextNode("Choice 2:", document); -Element.appendChild(radioText2, radioLabel2); +let radioLabel2 = createLabelWithText("Choice 2:"); Element.appendChild(radioInput2, radioLabel2); -let usernameContainer = Document.createElement("div", document); -let passwordContainer = Document.createElement("div", document); -let radioContainer = Document.createElement("div", document); +let select = createElement("select"); +Element.setAttribute("name", "select", select); +let selectLabel = createLabelWithText("Select:"); +Element.appendChild(select, selectLabel); + +let usernameContainer = createElement("div"); +let passwordContainer = createElement("div"); +let radioContainer = createElement("div"); +let selectContainer = createElement("div"); + +let formEl = form->asElement; Element.appendChild(usernameLabel, usernameContainer); Element.appendChild(passwordLabel, passwordContainer); Element.appendChild(radioLabel1, radioContainer); Element.appendChild(radioLabel2, radioContainer); -Element.appendChild(usernameContainer, form->asElement); -Element.appendChild(passwordContainer, form->asElement); -Element.appendChild(radioContainer, form->asElement); +Element.appendChild(selectLabel, selectContainer); +Element.appendChild(usernameContainer, formEl); +Element.appendChild(passwordContainer, formEl); +Element.appendChild(radioContainer, formEl); +Element.appendChild(selectContainer, formEl); let body = Document.asHtmlDocument(document)->Belt.Option.flatMap(HtmlDocument.body)->TestHelpers.unsafelyUnwrapOption; -Element.appendChild(form->asElement, body); +Element.appendChild(formEl, body); let collection = elements(form); @@ -98,4 +110,63 @@ switch (TestHelpers.unsafelyUnwrapOption(radioNodeList)) { | _ => () }; +let select = HtmlSelectElement.asSelectElement(select) + ->TestHelpers.unsafelyUnwrapOption; + +let opts = HtmlSelectElement.options(select); +Js.log2("HtmlSelectElement.options:", opts); + +HtmlOptionsCollection.setLength(opts, 3); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); +HtmlOptionsCollection.clearItem(opts, 0, Js.Null.empty); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); +HtmlOptionsCollection.setItem(opts, 2, createElement("option")); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); + +HtmlOptionsCollection.setLength(opts, 0); + +let opt1 = createElement("option"); +Element.setAttribute("value", "1", opt1); +Element.appendChild(createTextNode("opt1"), opt1); + +HtmlOptionsCollection.add(opt1, opts); +let selectedIndex = HtmlOptionsCollection.setSelectedIndex(opts, 0); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); +Js.log2("HtmlOptionsCollection.setSelectedIndex", selectedIndex); + +let opt2 = createElement("option"); +Element.setAttribute("value", "2", opt2); +Element.appendChild(createTextNode("opt2"), opt2); + +let item = HtmlOptionsCollection.item(0, opts); +Js.log2("HtmlOptionsCollection.item:", item); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); + +HtmlOptionsCollection.addBefore(opt2, 0, opts); +HtmlOptionsCollection.setSelectedElement(opts, opt2); +let item = HtmlOptionsCollection.item(0, opts); +Js.log2("HtmlOptionsCollection.addBefore:", item); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); +Js.log2("selected index", HtmlOptionsCollection.selectedIndex(opts)); + +let opt3 = createElement("option"); +Element.setAttribute("value", "3", opt3); +Element.appendChild(createTextNode("opt3"), opt3); + +HtmlOptionsCollection.addBeforeElement(opt3, opt2, opts); +let item = HtmlOptionsCollection.item(0, opts); +Js.log2("HtmlOptionsCollection.addBeforeElement:", item); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); + +let item = HtmlOptionsCollection.selectedIndex(opts); +Js.log2("HtmlOptionsCollection.selectedIndex:", item); + +let item = HtmlOptionsCollection.setSelectedElement(opts, opt3); +Js.log2("HtmlOptionsCollection.setSelectedElement:", item); +let item = HtmlOptionsCollection.selectedIndex(opts); +Js.log2("HtmlOptionsCollection.selectedIndex:", item); + +HtmlOptionsCollection.remove(0, opts); +Js.log2("collection length:", HtmlOptionsCollection.length(opts)); + let test_data = formElement => formElement |> data |> get("foo"); From 96dda030c0163be3c3f7bcde3ca17ffce3431df6 Mon Sep 17 00:00:00 2001 From: rob Date: Tue, 25 Aug 2020 23:23:00 -0400 Subject: [PATCH 13/14] refactor: rename asSelectElement to ofElement --- lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js | 2 +- src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re | 2 +- tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js index ea644cac..e1dc35c3 100644 --- a/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js +++ b/lib/js/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.js @@ -181,7 +181,7 @@ if (typeof match !== "number") { } } -var select$1 = TestHelpers.unsafelyUnwrapOption(Webapi__Dom__HtmlSelectElement.asSelectElement(select)); +var select$1 = TestHelpers.unsafelyUnwrapOption(Webapi__Dom__HtmlSelectElement.ofElement(select)); var opts = select$1.options; diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re index 8d3d4249..3ab70cd5 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re @@ -7,7 +7,7 @@ module Impl = (T: {type t;}) => { external unsafeAsSelectElement: Dom.element => t_htmlSelectElement = "%identity"; external asElement: t_htmlSelectElement => Dom.element = "%identity"; - let asSelectElement = (el): option(t_htmlSelectElement) => switch(Webapi__Dom__Element.tagName(el)) { + let ofElement = (el): option(t_htmlSelectElement) => switch(Webapi__Dom__Element.tagName(el)) { | "SELECT" => el->unsafeAsSelectElement->Some | _ => None }; diff --git a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re index a4e1e89f..aa1b4038 100644 --- a/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re +++ b/tests/Webapi/Dom/Webapi__Dom__HtmlFormElement__test.re @@ -110,7 +110,7 @@ switch (TestHelpers.unsafelyUnwrapOption(radioNodeList)) { | _ => () }; -let select = HtmlSelectElement.asSelectElement(select) +let select = HtmlSelectElement.ofElement(select) ->TestHelpers.unsafelyUnwrapOption; let opts = HtmlSelectElement.options(select); From cf203244d97bda3d51765069ac3da4f781ed7562 Mon Sep 17 00:00:00 2001 From: rob Date: Tue, 25 Aug 2020 23:26:04 -0400 Subject: [PATCH 14/14] refactor: rename unsafeAsSelectElement to unsafeOfElement --- src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re index 3ab70cd5..647bd5c8 100644 --- a/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re +++ b/src/Webapi/Dom/Webapi__Dom__HtmlSelectElement.re @@ -4,11 +4,11 @@ module Impl = (T: {type t;}) => { type t_htmlSelectElement = T.t; - external unsafeAsSelectElement: Dom.element => t_htmlSelectElement = "%identity"; + external unsafeOfElement: Dom.element => t_htmlSelectElement = "%identity"; external asElement: t_htmlSelectElement => Dom.element = "%identity"; let ofElement = (el): option(t_htmlSelectElement) => switch(Webapi__Dom__Element.tagName(el)) { - | "SELECT" => el->unsafeAsSelectElement->Some + | "SELECT" => el->unsafeOfElement->Some | _ => None };