jQuery Mobile 1.3.0 Betaがリリース!変更点まとめ

先日ついにjQuery Mobile 1.3.0 Betaのリリースがありました!

Announcing jQuery Mobile 1.3.0 Beta
http://jquerymobile.com/blog/2013/01/14/announcing-jquery-mobile-1-3-0-beta/


ここでは、jQuery Mobile 1.3の変更点を簡単にまとめたいと思います。
画面のサンプルやAPIなどについては、本家のBlogポストもしくはDocsを参照してください。


jQuery Mobile 1.3では、従来の予告通りResponsive Web Designにフォーカスしたアップデートになりました。Widgetの大きさにwidth: 100%などの指定をするように変更されており、画面サイズやグリッドなどにフレキシブルになるように設計されています。

これまでは、jQuery MobileかResponsive Web Designかを選択するような形に(結果的に)なっていましたが、1.3からはタブレット、デスクトップでも利用できるように配慮されています。また今後のアップデートでは、jQuery UIとの統合が図られるため、ますますその傾向は強くなります。

1.3で追加されたいくつかの機能は、Responsive Web Designの要であるMedia Queriesを利用する形となっていますが、この設定をスクリプトで記述することは難しいため、デフォルトでは多くのケースで望ましいと思われるサイズを決め打ちしています。そのため、個々のサイトに合わせてブレークポイントをカスタマイズする場合には、ui-responsive関連のCSSスタイルを自分で上書きする必要があります。


以降は、個々の機能について列挙していきます。

  • Panelウィジットの追加

Panelでは、Facebookでつかれているような出し入れ可能なサイドパネルが実装できます。
上下左右からメニューや任意のページなどをアニメーションをつけて表示することができます。


<div data-role="panel">などで作成できます。

Demo&Docs&API
http://jquerymobile.com/demos/1.3.0-beta.1/docs/demos/panels/panel-nav-form.html
http://jquerymobile.com/demos/1.3.0-beta.1/docs/panels/index.html
http://stage.api.jquerymobile.com/panel/

  • Responsive Tableの追加

画面が小さくなるとテーブルの形を変えるResponsive Tableが追加されました。
Responsive Tableには、以下の2つのモードが用意されています。

  • Reflow mode

横方向に伸びているテーブルを縦方向に伸ばして表示します。
<table data-role="table">などで作成できます。


Docs&API
http://jquerymobile.com/demos/1.3.0-beta.1/docs/tables/table-reflow.html
http://stage.api.jquerymobile.com/table-reflow/

  • Column toggle mode

1度に表示するカラム数を制限し、設定ボタンで任意に表示するカラムを選択することができます。
<table data-role="table" data-mode="columntoggle">などで作成できます。


Docs&API
http://jquerymobile.com/demos/1.3.0-beta.1/docs/tables/table-column-toggle.html
http://stage.api.jquerymobile.com/table-columntoggle/

  • Dual handle range sliderの追加

つまみが2つあるスライダーが追加されました。
開始と終了を設定することができます。
<div data-role="rangeslider">で2つのスライダーを囲むと作成できます。


Demo&API
http://jquerymobile.com/demos/1.3.0-beta.1/docs/demos/sliders/rangeslider.html
http://stage.api.jquerymobile.com/rangeslider/

  • Responsive Gridの追加

従来のグリッドレイアウトの仕組みに、Responsiveな設定が追加されました。
画面サイズが小さくなると1カラムになるようになっています。デフォルトの
ブレークポイントは、560px (35em)以下です。次のようにui-grid-*を指定する要素に
併せてui-responsiveクラスを追加するだけです。


<div class="ui-grid-b ui-responsive">


自分でブレークポイントを設定する場合は、Docsにサンプルがあります。


Docs&API
http://jquerymobile.com/demos/1.3.0-beta.1/docs/content/content-grids-responsive.html
http://stage.api.jquerymobile.com/grid-layout/



その他の変更点

  • 新たにhashchangeイベントとpopstateイベントを統合したNavigateイベントが追加されました。

また、history APIを簡単に扱うためのメソッドとして、$.mobile.navigateが追加されています。


http://stage.api.jquerymobile.com/navigate/
http://stage.api.jquerymobile.com/jQuery.mobile.navigate/

  • リストビューのfilter機能をうまく利用したAutocomplete機能が追加されました。

