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 "WECalendarField.h"
23#include <NGObjWeb/WEClientCapabilities.h>
24#include "common.h"
25
26static Class StrClass = Nil;
27
28@implementation WECalendarField
29
30+ (void)initialize {
31  StrClass = [NSString class];
32}
33
34static NSString *retStrForInt(int i) {
35  // TODO: find out good statics
36  return [[StrClass alloc] initWithFormat:@"%i", i];
37}
38static NSString *retStr02ForInt(int i) {
39  switch (i) { // TODO: find out a good count ...
40  case 0:  return @"00";
41  case 1:  return @"01";
42  case 2:  return @"02";
43  case 3:  return @"03";
44  case 4:  return @"04";
45  case 5:  return @"05";
46  case 6:  return @"06";
47  case 7:  return @"07";
48  case 8:  return @"08";
49  case 9:  return @"09";
50  default:
51    // TODO: add log ...
52    return [[StrClass alloc] initWithFormat:@"%02i", i];
53  }
54}
55
56- (id)initWithName:(NSString *)_name
57  associations:(NSDictionary *)_config
58  template:(WOElement *)_subs
59{
60  if ((self = [super initWithName:_name associations: _config template:_subs])) {
61    self->name           = OWGetProperty(_config, @"name");
62    self->date           = OWGetProperty(_config, @"date");
63
64    // time field associations
65    self->hour           = OWGetProperty(_config, @"hour");
66    self->minute         = OWGetProperty(_config, @"minute");
67    self->second         = OWGetProperty(_config, @"second");
68    self->useTextField   = OWGetProperty(_config, @"useTextField");
69    self->hourInterval   = OWGetProperty(_config, @"hourInterval");
70    self->minuteInterval = OWGetProperty(_config, @"minuteInterval");
71    self->secondInterval = OWGetProperty(_config, @"secondInterval");
72
73    // date field associations
74    self->year           = OWGetProperty(_config, @"year");
75    self->month          = OWGetProperty(_config, @"month");
76    self->day            = OWGetProperty(_config, @"day");
77    self->format         = OWGetProperty(_config, @"format");
78
79    self->template = [_subs retain];
80  }
81  return self;
82}
83
84- (void)dealloc {
85  [self->name release];
86  [self->date release];
87
88  /* time field associations */
89  [self->hour           release];
90  [self->minute         release];
91  [self->second         release];
92  [self->useTextField   release];
93  [self->hourInterval   release];
94  [self->minuteInterval release];
95  [self->secondInterval release];
96
97  /* date field associations */
98  [self->year   release];
99  [self->month  release];
100  [self->day    release];
101  [self->format release];
102
103  [self->template release];
104  [super dealloc];
105}
106
107- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
108  [self _takeValuesFromTimeFieldRequest:_rq inContext:_ctx];
109  [self _takeValuesFromDateFieldRequest:_rq inContext:_ctx];
110}
111
112- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
113  id result = nil;
114
115  result = [self _invokeActionForTimeFieldRequest:_rq inContext:_ctx];
116  if (result == nil)
117    result = [self _invokeActionForDateFieldRequest:_rq inContext:_ctx];
118
119  return result;
120}
121
122- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
123  if ([_ctx isRenderingDisabled]) {
124    [self->template appendToResponse:_response inContext:_ctx];
125    return;
126  }
127
128  [_response appendContentString:
129             @"<table border='0' cellpadding='0' cellspacing='0'>"
130             @"<tr>"
131             @"<td align='left' valign='bottom'>"];
132  [self _appendTimeFieldToResponse:_response inContext:_ctx];
133
134  [_response appendContentString:
135             @"</td>"
136             @"<td align='left' valign='bottom'>"];
137
138  [self _appendDateFieldToResponse:_response inContext:_ctx];
139
140  [_response appendContentString:
141             @"</td>"
142             @"</tr>"
143             @"</table>"];
144}
145
146@end /* WECalendarField */
147
148@implementation WECalendarField(WETimeFieldImplementation)
149
150/* Private Methodes */
151
152- (NSString *)_divIDAndScriptInContext:(WOContext *)_ctx
153  response:(WOResponse *)_response
154{
155  int divCount;
156
157  divCount = [[_ctx valueForKey: @"WETimeFieldScript"] intValue];
158  if (divCount == 0) {
159    [_response appendContentString:
160      @"<style type=\"text/css\">\n"
161      @"A.DDLlink { width: 23px; font: normal 10pt Arial; color: "
162      @"#6F1537; text-decoration: none; } \n"
163      @"A.DDLlink:hover { color: red; background: #FAE8B8; } \n"
164      @"</style>"];
165    [_response appendContentString:
166      @"<script language=\"JavaScript\">\n"
167      @"var DDLlayerCount = 1000;\n"
168      @"function DDLopen(layerObj,el) {\n"
169      @"  if (layerObj.style.visibility == 'hidden') {\n"
170      @"    layerObj.style.visibility = 'visible';\n"
171      @"    layerObj.style.zIndex     = DDLlayerCount;\n"
172      @"    formObj = DDLformField(el);\n"
173      @"    formObj.contentEditable = false;\n"
174      @"    DDLlayerCount++;\n"
175      @"    "
176      @"  } else { layerObj.style.visibility = 'hidden'; }\n"
177      @"}\n\n"
178      @"function DDLreturn(layerObj,el,value) {\n"
179      @"  formObj = DDLformField(el);\n"
180      @"  formObj.value = value;\n"
181      @"  formObj.contentEditable = true;\n"
182      @"  layerObj.style.visibility = 'hidden';\n"
183      @"}\n"
184      @"function DDLformField(el) {\n"
185      @"  for (i = 0; i < document.forms.length; i++)\n"
186      @"    for (j = 0; j < document.forms[i].elements.length; j++)\n"
187      @"      if (document.forms[i].elements[j].name == el)\n"
188      @"        return document.forms[i].elements[j];\n"
189      @"}\n"
190      @"</script>"];
191  }
192  [_ctx takeValue:[NSNumber numberWithInt:(divCount+1)]
193        forKey:@"WETimeFieldScript"];
194
195  return [StrClass stringWithFormat:@"dropDownDiv%i", divCount];
196}
197
198- (void)_appendSelectToResponse:(WOResponse *)_response
199  inContext:(WOContext *)_ctx
200  elementIDComponent:(NSString *)_elementIDComponent
201  count:(int)_count
202  selectedIndex:(int)_idx
203  interval:(int)_interval
204{
205  WEClientCapabilities *ccaps;
206  NSString *tmp;
207  int      i;
208  BOOL     isMSIE;
209  NSString *divID;
210  NSString *img;
211  NSString *elementId;
212
213  ccaps     = [[_ctx request] clientCapabilities];
214  isMSIE    = [ccaps isInternetExplorer];
215  elementId = [self elementIdWithSuffix:_elementIDComponent ctx:_ctx];
216
217  divID = [self _divIDAndScriptInContext:_ctx response:_response];
218
219  img = WEUriOfResource(@"downstairs.gif", _ctx);
220
221  if (isMSIE && img) {
222    NSString *s;
223
224    [_response appendContentString:@"<input readonly=\"readonly\" name=\""];
225    [_response appendContentString:elementId];
226    [_response appendContentString:@"\" value=\""];
227
228    s = retStr02ForInt(_idx);
229    [_response appendContentHTMLAttributeValue:s];
230    [s release];
231
232    [_response appendContentString:
233                 @"\" type=\"text\" size=\"2\" maxlength=\"2\""];
234#if 0
235    [_response appendContentString:@" style=\"background-color: #FFDAAA;\""];
236#endif
237    [_response appendContentString:@" /><img border=\"0\" src=\""];
238    [_response appendContentString:img];
239    [_response appendContentString:@"\" onClick=\""];
240    [_response appendContentString:@"javascript:DDLopen("];
241    [_response appendContentString:divID];
242    [_response appendContentString:@",'"];
243    [_response appendContentString:elementId];
244    [_response appendContentString:@"')\" /><br />"];
245    [_response appendContentString:@"<div id=\""];
246    [_response appendContentString:divID];
247    [_response appendContentString:
248      @"\" style=\"position: absolute; overflow: auto; height: 150; width: 47;"
249      @" background: #FFDAAA; border: 1 solid; "
250      @"visibility: hidden; padding: 0 0 0 2;\">"];
251  }
252  else {
253    [_response appendContentString:@"<select name=\""];
254    [_response appendContentString:elementId];
255    [_response appendContentString:@"\">"];
256  }
257
258  for (i = 0; i <= _count; i += _interval) {
259    tmp = retStr02ForInt(i);
260    if (isMSIE && img) {
261      NSString *s;
262
263      s = [[StrClass alloc] initWithFormat:
264         @"<a class=\"DDLlink\" href=\"javascript:DDLreturn(%@,'%@','%@')\">%@"
265         @"</a><br />",
266                    divID, elementId, tmp, tmp];
267      [_response appendContentString:s];
268      [s release];
269    }
270    else {
271      [_response appendContentString:@"<option value=\""];
272      [_response appendContentString:tmp];
273      [_response appendContentString:@"\""];
274      [_response appendContentString:
275                   (i == _idx) ? @" selected=\"selected\"" : @""];
276      [_response appendContentString:@">"];
277      [_response appendContentString:tmp];
278      [_response appendContentString:@"</option>"];
279    }
280    [tmp release]; tmp = nil;
281  }
282
283  if (isMSIE && img)
284    [_response appendContentString:@"</div>"];
285  else
286    [_response appendContentString:@"</select>"];
287}
288
289/* handle request */
290
291- (void)_takeValuesFromTimeFieldRequest:(WORequest *)_request
292  inContext:(WOContext *)_ctx
293{
294  WOComponent *comp;
295  id          formValue;
296  BOOL        tuseTField;
297  NSString    *elementId;
298  NSArray     *ta;
299  int         idx;
300
301  comp = [_ctx component];
302  tuseTField = self->useTextField
303    ? [[self->useTextField valueInComponent: comp] boolValue]
304    : NO;
305
306  if (tuseTField) {
307    // TextField value
308    elementId = [self elementIdWithSuffix:@"" ctx:_ctx];
309    if ((formValue = [_request formValueForKey:elementId])) {
310      int intValue, cnt;
311
312      ta = [formValue componentsSeparatedByString:@":"];
313      cnt = [ta count];
314
315      idx = 0;
316      if ([self isHourSettable]) {
317        intValue = (idx < cnt) ? [[ta objectAtIndex:idx] intValue] : 0;
318        [self setHour:intValue inComponent:comp];
319        idx++;
320      }
321      if ([self isMinuteSettable]) {
322        intValue = (idx < cnt) ? [[ta objectAtIndex:idx] intValue] : 0;
323        [self setMinute:intValue inComponent:comp];
324        idx++;
325      }
326      if ([self isSecondSettable]) {
327        intValue = (idx < cnt) ? [[ta objectAtIndex:idx] intValue] : 0;
328        [self setSecond:intValue inComponent:comp];
329      }
330    }
331  }
332  else {
333    elementId = [self elementIdWithSuffix:@"hour" ctx:_ctx];
334    if ((formValue = [_request formValueForKey:elementId])) {
335      if ([self isHourSettable])
336        [self setHour:[formValue intValue] inComponent:comp];
337    }
338
339    elementId = [self elementIdWithSuffix:@"minute" ctx:_ctx];
340    if ((formValue = [_request formValueForKey:elementId])) {
341      if ([self isMinuteSettable])
342        [self setMinute:[formValue intValue] inComponent:comp];
343    }
344
345    elementId = [self elementIdWithSuffix:@"second" ctx:_ctx];
346    if ((formValue = [_request formValueForKey:elementId])) {
347      if ([self isSecondSettable])
348        [self setSecond:[formValue intValue] inComponent:comp];
349    }
350  }
351
352  /* template */
353  [_ctx appendElementIDComponent:@"timeField"];
354  [self->template takeValuesFromRequest:_request inContext:_ctx];
355  [_ctx deleteLastElementIDComponent];
356}
357
358- (id)_invokeActionForTimeFieldRequest:(WORequest *)_rq
359  inContext:(WOContext *)_ctx
360{
361  return [self->template invokeActionForRequest:_rq inContext:_ctx];
362}
363
364/* generate response */
365
366- (void)_appendTimeFieldToResponse:(WOResponse *)_r inContext:(WOContext *)_cx{
367  WOComponent    *comp;
368  BOOL           tuseTField;
369  int            hourInt;        // hourInterval
370  int            minuteInt;      // minuteInterval
371  int            secondInt;      // secondInterval
372  NSMutableArray *ta;
373
374  comp  = [_cx component];
375
376  hourInt = self->hourInterval
377    ? [self->hourInterval intValueInComponent:comp] : 1;
378
379  minuteInt = self->minuteInterval
380    ? [self->minuteInterval intValueInComponent:comp] : 1;
381
382  secondInt = self->secondInterval
383    ? [self->secondInterval intValueInComponent:comp] : 1;
384
385  tuseTField = self->useTextField
386    ? [self->useTextField boolValueInComponent:comp]
387    : NO;
388
389  // template
390  [_cx appendElementIDComponent:@"timeField"];
391  [self->template appendToResponse:_r inContext:_cx];
392  [_cx deleteLastElementIDComponent];
393
394  // all values in one textField
395  if (tuseTField) {
396    int h, m, s;
397    NSString *tmp, *fmt;
398    // build string of values and @":"
399
400    h = [self   hourInComponent:comp];
401    m = [self minuteInComponent:comp];
402    s = [self secondInComponent:comp];
403
404    ta = [[NSMutableArray alloc] initWithCapacity: 3];
405    fmt = @"%02i";
406
407    if ([self hasHourInComponent:comp]) {
408      tmp = retStr02ForInt(h);
409      [ta addObject:tmp];
410      [tmp release];
411    }
412    if ([self hasMinuteInComponent:comp]) {
413      tmp = [[StrClass alloc] initWithFormat:fmt, m];
414      [ta addObject:tmp];
415      [tmp release];
416    }
417    if ([self hasSecondInComponent:comp]) {
418      tmp = [[StrClass alloc] initWithFormat:fmt, s];
419      [ta addObject:tmp];
420      [tmp release];
421    }
422
423    tmp = [ta componentsJoinedByString:@":"];
424    [ta release]; ta = nil;
425
426    /* append to response */
427    if ([tmp isNotEmpty]) {
428      [_r appendContentString:@"<input type=\"text\" name=\""];
429      [_r appendContentString:[self elementIdWithSuffix:@"" ctx:_cx]];
430      [_r appendContentString:@"\" value=\""];
431      [_r appendContentString:tmp];
432      [_r appendContentString:@"\""];
433
434      tmp = retStrForInt([tmp length]);
435      [_r appendContentString:@" size=\""];
436      [_r appendContentString:tmp];
437      [_r appendContentString:@"\" maxlength=\""];
438      [_r appendContentString:tmp];
439      [_r appendContentString:@"\""];
440      [tmp release];
441
442      [_r appendContentString:@" />"];
443    }
444  }
445  else {
446    // hour select field
447    [_r appendContentString:
448	  @"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>"];
449
450    if ([self hasHourInComponent:comp]) {
451      [_r appendContentString:@"<td valign=\"bottom\">"];
452      [self _appendSelectToResponse:_r inContext:_cx
453	    elementIDComponent:@"hour"
454            count:23 selectedIndex:[self hourInComponent:comp]
455            interval:hourInt];
456      [_r appendContentString:@"</td>"];
457    }
458
459    // minute select field
460    if ([self hasMinuteInComponent:comp]) {
461      [_r appendContentString:@"<td valign=\"bottom\">"];
462      [self _appendSelectToResponse:_r inContext:_cx
463	    elementIDComponent:@"minute"
464            count:59 selectedIndex:[self minuteInComponent:comp]
465            interval:minuteInt];
466      [_r appendContentString:@"</td>"];
467    }
468
469    // second select field
470    if ([self hasSecondInComponent:comp]) {
471      [_r appendContentString:@"<td valign=\"bottom\">"];
472      [self _appendSelectToResponse:_r inContext:_cx
473            elementIDComponent:@"second"
474            count:59 selectedIndex:[self secondInComponent:comp]
475            interval:secondInt];
476      [_r appendContentString:@"</td>"];
477    }
478    [_r appendContentString:@"</tr></table>"];
479
480  } /* end of (!tuseTField) */
481}
482
483@end /* WECalendarField(WETimeFieldImplementation */
484
485@implementation WECalendarField(WEDateFieldImplementation)
486
487- (void)_takeValuesFromDateFieldRequest:(WORequest *)_request
488  inContext:(WOContext *)_ctx
489{
490  NSString       *tformat;
491  NSCalendarDate *tdate;
492  int            tyear;
493  int            tmonth;
494  int            tday;
495  WOComponent    *comp;
496  NSString       *elementId;
497
498  comp = [_ctx component];
499
500  tformat = [self->format stringValueInComponent: comp];
501  if (tformat == nil) tformat = @"%Y-%m-%d";
502  elementId = [self elementIdWithSuffix:@"" ctx:_ctx];
503
504  if ([self isKindOfClass:[WECalendarField class]]) {
505    id t = tformat;
506
507    t = [[t componentsSeparatedByString:@"%H"] componentsJoinedByString:@""];
508    t = [[t componentsSeparatedByString:@"%M"] componentsJoinedByString:@""];
509    t = [[t componentsSeparatedByString:@"%S"] componentsJoinedByString:@""];
510
511    tformat = t;
512  }
513
514  tdate = [NSCalendarDate dateWithString:
515                          [_request formValueForKey:elementId]
516                          calendarFormat: tformat];
517  if (tdate == nil) {
518    NSLog(@"WARNING: WEDateField: field value and format do not match!");
519  }
520  else {
521    tyear  = [tdate yearOfCommonEra];
522    tmonth = [tdate monthOfYear];
523    tday   = [tdate dayOfMonth];
524
525
526    if ([self isYearSettable])  [self  setYear:tyear  inComponent:comp];
527    if ([self isMonthSettable]) [self setMonth:tmonth inComponent:comp];
528    if ([self isDaySettable])   [self   setDay:tday   inComponent:comp];
529  }
530
531  [_ctx appendElementIDComponent:@"dateField"];
532  [self->template takeValuesFromRequest:_request inContext:_ctx];
533  [_ctx deleteLastElementIDComponent];
534}
535
536- (id)_invokeActionForDateFieldRequest:(WORequest *)_request
537  inContext:(WOContext *)_ctx
538{
539  return [self->template invokeActionForRequest:_request inContext:_ctx];
540}
541
542- (void)_appendDateFieldToResponse:(WOResponse *)_response
543  inContext:(WOContext *)_ctx
544{
545  WEClientCapabilities *ccaps;
546  int            tyear;
547  int            tmonth;
548  int            tday;
549  NSString       *tformat;
550  NSString       *tmp;
551  WOComponent    *comp;
552  NSCalendarDate *tdate;
553  NSString       *calendarDivID;
554  int            calendarID;
555  BOOL           isMSIE;
556  NSString       *value;
557
558  ccaps  = [[_ctx request] clientCapabilities];
559  comp   = [_ctx component];
560  tdate  = [NSCalendarDate calendarDate];
561  isMSIE = [ccaps isInternetExplorer];
562
563  if (![_ctx valueForKey:@"WEDateFieldScriptDone"])
564    [WEDateFieldScript appendWEDateFieldScriptToResponse: _response
565      inContext: _ctx
566      headBackground: HEAD_BACKGROUND_COLOR
567      headColor:      HEAD_COLOR
568      headNavColor:   HEAD_NAVIGATION_COLOR
569      labels:         nil
570      useImages:      NO];
571
572  // associations
573  tyear = ([self hasYearInComponent:comp])
574    ? [self yearInComponent:comp]
575    : [tdate yearOfCommonEra];
576  tmonth = ([self hasMonthInComponent:comp])
577    ? [self monthInComponent:comp]
578    : [tdate monthOfYear];
579  tday = ([self hasDayInComponent:comp])
580    ? [self dayInComponent:comp]
581    : [tdate dayOfMonth];
582  tformat    = self->format
583    ? [self->format stringValueInComponent: comp]
584    : (NSString *)@"%Y-%m-%d";
585
586  if ([self isKindOfClass:[WECalendarField class]]) {
587    id t = tformat;
588
589    t = [[t componentsSeparatedByString:@"%H"] componentsJoinedByString:@""];
590    t = [[t componentsSeparatedByString:@"%M"] componentsJoinedByString:@""];
591    t = [[t componentsSeparatedByString:@"%S"] componentsJoinedByString:@""];
592
593    tformat = t;
594  }
595
596  // input field value
597  tdate = [NSCalendarDate dateWithYear: tyear
598                          month:        tmonth
599                          day:          tday
600                          hour: 0 minute: 0 second: 0
601                          timeZone: [tdate timeZone]];
602
603  value = [tdate descriptionWithCalendarFormat: tformat];
604
605  // div id for javascript calendar
606  calendarID = ([_ctx valueForKey: @"WEDateField_DivID"])
607     ? [[_ctx valueForKey: @"WEDateField_DivID"] intValue]
608     : 0;
609  calendarDivID = [StrClass stringWithFormat:@"calendarDiv%d", calendarID];
610  calendarID++;
611  [_ctx takeValue:[NSNumber numberWithInt: calendarID]
612        forKey:@"WEDateField_DivID"];
613
614  // template
615  [_ctx appendElementIDComponent:@"dateField"];
616  [self->template appendToResponse:_response inContext:_ctx];
617  [_ctx deleteLastElementIDComponent];
618
619  [_response appendContentString:
620             @"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">"];
621  [_response appendContentString:
622             @"<td valign=\"top\" align=\"left\">"];
623
624  // input field
625  [_response appendContentString:@"<input type=\"text\" name=\""];
626  [_response appendContentString:[self elementIdWithSuffix:@"" ctx:_ctx]];
627  [_response appendContentString:@"\" value=\""];
628  [_response appendContentString:value];
629  [_response appendContentString:@"\" size=\""];
630  [_response appendContentString:
631             [[NSNumber numberWithInt: [value length]] stringValue]];
632  [_response appendContentString:@"\" maxlength=\""];
633  [_response appendContentString:
634             [[NSNumber numberWithInt: [value length]] stringValue]];
635  [_response appendContentString:@"\" />"];
636
637  /* link to calendar panel */
638  [_response appendContentString:  @" <a href=\"javascript:doNothing()\" "];
639  [_response appendContentString: @"onClick=\""];
640  tmp = @"javascript:%@toggleCalendar('%@',%@%@,'%@')";
641  tmp = [[StrClass alloc] initWithFormat: tmp,
642              (isMSIE) ? @"" : @"actPos;",                  // layer position
643              [self elementIdWithSuffix:@"" ctx:_ctx],      // form element
644              (isMSIE) ? @"" : @"document.", calendarDivID, // calendar DIV
645              tformat];                                     // dateFormat
646  [_response appendContentString: tmp];
647  [tmp release];
648  [_response appendContentString: @"\">"];
649
650  // calendar image
651  tmp = WEUriOfResource(@"icon_popupcalendar.gif", _ctx);
652
653  if (tmp) {
654    tmp = [[StrClass alloc] initWithFormat:
655                              @"<img border=\"0\" src=\"%@\" />", tmp];
656  }
657  else
658    tmp = @"x";
659
660  [_response appendContentString:tmp];
661  [tmp release];
662
663  [_response appendContentString: @"</a><br />"];
664
665  /* calendar panel */
666  [_response appendContentString: @"<div id=\""];
667  [_response appendContentString: calendarDivID];
668  [_response appendContentString: @"\" style=\"position: absolute; "];
669  [_response appendContentString: @"visibility: "];
670  [_response appendContentString: (isMSIE) ? @"hidden" : @"hide"];
671  [_response appendContentString: @";\"></div>"];
672
673  [_response appendContentString: @"</td></tr></table>"];
674}
675
676@end /* WECalendarField(WEDateFieldImplementation) */
677
678@implementation WEDateFieldScript
679
680- (id)initWithName:(NSString *)_name
681   associations:(NSDictionary *)_config
682   template:    (WOElement *)_subs
683{
684  if ((self = [super initWithName:_name associations: _config template:_subs]))
685  {
686    self->headBackground = OWGetProperty(_config, @"headBackground");
687    self->headColor      = OWGetProperty(_config, @"headColor");
688    self->headNavColor   = OWGetProperty(_config, @"headNavColor");
689    self->labels         = OWGetProperty(_config, @"labels");
690    self->useImages      = OWGetProperty(_config, @"useImages");
691  }
692  return self;
693}
694
695- (void)dealloc {
696  [self->useImages      release];
697  [self->headBackground release];
698  [self->headColor      release];
699  [self->headNavColor   release];
700  [self->labels         release];
701  [super dealloc];
702}
703
704
705+ (void)appendWEDateFieldScriptToResponse: (WOResponse *)_response
706  inContext:      (WOContext *)_ctx
707  headBackground: (NSString *)_hBack
708  headColor:      (NSString *)_hCol
709  headNavColor:   (NSString *)_hNav
710  labels:         (id)_labels
711  useImages:      (BOOL)_useImg
712{
713  NSString *tmp;
714  NSString *tmon;
715  NSString *tweek;
716  NSString *timg;
717
718  // images...
719  NSString *firstI;
720  NSString *prevI;
721  NSString *todayI;
722  NSString *nextI;
723  NSString *lastI;
724  NSString *closeI;
725
726  // colors
727  if (_hBack == nil) _hBack = HEAD_BACKGROUND_COLOR;
728  if (_hCol  == nil) _hCol  = HEAD_COLOR;
729  if (_hNav  == nil) _hNav  = HEAD_NAVIGATION_COLOR;
730
731  // months and weekdays
732  if (_labels   == nil) {
733    NSLog(@"WARNING: WEDateFieldScript: undefined variable 'labels'");
734    tmon  = @"var externMonths = false; \n";
735    tweek = @"var externWeekdays = false; \n";
736  }
737  else {
738    tmon = @"var externMonths = new Array("
739           @"\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\","
740           @"\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\"); \n";
741    tmon = [[StrClass alloc] initWithFormat: tmon,
742                     [_labels valueForKey: @"January"],
743                     [_labels valueForKey: @"February"],
744                     [_labels valueForKey: @"March"],
745                     [_labels valueForKey: @"April"],
746                     [_labels valueForKey: @"May"],
747                     [_labels valueForKey: @"June"],
748                     [_labels valueForKey: @"July"],
749                     [_labels valueForKey: @"August"],
750                     [_labels valueForKey: @"September"],
751                     [_labels valueForKey: @"October"],
752                     [_labels valueForKey: @"November"],
753                     [_labels valueForKey: @"December"]
754                     ];
755    tweek = @"var externWeekdays = new Array("
756            @"\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\"); \n";
757    tweek = [[StrClass alloc] initWithFormat: tweek,
758                      [_labels valueForKey: @"SundayAbbrev"],
759                      [_labels valueForKey: @"MondayAbbrev"],
760                      [_labels valueForKey: @"TuesdayAbbrev"],
761                      [_labels valueForKey: @"WednesdayAbbrev"],
762                      [_labels valueForKey: @"ThursdayAbbrev"],
763                      [_labels valueForKey: @"FridayAbbrev"],
764                      [_labels valueForKey: @"SaturdayAbbrev"]
765                      ];
766  }
767
768  if (![_ctx valueForKey: @"WEDateFieldScriptDone"]) {
769    tmp = @"<style type='text/css'>\n"
770          @"TD.heading { text-decoration: none; color: black; "
771            @"font: bold 8pt arial, helvetica; } \n "
772          @"A.focusDay { color: blue; text-decoration: none; "
773            @"font: 8pt arial, helvetica; } \n"
774          @"A.focusDay:hover { color:darkred; text-decoration: none; "
775            @"font: 8pt arial, helvetica; } \n"
776          @"A.weekday { color: blue; text-decoration: none; "
777            @"font: 8pt arial, helvetica; } \n"
778          @"A.weekday:hover { color: darkred; font: 8pt arial, helvetica; } \n"
779          @"A.navMonYear "
780            @"{ color: %@; text-decoration: none; font: 8pt Arial; }\n"
781          @"TD.topCal "
782            @"{ font: 10pt Arial; color: %@; background-color: %@; } \n"
783          @"</style>\n";
784    tmp = [StrClass stringWithFormat: tmp, _hNav, _hCol, _hBack];
785    [_response appendContentString: tmp];
786
787    [_response appendContentString:
788               @"<script language=\"JavaScript\">\n"];
789    [_response appendContentString: @"var dateFormat = \"%Y-%m-%d\"; \n"];
790    [_response appendContentString: tmon];
791    [_response appendContentString: tweek];
792
793    // navigation images
794    // doppelt haelt wirklich besser
795    firstI = WEUriOfResource(@"first.gif", _ctx);
796    prevI  = WEUriOfResource(@"previous.gif", _ctx);
797    todayI = WEUriOfResource(@"non_sorted.gif", _ctx);
798    nextI  = WEUriOfResource(@"next.gif", _ctx);
799    lastI  = WEUriOfResource(@"last.gif", _ctx);
800    closeI = WEUriOfResource(@"icon_unread.gif", _ctx);
801
802    if (_useImg) {
803      NSString *s;
804
805      timg = @"var %@=new Image(); %@.src='%@';\n"
806             @"var %@=\"<img border='0' name='%@' src='%@' />\";\n";
807      s = [[StrClass alloc] initWithFormat: timg,
808                  @"dateFieldFirst", @"dateFieldFirst", firstI,
809                  @"dateFieldFirstSRC", @"dateFieldFirstImg", firstI];
810      [_response appendContentString:s];
811      [s release];
812      s = [[StrClass alloc] initWithFormat: timg,
813                  @"dateFieldPrevious", @"dateFieldPrevious", prevI,
814                  @"dateFieldPreviousSRC", @"dateFieldPreviousImg", prevI];
815      [_response appendContentString:s];
816      [s release];
817      s = [[StrClass alloc] initWithFormat: timg,
818                  @"dateFieldToday", @"dateFieldToday", todayI,
819                  @"dateFieldTodaySRC", @"dateFieldTodayImg", todayI];
820      [_response appendContentString:s];
821      [s release];
822      s = [[StrClass alloc] initWithFormat: timg,
823                  @"dateFieldNext", @"dateFieldNext", nextI,
824                  @"dateFieldNextSRC", @"dateFieldNextImg", nextI];
825      [_response appendContentString:s];
826      [s release];
827      s = [[StrClass alloc] initWithFormat: timg,
828                  @"dateFieldLast", @"dateFieldLast", lastI,
829                  @"dateFieldLastSRC", @"dateFieldLastImg", lastI];
830      [_response appendContentString:s];
831      [s release];
832      s = [[StrClass alloc] initWithFormat: timg,
833                  @"dateFieldClose", @"dateFieldClose", closeI,
834                  @"dateFieldCloseSRC", @"dateFieldCloseImg", closeI];
835      [_response appendContentString:s];
836      [s release];
837      [_response appendContentString:@"var usesNavImages = true;\n"];
838    }
839    else {
840      [_response appendContentString:@"var dateFieldCloseSRC=\"X\";\n"];
841      [_response appendContentString:@"var dateFieldFirstSRC=\"&lt;&lt;\";\n"];
842      [_response appendContentString:@"var dateFieldPreviousSRC=\"&lt;\";\n"];
843      [_response appendContentString:@"var dateFieldTodaySRC=\"O\";\n"];
844      [_response appendContentString:@"var dateFieldNextSRC=\"&gt;\";\n"];
845      [_response appendContentString:@"var dateFieldLastSRC=\"&gt;&gt;\";\n"];
846      [_response appendContentString:@"var usesNavImages = false;\n"];
847    }
848
849    tmp =
850#include "calendar.jsm"
851      ;
852    [_response appendContentString: tmp];
853    [_response appendContentString: @"\n</script>"];
854
855    [_ctx takeValue: [NSNumber numberWithBool: YES]
856          forKey: @"WEDateFieldScriptDone"];
857  }
858
859  [tmon  release];
860  [tweek release];
861}
862
863- (void)appendToResponse: (WOResponse *)_response
864  inContext: (WOContext *)_ctx
865{
866  WOComponent *comp;
867
868  if ([_ctx isRenderingDisabled]) return;
869
870  comp = [_ctx component];
871
872  [[self class] appendWEDateFieldScriptToResponse: _response inContext:_ctx
873    headBackground: [self->headBackground stringValueInComponent:comp]
874    headColor:      [self->headColor      stringValueInComponent:comp]
875    headNavColor:   [self->headNavColor   stringValueInComponent:comp]
876    labels:         [self->labels               valueInComponent:comp]
877    useImages:      [[self->useImages valueInComponent: comp] boolValue]];
878}
879
880@end /* WEDateFieldScript */
881
882@implementation WECalendarField(Accessors)
883
884- (NSString *)elementIdWithSuffix:(NSString *)_suffix ctx:(WOContext *)_ctx {
885  NSString *prefix = nil;
886
887  if ((prefix = [self->name stringValueInComponent:[_ctx component]]) == nil)
888    prefix = [_ctx elementID];
889
890  if ([_suffix isNotEmpty])
891    prefix = [prefix stringByAppendingString:@"_"];
892
893  return [prefix stringByAppendingString:_suffix];
894}
895
896- (void)setSecond:(int)_second inComponent:(WOComponent *)_comp {
897  if (self->date) {
898    NSCalendarDate *d = [self->date valueInComponent:_comp];
899
900
901    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
902                        month:[d monthOfYear]
903                        day:[d dayOfMonth]
904                        hour:[d hourOfDay]
905                        minute:[d minuteOfHour]
906                        second:_second
907                        timeZone:[d timeZone]];
908
909    [self->date setValue:d inComponent:_comp];
910  }
911  else {
912    [self->second setIntValue:_second inComponent:_comp];
913  }
914}
915- (int)secondInComponent:(WOComponent *)_comp {
916  return (self->date != nil)
917    ? [[self->date valueInComponent:_comp] secondOfMinute]
918    : [self->second intValueInComponent:_comp];
919}
920
921- (void)setMinute:(int)_minute inComponent:(WOComponent *)_comp {
922  if (self->date) {
923    NSCalendarDate *d;
924
925    d = [self->date valueInComponent:_comp];
926    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
927                        month:[d monthOfYear]
928                        day:[d dayOfMonth]
929                        hour:[d hourOfDay]
930                        minute:_minute
931                        second:[d secondOfMinute]
932                        timeZone:[d timeZone]];
933
934    [self->date setValue:d inComponent:_comp];
935  }
936  else {
937    [self->minute setIntValue:_minute inComponent:_comp];
938  }
939}
940- (int)minuteInComponent:(WOComponent *)_comp {
941  return (self->date != nil)
942    ? [[self->date valueInComponent:_comp] minuteOfHour]
943    : [self->minute intValueInComponent:_comp];
944}
945
946- (void)setHour:(int)_hour inComponent:(WOComponent *)_comp {
947  if (self->date) {
948    NSCalendarDate *d = [self->date valueInComponent:_comp];
949
950
951    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
952                        month:[d monthOfYear]
953                        day:[d dayOfMonth]
954                        hour:_hour
955                        minute:[d minuteOfHour]
956                        second:[d secondOfMinute]
957                        timeZone:[d timeZone]];
958
959    [self->date setValue:d inComponent:_comp];
960  }
961  else {
962    [self->hour setIntValue:_hour inComponent:_comp];
963  }
964}
965- (int)hourInComponent:(WOComponent *)_comp {
966  return (self->date != nil)
967    ? [[self->date valueInComponent:_comp] hourOfDay]
968    : [self->hour intValueInComponent:_comp];
969}
970
971- (void)setDay:(int)_day inComponent:(WOComponent *)_comp {
972  if (self->date) {
973    NSCalendarDate *d = [self->date valueInComponent:_comp];
974
975    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
976                        month:[d monthOfYear]
977                        day:_day
978                        hour:[d hourOfDay]
979                        minute:[d minuteOfHour]
980                        second:[d secondOfMinute]
981                        timeZone:[d timeZone]];
982
983    [self->date setValue:d inComponent:_comp];
984  }
985  else {
986    [self->day setIntValue:_day inComponent:_comp];
987  }
988}
989- (int)dayInComponent:(WOComponent *)_comp {
990  return (self->date != nil)
991    ? [[self->date valueInComponent:_comp] dayOfMonth]
992    : [self->day intValueInComponent:_comp];
993}
994
995- (void)setMonth:(int)_month inComponent:(WOComponent *)_comp {
996  if (self->date) {
997    NSCalendarDate *d = [self->date valueInComponent:_comp];
998
999    d = [NSCalendarDate dateWithYear:[d yearOfCommonEra]
1000                        month:_month
1001                        day:[d dayOfMonth]
1002                        hour:[d hourOfDay]
1003                        minute:[d minuteOfHour]
1004                        second:[d secondOfMinute]
1005                        timeZone:[d timeZone]];
1006
1007    [self->date setValue:d inComponent:_comp];
1008  }
1009  else {
1010    [self->month setIntValue:_month inComponent:_comp];
1011  }
1012}
1013- (int)monthInComponent:(WOComponent *)_comp {
1014   return (self->date != nil)
1015    ? [[self->date valueInComponent:_comp] monthOfYear]
1016    : [self->month intValueInComponent:_comp];
1017}
1018
1019- (void)setYear:(int)_year inComponent:(WOComponent *)_comp {
1020  if (self->date) {
1021    NSCalendarDate *d = [self->date valueInComponent:_comp];
1022
1023    d = [NSCalendarDate dateWithYear:_year
1024                        month:[d monthOfYear]
1025                        day:[d dayOfMonth]
1026                        hour:[d hourOfDay]
1027                        minute:[d minuteOfHour]
1028                        second:[d secondOfMinute]
1029                        timeZone:[d timeZone]];
1030
1031    [self->date setValue:d inComponent:_comp];
1032  }
1033  else {
1034    [self->year setIntValue:_year inComponent:_comp];
1035  }
1036}
1037- (int)yearInComponent:(WOComponent *)_comp {
1038  return (self->date != nil)
1039    ? [[self->date valueInComponent:_comp] yearOfCommonEra]
1040    : [self->year intValueInComponent:_comp];
1041}
1042
1043- (BOOL)isSecondSettable {
1044  return (self->date != nil)
1045    ? [self->date isValueSettable] : [self->second isValueSettable];
1046}
1047
1048- (BOOL)isMinuteSettable {
1049  return (self->date != nil)
1050    ? [self->date isValueSettable] : [self->minute isValueSettable];
1051}
1052
1053- (BOOL)isHourSettable {
1054  return (self->date != nil)
1055    ? [self->date isValueSettable] : [self->hour isValueSettable];
1056}
1057
1058- (BOOL)isDaySettable {
1059  return (self->date != nil)
1060    ? [self->date isValueSettable] : [self->day isValueSettable];
1061}
1062
1063- (BOOL)isMonthSettable {
1064  return (self->date != nil)
1065    ? [self->date isValueSettable] : [self->month isValueSettable];
1066}
1067
1068- (BOOL)isYearSettable {
1069  return (self->date != nil)
1070    ? [self->date isValueSettable] : [self->year isValueSettable];
1071}
1072
1073- (BOOL)_chkDateFormatKey:(NSString *)_s inComponent:(WOComponent *)_comp {
1074  NSString *fmt;
1075
1076  if (self->format == nil)
1077    return YES;
1078
1079  fmt = [self->format stringValueInComponent:_comp];
1080  return ([fmt rangeOfString:_s].length > 0) ? YES : NO;
1081}
1082
1083- (BOOL)hasSecondInComponent:(WOComponent *)_comp {
1084  return (self->date)
1085    ? [self _chkDateFormatKey:@"S" inComponent:_comp]
1086    : (self->second != nil ? YES : NO);
1087}
1088
1089- (BOOL)hasMinuteInComponent:(WOComponent *)_comp {
1090  return (self->date)
1091    ? [self _chkDateFormatKey:@"M" inComponent:_comp]
1092    : (self->minute != nil ? YES : NO);
1093}
1094
1095- (BOOL)hasHourInComponent:(WOComponent *)_comp {
1096  return (self->date)
1097    ? [self _chkDateFormatKey:@"H" inComponent:_comp]
1098    : (self->hour != nil ? YES : NO);
1099}
1100
1101- (BOOL)hasDayInComponent:(WOComponent *)_comp {
1102  return (self->date)
1103    ? [self _chkDateFormatKey:@"d" inComponent:_comp]
1104    : (self->day != nil ? YES : NO);
1105}
1106
1107- (BOOL)hasMonthInComponent:(WOComponent *)_comp {
1108  return (self->date)
1109    ? [self _chkDateFormatKey:@"m" inComponent:_comp]
1110    : (self->month != nil ? YES : NO);
1111}
1112
1113- (BOOL)hasYearInComponent:(WOComponent *)_comp {
1114  return (self->date)
1115    ? [self _chkDateFormatKey:@"Y" inComponent:_comp]
1116    : (self->year != nil ? YES : NO);
1117}
1118
1119@end /* WECalendarField */
1120