2 Copyright (C) 2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #import "SOGoJSStringFormatter.h"
25 #import <NGObjWeb/SoHTTPAuthenticator.h>
26 #import <NGObjWeb/WOResourceManager.h>
28 #import <SOGo/NSString+URL.h>
30 #import <SOGo/SOGoUser.h>
31 #import <SOGo/SOGoObject.h>
32 #import <SOGo/SOGoCustomGroupFolder.h>
33 #import <SOGo/NSCalendarDate+SOGo.h>
35 #import "../Common/UIxJSClose.h"
37 #import "UIxComponent.h"
39 @interface UIxComponent (PrivateAPI)
40 - (void)_parseQueryString:(NSString *)_s;
41 - (NSMutableDictionary *)_queryParameters;
44 @implementation UIxComponent
46 static NSMutableArray *dayLabelKeys = nil;
47 static NSMutableArray *abbrDayLabelKeys = nil;
48 static NSMutableArray *monthLabelKeys = nil;
49 static NSMutableArray *abbrMonthLabelKeys = nil;
51 static BOOL uixDebugEnabled = NO;
54 return [super version] + 0 /* v2 */;
58 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
60 NSAssert2([super version] == 2,
61 @"invalid superclass (%@) version %i !",
62 NSStringFromClass([self superclass]), [super version]);
64 uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
66 if (dayLabelKeys == nil) {
67 dayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
68 [dayLabelKeys addObject:@"Sunday"];
69 [dayLabelKeys addObject:@"Monday"];
70 [dayLabelKeys addObject:@"Tuesday"];
71 [dayLabelKeys addObject:@"Wednesday"];
72 [dayLabelKeys addObject:@"Thursday"];
73 [dayLabelKeys addObject:@"Friday"];
74 [dayLabelKeys addObject:@"Saturday"];
76 abbrDayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
77 [abbrDayLabelKeys addObject:@"a2_Sunday"];
78 [abbrDayLabelKeys addObject:@"a2_Monday"];
79 [abbrDayLabelKeys addObject:@"a2_Tuesday"];
80 [abbrDayLabelKeys addObject:@"a2_Wednesday"];
81 [abbrDayLabelKeys addObject:@"a2_Thursday"];
82 [abbrDayLabelKeys addObject:@"a2_Friday"];
83 [abbrDayLabelKeys addObject:@"a2_Saturday"];
85 monthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
86 [monthLabelKeys addObject:@"January"];
87 [monthLabelKeys addObject:@"February"];
88 [monthLabelKeys addObject:@"March"];
89 [monthLabelKeys addObject:@"April"];
90 [monthLabelKeys addObject:@"May"];
91 [monthLabelKeys addObject:@"June"];
92 [monthLabelKeys addObject:@"July"];
93 [monthLabelKeys addObject:@"August"];
94 [monthLabelKeys addObject:@"September"];
95 [monthLabelKeys addObject:@"October"];
96 [monthLabelKeys addObject:@"November"];
97 [monthLabelKeys addObject:@"December"];
99 abbrMonthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
100 [abbrMonthLabelKeys addObject:@"a3_January"];
101 [abbrMonthLabelKeys addObject:@"a3_February"];
102 [abbrMonthLabelKeys addObject:@"a3_March"];
103 [abbrMonthLabelKeys addObject:@"a3_April"];
104 [abbrMonthLabelKeys addObject:@"a3_May"];
105 [abbrMonthLabelKeys addObject:@"a3_June"];
106 [abbrMonthLabelKeys addObject:@"a3_July"];
107 [abbrMonthLabelKeys addObject:@"a3_August"];
108 [abbrMonthLabelKeys addObject:@"a3_September"];
109 [abbrMonthLabelKeys addObject:@"a3_October"];
110 [abbrMonthLabelKeys addObject:@"a3_November"];
111 [abbrMonthLabelKeys addObject:@"a3_December"];
117 if ((self = [super init]))
127 [self->queryParameters release];
129 [_selectedDate release];
133 /* query parameters */
135 - (void) _parseQueryString: (NSString *) _s
140 NSString *key, *value;
142 e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
143 part = [e nextObject];
146 r = [part rangeOfString:@"="];
149 /* missing value of query parameter */
150 key = [part stringByUnescapingURL];
155 key = [[part substringToIndex:r.location] stringByUnescapingURL];
156 value = [[part substringFromIndex:(r.location + r.length)]
157 stringByUnescapingURL];
159 [self->queryParameters setObject:value forKey:key];
160 part = [e nextObject];
164 - (void) addKeepAliveFormValuesToQueryParameters
168 - (NSString *) queryParameterForKey: (NSString *) _key
170 return [[self _queryParameters] objectForKey:_key];
173 - (void) setQueryParameter: (NSString *) _param
174 forKey: (NSString *) _key
179 [[self _queryParameters] setObject: _param forKey: _key];
181 [[self _queryParameters] removeObjectForKey: _key];
185 - (NSMutableDictionary *) _queryParameters
187 // TODO: this code is weird, should use WORequest methods for parsing
193 if (self->queryParameters)
194 return self->queryParameters;
196 self->queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
198 req = [[self context] request];
200 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
203 qs = [uri substringFromIndex:NSMaxRange(r)];
204 [self _parseQueryString:qs];
207 /* add form values */
208 [self addKeepAliveFormValuesToQueryParameters];
210 return self->queryParameters;
213 - (NSDictionary *) queryParameters
215 return [self _queryParameters];
218 - (NSDictionary *) queryParametersBySettingSelectedDate: (NSCalendarDate *) _date
220 NSMutableDictionary *qp;
222 qp = [[self queryParameters] mutableCopy];
223 [self setSelectedDateQueryParameter:_date inDictionary:qp];
224 return [qp autorelease];
227 - (void) setSelectedDateQueryParameter: (NSCalendarDate *) _newDate
228 inDictionary: (NSMutableDictionary *) _qp
231 [_qp setObject: [self dateStringForDate: _newDate] forKey: @"day"];
233 [_qp removeObjectForKey:@"day"];
236 - (NSString *) completeHrefForMethod: (NSString *) _method
240 NSString *qs, *qps, *href;
242 qp = [self queryParameters];
245 ctx = [self context];
246 qps = [ctx queryPathSeparator];
247 [ctx setQueryPathSeparator: @"&"];
248 qs = [ctx queryStringFromDictionary: qp];
249 [ctx setQueryPathSeparator: qps];
250 href = [_method stringByAppendingFormat:@"?%@", qs];
258 - (NSString *) ownMethodName
263 uri = [[[self context] request] uri];
265 /* first: cut off query parameters */
267 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
269 uri = [uri substringToIndex:r.location];
271 /* next: strip trailing slash */
273 if ([uri hasSuffix: @"/"])
274 uri = [uri substringToIndex: ([uri length] - 1)];
275 r = [uri rangeOfString:@"/" options: NSBackwardsSearch];
277 /* then: cut of last path component */
279 if (r.length == 0) // no slash? are we at root?
282 return [uri substringFromIndex: (r.location + 1)];
285 - (NSString *) userFolderPath
288 NSString *url, *path;
289 NSEnumerator *objects;
290 SOGoObject *currentObject;
293 ctx = [self context];
294 objects = [[ctx objectTraversalStack] objectEnumerator];
295 currentObject = [objects nextObject];
299 if ([currentObject isKindOfClass: [SOGoUserFolder class]])
302 currentObject = [objects nextObject];
304 url = [currentObject baseURLInContext:ctx];
305 path = [[NSURL URLWithString:url] path];
310 - (NSString *) applicationPath
312 SOGoObject *currentClient, *parent;
315 Class objectClass, groupFolderClass, userFolderClass;
318 groupFolderClass = [SOGoCustomGroupFolder class];
319 userFolderClass = [SOGoUserFolder class];
321 currentClient = [self clientObject];
322 objectClass = [currentClient class];
323 found = (objectClass == groupFolderClass || objectClass == userFolderClass);
324 while (!found && currentClient)
326 parent = [currentClient container];
327 objectClass = [parent class];
328 if (objectClass == groupFolderClass
329 || objectClass == userFolderClass)
332 currentClient = parent;
335 ctx = [self context];
336 url = [currentClient baseURLInContext: ctx];
338 return [[NSURL URLWithString: url] path];
341 - (NSString *) resourcesPath
343 WOResourceManager *rm;
345 if ((rm = [self resourceManager]) == nil)
346 rm = [[WOApplication application] resourceManager];
348 return [rm webServerResourcesPath];
351 - (NSString *) ownPath
356 uri = [[[self context] request] uri];
358 /* first: cut off query parameters */
360 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
362 uri = [uri substringToIndex:r.location];
367 - (NSString *) relativePathToUserFolderSubPath: (NSString *) _sub
371 dst = [[self userFolderPath] stringByAppendingPathComponent:_sub];
372 rel = [dst urlPathRelativeToPath:[self ownPath]];
377 - (NSCalendarDate *) selectedDate
383 dateFromShortDateString: [self queryParameterForKey: @"day"]
384 andShortTimeString: [self queryParameterForKey: @"hm"]
385 inTimeZone: [[self clientObject] userTimeZone]];
386 [_selectedDate retain];
389 return _selectedDate;
392 - (NSString *) dateStringForDate: (NSCalendarDate *) _date
394 [_date setTimeZone: [[self clientObject] userTimeZone]];
396 return [_date descriptionWithCalendarFormat:@"%Y%m%d"];
401 return ([[self queryParameterForKey: @"noframe"] boolValue]);
404 - (UIxComponent *) jsCloseWithRefreshMethod: (NSString *) methodName
408 jsClose = [UIxJSClose new];
409 [jsClose autorelease];
410 [jsClose setRefreshMethod: methodName];
421 ctx = [self context];
423 return [[[self clientObject] authenticatorInContext: ctx] userInContext: ctx];
426 - (NSString *) shortUserNameForDisplay
428 // TODO: better use a SoUser formatter?
429 // TODO: who calls that?
433 // TODO: USE USER MANAGER INSTEAD!
435 s = [[self user] login];
439 // TODO: algorithm might be inappropriate, depends on the actual UID
441 r = [s rangeOfString:@"."];
445 return [s substringToIndex:r.location];
450 - (NSString *) labelForKey: (NSString *) _str
452 WOResourceManager *rm;
454 NSString *lKey, *lTable, *lVal;
457 if ([_str length] == 0)
460 /* lookup languages */
462 languages = [[self context] resourceLookupLanguages];
464 /* find resource manager */
466 if ((rm = [self pageResourceManager]) == nil)
467 rm = [[WOApplication application] resourceManager];
469 [self warnWithFormat:@"missing resource manager!"];
473 r = [_str rangeOfString:@"/"];
475 lTable = [_str substringToIndex:r.location];
476 lKey = [_str substringFromIndex:(r.location + r.length)];
484 if ([lKey hasPrefix:@"$"])
485 lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
487 if ([lTable hasPrefix:@"$"])
488 lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
491 if ([lVal hasPrefix:@"$"])
492 lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
497 return [rm stringForKey: lKey
499 withDefaultValue: lVal
500 languages: languages];
503 - (NSString *) localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
504 NSString *key = [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
505 return [self labelForKey:key];
508 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
509 NSString *key = [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
510 return [self labelForKey:key];
513 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
514 NSString *key = [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
515 return [self labelForKey:key];
518 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
519 NSString *key = [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
520 return [self labelForKey:key];
523 /* HTTP method safety */
525 - (BOOL)isInvokedBySafeMethod {
526 // TODO: move to WORequest?
529 m = [[[self context] request] method];
530 if ([m isEqualToString:@"GET"]) return YES;
531 if ([m isEqualToString:@"HEAD"]) return YES;
537 - (NSDictionary *)locale {
538 /* we need no fallback here, as locale is guaranteed to be set by sogod */
539 return [[self context] valueForKey:@"locale"];
542 - (WOResourceManager *) pageResourceManager
544 WOResourceManager *rm;
546 if ((rm = [[[self context] page] resourceManager]) == nil)
547 rm = [[WOApplication application] resourceManager];
552 - (NSString *) urlForResourceFilename: (NSString *) filename
554 static NSMutableDictionary *pageToURL = nil;
557 WOResourceManager *rm;
558 NSBundle *pageBundle;
563 pageToURL = [[NSMutableDictionary alloc] initWithCapacity: 32];
565 url = [pageToURL objectForKey: filename];
568 rm = [self pageResourceManager];
569 page = [[self context] page];
570 pageBundle = [NSBundle bundleForClass: [page class]];
571 url = [rm urlForResourceNamed: filename
572 inFramework: [pageBundle bundlePath]
574 request: [[self context] request]];
578 if ([url hasPrefix: @"http"])
579 url = [url hostlessURL];
580 [pageToURL setObject: url forKey: filename];
583 // NSLog (@"url for '%@': '%@'", filename, url);
593 - (BOOL)isUIxDebugEnabled {
594 return uixDebugEnabled;
597 @end /* UIxComponent */