mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Resolve Issue #100
This commit is contained in:
parent
1996c79240
commit
bb15cd1ec3
5 changed files with 81 additions and 68 deletions
|
|
@ -1,6 +1,15 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
import { isArray } from 'Common/Utils';
|
import { isArray } from 'Common/Utils';
|
||||||
|
|
||||||
|
/*
|
||||||
|
oCallbacks:
|
||||||
|
ItemSelect
|
||||||
|
MiddleClick
|
||||||
|
AutoSelect
|
||||||
|
ItemGetUid
|
||||||
|
UpOrDown
|
||||||
|
*/
|
||||||
|
|
||||||
export class Selector {
|
export class Selector {
|
||||||
/**
|
/**
|
||||||
* @param {koProperty} koList
|
* @param {koProperty} koList
|
||||||
|
|
@ -209,11 +218,9 @@ export class Selector {
|
||||||
|
|
||||||
itemSelected(item) {
|
itemSelected(item) {
|
||||||
if (this.isListChecked()) {
|
if (this.isListChecked()) {
|
||||||
if (!item) {
|
item || (this.oCallbacks.ItemSelect || (()=>{}))(null);
|
||||||
(this.oCallbacks.onItemSelect || (()=>{}))(item || null);
|
|
||||||
}
|
|
||||||
} else if (item) {
|
} else if (item) {
|
||||||
(this.oCallbacks.onItemSelect || (()=>{}))(item);
|
(this.oCallbacks.ItemSelect || (()=>{}))(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,20 +233,32 @@ export class Selector {
|
||||||
this.oContentScrollable = contentScrollable;
|
this.oContentScrollable = contentScrollable;
|
||||||
|
|
||||||
if (contentScrollable) {
|
if (contentScrollable) {
|
||||||
|
let getItem = selector => {
|
||||||
|
let el = event.target.closestWithin(selector, contentScrollable);
|
||||||
|
return el ? ko.dataFor(el) : null;
|
||||||
|
};
|
||||||
|
|
||||||
contentScrollable.addEventListener('click', event => {
|
contentScrollable.addEventListener('click', event => {
|
||||||
let el = event.target.closestWithin(this.sItemSelector, contentScrollable);
|
let el = event.target.closestWithin(this.sItemSelector, contentScrollable);
|
||||||
el && this.actionClick(ko.dataFor(el), event);
|
el && this.actionClick(ko.dataFor(el), event);
|
||||||
|
|
||||||
el = event.target.closestWithin(this.sItemCheckedSelector, contentScrollable);
|
const item = getItem(this.sItemCheckedSelector);
|
||||||
if (el) {
|
if (item) {
|
||||||
const item = ko.dataFor(el);
|
if (event.shiftKey) {
|
||||||
|
this.actionClick(item, event);
|
||||||
|
} else {
|
||||||
|
this.focusedItem(item);
|
||||||
|
item.checked(!item.checked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
contentScrollable.addEventListener('auxclick', event => {
|
||||||
|
if (1 == event.button) {
|
||||||
|
const item = getItem(this.sItemSelector);
|
||||||
if (item) {
|
if (item) {
|
||||||
if (event.shiftKey) {
|
this.focusedItem(item);
|
||||||
this.actionClick(item, event);
|
(this.oCallbacks.MiddleClick || (()=>{}))(item);
|
||||||
} else {
|
|
||||||
this.focusedItem(item);
|
|
||||||
item.checked(!item.checked());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -271,7 +290,7 @@ export class Selector {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
autoSelect() {
|
autoSelect() {
|
||||||
return !!(this.oCallbacks.onAutoSelect || (()=>true))();
|
return !!(this.oCallbacks.AutoSelect || (()=>true))();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -281,7 +300,7 @@ export class Selector {
|
||||||
getItemUid(item) {
|
getItemUid(item) {
|
||||||
let uid = '';
|
let uid = '';
|
||||||
|
|
||||||
const getItemUidCallback = this.oCallbacks.onItemGetUid || null;
|
const getItemUidCallback = this.oCallbacks.ItemGetUid || null;
|
||||||
if (getItemUidCallback && item) {
|
if (getItemUidCallback && item) {
|
||||||
uid = getItemUidCallback(item);
|
uid = getItemUidCallback(item);
|
||||||
}
|
}
|
||||||
|
|
@ -312,7 +331,7 @@ export class Selector {
|
||||||
} else if (++i < listLen) {
|
} else if (++i < listLen) {
|
||||||
result = list[i];
|
result = list[i];
|
||||||
}
|
}
|
||||||
result || (this.oCallbacks.onUpUpOrDownDown || (()=>true))('ArrowUp' === sEventKey);
|
result || (this.oCallbacks.UpOrDown || (()=>true))('ArrowUp' === sEventKey);
|
||||||
} else if ('Home' === sEventKey) {
|
} else if ('Home' === sEventKey) {
|
||||||
result = list[0];
|
result = list[0];
|
||||||
} else if ('End' === sEventKey) {
|
} else if ('End' === sEventKey) {
|
||||||
|
|
|
||||||
|
|
@ -524,13 +524,6 @@ export class MessageModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storeDataInDom() {
|
|
||||||
if (this.body) {
|
|
||||||
this.body.rlIsHtml = !!this.isHtml();
|
|
||||||
this.body.rlHasImages = !!this.hasImages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchDataFromDom() {
|
fetchDataFromDom() {
|
||||||
if (this.body) {
|
if (this.body) {
|
||||||
this.isHtml(!!this.body.rlIsHtml);
|
this.isHtml(!!this.body.rlIsHtml);
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ export const MessageUserStore = new class {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.purgeMessageBodyCacheThrottle = this.purgeMessageBodyCache.throttle(30000);
|
this.purgeMessageBodyCache = this.purgeMessageBodyCache.throttle(30000);
|
||||||
}
|
}
|
||||||
|
|
||||||
purgeMessageBodyCache() {
|
purgeMessageBodyCache() {
|
||||||
|
|
@ -428,16 +428,12 @@ export const MessageUserStore = new class {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setMessage(data, cached) {
|
setMessage(data, cached, oMessage) {
|
||||||
let isNew = false,
|
let isNew = false,
|
||||||
body = null,
|
|
||||||
json = data && data.Result,
|
json = data && data.Result,
|
||||||
id = '',
|
|
||||||
plain = '',
|
|
||||||
resultHtml = '',
|
|
||||||
messagesDom = this.messagesBodiesDom(),
|
messagesDom = this.messagesBodiesDom(),
|
||||||
selectedMessage = this.selectorMessageSelected(),
|
selectedMessage = this.selectorMessageSelected(),
|
||||||
message = this.message();
|
message = oMessage || this.message();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
json &&
|
json &&
|
||||||
|
|
@ -447,7 +443,7 @@ export const MessageUserStore = new class {
|
||||||
) {
|
) {
|
||||||
const threads = message.threads();
|
const threads = message.threads();
|
||||||
if (message.uid !== json.Uid && 1 < threads.length && threads.includes(json.Uid)) {
|
if (message.uid !== json.Uid && 1 < threads.length && threads.includes(json.Uid)) {
|
||||||
message = MessageModel.reviveFromJson(json);
|
message = oMessage ? null : MessageModel.reviveFromJson(json);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.threads(threads);
|
message.threads(threads);
|
||||||
MessageFlagsCache.initMessage(message);
|
MessageFlagsCache.initMessage(message);
|
||||||
|
|
@ -460,7 +456,7 @@ export const MessageUserStore = new class {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message && message.uid === json.Uid) {
|
if (message && message.uid === json.Uid) {
|
||||||
this.messageError('');
|
oMessage || this.messageError('');
|
||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
delete json.IsSeen;
|
delete json.IsSeen;
|
||||||
|
|
@ -475,7 +471,8 @@ export const MessageUserStore = new class {
|
||||||
addRequestedMessage(message.folder, message.uid);
|
addRequestedMessage(message.folder, message.uid);
|
||||||
|
|
||||||
if (messagesDom) {
|
if (messagesDom) {
|
||||||
id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, '');
|
let body = null,
|
||||||
|
id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, '');
|
||||||
|
|
||||||
const textBody = elementById(id);
|
const textBody = elementById(id);
|
||||||
if (textBody) {
|
if (textBody) {
|
||||||
|
|
@ -483,7 +480,9 @@ export const MessageUserStore = new class {
|
||||||
message.fetchDataFromDom();
|
message.fetchDataFromDom();
|
||||||
messagesDom.append(textBody);
|
messagesDom.append(textBody);
|
||||||
} else {
|
} else {
|
||||||
let isHtml = !!json.Html;
|
let isHtml = !!json.Html,
|
||||||
|
plain = '',
|
||||||
|
resultHtml = '<pre></pre>';
|
||||||
if (isHtml) {
|
if (isHtml) {
|
||||||
resultHtml = json.Html.toString();
|
resultHtml = json.Html.toString();
|
||||||
if (SettingsUserStore.removeColors()) {
|
if (SettingsUserStore.removeColors()) {
|
||||||
|
|
@ -508,8 +507,6 @@ export const MessageUserStore = new class {
|
||||||
} else {
|
} else {
|
||||||
resultHtml = '<pre>' + resultHtml + '</pre>';
|
resultHtml = '<pre>' + resultHtml + '</pre>';
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
resultHtml = '<pre>' + resultHtml + '</pre>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body = Element.fromHTML('<div id="' + id + '" hidden="" class="b-text-part '
|
body = Element.fromHTML('<div id="' + id + '" hidden="" class="b-text-part '
|
||||||
|
|
@ -517,22 +514,25 @@ export const MessageUserStore = new class {
|
||||||
+ findEmailAndLinks(resultHtml)
|
+ findEmailAndLinks(resultHtml)
|
||||||
+ '</div>');
|
+ '</div>');
|
||||||
|
|
||||||
// Drop Microsoft Office style properties
|
if (isHtml) {
|
||||||
const rgbRE = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/g,
|
// Drop Microsoft Office style properties
|
||||||
hex = n => ('0' + parseInt(n).toString(16)).slice(-2);
|
const rgbRE = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/g,
|
||||||
body.querySelectorAll('[style*=mso]').forEach(el =>
|
hex = n => ('0' + parseInt(n).toString(16)).slice(-2);
|
||||||
el.setAttribute('style', el.style.cssText.replace(rgbRE, (m,r,g,b) => '#' + hex(r) + hex(g) + hex(b)))
|
body.querySelectorAll('[style*=mso]').forEach(el =>
|
||||||
);
|
el.setAttribute('style', el.style.cssText.replace(rgbRE, (m,r,g,b) => '#' + hex(r) + hex(g) + hex(b)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.rlIsHtml = isHtml;
|
||||||
|
body.rlHasImages = !!json.HasExternals;
|
||||||
|
|
||||||
message.body = body;
|
message.body = body;
|
||||||
|
|
||||||
message.isHtml(isHtml);
|
message.isHtml(isHtml);
|
||||||
message.hasImages(!!json.HasExternals);
|
message.hasImages(body.rlHasImages);
|
||||||
|
|
||||||
messagesDom.append(body);
|
messagesDom.append(body);
|
||||||
|
|
||||||
message.storeDataInDom();
|
|
||||||
|
|
||||||
if (json.HasInternals) {
|
if (json.HasInternals) {
|
||||||
message.showInternalImages();
|
message.showInternalImages();
|
||||||
}
|
}
|
||||||
|
|
@ -541,12 +541,12 @@ export const MessageUserStore = new class {
|
||||||
message.showExternalImages();
|
message.showExternalImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.purgeMessageBodyCacheThrottle();
|
this.purgeMessageBodyCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageActiveDom(message.body);
|
oMessage || this.messageActiveDom(message.body);
|
||||||
|
|
||||||
this.hideMessageBodies();
|
oMessage || this.hideMessageBodies();
|
||||||
|
|
||||||
if (body) {
|
if (body) {
|
||||||
this.initOpenPgpControls(body, message);
|
this.initOpenPgpControls(body, message);
|
||||||
|
|
@ -554,7 +554,8 @@ export const MessageUserStore = new class {
|
||||||
this.initBlockquoteSwitcher(body);
|
this.initBlockquoteSwitcher(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
message.body.hidden = false;
|
oMessage || (message.body.hidden = false);
|
||||||
|
oMessage && message.viewPopupMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageFlagsCache.initMessage(message);
|
MessageFlagsCache.initMessage(message);
|
||||||
|
|
@ -563,8 +564,6 @@ export const MessageUserStore = new class {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
message = this.message();
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
selectedMessage &&
|
selectedMessage &&
|
||||||
message &&
|
message &&
|
||||||
|
|
@ -613,20 +612,20 @@ export const MessageUserStore = new class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
populateMessageBody(oMessage) {
|
populateMessageBody(oMessage, preload) {
|
||||||
if (oMessage) {
|
if (oMessage) {
|
||||||
this.hideMessageBodies();
|
preload || this.hideMessageBodies();
|
||||||
this.messageLoading(true);
|
preload || this.messageLoading(true);
|
||||||
Remote.message((iError, oData, bCached) => {
|
Remote.message((iError, oData, bCached) => {
|
||||||
if (iError) {
|
if (iError) {
|
||||||
if (Notification.RequestAborted !== iError) {
|
if (Notification.RequestAborted !== iError && !preload) {
|
||||||
this.message(null);
|
this.message(null);
|
||||||
this.messageError(getNotification(iError));
|
this.messageError(getNotification(iError));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.setMessage(oData, bCached);
|
this.setMessage(oData, bCached, preload ? oMessage : null);
|
||||||
}
|
}
|
||||||
this.messageLoading(false);
|
preload || this.messageLoading(false);
|
||||||
}, oMessage.folder, oMessage.uid);
|
}, oMessage.folder, oMessage.uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,14 +79,14 @@ class ContactsPopupView extends AbstractViewPopup {
|
||||||
'.e-contact-item.focused'
|
'.e-contact-item.focused'
|
||||||
);
|
);
|
||||||
|
|
||||||
this.selector.on('onItemSelect', contact => {
|
this.selector.on('ItemSelect', contact => {
|
||||||
this.populateViewContact(contact || null);
|
this.populateViewContact(contact);
|
||||||
if (!contact) {
|
if (!contact) {
|
||||||
this.emptySelection(true);
|
this.emptySelection(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.selector.on('onItemGetUid', contact => contact ? contact.generateUid() : '');
|
this.selector.on('ItemGetUid', contact => contact ? contact.generateUid() : '');
|
||||||
|
|
||||||
this.bDropPageAfterDelete = false;
|
this.bDropPageAfterDelete = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
||||||
this.bPrefetch = false;
|
this.bPrefetch = false;
|
||||||
this.emptySubjectValue = '';
|
this.emptySubjectValue = '';
|
||||||
|
|
||||||
this.iGoToUpUpOrDownDownTimeout = 0;
|
this.iGoToUpOrDownTimeout = 0;
|
||||||
|
|
||||||
this.newMoveToFolder = !!SettingsGet('NewMoveToFolder');
|
this.newMoveToFolder = !!SettingsGet('NewMoveToFolder');
|
||||||
|
|
||||||
|
|
@ -191,13 +191,15 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
||||||
'.messageListItem.focused'
|
'.messageListItem.focused'
|
||||||
);
|
);
|
||||||
|
|
||||||
this.selector.on('onItemSelect', message => MessageUserStore.selectMessage(message));
|
this.selector.on('ItemSelect', message => MessageUserStore.selectMessage(message));
|
||||||
|
|
||||||
this.selector.on('onItemGetUid', message => (message ? message.generateUid() : ''));
|
this.selector.on('MiddleClick', message => MessageUserStore.populateMessageBody(message, true));
|
||||||
|
|
||||||
this.selector.on('onAutoSelect', () => this.useAutoSelect());
|
this.selector.on('ItemGetUid', message => (message ? message.generateUid() : ''));
|
||||||
|
|
||||||
this.selector.on('onUpUpOrDownDown', v => this.goToUpUpOrDownDown(v));
|
this.selector.on('AutoSelect', () => this.useAutoSelect());
|
||||||
|
|
||||||
|
this.selector.on('UpOrDown', v => this.goToUpOrDown(v));
|
||||||
|
|
||||||
addEventListener('mailbox.message-list.selector.go-down',
|
addEventListener('mailbox.message-list.selector.go-down',
|
||||||
e => this.selector.newSelectPosition('ArrowDown', false, e.detail)
|
e => this.selector.newSelectPosition('ArrowDown', false, e.detail)
|
||||||
|
|
@ -351,13 +353,13 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
||||||
showMessageComposer();
|
showMessageComposer();
|
||||||
}
|
}
|
||||||
|
|
||||||
goToUpUpOrDownDown(up) {
|
goToUpOrDown(up) {
|
||||||
if (MessageUserStore.listChecked().length) {
|
if (MessageUserStore.listChecked().length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearTimeout(this.iGoToUpUpOrDownDownTimeout);
|
clearTimeout(this.iGoToUpOrDownTimeout);
|
||||||
this.iGoToUpUpOrDownDownTimeout = setTimeout(() => {
|
this.iGoToUpOrDownTimeout = setTimeout(() => {
|
||||||
let prev, next, temp, current;
|
let prev, next, temp, current;
|
||||||
|
|
||||||
this.messageListPaginator().find(item => {
|
this.messageListPaginator().find(item => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue