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

Support Mermaid's callback configuration #6

Closed
artob opened this issue Aug 2, 2020 · 14 comments
Closed

Support Mermaid's callback configuration #6

artob opened this issue Aug 2, 2020 · 14 comments
Labels
enhancement New feature or request fixed The issue is fixed good first issue Good for newcomers

Comments

@artob
Copy link

artob commented Aug 2, 2020

Mermaid has the ability (see src/mermaid.js) to invoke a user-configured callback function as it renders each diagram:

mermaid.initialize({
  startOnLoad: true,
  mermaid: {
    callback: function(id) {
      // ...
    },
  },
});

This is invaluable for doing any number of things on Mermaid diagrams that simply cannot be done with CSS.

Right now, I don't see any way to configure a Mermaid callback function in this plugin. Could that be supported in the plugin configuration? The obvious way would seem to be as follows:

plugins:
  - mermaid2:
      arguments:
        theme: neutral
      callback: myMermaidCallbackFunction
@github-actions
Copy link

github-actions bot commented Aug 2, 2020

Thank you for your contribution! This is very appreciated.

@fralau fralau added enhancement New feature or request good first issue Good for newcomers labels Aug 2, 2020
@fralau
Copy link
Owner

fralau commented Aug 2, 2020

Thank you. This seems a good idea. Adding code into the javascript mermaid.initialize()sequence should be straightforward.

To give me a better idea, what do usually do with a callback function on a mermaid diagram?

Is it code that you want to have to rewrite ad-hoc for each specific website, or is it a standard code ?

Do you have a suggestion of where the callback function should sit ? (My first reaction would be in the source directory of the project.)

@artob
Copy link
Author

artob commented Aug 2, 2020

To give me a better idea, what do usually do with a callback function on a mermaid diagram?

In my case right now, I want to adjust the SVG viewBox so as to remove the spurious, hardcoded 20px padding that Mermaid adds to class diagrams. That doesn't seem possible to do with CSS.

I've seen others do things like add tooltips and, perhaps most commonly, click handlers to diagram elements.

Is it code that you want to have to rewrite ad-hoc for each specific website, or is it a standard code ?

In my case right now, this is ad-hoc, though I'd certainly like to use it on all of my MkDocs sites until such a time that upstream (Mermaid) fixes the viewBox attribute to not include hardcoded padding. (I may submit a patch upstream.)

Do you have a suggestion of where the callback function should sit ? (My first reaction would be in the source directory of the project.)

I'd just expect to define the function in my custom extra_javascript inclusions, as follows. (If there's a better way, I don't know of it.)

extra_javascript:
  - https://unpkg.com/mermaid@8.5.2/dist/mermaid.min.js
  - js/extra.js

@fralau
Copy link
Owner

fralau commented Aug 2, 2020

Thanks for this useful information, as this gives me context (I would also like to learn to do what you describe 🤔).

To make sure we are on the same page: the directory js in the path js/extra.js, is relative to the mkdoc project's root?

In that case, what about a syntax that would look like this:

plugins:
  - mermaid2:
      arguments:
        theme: neutral
      callback: js/extra.js:myMermaidCallbackFunction

We could then be smart and detect if it's an absolute path or an URL, and treat it accordingly?

@artob
Copy link
Author

artob commented Aug 2, 2020

To make sure we are on the same page: the directory js in the path js/extra.js, is relative to the mkdoc project's root?

That's relative to the docs_dir folder (by default, docs).

In that case, what about a syntax that would look like this:

plugins:
  - mermaid2:
      arguments:
        theme: neutral
      callback: js/extra.js:myMermaidCallbackFunction

We could then be smart and detect if it's an absolute path or an URL, and treat it accordingly?

That'd be fine, but I'm unsure why the plugin would need to know which file the callback function is located in? Wouldn't it just work to generate the following code, trusting that the user has made the function available:

mermaid.initialize({
  mermaid: {
    callback: myMermaidCallbackFunction,
  },
});

@fralau fralau added the planned label Aug 2, 2020
@fralau
Copy link
Owner

fralau commented Aug 2, 2020

Why not? 🤔

That would really simplify the code, and if it comes as natural to you, I assume it would for any other person who practices javascript...

We'll do that.

Would you give me a sample function myMermaidCallbackFunction, so that I have something to work with?

@fralau
Copy link
Owner

fralau commented Aug 2, 2020

Wait a minute 🤦 ... but can't we already do it?

What about this?

plugins:
  - mermaid2:
      arguments:
        theme: neutral
        mermaid:
            callback: myMermaidCallbackFunction

extra_javascript:
  - https://unpkg.com/mermaid@8.5.2/dist/mermaid.min.js
  - js/extra.js

Shouldn't that work?

@artob
Copy link
Author

artob commented Aug 3, 2020

Wait a minute 🤦 ... but can't we already do it? [...] Shouldn't that work?

Almost, but not quite. That generates this code:

<script>mermaid.initialize({"theme": "neutral", "mermaid": {"callback": "myMermaidCallbackFunction"}});</script></body>

Since the mermaid.callback parameter must be a function, and a string is certainly an invalid value, perhaps the simplest thing would be to just special-case the handling of that parameter so that the argument is output as a function name instead of a string literal?

@artob
Copy link
Author

artob commented Aug 3, 2020

Would you give me a sample function myMermaidCallbackFunction, so that I have something to work with?

The simplest thing would be to just check the browser's developer console to see that the configured callback function was indeed invoked:

// js/extra.js
function myMermaidCallbackFunction(id) {
  console.log('myMermaidCallbackFunction', id);
}

@fralau
Copy link
Owner

fralau commented Aug 3, 2020

@artob

Almost, but not quite. That generates this code:

<script>mermaid.initialize({"theme": "neutral", "mermaid": {"callback": "myMermaidCallbackFunction"}});</script></body>

Right. "For want of nail, a shoe was lost...".

Since the mermaid.callback parameter must be a function, and a string is certainly an invalid value, perhaps the simplest thing would be to just special-case the handling of that parameter so that the argument is output as a function name instead of a string literal?

Yes. I guess so.

fralau pushed a commit that referenced this issue Aug 4, 2020
  - Fixes issue #6
  - This is done by exactly replicating the proper initialize sequence:
```yaml
    - mermaid2:
        arguments:
          theme: dark
          mermaid:
            callback: ^myMermaidCallbackFunction
```
  - The caret in front of the function name signifies that
    this is a literal and not a string.
  - A new function `pyjs.dumps` had to be created.
@fralau
Copy link
Owner

fralau commented Aug 4, 2020

I found a solution that works on my side.

The json.dumps() function was a rabbit hole, because there was no simpley way to ask it to generate a function name (non-string).

Here is my "not too ugly" solution: I wrote a new dumps() function as a drop-in replacement for the json.dumps(...) function, but which produces an object in true Javascript syntax.

I used the caret (^) as a dequote operator, hence the function name myMermaidCallbackFunction will be translated as a function name, not a string.

Aside of that, I did not change the logic of the plugin.

I tested it on my side with the javascript function you gave me, and it works OK. I also updated the README.md.

Could you let me know if it works for you? If it works OK, I will update the pypi repository.

@fralau fralau added fixed The issue is fixed and removed planned labels Aug 4, 2020
@fralau
Copy link
Owner

fralau commented Aug 4, 2020

Two additional notes:

  1. How did you find out about this mermaid>callback argument for the mermaid.initialize() function? I could not find any mention about this on the official website.

  2. For the record (not tested and no idea whether this could possibly be useful): instead of a javascript function name, would it be possible to write its code directly, something like.

mermaid:
    callback: |
      ^function() {...
      }

@artob
Copy link
Author

artob commented Aug 4, 2020

Could you let me know if it works for you? If it works OK, I will update the pypi repository.

Great! That works 👍

  1. How did you find out about this mermaid>callback argument for the mermaid.initialize() function? I could not find any mention about this on the official website.

Hmm, I can't recall. Probably from examples in the wild, or Mermaid issues.

  1. For the record (not tested and no idea whether this could possibly be useful): instead of a javascript function name, would it be possible to write its code directly, something like.

Sure, I think that'd be nice for all those users who don't plan to add any other custom JS.

@fralau
Copy link
Owner

fralau commented Aug 7, 2020

It's now published on pypi under 0.3.1.

@fralau fralau closed this as completed Aug 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request fixed The issue is fixed good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants