<pre>要素内のコードブロックに行番号を表示する

これは何?

HTMLの末尾で読み込むことで、DOMをいじって各種機能を提供するJavaScriptであるpostprocess.jsの一部です。

GitHubにも置いてあります。リポジトリは「<pre>要素内のコードブロックに行番号を表示する」と共有しています。

https://github.com/kmaebashi/postprocess

HTMLの終わりの方、</body>の直前あたりで、以下のように読み込む使い方を想定しています。
(前略)
<script src="./postprocess.js"></script>
</body>
</html>

postprocess.jsは、上記<script>要素を読み込んだ時点で実行され、かつ、その時点で本文のDOMが構築済みであることを想定しているため、必ずページの末尾で読み込まなければいけません。

使い方

HTML内にソースコード等を載せる際、linenumberクラスを付与した<pre>要素として記述すると、行番号を付けてくれる機能です。この「コピペで使おう! ライブラリ」のページに貼ってあるソースはすべてこれで行番号を付けています。

このWebサイトでは、以前は、ソースを貼るときは、大昔に作った自作のCプログラムでHTML内に直接行番号を含めていました(たとえばここに実例があります)。しかし、この方法だと、Webページからソースをコピペしようとすると行番号も付いてきてしまいます。このプログラムを使えば、行番号抜きでのコピペが可能です。

<pre class=linenumber>
#include &lt;stdio.h&gt;

int main(int argc, char **argv)
{
    printf("hello, world.\n");

    return 0;
}
</pre>

このように書くと、以下のように行番号が振られます。

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("hello, world.\n");

    return 0;
}

<pre>内に記述するコードは、HTMLのエスケープが事前に行われている前提です(上記hello, worldの「#include <stdio.h>」を参照のこと)。

これで生成されるコードブロックは、1行2列の<table>要素であり、左の<td>に行番号が、右の<td>にソースが入れられています。以下のclass属性が付与されているので、見た目はCSSでいじってください。

要素 class属性
table全体 linenumbertable
左のpre linenumber-left-td
右のpre linenumber-right-td

ソース

postprocess.js(この機能分だけ抜粋)

"use strict;"

const lineNumberPreArray = document.querySelectorAll("pre.linenumber");
for (codePre of lineNumberPreArray) {
  const tableElem = document.createElement("table");
  tableElem.classList.add("linenumbertable");
  const trElem = document.createElement("tr");
  tableElem.appendChild(trElem);
  const leftTdElem = document.createElement("td");
  leftTdElem.classList.add("linenumber-left-td");
  trElem.appendChild(leftTdElem);
  const leftPreElem = document.createElement("pre");
  leftTdElem.appendChild(leftPreElem);
  const rightTdElem = document.createElement("td");
  rightTdElem.classList.add("linenumber-right-td");
  trElem.appendChild(rightTdElem);
  const rightPreElem = document.createElement("pre");
  rightTdElem.appendChild(rightPreElem);

  // 文字列を\nで区切ると最後の\nの分だけ1行多くなるので1削っている。
  const lineCount = codePre.innerText.split("\n").length - 1;
  let lineNumbers = "";
  for (let i = 0; i < lineCount; i++) {
    lineNumbers += ("" + (i+1)).padStart(3) + ":\n";
  }
  leftPreElem.innerText = lineNumbers;
  rightPreElem.innerHTML = codePre.innerHTML;

  codePre.parentElement.replaceChild(tableElem, codePre);
}

3行目でlinenumberクラスの<pre>をかき集め、それらすべてについて(4行目のループ)、中に1行2列の<table>要素を作って、左の<td>の中の<pre>(leftPre)には必要な数だけ行番号を突っ込み(20~26行目)、右の<td>の中の<pre>(rightPre)には元の<pre>の中身(ソース)を突っ込んでいます。

いまどき、コードを貼るなら、<pre>だけでなく<code>でも囲むのが普通のような気はしますが、それをやると行数の算出が変わってくるのと、うちのページでは見た目同じなのでやっていません。

このページと同等の見た目になるCSSも貼っておきます。

table.linenumbertable {
  margin-left: 2em;
  background: #ccffff;
  border-right: solid 1px #99cccc;
  border-bottom: solid 1px #99cccc;
  margin-top: 0px;
}

table.linenumbertable pre {
  margin-top: 0px;
  margin-bottom: 0px;
}

td.linenumber-left-td {
  padding-top: 5px;
  padding-bottom: 5px;
  padding-right: 3px;
  border: none;
  color: #0000ff;
}

td.linenumber-right-td {
  padding-top: 5px;
  padding-bottom: 5px;
  padding-right: 30px;
  border: none;
}

公開日: 2024/01/06



不具合等ありましたら、掲示板にご連絡願います。

ひとつ上のページに戻る