/ext-4.0.7/docs/source/Border.html

https://bitbucket.org/srogerf/javascript · HTML · 1130 lines · 1004 code · 126 blank · 0 comment · 0 complexity · 5d4366a9c99954a646446b4ac23f7480 MD5 · raw file

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-layout-container-Border'>/**
  19. </span> * This is a multi-pane, application-oriented UI layout style that supports multiple nested panels, automatic bars
  20. * between regions and built-in {@link Ext.panel.Panel#collapsible expanding and collapsing} of regions.
  21. *
  22. * This class is intended to be extended or created via the `layout:'border'` {@link Ext.container.Container#layout}
  23. * config, and should generally not need to be created directly via the new keyword.
  24. *
  25. * @example
  26. * Ext.create('Ext.panel.Panel', {
  27. * width: 500,
  28. * height: 400,
  29. * title: 'Border Layout',
  30. * layout: 'border',
  31. * items: [{
  32. * title: 'South Region is resizable',
  33. * region: 'south', // position for region
  34. * xtype: 'panel',
  35. * height: 100,
  36. * split: true, // enable resizing
  37. * margins: '0 5 5 5'
  38. * },{
  39. * // xtype: 'panel' implied by default
  40. * title: 'West Region is collapsible',
  41. * region:'west',
  42. * xtype: 'panel',
  43. * margins: '5 0 0 5',
  44. * width: 200,
  45. * collapsible: true, // make collapsible
  46. * id: 'west-region-container',
  47. * layout: 'fit'
  48. * },{
  49. * title: 'Center Region',
  50. * region: 'center', // center region is required, no width/height specified
  51. * xtype: 'panel',
  52. * layout: 'fit',
  53. * margins: '5 5 0 0'
  54. * }],
  55. * renderTo: Ext.getBody()
  56. * });
  57. *
  58. * # Notes
  59. *
  60. * - Any Container using the Border layout **must** have a child item with `region:'center'`.
  61. * The child item in the center region will always be resized to fill the remaining space
  62. * not used by the other regions in the layout.
  63. *
  64. * - Any child items with a region of `west` or `east` may be configured with either an initial
  65. * `width`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage width
  66. * **string** (Which is simply divided by 100 and used as a flex value).
  67. * The 'center' region has a flex value of `1`.
  68. *
  69. * - Any child items with a region of `north` or `south` may be configured with either an initial
  70. * `height`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage height
  71. * **string** (Which is simply divided by 100 and used as a flex value).
  72. * The 'center' region has a flex value of `1`.
  73. *
  74. * - The regions of a BorderLayout are **fixed at render time** and thereafter, its child
  75. * Components may not be removed or added**. To add/remove Components within a BorderLayout,
  76. * have them wrapped by an additional Container which is directly managed by the BorderLayout.
  77. * If the region is to be collapsible, the Container used directly by the BorderLayout manager
  78. * should be a Panel. In the following example a Container (an Ext.panel.Panel) is added to
  79. * the west region:
  80. *
  81. * wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
  82. * wrc.{@link Ext.container.Container#removeAll removeAll}();
  83. * wrc.{@link Ext.container.Container#add add}({
  84. * title: 'Added Panel',
  85. * html: 'Some content'
  86. * });
  87. *
  88. * - **There is no BorderLayout.Region class in ExtJS 4.0+**
  89. */
  90. Ext.define('Ext.layout.container.Border', {
  91. alias: ['layout.border'],
  92. extend: 'Ext.layout.container.Container',
  93. requires: ['Ext.resizer.Splitter', 'Ext.container.Container', 'Ext.fx.Anim'],
  94. alternateClassName: 'Ext.layout.BorderLayout',
  95. targetCls: Ext.baseCSSPrefix + 'border-layout-ct',
  96. itemCls: Ext.baseCSSPrefix + 'border-item',
  97. bindToOwnerCtContainer: true,
  98. percentageRe: /(\d+)%/,
  99. slideDirection: {
  100. north: 't',
  101. south: 'b',
  102. west: 'l',
  103. east: 'r'
  104. },
  105. constructor: function(config) {
  106. this.initialConfig = config;
  107. this.callParent(arguments);
  108. },
  109. onLayout: function() {
  110. var me = this;
  111. if (!me.borderLayoutInitialized) {
  112. me.initializeBorderLayout();
  113. }
  114. // Delegate this operation to the shadow &quot;V&quot; or &quot;H&quot; box layout, and then down to any embedded layout.
  115. me.fixHeightConstraints();
  116. me.shadowLayout.onLayout();
  117. if (me.embeddedContainer) {
  118. me.embeddedContainer.layout.onLayout();
  119. }
  120. // If the panel was originally configured with collapsed: true, it will have
  121. // been initialized with a &quot;borderCollapse&quot; flag: Collapse it now before the first layout.
  122. if (!me.initialCollapsedComplete) {
  123. Ext.iterate(me.regions, function(name, region){
  124. if (region.borderCollapse) {
  125. me.onBeforeRegionCollapse(region, region.collapseDirection, false, 0);
  126. }
  127. });
  128. me.initialCollapsedComplete = true;
  129. }
  130. },
  131. isValidParent : function(item, target, position) {
  132. if (!this.borderLayoutInitialized) {
  133. this.initializeBorderLayout();
  134. }
  135. // Delegate this operation to the shadow &quot;V&quot; or &quot;H&quot; box layout.
  136. return this.shadowLayout.isValidParent(item, target, position);
  137. },
  138. beforeLayout: function() {
  139. if (!this.borderLayoutInitialized) {
  140. this.initializeBorderLayout();
  141. }
  142. // Delegate this operation to the shadow &quot;V&quot; or &quot;H&quot; box layout.
  143. this.shadowLayout.beforeLayout();
  144. // note: don't call base because that does a renderItems again
  145. },
  146. renderItems: function(items, target) {
  147. //&lt;debug&gt;
  148. Ext.Error.raise('This should not be called');
  149. //&lt;/debug&gt;
  150. },
  151. renderItem: function(item) {
  152. //&lt;debug&gt;
  153. Ext.Error.raise('This should not be called');
  154. //&lt;/debug&gt;
  155. },
  156. renderChildren: function() {
  157. if (!this.borderLayoutInitialized) {
  158. this.initializeBorderLayout();
  159. }
  160. this.shadowLayout.renderChildren();
  161. },
  162. /*
  163. * Gathers items for a layout operation. Injected into child Box layouts through configuration.
  164. * We must not include child items which are floated over the layout (are primed with a slide out animation)
  165. */
  166. getVisibleItems: function() {
  167. return Ext.ComponentQuery.query(':not([slideOutAnim])', this.callParent(arguments));
  168. },
  169. initializeBorderLayout: function() {
  170. var me = this,
  171. i = 0,
  172. items = me.getLayoutItems(),
  173. ln = items.length,
  174. regions = (me.regions = {}),
  175. vBoxItems = [],
  176. hBoxItems = [],
  177. horizontalFlex = 0,
  178. verticalFlex = 0,
  179. comp, percentage;
  180. // Map of Splitters for each region
  181. me.splitters = {};
  182. // Map of regions
  183. for (; i &lt; ln; i++) {
  184. comp = items[i];
  185. regions[comp.region] = comp;
  186. // Intercept collapsing to implement showing an alternate Component as a collapsed placeholder
  187. if (comp.region != 'center' &amp;&amp; comp.collapsible &amp;&amp; comp.collapseMode != 'header') {
  188. // This layout intercepts any initial collapsed state. Panel must not do this itself.
  189. comp.borderCollapse = comp.collapsed;
  190. comp.collapsed = false;
  191. comp.on({
  192. beforecollapse: me.onBeforeRegionCollapse,
  193. beforeexpand: me.onBeforeRegionExpand,
  194. destroy: me.onRegionDestroy,
  195. scope: me
  196. });
  197. me.setupState(comp);
  198. }
  199. }
  200. //&lt;debug&gt;
  201. if (!regions.center) {
  202. Ext.Error.raise(&quot;You must specify a center region when defining a BorderLayout.&quot;);
  203. }
  204. //&lt;/debug&gt;
  205. comp = regions.center;
  206. if (!comp.flex) {
  207. comp.flex = 1;
  208. }
  209. delete comp.width;
  210. comp.maintainFlex = true;
  211. // Begin the VBox and HBox item list.
  212. comp = regions.west;
  213. if (comp) {
  214. comp.collapseDirection = Ext.Component.DIRECTION_LEFT;
  215. hBoxItems.push(comp);
  216. if (comp.split) {
  217. hBoxItems.push(me.splitters.west = me.createSplitter(comp));
  218. }
  219. percentage = Ext.isString(comp.width) &amp;&amp; comp.width.match(me.percentageRe);
  220. if (percentage) {
  221. horizontalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
  222. delete comp.width;
  223. }
  224. }
  225. comp = regions.north;
  226. if (comp) {
  227. comp.collapseDirection = Ext.Component.DIRECTION_TOP;
  228. vBoxItems.push(comp);
  229. if (comp.split) {
  230. vBoxItems.push(me.splitters.north = me.createSplitter(comp));
  231. }
  232. percentage = Ext.isString(comp.height) &amp;&amp; comp.height.match(me.percentageRe);
  233. if (percentage) {
  234. verticalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
  235. delete comp.height;
  236. }
  237. }
  238. // Decide into which Collection the center region goes.
  239. if (regions.north || regions.south) {
  240. if (regions.east || regions.west) {
  241. // Create the embedded center. Mark it with the region: 'center' property so that it can be identified as the center.
  242. vBoxItems.push(me.embeddedContainer = Ext.create('Ext.container.Container', {
  243. xtype: 'container',
  244. region: 'center',
  245. id: me.owner.id + '-embedded-center',
  246. cls: Ext.baseCSSPrefix + 'border-item',
  247. flex: regions.center.flex,
  248. maintainFlex: true,
  249. layout: {
  250. type: 'hbox',
  251. align: 'stretch',
  252. getVisibleItems: me.getVisibleItems
  253. }
  254. }));
  255. hBoxItems.push(regions.center);
  256. }
  257. // No east or west: the original center goes straight into the vbox
  258. else {
  259. vBoxItems.push(regions.center);
  260. }
  261. }
  262. // If we have no north or south, then the center is part of the HBox items
  263. else {
  264. hBoxItems.push(regions.center);
  265. }
  266. // Finish off the VBox and HBox item list.
  267. comp = regions.south;
  268. if (comp) {
  269. comp.collapseDirection = Ext.Component.DIRECTION_BOTTOM;
  270. if (comp.split) {
  271. vBoxItems.push(me.splitters.south = me.createSplitter(comp));
  272. }
  273. percentage = Ext.isString(comp.height) &amp;&amp; comp.height.match(me.percentageRe);
  274. if (percentage) {
  275. verticalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
  276. delete comp.height;
  277. }
  278. vBoxItems.push(comp);
  279. }
  280. comp = regions.east;
  281. if (comp) {
  282. comp.collapseDirection = Ext.Component.DIRECTION_RIGHT;
  283. if (comp.split) {
  284. hBoxItems.push(me.splitters.east = me.createSplitter(comp));
  285. }
  286. percentage = Ext.isString(comp.width) &amp;&amp; comp.width.match(me.percentageRe);
  287. if (percentage) {
  288. horizontalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
  289. delete comp.width;
  290. }
  291. hBoxItems.push(comp);
  292. }
  293. // Create the injected &quot;items&quot; collections for the Containers.
  294. // If we have north or south, then the shadow Container will be a VBox.
  295. // If there are also east or west regions, its center will be a shadow HBox.
  296. // If there are *only* east or west regions, then the shadow layout will be an HBox (or Fit).
  297. if (regions.north || regions.south) {
  298. me.shadowContainer = Ext.create('Ext.container.Container', {
  299. ownerCt: me.owner,
  300. el: me.getTarget(),
  301. layout: Ext.applyIf({
  302. type: 'vbox',
  303. align: 'stretch',
  304. getVisibleItems: me.getVisibleItems
  305. }, me.initialConfig)
  306. });
  307. me.createItems(me.shadowContainer, vBoxItems);
  308. // Allow the Splitters to orientate themselves
  309. if (me.splitters.north) {
  310. me.splitters.north.ownerCt = me.shadowContainer;
  311. }
  312. if (me.splitters.south) {
  313. me.splitters.south.ownerCt = me.shadowContainer;
  314. }
  315. // Inject items into the HBox Container if there is one - if there was an east or west.
  316. if (me.embeddedContainer) {
  317. me.embeddedContainer.ownerCt = me.shadowContainer;
  318. me.createItems(me.embeddedContainer, hBoxItems);
  319. // Allow the Splitters to orientate themselves
  320. if (me.splitters.east) {
  321. me.splitters.east.ownerCt = me.embeddedContainer;
  322. }
  323. if (me.splitters.west) {
  324. me.splitters.west.ownerCt = me.embeddedContainer;
  325. }
  326. // These spliiters need to be constrained by components one-level below
  327. // the component in their vobx. We update the min/maxHeight on the helper
  328. // (embeddedContainer) prior to starting the split/drag. This has to be
  329. // done on-the-fly to allow min/maxHeight of the E/C/W regions to be set
  330. // dynamically.
  331. Ext.each([me.splitters.north, me.splitters.south], function (splitter) {
  332. if (splitter) {
  333. splitter.on('beforedragstart', me.fixHeightConstraints, me);
  334. }
  335. });
  336. // The east or west region wanted a percentage
  337. if (horizontalFlex) {
  338. regions.center.flex -= horizontalFlex;
  339. }
  340. // The north or south region wanted a percentage
  341. if (verticalFlex) {
  342. me.embeddedContainer.flex -= verticalFlex;
  343. }
  344. } else {
  345. // The north or south region wanted a percentage
  346. if (verticalFlex) {
  347. regions.center.flex -= verticalFlex;
  348. }
  349. }
  350. }
  351. // If we have no north or south, then there's only one Container, and it's
  352. // an HBox, or, if only a center region was specified, a Fit.
  353. else {
  354. me.shadowContainer = Ext.create('Ext.container.Container', {
  355. ownerCt: me.owner,
  356. el: me.getTarget(),
  357. layout: Ext.applyIf({
  358. type: (hBoxItems.length == 1) ? 'fit' : 'hbox',
  359. align: 'stretch'
  360. }, me.initialConfig)
  361. });
  362. me.createItems(me.shadowContainer, hBoxItems);
  363. // Allow the Splitters to orientate themselves
  364. if (me.splitters.east) {
  365. me.splitters.east.ownerCt = me.shadowContainer;
  366. }
  367. if (me.splitters.west) {
  368. me.splitters.west.ownerCt = me.shadowContainer;
  369. }
  370. // The east or west region wanted a percentage
  371. if (horizontalFlex) {
  372. regions.center.flex -= verticalFlex;
  373. }
  374. }
  375. // Create upward links from the region Components to their shadow ownerCts
  376. for (i = 0, items = me.shadowContainer.items.items, ln = items.length; i &lt; ln; i++) {
  377. items[i].shadowOwnerCt = me.shadowContainer;
  378. }
  379. if (me.embeddedContainer) {
  380. for (i = 0, items = me.embeddedContainer.items.items, ln = items.length; i &lt; ln; i++) {
  381. items[i].shadowOwnerCt = me.embeddedContainer;
  382. }
  383. }
  384. // This is the layout that we delegate all operations to
  385. me.shadowLayout = me.shadowContainer.getLayout();
  386. me.borderLayoutInitialized = true;
  387. },
  388. setupState: function(comp){
  389. var getState = comp.getState;
  390. comp.getState = function(){
  391. // call the original getState
  392. var state = getState.call(comp) || {},
  393. region = comp.region;
  394. state.collapsed = !!comp.collapsed;
  395. if (region == 'west' || region == 'east') {
  396. state.width = comp.getWidth();
  397. } else {
  398. state.height = comp.getHeight();
  399. }
  400. return state;
  401. };
  402. comp.addStateEvents(['collapse', 'expand', 'resize']);
  403. },
  404. <span id='Ext-layout-container-Border-method-createItems'> /**
  405. </span> * Create the items collection for our shadow/embedded containers
  406. * @private
  407. */
  408. createItems: function(container, items){
  409. // Have to inject an items Collection *after* construction.
  410. // The child items of the shadow layout must retain their original, user-defined ownerCt
  411. delete container.items;
  412. container.initItems();
  413. container.items.addAll(items);
  414. },
  415. // Private
  416. // Create a splitter for a child of the layout.
  417. createSplitter: function(comp) {
  418. var me = this,
  419. interceptCollapse = (comp.collapseMode != 'header'),
  420. resizer;
  421. resizer = Ext.create('Ext.resizer.Splitter', {
  422. hidden: !!comp.hidden,
  423. collapseTarget: comp,
  424. performCollapse: !interceptCollapse,
  425. listeners: interceptCollapse ? {
  426. click: {
  427. fn: Ext.Function.bind(me.onSplitterCollapseClick, me, [comp]),
  428. element: 'collapseEl'
  429. }
  430. } : null
  431. });
  432. // Mini collapse means that the splitter is the placeholder Component
  433. if (comp.collapseMode == 'mini') {
  434. comp.placeholder = resizer;
  435. resizer.collapsedCls = comp.collapsedCls;
  436. }
  437. // Arrange to hide/show a region's associated splitter when the region is hidden/shown
  438. comp.on({
  439. hide: me.onRegionVisibilityChange,
  440. show: me.onRegionVisibilityChange,
  441. scope: me
  442. });
  443. return resizer;
  444. },
  445. // Private
  446. // Propagates the min/maxHeight values from the inner hbox items to its container.
  447. fixHeightConstraints: function () {
  448. var me = this,
  449. ct = me.embeddedContainer,
  450. maxHeight = 1e99, minHeight = -1;
  451. if (!ct) {
  452. return;
  453. }
  454. ct.items.each(function (item) {
  455. if (Ext.isNumber(item.maxHeight)) {
  456. maxHeight = Math.max(maxHeight, item.maxHeight);
  457. }
  458. if (Ext.isNumber(item.minHeight)) {
  459. minHeight = Math.max(minHeight, item.minHeight);
  460. }
  461. });
  462. ct.maxHeight = maxHeight;
  463. ct.minHeight = minHeight;
  464. },
  465. // Hide/show a region's associated splitter when the region is hidden/shown
  466. onRegionVisibilityChange: function(comp){
  467. this.splitters[comp.region][comp.hidden ? 'hide' : 'show']();
  468. this.layout();
  469. },
  470. // Called when a splitter mini-collapse tool is clicked on.
  471. // The listener is only added if this layout is controlling collapsing,
  472. // not if the component's collapseMode is 'mini' or 'header'.
  473. onSplitterCollapseClick: function(comp) {
  474. if (comp.collapsed) {
  475. this.onPlaceHolderToolClick(null, null, null, {client: comp});
  476. } else {
  477. comp.collapse();
  478. }
  479. },
  480. <span id='Ext-layout-container-Border-method-getPlaceholder'> /**
  481. </span> * Return the {@link Ext.panel.Panel#placeholder placeholder} Component to which the passed child Panel of the
  482. * layout will collapse. By default, this will be a {@link Ext.panel.Header Header} component (Docked to the
  483. * appropriate border). See {@link Ext.panel.Panel#placeholder placeholder}. config to customize this.
  484. *
  485. * **Note that this will be a fully instantiated Component, but will only be _rendered_ when the Panel is first
  486. * collapsed.**
  487. * @param {Ext.panel.Panel} panel The child Panel of the layout for which to return the {@link
  488. * Ext.panel.Panel#placeholder placeholder}.
  489. * @return {Ext.Component} The Panel's {@link Ext.panel.Panel#placeholder placeholder} unless the {@link
  490. * Ext.panel.Panel#collapseMode collapseMode} is `'header'`, in which case _undefined_ is returned.
  491. */
  492. getPlaceholder: function(comp) {
  493. var me = this,
  494. placeholder = comp.placeholder,
  495. shadowContainer = comp.shadowOwnerCt,
  496. shadowLayout = shadowContainer.layout,
  497. oppositeDirection = Ext.panel.Panel.prototype.getOppositeDirection(comp.collapseDirection),
  498. horiz = (comp.region == 'north' || comp.region == 'south');
  499. // No placeholder if the collapse mode is not the Border layout default
  500. if (comp.collapseMode == 'header') {
  501. return;
  502. }
  503. // Provide a replacement Container with an expand tool
  504. if (!placeholder) {
  505. if (comp.collapseMode == 'mini') {
  506. placeholder = Ext.create('Ext.resizer.Splitter', {
  507. id: 'collapse-placeholder-' + comp.id,
  508. collapseTarget: comp,
  509. performCollapse: false,
  510. listeners: {
  511. click: {
  512. fn: Ext.Function.bind(me.onSplitterCollapseClick, me, [comp]),
  513. element: 'collapseEl'
  514. }
  515. }
  516. });
  517. placeholder.addCls(placeholder.collapsedCls);
  518. } else {
  519. placeholder = {
  520. id: 'collapse-placeholder-' + comp.id,
  521. margins: comp.initialConfig.margins || Ext.getClass(comp).prototype.margins,
  522. xtype: 'header',
  523. orientation: horiz ? 'horizontal' : 'vertical',
  524. title: comp.title,
  525. textCls: comp.headerTextCls,
  526. iconCls: comp.iconCls,
  527. baseCls: comp.baseCls + '-header',
  528. ui: comp.ui,
  529. indicateDrag: comp.draggable,
  530. cls: Ext.baseCSSPrefix + 'region-collapsed-placeholder ' + Ext.baseCSSPrefix + 'region-collapsed-' + comp.collapseDirection + '-placeholder ' + comp.collapsedCls,
  531. listeners: comp.floatable ? {
  532. click: {
  533. fn: function(e) {
  534. me.floatCollapsedPanel(e, comp);
  535. },
  536. element: 'el'
  537. }
  538. } : null
  539. };
  540. // Hack for IE6/7/IEQuirks's inability to display an inline-block
  541. if ((Ext.isIE6 || Ext.isIE7 || (Ext.isIEQuirks)) &amp;&amp; !horiz) {
  542. placeholder.width = 25;
  543. }
  544. if (!comp.hideCollapseTool) {
  545. placeholder[horiz ? 'tools' : 'items'] = [{
  546. xtype: 'tool',
  547. client: comp,
  548. type: 'expand-' + oppositeDirection,
  549. handler: me.onPlaceHolderToolClick,
  550. scope: me
  551. }];
  552. }
  553. }
  554. placeholder = me.owner.createComponent(placeholder);
  555. if (comp.isXType('panel')) {
  556. comp.on({
  557. titlechange: me.onRegionTitleChange,
  558. iconchange: me.onRegionIconChange,
  559. scope: me
  560. });
  561. }
  562. }
  563. // The collapsed Component holds a reference to its placeholder and vice versa
  564. comp.placeholder = placeholder;
  565. placeholder.comp = comp;
  566. return placeholder;
  567. },
  568. <span id='Ext-layout-container-Border-method-onRegionTitleChange'> /**
  569. </span> * @private
  570. * Update the placeholder title when panel title has been set or changed.
  571. */
  572. onRegionTitleChange: function(comp, newTitle) {
  573. comp.placeholder.setTitle(newTitle);
  574. },
  575. <span id='Ext-layout-container-Border-method-onRegionIconChange'> /**
  576. </span> * @private
  577. * Update the placeholder iconCls when panel iconCls has been set or changed.
  578. */
  579. onRegionIconChange: function(comp, newIconCls) {
  580. comp.placeholder.setIconCls(newIconCls);
  581. },
  582. <span id='Ext-layout-container-Border-method-calculateChildBox'> /**
  583. </span> * @private
  584. * Calculates the size and positioning of the passed child item. Must be present because Panel's expand,
  585. * when configured with a flex, calls this method on its ownerCt's layout.
  586. * @param {Ext.Component} child The child Component to calculate the box for
  587. * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
  588. */
  589. calculateChildBox: function(comp) {
  590. var me = this;
  591. if (me.shadowContainer.items.contains(comp)) {
  592. return me.shadowContainer.layout.calculateChildBox(comp);
  593. }
  594. else if (me.embeddedContainer &amp;&amp; me.embeddedContainer.items.contains(comp)) {
  595. return me.embeddedContainer.layout.calculateChildBox(comp);
  596. }
  597. },
  598. <span id='Ext-layout-container-Border-method-onBeforeRegionCollapse'> /**
  599. </span> * @private
  600. * Intercepts the Panel's own collapse event and perform's substitution of the Panel
  601. * with a placeholder Header orientated in the appropriate dimension.
  602. * @param comp The Panel being collapsed.
  603. * @param direction
  604. * @param animate
  605. * @returns {Boolean} false to inhibit the Panel from performing its own collapse.
  606. */
  607. onBeforeRegionCollapse: function(comp, direction, animate) {
  608. if (comp.collapsedChangingLayout) {
  609. //&lt;debug warn&gt;
  610. if (Ext.global.console &amp;&amp; Ext.global.console.warn) {
  611. Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
  612. }
  613. //&lt;/debug&gt;
  614. return false;
  615. }
  616. comp.collapsedChangingLayout = true;
  617. var me = this,
  618. compEl = comp.el,
  619. width,
  620. miniCollapse = comp.collapseMode == 'mini',
  621. shadowContainer = comp.shadowOwnerCt,
  622. shadowLayout = shadowContainer.layout,
  623. placeholder = comp.placeholder,
  624. sl = me.owner.suspendLayout,
  625. scsl = shadowContainer.suspendLayout,
  626. isNorthOrWest = (comp.region == 'north' || comp.region == 'west'); // Flag to keep the placeholder non-adjacent to any Splitter
  627. // Do not trigger a layout during transition to collapsed Component
  628. me.owner.suspendLayout = true;
  629. shadowContainer.suspendLayout = true;
  630. // Prevent upward notifications from downstream layouts
  631. shadowLayout.layoutBusy = true;
  632. if (shadowContainer.componentLayout) {
  633. shadowContainer.componentLayout.layoutBusy = true;
  634. }
  635. me.shadowContainer.layout.layoutBusy = true;
  636. me.layoutBusy = true;
  637. me.owner.componentLayout.layoutBusy = true;
  638. // Provide a replacement Container with an expand tool
  639. if (!placeholder) {
  640. placeholder = me.getPlaceholder(comp);
  641. }
  642. // placeholder already in place; show it.
  643. if (placeholder.shadowOwnerCt === shadowContainer) {
  644. placeholder.show();
  645. }
  646. // Insert the collapsed placeholder Component into the appropriate Box layout shadow Container
  647. // It must go next to its client Component, but non-adjacent to the splitter so splitter can find its collapse client.
  648. // Inject an ownerCt value pointing to the owner, border layout Container as the user will expect.
  649. else {
  650. shadowContainer.insert(shadowContainer.items.indexOf(comp) + (isNorthOrWest ? 0 : 1), placeholder);
  651. placeholder.shadowOwnerCt = shadowContainer;
  652. placeholder.ownerCt = me.owner;
  653. }
  654. // Flag the collapsing Component as hidden and show the placeholder.
  655. // This causes the shadow Box layout's calculateChildBoxes to calculate the correct new arrangement.
  656. // We hide or slideOut the Component's element
  657. comp.hidden = true;
  658. if (!placeholder.rendered) {
  659. shadowLayout.renderItem(placeholder, shadowLayout.innerCt);
  660. // The inserted placeholder does not have the proper size, so copy the width
  661. // for N/S or the height for E/W from the component. This fixes EXTJSIV-1562
  662. // without recursive layouts. This is only an issue initially. After this time,
  663. // placeholder will have the correct width/height set by the layout (which has
  664. // already happened when we get here initially).
  665. if (comp.region == 'north' || comp.region == 'south') {
  666. placeholder.setCalculatedSize(comp.getWidth());
  667. } else {
  668. placeholder.setCalculatedSize(undefined, comp.getHeight());
  669. }
  670. }
  671. // Jobs to be done after the collapse has been done
  672. function afterCollapse() {
  673. // Reinstate automatic laying out.
  674. me.owner.suspendLayout = sl;
  675. shadowContainer.suspendLayout = scsl;
  676. delete shadowLayout.layoutBusy;
  677. if (shadowContainer.componentLayout) {
  678. delete shadowContainer.componentLayout.layoutBusy;
  679. }
  680. delete me.shadowContainer.layout.layoutBusy;
  681. delete me.layoutBusy;
  682. delete me.owner.componentLayout.layoutBusy;
  683. delete comp.collapsedChangingLayout;
  684. // Fire the collapse event: The Panel has in fact been collapsed, but by substitution of an alternative Component
  685. comp.collapsed = true;
  686. comp.fireEvent('collapse', comp);
  687. }
  688. /*
  689. * Set everything to the new positions. Note that we
  690. * only want to animate the collapse if it wasn't configured
  691. * initially with collapsed: true
  692. */
  693. if (comp.animCollapse &amp;&amp; me.initialCollapsedComplete) {
  694. shadowLayout.layout();
  695. compEl.dom.style.zIndex = 100;
  696. // If we're mini-collapsing, the placholder is a Splitter. We don't want it to &quot;bounce in&quot;
  697. if (!miniCollapse) {
  698. placeholder.el.hide();
  699. }
  700. compEl.slideOut(me.slideDirection[comp.region], {
  701. duration: Ext.Number.from(comp.animCollapse, Ext.fx.Anim.prototype.duration),
  702. listeners: {
  703. afteranimate: function() {
  704. compEl.show().setLeftTop(-10000, -10000);
  705. compEl.dom.style.zIndex = '';
  706. // If we're mini-collapsing, the placholder is a Splitter. We don't want it to &quot;bounce in&quot;
  707. if (!miniCollapse) {
  708. placeholder.el.slideIn(me.slideDirection[comp.region], {
  709. easing: 'linear',
  710. duration: 100
  711. });
  712. }
  713. afterCollapse();
  714. }
  715. }
  716. });
  717. } else {
  718. compEl.setLeftTop(-10000, -10000);
  719. shadowLayout.layout();
  720. afterCollapse();
  721. }
  722. return false;
  723. },
  724. // Hijack the expand operation to remove the placeholder and slide the region back in.
  725. onBeforeRegionExpand: function(comp, animate) {
  726. // We don't check for comp.collapsedChangingLayout here because onPlaceHolderToolClick does it
  727. this.onPlaceHolderToolClick(null, null, null, {client: comp, shouldFireBeforeexpand: false});
  728. return false;
  729. },
  730. // Called when the collapsed placeholder is clicked to reinstate a &quot;collapsed&quot; (in reality hidden) Panel.
  731. onPlaceHolderToolClick: function(e, target, owner, tool) {
  732. var me = this,
  733. comp = tool.client,
  734. // Hide the placeholder unless it was the Component's preexisting splitter
  735. hidePlaceholder = (comp.collapseMode != 'mini') || !comp.split,
  736. compEl = comp.el,
  737. toCompBox,
  738. placeholder = comp.placeholder,
  739. placeholderEl = placeholder.el,
  740. shadowContainer = comp.shadowOwnerCt,
  741. shadowLayout = shadowContainer.layout,
  742. curSize,
  743. sl = me.owner.suspendLayout,
  744. scsl = shadowContainer.suspendLayout,
  745. isFloating;
  746. if (comp.collapsedChangingLayout) {
  747. //&lt;debug warn&gt;
  748. if (Ext.global.console &amp;&amp; Ext.global.console.warn) {
  749. Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
  750. }
  751. //&lt;/debug&gt;
  752. return false;
  753. }
  754. if (tool.shouldFireBeforeexpand !== false &amp;&amp; comp.fireEvent('beforeexpand', comp, true) === false) {
  755. return false;
  756. }
  757. comp.collapsedChangingLayout = true;
  758. // If the slide in is still going, stop it.
  759. // This will either leave the Component in its fully floated state (which is processed below)
  760. // or in its collapsed state. Either way, we expand it..
  761. if (comp.getActiveAnimation()) {
  762. comp.stopAnimation();
  763. }
  764. // If the Component is fully floated when they click the placeholder Tool,
  765. // it will be primed with a slide out animation object... so delete that
  766. // and remove the mouseout listeners
  767. if (comp.slideOutAnim) {
  768. // Remove mouse leave monitors
  769. compEl.un(comp.panelMouseMon);
  770. placeholderEl.un(comp.placeholderMouseMon);
  771. delete comp.slideOutAnim;
  772. delete comp.panelMouseMon;
  773. delete comp.placeholderMouseMon;
  774. // If the Panel was floated and primed with a slideOut animation, we don't want to animate its layout operation.
  775. isFloating = true;
  776. }
  777. // Do not trigger a layout during transition to expanded Component
  778. me.owner.suspendLayout = true;
  779. shadowContainer.suspendLayout = true;
  780. // Prevent upward notifications from downstream layouts
  781. shadowLayout.layoutBusy = true;
  782. if (shadowContainer.componentLayout) {
  783. shadowContainer.componentLayout.layoutBusy = true;
  784. }
  785. me.shadowContainer.layout.layoutBusy = true;
  786. me.layoutBusy = true;
  787. me.owner.componentLayout.layoutBusy = true;
  788. // Unset the hidden and collapsed flags set in onBeforeRegionCollapse. The shadowLayout will now take it into account
  789. // Find where the shadow Box layout plans to put the expanding Component.
  790. comp.hidden = false;
  791. comp.collapsed = false;
  792. if (hidePlaceholder) {
  793. placeholder.hidden = true;
  794. }
  795. toCompBox = shadowLayout.calculateChildBox(comp);
  796. // Show the collapse tool in case it was hidden by the slide-in
  797. if (comp.collapseTool) {
  798. comp.collapseTool.show();
  799. }
  800. // If we're going to animate, we need to hide the component before moving it back into position
  801. if (comp.animCollapse &amp;&amp; !isFloating) {
  802. compEl.setStyle('visibility', 'hidden');
  803. }
  804. compEl.setLeftTop(toCompBox.left, toCompBox.top);
  805. // Equalize the size of the expanding Component prior to animation
  806. // in case the layout area has changed size during the time it was collapsed.
  807. curSize = comp.getSize();
  808. if (curSize.height != toCompBox.height || curSize.width != toCompBox.width) {
  809. me.setItemSize(comp, toCompBox.width, toCompBox.height);
  810. }
  811. // Jobs to be done after the expand has been done
  812. function afterExpand() {
  813. // Reinstate automatic laying out.
  814. me.owner.suspendLayout = sl;
  815. shadowContainer.suspendLayout = scsl;
  816. delete shadowLayout.layoutBusy;
  817. if (shadowContainer.componentLayout) {
  818. delete shadowContainer.componentLayout.layoutBusy;
  819. }
  820. delete me.shadowContainer.layout.layoutBusy;
  821. delete me.layoutBusy;
  822. delete me.owner.componentLayout.layoutBusy;
  823. delete comp.collapsedChangingLayout;
  824. // In case it was floated out and they clicked the re-expand tool
  825. comp.removeCls(Ext.baseCSSPrefix + 'border-region-slide-in');
  826. // Fire the expand event: The Panel has in fact been expanded, but by removal of an alternative Component
  827. comp.fireEvent('expand', comp);
  828. }
  829. // Hide the placeholder
  830. if (hidePlaceholder) {
  831. placeholder.el.hide();
  832. }
  833. // Slide the expanding Component to its new position.
  834. // When that is done, layout the layout.
  835. if (comp.animCollapse &amp;&amp; !isFloating) {
  836. compEl.dom.style.zIndex = 100;
  837. compEl.slideIn(me.slideDirection[comp.region], {
  838. duration: Ext.Number.from(comp.animCollapse, Ext.fx.Anim.prototype.duration),
  839. listeners: {
  840. afteranimate: function() {
  841. compEl.dom.style.zIndex = '';
  842. comp.hidden = false;
  843. shadowLayout.onLayout();
  844. afterExpand();
  845. }
  846. }
  847. });
  848. } else {
  849. shadowLayout.onLayout();
  850. afterExpand();
  851. }
  852. },
  853. floatCollapsedPanel: function(e, comp) {
  854. if (comp.floatable === false) {
  855. return;
  856. }
  857. var me = this,
  858. compEl = comp.el,
  859. placeholder = comp.placeholder,
  860. placeholderEl = placeholder.el,
  861. shadowContainer = comp.shadowOwnerCt,
  862. shadowLayout = shadowContainer.layout,
  863. placeholderBox = shadowLayout.getChildBox(placeholder),
  864. scsl = shadowContainer.suspendLayout,
  865. curSize, toCompBox, compAnim;
  866. // Ignore clicks on tools.
  867. if (e.getTarget('.' + Ext.baseCSSPrefix + 'tool')) {
  868. return;
  869. }
  870. // It's *being* animated, ignore the click.
  871. // Possible future enhancement: Stop and *reverse* the current active Fx.
  872. if (compEl.getActiveAnimation()) {
  873. return;
  874. }
  875. // If the Component is already fully floated when they click the placeholder,
  876. // it will be primed with a slide out animation object... so slide it out.
  877. if (comp.slideOutAnim) {
  878. me.slideOutFloatedComponent(comp);
  879. return;
  880. }
  881. // Function to be called when the mouse leaves the floated Panel
  882. // Slide out when the mouse leaves the region bounded by the slid Component and its placeholder.
  883. function onMouseLeaveFloated(e) {
  884. var slideRegion = compEl.getRegion().union(placeholderEl.getRegion()).adjust(1, -1, -1, 1);
  885. // If mouse is not within slide Region, slide it out
  886. if (!slideRegion.contains(e.getPoint())) {
  887. me.slideOutFloatedComponent(comp);
  888. }
  889. }
  890. // Monitor for mouseouting of the placeholder. Hide it if they exit for half a second or more
  891. comp.placeholderMouseMon = placeholderEl.monitorMouseLeave(500, onMouseLeaveFloated);
  892. // Do not trigger a layout during slide out of the Component
  893. shadowContainer.suspendLayout = true;
  894. // Prevent upward notifications from downstream layouts
  895. me.layoutBusy = true;
  896. me.owner.componentLayout.layoutBusy = true;
  897. // The collapse tool is hidden while slid.
  898. // It is re-shown on expand.
  899. if (comp.collapseTool) {
  900. comp.collapseTool.hide();
  901. }
  902. // Set flags so that the layout will calculate the boxes for what we want
  903. comp.hidden = false;
  904. comp.collapsed = false;
  905. placeholder.hidden = true;
  906. // Recalculate new arrangement of the Component being floated.
  907. toCompBox = shadowLayout.calculateChildBox(comp);
  908. placeholder.hidden = false;
  909. // Component to appear just after the placeholder, whatever &quot;after&quot; means in the context of the shadow Box layout.
  910. if (comp.region == 'north' || comp.region == 'west') {
  911. toCompBox[shadowLayout.parallelBefore] += placeholderBox[shadowLayout.parallelPrefix] - 1;
  912. } else {
  913. toCompBox[shadowLayout.parallelBefore] -= (placeholderBox[shadowLayout.parallelPrefix] - 1);
  914. }
  915. compEl.setStyle('visibility', 'hidden');
  916. compEl.setLeftTop(toCompBox.left, toCompBox.top);
  917. // Equalize the size of the expanding Component prior to animation
  918. // in case the layout area has changed size during the time it was collapsed.
  919. curSize = comp.getSize();
  920. if (curSize.height != toCompBox.height || curSize.width != toCompBox.width) {
  921. me.setItemSize(comp, toCompBox.width, toCompBox.height);
  922. }
  923. // This animation slides the collapsed Component's el out to just beyond its placeholder
  924. compAnim = {
  925. listeners: {
  926. afteranimate: function() {
  927. shadowContainer.suspendLayout = scsl;
  928. delete me.layoutBusy;
  929. delete me.owner.componentLayout.layoutBusy;
  930. // Prime the Component with an Anim config object to slide it back out
  931. compAnim.listeners = {
  932. afterAnimate: function() {
  933. compEl.show().removeCls(Ext.baseCSSPrefix + 'border-region-slide-in').setLeftTop(-10000, -10000);
  934. // Reinstate the correct, current state after slide out animation finishes
  935. comp.hidden = true;
  936. comp.collapsed = true;
  937. delete comp.slideOutAnim;
  938. delete comp.panelMouseMon;
  939. delete comp.placeholderMouseMon;
  940. }
  941. };
  942. comp.slideOutAnim = compAnim;
  943. }
  944. },
  945. duration: 500
  946. };
  947. // Give the element the correct class which places it at a high z-index
  948. compEl.addCls(Ext.baseCSSPrefix + 'border-region-slide-in');
  949. // Begin the slide in
  950. compEl.slideIn(me.slideDirection[comp.region], compAnim);
  951. // Monitor for mouseouting of the slid area. Hide it if they exit for half a second or more
  952. comp.panelMouseMon = compEl.monitorMouseLeave(500, onMouseLeaveFloated);
  953. },
  954. slideOutFloatedComponent: function(comp) {
  955. var compEl = comp.el,
  956. slideOutAnim;
  957. // Remove mouse leave monitors
  958. compEl.un(comp.panelMouseMon);
  959. comp.placeholder.el.un(comp.placeholderMouseMon);
  960. // Slide the Component out
  961. compEl.slideOut(this.slideDirection[comp.region], comp.slideOutAnim);
  962. delete comp.slideOutAnim;
  963. delete comp.panelMouseMon;
  964. delete comp.placeholderMouseMon;
  965. },
  966. /*
  967. * @private
  968. * Ensure any collapsed placeholder Component is destroyed along with its region.
  969. * Can't do this in onDestroy because they may remove a Component and use it elsewhere.
  970. */
  971. onRegionDestroy: function(comp) {
  972. var placeholder = comp.placeholder;
  973. if (placeholder) {
  974. delete placeholder.ownerCt;
  975. placeholder.destroy();
  976. }
  977. },
  978. /*
  979. * @private
  980. * Ensure any shadow Containers are destroyed.
  981. * Ensure we don't keep references to Components.
  982. */
  983. onDestroy: function() {
  984. var me = this,
  985. shadowContainer = me.shadowContainer,
  986. embeddedContainer = me.embeddedContainer;
  987. if (shadowContainer) {
  988. delete shadowContainer.ownerCt;
  989. Ext.destroy(shadowContainer);
  990. }
  991. if (embeddedContainer) {
  992. delete embeddedContainer.ownerCt;
  993. Ext.destroy(embeddedContainer);
  994. }
  995. delete me.regions;
  996. delete me.splitters;
  997. delete me.shadowContainer;
  998. delete me.embeddedContainer;
  999. me.callParent(arguments);
  1000. }
  1001. });
  1002. </pre>
  1003. </body>
  1004. </html>