I know this has been asked (Python Markdown nl2br extension, etc) but none of those answers is doing it for me.
I would like to render markdown so that linebreaks occuring within a <p>
element will be rendered as <br>
. Example: they type
Here is line one.
And line two.
New paragraph.
should render as
<p>Here is line one.<br>And line two.</p>
<p>New paragraph.</p>
I know that if you want that, you should type two spaces at the end of the line you want to <br>
. I am trying to make it so my users don't have to do that, but rather, enter text as though they were using a typewriter (for those who know what that is). One hard return, new line; two hard returns, new paragraph.
I've been working with https://parsedown.org/ and have also experimented with https://commonmark.thephpleague.com; also the Python markdown module with nl2br extension (tried their example verbatim, did not work for me). Whatever I do, I end up with either too many or not enough linebreaks, depending.
I have tried what I thought would be clever and elegant: style my markdown's <p>
with white-space: "pre"
(also tried pre-line
). That works, unless the user has done it "right" with two spaces, in which case you get the unwanted double <br>
effect.
Also tried nl2br($markdown)
with likewise unreliable results.
I want non-technical users to be able to use some basic formatting as easily as possible, and markdown seems just the thing, but for this detail. I don't want to write a CMS just to work around this. For example, I've thought of adding a boolean markdown
property on the entity and letting them choose, yadda yadda... don't wanna go there. I've thought of doing some string-replacement or regexp magic, either at database-write time or just before rendering. But again, hoping to avoid getting too complicated. (To make it a little more challenging, I will also have to import a few thousand legacy records that are non-markdown, and potentially deal with issues around old ones versus new.)
Maybe I'm overlooking a simple, sane way out. Any thoughts as to the best strategy?
Update: by popular demand, code examples of what does not work. It's a Zend MVC application that involves Doctrine entities I call MOTD and MOTW (Message Of The Day and Message Of The Week, respectively); these have a string property called content. Generically I think of these entities as Note
s and they implement a NoteInterface
. When I retrieve these from the database (via a NotesService
class that internally uses a custom Doctrine repository class), it's time to render the content as markdown before the controller assigns it to the view:
// from NotesService.php
use Parsedown;
// stuff omitted...
/**
* gets MOT(D|W) by date
*
* @param DateTime $date
* @param string $type
* @param boolean $render_markdown
* @return NoteInterface|null
*/
public function getNoteByDate(DateTime $date, string $type, bool $render_markdown = true) :? NoteInterface
{
$entity = $this->getRepository()->findByDate($date,$type);
if ($entity && $render_markdown) {
$content = $entity->getContent();
$entity->setContent($this->parsedown($content));
}
return $entity;
}
The point of the boolean $render_markdown
is for when we want raw markdown, i.e., when it's going to populate a textarea element of a form.
And the parsedown()
method, quite simply:
public function parsedown(string $content) : string
{
if (! $this->parseDown) {
$this->parseDown = new Parsedown();
}
// nope...
// return nl2br($this->parseDown->text($content));
return $this->parseDown->text($content);
}
Inside a viewscript, I just go, e.g.,
if ($this->notes['motd']):
// echo nl2br($this->notes['motd']->getContent());
echo $this->notes['motd']->getContent();
else:
?><p class="font-italic no-note">no MOTD for this date</p><?php
endif;
Now, if in the editing form they input this as content:
here is a line
and here is another
now, new paragraph.
and then we save it in the database, when you select it back out and run it through $parsedown->text($content), you get this HTML:
<p>here is a line
and here is another</p>
<p>now, new paragraph.</p>
Please note, the example input above does not have any space characters preceding the linebreaks. When you do type two spaces before the linebreaks, yeah, it works great. But I don't think my users want to think about that. So using nl2br()
helps, except when it results in too many consecutive <br>
s in the HTML.
My latest thinking is, use a CSS solution and an input filter that strips <space><space>
at the end of lines. When it works, I'll add the story to my memoir. :-)