8000 fix: Structure board update sometimes failed to add all interactive elements by fsbraun · Pull Request #8227 · django-cms/django-cms · GitHub
[go: up one dir, main page]

Skip to content

fix: Structure board update sometimes failed to add all interactive elements #8227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 14, 2025

Conversation

fsbraun
Copy link
Member
@fsbraun fsbraun commented May 13, 2025

Description

When opening the edit endpoint under (not entirely clear) circumstances not all plugin data inside the structure markup is recognized. This leads to some items in the structure board to be missing interaction handlers.

Reason is an outdated regex for inline javascript (which has been removed in django CMS 5.0).

Related resources

Screen_Recording_2025-05-13_at_16.36.54.mov
  • #...
  • #...

Checklist

  • I have opened this pull request against main
  • I have added or modified the tests when changing logic
  • I have followed the conventional commits guidelines to add meaningful information into the changelog
  • I have read the contribution guidelines and I have joined the channel #pr-reviews on our Discord Server to find a “pr review buddy” who is going to review my pull request.

Summary by Sourcery

Fix struct 8000 ure board update to reliably add all interactive elements by replacing outdated regex-based parsing with native DOM querying and update associated tests.

Bug Fixes:

  • Replace outdated inline-JS regex to ensure all plugins in the structure board load their interaction handlers correctly

Enhancements:

  • Refactor structure board content parsing to use plain JS (document.createElement, querySelector) instead of jQuery and regex
  • Simplify plugin registry update to accept parsed plugin data directly
  • Revise _getPluginDataFromMarkup to extract plugin settings from <script> elements

Tests:

  • Update unit tests to pass a DOM node to _getPluginDataFromMarkup and validate the new plugin data extraction output

Copy link
Contributor
sourcery-ai bot commented May 13, 2025

Reviewer's Guide

Refactors structure board parsing from regex/jQuery to DOM-based methods by using a div container, document.querySelector, and JSON-parsed script tags, updates the _getPluginDataFromMarkup signature and Plugin._updateRegistry invocation, and adjusts unit tests to match the new data extraction approach.

File-Level Changes

Change Details Files
Refactor structure markup parsing to use plain DOM methods
  • Replace jQuery body parsing via regex.exec and $ with document.createElement('div') and innerHTML
  • Switch selectors from jQuery .find to querySelector/querySelectorAll wrapped in $ as needed
  • Remove custom body.filter logic for cms-template scripts
cms/static/cms/js/modules/cms.structureboard.js
Simplify plugin data extraction by querying script tags instead of regex
  • Change _getPluginDataFromMarkup to accept a DOM node instead of a markup string
  • Replace regex.exec on markup with body.querySelector by script ID and JSON.parse of textContent
  • Update Plugin._updateRegistry call to pass the full pluginData array
cms/static/cms/js/modules/cms.structureboard.js
Update unit tests for _getPluginDataFromMarkup to match new signature and output
  • Wrap test markup in a
    node instead of passing raw string
  • Adjust args to provide a DOM node and plugin IDs array
  • Update expected results to arrays of settings objects rather than id/data tuples
cms/tests/frontend/unit/cms.structureboard.test.js

Possibly linked issues

  • #0: PR fixes structure board update causing missing interactive elements, matching issue where add plugin button fails.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@fsbraun fsbraun requested a review from jrief May 13, 2025 19:16
Copy link
Contributor
@jrief jrief left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this PR request fixes our problem. Thanks @fsbraun

@fsbraun fsbraun marked this pull request as ready for review May 14, 2025 07:02
Copy link
Contributor
@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @fsbraun - I've reviewed your changes - here's some feedback:

  • Cache the result of bodyRegex.exec(contentMarkup) (or remove the “g” flag) to avoid running the regex twice and guard against null matches before accessing the capture group.
  • Consider using DOMParser.parseFromString instead of creating a div and setting innerHTML directly for more robust and secure HTML parsing.
