Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 17 additions & 13 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,31 @@ packages:
- .
- src/ckeditor

minimumReleaseAge: 4320

minimumReleaseAgeExclude:
- '@ckeditor/*'
- '@cksource/*'
- '*ckeditor5*'

onlyBuiltDependencies:
- "@parcel/watcher"
- '@parcel/watcher'
- core-js
- cypress
- esbuild
- nice-napi
- protobufjs

overrides:
'ajv@^8': '^8.18.0'
'diff@^7': '^8.0.3'
'qs@^6': '^6.14.2'
'serialize-javascript@^6': '^7.0.3'
'tar@^6': '^7.5.11'
'@ckeditor/ckeditor5-integrations-common': link:../../../.local/share/pnpm/global/5/node_modules/@ckeditor/ckeditor5-integrations-common
ajv@^8: ^8.18.0
diff@^7: ^8.0.3
qs@^6: ^6.14.2
serialize-javascript@^6: ^7.0.3
tar@^6: ^7.5.11

minimumReleaseAge: 4320 # 3 days
minimumReleaseAgeExclude:
- '@ckeditor/*'
- '@cksource/*'
- '*ckeditor5*'
preferFrozenLockfile: true

shellEmulator: true
shamefullyHoist: true
preferFrozenLockfile: true

shellEmulator: true
13 changes: 6 additions & 7 deletions src/ckeditor/ckeditor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ import type {
import type { ControlValueAccessor } from '@angular/forms';

import { uid } from '@ckeditor/ckeditor5-integrations-common';
import { appendAllIntegrationPluginsToConfig } from './plugins/append-all-integration-plugins-to-config';
import { DisabledEditorWatchdog } from './disabled-editor-watchdog';
import { assignInitialDataToEditorConfig } from './utils/assignInitialDataToEditorConfig';
import { appendAllIntegrationPluginsToConfig } from './plugins/append-all-integration-plugins-to-config.js';
import { DisabledEditorWatchdog } from './disabled-editor-watchdog.js';
import { assignInitialDataToEditorConfig } from './compatibility/assignInitialDataToEditorConfig.js';

import type { EditorConstructor } from './types.js';

const ANGULAR_INTEGRATION_READ_ONLY_LOCK_ID = 'Lock from Angular integration (@ckeditor/ckeditor5-angular)';

Expand Down Expand Up @@ -80,10 +82,7 @@ export class CKEditorComponent<TEditor extends Editor = Editor> implements After
* The constructor of the editor to be used for the instance of the component.
* It can be e.g. the `ClassicEditorBuild`, `InlineEditorBuild` or some custom editor.
*/
@Input() public editor?: {
create( sourceElementOrData: HTMLElement | string, config?: EditorConfig ): Promise<TEditor>;
EditorWatchdog: typeof EditorWatchdog;
};
@Input() public editor?: EditorConstructor<TEditor>;

/**
* The configuration of the editor.
Expand Down
186 changes: 186 additions & 0 deletions src/ckeditor/compatibility/assignElementToEditorConfig.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/**
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/

import { beforeEach, describe, expect, it } from 'vitest';

import { assignElementToEditorConfig } from './assignElementToEditorConfig.js';
import type { EditorConstructor } from '../types.js';

function createEditorConstructor( editorName?: string ): EditorConstructor {
return { editorName } as unknown as EditorConstructor;
}

describe( 'assignElementToEditorConfig', () => {
let element: HTMLElement;

beforeEach( () => {
element = document.createElement( 'div' );
} );

describe( 'ClassicEditor (attachTo)', () => {
it( 'should assign element to attachTo when editorName is "ClassicEditor"', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'ClassicEditor' ),
element,
{}
);

expect( config.attachTo ).toBe( element );
} );

it( 'should assign element to attachTo when editorName is undefined', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( undefined ),
element,
{}
);

expect( config.attachTo ).toBe( element );
} );

it( 'should preserve other config properties', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'ClassicEditor' ),
element,
{ language: 'pl' }
) as any;

expect( config.language ).toBe( 'pl' );
expect( config.attachTo ).toBe( element );
} );

it( 'should override existing attachTo with the new element', () => {
const oldElement = document.createElement( 'div' );

const config = assignElementToEditorConfig(
createEditorConstructor( 'ClassicEditor' ),
element,
{ attachTo: oldElement }
);

expect( config.attachTo ).toBe( element );
} );

it( 'should not set roots.main.element', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'ClassicEditor' ),
element,
{}
) as any;

expect( config.roots?.main?.element ).toBeUndefined();
} );
} );

describe( 'non-ClassicEditor (roots.main.element)', () => {
it( 'should assign element to roots.main.element for DecoupledEditor', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{}
) as any;

expect( config.roots.main.element ).toBe( element );
} );

it( 'should assign element to roots.main.element for InlineEditor', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'InlineEditor' ),
element,
{}
) as any;

expect( config.roots.main.element ).toBe( element );
} );

it( 'should not set attachTo', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{}
);

expect( config.attachTo ).toBeUndefined();
} );

it( 'should delete config.root after mapping', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{ root: { initialData: 'hello' } }
) as any;

expect( config.root ).toBeUndefined();
} );

it( 'should merge config.root into roots.main', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{ root: { initialData: 'hello' } }
) as any;

expect( config.roots.main.initialData ).toBe( 'hello' );
expect( config.roots.main.element ).toBe( element );
} );

it( 'should merge existing config.roots.main into result', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{ roots: { main: { initialData: 'from-roots' } } }
) as any;

expect( config.roots.main.initialData ).toBe( 'from-roots' );
expect( config.roots.main.element ).toBe( element );
} );

it( 'should let config.roots.main take precedence over config.root', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{
root: { initialData: 'from-root' },
roots: { main: { initialData: 'from-roots-main' } }
}
) as any;

expect( config.roots.main.initialData ).toBe( 'from-roots-main' );
} );

it( 'should preserve other roots alongside main', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{ roots: { outro: { initialData: 'outro' } } }
) as any;

expect( config.roots ).toHaveProperty( 'outro' );
expect( config.roots ).toHaveProperty( 'main' );
} );

it( 'should preserve other top-level config properties', () => {
const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{ language: 'pl' }
) as any;

expect( config.language ).toBe( 'pl' );
} );

it( 'should override existing roots.main.element with the new element', () => {
const oldElement = document.createElement( 'span' );

const config = assignElementToEditorConfig(
createEditorConstructor( 'DecoupledEditor' ),
element,
{ roots: { main: { element: oldElement } } }
) as any;

expect( config.roots.main.element ).toBe( element );
} );
} );
} );
43 changes: 43 additions & 0 deletions src/ckeditor/compatibility/assignElementToEditorConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/

import type { EditorConstructor, EditorRelaxedConfig } from '../types.js';

/**
* Assigns a DOM element to the editor configuration in a way that is compatible with the specific editor type.
*
* @param Editor Constructor of the editor used to determine the location of element config entry.
* @param element Element to be assigned to config.
* @param config Config of the editor.
* @returns The updated configuration object.
*/
export function assignElementToEditorConfig(
Editor: EditorConstructor,
element: HTMLElement,
config: EditorRelaxedConfig
): EditorRelaxedConfig {
if ( !Editor.editorName || Editor.editorName === 'ClassicEditor' ) {
return {
...config,
attachTo: element
};
}

const mappedConfig: EditorRelaxedConfig = {
...config,
roots: {
...config.roots,
main: {
...config.root,
...config.roots?.main,
element
}
}
};

delete mappedConfig.root;

return mappedConfig;
}
Loading