ことれいのもり

JavaScriptでコードブロックに言語ラベルを自動で抽出して表示する方法

はじめに

プログラムの記事を書いていて、コードブロックからプログラミング言語を自動で抽出してラベル表示させたいと思った事はありませんか?

この記事では、JavaScriptを使って、HTML構造から特定のクラスを抽出する方法を紹介します。

初心者でも分かりやすいように丁寧に解説していきます!

実現したいもの

今回実装したい物は、コードブロックの上に言語名を表示するというものです。

画像の赤枠で囲った部分です。


コードブロックの上に言語名を表示


この部分のHTMLを見てみましょう。

<p>導入方法はとても簡単です。</p>|
<p>あなたのプロジェクトのheaderかfooterに以下のscriptタグを追加するだけです。</p>
<div class="code-block">
    <pre class="line-numbers" data-copy="true">
        <code class="language-html">&lt;scriptsrc="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"&gt;&lt;/script&gt;
        </code>
    </pre>
</div>


HTML内には「Html」という文字列はありません。

これは、HTMLで記述しているわけではなく、JavaScriptを使ってクラス名から抽出しているからです。


今回のゴールは、コードブロック内のクラスから「言語名」を表示させることです。

実装方法

実装方法は以下の通りです。


  1. codeタグ全体を div タグで囲い、任意のクラス名(例: code-block)をつける
  2. codeタグのクラス名を、language-言語名 にする(例: language-html)
  3. JavaScriptを使って抽出する


詳しく見ていきましょう

1. codeタグ全体をdivタグで囲い、任意のクラス名をつける

以下のようなコードブロックがあるとします。

場合によってはpreタグが前に存在する場合もあると思うので、今回はpreタグもあると仮定して進めます。(なかったらcodeタグだけでも大丈夫です)

<pre>
    <code>
        x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
    </code>
</pre>


まずは全体をdivブロックで囲みます。

このとき、「コードブロックを囲んでいる」という事が分かるような任意のクラス名をつけます。

今回は、code-blockというクラス名にしました。


<div class="code-block">
    <pre>
        <code>
            x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
        </code>
    </pre>
</div>


これで、コードブロックの塊が認識しやすくなりました。

2. codeタグのクラス名を language-言語名 にする

codeタグのクラス名をlanguage-言語名にします。

HTMLの場合は、language-html、テキストの場合は、language-textです。

<div class="code-block">
    <pre>
        <code class="language-text">
            x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
        </code>
    </pre>
</div>

3~4. JavaScriptコード紹介

この後文字列を抽出しますが、先にJavaScriptの全体像を載せておきます。

細かい解説は各ステップで行ないます。

document.querySelectorAll('.code-block').forEach(block => {
  const codeElement = block.querySelector('code');
  // 言語抽出
  const languageClass = codeElement.className.split(' ').find(className => className.startsWith('language-'));
  const language = languageClass.replace('language-', '');
  
  const label = document.createElement('div');
  label.className = 'language-label';
  label.textContent = language.charAt(0).toUpperCase() + language.slice(1);
  block.insertBefore(label, block.firstChild);
})

3. コード解説前半: 要素の抽出

// .code-blockを取得してforEachで1つずつ処理する
document.querySelectorAll('.code-block').forEach(block => {

  // 各code-block内の<code>要素を取得
  const codeElement = block.querySelector('code');

  // 前半:code.className.split(' ')でクラス名を配列に分割する
  // 後半: findを使って language- で始まるクラス名を見つける
  const languageClass = codeElement.className.split(' ').find(className => className.startsWith('language-'));

  // 言語名を抽出
  const language = languageClass.replace('language-', '');

  // ...
  // 後半へ続く
  // ...
})


前半部分では、要素を抽出します。

まず、code-blockというdivタグのクラスを全て取得します。

ここで得られた要素1つ1つに対して以下の処理をしていきます。

  • code-block内のcode要素を取得
  • code要素のクラス名を分割して後半部分のみ抽出


これで、言語名の文字列が抽出できました。

4. コード解説後半: divタグで生成

// .code-blockを取得してforEachで1つずつ処理する
document.querySelectorAll('.code-block').forEach(block => {
  // ...
  // 前半の続き
  // ...

  // divタグを動的に生成する
  const label = document.createElement('div');
  
  // divタグの各要素を設定する
  // class名は language-label
  label.className = 'language-label';
  
  // 文字列は先頭1文字のみ大文字にする
  label.textContent = language.charAt(0).toUpperCase() + language.slice(1);
  
  // code-blockの先頭にこのdiv要素を挿入する
  block.insertBefore(label, block.firstChild);
})


後半部分では、前半で取得した文字列をdiv要素にセットして動的に生成します。


まずは、labelというオブジェクトを宣言し、div要素を作成します。

このときクラス名、文字列を設定しますが、文字列は先頭1文字目は大文字にしています。

ここの処理は任意です。(javascriptのときにJavascriptと表記したいので先頭のみ大文字にしています)

最後に、code-block要素の前に挿入したら完成です。


これで、コードブロックの前に言語名を表示することができました!

おわりに

今回は、コードブロックからプログラミング言語を自動で抽出して表示する仕組みの実装方法を紹介しました。

やっていることは、クラス名から文字列を抽出しHTMLを動的に生成しているだけで、とてもシンプルです!

このやり方を応用すれば、いろいろな事が実現できると思います。

参考になれば幸いです。