選択範囲の数式を1クリックでコピーするブックマークレットのコード説明

本記事は↓のページで配布している「選択範囲にある数式のLaTeXコマンドを1クリックでコピーするブックマークレット」のソースコード説明や、カスタマイズのための情報提供を行っているページです。

数式コピー

[usemath] Webサイトで数式を表示する方法として最近、MathJaxやKaTeXといった数式表示JavaScriptライブラリがよく利用されるようになりました。 \begin{align*} x = \frac{-b\[…]

ソースコードはCC0 1.0(パブリックドメイン)で公開しているため、商用・非商用問わず誰でも自由に複製・改変・再配布できます。

またご利用にあたって申請も連絡もクレジット表記も不要です。

自分好みに改造したり、別のブックマークレットに組み込んだりするなどしてご自由にお使いください。

ソースコードの説明 (Ver.1.1.0)

該当ブックマークレット

See the Pen
選択したKaTeX数式を1クリックでコピー
by Pajoca (@Pajoca)
on CodePen.

CC0
Pajoca (パジョカ) はこのソースコードの全ての著作権および関連する権利をCC0により放棄しています。

 

ソースコードの概要

概要

ページ中の数式のLaTeXコマンドはKaTeXなら<annotation>要素内、MathJax(Ver2)なら<script>要素内に記述されています。

選択範囲にある特定の<annotation>要素 / <script>要素内の文字列を取得して1数式ごとに改行を挿入し、クリップボードに格納しています。

javascript:(function(){
  const MAIN_SELECTOR = "annotation[encoding=\"application/x-tex\"], script[type=\"math/tex\"], script[type=\"math/tex; mode=display\"]";
  const SUB_SELECTOR = "annotation, nwc-formula";
  const selection = window.getSelection();
  const selectionRange = selection.getRangeAt(0).cloneContents();

  let katexs = selectionRange.querySelectorAll(MAIN_SELECTOR);
  if(katexs.length === 0) katexs = selectionRange.querySelectorAll(SUB_SELECTOR);

  let copyText = "";
  for(let katex of katexs){
    copyText += katex.textContent+"\n";
  }
  navigator.clipboard.writeText(copyText).then(
  ()=>selection.removeAllRanges(),
  ()=>{}
  );
})()

大まかな流れ

  1. 選択範囲の取得(Selectionオブジェクトの取得) ← getSelection(), getRangeAt()
  2. MAIN_SELECTORで指定した要素を選択。該当要素が無ければ代わりにSUB_SELECTORで指定した要素を選択。
  3. 選択要素内の文字列(数式のTeXコマンド)を1個ずつ取り出し改行で繋げる
  4. クリップボードに書き込み。書き込み成功時は文字選択の解除。

 

説明 (文法や仕様)

選択関連の仕様について

選択範囲の取得方法と使い方

→ こちらのドキュメント参照:selection

ちなみにFirefoxブラウザの場合Ctrlキーにより複数の範囲を選択できるので、selectionオブジェクトが複数のrangeオブジェクトを持つことがある。

ただ今回のブックマークレットではgetRangeAt(0)で0番目のrangeオブジェクトしか取得していないため、複数範囲を選択していても1つ目の選択範囲の数式しかコピーされない。

選択に関する凄く分かりやすいドキュメント

→ 非常に丁寧かつ分かりやすく説明されているのでまずは以下を参照。

リンク: 選択(Selection) と 範囲(Range)

LaTeXコードの記述されている場所

数式描画ライブラリによってLaTeXの記述されている要素は異なる。

種類 LaTeXコマンドの記述要素
KaTeX <annotation encoding="application/x-tex">コマンド</annotation>
MathJax(V.2)
インライン数式
<script type="math/tex">コマンド</script>
MathJax(V.2)
ディスプレイ数式
<script type="math/tex; mode=display">コマンド</script>

querySelectorAll()は引数に指定したCSSセレクタ文字列に該当する要素を選択することができる。

ブクマレットではCSSセレクタとしてMAIN_SELECTORに

"annotation[encoding=\"application/x-tex\"], script[type=\"math/tex\"], script[type=\"math/tex; mode=display\"]"

を指定し、上記表で掲載した3種類の数式記述場所を指定している。
(※ダブルクォーテーション「"」内のダブルクォーテーションは「\"」でエスケープしている。)

 

また数式ライブラリの仕様変更により将来的に<annotation>要素の属性名や属性値が変更される可能性があるため、念のためSUB_SELECTORに属性なしの<annotation>要素を指定しておき、MAIN_SELECTORで何も要素がヒットしない場合はSUB_SELECTORにヒットする要素を選択する仕様にしている。

なおユーザーが数式表示関連のカスタムJavaScriptを使っている?と<nwc-formula>要素内にKaTeXの数式コマンドが記述される場合があるためそれもSUB_SELECTORに指定した。

なおこれらCSSセレクタ指定の文字列を編集すれば、その他の数式表示ライブラリの数式のLaTeXコマンドコピーも行える。

もっと言えば数式コマンドに限らず、選択範囲の(指定した)任意の要素のテキストをコピーできるブックマークレットが作れる

クリップボードへの書き込み

Clipboard.writeText()メソッドを使用。

navigator.clipboard.writeText(コピーしたい文字列).then(
  function() {書き込み成功時の処理}, 
  function() {書き込み失敗時の処理}
);

今回、書き込み成功時の処理はremoveAllRanges()メソッドによる選択範囲の解除。

失敗時は何もしない。

 

カスタマイズのための情報

カスタマイズ箇所

ソースコード先頭行の MAIN_SELECTOR に(中身の)文字列を抽出したい要素が対象になるCSSセレクタを指定すれば、選択範囲の(自分が指定した)好きな要素の文字列をコピーできるブックマークレットが作成可能

MAIN_SELECTOR に何の要素もヒットしなかった場合の保険は SUB_SELECTOR に指定すればOK。

MAIN_SELECTOR では属性名や属性値も含めた厳密な要素指定を行い、SUB_SELECTOR で緩めの要素指定を行えば仕様変更に耐えつつ不必要な要素に勝手にヒットしないようにできる。

(SUB_SELECTOR は MAIN_SELECTOR で何も要素が選択されなかった場合のみ使われるため)

ブックマークレット化するには

作成したソースコードをブックマークレット化するにはこちらのサイトが大変便利。

自動で改行やスペースを削除し短縮してくれる。

(function(){
★★この部分にソースコードを貼付★★
})()

※今回のブックマークレットの場合は★★の所に const MAIN_SELECTOR の行から ); の行までを貼り付ければOK。

しかし文字列中の空白まで削除されてしまうのでCSSセレクタが誤った物になってしまう

余計に書き換えられてしまった箇所は手動で空白を補い修正する。

誤:script[type=\"math/tex;mode=display\"]
正:script[type=\"math/tex; mode=display\"]
 ※セミコロン直後の空白

MathJax(Version 3)への対応について

MathJax3はHTMLソースコード中にLaTeXコードを埋め込んでいない仕様のため数式のLaTeXコマンドの取得ができない。

一応公式の機能として右クリックメニューから簡単にコマンドのコピー自体は可能ではあるけど、一括コピーのためのブックマークレットが作れなくて不便…。

この仕様についての報告を見る限り、対応は結構厳しそう…。

 

カスタマイズしたら教えて!

せっかくなのでこちらのブックマークレットをカスタマイズしたらコメント欄などでご紹介頂けると嬉しいです!

(もちろん任意です! 紹介は全く義務ではありません!)

ブックマークレットの配布は(私が行っているように)CodePenが便利です。

ユーザーがドラッグ&ドロップでブックマークレットを簡単に導入できます。

WordPressでブックマークレットをそのまま配布するのはかなり面倒ですが、CodePenなど外部サービスを埋め込めば簡単にできます。

配布時のドラッグ&ドロップボタンのデザインなども私のものをそのまま流用してもらって構わないので、便利なブックマークレットができたらどんどんみんなで共有して行こみゃあ~ฅ/ᐠ˶>ω<˶ᐟ\ฅ

記事化前の最新情報はこちらで先にツイートしています。サイト更新告知もこちら。