FixScroll0.7版をリリースしました。

機能的なバージョンアップはありません。
バグFIXというかレビューポイントFIXです。これでFullReviewを通るはず。


昨日から今日にかけて、Mozilla勉強会に参加してきました。
10月1日(土) に Mozilla 勉強会@東京 6th を開催します | Mozilla Developer Street (modest)


初めての勉強会だったのですが、皆さん温かく接してくださり、非常に楽しい時間をすごせました。ありがとうございます。
博識な方ばかりで肩身の狭い思いをしたのも良い勉強でした。


特にうれしかったのが、アドオン開発をはじめたきっかけともいえるpiroさんとお会いしてお話できたこと。
しかもアドオンのレビュー指摘でなかなか解決できなかった問題を相談したら、サクッと解決してもらえました。さすがのpiro先生です。


Firefox Hacks系の最新本が出るそうなので、お礼も兼ねてばっちり購入予定です。


1,2ヶ月ほど悩んでいた問題は以下です。

DOM mutation events profoundly degrade performance, and that degradation is not reversed by removing the listeners. We can't allow mutation listeners except when they're absolutely necessary, and never for the top-level browser document.


XULのscrollbarを利用していたのですが、scrollbarの変更を取得するのにはDOMAttrModifiedを利用する必要がありました。
が、そもそも単体でXUL内で呼び出すものではないとIRCの外国の方が教えてくれました。

そこで思いついたのが、xul:box要素(親)の中にxul:box要素(子)を入れて、子のほうのwidth,heightを調整して、スクロールバーを表示させる方法です。
しかし、ひとつ躓いたのが子要素に対してtextを設定しないと縦のスクロールバーが表示されないことでした。(textを設定すると、XMLワーニングが出ます。)


ワーニングが出るXUL

<box id="parent" style="width:100px; height:100px;">
  <box id="child" style="width:1000px; height:1000px;">text要素
  </box>
</box>

警告: box 要素の XUL ボックスがインラインの子要素 #text を含んでいるため、すべての子はブロック中で折り返されます。


このワーニングを防止かつ縦のスクロールを表示する方法を30分くらいでpiroさんがさくっと調べてくれました。
「気になるんだよねー。詳しく教えて」と聞いてくれました。優しくていい人すぎる!!
#piroさんに似顔絵サイン入りの名刺をいただいたのは一生の秘密です^^無理言ってすいませんでした。


リリースしたXUL

<box id="parent" style="width:100px; height:100px; position:fixed; display:block;">
  <box id="child" style="width:1000px; height:1000px; display:block;"> 
  </box>
</box>


そもそも縦方向のスクロールが出ないのはXULのbox要素のデフォルトのdisplayスタイルが'-moz-box'になっていて、このスタイルだと横方向か縦方向のどちらかにスクロールバーを表示するのが仕様だったのが原因です。

Child elements are laid out horizontally or vertically (based on the value of the -moz-box-orient property).

display - CSS: Cascading Style Sheets | MDN


それを回避して縦横両方にスクロールバーを表示させるために、display:blockを指定しています。
また、position:fixedにすることで、親要素のwidth,heightが利くようにしています。


また、pano作っているteranekoさんにcanvas要素に対して-moz-elementを指定するといいのではとアドバイスいただきました。ありがとうございます。
ちょっと試したところ、今の構成だとうまく使えない感じだったので、今回のリリースには含めませんでした。今後活かす方法を検討中です。


Mozilla JapanのDynamisさんにモバイル版も作ったらと言われたので、今後の課題に追加です。
ただ、Androidしか環境がないので、携帯はiOSにまみれている私は環境を求めるところから。

アドオンのレビュー申請の前というか、アドオン作るときに知っておくこと

とても悲しいことがおきました。
Fixscrollが削除されていました。何かの手続きの不備か、申請中の状態のものはFirefox更新とともに闇に葬られるのかもしれません。
ちょうど新しく対応したものがあったので、FullReview申請とともに再度アップしました。
#ようやくストレス少なく使えるように仕上がってきたので、ある意味気持ちの切り替えになりました。


さて、前回のエントリでレビュー前にやっておくことと書いたことができていませんでしたorz
禁則事項やら、基本の名前空間は事前にぐぐって調べておいたほうが幸せになれると思います。
アドオンバリデータでwarningになったらNGというぐらいの気構えのほうがいいかもしれません。
#このエントリもその一助になればと。


指摘いただいたのは以下です。

1) You are still defining the symbol animationManager in the global namespace.


2) Please remove the evalInSandbox calls from your timer implementation. I realize the intention is to ape the standard functions, but a) it doesn't, and b) such uses of setTimeout are not allowed in AMO add-ons.


1) 使わせてもらっていたpiroさんのライブラリのimportの仕方がまずかったです。

Components.utils.import('resource://snipescroll-modules/animationManager.js');


こうすると、globalネームスペースで宣言されます。(事前に存在チェックをかければ良いかもしれません。)
今回は、globalを使うことを避けてローカルのネームスペースを利用することにしました。

