スマホのブラウザでも使い易いエディタ

_スマホのブラウザでも使い易いエディタを作りました。_

※ブラウザアプリ開発向けエディタです。
この記事では開発中に得た知見とか(私的備忘録的用途)を共有できればなと思います。
実はとある別のシステムに内蔵されているものなので
エディタ及びフロント以外のことも書いてるかもしれません。

# ES6で書きたいしrequireもしたいしいろんなところで動いてほしい
Webpackとかを使う方法とかいろいろあるかと思います。
(もともとバックグラウンドはtypeScriptと
Webpackを使っていたプロジェクトではありました。)
先にES6(ナウいスッキリしたJavaScriptの書き方だと思っています)を
ES5(割といろんなところで動きそうなやつ)にすることだけ解決して
フロントでもrequireしたくなって対応してなので安直な対応になりました。

### ES6 to ES5

```shell
yarn add babel-cli babel-preset-es2015 --dev
echo '{ "presets": ["es2015"] }' > .babelrc
babel dev.js -w -o app.js
```

```javascript
// dev.js
const print = value => console.log(value);
```

↓ 多分こんな感じに

```javascript
// app.js
function print(value){
  console.log(value);
}
```

`-w` ファイルの更新を監視するオプションです。
`--compact=true` 多分余計なスペースや改行を消したりするやつ
`--source-maps` ソースマップを出力するオプションでデバッグの際に便利です。

### require

```javascript
// print.js

module.exports = value => console.log(value); 
```

```javascript
// dev.js

const print = require('./print');
print('Hello!');
```

```shell
yarn add watchify --dev
watchify dev.js -o app.js
```

ここまでしたらあとは

```html
<script src="./app.js"></script>
```

読み込ませるだけ。
複数のファイルにコードを分割しても
ブラウザからのリクエスト回数を減らせたりといい感じです。

