Add links to download one or all attachments

Also removed the contextual menu over file attachments and changed the
label color when moving over the file attachments.
pull/17/head
Francis Lachapelle 2013-12-20 15:37:01 -05:00
parent dc21c723f6
commit 5f369f201d
11 changed files with 172 additions and 74 deletions

1
NEWS
View File

@ -6,6 +6,7 @@ New features
using SOGoCalendarDefaultReminder
- select multiple files to attach to a message or drag'n'drop files onto the
mail editor; will also now display progress of uploads
- new popup menu to download all attachments of a mail
Enhancements
- we now automatically convert <img src=data...> into file attachments

View File

@ -97,11 +97,11 @@
"Reply-To" = "Reply-To";
"Add address" = "Add address";
"Attachments:" = "Attachments:";
"Open" = "Open";
"Select All" = "Select All";
"Attach Web Page..." = "Attach Web Page...";
"Attach File(s)..." = "Attach File(s)...";
"file" = "file";
"files" = "files";
"to" = "To";
"cc" = "Cc";

View File

@ -163,6 +163,11 @@ static NSArray *infoKeys = nil;
return item;
}
- (NSString *) uid
{
return [[self clientObject] nameInContainer];
}
- (NSArray *) priorityClasses
{
static NSArray *priorities = nil;
@ -382,16 +387,16 @@ static NSArray *infoKeys = nil;
ASSIGN (attachment, newAttachment);
}
- (NSFormatter *) sizeFormatter
{
return [UIxMailSizeFormatter sharedMailSizeFormatter];
}
- (NSDictionary *) attachment
{
return attachment;
}
- (NSFormatter *) sizeFormatter
{
return [UIxMailSizeFormatter sharedMailSizeFormatter];
}
/* from addresses */
- (NSArray *) fromEMails
@ -672,11 +677,6 @@ static NSArray *infoKeys = nil;
return [[self attachmentAttrs] count] > 0 ? YES : NO;
}
- (NSString *) uid
{
return [[self clientObject] nameInContainer];
}
- (id) defaultAction
{
SOGoDraftObject *co;

View File

@ -47,11 +47,12 @@
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserManager.h>
#import <SOGoUI/UIxComponent.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailFolder.h>
#import <SOGoUI/UIxComponent.h>
#import <MailPartViewers/UIxMailRenderingContext.h> // cyclic
#import <MailPartViewers/UIxMailSizeFormatter.h>
#import "WOContext+UIxMailer.h"
@ -60,6 +61,8 @@
id currentAddress;
NSString *shouldAskReceipt;
NSString *matchingIdentityEMail;
NSDictionary *attachment;
NSArray *attachmentAttrs;
}
@end
@ -80,6 +83,8 @@ static NSString *mailETag = nil;
- (void) dealloc
{
[matchingIdentityEMail release];
[attachment release];
[attachmentAttrs release];
[super dealloc];
}
@ -111,6 +116,16 @@ static NSString *mailETag = nil;
[self messageSubject]];
}
- (void) setAttachment: (NSDictionary *) newAttachment
{
ASSIGN (attachment, newAttachment);
}
- (NSDictionary *) attachment
{
return attachment;
}
/* links (DUP to UIxMailPartViewer!) */
- (NSString *) linkToEnvelopeAddress: (NGImap4EnvelopeAddress *) _address
@ -146,6 +161,36 @@ static NSString *mailETag = nil;
return [[[self clientObject] replyToEnvelopeAddresses] count] > 0 ? YES : NO;
}
/* attachment helper */
- (NSArray *) attachmentAttrs
{
if (!attachmentAttrs)
{
ASSIGN (attachmentAttrs, [[self clientObject] fetchFileAttachmentKeys]);
}
return attachmentAttrs;
}
- (BOOL) hasAttachments
{
return [[self attachmentAttrs] count] > 0 ? YES : NO;
}
- (NSFormatter *) sizeFormatter
{
return [UIxMailSizeFormatter sharedMailSizeFormatter];
}
- (NSString *) attachmentsText
{
if ([[self attachmentAttrs] count] > 1)
return [self labelForKey: @"files"];
else
return [self labelForKey: @"file"];
}
/* viewers */
- (id) contentViewerComponent

View File

@ -211,12 +211,6 @@
</ul>
</div>
<div class="menu" id="attachmentMenu">
<ul>
<li id="save_attachment"><var:string label:value="Save Attachment"/></li>
</ul>
</div>
<div id="leftPanel">
<div class="titlediv"><var:string label:value="Folders" /></div>
<div id="folderTreeContent"><!-- space --></div>

View File