単純にリストを非表示にしておき、フィルターに引っかかったものだけを表示して、あたかもAutocompleteしているかのように見せます。サンプルではAjaxを使った方法も記載されています。リストにdata-filter-reveal="true"の設定を追加します。


http://jquerymobile.com/demos/1.3.0-beta.1/docs/demos/listviews/listview-filter-reveal.html
http://jquerymobile.com/demos/1.3.0-beta.1/docs/demos/listviews/listview-filter-autocomplete.html

  • ダイアログの閉じるボタンの表示位置をカスタマイズできるようになりました。data-close-btn属性に"right"、"left"、"none"が指定できます。
  • ポップアップウィジットでポップアップの外の部分をタッチした際にポップアップを閉じないようにできるようになりました。data-dismissible="false"で設定できます。
  • テキスト系の入力フォームにデリートボタンを任意に追加することができるようになりました。data-clear-btn="true"で設定できます。
  • fileインプットをサポートしました。
  • カスタムセレクトメニューのoptgroup要素に任意のテーマが指定できるようになりました。また、ヘッダー内に配置した際に左右へ表示できるようになりました。data-divider-themeでテーマを、classにui-btn-right、ui-btn-leftでヘッダー内に配置した際の位置を指定できます。
  • ボタンのテーマをスクリプトから変更できるようになりました。(_setOptionを利用します。)
  • 折りたたみ可能ブロックにdata-corners(角丸の設定)が追加されました。
  • 固定ツールバーは、現在はposition:fixedをサポートしていないブラウザは対象外ですが、Download Builderツールにて、旧ブラウザをサポートするための設定が追加されました。fixedToolbar.workarounds.jsを選択すれば、Android 2.xやiOS 4でも固定ツールバーを利用できます。
  • チェックボックスラジオボタンに使われるグループ化の機能がウィジット化されました。createイベントなどをトリガーとして生成できるようになります。
  • 新たなアイコンとして、menuとeditが追加されました。
  • Swipeイベントの判定ロジックなどをカスタマイズできるようになりました。($.event.special.swipe.handleSwipeなどのfunctionを上書きする)
  • jQuery 1.9、2.0をサポートしました。
  • ページ遷移のアニメーションがIE10/WP8に対応しました。

IndexedDBでの検索がちょっと便利になるMultiEntry

HTML5 Advent Calendarの24日目です。
残すところあと1日となりました!
他の方々が有用な記事をたくさん書いて頂いているので、そちらも是非チェックしてみてください。

さて、私からはIndexedDBのMultiEntryという仕組みについて少しだけ解説したいと思います。
IndexedDBが題材ということで少しマニアックですが…


IndexedDBの検索方法
IndexedDBの検索方法について簡単に触れておくと、その名前の通り、あらかじめ索引を作成して検索するというものです。つまり、検索に使う可能性があるプロパティやパターンをあらかじめ洗い出しておく必要があります。また、RDBMSのように複合検索というものがないため、複雑な検索を行うためには、データ検索用のプロパティを別途用意しなければなりません。


検索がちょっと便利になるMultiEntry
前述したように、IndexedDBは複合検索が非常に面倒なのですが、MultiEntryという仕組みを利用すれば、ちょっとした複合検索ができます。
MultiEntryとは、索引を作成する際に複数のプロパティを指定する仕組みです。作成方法は簡単で、インデックスを作成する際のプロパティの指定をArrayで渡すだけです。

// インデックスを作成
store.createIndex('composite', ['flag', 'postDate'], { unique: false} );

// データ例:{id: 1, message: 'メッセージ1', flag: 0, postDate: new Date(2012,11,24) }


検索方法は、Rangeオブジェクトを作成する際にupperもしくはlowerなどに、同じようにArrayを渡して指定します。

// 検索条件:flag, postDate
var lower = [ 0, new Date(2012,11,1) ],
      upper = [ 0, new Date(2012,11,25) ] ;

// Rangeオブジェクト作成
var range = IDBKeyRange.bound(lower, upper);

// カーソル取得
var cursorReq = index.openCursor(range);


ここで注意して欲しいのは、例えばプロパティ1の検索条件で絞込み、更にプロパティ2で絞り込むというような形にはならないということです。サンプルの検索条件で言えば、flagで絞り込んだあとに、更にpostDateで絞り込んでいるように見えますが、正確には違います(それができるなら完全な複合検索ですね)。IndexedDBでは、あくまでflag+postDateでソートした結果を範囲検索しているだけです。よくわからないと思いますので、以下の図をみてください。


図: MultiEntryの検索範囲


つまり、flag+postDateでデータをソートし、そのデータの下限と上限をRangeのlowerとupperで指定するというものです。これが例えば、flag>postDateの順番が逆(postDate>flag)だと検索結果が違ってくることがわかるかと思います。


まとめ
今回は、IndexedDBのデータの持ち方を知っていないと、考え方がちょっと面倒なMultiEntryの仕組みを解説しました。MultiEntryは、複合検索する上で万能ではありませんが、ちょっとしたフラグ+プロパティ検索みたいなケースであれば簡単に利用することができるので、おすすめです。IndexedDBで複雑な検索をする場合は、選択肢のひとつとして覚えておくと良いかと思います。

Sublime Text 2のテーマをカスタマイズできる「Color Scheme Editor for Sublime」

Sublime Text 2 Advent Calendarの1日目です。
本当は12/1に書くはずが、風邪でダウンしていて公開が遅れてしまいました。。
気を取り直して、頑張って書きたいと思います。


最初にAdvent Calendarとは何か?という方は、技術評論社さんのこちらの記事が参考になります。

本日12月1日より,プログラマ有志による2012年の技術系Advent Calendarが各所ではじまる


Sublime Text 2 Advent Calendarについては、こちらで他の方のブログポストやエントリーができます。まだ空きがあるようですので、興味のある方は是非!

Sublime Text 2 Advent Calendar


さて今回は、意外とあまり取り上げられないSublime Text 2のテーマについて触れてみたいと思います。デフォルトでも多くのテーマがあり、Soda Themeのように有名なサードパーティ製のテーマもあります。他にもTextMate互換ということで、TextMateのテーマを利用することもできますので、テーマの種類はそれこそ星の数ほどあります。

こういった既存のテーマを利用するのは良いのですが、細部でちょこちょこ変えたいところが出てくると思います。そういった際に、Sublime Text 2のテーマを簡単にカスタマイズできる「Color Scheme Editor for Sublime」がおすすめです。


Color Scheme Editor for Sublime


http://tmtheme-editor.herokuapp.com/


Color Scheme Editor for Sublime*1は、個々のカラーを設定できるのはもちろん、既存のテーマを読み込んで編集することもできます。ダウンロードしたテーマは、PackagesフォルダのUserの下に配置して読み込みましょう。これで、見た目のカスタマイズも楽々ですね!


簡単ですが以上です!良いST2ライフを。 :)

*1:ちなみに、このColor Scheme Editor for SublimeはAngular.jsとHTML5のFile System APIが利用されているそうです。なので、File System APIが利用できるChromeオンリーでの動作になっていますのでご注意ください。

「jQuery Mobileパーフェクトガイド」を執筆しました

ずいぶん前から書いていたのですが、ようやく出版にこぎ着けました。
時間が掛かった分、それなりに良いものができたと思います。なんと全ページフルカラーです。


jQuery Mobileパーフェクトガイド 基本からデザインカスタマイズ、パフォーマンスアップまで

jQuery Mobileパーフェクトガイド 基本からデザインカスタマイズ、パフォーマンスアップまで

以降は、なんとなく自分で解説。


本書は、jQuery Mobileの基本から解説し、次のステップとしてデザインのカスタマイズについてさらに詳細に解説しています。デフォルトのデザインのままのjQuery Mobileを使いたくないという方は、是非手にとって見てみてください。


どちらかというと、スマートフォンサイト制作寄りの内容になっていますが、JavaScriptによる設定変更やイベントなども網羅しています。また、JavaScriptが良くわからないという方のためにも、サンプルコードは、そのままでも実践で使える利用頻度の高いものを選んだつもりです。その他にも、パフォーマンスチューニングやjQuery Mobileを取り巻くいろいろなプラグインやプロダクト、参考情報などをできる限り詰め込みました。jQuery Mobileのプラグインの開発方法まで解説しています。なので、これ1冊でjQuery Mobileのことはだいたい網羅できると思います。


本書のサンプルファイルは、インプレスジャパンの書籍ページから「ダウンロードとアフターケア」からダウンロードできます。サンプルファイルだけでも役に立つと思いますので、「本買うほどじゃねーよ」という人も良かったらどうぞ。


http://www.impressjapan.jp/books/3266


どうやら、まだセキュリティの脆弱性のある1.0bをそのまま使っているところもある様子。これを機に(?)是非バージョンアップしてください!
1.1.1を使っている方も別の問題があるので、ご注意。


jQuery Mobileのlocation.hrefのバグに起因するXSSへの対応をjQuery Mobile 1.1.1に適用したビルドを作りました


[2012/08/28追記]
本書のサンプルコード「ホワイトリストで読み込むページを制限する」 (p.304)にて、URLを相対パスで指定する際にチェックを抜ける問題があったので訂正しました。アフターケアにも記載しています。(id:malaさんに問題をご報告頂きました。ありがとうございます!)

(正)サンプル9-3-1: ホワイトリストで読み込むページを制限する

var a = document.createElement('a');
function getPathname(url) {
  a.href = url;
  return a.pathname;
}
$(document).on('pagebeforeload', function(e, data){
  // ホワイトリスト
  var urls = [
    '\/app1\/.*',
    '\/app2\/.*'
  ];
  
  var pathname = getPathname(data.url),
      isValid = false;

  // ホワイトリストと比較
  for ( var i = 0, len = urls.length; i < len; i++ ) {
    var reg = new RegExp('^' + urls[i] + '$', 'i');
    if ( pathname.match(reg) ) {
      isValid = true;
      break;
    }
  }

  if ( !isValid ) {
    console.log('denied', data.url);
    e.preventDefault();
    data.deferred.reject(data.absUrl, data.options);
  }
});

jQuery Mobileのlocation.hrefのバグに起因するXSSへの対応をjQuery Mobile 1.1.1に適用したビルドを作りました

Webkit系ブラウザのlocation.hrefのバグに起因するXSSへの対応をjQuery Mobile 1.1.1に適用したバージョンです。このセキュリティフィックスは、jQuery Mobile 1.2では対応されています。そちらの安定版が出るまでのつなぎとして利用してください。

jquery-mobile-1.1.1-issue-4787-fixed
https://github.com/pikotea/jquery-mobile-1.1.1-issue-4787-fixed


参考
githubのissue
issue #4787


location.hrefのバグについては下記エントリを参照してください。
Masato Kinugawa Security Blog: location.hrefの盲点

jQuery Mobile 1.2の新機能「Fetch Links」を先取りする

本機能は、1.2では見送りになりました。(2012/8/10)

