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

Run a completion block after text() has processed lines() #338

Closed
lakhman opened this issue Jul 24, 2015 · 4 comments · Fixed by #576
Closed

Run a completion block after text() has processed lines() #338

lakhman opened this issue Jul 24, 2015 · 4 comments · Fixed by #576
Labels

Comments

@lakhman
Copy link

lakhman commented Jul 24, 2015

I was building an extension and I wanted to run something after the blocks have been parsed by lines in text, the lines method is private (in Parsedown), and I wanted to do something after everything has been processed (but within my extension and not within my app).

A Complete callback to the text() function.

in Parsedown.php

function text($text)
{
    # make sure no definitions are set
    $this->DefinitionData = array();

    # standardize line breaks
    $text = str_replace(array("\r\n", "\r"), "\n", $text);

    # remove surrounding line breaks
    $text = trim($text, "\n");

    # split text into lines
    $lines = explode("\n", $text);

    # iterate through lines to identify blocks
    $markup = $this->lines($lines);

    # trim line breaks
    $markup = trim($markup, "\n");

    # CALLBACK: I want to run something here <---------------------
    // e.g: $this->completeCallback($markup) <-- Which I could override
    // Do custom processing before sending back to the client application (from an extension)

    return $markup;
}

Currently, I do something like this (This is within my app, I want to do this within my extension, once all the parsing is complete, I want to do some other stuff).

    $parsedown = new ParsedownExtension();
    $html = $parsedown->text($string);
    $html = $parsedown->completeCallback($html);

ParsedownExtension is a child of Parsedown, which I add the completeCallback and call it manually.

It would be great to have a function which is called after all processing is done which we could override to do custom things after, the other option is for me to override all the other blocks and count the lines to see where we are, and on the last line I could do whatever I wanted - obviously this is quite alot of work!

Currently, I'm using my solution above and doing this in my app, but If I want to use this in another app or publish it online, I would have to instruct everyone to call the callback (when I would really want my extension to do this - run a callback when everything is finished so I can do any custom processing in my extension before passing the $markup back to the client application).

Thoughts or ideas for a workaround? - I have to do it after everything is processed as the processTag messes things up when inside a div (markdown="1").

@erusev
Copy link
Owner

erusev commented Jul 24, 2015

Wouldn't it work if you overrode the text method:

function text($text)
{
    $markup = parent::text($text);
    // modify $markup here
    return $markup;
}

@lakhman
Copy link
Author

lakhman commented Jul 24, 2015

I tried doing that, but text can be called multiple times (if parsing a HTML markdown="1" for example), so the $markup in this case would only be the HTML snippet (not the whole document). There's no way to tell if text($text) was called from processTags or by the user for parsing.

I tried overriding the processTag and blockMarkComplete to try and track when we're parsing a HTML snippet and to ignore it (by setting a class variable $this->isProcessingHtmlTag), but I had a number of issues with this - and it wasn't really a clean solution.


Example: (Sorry, forgot to mention i'm using ParsedownExtra)

<div class="row" markdown="1">
    <div class="col-sm-6" markdown="1">
        # Row 1 - Introduction
    </div>
    <div class="col-sm-6" markdown="1">
        # Row 2 - Introduction
    </div>
</div>

{##CUSTOM_PLACEHOLDER##}

Then init it:

$parsedown = new ParsedownExtension();
$html = $parsedown->text($string);

In the above example, the text() method is called:

  1. When we initially called the text() method ($text = the ENTIRE document)
  2. When processTags is called to parse $text=<div class="row" markdown="1">...</div>
  3. When processTags calls text() to parse $text=# Row 1 - Introduction
  4. When processTags calls text() to parse $text=# Row 2 - Introduction

Inside the text() method, there is no way to know where it was called from (Was it a main request or a "sub-request" to parse content inside a HTML tag).

The offending line is in ParsedownExtra.php Line 486:

# This can call `text()` multiple times, and there is no way to know inside the `text()` method
$elementText = "\n".$this->text($elementText)."\n";

What I want to do

I want Parsedown to parse the entire document, then I want my extension to take the final markup and manipulate it (e.g: count the number of tags, and replace {##CUSTOM_PLACEHOLDER##} with content).

I know I can write an extension to replace the placeholder, but my current use case requires that I do it AFTER the ENTIRE document has been parsed into HTML (as I want to manipulate HTML elements and such after parsing). - Ideally I want to do this in my extension as opposed to adding the extra lines of code in my application (so the extension can be reusable across projects).

Hopefully that all makes sense!

@erusev
Copy link
Owner

erusev commented Jul 24, 2015

I see. I'll look into this next week.

@aidantwoods
Copy link
Collaborator

When #576 is finished you will be able to traverse the entire AST, which I think should give you what you are looking for? :)

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

Successfully merging a pull request may close this issue.

3 participants