+2007-05-15 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/Appointments/SOGoAppointmentFolder.m
+ ([SOGoAppointmentFolder -fetchContentObjectNames]): override
+ method to return the events in the range of 2 weeks ago up to 4
+ weeks from "now".
+
+ * UI/MailPartViewers/UIxMailPartTextViewer.m
+ ([UIxMailPartTextViewer -flatContentAsString]): use the new
+ "stringByDetectingURLs" method to offer clickable urls.
+
+ * SoObjects/SOGo/NSString+Utilities.m ([NSString
+ -stringByDetectingURLs]): this new method replaces passive URLS
+ with active ones for HTML resolution of the text.
+
2007-05-14 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/Mailer/SOGoDraftObject.m ([NSString
return calendarFolders;
}
+- (NSArray *) fetchContentObjectNames
+{
+ NSMutableArray *objectNames;
+ NSArray *records;
+ NSCalendarDate *today, *startDate, *endDate;
+
+#warning this should be user-configurable
+ objectNames = [NSMutableArray array];
+ today = [[NSCalendarDate calendarDate] beginOfDay];
+ [today setTimeZone: timeZone];
+
+ startDate = [today dateByAddingYears: 0 months: 0 days: -14
+ hours: 0 minutes: 0 seconds: 0];
+ endDate = [startDate dateByAddingYears: 0 months: 1 days: 0
+ hours: 0 minutes: 0 seconds: 0];
+ records = [self fetchFields: [NSArray arrayWithObject: @"c_name"]
+ from: startDate to: endDate
+ component: @"vevent"];
+ [objectNames addObjectsFromArray: [records valueForKey: @"c_name"]];
+ records = [self fetchFields: [NSArray arrayWithObject: @"c_name"]
+ from: startDate to: endDate
+ component: @"vtodo"];
+ [objectNames addObjectsFromArray: [records valueForKey: @"c_name"]];
+
+ return objectNames;
+}
+
/* folder type */
- (NSString *) folderType
- (NSString *) davMethodToObjC;
+- (NSString *) stringByDetectingURLs;
+
#ifndef GNUSTEP_BASE_LIBRARY
- (BOOL) boolValue;
#endif
*/
#import <Foundation/NSArray.h>
+#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSEnumerator.h>
#import "NSString+Utilities.h"
#import "NSDictionary+URL.h"
+static NSMutableCharacterSet *urlNonEndingChars = nil;
+static NSMutableCharacterSet *urlAfterEndingChars = nil;
+
@implementation NSString (SOGoURLExtension)
- (NSString *) composeURLWithAction: (NSString *) action
return newName;
}
-#ifndef GNUSTEP_BASE_LIBRARY
+- (NSRange) _rangeOfURLInRange: (NSRange) refRange
+{
+ int start, length;
+ NSRange endRange;
+
+ if (!urlNonEndingChars)
+ {
+ urlNonEndingChars = [NSMutableCharacterSet new];
+ [urlNonEndingChars addCharactersInString: @",.:;\t \r\n"];
+ }
+ if (!urlAfterEndingChars)
+ {
+ urlAfterEndingChars = [NSMutableCharacterSet new];
+ [urlAfterEndingChars addCharactersInString: @"\t \r\n"];
+ }
+
+ start = refRange.location;
+ while (start > -1
+ && [self characterAtIndex: start] != ' ')
+ start--;
+ start++;
+ length = [self length] - start;
+ endRange = NSMakeRange (start, length);
+ endRange = [self rangeOfCharacterFromSet: urlAfterEndingChars
+ options: NSLiteralSearch range: endRange];
+ if (endRange.location != NSNotFound)
+ length = endRange.location;
+ length -= start;
+ while
+ ([urlNonEndingChars characterIsMember:
+ [self characterAtIndex: (start + length - 1)]])
+ length--;
+
+ return NSMakeRange (start, length);
+}
+
+- (NSString *) stringByDetectingURLs
+{
+ NSMutableString *selfCopy;
+ NSRange httpRange, currentURL, rest;
+ NSString *urlText, *newUrlText;
+ unsigned int length;
+
+ selfCopy = [NSMutableString stringWithString: self];
+
+ httpRange = [selfCopy rangeOfString: @"://"];
+ while (httpRange.location != NSNotFound)
+ {
+ currentURL = [selfCopy _rangeOfURLInRange: httpRange];
+ urlText = [selfCopy substringFromRange: currentURL];
+ newUrlText = [NSString stringWithFormat: @"<a href=\"%@\">%@</a>",
+ urlText, urlText];
+ [selfCopy replaceCharactersInRange: currentURL
+ withString: newUrlText];
+ length = [selfCopy length];
+ rest.location = currentURL.location + [newUrlText length];
+ rest.length = length - rest.location;
+ httpRange = [selfCopy rangeOfString: @"://"
+ options: 0 range: rest];
+ }
+
+ return selfCopy;
+}
+
+#if LIB_FOUNDATION_LIBRARY
- (BOOL) boolValue
{
return !([self isEqualToString: @"0"]
TODO: add contained link detection.
*/
+#import <SoObjects/SOGo/NSString+Utilities.h>
+
#import "common.h"
#import "UIxMailPartTextViewer.h"
- (NSString *) flatContentAsString
{
- NSString *content;
-
- content = [[super flatContentAsString] stringByEscapingHTMLString];
- content = [content stringByReplacingString: @"\r\n"
- withString: @"<br />"];
-
- return [content stringByReplacingString: @"\n"
- withString: @"<br />"];
+ NSMutableString *content;
+ NSString *superContent, *urlText, *newUrlText;
+ NSRange httpRange, rest, currentURL;
+ unsigned int length;
+
+ content = [NSMutableString string];
+ superContent = [[super flatContentAsString] stringByEscapingHTMLString];
+ [content appendString: [superContent stringByDetectingURLs]];
+ [content replaceString: @"\r\n" withString: @"<br />"];
+ [content replaceString: @"\n" withString: @"<br />"];
+
+ return content;
}
@end /* UIxMailPartTextViewer */
}
function loadMessage(idx) {
- var cachedMessage = getCachedMessage(idx);
-
if (document.messageAjaxRequest) {
document.messageAjaxRequest.aborted = true;
document.messageAjaxRequest.abort();
}
+ var cachedMessage = getCachedMessage(idx);
+
if (cachedMessage == null) {
var url = (ApplicationBaseURL + currentMailbox + "/"
+ idx + "/view?noframe=1");
div.innerHTML = cachedMessage['text'];
cachedMessage['time'] = (new Date()).getTime();
document.messageAjaxRequest = null;
+ configureLinksInMessageDIV(div);
}
}
+function configureLinksInMessageDIV(div) {
+ var anchors = div.getElementsByTagName('a');
+ for (var i = 0; i < anchors.length; i++)
+ anchors[i].addEventListener("click", onMessageAnchorClick, false);
+}
+
+function onMessageAnchorClick (event) {
+ window.open(this.href);
+ event.preventDefault();
+}
+
function messageCallback(http) {
var div = $('messageContent');
&& http.status == 200) {
document.messageAjaxRequest = null;
div.innerHTML = http.responseText;
-
+ configureLinksInMessageDIV(div);
+
if (http.callbackData) {
var cachedMessage = new Array();
cachedMessage['idx'] = currentMailbox + '/' + http.callbackData;
DIV#calendarSelectorView
{ top: 0px; }
+DIV#calendarSelectorView
+{ overflow: hidden; }
+
DIV#calendarsList
{ height: 100%;
padding: 0px;
{ cursor: default;
margin: .25em;
padding: 0px;
- overflow: auto;
overflow-x: hidden;
overflow-y: auto;
border-bottom: 1px solid #fff;
margin: 0px;
margin-left: 5px;
padding: 0px;
- overflow: hidden;
-}
+ overflow: hidden; }
DIV#appointmentsListView
{
position: absolute;
+ display: block;
background: #fff;
height: 15.5em;
- top: 2.5em;
- left: 0px;
- width: 100%;
- overflow: auto;
-}
+ margin: 0.5em 0px 0px 0px;
+ min-width: 600px; }
DIV#calendarView
{
margin-top: 5px;
bottom: 0px;
width: 100%;
- overflow: hidden;
border-top: 1px solid #aaa;
border-left: 1px solid #aaa;
}
border: 1px solid #deebf7; }
TABLE#appointmentsList
-{ width: 100%; }
+{ ddisplay: table; }
+
+TABLE#appointmentsList td.tbtv_subject_headercell
+ { width: 35%; }
+
+TABLE#appointmentsList td.headerDateTime
+{ width: 17em; }
+
+TABLE#appointmentsList td.headerLocation
+{ width: 20%; }
#dateSelector TD._selected,
UL > LI._selected,