var hoge = {};
Components.utils.import('resource://snipescroll-modules/animationManager.js', hoge);

2)使わせてもらっていたpiroさんのライブラリのバージョンが古いままで更新してなかったのが原因です。
あと、evalInSandboxをライブラリのjsmtimer.jsm内で呼んでいるのもいけないようなので、L131,132の以下の行をコメントアウトしています。


ダウンロードしたもの

else
	evalInSandbox(this.callback);


レビュー申請時

//else
//	evalInSandbox(this.callback);


この処理は、実行部の引数に文字列(関数名)を記載したときにも動くようにしているので、自分が使うときに関数を渡すようにしていれば呼び出されることはありません。

アドオンのレビュー申請の前にやっておきたい2つのこと

すでに作者の方々は皆知っている内容と思いますが、
個人の反省も踏まえて、いったん共有しようと思います。
(えぇ、アドオン二つともFull Reviewをrejectされましたorz)


Firefoxのアドオンにはレビューが2段階あります。
1)Preliminary Review
2)Full Review
#公式Add-on Policies - Mozilla | MDN


1個目は簡易的なレビュー。通過するとAMOで検索できます。(ただし、実験的という注意書きがかかれます)
2個目は正式なレビュー。通過すればAMOで検索でき、何の注釈もつきません。(トップページにも表示されるようになったと思います。)


今までは1個目のPreliminary Reviewだけを申請していました。こちらはすんなり通ります。(今は高速サイクルリリースの影響もあって、レビューはかなり遅れ気味です。ただ、レビュワーの方はボランティアで見てくれているので、ただただ感謝です。)


余裕かと思いきや、Full Reviewはきちんと突っ込まれます。
引っかかったのは以下の2点。

1) In order to prevent conflicts with other add-ons that may be installed by users, you need to wrap your "loose" variables and functions within a JavaScript object. You can see examples on how to do this at https://developer.mozilla.org/en/XUL_School/JavaScript_Object_Management.


2) Your add-on uses the 'eval' function unnecessarily, which is something we normally don't accept. There are many reasons *not* to use 'eval', and also simple alternatives to using it. You can read more about it here: https://developer.mozilla.org/en/XUL_School/Appendix_C:_Avoid_using_eval_in_Add-ons


1個目は、アドオンで宣言しているJavaScriptのグローバル名称を管理しなさいということ。
⇒単純に同じ名称のオブジェクトがundefinedか確認するだけ。


2個目は、evalは一切使ってはいけません。ということ。
⇒既存のアドオンでもFullReview通っているからといって油断してはだめでした。
 ⇒関数の置き換えでわかりやすいように実装する。


せっかく作ったアドオンを早くAMOに載せられるように、ここは最初からきちんと読み込んで対応しておくべきでした。反省。


現在は2つのアドオンともに修正し、再度FullReview待ちの状態です。
FixScrollはRejectされてしまったので、現在はダウンロード不可の状態です。Firefox5対応がまだの状態なので、早くReviewされたいところです。


Reviewerとなってくれた方は外国の人でした。
日本語ばかりの説明なのにレビューしてくれて、ありがとうございました。
Thank you for your review.

javascript要素のdumpを吐くには

このサイトの機能を拝借します。JavaScript Infected


指定したjavascript要素の属性、メソッドなどの情報をdumpしてくれます。ものすごい便利。


javascript的に厳密にするのであれば、以下を

