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

Using listener extensions to add divs #518

Open
KirkMunro opened this issue Apr 19, 2018 · 5 comments
Open

Using listener extensions to add divs #518

KirkMunro opened this issue Apr 19, 2018 · 5 comments
Assignees

Comments

@KirkMunro
Copy link

KirkMunro commented Apr 19, 2018

Hello @tivie,

I'm trying to use an extension to add divs. Within the showdown extensibility model, it seems to me that listener extensions are the right way to do this, but with them not being documented (and from what I can tell, buggy), it is difficult to figure out.

Digging into the code and looking at examples, I found a jsfiddle that I modified to see if I could make it work. My goal is simple: if I have ::: className as an enclosure opening and ::: as a enclosure closing, then convert that to <div class="className">...</div>, where ... represents everything within the div enclosure.

I've gotten this to work somewhat, here:
https://jsfiddle.net/poshoholic/Lxkjyv11/34/

The problem I've run into is figuring where to put this in the listener event resolution order. How do I define this extension to get the following behavior:

  • <div ...> is never, ever wrapped in a paragraph tag;
  • </div> is never picked up as part of a list/list item, unless the entire div is inside of the list item;
  • </div> is never picked up at the end of a table as another row;

Ideally I would like this to work without having to place blank lines around tables, lists, etc. inside of the div block, but so far I've had limited success with that.

I think that I'm facing a bug or two in showdown (why would it wrap <div> in a paragraph tag?), combined with no knowledge of the actual listener event processing order. The two events I've had the best success with are tables.before and githubCodeBlocks.after, but it's still not right.

Can you please help fill in the blanks from what I've figured out so far so that this just works?

P.S. I know you're working hard on showdown 2.0, and I'm looking forward to it, but I'd love to get a handle on how extensions work in the meantime! I don't need full documentation, just some pointers (listener event processing order?) and maybe a bug fix or two.

@KirkMunro
Copy link
Author

Just to add to this, I really don't want newlines inserted after <div class="className"> and before </div>, because that prevents certain css styling from rendering properly. I put those line breaks in as I was tinkering with this, but ultimately they shouldn't be there.

@KirkMunro
Copy link
Author

Also, another related question when talking about listeners: can a listener be written to take each formatted output (HTML output) from one of the builtin markdown converters and modify what is generated before it is added to the HTML output document?

For example, if I wanted to add extra handling over how a code block is formatted, could I write a listener that would receive only the HTML code block (<pre><code>...</code></pre>) text, where what I return from that listener would be what is actually output in the document? Or is that what lang/output extensions are for (but those are going away in showdown 2.0)?

@tivie tivie self-assigned this May 7, 2018
@tivie
Copy link
Member

tivie commented May 7, 2018

@KirkMunro Sorry for the delay in answering, but I've been extra busy lately, and the little time I get for showdown is all spent on trying to release an alpha version 2 of showdown.

Also, another related question when talking about listeners: can a listener be written to take each formatted output (HTML output) from one of the builtin markdown converters and modify what is generated before it is added to the HTML output document?

For example, if I wanted to add extra handling over how a code block is formatted, could I write a listener that would receive only the HTML code block (

...
) text, where what I return from that listener would be what is actually output in the document? Or is that what lang/output extensions are for (but those are going away in showdown 2.0)?

Right now you can't, because listener extensions are actually just event listeners. Each subparser broadcasts 2 events: before it runs and after it runs. Showdown makes the all "raw text" available to listeners, not the "partial text" that was caught by the regex and actually changed by the subparser.

However, I have planned adding more events to listener extensions in v2.0 which will include that: partial text caught and partial text rendered by each parser, giving users a finer degree of control.

Output extensions will be dropped in v2.0, and replaced with a BeforeAll and AfterAll events (or something like that) which, effectively, behave exactly as Lang and Output extensions.


The problem I've run into is figuring where to put this in the listener event resolution order.
How do I define this extension to get the following behavior:

  1. <div ...> is never, ever wrapped in a paragraph tag;
  2. </div> is never picked up as part of a list/list item, unless the entire div is inside of the list item;
  3. </div> is never picked up at the end of a table as another row;

To achieve that behavior, you need to take into consideration some important things:

  1. Showdown relies on parsing order. That means you can't switch parser order because, for instance, the paragraph subparser assumes that all HTML code was already tokenized. So, in order to prevent the output of your extension to be parsed any further, you should tokenize it (have a look into 'hashHTMLBlocks' subparser).

  2. Is the "div parser" a block parser? Or a span parser? Or both? From your example it seems it can be both, so you would need actually 2 extensions: one for blocks and one for spans. You shouldn't try to make rules that apply to both. While that might be possible, it's a lot harder than treating them separately.

  3. You have to decide the priority of the div parsing. For instance, should github blocks take precedence, or divs? Example:

    :::
    ```
    :::
    ```
    

    Should this be parsed as <div>```</div>``` or :::<pre><code>:::</code></pre>?

@KirkMunro
Copy link
Author

This is very helpful, thank you @tivie! I'll review this, experiment with multiple extensions, and have a look at the example you highlighted.

P.S. I'm really looking forward to version 2, so I don't mind that you were focusing your time on that at all! :) Do you know if you'll have the extension logic you describe above, with partial text caught/rendered event handling in listeners, in your first alpha? Or is that planned for future use?

@tivie
Copy link
Member

tivie commented May 7, 2018

I would say it has a good chance of finishing in time for first alpha. I have implement it already, but don't have the proper testing cases yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants