/**
* パネルは、アプリケーション志向のユーザーインターフェイス用の完全なビルディングブロックを作成する、特定の機能および構造コンポーネントを持つコンテナです。
*
* パネルは、{@link Ext.container.Container}からの継承によって{@link Ext.container.Container#layout layout}を設定し、子コンポーネントを含めることができます。
*
* パネルの子{@link #cfg-items}を指定する場合、またはコンポーネントをパネルに動的に{@link Ext.container.Container#method-add 追加する}場合、パネルに子要素をどのように配置するか、そして、Extのビルトイン`{@link Ext.container.Container#layout #layout}`スキームを使用して子要素のサイズを調整する必要があるかどうかを必ず検討するようにします。デフォルトでは、パネルは{@link Ext.layout.container.Auto 自動}スキームを使用します。これは、単に子コンポーネントをレンダリングして、コンテナの内部に順に追加するだけで、**サイズ調整は全く行いません**。
*
* {@img Ext.panel.Panel/panel.png Panel components}
*
* パネルには、別々の{@link Ext.panel.Header ヘッダー}、{@link #fbar フッター}、ボディ部分とともに{@link #bbar 下部}および{@link #tbar 上部}ツールバーも含まれます。
*
* パネルはまた、組み込みの{@link #collapsible 折りたたみ、展開が可能}で、{@link #closable}の動作も備えています。パネルは、{@link Ext.container.Container コンテナ}に簡単にドロップすることができ、レイアウトと描画するパイプラインは、{@link Ext.container.Container#method-add 完全にフレームワークによって管理されています}。
*
* **注意:**デフォルトでは、`{@link #closable 閉じる}`ヘッダーツールにより、パネルの削除および下位コンポーネントの削除の結果、パネルが_削除されます_。このため、パネルオブジェクトおよびその下位パネルは**使用できなくなります**。閉じるツールを有効にするには、パネルを後で再利用できるように_非表示_にし、パネルを`{@link #closeAction closeAction}:'hide'`に設定します。
*
* 通常、パネルはアプリケーション内にあるものとして使用されますが、この場合はパネルはコンテナの子アイテムとして使用され、自身を子{@link #cfg-items}としてExt.Componentsを使用します。ただし、文書へパネルの描画を単純に図示するには、以下のようにします:
*
* @example
* Ext.create('Ext.panel.Panel', {
* title: 'Hello',
* width: 200,
* html: '<p>World!</p>',
* renderTo: Ext.getBody()
* });
*
* より現実味のあるシナリオにするには、描画されない入力フィールドを駐在させるために作成したパネルを、コンテナの一部として存在するものとして使用することです。
*
* @example
* var filterPanel = Ext.create('Ext.panel.Panel', {
* bodyPadding: 5, // Don't want content to crunch against the borders
* width: 300,
* title: 'Filters',
* items: [{
* xtype: 'datefield',
* fieldLabel: 'Start date'
* }, {
* xtype: 'datefield',
* fieldLabel: 'End date'
* }],
* renderTo: Ext.getBody()
* });
*
* 上記のパネルは、文書内に割り当てられたサイズで描画されるように設定するよう注意してください。現実のシナリオでは、パネルは、子コンポーネントを描画し、サイズおよび位置調整を行うために{@link #layout}を使用するコンテナの内側に追加されることがよくあります。
*
* パネルは、特定の{@link #layout}を使用し、子コンポーネントを含み配置することによって、形や構造をもったアプリケーションを作成します。
*
* @example
* var resultsPanel = Ext.create('Ext.panel.Panel', {
* title: 'Results',
* width: 600,
* height: 400,
* renderTo: Ext.getBody(),
* layout: {
* type: 'vbox', // Arrange child items vertically
* align: 'stretch', // Each takes up full width
* padding: 5
* },
* items: [{ // Results grid specified as a config object with an xtype of 'grid'
* xtype: 'grid',
* columns: [{header: 'Column One'}], // One header just for show. There's no data,
* store: Ext.create('Ext.data.ArrayStore', {}), // A dummy empty data store
* flex: 1 // Use 1/3 of Container's height (hint to Box layout)
* }, {
* xtype: 'splitter' // A splitter between the two child items
* }, { // Details Panel specified as a config object (no xtype defaults to 'panel').
* title: 'Details',
* bodyPadding: 5,
* items: [{
* fieldLabel: 'Data item',
* xtype: 'textfield'
* }], // An array of form fields
* flex: 2 // Use 2/3 of Container's height (hint to Box layout)
* }]
* });
*
* 例では、検索結果を表示する方法の1つを図示しています。パネルには、グリッドと行で表示された結果のデータが含まれます。以下のパネル内に選択された各行の詳細が表示されることがあります。{@link Ext.layout.container.VBox vbox}レイアウトは、2つのボックスを垂直に配置するために使用されます。子アイテムを全幅まで水平に広げるように設定されています。子アイテムには、高さを数値または`flex`値のいずれかで設定して、それに比例した利用可能なスペースを分配します。
*
* このパネル自身は、例えば、コンテンツエリア内に適合する子アイテムのサイズ調整を行う{@link Ext.tab.Panel}などの子アイテムである可能性があります。
*
* これらのテクニックを使用すると、**レイアウト**が正しく選択、設定されている限り、アプリケーションには、すべてのレベルのネストされた部品、設定により動的にサイズ調整されたすべての部品、ユーザーのプリファレンスやブラウザのサイズを含めることができます。
*/
Ext.define('Ext.panel.Panel', {
extend: 'Ext.container.Container',
alias: 'widget.panel',
alternateClassName: 'Ext.Panel',
requires: [
'Ext.panel.Header',
'Ext.util.MixedCollection',
'Ext.toolbar.Toolbar',
'Ext.fx.Anim',
'Ext.util.KeyMap',
'Ext.panel.DD',
'Ext.XTemplate',
'Ext.layout.component.Dock',
'Ext.util.Memento'
],
mixins: {
docking: 'Ext.container.DockingContainer'
},
childEls: [
'body'
],
renderTpl: [
// If this Panel is framed, the framing template renders the docked items round the frame
'{% this.renderDockedItems(out,values,0); %}',
'<div id="{id}-body" data-ref="body" class="{baseCls}-body<tpl if="bodyCls"> {bodyCls}</tpl>',
' {baseCls}-body-{ui}<tpl if="uiCls">',
'<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl>',
'</tpl>{childElCls}"',
'<tpl if="bodyRole"> role="{bodyRole}"<tpl else> role="presentation"</tpl>',
'<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',
'{%this.renderContainer(out,values);%}',
'</div>',
'{% this.renderDockedItems(out,values,1); %}'
],
// <editor-fold desc="Config">
// ***********************************************************************************
// Begin Config
// ***********************************************************************************
// the class body. This prevents the updaters from running on initialization in the
// default configuration scenario
headerPosition: 'top',
iconAlign: 'left',
titleAlign: 'left',
titleRotation: 'default',
beforeRenderConfig: {
/**
* @cfg {Number/String} glyph
* @inheritdoc Ext.panel.Header#glyph
*/
glyph: null,
* @cfg {String} [headerPosition='top']
* `'top'`、`'bottom'`、`'left'`、または`'right'`として指定します。
*/
headerPosition: null,
/**
* @cfg {String} icon
* @inheritdoc Ext.panel.Header#icon
*/
icon: null,
/**
* @cfg {'top'/'right'/'bottom'/'left'} [iconAlign='left']
* アイコンを表示するタイトルの側面。
*/
iconAlign: null,
/**
* @cfg {String} iconCls
* @inheritdoc Ext.panel.Header#iconCls
*/
iconCls: null,
/**
* @cfg {String}
* {@link Ext.panel.Header パネルヘッダー}内での表示に使用されるタイトルテキスト。あるいは、{@link Ext.panel.Title パネルタイトル}のコンフィグオブジェクト。`title`が指定されると、{@link #header}が`false`に設定されない限り、{@link Ext.panel.Header}が自動的に生成、表示されます。
*/
title: null,
/**
* @cfg {String} [titleAlign='left']
* アイコンとツールの間の使用可能な領域内でのタイトルテキストの文字揃えを設定します。
*/
titleAlign: null,
/**
* @cfg {'default'/0/1/2} [titleRotation='default']
* ヘッダーのタイトルテキストの回転。次の値のいずれかです。
*
* - `'default'` - ヘッダーのドッキング位置に応じたデフォルトの回転を使用
* - `0` - 回転なし
* - `1` - 時計回りに90度回転
* - `2` - 反時計回りに90度回転
*
* ヘッダーのドッキング位置に応じたこのコンフィグのデフォルトの動作。
*
* - `'top'`または`'bottom'` - `0`
* - `'right'` - `1`
* - `'left'` - `1`
*/
titleRotation: null
},
/**
* @cfg {Boolean} animCollapse
* `true`にすると、パネルが折りたたまれたときの状態遷移をアニメ化し、`false`にするとアニメ化を省略します({@link Ext.fx.Anim}クラスが使用可能な場合にデフォルトは`true`で、それ以外は`false`です)。アニメーションの継続時間をミリ秒で指定することもできます。
*/
animCollapse: Ext.enableFx,
/**
* @cfg {Boolean} bodyBorder
* パネルのボーダーを追加・削除するショートカット。これまでのクラシックテーマでは、これは{@link #frame}コンフィグが`true`に設定されているパネルにのみに適用されます。
* @since 2.3.0
*/
/**
* @cfg {String/String[]} bodyCls
* パネルのボディ要素に適用されるCSSクラス、クラスのスペースで区切られた文字列、クラスの配列。次の例は全て有効です:
*
* bodyCls: 'foo'
* bodyCls: 'foo bar'
* bodyCls: ['foo', 'bar']
*/
/**
* @cfg {Number/String} [bodyPadding=undefined]
* ボディ要素のpaddingスタイルを設定するショートカット。値は全てのサイドに適用される数値、またはpaddingを記述している標準のCSSの文字列で指定します。
*/
/**
* @cfg {String/Object/Function} bodyStyle
* パネルのボディ要素に適用されるカスタムCSSスタイル。 これは有効なCSSスタイル文字列、styleプロパティのname/valueペアを含むオブジェクト、そのような文字列やオブジェクトを返す関数のいずれかから指定します。例えば、次の2つの形式が等しく解釈されます:
*
* bodyStyle: 'background:#ffc; padding:10px;'
*
* bodyStyle: {
* background: '#ffc',
* padding: '10px'
* }
*
* @since 2.3.0
*/
/**
* @override
* @cfg {Boolean} [border=true]
* 幅が0のボーダーの付いたパネルを描画するには、`false`を指定します。
*
* 選択されたテーマの{@link Ext.panel.Panel#$panel-border-width}を使用するには、値を`true`のままにしておきます。
*
* Neptuneを使用または拡張する場合のデフォルト値は`false`です。
*/
border: true,
/**
* @cfg {Boolean} closable
* trueにすると、'閉じる'ツールボタンを表示して、ウィンドウをを閉じることができるようになります。 falseにするとボタンを表示せず、ウィンドウを閉じることはできません。
*
* デフォルトでは、「閉じる」リクエストがヘッダーの閉じるボタンをクリックすることで行われるとき、{@link #method-close}メソッドが呼び出されます。これにより、再利用されないパネルとそのコンテンツが_{@link Ext.Component#method-destroy 削除}_されます。
*
* 閉じる予定のパネルを再利用できるように_非表示_にするには、{@link #closeAction}を'hide'に設定します。
*/
closable: false,
/**
* @cfg {String} closeAction
* このアクションは閉じるヘッダーツールがクリックされると実行されます:
*
* - **`'{@link #method-destroy}'`** :
*
* DOMからウィンドウを{@link #method-remove 削除}して、その子コンポーネントと共に{@link Ext.Component#method-destroy 破棄}します。ウィンドウは、{@link #method-show}メソッド経由で再表示することは**できません**。
*
* - **`'{@link #method-hide}'`** :
*
* 表示を非表示に設定して負のオフセットを適用して、ウィンドウを{@link #method-hide}。ウィンドウは、{@link #method-show}メソッド経由で再表示することはできません。
*
* **注意:**この動作は変更された設定は、適切なcloseActionを起動する{@link #method-close}メソッドに*実際に*影響を与えます。
*/
closeAction: 'destroy',
/**
* @cfg {Boolean} collapsed
* `true`にするとパネルが折りたたまれた状態でレンダリングされ、`false`にすると展開された状態でレンダリングされます。
*/
collapsed: false,
/**
* @cfg {String} collapsedCls
* パネルの要素が折りたたまれた後に、そこに追加されるCSSクラス。
*/
collapsedCls: 'collapsed',
/**
* @cfg {String} collapseDirection
* トグルボタンがクリックされたときにPanelを折りたたむ方向。
*
* デフォルトは、{@link #headerPosition}になります。
*
* **重要:このコンフィグは{@link Ext.layout.container.Border ボーダーレイアウト}の直接の子アイテムである{@link #collapsible}パネルにのみ影響します。**
*
* `'top'`、`'bottom'`、`'left'`、または`'right'`として指定します。
*/
/**
* @cfg {Boolean} collapseFirst
* `true`にすると、折りたたみ/展開の切り替えボタンを、内包するPanelのタイトルバーで一番左のツールとして最初にレンダリングするようにします。`false`にすると、最後にレンダリングします。
*/
collapseFirst: true,
/**
* @cfg {Boolean} collapsible
* trueにするとパネルは折りたたみ可能になり、展開/折りたたみトグルツールがヘッダーのツールボタンエリアに追加されます。falseにすると、パネルは、静的に、または所有するレイアウトマネージャーによって、トグルツールを使わずにサイズ調整されます。パネルが{@link Ext.layout.container.Border ボーダーレイアウト}で使用されると、{@link #floatable}オプションは折りたたみの動作に影響を与えることがあります。{@link #collapseMode}および{@link #collapseDirection}を参照してください。
*/
collapsible: undefined,
/**
* @cfg {String} collapseMode
* **重要: このコンフィグは{@link Ext.layout.container.Border ボーダーレイアウト}の直接の子アイテムである{@link #collapsible}パネルにのみ影響します。**
*
* {@link Ext.layout.container.Border ボーダーレイアウト}の直接の子アイテムではない場合、Panelのヘッダーが表示されたままボディが折りたたまれサイズが0になります。パネルがヘッダーを持たない場合、タイトルと再展開するツールを表示するために、新しいヘッダー({@link #collapseDirection}に従い正確な方向を向く)が挿入されます。
*
* 子アイテムが{@link Ext.layout.container.Border borderレイアウト}の子アイテムである場合、このコンフィグには以下の3つ値を設定できます:
*
* - `undefined` - 折りたたまれたとき、Panelを表示し、Panelを再展開させるツールを持つUIを提供する、場所を確保する{@link Ext.panel.Header ヘッダー}がレイアウトに導入されます。
*
* - `"header"` - {@link Ext.layout.container.Border ボーダーレイアウト}がない場合には、パネルをヘッダーが見えるままの状態で折りたたみます。
*
* - `"mini"` - ヘッダーを表示しないでPanelを折りたたみます。
*/
/**
* @override
* @cfg {Boolean} constrain
* パネルの配置を、含められている要素の内部に制限する場合にはtrue、外部への移動を許可する場合にはfalse。デフォルトでは、Windowsが`document.body`へ描画される場合などのようなフローティングコンポーネントです。別の要素内にウィンドウを描画したり制限したりするには、{@link #renderTo}を指定します。オプションで、ヘッダーを{@link #constrainHeader}を使用して制限できます。
*/
constrain: false,
* @cfg {Boolean} constrainHeader
* (内包される要素の外側へパネル本体を置くことが可能な)内包される要素内のパネルヘッダーを制限するには、true、内包される要素の外側へヘッダーを置く場合には、false。オプションで、パネル全体を{@link #constrain}を使用して制限できます。
*/
constrainHeader: false,
// @cmd-auto-dependency {aliasPrefix: "widget.", typeProperty: "xtype"}
/**
* @cfg {Object/Object[]} dockedItems
* パネルにドッキングされたアイテムとして追加されるコンポーネント、またはコンポーネントの連続。アイテムは、パネルの上下左右のいずれかにドッキングすることができます。これは、一般的にツールバーやタブバーのようなものに使用されます:
*
* var panel = new Ext.panel.Panel({
* dockedItems: [{
* xtype: 'toolbar',
* dock: 'top',
* items: [{
* text: 'Docked to the top'
* }]
* }]
* });
*/
dockedItems: null,
/**
* @cfg {String} buttonAlign
* このパネルに追加されるボタンの配置。有効な値は、'right'、'left'、'center'のいずれかです(デフォルトはbuttonとfbarでは'right'、その他のツールバーでは'left'です)。
*
* **注意:**ツールバーを指定するための好ましい方法はdockedItemsコンフィグを使用することです。buttonAlignの代わりに、layout:{ pack:'start' | 'center' | 'end' }オプションをdockedItemコンフィグに追加します。
*/
// @cmd-auto-dependency {aliasPrefix: "widget.", typeProperty: "xtype", defaultType: "toolbar"}
/**
* @cfg {Object/Object[]} tbar
* 便利なコンフィグです。'Top Bar'の省略形です。
*
* tbar: [
* { xtype: 'button', text: 'Button 1' }
* ]
*
* これは以下と同等です。
*
* dockedItems: [{
* xtype: 'toolbar',
* dock: 'top',
* items: [
* { xtype: 'button', text: 'Button 1' }
* ]
* }]
*/
tbar: null,
// @cmd-auto-dependency {aliasPrefix: "widget.", typeProperty: "xtype", defaultType: "toolbar"}
/**
* @cfg {Object/Object[]} bbar
* 便利なコンフィグです。'Bottom Bar'の省略形です。
*
* bbar: [
* { xtype: 'button', text: 'Button 1' }
* ]
*
* これは以下と同等です。
*
* dockedItems: [{
* xtype: 'toolbar',
* dock: 'bottom',
* items: [
* { xtype: 'button', text: 'Button 1' }
* ]
* }]
*/
bbar: null,
// @cmd-auto-dependency {aliasPrefix: "widget.", typeProperty: "xtype", defaultType: "toolbar"}
/**
* @cfg {Object/Object[]} fbar
* パネルの下部にアイテムを追加するのに使用される便利な設定。Footer Barの省略形です。
*
* fbar: [
* { type: 'button', text: 'Button 1' }
* ]
*
* これは以下と同等です。
*
* dockedItems: [{
* xtype: 'toolbar',
* dock: 'bottom',
* ui: 'footer',
* defaults: {minWidth: {@link #minButtonWidth}},
* items: [
* { xtype: 'component', flex: 1 },
* { xtype: 'button', text: 'Button 1' }
* ]
* }]
*
* {@link #minButtonWidth}は、fbar中の各ボタンのデフォルトの{@link Ext.button.Button#minWidth minWidth}として使用されます。
*/
fbar: null,
// @cmd-auto-dependency {aliasPrefix: "widget.", typeProperty: "xtype", defaultType: "toolbar"}
/**
* @cfg {Object/Object[]} lbar
* 便利なコンフィグです。('Left Bar'の省略形)。
*
* lbar: [
* { xtype: 'button', text: 'Button 1' }
* ]
*
* これは以下と同等です。
*
* dockedItems: [{
* xtype: 'toolbar',
* dock: 'left',
* items: [
* { xtype: 'button', text: 'Button 1' }
* ]
* }]
*/
lbar: null,
// @cmd-auto-dependency {aliasPrefix: "widget.", typeProperty: "xtype", defaultType: "toolbar"}
/**
* @cfg {Object/Object[]} rbar
* 便利なコンフィグです。'Right Bar'の省略形です。
*
* rbar: [
* { xtype: 'button', text: 'Button 1' }
* ]
*
* これは以下と同等です。
*
* dockedItems: [{
* xtype: 'toolbar',
* dock: 'right',
* items: [
* { xtype: 'button', text: 'Button 1' }
* ]
* }]
*/
rbar: null,
/**
* @cfg {Object/Object[]} buttons
* パネルの下部にドッキングされたツールバーにボタンを追加するために使用する便利なコンフィグです。これは、{@link #fbar}コンフィグの同意語です。
*
* buttons: [
* { text: 'Button 1' }
* ]
*
* これは以下と同等です。
*
* dockedItems: [{
* xtype: 'toolbar',
* dock: 'bottom',
* ui: 'footer',
* defaults: {minWidth: {@link #minButtonWidth}},
* items: [
* { xtype: 'component', flex: 1 },
* { xtype: 'button', text: 'Button 1' }
* ]
* }]
*
* {@link #minButtonWidth}は、ボタンツールバー中の各ボタンのデフォルトの{@link Ext.button.Button#minWidth minWidth}として使用されます。
*/
buttons: null,
/**
* @cfg {Boolean} floatable
* **重要:このコンフィグは{@link Ext.layout.container.Border ボーダーレイアウト}の直接の子アイテムである{@link #collapsible}パネルにのみ影響します。**
*
* trueにすると、折りたたまれたPanelの{@link #placeholder}をクリックしてレイアウトの上にパネルを浮かせて表示することができます。
*/
floatable: true,
/**
* @cfg {Boolean} frame
* trueにすると、パネルにフレームを適用します。
*/
frame: false,
* @cfg {Boolean} frameHeader
* trueにすると、パネルのヘッダーにフレームを適用します('frame'がtrueの場合)。
*/
frameHeader: true,
* @cfg {Boolean/Object} [header]
* ヘッダーの作成と表示を防ぐには、`false`を渡します。
*
* このパネルのヘッダーをカスタム設定するには、(オプションで`xtype`を含む)コンフィグオブジェクトとして渡します。
*
* ここで指定したすべてのオプションについては、{@link Ext.panel.Header}を参照してください。
*
* {@link Ext.panel.Header パネルヘッダー}は、パネルの{@link #title}および{@link #tools}を含む{@link Ext.container.Container}です。{@link #tools}の*前*におかれる独自の子アイテムを持つパネルの`header`オプションも設定することができます。
*
* デフォルトでは、このコンフィグで設定したアイテムの後、ツールの前にパネル{@link #title}が挿入されます。全配列の中の任意の位置にタイトルを挿入するには、{@link Ext.panel.Header#titlePosition titlePosition}コンフィグを指定します:
*
* new Ext.panel.Panel({
* title: 'Test',
* tools: [{
* type: 'refresh'
* }, {
* type: 'help'
* }],
* titlePosition: 2 // Title will come AFTER the two tools
* ...
* });
*
*/
* @cfg {String} headerOverCls
* mouseoverのヘッダー要素へ追加するオプションのCSSクラスです。
*/
/**
* @cfg {Boolean} hideCollapseTool
* `true`にすると、`{@link #collapsible} == true`の場合、展開/折りたたみ式のトグルボタンを非表示にし、`false`にすると表示します。
*/
hideCollapseTool: false,
/**
* @cfg {Boolean} [manageHeight=true] trueの場合、ドッキングされたコンポーネントレイアウトは、シュリンクラップの高さの計算にに基づきパネルのDOM要素に高さの情報を書き込みます。これはブラウザが計算された高さを守ることを保証します。falseの場合、ドッキングされたコンポーネントレイアウトは、パネルまたはボディ要素に高さを書き込みません。いくつかの簡単なレイアウトの場合、ブラウザが直接のDOM操作(アニメーションのように)に応じることを許可するので、DOMに高さを書き込まないことが望ましいかもしれません。
*/
manageHeight: true,
/**
* @override
* @cfg {String} [maskElement="el"]
*
* LoadMaskによってマスクがかけられる際にマスクをかけるこのパネルの要素のプロパティ名。
*
* すべてのLoadMaskをこのパネルのカプセル化した要素内に描画する必要がある場合はデフォルト値を`"el"`とします。
*
* これは`"body"`と設定することもできます。すると、本体のみがツールバーとヘッダーはマウスでアクセスできます。
*/
maskElement: 'el',
/**
* @cfg {Number} minButtonWidth
* 全てのフッターツールバーボタンの最小の幅をピクセルで指定します。設定されると、これは{@link #fbar}または{@link #buttons}の設定を経由して**フッターツールバー**に追加された各ボタンの{@link Ext.button.Button#minWidth}コンフィグのデフォルト値として使用されます。これは、他の方法で設定されたminWidthを持つボタンでは無視されます。例えば、それ自身のコンフィグオブジェクト、または親コンテナの{@link Ext.container.Container#defaults デフォルト}により設定されたものなどです。
*/
minButtonWidth: 75,
* @cfg {Boolean} overlapHeader
* trueにすると、パネル自身のフレームを越えたヘッダーをオーバーラップします。これはframe:trueのときに必要です(そして自動的に実行されます)。それ以外の場合は、undefinedです。frame:trueでないパネルヘッダーに手動で丸みのある角を追加した場合、trueに設定する必要があります。
*/
/**
* @cfg {Ext.Component/Object} placeholder
* **重要:このコンフィグは、{@link #collapseMode}の`'header'`を使用しない場合に、{@link Ext.layout.container.Border ボーダーレイアウト}の直接の子アイテムである{@link #collapsible}パネルにのみ影響を与えます。**
*
* **オプション。**このパネルが{@link Ext.layout.container.Border ボーダーレイアウト}により折りたたまれたときに、このPanelの代わりに表示されるコンポーネント(またはコンポーネントのコンフィグオブジェクト)。デフォルトは、Panelを再展開する{@link Ext.panel.Tool Tool}を含む{@link Ext.panel.Header Header}が生成されます。
*/
/**
* @cfg {Number} [placeholderCollapseHideMode=Ext.Element.VISIBILITY]
* {@link #collapseMode}"プレイスホルダー"を使用する際に折りたたまれたパネルを非表示にする{@link Ext.dom.Element#setVisibilityMode モード}。
*/
//placeholderCollapseHideMode: Ext.Element.VISIBILITY,
* @cfg {Boolean} preventHeader
* @deprecated 4.1.0代わりに、{@link #header}を使用してください。ヘッダーが作成され、表示されるのを防いでください。
*/
preventHeader: false,
/**
* @cfg {Boolean/Number} shrinkWrapDock
* パネル全体のサイズを決定しようとする際に、このパネルに{@link #dockedItems}を含めることを許可します。このオプションは、このパネルが同じ面でシュリンクラップする場合にのみ適用できます。設定オプションの説明については、{@link Ext.Component#shrinkWrap}を参照してください。
*/
shrinkWrapDock: false,
/**
* @cfg {Boolean} [simpleDrag=false]
* {@link #cfg-draggable}が`true`である場合、これを`true`に指定すると`draggable`コンフィグによって{@link Ext.window.Window ウィンドウ}内と同じように機能します。このパネルは移動可能になります。DragDropインスタンスは通知を受け取りません。例:
*
* @example
* var win = Ext.create('widget.window', {
* height: 300,
* width: 300,
* title: 'Constraining Window',
* closable: false,
* items: {
* title: "Floating Panel",
* width: 100,
* height: 100,
* floating: true,
* draggable: true,
* constrain: true,
* simpleDrag: true
* }
* });
* win.show();
* // Floating components begin life hidden
* win.child('[title=Floating Panel]').show();
*
*/
/**
* @cfg {Boolean} titleCollapse
* `true`にすると、ヘッダーバーをクリックすることによりパネルの展開と折りたたみが可能になり(`{@link #collapsible} = true`の場合)、`false`にするとツールボタンをクリックするだけで可能になります。パネルが{@link Ext.layout.container.Border ボーダーレイアウト}で使用されると、{@link #floatable}オプションは折りたたみの動作に影響を与えることがあります。
*/
titleCollapse: undefined,
/**
* @cfg {Object[]/Ext.panel.Tool[]} tools
* ヘッダーのツールエリアに追加される{@link Ext.panel.Tool}のコンフィグまたはインスタンスの配列。ツールはヘッダーコンテナの子コンポーネントとして格納されます。ツールにアクセスするには、他のメソッドと同様に{@link #down}や{#query}を使用します。切り換えツールは、{@link #collapsible}がtrueに設定されている場合に、自動的に生成されます。
*
* パネルが折りたたみ可能に設定されたときに提供される切り替えツールを除いて、これらのツールは表示された状態のボタンとして提供されることに注意してください。ボタンがクリックされたときの機能は、必要な動作を実装したハンドラを追加して提供されなければなりません。
*
* 使用例:
*
* tools:[{
* type:'refresh',
* tooltip: 'Refresh form Data',
* // hidden:true,
* handler: function(event, toolEl, panelHeader) {
* // refresh logic
* }
* },
* {
* type:'help',
* tooltip: 'Get Help',
* callback: function(panel, tool, event) {
* // show help here
* }
* }]
*
* `handler`と`callback`の違いは、シグネチャです。この区別の詳細については、{@link Ext.panel.Tool}を参照してください。
*/
// ***********************************************************************************
// End Config
// ***********************************************************************************
// </editor-fold>
// <editor-fold desc="Properties">
// ***********************************************************************************
// Begin Properties
// ***********************************************************************************
baseCls: Ext.baseCSSPrefix + 'panel',
/**
* @property {Ext.dom.Element} body
* HTMLコンテンツを含む際に使用されるパネルのボディ{@link Ext.dom.Element 要素}。コンテンツは{@link #html}コンフィグ内で指定されるか、または{@link #loader}コンフィグを使ってロードされます。読み取り専用です。
*
* どちらにしても、これは可視状態のHTML要素をロードするのに使用され、パネルはネストされたパネルを提供するためのレイアウトとして使用されることはありません。
*
* このパネルをレイアウトの提供者として使用する場合({@link #layout}を参照してください)、ボディ要素はロードまたは変更してはいけません-パネルのレイアウトの管理下にあります。
*
* @readonly
*/
bodyPosProps: {
x: 'x',
y: 'y'
},
componentLayout: 'dock',
/**
* @property {String} [contentPaddingProperty='bodyPadding']
* @inheritdoc
*/
contentPaddingProperty: 'bodyPadding',
emptyArray: [],
/**
* @property {Boolean} isPanel
* このクラスまたはそのサブクラスでオブジェクトをインスタンス化したPanelとして識別するには`true`。
*/
isPanel: true,
defaultBindProperty: 'title',
// ***********************************************************************************
// End Properties
// ***********************************************************************************
// </editor-fold>
// <editor-fold desc="Events">
// ***********************************************************************************
// Begin Events
// ***********************************************************************************
/**
* @event beforeclose
* パネルを閉じる前に発火します。closeイベントの発火を中止するには、リスナからfalseを返します。
* @param {Ext.panel.Panel} panel パネルオブジェクト
*/
/**
* @event beforecollapse
* パネルが折りたたまれる前に発火します。折りたたみを中止するためにはfalseを返します。
* @param {Ext.panel.Panel} p 折りたたまれるパネル。
* @param {String} direction 。折りたたみの方向。次のうちのどれかです。
*
* - Ext.Component.DIRECTION_TOP
* - Ext.Component.DIRECTION_RIGHT
* - Ext.Component.DIRECTION_BOTTOM
* - Ext.Component.DIRECTION_LEFT
*
* @param {Boolean} animate 折りたたみがアニメ化される場合はtrue、そうでなければfalse。
*/
/**
* @event beforeexpand
* パネルが展開される前に発火します。展開を中止するためにはfalseを返します。
* @param {Ext.panel.Panel} p 展開しているパネル。
* @param {Boolean} animate 展開がアニメ化される場合はtrue、そうでなければfalse。
*/
/**
* @event close
* パネルを閉じるときに発火します。
* @param {Ext.panel.Panel} panel パネルオブジェクト
*/
/**
* @event collapse
* このパネルが折りたたまれた後に発火します。
* @param {Ext.panel.Panel} p 折りたたまれたパネル。
*/
/**
* @event expand
* このパネルが展開された後に発火します。
* @param {Ext.panel.Panel} p 展開されたパネル。
*/
/**
* @event float
* 折りたたまれたパネルがヘッダーのクリックによって「フロート」状態になった後に発火します。パネルが{@link Ext.layout.container.Border ボーダーレイアウト}内のアイテムである場合にのみ適用されます。
*/
/**
* @event glyphchange
* {@link #setGlyph}メソッドによりパネルのglyphが変更されると発火します。
* @param {Ext.panel.Panel} this
* @param {Number/String} newGlyph
* @param {Number/String} oldGlyph
*/
/**
* @event iconchange
* パネルのアイコンが設定または変更された後に発火します。
* @param {Ext.panel.Panel} p アイコンが変更されたパネル。
* @param {String} newIcon 新しいアイコン画像へのパス。
* @param {String} oldIcon 以前のパネルのアイコン画像へのパス。
*/
/**
* @event iconclschange
* パネルのiconClsが設定または変更された後に発火します。
* @param {Ext.panel.Panel} p iconClsが変更されたパネル。
* @param {String} newIconCls 新しいiconCls。
* @param {String} oldIconCls 前のパネルのiconCls。
*/
/**
* @event titlechange
* パネルのタイトルが設定または変更された後に発火します。
* @param {Ext.panel.Panel} p サイズが変更されたパネル。
* @param {String} newTitle 新しいタイトル。
* @param {String} oldTitle 以前のパネルのタイトル。
*/
/**
* @event unfloat
* マウスがパネルから離れた結果、フロート状態のパネルが折りたたまれた状態に戻った後に発火します。パネルが{@link Ext.layout.container.Border ボーダーレイアウト}内のアイテムである場合にのみ適用されます。
*/
// ***********************************************************************************
// End Events
// ***********************************************************************************
// </editor-fold>
// <editor-fold desc="Component Methods">
// ***********************************************************************************
// Begin Methods
// ***********************************************************************************
/**
* ボディ要素にCSSクラスを追加します。レンダリングされていない場合、パネルがレンダリングされたときにクラスが追加されます。
* @param {String} cls 追加するクラス
* @return {Ext.panel.Panel} this
*/
addBodyCls: function(cls) {
var me = this,
body = me.rendered ? me.body : me.getProtoBody();
body.addCls(cls);
return me;
},
/**
* このパネルにツールを追加します。
* @param {Object[]/Ext.panel.Tool[]} tools 追加するツール
*/
addTool: function(tools) {
if (!Ext.isArray(tools)) {
tools = [tools];
}
var me = this,
header = me.header,
tLen = tools.length,
curTools = me.tools,
t, tool;
if (!header || !header.isHeader) {
header = null;
if (!curTools) {
me.tools = curTools = [];
}
}
for (t = 0; t < tLen; t++) {
tool = tools[t];
tool.toolOwner = me;
if (header) {
header.addTool(tool);
} else {
// only modify the tools array if the header isn't created,
// otherwise, defer to the header to manage
curTools.push(tool);
}
}
me.updateHeader();
},
/**
* @protected
* @template
* 折りたためるツールの後にツールを追加するためにサブクラスで実行されるテンプレートメソッド。
*/
addTools: Ext.emptyFn,
setCollapsible: function (collapsible) {
var me = this,
current = me.collapsible,
collapseTool = me.collapseTool;
me.collapsible = collapsible;
if (collapsible && !current) {
me.updateCollapseTool();
collapseTool = me.collapseTool;
if (collapseTool) {
collapseTool.show();
}
} else if (!collapsible && current) {
if (collapseTool) {
collapseTool.hide();
}
}
},
// inherit docs
addUIClsToElement: function(cls) {
var me = this,
result = me.callParent(arguments);
me.addBodyCls([Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls]);
return result;
},
/**
* パネルが折りたたまれた後に呼び出されます。
*
* @param {Boolean} animated
*
* @template
* @protected
*/
afterCollapse: function(animated) {
var me = this,
ownerLayout = me.ownerLayout;
me.isCollapsingOrExpanding = 0;
me.updateCollapseTool();
// The x-animating-size class sets overflow:hidden so that overflowing
// content is clipped during animation.
if (animated) {
me.removeCls(Ext.baseCSSPrefix + 'animating-size');
}
me.setHiddenDocked();
me.fireEvent('collapse', me);
},
/**
* パネルが展開された後に呼び出されます。
*
* @param {Boolean} animated
*
* @template
* @protected
*/
afterExpand: function(animated) {
var me = this,
ownerLayout = me.ownerLayout;
me.isCollapsingOrExpanding = 0;
me.updateCollapseTool();
// The x-animating-size class sets overflow:hidden so that overflowing
// content is clipped during animation.
if (animated) {
me.removeCls(Ext.baseCSSPrefix + 'animating-size');
}
me.fireEvent('expand', me);
me.fireHierarchyEvent('expand');
},
beforeDestroy: function() {
var me = this;
Ext.destroy(
me.placeholder,
me.ghostPanel,
me.dd
);
this.destroyDockedItems();
me.callParent();
},
beforeRender: function() {
var me = this,
wasCollapsed;
me.callParent();
// Add class-specific header tools.
// Panel adds collapsible and closable.
me.initTools();
// Dock the header/title unless we are configured specifically not to create a header
if (!(me.preventHeader || (me.header === false))) {
me.updateHeader();
}
// If we are rendering collapsed, we still need to save and modify various configs
if (me.collapsed) {
if (me.isPlaceHolderCollapse()) {
if (!me.hidden) {
me.setHiddenState(true);
// This will insert the placeholder Component into the ownerCt's child collection
// Its getRenderTree call which is calling this will then iterate again and
// recreate the child items array to include the new Component. Prevent the first
// collapse from firing
me.preventCollapseFire = true;
me.placeholderCollapse();
delete me.preventCollapseFire;
wasCollapsed = me.collapsed;
// Temporarily clear the flag so that the header is rendered with a collapse tool in it.
// Placeholder collapse panels never really collapse, they just hide. The tool is always
// a collapse tool.
me.collapsed = false;
}
} else {
me.beginCollapse();
me.addClsWithUI(me.collapsedCls);
}
}
// Restore the flag if we are being rendered initially placeholder collapsed.
if (wasCollapsed) {
me.collapsed = wasCollapsed;
}
},
/**
* @private
* Mementoファクトリメソッド
* @param {String} name Mementoの名前(名前付きのMementoのプレフィックスとして使用)
s */
getMemento :function (name) {
var me = this;
if(name && typeof name == 'string') {
name += 'Memento';
return me[name] || (me[name] = new Ext.util.Memento(me));
}
},
/**
* @private
* 設定されたデフォルトの状態から折りたたまれた状態に変更される前に呼び出されます。最初に折りたたまれた状態でレンダリングできるように、このメソッドはレンダリング時に呼び出すことができます。 または存在する場合は実行時に完全にパネルが折りたたまれる様にレイアウトします。これは基本的に、折りたたまれた状態の継続時間を制限するために必要なコンフィグを保存します。
*/
beginCollapse: function() {
var me = this,
lastBox = me.lastBox,
rendered = me.rendered,
collapseMemento = me.getMemento('collapse'),
sizeModel = me.getSizeModel(),
header = me.header,
reExpander;
// When we collapse a panel, the panel is in control of one dimension (depending on
// collapse direction) and sets that on the component. We must restore the user's
// original value (including non-existance) when we expand. Using this technique, we
// mimic setCalculatedSize for the dimension we do not control and setSize for the
// one we do (only while collapsed).
// Additionally, the panel may have a shrink wrapped width and/or height. For shrinkWrapped
// panels this can be problematic, since a collapsed, shrink-wrapped panel has no way
// of determining its width (or height if the collapse direction is horizontal). It is
// therefore necessary to capture both the width and height regardless of collapse direction.
// This allows us to set a configured width or height on the panel when it is collapsed,
// and it will be restored to an unconfigured-width shrinkWrapped state on expand.
collapseMemento.capture(['height', 'minHeight', 'width', 'minWidth']);
if (lastBox) {
collapseMemento.capture(me.restoreDimension(), lastBox, 'last.');
}
// If the panel has a shrinkWrapped height/width and is already rendered, configure its width/height as its calculated width/height,
// so that the collapsed header will have the same width or height as the panel did before it was collapsed.
// If the shrinkWrapped panel has not yet been rendered, as will be the case when a panel is initially configured with
// collapsed:true, we attempt to use the configured width/height, and fall back to minWidth or minHeight if
// width/height has not been configured, and fall back to a value of 100 if a minWidth/minHeight has not been configured.
if (me.collapsedVertical()) {
if (sizeModel.width.shrinkWrap) {
me.width = rendered ? me.getWidth() : me.width || me.minWidth || 100;
}
delete me.height;
me.minHeight = 0;
} else if (me.collapsedHorizontal()) {
if (sizeModel.height.shrinkWrap) {
me.height = rendered ? me.getHeight() : me.height || me.minHeight || 100;
}
delete me.width;
me.minWidth = 0;
}
if (me.ownerCt) {
me.ownerCt.getLayout().beginCollapse(me);
}
// Get a reExpander header. This will return the Panel Header if the Header is in the correct orientation
// If we are using the Header as the reExpander, change its UI to collapsed state
if (!me.isPlaceHolderCollapse() && header !== false) {
if (header === (reExpander = me.getReExpander())) {
header.collapseImmune = true;
header.getInherited().collapseImmune = true;
header.addClsWithUI(me.getHeaderCollapsedClasses(header));
// Ensure that the reExpander has the correct framing applied.
if (header.rendered) {
header.updateFrame();
}
} else if (reExpander.el) {
// We're going to use a temporary reExpander: show it.
reExpander.el.show();
reExpander.hidden = false;
}
}
if (me.resizer) {
me.resizer.disable();
}
},
beginDrag: function() {
if (this.floatingDescendants) {
this.floatingDescendants.hide();
}
},
beginExpand: function() {
var me = this,
lastBox = me.lastBox,
collapseMemento = me.getMemento('collapse'),
restoreDimension = me.restoreDimension(),
header = me.header,
reExpander;
if (collapseMemento) {
collapseMemento.restore(['minHeight', 'minWidth', restoreDimension]);
if (lastBox) {
collapseMemento.restore(restoreDimension, true, lastBox, 'last.');
}
}
if (me.ownerCt) {
me.ownerCt.getLayout().beginExpand(me);
}
if (!me.isPlaceHolderCollapse() && header !== false) {
// If we have been using our Header as the reExpander then restore the Header to expanded UI
if (header === (reExpander = me.getReExpander())) {
delete header.collapseImmune;
delete header.getInherited().collapseImmune;
header.removeClsWithUI(me.getHeaderCollapsedClasses(header));
// Ensure that the reExpander has the correct framing applied.
if (header.rendered) {
header.expanding = true;
header.updateFrame();
delete header.expanding;
}
} else {
// We've been using a temporary reExpander: hide it.
reExpander.hidden = true;
reExpander.el.hide();
}
}
if (me.resizer) {
me.resizer.enable();
}
},
bridgeToolbars: function() {
var me = this,
docked = [],
minButtonWidth = me.minButtonWidth,
fbar, fbarDefaults;
function initToolbar (toolbar, pos, useButtonAlign) {
if (Ext.isArray(toolbar)) {
toolbar = {
xtype: 'toolbar',
items: toolbar
};
}
else if (!toolbar.xtype) {
toolbar.xtype = 'toolbar';
}
toolbar.dock = pos;
if (pos == 'left' || pos == 'right') {
toolbar.vertical = true;
}
// Legacy support for buttonAlign (only used by buttons/fbar)
if (useButtonAlign) {
toolbar.layout = Ext.applyIf(toolbar.layout || {}, {
// default to 'end' (right-aligned) if me.buttonAlign is undefined or invalid
pack: { left:'start', center:'center' }[me.buttonAlign] || 'end'
});
}
return toolbar;
}
if (me.tbar) {
docked.push(initToolbar(me.tbar, 'top'));
me.tbar = null;
}
if (me.bbar) {
docked.push(initToolbar(me.bbar, 'bottom'));
me.bbar = null;
}
if (me.buttons) {
me.fbar = me.buttons;
me.buttons = null;
}
if (me.fbar) {
fbar = initToolbar(me.fbar, 'bottom', true); // only we useButtonAlign
fbar.ui = 'footer';
// Apply the minButtonWidth config to buttons in the toolbar
if (minButtonWidth) {
fbarDefaults = fbar.defaults;
fbar.defaults = function(config) {
var defaults = fbarDefaults || {},
// no xtype or a button instance
isButton = !config.xtype || config.isButton,
cls;
// Here we have an object config with an xtype, check if it's a button
// or a button subclass
if (!isButton) {
cls = Ext.ClassManager.getByAlias('widget.' + config.xtype);
if (cls) {
isButton = cls.prototype.isButton;
}
}
if (isButton && !('minWidth' in defaults)) {
defaults = Ext.apply({minWidth: minButtonWidth}, defaults);
}
return defaults;
};
}
docked.push(fbar);
me.fbar = null;
}
if (me.lbar) {
docked.push(initToolbar(me.lbar, 'left'));
me.lbar = null;
}
if (me.rbar) {
docked.push(initToolbar(me.rbar, 'right'));
me.rbar = null;
}
if (me.dockedItems) {
if (me.dockedItems.isMixedCollection) {
me.addDocked(docked);
} else {
if (!Ext.isArray(me.dockedItems)) {
me.dockedItems = [me.dockedItems];
}
me.dockedItems = me.dockedItems.concat(docked);
}
} else {
me.dockedItems = docked;
}
},
/**
* パネルを閉じます。デフォルトでは、このメソッドはDOMからパネルを取り除き、パネルオブジェクトとその下位コンポーネントをすべて{@link Ext.Component#method-destroy 削除}します。{@link #beforeclose beforeclose}イベントは、閉じる動作が発生する前に発火され、falseを返す場合に閉じるアクションをキャンセルします。
*
* **注意:**このメソッドも、{@link #closeAction}設定によって影響を受けます。より明示的にコントロールを行うには、{@link #method-destroy}メソッドおよび{@link #method-hide}メソッドを使用してください。
*/
close: function() {
if (this.fireEvent('beforeclose', this) !== false) {
this.doClose();
}
},
/**
* パネルボディを折りたたみ、非表示にします。折りたたみが発生する方向の境界に並行にドックされたコンポーネントは、可視状態のままです。falseを返す場合、折りたたみアクションをキャンセルする{@link #beforecollapse}を発火します。
*
* @param {String} [direction] 折りたたまれる方向。以下のいずれかになります。
*
* - Ext.Component.DIRECTION_TOP
* - Ext.Component.DIRECTION_RIGHT
* - Ext.Component.DIRECTION_BOTTOM
* - Ext.Component.DIRECTION_LEFT
*
* デフォルトでは、{@link #collapseDirection}になります。
*
* @param {Boolean} [animate] トランジションをアニメーション化する場合はtrue、それ以外はfalse(デフォルトは{@link #animCollapse}パネルコンフィグの値)。アニメーションの継続時間をミリ秒で指定することもできます。
* @return {Ext.panel.Panel} this
*/
collapse: function(direction, animate) {
var me = this,
collapseDir = direction || me.collapseDirection,
ownerCt = me.ownerCt,
layout = me.ownerLayout,
rendered = me.rendered;
if (me.isCollapsingOrExpanding) {
return me;
}
if (arguments.length < 2) {
animate = me.animCollapse;
}
if (me.collapsed || me.fireEvent('beforecollapse', me, direction, animate) === false) {
return me;
}
if (layout && layout.onBeforeComponentCollapse) {
if (layout.onBeforeComponentCollapse(me) === false) {
return me;
}
}
if (rendered && ownerCt && me.isPlaceHolderCollapse()) {
return me.placeholderCollapse(direction, animate);
}
me.collapsed = collapseDir;
if (rendered) {
me.beginCollapse();
}
me.getInherited().collapsed = true;
me.fireHierarchyEvent('collapse');
if (rendered) {
me.doCollapseExpand(1, animate);
}
return me;
},
collapsedHorizontal: function () {
var dir = this.getCollapsed();
return dir === 'left' || dir === 'right';
},
collapsedVertical: function () {
var dir = this.getCollapsed();
return dir === 'top' || dir === 'bottom';
},
/**
* collapsdDirを、"l"と"r"を切り替えるrtlモードでオーバーライドされたElement.slideInのアンカー引数へと変換します。
*/
convertCollapseDir: function(collapseDir) {
return collapseDir.substr(0, 1);
},
createGhost: function(cls) {
var me = this,
header = me.header,
frame = me.frame && !me.alwaysFramed;
return {
xtype: 'panel',
hidden: false,
header: header ? {
titleAlign: header.getTitleAlign()
} : null,
ui: frame ? me.ui.replace(/-framed$/, '') : me.ui,
id: me.id + '-ghost',
renderTo: Ext.getBody(),
// The ghost's opacity causes the resize handles to obscure the frame in
// IE, so always force resizable to be false.
resizable: false,
// The ghost must not be draggable (the actual class instantiated my be draggable in its prototype)
draggable: false,
// Tools are explicitly copied. We do not want the overhead of a KeyMap for the ghost
closable: false,
floating: {
shadow: false
},
frame: frame,
alwaysFramed: me.alwaysFramed,
overlapHeader: me.overlapHeader,
headerPosition: me.getHeaderPosition(),
titleRotation: me.getTitleRotation(),
baseCls: me.baseCls,
getRefOwner: function () {
return me.getRefOwner();
},
cls: me.baseCls + '-ghost ' + (cls || '')
};
},
createReExpander: function(direction, defaults) {
var me = this,
isLeft = direction === 'left',
isRight = direction === 'right',
isVertical = isLeft || isRight,
ownerCt = me.ownerCt,
result = Ext.apply({
hideMode: 'offsets',
title: me.getTitle(),
titleAlign: me.getTitleAlign(),
vertical: isVertical,
textCls: me.headerTextCls,
icon: me.getIcon(),
iconCls: me.getIconCls(),
iconAlign: me.getIconAlign(),
glyph: me.getGlyph(),
baseCls: me.self.prototype.baseCls + '-header',
ui: me.ui,
frame: me.frame && me.frameHeader,
ignoreParentFrame: me.frame || me.overlapHeader,
ignoreBorderManagement: me.frame || me.ignoreHeaderBorderManagement,
indicateDrag: me.draggable,
collapseImmune: true,
headerRole: me.headerRole,
ownerCt: (ownerCt && me.collapseMode === 'placeholder') ? ownerCt : me,
ownerLayout: me.componentLayout,
margin: me.margin
}, defaults);
// If we're in mini mode, set the placeholder size to only 1px since
// we don't need it to show up.
if (me.collapseMode === 'mini') {
if (isVertical) {
result.width = 1;
} else {
result.height = 1;
}
}
// Create the re expand tool
// For UI consistency reasons, collapse:left reExpanders, and region: 'west' placeHolders
// have the re expand tool at the *top* with a bit of space.
if (!me.hideCollapseTool) {
if (isLeft || (isRight && me.isPlaceHolderCollapse())) {
// adjust the title position if the collapse tool needs to be at the
// top of a vertical header
result.titlePosition = 1;
}
result.tools = [{
xtype: 'tool',
type: 'expand-' + me.getOppositeDirection(direction),
uiCls: ['top'],
handler: me.toggleCollapse,
scope: me
}];
}
result = new Ext.panel.Header(result);
result.addClsWithUI(me.getHeaderCollapsedClasses(result));
return result;
},
// @private
doClose: function() {
this.fireEvent('close', this);
this[this.closeAction]();
},
doCollapseExpand: function (flags, animate) {
var me = this,
originalAnimCollapse = me.animCollapse,
ownerLayout = me.ownerLayout;
// we need to temporarily set animCollapse to the animate value here because ContextItem
// uses the animCollapse property to determine if the collapse/expand should be animated
me.animCollapse = animate;
// Flag used by the layout ContextItem to impose an animation policy based upon the
// collapse direction and the animCollapse setting.
me.isCollapsingOrExpanding = flags;
// The x-animating-size class sets overflow:hidden so that overflowing
// content is clipped during animation.
if (animate) {
me.addCls(Ext.baseCSSPrefix + 'animating-size');
}
if (ownerLayout && !animate) {
ownerLayout.onContentChange(me);
} else {
me.updateLayout({ isRoot: true });
}
// set animCollapse back to its original value
me.animCollapse = originalAnimCollapse;
return me;
},
endDrag: function() {
if (this.floatingDescendants) {
this.floatingDescendants.show();
}
},
/**
* パネルボディを展開し、表示させます。falseを返す場合、展開アクションをキャンセルする{@link #beforeexpand}を発火します。
* @param {Boolean} [animate] トランジションをアニメーション化する場合はtrue、それ以外はfalse(デフォルトは{@link #animCollapse}パネルコンフィグの値)。アニメーションの継続時間をミリ秒で指定することもできます。
* @return {Ext.panel.Panel} this
*/
expand: function(animate) {
var me = this,
layout = me.ownerLayout,
rendered = me.rendered;
if (me.isCollapsingOrExpanding) {
return me;
}
if (!arguments.length) {
animate = me.animCollapse;
}
if (!me.collapsed && !me.floatedFromCollapse) {
return me;
}
if (me.fireEvent('beforeexpand', me, animate) === false) {
return me;
}
if (layout && layout.onBeforeComponentExpand) {
if (layout.onBeforeComponentExpand(me) === false) {
return me;
}
}
delete me.getInherited().collapsed;
if (rendered && me.isPlaceHolderCollapse()) {
return me.placeholderExpand(animate);
}
me.restoreHiddenDocked();
if (rendered) {
me.beginExpand();
}
me.collapsed = false;
if (me.rendered) {
me.doCollapseExpand(2, animate);
}
return me;
},
findReExpander: function (direction) {
var me = this,
c = Ext.Component,
dockedItems = me.dockedItems.items,
dockedItemCount = dockedItems.length,
comp, i;
// never use the header if we're in collapseMode mini
if (me.collapseMode === 'mini') {
return;
}
switch (direction) {
case c.DIRECTION_TOP:
case c.DIRECTION_BOTTOM:
// Attempt to find a reExpander Component (docked in a horizontal orientation)
// Also, collect all other docked items which we must hide after collapse.
for (i = 0; i < dockedItemCount; i++) {
comp = dockedItems[i];
if (!comp.hidden) {
if (comp.isHeader && (!comp.dock || comp.dock === 'top' || comp.dock === 'bottom')) {
return comp;
}
}
}
break;
case c.DIRECTION_LEFT:
case c.DIRECTION_RIGHT:
// Attempt to find a reExpander Component (docked in a vecrtical orientation)
// Also, collect all other docked items which we must hide after collapse.
for (i = 0; i < dockedItemCount; i++) {
comp = dockedItems[i];
if (!comp.hidden) {
if (comp.isHeader && (comp.dock === 'left' || comp.dock === 'right')) {
return comp;
}
}
}
break;
default:
throw('Panel#findReExpander must be passed a valid collapseDirection');
}
},
floatCollapsedPanel: function() {
var me = this,
placeholder = me.placeholder,
ps = placeholder.getSize(),
myBox,
floatCls = Ext.baseCSSPrefix + 'border-region-slide-in',
collapsed = me.collapsed,
layoutOwner = me.ownerCt || me,
slideDirection,
onBodyMousedown;
if (me.isSliding) {
return;
}
// Already floated
if (me.el.hasCls(floatCls)) {
me.slideOutFloatedPanel();
return;
}
me.isSliding = true;
// Lay out in fully expanded mode to ensure we are at the correct size, and collect our expanded box
placeholder.el.hide();
placeholder.hidden = true;
me.el.show();
me.setHiddenState(false);
me.collapsed = false;
layoutOwner.updateLayout();
myBox = me.getBox(false, true);
// Then go back immediately to collapsed state from which to initiate the float into view.
placeholder.el.show();
placeholder.hidden = false;
me.el.hide();
me.setHiddenState(true);
me.collapsed = collapsed;
layoutOwner.updateLayout();
me.slideOutTask = me.slideOutTask || new Ext.util.DelayedTask(me.slideOutFloatedPanel, me);
// Tap outside the floated element slides it back.
if (Ext.supports.Touch) {
Ext.on('mousedown', onBodyMousedown = function(event) {
if (!event.within(me.el)) {
Ext.un('mousedown', onBodyMousedown);
me.slideOutFloatedPanel();
}
});
if (!me.placeholderListener) {
me.placeholderListener = placeholder.on({
resize: me.onPlaceholderResize,
scope: me,
destroyable: true
});
}
}
placeholder.el.on('mouseleave', me.onMouseLeaveFloated, me);
me.el.on('mouseleave', me.onMouseLeaveFloated, me);
placeholder.el.on('mouseenter', me.onMouseEnterFloated, me);
me.el.on('mouseenter', me.onMouseEnterFloated, me);
me.el.addCls(floatCls);
me.floated = collapsed;
// Hide collapse tool in header if there is one (we might be headerless)
if (me.collapseTool) {
me.collapseTool.el.hide();
}
switch (me.collapsed) {
case 'top':
me.setLocalXY(myBox.x, myBox.y + ps.height - 1);
break;
case 'right':
me.setLocalXY(myBox.x - ps.width + 1, myBox.y);
break;
case 'bottom':
me.setLocalXY(myBox.x, myBox.y - ps.height + 1);
break;
case 'left':
me.setLocalXY(myBox.x + ps.width - 1, myBox.y);
break;
}
slideDirection = me.convertCollapseDir(me.collapsed);
// Remember how we are really collapsed so we can restore it, but also so we can
// become a layoutRoot while we are floated:
me.floatedFromCollapse = me.collapsed;
me.collapsed = false;
me.setHiddenState(false);
me.el.slideIn(slideDirection, {
preserveScroll: true,
duration: Ext.Number.from(me.animCollapse, Ext.fx.Anim.prototype.duration),
listeners: {
afteranimate: function() {
me.isSliding = false;
me.fireEvent('float', me);
}
}
});
},
onPlaceholderResize: function(ph, newWidth, newHeight) {
var me = this,
myBox = me.getBox(false, true),
phBox = me.placeholder.getBox(false, true);
// Position floated panel alongside the placeholder, and sync the parallel dimension
switch (me.floated) {
case 'top':
this.width = newWidth;
me.setLocalY(phBox.y + phBox.height);
break;
case 'right':
this.height = newHeight;
me.setLocalX(phBox.x - myBox.width);
break;
case 'bottom':
this.width = newWidth;
me.setLocalY(phBox.y - myBox.height);
break;
case 'left':
this.height = newHeight;
me.setLocalX(phBox.x + phBox.width);
break;
}
this.updateLayout({
isRoot: true
});
},
getAnimationProps: function() {
var me = this,
animCollapse = me.animCollapse,
props;
props = me.callParent();
if (typeof animCollapse === 'number') {
props.duration = animCollapse;
}
return props;
},
/**
* 現在のパネルの折りたたみの状態を返します。
* @return {Boolean/String} 折りたたまれない場合はfalse、その他の場合は{@link #collapseDirection}の値。
*/
getCollapsed: function() {
var me = this;
// The collapsed flag, when the Panel is collapsed acts as the direction in which the collapse took
// place. It can still be tested as truthy/falsy if only a truth value is required.
if (me.collapsed === true) {
return me.collapseDirection;
}
return me.collapsed;
},
getCollapsedDockedItems: function () {
var me = this;
return me.header === false || me.collapseMode == 'placeholder' ? me.emptyArray : [ me.getReExpander() ];
},
/**
* デフォルトのコンポーネント検索を試みます({@link Ext.container.Container#getComponent}を参照してください)。コンポーネントが標準のアイテムの中に見つからなかった場合は、dockedItemsが検索され、一致したコンポーネントが返されます({@link #getDockedComponent}を参照してください)。ドッキングされたアイテムはコンポーネントのidまたはitemIdによってのみ一致することに注意してください。 数値のインデックスを渡した場合は、dockedItemsでない子コンポーネントのみが検索されます。
* @param {String/Number} comp 検索するコンポーネントのid、itemId、位置
* @return {Ext.Component} コンポーネント(見つかった場合)
* @since 2.3.0
*/
getComponent: function(comp) {
var component = this.callParent(arguments);
if (component === undefined && !Ext.isNumber(comp)) {
// If the arg is a numeric index skip docked items
component = this.getDockedComponent(comp);
}
return component;
},
* このパネルの{@link Ext.panel.Header ヘッダー}を取得します。
*/
getHeader: function() {
return this.header;
},
// Create the class array to add to the Header when collpsed.
getHeaderCollapsedClasses: function(header) {
var me = this,
collapsedCls = me.collapsedCls,
collapsedClasses;
collapsedClasses = [ collapsedCls, collapsedCls + '-' + header.getDockName()];
if (me.border && (!me.frame || (me.frame && Ext.supports.CSS3BorderRadius))) {
collapsedClasses.push(collapsedCls + '-border-' + header.getDockName());
}
return collapsedClasses;
},
// @private
getKeyMap: function() {
return this.keyMap || (this.keyMap = new Ext.util.KeyMap(Ext.apply({
target: this.el
}, this.keys)));
},
getOppositeDirection: function(d) {
var c = Ext.Component;
switch (d) {
case c.DIRECTION_TOP:
return c.DIRECTION_BOTTOM;
case c.DIRECTION_RIGHT:
return c.DIRECTION_LEFT;
case c.DIRECTION_BOTTOM:
return c.DIRECTION_TOP;
case c.DIRECTION_LEFT:
return c.DIRECTION_RIGHT;
}
},
getPlaceholder: function(direction) {
var me = this,
collapseDir = direction || me.collapseDirection,
listeners = null,
placeholder = me.placeholder,
floatable = me.floatable,
titleCollapse = me.titleCollapse;
if (!placeholder) {
if (floatable || (me.collapsible && titleCollapse)) {
listeners = {
click: {
// titleCollapse needs to take precedence over floatable
fn: (!titleCollapse && floatable) ? me.floatCollapsedPanel : me.toggleCollapse,
element: 'el',
scope: me
}
};
}
me.placeholder = placeholder = Ext.widget(me.createReExpander(collapseDir, {
id: me.id + '-placeholder',
listeners: listeners
}));
}
// User created placeholder was passed in
if (!placeholder.placeholderFor) {
// Handle the case of a placeholder config
if (!placeholder.isComponent) {
me.placeholder = placeholder = me.lookupComponent(placeholder);
}
Ext.applyIf(placeholder, {
margin: me.margin,
placeholderFor: me,
synthetic: true // not user-defined
});
placeholder.addCls([Ext.baseCSSPrefix + 'region-collapsed-placeholder', Ext.baseCSSPrefix + 'region-collapsed-' + collapseDir + '-placeholder', me.collapsedCls]);
}
return placeholder;
},
getProtoBody: function () {
var me = this,
body = me.protoBody;
if (!body) {
me.protoBody = body = new Ext.util.ProtoElement({
cls: me.bodyCls,
style: me.bodyStyle,
clsProp: 'bodyCls',
styleProp: 'bodyStyle',
styleIsText: true
});
}
return body;
},
getReExpander: function (direction) {
var me = this,
collapseDir = direction || me.collapseDirection,
reExpander = me.reExpander || me.findReExpander(collapseDir);
me.expandDirection = me.getOppositeDirection(collapseDir);
if (!reExpander) {
// We did not find a Header of the required orientation: create one.
me.reExpander = reExpander = me.createReExpander(collapseDir, {
dock: collapseDir,
cls: Ext.baseCSSPrefix + 'docked ' + me.baseCls + '-' + me.ui + '-collapsed',
isCollapsedExpander: true
});
me.dockedItems.insert(0, reExpander);
}
return reExpander;
},
getRefItems: function(deep) {
var items = this.callParent(arguments);
return this.getDockingRefItems(deep, items);
},
getState: function() {
var me = this,
state = me.callParent() || {},
collapsed = me.collapsed,
floated = me.floated,
memento;
// When taking state to restore on a page refresh, floated means collapsed
if (floated) {
me.collapsed = floated;
}
state = me.addPropertyToState(state, 'collapsed');
if (floated) {
me.collapsed = collapsed;
}
// If a collapse has taken place, use remembered values as the dimensions.
if (me.getCollapsed()) {
memento = me.getMemento('collapse').data;
state = me.addPropertyToState(state , 'collapsed', memento);
if (me.collapsedVertical()) {
delete state.height;
if (memento) {
state = me.addPropertyToState(state, 'height', memento.height);
}
} else {
delete state.width;
if (memento) {
state = me.addPropertyToState(state, 'width', memento.width);
}
}
}
return state;
},
applyState: function(state) {
var me = this,
collapseMemento = {},
collapsed;
if (state) {
collapsed = state.collapsed;
if(collapsed) {
collapseMemento = me.getMemento('collapse');
Ext.Object.merge(collapseMemento.data , collapsed);
state.collapsed = true;
}
me.callParent(arguments);
}
},
// @private
// used for dragging
ghost: function(cls) {
var me = this,
ghostPanel = me.ghostPanel,
box = me.getBox(),
header = me.header,
ghostHeader, tools, icon, iconCls, glyph, i;
if (!ghostPanel) {
me.ghostPanel = ghostPanel = Ext.widget(me.createGhost(cls));
} else {
ghostPanel.el.show();
}
ghostPanel.setHiddenState(false);
ghostPanel.floatParent = me.floatParent;
ghostPanel.toFront();
if (header && !me.preventHeader) {
ghostHeader = ghostPanel.header;
// restore options
ghostHeader.suspendLayouts();
tools = ghostHeader.query('tool');
for (i = tools.length; i--;) {
ghostHeader.remove(tools[i]);
}
// reset the title position to ensure that the title gets moved into the correct
// place after we add the tools (if the position didn't change the updater won't run)
ghostHeader.setTitlePosition(0);
ghostPanel.addTool(me.ghostTools());
ghostPanel.setTitle(me.getTitle());
ghostHeader.setTitlePosition(header.titlePosition);
iconCls = me.getIconCls();
if (iconCls) {
ghostPanel.setIconCls(iconCls);
} else {
icon = me.getIcon();
if (icon) {
ghostPanel.setIcon(icon);
} else {
glyph = me.getGlyph();
if (glyph) {
ghostPanel.setGlyph(glyph);
}
}
}
ghostHeader.addCls(Ext.baseCSSPrefix + 'header-ghost');
ghostHeader.resumeLayouts();
}
ghostPanel.setPagePosition(box.x, box.y);
ghostPanel.setSize(box.width, box.height);
me.el.hide();
return ghostPanel;
},
// @private
// helper function for ghost
ghostTools: function() {
var tools = [],
header = this.header,
headerTools = header ? header.query('tool[hidden=false]') : [],
t, tLen, tool;
if (headerTools.length) {
t = 0;
tLen = headerTools.length;
for (; t < tLen; t++) {
tool = headerTools[t];
// Some tools can be full components, and copying them into the ghost
// actually removes them from the owning panel. You could also potentially
// end up with duplicate DOM ids as well. To avoid any issues we just make
// a simple bare-minimum clone of each tool for ghosting purposes.
tools.push({
type: tool.type
});
}
} else {
tools = [{
type: 'placeholder'
}];
}
return tools;
},
initBodyBorder: function() {
var me = this;
if (me.frame && me.bodyBorder) {
if (!Ext.isNumber(me.bodyBorder)) {
me.bodyBorder = 1;
}
me.getProtoBody().setStyle('border-width', this.unitizeBox(me.bodyBorder));
}
},
/**
* ボディ要素に適用されるスタイル文字列を生成可能な場合に、{@link #bodyStyle}コンフィグをパースします。利用可能な場合、{@link #bodyPadding}および{@link #bodyBorder}も含みます。
* @return {String} ボディスタイル、パディング、ボーダーのCSSスタイル文字列
* @private
*/
initBodyStyles: function() {
var me = this,
body = me.getProtoBody();
if (me.bodyPadding !== undefined) {
if (me.layout.managePadding) {
// If the container layout manages padding, the layout will apply the
// padding to an inner element rather than the body element. The
// assumed intent is for the configured padding to override any padding
// that is applied to the body element via stylesheet rules. It is
// therefore necessary to set the body element's padding to "0".
body.setStyle('padding', 0);
} else {
body.setStyle('padding', this.unitizeBox((me.bodyPadding === true) ? 5 : me.bodyPadding));
}
}
me.initBodyBorder();
},
initBorderProps: function() {
var me = this;
if (me.frame && me.border && me.bodyBorder === undefined) {
me.bodyBorder = false;
}
if (me.frame && me.border && (me.bodyBorder === false || me.bodyBorder === 0)) {
me.manageBodyBorders = true;
}
},
initComponent: function() {
var me = this;
if (me.collapsible) {
// Save state on these two events.
me.addStateEvents(['expand', 'collapse']);
}
if (me.unstyled) {
me.setUI('plain');
}
if (me.frame) {
me.setUI(me.ui + '-framed');
}
// Backwards compatibility
me.bridgeToolbars();
me.initBorderProps();
me.callParent();
me.collapseDirection = me.collapseDirection || me.getHeaderPosition() || Ext.Component.DIRECTION_TOP;
// Used to track hidden content elements during collapsed state
me.hiddenOnCollapse = new Ext.dom.CompositeElement();
},
initItems: function() {
this.callParent();
this.initDockingItems();
},
/**
* renderTplをレンダリングするときに、使用されるrenderDataが初期化されます。
* @return {Object} renderTplへ適用されるキーと値を持つオブジェクト
* @private
*/
initRenderData: function() {
var me = this,
data = me.callParent();
me.initBodyStyles();
me.protoBody.writeTo(data);
delete me.protoBody;
return data;
},
/*
* @private
* @override
* ヘッダーを強制表示する場合のみヘッダーのサイズに基づいて表示位置を算出するPositionableメソッドのオーバーライドです。
*/
calculateConstrainedPosition: function(constrainTo, proposedPosition, local, proposedSize) {
var me = this,
fp;
// If we are only constraining the header, ask the header for its constrained position
// based upon the size the header will take on based upon this panel's proposedSize
if (me.constrainHeader) {
if (proposedSize) {
if (!me.header.vertical) {
proposedSize = [proposedSize[0], me.header.lastBox.height];
} else {
proposedSize = [me.header.lastBox.width, proposedSize[1]];
}
} else {
proposedSize = [me.header.lastBox.width, me.header.lastBox.height];
}
fp = me.floatParent;
constrainTo = constrainTo || me.constrainTo || (fp ? fp.getTargetEl() : null) || me.container || me.el.parent();
}
return me.callParent([constrainTo, proposedPosition, local, proposedSize]);
},
/**
* @private
* ツールはパネル特有の機能です。パネルはinitToolsを使用します。addToolsを実装することにより、サブクラスはツールに接続することができます。
*/
initTools: function() {
var me = this,
tools = me.tools,
i, tool;
me.tools = [];
for (i = tools && tools.length; i; ) {
--i;
me.tools[i] = tool = tools[i];
tool.toolOwner = me;
}
// Add a collapse tool unless configured to not show a collapse tool
// or to not even show a header.
if (me.collapsible && !(me.hideCollapseTool || me.header === false || me.preventHeader)) {
me.updateCollapseTool();
// Prepend collapse tool is configured to do so.
if (me.collapseFirst) {
me.tools.unshift(me.collapseTool);
}
}
// Add subclass-specific tools.
me.addTools();
if (me.pinnable) {
me.initPinnable();
}
// Make Panel closable.
if (me.closable) {
me.addClsWithUI('closable');
me.addTool({
xtype : 'tool',
type: 'close',
scope: me,
handler: me.close
});
}
// Append collapse tool if needed.
if (me.collapseTool && !me.collapseFirst) {
me.addTool(me.collapseTool);
}
},
isLayoutRoot: function() {
if (this.floatedFromCollapse) {
return true;
}
return this.callParent();
},
isPlaceHolderCollapse: function(){
return this.collapseMode == 'placeholder';
},
isVisible: function(deep){
var me = this;
if (me.collapsed && me.placeholder) {
return me.placeholder.isVisible(deep);
}
return me.callParent(arguments);
},
onBoxReady: function(){
this.callParent();
if (this.collapsed) {
this.setHiddenDocked();
}
},
onHide: function() {
var me = this,
dd = me.dd;
if (me.floatedFromCollapse) {
me.slideOutFloatedPanel(true);
}
if (me.draggable && dd) {
// Panels w/o headers won't have a Component Dragger.
dd.endDrag();
}
if (me.collapsed && me.placeholder) {
me.placeholder.hide();
} else {
me.callParent(arguments);
}
},
onMouseEnterFloated: function(e) {
this.slideOutTask.cancel();
},
onMouseLeaveFloated: function(e) {
this.slideOutTask.delay(500);
},
onRemoved: function(destroying) {
var me = this;
// If we are removed but not being destroyed, ensure our placeholder is also removed but not destroyed
// If we are being destroyed, our destroy processing will destroy the placeholder.
// Must run before callParent because that breaks the ownerCt link
if (me.placeholder && !destroying) {
me.ownerCt.remove(me.placeholder, false);
}
me.callParent(arguments);
},
onShow: function() {
var me = this;
if (me.collapsed && me.isPlaceHolderCollapse()) {
// force hidden back to true, since this gets set by the layout
me.setHiddenState(true);
me.placeholderCollapse();
} else {
me.callParent(arguments);
}
},
placeholderCollapse: function(direction, animate) {
var me = this,
ownerCt = me.ownerCt,
collapseDir = direction || me.collapseDirection,
floatCls = Ext.baseCSSPrefix + 'border-region-slide-in',
placeholder = me.getPlaceholder(collapseDir),
slideInDirection;
me.isCollapsingOrExpanding = 1;
// Upcoming layout run will ignore this Component
me.setHiddenState(true);
me.collapsed = collapseDir;
if (placeholder.rendered) {
// We may have been added to another Container from that in which we rendered the placeholder
if (placeholder.el.dom.parentNode !== me.el.dom.parentNode) {
me.el.dom.parentNode.insertBefore(placeholder.el.dom, me.el.dom);
}
placeholder.hidden = false;
placeholder.setHiddenState(false);
placeholder.el.show();
ownerCt.updateLayout();
} else {
ownerCt.insert(ownerCt.items.indexOf(me), placeholder);
}
if (me.rendered) {
// We MUST NOT hide using display because that resets all scroll information.
me.el.setVisibilityMode(me.placeholderCollapseHideMode);
if (animate) {
me.el.addCls(floatCls);
placeholder.el.hide();
slideInDirection = me.convertCollapseDir(collapseDir);
me.el.slideOut(slideInDirection, {
preserveScroll: true,
duration: Ext.Number.from(animate, Ext.fx.Anim.prototype.duration),
listeners: {
afteranimate: function() {
me.el.removeCls(floatCls);
/* We need to show the element so that slideIn will work correctly. However, if we leave it
visible then it can be seen before the animation starts, causing a flicker. The solution,
borrowed from date picker, is to hide it using display none. The slideIn effect includes
a call to fixDisplay() that will undo the display none at the appropriate time.
*/
placeholder.el.show().setStyle('display', 'none').slideIn(slideInDirection, {
easing: 'linear',
duration: 100,
listeners: {
afteranimate: function() {
placeholder.focus();
placeholder.setHiddenState(false);
me.isCollapsingOrExpanding = 0;
me.fireEvent('collapse', me);
}
}
});
}
}
});
} else {
me.el.hide();
placeholder.setHiddenState(false);
me.isCollapsingOrExpanding = 0;
me.fireEvent('collapse', me);
}
} else {
me.isCollapsingOrExpanding = 0;
if (!me.preventCollapseFire) {
me.fireEvent('collapse', me);
}
}
return me;
},
placeholderExpand: function(animate) {
var me = this,
collapseDir = me.collapsed,
floatCls = Ext.baseCSSPrefix + 'border-region-slide-in',
finalPos,
floatedPos,
center = me.ownerLayout ? me.ownerLayout.centerRegion: null;
// Layouts suspended - don't bother with animation shenanigans
if (Ext.Component.layoutSuspendCount) {
animate = false;
}
if (me.floatedFromCollapse) {
floatedPos = me.getPosition(true);
// these are the same cleanups performed by the normal slideOut mechanism:
me.slideOutFloatedPanelBegin();
me.slideOutFloatedPanelEnd();
me.floated = false;
}
if (animate) {
// Expand me and hide the placeholder
Ext.suspendLayouts();
me.placeholder.hide();
me.el.show();
me.collapsed = false;
me.setHiddenState(false);
// Stop the center region from moving when layed out without the placeholder there.
// Unless we are expanding from a floated out situation. In that case, it's layed out immediately.
if (center && !floatedPos) {
center.hidden = true;
}
Ext.resumeLayouts(true);
center.hidden = false;
me.el.addCls(floatCls);
// At this point, this Panel is arranged in its correct, expanded layout.
// The center region has not been affected because it has been flagged as hidden.
//
// If we are proceeding from floated, the center region has also been arranged
// in its new layout to accommodate this expansion, so no further layout is needed, just
// element animation.
//
// If we are proceeding from fully collapsed, the center region has *not* been relayed out because
// the UI look and feel dictates that it stays stable until the expanding panel has slid in all the
// way, and *then* it snaps into place.
me.isCollapsingOrExpanding = 2;
// Floated, move it back to the floated pos, and thence into the correct place
if (floatedPos) {
finalPos = me.getXY();
me.setLocalXY(floatedPos[0], floatedPos[1]);
me.setXY([finalPos[0], finalPos[1]], {
duration: Ext.Number.from(animate, Ext.fx.Anim.prototype.duration),
listeners: {
afteranimate: function() {
me.el.removeCls(floatCls);
me.isCollapsingOrExpanding = 0;
me.fireEvent('expand', me);
}
}
});
}
// Not floated, slide it in to the correct place
else {
me.el.hide();
me.placeholder.el.show();
me.placeholder.hidden = false;
// Slide this Component's el back into place, after which we lay out AGAIN
me.setHiddenState(false);
me.el.slideIn(me.convertCollapseDir(collapseDir), {
preserveScroll: true,
duration: Ext.Number.from(animate, Ext.fx.Anim.prototype.duration),
listeners: {
afteranimate: function() {
// the ordering of these two lines appears to be important in
// IE9. There is an odd expand issue in IE 9 in the border layout
// example that causes the index1 child of the south dock region
// to get 'hidden' after a collapse / expand cycle. See
// EXTJSIV-5318 for details
me.el.removeCls(floatCls);
me.placeholder.hide();
// The center region has been left in its larger size, so a layout is needed now
me.updateLayout();
me.isCollapsingOrExpanding = 0;
me.fireEvent('expand', me);
}
}
});
}
} else {
me.floated = me.collapsed = false;
me.el.removeCls(floatCls);
Ext.suspendLayouts();
me.placeholder.hide();
me.show();
Ext.resumeLayouts(true);
me.fireEvent('expand', me);
}
return me;
},
/**
* ボディ要素からCSSクラスを除去します。
* @param {String} cls 除去するCSSクラス
* @return {Ext.panel.Panel} this
*/
removeBodyCls: function(cls) {
var me = this,
body = me.rendered ? me.body : me.getProtoBody();
body.removeCls(cls);
return me;
},
removeUIClsFromElement: function(cls) {
var me = this,
result = me.callParent(arguments);
me.removeBodyCls([Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls]);
return result;
},
restoreDimension: function(){
var dir = this.collapseDirection;
// If we're collapsing top/bottom, we want to restore the height
// If we're collapsing left/right, we want to restore the width
return (dir === 'top' || dir === 'bottom') ? 'height' : 'width';
},
restoreHiddenDocked: function(){
var toShow = this.hiddenOnCollapse;
// Re-show Panel content which was hidden after collapse.
toShow.setStyle('visibility', '');
toShow.clear();
},
/**
* 渡されたパラメータに従ってボディスタイルを設定します。
* @param {Mixed} style 設定する完全なスタイル仕様の文字列、またはオブジェクト、またはstyleプロパティ名。
* @param {String} value 最初のパラメータがstypeプロパティ名である場合は、styleプロパティ値。
* @return {Ext.panel.Panel} this
*/
setBodyStyle: function(style, value) {
var me = this,
body = me.rendered ? me.body : me.getProtoBody();
if (Ext.isFunction(style)) {
style = style();
}
if (arguments.length == 1) {
if (Ext.isString(style)) {
style = Ext.Element.parseStyles(style);
}
body.setStyle(style);
} else {
body.setStyle(style, value);
}
return me;
},
// @inheritdoc
setBorder: function(border, targetEl) {
if (targetEl) {
// skip out here, the panel will set the border on the body/header during rendering
return;
}
var me = this,
header = me.header;
if (!border) {
border = 0;
} else if (border === true) {
border = '1px';
} else {
border = me.unitizeBox(border);
}
if (header) {
if (header.isHeader) {
header.setBorder(border);
} else {
header.border = border;
}
}
if (me.rendered && me.bodyBorder !== false) {
me.body.setStyle('border-width', border);
}
me.updateLayout();
me.border = border;
},
/**
* パネルの展開と折りたたみを行います。
* @param {Boolean} collapsed パネルを折りたたむ場合は`true`、展開する場合は`false`とします。
*/
setCollapsed: function(collapsed) {
this[collapsed ? 'collapse' : 'expand']();
},
setGlyph: function(glyph) {
var me = this,
oldGlyph = me.glyph,
header = me.header,
placeholder = me.placeholder;
if (glyph !== oldGlyph) {
me.glyph = glyph;
if (header) {
if (header.isHeader) {
header.setGlyph(glyph);
} else {
header.glyph = glyph;
}
} else if (me.rendered) {
me.updateHeader();
}
if (placeholder && placeholder.setGlyph) {
placeholder.setGlyph(glyph);
}
me.fireEvent('glyphchange', me, glyph, oldGlyph);
}
},
setIcon: function(icon) {
var me = this,
oldIcon = me.icon,
header = me.header,
placeholder = me.placeholder;
if (icon !== oldIcon) {
me.icon = icon;
if (header) {
if (header.isHeader) {
header.setIcon(icon);
} else {
header.icon = icon;
}
} else if (me.rendered) {
me.updateHeader();
}
if (placeholder && placeholder.setIcon) {
placeholder.setIcon(icon);
}
me.fireEvent('iconchange', me, icon, oldIcon);
}
},
setIconCls: function(iconCls) {
var me = this,
oldIconCls = me.iconCls,
header = me.header,
placeholder = me.placeholder;
if (iconCls !== oldIconCls) {
me.iconCls = iconCls;
if (header) {
if (header.isHeader) {
header.setIconCls(iconCls);
} else {
header.iconCls = iconCls;
}
} else if (me.rendered) {
me.updateHeader();
}
if (placeholder && placeholder.setIconCls) {
placeholder.setIconCls(iconCls);
}
me.fireEvent('iconclschange', me, iconCls, oldIconCls);
}
},
setTitle: function(title) {
var me = this,
oldTitle = me.title,
header = me.header,
reExpander = me.reExpander,
placeholder = me.placeholder;
if (title !== oldTitle) {
me.title = title;
if (header) {
if (header.isHeader) {
header.setTitle(title);
}
} else if (me.rendered) {
me.updateHeader();
}
if (reExpander) {
reExpander.setTitle(title);
}
if (placeholder && placeholder.setTitle) {
placeholder.setTitle(title);
}
me.fireEvent('titlechange', me, title, oldTitle);
}
},
setHiddenDocked: function(){
// Hide Panel content except reExpander using visibility to prevent focusing of contained elements.
// Track what we hide to re-show on expand
var me = this,
toHide = me.hiddenOnCollapse,
items = me.getDockedItems(),
len = items.length,
i = 0,
item, reExpander;
if (me.header !== false) {
reExpander = me.getReExpander();
}
toHide.add(me.body);
for (; i < len; i++) {
item = items[i];
if (item && item !== reExpander && item.el) {
toHide.add(item.el);
}
}
toHide.setStyle('visibility', 'hidden');
},
// @inheritdoc
setUI: function(ui) {
var me = this;
me.callParent(arguments);
if (me.header && me.header.rendered) {
me.header.setUI(ui);
}
},
/**
* 現在のパネルの状態に基づく{@link #method-expand}または{@link #method-collapse}を実行するショートカット。
* @return {Ext.panel.Panel} this
*/
toggleCollapse: function() {
return (this.collapsed || this.floatedFromCollapse) ? this.expand() : this.collapse();
},
updateCollapseTool: function () {
var me = this,
collapseTool = me.collapseTool;
if (!collapseTool && me.collapsible) {
me.collapseDirection = me.collapseDirection || me.getHeaderPosition() || 'top';
me.collapseTool = me.expandTool = collapseTool = Ext.widget({
xtype: 'tool',
handler: me.toggleCollapse,
scope: me
});
}
if (collapseTool) {
if (me.collapsed && !me.isPlaceHolderCollapse()) {
collapseTool.setType('expand-' + me.getOppositeDirection(me.collapseDirection));
} else {
collapseTool.setType('collapse-' + me.collapseDirection);
}
}
},
var header = this.header;
if (header && header.isHeader) {
header.setDock(position);
}
},
updateIconAlign: function(align) {
var header = this.header;
if (header && header.isHeader) {
header.setIconAlign(align);
}
},
updateTitleAlign: function(align) {
var header = this.header;
if (header && header.isHeader) {
header.setTitleAlign(align);
}
},
updateTitleRotation: function(rotation) {
var header = this.header;
if (header && header.isHeader) {
header.setTitleRotation(rotation);
}
},
// @private
unghost: function(show, matchPosition, focus) {
var me = this,
ghostPanel = me.ghostPanel;
if (!ghostPanel) {
return;
}
if (show !== false) {
// Show el first, so that position adjustment in setPagePosition
// will work when relative positioned elements have their XY read.
me.el.show();
if (matchPosition !== false) {
me.setPagePosition(ghostPanel.getXY());
if (me.hideMode === 'offsets') {
// clear the hidden style because we just repositioned
delete me.el.hideModeStyles;
}
}
if (focus) {
me.focus(false, 10);
}
}
ghostPanel.el.hide();
ghostPanel.setHiddenState(true);
},
* 現在のコンフィグに適したヘッダーを生成、非表示または表示します。
* @private
* @param {Boolean} force trueにすると、ヘッダーを強制的に生成します。
*/
updateHeader: function(force) {
var me = this,
header = me.header,
title = me.getTitle(),
tools = me.tools,
icon = me.getIcon(),
glyph = me.getGlyph(),
iconCls = me.getIconCls(),
hasIcon = glyph || icon || iconCls,
headerPosition = me.getHeaderPosition(),
vertical = headerPosition === 'left' || headerPosition === 'right';
if (Ext.isObject(header) || (header !== false && (force || (title || hasIcon) ||
(tools && tools.length) || (me.collapsible && !me.titleCollapse)))) {
if (header && header.isHeader) {
header.show();
} else {
// Apply the header property to the header config
header = me.header = Ext.widget(Ext.merge({
xtype: 'header',
title: title,
titleAlign: me.getTitleAlign(),
vertical: vertical,
dock: me.getHeaderPosition() || 'top',
titleRotation: me.getTitleRotation(),
textCls: me.headerTextCls,
iconCls: iconCls,
iconAlign: me.getIconAlign(),
icon: icon,
glyph: glyph,
baseCls: me.baseCls + '-header',
tools: tools,
ui: me.ui,
id: me.id + '_header',
overCls: me.headerOverCls,
indicateDrag: me.draggable,
frame: (me.frame || me.alwaysFramed) && me.frameHeader,
ignoreParentFrame : me.frame || me.overlapHeader,
ignoreBorderManagement: me.frame || me.ignoreHeaderBorderManagement,
headerRole: me.headerRole,
ownerCt: me,
synthetic: true, // not user-defined
listeners: me.collapsible && me.titleCollapse ? {
click: me.toggleCollapse,
scope: me
} : null
}, me.header));
// Header's onAdd mutates the tools array.
// It replaces tool configs at each index with the instantiated tool
// It also injects the tool instances as properties keyed by their type.
me.addDocked(header, 0);
}
} else if (header) {
header.hide();
}
},
// ***********************************************************************************
// End Methods
// ***********************************************************************************
// </editor-fold>
privates: {
addUIToElement: function() {
var me = this;
me.callParent(arguments);
me.addBodyCls(me.baseCls + '-body-' + me.ui);
},
applyTargetCls: function(targetCls) {
this.getProtoBody().addCls(targetCls);
},
getDefaultContentTarget: function() {
return this.body;
},
getFocusEl: function() {
return this.el;
},
getTargetEl: function() {
var me = this;
return me.body || me.protoBody || me.frameBody || me.el;
},
// @private
initDraggable: function() {
var me = this;
// For just simple dragging like Windows
if (me.simpleDrag) {
me.initSimpleDraggable();
}
// For DD package aware dragging of Panels
else {
/**
* @property {Ext.dd.DragSource/Ext.util.ComponentDragger} dd
*
* このパネルで{@link #cfg-draggable}が`true`に設定されていれば存在します。
*
* ##シンプルドラッグ##
*
* このパネルで{@link #cfg-simpleDrag}に`true`が設定されている場合(デフォルトは`false`)、 このプロパティはパネルのDOM要素の移動を処理し、{@link #constrain}および{@link #constrainHeader}に従って要素を制限する、{@link Ext.util.ComponentDragger}({@link Ext.dd.DragTracker DragTracker}のサブクラス)のインスタンスを参照します。
*
* このオブジェクトは、ライフサイクルおよびドラッグ操作中にさまざまなイベントを発火します。
*
* ##その他のDragDropインスタンス##と相互に機能する複雑なドラッグ
*
* デフォルトでは、{@link #cfg-draggable}パネル内のこのプロパティには、パネルのドラッグを扱う{@link Ext.dd.DragSource}のインスタンスが含まれます。
*
* 開発者は、ドラッグアンドドロップ処理の各ステージの動作を提供するために、{@link Ext.dd.DragSource}の抽象メソッドの実装をする必要があります。{@link #cfg-draggable}を参照してください。
*/
me.dd = new Ext.panel.DD(me, Ext.isBoolean(me.draggable) ? null : me.draggable);
}
},
initResizable: function() {
this.callParent(arguments);
if (this.collapsed) {
this.resizer.disable();
}
},
/**
* @private
* Component.initDraggableをオーバーライドします。パネル(およびサブクラス)では、ヘッダー要素をデリゲートとして使用します。
*/
initSimpleDraggable: function() {
var me = this,
ddConfig, dd;
if (!me.header) {
me.updateHeader(true);
}
/*
* ここで再度ヘッダーを確認します。理由を問わず、これがupdateHeader内に作成されなかった場合(header: falseと設定)、ヘッダーは、ドラッグハンドルとして機能するため残りは無視されます。
*/
if (me.header) {
ddConfig = Ext.applyIf({
el: me.el,
delegate: '#' + me.header.id
}, me.draggable);
// Add extra configs if Window is specified to be constrained
if (me.constrain || me.constrainHeader) {
ddConfig.constrain = me.constrain;
ddConfig.constrainDelegate = me.constrainHeader;
ddConfig.constrainTo = me.constrainTo || me.container;
}
dd = me.dd = new Ext.util.ComponentDragger(me, ddConfig);
me.relayEvents(dd, ['dragstart', 'drag', 'dragend']);
if (me.maximized) {
dd.disable();
}
}
},
removeUIFromElement: function() {
var me = this;
me.callParent(arguments);
me.removeBodyCls(me.baseCls + '-body-' + me.ui);
},
setupRenderTpl: function (renderTpl) {
this.callParent(arguments);
this.setupDockingRenderTpl(renderTpl);
},
slideOutFloatedPanel: function(preventAnimate) {
var me = this,
compEl = me.el,
collapseDirection;
if (me.isSliding || me.isDestroyed) {
return;
}
me.isSliding = true;
me.floated = false;
me.slideOutFloatedPanelBegin();
if (typeof me.collapsed == 'string') {
collapseDirection = me.convertCollapseDir(me.collapsed);
}
compEl.slideOut(collapseDirection, {
preserveScroll: true,
duration: Ext.Number.from(me.animCollapse, Ext.fx.Anim.prototype.duration),
autoEnd: preventAnimate === true,
listeners: {
afteranimate: function() {
me.slideOutFloatedPanelEnd();
// this would be in slideOutFloatedPanelEnd except that the only other
// caller removes this cls later
me.el.removeCls(Ext.baseCSSPrefix + 'border-region-slide-in');
}
}
});
},
/**
* このメソッドは浮かんでいるパネルからのスライドアウトを開始します。
* @private
*/
slideOutFloatedPanelBegin: function() {
var me = this,
placeholderEl = me.placeholder.el,
el = me.el;
me.collapsed = me.floatedFromCollapse;
me.setHiddenState(true);
me.floatedFromCollapse = null;
// Remove mouse leave/enter monitors
placeholderEl.un('mouseleave', me.onMouseLeaveFloated, me);
el.un('mouseleave', me.onMouseLeaveFloated, me);
placeholderEl.un('mouseenter', me.onMouseEnterFloated, me);
el.un('mouseenter', me.onMouseEnterFloated, me);
},
/**
* このメソッドは浮かんでいるパネルからスライドアウトした後にクリーンアップします。
* @private
*/
slideOutFloatedPanelEnd: function(suppressEvents) {
var me = this;
if (me.collapseTool) {
me.collapseTool.el.show();
}
me.slideOutTask.cancel();
me.isSliding = false;
if (!suppressEvents) {
me.fireEvent('unfloat', me);
}
}
} // private
}, function() {
var proto = this.prototype;
proto.animCollapse = Ext.enableFx;
proto.placeholderCollapseHideMode = Ext.Element.VISIBILITY;
});