Now browsing the archives for 8月, 2006.
スピンボタン付きテキストボックス (xul:textbox type=”number”)
先日XULのスピンボタンが実装されたと思いきや、今度は8月17日のトランクビルドにて Bug 345510 – Add <textbox type=”number”> がFixされ、スピンボタン付きの数値入力用テキストボックスが利用可能になった。通常の textbox 要素に type=”number” 属性をセットし、入力可能な最小値(min属性)、最大値(max属性)、増減(increment属性)を指定してやれば、思い通りにスピンボタンが動作してくれる。
また、属性 wraparound=”true” によって最小値と最大値が循環して入力できるようになる。また、属性 decimalplaces=”3″ などとすることで小数点以下何桁まで表示するかを指定可能である。
<textbox type="number" min="80" max="250" increment="10" />
詳しくは: chrome://global/content/bindings/numberbox.xml
parseInt の落とし穴 - 8月発生の時限式バグ
何気なくScrapBookのbackupフォルダを覗いてみたところ、なぜか一番新しいバックアップファイルが7月31日に生成されたもので、8月以降およそ2週間まったくバックアップファイルが生成されていなかった。
これは何か怪しいと思い、バックアップ処理を細かく調べたところ、バックアップファイル名の日付が何日前かをチェックする処理において、なぜか本日生成されたばかりのバックアップファイルが200日以上前のものだと判断され、即座に削除の対象にされていた。
ScrapBook では Firefox 起動時に本日付のバックアップファイルが存在するかを確認し、もしなければ本日付のバックアップファイルを生成し、なおかつ古いバックアップファイルの削除処理を行うという仕様になっている。したがって、 Firefox を起動する度に本日付のバックアップファイル生成→本日付のバックアップファイル削除、という処理が8月以降ずっと繰り返されていたというわけだ。
ではなぜ8月以降、バックアップファイルが何日前かを算出する処理がうまくいかなかったのだろうか。OSの設定が狂った、夏時間特有の問題、2つのDateオブジェクトの減算で型変換がうまくいっていない等の原因を考えたが、色々追求した結果、parseInt(“08”) が 0 になることが原因だと判明した。
alert( parseInt("08") ); // 「0」が表示される
今まで parseInt というJavaScript の組み込みグローバル関数は、string 型で表現された整数を、number 型に変換するだけの単純なものだと思っていたが、実は string 型で表現された小数や8進数や16進数や文字列も変換可能である。その際、引数として渡した string 型の値をどのような形式で変換するのかは自動で識別されるため、先頭に0をつけている場合は8進数とみなされ、”08″ が 0 に変換されるのである。また、第二引数に基数 10 を指定することで思い通りに10進数として変換させることが可能である。
alert( parseInt("08", 10) ); // 「8」が表示される
この parseInt(“08”) が原因となるバックアップ処理に関するバグは、8月になると突如発生する時限式バグといえよう。運良く2週間ほどでバグに気づけたことが不幸中の幸いである。このバグを修正したバージョン (1.1.0.2) はすでにリリース済みである。
ところで、ScrapBook を世に公開して間もない、非常に初期のバージョンにて、2004年10月になると突如取り込んだデータが上書きされ続けるという大変恐ろしい時限式バグが発生したが、このときの原因も今回のバグの原因と通ずるものがあり、年・月・日を加算するときに型の自動変換に頼っていたためにバグが引き起こされていた。
var y = 2004; // number var m = "09"; // string var d = 30; // number var ymd = y + m + d; alert(ymd); // 「20040930」が表示される
9月30日までは、数値 9 を 文字列 “09” にして加算をしていたため、 2004 + “09” は “200409” になってうまくいっていた。
var y = 2004; // number var m = 10; // number var d = "01"; // string var ymd = y + m + d; alert(ymd); // 「201401」が表示される
しかし、10月1日になると、数値 10 は文字列に変換せずに加算していたため、 2004 + 10 は 2014 になってしまった。
var y = 2004; // number var m = 10; // number var d = "01"; // string var ymd = y.toString() + m.toString() + d.toString(); alert(ymd); // 「20041001」が表示される
数値か文字列かわからないような値同士を加算するときには、必ず toString や parseInt を使って正しい型に変換してから加算をしなければならない。
parseInt のリファレンス:
Core JavaScript 1.5 Reference:Global Functions:parseInt – MDC
ローカライズ可能な文字列を properties ファイルでなく DTD ファイルで定義するテクニック
一般的に、ローカライズ可能な文字列の定義は、以下のように2通りの使い分けが必要となる。
(1) XULファイル内で使用する文字列
DTD ファイル内に実体参照として定義し、XULファイル から DOCTYPE 宣言によって呼び出す。
(2) JavaScript内で使用する文字列
properties ファイル内に定義し、XULファイル から stringbundle 要素によって呼び出す。その例を以下に示す。
sample.xul
<stringbundle id="sampleString" src="../locale/sample.properties" />
sample.properties
sample.hello=こんにちは
sample.js
var sampleString = document.getElementById("sampleString"); alert(sampleString.getString("sample.hello"));
しかし、時にはわざわざ DTD ファイルとは別に properties ファイルを作るのが面倒なケースもある。そのような時、DTD ファイル内で文字列を定義し、XUL ファイル内に直接 JavaScript を書き込んでその中で実体参照を用いるというテクニックがある。この場合、JavaScript を CDATA セクション内に記述すると実体参照が行われないので注意する必要がある。
sample.xul
<!DOCTYPE window SYSTEM "../locale/sample.dtd"> ... <script type="application/x-javascript"> var gSampleString = { hello : "&sample.hello;" }; </script>
sample.dtd
<!ENTITY sample.hello "こんにちは">
sample.js
alert(gSampleString.hello);
designMode
designModeとは多くのWebブラウザに搭載される簡易HTML編集機能であり、おもにブログ投稿やWebメール作成のためのリッチテキストエディタとして使用される。
javascript:void(document.designMode='on')
ScrapBookで保存したページを閲覧時、このようなブックマークレットを用いてデザインモードを有効にすると、ScrapBookの編集機能ではどうしても不可能だった編集ができるようになる。たとえば、ある文章の一部を改変したり、段落を一つ増やして自分のコメントを文中に挿入したり、ブロック要素の幅を変えたり、他のページからコピーした画像や文章の断片をそのままページ中に貼り付けたりできるようになる。
こういった編集をしたいというユーザからの要望に対しては、designModeのブックマークレットを薦めてきたが、いっそのことScrapBookのステータスバーアイコンのメニューなどからdesignModeのオン/オフができるようにしたら面白いかもと思った。しかしdesignModeで色々試しているうちに、色々とおかしな現象が多発したので、Bugzillaを調べてみたところかなりバグがあるようである。
Bug 287707 – After page had designmode on, there are still several issues
Bug 304994 – iframe with designMode=on breaks when you navigate to another loaded page and then back
特にBug 287707で報告されているように、次のページへ遷移しても何も表示されないというバグが致命的なので、designMode切り替えメニューの搭載は当面先送りにした。