mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-03-08 00:11:22 +00:00
merge of '571d9bfb5bd40cb2435fe9c4ecec1069f13f7a7d'
and 'b8d56bd5a31be825cfe66b8fe9f9a15269a09fbc' Monotone-Parent: 571d9bfb5bd40cb2435fe9c4ecec1069f13f7a7d Monotone-Parent: b8d56bd5a31be825cfe66b8fe9f9a15269a09fbc Monotone-Revision: 787fab4426e6ea6fab09ccfcc61ecc658e06ed5e Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2009-06-12T15:56:10 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
28
ChangeLog
28
ChangeLog
@@ -4,6 +4,34 @@
|
||||
-addressBooksList]): LDAP-based addressbooks must not be
|
||||
editable, even for super users.
|
||||
|
||||
2009-06-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/SOGoUserFolder.m (-davUserQuery:): do not return
|
||||
the user information for the current user.
|
||||
|
||||
* UI/MainUI/SOGoUserHomePage.m (-usersSearchAction): do not return
|
||||
the user information for the current user.
|
||||
(-foldersSearchAction): the method only search folders for the
|
||||
owner of the current folder. The "user" parameter has thus been
|
||||
removed.
|
||||
|
||||
2009-06-10 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/NSString+Utilities.m (-stringByDetectingURLs):
|
||||
fixed a leak. Fixed a crash on GNUstep by using arrays of pointers
|
||||
to NSRange instead of converting/parsing them to/from NSString.
|
||||
|
||||
* SoObjects/SOGo/NSArray+Utilities.m (-addRange): removed method.
|
||||
(-addNonNSObject:withSize:copy:): new helper method to add object
|
||||
pointers to arrays.
|
||||
(-freeNonNSObjects): new helper method to release the above object
|
||||
pointers.
|
||||
|
||||
* UI/MailPartViewers/UIxMailPartHTMLViewer.m: fixed rendering of
|
||||
CSS content containing comment characters. Ignore certain HTML
|
||||
tags that can alter the appearance of the SOGo display altogether
|
||||
(SCRIPT, LINK, BASE, META, TITLE).
|
||||
|
||||
2009-06-09 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/Appointments/SOGoFreeBusyObject.m
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#define SOGOUSERFOLDER_CONTACTS_H
|
||||
|
||||
@class NSArray;
|
||||
@class NSString;
|
||||
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
|
||||
|
||||
@@ -53,9 +53,13 @@
|
||||
|
||||
@interface NSMutableArray (SOGoArrayUtilities)
|
||||
|
||||
- (void) addNonNSObject: (void *) objectPtr
|
||||
withSize: (size_t) objectSize
|
||||
copy: (BOOL) doCopy;
|
||||
- (void) freeNonNSObjects;
|
||||
|
||||
- (void) addObjectUniquely: (id) object;
|
||||
|
||||
- (void) addRange: (NSRange) newRange;
|
||||
- (BOOL) hasRangeIntersection: (NSRange) testRange;
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import "NSArray+Utilities.h"
|
||||
|
||||
@@ -199,17 +200,42 @@
|
||||
|
||||
@implementation NSMutableArray (SOGoArrayUtilities)
|
||||
|
||||
- (void) addNonNSObject: (void *) objectPtr
|
||||
withSize: (size_t) objectSize
|
||||
copy: (BOOL) doCopy
|
||||
{
|
||||
void *newObjectPtr;
|
||||
|
||||
if (doCopy)
|
||||
{
|
||||
newObjectPtr = NSZoneMalloc (NULL, objectSize);
|
||||
memcpy (newObjectPtr, objectPtr, objectSize);
|
||||
}
|
||||
else
|
||||
newObjectPtr = objectPtr;
|
||||
|
||||
[self addObject: [NSValue valueWithPointer: newObjectPtr]];
|
||||
}
|
||||
|
||||
- (void) freeNonNSObjects
|
||||
{
|
||||
unsigned int count, max;
|
||||
void *objectPtr;
|
||||
|
||||
max = [self count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
objectPtr = [[self objectAtIndex: count] pointerValue];
|
||||
NSZoneFree (NULL, objectPtr);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) addObjectUniquely: (id) object
|
||||
{
|
||||
if (![self containsObject: object])
|
||||
[self addObject: object];
|
||||
}
|
||||
|
||||
- (void) addRange: (NSRange) newRange
|
||||
{
|
||||
[self addObject: NSStringFromRange (newRange)];
|
||||
}
|
||||
|
||||
- (BOOL) hasRangeIntersection: (NSRange) testRange
|
||||
{
|
||||
NSEnumerator *ranges;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCharacterSet.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <EOControl/EOQualifier.h>
|
||||
|
||||
@@ -88,7 +89,7 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
|
||||
r = [self rangeOfString:@"?" options: NSBackwardsSearch];
|
||||
if (r.length > 0)
|
||||
newUrl = [self substringToIndex: NSMaxRange(r) - 1];
|
||||
newUrl = [self substringToIndex: NSMaxRange (r) - 1];
|
||||
else
|
||||
newUrl = self;
|
||||
|
||||
@@ -132,11 +133,10 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
{
|
||||
nsEnclosing = [self rangeOfString: @"}"];
|
||||
length = [self length];
|
||||
if (nsEnclosing.length > 0
|
||||
&& nsEnclosing.location < (length - 1))
|
||||
if (nsEnclosing.length > 0 && nsEnclosing.location < (length - 1))
|
||||
{
|
||||
methodEnclosing = NSMakeRange(nsEnclosing.location + 1,
|
||||
length - nsEnclosing.location - 1);
|
||||
methodEnclosing = NSMakeRange (nsEnclosing.location + 1,
|
||||
length - nsEnclosing.location - 1);
|
||||
nsEnclosing.length = nsEnclosing.location - 1;
|
||||
nsEnclosing.location = 1;
|
||||
davInvocation = [NSMutableDictionary dictionaryWithCapacity: 2];
|
||||
@@ -176,7 +176,7 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
start--;
|
||||
start++;
|
||||
length = [self length] - start;
|
||||
workRange = NSMakeRange(start, length);
|
||||
workRange = NSMakeRange (start, length);
|
||||
workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars
|
||||
options: NSLiteralSearch range: workRange];
|
||||
if (workRange.location != NSNotFound)
|
||||
@@ -198,7 +198,8 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
NSEnumerator *enumRanges;
|
||||
NSMutableArray *newRanges;
|
||||
NSRange matchRange, currentUrlRange, rest;
|
||||
NSString *urlText, *newUrlText, *range;
|
||||
NSRange *rangePtr;
|
||||
NSString *urlText, *newUrlText;
|
||||
unsigned int length, matchLength, offset;
|
||||
int startLocation;
|
||||
|
||||
@@ -209,10 +210,11 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
@"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@"0123456789:@"];
|
||||
}
|
||||
newRanges = [NSMutableArray new];
|
||||
|
||||
newRanges = [NSMutableArray array];
|
||||
matchLength = [match length];
|
||||
rest.location = -1;
|
||||
|
||||
|
||||
matchRange = [selfCopy rangeOfString: match];
|
||||
while (matchRange.location != NSNotFound)
|
||||
{
|
||||
@@ -225,12 +227,14 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
|
||||
currentUrlRange = [selfCopy _rangeOfURLInRange: matchRange];
|
||||
if ([ranges hasRangeIntersection: currentUrlRange])
|
||||
rest.location = NSMaxRange(currentUrlRange);
|
||||
rest.location = NSMaxRange (currentUrlRange);
|
||||
else
|
||||
{
|
||||
if (currentUrlRange.length > matchLength)
|
||||
[newRanges addRange: currentUrlRange];
|
||||
rest.location = NSMaxRange(currentUrlRange);
|
||||
[newRanges addNonNSObject: ¤tUrlRange
|
||||
withSize: sizeof (NSRange)
|
||||
copy: YES];
|
||||
rest.location = NSMaxRange (currentUrlRange);
|
||||
}
|
||||
|
||||
length = [selfCopy length];
|
||||
@@ -242,25 +246,24 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
// Make the substitutions, keep track of the new offset
|
||||
offset = 0;
|
||||
enumRanges = [newRanges objectEnumerator];
|
||||
range = [enumRanges nextObject];
|
||||
while (range)
|
||||
while ((rangePtr = [[enumRanges nextObject] pointerValue]))
|
||||
{
|
||||
currentUrlRange = NSRangeFromString(range);
|
||||
currentUrlRange.location += offset;
|
||||
urlText = [selfCopy substringFromRange: currentUrlRange];
|
||||
rangePtr->location += offset;
|
||||
urlText = [selfCopy substringFromRange: *rangePtr];
|
||||
if ([urlText hasPrefix: prefix]) prefix = @"";
|
||||
newUrlText = [NSString stringWithFormat: @"<a href=\"%@%@\">%@</a>",
|
||||
prefix, urlText, urlText];
|
||||
[selfCopy replaceCharactersInRange: currentUrlRange
|
||||
[selfCopy replaceCharactersInRange: *rangePtr
|
||||
withString: newUrlText];
|
||||
offset += ([newUrlText length] - [urlText length]);
|
||||
|
||||
// Add range for further substitutions
|
||||
currentUrlRange = NSMakeRange (currentUrlRange.location, [newUrlText length]);
|
||||
[ranges addRange: currentUrlRange];
|
||||
|
||||
range = [enumRanges nextObject];
|
||||
[ranges addNonNSObject: ¤tUrlRange
|
||||
withSize: sizeof (NSRange)
|
||||
copy: YES];
|
||||
}
|
||||
[newRanges freeNonNSObjects];
|
||||
}
|
||||
|
||||
- (NSString *) stringByDetectingURLs
|
||||
@@ -268,7 +271,7 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
NSMutableString *selfCopy;
|
||||
NSMutableArray *ranges;
|
||||
|
||||
ranges = [NSMutableArray new];
|
||||
ranges = [NSMutableArray array];
|
||||
selfCopy = [NSMutableString stringWithString: self];
|
||||
[self _handleURLs: selfCopy
|
||||
textToMatch: @"://"
|
||||
@@ -278,7 +281,7 @@ static NSMutableCharacterSet *urlStartChars = nil;
|
||||
textToMatch: @"@"
|
||||
prefix: @"mailto:"
|
||||
inRanges: ranges];
|
||||
[ranges release];
|
||||
[ranges freeNonNSObjects];
|
||||
|
||||
return selfCopy;
|
||||
}
|
||||
|
||||
@@ -718,7 +718,7 @@ static NSArray *childRecordFields = nil;
|
||||
|
||||
currentUser = [localContext activeUser];
|
||||
|
||||
if (delegatedUsers && [delegatedUsers count])
|
||||
if ([delegatedUsers count])
|
||||
{
|
||||
if (![currentUser isSuperUser])
|
||||
{
|
||||
|
||||
@@ -129,7 +129,8 @@ static NSString *LDAPContactInfoAttribute = nil;
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
node = [children objectAtIndex: count];
|
||||
componentName = [[(id<DOMElement>)node attribute: @"name"] lowercaseString];
|
||||
componentName = [[(id<DOMElement>)node attribute: @"name"]
|
||||
lowercaseString];
|
||||
[filter setObject: [node textValue] forKey: componentName];
|
||||
}
|
||||
|
||||
@@ -381,13 +382,14 @@ static NSString *LDAPContactInfoAttribute = nil;
|
||||
LDAPUserManager *um;
|
||||
NSMutableString *fetch;
|
||||
NSDictionary *currentUser;
|
||||
NSString *field;
|
||||
NSString *field, *login;
|
||||
NSArray *users;
|
||||
int i;
|
||||
|
||||
#warning the attributes returned here should match the one requested in the query
|
||||
fetch = [NSMutableString string];
|
||||
|
||||
login = [[context activeUser] login];
|
||||
um = [LDAPUserManager sharedUserManager];
|
||||
|
||||
// We sort our array - this is pretty useful for the
|
||||
@@ -397,25 +399,26 @@ static NSString *LDAPContactInfoAttribute = nil;
|
||||
for (i = 0; i < [users count]; i++)
|
||||
{
|
||||
currentUser = [users objectAtIndex: i];
|
||||
|
||||
[fetch appendString: @"<user>"];
|
||||
field = [currentUser objectForKey: @"c_uid"];
|
||||
[fetch appendFormat: @"<id>%@</id>",
|
||||
[field stringByEscapingXMLString]];
|
||||
field = [currentUser objectForKey: @"cn"];
|
||||
[fetch appendFormat: @"<displayName>%@</displayName>",
|
||||
[field stringByEscapingXMLString]];
|
||||
field = [currentUser objectForKey: @"c_email"];
|
||||
[fetch appendFormat: @"<email>%@</email>",
|
||||
[field stringByEscapingXMLString]];
|
||||
if (LDAPContactInfoAttribute)
|
||||
{
|
||||
field = [currentUser objectForKey: LDAPContactInfoAttribute];
|
||||
if ([field length])
|
||||
[fetch appendFormat: @"<info>%@</info>",
|
||||
[field stringByEscapingXMLString]];
|
||||
}
|
||||
[fetch appendString: @"</user>"];
|
||||
if (![field isEqualToString: login])
|
||||
{
|
||||
[fetch appendFormat: @"<user><id>%@</id>",
|
||||
[field stringByEscapingXMLString]];
|
||||
field = [currentUser objectForKey: @"cn"];
|
||||
[fetch appendFormat: @"<displayName>%@</displayName>",
|
||||
[field stringByEscapingXMLString]];
|
||||
field = [currentUser objectForKey: @"c_email"];
|
||||
[fetch appendFormat: @"<email>%@</email>",
|
||||
[field stringByEscapingXMLString]];
|
||||
if (LDAPContactInfoAttribute)
|
||||
{
|
||||
field = [currentUser objectForKey: LDAPContactInfoAttribute];
|
||||
if ([field length])
|
||||
[fetch appendFormat: @"<info>%@</info>",
|
||||
[field stringByEscapingXMLString]];
|
||||
}
|
||||
[fetch appendString: @"</user>"];
|
||||
}
|
||||
}
|
||||
|
||||
return fetch;
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
#define showWhoWeAre()
|
||||
#endif
|
||||
|
||||
/* Tags that are forbidden within the body of the html content */
|
||||
static NSArray *BannedTags = nil;
|
||||
|
||||
static xmlCharEncoding
|
||||
_xmlCharsetForCharset (NSString *charset)
|
||||
{
|
||||
@@ -102,14 +105,14 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
NSMutableString *result;
|
||||
NSMutableString *css;
|
||||
NSDictionary *attachmentIds;
|
||||
BOOL ignoreContent;
|
||||
NSString *ignoreTag;
|
||||
BOOL inBody;
|
||||
BOOL inStyle;
|
||||
BOOL inScript;
|
||||
BOOL inCSSDeclaration;
|
||||
BOOL hasEmbeddedCSS;
|
||||
BOOL hasExternalImages;
|
||||
BOOL unsafe;
|
||||
NSMutableArray *crumb;
|
||||
xmlCharEncoding contentEncoding;
|
||||
}
|
||||
|
||||
@@ -119,13 +122,23 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
|
||||
@implementation _UIxHTMLMailContentHandler
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (!BannedTags)
|
||||
{
|
||||
BannedTags = [NSArray arrayWithObjects: @"SCRIPT", @"LINK", @"BASE",
|
||||
@"META", @"TITLE", nil];
|
||||
[BannedTags retain];
|
||||
}
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
crumb = nil;
|
||||
css = nil;
|
||||
result = nil;
|
||||
ignoreTag = nil;
|
||||
attachmentIds = nil;
|
||||
contentEncoding = XML_CHAR_ENCODING_UTF8;
|
||||
}
|
||||
@@ -135,7 +148,6 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[crumb release];
|
||||
[result release];
|
||||
[css release];
|
||||
[super dealloc];
|
||||
@@ -181,34 +193,25 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
{
|
||||
showWhoWeAre();
|
||||
|
||||
[crumb release];
|
||||
[css release];
|
||||
[result release];
|
||||
|
||||
result = [NSMutableString new];
|
||||
css = [NSMutableString new];
|
||||
crumb = [NSMutableArray new];
|
||||
|
||||
ignoreContent = NO;
|
||||
[ignoreTag release];
|
||||
ignoreTag = nil;
|
||||
|
||||
inBody = NO;
|
||||
inStyle = NO;
|
||||
inScript = NO;
|
||||
inCSSDeclaration = NO;
|
||||
hasEmbeddedCSS = NO;
|
||||
}
|
||||
|
||||
- (void) endDocument
|
||||
{
|
||||
unsigned int count, max;
|
||||
|
||||
|
||||
showWhoWeAre();
|
||||
max = [crumb count];
|
||||
if (max > 0)
|
||||
for (count = max - 1; count > -1; count--)
|
||||
{
|
||||
[result appendFormat: @"</%@>", [crumb objectAtIndex: count]];
|
||||
[crumb removeObjectAtIndex: count];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) startPrefixMapping: (NSString *)_prefix
|
||||
@@ -225,10 +228,13 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
- (void) _appendStyle: (unichar *) _chars
|
||||
length: (int) _len
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned int count, length;
|
||||
unichar *start, *currentChar;
|
||||
|
||||
start = _chars;
|
||||
while (*start < 33)
|
||||
start++;
|
||||
|
||||
currentChar = start;
|
||||
for (count = 0; count < _len; count++)
|
||||
{
|
||||
@@ -243,28 +249,39 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*currentChar == '{')
|
||||
inCSSDeclaration = YES;
|
||||
if (*currentChar == ',')
|
||||
hasEmbeddedCSS = NO;
|
||||
else if (!hasEmbeddedCSS)
|
||||
if (*currentChar < 32)
|
||||
{
|
||||
if (*currentChar == '@')
|
||||
hasEmbeddedCSS = YES;
|
||||
else
|
||||
if (*currentChar > 32)
|
||||
{
|
||||
[css appendString: [NSString stringWithCharacters: start
|
||||
length: (currentChar - start)]];
|
||||
[css appendString: @".SOGoHTMLMail-CSS-Delimiter "];
|
||||
if (currentChar > start)
|
||||
[css appendString: [NSString stringWithCharacters: start
|
||||
length: (currentChar - start)]];
|
||||
start = currentChar + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*currentChar == '{')
|
||||
inCSSDeclaration = YES;
|
||||
else if (*currentChar == ',')
|
||||
hasEmbeddedCSS = NO;
|
||||
else if (!hasEmbeddedCSS)
|
||||
{
|
||||
if (*currentChar == '@')
|
||||
hasEmbeddedCSS = YES;
|
||||
start = currentChar;
|
||||
}
|
||||
else
|
||||
if (*currentChar > 32)
|
||||
{
|
||||
length = (currentChar - start);
|
||||
[css appendFormat: @"%@\n.SOGoHTMLMail-CSS-Delimiter ",
|
||||
[NSString stringWithCharacters: start length: length]];
|
||||
hasEmbeddedCSS = YES;
|
||||
start = currentChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[css appendString: [NSString stringWithCharacters: start
|
||||
length: (currentChar - start)]];
|
||||
if (currentChar > start)
|
||||
[css appendString: [NSString stringWithCharacters: start
|
||||
length: (currentChar - start)]];
|
||||
}
|
||||
|
||||
- (void) startElement: (NSString *) _localName
|
||||
@@ -273,111 +290,146 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
attributes: (id <SaxAttributes>) _attributes
|
||||
{
|
||||
unsigned int count, max;
|
||||
NSString *name, *value, *cid;
|
||||
NSString *name, *value, *cid, *upperName;
|
||||
NSMutableString *resultPart;
|
||||
BOOL skipAttribute;
|
||||
|
||||
showWhoWeAre();
|
||||
if (inStyle || inScript)
|
||||
|
||||
upperName = [_localName uppercaseString];
|
||||
if (inStyle || ignoreContent)
|
||||
;
|
||||
else if ([_localName caseInsensitiveCompare: @"base"] == NSOrderedSame)
|
||||
else if ([upperName isEqualToString: @"BASE"])
|
||||
;
|
||||
else if ([_localName caseInsensitiveCompare: @"meta"] == NSOrderedSame)
|
||||
else if ([upperName isEqualToString: @"META"])
|
||||
;
|
||||
else if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame)
|
||||
else if ([upperName isEqualToString: @"BODY"])
|
||||
inBody = YES;
|
||||
else if ([_localName caseInsensitiveCompare: @"script"] == NSOrderedSame)
|
||||
inScript = YES;
|
||||
else if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame)
|
||||
else if ([upperName isEqualToString: @"STYLE"])
|
||||
inStyle = YES;
|
||||
else if (inBody)
|
||||
{
|
||||
resultPart = [NSMutableString new];
|
||||
[resultPart appendFormat: @"<%@", _rawName];
|
||||
|
||||
max = [_attributes count];
|
||||
for (count = 0; count < max; count++)
|
||||
if ([BannedTags containsObject: upperName])
|
||||
{
|
||||
skipAttribute = NO;
|
||||
name = [_attributes nameAtIndex: count];
|
||||
if ([[name lowercaseString] hasPrefix: @"on"])
|
||||
skipAttribute = YES;
|
||||
else if ([name caseInsensitiveCompare: @"src"] == NSOrderedSame)
|
||||
{
|
||||
value = [_attributes valueAtIndex: count];
|
||||
if ([value hasPrefix: @"cid:"])
|
||||
{
|
||||
cid = [NSString stringWithFormat: @"<%@>",
|
||||
[value substringFromIndex: 4]];
|
||||
value = [attachmentIds objectForKey: cid];
|
||||
skipAttribute = (value == nil);
|
||||
}
|
||||
else if ([_rawName caseInsensitiveCompare: @"img"] == NSOrderedSame)
|
||||
{
|
||||
hasExternalImages = YES;
|
||||
|
||||
if (!unsafe) skipAttribute = YES;
|
||||
}
|
||||
else
|
||||
skipAttribute = YES;
|
||||
}
|
||||
else if ([name caseInsensitiveCompare: @"href"] == NSOrderedSame
|
||||
|| [name caseInsensitiveCompare: @"action"] == NSOrderedSame)
|
||||
{
|
||||
value = [_attributes valueAtIndex: count];
|
||||
skipAttribute = ([value rangeOfString: @"://"].location
|
||||
== NSNotFound
|
||||
&& ![value hasPrefix: @"#"]);
|
||||
}
|
||||
else
|
||||
value = [_attributes valueAtIndex: count];
|
||||
if (!skipAttribute)
|
||||
[resultPart appendFormat: @" %@=\"%@\"",
|
||||
name, [value stringByReplacingString: @"\""
|
||||
withString: @"\\\""]];
|
||||
ignoreTag = [upperName copy];
|
||||
ignoreContent = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPart = [NSMutableString new];
|
||||
[resultPart appendFormat: @"<%@", _rawName];
|
||||
|
||||
[resultPart appendString: @">"];
|
||||
[result appendString: resultPart];
|
||||
[resultPart release];
|
||||
max = [_attributes count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
skipAttribute = NO;
|
||||
name = [[_attributes nameAtIndex: count] uppercaseString];
|
||||
if ([name hasPrefix: @"ON"])
|
||||
skipAttribute = YES;
|
||||
else if ([name isEqualToString: @"SRC"])
|
||||
{
|
||||
value = [_attributes valueAtIndex: count];
|
||||
if ([value hasPrefix: @"cid:"])
|
||||
{
|
||||
cid = [NSString stringWithFormat: @"<%@>",
|
||||
[value substringFromIndex: 4]];
|
||||
value = [attachmentIds objectForKey: cid];
|
||||
skipAttribute = (value == nil);
|
||||
}
|
||||
else if ([upperName isEqualToString: @"IMG"])
|
||||
{
|
||||
hasExternalImages = YES;
|
||||
|
||||
if (!unsafe) skipAttribute = YES;
|
||||
}
|
||||
else
|
||||
skipAttribute = YES;
|
||||
}
|
||||
else if ([name isEqualToString: @"HREF"]
|
||||
|| [name isEqualToString: @"ACTION"])
|
||||
{
|
||||
value = [_attributes valueAtIndex: count];
|
||||
skipAttribute = ([value rangeOfString: @"://"].location
|
||||
== NSNotFound
|
||||
&& ![value hasPrefix: @"#"]);
|
||||
}
|
||||
else
|
||||
value = [_attributes valueAtIndex: count];
|
||||
if (!skipAttribute)
|
||||
[resultPart appendFormat: @" %@=\"%@\"",
|
||||
name, [value stringByReplacingString: @"\""
|
||||
withString: @"\\\""]];
|
||||
}
|
||||
|
||||
[resultPart appendString: @">"];
|
||||
[result appendString: resultPart];
|
||||
[resultPart release];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _finishCSS
|
||||
{
|
||||
NSRange excessiveDelimiter;
|
||||
|
||||
[css replaceString: @"<!--" withString: @""];
|
||||
[css replaceString: @"-->" withString: @""];
|
||||
[css replaceString: @".SOGoHTMLMail-CSS-Delimiter body"
|
||||
withString: @".SOGoHTMLMail-CSS-Delimiter"];
|
||||
[css replaceString: @";" withString: @" !important;"];
|
||||
[css replaceString: @"<!--" withString: @""];
|
||||
[css replaceString: @"-->" withString: @""];
|
||||
|
||||
excessiveDelimiter = [css rangeOfString: @".SOGoHTMLMail-CSS-Delimiter "
|
||||
options: NSBackwardsSearch];
|
||||
if (excessiveDelimiter.location != NSNotFound)
|
||||
{
|
||||
if (NSMaxRange (excessiveDelimiter) == [css length])
|
||||
[css deleteCharactersInRange: excessiveDelimiter];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) endElement: (NSString *) _localName
|
||||
namespace: (NSString *) _ns
|
||||
rawName: (NSString *) _rawName
|
||||
{
|
||||
NSString *upperName;
|
||||
|
||||
showWhoWeAre();
|
||||
|
||||
if (inStyle)
|
||||
upperName = [_localName uppercaseString];
|
||||
|
||||
if (ignoreContent)
|
||||
{
|
||||
if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame)
|
||||
{
|
||||
inStyle = NO;
|
||||
inCSSDeclaration = NO;
|
||||
}
|
||||
if ([upperName isEqualToString: ignoreTag])
|
||||
{
|
||||
ignoreContent = NO;
|
||||
[ignoreTag release];
|
||||
ignoreTag = nil;
|
||||
}
|
||||
}
|
||||
else if (inScript)
|
||||
inScript = ([_localName caseInsensitiveCompare: @"script"] != NSOrderedSame);
|
||||
else if (inBody)
|
||||
else
|
||||
{
|
||||
if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame)
|
||||
{
|
||||
inBody = NO;
|
||||
if (css)
|
||||
[self _finishCSS];
|
||||
}
|
||||
else
|
||||
[result appendFormat: @"</%@>", _localName];
|
||||
if (inStyle)
|
||||
{
|
||||
if ([upperName isEqualToString: @"STYLE"])
|
||||
{
|
||||
inStyle = NO;
|
||||
inCSSDeclaration = NO;
|
||||
}
|
||||
}
|
||||
else if (inBody)
|
||||
{
|
||||
if ([upperName isEqualToString: @"BODY"])
|
||||
{
|
||||
inBody = NO;
|
||||
if (css)
|
||||
[self _finishCSS];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog (@"%@", _localName);
|
||||
[result appendFormat: @"</%@>", _localName];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +437,7 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
length: (int) _len
|
||||
{
|
||||
showWhoWeAre();
|
||||
if (!inScript)
|
||||
if (!ignoreContent)
|
||||
{
|
||||
if (inStyle)
|
||||
[self _appendStyle: _chars length: _len];
|
||||
@@ -394,7 +446,7 @@ _xmlCharsetForCharset (NSString *charset)
|
||||
NSString *tmpString;
|
||||
|
||||
tmpString = [NSString stringWithCharacters: _chars length: _len];
|
||||
|
||||
|
||||
// HACK: This is to avoid appending the useless junk in the <html> tag
|
||||
// that Outlook adds. It seems to confuse the XML parser for
|
||||
// forwarded messages as we get this in the _body_ of the email
|
||||
|
||||
@@ -289,16 +289,17 @@ static NSString *LDAPContactInfoAttribute = nil;
|
||||
return response;
|
||||
}
|
||||
|
||||
- (WOResponse *) _usersResponseForResults: (NSEnumerator *) users
|
||||
- (WOResponse *) _usersResponseForResults: (NSArray *) users
|
||||
{
|
||||
WOResponse *response;
|
||||
NSString *uid;
|
||||
NSMutableString *responseString;
|
||||
NSDictionary *contact;
|
||||
NSString *contactInfo;
|
||||
NSString *contactInfo, *login;
|
||||
NSArray *allUsers;
|
||||
int i;
|
||||
|
||||
login = [[context activeUser] login];
|
||||
response = [context response];
|
||||
[response setStatus: 200];
|
||||
[response setHeader: @"text/plain; charset=utf-8"
|
||||
@@ -308,25 +309,28 @@ static NSString *LDAPContactInfoAttribute = nil;
|
||||
|
||||
// We sort our array - this is pretty useful for the Web
|
||||
// interface of SOGo.
|
||||
allUsers = [[users allObjects]
|
||||
sortedArrayUsingSelector: @selector(caseInsensitiveDisplayNameCompare:)];
|
||||
allUsers = [users
|
||||
sortedArrayUsingSelector: @selector (caseInsensitiveDisplayNameCompare:)];
|
||||
|
||||
for (i = 0; i < [allUsers count]; i++)
|
||||
{
|
||||
contact = [allUsers objectAtIndex: i];
|
||||
uid = [contact objectForKey: @"c_uid"];
|
||||
if ([LDAPContactInfoAttribute length])
|
||||
{
|
||||
contactInfo = [contact objectForKey: LDAPContactInfoAttribute];
|
||||
if (!contactInfo)
|
||||
contactInfo = @"";
|
||||
}
|
||||
else
|
||||
contactInfo = @"";
|
||||
[responseString appendFormat: @"%@:%@:%@:%@\n", uid,
|
||||
[contact objectForKey: @"cn"],
|
||||
[contact objectForKey: @"c_email"],
|
||||
contactInfo];
|
||||
if (![uid isEqualToString: login])
|
||||
{
|
||||
if ([LDAPContactInfoAttribute length])
|
||||
{
|
||||
contactInfo = [contact objectForKey: LDAPContactInfoAttribute];
|
||||
if (!contactInfo)
|
||||
contactInfo = @"";
|
||||
}
|
||||
else
|
||||
contactInfo = @"";
|
||||
[responseString appendFormat: @"%@:%@:%@:%@\n", uid,
|
||||
[contact objectForKey: @"cn"],
|
||||
[contact objectForKey: @"c_email"],
|
||||
contactInfo];
|
||||
}
|
||||
}
|
||||
[response appendContentString: responseString];
|
||||
[responseString release];
|
||||
@@ -339,14 +343,13 @@ static NSString *LDAPContactInfoAttribute = nil;
|
||||
NSString *contact;
|
||||
id <WOActionResults> result;
|
||||
LDAPUserManager *um;
|
||||
NSEnumerator *users;
|
||||
|
||||
um = [LDAPUserManager sharedUserManager];
|
||||
contact = [self queryParameterForKey: @"search"];
|
||||
if ([contact length])
|
||||
{
|
||||
users = [[um fetchUsersMatching: contact] objectEnumerator];
|
||||
result = [self _usersResponseForResults: users];
|
||||
result
|
||||
= [self _usersResponseForResults: [um fetchUsersMatching: contact]];
|
||||
}
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 400
|
||||
@@ -375,27 +378,23 @@ static NSString *LDAPContactInfoAttribute = nil;
|
||||
|
||||
- (id <WOActionResults>) foldersSearchAction
|
||||
{
|
||||
NSString *contact, *folderType;
|
||||
NSString *folderType;
|
||||
NSArray *folders;
|
||||
id <WOActionResults> result;
|
||||
SOGoUserFolder *userFolder;
|
||||
|
||||
contact = [self queryParameterForKey: @"user"];
|
||||
if ([contact length])
|
||||
folderType = [self queryParameterForKey: @"type"];
|
||||
if ([folderType length])
|
||||
{
|
||||
folderType = [self queryParameterForKey: @"type"];
|
||||
if ([folderType length])
|
||||
{
|
||||
folders = [[self clientObject] foldersOfType: folderType
|
||||
forUID: contact];
|
||||
result = [self _foldersResponseForResults: folders];
|
||||
}
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 400
|
||||
reason: @"missing 'type' parameter"];
|
||||
userFolder = [self clientObject];
|
||||
folders
|
||||
= [userFolder foldersOfType: folderType
|
||||
forUID: [userFolder ownerInContext: context]];
|
||||
result = [self _foldersResponseForResults: folders];
|
||||
}
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 400
|
||||
reason: @"missing 'user' parameter"];
|
||||
reason: @"missing 'type' parameter"];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -94,9 +94,9 @@ function onUserNodeToggle(event) {
|
||||
this.stopObserving("click", onUserNodeToggle);
|
||||
|
||||
var person = this.parentNode.getAttribute("dataname");
|
||||
var url = (UserFolderURL + "foldersSearch"
|
||||
+ "?user=" + escape(person)
|
||||
+ "&type=" + window.opener.userFolderType);
|
||||
|
||||
var url = (UserFolderURLForUser(person) + "foldersSearch"
|
||||
+ "?type=" + window.opener.userFolderType);
|
||||
var nodeId = this.getAttribute("id").substr(3);
|
||||
triggerAjaxRequest(url, foldersSearchCallback,
|
||||
{ nodeId: nodeId, user: person });
|
||||
|
||||
@@ -34,333 +34,336 @@ function Node(id, pid, name, isParent, url, dataname, datatype, title, target,
|
||||
|
||||
// Tree object
|
||||
function dTree(objName) {
|
||||
this.config = {
|
||||
target : null,
|
||||
hideRoot : false,
|
||||
folderLinks : true,
|
||||
useSelection : true,
|
||||
useCookies : false,
|
||||
useLines : true,
|
||||
useIcons : true,
|
||||
useStatusText : false,
|
||||
closeSameLevel : false,
|
||||
inOrder : false
|
||||
}
|
||||
this.icon = {
|
||||
root : 'img/base.gif',
|
||||
folder : 'img/folder.gif',
|
||||
folderOpen : 'img/folderopen.gif',
|
||||
node : 'img/page.gif',
|
||||
empty : 'img/empty.gif',
|
||||
line : 'img/line.gif',
|
||||
join : 'img/join.gif',
|
||||
joinBottom : 'img/joinbottom.gif',
|
||||
plus : 'img/plus.gif',
|
||||
plusBottom : 'img/plusbottom.gif',
|
||||
minus : 'img/minus.gif',
|
||||
minusBottom : 'img/minusbottom.gif',
|
||||
nlPlus : 'img/nolines_plus.gif',
|
||||
nlMinus : 'img/nolines_minus.gif'
|
||||
};
|
||||
this.obj = objName;
|
||||
this.aNodes = [];
|
||||
this.aIndent = [];
|
||||
this.root = new Node(-1);
|
||||
this.selectedNode = null;
|
||||
this.selectedFound = false;
|
||||
this.completed = false;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Adds a new node to the node array
|
||||
dTree.prototype.add = function(id, pid, name, isParent, url, datatype,
|
||||
title, target, icon, iconOpen, open, hasUnseen) {
|
||||
this.aNodes[this.aNodes.length] = new Node(id, pid, name, isParent, url,
|
||||
datatype, title, target, icon,
|
||||
iconOpen, open, false, hasUnseen);
|
||||
};
|
||||
dTree.prototype = {
|
||||
obj: null,
|
||||
config: {
|
||||
target: null,
|
||||
hideRoot: false,
|
||||
folderLinks: true,
|
||||
useSelection: true,
|
||||
useCookies: false,
|
||||
useLines: true,
|
||||
useIcons: true,
|
||||
useStatusText: false,
|
||||
closeSameLevel: false,
|
||||
inOrder: false
|
||||
},
|
||||
icon: {
|
||||
root: 'img/base.gif',
|
||||
folder: 'img/folder.gif',
|
||||
folderOpen: 'img/folderopen.gif',
|
||||
node: 'img/page.gif',
|
||||
empty: 'img/empty.gif',
|
||||
line: 'img/line.gif',
|
||||
join: 'img/join.gif',
|
||||
joinBottom: 'img/joinbottom.gif',
|
||||
plus: 'img/plus.gif',
|
||||
plusBottom: 'img/plusbottom.gif',
|
||||
minus: 'img/minus.gif',
|
||||
minusBottom: 'img/minusbottom.gif',
|
||||
nlPlus: 'img/nolines_plus.gif',
|
||||
nlMinus: 'img/nolines_minus.gif'
|
||||
},
|
||||
aNodes: [],
|
||||
aIndent: [],
|
||||
root: new Node(-1),
|
||||
selectedNode: null,
|
||||
selectedFound: false,
|
||||
completed: false,
|
||||
|
||||
// Open/close all nodes
|
||||
dTree.prototype.openAll = function() {
|
||||
this.oAll(true);
|
||||
};
|
||||
dTree.prototype.closeAll = function() {
|
||||
this.oAll(false);
|
||||
};
|
||||
// Adds a new node to the node array
|
||||
add: function(id, pid, name, isParent, url, datatype,
|
||||
title, target, icon, iconOpen, open, hasUnseen) {
|
||||
this.aNodes[this.aNodes.length] = new Node(id, pid, name, isParent, url,
|
||||
datatype, title, target, icon,
|
||||
iconOpen, open, false, hasUnseen);
|
||||
},
|
||||
|
||||
// Outputs the tree to the page
|
||||
dTree.prototype.toString = function() {
|
||||
var str = '<div class="dtree" id="' + this.obj + '">\n';
|
||||
if (document.getElementById) {
|
||||
if (this.config.useCookies)
|
||||
this.selectedNode = this.getSelected();
|
||||
str += this.addNode(this.root);
|
||||
} else str += 'Browser not supported.';
|
||||
str += '</div>';
|
||||
if (!this.selectedFound) this.selectedNode = null;
|
||||
this.completed = true;
|
||||
return str;
|
||||
};
|
||||
// Open/close all nodes
|
||||
openAll: function() {
|
||||
this.oAll(true);
|
||||
},
|
||||
closeAll: function() {
|
||||
this.oAll(false);
|
||||
},
|
||||
|
||||
// Creates the tree structure
|
||||
dTree.prototype.addNode = function(pNode) {
|
||||
var str = '';
|
||||
var n=0;
|
||||
if (this.config.inOrder) n = pNode._ai;
|
||||
for (n; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == pNode.id) {
|
||||
var cn = this.aNodes[n];
|
||||
cn._p = pNode;
|
||||
cn._ai = n;
|
||||
this.setCS(cn);
|
||||
if (!cn.target && this.config.target) cn.target = this.config.target;
|
||||
if (cn._hc && !cn._io && this.config.useCookies) cn._io = this.isOpen(cn.id);
|
||||
if (!this.config.folderLinks && cn._hc) cn.url = null;
|
||||
if (this.config.useSelection && cn.id == this.selectedNode && !this.selectedFound) {
|
||||
cn._is = true;
|
||||
this.selectedNode = n;
|
||||
this.selectedFound = true;
|
||||
}
|
||||
str += this.node(cn, n);
|
||||
if (cn._ls) break;
|
||||
// Outputs the tree to the page
|
||||
toString: function() {
|
||||
var str = '<div class="dtree" id="' + this.obj + '">\n';
|
||||
if (document.getElementById) {
|
||||
if (this.config.useCookies)
|
||||
this.selectedNode = this.getSelected();
|
||||
str += this.addNode(this.root);
|
||||
} else str += 'Browser not supported.';
|
||||
str += '</div>';
|
||||
if (!this.selectedFound) this.selectedNode = null;
|
||||
this.completed = true;
|
||||
return str;
|
||||
},
|
||||
|
||||
// Creates the tree structure
|
||||
addNode: function(pNode) {
|
||||
var str = '';
|
||||
var n=0;
|
||||
if (this.config.inOrder) n = pNode._ai;
|
||||
for (n; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == pNode.id) {
|
||||
var cn = this.aNodes[n];
|
||||
cn._p = pNode;
|
||||
cn._ai = n;
|
||||
this.setCS(cn);
|
||||
if (!cn.target && this.config.target) cn.target = this.config.target;
|
||||
if (cn._hc && !cn._io && this.config.useCookies) cn._io = this.isOpen(cn.id);
|
||||
if (!this.config.folderLinks && cn._hc) cn.url = null;
|
||||
if (this.config.useSelection && cn.id == this.selectedNode && !this.selectedFound) {
|
||||
cn._is = true;
|
||||
this.selectedNode = n;
|
||||
this.selectedFound = true;
|
||||
}
|
||||
str += this.node(cn, n);
|
||||
if (cn._ls) break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
// Creates the node icon, url and text
|
||||
node: function(node, nodeId) {
|
||||
var str = '';
|
||||
|
||||
this.aNodes[nodeId] = node;
|
||||
if (this.root.id != node.pid || !this.config.hideRoot) {
|
||||
str += '<div class="dTreeNode"';
|
||||
if (node.datatype) str += ' datatype="' + node.datatype + '"';
|
||||
if (node.dataname) str += ' dataname="' + node.dataname + '"';
|
||||
str += '>' + this.indent(node, nodeId);
|
||||
if (node.url) {
|
||||
str += '<a id="s' + this.obj + nodeId + '" class="node" href="' + node.url + '"';
|
||||
if (node.title) str += ' title="' + node.title + '"';
|
||||
if (node.target) str += ' target="' + node.target + '"';
|
||||
if (this.config.useStatusText) str += ' onmouseover="window.status=\'' + node.name + '\';return true;" onmouseout="window.status=\'\';return true;" ';
|
||||
if (this.config.useSelection && ((node._hc && this.config.folderLinks) || !node._hc))
|
||||
str += ' onclick="' + this.obj + '.s(' + nodeId + ');"';
|
||||
str += '>';
|
||||
}
|
||||
else if ((!this.config.folderLinks || !node.url) && node._hc && node.pid != this.root.id)
|
||||
str += '<a href="#" onclick="' + this.obj + '.o(' + nodeId + ');" class="node">';
|
||||
if (this.config.useIcons) {
|
||||
if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node);
|
||||
if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node;
|
||||
if (this.root.id == node.pid) {
|
||||
node.icon = this.icon.root;
|
||||
node.iconOpen = this.icon.root;
|
||||
}
|
||||
str += '<img id="i' + this.obj + nodeId + '" src="' + ((node._io) ? node.iconOpen : node.icon) + '" alt="" />';
|
||||
}
|
||||
str += '<span class="nodeName';
|
||||
if (!node.isParent)
|
||||
str += ' leaf';
|
||||
if (node.hasUnseen)
|
||||
str += ' unseen';
|
||||
str += '">' + node.name + '</span>';
|
||||
if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += '</a>';
|
||||
str += '</div>';
|
||||
}
|
||||
if (node._hc) {
|
||||
str += '<div id="d' + this.obj + nodeId + '" class="clip" style="display:' + ((this.root.id == node.pid || node._io) ? 'block' : 'none') + ';">';
|
||||
str += this.addNode(node);
|
||||
str += '</div>';
|
||||
}
|
||||
this.aIndent.pop();
|
||||
return str;
|
||||
},
|
||||
|
||||
// Adds the empty and line icons
|
||||
indent: function(node, nodeId) {
|
||||
var str = '';
|
||||
if (this.root.id != node.pid)
|
||||
{
|
||||
for (var n=0; n<this.aIndent.length; n++)
|
||||
str += '<img src="' + ( (this.aIndent[n] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '" alt="" />';
|
||||
(node._ls) ? this.aIndent.push(0) : this.aIndent.push(1);
|
||||
if (node._hc)
|
||||
{
|
||||
str += '<a href="#" id="tg' + this.obj + nodeId + '" onclick="return ' + this.obj + '.o(' + nodeId + ');"><img id="j' + this.obj + nodeId + '" src="';
|
||||
if (!this.config.useLines) str += (node._io) ? this.icon.nlMinus : this.icon.nlPlus;
|
||||
else str += ( (node._io) ? ((node._ls && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node._ls && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) );
|
||||
str += '" alt="" /></a>';
|
||||
}
|
||||
else
|
||||
str += '<img src="' + ( (this.config.useLines) ? ((node._ls) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" />';
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
// Checks if a node has any children and if it is the last sibling
|
||||
setCS: function(node) {
|
||||
var lastId;
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == node.id) node._hc = true;
|
||||
if (this.aNodes[n].pid == node.pid) lastId = this.aNodes[n].id;
|
||||
}
|
||||
if (lastId==node.id) node._ls = true;
|
||||
},
|
||||
|
||||
// Returns the selected node
|
||||
getSelected: function() {
|
||||
var sn = this.getCookie('cs' + this.obj);
|
||||
return (sn) ? sn : null;
|
||||
},
|
||||
|
||||
// Highlights the selected node
|
||||
s: function(id) {
|
||||
if (!this.config.useSelection) return;
|
||||
var cn = this.aNodes[id];
|
||||
if (cn._hc && !this.config.folderLinks) return;
|
||||
if (this.selectedNode != id) {
|
||||
if (this.selectedNode || this.selectedNode==0) {
|
||||
eOld = document.getElementById("s" + this.obj + this.selectedNode);
|
||||
eOld.deselect();
|
||||
}
|
||||
eNew = document.getElementById("s" + this.obj + id);
|
||||
eNew.selectElement();
|
||||
this.selectedNode = id;
|
||||
if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.id);
|
||||
}
|
||||
},
|
||||
|
||||
// Toggle Open or close
|
||||
o: function(id) {
|
||||
var cn = this.aNodes[id];
|
||||
this.nodeStatus(!cn._io, id, cn._ls);
|
||||
cn._io = !cn._io;
|
||||
if (this.config.closeSameLevel) this.closeLevel(cn);
|
||||
if (this.config.useCookies) this.updateCookie();
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// Open or close all nodes
|
||||
oAll: function(status) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n]._hc && this.aNodes[n].pid != this.root.id) {
|
||||
this.nodeStatus(status, n, this.aNodes[n]._ls)
|
||||
this.aNodes[n]._io = status;
|
||||
}
|
||||
}
|
||||
if (this.config.useCookies) this.updateCookie();
|
||||
},
|
||||
|
||||
// Opens the tree to a specific node
|
||||
openTo: function(nId, bSelect, bFirst) {
|
||||
if (!bFirst) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].id == nId) {
|
||||
nId=n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var cn=this.aNodes[nId];
|
||||
if (cn.pid==this.root.id || !cn._p) return;
|
||||
cn._io = true;
|
||||
cn._is = bSelect;
|
||||
if (this.completed && cn._hc) this.nodeStatus(true, cn._ai, cn._ls);
|
||||
if (this.completed && bSelect) this.s(cn._ai);
|
||||
else if (bSelect) this._sn=cn._ai;
|
||||
this.openTo(cn._p._ai, false, true);
|
||||
},
|
||||
|
||||
// Closes all nodes on the same level as certain node
|
||||
closeLevel: function(node) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == node.pid && this.aNodes[n].id != node.id && this.aNodes[n]._hc) {
|
||||
this.nodeStatus(false, n, this.aNodes[n]._ls);
|
||||
this.aNodes[n]._io = false;
|
||||
this.closeAllChildren(this.aNodes[n]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Closes all children of a node
|
||||
closeAllChildren: function(node) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) {
|
||||
if (this.aNodes[n]._io) this.nodeStatus(false, n, this.aNodes[n]._ls);
|
||||
this.aNodes[n]._io = false;
|
||||
this.closeAllChildren(this.aNodes[n]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Change the status of a node(open or closed)
|
||||
nodeStatus: function(status, id, bottom) {
|
||||
eDiv = document.getElementById('d' + this.obj + id);
|
||||
if (eDiv) {
|
||||
eJoin = document.getElementById('j' + this.obj + id);
|
||||
if (this.config.useIcons) {
|
||||
eIcon = document.getElementById('i' + this.obj + id);
|
||||
eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;
|
||||
}
|
||||
eJoin.src = (this.config.useLines)?
|
||||
((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)):
|
||||
((status)?this.icon.nlMinus:this.icon.nlPlus);
|
||||
eDiv.style.display = (status) ? 'block': 'none';
|
||||
}
|
||||
},
|
||||
|
||||
// [Cookie] Clears a cookie
|
||||
clearCookie: function() {
|
||||
var now = new Date();
|
||||
var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
|
||||
this.setCookie('co'+this.obj, 'cookieValue', yesterday);
|
||||
this.setCookie('cs'+this.obj, 'cookieValue', yesterday);
|
||||
},
|
||||
|
||||
// [Cookie] Sets value in a cookie
|
||||
setCookie: function(cookieName, cookieValue, expires, path, domain, secure) {
|
||||
document.cookie =
|
||||
escape(cookieName) + '=' + escape(cookieValue)
|
||||
+ (expires ? '; expires=' + expires.toGMTString() : '')
|
||||
+ (path ? '; path=' + path : '')
|
||||
+ (domain ? '; domain=' + domain : '')
|
||||
+ (secure ? '; secure' : '');
|
||||
},
|
||||
|
||||
// [Cookie] Gets a value from a cookie
|
||||
getCookie: function(cookieName) {
|
||||
var cookieValue = '';
|
||||
var posName = document.cookie.indexOf(escape(cookieName) + '=');
|
||||
if (posName != -1) {
|
||||
var posValue = posName + (escape(cookieName) + '=').length;
|
||||
var endPos = document.cookie.indexOf(';', posValue);
|
||||
if (endPos != -1) cookieValue = unescape(document.cookie.substring(posValue, endPos));
|
||||
else cookieValue = unescape(document.cookie.substring(posValue));
|
||||
}
|
||||
return (cookieValue);
|
||||
},
|
||||
|
||||
// [Cookie] Returns ids of open nodes as a string
|
||||
updateCookie: function() {
|
||||
var str = '';
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n]._io && this.aNodes[n].pid != this.root.id) {
|
||||
if (str) str += '.';
|
||||
str += this.aNodes[n].id;
|
||||
}
|
||||
}
|
||||
this.setCookie('co' + this.obj, str);
|
||||
},
|
||||
|
||||
// [Cookie] Checks if a node id is in a cookie
|
||||
isOpen: function(id) {
|
||||
var aOpen = this.getCookie('co' + this.obj).split('.');
|
||||
for (var n=0; n<aOpen.length; n++)
|
||||
if (aOpen[n] == id) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
// Creates the node icon, url and text
|
||||
dTree.prototype.node = function(node, nodeId) {
|
||||
var str = '';
|
||||
|
||||
this.aNodes[nodeId] = node;
|
||||
if (this.root.id != node.pid || !this.config.hideRoot) {
|
||||
str += '<div class="dTreeNode"';
|
||||
if (node.datatype) str += ' datatype="' + node.datatype + '"';
|
||||
if (node.dataname) str += ' dataname="' + node.dataname + '"';
|
||||
str += '>' + this.indent(node, nodeId);
|
||||
if (node.url) {
|
||||
str += '<a id="s' + this.obj + nodeId + '" class="node" href="' + node.url + '"';
|
||||
if (node.title) str += ' title="' + node.title + '"';
|
||||
if (node.target) str += ' target="' + node.target + '"';
|
||||
if (this.config.useStatusText) str += ' onmouseover="window.status=\'' + node.name + '\';return true;" onmouseout="window.status=\'\';return true;" ';
|
||||
if (this.config.useSelection && ((node._hc && this.config.folderLinks) || !node._hc))
|
||||
str += ' onclick="' + this.obj + '.s(' + nodeId + ');"';
|
||||
str += '>';
|
||||
}
|
||||
else if ((!this.config.folderLinks || !node.url) && node._hc && node.pid != this.root.id)
|
||||
str += '<a href="#" onclick="' + this.obj + '.o(' + nodeId + ');" class="node">';
|
||||
if (this.config.useIcons) {
|
||||
if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node);
|
||||
if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node;
|
||||
if (this.root.id == node.pid) {
|
||||
node.icon = this.icon.root;
|
||||
node.iconOpen = this.icon.root;
|
||||
}
|
||||
str += '<img id="i' + this.obj + nodeId + '" src="' + ((node._io) ? node.iconOpen : node.icon) + '" alt="" />';
|
||||
}
|
||||
str += '<span class="nodeName';
|
||||
if (!node.isParent)
|
||||
str += ' leaf';
|
||||
if (node.hasUnseen)
|
||||
str += ' unseen';
|
||||
str += '">' + node.name + '</span>';
|
||||
if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += '</a>';
|
||||
str += '</div>';
|
||||
}
|
||||
if (node._hc) {
|
||||
str += '<div id="d' + this.obj + nodeId + '" class="clip" style="display:' + ((this.root.id == node.pid || node._io) ? 'block' : 'none') + ';">';
|
||||
str += this.addNode(node);
|
||||
str += '</div>';
|
||||
}
|
||||
this.aIndent.pop();
|
||||
return str;
|
||||
};
|
||||
|
||||
// Adds the empty and line icons
|
||||
dTree.prototype.indent = function(node, nodeId) {
|
||||
var str = '';
|
||||
if (this.root.id != node.pid)
|
||||
{
|
||||
for (var n=0; n<this.aIndent.length; n++)
|
||||
str += '<img src="' + ( (this.aIndent[n] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '" alt="" />';
|
||||
(node._ls) ? this.aIndent.push(0) : this.aIndent.push(1);
|
||||
if (node._hc)
|
||||
{
|
||||
str += '<a href="#" id="tg' + this.obj + nodeId + '" onclick="return ' + this.obj + '.o(' + nodeId + ');"><img id="j' + this.obj + nodeId + '" src="';
|
||||
if (!this.config.useLines) str += (node._io) ? this.icon.nlMinus : this.icon.nlPlus;
|
||||
else str += ( (node._io) ? ((node._ls && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node._ls && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) );
|
||||
str += '" alt="" /></a>';
|
||||
}
|
||||
else
|
||||
str += '<img src="' + ( (this.config.useLines) ? ((node._ls) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" />';
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
// Checks if a node has any children and if it is the last sibling
|
||||
dTree.prototype.setCS = function(node) {
|
||||
var lastId;
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == node.id) node._hc = true;
|
||||
if (this.aNodes[n].pid == node.pid) lastId = this.aNodes[n].id;
|
||||
}
|
||||
if (lastId==node.id) node._ls = true;
|
||||
};
|
||||
|
||||
// Returns the selected node
|
||||
dTree.prototype.getSelected = function() {
|
||||
var sn = this.getCookie('cs' + this.obj);
|
||||
return (sn) ? sn : null;
|
||||
};
|
||||
|
||||
// Highlights the selected node
|
||||
dTree.prototype.s = function(id) {
|
||||
if (!this.config.useSelection) return;
|
||||
var cn = this.aNodes[id];
|
||||
if (cn._hc && !this.config.folderLinks) return;
|
||||
if (this.selectedNode != id) {
|
||||
if (this.selectedNode || this.selectedNode==0) {
|
||||
eOld = document.getElementById("s" + this.obj + this.selectedNode);
|
||||
eOld.deselect();
|
||||
}
|
||||
eNew = document.getElementById("s" + this.obj + id);
|
||||
eNew.selectElement();
|
||||
this.selectedNode = id;
|
||||
if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.id);
|
||||
}
|
||||
};
|
||||
|
||||
// Toggle Open or close
|
||||
dTree.prototype.o = function(id) {
|
||||
var cn = this.aNodes[id];
|
||||
this.nodeStatus(!cn._io, id, cn._ls);
|
||||
cn._io = !cn._io;
|
||||
if (this.config.closeSameLevel) this.closeLevel(cn);
|
||||
if (this.config.useCookies) this.updateCookie();
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Open or close all nodes
|
||||
dTree.prototype.oAll = function(status) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n]._hc && this.aNodes[n].pid != this.root.id) {
|
||||
this.nodeStatus(status, n, this.aNodes[n]._ls)
|
||||
this.aNodes[n]._io = status;
|
||||
}
|
||||
}
|
||||
if (this.config.useCookies) this.updateCookie();
|
||||
};
|
||||
|
||||
// Opens the tree to a specific node
|
||||
dTree.prototype.openTo = function(nId, bSelect, bFirst) {
|
||||
if (!bFirst) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].id == nId) {
|
||||
nId=n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var cn=this.aNodes[nId];
|
||||
if (cn.pid==this.root.id || !cn._p) return;
|
||||
cn._io = true;
|
||||
cn._is = bSelect;
|
||||
if (this.completed && cn._hc) this.nodeStatus(true, cn._ai, cn._ls);
|
||||
if (this.completed && bSelect) this.s(cn._ai);
|
||||
else if (bSelect) this._sn=cn._ai;
|
||||
this.openTo(cn._p._ai, false, true);
|
||||
};
|
||||
|
||||
// Closes all nodes on the same level as certain node
|
||||
dTree.prototype.closeLevel = function(node) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == node.pid && this.aNodes[n].id != node.id && this.aNodes[n]._hc) {
|
||||
this.nodeStatus(false, n, this.aNodes[n]._ls);
|
||||
this.aNodes[n]._io = false;
|
||||
this.closeAllChildren(this.aNodes[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Closes all children of a node
|
||||
dTree.prototype.closeAllChildren = function(node) {
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) {
|
||||
if (this.aNodes[n]._io) this.nodeStatus(false, n, this.aNodes[n]._ls);
|
||||
this.aNodes[n]._io = false;
|
||||
this.closeAllChildren(this.aNodes[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change the status of a node(open or closed)
|
||||
dTree.prototype.nodeStatus = function(status, id, bottom) {
|
||||
eDiv = document.getElementById('d' + this.obj + id);
|
||||
if (eDiv) {
|
||||
eJoin = document.getElementById('j' + this.obj + id);
|
||||
if (this.config.useIcons) {
|
||||
eIcon = document.getElementById('i' + this.obj + id);
|
||||
eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;
|
||||
}
|
||||
eJoin.src = (this.config.useLines)?
|
||||
((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)):
|
||||
((status)?this.icon.nlMinus:this.icon.nlPlus);
|
||||
eDiv.style.display = (status) ? 'block': 'none';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// [Cookie] Clears a cookie
|
||||
dTree.prototype.clearCookie = function() {
|
||||
var now = new Date();
|
||||
var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
|
||||
this.setCookie('co'+this.obj, 'cookieValue', yesterday);
|
||||
this.setCookie('cs'+this.obj, 'cookieValue', yesterday);
|
||||
};
|
||||
|
||||
// [Cookie] Sets value in a cookie
|
||||
dTree.prototype.setCookie = function(cookieName, cookieValue, expires, path, domain, secure) {
|
||||
document.cookie =
|
||||
escape(cookieName) + '=' + escape(cookieValue)
|
||||
+ (expires ? '; expires=' + expires.toGMTString() : '')
|
||||
+ (path ? '; path=' + path : '')
|
||||
+ (domain ? '; domain=' + domain : '')
|
||||
+ (secure ? '; secure' : '');
|
||||
};
|
||||
|
||||
// [Cookie] Gets a value from a cookie
|
||||
dTree.prototype.getCookie = function(cookieName) {
|
||||
var cookieValue = '';
|
||||
var posName = document.cookie.indexOf(escape(cookieName) + '=');
|
||||
if (posName != -1) {
|
||||
var posValue = posName + (escape(cookieName) + '=').length;
|
||||
var endPos = document.cookie.indexOf(';', posValue);
|
||||
if (endPos != -1) cookieValue = unescape(document.cookie.substring(posValue, endPos));
|
||||
else cookieValue = unescape(document.cookie.substring(posValue));
|
||||
}
|
||||
return (cookieValue);
|
||||
};
|
||||
|
||||
// [Cookie] Returns ids of open nodes as a string
|
||||
dTree.prototype.updateCookie = function() {
|
||||
var str = '';
|
||||
for (var n=0; n<this.aNodes.length; n++) {
|
||||
if (this.aNodes[n]._io && this.aNodes[n].pid != this.root.id) {
|
||||
if (str) str += '.';
|
||||
str += this.aNodes[n].id;
|
||||
}
|
||||
}
|
||||
this.setCookie('co' + this.obj, str);
|
||||
};
|
||||
|
||||
// [Cookie] Checks if a node id is in a cookie
|
||||
dTree.prototype.isOpen = function(id) {
|
||||
var aOpen = this.getCookie('co' + this.obj).split('.');
|
||||
for (var n=0; n<aOpen.length; n++)
|
||||
if (aOpen[n] == id) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
// If Push and pop is not implemented by the browser
|
||||
|
||||
@@ -352,9 +352,7 @@ function getContrastingTextColor(bgColor) {
|
||||
|
||||
// Consider all colors with less than 56% brightness as dark colors and
|
||||
// use white as the foreground color, otherwise use black.
|
||||
return ((brightness < 144)
|
||||
? "white"
|
||||
: "black");
|
||||
return ((brightness < 144) ? "white" : "black");
|
||||
}
|
||||
|
||||
function triggerAjaxRequest(url, callback, userdata, content, headers) {
|
||||
@@ -1615,6 +1613,19 @@ function configureLinkBanner() {
|
||||
}
|
||||
}
|
||||
|
||||
/* accessing another user's data */
|
||||
function UserFolderURLForUser(user) {
|
||||
var folderArray = UserFolderURL.split("/");
|
||||
var count;
|
||||
if (UserFolderURL.endsWith('/'))
|
||||
count = folderArray.length - 2;
|
||||
else
|
||||
count = folderArray.length - 1;
|
||||
folderArray[count] = escape(user);
|
||||
|
||||
return folderArray.join("/");
|
||||
}
|
||||
|
||||
/* folder creation */
|
||||
function createFolder(name, okCB, notOkCB) {
|
||||
if (name) {
|
||||
|
||||
Reference in New Issue
Block a user