erusev/parsedown

blockquote issues

Closed this issue · 6 comments

.md:

> [!NOTE]
> Paragraph 1
> Paragraph 2

output:

<blockquote>
    <p class="note"></p>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</blockquote>

or output:

<blockquote>
    <p>[!NOTE]</p>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</blockquote>

If I want to implement the above mentioned features, can you tell me how to modify the code?Thank you very much!

Hi @xfstu, I am working on Alerts too! Have you solved this? Were you able to get Alerts rendering to work with blockquote elements?

@Meng-Heng yes,I changed the code at the elements function:

protected function elements(array $Elements)
    {
        $markup = '';

        $autoBreak = true;

        foreach ($Elements as $Element) {
            if (empty($Element)) {
                continue;
            }

            $autoBreakNext = (isset($Element['autobreak'])
                ? $Element['autobreak'] : isset($Element['name'])
            );
            // (autobreak === false) covers both sides of an element
            $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext;

            $markup .= ($autoBreak ? "\n" : '') . $this->element($Element);
            $autoBreak = $autoBreakNext;
        }
        $modified_html = preg_replace_callback(
            '#<blockquote>\s*<p>(.*?)</p>\s*</blockquote>#s',
            function ($matches) {
                // 将内容按换行符分割
                $lines = preg_split('/\r\n|\r|\n/', $matches[1]);
                // 为每一行添加 <p> 标签
                $lines = array_map(function ($line) {
                    /* switch ($line) {
                        case '[!NOTE]':
                            $line = '<span class=\'blockquote-tag note\'></span>';
                            break;
                        case '[!IMPORTANT]':
                            $line = '<span class=\'blockquote-tag important\'></span>';
                            break;
                        case '[!WARNING]':
                            $line = '<span class=\'blockquote-tag warning\'></span>';
                            break;
                        case '[!TIP]':
                            $line = '<span class=\'blockquote-tag tip\'></span>';
                            break;
                        case '[!IMPORTANT]':
                            $line = '<span class=\'blockquote-tag important\'></span>';
                            break;
                    } */
                    return '<p class=\'blockquote-p\'>' . (trim($line)) . '</p>';
                }, $lines);
                // 重新组合 <blockquote> 内容
                return '<blockquote>' . implode('', $lines) . '</blockquote>';
            },
            $markup
        );

        // dump($markup);
        // dump($modified_html);
        $modified_html .= $autoBreak ? "\n" : '';
        return $modified_html;
    }

Ha ha, it should be here. I changed the location so much that I forgot

But I found that the correct markdown tag would be:

> [!NOTE]
> 
>row 1
> 
> row2
> 
> ...more

For [!NOTE] tags, etc., you should use this keyword or other algorithms to identify the icon you need, such as a warning icon with a prompt. I don't know if that description is correct.

For example, I handle the blockquote tag in the front-end JavaScript:

var mapping = {
        '[!NOTE]': { className: 'note', displayText: 'NOTE' },
        '[!TIP]': { className: 'tip', displayText: 'TIP' },
        '[!IMPORTANT]': { className: 'important', displayText: 'IMPORTANT' },
        '[!WARNING]': { className: 'warning', displayText: 'WARNING' },
        '[!CAUTION]': { className: 'caution', displayText: 'CAUTION' }
      }

      // Select all blockquote elements
      var blockquotes = el.querySelectorAll('blockquote')
      // Iterate over each blockquote
      blockquotes.forEach(function (blockquote) {
        // Get the first child element
        var firstChild = blockquote.firstElementChild
        // Check if the first child is a <p> element
        if (firstChild && firstChild.tagName.toLowerCase() === 'p') {
          // Get the trimmed text content of the first child
          var content = firstChild.textContent.trim()

          // Check if the content matches one of the keys in the mapping object
          if (mapping[content]) {
            // Get the corresponding class name and display text
            var className = mapping[content].className
            var displayText = mapping[content].displayText

            // Add the corresponding class to the blockquote
            blockquote.classList.add('blockquote-' + className)
            console.log(firstChild)
            // Replace the first child's content
            firstChild.innerHTML = '<span class="icon-color-' + className + '"><i class="ali icon-' + className + ' icon-color-' + className + '"></i>' + displayText + '</span>'
          } else {
            console.log('No <p> element found in blockquote')
            blockquote.classList.add('blockquote-default')
          }
        }
      })

It allows lines with the [!NOTE] keyword to be replaced with ICONS

