2 Copyright (C) 2000-2006 SKYRIX Software AG
3 Copyright (C) 2006 Helge Hess
5 This file is part of SOPE.
7 SOPE is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with SOPE; see the file COPYING. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 #include "WOElement+private.h"
26 #include "WOContext+private.h"
27 #include <NGObjWeb/WOApplication.h>
30 @implementation WOForm
32 static int debugTakeValues = -1;
38 - (id)initWithName:(NSString *)_name
39 associations:(NSDictionary *)_config
40 template:(WOElement *)_c
42 if (debugTakeValues == -1) {
44 [[NSUserDefaults standardUserDefaults] boolForKey:@"WODebugTakeValues"]
46 if (debugTakeValues) NSLog(@"WOForm: WODebugTakeValues on.");
49 if ((self = [super initWithName:_name associations:_config template:_c])) {
50 WOAssociation *sidInUrlAssoc;
53 self->containsForm = YES;
55 sidInUrlAssoc = OWGetProperty(_config, @"?wosid");
56 self->action = OWGetProperty(_config, @"action");
57 self->href = OWGetProperty(_config, @"href");
58 self->pageName = OWGetProperty(_config, @"pageName");
59 self->queryDictionary = OWGetProperty(_config, @"queryDictionary");
60 self->queryParameters = OWExtractQueryParameters(_config);
61 self->actionClass = OWGetProperty(_config, @"actionClass");
62 self->directActionName = OWGetProperty(_config, @"directActionName");
63 self->method = OWGetProperty(_config, @"method");
64 self->fragmentIdentifier = OWGetProperty(_config, @"fragmentIdentifier");
66 self->sidInUrl = (sidInUrlAssoc != nil)
67 ? [sidInUrlAssoc boolValueInComponent:nil]
70 if ((tmp = OWGetProperty(_config, @"multipleSubmit")) != nil) {
71 /* not required with SOPE, for WO compatibility */
75 self->template = [_c retain];
81 [self->fragmentIdentifier release];
82 [self->method release];
83 [self->template release];
84 [self->actionClass release];
85 [self->directActionName release];
86 [self->queryDictionary release];
87 [self->queryParameters release];
88 [self->action release];
89 [self->pageName release];
94 /* handle active form elements */
97 return self->template;
100 /* handling requests */
102 - (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
103 static int alwaysPassIn = -1;
105 if (alwaysPassIn == -1) {
106 alwaysPassIn = [[[NSUserDefaults standardUserDefaults]
107 objectForKey:@"WOFormAlwaysPassDown"]
111 if ([_ctx isInForm]) {
112 [self errorWithFormat:@"(%s): another form is already active in context !",
113 __PRETTY_FUNCTION__];
116 [_ctx setInForm:YES];
118 WOComponent *sComponent = [_ctx component];
119 BOOL doTakeValues = NO;
121 if (self->queryParameters != nil) {
122 /* apply values to ?style parameters */
126 keys = [self->queryParameters keyEnumerator];
127 while ((key = [keys nextObject])) {
128 WOAssociation *assoc;
131 assoc = [self->queryParameters objectForKey:key];
132 value = [_rq formValueForKey:key];
134 [assoc setValue:value inComponent:sComponent];
138 // TODO: explain this href comparison
139 if ([[self->href stringValueInComponent:sComponent]
140 isEqualToString:[_rq uri]]) {
141 if (debugTakeValues) {
142 NSArray *formValues = [_rq formValueKeys];
143 NSLog(@"%s: we are uri active (uri=%@): %@ ..", __PRETTY_FUNCTION__,
144 [_rq uri], formValues);
148 else if ([[_ctx elementID] isEqualToString:[_ctx senderID]]) {
149 if (debugTakeValues) {
150 NSArray *formValues = [_rq formValueKeys];
151 NSLog(@"%s: we are elem active (eid=%@): %@ ..", __PRETTY_FUNCTION__,
152 [_ctx elementID], formValues);
156 else if (alwaysPassIn) {
157 // Note: this does not call the component! Bug? (see 'else' below)
159 NSLog(@"%s: taking values from foreign request ",__PRETTY_FUNCTION__);
163 /* finally, let the component decide */
164 doTakeValues = [sComponent shouldTakeValuesFromRequest:_rq
166 if (debugTakeValues) {
167 NSLog(@"%s: component should take values: %s ", __PRETTY_FUNCTION__,
168 doTakeValues ? "yes" : "no");
174 NSLog(@"%s: taking values ...", __PRETTY_FUNCTION__);
176 [self->template takeValuesFromRequest:_rq inContext:_ctx];
179 NSLog(@"%s: did take values.", __PRETTY_FUNCTION__);
181 else if (debugTakeValues) {
184 @"WOForm: *not* taking values from foreign request "
185 @"(id='%@' vs sid='%@') ...",
186 [_ctx elementID], [_ctx senderID]];
190 if (![_ctx isInForm]) {
192 errorWithFormat:@"(%s:%d): -isInForm is NO !!!",
193 __PRETTY_FUNCTION__, __LINE__];
199 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
202 [_ctx setInForm:YES];
204 if ([_ctx currentElementID] == nil) {
207 if ((element = [_ctx activeFormElement])) {
209 result = [self->template invokeActionForRequest:_rq inContext:_ctx];
212 /* wrong - need to setup correct component stack */
213 result = [[element invokeActionForRequest:_rq
218 else if (self->action) {
219 result = [self executeAction:self->action inContext:_ctx];
221 else if (self->pageName) {
222 NSString *pname = nil;
223 WOComponent *page = nil;
225 pname = [self->pageName stringValueInComponent:[_ctx component]];
226 page = [[_ctx application] pageWithName:pname inContext:_ctx];
229 [[_ctx session] logWithFormat:
230 @"%@[0x%p]: did not find page with name %@ !",
231 NSStringFromClass([self class]), self, pname];
233 NSLog(@"showing page %@", page);
238 result = [self->template invokeActionForRequest:_rq inContext:_ctx];
245 /* generate response */
247 - (NSString *)_addHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
248 /* post to a fixed hyperlink */
249 WOComponent *sComponent = [_ctx component];
253 s = [self->href stringValueInComponent:sComponent];
254 d = [self->queryDictionary valueInComponent:sComponent];
256 WOResponse_AddString(_r, s);
258 return [self queryStringForQueryDictionary:d
259 andQueryParameters:self->queryParameters
263 - (NSString *)_addActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
264 /* post to a component action */
267 WOResponse_AddString(_r, [_c componentActionURL]);
269 d = [self->queryDictionary valueInComponent:[_c component]];
270 return [self queryStringForQueryDictionary:d
271 andQueryParameters:self->queryParameters
275 - (void)_addDirectActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c {
276 /* a direct action link */
277 WOComponent *sComponent;
278 NSString *daClass = nil;
279 NSString *daName = nil;
280 NSMutableDictionary *qd;
284 sComponent = [_c component];
285 daClass = [self->actionClass stringValueInComponent:sComponent];
286 daName = [self->directActionName stringValueInComponent:sComponent];
288 if (daClass != nil) {
290 if (![daClass isEqualToString:@"DirectAction"])
291 daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
297 qd = [NSMutableDictionary dictionaryWithCapacity:16];
299 /* add query dictionary */
301 if (self->queryDictionary) {
302 if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
303 [qd addEntriesFromDictionary:tmp];
306 /* add ?style parameters */
308 if (self->queryParameters) {
312 keys = [self->queryParameters keyEnumerator];
313 while ((key = [keys nextObject])) {
316 assoc = [self->queryParameters objectForKey:key];
317 value = [assoc stringValueInComponent:sComponent];
319 [qd setObject:(value != nil ? value : (id)@"") forKey:key];
324 if (self->sidInUrl && [_c hasSession]) {
328 [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
330 if (![sn isDistributionEnabled]) {
331 [qd setObject:[[WOApplication application] number]
332 forKey:WORequestValueInstance];
335 else if (self->sidInUrl) {
336 /* Note: this is not a problem! Eg this occurs on the OGo Main component */
337 [self debugWithFormat:
338 @"Note: session-id is requested, but no session is active?"];
341 uri = [_c directActionURLForActionNamed:daName queryDictionary:qd];
342 WOResponse_AddString(_r, uri);
345 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
346 WOComponent *sComponent;
347 NSString *queryString = nil;
349 if ([[_ctx request] isFromClientComponent]) {
350 [self->template appendToResponse:_response inContext:_ctx];
354 sComponent = [_ctx component];
357 [self warnWithFormat:@"detected nested WOForm, component: %@", sComponent];
359 [_ctx setInForm:YES];
361 WOResponse_AddCString(_response, "<form action=\"");
363 /* add URL to response and return the query string */
365 if (self->href != nil)
366 queryString = [self _addHrefToResponse:_response inContext:_ctx];
367 else if (self->directActionName != nil || self->actionClass != nil)
368 [self _addDirectActionToResponse:_response inContext:_ctx];
370 queryString = [self _addActionToResponse:_response inContext:_ctx];
372 if (self->fragmentIdentifier != nil) {
373 NSString *f = [self->fragmentIdentifier stringValueInComponent:sComponent];
374 if ([f isNotEmpty]) {
375 [_response appendContentCharacter:'#'];
376 WOResponse_AddString(_response, f);
380 /* append the query string */
382 if (queryString != nil) {
383 [_response appendContentCharacter:'?'];
384 WOResponse_AddString(_response, queryString);
386 if (self->method != nil) {
387 WOResponse_AddCString(_response, "\" method=\"");
388 WOResponse_AddString(_response,
389 [self->method stringValueInComponent:sComponent]);
390 WOResponse_AddCString(_response, "\"");
393 WOResponse_AddCString(_response, "\" method=\"post\"");
395 [self appendExtraAttributesToResponse:_response inContext:_ctx];
397 if (self->otherTagString != nil) {
398 WOResponse_AddChar(_response, ' ');
399 WOResponse_AddString(_response,
400 [self->otherTagString stringValueInComponent:
403 WOResponse_AddChar(_response, '>');
405 /* render form content */
407 [self->template appendToResponse:_response inContext:_ctx];
411 WOResponse_AddCString(_response, "</form>");
417 - (NSString *)associationDescription {
418 NSMutableString *str = [NSMutableString stringWithCapacity:64];
419 //[str appendString:[super associationDescription]];
421 if (self->action) [str appendFormat:@" action=%@", self->action];
422 if (self->href) [str appendFormat:@" href=%@", self->href];
423 if (self->pageName) [str appendFormat:@" page=%@", self->pageName];
425 if (self->actionClass)
426 [str appendFormat:@" actionClass=%@", self->actionClass];
427 if (self->directActionName)
428 [str appendFormat:@" directAction=%@", self->directActionName];
430 [str appendFormat:@" template=%@", self->template];