changeset 305:43ba970f42cf

- Allowed form inputs outside FORM (it's in the standard).
author jcid
date Wed, 06 Aug 2008 14:58:39 +0200
parents 55b118a3b20d
children 7a76f872ce73
files ChangeLog src/form.cc src/form.hh src/html.cc src/html_common.hh
diffstat 5 files changed, 107 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Jul 12 19:29:56 2008 +0200
+++ b/ChangeLog	Wed Aug 06 14:58:39 2008 +0200
@@ -108,6 +108,7 @@
  - Moved charset decoding into cache.
  - Implemented OBJECT as link (similar to FRAME).
  - Enabled the file dpi to look inside gzipped files.
+ - Allowed form inputs outside FORM (it's in the standard).
    Patches: place (AKA corvid)
 +- Fixed a problem with locally-installed dpis.
  - Added code for optional image loading (nice interface) very advanced!
--- a/src/form.cc	Sat Jul 12 19:29:56 2008 +0200
+++ b/src/form.cc	Wed Aug 06 14:58:39 2008 +0200
@@ -37,7 +37,6 @@
  */
 
 class DilloHtmlReceiver;
-class DilloHtmlInput;
 class DilloHtmlSelect;
 class DilloHtmlOption;
 
@@ -120,15 +119,10 @@
                   DilloHtmlMethod method, const DilloUrl *action,
                   DilloHtmlEnc enc, const char *charset);
    ~DilloHtmlForm ();
-   DilloHtmlInput *getCurrentInput ();
    DilloHtmlInput *getInput (dw::core::ui::Resource *resource);
    DilloHtmlInput *getRadioInput (const char *name);
    void reset ();
-   void addInput(DilloHtmlInputType type,
-                 dw::core::ui::Embed *embed,
-                 const char *name,
-                 const char *init_str,
-                 bool init_val);
+   void addInput(DilloHtmlInput *input, DilloHtmlInputType type);
 };
 
 class DilloHtmlReceiver:
@@ -221,11 +215,72 @@
    delete form;
 }
 
+void a_Html_input_delete (DilloHtmlInput *input)
+{
+   delete input;
+}
+
 /*
  * Form parsing functions 
  */
 
 /*
+ * Add an HTML control
+ */
+static void Html_add_input(DilloHtml *html, DilloHtmlInputType type,
+                           dw::core::ui::Embed *embed, const char *name,
+                           const char *init_str, bool init_val)
+{
+   _MSG("name=[%s] init_str=[%s] init_val=[%d]\n", name, init_str, init_val);
+   DilloHtmlInput *input = new DilloHtmlInput(type, embed, name, init_str,
+                                              init_val);
+   if (html->InFlags & IN_FORM) {
+      html->getCurrentForm()->addInput(input, type);
+   } else {
+      int ni = html->inputs_outside_form->size();
+      html->inputs_outside_form->increase();
+      html->inputs_outside_form->set(ni, input);
+   }
+}
+
+/*
+ * Find radio input by name
+ */
+static DilloHtmlInput *Html_get_radio_input(DilloHtml *html, const char *name)
+{
+   lout::misc::SimpleVector<DilloHtmlInput*>* inputs;
+
+   if (html->InFlags & IN_FORM)
+      inputs = html->getCurrentForm()->inputs;
+   else
+      inputs = html->inputs_outside_form;
+
+   for (int idx = 0; idx < inputs->size(); idx++) {
+      DilloHtmlInput *input = inputs->get(idx);
+      if (input->type == DILLO_HTML_INPUT_RADIO &&
+          input->name && !dStrcasecmp(input->name, name))
+         return input;
+   }
+   return NULL;
+}
+
+/*
+ * Get the current input.
+ * Note that this _assumes_ that there _is_ a current input.
+ */
+static DilloHtmlInput *Html_get_current_input(DilloHtml *html)
+{
+   lout::misc::SimpleVector<DilloHtmlInput*>* inputs;
+
+   if (html->InFlags & IN_FORM)
+      inputs = html->getCurrentForm()->inputs;
+   else
+      inputs = html->inputs_outside_form;
+
+   return inputs->get (inputs->size() - 1);
+}
+
+/*
  * Handle <FORM> tag
  */
 void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize)
