2018/11/05 7:28 pm
Kenya Television Network #3
Uncategorized, , ,

というわけで私的な環境におけるキーバインディングを整理したのだが、実は赤福プラス自身も textarea においていくつか Emacs ライクなショートカットを定義している。

でもそもそもこれ、いるんだろうか。textarea にショートカットがたくさん用意されていないと死んでしまうような輩は、そもそも自分でシステムレベルで有効な環境を構築している気がする。

まああっても害になるものではないし、残しておくかな。とりあえず設定にそういったショートカットを有効にするかどうかの項目だけ追加しておくことにしよう。

ところで javascript から textarea 内のキャレット位置を変更するには、selectionStart/selectionEnd をいじる他に、Selection#modify() がとても有用なのだが…どうもこれ、Firefox だと全然動かないみたい。63.0 on Linux、63.0.1 on Windows10 の両方で動かない。リファレンスを自分とこで用意しておきながら動かないってどういうことなんだろう。

2018/10/22 8:41 pm
Let the box be light
Uncategorized, , , ,

画像をクリックするとデフォルトで lightbox 的な振る舞いをするのだが、これにはいくつか積み残しになっている点があった。

まず、画像を原寸表示させた際。このモードではマウスのドラッグにより画像のスクロールが可能なのだが、ドラッグしたままポインタをブラウザ外に持っていき、そこでボタンを離したりすると状態管理の不整合が起きてドラッグしてないのに画像がポインタについて来るみたいなことになってしまう。

これはつまりポインタのキャプチャをしていないからなのだが、何故していないのかと言うと、正確には覚えていないけど多分 Presto Opera にその機能がなかったんだと思う。これを直したい。

次に、全体表示から原寸表示モードに移行した際に拡大の原点がつねに画像の中心なのが不便。たとえば漫画なんかを1枚絵にした画像の場合に、原寸表示にしたあと上端へスクロールさせなければならないのが煩わしい。これを解決したい。

最後に、スマホで撮った写真など、本来90度回転して表示されるべきものが、そうなっていない場合がある。これに対応するため、画像の回転機能が欲しい。

というわけで、上記を解決するために書き直した。

回転にも transition をかけたのでやたらスムーズにくるくる回るのが面白い。

2番めの問題を解決するために、従来は画像をクリックすると lightbox を抜ける動作をしていたのだが、新しいバージョンではクリックしたポイントを原点に拡大縮小するようになった。lightbox を抜けるには画像以外の部分をクリックする必要がある。これはちょっと優しくない仕様変更かもしれない。

それと、画像のドラッグ時にいわゆる bounce-back 機能をつけたのだけど。これをつけると Apple に訴えられるんでしたっけ? ヤバイのかな。

* * *

とかなんとかやってたらまたふたばが全滅してるし…。

2018/10/13 4:22 pm
Improve 💃🏃 handling
Uncategorized, , , ,

赤福プラス上では絵文字を Twitter のそれに準拠して表示するようにしているが、それを v2 に引き上げた。twemoji が謳っているとおり、2,841パターンの絵文字に対応している、はず。

Firefox だとタブのタイトル部分もカラーの絵文字で表示されてえらい。

2018/10/04 9:15 pm
sync, sync, sync
Uncategorized, , , , ,

従来は設定を localStorage に持っていたが、chrome.storage.sync に持つようにした。storage の読み出しは非同期的に行われる。バックエンドの接続と、DOMContentLoadedの待機と併せて、起動時に非同期に行われる処理がこれで3つになった。これらを Promise.all を用いて並列的に処理するようにした。

そういえば sync って Firefox や Opera だとどういう扱いなんでしたっけ? Firefox は対応しているようだ。Opera は対応していないらしい。対応はしていないが、chrome.storage.local にフォールバックされるようで呼び出してもエラーにはならない。なにそれ。Opera Sync があるんだからそれとくっつけてよ。

カタログのリロード処理を見直した。また、デフォルトのソート順の場合はページ数を表示するようにした。選択したカタログのソート順を覚えておき、ページ全体をリロードした際も再現するようにもした。

ところで、xsl において、あるコンディションによって出力する内容を変えたいときがある。例えば出力する要素のクラス名に特定の文字列を状況によって含めたり、外したりしたい場合。

<span class="{if $need_hide='yes' then 'hide' else ''}">...</span>

のようなことをしたい。波括弧に囲まれた属性値テンプレートは xpath の式だ。当然上記はエラーになる。

そんなわけで

