【解説付き】コードゴルフでマークダウンメモ帳を、ブラウザにつくってみた

## メモ帳 + マークダウンのシンタックスハイライト
ブラウザで以下のURLを開くと、メモ帳になります。自動でマークダウンのようなシンタックスハイライトをつけてくれるようにしました。
このURLブックマークしとくとよいです！
```.js
data:text/html,<html contenteditable style="background:black;color:white">Note<script>window.onload=()=>document.body.oninput=()=>{for(D=document.querySelectorAll('div'),i=0;++i<D.length;D[i].style=D[i].innerHTML.startsWith('-')?'color:red;font-weight:bold;font-size:x-large':'');}</script>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453310/e00dcf3a-1b20-d1f2-4b85-c10e8550adf6.png)

また、Ctrl+Sなどの保存でhtmlファイルとして保存できますし、開き直せば引き続き編集ができます。
htmlファイルとして保存すればlocalStorageなどが使えるようになりますので、より多く機能を盛り込むこともできます。
ぜひ遊んでみてください。
※あくまで簡易的なものなので、大事な情報はちゃんとしたエディタで管理して下さい！


## 解説
### 1️⃣data url, contenteditableさえあればメモ帳として機能
```.js
data:text/html,<html contenteditable>
```
[data url](https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)を使用しています。
`data:text/html`までが宣言なので、ここでは`<html contenteditable>`のみが描画されることになります。

[`contenteditable`属性](https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/contenteditable)は、htmlを画面上で直接編集できる属性です。
Ctrl+BやCtrl+I（macではcmd+B,cmd+I）で、ボールド太文字やイタリック斜体にもできます。
なんて便利な属性。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453310/183d50c7-4586-8af0-cc48-496b3aa1eba8.png)


しかしこのままでは真っ白なので、styleで背景黒、文字白にしました。お好みでカスタマイズください。
```.html
data:text/html,<html contenteditable style="background:black;color:white">
```


### 2️⃣シンタックスハイライト（ただのCSS）をつけてみる
```.html
<script>window.onload=()=>document.body.oninput=()=>{for(D=document.querySelect
orAll('div'),i=0;++i<D.length;D[i].style=D[i].innerHTML.startsWith('-')?'color:r
ed;font-weight:bold;font-size:x-large':'');}</script>
```
次にscriptですが、data urlに入れる際は閉じタグがないと動作しないので注意。

また、URLに全て詰め込んでいる関係上、`#`がURLとして扱われてしまうため
マークダウンの`#`で`<h2>`にする処理ができませんでした。
代わりに`ハイフンから始まればタイトル文字とする`としています。

ミニマムにしてますが、冗長に書くと以下と同等のソースになっています
```.html
<script>
// このままだとscriptタグがbodyの中にあり、bodyがないままだとイベント登録できない。
// bodyが読み込まれた後に起動したいので、window.onloadイベントとして登録。
window.onload = () => {
  // contenteditableへの入力はonchangeでなく、oninputイベントで拾えます
  document.body.oninput = () => {
    // contenteditableで改行すると、1行文がdivとして作られます
    let D = document.querySelectorAll('div'); // div要素(行)を全て取得
    for (i = 0; i < D.length; i++) {
      let d = D[i]; // 1行分

      // ここほんとは「#から始まる」場合、としたかったがURLに#いれらんない ;w;
      if (d.innerHTML.startsWith('-')) {
        // シンタックスハイライト、お好みでどうぞ
        d.style = 'color:red;font-weight:bold;font-size:x-large'
      } else {
        // ハイフン消したらスタイルも戻す
        d.style = ''
      }

    }
  }
}

</script>
```

※通常forを使いたくてこう書いてますが、実際はこっちの方が見やすそうですね
```js
Array.from(document.querySelectorAll('div'))
.map(v => {
  v.style = v.innerHTML.startsWith('-')
    ? 'color:red;font-weight:bold;font-size:x-large'
    : ''
})
```

### 3️⃣コードゴルフしてソースを圧縮する
前提としてソースを圧縮する術を解説します。
他のソース圧縮技術については以下などが面白いので、興味がある方はぜひ見てみてください！
※もちろん可読性が著しく下がりますし、変数の安全性などが保証できず、バグを生む危険性がとても上がりますので、実際の開発で使うことはありません。
※あくまで、コード量を極限まで減らすネタテクニックとして参考にしてください。

https://qiita.com/ryuichi1208/items/f9e6ac2b99bbe4fc82d3

https://qiita.com/obake_fe/items/041715068665dc94aac4

https://qiita.com/ichimonji_haji/items/f602f6c437be9e7daa88

---
※windowをthisにしていなかったりlengthを使っていたりと、ちょいちょいゆるくやってます、これは完全に圧縮しきっていません。

#### ショートハンド
```.js
for (let i=0; i<10; i++) {
  console.log(i)
}
if (i === 0) {
  console.log(i)
}
```
このような書き方を
```.js
for (let i=0; i<10; i++) console.log(i);
if (i === 0) console.log(i);
```
とできます。
閉じ括弧`}`がないため、1行終わりの合図としてセミコロン`;`をつけています。
次の文がある時など、セミコロンがないと文法エラーである時もあるので注意。
#### 変数宣言の工夫
変数宣言時に`var`や`let`を省きます。
```.js
let i = 0 // これは
i=0 // これでOK
```
forやifの中で無理やり変数を宣言します。
```.js
a=b=0 // これでaとbが0で宣言されるし
a=0,b=1 // これでaが0、bが1で宣言される

for (i=0; i<10; i++) console.log(i); // これに加えて
for (i=0,l=1; i<10; i++) console.log(i+l); // 2つ変数が宣言できる

if (i=0,l=1) console.log(i+l) // ifも同様にできる

for(a=[b=c=0] ... // こんなこともできる aは0を持つ配列、bとcは0
```

#### forの工夫
for文ですが
```.js
for (初期値; 次の周やるかの条件(式を書いたら周最初に実行); この式やる) この式やったあとに;
```
です。セミコロン`;`に注目してください。
```.js
for (i=l=0; i<5; console.log(l), i++, l++) console.log(i);
```
これで、

1. iとlを0で宣言し
2. console.log(i)をしてから
3. console.log(l)をして、iを増やし、lを増やす
4. iが5より小さいなら次の周にいかずに、ループ終了

となります。
今回のシンタックスハイライトのループを見てみましょう。
長いのでif文のところを、`console.log`にしています。
```元の書き方.js
D = document.querySelectorAll('div') // これもforの中で宣言しちゃえ
for (i = 0; i < D.length; i++) {
  d = D[i] // 最終的にはこの行も消します
  console.log(d)
}
```
```宣言をまとめる.js
for(D=document.querySelectorAll('div'),i=0;i<D.length;i++){
  d=D[i]
  console.log(d)
}
```
宣言部のquerySelectorが長くて見づらいので、いったん略します
```略した.js
for(略,i=0;i<D.length;i++){ // ここから下を1行にしたい
  d=D[i]
  console.log(d)
}
```
```ループ内処理をまとめる.js
          // ++を移動      // ここから右を中に入れる
for(略,i=0;++i<D.length;)d=D[i],console.log(d);
```
```全部、周終了時にまとめる.js
                      // ここがfor文の中でやる式になった
for(略,i=0;++i<D.length;d=D[i],console.log(d));
```
とできます。だいぶスッキリしましたね。

#### ifは三項演算子に
三項演算子については[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Conditional_operator)を参照。

```元.js
if (d.innerHTML.startsWith('-')) {
  d.style = 'color:red;font-weight:bold;font-size:x-large'
} else {
  d.style = ''
}
```
```三項演算子にした.js
d.style = d.innerHTML.startsWith('-')
  ? 'color:red;font-weight:bold;font-size:x-large'
  : ''
```
```1行に.js
d.style=d.innerHTML.startsWith('-')?'color:red;font-weight:bold;font-size:x-large':''
```

スタイルについては自由にすると良いですし、if文を追加すれば
より多くのシンタックスに適応できます。

(まぁあまり多くなると管理が面倒ですが。。)

#### まとめると

※`d=D[i]`と変数置かない方が文字数少ないので修正してます
```.html
data:text/html,<html contenteditable style="background:black;color:white">Note
<script>window.onload=()=>document.body.oninput=()=>{
// 見やすく改行しています

for(D=document.querySelectorAll('div'),i=0; // 変数を宣言
++i<D.length; // 増やしつつループ終了条件

         // ここから下が、ループ内の処理
D[i].style=D[i].innerHTML.startsWith('-')
  ?'color:red;font-weight:bold;font-size:x-large'
  :'');

}</script>
```

1行79文字で改行すると
```.html
<script>window.onload=()=>document.body.oninput=()=>{for(D=document.querySelect
orAll('div'),i=0;++i<D.length;D[i].style=D[i].innerHTML.startsWith('-')?'color:r
ed;font-weight:bold;font-size:x-large':'');}</script>
```
と、3行にまとまりました！

以上、コードゴルフでマークダウンメモ帳を、ブラウザにつくってみた でした〜！