Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

13564 lines
501 KiB

  1. /*!
  2. * Ext JS Library 3.2.0
  3. * Copyright(c) 2006-2010 Ext JS, Inc.
  4. * licensing@extjs.com
  5. * http://www.extjs.com/license
  6. */
  7. /**
  8. * @class Ext.ComponentMgr
  9. * <p>Provides a registry of all Components (instances of {@link Ext.Component} or any subclass
  10. * thereof) on a page so that they can be easily accessed by {@link Ext.Component component}
  11. * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).</p>
  12. * <p>This object also provides a registry of available Component <i>classes</i>
  13. * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}.
  14. * The <code>{@link Ext.Component#xtype xtype}</code> provides a way to avoid instantiating child Components
  15. * when creating a full, nested config object for a complete Ext page.</p>
  16. * <p>A child Component may be specified simply as a <i>config object</i>
  17. * as long as the correct <code>{@link Ext.Component#xtype xtype}</code> is specified so that if and when the Component
  18. * needs rendering, the correct type can be looked up for lazy instantiation.</p>
  19. * <p>For a list of all available <code>{@link Ext.Component#xtype xtypes}</code>, see {@link Ext.Component}.</p>
  20. * @singleton
  21. */
  22. Ext.ComponentMgr = function(){
  23. var all = new Ext.util.MixedCollection();
  24. var types = {};
  25. var ptypes = {};
  26. return {
  27. /**
  28. * Registers a component.
  29. * @param {Ext.Component} c The component
  30. */
  31. register : function(c){
  32. all.add(c);
  33. },
  34. /**
  35. * Unregisters a component.
  36. * @param {Ext.Component} c The component
  37. */
  38. unregister : function(c){
  39. all.remove(c);
  40. },
  41. /**
  42. * Returns a component by {@link Ext.Component#id id}.
  43. * For additional details see {@link Ext.util.MixedCollection#get}.
  44. * @param {String} id The component {@link Ext.Component#id id}
  45. * @return Ext.Component The Component, <code>undefined</code> if not found, or <code>null</code> if a
  46. * Class was found.
  47. */
  48. get : function(id){
  49. return all.get(id);
  50. },
  51. /**
  52. * Registers a function that will be called when a Component with the specified id is added to ComponentMgr. This will happen on instantiation.
  53. * @param {String} id The component {@link Ext.Component#id id}
  54. * @param {Function} fn The callback function
  55. * @param {Object} scope The scope (<code>this</code> reference) in which the callback is executed. Defaults to the Component.
  56. */
  57. onAvailable : function(id, fn, scope){
  58. all.on("add", function(index, o){
  59. if(o.id == id){
  60. fn.call(scope || o, o);
  61. all.un("add", fn, scope);
  62. }
  63. });
  64. },
  65. /**
  66. * The MixedCollection used internally for the component cache. An example usage may be subscribing to
  67. * events on the MixedCollection to monitor addition or removal. Read-only.
  68. * @type {MixedCollection}
  69. */
  70. all : all,
  71. /**
  72. * The xtypes that have been registered with the component manager.
  73. * @type {Object}
  74. */
  75. types : types,
  76. /**
  77. * The ptypes that have been registered with the component manager.
  78. * @type {Object}
  79. */
  80. ptypes: ptypes,
  81. /**
  82. * Checks if a Component type is registered.
  83. * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up
  84. * @return {Boolean} Whether the type is registered.
  85. */
  86. isRegistered : function(xtype){
  87. return types[xtype] !== undefined;
  88. },
  89. /**
  90. * Checks if a Plugin type is registered.
  91. * @param {Ext.Component} ptype The mnemonic string by which the Plugin class may be looked up
  92. * @return {Boolean} Whether the type is registered.
  93. */
  94. isPluginRegistered : function(ptype){
  95. return ptypes[ptype] !== undefined;
  96. },
  97. /**
  98. * <p>Registers a new Component constructor, keyed by a new
  99. * {@link Ext.Component#xtype}.</p>
  100. * <p>Use this method (or its alias {@link Ext#reg Ext.reg}) to register new
  101. * subclasses of {@link Ext.Component} so that lazy instantiation may be used when specifying
  102. * child Components.
  103. * see {@link Ext.Container#items}</p>
  104. * @param {String} xtype The mnemonic string by which the Component class may be looked up.
  105. * @param {Constructor} cls The new Component class.
  106. */
  107. registerType : function(xtype, cls){
  108. types[xtype] = cls;
  109. cls.xtype = xtype;
  110. },
  111. /**
  112. * Creates a new Component from the specified config object using the
  113. * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
  114. * @param {Object} config A configuration object for the Component you wish to create.
  115. * @param {Constructor} defaultType The constructor to provide the default Component type if
  116. * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
  117. * @return {Ext.Component} The newly instantiated Component.
  118. */
  119. create : function(config, defaultType){
  120. return config.render ? config : new types[config.xtype || defaultType](config);
  121. },
  122. /**
  123. * <p>Registers a new Plugin constructor, keyed by a new
  124. * {@link Ext.Component#ptype}.</p>
  125. * <p>Use this method (or its alias {@link Ext#preg Ext.preg}) to register new
  126. * plugins for {@link Ext.Component}s so that lazy instantiation may be used when specifying
  127. * Plugins.</p>
  128. * @param {String} ptype The mnemonic string by which the Plugin class may be looked up.
  129. * @param {Constructor} cls The new Plugin class.
  130. */
  131. registerPlugin : function(ptype, cls){
  132. ptypes[ptype] = cls;
  133. cls.ptype = ptype;
  134. },
  135. /**
  136. * Creates a new Plugin from the specified config object using the
  137. * config object's {@link Ext.component#ptype ptype} to determine the class to instantiate.
  138. * @param {Object} config A configuration object for the Plugin you wish to create.
  139. * @param {Constructor} defaultType The constructor to provide the default Plugin type if
  140. * the config object does not contain a <code>ptype</code>. (Optional if the config contains a <code>ptype</code>).
  141. * @return {Ext.Component} The newly instantiated Plugin.
  142. */
  143. createPlugin : function(config, defaultType){
  144. var PluginCls = ptypes[config.ptype || defaultType];
  145. if (PluginCls.init) {
  146. return PluginCls;
  147. } else {
  148. return new PluginCls(config);
  149. }
  150. }
  151. };
  152. }();
  153. /**
  154. * Shorthand for {@link Ext.ComponentMgr#registerType}
  155. * @param {String} xtype The {@link Ext.component#xtype mnemonic string} by which the Component class
  156. * may be looked up.
  157. * @param {Constructor} cls The new Component class.
  158. * @member Ext
  159. * @method reg
  160. */
  161. Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally, shorthand to keep the bytes down
  162. /**
  163. * Shorthand for {@link Ext.ComponentMgr#registerPlugin}
  164. * @param {String} ptype The {@link Ext.component#ptype mnemonic string} by which the Plugin class
  165. * may be looked up.
  166. * @param {Constructor} cls The new Plugin class.
  167. * @member Ext
  168. * @method preg
  169. */
  170. Ext.preg = Ext.ComponentMgr.registerPlugin;
  171. /**
  172. * Shorthand for {@link Ext.ComponentMgr#create}
  173. * Creates a new Component from the specified config object using the
  174. * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
  175. * @param {Object} config A configuration object for the Component you wish to create.
  176. * @param {Constructor} defaultType The constructor to provide the default Component type if
  177. * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
  178. * @return {Ext.Component} The newly instantiated Component.
  179. * @member Ext
  180. * @method create
  181. */
  182. Ext.create = Ext.ComponentMgr.create;/**
  183. * @class Ext.Component
  184. * @extends Ext.util.Observable
  185. * <p>Base class for all Ext components. All subclasses of Component may participate in the automated
  186. * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.Container Container} class.
  187. * Components may be added to a Container through the {@link Ext.Container#items items} config option at the time the Container is created,
  188. * or they may be added dynamically via the {@link Ext.Container#add add} method.</p>
  189. * <p>The Component base class has built-in support for basic hide/show and enable/disable behavior.</p>
  190. * <p>All Components are registered with the {@link Ext.ComponentMgr} on construction so that they can be referenced at any time via
  191. * {@link Ext#getCmp}, passing the {@link #id}.</p>
  192. * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component (or
  193. * {@link Ext.BoxComponent} if managed box model handling is required, ie height and width management).</p>
  194. * <p>See the <a href="http://extjs.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how
  195. * and to either extend or augment ExtJs base classes to create custom Components.</p>
  196. * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
  197. * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
  198. * <pre>
  199. xtype Class
  200. ------------- ------------------
  201. box {@link Ext.BoxComponent}
  202. button {@link Ext.Button}
  203. buttongroup {@link Ext.ButtonGroup}
  204. colorpalette {@link Ext.ColorPalette}
  205. component {@link Ext.Component}
  206. container {@link Ext.Container}
  207. cycle {@link Ext.CycleButton}
  208. dataview {@link Ext.DataView}
  209. datepicker {@link Ext.DatePicker}
  210. editor {@link Ext.Editor}
  211. editorgrid {@link Ext.grid.EditorGridPanel}
  212. flash {@link Ext.FlashComponent}
  213. grid {@link Ext.grid.GridPanel}
  214. listview {@link Ext.ListView}
  215. panel {@link Ext.Panel}
  216. progress {@link Ext.ProgressBar}
  217. propertygrid {@link Ext.grid.PropertyGrid}
  218. slider {@link Ext.Slider}
  219. spacer {@link Ext.Spacer}
  220. splitbutton {@link Ext.SplitButton}
  221. tabpanel {@link Ext.TabPanel}
  222. treepanel {@link Ext.tree.TreePanel}
  223. viewport {@link Ext.ViewPort}
  224. window {@link Ext.Window}
  225. Toolbar components
  226. ---------------------------------------
  227. paging {@link Ext.PagingToolbar}
  228. toolbar {@link Ext.Toolbar}
  229. tbbutton {@link Ext.Toolbar.Button} (deprecated; use button)
  230. tbfill {@link Ext.Toolbar.Fill}
  231. tbitem {@link Ext.Toolbar.Item}
  232. tbseparator {@link Ext.Toolbar.Separator}
  233. tbspacer {@link Ext.Toolbar.Spacer}
  234. tbsplit {@link Ext.Toolbar.SplitButton} (deprecated; use splitbutton)
  235. tbtext {@link Ext.Toolbar.TextItem}
  236. Menu components
  237. ---------------------------------------
  238. menu {@link Ext.menu.Menu}
  239. colormenu {@link Ext.menu.ColorMenu}
  240. datemenu {@link Ext.menu.DateMenu}
  241. menubaseitem {@link Ext.menu.BaseItem}
  242. menucheckitem {@link Ext.menu.CheckItem}
  243. menuitem {@link Ext.menu.Item}
  244. menuseparator {@link Ext.menu.Separator}
  245. menutextitem {@link Ext.menu.TextItem}
  246. Form components
  247. ---------------------------------------
  248. form {@link Ext.form.FormPanel}
  249. checkbox {@link Ext.form.Checkbox}
  250. checkboxgroup {@link Ext.form.CheckboxGroup}
  251. combo {@link Ext.form.ComboBox}
  252. datefield {@link Ext.form.DateField}
  253. displayfield {@link Ext.form.DisplayField}
  254. field {@link Ext.form.Field}
  255. fieldset {@link Ext.form.FieldSet}
  256. hidden {@link Ext.form.Hidden}
  257. htmleditor {@link Ext.form.HtmlEditor}
  258. label {@link Ext.form.Label}
  259. numberfield {@link Ext.form.NumberField}
  260. radio {@link Ext.form.Radio}
  261. radiogroup {@link Ext.form.RadioGroup}
  262. textarea {@link Ext.form.TextArea}
  263. textfield {@link Ext.form.TextField}
  264. timefield {@link Ext.form.TimeField}
  265. trigger {@link Ext.form.TriggerField}
  266. Chart components
  267. ---------------------------------------
  268. chart {@link Ext.chart.Chart}
  269. barchart {@link Ext.chart.BarChart}
  270. cartesianchart {@link Ext.chart.CartesianChart}
  271. columnchart {@link Ext.chart.ColumnChart}
  272. linechart {@link Ext.chart.LineChart}
  273. piechart {@link Ext.chart.PieChart}
  274. Store xtypes
  275. ---------------------------------------
  276. arraystore {@link Ext.data.ArrayStore}
  277. directstore {@link Ext.data.DirectStore}
  278. groupingstore {@link Ext.data.GroupingStore}
  279. jsonstore {@link Ext.data.JsonStore}
  280. simplestore {@link Ext.data.SimpleStore} (deprecated; use arraystore)
  281. store {@link Ext.data.Store}
  282. xmlstore {@link Ext.data.XmlStore}
  283. </pre>
  284. * @constructor
  285. * @param {Ext.Element/String/Object} config The configuration options may be specified as either:
  286. * <div class="mdetail-params"><ul>
  287. * <li><b>an element</b> :
  288. * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li>
  289. * <li><b>a string</b> :
  290. * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li>
  291. * <li><b>anything else</b> :
  292. * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li>
  293. * </ul></div>
  294. */
  295. Ext.Component = function(config){
  296. config = config || {};
  297. if(config.initialConfig){
  298. if(config.isAction){ // actions
  299. this.baseAction = config;
  300. }
  301. config = config.initialConfig; // component cloning / action set up
  302. }else if(config.tagName || config.dom || Ext.isString(config)){ // element object
  303. config = {applyTo: config, id: config.id || config};
  304. }
  305. /**
  306. * This Component's initial configuration specification. Read-only.
  307. * @type Object
  308. * @property initialConfig
  309. */
  310. this.initialConfig = config;
  311. Ext.apply(this, config);
  312. this.addEvents(
  313. /**
  314. * @event added
  315. * Fires when a component is added to an Ext.Container
  316. * @param {Ext.Component} this
  317. * @param {Ext.Container} ownerCt Container which holds the component
  318. * @param {number} index Position at which the component was added
  319. */
  320. 'added',
  321. /**
  322. * @event disable
  323. * Fires after the component is disabled.
  324. * @param {Ext.Component} this
  325. */
  326. 'disable',
  327. /**
  328. * @event enable
  329. * Fires after the component is enabled.
  330. * @param {Ext.Component} this
  331. */
  332. 'enable',
  333. /**
  334. * @event beforeshow
  335. * Fires before the component is shown by calling the {@link #show} method.
  336. * Return false from an event handler to stop the show.
  337. * @param {Ext.Component} this
  338. */
  339. 'beforeshow',
  340. /**
  341. * @event show
  342. * Fires after the component is shown when calling the {@link #show} method.
  343. * @param {Ext.Component} this
  344. */
  345. 'show',
  346. /**
  347. * @event beforehide
  348. * Fires before the component is hidden by calling the {@link #hide} method.
  349. * Return false from an event handler to stop the hide.
  350. * @param {Ext.Component} this
  351. */
  352. 'beforehide',
  353. /**
  354. * @event hide
  355. * Fires after the component is hidden.
  356. * Fires after the component is hidden when calling the {@link #hide} method.
  357. * @param {Ext.Component} this
  358. */
  359. 'hide',
  360. /**
  361. * @event removed
  362. * Fires when a component is removed from an Ext.Container
  363. * @param {Ext.Component} this
  364. * @param {Ext.Container} ownerCt Container which holds the component
  365. */
  366. 'removed',
  367. /**
  368. * @event beforerender
  369. * Fires before the component is {@link #rendered}. Return false from an
  370. * event handler to stop the {@link #render}.
  371. * @param {Ext.Component} this
  372. */
  373. 'beforerender',
  374. /**
  375. * @event render
  376. * Fires after the component markup is {@link #rendered}.
  377. * @param {Ext.Component} this
  378. */
  379. 'render',
  380. /**
  381. * @event afterrender
  382. * <p>Fires after the component rendering is finished.</p>
  383. * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed
  384. * by any afterRender method defined for the Component, and, if {@link #stateful}, after state
  385. * has been restored.</p>
  386. * @param {Ext.Component} this
  387. */
  388. 'afterrender',
  389. /**
  390. * @event beforedestroy
  391. * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}.
  392. * @param {Ext.Component} this
  393. */
  394. 'beforedestroy',
  395. /**
  396. * @event destroy
  397. * Fires after the component is {@link #destroy}ed.
  398. * @param {Ext.Component} this
  399. */
  400. 'destroy',
  401. /**
  402. * @event beforestaterestore
  403. * Fires before the state of the component is restored. Return false from an event handler to stop the restore.
  404. * @param {Ext.Component} this
  405. * @param {Object} state The hash of state values returned from the StateProvider. If this
  406. * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
  407. * that simply copies property values into this Component. The method maybe overriden to
  408. * provide custom state restoration.
  409. */
  410. 'beforestaterestore',
  411. /**
  412. * @event staterestore
  413. * Fires after the state of the component is restored.
  414. * @param {Ext.Component} this
  415. * @param {Object} state The hash of state values returned from the StateProvider. This is passed
  416. * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
  417. * Component. The method maybe overriden to provide custom state restoration.
  418. */
  419. 'staterestore',
  420. /**
  421. * @event beforestatesave
  422. * Fires before the state of the component is saved to the configured state provider. Return false to stop the save.
  423. * @param {Ext.Component} this
  424. * @param {Object} state The hash of state values. This is determined by calling
  425. * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
  426. * developer to return whetever representation of state is required, by default, Ext.Component
  427. * has a null implementation.
  428. */
  429. 'beforestatesave',
  430. /**
  431. * @event statesave
  432. * Fires after the state of the component is saved to the configured state provider.
  433. * @param {Ext.Component} this
  434. * @param {Object} state The hash of state values. This is determined by calling
  435. * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
  436. * developer to return whetever representation of state is required, by default, Ext.Component
  437. * has a null implementation.
  438. */
  439. 'statesave'
  440. );
  441. this.getId();
  442. Ext.ComponentMgr.register(this);
  443. Ext.Component.superclass.constructor.call(this);
  444. if(this.baseAction){
  445. this.baseAction.addComponent(this);
  446. }
  447. this.initComponent();
  448. if(this.plugins){
  449. if(Ext.isArray(this.plugins)){
  450. for(var i = 0, len = this.plugins.length; i < len; i++){
  451. this.plugins[i] = this.initPlugin(this.plugins[i]);
  452. }
  453. }else{
  454. this.plugins = this.initPlugin(this.plugins);
  455. }
  456. }
  457. if(this.stateful !== false){
  458. this.initState();
  459. }
  460. if(this.applyTo){
  461. this.applyToMarkup(this.applyTo);
  462. delete this.applyTo;
  463. }else if(this.renderTo){
  464. this.render(this.renderTo);
  465. delete this.renderTo;
  466. }
  467. };
  468. // private
  469. Ext.Component.AUTO_ID = 1000;
  470. Ext.extend(Ext.Component, Ext.util.Observable, {
  471. // Configs below are used for all Components when rendered by FormLayout.
  472. /**
  473. * @cfg {String} fieldLabel <p>The label text to display next to this Component (defaults to '').</p>
  474. * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container which
  475. * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
  476. * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
  477. * <p>Also see <tt>{@link #hideLabel}</tt> and
  478. * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
  479. * Example use:<pre><code>
  480. new Ext.FormPanel({
  481. height: 100,
  482. renderTo: Ext.getBody(),
  483. items: [{
  484. xtype: 'textfield',
  485. fieldLabel: 'Name'
  486. }]
  487. });
  488. </code></pre>
  489. */
  490. /**
  491. * @cfg {String} labelStyle <p>A CSS style specification string to apply directly to this field's
  492. * label. Defaults to the container's labelStyle value if set (e.g.,
  493. * <tt>{@link Ext.layout.FormLayout#labelStyle}</tt> , or '').</p>
  494. * <br><p><b>Note</b>: see the note for <code>{@link #clearCls}</code>.</p><br>
  495. * <p>Also see <code>{@link #hideLabel}</code> and
  496. * <code>{@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</code></p>
  497. * Example use:<pre><code>
  498. new Ext.FormPanel({
  499. height: 100,
  500. renderTo: Ext.getBody(),
  501. items: [{
  502. xtype: 'textfield',
  503. fieldLabel: 'Name',
  504. labelStyle: 'font-weight:bold;'
  505. }]
  506. });
  507. </code></pre>
  508. */
  509. /**
  510. * @cfg {String} labelSeparator <p>The separator to display after the text of each
  511. * <tt>{@link #fieldLabel}</tt>. This property may be configured at various levels.
  512. * The order of precedence is:
  513. * <div class="mdetail-params"><ul>
  514. * <li>field / component level</li>
  515. * <li>container level</li>
  516. * <li>{@link Ext.layout.FormLayout#labelSeparator layout level} (defaults to colon <tt>':'</tt>)</li>
  517. * </ul></div>
  518. * To display no separator for this field's label specify empty string ''.</p>
  519. * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
  520. * <p>Also see <tt>{@link #hideLabel}</tt> and
  521. * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
  522. * Example use:<pre><code>
  523. new Ext.FormPanel({
  524. height: 100,
  525. renderTo: Ext.getBody(),
  526. layoutConfig: {
  527. labelSeparator: '~' // layout config has lowest priority (defaults to ':')
  528. },
  529. {@link Ext.layout.FormLayout#labelSeparator labelSeparator}: '>>', // config at container level
  530. items: [{
  531. xtype: 'textfield',
  532. fieldLabel: 'Field 1',
  533. labelSeparator: '...' // field/component level config supersedes others
  534. },{
  535. xtype: 'textfield',
  536. fieldLabel: 'Field 2' // labelSeparator will be '='
  537. }]
  538. });
  539. </code></pre>
  540. */
  541. /**
  542. * @cfg {Boolean} hideLabel <p><tt>true</tt> to completely hide the label element
  543. * ({@link #fieldLabel label} and {@link #labelSeparator separator}). Defaults to <tt>false</tt>.
  544. * By default, even if you do not specify a <tt>{@link #fieldLabel}</tt> the space will still be
  545. * reserved so that the field will line up with other fields that do have labels.
  546. * Setting this to <tt>true</tt> will cause the field to not reserve that space.</p>
  547. * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
  548. * Example use:<pre><code>
  549. new Ext.FormPanel({
  550. height: 100,
  551. renderTo: Ext.getBody(),
  552. items: [{
  553. xtype: 'textfield'
  554. hideLabel: true
  555. }]
  556. });
  557. </code></pre>
  558. */
  559. /**
  560. * @cfg {String} clearCls <p>The CSS class used to to apply to the special clearing div rendered
  561. * directly after each form field wrapper to provide field clearing (defaults to
  562. * <tt>'x-form-clear-left'</tt>).</p>
  563. * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container
  564. * which has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout
  565. * manager (e.g. {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) and either a
  566. * <tt>{@link #fieldLabel}</tt> is specified or <tt>isFormField=true</tt> is specified.</p><br>
  567. * <p>See {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} also.</p>
  568. */
  569. /**
  570. * @cfg {String} itemCls
  571. * <p><b>Note</b>: this config is only used when this Component is rendered by a Container which
  572. * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
  573. * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
  574. * <p>An additional CSS class to apply to the div wrapping the form item
  575. * element of this field. If supplied, <tt>itemCls</tt> at the <b>field</b> level will override
  576. * the default <tt>itemCls</tt> supplied at the <b>container</b> level. The value specified for
  577. * <tt>itemCls</tt> will be added to the default class (<tt>'x-form-item'</tt>).</p>
  578. * <p>Since it is applied to the item wrapper (see
  579. * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}), it allows
  580. * you to write standard CSS rules that can apply to the field, the label (if specified), or
  581. * any other element within the markup for the field.</p>
  582. * <br><p><b>Note</b>: see the note for <tt>{@link #fieldLabel}</tt>.</p><br>
  583. * Example use:<pre><code>
  584. // Apply a style to the field&#39;s label:
  585. &lt;style>
  586. .required .x-form-item-label {font-weight:bold;color:red;}
  587. &lt;/style>
  588. new Ext.FormPanel({
  589. height: 100,
  590. renderTo: Ext.getBody(),
  591. items: [{
  592. xtype: 'textfield',
  593. fieldLabel: 'Name',
  594. itemCls: 'required' //this label will be styled
  595. },{
  596. xtype: 'textfield',
  597. fieldLabel: 'Favorite Color'
  598. }]
  599. });
  600. </code></pre>
  601. */
  602. /**
  603. * @cfg {String} id
  604. * <p>The <b>unique</b> id of this component (defaults to an {@link #getId auto-assigned id}).
  605. * You should assign an id if you need to be able to access the component later and you do
  606. * not have an object reference available (e.g., using {@link Ext}.{@link Ext#getCmp getCmp}).</p>
  607. * <p>Note that this id will also be used as the element id for the containing HTML element
  608. * that is rendered to the page for this component. This allows you to write id-based CSS
  609. * rules to style the specific instance of this component uniquely, and also to select
  610. * sub-elements using this component's id as the parent.</p>
  611. * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see
  612. * <code>{@link #itemId}</code> and <code>{@link #ref}</code>.</p>
  613. * <p><b>Note</b>: to access the container of an item see <code>{@link #ownerCt}</code>.</p>
  614. */
  615. /**
  616. * @cfg {String} itemId
  617. * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component
  618. * when no object reference is available. Instead of using an <code>{@link #id}</code> with
  619. * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with
  620. * {@link Ext.Container}.{@link Ext.Container#getComponent getComponent} which will retrieve
  621. * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the
  622. * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container --
  623. * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a <b>unique</b>
  624. * <code>{@link #id}</code>.</p>
  625. * <pre><code>
  626. var c = new Ext.Panel({ //
  627. {@link Ext.BoxComponent#height height}: 300,
  628. {@link #renderTo}: document.body,
  629. {@link Ext.Container#layout layout}: 'auto',
  630. {@link Ext.Container#items items}: [
  631. {
  632. itemId: 'p1',
  633. {@link Ext.Panel#title title}: 'Panel 1',
  634. {@link Ext.BoxComponent#height height}: 150
  635. },
  636. {
  637. itemId: 'p2',
  638. {@link Ext.Panel#title title}: 'Panel 2',
  639. {@link Ext.BoxComponent#height height}: 150
  640. }
  641. ]
  642. })
  643. p1 = c.{@link Ext.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
  644. p2 = p1.{@link #ownerCt}.{@link Ext.Container#getComponent getComponent}('p2'); // reference via a sibling
  645. * </code></pre>
  646. * <p>Also see <tt>{@link #id}</tt> and <code>{@link #ref}</code>.</p>
  647. * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p>
  648. */
  649. /**
  650. * @cfg {String} xtype
  651. * The registered <tt>xtype</tt> to create. This config option is not used when passing
  652. * a config object into a constructor. This config option is used only when
  653. * lazy instantiation is being used, and a child item of a Container is being
  654. * specified not as a fully instantiated Component, but as a <i>Component config
  655. * object</i>. The <tt>xtype</tt> will be looked up at render time up to determine what
  656. * type of child Component to create.<br><br>
  657. * The predefined xtypes are listed {@link Ext.Component here}.
  658. * <br><br>
  659. * If you subclass Components to create your own Components, you may register
  660. * them using {@link Ext.ComponentMgr#registerType} in order to be able to
  661. * take advantage of lazy instantiation and rendering.
  662. */
  663. /**
  664. * @cfg {String} ptype
  665. * The registered <tt>ptype</tt> to create. This config option is not used when passing
  666. * a config object into a constructor. This config option is used only when
  667. * lazy instantiation is being used, and a Plugin is being
  668. * specified not as a fully instantiated Component, but as a <i>Component config
  669. * object</i>. The <tt>ptype</tt> will be looked up at render time up to determine what
  670. * type of Plugin to create.<br><br>
  671. * If you create your own Plugins, you may register them using
  672. * {@link Ext.ComponentMgr#registerPlugin} in order to be able to
  673. * take advantage of lazy instantiation and rendering.
  674. */
  675. /**
  676. * @cfg {String} cls
  677. * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be
  678. * useful for adding customized styles to the component or any of its children using standard CSS rules.
  679. */
  680. /**
  681. * @cfg {String} overCls
  682. * An optional extra CSS class that will be added to this component's Element when the mouse moves
  683. * over the Element, and removed when the mouse moves out. (defaults to ''). This can be
  684. * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules.
  685. */
  686. /**
  687. * @cfg {String} style
  688. * A custom style specification to be applied to this component's Element. Should be a valid argument to
  689. * {@link Ext.Element#applyStyles}.
  690. * <pre><code>
  691. new Ext.Panel({
  692. title: 'Some Title',
  693. renderTo: Ext.getBody(),
  694. width: 400, height: 300,
  695. layout: 'form',
  696. items: [{
  697. xtype: 'textarea',
  698. style: {
  699. width: '95%',
  700. marginBottom: '10px'
  701. }
  702. },
  703. new Ext.Button({
  704. text: 'Send',
  705. minWidth: '100',
  706. style: {
  707. marginBottom: '10px'
  708. }
  709. })
  710. ]
  711. });
  712. * </code></pre>
  713. */
  714. /**
  715. * @cfg {String} ctCls
  716. * <p>An optional extra CSS class that will be added to this component's container. This can be useful for
  717. * adding customized styles to the container or any of its children using standard CSS rules. See
  718. * {@link Ext.layout.ContainerLayout}.{@link Ext.layout.ContainerLayout#extraCls extraCls} also.</p>
  719. * <p><b>Note</b>: <tt>ctCls</tt> defaults to <tt>''</tt> except for the following class
  720. * which assigns a value by default:
  721. * <div class="mdetail-params"><ul>
  722. * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-layout-ct'</tt></li>
  723. * </ul></div>
  724. * To configure the above Class with an extra CSS class append to the default. For example,
  725. * for BoxLayout (Hbox and Vbox):<pre><code>
  726. * ctCls: 'x-box-layout-ct custom-class'
  727. * </code></pre>
  728. * </p>
  729. */
  730. /**
  731. * @cfg {Boolean} disabled
  732. * Render this component disabled (default is false).
  733. */
  734. disabled : false,
  735. /**
  736. * @cfg {Boolean} hidden
  737. * Render this component hidden (default is false). If <tt>true</tt>, the
  738. * {@link #hide} method will be called internally.
  739. */
  740. hidden : false,
  741. /**
  742. * @cfg {Object/Array} plugins
  743. * An object or array of objects that will provide custom functionality for this component. The only
  744. * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component.
  745. * When a component is created, if any plugins are available, the component will call the init method on each
  746. * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the
  747. * component as needed to provide its functionality.
  748. */
  749. /**
  750. * @cfg {Mixed} applyTo
  751. * <p>Specify the id of the element, a DOM element or an existing Element corresponding to a DIV
  752. * that is already present in the document that specifies some structural markup for this
  753. * component.</p><div><ul>
  754. * <li><b>Description</b> : <ul>
  755. * <div class="sub-desc">When <tt>applyTo</tt> is used, constituent parts of the component can also be specified
  756. * by id or CSS class name within the main element, and the component being created may attempt
  757. * to create its subcomponents from that markup if applicable.</div>
  758. * </ul></li>
  759. * <li><b>Notes</b> : <ul>
  760. * <div class="sub-desc">When using this config, a call to render() is not required.</div>
  761. * <div class="sub-desc">If applyTo is specified, any value passed for {@link #renderTo} will be ignored and the target
  762. * element's parent node will automatically be used as the component's container.</div>
  763. * </ul></li>
  764. * </ul></div>
  765. */
  766. /**
  767. * @cfg {Mixed} renderTo
  768. * <p>Specify the id of the element, a DOM element or an existing Element that this component
  769. * will be rendered into.</p><div><ul>
  770. * <li><b>Notes</b> : <ul>
  771. * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of
  772. * a {@link Ext.Container Container}. It is the responsibility of the
  773. * {@link Ext.Container Container}'s {@link Ext.Container#layout layout manager}
  774. * to render and manage its child items.</div>
  775. * <div class="sub-desc">When using this config, a call to render() is not required.</div>
  776. * </ul></li>
  777. * </ul></div>
  778. * <p>See <tt>{@link #render}</tt> also.</p>
  779. */
  780. /**
  781. * @cfg {Boolean} stateful
  782. * <p>A flag which causes the Component to attempt to restore the state of
  783. * internal properties from a saved state on startup. The component must have
  784. * either a <code>{@link #stateId}</code> or <code>{@link #id}</code> assigned
  785. * for state to be managed. Auto-generated ids are not guaranteed to be stable
  786. * across page loads and cannot be relied upon to save and restore the same
  787. * state for a component.<p>
  788. * <p>For state saving to work, the state manager's provider must have been
  789. * set to an implementation of {@link Ext.state.Provider} which overrides the
  790. * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
  791. * methods to save and recall name/value pairs. A built-in implementation,
  792. * {@link Ext.state.CookieProvider} is available.</p>
  793. * <p>To set the state provider for the current page:</p>
  794. * <pre><code>
  795. Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
  796. expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
  797. }));
  798. * </code></pre>
  799. * <p>A stateful Component attempts to save state when one of the events
  800. * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
  801. * <p>To save state, a stateful Component first serializes its state by
  802. * calling <b><code>getState</code></b>. By default, this function does
  803. * nothing. The developer must provide an implementation which returns an
  804. * object hash which represents the Component's restorable state.</p>
  805. * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
  806. * which uses the configured {@link Ext.state.Provider} to save the object
  807. * keyed by the Component's <code>{@link stateId}</code>, or, if that is not
  808. * specified, its <code>{@link #id}</code>.</p>
  809. * <p>During construction, a stateful Component attempts to <i>restore</i>
  810. * its state by calling {@link Ext.state.Manager#get} passing the
  811. * <code>{@link #stateId}</code>, or, if that is not specified, the
  812. * <code>{@link #id}</code>.</p>
  813. * <p>The resulting object is passed to <b><code>applyState</code></b>.
  814. * The default implementation of <code>applyState</code> simply copies
  815. * properties into the object, but a developer may override this to support
  816. * more behaviour.</p>
  817. * <p>You can perform extra processing on state save and restore by attaching
  818. * handlers to the {@link #beforestaterestore}, {@link #staterestore},
  819. * {@link #beforestatesave} and {@link #statesave} events.</p>
  820. */
  821. /**
  822. * @cfg {String} stateId
  823. * The unique id for this component to use for state management purposes
  824. * (defaults to the component id if one was set, otherwise null if the
  825. * component is using a generated id).
  826. * <p>See <code>{@link #stateful}</code> for an explanation of saving and
  827. * restoring Component state.</p>
  828. */
  829. /**
  830. * @cfg {Array} stateEvents
  831. * <p>An array of events that, when fired, should trigger this component to
  832. * save its state (defaults to none). <code>stateEvents</code> may be any type
  833. * of event supported by this component, including browser or custom events
  834. * (e.g., <tt>['click', 'customerchange']</tt>).</p>
  835. * <p>See <code>{@link #stateful}</code> for an explanation of saving and
  836. * restoring Component state.</p>
  837. */
  838. /**
  839. * @cfg {Mixed} autoEl
  840. * <p>A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
  841. * encapsulate this Component.</p>
  842. * <p>You do not normally need to specify this. For the base classes {@link Ext.Component}, {@link Ext.BoxComponent},
  843. * and {@link Ext.Container}, this defaults to <b><tt>'div'</tt></b>. The more complex Ext classes use a more complex
  844. * DOM structure created by their own onRender methods.</p>
  845. * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by
  846. * different DOM elements. Example usage:</p><pre><code>
  847. {
  848. xtype: 'box',
  849. autoEl: {
  850. tag: 'img',
  851. src: 'http://www.example.com/example.jpg'
  852. }
  853. }, {
  854. xtype: 'box',
  855. autoEl: {
  856. tag: 'blockquote',
  857. html: 'autoEl is cool!'
  858. }
  859. }, {
  860. xtype: 'container',
  861. autoEl: 'ul',
  862. cls: 'ux-unordered-list',
  863. items: {
  864. xtype: 'box',
  865. autoEl: 'li',
  866. html: 'First list item'
  867. }
  868. }
  869. </code></pre>
  870. */
  871. autoEl : 'div',
  872. /**
  873. * @cfg {String} disabledClass
  874. * CSS class added to the component when it is disabled (defaults to 'x-item-disabled').
  875. */
  876. disabledClass : 'x-item-disabled',
  877. /**
  878. * @cfg {Boolean} allowDomMove
  879. * Whether the component can move the Dom node when rendering (defaults to true).
  880. */
  881. allowDomMove : true,
  882. /**
  883. * @cfg {Boolean} autoShow
  884. * True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove
  885. * them on render (defaults to false).
  886. */
  887. autoShow : false,
  888. /**
  889. * @cfg {String} hideMode
  890. * <p>How this component should be hidden. Supported values are <tt>'visibility'</tt>
  891. * (css visibility), <tt>'offsets'</tt> (negative offset position) and <tt>'display'</tt>
  892. * (css display).</p>
  893. * <br><p><b>Note</b>: the default of <tt>'display'</tt> is generally preferred
  894. * since items are automatically laid out when they are first shown (no sizing
  895. * is done while hidden).</p>
  896. */
  897. hideMode : 'display',
  898. /**
  899. * @cfg {Boolean} hideParent
  900. * True to hide and show the component's container when hide/show is called on the component, false to hide
  901. * and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide
  902. * button on a window by setting hide:true on the button when adding it to its parent container.
  903. */
  904. hideParent : false,
  905. /**
  906. * <p>The {@link Ext.Element} which encapsulates this Component. Read-only.</p>
  907. * <p>This will <i>usually</i> be a &lt;DIV> element created by the class's onRender method, but
  908. * that may be overridden using the <code>{@link #autoEl}</code> config.</p>
  909. * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
  910. * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
  911. * for this Component's own Observable events), see the {@link Ext.util.Observable#listeners listeners}
  912. * config for a suggestion, or use a render listener directly:</p><pre><code>
  913. new Ext.Panel({
  914. title: 'The Clickable Panel',
  915. listeners: {
  916. render: function(p) {
  917. // Append the Panel to the click handler&#39;s argument list.
  918. p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
  919. },
  920. single: true // Remove the listener after first invocation
  921. }
  922. });
  923. </code></pre>
  924. * <p>See also <tt>{@link #getEl getEl}</p>
  925. * @type Ext.Element
  926. * @property el
  927. */
  928. /**
  929. * This Component's owner {@link Ext.Container Container} (defaults to undefined, and is set automatically when
  930. * this Component is added to a Container). Read-only.
  931. * <p><b>Note</b>: to access items within the Container see <tt>{@link #itemId}</tt>.</p>
  932. * @type Ext.Container
  933. * @property ownerCt
  934. */
  935. /**
  936. * True if this component is hidden. Read-only.
  937. * @type Boolean
  938. * @property hidden
  939. */
  940. /**
  941. * True if this component is disabled. Read-only.
  942. * @type Boolean
  943. * @property disabled
  944. */
  945. /**
  946. * True if this component has been rendered. Read-only.
  947. * @type Boolean
  948. * @property rendered
  949. */
  950. rendered : false,
  951. /**
  952. * @cfg {String} contentEl
  953. * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as the content
  954. * for this component.</p>
  955. * <ul>
  956. * <li><b>Description</b> :
  957. * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the layout element
  958. * of a new component (it simply moves the specified DOM element <i>after the Component is rendered</i> to use as the content.</div></li>
  959. * <li><b>Notes</b> :
  960. * <div class="sub-desc">The specified HTML element is appended to the layout element of the component <i>after any configured
  961. * {@link #html HTML} has been inserted</i>, and so the document will not contain this element at the time the {@link #render} event is fired.</div>
  962. * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.Container#layout layout}</b></code>
  963. * scheme that the Component may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.Container#items items}</b></code>.</div>
  964. * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to
  965. * prevent a brief flicker of the content before it is rendered to the panel.</div></li>
  966. * </ul>
  967. */
  968. /**
  969. * @cfg {String/Object} html
  970. * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element
  971. * content (defaults to ''). The HTML content is added after the component is rendered,
  972. * so the document will not contain this HTML at the time the {@link #render} event is fired.
  973. * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended.
  974. */
  975. /**
  976. * @cfg {Mixed} tpl
  977. * An <bold>{@link Ext.Template}</bold>, <bold>{@link Ext.XTemplate}</bold>
  978. * or an array of strings to form an Ext.XTemplate.
  979. * Used in conjunction with the <code>{@link #data}</code> and
  980. * <code>{@link #tplWriteMode}</code> configurations.
  981. */
  982. /**
  983. * @cfg {String} tplWriteMode The Ext.(X)Template method to use when
  984. * updating the content area of the Component. Defaults to <tt>'overwrite'</tt>
  985. * (see <code>{@link Ext.XTemplate#overwrite}</code>).
  986. */
  987. tplWriteMode : 'overwrite',
  988. /**
  989. * @cfg {Mixed} data
  990. * The initial set of data to apply to the <code>{@link #tpl}</code> to
  991. * update the content area of the Component.
  992. */
  993. /**
  994. * @cfg {Array} bubbleEvents
  995. * <p>An array of events that, when fired, should be bubbled to any parent container.
  996. * See {@link Ext.util.Observable#enableBubble}.
  997. * Defaults to <tt>[]</tt>.
  998. */
  999. bubbleEvents: [],
  1000. // private
  1001. ctype : 'Ext.Component',
  1002. // private
  1003. actionMode : 'el',
  1004. // private
  1005. getActionEl : function(){
  1006. return this[this.actionMode];
  1007. },
  1008. initPlugin : function(p){
  1009. if(p.ptype && !Ext.isFunction(p.init)){
  1010. p = Ext.ComponentMgr.createPlugin(p);
  1011. }else if(Ext.isString(p)){
  1012. p = Ext.ComponentMgr.createPlugin({
  1013. ptype: p
  1014. });
  1015. }
  1016. p.init(this);
  1017. return p;
  1018. },
  1019. /* // protected
  1020. * Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default).
  1021. * <pre><code>
  1022. // Traditional constructor:
  1023. Ext.Foo = function(config){
  1024. // call superclass constructor:
  1025. Ext.Foo.superclass.constructor.call(this, config);
  1026. this.addEvents({
  1027. // add events
  1028. });
  1029. };
  1030. Ext.extend(Ext.Foo, Ext.Bar, {
  1031. // class body
  1032. }
  1033. // initComponent replaces the constructor:
  1034. Ext.Foo = Ext.extend(Ext.Bar, {
  1035. initComponent : function(){
  1036. // call superclass initComponent
  1037. Ext.Container.superclass.initComponent.call(this);
  1038. this.addEvents({
  1039. // add events
  1040. });
  1041. }
  1042. }
  1043. </code></pre>
  1044. */
  1045. initComponent : function(){
  1046. /*
  1047. * this is double processing, however it allows people to be able to do
  1048. * Ext.apply(this, {
  1049. * listeners: {
  1050. * //here
  1051. * }
  1052. * });
  1053. * MyClass.superclass.initComponent.call(this);
  1054. */
  1055. if(this.listeners){
  1056. this.on(this.listeners);
  1057. delete this.listeners;
  1058. }
  1059. this.enableBubble(this.bubbleEvents);
  1060. },
  1061. /**
  1062. * <p>Render this Component into the passed HTML element.</p>
  1063. * <p><b>If you are using a {@link Ext.Container Container} object to house this Component, then
  1064. * do not use the render method.</b></p>
  1065. * <p>A Container's child Components are rendered by that Container's
  1066. * {@link Ext.Container#layout layout} manager when the Container is first rendered.</p>
  1067. * <p>Certain layout managers allow dynamic addition of child components. Those that do
  1068. * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
  1069. * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
  1070. * <p>If the Container is already rendered when a new child Component is added, you may need to call
  1071. * the Container's {@link Ext.Container#doLayout doLayout} to refresh the view which causes any
  1072. * unrendered child Components to be rendered. This is required so that you can add multiple
  1073. * child components if needed while only refreshing the layout once.</p>
  1074. * <p>When creating complex UIs, it is important to remember that sizing and positioning
  1075. * of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager.
  1076. * If you expect child items to be sized in response to user interactions, you must
  1077. * configure the Container with a layout manager which creates and manages the type of layout you
  1078. * have in mind.</p>
  1079. * <p><b>Omitting the Container's {@link Ext.Container#layout layout} config means that a basic
  1080. * layout manager is used which does nothing but render child components sequentially into the
  1081. * Container. No sizing or positioning will be performed in this situation.</b></p>
  1082. * @param {Element/HTMLElement/String} container (optional) The element this Component should be
  1083. * rendered into. If it is being created from existing markup, this should be omitted.
  1084. * @param {String/Number} position (optional) The element ID or DOM node index within the container <b>before</b>
  1085. * which this component will be inserted (defaults to appending to the end of the container)
  1086. */
  1087. render : function(container, position){
  1088. if(!this.rendered && this.fireEvent('beforerender', this) !== false){
  1089. if(!container && this.el){
  1090. this.el = Ext.get(this.el);
  1091. container = this.el.dom.parentNode;
  1092. this.allowDomMove = false;
  1093. }
  1094. this.container = Ext.get(container);
  1095. if(this.ctCls){
  1096. this.container.addClass(this.ctCls);
  1097. }
  1098. this.rendered = true;
  1099. if(position !== undefined){
  1100. if(Ext.isNumber(position)){
  1101. position = this.container.dom.childNodes[position];
  1102. }else{
  1103. position = Ext.getDom(position);
  1104. }
  1105. }
  1106. this.onRender(this.container, position || null);
  1107. if(this.autoShow){
  1108. this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]);
  1109. }
  1110. if(this.cls){
  1111. this.el.addClass(this.cls);
  1112. delete this.cls;
  1113. }
  1114. if(this.style){
  1115. this.el.applyStyles(this.style);
  1116. delete this.style;
  1117. }
  1118. if(this.overCls){
  1119. this.el.addClassOnOver(this.overCls);
  1120. }
  1121. this.fireEvent('render', this);
  1122. // Populate content of the component with html, contentEl or
  1123. // a tpl.
  1124. var contentTarget = this.getContentTarget();
  1125. if (this.html){
  1126. contentTarget.update(Ext.DomHelper.markup(this.html));
  1127. delete this.html;
  1128. }
  1129. if (this.contentEl){
  1130. var ce = Ext.getDom(this.contentEl);
  1131. Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']);
  1132. contentTarget.appendChild(ce);
  1133. }
  1134. if (this.tpl) {
  1135. if (!this.tpl.compile) {
  1136. this.tpl = new Ext.XTemplate(this.tpl);
  1137. }
  1138. if (this.data) {
  1139. this.tpl[this.tplWriteMode](contentTarget, this.data);
  1140. delete this.data;
  1141. }
  1142. }
  1143. this.afterRender(this.container);
  1144. if(this.hidden){
  1145. // call this so we don't fire initial hide events.
  1146. this.doHide();
  1147. }
  1148. if(this.disabled){
  1149. // pass silent so the event doesn't fire the first time.
  1150. this.disable(true);
  1151. }
  1152. if(this.stateful !== false){
  1153. this.initStateEvents();
  1154. }
  1155. this.fireEvent('afterrender', this);
  1156. }
  1157. return this;
  1158. },
  1159. /**
  1160. * Update the content area of a component.
  1161. * @param {Mixed} htmlOrData
  1162. * If this component has been configured with a template via the tpl config
  1163. * then it will use this argument as data to populate the template.
  1164. * If this component was not configured with a template, the components
  1165. * content area will be updated via Ext.Element update
  1166. * @param {Boolean} loadScripts
  1167. * (optional) Only legitimate when using the html configuration. Defaults to false
  1168. * @param {Function} callback
  1169. * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading
  1170. */
  1171. update: function(htmlOrData, loadScripts, cb) {
  1172. var contentTarget = this.getContentTarget();
  1173. if (this.tpl && typeof htmlOrData !== "string") {
  1174. this.tpl[this.tplWriteMode](contentTarget, htmlOrData || {});
  1175. } else {
  1176. var html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData;
  1177. contentTarget.update(html, loadScripts, cb);
  1178. }
  1179. },
  1180. /**
  1181. * @private
  1182. * Method to manage awareness of when components are added to their
  1183. * respective Container, firing an added event.
  1184. * References are established at add time rather than at render time.
  1185. * @param {Ext.Container} container Container which holds the component
  1186. * @param {number} pos Position at which the component was added
  1187. */
  1188. onAdded : function(container, pos) {
  1189. this.ownerCt = container;
  1190. this.initRef();
  1191. this.fireEvent('added', this, container, pos);
  1192. },
  1193. /**
  1194. * @private
  1195. * Method to manage awareness of when components are removed from their
  1196. * respective Container, firing an removed event. References are properly
  1197. * cleaned up after removing a component from its owning container.
  1198. */
  1199. onRemoved : function() {
  1200. this.removeRef();
  1201. this.fireEvent('removed', this, this.ownerCt);
  1202. delete this.ownerCt;
  1203. },
  1204. /**
  1205. * @private
  1206. * Method to establish a reference to a component.
  1207. */
  1208. initRef : function() {
  1209. /**
  1210. * @cfg {String} ref
  1211. * <p>A path specification, relative to the Component's <code>{@link #ownerCt}</code>
  1212. * specifying into which ancestor Container to place a named reference to this Component.</p>
  1213. * <p>The ancestor axis can be traversed by using '/' characters in the path.
  1214. * For example, to put a reference to a Toolbar Button into <i>the Panel which owns the Toolbar</i>:</p><pre><code>
  1215. var myGrid = new Ext.grid.EditorGridPanel({
  1216. title: 'My EditorGridPanel',
  1217. store: myStore,
  1218. colModel: myColModel,
  1219. tbar: [{
  1220. text: 'Save',
  1221. handler: saveChanges,
  1222. disabled: true,
  1223. ref: '../saveButton'
  1224. }],
  1225. listeners: {
  1226. afteredit: function() {
  1227. // The button reference is in the GridPanel
  1228. myGrid.saveButton.enable();
  1229. }
  1230. }
  1231. });
  1232. </code></pre>
  1233. * <p>In the code above, if the <code>ref</code> had been <code>'saveButton'</code>
  1234. * the reference would have been placed into the Toolbar. Each '/' in the <code>ref</code>
  1235. * moves up one level from the Component's <code>{@link #ownerCt}</code>.</p>
  1236. * <p>Also see the <code>{@link #added}</code> and <code>{@link #removed}</code> events.</p>
  1237. */
  1238. if(this.ref && !this.refOwner){
  1239. var levels = this.ref.split('/'),
  1240. last = levels.length,
  1241. i = 0,
  1242. t = this;
  1243. while(t && i < last){
  1244. t = t.ownerCt;
  1245. ++i;
  1246. }
  1247. if(t){
  1248. t[this.refName = levels[--i]] = this;
  1249. /**
  1250. * @type Ext.Container
  1251. * @property refOwner
  1252. * The ancestor Container into which the {@link #ref} reference was inserted if this Component
  1253. * is a child of a Container, and has been configured with a <code>ref</code>.
  1254. */
  1255. this.refOwner = t;
  1256. }
  1257. }
  1258. },
  1259. removeRef : function() {
  1260. if (this.refOwner && this.refName) {
  1261. delete this.refOwner[this.refName];
  1262. delete this.refOwner;
  1263. }
  1264. },
  1265. // private
  1266. initState : function(){
  1267. if(Ext.state.Manager){
  1268. var id = this.getStateId();
  1269. if(id){
  1270. var state = Ext.state.Manager.get(id);
  1271. if(state){
  1272. if(this.fireEvent('beforestaterestore', this, state) !== false){
  1273. this.applyState(Ext.apply({}, state));
  1274. this.fireEvent('staterestore', this, state);
  1275. }
  1276. }
  1277. }
  1278. }
  1279. },
  1280. // private
  1281. getStateId : function(){
  1282. return this.stateId || ((/^(ext-comp-|ext-gen)/).test(String(this.id)) ? null : this.id);
  1283. },
  1284. // private
  1285. initStateEvents : function(){
  1286. if(this.stateEvents){
  1287. for(var i = 0, e; e = this.stateEvents[i]; i++){
  1288. this.on(e, this.saveState, this, {delay:100});
  1289. }
  1290. }
  1291. },
  1292. // private
  1293. applyState : function(state){
  1294. if(state){
  1295. Ext.apply(this, state);
  1296. }
  1297. },
  1298. // private
  1299. getState : function(){
  1300. return null;
  1301. },
  1302. // private
  1303. saveState : function(){
  1304. if(Ext.state.Manager && this.stateful !== false){
  1305. var id = this.getStateId();
  1306. if(id){
  1307. var state = this.getState();
  1308. if(this.fireEvent('beforestatesave', this, state) !== false){
  1309. Ext.state.Manager.set(id, state);
  1310. this.fireEvent('statesave', this, state);
  1311. }
  1312. }
  1313. }
  1314. },
  1315. /**
  1316. * Apply this component to existing markup that is valid. With this function, no call to render() is required.
  1317. * @param {String/HTMLElement} el
  1318. */
  1319. applyToMarkup : function(el){
  1320. this.allowDomMove = false;
  1321. this.el = Ext.get(el);
  1322. this.render(this.el.dom.parentNode);
  1323. },
  1324. /**
  1325. * Adds a CSS class to the component's underlying element.
  1326. * @param {string} cls The CSS class name to add
  1327. * @return {Ext.Component} this
  1328. */
  1329. addClass : function(cls){
  1330. if(this.el){
  1331. this.el.addClass(cls);
  1332. }else{
  1333. this.cls = this.cls ? this.cls + ' ' + cls : cls;
  1334. }
  1335. return this;
  1336. },
  1337. /**
  1338. * Removes a CSS class from the component's underlying element.
  1339. * @param {string} cls The CSS class name to remove
  1340. * @return {Ext.Component} this
  1341. */
  1342. removeClass : function(cls){
  1343. if(this.el){
  1344. this.el.removeClass(cls);
  1345. }else if(this.cls){
  1346. this.cls = this.cls.split(' ').remove(cls).join(' ');
  1347. }
  1348. return this;
  1349. },
  1350. // private
  1351. // default function is not really useful
  1352. onRender : function(ct, position){
  1353. if(!this.el && this.autoEl){
  1354. if(Ext.isString(this.autoEl)){
  1355. this.el = document.createElement(this.autoEl);
  1356. }else{
  1357. var div = document.createElement('div');
  1358. Ext.DomHelper.overwrite(div, this.autoEl);
  1359. this.el = div.firstChild;
  1360. }
  1361. if (!this.el.id) {
  1362. this.el.id = this.getId();
  1363. }
  1364. }
  1365. if(this.el){
  1366. this.el = Ext.get(this.el);
  1367. if(this.allowDomMove !== false){
  1368. ct.dom.insertBefore(this.el.dom, position);
  1369. if (div) {
  1370. Ext.removeNode(div);
  1371. div = null;
  1372. }
  1373. }
  1374. }
  1375. },
  1376. // private
  1377. getAutoCreate : function(){
  1378. var cfg = Ext.isObject(this.autoCreate) ?
  1379. this.autoCreate : Ext.apply({}, this.defaultAutoCreate);
  1380. if(this.id && !cfg.id){
  1381. cfg.id = this.id;
  1382. }
  1383. return cfg;
  1384. },
  1385. // private
  1386. afterRender : Ext.emptyFn,
  1387. /**
  1388. * Destroys this component by purging any event listeners, removing the component's element from the DOM,
  1389. * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from
  1390. * {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method
  1391. * should usually not need to be called directly.
  1392. *
  1393. */
  1394. destroy : function(){
  1395. if(!this.isDestroyed){
  1396. if(this.fireEvent('beforedestroy', this) !== false){
  1397. this.destroying = true;
  1398. this.beforeDestroy();
  1399. if(this.ownerCt && this.ownerCt.remove){
  1400. this.ownerCt.remove(this, false);
  1401. }
  1402. if(this.rendered){
  1403. this.el.remove();
  1404. if(this.actionMode == 'container' || this.removeMode == 'container'){
  1405. this.container.remove();
  1406. }
  1407. }
  1408. // Stop any buffered tasks
  1409. if(this.focusTask && this.focusTask.cancel){
  1410. this.focusTask.cancel();
  1411. }
  1412. this.onDestroy();
  1413. Ext.ComponentMgr.unregister(this);
  1414. this.fireEvent('destroy', this);
  1415. this.purgeListeners();
  1416. this.destroying = false;
  1417. this.isDestroyed = true;
  1418. }
  1419. }
  1420. },
  1421. deleteMembers : function(){
  1422. var args = arguments;
  1423. for(var i = 0, len = args.length; i < len; ++i){
  1424. delete this[args[i]];
  1425. }
  1426. },
  1427. // private
  1428. beforeDestroy : Ext.emptyFn,
  1429. // private
  1430. onDestroy : Ext.emptyFn,
  1431. /**
  1432. * <p>Returns the {@link Ext.Element} which encapsulates this Component.</p>
  1433. * <p>This will <i>usually</i> be a &lt;DIV> element created by the class's onRender method, but
  1434. * that may be overridden using the {@link #autoEl} config.</p>
  1435. * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
  1436. * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
  1437. * for this Component's own Observable events), see the {@link #listeners} config for a suggestion,
  1438. * or use a render listener directly:</p><pre><code>
  1439. new Ext.Panel({
  1440. title: 'The Clickable Panel',
  1441. listeners: {
  1442. render: function(p) {
  1443. // Append the Panel to the click handler&#39;s argument list.
  1444. p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
  1445. },
  1446. single: true // Remove the listener after first invocation
  1447. }
  1448. });
  1449. </code></pre>
  1450. * @return {Ext.Element} The Element which encapsulates this Component.
  1451. */
  1452. getEl : function(){
  1453. return this.el;
  1454. },
  1455. // private
  1456. getContentTarget : function(){
  1457. return this.el;
  1458. },
  1459. /**
  1460. * Returns the <code>id</code> of this component or automatically generates and
  1461. * returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code>
  1462. * 'ext-comp-' + (++Ext.Component.AUTO_ID)
  1463. * </code></pre>
  1464. * @return {String} id
  1465. */
  1466. getId : function(){
  1467. return this.id || (this.id = 'ext-comp-' + (++Ext.Component.AUTO_ID));
  1468. },
  1469. /**
  1470. * Returns the <code>{@link #itemId}</code> of this component. If an
  1471. * <code>{@link #itemId}</code> was not assigned through configuration the
  1472. * <code>id</code> is returned using <code>{@link #getId}</code>.
  1473. * @return {String}
  1474. */
  1475. getItemId : function(){
  1476. return this.itemId || this.getId();
  1477. },
  1478. /**
  1479. * Try to focus this component.
  1480. * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
  1481. * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
  1482. * @return {Ext.Component} this
  1483. */
  1484. focus : function(selectText, delay){
  1485. if(delay){
  1486. this.focusTask = new Ext.util.DelayedTask(this.focus, this, [selectText, false]);
  1487. this.focusTask.delay(Ext.isNumber(delay) ? delay : 10);
  1488. return;
  1489. }
  1490. if(this.rendered && !this.isDestroyed){
  1491. this.el.focus();
  1492. if(selectText === true){
  1493. this.el.dom.select();
  1494. }
  1495. }
  1496. return this;
  1497. },
  1498. // private
  1499. blur : function(){
  1500. if(this.rendered){
  1501. this.el.blur();
  1502. }
  1503. return this;
  1504. },
  1505. /**
  1506. * Disable this component and fire the 'disable' event.
  1507. * @return {Ext.Component} this
  1508. */
  1509. disable : function(/* private */ silent){
  1510. if(this.rendered){
  1511. this.onDisable();
  1512. }
  1513. this.disabled = true;
  1514. if(silent !== true){
  1515. this.fireEvent('disable', this);
  1516. }
  1517. return this;
  1518. },
  1519. // private
  1520. onDisable : function(){
  1521. this.getActionEl().addClass(this.disabledClass);
  1522. this.el.dom.disabled = true;
  1523. },
  1524. /**
  1525. * Enable this component and fire the 'enable' event.
  1526. * @return {Ext.Component} this
  1527. */
  1528. enable : function(){
  1529. if(this.rendered){
  1530. this.onEnable();
  1531. }
  1532. this.disabled = false;
  1533. this.fireEvent('enable', this);
  1534. return this;
  1535. },
  1536. // private
  1537. onEnable : function(){
  1538. this.getActionEl().removeClass(this.disabledClass);
  1539. this.el.dom.disabled = false;
  1540. },
  1541. /**
  1542. * Convenience function for setting disabled/enabled by boolean.
  1543. * @param {Boolean} disabled
  1544. * @return {Ext.Component} this
  1545. */
  1546. setDisabled : function(disabled){
  1547. return this[disabled ? 'disable' : 'enable']();
  1548. },
  1549. /**
  1550. * Show this component. Listen to the '{@link #beforeshow}' event and return
  1551. * <tt>false</tt> to cancel showing the component. Fires the '{@link #show}'
  1552. * event after showing the component.
  1553. * @return {Ext.Component} this
  1554. */
  1555. show : function(){
  1556. if(this.fireEvent('beforeshow', this) !== false){
  1557. this.hidden = false;
  1558. if(this.autoRender){
  1559. this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender);
  1560. }
  1561. if(this.rendered){
  1562. this.onShow();
  1563. }
  1564. this.fireEvent('show', this);
  1565. }
  1566. return this;
  1567. },
  1568. // private
  1569. onShow : function(){
  1570. this.getVisibilityEl().removeClass('x-hide-' + this.hideMode);
  1571. },
  1572. /**
  1573. * Hide this component. Listen to the '{@link #beforehide}' event and return
  1574. * <tt>false</tt> to cancel hiding the component. Fires the '{@link #hide}'
  1575. * event after hiding the component. Note this method is called internally if
  1576. * the component is configured to be <code>{@link #hidden}</code>.
  1577. * @return {Ext.Component} this
  1578. */
  1579. hide : function(){
  1580. if(this.fireEvent('beforehide', this) !== false){
  1581. this.doHide();
  1582. this.fireEvent('hide', this);
  1583. }
  1584. return this;
  1585. },
  1586. // private
  1587. doHide: function(){
  1588. this.hidden = true;
  1589. if(this.rendered){
  1590. this.onHide();
  1591. }
  1592. },
  1593. // private
  1594. onHide : function(){
  1595. this.getVisibilityEl().addClass('x-hide-' + this.hideMode);
  1596. },
  1597. // private
  1598. getVisibilityEl : function(){
  1599. return this.hideParent ? this.container : this.getActionEl();
  1600. },
  1601. /**
  1602. * Convenience function to hide or show this component by boolean.
  1603. * @param {Boolean} visible True to show, false to hide
  1604. * @return {Ext.Component} this
  1605. */
  1606. setVisible : function(visible){
  1607. return this[visible ? 'show' : 'hide']();
  1608. },
  1609. /**
  1610. * Returns true if this component is visible.
  1611. * @return {Boolean} True if this component is visible, false otherwise.
  1612. */
  1613. isVisible : function(){
  1614. return this.rendered && this.getVisibilityEl().isVisible();
  1615. },
  1616. /**
  1617. * Clone the current component using the original config values passed into this instance by default.
  1618. * @param {Object} overrides A new config containing any properties to override in the cloned version.
  1619. * An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
  1620. * @return {Ext.Component} clone The cloned copy of this component
  1621. */
  1622. cloneConfig : function(overrides){
  1623. overrides = overrides || {};
  1624. var id = overrides.id || Ext.id();
  1625. var cfg = Ext.applyIf(overrides, this.initialConfig);
  1626. cfg.id = id; // prevent dup id
  1627. return new this.constructor(cfg);
  1628. },
  1629. /**
  1630. * Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all
  1631. * available xtypes, see the {@link Ext.Component} header. Example usage:
  1632. * <pre><code>
  1633. var t = new Ext.form.TextField();
  1634. alert(t.getXType()); // alerts 'textfield'
  1635. </code></pre>
  1636. * @return {String} The xtype
  1637. */
  1638. getXType : function(){
  1639. return this.constructor.xtype;
  1640. },
  1641. /**
  1642. * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
  1643. * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p>
  1644. * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
  1645. * to participate in determination of inherited xtypes.</b></p>
  1646. * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p>
  1647. * <p>Example usage:</p>
  1648. * <pre><code>
  1649. var t = new Ext.form.TextField();
  1650. var isText = t.isXType('textfield'); // true
  1651. var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
  1652. var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
  1653. </code></pre>
  1654. * @param {String} xtype The xtype to check for this Component
  1655. * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
  1656. * the default), or true to check whether this Component is directly of the specified xtype.
  1657. * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
  1658. */
  1659. isXType : function(xtype, shallow){
  1660. //assume a string by default
  1661. if (Ext.isFunction(xtype)){
  1662. xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component
  1663. }else if (Ext.isObject(xtype)){
  1664. xtype = xtype.constructor.xtype; //handle being passed an instance
  1665. }
  1666. return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 : this.constructor.xtype == xtype;
  1667. },
  1668. /**
  1669. * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all
  1670. * available xtypes, see the {@link Ext.Component} header.</p>
  1671. * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
  1672. * to participate in determination of inherited xtypes.</b></p>
  1673. * <p>Example usage:</p>
  1674. * <pre><code>
  1675. var t = new Ext.form.TextField();
  1676. alert(t.getXTypes()); // alerts 'component/box/field/textfield'
  1677. </code></pre>
  1678. * @return {String} The xtype hierarchy string
  1679. */
  1680. getXTypes : function(){
  1681. var tc = this.constructor;
  1682. if(!tc.xtypes){
  1683. var c = [], sc = this;
  1684. while(sc && sc.constructor.xtype){
  1685. c.unshift(sc.constructor.xtype);
  1686. sc = sc.constructor.superclass;
  1687. }
  1688. tc.xtypeChain = c;
  1689. tc.xtypes = c.join('/');
  1690. }
  1691. return tc.xtypes;
  1692. },
  1693. /**
  1694. * Find a container above this component at any level by a custom function. If the passed function returns
  1695. * true, the container will be returned.
  1696. * @param {Function} fn The custom function to call with the arguments (container, this component).
  1697. * @return {Ext.Container} The first Container for which the custom function returns true
  1698. */
  1699. findParentBy : function(fn) {
  1700. for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt);
  1701. return p || null;
  1702. },
  1703. /**
  1704. * Find a container above this component at any level by xtype or class
  1705. * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
  1706. * @return {Ext.Container} The first Container which matches the given xtype or class
  1707. */
  1708. findParentByType : function(xtype) {
  1709. return Ext.isFunction(xtype) ?
  1710. this.findParentBy(function(p){
  1711. return p.constructor === xtype;
  1712. }) :
  1713. this.findParentBy(function(p){
  1714. return p.constructor.xtype === xtype;
  1715. });
  1716. },
  1717. // protected
  1718. getPositionEl : function(){
  1719. return this.positionEl || this.el;
  1720. },
  1721. // private
  1722. purgeListeners : function(){
  1723. Ext.Component.superclass.purgeListeners.call(this);
  1724. if(this.mons){
  1725. this.on('beforedestroy', this.clearMons, this, {single: true});
  1726. }
  1727. },
  1728. // private
  1729. clearMons : function(){
  1730. Ext.each(this.mons, function(m){
  1731. m.item.un(m.ename, m.fn, m.scope);
  1732. }, this);
  1733. this.mons = [];
  1734. },
  1735. // private
  1736. createMons: function(){
  1737. if(!this.mons){
  1738. this.mons = [];
  1739. this.on('beforedestroy', this.clearMons, this, {single: true});
  1740. }
  1741. },
  1742. /**
  1743. * <p>Adds listeners to any Observable object (or Elements) which are automatically removed when this Component
  1744. * is destroyed. Usage:</p><code><pre>
  1745. myGridPanel.mon(myGridPanel.getSelectionModel(), 'selectionchange', handleSelectionChange, null, {buffer: 50});
  1746. </pre></code>
  1747. * <p>or:</p><code><pre>
  1748. myGridPanel.mon(myGridPanel.getSelectionModel(), {
  1749. selectionchange: handleSelectionChange,
  1750. buffer: 50
  1751. });
  1752. </pre></code>
  1753. * @param {Observable|Element} item The item to which to add a listener/listeners.
  1754. * @param {Object|String} ename The event name, or an object containing event name properties.
  1755. * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
  1756. * is the handler function.
  1757. * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
  1758. * is the scope (<code>this</code> reference) in which the handler function is executed.
  1759. * @param {Object} opt Optional. If the <code>ename</code> parameter was an event name, this
  1760. * is the {@link Ext.util.Observable#addListener addListener} options.
  1761. */
  1762. mon : function(item, ename, fn, scope, opt){
  1763. this.createMons();
  1764. if(Ext.isObject(ename)){
  1765. var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
  1766. var o = ename;
  1767. for(var e in o){
  1768. if(propRe.test(e)){
  1769. continue;
  1770. }
  1771. if(Ext.isFunction(o[e])){
  1772. // shared options
  1773. this.mons.push({
  1774. item: item, ename: e, fn: o[e], scope: o.scope
  1775. });
  1776. item.on(e, o[e], o.scope, o);
  1777. }else{
  1778. // individual options
  1779. this.mons.push({
  1780. item: item, ename: e, fn: o[e], scope: o.scope
  1781. });
  1782. item.on(e, o[e]);
  1783. }
  1784. }
  1785. return;
  1786. }
  1787. this.mons.push({
  1788. item: item, ename: ename, fn: fn, scope: scope
  1789. });
  1790. item.on(ename, fn, scope, opt);
  1791. },
  1792. /**
  1793. * Removes listeners that were added by the {@link #mon} method.
  1794. * @param {Observable|Element} item The item from which to remove a listener/listeners.
  1795. * @param {Object|String} ename The event name, or an object containing event name properties.
  1796. * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
  1797. * is the handler function.
  1798. * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
  1799. * is the scope (<code>this</code> reference) in which the handler function is executed.
  1800. */
  1801. mun : function(item, ename, fn, scope){
  1802. var found, mon;
  1803. this.createMons();
  1804. for(var i = 0, len = this.mons.length; i < len; ++i){
  1805. mon = this.mons[i];
  1806. if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){
  1807. this.mons.splice(i, 1);
  1808. item.un(ename, fn, scope);
  1809. found = true;
  1810. break;
  1811. }
  1812. }
  1813. return found;
  1814. },
  1815. /**
  1816. * Returns the next component in the owning container
  1817. * @return Ext.Component
  1818. */
  1819. nextSibling : function(){
  1820. if(this.ownerCt){
  1821. var index = this.ownerCt.items.indexOf(this);
  1822. if(index != -1 && index+1 < this.ownerCt.items.getCount()){
  1823. return this.ownerCt.items.itemAt(index+1);
  1824. }
  1825. }
  1826. return null;
  1827. },
  1828. /**
  1829. * Returns the previous component in the owning container
  1830. * @return Ext.Component
  1831. */
  1832. previousSibling : function(){
  1833. if(this.ownerCt){
  1834. var index = this.ownerCt.items.indexOf(this);
  1835. if(index > 0){
  1836. return this.ownerCt.items.itemAt(index-1);
  1837. }
  1838. }
  1839. return null;
  1840. },
  1841. /**
  1842. * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
  1843. * @return {Ext.Container} the Container which owns this Component.
  1844. */
  1845. getBubbleTarget : function(){
  1846. return this.ownerCt;
  1847. }
  1848. });
  1849. Ext.reg('component', Ext.Component);/**
  1850. * @class Ext.Action
  1851. * <p>An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it
  1852. * can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI
  1853. * updates across any components that support the Action interface (primarily {@link Ext.Toolbar}, {@link Ext.Button}
  1854. * and {@link Ext.menu.Menu} components).</p>
  1855. * <p>Aside from supporting the config object interface, any component that needs to use Actions must also support
  1856. * the following method list, as these will be called as needed by the Action class: setText(string), setIconCls(string),
  1857. * setDisabled(boolean), setVisible(boolean) and setHandler(function).</p>
  1858. * Example usage:<br>
  1859. * <pre><code>
  1860. // Define the shared action. Each component below will have the same
  1861. // display text and icon, and will display the same message on click.
  1862. var action = new Ext.Action({
  1863. {@link #text}: 'Do something',
  1864. {@link #handler}: function(){
  1865. Ext.Msg.alert('Click', 'You did something.');
  1866. },
  1867. {@link #iconCls}: 'do-something',
  1868. {@link #itemId}: 'myAction'
  1869. });
  1870. var panel = new Ext.Panel({
  1871. title: 'Actions',
  1872. width: 500,
  1873. height: 300,
  1874. tbar: [
  1875. // Add the action directly to a toolbar as a menu button
  1876. action,
  1877. {
  1878. text: 'Action Menu',
  1879. // Add the action to a menu as a text item
  1880. menu: [action]
  1881. }
  1882. ],
  1883. items: [
  1884. // Add the action to the panel body as a standard button
  1885. new Ext.Button(action)
  1886. ],
  1887. renderTo: Ext.getBody()
  1888. });
  1889. // Change the text for all components using the action
  1890. action.setText('Something else');
  1891. // Reference an action through a container using the itemId
  1892. var btn = panel.getComponent('myAction');
  1893. var aRef = btn.baseAction;
  1894. aRef.setText('New text');
  1895. </code></pre>
  1896. * @constructor
  1897. * @param {Object} config The configuration options
  1898. */
  1899. Ext.Action = Ext.extend(Object, {
  1900. /**
  1901. * @cfg {String} text The text to set for all components using this action (defaults to '').
  1902. */
  1903. /**
  1904. * @cfg {String} iconCls
  1905. * The CSS class selector that specifies a background image to be used as the header icon for
  1906. * all components using this action (defaults to '').
  1907. * <p>An example of specifying a custom icon class would be something like:
  1908. * </p><pre><code>
  1909. // specify the property in the config for the class:
  1910. ...
  1911. iconCls: 'do-something'
  1912. // css class that specifies background image to be used as the icon image:
  1913. .do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
  1914. </code></pre>
  1915. */
  1916. /**
  1917. * @cfg {Boolean} disabled True to disable all components using this action, false to enable them (defaults to false).
  1918. */
  1919. /**
  1920. * @cfg {Boolean} hidden True to hide all components using this action, false to show them (defaults to false).
  1921. */
  1922. /**
  1923. * @cfg {Function} handler The function that will be invoked by each component tied to this action
  1924. * when the component's primary event is triggered (defaults to undefined).
  1925. */
  1926. /**
  1927. * @cfg {String} itemId
  1928. * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
  1929. */
  1930. /**
  1931. * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the
  1932. * <code>{@link #handler}</code> is executed. Defaults to this Button.
  1933. */
  1934. constructor : function(config){
  1935. this.initialConfig = config;
  1936. this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
  1937. this.items = [];
  1938. },
  1939. // private
  1940. isAction : true,
  1941. /**
  1942. * Sets the text to be displayed by all components using this action.
  1943. * @param {String} text The text to display
  1944. */
  1945. setText : function(text){
  1946. this.initialConfig.text = text;
  1947. this.callEach('setText', [text]);
  1948. },
  1949. /**
  1950. * Gets the text currently displayed by all components using this action.
  1951. */
  1952. getText : function(){
  1953. return this.initialConfig.text;
  1954. },
  1955. /**
  1956. * Sets the icon CSS class for all components using this action. The class should supply
  1957. * a background image that will be used as the icon image.
  1958. * @param {String} cls The CSS class supplying the icon image
  1959. */
  1960. setIconClass : function(cls){
  1961. this.initialConfig.iconCls = cls;
  1962. this.callEach('setIconClass', [cls]);
  1963. },
  1964. /**
  1965. * Gets the icon CSS class currently used by all components using this action.
  1966. */
  1967. getIconClass : function(){
  1968. return this.initialConfig.iconCls;
  1969. },
  1970. /**
  1971. * Sets the disabled state of all components using this action. Shortcut method
  1972. * for {@link #enable} and {@link #disable}.
  1973. * @param {Boolean} disabled True to disable the component, false to enable it
  1974. */
  1975. setDisabled : function(v){
  1976. this.initialConfig.disabled = v;
  1977. this.callEach('setDisabled', [v]);
  1978. },
  1979. /**
  1980. * Enables all components using this action.
  1981. */
  1982. enable : function(){
  1983. this.setDisabled(false);
  1984. },
  1985. /**
  1986. * Disables all components using this action.
  1987. */
  1988. disable : function(){
  1989. this.setDisabled(true);
  1990. },
  1991. /**
  1992. * Returns true if the components using this action are currently disabled, else returns false.
  1993. */
  1994. isDisabled : function(){
  1995. return this.initialConfig.disabled;
  1996. },
  1997. /**
  1998. * Sets the hidden state of all components using this action. Shortcut method
  1999. * for <code>{@link #hide}</code> and <code>{@link #show}</code>.
  2000. * @param {Boolean} hidden True to hide the component, false to show it
  2001. */
  2002. setHidden : function(v){
  2003. this.initialConfig.hidden = v;
  2004. this.callEach('setVisible', [!v]);
  2005. },
  2006. /**
  2007. * Shows all components using this action.
  2008. */
  2009. show : function(){
  2010. this.setHidden(false);
  2011. },
  2012. /**
  2013. * Hides all components using this action.
  2014. */
  2015. hide : function(){
  2016. this.setHidden(true);
  2017. },
  2018. /**
  2019. * Returns true if the components using this action are currently hidden, else returns false.
  2020. */
  2021. isHidden : function(){
  2022. return this.initialConfig.hidden;
  2023. },
  2024. /**
  2025. * Sets the function that will be called by each Component using this action when its primary event is triggered.
  2026. * @param {Function} fn The function that will be invoked by the action's components. The function
  2027. * will be called with no arguments.
  2028. * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component firing the event.
  2029. */
  2030. setHandler : function(fn, scope){
  2031. this.initialConfig.handler = fn;
  2032. this.initialConfig.scope = scope;
  2033. this.callEach('setHandler', [fn, scope]);
  2034. },
  2035. /**
  2036. * Executes the specified function once for each Component currently tied to this action. The function passed
  2037. * in should accept a single argument that will be an object that supports the basic Action config/method interface.
  2038. * @param {Function} fn The function to execute for each component
  2039. * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component.
  2040. */
  2041. each : function(fn, scope){
  2042. Ext.each(this.items, fn, scope);
  2043. },
  2044. // private
  2045. callEach : function(fnName, args){
  2046. var cs = this.items;
  2047. for(var i = 0, len = cs.length; i < len; i++){
  2048. cs[i][fnName].apply(cs[i], args);
  2049. }
  2050. },
  2051. // private
  2052. addComponent : function(comp){
  2053. this.items.push(comp);
  2054. comp.on('destroy', this.removeComponent, this);
  2055. },
  2056. // private
  2057. removeComponent : function(comp){
  2058. this.items.remove(comp);
  2059. },
  2060. /**
  2061. * Executes this action manually using the handler function specified in the original config object
  2062. * or the handler function set with <code>{@link #setHandler}</code>. Any arguments passed to this
  2063. * function will be passed on to the handler function.
  2064. * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function
  2065. * @param {Mixed} arg2 (optional)
  2066. * @param {Mixed} etc... (optional)
  2067. */
  2068. execute : function(){
  2069. this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments);
  2070. }
  2071. });
  2072. /**
  2073. * @class Ext.Layer
  2074. * @extends Ext.Element
  2075. * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and
  2076. * automatic maintaining of shadow/shim positions.
  2077. * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
  2078. * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the
  2079. * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false)
  2080. * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}).
  2081. * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
  2082. * @cfg {String} cls CSS class to add to the element
  2083. * @cfg {Number} zindex Starting z-index (defaults to 11000)
  2084. * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4)
  2085. * @cfg {Boolean} useDisplay
  2086. * Defaults to use css offsets to hide the Layer. Specify <tt>true</tt>
  2087. * to use css style <tt>'display:none;'</tt> to hide the Layer.
  2088. * @constructor
  2089. * @param {Object} config An object with config options.
  2090. * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
  2091. */
  2092. (function(){
  2093. Ext.Layer = function(config, existingEl){
  2094. config = config || {};
  2095. var dh = Ext.DomHelper;
  2096. var cp = config.parentEl, pel = cp ? Ext.getDom(cp) : document.body;
  2097. if(existingEl){
  2098. this.dom = Ext.getDom(existingEl);
  2099. }
  2100. if(!this.dom){
  2101. var o = config.dh || {tag: 'div', cls: 'x-layer'};
  2102. this.dom = dh.append(pel, o);
  2103. }
  2104. if(config.cls){
  2105. this.addClass(config.cls);
  2106. }
  2107. this.constrain = config.constrain !== false;
  2108. this.setVisibilityMode(Ext.Element.VISIBILITY);
  2109. if(config.id){
  2110. this.id = this.dom.id = config.id;
  2111. }else{
  2112. this.id = Ext.id(this.dom);
  2113. }
  2114. this.zindex = config.zindex || this.getZIndex();
  2115. this.position('absolute', this.zindex);
  2116. if(config.shadow){
  2117. this.shadowOffset = config.shadowOffset || 4;
  2118. this.shadow = new Ext.Shadow({
  2119. offset : this.shadowOffset,
  2120. mode : config.shadow
  2121. });
  2122. }else{
  2123. this.shadowOffset = 0;
  2124. }
  2125. this.useShim = config.shim !== false && Ext.useShims;
  2126. this.useDisplay = config.useDisplay;
  2127. this.hide();
  2128. };
  2129. var supr = Ext.Element.prototype;
  2130. // shims are shared among layer to keep from having 100 iframes
  2131. var shims = [];
  2132. Ext.extend(Ext.Layer, Ext.Element, {
  2133. getZIndex : function(){
  2134. return this.zindex || parseInt((this.getShim() || this).getStyle('z-index'), 10) || 11000;
  2135. },
  2136. getShim : function(){
  2137. if(!this.useShim){
  2138. return null;
  2139. }
  2140. if(this.shim){
  2141. return this.shim;
  2142. }
  2143. var shim = shims.shift();
  2144. if(!shim){
  2145. shim = this.createShim();
  2146. shim.enableDisplayMode('block');
  2147. shim.dom.style.display = 'none';
  2148. shim.dom.style.visibility = 'visible';
  2149. }
  2150. var pn = this.dom.parentNode;
  2151. if(shim.dom.parentNode != pn){
  2152. pn.insertBefore(shim.dom, this.dom);
  2153. }
  2154. shim.setStyle('z-index', this.getZIndex()-2);
  2155. this.shim = shim;
  2156. return shim;
  2157. },
  2158. hideShim : function(){
  2159. if(this.shim){
  2160. this.shim.setDisplayed(false);
  2161. shims.push(this.shim);
  2162. delete this.shim;
  2163. }
  2164. },
  2165. disableShadow : function(){
  2166. if(this.shadow){
  2167. this.shadowDisabled = true;
  2168. this.shadow.hide();
  2169. this.lastShadowOffset = this.shadowOffset;
  2170. this.shadowOffset = 0;
  2171. }
  2172. },
  2173. enableShadow : function(show){
  2174. if(this.shadow){
  2175. this.shadowDisabled = false;
  2176. this.shadowOffset = this.lastShadowOffset;
  2177. delete this.lastShadowOffset;
  2178. if(show){
  2179. this.sync(true);
  2180. }
  2181. }
  2182. },
  2183. // private
  2184. // this code can execute repeatedly in milliseconds (i.e. during a drag) so
  2185. // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
  2186. sync : function(doShow){
  2187. var shadow = this.shadow;
  2188. if(!this.updating && this.isVisible() && (shadow || this.useShim)){
  2189. var shim = this.getShim(),
  2190. w = this.getWidth(),
  2191. h = this.getHeight(),
  2192. l = this.getLeft(true),
  2193. t = this.getTop(true);
  2194. if(shadow && !this.shadowDisabled){
  2195. if(doShow && !shadow.isVisible()){
  2196. shadow.show(this);
  2197. }else{
  2198. shadow.realign(l, t, w, h);
  2199. }
  2200. if(shim){
  2201. if(doShow){
  2202. shim.show();
  2203. }
  2204. // fit the shim behind the shadow, so it is shimmed too
  2205. var shadowAdj = shadow.el.getXY(), shimStyle = shim.dom.style,
  2206. shadowSize = shadow.el.getSize();
  2207. shimStyle.left = (shadowAdj[0])+'px';
  2208. shimStyle.top = (shadowAdj[1])+'px';
  2209. shimStyle.width = (shadowSize.width)+'px';
  2210. shimStyle.height = (shadowSize.height)+'px';
  2211. }
  2212. }else if(shim){
  2213. if(doShow){
  2214. shim.show();
  2215. }
  2216. shim.setSize(w, h);
  2217. shim.setLeftTop(l, t);
  2218. }
  2219. }
  2220. },
  2221. // private
  2222. destroy : function(){
  2223. this.hideShim();
  2224. if(this.shadow){
  2225. this.shadow.hide();
  2226. }
  2227. this.removeAllListeners();
  2228. Ext.removeNode(this.dom);
  2229. delete this.dom;
  2230. },
  2231. remove : function(){
  2232. this.destroy();
  2233. },
  2234. // private
  2235. beginUpdate : function(){
  2236. this.updating = true;
  2237. },
  2238. // private
  2239. endUpdate : function(){
  2240. this.updating = false;
  2241. this.sync(true);
  2242. },
  2243. // private
  2244. hideUnders : function(negOffset){
  2245. if(this.shadow){
  2246. this.shadow.hide();
  2247. }
  2248. this.hideShim();
  2249. },
  2250. // private
  2251. constrainXY : function(){
  2252. if(this.constrain){
  2253. var vw = Ext.lib.Dom.getViewWidth(),
  2254. vh = Ext.lib.Dom.getViewHeight();
  2255. var s = Ext.getDoc().getScroll();
  2256. var xy = this.getXY();
  2257. var x = xy[0], y = xy[1];
  2258. var so = this.shadowOffset;
  2259. var w = this.dom.offsetWidth+so, h = this.dom.offsetHeight+so;
  2260. // only move it if it needs it
  2261. var moved = false;
  2262. // first validate right/bottom
  2263. if((x + w) > vw+s.left){
  2264. x = vw - w - so;
  2265. moved = true;
  2266. }
  2267. if((y + h) > vh+s.top){
  2268. y = vh - h - so;
  2269. moved = true;
  2270. }
  2271. // then make sure top/left isn't negative
  2272. if(x < s.left){
  2273. x = s.left;
  2274. moved = true;
  2275. }
  2276. if(y < s.top){
  2277. y = s.top;
  2278. moved = true;
  2279. }
  2280. if(moved){
  2281. if(this.avoidY){
  2282. var ay = this.avoidY;
  2283. if(y <= ay && (y+h) >= ay){
  2284. y = ay-h-5;
  2285. }
  2286. }
  2287. xy = [x, y];
  2288. this.storeXY(xy);
  2289. supr.setXY.call(this, xy);
  2290. this.sync();
  2291. }
  2292. }
  2293. return this;
  2294. },
  2295. isVisible : function(){
  2296. return this.visible;
  2297. },
  2298. // private
  2299. showAction : function(){
  2300. this.visible = true; // track visibility to prevent getStyle calls
  2301. if(this.useDisplay === true){
  2302. this.setDisplayed('');
  2303. }else if(this.lastXY){
  2304. supr.setXY.call(this, this.lastXY);
  2305. }else if(this.lastLT){
  2306. supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
  2307. }
  2308. },
  2309. // private
  2310. hideAction : function(){
  2311. this.visible = false;
  2312. if(this.useDisplay === true){
  2313. this.setDisplayed(false);
  2314. }else{
  2315. this.setLeftTop(-10000,-10000);
  2316. }
  2317. },
  2318. // overridden Element method
  2319. setVisible : function(v, a, d, c, e){
  2320. if(v){
  2321. this.showAction();
  2322. }
  2323. if(a && v){
  2324. var cb = function(){
  2325. this.sync(true);
  2326. if(c){
  2327. c();
  2328. }
  2329. }.createDelegate(this);
  2330. supr.setVisible.call(this, true, true, d, cb, e);
  2331. }else{
  2332. if(!v){
  2333. this.hideUnders(true);
  2334. }
  2335. var cb = c;
  2336. if(a){
  2337. cb = function(){
  2338. this.hideAction();
  2339. if(c){
  2340. c();
  2341. }
  2342. }.createDelegate(this);
  2343. }
  2344. supr.setVisible.call(this, v, a, d, cb, e);
  2345. if(v){
  2346. this.sync(true);
  2347. }else if(!a){
  2348. this.hideAction();
  2349. }
  2350. }
  2351. return this;
  2352. },
  2353. storeXY : function(xy){
  2354. delete this.lastLT;
  2355. this.lastXY = xy;
  2356. },
  2357. storeLeftTop : function(left, top){
  2358. delete this.lastXY;
  2359. this.lastLT = [left, top];
  2360. },
  2361. // private
  2362. beforeFx : function(){
  2363. this.beforeAction();
  2364. return Ext.Layer.superclass.beforeFx.apply(this, arguments);
  2365. },
  2366. // private
  2367. afterFx : function(){
  2368. Ext.Layer.superclass.afterFx.apply(this, arguments);
  2369. this.sync(this.isVisible());
  2370. },
  2371. // private
  2372. beforeAction : function(){
  2373. if(!this.updating && this.shadow){
  2374. this.shadow.hide();
  2375. }
  2376. },
  2377. // overridden Element method
  2378. setLeft : function(left){
  2379. this.storeLeftTop(left, this.getTop(true));
  2380. supr.setLeft.apply(this, arguments);
  2381. this.sync();
  2382. return this;
  2383. },
  2384. setTop : function(top){
  2385. this.storeLeftTop(this.getLeft(true), top);
  2386. supr.setTop.apply(this, arguments);
  2387. this.sync();
  2388. return this;
  2389. },
  2390. setLeftTop : function(left, top){
  2391. this.storeLeftTop(left, top);
  2392. supr.setLeftTop.apply(this, arguments);
  2393. this.sync();
  2394. return this;
  2395. },
  2396. setXY : function(xy, a, d, c, e){
  2397. this.fixDisplay();
  2398. this.beforeAction();
  2399. this.storeXY(xy);
  2400. var cb = this.createCB(c);
  2401. supr.setXY.call(this, xy, a, d, cb, e);
  2402. if(!a){
  2403. cb();
  2404. }
  2405. return this;
  2406. },
  2407. // private
  2408. createCB : function(c){
  2409. var el = this;
  2410. return function(){
  2411. el.constrainXY();
  2412. el.sync(true);
  2413. if(c){
  2414. c();
  2415. }
  2416. };
  2417. },
  2418. // overridden Element method
  2419. setX : function(x, a, d, c, e){
  2420. this.setXY([x, this.getY()], a, d, c, e);
  2421. return this;
  2422. },
  2423. // overridden Element method
  2424. setY : function(y, a, d, c, e){
  2425. this.setXY([this.getX(), y], a, d, c, e);
  2426. return this;
  2427. },
  2428. // overridden Element method
  2429. setSize : function(w, h, a, d, c, e){
  2430. this.beforeAction();
  2431. var cb = this.createCB(c);
  2432. supr.setSize.call(this, w, h, a, d, cb, e);
  2433. if(!a){
  2434. cb();
  2435. }
  2436. return this;
  2437. },
  2438. // overridden Element method
  2439. setWidth : function(w, a, d, c, e){
  2440. this.beforeAction();
  2441. var cb = this.createCB(c);
  2442. supr.setWidth.call(this, w, a, d, cb, e);
  2443. if(!a){
  2444. cb();
  2445. }
  2446. return this;
  2447. },
  2448. // overridden Element method
  2449. setHeight : function(h, a, d, c, e){
  2450. this.beforeAction();
  2451. var cb = this.createCB(c);
  2452. supr.setHeight.call(this, h, a, d, cb, e);
  2453. if(!a){
  2454. cb();
  2455. }
  2456. return this;
  2457. },
  2458. // overridden Element method
  2459. setBounds : function(x, y, w, h, a, d, c, e){
  2460. this.beforeAction();
  2461. var cb = this.createCB(c);
  2462. if(!a){
  2463. this.storeXY([x, y]);
  2464. supr.setXY.call(this, [x, y]);
  2465. supr.setSize.call(this, w, h, a, d, cb, e);
  2466. cb();
  2467. }else{
  2468. supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
  2469. }
  2470. return this;
  2471. },
  2472. /**
  2473. * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
  2474. * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
  2475. * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
  2476. * @param {Number} zindex The new z-index to set
  2477. * @return {this} The Layer
  2478. */
  2479. setZIndex : function(zindex){
  2480. this.zindex = zindex;
  2481. this.setStyle('z-index', zindex + 2);
  2482. if(this.shadow){
  2483. this.shadow.setZIndex(zindex + 1);
  2484. }
  2485. if(this.shim){
  2486. this.shim.setStyle('z-index', zindex);
  2487. }
  2488. return this;
  2489. }
  2490. });
  2491. })();
  2492. /**
  2493. * @class Ext.Shadow
  2494. * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
  2495. * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
  2496. * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class.
  2497. * @constructor
  2498. * Create a new Shadow
  2499. * @param {Object} config The config object
  2500. */
  2501. Ext.Shadow = function(config){
  2502. Ext.apply(this, config);
  2503. if(typeof this.mode != "string"){
  2504. this.mode = this.defaultMode;
  2505. }
  2506. var o = this.offset, a = {h: 0};
  2507. var rad = Math.floor(this.offset/2);
  2508. switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
  2509. case "drop":
  2510. a.w = 0;
  2511. a.l = a.t = o;
  2512. a.t -= 1;
  2513. if(Ext.isIE){
  2514. a.l -= this.offset + rad;
  2515. a.t -= this.offset + rad;
  2516. a.w -= rad;
  2517. a.h -= rad;
  2518. a.t += 1;
  2519. }
  2520. break;
  2521. case "sides":
  2522. a.w = (o*2);
  2523. a.l = -o;
  2524. a.t = o-1;
  2525. if(Ext.isIE){
  2526. a.l -= (this.offset - rad);
  2527. a.t -= this.offset + rad;
  2528. a.l += 1;
  2529. a.w -= (this.offset - rad)*2;
  2530. a.w -= rad + 1;
  2531. a.h -= 1;
  2532. }
  2533. break;
  2534. case "frame":
  2535. a.w = a.h = (o*2);
  2536. a.l = a.t = -o;
  2537. a.t += 1;
  2538. a.h -= 2;
  2539. if(Ext.isIE){
  2540. a.l -= (this.offset - rad);
  2541. a.t -= (this.offset - rad);
  2542. a.l += 1;
  2543. a.w -= (this.offset + rad + 1);
  2544. a.h -= (this.offset + rad);
  2545. a.h += 1;
  2546. }
  2547. break;
  2548. };
  2549. this.adjusts = a;
  2550. };
  2551. Ext.Shadow.prototype = {
  2552. /**
  2553. * @cfg {String} mode
  2554. * The shadow display mode. Supports the following options:<div class="mdetail-params"><ul>
  2555. * <li><b><tt>sides</tt></b> : Shadow displays on both sides and bottom only</li>
  2556. * <li><b><tt>frame</tt></b> : Shadow displays equally on all four sides</li>
  2557. * <li><b><tt>drop</tt></b> : Traditional bottom-right drop shadow</li>
  2558. * </ul></div>
  2559. */
  2560. /**
  2561. * @cfg {String} offset
  2562. * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>)
  2563. */
  2564. offset: 4,
  2565. // private
  2566. defaultMode: "drop",
  2567. /**
  2568. * Displays the shadow under the target element
  2569. * @param {Mixed} targetEl The id or element under which the shadow should display
  2570. */
  2571. show : function(target){
  2572. target = Ext.get(target);
  2573. if(!this.el){
  2574. this.el = Ext.Shadow.Pool.pull();
  2575. if(this.el.dom.nextSibling != target.dom){
  2576. this.el.insertBefore(target);
  2577. }
  2578. }
  2579. this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
  2580. if(Ext.isIE){
  2581. this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
  2582. }
  2583. this.realign(
  2584. target.getLeft(true),
  2585. target.getTop(true),
  2586. target.getWidth(),
  2587. target.getHeight()
  2588. );
  2589. this.el.dom.style.display = "block";
  2590. },
  2591. /**
  2592. * Returns true if the shadow is visible, else false
  2593. */
  2594. isVisible : function(){
  2595. return this.el ? true : false;
  2596. },
  2597. /**
  2598. * Direct alignment when values are already available. Show must be called at least once before
  2599. * calling this method to ensure it is initialized.
  2600. * @param {Number} left The target element left position
  2601. * @param {Number} top The target element top position
  2602. * @param {Number} width The target element width
  2603. * @param {Number} height The target element height
  2604. */
  2605. realign : function(l, t, w, h){
  2606. if(!this.el){
  2607. return;
  2608. }
  2609. var a = this.adjusts, d = this.el.dom, s = d.style;
  2610. var iea = 0;
  2611. s.left = (l+a.l)+"px";
  2612. s.top = (t+a.t)+"px";
  2613. var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
  2614. if(s.width != sws || s.height != shs){
  2615. s.width = sws;
  2616. s.height = shs;
  2617. if(!Ext.isIE){
  2618. var cn = d.childNodes;
  2619. var sww = Math.max(0, (sw-12))+"px";
  2620. cn[0].childNodes[1].style.width = sww;
  2621. cn[1].childNodes[1].style.width = sww;
  2622. cn[2].childNodes[1].style.width = sww;
  2623. cn[1].style.height = Math.max(0, (sh-12))+"px";
  2624. }
  2625. }
  2626. },
  2627. /**
  2628. * Hides this shadow
  2629. */
  2630. hide : function(){
  2631. if(this.el){
  2632. this.el.dom.style.display = "none";
  2633. Ext.Shadow.Pool.push(this.el);
  2634. delete this.el;
  2635. }
  2636. },
  2637. /**
  2638. * Adjust the z-index of this shadow
  2639. * @param {Number} zindex The new z-index
  2640. */
  2641. setZIndex : function(z){
  2642. this.zIndex = z;
  2643. if(this.el){
  2644. this.el.setStyle("z-index", z);
  2645. }
  2646. }
  2647. };
  2648. // Private utility class that manages the internal Shadow cache
  2649. Ext.Shadow.Pool = function(){
  2650. var p = [];
  2651. var markup = Ext.isIE ?
  2652. '<div class="x-ie-shadow"></div>' :
  2653. '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
  2654. return {
  2655. pull : function(){
  2656. var sh = p.shift();
  2657. if(!sh){
  2658. sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
  2659. sh.autoBoxAdjust = false;
  2660. }
  2661. return sh;
  2662. },
  2663. push : function(sh){
  2664. p.push(sh);
  2665. }
  2666. };
  2667. }();/**
  2668. * @class Ext.BoxComponent
  2669. * @extends Ext.Component
  2670. * <p>Base class for any {@link Ext.Component Component} that is to be sized as a box, using width and height.</p>
  2671. * <p>BoxComponent provides automatic box model adjustments for sizing and positioning and will work correctly
  2672. * within the Component rendering model.</p>
  2673. * <p>A BoxComponent may be created as a custom Component which encapsulates any HTML element, either a pre-existing
  2674. * element, or one that is created to your specifications at render time. Usually, to participate in layouts,
  2675. * a Component will need to be a <b>Box</b>Component in order to have its width and height managed.</p>
  2676. * <p>To use a pre-existing element as a BoxComponent, configure it so that you preset the <b>el</b> property to the
  2677. * element to reference:<pre><code>
  2678. var pageHeader = new Ext.BoxComponent({
  2679. el: 'my-header-div'
  2680. });</code></pre>
  2681. * This may then be {@link Ext.Container#add added} to a {@link Ext.Container Container} as a child item.</p>
  2682. * <p>To create a BoxComponent based around a HTML element to be created at render time, use the
  2683. * {@link Ext.Component#autoEl autoEl} config option which takes the form of a
  2684. * {@link Ext.DomHelper DomHelper} specification:<pre><code>
  2685. var myImage = new Ext.BoxComponent({
  2686. autoEl: {
  2687. tag: 'img',
  2688. src: '/images/my-image.jpg'
  2689. }
  2690. });</code></pre></p>
  2691. * @constructor
  2692. * @param {Ext.Element/String/Object} config The configuration options.
  2693. * @xtype box
  2694. */
  2695. Ext.BoxComponent = Ext.extend(Ext.Component, {
  2696. // Configs below are used for all Components when rendered by BoxLayout.
  2697. /**
  2698. * @cfg {Number} flex
  2699. * <p><b>Note</b>: this config is only used when this Component is rendered
  2700. * by a Container which has been configured to use a <b>{@link Ext.layout.BoxLayout BoxLayout}.</b>
  2701. * Each child Component with a <code>flex</code> property will be flexed either vertically (by a VBoxLayout)
  2702. * or horizontally (by an HBoxLayout) according to the item's <b>relative</b> <code>flex</code> value
  2703. * compared to the sum of all Components with <code>flex</flex> value specified. Any child items that have
  2704. * either a <code>flex = 0</code> or <code>flex = undefined</code> will not be 'flexed' (the initial size will not be changed).
  2705. */
  2706. // Configs below are used for all Components when rendered by AnchorLayout.
  2707. /**
  2708. * @cfg {String} anchor <p><b>Note</b>: this config is only used when this Component is rendered
  2709. * by a Container which has been configured to use an <b>{@link Ext.layout.AnchorLayout AnchorLayout} (or subclass thereof).</b>
  2710. * based layout manager, for example:<div class="mdetail-params"><ul>
  2711. * <li>{@link Ext.form.FormPanel}</li>
  2712. * <li>specifying <code>layout: 'anchor' // or 'form', or 'absolute'</code></li>
  2713. * </ul></div></p>
  2714. * <p>See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.</p>
  2715. */
  2716. // tabTip config is used when a BoxComponent is a child of a TabPanel
  2717. /**
  2718. * @cfg {String} tabTip
  2719. * <p><b>Note</b>: this config is only used when this BoxComponent is a child item of a TabPanel.</p>
  2720. * A string to be used as innerHTML (html tags are accepted) to show in a tooltip when mousing over
  2721. * the associated tab selector element. {@link Ext.QuickTips}.init()
  2722. * must be called in order for the tips to render.
  2723. */
  2724. // Configs below are used for all Components when rendered by BorderLayout.
  2725. /**
  2726. * @cfg {String} region <p><b>Note</b>: this config is only used when this BoxComponent is rendered
  2727. * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
  2728. * layout manager (e.g. specifying <tt>layout:'border'</tt>).</p><br>
  2729. * <p>See {@link Ext.layout.BorderLayout} also.</p>
  2730. */
  2731. // margins config is used when a BoxComponent is rendered by BorderLayout or BoxLayout.
  2732. /**
  2733. * @cfg {Object} margins <p><b>Note</b>: this config is only used when this BoxComponent is rendered
  2734. * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
  2735. * or one of the two <b>{@link Ext.layout.BoxLayout BoxLayout} subclasses.</b></p>
  2736. * <p>An object containing margins to apply to this BoxComponent in the
  2737. * format:</p><pre><code>
  2738. {
  2739. top: (top margin),
  2740. right: (right margin),
  2741. bottom: (bottom margin),
  2742. left: (left margin)
  2743. }</code></pre>
  2744. * <p>May also be a string containing space-separated, numeric margin values. The order of the
  2745. * sides associated with each value matches the way CSS processes margin values:</p>
  2746. * <p><div class="mdetail-params"><ul>
  2747. * <li>If there is only one value, it applies to all sides.</li>
  2748. * <li>If there are two values, the top and bottom borders are set to the first value and the
  2749. * right and left are set to the second.</li>
  2750. * <li>If there are three values, the top is set to the first value, the left and right are set
  2751. * to the second, and the bottom is set to the third.</li>
  2752. * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
  2753. * </ul></div></p>
  2754. * <p>Defaults to:</p><pre><code>
  2755. * {top:0, right:0, bottom:0, left:0}
  2756. * </code></pre>
  2757. */
  2758. /**
  2759. * @cfg {Number} x
  2760. * The local x (left) coordinate for this component if contained within a positioning container.
  2761. */
  2762. /**
  2763. * @cfg {Number} y
  2764. * The local y (top) coordinate for this component if contained within a positioning container.
  2765. */
  2766. /**
  2767. * @cfg {Number} pageX
  2768. * The page level x coordinate for this component if contained within a positioning container.
  2769. */
  2770. /**
  2771. * @cfg {Number} pageY
  2772. * The page level y coordinate for this component if contained within a positioning container.
  2773. */
  2774. /**
  2775. * @cfg {Number} height
  2776. * The height of this component in pixels (defaults to auto).
  2777. * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
  2778. */
  2779. /**
  2780. * @cfg {Number} width
  2781. * The width of this component in pixels (defaults to auto).
  2782. * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
  2783. */
  2784. /**
  2785. * @cfg {Number} boxMinHeight
  2786. * <p>The minimum value in pixels which this BoxComponent will set its height to.</p>
  2787. * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
  2788. */
  2789. /**
  2790. * @cfg {Number} boxMinWidth
  2791. * <p>The minimum value in pixels which this BoxComponent will set its width to.</p>
  2792. * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
  2793. */
  2794. /**
  2795. * @cfg {Number} boxMaxHeight
  2796. * <p>The maximum value in pixels which this BoxComponent will set its height to.</p>
  2797. * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
  2798. */
  2799. /**
  2800. * @cfg {Number} boxMaxWidth
  2801. * <p>The maximum value in pixels which this BoxComponent will set its width to.</p>
  2802. * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
  2803. */
  2804. /**
  2805. * @cfg {Boolean} autoHeight
  2806. * <p>True to use height:'auto', false to use fixed height (or allow it to be managed by its parent
  2807. * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
  2808. * <p><b>Note</b>: Although many components inherit this config option, not all will
  2809. * function as expected with a height of 'auto'. Setting autoHeight:true means that the
  2810. * browser will manage height based on the element's contents, and that Ext will not manage it at all.</p>
  2811. * <p>If the <i>browser</i> is managing the height, be aware that resizes performed by the browser in response
  2812. * to changes within the structure of the Component cannot be detected. Therefore changes to the height might
  2813. * result in elements needing to be synchronized with the new height. Example:</p><pre><code>
  2814. var w = new Ext.Window({
  2815. title: 'Window',
  2816. width: 600,
  2817. autoHeight: true,
  2818. items: {
  2819. title: 'Collapse Me',
  2820. height: 400,
  2821. collapsible: true,
  2822. border: false,
  2823. listeners: {
  2824. beforecollapse: function() {
  2825. w.el.shadow.hide();
  2826. },
  2827. beforeexpand: function() {
  2828. w.el.shadow.hide();
  2829. },
  2830. collapse: function() {
  2831. w.syncShadow();
  2832. },
  2833. expand: function() {
  2834. w.syncShadow();
  2835. }
  2836. }
  2837. }
  2838. }).show();
  2839. </code></pre>
  2840. */
  2841. /**
  2842. * @cfg {Boolean} autoWidth
  2843. * <p>True to use width:'auto', false to use fixed width (or allow it to be managed by its parent
  2844. * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
  2845. * <p><b>Note</b>: Although many components inherit this config option, not all will
  2846. * function as expected with a width of 'auto'. Setting autoWidth:true means that the
  2847. * browser will manage width based on the element's contents, and that Ext will not manage it at all.</p>
  2848. * <p>If the <i>browser</i> is managing the width, be aware that resizes performed by the browser in response
  2849. * to changes within the structure of the Component cannot be detected. Therefore changes to the width might
  2850. * result in elements needing to be synchronized with the new width. For example, where the target element is:</p><pre><code>
  2851. &lt;div id='grid-container' style='margin-left:25%;width:50%'>&lt;/div>
  2852. </code></pre>
  2853. * A Panel rendered into that target element must listen for browser window resize in order to relay its
  2854. * child items when the browser changes its width:<pre><code>
  2855. var myPanel = new Ext.Panel({
  2856. renderTo: 'grid-container',
  2857. monitorResize: true, // relay on browser resize
  2858. title: 'Panel',
  2859. height: 400,
  2860. autoWidth: true,
  2861. layout: 'hbox',
  2862. layoutConfig: {
  2863. align: 'stretch'
  2864. },
  2865. defaults: {
  2866. flex: 1
  2867. },
  2868. items: [{
  2869. title: 'Box 1',
  2870. }, {
  2871. title: 'Box 2'
  2872. }, {
  2873. title: 'Box 3'
  2874. }],
  2875. });
  2876. </code></pre>
  2877. */
  2878. /**
  2879. * @cfg {Boolean} autoScroll
  2880. * <code>true</code> to use overflow:'auto' on the components layout element and show scroll bars automatically when
  2881. * necessary, <code>false</code> to clip any overflowing content (defaults to <code>false</code>).
  2882. */
  2883. /* // private internal config
  2884. * {Boolean} deferHeight
  2885. * True to defer height calculations to an external component, false to allow this component to set its own
  2886. * height (defaults to false).
  2887. */
  2888. // private
  2889. initComponent : function(){
  2890. Ext.BoxComponent.superclass.initComponent.call(this);
  2891. this.addEvents(
  2892. /**
  2893. * @event resize
  2894. * Fires after the component is resized.
  2895. * @param {Ext.Component} this
  2896. * @param {Number} adjWidth The box-adjusted width that was set
  2897. * @param {Number} adjHeight The box-adjusted height that was set
  2898. * @param {Number} rawWidth The width that was originally specified
  2899. * @param {Number} rawHeight The height that was originally specified
  2900. */
  2901. 'resize',
  2902. /**
  2903. * @event move
  2904. * Fires after the component is moved.
  2905. * @param {Ext.Component} this
  2906. * @param {Number} x The new x position
  2907. * @param {Number} y The new y position
  2908. */
  2909. 'move'
  2910. );
  2911. },
  2912. // private, set in afterRender to signify that the component has been rendered
  2913. boxReady : false,
  2914. // private, used to defer height settings to subclasses
  2915. deferHeight: false,
  2916. /**
  2917. * Sets the width and height of this BoxComponent. This method fires the {@link #resize} event. This method can accept
  2918. * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>.
  2919. * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
  2920. * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
  2921. * <li>A String used to set the CSS width style.</li>
  2922. * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
  2923. * <li><code>undefined</code> to leave the width unchanged.</li>
  2924. * </ul></div>
  2925. * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg).
  2926. * This may be one of:<div class="mdetail-params"><ul>
  2927. * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
  2928. * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
  2929. * <li><code>undefined</code> to leave the height unchanged.</li>
  2930. * </ul></div>
  2931. * @return {Ext.BoxComponent} this
  2932. */
  2933. setSize : function(w, h){
  2934. // support for standard size objects
  2935. if(typeof w == 'object'){
  2936. h = w.height;
  2937. w = w.width;
  2938. }
  2939. if (Ext.isDefined(w) && Ext.isDefined(this.boxMinWidth) && (w < this.boxMinWidth)) {
  2940. w = this.boxMinWidth;
  2941. }
  2942. if (Ext.isDefined(h) && Ext.isDefined(this.boxMinHeight) && (h < this.boxMinHeight)) {
  2943. h = this.boxMinHeight;
  2944. }
  2945. if (Ext.isDefined(w) && Ext.isDefined(this.boxMaxWidth) && (w > this.boxMaxWidth)) {
  2946. w = this.boxMaxWidth;
  2947. }
  2948. if (Ext.isDefined(h) && Ext.isDefined(this.boxMaxHeight) && (h > this.boxMaxHeight)) {
  2949. h = this.boxMaxHeight;
  2950. }
  2951. // not rendered
  2952. if(!this.boxReady){
  2953. this.width = w;
  2954. this.height = h;
  2955. return this;
  2956. }
  2957. // prevent recalcs when not needed
  2958. if(this.cacheSizes !== false && this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
  2959. return this;
  2960. }
  2961. this.lastSize = {width: w, height: h};
  2962. var adj = this.adjustSize(w, h),
  2963. aw = adj.width,
  2964. ah = adj.height,
  2965. rz;
  2966. if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
  2967. rz = this.getResizeEl();
  2968. if(!this.deferHeight && aw !== undefined && ah !== undefined){
  2969. rz.setSize(aw, ah);
  2970. }else if(!this.deferHeight && ah !== undefined){
  2971. rz.setHeight(ah);
  2972. }else if(aw !== undefined){
  2973. rz.setWidth(aw);
  2974. }
  2975. this.onResize(aw, ah, w, h);
  2976. this.fireEvent('resize', this, aw, ah, w, h);
  2977. }
  2978. return this;
  2979. },
  2980. /**
  2981. * Sets the width of the component. This method fires the {@link #resize} event.
  2982. * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
  2983. * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).</li>
  2984. * <li>A String used to set the CSS width style.</li>
  2985. * </ul></div>
  2986. * @return {Ext.BoxComponent} this
  2987. */
  2988. setWidth : function(width){
  2989. return this.setSize(width);
  2990. },
  2991. /**
  2992. * Sets the height of the component. This method fires the {@link #resize} event.
  2993. * @param {Mixed} height The new height to set. This may be one of:<div class="mdetail-params"><ul>
  2994. * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).</li>
  2995. * <li>A String used to set the CSS height style.</li>
  2996. * <li><i>undefined</i> to leave the height unchanged.</li>
  2997. * </ul></div>
  2998. * @return {Ext.BoxComponent} this
  2999. */
  3000. setHeight : function(height){
  3001. return this.setSize(undefined, height);
  3002. },
  3003. /**
  3004. * Gets the current size of the component's underlying element.
  3005. * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
  3006. */
  3007. getSize : function(){
  3008. return this.getResizeEl().getSize();
  3009. },
  3010. /**
  3011. * Gets the current width of the component's underlying element.
  3012. * @return {Number}
  3013. */
  3014. getWidth : function(){
  3015. return this.getResizeEl().getWidth();
  3016. },
  3017. /**
  3018. * Gets the current height of the component's underlying element.
  3019. * @return {Number}
  3020. */
  3021. getHeight : function(){
  3022. return this.getResizeEl().getHeight();
  3023. },
  3024. /**
  3025. * Gets the current size of the component's underlying element, including space taken by its margins.
  3026. * @return {Object} An object containing the element's size {width: (element width + left/right margins), height: (element height + top/bottom margins)}
  3027. */
  3028. getOuterSize : function(){
  3029. var el = this.getResizeEl();
  3030. return {width: el.getWidth() + el.getMargins('lr'),
  3031. height: el.getHeight() + el.getMargins('tb')};
  3032. },
  3033. /**
  3034. * Gets the current XY position of the component's underlying element.
  3035. * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
  3036. * @return {Array} The XY position of the element (e.g., [100, 200])
  3037. */
  3038. getPosition : function(local){
  3039. var el = this.getPositionEl();
  3040. if(local === true){
  3041. return [el.getLeft(true), el.getTop(true)];
  3042. }
  3043. return this.xy || el.getXY();
  3044. },
  3045. /**
  3046. * Gets the current box measurements of the component's underlying element.
  3047. * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
  3048. * @return {Object} box An object in the format {x, y, width, height}
  3049. */
  3050. getBox : function(local){
  3051. var pos = this.getPosition(local);
  3052. var s = this.getSize();
  3053. s.x = pos[0];
  3054. s.y = pos[1];
  3055. return s;
  3056. },
  3057. /**
  3058. * Sets the current box measurements of the component's underlying element.
  3059. * @param {Object} box An object in the format {x, y, width, height}
  3060. * @return {Ext.BoxComponent} this
  3061. */
  3062. updateBox : function(box){
  3063. this.setSize(box.width, box.height);
  3064. this.setPagePosition(box.x, box.y);
  3065. return this;
  3066. },
  3067. /**
  3068. * <p>Returns the outermost Element of this Component which defines the Components overall size.</p>
  3069. * <p><i>Usually</i> this will return the same Element as <code>{@link #getEl}</code>,
  3070. * but in some cases, a Component may have some more wrapping Elements around its main
  3071. * active Element.</p>
  3072. * <p>An example is a ComboBox. It is encased in a <i>wrapping</i> Element which
  3073. * contains both the <code>&lt;input></code> Element (which is what would be returned
  3074. * by its <code>{@link #getEl}</code> method, <i>and</i> the trigger button Element.
  3075. * This Element is returned as the <code>resizeEl</code>.
  3076. * @return {Ext.Element} The Element which is to be resized by size managing layouts.
  3077. */
  3078. getResizeEl : function(){
  3079. return this.resizeEl || this.el;
  3080. },
  3081. /**
  3082. * Sets the overflow on the content element of the component.
  3083. * @param {Boolean} scroll True to allow the Component to auto scroll.
  3084. * @return {Ext.BoxComponent} this
  3085. */
  3086. setAutoScroll : function(scroll){
  3087. if(this.rendered){
  3088. this.getContentTarget().setOverflow(scroll ? 'auto' : '');
  3089. }
  3090. this.autoScroll = scroll;
  3091. return this;
  3092. },
  3093. /**
  3094. * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
  3095. * This method fires the {@link #move} event.
  3096. * @param {Number} left The new left
  3097. * @param {Number} top The new top
  3098. * @return {Ext.BoxComponent} this
  3099. */
  3100. setPosition : function(x, y){
  3101. if(x && typeof x[1] == 'number'){
  3102. y = x[1];
  3103. x = x[0];
  3104. }
  3105. this.x = x;
  3106. this.y = y;
  3107. if(!this.boxReady){
  3108. return this;
  3109. }
  3110. var adj = this.adjustPosition(x, y);
  3111. var ax = adj.x, ay = adj.y;
  3112. var el = this.getPositionEl();
  3113. if(ax !== undefined || ay !== undefined){
  3114. if(ax !== undefined && ay !== undefined){
  3115. el.setLeftTop(ax, ay);
  3116. }else if(ax !== undefined){
  3117. el.setLeft(ax);
  3118. }else if(ay !== undefined){
  3119. el.setTop(ay);
  3120. }
  3121. this.onPosition(ax, ay);
  3122. this.fireEvent('move', this, ax, ay);
  3123. }
  3124. return this;
  3125. },
  3126. /**
  3127. * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
  3128. * This method fires the {@link #move} event.
  3129. * @param {Number} x The new x position
  3130. * @param {Number} y The new y position
  3131. * @return {Ext.BoxComponent} this
  3132. */
  3133. setPagePosition : function(x, y){
  3134. if(x && typeof x[1] == 'number'){
  3135. y = x[1];
  3136. x = x[0];
  3137. }
  3138. this.pageX = x;
  3139. this.pageY = y;
  3140. if(!this.boxReady){
  3141. return;
  3142. }
  3143. if(x === undefined || y === undefined){ // cannot translate undefined points
  3144. return;
  3145. }
  3146. var p = this.getPositionEl().translatePoints(x, y);
  3147. this.setPosition(p.left, p.top);
  3148. return this;
  3149. },
  3150. // private
  3151. afterRender : function(){
  3152. Ext.BoxComponent.superclass.afterRender.call(this);
  3153. if(this.resizeEl){
  3154. this.resizeEl = Ext.get(this.resizeEl);
  3155. }
  3156. if(this.positionEl){
  3157. this.positionEl = Ext.get(this.positionEl);
  3158. }
  3159. this.boxReady = true;
  3160. Ext.isDefined(this.autoScroll) && this.setAutoScroll(this.autoScroll);
  3161. this.setSize(this.width, this.height);
  3162. if(this.x || this.y){
  3163. this.setPosition(this.x, this.y);
  3164. }else if(this.pageX || this.pageY){
  3165. this.setPagePosition(this.pageX, this.pageY);
  3166. }
  3167. },
  3168. /**
  3169. * Force the component's size to recalculate based on the underlying element's current height and width.
  3170. * @return {Ext.BoxComponent} this
  3171. */
  3172. syncSize : function(){
  3173. delete this.lastSize;
  3174. this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight());
  3175. return this;
  3176. },
  3177. /* // protected
  3178. * Called after the component is resized, this method is empty by default but can be implemented by any
  3179. * subclass that needs to perform custom logic after a resize occurs.
  3180. * @param {Number} adjWidth The box-adjusted width that was set
  3181. * @param {Number} adjHeight The box-adjusted height that was set
  3182. * @param {Number} rawWidth The width that was originally specified
  3183. * @param {Number} rawHeight The height that was originally specified
  3184. */
  3185. onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
  3186. },
  3187. /* // protected
  3188. * Called after the component is moved, this method is empty by default but can be implemented by any
  3189. * subclass that needs to perform custom logic after a move occurs.
  3190. * @param {Number} x The new x position
  3191. * @param {Number} y The new y position
  3192. */
  3193. onPosition : function(x, y){
  3194. },
  3195. // private
  3196. adjustSize : function(w, h){
  3197. if(this.autoWidth){
  3198. w = 'auto';
  3199. }
  3200. if(this.autoHeight){
  3201. h = 'auto';
  3202. }
  3203. return {width : w, height: h};
  3204. },
  3205. // private
  3206. adjustPosition : function(x, y){
  3207. return {x : x, y: y};
  3208. }
  3209. });
  3210. Ext.reg('box', Ext.BoxComponent);
  3211. /**
  3212. * @class Ext.Spacer
  3213. * @extends Ext.BoxComponent
  3214. * <p>Used to provide a sizable space in a layout.</p>
  3215. * @constructor
  3216. * @param {Object} config
  3217. */
  3218. Ext.Spacer = Ext.extend(Ext.BoxComponent, {
  3219. autoEl:'div'
  3220. });
  3221. Ext.reg('spacer', Ext.Spacer);/**
  3222. * @class Ext.SplitBar
  3223. * @extends Ext.util.Observable
  3224. * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
  3225. * <br><br>
  3226. * Usage:
  3227. * <pre><code>
  3228. var split = new Ext.SplitBar("elementToDrag", "elementToSize",
  3229. Ext.SplitBar.HORIZONTAL, Ext.SplitBar.LEFT);
  3230. split.setAdapter(new Ext.SplitBar.AbsoluteLayoutAdapter("container"));
  3231. split.minSize = 100;
  3232. split.maxSize = 600;
  3233. split.animate = true;
  3234. split.on('moved', splitterMoved);
  3235. </code></pre>
  3236. * @constructor
  3237. * Create a new SplitBar
  3238. * @param {Mixed} dragElement The element to be dragged and act as the SplitBar.
  3239. * @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged
  3240. * @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
  3241. * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
  3242. Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
  3243. position of the SplitBar).
  3244. */
  3245. Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
  3246. /** @private */
  3247. this.el = Ext.get(dragElement, true);
  3248. this.el.dom.unselectable = "on";
  3249. /** @private */
  3250. this.resizingEl = Ext.get(resizingElement, true);
  3251. /**
  3252. * @private
  3253. * The orientation of the split. Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
  3254. * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
  3255. * @type Number
  3256. */
  3257. this.orientation = orientation || Ext.SplitBar.HORIZONTAL;
  3258. /**
  3259. * The increment, in pixels by which to move this SplitBar. When <i>undefined</i>, the SplitBar moves smoothly.
  3260. * @type Number
  3261. * @property tickSize
  3262. */
  3263. /**
  3264. * The minimum size of the resizing element. (Defaults to 0)
  3265. * @type Number
  3266. */
  3267. this.minSize = 0;
  3268. /**
  3269. * The maximum size of the resizing element. (Defaults to 2000)
  3270. * @type Number
  3271. */
  3272. this.maxSize = 2000;
  3273. /**
  3274. * Whether to animate the transition to the new size
  3275. * @type Boolean
  3276. */
  3277. this.animate = false;
  3278. /**
  3279. * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
  3280. * @type Boolean
  3281. */
  3282. this.useShim = false;
  3283. /** @private */
  3284. this.shim = null;
  3285. if(!existingProxy){
  3286. /** @private */
  3287. this.proxy = Ext.SplitBar.createProxy(this.orientation);
  3288. }else{
  3289. this.proxy = Ext.get(existingProxy).dom;
  3290. }
  3291. /** @private */
  3292. this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
  3293. /** @private */
  3294. this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
  3295. /** @private */
  3296. this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
  3297. /** @private */
  3298. this.dragSpecs = {};
  3299. /**
  3300. * @private The adapter to use to positon and resize elements
  3301. */
  3302. this.adapter = new Ext.SplitBar.BasicLayoutAdapter();
  3303. this.adapter.init(this);
  3304. if(this.orientation == Ext.SplitBar.HORIZONTAL){
  3305. /** @private */
  3306. this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT);
  3307. this.el.addClass("x-splitbar-h");
  3308. }else{
  3309. /** @private */
  3310. this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM);
  3311. this.el.addClass("x-splitbar-v");
  3312. }
  3313. this.addEvents(
  3314. /**
  3315. * @event resize
  3316. * Fires when the splitter is moved (alias for {@link #moved})
  3317. * @param {Ext.SplitBar} this
  3318. * @param {Number} newSize the new width or height
  3319. */
  3320. "resize",
  3321. /**
  3322. * @event moved
  3323. * Fires when the splitter is moved
  3324. * @param {Ext.SplitBar} this
  3325. * @param {Number} newSize the new width or height
  3326. */
  3327. "moved",
  3328. /**
  3329. * @event beforeresize
  3330. * Fires before the splitter is dragged
  3331. * @param {Ext.SplitBar} this
  3332. */
  3333. "beforeresize",
  3334. "beforeapply"
  3335. );
  3336. Ext.SplitBar.superclass.constructor.call(this);
  3337. };
  3338. Ext.extend(Ext.SplitBar, Ext.util.Observable, {
  3339. onStartProxyDrag : function(x, y){
  3340. this.fireEvent("beforeresize", this);
  3341. this.overlay = Ext.DomHelper.append(document.body, {cls: "x-drag-overlay", html: "&#160;"}, true);
  3342. this.overlay.unselectable();
  3343. this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
  3344. this.overlay.show();
  3345. Ext.get(this.proxy).setDisplayed("block");
  3346. var size = this.adapter.getElementSize(this);
  3347. this.activeMinSize = this.getMinimumSize();
  3348. this.activeMaxSize = this.getMaximumSize();
  3349. var c1 = size - this.activeMinSize;
  3350. var c2 = Math.max(this.activeMaxSize - size, 0);
  3351. if(this.orientation == Ext.SplitBar.HORIZONTAL){
  3352. this.dd.resetConstraints();
  3353. this.dd.setXConstraint(
  3354. this.placement == Ext.SplitBar.LEFT ? c1 : c2,
  3355. this.placement == Ext.SplitBar.LEFT ? c2 : c1,
  3356. this.tickSize
  3357. );
  3358. this.dd.setYConstraint(0, 0);
  3359. }else{
  3360. this.dd.resetConstraints();
  3361. this.dd.setXConstraint(0, 0);
  3362. this.dd.setYConstraint(
  3363. this.placement == Ext.SplitBar.TOP ? c1 : c2,
  3364. this.placement == Ext.SplitBar.TOP ? c2 : c1,
  3365. this.tickSize
  3366. );
  3367. }
  3368. this.dragSpecs.startSize = size;
  3369. this.dragSpecs.startPoint = [x, y];
  3370. Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
  3371. },
  3372. /**
  3373. * @private Called after the drag operation by the DDProxy
  3374. */
  3375. onEndProxyDrag : function(e){
  3376. Ext.get(this.proxy).setDisplayed(false);
  3377. var endPoint = Ext.lib.Event.getXY(e);
  3378. if(this.overlay){
  3379. Ext.destroy(this.overlay);
  3380. delete this.overlay;
  3381. }
  3382. var newSize;
  3383. if(this.orientation == Ext.SplitBar.HORIZONTAL){
  3384. newSize = this.dragSpecs.startSize +
  3385. (this.placement == Ext.SplitBar.LEFT ?
  3386. endPoint[0] - this.dragSpecs.startPoint[0] :
  3387. this.dragSpecs.startPoint[0] - endPoint[0]
  3388. );
  3389. }else{
  3390. newSize = this.dragSpecs.startSize +
  3391. (this.placement == Ext.SplitBar.TOP ?
  3392. endPoint[1] - this.dragSpecs.startPoint[1] :
  3393. this.dragSpecs.startPoint[1] - endPoint[1]
  3394. );
  3395. }
  3396. newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
  3397. if(newSize != this.dragSpecs.startSize){
  3398. if(this.fireEvent('beforeapply', this, newSize) !== false){
  3399. this.adapter.setElementSize(this, newSize);
  3400. this.fireEvent("moved", this, newSize);
  3401. this.fireEvent("resize", this, newSize);
  3402. }
  3403. }
  3404. },
  3405. /**
  3406. * Get the adapter this SplitBar uses
  3407. * @return The adapter object
  3408. */
  3409. getAdapter : function(){
  3410. return this.adapter;
  3411. },
  3412. /**
  3413. * Set the adapter this SplitBar uses
  3414. * @param {Object} adapter A SplitBar adapter object
  3415. */
  3416. setAdapter : function(adapter){
  3417. this.adapter = adapter;
  3418. this.adapter.init(this);
  3419. },
  3420. /**
  3421. * Gets the minimum size for the resizing element
  3422. * @return {Number} The minimum size
  3423. */
  3424. getMinimumSize : function(){
  3425. return this.minSize;
  3426. },
  3427. /**
  3428. * Sets the minimum size for the resizing element
  3429. * @param {Number} minSize The minimum size
  3430. */
  3431. setMinimumSize : function(minSize){
  3432. this.minSize = minSize;
  3433. },
  3434. /**
  3435. * Gets the maximum size for the resizing element
  3436. * @return {Number} The maximum size
  3437. */
  3438. getMaximumSize : function(){
  3439. return this.maxSize;
  3440. },
  3441. /**
  3442. * Sets the maximum size for the resizing element
  3443. * @param {Number} maxSize The maximum size
  3444. */
  3445. setMaximumSize : function(maxSize){
  3446. this.maxSize = maxSize;
  3447. },
  3448. /**
  3449. * Sets the initialize size for the resizing element
  3450. * @param {Number} size The initial size
  3451. */
  3452. setCurrentSize : function(size){
  3453. var oldAnimate = this.animate;
  3454. this.animate = false;
  3455. this.adapter.setElementSize(this, size);
  3456. this.animate = oldAnimate;
  3457. },
  3458. /**
  3459. * Destroy this splitbar.
  3460. * @param {Boolean} removeEl True to remove the element
  3461. */
  3462. destroy : function(removeEl){
  3463. Ext.destroy(this.shim, Ext.get(this.proxy));
  3464. this.dd.unreg();
  3465. if(removeEl){
  3466. this.el.remove();
  3467. }
  3468. this.purgeListeners();
  3469. }
  3470. });
  3471. /**
  3472. * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
  3473. */
  3474. Ext.SplitBar.createProxy = function(dir){
  3475. var proxy = new Ext.Element(document.createElement("div"));
  3476. document.body.appendChild(proxy.dom);
  3477. proxy.unselectable();
  3478. var cls = 'x-splitbar-proxy';
  3479. proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
  3480. return proxy.dom;
  3481. };
  3482. /**
  3483. * @class Ext.SplitBar.BasicLayoutAdapter
  3484. * Default Adapter. It assumes the splitter and resizing element are not positioned
  3485. * elements and only gets/sets the width of the element. Generally used for table based layouts.
  3486. */
  3487. Ext.SplitBar.BasicLayoutAdapter = function(){
  3488. };
  3489. Ext.SplitBar.BasicLayoutAdapter.prototype = {
  3490. // do nothing for now
  3491. init : function(s){
  3492. },
  3493. /**
  3494. * Called before drag operations to get the current size of the resizing element.
  3495. * @param {Ext.SplitBar} s The SplitBar using this adapter
  3496. */
  3497. getElementSize : function(s){
  3498. if(s.orientation == Ext.SplitBar.HORIZONTAL){
  3499. return s.resizingEl.getWidth();
  3500. }else{
  3501. return s.resizingEl.getHeight();
  3502. }
  3503. },
  3504. /**
  3505. * Called after drag operations to set the size of the resizing element.
  3506. * @param {Ext.SplitBar} s The SplitBar using this adapter
  3507. * @param {Number} newSize The new size to set
  3508. * @param {Function} onComplete A function to be invoked when resizing is complete
  3509. */
  3510. setElementSize : function(s, newSize, onComplete){
  3511. if(s.orientation == Ext.SplitBar.HORIZONTAL){
  3512. if(!s.animate){
  3513. s.resizingEl.setWidth(newSize);
  3514. if(onComplete){
  3515. onComplete(s, newSize);
  3516. }
  3517. }else{
  3518. s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
  3519. }
  3520. }else{
  3521. if(!s.animate){
  3522. s.resizingEl.setHeight(newSize);
  3523. if(onComplete){
  3524. onComplete(s, newSize);
  3525. }
  3526. }else{
  3527. s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
  3528. }
  3529. }
  3530. }
  3531. };
  3532. /**
  3533. *@class Ext.SplitBar.AbsoluteLayoutAdapter
  3534. * @extends Ext.SplitBar.BasicLayoutAdapter
  3535. * Adapter that moves the splitter element to align with the resized sizing element.
  3536. * Used with an absolute positioned SplitBar.
  3537. * @param {Mixed} container The container that wraps around the absolute positioned content. If it's
  3538. * document.body, make sure you assign an id to the body element.
  3539. */
  3540. Ext.SplitBar.AbsoluteLayoutAdapter = function(container){
  3541. this.basic = new Ext.SplitBar.BasicLayoutAdapter();
  3542. this.container = Ext.get(container);
  3543. };
  3544. Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
  3545. init : function(s){
  3546. this.basic.init(s);
  3547. },
  3548. getElementSize : function(s){
  3549. return this.basic.getElementSize(s);
  3550. },
  3551. setElementSize : function(s, newSize, onComplete){
  3552. this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
  3553. },
  3554. moveSplitter : function(s){
  3555. var yes = Ext.SplitBar;
  3556. switch(s.placement){
  3557. case yes.LEFT:
  3558. s.el.setX(s.resizingEl.getRight());
  3559. break;
  3560. case yes.RIGHT:
  3561. s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
  3562. break;
  3563. case yes.TOP:
  3564. s.el.setY(s.resizingEl.getBottom());
  3565. break;
  3566. case yes.BOTTOM:
  3567. s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
  3568. break;
  3569. }
  3570. }
  3571. };
  3572. /**
  3573. * Orientation constant - Create a vertical SplitBar
  3574. * @static
  3575. * @type Number
  3576. */
  3577. Ext.SplitBar.VERTICAL = 1;
  3578. /**
  3579. * Orientation constant - Create a horizontal SplitBar
  3580. * @static
  3581. * @type Number
  3582. */
  3583. Ext.SplitBar.HORIZONTAL = 2;
  3584. /**
  3585. * Placement constant - The resizing element is to the left of the splitter element
  3586. * @static
  3587. * @type Number
  3588. */
  3589. Ext.SplitBar.LEFT = 1;
  3590. /**
  3591. * Placement constant - The resizing element is to the right of the splitter element
  3592. * @static
  3593. * @type Number
  3594. */
  3595. Ext.SplitBar.RIGHT = 2;
  3596. /**
  3597. * Placement constant - The resizing element is positioned above the splitter element
  3598. * @static
  3599. * @type Number
  3600. */
  3601. Ext.SplitBar.TOP = 3;
  3602. /**
  3603. * Placement constant - The resizing element is positioned under splitter element
  3604. * @static
  3605. * @type Number
  3606. */
  3607. Ext.SplitBar.BOTTOM = 4;
  3608. /**
  3609. * @class Ext.Container
  3610. * @extends Ext.BoxComponent
  3611. * <p>Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the
  3612. * basic behavior of containing items, namely adding, inserting and removing items.</p>
  3613. *
  3614. * <p>The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}.
  3615. * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
  3616. * Container to be encapsulated by an HTML element to your specifications by using the
  3617. * <code><b>{@link Ext.Component#autoEl autoEl}</b></code> config option. This is a useful technique when creating
  3618. * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels}
  3619. * for example.</p>
  3620. *
  3621. * <p>The code below illustrates both how to explicitly create a Container, and how to implicitly
  3622. * create one using the <b><code>'container'</code></b> xtype:<pre><code>
  3623. // explicitly create a Container
  3624. var embeddedColumns = new Ext.Container({
  3625. autoEl: 'div', // This is the default
  3626. layout: 'column',
  3627. defaults: {
  3628. // implicitly create Container by specifying xtype
  3629. xtype: 'container',
  3630. autoEl: 'div', // This is the default.
  3631. layout: 'form',
  3632. columnWidth: 0.5,
  3633. style: {
  3634. padding: '10px'
  3635. }
  3636. },
  3637. // The two items below will be Ext.Containers, each encapsulated by a &lt;DIV> element.
  3638. items: [{
  3639. items: {
  3640. xtype: 'datefield',
  3641. name: 'startDate',
  3642. fieldLabel: 'Start date'
  3643. }
  3644. }, {
  3645. items: {
  3646. xtype: 'datefield',
  3647. name: 'endDate',
  3648. fieldLabel: 'End date'
  3649. }
  3650. }]
  3651. });</code></pre></p>
  3652. *
  3653. * <p><u><b>Layout</b></u></p>
  3654. * <p>Container classes delegate the rendering of child Components to a layout
  3655. * manager class which must be configured into the Container using the
  3656. * <code><b>{@link #layout}</b></code> configuration property.</p>
  3657. * <p>When either specifying child <code>{@link #items}</code> of a Container,
  3658. * or dynamically {@link #add adding} Components to a Container, remember to
  3659. * consider how you wish the Container to arrange those child elements, and
  3660. * whether those child elements need to be sized using one of Ext's built-in
  3661. * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the
  3662. * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only
  3663. * renders child components, appending them one after the other inside the
  3664. * Container, and <b>does not apply any sizing</b> at all.</p>
  3665. * <p>A common mistake is when a developer neglects to specify a
  3666. * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
  3667. * TreePanels are added to Containers for which no <code><b>{@link #layout}</b></code>
  3668. * has been specified). If a Container is left to use the default
  3669. * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its
  3670. * child components will be resized, or changed in any way when the Container
  3671. * is resized.</p>
  3672. * <p>Certain layout managers allow dynamic addition of child components.
  3673. * Those that do include {@link Ext.layout.CardLayout},
  3674. * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and
  3675. * {@link Ext.layout.TableLayout}. For example:<pre><code>
  3676. // Create the GridPanel.
  3677. var myNewGrid = new Ext.grid.GridPanel({
  3678. store: myStore,
  3679. columns: myColumnModel,
  3680. title: 'Results', // the title becomes the title of the tab
  3681. });
  3682. myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
  3683. myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
  3684. * </code></pre></p>
  3685. * <p>The example above adds a newly created GridPanel to a TabPanel. Note that
  3686. * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which
  3687. * means all its child items are sized to {@link Ext.layout.FitLayout fit}
  3688. * exactly into its client area.
  3689. * <p><b><u>Overnesting is a common problem</u></b>.
  3690. * An example of overnesting occurs when a GridPanel is added to a TabPanel
  3691. * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
  3692. * <code><b>{@link #layout}</b></code> specified) and then add that wrapping Panel
  3693. * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
  3694. * Component which can be added directly to a Container. If the wrapping Panel
  3695. * has no <code><b>{@link #layout}</b></code> configuration, then the overnested
  3696. * GridPanel will not be sized as expected.<p>
  3697. *
  3698. * <p><u><b>Adding via remote configuration</b></u></p>
  3699. *
  3700. * <p>A server side script can be used to add Components which are generated dynamically on the server.
  3701. * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
  3702. * based on certain parameters:
  3703. * </p><pre><code>
  3704. // execute an Ajax request to invoke server side script:
  3705. Ext.Ajax.request({
  3706. url: 'gen-invoice-grid.php',
  3707. // send additional parameters to instruct server script
  3708. params: {
  3709. startDate: Ext.getCmp('start-date').getValue(),
  3710. endDate: Ext.getCmp('end-date').getValue()
  3711. },
  3712. // process the response object to add it to the TabPanel:
  3713. success: function(xhr) {
  3714. var newComponent = eval(xhr.responseText); // see discussion below
  3715. myTabPanel.add(newComponent); // add the component to the TabPanel
  3716. myTabPanel.setActiveTab(newComponent);
  3717. },
  3718. failure: function() {
  3719. Ext.Msg.alert("Grid create failed", "Server communication failure");
  3720. }
  3721. });
  3722. </code></pre>
  3723. * <p>The server script needs to return an executable Javascript statement which, when processed
  3724. * using <code>eval()</code>, will return either a config object with an {@link Ext.Component#xtype xtype},
  3725. * or an instantiated Component. The server might return this for example:</p><pre><code>
  3726. (function() {
  3727. function formatDate(value){
  3728. return value ? value.dateFormat('M d, Y') : '';
  3729. };
  3730. var store = new Ext.data.Store({
  3731. url: 'get-invoice-data.php',
  3732. baseParams: {
  3733. startDate: '01/01/2008',
  3734. endDate: '01/31/2008'
  3735. },
  3736. reader: new Ext.data.JsonReader({
  3737. record: 'transaction',
  3738. idProperty: 'id',
  3739. totalRecords: 'total'
  3740. }, [
  3741. 'customer',
  3742. 'invNo',
  3743. {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
  3744. {name: 'value', type: 'float'}
  3745. ])
  3746. });
  3747. var grid = new Ext.grid.GridPanel({
  3748. title: 'Invoice Report',
  3749. bbar: new Ext.PagingToolbar(store),
  3750. store: store,
  3751. columns: [
  3752. {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
  3753. {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
  3754. {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
  3755. {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
  3756. ],
  3757. });
  3758. store.load();
  3759. return grid; // return instantiated component
  3760. })();
  3761. </code></pre>
  3762. * <p>When the above code fragment is passed through the <code>eval</code> function in the success handler
  3763. * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function
  3764. * runs, and returns the instantiated grid component.</p>
  3765. * <p>Note: since the code above is <i>generated</i> by a server script, the <code>baseParams</code> for
  3766. * the Store, the metadata to allow generation of the Record layout, and the ColumnModel
  3767. * can all be generated into the code since these are all known on the server.</p>
  3768. *
  3769. * @xtype container
  3770. */
  3771. Ext.Container = Ext.extend(Ext.BoxComponent, {
  3772. /**
  3773. * @cfg {Boolean} monitorResize
  3774. * True to automatically monitor window resize events to handle anything that is sensitive to the current size
  3775. * of the viewport. This value is typically managed by the chosen <code>{@link #layout}</code> and should not need
  3776. * to be set manually.
  3777. */
  3778. /**
  3779. * @cfg {String/Object} layout
  3780. * <p><b>*Important</b>: In order for child items to be correctly sized and
  3781. * positioned, typically a layout manager <b>must</b> be specified through
  3782. * the <code>layout</code> configuration option.</p>
  3783. * <br><p>The sizing and positioning of child {@link items} is the responsibility of
  3784. * the Container's layout manager which creates and manages the type of layout
  3785. * you have in mind. For example:</p><pre><code>
  3786. new Ext.Window({
  3787. width:300, height: 300,
  3788. layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
  3789. items: [{
  3790. title: 'Panel inside a Window'
  3791. }]
  3792. }).show();
  3793. * </code></pre>
  3794. * <p>If the {@link #layout} configuration is not explicitly specified for
  3795. * a general purpose container (e.g. Container or Panel) the
  3796. * {@link Ext.layout.ContainerLayout default layout manager} will be used
  3797. * which does nothing but render child components sequentially into the
  3798. * Container (no sizing or positioning will be performed in this situation).
  3799. * Some container classes implicitly specify a default layout
  3800. * (e.g. FormPanel specifies <code>layout:'form'</code>). Other specific
  3801. * purpose classes internally specify/manage their internal layout (e.g.
  3802. * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).</p>
  3803. * <br><p><b><code>layout</code></b> may be specified as either as an Object or
  3804. * as a String:</p><div><ul class="mdetail-params">
  3805. *
  3806. * <li><u>Specify as an Object</u></li>
  3807. * <div><ul class="mdetail-params">
  3808. * <li>Example usage:</li>
  3809. <pre><code>
  3810. layout: {
  3811. type: 'vbox',
  3812. padding: '5',
  3813. align: 'left'
  3814. }
  3815. </code></pre>
  3816. *
  3817. * <li><code><b>type</b></code></li>
  3818. * <br/><p>The layout type to be used for this container. If not specified,
  3819. * a default {@link Ext.layout.ContainerLayout} will be created and used.</p>
  3820. * <br/><p>Valid layout <code>type</code> values are:</p>
  3821. * <div class="sub-desc"><ul class="mdetail-params">
  3822. * <li><code><b>{@link Ext.layout.AbsoluteLayout absolute}</b></code></li>
  3823. * <li><code><b>{@link Ext.layout.AccordionLayout accordion}</b></code></li>
  3824. * <li><code><b>{@link Ext.layout.AnchorLayout anchor}</b></code></li>
  3825. * <li><code><b>{@link Ext.layout.ContainerLayout auto}</b></code> &nbsp;&nbsp;&nbsp; <b>Default</b></li>
  3826. * <li><code><b>{@link Ext.layout.BorderLayout border}</b></code></li>
  3827. * <li><code><b>{@link Ext.layout.CardLayout card}</b></code></li>
  3828. * <li><code><b>{@link Ext.layout.ColumnLayout column}</b></code></li>
  3829. * <li><code><b>{@link Ext.layout.FitLayout fit}</b></code></li>
  3830. * <li><code><b>{@link Ext.layout.FormLayout form}</b></code></li>
  3831. * <li><code><b>{@link Ext.layout.HBoxLayout hbox}</b></code></li>
  3832. * <li><code><b>{@link Ext.layout.MenuLayout menu}</b></code></li>
  3833. * <li><code><b>{@link Ext.layout.TableLayout table}</b></code></li>
  3834. * <li><code><b>{@link Ext.layout.ToolbarLayout toolbar}</b></code></li>
  3835. * <li><code><b>{@link Ext.layout.VBoxLayout vbox}</b></code></li>
  3836. * </ul></div>
  3837. *
  3838. * <li>Layout specific configuration properties</li>
  3839. * <br/><p>Additional layout specific configuration properties may also be
  3840. * specified. For complete details regarding the valid config options for
  3841. * each layout type, see the layout class corresponding to the <code>type</code>
  3842. * specified.</p>
  3843. *
  3844. * </ul></div>
  3845. *
  3846. * <li><u>Specify as a String</u></li>
  3847. * <div><ul class="mdetail-params">
  3848. * <li>Example usage:</li>
  3849. <pre><code>
  3850. layout: 'vbox',
  3851. layoutConfig: {
  3852. padding: '5',
  3853. align: 'left'
  3854. }
  3855. </code></pre>
  3856. * <li><code><b>layout</b></code></li>
  3857. * <br/><p>The layout <code>type</code> to be used for this container (see list
  3858. * of valid layout type values above).</p><br/>
  3859. * <li><code><b>{@link #layoutConfig}</b></code></li>
  3860. * <br/><p>Additional layout specific configuration properties. For complete
  3861. * details regarding the valid config options for each layout type, see the
  3862. * layout class corresponding to the <code>layout</code> specified.</p>
  3863. * </ul></div></ul></div>
  3864. */
  3865. /**
  3866. * @cfg {Object} layoutConfig
  3867. * This is a config object containing properties specific to the chosen
  3868. * <b><code>{@link #layout}</code></b> if <b><code>{@link #layout}</code></b>
  3869. * has been specified as a <i>string</i>.</p>
  3870. */
  3871. /**
  3872. * @cfg {Boolean/Number} bufferResize
  3873. * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
  3874. * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
  3875. * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to <code>50</code>.
  3876. */
  3877. bufferResize: 50,
  3878. /**
  3879. * @cfg {String/Number} activeItem
  3880. * A string component id or the numeric index of the component that should be initially activated within the
  3881. * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
  3882. * item in the container's collection). activeItem only applies to layout styles that can display
  3883. * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and
  3884. * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
  3885. */
  3886. /**
  3887. * @cfg {Object/Array} items
  3888. * <pre><b>** IMPORTANT</b>: be sure to <b>{@link #layout specify a <code>layout</code>} if needed ! **</b></pre>
  3889. * <p>A single item, or an array of child Components to be added to this container,
  3890. * for example:</p>
  3891. * <pre><code>
  3892. // specifying a single item
  3893. items: {...},
  3894. layout: 'fit', // specify a layout!
  3895. // specifying multiple items
  3896. items: [{...}, {...}],
  3897. layout: 'anchor', // specify a layout!
  3898. * </code></pre>
  3899. * <p>Each item may be:</p>
  3900. * <div><ul class="mdetail-params">
  3901. * <li>any type of object based on {@link Ext.Component}</li>
  3902. * <li>a fully instanciated object or</li>
  3903. * <li>an object literal that:</li>
  3904. * <div><ul class="mdetail-params">
  3905. * <li>has a specified <code>{@link Ext.Component#xtype xtype}</code></li>
  3906. * <li>the {@link Ext.Component#xtype} specified is associated with the Component
  3907. * desired and should be chosen from one of the available xtypes as listed
  3908. * in {@link Ext.Component}.</li>
  3909. * <li>If an <code>{@link Ext.Component#xtype xtype}</code> is not explicitly
  3910. * specified, the {@link #defaultType} for that Container is used.</li>
  3911. * <li>will be "lazily instanciated", avoiding the overhead of constructing a fully
  3912. * instanciated Component object</li>
  3913. * </ul></div></ul></div>
  3914. * <p><b>Notes</b>:</p>
  3915. * <div><ul class="mdetail-params">
  3916. * <li>Ext uses lazy rendering. Child Components will only be rendered
  3917. * should it become necessary. Items are automatically laid out when they are first
  3918. * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</li>
  3919. * <li>Do not specify <code>{@link Ext.Panel#contentEl contentEl}</code>/
  3920. * <code>{@link Ext.Panel#html html}</code> with <code>items</code>.</li>
  3921. * </ul></div>
  3922. */
  3923. /**
  3924. * @cfg {Object|Function} defaults
  3925. * <p>This option is a means of applying default settings to all added items whether added through the {@link #items}
  3926. * config or via the {@link #add} or {@link #insert} methods.</p>
  3927. * <p>If an added item is a config object, and <b>not</b> an instantiated Component, then the default properties are
  3928. * unconditionally applied. If the added item <b>is</b> an instantiated Component, then the default properties are
  3929. * applied conditionally so as not to override existing properties in the item.</p>
  3930. * <p>If the defaults option is specified as a function, then the function will be called using this Container as the
  3931. * scope (<code>this</code> reference) and passing the added item as the first parameter. Any resulting object
  3932. * from that call is then applied to the item as default properties.</p>
  3933. * <p>For example, to automatically apply padding to the body of each of a set of
  3934. * contained {@link Ext.Panel} items, you could pass: <code>defaults: {bodyStyle:'padding:15px'}</code>.</p>
  3935. * <p>Usage:</p><pre><code>
  3936. defaults: { // defaults are applied to items, not the container
  3937. autoScroll:true
  3938. },
  3939. items: [
  3940. {
  3941. xtype: 'panel', // defaults <b>do not</b> have precedence over
  3942. id: 'panel1', // options in config objects, so the defaults
  3943. autoScroll: false // will not be applied here, panel1 will be autoScroll:false
  3944. },
  3945. new Ext.Panel({ // defaults <b>do</b> have precedence over options
  3946. id: 'panel2', // options in components, so the defaults
  3947. autoScroll: false // will be applied here, panel2 will be autoScroll:true.
  3948. })
  3949. ]
  3950. * </code></pre>
  3951. */
  3952. /** @cfg {Boolean} autoDestroy
  3953. * If true the container will automatically destroy any contained component that is removed from it, else
  3954. * destruction must be handled manually (defaults to true).
  3955. */
  3956. autoDestroy : true,
  3957. /** @cfg {Boolean} forceLayout
  3958. * If true the container will force a layout initially even if hidden or collapsed. This option
  3959. * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false).
  3960. */
  3961. forceLayout: false,
  3962. /** @cfg {Boolean} hideBorders
  3963. * True to hide the borders of each contained component, false to defer to the component's existing
  3964. * border settings (defaults to false).
  3965. */
  3966. /** @cfg {String} defaultType
  3967. * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
  3968. * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
  3969. * <p>Defaults to <code>'panel'</code>, except {@link Ext.menu.Menu} which defaults to <code>'menuitem'</code>,
  3970. * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to <code>'button'</code>.</p>
  3971. */
  3972. defaultType : 'panel',
  3973. /** @cfg {String} resizeEvent
  3974. * The event to listen to for resizing in layouts. Defaults to <code>'resize'</code>.
  3975. */
  3976. resizeEvent: 'resize',
  3977. /**
  3978. * @cfg {Array} bubbleEvents
  3979. * <p>An array of events that, when fired, should be bubbled to any parent container.
  3980. * See {@link Ext.util.Observable#enableBubble}.
  3981. * Defaults to <code>['add', 'remove']</code>.
  3982. */
  3983. bubbleEvents: ['add', 'remove'],
  3984. // private
  3985. initComponent : function(){
  3986. Ext.Container.superclass.initComponent.call(this);
  3987. this.addEvents(
  3988. /**
  3989. * @event afterlayout
  3990. * Fires when the components in this container are arranged by the associated layout manager.
  3991. * @param {Ext.Container} this
  3992. * @param {ContainerLayout} layout The ContainerLayout implementation for this container
  3993. */
  3994. 'afterlayout',
  3995. /**
  3996. * @event beforeadd
  3997. * Fires before any {@link Ext.Component} is added or inserted into the container.
  3998. * A handler can return false to cancel the add.
  3999. * @param {Ext.Container} this
  4000. * @param {Ext.Component} component The component being added
  4001. * @param {Number} index The index at which the component will be added to the container's items collection
  4002. */
  4003. 'beforeadd',
  4004. /**
  4005. * @event beforeremove
  4006. * Fires before any {@link Ext.Component} is removed from the container. A handler can return
  4007. * false to cancel the remove.
  4008. * @param {Ext.Container} this
  4009. * @param {Ext.Component} component The component being removed
  4010. */
  4011. 'beforeremove',
  4012. /**
  4013. * @event add
  4014. * @bubbles
  4015. * Fires after any {@link Ext.Component} is added or inserted into the container.
  4016. * @param {Ext.Container} this
  4017. * @param {Ext.Component} component The component that was added
  4018. * @param {Number} index The index at which the component was added to the container's items collection
  4019. */
  4020. 'add',
  4021. /**
  4022. * @event remove
  4023. * @bubbles
  4024. * Fires after any {@link Ext.Component} is removed from the container.
  4025. * @param {Ext.Container} this
  4026. * @param {Ext.Component} component The component that was removed
  4027. */
  4028. 'remove'
  4029. );
  4030. /**
  4031. * The collection of components in this container as a {@link Ext.util.MixedCollection}
  4032. * @type MixedCollection
  4033. * @property items
  4034. */
  4035. var items = this.items;
  4036. if(items){
  4037. delete this.items;
  4038. this.add(items);
  4039. }
  4040. },
  4041. // private
  4042. initItems : function(){
  4043. if(!this.items){
  4044. this.items = new Ext.util.MixedCollection(false, this.getComponentId);
  4045. this.getLayout(); // initialize the layout
  4046. }
  4047. },
  4048. // private
  4049. setLayout : function(layout){
  4050. if(this.layout && this.layout != layout){
  4051. this.layout.setContainer(null);
  4052. }
  4053. this.initItems();
  4054. this.layout = layout;
  4055. layout.setContainer(this);
  4056. },
  4057. afterRender: function(){
  4058. // Render this Container, this should be done before setLayout is called which
  4059. // will hook onResize
  4060. Ext.Container.superclass.afterRender.call(this);
  4061. if(!this.layout){
  4062. this.layout = 'auto';
  4063. }
  4064. if(Ext.isObject(this.layout) && !this.layout.layout){
  4065. this.layoutConfig = this.layout;
  4066. this.layout = this.layoutConfig.type;
  4067. }
  4068. if(Ext.isString(this.layout)){
  4069. this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
  4070. }
  4071. this.setLayout(this.layout);
  4072. // If a CardLayout, the active item set
  4073. if(this.activeItem !== undefined){
  4074. var item = this.activeItem;
  4075. delete this.activeItem;
  4076. this.layout.setActiveItem(item);
  4077. }
  4078. // If we have no ownerCt, render and size all children
  4079. if(!this.ownerCt){
  4080. this.doLayout(false, true);
  4081. }
  4082. // This is a manually configured flag set by users in conjunction with renderTo.
  4083. // Not to be confused with the flag by the same name used in Layouts.
  4084. if(this.monitorResize === true){
  4085. Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
  4086. }
  4087. },
  4088. /**
  4089. * <p>Returns the Element to be used to contain the child Components of this Container.</p>
  4090. * <p>An implementation is provided which returns the Container's {@link #getEl Element}, but
  4091. * if there is a more complex structure to a Container, this may be overridden to return
  4092. * the element into which the {@link #layout layout} renders child Components.</p>
  4093. * @return {Ext.Element} The Element to render child Components into.
  4094. */
  4095. getLayoutTarget : function(){
  4096. return this.el;
  4097. },
  4098. // private - used as the key lookup function for the items collection
  4099. getComponentId : function(comp){
  4100. return comp.getItemId();
  4101. },
  4102. /**
  4103. * <p>Adds {@link Ext.Component Component}(s) to this Container.</p>
  4104. * <br><p><b>Description</b></u> :
  4105. * <div><ul class="mdetail-params">
  4106. * <li>Fires the {@link #beforeadd} event before adding</li>
  4107. * <li>The Container's {@link #defaults default config values} will be applied
  4108. * accordingly (see <code>{@link #defaults}</code> for details).</li>
  4109. * <li>Fires the {@link #add} event after the component has been added.</li>
  4110. * </ul></div>
  4111. * <br><p><b>Notes</b></u> :
  4112. * <div><ul class="mdetail-params">
  4113. * <li>If the Container is <i>already rendered</i> when <code>add</code>
  4114. * is called, you may need to call {@link #doLayout} to refresh the view which causes
  4115. * any unrendered child Components to be rendered. This is required so that you can
  4116. * <code>add</code> multiple child components if needed while only refreshing the layout
  4117. * once. For example:<pre><code>
  4118. var tb = new {@link Ext.Toolbar}();
  4119. tb.render(document.body); // toolbar is rendered
  4120. tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
  4121. tb.add({text:'Button 2'});
  4122. tb.{@link #doLayout}(); // refresh the layout
  4123. * </code></pre></li>
  4124. * <li><i>Warning:</i> Containers directly managed by the BorderLayout layout manager
  4125. * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout}
  4126. * for more details.</li>
  4127. * </ul></div>
  4128. * @param {...Object/Array} component
  4129. * <p>Either one or more Components to add or an Array of Components to add. See
  4130. * <code>{@link #items}</code> for additional information.</p>
  4131. * @return {Ext.Component/Array} The Components that were added.
  4132. */
  4133. add : function(comp){
  4134. this.initItems();
  4135. var args = arguments.length > 1;
  4136. if(args || Ext.isArray(comp)){
  4137. var result = [];
  4138. Ext.each(args ? arguments : comp, function(c){
  4139. result.push(this.add(c));
  4140. }, this);
  4141. return result;
  4142. }
  4143. var c = this.lookupComponent(this.applyDefaults(comp));
  4144. var index = this.items.length;
  4145. if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
  4146. this.items.add(c);
  4147. // *onAdded
  4148. c.onAdded(this, index);
  4149. this.onAdd(c);
  4150. this.fireEvent('add', this, c, index);
  4151. }
  4152. return c;
  4153. },
  4154. onAdd : function(c){
  4155. // Empty template method
  4156. },
  4157. // private
  4158. onAdded : function(container, pos) {
  4159. //overridden here so we can cascade down, not worth creating a template method.
  4160. this.ownerCt = container;
  4161. this.initRef();
  4162. //initialize references for child items
  4163. this.cascade(function(c){
  4164. c.initRef();
  4165. });
  4166. this.fireEvent('added', this, container, pos);
  4167. },
  4168. /**
  4169. * Inserts a Component into this Container at a specified index. Fires the
  4170. * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
  4171. * Component has been inserted.
  4172. * @param {Number} index The index at which the Component will be inserted
  4173. * into the Container's items collection
  4174. * @param {Ext.Component} component The child Component to insert.<br><br>
  4175. * Ext uses lazy rendering, and will only render the inserted Component should
  4176. * it become necessary.<br><br>
  4177. * A Component config object may be passed in order to avoid the overhead of
  4178. * constructing a real Component object if lazy rendering might mean that the
  4179. * inserted Component will not be rendered immediately. To take advantage of
  4180. * this 'lazy instantiation', set the {@link Ext.Component#xtype} config
  4181. * property to the registered type of the Component wanted.<br><br>
  4182. * For a list of all available xtypes, see {@link Ext.Component}.
  4183. * @return {Ext.Component} component The Component (or config object) that was
  4184. * inserted with the Container's default config values applied.
  4185. */
  4186. insert : function(index, comp){
  4187. this.initItems();
  4188. var a = arguments, len = a.length;
  4189. if(len > 2){
  4190. var result = [];
  4191. for(var i = len-1; i >= 1; --i) {
  4192. result.push(this.insert(index, a[i]));
  4193. }
  4194. return result;
  4195. }
  4196. var c = this.lookupComponent(this.applyDefaults(comp));
  4197. index = Math.min(index, this.items.length);
  4198. if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
  4199. if(c.ownerCt == this){
  4200. this.items.remove(c);
  4201. }
  4202. this.items.insert(index, c);
  4203. c.onAdded(this, index);
  4204. this.onAdd(c);
  4205. this.fireEvent('add', this, c, index);
  4206. }
  4207. return c;
  4208. },
  4209. // private
  4210. applyDefaults : function(c){
  4211. var d = this.defaults;
  4212. if(d){
  4213. if(Ext.isFunction(d)){
  4214. d = d.call(this, c);
  4215. }
  4216. if(Ext.isString(c)){
  4217. c = Ext.ComponentMgr.get(c);
  4218. Ext.apply(c, d);
  4219. }else if(!c.events){
  4220. Ext.applyIf(c, d);
  4221. }else{
  4222. Ext.apply(c, d);
  4223. }
  4224. }
  4225. return c;
  4226. },
  4227. // private
  4228. onBeforeAdd : function(item){
  4229. if(item.ownerCt){
  4230. item.ownerCt.remove(item, false);
  4231. }
  4232. if(this.hideBorders === true){
  4233. item.border = (item.border === true);
  4234. }
  4235. },
  4236. /**
  4237. * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires
  4238. * the {@link #remove} event after the component has been removed.
  4239. * @param {Component/String} component The component reference or id to remove.
  4240. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
  4241. * Defaults to the value of this Container's {@link #autoDestroy} config.
  4242. * @return {Ext.Component} component The Component that was removed.
  4243. */
  4244. remove : function(comp, autoDestroy){
  4245. this.initItems();
  4246. var c = this.getComponent(comp);
  4247. if(c && this.fireEvent('beforeremove', this, c) !== false){
  4248. this.doRemove(c, autoDestroy);
  4249. this.fireEvent('remove', this, c);
  4250. }
  4251. return c;
  4252. },
  4253. onRemove: function(c){
  4254. // Empty template method
  4255. },
  4256. // private
  4257. doRemove: function(c, autoDestroy){
  4258. var l = this.layout,
  4259. hasLayout = l && this.rendered;
  4260. if(hasLayout){
  4261. l.onRemove(c);
  4262. }
  4263. this.items.remove(c);
  4264. c.onRemoved();
  4265. this.onRemove(c);
  4266. if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
  4267. c.destroy();
  4268. }
  4269. if(hasLayout){
  4270. l.afterRemove(c);
  4271. }
  4272. },
  4273. /**
  4274. * Removes all components from this container.
  4275. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
  4276. * Defaults to the value of this Container's {@link #autoDestroy} config.
  4277. * @return {Array} Array of the destroyed components
  4278. */
  4279. removeAll: function(autoDestroy){
  4280. this.initItems();
  4281. var item, rem = [], items = [];
  4282. this.items.each(function(i){
  4283. rem.push(i);
  4284. });
  4285. for (var i = 0, len = rem.length; i < len; ++i){
  4286. item = rem[i];
  4287. this.remove(item, autoDestroy);
  4288. if(item.ownerCt !== this){
  4289. items.push(item);
  4290. }
  4291. }
  4292. return items;
  4293. },
  4294. /**
  4295. * Examines this container's <code>{@link #items}</code> <b>property</b>
  4296. * and gets a direct child component of this container.
  4297. * @param {String/Number} comp This parameter may be any of the following:
  4298. * <div><ul class="mdetail-params">
  4299. * <li>a <b><code>String</code></b> : representing the <code>{@link Ext.Component#itemId itemId}</code>
  4300. * or <code>{@link Ext.Component#id id}</code> of the child component </li>
  4301. * <li>a <b><code>Number</code></b> : representing the position of the child component
  4302. * within the <code>{@link #items}</code> <b>property</b></li>
  4303. * </ul></div>
  4304. * <p>For additional information see {@link Ext.util.MixedCollection#get}.
  4305. * @return Ext.Component The component (if found).
  4306. */
  4307. getComponent : function(comp){
  4308. if(Ext.isObject(comp)){
  4309. comp = comp.getItemId();
  4310. }
  4311. return this.items.get(comp);
  4312. },
  4313. // private
  4314. lookupComponent : function(comp){
  4315. if(Ext.isString(comp)){
  4316. return Ext.ComponentMgr.get(comp);
  4317. }else if(!comp.events){
  4318. return this.createComponent(comp);
  4319. }
  4320. return comp;
  4321. },
  4322. // private
  4323. createComponent : function(config, defaultType){
  4324. if (config.render) {
  4325. return config;
  4326. }
  4327. // add in ownerCt at creation time but then immediately
  4328. // remove so that onBeforeAdd can handle it
  4329. var c = Ext.create(Ext.apply({
  4330. ownerCt: this
  4331. }, config), defaultType || this.defaultType);
  4332. delete c.initialConfig.ownerCt;
  4333. delete c.ownerCt;
  4334. return c;
  4335. },
  4336. /**
  4337. * We can only lay out if there is a view area in which to layout.
  4338. * display:none on the layout target, *or any of its parent elements* will mean it has no view area.
  4339. */
  4340. // private
  4341. canLayout : function() {
  4342. var el = this.getVisibilityEl();
  4343. return el && el.dom && !el.isStyle("display", "none");
  4344. },
  4345. /**
  4346. * Force this container's layout to be recalculated. A call to this function is required after adding a new component
  4347. * to an already rendered container, or possibly after changing sizing/position properties of child components.
  4348. * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
  4349. * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
  4350. * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden.
  4351. * @return {Ext.Container} this
  4352. */
  4353. doLayout : function(shallow, force){
  4354. var rendered = this.rendered,
  4355. forceLayout = force || this.forceLayout;
  4356. if(this.collapsed || !this.canLayout()){
  4357. this.deferLayout = this.deferLayout || !shallow;
  4358. if(!forceLayout){
  4359. return;
  4360. }
  4361. shallow = shallow && !this.deferLayout;
  4362. } else {
  4363. delete this.deferLayout;
  4364. }
  4365. if(rendered && this.layout){
  4366. this.layout.layout();
  4367. }
  4368. if(shallow !== true && this.items){
  4369. var cs = this.items.items;
  4370. for(var i = 0, len = cs.length; i < len; i++){
  4371. var c = cs[i];
  4372. if(c.doLayout){
  4373. c.doLayout(false, forceLayout);
  4374. }
  4375. }
  4376. }
  4377. if(rendered){
  4378. this.onLayout(shallow, forceLayout);
  4379. }
  4380. // Initial layout completed
  4381. this.hasLayout = true;
  4382. delete this.forceLayout;
  4383. },
  4384. onLayout : Ext.emptyFn,
  4385. // private
  4386. shouldBufferLayout: function(){
  4387. /*
  4388. * Returns true if the container should buffer a layout.
  4389. * This is true only if the container has previously been laid out
  4390. * and has a parent container that is pending a layout.
  4391. */
  4392. var hl = this.hasLayout;
  4393. if(this.ownerCt){
  4394. // Only ever buffer if we've laid out the first time and we have one pending.
  4395. return hl ? !this.hasLayoutPending() : false;
  4396. }
  4397. // Never buffer initial layout
  4398. return hl;
  4399. },
  4400. // private
  4401. hasLayoutPending: function(){
  4402. // Traverse hierarchy to see if any parent container has a pending layout.
  4403. var pending = false;
  4404. this.ownerCt.bubble(function(c){
  4405. if(c.layoutPending){
  4406. pending = true;
  4407. return false;
  4408. }
  4409. });
  4410. return pending;
  4411. },
  4412. onShow : function(){
  4413. // removes css classes that were added to hide
  4414. Ext.Container.superclass.onShow.call(this);
  4415. // If we were sized during the time we were hidden, layout.
  4416. if(Ext.isDefined(this.deferLayout)){
  4417. delete this.deferLayout;
  4418. this.doLayout(true);
  4419. }
  4420. },
  4421. /**
  4422. * Returns the layout currently in use by the container. If the container does not currently have a layout
  4423. * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
  4424. * @return {ContainerLayout} layout The container's layout
  4425. */
  4426. getLayout : function(){
  4427. if(!this.layout){
  4428. var layout = new Ext.layout.AutoLayout(this.layoutConfig);
  4429. this.setLayout(layout);
  4430. }
  4431. return this.layout;
  4432. },
  4433. // private
  4434. beforeDestroy : function(){
  4435. var c;
  4436. if(this.items){
  4437. while(c = this.items.first()){
  4438. this.doRemove(c, true);
  4439. }
  4440. }
  4441. if(this.monitorResize){
  4442. Ext.EventManager.removeResizeListener(this.doLayout, this);
  4443. }
  4444. Ext.destroy(this.layout);
  4445. Ext.Container.superclass.beforeDestroy.call(this);
  4446. },
  4447. /**
  4448. * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
  4449. * function call will be the scope provided or the current component. The arguments to the function
  4450. * will be the args provided or the current component. If the function returns false at any point,
  4451. * the bubble is stopped.
  4452. * @param {Function} fn The function to call
  4453. * @param {Object} scope (optional) The scope of the function (defaults to current node)
  4454. * @param {Array} args (optional) The args to call the function with (default to passing the current component)
  4455. * @return {Ext.Container} this
  4456. */
  4457. bubble : function(fn, scope, args){
  4458. var p = this;
  4459. while(p){
  4460. if(fn.apply(scope || p, args || [p]) === false){
  4461. break;
  4462. }
  4463. p = p.ownerCt;
  4464. }
  4465. return this;
  4466. },
  4467. /**
  4468. * Cascades down the component/container heirarchy from this component (called first), calling the specified function with
  4469. * each component. The scope (<i>this</i>) of
  4470. * function call will be the scope provided or the current component. The arguments to the function
  4471. * will be the args provided or the current component. If the function returns false at any point,
  4472. * the cascade is stopped on that branch.
  4473. * @param {Function} fn The function to call
  4474. * @param {Object} scope (optional) The scope of the function (defaults to current component)
  4475. * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
  4476. * @return {Ext.Container} this
  4477. */
  4478. cascade : function(fn, scope, args){
  4479. if(fn.apply(scope || this, args || [this]) !== false){
  4480. if(this.items){
  4481. var cs = this.items.items;
  4482. for(var i = 0, len = cs.length; i < len; i++){
  4483. if(cs[i].cascade){
  4484. cs[i].cascade(fn, scope, args);
  4485. }else{
  4486. fn.apply(scope || cs[i], args || [cs[i]]);
  4487. }
  4488. }
  4489. }
  4490. }
  4491. return this;
  4492. },
  4493. /**
  4494. * Find a component under this container at any level by id
  4495. * @param {String} id
  4496. * @return Ext.Component
  4497. */
  4498. findById : function(id){
  4499. var m, ct = this;
  4500. this.cascade(function(c){
  4501. if(ct != c && c.id === id){
  4502. m = c;
  4503. return false;
  4504. }
  4505. });
  4506. return m || null;
  4507. },
  4508. /**
  4509. * Find a component under this container at any level by xtype or class
  4510. * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
  4511. * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
  4512. * the default), or true to check whether this Component is directly of the specified xtype.
  4513. * @return {Array} Array of Ext.Components
  4514. */
  4515. findByType : function(xtype, shallow){
  4516. return this.findBy(function(c){
  4517. return c.isXType(xtype, shallow);
  4518. });
  4519. },
  4520. /**
  4521. * Find a component under this container at any level by property
  4522. * @param {String} prop
  4523. * @param {String} value
  4524. * @return {Array} Array of Ext.Components
  4525. */
  4526. find : function(prop, value){
  4527. return this.findBy(function(c){
  4528. return c[prop] === value;
  4529. });
  4530. },
  4531. /**
  4532. * Find a component under this container at any level by a custom function. If the passed function returns
  4533. * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
  4534. * @param {Function} fn The function to call
  4535. * @param {Object} scope (optional)
  4536. * @return {Array} Array of Ext.Components
  4537. */
  4538. findBy : function(fn, scope){
  4539. var m = [], ct = this;
  4540. this.cascade(function(c){
  4541. if(ct != c && fn.call(scope || c, c, ct) === true){
  4542. m.push(c);
  4543. }
  4544. });
  4545. return m;
  4546. },
  4547. /**
  4548. * Get a component contained by this container (alias for items.get(key))
  4549. * @param {String/Number} key The index or id of the component
  4550. * @return {Ext.Component} Ext.Component
  4551. */
  4552. get : function(key){
  4553. return this.items.get(key);
  4554. }
  4555. });
  4556. Ext.Container.LAYOUTS = {};
  4557. Ext.reg('container', Ext.Container);
  4558. /**
  4559. * @class Ext.layout.ContainerLayout
  4560. * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
  4561. * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
  4562. */
  4563. Ext.layout.ContainerLayout = Ext.extend(Object, {
  4564. /**
  4565. * @cfg {String} extraCls
  4566. * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
  4567. * customized styles to the container or any of its children using standard CSS rules. See
  4568. * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p>
  4569. * <p><b>Note</b>: <tt>extraCls</tt> defaults to <tt>''</tt> except for the following classes
  4570. * which assign a value by default:
  4571. * <div class="mdetail-params"><ul>
  4572. * <li>{@link Ext.layout.AbsoluteLayout Absolute Layout} : <tt>'x-abs-layout-item'</tt></li>
  4573. * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-item'</tt></li>
  4574. * <li>{@link Ext.layout.ColumnLayout Column Layout} : <tt>'x-column'</tt></li>
  4575. * </ul></div>
  4576. * To configure the above Classes with an extra CSS class append to the default. For example,
  4577. * for ColumnLayout:<pre><code>
  4578. * extraCls: 'x-column custom-class'
  4579. * </code></pre>
  4580. * </p>
  4581. */
  4582. /**
  4583. * @cfg {Boolean} renderHidden
  4584. * True to hide each contained item on render (defaults to false).
  4585. */
  4586. /**
  4587. * A reference to the {@link Ext.Component} that is active. For example, <pre><code>
  4588. * if(myPanel.layout.activeItem.id == 'item-1') { ... }
  4589. * </code></pre>
  4590. * <tt>activeItem</tt> only applies to layout styles that can display items one at a time
  4591. * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
  4592. * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
  4593. * @type {Ext.Component}
  4594. * @property activeItem
  4595. */
  4596. // private
  4597. monitorResize:false,
  4598. // private
  4599. activeItem : null,
  4600. constructor : function(config){
  4601. this.id = Ext.id(null, 'ext-layout-');
  4602. Ext.apply(this, config);
  4603. },
  4604. type: 'container',
  4605. /* Workaround for how IE measures autoWidth elements. It prefers bottom-up measurements
  4606. whereas other browser prefer top-down. We will hide all target child elements before we measure and
  4607. put them back to get an accurate measurement.
  4608. */
  4609. IEMeasureHack : function(target, viewFlag) {
  4610. var tChildren = target.dom.childNodes, tLen = tChildren.length, c, d = [], e, i, ret;
  4611. for (i = 0 ; i < tLen ; i++) {
  4612. c = tChildren[i];
  4613. e = Ext.get(c);
  4614. if (e) {
  4615. d[i] = e.getStyle('display');
  4616. e.setStyle({display: 'none'});
  4617. }
  4618. }
  4619. ret = target ? target.getViewSize(viewFlag) : {};
  4620. for (i = 0 ; i < tLen ; i++) {
  4621. c = tChildren[i];
  4622. e = Ext.get(c);
  4623. if (e) {
  4624. e.setStyle({display: d[i]});
  4625. }
  4626. }
  4627. return ret;
  4628. },
  4629. // Placeholder for the derived layouts
  4630. getLayoutTargetSize : Ext.EmptyFn,
  4631. // private
  4632. layout : function(){
  4633. var ct = this.container, target = ct.getLayoutTarget();
  4634. if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){
  4635. target.addClass(this.targetCls);
  4636. }
  4637. this.onLayout(ct, target);
  4638. ct.fireEvent('afterlayout', ct, this);
  4639. },
  4640. // private
  4641. onLayout : function(ct, target){
  4642. this.renderAll(ct, target);
  4643. },
  4644. // private
  4645. isValidParent : function(c, target){
  4646. return target && c.getPositionEl().dom.parentNode == (target.dom || target);
  4647. },
  4648. // private
  4649. renderAll : function(ct, target){
  4650. var items = ct.items.items, i, c, len = items.length;
  4651. for(i = 0; i < len; i++) {
  4652. c = items[i];
  4653. if(c && (!c.rendered || !this.isValidParent(c, target))){
  4654. this.renderItem(c, i, target);
  4655. }
  4656. }
  4657. },
  4658. /**
  4659. * @private
  4660. * Renders the given Component into the target Element. If the Component is already rendered,
  4661. * it is moved to the provided target instead.
  4662. * @param {Ext.Component} c The Component to render
  4663. * @param {Number} position The position within the target to render the item to
  4664. * @param {Ext.Element} target The target Element
  4665. */
  4666. renderItem : function(c, position, target){
  4667. if (c) {
  4668. if (!c.rendered) {
  4669. c.render(target, position);
  4670. this.configureItem(c, position);
  4671. } else if (!this.isValidParent(c, target)) {
  4672. if (Ext.isNumber(position)) {
  4673. position = target.dom.childNodes[position];
  4674. }
  4675. target.dom.insertBefore(c.getPositionEl().dom, position || null);
  4676. c.container = target;
  4677. this.configureItem(c, position);
  4678. }
  4679. }
  4680. },
  4681. // private.
  4682. // Get all rendered items to lay out.
  4683. getRenderedItems: function(ct){
  4684. var t = ct.getLayoutTarget(), cti = ct.items.items, len = cti.length, i, c, items = [];
  4685. for (i = 0; i < len; i++) {
  4686. if((c = cti[i]).rendered && this.isValidParent(c, t)){
  4687. items.push(c);
  4688. }
  4689. };
  4690. return items;
  4691. },
  4692. /**
  4693. * @private
  4694. * Applies extraCls and hides the item if renderHidden is true
  4695. */
  4696. configureItem: function(c, position){
  4697. if (this.extraCls) {
  4698. var t = c.getPositionEl ? c.getPositionEl() : c;
  4699. t.addClass(this.extraCls);
  4700. }
  4701. // If we are forcing a layout, do so *before* we hide so elements have height/width
  4702. if (c.doLayout && this.forceLayout) {
  4703. c.doLayout();
  4704. }
  4705. if (this.renderHidden && c != this.activeItem) {
  4706. c.hide();
  4707. }
  4708. },
  4709. onRemove: function(c){
  4710. if(this.activeItem == c){
  4711. delete this.activeItem;
  4712. }
  4713. if(c.rendered && this.extraCls){
  4714. var t = c.getPositionEl ? c.getPositionEl() : c;
  4715. t.removeClass(this.extraCls);
  4716. }
  4717. },
  4718. afterRemove: function(c){
  4719. if(c.removeRestore){
  4720. c.removeMode = 'container';
  4721. delete c.removeRestore;
  4722. }
  4723. },
  4724. // private
  4725. onResize: function(){
  4726. var ct = this.container,
  4727. b;
  4728. if(ct.collapsed){
  4729. return;
  4730. }
  4731. if(b = ct.bufferResize && ct.shouldBufferLayout()){
  4732. if(!this.resizeTask){
  4733. this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
  4734. this.resizeBuffer = Ext.isNumber(b) ? b : 50;
  4735. }
  4736. ct.layoutPending = true;
  4737. this.resizeTask.delay(this.resizeBuffer);
  4738. }else{
  4739. this.runLayout();
  4740. }
  4741. },
  4742. runLayout: function(){
  4743. var ct = this.container;
  4744. this.layout();
  4745. ct.onLayout();
  4746. delete ct.layoutPending;
  4747. },
  4748. // private
  4749. setContainer : function(ct){
  4750. /**
  4751. * This monitorResize flag will be renamed soon as to avoid confusion
  4752. * with the Container version which hooks onWindowResize to doLayout
  4753. *
  4754. * monitorResize flag in this context attaches the resize event between
  4755. * a container and it's layout
  4756. */
  4757. if(this.monitorResize && ct != this.container){
  4758. var old = this.container;
  4759. if(old){
  4760. old.un(old.resizeEvent, this.onResize, this);
  4761. }
  4762. if(ct){
  4763. ct.on(ct.resizeEvent, this.onResize, this);
  4764. }
  4765. }
  4766. this.container = ct;
  4767. },
  4768. /**
  4769. * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
  4770. * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
  4771. * @param {Number|String} v The encoded margins
  4772. * @return {Object} An object with margin sizes for top, right, bottom and left
  4773. */
  4774. parseMargins : function(v){
  4775. if (Ext.isNumber(v)) {
  4776. v = v.toString();
  4777. }
  4778. var ms = v.split(' '),
  4779. len = ms.length;
  4780. if (len == 1) {
  4781. ms[1] = ms[2] = ms[3] = ms[0];
  4782. } else if(len == 2) {
  4783. ms[2] = ms[0];
  4784. ms[3] = ms[1];
  4785. } else if(len == 3) {
  4786. ms[3] = ms[1];
  4787. }
  4788. return {
  4789. top :parseInt(ms[0], 10) || 0,
  4790. right :parseInt(ms[1], 10) || 0,
  4791. bottom:parseInt(ms[2], 10) || 0,
  4792. left :parseInt(ms[3], 10) || 0
  4793. };
  4794. },
  4795. /**
  4796. * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
  4797. * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
  4798. * labeled and styled form Field. A default Template is supplied, but this may be
  4799. * overriden to create custom field structures. The template processes values returned from
  4800. * {@link Ext.layout.FormLayout#getTemplateArgs}.
  4801. * @property fieldTpl
  4802. * @type Ext.Template
  4803. */
  4804. fieldTpl: (function() {
  4805. var t = new Ext.Template(
  4806. '<div class="x-form-item {itemCls}" tabIndex="-1">',
  4807. '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
  4808. '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
  4809. '</div><div class="{clearCls}"></div>',
  4810. '</div>'
  4811. );
  4812. t.disableFormats = true;
  4813. return t.compile();
  4814. })(),
  4815. /*
  4816. * Destroys this layout. This is a template method that is empty by default, but should be implemented
  4817. * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
  4818. * @protected
  4819. */
  4820. destroy : function(){
  4821. // Stop any buffered layout tasks
  4822. if(this.resizeTask && this.resizeTask.cancel){
  4823. this.resizeTask.cancel();
  4824. }
  4825. if(!Ext.isEmpty(this.targetCls)){
  4826. var target = this.container.getLayoutTarget();
  4827. if(target){
  4828. target.removeClass(this.targetCls);
  4829. }
  4830. }
  4831. }
  4832. });/**
  4833. * @class Ext.layout.AutoLayout
  4834. * <p>The AutoLayout is the default layout manager delegated by {@link Ext.Container} to
  4835. * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into
  4836. * a {@link Ext.Container Container}.</tt>. AutoLayout provides only a passthrough of any layout calls
  4837. * to any child containers.</p>
  4838. */
  4839. Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, {
  4840. type: 'auto',
  4841. monitorResize: true,
  4842. onLayout : function(ct, target){
  4843. Ext.layout.AutoLayout.superclass.onLayout.call(this, ct, target);
  4844. var cs = this.getRenderedItems(ct), len = cs.length, i, c;
  4845. for(i = 0; i < len; i++){
  4846. c = cs[i];
  4847. if (c.doLayout){
  4848. // Shallow layout children
  4849. c.doLayout(true);
  4850. }
  4851. }
  4852. }
  4853. });
  4854. Ext.Container.LAYOUTS['auto'] = Ext.layout.AutoLayout;
  4855. /**
  4856. * @class Ext.layout.FitLayout
  4857. * @extends Ext.layout.ContainerLayout
  4858. * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
  4859. * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
  4860. * config, and should generally not need to be created directly via the new keyword.</p>
  4861. * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
  4862. * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
  4863. * multiple panels, only the first one will be displayed. Example usage:</p>
  4864. * <pre><code>
  4865. var p = new Ext.Panel({
  4866. title: 'Fit Layout',
  4867. layout:'fit',
  4868. items: {
  4869. title: 'Inner Panel',
  4870. html: '&lt;p&gt;This is the inner panel content&lt;/p&gt;',
  4871. border: false
  4872. }
  4873. });
  4874. </code></pre>
  4875. */
  4876. Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
  4877. // private
  4878. monitorResize:true,
  4879. type: 'fit',
  4880. getLayoutTargetSize : function() {
  4881. var target = this.container.getLayoutTarget();
  4882. if (!target) {
  4883. return {};
  4884. }
  4885. // Style Sized (scrollbars not included)
  4886. return target.getStyleSize();
  4887. },
  4888. // private
  4889. onLayout : function(ct, target){
  4890. Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
  4891. if(!ct.collapsed){
  4892. this.setItemSize(this.activeItem || ct.items.itemAt(0), this.getLayoutTargetSize());
  4893. }
  4894. },
  4895. // private
  4896. setItemSize : function(item, size){
  4897. if(item && size.height > 0){ // display none?
  4898. item.setSize(size);
  4899. }
  4900. }
  4901. });
  4902. Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
  4903. * @class Ext.layout.CardLayout
  4904. * @extends Ext.layout.FitLayout
  4905. * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
  4906. * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
  4907. * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
  4908. * and should generally not need to be created directly via the new keyword.</p>
  4909. * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
  4910. * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
  4911. * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
  4912. * so that functionality must be provided by the developer.</p>
  4913. * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
  4914. * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
  4915. * common navigation routine -- for this example, the implementation of that routine has been ommitted since
  4916. * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
  4917. * completely different implementation. For serious implementations, a better approach would be to extend
  4918. * CardLayout to provide the custom functionality needed. Example usage:</p>
  4919. * <pre><code>
  4920. var navHandler = function(direction){
  4921. // This routine could contain business logic required to manage the navigation steps.
  4922. // It would call setActiveItem as needed, manage navigation button state, handle any
  4923. // branching logic that might be required, handle alternate actions like cancellation
  4924. // or finalization, etc. A complete wizard implementation could get pretty
  4925. // sophisticated depending on the complexity required, and should probably be
  4926. // done as a subclass of CardLayout in a real-world implementation.
  4927. };
  4928. var card = new Ext.Panel({
  4929. title: 'Example Wizard',
  4930. layout:'card',
  4931. activeItem: 0, // make sure the active item is set on the container config!
  4932. bodyStyle: 'padding:15px',
  4933. defaults: {
  4934. // applied to each contained panel
  4935. border:false
  4936. },
  4937. // just an example of one possible navigation scheme, using buttons
  4938. bbar: [
  4939. {
  4940. id: 'move-prev',
  4941. text: 'Back',
  4942. handler: navHandler.createDelegate(this, [-1]),
  4943. disabled: true
  4944. },
  4945. '->', // greedy spacer so that the buttons are aligned to each side
  4946. {
  4947. id: 'move-next',
  4948. text: 'Next',
  4949. handler: navHandler.createDelegate(this, [1])
  4950. }
  4951. ],
  4952. // the panels (or "cards") within the layout
  4953. items: [{
  4954. id: 'card-0',
  4955. html: '&lt;h1&gt;Welcome to the Wizard!&lt;/h1&gt;&lt;p&gt;Step 1 of 3&lt;/p&gt;'
  4956. },{
  4957. id: 'card-1',
  4958. html: '&lt;p&gt;Step 2 of 3&lt;/p&gt;'
  4959. },{
  4960. id: 'card-2',
  4961. html: '&lt;h1&gt;Congratulations!&lt;/h1&gt;&lt;p&gt;Step 3 of 3 - Complete&lt;/p&gt;'
  4962. }]
  4963. });
  4964. </code></pre>
  4965. */
  4966. Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
  4967. /**
  4968. * @cfg {Boolean} deferredRender
  4969. * True to render each contained item at the time it becomes active, false to render all contained items
  4970. * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
  4971. * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
  4972. * true might improve performance.
  4973. */
  4974. deferredRender : false,
  4975. /**
  4976. * @cfg {Boolean} layoutOnCardChange
  4977. * True to force a layout of the active item when the active card is changed. Defaults to false.
  4978. */
  4979. layoutOnCardChange : false,
  4980. /**
  4981. * @cfg {Boolean} renderHidden @hide
  4982. */
  4983. // private
  4984. renderHidden : true,
  4985. type: 'card',
  4986. /**
  4987. * Sets the active (visible) item in the layout.
  4988. * @param {String/Number} item The string component id or numeric index of the item to activate
  4989. */
  4990. setActiveItem : function(item){
  4991. var ai = this.activeItem,
  4992. ct = this.container;
  4993. item = ct.getComponent(item);
  4994. // Is this a valid, different card?
  4995. if(item && ai != item){
  4996. // Changing cards, hide the current one
  4997. if(ai){
  4998. ai.hide();
  4999. if (ai.hidden !== true) {
  5000. return false;
  5001. }
  5002. ai.fireEvent('deactivate', ai);
  5003. }
  5004. var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
  5005. // Change activeItem reference
  5006. this.activeItem = item;
  5007. // The container is about to get a recursive layout, remove any deferLayout reference
  5008. // because it will trigger a redundant layout.
  5009. delete item.deferLayout;
  5010. // Show the new component
  5011. item.show();
  5012. this.layout();
  5013. if(layout){
  5014. item.doLayout();
  5015. }
  5016. item.fireEvent('activate', item);
  5017. }
  5018. },
  5019. // private
  5020. renderAll : function(ct, target){
  5021. if(this.deferredRender){
  5022. this.renderItem(this.activeItem, undefined, target);
  5023. }else{
  5024. Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
  5025. }
  5026. }
  5027. });
  5028. Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;
  5029. /**
  5030. * @class Ext.layout.AnchorLayout
  5031. * @extends Ext.layout.ContainerLayout
  5032. * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
  5033. * If the container is resized, all anchored items are automatically rerendered according to their
  5034. * <b><tt>{@link #anchor}</tt></b> rules.</p>
  5035. * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
  5036. * config, and should generally not need to be created directly via the new keyword.</p>
  5037. * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
  5038. * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
  5039. * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
  5040. * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
  5041. * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
  5042. * logic if necessary. For example:</p>
  5043. * <pre><code>
  5044. var viewport = new Ext.Viewport({
  5045. layout:'anchor',
  5046. anchorSize: {width:800, height:600},
  5047. items:[{
  5048. title:'Item 1',
  5049. html:'Content 1',
  5050. width:800,
  5051. anchor:'right 20%'
  5052. },{
  5053. title:'Item 2',
  5054. html:'Content 2',
  5055. width:300,
  5056. anchor:'50% 30%'
  5057. },{
  5058. title:'Item 3',
  5059. html:'Content 3',
  5060. width:600,
  5061. anchor:'-100 50%'
  5062. }]
  5063. });
  5064. * </code></pre>
  5065. */
  5066. Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
  5067. /**
  5068. * @cfg {String} anchor
  5069. * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
  5070. * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
  5071. *
  5072. * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
  5073. * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
  5074. * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
  5075. * The following types of anchor values are supported:<div class="mdetail-params"><ul>
  5076. *
  5077. * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
  5078. * The first anchor is the percentage width that the item should take up within the container, and the
  5079. * second is the percentage height. For example:<pre><code>
  5080. // two values specified
  5081. anchor: '100% 50%' // render item complete width of the container and
  5082. // 1/2 height of the container
  5083. // one value specified
  5084. anchor: '100%' // the width value; the height will default to auto
  5085. * </code></pre></div></li>
  5086. *
  5087. * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
  5088. * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
  5089. * and the second is the offset from the bottom edge. For example:<pre><code>
  5090. // two values specified
  5091. anchor: '-50 -100' // render item the complete width of the container
  5092. // minus 50 pixels and
  5093. // the complete height minus 100 pixels.
  5094. // one value specified
  5095. anchor: '-50' // anchor value is assumed to be the right offset value
  5096. // bottom offset will default to 0
  5097. * </code></pre></div></li>
  5098. *
  5099. * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
  5100. * (or <tt>'b'</tt>).<div class="sub-desc">
  5101. * Either the container must have a fixed size or an anchorSize config value defined at render time in
  5102. * order for these to have any effect.</div></li>
  5103. *
  5104. * <li><b>Mixed</b> : <div class="sub-desc">
  5105. * Anchor values can also be mixed as needed. For example, to render the width offset from the container
  5106. * right edge by 50 pixels and 75% of the container's height use:
  5107. * <pre><code>
  5108. anchor: '-50 75%'
  5109. * </code></pre></div></li>
  5110. *
  5111. *
  5112. * </ul></div>
  5113. */
  5114. // private
  5115. monitorResize : true,
  5116. type : 'anchor',
  5117. /**
  5118. * @cfg {String} defaultAnchor
  5119. *
  5120. * default anchor for all child container items applied if no anchor or specific width is set on the child item. Defaults to '100%'.
  5121. *
  5122. */
  5123. defaultAnchor : '100%',
  5124. parseAnchorRE : /^(r|right|b|bottom)$/i,
  5125. getLayoutTargetSize : function() {
  5126. var target = this.container.getLayoutTarget();
  5127. if (!target) {
  5128. return {};
  5129. }
  5130. // Style Sized (scrollbars not included)
  5131. return target.getStyleSize();
  5132. },
  5133. // private
  5134. onLayout : function(ct, target){
  5135. Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
  5136. var size = this.getLayoutTargetSize();
  5137. var w = size.width, h = size.height;
  5138. if(w < 20 && h < 20){
  5139. return;
  5140. }
  5141. // find the container anchoring size
  5142. var aw, ah;
  5143. if(ct.anchorSize){
  5144. if(typeof ct.anchorSize == 'number'){
  5145. aw = ct.anchorSize;
  5146. }else{
  5147. aw = ct.anchorSize.width;
  5148. ah = ct.anchorSize.height;
  5149. }
  5150. }else{
  5151. aw = ct.initialConfig.width;
  5152. ah = ct.initialConfig.height;
  5153. }
  5154. var cs = this.getRenderedItems(ct), len = cs.length, i, c, a, cw, ch, el, vs, boxes = [];
  5155. for(i = 0; i < len; i++){
  5156. c = cs[i];
  5157. el = c.getPositionEl();
  5158. // If a child container item has no anchor and no specific width, set the child to the default anchor size
  5159. if (!c.anchor && c.items && !Ext.isNumber(c.width) && !(Ext.isIE6 && Ext.isStrict)){
  5160. c.anchor = this.defaultAnchor;
  5161. }
  5162. if(c.anchor){
  5163. a = c.anchorSpec;
  5164. if(!a){ // cache all anchor values
  5165. vs = c.anchor.split(' ');
  5166. c.anchorSpec = a = {
  5167. right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
  5168. bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
  5169. };
  5170. }
  5171. cw = a.right ? this.adjustWidthAnchor(a.right(w) - el.getMargins('lr'), c) : undefined;
  5172. ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h) - el.getMargins('tb'), c) : undefined;
  5173. if(cw || ch){
  5174. boxes.push({
  5175. comp: c,
  5176. width: cw || undefined,
  5177. height: ch || undefined
  5178. });
  5179. }
  5180. }
  5181. }
  5182. for (i = 0, len = boxes.length; i < len; i++) {
  5183. c = boxes[i];
  5184. c.comp.setSize(c.width, c.height);
  5185. }
  5186. },
  5187. // private
  5188. parseAnchor : function(a, start, cstart){
  5189. if(a && a != 'none'){
  5190. var last;
  5191. // standard anchor
  5192. if(this.parseAnchorRE.test(a)){
  5193. var diff = cstart - start;
  5194. return function(v){
  5195. if(v !== last){
  5196. last = v;
  5197. return v - diff;
  5198. }
  5199. }
  5200. // percentage
  5201. }else if(a.indexOf('%') != -1){
  5202. var ratio = parseFloat(a.replace('%', ''))*.01;
  5203. return function(v){
  5204. if(v !== last){
  5205. last = v;
  5206. return Math.floor(v*ratio);
  5207. }
  5208. }
  5209. // simple offset adjustment
  5210. }else{
  5211. a = parseInt(a, 10);
  5212. if(!isNaN(a)){
  5213. return function(v){
  5214. if(v !== last){
  5215. last = v;
  5216. return v + a;
  5217. }
  5218. }
  5219. }
  5220. }
  5221. }
  5222. return false;
  5223. },
  5224. // private
  5225. adjustWidthAnchor : function(value, comp){
  5226. return value;
  5227. },
  5228. // private
  5229. adjustHeightAnchor : function(value, comp){
  5230. return value;
  5231. }
  5232. /**
  5233. * @property activeItem
  5234. * @hide
  5235. */
  5236. });
  5237. Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;
  5238. /**
  5239. * @class Ext.layout.ColumnLayout
  5240. * @extends Ext.layout.ContainerLayout
  5241. * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
  5242. * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
  5243. * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
  5244. * and should generally not need to be created directly via the new keyword.</p>
  5245. * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
  5246. * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
  5247. * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
  5248. * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
  5249. * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
  5250. * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
  5251. * less than 1 (e.g., .25).</p>
  5252. * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
  5253. * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
  5254. * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
  5255. * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
  5256. * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
  5257. * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
  5258. * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
  5259. * layout may not render as expected. Example usage:</p>
  5260. * <pre><code>
  5261. // All columns are percentages -- they must add up to 1
  5262. var p = new Ext.Panel({
  5263. title: 'Column Layout - Percentage Only',
  5264. layout:'column',
  5265. items: [{
  5266. title: 'Column 1',
  5267. columnWidth: .25
  5268. },{
  5269. title: 'Column 2',
  5270. columnWidth: .6
  5271. },{
  5272. title: 'Column 3',
  5273. columnWidth: .15
  5274. }]
  5275. });
  5276. // Mix of width and columnWidth -- all columnWidth values must add up
  5277. // to 1. The first column will take up exactly 120px, and the last two
  5278. // columns will fill the remaining container width.
  5279. var p = new Ext.Panel({
  5280. title: 'Column Layout - Mixed',
  5281. layout:'column',
  5282. items: [{
  5283. title: 'Column 1',
  5284. width: 120
  5285. },{
  5286. title: 'Column 2',
  5287. columnWidth: .8
  5288. },{
  5289. title: 'Column 3',
  5290. columnWidth: .2
  5291. }]
  5292. });
  5293. </code></pre>
  5294. */
  5295. Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
  5296. // private
  5297. monitorResize:true,
  5298. type: 'column',
  5299. extraCls: 'x-column',
  5300. scrollOffset : 0,
  5301. // private
  5302. targetCls: 'x-column-layout-ct',
  5303. isValidParent : function(c, target){
  5304. return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
  5305. },
  5306. getLayoutTargetSize : function() {
  5307. var target = this.container.getLayoutTarget(), ret;
  5308. if (target) {
  5309. ret = target.getViewSize();
  5310. // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
  5311. // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
  5312. // with getViewSize
  5313. if (Ext.isIE && Ext.isStrict && ret.width == 0){
  5314. ret = target.getStyleSize();
  5315. }
  5316. ret.width -= target.getPadding('lr');
  5317. ret.height -= target.getPadding('tb');
  5318. }
  5319. return ret;
  5320. },
  5321. renderAll : function(ct, target) {
  5322. if(!this.innerCt){
  5323. // the innerCt prevents wrapping and shuffling while
  5324. // the container is resizing
  5325. this.innerCt = target.createChild({cls:'x-column-inner'});
  5326. this.innerCt.createChild({cls:'x-clear'});
  5327. }
  5328. Ext.layout.ColumnLayout.superclass.renderAll.call(this, ct, this.innerCt);
  5329. },
  5330. // private
  5331. onLayout : function(ct, target){
  5332. var cs = ct.items.items,
  5333. len = cs.length,
  5334. c,
  5335. i,
  5336. m,
  5337. margins = [];
  5338. this.renderAll(ct, target);
  5339. var size = this.getLayoutTargetSize();
  5340. if(size.width < 1 && size.height < 1){ // display none?
  5341. return;
  5342. }
  5343. var w = size.width - this.scrollOffset,
  5344. h = size.height,
  5345. pw = w;
  5346. this.innerCt.setWidth(w);
  5347. // some columns can be percentages while others are fixed
  5348. // so we need to make 2 passes
  5349. for(i = 0; i < len; i++){
  5350. c = cs[i];
  5351. m = c.getPositionEl().getMargins('lr');
  5352. margins[i] = m;
  5353. if(!c.columnWidth){
  5354. pw -= (c.getWidth() + m);
  5355. }
  5356. }
  5357. pw = pw < 0 ? 0 : pw;
  5358. for(i = 0; i < len; i++){
  5359. c = cs[i];
  5360. m = margins[i];
  5361. if(c.columnWidth){
  5362. c.setSize(Math.floor(c.columnWidth * pw) - m);
  5363. }
  5364. }
  5365. // Browsers differ as to when they account for scrollbars. We need to re-measure to see if the scrollbar
  5366. // spaces were accounted for properly. If not, re-layout.
  5367. if (Ext.isIE) {
  5368. if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
  5369. var ts = this.getLayoutTargetSize();
  5370. if (ts.width != size.width){
  5371. this.adjustmentPass = true;
  5372. this.onLayout(ct, target);
  5373. }
  5374. }
  5375. }
  5376. delete this.adjustmentPass;
  5377. }
  5378. /**
  5379. * @property activeItem
  5380. * @hide
  5381. */
  5382. });
  5383. Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;
  5384. /**
  5385. * @class Ext.layout.BorderLayout
  5386. * @extends Ext.layout.ContainerLayout
  5387. * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
  5388. * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between
  5389. * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in
  5390. * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.</p>
  5391. * <p>This class is intended to be extended or created via the <tt>layout:'border'</tt>
  5392. * {@link Ext.Container#layout} config, and should generally not need to be created directly
  5393. * via the new keyword.</p>
  5394. * <p>BorderLayout does not have any direct config options (other than inherited ones).
  5395. * All configuration options available for customizing the BorderLayout are at the
  5396. * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion}
  5397. * levels.</p>
  5398. * <p>Example usage:</p>
  5399. * <pre><code>
  5400. var myBorderPanel = new Ext.Panel({
  5401. {@link Ext.Component#renderTo renderTo}: document.body,
  5402. {@link Ext.BoxComponent#width width}: 700,
  5403. {@link Ext.BoxComponent#height height}: 500,
  5404. {@link Ext.Panel#title title}: 'Border Layout',
  5405. {@link Ext.Container#layout layout}: 'border',
  5406. {@link Ext.Container#items items}: [{
  5407. {@link Ext.Panel#title title}: 'South Region is resizable',
  5408. {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
  5409. {@link Ext.BoxComponent#height height}: 100,
  5410. {@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
  5411. {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
  5412. {@link Ext.SplitBar#maxSize maxSize}: 150,
  5413. {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
  5414. },{
  5415. // xtype: 'panel' implied by default
  5416. {@link Ext.Panel#title title}: 'West Region is collapsible',
  5417. {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
  5418. {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
  5419. {@link Ext.BoxComponent#width width}: 200,
  5420. {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true, // make collapsible
  5421. {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
  5422. {@link Ext.Component#id id}: 'west-region-container',
  5423. {@link Ext.Container#layout layout}: 'fit',
  5424. {@link Ext.Panel#unstyled unstyled}: true
  5425. },{
  5426. {@link Ext.Panel#title title}: 'Center Region',
  5427. {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center', // center region is required, no width/height specified
  5428. {@link Ext.Component#xtype xtype}: 'container',
  5429. {@link Ext.Container#layout layout}: 'fit',
  5430. {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
  5431. }]
  5432. });
  5433. </code></pre>
  5434. * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
  5435. * <li>Any container using the BorderLayout <b>must</b> have a child item with <tt>region:'center'</tt>.
  5436. * The child item in the center region will always be resized to fill the remaining space not used by
  5437. * the other regions in the layout.</li>
  5438. * <li>Any child items with a region of <tt>west</tt> or <tt>east</tt> must have <tt>width</tt> defined
  5439. * (an integer representing the number of pixels that the region should take up).</li>
  5440. * <li>Any child items with a region of <tt>north</tt> or <tt>south</tt> must have <tt>height</tt> defined.</li>
  5441. * <li>The regions of a BorderLayout are <b>fixed at render time</b> and thereafter, its child Components may not be removed or added</b>. To add/remove
  5442. * Components within a BorderLayout, have them wrapped by an additional Container which is directly
  5443. * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
  5444. * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.Panel)
  5445. * is added to the west region:
  5446. * <div style="margin-left:16px"><pre><code>
  5447. wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
  5448. wrc.{@link Ext.Panel#removeAll removeAll}();
  5449. wrc.{@link Ext.Container#add add}({
  5450. title: 'Added Panel',
  5451. html: 'Some content'
  5452. });
  5453. wrc.{@link Ext.Container#doLayout doLayout}();
  5454. * </code></pre></div>
  5455. * </li>
  5456. * <li> To reference a {@link Ext.layout.BorderLayout.Region Region}:
  5457. * <div style="margin-left:16px"><pre><code>
  5458. wr = myBorderPanel.layout.west;
  5459. * </code></pre></div>
  5460. * </li>
  5461. * </ul></div>
  5462. */
  5463. Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
  5464. // private
  5465. monitorResize:true,
  5466. // private
  5467. rendered : false,
  5468. type: 'border',
  5469. targetCls: 'x-border-layout-ct',
  5470. getLayoutTargetSize : function() {
  5471. var target = this.container.getLayoutTarget();
  5472. return target ? target.getViewSize() : {};
  5473. },
  5474. // private
  5475. onLayout : function(ct, target){
  5476. var collapsed, i, c, pos, items = ct.items.items, len = items.length;
  5477. if(!this.rendered){
  5478. collapsed = [];
  5479. for(i = 0; i < len; i++) {
  5480. c = items[i];
  5481. pos = c.region;
  5482. if(c.collapsed){
  5483. collapsed.push(c);
  5484. }
  5485. c.collapsed = false;
  5486. if(!c.rendered){
  5487. c.render(target, i);
  5488. c.getPositionEl().addClass('x-border-panel');
  5489. }
  5490. this[pos] = pos != 'center' && c.split ?
  5491. new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
  5492. new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos);
  5493. this[pos].render(target, c);
  5494. }
  5495. this.rendered = true;
  5496. }
  5497. var size = this.getLayoutTargetSize();
  5498. if(size.width < 20 || size.height < 20){ // display none?
  5499. if(collapsed){
  5500. this.restoreCollapsed = collapsed;
  5501. }
  5502. return;
  5503. }else if(this.restoreCollapsed){
  5504. collapsed = this.restoreCollapsed;
  5505. delete this.restoreCollapsed;
  5506. }
  5507. var w = size.width, h = size.height,
  5508. centerW = w, centerH = h, centerY = 0, centerX = 0,
  5509. n = this.north, s = this.south, west = this.west, e = this.east, c = this.center,
  5510. b, m, totalWidth, totalHeight;
  5511. if(!c && Ext.layout.BorderLayout.WARN !== false){
  5512. throw 'No center region defined in BorderLayout ' + ct.id;
  5513. }
  5514. if(n && n.isVisible()){
  5515. b = n.getSize();
  5516. m = n.getMargins();
  5517. b.width = w - (m.left+m.right);
  5518. b.x = m.left;
  5519. b.y = m.top;
  5520. centerY = b.height + b.y + m.bottom;
  5521. centerH -= centerY;
  5522. n.applyLayout(b);
  5523. }
  5524. if(s && s.isVisible()){
  5525. b = s.getSize();
  5526. m = s.getMargins();
  5527. b.width = w - (m.left+m.right);
  5528. b.x = m.left;
  5529. totalHeight = (b.height + m.top + m.bottom);
  5530. b.y = h - totalHeight + m.top;
  5531. centerH -= totalHeight;
  5532. s.applyLayout(b);
  5533. }
  5534. if(west && west.isVisible()){
  5535. b = west.getSize();
  5536. m = west.getMargins();
  5537. b.height = centerH - (m.top+m.bottom);
  5538. b.x = m.left;
  5539. b.y = centerY + m.top;
  5540. totalWidth = (b.width + m.left + m.right);
  5541. centerX += totalWidth;
  5542. centerW -= totalWidth;
  5543. west.applyLayout(b);
  5544. }
  5545. if(e && e.isVisible()){
  5546. b = e.getSize();
  5547. m = e.getMargins();
  5548. b.height = centerH - (m.top+m.bottom);
  5549. totalWidth = (b.width + m.left + m.right);
  5550. b.x = w - totalWidth + m.left;
  5551. b.y = centerY + m.top;
  5552. centerW -= totalWidth;
  5553. e.applyLayout(b);
  5554. }
  5555. if(c){
  5556. m = c.getMargins();
  5557. var centerBox = {
  5558. x: centerX + m.left,
  5559. y: centerY + m.top,
  5560. width: centerW - (m.left+m.right),
  5561. height: centerH - (m.top+m.bottom)
  5562. };
  5563. c.applyLayout(centerBox);
  5564. }
  5565. if(collapsed){
  5566. for(i = 0, len = collapsed.length; i < len; i++){
  5567. collapsed[i].collapse(false);
  5568. }
  5569. }
  5570. if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
  5571. target.repaint();
  5572. }
  5573. // Putting a border layout into an overflowed container is NOT correct and will make a second layout pass necessary.
  5574. if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
  5575. var ts = this.getLayoutTargetSize();
  5576. if (ts.width != size.width || ts.height != size.height){
  5577. this.adjustmentPass = true;
  5578. this.onLayout(ct, target);
  5579. }
  5580. }
  5581. delete this.adjustmentPass;
  5582. },
  5583. destroy: function() {
  5584. var r = ['north', 'south', 'east', 'west'], i, region;
  5585. for (i = 0; i < r.length; i++) {
  5586. region = this[r[i]];
  5587. if(region){
  5588. if(region.destroy){
  5589. region.destroy();
  5590. }else if (region.split){
  5591. region.split.destroy(true);
  5592. }
  5593. }
  5594. }
  5595. Ext.layout.BorderLayout.superclass.destroy.call(this);
  5596. }
  5597. /**
  5598. * @property activeItem
  5599. * @hide
  5600. */
  5601. });
  5602. /**
  5603. * @class Ext.layout.BorderLayout.Region
  5604. * <p>This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer
  5605. * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is
  5606. * independent of other regions and the containing BorderLayout, and can be any of the
  5607. * {@link Ext.layout.ContainerLayout valid Ext layout types}.</p>
  5608. * <p>Region size is managed automatically and cannot be changed by the user -- for
  5609. * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.</p>
  5610. * @constructor
  5611. * Create a new Region.
  5612. * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
  5613. * @param {Object} config The configuration options
  5614. * @param {String} position The region position. Valid values are: <tt>north</tt>, <tt>south</tt>,
  5615. * <tt>east</tt>, <tt>west</tt> and <tt>center</tt>. Every {@link Ext.layout.BorderLayout BorderLayout}
  5616. * <b>must have a center region</b> for the primary content -- all other regions are optional.
  5617. */
  5618. Ext.layout.BorderLayout.Region = function(layout, config, pos){
  5619. Ext.apply(this, config);
  5620. this.layout = layout;
  5621. this.position = pos;
  5622. this.state = {};
  5623. if(typeof this.margins == 'string'){
  5624. this.margins = this.layout.parseMargins(this.margins);
  5625. }
  5626. this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins);
  5627. if(this.collapsible){
  5628. if(typeof this.cmargins == 'string'){
  5629. this.cmargins = this.layout.parseMargins(this.cmargins);
  5630. }
  5631. if(this.collapseMode == 'mini' && !this.cmargins){
  5632. this.cmargins = {left:0,top:0,right:0,bottom:0};
  5633. }else{
  5634. this.cmargins = Ext.applyIf(this.cmargins || {},
  5635. pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins);
  5636. }
  5637. }
  5638. };
  5639. Ext.layout.BorderLayout.Region.prototype = {
  5640. /**
  5641. * @cfg {Boolean} animFloat
  5642. * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
  5643. * panel that will close again once the user mouses out of that panel (or clicks out if
  5644. * <tt>{@link #autoHide} = false</tt>). Setting <tt>{@link #animFloat} = false</tt> will
  5645. * prevent the open and close of these floated panels from being animated (defaults to <tt>true</tt>).
  5646. */
  5647. /**
  5648. * @cfg {Boolean} autoHide
  5649. * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
  5650. * panel. If <tt>autoHide = true</tt>, the panel will automatically hide after the user mouses
  5651. * out of the panel. If <tt>autoHide = false</tt>, the panel will continue to display until the
  5652. * user clicks outside of the panel (defaults to <tt>true</tt>).
  5653. */
  5654. /**
  5655. * @cfg {String} collapseMode
  5656. * <tt>collapseMode</tt> supports two configuration values:<div class="mdetail-params"><ul>
  5657. * <li><b><tt>undefined</tt></b> (default)<div class="sub-desc">By default, {@link #collapsible}
  5658. * regions are collapsed by clicking the expand/collapse tool button that renders into the region's
  5659. * title bar.</div></li>
  5660. * <li><b><tt>'mini'</tt></b><div class="sub-desc">Optionally, when <tt>collapseMode</tt> is set to
  5661. * <tt>'mini'</tt> the region's split bar will also display a small collapse button in the center of
  5662. * the bar. In <tt>'mini'</tt> mode the region will collapse to a thinner bar than in normal mode.
  5663. * </div></li>
  5664. * </ul></div></p>
  5665. * <p><b>Note</b>: if a collapsible region does not have a title bar, then set <tt>collapseMode =
  5666. * 'mini'</tt> and <tt>{@link #split} = true</tt> in order for the region to be {@link #collapsible}
  5667. * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.</p>
  5668. * <p>See also <tt>{@link #cmargins}</tt>.</p>
  5669. */
  5670. /**
  5671. * @cfg {Object} margins
  5672. * An object containing margins to apply to the region when in the expanded state in the
  5673. * format:<pre><code>
  5674. {
  5675. top: (top margin),
  5676. right: (right margin),
  5677. bottom: (bottom margin),
  5678. left: (left margin)
  5679. }</code></pre>
  5680. * <p>May also be a string containing space-separated, numeric margin values. The order of the
  5681. * sides associated with each value matches the way CSS processes margin values:</p>
  5682. * <p><div class="mdetail-params"><ul>
  5683. * <li>If there is only one value, it applies to all sides.</li>
  5684. * <li>If there are two values, the top and bottom borders are set to the first value and the
  5685. * right and left are set to the second.</li>
  5686. * <li>If there are three values, the top is set to the first value, the left and right are set
  5687. * to the second, and the bottom is set to the third.</li>
  5688. * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
  5689. * </ul></div></p>
  5690. * <p>Defaults to:</p><pre><code>
  5691. * {top:0, right:0, bottom:0, left:0}
  5692. * </code></pre>
  5693. */
  5694. /**
  5695. * @cfg {Object} cmargins
  5696. * An object containing margins to apply to the region when in the collapsed state in the
  5697. * format:<pre><code>
  5698. {
  5699. top: (top margin),
  5700. right: (right margin),
  5701. bottom: (bottom margin),
  5702. left: (left margin)
  5703. }</code></pre>
  5704. * <p>May also be a string containing space-separated, numeric margin values. The order of the
  5705. * sides associated with each value matches the way CSS processes margin values.</p>
  5706. * <p><ul>
  5707. * <li>If there is only one value, it applies to all sides.</li>
  5708. * <li>If there are two values, the top and bottom borders are set to the first value and the
  5709. * right and left are set to the second.</li>
  5710. * <li>If there are three values, the top is set to the first value, the left and right are set
  5711. * to the second, and the bottom is set to the third.</li>
  5712. * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
  5713. * </ul></p>
  5714. */
  5715. /**
  5716. * @cfg {Boolean} collapsible
  5717. * <p><tt>true</tt> to allow the user to collapse this region (defaults to <tt>false</tt>). If
  5718. * <tt>true</tt>, an expand/collapse tool button will automatically be rendered into the title
  5719. * bar of the region, otherwise the button will not be shown.</p>
  5720. * <p><b>Note</b>: that a title bar is required to display the collapse/expand toggle button -- if
  5721. * no <tt>title</tt> is specified for the region's panel, the region will only be collapsible if
  5722. * <tt>{@link #collapseMode} = 'mini'</tt> and <tt>{@link #split} = true</tt>.
  5723. */
  5724. collapsible : false,
  5725. /**
  5726. * @cfg {Boolean} split
  5727. * <p><tt>true</tt> to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
  5728. * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
  5729. * resize the regions dynamically. Defaults to <tt>false</tt> creating a
  5730. * {@link Ext.layout.BorderLayout.Region Region}.</p><br>
  5731. * <p><b>Notes</b>:</p><div class="mdetail-params"><ul>
  5732. * <li>this configuration option is ignored if <tt>region='center'</tt></li>
  5733. * <li>when <tt>split == true</tt>, it is common to specify a
  5734. * <tt>{@link Ext.SplitBar#minSize minSize}</tt> and <tt>{@link Ext.SplitBar#maxSize maxSize}</tt>
  5735. * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
  5736. * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.</li>
  5737. * <li>if <tt>{@link #collapseMode} = 'mini'</tt> requires <tt>split = true</tt> to reserve space
  5738. * for the collapse tool</tt></li>
  5739. * </ul></div>
  5740. */
  5741. split:false,
  5742. /**
  5743. * @cfg {Boolean} floatable
  5744. * <tt>true</tt> to allow clicking a collapsed region's bar to display the region's panel floated
  5745. * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
  5746. * clicking the expand button to see it again (defaults to <tt>true</tt>).
  5747. */
  5748. floatable: true,
  5749. /**
  5750. * @cfg {Number} minWidth
  5751. * <p>The minimum allowable width in pixels for this region (defaults to <tt>50</tt>).
  5752. * <tt>maxWidth</tt> may also be specified.</p><br>
  5753. * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
  5754. * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
  5755. * <tt>minWidth</tt> / <tt>maxWidth</tt>.</p>
  5756. */
  5757. minWidth:50,
  5758. /**
  5759. * @cfg {Number} minHeight
  5760. * The minimum allowable height in pixels for this region (defaults to <tt>50</tt>)
  5761. * <tt>maxHeight</tt> may also be specified.</p><br>
  5762. * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
  5763. * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
  5764. * <tt>minHeight</tt> / <tt>maxHeight</tt>.</p>
  5765. */
  5766. minHeight:50,
  5767. // private
  5768. defaultMargins : {left:0,top:0,right:0,bottom:0},
  5769. // private
  5770. defaultNSCMargins : {left:5,top:5,right:5,bottom:5},
  5771. // private
  5772. defaultEWCMargins : {left:5,top:0,right:5,bottom:0},
  5773. floatingZIndex: 100,
  5774. /**
  5775. * True if this region is collapsed. Read-only.
  5776. * @type Boolean
  5777. * @property
  5778. */
  5779. isCollapsed : false,
  5780. /**
  5781. * This region's panel. Read-only.
  5782. * @type Ext.Panel
  5783. * @property panel
  5784. */
  5785. /**
  5786. * This region's layout. Read-only.
  5787. * @type Layout
  5788. * @property layout
  5789. */
  5790. /**
  5791. * This region's layout position (north, south, east, west or center). Read-only.
  5792. * @type String
  5793. * @property position
  5794. */
  5795. // private
  5796. render : function(ct, p){
  5797. this.panel = p;
  5798. p.el.enableDisplayMode();
  5799. this.targetEl = ct;
  5800. this.el = p.el;
  5801. var gs = p.getState, ps = this.position;
  5802. p.getState = function(){
  5803. return Ext.apply(gs.call(p) || {}, this.state);
  5804. }.createDelegate(this);
  5805. if(ps != 'center'){
  5806. p.allowQueuedExpand = false;
  5807. p.on({
  5808. beforecollapse: this.beforeCollapse,
  5809. collapse: this.onCollapse,
  5810. beforeexpand: this.beforeExpand,
  5811. expand: this.onExpand,
  5812. hide: this.onHide,
  5813. show: this.onShow,
  5814. scope: this
  5815. });
  5816. if(this.collapsible || this.floatable){
  5817. p.collapseEl = 'el';
  5818. p.slideAnchor = this.getSlideAnchor();
  5819. }
  5820. if(p.tools && p.tools.toggle){
  5821. p.tools.toggle.addClass('x-tool-collapse-'+ps);
  5822. p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over');
  5823. }
  5824. }
  5825. },
  5826. // private
  5827. getCollapsedEl : function(){
  5828. if(!this.collapsedEl){
  5829. if(!this.toolTemplate){
  5830. var tt = new Ext.Template(
  5831. '<div class="x-tool x-tool-{id}">&#160;</div>'
  5832. );
  5833. tt.disableFormats = true;
  5834. tt.compile();
  5835. Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
  5836. }
  5837. this.collapsedEl = this.targetEl.createChild({
  5838. cls: "x-layout-collapsed x-layout-collapsed-"+this.position,
  5839. id: this.panel.id + '-xcollapsed'
  5840. });
  5841. this.collapsedEl.enableDisplayMode('block');
  5842. if(this.collapseMode == 'mini'){
  5843. this.collapsedEl.addClass('x-layout-cmini-'+this.position);
  5844. this.miniCollapsedEl = this.collapsedEl.createChild({
  5845. cls: "x-layout-mini x-layout-mini-"+this.position, html: "&#160;"
  5846. });
  5847. this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
  5848. this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
  5849. this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true});
  5850. }else {
  5851. if(this.collapsible !== false && !this.hideCollapseTool) {
  5852. var t = this.toolTemplate.append(
  5853. this.collapsedEl.dom,
  5854. {id:'expand-'+this.position}, true);
  5855. t.addClassOnOver('x-tool-expand-'+this.position+'-over');
  5856. t.on('click', this.onExpandClick, this, {stopEvent:true});
  5857. }
  5858. if(this.floatable !== false || this.titleCollapse){
  5859. this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
  5860. this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
  5861. }
  5862. }
  5863. }
  5864. return this.collapsedEl;
  5865. },
  5866. // private
  5867. onExpandClick : function(e){
  5868. if(this.isSlid){
  5869. this.panel.expand(false);
  5870. }else{
  5871. this.panel.expand();
  5872. }
  5873. },
  5874. // private
  5875. onCollapseClick : function(e){
  5876. this.panel.collapse();
  5877. },
  5878. // private
  5879. beforeCollapse : function(p, animate){
  5880. this.lastAnim = animate;
  5881. if(this.splitEl){
  5882. this.splitEl.hide();
  5883. }
  5884. this.getCollapsedEl().show();
  5885. var el = this.panel.getEl();
  5886. this.originalZIndex = el.getStyle('z-index');
  5887. el.setStyle('z-index', 100);
  5888. this.isCollapsed = true;
  5889. this.layout.layout();
  5890. },
  5891. // private
  5892. onCollapse : function(animate){
  5893. this.panel.el.setStyle('z-index', 1);
  5894. if(this.lastAnim === false || this.panel.animCollapse === false){
  5895. this.getCollapsedEl().dom.style.visibility = 'visible';
  5896. }else{
  5897. this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2});
  5898. }
  5899. this.state.collapsed = true;
  5900. this.panel.saveState();
  5901. },
  5902. // private
  5903. beforeExpand : function(animate){
  5904. if(this.isSlid){
  5905. this.afterSlideIn();
  5906. }
  5907. var c = this.getCollapsedEl();
  5908. this.el.show();
  5909. if(this.position == 'east' || this.position == 'west'){
  5910. this.panel.setSize(undefined, c.getHeight());
  5911. }else{
  5912. this.panel.setSize(c.getWidth(), undefined);
  5913. }
  5914. c.hide();
  5915. c.dom.style.visibility = 'hidden';
  5916. this.panel.el.setStyle('z-index', this.floatingZIndex);
  5917. },
  5918. // private
  5919. onExpand : function(){
  5920. this.isCollapsed = false;
  5921. if(this.splitEl){
  5922. this.splitEl.show();
  5923. }
  5924. this.layout.layout();
  5925. this.panel.el.setStyle('z-index', this.originalZIndex);
  5926. this.state.collapsed = false;
  5927. this.panel.saveState();
  5928. },
  5929. // private
  5930. collapseClick : function(e){
  5931. if(this.isSlid){
  5932. e.stopPropagation();
  5933. this.slideIn();
  5934. }else{
  5935. e.stopPropagation();
  5936. this.slideOut();
  5937. }
  5938. },
  5939. // private
  5940. onHide : function(){
  5941. if(this.isCollapsed){
  5942. this.getCollapsedEl().hide();
  5943. }else if(this.splitEl){
  5944. this.splitEl.hide();
  5945. }
  5946. },
  5947. // private
  5948. onShow : function(){
  5949. if(this.isCollapsed){
  5950. this.getCollapsedEl().show();
  5951. }else if(this.splitEl){
  5952. this.splitEl.show();
  5953. }
  5954. },
  5955. /**
  5956. * True if this region is currently visible, else false.
  5957. * @return {Boolean}
  5958. */
  5959. isVisible : function(){
  5960. return !this.panel.hidden;
  5961. },
  5962. /**
  5963. * Returns the current margins for this region. If the region is collapsed, the
  5964. * {@link #cmargins} (collapsed margins) value will be returned, otherwise the
  5965. * {@link #margins} value will be returned.
  5966. * @return {Object} An object containing the element's margins: <tt>{left: (left
  5967. * margin), top: (top margin), right: (right margin), bottom: (bottom margin)}</tt>
  5968. */
  5969. getMargins : function(){
  5970. return this.isCollapsed && this.cmargins ? this.cmargins : this.margins;
  5971. },
  5972. /**
  5973. * Returns the current size of this region. If the region is collapsed, the size of the
  5974. * collapsedEl will be returned, otherwise the size of the region's panel will be returned.
  5975. * @return {Object} An object containing the element's size: <tt>{width: (element width),
  5976. * height: (element height)}</tt>
  5977. */
  5978. getSize : function(){
  5979. return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize();
  5980. },
  5981. /**
  5982. * Sets the specified panel as the container element for this region.
  5983. * @param {Ext.Panel} panel The new panel
  5984. */
  5985. setPanel : function(panel){
  5986. this.panel = panel;
  5987. },
  5988. /**
  5989. * Returns the minimum allowable width for this region.
  5990. * @return {Number} The minimum width
  5991. */
  5992. getMinWidth: function(){
  5993. return this.minWidth;
  5994. },
  5995. /**
  5996. * Returns the minimum allowable height for this region.
  5997. * @return {Number} The minimum height
  5998. */
  5999. getMinHeight: function(){
  6000. return this.minHeight;
  6001. },
  6002. // private
  6003. applyLayoutCollapsed : function(box){
  6004. var ce = this.getCollapsedEl();
  6005. ce.setLeftTop(box.x, box.y);
  6006. ce.setSize(box.width, box.height);
  6007. },
  6008. // private
  6009. applyLayout : function(box){
  6010. if(this.isCollapsed){
  6011. this.applyLayoutCollapsed(box);
  6012. }else{
  6013. this.panel.setPosition(box.x, box.y);
  6014. this.panel.setSize(box.width, box.height);
  6015. }
  6016. },
  6017. // private
  6018. beforeSlide: function(){
  6019. this.panel.beforeEffect();
  6020. },
  6021. // private
  6022. afterSlide : function(){
  6023. this.panel.afterEffect();
  6024. },
  6025. // private
  6026. initAutoHide : function(){
  6027. if(this.autoHide !== false){
  6028. if(!this.autoHideHd){
  6029. this.autoHideSlideTask = new Ext.util.DelayedTask(this.slideIn, this);
  6030. this.autoHideHd = {
  6031. "mouseout": function(e){
  6032. if(!e.within(this.el, true)){
  6033. this.autoHideSlideTask.delay(500);
  6034. }
  6035. },
  6036. "mouseover" : function(e){
  6037. this.autoHideSlideTask.cancel();
  6038. },
  6039. scope : this
  6040. };
  6041. }
  6042. this.el.on(this.autoHideHd);
  6043. this.collapsedEl.on(this.autoHideHd);
  6044. }
  6045. },
  6046. // private
  6047. clearAutoHide : function(){
  6048. if(this.autoHide !== false){
  6049. this.el.un("mouseout", this.autoHideHd.mouseout);
  6050. this.el.un("mouseover", this.autoHideHd.mouseover);
  6051. this.collapsedEl.un("mouseout", this.autoHideHd.mouseout);
  6052. this.collapsedEl.un("mouseover", this.autoHideHd.mouseover);
  6053. }
  6054. },
  6055. // private
  6056. clearMonitor : function(){
  6057. Ext.getDoc().un("click", this.slideInIf, this);
  6058. },
  6059. /**
  6060. * If this Region is {@link #floatable}, this method slides this Region into full visibility <i>over the top
  6061. * of the center Region</i> where it floats until either {@link #slideIn} is called, or other regions of the layout
  6062. * are clicked, or the mouse exits the Region.
  6063. */
  6064. slideOut : function(){
  6065. if(this.isSlid || this.el.hasActiveFx()){
  6066. return;
  6067. }
  6068. this.isSlid = true;
  6069. var ts = this.panel.tools, dh, pc;
  6070. if(ts && ts.toggle){
  6071. ts.toggle.hide();
  6072. }
  6073. this.el.show();
  6074. // Temporarily clear the collapsed flag so we can onResize the panel on the slide
  6075. pc = this.panel.collapsed;
  6076. this.panel.collapsed = false;
  6077. if(this.position == 'east' || this.position == 'west'){
  6078. // Temporarily clear the deferHeight flag so we can size the height on the slide
  6079. dh = this.panel.deferHeight;
  6080. this.panel.deferHeight = false;
  6081. this.panel.setSize(undefined, this.collapsedEl.getHeight());
  6082. // Put the deferHeight flag back after setSize
  6083. this.panel.deferHeight = dh;
  6084. }else{
  6085. this.panel.setSize(this.collapsedEl.getWidth(), undefined);
  6086. }
  6087. // Put the collapsed flag back after onResize
  6088. this.panel.collapsed = pc;
  6089. this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top];
  6090. this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
  6091. this.el.setStyle("z-index", this.floatingZIndex+2);
  6092. this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating');
  6093. if(this.animFloat !== false){
  6094. this.beforeSlide();
  6095. this.el.slideIn(this.getSlideAnchor(), {
  6096. callback: function(){
  6097. this.afterSlide();
  6098. this.initAutoHide();
  6099. Ext.getDoc().on("click", this.slideInIf, this);
  6100. },
  6101. scope: this,
  6102. block: true
  6103. });
  6104. }else{
  6105. this.initAutoHide();
  6106. Ext.getDoc().on("click", this.slideInIf, this);
  6107. }
  6108. },
  6109. // private
  6110. afterSlideIn : function(){
  6111. this.clearAutoHide();
  6112. this.isSlid = false;
  6113. this.clearMonitor();
  6114. this.el.setStyle("z-index", "");
  6115. this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed');
  6116. this.el.dom.style.left = this.restoreLT[0];
  6117. this.el.dom.style.top = this.restoreLT[1];
  6118. var ts = this.panel.tools;
  6119. if(ts && ts.toggle){
  6120. ts.toggle.show();
  6121. }
  6122. },
  6123. /**
  6124. * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides
  6125. * this region back into its collapsed state.
  6126. */
  6127. slideIn : function(cb){
  6128. if(!this.isSlid || this.el.hasActiveFx()){
  6129. Ext.callback(cb);
  6130. return;
  6131. }
  6132. this.isSlid = false;
  6133. if(this.animFloat !== false){
  6134. this.beforeSlide();
  6135. this.el.slideOut(this.getSlideAnchor(), {
  6136. callback: function(){
  6137. this.el.hide();
  6138. this.afterSlide();
  6139. this.afterSlideIn();
  6140. Ext.callback(cb);
  6141. },
  6142. scope: this,
  6143. block: true
  6144. });
  6145. }else{
  6146. this.el.hide();
  6147. this.afterSlideIn();
  6148. }
  6149. },
  6150. // private
  6151. slideInIf : function(e){
  6152. if(!e.within(this.el)){
  6153. this.slideIn();
  6154. }
  6155. },
  6156. // private
  6157. anchors : {
  6158. "west" : "left",
  6159. "east" : "right",
  6160. "north" : "top",
  6161. "south" : "bottom"
  6162. },
  6163. // private
  6164. sanchors : {
  6165. "west" : "l",
  6166. "east" : "r",
  6167. "north" : "t",
  6168. "south" : "b"
  6169. },
  6170. // private
  6171. canchors : {
  6172. "west" : "tl-tr",
  6173. "east" : "tr-tl",
  6174. "north" : "tl-bl",
  6175. "south" : "bl-tl"
  6176. },
  6177. // private
  6178. getAnchor : function(){
  6179. return this.anchors[this.position];
  6180. },
  6181. // private
  6182. getCollapseAnchor : function(){
  6183. return this.canchors[this.position];
  6184. },
  6185. // private
  6186. getSlideAnchor : function(){
  6187. return this.sanchors[this.position];
  6188. },
  6189. // private
  6190. getAlignAdj : function(){
  6191. var cm = this.cmargins;
  6192. switch(this.position){
  6193. case "west":
  6194. return [0, 0];
  6195. break;
  6196. case "east":
  6197. return [0, 0];
  6198. break;
  6199. case "north":
  6200. return [0, 0];
  6201. break;
  6202. case "south":
  6203. return [0, 0];
  6204. break;
  6205. }
  6206. },
  6207. // private
  6208. getExpandAdj : function(){
  6209. var c = this.collapsedEl, cm = this.cmargins;
  6210. switch(this.position){
  6211. case "west":
  6212. return [-(cm.right+c.getWidth()+cm.left), 0];
  6213. break;
  6214. case "east":
  6215. return [cm.right+c.getWidth()+cm.left, 0];
  6216. break;
  6217. case "north":
  6218. return [0, -(cm.top+cm.bottom+c.getHeight())];
  6219. break;
  6220. case "south":
  6221. return [0, cm.top+cm.bottom+c.getHeight()];
  6222. break;
  6223. }
  6224. },
  6225. destroy : function(){
  6226. if (this.autoHideSlideTask && this.autoHideSlideTask.cancel){
  6227. this.autoHideSlideTask.cancel();
  6228. }
  6229. Ext.destroy(this.miniCollapsedEl, this.collapsedEl);
  6230. }
  6231. };
  6232. /**
  6233. * @class Ext.layout.BorderLayout.SplitRegion
  6234. * @extends Ext.layout.BorderLayout.Region
  6235. * <p>This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that
  6236. * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar
  6237. * is configurable to move either {@link #tickSize smooth or incrementally}.</p>
  6238. * @constructor
  6239. * Create a new SplitRegion.
  6240. * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
  6241. * @param {Object} config The configuration options
  6242. * @param {String} position The region position. Valid values are: north, south, east, west and center. Every
  6243. * BorderLayout must have a center region for the primary content -- all other regions are optional.
  6244. */
  6245. Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){
  6246. Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos);
  6247. // prevent switch
  6248. this.applyLayout = this.applyFns[pos];
  6249. };
  6250. Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {
  6251. /**
  6252. * @cfg {Number} tickSize
  6253. * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}.
  6254. * By default, the {@link Ext.SplitBar SplitBar} moves smoothly.
  6255. */
  6256. /**
  6257. * @cfg {String} splitTip
  6258. * The tooltip to display when the user hovers over a
  6259. * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar
  6260. * (defaults to <tt>"Drag to resize."</tt>). Only applies if
  6261. * <tt>{@link #useSplitTips} = true</tt>.
  6262. */
  6263. splitTip : "Drag to resize.",
  6264. /**
  6265. * @cfg {String} collapsibleSplitTip
  6266. * The tooltip to display when the user hovers over a
  6267. * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar
  6268. * (defaults to "Drag to resize. Double click to hide."). Only applies if
  6269. * <tt>{@link #useSplitTips} = true</tt>.
  6270. */
  6271. collapsibleSplitTip : "Drag to resize. Double click to hide.",
  6272. /**
  6273. * @cfg {Boolean} useSplitTips
  6274. * <tt>true</tt> to display a tooltip when the user hovers over a region's split bar
  6275. * (defaults to <tt>false</tt>). The tooltip text will be the value of either
  6276. * <tt>{@link #splitTip}</tt> or <tt>{@link #collapsibleSplitTip}</tt> as appropriate.
  6277. */
  6278. useSplitTips : false,
  6279. // private
  6280. splitSettings : {
  6281. north : {
  6282. orientation: Ext.SplitBar.VERTICAL,
  6283. placement: Ext.SplitBar.TOP,
  6284. maxFn : 'getVMaxSize',
  6285. minProp: 'minHeight',
  6286. maxProp: 'maxHeight'
  6287. },
  6288. south : {
  6289. orientation: Ext.SplitBar.VERTICAL,
  6290. placement: Ext.SplitBar.BOTTOM,
  6291. maxFn : 'getVMaxSize',
  6292. minProp: 'minHeight',
  6293. maxProp: 'maxHeight'
  6294. },
  6295. east : {
  6296. orientation: Ext.SplitBar.HORIZONTAL,
  6297. placement: Ext.SplitBar.RIGHT,
  6298. maxFn : 'getHMaxSize',
  6299. minProp: 'minWidth',
  6300. maxProp: 'maxWidth'
  6301. },
  6302. west : {
  6303. orientation: Ext.SplitBar.HORIZONTAL,
  6304. placement: Ext.SplitBar.LEFT,
  6305. maxFn : 'getHMaxSize',
  6306. minProp: 'minWidth',
  6307. maxProp: 'maxWidth'
  6308. }
  6309. },
  6310. // private
  6311. applyFns : {
  6312. west : function(box){
  6313. if(this.isCollapsed){
  6314. return this.applyLayoutCollapsed(box);
  6315. }
  6316. var sd = this.splitEl.dom, s = sd.style;
  6317. this.panel.setPosition(box.x, box.y);
  6318. var sw = sd.offsetWidth;
  6319. s.left = (box.x+box.width-sw)+'px';
  6320. s.top = (box.y)+'px';
  6321. s.height = Math.max(0, box.height)+'px';
  6322. this.panel.setSize(box.width-sw, box.height);
  6323. },
  6324. east : function(box){
  6325. if(this.isCollapsed){
  6326. return this.applyLayoutCollapsed(box);
  6327. }
  6328. var sd = this.splitEl.dom, s = sd.style;
  6329. var sw = sd.offsetWidth;
  6330. this.panel.setPosition(box.x+sw, box.y);
  6331. s.left = (box.x)+'px';
  6332. s.top = (box.y)+'px';
  6333. s.height = Math.max(0, box.height)+'px';
  6334. this.panel.setSize(box.width-sw, box.height);
  6335. },
  6336. north : function(box){
  6337. if(this.isCollapsed){
  6338. return this.applyLayoutCollapsed(box);
  6339. }
  6340. var sd = this.splitEl.dom, s = sd.style;
  6341. var sh = sd.offsetHeight;
  6342. this.panel.setPosition(box.x, box.y);
  6343. s.left = (box.x)+'px';
  6344. s.top = (box.y+box.height-sh)+'px';
  6345. s.width = Math.max(0, box.width)+'px';
  6346. this.panel.setSize(box.width, box.height-sh);
  6347. },
  6348. south : function(box){
  6349. if(this.isCollapsed){
  6350. return this.applyLayoutCollapsed(box);
  6351. }
  6352. var sd = this.splitEl.dom, s = sd.style;
  6353. var sh = sd.offsetHeight;
  6354. this.panel.setPosition(box.x, box.y+sh);
  6355. s.left = (box.x)+'px';
  6356. s.top = (box.y)+'px';
  6357. s.width = Math.max(0, box.width)+'px';
  6358. this.panel.setSize(box.width, box.height-sh);
  6359. }
  6360. },
  6361. // private
  6362. render : function(ct, p){
  6363. Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p);
  6364. var ps = this.position;
  6365. this.splitEl = ct.createChild({
  6366. cls: "x-layout-split x-layout-split-"+ps, html: "&#160;",
  6367. id: this.panel.id + '-xsplit'
  6368. });
  6369. if(this.collapseMode == 'mini'){
  6370. this.miniSplitEl = this.splitEl.createChild({
  6371. cls: "x-layout-mini x-layout-mini-"+ps, html: "&#160;"
  6372. });
  6373. this.miniSplitEl.addClassOnOver('x-layout-mini-over');
  6374. this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true});
  6375. }
  6376. var s = this.splitSettings[ps];
  6377. this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation);
  6378. this.split.tickSize = this.tickSize;
  6379. this.split.placement = s.placement;
  6380. this.split.getMaximumSize = this[s.maxFn].createDelegate(this);
  6381. this.split.minSize = this.minSize || this[s.minProp];
  6382. this.split.on("beforeapply", this.onSplitMove, this);
  6383. this.split.useShim = this.useShim === true;
  6384. this.maxSize = this.maxSize || this[s.maxProp];
  6385. if(p.hidden){
  6386. this.splitEl.hide();
  6387. }
  6388. if(this.useSplitTips){
  6389. this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip;
  6390. }
  6391. if(this.collapsible){
  6392. this.splitEl.on("dblclick", this.onCollapseClick, this);
  6393. }
  6394. },
  6395. //docs inherit from superclass
  6396. getSize : function(){
  6397. if(this.isCollapsed){
  6398. return this.collapsedEl.getSize();
  6399. }
  6400. var s = this.panel.getSize();
  6401. if(this.position == 'north' || this.position == 'south'){
  6402. s.height += this.splitEl.dom.offsetHeight;
  6403. }else{
  6404. s.width += this.splitEl.dom.offsetWidth;
  6405. }
  6406. return s;
  6407. },
  6408. // private
  6409. getHMaxSize : function(){
  6410. var cmax = this.maxSize || 10000;
  6411. var center = this.layout.center;
  6412. return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth());
  6413. },
  6414. // private
  6415. getVMaxSize : function(){
  6416. var cmax = this.maxSize || 10000;
  6417. var center = this.layout.center;
  6418. return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight());
  6419. },
  6420. // private
  6421. onSplitMove : function(split, newSize){
  6422. var s = this.panel.getSize();
  6423. this.lastSplitSize = newSize;
  6424. if(this.position == 'north' || this.position == 'south'){
  6425. this.panel.setSize(s.width, newSize);
  6426. this.state.height = newSize;
  6427. }else{
  6428. this.panel.setSize(newSize, s.height);
  6429. this.state.width = newSize;
  6430. }
  6431. this.layout.layout();
  6432. this.panel.saveState();
  6433. return false;
  6434. },
  6435. /**
  6436. * Returns a reference to the split bar in use by this region.
  6437. * @return {Ext.SplitBar} The split bar
  6438. */
  6439. getSplitBar : function(){
  6440. return this.split;
  6441. },
  6442. // inherit docs
  6443. destroy : function() {
  6444. Ext.destroy(this.miniSplitEl, this.split, this.splitEl);
  6445. Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this);
  6446. }
  6447. });
  6448. Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;/**
  6449. * @class Ext.layout.FormLayout
  6450. * @extends Ext.layout.AnchorLayout
  6451. * <p>This layout manager is specifically designed for rendering and managing child Components of
  6452. * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of
  6453. * {@link Ext.form.Field Field}s.</p>
  6454. *
  6455. * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt>
  6456. * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly
  6457. * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
  6458. *
  6459. * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel}
  6460. * (which is configured with FormLayout as its layout class by default) since it also provides built-in
  6461. * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p>
  6462. *
  6463. * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g.
  6464. * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following
  6465. * layout-specific config properties:<div class="mdetail-params"><ul>
  6466. * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li>
  6467. * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li>
  6468. * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li>
  6469. * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li>
  6470. * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li>
  6471. * </ul></div></p>
  6472. *
  6473. * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option:
  6474. * <div class="mdetail-params"><ul>
  6475. * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li>
  6476. * </ul></div></p>
  6477. *
  6478. * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by
  6479. * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured
  6480. * in this way may be configured with the following options which affect the way the FormLayout renders them:
  6481. * <div class="mdetail-params"><ul>
  6482. * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li>
  6483. * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li>
  6484. * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li>
  6485. * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li>
  6486. * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li>
  6487. * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li>
  6488. * </ul></div></p>
  6489. *
  6490. * <p>Example usage:</p>
  6491. * <pre><code>
  6492. // Required if showing validation messages
  6493. Ext.QuickTips.init();
  6494. // While you can create a basic Panel with layout:'form', practically
  6495. // you should usually use a FormPanel to also get its form functionality
  6496. // since it already creates a FormLayout internally.
  6497. var form = new Ext.form.FormPanel({
  6498. title: 'Form Layout',
  6499. bodyStyle: 'padding:15px',
  6500. width: 350,
  6501. defaultType: 'textfield',
  6502. defaults: {
  6503. // applied to each contained item
  6504. width: 230,
  6505. msgTarget: 'side'
  6506. },
  6507. items: [{
  6508. fieldLabel: 'First Name',
  6509. name: 'first',
  6510. allowBlank: false,
  6511. {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
  6512. },{
  6513. fieldLabel: 'Last Name',
  6514. name: 'last'
  6515. },{
  6516. fieldLabel: 'Email',
  6517. name: 'email',
  6518. vtype:'email'
  6519. }, {
  6520. xtype: 'textarea',
  6521. hideLabel: true, // override hideLabels layout config
  6522. name: 'msg',
  6523. anchor: '100% -53'
  6524. }
  6525. ],
  6526. buttons: [
  6527. {text: 'Save'},
  6528. {text: 'Cancel'}
  6529. ],
  6530. layoutConfig: {
  6531. {@link #labelSeparator}: '~' // superseded by assignment below
  6532. },
  6533. // config options applicable to container when layout='form':
  6534. hideLabels: false,
  6535. labelAlign: 'left', // or 'right' or 'top'
  6536. {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
  6537. labelWidth: 65, // defaults to 100
  6538. labelPad: 8 // defaults to 5, must specify labelWidth to be honored
  6539. });
  6540. </code></pre>
  6541. */
  6542. Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
  6543. /**
  6544. * @cfg {String} labelSeparator
  6545. * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration
  6546. * of this property at the <b>container</b> level takes precedence.
  6547. */
  6548. labelSeparator : ':',
  6549. /**
  6550. * Read only. The CSS style specification string added to field labels in this layout if not
  6551. * otherwise {@link Ext.Component#labelStyle specified by each contained field}.
  6552. * @type String
  6553. * @property labelStyle
  6554. */
  6555. /**
  6556. * @cfg {Boolean} trackLabels
  6557. * True to show/hide the field label when the field is hidden. Defaults to <tt>false</tt>.
  6558. */
  6559. trackLabels: false,
  6560. type: 'form',
  6561. onRemove: function(c){
  6562. Ext.layout.FormLayout.superclass.onRemove.call(this, c);
  6563. if(this.trackLabels){
  6564. c.un('show', this.onFieldShow, this);
  6565. c.un('hide', this.onFieldHide, this);
  6566. }
  6567. // check for itemCt, since we may be removing a fieldset or something similar
  6568. var el = c.getPositionEl(),
  6569. ct = c.getItemCt && c.getItemCt();
  6570. if (c.rendered && ct) {
  6571. if (el && el.dom) {
  6572. el.insertAfter(ct);
  6573. }
  6574. Ext.destroy(ct);
  6575. Ext.destroyMembers(c, 'label', 'itemCt');
  6576. if (c.customItemCt) {
  6577. Ext.destroyMembers(c, 'getItemCt', 'customItemCt');
  6578. }
  6579. }
  6580. },
  6581. // private
  6582. setContainer : function(ct){
  6583. Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
  6584. if(ct.labelAlign){
  6585. ct.addClass('x-form-label-'+ct.labelAlign);
  6586. }
  6587. if(ct.hideLabels){
  6588. Ext.apply(this, {
  6589. labelStyle: 'display:none',
  6590. elementStyle: 'padding-left:0;',
  6591. labelAdjust: 0
  6592. });
  6593. }else{
  6594. this.labelSeparator = ct.labelSeparator || this.labelSeparator;
  6595. ct.labelWidth = ct.labelWidth || 100;
  6596. if(Ext.isNumber(ct.labelWidth)){
  6597. var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
  6598. Ext.apply(this, {
  6599. labelAdjust: ct.labelWidth + pad,
  6600. labelStyle: 'width:' + ct.labelWidth + 'px;',
  6601. elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px'
  6602. });
  6603. }
  6604. if(ct.labelAlign == 'top'){
  6605. Ext.apply(this, {
  6606. labelStyle: 'width:auto;',
  6607. labelAdjust: 0,
  6608. elementStyle: 'padding-left:0;'
  6609. });
  6610. }
  6611. }
  6612. },
  6613. // private
  6614. isHide: function(c){
  6615. return c.hideLabel || this.container.hideLabels;
  6616. },
  6617. onFieldShow: function(c){
  6618. c.getItemCt().removeClass('x-hide-' + c.hideMode);
  6619. },
  6620. onFieldHide: function(c){
  6621. c.getItemCt().addClass('x-hide-' + c.hideMode);
  6622. },
  6623. //private
  6624. getLabelStyle: function(s){
  6625. var ls = '', items = [this.labelStyle, s];
  6626. for (var i = 0, len = items.length; i < len; ++i){
  6627. if (items[i]){
  6628. ls += items[i];
  6629. if (ls.substr(-1, 1) != ';'){
  6630. ls += ';';
  6631. }
  6632. }
  6633. }
  6634. return ls;
  6635. },
  6636. /**
  6637. * @cfg {Ext.Template} fieldTpl
  6638. * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering
  6639. * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code>
  6640. new Ext.Template(
  6641. &#39;&lt;div class="x-form-item {itemCls}" tabIndex="-1">&#39;,
  6642. &#39;&lt;&#108;abel for="{id}" style="{labelStyle}" class="x-form-item-&#108;abel">{&#108;abel}{labelSeparator}&lt;/&#108;abel>&#39;,
  6643. &#39;&lt;div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">&#39;,
  6644. &#39;&lt;/div>&lt;div class="{clearCls}">&lt;/div>&#39;,
  6645. '&lt;/div>'
  6646. );
  6647. </code></pre>
  6648. * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p>
  6649. * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul>
  6650. * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
  6651. * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
  6652. * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
  6653. * supplied at the container level.</div></li>
  6654. * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
  6655. * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
  6656. * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
  6657. * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
  6658. * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
  6659. * field (defaults to <tt>''</tt>)</div></li>
  6660. * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
  6661. * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
  6662. * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
  6663. * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
  6664. * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
  6665. * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
  6666. * </ul></div>
  6667. * <p>Also see <tt>{@link #getTemplateArgs}</tt></p>
  6668. */
  6669. /**
  6670. * @private
  6671. *
  6672. */
  6673. renderItem : function(c, position, target){
  6674. if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
  6675. var args = this.getTemplateArgs(c);
  6676. if(Ext.isNumber(position)){
  6677. position = target.dom.childNodes[position] || null;
  6678. }
  6679. if(position){
  6680. c.itemCt = this.fieldTpl.insertBefore(position, args, true);
  6681. }else{
  6682. c.itemCt = this.fieldTpl.append(target, args, true);
  6683. }
  6684. if(!c.getItemCt){
  6685. // Non form fields don't have getItemCt, apply it here
  6686. // This will get cleaned up in onRemove
  6687. Ext.apply(c, {
  6688. getItemCt: function(){
  6689. return c.itemCt;
  6690. },
  6691. customItemCt: true
  6692. });
  6693. }
  6694. c.label = c.getItemCt().child('label.x-form-item-label');
  6695. if(!c.rendered){
  6696. c.render('x-form-el-' + c.id);
  6697. }else if(!this.isValidParent(c, target)){
  6698. Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
  6699. }
  6700. if(this.trackLabels){
  6701. if(c.hidden){
  6702. this.onFieldHide(c);
  6703. }
  6704. c.on({
  6705. scope: this,
  6706. show: this.onFieldShow,
  6707. hide: this.onFieldHide
  6708. });
  6709. }
  6710. this.configureItem(c);
  6711. }else {
  6712. Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
  6713. }
  6714. },
  6715. /**
  6716. * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p>
  6717. * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
  6718. * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
  6719. * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
  6720. * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
  6721. * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
  6722. * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
  6723. * supplied at the container level.</div></li>
  6724. * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
  6725. * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
  6726. * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
  6727. * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
  6728. * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
  6729. * field (defaults to the field's configured fieldLabel property)</div></li>
  6730. * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
  6731. * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
  6732. * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
  6733. * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
  6734. * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
  6735. * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
  6736. * </ul></div>
  6737. * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
  6738. * @return {Object} An object hash containing the properties required to render the Field.
  6739. */
  6740. getTemplateArgs: function(field) {
  6741. var noLabelSep = !field.fieldLabel || field.hideLabel;
  6742. return {
  6743. id : field.id,
  6744. label : field.fieldLabel,
  6745. itemCls : (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''),
  6746. clearCls : field.clearCls || 'x-form-clear-left',
  6747. labelStyle : this.getLabelStyle(field.labelStyle),
  6748. elementStyle : this.elementStyle || '',
  6749. labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator)
  6750. };
  6751. },
  6752. // private
  6753. adjustWidthAnchor: function(value, c){
  6754. if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){
  6755. var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict);
  6756. return value - this.labelAdjust + (adjust ? -3 : 0);
  6757. }
  6758. return value;
  6759. },
  6760. adjustHeightAnchor : function(value, c){
  6761. if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
  6762. return value - c.label.getHeight();
  6763. }
  6764. return value;
  6765. },
  6766. // private
  6767. isValidParent : function(c, target){
  6768. return target && this.container.getEl().contains(c.getPositionEl());
  6769. }
  6770. /**
  6771. * @property activeItem
  6772. * @hide
  6773. */
  6774. });
  6775. Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;
  6776. /**
  6777. * @class Ext.layout.AccordionLayout
  6778. * @extends Ext.layout.FitLayout
  6779. * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
  6780. * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
  6781. * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.Panel</b> may be used in an accordion layout Container.</p>
  6782. * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
  6783. * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
  6784. * <p>Example usage:</p>
  6785. * <pre><code>
  6786. var accordion = new Ext.Panel({
  6787. title: 'Accordion Layout',
  6788. layout:'accordion',
  6789. defaults: {
  6790. // applied to each contained panel
  6791. bodyStyle: 'padding:15px'
  6792. },
  6793. layoutConfig: {
  6794. // layout-specific configs go here
  6795. titleCollapse: false,
  6796. animate: true,
  6797. activeOnTop: true
  6798. },
  6799. items: [{
  6800. title: 'Panel 1',
  6801. html: '&lt;p&gt;Panel content!&lt;/p&gt;'
  6802. },{
  6803. title: 'Panel 2',
  6804. html: '&lt;p&gt;Panel content!&lt;/p&gt;'
  6805. },{
  6806. title: 'Panel 3',
  6807. html: '&lt;p&gt;Panel content!&lt;/p&gt;'
  6808. }]
  6809. });
  6810. </code></pre>
  6811. */
  6812. Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
  6813. /**
  6814. * @cfg {Boolean} fill
  6815. * True to adjust the active item's height to fill the available space in the container, false to use the
  6816. * item's current height, or auto height if not explicitly set (defaults to true).
  6817. */
  6818. fill : true,
  6819. /**
  6820. * @cfg {Boolean} autoWidth
  6821. * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true).
  6822. * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within
  6823. * layouts if they have auto width, so in such cases this config should be set to false.
  6824. */
  6825. autoWidth : true,
  6826. /**
  6827. * @cfg {Boolean} titleCollapse
  6828. * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
  6829. * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false,
  6830. * {@link #hideCollapseTool} should be false also.
  6831. */
  6832. titleCollapse : true,
  6833. /**
  6834. * @cfg {Boolean} hideCollapseTool
  6835. * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false).
  6836. * When set to true, {@link #titleCollapse} should be true also.
  6837. */
  6838. hideCollapseTool : false,
  6839. /**
  6840. * @cfg {Boolean} collapseFirst
  6841. * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
  6842. * in the contained panels' title bars, false to render it last (defaults to false).
  6843. */
  6844. collapseFirst : false,
  6845. /**
  6846. * @cfg {Boolean} animate
  6847. * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
  6848. * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each
  6849. * contained panel for this property, set this to undefined at the layout level.
  6850. */
  6851. animate : false,
  6852. /**
  6853. * @cfg {Boolean} sequence
  6854. * <b>Experimental</b>. If animate is set to true, this will result in each animation running in sequence.
  6855. */
  6856. sequence : false,
  6857. /**
  6858. * @cfg {Boolean} activeOnTop
  6859. * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
  6860. * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
  6861. */
  6862. activeOnTop : false,
  6863. type: 'accordion',
  6864. renderItem : function(c){
  6865. if(this.animate === false){
  6866. c.animCollapse = false;
  6867. }
  6868. c.collapsible = true;
  6869. if(this.autoWidth){
  6870. c.autoWidth = true;
  6871. }
  6872. if(this.titleCollapse){
  6873. c.titleCollapse = true;
  6874. }
  6875. if(this.hideCollapseTool){
  6876. c.hideCollapseTool = true;
  6877. }
  6878. if(this.collapseFirst !== undefined){
  6879. c.collapseFirst = this.collapseFirst;
  6880. }
  6881. if(!this.activeItem && !c.collapsed){
  6882. this.setActiveItem(c, true);
  6883. }else if(this.activeItem && this.activeItem != c){
  6884. c.collapsed = true;
  6885. }
  6886. Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments);
  6887. c.header.addClass('x-accordion-hd');
  6888. c.on('beforeexpand', this.beforeExpand, this);
  6889. },
  6890. onRemove: function(c){
  6891. Ext.layout.AccordionLayout.superclass.onRemove.call(this, c);
  6892. if(c.rendered){
  6893. c.header.removeClass('x-accordion-hd');
  6894. }
  6895. c.un('beforeexpand', this.beforeExpand, this);
  6896. },
  6897. // private
  6898. beforeExpand : function(p, anim){
  6899. var ai = this.activeItem;
  6900. if(ai){
  6901. if(this.sequence){
  6902. delete this.activeItem;
  6903. if (!ai.collapsed){
  6904. ai.collapse({callback:function(){
  6905. p.expand(anim || true);
  6906. }, scope: this});
  6907. return false;
  6908. }
  6909. }else{
  6910. ai.collapse(this.animate);
  6911. }
  6912. }
  6913. this.setActive(p);
  6914. if(this.activeOnTop){
  6915. p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
  6916. }
  6917. // Items have been hidden an possibly rearranged, we need to get the container size again.
  6918. this.layout();
  6919. },
  6920. // private
  6921. setItemSize : function(item, size){
  6922. if(this.fill && item){
  6923. var hh = 0, i, ct = this.getRenderedItems(this.container), len = ct.length, p;
  6924. // Add up all the header heights
  6925. for (i = 0; i < len; i++) {
  6926. if((p = ct[i]) != item){
  6927. hh += p.header.getHeight();
  6928. }
  6929. };
  6930. // Subtract the header heights from the container size
  6931. size.height -= hh;
  6932. // Call setSize on the container to set the correct height. For Panels, deferedHeight
  6933. // will simply store this size for when the expansion is done.
  6934. item.setSize(size);
  6935. }
  6936. },
  6937. /**
  6938. * Sets the active (expanded) item in the layout.
  6939. * @param {String/Number} item The string component id or numeric index of the item to activate
  6940. */
  6941. setActiveItem : function(item){
  6942. this.setActive(item, true);
  6943. },
  6944. // private
  6945. setActive : function(item, expand){
  6946. var ai = this.activeItem;
  6947. item = this.container.getComponent(item);
  6948. if(ai != item){
  6949. if(item.rendered && item.collapsed && expand){
  6950. item.expand();
  6951. }else{
  6952. if(ai){
  6953. ai.fireEvent('deactivate', ai);
  6954. }
  6955. this.activeItem = item;
  6956. item.fireEvent('activate', item);
  6957. }
  6958. }
  6959. }
  6960. });
  6961. Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
  6962. //backwards compat
  6963. Ext.layout.Accordion = Ext.layout.AccordionLayout;/**
  6964. * @class Ext.layout.TableLayout
  6965. * @extends Ext.layout.ContainerLayout
  6966. * <p>This layout allows you to easily render content into an HTML table. The total number of columns can be
  6967. * specified, and rowspan and colspan can be used to create complex layouts within the table.
  6968. * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
  6969. * and should generally not need to be created directly via the new keyword.</p>
  6970. * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
  6971. * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the
  6972. * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a
  6973. * TableLayout can supply the following table-specific config properties:</p>
  6974. * <ul>
  6975. * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
  6976. * <li><b>colspan</b> Applied to the table cell containing the item.</li>
  6977. * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
  6978. * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
  6979. * </ul>
  6980. * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
  6981. * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes
  6982. * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
  6983. * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
  6984. * total column count in the layoutConfig and start adding panels in their natural order from left to right,
  6985. * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans,
  6986. * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add
  6987. * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:</p>
  6988. * <pre><code>
  6989. // This code will generate a layout table that is 3 columns by 2 rows
  6990. // with some spanning included. The basic layout will be:
  6991. // +--------+-----------------+
  6992. // | A | B |
  6993. // | |--------+--------|
  6994. // | | C | D |
  6995. // +--------+--------+--------+
  6996. var table = new Ext.Panel({
  6997. title: 'Table Layout',
  6998. layout:'table',
  6999. defaults: {
  7000. // applied to each contained panel
  7001. bodyStyle:'padding:20px'
  7002. },
  7003. layoutConfig: {
  7004. // The total column count must be specified here
  7005. columns: 3
  7006. },
  7007. items: [{
  7008. html: '&lt;p&gt;Cell A content&lt;/p&gt;',
  7009. rowspan: 2
  7010. },{
  7011. html: '&lt;p&gt;Cell B content&lt;/p&gt;',
  7012. colspan: 2
  7013. },{
  7014. html: '&lt;p&gt;Cell C content&lt;/p&gt;',
  7015. cellCls: 'highlight'
  7016. },{
  7017. html: '&lt;p&gt;Cell D content&lt;/p&gt;'
  7018. }]
  7019. });
  7020. </code></pre>
  7021. */
  7022. Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
  7023. /**
  7024. * @cfg {Number} columns
  7025. * The total number of columns to create in the table for this layout. If not specified, all Components added to
  7026. * this layout will be rendered into a single row using one column per Component.
  7027. */
  7028. // private
  7029. monitorResize:false,
  7030. type: 'table',
  7031. targetCls: 'x-table-layout-ct',
  7032. /**
  7033. * @cfg {Object} tableAttrs
  7034. * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
  7035. * used to create the layout's <tt>&lt;table&gt;</tt> element. Example:</p><pre><code>
  7036. {
  7037. xtype: 'panel',
  7038. layout: 'table',
  7039. layoutConfig: {
  7040. tableAttrs: {
  7041. style: {
  7042. width: '100%'
  7043. }
  7044. },
  7045. columns: 3
  7046. }
  7047. }</code></pre>
  7048. */
  7049. tableAttrs:null,
  7050. // private
  7051. setContainer : function(ct){
  7052. Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
  7053. this.currentRow = 0;
  7054. this.currentColumn = 0;
  7055. this.cells = [];
  7056. },
  7057. // private
  7058. onLayout : function(ct, target){
  7059. var cs = ct.items.items, len = cs.length, c, i;
  7060. if(!this.table){
  7061. target.addClass('x-table-layout-ct');
  7062. this.table = target.createChild(
  7063. Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
  7064. }
  7065. this.renderAll(ct, target);
  7066. },
  7067. // private
  7068. getRow : function(index){
  7069. var row = this.table.tBodies[0].childNodes[index];
  7070. if(!row){
  7071. row = document.createElement('tr');
  7072. this.table.tBodies[0].appendChild(row);
  7073. }
  7074. return row;
  7075. },
  7076. // private
  7077. getNextCell : function(c){
  7078. var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
  7079. var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
  7080. for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
  7081. if(!this.cells[rowIndex]){
  7082. this.cells[rowIndex] = [];
  7083. }
  7084. for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
  7085. this.cells[rowIndex][colIndex] = true;
  7086. }
  7087. }
  7088. var td = document.createElement('td');
  7089. if(c.cellId){
  7090. td.id = c.cellId;
  7091. }
  7092. var cls = 'x-table-layout-cell';
  7093. if(c.cellCls){
  7094. cls += ' ' + c.cellCls;
  7095. }
  7096. td.className = cls;
  7097. if(c.colspan){
  7098. td.colSpan = c.colspan;
  7099. }
  7100. if(c.rowspan){
  7101. td.rowSpan = c.rowspan;
  7102. }
  7103. this.getRow(curRow).appendChild(td);
  7104. return td;
  7105. },
  7106. // private
  7107. getNextNonSpan: function(colIndex, rowIndex){
  7108. var cols = this.columns;
  7109. while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
  7110. if(cols && colIndex >= cols){
  7111. rowIndex++;
  7112. colIndex = 0;
  7113. }else{
  7114. colIndex++;
  7115. }
  7116. }
  7117. return [colIndex, rowIndex];
  7118. },
  7119. // private
  7120. renderItem : function(c, position, target){
  7121. // Ensure we have our inner table to get cells to render into.
  7122. if(!this.table){
  7123. this.table = target.createChild(
  7124. Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
  7125. }
  7126. if(c && !c.rendered){
  7127. c.render(this.getNextCell(c));
  7128. this.configureItem(c, position);
  7129. }else if(c && !this.isValidParent(c, target)){
  7130. var container = this.getNextCell(c);
  7131. container.insertBefore(c.getPositionEl().dom, null);
  7132. c.container = Ext.get(container);
  7133. this.configureItem(c, position);
  7134. }
  7135. },
  7136. // private
  7137. isValidParent : function(c, target){
  7138. return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
  7139. }
  7140. /**
  7141. * @property activeItem
  7142. * @hide
  7143. */
  7144. });
  7145. Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/**
  7146. * @class Ext.layout.AbsoluteLayout
  7147. * @extends Ext.layout.AnchorLayout
  7148. * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.AnchorLayout}</b> and adds the
  7149. * ability for x/y positioning using the standard x and y component config options.</p>
  7150. * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
  7151. * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
  7152. * <p>Example usage:</p>
  7153. * <pre><code>
  7154. var form = new Ext.form.FormPanel({
  7155. title: 'Absolute Layout',
  7156. layout:'absolute',
  7157. layoutConfig: {
  7158. // layout-specific configs go here
  7159. extraCls: 'x-abs-layout-item',
  7160. },
  7161. baseCls: 'x-plain',
  7162. url:'save-form.php',
  7163. defaultType: 'textfield',
  7164. items: [{
  7165. x: 0,
  7166. y: 5,
  7167. xtype:'label',
  7168. text: 'Send To:'
  7169. },{
  7170. x: 60,
  7171. y: 0,
  7172. name: 'to',
  7173. anchor:'100%' // anchor width by percentage
  7174. },{
  7175. x: 0,
  7176. y: 35,
  7177. xtype:'label',
  7178. text: 'Subject:'
  7179. },{
  7180. x: 60,
  7181. y: 30,
  7182. name: 'subject',
  7183. anchor: '100%' // anchor width by percentage
  7184. },{
  7185. x:0,
  7186. y: 60,
  7187. xtype: 'textarea',
  7188. name: 'msg',
  7189. anchor: '100% 100%' // anchor width and height
  7190. }]
  7191. });
  7192. </code></pre>
  7193. */
  7194. Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
  7195. extraCls: 'x-abs-layout-item',
  7196. type: 'absolute',
  7197. onLayout : function(ct, target){
  7198. target.position();
  7199. this.paddingLeft = target.getPadding('l');
  7200. this.paddingTop = target.getPadding('t');
  7201. Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target);
  7202. },
  7203. // private
  7204. adjustWidthAnchor : function(value, comp){
  7205. return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value;
  7206. },
  7207. // private
  7208. adjustHeightAnchor : function(value, comp){
  7209. return value ? value - comp.getPosition(true)[1] + this.paddingTop : value;
  7210. }
  7211. /**
  7212. * @property activeItem
  7213. * @hide
  7214. */
  7215. });
  7216. Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
  7217. /**
  7218. * @class Ext.layout.BoxLayout
  7219. * @extends Ext.layout.ContainerLayout
  7220. * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
  7221. */
  7222. Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
  7223. /**
  7224. * @cfg {Object} defaultMargins
  7225. * <p>If the individual contained items do not have a <tt>margins</tt>
  7226. * property specified, the default margins from this property will be
  7227. * applied to each item.</p>
  7228. * <br><p>This property may be specified as an object containing margins
  7229. * to apply in the format:</p><pre><code>
  7230. {
  7231. top: (top margin),
  7232. right: (right margin),
  7233. bottom: (bottom margin),
  7234. left: (left margin)
  7235. }</code></pre>
  7236. * <p>This property may also be specified as a string containing
  7237. * space-separated, numeric margin values. The order of the sides associated
  7238. * with each value matches the way CSS processes margin values:</p>
  7239. * <div class="mdetail-params"><ul>
  7240. * <li>If there is only one value, it applies to all sides.</li>
  7241. * <li>If there are two values, the top and bottom borders are set to the
  7242. * first value and the right and left are set to the second.</li>
  7243. * <li>If there are three values, the top is set to the first value, the left
  7244. * and right are set to the second, and the bottom is set to the third.</li>
  7245. * <li>If there are four values, they apply to the top, right, bottom, and
  7246. * left, respectively.</li>
  7247. * </ul></div>
  7248. * <p>Defaults to:</p><pre><code>
  7249. * {top:0, right:0, bottom:0, left:0}
  7250. * </code></pre>
  7251. */
  7252. defaultMargins : {left:0,top:0,right:0,bottom:0},
  7253. /**
  7254. * @cfg {String} padding
  7255. * <p>Sets the padding to be applied to all child items managed by this layout.</p>
  7256. * <p>This property must be specified as a string containing
  7257. * space-separated, numeric padding values. The order of the sides associated
  7258. * with each value matches the way CSS processes padding values:</p>
  7259. * <div class="mdetail-params"><ul>
  7260. * <li>If there is only one value, it applies to all sides.</li>
  7261. * <li>If there are two values, the top and bottom borders are set to the
  7262. * first value and the right and left are set to the second.</li>
  7263. * <li>If there are three values, the top is set to the first value, the left
  7264. * and right are set to the second, and the bottom is set to the third.</li>
  7265. * <li>If there are four values, they apply to the top, right, bottom, and
  7266. * left, respectively.</li>
  7267. * </ul></div>
  7268. * <p>Defaults to: <code>"0"</code></p>
  7269. */
  7270. padding : '0',
  7271. // documented in subclasses
  7272. pack : 'start',
  7273. // private
  7274. monitorResize : true,
  7275. type: 'box',
  7276. scrollOffset : 0,
  7277. extraCls : 'x-box-item',
  7278. targetCls : 'x-box-layout-ct',
  7279. innerCls : 'x-box-inner',
  7280. constructor : function(config){
  7281. Ext.layout.BoxLayout.superclass.constructor.call(this, config);
  7282. if (Ext.isString(this.defaultMargins)) {
  7283. this.defaultMargins = this.parseMargins(this.defaultMargins);
  7284. }
  7285. },
  7286. /**
  7287. * @private
  7288. * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
  7289. * when laying out
  7290. */
  7291. onLayout: function(container, target) {
  7292. Ext.layout.BoxLayout.superclass.onLayout.call(this, container, target);
  7293. var items = this.getVisibleItems(container),
  7294. tSize = this.getLayoutTargetSize();
  7295. /**
  7296. * @private
  7297. * @property layoutTargetLastSize
  7298. * @type Object
  7299. * Private cache of the last measured size of the layout target. This should never be used except by
  7300. * BoxLayout subclasses during their onLayout run.
  7301. */
  7302. this.layoutTargetLastSize = tSize;
  7303. /**
  7304. * @private
  7305. * @property childBoxCache
  7306. * @type Array
  7307. * Array of the last calculated height, width, top and left positions of each visible rendered component
  7308. * within the Box layout.
  7309. */
  7310. this.childBoxCache = this.calculateChildBoxes(items, tSize);
  7311. this.updateInnerCtSize(tSize, this.childBoxCache);
  7312. this.updateChildBoxes(this.childBoxCache.boxes);
  7313. // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary.
  7314. this.handleTargetOverflow(tSize, container, target);
  7315. },
  7316. /**
  7317. * Resizes and repositions each child component
  7318. * @param {Array} boxes The box measurements
  7319. */
  7320. updateChildBoxes: function(boxes) {
  7321. for (var i = 0, length = boxes.length; i < length; i++) {
  7322. var box = boxes[i],
  7323. comp = box.component;
  7324. if (box.dirtySize) {
  7325. comp.setSize(box.width, box.height);
  7326. }
  7327. // Don't set positions to NaN
  7328. if (isNaN(box.left) || isNaN(box.top)) {
  7329. continue;
  7330. }
  7331. comp.setPosition(box.left, box.top);
  7332. }
  7333. },
  7334. /**
  7335. * @private
  7336. * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
  7337. * to make sure all child items fit within it. We call this before sizing the children because if our child
  7338. * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
  7339. * again immediately afterwards, giving a performance hit.
  7340. * Subclasses should provide an implementation.
  7341. * @param {Object} currentSize The current height and width of the innerCt
  7342. * @param {Array} calculations The new box calculations of all items to be laid out
  7343. */
  7344. updateInnerCtSize: Ext.emptyFn,
  7345. /**
  7346. * @private
  7347. * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
  7348. * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
  7349. * target. Having a Box layout inside such a target is therefore not recommended.
  7350. * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
  7351. * @param {Ext.Container} container The container
  7352. * @param {Ext.Element} target The target element
  7353. */
  7354. handleTargetOverflow: function(previousTargetSize, container, target) {
  7355. var overflow = target.getStyle('overflow');
  7356. if (overflow && overflow != 'hidden' &&!this.adjustmentPass) {
  7357. var newTargetSize = this.getLayoutTargetSize();
  7358. if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height){
  7359. this.adjustmentPass = true;
  7360. this.onLayout(container, target);
  7361. }
  7362. }
  7363. delete this.adjustmentPass;
  7364. },
  7365. // private
  7366. isValidParent : function(c, target){
  7367. return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
  7368. },
  7369. /**
  7370. * @private
  7371. * Returns all items that are both rendered and visible
  7372. * @return {Array} All matching items
  7373. */
  7374. getVisibleItems: function(ct) {
  7375. var ct = ct || this.container,
  7376. t = ct.getLayoutTarget(),
  7377. cti = ct.items.items,
  7378. len = cti.length,
  7379. i, c, items = [];
  7380. for (i = 0; i < len; i++) {
  7381. if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true && c.collapsed !== true){
  7382. items.push(c);
  7383. }
  7384. }
  7385. return items;
  7386. },
  7387. // private
  7388. renderAll : function(ct, target){
  7389. if(!this.innerCt){
  7390. // the innerCt prevents wrapping and shuffling while
  7391. // the container is resizing
  7392. this.innerCt = target.createChild({cls:this.innerCls});
  7393. this.padding = this.parseMargins(this.padding);
  7394. }
  7395. Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt);
  7396. },
  7397. getLayoutTargetSize : function(){
  7398. var target = this.container.getLayoutTarget(), ret;
  7399. if (target) {
  7400. ret = target.getViewSize();
  7401. // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
  7402. // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
  7403. // with getViewSize
  7404. if (Ext.isIE && Ext.isStrict && ret.width == 0){
  7405. ret = target.getStyleSize();
  7406. }
  7407. ret.width -= target.getPadding('lr');
  7408. ret.height -= target.getPadding('tb');
  7409. }
  7410. return ret;
  7411. },
  7412. // private
  7413. renderItem : function(c){
  7414. if(Ext.isString(c.margins)){
  7415. c.margins = this.parseMargins(c.margins);
  7416. }else if(!c.margins){
  7417. c.margins = this.defaultMargins;
  7418. }
  7419. Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
  7420. }
  7421. });
  7422. /**
  7423. * @class Ext.layout.VBoxLayout
  7424. * @extends Ext.layout.BoxLayout
  7425. * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
  7426. * space between child items containing a numeric <code>flex</code> configuration.</p>
  7427. * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
  7428. */
  7429. Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
  7430. /**
  7431. * @cfg {String} align
  7432. * Controls how the child items of the container are aligned. Acceptable configuration values for this
  7433. * property are:
  7434. * <div class="mdetail-params"><ul>
  7435. * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
  7436. * at the <b>left</b> side of the container</div></li>
  7437. * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
  7438. * <b>mid-width</b> of the container</div></li>
  7439. * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
  7440. * the width of the container</div></li>
  7441. * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
  7442. * the size of the largest item.</div></li>
  7443. * </ul></div>
  7444. */
  7445. align : 'left', // left, center, stretch, strechmax
  7446. type: 'vbox',
  7447. /**
  7448. * @cfg {String} pack
  7449. * Controls how the child items of the container are packed together. Acceptable configuration values
  7450. * for this property are:
  7451. * <div class="mdetail-params"><ul>
  7452. * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
  7453. * <b>top</b> side of container</div></li>
  7454. * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
  7455. * <b>mid-height</b> of container</div></li>
  7456. * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>bottom</b>
  7457. * side of container</div></li>
  7458. * </ul></div>
  7459. */
  7460. /**
  7461. * @cfg {Number} flex
  7462. * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
  7463. * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>vertically</b>
  7464. * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
  7465. * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
  7466. * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
  7467. */
  7468. /**
  7469. * @private
  7470. * See parent documentation
  7471. */
  7472. updateInnerCtSize: function(tSize, calcs) {
  7473. var innerCtHeight = tSize.height,
  7474. innerCtWidth = calcs.meta.maxWidth + this.padding.left + this.padding.right;
  7475. if (this.align == 'stretch') {
  7476. innerCtWidth = tSize.width;
  7477. } else if (this.align == 'center') {
  7478. innerCtWidth = Math.max(tSize.width, innerCtWidth);
  7479. }
  7480. //we set the innerCt size first because if our child items are larger than the previous innerCt size
  7481. //the browser will insert scrollbars and then remove them again immediately afterwards
  7482. this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
  7483. },
  7484. /**
  7485. * @private
  7486. * Calculates the size and positioning of each item in the VBox. This iterates over all of the rendered,
  7487. * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
  7488. * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
  7489. * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
  7490. * @param {Object} targetSize Object containing target size and height
  7491. * @return {Object} Object containing box measurements for each child, plus meta data
  7492. */
  7493. calculateChildBoxes: function(visibleItems, targetSize) {
  7494. var visibleCount = visibleItems.length,
  7495. padding = this.padding,
  7496. topOffset = padding.top,
  7497. leftOffset = padding.left,
  7498. paddingVert = topOffset + padding.bottom,
  7499. paddingHoriz = leftOffset + padding.right,
  7500. width = targetSize.width - this.scrollOffset,
  7501. height = targetSize.height,
  7502. availWidth = Math.max(0, width - paddingHoriz),
  7503. isStart = this.pack == 'start',
  7504. isCenter = this.pack == 'center',
  7505. isEnd = this.pack == 'end',
  7506. nonFlexHeight= 0,
  7507. maxWidth = 0,
  7508. totalFlex = 0,
  7509. //used to cache the calculated size and position values for each child item
  7510. boxes = [],
  7511. //used in the for loops below, just declared here for brevity
  7512. child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedHeight, horizMargins, stretchWidth;
  7513. //gather the total flex of all flexed items and the width taken up by fixed width items
  7514. for (i = 0; i < visibleCount; i++) {
  7515. child = visibleItems[i];
  7516. childHeight = child.height;
  7517. childWidth = child.width;
  7518. canLayout = !child.hasLayout && Ext.isFunction(child.doLayout);
  7519. // Static height (numeric) requires no calcs
  7520. if (!Ext.isNumber(childHeight)) {
  7521. // flex and not 'auto' height
  7522. if (child.flex && !childHeight) {
  7523. totalFlex += child.flex;
  7524. // Not flexed or 'auto' height or undefined height
  7525. } else {
  7526. //Render and layout sub-containers without a flex or width defined, as otherwise we
  7527. //don't know how wide the sub-container should be and cannot calculate flexed widths
  7528. if (!childHeight && canLayout) {
  7529. child.doLayout();
  7530. }
  7531. childSize = child.getSize();
  7532. childWidth = childSize.width;
  7533. childHeight = childSize.height;
  7534. }
  7535. }
  7536. childMargins = child.margins;
  7537. nonFlexHeight += (childHeight || 0) + childMargins.top + childMargins.bottom;
  7538. // Max width for align - force layout of non-layed out subcontainers without a numeric width
  7539. if (!Ext.isNumber(childWidth)) {
  7540. if (canLayout) {
  7541. child.doLayout();
  7542. }
  7543. childWidth = child.getWidth();
  7544. }
  7545. maxWidth = Math.max(maxWidth, childWidth + childMargins.left + childMargins.right);
  7546. //cache the size of each child component
  7547. boxes.push({
  7548. component: child,
  7549. height : childHeight || undefined,
  7550. width : childWidth || undefined
  7551. });
  7552. }
  7553. //the height available to the flexed items
  7554. var availableHeight = Math.max(0, (height - nonFlexHeight - paddingVert));
  7555. if (isCenter) {
  7556. topOffset += availableHeight / 2;
  7557. } else if (isEnd) {
  7558. topOffset += availableHeight;
  7559. }
  7560. //temporary variables used in the flex height calculations below
  7561. var remainingHeight = availableHeight,
  7562. remainingFlex = totalFlex;
  7563. //calculate the height of each flexed item, and the left + top positions of every item
  7564. for (i = 0; i < visibleCount; i++) {
  7565. child = visibleItems[i];
  7566. calcs = boxes[i];
  7567. childMargins = child.margins;
  7568. horizMargins = childMargins.left + childMargins.right;
  7569. topOffset += childMargins.top;
  7570. if (isStart && child.flex && !child.height) {
  7571. flexedHeight = Math.ceil((child.flex / remainingFlex) * remainingHeight);
  7572. remainingHeight -= flexedHeight;
  7573. remainingFlex -= child.flex;
  7574. calcs.height = flexedHeight;
  7575. calcs.dirtySize = true;
  7576. }
  7577. calcs.left = leftOffset + childMargins.left;
  7578. calcs.top = topOffset;
  7579. switch (this.align) {
  7580. case 'stretch':
  7581. stretchWidth = availWidth - horizMargins;
  7582. calcs.width = stretchWidth.constrain(child.minHeight || 0, child.maxWidth || 1000000);
  7583. calcs.dirtySize = true;
  7584. break;
  7585. case 'stretchmax':
  7586. stretchWidth = maxWidth - horizMargins;
  7587. calcs.width = stretchWidth.constrain(child.minHeight || 0, child.maxWidth || 1000000);
  7588. calcs.dirtySize = true;
  7589. break;
  7590. case 'center':
  7591. var diff = availWidth - calcs.width - horizMargins;
  7592. if (diff > 0) {
  7593. calcs.left = leftOffset + horizMargins + (diff / 2);
  7594. }
  7595. }
  7596. topOffset += calcs.height + childMargins.bottom;
  7597. }
  7598. return {
  7599. boxes: boxes,
  7600. meta : {
  7601. maxWidth: maxWidth
  7602. }
  7603. };
  7604. }
  7605. });
  7606. Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
  7607. /**
  7608. * @class Ext.layout.HBoxLayout
  7609. * @extends Ext.layout.BoxLayout
  7610. * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
  7611. * space between child items containing a numeric <code>flex</code> configuration.</p>
  7612. * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
  7613. */
  7614. Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
  7615. /**
  7616. * @cfg {String} align
  7617. * Controls how the child items of the container are aligned. Acceptable configuration values for this
  7618. * property are:
  7619. * <div class="mdetail-params"><ul>
  7620. * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
  7621. * at the <b>top</b> of the container</div></li>
  7622. * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
  7623. * <b>middle</b> of the container</div></li>
  7624. * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
  7625. * the height of the container</div></li>
  7626. * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
  7627. * the height of the largest item.</div></li>
  7628. */
  7629. align: 'top', // top, middle, stretch, strechmax
  7630. type : 'hbox',
  7631. /**
  7632. * @private
  7633. * See parent documentation
  7634. */
  7635. updateInnerCtSize: function(tSize, calcs) {
  7636. var innerCtWidth = tSize.width,
  7637. innerCtHeight = calcs.meta.maxHeight + this.padding.top + this.padding.bottom;
  7638. if (this.align == 'stretch') {
  7639. innerCtHeight = tSize.height;
  7640. } else if (this.align == 'middle') {
  7641. innerCtHeight = Math.max(tSize.height, innerCtHeight);
  7642. }
  7643. this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
  7644. },
  7645. /**
  7646. * @cfg {String} pack
  7647. * Controls how the child items of the container are packed together. Acceptable configuration values
  7648. * for this property are:
  7649. * <div class="mdetail-params"><ul>
  7650. * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
  7651. * <b>left</b> side of container</div></li>
  7652. * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
  7653. * <b>mid-width</b> of container</div></li>
  7654. * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
  7655. * side of container</div></li>
  7656. * </ul></div>
  7657. */
  7658. /**
  7659. * @cfg {Number} flex
  7660. * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
  7661. * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
  7662. * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
  7663. * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
  7664. * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
  7665. */
  7666. /**
  7667. * @private
  7668. * Calculates the size and positioning of each item in the HBox. This iterates over all of the rendered,
  7669. * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
  7670. * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
  7671. * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
  7672. * @param {Object} targetSize Object containing target size and height
  7673. * @return {Object} Object containing box measurements for each child, plus meta data
  7674. */
  7675. calculateChildBoxes: function(visibleItems, targetSize) {
  7676. var visibleCount = visibleItems.length,
  7677. padding = this.padding,
  7678. topOffset = padding.top,
  7679. leftOffset = padding.left,
  7680. paddingVert = topOffset + padding.bottom,
  7681. paddingHoriz = leftOffset + padding.right,
  7682. width = targetSize.width - this.scrollOffset,
  7683. height = targetSize.height,
  7684. availHeight = Math.max(0, height - paddingVert),
  7685. isStart = this.pack == 'start',
  7686. isCenter = this.pack == 'center',
  7687. isEnd = this.pack == 'end',
  7688. // isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
  7689. nonFlexWidth = 0,
  7690. maxHeight = 0,
  7691. totalFlex = 0,
  7692. //used to cache the calculated size and position values for each child item
  7693. boxes = [],
  7694. //used in the for loops below, just declared here for brevity
  7695. child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth, vertMargins, stretchHeight;
  7696. //gather the total flex of all flexed items and the width taken up by fixed width items
  7697. for (i = 0; i < visibleCount; i++) {
  7698. child = visibleItems[i];
  7699. childHeight = child.height;
  7700. childWidth = child.width;
  7701. canLayout = !child.hasLayout && Ext.isFunction(child.doLayout);
  7702. // Static width (numeric) requires no calcs
  7703. if (!Ext.isNumber(childWidth)) {
  7704. // flex and not 'auto' width
  7705. if (child.flex && !childWidth) {
  7706. totalFlex += child.flex;
  7707. // Not flexed or 'auto' width or undefined width
  7708. } else {
  7709. //Render and layout sub-containers without a flex or width defined, as otherwise we
  7710. //don't know how wide the sub-container should be and cannot calculate flexed widths
  7711. if (!childWidth && canLayout) {
  7712. child.doLayout();
  7713. }
  7714. childSize = child.getSize();
  7715. childWidth = childSize.width;
  7716. childHeight = childSize.height;
  7717. }
  7718. }
  7719. childMargins = child.margins;
  7720. nonFlexWidth += (childWidth || 0) + childMargins.left + childMargins.right;
  7721. // Max height for align - force layout of non-layed out subcontainers without a numeric height
  7722. if (!Ext.isNumber(childHeight)) {
  7723. if (canLayout) {
  7724. child.doLayout();
  7725. }
  7726. childHeight = child.getHeight();
  7727. }
  7728. maxHeight = Math.max(maxHeight, childHeight + childMargins.top + childMargins.bottom);
  7729. //cache the size of each child component
  7730. boxes.push({
  7731. component: child,
  7732. height : childHeight || undefined,
  7733. width : childWidth || undefined
  7734. });
  7735. }
  7736. //the width available to the flexed items
  7737. var availableWidth = Math.max(0, (width - nonFlexWidth - paddingHoriz));
  7738. if (isCenter) {
  7739. leftOffset += availableWidth / 2;
  7740. } else if (isEnd) {
  7741. leftOffset += availableWidth;
  7742. }
  7743. //temporary variables used in the flex width calculations below
  7744. var remainingWidth = availableWidth,
  7745. remainingFlex = totalFlex;
  7746. //calculate the widths of each flexed item, and the left + top positions of every item
  7747. for (i = 0; i < visibleCount; i++) {
  7748. child = visibleItems[i];
  7749. calcs = boxes[i];
  7750. childMargins = child.margins;
  7751. vertMargins = childMargins.top + childMargins.bottom;
  7752. leftOffset += childMargins.left;
  7753. if (isStart && child.flex && !child.width) {
  7754. flexedWidth = Math.ceil((child.flex / remainingFlex) * remainingWidth);
  7755. remainingWidth -= flexedWidth;
  7756. remainingFlex -= child.flex;
  7757. calcs.width = flexedWidth;
  7758. calcs.dirtySize = true;
  7759. }
  7760. calcs.left = leftOffset;
  7761. calcs.top = topOffset + childMargins.top;
  7762. switch (this.align) {
  7763. case 'stretch':
  7764. stretchHeight = availHeight - vertMargins;
  7765. calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
  7766. calcs.dirtySize = true;
  7767. break;
  7768. case 'stretchmax':
  7769. stretchHeight = maxHeight - vertMargins;
  7770. calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
  7771. calcs.dirtySize = true;
  7772. break;
  7773. case 'middle':
  7774. var diff = availHeight - calcs.height - vertMargins;
  7775. if (diff > 0) {
  7776. calcs.top = topOffset + vertMargins + (diff / 2);
  7777. }
  7778. }
  7779. leftOffset += calcs.width + childMargins.right;
  7780. }
  7781. return {
  7782. boxes: boxes,
  7783. meta : {
  7784. maxHeight: maxHeight
  7785. }
  7786. };
  7787. }
  7788. });
  7789. Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;
  7790. /**
  7791. * @class Ext.layout.ToolbarLayout
  7792. * @extends Ext.layout.ContainerLayout
  7793. * Layout manager used by Ext.Toolbar. This is highly specialised for use by Toolbars and would not
  7794. * usually be used by any other class.
  7795. */
  7796. Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
  7797. monitorResize : true,
  7798. type: 'toolbar',
  7799. /**
  7800. * @property triggerWidth
  7801. * @type Number
  7802. * The width allocated for the menu trigger at the extreme right end of the Toolbar
  7803. */
  7804. triggerWidth: 18,
  7805. /**
  7806. * @property noItemsMenuText
  7807. * @type String
  7808. * HTML fragment to render into the toolbar overflow menu if there are no items to display
  7809. */
  7810. noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
  7811. /**
  7812. * @private
  7813. * @property lastOverflow
  7814. * @type Boolean
  7815. * Used internally to record whether the last layout caused an overflow or not
  7816. */
  7817. lastOverflow: false,
  7818. /**
  7819. * @private
  7820. * @property tableHTML
  7821. * @type String
  7822. * String used to build the HTML injected to support the Toolbar's layout. The align property is
  7823. * injected into this string inside the td.x-toolbar-left element during onLayout.
  7824. */
  7825. tableHTML: [
  7826. '<table cellspacing="0" class="x-toolbar-ct">',
  7827. '<tbody>',
  7828. '<tr>',
  7829. '<td class="x-toolbar-left" align="{0}">',
  7830. '<table cellspacing="0">',
  7831. '<tbody>',
  7832. '<tr class="x-toolbar-left-row"></tr>',
  7833. '</tbody>',
  7834. '</table>',
  7835. '</td>',
  7836. '<td class="x-toolbar-right" align="right">',
  7837. '<table cellspacing="0" class="x-toolbar-right-ct">',
  7838. '<tbody>',
  7839. '<tr>',
  7840. '<td>',
  7841. '<table cellspacing="0">',
  7842. '<tbody>',
  7843. '<tr class="x-toolbar-right-row"></tr>',
  7844. '</tbody>',
  7845. '</table>',
  7846. '</td>',
  7847. '<td>',
  7848. '<table cellspacing="0">',
  7849. '<tbody>',
  7850. '<tr class="x-toolbar-extras-row"></tr>',
  7851. '</tbody>',
  7852. '</table>',
  7853. '</td>',
  7854. '</tr>',
  7855. '</tbody>',
  7856. '</table>',
  7857. '</td>',
  7858. '</tr>',
  7859. '</tbody>',
  7860. '</table>'
  7861. ].join(""),
  7862. /**
  7863. * @private
  7864. * Create the wrapping Toolbar HTML and render/move all the items into the correct places
  7865. */
  7866. onLayout : function(ct, target) {
  7867. //render the Toolbar <table> HTML if it's not already present
  7868. if (!this.leftTr) {
  7869. var align = ct.buttonAlign == 'center' ? 'center' : 'left';
  7870. target.addClass('x-toolbar-layout-ct');
  7871. target.insertHtml('beforeEnd', String.format(this.tableHTML, align));
  7872. this.leftTr = target.child('tr.x-toolbar-left-row', true);
  7873. this.rightTr = target.child('tr.x-toolbar-right-row', true);
  7874. this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
  7875. if (this.hiddenItem == undefined) {
  7876. /**
  7877. * @property hiddenItems
  7878. * @type Array
  7879. * Holds all items that are currently hidden due to there not being enough space to render them
  7880. * These items will appear on the expand menu.
  7881. */
  7882. this.hiddenItems = [];
  7883. }
  7884. }
  7885. var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
  7886. items = ct.items.items,
  7887. position = 0;
  7888. //render each item if not already rendered, place it into the correct (left or right) target
  7889. for (var i = 0, len = items.length, c; i < len; i++, position++) {
  7890. c = items[i];
  7891. if (c.isFill) {
  7892. side = this.rightTr;
  7893. position = -1;
  7894. } else if (!c.rendered) {
  7895. c.render(this.insertCell(c, side, position));
  7896. } else {
  7897. if (!c.xtbHidden && !this.isValidParent(c, side.childNodes[position])) {
  7898. var td = this.insertCell(c, side, position);
  7899. td.appendChild(c.getPositionEl().dom);
  7900. c.container = Ext.get(td);
  7901. }
  7902. }
  7903. }
  7904. //strip extra empty cells
  7905. this.cleanup(this.leftTr);
  7906. this.cleanup(this.rightTr);
  7907. this.cleanup(this.extrasTr);
  7908. this.fitToSize(target);
  7909. },
  7910. /**
  7911. * @private
  7912. * Removes any empty nodes from the given element
  7913. * @param {Ext.Element} el The element to clean up
  7914. */
  7915. cleanup : function(el) {
  7916. var cn = el.childNodes, i, c;
  7917. for (i = cn.length-1; i >= 0 && (c = cn[i]); i--) {
  7918. if (!c.firstChild) {
  7919. el.removeChild(c);
  7920. }
  7921. }
  7922. },
  7923. /**
  7924. * @private
  7925. * Inserts the given Toolbar item into the given element
  7926. * @param {Ext.Component} c The component to add
  7927. * @param {Ext.Element} target The target to add the component to
  7928. * @param {Number} position The position to add the component at
  7929. */
  7930. insertCell : function(c, target, position) {
  7931. var td = document.createElement('td');
  7932. td.className = 'x-toolbar-cell';
  7933. target.insertBefore(td, target.childNodes[position] || null);
  7934. return td;
  7935. },
  7936. /**
  7937. * @private
  7938. * Hides an item because it will not fit in the available width. The item will be unhidden again
  7939. * if the Toolbar is resized to be large enough to show it
  7940. * @param {Ext.Component} item The item to hide
  7941. */
  7942. hideItem : function(item) {
  7943. this.hiddenItems.push(item);
  7944. item.xtbHidden = true;
  7945. item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
  7946. item.hide();
  7947. },
  7948. /**
  7949. * @private
  7950. * Unhides an item that was previously hidden due to there not being enough space left on the Toolbar
  7951. * @param {Ext.Component} item The item to show
  7952. */
  7953. unhideItem : function(item) {
  7954. item.show();
  7955. item.xtbHidden = false;
  7956. this.hiddenItems.remove(item);
  7957. },
  7958. /**
  7959. * @private
  7960. * Returns the width of the given toolbar item. If the item is currently hidden because there
  7961. * is not enough room to render it, its previous width is returned
  7962. * @param {Ext.Component} c The component to measure
  7963. * @return {Number} The width of the item
  7964. */
  7965. getItemWidth : function(c) {
  7966. return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
  7967. },
  7968. /**
  7969. * @private
  7970. * Called at the end of onLayout. At this point the Toolbar has already been resized, so we need
  7971. * to fit the items into the available width. We add up the width required by all of the items in
  7972. * the toolbar - if we don't have enough space we hide the extra items and render the expand menu
  7973. * trigger.
  7974. * @param {Ext.Element} target The Element the Toolbar is currently laid out within
  7975. */
  7976. fitToSize : function(target) {
  7977. if (this.container.enableOverflow === false) {
  7978. return;
  7979. }
  7980. var width = target.dom.clientWidth,
  7981. tableWidth = target.dom.firstChild.offsetWidth,
  7982. clipWidth = width - this.triggerWidth,
  7983. lastWidth = this.lastWidth || 0,
  7984. hiddenItems = this.hiddenItems,
  7985. hasHiddens = hiddenItems.length != 0,
  7986. isLarger = width >= lastWidth;
  7987. this.lastWidth = width;
  7988. if (tableWidth > width || (hasHiddens && isLarger)) {
  7989. var items = this.container.items.items,
  7990. len = items.length,
  7991. loopWidth = 0,
  7992. item;
  7993. for (var i = 0; i < len; i++) {
  7994. item = items[i];
  7995. if (!item.isFill) {
  7996. loopWidth += this.getItemWidth(item);
  7997. if (loopWidth > clipWidth) {
  7998. if (!(item.hidden || item.xtbHidden)) {
  7999. this.hideItem(item);
  8000. }
  8001. } else if (item.xtbHidden) {
  8002. this.unhideItem(item);
  8003. }
  8004. }
  8005. }
  8006. }
  8007. //test for number of hidden items again here because they may have changed above
  8008. hasHiddens = hiddenItems.length != 0;
  8009. if (hasHiddens) {
  8010. this.initMore();
  8011. if (!this.lastOverflow) {
  8012. this.container.fireEvent('overflowchange', this.container, true);
  8013. this.lastOverflow = true;
  8014. }
  8015. } else if (this.more) {
  8016. this.clearMenu();
  8017. this.more.destroy();
  8018. delete this.more;
  8019. if (this.lastOverflow) {
  8020. this.container.fireEvent('overflowchange', this.container, false);
  8021. this.lastOverflow = false;
  8022. }
  8023. }
  8024. },
  8025. /**
  8026. * @private
  8027. * Returns a menu config for a given component. This config is used to create a menu item
  8028. * to be added to the expander menu
  8029. * @param {Ext.Component} component The component to create the config for
  8030. * @param {Boolean} hideOnClick Passed through to the menu item
  8031. */
  8032. createMenuConfig : function(component, hideOnClick){
  8033. var config = Ext.apply({}, component.initialConfig),
  8034. group = component.toggleGroup;
  8035. Ext.copyTo(config, component, [
  8036. 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
  8037. ]);
  8038. Ext.apply(config, {
  8039. text : component.overflowText || component.text,
  8040. hideOnClick: hideOnClick
  8041. });
  8042. if (group || component.enableToggle) {
  8043. Ext.apply(config, {
  8044. group : group,
  8045. checked: component.pressed,
  8046. listeners: {
  8047. checkchange: function(item, checked){
  8048. component.toggle(checked);
  8049. }
  8050. }
  8051. });
  8052. }
  8053. delete config.ownerCt;
  8054. delete config.xtype;
  8055. delete config.id;
  8056. return config;
  8057. },
  8058. /**
  8059. * @private
  8060. * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
  8061. * @param {Ext.menu.Menu} menu The menu to add to
  8062. * @param {Ext.Component} component The component to add
  8063. */
  8064. addComponentToMenu : function(menu, component) {
  8065. if (component instanceof Ext.Toolbar.Separator) {
  8066. menu.add('-');
  8067. } else if (Ext.isFunction(component.isXType)) {
  8068. if (component.isXType('splitbutton')) {
  8069. menu.add(this.createMenuConfig(component, true));
  8070. } else if (component.isXType('button')) {
  8071. menu.add(this.createMenuConfig(component, !component.menu));
  8072. } else if (component.isXType('buttongroup')) {
  8073. component.items.each(function(item){
  8074. this.addComponentToMenu(menu, item);
  8075. }, this);
  8076. }
  8077. }
  8078. },
  8079. /**
  8080. * @private
  8081. * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
  8082. * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
  8083. */
  8084. clearMenu : function(){
  8085. var menu = this.moreMenu;
  8086. if (menu && menu.items) {
  8087. menu.items.each(function(item){
  8088. delete item.menu;
  8089. });
  8090. }
  8091. },
  8092. /**
  8093. * @private
  8094. * Called before the expand menu is shown, this rebuilds the menu since it was last shown because
  8095. * it is possible that the items hidden due to space limitations on the Toolbar have changed since.
  8096. * @param {Ext.menu.Menu} m The menu
  8097. */
  8098. beforeMoreShow : function(menu) {
  8099. var items = this.container.items.items,
  8100. len = items.length,
  8101. item,
  8102. prev;
  8103. var needsSep = function(group, item){
  8104. return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
  8105. };
  8106. this.clearMenu();
  8107. menu.removeAll();
  8108. for (var i = 0; i < len; i++) {
  8109. item = items[i];
  8110. if (item.xtbHidden) {
  8111. if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
  8112. menu.add('-');
  8113. }
  8114. this.addComponentToMenu(menu, item);
  8115. prev = item;
  8116. }
  8117. }
  8118. // put something so the menu isn't empty if no compatible items found
  8119. if (menu.items.length < 1) {
  8120. menu.add(this.noItemsMenuText);
  8121. }
  8122. },
  8123. /**
  8124. * @private
  8125. * Creates the expand trigger and menu, adding them to the <tr> at the extreme right of the
  8126. * Toolbar table
  8127. */
  8128. initMore : function(){
  8129. if (!this.more) {
  8130. /**
  8131. * @private
  8132. * @property moreMenu
  8133. * @type Ext.menu.Menu
  8134. * The expand menu - holds items for every Toolbar item that cannot be shown
  8135. * because the Toolbar is currently not wide enough.
  8136. */
  8137. this.moreMenu = new Ext.menu.Menu({
  8138. ownerCt : this.container,
  8139. listeners: {
  8140. beforeshow: this.beforeMoreShow,
  8141. scope: this
  8142. }
  8143. });
  8144. /**
  8145. * @private
  8146. * @property more
  8147. * @type Ext.Button
  8148. * The expand button which triggers the overflow menu to be shown
  8149. */
  8150. this.more = new Ext.Button({
  8151. iconCls: 'x-toolbar-more-icon',
  8152. cls : 'x-toolbar-more',
  8153. menu : this.moreMenu,
  8154. ownerCt: this.container
  8155. });
  8156. var td = this.insertCell(this.more, this.extrasTr, 100);
  8157. this.more.render(td);
  8158. }
  8159. },
  8160. destroy : function(){
  8161. Ext.destroy(this.more, this.moreMenu);
  8162. delete this.leftTr;
  8163. delete this.rightTr;
  8164. delete this.extrasTr;
  8165. Ext.layout.ToolbarLayout.superclass.destroy.call(this);
  8166. }
  8167. });
  8168. Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
  8169. /**
  8170. * @class Ext.layout.MenuLayout
  8171. * @extends Ext.layout.ContainerLayout
  8172. * <p>Layout manager used by {@link Ext.menu.Menu}. Generally this class should not need to be used directly.</p>
  8173. */
  8174. Ext.layout.MenuLayout = Ext.extend(Ext.layout.ContainerLayout, {
  8175. monitorResize : true,
  8176. type: 'menu',
  8177. setContainer : function(ct){
  8178. this.monitorResize = !ct.floating;
  8179. // This event is only fired by the menu in IE, used so we don't couple
  8180. // the menu with the layout.
  8181. ct.on('autosize', this.doAutoSize, this);
  8182. Ext.layout.MenuLayout.superclass.setContainer.call(this, ct);
  8183. },
  8184. renderItem : function(c, position, target){
  8185. if (!this.itemTpl) {
  8186. this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate(
  8187. '<li id="{itemId}" class="{itemCls}">',
  8188. '<tpl if="needsIcon">',
  8189. '<img src="{icon}" class="{iconCls}"/>',
  8190. '</tpl>',
  8191. '</li>'
  8192. );
  8193. }
  8194. if(c && !c.rendered){
  8195. if(Ext.isNumber(position)){
  8196. position = target.dom.childNodes[position];
  8197. }
  8198. var a = this.getItemArgs(c);
  8199. // The Component's positionEl is the <li> it is rendered into
  8200. c.render(c.positionEl = position ?
  8201. this.itemTpl.insertBefore(position, a, true) :
  8202. this.itemTpl.append(target, a, true));
  8203. // Link the containing <li> to the item.
  8204. c.positionEl.menuItemId = c.getItemId();
  8205. // If rendering a regular Component, and it needs an icon,
  8206. // move the Component rightwards.
  8207. if (!a.isMenuItem && a.needsIcon) {
  8208. c.positionEl.addClass('x-menu-list-item-indent');
  8209. }
  8210. this.configureItem(c, position);
  8211. }else if(c && !this.isValidParent(c, target)){
  8212. if(Ext.isNumber(position)){
  8213. position = target.dom.childNodes[position];
  8214. }
  8215. target.dom.insertBefore(c.getActionEl().dom, position || null);
  8216. }
  8217. },
  8218. getItemArgs : function(c) {
  8219. var isMenuItem = c instanceof Ext.menu.Item;
  8220. return {
  8221. isMenuItem: isMenuItem,
  8222. needsIcon: !isMenuItem && (c.icon || c.iconCls),
  8223. icon: c.icon || Ext.BLANK_IMAGE_URL,
  8224. iconCls: 'x-menu-item-icon ' + (c.iconCls || ''),
  8225. itemId: 'x-menu-el-' + c.id,
  8226. itemCls: 'x-menu-list-item '
  8227. };
  8228. },
  8229. // Valid if the Component is in a <li> which is part of our target <ul>
  8230. isValidParent : function(c, target) {
  8231. return c.el.up('li.x-menu-list-item', 5).dom.parentNode === (target.dom || target);
  8232. },
  8233. onLayout : function(ct, target){
  8234. Ext.layout.MenuLayout.superclass.onLayout.call(this, ct, target);
  8235. this.doAutoSize();
  8236. },
  8237. doAutoSize : function(){
  8238. var ct = this.container, w = ct.width;
  8239. if(ct.floating){
  8240. if(w){
  8241. ct.setWidth(w);
  8242. }else if(Ext.isIE){
  8243. ct.setWidth(Ext.isStrict && (Ext.isIE7 || Ext.isIE8) ? 'auto' : ct.minWidth);
  8244. var el = ct.getEl(), t = el.dom.offsetWidth; // force recalc
  8245. ct.setWidth(ct.getLayoutTarget().getWidth() + el.getFrameWidth('lr'));
  8246. }
  8247. }
  8248. }
  8249. });
  8250. Ext.Container.LAYOUTS['menu'] = Ext.layout.MenuLayout;
  8251. /**
  8252. * @class Ext.Viewport
  8253. * @extends Ext.Container
  8254. * <p>A specialized container representing the viewable application area (the browser viewport).</p>
  8255. * <p>The Viewport renders itself to the document body, and automatically sizes itself to the size of
  8256. * the browser viewport and manages window resizing. There may only be one Viewport created
  8257. * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s
  8258. * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
  8259. * method of any of its child Panels may themselves have a layout.</p>
  8260. * <p>The Viewport does not provide scrolling, so child Panels within the Viewport should provide
  8261. * for scrolling if needed using the {@link #autoScroll} config.</p>
  8262. * <p>An example showing a classic application border layout:</p><pre><code>
  8263. new Ext.Viewport({
  8264. layout: 'border',
  8265. items: [{
  8266. region: 'north',
  8267. html: '&lt;h1 class="x-panel-header">Page Title&lt;/h1>',
  8268. autoHeight: true,
  8269. border: false,
  8270. margins: '0 0 5 0'
  8271. }, {
  8272. region: 'west',
  8273. collapsible: true,
  8274. title: 'Navigation',
  8275. width: 200
  8276. // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
  8277. }, {
  8278. region: 'south',
  8279. title: 'Title for Panel',
  8280. collapsible: true,
  8281. html: 'Information goes here',
  8282. split: true,
  8283. height: 100,
  8284. minHeight: 100
  8285. }, {
  8286. region: 'east',
  8287. title: 'Title for the Grid Panel',
  8288. collapsible: true,
  8289. split: true,
  8290. width: 200,
  8291. xtype: 'grid',
  8292. // remaining grid configuration not shown ...
  8293. // notice that the GridPanel is added directly as the region
  8294. // it is not "overnested" inside another Panel
  8295. }, {
  8296. region: 'center',
  8297. xtype: 'tabpanel', // TabPanel itself has no title
  8298. items: {
  8299. title: 'Default Tab',
  8300. html: 'The first tab\'s content. Others may be added dynamically'
  8301. }
  8302. }]
  8303. });
  8304. </code></pre>
  8305. * @constructor
  8306. * Create a new Viewport
  8307. * @param {Object} config The config object
  8308. * @xtype viewport
  8309. */
  8310. Ext.Viewport = Ext.extend(Ext.Container, {
  8311. /*
  8312. * Privatize config options which, if used, would interfere with the
  8313. * correct operation of the Viewport as the sole manager of the
  8314. * layout of the document body.
  8315. */
  8316. /**
  8317. * @cfg {Mixed} applyTo @hide
  8318. */
  8319. /**
  8320. * @cfg {Boolean} allowDomMove @hide
  8321. */
  8322. /**
  8323. * @cfg {Boolean} hideParent @hide
  8324. */
  8325. /**
  8326. * @cfg {Mixed} renderTo @hide
  8327. */
  8328. /**
  8329. * @cfg {Boolean} hideParent @hide
  8330. */
  8331. /**
  8332. * @cfg {Number} height @hide
  8333. */
  8334. /**
  8335. * @cfg {Number} width @hide
  8336. */
  8337. /**
  8338. * @cfg {Boolean} autoHeight @hide
  8339. */
  8340. /**
  8341. * @cfg {Boolean} autoWidth @hide
  8342. */
  8343. /**
  8344. * @cfg {Boolean} deferHeight @hide
  8345. */
  8346. /**
  8347. * @cfg {Boolean} monitorResize @hide
  8348. */
  8349. initComponent : function() {
  8350. Ext.Viewport.superclass.initComponent.call(this);
  8351. document.getElementsByTagName('html')[0].className += ' x-viewport';
  8352. this.el = Ext.getBody();
  8353. this.el.setHeight = Ext.emptyFn;
  8354. this.el.setWidth = Ext.emptyFn;
  8355. this.el.setSize = Ext.emptyFn;
  8356. this.el.dom.scroll = 'no';
  8357. this.allowDomMove = false;
  8358. this.autoWidth = true;
  8359. this.autoHeight = true;
  8360. Ext.EventManager.onWindowResize(this.fireResize, this);
  8361. this.renderTo = this.el;
  8362. },
  8363. fireResize : function(w, h){
  8364. this.fireEvent('resize', this, w, h, w, h);
  8365. }
  8366. });
  8367. Ext.reg('viewport', Ext.Viewport);
  8368. /**
  8369. * @class Ext.Panel
  8370. * @extends Ext.Container
  8371. * <p>Panel is a container that has specific functionality and structural components that make
  8372. * it the perfect building block for application-oriented user interfaces.</p>
  8373. * <p>Panels are, by virtue of their inheritance from {@link Ext.Container}, capable
  8374. * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.</p>
  8375. * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components
  8376. * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
  8377. * those child elements need to be sized using one of Ext's built-in <code><b>{@link Ext.Container#layout layout}</b></code> schemes. By
  8378. * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
  8379. * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
  8380. * at all.</p>
  8381. * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
  8382. * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
  8383. * information).</p>
  8384. * <p>Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with
  8385. * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized
  8386. * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the
  8387. * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.</p>
  8388. * @constructor
  8389. * @param {Object} config The config object
  8390. * @xtype panel
  8391. */
  8392. Ext.Panel = Ext.extend(Ext.Container, {
  8393. /**
  8394. * The Panel's header {@link Ext.Element Element}. Read-only.
  8395. * <p>This Element is used to house the {@link #title} and {@link #tools}</p>
  8396. * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
  8397. * @type Ext.Element
  8398. * @property header
  8399. */
  8400. /**
  8401. * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content.
  8402. * The content may be specified in the {@link #html} config, or it may be loaded using the
  8403. * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only.
  8404. * <p>If this is used to load visible HTML elements in either way, then
  8405. * the Panel may not be used as a Layout for hosting nested Panels.</p>
  8406. * <p>If this Panel is intended to be used as the host of a Layout (See {@link #layout}
  8407. * then the body Element must not be loaded or changed - it is under the control
  8408. * of the Panel's Layout.
  8409. * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
  8410. * @type Ext.Element
  8411. * @property body
  8412. */
  8413. /**
  8414. * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements
  8415. * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only.
  8416. * @type Ext.Element
  8417. * @property bwrap
  8418. */
  8419. /**
  8420. * True if this panel is collapsed. Read-only.
  8421. * @type Boolean
  8422. * @property collapsed
  8423. */
  8424. /**
  8425. * @cfg {Object} bodyCfg
  8426. * <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
  8427. * Panel Element.</p>
  8428. * <p>By default, the Default element in the table below will be used for the html markup to
  8429. * create a child element with the commensurate Default class name (<code>baseCls</code> will be
  8430. * replaced by <code>{@link #baseCls}</code>):</p>
  8431. * <pre>
  8432. * Panel Default Default Custom Additional Additional
  8433. * Element element class element class style
  8434. * ======== ========================== ========= ============== ===========
  8435. * {@link #header} div {@link #baseCls}+'-header' {@link #headerCfg} headerCssClass headerStyle
  8436. * {@link #bwrap} div {@link #baseCls}+'-bwrap' {@link #bwrapCfg} bwrapCssClass bwrapStyle
  8437. * + tbar div {@link #baseCls}+'-tbar' {@link #tbarCfg} tbarCssClass tbarStyle
  8438. * + {@link #body} div {@link #baseCls}+'-body' {@link #bodyCfg} {@link #bodyCssClass} {@link #bodyStyle}
  8439. * + bbar div {@link #baseCls}+'-bbar' {@link #bbarCfg} bbarCssClass bbarStyle
  8440. * + {@link #footer} div {@link #baseCls}+'-footer' {@link #footerCfg} footerCssClass footerStyle
  8441. * </pre>
  8442. * <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
  8443. * to use a different form of markup than is created by default. An example of this might be
  8444. * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
  8445. * a header, or forcing centering of all Panel content by having the body be a &lt;center&gt;
  8446. * element:</p>
  8447. * <pre><code>
  8448. new Ext.Panel({
  8449. title: 'Message Title',
  8450. renderTo: Ext.getBody(),
  8451. width: 200, height: 130,
  8452. <b>bodyCfg</b>: {
  8453. tag: 'center',
  8454. cls: 'x-panel-body', // Default class not applied if Custom element specified
  8455. html: 'Message'
  8456. },
  8457. footerCfg: {
  8458. tag: 'h2',
  8459. cls: 'x-panel-footer' // same as the Default class
  8460. html: 'footer html'
  8461. },
  8462. footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
  8463. footerStyle: 'background-color:red' // see {@link #bodyStyle}
  8464. });
  8465. * </code></pre>
  8466. * <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
  8467. * styling applied.</p>
  8468. */
  8469. /**
  8470. * @cfg {Object} headerCfg
  8471. * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
  8472. * of this Panel's {@link #header} Element. See <code>{@link #bodyCfg}</code> also.</p>
  8473. */
  8474. /**
  8475. * @cfg {Object} bwrapCfg
  8476. * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
  8477. * of this Panel's {@link #bwrap} Element. See <code>{@link #bodyCfg}</code> also.</p>
  8478. */
  8479. /**
  8480. * @cfg {Object} tbarCfg
  8481. * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
  8482. * of this Panel's {@link #tbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
  8483. */
  8484. /**
  8485. * @cfg {Object} bbarCfg
  8486. * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
  8487. * of this Panel's {@link #bbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
  8488. */
  8489. /**
  8490. * @cfg {Object} footerCfg
  8491. * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
  8492. * of this Panel's {@link #footer} Element. See <code>{@link #bodyCfg}</code> also.</p>
  8493. */
  8494. /**
  8495. * @cfg {Boolean} closable
  8496. * Panels themselves do not directly support being closed, but some Panel subclasses do (like
  8497. * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify <code>true</code>
  8498. * to enable closing in such situations. Defaults to <code>false</code>.
  8499. */
  8500. /**
  8501. * The Panel's footer {@link Ext.Element Element}. Read-only.
  8502. * <p>This Element is used to house the Panel's <code>{@link #buttons}</code> or <code>{@link #fbar}</code>.</p>
  8503. * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
  8504. * @type Ext.Element
  8505. * @property footer
  8506. */
  8507. /**
  8508. * @cfg {Mixed} applyTo
  8509. * <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
  8510. * the document that specifies some panel-specific structural markup. When <code>applyTo</code> is used,
  8511. * constituent parts of the panel can be specified by CSS class name within the main element, and the panel
  8512. * will automatically create those components from that markup. Any required components not specified in the
  8513. * markup will be autogenerated if necessary.</p>
  8514. * <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
  8515. * <ul><li>baseCls + '-header'</li>
  8516. * <li>baseCls + '-header-text'</li>
  8517. * <li>baseCls + '-bwrap'</li>
  8518. * <li>baseCls + '-tbar'</li>
  8519. * <li>baseCls + '-body'</li>
  8520. * <li>baseCls + '-bbar'</li>
  8521. * <li>baseCls + '-footer'</li></ul>
  8522. * <p>Using this config, a call to render() is not required. If applyTo is specified, any value passed for
  8523. * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
  8524. * panel's container.</p>
  8525. */
  8526. /**
  8527. * @cfg {Object/Array} tbar
  8528. * <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
  8529. * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
  8530. * To access the top toolbar after render, use {@link #getTopToolbar}.</p>
  8531. * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
  8532. * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
  8533. * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
  8534. * submission parameters are collected from the DOM tree.</p>
  8535. */
  8536. /**
  8537. * @cfg {Object/Array} bbar
  8538. * <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
  8539. * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
  8540. * To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
  8541. * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
  8542. * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
  8543. * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
  8544. * submission parameters are collected from the DOM tree.</p>
  8545. */
  8546. /** @cfg {Object/Array} fbar
  8547. * <p>A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of
  8548. * {@link Ext.Button Button}s/{@link Ext.Button Button} configs, describing a {@link Ext.Toolbar Toolbar} to be rendered into this Panel's footer element.</p>
  8549. * <p>After render, the <code>fbar</code> property will be an {@link Ext.Toolbar Toolbar} instance.</p>
  8550. * <p>If <code>{@link #buttons}</code> are specified, they will supersede the <code>fbar</code> configuration property.</p>
  8551. * The Panel's <code>{@link #buttonAlign}</code> configuration affects the layout of these items, for example:
  8552. * <pre><code>
  8553. var w = new Ext.Window({
  8554. height: 250,
  8555. width: 500,
  8556. bbar: new Ext.Toolbar({
  8557. items: [{
  8558. text: 'bbar Left'
  8559. },'->',{
  8560. text: 'bbar Right'
  8561. }]
  8562. }),
  8563. {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
  8564. // to control the alignment of fbar items
  8565. fbar: [{
  8566. text: 'fbar Left'
  8567. },'->',{
  8568. text: 'fbar Right'
  8569. }]
  8570. }).show();
  8571. * </code></pre>
  8572. * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
  8573. * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
  8574. * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
  8575. * submission parameters are collected from the DOM tree.</p>
  8576. */
  8577. /**
  8578. * @cfg {Boolean} header
  8579. * <code>true</code> to create the Panel's header element explicitly, <code>false</code> to skip creating
  8580. * it. If a <code>{@link #title}</code> is set the header will be created automatically, otherwise it will not.
  8581. * If a <code>{@link #title}</code> is set but <code>header</code> is explicitly set to <code>false</code>, the header
  8582. * will not be rendered.
  8583. */
  8584. /**
  8585. * @cfg {Boolean} footer
  8586. * <code>true</code> to create the footer element explicitly, false to skip creating it. The footer
  8587. * will be created automatically if <code>{@link #buttons}</code> or a <code>{@link #fbar}</code> have
  8588. * been configured. See <code>{@link #bodyCfg}</code> for an example.
  8589. */
  8590. /**
  8591. * @cfg {String} title
  8592. * The title text to be used as innerHTML (html tags are accepted) to display in the panel
  8593. * <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
  8594. * <code>{@link #header}</code> element will automatically be created and displayed unless
  8595. * {@link #header} is explicitly set to <code>false</code>. If you do not want to specify a
  8596. * <code>title</code> at config time, but you may want one later, you must either specify a non-empty
  8597. * <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
  8598. * element will get created.
  8599. */
  8600. /**
  8601. * @cfg {Array} buttons
  8602. * <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
  8603. * the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
  8604. * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
  8605. * If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
  8606. * that width will be applied to the item.
  8607. */
  8608. /**
  8609. * @cfg {Object/String/Function} autoLoad
  8610. * A valid url spec according to the Updater {@link Ext.Updater#update} method.
  8611. * If autoLoad is not null, the panel will attempt to load its contents
  8612. * immediately upon render.<p>
  8613. * The URL will become the default URL for this panel's {@link #body} element,
  8614. * so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
  8615. */
  8616. /**
  8617. * @cfg {Boolean} frame
  8618. * <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
  8619. * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
  8620. * <p>The template generated for each condition is depicted below:</p><pre><code>
  8621. *
  8622. // frame = false
  8623. &lt;div id="developer-specified-id-goes-here" class="x-panel">
  8624. &lt;div class="x-panel-header">&lt;span class="x-panel-header-text">Title: (frame:false)&lt;/span>&lt;/div>
  8625. &lt;div class="x-panel-bwrap">
  8626. &lt;div class="x-panel-body">&lt;p>html value goes here&lt;/p>&lt;/div>
  8627. &lt;/div>
  8628. &lt;/div>
  8629. // frame = true (create 9 elements)
  8630. &lt;div id="developer-specified-id-goes-here" class="x-panel">
  8631. &lt;div class="x-panel-tl">&lt;div class="x-panel-tr">&lt;div class="x-panel-tc">
  8632. &lt;div class="x-panel-header">&lt;span class="x-panel-header-text">Title: (frame:true)&lt;/span>&lt;/div>
  8633. &lt;/div>&lt;/div>&lt;/div>
  8634. &lt;div class="x-panel-bwrap">
  8635. &lt;div class="x-panel-ml">&lt;div class="x-panel-mr">&lt;div class="x-panel-mc">
  8636. &lt;div class="x-panel-body">&lt;p>html value goes here&lt;/p>&lt;/div>
  8637. &lt;/div>&lt;/div>&lt;/div>
  8638. &lt;div class="x-panel-bl">&lt;div class="x-panel-br">&lt;div class="x-panel-bc"/>
  8639. &lt;/div>&lt;/div>&lt;/div>
  8640. &lt;/div>
  8641. * </code></pre>
  8642. */
  8643. /**
  8644. * @cfg {Boolean} border
  8645. * True to display the borders of the panel's body element, false to hide them (defaults to true). By default,
  8646. * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
  8647. */
  8648. /**
  8649. * @cfg {Boolean} bodyBorder
  8650. * True to display an interior border on the body element of the panel, false to hide it (defaults to true).
  8651. * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display
  8652. * as a 1px wide inset border, giving the entire body element an inset appearance.
  8653. */
  8654. /**
  8655. * @cfg {String/Object/Function} bodyCssClass
  8656. * Additional css class selector to be applied to the {@link #body} element in the format expected by
  8657. * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
  8658. */
  8659. /**
  8660. * @cfg {String/Object/Function} bodyStyle
  8661. * Custom CSS styles to be applied to the {@link #body} element in the format expected by
  8662. * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
  8663. */
  8664. /**
  8665. * @cfg {String} iconCls
  8666. * The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
  8667. * <p>An example of specifying a custom icon class would be something like:
  8668. * </p><pre><code>
  8669. // specify the property in the config for the class:
  8670. ...
  8671. iconCls: 'my-icon'
  8672. // css class that specifies background image to be used as the icon image:
  8673. .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
  8674. </code></pre>
  8675. */
  8676. /**
  8677. * @cfg {Boolean} collapsible
  8678. * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
  8679. * the header tool button area, false to keep the panel statically sized with no button (defaults to false).
  8680. */
  8681. /**
  8682. * @cfg {Array} tools
  8683. * An array of tool button configs to be added to the header tool area. When rendered, each tool is
  8684. * stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i>&lt;tool-type&gt;</i></code>
  8685. * <p>Each tool config may contain the following properties:
  8686. * <div class="mdetail-params"><ul>
  8687. * <li><b>id</b> : String<div class="sub-desc"><b>Required.</b> The type
  8688. * of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i>&lt;tool-type&gt;</i></code> to the
  8689. * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
  8690. * The developer may implement custom tools by supplying alternate CSS rules and background images:
  8691. * <ul>
  8692. * <div class="x-tool x-tool-toggle" style="float:left; margin-right:5;"> </div><div><code> toggle</code> (Created by default when {@link #collapsible} is <code>true</code>)</div>
  8693. * <div class="x-tool x-tool-close" style="float:left; margin-right:5;"> </div><div><code> close</code></div>
  8694. * <div class="x-tool x-tool-minimize" style="float:left; margin-right:5;"> </div><div><code> minimize</code></div>
  8695. * <div class="x-tool x-tool-maximize" style="float:left; margin-right:5;"> </div><div><code> maximize</code></div>
  8696. * <div class="x-tool x-tool-restore" style="float:left; margin-right:5;"> </div><div><code> restore</code></div>
  8697. * <div class="x-tool x-tool-gear" style="float:left; margin-right:5;"> </div><div><code> gear</code></div>
  8698. * <div class="x-tool x-tool-pin" style="float:left; margin-right:5;"> </div><div><code> pin</code></div>
  8699. * <div class="x-tool x-tool-unpin" style="float:left; margin-right:5;"> </div><div><code> unpin</code></div>
  8700. * <div class="x-tool x-tool-right" style="float:left; margin-right:5;"> </div><div><code> right</code></div>
  8701. * <div class="x-tool x-tool-left" style="float:left; margin-right:5;"> </div><div><code> left</code></div>
  8702. * <div class="x-tool x-tool-up" style="float:left; margin-right:5;"> </div><div><code> up</code></div>
  8703. * <div class="x-tool x-tool-down" style="float:left; margin-right:5;"> </div><div><code> down</code></div>
  8704. * <div class="x-tool x-tool-refresh" style="float:left; margin-right:5;"> </div><div><code> refresh</code></div>
  8705. * <div class="x-tool x-tool-minus" style="float:left; margin-right:5;"> </div><div><code> minus</code></div>
  8706. * <div class="x-tool x-tool-plus" style="float:left; margin-right:5;"> </div><div><code> plus</code></div>
  8707. * <div class="x-tool x-tool-help" style="float:left; margin-right:5;"> </div><div><code> help</code></div>
  8708. * <div class="x-tool x-tool-search" style="float:left; margin-right:5;"> </div><div><code> search</code></div>
  8709. * <div class="x-tool x-tool-save" style="float:left; margin-right:5;"> </div><div><code> save</code></div>
  8710. * <div class="x-tool x-tool-print" style="float:left; margin-right:5;"> </div><div><code> print</code></div>
  8711. * </ul></div></li>
  8712. * <li><b>handler</b> : Function<div class="sub-desc"><b>Required.</b> The function to
  8713. * call when clicked. Arguments passed are:<ul>
  8714. * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
  8715. * <li><b>toolEl</b> : Ext.Element<div class="sub-desc">The tool Element.</div></li>
  8716. * <li><b>panel</b> : Ext.Panel<div class="sub-desc">The host Panel</div></li>
  8717. * <li><b>tc</b> : Object<div class="sub-desc">The tool configuration object</div></li>
  8718. * </ul></div></li>
  8719. * <li><b>stopEvent</b> : Boolean<div class="sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
  8720. * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the handler.</div></li>
  8721. * <li><b>qtip</b> : String/Object<div class="sub-desc">A tip string, or
  8722. * a config argument to {@link Ext.QuickTip#register}</div></li>
  8723. * <li><b>hidden</b> : Boolean<div class="sub-desc">True to initially render hidden.</div></li>
  8724. * <li><b>on</b> : Object<div class="sub-desc">A listener config object specifiying
  8725. * event listeners in the format of an argument to {@link #addListener}</div></li>
  8726. * </ul></div>
  8727. * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
  8728. * tools only provide the visual button. Any required functionality must be provided by adding
  8729. * handlers that implement the necessary behavior.</p>
  8730. * <p>Example usage:</p>
  8731. * <pre><code>
  8732. tools:[{
  8733. id:'refresh',
  8734. qtip: 'Refresh form Data',
  8735. // hidden:true,
  8736. handler: function(event, toolEl, panel){
  8737. // refresh logic
  8738. }
  8739. },
  8740. {
  8741. id:'help',
  8742. qtip: 'Get Help',
  8743. handler: function(event, toolEl, panel){
  8744. // whatever
  8745. }
  8746. }]
  8747. </code></pre>
  8748. * <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
  8749. * a 15x15 image:</p>
  8750. * <pre><code>
  8751. .x-tool-help {background-image: url(images/help.png);}
  8752. .x-tool-help-over {background-image: url(images/help_over.png);}
  8753. // if using an image sprite:
  8754. .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
  8755. .x-tool-help-over {background-position:-15px 0;}
  8756. </code></pre>
  8757. */
  8758. /**
  8759. * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
  8760. * <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
  8761. new Ext.Template('&lt;div class="x-tool x-tool-{id}">&amp;#160;&lt;/div>')</code></pre>
  8762. * <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
  8763. * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
  8764. * as specified in {@link #tools}. In the following example an &lt;a> tag is used to provide a
  8765. * visual indication when hovering over the tool:</p><pre><code>
  8766. var win = new Ext.Window({
  8767. tools: [{
  8768. id: 'download',
  8769. href: '/MyPdfDoc.pdf'
  8770. }],
  8771. toolTemplate: new Ext.XTemplate(
  8772. '&lt;tpl if="id==\'download\'">',
  8773. '&lt;a class="x-tool x-tool-pdf" href="{href}">&lt;/a>',
  8774. '&lt;/tpl>',
  8775. '&lt;tpl if="id!=\'download\'">',
  8776. '&lt;div class="x-tool x-tool-{id}">&amp;#160;&lt;/div>',
  8777. '&lt;/tpl>'
  8778. ),
  8779. width:500,
  8780. height:300,
  8781. closeAction:'hide'
  8782. });</code></pre>
  8783. * <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
  8784. * appropriate background image, something like:</p>
  8785. <pre><code>
  8786. a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
  8787. </code></pre>
  8788. */
  8789. /**
  8790. * @cfg {Boolean} hideCollapseTool
  8791. * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
  8792. * <code>false</code> to display it (defaults to <code>false</code>).
  8793. */
  8794. /**
  8795. * @cfg {Boolean} titleCollapse
  8796. * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
  8797. * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
  8798. * (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
  8799. * {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
  8800. * <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
  8801. */
  8802. /**
  8803. * @cfg {Mixed} floating
  8804. * <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
  8805. * configuration property are:</p><div class="mdetail-params"><ul>
  8806. * <li><b><code>false</code></b> : <b>Default.</b><div class="sub-desc">Display the panel inline where it is
  8807. * rendered.</div></li>
  8808. * <li><b><code>true</code></b> : <div class="sub-desc">Float the panel (absolute position it with automatic
  8809. * shimming and shadow).<ul>
  8810. * <div class="sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
  8811. * panel at negative offsets so that it is hidden.</div>
  8812. * <div class="sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
  8813. * <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
  8814. * <div class="sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
  8815. * otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
  8816. * </ul></div></li>
  8817. * <li><b><code>{@link Ext.Layer object}</code></b> : <div class="sub-desc">The specified object will be used
  8818. * as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
  8819. * </ul></div>
  8820. */
  8821. /**
  8822. * @cfg {Boolean/String} shadow
  8823. * <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
  8824. * panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>). Note that this option
  8825. * only applies when <code>{@link #floating} = true</code>.
  8826. */
  8827. /**
  8828. * @cfg {Number} shadowOffset
  8829. * The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
  8830. * option only applies when <code>{@link #floating} = true</code>.
  8831. */
  8832. /**
  8833. * @cfg {Boolean} shim
  8834. * <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
  8835. * Note that this option only applies when <code>{@link #floating} = true</code>.
  8836. */
  8837. /**
  8838. * @cfg {Object/Array} keys
  8839. * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
  8840. * used to assign custom key handling to this panel (defaults to <code>null</code>).
  8841. */
  8842. /**
  8843. * @cfg {Boolean/Object} draggable
  8844. * <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
  8845. * <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
  8846. * in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
  8847. * moves a proxy Element around in place of the Panel's element, but provides no other behaviour
  8848. * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
  8849. * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
  8850. * <pre><code>
  8851. new Ext.Panel({
  8852. title: 'Drag me',
  8853. x: 100,
  8854. y: 100,
  8855. renderTo: Ext.getBody(),
  8856. floating: true,
  8857. frame: true,
  8858. width: 400,
  8859. height: 200,
  8860. draggable: {
  8861. // Config option of Ext.Panel.DD class.
  8862. // It&#39;s a floating Panel, so do not show a placeholder proxy in the original position.
  8863. insertProxy: false,
  8864. // Called for each mousemove event while dragging the DD object.
  8865. onDrag : function(e){
  8866. // Record the x,y position of the drag proxy so that we can
  8867. // position the Panel at end of drag.
  8868. var pel = this.proxy.getEl();
  8869. this.x = pel.getLeft(true);
  8870. this.y = pel.getTop(true);
  8871. // Keep the Shadow aligned if there is one.
  8872. var s = this.panel.getEl().shadow;
  8873. if (s) {
  8874. s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
  8875. }
  8876. },
  8877. // Called on the mouseup event.
  8878. endDrag : function(e){
  8879. this.panel.setPosition(this.x, this.y);
  8880. }
  8881. }
  8882. }).show();
  8883. </code></pre>
  8884. */
  8885. /**
  8886. * @cfg {Boolean} disabled
  8887. * Render this panel disabled (default is <code>false</code>). An important note when using the disabled
  8888. * config on panels is that IE will often fail to initialize the disabled mask element correectly if
  8889. * the panel's layout has not yet completed by the time the Panel is disabled during the render process.
  8890. * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
  8891. * the disabled state:
  8892. * <pre><code>
  8893. new Ext.Panel({
  8894. ...
  8895. listeners: {
  8896. 'afterlayout': {
  8897. fn: function(p){
  8898. p.disable();
  8899. },
  8900. single: true // important, as many layouts can occur
  8901. }
  8902. }
  8903. });
  8904. </code></pre>
  8905. */
  8906. /**
  8907. * @cfg {Boolean} autoHeight
  8908. * <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
  8909. * <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
  8910. * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
  8911. * manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
  8912. * can cause issues with scrolling and will not generally work as expected since the panel will take
  8913. * on the height of its contents rather than the height required by the Ext layout.
  8914. */
  8915. /**
  8916. * @cfg {String} baseCls
  8917. * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
  8918. * <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
  8919. * except for required attributes for Ext layouts to function (e.g. overflow:hidden).
  8920. * See <code>{@link #unstyled}</code> also.</p>
  8921. */
  8922. baseCls : 'x-panel',
  8923. /**
  8924. * @cfg {String} collapsedCls
  8925. * A CSS class to add to the panel's element after it has been collapsed (defaults to
  8926. * <code>'x-panel-collapsed'</code>).
  8927. */
  8928. collapsedCls : 'x-panel-collapsed',
  8929. /**
  8930. * @cfg {Boolean} maskDisabled
  8931. * <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
  8932. * to <code>true</code>). Either way, the panel will always tell its contained elements to disable themselves
  8933. * when it is disabled, but masking the panel can provide an additional visual cue that the panel is
  8934. * disabled.
  8935. */
  8936. maskDisabled : true,
  8937. /**
  8938. * @cfg {Boolean} animCollapse
  8939. * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
  8940. * animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
  8941. */
  8942. animCollapse : Ext.enableFx,
  8943. /**
  8944. * @cfg {Boolean} headerAsText
  8945. * <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
  8946. * <code>false</code> to hide it (defaults to <code>true</code>).
  8947. */
  8948. headerAsText : true,
  8949. /**
  8950. * @cfg {String} buttonAlign
  8951. * The alignment of any {@link #buttons} added to this panel. Valid values are <code>'right'</code>,
  8952. * <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
  8953. */
  8954. buttonAlign : 'right',
  8955. /**
  8956. * @cfg {Boolean} collapsed
  8957. * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
  8958. * <code>false</code>).
  8959. */
  8960. collapsed : false,
  8961. /**
  8962. * @cfg {Boolean} collapseFirst
  8963. * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
  8964. * any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
  8965. */
  8966. collapseFirst : true,
  8967. /**
  8968. * @cfg {Number} minButtonWidth
  8969. * Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
  8970. */
  8971. minButtonWidth : 75,
  8972. /**
  8973. * @cfg {Boolean} unstyled
  8974. * Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
  8975. * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
  8976. */
  8977. /**
  8978. * @cfg {String} elements
  8979. * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be
  8980. * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
  8981. * make sure a structural element is rendered even if not specified at config time (for example, you may want
  8982. * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this
  8983. * list will allocate the required placeholders in the panel when it is rendered. Valid values are<div class="mdetail-params"><ul>
  8984. * <li><code>header</code></li>
  8985. * <li><code>tbar</code> (top bar)</li>
  8986. * <li><code>body</code></li>
  8987. * <li><code>bbar</code> (bottom bar)</li>
  8988. * <li><code>footer</code></li>
  8989. * </ul></div>
  8990. * Defaults to '<code>body</code>'.
  8991. */
  8992. elements : 'body',
  8993. /**
  8994. * @cfg {Boolean} preventBodyReset
  8995. * Defaults to <code>false</code>. When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
  8996. * will be added to the panel's element, effectively applying css styles suggested by the W3C
  8997. * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
  8998. * footer, etc.).
  8999. */
  9000. preventBodyReset : false,
  9001. /**
  9002. * @cfg {Number/String} padding
  9003. * A shortcut for setting a padding style on the body element. The value can either be
  9004. * a number to be applied to all sides, or a normal css string describing padding.
  9005. * Defaults to <tt>undefined</tt>.
  9006. *
  9007. */
  9008. padding: undefined,
  9009. /** @cfg {String} resizeEvent
  9010. * The event to listen to for resizing in layouts. Defaults to <tt>'bodyresize'</tt>.
  9011. */
  9012. resizeEvent: 'bodyresize',
  9013. // protected - these could be used to customize the behavior of the window,
  9014. // but changing them would not be useful without further mofifications and
  9015. // could lead to unexpected or undesirable results.
  9016. toolTarget : 'header',
  9017. collapseEl : 'bwrap',
  9018. slideAnchor : 't',
  9019. disabledClass : '',
  9020. // private, notify box this class will handle heights
  9021. deferHeight : true,
  9022. // private
  9023. expandDefaults: {
  9024. duration : 0.25
  9025. },
  9026. // private
  9027. collapseDefaults : {
  9028. duration : 0.25
  9029. },
  9030. // private
  9031. initComponent : function(){
  9032. Ext.Panel.superclass.initComponent.call(this);
  9033. this.addEvents(
  9034. /**
  9035. * @event bodyresize
  9036. * Fires after the Panel has been resized.
  9037. * @param {Ext.Panel} p the Panel which has been resized.
  9038. * @param {Number} width The Panel body's new width.
  9039. * @param {Number} height The Panel body's new height.
  9040. */
  9041. 'bodyresize',
  9042. /**
  9043. * @event titlechange
  9044. * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
  9045. * @param {Ext.Panel} p the Panel which has had its title changed.
  9046. * @param {String} The new title.
  9047. */
  9048. 'titlechange',
  9049. /**
  9050. * @event iconchange
  9051. * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
  9052. * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
  9053. * @param {String} The new icon class.
  9054. * @param {String} The old icon class.
  9055. */
  9056. 'iconchange',
  9057. /**
  9058. * @event collapse
  9059. * Fires after the Panel has been collapsed.
  9060. * @param {Ext.Panel} p the Panel that has been collapsed.
  9061. */
  9062. 'collapse',
  9063. /**
  9064. * @event expand
  9065. * Fires after the Panel has been expanded.
  9066. * @param {Ext.Panel} p The Panel that has been expanded.
  9067. */
  9068. 'expand',
  9069. /**
  9070. * @event beforecollapse
  9071. * Fires before the Panel is collapsed. A handler can return false to cancel the collapse.
  9072. * @param {Ext.Panel} p the Panel being collapsed.
  9073. * @param {Boolean} animate True if the collapse is animated, else false.
  9074. */
  9075. 'beforecollapse',
  9076. /**
  9077. * @event beforeexpand
  9078. * Fires before the Panel is expanded. A handler can return false to cancel the expand.
  9079. * @param {Ext.Panel} p The Panel being expanded.
  9080. * @param {Boolean} animate True if the expand is animated, else false.
  9081. */
  9082. 'beforeexpand',
  9083. /**
  9084. * @event beforeclose
  9085. * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some
  9086. * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only
  9087. * applies to such subclasses.
  9088. * A handler can return false to cancel the close.
  9089. * @param {Ext.Panel} p The Panel being closed.
  9090. */
  9091. 'beforeclose',
  9092. /**
  9093. * @event close
  9094. * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some
  9095. * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
  9096. * @param {Ext.Panel} p The Panel that has been closed.
  9097. */
  9098. 'close',
  9099. /**
  9100. * @event activate
  9101. * Fires after the Panel has been visually activated.
  9102. * Note that Panels do not directly support being activated, but some Panel subclasses
  9103. * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
  9104. * activate and deactivate events under the control of the TabPanel.
  9105. * @param {Ext.Panel} p The Panel that has been activated.
  9106. */
  9107. 'activate',
  9108. /**
  9109. * @event deactivate
  9110. * Fires after the Panel has been visually deactivated.
  9111. * Note that Panels do not directly support being deactivated, but some Panel subclasses
  9112. * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
  9113. * activate and deactivate events under the control of the TabPanel.
  9114. * @param {Ext.Panel} p The Panel that has been deactivated.
  9115. */
  9116. 'deactivate'
  9117. );
  9118. if(this.unstyled){
  9119. this.baseCls = 'x-plain';
  9120. }
  9121. this.toolbars = [];
  9122. // shortcuts
  9123. if(this.tbar){
  9124. this.elements += ',tbar';
  9125. this.topToolbar = this.createToolbar(this.tbar);
  9126. this.tbar = null;
  9127. }
  9128. if(this.bbar){
  9129. this.elements += ',bbar';
  9130. this.bottomToolbar = this.createToolbar(this.bbar);
  9131. this.bbar = null;
  9132. }
  9133. if(this.header === true){
  9134. this.elements += ',header';
  9135. this.header = null;
  9136. }else if(this.headerCfg || (this.title && this.header !== false)){
  9137. this.elements += ',header';
  9138. }
  9139. if(this.footerCfg || this.footer === true){
  9140. this.elements += ',footer';
  9141. this.footer = null;
  9142. }
  9143. if(this.buttons){
  9144. this.fbar = this.buttons;
  9145. this.buttons = null;
  9146. }
  9147. if(this.fbar){
  9148. this.createFbar(this.fbar);
  9149. }
  9150. if(this.autoLoad){
  9151. this.on('render', this.doAutoLoad, this, {delay:10});
  9152. }
  9153. },
  9154. // private
  9155. createFbar : function(fbar){
  9156. var min = this.minButtonWidth;
  9157. this.elements += ',footer';
  9158. this.fbar = this.createToolbar(fbar, {
  9159. buttonAlign: this.buttonAlign,
  9160. toolbarCls: 'x-panel-fbar',
  9161. enableOverflow: false,
  9162. defaults: function(c){
  9163. return {
  9164. minWidth: c.minWidth || min
  9165. };
  9166. }
  9167. });
  9168. // @compat addButton and buttons could possibly be removed
  9169. // @target 4.0
  9170. /**
  9171. * This Panel's Array of buttons as created from the <code>{@link #buttons}</code>
  9172. * config property. Read only.
  9173. * @type Array
  9174. * @property buttons
  9175. */
  9176. this.fbar.items.each(function(c){
  9177. c.minWidth = c.minWidth || this.minButtonWidth;
  9178. }, this);
  9179. this.buttons = this.fbar.items.items;
  9180. },
  9181. // private
  9182. createToolbar: function(tb, options){
  9183. var result;
  9184. // Convert array to proper toolbar config
  9185. if(Ext.isArray(tb)){
  9186. tb = {
  9187. items: tb
  9188. };
  9189. }
  9190. result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar');
  9191. this.toolbars.push(result);
  9192. return result;
  9193. },
  9194. // private
  9195. createElement : function(name, pnode){
  9196. if(this[name]){
  9197. pnode.appendChild(this[name].dom);
  9198. return;
  9199. }
  9200. if(name === 'bwrap' || this.elements.indexOf(name) != -1){
  9201. if(this[name+'Cfg']){
  9202. this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']);
  9203. }else{
  9204. var el = document.createElement('div');
  9205. el.className = this[name+'Cls'];
  9206. this[name] = Ext.get(pnode.appendChild(el));
  9207. }
  9208. if(this[name+'CssClass']){
  9209. this[name].addClass(this[name+'CssClass']);
  9210. }
  9211. if(this[name+'Style']){
  9212. this[name].applyStyles(this[name+'Style']);
  9213. }
  9214. }
  9215. },
  9216. // private
  9217. onRender : function(ct, position){
  9218. Ext.Panel.superclass.onRender.call(this, ct, position);
  9219. this.createClasses();
  9220. var el = this.el,
  9221. d = el.dom,
  9222. bw,
  9223. ts;
  9224. if(this.collapsible && !this.hideCollapseTool){
  9225. this.tools = this.tools ? this.tools.slice(0) : [];
  9226. this.tools[this.collapseFirst?'unshift':'push']({
  9227. id: 'toggle',
  9228. handler : this.toggleCollapse,
  9229. scope: this
  9230. });
  9231. }
  9232. if(this.tools){
  9233. ts = this.tools;
  9234. this.elements += (this.header !== false) ? ',header' : '';
  9235. }
  9236. this.tools = {};
  9237. el.addClass(this.baseCls);
  9238. if(d.firstChild){ // existing markup
  9239. this.header = el.down('.'+this.headerCls);
  9240. this.bwrap = el.down('.'+this.bwrapCls);
  9241. var cp = this.bwrap ? this.bwrap : el;
  9242. this.tbar = cp.down('.'+this.tbarCls);
  9243. this.body = cp.down('.'+this.bodyCls);
  9244. this.bbar = cp.down('.'+this.bbarCls);
  9245. this.footer = cp.down('.'+this.footerCls);
  9246. this.fromMarkup = true;
  9247. }
  9248. if (this.preventBodyReset === true) {
  9249. el.addClass('x-panel-reset');
  9250. }
  9251. if(this.cls){
  9252. el.addClass(this.cls);
  9253. }
  9254. if(this.buttons){
  9255. this.elements += ',footer';
  9256. }
  9257. // This block allows for maximum flexibility and performance when using existing markup
  9258. // framing requires special markup
  9259. if(this.frame){
  9260. el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
  9261. this.createElement('header', d.firstChild.firstChild.firstChild);
  9262. this.createElement('bwrap', d);
  9263. // append the mid and bottom frame to the bwrap
  9264. bw = this.bwrap.dom;
  9265. var ml = d.childNodes[1], bl = d.childNodes[2];
  9266. bw.appendChild(ml);
  9267. bw.appendChild(bl);
  9268. var mc = bw.firstChild.firstChild.firstChild;
  9269. this.createElement('tbar', mc);
  9270. this.createElement('body', mc);
  9271. this.createElement('bbar', mc);
  9272. this.createElement('footer', bw.lastChild.firstChild.firstChild);
  9273. if(!this.footer){
  9274. this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
  9275. }
  9276. /*
  9277. * Store a reference to this element so:
  9278. * a) We aren't looking it up all the time
  9279. * b) The last element is reported incorrectly when using a loadmask
  9280. */
  9281. this.ft = Ext.get(this.bwrap.dom.lastChild);
  9282. this.mc = Ext.get(mc);
  9283. }else{
  9284. this.createElement('header', d);
  9285. this.createElement('bwrap', d);
  9286. // append the mid and bottom frame to the bwrap
  9287. bw = this.bwrap.dom;
  9288. this.createElement('tbar', bw);
  9289. this.createElement('body', bw);
  9290. this.createElement('bbar', bw);
  9291. this.createElement('footer', bw);
  9292. if(!this.header){
  9293. this.body.addClass(this.bodyCls + '-noheader');
  9294. if(this.tbar){
  9295. this.tbar.addClass(this.tbarCls + '-noheader');
  9296. }
  9297. }
  9298. }
  9299. if(Ext.isDefined(this.padding)){
  9300. this.body.setStyle('padding', this.body.addUnits(this.padding));
  9301. }
  9302. if(this.border === false){
  9303. this.el.addClass(this.baseCls + '-noborder');
  9304. this.body.addClass(this.bodyCls + '-noborder');
  9305. if(this.header){
  9306. this.header.addClass(this.headerCls + '-noborder');
  9307. }
  9308. if(this.footer){
  9309. this.footer.addClass(this.footerCls + '-noborder');
  9310. }
  9311. if(this.tbar){
  9312. this.tbar.addClass(this.tbarCls + '-noborder');
  9313. }
  9314. if(this.bbar){
  9315. this.bbar.addClass(this.bbarCls + '-noborder');
  9316. }
  9317. }
  9318. if(this.bodyBorder === false){
  9319. this.body.addClass(this.bodyCls + '-noborder');
  9320. }
  9321. this.bwrap.enableDisplayMode('block');
  9322. if(this.header){
  9323. this.header.unselectable();
  9324. // for tools, we need to wrap any existing header markup
  9325. if(this.headerAsText){
  9326. this.header.dom.innerHTML =
  9327. '<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
  9328. if(this.iconCls){
  9329. this.setIconClass(this.iconCls);
  9330. }
  9331. }
  9332. }
  9333. if(this.floating){
  9334. this.makeFloating(this.floating);
  9335. }
  9336. if(this.collapsible && this.titleCollapse && this.header){
  9337. this.mon(this.header, 'click', this.toggleCollapse, this);
  9338. this.header.setStyle('cursor', 'pointer');
  9339. }
  9340. if(ts){
  9341. this.addTool.apply(this, ts);
  9342. }
  9343. // Render Toolbars.
  9344. if(this.fbar){
  9345. this.footer.addClass('x-panel-btns');
  9346. this.fbar.ownerCt = this;
  9347. this.fbar.render(this.footer);
  9348. this.footer.createChild({cls:'x-clear'});
  9349. }
  9350. if(this.tbar && this.topToolbar){
  9351. this.topToolbar.ownerCt = this;
  9352. this.topToolbar.render(this.tbar);
  9353. }
  9354. if(this.bbar && this.bottomToolbar){
  9355. this.bottomToolbar.ownerCt = this;
  9356. this.bottomToolbar.render(this.bbar);
  9357. }
  9358. },
  9359. /**
  9360. * Sets the CSS class that provides the icon image for this panel. This method will replace any existing
  9361. * icon class if one has already been set and fire the {@link #iconchange} event after completion.
  9362. * @param {String} cls The new CSS class name
  9363. */
  9364. setIconClass : function(cls){
  9365. var old = this.iconCls;
  9366. this.iconCls = cls;
  9367. if(this.rendered && this.header){
  9368. if(this.frame){
  9369. this.header.addClass('x-panel-icon');
  9370. this.header.replaceClass(old, this.iconCls);
  9371. }else{
  9372. var hd = this.header,
  9373. img = hd.child('img.x-panel-inline-icon');
  9374. if(img){
  9375. Ext.fly(img).replaceClass(old, this.iconCls);
  9376. }else{
  9377. var hdspan = hd.child('span.' + this.headerTextCls);
  9378. if (hdspan) {
  9379. Ext.DomHelper.insertBefore(hdspan.dom, {
  9380. tag:'img', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls
  9381. });
  9382. }
  9383. }
  9384. }
  9385. }
  9386. this.fireEvent('iconchange', this, cls, old);
  9387. },
  9388. // private
  9389. makeFloating : function(cfg){
  9390. this.floating = true;
  9391. this.el = new Ext.Layer(Ext.apply({}, cfg, {
  9392. shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
  9393. shadowOffset: this.shadowOffset,
  9394. constrain:false,
  9395. shim: this.shim === false ? false : undefined
  9396. }), this.el);
  9397. },
  9398. /**
  9399. * Returns the {@link Ext.Toolbar toolbar} from the top (<code>{@link #tbar}</code>) section of the panel.
  9400. * @return {Ext.Toolbar} The toolbar
  9401. */
  9402. getTopToolbar : function(){
  9403. return this.topToolbar;
  9404. },
  9405. /**
  9406. * Returns the {@link Ext.Toolbar toolbar} from the bottom (<code>{@link #bbar}</code>) section of the panel.
  9407. * @return {Ext.Toolbar} The toolbar
  9408. */
  9409. getBottomToolbar : function(){
  9410. return this.bottomToolbar;
  9411. },
  9412. /**
  9413. * Returns the {@link Ext.Toolbar toolbar} from the footer (<code>{@link #fbar}</code>) section of the panel.
  9414. * @return {Ext.Toolbar} The toolbar
  9415. */
  9416. getFooterToolbar : function() {
  9417. return this.fbar;
  9418. },
  9419. /**
  9420. * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred
  9421. * approach is to add buttons via the {@link #buttons} config.
  9422. * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
  9423. * button config, an object will be treated as a button config object.
  9424. * @param {Function} handler The function to be called on button {@link Ext.Button#click}
  9425. * @param {Object} scope The scope (<code>this</code> reference) in which the button handler function is executed. Defaults to the Button.
  9426. * @return {Ext.Button} The button that was added
  9427. */
  9428. addButton : function(config, handler, scope){
  9429. if(!this.fbar){
  9430. this.createFbar([]);
  9431. }
  9432. if(handler){
  9433. if(Ext.isString(config)){
  9434. config = {text: config};
  9435. }
  9436. config = Ext.apply({
  9437. handler: handler,
  9438. scope: scope
  9439. }, config);
  9440. }
  9441. return this.fbar.add(config);
  9442. },
  9443. // private
  9444. addTool : function(){
  9445. if(!this.rendered){
  9446. if(!this.tools){
  9447. this.tools = [];
  9448. }
  9449. Ext.each(arguments, function(arg){
  9450. this.tools.push(arg);
  9451. }, this);
  9452. return;
  9453. }
  9454. // nowhere to render tools!
  9455. if(!this[this.toolTarget]){
  9456. return;
  9457. }
  9458. if(!this.toolTemplate){
  9459. // initialize the global tool template on first use
  9460. var tt = new Ext.Template(
  9461. '<div class="x-tool x-tool-{id}">&#160;</div>'
  9462. );
  9463. tt.disableFormats = true;
  9464. tt.compile();
  9465. Ext.Panel.prototype.toolTemplate = tt;
  9466. }
  9467. for(var i = 0, a = arguments, len = a.length; i < len; i++) {
  9468. var tc = a[i];
  9469. if(!this.tools[tc.id]){
  9470. var overCls = 'x-tool-'+tc.id+'-over';
  9471. var t = this.toolTemplate.insertFirst(this[this.toolTarget], tc, true);
  9472. this.tools[tc.id] = t;
  9473. t.enableDisplayMode('block');
  9474. this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this));
  9475. if(tc.on){
  9476. this.mon(t, tc.on);
  9477. }
  9478. if(tc.hidden){
  9479. t.hide();
  9480. }
  9481. if(tc.qtip){
  9482. if(Ext.isObject(tc.qtip)){
  9483. Ext.QuickTips.register(Ext.apply({
  9484. target: t.id
  9485. }, tc.qtip));
  9486. } else {
  9487. t.dom.qtip = tc.qtip;
  9488. }
  9489. }
  9490. t.addClassOnOver(overCls);
  9491. }
  9492. }
  9493. },
  9494. onLayout : function(shallow, force){
  9495. Ext.Panel.superclass.onLayout.apply(this, arguments);
  9496. if(this.hasLayout && this.toolbars.length > 0){
  9497. Ext.each(this.toolbars, function(tb){
  9498. tb.doLayout(undefined, force);
  9499. });
  9500. this.syncHeight();
  9501. }
  9502. },
  9503. syncHeight : function(){
  9504. var h = this.toolbarHeight,
  9505. bd = this.body,
  9506. lsh = this.lastSize.height,
  9507. sz;
  9508. if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
  9509. return;
  9510. }
  9511. if(h != this.getToolbarHeight()){
  9512. h = Math.max(0, lsh - this.getFrameHeight());
  9513. bd.setHeight(h);
  9514. sz = bd.getSize();
  9515. this.toolbarHeight = this.getToolbarHeight();
  9516. this.onBodyResize(sz.width, sz.height);
  9517. }
  9518. },
  9519. // private
  9520. onShow : function(){
  9521. if(this.floating){
  9522. return this.el.show();
  9523. }
  9524. Ext.Panel.superclass.onShow.call(this);
  9525. },
  9526. // private
  9527. onHide : function(){
  9528. if(this.floating){
  9529. return this.el.hide();
  9530. }
  9531. Ext.Panel.superclass.onHide.call(this);
  9532. },
  9533. // private
  9534. createToolHandler : function(t, tc, overCls, panel){
  9535. return function(e){
  9536. t.removeClass(overCls);
  9537. if(tc.stopEvent !== false){
  9538. e.stopEvent();
  9539. }
  9540. if(tc.handler){
  9541. tc.handler.call(tc.scope || t, e, t, panel, tc);
  9542. }
  9543. };
  9544. },
  9545. // private
  9546. afterRender : function(){
  9547. if(this.floating && !this.hidden){
  9548. this.el.show();
  9549. }
  9550. if(this.title){
  9551. this.setTitle(this.title);
  9552. }
  9553. Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
  9554. if (this.collapsed) {
  9555. this.collapsed = false;
  9556. this.collapse(false);
  9557. }
  9558. this.initEvents();
  9559. },
  9560. // private
  9561. getKeyMap : function(){
  9562. if(!this.keyMap){
  9563. this.keyMap = new Ext.KeyMap(this.el, this.keys);
  9564. }
  9565. return this.keyMap;
  9566. },
  9567. // private
  9568. initEvents : function(){
  9569. if(this.keys){
  9570. this.getKeyMap();
  9571. }
  9572. if(this.draggable){
  9573. this.initDraggable();
  9574. }
  9575. if(this.toolbars.length > 0){
  9576. Ext.each(this.toolbars, function(tb){
  9577. tb.doLayout();
  9578. tb.on({
  9579. scope: this,
  9580. afterlayout: this.syncHeight,
  9581. remove: this.syncHeight
  9582. });
  9583. }, this);
  9584. this.syncHeight();
  9585. }
  9586. },
  9587. // private
  9588. initDraggable : function(){
  9589. /**
  9590. * <p>If this Panel is configured {@link #draggable}, this property will contain
  9591. * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
  9592. * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
  9593. * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
  9594. * @type Ext.dd.DragSource.
  9595. * @property dd
  9596. */
  9597. this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
  9598. },
  9599. // private
  9600. beforeEffect : function(anim){
  9601. if(this.floating){
  9602. this.el.beforeAction();
  9603. }
  9604. if(anim !== false){
  9605. this.el.addClass('x-panel-animated');
  9606. }
  9607. },
  9608. // private
  9609. afterEffect : function(anim){
  9610. this.syncShadow();
  9611. this.el.removeClass('x-panel-animated');
  9612. },
  9613. // private - wraps up an animation param with internal callbacks
  9614. createEffect : function(a, cb, scope){
  9615. var o = {
  9616. scope:scope,
  9617. block:true
  9618. };
  9619. if(a === true){
  9620. o.callback = cb;
  9621. return o;
  9622. }else if(!a.callback){
  9623. o.callback = cb;
  9624. }else { // wrap it up
  9625. o.callback = function(){
  9626. cb.call(scope);
  9627. Ext.callback(a.callback, a.scope);
  9628. };
  9629. }
  9630. return Ext.applyIf(o, a);
  9631. },
  9632. /**
  9633. * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will
  9634. * cancel the collapse action if it returns false.
  9635. * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
  9636. * {@link #animCollapse} panel config)
  9637. * @return {Ext.Panel} this
  9638. */
  9639. collapse : function(animate){
  9640. if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){
  9641. return;
  9642. }
  9643. var doAnim = animate === true || (animate !== false && this.animCollapse);
  9644. this.beforeEffect(doAnim);
  9645. this.onCollapse(doAnim, animate);
  9646. return this;
  9647. },
  9648. // private
  9649. onCollapse : function(doAnim, animArg){
  9650. if(doAnim){
  9651. this[this.collapseEl].slideOut(this.slideAnchor,
  9652. Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
  9653. this.collapseDefaults));
  9654. }else{
  9655. this[this.collapseEl].hide(this.hideMode);
  9656. this.afterCollapse(false);
  9657. }
  9658. },
  9659. // private
  9660. afterCollapse : function(anim){
  9661. this.collapsed = true;
  9662. this.el.addClass(this.collapsedCls);
  9663. if(anim !== false){
  9664. this[this.collapseEl].hide(this.hideMode);
  9665. }
  9666. this.afterEffect(anim);
  9667. // Reset lastSize of all sub-components so they KNOW they are in a collapsed container
  9668. this.cascade(function(c) {
  9669. if (c.lastSize) {
  9670. c.lastSize = { width: 0, height: 0 };
  9671. }
  9672. });
  9673. this.fireEvent('collapse', this);
  9674. },
  9675. /**
  9676. * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will
  9677. * cancel the expand action if it returns false.
  9678. * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
  9679. * {@link #animCollapse} panel config)
  9680. * @return {Ext.Panel} this
  9681. */
  9682. expand : function(animate){
  9683. if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){
  9684. return;
  9685. }
  9686. var doAnim = animate === true || (animate !== false && this.animCollapse);
  9687. this.el.removeClass(this.collapsedCls);
  9688. this.beforeEffect(doAnim);
  9689. this.onExpand(doAnim, animate);
  9690. return this;
  9691. },
  9692. // private
  9693. onExpand : function(doAnim, animArg){
  9694. if(doAnim){
  9695. this[this.collapseEl].slideIn(this.slideAnchor,
  9696. Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
  9697. this.expandDefaults));
  9698. }else{
  9699. this[this.collapseEl].show(this.hideMode);
  9700. this.afterExpand(false);
  9701. }
  9702. },
  9703. // private
  9704. afterExpand : function(anim){
  9705. this.collapsed = false;
  9706. if(anim !== false){
  9707. this[this.collapseEl].show(this.hideMode);
  9708. }
  9709. this.afterEffect(anim);
  9710. if (this.deferLayout) {
  9711. delete this.deferLayout;
  9712. this.doLayout(true);
  9713. }
  9714. this.fireEvent('expand', this);
  9715. },
  9716. /**
  9717. * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel.
  9718. * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
  9719. * {@link #animCollapse} panel config)
  9720. * @return {Ext.Panel} this
  9721. */
  9722. toggleCollapse : function(animate){
  9723. this[this.collapsed ? 'expand' : 'collapse'](animate);
  9724. return this;
  9725. },
  9726. // private
  9727. onDisable : function(){
  9728. if(this.rendered && this.maskDisabled){
  9729. this.el.mask();
  9730. }
  9731. Ext.Panel.superclass.onDisable.call(this);
  9732. },
  9733. // private
  9734. onEnable : function(){
  9735. if(this.rendered && this.maskDisabled){
  9736. this.el.unmask();
  9737. }
  9738. Ext.Panel.superclass.onEnable.call(this);
  9739. },
  9740. // private
  9741. onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
  9742. var w = adjWidth,
  9743. h = adjHeight;
  9744. if(Ext.isDefined(w) || Ext.isDefined(h)){
  9745. if(!this.collapsed){
  9746. // First, set the the Panel's body width.
  9747. // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
  9748. // The Toolbars must not buffer this resize operation because we need to know their heights.
  9749. if(Ext.isNumber(w)){
  9750. this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
  9751. } else if (w == 'auto') {
  9752. w = this.body.setWidth('auto').dom.offsetWidth;
  9753. } else {
  9754. w = this.body.dom.offsetWidth;
  9755. }
  9756. if(this.tbar){
  9757. this.tbar.setWidth(w);
  9758. if(this.topToolbar){
  9759. this.topToolbar.setSize(w);
  9760. }
  9761. }
  9762. if(this.bbar){
  9763. this.bbar.setWidth(w);
  9764. if(this.bottomToolbar){
  9765. this.bottomToolbar.setSize(w);
  9766. // The bbar does not move on resize without this.
  9767. if (Ext.isIE) {
  9768. this.bbar.setStyle('position', 'static');
  9769. this.bbar.setStyle('position', '');
  9770. }
  9771. }
  9772. }
  9773. if(this.footer){
  9774. this.footer.setWidth(w);
  9775. if(this.fbar){
  9776. this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
  9777. }
  9778. }
  9779. // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
  9780. if(Ext.isNumber(h)){
  9781. h = Math.max(0, h - this.getFrameHeight());
  9782. //h = Math.max(0, h - (this.getHeight() - this.body.getHeight()));
  9783. this.body.setHeight(h);
  9784. }else if(h == 'auto'){
  9785. this.body.setHeight(h);
  9786. }
  9787. if(this.disabled && this.el._mask){
  9788. this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
  9789. }
  9790. }else{
  9791. // Adds an event to set the correct height afterExpand. This accounts for the deferHeight flag in panel
  9792. this.queuedBodySize = {width: w, height: h};
  9793. if(!this.queuedExpand && this.allowQueuedExpand !== false){
  9794. this.queuedExpand = true;
  9795. this.on('expand', function(){
  9796. delete this.queuedExpand;
  9797. this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
  9798. }, this, {single:true});
  9799. }
  9800. }
  9801. this.onBodyResize(w, h);
  9802. }
  9803. this.syncShadow();
  9804. Ext.Panel.superclass.onResize.call(this, adjWidth, adjHeight, rawWidth, rawHeight);
  9805. },
  9806. // private
  9807. onBodyResize: function(w, h){
  9808. this.fireEvent('bodyresize', this, w, h);
  9809. },
  9810. // private
  9811. getToolbarHeight: function(){
  9812. var h = 0;
  9813. if(this.rendered){
  9814. Ext.each(this.toolbars, function(tb){
  9815. h += tb.getHeight();
  9816. }, this);
  9817. }
  9818. return h;
  9819. },
  9820. // deprecate
  9821. adjustBodyHeight : function(h){
  9822. return h;
  9823. },
  9824. // private
  9825. adjustBodyWidth : function(w){
  9826. return w;
  9827. },
  9828. // private
  9829. onPosition : function(){
  9830. this.syncShadow();
  9831. },
  9832. /**
  9833. * Returns the width in pixels of the framing elements of this panel (not including the body width). To
  9834. * retrieve the body width see {@link #getInnerWidth}.
  9835. * @return {Number} The frame width
  9836. */
  9837. getFrameWidth : function(){
  9838. var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr');
  9839. if(this.frame){
  9840. var l = this.bwrap.dom.firstChild;
  9841. w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r'));
  9842. w += this.mc.getFrameWidth('lr');
  9843. }
  9844. return w;
  9845. },
  9846. /**
  9847. * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and
  9848. * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}.
  9849. * @return {Number} The frame height
  9850. */
  9851. getFrameHeight : function() {
  9852. var h = Math.max(0, this.getHeight() - this.body.getHeight());
  9853. if (isNaN(h)) {
  9854. h = 0;
  9855. }
  9856. return h;
  9857. /* Deprecate
  9858. var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb');
  9859. h += (this.tbar ? this.tbar.getHeight() : 0) +
  9860. (this.bbar ? this.bbar.getHeight() : 0);
  9861. if(this.frame){
  9862. h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb');
  9863. }else{
  9864. h += (this.header ? this.header.getHeight() : 0) +
  9865. (this.footer ? this.footer.getHeight() : 0);
  9866. }
  9867. return h;
  9868. */
  9869. },
  9870. /**
  9871. * Returns the width in pixels of the body element (not including the width of any framing elements).
  9872. * For the frame width see {@link #getFrameWidth}.
  9873. * @return {Number} The body width
  9874. */
  9875. getInnerWidth : function(){
  9876. return this.getSize().width - this.getFrameWidth();
  9877. },
  9878. /**
  9879. * Returns the height in pixels of the body element (not including the height of any framing elements).
  9880. * For the frame height see {@link #getFrameHeight}.
  9881. * @return {Number} The body height
  9882. */
  9883. getInnerHeight : function(){
  9884. return this.body.getHeight();
  9885. /* Deprecate
  9886. return this.getSize().height - this.getFrameHeight();
  9887. */
  9888. },
  9889. // private
  9890. syncShadow : function(){
  9891. if(this.floating){
  9892. this.el.sync(true);
  9893. }
  9894. },
  9895. // private
  9896. getLayoutTarget : function(){
  9897. return this.body;
  9898. },
  9899. // private
  9900. getContentTarget : function(){
  9901. return this.body;
  9902. },
  9903. /**
  9904. * <p>Sets the title text for the panel and optionally the {@link #iconCls icon class}.</p>
  9905. * <p>In order to be able to set the title, a header element must have been created
  9906. * for the Panel. This is triggered either by configuring the Panel with a non-blank <code>{@link #title}</code>,
  9907. * or configuring it with <code><b>{@link #header}: true</b></code>.</p>
  9908. * @param {String} title The title text to set
  9909. * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel
  9910. */
  9911. setTitle : function(title, iconCls){
  9912. this.title = title;
  9913. if(this.header && this.headerAsText){
  9914. this.header.child('span').update(title);
  9915. }
  9916. if(iconCls){
  9917. this.setIconClass(iconCls);
  9918. }
  9919. this.fireEvent('titlechange', this, title);
  9920. return this;
  9921. },
  9922. /**
  9923. * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body.
  9924. * @return {Ext.Updater} The Updater
  9925. */
  9926. getUpdater : function(){
  9927. return this.body.getUpdater();
  9928. },
  9929. /**
  9930. * Loads this content panel immediately with content returned from an XHR call.
  9931. * @param {Object/String/Function} config A config object containing any of the following options:
  9932. <pre><code>
  9933. panel.load({
  9934. url: 'your-url.php',
  9935. params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
  9936. callback: yourFunction,
  9937. scope: yourObject, // optional scope for the callback
  9938. discardUrl: false,
  9939. nocache: false,
  9940. text: 'Loading...',
  9941. timeout: 30,
  9942. scripts: false
  9943. });
  9944. </code></pre>
  9945. * The only required property is url. The optional properties nocache, text and scripts
  9946. * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their
  9947. * associated property on this panel Updater instance.
  9948. * @return {Ext.Panel} this
  9949. */
  9950. load : function(){
  9951. var um = this.body.getUpdater();
  9952. um.update.apply(um, arguments);
  9953. return this;
  9954. },
  9955. // private
  9956. beforeDestroy : function(){
  9957. Ext.Panel.superclass.beforeDestroy.call(this);
  9958. if(this.header){
  9959. this.header.removeAllListeners();
  9960. }
  9961. if(this.tools){
  9962. for(var k in this.tools){
  9963. Ext.destroy(this.tools[k]);
  9964. }
  9965. }
  9966. if(this.toolbars.length > 0){
  9967. Ext.each(this.toolbars, function(tb){
  9968. tb.un('afterlayout', this.syncHeight, this);
  9969. tb.un('remove', this.syncHeight, this);
  9970. }, this);
  9971. }
  9972. if(Ext.isArray(this.buttons)){
  9973. while(this.buttons.length) {
  9974. Ext.destroy(this.buttons[0]);
  9975. }
  9976. }
  9977. if(this.rendered){
  9978. Ext.destroy(
  9979. this.ft,
  9980. this.header,
  9981. this.footer,
  9982. this.toolbars,
  9983. this.tbar,
  9984. this.bbar,
  9985. this.body,
  9986. this.mc,
  9987. this.bwrap
  9988. );
  9989. if (this.fbar) {
  9990. Ext.destroy(
  9991. this.fbar,
  9992. this.fbar.el
  9993. );
  9994. }
  9995. }else{
  9996. Ext.destroy(
  9997. this.topToolbar,
  9998. this.bottomToolbar
  9999. );
  10000. }
  10001. },
  10002. // private
  10003. createClasses : function(){
  10004. this.headerCls = this.baseCls + '-header';
  10005. this.headerTextCls = this.baseCls + '-header-text';
  10006. this.bwrapCls = this.baseCls + '-bwrap';
  10007. this.tbarCls = this.baseCls + '-tbar';
  10008. this.bodyCls = this.baseCls + '-body';
  10009. this.bbarCls = this.baseCls + '-bbar';
  10010. this.footerCls = this.baseCls + '-footer';
  10011. },
  10012. // private
  10013. createGhost : function(cls, useShim, appendTo){
  10014. var el = document.createElement('div');
  10015. el.className = 'x-panel-ghost ' + (cls ? cls : '');
  10016. if(this.header){
  10017. el.appendChild(this.el.dom.firstChild.cloneNode(true));
  10018. }
  10019. Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight());
  10020. el.style.width = this.el.dom.offsetWidth + 'px';;
  10021. if(!appendTo){
  10022. this.container.dom.appendChild(el);
  10023. }else{
  10024. Ext.getDom(appendTo).appendChild(el);
  10025. }
  10026. if(useShim !== false && this.el.useShim !== false){
  10027. var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el);
  10028. layer.show();
  10029. return layer;
  10030. }else{
  10031. return new Ext.Element(el);
  10032. }
  10033. },
  10034. // private
  10035. doAutoLoad : function(){
  10036. var u = this.body.getUpdater();
  10037. if(this.renderer){
  10038. u.setRenderer(this.renderer);
  10039. }
  10040. u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad});
  10041. },
  10042. /**
  10043. * Retrieve a tool by id.
  10044. * @param {String} id
  10045. * @return {Object} tool
  10046. */
  10047. getTool : function(id) {
  10048. return this.tools[id];
  10049. }
  10050. /**
  10051. * @cfg {String} autoEl @hide
  10052. */
  10053. });
  10054. Ext.reg('panel', Ext.Panel);
  10055. /**
  10056. * @class Ext.Editor
  10057. * @extends Ext.Component
  10058. * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
  10059. * @constructor
  10060. * Create a new Editor
  10061. * @param {Object} config The config object
  10062. * @xtype editor
  10063. */
  10064. Ext.Editor = function(field, config){
  10065. if(field.field){
  10066. this.field = Ext.create(field.field, 'textfield');
  10067. config = Ext.apply({}, field); // copy so we don't disturb original config
  10068. delete config.field;
  10069. }else{
  10070. this.field = field;
  10071. }
  10072. Ext.Editor.superclass.constructor.call(this, config);
  10073. };
  10074. Ext.extend(Ext.Editor, Ext.Component, {
  10075. /**
  10076. * @cfg {Ext.form.Field} field
  10077. * The Field object (or descendant) or config object for field
  10078. */
  10079. /**
  10080. * @cfg {Boolean} allowBlur
  10081. * True to {@link #completeEdit complete the editing process} if in edit mode when the
  10082. * field is blurred. Defaults to <tt>true</tt>.
  10083. */
  10084. allowBlur: true,
  10085. /**
  10086. * @cfg {Boolean/String} autoSize
  10087. * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
  10088. * or "height" to adopt the height only, "none" to always use the field dimensions. (defaults to false)
  10089. */
  10090. /**
  10091. * @cfg {Boolean} revertInvalid
  10092. * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
  10093. * validation fails (defaults to true)
  10094. */
  10095. /**
  10096. * @cfg {Boolean} ignoreNoChange
  10097. * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
  10098. * the value has not changed (defaults to false). Applies only to string values - edits for other data types
  10099. * will never be ignored.
  10100. */
  10101. /**
  10102. * @cfg {Boolean} hideEl
  10103. * False to keep the bound element visible while the editor is displayed (defaults to true)
  10104. */
  10105. /**
  10106. * @cfg {Mixed} value
  10107. * The data value of the underlying field (defaults to "")
  10108. */
  10109. value : "",
  10110. /**
  10111. * @cfg {String} alignment
  10112. * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?").
  10113. */
  10114. alignment: "c-c?",
  10115. /**
  10116. * @cfg {Array} offsets
  10117. * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details. Defaults to <tt>[0, 0]</tt>.
  10118. */
  10119. offsets: [0, 0],
  10120. /**
  10121. * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
  10122. * for bottom-right shadow (defaults to "frame")
  10123. */
  10124. shadow : "frame",
  10125. /**
  10126. * @cfg {Boolean} constrain True to constrain the editor to the viewport
  10127. */
  10128. constrain : false,
  10129. /**
  10130. * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
  10131. */
  10132. swallowKeys : true,
  10133. /**
  10134. * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
  10135. */
  10136. completeOnEnter : true,
  10137. /**
  10138. * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
  10139. */
  10140. cancelOnEsc : true,
  10141. /**
  10142. * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
  10143. */
  10144. updateEl : false,
  10145. initComponent : function(){
  10146. Ext.Editor.superclass.initComponent.call(this);
  10147. this.addEvents(
  10148. /**
  10149. * @event beforestartedit
  10150. * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
  10151. * false from the handler of this event.
  10152. * @param {Editor} this
  10153. * @param {Ext.Element} boundEl The underlying element bound to this editor
  10154. * @param {Mixed} value The field value being set
  10155. */
  10156. "beforestartedit",
  10157. /**
  10158. * @event startedit
  10159. * Fires when this editor is displayed
  10160. * @param {Ext.Element} boundEl The underlying element bound to this editor
  10161. * @param {Mixed} value The starting field value
  10162. */
  10163. "startedit",
  10164. /**
  10165. * @event beforecomplete
  10166. * Fires after a change has been made to the field, but before the change is reflected in the underlying
  10167. * field. Saving the change to the field can be canceled by returning false from the handler of this event.
  10168. * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
  10169. * event will not fire since no edit actually occurred.
  10170. * @param {Editor} this
  10171. * @param {Mixed} value The current field value
  10172. * @param {Mixed} startValue The original field value
  10173. */
  10174. "beforecomplete",
  10175. /**
  10176. * @event complete
  10177. * Fires after editing is complete and any changed value has been written to the underlying field.
  10178. * @param {Editor} this
  10179. * @param {Mixed} value The current field value
  10180. * @param {Mixed} startValue The original field value
  10181. */
  10182. "complete",
  10183. /**
  10184. * @event canceledit
  10185. * Fires after editing has been canceled and the editor's value has been reset.
  10186. * @param {Editor} this
  10187. * @param {Mixed} value The user-entered field value that was discarded
  10188. * @param {Mixed} startValue The original field value that was set back into the editor after cancel
  10189. */
  10190. "canceledit",
  10191. /**
  10192. * @event specialkey
  10193. * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
  10194. * {@link Ext.EventObject#getKey} to determine which key was pressed.
  10195. * @param {Ext.form.Field} this
  10196. * @param {Ext.EventObject} e The event object
  10197. */
  10198. "specialkey"
  10199. );
  10200. },
  10201. // private
  10202. onRender : function(ct, position){
  10203. this.el = new Ext.Layer({
  10204. shadow: this.shadow,
  10205. cls: "x-editor",
  10206. parentEl : ct,
  10207. shim : this.shim,
  10208. shadowOffset: this.shadowOffset || 4,
  10209. id: this.id,
  10210. constrain: this.constrain
  10211. });
  10212. if(this.zIndex){
  10213. this.el.setZIndex(this.zIndex);
  10214. }
  10215. this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden");
  10216. if(this.field.msgTarget != 'title'){
  10217. this.field.msgTarget = 'qtip';
  10218. }
  10219. this.field.inEditor = true;
  10220. this.mon(this.field, {
  10221. scope: this,
  10222. blur: this.onBlur,
  10223. specialkey: this.onSpecialKey
  10224. });
  10225. if(this.field.grow){
  10226. this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1});
  10227. }
  10228. this.field.render(this.el).show();
  10229. this.field.getEl().dom.name = '';
  10230. if(this.swallowKeys){
  10231. this.field.el.swallowEvent([
  10232. 'keypress', // *** Opera
  10233. 'keydown' // *** all other browsers
  10234. ]);
  10235. }
  10236. },
  10237. // private
  10238. onSpecialKey : function(field, e){
  10239. var key = e.getKey(),
  10240. complete = this.completeOnEnter && key == e.ENTER,
  10241. cancel = this.cancelOnEsc && key == e.ESC;
  10242. if(complete || cancel){
  10243. e.stopEvent();
  10244. if(complete){
  10245. this.completeEdit();
  10246. }else{
  10247. this.cancelEdit();
  10248. }
  10249. if(field.triggerBlur){
  10250. field.triggerBlur();
  10251. }
  10252. }
  10253. this.fireEvent('specialkey', field, e);
  10254. },
  10255. /**
  10256. * Starts the editing process and shows the editor.
  10257. * @param {Mixed} el The element to edit
  10258. * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
  10259. * to the innerHTML of el.
  10260. */
  10261. startEdit : function(el, value){
  10262. if(this.editing){
  10263. this.completeEdit();
  10264. }
  10265. this.boundEl = Ext.get(el);
  10266. var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
  10267. if(!this.rendered){
  10268. this.render(this.parentEl || document.body);
  10269. }
  10270. if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){
  10271. this.startValue = v;
  10272. this.field.reset();
  10273. this.field.setValue(v);
  10274. this.realign(true);
  10275. this.editing = true;
  10276. this.show();
  10277. }
  10278. },
  10279. // private
  10280. doAutoSize : function(){
  10281. if(this.autoSize){
  10282. var sz = this.boundEl.getSize(),
  10283. fs = this.field.getSize();
  10284. switch(this.autoSize){
  10285. case "width":
  10286. this.setSize(sz.width, fs.height);
  10287. break;
  10288. case "height":
  10289. this.setSize(fs.width, sz.height);
  10290. break;
  10291. case "none":
  10292. this.setSize(fs.width, fs.height);
  10293. break;
  10294. default:
  10295. this.setSize(sz.width, sz.height);
  10296. }
  10297. }
  10298. },
  10299. /**
  10300. * Sets the height and width of this editor.
  10301. * @param {Number} width The new width
  10302. * @param {Number} height The new height
  10303. */
  10304. setSize : function(w, h){
  10305. delete this.field.lastSize;
  10306. this.field.setSize(w, h);
  10307. if(this.el){
  10308. if(Ext.isGecko2 || Ext.isOpera){
  10309. // prevent layer scrollbars
  10310. this.el.setSize(w, h);
  10311. }
  10312. this.el.sync();
  10313. }
  10314. },
  10315. /**
  10316. * Realigns the editor to the bound field based on the current alignment config value.
  10317. * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
  10318. */
  10319. realign : function(autoSize){
  10320. if(autoSize === true){
  10321. this.doAutoSize();
  10322. }
  10323. this.el.alignTo(this.boundEl, this.alignment, this.offsets);
  10324. },
  10325. /**
  10326. * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
  10327. * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
  10328. */
  10329. completeEdit : function(remainVisible){
  10330. if(!this.editing){
  10331. return;
  10332. }
  10333. // Assert combo values first
  10334. if (this.field.assertValue) {
  10335. this.field.assertValue();
  10336. }
  10337. var v = this.getValue();
  10338. if(!this.field.isValid()){
  10339. if(this.revertInvalid !== false){
  10340. this.cancelEdit(remainVisible);
  10341. }
  10342. return;
  10343. }
  10344. if(String(v) === String(this.startValue) && this.ignoreNoChange){
  10345. this.hideEdit(remainVisible);
  10346. return;
  10347. }
  10348. if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
  10349. v = this.getValue();
  10350. if(this.updateEl && this.boundEl){
  10351. this.boundEl.update(v);
  10352. }
  10353. this.hideEdit(remainVisible);
  10354. this.fireEvent("complete", this, v, this.startValue);
  10355. }
  10356. },
  10357. // private
  10358. onShow : function(){
  10359. this.el.show();
  10360. if(this.hideEl !== false){
  10361. this.boundEl.hide();
  10362. }
  10363. this.field.show().focus(false, true);
  10364. this.fireEvent("startedit", this.boundEl, this.startValue);
  10365. },
  10366. /**
  10367. * Cancels the editing process and hides the editor without persisting any changes. The field value will be
  10368. * reverted to the original starting value.
  10369. * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
  10370. * cancel (defaults to false)
  10371. */
  10372. cancelEdit : function(remainVisible){
  10373. if(this.editing){
  10374. var v = this.getValue();
  10375. this.setValue(this.startValue);
  10376. this.hideEdit(remainVisible);
  10377. this.fireEvent("canceledit", this, v, this.startValue);
  10378. }
  10379. },
  10380. // private
  10381. hideEdit: function(remainVisible){
  10382. if(remainVisible !== true){
  10383. this.editing = false;
  10384. this.hide();
  10385. }
  10386. },
  10387. // private
  10388. onBlur : function(){
  10389. // selectSameEditor flag allows the same editor to be started without onBlur firing on itself
  10390. if(this.allowBlur === true && this.editing && this.selectSameEditor !== true){
  10391. this.completeEdit();
  10392. }
  10393. },
  10394. // private
  10395. onHide : function(){
  10396. if(this.editing){
  10397. this.completeEdit();
  10398. return;
  10399. }
  10400. this.field.blur();
  10401. if(this.field.collapse){
  10402. this.field.collapse();
  10403. }
  10404. this.el.hide();
  10405. if(this.hideEl !== false){
  10406. this.boundEl.show();
  10407. }
  10408. },
  10409. /**
  10410. * Sets the data value of the editor
  10411. * @param {Mixed} value Any valid value supported by the underlying field
  10412. */
  10413. setValue : function(v){
  10414. this.field.setValue(v);
  10415. },
  10416. /**
  10417. * Gets the data value of the editor
  10418. * @return {Mixed} The data value
  10419. */
  10420. getValue : function(){
  10421. return this.field.getValue();
  10422. },
  10423. beforeDestroy : function(){
  10424. Ext.destroyMembers(this, 'field');
  10425. delete this.parentEl;
  10426. delete this.boundEl;
  10427. }
  10428. });
  10429. Ext.reg('editor', Ext.Editor);
  10430. /**
  10431. * @class Ext.ColorPalette
  10432. * @extends Ext.Component
  10433. * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
  10434. * Here's an example of typical usage:
  10435. * <pre><code>
  10436. var cp = new Ext.ColorPalette({value:'993300'}); // initial selected color
  10437. cp.render('my-div');
  10438. cp.on('select', function(palette, selColor){
  10439. // do something with selColor
  10440. });
  10441. </code></pre>
  10442. * @constructor
  10443. * Create a new ColorPalette
  10444. * @param {Object} config The config object
  10445. * @xtype colorpalette
  10446. */
  10447. Ext.ColorPalette = Ext.extend(Ext.Component, {
  10448. /**
  10449. * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component.
  10450. */
  10451. /**
  10452. * @cfg {String} itemCls
  10453. * The CSS class to apply to the containing element (defaults to 'x-color-palette')
  10454. */
  10455. itemCls : 'x-color-palette',
  10456. /**
  10457. * @cfg {String} value
  10458. * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
  10459. * the hex codes are case-sensitive.
  10460. */
  10461. value : null,
  10462. /**
  10463. * @cfg {String} clickEvent
  10464. * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu).
  10465. * Defaults to <tt>'click'</tt>.
  10466. */
  10467. clickEvent :'click',
  10468. // private
  10469. ctype : 'Ext.ColorPalette',
  10470. /**
  10471. * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event
  10472. */
  10473. allowReselect : false,
  10474. /**
  10475. * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
  10476. * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
  10477. * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
  10478. * of colors with the width setting until the box is symmetrical.</p>
  10479. * <p>You can override individual colors if needed:</p>
  10480. * <pre><code>
  10481. var cp = new Ext.ColorPalette();
  10482. cp.colors[0] = 'FF0000'; // change the first box to red
  10483. </code></pre>
  10484. Or you can provide a custom array of your own for complete control:
  10485. <pre><code>
  10486. var cp = new Ext.ColorPalette();
  10487. cp.colors = ['000000', '993300', '333300'];
  10488. </code></pre>
  10489. * @type Array
  10490. */
  10491. colors : [
  10492. '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
  10493. '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
  10494. 'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
  10495. 'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
  10496. 'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
  10497. ],
  10498. /**
  10499. * @cfg {Function} handler
  10500. * Optional. A function that will handle the select event of this palette.
  10501. * The handler is passed the following parameters:<div class="mdetail-params"><ul>
  10502. * <li><code>palette</code> : ColorPalette<div class="sub-desc">The {@link #palette Ext.ColorPalette}.</div></li>
  10503. * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
  10504. * </ul></div>
  10505. */
  10506. /**
  10507. * @cfg {Object} scope
  10508. * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
  10509. * function will be called. Defaults to this ColorPalette instance.
  10510. */
  10511. // private
  10512. initComponent : function(){
  10513. Ext.ColorPalette.superclass.initComponent.call(this);
  10514. this.addEvents(
  10515. /**
  10516. * @event select
  10517. * Fires when a color is selected
  10518. * @param {ColorPalette} this
  10519. * @param {String} color The 6-digit color hex code (without the # symbol)
  10520. */
  10521. 'select'
  10522. );
  10523. if(this.handler){
  10524. this.on('select', this.handler, this.scope, true);
  10525. }
  10526. },
  10527. // private
  10528. onRender : function(container, position){
  10529. this.autoEl = {
  10530. tag: 'div',
  10531. cls: this.itemCls
  10532. };
  10533. Ext.ColorPalette.superclass.onRender.call(this, container, position);
  10534. var t = this.tpl || new Ext.XTemplate(
  10535. '<tpl for="."><a href="#" class="color-{.}" hidefocus="on"><em><span style="background:#{.}" unselectable="on">&#160;</span></em></a></tpl>'
  10536. );
  10537. t.overwrite(this.el, this.colors);
  10538. this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'});
  10539. if(this.clickEvent != 'click'){
  10540. this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true});
  10541. }
  10542. },
  10543. // private
  10544. afterRender : function(){
  10545. Ext.ColorPalette.superclass.afterRender.call(this);
  10546. if(this.value){
  10547. var s = this.value;
  10548. this.value = null;
  10549. this.select(s);
  10550. }
  10551. },
  10552. // private
  10553. handleClick : function(e, t){
  10554. e.preventDefault();
  10555. if(!this.disabled){
  10556. var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
  10557. this.select(c.toUpperCase());
  10558. }
  10559. },
  10560. /**
  10561. * Selects the specified color in the palette (fires the {@link #select} event)
  10562. * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
  10563. */
  10564. select : function(color){
  10565. color = color.replace('#', '');
  10566. if(color != this.value || this.allowReselect){
  10567. var el = this.el;
  10568. if(this.value){
  10569. el.child('a.color-'+this.value).removeClass('x-color-palette-sel');
  10570. }
  10571. el.child('a.color-'+color).addClass('x-color-palette-sel');
  10572. this.value = color;
  10573. this.fireEvent('select', this, color);
  10574. }
  10575. }
  10576. /**
  10577. * @cfg {String} autoEl @hide
  10578. */
  10579. });
  10580. Ext.reg('colorpalette', Ext.ColorPalette);
  10581. /**
  10582. * @class Ext.DatePicker
  10583. * @extends Ext.Component
  10584. * <p>A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class
  10585. * to allow browsing and selection of valid dates.</p>
  10586. * <p>All the string values documented below may be overridden by including an Ext locale file in
  10587. * your page.</p>
  10588. * @constructor
  10589. * Create a new DatePicker
  10590. * @param {Object} config The config object
  10591. * @xtype datepicker
  10592. */
  10593. Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
  10594. /**
  10595. * @cfg {String} todayText
  10596. * The text to display on the button that selects the current date (defaults to <code>'Today'</code>)
  10597. */
  10598. todayText : 'Today',
  10599. /**
  10600. * @cfg {String} okText
  10601. * The text to display on the ok button (defaults to <code>'&#160;OK&#160;'</code> to give the user extra clicking room)
  10602. */
  10603. okText : '&#160;OK&#160;',
  10604. /**
  10605. * @cfg {String} cancelText
  10606. * The text to display on the cancel button (defaults to <code>'Cancel'</code>)
  10607. */
  10608. cancelText : 'Cancel',
  10609. /**
  10610. * @cfg {Function} handler
  10611. * Optional. A function that will handle the select event of this picker.
  10612. * The handler is passed the following parameters:<div class="mdetail-params"><ul>
  10613. * <li><code>picker</code> : DatePicker<div class="sub-desc">This DatePicker.</div></li>
  10614. * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
  10615. * </ul></div>
  10616. */
  10617. /**
  10618. * @cfg {Object} scope
  10619. * The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
  10620. * function will be called. Defaults to this DatePicker instance.
  10621. */
  10622. /**
  10623. * @cfg {String} todayTip
  10624. * A string used to format the message for displaying in a tooltip over the button that
  10625. * selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
  10626. * the <code>{0}</code> token is replaced by today's date.
  10627. */
  10628. todayTip : '{0} (Spacebar)',
  10629. /**
  10630. * @cfg {String} minText
  10631. * The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
  10632. */
  10633. minText : 'This date is before the minimum date',
  10634. /**
  10635. * @cfg {String} maxText
  10636. * The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
  10637. */
  10638. maxText : 'This date is after the maximum date',
  10639. /**
  10640. * @cfg {String} format
  10641. * The default date format string which can be overriden for localization support. The format must be
  10642. * valid according to {@link Date#parseDate} (defaults to <code>'m/d/y'</code>).
  10643. */
  10644. format : 'm/d/y',
  10645. /**
  10646. * @cfg {String} disabledDaysText
  10647. * The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
  10648. */
  10649. disabledDaysText : 'Disabled',
  10650. /**
  10651. * @cfg {String} disabledDatesText
  10652. * The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
  10653. */
  10654. disabledDatesText : 'Disabled',
  10655. /**
  10656. * @cfg {Array} monthNames
  10657. * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
  10658. */
  10659. monthNames : Date.monthNames,
  10660. /**
  10661. * @cfg {Array} dayNames
  10662. * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
  10663. */
  10664. dayNames : Date.dayNames,
  10665. /**
  10666. * @cfg {String} nextText
  10667. * The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
  10668. */
  10669. nextText : 'Next Month (Control+Right)',
  10670. /**
  10671. * @cfg {String} prevText
  10672. * The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
  10673. */
  10674. prevText : 'Previous Month (Control+Left)',
  10675. /**
  10676. * @cfg {String} monthYearText
  10677. * The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
  10678. */
  10679. monthYearText : 'Choose a month (Control+Up/Down to move years)',
  10680. /**
  10681. * @cfg {Number} startDay
  10682. * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
  10683. */
  10684. startDay : 0,
  10685. /**
  10686. * @cfg {Boolean} showToday
  10687. * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
  10688. * that selects the current date (defaults to <code>true</code>).
  10689. */
  10690. showToday : true,
  10691. /**
  10692. * @cfg {Date} minDate
  10693. * Minimum allowable date (JavaScript date object, defaults to null)
  10694. */
  10695. /**
  10696. * @cfg {Date} maxDate
  10697. * Maximum allowable date (JavaScript date object, defaults to null)
  10698. */
  10699. /**
  10700. * @cfg {Array} disabledDays
  10701. * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
  10702. */
  10703. /**
  10704. * @cfg {RegExp} disabledDatesRE
  10705. * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
  10706. * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
  10707. * disabledDates value.
  10708. */
  10709. /**
  10710. * @cfg {Array} disabledDates
  10711. * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
  10712. * expression so they are very powerful. Some examples:
  10713. * <ul>
  10714. * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
  10715. * <li>['03/08', '09/16'] would disable those days for every year</li>
  10716. * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
  10717. * <li>['03/../2006'] would disable every day in March 2006</li>
  10718. * <li>['^03'] would disable every day in every March</li>
  10719. * </ul>
  10720. * Note that the format of the dates included in the array should exactly match the {@link #format} config.
  10721. * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
  10722. * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
  10723. */
  10724. // private
  10725. // Set by other components to stop the picker focus being updated when the value changes.
  10726. focusOnSelect: true,
  10727. // default value used to initialise each date in the DatePicker
  10728. // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
  10729. initHour: 12, // 24-hour format
  10730. // private
  10731. initComponent : function(){
  10732. Ext.DatePicker.superclass.initComponent.call(this);
  10733. this.value = this.value ?
  10734. this.value.clearTime(true) : new Date().clearTime();
  10735. this.addEvents(
  10736. /**
  10737. * @event select
  10738. * Fires when a date is selected
  10739. * @param {DatePicker} this DatePicker
  10740. * @param {Date} date The selected date
  10741. */
  10742. 'select'
  10743. );
  10744. if(this.handler){
  10745. this.on('select', this.handler, this.scope || this);
  10746. }
  10747. this.initDisabledDays();
  10748. },
  10749. // private
  10750. initDisabledDays : function(){
  10751. if(!this.disabledDatesRE && this.disabledDates){
  10752. var dd = this.disabledDates,
  10753. len = dd.length - 1,
  10754. re = '(?:';
  10755. Ext.each(dd, function(d, i){
  10756. re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
  10757. if(i != len){
  10758. re += '|';
  10759. }
  10760. }, this);
  10761. this.disabledDatesRE = new RegExp(re + ')');
  10762. }
  10763. },
  10764. /**
  10765. * Replaces any existing disabled dates with new values and refreshes the DatePicker.
  10766. * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
  10767. * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
  10768. */
  10769. setDisabledDates : function(dd){
  10770. if(Ext.isArray(dd)){
  10771. this.disabledDates = dd;
  10772. this.disabledDatesRE = null;
  10773. }else{
  10774. this.disabledDatesRE = dd;
  10775. }
  10776. this.initDisabledDays();
  10777. this.update(this.value, true);
  10778. },
  10779. /**
  10780. * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
  10781. * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
  10782. * for details on supported values.
  10783. */
  10784. setDisabledDays : function(dd){
  10785. this.disabledDays = dd;
  10786. this.update(this.value, true);
  10787. },
  10788. /**
  10789. * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
  10790. * @param {Date} value The minimum date that can be selected
  10791. */
  10792. setMinDate : function(dt){
  10793. this.minDate = dt;
  10794. this.update(this.value, true);
  10795. },
  10796. /**
  10797. * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
  10798. * @param {Date} value The maximum date that can be selected
  10799. */
  10800. setMaxDate : function(dt){
  10801. this.maxDate = dt;
  10802. this.update(this.value, true);
  10803. },
  10804. /**
  10805. * Sets the value of the date field
  10806. * @param {Date} value The date to set
  10807. */
  10808. setValue : function(value){
  10809. this.value = value.clearTime(true);
  10810. this.update(this.value);
  10811. },
  10812. /**
  10813. * Gets the current selected value of the date field
  10814. * @return {Date} The selected date
  10815. */
  10816. getValue : function(){
  10817. return this.value;
  10818. },
  10819. // private
  10820. focus : function(){
  10821. this.update(this.activeDate);
  10822. },
  10823. // private
  10824. onEnable: function(initial){
  10825. Ext.DatePicker.superclass.onEnable.call(this);
  10826. this.doDisabled(false);
  10827. this.update(initial ? this.value : this.activeDate);
  10828. if(Ext.isIE){
  10829. this.el.repaint();
  10830. }
  10831. },
  10832. // private
  10833. onDisable : function(){
  10834. Ext.DatePicker.superclass.onDisable.call(this);
  10835. this.doDisabled(true);
  10836. if(Ext.isIE && !Ext.isIE8){
  10837. /* Really strange problem in IE6/7, when disabled, have to explicitly
  10838. * repaint each of the nodes to get them to display correctly, simply
  10839. * calling repaint on the main element doesn't appear to be enough.
  10840. */
  10841. Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
  10842. Ext.fly(el).repaint();
  10843. });
  10844. }
  10845. },
  10846. // private
  10847. doDisabled : function(disabled){
  10848. this.keyNav.setDisabled(disabled);
  10849. this.prevRepeater.setDisabled(disabled);
  10850. this.nextRepeater.setDisabled(disabled);
  10851. if(this.showToday){
  10852. this.todayKeyListener.setDisabled(disabled);
  10853. this.todayBtn.setDisabled(disabled);
  10854. }
  10855. },
  10856. // private
  10857. onRender : function(container, position){
  10858. var m = [
  10859. '<table cellspacing="0">',
  10860. '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'">&#160;</a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'">&#160;</a></td></tr>',
  10861. '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
  10862. dn = this.dayNames,
  10863. i;
  10864. for(i = 0; i < 7; i++){
  10865. var d = this.startDay+i;
  10866. if(d > 6){
  10867. d = d-7;
  10868. }
  10869. m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
  10870. }
  10871. m[m.length] = '</tr></thead><tbody><tr>';
  10872. for(i = 0; i < 42; i++) {
  10873. if(i % 7 === 0 && i !== 0){
  10874. m[m.length] = '</tr><tr>';
  10875. }
  10876. m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
  10877. }
  10878. m.push('</tr></tbody></table></td></tr>',
  10879. this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
  10880. '</table><div class="x-date-mp"></div>');
  10881. var el = document.createElement('div');
  10882. el.className = 'x-date-picker';
  10883. el.innerHTML = m.join('');
  10884. container.dom.insertBefore(el, position);
  10885. this.el = Ext.get(el);
  10886. this.eventEl = Ext.get(el.firstChild);
  10887. this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
  10888. handler: this.showPrevMonth,
  10889. scope: this,
  10890. preventDefault:true,
  10891. stopDefault:true
  10892. });
  10893. this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
  10894. handler: this.showNextMonth,
  10895. scope: this,
  10896. preventDefault:true,
  10897. stopDefault:true
  10898. });
  10899. this.monthPicker = this.el.down('div.x-date-mp');
  10900. this.monthPicker.enableDisplayMode('block');
  10901. this.keyNav = new Ext.KeyNav(this.eventEl, {
  10902. 'left' : function(e){
  10903. if(e.ctrlKey){
  10904. this.showPrevMonth();
  10905. }else{
  10906. this.update(this.activeDate.add('d', -1));
  10907. }
  10908. },
  10909. 'right' : function(e){
  10910. if(e.ctrlKey){
  10911. this.showNextMonth();
  10912. }else{
  10913. this.update(this.activeDate.add('d', 1));
  10914. }
  10915. },
  10916. 'up' : function(e){
  10917. if(e.ctrlKey){
  10918. this.showNextYear();
  10919. }else{
  10920. this.update(this.activeDate.add('d', -7));
  10921. }
  10922. },
  10923. 'down' : function(e){
  10924. if(e.ctrlKey){
  10925. this.showPrevYear();
  10926. }else{
  10927. this.update(this.activeDate.add('d', 7));
  10928. }
  10929. },
  10930. 'pageUp' : function(e){
  10931. this.showNextMonth();
  10932. },
  10933. 'pageDown' : function(e){
  10934. this.showPrevMonth();
  10935. },
  10936. 'enter' : function(e){
  10937. e.stopPropagation();
  10938. return true;
  10939. },
  10940. scope : this
  10941. });
  10942. this.el.unselectable();
  10943. this.cells = this.el.select('table.x-date-inner tbody td');
  10944. this.textNodes = this.el.query('table.x-date-inner tbody span');
  10945. this.mbtn = new Ext.Button({
  10946. text: '&#160;',
  10947. tooltip: this.monthYearText,
  10948. renderTo: this.el.child('td.x-date-middle', true)
  10949. });
  10950. this.mbtn.el.child('em').addClass('x-btn-arrow');
  10951. if(this.showToday){
  10952. this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
  10953. var today = (new Date()).dateFormat(this.format);
  10954. this.todayBtn = new Ext.Button({
  10955. renderTo: this.el.child('td.x-date-bottom', true),
  10956. text: String.format(this.todayText, today),
  10957. tooltip: String.format(this.todayTip, today),
  10958. handler: this.selectToday,
  10959. scope: this
  10960. });
  10961. }
  10962. this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
  10963. this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
  10964. this.mon(this.mbtn, 'click', this.showMonthPicker, this);
  10965. this.onEnable(true);
  10966. },
  10967. // private
  10968. createMonthPicker : function(){
  10969. if(!this.monthPicker.dom.firstChild){
  10970. var buf = ['<table border="0" cellspacing="0">'];
  10971. for(var i = 0; i < 6; i++){
  10972. buf.push(
  10973. '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
  10974. '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
  10975. i === 0 ?
  10976. '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
  10977. '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
  10978. );
  10979. }
  10980. buf.push(
  10981. '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
  10982. this.okText,
  10983. '</button><button type="button" class="x-date-mp-cancel">',
  10984. this.cancelText,
  10985. '</button></td></tr>',
  10986. '</table>'
  10987. );
  10988. this.monthPicker.update(buf.join(''));
  10989. this.mon(this.monthPicker, 'click', this.onMonthClick, this);
  10990. this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
  10991. this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
  10992. this.mpYears = this.monthPicker.select('td.x-date-mp-year');
  10993. this.mpMonths.each(function(m, a, i){
  10994. i += 1;
  10995. if((i%2) === 0){
  10996. m.dom.xmonth = 5 + Math.round(i * 0.5);
  10997. }else{
  10998. m.dom.xmonth = Math.round((i-1) * 0.5);
  10999. }
  11000. });
  11001. }
  11002. },
  11003. // private
  11004. showMonthPicker : function(){
  11005. if(!this.disabled){
  11006. this.createMonthPicker();
  11007. var size = this.el.getSize();
  11008. this.monthPicker.setSize(size);
  11009. this.monthPicker.child('table').setSize(size);
  11010. this.mpSelMonth = (this.activeDate || this.value).getMonth();
  11011. this.updateMPMonth(this.mpSelMonth);
  11012. this.mpSelYear = (this.activeDate || this.value).getFullYear();
  11013. this.updateMPYear(this.mpSelYear);
  11014. this.monthPicker.slideIn('t', {duration:0.2});
  11015. }
  11016. },
  11017. // private
  11018. updateMPYear : function(y){
  11019. this.mpyear = y;
  11020. var ys = this.mpYears.elements;
  11021. for(var i = 1; i <= 10; i++){
  11022. var td = ys[i-1], y2;
  11023. if((i%2) === 0){
  11024. y2 = y + Math.round(i * 0.5);
  11025. td.firstChild.innerHTML = y2;
  11026. td.xyear = y2;
  11027. }else{
  11028. y2 = y - (5-Math.round(i * 0.5));
  11029. td.firstChild.innerHTML = y2;
  11030. td.xyear = y2;
  11031. }
  11032. this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
  11033. }
  11034. },
  11035. // private
  11036. updateMPMonth : function(sm){
  11037. this.mpMonths.each(function(m, a, i){
  11038. m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
  11039. });
  11040. },
  11041. // private
  11042. selectMPMonth : function(m){
  11043. },
  11044. // private
  11045. onMonthClick : function(e, t){
  11046. e.stopEvent();
  11047. var el = new Ext.Element(t), pn;
  11048. if(el.is('button.x-date-mp-cancel')){
  11049. this.hideMonthPicker();
  11050. }
  11051. else if(el.is('button.x-date-mp-ok')){
  11052. var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
  11053. if(d.getMonth() != this.mpSelMonth){
  11054. // 'fix' the JS rolling date conversion if needed
  11055. d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
  11056. }
  11057. this.update(d);
  11058. this.hideMonthPicker();
  11059. }
  11060. else if((pn = el.up('td.x-date-mp-month', 2))){
  11061. this.mpMonths.removeClass('x-date-mp-sel');
  11062. pn.addClass('x-date-mp-sel');
  11063. this.mpSelMonth = pn.dom.xmonth;
  11064. }
  11065. else if((pn = el.up('td.x-date-mp-year', 2))){
  11066. this.mpYears.removeClass('x-date-mp-sel');
  11067. pn.addClass('x-date-mp-sel');
  11068. this.mpSelYear = pn.dom.xyear;
  11069. }
  11070. else if(el.is('a.x-date-mp-prev')){
  11071. this.updateMPYear(this.mpyear-10);
  11072. }
  11073. else if(el.is('a.x-date-mp-next')){
  11074. this.updateMPYear(this.mpyear+10);
  11075. }
  11076. },
  11077. // private
  11078. onMonthDblClick : function(e, t){
  11079. e.stopEvent();
  11080. var el = new Ext.Element(t), pn;
  11081. if((pn = el.up('td.x-date-mp-month', 2))){
  11082. this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
  11083. this.hideMonthPicker();
  11084. }
  11085. else if((pn = el.up('td.x-date-mp-year', 2))){
  11086. this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
  11087. this.hideMonthPicker();
  11088. }
  11089. },
  11090. // private
  11091. hideMonthPicker : function(disableAnim){
  11092. if(this.monthPicker){
  11093. if(disableAnim === true){
  11094. this.monthPicker.hide();
  11095. }else{
  11096. this.monthPicker.slideOut('t', {duration:0.2});
  11097. }
  11098. }
  11099. },
  11100. // private
  11101. showPrevMonth : function(e){
  11102. this.update(this.activeDate.add('mo', -1));
  11103. },
  11104. // private
  11105. showNextMonth : function(e){
  11106. this.update(this.activeDate.add('mo', 1));
  11107. },
  11108. // private
  11109. showPrevYear : function(){
  11110. this.update(this.activeDate.add('y', -1));
  11111. },
  11112. // private
  11113. showNextYear : function(){
  11114. this.update(this.activeDate.add('y', 1));
  11115. },
  11116. // private
  11117. handleMouseWheel : function(e){
  11118. e.stopEvent();
  11119. if(!this.disabled){
  11120. var delta = e.getWheelDelta();
  11121. if(delta > 0){
  11122. this.showPrevMonth();
  11123. } else if(delta < 0){
  11124. this.showNextMonth();
  11125. }
  11126. }
  11127. },
  11128. // private
  11129. handleDateClick : function(e, t){
  11130. e.stopEvent();
  11131. if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
  11132. this.cancelFocus = this.focusOnSelect === false;
  11133. this.setValue(new Date(t.dateValue));
  11134. delete this.cancelFocus;
  11135. this.fireEvent('select', this, this.value);
  11136. }
  11137. },
  11138. // private
  11139. selectToday : function(){
  11140. if(this.todayBtn && !this.todayBtn.disabled){
  11141. this.setValue(new Date().clearTime());
  11142. this.fireEvent('select', this, this.value);
  11143. }
  11144. },
  11145. // private
  11146. update : function(date, forceRefresh){
  11147. if(this.rendered){
  11148. var vd = this.activeDate, vis = this.isVisible();
  11149. this.activeDate = date;
  11150. if(!forceRefresh && vd && this.el){
  11151. var t = date.getTime();
  11152. if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
  11153. this.cells.removeClass('x-date-selected');
  11154. this.cells.each(function(c){
  11155. if(c.dom.firstChild.dateValue == t){
  11156. c.addClass('x-date-selected');
  11157. if(vis && !this.cancelFocus){
  11158. Ext.fly(c.dom.firstChild).focus(50);
  11159. }
  11160. return false;
  11161. }
  11162. }, this);
  11163. return;
  11164. }
  11165. }
  11166. var days = date.getDaysInMonth(),
  11167. firstOfMonth = date.getFirstDateOfMonth(),
  11168. startingPos = firstOfMonth.getDay()-this.startDay;
  11169. if(startingPos < 0){
  11170. startingPos += 7;
  11171. }
  11172. days += startingPos;
  11173. var pm = date.add('mo', -1),
  11174. prevStart = pm.getDaysInMonth()-startingPos,
  11175. cells = this.cells.elements,
  11176. textEls = this.textNodes,
  11177. // convert everything to numbers so it's fast
  11178. d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart, this.initHour)),
  11179. today = new Date().clearTime().getTime(),
  11180. sel = date.clearTime(true).getTime(),
  11181. min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
  11182. max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
  11183. ddMatch = this.disabledDatesRE,
  11184. ddText = this.disabledDatesText,
  11185. ddays = this.disabledDays ? this.disabledDays.join('') : false,
  11186. ddaysText = this.disabledDaysText,
  11187. format = this.format;
  11188. if(this.showToday){
  11189. var td = new Date().clearTime(),
  11190. disable = (td < min || td > max ||
  11191. (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
  11192. (ddays && ddays.indexOf(td.getDay()) != -1));
  11193. if(!this.disabled){
  11194. this.todayBtn.setDisabled(disable);
  11195. this.todayKeyListener[disable ? 'disable' : 'enable']();
  11196. }
  11197. }
  11198. var setCellClass = function(cal, cell){
  11199. cell.title = '';
  11200. var t = d.clearTime(true).getTime();
  11201. cell.firstChild.dateValue = t;
  11202. if(t == today){
  11203. cell.className += ' x-date-today';
  11204. cell.title = cal.todayText;
  11205. }
  11206. if(t == sel){
  11207. cell.className += ' x-date-selected';
  11208. if(vis){
  11209. Ext.fly(cell.firstChild).focus(50);
  11210. }
  11211. }
  11212. // disabling
  11213. if(t < min) {
  11214. cell.className = ' x-date-disabled';
  11215. cell.title = cal.minText;
  11216. return;
  11217. }
  11218. if(t > max) {
  11219. cell.className = ' x-date-disabled';
  11220. cell.title = cal.maxText;
  11221. return;
  11222. }
  11223. if(ddays){
  11224. if(ddays.indexOf(d.getDay()) != -1){
  11225. cell.title = ddaysText;
  11226. cell.className = ' x-date-disabled';
  11227. }
  11228. }
  11229. if(ddMatch && format){
  11230. var fvalue = d.dateFormat(format);
  11231. if(ddMatch.test(fvalue)){
  11232. cell.title = ddText.replace('%0', fvalue);
  11233. cell.className = ' x-date-disabled';
  11234. }
  11235. }
  11236. };
  11237. var i = 0;
  11238. for(; i < startingPos; i++) {
  11239. textEls[i].innerHTML = (++prevStart);
  11240. d.setDate(d.getDate()+1);
  11241. cells[i].className = 'x-date-prevday';
  11242. setCellClass(this, cells[i]);
  11243. }
  11244. for(; i < days; i++){
  11245. var intDay = i - startingPos + 1;
  11246. textEls[i].innerHTML = (intDay);
  11247. d.setDate(d.getDate()+1);
  11248. cells[i].className = 'x-date-active';
  11249. setCellClass(this, cells[i]);
  11250. }
  11251. var extraDays = 0;
  11252. for(; i < 42; i++) {
  11253. textEls[i].innerHTML = (++extraDays);
  11254. d.setDate(d.getDate()+1);
  11255. cells[i].className = 'x-date-nextday';
  11256. setCellClass(this, cells[i]);
  11257. }
  11258. this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
  11259. if(!this.internalRender){
  11260. var main = this.el.dom.firstChild,
  11261. w = main.offsetWidth;
  11262. this.el.setWidth(w + this.el.getBorderWidth('lr'));
  11263. Ext.fly(main).setWidth(w);
  11264. this.internalRender = true;
  11265. // opera does not respect the auto grow header center column
  11266. // then, after it gets a width opera refuses to recalculate
  11267. // without a second pass
  11268. if(Ext.isOpera && !this.secondPass){
  11269. main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
  11270. this.secondPass = true;
  11271. this.update.defer(10, this, [date]);
  11272. }
  11273. }
  11274. }
  11275. },
  11276. // private
  11277. beforeDestroy : function() {
  11278. if(this.rendered){
  11279. Ext.destroy(
  11280. this.keyNav,
  11281. this.monthPicker,
  11282. this.eventEl,
  11283. this.mbtn,
  11284. this.nextRepeater,
  11285. this.prevRepeater,
  11286. this.cells.el,
  11287. this.todayBtn
  11288. );
  11289. delete this.textNodes;
  11290. delete this.cells.elements;
  11291. }
  11292. }
  11293. /**
  11294. * @cfg {String} autoEl @hide
  11295. */
  11296. });
  11297. Ext.reg('datepicker', Ext.DatePicker);
  11298. /**
  11299. * @class Ext.LoadMask
  11300. * A simple utility class for generically masking elements while loading data. If the {@link #store}
  11301. * config option is specified, the masking will be automatically synchronized with the store's loading
  11302. * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
  11303. * element's Updater load indicator and will be destroyed after the initial load.
  11304. * <p>Example usage:</p>
  11305. *<pre><code>
  11306. // Basic mask:
  11307. var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
  11308. myMask.show();
  11309. </code></pre>
  11310. * @constructor
  11311. * Create a new LoadMask
  11312. * @param {Mixed} el The element or DOM node, or its id
  11313. * @param {Object} config The config object
  11314. */
  11315. Ext.LoadMask = function(el, config){
  11316. this.el = Ext.get(el);
  11317. Ext.apply(this, config);
  11318. if(this.store){
  11319. this.store.on({
  11320. scope: this,
  11321. beforeload: this.onBeforeLoad,
  11322. load: this.onLoad,
  11323. exception: this.onLoad
  11324. });
  11325. this.removeMask = Ext.value(this.removeMask, false);
  11326. }else{
  11327. var um = this.el.getUpdater();
  11328. um.showLoadIndicator = false; // disable the default indicator
  11329. um.on({
  11330. scope: this,
  11331. beforeupdate: this.onBeforeLoad,
  11332. update: this.onLoad,
  11333. failure: this.onLoad
  11334. });
  11335. this.removeMask = Ext.value(this.removeMask, true);
  11336. }
  11337. };
  11338. Ext.LoadMask.prototype = {
  11339. /**
  11340. * @cfg {Ext.data.Store} store
  11341. * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
  11342. * hidden on either load sucess, or load fail.
  11343. */
  11344. /**
  11345. * @cfg {Boolean} removeMask
  11346. * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
  11347. * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
  11348. */
  11349. /**
  11350. * @cfg {String} msg
  11351. * The text to display in a centered loading message box (defaults to 'Loading...')
  11352. */
  11353. msg : 'Loading...',
  11354. /**
  11355. * @cfg {String} msgCls
  11356. * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
  11357. */
  11358. msgCls : 'x-mask-loading',
  11359. /**
  11360. * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
  11361. * @type Boolean
  11362. */
  11363. disabled: false,
  11364. /**
  11365. * Disables the mask to prevent it from being displayed
  11366. */
  11367. disable : function(){
  11368. this.disabled = true;
  11369. },
  11370. /**
  11371. * Enables the mask so that it can be displayed
  11372. */
  11373. enable : function(){
  11374. this.disabled = false;
  11375. },
  11376. // private
  11377. onLoad : function(){
  11378. this.el.unmask(this.removeMask);
  11379. },
  11380. // private
  11381. onBeforeLoad : function(){
  11382. if(!this.disabled){
  11383. this.el.mask(this.msg, this.msgCls);
  11384. }
  11385. },
  11386. /**
  11387. * Show this LoadMask over the configured Element.
  11388. */
  11389. show: function(){
  11390. this.onBeforeLoad();
  11391. },
  11392. /**
  11393. * Hide this LoadMask.
  11394. */
  11395. hide: function(){
  11396. this.onLoad();
  11397. },
  11398. // private
  11399. destroy : function(){
  11400. if(this.store){
  11401. this.store.un('beforeload', this.onBeforeLoad, this);
  11402. this.store.un('load', this.onLoad, this);
  11403. this.store.un('exception', this.onLoad, this);
  11404. }else{
  11405. var um = this.el.getUpdater();
  11406. um.un('beforeupdate', this.onBeforeLoad, this);
  11407. um.un('update', this.onLoad, this);
  11408. um.un('failure', this.onLoad, this);
  11409. }
  11410. }
  11411. };Ext.ns('Ext.slider');
  11412. /**
  11413. * @class Ext.slider.Thumb
  11414. * @extends Object
  11415. * Represents a single thumb element on a Slider. This would not usually be created manually and would instead
  11416. * be created internally by an {@link Ext.slider.MultiSlider Ext.Slider}.
  11417. */
  11418. Ext.slider.Thumb = Ext.extend(Object, {
  11419. /**
  11420. * @constructor
  11421. * @cfg {Ext.slider.MultiSlider} slider The Slider to render to (required)
  11422. */
  11423. constructor: function(config) {
  11424. /**
  11425. * @property slider
  11426. * @type Ext.slider.MultiSlider
  11427. * The slider this thumb is contained within
  11428. */
  11429. Ext.apply(this, config || {}, {
  11430. cls: 'x-slider-thumb',
  11431. /**
  11432. * @cfg {Boolean} constrain True to constrain the thumb so that it cannot overlap its siblings
  11433. */
  11434. constrain: false
  11435. });
  11436. Ext.slider.Thumb.superclass.constructor.call(this, config);
  11437. if (this.slider.vertical) {
  11438. Ext.apply(this, Ext.slider.Thumb.Vertical);
  11439. }
  11440. },
  11441. /**
  11442. * Renders the thumb into a slider
  11443. */
  11444. render: function() {
  11445. this.el = this.slider.innerEl.insertFirst({cls: this.cls});
  11446. this.initEvents();
  11447. },
  11448. /**
  11449. * Enables the thumb if it is currently disabled
  11450. */
  11451. enable: function() {
  11452. this.disabled = false;
  11453. this.el.removeClass(this.slider.disabledClass);
  11454. },
  11455. /**
  11456. * Disables the thumb if it is currently enabled
  11457. */
  11458. disable: function() {
  11459. this.disabled = true;
  11460. this.el.addClass(this.slider.disabledClass);
  11461. },
  11462. /**
  11463. * Sets up an Ext.dd.DragTracker for this thumb
  11464. */
  11465. initEvents: function() {
  11466. var el = this.el;
  11467. el.addClassOnOver('x-slider-thumb-over');
  11468. this.tracker = new Ext.dd.DragTracker({
  11469. onBeforeStart: this.onBeforeDragStart.createDelegate(this),
  11470. onStart : this.onDragStart.createDelegate(this),
  11471. onDrag : this.onDrag.createDelegate(this),
  11472. onEnd : this.onDragEnd.createDelegate(this),
  11473. tolerance : 3,
  11474. autoStart : 300
  11475. });
  11476. this.tracker.initEl(el);
  11477. },
  11478. /**
  11479. * @private
  11480. * This is tied into the internal Ext.dd.DragTracker. If the slider is currently disabled,
  11481. * this returns false to disable the DragTracker too.
  11482. * @return {Boolean} False if the slider is currently disabled
  11483. */
  11484. onBeforeDragStart : function(e) {
  11485. if (this.disabled) {
  11486. return false;
  11487. } else {
  11488. this.slider.promoteThumb(this);
  11489. return true;
  11490. }
  11491. },
  11492. /**
  11493. * @private
  11494. * This is tied into the internal Ext.dd.DragTracker's onStart template method. Adds the drag CSS class
  11495. * to the thumb and fires the 'dragstart' event
  11496. */
  11497. onDragStart: function(e){
  11498. this.el.addClass('x-slider-thumb-drag');
  11499. this.dragging = true;
  11500. this.dragStartValue = this.value;
  11501. this.slider.fireEvent('dragstart', this.slider, e, this);
  11502. },
  11503. /**
  11504. * @private
  11505. * This is tied into the internal Ext.dd.DragTracker's onDrag template method. This is called every time
  11506. * the DragTracker detects a drag movement. It updates the Slider's value using the position of the drag
  11507. */
  11508. onDrag: function(e) {
  11509. var slider = this.slider,
  11510. index = this.index,
  11511. newValue = this.getNewValue();
  11512. if (this.constrain) {
  11513. var above = slider.thumbs[index + 1],
  11514. below = slider.thumbs[index - 1];
  11515. if (below != undefined && newValue <= below.value) newValue = below.value;
  11516. if (above != undefined && newValue >= above.value) newValue = above.value;
  11517. }
  11518. slider.setValue(index, newValue, false);
  11519. slider.fireEvent('drag', slider, e, this);
  11520. },
  11521. getNewValue: function() {
  11522. var slider = this.slider,
  11523. pos = slider.innerEl.translatePoints(this.tracker.getXY());
  11524. return Ext.util.Format.round(slider.reverseValue(pos.left), slider.decimalPrecision);
  11525. },
  11526. /**
  11527. * @private
  11528. * This is tied to the internal Ext.dd.DragTracker's onEnd template method. Removes the drag CSS class and
  11529. * fires the 'changecomplete' event with the new value
  11530. */
  11531. onDragEnd: function(e) {
  11532. var slider = this.slider,
  11533. value = this.value;
  11534. this.el.removeClass('x-slider-thumb-drag');
  11535. this.dragging = false;
  11536. slider.fireEvent('dragend', slider, e);
  11537. if (this.dragStartValue != value) {
  11538. slider.fireEvent('changecomplete', slider, value, this);
  11539. }
  11540. }
  11541. });
  11542. /**
  11543. * @class Ext.slider.MultiSlider
  11544. * @extends Ext.BoxComponent
  11545. * Slider which supports vertical or horizontal orientation, keyboard adjustments, configurable snapping, axis clicking and animation. Can be added as an item to any container. Example usage:
  11546. <pre>
  11547. new Ext.Slider({
  11548. renderTo: Ext.getBody(),
  11549. width: 200,
  11550. value: 50,
  11551. increment: 10,
  11552. minValue: 0,
  11553. maxValue: 100
  11554. });
  11555. </pre>
  11556. * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one:
  11557. <pre>
  11558. new Ext.Slider({
  11559. renderTo: Ext.getBody(),
  11560. width: 200,
  11561. values: [25, 50, 75],
  11562. minValue: 0,
  11563. maxValue: 100,
  11564. //this defaults to true, setting to false allows the thumbs to pass each other
  11565. {@link #constrainThumbs}: false
  11566. });
  11567. </pre>
  11568. */
  11569. Ext.slider.MultiSlider = Ext.extend(Ext.BoxComponent, {
  11570. /**
  11571. * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
  11572. */
  11573. /**
  11574. * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
  11575. */
  11576. vertical: false,
  11577. /**
  11578. * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
  11579. */
  11580. minValue: 0,
  11581. /**
  11582. * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
  11583. */
  11584. maxValue: 100,
  11585. /**
  11586. * @cfg {Number/Boolean} decimalPrecision.
  11587. * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
  11588. * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
  11589. */
  11590. decimalPrecision: 0,
  11591. /**
  11592. * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead.
  11593. */
  11594. keyIncrement: 1,
  11595. /**
  11596. * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
  11597. */
  11598. increment: 0,
  11599. /**
  11600. * @private
  11601. * @property clickRange
  11602. * @type Array
  11603. * Determines whether or not a click to the slider component is considered to be a user request to change the value. Specified as an array of [top, bottom],
  11604. * the click event's 'top' property is compared to these numbers and the click only considered a change request if it falls within them. e.g. if the 'top'
  11605. * value of the click event is 4 or 16, the click is not considered a change request as it falls outside of the [5, 15] range
  11606. */
  11607. clickRange: [5,15],
  11608. /**
  11609. * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
  11610. */
  11611. clickToChange : true,
  11612. /**
  11613. * @cfg {Boolean} animate Turn on or off animation. Defaults to true
  11614. */
  11615. animate: true,
  11616. /**
  11617. * True while the thumb is in a drag operation
  11618. * @type Boolean
  11619. */
  11620. dragging: false,
  11621. /**
  11622. * @cfg {Boolean} constrainThumbs True to disallow thumbs from overlapping one another. Defaults to true
  11623. */
  11624. constrainThumbs: true,
  11625. /**
  11626. * @private
  11627. * @property topThumbZIndex
  11628. * @type Number
  11629. * The number used internally to set the z index of the top thumb (see promoteThumb for details)
  11630. */
  11631. topThumbZIndex: 10000,
  11632. // private override
  11633. initComponent : function(){
  11634. if(!Ext.isDefined(this.value)){
  11635. this.value = this.minValue;
  11636. }
  11637. /**
  11638. * @property thumbs
  11639. * @type Array
  11640. * Array containing references to each thumb
  11641. */
  11642. this.thumbs = [];
  11643. Ext.slider.MultiSlider.superclass.initComponent.call(this);
  11644. this.keyIncrement = Math.max(this.increment, this.keyIncrement);
  11645. this.addEvents(
  11646. /**
  11647. * @event beforechange
  11648. * Fires before the slider value is changed. By returning false from an event handler,
  11649. * you can cancel the event and prevent the slider from changing.
  11650. * @param {Ext.Slider} slider The slider
  11651. * @param {Number} newValue The new value which the slider is being changed to.
  11652. * @param {Number} oldValue The old value which the slider was previously.
  11653. */
  11654. 'beforechange',
  11655. /**
  11656. * @event change
  11657. * Fires when the slider value is changed.
  11658. * @param {Ext.Slider} slider The slider
  11659. * @param {Number} newValue The new value which the slider has been changed to.
  11660. * @param {Ext.slider.Thumb} thumb The thumb that was changed
  11661. */
  11662. 'change',
  11663. /**
  11664. * @event changecomplete
  11665. * Fires when the slider value is changed by the user and any drag operations have completed.
  11666. * @param {Ext.Slider} slider The slider
  11667. * @param {Number} newValue The new value which the slider has been changed to.
  11668. * @param {Ext.slider.Thumb} thumb The thumb that was changed
  11669. */
  11670. 'changecomplete',
  11671. /**
  11672. * @event dragstart
  11673. * Fires after a drag operation has started.
  11674. * @param {Ext.Slider} slider The slider
  11675. * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
  11676. */
  11677. 'dragstart',
  11678. /**
  11679. * @event drag
  11680. * Fires continuously during the drag operation while the mouse is moving.
  11681. * @param {Ext.Slider} slider The slider
  11682. * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
  11683. */
  11684. 'drag',
  11685. /**
  11686. * @event dragend
  11687. * Fires after the drag operation has completed.
  11688. * @param {Ext.Slider} slider The slider
  11689. * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
  11690. */
  11691. 'dragend'
  11692. );
  11693. /**
  11694. * @property values
  11695. * @type Array
  11696. * Array of values to initalize the thumbs with
  11697. */
  11698. if (this.values == undefined || Ext.isEmpty(this.values)) this.values = [0];
  11699. var values = this.values;
  11700. for (var i=0; i < values.length; i++) {
  11701. this.addThumb(values[i]);
  11702. }
  11703. if(this.vertical){
  11704. Ext.apply(this, Ext.slider.Vertical);
  11705. }
  11706. },
  11707. /**
  11708. * Creates a new thumb and adds it to the slider
  11709. * @param {Number} value The initial value to set on the thumb. Defaults to 0
  11710. */
  11711. addThumb: function(value) {
  11712. var thumb = new Ext.slider.Thumb({
  11713. value : value,
  11714. slider : this,
  11715. index : this.thumbs.length,
  11716. constrain: this.constrainThumbs
  11717. });
  11718. this.thumbs.push(thumb);
  11719. //render the thumb now if needed
  11720. if (this.rendered) thumb.render();
  11721. },
  11722. /**
  11723. * @private
  11724. * Moves the given thumb above all other by increasing its z-index. This is called when as drag
  11725. * any thumb, so that the thumb that was just dragged is always at the highest z-index. This is
  11726. * required when the thumbs are stacked on top of each other at one of the ends of the slider's
  11727. * range, which can result in the user not being able to move any of them.
  11728. * @param {Ext.slider.Thumb} topThumb The thumb to move to the top
  11729. */
  11730. promoteThumb: function(topThumb) {
  11731. var thumbs = this.thumbs,
  11732. zIndex, thumb;
  11733. for (var i = 0, j = thumbs.length; i < j; i++) {
  11734. thumb = thumbs[i];
  11735. if (thumb == topThumb) {
  11736. zIndex = this.topThumbZIndex;
  11737. } else {
  11738. zIndex = '';
  11739. }
  11740. thumb.el.setStyle('zIndex', zIndex);
  11741. }
  11742. },
  11743. // private override
  11744. onRender : function() {
  11745. this.autoEl = {
  11746. cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
  11747. cn : {
  11748. cls: 'x-slider-end',
  11749. cn : {
  11750. cls:'x-slider-inner',
  11751. cn : [{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]
  11752. }
  11753. }
  11754. };
  11755. Ext.slider.MultiSlider.superclass.onRender.apply(this, arguments);
  11756. this.endEl = this.el.first();
  11757. this.innerEl = this.endEl.first();
  11758. this.focusEl = this.innerEl.child('.x-slider-focus');
  11759. //render each thumb
  11760. for (var i=0; i < this.thumbs.length; i++) {
  11761. this.thumbs[i].render();
  11762. }
  11763. //calculate the size of half a thumb
  11764. var thumb = this.innerEl.child('.x-slider-thumb');
  11765. this.halfThumb = (this.vertical ? thumb.getHeight() : thumb.getWidth()) / 2;
  11766. this.initEvents();
  11767. },
  11768. /**
  11769. * @private
  11770. * Adds keyboard and mouse listeners on this.el. Ignores click events on the internal focus element.
  11771. * Creates a new DragTracker which is used to control what happens when the user drags the thumb around.
  11772. */
  11773. initEvents : function(){
  11774. this.mon(this.el, {
  11775. scope : this,
  11776. mousedown: this.onMouseDown,
  11777. keydown : this.onKeyDown
  11778. });
  11779. this.focusEl.swallowEvent("click", true);
  11780. },
  11781. /**
  11782. * @private
  11783. * Mousedown handler for the slider. If the clickToChange is enabled and the click was not on the draggable 'thumb',
  11784. * this calculates the new value of the slider and tells the implementation (Horizontal or Vertical) to move the thumb
  11785. * @param {Ext.EventObject} e The click event
  11786. */
  11787. onMouseDown : function(e){
  11788. if(this.disabled){
  11789. return;
  11790. }
  11791. //see if the click was on any of the thumbs
  11792. var thumbClicked = false;
  11793. for (var i=0; i < this.thumbs.length; i++) {
  11794. thumbClicked = thumbClicked || e.target == this.thumbs[i].el.dom;
  11795. }
  11796. if (this.clickToChange && !thumbClicked) {
  11797. var local = this.innerEl.translatePoints(e.getXY());
  11798. this.onClickChange(local);
  11799. }
  11800. this.focus();
  11801. },
  11802. /**
  11803. * @private
  11804. * Moves the thumb to the indicated position. Note that a Vertical implementation is provided in Ext.slider.Vertical.
  11805. * Only changes the value if the click was within this.clickRange.
  11806. * @param {Object} local Object containing top and left values for the click event.
  11807. */
  11808. onClickChange : function(local) {
  11809. if (local.top > this.clickRange[0] && local.top < this.clickRange[1]) {
  11810. //find the nearest thumb to the click event
  11811. var thumb = this.getNearest(local, 'left'),
  11812. index = thumb.index;
  11813. this.setValue(index, Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
  11814. }
  11815. },
  11816. /**
  11817. * @private
  11818. * Returns the nearest thumb to a click event, along with its distance
  11819. * @param {Object} local Object containing top and left values from a click event
  11820. * @param {String} prop The property of local to compare on. Use 'left' for horizontal sliders, 'top' for vertical ones
  11821. * @return {Object} The closest thumb object and its distance from the click event
  11822. */
  11823. getNearest: function(local, prop) {
  11824. var localValue = prop == 'top' ? this.innerEl.getHeight() - local[prop] : local[prop],
  11825. clickValue = this.reverseValue(localValue),
  11826. nearestDistance = (this.maxValue - this.minValue) + 5, //add a small fudge for the end of the slider
  11827. index = 0,
  11828. nearest = null;
  11829. for (var i=0; i < this.thumbs.length; i++) {
  11830. var thumb = this.thumbs[i],
  11831. value = thumb.value,
  11832. dist = Math.abs(value - clickValue);
  11833. if (Math.abs(dist <= nearestDistance)) {
  11834. nearest = thumb;
  11835. index = i;
  11836. nearestDistance = dist;
  11837. }
  11838. }
  11839. return nearest;
  11840. },
  11841. /**
  11842. * @private
  11843. * Handler for any keypresses captured by the slider. If the key is UP or RIGHT, the thumb is moved along to the right
  11844. * by this.keyIncrement. If DOWN or LEFT it is moved left. Pressing CTRL moves the slider to the end in either direction
  11845. * @param {Ext.EventObject} e The Event object
  11846. */
  11847. onKeyDown : function(e){
  11848. if(this.disabled){e.preventDefault();return;}
  11849. var k = e.getKey();
  11850. switch(k){
  11851. case e.UP:
  11852. case e.RIGHT:
  11853. e.stopEvent();
  11854. if(e.ctrlKey){
  11855. this.setValue(this.maxValue, undefined, true);
  11856. }else{
  11857. this.setValue(this.value+this.keyIncrement, undefined, true);
  11858. }
  11859. break;
  11860. case e.DOWN:
  11861. case e.LEFT:
  11862. e.stopEvent();
  11863. if(e.ctrlKey){
  11864. this.setValue(this.minValue, undefined, true);
  11865. }else{
  11866. this.setValue(this.value-this.keyIncrement, undefined, true);
  11867. }
  11868. break;
  11869. default:
  11870. e.preventDefault();
  11871. }
  11872. },
  11873. /**
  11874. * @private
  11875. * If using snapping, this takes a desired new value and returns the closest snapped
  11876. * value to it
  11877. * @param {Number} value The unsnapped value
  11878. * @return {Number} The value of the nearest snap target
  11879. */
  11880. doSnap : function(value){
  11881. if (!(this.increment && value)) {
  11882. return value;
  11883. }
  11884. var newValue = value,
  11885. inc = this.increment,
  11886. m = value % inc;
  11887. if (m != 0) {
  11888. newValue -= m;
  11889. if (m * 2 >= inc) {
  11890. newValue += inc;
  11891. } else if (m * 2 < -inc) {
  11892. newValue -= inc;
  11893. }
  11894. }
  11895. return newValue.constrain(this.minValue, this.maxValue);
  11896. },
  11897. // private
  11898. afterRender : function(){
  11899. Ext.slider.MultiSlider.superclass.afterRender.apply(this, arguments);
  11900. for (var i=0; i < this.thumbs.length; i++) {
  11901. var thumb = this.thumbs[i];
  11902. if (thumb.value !== undefined) {
  11903. var v = this.normalizeValue(thumb.value);
  11904. if (v !== thumb.value) {
  11905. // delete this.value;
  11906. this.setValue(i, v, false);
  11907. } else {
  11908. this.moveThumb(i, this.translateValue(v), false);
  11909. }
  11910. }
  11911. };
  11912. },
  11913. /**
  11914. * @private
  11915. * Returns the ratio of pixels to mapped values. e.g. if the slider is 200px wide and maxValue - minValue is 100,
  11916. * the ratio is 2
  11917. * @return {Number} The ratio of pixels to mapped values
  11918. */
  11919. getRatio : function(){
  11920. var w = this.innerEl.getWidth(),
  11921. v = this.maxValue - this.minValue;
  11922. return v == 0 ? w : (w/v);
  11923. },
  11924. /**
  11925. * @private
  11926. * Returns a snapped, constrained value when given a desired value
  11927. * @param {Number} value Raw number value
  11928. * @return {Number} The raw value rounded to the correct d.p. and constrained within the set max and min values
  11929. */
  11930. normalizeValue : function(v){
  11931. v = this.doSnap(v);
  11932. v = Ext.util.Format.round(v, this.decimalPrecision);
  11933. v = v.constrain(this.minValue, this.maxValue);
  11934. return v;
  11935. },
  11936. /**
  11937. * Sets the minimum value for the slider instance. If the current value is less than the
  11938. * minimum value, the current value will be changed.
  11939. * @param {Number} val The new minimum value
  11940. */
  11941. setMinValue : function(val){
  11942. this.minValue = val;
  11943. this.syncThumb();
  11944. for (var i=0, j = this.thumbs.length; i < j; i++) {
  11945. if (this.thumbs[i].value < val) this.thumbs[i].value = val;
  11946. }
  11947. },
  11948. /**
  11949. * Sets the maximum value for the slider instance. If the current value is more than the
  11950. * maximum value, the current value will be changed.
  11951. * @param {Number} val The new maximum value
  11952. */
  11953. setMaxValue : function(val){
  11954. this.maxValue = val;
  11955. this.syncThumb();
  11956. for (var i=0; i < this.thumbs.length; i++) {
  11957. if (this.thumbs[i].value > val) this.thumbs[i].value = val;
  11958. }
  11959. },
  11960. /**
  11961. * Programmatically sets the value of the Slider. Ensures that the value is constrained within
  11962. * the minValue and maxValue.
  11963. * @param {Number} index Index of the thumb to move
  11964. * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
  11965. * @param {Boolean} animate Turn on or off animation, defaults to true
  11966. */
  11967. setValue : function(index, v, animate, changeComplete) {
  11968. var thumb = this.thumbs[index],
  11969. el = thumb.el;
  11970. v = this.normalizeValue(v);
  11971. if (v !== thumb.value && this.fireEvent('beforechange', this, v, thumb.value) !== false) {
  11972. thumb.value = v;
  11973. this.moveThumb(index, this.translateValue(v), animate !== false);
  11974. this.fireEvent('change', this, v, thumb);
  11975. if(changeComplete){
  11976. this.fireEvent('changecomplete', this, v, thumb);
  11977. }
  11978. }
  11979. },
  11980. /**
  11981. * @private
  11982. */
  11983. translateValue : function(v) {
  11984. var ratio = this.getRatio();
  11985. return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
  11986. },
  11987. /**
  11988. * @private
  11989. * Given a pixel location along the slider, returns the mapped slider value for that pixel.
  11990. * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reverseValue(50)
  11991. * returns 200
  11992. * @param {Number} pos The position along the slider to return a mapped value for
  11993. * @return {Number} The mapped value for the given position
  11994. */
  11995. reverseValue : function(pos){
  11996. var ratio = this.getRatio();
  11997. return (pos + (this.minValue * ratio)) / ratio;
  11998. },
  11999. /**
  12000. * @private
  12001. * @param {Number} index Index of the thumb to move
  12002. */
  12003. moveThumb: function(index, v, animate){
  12004. var thumb = this.thumbs[index].el;
  12005. if(!animate || this.animate === false){
  12006. thumb.setLeft(v);
  12007. }else{
  12008. thumb.shift({left: v, stopFx: true, duration:.35});
  12009. }
  12010. },
  12011. // private
  12012. focus : function(){
  12013. this.focusEl.focus(10);
  12014. },
  12015. // private
  12016. onResize : function(w, h){
  12017. var thumbs = this.thumbs,
  12018. len = thumbs.length,
  12019. i = 0;
  12020. /*
  12021. * If we happen to be animating during a resize, the position of the thumb will likely be off
  12022. * when the animation stops. As such, just stop any animations before syncing the thumbs.
  12023. */
  12024. for(; i < len; ++i){
  12025. thumbs[i].el.stopFx();
  12026. }
  12027. this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
  12028. this.syncThumb();
  12029. Ext.slider.MultiSlider.superclass.onResize.apply(this, arguments);
  12030. },
  12031. //private
  12032. onDisable: function(){
  12033. Ext.slider.MultiSlider.superclass.onDisable.call(this);
  12034. for (var i=0; i < this.thumbs.length; i++) {
  12035. var thumb = this.thumbs[i],
  12036. el = thumb.el;
  12037. thumb.disable();
  12038. if(Ext.isIE){
  12039. //IE breaks when using overflow visible and opacity other than 1.
  12040. //Create a place holder for the thumb and display it.
  12041. var xy = el.getXY();
  12042. el.hide();
  12043. this.innerEl.addClass(this.disabledClass).dom.disabled = true;
  12044. if (!this.thumbHolder) {
  12045. this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});
  12046. }
  12047. this.thumbHolder.show().setXY(xy);
  12048. }
  12049. }
  12050. },
  12051. //private
  12052. onEnable: function(){
  12053. Ext.slider.MultiSlider.superclass.onEnable.call(this);
  12054. for (var i=0; i < this.thumbs.length; i++) {
  12055. var thumb = this.thumbs[i],
  12056. el = thumb.el;
  12057. thumb.enable();
  12058. if (Ext.isIE) {
  12059. this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
  12060. if (this.thumbHolder) this.thumbHolder.hide();
  12061. el.show();
  12062. this.syncThumb();
  12063. }
  12064. }
  12065. },
  12066. /**
  12067. * Synchronizes the thumb position to the proper proportion of the total component width based
  12068. * on the current slider {@link #value}. This will be called automatically when the Slider
  12069. * is resized by a layout, but if it is rendered auto width, this method can be called from
  12070. * another resize handler to sync the Slider if necessary.
  12071. */
  12072. syncThumb : function() {
  12073. if (this.rendered) {
  12074. for (var i=0; i < this.thumbs.length; i++) {
  12075. this.moveThumb(i, this.translateValue(this.thumbs[i].value));
  12076. }
  12077. }
  12078. },
  12079. /**
  12080. * Returns the current value of the slider
  12081. * @param {Number} index The index of the thumb to return a value for
  12082. * @return {Number} The current value of the slider
  12083. */
  12084. getValue : function(index) {
  12085. return this.thumbs[index].value;
  12086. },
  12087. /**
  12088. * Returns an array of values - one for the location of each thumb
  12089. * @return {Array} The set of thumb values
  12090. */
  12091. getValues: function() {
  12092. var values = [];
  12093. for (var i=0; i < this.thumbs.length; i++) {
  12094. values.push(this.thumbs[i].value);
  12095. }
  12096. return values;
  12097. },
  12098. // private
  12099. beforeDestroy : function(){
  12100. Ext.destroyMembers(this, 'endEl', 'innerEl', 'thumb', 'halfThumb', 'focusEl', 'tracker', 'thumbHolder');
  12101. Ext.slider.MultiSlider.superclass.beforeDestroy.call(this);
  12102. }
  12103. });
  12104. Ext.reg('multislider', Ext.slider.MultiSlider);
  12105. /**
  12106. * @class Ext.slider.SingleSlider
  12107. * @extends Ext.slider.MultiSlider
  12108. * Slider which supports vertical or horizontal orientation, keyboard adjustments,
  12109. * configurable snapping, axis clicking and animation. Can be added as an item to
  12110. * any container. Example usage:
  12111. <pre><code>
  12112. new Ext.slider.SingleSlider({
  12113. renderTo: Ext.getBody(),
  12114. width: 200,
  12115. value: 50,
  12116. increment: 10,
  12117. minValue: 0,
  12118. maxValue: 100
  12119. });
  12120. </code></pre>
  12121. * The class Ext.slider.SingleSlider is aliased to Ext.Slider for backwards compatibility.
  12122. */
  12123. Ext.slider.SingleSlider = Ext.extend(Ext.slider.MultiSlider, {
  12124. constructor: function(config) {
  12125. config = config || {};
  12126. Ext.applyIf(config, {
  12127. values: [config.value || 0]
  12128. });
  12129. Ext.slider.SingleSlider.superclass.constructor.call(this, config);
  12130. },
  12131. /**
  12132. * Returns the current value of the slider
  12133. * @return {Number} The current value of the slider
  12134. */
  12135. getValue: function() {
  12136. //just returns the value of the first thumb, which should be the only one in a single slider
  12137. return Ext.slider.SingleSlider.superclass.getValue.call(this, 0);
  12138. },
  12139. /**
  12140. * Programmatically sets the value of the Slider. Ensures that the value is constrained within
  12141. * the minValue and maxValue.
  12142. * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
  12143. * @param {Boolean} animate Turn on or off animation, defaults to true
  12144. */
  12145. setValue: function(value, animate) {
  12146. var args = Ext.toArray(arguments),
  12147. len = args.length;
  12148. //this is to maintain backwards compatiblity for sliders with only one thunb. Usually you must pass the thumb
  12149. //index to setValue, but if we only have one thumb we inject the index here first if given the multi-slider
  12150. //signature without the required index. The index will always be 0 for a single slider
  12151. if (len == 1 || (len <= 3 && typeof arguments[1] != 'number')) {
  12152. args.unshift(0);
  12153. }
  12154. return Ext.slider.SingleSlider.superclass.setValue.apply(this, args);
  12155. },
  12156. /**
  12157. * Synchronizes the thumb position to the proper proportion of the total component width based
  12158. * on the current slider {@link #value}. This will be called automatically when the Slider
  12159. * is resized by a layout, but if it is rendered auto width, this method can be called from
  12160. * another resize handler to sync the Slider if necessary.
  12161. */
  12162. syncThumb : function() {
  12163. return Ext.slider.SingleSlider.superclass.syncThumb.apply(this, [0].concat(arguments));
  12164. },
  12165. // private
  12166. getNearest : function(){
  12167. // Since there's only 1 thumb, it's always the nearest
  12168. return this.thumbs[0];
  12169. }
  12170. });
  12171. //backwards compatibility
  12172. Ext.Slider = Ext.slider.SingleSlider;
  12173. Ext.reg('slider', Ext.slider.SingleSlider);
  12174. // private class to support vertical sliders
  12175. Ext.slider.Vertical = {
  12176. onResize : function(w, h){
  12177. this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
  12178. this.syncThumb();
  12179. },
  12180. getRatio : function(){
  12181. var h = this.innerEl.getHeight(),
  12182. v = this.maxValue - this.minValue;
  12183. return h/v;
  12184. },
  12185. moveThumb: function(index, v, animate) {
  12186. var thumb = this.thumbs[index],
  12187. el = thumb.el;
  12188. if (!animate || this.animate === false) {
  12189. el.setBottom(v);
  12190. } else {
  12191. el.shift({bottom: v, stopFx: true, duration:.35});
  12192. }
  12193. },
  12194. onClickChange : function(local) {
  12195. if (local.left > this.clickRange[0] && local.left < this.clickRange[1]) {
  12196. var thumb = this.getNearest(local, 'top'),
  12197. index = thumb.index,
  12198. value = this.minValue + this.reverseValue(this.innerEl.getHeight() - local.top);
  12199. this.setValue(index, Ext.util.Format.round(value, this.decimalPrecision), undefined, true);
  12200. }
  12201. }
  12202. };
  12203. //private class to support vertical dragging of thumbs within a slider
  12204. Ext.slider.Thumb.Vertical = {
  12205. getNewValue: function() {
  12206. var slider = this.slider,
  12207. innerEl = slider.innerEl,
  12208. pos = innerEl.translatePoints(this.tracker.getXY()),
  12209. bottom = innerEl.getHeight() - pos.top;
  12210. return slider.minValue + Ext.util.Format.round(bottom / slider.getRatio(), slider.decimalPrecision);
  12211. }
  12212. };
  12213. /**
  12214. * @class Ext.ProgressBar
  12215. * @extends Ext.BoxComponent
  12216. * <p>An updateable progress bar component. The progress bar supports two different modes: manual and automatic.</p>
  12217. * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
  12218. * progress bar as needed from your own code. This method is most appropriate when you want to show progress
  12219. * throughout an operation that has predictable points of interest at which you can update the control.</p>
  12220. * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
  12221. * once the operation is complete. You can optionally have the progress bar wait for a specific amount of time
  12222. * and then clear itself. Automatic mode is most appropriate for timed operations or asynchronous operations in
  12223. * which you have no need for indicating intermediate progress.</p>
  12224. * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
  12225. * @cfg {String} text The progress bar text (defaults to '')
  12226. * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
  12227. * bar's internal text element)
  12228. * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
  12229. * @xtype progress
  12230. */
  12231. Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
  12232. /**
  12233. * @cfg {String} baseCls
  12234. * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
  12235. */
  12236. baseCls : 'x-progress',
  12237. /**
  12238. * @cfg {Boolean} animate
  12239. * True to animate the progress bar during transitions (defaults to false)
  12240. */
  12241. animate : false,
  12242. // private
  12243. waitTimer : null,
  12244. // private
  12245. initComponent : function(){
  12246. Ext.ProgressBar.superclass.initComponent.call(this);
  12247. this.addEvents(
  12248. /**
  12249. * @event update
  12250. * Fires after each update interval
  12251. * @param {Ext.ProgressBar} this
  12252. * @param {Number} The current progress value
  12253. * @param {String} The current progress text
  12254. */
  12255. "update"
  12256. );
  12257. },
  12258. // private
  12259. onRender : function(ct, position){
  12260. var tpl = new Ext.Template(
  12261. '<div class="{cls}-wrap">',
  12262. '<div class="{cls}-inner">',
  12263. '<div class="{cls}-bar">',
  12264. '<div class="{cls}-text">',
  12265. '<div>&#160;</div>',
  12266. '</div>',
  12267. '</div>',
  12268. '<div class="{cls}-text {cls}-text-back">',
  12269. '<div>&#160;</div>',
  12270. '</div>',
  12271. '</div>',
  12272. '</div>'
  12273. );
  12274. this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
  12275. : tpl.append(ct, {cls: this.baseCls}, true);
  12276. if(this.id){
  12277. this.el.dom.id = this.id;
  12278. }
  12279. var inner = this.el.dom.firstChild;
  12280. this.progressBar = Ext.get(inner.firstChild);
  12281. if(this.textEl){
  12282. //use an external text el
  12283. this.textEl = Ext.get(this.textEl);
  12284. delete this.textTopEl;
  12285. }else{
  12286. //setup our internal layered text els
  12287. this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
  12288. var textBackEl = Ext.get(inner.childNodes[1]);
  12289. this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
  12290. this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
  12291. this.textEl.setWidth(inner.offsetWidth);
  12292. }
  12293. this.progressBar.setHeight(inner.offsetHeight);
  12294. },
  12295. // private
  12296. afterRender : function(){
  12297. Ext.ProgressBar.superclass.afterRender.call(this);
  12298. if(this.value){
  12299. this.updateProgress(this.value, this.text);
  12300. }else{
  12301. this.updateText(this.text);
  12302. }
  12303. },
  12304. /**
  12305. * Updates the progress bar value, and optionally its text. If the text argument is not specified,
  12306. * any existing text value will be unchanged. To blank out existing text, pass ''. Note that even
  12307. * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
  12308. * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
  12309. * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
  12310. * @param {String} text (optional) The string to display in the progress text element (defaults to '')
  12311. * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
  12312. * not specified, the default for the class is used (default to false)
  12313. * @return {Ext.ProgressBar} this
  12314. */
  12315. updateProgress : function(value, text, animate){
  12316. this.value = value || 0;
  12317. if(text){
  12318. this.updateText(text);
  12319. }
  12320. if(this.rendered && !this.isDestroyed){
  12321. var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
  12322. this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
  12323. if(this.textTopEl){
  12324. //textTopEl should be the same width as the bar so overflow will clip as the bar moves
  12325. this.textTopEl.removeClass('x-hidden').setWidth(w);
  12326. }
  12327. }
  12328. this.fireEvent('update', this, value, text);
  12329. return this;
  12330. },
  12331. /**
  12332. * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress
  12333. * bar will automatically reset after a fixed amount of time and optionally call a callback function
  12334. * if specified. If no duration is passed in, then the progress bar will run indefinitely and must
  12335. * be manually cleared by calling {@link #reset}. The wait method accepts a config object with
  12336. * the following properties:
  12337. * <pre>
  12338. Property Type Description
  12339. ---------- ------------ ----------------------------------------------------------------------
  12340. duration Number The length of time in milliseconds that the progress bar should
  12341. run before resetting itself (defaults to undefined, in which case it
  12342. will run indefinitely until reset is called)
  12343. interval Number The length of time in milliseconds between each progress update
  12344. (defaults to 1000 ms)
  12345. animate Boolean Whether to animate the transition of the progress bar. If this value is
  12346. not specified, the default for the class is used.
  12347. increment Number The number of progress update segments to display within the progress
  12348. bar (defaults to 10). If the bar reaches the end and is still
  12349. updating, it will automatically wrap back to the beginning.
  12350. text String Optional text to display in the progress bar element (defaults to '').
  12351. fn Function A callback function to execute after the progress bar finishes auto-
  12352. updating. The function will be called with no arguments. This function
  12353. will be ignored if duration is not specified since in that case the
  12354. progress bar can only be stopped programmatically, so any required function
  12355. should be called by the same code after it resets the progress bar.
  12356. scope Object The scope that is passed to the callback function (only applies when
  12357. duration and fn are both passed).
  12358. </pre>
  12359. *
  12360. * Example usage:
  12361. * <pre><code>
  12362. var p = new Ext.ProgressBar({
  12363. renderTo: 'my-el'
  12364. });
  12365. //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
  12366. p.wait({
  12367. interval: 100, //bar will move fast!
  12368. duration: 5000,
  12369. increment: 15,
  12370. text: 'Updating...',
  12371. scope: this,
  12372. fn: function(){
  12373. Ext.fly('status').update('Done!');
  12374. }
  12375. });
  12376. //Or update indefinitely until some async action completes, then reset manually
  12377. p.wait();
  12378. myAction.on('complete', function(){
  12379. p.reset();
  12380. Ext.fly('status').update('Done!');
  12381. });
  12382. </code></pre>
  12383. * @param {Object} config (optional) Configuration options
  12384. * @return {Ext.ProgressBar} this
  12385. */
  12386. wait : function(o){
  12387. if(!this.waitTimer){
  12388. var scope = this;
  12389. o = o || {};
  12390. this.updateText(o.text);
  12391. this.waitTimer = Ext.TaskMgr.start({
  12392. run: function(i){
  12393. var inc = o.increment || 10;
  12394. i -= 1;
  12395. this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
  12396. },
  12397. interval: o.interval || 1000,
  12398. duration: o.duration,
  12399. onStop: function(){
  12400. if(o.fn){
  12401. o.fn.apply(o.scope || this);
  12402. }
  12403. this.reset();
  12404. },
  12405. scope: scope
  12406. });
  12407. }
  12408. return this;
  12409. },
  12410. /**
  12411. * Returns true if the progress bar is currently in a {@link #wait} operation
  12412. * @return {Boolean} True if waiting, else false
  12413. */
  12414. isWaiting : function(){
  12415. return this.waitTimer !== null;
  12416. },
  12417. /**
  12418. * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress
  12419. * bar itself will display the updated text.
  12420. * @param {String} text (optional) The string to display in the progress text element (defaults to '')
  12421. * @return {Ext.ProgressBar} this
  12422. */
  12423. updateText : function(text){
  12424. this.text = text || '&#160;';
  12425. if(this.rendered){
  12426. this.textEl.update(this.text);
  12427. }
  12428. return this;
  12429. },
  12430. /**
  12431. * Synchronizes the inner bar width to the proper proportion of the total componet width based
  12432. * on the current progress {@link #value}. This will be called automatically when the ProgressBar
  12433. * is resized by a layout, but if it is rendered auto width, this method can be called from
  12434. * another resize handler to sync the ProgressBar if necessary.
  12435. */
  12436. syncProgressBar : function(){
  12437. if(this.value){
  12438. this.updateProgress(this.value, this.text);
  12439. }
  12440. return this;
  12441. },
  12442. /**
  12443. * Sets the size of the progress bar.
  12444. * @param {Number} width The new width in pixels
  12445. * @param {Number} height The new height in pixels
  12446. * @return {Ext.ProgressBar} this
  12447. */
  12448. setSize : function(w, h){
  12449. Ext.ProgressBar.superclass.setSize.call(this, w, h);
  12450. if(this.textTopEl){
  12451. var inner = this.el.dom.firstChild;
  12452. this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
  12453. }
  12454. this.syncProgressBar();
  12455. return this;
  12456. },
  12457. /**
  12458. * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress
  12459. * bar will also be hidden (using the {@link #hideMode} property internally).
  12460. * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
  12461. * @return {Ext.ProgressBar} this
  12462. */
  12463. reset : function(hide){
  12464. this.updateProgress(0);
  12465. if(this.textTopEl){
  12466. this.textTopEl.addClass('x-hidden');
  12467. }
  12468. this.clearTimer();
  12469. if(hide === true){
  12470. this.hide();
  12471. }
  12472. return this;
  12473. },
  12474. // private
  12475. clearTimer : function(){
  12476. if(this.waitTimer){
  12477. this.waitTimer.onStop = null; //prevent recursion
  12478. Ext.TaskMgr.stop(this.waitTimer);
  12479. this.waitTimer = null;
  12480. }
  12481. },
  12482. onDestroy: function(){
  12483. this.clearTimer();
  12484. if(this.rendered){
  12485. if(this.textEl.isComposite){
  12486. this.textEl.clear();
  12487. }
  12488. Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
  12489. }
  12490. Ext.ProgressBar.superclass.onDestroy.call(this);
  12491. }
  12492. });
  12493. Ext.reg('progress', Ext.ProgressBar);