<span class="{substring('hide',1,4*number($need_hide='yes'))}">...</span>

のようなとてもトリッキーな書き方をせざるを得ない。= 演算子が true か false かを返し、number() がそれを 1 か 0 に変換し、式が真の場合は hide の先頭から4文字(つまり “hide” そのもの)、偽の場合は先頭から0文字(つまり空文字列)を出力する。

もうちょっとスマートな方法がないものかな。

2018/09/26 12:53 am
WebExtensions and clipboard operation, revised
Uncategorized, , , ,

現状では赤福プラスのファーストクラスブラウザは Chrome なのだが、一応 Firefox の WebExtensions でも動作確認はしている。でもどうなんでしょう。そもそも Firefox たまにしか立ち上げないし、また Firefox 上の他のふたば用エクステンションはここの所かなりたくさんリリースされているので、そこに加わるのもなあという感じ。

まあそれはそれとして。

WebExtensions では、パッケージ内のリソースを参照する際は moz-extension: スキームを使う。Chrome では chrome-extension: だ。これは内部で使用している xsl ファイルに埋め込まれたスタイルシートの中の background-image なんかで問題になる。background-image を使用する箇所だけを別の css ファイルにして解決(あんまりイケている解法ではない)。

以前クリップボードの取り扱いについて四苦八苦したことがあったが、基本的に変わってない。なぜか Chrome と全く違うクリップボード操作を強いられる。ただしそれとは別に、javascript からクリップボードを扱うための API ができて、割と最新のブラウザなら使えるようだ。とりあえず Chrome 69 なら使える。Firefox 63 では about:config から dom.events.asyncClipboard.dataTransfer を true にすることで使える。デフォルトの状態では使えない。

そういうわけなので

if ('clipboard' in navigator)
  navigator.clipboard.writeText(text);
else if (IS_GECKO)
  setClipboardGecko(text);
else
  setClipboard(text);

…みたいな感じにした。

2017/01/18 6:12 pm
Testing with selenium javascript binding #4
Uncategorized, , , ,

そういうわけで Linux 上では WebExtensions 版の wasavi の、Selenium による、Firefox 上の機能テストを一通り通せるようになったのだが、結局これを Windows 上ではできていない。過去の記事で何度か書いているが Windows では既存のプロファイルでもって Firefox を起動させることができず、かつ新規プロファイルに WebExtensions ベースの拡張を登録させつつ Firefox を起動させることもできない。両方できないと身動きが取れない。

実を言うと Linux 上でもテストが問題なく滞りなくできてるわけではない。例えば:

  • なにかが leak してますよ〜的なログがいっぱい出る。
    (node) warning: possible EventEmitter memory leak detected. 11 listeners added.

    云々。このエラー自体は書いてあるとおりのそのままの意味なんだろうけど、Chrome でテストする際は出ないので Selenium 内の Firefox とのやり取りをするコードにおける問題だと思う

  • wasavi でテストする際は当然ながら様々なキーストロークを発生させる必要がある。で、selenium.Key.chord() というものがあり、chord(Key.CONTROL, 'c') などと呼ぶと ctrl+C を押されたとブラウザに振る舞わせるような擬似的なキーストロークを生成する。Key[なんとか] は、型自体は普通の string で、Unicode の Private Use Area 内の文字である。chord 自体は単に引数を全部 join(”) したものに Key.NULL をくっつけたものを返す。したがって擬似的なキーストロークもまた単純な文字列である。さてそういうルールのもとに構成された chord を送出したあと、geckodriver かあるいは Firefox 本体が例えば前述の例だとそれを ctrl+C としてデコードしてくれないと困るわけなのだが。困ったことに、誰もデコードしてくれない。そのまんま PUA が入力され、テストは失敗する。ひどい
  • テスト中 Web Content なるプロセスが生成されて、これが60〜80%の CPU パワーを消費する。同時に Firefox 自体のプロセスが残りの CPU パワーを消費する。そんなわけでテスト中は待ってる以外にほとんど何もできないし、そもそも端末以外のアプリケーションを全て落とした状態じゃないとテスト自体がうまく始まらない。Chrome を起動しながらとか成功した試しがないのである。そして CPU パワーはめちゃくちゃ食いまくる割にテストの進行は Chrome でのそれより 2 割増しくらいで遅い

