CompactComposer support older browsers and a different idea to modify the dialog for #1498

This commit is contained in:
the-djmaze 2024-03-19 14:10:03 +01:00
parent 0d34d0b25b
commit 70b1a93108
3 changed files with 49 additions and 51 deletions

View file

@ -6,15 +6,15 @@ class CompactComposerPlugin extends \RainLoop\Plugins\AbstractPlugin
NAME = 'Compact Composer', NAME = 'Compact Composer',
AUTHOR = 'Sergey Mosin', AUTHOR = 'Sergey Mosin',
URL = 'https://github.com/the-djmaze/snappymail/pull/1466', URL = 'https://github.com/the-djmaze/snappymail/pull/1466',
VERSION = '1.0.2', VERSION = '1.0.3-beta',
RELEASE = '2024-02-23', RELEASE = '2024-03-19',
REQUIRED = '2.34.0', REQUIRED = '2.34.0',
LICENSE = 'AGPL v3', LICENSE = 'AGPL v3',
DESCRIPTION = 'WYSIWYG editor with a compact toolbar'; DESCRIPTION = 'WYSIWYG editor with a compact toolbar';
public function Init(): void public function Init(): void
{ {
$this->addTemplate('templates/PopupsCompactCompose.html'); // $this->addTemplate('templates/PopupsCompactCompose.html');
$this->addCss('css/composer.css'); $this->addCss('css/composer.css');
$this->addJs('js/squire-raw.js'); $this->addJs('js/squire-raw.js');
$this->addJs('js/parsel.js'); $this->addJs('js/parsel.js');

View file

@ -14,34 +14,26 @@
const doc = win.document; const doc = win.document;
// If a user (or admin) selected the CompactComposer we need to addEventListener('rl-view-model', e => {
// replace PopupsCompose template with PopupsCompactCompose template. const vm = e.detail;
// -- if ('PopupsCompose' === vm.viewModelTemplateID && rl.settings.get('editorWysiwyg') === 'CompactComposer') {
// This might break some plugins if they query/change PopupsCompose template vm.querySelector('.tabs label[for="tab-body"]').dataset.bind = "visible: canMailvelope";
// before this code is called. They should instead listen for // Now move the attachments tab to the bottom of the screen
// 'rl-view-model.create' to work properly. const
if (rl.settings.get('editorWysiwyg') === 'CompactComposer') { input = vm.querySelector('.tabs input[value="attachments"]'),
const compactTemplate = doc.getElementById('PopupsCompactCompose'); label = vm.querySelector('.tabs label[for="tab-attachments"]'),
if (!compactTemplate) { area = vm.querySelector('.tabs .attachmentAreaParent');
console.error('CompactComposer: PopupsCompactCompose template not found'); input.remove();
return; label.remove();
} area.remove();
const originalTemplate = doc.getElementById('PopupsCompose'); area.classList.add('compact');
if (originalTemplate) { area.querySelector('.b-attachment-place').dataset.bind = "visible: addAttachmentEnabled(), css: {dragAndDropOver: dragAndDropVisible}";
originalTemplate.id = 'PopupsCompose_replaced'; vm.viewModelDom.append(area);
} else {
console.warn('CompactComposer: PopupsCompose template not found');
}
compactTemplate.id = 'PopupsCompose';
addEventListener('rl-view-model.create', e => {
if (e.detail.viewModelTemplateID === 'PopupsCompose') {
// There is a better way to do this probably, // There is a better way to do this probably,
// but we need this for drag and drop to work // but we need this for drag and drop to work
e.detail.attachmentsArea = e.detail.bodyArea; e.detail.attachmentsArea = e.detail.bodyArea;
} }
}); });
}
const const
removeElements = 'HEAD,LINK,META,NOSCRIPT,SCRIPT,TEMPLATE,TITLE', removeElements = 'HEAD,LINK,META,NOSCRIPT,SCRIPT,TEMPLATE,TITLE',
@ -155,7 +147,7 @@
this.toolbar = toolbar; this.toolbar = toolbar;
toolbar.className = 'squire-toolbar btn-toolbar'; toolbar.className = 'squire-toolbar btn-toolbar';
const actions = this.#makeActions(squire, toolbar); const actions = this.makeActions(squire, toolbar);
this.squire.addEventListener('willPaste', pasteSanitizer); this.squire.addEventListener('willPaste', pasteSanitizer);
this.squire.addEventListener('pasteImage', (e) => { this.squire.addEventListener('pasteImage', (e) => {
@ -300,10 +292,11 @@
* @param {Squire} squire * @param {Squire} squire
* @param {HTMLDivElement} toolbar * @param {HTMLDivElement} toolbar
* @returns {Array} * @returns {Array}
* @private
*/ */
#makeActions(squire, toolbar) { makeActions(squire, toolbar) {
const clr = this.#makeClr(); const clr = this.makeClr();
const doClr = name => input => { const doClr = name => input => {
// https://github.com/the-djmaze/snappymail/issues/826 // https://github.com/the-djmaze/snappymail/issues/826
clr.style.left = (input.offsetLeft + input.parentNode.offsetLeft) + 'px'; clr.style.left = (input.offsetLeft + input.parentNode.offsetLeft) + 'px';
@ -640,11 +633,14 @@
actions: actions actions: actions
} }
})); }));
this.indicators = this.#addActionsToParent(actions, toolbar); this.indicators = this.addActionsToParent(actions, toolbar);
return actions; return actions;
} }
#makeClr() { /**
* @private
*/
makeClr() {
/**@type {HTMLInputElement} clr*/ /**@type {HTMLInputElement} clr*/
const clr = createElement('input'); const clr = createElement('input');
clr.type = 'color'; clr.type = 'color';
@ -675,8 +671,9 @@
/** /**
* @param {Array} items * @param {Array} items
* @param {HTMLElement} parent * @param {HTMLElement} parent
* @private
*/ */
#addActionsToParent(items, parent) { addActionsToParent(items, parent) {
const indicators = []; const indicators = [];
items.forEach(item => { items.forEach(item => {
let element, event; let element, event;
@ -688,7 +685,7 @@
group.className += ' squire-html-mode-item'; group.className += ' squire-html-mode-item';
} }
if (item.items) { if (item.items) {
indicators.push(...this.#addActionsToParent(item.items, group)); indicators.push(...this.addActionsToParent(item.items, group));
} }
parent.append(group); parent.append(group);
return indicators; return indicators;
@ -720,7 +717,7 @@
menu.setAttribute('role', 'menu'); menu.setAttribute('role', 'menu');
if (item.items) { if (item.items) {
indicators.push(...this.#addActionsToParent(item.items, menu)); indicators.push(...this.addActionsToParent(item.items, menu));
} }
menuWrap.appendChild(menu); menuWrap.appendChild(menu);
parent.append(menuWrap); parent.append(menuWrap);

View file

@ -167,6 +167,7 @@
<div class="tab-content" role="tabpanel" aria-hidden="false" style="grid-column-end:3"> <div class="tab-content" role="tabpanel" aria-hidden="false" style="grid-column-end:3">
<div class="textAreaParent" data-bind="initDom: editorArea, attr:{spellcheck:allowSpellcheck()?'true':'false'}"></div> <div class="textAreaParent" data-bind="initDom: editorArea, attr:{spellcheck:allowSpellcheck()?'true':'false'}"></div>
</div> </div>
<input type="radio" name="tabs" value="mailvelope" id="tab-mailvelope" data-bind="checked: viewArea"> <input type="radio" name="tabs" value="mailvelope" id="tab-mailvelope" data-bind="checked: viewArea">
<label for="tab-mailvelope" <label for="tab-mailvelope"
role="tab" role="tab"