]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOForm.m
a1165e853a81513f41e217c6a46730348810e483
[sope] / sope-appserver / NGObjWeb / DynamicElements / WOForm.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "WOForm.h"
24 #include "WOElement+private.h"
25 #include "WOInput.h"
26 #include "WOContext+private.h"
27 #include <NGObjWeb/WOApplication.h>
28 #include "common.h"
29
30 @implementation WOForm
31
32 static int debugTakeValues = -1;
33
34 + (int)version {
35   return 4;
36 }
37
38 - (id)initWithName:(NSString *)_name
39   associations:(NSDictionary *)_config
40   template:(WOElement *)_c
41 {
42   if (debugTakeValues == -1) {
43     debugTakeValues = 
44       [[NSUserDefaults standardUserDefaults] boolForKey:@"WODebugTakeValues"]
45       ? 1 : 0;
46     if (debugTakeValues) NSLog(@"WOForm: WODebugTakeValues on.");
47   }
48   
49   if ((self = [super initWithName:_name associations:_config template:_c])) {
50     WOAssociation *sidInUrlAssoc;
51
52     self->containsForm = YES;
53     
54     sidInUrlAssoc          = OWGetProperty(_config, @"?wosid");
55     self->action           = OWGetProperty(_config, @"action");
56     self->href             = OWGetProperty(_config, @"href");
57     self->pageName         = OWGetProperty(_config, @"pageName");
58     self->queryDictionary  = OWGetProperty(_config, @"queryDictionary");
59     self->queryParameters  = OWExtractQueryParameters(_config);
60     self->actionClass      = OWGetProperty(_config, @"actionClass");
61     self->directActionName = OWGetProperty(_config, @"directActionName");
62     self->method           = OWGetProperty(_config, @"method");
63     
64     self->sidInUrl = (sidInUrlAssoc != nil)
65       ? [sidInUrlAssoc boolValueInComponent:nil]
66       : YES;
67     
68     self->template = [_c retain];
69   }
70   return self;
71 }
72
73 - (void)dealloc {
74   [self->method           release];
75   [self->template         release];
76   [self->actionClass      release];
77   [self->directActionName release];
78   [self->queryDictionary  release];
79   [self->queryParameters  release];
80   [self->action           release];
81   [self->pageName         release];
82   [self->href             release];
83   [super dealloc];
84 }
85
86 /* handle active form elements */
87
88 - (WOElement *)template {
89   return self->template;
90 }
91
92 // ******************** responder ********************
93
94 - (void)takeValuesFromRequest:(WORequest *)_request
95   inContext:(WOContext *)_ctx
96 {
97   static int alwaysPassIn = -1;
98
99   if (alwaysPassIn == -1) {
100     alwaysPassIn = [[[NSUserDefaults standardUserDefaults]
101                                      objectForKey:@"WOFormAlwaysPassDown"]
102                                      boolValue] ? 1 : 0;
103   }
104   
105   if ([_ctx isInForm]) {
106     NSLog(@"ERROR(%s): another form is already active in context !",
107           __PRETTY_FUNCTION__);
108   }
109   
110   [_ctx setInForm:YES];
111   {
112     WOComponent *sComponent = [_ctx component];
113     BOOL doTakeValues = NO;
114     
115     if (self->queryParameters) {
116       /* apply values to ?style parameters */
117       NSEnumerator *keys;
118       NSString     *key;
119
120       keys = [self->queryParameters keyEnumerator];
121       while ((key = [keys nextObject])) {
122         WOAssociation *assoc;
123         id value;
124         
125         assoc = [self->queryParameters objectForKey:key];
126         value = [_request formValueForKey:key];
127
128         [assoc setValue:value inComponent:sComponent];
129       }
130     }
131     
132     if ([[self->href stringValueInComponent:sComponent] 
133           isEqualToString:[_request uri]]) {
134       if (debugTakeValues) {
135         NSArray *formValues = [_request formValueKeys];
136         NSLog(@"%s: we are uri active (uri=%@): %@ ..", __PRETTY_FUNCTION__,
137               [_request uri], formValues);
138       }
139       doTakeValues = YES;
140     }
141     else if ([[_ctx elementID] isEqualToString:[_ctx senderID]]) {
142       if (debugTakeValues) {
143         NSArray *formValues = [_request formValueKeys];
144         NSLog(@"%s: we are elem active (eid=%@): %@ ..", __PRETTY_FUNCTION__,
145               [_ctx elementID], formValues);
146       }
147       doTakeValues = YES;
148     }
149     else if (alwaysPassIn) {
150       if (debugTakeValues)
151         NSLog(@"%s: taking values from foreign request ",__PRETTY_FUNCTION__);
152       doTakeValues = YES;
153     }
154     else {
155       /* finally, let the component decide */
156       doTakeValues = [sComponent shouldTakeValuesFromRequest:_request 
157                                  inContext:_ctx];
158       if (debugTakeValues) {
159         NSLog(@"%s: component should take values: %s ", __PRETTY_FUNCTION__,
160               doTakeValues ? "yes" : "no");
161       }
162     }
163     
164     if (doTakeValues) {
165       if (debugTakeValues) 
166         NSLog(@"%s: taking values ...", __PRETTY_FUNCTION__);
167       
168       [self->template takeValuesFromRequest:_request inContext:_ctx];
169
170       if (debugTakeValues) 
171         NSLog(@"%s: did take values.", __PRETTY_FUNCTION__);
172     }
173     else if (debugTakeValues) {
174       [sComponent
175              debugWithFormat:
176                @"WOForm: *not* taking values from foreign request "
177                @"(id='%@' vs sid='%@') ...",
178                [_ctx elementID], [_ctx senderID]];
179     }
180   }
181   
182   if (![_ctx isInForm]) {
183     [[_ctx component]
184            logWithFormat:@"ERROR(%s:%d): -isInForm is NO !!!",
185              __PRETTY_FUNCTION__, __LINE__];
186   }
187   else
188     [_ctx setInForm:NO];
189 }
190
191 - (id)invokeActionForRequest:(WORequest *)_request
192   inContext:(WOContext *)_ctx
193 {
194   id result = nil;
195   
196   [_ctx setInForm:YES];
197
198   if ([_ctx currentElementID] == nil) {
199     WOElement *element;
200     
201     if ((element = [_ctx activeFormElement])) {
202 #if 1
203       result = [self->template invokeActionForRequest:_request inContext:_ctx];
204       RETAIN(result);
205 #else
206       /* wrong - need to setup correct component stack */
207       result = [[element invokeActionForRequest:_request
208                          inContext:_ctx]
209                          retain];
210 #endif
211     }
212     else if (self->action) {
213       result = [self executeAction:self->action inContext:_ctx];
214     }
215     else if (self->pageName) {
216       NSString    *pname = nil;
217       WOComponent *page = nil;
218
219       pname = [self->pageName stringValueInComponent:[_ctx component]];
220       page  = [[_ctx application] pageWithName:pname inContext:_ctx];
221
222       if (page == nil) {
223         [[_ctx session] logWithFormat:
224                           @"%@[0x%08X]: did not find page with name %@ !",
225                           NSStringFromClass([self class]), self, pname];
226       }
227       NSLog(@"showing page %@", page);
228       result = page;
229     }
230   }
231   else
232     result = [self->template invokeActionForRequest:_request inContext:_ctx];
233
234   [_ctx setInForm:NO];
235
236   return result;
237 }
238
239 - (NSString *)_addHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
240   /* post to a fixed hyperlink */
241   WOComponent *sComponent = [_ctx component];
242   NSString     *s;
243   NSDictionary *d;
244
245   s = [self->href stringValueInComponent:sComponent];
246   d = [self->queryDictionary valueInComponent:sComponent];
247   
248   WOResponse_AddString(_r, s);
249   
250   return [self queryStringForQueryDictionary:d
251                andQueryParameters:self->queryParameters
252                inContext:_ctx];
253 }
254
255 - (NSString *)_addActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
256   /* post to a component action */
257   NSDictionary *d;
258         
259   WOResponse_AddString(_r, [_c componentActionURL]);
260
261   d = [self->queryDictionary valueInComponent:[_c component]];
262   return [self queryStringForQueryDictionary:d
263                andQueryParameters:self->queryParameters
264                inContext:_c];
265 }
266
267 - (void)_addDirectActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
268   /* a direct action link */
269   WOComponent *sComponent;
270   NSString            *daClass = nil;
271   NSString            *daName  = nil;
272   NSMutableDictionary *qd;
273   NSDictionary        *tmp;
274   NSString            *uri;
275           
276   sComponent = [_c component];
277   daClass = [self->actionClass stringValueInComponent:sComponent];
278   daName  = [self->directActionName stringValueInComponent:sComponent];
279   
280   if (daClass) {
281     if (daName) {
282       if (![daClass isEqualToString:@"DirectAction"])
283         daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
284     }
285     else
286       daName = daClass;
287   }
288   
289   qd = [NSMutableDictionary dictionaryWithCapacity:16];
290   
291   /* add query dictionary */
292         
293   if (self->queryDictionary) {
294     if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
295       [qd addEntriesFromDictionary:tmp];
296   }
297         
298   /* add ?style parameters */
299   
300   if (self->queryParameters) {
301     NSEnumerator *keys;
302     NSString     *key;
303   
304     keys = [self->queryParameters keyEnumerator];
305     while ((key = [keys nextObject])) {
306       id assoc, value;
307   
308       assoc = [self->queryParameters objectForKey:key];
309       value = [assoc stringValueInComponent:sComponent];
310             
311       [qd setObject:(value ? value : @"") forKey:key];
312     }
313   }
314         
315   /* add session ID */
316   if (self->sidInUrl && [_c hasSession]) {
317     WOSession *sn;
318
319     sn = [_c session];
320     [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
321             
322     if (![sn isDistributionEnabled]) {
323       [qd setObject:[[WOApplication application] number]
324           forKey:WORequestValueInstance];
325     }
326   }
327   else if (self->sidInUrl) {
328     [self debugWithFormat:
329             @"Note: session-id is requested, but no session is active?"];
330   }
331   
332   uri = [_c directActionURLForActionNamed:daName queryDictionary:qd];
333   WOResponse_AddString(_r, uri);
334 }
335
336 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
337   WOComponent *sComponent;
338   NSString    *queryString = nil;
339   
340   if ([[_ctx request] isFromClientComponent]) {
341     [self->template appendToResponse:_response inContext:_ctx];
342     return;
343   }
344   
345   [_ctx setInForm:YES];
346   sComponent  = [_ctx component];
347
348   WOResponse_AddCString(_response, "<form action=\"");
349       
350   if (self->href) 
351     queryString = [self _addHrefToResponse:_response inContext:_ctx];
352   else if (self->directActionName != nil || self->actionClass != nil)
353     [self _addDirectActionToResponse:_response inContext:_ctx];
354   else
355     queryString = [self _addActionToResponse:_response inContext:_ctx];
356   
357   if (queryString) {
358     [_response appendContentCharacter:'?'];
359     WOResponse_AddString(_response, queryString);
360   }
361   if (self->method) {
362     WOResponse_AddCString(_response, "\" method=\"");
363     WOResponse_AddString(_response, 
364                          [self->method stringValueInComponent:sComponent]);
365     WOResponse_AddCString(_response, "\"");
366   }
367   else
368     WOResponse_AddCString(_response, "\" method=\"post\"");
369       
370   [self appendExtraAttributesToResponse:_response inContext:_ctx];
371   
372   if (self->otherTagString) {
373     NSString *s;
374     
375     s = [self->otherTagString stringValueInComponent:sComponent];
376     if ([s length] > 0) WOResponse_AddString(_response, s);
377   }
378   WOResponse_AddChar(_response, '>');
379     
380   [self->template appendToResponse:_response inContext:_ctx];
381   
382   WOResponse_AddCString(_response, "</form>");
383   [_ctx setInForm:NO];
384 }
385
386 /* description */
387
388 - (NSString *)associationDescription {
389   NSMutableString *str = [NSMutableString stringWithCapacity:64];
390   //[str appendString:[super associationDescription]];
391
392   if (self->action)   [str appendFormat:@" action=%@", self->action];
393   if (self->href)     [str appendFormat:@" href=%@", self->href];
394   if (self->pageName) [str appendFormat:@" page=%@", self->pageName];
395
396   if (self->actionClass)
397     [str appendFormat:@" actionClass=%@", self->actionClass];
398   if (self->directActionName)
399     [str appendFormat:@" directAction=%@", self->directActionName];
400   if (self->template)
401     [str appendFormat:@" template=%@", self->template];
402   
403   return str;
404 }
405
406 @end /* WOForm */