@ -9,13 +9,11 @@
const:jsFiles="SOGoAutoCompletion.js"
const:userDefaultsKeys="SOGoMailDisplayRemoteInlineImages"
const:popup="YES">
<script type="text/javascript">
var messageName = '<var:string value="clientObject.relativeImap4Name"/>';
var mailboxName = '/<var:string value="clientObject.container.container.nameInContainer"/>/<var:string value="clientObject.container.nameInContainer"/>';
</script>
<span id="messageContent">
<var:component className="UIxMailView" />
</span>
<script type="text/javascript">
var messageName = '<var:string value="clientObject.relativeImap4Name"/>';
var mailboxName = '/<var:string value="clientObject.container.container.nameInContainer"/>/<var:string value="clientObject.container.nameInContainer"/>';
</script>
<var:component className="UIxMailView" />
<div class="menu" id="addressMenu">
<ul>
<li id="add_to_addressbook"><var:string label:value="Add to Address Book..."/></li>
@ -28,9 +26,4 @@
<li id="save_image"><var:string label:value="Save Image"/></li>
</ul>
</div>
<div class="menu" id="attachmentMenu">
<ul>
<li id="save_attachment"><var:string label:value="Save Attachment"/></li>
</ul>
</div>
</var:component>
</var:component>

View File

@ -5,14 +5,25 @@
xmlns:uix="OGo:uix"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<var:if condition="clientObject.hasAttachment">
<div class="menu" const:id="attachmentsMenu">
<ul>
<li><var:string label:value="Save all"/></li>
<li class="separator"><!-- separator --></li
><var:foreach list="attachmentAttrs" item="attachment">
<li var:data-url="attachment.urlAsAttachment"><img rsrc:src="attachment.gif"/><var:string value="attachment.filename"
/> <span class="muted">(<var:string value="attachment.size" formatter="sizeFormatter"/>)</span></li>
</var:foreach
></ul>
</div>
</var:if>
<span id="messageContent">
<input type="hidden" const:id="shouldAskReceipt" var:value="shouldAskReceipt"/>
<var:if var:condition="mailIsDraft"
><input const:name="editDraftButton" const:id="editDraftButton"
type="button" class="button" label:value="Edit Draft..."
/></var:if>
<input const:name="loadImagesButton" const:id="loadImagesButton"
type="button" class="button" label:value="Load Images"
/>
><a href="#" const:id="editDraftButton" class="button"><span><var:string label:value="Edit Draft..."/></span></a
></var:if>
<a href="#" const:name="loadImagesButton" const:id="loadImagesButton"
class="button"><span><var:string label:value="Load Images"/></span></a>
<table class="mailer_fieldtable">
<tr class="mailer_fieldrow">
<td class="mailer_fieldname" ><var:string label:value="Subject"/>:</td>
@ -93,11 +104,19 @@
</td>
</tr>
</var:if>
<var:if condition="clientObject.hasAttachment">
<tr class="mailer_fieldrow">
<td class="mailer_fieldname"><img rsrc:src="title_attachment_14x14.png"/></td>
<td class="mailer_fieldvalue">
<a href="#" const:id="attachmentsHref"><var:string value="attachmentAttrs.count"/> <var:string value="attachmentsText"/></a>
</td>
</tr>
</var:if>
</table>
<div class="mailer_mailcontent">
<var:component value="contentViewerComponent"
bodyInfo="clientObject.bodyStructure" />
</div>
</span>
</container>

View File

