2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
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
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.
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
23 #include "WOElement+private.h"
25 #include "WOContext+private.h"
26 #include <NGObjWeb/WOApplication.h>
29 @implementation WOForm
31 static int debugTakeValues = -1;
37 - (id)initWithName:(NSString *)_name
38 associations:(NSDictionary *)_config
39 template:(WOElement *)_c
41 if (debugTakeValues == -1) {
43 [[NSUserDefaults standardUserDefaults] boolForKey:@"WODebugTakeValues"]
45 if (debugTakeValues) NSLog(@"WOForm: WODebugTakeValues on.");
48 if ((self = [super initWithName:_name associations:_config template:_c])) {
49 WOAssociation *sidInUrlAssoc;
52 self->containsForm = YES;
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");
64 self->sidInUrl = (sidInUrlAssoc != nil)
65 ? [sidInUrlAssoc boolValueInComponent:nil]
68 if ((tmp = OWGetProperty(_config, @"multipleSubmit")) != nil) {
69 /* not required with SOPE, for WO compatibility */
73 self->template = [_c retain];
79 [self->method release];
80 [self->template release];
81 [self->actionClass release];
82 [self->directActionName release];
83 [self->queryDictionary release];
84 [self->queryParameters release];
85 [self->action release];
86 [self->pageName release];
91 /* handle active form elements */
94 return self->template;
97 /* handling requests */
99 - (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
100 static int alwaysPassIn = -1;
102 if (alwaysPassIn == -1) {
103 alwaysPassIn = [[[NSUserDefaults standardUserDefaults]
104 objectForKey:@"WOFormAlwaysPassDown"]
108 if ([_ctx isInForm]) {
109 [self errorWithFormat:@"(%s): another form is already active in context !",
110 __PRETTY_FUNCTION__];
113 [_ctx setInForm:YES];
115 WOComponent *sComponent = [_ctx component];
116 BOOL doTakeValues = NO;
118 if (self->queryParameters != nil) {
119 /* apply values to ?style parameters */
123 keys = [self->queryParameters keyEnumerator];
124 while ((key = [keys nextObject])) {
125 WOAssociation *assoc;
128 assoc = [self->queryParameters objectForKey:key];
129 value = [_rq formValueForKey:key];
131 [assoc setValue:value inComponent:sComponent];
135 // TODO: explain this href comparison
136 if ([[self->href stringValueInComponent:sComponent]
137 isEqualToString:[_rq uri]]) {
138 if (debugTakeValues) {
139 NSArray *formValues = [_rq formValueKeys];
140 NSLog(@"%s: we are uri active (uri=%@): %@ ..", __PRETTY_FUNCTION__,
141 [_rq uri], formValues);
145 else if ([[_ctx elementID] isEqualToString:[_ctx senderID]]) {
146 if (debugTakeValues) {
147 NSArray *formValues = [_rq formValueKeys];
148 NSLog(@"%s: we are elem active (eid=%@): %@ ..", __PRETTY_FUNCTION__,
149 [_ctx elementID], formValues);
153 else if (alwaysPassIn) {
154 // Note: this does not call the component! Bug? (see 'else' below)
156 NSLog(@"%s: taking values from foreign request ",__PRETTY_FUNCTION__);
160 /* finally, let the component decide */
161 doTakeValues = [sComponent shouldTakeValuesFromRequest:_rq
163 if (debugTakeValues) {
164 NSLog(@"%s: component should take values: %s ", __PRETTY_FUNCTION__,
165 doTakeValues ? "yes" : "no");
171 NSLog(@"%s: taking values ...", __PRETTY_FUNCTION__);
173 [self->template takeValuesFromRequest:_rq inContext:_ctx];
176 NSLog(@"%s: did take values.", __PRETTY_FUNCTION__);
178 else if (debugTakeValues) {
181 @"WOForm: *not* taking values from foreign request "
182 @"(id='%@' vs sid='%@') ...",
183 [_ctx elementID], [_ctx senderID]];
187 if (![_ctx isInForm]) {
189 errorWithFormat:@"(%s:%d): -isInForm is NO !!!",
190 __PRETTY_FUNCTION__, __LINE__];
196 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
199 [_ctx setInForm:YES];
201 if ([_ctx currentElementID] == nil) {
204 if ((element = [_ctx activeFormElement])) {
206 result = [self->template invokeActionForRequest:_rq inContext:_ctx];
209 /* wrong - need to setup correct component stack */
210 result = [[element invokeActionForRequest:_rq
215 else if (self->action) {
216 result = [self executeAction:self->action inContext:_ctx];
218 else if (self->pageName) {
219 NSString *pname = nil;
220 WOComponent *page = nil;
222 pname = [self->pageName stringValueInComponent:[_ctx component]];
223 page = [[_ctx application] pageWithName:pname inContext:_ctx];
226 [[_ctx session] logWithFormat:
227 @"%@[0x%08X]: did not find page with name %@ !",
228 NSStringFromClass([self class]), self, pname];
230 NSLog(@"showing page %@", page);
235 result = [self->template invokeActionForRequest:_rq inContext:_ctx];
242 /* generate response */
244 - (NSString *)_addHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
245 /* post to a fixed hyperlink */
246 WOComponent *sComponent = [_ctx component];
250 s = [self->href stringValueInComponent:sComponent];
251 d = [self->queryDictionary valueInComponent:sComponent];
253 WOResponse_AddString(_r, s);
255 return [self queryStringForQueryDictionary:d
256 andQueryParameters:self->queryParameters
260 - (NSString *)_addActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
261 /* post to a component action */
264 WOResponse_AddString(_r, [_c componentActionURL]);
266 d = [self->queryDictionary valueInComponent:[_c component]];
267 return [self queryStringForQueryDictionary:d
268 andQueryParameters:self->queryParameters
272 - (void)_addDirectActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
273 /* a direct action link */
274 WOComponent *sComponent;
275 NSString *daClass = nil;
276 NSString *daName = nil;
277 NSMutableDictionary *qd;
281 sComponent = [_c component];
282 daClass = [self->actionClass stringValueInComponent:sComponent];
283 daName = [self->directActionName stringValueInComponent:sComponent];
285 if (daClass != nil) {
287 if (![daClass isEqualToString:@"DirectAction"])
288 daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
294 qd = [NSMutableDictionary dictionaryWithCapacity:16];
296 /* add query dictionary */
298 if (self->queryDictionary) {
299 if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
300 [qd addEntriesFromDictionary:tmp];
303 /* add ?style parameters */
305 if (self->queryParameters) {
309 keys = [self->queryParameters keyEnumerator];
310 while ((key = [keys nextObject])) {
313 assoc = [self->queryParameters objectForKey:key];
314 value = [assoc stringValueInComponent:sComponent];
316 [qd setObject:(value ? value : @"") forKey:key];
321 if (self->sidInUrl && [_c hasSession]) {
325 [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
327 if (![sn isDistributionEnabled]) {
328 [qd setObject:[[WOApplication application] number]
329 forKey:WORequestValueInstance];
332 else if (self->sidInUrl) {
333 /* Note: this is not a problem! Eg this occurs on the OGo Main component */
334 [self debugWithFormat:
335 @"Note: session-id is requested, but no session is active?"];
338 uri = [_c directActionURLForActionNamed:daName queryDictionary:qd];
339 WOResponse_AddString(_r, uri);
342 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
343 WOComponent *sComponent;
344 NSString *queryString = nil;
346 if ([[_ctx request] isFromClientComponent]) {
347 [self->template appendToResponse:_response inContext:_ctx];
351 [_ctx setInForm:YES];
352 sComponent = [_ctx component];
354 WOResponse_AddCString(_response, "<form action=\"");
356 if (self->href != nil)
357 queryString = [self _addHrefToResponse:_response inContext:_ctx];
358 else if (self->directActionName != nil || self->actionClass != nil)
359 [self _addDirectActionToResponse:_response inContext:_ctx];
361 queryString = [self _addActionToResponse:_response inContext:_ctx];
364 [_response appendContentCharacter:'?'];
365 WOResponse_AddString(_response, queryString);
368 WOResponse_AddCString(_response, "\" method=\"");
369 WOResponse_AddString(_response,
370 [self->method stringValueInComponent:sComponent]);
371 WOResponse_AddCString(_response, "\"");
374 WOResponse_AddCString(_response, "\" method=\"post\"");
376 [self appendExtraAttributesToResponse:_response inContext:_ctx];
378 if (self->otherTagString) {
379 WOResponse_AddChar(_response, ' ');
380 WOResponse_AddString(_response,
381 [self->otherTagString stringValueInComponent:
384 WOResponse_AddChar(_response, '>');
386 [self->template appendToResponse:_response inContext:_ctx];
388 WOResponse_AddCString(_response, "</form>");
394 - (NSString *)associationDescription {
395 NSMutableString *str = [NSMutableString stringWithCapacity:64];
396 //[str appendString:[super associationDescription]];
398 if (self->action) [str appendFormat:@" action=%@", self->action];
399 if (self->href) [str appendFormat:@" href=%@", self->href];
400 if (self->pageName) [str appendFormat:@" page=%@", self->pageName];
402 if (self->actionClass)
403 [str appendFormat:@" actionClass=%@", self->actionClass];
404 if (self->directActionName)
405 [str appendFormat:@" directAction=%@", self->directActionName];
407 [str appendFormat:@" template=%@", self->template];