From aa1178446a69eee0c1661395fc2e5c2985779fb1 Mon Sep 17 00:00:00 2001 From: wolfgang Date: Mon, 5 Nov 2007 22:42:20 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1238 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 13 +++ NEWS | 1 + SOPE/NGCards/iCalRecurrenceRule.h | 3 + SOPE/NGCards/iCalRepeatableEntityObject.h | 1 + UI/MailPartViewers/UIxMailPartTextViewer.m | 64 +++++++++++- UI/MailPartViewers/UIxMailPartViewer.m | 24 ++--- UI/MailerUI/UIxMailListView.h | 1 + UI/MailerUI/UIxMailListView.m | 55 ++++++----- UI/WebServerResources/MailerUI.css | 9 +- UI/WebServerResources/MailerUI.js | 110 +++++++++++---------- 10 files changed, 182 insertions(+), 99 deletions(-) diff --git a/ChangeLog b/ChangeLog index d632805b..54838b55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 2007-11-05 Wolfgang Sourdeau + * UI/MailPartViewers/UIxMailPartTextViewer.m + ([UIxMailPartTextViewer -flatContentAsString]): re-added + conversion of line-break to sequences of HTML "BR", with a fast + algorithm in C. + + * UI/MailPartViewers/UIxMailPartViewer.m ([UIxMailPartViewer + -flatContentAsString]): simplified method now that we know + -[NSString stringWithData:usingEncodingNamed:] has a more robust + implementation. + + * UI/MailerUI/UIxMailListView.m ([UIxMailListView + -showToAddress]): the answer is cached. + * UI/Common/UIxObjectActions.m ([UIxObjectActions +initialize]): read "SOGoACLsSendEMailNotifications" from the user defaults to determiner whether to send an email when a user is added or diff --git a/NEWS b/NEWS index e563d7fb..48bf59ed 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ - support for resizable columns in tables; - improved support for multiple selection in tables and lists; - improved IE7 and Safari support: attendees selector, email file attachments; +- changed look of message composition window to Thunderbird 2.0; - countless bugfixes; 0.9.0-20070824 diff --git a/SOPE/NGCards/iCalRecurrenceRule.h b/SOPE/NGCards/iCalRecurrenceRule.h index 53a254e7..478f507f 100644 --- a/SOPE/NGCards/iCalRecurrenceRule.h +++ b/SOPE/NGCards/iCalRecurrenceRule.h @@ -82,10 +82,13 @@ typedef enum { - (void) setFrequency: (iCalRecurrenceFrequency) _frequency; - (iCalRecurrenceFrequency) frequency; +- (iCalRecurrenceFrequency) valueForFrequency: (NSString *) value; - (void) setRepeatInterval: (int) _repeatInterval; - (int) repeatInterval; +- (void) setInterval: (NSString *) _interval; + - (void) setWeekStart: (iCalWeekDay) _weekStart; - (iCalWeekDay) weekStart; diff --git a/SOPE/NGCards/iCalRepeatableEntityObject.h b/SOPE/NGCards/iCalRepeatableEntityObject.h index d3225468..08f19f81 100644 --- a/SOPE/NGCards/iCalRepeatableEntityObject.h +++ b/SOPE/NGCards/iCalRepeatableEntityObject.h @@ -43,6 +43,7 @@ - (void)removeAllRecurrenceRules; - (void)addToRecurrenceRules:(id)_rrule; +- (void)setRecurrenceRules:(id)_rrule; - (BOOL)hasRecurrenceRules; - (NSArray *)recurrenceRules; diff --git a/UI/MailPartViewers/UIxMailPartTextViewer.m b/UI/MailPartViewers/UIxMailPartTextViewer.m index 22d41a38..d4ff0ccd 100644 --- a/UI/MailPartViewers/UIxMailPartTextViewer.m +++ b/UI/MailPartViewers/UIxMailPartTextViewer.m @@ -34,18 +34,74 @@ #import "UIxMailPartTextViewer.h" +@interface NSString (SOGoMailUIExtension) + +- (NSString *) stringByConvertingCRLNToHTML; + +@end + +@implementation NSString (SOGoMailUIExtension) + +- (NSString *) stringByConvertingCRLNToHTML +{ + NSString *convertedString; + const char *oldString, *currentChar; + char *newString, *destChar; + unsigned int oldLength, length, delta; + + oldString = [self cStringUsingEncoding: NSUTF8StringEncoding]; + oldLength = [self lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; + + length = oldLength; + newString = malloc (length + 500); + destChar = newString; + currentChar = oldString; + while (currentChar < (oldString + oldLength)) + { + if (*currentChar != '\r') + { + if (*currentChar == '\n') + { + strcpy (destChar, "
"); + destChar += 6; + delta = (destChar - newString); + if (delta > length) + { + length += 500; + newString = realloc (newString, length + 500); + destChar = newString + delta; + } + } + else + { + *destChar = *currentChar; + destChar++; + } + } + currentChar++; + } + *destChar = 0; + + convertedString = [[NSString alloc] initWithBytes: newString + length: (destChar + 1 - newString) + encoding: NSUTF8StringEncoding]; + [convertedString autorelease]; + free (newString); + + return convertedString; +} + +@end + @implementation UIxMailPartTextViewer - (NSString *) flatContentAsString { - NSMutableString *content; NSString *superContent; - content = [NSMutableString string]; superContent = [[super flatContentAsString] stringByEscapingHTMLString]; - [content appendString: [superContent stringByDetectingURLs]]; - return content; + return [[superContent stringByDetectingURLs] stringByConvertingCRLNToHTML]; } @end /* UIxMailPartTextViewer */ diff --git a/UI/MailPartViewers/UIxMailPartViewer.m b/UI/MailPartViewers/UIxMailPartViewer.m index ab4ace1c..78a8fc8e 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.m +++ b/UI/MailPartViewers/UIxMailPartViewer.m @@ -176,27 +176,19 @@ { charset = [[bodyInfo objectForKey:@"parameterList"] objectForKey: @"charset"]; - charset = [charset lowercaseString]; - if (![charset length] - || [charset isEqualToString: @"us-ascii"]) + if ([charset length]) + charset = [charset lowercaseString]; + else + charset = @"us-ascii"; + s = [NSString stringWithData: content usingEncodingNamed: charset]; + if (![s length]) { + /* latin 1 is used as a 8bit fallback charset... but does this + encoding accept any byte from 0 to 255? */ s = [[NSString alloc] initWithData: content encoding: NSISOLatin1StringEncoding]; [s autorelease]; } - else - { - s = [NSString stringWithData: content - usingEncodingNamed: charset]; - if (![s length]) - { - /* latin 1 is used as a 8bit fallback charset... but does this - encoding accept any byte from 0 to 255? */ - s = [[NSString alloc] initWithData: content - encoding: NSISOLatin1StringEncoding]; - [s autorelease]; - } - } if (!s) { diff --git a/UI/MailerUI/UIxMailListView.h b/UI/MailerUI/UIxMailListView.h index 8ab751e3..8da0e5aa 100644 --- a/UI/MailerUI/UIxMailListView.h +++ b/UI/MailerUI/UIxMailListView.h @@ -36,6 +36,7 @@ EOQualifier *qualifier; SOGoDateFormatter *dateFormatter; NSTimeZone *userTimeZone; + int folderType; } - (NSString *) defaultSortKey; diff --git a/UI/MailerUI/UIxMailListView.m b/UI/MailerUI/UIxMailListView.m index be291094..ed4d74f4 100644 --- a/UI/MailerUI/UIxMailListView.m +++ b/UI/MailerUI/UIxMailListView.m @@ -38,8 +38,10 @@ #import +#import #import #import +#import #import #import #import @@ -60,6 +62,7 @@ user = [context activeUser]; ASSIGN (dateFormatter, [user dateFormatterInContext: context]); ASSIGN (userTimeZone, [user timeZone]); + folderType = 0; } return self; @@ -113,10 +116,19 @@ - (BOOL) showToAddress { - NSString *ftype; - - ftype = [[self clientObject] valueForKey:@"outlookFolderClass"]; - return [ftype isEqual:@"IPF.Sent"]; + SOGoMailFolder *co; + + if (!folderType) + { + co = [self clientObject]; + if ([co isKindOfClass: [SOGoSentFolder class]] + || [co isKindOfClass: [SOGoDraftsFolder class]]) + folderType = 1; + else + folderType = -1; + } + + return (folderType == 1); } /* title */ @@ -161,39 +173,36 @@ - (NSString *) messageRowStyleClass { - return [self isMessageDeleted] - ? @"mailer_listcell_deleted" - : @"mailer_listcell_regular"; + NSString *rowClass; + + rowClass = [self isMessageDeleted]? @"mailer_listcell_deleted" : @"mailer_listcell_regular"; + + if (![self isMessageRead]) + rowClass = [rowClass stringByAppendingString: @" mailer_unreadmail"]; + + return rowClass; } - (NSString *) messageSubjectCellStyleClass { NSArray *flags; - NSString *cellClass; + NSString *cellClass = @"messageSubjectColumn "; flags = [[self message] valueForKey:@"flags"]; - if ([flags containsObject: @"seen"]) + if ([flags containsObject: @"answered"]) { - if ([flags containsObject: @"answered"]) - { - if ([flags containsObject: @"$forwarded"]) - cellClass = @"mailer_forwardedrepliedmailsubject"; - else - cellClass = @"mailer_repliedmailsubject"; - } - else if ([flags containsObject: @"$forwarded"]) - cellClass = @"mailer_forwardedmailsubject"; + if ([flags containsObject: @"$forwarded"]) + cellClass = [cellClass stringByAppendingString: @"mailer_forwardedrepliedmailsubject"]; else - cellClass = @"mailer_readmailsubject"; + cellClass = [cellClass stringByAppendingString: @"mailer_repliedmailsubject"]; } + else if ([flags containsObject: @"$forwarded"]) + cellClass = [cellClass stringByAppendingString: @"mailer_forwardedmailsubject"]; else - cellClass = @"mailer_unreadmailsubject"; + cellClass = [cellClass stringByAppendingString: @"mailer_readmailsubject"]; return cellClass; -// return ([self isMessageRead] -// ? @"mailer_readmailsubject" -// : @"mailer_unreadmailsubject"); } - (BOOL) hasMessageAttachment diff --git a/UI/WebServerResources/MailerUI.css b/UI/WebServerResources/MailerUI.css index a5cd1c5a..ead44e6f 100644 --- a/UI/WebServerResources/MailerUI.css +++ b/UI/WebServerResources/MailerUI.css @@ -243,9 +243,14 @@ TD.mailer_readmailsubject padding-left: 20px !important; } -TD.mailer_unreadmailsubject +TR.mailer_unreadmail TD { - background-image: url(icon-new.png) !important; + font-weight: bold !important; +} + +TR.mailer_unreadmail TD.messageSubjectColumn +{ + background-image: url(icon-new.png); background-repeat: no-repeat !important; background-position: 0px 0px !important; padding-left: 20px !important; diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index a87b84a8..9bb9fccc 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -83,45 +83,36 @@ function onMenuSharing(event) { /* mail list DOM changes */ function markMailInWindow(win, msguid, markread) { - var msgDiv; - - msgDiv = win.$("div_" + msguid); - if (msgDiv) { + var row = win.$("row_" + msguid); + var subjectCell = win.$("div_" + msguid); + if (row && subjectCell) { if (markread) { - msgDiv.removeClassName("mailer_unreadmailsubject"); - msgDiv.addClassName("mailer_readmailsubject"); - msgDiv = win.$("unreaddiv_" + msguid); - if (msgDiv) - { - msgDiv.setAttribute("class", "mailerUnreadIcon"); - msgDiv.setAttribute("id", "readdiv_" + msguid); - msgDiv.setAttribute("src", ResourcesURL + "/icon_read.gif"); - msgDiv.setAttribute("onclick", "mailListMarkMessage(this," - + " 'markMessageUnread', " + msguid - + ", false);" - +" return false;"); - var title = msgDiv.getAttribute("title-markunread"); - if (title) - msgDiv.setAttribute("title", title); - } + row.removeClassName("mailer_unreadmail"); + subjectCell.addClassName("mailer_readmailsubject"); + var img = win.$("unreaddiv_" + msguid); + if (img) { + img.removeClassName("mailerUnreadIcon"); + img.addClassName("mailerReadIcon"); + img.setAttribute("id", "readdiv_" + msguid); + img.setAttribute("src", ResourcesURL + "/icon_read.gif"); + var title = img.getAttribute("title-markunread"); + if (title) + img.setAttribute("title", title); + } } else { - msgDiv.removeClassName('mailer_readmailsubject'); - msgDiv.addClassName('mailer_unreadmailsubject'); - msgDiv = win.$("readdiv_" + msguid); - if (msgDiv) - { - msgDiv.setAttribute("class", "mailerReadIcon"); - msgDiv.setAttribute("id", "unreaddiv_" + msguid); - msgDiv.setAttribute("src", ResourcesURL + "/icon_unread.gif"); - msgDiv.setAttribute("onclick", "mailListMarkMessage(this," - + " 'markMessageRead', " + msguid - + ", true);" - +" return false;"); - var title = msgDiv.getAttribute("title-markread"); - if (title) - msgDiv.setAttribute("title", title); - } + row.addClassName("mailer_unreadmail"); + subjectCell.removeClassName('mailer_readmailsubject'); + var img = win.$("readdiv_" + msguid); + if (img) { + img.removeClassName("mailerReadIcon"); + img.addClassName("mailerUnreadIcon"); + img.setAttribute("id", "unreaddiv_" + msguid); + img.setAttribute("src", ResourcesURL + "/icon_unread.gif"); + var title = img.getAttribute("title-markread"); + if (title) + img.setAttribute("title", title); + } } return true; } @@ -161,25 +152,36 @@ function openMessageWindowsForSelection(action, firstOnly) { } function mailListMarkMessage(event) { - var http = createHTTPClient(); + var msguid = this.id.split('_')[1]; + var action; + var markread; + if ($(this).hasClassName('mailerUnreadIcon')) { + action = 'markMessageRead'; + markread = true; + } + else { + action = 'markMessageUnread'; + markread = false; + } var url = ApplicationBaseURL + currentMailbox + "/" + msguid + "/" + action; - if (http) { - // TODO: add parameter to signal that we are only interested in OK - http.open("POST", url, false /* not async */); - http.send(""); - if (http.status != 200) { - // TODO: refresh page? - alert("Message Mark Failed: " + http.statusText); - window.location.reload(); + var data = { "window": window, "msguid": msguid, "markread": markread }; + triggerAjaxRequest(url, mailListMarkMessageCallback, data); + + preventDefault(event); + return false; +} + +function mailListMarkMessageCallback(http) { + if (http.readyState == 4) + if (isHttpStatus204(http.status)) { + var data = http.callbackData; + markMailInWindow(data["window"], data["msguid"], data["markread"]); } else { - markMailInWindow(window, msguid, markread); + alert("Message Mark Failed (" + http.status + "): " + http.statusText); + window.location.reload(); } - } - else { - window.location.href = url; - } } /* maillist row highlight */ @@ -210,7 +212,7 @@ function deleteSelectedMessages(sender) { var rowIds = messageList.getSelectedRowsId(); for (var i = 0; i < rowIds.length; i++) { - var url, http; + var url; var rowId = rowIds[i].substr(4); var messageId = currentMailbox + "/" + rowId; url = ApplicationBaseURL + messageId + "/trash"; @@ -699,12 +701,12 @@ function loadMessage(idx) { var cachedMessage = getCachedMessage(idx); + markMailInWindow(window, idx, true); if (cachedMessage == null) { var url = (ApplicationBaseURL + currentMailbox + "/" + idx + "/view?noframe=1"); document.messageAjaxRequest = triggerAjaxRequest(url, messageCallback, idx); - markMailInWindow(window, idx, true); } else { var div = $('messageContent'); div.update(cachedMessage['text']); @@ -1054,7 +1056,7 @@ function configureMessageListBodyEvents(table) { Event.observe(cell, "dblclick", onMessageDoubleClick.bindAsEventListener(cell)); else if (j == 4) { var img = cell.childNodesWithTag("img")[0]; - Event.observe(img, "click", mailListMarkMessage); + Event.observe(img, "click", mailListMarkMessage.bindAsEventListener(img)); } } } @@ -1351,7 +1353,7 @@ function onMenuCreateFolder(event) { var name = window.prompt(labels["Name :"], ""); if (name && name.length > 0) { var folderID = document.menuTarget.getAttribute("dataname"); - var urlstr = URLForFolderID(folderID) + "/createFolder?name=" + name; log ("create " + urlstr); + var urlstr = URLForFolderID(folderID) + "/createFolder?name=" + name; triggerAjaxRequest(urlstr, folderOperationCallback); } } -- 2.39.5