summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2018-01-20 10:22:55 +0000
committerDaniel Silverstone <dsilvers@digital-scurf.org>2018-01-21 10:38:48 +0000
commite28c8c517ef1e89638de059c5f8da6cb8dab0adc (patch)
treec744435d4010a632b7fda19c01d03650f15e36dc
parent9158d4bedb8b16b8bc413c365a70321db6fbb1cd (diff)
downloadlibdom-dsilvers/forms1.tar.gz
libdom-dsilvers/forms1.tar.bz2
Add HTMLFormControlsCollection and RadioNodeListdsilvers/forms1
These are a necessary step on the way to libdom being able to manage the content and behaviours of web forms.
-rw-r--r--Makefile2
-rw-r--r--include/dom/dom.h2
-rw-r--r--include/dom/html/html_form_controls_collection.h38
-rw-r--r--include/dom/html/html_form_element.h4
-rw-r--r--include/dom/html/html_radio_nodelist.h33
-rw-r--r--src/html/Makefile3
-rw-r--r--src/html/html_document_strings.h3
-rw-r--r--src/html/html_form_controls_collection.c69
-rw-r--r--src/html/html_form_controls_collection.h23
-rw-r--r--src/html/html_form_element.c81
-rw-r--r--src/html/html_form_element.h4
-rw-r--r--src/html/html_radio_nodelist.c419
-rw-r--r--src/html/html_radio_nodelist.h35
13 files changed, 656 insertions, 60 deletions
diff --git a/Makefile b/Makefile
index 984a020..6db4201 100644
--- a/Makefile
+++ b/Makefile
@@ -89,6 +89,8 @@ Is := include/dom/html
I := /$(INCLUDEDIR)/dom/html
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_document.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_collection.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_radio_nodelist.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_form_controls_collection.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_element.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_elements.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_html_element.h
diff --git a/include/dom/dom.h b/include/dom/dom.h
index 0740fe9..26f139c 100644
--- a/include/dom/dom.h
+++ b/include/dom/dom.h
@@ -40,6 +40,8 @@
/* DOM HTML headers */
#include <dom/html/html_collection.h>
+#include <dom/html/html_radio_nodelist.h>
+#include <dom/html/html_form_controls_collection.h>
#include <dom/html/html_document.h>
#include <dom/html/html_element.h>
#include <dom/html/html_html_element.h>
diff --git a/include/dom/html/html_form_controls_collection.h b/include/dom/html/html_form_controls_collection.h
new file mode 100644
index 0000000..23a1725
--- /dev/null
+++ b/include/dom/html/html_form_controls_collection.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2018 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ */
+
+#ifndef dom_html_form_controls_collection_h_
+#define dom_html_form_controls_collection_h_
+
+#include <dom/core/exceptions.h>
+#include <dom/core/string.h>
+
+struct dom_node;
+struct dom_html_radionodelist;
+
+typedef struct dom_html_collection dom_html_form_controls_collection;
+
+#define dom_html_form_controls_collection_get_length(col, len) \
+ dom_html_collection_get_length((dom_html_collection *)(col), (len))
+
+#define dom_html_form_controls_collection_item(col, index, node) \
+ dom_html_collection((dom_html_collection *)(col), (index), (node))
+
+#define dom_html_form_controls_collection_named_item(col, name, node) \
+ dom_html_collection((dom_html_collection *)(col), (name), (node))
+
+dom_exception dom_html_form_controls_collection_named_items(dom_html_form_controls_collection *col,
+ dom_string *name, struct dom_html_radionodelist **nodes);
+
+#define dom_html_form_controls_collection_ref(col) \
+ dom_html_collection_ref((dom_html_collection *)(col))
+
+#define dom_html_form_controls_collection_unref(col) \
+ dom_html_collection_unref((dom_html_collection *)(col))
+
+#endif
+
diff --git a/include/dom/html/html_form_element.h b/include/dom/html/html_form_element.h
index 81637a3..fe4bf3f 100644
--- a/include/dom/html/html_form_element.h
+++ b/include/dom/html/html_form_element.h
@@ -11,12 +11,12 @@
#include <dom/core/exceptions.h>
#include <dom/core/string.h>
-struct dom_html_collection;
+#include <dom/html/html_form_controls_collection.h>
typedef struct dom_html_form_element dom_html_form_element;
dom_exception dom_html_form_element_get_elements(dom_html_form_element *ele,
- struct dom_html_collection **col);
+ dom_html_form_controls_collection **col);
dom_exception dom_html_form_element_get_length(dom_html_form_element *ele,
uint32_t *len);
diff --git a/include/dom/html/html_radio_nodelist.h b/include/dom/html/html_radio_nodelist.h
new file mode 100644
index 0000000..c15ec7c
--- /dev/null
+++ b/include/dom/html/html_radio_nodelist.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2018 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ */
+
+#ifndef dom_html_radio_nodelist_h_
+#define dom_html_radio_nodelist_h_
+
+#include <dom/core/exceptions.h>
+#include <dom/core/string.h>
+
+struct dom_node;
+
+typedef struct dom_html_radio_nodelist dom_html_radio_nodelist;
+
+dom_exception dom_html_radio_nodelist_get_length(dom_html_radio_nodelist *nodelist,
+ uint32_t *len);
+dom_exception dom_html_radio_nodelist_item(dom_html_radio_nodelist *nodelist,
+ uint32_t index, struct dom_node **node);
+
+dom_exception dom_html_radio_nodelist_get_value(dom_html_radio_nodelist *nodelist,
+ dom_string **value);
+
+dom_exception dom_html_radio_nodelist_set_value(dom_html_radio_nodelist *nodelist,
+ dom_string *value);
+
+void dom_html_radio_nodelist_ref(dom_html_radio_nodelist *nodelist);
+void dom_html_radio_nodelist_unref(dom_html_radio_nodelist *nodelist);
+
+#endif
+
diff --git a/src/html/Makefile b/src/html/Makefile
index c98ce9a..55a2d15 100644
--- a/src/html/Makefile
+++ b/src/html/Makefile
@@ -3,7 +3,7 @@ DIR_SOURCES := \
html_document.c html_collection.c html_options_collection.c \
html_element.c html_html_element.c html_head_element.c \
html_link_element.c html_title_element.c html_meta_element.c \
- html_base_element.c html_style_element.c \
+ html_base_element.c html_style_element.c html_form_controls_collection.c \
html_body_element.c html_form_element.c html_select_element.c \
html_button_element.c html_input_element.c html_text_area_element.c \
html_opt_group_element.c html_option_element.c html_hr_element.c \
@@ -19,6 +19,7 @@ DIR_SOURCES := \
html_tablecell_element.c html_tablecol_element.c html_tablesection_element.c \
html_table_element.c html_tablerow_element.c html_frameset_element.c \
html_frame_element.c html_iframe_element.c html_isindex_element.c \
+ html_radio_nodelist.c \
UNINMPLEMENTED_SOURCES := \
diff --git a/src/html/html_document_strings.h b/src/html/html_document_strings.h
index 8b5fea7..26c4dde 100644
--- a/src/html/html_document_strings.h
+++ b/src/html/html_document_strings.h
@@ -145,6 +145,9 @@ HTML_DOCUMENT_STRINGS_ACTION1(select)
HTML_DOCUMENT_STRINGS_ACTION1(click)
HTML_DOCUMENT_STRINGS_ACTION1(submit)
HTML_DOCUMENT_STRINGS_ACTION1(reset)
+/* For dom_html_radio_nodelist */
+HTML_DOCUMENT_STRINGS_ACTION1(on)
+HTML_DOCUMENT_STRINGS_ACTION1(radio)
#ifdef HTML_DOCUMENT_STRINGS_SUFFIX
HTML_DOCUMENT_STRINGS_SUFFIX
diff --git a/src/html/html_form_controls_collection.c b/src/html/html_form_controls_collection.c
new file mode 100644
index 0000000..f42f3f7
--- /dev/null
+++ b/src/html/html_form_controls_collection.c
@@ -0,0 +1,69 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2018 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "html/html_form_controls_collection.h"
+#include "html/html_document.h"
+#include "html/html_form_element.h"
+
+#include "html/html_input_element.h"
+#include "html/html_select_element.h"
+#include "html/html_text_area_element.h"
+#include "html/html_button_element.h"
+
+#include "core/node.h"
+#include "core/element.h"
+#include "core/string.h"
+
+/*-----------------------------------------------------------------------*/
+/* Internal functions */
+
+/* Callback function to test whether certain node is a form control, see
+ * src/html/html_collection.h for detail. */
+bool _dom_is_form_control(struct dom_node_internal *node, void *ctx)
+{
+ struct dom_html_document *doc =
+ (struct dom_html_document *)(node->owner);
+ struct dom_html_form_element *form = ctx;
+
+
+ assert(node->type == DOM_ELEMENT_NODE);
+
+ /* Form controls are INPUT TEXTAREA SELECT and BUTTON*/
+ if (dom_string_caseless_isequal(node->name,
+ doc->elements[DOM_HTML_ELEMENT_TYPE_INPUT]))
+ return ((dom_html_input_element *)node)->form == form;
+ if (dom_string_caseless_isequal(node->name,
+ doc->elements[DOM_HTML_ELEMENT_TYPE_TEXTAREA]))
+ return ((dom_html_text_area_element *)node)->form == form;
+ if (dom_string_caseless_isequal(node->name,
+ doc->elements[DOM_HTML_ELEMENT_TYPE_SELECT]))
+ return ((dom_html_select_element *)node)->form == form;
+ if (dom_string_caseless_isequal(node->name,
+ doc->elements[DOM_HTML_ELEMENT_TYPE_BUTTON])) {
+ return ((dom_html_button_element *)node)->form == form;
+ }
+
+ return false;
+}
+
+
+dom_exception _dom_html_form_controls_collection_create(struct dom_html_form_element *form,
+ dom_html_form_controls_collection **col)
+{
+ dom_html_document *doc = (dom_html_document *) dom_node_get_owner(form);
+
+ assert(doc != NULL);
+
+ return _dom_html_collection_create(doc,
+ (dom_node_internal *) doc,
+ _dom_is_form_control, form, col);
+}
diff --git a/src/html/html_form_controls_collection.h b/src/html/html_form_controls_collection.h
new file mode 100644
index 0000000..2604c38
--- /dev/null
+++ b/src/html/html_form_controls_collection.h
@@ -0,0 +1,23 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2018 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ */
+
+#ifndef dom_internal_html_form_controls_collection_h_
+#define dom_internal_html_form_controls_collection_h_
+
+#include <dom/html/html_form_controls_collection.h>
+
+#include "html/html_collection.h"
+
+struct dom_html_form_element;
+
+/* Exposed so that the radio nodelist can use it as a sub-criterion */
+bool _dom_is_form_control(struct dom_node_internal *node, void *ctx);
+
+dom_exception _dom_html_form_controls_collection_create(struct dom_html_form_element *form,
+ dom_html_form_controls_collection **col);
+
+#endif
diff --git a/src/html/html_form_element.c b/src/html/html_form_element.c
index 1dd1992..b3ac05f 100644
--- a/src/html/html_form_element.c
+++ b/src/html/html_form_element.c
@@ -11,12 +11,8 @@
#include <dom/html/html_form_element.h>
#include "html/html_form_element.h"
-#include "html/html_input_element.h"
-#include "html/html_select_element.h"
-#include "html/html_text_area_element.h"
-#include "html/html_button_element.h"
-#include "html/html_collection.h"
+#include "html/html_form_controls_collection.h"
#include "html/html_document.h"
#include "core/node.h"
@@ -29,8 +25,6 @@ static struct dom_element_protected_vtable _protect_vtable = {
DOM_HTML_FORM_ELEMENT_PROTECT_VTABLE
};
-static bool _dom_is_form_control(struct dom_node_internal *node, void *ctx);
-
/**
* Create a dom_html_form_element object
*
@@ -71,6 +65,8 @@ dom_exception _dom_html_form_element_initialise(
err = _dom_html_element_initialise(params, &ele->base);
+ ele->elements = NULL;
+
return err;
}
@@ -81,6 +77,10 @@ dom_exception _dom_html_form_element_initialise(
*/
void _dom_html_form_element_finalise(struct dom_html_form_element *ele)
{
+ if (ele->elements != NULL) {
+ dom_html_form_controls_collection_unref(ele->elements);
+ ele->elements = NULL;
+ }
_dom_html_element_finalise(&ele->base);
}
@@ -167,15 +167,23 @@ dom_exception _dom_html_form_element_copy_internal(
* \return DOM_NO_ERR on success, appropriate dom_exception on failure.
*/
dom_exception dom_html_form_element_get_elements(dom_html_form_element *ele,
- struct dom_html_collection **col)
+ dom_html_form_controls_collection **col)
{
dom_exception err;
- dom_html_document *doc = (dom_html_document *) dom_node_get_owner(ele);
+
+ if (ele->elements != NULL) {
+ dom_html_form_controls_collection_ref(ele->elements);
+ *col = ele->elements;
+ return DOM_NO_ERR;
+ }
- assert(doc != NULL);
- err = _dom_html_collection_create(doc,
- (dom_node_internal *) doc,
- _dom_is_form_control, ele, col);
+ err = _dom_html_form_controls_collection_create(ele, col);
+
+ if (err == DOM_NO_ERR) {
+ dom_html_form_controls_collection_ref(*col);
+ ele->elements = *col;
+ }
+
return err;
}
@@ -190,20 +198,16 @@ dom_exception dom_html_form_element_get_length(dom_html_form_element *ele,
uint32_t *len)
{
dom_exception err;
- dom_html_document *doc = (dom_html_document *) dom_node_get_owner(ele);
- dom_html_collection *col;
+ dom_html_form_controls_collection *col;
- assert(doc != NULL);
- err = _dom_html_collection_create(doc,
- (dom_node_internal *) doc,
- _dom_is_form_control, ele, &col);
+ err = dom_html_form_element_get_elements(ele, &col);
+
if (err != DOM_NO_ERR)
return err;
-
- err = dom_html_collection_get_length(col, len);
+ err = dom_html_form_controls_collection_get_length(col, len);
- dom_html_collection_unref(col);
+ dom_html_form_controls_collection_unref(col);
return err;
}
@@ -293,36 +297,3 @@ dom_exception dom_html_form_element_reset(dom_html_form_element *ele)
doc->memoised[hds_reset], true,
true, &success);
}
-
-/*-----------------------------------------------------------------------*/
-/* Internal functions */
-
-/* Callback function to test whether certain node is a form control, see
- * src/html/html_collection.h for detail. */
-static bool _dom_is_form_control(struct dom_node_internal *node, void *ctx)
-{
- struct dom_html_document *doc =
- (struct dom_html_document *)(node->owner);
- struct dom_html_form_element *form = ctx;
-
-
- assert(node->type == DOM_ELEMENT_NODE);
-
- /* Form controls are INPUT TEXTAREA SELECT and BUTTON*/
- if (dom_string_caseless_isequal(node->name,
- doc->elements[DOM_HTML_ELEMENT_TYPE_INPUT]))
- return ((dom_html_input_element *)node)->form == form;
- if (dom_string_caseless_isequal(node->name,
- doc->elements[DOM_HTML_ELEMENT_TYPE_TEXTAREA]))
- return ((dom_html_text_area_element *)node)->form == form;
- if (dom_string_caseless_isequal(node->name,
- doc->elements[DOM_HTML_ELEMENT_TYPE_SELECT]))
- return ((dom_html_select_element *)node)->form == form;
- if (dom_string_caseless_isequal(node->name,
- doc->elements[DOM_HTML_ELEMENT_TYPE_BUTTON])) {
- return ((dom_html_button_element *)node)->form == form;
- }
-
- return false;
-}
-
diff --git a/src/html/html_form_element.h b/src/html/html_form_element.h
index 4987820..4a75379 100644
--- a/src/html/html_form_element.h
+++ b/src/html/html_form_element.h
@@ -12,11 +12,11 @@
#include "html/html_element.h"
-struct dom_html_collection;
-
struct dom_html_form_element {
struct dom_html_element base;
/**< The base class */
+ dom_html_form_controls_collection *elements;
+ /**< The elements collection (memoised) */
};
/* Create a dom_html_form_element object */
diff --git a/src/html/html_radio_nodelist.c b/src/html/html_radio_nodelist.c
new file mode 100644
index 0000000..52e25f1
--- /dev/null
+++ b/src/html/html_radio_nodelist.c
@@ -0,0 +1,419 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2018 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#include <dom/html/html_radio_nodelist.h>
+#include <dom/html/html_input_element.h>
+
+#include "html/html_radio_nodelist.h"
+#include "html/html_form_controls_collection.h"
+#include "html/html_document.h"
+#include "html/html_form_element.h"
+
+#include "core/node.h"
+#include "core/element.h"
+#include "core/string.h"
+
+/*-----------------------------------------------------------------------*/
+/* Internal functions */
+
+/* Callback function to test whether certain node is a form control, see
+ * src/html/html_collection.h for detail. */
+static bool _dom_is_specific_form_control(struct dom_node_internal *node, void *ctx)
+{
+ struct dom_html_document *doc =
+ (struct dom_html_document *)(node->owner);
+ struct dom_html_radio_nodelist *nodelist = ctx;
+ dom_string *str;
+ dom_exception exc;
+
+ if (_dom_is_form_control(node, nodelist->form)) {
+ /* It's the control we care about if id or name are equal
+ * to nodelist->name. We wouldn't be here if node wasn't
+ * an element node.
+ */
+ exc = _dom_element_get_id((struct dom_element *)node, &str);
+
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ if (str != NULL && dom_string_isequal(str, nodelist->name)) {
+ dom_string_unref(str);
+ return true;
+ }
+
+ if (str != NULL)
+ dom_string_unref(str);
+
+ exc = _dom_element_get_attribute((struct dom_element *)node,
+ doc->memoised[hds_name], &str);
+
+ if (str != NULL && dom_string_isequal(str, nodelist->name)) {
+ dom_string_unref(str);
+ return true;
+ }
+
+ if (str != NULL)
+ dom_string_unref(str);
+ }
+
+ return false;
+}
+
+/**
+ * Create a dom_html_radio_nodelist
+ *
+ * \param form The HTML form element for the radio nodelist
+ * \param name The element id/name for the radio nodelist
+ * \param nodelist The result radio nodelist object
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_html_radio_nodelist_create(struct dom_html_form_element *form,
+ dom_string *name,
+ struct dom_html_radio_nodelist **nodelist)
+{
+ dom_exception exc;
+ *nodelist = malloc(sizeof(struct dom_html_radio_nodelist));
+
+ if (*nodelist == NULL)
+ return DOM_NO_MEM_ERR;
+
+ exc = _dom_html_radio_nodelist_initialise(form, *nodelist, name);
+
+ if (exc != DOM_NO_ERR) {
+ /* This is safe because we only ever get an error before we
+ * ref anything which would need finalising
+ */
+ free(*nodelist);
+ *nodelist = NULL;
+ }
+
+ return exc;
+}
+
+/**
+ * Initialise a dom_html_radio_nodelist
+ *
+ * \param form The HTML form element for the radio nodelist
+ * \param nodelist The radio nodelist object to initialise
+ * \param name The element id/name for the radio nodelist
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception _dom_html_radio_nodelist_initialise(struct dom_html_form_element *form,
+ struct dom_html_radio_nodelist *nodelist,
+ dom_string *name)
+{
+ dom_exception exc;
+ dom_html_document *doc = (dom_html_document *) dom_node_get_owner(form);
+
+ assert(form != NULL);
+ assert(name != NULL);
+
+ assert(doc != NULL);
+
+ exc = _dom_html_collection_create(doc,
+ (dom_node_internal *) doc,
+ _dom_is_specific_form_control,
+ nodelist, &nodelist->col);
+
+ if (exc != DOM_NO_ERR)
+ return exc;
+
+ nodelist->form = form;
+ dom_node_ref(form);
+
+ nodelist->name = name;
+ dom_string_ref(name);
+
+ nodelist->refcnt = 1;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Finalise a dom_html_radio_nodelist object
+ *
+ * \param nodelist The dom_html_radio_nodelist object
+ */
+void _dom_html_radio_nodelist_finalise(struct dom_html_radio_nodelist *nodelist)
+{
+ assert(nodelist->refcnt == 0);
+ dom_node_unref(nodelist->form);
+ nodelist->form = NULL;
+ dom_string_unref(nodelist->name);
+ nodelist->name = NULL;
+ dom_html_collection_unref(nodelist->col);
+ nodelist->col = NULL;
+}
+
+/**
+ * Destroy a dom_html_radio_nodelist object
+ *
+ * \param nodelist The dom_html_radio_nodelist object
+ */
+void _dom_html_radio_nodelist_destroy(struct dom_html_radio_nodelist *nodelist)
+{
+ _dom_html_radio_nodelist_finalise(nodelist);
+ free(nodelist);
+}
+
+/*-----------------------------------------------------------------------*/
+/* Public API */
+
+/**
+ * Claim a reference on this radio nodelist
+ *
+ * \param nodelist The radio nodelist object
+ */
+void dom_html_radio_nodelist_ref(dom_html_radio_nodelist *nodelist)
+{
+ if (nodelist == NULL)
+ return;
+
+ nodelist->refcnt ++;
+}
+
+/**
+ * Relese a reference on this radio nodelist
+ *
+ * \param nodelist The radio nodelist object
+ */
+void dom_html_radio_nodelist_unref(dom_html_radio_nodelist *nodelist)
+{
+ if (nodelist == NULL)
+ return;
+
+ if (nodelist->refcnt > 0)
+ nodelist->refcnt --;
+
+ if (nodelist->refcnt == 0)
+ _dom_html_radio_nodelist_destroy(nodelist);
+}
+
+
+/**
+ * Retrieve the length of a node list
+ *
+ * \param nodelist List to retrieve length of
+ * \param len Pointer to location to receive length
+ * \return DOM_NO_ERR.
+ */
+dom_exception dom_html_radio_nodelist_get_length(dom_html_radio_nodelist *nodelist,
+ uint32_t *len)
+{
+ return dom_html_collection_get_length(nodelist->col, len);
+}
+
+/**
+ * Retrieve an item from a node list
+ *
+ * \param nodelist The list to retrieve the item from
+ * \param index The list index to retrieve
+ * \param node Pointer to location to receive item
+ * \return DOM_NO_ERR.
+ *
+ * ::index is a zero-based index into ::list.
+ * ::index lies in the range [0, length-1]
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_html_radio_nodelist_item(dom_html_radio_nodelist *nodelist,
+ uint32_t index, struct dom_node **node)
+{
+ return dom_html_collection_item(nodelist->col, index, node);
+}
+
+/**
+ * Retrieve the value of the radio nodelist per 2.7.2.2.
+ *
+ * \param nodelist The list to retrieve the value from
+ * \param value The value string to fill out
+ * \return DOM_NO_ERR
+ */
+dom_exception dom_html_radio_nodelist_get_value(dom_html_radio_nodelist *nodelist,
+ dom_string **value)
+{
+ dom_exception exc;
+ dom_node *node = NULL;
+ uint32_t count;
+ struct dom_html_document *doc =
+ (struct dom_html_document *)(((struct dom_node_internal *)nodelist->form)->owner);
+
+ assert(doc != NULL);
+
+ exc = dom_html_collection_get_length(nodelist->col, &count);
+
+ if (exc != DOM_NO_ERR)
+ return exc;
+
+ /* 1. Let element be the first element in tree order represented by the
+ * RadioNodeList object that is an input element whose type attribute
+ * is in the Radio Button state and whose checkedness is
+ * true. Otherwise, let it be NULL.
+ */
+
+ for (uint32_t idx = 0; idx < count; idx++) {
+ exc = dom_html_collection_item(nodelist->col, idx, &node);
+ if (exc != DOM_NO_ERR)
+ return exc;
+
+ assert(node->type == DOM_ELEMENT_NODE);
+
+ if (dom_string_caseless_isequal(((struct dom_node_internal *)node)->name,
+ doc->elements[DOM_HTML_ELEMENT_TYPE_INPUT])) {
+ bool checked = false;
+ dom_string *type;
+
+ exc = dom_element_get_attribute(node, doc->memoised[hds_type], &type);
+ if (exc != DOM_NO_ERR) {
+ dom_node_unref(node);
+ return exc;
+ }
+
+ if (dom_string_caseless_isequal(type, doc->memoised[hds_radio]) == false) {
+ dom_node_unref(node);
+ dom_string_unref(type);
+ continue;
+ }
+
+ dom_string_unref(type);
+
+ exc = dom_html_input_element_get_checked((dom_html_input_element *)node, &checked);
+
+ if (exc != DOM_NO_ERR) {
+ dom_node_unref(node);
+ return exc;
+ }
+ if (checked == true)
+ break;
+ }
+
+ dom_node_unref(node);
+ node = NULL;
+ }
+
+ /* 2. If element is null, return the empty string. */
+ if (node == NULL) {
+ *value = doc->base._memo_empty;
+ dom_string_ref(*value);
+ return DOM_NO_ERR;
+ }
+
+ exc = dom_html_input_element_get_value((dom_html_input_element *)node, value);
+
+ /* 3. If element is an element with no value attribute, return the
+ * string "on".
+ */
+ if (*value == NULL) {
+ *value = doc->memoised[hds_on];
+ dom_string_ref(*value);
+ return DOM_NO_ERR;
+ }
+
+ /* 4. Otherwise, return the value of element’s value attribute. */
+
+ dom_node_unref(node);
+
+ return DOM_NO_ERR;
+}
+
+dom_exception dom_html_radio_nodelist_set_value(dom_html_radio_nodelist *nodelist,
+ dom_string *value)
+{
+ dom_exception exc;
+ dom_node *node = NULL;
+ uint32_t count;
+ bool goal_is_on = false;
+ struct dom_html_document *doc =
+ (struct dom_html_document *)(((struct dom_node_internal *)nodelist->form)->owner);
+
+ assert(doc != NULL);
+
+ exc = dom_html_collection_get_length(nodelist->col, &count);
+
+ if (exc != DOM_NO_ERR)
+ return exc;
+
+ goal_is_on = dom_string_caseless_isequal(value, doc->memoised[hds_on]);
+
+ /* 1. If the new value is the string "on": let element be the first
+ * element in tree order represented by the RadioNodeList object that
+ * is an input element whose type attribute is in the Radio Button
+ * state and whose value content attribute is either absent, or present
+ * and equal to the new value, if any. If no such element exists, then
+ * instead let element be null.
+ *
+ * Otherwise: let element be the first element in tree order
+ * represented by the RadioNodeList object that is an input element
+ * whose type attribute is in the Radio Button state and whose value
+ * content attribute is present and equal to the new value, if any. If
+ * no such element exists, then instead let element be null.
+ */
+
+ for (uint32_t idx = 0; idx < count; idx++) {
+ exc = dom_html_collection_item(nodelist->col, idx, &node);
+ if (exc != DOM_NO_ERR)
+ return exc;
+
+ assert(node->type == DOM_ELEMENT_NODE);
+ if (dom_string_caseless_isequal(((struct dom_node_internal *)node)->name,
+ doc->elements[DOM_HTML_ELEMENT_TYPE_INPUT])) {
+ dom_string *type;
+ dom_string *test_value;
+
+ exc = dom_element_get_attribute(node, doc->memoised[hds_type], &type);
+ if (exc != DOM_NO_ERR) {
+ dom_node_unref(node);
+ return exc;
+ }
+
+ if (dom_string_caseless_isequal(type, doc->memoised[hds_radio]) == false) {
+ dom_node_unref(node);
+ dom_string_unref(type);
+ continue;
+ }
+
+ dom_string_unref(type);
+
+ exc = dom_html_input_element_get_value((dom_html_input_element *)node, &test_value);
+
+ if (test_value == NULL) {
+ if (goal_is_on) {
+ dom_string_unref(test_value);
+ break;
+ }
+ } else {
+ if (dom_string_caseless_isequal(test_value, value)) {
+ dom_string_unref(test_value);
+ break;
+ }
+ }
+
+ dom_string_unref(test_value);
+ }
+
+ dom_node_unref(node);
+ node = NULL;
+ }
+
+ exc = DOM_NO_ERR;
+
+ /* 2. If element is not null, then set its checkedness to true. */
+ if (node != NULL) {
+ exc = dom_html_input_element_set_checked((dom_html_input_element *)node, true);
+ }
+
+ dom_node_unref(node);
+
+ return exc;
+}
diff --git a/src/html/html_radio_nodelist.h b/src/html/html_radio_nodelist.h
new file mode 100644
index 0000000..ffb2b12
--- /dev/null
+++ b/src/html/html_radio_nodelist.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2018 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ */
+
+#ifndef dom_internal_html_radio_nodelist_h_
+#define dom_internal_html_radio_nodelist_h_
+
+#include <dom/html/html_collection.h>
+
+struct dom_html_form_element;
+
+struct dom_html_radio_nodelist {
+ uint32_t refcnt; /**< The reference count of the nodelist */
+ dom_string *name; /**< The name used for the nodelist */
+ struct dom_html_form_element *form; /**< The form on which we constructed */
+ dom_html_collection *col; /**< the underlying collection */
+};
+
+dom_exception _dom_html_radio_nodelist_create(struct dom_html_form_element *form,
+ dom_string *name,
+ struct dom_html_radio_nodelist **nodelist);
+
+dom_exception _dom_html_radio_nodelist_initialise(struct dom_html_form_element *form,
+ struct dom_html_radio_nodelist *nodelist,
+ dom_string *name);
+
+void _dom_html_radio_nodelist_finalise(struct dom_html_radio_nodelist *nodelist);
+
+void _dom_html_radio_nodelist_destroy(struct dom_html_radio_nodelist *nodelist);
+
+
+#endif