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

Add selected language as a data- attribute in rendered code block #37

Closed
adriandomenico opened this issue Mar 4, 2020 · 15 comments · Fixed by #208
Closed

Add selected language as a data- attribute in rendered code block #37

adriandomenico opened this issue Mar 4, 2020 · 15 comments · Fixed by #208
Labels
changelogged enhancement New feature or request

Comments

@adriandomenico
Copy link

Excellent plugin. Nice and simple.

For my purposes I've added a rel tag to include the $language so I can use it as content in the ::before pseudo and style it on the front end.

Line 245:
sprintf( ' rel=%s class="%s" ', esc_attr( $language ), esc_attr( $added_classes ) ),

Worth doing? It's a slight misuse of the rel tag so if you can think of a better solution...

@westonruter
Copy link
Owner

Please share the CSS you are using as well.

What about a data-* attribute?

@adriandomenico
Copy link
Author

adriandomenico commented Mar 5, 2020

Yes, I changed it to data-lang which works fine.

The basic CSS is:

pre {
    postion: relative;
}

.hljs {
    padding-top: 40px; /* to avoid line numbers */
}

.hljs::before {
    position: absolute; /* break out from the line numbers */
    display: block;
    content: attr(data-lang);
    top: 0;
    left: 0;
    width: 100%;
    padding: 5px 0 5px 1em;
    text-transform: uppercase;
    background: rgba(0, 0, 0, 0.03);
}

It looks fine on a static block but I'm playing with scrolling the code block at fixed height, so it disappears on scroll because of overflow: auto. That's not a big deal. It either needs a <div> external to the code block or .hljs element which is set to scroll, or I need to understand how to make it show from 'behind' the overflow!

code-with-language-tag

Note, the "CSS" tag at the bottom in this image, is a styled paragraph block made to look like a caption on the front end.

Hope this helps.

@westonruter
Copy link
Owner

@Broken8 Thanks, that's helpful.

Actually you can accomplish what you want today using this PHP code in a custom plugin or your custom theme's functions.php:

add_filter(
	'render_block',
	function( $block_content, $block ) {
		if ( 'core/code' === $block['blockName'] && preg_match( '/class="hljs language-(?P<lang>\w+)/', $block_content, $matches ) ) {
			$block_content = preg_replace(
				'/(?<=<code\s)/',
				sprintf( ' data-lang="%s" ', esc_attr( $matches['lang'] ) ),
				$block_content
			);
		}
		return $block_content;
	},
	10,
	2
);

@adriandomenico
Copy link
Author

adriandomenico commented Mar 5, 2020

@westonruter You read my mind. I'd prefer to do that for this theme but I struggle with the back end, so thank you so much for this. Amazing! It works like a charm.

If you can keep the plugin lightweight, a switchable option - like you've done with the line numbers - would be nice.

Thanks again.

PS: When I release this theme, this plugin will be recommended in the TGM package.

@studiochris
Copy link

studiochris commented Apr 6, 2020

Can this one be opened again?

I added the filter mentioned above (only, I changed it from applying to the code tag to applying to the pre tag). It works, but the result isn't always the expected result.

For instance, with HTML (both auto-detected and manually selected as "HTML, XML" from the dropdown), the resulting data-lang attribute is xml. While this is technically true, and the highlighting is right, the language is not correct.

I assume the same would apply to any of the other aliases listed in languages/xml.json — they'd all be returned as just XML.

JavaScript's data-lang is javascript, which looks strange in all-caps using similar CSS as @Broken8 listed above.

For my use-case, I'd like to be able to arbitrarily, and correctly, tag code blocks, no matter the primary highlighting language. As examples:

  • JavaScript tagged as JS, JavaScript, Node.js, React, JSX (React or Adobe ExtendScript), Electron, or NWjs
  • XML tagged as HTML, SVG, MXML, or Vue.js (for single-file components, which should be possible due to the subLanguage values in languages\xml.json)

@allejo
Copy link
Collaborator

allejo commented Apr 7, 2020

I can reopen this issue up for more discussion but I'm not sure how I'd feel about requiring users to manually correct each javascript block as JavaScript or Javascript or JS if they want this behavior. Is there a better way of handling this?

  • Do we just add a list of stylized language names in the filter above?
  • Do we have an optional input box for each code block? If no value is provided, it'll default to the language name (stylized or unstylized)

@allejo allejo reopened this Apr 7, 2020
@studiochris
Copy link

