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 "UIxTabView.h"
25 #import <NGObjWeb/NGObjWeb.h>
26 #import <NGExtensions/NGExtensions.h>
27 #import <EOControl/EOControl.h>
28 #include <WEExtensions/WEClientCapabilities.h>
31 // # define DEBUG_TAKEVALUES 1
36 NSString *UIxTabView_HEAD = @"UIxTabView_head";
37 NSString *UIxTabView_BODY = @"UIxTabView_body";
38 NSString *UIxTabView_KEYS = @"UIxTabView_keys";
39 NSString *UIxTabView_SCRIPT = @"UIxTabView_script";
40 NSString *UIxTabView_ACTIVEKEY = @"UIxTabView_activekey";
41 NSString *UIxTabView_COLLECT = @"~tv~";
43 @implementation UIxTabView
45 static NSNumber *YesNumber;
49 YesNumber = [[NSNumber numberWithBool:YES] retain];
53 return [super version] + 0;
56 - (id)initWithName:(NSString *)_name
57 associations:(NSDictionary *)_config
58 template:(WOElement *)_subs
60 if ((self = [super initWithName:_name associations:_config template:_subs])) {
61 self->selection = WOExtGetProperty(_config, @"selection");
63 self->headerStyle = WOExtGetProperty(_config, @"headerStyle");
64 self->bodyStyle = WOExtGetProperty(_config, @"bodyStyle");
65 self->tabStyle = WOExtGetProperty(_config, @"tabStyle");
66 self->selectedTabStyle = WOExtGetProperty(_config, @"selectedTabStyle");
68 self->bgColor = WOExtGetProperty(_config, @"bgColor");
69 self->nonSelectedBgColor = WOExtGetProperty(_config, @"nonSelectedBgColor");
70 self->leftCornerIcon = WOExtGetProperty(_config, @"leftCornerIcon");
71 self->rightCornerIcon = WOExtGetProperty(_config, @"rightCornerIcon");
73 self->tabIcon = WOExtGetProperty(_config, @"tabIcon");
74 self->leftTabIcon = WOExtGetProperty(_config, @"leftTabIcon");
75 self->selectedTabIcon = WOExtGetProperty(_config, @"selectedTabIcon");
77 self->asBackground = WOExtGetProperty(_config, @"asBackground");
78 self->width = WOExtGetProperty(_config, @"width");
79 self->height = WOExtGetProperty(_config, @"height");
80 self->activeBgColor = WOExtGetProperty(_config, @"activeBgColor");
81 self->inactiveBgColor = WOExtGetProperty(_config, @"inactiveBgColor");
83 self->fontColor = WOExtGetProperty(_config, @"fontColor");
84 self->fontSize = WOExtGetProperty(_config, @"fontSize");
85 self->fontFace = WOExtGetProperty(_config, @"fontFace");
87 self->template = RETAIN(_subs);
93 [self->selection release];
95 [self->headerStyle release];
96 [self->bodyStyle release];
97 [self->tabStyle release];
98 [self->selectedTabStyle release];
100 RELEASE(self->bgColor);
101 RELEASE(self->nonSelectedBgColor);
102 RELEASE(self->leftCornerIcon);
103 RELEASE(self->rightCornerIcon);
105 RELEASE(self->leftTabIcon);
106 RELEASE(self->selectedTabIcon);
107 RELEASE(self->tabIcon);
109 RELEASE(self->width);
110 RELEASE(self->height);
112 RELEASE(self->activeBgColor);
113 RELEASE(self->inactiveBgColor);
115 RELEASE(self->fontColor);
116 RELEASE(self->fontSize);
117 RELEASE(self->fontFace);
119 RELEASE(self->template);
125 - (id)saveNestedStateInContext:(WOContext *)_ctx {
128 - (void)restoreNestedState:(id)_state inContext:(WOContext *)_ctx {
129 if (_state == nil) return;
132 - (NSArray *)collectKeysInContext:(WOContext *)_ctx {
133 /* collect mode, collects all keys */
134 [_ctx setObject:UIxTabView_COLLECT forKey:UIxTabView_HEAD];
136 [self->template appendToResponse:nil inContext:_ctx];
138 [_ctx removeObjectForKey:UIxTabView_HEAD];
139 return [_ctx objectForKey:UIxTabView_KEYS];
144 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
146 NSString *activeTabKey;
148 activeTabKey = [self->selection stringValueInComponent:[_ctx component]];
149 NSLog(@"%s activeTabKey:%@", __PRETTY_FUNCTION__, activeTabKey);
150 nestedState = [self saveNestedStateInContext:_ctx];
151 [_ctx appendElementIDComponent:@"b"];
152 [_ctx appendElementIDComponent:activeTabKey];
154 [_ctx setObject:activeTabKey forKey:UIxTabView_BODY];
157 [[_ctx component] debugWithFormat:@"UIxTabView: body takes values, eid='%@'",
161 [self->template takeValuesFromRequest:_req inContext:_ctx];
163 [_ctx removeObjectForKey:UIxTabView_BODY];
164 [_ctx deleteLastElementIDComponent]; // activeKey
165 [_ctx deleteLastElementIDComponent]; /* 'b' */
166 [self restoreNestedState:nestedState inContext:_ctx];
169 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
174 if ((key = [_ctx currentElementID]) == nil)
178 nestedState = [self saveNestedStateInContext:_ctx];
180 if ([key isEqualToString:@"h"]) {
184 [_ctx consumeElementID];
185 [_ctx appendElementIDComponent:@"h"];
187 if ((urlKey = [_ctx currentElementID]) == nil) {
189 debugWithFormat:@"missing active head tab key !"];
192 //NSLog(@"clicked: %@", urlKey);
193 [_ctx consumeElementID];
194 [_ctx appendElementIDComponent:urlKey];
198 [_ctx setObject:self->selection forKey:UIxTabView_HEAD];
199 result = [self->template invokeActionForRequest:_req inContext:_ctx];
200 [_ctx removeObjectForKey:UIxTabView_HEAD];
204 [_ctx deleteLastElementIDComponent]; // active key
206 [_ctx deleteLastElementIDComponent]; // 'h'
208 else if ([key isEqualToString:@"b"]) {
210 NSString *activeTabKey, *urlKey;
212 [_ctx consumeElementID];
213 [_ctx appendElementIDComponent:@"b"];
215 if ((urlKey = [_ctx currentElementID]) == nil) {
217 debugWithFormat:@"missing active body tab key !"];
220 //NSLog(@"clicked: %@", urlKey);
221 [_ctx consumeElementID];
222 [_ctx appendElementIDComponent:urlKey];
225 activeTabKey = [self->selection stringValueInComponent:[_ctx component]];
226 [_ctx setObject:activeTabKey forKey:UIxTabView_BODY];
228 result = [self->template invokeActionForRequest:_req inContext:_ctx];
230 [_ctx removeObjectForKey:UIxTabView_BODY];
233 [_ctx deleteLastElementIDComponent]; // active key
234 [_ctx deleteLastElementIDComponent]; // 'b'
238 debugWithFormat:@"unknown tab container key '%@'", key];
241 [self restoreNestedState:nestedState inContext:_ctx];
245 - (NSString *)_tabViewCountInContext:(WOContext *)_ctx {
247 count = [[_ctx valueForKey:@"UIxTabViewScriptDone"] intValue];
248 return [NSString stringWithFormat:@"%d",count];
251 - (NSString *)scriptHref:(UIxTabItemInfo *)_info
252 inContext:(WOContext *)_ctx
254 keys:(NSArray *)_keys
256 NSMutableString *result = [NSMutableString string];
263 activeKey = [self->selection stringValueInComponent:[_ctx component]];
264 [result appendString:@"JavaScript:showTab("];
265 [result appendString:_info->key];
266 [result appendString:@"Tab);"];
268 [result appendString:@"swapCorners("];
270 ? @"tabCorner%@,tabCornerLeft%@);"
271 : @"tabCornerLeft%@,tabCorner%@);";
272 elID = [self _tabViewCountInContext:_ctx];
273 [result appendString:[NSString stringWithFormat:tstring,elID,elID]];
275 for (i=0, cnt = [_keys count]; i < cnt; i++) {
276 tmp = [_keys objectAtIndex:i];
278 if ((tmp->isScript || [tmp->key isEqualToString:activeKey])
279 && ![tmp->key isEqualToString:_info->key]) {
280 [result appendString:@"hideTab("];
281 [result appendString:tmp->key];
282 [result appendString:@"Tab);"];
288 - (void)appendLink:(UIxTabItemInfo *)_info
289 toResponse:(WOResponse *)_response
290 inContext:(WOContext *)_ctx
291 isActive:(BOOL)_isActive isLeft:(BOOL)_isLeft
292 doScript:(BOOL)_doScript keys:(NSArray *)_keys
294 NSString *headUri = nil;
295 NSString *label = nil;
296 NSString *scriptHref = nil;
297 NSString *styleName = nil;
299 WEClientCapabilities *ccaps;
302 ccaps = [[_ctx request] clientCapabilities];
304 comp = [_ctx component];
305 headUri = _info->uri;
307 if ((label = _info->label) == nil)
311 styleName = (_info->selectedTabStyle)
312 ? _info->selectedTabStyle
313 : [self->selectedTabStyle stringValueInComponent:comp];
316 styleName = (_info->tabStyle)
318 : [self->tabStyle stringValueInComponent:comp];
321 [_response appendContentString:@"<td align='center' valign='middle'"];
324 [_response appendContentString:@" class='"];
325 [_response appendContentHTMLAttributeValue:styleName];
326 [_response appendContentCharacter:'\''];
329 // click on td background
330 if ([ccaps isInternetExplorer] && [ccaps isJavaScriptBrowser]) {
331 [_response appendContentString:@" onclick=\"window.location.href='"];
332 [_response appendContentHTMLAttributeValue:headUri];
333 [_response appendContentString:@"'\""];
336 [_response appendContentCharacter:'>'];
338 [_response appendContentString:@"<a href=\""];
340 if (_doScript && (_info->isScript || _isActive)) {
342 [self scriptHref:_info inContext:_ctx isLeft:_isLeft keys:_keys];
343 [_response appendContentHTMLAttributeValue:scriptHref];
346 [_response appendContentHTMLAttributeValue:headUri];
349 [_response appendContentString:@"\" "];
350 [_response appendContentString:
351 [NSString stringWithFormat:@"name='%@TabLink'", _info->key]];
352 [_response appendContentString:@">"];
354 if ([label length] < 1)
356 [_response appendContentString:@"<nobr>"];
357 [_response appendContentHTMLString:label];
358 [_response appendContentString:@"</nobr>"];
360 [_response appendContentString:@"</a>"];
362 [_response appendContentString:@"</td>"];
365 if (_doScript && (_info->isScript || _isActive)) {
367 NSString *s; // selected tab icon
368 NSString *u; // unselected tab icon
372 s = _info->selIcon; // selectedTabIcon
373 u = (_isLeft) ? _info->leftIcon : _info->tabIcon;
375 s = WEUriOfResource(s, _ctx);
376 u = WEUriOfResource(u, _ctx);
378 s = ([s length] < 1) ? imgUri : s;
379 u = ([u length] < 1) ? imgUri : u;
382 out = [NSString alloc];
383 out = [out initWithFormat:
384 @"<script language=\"JavaScript\">\n"
386 @"var %@Tab = new Array();\n"
387 @"%@Tab[\"link\"] = %@TabLink;\n"
388 @"%@Tab[\"href1\"] = \"%@\";\n"
389 @"%@Tab[\"href2\"] = \"%@\";\n"
390 @"%@Tab[\"Img\"] = window.document.%@TabImg;\n"
391 @"%@Tab[\"Ar\"] = new Array();\n"
392 @"%@Tab[\"Ar\"][0] = new Image();\n"
393 @"%@Tab[\"Ar\"][0].src = \"%@\";\n"
394 @"%@Tab[\"Ar\"][1] = new Image();\n"
395 @"%@Tab[\"Ar\"][1].src = \"%@\";\n"
397 k, k, k, k, scriptHref, k, headUri,
402 [_response appendContentString:out];
405 # define _appendStr_(_str_) [_response appendContentString:_str_]
406 _appendStr_(@"<script language=\"JavaScript\">\n<!--\nvar ");
407 _appendStr_(k); _appendStr_(@"Tab = new Array();\n");
409 _appendStr_(k); _appendStr_(@"Tab[\"link\"] = ");
410 _appendStr_(k); _appendStr_(@"TabLink;\n"); // linkName
412 _appendStr_(k); _appendStr_(@"Tab[\"href1\"] = \"");
413 _appendStr_(scriptHref); _appendStr_(@"\";\n"); // scriptHref
415 _appendStr_(k); _appendStr_(@"Tab[\"href2\"] = \"");
416 _appendStr_(_info->uri); _appendStr_(@"\";\n"); // actionHref
418 _appendStr_(k); _appendStr_(@"Tab[\"Img\"] = window.document.");
419 _appendStr_(k); _appendStr_(@"TabImg;\n");
420 _appendStr_(k); _appendStr_(@"Tab[\"Ar\"] = new Array();\n");
421 _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][0] = new Image();\n");
422 _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][0].src = \"");
423 _appendStr_(u); _appendStr_(@"\";\n"); // unselected img
424 _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][1] = new Image();\n");
425 _appendStr_(k); _appendStr_(@"Tab[\"Ar\"][1].src = \"");
426 _appendStr_(s); _appendStr_(@"\";\n"); // selected img
427 _appendStr_(@"//-->\n</script>");
434 - (void)appendSubmitButton:(UIxTabItemInfo *)_info
435 toResponse:(WOResponse *)_response
436 inContext:(WOContext *)_ctx
437 isActive:(BOOL)_isActive isLeft:(BOOL)_left
438 doScript:(BOOL)_doScript keys:(NSArray *)_keys
440 [self appendLink:_info
443 isActive:_isActive isLeft:_left
444 doScript:_doScript keys:_keys];
447 - (void)_appendTabViewJSScriptToResponse:(WOResponse *)_response
448 inContext:(WOContext *)_ctx
450 [_response appendContentString:
451 @"<script language=\"JavaScript\">\n<!--\n\n"
452 @"function showTab(obj) {\n"
454 @" if (obj==null) { alert('missing tab obj ..'); return; }\n"
455 @" if (obj['Div']==null) {"
456 @" alert('missing div key in ' + obj); return; }\n"
457 @" if (obj['Div'].style==null) {"
458 @" alert('missing style key in div ' + obj['Div']);return; }\n"
460 @" obj['Div'].style.display = \"\";\n"
461 @" obj['Img'].src = obj[\"Ar\"][1].src;\n"
462 @" obj['link'].href = obj[\"href2\"];\n"
464 @"function hideTab(obj) {\n"
466 @" if (obj==null) { alert('missing tab obj ..'); return; }\n"
467 @" if (obj['Div']==null) {"
468 @" alert('missing div key in ' + obj); return; }\n"
469 @" if (obj['Div'].style==null) {"
470 @" alert('missing style key in div ' + obj['Div']);return; }\n"
472 @" obj['Div'].style.display = \"none\";\n"
473 @" obj['Img'].src = obj[\"Ar\"][0].src;\n"
474 @" obj['link'].href = obj[\"href1\"];\n"
476 @"function swapCorners(obj1,obj2) {\n"
477 @" if (obj1==null) { alert('missing corner 1'); return; }\n"
478 @" if (obj2==null) { alert('missing corner 2'); return; }\n"
479 @" obj1.style.display = \"none\";\n"
480 @" obj2.style.display = \"\";\n"
482 @"//-->\n</script>"];
485 - (void)_appendHeaderRowToResponse:(WOResponse *)_response
486 inContext:(WOContext *)_ctx
487 keys:(NSArray *)keys activeKey:(NSString *)activeKey
488 doScript:(BOOL)doScript
494 doForm = NO; /* generate form controls ? */
496 [_response appendContentString:@"<tr><td colspan='2'>"];
498 styleName = [self->headerStyle stringValueInComponent:[_ctx component]];
500 [_response appendContentString:
501 @"<table border='0' cellpadding='0' cellspacing='0' class='"];
502 [_response appendContentHTMLAttributeValue:styleName];
503 [_response appendContentString:@"'><tr>"];
506 [_response appendContentString:
507 @"<table border='0' cellpadding='0' cellspacing='0'><tr>"];
510 for (i = 0, count = [keys count]; i < count; i++) {
511 UIxTabItemInfo *info;
515 info = [keys objectAtIndex:i];
517 isActive = [key isEqualToString:activeKey];
519 [_ctx appendElementIDComponent:key];
522 /* tab is inside of a FORM, so produce submit buttons */
523 [self appendSubmitButton:info
527 isLeft:(i == 0) ? YES : NO
532 /* tab is not in a FORM, generate hyperlinks for tab */
533 [self appendLink:info
537 isLeft:(i == 0) ? YES : NO
542 [_ctx deleteLastElementIDComponent];
544 // [_response appendContentString:@"<td></td>"];
545 [_response appendContentString:@"</tr></table>"];
546 [_response appendContentString:@"</td></tr>"];
549 - (void)_appendHeaderFootRowToResponse:(WOResponse *)_response
550 inContext:(WOContext *)_ctx
551 bgcolor:(NSString *)bgcolor
552 doScript:(BOOL)doScript
553 isLeftActive:(BOOL)isLeftActive
556 [_response appendContentString:@" <tr"];
558 styleName = [self->bodyStyle stringValueInComponent:[_ctx component]];
560 [_response appendContentString:@" class='"];
561 [_response appendContentHTMLAttributeValue:styleName];
562 [_response appendContentCharacter:'\''];
565 [_response appendContentString:@" bgcolor=\""];
566 [_response appendContentHTMLAttributeValue:bgcolor];
567 [_response appendContentString:@"\""];
569 [_response appendContentString:@">\n"];
572 [_response appendContentString:@" <td align=\"left\" width=\"10\">"];
575 [_response appendContentString:@"<div id=\"tabCorner"];
576 [_response appendContentString:[self _tabViewCountInContext:_ctx]];
577 [_response appendContentString:@"\" "];
578 [_response appendContentString:@"style=\"display: "];
579 [_response appendContentString:(isLeftActive) ? @"" : @"none"];
580 [_response appendContentString:@";\">"];
581 [_response appendContentString:@" "];
582 [_response appendContentString:@"</div>"];
584 else if (isLeftActive)
585 [_response appendContentString:@" "];
588 [_response appendContentString:@"<div id=\"tabCornerLeft"];
589 [_response appendContentString:[self _tabViewCountInContext:_ctx]];
590 [_response appendContentString:@"\" "];
591 [_response appendContentString:@"style=\"display: "];
592 [_response appendContentString:(!isLeftActive) ? @"visible" : @"none"];
593 [_response appendContentString:@";\">"];
596 if (!isLeftActive || doScript) {
599 uri = [self->leftCornerIcon stringValueInComponent:[_ctx component]];
600 if ((uri = WEUriOfResource(uri, _ctx))) {
601 [_response appendContentString:@"<img border=\"0\" alt=\"\" src=\""];
602 [_response appendContentString:uri];
603 [_response appendContentString:@"\">"];
606 [_response appendContentString:@" "];
609 [_response appendContentString:@"</div>"];
611 [_response appendContentString:@"</td>\n"];
614 [_response appendContentString:@" <td align=\"right\">"];
618 uri = [self->rightCornerIcon stringValueInComponent:[_ctx component]];
619 if ((uri = WEUriOfResource(uri, _ctx))) {
620 [_response appendContentString:@"<img border=\"0\" alt=\"\" src=\""];
621 [_response appendContentString:uri];
622 [_response appendContentString:@"\" />"];
625 [_response appendContentString:@" "];
627 [_response appendContentString:@"</td>\n"];
629 [_response appendContentString:@" </tr>\n"];
632 - (void)_appendBodyRowToResponse:(WOResponse *)_response
633 inContext:(WOContext *)_ctx
634 bgcolor:(NSString *)bgcolor
635 activeKey:(NSString *)activeKey
637 WEClientCapabilities *ccaps;
641 styleName = [self->bodyStyle stringValueInComponent:[_ctx component]];
642 ccaps = [[_ctx request] clientCapabilities];
644 /* put additional padding table into content ??? */
645 indentContent = [ccaps isFastTableBrowser] && ![ccaps isTextModeBrowser];
647 [_response appendContentString:@"<tr"];
649 [_response appendContentString:@" class='"];
650 [_response appendContentHTMLAttributeValue:styleName];
651 [_response appendContentCharacter:'\''];
653 [_response appendContentString:@"><td colspan='2'"];
655 [_response appendContentString:@" bgcolor=\""];
656 [_response appendContentHTMLAttributeValue:bgcolor];
657 [_response appendContentCharacter:'\"'];
659 [_response appendContentCharacter:'>'];
662 /* start padding table */
663 [_response appendContentString:
664 @"<table border='0' width='100%'"
665 @" cellpadding='10' cellspacing='0'>"];
666 [_response appendContentString:@"<tr><td>"];
669 [_ctx appendElementIDComponent:@"b"];
670 [_ctx appendElementIDComponent:activeKey];
672 /* generate currently active body */
674 [_ctx setObject:activeKey forKey:UIxTabView_BODY];
675 [self->template appendToResponse:_response inContext:_ctx];
676 [_ctx removeObjectForKey:UIxTabView_BODY];
679 [_ctx deleteLastElementIDComponent]; // activeKey
680 [_ctx deleteLastElementIDComponent]; // 'b'
683 /* close padding table */
684 [_response appendContentString:@"</td></tr></table>"];
686 [_response appendContentString:@"</td></tr>"];
689 - (BOOL)isLeftActiveInKeys:(NSArray *)keys activeKey:(NSString *)activeKey{
695 for (i = 0, count = [keys count]; i < count; i++) {
696 UIxTabItemInfo *info;
698 info = [keys objectAtIndex:i];
700 if ((i == 0) && [info->key isEqualToString:activeKey])
707 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
715 int tabViewCount; /* used for image id's and writing script once */
717 doScript = NO; /* perform tab-clicks on browser (use javascript) */
718 tabViewCount = [[_ctx valueForKey:@"UIxTabViewScriptDone"] intValue];
719 cmp = [_ctx component];
721 /* check for browser */
723 WEClientCapabilities *ccaps;
724 //BOOL isJavaScriptBrowser;
726 ccaps = [[_ctx request] clientCapabilities];
727 doScript = [ccaps isInternetExplorer] && [ccaps isJavaScriptBrowser];
728 doScript = (doScript &&
730 valueForKey:@"isJavaScriptEnabled"] boolValue]);
733 /* disable javascript */
738 nestedState = [self saveNestedStateInContext:_ctx];
742 activeKey = [self->selection stringValueInComponent:cmp];
744 bgcolor = [self->bgColor stringValueInComponent:cmp];
745 bgcolor = [bgcolor stringValue];
747 [_ctx appendElementIDComponent:@"h"];
749 /* collect & process keys (= available tabs) */
751 keys = [self collectKeysInContext:_ctx];
753 if (![[keys valueForKey:@"key"] containsObject:activeKey])
754 /* selection is not available in keys */
757 if ((activeKey == nil) && ([keys count] > 0)) {
758 /* no or invalid selection, use first key */
759 activeKey = [[keys objectAtIndex:0] key];
760 if ([self->selection isValueSettable])
761 [self->selection setValue:activeKey inComponent:[_ctx component]];
765 doScript = [[keys valueForKey:@"isScript"] containsObject:YesNumber];
766 [_ctx setObject:[NSNumber numberWithBool:doScript]
767 forKey:UIxTabView_SCRIPT];
770 /* start appending */
772 if ((doScript) && (tabViewCount == 0))
773 [self _appendTabViewJSScriptToResponse:_response inContext:_ctx];
775 /* count up for unique tabCorner/tabCornerLeft images */
776 [_ctx takeValue:[NSNumber numberWithInt:(tabViewCount + 1)]
777 forKey:@"UIxTabViewScriptDone"];
779 [_response appendContentString:
780 @"<table border='0' width='100%'"
781 @" cellpadding='0' cellspacing='0'>"];
783 /* find out whether left is active */
785 isLeftActive = [self isLeftActiveInKeys:keys activeKey:activeKey];
787 /* generate header row */
789 [self _appendHeaderRowToResponse:_response inContext:_ctx
790 keys:keys activeKey:activeKey
793 [_ctx deleteLastElementIDComponent]; // 'h' for head
794 [_ctx removeObjectForKey:UIxTabView_HEAD];
797 /* header foot row */
799 [self _appendHeaderFootRowToResponse:_response inContext:_ctx
802 isLeftActive:isLeftActive];
807 [self _appendBodyRowToResponse:_response inContext:_ctx
809 activeKey:activeKey];
813 [_response appendContentString:@"</table>"];
814 [_ctx removeObjectForKey:UIxTabView_ACTIVEKEY];
815 [_ctx removeObjectForKey:UIxTabView_KEYS];
816 [self restoreNestedState:nestedState inContext:_ctx];
819 @end /* UIxTabView */