Skip to content

Commit

Permalink
GH-7141: Add ckeditor plugin for mail
Browse files Browse the repository at this point in the history
1)

Move conversion for paragraph to <p style="margin:0;"></p> to plugin

2) Drop schema listener for nested <blockQuote>.

Older versions of ckeditor did not support nested blockquotes[^1].
The schema listener is a workaround to keep nested blockquotes[^2].
CKEditor 28 added support for nested blockquotes back[^3][^4].

[^1]: ckeditor/ckeditor5#419 (comment)
[^2]: ckeditor/ckeditor5#419 (comment)
[^3]: ckeditor/ckeditor5#9382
[^4]: ckeditor/ckeditor5#9472

Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
  • Loading branch information
kesselb committed Sep 6, 2022
1 parent 318b013 commit 2adc96a
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 35 deletions.
53 changes: 53 additions & 0 deletions src/ckeditor/mail/MailPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @author Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license AGPL-3.0-or-later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

import Plugin from '@ckeditor/ckeditor5-core/src/plugin'
import {Paragraph} from '@ckeditor/ckeditor5-paragraph'

export default class Mail extends Plugin {

static get requires() {
return [Paragraph]
}

init() {
this._overwriteParagraphConversion()
}

/**
* Overwrite the elementToElement conversion
* from the default paragraph plugin to add
* margin:0 to every <p>.
*
* @private
*/
_overwriteParagraphConversion() {
this.editor.conversion.elementToElement({
model: 'paragraph',
view: {
name: 'p',
styles: {
'margin': 0,
},
},
converterPriority: 'high',
})
}

}
38 changes: 3 additions & 35 deletions src/components/TextEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import Base64UploadAdapter from '@ckeditor/ckeditor5-upload/src/adapters/base64u
import ImagePlugin from '@ckeditor/ckeditor5-image/src/image'
import ImageResizePlugin from '@ckeditor/ckeditor5-image/src/imageresize'
import ImageUploadPlugin from '@ckeditor/ckeditor5-image/src/imageupload'
import MailPlugin from '../ckeditor/mail/MailPlugin'

import { getLanguage } from '@nextcloud/l10n'

Expand Down Expand Up @@ -108,6 +109,7 @@ export default {
ImageUploadPlugin,
Base64UploadAdapter,
ImageResizePlugin,
MailPlugin,
])
toolbar.unshift(...[
'heading',
Expand Down Expand Up @@ -175,43 +177,9 @@ export default {
* @param {module:core/editor/editor~Editor} editor editor the editor instance
*/
onEditorReady(editor) {
const schema = editor.model.schema

logger.debug('TextEditor is ready', { editor, schema })

logger.debug('TextEditor is ready', {editor})
this.editorInstance = editor

// Set 0 pixel margin to all <p> elements
editor.conversion.for('downcast').add((dispatcher) => {
dispatcher.on(
'insert:paragraph',
(evt, data, conversionApi) => {
const viewWriter = conversionApi.writer
viewWriter.setStyle('margin', '0', conversionApi.mapper.toViewElement(data.item))
},
{
priority: 'low',
}
)
})

schema.on(
'checkChild',
(evt, args) => {
const context = args[0]

if (context.endsWith('blockQuote')) {
// Prevent next listeners from being called.
evt.stop()
// Set the checkChild()'s return value.
evt.return = true
}
},
{
priority: 'highest',
}
)

if (this.focus) {
logger.debug('focusing TextEditor')
editor.editing.view.focus()
Expand Down
40 changes: 40 additions & 0 deletions src/tests/unit/components/MailPlugin.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* @copyright 2022 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @author 2022 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import VirtualTestEditor from '../../virtualtesteditor'
import ParagraphPlugin from '@ckeditor/ckeditor5-paragraph/src/paragraph'
import MailPlugin from '../../../ckeditor/mail/MailPlugin'

describe('MailPlugin', () => {

it('Add margin:0 to paragraph', async() => {
const text = '<p>bonjour bonjour</p>'
const expected = '<p style="margin:0;">bonjour bonjour</p>'

const editor = await VirtualTestEditor.create({
initialData: text,
plugins: [ParagraphPlugin, MailPlugin],
})

expect(editor.getData()).toEqual(expected)
})

})

0 comments on commit 2adc96a

Please sign in to comment.