mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Extend the use of ResizeObserver by dropping all knockoutjs observable this.resizerTrigger in mail composer
As benefit this also drops the CustomEvent('resize.real')
This commit is contained in:
parent
35c9f3fff5
commit
d1c06a8ece
10 changed files with 48 additions and 117 deletions
|
|
@ -31,20 +31,6 @@ class AbstractApp extends AbstractBoot {
|
||||||
this.isLocalAutocomplete = true;
|
this.isLocalAutocomplete = true;
|
||||||
this.lastErrorTime = 0;
|
this.lastErrorTime = 0;
|
||||||
|
|
||||||
addEventListener(
|
|
||||||
'resize',
|
|
||||||
(()=>{
|
|
||||||
const iH = $win.height(),
|
|
||||||
iW = $win.height();
|
|
||||||
|
|
||||||
if ($win.__sizes[0] !== iH || $win.__sizes[1] !== iW) {
|
|
||||||
$win.__sizes[0] = iH;
|
|
||||||
$win.__sizes[1] = iW;
|
|
||||||
dispatchEvent(new CustomEvent('resize.real'));
|
|
||||||
}
|
|
||||||
}).throttle(50)
|
|
||||||
);
|
|
||||||
|
|
||||||
const $doc = document;
|
const $doc = document;
|
||||||
$doc.addEventListener('keydown', (event) => {
|
$doc.addEventListener('keydown', (event) => {
|
||||||
if (event && event.ctrlKey) {
|
if (event && event.ctrlKey) {
|
||||||
|
|
|
||||||
|
|
@ -80,31 +80,6 @@ import { AbstractApp } from 'App/Abstract';
|
||||||
|
|
||||||
const doc = document;
|
const doc = document;
|
||||||
|
|
||||||
if (!window.ResizeObserver) {
|
|
||||||
window.ResizeObserver = class {
|
|
||||||
constructor(callback) {
|
|
||||||
callback = callback.debounce(250);
|
|
||||||
this.observer = new MutationObserver(mutations => {
|
|
||||||
let i = mutations.length;
|
|
||||||
while (i--) {
|
|
||||||
if ('style' == mutations[i].attributeName) {
|
|
||||||
callback();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnect() {
|
|
||||||
this.observer.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(target) {
|
|
||||||
this.observer.observe(target, { attributes: true });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppUser extends AbstractApp {
|
class AppUser extends AbstractApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(Remote);
|
super(Remote);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import ko from 'ko';
|
||||||
import { KeyState } from 'Common/Enums';
|
import { KeyState } from 'Common/Enums';
|
||||||
|
|
||||||
const $win = jQuery(window);
|
const $win = jQuery(window);
|
||||||
$win.__sizes = [0, 0];
|
|
||||||
|
|
||||||
export { $win };
|
export { $win };
|
||||||
|
|
||||||
|
|
|
||||||
16
dev/External/ko.js
vendored
16
dev/External/ko.js
vendored
|
|
@ -245,22 +245,6 @@ ko.bindingHandlers.initDom = {
|
||||||
init: (element, fValueAccessor) => fValueAccessor()(element)
|
init: (element, fValueAccessor) => fValueAccessor()(element)
|
||||||
};
|
};
|
||||||
|
|
||||||
ko.bindingHandlers.initResizeTrigger = {
|
|
||||||
init: (element, fValueAccessor) =>
|
|
||||||
element.style.height = element.style.minHeight = ko.unwrap(fValueAccessor())[1] + 'px',
|
|
||||||
update: (element, fValueAccessor) => {
|
|
||||||
const values = ko.unwrap(fValueAccessor());
|
|
||||||
let offset = element.getBoundingClientRect().top + pageYOffset;
|
|
||||||
if (0 < offset) {
|
|
||||||
offset += parseInt(values[2], 10) || 0;
|
|
||||||
element.style.height = element.style.minHeight = Math.max(
|
|
||||||
parseInt(values[1], 10) || 0,
|
|
||||||
window.innerHeight - offset
|
|
||||||
) + 'px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ko.bindingHandlers.appendDom = {
|
ko.bindingHandlers.appendDom = {
|
||||||
update: (element, fValueAccessor) => {
|
update: (element, fValueAccessor) => {
|
||||||
$(element)
|
$(element)
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@
|
||||||
.b-compose {
|
.b-compose {
|
||||||
|
|
||||||
&.modal {
|
&.modal {
|
||||||
|
width: 98%;
|
||||||
width: 850px;
|
max-width: 1000px;
|
||||||
margin: 10px auto;
|
margin: 10px auto;
|
||||||
|
/* height: 94vh;*/
|
||||||
|
|
||||||
.modal-body {
|
.modal-body {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
@ -15,6 +16,9 @@
|
||||||
.textAreaParent, .attachmentAreaParent {
|
.textAreaParent, .attachmentAreaParent {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
height: 200px;
|
||||||
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachmentAreaParent {
|
.attachmentAreaParent {
|
||||||
|
|
|
||||||
|
|
@ -186,10 +186,6 @@ html.ssm-state-desktop-large {
|
||||||
left: 500px;
|
left: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.b-compose.modal {
|
|
||||||
width: 1000px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.b-contacts-content.modal {
|
.b-contacts-content.modal {
|
||||||
width: 900px;
|
width: 900px;
|
||||||
}
|
}
|
||||||
|
|
@ -213,10 +209,6 @@ html.ssm-state-desktop {
|
||||||
left: 400px;
|
left: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.b-compose.modal {
|
|
||||||
width: 1000px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.b-contacts-content.modal {
|
.b-contacts-content.modal {
|
||||||
width: 900px;
|
width: 900px;
|
||||||
}
|
}
|
||||||
|
|
@ -244,10 +236,6 @@ html.ssm-state-tablet, html.ssm-state-mobile {
|
||||||
left: 310px;
|
left: 310px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.b-compose.modal {
|
|
||||||
width: 720px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.b-contacts-content.modal {
|
.b-contacts-content.modal {
|
||||||
width: 700px;
|
width: 700px;
|
||||||
}
|
}
|
||||||
|
|
@ -261,10 +249,6 @@ html.ssm-state-tablet, html.ssm-state-mobile {
|
||||||
|
|
||||||
html.ssm-state-tablet {
|
html.ssm-state-tablet {
|
||||||
|
|
||||||
.b-compose.modal {
|
|
||||||
width: 720px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.b-contacts-content.modal {
|
.b-contacts-content.modal {
|
||||||
width: 800px;
|
width: 800px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ html.no-rgba .modal {
|
||||||
|
|
||||||
.popups {
|
.popups {
|
||||||
|
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,6 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
|
|
||||||
this.sLastFocusedField = 'to';
|
this.sLastFocusedField = 'to';
|
||||||
|
|
||||||
this.resizerTrigger = this.resizerTrigger.debounce(50).bind(this);
|
|
||||||
|
|
||||||
this.allowContacts = !!AppStore.contactsIsAllowed();
|
this.allowContacts = !!AppStore.contactsIsAllowed();
|
||||||
this.allowFolders = !!Settings.capa(Capa.Folders);
|
this.allowFolders = !!Settings.capa(Capa.Folders);
|
||||||
|
|
||||||
|
|
@ -141,11 +139,7 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
this.sendErrorDesc = ko.observable('');
|
this.sendErrorDesc = ko.observable('');
|
||||||
this.savedErrorDesc = ko.observable('');
|
this.savedErrorDesc = ko.observable('');
|
||||||
|
|
||||||
this.sendError.subscribe((value) => {
|
this.sendError.subscribe(value => !value && this.sendErrorDesc(''));
|
||||||
if (!value) {
|
|
||||||
this.sendErrorDesc('');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.savedError.subscribe(value => !value && this.savedErrorDesc(''));
|
this.savedError.subscribe(value => !value && this.savedErrorDesc(''));
|
||||||
|
|
||||||
|
|
@ -217,9 +211,6 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
|
|
||||||
this.attachmentsPlace = ko.observable(false);
|
this.attachmentsPlace = ko.observable(false);
|
||||||
|
|
||||||
this.attachments.subscribe(this.resizerTrigger);
|
|
||||||
this.attachmentsPlace.subscribe(this.resizerTrigger);
|
|
||||||
|
|
||||||
this.attachmentsInErrorCount.subscribe((value) => {
|
this.attachmentsInErrorCount.subscribe((value) => {
|
||||||
if (0 === value) {
|
if (0 === value) {
|
||||||
this.attachmentsInErrorError(false);
|
this.attachmentsInErrorError(false);
|
||||||
|
|
@ -278,14 +269,6 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resizer = ko.observable(false).extend({ throttle: 50 });
|
|
||||||
|
|
||||||
this.resizer.subscribe(() => {
|
|
||||||
if (this.oEditor) {
|
|
||||||
this.oEditor.resize();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.canBeSentOrSaved = ko.computed(() => !this.sending() && !this.saving());
|
this.canBeSentOrSaved = ko.computed(() => !this.sending() && !this.saving());
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
|
@ -302,16 +285,14 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
}, 120000);
|
}, 120000);
|
||||||
|
|
||||||
this.showCc.subscribe(this.resizerTrigger);
|
|
||||||
this.showBcc.subscribe(this.resizerTrigger);
|
|
||||||
this.showReplyTo.subscribe(this.resizerTrigger);
|
|
||||||
|
|
||||||
this.bDisabeCloseOnEsc = true;
|
this.bDisabeCloseOnEsc = true;
|
||||||
this.sDefaultKeyScope = KeyState.Compose;
|
this.sDefaultKeyScope = KeyState.Compose;
|
||||||
|
|
||||||
this.tryToClosePopup = this.tryToClosePopup.debounce(200);
|
this.tryToClosePopup = this.tryToClosePopup.debounce(200);
|
||||||
|
|
||||||
this.iTimer = 0;
|
this.iTimer = 0;
|
||||||
|
|
||||||
|
this.resizeObserver = new ResizeObserver(this.resizerTrigger.throttle(50).bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessageRequestParams(sSaveFolder)
|
getMessageRequestParams(sSaveFolder)
|
||||||
|
|
@ -660,6 +641,8 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
this.to.focused(false);
|
this.to.focused(false);
|
||||||
|
|
||||||
routeOn();
|
routeOn();
|
||||||
|
|
||||||
|
this.resizeObserver.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
editor(fOnInit) {
|
editor(fOnInit) {
|
||||||
|
|
@ -671,7 +654,6 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
null,
|
null,
|
||||||
() => {
|
() => {
|
||||||
fOnInit(this.oEditor);
|
fOnInit(this.oEditor);
|
||||||
this.resizerTrigger();
|
|
||||||
},
|
},
|
||||||
(bHtml) => {
|
(bHtml) => {
|
||||||
this.isHtml(!!bHtml);
|
this.isHtml(!!bHtml);
|
||||||
|
|
@ -680,7 +662,6 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
// }, 1000);
|
// }, 1000);
|
||||||
} else if (this.oEditor) {
|
} else if (this.oEditor) {
|
||||||
fOnInit(this.oEditor);
|
fOnInit(this.oEditor);
|
||||||
this.resizerTrigger();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1077,7 +1058,12 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
this.currentIdentity(identity);
|
this.currentIdentity(identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resizerTrigger();
|
let el = document.querySelector('.b-compose');
|
||||||
|
this.resizeObserver.compose = el;
|
||||||
|
this.resizeObserver.popups = el.parentNode; // el.closest('.popups');
|
||||||
|
this.resizeObserver.els = [el.querySelector('.textAreaParent'), el.querySelector('.attachmentAreaParent')];
|
||||||
|
this.resizeObserver.observe(el);
|
||||||
|
this.resizeObserver.observe(el.querySelector('.b-header'));
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageUploadAttachments(sResult, oData) {
|
onMessageUploadAttachments(sResult, oData) {
|
||||||
|
|
@ -1113,10 +1099,6 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onShowWithDelay() {
|
|
||||||
this.resizerTrigger();
|
|
||||||
}
|
|
||||||
|
|
||||||
tryToClosePopup() {
|
tryToClosePopup() {
|
||||||
const PopupsAskViewModel = require('View/Popup/Ask');
|
const PopupsAskViewModel = require('View/Popup/Ask');
|
||||||
if (!isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) {
|
if (!isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) {
|
||||||
|
|
@ -1179,14 +1161,6 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
addEventListener('resize.real', this.resizerTrigger);
|
|
||||||
|
|
||||||
setInterval(() => {
|
|
||||||
if (this.modalVisibility() && this.oEditor) {
|
|
||||||
this.oEditor.resize();
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1542,7 +1516,17 @@ class ComposePopupView extends AbstractViewNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
resizerTrigger() {
|
resizerTrigger() {
|
||||||
this.resizer(!this.resizer());
|
let top = 0;
|
||||||
|
this.resizeObserver.els.forEach(element => top = Math.max(top, element.getBoundingClientRect().top));
|
||||||
|
if (0 < top) {
|
||||||
|
top = this.resizeObserver.popups.clientHeight - this.resizeObserver.compose.offsetTop - 50 - top;
|
||||||
|
this.resizeObserver.els.forEach(element =>
|
||||||
|
element.style.height = Math.max(top, Math.max(200,parseInt(element.style.minHeight,10))) + 'px'
|
||||||
|
);
|
||||||
|
if (this.oEditor) {
|
||||||
|
this.oEditor.resize();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,19 @@ Array.prototype.flat || Object.defineProperty(Array.prototype, 'flat', {
|
||||||
},
|
},
|
||||||
writable: true
|
writable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!window.ResizeObserver) {
|
||||||
|
window.ResizeObserver = class {
|
||||||
|
constructor(callback) {
|
||||||
|
this.observer = new MutationObserver(callback.debounce(250));
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(target) {
|
||||||
|
this.observer.observe(target, { attributes: true, subtree: true, attributeFilter: ['style'] });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attachmentAreaParent b-content" style="height: 200px; min-height: 200px" data-bind="visible: attachmentsPlace, initResizeTrigger: [resizer(), 200, 57]">
|
<div class="attachmentAreaParent b-content" data-bind="visible: attachmentsPlace">
|
||||||
<div class="content g-scrollbox">
|
<div class="content g-scrollbox">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropEnabled() && dragAndDropVisible(), initDom: composeUploaderDropPlace, css: {'dragAndDropOver': dragAndDropOver}">
|
<div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropEnabled() && dragAndDropVisible(), initDom: composeUploaderDropPlace, css: {'dragAndDropOver': dragAndDropOver}">
|
||||||
|
|
@ -199,8 +199,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="textAreaParent" style="height: 200px; min-height: 200px"
|
<div class="textAreaParent" data-bind="visible: !attachmentsPlace(), initDom: composeEditorArea"></div>
|
||||||
data-bind="visible: !attachmentsPlace(), initDom: composeEditorArea, initResizeTrigger: [resizer(), 200, 40]"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue