ようへい
ラベル JavaScript の投稿を表示しています。 すべての投稿を表示
ラベル JavaScript の投稿を表示しています。 すべての投稿を表示

2014年2月19日水曜日

IEEE 754 浮動小数点数 コンバーター

アセンブラ等で使用するIEEE 754 浮動小数点数のコンバーターです。
個人的に一番利用する機会がある32ビット単精度での相互変換を行います。

数値 -> 浮動小数点数

変換結果

浮動小数点数 -> 数値

変換結果
これを使うと、以下のような変換ができます。
Decimal Hexadecimal
-0.1 0xBDCCCCCC
0.1 0x3DCCCCCC
0.25 0x3E800000
0.5 0x3F000000
0.75 0x3F400000
1 0x3F800000
1.25 0x3FA00000
1.5 0x3FC00000
2 0x40000000
3 0x40400000
4 0x40800000
5 0x40A00000
10 0x41200000
50 0x42480000
100 0x42C80000
500 0x43FA0000
1000 0x447A0000
関連記事

2013年7月18日木曜日

非推奨になった Mutation events を Mutation Observers に置き換えよう

前からDOM3(黒い三連星じゃないよ)で実装されたDOMAttrModifiedや、DOMNodeInsertedをGreasemonkeyスクリプト内で使用していたのだが、これらのMutation eventsが非推奨となってしまったらしい。
じゃあ何を使ったらいいの?ということで、Mutation ObserversというAPIが提供されているらしい。 Mutation Observersの利用方法をまとめてみた。

ちょっと読んでみよう

使う前に、どうやって使うかなど、ちょっと頭に入れておこう。
Mozillaのページにまとめて書いてあるので、そちらを見れば大丈夫かと。
MutationObserver - Web API リファレンス | MDN
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver MutationObserverにメソッドを与えてインスタンスを作成。
インスタンスメソッドのobserve実行時のオプションで、監視する種類などを設定すると。フムフム。

MutationObserverはこう使う

コードを見た方が速いので、まずは使い方から。
たとえば、DOMAttrModifiedMutationObserverに置き換えるとこんな感じ。
$('#hoge').bind('DOMAttrModified',function(event){
  console.dir(event);
});
var mo = new MutationObserver(function(mutationRecords){
  console.dir(mutationRecords);
});
mo.observe($('#hoge').get(0), {attributes: true});
変更前の値も欲しいならこう
var mo = new MutationObserver(function(mutationRecords){
  console.dir(mutationRecords);
});
mo.observe($('#hoge').get(0), {attributes: true, attributeOldValue: true});

Mutation eventsからMutationObserverへ移行しよう

こんな感じかな。
Mutation events Mutation Observers
DOMAttrModified observe( Node target, {attributes: true, attributeOldValue: true} );
DOMNodeInserted observe( Node target, {childList: true} );
DOMNodeRemoved observe( Node target, {childList: true} );
DOMCharacterDataModified observe( Node target, {characterData: true, characterDataOldValue: true} );
DOMSubtreeModified observe( Node target, {subtree: true} );
そして Firefox、Chromeは実装しているけど、Internet Explorerは未実装らしい。さすがやで!期待を裏切らない。それでこそIE。
IEは消費電力で勝負ですもんね。
よいこのみんな!夏は消費電力を抑えるためにIEを使おうね (オイ)
Internet Explorer 10の消費電力はChromeやFirefoxより18%低い, とMicrosoftは主張 | TechCrunch Japan
http://jp.techcrunch.com/2013/06/06/20130605microsoft-internet-explorer-10-is-the-most-energy-efficient-browser-uses-up-to-18-less-power-than-chrome-and-firefox/
関連記事

2013年6月21日金曜日

Firefoxでの HTML5 Notifications (デスクトップ通知) 設定変更方法

Firefox 22から実装されているHTML5 Notifications APIですが、権限がリクエストされた時にこんなポップアップが表示されます。
Firefoxでの HTML5 Notifications (デスクトップ通知) 設定変更方法
Firefoxでの HTML5 Notifications (デスクトップ通知) 設定変更方法
ここで、デスクトップ通知の許可/拒否を設定します。
常に通知を表示する」か「通知をブロックする」に設定した場合、以後はポップアップが表示されません。
許可されると、こんなカンジでデスクトップ通知を受けれます。
Firefoxでの HTML5 Notifications (デスクトップ通知) 設定変更方法
のちのち、この設定を変更したいという場合、どうやったら変更できるのか調べてみました。

設定に無い!

まずオプション画面を一通り見たのですが、該当の設定がありませんでした。
こりゃ困った。
どっかには保存されているだろうと、Firefoxのprofileを覗いてみる。
permissions.sqliteに、typedesktop-notificationとなっているレコードを発見。hostの値も合っているし、これっぽい。
最悪、ここから変更はできそう。
でも、さすがに設定画面が用意されていない事は無いだろう。ということで、Firefoxの画面を一通り調べてみた。

こんなところにあった

ありましたよ。分かりにくいけど。
Firefoxのメニューから、ツール»ページの情報をクリックして、サイト別設定タブを開く。
すると、サイトからの通知の表示というのがあるので、ここから設定できます。
Firefoxでの HTML5 Notifications (デスクトップ通知) 設定変更方法
Firefoxでの HTML5 Notifications (デスクトップ通知) 設定変更方法
一括管理できる画面欲しいなぁ・・・。
FirefoxでのHTML5 Notifications API 通知方法 - ログろいど
関連記事

FirefoxでのHTML5 Notifications API 通知方法

Firefox 22からHTML5 Notifications APIがサポートされるという事で早速使ってみた。 とりあえずこんな感じで使える。
function notifyReq(){
  Notification.requestPermission(function(permission){
    console.debug("Notification permission: "+permission);
    if(Notification.permission == "granted"){
      notify();
    }
  });
};
function notify(){
  switch(Notification.permission){
    case "granted":
      new Notification("デスクトップ通知テスト", {
        icon:"https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixMhqVE-KPC4uFvSew7A5jZ64O0oJVsUXtBJVwv6JTF0BRIV_dI0hyYUh8qEGR6pdJ-WJaYd9xk97foeo_VCFIXc1O6vI8wWbl6grHGpbItKdrIMbn4tU8w4Zeaqj05ynBJdbhEHtkyWgE/s220/logroid_150.png",
        body:"デスクトップ通知のテストです",
        tag:"notification-test",
      });
      break;
    case "default":
      notifyReq();
      break;
    case "denied":
      console.warn("デスクトップ通知が拒否されています");
      break;
  }
};
notify();
こんなカンジで通知されます。
FirefoxでのHTML5 Notifications API 通知方法
Notification.permissionで現在の権限を見ることができる。
デフォルト状態(ポップアップ表示)なら"default"、許可されていれば"granted"、拒否されていれば"denied"の文字列が返される。
表示が許可されていない場合はNotification.requestPermissionで、権限をリクエストする。こんなポップアップが表示される。
FirefoxでのHTML5 Notifications API 通知方法
FirefoxでのHTML5 Notifications API 通知方法
その後、new Notificationにタイトルとオプションを設定したハッシュを渡す。
ハッシュの中のiconはURLでも良いし、base64の文字列でも良い。
tagを設定すると、デスクトップ通知が多重表示されるのを防げる。
という感じ。
また、new Notificationで得られるインスタンスには、oncloseonclickonerroronshowイベントが登録できる。
onclick時に得られるEventのtargetはNotificationオブジェクトとなっている。
通知クリックで、該当のウィンドウ(タブ)をアクティブ化とかできれば楽しそうだったけど、無理っぽい。

デモ

Firefoxでの HTML5 Notifications (デスクトップ通知) 設定変更方法 - ログろいど
関連記事

2013年1月28日月曜日

Firefox で BFCache によるキャッシュを無効化する方法

発端

Firefox で開発をしていると、サーバのJavaScriptを変更してもFirefoxがキャッシュしているJavaScriptを使用してしまっていたりすることがある。
これがJavaScriptだけならまだCtrl+Shift+Rで強制読み込みさせて回避できるのだが、JSONの戻りまでキャッシュされてしまう事がある。
キャッシュされたリクエストをFirebugのネットタブで表示すると、以下のようになる。
※google.co.jpを表示した例
Firefox で BFCache によるキャッシュを無効化する方法
レスポンスヘッダを見ると、以下のメッセージが
キャッシュから直接リクエストが解決されたため、サーバからのレスポンスはありません。キャッシュされているレスポンスについては下を参照してください。
これは、Firefox 15から搭載されている、BFCache(Back-Forward Cache)という機能によるものだ。
Firefox 1.5 ではウェブページ全体をその JavaScript の状態も含めてメモリ内にキャッシュし、1 つのブラウザセッションとして使用します。訪問したページ間の戻る、進むという動作にページのロードが不要になり、JavaScript の状態も保存されます。この機能によってページナビゲーションが非常に高速化します。この機能は bfcache("Back-Forward Cache" のこと)と呼ばれることもあります。このキャッシュ状態はユーザがブラウザを閉じるまで保存されます。
Firefox がページをキャッシュしない場合があります。ページがキャッシュされないプログラム的な理由でよくあるものをいくつか以下に示します。
  • ページが unload ハンドラを使用している
  • ページが "cache-control: no-store" をセットしている
  • ページが "cache-control: no-cache" をセットしていて、サイトが HTTPS である
  • ページが完全にはロードされないまま、ユーザがそのページから去るナビゲートをする
  • トップレベルのページにキャッシュ不可能なフレームがある
  • ページがフレーム内にあり、ユーザがそのフレーム内に新しいページをロードする(この場合、ユーザがそのページから去るナビゲートをするとそのフレームに最後にロードされたコンテンツがキャッシュされる)
この新しいキャッシュ機能により、ページロードの挙動が変わります。ウェブ作者は次のことをしたいと思うことがあるでしょう。
  • ナビゲートされたことがあるページであることを知ること(そのページがユーザのキャッシュからロードされるとき)
  • ユーザがそのページを去るときのページの挙動を定義すること(ページがキャッシュされるようになっている間)
ブラウザの 2 つの新しいイベントによってウェブ作者はそのどちらもできるようになります。
JSONのレスポンスが保存されるのは、以下の記載によるものであると思われる。
ウェブページの標準的な挙動は次のとおりです。
  1. ユーザがページにナビゲートする。
  2. ページロード時にインラインスクリプトが実行される。
  3. ページがロードされると onload ハンドラが実行される。
4 ステップ目があるページもあります。ページが unload ハンドラを使用していると、ユーザがそのページから去るナビゲートをするときにそれが実行されます。unload ハンドラが存在しているとそのページはキャッシュされません。 ユーザがキャッシュされたページにナビゲートしたとき、インラインスクリプトと onload ハンドラは実行されません(ステップ 2 および 3)。ほとんどの場合、これらのスクリプトの効果が保存されているためです。

