目次


jQuery を扱う

第 3 回 中級レベルの jQuery: 独自のプラグインを作成する

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: jQuery を扱う

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:jQuery を扱う

このシリーズの続きに乞うご期待。

はじめに

この連載の前回の記事「jQuery を扱う: 第 2 回 中級レベルの jQuery: UI プロジェクト」では、Web アプリケーションの有効性を向上させるために、自分が使用している jQuery コードの中でプラグインを使用する方法を説明しました。しかし、これらのプラグインは自然に生まれてくるわけではありません。私や読者の皆さんのような開発者たちが jQuery コミュニティーを良くしようと、空いた時間を使って作成し、テストした結果生まれるものです。しかも、開発者たちの作業に報酬はありません。それでも無償でプラグインを作成する理由は、自作のコードに対する愛情だけです。この記事では、独自のプラグインを作成して jQuery がホストするプラグイン・ページにチェックインすることによって、この素晴らしいコミュニティーに貢献する方法を説明します。こうすることによって、皆さんが作成したプラグインを誰もが使用できるようになり、jQuery 開発コミュニティー全体を向上させることができます。これは、私の今年の慈善活動だと思ってください。

この記事のサンプル・プラグインを作成するなかで、プラグインの作成、そしてプラグインを作成するためのフレームワークは至って単純明快であることがわかりました。作業で大変なのは、他の誰かがまだ作成したことのない内容のプラグインを考案し、その内容を実際に行う「単調でつまらない」JavaScript コードを作成するという部分です。プラグインの構造は単純であるため、初心者でもわかりやすく、上級コード作成者は柔軟な処理が可能です。そのため、プラグインの数は急速に増えています。

もちろん、この記事のための調査を進めるうちに、どのプラグイン作成者も独自の作成スタイルがあること、そして jQuery には何種類かのプラグインの作成スタイルを使用できることもわかりました。ここでは最も簡単で、jQuery 自体が推奨している作成スタイルに重点を置きますが、スタイルの違いやオプションが関係する場合にはその都度指摘します。

プラグインについての説明

プラグインを作成する際のステップ 1 は当然、優れたプラグインを考案することです。ほとんどの名案がそうであるように、他の誰かが既に同じプラグインを思い付いている可能性があります。この記事で作成するプラグインはまったく新しい概念というわけではありませんが、記事を書いている時点では、jQuery プラグイン・コミュニティーのどこを探してもこれと同じプラグインは見つかりませんでした。私としては、個人的にいろいろと役に立つプラグインになることがわかっています。

私のプラグインは NumberFormatter プラグインです。数字書式は、Java™ や PHP などのサーバー・サイドのコード、それに国際化対応に取り組んだことがある人には馴染み深いと思います。言うまでもありませんが、世界の誰もが数字に同じ書式を使うわけではありません。例えば、距離にマイルを使わない国もあります。また、アメリカでは例えば「1,250,500.75」(この数字は私の納税申告書から取ってきただけです) と書きますが、国によって書き方はさまざまです。ドイツでは「1.250.500,75」、フランスでは「1 250 500,75」、スイスでは「1'250'500.75」、日本では「125,0500.75」となります。いずれもまったく同じ数字です。ただ、Web アプリケーションのユーザーに表示するときにはそれぞれに異なる書式で書かれるというだけです。

そこで浮かんでくる疑問として、国際的なアプリケーションを作成している場合、各国の人々にどうやって数字を表示したらよいのでしょうか。もちろんこの疑問に対する答えは、サーバー・サイドの書式設定を使うことであり、これはかなり一般的な方法です。Java には堅牢な書式設定ライブラリーがあり、これによって数字の書式設定は容易になります。数字を含んだページがサーバー上でセットアップされるときに、サーバーで数字の書式設定を処理することができます。しかし、サーバーにアクセスできない環境で開発することはよくあるため、クライアントでサーバーと対話することなく数字を書式設定する方法が必要になってきます。

私が説明しているプラグインの一般的な使用ケースは、ユーザーに年収の入力を求めるフィールドがあるような Web アプリケーションの場合です。アメリカでは、ユーザーは「$65000」、「65,000」、「65000」、「65,000.00」のようにさまざまな形で入力するはずです。いずれもまったく同じ数字ですが、ユーザー・エクスペリエンスを改善させるためには、画面上での数字の表示方法を制御しなければなりません。数字が入力された後にサーバーを呼び出すこともできますが、書式がそれぞれに異なる数字のフィールドが大量にある場合、この方法では厄介なことになります。しかも、この問題をクライアント・サイドで解決してユーザーに瞬時にフィードバックできるとしたら、そのほうが賢明です。

以上で明確にしたのが、私が埋めようとしている JavaScript と jQuery の間にある機能のギャップです。私はこのプラグインで、クライアント上で数字を書式設定できるようにして、サーバーと対話しなくても Web アプリケーションを国際化対応させる手段を他の開発者たちに提供したいと思います。おまけに、このプラグインは逆の機能も果たします。それは、書式設定されたテキスト・ストリングから数字を抽出できるようにし、開発者が数字を解析できるようにする機能です。この機能は、クライアントでの数学演算に使用することができます。さらに Java DecimalFormatter クラスの機能を真似て、数字書式設定を行うクライアント・コードと標準的なサーバー・サイドのメソッドとの共通性を維持するつもりです。

ステップ 1 の結果: プラグインの必要性を明確にし、その必要性を満たすために使用する仕様を定義しました。

プラグインの規則

jQuery チームは、プラグインのユーザーが期待する共通の環境を作り出すため、プラグインの作成者に従って欲しい多数の一般規則を制定しています。jQuery チームは私よりもはるかに賢いはずなので、彼らが作った規則に異論を唱えるべきではないでしょう。そのため、ここではこれらの規則を概説し、私自身のプラグインでもすべてのステップで規則に従うようにします。

  • ファイルには「jquery.<your plug-in name>.js」という名前を付けること
    これはもっともなことで、誰かがファイルを見たときに一目でそれが jQuery プラグインであること、そしてどのプラグインであるかがわかるからです。

    したがって、サンプル・プラグインは「jquery.numberformatter.js」という名前にします。

  • すべての新しいメソッドはjQuery.fn オブジェクトにアタッチし、すべての新しい関数は jQuery オブジェクトにアタッチすること
    この段階ではわかりにくいかもしれませんが、これは実際のコーディングで最も重要な規則なので、次のセクションで詳しく説明します。

    したがって、私はメソッド/関数をこの 2 つのオブジェクトにのみアタッチすることにします。

  • this」は jQuery オブジェクトへの参照であること
    この規則は、「this」を参照すれば、すべてのプラグイン作成者が jQuery からどのオブジェクトを受け取るかがわかるようにして、プラグインの作成を容易にすることを目的としています。

    したがって、「this」は jQuery オブジェクトへの参照としてのみ使用することにします。

  • プラグインで定義するすべてのメソッド/関数には、最後に「;」(セミコロン) を付けること (こうしないと、コード・ミニマイザーが壊れるため)
    JavaScript ファイルを最小化することはベスト・プラクティスなので、ミニマイザーを壊してしまうと都合が悪く、プラグインがすぐにお払い箱になってしまう可能性があります。

    したがって、すべてのメソッド/関数は「;」で終わるようにします。

  • 特に断りのない限り、すべてのメソッドは jQuery オブジェクトを返すこと
    jQuery メソッドを連鎖させて呼び出すのはよく使われる方法であり、もしこの鎖を断ち切るようなプラグインを作成してしまうと、文字通り「鎖が切れて」しまいます。

    したがって、format() メソッドでは jQuery オブジェクトを返すようにします。また、parse() メソッドは jQuery オブジェクトを返しませんが、この関数が鎖を断ち切ることをドキュメントのあらゆる箇所に記述しました (結局のところ、Number オブジェクトを返しながらも鎖を維持するのは困難であるか、あるいは不可能です)。

  • 一致する要素を繰り返し処理する場合は常に this.each() を使用すること (オブジェクトをループする方法として信頼性が高く、効率的であるため)
    パフォーマンスと安定性のため、すべてのメソッドはこの方法を使って一致する要素をループ処理するように推奨されています。

    したがって、メソッドではこの方法でのみ、一致する要素をループ処理するようにします。

  • プラグイン・コードでは「$」ではなく、必ず「jQuery」を使用すること
    これは重要な点で、このようにすると、「$」が競合しているプラグイン・ユーザー (別の JavaScript ライブラリーを使用している可能性のあるユーザー) が「var JQ = jQuery.noConflict();」という関数を使ってこの jQuery のショートカットを 1 箇所で変更できるからです。しかし残念ながら、私がこれまで多くのプラグインで目にしてきたように、この規則はかなり頻繁に破られています。開発者が jQuery のショートカットを変更しなければならないとしたら、おそらくそれは壊れたプラグインがお払い箱になることを意味しています。

    したがって、サンプル・プラグインでは jQuery だけを使用し、そのショートカットである「$」は使用しないことにします。

上記はプラグイン・コードに関する規則/推奨だけですが、実を言うとこれらの規則には事実上、従わざるを得ません。なぜなら、プラグインの規則を破り出すと、プラグインが使われなくなるだけでなく、開発者仲間からの酷評を受けることになります。プラグインがほとんど使われないということは、プラグインにかけている時間を無駄にしていることと同じです。そのため、これらの規則に従うことが重要です。そうすることによって開発者仲間を助け、彼らのコーディングに一貫性をもたらすだけでなく、作成したプラグインがよく使われるようになる可能性も高くなります。

ステップ 2 の結果: jQuery プラグインを作成する上でのすべての規則に従うことにします。

プラグインの作成

いよいよコードの作成に取り掛かる準備ができました。プラグインを作成する際の最初のステップは、プラグインの構造を決めることです。まずは、その構造をメソッドと関数のどちらにするかを決めなければなりません。しかし皆さんからは、「その違いは何なのか?」という質問が出てくることでしょう。

上記で説明したように、メソッドと関数の違いは、メソッドは jQuery.fn オブジェクトにアタッチし、関数は jQuery オブジェクトにアタッチしなければならないことです。これで疑問が晴れるかと言えば、jQuery を扱い始めたばかりという方には、まだ十分ではないでしょう。代わりにこのように考えてみてください。構造をメソッドにすると、プラグインに渡すように選択されたすべての要素をループ処理することが可能なコードになります。その結果、プラグインは任意のタイプの HTML 要素を受け入れ、それぞれの要素をどのように処理するかはプラグインが定義します。したがって、プラグインのメソッドは「p」から「#mySpecificPageElement」に至るまでのすべての jQuery セレクターを受け入れることができます。これは、プラグインに柔軟性を持たせ、プラグインのユーザーがあらゆるタイプのページ要素を渡せるようにしたい場合には理想的です。すべてを適切に処理するようにする責任はプラグイン開発者としてのあなたにあります。それとは対照的に、関数は選択された要素を引数として取りません。つまり、プラグインの構造を関数にすると、ページ全体に適用されるだけとなります。責任はプラグイン開発者に移り、プラグイン開発者が、プラグインにどのページ要素と対話させ、残りのページ要素を無視させるかを定義します。その違いについて以下のコードで検討してみましょう。

リスト 1. jQuery プラグイン・メソッド/関数
// This is a method because you can pass any type of selector to the method and it 
// will take some action on the results of the selector.  In this case, it will
// doSomething() on the page element with an ID of myExample
$("#myExample").doSomething();
   
// This is also a method, even though you are passing the entire page body to
// the method, because you are still passing a selector
$("body").doSomethingElse();

// This is a function, because you are NOT passing any selector to the function
// The plug-in developer must determine what page elements they want to take action on.
// This is usually accomplished by the plug-in developer requiring the page elements
// to contain a certain class name.

<div class="anotherThing">

// This hypothetical plug-in developer would document that his plug-in only works
// on elements with the class "anotherThing"
$.anotherThing();

上記の説明から判断すると、サンプル・プラグインではユーザーがどのページ要素を書式設定するのかを指示できるようにしたいため、このサンプル・プラグインではメソッドを使用しなければならないようです。リスト 2 に、その場合のプラグイン・コードを記載します。

リスト 2. メソッド定義
jQuery.fn.format = function();

// You would call your plug-in like this (at this point)
$("#myText").format();

当然のことですが、関数を単純に万能なプラグインにすることはできません。ここでは国際化対応に取り組んでいますが、どの国を対象にテキストの書式を設定したいのか、そしてどの書式が必要なのかは自然と明らかになるわけではないからです。そのため、いくつかのオプションを許容するようにプラグインを多少変更しなければなりません。書式設定メソッドに必要となるオプションは 2 つあります。1 つは、数字が使用するフォーマット (#,###、#,###.00 など)、そしてもう 1 つはロケール (使用する国際数字書式設定を決定する、単純な 2 文字の国番号としてのロケール) です。

また、プラグインがよく使われるようになる可能性を高くするには、できるだけ使いやすいプラグインにする必要もあります。これは、ユーザーがオプションを渡したくない場合、その必要がなくなるように事前にいくつかのデフォルト・オプションを定義することを意味します。私はこの記事をアメリカで書いていて、たまたま世界で最も一般的な数字書式でもあるという理由で、ロケールのデフォルトは「us」、書式のデフォルトは「#,###.00」に設定しますが、これ以外の理由は何もないので、他の通貨をデフォルトに使用することもできます。

リスト 3. プラグインでのオプションの許可
jQuery.fn.format = function(options) {

    // the jQuery.extend function takes an unlimited number of arguments, and each
    // successive argument can overwrite the values of the previous ones.
    // This setup is beneficial for defining default values, because you define
    // them first, and then use the options passed into the method as the
    // second argument.  This allows the user to override any default values with their
    // own in an easy-to-use setup.
    var options = jQuery.extend( {

      format: "#,###.00",
      locale: "us"

}, options);

プラグイン・フレームワークを作成するための最後のステップは、メソッドに渡された選択要素を適切に処理することです。上記の例を思い出してください。選択される要素は 1 つのページ要素であることも、多数のページ要素であることもあります。いずれの場合も同じように正しく処理しなければなりません。また、jQuery プラグインの規則にあるように、「this」オブジェクトは jQuery オブジェクトへの参照であるため、メソッドに渡された jQuery の選択要素への参照はあります。後はこれらの要素を繰り返し処理すればよいだけです。jQuery プラグインの規則では、それぞれのプラグイン・メソッドは jQuery オブジェクトを返すことにもなっています。ご存知のとおり jQuery オブジェクトは「this」なので、メソッドでこの this を返せば、すべて上手く行くはずです。以下のコード・スニペットで、選択された各要素を繰り返し処理する方法と、jQuery オブジェクトを返す方法をどのように実現しているかを見てください。

リスト 4. jQuery オブジェクトの操作
jQuery.fn.format = function(options) {

    var options = jQuery.extend( {

      format: "#,###.00",
      locale: "us"

    }, options);

// this code snippet will loop through the selected elements and return the jQuery object 
// when complete
return this.each(function(){
  // inside each iteration, you can reference the current element by using the standard
  // jQuery(this) notation
  // the rest of the plug-in code goes here
  });

実際のプラグイン・コードそのものは、この記事の話題の中心ではないのでこれ以上説明しませんが、完全なプラグイン・コードが記事に付属しているので、コードの全容を確認することができます (「ダウンロード」を参照)。以下に、メソッドではなく関数を作成することにした場合にプラグイン・アーキテクチャーをどのようにセットアップするかを示す例を記載しておきます。

リスト 5. 関数を使用するプラグインの例
jQuery.exampleFunction = function(options) {

   var options = jQuery.extend( {

     // your defaults

    }, options);
    
    jQuery(".exampleSelector").each(function(){
    
    });

});

プラグインの微調整

Web で見つかる大抵の初心者向けプラグインの記事は、基本的なプラグイン・フォーマットを用いて説明するだけで終わります。しかし、基本的なフレームワークはその言葉どおり基本でしかありません。独自のプラグインを作成するときには、その他にも考慮しなければならない重要なことがあります。つまり、プラグインに磨きをかけて、初心者レベルのプラグイン以上のものにするための考慮事項です。そこで、以降の 2 つの追加ステップに従って、現段階での初心者レベルのプラグインを中級レベルのプラグインに変身させてください。

微調整 1 – 内部メソッドを private メソッドにする

オブジェクト指向のプログラミング言語では、反復コードを実行できる外部関数を作成しておくと重宝します。私が作成した NumberFormatter プラグインにはその一例として、関数に渡されたロケールと、小数点として使用する文字およびグループの区切り文字として使用する文字を判断するコードがあります。このコードは format() メソッドと parse() メソッドの両方に必要なので、初心者のプログラマーでもこのコードが独自のメソッドに属することはわかるはずです。けれどもここでは jQuery プラグインに取り組んでいることから、この決定によって 1 つの問題が持ち上がってきます。このコードを JavaScript に定義された独自の関数にしただけだと、このスクリプトを使用する誰もが目的を問わずにこのメソッドを呼び出すことができてしまいます。それでは、内部の作業用に作成したこの関数の意図に反するため、部外者が呼び出さないようにしたいと思います。これから、この関数を private 関数にする方法を説明します。

この private メソッド問題に対するソリューションは、クロージャーと呼ばれるものです。クロージャーは基本的に、jQuery オブジェクト (公開オブジェクト) にアタッチした呼び出しを除き、外部の呼び出しからプラグイン・コード全体を遮断します。この設計を使えば、必要なあらゆるコードをプラグインに組み込んでも、コードが外部スクリプトによって呼び出される心配はありません。プラグイン・メソッドを jQuery オブジェクトにアタッチすることによって、本質的にメソッドは public メソッドになり、残りのすべての関数/クラスは private になります。そのために必要なコードは、リスト 6 のとおりです。

リスト 6. private 関数への変更
// this code creates the Closure structure
(function(jQuery) {

   // this function is "private"
   function formatCodes(locale) {
      // plug-in specific code here
   };  // don't forget the semi-colon

   // this method is "public" because it's attached to the jQuery object
    jQuery.fn.format = function(options) {

     var options = jQuery.extend( {

          format: "#,###.00",
          locale: "us"

     },options);

     return this.each(function(){
         var text = new String(jQuery(this).text());
         if (jQuery(this).is(":input"))
             text = new String(jQuery(this).val());

         // you can call the private function like any other function
         var formatData = formatCodes(options.locale.toLowerCase());

         // plug-in-specific code  here
      });
     }; // don't forget the semi-colon to close the method

// this code ends the Closure structure
})(jQuery);

微調整 2 – プラグインのデフォルトをオーバーライド可能にする

このプラグインを微調整する最後のステップは、デフォルトをオーバーライドできるようにすることです。結局のところ、このプラグインをダウンロードしたドイツの開発者が、彼の Web アプリケーションのユーザーは揃ってドイツ語ロケールを希望していることがわかっているとしたら、あらゆるメソッド呼び出しでドイツ語ロケールを作成することになります。しかし開発者にそうさせることなく、1 行のコードでデフォルト・ロケールを変更できるようにしなければなりません。このサンプル・プラグインでは、デフォルト・ロケールを変更できるようにすることがとりわけ役に立ちます。Web アプリケーションがユーザーにさまざまな国の書式で数字を表示することは考えられないためです。Web ページでは、すべての数字が同じロケールを使用して書式設定されるはずです。

このステップではコードを多少変更する必要があります。そのため、この最後の改良ステップを反映するように、これまで見てきた内容が更新されています。

リスト 7. オーバーライド可能なデフォルト
jQuery.fn.format = function(options) {
// Change how you load your options in to take advantage of your overridable defaults
// You change how your extend() function works, because the defaults
// are globally defined, rather than within the method.  If you didn't use the
// {} as the first argument, you'd copy the options passed in over the defaults, which is
// undesirable.  This {} creates a new temporary object to store the options
// You can simply call the defaults as an object within your plug-in
var options = jQuery.extend({},jQuery.fn.format.defaults, options);

   return this.each(function(){
   
   // rest of the plug-in code here

// define the defaults here as an object in the plug-in
 jQuery.fn.format.defaults = {
      format: "#,###.00",
      locale: "us"
      }; // don't forget the semi-colon

この最後のステップで、プラグインの作成は終了です。この時点で、最終段階のテストに使用できる改良されたプラグインが完成しました。リスト 8 に、この記事で作成してきたプラグインの完成版を記載します。これを見ると、それぞれのコードをどのように 1 つに組み立てているかがわかります。また、これまで話題にのぼりませんでしたが、このプラグインには parse() 関数が組み込まれています (これは書式設定を処理する関数です。このような単調な作業は記事の範囲外なので省きましたが、該当する部分はサンプル・コードにも、そしてもちろんプラグイン自体にも含まれています)。

リスト 8. NumberFormatter プラグイン
(function(jQuery) {

    function FormatData(valid, dec, group, neg) {
       this.valid = valid;
       this.dec = dec;
       this.group = group;
       this.neg = neg;
    };

    function formatCodes(locale) {
      // format logic goes here
      return new FormatData(valid, dec, group, neg);
    };

 jQuery.fn.parse = function(options) {

    var options = jQuery.extend({},jQuery.fn.parse.defaults, options);

    var formatData = formatCodes(options.locale.toLowerCase());

    var valid = formatData.valid;
    var dec = formatData.dec;
    var group = formatData.group;
    var neg = formatData.neg;

    var array = [];
    this.each(function(){

       var text = new String(jQuery(this).text());
       if (jQuery(this).is(":input"))
           text = new String(jQuery(this).val());


       // now we need to convert it into a number
       var number = new Number(text.replace(group,'').replace(dec,".").replace(neg,"-"));
       array.push(number);
     });

     return array;
 };

 jQuery.fn.format = function(options) {

    var options = jQuery.extend({},jQuery.fn.format.defaults, options);  

    var formatData = formatCodes(options.locale.toLowerCase());

    var valid = formatData.valid;
    var dec = formatData.dec;
    var group = formatData.group;
    var neg = formatData.neg;

    return this.each(function(){
       var text = new String(jQuery(this).text());
       if (jQuery(this).is(":input"))
           text = new String(jQuery(this).val());

       // formatting logic goes here

       if (jQuery(this).is(":input"))
           jQuery(this).val(returnString);
       else
           jQuery(this).text(returnString);
    });
 };
 
 jQuery.fn.parse.defaults = {
    locale: "us"
 };

 jQuery.fn.format.defaults = {
    format: "#,###.00",
    locale: "us"
 };
 
 })(jQuery);

プラグインのテスト

プラグインを作成する上での最終ステップは、プラグインを徹底的にテストすることです。プラグインにバグが見つかることほど、プラグインのユーザーを怒らせることはありません。ユーザーはバグを見つけると、それを修正する代わりに即刻プラグインを捨てるはずです。このようなユーザーが何人か出てきて、しかも酷評を受けたとしたら、プラグインは瞬く間に使われなくなってしまいます。それとは別に、徹底的にプラグインをテストするのはお互い様のことで、自分のコードで使用する他の開発者が作成したプラグインも十分にテストされたものであって欲しいはずです。自分が作成したプラグイン・コードで、そのお返しをしてください。

サンプル・プラグインをテストするために、簡単なテスト構造を作成しました (ユニット・テスト・ライブラリーは不要です)。このテスト構造は、さまざまな数字とその直後に正しい書式が続く何十かのスパンを作成します。JavaScript テストではまず数字に関する書式設定を呼び出し、続いて書式設定された数字を期待される結果と比較し、一致しない場合にはその数字を赤で示します。この簡単なテストでは、私が実際行ったように、数十の異なるテスト・ケースをセットアップして、考えられるあらゆる書式をテストすることができます。このテスト・ページをサンプルのダウンロードに追加してあるので、jQuery を使った自動的なプラグイン・テストの 1 つのソリューションを確認することができます。

完成したプラグインの確認

新しく作成した NumberFormatter の動作を見てください。これは、NumberFormatter プラグインがどのようにアプリケーションに組み込まれるかを確認できるように作成した単純な Web アプリケーションです。

図 1. NumberFormatter の動作
NumberFormatter の動作
NumberFormatter の動作

この Web アプリケーションは単純で、そのまますぐに理解できるものです。ユーザーが年収、住宅、そして子供に関する情報を入力した後にテキスト・フィールドからカーソルを移動させると、NumberFormatter プラグインが入力された数字を適切な書式に設定します。このプラグインによって、Web アプリケーションは数字を一貫した書式に設定することができます。また、この Web アプリケーションではドイツのユーザーを対象に書式が設定されていることに注意してください。そのため、小数点と区切り文字はアメリカのユーザーを対象としたものとは異なります (これは、後でデフォルトを変更する方法を説明するためです)。

リスト 9. NumberFormatter の動作
$(document).ready(function() {

   // use the AlphaNumeric plug-in to limit the input
   $(".decimal").decimal();
   $(".numeric").numeric();

   // you want to change the defaults to use the German locale
   // this will change the default for every method call on the
   // entire page, so you won't have to pass in the "locale"
   // argument to any function
   $.fn.format.defaults.locale = "de";
   $.fn.parse.defaults.locale = "de";

   // when the salary field loses focus, format it properly
   $("#salary").blur(function(){
      $(this).format({format:"#,###.00"});
   });

   // when the house field loses focus, format it properly
   $("#houseWorth").blur(function(){
      $(this).format({format:"#,###"});
   });
   
   // when the kids field loses focus, format it properly
   $("#kids").blur(function(){
      $(this).format({format:"#"});
   });
   
   // calculate the tax
   $("#calculate").click(function(){
      // parse all the numbers from the fields
      var salary = $("#salary").parse();
      var house = $("#houseWorth").parse();
      var kids = $("#kids").parse();
      // make some imaginary tax formula
      var tax = Math.max(0,(0.22*salary) + (0.03*house) - (4000*kids));
      // place the result in the tax field, and then format the resulting number
      // you need one intermediate step though, and that's the "formatNumber" function
      // because all numbers in JavaScript use a US locale when made into a String
      // you need to convert this Number into a German locale String before
      // calling format on it.
      // So, the steps are:
      //   1) the tax is a Number that looks like 9200.54 (US locale)
      //   2) formatNumber converts this to a String of 9200,54 (German locale)
      //   3) put this String in the #tax field
      //   4) Call format() on this field
      $("#tax").text($.formatNumber(tax)).format({format:"#,###"});
   });

});

説明を締めくくる前に、まだ NumberFormatter プラグインについて指摘しなければならない点がいくつか残っています。まず、これはこのプラグイン初の 1.0.0 リリースです。今後は、Java DecimalFormatter に組み込まれている書式設定機能を追加して拡張したいと思っています。追加したい機能には、通貨、科学的記数法、パーセンテージのサポートがあります。また、負の値として単純に「-」を使うだけでなく、正の数字と負の数字それぞれに対応した書式設定規則も組み込む予定です (例えば、会計で行われているように負の数字に (5,000) を使用するなど)。最後に指摘する点として、すぐれたフォーマッターは、書式にあらゆる文字を含めることができ、予約された文字のなかに含まれていない文字は単に無視するようでなければなりません。以上が、このプラグインを堅牢なものにするために近い将来追加しようと思っている機能です。

ユーザーのロケールの取得

最後に残っている疑問は jQuery プラグインに特有のことではありませんが、このプラグインを使用するときに持ち上がってきます。それは、ユーザーのロケールをどのように取得するかです。現在、JavaScript を使用してこの情報を取得する手段はないため、これはもっともな疑問だと言えます。ユーザーのロケールを取得するには、JavaScript Bridge を作成する必要があります。JavaScript Bridge とは何かというと、私は単に、サーバー・サイドのコードから値を JavaScript コードに挿入するための単純な設計パターンをセットアップできることを意味しているだけです。リスト 10 に、Java を使って JSP ページでユーザーのロケールを取得する方法を示します。

リスト 10. ユーザーのロケールの取得
<%

    // the request object is built into JSPs
    // unfortunately, it's not any easier
    // tested on FF, IE, Safari, Chrome
    String locale = "us"; // or your default locale
    String accLang = request.getHeader("Accept-Language");
    if (accLang.length() > 5)
    {
       accLang = accLang.substring(0,5);
       locale = accLang.substring(accLang.indexOf("-")+1);
    }

%>

$(document).ready(function() {

   // take advantage of the ability to override defaults by using the JavaScript
   // Bridge here.  Then your page can use the format() and parse() functions
   // elsewhere in the page without modifying them for a user's locale.
   $.fn.format.defaults.locale = "<%=locale%>";
   $.fn.parse.defaults.locale = "<%=locale%>";
   
   });

プラグインの共有

これで、プラグインの作成とテストはすべて完了しました。最後のステップは、このプラグインを世界と共有し、jQuery Web サイトのプラグイン・リポジトリーに登録することです。

  • jQuery Web サイトのプラグイン・ページにアクセスし、左側のナビゲーションで Login/Register をクリックし、次に Create New Account をクリックします。すでにアカウントを持っている場合はログインし、そうでなければ新規アカウントを作成します。
  • アカウントの認証が行われた後、左のナビゲーションに選択肢が表示されます。そのなかから、「Add plug-in」を選択します。
  • プラグインを作成するページまでナビゲートしてください。このプラグインは jQuery 1.2 でしかテストしていないため、互換バージョンとしては jQuery 1.2 だけを含めることになります。時間をかけてプラグインにぴったりのタイトルとわかりやすい説明を付けてください。最終的には、この作業によって作成されたタイトルと説明がプラグインを他のユーザーに売り込むことになります。プラグインは何百もあるため、自分のプラグインを他より目立たせるための方法が必要です。自分が作成したプラグインの素晴らしい機能に控え目になる必要はありません。
  • 次に、プラグインのホーム・ページを指定するように求められます。プラグインを作成したばかりであれば、ホーム・ページはまだ用意していないことでしょう。プラグインをホストする独自のサーバーをセットアップしていない場合、幸いなことに Google では積極的にオープンソース・プロジェクトに対するホスティングを提供しています。私も、Google Code にこのプラグインを置くことにしました。独自の Google Code プロジェクトをセットアップするには、code.google.com にアクセスして登録プロセスに従うだけです。
  • Submit をクリックすれば、プラグインが作成されます。
    おめでとうございます。これで、あなたのプラグインが jQuery プラグイン・コミュニティーに加わり、あなたは正式にオープンソース・プロジェクトのコントリビューターとなりました。自分へのご褒美として、プラグインに 5 つ星の評価を付けてください。それだけの努力をしてきたからです。

まとめ

この記事では一貫して、jQuery JavaScript フレームワークのプラグインを作成する方法に焦点を当てました。まず始めのステップでは、独創的なプラグインを考え出し、プラグインで使用する仕様をまとめることでした。次に、jQuery プラグインの規則として、プラグインが作成者たちの間で一貫性を持つために押さえておくべき規則をリストアップしました。また、これらの規則については記事全体を通して指摘してきましたが、それは規則の多くが破られているプラグインを見てきたからです。なかでも顕著なのは、プラグインでは「$」を使用する代わりに「jQuery」のみを使用するという規則です (もちろん私はこの規則に従っています)。

サンプル・プラグインを作成する背景、そしてプラグインを作成する上での規則を説明した後は、基本的なプラグイン・フレームワークと、プラグインの中でメソッドを作成する場合と関数を作成する場合の違いについて説明しました。選択された要素を引数として取り、それに応じて操作を行う必要があるとしたら、常にメソッドを使用しなければなりません。この場合、ページ要素を提供する責任は、メソッドを呼び出す当の本人にあります。その一方、ページ上で操作対象となる要素がすでにわかっているため、選択された要素には関心がないというのであれば、関数を使用します。この場合、ページ要素を提供するのは、関数を作成するプラグイン開発者の責任です。どちらのプラグインの形も有効であり、その違いはプラグインに何を求めているかのみです。最後に、デフォルト・オプションをセットアップする基本的な方法、ユーザーが独自のオプションを提供できるようにする方法も説明しました。

さらに次のステップでは、プラグインをより高度にするための改良を加えました。このステップでは、プラグイン全体をクロージャーで囲むことによって効率的に private 関数と public 関数を作成できるようにしました。プラグイン内部で呼び出す関数は private にしたため、プラグインの外部からこの関数を呼び出すことはできません。また、デフォルトをプラグインのユーザーに公開し、ユーザーがコーディングの作業に苦労することなく、独自のデフォルトを 1 箇所で定義できるようにする方法も説明しました。

そして最後に、プラグインをサンプル Web アプリケーションで使用して、このプラグインがどのように振る舞うかを披露しました。記事の締めくくりの部分は、プラグインの作成に努力を払ってきた目的そのものです。つまり、自作のプラグインを jQuery プラグイン・コミュニティーにチェックインし、多くの拡張をもたらしてきた JavaScript ライブラリーに加えることです。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=398856
ArticleTitle=jQuery を扱う: 第 3 回 中級レベルの jQuery: 独自のプラグインを作成する
publish-date=05262009