jsoneditor icon indicating copy to clipboard operation
jsoneditor copied to clipboard

Attach custom classnames to the DOM root of a node instead of nested inside

Open R-Jimenez opened this issue 4 years ago • 10 comments

Another small suggestion for a neater design! Would be fantastic for the onCreateMenu callback to be able to return undefined and have the rendering of the context menu icon skipped or set to display:none. This way the tree view can more easily convey at a glance which of the elements may have context actions for those of us that are replacing the menu with our own actions.

JSONEditorOptions.onCreateMenu?: ((menuItems: MenuItem[], node: MenuItemNode) => MenuItem[]) | undefined
=>
JSONEditorOptions.onCreateMenu?: ((menuItems: MenuItem[], node: MenuItemNode) => MenuItem[] | undefined) | undefined

Alternatively, an isEmpty check of the MenuItem array would do the same job.

Cheers!

R-Jimenez avatar Aug 17 '20 19:08 R-Jimenez

Thanks for your suggestion Alberto. A node with an empty context sounds like you want to make some nodes read-only. I guess it makes most sense in those cases to disable or not show the context menu button in such cases. That would not be trivial though: currently the onCreateMenu is only called after clicking a context menu button, not when rendering all those buttons.

An easy step could be to show the context menu with a text like "no actions available" when there are no menu items.

Can you explain a bit more about the cases where you want to have nodes completely without context menu?

Have you looked into the option onEditable which also allows to disable many of the menu items?

josdejong avatar Aug 19 '20 06:08 josdejong

I'm more interested in disabling the button as a way to signal to the user which elements do have action items. This is certainly an edge case so an example is likely in order:

Screen Shot 2020-08-19 at 5 50 15 PM

I am using onEditable to whitelist elements such as each individual connection (to allow reordering and removal), and have used onCreateMenu to create my own list of insertion elements. In the example above is an array of connections. The connection object itself is not editable, however does have an Add Connection action in the context menu. Each individual connection is editable, and therefore I keep the default Delete action as the sole action in their context menu. The rest of the elements have no context menu items after my functional filtering, but the user can't tell that at a glance; they'll only know which element can be inserted into or deleted by clicking each one, which is less than ideal. Basically I'm trying to replicate a structural edit flag but on two levels (parent-child).

Hopefully that makes my idea make more sense, and again great work on this editor!

R-Jimenez avatar Aug 19 '20 21:08 R-Jimenez

Thanks, yes that helps understand where you come from.

Just thinking aloud: maybe you can use onClassName to give some nodes a class like "nocontextmenu" or so, and then with CSS make the context menu button readonly using for example pointer-events: none;?

josdejong avatar Aug 20 '20 16:08 josdejong

Yes, I had that same thought. I played around with CSS display trickle down but didn't get too far. Will likely revisit that attempt sometime this weekend.

R-Jimenez avatar Aug 21 '20 13:08 R-Jimenez

I gave it a try and I now understand why it doesn't work. The DOM tree looks like:

tr.jsoneditor-expandable.jsoneditor-collapsed
  td
    button.jsoneditor-button.jsoneditor-dragarea
  td
    button.jsoneditor-button.jsoneditor-contextmenu-button    <-- button we want to disable here
  td
    table.jsoneditor-values.my-custom-class       <-- custom class attached here

I think the custom class should be attached higher in the tree, this way you can't customize the drag and context menu buttons. With some JavaScript and css selectors it's possible to locate the buttons. It's ugly but at least it's a working workaround:

https://jsbin.com/fidoqok/edit?html,output

<!DOCTYPE HTML>
<html>
<head>
  <title>JSONEditor | Disable context menu button</title>

  <link href="https://unpkg.com/[email protected]/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
  <script src="https://unpkg.com/[email protected]/dist/jsoneditor.min.js"></script>
  <script src="https://unpkg.com/[email protected]/lodash.js"></script>
</head>
<body>
<p>
  Context menu of property "disabled" is disabled
</p>
<div id="jsoneditor"></div>

<script>
  const disabledClassName = 'disabled-context-menu'
  const container = document.getElementById('jsoneditor')
  
  const disableContextMenus = _.debounce(() => {
    const items = container.querySelectorAll('.' + disabledClassName)
    items.forEach(item => {
      // locate the context menu button
      const root = item.parentNode.parentNode
      const button = root.querySelector('.jsoneditor-contextmenu-button')
      button.style.pointerEvents = 'none'
    })
  })
  
  const options = {
    onClassName: ({ path }) => {
      if (path && path[0] === 'disabled') {
        disableContextMenus()
        return disabledClassName
      }

      return undefined
    }
  }
  const editor = new JSONEditor(container, options)

  const json = {
    'enabled': [1, 2, 3],
    'disabled': [1, 2, 3]
  }
  editor.set(json)
</script>
</body>
</html>

josdejong avatar Aug 22 '20 18:08 josdejong

Forgot to get back to this, but yes, I did manage to make it work using a similar dive and surface algorithm as yours and a utility callback. My algorithms for dynamic parsing of two-layer editability was already quite a messy one, so it wasn't a big deal to add another element to it. Cheers!

R-Jimenez avatar Aug 28 '20 14:08 R-Jimenez

Thanks for sharing your solution Alberto 👍

I keep this issue open to change the place where the custom class name is added in the DOM. Will Change the title accordingly.

josdejong avatar Aug 29 '20 10:08 josdejong

There's no need for the (visible) debounce delay if you initially set all context menu buttons to display:none and then later set all buttons to display:block when there's no custom class 'disabled-context-menu'.

mbeekhuis avatar Feb 09 '22 13:02 mbeekhuis

is there a way I can add custom styles instead of creating a class?

SAM33RG avatar Dec 20 '23 17:12 SAM33RG

no

josdejong avatar Dec 20 '23 19:12 josdejong