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