@@ -338,17 +393,12 @@
  */
 void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
 {
-   DilloHtmlForm *form;
    DilloHtmlInputType inp_type;
    dw::core::ui::Embed *embed = NULL;
    char *value, *name, *type, *init_str;
    const char *attrbuf, *label;
    bool init_val = false;
   
-   if (!(html->InFlags & IN_FORM)) {
-      BUG_MSG("<input> element outside <form>\n");
-      return;
-   }
    if (html->InFlags & IN_SELECT) {
       BUG_MSG("<input> element inside <select>\n");
       return;
@@ -358,8 +408,6 @@
       return;
    }
   
-   form = html->getCurrentForm ();
-  
    /* Get 'value', 'name' and 'type' */
    value = a_Html_get_attr_wdef(html, tag, tagsize, "value", NULL);
    name = a_Html_get_attr_wdef(html, tag, tagsize, "name", NULL);
@@ -383,7 +431,7 @@
    } else if (!dStrcasecmp(type, "radio")) {
       inp_type = DILLO_HTML_INPUT_RADIO;
       dw::core::ui::RadioButtonResource *rb_r = NULL;
-      DilloHtmlInput *input = form->getRadioInput(name);
+      DilloHtmlInput *input = Html_get_radio_input(html, name);
       if (input)
          rb_r =
             (dw::core::ui::RadioButtonResource*)
@@ -432,15 +480,22 @@
          init_str = value;
       }
    } else if (!dStrcasecmp(type, "file")) {
-      if (form->method != DILLO_HTML_METHOD_POST) {
-         BUG_MSG("Forms with file input MUST use HTTP POST method\n");
-         MSG("File input ignored in form not using HTTP POST method\n");
-      } else if (form->enc != DILLO_HTML_ENC_MULTIPART) {
-         BUG_MSG("Forms with file input MUST use multipart/form-data"
-                 " encoding\n");
-         MSG("File input ignored in form not using multipart/form-data"
-             " encoding\n");
-      } else {
+      bool valid = true;
+      if (html->InFlags & IN_FORM) {
+         DilloHtmlForm *form = html->getCurrentForm();
+         if (form->method != DILLO_HTML_METHOD_POST) {
+            valid = false;
+            BUG_MSG("Forms with file input MUST use HTTP POST method\n");
+            MSG("File input ignored in form not using HTTP POST method\n");
+         } else if (form->enc != DILLO_HTML_ENC_MULTIPART) {
+            valid = false;
+            BUG_MSG("Forms with file input MUST use multipart/form-data"
+                    " encoding\n");
+            MSG("File input ignored in form not using multipart/form-data"
+                " encoding\n");
+         }
+      }
+      if (valid) {
          inp_type = DILLO_HTML_INPUT_FILE;
          init_str = dStrdup("File selector");
          dw::core::ui::LabelButtonResource *lbr =
@@ -470,7 +525,7 @@
    }
 
    if (inp_type != DILLO_HTML_INPUT_UNKNOWN) {
-      form->addInput(inp_type, embed, name,
+      Html_add_input(html, inp_type, embed, name,
                      (init_str) ? init_str : "", init_val);
    }
   
@@ -515,7 +570,6 @@
  */
 void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize)
 {
-   DilloHtmlForm *form;
    DilloUrl *action;
    dw::core::ui::Embed *embed;
    const char *attrbuf;
@@ -532,8 +586,7 @@
   
    html->formNew(DILLO_HTML_METHOD_GET, action, DILLO_HTML_ENC_URLENCODING,
                  html->charset);
-  
-   form = html->getCurrentForm ();
+   html->InFlags |= IN_FORM;
   
    DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
   
@@ -543,7 +596,7 @@
    dw::core::ui::EntryResource *entryResource =
       HT2LT(html)->getResourceFactory()->createEntryResource (10, false);
    embed = new dw::core::ui::Embed (entryResource);
-   form->addInput(DILLO_HTML_INPUT_INDEX, embed, NULL, NULL, FALSE);
+   Html_add_input(html, DILLO_HTML_INPUT_INDEX, embed, NULL, NULL, FALSE);
 
    if (prefs.standard_widget_colors) {
       HTML_SET_TOP_ATTR(html, color, NULL);
@@ -552,6 +605,7 @@
    DW2TB(html->dw)->addWidget (embed, S_TOP(html)->style);
   
    a_Url_free(action);
+   html->InFlags &= ~IN_FORM;
 }
 
 /*
@@ -560,17 +614,10 @@
  */
 void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize)
 {
-   DilloHtmlForm *form;
    char *name;
    const char *attrbuf;
    int cols, rows;
   
-   /* We can't push a new <FORM> because the 'action' URL is unknown */
-   if (!(html->InFlags & IN_FORM)) {
-      BUG_MSG("<textarea> outside <form>\n");
-      html->ReqTagClose = TRUE;
-      return;
-   }
    if (html->InFlags & IN_TEXTAREA) {
       BUG_MSG("nested <textarea>\n");
       html->ReqTagClose = TRUE;
@@ -578,7 +625,6 @@
    }
   
    html->InFlags |= IN_TEXTAREA;
-   form = html->getCurrentForm ();
    a_Html_stash_init(html);
    S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_VERBATIM;
   
@@ -601,7 +647,7 @@
    if (a_Html_get_attr(html, tag, tagsize, "readonly"))
       textres->setEditable(false);
 
-   form->addInput(DILLO_HTML_INPUT_TEXTAREA, embed, name, NULL, false);
+   Html_add_input(html, DILLO_HTML_INPUT_TEXTAREA, embed, name, NULL, false);
 
    DW2TB(html->dw)->addWidget (embed, S_TOP(html)->style);
 
@@ -630,7 +676,7 @@
 // gtk_widget_show(widget);
 // gtk_widget_show(scroll);
 //
-// form->addInput(DILLO_HTML_INPUT_TEXTAREA,
+// Html_add_input(html, DILLO_HTML_INPUT_TEXTAREA,
 //                widget, name, NULL, FALSE);
 // dFree(name);
 //
@@ -647,12 +693,10 @@
 void Html_tag_close_textarea(DilloHtml *html, int TagIdx)
 {
    char *str;
-   DilloHtmlForm *form;
    DilloHtmlInput *input;
    int i;
 
-   if (html->InFlags & IN_FORM &&
-       html->InFlags & IN_TEXTAREA) {
+   if (html->InFlags & IN_TEXTAREA) {
       /* Remove the line ending that follows the opening tag */
       if (html->Stash->str[0] == '\r')
          dStr_erase(html->Stash, 0, 1);
@@ -672,8 +716,7 @@
    
       /* The HTML3.2 spec says it can have "text and character entities". */
       str = a_Html_parse_entities(html, html->Stash->str, html->Stash->len);
-      form = html->getCurrentForm ();
-      input = form->getCurrentInput ();
+      input = Html_get_current_input(html);
       input->init_str = str;
       ((dw::core::ui::MultiLineTextResource *)input->embed->getResource ())
          ->setText(str);
@@ -692,10 +735,6 @@
 // const char *attrbuf;
 // int size, type, multi;
 
-   if (!(html->InFlags & IN_FORM)) {
-      BUG_MSG("<select> outside <form>\n");
-      return;
-   }
    if (html->InFlags & IN_SELECT) {
       BUG_MSG("nested <select>\n");
       return;
@@ -703,7 +742,6 @@
    html->InFlags |= IN_SELECT;
    html->InFlags &= ~IN_OPTION;
 
-   DilloHtmlForm *form = html->getCurrentForm ();
    char *name = a_Html_get_attr_wdef(html, tag, tagsize, "name", NULL);
    dw::core::ui::ResourceFactory *factory =
       HT2LT(html)->getResourceFactory ();
@@ -746,7 +784,7 @@
 //    type = DILLO_HTML_INPUT_SEL_LIST;
 // }
 
-   form->addInput(type, embed, name, NULL, false);
+   Html_add_input(html, type, embed, name, NULL, false);
    a_Html_stash_init(html);
    dFree(name);
 }
@@ -756,15 +794,13 @@
  */
 void Html_tag_close_select(DilloHtml *html, int TagIdx)
 {
-   if (html->InFlags & IN_FORM &&
-       html->InFlags & IN_SELECT) {
+   if (html->InFlags & IN_SELECT) {
       if (html->InFlags & IN_OPTION)
          Html_option_finish(html);
       html->InFlags &= ~IN_SELECT;
       html->InFlags &= ~IN_OPTION;
 
-      DilloHtmlForm *form = html->getCurrentForm ();
-      DilloHtmlInput *input = form->getCurrentInput ();
+      DilloHtmlInput *input = Html_get_current_input(html);
       DilloHtmlSelect *select = input->select;
 
       // BUG(?): should not do this for MULTI selections 
@@ -783,15 +819,15 @@
  */
 void Html_tag_open_option(DilloHtml *html, const char *tag, int tagsize)
 {
-   if (!(html->InFlags & IN_FORM &&
-         html->InFlags & IN_SELECT ))
+   if (!(html->InFlags & IN_SELECT)) {
+      BUG_MSG("<option> element outside <select>\n");
       return;
+   }
    if (html->InFlags & IN_OPTION)
       Html_option_finish(html);
    html->InFlags |= IN_OPTION;
 
-   DilloHtmlForm *form = html->getCurrentForm ();
-   DilloHtmlInput *input = form->getCurrentInput ();
+   DilloHtmlInput *input = Html_get_current_input(html);
 
    if (input->type == DILLO_HTML_INPUT_SELECT ||
        input->type == DILLO_HTML_INPUT_SEL_LIST) {
@@ -816,21 +852,15 @@
     * Buttons are rendered on one line, this is (at several levels) a
     * bit simpler. May be changed in the future.
     */
-   DilloHtmlForm *form;
    DilloHtmlInputType inp_type;
    char *type;
 
-   if (!(html->InFlags & IN_FORM)) {
-      BUG_MSG("<button> element outside <form>\n");
-      return;
-   }
    if (html->InFlags & IN_BUTTON) {
       BUG_MSG("nested <button>\n");
       return;
    }
    html->InFlags |= IN_BUTTON;
 
-   form = html->getCurrentForm ();
    type = a_Html_get_attr_wdef(html, tag, tagsize, "type", "");
 
    if (!dStrcasecmp(type, "button")) {
@@ -880,7 +910,7 @@
       value = a_Html_get_attr_wdef(html, tag, tagsize, "value", NULL);
       name = a_Html_get_attr_wdef(html, tag, tagsize, "name", NULL);
 
-      form->addInput(inp_type, embed, name, value, FALSE);
+      Html_add_input(html, inp_type, embed, name, value, FALSE);
       dFree(name);
       dFree(value);
    }
@@ -1398,14 +1428,6 @@
 }
 
 /*
- * Get the current input.
- */
-DilloHtmlInput *DilloHtmlForm::getCurrentInput ()
-{
-   return inputs->get (inputs->size() - 1);
-}
-
-/*
  * Reset all inputs containing reset to their initial values.  In
  * general, reset is the reset button for the form.
  */
@@ -1417,18 +1439,10 @@
 }
 
 /*
- * Add a new input, setting the initial values.
+ * Add a new input.
  */
-void DilloHtmlForm::addInput(DilloHtmlInputType type,
-                             dw::core::ui::Embed *embed,
-                             const char *name,
-                             const char *init_str,
-                             bool init_val)
+void DilloHtmlForm::addInput(DilloHtmlInput *input, DilloHtmlInputType type)
 {
-   _MSG("name=[%s] init_str=[%s] init_val=[%d]\n",
-        name, init_str, init_val);
-   DilloHtmlInput *input =
-      new DilloHtmlInput (type,embed,name,init_str,init_val);
    input->connectTo (form_receiver);
    int ni = inputs->size ();
    inputs->increase ();
@@ -1911,8 +1925,7 @@
  */
 static void Html_option_finish(DilloHtml *html)
 {
-   DilloHtmlForm *form = html->getCurrentForm ();
-   DilloHtmlInput *input = form->getCurrentInput ();
+   DilloHtmlInput *input = Html_get_current_input(html);
    if (input->type == DILLO_HTML_INPUT_SELECT ||
        input->type == DILLO_HTML_INPUT_SEL_LIST) {
       DilloHtmlOption *option =
--- a/src/form.hh	Sat Jul 12 19:29:56 2008 +0200
+++ b/src/form.hh	Wed Aug 06 14:58:39 2008 +0200
@@ -23,6 +23,7 @@
  */
 
 class DilloHtmlForm;
+class DilloHtmlInput;
 class DilloHtml;
 
 /*
@@ -36,6 +37,7 @@
                                const char *charset);
 
 void a_Html_form_delete(DilloHtmlForm* form);
+void a_Html_input_delete(DilloHtmlInput* input);
 
 /*
  * Form parsing functions 
--- a/src/html.cc	Sat Jul 12 19:29:56 2008 +0200
+++ b/src/html.cc	Wed Aug 06 14:58:39 2008 +0200
@@ -503,6 +503,7 @@
 
    /* Init page-handling variables */
    forms = new misc::SimpleVector <DilloHtmlForm*> (1);
+   inputs_outside_form = new misc::SimpleVector <DilloHtmlInput*> (1);
    links = new misc::SimpleVector <DilloUrl*> (64);
    images = new misc::SimpleVector <DilloLinkImage*> (16);
    //a_Dw_image_map_list_init(&maps);
@@ -570,6 +571,10 @@
       a_Html_form_delete (forms->get(i));
    delete(forms);
 
+   for (int i = 0; i < inputs_outside_form->size(); i++)
+      a_Html_input_delete(inputs_outside_form->get(i));
+   delete(inputs_outside_form);
+
    for (int i = 0; i < links->size(); i++)
       if (links->get(i))
          a_Url_free(links->get(i));
--- a/src/html_common.hh	Sat Jul 12 19:29:56 2008 +0200
+++ b/src/html_common.hh	Wed Aug 06 14:58:39 2008 +0200
@@ -197,6 +197,7 @@
    /* Variables required after parsing (for page functionality)          */
    /* -------------------------------------------------------------------*/
    lout::misc::SimpleVector<DilloHtmlForm*> *forms;
+   lout::misc::SimpleVector<DilloHtmlInput*> *inputs_outside_form;
    lout::misc::SimpleVector<DilloUrl*> *links;
    lout::misc::SimpleVector<DilloLinkImage*> *images;
    dw::ImageMapsList maps;