1/* 2 Copyright (C) 2000-2005 SKYRIX Software AG 3 4 This file is part of SOPE. 5 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 9 later version. 10 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. 15 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 19 02111-1307, USA. 20*/ 21 22#include "WETableView.h" 23#include "WETableView+Grouping.h" 24#include "WETableViewState.h" 25#include "WETableViewColorConfig.h" 26#include "WETableViewIconConfig.h" 27#include "WETableViewLabelConfig.h" 28 29#include "common.h" 30#include <NGObjWeb/NGObjWeb.h> 31#include <EOControl/EOSortOrdering.h> 32#include "WEContextConditional.h" 33 34@interface WETableView(JavaScriptAdditions) 35 36- (void)_appendGroupCollapseScript:(WOResponse *)_resp 37 inContext:(WOContext *)_ctx; 38- (void)jsButton:(WOResponse *)_resp ctx:(WOContext *)_ctx 39 name:(NSString *)_name button:(NSString *)_button; 40 41- (void)appendJavaScript:(WOResponse *)_resp inContext:(WOContext *)_ctx; 42- (void)_appendTableContentAsScript:(WOResponse *)_resp 43 inContext:(WOContext *)_ctx; 44 45- (void)_appendScriptLink:(WOResponse *)_response name:(NSString *)_name; 46- (void)_appendScriptImgName:(WOResponse *)_response name:(NSString *)_name; 47 48@end 49 50#include <NGObjWeb/WEClientCapabilities.h> 51 52@implementation WETableView 53 54static NSNumber *YesNumber = nil; 55static NSNumber *NoNumber = nil; 56static Class StrClass = Nil; 57static BOOL ShowNavigationAlways = YES; 58static BOOL ShowNavigationInFooter = YES; 59 60+ (void)initialize { 61 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; 62 63 StrClass = [NSString class]; 64 if (YesNumber == nil) YesNumber = [[NSNumber numberWithBool:YES] retain]; 65 if (NoNumber == nil) NoNumber = [[NSNumber numberWithBool:NO] retain]; 66 67 ShowNavigationAlways = [ud boolForKey:@"WETableView_showBlindNavigation"]; 68} 69 70static NSString *retStrForInt(int i) { 71 switch(i) { 72 case 0: return @"0"; 73 case 1: return @"1"; 74 case 2: return @"2"; 75 case 3: return @"3"; 76 case 4: return @"4"; 77 case 5: return @"5"; 78 case 6: return @"6"; 79 case 7: return @"7"; 80 case 8: return @"8"; 81 case 9: return @"9"; 82 case 10: return @"10"; 83 // TODO: find useful count! 84 default: 85 return [[StrClass alloc] initWithFormat:@"%i", i]; 86 } 87} 88 89- (id)initWithName:(NSString *)_name 90 associations:(NSDictionary *)_config 91 template:(WOElement *)_c 92{ 93 if ((self = [super initWithName:_name associations:_config template:_c])) { 94 self->state = [[WETableViewState alloc] init]; 95 96 self->list = WOExtGetProperty(_config, @"list"); 97 self->currentBatch = WOExtGetProperty(_config, @"currentBatch"); 98 self->batchSize = WOExtGetProperty(_config, @"batchSize"); 99 100 self->item = WOExtGetProperty(_config, @"item"); 101 self->index = WOExtGetProperty(_config, @"index"); 102 self->identifier = WOExtGetProperty(_config, @"identifier"); 103 self->previousItem = WOExtGetProperty(_config, @"previousItem"); 104 self->previousIndex = WOExtGetProperty(_config, @"previousIndex"); 105 self->sortedKey = WOExtGetProperty(_config, @"sortedKey"); 106 self->isDescending = WOExtGetProperty(_config, @"isDescending"); 107 self->selection = WOExtGetProperty(_config, @"selection"); 108 self->groups = WOExtGetProperty(_config, @"groups"); 109 self->showGroup = WOExtGetProperty(_config, @"showGroup"); 110 111 // display state 112 self->indexOfFirst = 113 WOExtGetProperty(_config, @"indexOfFirstDisplayedObject"); 114 self->indexOfLast = 115 WOExtGetProperty(_config, @"indexOfLastDisplayedObject"); 116 117 self->collapseOnClient = WOExtGetProperty(_config, @"collapseOnClient"); 118 self->scrollOnClient = WOExtGetProperty(_config, @"scrollOnClient"); 119 self->autoScroll = WOExtGetProperty(_config, @"autoScroll"); 120 self->showBatchResizeButtons = 121 WOExtGetProperty(_config, @"showBatchResizeButtons"); 122 123 // actions 124 self->sortAction = WOExtGetProperty(_config, @"sortAction"); 125 self->firstAction = WOExtGetProperty(_config, @"firstAction"); 126 self->previousAction = WOExtGetProperty(_config, @"previousAction"); 127 self->nextAction = WOExtGetProperty(_config, @"nextAction"); 128 self->lastAction = WOExtGetProperty(_config, @"lastAction"); 129 130 // config stuff: 131 self->colors = 132 [[WETableViewColorConfig alloc] initWithAssociations:_config]; 133 self->groupColor = WOExtGetProperty(_config, @"groupColor"); 134 self->fontColor = WOExtGetProperty(_config, @"fontColor"); 135 self->fontFace = WOExtGetProperty(_config, @"fontFace"); 136 self->fontSize = WOExtGetProperty(_config, @"fontSize"); 137 138 // icons: 139 self->icons = [[WETableViewIconConfig alloc] initWithAssociations:_config]; 140 self->groupOpenedIcon = WOExtGetProperty(_config, @"groupOpenedIcon"); 141 self->groupClosedIcon = WOExtGetProperty(_config, @"groupClosedIcon"); 142 143 // labels: 144 self->labels = 145 [[WETableViewLabelConfig alloc] initWithAssociations:_config]; 146 147 self->cellspacing = WOExtGetProperty(_config, @"cellspacing"); 148 self->cellpadding = WOExtGetProperty(_config, @"cellpadding"); 149 self->border = WOExtGetProperty(_config, @"border"); 150 151 self->showGroupTitle = WOExtGetProperty(_config, @"showGroupTitle"); 152 153#define SetAssociationValue(_a_, _value_) \ 154 if (_a_ == nil) \ 155 _a_ = [[WOAssociation associationWithValue:_value_] retain]; 156 157 SetAssociationValue(self->cellspacing, @"0"); 158 SetAssociationValue(self->cellpadding, @"1"); 159 SetAssociationValue(self->border, @"0"); 160 161#undef SetAssociationValue 162 163 if (self->list == nil) { 164 [self logWithFormat:@"ERROR: no 'list' binding is set!"]; 165 [self release]; 166 return nil; 167 } 168 169 self->state->doScriptScrolling = NO; 170 self->template = [_c retain]; 171 } 172 return self; 173} 174 175- (void)dealloc { 176 [self->state release]; 177 [self->colors release]; 178 [self->labels release]; 179 [self->icons release]; 180 181 [self->list release]; 182 [self->currentBatch release]; 183 [self->batchSize release]; 184 185 [self->item release]; 186 [self->index release]; 187 [self->identifier release]; 188 [self->previousItem release]; 189 [self->previousIndex release]; 190 [self->sortedKey release]; 191 [self->isDescending release]; 192 [self->selection release]; 193 [self->groups release]; 194 [self->showGroup release]; 195 196 [self->indexOfFirst release]; 197 [self->indexOfLast release]; 198 199 [self->collapseOnClient release]; 200 [self->scrollOnClient release]; 201 [self->autoScroll release]; 202 [self->showBatchResizeButtons release]; 203 204 [self->sortAction release]; 205 [self->firstAction release]; 206 [self->previousAction release]; 207 [self->nextAction release]; 208 [self->lastAction release]; 209 210 [self->fontColor release]; 211 [self->fontFace release]; 212 [self->fontSize release]; 213 214 [self->groupColor release]; 215 [self->groupOpenedIcon release]; 216 [self->groupClosedIcon release]; 217 218 [self->allObjects release]; 219 [self->scriptID release]; 220 [self->template release]; 221 222 [self->cellpadding release]; 223 [self->cellspacing release]; 224 [self->border release]; 225 226 [self->showGroupTitle release]; 227 228 [super dealloc]; 229} 230 231static inline void 232_applyIdentifier(WETableView *self, WOComponent *comp, NSString *_idx) 233{ 234 unsigned count; 235 count = [self->allObjects count]; 236 237 if (count > 0) { 238 unsigned i; 239 240 /* find subelement for unique id */ 241 242 for (i = 0; i < count; i++) { 243 NSString *ident; 244 245 if (self->index) 246 [self->index setUnsignedIntValue:i inComponent:comp]; 247 248 if (self->item) { 249 [self->item setValue:[self->allObjects objectAtIndex:i] 250 inComponent:comp]; 251 } 252 if ([self->previousItem isValueSettable]) { 253 [self->previousItem setValue:(i > self->state->firstIndex) 254 ? [self->allObjects objectAtIndex:i-1] : nil 255 inComponent:comp]; 256 } 257 if ([self->previousIndex isValueSettable]) 258 [self->previousIndex setUnsignedIntValue:(i-1) inComponent:comp]; 259 260 ident = [self->identifier stringValueInComponent:comp]; 261 262 if ([ident isEqualToString:_idx]) { 263 /* found subelement with unique id */ 264 return; 265 } 266 } 267 268 [comp logWithFormat: 269 @"WETableView: array did change, " 270 @"unique-id isn't contained."]; 271 [self->item setValue:nil inComponent:comp]; 272 [self->index setUnsignedIntValue:0 inComponent:comp]; 273 } 274} 275 276static inline void _applyItems_(WETableView *self, WOComponent *cmp, int i) { 277 if ([self->index isValueSettable]) 278 [self->index setUnsignedIntValue:i inComponent:cmp]; 279 if ([self->item isValueSettable]) 280 [self->item setValue:[self->allObjects objectAtIndex:i] inComponent:cmp]; 281 if ([self->previousItem isValueSettable]) { 282 id value; 283 284 value = (i > (int)self->state->firstIndex) 285 ? [self->allObjects objectAtIndex:(i - 1)] 286 : nil; 287 [self->previousItem setValue:value inComponent:cmp]; 288 } 289 if ([self->previousIndex isValueSettable]) 290 [self->previousIndex setUnsignedIntValue:(i-1) inComponent:cmp]; 291} 292 293static inline void _applyState_(WETableView *self, WOComponent *cmp) { 294 if ([self->currentBatch isValueSettable]) 295 [self->currentBatch setUnsignedIntValue:self->state->currentBatch 296 inComponent:cmp]; 297} 298 299- (void)updateStateInContext:(WOContext *)_ctx { 300 WEClientCapabilities *ccaps; 301 BOOL isAutoScroll; 302 WOComponent *cmp; 303 NSArray *array; 304 unsigned batchIdx, size, cnt; 305 306 cmp = [_ctx component]; 307 ccaps = [[_ctx request] clientCapabilities]; 308 isAutoScroll = [ccaps doesSupportCSSOverflow]; 309 self->state->doScriptScrolling = [ccaps isInternetExplorer]; 310 self->state->doScriptCollapsing = [ccaps isInternetExplorer]; 311 if (self->state->doScriptCollapsing) { 312 self->state->doScriptCollapsing = 313 [self->collapseOnClient boolValueInComponent:cmp]; 314 } 315 316 if ([[self->autoScroll valueInComponent:cmp] intValue] < 10) 317 isAutoScroll = NO; 318 else if (isAutoScroll) 319 self->state->doScriptScrolling = NO; 320 321 /* use JavaScript on InternetExplorer only */ 322 self->state->doScriptScrolling = (self->state->doScriptScrolling) 323 ? (self->state->batchCount > 1) 324 : NO; 325 326 self->state->doScriptScrolling = (self->state->doScriptScrolling) 327 ? [self->scrollOnClient boolValueInComponent:cmp] 328 : NO; 329 330 array = [self->list valueInComponent:cmp]; 331 batchIdx = [self->currentBatch unsignedIntValueInComponent:cmp]; 332 size = [self->batchSize unsignedIntValueInComponent:cmp]; 333 cnt = [array count]; 334 size = (isAutoScroll) ? cnt : size; 335 batchIdx = (batchIdx) ? batchIdx : 1; 336 batchIdx = ((batchIdx * size) < (cnt+size)) ? batchIdx : 1; 337 338 ASSIGN(self->allObjects, array); 339 340 self->state->currentBatch = batchIdx; 341 self->state->batchSize = size; 342 343 self->state->batchCount = (!size) ? 1 :(cnt / size) + ((cnt % size) ? 1 : 0); 344 self->state->firstIndex = (batchIdx - 1) * size; 345 self->state->lastIndex = 346 (size == 0 || !((self->state->firstIndex+size) < cnt)) 347 ? cnt-1 348 : self->state->firstIndex + size - 1; 349 350 if ([self->indexOfFirst isValueSettable]) { 351 [self->indexOfFirst setUnsignedIntValue:self->state->firstIndex 352 inComponent:cmp]; 353 } 354 355 if ([self->indexOfLast isValueSettable]) { 356 [self->indexOfLast setUnsignedIntValue:self->state->lastIndex 357 inComponent:cmp]; 358 } 359 360 self->state->doCheckBoxes = 361 ([_ctx isInForm] && [self->selection isValueSettable]) ? YES : NO; 362 self->state->doOverflow = isAutoScroll; 363} 364 365- (void)updateScriptIdInContext:(WOContext *)_ctx { 366 NSArray *tmp; 367 NSString *str; 368 369 tmp = [[_ctx elementID] componentsSeparatedByString:@"."]; 370 str = [tmp componentsJoinedByString:@""]; 371 372 ASSIGN(self->scriptID, str); 373} 374 375- (void)updateConfigInContext:(WOContext *)_ctx { 376 WOComponent *cmp; 377 NSString *tmp; 378 379 cmp = [_ctx component]; 380 381 [self->colors updateConfigInContext:_ctx]; 382 [self->icons updateConfigInContext:_ctx]; 383 [self->labels updateConfigInContext:_ctx]; 384 385#define SetConfigInContext(_a_, _key_) \ 386 if (_a_ && (tmp = [_a_ valueInComponent:cmp])) \ 387 [_ctx setObject:tmp forKey:_key_]; \ 388 389 SetConfigInContext(self->fontColor, WETableView_fontColor); 390 SetConfigInContext(self->fontFace, WETableView_fontFace); 391 SetConfigInContext(self->fontSize, WETableView_fontSize); 392#undef SetConfigInContext 393} 394 395- (void)removeConfigInContext:(WOContext *)_ctx { 396 [_ctx removeObjectForKey:WETableView_titleColor]; 397 [_ctx removeObjectForKey:WETableView_headerColor]; 398 [_ctx removeObjectForKey:WETableView_footerColor]; 399 [_ctx removeObjectForKey:WETableView_evenColor]; 400 [_ctx removeObjectForKey:WETableView_oddColor]; 401 [_ctx removeObjectForKey:WETableView_fontColor]; 402 [_ctx removeObjectForKey:WETableView_fontFace]; 403 [_ctx removeObjectForKey:WETableView_fontSize]; 404 405 [_ctx removeObjectForKey:WETableView_downwardIcon]; 406 [_ctx removeObjectForKey:WETableView_upwardIcon]; 407 [_ctx removeObjectForKey:WETableView_nonSortIcon]; 408 409 [_ctx removeObjectForKey:WETableView_first]; 410 [_ctx removeObjectForKey:WETableView_first_blind]; 411 [_ctx removeObjectForKey:WETableView_previous]; 412 [_ctx removeObjectForKey:WETableView_previous_blind]; 413 [_ctx removeObjectForKey:WETableView_next]; 414 [_ctx removeObjectForKey:WETableView_next_blind]; 415 [_ctx removeObjectForKey:WETableView_last]; 416 [_ctx removeObjectForKey:WETableView_last_blind]; 417 [_ctx removeObjectForKey:WETableView_select_all]; 418 [_ctx removeObjectForKey:WETableView_deselect_all]; 419 420 [_ctx removeObjectForKey:WETableView_ofLabel]; 421 [_ctx removeObjectForKey:WETableView_toLabel]; 422 [_ctx removeObjectForKey:WETableView_firstLabel]; 423 [_ctx removeObjectForKey:WETableView_previousLabel]; 424 [_ctx removeObjectForKey:WETableView_nextLabel]; 425 [_ctx removeObjectForKey:WETableView_lastLabel]; 426 [_ctx removeObjectForKey:WETableView_pageLabel]; 427 [_ctx removeObjectForKey:WETableView_sortLabel]; 428} 429 430- (NSArray *)_collectDataInContext:(WOContext *)_ctx 431{ 432 NSAutoreleasePool *pool; 433 NSMutableArray *matrix = nil; 434 NSMutableArray *headInfos = nil; 435 NSString *k = nil; 436 WOComponent *cmp = nil; 437 id oldGroup = nil; 438 int i, first, last; 439 int sortedHeadIndex = -2; 440 441 pool = [[NSAutoreleasePool alloc] init]; 442 cmp = [_ctx component]; 443 k = [self->sortedKey stringValueInComponent:cmp]; 444 445 first = self->state->firstIndex; 446 last = self->state->lastIndex; 447 matrix = [NSMutableArray arrayWithCapacity:last-first+1]; 448 449 [_ctx setObject:YesNumber forKey:WETableView_CollectMode]; 450 [_ctx setObject:k forKey:WETableView_SORTEDKEY]; 451 452 self->state->groupCount = 0; 453 454 for (i=first; i<=last; i++) { 455 NSMutableArray *infos = nil; 456 NSString *tmp = nil; 457 458 _applyItems_(self, cmp, i); 459 460 [_ctx removeObjectForKey:WETableView_INFOS]; 461 [self->template appendToResponse:nil inContext:_ctx]; 462 infos = [_ctx objectForKey:WETableView_INFOS]; 463 464 if (infos == nil) 465 infos = [NSArray array]; 466 467 NSAssert(infos != nil, @"Infos is nil."); 468 469 if (headInfos == nil) { 470 unsigned j, cnt; 471 headInfos = [[NSMutableArray alloc] initWithArray:infos]; 472 473 for (j=0, cnt=[headInfos count]; j<cnt; j++) { 474 WETableViewInfo *headInfo = [headInfos objectAtIndex:j]; 475 476 headInfo->isEven = (((i-first) % 2) == 0) ? YES : NO; 477 } 478 } 479 else { 480 unsigned j, cnt; 481 BOOL isEven = NO; 482 483 cnt = [infos count]; 484 485 if (sortedHeadIndex == -2) { // first time 486 for (j=0; j < cnt; j++) { 487 WETableViewInfo *info; 488 489 info = [infos objectAtIndex:j]; 490 if (info->isSorted) { 491 sortedHeadIndex = j; 492 break; 493 } 494 } 495 sortedHeadIndex = (sortedHeadIndex < 0) ? -1 : sortedHeadIndex; 496 } 497 498 if (cnt) { 499 WETableViewInfo *headInfo; 500 WETableViewInfo *info; 501 502 if (sortedHeadIndex >= 0) { 503 NSAssert(sortedHeadIndex < (int)cnt, 504 @"SortedHeadIndex out of range!!!"); 505 headInfo = [headInfos objectAtIndex:sortedHeadIndex]; 506 info = [infos objectAtIndex:sortedHeadIndex]; 507 isEven = (!info->isGroup) ? !headInfo->isEven : headInfo->isEven; 508 } 509 else { // sortedHeadIndex == -1 --> no column is sorted 510 headInfo = [headInfos lastObject]; 511 isEven = !headInfo->isEven; 512 } 513 } 514 515 for (j = 0; j < cnt; j++) { 516 WETableViewInfo *info = [infos objectAtIndex:j]; 517 WETableViewInfo *headInfo = [headInfos objectAtIndex:j]; 518 519 if (!info->isGroup || ((int)j != sortedHeadIndex)) { 520 info->isEven = isEven; 521 info->isGroup = NO; 522 [headInfos replaceObjectAtIndex:j withObject:info]; 523 } 524 else 525 headInfo->rowSpan++; 526 } 527 } 528 { 529 BOOL doGroupTitle = [self->showGroupTitle boolValueInComponent:cmp]; 530 531 // insert groupMode (to render the group title) 532 tmp = [self->groups valueInComponent:cmp]; 533 if ((tmp != nil) && ![oldGroup isEqual:tmp] && doGroupTitle) { 534 oldGroup = [self->groups valueInComponent:cmp]; 535 self->state->groupCount++; 536 [infos addObject:tmp]; 537 [infos addObject:WETableView_GroupMode]; 538 } 539 } 540 541 [matrix addObject:infos]; 542 } 543 [_ctx removeObjectForKey:WETableView_INFOS]; 544 [_ctx removeObjectForKey:WETableView_CollectMode]; 545 [_ctx removeObjectForKey:WETableView_SORTEDKEY]; 546 547 matrix = [matrix retain]; 548 [headInfos release]; 549 [pool release]; 550 551 return [matrix autorelease]; 552} 553 554- (void)_appendNav:(NSString *)_nav isBlind:(BOOL)_isBlind 555 toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx 556{ 557 NSString *imgUri; 558 NSString *label; 559 BOOL doForm = [_ctx isInForm]; 560 561 imgUri = [WETableView_ stringByAppendingString:_nav]; 562 imgUri = [imgUri stringByAppendingString:(_isBlind) ? @"_blind" : @""]; 563 imgUri = [_ctx objectForKey:imgUri]; 564 imgUri = WEUriOfResource(imgUri,_ctx); 565 566 label = WETableLabelForKey(_nav, _ctx); 567 568 [_response appendContentString:@"<td valign='middle' width='5'>"]; 569 // append as submit button 570 if (doForm && !_isBlind && !self->state->doScriptScrolling && imgUri) { 571 [_ctx appendElementIDComponent:_nav]; 572 [_response appendContentString:@"<input type=\"image\" border=\"0\""]; 573 [_response appendContentString:@" name=\""]; 574 [_response appendContentString:[_ctx elementID]]; 575 [_response appendContentString:@"\" src=\""]; 576 [_response appendContentString:imgUri]; 577 [_response appendContentString:@"\" alt=\""]; 578 [_response appendContentString:label]; 579 [_response appendContentString:@"\" title=\""]; 580 [_response appendContentString:label]; 581 [_response appendContentString:@"\" />"]; 582 [_ctx deleteLastElementIDComponent]; 583 [_response appendContentString:@"</td>"]; 584 return; 585 } 586 587 /* open anker */ 588 if (!_isBlind || self->state->doScriptScrolling) { 589 [_ctx appendElementIDComponent:_nav]; 590 [_response appendContentString:@"<a href=\""]; 591 if (self->state->doScriptScrolling) 592 [self _appendScriptLink:_response name:_nav]; 593 else 594 [_response appendContentString:[_ctx componentActionURL]]; 595 [_response appendContentString:@"\">"]; 596 } 597 if (imgUri == nil) { 598 [_response appendContentCharacter:'[']; 599 [_response appendContentString:label]; 600 [_response appendContentCharacter:']']; 601 } 602 else { 603 [_response appendContentString:@"<img border=\"0\" src=\""]; 604 [_response appendContentString:imgUri]; 605 if (self->state->doScriptScrolling) { 606 [_response appendContentString:@"\" name=\""]; 607 [self _appendScriptImgName:_response name:_nav]; 608 } 609 [_response appendContentString:@"\" alt=\""]; 610 [_response appendContentString:label]; 611 [_response appendContentString:@"\" title=\""]; 612 [_response appendContentString:label]; 613 [_response appendContentString:@"\" />"]; 614 } 615 /* close anker */ 616 if (!_isBlind || self->state->doScriptScrolling) { 617 [_response appendContentString:@"</a>"]; 618 [_ctx deleteLastElementIDComponent]; 619 } 620 [_response appendContentString:@"</td>"]; 621} 622 623- (void)_appendPreviousNav:(WOResponse *)_resp inContext:(WOContext *)_ctx { 624 int batch, batchCount; 625 BOOL isFirstBlind, isPreviousBlind, isNextBlind, isLastBlind; 626 627 batch = self->state->currentBatch; 628 batchCount = self->state->batchCount; 629 630 isFirstBlind = (batch < 2); 631 isPreviousBlind = (batch < 2); 632 isNextBlind = ((batchCount-1) < batch); 633 isLastBlind = ((batchCount-1) < batch); 634 635 if ((ShowNavigationAlways) || 636 (!(isFirstBlind && isPreviousBlind && isNextBlind && isLastBlind))) { 637 [self _appendNav:@"first" isBlind:isFirstBlind 638 toResponse:_resp inContext:_ctx]; 639 [self _appendNav:@"previous" isBlind:isPreviousBlind 640 toResponse:_resp inContext:_ctx]; 641 } 642} 643 644- (void)_appendNextNav:(WOResponse *)_resp inContext:(WOContext *)_ctx { 645 int batch, batchCount; 646 BOOL isFirstBlind, isPreviousBlind, isNextBlind, isLastBlind; 647 648 batch = self->state->currentBatch; 649 batchCount = self->state->batchCount; 650 651 isFirstBlind = (batch < 2); 652 isPreviousBlind = (batch < 2); 653 isNextBlind = ((batchCount-1) < batch); 654 isLastBlind = ((batchCount-1) < batch); 655 656 if ((ShowNavigationAlways) || 657 (!(isFirstBlind && isPreviousBlind && isNextBlind && isLastBlind))) { 658 [self _appendNav:@"next" isBlind:isNextBlind 659 toResponse:_resp inContext:_ctx]; 660 [self _appendNav:@"last" isBlind:isLastBlind 661 toResponse:_resp inContext:_ctx]; 662 } 663} 664 665- (void)_appendNavigation:(WOResponse *)_resp inContext:(WOContext *)_ctx { 666 [_resp appendContentString: 667 @"<table border='0' cellspacing='0' cellpadding='0'><tr>"]; 668 669 [self _appendPreviousNav:_resp inContext:_ctx]; 670 671 /* append extra buttons */ 672 [_resp appendContentString:@"<td valign='middle'>"]; 673 [_ctx setObject:YesNumber forKey:WETableView_ButtonMode]; 674 [_ctx appendElementIDComponent:@"button"]; 675 [self->template appendToResponse:_resp inContext:_ctx]; 676 [_ctx deleteLastElementIDComponent]; 677 [_ctx removeObjectForKey:WETableView_ButtonMode]; 678 [_resp appendContentString:@"</td>"]; 679 680 [self _appendNextNav:_resp inContext:_ctx]; 681 682 [_resp appendContentString:@"</tr></table>"]; 683} 684 685- (void)_appendTitle:(WOResponse *)_response inContext:(WOContext *)_ctx { 686 NSString *bg; 687 688 bg = [_ctx objectForKey:WETableView_titleColor]; 689 690 /* open title bar*/ 691 [_response appendContentString: 692 @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>" 693 @"<tr>"]; 694 695 /* append title */ 696 [_ctx setObject:YesNumber forKey:WETableView_TitleMode]; 697 [_ctx appendElementIDComponent:@"title"]; 698 WEAppendTD(_response, @"left", @"middle", bg); // <td..> 699 [self->template appendToResponse:_response inContext:_ctx]; 700 [_response appendContentString:@"</td>"]; // </td> 701 [_ctx deleteLastElementIDComponent]; // delete "title" 702 [_ctx removeObjectForKey:WETableView_TitleMode]; 703 704 /* append navigation + extra buttons */ 705 WEAppendTD(_response, @"right", @"middle", bg); // <td..> 706 [self _appendNavigation:_response inContext:_ctx]; 707 [_response appendContentString:@"</td>"]; // </td> 708 709 /* close title bar*/ 710 [_response appendContentString:@"</tr></table>"]; 711} 712 713- (void)_appendHeader:(WOResponse *)_response inContext:(WOContext *)_ctx { 714 if (self->sortedKey) 715 [_ctx setObject:[self->sortedKey stringValueInComponent:[_ctx component]] 716 forKey:WETableView_SORTEDKEY]; 717 if (self->isDescending) 718 [_ctx setObject:[self->isDescending valueInComponent:[_ctx component]] 719 forKey:WETableView_ISDESCENDING]; 720 [_ctx setObject:YesNumber forKey:WETableView_HeaderMode]; 721 [_response appendContentString:@"<tr>"]; 722 723 [_ctx appendElementIDComponent:@"header"]; 724 { 725 NSString *bn; 726 bn = retStrForInt(self->state->currentBatch); 727 [_ctx appendElementIDComponent:bn]; // append batchNumber 728 [bn release]; 729 } 730 if (self->state->doCheckBoxes) { 731 NSString *img; 732 NSArray *selArray; 733 BOOL doSelectAll; 734 735 selArray = [self->selection valueInComponent:[_ctx component]]; 736 doSelectAll = ([selArray count] < ([self->allObjects count] / 2)); 737 738 img = [_ctx objectForKey:(doSelectAll) 739 ? WETableView_select_all 740 : WETableView_deselect_all]; 741 742 img = WEUriOfResource(img, _ctx); 743 744 [_response appendContentString: 745 @"<td align=\"center\" bgcolor=\""]; 746 [_response appendContentString: 747 [_ctx objectForKey:WETableView_headerColor]]; 748 [_response appendContentString:@"\">"]; 749 750 if (doSelectAll) 751 [_ctx appendElementIDComponent:@"_sa"]; // select all 752 else 753 [_ctx appendElementIDComponent:@"_dsa"]; // deselect all 754 755 [_response appendContentString:@"<a href=\""]; 756 [_response appendContentString:[_ctx componentActionURL]]; 757 [_response appendContentString:@"\">"]; 758 759 if (img) { 760 [_response appendContentString:@"<img border=\"0\" src=\""]; 761 [_response appendContentString:img]; 762 [_response appendContentString:@"\" alt=\""]; 763 [_response appendContentString:(doSelectAll) 764 ? @"selectall" 765 : @"deselect all"]; 766 [_response appendContentString:@"\" title=\""]; 767 [_response appendContentString:(doSelectAll) 768 ? @"selectall" 769 : @"deselect all"]; 770 [_response appendContentString:@"\" />"]; 771 } 772 else 773 [_response appendContentString:(doSelectAll) ? @"[+]" : @"[-]"]; 774 775 [_response appendContentString:@"</a>"]; 776 [_ctx deleteLastElementIDComponent]; // (de)select all 777 [_response appendContentString:@"</td>"]; 778 } 779 [self->template appendToResponse:_response inContext:_ctx]; 780 781 [_ctx deleteLastElementIDComponent]; // delete batchNumber 782 [_ctx deleteLastElementIDComponent]; // delete "header" 783 784 if (self->state->showBatchResizeButtons) { 785 int cnt; 786 787 cnt = (self->state->lastIndex - self->state->firstIndex + 1); 788 789 if (cnt == (int)self->state->batchSize && !self->state->doOverflow) { 790 [_response appendContentString:@"<td width=\"1%\""]; 791 if ([_ctx objectForKey:WETableView_headerColor]) { 792 [_response appendContentString:@" bgcolor=\""]; 793 [_response appendContentString: 794 [_ctx objectForKey:WETableView_headerColor]]; 795 [_response appendContentString:@"\""]; 796 } 797 [_response appendContentString:@"></td>"]; 798 } 799 } 800 801 [_response appendContentString:@"</tr>"]; 802 [_ctx removeObjectForKey:WETableView_HeaderMode]; 803 [_ctx removeObjectForKey:WETableView_SORTEDKEY]; 804 [_ctx removeObjectForKey:WETableView_ISDESCENDING]; 805} 806 807- (void)_appendResizeButtons:(WOResponse *)_response 808 actionUrl:(NSString *)_actionUrl 809 inContext:(WOContext *)_ctx 810{ 811 NSString *img; 812 NSString *uri; 813 814 // append batchSize--Button 815 img = [self->icons->minusResizeIcon stringValueInComponent:[_ctx component]]; 816 img = WEUriOfResource(img, _ctx); 817 uri = [_actionUrl stringByAppendingString:@".mm"]; 818 819 if (img && [_ctx isInForm]) { 820 uri = [[uri componentsSeparatedByString:@"/"] lastObject]; 821 [_response appendContentString:@"<input type=\"image\" border=\"0\""]; 822 [_response appendContentString:@" name=\""]; 823 [_response appendContentString:uri]; 824 [_response appendContentString:@"\" src=\""]; 825 [_response appendContentString:img]; 826 [_response appendContentString:@"\" alt=\"minus\" title=\"minus\" />"]; 827 } 828 else { 829 [_response appendContentString:@"<a href=\""]; 830 [_response appendContentString:uri]; 831 [_response appendContentString:@"\">"]; 832 } 833 834 if (img && ![_ctx isInForm]) { 835 [_response appendContentString:@"<img border=\"0\" src=\""]; 836 [_response appendContentString:img]; 837 [_response appendContentString:@"\" alt=\"minus\" title=\"minus\" />"]; 838 } 839 else if (!img) 840 [_response appendContentString:@"-"]; 841 842 if (!(img && [_ctx isInForm])) 843 [_response appendContentString:@"</a>"]; 844 845 // append batchSize--Button 846 img = [self->icons->plusResizeIcon stringValueInComponent:[_ctx component]]; 847 img = WEUriOfResource(img, _ctx); 848 uri = [_actionUrl stringByAppendingString:@".pp"] ; 849 850 if (img && [_ctx isInForm]) { 851 uri = [[uri componentsSeparatedByString:@"/"] lastObject]; 852 [_response appendContentString:@"<input type=\"image\" border=\"0\""]; 853 [_response appendContentString:@" name=\""]; 854 [_response appendContentString:uri]; 855 [_response appendContentString:@"\" src=\""]; 856 [_response appendContentString:img]; 857 [_response appendContentString:@"\" alt=\"plus\" title=\"plus\" />"]; 858 } 859 else { 860 [_response appendContentString:@"<a href=\""]; 861 [_response appendContentString:uri]; 862 [_response appendContentString:@"\">"]; 863 } 864 865 if (img && ![_ctx isInForm]) { 866 [_response appendContentString:@"<img border=\"0\" src=\""]; 867 [_response appendContentString:img]; 868 [_response appendContentString:@"\" alt=\"plus\" title=\"plus\" />"]; 869 } 870 else if (!img) 871 [_response appendContentString:@"+"]; 872 873 if (!(img && [_ctx isInForm])) 874 [_response appendContentString:@"</a>"]; 875 876} 877 878- (void)_appendBatchResizeButtons:(WOResponse *)_response 879 rowSpan:(unsigned int)_rowSpan 880 actionUrl:(NSString *)_actionUrl 881 inContext:(WOContext *)_ctx 882{ 883 NSString *s; 884 885 // open "td" 886 s = [[StrClass alloc] initWithFormat: 887 @"<td align='center' valign='bottom' width='5' rowspan='%d'", _rowSpan]; 888 [_response appendContentString:s]; 889 [s release]; 890 891 if ([_ctx objectForKey:WETableView_footerColor]) { 892 [_response appendContentString:@" bgcolor='"]; 893 [_response appendContentString: 894 [_ctx objectForKey:WETableView_footerColor]]; 895 [_response appendContentCharacter:'\'']; 896 } 897 [_response appendContentCharacter:'>']; 898 899 // apppend resize buttons 900 [self _appendResizeButtons:_response 901 actionUrl:_actionUrl 902 inContext:_ctx]; 903 // close "td" 904 [_response appendContentString:@"</td>"]; 905} 906 907- (void)_appendData:(WOResponse *)_response inContext:(WOContext *)_ctx { 908 WOComponent *comp; 909 NSArray *matrix; 910 NSString *batchSizeUrl = nil; 911 NSArray *selArray = nil; 912 NSString *groupId = nil; 913 BOOL hideObject = NO; 914 unsigned i, cnt, first; 915 916 comp = [_ctx component]; 917 matrix = [self _collectDataInContext:_ctx]; 918 first = self->state->firstIndex; 919 cnt = [matrix count]; 920 921 if (matrix == nil || cnt == 0) 922 return; 923 924 if (self->state->doCheckBoxes) 925 selArray = [self->selection valueInComponent:comp]; 926 927 if (self->state->doScriptCollapsing) 928 [self _appendGroupCollapseScript:_response inContext:_ctx]; 929 930 [_ctx appendElementIDComponent:@"data"]; 931 { 932 NSString *bn; 933 bn = retStrForInt(self->state->currentBatch); 934 [_ctx appendElementIDComponent:bn]; // append batchNumber 935 [bn release]; 936 } 937 938 batchSizeUrl = [_ctx componentActionURL]; 939 940 if (self->identifier == nil) { 941 NSString *s; 942 943 s = retStrForInt(first); 944 [_ctx appendElementIDComponent:s]; 945 [s release]; 946 } 947 948 for (i = 0; i < cnt; i++) { 949 NSMutableArray *infos = nil; 950 951 _applyItems_(self, comp, first+i); 952 if (self->identifier) { 953 NSString *ident; 954 955 ident = [self->identifier stringValueInComponent:comp]; 956 [_ctx appendElementIDComponent:ident]; 957 } 958 959 infos = [matrix objectAtIndex:i]; 960 961 if ([[infos lastObject] isEqual:WETableView_GroupMode]) { 962 unsigned rowSpan; 963 964 groupId = [StrClass stringWithFormat:@"group%d", i]; 965 966 rowSpan = ((i==0) && self->state->showBatchResizeButtons) 967 ? cnt+self->state->groupCount 968 : 0; 969 [self _appendGroupTitle:_response 970 inContext:_ctx 971 infos:infos 972 actionUrl:batchSizeUrl 973 rowSpan:rowSpan 974 groupId:groupId]; 975 976 if ((self->state->groupCount > 0) && !self->state->doScriptCollapsing && 977 (self->showGroup) && ![self->showGroup boolValueInComponent:comp]) 978 hideObject = YES; 979 else 980 hideObject = NO; 981 } 982 983 [_ctx setObject:infos forKey:WETableView_INFOS]; 984 985 if (hideObject) { 986 if (self->identifier == nil) 987 [_ctx incrementLastElementIDComponent]; 988 else 989 [_ctx deleteLastElementIDComponent]; // delete identifier 990 continue; 991 } 992 993 [_response appendContentString:@"<tr"]; 994 if (groupId) { 995 [_response appendContentString:@" groupName=\""]; 996 [_response appendContentString:groupId]; 997 [_response appendContentCharacter:'"']; 998 if (self->state->doScriptCollapsing && 999 self->showGroup && ![self->showGroup boolValueInComponent:comp]) 1000 [_response appendContentString:@" style=\"display:none;\""]; 1001 } 1002 [_response appendContentCharacter:'>']; 1003 1004 [_ctx setObject:YesNumber forKey:WETableView_DataMode]; 1005 1006 if (self->state->doCheckBoxes) { 1007 WETableViewInfo *info = nil; 1008 NSString *bg = nil; 1009 NSString *s; 1010 1011 info = ([infos count]) ? [infos objectAtIndex:0] : nil; 1012 1013 bg = (info && info->isEven) 1014 ? [_ctx objectForKey:WETableView_evenColor] 1015 : [_ctx objectForKey:WETableView_oddColor]; 1016 1017 [_ctx appendElementIDComponent:@"cb"]; 1018 [_response appendContentString:@"<td width=\"15\" align=\"left\""]; 1019 [_response appendContentString:@" bgcolor=\""]; 1020 [_response appendContentString:bg]; 1021 [_response appendContentString:@"\"><input type=\"checkbox\" name=\""]; 1022 [_response appendContentHTMLAttributeValue:[_ctx elementID]]; 1023 [_response appendContentString:@"\" value=\""]; 1024 s = retStrForInt(first + i); 1025 [_response appendContentString:s]; 1026 [s release]; 1027 [_response appendContentCharacter:'"']; 1028 1029 if ([selArray containsObject:[self->allObjects objectAtIndex:first+i]]) 1030 [_response appendContentString:@" checked=\"checked\""]; 1031 1032 [_response appendContentString:@" />"]; 1033 [_response appendContentString:@"</td>"]; 1034 1035 [_ctx deleteLastElementIDComponent]; // delete "cb" 1036 } 1037 1038 [self->template appendToResponse:_response inContext:_ctx]; 1039 1040 if (!i && self->state->showBatchResizeButtons &&!self->state->groupCount) { 1041 [self _appendBatchResizeButtons:_response 1042 rowSpan:cnt+self->state->groupCount 1043 actionUrl:batchSizeUrl 1044 inContext:_ctx]; 1045 } 1046 1047 [_response appendContentString:@"</tr>"]; 1048 1049 if (self->identifier == nil) 1050 [_ctx incrementLastElementIDComponent]; 1051 else 1052 [_ctx deleteLastElementIDComponent]; // delete identifier 1053 } 1054 if (self->identifier == nil) 1055 [_ctx deleteLastElementIDComponent]; // delete index 1056 [_ctx deleteLastElementIDComponent]; // delete batchNumber 1057 [_ctx deleteLastElementIDComponent]; // delete "data" 1058 [_ctx removeObjectForKey:WETableView_DataMode]; 1059} 1060 1061- (void)_appendFooter:(WOResponse *)_response inContext:(WOContext *)_ctx { 1062 NSString *bg = nil; 1063 unsigned first = self->state->firstIndex + 1; 1064 unsigned last = self->state->lastIndex + 1; 1065 unsigned count = [self->allObjects count]; 1066 unsigned batch = self->state->currentBatch; 1067 unsigned batchCnt = self->state->batchCount; 1068 NSString *s; 1069 1070 first = (count) ? first : 0; 1071 batchCnt = (batchCnt) ? batchCnt : 1; 1072 bg = [_ctx objectForKey:WETableView_footerColor]; 1073 1074 [_response appendContentString: 1075 @"<table border='0' width='100%' cellpadding='0' cellspacing='0'>"]; 1076 [_response appendContentString:@"<tr>"]; // <TR> 1077 1078 WEAppendTD(_response, @"left", nil, bg); // <TD...> 1079 1080 [_ctx setObject:YesNumber forKey:WETableView_FooterMode]; 1081 [_ctx appendElementIDComponent:@"footer"]; 1082 [self->template appendToResponse:_response inContext:_ctx]; 1083 [_ctx deleteLastElementIDComponent]; 1084 [_ctx removeObjectForKey:WETableView_FooterMode]; 1085 1086 [_response appendContentString:@"<small>"]; 1087 if (!self->state->doOverflow) { 1088 s = [[StrClass alloc] initWithFormat:@"%d ", first]; 1089 [_response appendContentString:s]; 1090 [s release]; 1091 [_response appendContentString:WETableLabelForKey(@"to", _ctx)]; 1092 s = [[StrClass alloc] initWithFormat:@" %d ", last]; 1093 [_response appendContentString:s]; 1094 [s release]; 1095 [_response appendContentString:WETableLabelForKey(@"of", _ctx)]; 1096 } 1097 s = [[StrClass alloc] initWithFormat:@" %d", count]; 1098 [_response appendContentString:s]; 1099 [s release]; 1100 [_response appendContentString:@"</small>"]; 1101 1102 [_response appendContentString:@"</td>"]; // </td> 1103 1104 WEAppendTD(_response, @"right", nil, bg); // <td...> 1105 if (!self->state->doOverflow) { 1106 if (ShowNavigationInFooter) { 1107 [_response appendContentString: 1108 @"<table border='0' cellpadding='0' cellspacing='0'><tr>"]; 1109 [self _appendPreviousNav:_response inContext:_ctx]; 1110 WEAppendTD(_response, nil, nil, bg); // <td...> 1111 } 1112 [_response appendContentString:@"<small>"]; 1113 [_response appendContentString:@" "]; 1114 [_response appendContentString:WETableLabelForKey(@"page", _ctx)]; 1115 s = [[StrClass alloc] initWithFormat:@": %d ", batch]; 1116 [_response appendContentString:s]; 1117 [s release]; 1118 [_response appendContentString:WETableLabelForKey(@"of", _ctx)]; 1119 s = [[StrClass alloc] initWithFormat:@" %d", batchCnt]; 1120 [_response appendContentString:s]; 1121 [s release]; 1122 [_response appendContentString:@" "]; 1123 [_response appendContentString:@"</small>"]; 1124 if (ShowNavigationInFooter) { 1125 [_response appendContentString:@"</td>"]; 1126 [self _appendNextNav:_response inContext:_ctx]; 1127 [_response appendContentString:@"</tr></table>"]; 1128 } 1129 } 1130 else { 1131 [self _appendResizeButtons:_response 1132 actionUrl:[_ctx componentActionURL] 1133 inContext:_ctx]; 1134 } 1135 1136 [_response appendContentString:@"</td></tr>"]; // </td></tr> 1137 [_response appendContentString:@"</table>"]; // </table> 1138} 1139 1140// --- action handler ----------------------------------------------------- 1141 1142- (void)_handleSortActionInContext:(WOContext *)_ctx { 1143 WOComponent *cmp; 1144 NSString *key; 1145 NSString *oldKey; 1146 BOOL isDesc; 1147 BOOL oldIsDesc; 1148 1149 if (self->sortedKey == nil || self->isDescending == nil) 1150 return; // nothing to do 1151 1152 if ([_ctx objectForKey:WETableView_SORTEDKEY] == nil || 1153 [_ctx objectForKey:WETableView_ISDESCENDING] == nil) 1154 return; // nothing to do 1155 1156 cmp = [_ctx component]; 1157 key = [_ctx objectForKey:WETableView_SORTEDKEY]; 1158 isDesc = [[_ctx objectForKey:WETableView_ISDESCENDING] boolValue]; 1159 1160 oldIsDesc = [self->isDescending boolValueInComponent:cmp]; 1161 oldKey = [self->sortedKey stringValueInComponent:cmp]; 1162 1163 if ([oldKey isEqual:key] && oldIsDesc == isDesc) 1164 return; // nothing to do 1165 1166 if ([self->isDescending isValueSettable]) 1167 [self->isDescending setBoolValue:isDesc inComponent:cmp]; 1168 if ([self->sortedKey isValueSettable]) 1169 [self->sortedKey setStringValue:key inComponent:cmp]; 1170 1171 if (self->sortAction == nil && key != nil) { 1172 EOSortOrdering *so; 1173 NSArray *soArray; 1174 SEL sel; 1175 NSArray *tmp; 1176 1177 sel = (isDesc) ? EOCompareDescending : EOCompareAscending; 1178 so = [EOSortOrdering sortOrderingWithKey:key selector:sel]; 1179 1180 soArray = [[NSArray alloc] initWithObjects:&so count:1]; 1181 tmp = [self->allObjects sortedArrayUsingKeyOrderArray:soArray]; 1182 [soArray release]; 1183 1184 if ([self->list isValueSettable]) 1185 [self->list setValue:tmp inComponent:[_ctx component]]; 1186 else { 1187 [[_ctx component] debugWithFormat: 1188 @"couldn't set sorted list on 'list' binding"]; 1189 } 1190 } 1191 else if (self->sortAction) 1192 [self->sortAction valueInComponent:cmp]; 1193} 1194 1195- (void)_handleFirstButtonInContext:(WOContext *)_ctx { 1196 if (self->firstAction) 1197 [self->firstAction valueInComponent:[_ctx component]]; 1198 else if (self->state->currentBatch != 1) { 1199 self->state->currentBatch = 1; 1200 _applyState_(self, [_ctx component]); 1201 } 1202} 1203 1204- (void)_handlePreviousButtonInContext:(WOContext *)_ctx { 1205 if (self->previousAction) 1206 [self->previousAction valueInComponent:[_ctx component]]; 1207 else { 1208 unsigned batch = self->state->currentBatch; 1209 1210 self->state->currentBatch = ((batch -1) > 0) ? batch - 1 : 1; 1211 _applyState_(self, [_ctx component]); 1212 } 1213} 1214 1215- (void)_handleNextButtonInContext:(WOContext *)_ctx { 1216 if (self->nextAction) 1217 [self->nextAction valueInComponent:[_ctx component]]; 1218 else { 1219 unsigned batch = self->state->currentBatch; 1220 unsigned cnt = self->state->batchCount; 1221 1222 self->state->currentBatch = ((batch +1) < cnt) ? batch + 1 : cnt; 1223 _applyState_(self, [_ctx component]); 1224 } 1225} 1226 1227- (void)_handleLastButtonInContext:(WOContext *)_ctx { 1228 if (self->lastAction) 1229 [self->lastAction valueInComponent:[_ctx component]]; 1230 else { 1231 self->state->currentBatch = self->state->batchCount; 1232 _applyState_(self, [_ctx component]); 1233 } 1234} 1235 1236/* handle request */ 1237 1238- (void)takeValuesFromRequest:(WORequest *)_request 1239 forBatch:(int)_batch 1240 selections:(NSMutableArray *)_selArray 1241 inContext:(WOContext *)_ctx 1242{ 1243 NSString *eid, *s; 1244 int i, first, last; 1245 1246 first = self->state->firstIndex; 1247 last = self->state->lastIndex; 1248 1249 { 1250 NSString *bn; 1251 bn = retStrForInt(self->state->currentBatch); 1252 [_ctx appendElementIDComponent:bn]; // append batchNumber 1253 [bn release]; 1254 } 1255 1256 eid = [_ctx elementID]; 1257 1258 if ([_request formValueForKey:[eid stringByAppendingString:@".pp.x"]]) { 1259 [_ctx addActiveFormElement:self]; 1260 [_ctx setRequestSenderID: 1261 [[_ctx senderID] stringByAppendingString:@".pp"]]; 1262 } 1263 else if ([_request formValueForKey:[eid stringByAppendingString:@".mm.x"]]) { 1264 [_ctx addActiveFormElement:self]; 1265 [_ctx setRequestSenderID: 1266 [[_ctx senderID] stringByAppendingString:@".mm"]]; 1267 } 1268 1269 if (self->identifier == nil) { // append index 1270 s = retStrForInt(first); 1271 [_ctx appendElementIDComponent:s]; 1272 [s release]; 1273 } 1274 1275 for (i = first; i <= last; i++) { 1276 _applyItems_(self, [_ctx component], i); 1277 if (self->identifier) { 1278 NSString *s; 1279 1280 s = [self->identifier stringValueInComponent:[_ctx component]]; 1281 [_ctx appendElementIDComponent:s]; 1282 } 1283 1284 if (_selArray) { 1285 NSString *cbID; // checkBoxID 1286 id formValue; 1287 id obj; 1288 1289 cbID = [[_ctx elementID] stringByAppendingString:@".cb"]; 1290 obj = [self->item valueInComponent:[_ctx component]]; 1291 1292 if (obj) { 1293 if ((formValue = [_request formValueForKey:cbID])) { 1294 if (![_selArray containsObject:obj]) 1295 [_selArray addObject:obj]; 1296 } 1297 else if ([_selArray containsObject:obj]) 1298 [_selArray removeObject:obj]; 1299 } 1300 } 1301 [self->template takeValuesFromRequest:_request inContext:_ctx]; 1302 1303 if (self->identifier == nil) 1304 [_ctx incrementLastElementIDComponent]; 1305 else 1306 [_ctx deleteLastElementIDComponent]; // delete identifier 1307 } 1308 if (self->identifier == nil) 1309 [_ctx deleteLastElementIDComponent]; // delete index 1310 1311 [_ctx deleteLastElementIDComponent]; // delete batchNumber 1312} 1313 1314- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx { 1315 int i, firstBatch, lastBatch, savedCurrentBatch; 1316 NSString *eid; 1317 NSMutableArray *selArray = nil; 1318 1319 [self updateStateInContext:_ctx]; 1320 1321 eid = [_ctx elementID]; 1322 1323 /* handle "data" section */ 1324 1325 if (self->state->doCheckBoxes) { 1326 selArray = [self->selection valueInComponent:[_ctx component]]; 1327 selArray = [selArray mutableCopyWithZone:[self zone]]; 1328 } 1329 1330 firstBatch = self->state->doScriptScrolling ? 1 : self->state->currentBatch; 1331 lastBatch = (self->state->doScriptScrolling) 1332 ? self->state->batchCount 1333 : self->state->currentBatch; 1334 1335 [_ctx appendElementIDComponent:@"data"]; 1336 [_ctx setObject:YesNumber forKey:WETableView_DataMode]; 1337 1338 savedCurrentBatch = self->state->currentBatch; 1339 for (i = firstBatch; i <= lastBatch; i++) { 1340 self->state->currentBatch = i; 1341 _applyState_(self, [_ctx component]); 1342 [self updateStateInContext:_ctx]; 1343 1344 [self takeValuesFromRequest:_rq 1345 forBatch:i 1346 selections:selArray 1347 inContext:_ctx]; 1348 } 1349 [_ctx removeObjectForKey:WETableView_DataMode]; 1350 1351 if (self->state->currentBatch != (unsigned)savedCurrentBatch) { 1352 self->state->currentBatch = savedCurrentBatch; 1353 _applyState_(self, [_ctx component]); 1354 } 1355 1356 [_ctx deleteLastElementIDComponent]; // delete "data" 1357 1358 if (self->state->doCheckBoxes) { 1359 [self->selection setValue:selArray inComponent:[_ctx component]]; 1360 [selArray release]; 1361 } 1362 1363 // handle header (sort buttons, ...) 1364 [_ctx setObject:YesNumber forKey:WETableView_HeaderMode]; 1365 [_ctx appendElementIDComponent:@"header"]; 1366 1367 for (i = 1; i <= (int)self->state->batchCount; i++) { 1368 NSString *s; 1369 1370 // TODO: improve 1371 s = retStrForInt(i); 1372 [_ctx appendElementIDComponent:s]; 1373 [s release]; 1374 1375 [self->template takeValuesFromRequest:_rq inContext:_ctx]; 1376 [_ctx deleteLastElementIDComponent]; // delete batchNumber 1377 } 1378 1379 [_ctx deleteLastElementIDComponent]; // delete "header" 1380 [_ctx removeObjectForKey:WETableView_HeaderMode]; 1381 1382 // handle title 1383 [_ctx setObject:YesNumber forKey:WETableView_TitleMode]; 1384 [_ctx appendElementIDComponent:@"title"]; 1385 [self->template takeValuesFromRequest:_rq inContext:_ctx]; 1386 [_ctx deleteLastElementIDComponent]; // delete "title" 1387 [_ctx removeObjectForKey:WETableView_TitleMode]; 1388 1389 // handle buttons 1390 [_ctx setObject:YesNumber forKey:WETableView_ButtonMode]; 1391 [_ctx appendElementIDComponent:@"button"]; 1392 [self->template takeValuesFromRequest:_rq inContext:_ctx]; 1393 [_ctx deleteLastElementIDComponent]; // delete "button" 1394 [_ctx removeObjectForKey:WETableView_ButtonMode]; 1395 1396 // handle footer 1397 [_ctx setObject:YesNumber forKey:WETableView_FooterMode]; 1398 [_ctx appendElementIDComponent:@"footer"]; 1399 1400 // reset autoScrollHeight 1401 if ([_rq formValueForKey:[eid stringByAppendingString:@".footer.pp.x"]]) { 1402 [_ctx addActiveFormElement:self]; 1403 [_ctx setRequestSenderID: 1404 [[_ctx senderID] stringByAppendingString:@".pp"]]; 1405 } 1406 else if ([_rq formValueForKey: 1407 [eid stringByAppendingString:@".footer.mm.x"]]) { 1408 [_ctx addActiveFormElement:self]; 1409 [_ctx setRequestSenderID: 1410 [[_ctx senderID] stringByAppendingString:@".mm"]]; 1411 } 1412 1413 [self->template takeValuesFromRequest:_rq inContext:_ctx]; 1414 [_ctx deleteLastElementIDComponent]; // delete "footer" 1415 [_ctx removeObjectForKey:WETableView_FooterMode]; 1416 1417 if ([_rq formValueForKey:[eid stringByAppendingString:@".first.x"]]) { 1418 [_ctx addActiveFormElement:self]; 1419 [_ctx setRequestSenderID: 1420 [[_ctx senderID] stringByAppendingString:@".first"]]; 1421 } 1422 if ([_rq formValueForKey:[eid stringByAppendingString:@".next.x"]]) { 1423 [_ctx addActiveFormElement:self]; 1424 [_ctx setRequestSenderID: 1425 [[_ctx senderID] stringByAppendingString:@".next"]]; 1426 } 1427 if ([_rq formValueForKey:[eid stringByAppendingString:@".last.x"]]) { 1428 [_ctx addActiveFormElement:self]; 1429 [_ctx setRequestSenderID: 1430 [[_ctx senderID] stringByAppendingString:@".last"]]; 1431 } 1432 if ([_rq formValueForKey:[eid stringByAppendingString:@".previous.x"]]) { 1433 [_ctx addActiveFormElement:self]; 1434 [_ctx setRequestSenderID: 1435 [[_ctx senderID] stringByAppendingString:@".previous"]]; 1436 } 1437} 1438 1439- (id)increaseAutoScrollHeightInContext:(WOContext *)_ctx { 1440 if ([self->autoScroll isValueSettable]) { 1441 int sh; // scrollHeight 1442 1443 sh = [self->autoScroll intValueInComponent:[_ctx component]] + 20; 1444 [self->autoScroll setIntValue:sh inComponent:[_ctx component]]; 1445 } 1446 return nil; 1447} 1448 1449- (id)decreaseAutoScrollHeightInContext:(WOContext *)_ctx { 1450 if ([self->autoScroll isValueSettable]) { 1451 int sh; // scrollHeight 1452 1453 sh = [self->autoScroll intValueInComponent:[_ctx component]] - 20; 1454 if (sh > 50) 1455 [self->autoScroll setIntValue:sh inComponent:[_ctx component]]; 1456 } 1457 return nil; 1458} 1459 1460 1461- (id)increaseBatchSizeInContext:(WOContext *)_ctx { 1462 if ([self->batchSize isValueSettable]) { 1463 int bs; 1464 1465 bs = [self->batchSize intValueInComponent:[_ctx component]] + 1; 1466 [self->batchSize setIntValue:bs inComponent:[_ctx component]]; 1467 } 1468 return nil; 1469} 1470 1471- (id)decreaseBatchSizeInContext:(WOContext *)_ctx { 1472 if ([self->batchSize isValueSettable]) { 1473 int bs; 1474 1475 bs = [self->batchSize intValueInComponent:[_ctx component]] - 1; 1476 if (bs > 1) 1477 [self->batchSize setIntValue:bs inComponent:[_ctx component]]; 1478 } 1479 return nil; 1480} 1481 1482- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx { 1483 WOComponent *cmp; 1484 NSString *eid; 1485 id result = nil; 1486 1487 [self updateStateInContext:_ctx]; 1488 1489 eid = [_ctx currentElementID]; 1490 cmp = [_ctx component]; 1491 1492 if ([eid isEqual:@"first"]) 1493 [self _handleFirstButtonInContext:_ctx]; 1494 else if ([eid isEqual:@"previous"]) 1495 [self _handlePreviousButtonInContext:_ctx]; 1496 else if ([eid isEqual:@"next"]) 1497 [self _handleNextButtonInContext:_ctx]; 1498 else if ([eid isEqual:@"last"]) 1499 [self _handleLastButtonInContext:_ctx]; 1500 else if ([eid isEqual:@"data"]) { 1501 NSString *idxId; 1502 1503 [_ctx consumeElementID]; // consume "data" 1504 [_ctx appendElementIDComponent:eid]; // append "data" 1505 1506 { 1507 NSString *bn; 1508 1509 bn = [_ctx currentElementID]; 1510 if ([self->currentBatch isValueSettable]) 1511 [self->currentBatch setIntValue:[bn intValue] inComponent:cmp]; 1512 1513 [_ctx consumeElementID]; // consume batchNumber 1514 [_ctx appendElementIDComponent:bn]; // append batch 1515 } 1516 1517 if ((idxId = [_ctx currentElementID])) { 1518 [_ctx consumeElementID]; // consume index-id 1519 [_ctx appendElementIDComponent:idxId]; // append index-id 1520 1521 // reset batchSize 1522 if ([idxId isEqualToString:@"pp"]) 1523 result = [self increaseBatchSizeInContext:_ctx]; 1524 else if ([idxId isEqualToString:@"mm"]) 1525 result = [self decreaseBatchSizeInContext:_ctx]; 1526 else { 1527 if (self->identifier == nil) { 1528 NSInteger idx; 1529 1530 idx = [idxId integerValue]; 1531 if (idx < [self->allObjects count] && idx >= 0) { 1532 _applyItems_(self, cmp, idx); 1533 } 1534 else 1535 NSLog(@"WETableView: index is out of range!"); 1536 } 1537 else 1538 _applyIdentifier(self, cmp, idxId); 1539 1540 result = [self invokeGrouping:_rq inContext:_ctx]; 1541 } 1542 [_ctx deleteLastElementIDComponent]; // delete index-id 1543 } 1544 [_ctx deleteLastElementIDComponent]; // delete batchNumber 1545 [_ctx deleteLastElementIDComponent]; // delete "data" 1546 } 1547 else if ([eid isEqual:@"header"]) { 1548 [_ctx consumeElementID]; // consume "header" 1549 [_ctx appendElementIDComponent:eid]; // append "header" 1550 1551 if ([self->currentBatch isValueSettable]) { 1552 int bn = [[_ctx currentElementID] intValue]; 1553 [self->currentBatch setIntValue:bn inComponent:cmp]; 1554 } 1555 [_ctx appendElementIDComponent:[_ctx currentElementID]]; // batchNumber 1556 [_ctx consumeElementID]; // consume batchNumber 1557 1558 // handle selectAllCheckBoxes: 1559 if ([[_ctx currentElementID] isEqualToString:@"_sa"]) { 1560 NSMutableArray *selArray; 1561 1562 selArray = [self->allObjects mutableCopyWithZone:[self zone]]; 1563 [self->selection setValue:selArray inComponent:cmp]; 1564 [selArray release]; 1565 } 1566 // handle deselectAllCheckBoxes: 1567 else if ([[_ctx currentElementID] isEqualToString:@"_dsa"]) { 1568 [self->selection setValue:[NSMutableArray array] inComponent:cmp]; 1569 } 1570 else 1571 result = [self->template invokeActionForRequest:_rq inContext:_ctx]; 1572 1573 [_ctx deleteLastElementIDComponent]; // delete batchNumber 1574 [_ctx deleteLastElementIDComponent]; // delete "header" 1575 1576 [self _handleSortActionInContext:_ctx]; 1577 1578 [_ctx removeObjectForKey:WETableView_SORTEDKEY]; 1579 [_ctx removeObjectForKey:WETableView_ISDESCENDING]; 1580 } 1581 else if ([eid isEqual:@"title"] || [eid isEqual:@"button"] || 1582 [eid isEqual:@"footer"]) { 1583 [_ctx consumeElementID]; 1584 [_ctx appendElementIDComponent:eid]; 1585 1586 eid = [_ctx currentElementID]; 1587 1588 // reset autoScrollHeight 1589 if ([eid isEqualToString:@"pp"]) 1590 result = [self increaseAutoScrollHeightInContext:_ctx]; 1591 else if ([eid isEqualToString:@"mm"]) 1592 result = [self decreaseAutoScrollHeightInContext:_ctx]; 1593 else 1594 result = [self->template invokeActionForRequest:_rq inContext:_ctx]; 1595 1596 [_ctx deleteLastElementIDComponent]; 1597 } 1598 else 1599 result = [self->template invokeActionForRequest:_rq inContext:_ctx]; 1600 1601 return result; 1602} 1603 1604- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { 1605 /* 1606 The main HTML of the tableview are two tables: 1607 - a table with the: title+buttons, header and content 1608 this table has three rows: 1609 - a row for the title+buttons 1610 - some kind of padding row? 1611 - a row for the header and the content 1612 this is just a single cell with an embedded table with one row for 1613 the header and n-rows for the content 1614 - a separate table with the footer 1615 */ 1616 WOComponent *cmp; 1617 1618 if ([_ctx isRenderingDisabled]) { 1619 [self->template appendToResponse:_response inContext:_ctx]; 1620 return; 1621 } 1622 1623 [self updateStateInContext:_ctx]; 1624 [self updateScriptIdInContext:_ctx]; 1625 [self updateConfigInContext:_ctx]; 1626 1627 cmp = [_ctx component]; 1628 1629 /* open main tableView */ 1630 // TODO: add CSS 1631 [_response appendContentString: 1632 @"<table border='0' width='100%' " 1633 @"cellpadding='0' cellspacing='0'>"]; 1634 1635 /* append tableTitle + navigation */ 1636 [_response appendContentString:@"<tr><td>"]; 1637 [self _appendTitle:_response inContext:_ctx]; 1638 [_response appendContentString:@"</td></tr>"]; 1639 1640 [_response appendContentString:@"<tr><td></td></tr>"]; 1641 1642 if (self->state->doScriptScrolling) { 1643 [self _appendTableContentAsScript:_response inContext:_ctx]; //close tables 1644 } 1645 else { 1646 /* open header + data area */ 1647 [_response appendContentString:@"<tr><td>"]; 1648 1649 if (self->state->doOverflow) { 1650 [_response appendContentString: 1651 @"<p style=\"width:100%; height: "]; 1652 [_response appendContentString: 1653 [self->autoScroll stringValueInComponent:cmp]]; 1654 [_response appendContentString:@"; overflow-y: auto\">"]; 1655 } 1656 1657 [_response appendContentString:@"<table width='100%' border='"]; 1658 [_response appendContentString:[self->border stringValueInComponent:cmp]]; 1659 [_response appendContentString:@"' cellpadding='"]; 1660 [_response appendContentString: 1661 [self->cellpadding stringValueInComponent:cmp]]; 1662 [_response appendContentString:@"' cellspacing='"]; 1663 [_response appendContentString: 1664 [self->cellspacing stringValueInComponent:cmp]]; 1665 [_response appendContentString:@"'>"]; 1666 1667 1668 self->state->showBatchResizeButtons = 1669 ([self->showBatchResizeButtons boolValueInComponent:cmp] && 1670 (self->state->currentBatch < self->state->batchCount) && 1671 !self->state->doOverflow); 1672 1673 [self _appendHeader:_response inContext:_ctx]; 1674 [self _appendData:_response inContext:_ctx]; 1675 1676 [_response appendContentString:@"</table>"]; 1677 if (self->state->doOverflow) 1678 [_response appendContentString:@"</p>"]; 1679 1680 /* close header + data area */ 1681 [_response appendContentString:@"</td></tr>"]; 1682 1683 [_response appendContentString:@"</table>"]; // </TABLE> 1684 1685 /* append footer */ 1686 [self _appendFooter:_response inContext:_ctx]; 1687 } 1688 1689 // close tableView 1690 1691 1692 if (self->state->doScriptScrolling) 1693 [self appendJavaScript:_response inContext:_ctx]; 1694 1695 [self removeConfigInContext:_ctx]; 1696} 1697 1698@end /* WETableView */ 1699 1700@implementation WETableViewInfo 1701@end 1702 1703// --- JavaScript additions ------------------------------------------------- 1704 1705@implementation WETableView(JavaScriptAdditions) 1706 1707- (void)_appendGroupCollapseScript:(WOResponse *)_resp 1708 inContext:(WOContext *)_ctx 1709{ 1710 if ([_ctx objectForKey:WETableView_HasCollapseScript]) 1711 return; 1712 1713 [_resp appendContentString: 1714 @"\n<script language=\"JavaScript\">\n" 1715 @"<!--\n" 1716 @"function toggleTableGroup()\n" 1717 @"{\n" 1718 @" img = event.srcElement;\n" 1719 @" visibility = img.isGroupVisible;\n" 1720 @" visibility = (visibility != \"none\") ? \"none\" : \"\";\n" 1721 @" img.isGroupVisible = visibility;\n" 1722 @" img.src = (visibility == \"\") ? img.openImg : img.closeImg;\n" 1723 @" groupName = img.group;\n" 1724 @" table = img.parentNode.parentNode.parentNode;\n" 1725 @" trList = table.getElementsByTagName(\"TR\");\n" 1726 @" cnt = trList.length;\n" 1727 @" for (i=0; i<cnt; i++) {\n" 1728 @" tr = trList[i];\n" 1729 @" if (tr.groupName == groupName)\n" 1730 @" tr.style.display = visibility;\n" 1731 @" }\n" 1732 @"}\n" 1733 @"//-->\n" 1734 @"</script>\n"]; 1735 [_ctx setObject:YesNumber forKey:WETableView_HasCollapseScript]; 1736} 1737 1738- (void)jsButton:(WOResponse *)_resp ctx:(WOContext *)_ctx 1739 name:(NSString *)_name button:(NSString *)_button 1740{ 1741 NSString *imgUri; 1742 NSString *n; 1743 1744 _button = [_button stringByAppendingString:@".gif"]; 1745 imgUri = WEUriOfResource(_button, _ctx); 1746 n = [_name stringByAppendingString:self->scriptID]; 1747 1748 n = [[StrClass alloc] initWithFormat: 1749 @"var %@ = new Image(); %@.src = \"%@\";\n", n, n, imgUri]; 1750 [_resp appendContentString:n]; 1751 [n release]; 1752} 1753 1754- (void)appendJavaScript:(WOResponse *)_resp inContext:(WOContext *)_ctx { 1755 NSString *n; 1756 1757 [_resp appendContentString:@"<script language=\"JavaScript\">\n<!--\n"]; 1758 1759 [self jsButton:_resp ctx:_ctx name:@"First" button:@"first"]; 1760 [self jsButton:_resp ctx:_ctx name:@"First2" button:@"first_blind"]; 1761 [self jsButton:_resp ctx:_ctx name:@"Previous" button:@"previous"]; 1762 [self jsButton:_resp ctx:_ctx name:@"Previous2" button:@"previous_blind"]; 1763 [self jsButton:_resp ctx:_ctx name:@"Next" button:@"next"]; 1764 [self jsButton:_resp ctx:_ctx name:@"Next2" button:@"next_blind"]; 1765 [self jsButton:_resp ctx:_ctx name:@"Last" button:@"last"]; 1766 [self jsButton:_resp ctx:_ctx name:@"Last2" button:@"last_blind"]; 1767 1768 n = [[StrClass alloc] initWithFormat: 1769 @"function showPage%@() {\n" 1770 @" for (var i=1; i< page%@.length; i++) {\n" 1771 @" if (i == actualPage%@) {\n" 1772 @" page%@[i][\"Div\"].style.display = \"\";\n" 1773 @" footer%@[i][\"Div\"].style.display = \"\";\n" 1774 @" }\n" 1775 @" else {\n" 1776 @" page%@[i][\"Div\"].style.display = \"none\";\n" 1777 @" footer%@[i][\"Div\"].style.display = \"none\";\n" 1778 @" }\n" 1779 @" }\n" 1780 @" flushImages%@();\n" 1781 @"}\n", 1782 self->scriptID, // showPage 1783 self->scriptID, // page.length 1784 self->scriptID, // actualPage 1785 self->scriptID, // page 1786 self->scriptID, // footer 1787 self->scriptID, // page 1788 self->scriptID, // footer 1789 self->scriptID // flushImages 1790 ]; 1791 [_resp appendContentString:n]; 1792 [n release]; 1793 1794 n = [[StrClass alloc] initWithFormat: 1795 @"function firstPage%@() {\n" 1796 @" actualPage%@ = 1;\n" 1797 @" showPage%@();\n" 1798 @"}\n", 1799 self->scriptID, // firstPage 1800 self->scriptID, // actualPage 1801 self->scriptID // showPage 1802 ]; 1803 [_resp appendContentString:n]; 1804 [n release]; 1805 1806 n = [[StrClass alloc] initWithFormat: 1807 @"function previousPage%@() {\n" 1808 @" if (actualPage%@ > 1) {\n" 1809 @" actualPage%@--;\n" 1810 @" showPage%@();\n" 1811 @" }\n" 1812 @"}\n", 1813 self->scriptID, // previousPage 1814 self->scriptID, // actualPage 1815 self->scriptID, // actualPage 1816 self->scriptID // showPage 1817 ]; 1818 [_resp appendContentString:n]; 1819 [n release]; 1820 1821 n = [[StrClass alloc] initWithFormat: 1822 @"function nextPage%@() {\n" 1823 @" if (actualPage%@ < page%@.length - 1) {\n" 1824 @" actualPage%@++;\n" 1825 @" showPage%@();\n" 1826 @" }\n" 1827 @"}\n", 1828 self->scriptID, // nextPage 1829 self->scriptID, // actualPage 1830 self->scriptID, // page 1831 self->scriptID, // actualPage 1832 self->scriptID // showPage 1833 ]; 1834 [_resp appendContentString:n]; 1835 [n release]; 1836 1837 n = [[StrClass alloc] initWithFormat: 1838 @"function lastPage%@() {\n" 1839 @" actualPage%@ = page%@.length - 1;\n" 1840 @" showPage%@();\n" 1841 @"}\n", 1842 self->scriptID, // lastPage 1843 self->scriptID, // actualPage 1844 self->scriptID, // page 1845 self->scriptID // showPage 1846 ]; 1847 [_resp appendContentString:n]; 1848 [n release]; 1849 1850 n = [[StrClass alloc] initWithFormat: 1851 @"function flushImages%@() {\n" 1852 @" document.images[\"firstPageImg%@\"].src = First%@.src;\n" 1853 @" document.images[\"previousPageImg%@\"].src = Previous%@.src;\n" 1854 @" document.images[\"nextPageImg%@\"].src = Next%@.src;\n" 1855 @" document.images[\"lastPageImg%@\"].src = Last%@.src;\n" 1856 @" if (actualPage%@ == 1) {\n" 1857 @" document.images[\"firstPageImg%@\"].src = First2%@.src;\n" 1858 @" document.images[\"previousPageImg%@\"].src = Previous2%@.src;\n" 1859 @" }\n" 1860 1861#if 0 1862 @" if (actualPage%@ == 2) {\n" 1863 @" document.images[\"firstPageImg%@\"].src = First2%@.src;\n" 1864 @" }\n" 1865 @" if (actualPage%@ == page%@.length -2) {\n" 1866 @" document.images[\"lastPageImg%@\"].src = Last2%@.src;\n" 1867 @" }\n" 1868#endif 1869 1870 @" if (actualPage%@ == page%@.length - 1) {\n" 1871 @" document.images[\"nextPageImg%@\"].src = Next2%@.src;\n" 1872 @" document.images[\"lastPageImg%@\"].src = Last2%@.src;\n" 1873 @" }\n" 1874 @"}\n", 1875 self->scriptID, // flushImages 1876 self->scriptID, // firstPageImg 1877 self->scriptID, // First 1878 self->scriptID, // previousPageImg 1879 self->scriptID, // Previous 1880 self->scriptID, // nextPageImg 1881 self->scriptID, // Next 1882 self->scriptID, // lastPageImg 1883 self->scriptID, // Last 1884 self->scriptID, // actualPage 1885 self->scriptID, // firstPageImg 1886 self->scriptID, // First2 1887 self->scriptID, // previousPageImg 1888 self->scriptID, // Previous2 1889 1890#if 0 1891 self->scriptID, // actualPage 1892 self->scriptID, // firstPageImg 1893 self->scriptID, // First2 1894 1895 self->scriptID, // actualPage 1896 self->scriptID, // page 1897 self->scriptID, // lastPageImg 1898 self->scriptID, // Last2 1899#endif 1900 1901 self->scriptID, // actualPage 1902 self->scriptID, // page 1903 self->scriptID, // nextPageImg, 1904 self->scriptID, // Next2 1905 self->scriptID, // lastPageImg 1906 self->scriptID // Last2 1907 ]; 1908 [_resp appendContentString:n]; 1909 [n release]; 1910 1911 n = [[StrClass alloc] initWithFormat: 1912 @"var page%@ = new Array();\n" 1913 @"var footer%@ = new Array();\n" 1914 @"var actualPage%@ = %d;", 1915 self->scriptID, // page 1916 self->scriptID, // footer 1917 self->scriptID, //actualPage 1918 self->state->currentBatch 1919 ]; 1920 [_resp appendContentString:n]; 1921 [n release]; 1922 1923 { 1924 unsigned i; 1925 1926 for (i = 1; i <= self->state->batchCount; i++) { 1927 n = [[StrClass alloc] initWithFormat: 1928 @"page%@[%d] = new Array();\n" 1929 @"page%@[%d][\"Div\"] = page%dDiv%@;\n\n" 1930 @"footer%@[%d] = new Array();\n" 1931 @"footer%@[%d][\"Div\"] = footer%dDiv%@;\n\n", 1932 self->scriptID, // page 1933 i, // page[i] 1934 self->scriptID, // page 1935 i, // page[i] 1936 i, // pageiDiv 1937 self->scriptID, // pageDiv 1938 self->scriptID, // footer 1939 i, // footer[i] 1940 self->scriptID, // footer 1941 i, // footer[i] 1942 i, // footeriDiv 1943 self->scriptID // footerDiv 1944 ]; 1945 [_resp appendContentString:n]; 1946 [n release]; 1947 } 1948 } 1949 n = [[StrClass alloc] initWithFormat:@"showPage%@();", self->scriptID]; 1950 [_resp appendContentString:n]; 1951 [n release]; 1952 1953 [_resp appendContentString:@"//-->\n</script>\n"]; 1954} 1955 1956- (void)_appendTableContentAsScript:(WOResponse *)_resp 1957 inContext:(WOContext *)_ctx 1958{ 1959 WOComponent *cmp; 1960 unsigned i, savedBatchIndex; 1961 1962 cmp = [_ctx component]; 1963 1964 savedBatchIndex = self->state->currentBatch; 1965 /* open header + data area */ 1966 [_resp appendContentString:@"<tr><td>"]; 1967 1968 for (i = 1; i <= self->state->batchCount; i++) { 1969 NSString *s; 1970 1971 self->state->currentBatch = i; 1972 _applyState_(self, cmp); 1973 [self updateStateInContext:_ctx]; 1974 1975 s = [[StrClass alloc] initWithFormat: // <DIV...> 1976 @"<div id=\"page%dDiv%@\" style=\"display: ; \">", i, self->scriptID]; 1977 [_resp appendContentString:s]; 1978 [s release]; 1979 1980 [_resp appendContentString: 1981 @"<table border='0' width='100%' cellpadding='1' cellspacing='0'>"]; 1982 1983 [self _appendHeader:_resp inContext:_ctx]; 1984 [self _appendData:_resp inContext:_ctx]; 1985 1986 [_resp appendContentString:@"</table>"]; 1987 [_resp appendContentString:@"</div>"]; // </DIV> 1988 1989 1990 /* append footer */ 1991 s = [[StrClass alloc] initWithFormat: // <DIV...> 1992 @"<div id=\"footer%dDiv%@\" style=\"display: ; \">", i, self->scriptID]; 1993 [_resp appendContentString:s]; 1994 [s release]; 1995 1996 [self _appendFooter:_resp inContext:_ctx]; 1997 1998 [_resp appendContentString:@"</div>"]; // </DIV> 1999 } 2000 2001 /* close header + data area */ 2002 [_resp appendContentString:@"</td></tr>"]; 2003 if (self->state->currentBatch != savedBatchIndex) { 2004 self->state->currentBatch = savedBatchIndex; 2005 _applyState_(self, cmp); 2006 } 2007 [self updateStateInContext:_ctx]; 2008} 2009 2010- (void)_appendScriptLink:(WOResponse *)_response name:(NSString *)_name { 2011 NSString *s; 2012 2013 [_response appendContentString:@"JavaScript:"]; 2014 [_response appendContentString:_name]; 2015 s = [[StrClass alloc] initWithFormat:@"Page%@();", self->scriptID]; 2016 [_response appendContentString:s]; 2017 [s release]; 2018} 2019 2020- (void)_appendScriptImgName:(WOResponse *)_response name:(NSString *)_name { 2021 [_response appendContentString:_name]; 2022 [_response appendContentString:@"PageImg"]; 2023 [_response appendContentString:self->scriptID]; 2024} 2025 2026@end /* WETableView(JavaScriptAdditions) */ 2027