Skip to content
This repository was archived by the owner on Nov 4, 2024. It is now read-only.

Commit 1564815

Browse files
authored
Merge pull request #1796 from SergeyMosin/compact-composer-plugin-v1.0.5
Compact composer plugin v1.0.5
2 parents b86743d + e7ecf53 commit 1564815

File tree

3 files changed

+29
-31
lines changed

3 files changed

+29
-31
lines changed

plugins/compact-composer/css/composer.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/* Prevent collapse of empty elements so that the caret can be placed in there */
2+
.CompactComposer *:empty::before {
3+
content: "\200B";
4+
}
5+
16
.CompactComposer .squire-toolbar {
27
padding-top: 4px;
38
padding-bottom: 0;

plugins/compact-composer/index.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ class CompactComposerPlugin extends \RainLoop\Plugins\AbstractPlugin
66
NAME = 'Compact Composer',
77
AUTHOR = 'Sergey Mosin',
88
URL = 'https://github.com/the-djmaze/snappymail/pull/1466',
9-
VERSION = '1.0.4',
10-
RELEASE = '2024-04-23',
9+
VERSION = '1.0.5',
10+
RELEASE = '2024-08-08',
1111
REQUIRED = '2.34.0',
1212
LICENSE = 'AGPL v3',
1313
DESCRIPTION = 'WYSIWYG editor with a compact toolbar';

plugins/compact-composer/js/CompactComposer.js

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,35 @@
1717
addEventListener('rl-view-model', e => {
1818
const vm = e.detail;
1919
if ('PopupsCompose' === vm.viewModelTemplateID && rl.settings.get('editorWysiwyg') === 'CompactComposer') {
20-
vm.querySelector('.tabs label[for="tab-body"]').dataset.bind = "visible: canMailvelope";
20+
// add visible binding to the label
21+
const bodyLabel = vm.querySelector('.tabs label[for="tab-body"]');
22+
bodyLabel.dataset.bind = 'visible: canMailvelope';
23+
// re-apply the binding
24+
const labelNext = bodyLabel.nextElementSibling;
25+
ko.removeNode(bodyLabel);
26+
labelNext.parentElement.insertBefore(bodyLabel, labelNext);
27+
ko.applyBindingAccessorsToNode(bodyLabel, null, vm);
28+
2129
// Now move the attachments tab to the bottom of the screen
22-
const
23-
input = vm.querySelector('.tabs input[value="attachments"]'),
24-
label = vm.querySelector('.tabs label[for="tab-attachments"]'),
25-
area = vm.querySelector('.tabs .attachmentAreaParent');
26-
input.remove();
27-
label.remove();
28-
area.remove();
30+
const area = vm.querySelector('.tabs .attachmentAreaParent');
31+
vm.querySelector('.tabs input[value="attachments"]').remove();
32+
vm.querySelector('.tabs label[for="tab-attachments"]').remove();
33+
area.querySelector('.no-attachments-desc').remove();
2934
area.classList.add('compact');
30-
area.querySelector('.b-attachment-place').dataset.bind = "visible: addAttachmentEnabled(), css: {dragAndDropOver: dragAndDropVisible}";
3135
vm.viewModelDom.append(area);
36+
// Add and re-apply the bindings for the attachment-place
37+
const place = area.querySelector('.b-attachment-place');
38+
ko.removeNode(place);
39+
area.insertBefore(place, area.firstElementChild);
40+
place.dataset.bind = 'visible: addAttachmentEnabled(), css: {dragAndDropOver: dragAndDropVisible}';
41+
ko.applyBindingAccessorsToNode(place, null, vm);
3242
// There is a better way to do this probably,
3343
// but we need this for drag and drop to work
3444
e.detail.attachmentsArea = e.detail.bodyArea;
3545
}
3646
});
3747

3848
const
39-
removeElements = 'HEAD,LINK,META,NOSCRIPT,SCRIPT,TEMPLATE,TITLE',
40-
allowedElements = 'A,B,BLOCKQUOTE,BR,DIV,EM,FONT,H1,H2,H3,H4,H5,H6,HR,I,IMG,LI,OL,P,SPAN,STRONG,TABLE,TD,TH,TR,U,UL',
41-
allowedAttributes = 'abbr,align,background,bgcolor,border,cellpadding,cellspacing,class,color,colspan,dir,face,frame,height,href,hspace,id,lang,rowspan,rules,scope,size,src,style,target,type,usemap,valign,vspace,width'.split(','),
42-
4349
// TODO: labels translations
4450
i18n = (str, def) => rl.i18n(str) || def,
4551

@@ -95,21 +101,7 @@
95101
},
96102

97103
pasteSanitizer = (event) => {
98-
const frag = event.detail.fragment;
99-
frag.querySelectorAll('a:empty,span:empty').forEach(el => el.remove());
100-
frag.querySelectorAll(removeElements).forEach(el => el.remove());
101-
frag.querySelectorAll('*').forEach(el => {
102-
if (!el.matches(allowedElements)) {
103-
el.replaceWith(getFragmentOfChildren(el));
104-
} else if (el.hasAttributes()) {
105-
[...el.attributes].forEach(attr => {
106-
let name = attr.name.toLowerCase();
107-
if (!allowedAttributes.includes(name)) {
108-
el.removeAttribute(name);
109-
}
110-
});
111-
}
112-
});
104+
return rl.Utils.cleanHtml(event.detail.html).html;
113105
},
114106

115107
pasteImageHandler = (e, squire) => {
@@ -317,7 +309,8 @@
317309
clr.style.left = (input.offsetLeft + input.parentNode.offsetLeft) + 'px';
318310
clr.style.width = input.offsetWidth + 'px';
319311

320-
clr.value = '';
312+
// firefox does not call "onchange" for #000 if we use clr.value=''
313+
clr.value = '#00ff0c';
321314
clr.onchange = () => {
322315
switch (name) {
323316
case 'color':

0 commit comments

Comments
 (0)