Here's what I looked at during the review
  • 🟡 General issues: 2 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -395,22 +395,20 @@ class StructureBoard {
CMS.settings.states = Helpers.getSettings().states;

const bodyRegex = /<body[\S\s]*?>([\S\s]*)<\/body>/gi;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Remove the global flag from bodyRegex to avoid stateful exec issues

RegExp.exec with g is stateful and can return null on reuse; remove the g flag since only a single match is needed.

Suggested change
const bodyRegex = /<body[\S\s]*?>([\S\s]*)<\/body>/gi;
const bodyRegex = /<body[\S\s]*?>([\S\s]*)<\/body>/i;

const pluginIds = this.getIds(body.find('.cms-draggable'));
const pluginDataSource = body.filter('script[data-cms]').toArray()
.map(script => script.textContent || '').join();
body.innerHTML = bodyRegex.exec(contentMarkup)[1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Guard against null return from exec before indexing

Assign bodyRegex.exec(contentMarkup) to a variable and verify it’s not null before accessing [1] to prevent a runtime error when there’s no match.

@vinitkumar vinitkumar merged commit de313e7 into main May 14, 2025
66 checks passed
@fsbraun fsbraun deleted the fix/data-bridge branch May 14, 2025 07:40
fsbraun added a commit that referenced this pull request May 14, 2025
…lements (#8227)

* fix: Scan plugin data after structure mode Xhr load

* Fix test

* fix js linting issues
@fsbraun fsbraun restored the fix/data-bridge branch May 14, 2025 12:03
fsbraun added a commit that referenced this pull request May 14, 2025
…lements (#8227)

* fix: Scan plugin data after structure mode Xhr load

* Fix test

* fix js linting issues
vinitkumar pushed a commit that referenced this pull request May 21, 2025
* [5.1.0dev1 release process] Bumped version to 5.1.0dev1

* [5.1.0dev1 release process] compilemessages

* [5.1.0dev1 release process] compiling new static files

* [5.1.0dev1 release process] updating latest docs

* Prepare new main branch

* Fix typos

* fix: No changes to changelog

* fix: Remove unnecessary change to migration

* Remove circular import

* Fix import order

* Re-introduce dummy `PlaceholderField` for legacy migrations

* fix: Do not assume page url cache to be filled

* fix: Structure board update sometimes failed to add all interactive elements (#8227)

* fix: Scan plugin data after structure mode Xhr load

* Fix test

* fix js linting issues

* fix: Update assets

* fix: Empty plugin selectors in all but first placeholder

* fix: Add slotname argument to dummy `PlaceholderField`

* fix: Adjust checks for `GrouperAdmin` to allow for `prepopulated_fields` (#8232)

* fix: Adjust checks for GrouperAdmin to allow for `prepopulated_fields`

* Update cms/tests/test_grouper_admin.py

---------

Co-authored-by: Github Release Action <info@django-cms.org>
vinitkumar pushed a commit that referenced this pull request May 21, 2025
…#8233)

* [5.1.0dev1 release process] Bumped version to 5.1.0dev1

* [5.1.0dev1 release process] compilemessages

* [5.1.0dev1 release process] compiling new static files

* [5.1.0dev1 release process] updating latest docs

* Prepare new main branch

* Fix typos

* fix: No changes to changelog

* fix: Remove unnecessary change to migration

* Remove circular import

* Fix import order

* Re-introduce dummy `PlaceholderField` for legacy migrations

* fix: Do not assume page url cache to be filled

* fix: Structure board update sometimes failed to add all interactive elements (#8227)

* fix: Scan plugin data after structure mode Xhr load

* Fix test

* fix js linting issues

* fix: Update assets

* fix: Empty plugin selectors in all but first placeholder

* chore: Move from script tags containing dom elements to template tags

* Update cms/models/fields.py

* Update cms/models/fields.py

---------

Co-authored-by: Github Release Action <info@django-cms.org>
fsbraun added a commit that referenced this pull request May 22, 2025
…#8233)

* [5.1.0dev1 release process] Bumped version to 5.1.0dev1

* [5.1.0dev1 release process] compilemessages

* [5.1.0dev1 release process] compiling new static files

* [5.1.0dev1 release process] updating latest docs

* Prepare new main branch

* Fix typos

* fix: No changes to changelog

* fix: Remove unnecessary change to migration

* Remove circular import

* Fix import order

* Re-introduce dummy `PlaceholderField` for legacy migrations

* fix: Do not assume page url cache to be filled

* fix: Structure board update sometimes failed to add all interactive elements (#8227)

* fix: Scan plugin data after structure mode Xhr load

* Fix test

* fix js linting issues

* fix: Update assets

* fix: Empty plugin selectors in all but first placeholder

* chore: Move from script tags containing dom elements to template tags

* Update cms/models/fields.py

* Update cms/models/fields.py

---------

Co-authored-by: Github Release Action <info@django-cms.org>
fsbraun added a commit that referenced this pull request May 22, 2025
…#8233) (#8237)

* [5.1.0dev1 release process] Bumped version to 5.1.0dev1

* [5.1.0dev1 release process] compilemessages

* [5.1.0dev1 release process] compiling new static files

* [5.1.0dev1 release process] updating latest docs

* Prepare new main branch

* Fix typos

* fix: No changes to changelog

* fix: Remove unnecessary change to migration

* Remove circular import

* Fix import order

* Re-introduce dummy `PlaceholderField` for legacy migrations

* fix: Do not assume page url cache to be filled

* fix: Structure board update sometimes failed to add all interactive elements (#8227)

* fix: Scan plugin data after structure mode Xhr load

* Fix test

* fix js linting issues

* fix: Update assets

* fix: Empty plugin selectors in all but first placeholder

* chore: Move from script tags containing dom elements to template tags

* Update cms/models/fields.py

* Update cms/models/fields.py

---------

Co-authored-by: Github Release Action <info@django-cms.org>
fsbraun added a commit that referenced this pull request May 22, 2025
* fix: Remove circular import in `cms.forms.validators` (#8225)

* Remove circular import

* Fix linting

* Update cms/forms/validators.py

* fix: Do not assume page url cache is filled

* fix: Structure board update sometimes failed to add all interactive elements (#8227)

* fix: Scan plugin data after structure mode Xhr load

* Fix test

* fix js linting issues

* fix: Empty plugin selectors in all but first placeholder

* fix: Show all text-enabled plugins (#8229)

* fix: Adjust checks for GrouperAdmin to allow for `prepopulated_fields`

* fix: Page settings raised an exception when `USE_I18N = False`

* update ruff check

* Fix pk reference

---------

Co-authored-by: Vinit Kumar <mail@vinitkumar.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0