Ext JS 5 の新機能
Ext JS 5 を公開しました。 Ext JS 5 では Sencha のフレームワークに多くの魅力的な改善が導入され、皆様に新機能、ユーザビリティ、新たなスタイルを提供します。
これから紹介する新機能を追加しつつも、Ext JS 5 へのアップグレードが複雑になってしまわないように配慮しました。 もしアップグレードによっておかしくなってしまった部分があれば、何が変わったのか、どのようにアプリケーションをアップデートするべきなのかを説明する診断メッセージを可能な限り表示するようにしています。 この変更についての詳細は Ext JS 5 アップグレードガイド をご覧ください。
さらに深く調べたい人には、Ext JS 5 のサンプルのページと Ext JS 5 ドキュメントページを参考にしてください。
Ext JS 5 では MVVM アーキテクチャのサポートを導入し、 MVC の (C) も進化しました。 これらの進化を調査しそのアドバンテージを手に入れることを推奨すると共に、 これは重要なことですが、既存の Ext JS 4 の MVC アプリケーションが、変更なしで機能し続けられるように努力しました。
では、新しく追加されたものをいくつか紹介しましょう!
タブレットのサポートと新しいテーマ
Ext JS 5 の目玉となる新機能の1つは、タッチデバイスに対応したことです。 これはタブレットとタッチパネルを搭載したノートパソコンも対象としています。 わずかな変更で、あなたの Ext JS アプリケーションがタッチデバイスでも動作するようになります! これにより、今後は互換性の問題を考えていた時間を機能性の追求に使えるようになります。
Ext JS 5 に二つの新しいテーマが追加されました。Neptune Touch と Crisp です。
Neptune Touch テーマはモダンで無駄のない Neptune のルックアンドフィールをベースに、タッチ環境に最適化してあります。 タップするエレメントのサイズを大きくして、よりタッチしやすいテーマにしました。
Crisp テーマは Neptune Touch をベースに、デフォルトの色、アイコンなどを変更しながらも、タッチしやすいサイズはそのままに作り上げました。 Crisp と Neptune Touch は、独自のカスタムテーマを作成するための優れた起点となり、サイズ、余白、色、フォント、ボーダー、アイコンなどを簡単にカスタマイズできます。
/wp-content/uploads/2014/06/新しいアプリケーション アーキテクチャ – ようこそ MVVM へ
Ext JS 4 では MVC のアーキテクチャパターンのサポートを導入しました。Ext JS 5 では、MVC に代わり人気がある MVVM (Model-View-ViewModel) のサポートを追加しています。 MVVM の最大の魅力はデータバインドでしょう。 データバインドがあれば、モデルをビューに連携するための「接着剤」コードを書いたり、ビューが更新されたときにモデルをアップデートする手間がなくなります。
データバインド
setter メソッドがあるコンポーネントには他のコンフィグを Ext.app.ViewModel( 後述 ) のデータに連携させる新しい “bind” コンフィグがあります。 bind を利用すると、コンポーネントコンフィグが適切に設定されていれば 、バインドされた値が変化する度に、setter メソッドが呼び出されます。カスタムのイベントハンドラーは必要ありません。
bind コンフィグは双方向データバインドも可能としますので、ビューとモデル間でデータのライブな同期が行えます。 ビューで行ったデータ変更は、自動的にモデルに書き込まれて、同じデータにバインドされているコンポーネントを自動的にアップデートします。
ViewController
Ext JS 4 でコントローラーは、ロジックをアプリケーションに適用することを可能とする、全体的なソリューションを提供しました。 Ext JS 5 はビューインスタンスと直接関連できるビュー専用のコントローラーを提供しています。 インスタンス化から破棄まで、Ext.app.ViewController は参照したコンポーネントと結びつけられています。 同一のビュークラスの二つ目のインスタンスは独自の ViewController インスタンスを取得します。
Ext JS 4 MVC アーキテクチャで生成されたグローバル コントローラーはいままで通り動作しますが、ViewController を作ればさらに良くフィットします。 特にイベントとコンポーネントの参照の連携がシンプルになりますので、状態の管理やメモリリークなどの心配をせずに、アプリケーションの開発に集中できます。
reference と listeners
ViewController の最大の利点の一つは、コンポーネントが複数のコンテナのレイヤに分かれていても、大規模なアプリケーションがそのコンポーネントとイベントを連携するのに役に立つところです。 例えば、次のようにビューにはコンテナにたくさんの項目がネストされているかもしれません:
... items: [{ xtype: 'textfield', reference: 'someField' // this is new }], ... items: [{ xtype: 'button', text: 'Delete, listeners: { click: 'onClickDelete' // also new (no "scope" here) } }] |
ViewController があると、テキストフィールドにアクセスしながら、クリックイベントを扱うのがとても簡単になります
Ext.define('App.view.foo.FooController', { extend: 'Ext.app.ViewController', onClickDelete: function (deleteButton) { var someField = this.getReference('someField'); Ext.Msg.confirm('Confirm Delete', 'Are you sure you want to delete ' + someField.getValue(), 'onConfirm', this); }, onConfirm: function (choice) { // 'yes' または 'no' の処理 } }); |
Ext JS 4 の Component Query を使った refs や listeners と比べて、新しい Ext.app.ViewController のスリム化された形式は、連携がよりわかりやすくなります。 この連携も ViewController にカプセル化されているので、より安全になります。ビューの中に他のビューを入れ子する場合には、二つのビューのリスナーと参照はお互いから切り離されているので、それぞれの ViewController に連携するだけです。
ViewModel
Ext.app.ViewModel はデータオブジェクトを管理するクラスで、このデータに関与するものにバインドして、データに変更があった場合に通知されます。ViewController と同じように、ViewModel は参照するビューに所有されています。 ViewModel はビューと関連しているので、コンポーネント階層で親コンポーネントが所有している親 ViewModel にも連携できます。これにより、子のビューが親 ViewMode のデータを継承できます。
ViewModel はクラスなので継承されます。 主要な役割はビューにデータを提供することなので、このタスクをシンプルにするために、ViewModel が提供する二つの機能があります。”formulas” と “stores” です。 派生クラスにはデータの操作をカプセル化するために他の便利なメソッドを追加できますが、formulas と stores は ViewModel 専用です。
Formulas
データを保持したり、バインドしたりする以外に、Ext.app.ViewModel は “formulas” と呼ばれる、他のデータからデータを計算する便利な方法も提供します。 Ext.app.ViewModel-cfg-formulas は ViewModel でデータの依存性をカプセル化して、ビューは構造の宣言に集中できます。従来のデータモデルのフィールドの変換設定の動きと似ています。
Stores
ViewModel は指定されたビューに提供されるバインド可能なオブジェクトとして stores を定義することもできます。 formulas と同じく、ビューが構造を自由に宣言できるようになり、 複雑なストア定義が散乱することなく、独自のストアインスタンスを持っていることも確保できます。
サンプル
ビューは次のようになります
xtype: 'grid', bind: { title: 'Summary for {fullName}', store: '{summary}' } |
ビューのシンプルな ViewModel は次のようになります:
Ext.define('App.view.summary.SummaryModel', { extend: 'Ext.app.ViewModel', formulas: { fullName: function (data) { return data.firstName + ' ' + data.lastName; } }, stores: { summary: { source: 'allSummaries', // グローバルストアとチェーンする filters: [{ property: 'fullName', value: '{fullName}' }] } } }); |
上のサンプルはストアが他のストアとチェーンできて、 独自のフィルター (あるいはソーター) を適用できることを示しています。 チェーンドストアの詳細については、後述します。 ごらんのように色々行っているようですね。 これは ViewModel はさらに一歩進みますので、上記のフィルターの様に動的な値に反応するように、ストア コンフィグをバインドとして処理します。
一緒に利用する
Ext JS 5 では、ViewControllers を利用して、ビューとの連携をより簡単にすることで、既存の MVC アーキテクチャを改善できます。
また、ViewModel を利用すれば、ビューとデータ間の接続を自動化して、さらにそのデータを操作するためのメソッド (MVVM では “commands” と呼ばれることがあります) も提供できます。
Ext JS 5 はどちらもサポートしているので、一緒に利用することもできます。
これは対象物の分離を維持するときにとても役に立ちます。新しいビューを生成するイベントがトリガーされる場合や、ルーティングアクションを行う場合、または View や ViewModel では本来無視したいものに集中する必要があるときには特に有用です。
ルーティング
Ext JS 5 ではアプリケーション内に「ディープリンク」することが可能になるルーティングを実装しました。 これはアプリケーション URL をコントローラーアクションとメソッドに変換して実現します。
Sencha Touch のルーティングは、アプリケーション内で特定の状態にリンクすることが可能でした。 しかし、Ext JS のアプリケーションは複雑なので、Ext JS ルーターは一つの URI で複数のルートに対応します。 各ルートはサンドボックスになっているため、さらに柔軟性のあるアプリケーション管理ができます。
ルートの実行は before 関数を利用して管理できます。この関数は実際にルーティングが行う前に発火しますので、アクションの前に適切なバリデーションが行えます。このため、現在のルート、もしくは他の順番待ちのルートを止めることができますし、または Ajax リクエストが返ったときなどのアクションの後にルートの実行を続けることができます。
ルーティングに関する詳しい情報は Routing Guide をご覧ください。
Responsive Configs
Ext JS アプリケーションの外観は、コンポーネントのコンフィグオブジェクトで指定されます。 新しいデータバインディングシステムシステムは、コンフィグに基づきますが、”responsiveConfig” と呼ばれる新しいメカニズムを用いたコンフィグで管理することもできます。 responsiveConfig は、ルールとそれに当てはまるコンフィグ値のセットで、ルールが真になったときに適用されます。 たとえば:
Ext.create({ xtype: 'viewport', layout: 'border', items: [{ title: 'Tools', region: 'north', plugins: 'responsive', responsiveConfig: { tall: { region: 'north' }, wide: { region: 'west' } } }, { title: 'Center', region: 'center' }] }); |
レスポンシブルールを判定する沢山の動的な値が利用可能です、 例えば、”tall” (ビューポートの幅より高さの方が大きい) 、 “portrait” や “landscape” さらにはビューポートの “width” や “height” などがあります。 ルールは、これらの値を用いた任意の式が使えます。
responsiveConfig: { 'width < 600': { region: 'north' }, 'width >= 600': { region: 'west' } } |
動的条件によりレスポンシブである必要が無い場合でも、responsiveConfig は mixin や plugin すべてのコンポーネントが動的な条件にレスポンシブ反応する必要があるというわけではないので、responsiveConfig は、mixin または plugin として、必要とするクラスまたはインスタンスに加えることができます。
データパッケージの改善
共通データ
デスクトップとモバイル向けにアプリケーションを開発しているユーザーからは、Ext JS と Sencha Touch のパッケージのマージをよく要求されます。 Ext JS 5 では Ext.data を新しい Sencha Core パッケージ (下記をご覧ください) に移動して、この要求に応えました。このマージで、双方の世界でメリットを提供するための素晴らしい改善もいくつか追加しました。
モデル
通常のアプリケーションには様々なモデルの種類があって、何千ものレコードを生成する必要があるかもしれません。 Ext JS 5 では、生のデータオブジェクトからレコード作成やID生成を行う仕組みをできるだけスリム化しました。
モデルコンストラクタは渡されたデータオブジェクトからフィールドを抽出して、定義したフィールドのデフォルト値や converter に基づいて、アップグレードします。 このため、レコードに残したいフィールドを全て定義する必要はもうありません。 サーバーが正確な形式でデータを送るかぎり、そのプロパティはレコードのデータオブジェクトに残ります。 この宣言されてないフィールドは永続化されるため、変更が追跡されてサーバーへ保存されます。
Associations
シンプルになったアノテーション
Ext JS 5 ではフィールド定義に “reference” コンフィグを追加し、関連を宣言する処理をよりシンプルにします。 reference コンフィグは一対一や一対多のアソシエーションを簡単に宣言できます。
例えば:
Ext.define('App.model.Comment', { fields: [ { name: 'userId', reference: 'User' } ] }); |
アソシエーションの様々なオプションは reference コンフィグのオプションとして指定できます。 リンク値があるフィールドに reference を利用すると、この連携を個別に指定する必要はありません。 さらに、両サイドで必要だった “belongsTo” と “hasMany” を宣言する必要もありません。
多対多のアソシエーション
Ext JS 5 は Ext.data.schema.ManyToMany のサポートも追加しました。 よくある多対多の状況といえば Users と Groups があるフォーラムです。あるユーザーは複数のグループに所属しているかもしれませんし、グループには多勢のユーザーがいます。 多対多のアソシエーションはどちらのクラスでも (または両方で) 行うことができます。
Ext.define('App.model.User', { extend: 'Ext.data.Model', fields: [{ ... }], manyToMany: 'Group' }); |
他のアソシエーションと同じく、Store によって表現されます。多対多の特殊な点は、Ext JS が対称性を維持していることです。 例えば、ユーザー A の groups ストアに Group G のレコードを追加した場合には、ユーザー A のレコードは Group G の users ストアにも追加されます (削除する時にはその逆になります) 。
チェインドストア
Ext JS では、ストアは二つの大事な (時に矛盾する) ことを提供します。 一つ目は、データレイヤーで、サーバーから取得した情報に対するクライアントの「記録システム」となります。 二つ目は Grid や DataView などのコンポーネントが情報を表現することです。 以前のバージョンでは、1つのストアが複数のコンポーネントで読み込まれているとき、どのように管理するかが課題になっていました。 問題点は、各コンポーネントが表示するデータを並べ替えたりフィルタリングを行うと、そのストアを共有しているコンポーネント全てに影響を与えてしまうことでした。
Ext JS 5 のチェーンドストアでは、この同期を自動化できます。 チェインドストアは、レコードのセットを定義する “source” ストアを持つストアです。 チェインドストアはフィルター、ソーター、グルーパーを適用して、ソースストアのレコードを独自の並び順で定義できます。 レコードがソースストアで追加、削除、変更されると、チェーンドストアと関連しているビューが適切に応答します。
チェインドストアは ViewModel でさらに自動化されますが、直接生成するのも簡単にできます。 チェインドストアはソースストアのレコードを再使用するため、メモリやサーバー呼び出しも節約できます。
データセッション
Ext JS 4 でサーバーにレコードを保存していた時は、それぞれのオブジェクトを保存する順番に注意する必要がありました。 また、変更したストアとレコードに全て save を呼び出すことに気をつける必要がありました。 これらはデータを調整する際にエラーを起こす機会となりました。
Ext JS 5 ではこれらの動作を全て管理するクラスがあります。 Ext.data.Session です。 セッションがサーバーでアップデート、生成、破棄する必要があるレコードを追跡します。 また、新しく生成されたレコードが他の新しいレコードを、新しくサーバーに割り当てられた ID で正しく参照するように順番を変更します。
セッションは、あるモデルクラスの特定の ID への全ての参照は同じレコードをさしていることを確保します。 その Model/id に関する全ての関連するストアは同じレコードインスタンスを共有しています。 そのため、そのレコードの編集は全て一箇所にあることが確保されます。 Sencha Touch の ModelCache とは違い、Ext.data.Session は自分で生成できます。 例えば、多のページから独立させるために、モーダルウィンドウの新しいセッションを生成するといったことができます。
セッションを使えば、レコードとそのアソシエーションを簡単に編集でき、更新を全てまとめて、サーバーにコミットできます。 セッションが全ての編集を追跡しているため、全ての変更を一度に取得し、カスタマイズされた方法でサーバーに送信できます。
Heterogeneous Store (異種ストア) と TreeStore
Ext JS でツリーはいつでも人気があったため、Ext JS 5 では、複数のタイプのノードを持つツリーを読み込む方法を提供することで、さらにツリーを進化させました。 最初の、そして最も柔軟なオプションは Ext.data.reader.Reader-cfg-typeProperty コンフィグです。 このプロパティは、ノードに生成するために読み込まれたデータからモデルタイプの名前を抽出するために使用されます。 これは reader のコンフィグなので、どのストアでもレコードタイプをミックスできます。
ツリーは、別の方法でもレコードタイプを解決できます。 Ext.data.TreeModel-cfg-childType プロパティです。 このプロパティはツリーのどのノードでもありますので、どのタイプの子ノードを生成するか指定します。
このため、ツリーの各レベル、そしてノードごとのModel クラスは違ったタイプでも問題ありません。 ツリーの中で関連付けられているが異なったデータタイプを使用することを可能としています。
カスタムフィールドタイプ
データモデルによくある課題はフィールドのバリデーションです。 バリデーションは各フィールド固有なものになることがよくあります。 (例えば:メールアドレス) Ext JS 5 では値をバリデーションするカスタムフィールドクラスを定義できますので、全てのモデルクラスにそのルールを繰り返し書く必要はありません。 例えば:
Ext.define('App.fields.Email', { extend: 'Ext.data.field.String', // converterを継承 alias: 'data.field.email', // フィールドタイプとして使う validators: 'email' }); Ext.define('App.model.User', { extend: 'Ext.data.Model', fields: [{ name: 'emailAddress', type: 'email' }] }); |
このようにクラスとしてフィールドオプションをいくつでも使うことができ、そのクラスを Models で利用できます。
モデルバリデーションのバインド
フィールドだけではなく、Model もバリデーションできるようになりました。 ViewModel を使用する簡単な方法は、結果が表示されるフォームに接続することです。 これを行うためには、一つのコンフィグをフォームに追加するだけです。
modelValidation: true, items: [{ xtype: 'textfield', bind: '{user.name}' },{ xtype: 'textfield', bind: '{user.emailAddress}' }, ... |
Ext.Component-cfg-modelValidation コンフィグは継承されたプロパティで、コンポーネント階層でその位置より下の子アイテムに適用されます。 入力フィールドはこのオプションに従って、新しい “validation” アソシエーションを利用して、値バインドから追加のバインドをリクエストします。 つまり、”modelValidation” オプションなしで、上記のコードを次のように (冗長に) 作成できます。
items: [{ xtype: 'textfield', bind: { value: '{user.name}', validation: '{user.validation.name}' } },{ xtype: 'textfield', bind: { value: '{user.emailAddress}', validation: '{user.validation.emailAddress}' } }, ... |
イベントシステム
Ext JS 5 のイベントシステムは大きく変化し、直接アタッチされた DOM リスナーから Sencha Touch で最初に実装された “delegated” イベントモデルに移行しました。 このため、各イベントの種類 (mousedown, touchstart など) に対して、DOM 階層の最上部に単一のリスナーが割り当てられます。 DOM エレメントがイベントを発火すると、ハンドリングされる前に最上部まで上がっていきます。 次にフレームワークは Element API を利用して追加したリスナーに、送信予定のシーケンスをシミュレーションします。
このアプローチには少し複雑な部分もありますが、重要なメリットを持っています。 まず、これは特に古いブラウザで重くなる DOM とのやりとりを減らすことができ、さらにジェスチャーを利用できるようになります。
ジェスチャー
Sencha Touch では、最初にブラウザでネイティブに生成されないハイレベルな「イベント」をアプリケーションに提供するジェスチャーシステムを導入しました。例えば tap、rotate、swipe などです。Ext JS アプリケーションに適切なタッチ操作を提供するために、このサポートはとても重要なものです。
Ext JS はデスクトップアプリケーションを中心としていましたので、マウス入力をジェスチャーとして認識させることを可能にするために、さらに改善する必要がありました。 このマッピングがあるため、アプリケーションの click リスナーを全て tap にしたり、 mousedown を touchstart に編集したりする必要はありません。 Ext JS 5 のマッピングのレイヤーはこのようなイベントまで拡張し、各デバイスに最も近いマッピングを提供しています。
Sencha チャート
Sencha Touch 2.1 では、ハイパフォーマンスでタッチ操作に最適化された新しいチャートパッケージを公開しました。 Ext JS 5 では、このチャートパッケージが Ext JS と Sencha Touch で動作するようになりました。 これはタブレットデバイス上で、多くの新機能と素晴らしいパフォーマンスを発揮します。
Ext JS 4 のチャートは別のパッケージにコンバートされましたので、引き続き利用できます。これはExt JS 5 への移行作業を軽減するためです。 新しいチャートパッケージへのアップデートは、ext-charts パッケージを新しい sencha-charts パッケージに切り替えるだけです。 ほとんどの API は同じで、変更されたものついては Upgrade Guide で説明されています。
新しいチャートパッケージには次の新機能を追加しています
- ローソク足チャート と OHLC シリーズ
- パン, ズーム, 十字線の相互作用
- Floating アクシス
- Multiple アクシス
- SVG と HTML Canvas をサポート
- パフォーマンスの向上
- さらに自由なカスタマイズ
これまでの Ext JS チャートはレガシーサポートのために、少なくとも Ext JS 5.1 まではフレームワークに残ります。 ただし、そのチャートは Sencha Charts に含まれている新しい機能は利用できません。
タブパネル
Ext JS 4.2 では、タブ・バーをタブパネルの左または右に置けるようになりました。 Ext JS 5 では、アイコンの配置やテキストの向きなど、タブパネルのより多くの部分をコントロールできます。 タブ・バーをパネル・ヘッダと一緒にするように設定して、スペースを節約することさえできます。 柔軟で新しい Sass の mixins とあわせて、多くの表示オプションを簡単にコントロールすることができ、素晴らしい結果を作ることができます。
これらを “responsiveConfig” コントロールと合われば、 あなたは新しいダッシュボードサンプルのようなアプリケーションを素早く作ることができます。
グリッド
セル内のコンポーネント
Ext JS で要望の多かった機能はグリッドにコンポーネントを簡単に追加できるようにすることで、これは Ext JS 5 では可能になりました。 Widget Column が登場しました! 新しい Ext.grid.column.Widget に component、もしくは、widget (次のように) コンフィグを追加でき、そのアイテムは template として扱われ、カラムに表示されている各セルごとに一つのインスタンスを生成します。 それを bufferedrenderer プラグインと組み合わせると、大規模のグリッドでも問題なくコンポーネントやウィジェットをレンダリングできます。
バッファードアップデート
データのアップデートの届くペースが早すぎて、DOM があふれてアプリケーションが反応しなくなる場合がたまにあります。 バッファード アップデートのおかげで、アップデートが DOM に反影される速度を設定できます。 このアップデートは少ないサイクルを利用するため、より反応が良くなります。
セルアップデーター
renderer はセルのカスタムマークアップを簡単に生成する方法です。 しかし、renderer はクラス名などのセルの異なる部分にも多く影響するため、そのようなセルを変更するとなると非効率的になります。
新しいセル updater はカラムに提供できるオプションのメソッドです。 この updater はセル全体に作用し、値が変更されたら、 DOM をアップデートするために呼び出されます。 このため、 renderer のアクションに関する知識を使って、より効率的にセルの DOM を更新できます。
レンダリングの最適化
グリッドは高速なほど良いので、Ext JS 4.2 で新しく最適化したグリッドを再びプロファイリングして、どうすればもっと高速化できるか検討しました。 結果として、グリッドの各行を独自のテーブルに分解すると、ブラウザへのリフローコストを大きく削減できることがわかりました。
これで、バッファードレンダリングがさらに効率的にスクロールの最後から行を削除できます。 同じように、新しい行を追加するときには、既に存在している行はリフローする必要はありません。 グリッドやスタイリングされたグリッド行にレンダリングのパイプラインを拡張しない限り、この変更は検出されないはずです。
ウィジェット
完全なコンポーネントと renderers/updaters の中間として、Widget でセルの表示をカプセル化することができます。 Widget は低コストで生成できる軽量コンポーネントです。 なぜなら、Widget は通常の Ext.Component の完全なライフサイクルを持たないからです。
Ext.Widget はオブジェクトテンプレートから DOM を生成するのに必要な仕組みと、自身と生成するエレメントにイベントを送信することを提供しています。 これは Sencha Touch のコンポーネントと同じく、全てコンフィグシステム上に構築されています。 Widget であなたのカスタムセル表示を実装すれば、他のグリッドでコードを再利用できますし、その他に mouse over のようなイベントにも反応できます。
Ext JS 5 に新しいウィジェットがいくつか含まれています。 その中の二つ (プログレスバーとスライダー) は既存コンポーネントの軽量版です。 最も刺激的な新ウィジェットは sparkline です。 Sparkline は最小限のサイズで値を表現する、とてもコンパクトなチャートで、グリッドを活かせます。
もちろん、自分のウィジェットを作成するのも非常に簡単なので、可能性は無限大です!
パンくずリスト
画面が狭いときには、 Ext.data.TreeStore の内容をツールバーフォームファクターに表示する方法ができました。 新しい、 Ext.toolbar.Breadcrumb は Kitchen Sink でデモをご覧になれます。
Ext.tree.Panel と較べて、パンくずリストではタブレットでのスペースを節約できます。
フォームパッケージの改善
Tagfield
新しい “tagfield” (Ext.form.field.Tag) は長くて、不規則なセレクトオプションを扱う手間をなくしてくれます。 picker 内でその選択された状態を保つのではなく、選択されたリストは値表示エリアで目に見える形でキープされます。 そこから選択された tags を簡単に削除・検索・追加されます。
セグメンテッドボタン
モバイルで複数からの選択を表現するやり方を提供します。 Ext.button.Segmented です。 セグメンテッドボタンは横方向にも配置できますし、
縦方向にも配置できます。
これらは Ext.button.Button の完全なインスタンスなので、icon、glyph、menus などが使えます。
テキストフィールドトリガー
テキストフィールドにはトリガーを設定でき、そのトリガーは簡単に表示/非表示を切り替えられます。 Ext JS 4 では、 TriggerField のクラスだけがトリガーを持っており、そのトリガーは融通のきかないものでしたが、Ext JS 5 は、次のようにどの TextField にもトリガーを簡単に追加できます:
Ext.create('Ext.form.field.Text', { renderTo: Ext.getBody(), fieldLabel: 'My Custom Field', triggers: { foo: { cls: 'my-foo-trigger', weight: 1, // controls display order handler: function() { console.log('foo trigger clicked'); } }, bar: { cls: 'my-bar-trigger', handler: function() { console.log('bar trigger clicked'); } } } }); |
triggers コンフィグは、オブジェクトで、キーはトリガーのユニークな名前で、値は新しい Ext.form.trigger.Trigger クラスのコンフィグオブジェクトを受け入れます。 このため、各トリガーは同じ API に従い、次のようにそれぞれのトリガーで show/hide などのアクションを行えます
myField.getTrigger('foo').hide(); |
その上、Ext.form.trigger.Trigger はクラスなので、拡張して Ext.form.trigger.Spinner のような高度なトリガーを作成できます。
フィールドレイアウト
フォームフィールドは幅広いレイアウトオプションをサポートしています。 以前は、IE6 や IE の quirks モードに対する需要があり、HTML と CSS のみを利用して、望んだレイアウトの全てをフォームフィールドで実現することはできませんでした。 そのため、ブラウザから出来るだけアシストを受けるために、Ext JS 4.1 ではもっと上品な div ベースのフォームフィールドからテーブルに切り替えました。 しかし、最終的には、JavaScript がまだフィールドのレイアウトに深く関わる必要があったので、パフォーマンスが悪くなってしまいました。
Ext JS 5 でサポートされている最も古いブラウザは strict モードの IE8 になっているため、HTML と CSS だけで管理されている div ベースのフォームフィールドの夢を実現できました! その結果、フォームフィールドのレンダリングとレイアウト処理をリファクタリングし、フィールドの内部的なエレメントの位置とサイズに JavaScript が関わらなくなりました。
レイアウトフリーのコンテナ
新しいフォームフィールドと「リキッドレイアウト」動作の子アイテムと対話する必要がないコンテナレイアウト (auto や form ) を組み合わせると、大きなメリットがあります。 そのメリットとは Ext JS 5 のレイアウトエンジンがそのコンポーネントを完全にスキップできることです!
form レイアウト
auto コンテナのレイアウトは長い間 Ext JS に入っていましたが、form レイアウトの歴史は興味深いものがあります。
Ext JS 3 では、ラベルをつけたい場合は、form レイアウトが必須条件でした。 Ext JS 4.0 では、ラベルはフォームフィールドが所有し、form レイアウトの役割がありませんでした。 Ext JS 4.1 では、フィールドが独自のラベルを管理することに頼りながら、新しい form レイアウトを導入して、二つ重要な問題を解決しました
- ラベルは同じ幅であるべき
- フォームフィールドはフォームの幅と一致させるためにストレッチされるべき ( anchor レイアウトのように)
当時のフォームレイアウトは大きな HTML テーブルに行とセルそれぞれに、フォームフィールドをマークアップして変換していました。 この代償として、フォームレイアウトは余り注目されませんでした。
しかし、Ext JS 5 では、テーブルである必要はありませんので、フォームパッケージで最も望まれているユースケースを解決することができました。 ラベルサイズの自動調整です! このため、フォームレイアウトはラベルの幅を指定しなくても、最も長いラベルの幅に合わせます。
Ext.layout.container.Form はローカライズや動的なアプリケーションにおいて、前もってラベルのテキスト幅が分からない状況で効果がわかると思います。 全ての items の labelWidth を指定するには、form レイアウトで設定します
layout: { type: 'form', labelWidth: 90 }, items: [{ ... |
form レイアウトの以前のバージョンからアップグレードする時に、これは動作の変更であることに注意して下さい。 form レイアウトでの items の labelWidth は無視されます。
ダッシュボード
以前のリリースでの Portal サンプルはよく模倣されたユーザー体験でした。 しかし、実際のアプリケーションを作成するための具体的なサンプルとしては足りないものでした。
改善された Portal は新しい Ext.dashboard.Dashboard コンポーネントをベースにしています。 このコンポーネントとヘルパークラスはかっこいいアプリケーションのより優れたスタートポイントを提供しています。 例えば、サイズ変更が可能なカラム、空カラムのクリーンアップ、ドラッグ&ドロップによるカラム生成、アイテムの永続化などがあります。
もしあなたのアプリケーションがダッシュボードやポータルではなかったとしても、きっと役立つ機能が導入されています。マッシュアップです。
新しい SASS ミックスイン
バージョン 4 で UI mixins を持たなかったいくつかのコンポーネントのスタイルを整えるために、Ext JS 5 は、新しいSASS “UI” ミックスインを追加します。 過去のリリースにおいては、これらのコンポーネントは、グローバル変数 (テーマまたはアプリにつき1つの視覚の処置) のみを使用して、スタイルを設定できるだけでした。 これらの新しいミックスインでは、コンポーネントが一つのテーマまたはアプリで複数の方法でスタイリングできるようになります。
- Ext.menu.Menu – extjs-menu-ui()
- Ext.form.Labelable – extjs-label-ui()
- Ext.form.FieldSet – extjs-fieldset-ui()
- Ext.form.CheckboxGroup – extjs-checkboxgroup-ui()
- Ext.form.field.Text – extjs-text-field-ui()
- Ext.form.field.Spinner – extjs-spinner-trigger-ui()
- Ext.form.field.Display – extjs-display-field-ui()
- Ext.form.field.Checkbox – extjs-checkbox-ui()
マルチセレクトグリッド
以前の “Multi-Item Selector” サンプルを少し変更して、新しいコンポーネントを追加しました。 この新しいコンポーネントで、選択した項目の大きなリストを簡単に管理できるだけでなく、さらに大きな選択肢のリストを効率的に検索できるようになりました。
Ext.mixin.Mashup
この mixin はターゲットクラスに新しいコンフィグプロパティ Ext.ux.google.Api-property-requiredScripts を追加します。 このプロパティには Mashup が読み込む URL の配列を指定します。 Mashup はクラスシステムとローダーのやりとりを管理して、requiredScripts がクラス生成のコールバックやアプリケーションが起動する前に読み込まれることを確保します。
ポータルは二つのヘルパークラス経由で 間接的にMashup を利用します。何かできるのか下記にいくつかのコードスニペットを紹介します
Ext.define('Ext.ux.google.Api', { mixins: [ 'Ext.mixin.Mashup' ], requiredScripts: [ 'http://www.google.com/jsapi' ], ... }); |
Ext.ux.google.Api クラスは その派生クラスにさらに高レベルのプロパティ Ext.ux.google.Feeds-property-requiresGoogle を与えるために Mashup を利用します:
Ext.define('Ext.ux.google.Feeds', { extend: 'Ext.ux.google.Api', requiresGoogle: { api:'feeds', nocss : true } }); |
内部的には、Google loader は request を処理するために Ext.ux.google.Feeds を使用し、Feeds クラスは “feeds” モジュールをリスト表示します。 現在は Ext.ux.google.Feeds が必要なクラス全てで google.feeds の API が使用可能となっています。
Sencha Core Package
このパッケージは Ext JS 5 と Sencha Touch の次のメジャーバージョンリリースが共有するコアコードが含まれています。 このパッケージには次のものが含まれています。
- クラスシステム
- データ
- イベント
- エレメント
- ユーティリティ
- 機能/環境の検出
この共有クラスのおかげで、どのフレームワークでも多くのリソースを共有するアプリケーションがつくれます。
コンフィグシステム
Ext JS 5 は Sencha Touch のクラスのようなコンフィグシステムに切り替えていくのかどうか、これはよく質問されます。 簡単に答えるならば「ある程度」です。 この質問の意図はたいてい「コンフィグシステムは違ったシンタックスなのに、どうやってクロスフレームワークのコードを記述するのですか?」です。
まず、Ext JS 5 でのコンポーネントはいくつかのコンフィグにコンフィグシステムを利用しますし、起動時の動作をさせるためにコンストラクタで initConfig を呼び出しています。 これは以前 initConfig を自分で呼び出していたカスタムコンポーネントには影響があります。
より重要な課題に対処するために、API を壊す変更を導入せずに、コンフィグシステムを少しずつ利用できるようチューニングしました。細かくは説明しませんが、次の派生クラスを作成するときに大きなメリットが見えます
ベースクラスで定義されたコンフィグプロパティを設定するとき、そのコンフィグはもう config オブジェクトで包む必要はありません。
新しいコンフィグプロパティを宣言するには、まだ “config: {}” が必要ですが、派生クラスでは直接これをクラスボディにセットできます。 このアプローチで、ベースクラスがコンフィグシステムを利用するように切り替えても、派生クラスの互換性を保つことができます。
結果的に、コンフィグシステムが利用されている場合でも、コンフィグシステムが使用されてない Ext JS 4 のために作成されたクラスは Ext JS 5 でも互換性があるということになります。
互換性とアップグレード
Ext JS 5 では、既存のコンポーネントとクラスに新機能の追加と改善するとき、出来る限り後方互換性を維持するようにバランスをとろうとしてきました。
アップグレードをアシストするために、二つのクラスシステムレベルのメカニズムを追加しました。 両方とも Sencha Cmd でビルドから取り外されます (既に構築されているフレームワークを利用しているなら、ext-all.js には存在していません) 。
互換性レイヤー
変更によりアプリケーションが動作しなくなるす可能性がある部分には、フレームワークに直接統合されている互換性レイヤーを追加しました。 一つのオプションをセットすれば、スクリプトの追加や削除をすることなく、互換性レイヤーを有効にできます。
互換性レイヤーを有効にすると、フレームワークは以前のバージョンのように動作し、同時に (対応するブラウザでは) 非推奨のメソッドと廃止されたプロパティが使用われていることを診断メッセージで通知します。
private メソッド
Ext JS のような堅牢なフレームワークを利用している時に、よくある失敗は間違ってプライベートフレームワークメソッドを隠してしまうことです。 JavaScript では、全てのオブジェクトプロパティがパブリックなので、この間違いを指摘する組み込みの実行時の保護はありません。 その上、プライベートメソッドとの衝突を 100% 回避できたとしても、新しいリリースごと (特にメジャーバージョンの公開時) にクラスメソッドでさらに新しい衝突が生まれる可能性があります。
この衝突を明らかにするために、クラスシステムに “privates” を追加しました。 次のように利用します。
Ext.define('Ext.Component', { ... privates: { foo: function () { } } }); |
もし派生クラスがこのようにメソッドをオーバーライドすると、コンソールでエラーが発生します:
Ext.define('MyComponent', { extend: 'Ext.Component' ... foo: function () { } }); |
これが意図的なオーバーライドであるなら、Ext.Component と同じように関数を “privates” で包みましょう。
はじめましょう
下記から、Sencha Cmd 5 のダウンロードや、既知の問題点をリリースノートでチェックできます。
あたらしい、 Sencha Cmd 5アップグレードガイド で詳細を確認するようにしてください。
すでに Sencha Cmd 5 をお使いでしたら、次のコマンドで最新版に更新できます。
sencha upgrade |
Sencha Cmd をインストールして、ターミナルを再起動します。
また、SDK を自動的にダウンロードして、Ext JS 5 アプリケーションを生成できます。
sencha generate app -ext MyApp ./app cd app sencha app watch |
既存のアプリケーションの場合には次を実行してください。
cd /path/to/app sencha app upgrade -ext sencha app build |