reflex近況報告。2016とのクロスポストです。Editorという簡単なツールを紹介します。X3の環境では良い方法がなさげです。自分は絵文字はパレットから選択したい派、というか顔文字に対応する読みをいちいち覚えてられない派なので、やるなら一覧の中からぽちぽちクリックして選びたいです。ATOKに付属の文字パレットというユーティリティの分類には「顔」みたいなグループ分けが無いため、Unicode絵文字を使おうと思うとUnicodeの表のあっちこっちを行き来しながら探さないといけません。(最新のATOK2017ではこの辺どうなんでしょう?)また、これはカラー絵文字のフォントが無いという古い環境だからのようですが、文字パレット上だけでなくテキストエディタ上でも絵文字は白黒表示です。自分が絵文字を使いたいのは主にTwitterでの投稿なので、見るならTwitter上でどう見えるかが分からないと安心して使えません。絵文字を使う習慣が無かった自分が絵文字に触れる機会が増えたのは、「シス管系女子」の広報用Twitterアカウント(みんとちゃんbot)がきっかけです。いつもの自分のノリでやると堅すぎると思ったので、みんとちゃんbotの発言についてはあえて絵文字を入れて柔らかい印象を持ってもらえるようにしたい、という下心ドリブンです。当初はAndroidのGoogle日本語入力から絵文字を入れていましたが、運用のためのbotスクリプトを作成して、発言データにするためのテキストを大量に用意する段階になってPC上で作業に入ろうとしたときに、前述のような状況に気が付きました。Ver2というサービスで絵文字の入力自体はできる事が分かりました。このページは既に作成済みのデータの編集には使えません。ここは、Twitter絵文字を含んだプレーンテキストをWYSIWYGで編集できるツールが欲しくなるところです。探し方が悪かったのかもしれませんが、自分はその時「まさにこれだ!」と思える物を見つけられなかったため、無いなら作るか......という事で作りました。Editor(名前が安直すぎる)。HTMLファイル1つだけで完結する、フレームワークも何も使ってないSPAとも呼べないような代物です。このエントリの公開を機に、GitHubにリポジトリを作りましたので、forkしたりプルリクしたりして頂ければ幸いです。説明の必要も無いと思いますが一応説明しておくと、上半分が入力エリア(右下の所をドラッグしてサイズを変えられます)で、下半分が絵文字のパレットになっています。入力エリアに普通にテキストを入力して、「ここに絵文字を入れたい!」と思ったらおもむろにパレットから好きな絵文字をクリックすると、カーソルの位置にその絵文字が挿入されます。真ん中の所には最近使った絵文字が25個まで保持されるようになっています。絵文字を1秒以上長押しすると、その絵文字単体をクリップボードにコピーします。テキストの保存機能はありません。できたテキストはUTF-8等でのファイル編集に対応したテキストエディタにコピー&ペーストして自分で保存して下さい。テキストのロード機能もありません。ある絵文字を含んだテキストを編集したいときは、テキストファイルをエディタで開いて編集したい部分(あるいはファイル全体)を入力エリアにコピー&ペーストして下さい。Ver2やAndroidのGoogle日本語入力での並び順を参考にしつつ、「これはこっちの仲間じゃね?」と筆者が思った物を適当に並べ替えたりグループ化したりしています。パレットの実体は、以下のような単純なリストになっています。...h3は切り替え式のタブになります。絵文字の並び順が気に入らない場合や収録絵文字が足りないという場合は、HTMLファイルを保存してソース上の絵文字リストを適当に編集して下さい。絵文字を普通に使える最近の環境や、最近のFirefoxのようにカラー絵文字に対応したブラウザであれば、ローカルに置いたHTMLファイルでもそこそこ使えます。OSやブラウザの絵文字じゃアテにならないのでやっぱりTwitterの絵文字で見たいという場合には、Gistにindex.htmlと名前を付けて保存してbl.ocks.orgあたりで表示させれば、twemojiが読み込まれて絵文字が画像に変換されるようになります。Editorの入力欄にペーストすれば、絵文字がいい感じに表示された状態で編集できます。ルート要素の属性値を編集すると、最近使った項目の保持数や長押しの判定の秒数も変更できます。注意点⚠Unicode絵文字を日本語入力ソフトから直接入力した場合、twiemojiで画像に置き換える操作が入る関係で、絵文字の入力や絵文字を含んだ文字列をペーストした直後のアンドゥができなくなります。Firefoxでは問題ありませんが、Chromeだとカーソル位置の取得や設定がうまくいかなくて、Unicode絵文字の日本語入力ソフトからの挿入時にカーソル位置が吹っ飛ぶ事があります。仕様の範囲外の実装依存のChromeの挙動(contenteditable="true"の要素の中での改行操作をどう処理するかの違い)に起因する物です。誰か直してくれると嬉しいな......技術的な解説⌨contenteditable="true"にしたdivにtwemojiを適用すればええんやろ、と思ってたんですが意外と細かい所でハマったのでちょっとだけ実装のポイントを解説しておきます。ほとんどはcontenteditable="true"を生で触る時の注意点集です。パレットから絵文字を挿入する🎨パレットをクリックした時の絵文字の挿入はdocument.execCommand()で行っています。).singleNodeValue;}twemojiを使えるときはUnicode絵文字をHTMLの<img>タグに変換してからinsertHTMLコマンドでHTMLのソースとして挿入し、そうでない時はUnicode絵文字のままinsertTextで挿入しています。これは操作をアンドゥできるようにするためで、これに限らず編集エリア内のDOMツリーを直接操作するとアンドゥできなくなるので、編集操作は基本的にdocument.execCommand()でやるようにしないといけません。XPathでは属性値の文字列も一発で取れるのですが、<li>要素の方を操作したい場面があるので、ここでは要素ノードを取得しています)。パレットの長押しで絵文字を1文字だけコピーする☝この記事を書くにあたってパレットから1文字だけ絵文字をコピーしたいという場面がありました。「パレットをクリックすると編集領域に挿入する」という通常の動作を阻害したくなかったので、「長押しでコピー」という風に実装してしてみました。1000);してクリップボードにコピーすれば良いのでは?」という事になって、実際Firefoxの(従来の)アドオン開発ではそういう書き方で良かったのですが、WebのJSではそうはいきません。いうのも、安全のためにdocument.execCommapd('copy')は何かしらのイベントが発生したときのイベントループ中以外では呼べないことになっている(呼ぶとエラーになる)のです。mousedownとclickを連携して実装しないといけません。要点だけ示すと以下のようになります。長押しが成立したかどうかのフラグをリセット。1秒後にフラグを立てる。マウスから手を放したときの事もここでまとめて行う。長押し成立前にmouseupされた場合はタイマーをキャンセル。長押しが成立していたらクリップボードにコピー。なければ普通に入力欄に挿入。コピーするための定番の方法。普通Webブラウザのウィンドウ内でTabキーを押すとリンク間のフォーカス移動になりますが、作りたいデータの形式がタブ区切りだったので、Tabでタブ文字を入れられるようにする必要がありました。やり方は簡単で、keypressイベントが発生したときにモディファイアキー無しのTabキーの入力だったら\tを挿入してイベントをキャンセルするだけです。aEvent.preventDefault();});これも、アンドゥできるようにするにはdocument.execCommand()でinsertTextコマンドで挿入しないといけません。これだけだとタブ文字\u0009を入れたはずが何故か半角スペース1個だけ\u0020になってしまいます。これはcontenteditable="true"にしたHTML要素のレンダリングのされ方の影響で、white-space:normalな要素の中に上記の方法でタブ文字を入れても、通常のHTMLのソースに書かれたタブ文字と同様に、最終的に半角スペース1つに正規化されてしまうからです。それを防ぐために、編集エリアとして使うHTML要素にはwhite-space:preまたはwhite-space:pre-wrapを指定しておく必要があります。編集した内容を外部のテキストエディタにコピペして保存するときはいいのですが、エディタを経由せずそのままTwitterの入力欄などにコピペしようとすると問題が起こります。どっちの入力欄もcontenteditable="true"のリッチテキストエディタ扱いなので、貼り付け時には可能な限り多くの情報を引き継ごうとブラウザが気を利かせてtext/htmlのデータを貼り付けてくれるのですが、Twitterの入力欄では画像の直接の埋め込みは許可されていないため、twemojiが画像にした絵文字が消えてしまうのです。Eventのcopyとcutをフックして、text/plain形式のデータだけをクリップボードに格納するようにしています。`cut`の場合は切り取った後の部分を消す必要がある。aEvent.preventDefault();});これにより、text/htmlのデータを伴わない、Unicode絵文字込みのtext/plainのデータだけを確実にコピーできます。同じ理由で、テキストの貼り付け時にも対策が必要です。Editorの入力欄に貼り付けようとすると、HTMLの要素がそのまま貼り付けられてしまって編集に難儀します。Editorにとって都合の良い形式にしてから取り扱うようにしています。'&lt;');}テキストの挿入時にはパレットからの絵文字入力の時と同じようにinsertTextかinsertHTMLを使うのですが、insertHTMLを使う時は文字列の中にある<や>がそのままタグとして解釈されてしまうと困るので、sanitizeForHTML()という関数を用意してHTMLのソースとして安全な形に変換してから挿入します。タブ文字を残してコピー&ペーストする✂ここから話がややこしくなってきます。先程のコード片でcopyイベントをフックしたとき、text/plainのデータとしてwindow.getSelection().toString()をそのまま設定しないでrangeToPlainText(window.getSelection().getRangeAt(0))としていたことに気付いたでしょうか?Twitterのツイートあたりをそのままコピーしてテキストエディタにペーストすると分かるのですが、window.getSelection().toString()とすると、画像がalt属性の値で置き換えられたり改行がプラットフォームごとの一般的な改行コードに合わせてLFまたはCRLFになったりという具合に、通常はブラウザが良い感じに文字列を組み立ててくれます。それをそのまま使わないかというと、少なくともFirefoxでは、この方法を使ったときに選択範囲の中に画像が1個でもあるとタブ文字が半角スペース1個に変換されてしまうのです。実際に、テキストノードの部分だけを選択した場合と画像を含めて選択した場合でwindow.getSelection().toString()の結果を確認したら、テキストノードだけの時は確かに\u0009として取り出せていた部分が、画像も含めての選択時には\u0020になってしまっていました。Rangeを走査して自分で必要なテキストを組み立てる処理を書きました。改行として使う文字はプラットフォーム標準の物を使う。コピーしたときに内容を取り出す対象になり得るノードを収集する(後述)。Rangeの最初のノードまでスキップする。テキストノードの場合、(部分)文字列を取り出す。改行のタグは改行文字に変換。twemojiの画像は代替テキストに変換。Rangeの終端に辿り着いたらループを打ち切る。編集欄の中のテキストノード、画像、改行のタグだけを収集する。XPathで一気に取ってくる。これはC++の実装が使われるので高速。イテレータにして返す。})();}ペーストするときは前述の通りwhite-space:pre-wrapを指定しておけば大丈夫でした。Editorのパレットとクリップボードからのペーストで入力される絵文字についてはtwemojiで画像のタグにしたものをinsertHTMLで挿入するようにしていますが、それ以外の方法、例えば日本語入力ソフトからの入力でUnicode絵文字が直接挿入された場合の対応も必要です。入力欄に絵文字が入力されたこと自体は、MutationObserverで検知できます。});}この時、twemoji.parse()で編集エリア内のUnicode絵文字を画像に置き換えるとカーソルの位置がずれてしまうという問題が起こります。カーソル位置に新しくUnicode絵文字を挿入した場合はその文字の次の位置にカーソルが移動しているはずなのに、絵文字を入力する前の位置や、あるいはとんでもない明後日の位置にカーソルが飛んでしまったりします。この問題を解消するためには、頑張ってカーソル位置を調整してやる必要があります。twemoji.parse()の実行直前に元のカーソル位置(この時点ではきちんと絵文字の後に移動している)を取得します。その中に含まれる論理的な文字の数を数える。前述の方法で一回テキストに変換し、その文字数を数えている。サロゲートペアが使われた絵文字を「1文字」として文字列を文字ごとに分割する。[];}で、絵文字が画像になった後で改めてカーソル位置を再設定します。さっき使った編集対象のノードを収集する処理をここでも使う。あと何文字分カーソルを移動すれば良いか、のカウンタ。そこで走査を打ち切る。ノードの文字数分だけカウンタを減らす。その位置をカーソルとして確定する。Chromeでは入力欄でEnterすると改行要素ではなくdivが追加される場合があるみたいで、どうもこの処理が期待通りに動いてくれませんでした。誰か直せる人は直してもらえるとありがたいです。いうことで、自分でcontenteditable="true"の要素をコントロールしようと思うと結構色々大変なのでした。妙な事は考えずに、素直にどっかのフレームワークとかFacebookの投稿欄とかを使った方がよかったですかね......?絵文字を含むツイートを簡単にできる幸せ💃みんとちゃんbotの運用に使っているbotやそのベースになっているTwitterクライアントはどちらもシェルスクリプト製で、データの取り扱いは一事が万事プレーンテキストなのですが、Twitterが「単にUnicode絵文字を含んだデータを投稿すればOK」という仕様なおかげで、botのデータファイルは以下のように容易にプレビュー可能な形で作成できています。Editorを作ってみようなんて思わなかったと思いますし、みんとちゃんbotはかわいげの無い発言をするbotになっていたことでしょう。電子テキストの世界を彩り、楽しくかわいくしてくれるUnicode絵文字。賛否はあるようですが、筆者は素晴らしいものだと思っております。いうわけで、みんとちゃんbotは今日も元気に絵文字を織り交ぜつつLinuxのコマンド操作やシェルスクリプトの豆知識を披露したり本や連載の宣伝をしたりしています。イラストもたまに流していますので、もし良かったらフォローしてあげて下さい。Calendarなんてのもありますので、そっちも見て頂けると嬉しいです。Editエントリを編集します。2016](http://qiita.com/advent-calendar/2016/emoji)とのクロスポストです。Editor][]という簡単なツールを紹介します。X3の環境では良い方法がなさげです。自分は絵文字はパレットから選択したい派、というか顔文字に対応する読みをいちいち覚えてられない派なので、やるなら一覧の中からぽちぽちクリックして選びたいです。ATOKに付属の文字パレットというユーティリティの分類には「顔」みたいなグループ分けが無いため、Unicode絵文字を使おうと思うとUnicodeの表のあっちこっちを行き来しながら探さないといけません。これはカラー絵文字のフォントが無いという古い環境だからのようですが、文字パレット上だけでなくテキストエディタ上でも絵文字は白黒表示です。自分が絵文字を使いたいのは主にTwitterでの投稿なので、見るならTwitter上でどう見えるかが分からないと安心して使えません。絵文字を使う習慣が無かった自分が絵文字に触れる機会が増えたのは、[「シス管系女子」の広報用Twitterアカウント(みんとちゃんbot)][みんとちゃんbot]がきっかけです。いつもの自分のノリでやると堅すぎると思ったので、みんとちゃんbotの発言についてはあえて絵文字を入れて柔らかい印象を持ってもらえるようにしたい、という下心ドリブンです。当初はAndroidのGoogle日本語入力から絵文字を入れていましたが、[運用のためのbotスクリプトを作成][tweetbot.sh-解説]して、発言データにするためのテキストを大量に用意する段階になってPC上で作業に入ろうとしたときに、前述のような状況に気が付きました。Ver2")というサービスで絵文字の入力自体はできる事が分かりました。このページは既に作成済みのデータの編集には使えません。ここは、*Twitter絵文字を含んだプレーンテキストをWYSIWYGで編集できるツール*が欲しくなるところです。探し方が悪かったのかもしれませんが、自分はその時「まさにこれだ!」と思える物を見つけられなかったため、無いなら作るか......という事で作りました。Editor][](名前が安直すぎる)。HTMLファイル1つだけで完結する、フレームワークも何も使ってないSPAとも呼べないような代物です。Editor")ので、forkしたりプルリクしたりして頂ければ幸いです。説明の必要も無いと思いますが一応説明しておくと、上半分が入力エリア(右下の所をドラッグしてサイズを変えられます)で、下半分が絵文字のパレットになっています。入力エリアに普通にテキストを入力して、「ここに絵文字を入れたい!」と思ったらおもむろにパレットから好きな絵文字をクリックすると、カーソルの位置にその絵文字が挿入されます。真ん中の所には最近使った絵文字が25個まで保持されるようになっています。絵文字を1秒以上長押しすると、その絵文字単体をクリップボードにコピーします。*テキストの保存機能はありません*。できたテキストはUTF-8等でのファイル編集に対応したテキストエディタにコピー&ペーストして自分で保存して下さい。*テキストのロード機能もありません*。ある絵文字を含んだテキストを編集したいときは、テキストファイルをエディタで開いて編集したい部分(あるいはファイル全体)を入力エリアにコピー&ペーストして下さい。Ver2")やAndroidのGoogle日本語入力での並び順を参考にしつつ、「これはこっちの仲間じゃね?」と筆者が思った物を適当に並べ替えたりグループ化したりしています。パレットの実体は、以下のような単純なリストになっています。`h3`は切り替え式のタブになります。絵文字の並び順が気に入らない場合や収録絵文字が足りないという場合は、HTMLファイルを保存してソース上の絵文字リストを適当に編集して下さい。Calendar...")であれば、ローカルに置いたHTMLファイルでもそこそこ使えます。Qiita")させれば、twemojiが読み込まれて絵文字が画像に変換されるようになります。Editorの入力欄にペーストすれば、絵文字がいい感じに表示された状態で編集できます。ルート要素の属性値を編集すると、最近使った項目の保持数や長押しの判定の秒数も変更できます。Unicode絵文字を日本語入力ソフトから直接入力した場合、twiemojiで画像に置き換える操作が入る関係で、絵文字の入力や絵文字を含んだ文字列をペーストした直後のアンドゥができなくなります。Firefoxでは問題ありませんが、Chromeだとカーソル位置の取得や設定がうまくいかなくて、Unicode絵文字の日本語入力ソフトからの挿入時にカーソル位置が吹っ飛ぶ事があります。仕様の範囲外の実装依存のChromeの挙動(`contenteditable="true"`の要素の中での改行操作をどう処理するかの違い)に起因する物です。`contenteditable="true"`にした`div`にtwemojiを適用すればええんやろ、と思ってたんですが意外と細かい所でハマったのでちょっとだけ実装のポイントを解説しておきます。ほとんどは`contenteditable="true"`を生で触る時の注意点集です。パレットをクリックした時の絵文字の挿入は`document.execCommand()`で行っています。`twemoji`を使えるときはUnicode絵文字をHTMLの`<img>`タグに変換してから`insertHTML`コマンドでHTMLのソースとして挿入し、そうでない時はUnicode絵文字のまま`insertText`で挿入しています。これは操作をアンドゥできるようにするためで、これに限らず*編集エリア内のDOMツリーを直接操作するとアンドゥできなくなる*ので、編集操作は基本的に`document.execCommand()`でやるようにしないといけません。XPathでは属性値の文字列も一発で取れるのですが、`<li>`要素の方を操作したい場面があるので、ここでは要素ノードを取得しています)。この記事を書くにあたってパレットから1文字だけ絵文字をコピーしたいという場面がありました。「パレットをクリックすると編集領域に挿入する」という通常の動作を阻害したくなかったので、「長押しでコピー」という風に実装してしてみました。1000);`してクリップボードにコピーすれば良いのでは?」という事になって、実際Firefoxの(従来の)アドオン開発ではそういう書き方で良かったのですが、WebのJSではそうはいきません。いうのも、安全のために`document.execCommapd('copy')`は何かしらのイベントが発生したときのイベントループ中以外では呼べないことになっている(呼ぶとエラーになる)のです。`mousedown`と`click`を連携して実装しないといけません。要点だけ示すと以下のようになります。長押しが成立したかどうかのフラグをリセット。1秒後にフラグを立てる。マウスから手を放したときの事もここでまとめて行う。長押し成立前にmouseupされた場合はタイマーをキャンセル。長押しが成立していたらクリップボードにコピー。なければ普通に入力欄に挿入。コピーするための定番の方法。普通Webブラウザのウィンドウ内でTabキーを押すとリンク間のフォーカス移動になりますが、[作りたいデータの形式がタブ区切り][tweetbot.sh-解説]だったので、Tabでタブ文字を入れられるようにする必要がありました。やり方は簡単で、`keypress`イベントが発生したときにモディファイアキー無しのTabキーの入力だったら`\t`を挿入してイベントをキャンセルするだけです。これも、アンドゥできるようにするには`document.execCommand()`で`insertText`コマンドで挿入しないといけません。これだけだとタブ文字`\u0009`を入れたはずが何故か半角スペース1個だけ`\u0020`になってしまいます。これは`contenteditable="true"`にしたHTML要素のレンダリングのされ方の影響で、`white-space:normal`な要素の中に上記の方法でタブ文字を入れても、通常のHTMLのソースに書かれたタブ文字と同様に、最終的に半角スペース1つに正規化されてしまうからです。それを防ぐために、*編集エリアとして使うHTML要素には`white-space:pre`または`white-space:pre-wrap`を指定しておく必要があります*。編集した内容を外部のテキストエディタにコピペして保存するときはいいのですが、エディタを経由せずそのままTwitterの入力欄などにコピペしようとすると問題が起こります。どっちの入力欄も`contenteditable="true"`のリッチテキストエディタ扱いなので、貼り付け時には可能な限り多くの情報を引き継ごうとブラウザが気を利かせて`text/html`のデータを貼り付けてくれるのですが、*Twitterの入力欄では画像の直接の埋め込みは許可されていないため、twemojiが画像にした絵文字が消えてしまう*のです。Eventの`copy`と`cut`をフックして、`text/plain`形式のデータだけをクリップボードに格納するようにしています。`cut`の場合は切り取った後の部分を消す必要がある。これにより、`text/html`のデータを伴わない、Unicode絵文字込みの`text/plain`のデータだけを確実にコピーできます。同じ理由で、テキストの貼り付け時にも対策が必要です。Editorの入力欄に貼り付けようとすると、HTMLの要素がそのまま貼り付けられてしまって編集に難儀します。Editorにとって都合の良い形式にしてから取り扱うようにしています。テキストの挿入時にはパレットからの絵文字入力の時と同じように`insertText`か`insertHTML`を使うのですが、`insertHTML`を使う時は文字列の中にある`<`や`>`がそのままタグとして解釈されてしまうと困るので、`sanitizeForHTML()`という関数を用意してHTMLのソースとして安全な形に変換してから挿入します。ここから話がややこしくなってきます。Twitterのツイートあたりをそのままコピーしてテキストエディタにペーストすると分かるのですが、`window.getSelection().toString()`とすると、画像が`alt`属性の値で置き換えられたり改行がプラットフォームごとの一般的な改行コードに合わせて`LF`または`CRLF`になったりという具合に、通常はブラウザが良い感じに文字列を組み立ててくれます。それをそのまま使わないかというと、少なくともFirefoxでは、この方法を使ったときに選択範囲の中に画像が1個でもあると*タブ文字が半角スペース1個に変換されてしまう*のです。実際に、テキストノードの部分だけを選択した場合と画像を含めて選択した場合で`window.getSelection().toString()`の結果を確認したら、テキストノードだけの時は確かに`\u0009`として取り出せていた部分が、画像も含めての選択時には`\u0020`になってしまっていました。Rangeを走査して自分で必要なテキストを組み立てる処理を書きました。改行として使う文字はプラットフォーム標準の物を使う。コピーしたときに内容を取り出す対象になり得るノードを収集する(後述)。Rangeの最初のノードまでスキップする。テキストノードの場合、(部分)文字列を取り出す。改行のタグは改行文字に変換。twemojiの画像は代替テキストに変換。Rangeの終端に辿り着いたらループを打ち切る。編集欄の中のテキストノード、画像、改行のタグだけを収集する。XPathで一気に取ってくる。これはC++の実装が使われるので高速。イテレータにして返す。ペーストするときは前述の通り`white-space:pre-wrap`を指定しておけば大丈夫でした。Editorのパレットとクリップボードからのペーストで入力される絵文字についてはtwemojiで画像のタグにしたものを`insertHTML`で挿入するようにしていますが、それ以外の方法、例えば日本語入力ソフトからの入力でUnicode絵文字が直接挿入された場合の対応も必要です。入力欄に絵文字が入力されたこと自体は、MutationObserverで検知できます。この時、`twemoji.parse()`で編集エリア内のUnicode絵文字を画像に置き換えるとカーソルの位置がずれてしまうという問題が起こります。カーソル位置に新しくUnicode絵文字を挿入した場合はその文字の次の位置にカーソルが移動しているはずなのに、絵文字を入力する前の位置や、あるいはとんでもない明後日の位置にカーソルが飛んでしまったりします。この問題を解消するためには、頑張ってカーソル位置を調整してやる必要があります。`twemoji.parse()`の実行直前に元のカーソル位置(この時点ではきちんと絵文字の後に移動している)を取得します。その中に含まれる論理的な文字の数を数える。前述の方法で一回テキストに変換し、その文字数を数えている。サロゲートペアが使われた絵文字を「1文字」として文字列を文字ごとに分割する。絵文字が画像になった後で改めてカーソル位置を再設定します。さっき使った編集対象のノードを収集する処理をここでも使う。あと何文字分カーソルを移動すれば良いか、のカウンタ。そこで走査を打ち切る。ノードの文字数分だけカウンタを減らす。その位置をカーソルとして確定する。Chromeでは入力欄でEnterすると改行要素ではなく`div`が追加される場合があるみたいで、どうもこの処理が期待通りに動いてくれませんでした。誰か直せる人は直してもらえるとありがたいです。いうことで、自分で`contenteditable="true"`の要素をコントロールしようと思うと結構色々大変なのでした。みんとちゃんbotの運用に使っている[bot][tweetbot.sh-解説]やそのベースになっている[Twitterクライアント][tweet.sh-解説]はどちらもシェルスクリプト製で、データの取り扱いは一事が万事プレーンテキストなのですが、Twitterが「単にUnicode絵文字を含んだデータを投稿すればOK」という仕様なおかげで、botのデータファイルは以下のように容易にプレビュー可能な形で作成できています。Editorを作ってみようなんて思わなかったと思いますし、みんとちゃんbotはかわいげの無い発言をするbotになっていたことでしょう。電子テキストの世界を彩り、楽しくかわいくしてくれるUnicode絵文字。賛否はあるようですが、筆者は素晴らしいものだと思っております。いうわけで、[みんとちゃんbot][]は今日も元気に絵文字を織り交ぜつつLinuxのコマンド操作やシェルスクリプトの豆知識を披露したり本や連載の宣伝をしたりしています。[イラスト](http://system-admin-girl.com/comic/#illust)もたまに流していますので、もし良かったらフォローしてあげて下さい。Calendar](http://www.adventar.org/calendars/1692)なんてのもありますので、そっちも見て頂けると嬉しいです。