BFCache を無効にしてみる

開発を行う上で、JavaScriptや、JavaScriptの結果、JSONがキャッシュされてしまうのはかなり迷惑。
という事でBFCacheを無効にしてみます。
※ブラウジングのパフォーマンスに影響する可能性があるため、開発用のプロファイル等を作成し、そのプロファイルでのみBFCacheを無効にする事をお勧めします。
  1. about:configにアクセスする
  2. network.http.use-cacheと入力する
  3. 値をfalseに設定する
  4. Firefoxを再起動する
Firefox で BFCache によるキャッシュを無効化する方法

確認

google.co.jpにアクセスしてみる。
Firefox で BFCache によるキャッシュを無効化する方法
何回もページをリクエストしてみたが、Firefoxでキャッシュが行われないようになった。
関連記事

2013年1月25日金曜日

[SyntaxHighlighter] JavaScript用Brush

SyntaxHighlighterにデフォルトで入っているBrushに、予約オブジェクトを追加したBrushを作りました。
document.title="hoge";
window.open("http://example.com");
console.info("info message");
location.href="http://example.com";
以下で実際に確認することが可能です。
SyntaxHighlighter用タグ 変換/生成ツール - ログろいど

ダウンロード

共に、3.0.83専用です。
他のバージョンでの動作は未確認です。
非圧縮版(1.80KB)
https://sites.google.com/site/logroid/syntaxhighlighter/shBrushJScript
圧縮版(1.32KB)
https://sites.google.com/site/logroid/syntaxhighlighter/shBrushJScript.min.js
関連記事

[SyntaxHighlighter] jQuery用Brush (jQuery 1.9対応版)

jQuery 1.9対応のSyntaxHighlighter用Brushを作ってみましたので、公開します。
Brushのエイリアスは、jqjqueryです。
このBrushを使うと、jQuery APIが以下のようにハイライトされます。
$(document).ready(function(){
  // #hogeに#fugaを追加
  $('#hoge').append($('<div>').prop('id','fuga').attr('key','bar').text('baz'));
  $('input[type="radio"]:checked').click(
    function(){
      alert($(this).val());
      $('#hogehoge').addBack('.hoge').text($(this).val());
    }
  );
});
jQuery 1.9時点でdeprecated/removedとなったメソッドは色を分けています。
1.9で削除された.live().die()メソッドの例
$('.live').live('click', liveFunction);
$('.live').die('click', liveFunction);
また、deprecated/removedとなっていても、同名のメソッドがdeprecated/removedではない場合は、通常のjQuery APIとしてハイライトされます。
.toggle()メソッドの例
$('.target').toggle();
$('#target').toggle(function() {
  alert('First handler for .toggle() called.');
}, function() {
  alert('Second handler for .toggle() called.');
});
以下で実際に確認することが可能です。
SyntaxHighlighter用タグ 変換/生成ツール - ログろいど

jQuery 1.9でのjQuery APIに対応しています。
1.9以下のバージョンでも正常にハイライトされると思います。
ただし、前述のとおり、jQuery 1.9時点でdeprecated/removedとなったメソッドは色分けされます。

ダウンロード

共に、3.0.83専用です。
他のバージョンでの動作は未確認です。
非圧縮版(4.45KB)
https://sites.google.com/site/logroid/syntaxhighlighter/shBrushJQuery.js
圧縮版(3.30KB)
https://sites.google.com/site/logroid/syntaxhighlighter/shBrushJQuery.min.js
関連記事

2013年1月24日木曜日

jQuery 1.9に移行してハマったこと

jQuery 1.9へのアップグレードガイドはこちら (英語)
jQuery Core 1.9 Upgrade Guide | jQuery
http://stage.jquery.com/upgrade-guide/1.9/ そのうち(機械翻訳を駆使して)翻訳するかもしれません。

TypeError: $(...).live is not a function

jQuery 1.9では.live()が削除されている。同じように、.die()も削除されている。
.live()を、jQuery 1.9で使用しようとすると、以下のようなエラーが出力される。
TypeError: $(...).live is not a function
.live().on()に、.die().off()にそれぞれ置き換えられている。
以下のように書き直すことで、1.9へ移行する事ができる。
$('.live').live('click', liveFunction);
$('.live').die('click', liveFunction);
$(document).on('click', '.live', liveFunction);
$(document).off('click', '.live', liveFunction);

Error: Syntax error, unrecognized expression

$()にHTML文字列を渡して解析していたのだが、jQuery 1.9ではエラーになった。
jQuery 1.9からは、$()に渡す文字列の最初が<以外の場合はセレクタとしてみなされるようになったためだ。
HTML文字列が<で始まっていない場合、以下のようなエラーが出力される。
Error: Syntax error, unrecognized expression:
この場合、$.parseHTML()を用いることで解析することが出来る。
以下のように書き直すことで、1.9へ移行する事ができる。
var html_string_1="<div>hoge</div>",
html_string_2=" <div>HOGE<div>FUGA</div></div>";
console.dirxml($(html_string_1).get(0));
console.dirxml($(html_string_2).get(0));
var html_string_1="<div>hoge</div>",
html_string_2=" <div>HOGE<div>FUGA</div></div>";
console.dirxml($($.parseHTML(html_string_1)).get(0));
console.dirxml($($.parseHTML(html_string_2)).get(0));
あれ、思ったような結果にならない・・・
という事でこんな感じにしました。
var html_string_1="<div>hoge</div>",
html_string_2=" <div>HOGE<div>FUGA</div></div>";
console.dirxml($($.parseHTML(html_string_1)).get(0));
console.dirxml($($.parseHTML(html_string_2.trim())).get(0));
または
var html_string_1="<div>hoge</div>",
html_string_2=" <div>HOGE<div>FUGA</div></div>";
console.dirxml($($.parseHTML(html_string_1)).get(0));
console.dirxml($($.parseHTML(html_string_2.replace(/^[^<]+/,''))).get(0));
もうちょっと調べる必要があるな・・・
関連記事

