Tegaki #2

akahukuplus-tegaki-in-summary2

ふたばのオリジナルの手描き機能では、手描き画像でスレを立てることはできない設定になっている。少なくとも虹裏 may ではできない。これはきっと理由があるのだと思うけど、まあブラウザのエクステンションでは特にそういう制限をかける必要はあるまいということで、立てられるようにした。

このとき、手描き画像のキャンバスサイズは 640×480 に拡大されるようになっている。これは Tegaki Draw and Tweet の画像サイズに準じた。

ちなみにオリジナルの手描き機能を送信する際の内部的なフォームデータは、baseform という hidden input 要素である。手描きの flash が逐一この要素に画像を base64 でエンコードした文字列を設定する。これとは別に、従来通りの普通にファイルを送信する要素は upfile である。すなわち可能性としてはファイルと手描き画像を両方同時に送信することが可能なのだが、試していないがたぶん upfile のほうが優先される。

赤福プラスでは baseform 要素を特に積極的に使う必要はない。というのは手描き画像を保持する canvas 要素から blob データを得て、送信フォームの構築時に upfile に割り当てればいいだけの話だからだ。そんな細かいことをブラウザだけでできるようになったんだねぇとしみじみしちゃうが、とりあえずレス画像としての手描きは baseform、スレ画像としては upfile を使うようにしてある。

ついでに 1 回限りの undo やペンサイズを変更するためのショートカットなどを追加。

Tegaki

虹裏の中には手書き機能が付いている板もあるのだが、赤福プラスで閲覧している状態ではその機能を利用できなかった。そうこうしているうちにはよ実装しろやバーカバーカという声まで来てしまった。

なぜ延び延びになっているかといえば、ぶっちゃけて言えば赤福プラスをいじっても 1 円も儲からないからだ。

wasavi の場合は、Pledgie へのリンクをつけてあり、まあ元をとっているのかといえば全然ではあるのだけど、一応開発に対する対価は得ている。しかし赤福プラスの場合はそういうものはつけていない。じゃあつければいいじゃんということなのだが、果たして「」やとっしーが虹裏向けのブラウザなんかにお金を払うだろうか。いや払うわけがない。そして、仮に払ったとしても、そうすると調子に乗って文句たらたらになることは火を見るよりも明らかである。

実装の面から考えてみると、元の手書き機能は flash なのであまり扱いたくない。また、代替品を作るにしてもそれなりに手間がかかる。

そういうわけでなかなか腰が重い。殊勝なとっしーがポンと30万円くらい払ってくれてしかもおかしな注文もつけてこなければ一生懸命いじるのだが。

* * *

最後に 1 つ書いておくと、赤福プラス 3.1.207 からは手書き機能がついてある。

Pick it up

とある事情でいわゆるカラーピッカーが入り用になった。そこで、とりあえずググった所ものすごくたくさんある。なぜプログラマはカラーピッカーを書きたがるのか?

ちなみに、今回欲しいカラーピッカーの要件は:

  • シンプルでいい。HSV 方式だけでいい
  • 付加的な画像ファイルやCSSファイルを必要としないほうがいい。javascript ソースだけで動けばいい
  • jQuery 等々には依存しないほうがいい
  • 最後に選択した色を憶えててくれて、再選択できるといい
  • hex 表記との相互変換ができるといい
  • 表示開始のタイミングを呼び出し側で制御できるといい

最後の表示開始タイミング云々というのは、既存のライブラリの中には、ドキュメントの load イベント時に、カラーピッカーを起動させるべく特別なクラス名などが付加された要素に対してアタッチするようなものも少なくないのである。しかし静的なページならそれでもいいけど、動的なページだとかなり相性が悪い。そんなわけで表示開始のタイミングは呼び出し側で制御したい。こんな感じで:

targetElement.addEventListener('click', function (e) {
startColorPicker(e.target, {
onchange: function (color) {
},
ok: function (color) {
},
cancel: function () {
}
});
}, false);

ところが、この要件に合致する既存のライブラリがなかなか見つからないのである。そもそも、jQuery プラグインとして作ってあるものが大半だったりする。別に jQuery プラグインだからダメというわけではない。最初から jQuery ありの前提で書いてたアプリに組み込むのならまったく問題ない。しかしもともと jQuery なしで開発してたものにたかがカラーピッカー 1 つのために jQuery を読み込ませるのはかなりとっても相当嫌だ。jQuery プラグインと同時に、依存なし版も合わせて作って公開してくれれば更に多くの人に使われると思うのだけど。