for ( k in o ) {

書き換えて、

for ( var k in o ) {


にするのと、ダンプをコンソールに出力するように、以下を

el.innerHTML = str;

書き換えて

Application.console.log(str);

と修正すればOK

FixScrollで困ったイベントの再帰防止方法メモ

FirefoxのアドオンFixScrollでは、通常のスクロール機能を完全に隠蔽して、その上にFixScroll方式のスクロール機能を実装しています。


中でも困ったのがページ内リンクでした。
最初のバージョンでは未対応のままリリースしましたが、実際に自分で使う中でこの機能が働かないと非常に使いにくい。ということでなんとかバブリングの再帰防止対応しました。かなり強引な方法なので、正規なやり方ではないかもしれませんが、とりあえず共有。


簡単な構造はこちら

<tabbrowser>
  <stack>
    <browser/>
    <canvas/>
    <scrollbar/> //縦スクロールバー
  </stack>
<tabbrowser>

■前提

scrollbarの変更をbrowser,canvasの表示領域に反映する。
=scrollbarを変更するとbrowserがscrollする。

(1)リスナーの追加


ページ内リンクのイベントをキャプチャする方法のひとつはタグのscrollイベント。(他の方法を調べてみましたが、どのソースに書いてあるのか突き止めきれず。)それをbrowserに対して追加します。

browser.addEventListener('scroll', method, bool);


#上記のメソッド内でscrollbarが変更されるため、結局browserに再度scrollイベントが発生する。そのため、再帰的にイベントが発生してしまう。

(2)メソッド内の最初にリスナーの削除、最後にリスナーの追加

function method(){
  browser.removeEventListener('scroll', method, bool);
  //ここに処理内容を記載(scrollを発生させる処理が含まれる)
  browser.addEventListener('scroll', method, bool);
}


この場合でもscrollのイベントをキャプチャしてしまいます。
(method内での処理をトリガーとするリスナーはmethodが終わってから判定する?)

(3)最後にリスナー追加する部分をスレッドで処理させる

function method(){
  browser.removeEventListener('scroll', method, bool);
  //ここに処理内容を記載(scrollを発生させる処理が含まれる)
  window.setTimeout(function(){browser.addEventListener('scroll', method, bool);}, 0);
}


これは他のアドオンでどのように実装しているのか調べているときに見つけました。調べたアドオンはこちらFoxSplitterです。


こうすると、method内で処理した内容を元にキャプチャしなくなります。

(4)[bad know how] 最終イベント実行時を保持して、現在時刻と比較して処理の実行可否を判断


上記の処理が連続で起こる場合、タイミング次第ではイベントが発生してしまいます。method内でリスナー削除した後にスレッドがリスナー追加してしまうような状況です。


FixScrollアドオンでは、scrollイベントをトリガーにスクロール処理をするため、余分なイベントをキャプチャ=余分なスクロールとなり、避ける必要がありました。ページ内リンクが連続して行われることはないため、選択肢のひとつとなりえました。

function method(){
  var diff = new Date() - lastMethodTime;
  lastMethodTime = new Date();
  if(diff < 300) return;
  browser.removeEventListener('scroll', method, bool);
  //ここに処理内容を記載(scrollを発生させる処理が含まれる)
  window.setTimeout(function(){browser.addEventListener('scroll', method, bool);}, 0);
}


(4)の対応をしても、ページが重い場合には閾値をどうしても超えることもあるため、100%確実な方法とは言えません。とはいえ、ほとんどのケースでは(3)までの対応で何とかなると思います。

FixScrollの 未実装の機能メモ

現在開発中のアドオンのため、以下の点で改善が必要です。


・ページ内リンクに飛べない。(ver0.3_20110523で解消)
・ZOOMが100%以外のときに表示がカクカクする。
FLASHなどでの動画表示は分割されている片側でしか表示できない。
 ->youtubeニコニコ動画をみるのには向いていない。
・frame,iframeでは通常スクロールのまま。
 ->GMailはiframeで表示されているため、FixScroll機能は利用できません。
・ページ読み込み中にスクロールしても、先頭までスクロールが戻ることがある。
・スクロールしても、ヘッダ部分などをずっと表示するスクリプトがあるページをみると、表示がおかしくなる。

という点はありますが、ものを読むという点では、通常のスクロールよりも大幅に読みやすいと考えています。随時開発して改善を進めていく予定です。

#他にも不具合が見つかりましたら、本ブログでもアドオンレビューでも構いませんので、フィードバックいただけるとうれしいです。

ブラウザのスクロールを改善するアドオンFixScrollをリリースしました。

Preliminary Review申請中ですが、Firefoxのアドオン第2弾をリリースしました。

ワイプするようにスクロールができるようになります。イメージ的には日めくりカレンダー。
パワポのページ切り替え方式でいうと、通常のスクロールはスライド、このアドオンはワイプに当たります。)


まだPreliminary Review前(5/21)
https://addons.mozilla.org/ja/firefox/addon/fixscroll/


通常のスクロールだと、スクロール中にコンテンツが動いてしまうため、読む⇒スクロール⇒読むの繰り返しになります。これが私には苦痛でした。スクロールするたびに読んだ位置を目で追わなければならず、読み物にはスクロールは本当に向いていない!と感じていました。
いつも読むときはこんな感じ。
1.読み終わったテキストを選択して目印とする
2.スクロールする(読み終わった位置を一番上に持ってくる)
3.また読み始める
4.この繰り返し
※この動作を簡略化するため、前のアドオンSnipeScrollを開発しました。


FixScrollの表示の仕方だと、コンテンツは一切動かないため、読むのを中断せずにスクロールすることができます。(上記の作業は一切いらなくなる)


まずはページが表示されます。(ブラウザを普通に使うように)


ある程度まで読んだらスクロールします。


すると、次のコンテンツが上から出てきます。
⇒表示されている部分はつねに同じ位置なので、どこまで読んだか探す必要はありません。


さらにスクロール


と読み続けられます。


操作方法としては、通常のスクロール動作をほとんどエミュレートしているので、違和感なく使えると思います。1点異なるのはALTキー(Metaキー)を押しながらスクロールすると、通常のスクロールの動作をします。この機能は画面の端で画像が切れているときなどの調整時に使います。


こんなとき


ALT+スクロールすると


画像全体を見れるようになります。


画面の最下部には、灰色で半透明に表示されているエリアがあります。この部分は次のページでも同じ内容を表示している領域になります。スクロールの仕組みを変更したことで、画面の端で文字が切れてしまう場合があり、その際にALTキースクロールをしなくても読み続けられるようにするためです。


なお、0.2_20110521版まではページ内検索機能を利用するには、「Find to Center」が必要となります。

まだ未実装の機能は別記事でまとめます。


ソースはGithubにあります。