Skip to content

Conversation

dlford
Copy link

@dlford dlford commented Aug 31, 2025

fixes #7431

Summary

The code widget executes the onChange callback anytime lang is changed, including when initializing the value from props. This causes the CMS to act as if there are unsaved changes any time a document is loaded with a saved language in the code widget.

Test plan

Using the below config and index, create a new blog post and add a code component, set the language and save. Reload the page, you should see the "changes saved" message in the top left of the CMS instead of "unsaved changes".

config.yml

local_backend: true
backend:
  name: test-repo
media_folder: static/media
public_folder: /media

collections:
  - name: blog
    label: Blog Posts
    label_singular: Blog Post
    folder: content/blog
    create: true
    preview_path: "{{fields.slug}}"
    identifier_field: slug
    fields:
    - label: Title
      name: title
      hint: The title should ideally be between 5 and 60 characters long for SEO
      widget: string
      required: true
    - label: Post Content
      name: body
      widget: markdown
      required: false
      editor_components:
      - code

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Decap CMS</title>
  </head>
  <body>
    <script src="dist/decap-cms.js"></script>
    <script>
      const CMS = window.CMS;

      const langMap = {
        js: 'javascript',
        ts: 'typescript',
        sh: 'shell',
        'go-html-template': 'go',
        yml: 'yaml',
        cfg: 'ini',
        txt: '',
      };

      CMS.registerEditorComponent({
        id: 'code',
        label: 'Code',
        summary: '{{fields.title}}',
        collapsed: true,
        fields: [
          {
            name: 'title',
            label: 'Title',
            widget: 'string',
            default: '',
            required: false,
          },
          {
            name: 'hl',
            label: 'Highlight Lines',
            hint: 'Use spaces to separate multiple lines and hyphens for ranges, e.g. `1 3-5`',
            widget: 'string',
            default: '',
            required: false,
          },
          {
            name: 'code',
            label: 'Code',
            widget: 'code',
            required: true,
          },
        ],
        pattern:
          /{{<code[ \n]?(lang="([^"]+)?")?[ \n]?(title="([^"]+)?")?[ \n]?(hl="([^"]+)?")?>}}\n+```([a-zA-Z]+)?\n((?!```).*?$)\n```\n+{{<\/code>}}/ms,
        fromBlock: function (match) {
          return {
            title: match[4],
            hl: match[6],
            code: {
              lang: match[2] ? langMap[match[2]] || match[2] : '',
              code: match[8] || '',
            },
          };
        },
        toBlock: function ({ title, hl, code }) {
          let lang = code?.lang ? langMap[code.lang] || code.lang : '';

          let args = '';
          if (lang) args += ` lang="${lang}"`;
          if (title) args += ` title="${title}"`;
          if (hl) args += ` hl="${hl}"`;
          return `{{<code${args}>}}\n\`\`\`\n${code?.code}\n\`\`\`\n{{</code>}}`;
        },
        toPreview: function ({ title, hl, code }) {
          return `<code>Language: ${code?.lang}</code>\n<code>Title: ${
            title || ''
          }</code>\n<code>Highlight Lines: ${hl || ''}</code>\n<pre><code>\n${
            code?.code || ''
          }\n</code></pre>`;
        },
      });
    </script>
  </body>
</html>

Checklist

Please add a x inside each checkbox:

@dlford dlford requested a review from a team as a code owner August 31, 2025 16:57
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.

Code block with language annotation causes report of unsaved changes
1 participant