My thought is just to add an optional attribute that can be filled in or left blank. If blank, it will use the auto-detected or chosen language (really, this is perhaps niche and not worth pursuing -- it's just a wishlist item for me). Currently, I'm overriding it using CSS, which isn't ideal, but it gets the job done.

Perhaps a more universal approach would be to add a second dropdown (or use option groups in the current dropdown) to include the aliases that are in the language files, so HTML, SVG, and others can be explicitly chosen. In normal highlight.js usage, the language could be defined as an alias in the class name.

@allejo
Copy link
Collaborator

allejo commented Apr 13, 2020

For language naming, highlight.js 10 (currently in beta) has prettified language names in the definition files; so that'll be available in highlight.php 10 and we could make use of that for this feature.

However, no ETA on highlight.php 10 since the release schedule for that is typically a few weeks behind the highlight.js project. With it being a breaking release, it may take a bit longer for me to port changes especially if internal APIs changed/broke.

In normal highlight.js usage, the language could be defined as an alias in the class name.

Could you provide an example of this behavior?

@studiochris
Copy link

From highlight.js Usage, all of these would highlight as HTML (which is defined as an alias of XML):

<pre><code class="html">...</code></pre>

<pre><code class="lang-html">...</code></pre>

<pre><code class="language-html">...</code></pre>

Looking at highlighted blocks on the Usage page, the markup of the first example above becomes:

<pre>
  <code class="html hljs xml">
    ...highlighted code...
  </code>
</pre>

It adds hljs and the primary xml language as CSS classes but preserves the original html class, which was used to find that the block should be highlighted with the XML language definition.

For JavaScript, it's similar (with js being an alias of javascript):

<pre><code class="js">...</code></pre>

It adds hljs and the primary javascript language as CSS classes but preserves the original js class.

<pre>
  <code class="js hljs javascript">
    ...highlighted code...
  </code>
</pre>

@allejo
Copy link
Collaborator

allejo commented Apr 18, 2020

@studiochris so just to be sure I'm understanding you correctly, you would want this plug-in to let you pick either "JavaScript" or "JS" in the language selector in the editor so then you can use that value in your CSS?

@allejo allejo added the enhancement New feature or request label Apr 18, 2020
@allejo allejo changed the title FEATURE REQUEST: Code language tag Add selected language as a data- attribute in rendered code block Apr 18, 2020
@studiochris
Copy link

@allejo Sorry for the delay.

It's not necessarily important that I be able to pick "JS" or "JavaScript" from the language selector, but I'd be okay with that. I would like to use the language value in CSS (and I'm currently doing exactly that).

The most important thing to me is that the language chosen from the language selector is correct when it's transferred over to rendering on the front end.

HTML (and other sublanguages of XML per highlight.js are good examples. Currently, choosing "HTML/XML" from the language selector the rendered markup (modified slightly using the filter above -- and moving the data-lang attribute from the code tag to the pre tag) results in:

<pre data-lang="xml" class="wp-block-code">
  <code class="hljs language-xml">
    ...highlighted code...
  </code>
</pre>

XML is declared as the language, which is not correct. It's HTML. The same would be the case for SVG, another sublanguage of XML.

I'm working around it currently by adding additional classes that change what's displayed in the pre::before pseudo-element. I'd very much prefer to be able to choose the correct language and have that "stick" instead of having to write custom overrides.

A couple of examples are available at: https://studiochris.us/elements/ (scroll to the code blocks section -- I added an HTML block just so you can see it).

@allejo
Copy link
Collaborator

allejo commented May 13, 2020

The most important thing to me is that the language chosen from the language selector is correct when it's transferred over to rendering on the front end.

Got it! The language selection isn't related to this plugin but the underlying highlight.php (and therefore highlight.js) behavior of how sublanguages work. If I'm not mistaken, sublanguage detection changed somehow in highlight.js 10.x. Once highlight.php is ported over, then the language accuracy of sublanguages can be investigated.

@ronalfy
Copy link

ronalfy commented Oct 25, 2020

Just wanted to add a +1 to this one. Here's how I tackle it currently, but it would be nice if some variation of this is included in the core plugin or able to be added via filter with the language being passed so we can customize the text, which may be the better alternative here as there are many use-cases and customizations that could be achieved.

Gist here: https://gist.github.com/ronalfy/2dbb84ceee04328d6bca98b21df7fb1c

Screenshot:

Screen Shot 2020-10-25 at 11 37 17 AM

@westonruter
Copy link
Owner

@ronalfy Why use the rel attribute? Is this valid? Shouldn't data-* attributes be used instead?

@westonruter
Copy link
Owner

Please give this PR a look: #208.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelogged enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants