Skip to content
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

Can't nest custom widgets #7180

Open
tobiasBora opened this issue Apr 14, 2024 · 0 comments
Open

Can't nest custom widgets #7180

tobiasBora opened this issue Apr 14, 2024 · 0 comments
Labels
type: bug code to address defects in shipped code

Comments

@tobiasBora
Copy link

tobiasBora commented Apr 14, 2024

Describe the bug

If I define a custom widget, I can only specify a regexp as a pattern, like pattern: /^<details>$\s*?<summary>(.*?)<\/summary>\n\n(.*?)\n^<\/details>$/ms,. But this will parse nested components poorly, for instance:

<details>
  <summary>This is a collapsible note</summary>
  This is the content of a collapsible note, that's soooo awesome!!!
<details>
  <summary>Nested collapsible note.</summary>
  Is this even working??
</details>
</details>

Is not parsed correctly since the regexp will match the first <detail> with the first </detail>, like in:

<details>
  <summary>This is a collapsible note</summary>
  This is the content of a collapsible note, that's soooo awesome!!!
<details>
  <summary>Nested collapsible note.</summary>
  Is this even working??
</details>

Unfortunately, I don't think any regexp expression can work here, as an automata "cannot count"… so we should allow the user to use a true XML/MDX parser. So we could maybe provide two options, one with a very generic function that is just given the rest of the file to parse, and one easier function that is made for xml files that are the most common kind of data anyway.

To Reproduce

Add a custom widget, I just used the one from the documentation:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="robots" content="noindex" />
    <title>Content Manager</title>
    <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
  </head>
  <body>
    <!-- Include the script that builds the page and powers Decap CMS -->
    <script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
    <script>
      CMS.registerEditorComponent({
        // Internal id of the component
        id: "collapsible-note",
        // Visible label
        label: "Collapsible Note",
        // Fields the user need to fill out when adding an instance of the component
        fields: [
          {
            name: 'summary',
            label: 'Summary',
            widget: 'string'
          },
          {
            name: 'contents',
            label: 'Contents',
            widget: 'markdown'
          }
        ],
        // Regex pattern used to search for instances of this block in the markdown document.
        // Patterns are run in a multiline environment (against the entire markdown document),
        // and so generally should make use of the multiline flag (`m`). If you need to capture
        // newlines in your capturing groups, you can either use something like
        // `([\S\s]*)`, or you can additionally enable the "dot all" flag (`s`),
        // which will cause `(.*)` to match newlines as well.
        //
        // Additionally, it's recommended that you use non-greedy capturing groups (e.g.
        // `(.*?)` vs `(.*)`), especially if matching against newline characters.
        pattern: /^<details>$\s*?<summary>(.*?)<\/summary>\n\n(.*?)\n^<\/details>$/ms,
        // Given a RegExp Match object
        // (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#return_value),
        // return an object with one property for each field defined in `fields`.
        //
        // This is used to populate the custom widget in the markdown editor in the CMS.
        fromBlock: function(match) {
          return {
            summary: match[1],
            contents: match[2]
          };
        },
        // Given an object with one property for each field defined in `fields`,
        // return the string you wish to be inserted into your markdown.
        //
        // This is used to serialize the data from the custom widget to the
        // markdown document
        toBlock: function(data) {
          return `
<details>
  <summary>${data.summary}</summary>

  ${data.contents}

</details>
          `;
        },
        // Preview output for this component. Can either be a string or a React component
        // (component gives better render performance)
        toPreview: function(data) {
          return `
<details>
  <summary>${data.summary}</summary>

  ${data.contents}

</details>
          `;
        }
      });
    </script>
  </body>
</html>

Expected behavior
This should just parse correctly without any error

Screenshots

Applicable Versions:

  • Decap CMS version: 3.0.0
  • Git provider: local
  • OS: NixOs

CMS configuration

and the following configuration

# when using the default proxy server port
local_backend: true

media_folder: "static/images/uploads" # Media files will be stored in the repo under images/uploads
public_folder: "/images/uploads" # The src attribute for uploaded media will begin with /images/uploads

backend:
  name: git-gateway
  branch: main # Branch to update (optional; defaults to master)
  commit_messages:
    create: Create {{collection}} “{{slug}}”
    update: Update {{collection}} “{{slug}}”
    delete: Delete {{collection}} “{{slug}}”
    uploadMedia: Upload “{{path}}”
    deleteMedia: Delete “{{path}}”
    openAuthoring: '{{message}}'
  publish_mode: editorial_workflow
  site_url: http://localhost:5173/
    
collections:
  - name: "post" # Used in routes, e.g., /admin/collections/blog
    label: "Posts" # Used in the UI
    preview_path: blog/{{slug}}
    folder: "src/lib/posts/" # The path to the folder where the documents are stored
    create: true # Allow users to create new documents in this collection
    slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
    fields: # The fields for each document, usually in front matter
      - { label: "Layout", name: "layout", widget: "hidden", default: "blog" }
      - { label: "Title", name: "title", widget: "string" }
      - { label: "Publish Date", name: "date", widget: "datetime" }
      - { label: "Featured Image", name: "thumbnail", widget: "image" }
      - { label: "Rating (scale of 1-5)", name: "rating", widget: "number" }
      - { label: "Body", name: "body", widget: "markdown" }
  - name: pages
    label: Pages
    label_singular: 'Page'
    folder: content/pages
    create: true
    # adding a nested object will show the collection folder structure
    nested:
      depth: 100 # max depth to show in the collection tree
      summary: '{{title}}' # optional summary for a tree node, defaults to the inferred title field
    fields:
      - label: Title
        name: title
        widget: string
      - label: Body
        name: body
        widget: markdown
    # adding a meta object with a path property allows editing the path of entries
    # moving an existing entry will move the entire sub tree of the entry to the new location
    meta: { path: { widget: string, label: 'Path', index_file: 'index' } }

Additional context

@tobiasBora tobiasBora added the type: bug code to address defects in shipped code label Apr 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug code to address defects in shipped code
Projects
None yet
Development

No branches or pull requests

1 participant