2010-02-01

KAYACモバゲー参入に伴いAmazon Web Serviceと格闘中のagoです。

弊社ではPC版mixiアプリもいくつか作成しておりますが、今回そこで得られたノウハウを集めてmixiアプリ フレームワークを公開しました。

ソースコード github

opensocialに関しては過去にjquery.opensocial-simple.jsを公開しておりますが、社内からも「JSなしでmixi appを作りたい」と言う要望もあり、今回frameworkの形で公開いたしました。

コンセプト

JSを書かなくてもそこそこリッチなmixi appが作れるフレームワーク

機能

  • OWNER、VIEWER情報の取得
  • マイミク情報の取得
  • 指定mixi IDユーザ情報の取得
  • 画面遷移の制御
  • 表示領域の自動調整
  • 「日記に書く」リンクの自動設定
  • アクティビティの発行
  • 「友達を誘う」機能の追加

詳細はgithubをご覧ください。

ソースコード github

カヤックではフレームワークを造ることが好きな技術者を募集しています!

2010-01-25

時が経つのは早いもので、ぼーとしてたらもう1月も終わりそうですね。外村です。

先日リリースされたjQuery1.4で新しく追加されたメソッドや新しい使い方ができるようになった機能を全部ではないですがいくつか紹介します。以下に変更点が全て掲載されているのでそちらも参照するといいと思います。

Version 1.4 – jQuery API

新規で追加されたメソッド

1. nextUntil()、prevUntil()、parentsUntil()

指定したセレクタまでの要素を返します。以下の例ではitem3とitem4の後ろにテキストが追加されます。

<ul>  
    <li id="item1">item1</li>  
    <li id="item2">item2</li>  
    <li id="item3">item3</li>  
    <li id="item4">item4</li>  
    <li id="item5">item5</li>
</ul>

$('#item2').nextUntil('#item5').append('[foo]');

nextUntil()は後方、prevUntil()は前方、parentsUntil()だと親要素を探します。

2. delay()

指定の時間処理を遅らせます。アニメーションの途中などに挟んで使うようです。下記のようにするとsilidUpとfadeInのあいだに1000ms時間が空きます。

$('#foo').slideUp(300).delay(1000).fadeIn(400);

.delay() – jQuery API

3. has()

指定したセレクタの要素がるかどうかを調べます。セレクタが存在したら元のjQueryオブジェクトを返します。

以下のようにした場合、#fooの子要素にli.barがあった場合#fooにbazというclassが追加されます。li.barにつくのではないというのがポイントです。

$('#foo').has('li.bar').addClass('baz');

.has() – jQuery API

4. unwrap()

親要素を削除します。wrap()の反対ですね。

$('#foo').unwrap();

.unwrap() – jQuery API

5. detach()

要素を削除します。remove()と同じような感じですが、remove()と違うのはイベントや$.dataは残るということです。

以下の例ではdetach()を使っているので、DOM要素は削除されますが、detachする前に設定したイベントや$.dataにデータは残っています。

var $div = $('#foo');
var div = $div.get(0);

$div.click(function() { alert('foo') });
$.data(div, 'foo', 'bar');

$div.detach();
$('#hoge').append($div); // => 再度追加してもクリックイベントは残ってる
console.log( $.data(div, 'foo') ); // => bar

.detach() – jQuery API

6. focusin()、focusout()

focusin、focusoutというイベントが新規で追加されています。基本的には以前のfocusとblurと同じようなものですが、focus、blurと違うところは指定した要素だけでなく、子要素にもイベントが適用されるというところのようです。

<div id="foo">
    <input type="text" />
    <input type="text" />
</div>

$('#foo')
    .focusin(function() {
        // focus時の処理
    })
    .focusout(function() {
        // focusout時の処理
    });

7. first()、last()

first()は最初の要素、last()は最後の要素を返します。セレクタの指定で:first-child、:last-childとつけるのと同等ですね。

<ul id="foo">
    <li id="item1">list1</li>
    <li id="item2">list2</li>
    <li id="item3">list3</li>
    <li id="item4">list4</li>
    <li id="item5">list5</li>
</ul>

console.log( $('#foo li').first().attr('id') ); // => item1
console.log( $('#foo li').last().attr('id') );  // => item5

8. toArray()

jQueryオブジェクトを配列にして返します。get()と等価で、get()を引数なしで呼ぶと内部ではtoArray()が呼ばれているようです。get()よりもこっちのほうが直感的でいいですね。

<ul id="foo">
    <li id="item1">list1</li>
    <li id="item2">list2</li>
    <li id="item3">list3</li>
    <li id="item4">list4</li>
    <li id="item5">list5</li>
</ul>

console.log( $('#foo li').toArray() ); // =>  [li#item1, li#item2, li#item3, li#item4, li#item5]

.toArray() – jQuery API

9. $.proxy()

例えば以下の様なコードがあったときに、click時に呼ばれるclickHandlerメソッドのthis.nameのthisは#fooになってしまうので、this.nameはundefinedになっていしまいます。

var app = {
    name: 'app name',
    clickHandler: function() {
        alert( this.name + ' clicked.' );
    }
};

$('#foo').click(app.clickHandler);

そこで$.proxyを使って以下のように書くととclickHandlerメソッドのthisをappとして扱うことができます。

$('#foo').click( $.proxy(app, 'clickHandler') );

もしくは

$('#foo').click( $.proxy(app.clickHandler, app) );

のどちらでも同じように動作します。

jQuery.proxy() – jQuery API

10. $.isEmptyObject()、$.isPlainObject()

空のオブジェクトか判定するメソッドとオブジェクトかどうかを判定するメソッドが追加されています。挙動は以下のようになるようです。

$.isEmptyObject({});          //=> true
$.isEmptyObject([]);          //=> true
$.isEmptyObject('');          //=> true
$.isEmptyObject(0);           //=> true
$.isEmptyObject(null);        //=> true
$.isEmptyObject(undefined);   //=> true
$.isEmptyObject('foo');       //=> false
$.isEmptyObject({foo:'bar'}); //=> false
$.isEmptyObject(new Object);  //=> true

$.isPlainObject({});          //=> true
$.isPlainObject([]);          //=> false
$.isPlainObject('');          //=> false
$.isPlainObject(0);           //=> false
$.isPlainObject(null);        //=> false
$.isPlainObject(undefined);   //=> false
$.isPlainObject('foo');       //=> false
$.isPlainObject({foo:'bar'}); //=> true
$.isPlainObject(new Object);  //=> true

新しい使い方ができるようになったメソッド

11. bind()で複数イベントをまとめて指定

bind()にオブジェクトを指定することで複数のイベントをbindできるようになっています。

$('#foo').bind({
    click: function() {
        // click event
    },
    mouseover: function() {
        // mouseover event
    },
    mouseout: function() {
        // mouseout event
    }
});

.bind() – jQuery API

12. animate()でプロパティ毎にeasing

animate()のeasingが以下の様にプロパティ毎に設定できるようになっています。これで複雑なアニメーションがより簡単に定義できそうですね。

$('#foo').animate({
   left: 500,
   top: [500, 'linear']
}, 1000);

.animate() – jQuery API

13. live()が全イベントに対応

以前までのバージョンのlive()はsubmitやfocusなど、対応してないないイベントもありましたが、今回全てのイベントに対応したようです。ただしfocus、blurはfocusin、focusoutを指定する必要があります。

$('.input-text').live('focusin', function() {
    // focus時のイベント
});

.live() – jQuery API

14. append()やcss()にfunctionを指定

append()などのDOM操作系のメソッド全般にfunctionが指定できるようになっています。これでどういうことができるようになったかというと、以下のようにthisで自分の要素を取れたり

$('#foo').append(function() {
    return $(this).hasClass('hoge') ? 'hoge' : 'fuga';
});

引数にインデックスと値をとるので、以下のような処理も書けけるようになっています。

$('#foo li').css('color', function(i, val) {
    return i % 2 ? 'red' : 'blue';  
});

以上です。新しい機能だけでなく1.4では速度も劇的に速くなっているようなのでぜひ使ってみるといいと思います。

kayacでは新しいものにすぐに飛びつくミーハーなプログラマも募集しています!

2010-01-22

最近ロフトで買った立体型のアイマスクが個人的にヒットでした。agoです。

今日はgoogle map api+IE6で「未知の実行時エラーです。」が出る場合の対応をご紹介したいと思います。

まず、IE6の場合、一部の要素のinnerHTMLが書き換え不可になっており、他のブラウザと同じようにinnerHTMLで内容を書き換えられない場合があります。

私が遭遇した状況では<p>に追加しようとしたためエラーになっていたのですが、他にもhtmlの文法上<div>を追加できない要素に対してnew GMap2を行うのは問題となるかもしれません。

他の状況であれば問題となる箇所の切り分けも楽なのですが、後々また「google map api "未知の実行時エラーです"」的な検索をしそうなのでエントリにしてみました。

カヤックではアイマスクにこだわりを持つ技術者も募集しています!

2009-12-22

週末料理をしていて足を切ってしまいました。agoです。

以前Perlは書いていたんですが、その頃以下の記事を読んで非常に感銘を受けました。

Perlプログラマのレベル10 - Perlプログラミング救命病棟より - naoyaのはてなダイアリー

当時あまりコミュニティとのつきあいがなかったので、「自分のスキルの絶対位置」、「次のレベルへ行くために必要なもの」を知ることで非常に安心感を感じた記憶があります。

いま確認したところ、「JavaScriptプログラマのレベル10」はないようなので書いてみました。


レベル0 : JavaScriptがプログラミング言語だと言うことは知っているが、JavaとJavaScriptの区別が付かない。
(Webプログラマの自己紹介を聞いて)「Javaやってるんだ?」

レベル1 : 「JS」がJavaScriptの略称であることを知っている。JavaScriptはWeb Siteを作成するための言語と理解しており、alertやチカチカしたものはJavaScriptで作られたと思っている。自分でコードを記述することは出来ないが、Dreamweaver等が埋め込んだコードを壊すことなくhtmlを編集することが出来る。
(何度も出るalertを見て)「またJavaScriptか!」

レベル2 : 広く公開されているライブラリを自分のサイトへ組み込むことが出来る。各ライブラリには相性があることを理解しており、あるライブラリとあるライブラリが衝突することは知っているがどういう条件で衝突するかは知らない。ライブラリの呼び出し部分に関してサンプルコードを修正し、自分のサイトに合わせたid、class名に変更することが出来る。
「カチカチカチ」(「xxするためのライブラリまとめ100」とかをブックマークしている)

レベル3 : 変数、条件分岐、ループを理解しており、簡単なコードであれば0から記述することが出来る。デザインとロジックの分離は出来ないが、ブラウザのuser agentで切り分けることでクロスブラウザのコードを記述することが出来る。公開されているライブラリに埋め込まれているhtml部分を好きな形へ書き換えることが出来る。
(次の仕事の仕様説明を聞いて)「そこもJavaScriptつかうんですか!?」

レベル4 : 自作のライブラリ群に限界を感じ、jQuery、Prototype.js等に手を出す。簡単なアニメーションを行うことが出来、デザインとロジックの分離を行うことができる。firebugがないとデバッグする気が起きない。GreaseMonkey等のUserScriptを作成し、既存のサイトを修正する事が出来る。
(ユーザから「動かない」と呼ばれて)「ごめん。まずfirebug入れていい?」

レベル5 : 正規表現、再帰、無名関数を使いこなせる。jQuery、Prototype.js等の普段使用しているライブラリに沿った記述が可能になる。.prototypeを使用して既存のオブジェクトを拡張することが出来る。コードを記述するときに速度をきにしだす。普段からlocal proxyが起動している。
(IEだけ非常に遅いのを見て)「IE爆発しろ!」

レベル6 : this, .apply, instanceOf等の効果を他人に説明することが出来る。各種外部APIを連動させてJavaScript単体では出来なかったことを実現する。JavaScriptではサポートされていない機能を実装するためにJavaScriptから呼び出されるだけのswfを作成したことがある。速度的な問題から各要素に直接イベントを設定するのではなく、上位要素にイベントを設定し独自のディスパッチャでイベントの処理を行う。
(Yahoo! pipesを使って)「Yahoo! いいじゃん!」

レベル7 : 各ブラウザが独自実装している機能に関して、共通部分を抜き出してライブラリ化する。HTML5を試してみる。profileでいくつかのコードをテストし、一番早いものを採用する。速度的な問題から、あえてライブラリを使用しない。
(できあがったコードを見て)「半分がIE対策か。。。」

レベル8 : JavaScriptでDSLを作成する。ブラウザのextensionを作成し、addons.mozilla.org等で公開する。広く公開されているライブラリに限界を感じ自作することを思い立つ。カンファレンス、勉強会等でLightning Talkを行う。
(Lightning Talkにて)「どうもxxのnnです」

レベル9 : サーバサイドJavaScriptに手を出す。カンファレンスにスピーカーとして呼ばれる。JavaScriptの仕様に限界を感じ、仕様を変更できないか考える。作ったライブラリが広く使われるようになるが、本人のやる気がついてこらず放置気味になる。
(自作ライブラリへの問い合わせに対して)「次のバージョンでは修正予定です!(いつ出るかわからないけど)」

レベル10 : JavaScriptの実装を開発している。次世代のECMAScriptに関しての提言が受け入れられる。自作したライブラリがOSやブラウザ等の実行環境に標準で取り入れられる。JavaScriptに関する書籍を出版し、コミュニティから「バイブル」と呼ばれ読書会が開かれる。
(始めてあった人から)「もしかしてnnさんじゃないですか?はじめまして!いつもお世話になっています!」


各レベル内容はどれか一つでも当てはまればクリアと想定しています。

ただ、内容はかなり偏っていると思うので、皆さん独自の「レベル10」を作ってみてください。

カヤックではすごいエンジニアを募集しています

2009-12-18

齢27にしてNirvanaをまともに聴き出したtaiyohです。
最近、ベースの他にギターも始めてみたのですが、本当に難しい…
(個人の方含め)ブログ書くの本当に久しぶりです。

ちょうど今JavaScriptをがっつり使った案件に関わっているので、開発周りで小ネタを一つ。

JSの割とポピュラーな開発方法として、ローカルプロキシ経由でアクセスし、開発中のファイルを読みこませてチェックするという方法があります。
その最に使う代表的なローカルプロキシとして、Mac OSXやLinuxの場合はCocProxyがありますし、Windowsの場合、FiddlerProxomitronがあります。

さて、僕の開発方法はといいますと、ローカルプロキシを使用しているという意味ではあまり変わったことはしていません。
ただ最近、ひょんなことから、PerlのHTTP::Proxy::Selectiveというモジュールがローカルプロキシとして使えることがわかったので、今ではこれを使って開発を進めています。

使い方

実はSynopsisより、このモジュールに同梱されているお手軽スクリプトのselective_proxyのソースを見る方が、より具体的な使い方がわかると思います。

[taiyoh@watkins] $ cat list.ini
debug = 1

[www.example.com]
/path/to/remote.js = /path/to/local.js

こんな.iniファイルを作成し、

[taiyoh@watkins] $ perl -Ilib script/selective_proxy list.ini

これでもう動きます。 あとはブラウザのプロキシ設定を切り替えるだけでOK。まあ、selective_proxyのSynopsisのまんま…

問題点

ただ、素のselective_proxy(H::P::Selective)には以下のような不満があります

・ローカルホスト以外からのアクセスは受け付けない

僕は、開発サーバとその他用とでのマシンを分けているため、
開発用マシンにプロキシサーバを設置し、その他用マシンからそちらにアクセスする必要があります。
が、ローカルホスト以外からのアクセスの制限を外さないと、その他用マシンからアクセスしても弾かれてしまいます。

・ルールの保持方法がちょっとアレ

パスの指定方法は、ちょっと違う方がいいかな、と思ってます。
普通にハッシュのまま保存するのじゃだめなのかな…
マッチするパス以下のファイルを全部対象にするというのも、明示的にワイルドカード書かせた方が分かり易い気が。 (ワイルドカード対応は未検証です)

・(おまけ)デバッグログ用のメソッドくらい定義してくれ&デバッグログがしょぼい

直でwarnか…まあいいけど

ということで、(おまけ以外の)これらの点をどうにかしてみました。
selective_proxyと使い方は殆ど同じです。スクリプトはgistに置いておきました。
http://gist.github.com/259276
無保証ですが、気になった方はどうぞお使いください。

ところで、PAC(Proxy Auto-Config)って知ってます?

例えば

[taiyoh@watkins] $ cat proxy.pac
function FindProxyForURL(url, host) {
    var proxy = 'PROXY hogefuga.local:3128';

    if (dnsDomainIs(host, 'www\.example\.com')) {
        if(/\/path\/to\/modified\.js/.test(url)) {
            return proxy;
        }
    }
    return 'DIRECT';
}

こんなファイルを用意していたとします。
そしてこれをブラウザのプロキシ設定に読み込ませます。
(Firefoxだと、環境設定->詳細->ネットワーク->接続設定から自動プロキシ設定スクリプトURLにラジオボタンを合わせ、ファイルのパスを入力)
すると、上の例だと「http://www.example.com/path/to/modified.js」にリクエストが飛ぶ時だけ、
指定したプロキシ経由でのリクエストに切り替えることができます。
何がいいかというと、特定のファイルのみをローカルプロキシ経由で取得できるので、
レスポンスが圧倒的に速くなります(といっても、普通に閲覧する程度になる、という意味です)。

尚、PACのもっと詳しい使い方については、「プロキシの自動設定方法」というページをご参照ください。

(追記:IEだと動作が怪しいという噂も…)

さっきのPerlのローカルプロキシのときに作っていたlist.iniから、このPACファイルも生成できないかな

ということで、これも変換スクリプトを作ってしまいました。
http://gist.github.com/259275
今僕の環境では、list.iniを書き換えたらこの変換スクリプトを起動してproxy.pacを生成しなおし、
プロキシを再起動、firefoxのPACファイルの再読み込み、というフローで新しいファイルに対応できるようにしています。
まあ、これはもっと自動化できますね…。でも、そんなに頻繁に切り替えるものでもないですが。

総括

ということで、殆ど僕の開発環境晒しみたいになってしまってますね…
PACについては、あまり知られていないけど、あると便利な技術だと思いますので、試しに使ってみては如何でしょうか!

カヤックでは、オールラウンドにプログラムを書きたい技術者も募集しています!