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
24 #include <SOGoUI/UIxComponent.h>
26 @class NSMutableDictionary;
28 @interface UIxContactEditor : UIxComponent
30 NSString *contentString;
32 NSMutableDictionary *snapshot; /* contains the values for editing */
37 #include <Contacts/SOGoContactObject.h>
38 #include <Contacts/SOGoContactFolder.h>
41 @implementation UIxContactEditor
44 if ((self = [super init])) {
45 self->snapshot = [[NSMutableDictionary alloc] initWithCapacity:16];
51 [self->snapshot release];
52 [self->errorText release];
53 [self->contentString release];
59 - (void)setContentString:(NSString *)_cstr {
60 ASSIGNCOPY(self->contentString, _cstr);
62 - (NSString *)contentString {
63 return self->contentString;
66 - (NSString *)contentStringTemplate {
67 return @"{}"; /* empty property list */
70 - (NSMutableDictionary *)snapshot {
71 return self->snapshot;
74 - (void)setErrorText:(NSString *)_txt {
75 ASSIGNCOPY(self->errorText, _txt);
77 - (NSString *)errorText {
78 return self->errorText;
80 - (BOOL)hasErrorText {
81 return [self->errorText length] > 0 ? YES : NO;
84 /* load/store content format */
86 - (void)loadValuesFromContentString:(NSString *)_s {
89 if ((plist = [_s propertyList]) == nil) {
90 [self errorWithFormat:@"could not parse content string!"];
94 [self->snapshot removeAllObjects];
95 [self->snapshot addEntriesFromDictionary:plist];
98 - (void)_fixupSnapshot {
99 // TODO: perform sanity checking, eg build CN on demand
100 NSString *cn, *gn, *sn;
102 cn = [self->snapshot objectForKey:@"cn"];
103 gn = [self->snapshot objectForKey:@"givenName"];
104 sn = [self->snapshot objectForKey:@"sn"];
106 if (![sn isNotNull] || [sn length] == 0)
108 if (![cn isNotNull] || [cn length] == 0)
115 // TODO: need a better name parser here
118 r = [cn rangeOfString:@" "];
120 ? [cn substringFromIndex:(r.location + r.length)]
123 [self->snapshot setObject:sn forKey:@"sn"];
126 if (sn == nil && gn == nil)
133 cn = [[gn stringByAppendingString:@" "] stringByAppendingString:sn];
134 [self->snapshot setObject:cn forKey:@"cn"];
137 - (void)saveValuesIntoRecord:(NSMutableDictionary *)_record {
138 [self _fixupSnapshot];
139 [_record addEntriesFromDictionary:[self snapshot]];
144 - (NSString *)jsCopyContactCode {
145 static NSString *jsCode = \
146 @"function unescapeCallbackParameter(s) {\n"
147 @" if(!s || s.length == 0)\n"
149 @" s = s.replace(/'/g, \"'\");\n"
150 @" s = s.replace(/"/g, '\"');\n"
154 @"function copyContact()"
156 @" var type = arguments[0]; \n"
157 @" var email = arguments[1]; \n"
158 @" var uid = arguments[2]; \n"
159 @" var sn = arguments[3]; \n"
160 @" var givenName = arguments[4]; \n"
161 @" var telephoneNumber = arguments[5]; \n"
162 @" var facsimileTelephoneNumber = arguments[6]; \n"
163 @" var mobile = arguments[7]; \n"
164 @" var postalAddress = arguments[8]; \n"
165 @" var homePostalAddress = arguments[9]; \n"
166 @" var departmentNumber = arguments[10]; \n"
167 @" var l = arguments[11]; \n"
169 @" e = document.getElementById('email');\n"
170 @" e.setAttribute('value', email);\n"
171 @" e = document.getElementById('sn');\n"
172 @" e.setAttribute('value', unescapeCallbackParameter(sn));\n"
173 @" e = document.getElementById('givenName');\n"
174 @" e.setAttribute('value', unescapeCallbackParameter(givenName));\n"
175 @" e = document.getElementById('telephoneNumber');\n"
176 @" e.setAttribute('value', telephoneNumber);\n"
177 @" e = document.getElementById('facsimileTelephoneNumber');\n"
178 @" e.setAttribute('value', facsimileTelephoneNumber);\n"
179 @" e = document.getElementById('mobile');\n"
180 @" e.setAttribute('value', mobile);\n"
181 @" e = document.getElementById('postalAddress');\n"
182 @" e.setAttribute('value', unescapeCallbackParameter(postalAddress));\n"
183 @" e = document.getElementById('homePostalAddress');\n"
184 @" e.setAttribute('value', unescapeCallbackParameter(homePostalAddress));\n"
185 @" e = document.getElementById('departmentNumber');\n"
186 @" e.setAttribute('value', unescapeCallbackParameter(departmentNumber));\n"
187 @" e = document.getElementById('l');\n"
188 @" e.setAttribute('value', unescapeCallbackParameter(l));\n"
195 - (NSString *)_completeURIForMethod:(NSString *)_method {
196 // TODO: this is a DUP of UIxAppointmentEditor
200 uri = [[[self context] request] uri];
202 /* first: identify query parameters */
203 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
205 uri = [uri substringToIndex:r.location];
207 /* next: append trailing slash */
208 if (![uri hasSuffix:@"/"])
209 uri = [uri stringByAppendingString:@"/"];
211 /* next: append method */
212 uri = [uri stringByAppendingString:_method];
214 /* next: append query parameters */
215 return [self completeHrefForMethod:uri];
220 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
224 - (id)defaultAction {
225 // TODO: very similiar to apt-editor (apt editor would need to use std names
228 /* load iCalendar file */
230 c = [[self clientObject] contentAsString];
231 if ([c length] == 0) /* a new contact */
232 c = [self contentStringTemplate];
234 [self setContentString:c];
235 [self loadValuesFromContentString:c];
240 - (BOOL)isWriteableClientObject {
241 return [[self clientObject]
242 respondsToSelector:@selector(saveContentString:)];
250 if (![self isWriteableClientObject]) {
251 /* return 400 == Bad Request */
252 return [NSException exceptionWithHTTPStatus:400
253 reason:@"method cannot be invoked on "
254 @"the specified object"];
257 record = [[[[self contentString] propertyList] mutableCopy] autorelease];
259 [self setErrorText:@"Invalid property list data ..."]; // localize
263 [self saveValuesIntoRecord:record];
265 recstr = [record description]; // make plist
266 ex = [[self clientObject] saveContentString:recstr];
268 [self setErrorText:[ex reason]];
272 return [self redirectToLocation:[self _completeURIForMethod:@".."]];
276 [self logWithFormat:@"test ..."];
281 // TODO: this is almost a DUP of UIxAppointmentEditor
283 This method creates a unique ID and redirects to the "edit" method on the
285 It is actually a folder method and should be defined on the folder.
287 Note: 'clientObject' is the SOGoAppointmentFolder!
288 Update: remember that there are group folders as well.
290 NSString *uri, *objectId, *nextMethod;
292 objectId = [NSClassFromString(@"SOGoContactFolder") globallyUniqueObjectId];
293 if ([objectId length] == 0) {
294 return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
295 reason:@"could not create a unique ID"];
298 nextMethod = [NSString stringWithFormat:@"../%@/edit", objectId];
299 uri = [self _completeURIForMethod:nextMethod];
300 return [self redirectToLocation:uri];
303 @end /* UIxContactEditor */