diff options
-rw-r--r-- | desktop/browser.c | 159 | ||||
-rw-r--r-- | desktop/browser.h | 4 | ||||
-rw-r--r-- | desktop/gui.h | 2 | ||||
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | render/box.c | 164 | ||||
-rw-r--r-- | render/box.h | 63 | ||||
-rw-r--r-- | render/form.c | 175 | ||||
-rw-r--r-- | render/form.h | 89 | ||||
-rw-r--r-- | riscos/gui.c | 7 | ||||
-rw-r--r-- | riscos/gui.h | 2 | ||||
-rw-r--r-- | riscos/htmlredraw.c | 8 |
11 files changed, 367 insertions, 308 deletions
diff --git a/desktop/browser.c b/desktop/browser.c index 1eb881f1c..67a4670dc 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -21,6 +21,7 @@ #include "netsurf/desktop/browser.h" #include "netsurf/render/box.h" #include "netsurf/render/font.h" +#include "netsurf/render/form.h" #include "netsurf/render/layout.h" #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" @@ -41,14 +42,13 @@ static void browser_window_callback(content_msg msg, struct content *c, void *p1, void *p2, const char *error); static void download_window_callback(content_msg msg, struct content *c, void *p1, void *p2, const char *error); -static void clear_radio_gadgets(struct browser_window* bw, struct box* box, struct gui_gadget* group); -static void gui_redraw_gadget2(struct browser_window* bw, struct box* box, struct gui_gadget* g, +static void clear_radio_gadgets(struct browser_window* bw, struct box* box, struct form_control* group); +static void gui_redraw_gadget2(struct browser_window* bw, struct box* box, struct form_control* g, unsigned long x, unsigned long y); -static void browser_window_gadget_select(struct browser_window* bw, struct gui_gadget* g, int item); +static void browser_window_gadget_select(struct browser_window* bw, struct form_control* g, int item); static int browser_window_gadget_click(struct browser_window* bw, unsigned long click_x, unsigned long click_y); -static void browser_form_submit(struct browser_window *bw, struct form *form); -static char* browser_form_construct_get(struct page_elements *elements, struct formsubmit* fs); -static void browser_form_get_append(char **s, int *length, char sep, char *name, char *value); +static void browser_form_submit(struct browser_window *bw, struct form *form, + struct form_control *submit_button); static void browser_window_textarea_click(struct browser_window* bw, unsigned long actual_x, unsigned long actual_y, long x, long y, @@ -370,8 +370,7 @@ void browser_window_callback(content_msg msg, struct content *c, break; case CONTENT_MSG_REFORMAT: - if (bw->current_content->status == CONTENT_STATUS_DONE) - browser_window_reformat(bw, 0); + browser_window_reformat(bw, 0); break; default: @@ -413,7 +412,7 @@ void download_window_callback(content_msg msg, struct content *c, } } -void clear_radio_gadgets(struct browser_window* bw, struct box* box, struct gui_gadget* group) +void clear_radio_gadgets(struct browser_window* bw, struct box* box, struct form_control* group) { struct box* c; if (box == NULL) @@ -440,7 +439,7 @@ void clear_radio_gadgets(struct browser_window* bw, struct box* box, struct gui_ clear_radio_gadgets(bw, c, group); } -void gui_redraw_gadget2(struct browser_window* bw, struct box* box, struct gui_gadget* g, +void gui_redraw_gadget2(struct browser_window* bw, struct box* box, struct form_control* g, unsigned long x, unsigned long y) { struct box* c; @@ -458,15 +457,15 @@ void gui_redraw_gadget2(struct browser_window* bw, struct box* box, struct gui_g gui_redraw_gadget2(bw, c, g, box->x + x, box->y + y); } -void gui_redraw_gadget(struct browser_window* bw, struct gui_gadget* g) +void gui_redraw_gadget(struct browser_window* bw, struct form_control* g) { assert(bw->current_content->type == CONTENT_HTML); gui_redraw_gadget2(bw, bw->current_content->data.html.layout->children, g, 0, 0); } -void browser_window_gadget_select(struct browser_window* bw, struct gui_gadget* g, int item) +void browser_window_gadget_select(struct browser_window* bw, struct form_control* g, int item) { - struct formoption* o; + struct form_option* o; int count; struct box *inline_box = g->box->children->children; int x, y; @@ -533,7 +532,7 @@ int browser_window_gadget_click(struct browser_window* bw, unsigned long click_x if (click_boxes[i].box->gadget) { - struct gui_gadget* g = click_boxes[i].box->gadget; + struct form_control* g = click_boxes[i].box->gadget; /* gadget clicked */ switch (g->type) @@ -551,7 +550,7 @@ int browser_window_gadget_click(struct browser_window* bw, unsigned long click_x gui_redraw_gadget(bw, g); break; case GADGET_SUBMIT: - browser_form_submit(bw, g->form); + browser_form_submit(bw, g->form, g); break; case GADGET_TEXTAREA: browser_window_textarea_click(bw, @@ -576,7 +575,7 @@ int browser_window_gadget_click(struct browser_window* bw, unsigned long click_x box_coords(click_boxes[i].box, &x, &y); g->data.image.mx = click_x - x; g->data.image.my = click_y - y; - browser_form_submit(bw, g->form); + browser_form_submit(bw, g->form, g); break; } @@ -1068,7 +1067,7 @@ void browser_window_input_callback(struct browser_window *bw, char key, void *p) char_offset--; } else if (key == 10 || key == 13) { /* Return/Enter hit */ - browser_form_submit(bw, form); + browser_form_submit(bw, form, 0); /*TODO: remove caret from new page */ } else if (key == 9) { /* Tab */ @@ -1570,31 +1569,28 @@ void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* } -void browser_form_submit(struct browser_window *bw, struct form *form) +void browser_form_submit(struct browser_window *bw, struct form *form, + struct form_control *submit_button) { - /*create submission request*/ - struct formsubmit* fs = (struct formsubmit*) xcalloc(1, sizeof(struct formsubmit)); - fs->form = form; - /*fs->items = g;*/ - LOG(("Submission request created")); + struct form_successful_control *success; - if (fs->form->method == method_GET) { + success = form_successful_controls(form, submit_button); + + if (form->method == method_GET) { /*GET request*/ /*GET basically munges the entire form data into one URL. */ - char *url = browser_form_construct_get(&bw->current_content->data.html.elements, - fs); - - LOG(("GET request")); - - /*send request*/ + char *data = form_url_encode(success); + char *url = xcalloc(1, strlen(form->action) + strlen(data) + 2); + sprintf(url, "%s?%s", form->action, data); + free(data); browser_window_open_location(bw, url); xfree(url); } else { /*POST request*/ - assert(fs->form->method == method_POST); + assert(form->method == method_POST); LOG(("POST request - not implemented yet")); @@ -1604,104 +1600,5 @@ void browser_form_submit(struct browser_window *bw, struct form *form) body.*/ } - xfree(fs); -} - - -char* browser_form_construct_get(struct page_elements *elements, struct formsubmit* fs) -{ - char *ret; - int i,j, length; - struct formoption* opt; - - ret = xstrdup(fs->form->action); - length = strlen(ret); - - j=0; - for (i=0;i<elements->numGadgets;i++){ - if(elements->gadgets[i]->form == fs->form){ - - if(elements->gadgets[i]->name != 0){ - char *value = 0; - - switch(elements->gadgets[i]->type){ - - case GADGET_HIDDEN: value = elements->gadgets[i]->data.hidden.value; - break; - case GADGET_TEXTBOX: value = elements->gadgets[i]->value; - break; - case GADGET_PASSWORD: value = elements->gadgets[i]->value; - break; - case GADGET_RADIO: if(elements->gadgets[i]->data.radio.selected == -1) - value = elements->gadgets[i]->data.radio.value; - break; - case GADGET_CHECKBOX: if(elements->gadgets[i]->data.checkbox.selected == 1) - value = elements->gadgets[i]->data.checkbox.value; - break; - case GADGET_SELECT: opt = elements->gadgets[i]->data.select.items; - while(opt != NULL){ - if(opt->selected == -1 || opt->selected == 1) { - browser_form_get_append(&ret, &length, j == 0 ? '?' : '&', - elements->gadgets[i]->name, opt->value); - j++; - } - opt = opt->next; - } - break; - case GADGET_TEXTAREA: /* TODO */ - break; - case GADGET_IMAGE: sprintf(elements->gadgets[i]->data.image.name, - "%s.x", - elements->gadgets[i]->data.image.n); - sprintf(elements->gadgets[i]->data.image.value, - "%d", - elements->gadgets[i]->data.image.mx); - browser_form_get_append(&ret, &length, - j == 0 ? '?' : '&', - elements->gadgets[i]->data.image.name, - elements->gadgets[i]->data.image.value); - sprintf(elements->gadgets[i]->data.image.name, - "%s.y", - elements->gadgets[i]->data.image.n); - sprintf(elements->gadgets[i]->data.image.value, - "%d", - elements->gadgets[i]->data.image.my); - browser_form_get_append(&ret, &length, - j == 0 ? '?' : '&', - elements->gadgets[i]->data.image.name, - elements->gadgets[i]->data.image.value); - j++; - break; - default: break; - } - - if (value != 0) { - browser_form_get_append(&ret, &length, j == 0 ? '?' : '&', - elements->gadgets[i]->name, value); - j++; - } - } - - } - } - return ret; -} - - -void browser_form_get_append(char **s, int *length, char sep, char *name, char *value) -{ - unsigned int length1; - - name = curl_escape(name, 0); - value = curl_escape(value, 0); - length1 = 2 + strlen(name) + strlen(value); - - LOG(("append %c%s=%s, length1 %i, *s %p", sep, name, value, length1, *s)); - *s = xrealloc(*s, *length + length1 + 1); - - sprintf(*s + *length, "%c%s=%s", sep, name, value); - *length += length1; - - curl_free(name); - curl_free(value); + form_free_successful(success); } diff --git a/desktop/browser.h b/desktop/browser.h index 8bd4f437b..38dc3628b 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -80,7 +80,7 @@ struct browser_action action_buttons buttons; } mouse; struct { - struct gui_gadget* g; + struct form_control* g; int item; } gadget_select; } data; @@ -114,7 +114,7 @@ int box_position_gt(struct box_position* x, struct box_position* y); int box_position_eq(struct box_position* x, struct box_position* y); int box_position_distance(struct box_position* x, struct box_position* y); -void gui_redraw_gadget(struct browser_window* bw, struct gui_gadget* g); +void gui_redraw_gadget(struct browser_window* bw, struct form_control* g); void browser_window_stop_throbber(struct browser_window* bw); void browser_window_reformat(struct browser_window* bw, int scroll_to_top); diff --git a/desktop/gui.h b/desktop/gui.h index 619ded567..bb52979c2 100644 --- a/desktop/gui.h +++ b/desktop/gui.h @@ -58,7 +58,7 @@ gui_safety gui_window_set_redraw_safety(gui_window* g, gui_safety s); void gui_window_start_throbber(gui_window* g); void gui_window_stop_throbber(gui_window* g); -void gui_gadget_combo(struct browser_window* bw, struct gui_gadget* g, unsigned long mx, unsigned long my); +void gui_gadget_combo(struct browser_window* bw, struct form_control* g, unsigned long mx, unsigned long my); void gui_window_place_caret(gui_window *g, int x, int y, int height); @@ -8,7 +8,7 @@ CC = riscos-gcc CC_DEBUG = gcc OBJECTS_COMMON = cache.o content.o fetch.o fetchcache.o other.o \ css.o css_enum.o parser.o ruleset.o scanner.o \ - box.o html.o layout.o textplain.o \ + box.o form.o html.o layout.o textplain.o \ messages.o utils.o OBJECTS = $(OBJECTS_COMMON) \ browser.o netsurf.o \ diff --git a/render/box.c b/render/box.c index 77fc99f00..3ad80ffad 100644 --- a/render/box.c +++ b/render/box.c @@ -18,6 +18,7 @@ #include "netsurf/css/css.h" #include "netsurf/render/box.h" #include "netsurf/render/font.h" +#include "netsurf/render/form.h" #include "netsurf/render/html.h" #ifdef riscos #include "netsurf/desktop/gui.h" @@ -70,7 +71,7 @@ static struct box *box_input_text(xmlNode *n, struct status *status, struct css_style *style, bool password); static struct result box_button(xmlNode *n, struct status *status, struct css_style *style); -static void add_option(xmlNode* n, struct gui_gadget* current_select, char *text); +static void add_option(xmlNode* n, struct form_control* current_select, char *text); static void box_normalise_block(struct box *block); static void box_normalise_table(struct box *table); void box_normalise_table_row_group(struct box *row_group, @@ -78,7 +79,7 @@ void box_normalise_table_row_group(struct box *row_group, void box_normalise_table_row(struct box *row, unsigned int **row_span, unsigned int *table_columns); static void box_normalise_inline_container(struct box *cont); -static void gadget_free(struct gui_gadget* g); +static void gadget_free(struct form_control* g); static void box_free_box(struct box *box); static struct result box_object(xmlNode *n, struct status *status, struct css_style *style); @@ -88,9 +89,8 @@ static struct result box_applet(xmlNode *n, struct status *status, struct css_style *style); static struct result box_iframe(xmlNode *n, struct status *status, struct css_style *style); -static struct form* create_form(xmlNode* n); static void add_form_element(struct page_elements* pe, struct form* f); -static void add_gadget_element(struct page_elements* pe, struct gui_gadget* g); +static void add_gadget_element(struct page_elements* pe, struct form_control* g); static bool plugin_decode(struct content* content, char* url, struct box* box, struct object_params* po); @@ -370,7 +370,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content, } box = box_create(parent_style, status.href, title); - box->text = text; + box->text = text; box->style_clone = 1; box->length = strlen(text); if (text[box->length - 1] == ' ') { @@ -653,7 +653,7 @@ struct css_style * box_get_style(struct content ** stylesheet, xmlFree(s); } } - + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) { struct css_style * astyle = xcalloc(1, sizeof(struct css_style)); memcpy(astyle, &css_empty_style, sizeof(struct css_style)); @@ -737,9 +737,27 @@ struct result box_image(xmlNode *n, struct status *status, struct result box_form(xmlNode *n, struct status *status, struct css_style *style) { + char* s; struct box *box; + struct form *form; + box = box_create(style, status->href, status->title); - status->current_form = create_form(n); + + status->current_form = form = xcalloc(1, sizeof(*form)); + + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) { + form->action = s; + } + + form->method = method_GET; + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "method"))) { + if (stricmp(s, "post") == 0) + form->method = method_POST; + xmlFree(s); + } + + form->controls = form->last_control = 0; + add_form_element(status->elements, status->current_form); return (struct result) {box, 1}; } @@ -752,10 +770,10 @@ struct result box_textarea(xmlNode *n, struct status *status, char* s; box = box_create(style, NULL, 0); - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->box = box; box->gadget->type = GADGET_TEXTAREA; - box->gadget->form = status->current_form; + form_add_control(status->current_form, box->gadget); style->display = CSS_DISPLAY_INLINE_BLOCK; /* split the content at newlines and make an inline container with an @@ -800,12 +818,12 @@ struct result box_select(xmlNode *n, struct status *status, struct box *box; struct box *inline_container; struct box *inline_box; - struct gui_gadget *gadget = xcalloc(1, sizeof(struct gui_gadget)); + struct form_control *gadget = xcalloc(1, sizeof(struct form_control)); char* s; xmlNode *c, *c2; gadget->type = GADGET_SELECT; - gadget->form = status->current_form; + form_add_control(status->current_form, gadget); gadget->data.select.multiple = false; if ((s = (char *) xmlGetProp(n, (const xmlChar *) "multiple"))) { @@ -882,9 +900,9 @@ struct result box_select(xmlNode *n, struct status *status, return (struct result) {box, 0}; } -void add_option(xmlNode* n, struct gui_gadget* current_select, char *text) +void add_option(xmlNode* n, struct form_control* current_select, char *text) { - struct formoption *option = xcalloc(1, sizeof(struct formoption)); + struct form_option *option = xcalloc(1, sizeof(struct form_option)); char *s, *c; assert(current_select != 0); @@ -922,7 +940,7 @@ struct result box_input(xmlNode *n, struct status *status, struct css_style *style) { struct box* box = 0; - struct gui_gadget *gadget = 0; + struct form_control *gadget = 0; char *s, *type, *url; type = (char *) xmlGetProp(n, (const xmlChar *) "type"); @@ -943,16 +961,16 @@ struct result box_input(xmlNode *n, struct status *status, else if (stricmp(type, "hidden") == 0) { /* no box for hidden inputs */ - gadget = xcalloc(1, sizeof(struct gui_gadget)); + gadget = xcalloc(1, sizeof(struct form_control)); gadget->type = GADGET_HIDDEN; if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) - gadget->data.hidden.value = s; + gadget->value = s; } else if (stricmp(type, "checkbox") == 0 || stricmp(type, "radio") == 0) { box = box_create(style, NULL, 0); - box->gadget = gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = gadget = xcalloc(1, sizeof(struct form_control)); gadget->box = box; if (type[0] == 'c' || type[0] == 'C') gadget->type = GADGET_CHECKBOX; @@ -967,12 +985,8 @@ struct result box_input(xmlNode *n, struct status *status, xmlFree(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { - if (gadget->type == GADGET_CHECKBOX) - gadget->data.checkbox.value = s; - else - gadget->data.radio.value = s; - } + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) + gadget->value = s; } else if (stricmp(type, "submit") == 0 || stricmp(type, "reset") == 0) { @@ -998,33 +1012,21 @@ struct result box_input(xmlNode *n, struct status *status, else if (stricmp(type, "image") == 0) { box = box_create(style, NULL, 0); - box->gadget = gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = gadget = xcalloc(1, sizeof(struct form_control)); gadget->box = box; gadget->type = GADGET_IMAGE; - if ((s = (char *) xmlGetProp(n, (const xmlChar*) "name"))) { - gadget->data.image.n = s; - } - if ((s = (char *) xmlGetProp(n, (const xmlChar*) "width"))) { - gadget->data.image.width = (atoi(s)); - } - if ((s = (char *) xmlGetProp(n, (const xmlChar*) "height"))) { - gadget->data.image.height = (atoi(s)); - } if ((s = (char *) xmlGetProp(n, (const xmlChar*) "src"))) { - url = url_join(strdup(s), status->content->url); + url = url_join(s, status->content->url); html_fetch_object(status->content, url, box); + xmlFree(s); } - gadget->data.image.name = - xcalloc(strlen(gadget->data.image.n) + 5, sizeof(char)); - gadget->data.image.value = - xcalloc(strlen(gadget->data.image.n) + 20, sizeof(char)); } if (type != 0) xmlFree(type); if (gadget != 0) { - gadget->form = status->current_form; + form_add_control(status->current_form, gadget); gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name"); add_gadget_element(status->elements, gadget); } @@ -1041,7 +1043,7 @@ struct box *box_input_text(xmlNode *n, struct status *status, struct box *inline_container, *inline_box; style->display = CSS_DISPLAY_INLINE_BLOCK; - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->box = box; box->gadget->maxlength = 100; @@ -1090,10 +1092,10 @@ struct result box_button(xmlNode *n, struct status *status, style->display = CSS_DISPLAY_INLINE_BLOCK; if (!type || strcasecmp(type, "submit") == 0) { - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->type = GADGET_SUBMIT; } else if (strcasecmp(type, "reset") == 0) { - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->type = GADGET_RESET; } else { /* type="button" or unknown: just render the contents */ @@ -1104,7 +1106,7 @@ struct result box_button(xmlNode *n, struct status *status, if (type) xmlFree(type); - box->gadget->form = status->current_form; + form_add_control(status->current_form, box->gadget); box->gadget->box = box; box->gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name"); box->gadget->value = (char *) xmlGetProp(n, (const xmlChar *) "value"); @@ -1561,50 +1563,27 @@ void box_normalise_inline_container(struct box *cont) } -void gadget_free(struct gui_gadget* g) +void gadget_free(struct form_control* g) { - struct formoption *o, *o1; + struct form_option *o, *o1; if (g->name != 0) xmlFree(g->name); free(g->value); free(g->initial_value); - switch (g->type) - { - case GADGET_HIDDEN: - if (g->data.hidden.value != 0) - xmlFree(g->data.hidden.value); - break; - case GADGET_RADIO: - if (g->data.checkbox.value != 0) - xmlFree(g->data.radio.value); - break; - case GADGET_CHECKBOX: - if (g->data.checkbox.value != 0) - xmlFree(g->data.checkbox.value); - break; - case GADGET_IMAGE: - if (g->data.image.n != 0) - xmlFree(g->data.image.n); - if (g->data.image.name != 0) - xfree(g->data.image.name); - if (g->data.image.value != 0) - xfree(g->data.image.value); - break; - case GADGET_SELECT: - o = g->data.select.items; - while (o != NULL) - { - if (o->text != 0) - xmlFree(o->text); - if (o->value != 0) - xmlFree(o->value); - o1 = o->next; - xfree(o); - o = o1; - } - break; + if (g->type == GADGET_SELECT) { + o = g->data.select.items; + while (o != NULL) + { + if (o->text != 0) + xmlFree(o->text); + if (o->value != 0) + xmlFree(o->value); + o1 = o->next; + xfree(o); + o = o1; + } } } @@ -1649,27 +1628,6 @@ void box_free_box(struct box *box) * form helper functions */ -struct form* create_form(xmlNode* n) -{ - struct form* form; - char* s; - - form = xcalloc(1, sizeof(*form)); - - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) { - form->action = s; - } - - form->method = method_GET; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "method"))) { - if (stricmp(s, "post") == 0) - form->method = method_POST; - xmlFree(s); - } - - return form; -} - void add_form_element(struct page_elements* pe, struct form* f) { pe->forms = xrealloc(pe->forms, (pe->numForms + 1) * sizeof(struct form*)); @@ -1677,9 +1635,9 @@ void add_form_element(struct page_elements* pe, struct form* f) pe->numForms++; } -void add_gadget_element(struct page_elements* pe, struct gui_gadget* g) +void add_gadget_element(struct page_elements* pe, struct form_control* g) { - pe->gadgets = xrealloc(pe->gadgets, (pe->numGadgets + 1) * sizeof(struct gui_gadget*)); + pe->gadgets = xrealloc(pe->gadgets, (pe->numGadgets + 1) * sizeof(struct form_control*)); pe->gadgets[pe->numGadgets] = g; pe->numGadgets++; } diff --git a/render/box.h b/render/box.h index 76c9500c9..2c76f3ffd 100644 --- a/render/box.h +++ b/render/box.h @@ -33,59 +33,8 @@ struct column { unsigned long min, max, width; }; -struct formoption { - bool selected; - bool initial_selected; - char* value; - char* text; - struct formoption* next; -}; - struct box; -struct gui_gadget { - enum { GADGET_HIDDEN = 0, GADGET_TEXTBOX, GADGET_RADIO, GADGET_CHECKBOX, - GADGET_SELECT, GADGET_TEXTAREA, - GADGET_IMAGE, GADGET_PASSWORD, GADGET_SUBMIT, GADGET_RESET } type; - char *name; - char *value; - char *initial_value; - struct form *form; - struct box *box; - struct box *caret_inline_container; - struct box *caret_text_box; - int caret_char_offset; - unsigned int maxlength; - union { - struct { - char* value; - } hidden; - struct { - char* name; - char* value; - char* n; - int width, height; - int mx, my; - } image; - struct { - int num_items; - struct formoption *items, *last_item; - bool multiple; - int num_selected; - /** Currently selected item, if num_selected == 1. */ - struct formoption *current; - } select; - struct { - int selected; - char* value; - } checkbox; - struct { - int selected; - char* value; - } radio; - } data; -}; - /* parameters for <object> and related elements */ struct object_params { char* data; @@ -137,28 +86,22 @@ struct box { struct box * next_float; struct column *col; struct font_data *font; - struct gui_gadget* gadget; + struct form_control* gadget; struct content* object; /* usually an image */ struct object_params *object_params; void* object_state; /* state of any object */ }; -struct form -{ - char* action; /* url */ - enum {method_GET, method_POST} method; -}; - struct formsubmit { struct form* form; - struct gui_gadget* items; + struct form_control* items; }; struct page_elements { struct form** forms; - struct gui_gadget** gadgets; + struct form_control** gadgets; struct img** images; int numForms; int numGadgets; diff --git a/render/form.c b/render/form.c new file mode 100644 index 000000000..f4ed0a9f8 --- /dev/null +++ b/render/form.c @@ -0,0 +1,175 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 James Bursa <bursa@users.sourceforge.net> + * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net> + */ + +/** \file + * Form handling functions (implementation). + */ + +#include <assert.h> +#include <string.h> +#include "curl/curl.h" +#include "netsurf/render/form.h" +#include "netsurf/utils/utils.h" + + +/** + * Add a control to the list of controls in a form. + */ + +void form_add_control(struct form *form, struct form_control *control) +{ + control->form = form; + if (form->controls) { + assert(form->last_control); + form->last_control->next = control; + control->next = 0; + form->last_control = control; + } else { + form->controls = form->last_control = control; + } +} + + +/** + * Identify 'successful' controls. + * + * See HTML 4.01 section 17.13.2. + */ + +struct form_successful_control *form_successful_controls(struct form *form, + struct form_control *submit_button) +{ + struct form_control *control; + struct form_option *option; + struct form_successful_control sentinel, *last_success; + last_success = &sentinel; + + for (control = form->controls; control; control = control->next) { + struct form_successful_control *success_new; + + /* ignore disabled controls */ + if (control->disabled) + continue; + + /* ignore controls with no name */ + if (!control->name) + continue; + + /* only the activated submit button is successful */ + if (control->type == GADGET_SUBMIT && control != submit_button) + continue; + + /* ignore checkboxes and radio buttons which aren't selected */ + if (control->type == GADGET_CHECKBOX && !control->data.checkbox.selected) + continue; + if (control->type == GADGET_RADIO && !control->data.radio.selected) + continue; + + /* select */ + if (control->type == GADGET_SELECT) { + for (option = control->data.select.items; option; + option = option->next) { + if (option->selected && option->value) { + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xstrdup(control->name); + success_new->value = xstrdup(option->value); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + } + } + continue; + } + + /* textarea */ + if (control->type == GADGET_TEXTAREA) { + /* TODO */ + continue; + } + + /* image */ + if (control->type == GADGET_IMAGE) { + int len = strlen(control->name) + 3; + /* x */ + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xcalloc(1, len); + sprintf(success_new->name, "%s.x", control->name); + success_new->value = xcalloc(1, 20); + sprintf(success_new->value, "%i", control->data.image.mx); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + /* y */ + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xcalloc(1, len); + sprintf(success_new->name, "%s.y", control->name); + success_new->value = xcalloc(1, 20); + sprintf(success_new->value, "%i", control->data.image.my); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + } + + /* ignore reset */ + if (control->type == GADGET_RESET) + continue; + + /* all others added if they have a value */ + if (control->value) { + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xstrdup(control->name); + success_new->value = xstrdup(control->value); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + } + } + + return sentinel.next; +} + + +/** + * Encode controls using application/x-www-form-urlencoded. + */ + +char *form_url_encode(struct form_successful_control *control) +{ + char *s = xcalloc(1, 0); + int len = 0, len1; + + for (; control; control = control->next) { + char *name = curl_escape(control->name, 0); + char *value = curl_escape(control->value, 0); + len1 = len + strlen(name) + strlen(value) + 2; + s = xrealloc(s, len1 + 1); + sprintf(s + len, "%s=%s&", name, value); + len = len1; + curl_free(name); + curl_free(value); + } + if (len) + s[len - 1] = 0; + return s; +} + + +/** + * Free a linked list of form_successful_control. + */ + +void form_free_successful(struct form_successful_control *control) +{ + struct form_successful_control *next; + for (; control; control = next) { + next = control->next; + free(control->name); + free(control->value); + free(control); + } +} diff --git a/render/form.h b/render/form.h new file mode 100644 index 000000000..b81abf01a --- /dev/null +++ b/render/form.h @@ -0,0 +1,89 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net> + * Copyright 2003 James Bursa <bursa@users.sourceforge.net> + */ + +/** \file + * Form handling functions (interface). + */ + +#ifndef _NETSURF_RENDER_FORM_H_ +#define _NETSURF_RENDER_FORM_H_ + +#include <stdbool.h> +#include "netsurf/render/box.h" + +struct form_control; +struct form_option; + +/** HTML form. */ +struct form { + char *action; /* url */ + enum {method_GET, method_POST} method; + struct form_control *controls; /**< Linked list of controls. */ + struct form_control *last_control; /**< Last control in list. */ +}; + +/** Form control. */ +struct form_control { + enum { GADGET_HIDDEN, GADGET_TEXTBOX, GADGET_RADIO, GADGET_CHECKBOX, + GADGET_SELECT, GADGET_TEXTAREA, GADGET_IMAGE, + GADGET_PASSWORD, GADGET_SUBMIT, GADGET_RESET } type; + char *name; + char *value; + char *initial_value; + bool disabled; + struct form *form; + struct box *box; + struct box *caret_inline_container; + struct box *caret_text_box; + int caret_char_offset; + unsigned int maxlength; + union { + struct { + int mx, my; + } image; + struct { + int num_items; + struct form_option *items, *last_item; + bool multiple; + int num_selected; + /** Currently selected item, if num_selected == 1. */ + struct form_option *current; + } select; + struct { + int selected; + } checkbox; + struct { + int selected; + } radio; + } data; + struct form_control *next; /**< Next control in this form. */ +}; + +/** Option in a select. */ +struct form_option { + bool selected; + bool initial_selected; + char* value; + char* text; + struct form_option* next; +}; + +/** Successful control, as defined by HTML 4.01 17.13. */ +struct form_successful_control { + char *name; /**< Control name. */ + char *value; /**< Current value. */ + struct form_successful_control *next; /**< Next in linked list. */ +}; + +void form_add_control(struct form *form, struct form_control *control); +struct form_successful_control *form_successful_controls(struct form *form, + struct form_control *submit_button); +char *form_url_encode(struct form_successful_control *control); +void form_free_successful(struct form_successful_control *control); + +#endif diff --git a/riscos/gui.c b/riscos/gui.c index ca21c4e83..328d40691 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -25,6 +25,7 @@ #include "netsurf/desktop/netsurf.h" #include "netsurf/desktop/options.h" #include "netsurf/render/font.h" +#include "netsurf/render/form.h" #include "netsurf/render/html.h" #include "netsurf/riscos/about.h" #include "netsurf/riscos/gui.h" @@ -71,7 +72,7 @@ int ro_save_data(void *data, unsigned long length, char *file_name, bits file_ty wimp_menu* combo_menu; -struct gui_gadget* current_gadget; +struct form_control* current_gadget; int TOOLBAR_HEIGHT = 128; @@ -1282,10 +1283,10 @@ void gui_window_stop_throbber(gui_window* g) wimp_set_icon_state(g->data.browser.toolbar, ro_theme_icon(current_theme, THEME_TOOLBAR, "TOOLBAR_THROBBER"), 0, 0); } -void gui_gadget_combo(struct browser_window* bw, struct gui_gadget* g, unsigned long mx, unsigned long my) +void gui_gadget_combo(struct browser_window* bw, struct form_control* g, unsigned long mx, unsigned long my) { int count = 0; - struct formoption* o; + struct form_option* o; wimp_pointer pointer; if (combo_menu != NULL) diff --git a/riscos/gui.h b/riscos/gui.h index 3ad54ed0a..a88ff0476 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -22,7 +22,7 @@ extern wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br, extern wimp_menu *current_menu, *iconbar_menu, *browser_menu, *combo_menu, *theme_menu; extern int current_menu_x, current_menu_y, iconbar_menu_height; -extern struct gui_gadget *current_gadget; +extern struct form_control *current_gadget; extern const char *HOME_URL; extern gui_window *window_list; diff --git a/riscos/htmlredraw.c b/riscos/htmlredraw.c index 83e7b4009..d60d97a31 100644 --- a/riscos/htmlredraw.c +++ b/riscos/htmlredraw.c @@ -13,6 +13,7 @@ #include "oslib/font.h" #include "netsurf/css/css.h" #include "netsurf/content/content.h" +#include "netsurf/render/form.h" #include "netsurf/render/html.h" #include "netsurf/riscos/gui.h" #include "netsurf/utils/log.h" @@ -56,14 +57,9 @@ void html_redraw(struct content *c, long x, long y, /* validation strings can't be const */ -static char validation_textarea[] = "R7;L"; -static char validation_textbox[] = ""; -static char validation_password[] = "D*"; static char validation_select[] = "R2"; static char validation_checkbox_selected[] = "Sopton"; static char validation_checkbox_unselected[] = "Soptoff"; -static char validation_radio_selected[] = "Sradioon"; -static char validation_radio_unselected[] = "Sradiooff"; static char select_text_multiple[] = "<Multiple>"; /* TODO: read from messages */ static char select_text_none[] = "<None>"; @@ -79,7 +75,7 @@ void html_redraw_box(struct content *content, struct box * box, { struct box *c; char *select_text; - struct formoption *opt; + struct form_option *opt; int width, height, x0, y0, x1, y1; x += box->x * 2; |