From e28c8c517ef1e89638de059c5f8da6cb8dab0adc Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 20 Jan 2018 10:22:55 +0000 Subject: Add HTMLFormControlsCollection and RadioNodeList These are a necessary step on the way to libdom being able to manage the content and behaviours of web forms. --- Makefile | 2 + include/dom/dom.h | 2 + include/dom/html/html_form_controls_collection.h | 38 ++ include/dom/html/html_form_element.h | 4 +- include/dom/html/html_radio_nodelist.h | 33 ++ src/html/Makefile | 3 +- src/html/html_document_strings.h | 3 + src/html/html_form_controls_collection.c | 69 ++++ src/html/html_form_controls_collection.h | 23 ++ src/html/html_form_element.c | 81 ++--- src/html/html_form_element.h | 4 +- src/html/html_radio_nodelist.c | 419 +++++++++++++++++++++++ src/html/html_radio_nodelist.h | 35 ++ 13 files changed, 656 insertions(+), 60 deletions(-) create mode 100644 include/dom/html/html_form_controls_collection.h create mode 100644 include/dom/html/html_radio_nodelist.h create mode 100644 src/html/html_form_controls_collection.c create mode 100644 src/html/html_form_controls_collection.h create mode 100644 src/html/html_radio_nodelist.c create mode 100644 src/html/html_radio_nodelist.h 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 +#include +#include #include #include #include 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 + */ + +#ifndef dom_html_form_controls_collection_h_ +#define dom_html_form_controls_collection_h_ + +#include +#include + +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 #include -struct dom_html_collection; +#include 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 + */ + +#ifndef dom_html_radio_nodelist_h_ +#define dom_html_radio_nodelist_h_ + +#include +#include + +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 + */ + +#include +#include + +#include + +#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 + */ + +#ifndef dom_internal_html_form_controls_collection_h_ +#define dom_internal_html_form_controls_collection_h_ + +#include + +#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 #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 + */ + +#include +#include + +#include + +#include +#include + +#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 + */ + +#ifndef dom_internal_html_radio_nodelist_h_ +#define dom_internal_html_radio_nodelist_h_ + +#include + +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 -- cgit v1.2.3