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