そんなわけでググれどググれど見つからないので、しょうがないので自分で書く羽目になってしまったのである。なんでこんなものがないんだ。かなりプンプンだ。

color-picker

そんなこんなでドバババと書いたのであった。

Let’s talk about a News

ちょっと前に tsumami というアプリケーションを書いた。

これは要するに RSS リーダーの一種なのだけど、最大の特徴は取り込んだフィードを読み上げるというものだった。これに適当なニュースサイトのフィードを登録しておくと、自分の仕事をしながら世の中の動きにもついていけるという……非常に素晴らしいアプリケーション……のはずだったのだが、インストールが我ながら笑っちゃうほど死ぬほど面倒くさいわけで、もう使わなくなってしまった。

しかしフィードを読み上げるというのは面白い試みではあるので、リベンジとして作りなおしてみた。今回は Chrome のエクステンションなので、単にインストールするだけである。ただし任意のフィードは登録できなくて、とりあえず今の所 NHK News WEB のものだけ。

PhoneticNews
https://chrome.google.com/webstore/detail/phoneticnews/jdpmokplldjoalkopfkeedeehmfaejjh

vi flavored browser UX #3

実は今現在最新の Firefox Developer Edition 46.0a では Keysnail が動作しないので、とても不便である。

せっかく Chrome 上での vi flavored なエクステンション群の評価をしたので、cVim をベースに uBlock、ScriptBlock 等を入れて色々整えてみた所割合快適な感じになってしまって、あれ? これ Firefox もう窓から投げ捨ててしまってもいいんじゃないの? という気になりつつある。

従来、どういうわけか Linux 上で Chromium(Opera も)を動かすとオムニバー上のキー入力が耐えられないほど重かった。また Chrome ではオムニバー周辺をエクステンションからいじることはほとんどできない。アドレスを編集するときに [cci]^F[/cci] [cci]^B[/cci] [cci]^H[/cci] 位は使いたいのだ。そのあたりが Firefox を常用ブラウザに選んだ理由だったのだが、オムニバーの代わりに cVim のコマンドラインを代用すれば今まで感じていた不満が何とかなってしまうわけで、そんなわけで 3 日に 1 回くらい落ちる Firefox Developer Edition を常用する理由がなくなってしまった。

vi flavored browser UX #2

地道に試しているのだが、インストールしたらページが hjkl でスクロールできたよやったねたえちゃん! という観点で見ると違いはそれほどわからない。なんとか違いを探してみると:

開発の活発さ
Vichrome と Hometype は github 上のコードの最終更新が数年前と、すでに中の人がやる気をなくしている感がある。それ以外は活発なようだ。

vi/vim の機能の理解
ほぼすべてのエクステンションにおいて gt/gT で次のタブ・前のタブに切り替えることができるが、この時カウントを前置できる・できないエクステンションがある。Vichrome はできない(というよりカウントの前置という概念がないように思える)。Hometype はキーボードからのアクティブタブの移動という機能自体がない。見た目のセンスはいいと思うけど、全般的に機能が足りない感じがする。

一方で機能の豊富さで言うと vrome が優れているように思える。ただあんまり機能が多くても全部使うわけでもないので、個人的には vimium くらいの規模が妥当かなという感じ。

コンテントスクリプトのサイズ
フロントエンド側の機能を提供するコンテントスクリプトはすべてのタブのみならずすべてのサブフレームでも読み込まれるので、できるだけコンパクトな方が良く、jquery に代表される汎用的なライブラリ等には頼っていないほうが好ましい。そうじゃないとなんちゃらまとめサイトみたいな iframe 広告だらけのページを開いた時に悲惨なことになってしまう。

Vimium、Vrome、cVim はそのようなライブラリに頼っていない。特に cVim は機能の大多数をページに差し込む iframe 内に置いているようでコンテントスクリプトは非常にコンパクトであり、アーキテクチャは最も洗練されているように思える。

