s9e / phpbb-ext-highlighter

MIT License
15 stars 8 forks source link

Turn off language autodetection #12

Closed mb4e closed 10 months ago

mb4e commented 10 months ago

Hello,

I'm trying to turn off the highlight.js language detection in this phpbb extension, because even if a code tag does not have a lang attribute, there is still syntax highlighting, which I do not want. The problem seems more complicated than I thought, as I haven't been able to find a working solution. Can someone help me ?

Thanks for the work, MB.

JoshyPHP commented 10 months ago

I believe you can disable the syntax by using something like none, plain, or text as the language. The first two may disable Highlight.js style as well.

mb4e commented 10 months ago

Yes, but this means that you would have to edit all messages that already contain code tags in order to add plaintext language. I thought it would be possible to modify the extension code a little to ensure that this plaintext language was added on the fly.

JoshyPHP commented 10 months ago

I don't have a working phpBB install to test it but I'd do something like that, preferably in its own extension using the same onConfigure method as the one in this extension.


$dom = $configurator->tags['CODE']->template->asDOM();
foreach ($dom->getElementsByTagName('code') as $code)
{
    $attrValue = trim($code->getAttribute('class') . ' language-');
    $code->removeAttribute('class');

    $choose = $code->prependXslAttribute('class', $attrValue)->appendXslChoose();
    $choose->appendXslWhen('@class')->appendXslValueOf('@lang');
    $choose->appendXslOtherwise('plaintext');
}
$dom->saveChanges();

It adds a <xsl:choose> conditional that sets the language to plaintext if there was none provided.

You'll probably have to remove the original language-{@class} from $attrValue too.

mb4e commented 10 months ago

Thank you, I just tried and it seems to me that this modification causes all the codes to be in plaintext format, including those whose language had been specified.

Edit: I must have made a mistake since I don't understand exactly how it works, but I edited the listener.php file of the extension in order to modify the onConfigure method, as shown below.

    public function onConfigure($event)
    {
        $configurator = $event['configurator'];
        if (!isset($configurator->tags['CODE'], $configurator->BBCodes['CODE']))
        {
            return;
        }

        $configurator->BBCodes['CODE']->defaultAttribute = 'lang';
        if (!isset($configurator->tags['CODE']->attributes['lang']))
        {
            $attribute = $configurator->tags['CODE']->attributes->add('lang');
            $attribute->required = false;
            $attribute->filterChain->append('#identifier');
        }

        $attribute = $configurator->tags['CODE']->attributes['lang'];
        $attribute->filterChain->prepend('#map')->setMap(
            [
                'asy' => 'cpp',
            ],
            false
        );
        $attribute->filterChain->prepend('strtolower');

        $dom = $configurator->tags['CODE']->template->asDOM();
        foreach ($dom->getElementsByTagName('code') as $code)
        {
            $code->setAttribute('class', trim($code->getAttribute('class') . ' language-{@lang}'));
            $attrValue = trim($code->getAttribute('class') . ' language-');
            $code->removeAttribute('class');
            $choose = $code->prependXslAttribute('class', $attrValue)->appendXslChoose();
            $choose->appendXslWhen('@class')->appendXslValueOf('@lang');
            $choose->appendXslOtherwise('plaintext');
        }
        foreach ($dom->getElementsByTagName('pre') as $pre)
        {
            $pre->setAttribute('data-s9e-livepreview-hash', '');
            $pre->setAttribute('data-s9e-livepreview-onupdate', "if(typeof hljsLoader!=='undefined')hljsLoader.highlightBlocks(this)");
        }
        $dom->saveChanges();
    }

On the other hand, I'm not sure I understand correctly, but does the following code ensure that the pre tags are processed by highlight.js ? If so, would it be possible to ensure that highlight.js is not called when the pre tag contains code without a specified language ? I don't know if this is possible, but I was initially considering something like this.

$pre->setAttribute('data-s9e-livepreview-hash', '');
$pre->setAttribute('data-s9e-livepreview-onupdate', "if(typeof hljsLoader!=='undefined')hljsLoader.highlightBlocks(this)");

Thanks again for the help.

JoshyPHP commented 10 months ago
      $code->setAttribute('class', trim($code->getAttribute('class') . ' language-{@lang}'));

If you're modifying the extension itself (which I don't really recommend, it's better to write a small independent extension instead) then you can remove that line.

On the other hand, I'm not sure I understand correctly, but does the following code ensure that the pre tags are processed by highlight.js ? If so, would it be possible to ensure that highlight.js is not called when the pre tag contains code without a specified language ? I don't know if this is possible, but I was initially considering something like this.

The data-s9e-livepreview attributes only relate to Live Preview, which phpBB does not use. The hljs-loader script always loads if there's a code block and IIRC it manually highlights all code blocks, that's why you'd have to explicitly mark it as plaintext.

mb4e commented 10 months ago

Thank you for the explanations.

I had initially tested without the line you suggested removing, but the result is that all code tags end up in plaintext mode, even if another lang attribute was specified.

For the moment I am modifying the extension directly, but if everything works I will be able to separate it into a new extension. Besides, I modified the extension as shown below, in order to use the latest version. I don't know if it was a good idea.

$parameters = [
    'hljs_options'     => '',
    'hljs_style'       => 'github',
    'hljs_url'         => '',
    'needs_loader'     => 1,
    'script_integrity' => 'sha384-E9ssooeJ4kPel3JD7st0BgS50OLWFEdg4ZOp8lYPy52ctQazOIV37TCvzV8l4cYG',
    'script_src'       => 'https://cdn.jsdelivr.net/gh/s9e/hljs-loader@1.0.34/loader.min.js'
];
mb4e commented 10 months ago

Hello, I finally figured out what was wrong. It was simply necessary to replace @class with @lang in the following line.

$choose->appendXslWhen('@class')->appendXslValueOf('@lang');

The following code therefore seems to work.

    public function onConfigure($event)
    {
        $configurator = $event['configurator'];
        if (!isset($configurator->tags['CODE'], $configurator->BBCodes['CODE']))
        {
            return;
        }

        $configurator->BBCodes['CODE']->defaultAttribute = 'lang';
        if (!isset($configurator->tags['CODE']->attributes['lang']))
        {
            $attribute = $configurator->tags['CODE']->attributes->add('lang');
            $attribute->required = false;
            $attribute->filterChain->append('#identifier');
        }

        $attribute = $configurator->tags['CODE']->attributes['lang'];
        $attribute->filterChain->prepend('#map')->setMap(
            [
                'asy' => 'cpp',
            ],
            false
        );
        $attribute->filterChain->prepend('strtolower');

        $dom = $configurator->tags['CODE']->template->asDOM();
        foreach ($dom->getElementsByTagName('code') as $code)
        {
            $attrValue = trim($code->getAttribute('class') . ' language-');
            $code->removeAttribute('class');
            $choose = $code->prependXslAttribute('class', $attrValue)->appendXslChoose();
            $choose->appendXslWhen('@lang')->appendXslValueOf('@lang');
            $choose->appendXslOtherwise('plaintext');
        }
        foreach ($dom->getElementsByTagName('pre') as $pre)
        {
            $pre->setAttribute('data-s9e-livepreview-hash', '');
            $pre->setAttribute('data-s9e-livepreview-onupdate', "if(typeof hljsLoader!=='undefined')hljsLoader.highlightBlocks(this)");
        }
        $dom->saveChanges();
    }

Thanks again.