2012年12月28日金曜日

JavaScript用 複数行文字列 → 文字列配列 変換ツール

JavaScript向けに、複数行文字列を文字列配列に変換するツールを作りました。

変換サンプル

#gbx3, #gbx4 {
    background-color: #2D2D2D;
    background-image: none;
    background-position: 0 -138px;
    background-repeat: repeat-x;
    border-bottom: 1px solid #000000;
    font-size: 24px;
    height: 29px;
    opacity: 1;
    position: absolute;
    top: 0;
    width: 100%;
    z-index: 990;
}
.gbtb .gbts {
    background: url("//ssl.gstatic.com/gb/images/b_8d5afc09.png") repeat scroll -27px -22px transparent;
    border: 0 none;
    font-size: 0;
    padding: 29px 0 0;
    width: 1px;
}
.gbtb .gbts {
    background: url('//ssl.gstatic.com/gb/images/b_8d5afc09.png') repeat scroll -27px -22px transparent;
    border: 0 none;
    font-size: 0;
    padding: 29px 0 0;
    width: 1px;
}
['#gbx3, #gbx4 {',
'background-color: #2D2D2D;',
'background-image: none;',
'background-position: 0 -138px;',
'background-repeat: repeat-x;',
'border-bottom: 1px solid #000000;',
'font-size: 24px;',
'height: 29px;',
'opacity: 1;',
'position: absolute;',
'top: 0;',
'width: 100%;',
'z-index: 990;',
'}',
'.gbtb .gbts {',
'background: url("//ssl.gstatic.com/gb/images/b_8d5afc09.png") repeat scroll -27px -22px transparent;',
'border: 0 none;',
'font-size: 0;',
'padding: 29px 0 0;',
'width: 1px;',
'}',
'.gbtb .gbts {',
'background: url(\'//ssl.gstatic.com/gb/images/b_8d5afc09.png\') repeat scroll -27px -22px transparent;',
'border: 0 none;',
'font-size: 0;',
'padding: 29px 0 0;',
'width: 1px;',
'}'];

変換ツール



関連記事

2012年11月20日火曜日

ブラウザごとの閉じられたウィンドウオブジェクトの違い

window.openでウィンドウを開き、開いたウィンドウを閉じた場合、ブラウザによって閉じたウィンドウオブジェクトに対する処理が異なっていた。
リファレンス等に書かれていないようなので、メモ。
具体的には、以下のような処理を行った際の結果が異なる。
var wo = window.open("about:blank","hoge");

開いたウィンドウを閉じる
alert(typeof wo.name);

検証プログラム

以下で、実際の動きを確認できます。
ウィンドウチェックを行うと、テキストボックス内に、windowのステータスがdumpされます。

Internet Explorer 9の場合

閉じられたウィンドウのnameプロパティにアクセスしようとすると、エラーが発生する。
アクセスが拒否されました。
エラーnumberは-2147024891
閉じられたウィンドウオブジェクトのnameプロパティにはアクセスできないようだ。

Mozilla Firefox 17の場合

閉じられたウィンドウのnameプロパティの値はnullオブジェクトとなる。

Google Chrome 23の場合

閉じられたウィンドウのnameプロパティの値はstringオブジェクトとなる。
stringの値は""だった。

Opera 12の場合

閉じられたウィンドウのnameプロパティの値はstringオブジェクトとなる。
stringの値は""だった。
と、まぁ気にしない人にはどうでもいい情報でした。
関連記事

2012年10月17日水曜日

Firefox での CDATA の扱い

Firefox 17 beta1 に更新したところ、とあるGreasemonkeyスクリプトが動かなくなった。
スクリプト内部で使用している、CDATAが、Firefox 17ではsyntax errorとなっていた。
警告: E4X は非推奨となりました。 この機能は、Firefox 16 において content 向けにはデフォルトで無効となり、Firefox 17 では chrome 向けにもデフォルトで無効となる予定です。 そして、Firefox 18 において削除される予定となっています。 代わりに、DOMParser/DOMSerializer や非ネイティブの JXON アルゴリズムを使用してください。
JavaScript
E4X が無効化されました

 Bug 778851 – Turn javascript.options.xml.content off by default

ECMAScript for XML (E4X) は非推奨となり、Firefox 17 で無効化されました。隠し設定 javascript.options.xml.content の値を true に変更すれば有効になりますが、Firefox 18 Firefox の近い将来のバージョン (当初 Firefox 18 とされていましたが現状未定のようです) では実装そのものが完全に削除される予定です。
Firefox 17 のサイト互換性に関わる修正のまとめ | Mozilla Developer Street (modest)
https://dev.mozilla.jp/2012/10/firefox-17-site-compatibility/
これによると、ECMAScript for XML (E4X) は、Firefox 17ではデフォルトで無効、Firefox 18で削除予定らしい。
about:configで有効にできるみたいですけど、一時しのぎにしかならないな。
Greasemonkeyのページにも書いてあった。
E4X is deprecated. It will stop working in phases, Firefox 16 through 18.
Multi Line Strings - GreaseSpot Wiki
http://wiki.greasespot.net/Multi_Line_Strings
こうなると、CDATAで実装していたようなヒアドキュメントをJavaScriptで実装する手段が無いな・・・。
ということで、CDATAを文字列の配列に変換するスクリプトを作りました。
詳しくは以下のページを参照ください。

JavaScript内の CDATA → 文字列配列 変換スクリプト - ログろいど

しかし、これからGreasemonkey内にスタイルシート埋め込む時の手間が増えるな・・・。
何かいい方法無いだろうか。
その後
SpiderMonkey から E4X サポートが削除されました。
Firefox 21 ベータ版リリースノート
http://www.mozilla.jp/firefox/21.0/releasenotes/
Firefox 21で正式に削除となるようです。
関連記事

JavaScript内の CDATA → 文字列配列 変換ツール

Firefox 17から無効となるE4X
Greasemonkeyスクリプト内でCDATAを使用している方も多いと思います。(私もその一人でした)
そんな方のために、CDATAを文字列の配列に変換するスクリプトを作りました。

変換サンプル

var hoge=<><![CDATA[
<pre class="hoge" id='fuga'>
  hoge
</pre>
]]></>.toString();

var fuga=<><![CDATA[<pre class="hogehoge" id='fugafuga'>
  fuga
</pre>]]></>;

var fuga=<><![CDATA[<pre class="bar" id='bar'>bar</pre>]]></>.toString();
var hoge=['<pre class="hoge" id=\'fuga\'>',
'  hoge',
'</pre>'].join("\n");
 
var fuga=['<pre class="hogehoge" id=\'fugafuga\'>',
'  fuga',
'</pre>'].join("\n");
 
var fuga='<pre class="bar" id=\'bar\'>bar</pre>';

変換ツール



関連記事

2012年9月26日水曜日

[Eclipse] PhoneGap で Android アプリ開発

面白そうな記事を見つけたので、早速試してみる。
なんでもHTML、JavaScript、CSSでAndroidアプリが作れるそうだ。
Adobeいつのまにこんなフレームワーク作ってたんだ・・・
Eclipse×PhoneGapでAndroidアプリ開発! ~インストールからアプリ実行まで (1/3):CodeZine
http://codezine.jp/article/detail/6687
Apache Cordova API Documentation
http://docs.phonegap.com/en/2.1.0/guide_getting-started_android_index.md.html#Getting Started with Android

PhoneGapの準備

以下のページからPhoneGapをダウンロード。
PhoneGap | Download & Archives
http://www.phonegap.com/download 現時点で最新の 2.1.0 をダウンロードしました。
ダウンロード後、解凍しておきます。

プロジェクトの作成

Androidプロジェクトを新規に作ります。
PhoneGap で Android アプリ開発
ここでは、2.3.3をターゲットとしてプロジェクトを作りました。
テストプロジェクトなのでCreate custom launcher iconのチェックは外します。
PhoneGap で Android アプリ開発
BlankActivityを作成します。
PhoneGap で Android アプリ開発
後は適当に。

PhoneGapインストール

PhoneGap で Android アプリ開発
プロジェクトのassetsディレクトリ内にwwwフォルダを作成します。
また、libsフォルダが無い場合は新規に作成します。
PhoneGap で Android アプリ開発
PhoneGapのlib/android/cordova-2.1.0.jsassets/wwwディレクトリにコピーします。
lib/android/cordova-2.1.0.jarlibsディレクトリにコピーします。
lib/android/xmlディレクトリをresディレクトリにコピーします。
libs配下に追加したcordova-2.1.0.jarをビルドパスに追加するため、libs/cordova-2.1.0.jarを右クリックし、ビルド・パス->ビルド・パスに追加を行います。

アプリの作成

PhoneGap で Android アプリ開発
index.htmlをwwwディレクトリ配下に作成。
Webサイトと同じように、このファイルがアプリのトップ画面になるようだ。
index.htmlに書くコードは以下。
<!DOCTYPE HTML>
<html>
  <head>
    <title>PhoneGap</title>
    <script type="text/javascript" charset="utf8" src="cordova-2.1.0.js"></script>
  </head>
  <body>
    <h1>Hello PhoneGap</h1>
  </body>
</html>
Activityファイルを開き、以下のように変更します。
package jp.blogspot.logroid.phonegap.test;

import org.apache.cordova.DroidGap;

import android.os.Bundle;

public class MainActivity extends DroidGap {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 super.loadUrl("file:///android_asset/www/index.html");
    }

}

メタデータ修正

AndroidManifest.xmlファイルを開き、以下のように変更します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.blogspot.logroid.phonegap.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="15" />

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:resizeable="true"
        android:smallScreens="true" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            configChanges="orientation|keyboardHidden"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

実行

PhoneGap で Android アプリ開発
なかなか簡単に実行までできました。
本格的にJavaScript、CSS使ったアプリも作ってみたいと思います。
関連記事

2012年9月18日火曜日

[SyntaxHighlighter] Greasemonkey用Brush

Greasemonkey用のBrushを作ってみましたので、公開します。
Brushのエイリアスは、gmgreasemonkeyです。
このBrushを使うと、Greasemonkey APIが以下のようにハイライトされます。
GM_xmlhttpRequest({
  method: 'GET',
  url: 'http://www.google.co.jp/',
  timeout: 5000,
  onload: function(r){
    GM_addStyle(<><![CDATA[
#hoge {
  color: #CCC;
}
]]></>.toString());
    GM_log( GM_info.script.version +"\n"+r.responseText );
  }
});
以下で実際に確認することが可能です。
SyntaxHighlighter用タグ 変換/生成ツール - ログろいど

ダウンロード

共に、3.0.83専用です。
他のバージョンでの動作は未確認です。
非圧縮版(2.00KB)
https://sites.google.com/site/logroid/syntaxhighlighter/shBrushGreasemonkey.js
圧縮版(1.06KB)
https://sites.google.com/site/logroid/syntaxhighlighter/shBrushGreasemonkey.min.js
関連記事

[Greasemonkey] timeout と synchronous の関係について

先日の記事で、GM_xmlhttpRequesttimeoutパラメタを指定したらエラーを吐いた件で、詳細を調査してみました。

検証スクリプト

GM_xmlhttpRequestのみを実行するスクリプトを組んだ。
こんな感じ。
// ==UserScript==
// @name        GM_xmlhttpRequest Test
// @namespace   http://logroid.blogspot.jp/
// @version     1
// @description GM_xmlhttpRequest 検証スクリプト
// @include     http://127.0.0.1/*
// @include     http://127.0.0.1:*/*
// @grant       GM_log
// @grant       GM_xmlhttpRequest
// ==/UserScript==
GM_xmlhttpRequest({
  method: 'GET',
  url: 'http://www.google.co.jp/',
  timeout: 5000,
  onload: function(r){
    GM_log("synchronous:false\n"+r.responseText);
  }
});
GM_xmlhttpRequest({
  method: 'GET',
  url: 'http://www.google.co.jp/',
  timeout: 5000,
  synchronous:true,
  onload: function(r){
    GM_log("synchronous:true\n"+r.responseText);
  }
});

実行

スクリプトをインストールし、実行した。
成功すればGoogleのトップのHTMLソースがコンソールに出力されるはず。
synchronous:falseになっているGM_xmlhttpRequestは成功した。
しかし、synchronous:trueになっているGM_xmlhttpRequestでは以下のエラーが出力された。
エラー: A parameter or an operation is not supported by the underlying object
ソースファイル: file:///C:/Users/hoge/AppData/Roaming/Mozilla/Firefox/Profiles/hoge/gm_scripts/GM_xmlhttpRequest_Test/gm_xmlhttprequest_test.user.js
行: 96

検証結果

どうやら、GM_xmlhttpRequestのtimeoutはsynchronousがfalseの場合のみ有効なパラメタであるようです。
ただし、リファレンスを見ても、そのようなことは記載されていませんでした。
エラーメッセージから推測するとFirefoxが出していると思うので、Greasemonkeyではなく、Firefox側の制限であると考えられます。
synchronous
Boolean (Compatibility: 0.9.9+) When true, this is a synchronous request. Be careful: The entire Firefox UI will be locked and frozen until the request completes. In this mode, more data will be available in the return value.
timeout
Number (Compatibility: Greasemonkey 1.0+, Firefox 12) The number of milliseconds to wait before terminating the call; zero (the default) means wait forever.
GM_xmlhttpRequest - GreaseSpot Wiki
http://wiki.greasespot.net/GM_xmlhttpRequest
ちなみにtimeoutの実装が行われたコミットログは以下。
Allow timeout option for GM_xmlhttpRequest. · b4ecc6f · arantius/greasemonkey · GitHub
https://github.com/arantius/greasemonkey/commit/b4ecc6ff731ec9e38402fb46a3c7343908896828 こちらにも何も書かれていません。
とりあえずtimeout使いたいときはsynchronousfalseにすればいいという事がわかったので良しとするか。
関連記事

2012年8月26日日曜日

Greasemonkey 1.0 リリース

ついに、Greasemonkey 1.0 がリリースされました。
やっと安定版というところでしょうか。
Greasespot: Greasemonkey 1.0 Release
http://www.greasespot.net/2012/08/greasemonkey-10-release.html 1.0での主な変更点は、@grantという権限パラメタがMetaブロックに追加されています。
スクリプト内で使用しているGM_関数を、あらかじめ@grantで宣言しなければいけないようです。
Greasemonkey 1.0 adds a special Metadata Block imperative: @grant. As of version 1.0:

 If a script does not specify any @grant values, Greasemonkey will attempt to auto-detect the right settings.
 If a script specifies any values (or they have been auto detected), then it will be provided with only those API methods that it declares.
 The valid values are the names of those GM_ prefixed values that you wish your script to be granted access to. 
 Otherwise the script will be granted no special API privileges, and thus run without the security constraints Greasemonkey scripts have traditionally had. If you want your script to operate in this mode, you should explicitly declare @grant none.
@grant - GreaseSpot Wiki
http://wiki.greasespot.net/@grant
@grantの追記は大きな手間ではなかったのですが、1.0にすると以下のエラーが出るようになりました。
なお、@grantにGM_xmlhttpRequestは追記済みです。
[Exception... "A parameter or an operation is not supported by the underlying object"  code: "15" nsresult: "0x8053000f (InvalidAccessError)"  location: "chrome://greasemonkey/content/xmlhttprequester.js Line: 86"]
ちなみに、xmlhttprequester.jsの該当行は以下。
// this function is intended to be called in chrome's security context, so
// that it can access other domains without security warning
GM_xmlhttpRequester.prototype.chromeStartRequest =
function(safeUrl, details, req) {
  this.setupReferer(details, req);

  var setupRequestEvent = GM_util.hitch(this, 'setupRequestEvent', this.wrappedContentWin);

  setupRequestEvent(req, "abort", details);
  setupRequestEvent(req, "error", details);
  setupRequestEvent(req, "load", details);
  setupRequestEvent(req, "progress", details);
  setupRequestEvent(req, "readystatechange", details);
  setupRequestEvent(req, "timeout", details);
  if (details.upload) {
    setupRequestEvent(req.upload, "abort", details.upload);
    setupRequestEvent(req.upload, "error", details.upload);
    setupRequestEvent(req.upload, "load", details.upload);
    setupRequestEvent(req.upload, "progress", details.upload);
  }

  req.mozBackgroundRequest = !!details.mozBackgroundRequest;

  req.open(details.method, safeUrl,
      !details.synchronous, details.user || "", details.password || "");

  if (details.overrideMimeType) {
    req.overrideMimeType(details.overrideMimeType);
  }
  if (details.timeout) {
    req.timeout = details.timeout;
  }

  if (details.headers) {
    var headers = details.headers;

    for (var prop in headers) {
      if (Object.prototype.hasOwnProperty.call(headers, prop)) {
        req.setRequestHeader(prop, headers[prop]);
      }
    }
  }
どうやらGM_xmlhttpRequestのtimeoutパラメタが悪さしているみたい。
ということで、一時的にGM_xmlhttpRequestのtimeoutパラメタをコメントアウトすることで回避できました。
ちなみに以下のページから、0.9系をインストールして確認すると、上記のようなエラーは出ませんでした。
おそらく、1.0でのバグだと考えられます。
Greasemonkey :: Versions :: Add-ons for Firefox
https://addons.mozilla.org/ja/firefox/addon/greasemonkey/versions/ ちなみに、@grantを設定していないスクリプトで表示される警告メッセージはabout:configのgreasemonkey.showGrantsWarningをfalseにすることで、表示しないようにすることが出来るようです。

後日談

timeoutを設定した際にエラーを吐いた件は使い方がまずかったみたい。
[Greasemonkey] timeout と synchronous の関係について - ログろいど
関連記事

2012年8月16日木曜日

[JavaScript] ログ出力ライブラリ (console へ 出力レベル機能を追加)

作成に至る発端

Log4js もあるが、ほとんどデバッグ目的のログ出力なので、console.assertconsole.dir、可変長引数の console.log で出力する事が多い。
文字列のみを出力する Log4js はオブジェクトや、XMLの出力において、console での出力に圧倒的に劣る。
また、Log4js自体のファイルサイズも大きい。
しかし、console は、ログ出力レベルを指定して出力をコントロールするといった機能が無い。
そんな事を考えていると、以下の記事が目に入り、ライブラリを作るかという事になった。
console.log は長くてつらい #JavaScript - Qiita
http://qiita.com/items/6f2ae599207fa9af323a

挫折

難しくないだろうと、こんなコードを書いた。
var LoggerLevel={
  ALL:-99,
  DEBUG:-1,
  INFO:0,
  WARN:1,
  ERROR:2,
  OFF:99
},
self=null;
var Logger=function(level){
  self=this;
  self.level=isNaN(level) ? LoggerLevel.INFO : level;
};
for(var key in console){
  var level=LoggerLevel[key.toUpperCase()];
  if(!level){level=99};
  (
    function(k,l){
      Logger.prototype[k]=function(){
        self=this;
        if(self.level<=l){
          return console[k].apply(console, arguments);
        }
      }
    }
  )(key, level);
};
こんな感じで実行する。
var logger=new Logger(LoggerLevel.INFO);
logger.debug("debugメッセージ");
logger.info("infoメッセージ");
logger.warn("warnメッセージ");
logger.error("errorメッセージ");
logger.dir([1,2,3,4,5]);
ブラウザのコンソールを確認すると、うまく出力されているようだ。
ん・・・コンソールに表示される、どこでログ出力が呼ばれたかという行番号が、logger.js の console[k].apply の行番号になっている。
本当は、logger.info等を実行している行番号が出てほしいんだけど・・・。
これじゃデバッグが不便になるな。
うむ~まいった。
なやんでいると、こんな記事を見つけた。
console.logのエイリアス - hokaccha.hamalog v2
http://d.hatena.ne.jp/hokaccha/20111216/1324026093 bindね。
これを使うと、bindされたファンクションを、コンストラクタとして扱えるようになるという事。
bind | Mozilla Developer Network
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind

そして完成

bindを使い、以下のように書き直した。
var LoggerLevel={
  ALL:-99,
  DEBUG:-1,
  INFO:0,
  WARN:1,
  ERROR:2,
  OFF:99
},
self=null;
var Logger=function(level){
  self=this;
  self.level=isNaN(level) ? LoggerLevel.INFO : level;
};
for(var key in console){
  var level=LoggerLevel[key.toUpperCase()];
  if(!level){level=99};
  Logger.prototype[key]=(
    function(k,l){
      self=this;
      if(self.level<=l){
        if(Function.bind){
          return console[k].bind(console);
        }else{
          return console[k].apply(console, arguments);
        }
      }
    }
  )(key, level);
};
先ほどと同じように実行してみる。
今度は、ちゃんと呼び出し元のファイル名、行番号でコンソールに出力された。
めでたしめでたし。

ちょっと修正

上のコードでも問題ないんだけど、ちょっと見直し。
ログ出力の度いちいちFunction.bindを判定するのもなぁ・・・と思ったので以下のようにした。
var LoggerLevel={
  ALL:-99,
  DEBUG:-1,
  INFO:0,
  WARN:1,
  ERROR:2,
  OFF:99
},
self=null;
var Logger=function(level){
  self=this;
  self.level=isNaN(level) ? LoggerLevel.INFO : level;
};
for(var key in console){
  var level=LoggerLevel[key.toUpperCase()];
  if(!level){level=LoggerLevel.OFF};
  if(Function.bind){
    Logger.prototype[key]=(
      function(k,l){
        self=this;
        if(self.level<=l){
          return console[k].bind(console);
        }
      }
    )(key, level);
  }else{
    Logger.prototype[key]=(
      function(k,l){
        self=this;
        if(self.level<=l){
          return console[k].apply(console, arguments);
        }
      }
    )(key, level);
  }
};
Loggerのprototypeを作る際にあらかじめ判定するようにしてみた。
console.timeとか使った際に、判定が入ることによる誤差を無くすための処置。

更に修正

var LoggerLevel={
  ALL:-99,
  DEBUG:-1,
  INFO:0,
  WARN:1,
  ERROR:2,
  OFF:99
};
var Logger=function(level){
  var self=this;
  self.level=isNaN(level) ? LoggerLevel.INFO : level;
  self.make();
};
Logger.prototype.make=function(){
  var self=this;
  for(var key in console){
    var l=LoggerLevel[key.toUpperCase()];
    if(!l){l=LoggerLevel.OFF};
    if(self.level<=l){
      if(Function.bind){
        Logger.prototype[key]=(
          function(k){
            return console[k].bind(console);
          }
        )(key);
      }else{
        Logger.prototype[key]=(
          function(k){
            return console[k].apply(console, arguments);
          }
        )(key);
      }
    }else{
      Logger.prototype[key]=function(){};
    }
  }
};
さらに無駄な処理を省いた
一応最終版。

ダウンロード

非圧縮版(915B)
https://sites.google.com/site/logroid/files/logger.js
圧縮版(661B)
https://sites.google.com/site/logroid/files/logger.min.js
関連記事

2012年8月11日土曜日

[JavaScript] 正規表現はコンパイルしたほうが処理速度が速いのか?

今までJavaScriptにおいて、正規表現は使い捨ての正規表現を除いてコンパイルした方が早いと思っていました。
そして、コンパイルした方が早いのか確認するためのベンチマークツールを作ってみました。
チェックツールは以下から利用できます。
[JavaScript] ベンチマークツール - ログろいど
なんと、Firefox、Chromeではコンパイルした方が遅い。
Firefoxでは、コンパイルした場合と、しない場合の差は大きくないが、Chromeでは大きな差が出ました。
ちなみに、Firefoxで指定しているJavaScript JITコンパイラは JaegerMonkey。
私の実行環境はこんな感じ。
OS Windows 7 Professional Service Pack 1 32bit
CPU Intel Core i5 M 560 2.67GHz
RAM 2GB
テストコードは以下。
パターン1
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
パターン2
var r=new RegExp();
r.compile("h","g");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
パターン3
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
"hogehogehogehogehoge".replace(/h/g,"H");
パターン4
var r=new RegExp();
r.compile("h","g");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
"hogehogehogehogehoge".replace(r,"H");
確認を行ったのは以下のブラウザ。
  • Mozilla Firefox 14,15,16.17
  • Google Chrome 21
  • Windows Internet Explorer 9
このうち、IE9のみ、パターン4ではコンパイルした方が早いという結果になりました。
皆さんもチェックツールの結果をお教えください。
以下のリンクを開くと、上記のテストコードが入力された状態で開きます。
[JavaScript] ベンチマークツール - ログろいど
関連記事

[JavaScript] ベンチマークツール

JavaScriptのベンチマークを確認できます。
ベンチマーク結果は別ウィンドウで開くので、ポップアップを許可してください。
動作確認ブラウザ
  • Mozilla Firefox 14,15,16.17
  • Google Chrome 21
  • Windows Internet Explorer 9
基本情報

1セットでの実行回数

セット数

jQuery


jQueryのバージョンは、1と指定した場合、1系の最新が使用され、1.7と指定した場合、1.7系の最新が使用されます。
パターン
関連記事

2012年8月1日水曜日

IE8ではIE7互換モード、IE9は標準でレンダリングさせる方法

私は Internet Explorer が嫌いだ。
IE9になっても、まともにサポートされないHTML5。
という事で、このサイトはIEでの動作確認をあまり行っていない。
また、これまで、以下のMETAタグをヘッダに挿入し、強制的にIE7互換モードでレンダリングするようにしてきた。
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"/>
これが無いと、IE8でまともに表示されない。
IE9まではこれで良かった。
IE9になり、CSSのサポートがマシになってきたので、IE8はIE7互換モード、IE9は標準でレンダリングさせたいと思い、調べていると以下のブログを見つけた。
Bloggerのカスタマイズでお馴染み、クリボウさんのブログ。
Internet Explorer でレイアウトが崩れる Blogger テンプレートは、IE 7 互換モードのタグを削除してみるといいかも | クリボウの Blogger Tips
http://www.kuribo.info/2012/07/blogger-ie7-compatibility-tag.html
IE9のブラウザーモードとドキュメントモード - hachy.net
http://www.hachy.net/2010/08/ie9.html 複数指定できるなんて知らなかった。
という事で、METAタグを以下のように書き換えてみた。
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7; IE=EmulateIE9"/>
これで、IE8はIE7互換モード、IE9は標準でレンダリングされるハズ。
関連記事