diff --git a/src/components/AppSettingsMenu.vue b/src/components/AppSettingsMenu.vue index e7f0cb7a4a..10d0834546 100755 --- a/src/components/AppSettingsMenu.vue +++ b/src/components/AppSettingsMenu.vue @@ -312,7 +312,8 @@ :is-form="true" size="normal"> - +
+ @show-toolbar="handleShowToolbar" + ref="textEditor" />

{{ t('mail', 'Your signature is larger than 2 MB. This may affect the performance of your editor.') }}

@@ -84,6 +86,7 @@ export default { identity: null, signature: '', signatureAboveQuote: this.account.signatureAboveQuote, + toolbarElement: null, } }, computed: { @@ -125,6 +128,12 @@ export default { } }, }, + toolbarElement(newEl) { + if (newEl && this.$refs.toolbarContainer) { + this.$refs.toolbarContainer.innerHTML = '' + this.$refs.toolbarContainer.appendChild(newEl) + } + }, beforeMount() { this.changeIdentity(this.identities[0]) }, @@ -145,7 +154,7 @@ export default { const payload = { account: this.account, - signature: this.signature, + signature: this.$refs.textEditor.convertImageClassesToInlineStyles(this.signature), } if (this.identity.id > -1) { @@ -215,6 +224,7 @@ export default { display: block; padding: 0; margin-bottom: 23px; + height: 100%; } .ck-balloon-panel { diff --git a/src/components/TextEditor.vue b/src/components/TextEditor.vue index 103a981191..467f8c301e 100644 --- a/src/components/TextEditor.vue +++ b/src/components/TextEditor.vue @@ -47,6 +47,13 @@ import ImagePlugin from '@ckeditor/ckeditor5-image/src/image.js' import FindAndReplace from '@ckeditor/ckeditor5-find-and-replace/src/findandreplace.js' import ImageResizePlugin from '@ckeditor/ckeditor5-image/src/imageresize.js' import ImageUploadPlugin from '@ckeditor/ckeditor5-image/src/imageupload.js' +import ImageStylePlugin from '@ckeditor/ckeditor5-image/src/imagestyle.js' +import { + ImageToolbarPlugin, + ImageUtilsPlugin, + ImageCaptionPlugin, + ImageTextAlternativePlugin, +} from '@ckeditor/ckeditor5-image' import GeneralHtmlSupport from '@ckeditor/ckeditor5-html-support/src/generalhtmlsupport.js' import { DropdownView } from '@ckeditor/ckeditor5-ui' import MailPlugin from '../ckeditor/mail/MailPlugin.js' @@ -129,6 +136,11 @@ export default { ImagePlugin, ImageUploadPlugin, ImageResizePlugin, + ImageStylePlugin, + ImageToolbarPlugin, + ImageUtilsPlugin, + ImageCaptionPlugin, + ImageTextAlternativePlugin, ListProperties, FontPlugin, RemoveFormat, @@ -196,6 +208,18 @@ export default { }, ], }, + image: { + toolbar: [ + 'imageStyle:alignLeft', + 'imageStyle:alignCenter', + 'imageStyle:alignRight', + '|', + 'imageTextAlternative', + ], + styles: [ + 'alignLeft', 'alignCenter', 'alignRight', + ], + }, }, } }, @@ -278,6 +302,44 @@ export default { return itemElement }, + convertImageClassesToInlineStyles(html) { + const div = document.createElement('div') + div.innerHTML = html + + div.querySelectorAll('figure.image').forEach(figure => { + // Keep the original style attribute + const baseStyle = figure.getAttribute('style') || '' + let alignmentStyle = 'display:block;margin-top:1em;margin-bottom:1em;' + + if (figure.classList.contains('image-style-align-left')) { + alignmentStyle += 'margin-left:0;margin-right:auto;' + } else if (figure.classList.contains('image-style-align-right')) { + alignmentStyle += 'margin-left:auto;margin-right:0;' + } else if (figure.classList.contains('image-style-align-center')) { + alignmentStyle += 'margin-left:auto;margin-right:auto;text-align:center;' + } + + // Combine original styles with alignment styles + const combinedStyle = `${baseStyle.trim()}${!baseStyle.endsWith(';') ? ';' : ''}${alignmentStyle}` + figure.setAttribute('style', combinedStyle) + + // IMPORTANT: Do NOT remove alignment classes + // so CKEditor can reuse them when reopening the content + + // Adjust the inside the figure to ensure correct display in email clients + const img = figure.querySelector('img') + if (img) { + const baseImgStyle = img.getAttribute('style') || '' + const imgStyle = 'display:block;margin:0 auto;max-width:100%;height:auto;border:0;' + img.setAttribute( + 'style', + `${baseImgStyle.trim()}${!baseImgStyle.endsWith(';') ? ';' : ''}${imgStyle}`, + ) + } + }) + + return div.innerHTML + }, overrideDropdownPositionsToNorth(editor, toolbarView) { const { south, north, southEast, southWest, northEast, northWest, diff --git a/src/components/textBlocks/ListItem.vue b/src/components/textBlocks/ListItem.vue index caf597d82b..bc410162c5 100644 --- a/src/components/textBlocks/ListItem.vue +++ b/src/components/textBlocks/ListItem.vue @@ -35,7 +35,8 @@ {{ localTextBlock.title }}

-