diff --git a/frontend/src/components/CampaignPreview.vue b/frontend/src/components/CampaignPreview.vue index 636cedad..b6a4446b 100644 --- a/frontend/src/components/CampaignPreview.vue +++ b/frontend/src/components/CampaignPreview.vue @@ -22,7 +22,7 @@ > diff --git a/frontend/src/components/Editor.vue b/frontend/src/components/Editor.vue index a5c4cbea..c59e3515 100644 --- a/frontend/src/components/Editor.vue +++ b/frontend/src/components/Editor.vue @@ -36,12 +36,32 @@ - + @@ -83,7 +103,6 @@ import 'tinymce/skins/ui/oxide/skin.css'; import 'tinymce/plugins/autoresize'; import 'tinymce/plugins/autolink'; import 'tinymce/plugins/charmap'; -import 'tinymce/plugins/code'; import 'tinymce/plugins/colorpicker'; import 'tinymce/plugins/contextmenu'; import 'tinymce/plugins/emoticons'; @@ -148,8 +167,10 @@ export default { isEditorFullscreen: false, isReady: false, isRichtextReady: false, + isRichtextSourceVisible: false, richtextConf: {}, isTrackLink: false, + richTextSourceBody: '', form: { body: '', format: this.contentType, @@ -180,13 +201,20 @@ export default { editor.on('init', () => { this.onEditorDialogOpen(editor); }); + + // Custom HTML editor. + editor.ui.registry.addButton('html', { + icon: 'sourcecode', + tooltip: 'Source code', + onAction: this.onRichtextViewSource, + }); }, min_height: 500, entity_encoding: 'raw', convert_urls: true, plugins: [ - 'autoresize', 'autolink', 'charmap', 'code', 'emoticons', 'fullscreen', 'help', + 'autoresize', 'autolink', 'charmap', 'emoticons', 'fullscreen', 'help', 'hr', 'image', 'imagetools', 'link', 'lists', 'paste', 'searchreplace', 'table', 'visualblocks', 'visualchars', 'wordcount', ], @@ -194,7 +222,7 @@ export default { bold italic underline strikethrough forecolor backcolor subscript superscript | alignleft aligncenter alignright alignjustify | bullist numlist table image | outdent indent | link hr removeformat | - code fullscreen help`, + html fullscreen help`, fontsize_formats: '10px 11px 12px 14px 15px 16px 18px 24px 36px', skin: false, content_css: false, @@ -242,6 +270,23 @@ export default { return u; }, + + onRichtextViewSource() { + this.richTextSourceBody = this.form.body; + this.isRichtextSourceVisible = true; + }, + + onFormatRichtextHTML() { + this.richTextSourceBody = this.beautifyHTML(this.richTextSourceBody); + }, + + onSaveRichTextSource() { + this.form.body = this.richTextSourceBody; + window.tinymce.editors[0].setContent(this.form.body); + this.richTextSourceBody = ''; + this.isRichtextSourceVisible = false; + }, + onEditorDialogOpen(editor) { const ed = editor; const oldEd = ed.windowManager.open; @@ -384,7 +429,9 @@ export default { // Preserve line breaks when converting HTML to plaintext. const d = document.createElement('div'); d.innerHTML = this.beautifyHTML(this.form.body); - this.form.body = this.trimLines(d.innerText.trim(), true); + this.$nextTick(() => { + this.form.body = this.trimLines(d.innerText.trim(), true); + }); } else if ((from === 'richtext' || from === 'html') && to === 'markdown') { // richtext, html => markdown this.form.body = turndown.turndown(this.form.body).replace(/\n\n+/ig, '\n\n'); diff --git a/frontend/src/components/HTMLEditor.vue b/frontend/src/components/HTMLEditor.vue index a521755d..00d28f8c 100644 --- a/frontend/src/components/HTMLEditor.vue +++ b/frontend/src/components/HTMLEditor.vue @@ -14,6 +14,7 @@ export default { data() { return { + data: '', flask: null, }; }, @@ -43,8 +44,9 @@ export default { readonly: this.disabled, }); - this.flask.onUpdate((b) => { - this.$emit('input', b); + this.flask.onUpdate((v) => { + this.data = v; + this.$emit('input', v); }); // Set the initial value. @@ -55,5 +57,13 @@ export default { mounted() { this.initHTMLEditor(this.$props.value || ''); }, + + watch: { + value(newVal) { + if (newVal !== this.data) { + this.flask.updateCode(newVal); + } + }, + }, }; diff --git a/frontend/src/views/TemplateForm.vue b/frontend/src/views/TemplateForm.vue index 0342572b..60b12244 100644 --- a/frontend/src/views/TemplateForm.vue +++ b/frontend/src/views/TemplateForm.vue @@ -18,7 +18,7 @@ - +

diff --git a/i18n/cs-cz.json b/i18n/cs-cz.json index 83ab14ea..9165632f 100644 --- a/i18n/cs-cz.json +++ b/i18n/cs-cz.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Neplatná délka jména.", "campaigns.fieldInvalidSendAt": "Naplánované datum by mělo být v budoucnosti.", "campaigns.fieldInvalidSubject": "Neplatná délka předmětu.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Z adresy", "campaigns.fromAddressPlaceholder": "Vaše jméno ", "campaigns.invalid": "Neplatná kampaň", diff --git a/i18n/de.json b/i18n/de.json index fc23bed0..5983eb0d 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Ungültige Länge für `name`.", "campaigns.fieldInvalidSendAt": "Das Datum muss in der Zukunft liegen.", "campaigns.fieldInvalidSubject": "Ungültige Länge für `subject`.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Absender", "campaigns.fromAddressPlaceholder": "Dein Name ", "campaigns.invalid": "Ungültige Kampagne", diff --git a/i18n/en.json b/i18n/en.json index 13944b2c..be423859 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Invalid length for name.", "campaigns.fieldInvalidSendAt": "Scheduled date should be in the future.", "campaigns.fieldInvalidSubject": "Invalid length for subject.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "From address", "campaigns.fromAddressPlaceholder": "Your Name ", "campaigns.invalid": "Invalid campaign", diff --git a/i18n/es.json b/i18n/es.json index 37b7b763..508f3577 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Largo de nombre inválido", "campaigns.fieldInvalidSendAt": "La hora agendada debe ser en el futuro.", "campaigns.fieldInvalidSubject": "Largo de asunto inválido", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Dirección origen", "campaigns.fromAddressPlaceholder": "Su Nombre ", "campaigns.invalid": "Campaña inválida", diff --git a/i18n/fr.json b/i18n/fr.json index b9a95110..b5e4150f 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Longueur du nom invalide.", "campaigns.fieldInvalidSendAt": "La date planifiée doit être future.", "campaigns.fieldInvalidSubject": "Longueur d'objet non valide.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Adresse d'envoi", "campaigns.fromAddressPlaceholder": "Nom à afficher ", "campaigns.invalid": "Campagne non valide", diff --git a/i18n/it.json b/i18n/it.json index 5fc83f88..bc799221 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Lunghezza del nome non valida.", "campaigns.fieldInvalidSendAt": "La data programmata deve essere futura.", "campaigns.fieldInvalidSubject": "Lunghezza dell'oggetto non valida.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Mittente", "campaigns.fromAddressPlaceholder": "Tuo nome ", "campaigns.invalid": "Campagna non valida", diff --git a/i18n/ml.json b/i18n/ml.json index 1fb2d980..13460f8e 100644 --- a/i18n/ml.json +++ b/i18n/ml.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "`name` ന്റെ ദൈർഘ്യം അസാധുവാണ്.", "campaigns.fieldInvalidSendAt": "`send_at` ഭാവിയിലുള്ള തിയതിയായിരിക്കണം.", "campaigns.fieldInvalidSubject": "`subject` ന്റെ ദൈർഘ്യം അസാധുവാണ്.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "പ്രേക്ഷകൻ", "campaigns.fromAddressPlaceholder": "നിങ്ങളുടെ പേര് ", "campaigns.invalid": "ക്യാമ്പേയ്ൻ അസാധുവാണ്", diff --git a/i18n/pl.json b/i18n/pl.json index bcdda382..ccf9e1c1 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Nieprawidłowa długość dla nazwy,", "campaigns.fieldInvalidSendAt": "Zaplanowana data powinna być w przyszłości,", "campaigns.fieldInvalidSubject": "Nieprawidłowa długość tytułu", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Adres od", "campaigns.fromAddressPlaceholder": "Twoja Nazwa ", "campaigns.invalid": "Nieprawidłowa kampania", diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index 3bda1573..8e0e3ace 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Quantidade de caracteres inválida para o nome.", "campaigns.fieldInvalidSendAt": "A data agendada deve ser no futuro.", "campaigns.fieldInvalidSubject": "Quantidade de caracteres inválida para o assunto.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Endereço do remetente", "campaigns.fromAddressPlaceholder": "Seu Nome ", "campaigns.invalid": "Campanha inválida", diff --git a/i18n/pt.json b/i18n/pt.json index 324db8df..bec0dcd6 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Tamanho de nome inválido.", "campaigns.fieldInvalidSendAt": "Data agendada deve ser no futuro.", "campaigns.fieldInvalidSubject": "Tamanho de corpo inválido.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Endereço do Remetente", "campaigns.fromAddressPlaceholder": "O Teu Nome ", "campaigns.invalid": "Campanha inválida", diff --git a/i18n/ro.json b/i18n/ro.json index 49f43aa2..eb061b2b 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Lungime nevalidă pentru nume", "campaigns.fieldInvalidSendAt": "Data programată ar trebui să fie în viitor.", "campaigns.fieldInvalidSubject": "Lungime nevalida pentru subiect.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "De la adresa", "campaigns.fromAddressPlaceholder": "Numele tau ", "campaigns.invalid": "Campanie nevalidă", diff --git a/i18n/ru.json b/i18n/ru.json index 7d5af4ee..539fa85f 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "Неверная длина имени.", "campaigns.fieldInvalidSendAt": "Запланированная дата должна быть позже текущей.", "campaigns.fieldInvalidSubject": "Неверная длина темы.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Адрес отправителя", "campaigns.fromAddressPlaceholder": "Ваше имя ", "campaigns.invalid": "Неверная компания", diff --git a/i18n/tr.json b/i18n/tr.json index ea24a2ff..6b0c5072 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -31,6 +31,7 @@ "campaigns.fieldInvalidName": "İsim uzunluğu yanlış.", "campaigns.fieldInvalidSendAt": "Tanımlanan tarih gelecekte olmalı.", "campaigns.fieldInvalidSubject": "Konu uzunluğu yanlış verilmiş.", + "campaigns.formatHTML": "Format HTML", "campaigns.fromAddress": "Gelen adres", "campaigns.fromAddressPlaceholder": "isminiz ", "campaigns.invalid": "Yanlış tanımlı kapmanya",