jQuery Mobileの1.1の安定版もまだ出ていませんが、1.2で追加される予定の新機能「Fetch links」が凄く良かったので、紹介したいと思います。(ここで紹介するFetch linksは、jQuery Mobile本家の開発中のブランチを動くように修正したものです。実際にリリースされる際には内容が変わる場合もあります。

Fetch linksは、これまでのようにページ全体をajaxで取得してページ遷移するのではなく、一部のHTMLのみをajaxで取得して指定の要素に埋め込む機能です。この機能を利用すれば、タブやPull to Refresh(リストを引っ張ると更新されるようなUI)のようなものを簡単に作ることができます。


実際の動きは、デモを用意したので、見てもらったほうが早いでしょう。


例えば、あるページのコンテンツ部分だけ、取得して表示したい場合、次ように記述します。

<a href="target.html" data-target="#target" data-fragment="[data-role='content']">取得する</a>

<div id="target">
  ここにajaxで取得した要素が入ります。
</div>

リンクをクリックすると、リンク先のページのコンテンツをajaxで取得してdiv要素に埋めこみます。

リンクに追加した属性は、data-target属性とdata-fragment属性の2つだけです。data-target属性は、埋め込み先の要素をセレクターで指定します。data-fragment属性は、ajaxで取得したデータからどこを切り出すかをセレクターで指定します。これだけで、Fetch linksの機能が利用できます。


Fetch linksの設定を以下にまとめておきます。

属性 説明
data-target 埋め込み先の要素をセレクターで指定する
data-fragment 取得データからどこを切り出すかをセクレターで指定する  :jqmData(role='page')
data-method 埋め込み方法を指定する。 (html/append/prepend/replace/before/after)
data-breakpoint Fetch linksを実行する画面サイズのしきい値。実行しない場合は普通のリンクと同じ扱いになる
(例: 600を指定するとウィンドウサイズが600より大きければ実行する)

Fetch linksでResponsive Web Design

Fetch linksの中でも面白いのが、data-breakpointです。この設定を利用すると、モバイルでは普通のページ遷移になりますが、デスクトップやタブレットだとフレームのように画面の一部のみを別のページで書き換えることができます。次のサンプルはdata-breakpointに600を指定したものです。


リンクボタンをクリックすると、画面サイズに応じて動作が変化します。


画面サイズが600pxより大きい場合、ボタンの下にページが追加されます。


画面サイズが600px以下の場合、通常通りページ遷移します。

Fetch linksを試してみる

jQuery Mobile 1.2のリリースが待てないという方ために、プラグインを用意しておきます。利用方法は、通常のプラグインと同じですが、簡単に説明します。(このプラグインは公式のものではありませんので、自己の責任の範囲で利用してください。)


1. githubからソースをダウンロードする。
https://github.com/pikotea/jquery-mobile-fetchlinks/

2. 解凍して、jquery.mobile.fetchlinks.cssjquery.mobile.fetchlinks.jsをコピーして配置する。

3. Fetch Links Pluginを読み込む

<link rel="stylesheet"  href="http://code.jquery.com/mobile/1.1.0-rc.2/jquery.mobile-1.1.0-rc.2.min.css" />  
<link rel="stylesheet"  href="jquery.mobile.fetchlinks.css" />  
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.1.0-rc.2/jquery.mobile-1.1.0-rc.2.min.js"></script>
<script src="jquery.mobile.fetchlinks.js"></script>

4. リンクにdata-targetなどのFetch linksの設定を追加して試してみる。

ajaxで外部のリソースを読み込むことになるので、取得先のリソースは自分の管理下にあるものに限ったほうが良いでしょう。

まとめ

Fetch linksを利用すると、いろいろな機能に応用することができます。ページ遷移だけでなく、簡単にajaxライクなものができるようになるので、アップデートが楽しみですね。

そろそろjQuery Mobileでajaxを無効にしてるやつに一言いっておくか

jQuery Mobileでは、ページ遷移の際に自動的にajaxが利用されています。特に何もしなくても遷移先のページをajaxで取得してアニメーションをつけて遷移するというのがjQuery Mobileの大きな特徴のひとつになっています。
しかしながら、巷では、何か問題があるとすぐにこのajaxを無効にするという対処方法が蔓延しているようです。ちなみにajaxを無効にする方法というのは、以下のようなものを指します。

  • a要素やform要素に data-ajax="false" を指定する。
  • グローバル設定で $.mobile.ajaxEnabled = false; を設定する。


もちろん、このajaxの挙動を理解した上で、ajaxを無効にするという方法を取ることは何ら問題ないのですが、とにかく困ったらajaxを無効にするということが多いようです。
具体的には以下のようなケースが挙げられるでしょう。

  • ページ遷移が遅いからajaxを無効にする
  • Google AnalyticsAdSenseを入れるためにajaxを無効にする
  • スクリプトが動かない、スタイルが効かないから無効にする
  • 何か問題があると取り敢えずajaxを無効にしてみる


(2012/04/12 追記)
次のパターンも注意が必要なのでこちらに載せておきます。

  • 同一ドメイン上に安全でないリソースがある可能性がある場合

これらのケースについて、個別に対処方法などを解説していきたいと思います。

ページ遷移が遅いからってajaxを無効にしない

よく誤解されがちなのが、ページ遷移が遅いという問題です。たしかに、Android端末では特にCSS周りの実装が怪しく、アニメーションがやばい感じですが、それを除けばajaxを有効にしたほうが確実に早いです。
なぜなら、ajaxでは遷移先のページの最初のdata-role="page"の要素のみを切り出して読み込むからです。head要素内ののscript要素やstyle要素は一切読み込まないため、余計なリクエストは発生しません(まあ、この読み込まないという部分が後述する問題にもなっていますが)。
アニメーションが遅いのであれば、アニメーションをオフにすれば良いだけなので、ajaxとは別に考えましょう。


アニメーションを無効にする

$(document).bind('mobileinit', function(){
  $.mobile.defaultPageTransition = 'none';  
});


また、リンクをタップしてからページ遷移するまで遅いという人は、vclickイベントでページを遷移するようにチューニングしてみると良いかもしれません。Webkit系のブラウザでは、clickイベントなどはdouble tapなどの判定のために、300msほどの待ち時間が発生するので、代わりにvclickイベント使えばすぐに反応するようになります。vclickイベントはtouchイベントとclickイベントを統合したjQuery Mobile仮想イベントです。


vclickイベントでページ遷移する

$(document).delegate('a', 'vclick', function(e){
  e.preventDefault();
  var link = $(this);
  $.mobile.changePage(link.attr('href'), {
    transition: link.jqmData('transition')
  });
});

delegate自体が遅いとか、changePageの引数が足りないとかは自身でカスタマイズして使ってください)

