Skip to content

fix: upgrade TinyMCE to v7 and remove the premium plugin stub package - #3245

Open
bradenmacdonald wants to merge 3 commits into
openedx:masterfrom
open-craft:braden/tinymce-7-upgrade
Open

bradenmacdonald wants to merge 3 commits into
openedx:masterfrom
open-craft:braden/tinymce-7-upgrade

Conversation

@bradenmacdonald

Copy link
Copy Markdown
Contributor

Description

Upgrades TinyMCE from 5.10 to 7.9 (supersedes #3176, renovate's security bump, which fails tests and would break the editor at runtime) and removes the frontend-components-tinymce-advanced-plugins dependency, replacing it with a configuration-based way to load premium plugins.

This affects Course Authors and Library Authors (all rich text editors: HTML/Text, Problem, hints, feedback, expandable text areas, course updates, schedule & details) and Operators (new configuration keys, license change, dependency removal).

Why the renovate PR alone was not mergeable

  1. tinymce.editors was removed in v7. The problem editor used it to collect answer/hint/feedback content and to check dirty state. This was the cause of the two failing tests. It now uses the public tinymce.get() API and reads each editor's id.
  2. A second TinyMCE core was being bundled. frontend-components-tinymce-advanced-plugins pins tinymce ^5.10.4, so with v7 at the root npm nested a separate TinyMCE 5 copy under it. The app imported all of its standard plugins through that package, so the bundle contained two cores, and the v5 one overwrote window.tinymce, which is what @tinymce/tinymce-react reads. The editor would have been broken in the browser even though the unit tests didn't catch it.
  3. Other v5 to v7 breaking changes in our config:
    • The hr and imagetools plugins no longer exist (hr is now a core button). The "Edit Image Settings" context toolbar that imagetools_toolbar used to provide is re-registered as a plain context toolbar on <img> nodes.
    • The formatselect toolbar item was renamed to blocks.
    • The dom model and each core plugin now have to be imported explicitly.
    • v7 logs a "running in evaluation mode" warning unless a license key is declared (licenseKey="gpl" on the React Editor).

Removal of frontend-components-tinymce-advanced-plugins

That package only shipped no-op stubs for the paid a11ychecker and powerpaste plugins, is still on TinyMCE 5 upstream (a renovate PR bumping it was closed), and re-exports plugins that no longer exist. It is removed entirely. Operators who have licensed the premium plugins can now load them through env.config.jsx:

  • TINYMCE_EXTERNAL_PLUGINS: { pluginName: 'https://.../plugin.min.js' }, passed to TinyMCE's built-in external_plugins loader. Configuring a11ychecker restores its toolbar button; configuring powerpaste restores the paste defaults the app previously set.
  • TINYMCE_LICENSE_KEY: the commercial license key that premium plugins in v7 require (defaults to gpl).
  • TINYMCE_PLUGIN_OPTIONS: extra init options for those plugins.

Documented in the README under "Feature: New React XBlock Editors", with a test in pluginConfig.test.

Behavior changes to be aware of

  • License: TinyMCE 7 is GPL-2.0-or-later (v5 was LGPL-2.1). Compatible with this AGPL project, but worth a deliberate acknowledgement.
  • Content sanitization (the CVE fix): I ran v7's parser against course-style HTML with this app's permissive valid_elements: '*[*]'. <script> tags and inline event handlers are preserved exactly as v5 did, so existing course content is not stripped. The one change is the fix for CVE-2024-29881 itself: convert_unsafe_embeds is on by default, so <object>/<embed> are rewritten to <iframe>/<img>/<video>/<audio> (by MIME type) when content is loaded and re-saved.
  • Pasting images: paste moved into core in v6 with paste_data_images defaulting to true, so pasted screenshots now land in the content as base64 data URIs (v5 dropped them). Left at the default; easy to set to false if we would rather not allow it.
  • Focus outline: v7 enables highlight_on_focus by default, adding a blue outline around the focused editor.

Test-suite note

Removing the stub plugin names exposed that the jest suite has always relied on TinyMCE never finishing initialization under JSDOM: previously the editor silently hung trying to fetch the (mocked) a11ychecker/powerpaste scripts over the network. With every plugin genuinely registered, the editor initialized for real and crashed inside the theme's sizing code, which JSDOM can't support. src/setupTest.js now stubs tinymce/themes/silver to make that dependency explicit. Browser behavior is unaffected.

Supporting information

Testing instructions

Automated: full jest suite (568 suites), npm run types, npm run lint, and npm run build all pass. The production bundle contains exactly one TinyMCE core (7.9.3).

Manual:

  1. Open the Text/HTML editor on a course unit. Check the toolbar renders (including the block format dropdown, horizontal rule, table, emoji, charmap, code sample, "HTML" source button, embed iframe), that formatting works, and that content saves and reloads correctly. There should be no "evaluation mode" or "failed to load plugin" messages in the console or editor.
  2. Insert an image, then click it: the "Edit Image Settings" context toolbar should appear and open the image settings modal. Resizing the image should still sync dimensions.
  3. Open the Problem editor for a multiple choice problem: edit the question, answers, hints and feedback; add/delete answers (deleting shifts later answers' content into the earlier editors); switch to the advanced editor and back; save. Also check the "unsaved changes" warning on close still triggers only after editing.
  4. Try the expandable text areas (answers/feedback) and confirm the floating quick toolbar still works.
  5. Course Updates and Schedule & Details pages also embed the editor; do a quick check there.
  6. Optional (operators): set TINYMCE_EXTERNAL_PLUGINS / TINYMCE_LICENSE_KEY in env.config.jsx and confirm the plugins load and the a11ycheck button appears.

Other information

  • No dependency on other changes. The upstream frontend-components-tinymce-advanced-plugins package no longer needs a TinyMCE 7 release for this MFE.
  • Operators who were substituting their own build of that package to get the premium plugins must switch to the new TINYMCE_* configuration keys.

Best Practices Checklist

  • Any new files are using TypeScript (.ts, .tsx).
  • Avoid propTypes and defaultProps in any new or modified code. (No new usages; the pre-existing ones in TinyMceWidget are untouched.)
  • Tests should use the helpers in src/testUtils.tsx (specifically initializeMocks) (N/A: the new test is a pure config test; existing tests were adapted in place.)
  • Do not add new fields to the Redux state/store.
  • Use React Query to load data from REST APIs. (N/A)
  • All new i18n messages in messages.ts files have a description. (N/A)
  • Avoid using ../ in import paths. (No new relative imports added.)

🤖 Generated with Claude Code

renovate Bot and others added 2 commits September 11, 2026 21:56
TinyMCE 5 -> 7 removed several APIs and plugins this app relied on:

- `tinymce.editors` is gone; the problem editor now uses `tinymce.get()`
  to collect answer/hint/feedback content and check dirty state.
- The `hr` and `imagetools` plugins were removed (the `hr` button is now
  core). The "Edit Image Settings" context toolbar that imagetools used to
  provide is re-registered as a plain context toolbar.
- The `formatselect` toolbar item was renamed to `blocks`.
- The `dom` model and each core plugin must now be imported explicitly.
- TinyMCE 7 is GPL-2.0-or-later; `licenseKey="gpl"` silences its
  evaluation-mode warning.

`frontend-components-tinymce-advanced-plugins` is removed as a dependency.
It pinned TinyMCE 5 (pulling a second core into the bundle that clobbered
`window.tinymce`) and only shipped no-op stubs for the paid a11ychecker and
powerpaste plugins. Operators who have licensed those plugins can now load
them via `TINYMCE_EXTERNAL_PLUGINS`, `TINYMCE_LICENSE_KEY` and
`TINYMCE_PLUGIN_OPTIONS` in env.config.jsx (see README).

The jest setup now stubs `tinymce/themes/silver` so the editor never
finishes initializing under JSDOM, which the test suite has always
implicitly relied on (previously the stubbed plugins hung initialization).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@openedx-webhooks

Copy link
Copy Markdown

Thanks for the pull request, @bradenmacdonald!

This repository is currently maintained by @bradenmacdonald.

Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review.

🔘 Get product approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

Details
Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@openedx-webhooks openedx-webhooks added open-source-contribution PR author is not from Axim or 2U core contributor PR author is a Core Contributor (who may or may not have write access to this repo). labels Sep 11, 2026
@github-project-automation github-project-automation Bot moved this to Needs Triage in Contributions Sep 11, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 96.03%. Comparing base (87cba01) to head (ca38df9).

Files with missing lines Patch % Lines
...rc/editors/sharedComponents/TinyMceWidget/hooks.ts 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3245      +/-   ##
==========================================
- Coverage   96.03%   96.03%   -0.01%     
==========================================
  Files        1407     1407              
  Lines       34287    34295       +8     
  Branches     7882     8148     +266     
==========================================
+ Hits        32928    32935       +7     
+ Misses       1318     1304      -14     
- Partials       41       56      +15     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core contributor PR author is a Core Contributor (who may or may not have write access to this repo). open-source-contribution PR author is not from Axim or 2U

Projects

Status: Needs Triage

Development

Successfully merging this pull request may close these issues.

2 participants