parent
cc6fcc5fbd
commit
b5949752b4
1
NEWS
1
NEWS
|
@ -9,6 +9,7 @@ Enhancements
|
|||
- [web] add Indonesian (id) translation
|
||||
- [web] updated Angular Material to version 1.1.19
|
||||
- [web] replaced bower packages by npm packages
|
||||
- [web] restored mail threads (#3478, #4616, #4735)
|
||||
|
||||
Bug fixes
|
||||
- [web] fixed wrong translation of custom calendar categories
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSURL.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
@ -221,16 +222,30 @@
|
|||
|
||||
- (void) collapseAction: (BOOL) isCollapsing
|
||||
{
|
||||
WORequest *request;
|
||||
NSMutableDictionary *moduleSettings, *threadsCollapsed, *content;
|
||||
NSArray *currentComponents;
|
||||
NSMutableArray *mailboxThreadsCollapsed;
|
||||
NSString *msguid, *keyForMsgUIDs;
|
||||
NSMutableDictionary *moduleSettings, *threadsCollapsed;
|
||||
NSString *accountName, *msguid, *keyForMsgUIDs;
|
||||
SOGoMailAccount *account;
|
||||
SOGoMailFolder *mailbox;
|
||||
SOGoMailObject *co;
|
||||
SOGoUserSettings *us;
|
||||
int count;
|
||||
|
||||
request = [context request];
|
||||
content = [[request contentAsString] objectFromJSONString];
|
||||
keyForMsgUIDs = [content objectForKey:@"currentMailbox"];
|
||||
msguid = [content objectForKey:@"msguid"];
|
||||
co = [self clientObject];
|
||||
account = [co mailAccountFolder];
|
||||
accountName = [account nameInContainer];
|
||||
mailbox = [co container];
|
||||
msguid = [co nameInContainer];
|
||||
|
||||
// Build lookup key for current mailbox path
|
||||
currentComponents = [[mailbox imap4URL] pathComponents];
|
||||
count = [currentComponents count];
|
||||
currentComponents = [[currentComponents subarrayWithRange: NSMakeRange(1,count-1)]
|
||||
resultsOfSelector: @selector (asCSSIdentifier)];
|
||||
currentComponents = [currentComponents stringsWithFormat: @"folder%@"];
|
||||
keyForMsgUIDs = [NSString stringWithFormat:@"/%@/%@", accountName,
|
||||
[currentComponents componentsJoinedByString: @"/"]];
|
||||
|
||||
us = [[context activeUser] userSettings];
|
||||
if (!(moduleSettings = [us objectForKey: @"Mail"]))
|
||||
|
|
|
@ -300,7 +300,7 @@
|
|||
<md-list-item
|
||||
aria-label="{{currentMessage.subject}}"
|
||||
class="sg-message-list-item"
|
||||
ng-class="{'md-default-theme md-accent md-bg md-hue-2': mailbox.selectedFolder.isSelectedMessage(currentMessage.uid, currentMessage.$mailbox.path)}"
|
||||
ng-class="{'md-default-theme md-accent md-bg md-hue-2': mailbox.selectedFolder.isSelectedMessage(currentMessage.uid, currentMessage.$mailbox.path), 'sg-message-thread-first': currentMessage.first, 'sg-message-thread': currentMessage.threadMember}"
|
||||
md-virtual-repeat="currentMessage in mailbox.service.selectedFolder"
|
||||
md-on-demand="md-on-demand" md-item-size="56"
|
||||
ng-click="mailbox.selectMessage(currentMessage)"
|
||||
|
|
|
@ -578,7 +578,7 @@
|
|||
</md-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="ng-hide">
|
||||
<div>
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.SOGoMailSortByThreads"
|
||||
ng-true-value="1"
|
||||
|
|
|
@ -266,6 +266,16 @@
|
|||
'}'
|
||||
].join(''));
|
||||
|
||||
// Register custom stylesheet for Mail module
|
||||
$mdThemingProvider.registerStyles([
|
||||
'.sg-message-thread {',
|
||||
' background-color: \'{{primary-100}}\';',
|
||||
'}',
|
||||
'.sg-message-thread-first {',
|
||||
' background-color: \'{{primary-200}}\';',
|
||||
'}',
|
||||
].join(''));
|
||||
|
||||
if (!window.DebugEnabled) {
|
||||
// Disable debugging information
|
||||
$logProvider.debugEnabled(false);
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
if (this.path) {
|
||||
this.id = this.$id();
|
||||
this.$acl = new Mailbox.$$Acl('Mail/' + this.id);
|
||||
if (this.threaded) {
|
||||
this.$collapsedThreads = Mailbox.$Preferences.settings.Mail.threadsCollapsed['/' + this.id] || [];
|
||||
}
|
||||
}
|
||||
this.$displayName = this.name;
|
||||
if (this.type) {
|
||||
|
@ -222,7 +225,16 @@
|
|||
* @returns the number of messages in the mailbox
|
||||
*/
|
||||
Mailbox.prototype.getLength = function() {
|
||||
return this.$messages.length;
|
||||
var _this = this, collapsedThread = false;
|
||||
var visibleMessages = _.filter(this.$messages, function(msg, i) {
|
||||
if (msg.first) {
|
||||
collapsedThread = msg.collapsed;
|
||||
} else if (msg.level < 0) {
|
||||
collapsedThread = false;
|
||||
}
|
||||
return msg.first || collapsedThread === false;
|
||||
});
|
||||
return visibleMessages.length;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -232,10 +244,18 @@
|
|||
* @returns the message at the specified index
|
||||
*/
|
||||
Mailbox.prototype.getItemAtIndex = function(index) {
|
||||
var message;
|
||||
var _this = this, collapsedThread = false, message;
|
||||
var visibleMessages = _.filter(this.$messages, function(msg, i) {
|
||||
if (msg.first) {
|
||||
collapsedThread = msg.collapsed;
|
||||
} else if (msg.level < 0) {
|
||||
collapsedThread = false; // leaving the thread
|
||||
}
|
||||
return msg.first || collapsedThread === false;
|
||||
});
|
||||
|
||||
if (index >= 0 && index < this.$messages.length) {
|
||||
message = this.$messages[index];
|
||||
if (index >= 0 && index < visibleMessages.length) {
|
||||
message = visibleMessages[index];
|
||||
this.$lastVisibleIndex = Math.max(0, index - 3); // Magic number is NUM_EXTRA from virtual-repeater.js
|
||||
|
||||
if (this.$loadMessage(message.uid))
|
||||
|
@ -928,7 +948,7 @@
|
|||
|
||||
// First entry of 'uids' are keys when threaded view is enabled
|
||||
if (_this.threaded) {
|
||||
uids = _this.uids[0];
|
||||
uids = _this.uids[0]; // uid, level, first
|
||||
_this.uids.splice(0, 1);
|
||||
}
|
||||
|
||||
|
@ -937,6 +957,19 @@
|
|||
var data, msgObject;
|
||||
if (_this.threaded) {
|
||||
data = _.zipObject(uids, msg);
|
||||
if (data.first === 1) {
|
||||
var count = 1;
|
||||
while (_this.uids[i + count] &&
|
||||
_this.uids[i + count][1] >= 0 &&
|
||||
_this.uids[i + count][2] !== 1) {
|
||||
count++;
|
||||
}
|
||||
data.count = count;
|
||||
data.collapsed = false;
|
||||
if (_this.$collapsedThreads.indexOf(data.uid.toString()) >= 0) {
|
||||
data.collapsed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = {uid: msg.toString()};
|
||||
}
|
||||
|
|
|
@ -26,6 +26,15 @@
|
|||
this.init(futureMessageData);
|
||||
}
|
||||
this.uid = parseInt(futureMessageData.uid);
|
||||
this.level = parseInt(futureMessageData.level);
|
||||
this.first = parseInt(futureMessageData.first) === 1;
|
||||
if (this.first) {
|
||||
this.threadCount = parseInt(futureMessageData.count);
|
||||
this.collapsed = (futureMessageData.collapsed === true);
|
||||
}
|
||||
else if (!isNaN(this.level) && this.level >= 0) {
|
||||
this.threadMember = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The promise will be unwrapped first
|
||||
|
@ -539,7 +548,7 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* @function $markAsFlaggedOrUnflagged
|
||||
* @function toggleFlag
|
||||
* @memberof Message.prototype
|
||||
* @desc Add or remove a the \\Flagged flag on the current message.
|
||||
* @returns a promise of the HTTP operation
|
||||
|
@ -558,6 +567,24 @@
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function toggleThread
|
||||
* @memberof Message.prototype
|
||||
* @desc Collapse or expand mail thread
|
||||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Message.prototype.toggleThread = function() {
|
||||
var _this = this,
|
||||
action = 'markMessageCollapse';
|
||||
|
||||
if (this.collapsed)
|
||||
action = 'markMessageUncollapse';
|
||||
|
||||
this.collapsed = !this.collapsed;
|
||||
|
||||
return Message.$$resource.post(this.$absolutePath(), action);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $isLoading
|
||||
* @memberof Message.prototype
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
' <div class="sg-md-body">',
|
||||
' <div class="sg-tile-subject"><!-- subject --></div>',
|
||||
' <div class="sg-tile-size"><!-- size --></div>',
|
||||
' <md-button class="sg-tile-thread md-secondary ng-hide" md-colors="::{ color: \'accent-600\'}" ng-click="$ctrl.toggleThread()">',
|
||||
' <md-icon class="md-rotate-180-ccw" md-colors="::{ color: \'accent-600\'}">expand_more</md-icon><span><span>', // expanded by default (icon is rotated)
|
||||
' </md-button>',
|
||||
' </div>',
|
||||
'</div>',
|
||||
'<div class="sg-tile-icons">',
|
||||
|
@ -59,7 +62,7 @@
|
|||
var $ctrl = this;
|
||||
|
||||
this.$postLink = function () {
|
||||
var contentDivElement, iconsDivElement;
|
||||
var contentDivElement, threadButton, iconsDivElement;
|
||||
var parentControllerOnUpdate, setVisibility;
|
||||
|
||||
this.parentController = $scope.parentController;
|
||||
|
@ -74,6 +77,12 @@
|
|||
iconsDivElement = angular.element(div);
|
||||
});
|
||||
|
||||
threadButton = contentDivElement.find('button')[0];
|
||||
this.threadButton = threadButton;
|
||||
threadButton = angular.element(threadButton);
|
||||
this.threadIconElement = threadButton.find('md-icon')[0];
|
||||
this.threadCountElement = threadButton.find('span')[0];
|
||||
|
||||
this.priorityIconElement = contentDivElement.find('md-icon')[0];
|
||||
|
||||
if (Mailbox.$virtualMode) {
|
||||
|
@ -147,9 +156,19 @@
|
|||
else
|
||||
$ctrl.priorityIconElement.classList.add('ng-hide');
|
||||
|
||||
// Mail thread
|
||||
if ($ctrl.message.first) {
|
||||
$ctrl.threadButton.classList.remove('ng-hide');
|
||||
$ctrl.threadCountElement.innerHTML = $ctrl.message.threadCount;
|
||||
if ($ctrl.message.collapsed)
|
||||
$ctrl.threadIconElement.classList.remove('md-rotate-180-ccw');
|
||||
}
|
||||
else {
|
||||
$ctrl.threadButton.classList.add('ng-hide');
|
||||
}
|
||||
|
||||
// Subject
|
||||
$ctrl.subjectElement.innerHTML = $ctrl.message.subject.encodeEntities();
|
||||
|
||||
// Message size
|
||||
$ctrl.sizeElement.innerHTML = $ctrl.message.size;
|
||||
|
||||
|
@ -173,6 +192,14 @@
|
|||
this.MailboxService = Mailbox;
|
||||
};
|
||||
|
||||
this.toggleThread = function() {
|
||||
if (this.message.collapsed)
|
||||
this.threadIconElement.classList.add('md-rotate-180-ccw');
|
||||
else
|
||||
this.threadIconElement.classList.remove('md-rotate-180-ccw');
|
||||
this.message.toggleThread();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
var _this = this, defaultsElement, settingsElement, data;
|
||||
|
||||
this.defaults = {};
|
||||
this.settings = {};
|
||||
this.settings = {Mail: {}};
|
||||
|
||||
defaultsElement = Preferences.$document[0].getElementById('UserDefaults');
|
||||
if (defaultsElement) {
|
||||
|
|
|
@ -172,16 +172,25 @@ div.md-tile-left {
|
|||
&-tile-content {
|
||||
flex: 1;
|
||||
overflow: hidden; // required in Firefox
|
||||
.sg-tile-date, .sg-tile-size {
|
||||
.sg-tile-date, .sg-tile-size, .sg-tile-thread {
|
||||
flex-shrink: 0;
|
||||
font-size: sg-size(body);
|
||||
font-weight: $sg-font-light;
|
||||
line-height: $sg-line-height-2;
|
||||
margin-left: 3px;
|
||||
margin-left: 3px !important;
|
||||
}
|
||||
.sg-tile-size {
|
||||
font-size: sg-size(caption);
|
||||
}
|
||||
.sg-tile-thread {
|
||||
min-height: auto;
|
||||
min-width: auto;
|
||||
padding: 0 3px !important;
|
||||
font-weight: $sg-font-medium;
|
||||
md-icon {
|
||||
font-size: sg-size(body);
|
||||
}
|
||||
}
|
||||
.#{$md}-subhead {
|
||||
@extend .#{$md}-body-1;
|
||||
white-space: pre;
|
||||
|
|
Loading…
Reference in New Issue