@ -374,21 +374,21 @@ TR.mailer_listcell_regular TD A
}
/* mail viewer */
INPUT#editDraftButton
#editDraftButton
{
position: absolute;
top: 2.5em;
right: 1em;
}
INPUT#loadImagesButton
#loadImagesButton
{
position: absolute;
top: 2.5em;
right: 1em;
}
.popup INPUT#loadImagesButton
.popup #loadImagesButton
{
top: 9.0em;
right: 1em;
@ -434,7 +434,8 @@ DIV.mailer_mailcontent TABLE
}
/* collapsable header */
TD.mailer_fieldname IMG
TD.mailer_fieldname IMG.collapse,
TD.mailer_fieldname IMG.expand
{ cursor: pointer;
padding-right: 5px; }
TD.mailer_fieldvalue SPAN.collapse
@ -577,7 +578,7 @@ DIV.linked_attachment_meta
{
color: #444444;
border-width: 0;
padding: 2px;
padding: 2px 4px;
}
TABLE.linked_attachment_meta
@ -585,6 +586,25 @@ TABLE.linked_attachment_meta
color: #444444;
}
.linked_attachment_body a:hover
{
text-decoration: none;
}
.linked_attachment_body a:hover .linked_attachment_meta
{
background-color: #9ABCD8;
color: #fff;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.linked_attachment_body a:hover .muted
{
color: #fff !important;
}
DIV.linked_attachment_body HR
{
border: 0px;

View File

@ -1357,13 +1357,27 @@ function configureLinksInMessage() {
anchor.observe("contextmenu", onEmailAddressClick);
anchor.writeAttribute("moz-do-not-send", false);
}
else
else if (!anchor.id)
anchor.observe("click", onMessageAnchorClick);
}
var attachments = messageDiv.select ("DIV.linked_attachment_body");
for (var i = 0; i < attachments.length; i++)
$(attachments[i]).observe("contextmenu", onAttachmentClick);
var attachmentsMenu = $("attachmentsMenu");
if (attachmentsMenu) {
var options = attachmentsMenu.select("li");
var callbacks = [];
for (var i = 0; i < options.length; i++) {
if (options[i].className == 'separator')
callbacks.push(null);
else
callbacks.push(saveAttachment);
}
initMenu(attachmentsMenu, callbacks);
$("attachmentsHref").on("click", function (event) {
popupMenu(event, 'attachmentsMenu', this);
preventDefault(event);
return false;
});
}
var images = messageDiv.select("IMG.mailer_imagecontent");
for (var i = 0; i < images.length; i++)
@ -1371,12 +1385,11 @@ function configureLinksInMessage() {
var editDraftButton = $("editDraftButton");
if (editDraftButton)
editDraftButton.observe("click",
onMessageEditDraft.bindAsEventListener(editDraftButton));
editDraftButton.on("click", onMessageEditDraft);
var loadImagesButton = $("loadImagesButton");
if (loadImagesButton)
$(loadImagesButton).observe("click", onMessageLoadImages);
loadImagesButton.on("click", onMessageLoadImages);
configureiCalLinksInMessage();
}
@ -1562,12 +1575,13 @@ function onMessageContentMenu(event) {
}
function onMessageEditDraft(event) {
Event.stop(event);
return openMessageWindowsForSelection("edit", true);
}
function onMessageLoadImages(event) {
loadRemoteImages();
Event.stop(event);
loadRemoteImages();
}
function loadRemoteImages() {
@ -1613,12 +1627,6 @@ function onImageClick(event) {
return false;
}
function onAttachmentClick (event) {
popupMenu (event, 'attachmentMenu', this);
preventDefault (event);
return false;
}
function handleReturnReceipt() {
var input = $("shouldAskReceipt");
if (input) {
@ -1773,13 +1781,29 @@ function saveImage(event) {
window.location.href = urlAsAttachment;
}
function saveAttachment(event) {
var div = document.menuTarget;
var link = div.select ("a").first ();
var url = link.getAttribute("href");
var urlAsAttachment = url.replace(/(\/[^\/]*)$/,"/asAttachment$1");
/* Download a file using a temporary iframe that we delete once the download is started */
function download(url) {
var form = createElement('form', null, 'hidden', { action: url, method: 'GET'});
$(document.body).appendChild(form);
var div = AIM.submit(form);
form.submit();
setTimeout(function () {
form.remove();
div.remove();
}, 2000);
}
window.location.href = urlAsAttachment;
function saveAttachment(event) {
var url = $(this).readAttribute('data-url');
if (url) {
download(url);
}
else {
$(this).up('ul').select('li[data-url]').each(function (item) {
url = $(item).readAttribute('data-url');
download(url);
});
}
}
/* contacts */
@ -2820,7 +2844,6 @@ function getMenus() {
saveAs, null, null,
onMenuDeleteMessage ],
imageMenu: [ saveImage ],
attachmentMenu: [ saveAttachment ],
messageContentMenu: [ onMenuReplyToSender,
onMenuReplyToAll,
onMenuForwardMessage,

View File

@ -251,7 +251,8 @@ DIV.contactSelector DIV.contactList
padding-bottom: .15em;
margin: 0px;
width: auto;
white-space: nowrap; }
white-space: nowrap;
cursor: pointer; }
.menu LI.disabled,
.popuMenu LI.disabled,
@ -283,10 +284,11 @@ UL.choiceMenu LI._chosen:hover
{ list-style-image: url("menu-check-hover.gif"); }
.menu LI:hover,
.menu LI:hover .muted,
.menu LI.selected,
.menu LI.submenu-selected
{ background-color: #9ABCD8;
color: #fff; }
color: #fff !important; }
.menu LI.disabled:hover
{ background-color: inherit; }

View File

@ -1925,7 +1925,7 @@ AIM = {
d.innerHTML = '<iframe class="hidden" src="about:blank" id="'
+ n + '" name="' + n + '" onload="AIM.loaded(\'' + n + '\')"></iframe>';
document.body.appendChild(d);
var i = $(n); // TODO: useful?
var i = $(n);
if (c && typeof(c.onComplete) == 'function')
i.onComplete = c.onComplete;
return n;
@ -1936,27 +1936,28 @@ AIM = {
},
submit: function(f, c) {
AIM.form(f, AIM.frame(c));
var id = AIM.frame(c);
AIM.form(f, id);
if (c && typeof(c.onStart) == 'function')
return c.onStart();
else
return true;
return $(id);
},
loaded: function(id) {
var i = $(id);
var d;
if (i.contentDocument) {
var d = i.contentDocument;
d = i.contentDocument;
}
else if (i.contentWindow) {
var d = i.contentWindow.document;
d = i.contentWindow.document;
}
else {
var d = window.frames[id].document;
d = window.frames[id].document;
}
if (d.location.href == "about:blank")
return;
if (typeof(i.onComplete) == 'function') {
i.onComplete(Element.allTextContent(d.body));
}