diff --git a/.yarn/cache/@ckeditor-ckeditor5-editor-decoupled-patch-4948255868-bdaefd4a0b.zip b/.yarn/cache/@ckeditor-ckeditor5-editor-decoupled-patch-4948255868-bdaefd4a0b.zip
new file mode 100644
index 0000000000..3d0898d66b
Binary files /dev/null and b/.yarn/cache/@ckeditor-ckeditor5-editor-decoupled-patch-4948255868-bdaefd4a0b.zip differ
diff --git a/.yarnrc.yml b/.yarnrc.yml
index f53641d9a2..d41dbf526e 100644
--- a/.yarnrc.yml
+++ b/.yarnrc.yml
@@ -35,3 +35,5 @@ changesetIgnorePatterns:
npmAlwaysAuth: false
npmAuthToken: "${NPM_TOKEN-}"
npmPublishAccess: "public"
+
+patchFolder: "./patches"
diff --git a/Tests/IntegrationTests/Fixtures/1Dimension/richTextEditor.e2e.js b/Tests/IntegrationTests/Fixtures/1Dimension/richTextEditor.e2e.js
index 7af31fa28c..35becede17 100644
--- a/Tests/IntegrationTests/Fixtures/1Dimension/richTextEditor.e2e.js
+++ b/Tests/IntegrationTests/Fixtures/1Dimension/richTextEditor.e2e.js
@@ -9,12 +9,12 @@ fixture`Rich text editor`
.beforeEach(beforeEach)
.afterEach(() => checkPropTypes());
-test('Can crop an image', async t => {
+test('Secondary RTE editor works', async t => {
const testContent = 'Test RTE content';
await Page.waitForIframeLoading(t);
const rteInspectorEditor = await ReactSelector('InspectorEditorEnvelope').withProps('id', 'rte');
- const ckeContent = await Selector('.ck-content p');
+ const ckeContent = await Selector('.ck-content');
await t
.click(rteInspectorEditor.findReact('Button'));
await t
diff --git a/Tests/IntegrationTests/SharedNodeTypesPackage/NodeTypes/Content/InlineHeadline.yaml b/Tests/IntegrationTests/SharedNodeTypesPackage/NodeTypes/Content/InlineHeadline.yaml
index dc8217b52f..1eb0eb5638 100644
--- a/Tests/IntegrationTests/SharedNodeTypesPackage/NodeTypes/Content/InlineHeadline.yaml
+++ b/Tests/IntegrationTests/SharedNodeTypesPackage/NodeTypes/Content/InlineHeadline.yaml
@@ -21,7 +21,7 @@
inlineEditable: true
inline:
editorOptions:
- autoparagraph: false
+ isInline: true
# we show it also in the inspector so we can easily see the raw text content
inspector:
group: 'default'
diff --git a/package.json b/package.json
index d4b48acbc2..c22807a38d 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,8 @@
"moment": "^2.20.1",
"vfile-message": "^2.0.2",
"isemail@3.2.0": "patch:isemail@npm:3.2.0#./patches/isemail-npm-3.2.0-browserified.patch",
- "react-codemirror2@7.2.1": "patch:react-codemirror2@npm:7.2.1#./patches/react-codemirror2-npm-7.2.1-browserified.patch"
+ "react-codemirror2@7.2.1": "patch:react-codemirror2@npm:7.2.1#./patches/react-codemirror2-npm-7.2.1-browserified.patch",
+ "@ckeditor/ckeditor5-editor-decoupled@16.0.0": "patch:@ckeditor/ckeditor5-editor-decoupled@npm:16.0.0#./patches/@ckeditor-ckeditor5-editor-decoupled-npm-16.0.0-inline-mode.patch"
},
"scripts": {
"lint": "tsc --noemit && stylelint 'packages/*/src/**/*.css' && yarn eslint 'packages/*/src/**/*.{js,jsx,ts,tsx}'",
diff --git a/packages/neos-ui-ckeditor5-bindings/package.json b/packages/neos-ui-ckeditor5-bindings/package.json
index d410ed467f..8691059b93 100644
--- a/packages/neos-ui-ckeditor5-bindings/package.json
+++ b/packages/neos-ui-ckeditor5-bindings/package.json
@@ -8,7 +8,7 @@
"@ckeditor/ckeditor5-alignment": "^16.0.0",
"@ckeditor/ckeditor5-basic-styles": "^16.0.0",
"@ckeditor/ckeditor5-core": "^16.0.0",
- "@ckeditor/ckeditor5-editor-decoupled": "^16.0.0",
+ "@ckeditor/ckeditor5-editor-decoupled": "16.0.0",
"@ckeditor/ckeditor5-engine": "^16.0.0",
"@ckeditor/ckeditor5-essentials": "^16.0.0",
"@ckeditor/ckeditor5-heading": "^16.0.0",
diff --git a/packages/neos-ui-ckeditor5-bindings/src/ckEditorApi.js b/packages/neos-ui-ckeditor5-bindings/src/ckEditorApi.js
index fa7f56352a..caec7d982a 100644
--- a/packages/neos-ui-ckeditor5-bindings/src/ckEditorApi.js
+++ b/packages/neos-ui-ckeditor5-bindings/src/ckEditorApi.js
@@ -44,6 +44,16 @@ export const createEditor = store => async options => {
propertyDomNode
});
+ const isInline = editorOptions?.isInline === true ||
+ propertyDomNode.tagName === 'SPAN' ||
+ propertyDomNode.tagName === 'H1' ||
+ propertyDomNode.tagName === 'H2' ||
+ propertyDomNode.tagName === 'H3' ||
+ propertyDomNode.tagName === 'H4' ||
+ propertyDomNode.tagName === 'H5' ||
+ propertyDomNode.tagName === 'H6' ||
+ propertyDomNode.tagName === 'P';
+
class NeosEditor extends DecoupledEditor {
constructor(...args) {
super(...args);
@@ -55,7 +65,7 @@ export const createEditor = store => async options => {
}
return NeosEditor
- .create(propertyDomNode, ckEditorConfig)
+ .create(propertyDomNode, ckEditorConfig, /* this option is introduced via patch */ isInline)
.then(editor => {
editor.ui.focusTracker.on('change:isFocused', event => {
if (event.source.isFocused) {
diff --git a/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.js b/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.js
index 3ce6672bcd..3ca7f3be31 100644
--- a/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.js
+++ b/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.js
@@ -4,20 +4,5 @@ export const cleanupContentBeforeCommit = content => {
if (content.match(/^<([a-z][a-z0-9]*)\b[^>]*> <\/\1>$/)) {
return '';
}
-
- // We remove opening and closing span tags that are produced by the `DisabledAutoparagraphMode` plugin
- if (content.startsWith('') && content.endsWith('')) {
- const contentWithoutOuterSpan = content
- .replace(/^/, '')
- .replace(/<\/span>$/, '');
-
- if (contentWithoutOuterSpan.includes('')) {
- // In case there is still a span tag, we can be sure that the previously trimmed ones were belonging together,
- // as it could be the case that multiple root paragraph/span elements were inserted into the ckeditor
- // (which is currently not prevented if the html is modified from outside), so we will preserve the output.
- return content;
- }
- return contentWithoutOuterSpan;
- }
return content;
};
diff --git a/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.spec.js b/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.spec.js
index 96cc21e9a8..08e5603a64 100644
--- a/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.spec.js
+++ b/packages/neos-ui-ckeditor5-bindings/src/cleanupContentBeforeCommit.spec.js
@@ -8,27 +8,3 @@ test('remove empty nbsp', () => {
assertCleanedUpContent('
', '');
assertCleanedUpContent(' ', '');
})
-
-describe('ckeditor DisabledAutoparagraphMode hack, cleanup outer spans', () => {
- test('noop', () => {
- assertCleanedUpContent('', '');
-
- assertCleanedUpContent('', '');
-
- assertCleanedUpContent('foo', 'foo');
- })
-
- test('cleanup single root ', () => {
- assertCleanedUpContent('', '');
- assertCleanedUpContent('foo', 'foo');
- })
-
- test('cleanup multiple root ', () => {
- assertCleanedUpContent('foobar', 'foobar');
- })
-
- test('cleanup root after other root', () => {
- // in the case you had multiple paragraphs and a headline and switched to autoparagraph: false
- assertCleanedUpContent('foo
bar', 'foo
bar');
- })
-})
diff --git a/packages/neos-ui-ckeditor5-bindings/src/manifest.config.js b/packages/neos-ui-ckeditor5-bindings/src/manifest.config.js
index 70e25db8af..f912217577 100644
--- a/packages/neos-ui-ckeditor5-bindings/src/manifest.config.js
+++ b/packages/neos-ui-ckeditor5-bindings/src/manifest.config.js
@@ -33,18 +33,6 @@ const addPlugin = (Plugin, isEnabled) => (ckEditorConfiguration, options) => {
return ckEditorConfiguration;
};
-// If the editable is a span or a heading, we automatically disable paragraphs and enable the soft break mode
-// Also possible to force this behavior with `autoparagraph: false`
-const disableAutoparagraph = (editorOptions, {propertyDomNode}) =>
- editorOptions?.autoparagraph === false ||
- propertyDomNode.tagName === 'SPAN' ||
- propertyDomNode.tagName === 'H1' ||
- propertyDomNode.tagName === 'H2' ||
- propertyDomNode.tagName === 'H3' ||
- propertyDomNode.tagName === 'H4' ||
- propertyDomNode.tagName === 'H5' ||
- propertyDomNode.tagName === 'H6';
-
//
// Create richtext editing toolbar registry
//
@@ -102,7 +90,8 @@ export default ckEditorRegistry => {
//
config.set('essentials', addPlugin(Essentials));
config.set('paragraph', addPlugin(Paragraph));
- config.set('disabledAutoparagraphMode', addPlugin(DisabledAutoparagraphMode, disableAutoparagraph));
+ // @deprecated
+ config.set('disabledAutoparagraphMode', addPlugin(DisabledAutoparagraphMode, (editorOptions) => editorOptions?.autoparagraph === false));
config.set('sub', addPlugin(Sub, $get('formatting.sub')));
config.set('sup', addPlugin(Sup, $get('formatting.sup')));
config.set('bold', addPlugin(Bold, $get('formatting.strong')));
diff --git a/packages/neos-ui-ckeditor5-bindings/src/plugins/disabledAutoparagraphMode.js b/packages/neos-ui-ckeditor5-bindings/src/plugins/disabledAutoparagraphMode.js
index 17d42ef41e..5956110ac5 100644
--- a/packages/neos-ui-ckeditor5-bindings/src/plugins/disabledAutoparagraphMode.js
+++ b/packages/neos-ui-ckeditor5-bindings/src/plugins/disabledAutoparagraphMode.js
@@ -1,10 +1,8 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
/**
- * HACK, since there is yet no native support for CKEditor 4 autoparagraph false
- * see https://github.com/ckeditor/ckeditor5/issues/762
- *
- * We will try to find a serious alternative see https://github.com/neos/neos-ui/pull/3553
+ * Legacy HACK -> our previous "inlineMode" the `autoparagraph: false` mode (from CKEditor 4) for backwards compatibility
+ * @deprecated in favour of the serious "inlineMode"
*/
export default class DisabledAutoparagraphMode extends Plugin {
static get pluginName() {
diff --git a/packages/neos-ui-ckeditor5-bindings/tests/manual/index.js b/packages/neos-ui-ckeditor5-bindings/tests/manual/index.js
index 8b1d73e9b4..1113368d4b 100644
--- a/packages/neos-ui-ckeditor5-bindings/tests/manual/index.js
+++ b/packages/neos-ui-ckeditor5-bindings/tests/manual/index.js
@@ -34,7 +34,7 @@ createInlineEditor({
propertyDomNode: document.getElementById('input'),
propertyName: 'test',
editorOptions: {
- autoparagraph: false,
+ isInline: true,
formatting: {
h1: true,
h2: true,
diff --git a/packages/neos-ui-editors/src/Editors/Image/index.js b/packages/neos-ui-editors/src/Editors/Image/index.js
index 539b1fb24e..f94f7fa457 100644
--- a/packages/neos-ui-editors/src/Editors/Image/index.js
+++ b/packages/neos-ui-editors/src/Editors/Image/index.js
@@ -57,7 +57,7 @@ export default class ImageEditor extends Component {
accept: PropTypes.string,
siteNodePath: PropTypes.string.isRequired,
- focusedNodePath: PropTypes.string.isRequired,
+ focusedNodePath: PropTypes.string.isRequired
};
static defaultProps = {
diff --git a/patches/@ckeditor-ckeditor5-editor-decoupled-npm-16.0.0-inline-mode.patch b/patches/@ckeditor-ckeditor5-editor-decoupled-npm-16.0.0-inline-mode.patch
new file mode 100644
index 0000000000..0f5a8ba4f7
--- /dev/null
+++ b/patches/@ckeditor-ckeditor5-editor-decoupled-npm-16.0.0-inline-mode.patch
@@ -0,0 +1,64 @@
+
+fixes https://github.com/neos/neos-ui/issues/3545
+
+diff --git a/src/decouplededitor.js b/src/decouplededitor.js
+index 807e531075bdbded8a34a15ddc5fe50370e0fd61..73afd7a95c8d6b9adf16fe48bf4774d0cfade361 100755
+--- a/src/decouplededitor.js
++++ b/src/decouplededitor.js
+@@ -64,7 +64,7 @@ export default class DecoupledEditor extends Editor {
+ * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.
+ * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
+ */
+- constructor( sourceElementOrData, config ) {
++ constructor( sourceElementOrData, config, isInlineMode ) {
+ super( config );
+
+ if ( isElement( sourceElementOrData ) ) {
+@@ -74,7 +74,25 @@ export default class DecoupledEditor extends Editor {
+
+ this.data.processor = new HtmlDataProcessor();
+
+- this.model.document.createRoot();
++ if (isInlineMode === false) {
++ this.model.document.createRoot();
++ } else {
++ // patched ala https://github.com/ckeditor/ckeditor5/issues/762#issuecomment-370762111
++
++ // we define paragraph as root instead of $root. This will give us no outer tags out of the box and also disable the splitting
++ this.model.document.createRoot('paragraph');
++
++ // it is enforced that the root cannot be splitted, but to make this obvious for other plugins we set isLimit
++ this.on('ready', () => this.model.schema.extend('paragraph', {isLimit: true}));
++
++ // we redefine enter key to create soft breaks (
) instead of new paragraphs
++ this.editing.view.document.on('enter', (evt, data) => {
++ this.execute('shiftEnter');
++ data.preventDefault();
++ evt.stop();
++ this.editing.view.scrollToTheSelection();
++ }, {priority: 'high'});
++ }
+
+ const shouldToolbarGroupWhenFull = !this.config.get( 'toolbar.shouldNotGroupWhenFull' );
+ const view = new DecoupledEditorUIView( this.locale, this.editing.view, {
+@@ -218,9 +236,10 @@ export default class DecoupledEditor extends Editor {
+ * {@link module:editor-decoupled/decouplededitorui~DecoupledEditorUI#getEditableElement `editor.ui.getEditableElement()`}.
+ *
+ * @param {module:core/editor/editorconfig~EditorConfig} [config] The editor configuration.
++ * @param {Boolean} isInlineMode Patched inline mode https://github.com/ckeditor/ckeditor5/issues/762#issuecomment-370762111
+ * @returns {Promise} A promise resolved once the editor is ready. The promise resolves with the created editor instance.
+ */
+- static create( sourceElementOrData, config = {} ) {
++ static create( sourceElementOrData, config = {}, isInlineMode ) {
+ return new Promise( resolve => {
+ const isHTMLElement = isElement( sourceElementOrData );
+
+@@ -230,7 +249,7 @@ export default class DecoupledEditor extends Editor {
+ 'editor-wrong-element: This type of editor cannot be initialized inside