+2007-10-18 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoWebAuthenticator.m ([SOGoWebAuthenticator
+ -userInContext:]): override the super method by returning
+ anonymous if the super returns nil.
+
+ * UI/Common/UIxPageFrame.m ([UIxPageFrame
+ -productLocalizableStrings]): new method that returns the
+ product-specific translation dictionary as a JSON hash.
+ ([UIxPageFrame -commonLocalizableStrings]): same as above but for
+ the "Common" framework.
+ ([UIxPageFrame -setJsFiles:newJSFiles]): new setter that enables
+ the requestor components to require additional Javascript files.
+ This is useful now that all the scripts are loaded at the end of
+ the HTML code.
+ ([UIxPageFrame -additionalJSFiles]): new getter related to the
+ above.
+
+2007-10-17 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * UI/MailerUI/UIxMailActions.m ([UIxMailActions -copyAction]):
+ implemented new web method.
+
+ * SoObjects/Mailer/SOGoMailObject.m ([SOGoMailObject
+ -copyToFolderNamed:folderNameinContext:]): new method with the
+ code cut/pasted from -moveToFolderNamed:inContext:.
+ ([SOGoMailObject -moveToFolderNamed:folderNameinContext:]):
+ modified to use the code from -copyToFolderNamed:inContext:, which
+ is common between the two actions.
+
+ * SoObjects/Mailer/SOGoMailAccount.m ([SOGoMailAccount -draftsFolderNameInContext:_ctx])
+ ([SOGoMailAccount -sentFolderNameInContext:])
+ ([SOGoMailAccount -trashFolderNameInContext:]): modified to take
+ the user settings into account.
+
+ * UI/MailerUI/UIxMailFolderActions.m ([UIxMailFolderActions -setAsDraftsFolderAction])
+ ([UIxMailFolderActions -setAsSentFolderAction])
+ ([UIxMailFolderActions -setAsTrashFolderAction]): new web methods
+ that change the purpose of the active folder to "Sent", "Drafts"
+ or "Trash".
+
+ * UI/SOGoUI/SOGoACLAdvisory.m ([SOGoACLAdvisory -subject]):
+ returns the subject as quoted-printable.
+
+ * UI/SOGoUI/SOGoACLAdvisory.[hm]: added two intermediary classes:
+ SOGoACLAdditionAdvisory and SOGoACLRemovalAdvisory implementing
+ the "aclMethod" method for the subsequent language-dependent
+ subclasses.
+
+ * UI/SOGoUI/SOGoFolderAdvisory.m ([SOGoFolderAdvisory -subject]):
+ returns the subject as quoted-printable.
+
+ * UI/Scheduler/UIxAppointmentEditor.m ([UIxAppointmentEditor
+ -dealloc]): release item, aptStartDate and aptEndDate.
+
+2007-10-16 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/Mailer/SOGoMailFolder.m ([SOGoMailFolder
+ -initWithName:newNameinContainer:newContainer]): the owner of a
+ shared folder is set to "nobody" by default.
+
+ * UI/Common/UIxAclEditor.m ([UIxAclEditor -hasOwner]): new method
+ that returns whether the object has an owner or not.
+
+2007-10-15 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder -ocsFolder]): create
+ the folder even if the current user is not its owner.
+
+2007-10-10 Ludovic Marcotte <ludovic@inverse.ca>
+
+ * We now send advisory emails when folders
+ are created / deleted.
+
+ * Fixed the sending of advisory emails upon
+ ACL changes on folders.
+
2007-10-10 Ludovic Marcotte <ludovic@inverse.ca>
* UI/Scheduler/UIxComponentEditor.m
+0.9.0-200710XX
+--------------
+- the user can now configure his folders as drafts, trash or sent folder;
+- added the ability the move and copy message across mail folders;
+
0.9.0-200709XX
--------------
- implemented cookie-based identification in the web interface;
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject+SoDAV.h>
#import <NGObjWeb/WOContext.h>
+#import <NGObjWeb/WOResponse.h>
#import <NGObjWeb/WORequest.h>
#import <NGExtensions/NSObject+Logs.h>
+#import <NGExtensions/NSString+misc.h>
#import <EOControl/EOQualifier.h>
#import <EOControl/EOSortOrdering.h>
#import <GDLContentStore/GCSFolder.h>
if (filter && [filter length] > 0)
{
-#warning why we do not use %%%@%% everywhere?
qs = [NSString stringWithFormat:
@"(c_sn isCaseInsensitiveLike: '%@%%') OR "
@"(c_givenname isCaseInsensitiveLike: '%@%%') OR "
NSMutableDictionary *filterData;
id <DOMNode> parentNode;
id <DOMNodeList> ranges;
- NSString *componentName;
parentNode = [filterElement parentNode];
return filters;
}
-- (void) _appendComponentsMatchingFilters: (NSArray *) filters
- toResponse: (WOResponse *) response
-{
- unsigned int count, max;
- NSDictionary *currentFilter, *contact;
- NSEnumerator *contacts;
- NSString *baseURL;
-
- baseURL = [self baseURLInContext: context];
-
- max = [filters count];
- for (count = 0; count < max; count++)
- {
- currentFilter = [filters objectAtIndex: count];
- contacts = [[self lookupContactsWithFilter: [[currentFilter allValues] lastObject]
- sortBy: @"c_givenname"
- ordering: NSOrderedDescending]
- objectEnumerator];
-
- while ((contact = [contacts nextObject]))
- {
- [self appendObject: contact
- withBaseURL: baseURL
- toREPORTResponse: response];
- }
- }
-}
-
- (void) appendObject: (NSDictionary *) object
withBaseURL: (NSString *) baseURL
toREPORTResponse: (WOResponse *) r
[r appendContentString: @" </D:response>\r\n"];
}
+- (void) _appendComponentsMatchingFilters: (NSArray *) filters
+ toResponse: (WOResponse *) response
+{
+ unsigned int count, max;
+ NSDictionary *currentFilter, *contact;
+ NSEnumerator *contacts;
+ NSString *baseURL;
+
+ baseURL = [self baseURLInContext: context];
+
+ max = [filters count];
+ for (count = 0; count < max; count++)
+ {
+ currentFilter = [filters objectAtIndex: count];
+ contacts = [[self lookupContactsWithFilter: [[currentFilter allValues] lastObject]
+ sortBy: @"c_givenname"
+ ordering: NSOrderedDescending]
+ objectEnumerator];
+
+ while ((contact = [contacts nextObject]))
+ {
+ [self appendObject: contact
+ withBaseURL: baseURL
+ toREPORTResponse: response];
+ }
+ }
+}
+
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
sortBy: (NSString *) sortKey
ordering: (NSComparisonResult) sortOrdering
#import <NGExtensions/NSNull+misc.h>
#import <NGImap4/NGImap4Connection.h>
+#import <SoObjects/SOGo/SOGoUser.h>
+
#import "SOGoMailFolder.h"
#import "SOGoMailManager.h"
#import "SOGoDraftsFolder.h"
return [NSString stringWithFormat: @"folder%@", inboxFolderName];
}
+- (NSString *) _userFolderNameWithPurpose: (NSString *) purpose
+{
+ NSUserDefaults *ud;
+ NSMutableDictionary *mailSettings;
+ NSString *folderName;
+
+ folderName = nil;
+ ud = [[context activeUser] userSettings];
+ mailSettings = [ud objectForKey: @"Mail"];
+ if (mailSettings)
+ folderName
+ = [mailSettings objectForKey: [NSString stringWithFormat: @"%@Folder",
+ purpose]];
+
+ return folderName;
+}
+
- (NSString *) draftsFolderNameInContext: (id) _ctx
{
- /* SOGo managed folder */
- return [NSString stringWithFormat: @"folder%@", draftsFolderName];
+ NSString *folderName;
+
+ folderName = [self _userFolderNameWithPurpose: @"Drafts"];
+ if (!folderName)
+ folderName = draftsFolderName;
+
+ return [NSString stringWithFormat: @"folder%@", folderName];
}
- (NSString *) sieveFolderNameInContext: (id) _ctx
- (NSString *) sentFolderNameInContext: (id)_ctx
{
- return [NSString stringWithFormat: @"folder%@", sentFolderName];
+ NSString *folderName;
+
+ folderName = [self _userFolderNameWithPurpose: @"Sent"];
+ if (!folderName)
+ folderName = sentFolderName;
+
+ return [NSString stringWithFormat: @"folder%@", folderName];
}
- (NSString *) trashFolderNameInContext: (id)_ctx
{
- return [NSString stringWithFormat: @"folder%@", trashFolderName];
+ NSString *folderName;
+
+ folderName = [self _userFolderNameWithPurpose: @"Trash"];
+ if (!folderName)
+ folderName = trashFolderName;
+
+ return [NSString stringWithFormat: @"folder%@", folderName];
}
- (SOGoMailFolder *) inboxFolderInContext: (id) _ctx
folder = [mailAccount sharedFolderName];
if (folder && [path hasPrefix: folder])
- [self setOwner: @"anyone"];
+ [self setOwner: @"nobody"];
else
{
folder = [mailAccount otherUsersFolderName];
if ([names count] > 1)
[self setOwner: [names objectAtIndex: 1]];
else
- [self setOwner: @"anyone"];
+ [self setOwner: @"nobody"];
}
}
}
return userPath;
}
-- (NSString *) httpURLForAdvisoryToUser: (NSString *) uid;
+- (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
{
SOGoUser *user;
NSString *otherUsersPath, *url;
return url;
}
-- (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid;
+- (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
{
NSURL *selfURL, *userURL;
- (BOOL)isDeletionAllowed;
- (NSException *) trashInContext:(id)_ctx;
+- (NSException *) copyToFolderNamed: (NSString *) folderName
+ inContext: (id)_ctx;
- (NSException *) moveToFolderNamed: (NSString *) folderName
inContext: (id)_ctx;
return nil;
}
-- (NSException *) moveToFolderNamed: (NSString *) folderName
+- (NSException *) copyToFolderNamed: (NSString *) folderName
inContext: (id)_ctx
{
SOGoMailAccounts *destFolder;
NSEnumerator *folders;
NSString *currentFolderName, *reason;
- NSException *error;
// TODO: check for safe HTTP method
[destFolder flushMailCaches];
/* a) copy */
-
- error = [self davCopyToTargetObject: destFolder
- newName: @"fakeNewUnusedByIMAP4" /* autoassigned */
- inContext:_ctx];
- if (error != nil) return error;
- /* b) mark deleted */
+ return [self davCopyToTargetObject: destFolder
+ newName: @"fakeNewUnusedByIMAP4" /* autoassigned */
+ inContext:_ctx];
+}
+
+- (NSException *) moveToFolderNamed: (NSString *) folderName
+ inContext: (id)_ctx
+{
+ NSException *error;
+
+ if (![self copyToFolderNamed: folderName
+ inContext: _ctx])
+ {
+ /* b) mark deleted */
- error = [[self imap4Connection] markURLDeleted: [self imap4URL]];
- if (error != nil) return error;
+ error = [[self imap4Connection] markURLDeleted: [self imap4URL]];
+ if (error != nil) return error;
- [self flushMailCaches];
+ [self flushMailCaches];
+ }
return nil;
}
#import <NGObjWeb/SoObject+SoDAV.h>
#import <NGObjWeb/SoSelectorInvocation.h>
#import <NGObjWeb/WOContext+SoObjects.h>
+#import <NGObjWeb/WOApplication.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <EOControl/EOQualifier.h>
#import <GDLContentStore/GCSFolderType.h>
#import <GDLContentStore/NSURL+GCS.h>
#import <SaxObjC/XMLNamespaces.h>
+#import <UI/SOGoUI/SOGoFolderAdvisory.h>
#import "NSArray+Utilities.h"
#import "NSString+Utilities.h"
ocsFolder = [self ocsFolderForPath: [self ocsPath]];
userLogin = [[context activeUser] login];
if (!ocsFolder
- && [userLogin isEqualToString: [self ownerInContext: context]]
+/* && [userLogin isEqualToString: [self ownerInContext: context]] */
&& [self folderIsMandatory]
&& [self create])
ocsFolder = [self ocsFolderForPath: [self ocsPath]];
return @"";
}
+- (void) sendFolderAdvisoryTemplate: (NSString *) template
+{
+ NSString *language, *pageName;
+ SOGoUser *user;
+ SOGoFolderAdvisory *page;
+ WOApplication *app;
+
+ user = [SOGoUser userWithLogin: [[context activeUser] login] roles: nil];
+ language = [user language];
+ pageName = [NSString stringWithFormat: @"SOGoFolder%@%@Advisory",
+ language, template];
+
+ app = [WOApplication application];
+ page = [app pageWithName: pageName inContext: context];
+ [page setFolderObject: self];
+ [page setRecipientUID: [[context activeUser] login]];
+ [page send];
+}
+
- (BOOL) create
{
NSException *result;
-// [self dieHard];
result = [[self folderManager] createFolderOfType: [self folderType]
withName: displayName
atPath: ocsPath];
+ if (!result) [self sendFolderAdvisoryTemplate: @"Addition"];
+
return (result == nil);
}
{
NSException *error;
+ // We just fetch our displayName since our table will use it!
+ [self displayName];
+
if ([nameInContainer isEqualToString: @"personal"])
error = [NSException exceptionWithHTTPStatus: 403
reason: @"folder 'personal' cannot be deleted"];
else
error = [[self folderManager] deleteFolderAtPath: ocsPath];
+ if (!error) [self sendFolderAdvisoryTemplate: @"Removal"];
+
return error;
}
extern NSString *SOGoWeekStartFirst4DayWeek;
extern NSString *SOGoWeekStartFirstFullWeek;
+@interface SoUser (SOGoExtension)
+
+- (NSString *) language;
+
+@end
+
@interface SOGoUser : SoUser
{
NSString *currentPassword;
@end
+@implementation SoUser (SOGoExtension)
+
+- (NSString *) language
+{
+ NSArray *bLanguages;
+ WOContext *context;
+ NSString *language;
+
+ context = [[WOApplication application] context];
+ bLanguages = [[context request] browserLanguages];
+ if ([bLanguages count] > 0)
+ language = [bLanguages objectAtIndex: 0];
+
+ if (![language length])
+ language = defaultLanguage;
+
+ return language;
+}
+
+@end
+
@implementation SOGoUser
+ (void) initialize
// && [_pwd isEqualToString: @"freebusy"]));
}
+- (SOGoUser *) userInContext: (WOContext *)_ctx
+{
+ static SOGoUser *anonymous = nil;
+ SOGoUser *user;
+
+ if (!anonymous)
+ anonymous
+ = [[SOGoUser alloc] initWithLogin: @"anonymous"
+ roles: [NSArray arrayWithObject: SoRole_Anonymous]];
+
+ user = (SOGoUser *) [super userInContext: _ctx];
+ if (!user)
+ user = anonymous;
+
+ return user;
+}
+
- (NSString *) passwordInContext: (WOContext *) context
{
NSArray *creds;
"Unable to rename that folder!" = "Unable to rename that folder!";
"You have already subscribed to that folder!"
= "You have already subscribed to that folder!";
+"The user rights cannot be edited for this object!"
+ = "The user rights cannot be edited for this object!";
"Unable to rename that folder!" = "Impossible de renommer ce dossier.";
"You have already subscribed to that folder!"
= "Vous êtes déja abonné à ce dossier.";
+"The user rights cannot be edited for this object!"
+ = "Les droits sur cet objet ne peuvent pas être édités.";
"Unable to rename that folder!" = "Unable to rename that folder!";
"You have already subscribed to that folder!"
= "You have already subscribed to that folder!";
+"The user rights cannot be edited for this object!"
+ = "The user rights cannot be edited for this object!";
- (NSString *) currentUser;
- (NSString *) ownerName;
+- (BOOL) hasOwner;
@end
return [self _displayNameForUID: ownerLogin];
}
+- (BOOL) hasOwner
+{
+ NSString *ownerLogin;
+
+ ownerLogin = [[self clientObject] ownerInContext: context];
+
+ return (![ownerLogin isEqualToString: @"nobody"]);
+}
+
- (NSString *) defaultUserID
{
if (!defaultUserID)
#import <SOGoUI/UIxComponent.h>
#import <NGObjWeb/WEClientCapabilities.h>
+@class NSString;
+@class NSMutableArray;
+
@interface WOComponent (PopupExtension)
- (BOOL) isPopup;
NSString *toolbar;
id item;
BOOL isPopup;
+ NSMutableArray *additionalJSFiles;
}
+- (NSString *) commonLocalizableStrings;
+- (NSString *) productLocalizableStrings;
+
- (NSString *) pageJavaScriptURL;
- (NSString *) productJavaScriptURL;
- (BOOL) hasPageSpecificJavaScript;
- (BOOL) hasProductSpecificJavaScript;
+- (NSArray *) additionalJSFiles;
+
- (NSString *) pageCSSURL;
- (NSString *) productCSSURL;
- (BOOL) hasPageSpecificCSS;
- (BOOL) hasProductSpecificCSS;
-- (NSString *) productFrameworkName;
-
- (void) setPopup: (BOOL) popup;
- (BOOL) isPopup;
#import <NGObjWeb/SoComponent.h>
#import <NGObjWeb/WOComponent.h>
+#import <SoObjects/SOGo/SOGoUser.h>
+#import <SoObjects/SOGo/NSDictionary+Utilities.h>
+
#import <SOGoUI/UIxComponent.h>
-#import <SOGo/SOGoUser.h>
#import <Main/build.h>
{
if ((self = [super init]))
{
+ item = nil;
+ title = nil;
toolbar = nil;
+ additionalJSFiles = nil;
}
return self;
{
[item release];
[title release];
- if (toolbar)
- [toolbar release];
+ [toolbar release];
+ [additionalJSFiles release];
[super dealloc];
}
- (void) setTitle: (NSString *) _value
{
- ASSIGNCOPY(title, _value);
+ ASSIGN (title, _value);
}
- (NSString *) title
- (void) setItem: (id) _item
{
- ASSIGN(item, _item);
+ ASSIGN (item, _item);
}
- (id) item
/* page based JavaScript */
+- (NSString *) _stringsForFramework: (NSString *) framework
+{
+ NSString *language, *frameworkName;
+ id table;
+
+ frameworkName = [NSString stringWithFormat: @"%@.SOGo",
+ (framework ? framework : [self frameworkName])];
+ language = [[context activeUser] language];
+ table
+ = [[self resourceManager] stringTableWithName: @"Localizable"
+ inFramework: frameworkName
+ languages: [NSArray arrayWithObject: language]];
+
+ /* table is not really an NSDictionary but a hackish variation thereof */
+ return [[NSDictionary dictionaryWithDictionary: table] jsonRepresentation];
+}
+
+- (NSString *) commonLocalizableStrings
+{
+ return [NSString stringWithFormat: @"var clabels = %@;",
+ [self _stringsForFramework: nil]];
+}
+
+- (NSString *) productLocalizableStrings
+{
+ NSString *frameworkName;
+
+ frameworkName = [[context page] frameworkName];
+
+ return [NSString stringWithFormat: @"var labels = %@;",
+ [self _stringsForFramework: frameworkName]];
+}
+
- (NSString *) pageJavaScriptURL
{
WOComponent *page;
return [self urlForResourceFilename: fwJSFilename];
}
-- (NSString *) productFrameworkName
-{
- WOComponent *page;
-
- page = [context page];
-
- return [NSString stringWithFormat: @"%@.SOGo", [page frameworkName]];
-}
-
- (BOOL) hasPageSpecificJavaScript
{
return ([[self pageJavaScriptURL] length] > 0);
return ([[self productJavaScriptURL] length] > 0);
}
+- (void) setJsFiles: (NSString *) newJSFiles
+{
+ NSEnumerator *jsFiles;
+ NSString *currentFile, *filename;
+
+ [additionalJSFiles release];
+ additionalJSFiles = [NSMutableArray new];
+
+ jsFiles = [[newJSFiles componentsSeparatedByString: @","] objectEnumerator];
+ while ((currentFile = [jsFiles nextObject]))
+ {
+ filename = [self urlForResourceFilename:
+ [currentFile stringByTrimmingSpaces]];
+ [additionalJSFiles addObject: filename];
+ }
+}
+
+- (NSArray *) additionalJSFiles
+{
+ return additionalJSFiles;
+}
+
- (NSString *) pageCSSURL
{
WOComponent *page;
NSLog(@"User agent = %@", [cc userAgent]);
//NSLog(@"Browser major version = %i", [cc majorVersion]);
- return (
- ([[cc userAgentType] isEqualToString: @"IE"] && [cc majorVersion] >= 7) ||
- ([[cc userAgentType] isEqualToString: @"Mozilla"] && [cc majorVersion] >= 5) ||
- ([[cc userAgentType] isEqualToString: @"Safari"] && [cc majorVersion] >= 4)
+ return (([[cc userAgentType] isEqualToString: @"IE"]
+ && [cc majorVersion] >= 7)
+ || ([[cc userAgentType] isEqualToString: @"Mozilla"]
+ && [cc majorVersion] >= 5)
+ || ([[cc userAgentType] isEqualToString: @"Safari"]
+ && [cc majorVersion] >= 4)
// ([[cc userAgentType] isEqualToString: @"Konqueror"])
);
}
return [cc isMacBrowser];
}
-
@end /* UIxPageFrame */
"MoveTo" = "Move …";
-"error_missingsubject" = "Missing Subject";
-"error_missingrecipients" = "Missing Recipients";
-"error_validationfailed" = "Validation failed";
+/* Address Popup menu */
+"Add to Address Book..." = "Add to Address Book...";
+"Compose Mail To" = "Compose Mail To";
+"Create Filter From Message..." = "Create Filter From Message...";
+
+/* Mailbox popup menus */
+"Open in New Mail Window" = "Open in New Mail Window";
+"Copy Folder Location" = "Copy Folder Location";
+"Subscribe..." = "Subscribe...";
+"Mark Folder Read..." = "Mark Folder Read...";
+"New Folder..." = "New Folder...";
+"Compact This Folder" = "Compact This Folder";
+"Search Messages..." = "Search Messages...";
+"Sharing..." = "Sharing...";
+"New Subfolder..." = "New Subfolder...";
+"Rename Folder..." = "Rename Folder...";
+"Delete Folder" = "Delete Folder";
+"Use This Folder For" = "Use This Folder For";
+"Get Messages for Account" = "Get Messages for Account";
+
+/* Use This Folder menu */
+"Sent Messages" = "Sent Messages";
+"Drafts" = "Drafts";
+"Deleted Messages" = "Deleted Messages";
+
+/* Message list popup menu */
+"Open Message In New Window" = "Open Message In New Window";
+"Reply to Sender Only" = "Reply to Sender Only";
+"Reply to All" = "Reply to All";
+"Forward" = "Forward";
+"Edit As New..." = "Edit As New...";
+"Move To" = "Move To";
+"Copy To" = "Copy To";
+"Label" = "Label";
+"Mark" = "Mark";
+"Save As..." = "Save As...";
+"Print Preview" = "Print Preview";
+"View Message Source" = "View Message Source";
+"Print..." = "Print...";
+"Delete Message" = "Delete Message";
+
+"This Folder" = "This Folder";
+
+/* Label popup menu */
+"None" = "None";
+"Important" = "Important";
+"Work" = "Work";
+"Personal" = "Personal";
+"To Do" = "To Do";
+"Later" = "Later";
+
+/* Mark popup menu */
+"As Read" = "As Read";
+"Thread As Read" = "Thread As Read";
+"As Read By Date..." = "As Read By Date...";
+"All Read" = "All Read";
+"Flag" = "Flag";
+"As Junk" = "As Junk";
+"As Not Junk" = "As Not Junk";
+"Run Junk Mail Controls" = "Run Junk Mail Controls";
/* Folder operations */
"Name :" = "Name :";
"Please select a message." = "Please select a message.";
"Please select a message to print." = "Please select a message to print.";
"Please select only one message to print." = "Please select only one message to print.";
+
+"You need to choose a non-virtual folder!" = "You need to choose a non-virtual folder!";
+"You need to choose a root subfolder!" = "You need to choose a root subfolder!";
+
+"Moving a message into its own folder is impossible!"
+= "Moving a message into its own folder is impossible!";
+"Copying a message into its own folder is impossible!"
+= "Copying a message into its own folder is impossible!";
"New Subfolder..." = "Nouveau sous-dossier...";
"Rename Folder..." = "Renommer le dossier...";
"Delete Folder" = "Supprimer le dossier...";
+"Use This Folder For" = "Utiliser ce dossier pour";
"Get Messages for Account" = "Relever les messages de ce compte";
+/* Use This Folder menu */
+"Sent Messages" = "les message envoyés";
+"Drafts" = "les brouillons";
+"Deleted Messages" = "les message effacés";
+
/* Message list popup menu */
"Open Message In New Window" = "Ouvrir dans une nouvelle fenétre";
"Reply to Sender Only" = "Répondre à l'expéditeur";
"Print..." = "Imprimer...";
"Delete Message" = "Supprimer le message";
+"This Folder" = "Ce dossier-ci";
+
/* Label popup menu */
"None" = "Aucune";
"Important" = "Important";
"Please select a message." = "Veuillez sélectionner un message.";
"Please select a message to print." = "Veuillez sélectionner un message à imprimer.";
"Please select only one message to print." = "Veuillez ne sélectionner qu'un seul message à imprimer.";
+
+"You need to choose a non-virtual folder!" = "Vous devez choisir un dossier non-virtuel.";
+"You need to choose a root subfolder!" = "Vous devez choisir un sous-dossier de la racine.";
+
+"Moving a message into its own folder is impossible!"
+= "Le déplacement d'un message dans son propre dossier est impossible.";
+"Copying a message into its own folder is impossible!"
+= "La copie d'un message dans son propre dossier est impossible.";
"New Subfolder..." = "Neuer Unterordner...";
"Rename Folder..." = "Umbenennen...";
"Delete Folder" = "Löschen";
+"Use This Folder For" = "Use This Folder For";
"Get Messages for Account" = "Neue Nachrichten empfangen";
+/* Use This Folder menu */
+"Sent Messages" = "Sent Messages";
+"Drafts" = "Drafts";
+"Deleted Messages" = "Deleted Messages";
+
/* Message list popup menu */
"Open Message In New Window" = "In neuem Fenster õffnen";
"Reply to Sender Only" = "Antworten nur an Absender";
"Print..." = "Drucken...";
"Delete Message" = "Lõschen";
+"This Folder" = "This Folder";
+
/* Label popup menu */
"None" = "Aucune";
"Important" = "Important";
"Please select a message." = "Sie müssen eine Nachricht auswählen.";
"Please select a message to print." = "Sie müssen eine Nachricht zum Drucken auswählen.";
"Please select only one message to print." = "Bitte wählen Sie nur eine Nachricht zum Drucken aus.";
+
+"You need to choose a non-virtual folder!" = "You need to choose a non-virtual folder!";
+"You need to choose a root subfolder!" = "You need to choose a root subfolder!";
+
+"Moving a message into its own folder is impossible!"
+= "Moving a message into its own folder is impossible!";
+"Copying a message into its own folder is impossible!"
+= "Copying a message into its own folder is impossible!";
NSString *destinationFolder;
id response;
- destinationFolder = [[context request] formValueForKey: @"tofolder"];
+ destinationFolder = [[context request] formValueForKey: @"folder"];
if ([destinationFolder length] > 0)
{
response = [[self clientObject] moveToFolderNamed: destinationFolder
return response;
}
+- (id) copyAction
+{
+ NSString *destinationFolder;
+ id response;
+
+ destinationFolder = [[context request] formValueForKey: @"folder"];
+ if ([destinationFolder length] > 0)
+ {
+ response = [[self clientObject] copyToFolderNamed: destinationFolder
+ inContext: context];
+ if (!response)
+ response = [self responseWith204];
+ }
+ else
+ response = [NSException exceptionWithHTTPStatus: 500 /* Server Error */
+ reason: @"No destination folder given"];
+
+ return response;
+}
+
/* active message */
- (id) markMessageUnreadAction
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSURL.h>
+#import <Foundation/NSUserDefaults.h>
#import <NGObjWeb/WOContext.h>
+#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGObjWeb/WORequest.h>
#import <NGImap4/NGImap4Connection.h>
#import <SoObjects/Mailer/SOGoTrashFolder.h>
#import <SoObjects/Mailer/SOGoMailAccount.h>
#import <SoObjects/SOGo/NSObject+Utilities.h>
+#import <SoObjects/SOGo/SOGoUser.h>
#import <UI/Common/WODirectAction+SOGo.h>
return response;
}
+- (WOResponse *) _setFolderPurpose: (NSString *) purpose
+{
+ SOGoMailFolder *co;
+ WOResponse *response;
+ NSUserDefaults *ud;
+ NSMutableDictionary *mailSettings;
+
+ co = [self clientObject];
+ if ([NSStringFromClass ([co class]) isEqualToString: @"SOGoMailFolder"])
+ {
+ ud = [[context activeUser] userSettings];
+ mailSettings = [ud objectForKey: @"Mail"];
+ if (!mailSettings)
+ {
+ mailSettings = [NSMutableDictionary new];
+ [mailSettings autorelease];
+ }
+ [ud setObject: mailSettings forKey: @"Mail"];
+ [mailSettings setObject: [co relativeImap4Name]
+ forKey: [NSString stringWithFormat: @"%@Folder",
+ purpose]];
+ [ud synchronize];
+ response = [self responseWith204];
+ }
+ else
+ {
+ response = [self responseWithStatus: 500];
+ [response
+ appendContentString: @"Unable to change the purpose of this folder."];
+ }
+
+ return response;
+}
+
+- (WOResponse *) setAsDraftsFolderAction
+{
+ return [self _setFolderPurpose: @"Drafts"];
+}
+
+- (WOResponse *) setAsSentFolderAction
+{
+ return [self _setFolderPurpose: @"Sent"];
+}
+
+- (WOResponse *) setAsTrashFolderAction
+{
+ return [self _setFolderPurpose: @"Trash"];
+}
+
- (WOResponse *) expungeAction
{
NSException *error;
actionClass = "UIxMailFolderActions";
actionName = "deleteFolder";
};
+ setAsDraftsFolder = {
+ protectedBy = "View";
+ actionClass = "UIxMailFolderActions";
+ actionName = "setAsDraftsFolder";
+ };
+ setAsSentFolder = {
+ protectedBy = "View";
+ actionClass = "UIxMailFolderActions";
+ actionName = "setAsSentFolder";
+ };
+ setAsTrashFolder = {
+ protectedBy = "View";
+ actionClass = "UIxMailFolderActions";
+ actionName = "setAsTrashFolder";
+ };
userRights = {
protectedBy = "ReadAcls";
pageName = "UIxMailUserRightsEditor";
actionClass = "UIxMailActions";
actionName = "move";
};
+ copy = {
+ protectedBy = "View";
+ actionClass = "UIxMailActions";
+ actionName = "copy";
+ };
trash = {
protectedBy = "View";
actionClass = "UIxMailActions";
NSString *login, *oldLocation;
login = [[context activeUser] login];
- if ([login isEqualToString: @"anonymous"])
+ if (!login || [login isEqualToString: @"anonymous"])
response = self;
else
{
SOGoAptFormatter.m \
SOGoJSStringFormatter.m \
WOContext+UIx.m \
- \
- SOGoACLAdvisory.m
+ SOGoACLAdvisory.m \
+ SOGoFolderAdvisory.m
# make
@end
-@interface SOGoACLEnglishAdditionAdvisory : SOGoACLAdvisory
+@interface SOGoACLAdditionAdvisory : SOGoACLAdvisory
+
+- (NSString *) aclMethod;
+
+@end
+
+@interface SOGoACLRemovalAdvisory : SOGoACLAdvisory
+
+- (NSString *) aclMethod;
+
+@end
+
+@interface SOGoACLEnglishAdditionAdvisory : SOGoACLAdditionAdvisory
@end
-@interface SOGoACLEnglishRemovalAdvisory : SOGoACLAdvisory
+@interface SOGoACLFrenchAdditionAdvisory : SOGoACLAdditionAdvisory
@end
-@interface SOGoACLFrenchAdditionAdvisory : SOGoACLAdvisory
+@interface SOGoACLGermanAdditionAdvisory : SOGoACLAdditionAdvisory
@end
-@interface SOGoACLFrenchRemovalAdvisory : SOGoACLAdvisory
+@interface SOGoACLEnglishRemovalAdvisory : SOGoACLRemovalAdvisory
@end
-@interface SOGoACLGermanAdditionAdvisory : SOGoACLAdvisory
+@interface SOGoACLFrenchRemovalAdvisory : SOGoACLRemovalAdvisory
@end
-@interface SOGoACLGermanRemovalAdvisory : SOGoACLAdvisory
+@interface SOGoACLGermanRemovalAdvisory : SOGoACLRemovalAdvisory
@end
#endif /* SOGOACLADVISORY_H */
#import <SoObjects/SOGo/SOGoObject.h>
#import <SoObjects/SOGo/LDAPUserManager.h>
#import <SoObjects/SOGo/NSCalendarDate+SOGo.h>
+#import <SoObjects/SOGo/NSString+Utilities.h>
#import "SOGoACLAdvisory.h"
subject = [[self generateResponse] contentAsString];
isSubject = NO;
- return [subject stringByTrimmingSpaces];
+ return [[subject stringByTrimmingSpaces] asQPSubjectString: @"utf-8"];
}
- (NSString *) body
- (NSString *) aclMethod
{
[self subclassResponsibility: _cmd];
-
+
return nil;
}
@end
-@implementation SOGoACLEnglishAdditionAdvisory
+@implementation SOGoACLAdditionAdvisory
+
+- (NSString *) aclMethod { return @"add"; }
+
@end
-@implementation SOGoACLEnglishRemovalAdvisory
+@implementation SOGoACLRemovalAdvisory
+
+- (NSString *) aclMethod { return @"remove"; }
+
@end
-@implementation SOGoACLFrenchAdditionAdvisory
+@implementation SOGoACLEnglishAdditionAdvisory
@end
-@implementation SOGoACLFrenchRemovalAdvisory
+@implementation SOGoACLFrenchAdditionAdvisory
@end
@implementation SOGoACLGermanAdditionAdvisory
@end
+@implementation SOGoACLEnglishRemovalAdvisory
+@end
+
+@implementation SOGoACLFrenchRemovalAdvisory
+@end
+
@implementation SOGoACLGermanRemovalAdvisory
@end
--- /dev/null
+/* SOGoFolderAdvisory.h - this file is part of SOGo
+ *
+ * Copyright (C) 2007 Inverse groupe conseil
+ *
+ * Author: Ludovic Marcotte <ludovic@inverse.ca>
+ *
+ * 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 SOGOFOLDERADVISORY_H
+#define SOGOFOLDERADVISORY_H
+
+#import "UIxComponent.h"
+#import "../../SoObjects/SOGo/SOGoFolder.h"
+
+@interface SOGoFolderAdvisory : UIxComponent
+{
+ NSString *recipientUID;
+ SOGoFolder *folderObject;
+ BOOL isSubject;
+ BOOL isBody;
+}
+
+- (void) setFolderObject: (SOGoFolder *) theFolder;
+- (void) setRecipientUID: (NSString *) newRecipientUID;
+- (void) send;
+
+- (BOOL) isSubject;
+- (BOOL) isBody;
+
+- (NSString *) subject;
+- (NSString *) body;
+- (NSString *) folderMethod;
+
+@end
+
+@interface SOGoFolderEnglishAdditionAdvisory : SOGoFolderAdvisory
+@end
+
+@interface SOGoFolderEnglishRemovalAdvisory : SOGoFolderAdvisory
+@end
+
+@interface SOGoFolderFrenchAdditionAdvisory : SOGoFolderAdvisory
+@end
+
+@interface SOGoFolderFrenchRemovalAdvisory : SOGoFolderAdvisory
+@end
+
+@interface SOGoFolderGermanAdditionAdvisory : SOGoFolderAdvisory
+@end
+
+@interface SOGoFolderGermanRemovalAdvisory : SOGoFolderAdvisory
+@end
+
+#endif /* SOGOFOLDERADVISORY_H */
--- /dev/null
+/* SOGoFolderAdvisory.m - this file is part of SOGo
+ *
+ * Copyright (C) 2007 Inverse groupe conseil
+ *
+ * Author: Ludovic Marcotte <ludovic@inverse.ca>
+ *
+ * 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 <Foundation/NSURL.h>
+
+#import <NGObjWeb/WOResponse.h>
+#import <NGExtensions/NGHashMap.h>
+#import <NGMail/NGMimeMessage.h>
+#import <NGMime/NGMimeBodyPart.h>
+#import <NGMime/NGMimeMultipartBody.h>
+
+#import <SoObjects/SOGo/SOGoMailer.h>
+#import <SoObjects/SOGo/SOGoUser.h>
+#import <SoObjects/SOGo/SOGoObject.h>
+#import <SoObjects/SOGo/LDAPUserManager.h>
+#import <SoObjects/SOGo/NSCalendarDate+SOGo.h>
+#import <SoObjects/SOGo/NSString+Utilities.h>
+
+#import "SOGoFolderAdvisory.h"
+
+@implementation SOGoFolderAdvisory
+
+- (id) init
+{
+ if ((self = [super init]))
+ {
+ recipientUID = nil;
+ folderObject = nil;
+ isSubject = NO;
+ isBody = NO;
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [recipientUID release];
+ [folderObject release];
+ [super dealloc];
+}
+
+- (void) setFolderObject: (SOGoFolder *) theFolder
+{
+ ASSIGN(folderObject, theFolder);
+}
+
+- (void) setRecipientUID: (NSString *) newRecipientUID
+{
+ ASSIGN (recipientUID, newRecipientUID);
+}
+
+- (BOOL) isSubject
+{
+ return isSubject;
+}
+
+- (BOOL) isBody
+{
+ return isBody;
+}
+
+- (NSString *) displayName
+{
+ return [folderObject displayName];
+}
+
+- (NSString *) httpFolderURL
+{
+ NSString *absoluteString;
+ NSMutableString *url;
+
+#warning the url returned by SOGoMail may be empty, we need to handle that
+ absoluteString = [[folderObject soURL] absoluteString];
+ url = [NSMutableString stringWithString: absoluteString];
+
+ if (![url hasSuffix: @"/"])
+ [url appendString: @"/"];
+
+ return url;
+}
+
+- (NSString *) subject
+{
+ NSString *subject;
+
+ isSubject = YES;
+ subject = [[self generateResponse] contentAsString];
+ isSubject = NO;
+
+ return [[subject stringByTrimmingSpaces] asQPSubjectString: @"utf-8"];
+}
+
+- (NSString *) body
+{
+ NSString *body;
+
+ isBody = YES;
+ body = [[self generateResponse] contentAsString];
+ isBody = NO;
+
+ return [body stringByTrimmingSpaces];
+}
+
+- (NSString *) folderMethod
+{
+ [self subclassResponsibility: _cmd];
+
+ return nil;
+}
+
+- (NGMimeBodyPart *) _textPart
+{
+ NGMutableHashMap *headerMap;
+ NGMimeBodyPart *part;
+ NSData *body;
+
+ headerMap = [NGMutableHashMap hashMapWithCapacity: 1];
+ [headerMap setObject: @"text/plain; charset=utf-8" forKey: @"content-type"];
+
+ part = [NGMimeBodyPart bodyPartWithHeader: headerMap];
+ body = [[self body] dataUsingEncoding: NSUTF8StringEncoding];
+ [part setBody: [self body]];
+
+ return part;
+}
+
+- (NGMimeBodyPart *) _sogoNotificationPart
+{
+ NGMutableHashMap *headerMap;
+ NGMimeBodyPart *part;
+ NSData *body;
+
+ /* calendar part */
+ headerMap = [NGMutableHashMap hashMapWithCapacity: 1];
+ [headerMap setObject: [NSString stringWithFormat:
+ @"%@; method=%@; type=%@; charset=%@",
+ @"application/x-sogo-notification",
+ [self folderMethod], [folderObject folderType],
+ @"utf-8"]
+ forKey: @"content-type"];
+
+ part = [NGMimeBodyPart bodyPartWithHeader: headerMap];
+ body = [[self httpFolderURL] dataUsingEncoding: NSUTF8StringEncoding];
+ [part setBody: body];
+
+ return part;
+}
+
+- (void) send
+{
+ NSString *recipient, *date;
+ NGMutableHashMap *headerMap;
+ NGMimeMessage *message;
+ NGMimeMultipartBody *body;
+ SOGoUser *activeUser;
+ NSDictionary *identity;
+ NSString *from, *fullMail;
+
+ activeUser = [context activeUser];
+ identity = [activeUser primaryIdentity];
+ from = [identity objectForKey: @"email"];
+ fullMail = [NSString stringWithFormat: @"%@ <%@>",
+ [identity objectForKey: @"fullName"], from];
+
+ recipient = [[LDAPUserManager sharedUserManager]
+ getFullEmailForUID: recipientUID];
+
+ headerMap = [NGMutableHashMap hashMapWithCapacity: 5];
+ [headerMap setObject: @"multipart/alternative" forKey: @"content-type"];
+ [headerMap setObject: fullMail forKey: @"From"];
+ [headerMap setObject: recipient forKey: @"To"];
+ date = [[NSCalendarDate date] rfc822DateString];
+ [headerMap setObject: date forKey: @"Date"];
+ [headerMap setObject: [self subject] forKey: @"Subject"];
+ message = [NGMimeMessage messageWithHeader: headerMap];
+
+ body = [[NGMimeMultipartBody alloc] initWithPart: message];
+ [body addBodyPart: [self _textPart]];
+ [body addBodyPart: [self _sogoNotificationPart]];
+ [message setBody: body];
+ [body release];
+
+ [[SOGoMailer sharedMailer] sendMimePart: message
+ toRecipients: [NSArray arrayWithObject: recipient]
+ sender: from];
+}
+
+@end
+
+@implementation SOGoFolderEnglishAdditionAdvisory
+- (NSString *) folderMethod { return @"add"; }
+@end
+
+@implementation SOGoFolderEnglishRemovalAdvisory
+- (NSString *) folderMethod { return @"remove"; }
+@end
+
+@implementation SOGoFolderFrenchAdditionAdvisory
+- (NSString *) folderMethod { return @"add"; }
+@end
+
+@implementation SOGoFolderFrenchRemovalAdvisory
+- (NSString *) folderMethod { return @"remove"; }
+@end
+
+@implementation SOGoFolderGermanAdditionAdvisory
+- (NSString *) folderMethod { return @"add"; }
+@end
+
+@implementation SOGoFolderGermanRemovalAdvisory
+- (NSString *) folderMethod { return @"remove"; }
+@end
* Boston, MA 02111-1307, USA.
*/
-#warning WE LEAK IVARS LIKE CRAZY HERE
-
#include <math.h>
#import <NGObjWeb/SoObject.h>
- (void) dealloc
{
- RELEASE(repeat);
+ [item release];
+ [repeat release];
+ [aptStartDate release];
+ [aptEndDate release];
[super dealloc];
}
else
text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]];
- NSLog(@"itemRepeatText: %@", text);
-
return text;
}
- (void) setItem: (NSString *) newItem
{
- item = newItem;
+ ASSIGN (item, newItem);
}
- (NSString *) item
// return reminder;
// }
+- (NSString *) reminder
+{
+ return @"";
+}
+
+- (void) setReminder: (NSString *) newReminder
+{
+}
+
- (NSString *) itemReminderText
{
NSString *text;
- (void) setRepeat: (NSString *) newRepeat
{
- ASSIGN(repeat, newRepeat);
-}
-
-- (NSString *) reminder
-{
- return @"";
-}
-
-- (void) setReminder: (NSString *) newReminder
-{
+ ASSIGN (repeat, newRepeat);
}
/* actions */
NSCalendarDate *startDate, *endDate;
NSString *duration;
unsigned int minutes;
+ iCalRecurrenceRule *rule;
event = (iCalEvent *) [[self clientObject] component: NO];
if (event)
// We initialize our repeat ivars
if ([event hasRecurrenceRules])
{
- iCalRecurrenceRule *rule;
-
repeat = @"CUSTOM";
rule = [[event recurrenceRules] lastObject];
if ([rule frequency] == iCalRecurrenceFrequenceWeekly)
{
- if ([rule repeatInterval] == 1) repeat = @"WEEKLY";
- else if ([rule repeatInterval] == 2) repeat = @"BI-WEEKLY";
+ if ([rule repeatInterval] == 1)
+ repeat = @"WEEKLY";
+ else if ([rule repeatInterval] == 2)
+ repeat = @"BI-WEEKLY";
}
else if ([rule frequency] == iCalRecurrenceFrequenceDaily)
{
- if ([rule byDayMask] == (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)) repeat = @"EVERY WEEKDAY";
- else if (![rule byDayMask]) repeat = @"DAILY";
+ if ([rule byDayMask] == (iCalWeekDayMonday
+ | iCalWeekDayTuesday
+ | iCalWeekDayWednesday
+ | iCalWeekDayThursday
+ | iCalWeekDayFriday))
+ repeat = @"EVERY WEEKDAY";
+ else if (![rule byDayMask])
+ repeat = @"DAILY";
}
- else if ([rule frequency] == iCalRecurrenceFrequenceMonthly && [rule repeatInterval] == 1) repeat = @"MONTHLY";
- else if ([rule frequency] == iCalRecurrenceFrequenceYearly && [rule repeatInterval] == 1) repeat = @"YEARLY";
+ else if ([rule frequency] == iCalRecurrenceFrequenceMonthly
+ && [rule repeatInterval] == 1)
+ repeat = @"MONTHLY";
+ else if ([rule frequency] == iCalRecurrenceFrequenceYearly
+ && [rule repeatInterval] == 1)
+ repeat = @"YEARLY";
}
else
- {
- DESTROY(repeat);
- }
+ DESTROY(repeat);
return self;
}
{
SOGoAppointmentObject *clientObject;
int nbrDays;
+ iCalRecurrenceRule *rule;
clientObject = [self clientObject];
event = (iCalEvent *) [clientObject component: YES];
// We remove any repeat rules
if (!repeat && [event hasRecurrenceRules])
+ [event removeAllRecurrenceRules];
+ else if (!([repeat caseInsensitiveCompare: @"-"] == NSOrderedSame
+ || [repeat caseInsensitiveCompare: @"CUSTOM"] == NSOrderedSame))
{
- [event removeAllRecurrenceRules];
- }
- else if (!([repeat caseInsensitiveCompare: @"-"] == NSOrderedSame || [repeat caseInsensitiveCompare: @"CUSTOM"] == NSOrderedSame))
- {
- iCalRecurrenceRule *rule;
-
- rule = [[iCalRecurrenceRule alloc] init];
+ rule = [iCalRecurrenceRule new];
+ [rule setInterval: @"1"];
if ([repeat caseInsensitiveCompare: @"BI-WEEKLY"] == NSOrderedSame)
{
[rule setFrequency: iCalRecurrenceFrequenceWeekly];
}
else if ([repeat caseInsensitiveCompare: @"EVERY WEEKDAY"] == NSOrderedSame)
{
- [rule setByDayMask: (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)];
+ [rule setByDayMask: (iCalWeekDayMonday
+ |iCalWeekDayTuesday
+ |iCalWeekDayWednesday
+ |iCalWeekDayThursday
+ |iCalWeekDayFriday)];
[rule setFrequency: iCalRecurrenceFrequenceDaily];
- [rule setInterval: @"1"];
}
else
- {
- [rule setFrequency: (iCalRecurrenceFrequency)[rule valueForFrequency: repeat]];
- [rule setInterval: @"1"];
- }
+ [rule setFrequency:
+ (iCalRecurrenceFrequency) [rule valueForFrequency: repeat]];
[event setRecurrenceRules: [NSArray arrayWithObject: rule]];
- RELEASE(rule);
+ [rule release];
}
}
onclick="window.close(); return false;" />
</div>
</form>
-
- <script type="text/javascript">
- initEditorForm();
- </script>
</var:component>
className="UIxPageFrame"
title="name"
const:toolbar="none"
- const:popup="YES">
- <script type="text/javascript" rsrc:src="dtree.js"><!-- space --></script>
+ const:popup="YES"
+ const:jsFiles="dtree.js">
<var:component className="UIxContactsFilterPanel" qualifier="qualifier" />
- <div id="folders">
- </div>
+ <div id="folders"><!-- space --></div>
<div id="buttons">
<input type="submit" id="addButton" class="button" label:value="Add..."/>
</div>
xmlns:label="OGo:label"
className="UIxPageFrame"
title="panelTitle"
- const:popup="YES">
+ const:popup="YES"
+ const:jsFiles="UIxMailToSelection.js">
<div class="menu" id="attachmentsMenu">
<ul>
<li><var:string label:value="Open"/></li>
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
- >
- <script type="text/javascript" rsrc:src="dtree.js"><!-- space --></script>
- <script type="text/javascript" rsrc:src="MailerUI+dTree.js"><!-- space --></script>
+ const:jsFiles="dtree.js,MailerUI+dTree.js">
<script type="text/javascript">
- var mailAccounts = '<var:string value="mailAccounts" const:escapeHTML="NO"/>'.evalJSON(true);
+ var textMailAccounts = '<var:string value="mailAccounts" const:escapeHTML="NO"/>';
</script>
<div class="menu" id="accountIconMenu">
<ul>
<li><var:string label:value="Rename Folder..." /></li>
<li><var:string label:value="Compact This Folder" /></li>
<li><var:string label:value="Delete Folder" /></li>
+ <li><var:string label:value="Use This Folder For" /></li>
<li><!-- separator --></li>
<li><var:string label:value="Search Messages..." /></li>
<li><var:string label:value="Sharing..." /></li>
</ul>
</div>
+
+ <div class="menu" id="folderTypeMenu">
+ <ul>
+ <li><var:string label:value="Sent Messages" /></li>
+ <li><var:string label:value="Drafts" /></li>
+ <li><var:string label:value="Deleted Messages" /></li>
+ </ul>
+ </div>
<div class="menu" id="addressMenu">
<ul>
<script type="text/javascript">
var currentIndex = <var:string value="currentIndex" />;
</script>
- <script type="text/javascript" rsrc:src="UIxMailToSelection.js"><!-- space --></script>
<div id="addressList"
><var:foreach list="addressLists" item="addressList"
+++ /dev/null
-<?xml version="1.0" standalone="yes"?>
- <div id="folderTreeContent"
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:var="http://www.skyrix.com/od/binding"
- xmlns:const="http://www.skyrix.com/od/constant"
- xmlns:rsrc="OGo:url"
- xmlns:label="OGo:label">
- <!-- TODO: extend treeview to use CSS -->
-
- <script type="text/javascript" rsrc:src="dtree.js"><!-- space --></script>
- <script type="text/javascript">
- d = new dTree('d');
- d.config.folderLlinks = true;
- d.config.hideRoot = true;
-
- d.icon.root = '<var:string rsrc:value="tbtv_account_17x17.gif" />';
- d.icon.folder = '<var:string rsrc:value="tbtv_leaf_corner_17x17.gif" />';
- d.icon.folderOpen = '<var:string rsrc:value="tbtv_leaf_corner_17x17.gif" />';
- d.icon.node = '<var:string rsrc:value="tbtv_leaf_corner_17x17.gif" />';
- d.icon.line = '<var:string rsrc:value="tbtv_line_17x17.gif" />';
- d.icon.join = '<var:string rsrc:value="tbtv_junction_17x17.gif" />';
- d.icon.joinBottom = '<var:string rsrc:value="tbtv_corner_17x17.gif" />';
- d.icon.plus = '<var:string rsrc:value="tbtv_plus_17x17.gif" />';
- d.icon.plusBottom = '<var:string rsrc:value="tbtv_corner_plus_17x17.gif" />';
- d.icon.minus = '<var:string rsrc:value="tbtv_minus_17x17.gif" />';
- d.icon.minusBottom = '<var:string rsrc:value="tbtv_corner_minus_17x17.gif" />';
- d.icon.nlPlus = '<var:string rsrc:value="tbtv_corner_plus_17x17.gif" />';
- d.icon.nlMinus = '<var:string rsrc:value="tbtv_corner_minus_17x17.gif" />';
- d.icon.empty = '<var:string rsrc:value="empty.gif" />';
-
- d.add(0, -1, '');
- <var:foreach list="flattenedNodes" item="item"
- ><var:component className="UIxMailTreeBlockJS"
- const:treeObjectName="d"
- var:item="item"
- /></var:foreach>
- document.write(d);
- </script>
- </div>
+++ /dev/null
-<?xml version="1.0" standalone="yes"?>
- <container
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:var="http://www.skyrix.com/od/binding"
- xmlns:const="http://www.skyrix.com/od/constant"
- ><var:string value="treeObjectName" />.add(<var:string value="item.serial" />, <var:string value="item.parent" />, '<var:string value="item.title" />', <var:string value="item.hasChildren" />, '#', '<var:string value="item.name" />', '<var:string value="item.folderType" />', '', '', '<var:string value="iconName" />', '<var:string value="iconName" />');
- </container>
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE container>
+<container
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label">
+
+<var:if condition="isSubject">
+ <var:string value="displayName"/> has been created
+</var:if>
+
+<var:if condition="isBody">
+The <var:string value="displayName"/> folder has been created.
+
+You can access this resource remotely by using the following URL:
+
+<var:string value="httpFolderURL"/>
+</var:if>
+
+</container>
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE container>
+<container
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label">
+
+<var:if condition="isSubject">
+ <var:string value="displayName"/> has been deleted
+</var:if>
+
+<var:if condition="isBody">
+The <var:string value="displayName"/> folder has been deleted.
+
+The following URL is now no longer active:
+
+<var:string value="httpFolderURL"/>
+</var:if>
+
+</container>
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE container>
+<container
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label">
+
+ <var:if condition="isSubject">
+ <var:string value="displayName"/> a été créé
+ </var:if>
+
+ <var:if condition="isBody">
+Le dossier <var:string value="displayName"/> a été créé.
+
+Vous pouvez accéder à distance à ce dossier avec le lien suivant:
+
+ <var:string value="httpFolderURL"/>
+ </var:if>
+</container>
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE container>
+<container
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label">
+
+<var:if condition="isSubject">
+ <var:string value="displayName"/> a été supprimé
+</var:if>
+
+<var:if condition="isBody">
+Le dossier <var:string value="displayName"/> a été supprimé.
+
+Le lien suivant n'est plus actif:
+
+<var:string value="httpFolderURL"/>
+</var:if>
+
+</container>
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE container>
+<container
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label">
+
+<var:if condition="isSubject">
+ <var:string value="displayName"/> has been created
+</var:if>
+
+<var:if condition="isBody">
+The <var:string value="displayName"/> folder has been created.
+
+You can access this resource remotely by using the following URL:
+
+<var:string value="httpFolderURL"/>
+</var:if>
+
+</container>
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE container>
+<container
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label">
+
+<var:if condition="isSubject">
+ <var:string value="displayName"/> has been deleted
+</var:if>
+
+<var:if condition="isBody">
+The <var:string value="displayName"/> folder has been deleted.
+
+The following URL is now no longer active:
+
+<var:string value="httpFolderURL"/>
+</var:if>
+
+</container>
xmlns:label="OGo:label"
className="UIxPageFrame"
const:toolbar="none"
- const:popup="YES">
- <script type="text/javascript" rsrc:src="skycalendar.js"><!-- space --></script>
+ const:popup="YES"
+ const:jsFiles="skycalendar.js">
<div id="attendeesView">
<div id="freeBusyViewButtons">
<var:string label:value="Suggest time slot:"/>
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
className="UIxPageFrame"
- title="title"
- >
+ title="title">
<script type="text/javascript">
var UTCOffset = <var:string value="userUTCOffset"/>;
</script>
className="UIxPageFrame"
const:popup="YES"
title="name"
- var:toolbar="toolbar">
- <script type="text/javascript" rsrc:src="skycalendar.js"><!-- space --></script>
- <script type="text/javascript" rsrc:src="UIxComponentEditor.js"><!-- space --></script>
+ var:toolbar="toolbar"
+ const:jsFiles="skycalendar.js,UIxComponentEditor.js">
<script type="text/javascript">
var activeCalendar = '<var:string value="clientObject.container.nameInContainer"/>';
<input type="hidden" name="action" value="saveAcls"/>
<input type="hidden" id="userUIDS" name="userUIDS"
var:value="userUIDS"/>
- <label><var:string label:value="Owner:"/><br/>
- <span class="value"><strong><var:string value="ownerName"/></strong></span></label><br/>
+ <var:if condition="hasOwner">
+ <label><var:string label:value="Owner:"/><br/>
+ <span class="value"><strong><var:string value="ownerName"/></strong></span></label><br/>
+ </var:if>
</div>
<input id="defaultRolesBtn" type="button"
class="button" label:value="Default Roles"/>
</head>
<body var:class="bodyClasses"
- ><var:if condition="isCompatibleBrowser"
- ><script type="text/javascript">
- var ApplicationBaseURL = '<var:string value="applicationPath" />';
- var ResourcesURL = '/SOGo.woa/WebServerResources';
+ ><var:if condition="isCompatibleBrowser"
+ >
<var:if condition="shortUserNameForDisplay" const:value="anonymous"
const:negate="YES"
- >var UserFolderURL = '<var:string value="userFolderPath" />';
- var UserLogin = '<var:string value="shortUserNameForDisplay" />';</var:if>
- </script>
- <script type="text/javascript" rsrc:src="events.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="prototype.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="tablekit.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="tablekit-trueresize.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="JavascriptAPIExtensions.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="HTMLElement.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="HTMLInputElement.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="HTMLTableElement.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="HTMLUListElement.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="generic.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="SOGoDragAndDrop.js"><!-- space required --></script>
- <script type="text/javascript" rsrc:src="SOGoDragHandles.js"><!-- space required --></script>
- <var:if condition="hasProductSpecificJavaScript"><script type="text/javascript"
- var:src="productJavaScriptURL"><!-- space required --></script></var:if>
- <var:if condition="hasPageSpecificJavaScript"><script type="text/javascript"
- var:src="pageJavaScriptURL"><!-- space required --></script></var:if>
- <var:js-stringtable
- var:framework="productFrameworkName"
- const:identifier="labels" />
- <var:js-stringtable
- const:identifier="clabels" />
- <var:if condition="shortUserNameForDisplay" const:value="anonymous"
- const:negate="YES"
- ><var:if condition="shortUserNameForDisplay" const:value="wrongusernamepassword"
- const:negate="YES"
- ><var:if condition="isPopup" const:negate="YES"
- ><var:if condition="context.isUIxDebugEnabled"
- ><div id="logConsole"><!-- space --></div></var:if>
- <div id="linkBanner" class="linkbanner">
- <a id="logoff" var:href="logoffPath"
- ><var:string label:value="Sign Out" /></a>
- <a var:href="relativeCalendarPath"
- ><var:string label:value="Calendar" /></a> |
- <a var:href="relativeContactsPath"
- ><var:string label:value="Address Book" /></a> |
- <a var:href="relativeMailPath"
- ><var:string label:value="Mail" /></a> |
- <a var:href="relativePreferencesPath"
- ><var:string label:value="Preferences" /></a>
- <var:if condition="context.isUIxDebugEnabled"
- >| <a href="#"><var:string
- label:value="Log Console (dev.)" /></a
- ></var:if>
- </div>
- </var:if
- ><var:component className="UIxToolbar" var:toolbar="toolbar"
- />
- </var:if></var:if>
-
- <div class="pageContent"
- ><var:component-content
- /></div>
+ ><var:if condition="shortUserNameForDisplay" const:value="wrongusernamepassword"
+ const:negate="YES"
+ ><var:if condition="isPopup" const:negate="YES"
+ ><var:if condition="context.isUIxDebugEnabled"
+ ><div id="logConsole"><!-- space --></div></var:if>
+ <div id="linkBanner" class="linkbanner">
+ <a id="logoff" var:href="logoffPath"
+ ><var:string label:value="Sign Out" /></a>
+ <a var:href="relativeCalendarPath"
+ ><var:string label:value="Calendar" /></a> |
+ <a var:href="relativeContactsPath"
+ ><var:string label:value="Address Book" /></a> |
+ <a var:href="relativeMailPath"
+ ><var:string label:value="Mail" /></a> |
+ <a var:href="relativePreferencesPath"
+ ><var:string label:value="Preferences" /></a>
+ <var:if condition="context.isUIxDebugEnabled"
+ >| <a href="#"><var:string
+ label:value="Log Console (dev.)" /></a
+ ></var:if>
+ </div>
+ </var:if
+ ><var:component className="UIxToolbar" var:toolbar="toolbar"
+ />
+ </var:if></var:if>
+
+ <div id="pageContent"><var:component-content/></div>
+
+ <script type="text/javascript">
+ var ApplicationBaseURL = '<var:string value="applicationPath" />';
+ var ResourcesURL = '/SOGo.woa/WebServerResources';
+ <var:if condition="shortUserNameForDisplay" const:value="anonymous"
+ const:negate="YES"
+ >var UserFolderURL = '<var:string value="userFolderPath" />';
+ var UserLogin = '<var:string value="shortUserNameForDisplay" />';</var:if>
+ <var:string value="commonLocalizableStrings" const:escapeHTML="NO"/>
+ <var:string value="productLocalizableStrings" const:escapeHTML="NO"/>
+ </script>
+ <script type="text/javascript" rsrc:src="events.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="prototype.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="tablekit.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="tablekit-trueresize.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="JavascriptAPIExtensions.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="HTMLElement.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="HTMLInputElement.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="HTMLTableElement.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="HTMLUListElement.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="generic.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="SOGoDragAndDrop.js"><!-- space --></script>
+ <script type="text/javascript" rsrc:src="SOGoDragHandles.js"><!-- space --></script>
+ <var:if condition="hasProductSpecificJavaScript"><script type="text/javascript"
+ var:src="productJavaScriptURL"><!-- space --></script></var:if>
+ <var:if condition="hasPageSpecificJavaScript"><script type="text/javascript"
+ var:src="pageJavaScriptURL"><!-- space --></script></var:if>
+ <var:foreach list="additionalJSFiles" item="item"
+ ><script type="text/javascript" var:src="item"><!-- space --></script>
+ </var:foreach>
</var:if>
<var:if condition="isCompatibleBrowser" const:negate="YES">
- <div id="loginScreen">
- <img id="splash" rsrc:src="lori-login.jpg"/><br/><br/>
- <p><var:string label:value="browserNotCompatible"/></p>
- <p class="browser"><a href="http://www.getfirefox.com/"><img rsrc:src="browser_firefox.gif"/><var:string label:value="Download"/> Firefox</a></p>
- <var:if condition="isIE7Compatible">
- <p><var:string label:value="alternativeBrowsers"/></p>
- <p class="browser"><a href="http://www.microsoft.com/ie/download/"><img rsrc:src="browser_ie.gif"/><var:string label:value="Download"/> Internet Explorer 7</a></p>
- <p class="browser"><a href="http://www.apple.com/safari/download/"><img rsrc:src="browser_safari.gif"/><var:string label:value="Download"/> Safari 3</a></p>
- </var:if>
- <var:if condition="isMac">
- <p><var:string label:value="alternativeBrowserSafari"/></p>
- <p class="browser"><a href="http://www.apple.com/safari/download/"><img rsrc:src="browser_safari.gif"/><var:string label:value="Download"/> Safari 3</a></p>
- </var:if>
- </div>
- </var:if>
+ <div id="loginScreen">
+ <img id="splash" rsrc:src="lori-login.jpg"/><br/><br/>
+ <p><var:string label:value="browserNotCompatible"/></p>
+ <p class="browser"><a href="http://www.getfirefox.com/"><img rsrc:src="browser_firefox.gif"/><var:string label:value="Download"/> Firefox</a></p>
+ <var:if condition="isIE7Compatible">
+ <p><var:string label:value="alternativeBrowsers"/></p>
+ <p class="browser"><a href="http://www.microsoft.com/ie/download/"><img rsrc:src="browser_ie.gif"/><var:string label:value="Download"/> Internet Explorer 7</a></p>
+ <p class="browser"><a href="http://www.apple.com/safari/download/"><img rsrc:src="browser_safari.gif"/><var:string label:value="Download"/> Safari 3</a></p>
+ </var:if>
+ <var:if condition="isMac">
+ <p><var:string label:value="alternativeBrowserSafari"/></p>
+ <p class="browser"><a href="http://www.apple.com/safari/download/"><img rsrc:src="browser_safari.gif"/><var:string label:value="Download"/> Safari 3</a></p>
+ </var:if>
+ </div>
+ </var:if>
<noscript>
<div class="javascriptPopupBackground">
</div>
var emailCell = contactRow.down('td', 1);
if (!emailCell.firstChild) { // .nodeValue is the contact email address
- window.alert(labels["The selected contact has no email address."].decodeEntities());
+ window.alert(labels["The selected contact has no email address."]);
return false;
}
}
if (rowsWithEmail == 0) {
- window.alert(labels["The selected contact has no email address."].decodeEntities());
+ window.alert(labels["The selected contact has no email address."]);
}
else if (document.body.hasClassName("popup"))
window.close();
function onMenuSharing(event) {
var folders = $("contactFolders");
var selected = folders.getSelectedNodes()[0];
- var title = this.innerHTML;
- var url = URLForFolderID(selected.getAttribute("id"));
+ var owner = selected.getAttribute("owner");
+ if (owner == "nobody")
+ window.alert(clabels["The user rights cannot be"
+ + " edited for this object!"]);
+ else {
+ var title = this.innerHTML;
+ var url = URLForFolderID(selected.getAttribute("id"));
- openAclWindow(url + "/acls", title);
+ openAclWindow(url + "/acls", title);
+ }
}
function getMenus() {
var menuTop = Event.pointerY(event);
var menuLeft = Event.pointerX(event);
- var heightDiff = (window.innerHeight
+ var heightDiff = (window.height()
- (menuTop + popup.offsetHeight));
if (heightDiff < 0)
menuTop += heightDiff;
- var leftDiff = (window.innerWidth
+ var leftDiff = (window.width()
- (menuLeft + popup.offsetWidth));
if (leftDiff < 0)
menuLeft -= popup.offsetWidth;
attachMenu: function(element, menuName) {
element = $(element);
element.sogoContextMenu = $(menuName);
- Event.observe(element, "contextmenu", element.onContextMenu.bindAsEventListener(element));
+ Event.observe(element, "contextmenu",
+ element.onContextMenu.bindAsEventListener(element));
},
select: function(element) {
return newString;
}
+
+window.width = function() {
+ if (window.innerWidth)
+ return window.innerWidth;
+ else if (document.body && document.body.offsetWidth)
+ return document.body.offsetWidth;
+ else
+ return 0;
+}
+
+window.height = function() {
+ if (window.innerHeight)
+ return window.innerHeight;
+ else if (document.body && document.body.offsetHeight)
+ return document.body.offsetHeight;
+ else
+ return 0;
+}
},
_addFolder: function (parent, folder) {
var thisCounter = this.elementCounter;
- var fullName = "";
- var currentFolder = folder;
- while (currentFolder.parentFolder) {
- fullName = "/folder" + currentFolder.name + fullName;
- currentFolder = currentFolder.parentFolder;
- }
- fullName = "/" + currentFolder.name + fullName;
- this._addFolderNode(parent, folder.name, fullName, folder.type);
+ this._addFolderNode(parent, folder.name, folder.fullName(), folder.type);
for (var i = 0; i < folder.children.length; i++)
this._addFolder(thisCounter, folder.children[i]);
},
/* JavaScript for SOGoMail */
var accounts = {};
var mailboxTree;
+var mailAccounts;
+if (typeof textMailAccounts != 'undefined')
+ mailAccounts = textMailAccounts.evalJSON(true);
var currentMessages = new Array();
var maxCachedMessages = 20;
var usersRightsWindowHeight = 320;
var usersRightsWindowWidth = 400;
+var pageContent;
+
/* mail list */
function openMessageWindow(msguid, url) {
urlstr = ApplicationBaseURL + "/../Contacts/?popup=YES";
var w = window.open(urlstr, "Addressbook",
"width=640,height=400,resizable=1,scrollbars=1,toolbar=0,"
- + "location=0,directories=0,status=0,menubar=0,copyhistory=0");
+ + "location=no,directories=0,status=0,menubar=0,copyhistory=0");
w.focus();
return false;
function onMenuSharing(event) {
var folderID = document.menuTarget.getAttribute("dataname");
- var urlstr = URLForFolderID(folderID) + "/acls";
- preventDefault(event);
-
- openAclWindow(urlstr);
+ var type = document.menuTarget.getAttribute("datatype");
+ if (type == "additional")
+ window.alert(clabels["The user rights cannot be"
+ + " edited for this object!"]);
+ else {
+ var urlstr = URLForFolderID(folderID) + "/acls";
+ openAclWindow(urlstr);
+ }
}
/* mail list DOM changes */
}
-/* folder operations */
-
-function ctxFolderAdd(sender) {
- var folderName;
-
- folderName = prompt("Foldername: ");
- if (folderName == undefined)
- return false;
- if (folderName == "")
- return false;
-
- // TODO: should use a form-POST or AJAX
- window.location.href = "createFolder?name=" + escape(folderName);
- return false;
-}
-
-function ctxFolderDelete(sender) {
- if (!confirm("Delete current folder?"))
- return false;
-
- // TODO: should use a form-POST or AJAX
- window.location.href = "deleteFolder";
- return false;
-}
-
/* bulk delete of messages */
function uixDeleteSelectedMessages(sender) {
Event.stop(event);
}
-function onMailboxMenuMove() {
- window.alert("unimplemented");
+function _onMailboxMenuAction(menuEntry, error, actionName) {
+ var targetMailbox = menuEntry.mailbox.fullName();
+
+ if (targetMailbox == currentMailbox)
+ window.alert(labels[error]);
+ else {
+ var message;
+ if (document.menuTarget.tagName == "DIV")
+ message = currentMessages[currentMailbox];
+ else
+ message = document.menuTarget.getAttribute("id").substr(4);
+
+ var urlstr = (URLForFolderID(currentMailbox) + "/" + message
+ + "/" + actionName + "?folder=" + targetMailbox);
+ triggerAjaxRequest(urlstr, folderRefreshCallback, currentMailbox);
+ }
+}
+
+function onMailboxMenuMove(event) {
+ _onMailboxMenuAction(this,
+ "Moving a message into its own folder is impossible!",
+ "move");
}
-function onMailboxMenuCopy() {
- window.alert("unimplemented");
+function onMailboxMenuCopy(event) {
+ _onMailboxMenuAction(this,
+ "Copying a message into its own folder is impossible!",
+ "copy");
}
function refreshMailbox() {
}
function messageListCallback(http) {
+ var div = $('mailboxContent');
var table = $('messageList');
if (http.readyState == 4
}
else {
// Add table
- var div = $('mailboxContent');
div.update(http.responseText);
table = $('messageList');
configureMessageListEvents(table);
var selected = http.callbackData;
if (selected) {
var row = $("row_" + selected);
- if (row)
+ if (row) {
row.select();
+ div.scrollTop = row.rowIndex * row.getHeight(); // scroll to selected message
+ }
else
$("messageContent").update();
}
+ else
+ div.scrollTop = 0;
if (sorting["attribute"] && sorting["attribute"].length > 0) {
var sortHeader = $(sorting["attribute"] + "Header");
var tree = $("mailboxTree");
var nodes = document.getElementsByClassName("node", tree);
for (i = 0; i < nodes.length; i++) {
- Event.observe(nodes[i], "click", onMailboxTreeItemClick.bindAsEventListener(nodes[i]));
- Event.observe(nodes[i], "contextmenu", onFolderMenuClick.bindAsEventListener(nodes[i]));
+ Event.observe(nodes[i], "click",
+ onMailboxTreeItemClick.bindAsEventListener(nodes[i]));
+ Event.observe(nodes[i], "contextmenu",
+ onFolderMenuClick.bindAsEventListener(nodes[i]));
if (!inboxFound
&& nodes[i].parentNode.getAttribute("datatype") == "inbox") {
openInbox(nodes[i]);
var image = document.createElement("img");
image.src = ResourcesURL + "/" + icon;
newNode.appendChild(image);
- newNode.appendChild(document.createTextNode(" " + name));
+ var displayName = MailerUIdTreeExtension.folderNames[type];
+ if (!displayName)
+ displayName = name;
+ newNode.appendChild(document.createTextNode(" " + displayName));
return newNode;
}
menuDIV.setAttribute("id", prefix + "Submenu");
var menu = document.createElement("ul");
menuDIV.appendChild(menu);
+ pageContent.appendChild(menuDIV);
var callbacks = new Array();
if (mailbox.type != "account") {
var newNode = document.createElement("li");
newNode.mailbox = mailbox;
- newNode.appendChild(document.createTextNode("coucou"));
+ newNode.appendChild(document.createTextNode(labels["This Folder"]));
menu.appendChild(newNode);
menu.appendChild(document.createElement("li"));
callbacks.push(callback);
menu.appendChild(newNode);
if (child.children.length > 0) {
var newPrefix = prefix + submenuCount;
- var newSubmenu = generateMenuForMailbox(child,
- newPrefix,
- callback);
- document.body.appendChild(newSubmenu);
- callbacks.push(newPrefix + "Submenu");
+ var newSubmenuId = generateMenuForMailbox(child, newPrefix, callback);
+ callbacks.push(newSubmenuId);
submenuCount++;
}
else {
}
initMenu(menuDIV, callbacks);
- return menuDIV;
+ return menuDIV.getAttribute("id");
}
function updateMailboxMenus() {
menuDIV.parentNode.removeChild(menuDIV);
menuDIV = document.createElement("div");
- document.body.appendChild(menuDIV);
+ pageContent = $("pageContent");
+ pageContent.appendChild(menuDIV);
var menu = document.createElement("ul");
menuDIV.appendChild(menu);
$(menuDIV).addClassName("menu");
menuDIV.setAttribute("id", menuId);
-
+
var submenuIds = new Array();
for (var i = 0; i < mailAccounts.length; i++) {
var menuEntry = mailboxMenuNode("account", mailAccounts[i]);
menu.appendChild(menuEntry);
var mailbox = accounts[mailAccounts[i]];
- var newSubmenu = generateMenuForMailbox(mailbox,
+ var newSubmenuId = generateMenuForMailbox(mailbox,
key, mailboxActions[key]);
- document.body.appendChild(newSubmenu);
- submenuIds.push(newSubmenu.getAttribute("id"));
+ submenuIds.push(newSubmenuId);
}
initMenu(menuDIV, submenuIds);
}
deleteCachedMessage(folderID + "/" + msgID);
}
+function _onMenuChangeToXXXFolder(event, folder) {
+ var type = document.menuTarget.getAttribute("datatype");
+ if (type == "additional")
+ window.alert(labels["You need to choose a non-virtual folder!"]);
+ else {
+ var folderID = document.menuTarget.getAttribute("dataname");
+ var number = folderID.split("/").length;
+ if (number > 3)
+ window.alert(labels["You need to choose a root subfolder!"]);
+ else {
+ var urlstr = URLForFolderID(folderID) + "/setAs" + folder + "Folder";
+ triggerAjaxRequest(urlstr, folderOperationCallback);
+ }
+ }
+}
+
+function onMenuChangeToDraftsFolder(event) {
+ return _onMenuChangeToXXXFolder(event, "Drafts");
+}
+
+function onMenuChangeToSentFolder(event) {
+ return _onMenuChangeToXXXFolder(event, "Sent");
+}
+
+function onMenuChangeToTrashFolder(event) {
+ return _onMenuChangeToXXXFolder(event, "Trash");
+}
+
function folderOperationCallback(http) {
if (http.readyState == 4
&& isHttpStatus204(http.status))
onMenuCreateFolder,
onMenuRenameFolder,
onMenuExpungeFolder,
- onMenuDeleteFolder, "-", null,
+ onMenuDeleteFolder,
+ "folderTypeMenu",
+ "-", null,
onMenuSharing);
menus["addressMenu"] = new Array(newContactFromEmail, newEmailTo, null);
menus["messageListMenu"] = new Array(onMenuOpenMessage, "-",
null, onMenuViewMessageSource,
null, onPrintCurrentMessage,
onMenuDeleteMessage);
+ menus["folderTypeMenu"] = new Array(onMenuChangeToSentFolder,
+ onMenuChangeToDraftsFolder,
+ onMenuChangeToTrashFolder);
+
menus["label-menu"] = new Array(null, "-", null , null, null, null , null,
null);
menus["mark-menu"] = new Array(null, null, null, null, "-", null, "-",
}
}
+Mailbox.prototype.fullName = function() {
+ var fullName = "";
+
+ var currentFolder = this;
+ while (currentFolder.parentFolder) {
+ fullName = "/folder" + currentFolder.name + fullName;
+ currentFolder = currentFolder.parentFolder;
+ }
+
+ return "/" + currentFolder.name + fullName;
+}
+
Mailbox.prototype.findMailboxByName = function(name) {
var mailbox = null;
var entries = menu.childNodes[1].childNodes;
for (i = 0; i < entries.length; i++) {
var entry = entries[i];
- if (entry instanceof HTMLLIElement) {
+ if (entry.tagName == "LI") {
var entryMonth = entry.innerHTML;
if (entryMonth == month)
entry.addClassName("currentMonth");
node = $("givenName");
window.alert("x: " + node.cascadeLeftOffset()
+ ";y: " + node.cascadeTopOffset()
- + ";width: " + window.innerWidth
- + ";height: " + window.innerHeight);
+ + ";width: " + window.width()
+ + ";height: " + window.height());
}
function onFnKeyDown() {
$("sn").onkeyup = onFnNewValue;
$("givenName").onkeyup = onFnNewValue;
}
+
+addEvent(window, 'load', initEditorForm);
UL#attachments LI IMG
{ vertical-align: bottom; }
-DIV.pageContent TEXTAREA
+#pageContent TEXTAREA
{ position: absolute;
left: 0em;
right: 0em;
function onWindowResize(event) {
var textarea = document.pageform.text;
- var windowheight = (typeof self.innerHeight == "number" ? self.innerHeight : document.body.clientHeight);
var rowheight = (Element.getHeight(textarea) / textarea.rows);
var headerarea = $("headerArea");
var textareaoffset = textarea.offsetTop;
// Resize the textarea (message content)
- textarea.rows = Math.round((windowheight - textareaoffset) / rowheight);
+ textarea.rows = Math.round((window.height() - textareaoffset) / rowheight);
var attachmentsarea = $("attachmentsArea");
var attachmentswidth = 0;
if (attachmentsarea.style.display)
attachmentswidth = attachmentsarea.getWidth();
- var windowwidth = (typeof self.innerWidth == "number" ? self.innerWidth : document.body.clientWidth);
- var subjectfield = $(document).getElementsByClassName('headerField', $('subjectRow'))[0];
- var subjectinput = $(document).getElementsByClassName('textField', $('subjectRow'))[0];
+ var subjectfield = $(document).getElementsByClassName('headerField',
+ $('subjectRow'))[0];
+ var subjectinput = $(document).getElementsByClassName('textField',
+ $('subjectRow'))[0];
// Resize subject field
- subjectinput.setStyle({ width: (windowwidth
+ subjectinput.setStyle({ width: (window.width()
- $(subjectfield).getWidth()
- attachmentswidth
- - 4 - 30
- ) + 'px' });
+ - 4 - 30) + 'px' });
// Resize address fields
var addresslist = $('addressList');
var firstselect = document.getElementsByClassName('headerField', addresslist)[0];
- var inputwidth = windowwidth - $(firstselect).getWidth() - attachmentswidth - 24 - 30;
+ var inputwidth = ($(this).width() - $(firstselect).getWidth()
+ - attachmentswidth - 24 - 30);
var addresses = document.getElementsByClassName('textField', addresslist);
- for (var i = 0; i < addresses.length; i++) {
+ for (var i = 0; i < addresses.length; i++)
addresses[i].setStyle({ width: inputwidth + 'px' });
- }
}
function onMailEditorClose(event) {
margin-top: 1.5em;
margin-right: 1em; }
-DIV.pageContent
+DIV#pageContent
{ /* position: absolute;
background-color: #ffa;
top: 3em;
function createElement(tagName, id, classes, attributes, htmlAttributes,
parentNode) {
- var newElement = $(document.createElement(tagName));
- if (id)
- newElement.setAttribute("id", id);
- if (classes) {
- if (typeof(classes) == "string")
- newElement.addClassName(classes);
- else
- for (var i = 0; i < classes.length; i++)
- newElement.addClassName(classes[i]);
- }
- if (attributes)
- for (var i in attributes)
- newElement[i] = attributes[i];
- if (htmlAttributes)
- for (var i in htmlAttributes)
- newElement.setAttribute(i, htmlAttributes[i]);
- if (parentNode)
- parentNode.appendChild(newElement);
+ var newElement = $(document.createElement(tagName));
+ if (id)
+ newElement.setAttribute("id", id);
+ if (classes) {
+ if (typeof(classes) == "string")
+ newElement.addClassName(classes);
+ else
+ for (var i = 0; i < classes.length; i++)
+ newElement.addClassName(classes[i]);
+ }
+ if (attributes)
+ for (var i in attributes)
+ newElement[i] = attributes[i];
+ if (htmlAttributes)
+ for (var i in htmlAttributes)
+ newElement.setAttribute(i, htmlAttributes[i]);
+ if (parentNode)
+ parentNode.appendChild(newElement);
- return $(newElement);
+ return $(newElement);
}
function ml_stripActionInURL(url) {
}
function URLForFolderID(folderID) {
- var folderInfos = folderID.split(":");
- var url;
- if (folderInfos.length > 1) {
- url = UserFolderURL + "../" + folderInfos[0];
- if (!folderInfos[1].startsWith('/'))
- url += '/';
- url += folderInfos[1];
- }
- else
- url = ApplicationBaseURL + folderInfos[0];
+ var folderInfos = folderID.split(":");
+ var url;
+ if (folderInfos.length > 1) {
+ url = UserFolderURL + "../" + folderInfos[0];
+ if (!folderInfos[1].startsWith('/'))
+ url += '/';
+ url += folderInfos[1];
+ }
+ else
+ url = ApplicationBaseURL + folderInfos[0];
- if (url[url.length-1] == '/')
- url = url.substr(0, url.length-1);
+ if (url[url.length-1] == '/')
+ url = url.substr(0, url.length-1);
- return url;
+ return url;
}
function extractEmailAddress(mailTo) {
function extractEmailName(mailTo) {
var emailName = "";
- var tmpMailTo = mailTo.replace("<", "<");
- tmpMailTo = tmpMailTo.replace(">", ">");
+ var tmpMailTo = mailTo.replace("<", "<");
+ tmpMailTo = tmpMailTo.replace(">", ">");
- var emailNamere = /([ ]+)?(.+)\ </;
- if (emailNamere.test(tmpMailTo)) {
- emailNamere.exec(tmpMailTo);
- emailName = RegExp.$2;
- }
+ var emailNamere = /([ ]+)?(.+)\ </;
+ if (emailNamere.test(tmpMailTo)) {
+ emailNamere.exec(tmpMailTo);
+ emailName = RegExp.$2;
+ }
- return emailName;
+ return emailName;
}
function sanitizeMailTo(dirtyMailTo) {
- var emailName = extractEmailName(dirtyMailTo);
- var email = "" + extractEmailAddress(dirtyMailTo);
+ var emailName = extractEmailName(dirtyMailTo);
+ var email = "" + extractEmailAddress(dirtyMailTo);
- var mailto = "";
- if (emailName && emailName.length > 0)
- mailto = emailName + ' <' + email + '>';
- else
- mailto = email;
+ var mailto = "";
+ if (emailName && emailName.length > 0)
+ mailto = emailName + ' <' + email + '>';
+ else
+ mailto = email;
- return mailto;
+ return mailto;
}
function openUserFolderSelector(callback, type) {
- var urlstr = ApplicationBaseURL;
- if (! urlstr.endsWith('/'))
- urlstr += '/';
- urlstr += ("../../" + UserLogin + "/Contacts/userFolders");
- var w = window.open(urlstr, "_blank",
- "width=322,height=250,resizable=1,scrollbars=0");
- w.opener = window;
- window.userFolderCallback = callback;
- window.userFolderType = type;
- w.focus();
+ var urlstr = ApplicationBaseURL;
+ if (! urlstr.endsWith('/'))
+ urlstr += '/';
+ urlstr += ("../../" + UserLogin + "/Contacts/userFolders");
+ var w = window.open(urlstr, "_blank",
+ "width=322,height=250,resizable=1,scrollbars=0,location=0");
+ w.opener = window;
+ window.userFolderCallback = callback;
+ window.userFolderType = type;
+ w.focus();
}
function openContactWindow(url, wId) {
if (!wId)
wId = "" + (new Date().getTime());
var w = window.open(url, wId,
- "width=450,height=600,resizable=0");
+ "width=450,height=600,resizable=0,location=0");
w.focus();
return w;
}
function openMailTo(senderMailTo) {
- var mailto = sanitizeMailTo(senderMailTo);
- if (mailto.length > 0)
- openMailComposeWindow(ApplicationBaseURL
- + "/../Mail/compose?mailto=" + mailto);
+ var mailto = sanitizeMailTo(senderMailTo);
+ if (mailto.length > 0)
+ openMailComposeWindow(ApplicationBaseURL
+ + "/../Mail/compose?mailto=" + mailto);
return false; /* stop following the link */
}
http.url = url;
http.onreadystatechange
= function() {
- //log ("state changed (" + http.readyState + "): " + url);
- try {
- if (http.readyState == 4
- && activeAjaxRequests > 0) {
- if (!http.aborted) {
- http.callbackData = userdata;
- callback(http);
- }
- activeAjaxRequests -= 1;
- checkAjaxRequestsState();
- }
- }
- catch( e ) {
- activeAjaxRequests -= 1;
- checkAjaxRequestsState();
- log("AJAX Request, Caught Exception: " + e.name);
- log(e.message);
- log(backtrace());
- }
- };
+ //log ("state changed (" + http.readyState + "): " + url);
+ try {
+ if (http.readyState == 4
+ && activeAjaxRequests > 0) {
+ if (!http.aborted) {
+ http.callbackData = userdata;
+ callback(http);
+ }
+ activeAjaxRequests -= 1;
+ checkAjaxRequestsState();
+ }
+ }
+ catch( e ) {
+ activeAjaxRequests -= 1;
+ checkAjaxRequestsState();
+ log("AJAX Request, Caught Exception: " + e.name);
+ log(e.message);
+ log(backtrace());
+ }
+ };
http.send(null);
}
else {
function parseQueryString() {
var queryArray, queryDict
- var key, value, s, idx;
+ var key, value, s, idx;
queryDict.length = 0;
queryDict = new Array();
}
function acceptMultiSelect(node) {
- var response = false;
- var attribute = node.getAttribute('multiselect');
- if (attribute && attribute.length > 0) {
- log("node '" + node.getAttribute("id")
- + "' is still using old-stylemultiselect!");
- response = (attribute.toLowerCase() == 'yes');
- }
- else
- response = node.multiselect;
+ var response = false;
+ var attribute = node.getAttribute('multiselect');
+ if (attribute && attribute.length > 0) {
+ log("node '" + node.getAttribute("id")
+ + "' is still using old-stylemultiselect!");
+ response = (attribute.toLowerCase() == 'yes');
+ }
+ else
+ response = node.multiselect;
- return response;
+ return response;
}
function onRowClick(event) {
// var acceptClick = false;
function popupMenu(event, menuId, target) {
- document.menuTarget = target;
-
- if (document.currentPopupMenu)
- hideMenu(document.currentPopupMenu);
-
- var popup = $(menuId);
- var menuTop = Event.pointerY(event);
- var menuLeft = Event.pointerX(event);
- var heightDiff = (window.innerHeight
- - (menuTop + popup.offsetHeight));
- if (heightDiff < 0)
- menuTop += heightDiff;
+ document.menuTarget = target;
+
+ if (document.currentPopupMenu)
+ hideMenu(document.currentPopupMenu);
+
+ var popup = $(menuId);
+ var menuTop = Event.pointerY(event);
+ var menuLeft = Event.pointerX(event);
+ var heightDiff = (window.height()
+ - (menuTop + popup.offsetHeight));
+ if (heightDiff < 0)
+ menuTop += heightDiff;
- var leftDiff = (window.innerWidth
- - (menuLeft + popup.offsetWidth));
- if (leftDiff < 0)
- menuLeft -= popup.offsetWidth;
+ var leftDiff = (window.width()
+ - (menuLeft + popup.offsetWidth));
+ if (leftDiff < 0)
+ menuLeft -= popup.offsetWidth;
- popup.setStyle({ top: menuTop + "px",
- left: menuLeft + "px",
- visibility: "visible" });
+ popup.setStyle({ top: menuTop + "px",
+ left: menuLeft + "px",
+ visibility: "visible" });
- document.currentPopupMenu = popup;
+ document.currentPopupMenu = popup;
- Event.observe(document.body, "click", onBodyClickMenuHandler);
+ Event.observe(document.body, "click", onBodyClickMenuHandler);
- preventDefault(event);
+ preventDefault(event);
}
function getParentMenu(node) {
}
function onBodyClickMenuHandler(event) {
- document.body.menuTarget = null;
- hideMenu(document.currentPopupMenu);
- Event.stopObserving(document.body, "click", onBodyClickMenuHandler);
+ document.body.menuTarget = null;
+ hideMenu(document.currentPopupMenu);
+ Event.stopObserving(document.body, "click", onBodyClickMenuHandler);
- preventDefault(event);
+ preventDefault(event);
}
function hideMenu(menuNode) {
menuNode.setStyle({ visibility: "hidden" });
// menuNode.hide();
if (menuNode.parentMenuItem) {
- menuNode.parentMenuItem.setAttribute('class', 'submenu');
+ Event.stopObserving(menuNode.parentMenuItem, "mouseover",
+ onMouseEnteredSubmenu);
+ Event.stopObserving(menuNode, "mouseover", onMouseEnteredSubmenu);
+ Event.stopObserving(menuNode.parentMenuItem, "mouseout", onMouseLeftSubmenu);
+ Event.stopObserving(menuNode, "mouseout", onMouseLeftSubmenu);
+ Event.stopObserving(menuNode.parentMenu, "mouseover",
+ onMouseEnteredParentMenu);
+ $(menuNode.parentMenuItem).removeClassName("submenu-selected");
+ menuNode.parentMenuItem.mouseInside = false;
menuNode.parentMenuItem = null;
- Event.stopObserving(menuNode, 'mousemove', checkDropDown);
menuNode.parentMenu.submenuItem = null;
menuNode.parentMenu.submenu = null;
menuNode.parentMenu = null;
}
function initLogConsole() {
- var logConsole = $("logConsole");
- if (logConsole) {
- logConsole.highlighted = false;
- Event.observe(logConsole, "dblclick", onLogDblClick, false);
- logConsole.innerHTML = "";
- Event.observe(window, "keydown", onBodyKeyDown);
- }
+ var logConsole = $("logConsole");
+ if (logConsole) {
+ logConsole.highlighted = false;
+ Event.observe(logConsole, "dblclick", onLogDblClick, false);
+ logConsole.innerHTML = "";
+ Event.observe(window, "keydown", onBodyKeyDown);
+ }
}
function onBodyKeyDown(event) {
- if (event.keyCode == 27) {
- toggleLogConsole();
- preventDefault(event);
- }
+ if (event.keyCode == 27) {
+ toggleLogConsole();
+ preventDefault(event);
+ }
}
function onLogDblClick(event) {
logConsole.setStyle({ display: '' });
}
if (event)
- preventDefault(event);
+ preventDefault(event);
}
function log(message) {
}
var logConsole = logWindow.document.getElementById("logConsole");
if (logConsole) {
- logConsole.highlighted = !logConsole.highlighted;
- if (message == '\c') {
- logConsole.innerHTML = "";
- return;
- }
- var logMessage = message.replace("<", "<", "g");
- logMessage = logMessage.replace(" ", " ", "g");
- logMessage = logMessage.replace("\r\n", "<br />\n", "g");
- logMessage = logMessage.replace("\n", "<br />\n", "g");
- logMessage += '<br />' + "\n";
- if (logConsole.highlighted)
- logMessage = '<div class="highlighted">' + logMessage + '</div>';
- logConsole.innerHTML += logMessage;
+ logConsole.highlighted = !logConsole.highlighted;
+ if (message == '\c') {
+ logConsole.innerHTML = "";
+ return;
+ }
+ var logMessage = message.replace("<", "<", "g");
+ logMessage = logMessage.replace(" ", " ", "g");
+ logMessage = logMessage.replace("\r\n", "<br />\n", "g");
+ logMessage = logMessage.replace("\n", "<br />\n", "g");
+ logMessage += '<br />' + "\n";
+ if (logConsole.highlighted)
+ logMessage = '<div class="highlighted">' + logMessage + '</div>';
+ logConsole.innerHTML += logMessage;
}
}
function backtrace() {
- var func = backtrace.caller;
- var str = "backtrace:\n";
+ var func = backtrace.caller;
+ var str = "backtrace:\n";
- while (func)
- {
+ while (func)
+ {
if (func.name)
- {
- str += " " + func.name;
- if (this)
+ {
+ str += " " + func.name;
+ if (this)
str += " (" + this + ")";
- }
+ }
else
- str += "[anonymous]\n";
+ str += "[anonymous]\n";
str += "\n";
func = func.caller;
- }
- str += "--\n";
-
- return str;
-}
-
-function dropDownSubmenu(event) {
- var node = this;
- if (this.submenu && this.submenu != "") {
- log ("submenu: " + this.submenu);
- var submenuNode = $(this.submenu);
- var parentNode = getParentMenu(node);
- if (parentNode.submenu)
- hideMenu(parentNode.submenu);
- submenuNode.parentMenuItem = node;
- submenuNode.parentMenu = parentNode;
- parentNode.submenuItem = node;
- parentNode.submenu = submenuNode;
-
- var menuTop = (node.offsetTop - 2);
-
- var heightDiff = (window.innerHeight
- - (menuTop + submenuNode.offsetHeight));
- if (heightDiff < 0)
- menuTop += heightDiff;
-
- var menuLeft = parentNode.offsetWidth - 3;
- if (window.innerWidth
- < (menuLeft + submenuNode.offsetWidth
- + parentNode.cascadeLeftOffset()))
- menuLeft = - submenuNode.offsetWidth + 3;
-
- Event.observe(parentNode, "mousemove", checkDropDown);
- node.setAttribute('class', 'submenu-selected');
- submenuNode.setStyle({ top: menuTop + "px",
- left: menuLeft + "px",
- visibility: "visible" });
- }
-}
-
-function checkDropDown(event) {
- var parentMenu = getParentMenu(event.target);
- var submenuItem = parentMenu.submenuItem;
- if (submenuItem) {
- var menuX = event.clientX - parentMenu.cascadeLeftOffset();
- var menuY = event.clientY - parentMenu.cascadeTopOffset();
- var itemX = submenuItem.offsetLeft;
- var itemY = submenuItem.offsetTop - 75;
-
- if (menuX >= itemX
- && menuX < itemX + submenuItem.offsetWidth
- && (menuY < itemY
- || menuY > (itemY + submenuItem.offsetHeight))) {
- hideMenu(parentMenu.submenu);
- parentMenu.submenu = null;
- parentMenu.submenuItem = null;
- Event.stopObserving(parentMenu, 'mousemove', checkDropDown);
}
+ str += "--\n";
+
+ return str;
+}
+
+function popupSubmenu(event) {
+ if (this.submenu && this.submenu != "") {
+ var submenuNode = $(this.submenu);
+ var parentNode = getParentMenu(this);
+ if (parentNode.submenu)
+ hideMenu(parentNode.submenu);
+ submenuNode.parentMenuItem = this;
+ submenuNode.parentMenu = parentNode;
+ parentNode.submenuItem = this;
+ parentNode.submenu = submenuNode;
+
+ var menuTop = (parentNode.offsetTop - 2 + this.offsetTop);
+ if (window.height() < (menuTop + submenuNode.offsetHeight))
+ menuTop = window.height() - submenuNode.offsetHeight - 3;
+ var menuLeft = (parentNode.offsetLeft + parentNode.offsetWidth - 3);
+ if (window.width()
+ < (menuLeft + submenuNode.offsetWidth))
+ menuLeft = parentNode.offsetLeft - submenuNode.offsetWidth + 3;
+
+ this.mouseInside = true;
+ Event.observe(this, "mouseover",
+ onMouseEnteredSubmenu.bindAsEventListener(this));
+ Event.observe(submenuNode, "mouseover",
+ onMouseEnteredSubmenu.bindAsEventListener(submenuNode));
+ Event.observe(this, "mouseout", onMouseLeftSubmenu.bindAsEventListener(this));
+ Event.observe(submenuNode, "mouseout",
+ onMouseLeftSubmenu.bindAsEventListener(submenuNode));
+ Event.observe(parentNode, "mouseover",
+ onMouseEnteredParentMenu.bindAsEventListener(parentNode));
+ $(this).addClassName("submenu-selected");
+ submenuNode.setStyle({ top: menuTop + "px",
+ left: menuLeft + "px",
+ visibility: "visible" });
+ preventDefault(event);
}
}
+function onMouseEnteredParentMenu(event) {
+ if (this.submenuItem && !this.submenuItem.mouseInside)
+ hideMenu(this.submenu);
+}
+
+function onMouseEnteredSubmenu(event) {
+ $(this).mouseInside = true;
+}
+
+function onMouseLeftSubmenu(event) {
+ $(this).mouseInside = false;
+}
+
/* search field */
function popupSearchMenu(event) {
var menuId = this.getAttribute("menuid");
var popup = $(menuId);
offset = Position.positionedOffset(this);
popup.setStyle({ top: this.offsetHeight + "px",
- left: (offset[0] + 3) + "px",
- visibility: "visible" });
+ left: (offset[0] + 3) + "px",
+ visibility: "visible" });
document.currentPopupMenu = popup;
Event.observe(document.body, "click", onBodyClickMenuHandler);
}
function configureSearchField() {
- var searchValue = $("searchValue");
- var searchOptions = $("searchOptions");
-
- if (!searchValue) return;
-
- Event.observe(searchValue, "mousedown",
- onSearchMouseDown.bindAsEventListener(searchValue));
- Event.observe(searchValue, "click",
- popupSearchMenu.bindAsEventListener(searchValue));
- Event.observe(searchValue, "blur",
- onSearchBlur.bindAsEventListener(searchValue));
- Event.observe(searchValue, "focus",
- onSearchFocus.bindAsEventListener(searchValue));
- Event.observe(searchValue, "keydown",
- onSearchKeyDown.bindAsEventListener(searchValue));
-
- if (!searchOptions) return;
+ var searchValue = $("searchValue");
+ var searchOptions = $("searchOptions");
+
+ if (!searchValue) return;
+
+ Event.observe(searchValue, "mousedown",
+ onSearchMouseDown.bindAsEventListener(searchValue));
+ Event.observe(searchValue, "click",
+ popupSearchMenu.bindAsEventListener(searchValue));
+ Event.observe(searchValue, "blur",
+ onSearchBlur.bindAsEventListener(searchValue));
+ Event.observe(searchValue, "focus",
+ onSearchFocus.bindAsEventListener(searchValue));
+ Event.observe(searchValue, "keydown",
+ onSearchKeyDown.bindAsEventListener(searchValue));
+
+ if (!searchOptions) return;
- // Set the checkmark to the first option
- var firstOption = searchOptions.down('li');
- firstOption.addClassName("_chosen");
- searchOptions.chosenNode = firstOption;
+ // Set the checkmark to the first option
+ var firstOption = searchOptions.down('li');
+ firstOption.addClassName("_chosen");
+ searchOptions.chosenNode = firstOption;
}
function onSearchMouseDown(event) {
- var superNode = this.parentNode.parentNode.parentNode;
- relX = (Event.pointerX(event) - superNode.offsetLeft - this.offsetLeft);
- relY = (Event.pointerY(event) - superNode.offsetTop - this.offsetTop);
+ var superNode = this.parentNode.parentNode.parentNode;
+ relX = (Event.pointerX(event) - superNode.offsetLeft - this.offsetLeft);
+ relY = (Event.pointerY(event) - superNode.offsetTop - this.offsetTop);
- if (relY < 24) {
- event.cancelBubble = true;
- event.returnValue = false;
- }
+ if (relY < 24) {
+ event.cancelBubble = true;
+ event.returnValue = false;
+ }
}
function onSearchFocus() {
}
function onSearchBlur(event) {
- var ghostPhrase = this.getAttribute("ghost-phrase");
+ var ghostPhrase = this.getAttribute("ghost-phrase");
- if (!this.value) {
+ if (!this.value) {
this.setAttribute("modified", "");
this.setStyle({ color: "#aaa" });
this.value = ghostPhrase;
}
function onSearchFormSubmit(event) {
- var searchValue = $("searchValue");
- var searchCriteria = $("searchCriteria");
- var ghostPhrase = searchValue.getAttribute('ghost-phrase');
+ var searchValue = $("searchValue");
+ var searchCriteria = $("searchCriteria");
+ var ghostPhrase = searchValue.getAttribute('ghost-phrase');
- if (searchValue.value == ghostPhrase) return;
+ if (searchValue.value == ghostPhrase) return;
- search["criteria"] = searchCriteria.value;
- search["value"] = searchValue.value;
+ search["criteria"] = searchCriteria.value;
+ search["value"] = searchValue.value;
- refreshCurrentFolder();
+ refreshCurrentFolder();
}
function initCriteria() {
/* toolbar buttons */
function popupToolbarMenu(node, menuId) {
- if (document.currentPopupMenu)
- hideMenu(document.currentPopupMenu);
+ if (document.currentPopupMenu)
+ hideMenu(document.currentPopupMenu);
- var popup = $(menuId);
- var top = ($(node).getStyle('top') || 0) + node.offsetHeight - 2;
- popup.setStyle({ top: top + "px",
- left: $(node).cascadeLeftOffset() + "px",
- visibility: "visible" });
+ var popup = $(menuId);
+ var top = ($(node).getStyle('top') || 0) + node.offsetHeight - 2;
+ popup.setStyle({ top: top + "px",
+ left: $(node).cascadeLeftOffset() + "px",
+ visibility: "visible" });
- document.currentPopupMenu = popup;
- Event.observe(document.body, "click", onBodyClickMenuHandler);
+ document.currentPopupMenu = popup;
+ Event.observe(document.body, "click", onBodyClickMenuHandler);
}
/* contact selector */
function folderSubscriptionCallback(http) {
- if (http.readyState == 4) {
- if (isHttpStatus204(http.status)) {
- if (http.callbackData)
- http.callbackData["method"](http.callbackData["data"]);
- }
- else
- window.alert(clabels["Unable to subscribe to that folder!"].decodeEntities());
- document.subscriptionAjaxRequest = null;
- }
- else
- log ("folderSubscriptionCallback Ajax error");
+ if (http.readyState == 4) {
+ if (isHttpStatus204(http.status)) {
+ if (http.callbackData)
+ http.callbackData["method"](http.callbackData["data"]);
+ }
+ else
+ window.alert(clabels["Unable to subscribe to that folder!"]);
+ document.subscriptionAjaxRequest = null;
+ }
+ else
+ log ("folderSubscriptionCallback Ajax error");
}
function subscribeToFolder(refreshCallback, refreshCallbackData) {
- var folderData = refreshCallbackData["folder"].split(":");
- var username = folderData[0];
- var folderPath = folderData[1];
- if (username != UserLogin) {
- var url = (UserFolderURL + "../" + username
- + folderPath + "/subscribe");
- if (document.subscriptionAjaxRequest) {
- document.subscriptionAjaxRequest.aborted = true;
- document.subscriptionAjaxRequest.abort();
- }
+ var folderData = refreshCallbackData["folder"].split(":");
+ var username = folderData[0];
+ var folderPath = folderData[1];
+ if (username != UserLogin) {
+ var url = (UserFolderURL + "../" + username
+ + folderPath + "/subscribe");
+ if (document.subscriptionAjaxRequest) {
+ document.subscriptionAjaxRequest.aborted = true;
+ document.subscriptionAjaxRequest.abort();
+ }
- var rfCbData = { method: refreshCallback, data: refreshCallbackData };
- document.subscriptionAjaxRequest = triggerAjaxRequest(url,
- folderSubscriptionCallback,
- rfCbData);
- }
- else
- refreshCallbackData["window"].alert(clabels["You cannot subscribe to a folder that you own!"]
- .decodeEntities());
+ var rfCbData = { method: refreshCallback, data: refreshCallbackData };
+ document.subscriptionAjaxRequest = triggerAjaxRequest(url,
+ folderSubscriptionCallback,
+ rfCbData);
+ }
+ else
+ refreshCallbackData["window"].alert(clabels["You cannot subscribe to a folder that you own!"]
+ );
}
function folderUnsubscriptionCallback(http) {
- if (http.readyState == 4) {
- if (isHttpStatus204(http.status)) {
- if (http.callbackData)
- http.callbackData["method"](http.callbackData["data"]);
- }
- else
- window.alert(clabels["Unable to unsubscribe from that folder!"].decodeEntities());
- document.unsubscriptionAjaxRequest = null;
- }
+ if (http.readyState == 4) {
+ if (isHttpStatus204(http.status)) {
+ if (http.callbackData)
+ http.callbackData["method"](http.callbackData["data"]);
+ }
+ else
+ window.alert(clabels["Unable to unsubscribe from that folder!"]);
+ document.unsubscriptionAjaxRequest = null;
+ }
}
function unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData) {
rfCbData);
}
else
- window.alert(clabels["You cannot unsubscribe from a folder that you own!"].decodeEntities());
+ window.alert(clabels["You cannot unsubscribe from a folder that you own!"]);
}
}
firstTab = null;
for (var i = 0; i < nodes.length; i++) {
- var currentNode = nodes[i];
- if (currentNode.tagName == 'LI') {
- if (!firstTab)
- firstTab = i;
- Event.observe(currentNode, "mousedown",
- onTabMouseDown.bindAsEventListener(currentNode));
- Event.observe(currentNode, "click",
- onTabClick.bindAsEventListener(currentNode));
- //$(currentNode.getAttribute("target")).hide();
- }
+ var currentNode = nodes[i];
+ if (currentNode.tagName == 'LI') {
+ if (!firstTab)
+ firstTab = i;
+ Event.observe(currentNode, "mousedown",
+ onTabMouseDown.bindAsEventListener(currentNode));
+ Event.observe(currentNode, "click",
+ onTabClick.bindAsEventListener(currentNode));
+ //$(currentNode.getAttribute("target")).hide();
+ }
}
nodes[firstTab].addClassName("first");
}
function initMenus() {
- var menus = getMenus();
- if (menus) {
- for (var menuID in menus) {
- var menuDIV = $(menuID);
- if (menuDIV)
- initMenu(menuDIV, menus[menuID]);
- }
- }
+ var menus = getMenus();
+ if (menus) {
+ for (var menuID in menus) {
+ var menuDIV = $(menuID);
+ if (menuDIV)
+ initMenu(menuDIV, menus[menuID]);
+ }
+ }
}
function initMenu(menuDIV, callbacks) {
- var lis = $(menuDIV.childNodesWithTag("ul")[0]).childNodesWithTag("li");
- for (var j = 0; j < lis.length; j++) {
- var node = $(lis[j]);
- Event.observe(node, "mousedown", listRowMouseDownHandler, false);
- var callback = callbacks[j];
- if (callback) {
- if (typeof(callback) == "string") {
- if (callback == "-")
- node.addClassName("separator");
- else {
- node.submenu = callback;
- node.addClassName("submenu");
- Event.observe(node, "mouseover", dropDownSubmenu);
- }
- }
- else
- Event.observe(node, "mouseup",
- $(callback).bindAsEventListener(node));
+ var lis = $(menuDIV.childNodesWithTag("ul")[0]).childNodesWithTag("li");
+ for (var j = 0; j < lis.length; j++) {
+ var node = $(lis[j]);
+ Event.observe(node, "mousedown",
+ listRowMouseDownHandler.bindAsEventListener(node),
+ false);
+ var callback = callbacks[j];
+ if (callback) {
+ if (typeof(callback) == "string") {
+ if (callback == "-") {
+ node.addClassName("separator");
+ node.appendChild(document.createElement("hr"));
+ }
+ else {
+ node.submenu = callback;
+ node.addClassName("submenu");
+ Event.observe(node, "mouseover",
+ popupSubmenu.bindAsEventListener(node));
+ }
}
else
- node.addClassName("disabled");
- }
+ Event.observe(node, "mouseup",
+ $(callback).bindAsEventListener(node));
+ }
+ else
+ node.addClassName("disabled");
+ }
}
function onTabMouseDown(event) {
}
function getUsersRightsWindowHeight() {
- return usersRightsWindowHeight;
+ return usersRightsWindowHeight;
}
function getUsersRightsWindowWidth() {
- return usersRightsWindowWidth;
+ return usersRightsWindowWidth;
}
function getTopWindow() {
- var topWindow = null;
- var currentWindow = window;
- while (!topWindow) {
- if (currentWindow.document.body.hasClassName("popup")
- && currentWindow.opener)
- currentWindow = currentWindow.opener;
- else
- topWindow = currentWindow;
- }
+ var topWindow = null;
+ var currentWindow = window;
+ while (!topWindow) {
+ if (currentWindow.document.body.hasClassName("popup")
+ && currentWindow.opener)
+ currentWindow = currentWindow.opener;
+ else
+ topWindow = currentWindow;
+ }
- return topWindow;
+ return topWindow;
}
function onTabClick(event) {
var currentValue = number;
var index = 0;
while (currentValue) {
- if (currentValue & 1)
- colorTable[index]++;
- if (index == 3)
- index = 0;
- currentValue >>= 1;
- index++;
+ if (currentValue & 1)
+ colorTable[index]++;
+ if (index == 3)
+ index = 0;
+ currentValue >>= 1;
+ index++;
}
color = ("#"
}
function loadPreferences() {
- var url = UserFolderURL + "jsonDefaults";
- var http = createHTTPClient();
- http.open("GET", url, false);
- http.send("");
- if (http.status == 200)
- userDefaults = http.responseText.evalJSON(true);
+ var url = UserFolderURL + "jsonDefaults";
+ var http = createHTTPClient();
+ http.open("GET", url, false);
+ http.send("");
+ if (http.status == 200)
+ userDefaults = http.responseText.evalJSON(true);
- url = UserFolderURL + "jsonSettings";
- http.open("GET", url, false);
- http.send("");
- if (http.status == 200)
- userSettings = http.responseText.evalJSON(true);
+ url = UserFolderURL + "jsonSettings";
+ http.open("GET", url, false);
+ http.send("");
+ if (http.status == 200)
+ userSettings = http.responseText.evalJSON(true);
}
function onLoadHandler(event) {
initTabs();
configureDragHandles();
configureLinkBanner();
- translateLabels();
var progressImage = $("progressIndicator");
if (progressImage)
progressImage.parentNode.removeChild(progressImage);
Event.observe(document.body, "contextmenu", onBodyClickContextMenu);
}
-function translateLabels() {
- if (typeof labels != "undefined") {
- for (var key in labels)
- labels[key] = labels[key].decodeEntities();
- }
-
- if (typeof clabels != "undefined") {
- for (var key in clabels)
- clabels[key] = clabels[key].decodeEntities();
- }
-}
-
function onBodyClickContextMenu(event) {
- preventDefault(event);
+ preventDefault(event);
}
function configureSortableTableHeaders(table) {
- var headers = $(table).getElementsByClassName("sortableTableHeader");
- for (var i = 0; i < headers.length; i++) {
- var header = headers[i];
- Event.observe(header, "click", onHeaderClick.bindAsEventListener(header))
- }
+ var headers = $(table).getElementsByClassName("sortableTableHeader");
+ for (var i = 0; i < headers.length; i++) {
+ var header = headers[i];
+ Event.observe(header, "click", onHeaderClick.bindAsEventListener(header))
+ }
}
function onLinkBannerClick() {
}
function onPreferencesClick(event) {
- var urlstr = UserFolderURL + "preferences";
- var w = window.open(urlstr, "_blank",
- "width=430,height=250,resizable=0,scrollbars=0");
- w.opener = window;
- w.focus();
+ var urlstr = UserFolderURL + "preferences";
+ var w = window.open(urlstr, "_blank",
+ "width=430,height=250,resizable=0,scrollbars=0,location=0");
+ w.opener = window;
+ w.focus();
- preventDefault(event);
+ preventDefault(event);
}
function configureLinkBanner() {
if (linkBanner) {
var anchors = linkBanner.childNodesWithTag("a");
for (var i = 1; i < 3; i++) {
- Event.observe(anchors[i], "mousedown", listRowMouseDownHandler);
- Event.observe(anchors[i], "click", onLinkBannerClick);
+ Event.observe(anchors[i], "mousedown", listRowMouseDownHandler);
+ Event.observe(anchors[i], "click", onLinkBannerClick);
}
Event.observe(anchors[4], "mousedown", listRowMouseDownHandler);
Event.observe(anchors[4], "click", onPreferencesClick);
if (anchors.length > 5)
- Event.observe(anchors[5], "click", toggleLogConsole);
+ Event.observe(anchors[5], "click", toggleLogConsole);
}
}
}
var url = ApplicationBaseURL + "/createFolder?name=" + name;
document.newFolderAjaxRequest
- = triggerAjaxRequest(url, createFolderCallback,
- {name: name,
- okCB: okCB,
- notOkCB: notOkCB});
+ = triggerAjaxRequest(url, createFolderCallback,
+ {name: name,
+ okCB: okCB,
+ notOkCB: notOkCB});
}
}
addEvent(window, 'load', onLoadHandler);
function parent$(element) {
- return this.opener.document.getElementById(element);
+ return this.opener.document.getElementById(element);
}
/* stubs */
}
function onHeaderClick(event) {
- window.alert("generic headerClick");
+ window.alert("generic headerClick");
}
-/*\r
-*\r
-* Copyright (c) 2007 Andrew Tetlaw & Millstream Web Software\r
-* http://www.millstream.com.au/view/code/tablekit/\r
-* Version: 1.2.1 2007-03-11\r
-* \r
-* Permission is hereby granted, free of charge, to any person\r
-* obtaining a copy of this software and associated documentation\r
-* files (the "Software"), to deal in the Software without\r
-* restriction, including without limitation the rights to use, copy,\r
-* modify, merge, publish, distribute, sublicense, and/or sell copies\r
-* of the Software, and to permit persons to whom the Software is\r
-* furnished to do so, subject to the following conditions:\r
-* \r
-* The above copyright notice and this permission notice shall be\r
-* included in all copies or substantial portions of the Software.\r
-* \r
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
-* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
-* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
-* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
-* SOFTWARE.\r
-* * \r
-*/\r
-\r
-// Use the TableKit class constructure if you'd prefer to init your tables as JS objects\r
-var TableKit = Class.create();\r
-\r
-TableKit.prototype = {\r
- initialize : function(elm, options) {\r
- var table = $(elm);\r
- if(table.tagName !== "TABLE") {\r
- return;\r
- }\r
- TableKit.register(table,Object.extend(TableKit.options,options || {}));\r
- this.id = table.id;\r
- var op = TableKit.option('sortable resizable editable', this.id);\r
- if(op.sortable) {\r
- TableKit.Sortable.init(table);\r
- } \r
- if(op.resizable) {\r
- TableKit.Resizable.init(table);\r
- }\r
- if(op.editable) {\r
- TableKit.Editable.init(table);\r
- }\r
- },\r
- sort : function(column, order) {\r
- TableKit.Sortable.sort(this.id, column, order);\r
- },\r
- resizeColumn : function(column, w) {\r
- TableKit.Resizable.resize(this.id, column, w);\r
- },\r
- editCell : function(row, column) {\r
- TableKit.Editable.editCell(this.id, row, column);\r
- }\r
-};\r
-\r
-Object.extend(TableKit, {\r
- getBodyRows : function(table) {\r
- table = $(table);\r
- var id = table.id;\r
- if(!TableKit.rows[id]) {\r
- TableKit.rows[id] = (table.tHead && table.tHead.rows.length > 0) ? $A(table.tBodies[0].rows) : $A(table.rows).without(table.rows[0]);\r
- }\r
- return TableKit.rows[id];\r
- },\r
- getHeaderCells : function(table, cell) {\r
- if(!table) { table = $(cell).up('table'); }\r
- var id = table.id;\r
- if(!TableKit.heads[id]) {\r
- //TableKit.heads[id] = $A((table.tHead && table.tHead.rows.length > 0) ? table.tHead.rows[table.tHead.rows.length-1].cells : table.rows[0].cells);\r
- TableKit.heads[id] = $A((table.tHead && table.tHead.rows.length > 0) ? table.tHead.rows[0].cells : table.rows[0].cells);\r
- }\r
- return TableKit.heads[id];\r
- },\r
- getCellIndex : function(cell) {\r
- return $A(cell.parentNode.cells).indexOf(cell);\r
- },\r
- getRowIndex : function(row) {\r
- return $A(row.parentNode.rows).indexOf(row);\r
- },\r
- getCellText : function(cell, refresh) {\r
- if(!cell) { return ""; }\r
- TableKit.registerCell(cell);\r
- var data = TableKit.cells[cell.id];\r
- if(refresh || data.refresh || !data.textContent) {\r
- data.textContent = cell.textContent ? cell.textContent : cell.innerText;\r
- data.refresh = false;\r
- }\r
- return data.textContent;\r
- },\r
- register : function(table, options) {\r
- if(!table.id) {\r
- TableKit._tblcount += 1;\r
- table.id = "tablekit-table-" + TableKit._tblcount;\r
- }\r
- var id = table.id;\r
- TableKit.tables[id] = TableKit.tables[id] ? Object.extend(TableKit.tables[id], options || {}) : Object.extend({sortable:false,resizable:false,editable:false}, options || {});\r
- },\r
- registerCell : function(cell) {\r
- if(!cell.id) {\r
- TableKit._cellcount += 1;\r
- cell.id = "tablekit-cell-" + TableKit._cellcount;\r
- }\r
- if(!TableKit.cells[cell.id]) {\r
- TableKit.cells[cell.id] = {textContent : '', htmlContent : '', active : false};\r
- }\r
- },\r
- isSortable : function(table) {\r
- return TableKit.tables[table.id] ? TableKit.tables[table.id].sortable : false;\r
- },\r
- isResizable : function(table) {\r
- return TableKit.tables[table.id] ? TableKit.tables[table.id].resizable : false;\r
- },\r
- isEditable : function(table) {\r
- return TableKit.tables[table.id] ? TableKit.tables[table.id].editable : false;\r
- },\r
- setup : function(o) {\r
- Object.extend(TableKit.options, o || {} );\r
- },\r
- option : function(s, id, o1, o2) {\r
- o1 = o1 || TableKit.options;\r
- o2 = o2 || (id ? (TableKit.tables[id] ? TableKit.tables[id] : {}) : {});\r
- var key = id + s;\r
- if(!TableKit._opcache[key]){\r
- TableKit._opcache[key] = $A($w(s)).inject([],function(a,v){\r
- a.push(a[v] = o2[v] || o1[v]);\r
- return a;\r
- });\r
- }\r
- return TableKit._opcache[key];\r
- },\r
- e : function(event) {\r
- return event || window.event;\r
- },\r
- tables : {},\r
- _opcache : {},\r
- cells : {},\r
- rows : {},\r
- heads : {},\r
- options : {\r
- autoLoad : true,\r
- stripe : true,\r
- sortable : true,\r
- resizable : true,\r
- editable : true,\r
- rowEvenClass : 'roweven',\r
- rowOddClass : 'rowodd',\r
- sortableSelector : ['table.sortable'],\r
- columnClass : 'sortcol',\r
- descendingClass : 'sortdesc',\r
- ascendingClass : 'sortasc',\r
- noSortClass : 'nosort',\r
- sortFirstAscendingClass : 'sortfirstasc',\r
- sortFirstDecendingClass : 'sortfirstdesc',\r
- resizableSelector : ['table.resizable'],\r
- minWidth : 10,\r
- showHandle : true,\r
- resizeOnHandleClass : 'resize-handle-active',\r
- editableSelector : ['table.editable'],\r
- formClassName : 'editable-cell-form',\r
- noEditClass : 'noedit',\r
- editAjaxURI : '/',\r
- editAjaxOptions : {}\r
- },\r
- _tblcount : 0,\r
- _cellcount : 0,\r
- load : function() {\r
- if(TableKit.options.autoLoad) {\r
- if(TableKit.options.sortable) {\r
- $A(TableKit.options.sortableSelector).each(function(s){\r
- $$(s).each(function(t) {\r
- TableKit.Sortable.init(t);\r
- });\r
- });\r
- }\r
- if(TableKit.options.resizable) {\r
- $A(TableKit.options.resizableSelector).each(function(s){\r
- $$(s).each(function(t) {\r
- TableKit.Resizable.init(t);\r
- });\r
- });\r
- }\r
- if(TableKit.options.editable) {\r
- $A(TableKit.options.editableSelector).each(function(s){\r
- $$(s).each(function(t) {\r
- TableKit.Editable.init(t);\r
- });\r
- });\r
- }\r
- }\r
- }\r
-});\r
-\r
-TableKit.Rows = {\r
- stripe : function(table) {\r
- var rows = TableKit.getBodyRows(table);\r
- rows.each(function(r,i) {\r
- TableKit.Rows.addStripeClass(table,r,i);\r
- });\r
- },\r
- addStripeClass : function(t,r,i) {\r
- t = t || r.up('table');\r
- var op = TableKit.option('rowEvenClass rowOddClass', t.id);\r
- var css = ((i+1)%2 === 0 ? op[0] : op[1]);\r
- // using prototype's assClassName/RemoveClassName was not efficient for large tables, hence:\r
- var cn = r.className.split(/\s+/);\r
- var newCn = [];\r
- for(var x = 0, l = cn.length; x < l; x += 1) {\r
- if(cn[x] !== op[0] && cn[x] !== op[1]) { newCn.push(cn[x]); }\r
- }\r
- newCn.push(css);\r
- r.className = newCn.join(" ");\r
- }\r
-};\r
-\r
-TableKit.Sortable = {\r
- init : function(elm, options){\r
- var table = $(elm);\r
- if(table.tagName !== "TABLE") {\r
- return;\r
- }\r
- TableKit.register(table,Object.extend(options || {},{sortable:true}));\r
- var sortFirst;\r
- var cells = TableKit.getHeaderCells(table);\r
- var op = TableKit.option('noSortClass columnClass sortFirstAscendingClass sortFirstDecendingClass', table.id);\r
- cells.each(function(c){\r
- c = $(c);\r
- if(!c.hasClassName(op.noSortClass)) {\r
- Event.observe(c, 'mousedown', TableKit.Sortable._sort);\r
- c.addClassName(op.columnClass);\r
- if(c.hasClassName(op.sortFirstAscendingClass) || c.hasClassName(op.sortFirstDecendingClass)) {\r
- sortFirst = c;\r
- }\r
- }\r
- });\r
-\r
- if(sortFirst) {\r
- if(sortFirst.hasClassName(op.sortFirstAscendingClass)) {\r
- TableKit.Sortable.sort(table, sortFirst, 1);\r
- } else {\r
- TableKit.Sortable.sort(table, sortFirst, -1);\r
- }\r
- } else { // just add row stripe classes\r
- TableKit.Rows.stripe(table);\r
- }\r
- },\r
- reload : function(table) {\r
- table = $(table);\r
- var cells = TableKit.getHeaderCells(table);\r
- var op = TableKit.option('noSortClass columnClass', table.id);\r
- cells.each(function(c){\r
- c = $(c);\r
- if(!c.hasClassName(op.noSortClass)) {\r
- Event.stopObserving(c, 'mousedown', TableKit.Sortable._sort);\r
- c.removeClassName(op.columnClass);\r
- }\r
- });\r
- TableKit.Sortable.init(table);\r
- },\r
- _sort : function(e) {\r
- if(TableKit.Resizable._onHandle) {return;}\r
- e = TableKit.e(e);\r
- Event.stop(e);\r
- var cell = Event.element(e);\r
- while(!(cell.tagName && cell.tagName.match(/td|th/gi))) {\r
- cell = cell.parentNode;\r
- }\r
- TableKit.Sortable.sort(null, cell);\r
- },\r
- sort : function(table, index, order) {\r
- var cell;\r
- if(typeof index === 'number') {\r
- if(!table || (table.tagName && table.tagName !== "TABLE")) {\r
- return;\r
- }\r
- table = $(table);\r
- index = Math.min(table.rows[0].cells.length, index);\r
- index = Math.max(1, index);\r
- index -= 1;\r
- cell = (table.tHead && table.tHead.rows.length > 0) ? $(table.tHead.rows[table.tHead.rows.length-1].cells[index]) : $(table.rows[0].cells[index]);\r
- } else {\r
- cell = $(index);\r
- table = table ? $(table) : cell.up('table');\r
- index = TableKit.getCellIndex(cell);\r
- }\r
- var op = TableKit.option('noSortClass descendingClass ascendingClass', table.id);\r
- \r
- if(cell.hasClassName(op.noSortClass)) {return;} \r
- \r
- order = order ? order : (cell.hasClassName(op.descendingClass) ? 1 : -1);\r
- var rows = TableKit.getBodyRows(table);\r
-\r
- if(cell.hasClassName(op.ascendingClass) || cell.hasClassName(op.descendingClass)) {\r
- rows.reverse(); // if it was already sorted we just need to reverse it.\r
- } else {\r
- var datatype = TableKit.Sortable.getDataType(cell,index,table);\r
- var tkst = TableKit.Sortable.types;\r
- rows.sort(function(a,b) {\r
- return order * tkst[datatype].compare(TableKit.getCellText(a.cells[index]),TableKit.getCellText(b.cells[index]));\r
- });\r
- }\r
- var tb = table.tBodies[0];\r
- var tkr = TableKit.Rows;\r
- rows.each(function(r,i) {\r
- tb.appendChild(r);\r
- tkr.addStripeClass(table,r,i);\r
- });\r
- var hcells = TableKit.getHeaderCells(null, cell);\r
- $A(hcells).each(function(c,i){\r
- c = $(c);\r
- c.removeClassName(op.ascendingClass);\r
- c.removeClassName(op.descendingClass);\r
- if(index === i) {\r
- if(order === 1) {\r
- c.removeClassName(op.descendingClass);\r
- c.addClassName(op.ascendingClass);\r
- } else {\r
- c.removeClassName(op.ascendingClass);\r
- c.addClassName(op.descendingClass);\r
- }\r
- }\r
- });\r
- },\r
- types : {},\r
- detectors : [],\r
- addSortType : function() {\r
- $A(arguments).each(function(o){\r
- TableKit.Sortable.types[o.name] = o;\r
- });\r
- },\r
- getDataType : function(cell,index,table) {\r
- cell = $(cell);\r
- index = (index || index === 0) ? index : TableKit.getCellIndex(cell);\r
- \r
- var colcache = TableKit.Sortable._coltypecache;\r
- var cache = colcache[table.id] ? colcache[table.id] : (colcache[table.id] = {});\r
- \r
- if(!cache[index]) {\r
- var t = '';\r
- // first look for a data type id on the heading row cell\r
- if(cell.id && TableKit.Sortable.types[cell.id]) {\r
- t = cell.id;\r
- }\r
- t = cell.classNames().detect(function(n){ // then look for a data type classname on the heading row cell\r
- return (TableKit.Sortable.types[n]) ? true : false;\r
- });\r
- if(!t) {\r
- var rows = TableKit.getBodyRows(table);\r
- cell = rows[0].cells[index]; // grab same index cell from body row to try and match data type\r
- t = TableKit.Sortable.detectors.detect(\r
- function(d){\r
- return TableKit.Sortable.types[d].detect(TableKit.getCellText(cell));\r
- });\r
- }\r
- cache[index] = t;\r
- }\r
- return cache[index];\r
- },\r
- _coltypecache : {}\r
-};\r
-\r
-TableKit.Sortable.detectors = $A($w('date-iso date date-eu date-au time currency datasize number casesensitivetext text')); // setting it here because Safari complained when I did it above...\r
-\r
-TableKit.Sortable.Type = Class.create();\r
-TableKit.Sortable.Type.prototype = {\r
- initialize : function(name, options){\r
- this.name = name;\r
- options = Object.extend({\r
- normal : function(v){\r
- return v;\r
- },\r
- pattern : /.*/\r
- }, options || {});\r
- this.normal = options.normal;\r
- this.pattern = options.pattern;\r
- if(options.compare) {\r
- this.compare = options.compare;\r
- }\r
- if(options.detect) {\r
- this.detect = options.detect;\r
- }\r
- },\r
- compare : function(a,b){\r
- return TableKit.Sortable.Type.compare(this.normal(a), this.normal(b));\r
- },\r
- detect : function(v){\r
- return this.pattern.test(v);\r
- }\r
-};\r
-\r
-TableKit.Sortable.Type.compare = function(a,b) {\r
- return a < b ? -1 : a === b ? 0 : 1;\r
-};\r
-\r
-TableKit.Sortable.addSortType(\r
- new TableKit.Sortable.Type('number', {\r
- pattern : /^[-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?/,\r
- normal : function(v) {\r
- // This will grab the first thing that looks like a number from a string, so you can use it to order a column of various srings containing numbers.\r
- v = parseFloat(v.replace(/^.*?([-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?).*$/,"$1"));\r
- return isNaN(v) ? 0 : v;\r
- }}),\r
- new TableKit.Sortable.Type('text',{\r
- normal : function(v) {\r
- return v ? v.toLowerCase() : '';\r
- }}),\r
- new TableKit.Sortable.Type('casesensitivetext',{pattern : /^[A-Z]+$/}),\r
- new TableKit.Sortable.Type('datasize',{\r
- pattern : /^[-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?\s?[k|m|g|t]b$/i,\r
- normal : function(v) {\r
- var r = v.match(/^([-+]?[\d]*\.?[\d]+([eE][-+]?[\d]+)?)\s?([k|m|g|t]?b)?/i);\r
- var b = r[1] ? Number(r[1]).valueOf() : 0;\r
- var m = r[3] ? r[3].substr(0,1).toLowerCase() : '';\r
- var result = b;\r
- switch(m) {\r
- case 'k':\r
- result = b * 1024;\r
- break;\r
- case 'm': \r
- result = b * 1024 * 1024;\r
- break;\r
- case 'g':\r
- result = b * 1024 * 1024 * 1024;\r
- break;\r
- case 't':\r
- result = b * 1024 * 1024 * 1024 * 1024;\r
- break;\r
- }\r
- return result;\r
- }}),\r
- new TableKit.Sortable.Type('date-au',{\r
- pattern : /^\d{2}\/\d{2}\/\d{4}\s?(?:\d{1,2}\:\d{2}(?:\:\d{2})?\s?[a|p]?m?)?/i,\r
- normal : function(v) {\r
- if(!this.pattern.test(v)) {return 0;}\r
- var r = v.match(/^(\d{2})\/(\d{2})\/(\d{4})\s?(?:(\d{1,2})\:(\d{2})(?:\:(\d{2}))?\s?([a|p]?m?))?/i);\r
- var yr_num = r[3];\r
- var mo_num = parseInt(r[2],10)-1;\r
- var day_num = r[1];\r
- var hr_num = r[4] ? r[4] : 0;\r
- if(r[7] && r[7].toLowerCase().indexOf('p') !== -1) {\r
- hr_num = parseInt(r[4],10) + 12;\r
- }\r
- var min_num = r[5] ? r[5] : 0;\r
- var sec_num = r[6] ? r[6] : 0;\r
- return new Date(yr_num, mo_num, day_num, hr_num, min_num, sec_num, 0).valueOf();\r
- }}),\r
- new TableKit.Sortable.Type('date-us',{\r
- pattern : /^\d{2}\/\d{2}\/\d{4}\s?(?:\d{1,2}\:\d{2}(?:\:\d{2})?\s?[a|p]?m?)?/i,\r
- normal : function(v) {\r
- if(!this.pattern.test(v)) {return 0;}\r
- var r = v.match(/^(\d{2})\/(\d{2})\/(\d{4})\s?(?:(\d{1,2})\:(\d{2})(?:\:(\d{2}))?\s?([a|p]?m?))?/i);\r
- var yr_num = r[3];\r
- var mo_num = parseInt(r[1],10)-1;\r
- var day_num = r[2];\r
- var hr_num = r[4] ? r[4] : 0;\r
- if(r[7] && r[7].toLowerCase().indexOf('p') !== -1) {\r
- hr_num = parseInt(r[4],10) + 12;\r
- }\r
- var min_num = r[5] ? r[5] : 0;\r
- var sec_num = r[6] ? r[6] : 0;\r
- return new Date(yr_num, mo_num, day_num, hr_num, min_num, sec_num, 0).valueOf();\r
- }}),\r
- new TableKit.Sortable.Type('date-eu',{\r
- pattern : /^\d{2}-\d{2}-\d{4}/i,\r
- normal : function(v) {\r
- if(!this.pattern.test(v)) {return 0;}\r
- var r = v.match(/^(\d{2})-(\d{2})-(\d{4})/);\r
- var yr_num = r[3];\r
- var mo_num = parseInt(r[2],10)-1;\r
- var day_num = r[1];\r
- return new Date(yr_num, mo_num, day_num).valueOf();\r
- }}),\r
- new TableKit.Sortable.Type('date-iso',{\r
- pattern : /[\d]{4}-[\d]{2}-[\d]{2}(?:T[\d]{2}\:[\d]{2}(?:\:[\d]{2}(?:\.[\d]+)?)?(Z|([-+][\d]{2}:[\d]{2})?)?)?/, // 2005-03-26T19:51:34Z\r
- normal : function(v) {\r
- if(!this.pattern.test(v)) {return 0;}\r
- var d = v.match(/([\d]{4})(-([\d]{2})(-([\d]{2})(T([\d]{2}):([\d]{2})(:([\d]{2})(\.([\d]+))?)?(Z|(([-+])([\d]{2}):([\d]{2})))?)?)?)?/); \r
- var offset = 0;\r
- var date = new Date(d[1], 0, 1);\r
- if (d[3]) { date.setMonth(d[3] - 1) ;}\r
- if (d[5]) { date.setDate(d[5]); }\r
- if (d[7]) { date.setHours(d[7]); }\r
- if (d[8]) { date.setMinutes(d[8]); }\r
- if (d[10]) { date.setSeconds(d[10]); }\r
- if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }\r
- if (d[14]) {\r
- offset = (Number(d[16]) * 60) + Number(d[17]);\r
- offset *= ((d[15] === '-') ? 1 : -1);\r
- }\r
- offset -= date.getTimezoneOffset();\r
- if(offset !== 0) {\r
- var time = (Number(date) + (offset * 60 * 1000));\r
- date.setTime(Number(time));\r
- }\r
- return date.valueOf();\r
- }}),\r
- new TableKit.Sortable.Type('date',{\r
- pattern: /^(?:sun|mon|tue|wed|thu|fri|sat)\,\s\d{1,2}\s(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\s\d{4}(?:\s\d{2}\:\d{2}(?:\:\d{2})?(?:\sGMT(?:[+-]\d{4})?)?)?/i, //Mon, 18 Dec 1995 17:28:35 GMT\r
- compare : function(a,b) { // must be standard javascript date format\r
- if(a && b) {\r
- return TableKit.Sortable.Type.compare(new Date(a),new Date(b));\r
- } else {\r
- return TableKit.Sortable.Type.compare(a ? 1 : 0, b ? 1 : 0);\r
- }\r
- }}),\r
- new TableKit.Sortable.Type('time',{\r
- pattern : /^\d{1,2}\:\d{2}(?:\:\d{2})?(?:\s[a|p]m)?$/i,\r
- compare : function(a,b) {\r
- var d = new Date();\r
- var ds = d.getMonth() + "/" + d.getDate() + "/" + d.getFullYear() + " ";\r
- return TableKit.Sortable.Type.compare(new Date(ds + a),new Date(ds + b));\r
- }}),\r
- new TableKit.Sortable.Type('currency',{\r
- pattern : /^[$£¥\80¤]/, // dollar,pound,yen,euro,generic currency symbol\r
- normal : function(v) {\r
- return v ? parseFloat(v.replace(/[^-\d\.]/g,'')) : 0;\r
- }})\r
-);\r
-\r
-TableKit.Resizable = {\r
- init : function(elm, options){\r
- var table = $(elm);\r
- if(table.tagName !== "TABLE") {return;}\r
- TableKit.register(table,Object.extend(options || {},{resizable:true})); \r
- var cells = TableKit.getHeaderCells(table);\r
- cells.each(function(c){\r
- c = $(c);\r
- //log ("init on " + c.firstChild.nodeValue);\r
- Event.observe(c, 'mouseover', TableKit.Resizable.initDetect);\r
- Event.observe(c, 'mouseout', TableKit.Resizable.killDetect);\r
- });\r
- },\r
- reload : function(table) {\r
- table = $(table);\r
- var cells = TableKit.getHeaderCells(table);\r
- cells.each(function(c){\r
- c = $(c);\r
- Event.stopObserving(c, 'mouseover', TableKit.Resizable.initDetect);\r
- Event.stopObserving(c, 'mouseout', TableKit.Resizable.killDetect);\r
- });\r
- TableKit.Resizable.init(table);\r
- },\r
- resize : function(table, index, w) {\r
- var cell;\r
- if(typeof index === 'number') {\r
- if(!table || (table.tagName && table.tagName !== "TABLE")) {return;}\r
- table = $(table);\r
- index = Math.min(table.rows[0].cells.length, index);\r
- index = Math.max(1, index);\r
- index -= 1;\r
- cell = (table.tHead && table.tHead.rows.length > 0) ? $(table.tHead.rows[table.tHead.rows.length-1].cells[index]) : $(table.rows[0].cells[index]);\r
- } else {\r
- cell = $(index);\r
- table = table ? $(table) : cell.up('table');\r
- index = TableKit.getCellIndex(cell);\r
- }\r
- var pad = parseInt(cell.getStyle('paddingLeft'),10) + parseInt(cell.getStyle('paddingRight'),10);\r
- w = Math.max(w-pad, TableKit.option('minWidth', table.id)[0]);\r
- cell.setStyle({'width' : w + 'px'});\r
- },\r
- initDetect : function(e) {\r
- e = TableKit.e(e);\r
- var cell = Event.element(e);\r
- Event.observe(cell, 'mousemove', TableKit.Resizable.detectHandle);\r
- Event.observe(cell, 'mousedown', TableKit.Resizable.startResize);\r
- },\r
- detectHandle : function(e) {\r
- e = TableKit.e(e);\r
- var cell = Event.element(e);\r
- if(TableKit.Resizable.pointerPos(cell,Event.pointerX(e),Event.pointerY(e))){\r
- cell.addClassName(TableKit.option('resizeOnHandleClass', cell.up('table').id)[0]);\r
- TableKit.Resizable._onHandle = true;\r
- } else {\r
- cell.removeClassName(TableKit.option('resizeOnHandleClass', cell.up('table').id)[0]);\r
- TableKit.Resizable._onHandle = false;\r
- }\r
- },\r
- killDetect : function(e) {\r
- e = TableKit.e(e);\r
- TableKit.Resizable._onHandle = false;\r
- var cell = Event.element(e);\r
- if (!cell.tagName || cell.tagName != 'TD') return;\r
- Event.stopObserving(cell, 'mousemove', TableKit.Resizable.detectHandle);\r
- Event.stopObserving(cell, 'mousedown', TableKit.Resizable.startResize);\r
- cell.removeClassName(TableKit.option('resizeOnHandleClass', cell.up('table').id)[0]);\r
- },\r
- startResize : function(e) {\r
- e = TableKit.e(e);\r
- if(!TableKit.Resizable._onHandle) { return;}\r
- var cell = Event.element(e);\r
- Event.stopObserving(cell, 'mousemove', TableKit.Resizable.detectHandle);\r
- Event.stopObserving(cell, 'mousedown', TableKit.Resizable.startResize);\r
- Event.stopObserving(cell, 'mouseout', TableKit.Resizable.killDetect);\r
- TableKit.Resizable._cell = cell;\r
- var table = cell.up('table');\r
- TableKit.Resizable._tbl = table;\r
- if(TableKit.option('showHandle', table.id)[0]) {\r
- TableKit.Resizable._handle = $(document.createElement('div')).addClassName('resize-handle').setStyle({\r
- 'top' : Position.cumulativeOffset(cell)[1] + 'px',\r
- 'left' : Event.pointerX(e) + 'px',\r
- 'height' : table.getDimensions().height + 'px'\r
- });\r
- document.body.appendChild(TableKit.Resizable._handle);\r
- }\r
- Event.observe(document, 'mousemove', TableKit.Resizable.drag);\r
- Event.observe(document, 'mouseup', TableKit.Resizable.endResize);\r
- Event.stop(e);\r
- },\r
- endResize : function(e) {\r
- e = TableKit.e(e);\r
- var cell = TableKit.Resizable._cell;\r
- TableKit.Resizable.resize(null, cell, (Event.pointerX(e) - Position.cumulativeOffset(cell)[0]));\r
- Event.stopObserving(document, 'mousemove', TableKit.Resizable.drag);\r
- Event.stopObserving(document, 'mouseup', TableKit.Resizable.endResize);\r
- if(TableKit.option('showHandle', TableKit.Resizable._tbl.id)[0]) {\r
- $$('div.resize-handle').each(function(elm){\r
- document.body.removeChild(elm);\r
- });\r
- }\r
- Event.observe(cell, 'mouseout', TableKit.Resizable.killDetect);\r
- TableKit.Resizable._tbl = TableKit.Resizable._handle = TableKit.Resizable._cell = null;\r
- Event.stop(e);\r
- },\r
- drag : function(e) {\r
- e = TableKit.e(e);\r
- if(TableKit.Resizable._handle === null) {\r
- try {\r
- TableKit.Resizable.resize(TableKit.Resizable._tbl, TableKit.Resizable._cell, (Event.pointerX(e) - Position.cumulativeOffset(TableKit.Resizable._cell)[0]));\r
- } catch(e) {}\r
- } else {\r
- TableKit.Resizable._handle.setStyle({'left' : Event.pointerX(e) + 'px'});\r
- }\r
- return false;\r
- },\r
- pointerPos : function(element, x, y) {\r
- var offset = Position.cumulativeOffset(element);\r
- return (y >= offset[1] &&\r
- y < offset[1] + element.offsetHeight &&\r
- x >= offset[0] + element.offsetWidth - 5 &&\r
- x < offset[0] + element.offsetWidth);\r
- },\r
- _onHandle : false,\r
- _cell : null,\r
- _tbl : null,\r
- _handle : null\r
-};\r
-\r
-\r
-TableKit.Editable = {\r
- init : function(elm, options){\r
- var table = $(elm);\r
- if(table.tagName !== "TABLE") {return;}\r
- TableKit.register(table,Object.extend(options || {},{editable:true}));\r
- Event.observe(table.tBodies[0], 'click', TableKit.Editable._editCell);\r
- },\r
- _editCell : function(e) {\r
- e = TableKit.e(e);\r
- var cell = Event.findElement(e,'td');\r
- TableKit.Editable.editCell(null, cell);\r
- },\r
- editCell : function(table, index, cindex) {\r
- var cell, row;\r
- if(typeof index === 'number') {\r
- if(!table || (table.tagName && table.tagName !== "TABLE")) {return;}\r
- table = $(table);\r
- index = Math.min(table.tBodies[0].rows.length, index);\r
- index = Math.max(1, index);\r
- index -= 1;\r
- cindex = Math.min(table.rows[0].cells.length, cindex);\r
- cindex = Math.max(1, cindex);\r
- cindex -= 1;\r
- row = $(table.tBodies[0].rows[index]);\r
- cell = $(row.cells[cindex]);\r
- } else {\r
- cell = $(index);\r
- table = (table && table.tagName && table.tagName !== "TABLE") ? $(table) : cell.up('table');\r
- row = cell.up('tr');\r
- }\r
- var op = TableKit.option('noEditClass', table.id);\r
- if(cell.hasClassName(op.noEditClass)) {return;}\r
- \r
- var head = $(TableKit.getHeaderCells(table, cell)[TableKit.getCellIndex(cell)]);\r
- if(head.hasClassName(op.noEditClass)) {return;}\r
- \r
- TableKit.registerCell(cell);\r
- var data = TableKit.cells[cell.id];\r
- if(data.active) {return;}\r
- data.htmlContent = cell.innerHTML;\r
- var ftype = TableKit.Editable.types['text-input'];\r
- if(head.id && TableKit.Editable.types[head.id]) {\r
- ftype = TableKit.Editable.types[head.id];\r
- } else {\r
- var n = head.classNames().detect(function(n){\r
- return (TableKit.Editable.types[n]) ? true : false;\r
- });\r
- ftype = n ? TableKit.Editable.types[n] : ftype;\r
- }\r
- ftype.edit(cell);\r
- data.active = true;\r
- },\r
- types : {},\r
- addCellEditor : function(o) {\r
- if(o && o.name) { TableKit.Editable.types[o.name] = o; }\r
- }\r
-};\r
-\r
-TableKit.Editable.CellEditor = Class.create();\r
-TableKit.Editable.CellEditor.prototype = {\r
- initialize : function(name, options){\r
- this.name = name;\r
- this.options = Object.extend({\r
- element : 'input',\r
- attributes : {name : 'value', type : 'text'},\r
- selectOptions : [],\r
- showSubmit : true,\r
- submitText : 'OK',\r
- showCancel : true,\r
- cancelText : 'Cancel',\r
- ajaxURI : null,\r
- ajaxOptions : null\r
- }, options || {});\r
- },\r
- edit : function(cell) {\r
- cell = $(cell);\r
- var op = this.options;\r
- var table = cell.up('table');\r
- \r
- var form = $(document.createElement("form"));\r
- form.id = cell.id + '-form';\r
- form.addClassName(TableKit.option('formClassName', table.id)[0]);\r
- form.onsubmit = this._submit.bindAsEventListener(this);\r
- \r
- var field = document.createElement(op.element);\r
- $H(op.attributes).each(function(v){\r
- field[v.key] = v.value;\r
- });\r
- switch(op.element) {\r
- case 'input':\r
- case 'textarea':\r
- field.value = TableKit.getCellText(cell);\r
- break;\r
- \r
- case 'select':\r
- var txt = TableKit.getCellText(cell);\r
- $A(op.selectOptions).each(function(v){\r
- field.options[field.options.length] = new Option(v[0], v[1]);\r
- if(txt === v[1]) {\r
- field.options[field.options.length-1].selected = 'selected';\r
- }\r
- });\r
- break;\r
- }\r
- form.appendChild(field);\r
- if(op.element === 'textarea') {\r
- form.appendChild(document.createElement("br"));\r
- }\r
- if(op.showSubmit) {\r
- var okButton = document.createElement("input");\r
- okButton.type = "submit";\r
- okButton.value = op.submitText;\r
- okButton.className = 'editor_ok_button';\r
- form.appendChild(okButton);\r
- }\r
- if(op.showCancel) {\r
- var cancelLink = document.createElement("a");\r
- cancelLink.href = "#";\r
- cancelLink.appendChild(document.createTextNode(op.cancelText));\r
- cancelLink.onclick = this._cancel.bindAsEventListener(this);\r
- cancelLink.className = 'editor_cancel'; \r
- form.appendChild(cancelLink);\r
- }\r
- cell.innerHTML = '';\r
- cell.appendChild(form);\r
- },\r
- _submit : function(e) {\r
- var cell = Event.findElement(e,'td');\r
- var form = Event.findElement(e,'form');\r
- Event.stop(e);\r
- this.submit(cell,form);\r
- },\r
- submit : function(cell, form) {\r
- var op = this.options;\r
- form = form ? form : cell.down('form');\r
- var head = $(TableKit.getHeaderCells(null, cell)[TableKit.getCellIndex(cell)]);\r
- var row = cell.up('tr');\r
- var table = cell.up('table');\r
- var s = '&row=' + (TableKit.getRowIndex(row)+1) + '&cell=' + (TableKit.getCellIndex(cell)+1) + '&id=' + row.id + '&field=' + head.id + '&' + Form.serialize(form);\r
- this.ajax = new Ajax.Updater(cell, op.ajaxURI || TableKit.option('editAjaxURI', table.id)[0], Object.extend(op.ajaxOptions || TableKit.option('editAjaxOptions', table.id)[0], {\r
- postBody : s,\r
- onComplete : function() {\r
- var data = TableKit.cells[cell.id];\r
- data.active = false;\r
- data.refresh = true; // mark cell cache for refreshing, in case cell contents has changed and sorting is applied\r
- }\r
- }));\r
- },\r
- _cancel : function(e) {\r
- var cell = Event.findElement(e,'td');\r
- Event.stop(e);\r
- this.cancel(cell);\r
- },\r
- cancel : function(cell) {\r
- this.ajax = null;\r
- var data = TableKit.cells[cell.id];\r
- cell.innerHTML = data.htmlContent;\r
- data.htmlContent = '';\r
- data.active = false;\r
- },\r
- ajax : null\r
-};\r
-\r
-TableKit.Editable.textInput = function(n,attributes) {\r
- TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {\r
- element : 'input',\r
- attributes : Object.extend({name : 'value', type : 'text'}, attributes||{})\r
- }));\r
-};\r
-TableKit.Editable.textInput('text-input');\r
-\r
-TableKit.Editable.multiLineInput = function(n,attributes) {\r
- TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {\r
- element : 'textarea',\r
- attributes : Object.extend({name : 'value', rows : '5', cols : '20'}, attributes||{})\r
- })); \r
-}; \r
-TableKit.Editable.multiLineInput('multi-line-input');\r
-\r
-TableKit.Editable.selectInput = function(n,attributes,selectOptions) {\r
- TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {\r
- element : 'select',\r
- attributes : Object.extend({name : 'value'}, attributes||{}),\r
- 'selectOptions' : selectOptions\r
- })); \r
-};\r
-\r
-/*\r
-TableKit.Bench = {\r
- bench : [],\r
- start : function(){\r
- TableKit.Bench.bench[0] = new Date().getTime();\r
- },\r
- end : function(s){\r
- TableKit.Bench.bench[1] = new Date().getTime();\r
- alert(s + ' ' + ((TableKit.Bench.bench[1]-TableKit.Bench.bench[0])/1000)+' seconds.') //console.log(s + ' ' + ((TableKit.Bench.bench[1]-TableKit.Bench.bench[0])/1000)+' seconds.')\r
- TableKit.Bench.bench = [];\r
- }\r
-} */\r
-\r
-if(window.FastInit) {\r
- FastInit.addOnLoad(TableKit.load);\r
-} else {\r
- Event.observe(window, 'load', TableKit.load);\r
-}\r
+/*
+*
+* Copyright (c) 2007 Andrew Tetlaw & Millstream Web Software
+* http://www.millstream.com.au/view/code/tablekit/
+* Version: 1.2.1 2007-03-11
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy,
+* modify, merge, publish, distribute, sublicense, and/or sell copies
+* of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+* *
+*/
+
+// Use the TableKit class constructure if you'd prefer to init your tables as JS objects
+var TableKit = Class.create();
+
+TableKit.prototype = {
+ initialize : function(elm, options) {
+ var table = $(elm);
+ if(table.tagName !== "TABLE") {
+ return;
+ }
+ TableKit.register(table,Object.extend(TableKit.options,options || {}));
+ this.id = table.id;
+ var op = TableKit.option('sortable resizable editable', this.id);
+ if(op.sortable) {
+ TableKit.Sortable.init(table);
+ }
+ if(op.resizable) {
+ TableKit.Resizable.init(table);
+ }
+ if(op.editable) {
+ TableKit.Editable.init(table);
+ }
+ },
+ sort : function(column, order) {
+ TableKit.Sortable.sort(this.id, column, order);
+ },
+ resizeColumn : function(column, w) {
+ TableKit.Resizable.resize(this.id, column, w);
+ },
+ editCell : function(row, column) {
+ TableKit.Editable.editCell(this.id, row, column);
+ }
+};
+
+Object.extend(TableKit, {
+ getBodyRows : function(table) {
+ table = $(table);
+ var id = table.id;
+ if(!TableKit.rows[id]) {
+ TableKit.rows[id] = (table.tHead && table.tHead.rows.length > 0) ? $A(table.tBodies[0].rows) : $A(table.rows).without(table.rows[0]);
+ }
+ return TableKit.rows[id];
+ },
+ getHeaderCells : function(table, cell) {
+ if(!table) { table = $(cell).up('table'); }
+ var id = table.id;
+ if(!TableKit.heads[id]) {
+ //TableKit.heads[id] = $A((table.tHead && table.tHead.rows.length > 0) ? table.tHead.rows[table.tHead.rows.length-1].cells : table.rows[0].cells);
+ TableKit.heads[id] = $A((table.tHead && table.tHead.rows.length > 0) ? table.tHead.rows[0].cells : table.rows[0].cells);
+ }
+ return TableKit.heads[id];
+ },
+ getCellIndex : function(cell) {
+ return $A(cell.parentNode.cells).indexOf(cell);
+ },
+ getRowIndex : function(row) {
+ return $A(row.parentNode.rows).indexOf(row);
+ },
+ getCellText : function(cell, refresh) {
+ if(!cell) { return ""; }
+ TableKit.registerCell(cell);
+ var data = TableKit.cells[cell.id];
+ if(refresh || data.refresh || !data.textContent) {
+ data.textContent = cell.textContent ? cell.textContent : cell.innerText;
+ data.refresh = false;
+ }
+ return data.textContent;
+ },
+ register : function(table, options) {
+ if(!table.id) {
+ TableKit._tblcount += 1;
+ table.id = "tablekit-table-" + TableKit._tblcount;
+ }
+ var id = table.id;
+ TableKit.tables[id] = TableKit.tables[id] ? Object.extend(TableKit.tables[id], options || {}) : Object.extend({sortable:false,resizable:false,editable:false}, options || {});
+ },
+ registerCell : function(cell) {
+ if(!cell.id) {
+ TableKit._cellcount += 1;
+ cell.id = "tablekit-cell-" + TableKit._cellcount;
+ }
+ if(!TableKit.cells[cell.id]) {
+ TableKit.cells[cell.id] = {textContent : '', htmlContent : '', active : false};
+ }
+ },
+ isSortable : function(table) {
+ return TableKit.tables[table.id] ? TableKit.tables[table.id].sortable : false;
+ },
+ isResizable : function(table) {
+ return TableKit.tables[table.id] ? TableKit.tables[table.id].resizable : false;
+ },
+ isEditable : function(table) {
+ return TableKit.tables[table.id] ? TableKit.tables[table.id].editable : false;
+ },
+ setup : function(o) {
+ Object.extend(TableKit.options, o || {} );
+ },
+ option : function(s, id, o1, o2) {
+ o1 = o1 || TableKit.options;
+ o2 = o2 || (id ? (TableKit.tables[id] ? TableKit.tables[id] : {}) : {});
+ var key = id + s;
+ if(!TableKit._opcache[key]){
+ TableKit._opcache[key] = $A($w(s)).inject([],function(a,v){
+ a.push(a[v] = o2[v] || o1[v]);
+ return a;
+ });
+ }
+ return TableKit._opcache[key];
+ },
+ e : function(event) {
+ return event || window.event;
+ },
+ tables : {},
+ _opcache : {},
+ cells : {},
+ rows : {},
+ heads : {},
+ options : {
+ autoLoad : true,
+ stripe : true,
+ sortable : true,
+ resizable : true,
+ editable : true,
+ rowEvenClass : 'roweven',
+ rowOddClass : 'rowodd',
+ sortableSelector : ['table.sortable'],
+ columnClass : 'sortcol',
+ descendingClass : 'sortdesc',
+ ascendingClass : 'sortasc',
+ noSortClass : 'nosort',
+ sortFirstAscendingClass : 'sortfirstasc',
+ sortFirstDecendingClass : 'sortfirstdesc',
+ resizableSelector : ['table.resizable'],
+ minWidth : 10,
+ showHandle : true,
+ resizeOnHandleClass : 'resize-handle-active',
+ editableSelector : ['table.editable'],
+ formClassName : 'editable-cell-form',
+ noEditClass : 'noedit',
+ editAjaxURI : '/',
+ editAjaxOptions : {}
+ },
+ _tblcount : 0,
+ _cellcount : 0,
+ load : function() {
+ if(TableKit.options.autoLoad) {
+ if(TableKit.options.sortable) {
+ $A(TableKit.options.sortableSelector).each(function(s){
+ $$(s).each(function(t) {
+ TableKit.Sortable.init(t);
+ });
+ });
+ }
+ if(TableKit.options.resizable) {
+ $A(TableKit.options.resizableSelector).each(function(s){
+ $$(s).each(function(t) {
+ TableKit.Resizable.init(t);
+ });
+ });
+ }
+ if(TableKit.options.editable) {
+ $A(TableKit.options.editableSelector).each(function(s){
+ $$(s).each(function(t) {
+ TableKit.Editable.init(t);
+ });
+ });
+ }
+ }
+ }
+});
+
+TableKit.Rows = {
+ stripe : function(table) {
+ var rows = TableKit.getBodyRows(table);
+ rows.each(function(r,i) {
+ TableKit.Rows.addStripeClass(table,r,i);
+ });
+ },
+ addStripeClass : function(t,r,i) {
+ t = t || r.up('table');
+ var op = TableKit.option('rowEvenClass rowOddClass', t.id);
+ var css = ((i+1)%2 === 0 ? op[0] : op[1]);
+ // using prototype's assClassName/RemoveClassName was not efficient for large tables, hence:
+ var cn = r.className.split(/\s+/);
+ var newCn = [];
+ for(var x = 0, l = cn.length; x < l; x += 1) {
+ if(cn[x] !== op[0] && cn[x] !== op[1]) { newCn.push(cn[x]); }
+ }
+ newCn.push(css);
+ r.className = newCn.join(" ");
+ }
+};
+
+TableKit.Sortable = {
+ init : function(elm, options){
+ var table = $(elm);
+ if(table.tagName !== "TABLE") {
+ return;
+ }
+ TableKit.register(table,Object.extend(options || {},{sortable:true}));
+ var sortFirst;
+ var cells = TableKit.getHeaderCells(table);
+ var op = TableKit.option('noSortClass columnClass sortFirstAscendingClass sortFirstDecendingClass', table.id);
+ cells.each(function(c){
+ c = $(c);
+ if(!c.hasClassName(op.noSortClass)) {
+ Event.observe(c, 'mousedown', TableKit.Sortable._sort);
+ c.addClassName(op.columnClass);
+ if(c.hasClassName(op.sortFirstAscendingClass) || c.hasClassName(op.sortFirstDecendingClass)) {
+ sortFirst = c;
+ }
+ }
+ });
+
+ if(sortFirst) {
+ if(sortFirst.hasClassName(op.sortFirstAscendingClass)) {
+ TableKit.Sortable.sort(table, sortFirst, 1);
+ } else {
+ TableKit.Sortable.sort(table, sortFirst, -1);
+ }
+ } else { // just add row stripe classes
+ TableKit.Rows.stripe(table);
+ }
+ },
+ reload : function(table) {
+ table = $(table);
+ var cells = TableKit.getHeaderCells(table);
+ var op = TableKit.option('noSortClass columnClass', table.id);
+ cells.each(function(c){
+ c = $(c);
+ if(!c.hasClassName(op.noSortClass)) {
+ Event.stopObserving(c, 'mousedown', TableKit.Sortable._sort);
+ c.removeClassName(op.columnClass);
+ }
+ });
+ TableKit.Sortable.init(table);
+ },
+ _sort : function(e) {
+ if(TableKit.Resizable._onHandle) {return;}
+ e = TableKit.e(e);
+ Event.stop(e);
+ var cell = Event.element(e);
+ while(!(cell.tagName && cell.tagName.match(/td|th/gi))) {
+ cell = cell.parentNode;
+ }
+ TableKit.Sortable.sort(null, cell);
+ },
+ sort : function(table, index, order) {
+ var cell;
+ if(typeof index === 'number') {
+ if(!table || (table.tagName && table.tagName !== "TABLE")) {
+ return;
+ }
+ table = $(table);
+ index = Math.min(table.rows[0].cells.length, index);
+ index = Math.max(1, index);
+ index -= 1;
+ cell = (table.tHead && table.tHead.rows.length > 0) ? $(table.tHead.rows[table.tHead.rows.length-1].cells[index]) : $(table.rows[0].cells[index]);
+ } else {
+ cell = $(index);
+ table = table ? $(table) : cell.up('table');
+ index = TableKit.getCellIndex(cell);
+ }
+ var op = TableKit.option('noSortClass descendingClass ascendingClass', table.id);
+
+ if(cell.hasClassName(op.noSortClass)) {return;}
+
+ order = order ? order : (cell.hasClassName(op.descendingClass) ? 1 : -1);
+ var rows = TableKit.getBodyRows(table);
+
+ if(cell.hasClassName(op.ascendingClass) || cell.hasClassName(op.descendingClass)) {
+ rows.reverse(); // if it was already sorted we just need to reverse it.
+ } else {
+ var datatype = TableKit.Sortable.getDataType(cell,index,table);
+ var tkst = TableKit.Sortable.types;
+ rows.sort(function(a,b) {
+ return order * tkst[datatype].compare(TableKit.getCellText(a.cells[index]),TableKit.getCellText(b.cells[index]));
+ });
+ }
+ var tb = table.tBodies[0];
+ var tkr = TableKit.Rows;
+ rows.each(function(r,i) {
+ tb.appendChild(r);
+ tkr.addStripeClass(table,r,i);
+ });
+ var hcells = TableKit.getHeaderCells(null, cell);
+ $A(hcells).each(function(c,i){
+ c = $(c);
+ c.removeClassName(op.ascendingClass);
+ c.removeClassName(op.descendingClass);
+ if(index === i) {
+ if(order === 1) {
+ c.removeClassName(op.descendingClass);
+ c.addClassName(op.ascendingClass);
+ } else {
+ c.removeClassName(op.ascendingClass);
+ c.addClassName(op.descendingClass);
+ }
+ }
+ });
+ },
+ types : {},
+ detectors : [],
+ addSortType : function() {
+ $A(arguments).each(function(o){
+ TableKit.Sortable.types[o.name] = o;
+ });
+ },
+ getDataType : function(cell,index,table) {
+ cell = $(cell);
+ index = (index || index === 0) ? index : TableKit.getCellIndex(cell);
+
+ var colcache = TableKit.Sortable._coltypecache;
+ var cache = colcache[table.id] ? colcache[table.id] : (colcache[table.id] = {});
+
+ if(!cache[index]) {
+ var t = '';
+ // first look for a data type id on the heading row cell
+ if(cell.id && TableKit.Sortable.types[cell.id]) {
+ t = cell.id;
+ }
+ t = cell.classNames().detect(function(n){ // then look for a data type classname on the heading row cell
+ return (TableKit.Sortable.types[n]) ? true : false;
+ });
+ if(!t) {
+ var rows = TableKit.getBodyRows(table);
+ cell = rows[0].cells[index]; // grab same index cell from body row to try and match data type
+ t = TableKit.Sortable.detectors.detect(
+ function(d){
+ return TableKit.Sortable.types[d].detect(TableKit.getCellText(cell));
+ });
+ }
+ cache[index] = t;
+ }
+ return cache[index];
+ },
+ _coltypecache : {}
+};
+
+TableKit.Sortable.detectors = $A($w('date-iso date date-eu date-au time currency datasize number casesensitivetext text')); // setting it here because Safari complained when I did it above...
+
+TableKit.Sortable.Type = Class.create();
+TableKit.Sortable.Type.prototype = {
+ initialize : function(name, options){
+ this.name = name;
+ options = Object.extend({
+ normal : function(v){
+ return v;
+ },
+ pattern : /.*/
+ }, options || {});
+ this.normal = options.normal;
+ this.pattern = options.pattern;
+ if(options.compare) {
+ this.compare = options.compare;
+ }
+ if(options.detect) {
+ this.detect = options.detect;
+ }
+ },
+ compare : function(a,b){
+ return TableKit.Sortable.Type.compare(this.normal(a), this.normal(b));
+ },
+ detect : function(v){
+ return this.pattern.test(v);
+ }
+};
+
+TableKit.Sortable.Type.compare = function(a,b) {
+ return a < b ? -1 : a === b ? 0 : 1;
+};
+
+TableKit.Sortable.addSortType(
+ new TableKit.Sortable.Type('number', {
+ pattern : /^[-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?/,
+ normal : function(v) {
+ // This will grab the first thing that looks like a number from a string, so you can use it to order a column of various srings containing numbers.
+ v = parseFloat(v.replace(/^.*?([-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?).*$/,"$1"));
+ return isNaN(v) ? 0 : v;
+ }}),
+ new TableKit.Sortable.Type('text',{
+ normal : function(v) {
+ return v ? v.toLowerCase() : '';
+ }}),
+ new TableKit.Sortable.Type('casesensitivetext',{pattern : /^[A-Z]+$/}),
+ new TableKit.Sortable.Type('datasize',{
+ pattern : /^[-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?\s?[k|m|g|t]b$/i,
+ normal : function(v) {
+ var r = v.match(/^([-+]?[\d]*\.?[\d]+([eE][-+]?[\d]+)?)\s?([k|m|g|t]?b)?/i);
+ var b = r[1] ? Number(r[1]).valueOf() : 0;
+ var m = r[3] ? r[3].substr(0,1).toLowerCase() : '';
+ var result = b;
+ switch(m) {
+ case 'k':
+ result = b * 1024;
+ break;
+ case 'm':
+ result = b * 1024 * 1024;
+ break;
+ case 'g':
+ result = b * 1024 * 1024 * 1024;
+ break;
+ case 't':
+ result = b * 1024 * 1024 * 1024 * 1024;
+ break;
+ }
+ return result;
+ }}),
+ new TableKit.Sortable.Type('date-au',{
+ pattern : /^\d{2}\/\d{2}\/\d{4}\s?(?:\d{1,2}\:\d{2}(?:\:\d{2})?\s?[a|p]?m?)?/i,
+ normal : function(v) {
+ if(!this.pattern.test(v)) {return 0;}
+ var r = v.match(/^(\d{2})\/(\d{2})\/(\d{4})\s?(?:(\d{1,2})\:(\d{2})(?:\:(\d{2}))?\s?([a|p]?m?))?/i);
+ var yr_num = r[3];
+ var mo_num = parseInt(r[2],10)-1;
+ var day_num = r[1];
+ var hr_num = r[4] ? r[4] : 0;
+ if(r[7] && r[7].toLowerCase().indexOf('p') !== -1) {
+ hr_num = parseInt(r[4],10) + 12;
+ }
+ var min_num = r[5] ? r[5] : 0;
+ var sec_num = r[6] ? r[6] : 0;
+ return new Date(yr_num, mo_num, day_num, hr_num, min_num, sec_num, 0).valueOf();
+ }}),
+ new TableKit.Sortable.Type('date-us',{
+ pattern : /^\d{2}\/\d{2}\/\d{4}\s?(?:\d{1,2}\:\d{2}(?:\:\d{2})?\s?[a|p]?m?)?/i,
+ normal : function(v) {
+ if(!this.pattern.test(v)) {return 0;}
+ var r = v.match(/^(\d{2})\/(\d{2})\/(\d{4})\s?(?:(\d{1,2})\:(\d{2})(?:\:(\d{2}))?\s?([a|p]?m?))?/i);
+ var yr_num = r[3];
+ var mo_num = parseInt(r[1],10)-1;
+ var day_num = r[2];
+ var hr_num = r[4] ? r[4] : 0;
+ if(r[7] && r[7].toLowerCase().indexOf('p') !== -1) {
+ hr_num = parseInt(r[4],10) + 12;
+ }
+ var min_num = r[5] ? r[5] : 0;
+ var sec_num = r[6] ? r[6] : 0;
+ return new Date(yr_num, mo_num, day_num, hr_num, min_num, sec_num, 0).valueOf();
+ }}),
+ new TableKit.Sortable.Type('date-eu',{
+ pattern : /^\d{2}-\d{2}-\d{4}/i,
+ normal : function(v) {
+ if(!this.pattern.test(v)) {return 0;}
+ var r = v.match(/^(\d{2})-(\d{2})-(\d{4})/);
+ var yr_num = r[3];
+ var mo_num = parseInt(r[2],10)-1;
+ var day_num = r[1];
+ return new Date(yr_num, mo_num, day_num).valueOf();
+ }}),
+ new TableKit.Sortable.Type('date-iso',{
+ pattern : /[\d]{4}-[\d]{2}-[\d]{2}(?:T[\d]{2}\:[\d]{2}(?:\:[\d]{2}(?:\.[\d]+)?)?(Z|([-+][\d]{2}:[\d]{2})?)?)?/, // 2005-03-26T19:51:34Z
+ normal : function(v) {
+ if(!this.pattern.test(v)) {return 0;}
+ var d = v.match(/([\d]{4})(-([\d]{2})(-([\d]{2})(T([\d]{2}):([\d]{2})(:([\d]{2})(\.([\d]+))?)?(Z|(([-+])([\d]{2}):([\d]{2})))?)?)?)?/);
+ var offset = 0;
+ var date = new Date(d[1], 0, 1);
+ if (d[3]) { date.setMonth(d[3] - 1) ;}
+ if (d[5]) { date.setDate(d[5]); }
+ if (d[7]) { date.setHours(d[7]); }
+ if (d[8]) { date.setMinutes(d[8]); }
+ if (d[10]) { date.setSeconds(d[10]); }
+ if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
+ if (d[14]) {
+ offset = (Number(d[16]) * 60) + Number(d[17]);
+ offset *= ((d[15] === '-') ? 1 : -1);
+ }
+ offset -= date.getTimezoneOffset();
+ if(offset !== 0) {
+ var time = (Number(date) + (offset * 60 * 1000));
+ date.setTime(Number(time));
+ }
+ return date.valueOf();
+ }}),
+ new TableKit.Sortable.Type('date',{
+ pattern: /^(?:sun|mon|tue|wed|thu|fri|sat)\,\s\d{1,2}\s(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\s\d{4}(?:\s\d{2}\:\d{2}(?:\:\d{2})?(?:\sGMT(?:[+-]\d{4})?)?)?/i, //Mon, 18 Dec 1995 17:28:35 GMT
+ compare : function(a,b) { // must be standard javascript date format
+ if(a && b) {
+ return TableKit.Sortable.Type.compare(new Date(a),new Date(b));
+ } else {
+ return TableKit.Sortable.Type.compare(a ? 1 : 0, b ? 1 : 0);
+ }
+ }}),
+ new TableKit.Sortable.Type('time',{
+ pattern : /^\d{1,2}\:\d{2}(?:\:\d{2})?(?:\s[a|p]m)?$/i,
+ compare : function(a,b) {
+ var d = new Date();
+ var ds = d.getMonth() + "/" + d.getDate() + "/" + d.getFullYear() + " ";
+ return TableKit.Sortable.Type.compare(new Date(ds + a),new Date(ds + b));
+ }}),
+ new TableKit.Sortable.Type('currency',{
+ pattern : /^[$£¥\80¤]/, // dollar,pound,yen,euro,generic currency symbol
+ normal : function(v) {
+ return v ? parseFloat(v.replace(/[^-\d\.]/g,'')) : 0;
+ }})
+);
+
+TableKit.Resizable = {
+ init : function(elm, options){
+ var table = $(elm);
+ if(table.tagName !== "TABLE") {return;}
+ TableKit.register(table,Object.extend(options || {},{resizable:true}));
+ var cells = TableKit.getHeaderCells(table);
+ cells.each(function(c){
+ c = $(c);
+ //log ("init on " + c.firstChild.nodeValue);
+ Event.observe(c, 'mouseover', TableKit.Resizable.initDetect);
+ Event.observe(c, 'mouseout', TableKit.Resizable.killDetect);
+ });
+ },
+ reload : function(table) {
+ table = $(table);
+ var cells = TableKit.getHeaderCells(table);
+ cells.each(function(c){
+ c = $(c);
+ Event.stopObserving(c, 'mouseover', TableKit.Resizable.initDetect);
+ Event.stopObserving(c, 'mouseout', TableKit.Resizable.killDetect);
+ });
+ TableKit.Resizable.init(table);
+ },
+ resize : function(table, index, w) {
+ var cell;
+ if(typeof index === 'number') {
+ if(!table || (table.tagName && table.tagName !== "TABLE")) {return;}
+ table = $(table);
+ index = Math.min(table.rows[0].cells.length, index);
+ index = Math.max(1, index);
+ index -= 1;
+ cell = (table.tHead && table.tHead.rows.length > 0) ? $(table.tHead.rows[table.tHead.rows.length-1].cells[index]) : $(table.rows[0].cells[index]);
+ } else {
+ cell = $(index);
+ table = table ? $(table) : cell.up('table');
+ index = TableKit.getCellIndex(cell);
+ }
+ var pad = parseInt(cell.getStyle('paddingLeft'),10) + parseInt(cell.getStyle('paddingRight'),10);
+ w = Math.max(w-pad, TableKit.option('minWidth', table.id)[0]);
+ cell.setStyle({'width' : w + 'px'});
+ },
+ initDetect : function(e) {
+ e = TableKit.e(e);
+ var cell = Event.element(e);
+ Event.observe(cell, 'mousemove', TableKit.Resizable.detectHandle);
+ Event.observe(cell, 'mousedown', TableKit.Resizable.startResize);
+ },
+ detectHandle : function(e) {
+ e = TableKit.e(e);
+ var cell = Event.element(e);
+ if(TableKit.Resizable.pointerPos(cell,Event.pointerX(e),Event.pointerY(e))){
+ cell.addClassName(TableKit.option('resizeOnHandleClass', cell.up('table').id)[0]);
+ TableKit.Resizable._onHandle = true;
+ } else {
+ cell.removeClassName(TableKit.option('resizeOnHandleClass', cell.up('table').id)[0]);
+ TableKit.Resizable._onHandle = false;
+ }
+ },
+ killDetect : function(e) {
+ e = TableKit.e(e);
+ TableKit.Resizable._onHandle = false;
+ var cell = Event.element(e);
+ if (!cell.tagName || cell.tagName != 'TD') return;
+ Event.stopObserving(cell, 'mousemove', TableKit.Resizable.detectHandle);
+ Event.stopObserving(cell, 'mousedown', TableKit.Resizable.startResize);
+ cell.removeClassName(TableKit.option('resizeOnHandleClass', cell.up('table').id)[0]);
+ },
+ startResize : function(e) {
+ e = TableKit.e(e);
+ if(!TableKit.Resizable._onHandle) { return;}
+ var cell = Event.element(e);
+ Event.stopObserving(cell, 'mousemove', TableKit.Resizable.detectHandle);
+ Event.stopObserving(cell, 'mousedown', TableKit.Resizable.startResize);
+ Event.stopObserving(cell, 'mouseout', TableKit.Resizable.killDetect);
+ TableKit.Resizable._cell = cell;
+ var table = cell.up('table');
+ TableKit.Resizable._tbl = table;
+ if(TableKit.option('showHandle', table.id)[0]) {
+ TableKit.Resizable._handle = $(document.createElement('div')).addClassName('resize-handle').setStyle({
+ 'top' : Position.cumulativeOffset(cell)[1] + 'px',
+ 'left' : Event.pointerX(e) + 'px',
+ 'height' : table.getDimensions().height + 'px'
+ });
+ document.body.appendChild(TableKit.Resizable._handle);
+ }
+ Event.observe(document, 'mousemove', TableKit.Resizable.drag);
+ Event.observe(document, 'mouseup', TableKit.Resizable.endResize);
+ Event.stop(e);
+ },
+ endResize : function(e) {
+ e = TableKit.e(e);
+ var cell = TableKit.Resizable._cell;
+ TableKit.Resizable.resize(null, cell, (Event.pointerX(e) - Position.cumulativeOffset(cell)[0]));
+ Event.stopObserving(document, 'mousemove', TableKit.Resizable.drag);
+ Event.stopObserving(document, 'mouseup', TableKit.Resizable.endResize);
+ if(TableKit.option('showHandle', TableKit.Resizable._tbl.id)[0]) {
+ $$('div.resize-handle').each(function(elm){
+ document.body.removeChild(elm);
+ });
+ }
+ Event.observe(cell, 'mouseout', TableKit.Resizable.killDetect);
+ TableKit.Resizable._tbl = TableKit.Resizable._handle = TableKit.Resizable._cell = null;
+ Event.stop(e);
+ },
+ drag : function(e) {
+ e = TableKit.e(e);
+ if(TableKit.Resizable._handle === null) {
+ try {
+ TableKit.Resizable.resize(TableKit.Resizable._tbl, TableKit.Resizable._cell, (Event.pointerX(e) - Position.cumulativeOffset(TableKit.Resizable._cell)[0]));
+ } catch(e) {}
+ } else {
+ TableKit.Resizable._handle.setStyle({'left' : Event.pointerX(e) + 'px'});
+ }
+ return false;
+ },
+ pointerPos : function(element, x, y) {
+ var offset = Position.cumulativeOffset(element);
+ return (y >= offset[1] &&
+ y < offset[1] + element.offsetHeight &&
+ x >= offset[0] + element.offsetWidth - 5 &&
+ x < offset[0] + element.offsetWidth);
+ },
+ _onHandle : false,
+ _cell : null,
+ _tbl : null,
+ _handle : null
+};
+
+
+TableKit.Editable = {
+ init : function(elm, options){
+ var table = $(elm);
+ if(table.tagName !== "TABLE") {return;}
+ TableKit.register(table,Object.extend(options || {},{editable:true}));
+ Event.observe(table.tBodies[0], 'click', TableKit.Editable._editCell);
+ },
+ _editCell : function(e) {
+ e = TableKit.e(e);
+ var cell = Event.findElement(e,'td');
+ TableKit.Editable.editCell(null, cell);
+ },
+ editCell : function(table, index, cindex) {
+ var cell, row;
+ if(typeof index === 'number') {
+ if(!table || (table.tagName && table.tagName !== "TABLE")) {return;}
+ table = $(table);
+ index = Math.min(table.tBodies[0].rows.length, index);
+ index = Math.max(1, index);
+ index -= 1;
+ cindex = Math.min(table.rows[0].cells.length, cindex);
+ cindex = Math.max(1, cindex);
+ cindex -= 1;
+ row = $(table.tBodies[0].rows[index]);
+ cell = $(row.cells[cindex]);
+ } else {
+ cell = $(index);
+ table = (table && table.tagName && table.tagName !== "TABLE") ? $(table) : cell.up('table');
+ row = cell.up('tr');
+ }
+ var op = TableKit.option('noEditClass', table.id);
+ if(cell.hasClassName(op.noEditClass)) {return;}
+
+ var head = $(TableKit.getHeaderCells(table, cell)[TableKit.getCellIndex(cell)]);
+ if(head.hasClassName(op.noEditClass)) {return;}
+
+ TableKit.registerCell(cell);
+ var data = TableKit.cells[cell.id];
+ if(data.active) {return;}
+ data.htmlContent = cell.innerHTML;
+ var ftype = TableKit.Editable.types['text-input'];
+ if(head.id && TableKit.Editable.types[head.id]) {
+ ftype = TableKit.Editable.types[head.id];
+ } else {
+ var n = head.classNames().detect(function(n){
+ return (TableKit.Editable.types[n]) ? true : false;
+ });
+ ftype = n ? TableKit.Editable.types[n] : ftype;
+ }
+ ftype.edit(cell);
+ data.active = true;
+ },
+ types : {},
+ addCellEditor : function(o) {
+ if(o && o.name) { TableKit.Editable.types[o.name] = o; }
+ }
+};
+
+TableKit.Editable.CellEditor = Class.create();
+TableKit.Editable.CellEditor.prototype = {
+ initialize : function(name, options){
+ this.name = name;
+ this.options = Object.extend({
+ element : 'input',
+ attributes : {name : 'value', type : 'text'},
+ selectOptions : [],
+ showSubmit : true,
+ submitText : 'OK',
+ showCancel : true,
+ cancelText : 'Cancel',
+ ajaxURI : null,
+ ajaxOptions : null
+ }, options || {});
+ },
+ edit : function(cell) {
+ cell = $(cell);
+ var op = this.options;
+ var table = cell.up('table');
+
+ var form = $(document.createElement("form"));
+ form.id = cell.id + '-form';
+ form.addClassName(TableKit.option('formClassName', table.id)[0]);
+ form.onsubmit = this._submit.bindAsEventListener(this);
+
+ var field = document.createElement(op.element);
+ $H(op.attributes).each(function(v){
+ field[v.key] = v.value;
+ });
+ switch(op.element) {
+ case 'input':
+ case 'textarea':
+ field.value = TableKit.getCellText(cell);
+ break;
+
+ case 'select':
+ var txt = TableKit.getCellText(cell);
+ $A(op.selectOptions).each(function(v){
+ field.options[field.options.length] = new Option(v[0], v[1]);
+ if(txt === v[1]) {
+ field.options[field.options.length-1].selected = 'selected';
+ }
+ });
+ break;
+ }
+ form.appendChild(field);
+ if(op.element === 'textarea') {
+ form.appendChild(document.createElement("br"));
+ }
+ if(op.showSubmit) {
+ var okButton = document.createElement("input");
+ okButton.type = "submit";
+ okButton.value = op.submitText;
+ okButton.className = 'editor_ok_button';
+ form.appendChild(okButton);
+ }
+ if(op.showCancel) {
+ var cancelLink = document.createElement("a");
+ cancelLink.href = "#";
+ cancelLink.appendChild(document.createTextNode(op.cancelText));
+ cancelLink.onclick = this._cancel.bindAsEventListener(this);
+ cancelLink.className = 'editor_cancel';
+ form.appendChild(cancelLink);
+ }
+ cell.innerHTML = '';
+ cell.appendChild(form);
+ },
+ _submit : function(e) {
+ var cell = Event.findElement(e,'td');
+ var form = Event.findElement(e,'form');
+ Event.stop(e);
+ this.submit(cell,form);
+ },
+ submit : function(cell, form) {
+ var op = this.options;
+ form = form ? form : cell.down('form');
+ var head = $(TableKit.getHeaderCells(null, cell)[TableKit.getCellIndex(cell)]);
+ var row = cell.up('tr');
+ var table = cell.up('table');
+ var s = '&row=' + (TableKit.getRowIndex(row)+1) + '&cell=' + (TableKit.getCellIndex(cell)+1) + '&id=' + row.id + '&field=' + head.id + '&' + Form.serialize(form);
+ this.ajax = new Ajax.Updater(cell, op.ajaxURI || TableKit.option('editAjaxURI', table.id)[0], Object.extend(op.ajaxOptions || TableKit.option('editAjaxOptions', table.id)[0], {
+ postBody : s,
+ onComplete : function() {
+ var data = TableKit.cells[cell.id];
+ data.active = false;
+ data.refresh = true; // mark cell cache for refreshing, in case cell contents has changed and sorting is applied
+ }
+ }));
+ },
+ _cancel : function(e) {
+ var cell = Event.findElement(e,'td');
+ Event.stop(e);
+ this.cancel(cell);
+ },
+ cancel : function(cell) {
+ this.ajax = null;
+ var data = TableKit.cells[cell.id];
+ cell.innerHTML = data.htmlContent;
+ data.htmlContent = '';
+ data.active = false;
+ },
+ ajax : null
+};
+
+TableKit.Editable.textInput = function(n,attributes) {
+ TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {
+ element : 'input',
+ attributes : Object.extend({name : 'value', type : 'text'}, attributes||{})
+ }));
+};
+TableKit.Editable.textInput('text-input');
+
+TableKit.Editable.multiLineInput = function(n,attributes) {
+ TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {
+ element : 'textarea',
+ attributes : Object.extend({name : 'value', rows : '5', cols : '20'}, attributes||{})
+ }));
+};
+TableKit.Editable.multiLineInput('multi-line-input');
+
+TableKit.Editable.selectInput = function(n,attributes,selectOptions) {
+ TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {
+ element : 'select',
+ attributes : Object.extend({name : 'value'}, attributes||{}),
+ 'selectOptions' : selectOptions
+ }));
+};
+
+/*
+TableKit.Bench = {
+ bench : [],
+ start : function(){
+ TableKit.Bench.bench[0] = new Date().getTime();
+ },
+ end : function(s){
+ TableKit.Bench.bench[1] = new Date().getTime();
+ alert(s + ' ' + ((TableKit.Bench.bench[1]-TableKit.Bench.bench[0])/1000)+' seconds.') //console.log(s + ' ' + ((TableKit.Bench.bench[1]-TableKit.Bench.bench[0])/1000)+' seconds.')
+ TableKit.Bench.bench = [];
+ }
+} */
+
+if(window.FastInit) {
+ FastInit.addOnLoad(TableKit.load);
+} else {
+ Event.observe(window, 'load', TableKit.load);
+}