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
22 #include <NGObjWeb/WODynamicElement.h>
30 - extra attributes are attributes of the <table> tag
33 @interface WEBrowser : WODynamicElement
38 WOAssociation *sublist;
39 WOAssociation *currentPath;
42 WOAssociation *bgColor;
43 WOAssociation *height;
44 WOAssociation *columnWidth;
50 #include <NGObjWeb/WEClientCapabilities.h>
53 static NSString *WEBrowser_Plus = @"WEBrowser_Plus";
54 static NSString *WEBrowser_Minus = @"WEBrowser_Minus";
56 @implementation WEBrowser
59 static NSString *retStrForInt(int i) {
60 return [[NSString alloc] initWithFormat:@"%i", i];
65 _applyPath(WEBrowser *self, NSArray *path, WOComponent *cmp) {
66 [self->currentPath setValue:path inComponent:cmp];
67 [self->item setValue:[path lastObject] inComponent:cmp];
71 _applyPathAppenedByItem(WEBrowser *self, NSArray *path, id obj, id cmp) {
72 [self->currentPath setValue:[path arrayByAddingObject:obj] inComponent:cmp];
73 [self->item setValue:obj inComponent:cmp];
76 - (id)initWithName:(NSString *)_name
77 associations:(NSDictionary *)_config
78 template:(WOElement *)_root
80 if ((self=[super initWithName:_name associations:_config template:_root])) {
81 self->list = WOExtGetProperty(_config, @"list");
82 self->item = WOExtGetProperty(_config, @"item");
83 self->sublist = WOExtGetProperty(_config, @"sublist");
84 self->currentPath = WOExtGetProperty(_config, @"currentPath");
87 self->bgColor = WOExtGetProperty(_config, @"bgColor");
88 self->height = WOExtGetProperty(_config, @"height");
89 self->columnWidth = WOExtGetProperty(_config, @"columnWidth");
91 self->template = [_root retain];
99 [self->sublist release];
100 [self->currentPath release];
102 [self->columnWidth release];
103 [self->bgColor release];
104 [self->height release];
106 [self->template release];
110 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
112 [self->template takeValuesFromRequest:_req inContext:_ctx];
116 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
118 NSMutableArray *stack;
127 cmp = [_ctx component];
128 selects = [self->currentPath valueInComponent:cmp];
130 cid = [_ctx currentElementID];
132 if ([cid isEqualToString:@"scroll"]) {
135 [_ctx appendElementIDComponent:cid]; // append scroll
136 cid = [_ctx consumeElementID]; // get currentPath index (=column)
137 col = [cid intValue]; //
138 [_ctx appendElementIDComponent:cid]; // append column
139 cid = [_ctx consumeElementID]; // get row
140 row = [cid intValue];
141 [_ctx appendElementIDComponent:cid]; // append row
142 cid = [_ctx consumeElementID]; // get plus or minus action or else
145 cid = [_ctx currentElementID]; // get row
146 row = [cid intValue];
147 [_ctx appendElementIDComponent:cid]; // append row
148 cid = [_ctx consumeElementID]; // get currentPath index (=column)
149 col = [cid intValue];
150 [_ctx appendElementIDComponent:cid]; // append index
151 cid = [_ctx consumeElementID]; // get plus or minus action or else
154 stack = [NSMutableArray arrayWithArray:
155 [selects subarrayWithRange:NSMakeRange(0, col)]];
157 if ([cid isEqual:WEBrowser_Minus]) {
158 // last object of current path is the clicked one
159 if (col < (int)[selects count]) {
160 [self->currentPath setValue:stack inComponent:cmp];
161 [self->item setValue:[stack lastObject] inComponent:cmp];
167 // prepare for getting the clicked object
169 subarray = [self->list valueInComponent:cmp];
171 obj = [selects objectAtIndex:col-1];
172 [self->item setValue:obj inComponent:cmp];
173 [self->currentPath setValue:stack inComponent:cmp];
175 subarray = [self->sublist valueInComponent:cmp];
177 // get clicked object and update currentPath (=stack)
178 if (row < (int)[subarray count]) {
179 obj = [subarray objectAtIndex:row];
180 [stack addObject:obj];
183 [self->currentPath setValue:stack inComponent:cmp];
184 [self->item setValue:obj inComponent:cmp];
186 if ([cid isEqual:WEBrowser_Plus])
189 result = [self->template invokeActionForRequest:_req inContext:_ctx];
191 [_ctx deleteLastElementIDComponent]; // delete row
192 [_ctx deleteLastElementIDComponent]; // delete index
197 - (BOOL)_useScrollingInContext:(WOContext *)_ctx {
198 return [[[_ctx request] clientCapabilities] doesSupportCSSOverflow];
201 - (void)appendWithScrolling:(WOResponse *)_resp inContext:(WOContext *)_ctx {
202 WOComponent *cmp = nil;
203 NSArray *selects = nil;
205 int columns, cnt, i, j;
208 useScrolling = [self _useScrollingInContext:_ctx];
210 cmp = [_ctx component];
212 if ((selects = [[self->currentPath valueInComponent:cmp] copy]) == nil) {
213 selects = [[NSArray alloc] init];
214 [self->currentPath setValue:selects inComponent:cmp];
217 columns = [selects count] + 1;
219 [_resp appendContentString:@"<table"];
220 [self appendExtraAttributesToResponse:_resp inContext:_ctx];
221 [_resp appendContentString:@">"];
223 [_resp appendContentString:@"<tr>"];
225 [_ctx appendElementIDComponent:@"scroll"]; // scroll - mode
227 [_ctx appendZeroElementIDComponent];
228 for (i=0; i < columns; i++) {
231 path = [selects subarrayWithRange:NSMakeRange(0, i)];
232 _applyPath(self, path, cmp);
235 ? [self->list valueInComponent:cmp]
236 : [self->sublist valueInComponent:cmp];
240 [_resp appendContentString:@"<td valign=\"top\""];
241 if (self->columnWidth) {
242 [_resp appendContentString:@" width=\""];
243 [_resp appendContentHTMLAttributeValue:
244 [self->columnWidth stringValueInComponent:cmp]];
245 [_resp appendContentString:@"\""];
247 [_resp appendContentCharacter:'>'];
248 if (self->height && useScrolling) {
249 [_resp appendContentString:@"<p style=\"width:100%; height="];
250 [_resp appendContentString:[self->height stringValueInComponent:cmp]];
251 [_resp appendContentString:@"; overflow-y: auto;\">"];
253 [_resp appendContentString:
254 @"<table width=\"100%\" border=\"0\" "
255 @"cellspacing=\"0\" cellpadding=\"2\">"];
257 [_ctx appendZeroElementIDComponent];
258 for (j = 0; j < cnt; j++) {
262 obj = [array objectAtIndex:j];
263 _applyPathAppenedByItem(self, path, obj, cmp);
264 bg = [self->bgColor stringValueInComponent:cmp];
266 [_resp appendContentString:@"<tr><td valign=\"center\""];
268 [_resp appendContentString:@" bgcolor=\""];
269 [_resp appendContentHTMLAttributeValue:bg];
270 [_resp appendContentCharacter:'"'];
272 [_resp appendContentString:@">"];
275 // named ankers for 'jump-to' functionality
276 [_resp appendContentString:@"<a name=\""];
278 [_resp appendContentString:s];
280 [_resp appendContentString:@"\">"];
282 [_resp appendContentString:s];
284 [_resp appendContentString:@"</a>"];
287 [self->template appendToResponse:_resp inContext:_ctx];
289 [_resp appendContentString:@"</td></tr>"];
290 [_ctx incrementLastElementIDComponent];
292 [_ctx deleteLastElementIDComponent];
294 [_resp appendContentString:@"</table>"];
295 if (self->height && useScrolling)
296 [_resp appendContentString:@"</p>"];
297 [_resp appendContentString:@"</td>"];
299 [_ctx incrementLastElementIDComponent];
301 [_ctx deleteLastElementIDComponent];
302 [_resp appendContentString:@"</tr></table>"];
304 [_ctx deleteLastElementIDComponent]; // delete scroll-mode
306 [self->currentPath setValue:selects inComponent:cmp];
308 [selects release]; selects = nil;
311 - (void)appendWithoutScrolling:(WOResponse *)_resp inContext:(WOContext *)_ctx {
312 WOComponent *cmp = nil;
313 NSArray *selects = nil;
314 NSArray *array = nil;
315 NSMutableArray *path = nil;
317 int selectCnt, cnt, i, j;
319 NSAssert(self->currentPath,
320 @"WEBrowser: missing 'currentPath' association!");
322 cmp = [_ctx component];
323 array = [self->list valueInComponent:cmp];
324 selects = [[self->currentPath valueInComponent:cmp] copy];
327 selectCnt = [selects count] + 1;
328 path = [NSMutableArray arrayWithCapacity:selectCnt];
330 [_resp appendContentString:@"<table"];
331 [self appendExtraAttributesToResponse:_resp inContext:_ctx];
332 [_resp appendContentString:@">"];
334 [_ctx appendZeroElementIDComponent];
335 for (i = 0; i < cnt; i++) {
336 [_resp appendContentString:@"<tr>"];
338 [_ctx appendZeroElementIDComponent];
340 for (j = 0; j < selectCnt; j++) {
344 [path removeAllObjects];
345 [path addObjectsFromArray:
346 [selects subarrayWithRange:NSMakeRange(0, j)]];
354 obj = [selects objectAtIndex:j-1];
355 [self->item setValue:obj inComponent:cmp];
356 [self->currentPath setValue:path inComponent:cmp];
357 subarray = [self->sublist valueInComponent:cmp];
360 subCount = [subarray count];
361 cnt = (subCount > cnt) ? subCount : cnt;
368 obj = [subarray objectAtIndex:i];
369 [self->item setValue:obj inComponent:cmp];
370 // [self->currentPath setValue:path inComponent:cmp];
372 // is current object in currentPath?
374 if ((j < (int)[selects count]) &&
375 [[selects objectAtIndex:j] isEqual:obj]) {
376 k = (j < selectCnt-1)
383 bg = [self->bgColor stringValueInComponent:cmp];
385 WEAppendTD(_resp, nil, nil, bg);
386 [path addObject:obj];
387 [self->currentPath setValue:path inComponent:cmp];
388 [self->template appendToResponse:_resp inContext:_ctx];
389 [_resp appendContentString:@"</td>"];
392 [_resp appendContentString:@"<td colspan=\"2\""];
393 [self->currentPath setValue:nil inComponent:cmp];
394 [self->item setValue:nil inComponent:cmp];
395 bg = [self->bgColor stringValueInComponent:cmp];
397 [_resp appendContentString:@" bgcolor=\""];
398 [_resp appendContentString:bg];
400 [_resp appendContentString:@"\"> </td>"];
402 [_ctx incrementLastElementIDComponent];
404 [_ctx deleteLastElementIDComponent];
405 [_resp appendContentString:@"</tr>"];
406 [_ctx incrementLastElementIDComponent];
408 [_ctx deleteLastElementIDComponent];
409 [_resp appendContentString:@"</table>"];
411 [self->currentPath setValue:selects inComponent:cmp];
415 - (void)appendToResponse:(WOResponse *)_resp inContext:(WOContext *)_ctx {
417 [self appendWithScrolling:_resp inContext:_ctx];
419 if ([self _useScrollingInContext:_ctx])
420 [self appendWithScrolling:_resp inContext:_ctx];
422 [self appendWithoutScrolling:_resp inContext:_ctx];