まとめ
後発なだけに cVim が優れている感じだが、Vimium や vrome も悪くはない。Vichrome と Hometype は今のところ一休み状態かなーという感じ。Vichrome は [cci]/[/cci] [cci]?[/cci] コマンドなどで日本語対応というのが売りらしいので、そういう方向ではいいのかも。といいつつ今 [cci]?[/cci] を押して何も入力しないまま enter 押したら Chrome ごと固まっちゃったが……。

vi flavored browser UX

テストのために VimFx を入れたり外してたりしたわけだが、普段はこの手の、ブラウザのインターフェースを vi 風味にする拡張というものを使っていない。正確には、Keysnail によって最低限の vi っぽいショートカット(hjlk とかその程度)を付け足してはいるが、その程度だ。hit-a-hint などのナウい機能は使わなくても何とかなっている。

これはなぜかと改めて振り返ってみると:

  • トラックポイント付きのキーボードを常用しているので、そもそもポインティングデバイスとキーボードの併用にストレスがあまりない
  • wasavi の動作テストをするにあたって、特定の拡張の影響を排除したい
  • この手の拡張を入れると、web ページが個別に定義するキーボードショートカットと拡張自身のショートカットのどちらを優先するかという問題が必ずつきまとう。この手の問題に煩わされたくない

ということだろうと思う。

そういうわけで個人的な要求としては、「ブラウザのナビゲーションにおいて vi っぽいショートカットは多少はあれば嬉しいけど、おおがかりに vi っぽくはしなくていいし、してほしくない」ということなのである。現在常用している Firefox においては、それは Keysnail で自分でちまちまとスクリプトを書けば対応できる。一方で Chrome はどうだろうか。Chrome も常用とはいかないが、それなりに使っている。

まず vi flavored なエクステンションはどうだろうか。Chrome におけるその手のエクステンションを列挙してみると:

…なんでこんなにあるんだ?

Compatibility to VimFx #3

色々やりとりしてみた所、何やら思いがけない方向に進んだ。

まず、wasavi 側で VimFx を意識した処理をする必要はなくなった。逆に、VimFx 側で wasavi の iframe を contenteditable な要素として扱ってもらえるようになった。のだが、途中から wasavi が起動中に blur させる方法がないのが問題、という話になり、正直なところへぁ? なんのこと? という気分に。

どうも VimFx の作法として、編集可能な要素がフォーカスを持っている場合は VimFx は自身のキーバインドを使用しないというものがあるようだ(逆に言うと、編集可能な要素の振る舞いを上書くことは VimFx ではできない)。ただし、編集可能な要素上で esc キーを押すとフォーカスを外す、つまり VimFx のキーバインドが再度有効になるようにはなっている。したがって、例えば通常の textarea で編集中に他のタブに切り替え、必要なものをコピー、戻って貼り付けなどという一連の動作をすべてキーボードで行うには、

  • textarea 上で esc
  • gt (次のタブへ)
  • yf 等々で必要なものをコピー
  • gT (前のタブへ)
  • gi (先頭、あるいは最後にフォーカスした編集可能要素に再度フォーカス)
  • wasavi 上で [cci]”*p[/cci]

というようなキーボード操作になる。で、これを可能とするために、wasavi も esc で blur して欲しいということのようだ。

というわけで、そういう風にした。ただ、この常にこの仕様で動作させて良いのか? という懸念はある。

  • vi 使いの中にはノーマルモードに戻るために esc を連打する人もいる
  • そうでなくても、うっかりノーマルモード上で esc を押してしまうことは有り得る
  • あくまで VimFx の作法である。VimFx がインストールされていれば、wasavi がフォーカスを失っても即 [cci]gi[/cci] で戻すことはできるが、インストールされていなければポインティングデバイスで wasavi をクリックし直すしかない

なので、新しいオプション [cci]esctoblur[/cci] を導入し、これがオンの場合のみに blur 処理を行うようにした。

Compatibility to VimFx #2

動作するようにはなったのだが、やはりイベントハンドラの実引数として渡された何かを取っておいてハンドラのスコープの外で使うというやり方はちょっと嫌な感じではある。

VimFx の issue に何か参考になるものがないのかなと見てみたら、丁度よく wasavi が動かない、正確には Pterosaur や CodeMirror や wasavi 等々、自前で色々キー入力を消費するタイプの拡張と競合する、というが上がっていたので乗っかってみよう。

