Initial mail editor
parent
74177e4d04
commit
fb63689573
|
@ -72,9 +72,11 @@
|
|||
|
||||
- (WOResponse *) composeAction
|
||||
{
|
||||
NSString *urlBase, *url, *value, *signature, *nl;
|
||||
NSString *value, *signature, *nl;
|
||||
SOGoDraftObject *newDraftMessage;
|
||||
NSMutableDictionary *headers;
|
||||
NSDictionary *data;
|
||||
NSString *accountName, *mailboxName, *messageName;
|
||||
SOGoDraftsFolder *drafts;
|
||||
id mailTo;
|
||||
BOOL save;
|
||||
|
@ -118,12 +120,16 @@
|
|||
if (save)
|
||||
[newDraftMessage storeInfo];
|
||||
|
||||
urlBase = [newDraftMessage baseURLInContext: context];
|
||||
url = [urlBase composeURLWithAction: @"edit"
|
||||
parameters: nil
|
||||
andHash: NO];
|
||||
accountName = [[self clientObject] nameInContainer];
|
||||
mailboxName = [drafts relativeImap4Name];
|
||||
messageName = [newDraftMessage nameInContainer];
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
accountName, @"accountId",
|
||||
mailboxName, @"mailboxPath",
|
||||
messageName, @"uid", nil];
|
||||
|
||||
return [self redirectToLocation: url];
|
||||
return [self responseWithStatus: 201
|
||||
andString: [data jsonRepresentation]];
|
||||
}
|
||||
|
||||
- (WOResponse *) _performDelegationAction: (SEL) action
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/WOResourceManager+SOGo.h>
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
#import <Mailer/SOGoDraftObject.h>
|
||||
|
@ -83,7 +84,7 @@
|
|||
NSString *sourceFolder;
|
||||
NSString *text;
|
||||
NSMutableArray *fromEMails;
|
||||
NSString *from;
|
||||
NSDictionary *from;
|
||||
SOGoMailFolder *sentFolder;
|
||||
BOOL isHTML;
|
||||
|
||||
|
@ -112,7 +113,8 @@ static NSArray *infoKeys = nil;
|
|||
@"subject", @"to", @"cc", @"bcc",
|
||||
@"from", @"inReplyTo",
|
||||
@"replyTo",
|
||||
@"priority", @"receipt", nil];
|
||||
@"priority", @"receipt",
|
||||
@"content", nil];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
|
@ -217,6 +219,11 @@ static NSArray *infoKeys = nil;
|
|||
return [[ud mailComposeMessageType] isEqualToString: @"html"];
|
||||
}
|
||||
|
||||
- (NSString *) editorClass
|
||||
{
|
||||
return ([self isHTML]? @"ck-editor" : @"plain-text");
|
||||
}
|
||||
|
||||
- (NSString *) itemPriorityText
|
||||
{
|
||||
return [self labelForKey: [NSString stringWithFormat: @"%@", [item lowercaseString]]];
|
||||
|
@ -246,20 +253,21 @@ static NSArray *infoKeys = nil;
|
|||
ASSIGN (from, newFrom);
|
||||
}
|
||||
|
||||
- (NSString *) _emailFromIdentity: (NSDictionary *) identity
|
||||
- (NSDictionary *) _emailFromIdentity: (NSDictionary *) identity
|
||||
{
|
||||
NSString *fullName, *format;
|
||||
static NSArray *keys = nil;
|
||||
|
||||
fullName = [identity objectForKey: @"fullName"];
|
||||
if ([fullName length])
|
||||
format = @"%{fullName} <%{email}>";
|
||||
else
|
||||
format = @"%{email}";
|
||||
if (!keys)
|
||||
{
|
||||
keys = [NSArray arrayWithObjects: @"email", @"fullName", nil];
|
||||
[keys retain];
|
||||
}
|
||||
|
||||
return [identity keysWithFormat: format];
|
||||
return [NSDictionary dictionaryWithObjects: [identity objectsForKeys: keys notFoundMarker: [NSNull null]]
|
||||
forKeys: [NSArray arrayWithObjects: @"email", @"name", nil]];
|
||||
}
|
||||
|
||||
- (NSString *) from
|
||||
- (NSDictionary *) from
|
||||
{
|
||||
NSDictionary *identity;
|
||||
|
||||
|
@ -412,7 +420,7 @@ static NSArray *infoKeys = nil;
|
|||
{
|
||||
NSArray *identities;
|
||||
int count, max;
|
||||
NSString *email;
|
||||
NSDictionary *email;
|
||||
SOGoMailAccount *account;
|
||||
|
||||
if (!fromEMails)
|
||||
|
@ -423,8 +431,7 @@ static NSArray *infoKeys = nil;
|
|||
fromEMails = [[NSMutableArray alloc] initWithCapacity: max];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
email
|
||||
= [self _emailFromIdentity: [identities objectAtIndex: count]];
|
||||
email = [self _emailFromIdentity: [identities objectAtIndex: count]];
|
||||
[fromEMails addObjectUniquely: email];
|
||||
}
|
||||
}
|
||||
|
@ -443,79 +450,91 @@ static NSArray *infoKeys = nil;
|
|||
|
||||
- (NSDictionary *) storeInfo
|
||||
{
|
||||
[self debugWithFormat:@"storing info ..."];
|
||||
return [self dictionaryWithValuesForKeys: infoKeys];
|
||||
WORequest *request;
|
||||
NSDictionary *params, *filteredParams;
|
||||
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
filteredParams = [NSDictionary dictionaryWithObjects: [params objectsForKeys: infoKeys notFoundMarker: [NSNull null]]
|
||||
forKeys: infoKeys];
|
||||
|
||||
[self setTo: [filteredParams objectForKey: @"to"]];
|
||||
[self setCc: [filteredParams objectForKey: @"cc"]];
|
||||
[self setBcc: [filteredParams objectForKey: @"bcc"]];
|
||||
[self setText: [filteredParams objectForKey: @"content"]];
|
||||
|
||||
return filteredParams;
|
||||
}
|
||||
|
||||
/* contacts search */
|
||||
- (NSArray *) contactFolders
|
||||
{
|
||||
SOGoContactFolders *folderContainer;
|
||||
// - (NSArray *) contactFolders
|
||||
// {
|
||||
// SOGoContactFolders *folderContainer;
|
||||
|
||||
folderContainer = (SOGoContactFolders *) [[[self clientObject] lookupUserFolder] privateContacts: @"Contacts"
|
||||
inContext: nil];
|
||||
// folderContainer = (SOGoContactFolders *) [[[self clientObject] lookupUserFolder] privateContacts: @"Contacts"
|
||||
// inContext: nil];
|
||||
|
||||
return [folderContainer subFolders];
|
||||
}
|
||||
// return [folderContainer subFolders];
|
||||
// }
|
||||
|
||||
- (NSArray *) personalContactInfos
|
||||
{
|
||||
SOGoContactFolders *folderContainer;
|
||||
id <SOGoContactFolder> folder;
|
||||
NSArray *contactInfos;
|
||||
// - (NSArray *) personalContactInfos
|
||||
// {
|
||||
// SOGoContactFolders *folderContainer;
|
||||
// id <SOGoContactFolder> folder;
|
||||
// NSArray *contactInfos;
|
||||
|
||||
folderContainer = (SOGoContactFolders *) [[[self clientObject] lookupUserFolder] privateContacts: @"Contacts"
|
||||
inContext: nil];
|
||||
// folderContainer = (SOGoContactFolders *) [[[self clientObject] lookupUserFolder] privateContacts: @"Contacts"
|
||||
// inContext: nil];
|
||||
|
||||
folder = [folderContainer lookupPersonalFolder: @"personal" ignoringRights: YES];
|
||||
// folder = [folderContainer lookupPersonalFolder: @"personal" ignoringRights: YES];
|
||||
|
||||
// If the folder doesn't exist anymore or if the database is down, we
|
||||
// return an empty array.
|
||||
if ([folder isKindOfClass: [NSException class]])
|
||||
return [NSArray array];
|
||||
// // If the folder doesn't exist anymore or if the database is down, we
|
||||
// // return an empty array.
|
||||
// if ([folder isKindOfClass: [NSException class]])
|
||||
// return [NSArray array];
|
||||
|
||||
contactInfos = [folder lookupContactsWithFilter: nil
|
||||
onCriteria: nil
|
||||
sortBy: @"c_cn"
|
||||
ordering: NSOrderedAscending
|
||||
inDomain: nil];
|
||||
// contactInfos = [folder lookupContactsWithFilter: nil
|
||||
// onCriteria: nil
|
||||
// sortBy: @"c_cn"
|
||||
// ordering: NSOrderedAscending
|
||||
// inDomain: nil];
|
||||
|
||||
return contactInfos;
|
||||
}
|
||||
// return contactInfos;
|
||||
// }
|
||||
|
||||
- (void) setCurrentFolder: (id) _currentFolder
|
||||
{
|
||||
ASSIGN (currentFolder, _currentFolder);
|
||||
}
|
||||
// - (void) setCurrentFolder: (id) _currentFolder
|
||||
// {
|
||||
// ASSIGN (currentFolder, _currentFolder);
|
||||
// }
|
||||
|
||||
- (NSString *) currentContactFolderId
|
||||
{
|
||||
return [NSString stringWithFormat: @"/%@", [currentFolder nameInContainer]];
|
||||
}
|
||||
// - (NSString *) currentContactFolderId
|
||||
// {
|
||||
// return [NSString stringWithFormat: @"/%@", [currentFolder nameInContainer]];
|
||||
// }
|
||||
|
||||
- (NSString *) currentContactFolderName
|
||||
{
|
||||
return [currentFolder displayName];
|
||||
}
|
||||
// - (NSString *) currentContactFolderName
|
||||
// {
|
||||
// return [currentFolder displayName];
|
||||
// }
|
||||
|
||||
- (NSString *) currentContactFolderOwner
|
||||
{
|
||||
return [currentFolder ownerInContext: context];
|
||||
}
|
||||
// - (NSString *) currentContactFolderOwner
|
||||
// {
|
||||
// return [currentFolder ownerInContext: context];
|
||||
// }
|
||||
|
||||
- (NSString *) currentContactFolderClass
|
||||
{
|
||||
return ([currentFolder isKindOfClass: [SOGoContactSourceFolder class]]
|
||||
? @"remote" : @"local");
|
||||
}
|
||||
// - (NSString *) currentContactFolderClass
|
||||
// {
|
||||
// return ([currentFolder isKindOfClass: [SOGoContactSourceFolder class]]
|
||||
// ? @"remote" : @"local");
|
||||
// }
|
||||
|
||||
/* requests */
|
||||
|
||||
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
|
||||
inContext: (WOContext*) localContext
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
// - (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
|
||||
// inContext: (WOContext*) localContext
|
||||
// {
|
||||
// return YES;
|
||||
// }
|
||||
|
||||
/* actions */
|
||||
- (NSString *) _fixedFilename: (NSString *) filename
|
||||
|
@ -687,9 +706,12 @@ static NSArray *infoKeys = nil;
|
|||
return [[self attachmentAttrs] count] > 0 ? YES : NO;
|
||||
}
|
||||
|
||||
- (id) defaultAction
|
||||
- (id <WOActionResults>) editAction
|
||||
{
|
||||
id <WOActionResults> response;
|
||||
SOGoDraftObject *co;
|
||||
NSMutableDictionary *data;
|
||||
id value;
|
||||
|
||||
co = [self clientObject];
|
||||
[co fetchInfo];
|
||||
|
@ -698,13 +720,37 @@ static NSArray *infoKeys = nil;
|
|||
[self setSourceUID: [co IMAP4ID]];
|
||||
[self setSourceFolder: [co sourceFolder]];
|
||||
|
||||
return self;
|
||||
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSArray arrayWithObject: [self from]], @"from",
|
||||
[self localeCode], @"locale",
|
||||
text, @"content",
|
||||
nil];
|
||||
if ((value = [self replyTo]))
|
||||
[data setObject: value forKey: @"replyTo"];
|
||||
if ((value = [self to]))
|
||||
[data setObject: value forKey: @"to"];
|
||||
if ((value = [self cc]))
|
||||
[data setObject: value forKey: @"cc"];
|
||||
if ((value = [self bcc]))
|
||||
[data setObject: value forKey: @"bcc"];
|
||||
if ((value = [self subject]))
|
||||
[data setObject: value forKey: @"subject"];
|
||||
if ((value = [self attachmentAttrs]))
|
||||
[data setObject: value forKey: @"attachmentAttrs"];
|
||||
// [self shouldAskReceipt], @"shouldAskReceipt",
|
||||
// [NSNumber numberWithBool: [self mailIsDraft]], @"isDraft",
|
||||
response = [self responseWithStatus: 200
|
||||
andString: [data jsonRepresentation]];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) saveAction
|
||||
- (WOResponse *) saveAction
|
||||
{
|
||||
id result;
|
||||
NSArray *attrs;
|
||||
|
||||
[self setIsHTML: [self isHTML]];
|
||||
result = [self _saveFormInfo];
|
||||
if (!result)
|
||||
{
|
||||
|
@ -713,7 +759,7 @@ static NSArray *infoKeys = nil;
|
|||
if (!result)
|
||||
{
|
||||
attachmentAttrs = nil;
|
||||
NSArray *attrs = [self attachmentAttrs];
|
||||
attrs = [self attachmentAttrs];
|
||||
result = [self responseWithStatus: 200
|
||||
andString: [attrs jsonRepresentation]];
|
||||
}
|
||||
|
@ -790,10 +836,10 @@ static NSArray *infoKeys = nil;
|
|||
co = [self clientObject];
|
||||
|
||||
/* first, save form data */
|
||||
error = [self validateForSend];
|
||||
error = [self _saveFormInfo];
|
||||
if (!error)
|
||||
{
|
||||
error = [self _saveFormInfo];
|
||||
error = [self validateForSend];
|
||||
if (!error)
|
||||
error = [co sendMail];
|
||||
else
|
||||
|
|
|
@ -234,9 +234,9 @@
|
|||
SOGoMailFolder *co;
|
||||
SOGoMailAccount *account;
|
||||
SOGoUserSettings *us;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
NSArray *uids;
|
||||
NSString *value;
|
||||
id uids;
|
||||
NSDictionary *data;
|
||||
BOOL withTrash;
|
||||
NSMutableDictionary *moduleSettings, *threadsCollapsed;
|
||||
|
@ -244,14 +244,14 @@
|
|||
NSMutableArray *mailboxThreadsCollapsed;
|
||||
int i;
|
||||
|
||||
co = [self clientObject];
|
||||
value = [[context request] formValueForKey: @"uid"];
|
||||
withTrash = ![[[context request] formValueForKey: @"withoutTrash"] boolValue];
|
||||
response = nil;
|
||||
request = [context request];
|
||||
co = [self clientObject];
|
||||
data = [[request contentAsString] objectFromJSONString];
|
||||
withTrash = ![[data objectForKey: @"withoutTrash"] boolValue];
|
||||
|
||||
if ([value length] > 0)
|
||||
if ((uids = [data objectForKey: @"uids"]) && [uids isKindOfClass: [NSArray class]] && [uids length] > 0)
|
||||
{
|
||||
uids = [value componentsSeparatedByString: @","];
|
||||
response = (WOResponse *) [co deleteUIDs: uids useTrashFolder: &withTrash inContext: context];
|
||||
if (!response)
|
||||
{
|
||||
|
@ -289,7 +289,8 @@
|
|||
else
|
||||
{
|
||||
response = [self responseWithStatus: 500];
|
||||
[response appendContentString: @"Missing 'uid' parameter."];
|
||||
data = [NSDictionary dictionaryWithObject: @"Missing 'uids' parameter." forKey: @"error"];
|
||||
[response appendContentString: [data jsonRepresentation]];
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/SOGoDraftObject.h>
|
||||
#import <Mailer/SOGoDraftsFolder.h>
|
||||
#import <Mailer/SOGoMailAccount.h>
|
||||
#import <Mailer/SOGoMailFolder.h>
|
||||
#import <MailPartViewers/UIxMailRenderingContext.h> // cyclic
|
||||
|
@ -275,12 +277,13 @@ static NSString *mailETag = nil;
|
|||
|
||||
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
[self formattedDate], @"date",
|
||||
[self messageSubject], @"subject",
|
||||
[self attachmentAttrs], @"attachmentAttrs",
|
||||
[self shouldAskReceipt], @"shouldAskReceipt",
|
||||
[NSNumber numberWithBool: [self mailIsDraft]], @"isDraft",
|
||||
[[self generateResponse] contentAsString], @"content",
|
||||
nil];
|
||||
if ([self messageSubject])
|
||||
[data setObject: [self messageSubject] forKey: @"subject"];
|
||||
if ((addresses = [addressFormatter dictionariesForArray: [co fromEnvelopeAddresses]]))
|
||||
[data setObject: addresses forKey: @"from"];
|
||||
if ((addresses = [addressFormatter dictionariesForArray: [co toEnvelopeAddresses]]))
|
||||
|
@ -292,6 +295,20 @@ static NSString *mailETag = nil;
|
|||
if ((addresses = [addressFormatter dictionariesForArray: [co replyToEnvelopeAddresses]]))
|
||||
[data setObject: addresses forKey: @"reply-to"];
|
||||
|
||||
if ([self mailIsDraft])
|
||||
{
|
||||
SOGoMailAccount *account;
|
||||
SOGoDraftsFolder *folder;
|
||||
SOGoDraftObject *newMail;
|
||||
|
||||
account = [co mailAccountFolder];
|
||||
folder = [account draftsFolderInContext: context];
|
||||
newMail = [folder newDraft];
|
||||
[newMail fetchMailForEditing: co];
|
||||
[newMail storeInfo];
|
||||
[data setObject: [newMail nameInContainer] forKey: @"draftId"];
|
||||
}
|
||||
|
||||
response = [self responseWithStatus: 200
|
||||
andString: [data jsonRepresentation]];
|
||||
|
||||
|
|
|
@ -337,6 +337,10 @@
|
|||
protectedBy = "View";
|
||||
pageName = "UIxMailSearch";
|
||||
};
|
||||
editorTemplate = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxMailEditor";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -388,13 +392,10 @@
|
|||
};
|
||||
};
|
||||
methods = {
|
||||
view = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxMailEditor";
|
||||
};
|
||||
edit = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxMailEditor";
|
||||
actionName = "edit";
|
||||
};
|
||||
save = {
|
||||
protectedBy = "View";
|
||||
|
|
|
@ -1,131 +1,30 @@
|
|||
<?xml version='1.0' standalone='yes'?>
|
||||
<!DOCTYPE var:component>
|
||||
<var:component
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:uix="OGo:uix"
|
||||
xmlns:rsrc="OGo:url"
|
||||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
title="panelTitle"
|
||||
const:popup="YES"
|
||||
const:userDefaultsKeys="SOGoMailComposeMessageType,SOGoMailReplyPlacement,SOGoMailSignature,SOGoMailAutoSave,SOGoDraftsFolderName"
|
||||
const:jsFiles="UIxMailToSelection.js,ckeditor/ckeditor.js,SOGoAutoCompletion.js,ContactsUI.js,jquery-ui.js,jquery.fileupload.js,jquery.iframe-transport.js"
|
||||
const:cssFiles="jquery.fileupload.css">
|
||||
<script type="text/javascript">
|
||||
var mailIsReply = <var:string value="isMailReply"/>;
|
||||
var sourceUID = <var:string value="sourceUID"/>;
|
||||
var sourceFolder = '<var:string value="sourceFolder" const:escapeHTML="NO"/>';
|
||||
var localeCode = '<var:string value="localeCode"/>';
|
||||
</script>
|
||||
|
||||
<div class="popupMenu" id="contactsMenu">
|
||||
<ul><!-- space --></ul>
|
||||
</div>
|
||||
|
||||
<div class="menu" id="optionsMenu">
|
||||
<ul class="choiceMenu">
|
||||
<li><var:string label:value="Return Receipt"/></li>
|
||||
<li><!-- separator --></li>
|
||||
<li><var:string label:value="Priority"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="menu" id="priorityMenu">
|
||||
<ul id="itemPriorityList" class="choiceMenu">
|
||||
<var:foreach list="priorityClasses" item="item">
|
||||
<li var:priority="item"><var:string
|
||||
var:value="itemPriorityText" /></li>
|
||||
</var:foreach>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="contacts" style="display: none;">
|
||||
<div id="leftPanel">
|
||||
<div id="contactsSearch">
|
||||
<label><var:string label:value="Address Book:" /></label>
|
||||
<var:popup const:name="contactFolder" const:id="contactFolder"
|
||||
list="contactFolders"
|
||||
item="currentFolder"
|
||||
string="currentContactFolderName"
|
||||
value="currentContactFolderId"
|
||||
/>
|
||||
<label><var:string label:value="Search For:"/></label>
|
||||
<var:component className="UIxContactsFilterPanel" qualifier="qualifier" />
|
||||
<div id="contactsListContent">
|
||||
<table id="contactsList" cellspacing="0">
|
||||
<thead>
|
||||
<tr class="tableview">
|
||||
<!-- localize -->
|
||||
<td class="tbtv_headercell sortableTableHeader" id="nameHeader"
|
||||
><img id="messageSortImage" class="sortImage" rsrc:src="arrow-up.png"
|
||||
/><var:string label:value="Name"
|
||||
/></td
|
||||
><td class="tbtv_headercell sortableTableHeader" id="mailHeader"
|
||||
><var:string label:value="Email"/></td
|
||||
></tr>
|
||||
</thead>
|
||||
<tbody id="contactsListTbody">
|
||||
|
||||
<var:foreach list="personalContactInfos" item="currentContact">
|
||||
<tr var:class="currentContactClasses"
|
||||
var:categories="currentContact.c_categories"
|
||||
var:id="currentContact.c_name"
|
||||
var:contactname="currentContact.c_cn">
|
||||
<td class="displayName" var:title="currentContact.c_cn"><var:string value="currentContact.c_cn" const:escapeHTML="YES" /></td>
|
||||
<td var:title="currentContact.c_mail"><var:string value="currentContact.c_mail"/></td>
|
||||
</tr>
|
||||
</var:foreach>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="contactSelection">
|
||||
<var:component className="UIxContactsMailerSelection" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dragHandle" id="hiddenDragHandle"><!-- space --></div>
|
||||
</div>
|
||||
|
||||
<div id="rightPanel">
|
||||
<form href="save" name="pageform" enctype="multipart/form-data" autocomplete="off">
|
||||
<input type="hidden" name="priority" id="priority" var:value="priority"/>
|
||||
<input type="hidden" name="receipt" id="receipt" var:value="receipt"/>
|
||||
<input type="hidden" name="isHTML" id="isHTML" var:value="isHTML"/>
|
||||
|
||||
<div id="headerArea">
|
||||
<span class="headerField" const:id="fromField"><var:string label:value="From" />:</span>
|
||||
<var:popup const:name="from" const:id="fromSelect"
|
||||
list="fromEMails"
|
||||
item="item"
|
||||
selection="from"
|
||||
/><br />
|
||||
<div>
|
||||
<var:component className="UIxMailToSelection"
|
||||
to="to" cc="cc" bcc="bcc" />
|
||||
<?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:label="OGo:label"
|
||||
xmlns:uix="OGo:uix"><var:string var:value="doctype" const:escapeHTML="NO" />
|
||||
<div id="messageEditor">
|
||||
<form>
|
||||
<label><var:string label:value="From"/>
|
||||
<select name="from"
|
||||
data-ng-model="message.from"
|
||||
data-ng-options="identity.full as identity.full for identity in identities"><!-- from --></select></label>
|
||||
<label><var:string label:value="To"/>
|
||||
<input type="text" name="to" ng-model="message.to"/></label>
|
||||
<label><var:string label:value="Subject"/>
|
||||
<input type="text" name="subject" ng-model="message.subject"/></label>
|
||||
<textarea name="content" var:class="editorClass" ng-model="message.content"/>
|
||||
<div class="buttonsToolbar">
|
||||
<span>
|
||||
<a class="button tiny radius"
|
||||
data-ng-click="message.$save()"><i class="icon-disk"><!-- send --></i> <var:string label:value="Save"/></a>
|
||||
<a class="button tiny radius"
|
||||
data-ng-click="send(message)"><i class="icon-mail"><!-- send --></i> <var:string label:value="Send"/></a>
|
||||
</span>
|
||||
</div>
|
||||
<div id="subjectRow">
|
||||
<span class="headerField"><var:string label:value="Subject"/>:</span>
|
||||
<input name="subject" type="text" class="textField" var:value="subject"/>
|
||||
</div>
|
||||
<div id="fileupload">
|
||||
<ul id="attachments">
|
||||
<li class="attachButton"><span class="button fileinput-button"><span><img rsrc:src="title_attachment_14x14.png" /> <var:string label:value="Attach"/></span><input id="fileUpload" type="file" name="attachments" tabindex="-1" multiple="multiple"/></span></li>
|
||||
<var:foreach list="attachmentAttrs" item="attachment"
|
||||
><li class="progressDone" var:data-filename="attachment.filename">
|
||||
<i class="icon-attachment"><!-- icon --></i><a var:href="attachment.url" target="_new"><var:string value="attachment.filename"/></a><span class="muted">(<var:string value="attachment.size" formatter="sizeFormatter" />)</span>
|
||||
</li></var:foreach>
|
||||
</ul>
|
||||
</div>
|
||||
</div><!-- #headerArea -->
|
||||
<textarea id="text" name="text" rows="25" style="display:none" var:value="text"/>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="dropZone" style="display: none;"><!-- dropzone --></div>
|
||||
</var:component>
|
||||
</container>
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
title="title"
|
||||
const:userDefaultsKeys="SOGoMailMessageCheck,SOGoRefreshViewCheck,SOGoMailSortByThreads,SOGoMailListViewColumnsOrder,SOGoMailDisplayRemoteInlineImages"
|
||||
const:userDefaultsKeys="SOGoMailMessageCheck,SOGoRefreshViewCheck,SOGoMailSortByThreads,SOGoMailListViewColumnsOrder,SOGoMailDisplayRemoteInlineImages,SOGoMailComposeMessageType,SOGoMailReplyPlacement"
|
||||
const:userSettingsKeys="Mail"
|
||||
const:jsFiles="Common/resource.js, Mailer/message-model.js, Mailer/mailbox-model.js, Mailer/account-model.js">
|
||||
const:jsFiles="Common/resource.js, Mailer/message-model.js, Mailer/mailbox-model.js, Mailer/account-model.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js">
|
||||
<script type="text/javascript">
|
||||
var mailAccounts = <var:string value="mailAccounts" const:escapeHTML="NO"/>;
|
||||
var userNames = <var:string value="userNames" const:escapeHTML="NO" />;
|
||||
|
@ -234,13 +234,36 @@
|
|||
</div>
|
||||
|
||||
<div id="mailboxesList" class="folders-list">
|
||||
<ul data-ng-repeat="account in accounts">
|
||||
<li><label>{{account.name}}</label></li>
|
||||
<sg-folder-tree data-ng-repeat="folder in account.$mailboxes track by folder.id"
|
||||
data-sg-root="account"
|
||||
data-sg-folder="folder"
|
||||
data-sg-set-folder="setCurrentFolder"><!-- tree --></sg-folder-tree>
|
||||
</ul>
|
||||
<div class="newItemsToolbar">
|
||||
<a class="button tiny radius split" data-ui-sref="mail.newMessage()"><var:string label:value="Compose"/><span data-dropdown-toggle="#draftsDrop"></span></a><br/>
|
||||
</div>
|
||||
<div class="scrollView">
|
||||
<ul data-ng-repeat="account in accounts track by account.id">
|
||||
<li><label>{{account.name}}</label></li>
|
||||
<li data-ng-repeat="folder in account.$flattenMailboxes() track by folder.path"
|
||||
data-ng-class="{_selected: folder.id == currentFolder.id}"
|
||||
data-ng-click="setCurrentFolder(account, folder)">
|
||||
<span class="folder-container">
|
||||
<span class="folder-content">
|
||||
<i class="icon icon-ion-folder"
|
||||
data-ng-class="'childLevel' + folder.level"><!-- folder --></i>
|
||||
<form>
|
||||
<a data-ng-cloak="ng-cloak">{{folder.name}}</a>
|
||||
</form>
|
||||
<span class="icon ng-hide" data-ng-cloak="ng-cloak">
|
||||
<a class="icon" href="#"
|
||||
data-dropdown-toggle="#folderProperties"
|
||||
data-options="align:right"><i class="icon-cog"><!-- options --></i></a>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
<!--<sg-folder-tree data-ng-repeat="folder in account.$mailboxes track by folder.id"
|
||||
data-sg-root="account"
|
||||
data-sg-folder="folder"
|
||||
data-sg-set-folder="setCurrentFolder"> tree </sg-folder-tree>-->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div data-ui-view="mailbox"><!-- messages list --></div>
|
||||
</script>
|
||||
|
@ -249,7 +272,7 @@
|
|||
<div id="messagesList">
|
||||
<ul data-vs-repeat="56"
|
||||
data-vs-scroll-parent="#messagesList">
|
||||
<li ng-repeat="currentMessage in mailbox.$messages"
|
||||
<li ng-repeat="currentMessage in mailbox.$messages track by currentMessage.id"
|
||||
data-ng-class="{unread: !currentMessage.isread, _selected: message.id == currentMessage.id}">
|
||||
<a data-ui-sref="mail.account.mailbox.message({accountId: account.id, mailboxId: (mailbox.path | encodeUri), messageId: currentMessage.uid})">
|
||||
<div class="name">
|
||||
|
@ -284,14 +307,15 @@
|
|||
<div class="buttonsToolbar">
|
||||
<span>
|
||||
<a class="button tiny radius"
|
||||
data-ui-sref="mail.account.mailbox.messageEditor({accountId: account.id, mailboxId: (mailbox.path | encodeUri), messageId: message.uid})"
|
||||
data-ui-sref="mail.account.mailbox.message.editMessage({accountId: account.id, mailboxId: (mailbox.path | encodeUri), messageId: message.uid})"
|
||||
data-ng-show="message.isDraft"><i class="icon-pencil"><!-- edit --></i></a>
|
||||
<span class="button tiny radius alert"
|
||||
data-ng-click="delete(message)"><i class="icon-trash"><!-- delete --></i></span>
|
||||
data-ng-click="doDelete(message)"><i class="icon-trash"><!-- delete --></i></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mailer_mailcontent"
|
||||
data-ng-bind-html="message.$content()"><!-- msg --></div>
|
||||
</script>
|
||||
|
||||
</var:component>
|
||||
|
|
|
@ -12,7 +12,13 @@
|
|||
// Data is immediately available
|
||||
if (typeof futureAccountData.then !== 'function') {
|
||||
angular.extend(this, futureAccountData);
|
||||
Account.$log.debug('Account:' + JSON.stringify(futureAccountData, undefined, 2));
|
||||
_.each(this.identities, function(identity) {
|
||||
if (identity.fullName)
|
||||
identity.full = identity.fullName + ' <' + identity.email + '>';
|
||||
else
|
||||
identity.full = '<' + identity.email + '>';
|
||||
});
|
||||
Account.$log.debug('Account: ' + JSON.stringify(futureAccountData, undefined, 2));
|
||||
}
|
||||
else {
|
||||
// The promise will be unwrapped first
|
||||
|
@ -25,13 +31,14 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the Account constructor
|
||||
*/
|
||||
Account.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgMailbox', function($q, $timeout, $log, Settings, Resource, Mailbox) {
|
||||
Account.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgMailbox', 'sgMessage', function($q, $timeout, $log, Settings, Resource, Mailbox, Message) {
|
||||
angular.extend(Account, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
$log: $log,
|
||||
$$resource: new Resource(Settings.baseURL, Settings.activeUser),
|
||||
$Mailbox: Mailbox
|
||||
$Mailbox: Mailbox,
|
||||
$Message: Message
|
||||
});
|
||||
|
||||
return Account; // return constructor
|
||||
|
@ -66,13 +73,95 @@
|
|||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Account.prototype.$getMailboxes = function() {
|
||||
var _this = this;
|
||||
var _this = this,
|
||||
deferred = Account.$q.defer();
|
||||
|
||||
var mailboxes = Account.$Mailbox.$find(this).then(function(data) {
|
||||
_this.$mailboxes = data;
|
||||
if (this.$mailboxes) {
|
||||
deferred.resolve(this.$mailboxes);
|
||||
}
|
||||
else {
|
||||
Account.$Mailbox.$find(this).then(function(data) {
|
||||
_this.$mailboxes = data;
|
||||
deferred.resolve(_this.$mailboxes);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Account.prototype.$flattenMailboxes = function() {
|
||||
var _this = this,
|
||||
allMailboxes = [],
|
||||
_visit = function(level, mailboxes) {
|
||||
_.each(mailboxes, function(o) {
|
||||
allMailboxes.push({ id: o.id, path: o.path, name: o.name, level: level });
|
||||
if (o.children && o.children.length > 0) {
|
||||
_visit(level+1, o.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (this.$$flattenMailboxes) {
|
||||
allMailboxes = this.$$flattenMailboxes;
|
||||
}
|
||||
else {
|
||||
_visit(0, this.$mailboxes);
|
||||
_this.$$flattenMailboxes = allMailboxes;
|
||||
}
|
||||
|
||||
return allMailboxes;
|
||||
};
|
||||
|
||||
Account.prototype.$getMailboxByType = function(type) {
|
||||
var mailbox,
|
||||
// Recursive find function
|
||||
_find = function(mailboxes) {
|
||||
var mailbox = _.find(mailboxes, function(o) {
|
||||
return o.type == type;
|
||||
});
|
||||
if (!mailbox) {
|
||||
angular.forEach(mailboxes, function(o) {
|
||||
if (!mailbox && o.children && o.children.length > 0) {
|
||||
mailbox = _find(o.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
return mailbox;
|
||||
};
|
||||
mailbox = _find(this.mailboxes);
|
||||
|
||||
console.debug(mailbox);
|
||||
console.debug(this.specialMailboxes);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $newMessage
|
||||
* @memberof Account.prototype
|
||||
* @desc Prepare a new Message object associated to the appropriate mailbox.
|
||||
* @returns a promise of the HTTP operations
|
||||
*/
|
||||
Account.prototype.$newMessage = function() {
|
||||
var _this = this,
|
||||
deferred = Account.$q.defer(),
|
||||
message;
|
||||
|
||||
// Query account for draft folder and draft UID
|
||||
Account.$$resource.fetch(this.id, 'compose').then(function(data) {
|
||||
message = new Account.$Message(data.accountId, data.mailboxPath, data);
|
||||
// Fetch draft initial data
|
||||
Account.$$resource.fetch(message.id, 'edit').then(function(data) {
|
||||
Account.$log.debug('New message: ' + JSON.stringify(data, undefined, 2));
|
||||
angular.extend(message, data);
|
||||
message.$formatFullAddresses();
|
||||
deferred.resolve(message);
|
||||
}, function(data) {
|
||||
deferred.reject(data);
|
||||
});
|
||||
}, function(data) {
|
||||
deferred.reject(data);
|
||||
});
|
||||
|
||||
return mailboxes;
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -75,13 +75,13 @@
|
|||
* @memberof Mailbox
|
||||
* @desc Fetch list of mailboxes of a specific account
|
||||
* @param {string} accountId - the account
|
||||
* @return a promise of the HTTP operation
|
||||
* @see {@link Account.$getMailboxes}
|
||||
*/
|
||||
Mailbox.$find = function(account) {
|
||||
var path, futureMailboxData;
|
||||
|
||||
path = Mailbox.$absolutePath(account.id);
|
||||
futureMailboxData = this.$$resource.post(path, 'view', {sortingAttributes: {sort: 'date', asc: false}});
|
||||
futureMailboxData = this.$$resource.post(account.id, 'view', {sortingAttributes: {sort: 'date', asc: false}});
|
||||
|
||||
return Mailbox.$unwrapCollection(account, futureMailboxData); // a collection of mailboxes
|
||||
};
|
||||
|
@ -206,7 +206,17 @@
|
|||
}
|
||||
return loaded;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @function $deleteMessages
|
||||
* @memberof Mailbox.prototype
|
||||
* @desc Delete multiple messages from mailbox.
|
||||
* @return a promise of the HTTP operation
|
||||
*/
|
||||
Mailbox.prototype.$deleteMessages = function(uids) {
|
||||
return Mailbox.$$resource.post(this.id, 'batchDelete', {uids: uids});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $omit
|
||||
* @memberof Mailbox.prototype
|
||||
|
|
|
@ -107,21 +107,50 @@
|
|||
/**
|
||||
* @function $content
|
||||
* @memberof Message.prototype
|
||||
* @desc Fetch the message body along with other metadata such as the list of attachments.
|
||||
* @returns the HTML representation of the body or a promise of the HTTP operation
|
||||
* @desc Get the message body as accepted by SCE (Angular Strict Contextual Escaping).
|
||||
* @returns the HTML representation of the body
|
||||
*/
|
||||
Message.prototype.$content = function() {
|
||||
var futureMessageData;
|
||||
return Message.$sce.trustAs('html', this.content);
|
||||
};
|
||||
|
||||
if (this.$futureMessageData) {
|
||||
return Message.$sce.trustAs('html', this.content);
|
||||
}
|
||||
/**
|
||||
* @function $update
|
||||
* @memberof Message.prototype
|
||||
* @desc Fetch the message body along with other metadata such as the list of attachments.
|
||||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Message.prototype.$update = function() {
|
||||
var futureMessageData;
|
||||
|
||||
futureMessageData = Message.$$resource.fetch(this.id, 'view');
|
||||
|
||||
return this.$unwrap(futureMessageData);
|
||||
};
|
||||
|
||||
Message.prototype.$save = function() {
|
||||
var data = this.$omit();
|
||||
Message.$log.debug(JSON.stringify(data, undefined, 2));
|
||||
|
||||
return Message.$$resource.save(this.$absolutePath({asDraft: true}), data);
|
||||
};
|
||||
|
||||
Message.prototype.$send = function() {
|
||||
var data = this.$omit(),
|
||||
deferred = Message.$q.defer();
|
||||
|
||||
Message.$$resource.post(this.$absolutePath({asDraft: true}), 'send', data).then(function(data) {
|
||||
if (data.status == 'success') {
|
||||
deferred.resolve(data);
|
||||
}
|
||||
else {
|
||||
deferred.reject(data);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $unwrap
|
||||
* @memberof Message.prototype
|
||||
|
@ -154,4 +183,28 @@
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $omit
|
||||
* @memberof Message.prototype
|
||||
* @desc Return a sanitized object used to send to the server.
|
||||
* @return an object literal copy of the Message instance
|
||||
*/
|
||||
Message.prototype.$omit = function() {
|
||||
var message = {};
|
||||
angular.forEach(this, function(value, key) {
|
||||
if (key != 'constructor' && key[0] != '$') {
|
||||
message[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// Format addresses as arrays
|
||||
_.each(['from', 'to', 'cc', 'bcc', 'reply-to'], function(type) {
|
||||
if (message[type])
|
||||
message[type] = _.invoke(message[type].split(','), 'trim');
|
||||
});
|
||||
|
||||
//Message.$log.debug(JSON.stringify(message, undefined, 2));
|
||||
return message;
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
angular.module('SOGo.Common', []);
|
||||
|
||||
angular.module('SOGo.MailerUI', ['ngSanitize', 'ui.router', 'mm.foundation', 'vs-repeat', 'SOGo.Common', 'SOGo.UICommon', 'SOGo.UIDesktop'])
|
||||
angular.module('SOGo.MailerUI', ['ngSanitize', 'ui.router', 'mm.foundation', 'vs-repeat', 'ck', 'SOGo.Common', 'SOGo.UICommon', 'SOGo.UIDesktop'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
|
@ -34,9 +34,7 @@
|
|||
var promises = [];
|
||||
// Fetch list of mailboxes for each account
|
||||
angular.forEach(accounts, function(account, i) {
|
||||
console.debug(i);
|
||||
var mailboxes = account.$getMailboxes();
|
||||
console.debug(mailboxes);
|
||||
promises.push(mailboxes.then(function(objects) {
|
||||
return account;
|
||||
}));
|
||||
|
@ -90,10 +88,10 @@
|
|||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message', {
|
||||
url: "/:messageId",
|
||||
url: '/:messageId',
|
||||
views: {
|
||||
message: {
|
||||
templateUrl: "message.html",
|
||||
templateUrl: 'message.html',
|
||||
controller: 'MessageCtrl'
|
||||
}
|
||||
},
|
||||
|
@ -102,25 +100,47 @@
|
|||
var message = _.find(stateMessages, function(messageObject) {
|
||||
return messageObject.uid == $stateParams.messageId;
|
||||
});
|
||||
return message;
|
||||
|
||||
return message.$update();
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message.editMessage', {
|
||||
url: '/edit',
|
||||
views: {
|
||||
'mailbox@mail': {
|
||||
templateUrl: 'editorTemplate', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorCtrl'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('mail.newMessage', {
|
||||
url: '/new',
|
||||
views: {
|
||||
mailbox: {
|
||||
templateUrl: 'editorTemplate', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateMessage: ['stateAccounts', function(stateAccounts) {
|
||||
if (stateAccounts.length > 0) {
|
||||
return stateAccounts[0].$newMessage();
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
// .state('mailbox.newMessage', {
|
||||
// url: "/new",
|
||||
// templateUrl: "messageEditor.html",
|
||||
// controller: 'MessageCtrl'
|
||||
// })
|
||||
// .state('mailbox.editMessage', {
|
||||
// url: "/:messageId/edit",
|
||||
// templateUrl: "messageEditor.html",
|
||||
// controller: 'MessageCtrl'
|
||||
// });
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/Mail');
|
||||
}])
|
||||
|
||||
.run(function($rootScope) {
|
||||
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
|
||||
console.log(event, current, previous, rejection)
|
||||
})
|
||||
})
|
||||
|
||||
.directive('sgFocusOn', function() {
|
||||
return function(scope, elem, attr) {
|
||||
scope.$on('sgFocusOn', function(e, name) {
|
||||
|
@ -166,7 +186,7 @@
|
|||
});
|
||||
};
|
||||
|
||||
if (_.isEmpty($state.params) && $scope.accounts.length > 0 && $scope.accounts[0].$mailboxes.length > 0) {
|
||||
if ($state.current.name == 'mail' && $scope.accounts.length > 0 && $scope.accounts[0].$mailboxes.length > 0) {
|
||||
var account = $scope.accounts[0];
|
||||
var mailbox = account.$mailboxes[0];
|
||||
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(mailbox.path) });
|
||||
|
@ -182,8 +202,38 @@
|
|||
});
|
||||
}])
|
||||
|
||||
.controller('MessageCtrl', ['$scope', '$rootScope', '$stateParams', 'stateMessage', '$timeout', '$modal', 'sgFocus', 'sgDialog', 'sgAccount', 'sgMailbox', function($scope, $rootScope, $stateParams, stateMessage, $timeout, $modal, focus, Dialog, Account, Mailbox) {
|
||||
.controller('MessageCtrl', ['$scope', '$rootScope', '$stateParams', '$state', 'stateAccount', 'stateMailbox', 'stateMessage', '$timeout', '$modal', 'encodeUriFilter', 'sgFocus', 'sgDialog', 'sgAccount', 'sgMailbox', function($scope, $rootScope, $stateParams, $state, stateAccount, stateMailbox, stateMessage, $timeout, $modal, encodeUriFilter, focus, Dialog, Account, Mailbox) {
|
||||
$rootScope.message = stateMessage;
|
||||
$scope.doDelete = function() {
|
||||
stateMailbox.$deleteMessages([stateMessage.uid]).then(function() {
|
||||
// Remove card from list of addressbook
|
||||
stateMailbox.$messages = _.reject(stateMailbox.$messages, function(o) {
|
||||
return o.uid == stateMessage.uid;
|
||||
});
|
||||
// Remove card object from scope
|
||||
$rootScope.message = null;
|
||||
$state.go('mail.account.mailbox', { accountId: stateAccount.id, mailboxId: encodeUriFilter(stateMailbox.path) });
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('MessageEditorCtrl', ['$scope', '$rootScope', '$stateParams', 'stateAccounts', 'stateMessage', '$timeout', '$modal', 'sgFocus', 'sgDialog', 'sgAccount', 'sgMailbox', function($scope, $rootScope, $stateParams, stateAccounts, stateMessage, $timeout, $modal, focus, Dialog, Account, Mailbox) {
|
||||
if (angular.isDefined(stateMessage)) {
|
||||
$scope.message = stateMessage;
|
||||
// Flatten addresses as strings
|
||||
_.each(['from', 'to', 'cc', 'bcc', 'reply-to'], function(type) {
|
||||
if ($scope.message[type])
|
||||
$scope.message[type] = _.pluck($scope.message[type], 'full').join(', ');
|
||||
});
|
||||
}
|
||||
$scope.identities = _.flatten(_.pluck(stateAccounts, 'identities'));
|
||||
$scope.send = function(message) {
|
||||
message.$send().then(function(data) {
|
||||
console.debug('success ' + JSON.stringify(data, undefined, 2));
|
||||
}, function(data) {
|
||||
console.debug('failure ' + JSON.stringify(data, undefined, 2));
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
})();
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for CKEditor module */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('ck', []).directive('ckEditor', function() {
|
||||
var calledEarly, loaded;
|
||||
loaded = false;
|
||||
calledEarly = false;
|
||||
|
||||
return {
|
||||
restrict: 'C',
|
||||
require: '?ngModel',
|
||||
compile: function(element, attributes, transclude) {
|
||||
var loadIt, local;
|
||||
|
||||
local = this;
|
||||
loadIt = function() {
|
||||
return calledEarly = true;
|
||||
};
|
||||
|
||||
element.ready(function() {
|
||||
return loadIt();
|
||||
});
|
||||
|
||||
return {
|
||||
post: function($scope, element, attributes, controller) {
|
||||
if (calledEarly) {
|
||||
return local.link($scope, element, attributes, controller);
|
||||
}
|
||||
loadIt = (function($scope, element, attributes, controller) {
|
||||
return function() {
|
||||
local.link($scope, element, attributes, controller);
|
||||
};
|
||||
})($scope, element, attributes, controller);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
link: function($scope, elm, attr, ngModel) {
|
||||
var ck;
|
||||
if (!ngModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (calledEarly && !loaded) {
|
||||
return loaded = true;
|
||||
}
|
||||
loaded = false;
|
||||
|
||||
ck = CKEDITOR.replace(elm[0]);
|
||||
ck.on('pasteState', function() {
|
||||
$scope.$apply(function() {
|
||||
ngModel.$setViewValue(ck.getData());
|
||||
});
|
||||
});
|
||||
|
||||
ngModel.$render = function(value) {
|
||||
ck.setData(ngModel.$viewValue);
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
})();
|
|
@ -348,6 +348,9 @@ $column-gutter: 0;
|
|||
}
|
||||
#messageEditor {
|
||||
right: 0;
|
||||
textarea {
|
||||
height: 20em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue