Add to git.
[monolith.git] / src / ml_form.c
1 /* Monolith form class.
2  * - by Richard W.M. Jones <rich@annexia.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * $Id: ml_form.c,v 1.6 2002/11/23 16:46:05 rich Exp $
19  */
20
21 #include "config.h"
22
23 #ifdef HAVE_ASSERT_H
24 #include <assert.h>
25 #endif
26
27 #include <vector.h>
28 #include <hash.h>
29 #include <pstring.h>
30
31 #include <pthr_iolib.h>
32 #include <pthr_cgi.h>
33
34 #include "monolith.h"
35 #include "ml_widget.h"
36 #include "ml_form_input.h"
37 #include "ml_form.h"
38
39 static void repaint (void *, ml_session, const char *, io_handle);
40 static struct ml_widget_property properties[];
41
42 struct ml_widget_operations form_ops =
43   {
44     repaint: repaint,
45     properties: properties,
46   };
47
48 struct ml_form
49 {
50   struct ml_widget_operations *ops;
51   pool pool;                    /* Pool for allocations. */
52   ml_widget w;                  /* Packed widget. */
53   const char *action_id;        /* Form's callback action. */
54   const char *method;           /* Either "GET" or "POST". */
55   const char *name;             /* Unique name of the form. */
56
57   /* This is the user's real callback function. */
58   void (*submit_fn) (ml_session, void *);
59   void *submit_data;
60
61   vector inputs;                /* List of input widgets. */
62 };
63
64 static struct ml_widget_property properties[] =
65   {
66     { name: "method",
67       offset: ml_offsetof (struct ml_form, method),
68       type: ML_PROP_STRING },
69     { name: "form.name",
70       offset: ml_offsetof (struct ml_form, name),
71       type: ML_PROP_STRING,
72       flags: ML_PROP_READ_ONLY },
73     { 0 },
74   };
75
76 struct form_input
77 {
78   ml_form_input w;              /* Widget pointer. */
79   const char *name;             /* Name of input widget. */
80 };
81
82 static void form_callback (ml_session, void *);
83
84 ml_form
85 new_ml_form (pool pool)
86 {
87   static int unique = 0;
88   ml_form w = pmalloc (pool, sizeof *w);
89
90   w->ops = &form_ops;
91   w->pool = pool;
92   w->w = 0;
93   w->action_id = 0;
94   w->method = "POST";
95   w->name = psprintf (pool, "ml_form%d", ++unique);
96   w->submit_fn = 0;
97   w->submit_data = 0;
98   w->inputs = new_vector (pool, struct form_input);
99
100   return w;
101 }
102
103 void
104 ml_form_set_callback (ml_form w, void (*callback_fn) (ml_session, void *),
105                       ml_session session, void *data)
106 {
107   if (w->action_id)
108     ml_unregister_action (session, w->action_id);
109   w->action_id = 0;
110   w->submit_fn = 0;
111   w->submit_data = 0;
112
113   if (callback_fn)
114     {
115       w->action_id = ml_register_action (session, form_callback, w);
116       w->submit_fn = callback_fn;
117       w->submit_data = data;
118     }
119 }
120
121 void
122 ml_form_pack (ml_form w, ml_widget _w)
123 {
124   w->w = _w;
125 }
126
127 /* We capture the callback function when the submit button is pressed
128  * and allow ourselves to update the values fields of all our input
129  * widgets first.
130  */
131 static void
132 form_callback (ml_session session, void *vw)
133 {
134   pool session_pool = ml_session_pool (session);
135   ml_form w = (ml_form) vw;
136   cgi args;
137   int i;
138
139   /* Get the arguments passed to this HTTP request. */
140   args = _ml_session_submitted_args (session);
141
142   /* Update the values of submitted form elements. */
143   for (i = 0; i < vector_size (w->inputs); ++i)
144     {
145       struct form_input input;
146       vector values;
147       const char *value;
148       int j;
149
150       vector_get (w->inputs, i, input);
151       values = cgi_param_list (args, input.name);
152
153       /* Clear value first. */
154       ml_form_input_clear_value (input.w);
155
156       /* Set value(s). */
157       if (values)
158         for (j = 0; j < vector_size (values); ++j)
159           {
160             vector_get (values, j, value);
161             ml_form_input_set_value (input.w, pstrdup (session_pool, value));
162           }
163     }
164
165   /* Call the user's real callback function. */
166   assert (w->submit_fn != 0);
167   w->submit_fn (session, w->submit_data);
168 }
169
170 const char *
171 _ml_form_register_widget (ml_form f, ml_form_input w)
172 {
173   struct form_input input;
174   static int name_id = 0;
175
176   input.name = psprintf (f->pool, "ml_f%d", ++name_id);
177   input.w = w;
178
179   vector_push_back (f->inputs, input);
180
181   return input.name;
182 }
183
184 static void
185 repaint (void *vw, ml_session session, const char *windowid, io_handle io)
186 {
187   ml_form w = (ml_form) vw;
188
189   if (w->w)
190     {
191       if (w->action_id)
192         io_fprintf (io,
193                     "<form method=\"%s\" action=\"%s\" name=\"%s\">"
194                     "<input type=\"hidden\" name=\"ml_window\" value=\"%s\" />"
195                     "<input type=\"hidden\" name=\"ml_action\" value=\"%s\" />"
196                     ,
197                     w->method,
198                     ml_session_script_name (session),
199                     w->name,
200                     windowid,
201                     w->action_id);
202       else
203         io_fputs ("<form>", io);
204       ml_widget_repaint (w->w, session, windowid, io);
205       io_fputs ("</form>", io);
206     }
207 }