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.
This commit is contained in:
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));
}