]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Contacts/UIxContactEditor.m
Adapted to Anais1.11
[scalable-opengroupware.org] / SOGo / UI / Contacts / UIxContactEditor.m
1 /*
2   Copyright (C) 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
24 #include <SOGoUI/UIxComponent.h>
25
26 @class NSMutableDictionary;
27
28 @interface UIxContactEditor : UIxComponent
29 {
30   NSString *contentString;
31   NSString *errorText;
32   NSMutableDictionary *snapshot; /* contains the values for editing */
33 }
34
35 @end
36
37 #include <Contacts/SOGoContactObject.h>
38 #include <Contacts/SOGoContactFolder.h>
39 #include "common.h"
40
41 @implementation UIxContactEditor
42
43 - (id)init {
44   if ((self = [super init])) {
45     self->snapshot = [[NSMutableDictionary alloc] initWithCapacity:16];
46   }
47   return self;
48 }
49
50 - (void)dealloc {
51   [self->snapshot      release];
52   [self->errorText     release];
53   [self->contentString release];
54   [super dealloc];
55 }
56
57 /* accessors */
58
59 - (void)setContentString:(NSString *)_cstr {
60   ASSIGNCOPY(self->contentString, _cstr);
61 }
62 - (NSString *)contentString {
63   return self->contentString;
64 }
65
66 - (NSString *)contentStringTemplate {
67   return @"{}"; /* empty property list */
68 }
69
70 - (NSMutableDictionary *)snapshot {
71   return self->snapshot;
72 }
73
74 - (void)setErrorText:(NSString *)_txt {
75   ASSIGNCOPY(self->errorText, _txt);
76 }
77 - (NSString *)errorText {
78   return self->errorText;
79 }
80 - (BOOL)hasErrorText {
81   return [self->errorText length] > 0 ? YES : NO;
82 }
83
84 /* load/store content format */
85
86 - (void)loadValuesFromContentString:(NSString *)_s {
87   NSDictionary *plist;
88   
89   if ((plist = [_s propertyList]) == nil) {
90     [self errorWithFormat:@"could not parse content string!"];
91     return;
92   }
93   
94   [self->snapshot removeAllObjects];
95   [self->snapshot addEntriesFromDictionary:plist];
96 }
97
98 - (void)_fixupSnapshot {
99   // TODO: perform sanity checking, eg build CN on demand
100   NSString *cn, *gn, *sn;
101   
102   cn = [self->snapshot objectForKey:@"cn"];
103   gn = [self->snapshot objectForKey:@"givenName"];
104   sn = [self->snapshot objectForKey:@"sn"];
105   
106   if (![sn isNotNull] || [sn length] == 0)
107     sn = nil;
108   if (![cn isNotNull] || [cn length] == 0)
109     cn = nil;
110   
111   if (sn == nil) {
112     if (cn == nil)
113       sn = @"[noname]";
114     else {
115       // TODO: need a better name parser here
116       NSRange r;
117       
118       r = [cn rangeOfString:@" "];
119       sn = (r.length > 0)
120         ? [cn substringFromIndex:(r.location + r.length)]
121         : cn;
122     }
123     [self->snapshot setObject:sn forKey:@"sn"];
124   }
125   
126   if (sn == nil && gn == nil)
127     cn = @"[noname]";
128   else if (sn == nil)
129     cn = gn;
130   else if (gn == nil)
131     cn = sn;
132   else
133     cn = [[gn stringByAppendingString:@" "] stringByAppendingString:sn];
134   [self->snapshot setObject:cn forKey:@"cn"];
135 }
136
137 - (void)saveValuesIntoRecord:(NSMutableDictionary *)_record {
138   [self _fixupSnapshot];
139   [_record addEntriesFromDictionary:[self snapshot]];
140 }
141
142 /* JavaScript */
143
144 - (NSString *)jsCopyContactCode {
145   static NSString *jsCode = \
146     @"function unescapeCallbackParameter(s) {\n"
147     @"  if(!s || s.length == 0)\n"
148     @"    return s;\n"
149     @"  s = s.replace(/&apos;/g, \"'\");\n"
150     @"  s = s.replace(/&quot;/g, '\"');\n"
151     @"  return s;\n"
152     @"}\n"
153     @"\n"
154     @"function copyContact()"
155     @"{\n"
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"
168     @"  var e;\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"
189     @"}\n";
190   return jsCode;
191 }
192
193 /* helper */
194
195 - (NSString *)_completeURIForMethod:(NSString *)_method {
196   // TODO: this is a DUP of UIxAppointmentEditor
197   NSString *uri;
198   NSRange r;
199     
200   uri = [[[self context] request] uri];
201     
202   /* first: identify query parameters */
203   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
204   if (r.length > 0)
205     uri = [uri substringToIndex:r.location];
206     
207   /* next: append trailing slash */
208   if (![uri hasSuffix:@"/"])
209     uri = [uri stringByAppendingString:@"/"];
210   
211   /* next: append method */
212   uri = [uri stringByAppendingString:_method];
213     
214   /* next: append query parameters */
215   return [self completeHrefForMethod:uri];
216 }
217
218 /* actions */
219
220 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
221   return YES;
222 }
223
224 - (id)defaultAction {
225   // TODO: very similiar to apt-editor (apt editor would need to use std names
226   NSString *c;
227   
228   /* load iCalendar file */
229   
230   c = [[self clientObject] contentAsString];
231   if ([c length] == 0) /* a new contact */
232     c = [self contentStringTemplate];
233   
234   [self setContentString:c];
235   [self loadValuesFromContentString:c];
236   
237   return self;
238 }
239
240 - (BOOL)isWriteableClientObject {
241   return [[self clientObject] 
242                 respondsToSelector:@selector(saveContentString:)];
243 }
244
245 - (id)saveAction {
246   NSException *ex;
247   NSString *recstr;
248   id record;
249   
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"];
255   }
256   
257   record = [[[[self contentString] propertyList] mutableCopy] autorelease];
258   if (record == nil) {
259     [self setErrorText:@"Invalid property list data ..."]; // localize
260     return self;
261   }
262   
263   [self saveValuesIntoRecord:record];
264   
265   recstr = [record description]; // make plist
266   ex = [[self clientObject] saveContentString:recstr];
267   if (ex != nil) {
268     [self setErrorText:[ex reason]];
269     return self;
270   }
271   
272   return [self redirectToLocation:[self _completeURIForMethod:@".."]];
273 }
274
275 - (id)testAction {
276   [self logWithFormat:@"test ..."];
277   return self;
278 }
279
280 - (id)newAction {
281   // TODO: this is almost a DUP of UIxAppointmentEditor
282   /*
283     This method creates a unique ID and redirects to the "edit" method on the
284     new ID.
285     It is actually a folder method and should be defined on the folder.
286     
287     Note: 'clientObject' is the SOGoAppointmentFolder!
288           Update: remember that there are group folders as well.
289   */
290   NSString *uri, *objectId, *nextMethod;
291   
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"];
296   }
297   
298   nextMethod = [NSString stringWithFormat:@"../%@/edit", objectId];
299   uri = [self _completeURIForMethod:nextMethod];
300   return [self redirectToLocation:uri];
301 }
302
303 @end /* UIxContactEditor */