前述のプロファイル関連の不具合と合わせて、どーにもこーにも…… Firefox が絡む Selenium のテスト環境はいつも質が悪い、質が低いと言わざるを得ない。どうなってんのかなあこれ……。この辺が快適になってくれないと、Firefox 向けの拡張を作るという事自体にくじけてしまいそうなのだけど。

2017/01/14 10:06 pm
Testing with selenium javascript binding #3
Uncategorized, , , , , ,

テストを開始しても、Chrome は起動するもののテストページへのナビゲーションが発生せず、そのままタイムアウトで失敗してしまうことがたまにある。これの原因がよくわからない。とりあえずエラーメッセージとしては “unable to discover open pages” というものが返される。

原因はよくわからない。テスト用とは別の常用の Chrome を起動している状態でテストを開始すると、そういう状況が発生することがあるが、しないこともある。常用の Chrome を落とした状態でも発生することがある。また youtube とかの動画を再生中だと発生する確率が上がるような気がしないでもない。要するに chromedriver が Chrome を起動するものの、複数ある Chrome のうち自分が起動させたものを見失うことがある、というような感じなのだが……そんなわけあるかいな。

上記のエラーメッセージでググっても特にこれだというものもない。謎。

ちなみに Linux 版の Chrome で UI のロケールを任意のものにするには、LANGUAGE=en google-chrome などとする。LANG でも LC_ALL でもなく、LANGUAGE。また、--lang スイッチは効かない。

 * * *

というわけで、とりあえずすべての機能テストを java から javascript へ移植した。疲れた。次にこれを Windows 上の Firefox にて通してテストする。とその前に、Linux 上でも動かしてみよう。

ナウい Firefox で Selenium のテストをするには、geckodriver が必要なので、これをパスの通ったところに置いておく。

var options = new firefox.Options();
options.setProfile(profilePath);
result = new webdriver.Builder()
      .withCapabilities(webdriver.Capabilities.firefox())
      .setFirefoxOptions(options)
      .build()

こんな感じで起動。これは既存のプロファイルを利用するような動作を意図しているが、どうも既存のプロファイルを /tmp あたりにまるごとコピーしてから起動するような感じがする。そのため実際に Firefox のウィンドウが表示されるまでは結構待たされる。

それから、webdriver.actions().sendKeys().perform() が未実装なのだそうでエラーになる。その代わり WebElement#sendKeys() を使う。geckodriver 自体が新しいプロジェクトなので、すべての想定された機能が実装されるまでにはもうちょっとかかる雰囲気。

 * * *

結局のところ wasavi でテストするには

  1. npm install -g selenium-webdriver
  2. npm install -g chromedriver geckodriver operadriver
  3. npm install -g mocha
  4. npm install

と入れて、make run-chrome としてとりあえずテスト用プロファイルでもって起動し、開発者モードで wasavi を組み込み、ついでに dropbox などに wasavi からアクセスして認証を得ておき、ブラウザを閉じてから make test-chrome とする……という感じ。ただし Firefox に関しては、過去の記事の通りオンザフライで WebExtensions ベースの拡張を登録するのが現在のところできないので、wasavi をビルドした上で xpi を登録したプロファイルを用意する必要がある。

2016/12/25 10:20 am
Add-on SDK to WebExtensions #5
Uncategorized, , , ,

ところが結局、Windows 上の Firefox で Selenium によるテストを行うところまで至っていない。現状では

  • Windows 上で
  • 任意の拡張を一時的に読み込ませつつ
  • そのプロファイルを使うよう Selenium に指示する

という術がないように思える。となるとテストのために一旦 xpi をビルドして、署名して、それを使うしかない。

ちなみに Selenium は現在 version 3 になっていて、Firefox に関しては Chrome の chromedriver.exe と同様 geckodriver.exe を介在させるようになっている。そのためにシステムプロパティ webdriver.gecko.driver に geckodriver.exe へのフルパスを書いておく必要がある。

ということで試してみたところ

File p = new File("C:\\path\\to\\profile");
WebDriver driver = new FirefoxDriver(p);

の呼び出し中に

Java heap space
java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:3332)
        at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
        at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
        at java.lang.StringBuilder.append(StringBuilder.java:136)
        at org.openqa.selenium.remote.ProtocolHandshake.amendOssParamters(ProtocolHandshake.java:183)
        at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:61)
        at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:141)
        at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:82)
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:601)
        at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:241)
        at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:128)
        at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:259)
        at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:247)
        at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:242)
        at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:238)
        at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:131)
        at WasaviTest.WasaviTest.createDriver(Unknown Source)
        at WasaviTest.WasaviTest.beforeClass(Unknown Source)

……どうしろというのか。

 * * *

FirefoxDriver のコンストラクタに独自のプロファイルを与えるのではなくデフォルトのそれを使用するようにすると(要するに何も引数を与えないと)起動した。なにそれ。テストのためのツールである Selenium ががろくにテストされてない…。真面目にやってくださいよ本当に。

 * * *

FirefoxProfile p = new FirefoxProfile();
p.addExtension("/path/to/wasavi.xpi");
driver = new FirefoxDriver(p);

とやるととりあえず OutOfMemoryError で落ちることはないのだが、拡張を登録する処理で「アーカイブの中に install.rdf がないよ〜」的なエラーになる。この場合の wasavi.xpi は WebExtensions ベースの拡張なので install.rdf ではなく manifest.json を見に行ってくれないといけないのだが、Selenium 側がまだ WebExtensions ベースの拡張を知らない状態なのだろう。

うーん! だめじゃん。WebExtensions の拡張を Selenium でテストするのは時期尚早なのか。

2016/12/17 3:14 pm
Add-on SDK to WebExtensions #3
Uncategorized, , , ,

content script において window.Uint8Array を使おうとするとエラーになる。グローバルオブジェクトのそれを使わないといけない。両者は権限のドメインが違う、らしい。グローバルオブジェクトに Uint8Array が存在する場合はそれを、次に window に存在する場合はそれを使うようにした。

window. を前置するのをやめればいいじゃん、と思うかもしれないが、そうはいかない。赤福プラスでは window のプロパティを参照する際は必ず window を前置している。これは Presto Opera で動かすための措置で、Presto Opera の injected script では window がグローバルオブジェクトではないのである。したがって前置は必須なのだった。

それにしても、今 Presto Opera 使ってる人ってどんくらいいるのかなあ…? とはいえ赤福プラスはまだ Presto Opera もサポートしているので、動作確認のために新しい環境にも 12.16 を落としてインストール。

ところでメモやブックマークを同期しようとログインしようとしたらどうやっても弾かれるんですけど…。

Firefox の方は SDK 版から WebExtensions 版への自動更新が滞りなく行われることを確認。

さてこの SDK -> WebExtensions の作業において赤福プラスは前座でしかない。本丸は wasavi なのである。

2016/12/15 5:47 pm
Add-on SDK to WebExtensions #2
Uncategorized, , ,

一通り動くようになった。

すでに上げた Port の引数の問題の他、content script で生成した XMLHttpRequest の動きが変。

  • Referer が吐かれない
  • Cookie が送出されない
  • open() の際、相対 URL を与えるとエラーになる

同様の問題を抱えている人がいた。そのやり取りによると、

   try {
      return XPCNativeWrapper(new window.wrappedJSObject.XMLHttpRequest());
   }
   catch(evt){
      return new XMLHttpRequest();
   }

こんな感じで Firefox に限り意味の分からない書き方をすることで解決できるそうな。確かにこれでうまく行くけど…早く直してほしい。

ところでもうひとつ、ID の問題がある。Chrome のエクステンションは基本的にそれを識別する ID というものを開発者が意識する必要はない。エクステンションをローカルで crx にパッケージングした際に生成される .pem ファイルは取り扱いに気をつける必要はあるが、今日ではローカルパッケージングは zip で事足りるので .pem ファイルを生成する必要自体が基本的にない。

WebExtensions の場合は一応その流儀に倣っているが、しかしやはり Firefox の拡張らしく、ID は裏で健在だったりする。というのも署名を mozilla のサーバにつけてもらうと .web-extension-id という ID が書かれたドットファイルをもれなくプレゼントされるのである。うーんなんかイケてなくないですか。

一方で陽に ID を取り扱うこともできる。manifest.json の applications に

  "applications": {
    "gecko": {
      "id": "[email protected]",
      "strict_min_version": "42.0",
      "update_url": "https://github.com/akahuku/akahukuplus/raw/master/dist/firefox.json"
    }
  },

とこんな感じに書けばいい。ただよく分かんないことに、こう明示したとしてもやはり .web-extensions-id ファイルはプレゼントされる。いらないんですけど!

ところで上記の ID、いかにも Add on SDK 製の拡張っぽい書式だが、実際に SDK 版の赤福プラスの ID だ。というのも、おそらく流用しないと SDK 版から WebExtensions 版へのスムーズな自動更新が行えないからだ。うーんなんだかかっこ悪いなあ…。

Archives