erusev / parsedown

Better Markdown Parser in PHP

Home Page:https://parsedown.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Allow excluding certain elements

userofit123 opened this issue · comments

commented

I haven't found a way at the moment to do this.
What i would like is to be able to pass a rule to the class to not render headers.

I can take them out of the raw string, but if there was a way to apply a setting to not render the ## for example as a header, that would be more efficient.

Also, if there was a way to replace the headers with just bold text, that would be even better.

Hi! Great question! This is fairly easy to do in the upcoming 2.0.0 release (you'll find a beta release available at the moment if you'd like to try or give feedback).

Removing a default block

To remove the header block rule entirely, you can do the following:

use Erusev\Parsedown\Components\Blocks\Header;
use Erusev\Parsedown\Configurables\BlockTypes;
use Erusev\Parsedown\Parsedown;
use Erusev\Parsedown\State;

$State = new State;

$BlocksTypes = $State->get(BlockTypes::class);
$BlocksTypes = $BlocksTypes->removing([Header::class]);

$State = $State->setting($BlocksTypes);

$Parsedown = new Parsedown($State);

echo $Parsedown->toHtml('### Testing! ###');

Which would result in this output:

<p>### Testing! ###</p>

Replacing a default block with a custom block

If you wanted to replace all the headers with bold text, this is possible too. What you'd need to do, is write a custom block for the BoldHeader and feed that block into Parsedown's ruleset. This isn't as difficult as it sounds, because you can defer all the parsing to Parsedown's Header parser, and then update the rendering instructions (so that instead of rendering between varying levels of h tags, you always use a b tag):

<?php

require 'vendor/autoload.php';

use Erusev\Parsedown\AST\Handler;
use Erusev\Parsedown\Components\Block;
use Erusev\Parsedown\Components\Blocks\Header;
use Erusev\Parsedown\Configurables\BlockTypes;
use Erusev\Parsedown\Html\Renderables\Element;
use Erusev\Parsedown\Parsedown;
use Erusev\Parsedown\Parsing\Context;
use Erusev\Parsedown\State;

final class BoldHeader implements Block
{
    /** @var Header */
    private $Header;

    private function __construct(Header $Header)
    {
        $this->Header = $Header;
    }

    /**
     * @return static|null
     */
    public static function build(
        Context $Context,
        State $State,
        Block $Block = null
    ) {
        $Header = Header::build($Context, $State, $Block);

        if (!isset($Header)) {
            return null;
        }

        return new self($Header);
    }

    /**
     * @return Handler<Element>
     */
    public function stateRenderable()
    {
        return new Handler(
            /** @return Element */
            function (State $State) {
                return new Element(
                    'b',
                    [],
                    $State->applyTo(Parsedown::line($this->Header->text(), $State))
                );
            }
        );
    }
}

$State = new State;

$BlocksTypes = $State->get(BlockTypes::class);
$BlocksTypes = $BlocksTypes->replacing(Header::class, BoldHeader::class);

$State = $State->setting($BlocksTypes);

$Parsedown = new Parsedown($State);

echo $Parsedown->toHtml('### Testing! ###');

Which outputs:

<b>Testing!</b>

Walkthrough of the custom block

Walking through the above example:

final class BoldHeader implements Block
{

This defines a new BoldHeader block, which implements Parsedown's Block parser interface. There are two things a Block needs to do:

  1. Specify how to parse the text: this is done by implementing the static method build.
  2. Specify how to render the block: this is done by implementing the instance method stateRenderable

For 1. this is easy enough, just defer to the existing Header renderer and store the resulting block in a new instance of BoldHeader:

/** @var Header */
    private $Header;

    private function __construct(Header $Header)
    {
        $this->Header = $Header;
    }

    /**
     * @return static|null
     */
    public static function build(
        Context $Context,
        State $State,
        Block $Block = null
    ) {
        $Header = Header::build($Context, $State, $Block);

        if (!isset($Header)) {
            return null;
        }

        return new self($Header);
    }

For 2. we need to return whatever text the stored Header parsed, but inside a bold tag instead of a h tag. This is done like so:

    /**
     * @return Handler<Element>
     */
    public function stateRenderable()
    {
        return new Handler(
            /** @return Element */
            function (State $State) {
                return new Element(
                    'b',
                    [],
                    $State->applyTo(Parsedown::line($this->Header->text(), $State))
                );
            }
        );
    }

Note that the contents of the bold element is $State->applyTo(Parsedown::line($this->Header->text(), $State)), this tells Parsedown to try to render any inline elements (e.g. links, codespans etc...) that might appear within that text. If you just wanted to return the header contents without looking for these elements, you could write it a bit simpler (adding use Erusev\Parsedown\Html\Renderables\Text; to the imports lines at the top of the file):

    /**
     * @return Element
     */
    public function stateRenderable()
    {
        return new Element(
            'b',
            [],
            [new Text($this->Header->text())]
        );
    }

The final lines do the following:

  1. Create a new "default" State object (this is what Parsedown uses to store all information about what kinds of parsing rules it will use, among other things).

    $State = new State;
  2. Extract the rules about what block types Parsedown will use

    $BlocksTypes = $State->get(BlockTypes::class);
  3. Rewrite this copy of the block types rules, replacing all rules for Header with the new BoldHeader parser.

    $BlocksTypes = $BlocksTypes->replacing(Header::class, BoldHeader::class);
  4. Rewrite the state object to include these updated block rules.

    $State = $State->setting($BlocksTypes);
  5. Finally, create a new instance of Parsedown using these newly configured rules.

    $Parsedown = new Parsedown($State);

Also bear in mind that there is a second type of header called SetextHeader, which will render things such as:

Testing
====

as a header too.

The instructions for dealing with this are essentially the same as above, and you could just opt to remove it if you didn't want to display these in bold.

Hello everybody,
this is a very cool but I have a Question about this: is it possible to rescrict the use of Link and images to prevent other users in case of "bad" links & images and myselft in case of images and the copyright? All in all a very fast parser, so my respect!
Greets