初めてまともなWEBアプリを作ってみたので知見を走り書き

# 初めてまともなWEBアプリを作ってみたので知見を走り書き

この記事は[アドカレ](https://qiita.com/advent-calendar/2023/hachinohe_kosen)に参加しています。

## 反省会
初めてまともなWEBアプリを作ってみたので反省会をします。反省会は独りでやります。~~ぼっちって言うな~~

作ったWEBアプリのコードなどはこちらから見られます。

https://github.com/metaphysical-bard/mathjax-editor

### 1. contenteditable
一番の壁は`contenteditable`でした。やばすぎてこれだけで一本の記事になるレベルです。

https://qiita.com/metaphysical_bard/items/bc99f8a7c31e58a53c6f

はい、次。

### 2. CSS変数
CSSで変数を使えるというのがCSS変数です。これは革命です。

```css
:root {
  /*変数を宣言*/
  --text-color: #000000;
  --border-size: 3px;
}

div {
  /*var()で変数の値を参照*/
  color: var(--text-color);
  padding: var(--border-size);
}

p {
  color: var(--text-color);
  padding: 10px;
}
```

はい。すごいです。

更にさらに、JavaScript側からCSS変数を取得、設定することもできます。
```javascript
//取得
let col = getComputedStyle(document.documentElement).getPropertyValue("--text-color")

//設定
document.documentElement.style.setProperty("--text-color", "#ff0000")
```
便利すぎる。

#### 参考
https://qiita.com/taqumo/items/b221e689c8c27500b47a

### 3. LaTeXから画像ファイル
LaTeXコードから画像ファイルを生成するにはいろいろな方法があるみたいです。`canvas`の`toDataURL`メソッドが一番楽そうだったので、それを用いて実装しました。

https://qiita.com/metaphysical_bard/items/b2e6b278be60877ad17b

### 4. コマンド処理
コマンドを入力することで特定の挙動を起こしたかったので、[コナミコマンド](https://ja.wikipedia.org/wiki/コナミコマンド)を参考にコマンド処理クラスを作りました。

```javascript
//(いろいろ省略してます)

class shortcut_M {
  array = {}//コマンドがどこまで入力されたかのフラグ

  //arrayをリセットする
  reset() {}

  //タイマーを止める
  uncheck() {
    if (this.timer_id !== undefined) {
      clearTimeout(this.timer_id)
      this.timer_id = undefined
    }
  }

  //タイマー起動
  check() {
    this.uncheck()
    this.timer_id = setTimeout(() => { this.reset() }, 3000)
  }

  constructor() { this.reset() }

  put(key) {
    if () {
      //コマンド入力で何らかの処理
      this.reset()
      this.uncheck()
      return true
    }
    else {
      this.reset()
      this.uncheck()
    }
    return false
  }
}
```

`keydown`イベントでどのキーが押されたかを確認していきます。コマンド以外のキーが押されたり、キーが3000ms以上押されなかった場合には`reset`メソッドが呼ばれます。
```javascript
let s = new shortcut_M()

ele.addEventListener("keydown", (event) => {
  s.put(event.key)
}
```

#### 参考
https://qiita.com/amamamaou/items/b663e3fae23031431535

### 5. 画面分割
画面分割しながらも、ユーザーがそれぞれの要素のサイズを動的に変えられるようなもの実装したいと考えました。スプリットウィンドウと呼ばれたりしているようです。

つまみ用の`element`を用意しておいて、そのつまみがドラッグされたら画面分割の比率も変更されるようにしました。

`Math.min(Math.max(num, min), max)`にして比率`num`が画面外(min~max)に行かないよう工夫しました。

#### 参考
https://contentsviewer.work/Master/Library/JavaScript/SplitView/docs

https://split.js.org/

### 6. 一部文字のエスケープ
`innerText`から文字列処理をしてDOM構造を構築し、`innerHTML`に直接挿入するような処理を書いたのですが、予約済み文字をエスケープしていなかったので躓きました。

4つの予約済み文字をしっかりエスケープしてから、文字列処理をして`innerHTML`する必要があります。
```javascript
ele.innerHTML = ele.innerText
  //予約済み文字をエスケープ
  .replace(/&/gu, "&amp;").replace(/</gu, "&lt;")
  .replace(/>/gu, "&gt;").replace(/"/gu, "&quot;")
  //文字列処理
  .replace(/(#[0-9a-fA-F]{6})/gu, "<span class=\"color\" style=\"background: $1;\"></span>$1")
  .replace(/(%[^<]*)/gu, "<span class=\"comment\">$1</span>")
```

#### 参考
https://developer.mozilla.org/ja/docs/Web/HTML/Element/pre

https://developer.mozilla.org/ja/docs/Glossary/Entity


### 7. 正規表現
初めて正規表現を使用しましたが、分かると意外と楽しかったです。簡単な文字列処理であれば正規表現で記述したほうが楽ですし、コードの可読性にも優れています。ただ、正規表現に慣れるまでが大変でした。正規表現の記法は暗黙のルールが多いように感じます。

#### 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_expressions

## むすび
独り反省会の議事録でした。

(後から見返すと反省会というよりほぼ備忘録ですね笑)

　
[bsky](https://bsky.app/profile/drywaterfall.bsky.social)