あとは、ページ要素へのdata-dom-cache設定や、リンクへのdata-prefetch設定などもあるので、うまく使ってチューニングしてください。

Google AnalyticsAdSenseを入れるためでもajaxを無効にしない

ページの遷移方法が、通常と異なるために、単純にコードやHTMLを貼りつけただけでは最初のページ以外ではうまく動作しません。これは、下記エントリで既に書いたので、参照してください。Google AdSenseは使ったことないので、なんとか自力で頑張ってください。


jQuery MobileでGoogle Analyticsを使う方法

スクリプトが動かない、スタイルが効かないからってajaxは無効にしない

遷移先のページをajaxで取得して、ページ要素のみを切り取るので、他の部分に記述したスクリプトやスタイルは読み込まれません。そのため、最初に読み込まれるページですべてのスクリプトやスタイルを読み込む必要があります。ページ表示時に発火するpageshowイベントやページのイニシャライズで1回だけ発生するpageinitイベントなど、ページ関連のイベントをうまく使ってください。


pageshow(ページ表示のたびに毎回発生)

$(document).delegate('#page1', 'pageshow', function(){
  // 情報の更新やトラッキングなど
});

pageinit(ページのイニシャライズで1回のみ発生)

$(document).delegate('#page1', 'pageinit', function(){
  // スクリプトによる静的要素の追加やイベントの登録など
});


また、ここで作成した全ページ共通のスクリプトやスタイルを、全ページに埋め込んでおいてください。なぜなら、どのページが最初に読み込まれるからわからないからです。途中のページでブラウザのリロードを実行しまうと、そこが基点になってしまいます。逆に、全ページに埋め込んでも、読み込まれるのは最初のページだけです。他にもどうしても、ページごとに書きたいという場合は、ページ要素の中にスクリプトを書くという手もあります。


スクリプトやスタイルをページ要素に含める

<div data-role="page">
  <script>
    // 何か
  </script>
</div>

何か問題があっても取り敢えずajaxを無効にしない

とりあえず、何か問題があったらバグだと早計する前に、挙動をひとつひとつ確認して対処しましょう。ajax無効にするのであれば、Twitter Bootstrapなどのデザインフレームワークだけを使うとか、もしくは一から作るとかしたほうが良いと思います。(jQuery Mobileはデザインフレームワークだけで使うには巨大なので)


(2012/04/12 追記)

同一ドメイン上に安全でないリソースがある可能性がある場合

ajaxによるページ遷移は、URLから実行することが可能なため、同一ドメイン上に安全でないリソースがある場合は注意が必要です。例えば、ユーザーが自由にアップロードできるフォルダがあるとか、共有ドメインを使ってる場合などです。そういう場合には、pagebeforeloadイベントを使ってチェックしましょう。

$(document).bind('pagebeforeload', function(e, data){
  
  var isValid = false;
  // ホワイトリストなどでajax遷移できるアドレスを制限する
  if ( !isValid ) {
    e.preventDefault();
    data.deferred.reject(data.absUrl, data.options);
  }
});