Problem/Motivation

When a CKEditor 5 field only has a single permitted text format (either natively or enforced by the allowed_formats module), the text format switcher element (.js-filter-list) is not rendered in the DOM.
In RealtimeAdapter.init(), querySelector('.js-filter-list') returns null, so this.textFormatSelect is explicitly set to null. The addEventListener call on line 68 is correctly guarded, so no error occurs on initialisation.
However, destroy() contains a faulty guard condition:
if (this.textFormatSelect || typeof this.textFormatSelect !== "undefined") {
this.textFormatSelect.removeEventListener('change', this.changeEditor.bind(this));
}
When this.textFormatSelect is null:
null is falsy → first operand is false
typeof null is "object", not "undefined" → second operand is true
The condition evaluates to true, and removeEventListener is called on null, throwing a TypeError

Steps to Reproduce
Install drupal/ckeditor5_premium_features with Real-Time Collaboration enabled.
Configure a text field (e.g. inside a paragraph) with only one permitted text format, or use the allowed_formats module to restrict a field to a single format.
Open a node edit form containing that field.
Navigate away or trigger editor destruction.

Actual Result
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'removeEventListener')
at RealtimeAdapter.destroy

Expected Result
No error. destroy() should safely no-op when textFormatSelect is null.

Proposed Fix
Change the guard in destroy() from:
if (this.textFormatSelect || typeof this.textFormatSelect !== "undefined") {
to:
if (this.textFormatSelect != null) {
This correctly handles both null (querySelector found no element) and undefined (property never assigned), and matches the intent of the existing addEventListener guard in init().

Environment
drupal/ckeditor5_premium_features: 1.8.1
Drupal: 11.x
Triggered by: allowed_formats module + single-format paragraph fields

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

astoker88 created an issue. See original summary.

salmonek’s picture

Status: Active » Reviewed & tested by the community

Hi Alex

Thank you for the report and fix. We have tested it and it works good.

  • salmonek committed fa8ca56a on 1.8.x
    fix: #3589688 by astoker88 RealtimeAdapter.destroy() throws TypeError...
salmonek’s picture

Status: Reviewed & tested by the community » Fixed

Released in 1.8.2

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.