_reveal.js – The HTML Presentation Framework_ [https://revealjs.com/#/](https://revealjs.com/#/)
にてscssやejsを使ったり
requireを使えるようにしようとしたときのものを流用できました。

とりあえずこれらは　
`package.json` の `scripts` に登録しておくと便利だと思います。

# [https://ace.c9.io](https://ace.c9.io) 
ブラウザ上で動く非常に高機能なエディタです。
豊富な言語対応、コードのハイライトや補完、インデントの補助、undo・redo…etc
[https://github.com/ajaxorg/ace/blob/master/LICENSE](https://github.com/ajaxorg/ace/blob/master/LICENSE)

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ext-language_tools.js"></script>

<div id="editor" style="height: 100vh;"></div>

<script>
const editor = ace.edit('editor');
editor.setTheme('ace/theme/monokai');
editor.setFontSize(14);

editor.getSession().setMode('ace/mode/javascript');
// ace/mode/html or ace/mode/css

editor.getSession().setUseWrapMode(true);
editor.getSession().setTabSize(2);
editor.$blockScrolling = Infinity;
editor.setOptions({
  enableBasicAutocompletion: true,
  enableSnippets: true,
  enableLiveAutocompletion: true
});
</script>
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/133081/02ea0016-cd72-658b-3ed3-7af2727b939f.png)

### 内容更新イベント・内容取得・内容更新

```javascript
editor.getSession().on('change', () => {
  if (editor.getValue() === 'ねこ') editor.getValue('にゃーん');
});
```
`ねこ` と書いたら多分 `にゃーん` となります。 😺

### カーソル(セレクタ)変更イベント・カーソル位置取得

```javascript
editor.selection.on('changeSelection', () => {
  console.log(editor.selection.getCursor());
  // {row: 0, column: 0}
});
```

カーソルの情報は例えば文章中に特定の文字を挿入する機能を実装したい場合に有効です。

```javascript
const editorVal = editor.getValue();
let editorValLines = /\n/.test(editorVal) ? editorVal.split('\n') : [editorVal];
const targetLine = editorValLines[editor.selection.getCursor().row];
const beforeVal = targetLine.substr(0, editor.selection.getCursor().column);
const afterVal = targetLine.substr(editor.selection.getCursor().column, targetLine.length);
editorValLines[cursorInf.pos.row] = beforeVal + '挿入したい文字' + afterVal;
editor.setValue(editorValLines.join('\n'));
```

### undo・redo

```javascript
editor.undo();
editor.redo();
```

😊

# jquery-linedtextarea
[https://github.com/cotenoni/jquery-linedtextarea](https://github.com/cotenoni/jquery-linedtextarea)

指定したtextarea要素に行数を添えてくれるJQueryプラグインです。

[https://github.com/cotenoni/jquery-linedtextarea/blob/master/jquery-linedtextarea-license.txt](https://github.com/cotenoni/jquery-linedtextarea/blob/master/jquery-linedtextarea-license.txt)

暇つぶしにスマホで[https://atcoder.jp](https://atcoder.jp)の過去問題や
[https://paiza.jp](https://paiza.jp)のスキルチェックの問題を提出する方々が
いらっしゃるかと思います。
![ios__________.jpg](https://qiita-image-store.s3.amazonaws.com/0/133081/310beae1-0422-e3b9-48ab-ecb1943a356e.jpeg)
_sample_

とくにPaizaのスキルチェックのエディタは
Ace editorを使っている印象を受ける程高機能です。
しかしこれらをスマホブラウザで使ってみたところコピペ、
セレクトができない場合が多かったです。

そこでtextareaとAce editorで行き来できるように実装しました。
textareaの方には行数の表示くらいはするようにしました。

```shell
wget https://raw.githubusercontent.com/cotenoni/jquery-linedtextarea/master/jquery-linedtextarea.css
wget https://raw.githubusercontent.com/cotenoni/jquery-linedtextarea/master/jquery-linedtextarea.js
```

```html
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<link rel="stylesheet" href="./jquery-linedtextarea.css">
<script src="./jquery-linedtextarea.js"></script>

<textarea style="height: 100vh;"></textarea>

<script>
$('textarea').linedtextarea({selectedLine: 1});
</script>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/133081/8cb0f7b3-9211-af57-3d1d-16e6aee5a008.png)

### textareaでの内容更新イベント

内容が更新されたときに発火してほしい。

```javascript
$('textarea').change(() => {
  console.log('textareaのフォーカスが外れたときとかにしか発火しない。');
});

$('textarea').keyup(() => { // or keydown
  console.log('十字キーとかでも発火してしまう。 *ここではスマホで使うのが大前提だが');
});

$('textarea').on('input propertychange', () => {
  console.log('上手くいったもの');
});
```

### textareaでのカーソル位置取得
```javascript
$('textarea').eq(0).on('keyup click focus', () => {
  console.log($('textarea').eq(0).prop('selectionStart')); // 0
});
```

Ace editorと違い、rowやcolumnでの情報ではなく
`$('textarea').eq(0).val()` での文字列的に何文字目あたりに
カーソル(セレクタ)があるかというような数値の情報な印象を感じました。

# スマホでのJQuery-UI
マウスでグリグリ動かせる `draggable` な要素を
作れたりする有名なJQueryプラグインです。
スマホではそのままでは使えないので以下を導入する必要があります。

```html
<script src='https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js'></script>
```

### スマホでも動くようになったけど `draggable` な要素上のボタンとかが押せない
脳筋的解決になりますが `draggable` な要素のスペースやポインタを作って
ボタンとかをのせた要素を `position: absolute;` な要素にさせて
先述の `draggable` な要素のスペースやポインタと
JavaScriptで重ねさせたり追尾させたりしてみました。

# Auto Indent

```html
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.10-beta1/beautify.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.10-beta1/beautify-css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.10-beta1/beautify-html.min.js"></script>

<textarea id="html"></textarea>
<textarea id="css"></textarea>
<textarea id="js"></textarea>

<span id="auto">AUTO</span>

<script>
const beautifyOp = { indent_size: 2, space_in_empty_paren: true };

$('#auto').click(() => {
  $('#html').val(html_beautify($('#html').val(), beautifyOp));
  $('#css').val(css_beautify($('#css').val(), beautifyOp));
  $('#js').val(js_beautify($('#js').val(), beautifyOp));
});
</script>
```

思ったよりあっさり実装できてしまって感動もの。
[https://github.com/beautify-web/js-beautify](https://github.com/beautify-web/js-beautify) MIT😊

こんな左寄せコードも…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/133081/ae4e57a0-3809-5a82-2f09-5631ca691b45.png)

美しく✨
![image.png](https://qiita-image-store.s3.amazonaws.com/0/133081/42f8adf6-ef14-a023-e600-9be383af2eff.png)

#成果物
![image.png](https://qiita-image-store.s3.amazonaws.com/0/133081/58f9301e-0aa5-bacb-a845-87af60d8fe12.png)

***実装済***

+ 通常のtextareaで記述するモード ⬜
+ 行数表示つきのtextareaで記述するモード 🔢
+ AceEditorモード 🎨
+ 上記3つ全て表示 🚀
+ 上記3つの内容の連携
+ 上記3つの切り替え(表示・非表示)
+ 編集(表示)するファイルの切り替え
    + `HTML` `CSS` `JavaScript` から何れか1つ或いは全部 
+ AutoIndent
+ undo
+ redo
+ よく使う記号などの挿入機能
    + _※スマホにてダブルクォーテーションなどが全角になったりする対策_
+ ボタン一覧を好きな場所に設置可能

***これから***

+ コードのsave機能
+ アプリのプレビュー機能
+ アプリの公開ボタン

※バックグラウンドが絡むものたち

# 経緯

### N高 🏫
私が在学中の学校法人角川ドワンゴ学園N高等学校は
通信制の高等学校ではあるものの
通学コースというものがあり、キャンパスもあり、オープンキャンパスもしています。
[https://nnn.ed.jp/](https://nnn.ed.jp/)

### オープンキャンパス 🌸
オープンキャンパスは月1度以上の頻度で行われ
たくさんの中学生と保護者の方々がお越し下さいます。(中には常連な方も)
プログラミングやプロジェクト学習の体験授業を行っています。

### プログラミング体験授業 💻
プログラミングの体験授業ではN高生が作ったブラウザアプリを改造して
いわゆる自分色に変えていくという
40分前後しか時間が設けられてない割には濃い内容でした。
[https://nnn.ed.jp/news/blog/archives/5283.html](https://nnn.ed.jp/news/blog/archives/5283.html)

### 新しい教材 📕
しかし最近は良くも悪くもScratchを採用したので
また別に新しい教材を作ろうと思いました。
自分自身のPCを持ってない方でもオープンキャンパス後でも利用できると
良いと思い…

+ 環境構築不要
+ ブラウザアプリを作れる(&作ったものを保護者や友人に触って貰える)
+ **スマホのブラウザで** 📱

上記3つのルール的なものの下いろいろ考えていたら
スマホのブラウザ上で動く使いやすいエディタが欲しいなと思いました。

(私自身の習得の機会も兼ねてネイティブアプリも考えたものの場合によっては
ペアレンタルコントロール等の制限があり、
保護者とコミュニケーションをするという
案外面倒な環境構築が必要になったりするかも😅)

# 最後に

プログラミングは楽しい上に美味しいので
いろんな方々に是非習得していってほしいなと思っています。
※とくにものづくりが好きな私みたいな方とかには🔧

既にプログラミング以外の得意なことを持っている方は尚更プログラミングと
合わせて使うことでより良いものになるかもしれません。(メディアアートとか)
あとコンテストや登壇会などのイベント、コミュニティも活発です。

とくにN高等学校での学校生活では、プログラミングをしている生徒や
現役のエンジニアの講師の方々が多くいて、彼らとプログラミングを教え会ったり
大会やイベントに参加したりできました。本当に良い思い出となりました。
私の留学先のキリロム工科大学(カンボジア🇰🇭 [https://kit.edu.kh](https://kit.edu.kh))でも
N高等学校で得たプログラミングなどのノウハウを活かせると嬉しく思います。