@Meng-Heng yes,I changed the code at the elements function:

protected function elements(array $Elements)
    {
        $markup = '';

        $autoBreak = true;

        foreach ($Elements as $Element) {
            if (empty($Element)) {
                continue;
            }

            $autoBreakNext = (isset($Element['autobreak'])
                ? $Element['autobreak'] : isset($Element['name'])
            );
            // (autobreak === false) covers both sides of an element
            $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext;

            $markup .= ($autoBreak ? "\n" : '') . $this->element($Element);
            $autoBreak = $autoBreakNext;
        }
        $modified_html = preg_replace_callback(
            '#<blockquote>\s*<p>(.*?)</p>\s*</blockquote>#s',
            function ($matches) {
                // 将内容按换行符分割
                $lines = preg_split('/\r\n|\r|\n/', $matches[1]);
                // 为每一行添加 <p> 标签
                $lines = array_map(function ($line) {
                    /* switch ($line) {
                        case '[!NOTE]':
                            $line = '<span class=\'blockquote-tag note\'></span>';
                            break;
                        case '[!IMPORTANT]':
                            $line = '<span class=\'blockquote-tag important\'></span>';
                            break;
                        case '[!WARNING]':
                            $line = '<span class=\'blockquote-tag warning\'></span>';
                            break;
                        case '[!TIP]':
                            $line = '<span class=\'blockquote-tag tip\'></span>';
                            break;
                        case '[!IMPORTANT]':
                            $line = '<span class=\'blockquote-tag important\'></span>';
                            break;
                    } */
                    return '<p class=\'blockquote-p\'>' . (trim($line)) . '</p>';
                }, $lines);
                // 重新组合 <blockquote> 内容
                return '<blockquote>' . implode('', $lines) . '</blockquote>';
            },
            $markup
        );

        // dump($markup);
        // dump($modified_html);
        $modified_html .= $autoBreak ? "\n" : '';
        return $modified_html;
    }

Ha ha, it should be here. I changed the location so much that I forgot

But I found that the correct markdown tag would be:

> [!NOTE]
> 
>row 1
> 
> row2
> 
> ...more

For [!NOTE] tags, etc., you should use this keyword or other algorithms to identify the icon you need, such as a warning icon with a prompt. I don't know if that description is correct.

For example, I handle the blockquote tag in the front-end JavaScript:

var mapping = {
        '[!NOTE]': { className: 'note', displayText: 'NOTE' },
        '[!TIP]': { className: 'tip', displayText: 'TIP' },
        '[!IMPORTANT]': { className: 'important', displayText: 'IMPORTANT' },
        '[!WARNING]': { className: 'warning', displayText: 'WARNING' },
        '[!CAUTION]': { className: 'caution', displayText: 'CAUTION' }
      }

      // Select all blockquote elements
      var blockquotes = el.querySelectorAll('blockquote')
      // Iterate over each blockquote
      blockquotes.forEach(function (blockquote) {
        // Get the first child element
        var firstChild = blockquote.firstElementChild
        // Check if the first child is a <p> element
        if (firstChild && firstChild.tagName.toLowerCase() === 'p') {
          // Get the trimmed text content of the first child
          var content = firstChild.textContent.trim()

          // Check if the content matches one of the keys in the mapping object
          if (mapping[content]) {
            // Get the corresponding class name and display text
            var className = mapping[content].className
            var displayText = mapping[content].displayText

            // Add the corresponding class to the blockquote
            blockquote.classList.add('blockquote-' + className)
            console.log(firstChild)
            // Replace the first child's content
            firstChild.innerHTML = '<span class="icon-color-' + className + '"><i class="ali icon-' + className + ' icon-color-' + className + '"></i>' + displayText + '</span>'
          } else {
            console.log('No <p> element found in blockquote')
            blockquote.classList.add('blockquote-default')
          }
        }
      })

It allows lines with the [!NOTE] keyword to be replaced with ICONS

Perhaps the [!NOTE] can be changed directly to a recognizable icon in the Parsedown elements function

I'm doing this in a different way but yours's seems a bit more complicated. Did you get it to appear as expected?

Note

42

I'm doing this in a different way but yours's seems a bit more complicated. Did you get it to appear as expected?

Note

42

@Meng-Heng Yes, it worked as I expected, and it was a bit more complex, haha, I'm not a professional programmer and my code looks a bit weird.
20240827221618

That's awesome to see, @xfstu ! I am using the from Parsedown, the code is definitely easy to read but hard to configure.