2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
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
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.
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
23 #include <NGObjWeb/WODynamicElement.h>
27 @interface WECollapsibleComponentContent : WODynamicElement
30 WOAssociation *condition;
31 WOAssociation *visibility;
33 WOAssociation *allowScript; /* perform clicks on browser (use javaScript) */
39 @interface WECollapsibleAction : WODynamicElement
42 WOAssociation *openedImageFileName;
43 WOAssociation *closedImageFileName;
44 WOAssociation *framework;
45 WOAssociation *openedLabel;
46 WOAssociation *closedLabel;
47 WOAssociation *submitActionName;
48 WOAssociation *action; // if submit button, use submitActionName instead
49 WOAssociation *fragmentIdentifier;
50 WOAssociation *isClicked;
56 #include <NGObjWeb/NGObjWeb.h>
57 #include "WEContextConditional.h"
58 #include "WEClientCapabilities.h"
61 static NSString *WECollapsible_TitleMode = @"WECollapsible_TitleMode";
62 static NSString *WECollapsible_ContentMode = @"WECollapsible_ContentMode";
63 static NSString *WECollapsible_IsCollapsed = @"WECollapsible_IsCollapsed";
64 static NSString *WECollapsible_ScriptId = @"WECollapsible_ScriptId";
65 static NSString *WECollapsible_HasScript = @"WECollapsible_HasScript";
66 static NSString *Yes = @"YES";
67 static NSString *No = @"NO";
69 @implementation WECollapsibleComponentContent
71 - (id)initWithName:(NSString *)_name
72 associations:(NSDictionary *)_config
73 template:(WOElement *)_tmp
75 if ((self = [super initWithName:_name associations:_config template:_tmp])) {
76 self->condition = WOExtGetProperty(_config, @"condition");
77 self->visibility = WOExtGetProperty(_config, @"visibility");
78 self->allowScript = WOExtGetProperty(_config, @"allowScript");
80 if (self->visibility == nil)
81 NSLog(@"WARNING: WECollapsibleComponent 'visibility' not set");
83 if (self->visibility && ![self->visibility isValueSettable])
84 NSLog(@"WARNING: WECollapsibleComponent 'visibility' is not settable");
86 self->template = [_tmp retain];
92 [self->condition release];
93 [self->visibility release];
94 [self->allowScript release];
95 [self->template release];
101 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
104 isCollapsed = ![self->visibility boolValueInComponent:[_ctx component]];
108 [_ctx setObject:Yes forKey:WECollapsible_ContentMode];
109 [self->template takeValuesFromRequest:_req inContext:_ctx];
110 [_ctx removeObjectForKey:WECollapsible_ContentMode];
114 [_ctx setObject:Yes forKey:WECollapsible_TitleMode];
116 [self->template takeValuesFromRequest:_req inContext:_ctx];
118 [_ctx removeObjectForKey:WECollapsible_TitleMode];
121 - (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
125 isCollapsed = ![self->visibility boolValueInComponent:[_ctx component]];
128 [_ctx setObject:Yes forKey:WECollapsible_TitleMode];
129 [_ctx setObject:Yes forKey:WECollapsible_ContentMode];
130 [_ctx setObject:(isCollapsed) ? Yes : No forKey:WECollapsible_IsCollapsed];
132 result = [self->template invokeActionForRequest:_request inContext:_ctx];
133 isCollapsed = [[_ctx objectForKey:WECollapsible_IsCollapsed] boolValue];
135 if ([self->visibility isValueSettable])
136 [self->visibility setBoolValue:!isCollapsed inComponent:[_ctx component]];
138 [_ctx removeObjectForKey:WECollapsible_IsCollapsed];
139 [_ctx removeObjectForKey:WECollapsible_ContentMode];
140 [_ctx removeObjectForKey:WECollapsible_TitleMode];
145 - (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
151 comp = [_ctx component];
152 doScript = [self->allowScript boolValueInComponent:comp];
153 scriptId = [[[_ctx elementID] componentsSeparatedByString:@"."]
154 componentsJoinedByString:@"_"];
157 WEClientCapabilities *ccaps;
159 ccaps = [[_ctx request] clientCapabilities];
160 doScript = [ccaps isInternetExplorer];
164 [_ctx setObject:scriptId forKey:WECollapsible_ScriptId];
166 if ([self->visibility valueInComponent:comp] == nil) {
167 isCollapsed = ![self->condition boolValueInComponent:comp];
168 if ([self->visibility isValueSettable])
169 [self->visibility setBoolValue:!isCollapsed inComponent:comp];
172 isCollapsed = ![self->visibility boolValueInComponent:comp];
175 [_ctx setObject:Yes forKey:WECollapsible_TitleMode];
176 [_ctx setObject:(isCollapsed) ? Yes : No forKey:WECollapsible_IsCollapsed];
178 [self->template appendToResponse:_resp inContext:_ctx];
180 [_ctx removeObjectForKey:WECollapsible_IsCollapsed];
181 [_ctx removeObjectForKey:WECollapsible_TitleMode];
184 if (!isCollapsed || doScript) {
185 [_ctx setObject:Yes forKey:WECollapsible_ContentMode];
187 [_resp appendContentString:@"<div class=\"collapsible\" "];
188 [_resp appendContentString:@"id=\"collapsible"];
189 [_resp appendContentString:scriptId];
190 [_resp appendContentString:@"\" style=\"display:"];
191 [_resp appendContentString:(isCollapsed) ? @"none" : @"block"];
192 [_resp appendContentString:@";\">"];
195 [self->template appendToResponse:_resp inContext:_ctx];
198 [_resp appendContentString:@"</div>"];
199 [_ctx removeObjectForKey:WECollapsible_ContentMode];
201 [_ctx removeObjectForKey:WECollapsible_ScriptId];
203 @end /* WECollapsibleComponentContent */
205 @implementation WECollapsibleAction
207 - (id)initWithName:(NSString *)_name
208 associations:(NSDictionary *)_config
209 template:(WOElement *)_temp
211 if ((self = [super initWithName:_name associations:_config template:_temp])) {
212 self->openedImageFileName = WOExtGetProperty(_config, @"openedImageFileName");
213 self->closedImageFileName = WOExtGetProperty(_config, @"closedImageFileName");
214 self->framework = WOExtGetProperty(_config, @"framework");
215 self->openedLabel = WOExtGetProperty(_config, @"openedLabel");
216 self->closedLabel = WOExtGetProperty(_config, @"closedLabel");
217 self->submitActionName = WOExtGetProperty(_config, @"submitActionName");
218 self->action = WOExtGetProperty(_config, @"action");
219 self->fragmentIdentifier = WOExtGetProperty(_config, @"fragmentIdentifier");
220 self->isClicked = WOExtGetProperty(_config, @"isClicked");
222 self->template = [_temp retain];
228 [self->openedImageFileName release];
229 [self->closedImageFileName release];
230 [self->framework release];
231 [self->openedLabel release];
232 [self->closedLabel release];
233 [self->submitActionName release];
234 [self->action release];
235 [self->fragmentIdentifier release];
236 [self->isClicked release];
237 [self->template release];
243 - (void)takeValuesFromRequest:(WORequest *)_request
244 inContext:(WOContext *)_ctx
248 eid = [_ctx elementID];
250 if ([_request formValueForKey:[eid stringByAppendingString:@".c.x"]]) {
251 [_ctx addActiveFormElement:self];
252 [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".c"]];
254 else if ([_request formValueForKey:[eid stringByAppendingString:@".e.x"]]) {
255 [_ctx addActiveFormElement:self];
256 [_ctx setRequestSenderID:[[_ctx senderID] stringByAppendingString:@".e"]];
260 - (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
264 state = [[_ctx currentElementID] stringValue];
266 doForm = ([_ctx isInForm] && self->submitActionName &&
267 ([self->submitActionName valueInComponent:[_ctx component]]));
269 [_ctx consumeElementID]; // consume state-id
271 if ([state isEqualToString:@"e"]) {
272 [_ctx setObject:[NSNumber numberWithBool:YES]
273 forKey:WECollapsible_IsCollapsed];
276 [self->submitActionName valueInComponent:[_ctx component]];
277 else if ([self->action valueInComponent:[_ctx component]] != nil)
278 [self->action valueInComponent:[_ctx component]];
280 else if ([state isEqualToString:@"c"]) {
281 [_ctx setObject:[NSNumber numberWithBool:NO]
282 forKey:WECollapsible_IsCollapsed];
285 [self->submitActionName valueInComponent:[_ctx component]];
286 else if ([self->action valueInComponent:[_ctx component]] != nil)
287 [self->action valueInComponent:[_ctx component]];
289 if ([self->isClicked isValueSettable])
290 [self->isClicked setBoolValue:YES inComponent:[_ctx component]];
295 - (void)_appendScriptWithID:(NSString *)scriptId
296 label:(NSString *)label imageURL:(NSString *)img
297 toResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx
300 NSString *openedImg = nil;
301 NSString *closedImg = nil;
302 NSString *openLabel = nil;
303 NSString *closeLabel = nil;
305 comp = [_ctx component];
306 closedImg = [self->closedImageFileName stringValueInComponent:comp];
307 openedImg = [self->openedImageFileName stringValueInComponent:comp];
308 openLabel = [self->openedLabel stringValueInComponent:comp];
309 closeLabel = [self->closedLabel stringValueInComponent:comp];
311 closedImg = WEUriOfResource(closedImg, _ctx);
312 openedImg = WEUriOfResource(openedImg, _ctx);
314 if (![_ctx objectForKey:WECollapsible_HasScript]) {
315 [_resp appendContentString:
316 @"\n<script language=\"JavaScript\">\n"
318 @"function toggleColl(el, img1, img2, alt1, alt2)\n"
320 @" whichEl = eval(\"collapsible\" + el);\n"
321 @" whichIm = event.srcElement;\n"
322 @" if (whichEl.style.display == \"none\") {\n"
323 @" whichEl.style.display = \"block\";\n"
324 @" whichIm.src = img1;\n"
325 @" whichIm.alt = alt1;\n"
328 @" whichEl.style.display = \"none\";\n"
329 @" whichIm.src = img2;\n"
330 @" whichIm.alt = alt2;\n"
335 [_ctx setObject:Yes forKey:WECollapsible_HasScript];
338 [_resp appendContentString:@"<a href=\"#\" onclick=\"toggleColl('"];
339 [_resp appendContentString:scriptId];
340 [_resp appendContentString:@"','"];
341 [_resp appendContentHTMLString:openedImg];
342 [_resp appendContentString:@"','"];
343 [_resp appendContentHTMLString:closedImg];
344 [_resp appendContentString:@"','"];
345 [_resp appendContentHTMLString:openLabel];
346 [_resp appendContentString:@"','"];
347 [_resp appendContentHTMLString:closeLabel];
348 [_resp appendContentString:@"'); return false\"><img "];
350 [_resp appendContentString:@"alt=\""];
351 [_resp appendContentString:label];
352 [_resp appendContentString:@"\" title=\""];
353 [_resp appendContentString:label];
354 [_resp appendContentString:@"\" "];
356 [_resp appendContentString:@"border=\"0\" name=\"imEx\" src=\""];
357 [_resp appendContentString:img];
358 [_resp appendContentString:@"\" /></a>"];
361 - (void)_appendLinkWithFragmentID:(NSString *)fragId
362 label:(NSString *)label imageURL:(NSString *)img
363 isCollapsed:(BOOL)isCollapsed
364 toResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx
366 [_resp appendContentString:@"<a href=\""];
367 [_resp appendContentString:[_ctx componentActionURL]];
368 if ([fragId length] > 0) {
369 [_resp appendContentString:@"#"];
370 [_resp appendContentString:fragId];
372 [_resp appendContentString:@"\">"];
375 [_resp appendContentString:@"<img border=\"0\" src=\""];
376 [_resp appendContentString:img];
377 [_resp appendContentString:@"\""];
379 [_resp appendContentString:@" alt=\""];
380 [_resp appendContentString:label];
381 [_resp appendContentString:@"\" title=\""];
382 [_resp appendContentString:label];
383 [_resp appendContentString:@"\""];
385 [_resp appendContentString:@" />"];
388 [_resp appendContentString:(isCollapsed) ? @"[+]" : @"[-]"];
390 [_resp appendContentString:@"</a>"];
393 - (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
394 /* TODO: split up this huge method */
400 NSString *label = nil;
401 NSString *fragId = nil;
402 NSString *scriptId = nil;
404 comp = [_ctx component];
405 fragId = [self->fragmentIdentifier stringValueInComponent:comp];
407 isCollapsed = [[_ctx objectForKey:WECollapsible_IsCollapsed] boolValue];
408 scriptId = [_ctx objectForKey:WECollapsible_ScriptId];
409 doScript = [scriptId length] > 0 ? YES : NO;
412 ? [self->closedImageFileName stringValueInComponent:comp]
413 : [self->openedImageFileName stringValueInComponent:comp];
415 label = (isCollapsed)
416 ? [self->closedLabel stringValueInComponent:comp]
417 : [self->openedLabel stringValueInComponent:comp];
419 img = WEUriOfResource(img, _ctx);
423 [_resp appendContentString:@" "];
426 doForm = ([_ctx isInForm] && self->submitActionName && img);
428 [_ctx appendElementIDComponent:(isCollapsed) ? @"c" : @"e"];
430 [self _appendScriptWithID:scriptId label:label imageURL:img
431 toResponse:_resp inContext:_ctx];
434 [_resp appendContentString:@"<input type=\"image\" border=\"0\" name=\""];
435 [_resp appendContentString:[_ctx elementID]];
436 [_resp appendContentString:@"\" src=\""];
437 [_resp appendContentString:img];
438 [_resp appendContentString:@"\" />"];
441 [self _appendLinkWithFragmentID:fragId label:label imageURL:img
442 isCollapsed:isCollapsed
443 toResponse:_resp inContext:_ctx];
447 WEClientCapabilities *ccaps;
449 ccaps = [[_ctx request] clientCapabilities];
451 [_resp appendContentString:@"<a name=\""];
452 [_resp appendContentString:fragId];
453 [_resp appendContentString:@"\"> </a>"];
454 if ([self->isClicked boolValueInComponent:comp] &&
455 ([ccaps isInternetExplorer] || [ccaps isMozilla] || [ccaps isNetscape6])) {
456 if ([self->isClicked isValueSettable])
457 [self->isClicked setBoolValue:NO inComponent:comp];
459 [_resp appendContentString:
460 [NSString stringWithFormat:
461 @"\n<script language=\"JavaScript\">\n"
463 @" window.location.hash=\"#%@\";\n"
470 [_resp appendContentString:@" "];
472 if (label && !doScript) {
474 [_resp appendContentString:@"<a href=\""];
475 [_resp appendContentString:[_ctx componentActionURL]];
477 [_resp appendContentString:@"#"];
478 [_resp appendContentString:fragId];
480 [_resp appendContentString:@"\">"];
483 [_resp appendContentString:label];
486 [_resp appendContentString:@"</a>"];
488 [_ctx deleteLastElementIDComponent];
491 @end /* WECollapsibleAction */
493 @interface WECollapsibleTitleMode: WEContextConditional
496 @implementation WECollapsibleTitleMode
498 - (NSString *)_contextKey {
499 return WECollapsible_TitleMode;
502 @end /* WECollapsibleTitleMode */
504 @interface WECollapsibleContentMode: WEContextConditional
507 @implementation WECollapsibleContentMode
509 - (NSString *)_contextKey {
510 return WECollapsible_ContentMode;
513 @end /* WECollapsibleContentMode */