From: wolfgang Date: Fri, 7 Mar 2008 22:36:00 +0000 (+0000) Subject: git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1385 d1b88da0-ebda-0310... X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=516106542554c97188148068321171c58d3828d3;p=scalable-opengroupware.org git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1385 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/ChangeLog b/ChangeLog index 7742fdb8..3aedecfb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,49 @@ +2008-03-07 Wolfgang Sourdeau + + * OGoContentStore/OCSContactFieldExtractor.m + ([OCSContactFieldExtractor -extractQuickFieldsFromVList:vList]): + new method to handle extraction of quick information from the + VLIST components. I.e.: the display name of the card. + + * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder + -isValidContentName:name]): moved method from + SOGoAppointmentFolder's isValidAppointmentName. + + * SoObjects/Contacts/SOGoContactGCSFolder.m ([SOGoContactGCSFolder -objectClassForContent:content]) + ([SOGoContactGCSFolder -deduceObjectForName:inContext:]) + ([SOGoContactGCSFolder -requestNamedIsHandledLater:name]) + ([SOGoContactGCSFolder -lookupName:inContext:acquire:]): those + methods were modified to match the ones in SOGoAppointmentFolder, + in order to manage both vcard and vlist components. + + * SoObjects/Contacts/SOGoContactGCSList.[hm]: new class module + that implements the list counterpart to VCARD: VLIST. + + * UI/Contacts/UIxContactEditor.m ([UIxContactEditor -saveURL]): + new accessor that returns the url + "saveAsContact". + ([UIxContactEditor + -shouldTakeValuesFromRequest:requestinContext:context]): changed + method to match the one from the event and todo editor module. + ([UIxContactEditor -editActionName]): changed to "editAsContact". + ([UIxContactEditor -newAction]): changed method to match the one + from the event and todo editor module. + + * UI/Contacts/UIxListView.m: new view module for the VLIST format + components. + + * UI/Contacts/UIxListEditor.m: new edition module for the VLIST + format components. + + * SoObjects/Contacts/SOGoContactGCSList.m: new controller module + for the VLIST format. + +2008-03-04 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoObject.m ([SOGoObject -isFolderish]): new + parent method, meant to be overriden. + ([SOGoObject -davIsCollection]): moved method from SOGoFolder up + to this parent class. + 2008-02-25 Wolfgang Sourdeau * SoObjects/SOGo/SOGoGCSFolder.m ([SOGoGCSFolder diff --git a/NEWS b/NEWS index 415ca7fb..03ec83cb 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ - retrieving the freebusy DAV object was causing SOGo to crash - converted to use the gnustep-make 2 build framework - added custom DAV methods for managing user permissions from the SOGo Integrator +- pressing enter in the contact edition dialog will perform the creation/update operation 0.9.0-20080208 (1.0 rc5) ------------------------ diff --git a/OGoContentStore/OCSContactFieldExtractor.m b/OGoContentStore/OCSContactFieldExtractor.m index b52b567e..24fb4246 100644 --- a/OGoContentStore/OCSContactFieldExtractor.m +++ b/OGoContentStore/OCSContactFieldExtractor.m @@ -25,6 +25,7 @@ #import #import +#import @interface OCSContactFieldExtractor : GCSFieldExtractor @end @@ -75,6 +76,22 @@ [fields setObject: [adr value: 3] forKey: @"c_l"]; value = [[vCard uniqueChildWithTag: @"X-AIM"] value: 0]; [fields setObject: value forKey: @"c_screenname"]; + [fields setObject: @"vcard" forKey: @"c_component"]; + + return fields; +} + +- (NSMutableDictionary *) extractQuickFieldsFromVList: (NGVList *) vList +{ + NSMutableDictionary *fields; + NSString *value; + + fields = [NSMutableDictionary dictionaryWithCapacity: 1]; + + value = [vList fn]; + if (value) + [fields setObject: value forKey: @"c_cn"]; + [fields setObject: @"vlist" forKey: @"c_component"]; return fields; } @@ -83,19 +100,34 @@ { NSMutableDictionary *fields; NGVCard *vCard; + NGVList *vList; + NSString *upperContent; fields = nil; - if ([content length] > 0 - && [[content uppercaseString] hasPrefix: @"BEGIN:VCARD"]) + if ([content length] > 0) { - vCard = [NGVCard parseSingleFromSource: content]; - if (vCard) - fields = [self extractQuickFieldsFromVCard: vCard]; + upperContent = [content uppercaseString]; + if ([upperContent hasPrefix: @"BEGIN:VCARD"]) + { + vCard = [NGVCard parseSingleFromSource: content]; + if (vCard) + fields = [self extractQuickFieldsFromVCard: vCard]; + else + [self errorWithFormat: @"Could not parse VCARD content."]; + } + else if ([upperContent hasPrefix: @"BEGIN:VLIST"]) + { + vList = [NGVList parseSingleFromSource: content]; + if (vList) + fields = [self extractQuickFieldsFromVList: vList]; + else + [self errorWithFormat: @"Could not parse VLIST content."]; + } else - [self errorWithFormat: @"Could not parse content as a vCard."]; + [self errorWithFormat: @"Content is unknown."]; } else - [self errorWithFormat: @"Content is not a vCard"]; + [self errorWithFormat: @"Content is empty."]; return fields; } diff --git a/OGoContentStore/contact-oracle.ocs b/OGoContentStore/contact-oracle.ocs index 1174d649..f3539c28 100644 --- a/OGoContentStore/contact-oracle.ocs +++ b/OGoContentStore/contact-oracle.ocs @@ -54,5 +54,10 @@ sqlType = "VARCHAR2(256)"; allowsNull = YES; }, + { + columnName = c_component; + sqlType = "VARCHAR2(10)"; + allowsNull = NO; + }, ); } diff --git a/OGoContentStore/contact.ocs b/OGoContentStore/contact.ocs index d51c6e70..dd465317 100644 --- a/OGoContentStore/contact.ocs +++ b/OGoContentStore/contact.ocs @@ -54,5 +54,10 @@ sqlType = "VARCHAR(256)"; allowsNull = YES; }, + { + columnName = c_component; + sqlType = "VARCHAR(10)"; + allowsNull = NO; + }, ); } diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index 6ecd16f9..a3644f07 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,11 @@ +2008-03-03 Wolfgang Sourdeau + + * NGVCardReference.[hm]: new class module that implements the base + data type contained in a VLIST element. + + * NGVList.[hm]: new class module that implements Thunderbird-style + personal mailing lists. Base mime-type is "text/x-vlist". + 2008-02-08 Wolfgang Sourdeau * iCalRecurrenceRule.m ([iCalRecurrenceRule -wkst]): if no wkst diff --git a/SOPE/NGCards/GNUmakefile b/SOPE/NGCards/GNUmakefile index 7c324434..252fbbdc 100644 --- a/SOPE/NGCards/GNUmakefile +++ b/SOPE/NGCards/GNUmakefile @@ -53,6 +53,8 @@ libNGCards_HEADER_FILES = \ NSCalendarDate+ICal.h \ \ NGVCard.h \ + NGVList.h \ + NGVCardReference.h \ # NGVCardAddress.h \ # NGVCardStrArrayValue.h \ # NGVCardName.h \ @@ -101,11 +103,12 @@ libNGCards_OBJC_FILES = \ iCalYearlyRecurrenceCalculator.m\ \ NGVCard.m \ + NGVList.m \ + NGVCardReference.m \ NGCardsSaxHandler.m \ # IcalElements.m # IcalResponse.m - # framework support NGCards_PCH_FILE = $(libNGCards_PCH_FILE) diff --git a/SOPE/NGCards/NGVCard.h b/SOPE/NGCards/NGVCard.h index 7b9f69ee..a687e2a0 100644 --- a/SOPE/NGCards/NGVCard.h +++ b/SOPE/NGCards/NGVCard.h @@ -59,6 +59,14 @@ @class NSDictionary; @class NSString; +/* this should be merged in a common definition headers with iCalAccessClass */ +typedef enum +{ + NGCardsAccessPublic = 0, + NGCardsAccessPrivate = 1, + NGCardsAccessConfidential = 2, +} NGCardsAccessClass; + @interface NGVCard : CardGroup + (id) cardWithUid: (NSString *) _uid; diff --git a/SOPE/NGCards/NGVList.h b/SOPE/NGCards/NGVList.h new file mode 100644 index 00000000..85d9caf3 --- /dev/null +++ b/SOPE/NGCards/NGVList.h @@ -0,0 +1,69 @@ +/* NGVList.h - this file is part of NGCards + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef NGVLIST_H +#define NGVLIST_H + +#import "CardGroup.h" + +#import "NGVCard.h" + +@class NSArray; +@class NSDictionary; +@class NSString; + +@class NGVCardReference; + +@interface NGVList : CardGroup + ++ (id) listWithUid: (NSString *) newUid; +- (id) initWithUid: (NSString *) newUid; + +/* accessors */ + +- (void) setProdID: (NSString *) newProdID; +- (NSString *) prodID; +- (void) setVersion: (NSString *) newVersion; +- (NSString *) version; + +- (void) setUid: (NSString *) newUid; +- (NSString *) uid; + +- (void) setAccessClass: (NSString *) newAccessClass; +- (NSString *) accessClass; +- (NGCardsAccessClass) symbolicAccessClass; +- (BOOL) isPublic; + +- (void) setFn: (NSString *) newFn; +- (NSString *) fn; +- (void) setNickname: (NSString *) newNickname; +- (NSString *) nickname; +- (void) setDescription: (NSString *) newDescription; +- (NSString *) description; + +- (void) addCardReference: (NGVCardReference *) newCardRef; +- (void) deleteCardReference: (NGVCardReference *) cardRef; +- (NSArray *) cardReferences; + +@end + +#endif /* NGVLIST_H */ diff --git a/SOPE/NGCards/NGVList.m b/SOPE/NGCards/NGVList.m new file mode 100644 index 00000000..7d359df6 --- /dev/null +++ b/SOPE/NGCards/NGVList.m @@ -0,0 +1,200 @@ +/* NGVList.m - this file is part of NGCards + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import + +#import "NGVCardReference.h" + +#import "NGVList.h" + +@implementation NGVList + ++ (id) listWithUid: (NSString *) _uid +{ + NGVList *newList; + + newList = [[self alloc] initWithUid: _uid]; + [newList autorelease]; + + return newList; +} + +- (id) initWithUid: (NSString *) _uid +{ + if ((self = [self init])) + { + [self setTag: @"vlist"]; + [self setUid: _uid]; + [self setVersion: @"1.0"]; + } + + return self; +} + +/* class mapping */ +- (Class) classForTag: (NSString *) classTag +{ + Class tagClass; + + tagClass = Nil; + if ([classTag isEqualToString: @"PRODID"] + || [classTag isEqualToString: @"VERSION"] + || [classTag isEqualToString: @"UID"] + || [classTag isEqualToString: @"CLASS"] + || [classTag isEqualToString: @"FN"] + || [classTag isEqualToString: @"NICKNAME"] + || [classTag isEqualToString: @"DESCRIPTION"]) + tagClass = [CardElement class]; + else if ([classTag isEqualToString: @"CARD"]) + tagClass = [NGVCardReference class]; + else + tagClass = [super classForTag: classTag]; + + return tagClass; +} + +- (void) setProdID: (NSString *) newProdID +{ + [[self uniqueChildWithTag: @"prodid"] setValue: 0 to: newProdID]; +} + +- (NSString *) prodID +{ + return [[self uniqueChildWithTag: @"prodid"] value: 0]; +} + +- (void) setVersion: (NSString *) newVersion +{ + [[self uniqueChildWithTag: @"version"] setValue: 0 + to: newVersion]; +} + +- (NSString *) version +{ + return [[self uniqueChildWithTag: @"version"] value: 0]; +} + +- (void) setUid: (NSString *) newUid +{ + [[self uniqueChildWithTag: @"uid"] setValue: 0 + to: newUid]; +} + +- (NSString *) uid +{ + return [[self uniqueChildWithTag: @"uid"] value: 0]; +} + +- (void) setAccessClass: (NSString *) newAccessClass +{ + [[self uniqueChildWithTag: @"class"] setValue: 0 + to: newAccessClass]; +} + +- (NSString *) accessClass +{ + return [[self uniqueChildWithTag: @"class"] value: 0]; +} + +- (NGCardsAccessClass) symbolicAccessClass +{ + NGCardsAccessClass symbolicAccessClass; + NSString *accessClass; + + accessClass = [[self accessClass] uppercaseString]; + if ([accessClass isEqualToString: @"PRIVATE"]) + symbolicAccessClass = NGCardsAccessPrivate; + else if ([accessClass isEqualToString: @"CONFIDENTIAL"]) + symbolicAccessClass = NGCardsAccessConfidential; + else + symbolicAccessClass = NGCardsAccessPublic; + + return symbolicAccessClass; +} + +- (BOOL) isPublic +{ + return ([self symbolicAccessClass] == NGCardsAccessPublic); +} + +- (void) setFn: (NSString *) newFn +{ + [[self uniqueChildWithTag: @"fn"] setValue: 0 to: newFn]; +} + +- (NSString *) fn +{ + return [[self uniqueChildWithTag: @"fn"] value: 0]; +} + +- (void) setNickname: (NSString *) newNickname +{ + [[self uniqueChildWithTag: @"nickname"] setValue: 0 + to: newNickname]; +} + +- (NSString *) nickname +{ + return [[self uniqueChildWithTag: @"nickname"] value: 0]; +} + +- (void) setDescription: (NSString *) newDescription +{ + [[self uniqueChildWithTag: @"description"] setValue: 0 + to: newDescription]; +} + +- (NSString *) description +{ + return [[self uniqueChildWithTag: @"description"] value: 0]; +} + +- (void) addCardReference: (NGVCardReference *) newCardRef +{ + [self addChild: newCardRef]; +} + +- (void) deleteCardReference: (NGVCardReference *) cardRef +{ + NSEnumerator *cardReferences; + NGVCardReference *currentRef; + NSMutableArray *deletedRefs; + + deletedRefs = [NSMutableArray array]; + cardReferences + = [[self childrenWithTag: @"card"] objectEnumerator]; + while ((currentRef = [cardReferences nextObject])) + if ([[currentRef reference] + isEqualToString: [cardRef reference]]) + [deletedRefs addObject: currentRef]; + + [children removeObjectsInArray: deletedRefs]; +} + +- (NSArray *) cardReferences +{ + return [self childrenWithTag: @"card"]; +} + +@end diff --git a/SOPE/NGCards/versitCardsSaxDriver/bundle-info.plist b/SOPE/NGCards/versitCardsSaxDriver/bundle-info.plist index 41acb508..69ad8c42 100644 --- a/SOPE/NGCards/versitCardsSaxDriver/bundle-info.plist +++ b/SOPE/NGCards/versitCardsSaxDriver/bundle-info.plist @@ -9,6 +9,7 @@ { name = "VSCardSaxDriver"; sourceTypes = ( "text/x-vcard", "text/vcard", + "text/x-vlist", "text/x-calendar", "text/calendar" ); } ); diff --git a/Scripts/sql-update-20080303.sh b/Scripts/sql-update-20080303.sh new file mode 100644 index 00000000..e71a28b0 --- /dev/null +++ b/Scripts/sql-update-20080303.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# this script only work with PostgreSQL + +defaultusername=$USER +defaulthostname=localhost +defaultdatabase=$USER +indextable=sogo_folder_info + +read -p "Username ($defaultusername): " username +read -p "Hostname ($defaulthostname): " hostname +read -p "Database ($defaultdatabase): " database + +if [ -z "$username" ] +then + username=$defaultusername +fi +if [ -z "$hostname" ] +then + hostname=$defaulthostname +fi +if [ -z "$database" ] +then + database=$defaultdatabase +fi + +echo "" +echo "You will now be requested your password twice..." +echo "After that, a list of SQL operations will scroll." +echo "" + +sqlscript="" + +function addField() { + oldIFS="$IFS" + IFS=" " + part="`echo -e \"ALTER TABLE $table ADD COLUMN c_component VARCHAR(10) NOT NULL DEFAULT 'vcard';\\n\"`"; + sqlscript="$sqlscript$part" + IFS="$oldIFS" +} + +tables=`psql -t -U $username -h $hostname $database -c "select split_part(c_quick_location, '/', 5) from $indextable where c_folder_type = 'Contact';"` + +for table in $tables; +do + addField +done + +echo "$sqlscript" | psql -q -e -U $username -h $hostname $database > /dev/null + +echo "Please ignore the errors above. They just mean that the migration was already done for the elements in question."; diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 745e312c..6491a353 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -150,11 +150,6 @@ static NSNumber *sharedYes = nil; /* name lookup */ -- (BOOL) isValidAppointmentName: (NSString *)_key -{ - return ([_key length] != 0); -} - - (void) appendObject: (NSDictionary *) object withBaseURL: (NSString *) baseURL toREPORTResponse: (WOResponse *) r @@ -391,7 +386,7 @@ static NSNumber *sharedYes = nil; obj = [super lookupName:_key inContext:_ctx acquire:NO]; if (!obj) { - if ([self isValidAppointmentName:_key]) + if ([self isValidContentName:_key]) { url = [[[_ctx request] uri] urlWithoutParameters]; if ([url hasSuffix: @"AsTask"]) diff --git a/SoObjects/Appointments/SOGoFreeBusyObject.m b/SoObjects/Appointments/SOGoFreeBusyObject.m index b6ecfda2..d8c3ea43 100644 --- a/SoObjects/Appointments/SOGoFreeBusyObject.m +++ b/SoObjects/Appointments/SOGoFreeBusyObject.m @@ -205,6 +205,11 @@ return r; } +- (BOOL) isFolderish +{ + return NO; +} + - (NSString *) davContentType { return @"text/calendar"; diff --git a/SoObjects/Appointments/product.plist b/SoObjects/Appointments/product.plist index 3250fef2..ce2616d7 100644 --- a/SoObjects/Appointments/product.plist +++ b/SoObjects/Appointments/product.plist @@ -8,7 +8,7 @@ }; classes = { - SOGoAppointmentFolder = { + SOGoAppointmentFolders = { superclass = "SOGoParentFolder"; }; SOGoAppointmentFolder = { diff --git a/SoObjects/Contacts/GNUmakefile b/SoObjects/Contacts/GNUmakefile index dd0ae6da..b452a417 100644 --- a/SoObjects/Contacts/GNUmakefile +++ b/SoObjects/Contacts/GNUmakefile @@ -12,6 +12,7 @@ Contacts_OBJC_FILES = \ SOGoFolder+CardDAV.m \ SOGoContactFolders.m \ SOGoContactGCSEntry.m \ + SOGoContactGCSList.m \ SOGoContactGCSFolder.m \ SOGoContactLDIFEntry.m \ SOGoContactLDAPFolder.m \ diff --git a/SoObjects/Contacts/SOGoContactGCSEntry.h b/SoObjects/Contacts/SOGoContactGCSEntry.h index 4ebfeac3..fe9b62e0 100644 --- a/SoObjects/Contacts/SOGoContactGCSEntry.h +++ b/SoObjects/Contacts/SOGoContactGCSEntry.h @@ -29,7 +29,8 @@ @class NGVCard; -@interface SOGoContactGCSEntry : SOGoContentObject +@interface SOGoContactGCSEntry + : SOGoContentObject { NGVCard *card; } diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.m b/SoObjects/Contacts/SOGoContactGCSFolder.m index eff8313e..0c285bae 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.m +++ b/SoObjects/Contacts/SOGoContactGCSFolder.m @@ -29,12 +29,19 @@ #import #import #import +#import #import #import #import -#import +#import +#import +#import +#import + #import "SOGoContactGCSEntry.h" +#import "SOGoContactGCSList.h" + #import "SOGoContactGCSFolder.h" #define folderListingFields [NSArray arrayWithObjects: @"c_name", @"c_cn", \ @@ -59,29 +66,149 @@ return contact; } -- (id) lookupName: (NSString *) _key - inContext: (WOContext *) _ctx - acquire: (BOOL) _flag +- (Class) objectClassForContent: (NSString *) content { - id obj; - BOOL isPut; + CardGroup *cardEntry; + NSString *firstTag; + Class objectClass; - isPut = NO; - obj = [super lookupName:_key inContext:_ctx acquire:NO]; - - if (!obj) + objectClass = Nil; + + cardEntry = [CardGroup parseSingleFromSource: content]; + if (cardEntry) + { + firstTag = [[cardEntry tag] uppercaseString]; + if ([firstTag isEqualToString: @"VCARD"]) + objectClass = [SOGoContactGCSEntry class]; + else if ([firstTag isEqualToString: @"VLIST"]) + objectClass = [SOGoContactGCSList class]; + } + + return objectClass; +} + +- (Class) objectClassForResourceNamed: (NSString *) name +{ + EOQualifier *qualifier; + NSArray *records; + NSString *component; + Class objectClass; + + qualifier = [EOQualifier qualifierWithQualifierFormat:@"c_name = %@", name]; + records = [[self ocsFolder] fetchFields: [NSArray arrayWithObject: @"c_component"] + matchingQualifier: qualifier]; + + if ([records count]) { - if ([[[_ctx request] method] isEqualToString: @"PUT"]) - { - if ([_key isEqualToString: @"PUT"]) - isPut = YES; - else - obj = [SOGoContactGCSEntry objectWithName: _key - inContainer: self]; - } + component = [[records objectAtIndex: 0] valueForKey: @"c_component"]; + if ([component isEqualToString: @"vcard"]) + objectClass = [SOGoContactGCSEntry class]; + else if ([component isEqualToString: @"vlist"]) + objectClass = [SOGoContactGCSList class]; else - obj = [self lookupContactWithId: _key]; + objectClass = Nil; } + else + objectClass = Nil; + + return objectClass; +} + +- (id) deduceObjectForName: (NSString *)_key + inContext: (id)_ctx +{ + WORequest *request; + NSString *method; + Class objectClass; + id obj; + + request = [_ctx request]; + method = [request method]; + if ([method isEqualToString: @"PUT"]) + objectClass = [self objectClassForContent: [request contentAsString]]; + else + objectClass = [self objectClassForResourceNamed: _key]; + + if (objectClass) + obj = [objectClass objectWithName: _key inContainer: self]; + else + obj = nil; + + return obj; +} + +- (BOOL) requestNamedIsHandledLater: (NSString *) name +{ + return [name isEqualToString: @"OPTIONS"]; +} + +- (id) lookupName: (NSString *)_key + inContext: (id)_ctx + acquire: (BOOL)_flag +{ + id obj; + NSString *url; + BOOL handledLater; + + /* first check attributes directly bound to the application */ + handledLater = [self requestNamedIsHandledLater: _key]; + if (handledLater) + obj = nil; + else + { + obj = [super lookupName:_key inContext:_ctx acquire:NO]; + if (!obj) + { + if ([self isValidContentName: _key]) + { + url = [[[_ctx request] uri] urlWithoutParameters]; + if ([url hasSuffix: @"AsContact"]) + obj = [SOGoContactGCSEntry objectWithName: _key + inContainer: self]; + else if ([url hasSuffix: @"AsList"]) + obj = [SOGoContactGCSList objectWithName: _key + inContainer: self]; + else + obj = [self deduceObjectForName: _key + inContext: _ctx]; + } + } + if (!obj) + obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */]; + } + + if (obj) + [[SOGoCache sharedCache] registerObject: obj + withName: _key + inContainer: container]; + + return obj; +} + +// - (id) lookupName: (NSString *) _key +// inContext: (WOContext *) _ctx +// acquire: (BOOL) _flag +// { +// id obj; +// BOOL isPut; + +// isPut = NO; +// obj = [super lookupName:_key inContext:_ctx acquire:NO]; + +// if (!obj) +// { +// if ([[[_ctx request] method] isEqualToString: @"PUT"]) +// { +// if ([_key isEqualToString: @"PUT"]) +// isPut = YES; +// else + +// obj = [SOGoContactGCSEntry objectWithName: _key +// inContainer: self]; +// } +// else +// obj = [self lookupContactWithId: _key]; +// } // if (!(obj || isPut)) // obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */]; @@ -91,9 +218,9 @@ // return [self contactWithName:_key inContext:_ctx]; // } - /* return 404 to stop acquisition */ - return obj; -} +// /* return 404 to stop acquisition */ +// return obj; +// } /* fetching */ - (EOQualifier *) _qualifierForFilter: (NSString *) filter @@ -280,7 +407,6 @@ cardDavCollection = [NSArray arrayWithObjects: @"addressbook", @"urn:ietf:params:xml:ns:carddav", nil]; - resourceType = [NSMutableArray arrayWithArray: [super davResourceType]]; [resourceType addObject: cardDavCollection]; diff --git a/SoObjects/Contacts/SOGoContactGCSList.h b/SoObjects/Contacts/SOGoContactGCSList.h new file mode 100644 index 00000000..5e3cc164 --- /dev/null +++ b/SoObjects/Contacts/SOGoContactGCSList.h @@ -0,0 +1,37 @@ +/* SOGoContactGCSList.h - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef SOGOCONTACTGCSLIST_H +#define SOGOCONTACTGCSLIST_H + +#import + +@class NGVList; + +@interface SOGoContactGCSList : SOGoContentObject +{ + NGVList *list; +} + +@end + +#endif /* SOGOCONTACTGCSLIST_H */ diff --git a/SoObjects/Contacts/SOGoContactGCSList.m b/SoObjects/Contacts/SOGoContactGCSList.m new file mode 100644 index 00000000..2534fc6d --- /dev/null +++ b/SoObjects/Contacts/SOGoContactGCSList.m @@ -0,0 +1,92 @@ +/* SOGoContactGCSList.m - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import + +#import + +#import "SOGoContactGCSList.h" + +@implementation SOGoContactGCSList + +- (id) init +{ + if ((self = [super init])) + { + list = nil; + } + + return self; +} + +- (void) dealloc +{ + [list release]; + [super dealloc]; +} + +/* content */ + +- (NGVList *) vList +{ + NSString *content; + + if (!list) + { + content = [record objectForKey: @"c_content"]; + if ([[content uppercaseString] hasPrefix: @"BEGIN:VLIST"]) + list = [NGVList parseSingleFromSource: content]; + else + list = [NGVList listWithUid: [self nameInContainer]]; + [list retain]; + } + + return list; +} + +/* DAV */ + +- (NSString *) davContentType +{ + return @"text/x-vlist"; +} + +/* specialized actions */ + +- (void) save +{ + NGVList *vlist; + + vlist = [self vList]; + + [self saveContentString: [vlist versitString]]; +} + +/* message type */ + +- (NSString *) outlookMessageClass +{ + return @"IPM.Contact"; +} + +@end diff --git a/SoObjects/Contacts/product.plist b/SoObjects/Contacts/product.plist index f3035902..dd5dcd41 100644 --- a/SoObjects/Contacts/product.plist +++ b/SoObjects/Contacts/product.plist @@ -17,6 +17,9 @@ SOGoContactGCSEntry = { superclass = "SOGoContentObject"; }; + SOGoContactGCSList = { + superclass = "SOGoContentObject"; + }; SOGoContactLDAPFolder = { superclass = "SOGoGCSFolder"; protectedBy = "Access Contents Information"; diff --git a/SoObjects/Mailer/SOGoMailBaseObject.h b/SoObjects/Mailer/SOGoMailBaseObject.h index 8d596742..a7028b30 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.h +++ b/SoObjects/Mailer/SOGoMailBaseObject.h @@ -48,6 +48,8 @@ NGImap4Connection *imap4; } +- (BOOL) isFolderish; + - (id) initWithImap4URL: (NSURL *) _url inContainer: (id) _container; diff --git a/SoObjects/Mailer/SOGoMailBaseObject.m b/SoObjects/Mailer/SOGoMailBaseObject.m index cfeda797..7c5ec4e7 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.m +++ b/SoObjects/Mailer/SOGoMailBaseObject.m @@ -60,6 +60,11 @@ static BOOL debugOn = YES; [super dealloc]; } +- (BOOL) isFolderish +{ + return YES; +} + /* hierarchy */ - (SOGoMailAccount *) mailAccountFolder diff --git a/SoObjects/Mailer/SOGoMailBodyPart.m b/SoObjects/Mailer/SOGoMailBodyPart.m index 3afd10e0..38671f81 100644 --- a/SoObjects/Mailer/SOGoMailBodyPart.m +++ b/SoObjects/Mailer/SOGoMailBodyPart.m @@ -449,6 +449,11 @@ static BOOL debugOn = NO; return klazz; } +- (BOOL) isFolderish +{ + return NO; +} + /* etag support */ - (id)davEntityTag { diff --git a/SoObjects/SOGo/SOGoContentObject.m b/SoObjects/SOGo/SOGoContentObject.m index ac27122b..a4bfbc37 100644 --- a/SoObjects/SOGo/SOGoContentObject.m +++ b/SoObjects/SOGo/SOGoContentObject.m @@ -377,10 +377,6 @@ reason:@"this object cannot be copied via WebDAV"]; } -- (BOOL)davIsCollection { - return [self isFolderish]; -} - /* acls */ - (NSArray *) aclUsers diff --git a/SoObjects/SOGo/SOGoFolder.h b/SoObjects/SOGo/SOGoFolder.h index 69951d95..03f1c934 100644 --- a/SoObjects/SOGo/SOGoFolder.h +++ b/SoObjects/SOGo/SOGoFolder.h @@ -36,6 +36,8 @@ - (NSString *) folderType; - (NSArray *) fetchContentObjectNames; +- (BOOL) isValidContentName: (NSString *) name; + /* sorting */ - (NSComparisonResult) compare: (id) otherFolder; diff --git a/SoObjects/SOGo/SOGoFolder.m b/SoObjects/SOGo/SOGoFolder.m index 3f404fdf..b01bfe5a 100644 --- a/SoObjects/SOGo/SOGoFolder.m +++ b/SoObjects/SOGo/SOGoFolder.m @@ -112,6 +112,11 @@ return [NSArray array]; } +- (BOOL) isValidContentName: (NSString *) name +{ + return ([name length] > 0); +} + - (BOOL) isFolderish { return YES; @@ -201,11 +206,6 @@ /* WebDAV */ -- (BOOL) davIsCollection -{ - return [self isFolderish]; -} - - (NSString *) davContentType { return @"httpd/unix-directory"; diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index 7fbace9f..84d69356 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -634,6 +634,18 @@ static BOOL sendACLAdvisories = NO; return [NSNumber numberWithBool:YES]; /* delete worked out ... */ } +- (BOOL) isFolderish +{ + [self subclassResponsibility: _cmd]; + + return NO; +} + +- (BOOL) davIsCollection +{ + return [self isFolderish]; +} + - (NSString *) davContentType { return @"text/plain"; diff --git a/UI/Contacts/GNUmakefile b/UI/Contacts/GNUmakefile index b9d4b0eb..a561d82f 100644 --- a/UI/Contacts/GNUmakefile +++ b/UI/Contacts/GNUmakefile @@ -17,6 +17,8 @@ ContactsUI_OBJC_FILES = \ UIxContactsFilterPanel.m \ UIxContactView.m \ UIxContactEditor.m \ + UIxListView.m \ + UIxListEditor.m \ UIxContactsListView.m \ UIxContactsListViewContainer.m \ UIxContactFoldersView.m \ diff --git a/UI/Contacts/UIxContactEditor.m b/UI/Contacts/UIxContactEditor.m index 754b6ea7..af0317af 100644 --- a/UI/Contacts/UIxContactEditor.m +++ b/UI/Contacts/UIxContactEditor.m @@ -25,13 +25,15 @@ #import #import #import +#import #import #import #import #import -#import +#import +#import #import "UIxContactEditor.h" @@ -57,6 +59,12 @@ /* accessors */ +- (NSString *) saveURL +{ + return [NSString stringWithFormat: @"%@/saveAsContact", + [[self clientObject] baseURL]]; +} + - (NSArray *) htmlMailFormatList { static NSArray *htmlMailFormatItems = nil; @@ -136,10 +144,15 @@ /* actions */ -- (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq - inContext: (WOContext*) _c +- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request + inContext: (WOContext*) context { - return YES; + NSString *actionName; + + actionName = [[request requestHandlerPath] lastPathComponent]; + + return ([[self clientObject] isKindOfClass: [SOGoContactGCSEntry class]] + && [actionName hasPrefix: @"save"]); } - (void) _setSnapshotValue: (NSString *) key @@ -375,7 +388,7 @@ - (NSString *) editActionName { /* this is overridden in the mail based contacts UI to redirect to tb.edit */ - return @"edit"; + return @"editAsContact"; } - (CardElement *) _elementWithTag: (NSString *) tag @@ -492,7 +505,7 @@ - (id ) saveAction { - id contact; + SOGoContactGCSEntry *contact; id result; NSString *jsRefreshMethod; @@ -552,35 +565,27 @@ return [self redirectToLocation: url]; } +#warning Could this be part of a common parent with UIxAppointment/UIxTaskEditor/UIxListEditor ? - (id) newAction { - // TODO: this is almost a DUP of UIxAppointmentEditor - /* - This method creates a unique ID and redirects to the "edit" method on the - new ID. - It is actually a folder method and should be defined on the folder. - - Note: 'clientObject' is the SOGoAppointmentFolder! - Update: remember that there are group folders as well. - */ - NSString *uri, *objectId, *nextMethod; - SOGoObject *co; + NSString *objectId, *method, *uri; + id result; + SOGoContactGCSFolder *co; co = [self clientObject]; - if ([co respondsToSelector: @selector (globallyUniqueObjectId)]) - objectId = [co globallyUniqueObjectId]; + objectId = [co globallyUniqueObjectId]; + if ([objectId length] > 0) + { + method = [NSString stringWithFormat:@"%@/%@.vcf/editAsContact", + [co soURL], objectId]; + uri = [self completeHrefForMethod: method]; + result = [self redirectToLocation: uri]; + } else - objectId = nil; - - if ([objectId length] == 0) - return [NSException exceptionWithHTTPStatus: 500 /* Internal Error */ - reason: @"could not create a unique ID"]; + result = [NSException exceptionWithHTTPStatus: 500 /* Internal Error */ + reason: @"could not create a unique ID"]; - nextMethod = [NSString stringWithFormat: @"../%@.vcf/%@", - objectId, [self editActionName]]; - uri = [self _completeURIForMethod: nextMethod]; - - return [self redirectToLocation: uri]; + return result; } @end /* UIxContactEditor */ diff --git a/UI/Contacts/UIxListEditor.h b/UI/Contacts/UIxListEditor.h new file mode 100644 index 00000000..f895eae8 --- /dev/null +++ b/UI/Contacts/UIxListEditor.h @@ -0,0 +1,32 @@ +/* UIxListEditor.h - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef UIXLISTEDITOR_H +#define UIXLISTEDITOR_H + +#import + +@interface UIxListEditor : UIxComponent + +@end + +#endif /* UIXLISTEDITOR_H */ diff --git a/UI/Contacts/UIxListEditor.m b/UI/Contacts/UIxListEditor.m new file mode 100644 index 00000000..ba9e57a4 --- /dev/null +++ b/UI/Contacts/UIxListEditor.m @@ -0,0 +1,61 @@ +/* UIxListEditor.m - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import + +#import + +#import "UIxListEditor.h" + +@implementation UIxListEditor + +- (NSString *) saveURL +{ + return [NSString stringWithFormat: @"%@/saveAsList", + [[self clientObject] baseURL]]; +} + +#warning Could this be part of a common parent with UIxAppointment/UIxTaskEditor/UIxListEditor ? +- (id) newAction +{ + NSString *objectId, *method, *uri; + id result; + SOGoContactGCSFolder *co; + + co = [self clientObject]; + objectId = [co globallyUniqueObjectId]; + if ([objectId length] > 0) + { + method = [NSString stringWithFormat:@"%@/%@.vls/editAsList", + [co soURL], objectId]; + uri = [self completeHrefForMethod: method]; + result = [self redirectToLocation: uri]; + } + else + result = [NSException exceptionWithHTTPStatus: 500 /* Internal Error */ + reason: @"could not create a unique ID"]; + + return result; +} + +@end diff --git a/UI/Contacts/UIxListView.h b/UI/Contacts/UIxListView.h new file mode 100644 index 00000000..40783eb9 --- /dev/null +++ b/UI/Contacts/UIxListView.h @@ -0,0 +1,32 @@ +/* UIxListView.h - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef UIXLISTVIEW_H +#define UIXLISTVIEW_H + +#import + +@interface UIxListView : UIxComponent + +@end + +#endif /* UIXLISTVIEW_H */ diff --git a/UI/Contacts/UIxListView.m b/UI/Contacts/UIxListView.m new file mode 100644 index 00000000..de69286c --- /dev/null +++ b/UI/Contacts/UIxListView.m @@ -0,0 +1,27 @@ +/* UIxListView.m - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import "UIxListView.h" + +@implementation UIxListView + +@end diff --git a/UI/Contacts/product.plist b/UI/Contacts/product.plist index 4a0285ae..5b19b2f6 100644 --- a/UI/Contacts/product.plist +++ b/UI/Contacts/product.plist @@ -77,11 +77,16 @@ protectedBy = "View"; pageName = "UIxContactsListView"; }; - new = { + newcontact = { protectedBy = "Add Documents, Images, and Files"; pageName = "UIxContactEditor"; actionName = "new"; }; + newlist = { + protectedBy = "Add Documents, Images, and Files"; + pageName = "UIxListEditor"; + actionName = "new"; + }; mailer-contacts = { protectedBy = "View"; pageName = "UIxContactsListView"; @@ -144,11 +149,20 @@ protectedBy = "Access Contents Information"; pageName = "UIxContactEditor"; }; + editAsContact = { + protectedBy = "Access Contents Information"; + pageName = "UIxContactEditor"; + }; save = { protectedBy = "Change Images And Files"; pageName = "UIxContactEditor"; actionName = "save"; }; + saveAsContact = { + protectedBy = "Change Images And Files"; + pageName = "UIxContactEditor"; + actionName = "save"; + }; write = { protectedBy = "View"; pageName = "UIxContactEditor"; @@ -157,6 +171,38 @@ }; }; + SOGoContactGCSList = { + methods = { + view = { + protectedBy = "Access Contents Information"; + pageName = "UIxListView"; + }; + delete = { + protectedBy = "Delete Objects"; + pageName = "UIxListView"; + actionName = "delete"; + }; + edit = { + protectedBy = "Access Contents Information"; + pageName = "UIxListEditor"; + }; + editAsList = { + protectedBy = "Access Contents Information"; + pageName = "UIxListEditor"; + }; + save = { + protectedBy = "Change Images And Files"; + pageName = "UIxListEditor"; + actionName = "save"; + }; + saveAsList = { + protectedBy = "Change Images And Files"; + pageName = "UIxListEditor"; + actionName = "save"; + }; + }; + }; + SOGoContactLDIFEntry = { methods = { view = { @@ -176,4 +222,3 @@ }; }; } - diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index a1c33099..745d432a 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -80,7 +80,7 @@ - (NSString *) saveURL { return [NSString stringWithFormat: @"%@/saveAsAppointment", - [[self clientObject] baseURL]]; + [[self clientObject] baseURL]]; } /* icalendar values */ diff --git a/UI/Templates/ContactsUI/UIxContactEditor.wox b/UI/Templates/ContactsUI/UIxContactEditor.wox index 96894d14..2f49e537 100644 --- a/UI/Templates/ContactsUI/UIxContactEditor.wox +++ b/UI/Templates/ContactsUI/UIxContactEditor.wox @@ -9,7 +9,7 @@ title="name" const:popup="YES" > -
@@ -336,17 +336,17 @@
+ name="cancel"/> + name="submit" />
diff --git a/UI/Templates/ContactsUI/UIxListEditor.wox b/UI/Templates/ContactsUI/UIxListEditor.wox new file mode 100644 index 00000000..02bb0211 --- /dev/null +++ b/UI/Templates/ContactsUI/UIxListEditor.wox @@ -0,0 +1,12 @@ + + Unimplemented diff --git a/UI/Templates/ContactsUI/UIxListView.wox b/UI/Templates/ContactsUI/UIxListView.wox new file mode 100644 index 00000000..02bb0211 --- /dev/null +++ b/UI/Templates/ContactsUI/UIxListView.wox @@ -0,0 +1,12 @@ + + Unimplemented diff --git a/UI/Templates/SchedulerUI/UIxComponentEditor.wox b/UI/Templates/SchedulerUI/UIxComponentEditor.wox index f9f1a7ba..96569032 100644 --- a/UI/Templates/SchedulerUI/UIxComponentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxComponentEditor.wox @@ -145,8 +145,6 @@ - - diff --git a/UI/WebServerResources/ContactsUI.js b/UI/WebServerResources/ContactsUI.js index e6196b0b..d9d7a876 100644 --- a/UI/WebServerResources/ContactsUI.js +++ b/UI/WebServerResources/ContactsUI.js @@ -455,7 +455,7 @@ function onHeaderClick(event) { } function newContact(sender) { - openContactWindow(URLForFolderID(currentContactFolder) + "/new"); + openContactWindow(URLForFolderID(currentContactFolder) + "/newcontact"); return false; /* stop following the link */ } diff --git a/UI/WebServerResources/UIxContactEditor.js b/UI/WebServerResources/UIxContactEditor.js index 76910d03..97d38c70 100644 --- a/UI/WebServerResources/UIxContactEditor.js +++ b/UI/WebServerResources/UIxContactEditor.js @@ -127,11 +127,18 @@ function onFnNewValue(event) { return true; } +function onEditorCancelClick(event) { + preventDefault(event); + window.close(); +} + function initEditorForm() { displayNameChanged = ($("fn").value.length > 0); $("fn").onkeydown = onFnKeyDown; $("sn").onkeyup = onFnNewValue; $("givenName").onkeyup = onFnNewValue; + + $("cancelButton").observe("click", onEditorCancelClick); } FastInit.addOnLoad(initEditorForm); diff --git a/UI/WebServerResources/UIxMailEditor.js b/UI/WebServerResources/UIxMailEditor.js index e961740b..1aa2e1a5 100644 --- a/UI/WebServerResources/UIxMailEditor.js +++ b/UI/WebServerResources/UIxMailEditor.js @@ -288,10 +288,8 @@ function initMailEditor() { var list = $("attachments"); $(list).attachMenu("attachmentsMenu"); var elements = list.childNodesWithTag("li"); - for (var i = 0; i < elements.length; i++) { - Event.observe(elements[i], "click", - onRowClick.bindAsEventListener(elements[i])); - } + for (var i = 0; i < elements.length; i++) + elements[i].observe("click", onRowClick); var listContent = $("attachments").childNodesWithTag("li"); if (listContent.length > 0)