Compatibility to VimFx

Firefox の拡張には、キーボード周りを含めたブラウザのインターフェースを「強力に」書き換える能力があるわけなのだが、それらと wasavi の相性は一般的によくない。wasavi もまたすべてのキーボード入力を自分で消費するからだ。すると、あるキー入力が他の拡張に横取りされてしまうとか、wasavi と同時に処理されてしまうと言った不具合が起きる。

それを避けるために、VimperatorKeysnail 用のプラグインスクリプトを用意してある。これらは主に 2 つの仕事を受け持つ:

  1. タブの切り替えを監視し、アクティブなタブのドキュメント上に実行中の wasavi が存在するかどうかで対象の拡張を一時的にサスペンドさせるかを制御する(ちなみにこの辺の処理は e10s が有効だと完璧に破綻する: プラグインは Chrome 権限上で動いている、そして content を直接触るためだ)
  2. ドキュメントのカスタムイベント [cci]WasaviStarted[/cci] [cci]WasaviTerminated[/cci] を監視し、各イベントに応じて適宜対象の拡張を一時的にサスペンドさせるかを制御する

ところで、こういったインターフェースを再定義する拡張はもちろんこれだけではない。issue では VimFx との相性がよくないというものが上がっているので、とりあえずそれに対応してみることにしよう。

* * *

VimFx というのはなんぞやというと、実はあまり知らないのだが、本質的には Vimperator と同様に Firefox のインターフェースを vim っぽくする系の拡張である。ただし、Vimperator がインターフェースを「ドラスティックに」変えるのに対して VimFx はもうちょっと大人しいようだ。

プラグインの機構はない。ただし、Chrome 権限のスクリプトから使用できる API が提供されている。

さて、対象の拡張が変わったとしても、やるべきことは上記の 2 点なのは変わらない。ただし 1 は上記のとおり、e10s を見越して content 内で処理する必要がある。普通の DOM のイベントでタブがアクティブ・非アクティブになったというのを判定するには Page Visibility という割と新し目の API で定義される visibilitychange イベントを使えば良いだろう。一方で、wasavi の状態によって他の拡張にアクセスするのは content ではなくバックエンドの chrome スクリプトでなければならないので、つまり visibilitychange イベントでやることはアクティブなタブだったらバックエンドにメッセージを投げる、ということになる。そんなわけで:


window.addEventListener('visibilitychange', function () {
if (document.hidden) return;
extension.postMessage({
type: 'visibility-change',
wasaviRunning: !!wasaviFrame
})
}, false);

というような感じ。

このメッセージをバックエンドで受け取り、wasavi が起動しているようなら VimFx をサスペンドさせればいいのである。

* * *

というわけで色々作って、VimFx の API を使ってどうこうするところまで来たのだが。

ドキュメントによれば、API はそれを提供するオブジェクトのインスタンスを通して使用する。インスタンスの取得は

let {classes: Cc, interfaces: Ci, utils: Cu} = Components
Cu.import('resource://gre/modules/Services.jsm')
let apiPref = 'extensions.VimFx.api_url'
let apiUrl = Services.prefs.getComplexValue(apiPref, Ci.nsISupportsString).data
Cu.import(apiUrl, {}).getAPI(vimfx => {

// Do things with the `vimfx` object here.

})

こんな感じで、ここで [cci]getAPI[/cci] に渡しているコールバックに渡される仮引数 vimfx がそのインスタンスなのだが。困ったことにその中に VimFx をサスペンドさせるようなそのものズバリの機能はないのである。

というより VimFx 自体にサスペンドという概念がない。その代わり、すべての入力を素通りさせて VimFx は関与しない ignore モードというのがあって、normal モードから ignore モードへ遷移することで結果的にサスペンドが行える。で、このモードを遷移するための [cci]enterMode()[/cci] メソッドはどこに属しているのかというと VimFx のコマンド群のそのハンドラに渡される vim パラメータが持っているらしい。しかしこれを API から直接的に得る手段はない。うーんどうすれば……。

しかし、間接的に得る手段はある。[cci]vimfx.on()[/cci] でいくつかのイベントハンドラを登録することができて、その時も vim パラメータが渡される。これを取っておいて、必要なときに使えばいけるかもしれない。

* * *

というわけで、期待した動きをするようになった。