3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.form.field.Picker
17 * @extends Ext.form.field.Trigger
18 * <p>An abstract class for fields that have a single trigger which opens a "picker" popup below
19 * the field, e.g. a combobox menu list or a date picker. It provides a base implementation for
20 * toggling the picker's visibility when the trigger is clicked, as well as keyboard navigation
21 * and some basic events. Sizing and alignment of the picker can be controlled via the {@link #matchFieldWidth}
22 * and {@link #pickerAlign}/{@link #pickerOffset} config properties respectively.</p>
23 * <p>You would not normally use this class directly, but instead use it as the parent class for
24 * a specific picker field implementation. Subclasses must implement the {@link #createPicker} method
25 * to create a picker component appropriate for the field.</p>
28 Ext.define('Ext.form.field.Picker', {
29 extend: 'Ext.form.field.Trigger',
30 alias: 'widget.pickerfield',
31 alternateClassName: 'Ext.form.Picker',
32 requires: ['Ext.util.KeyNav'],
35 * @cfg {Boolean} matchFieldWidth
36 * Whether the picker dropdown's width should be explicitly set to match the width of the field.
37 * Defaults to <tt>true</tt>.
39 matchFieldWidth: true,
42 * @cfg {String} pickerAlign
43 * The {@link Ext.core.Element#alignTo alignment position} with which to align the picker. Defaults
44 * to <tt>"tl-bl?"</tt>
46 pickerAlign: 'tl-bl?',
49 * @cfg {Array} pickerOffset
50 * An offset [x,y] to use in addition to the {@link #pickerAlign} when positioning the picker.
51 * Defaults to undefined.
55 * @cfg {String} openCls
56 * A class to be added to the field's {@link #bodyEl} element when the picker is opened. Defaults
57 * to 'x-pickerfield-open'.
59 openCls: Ext.baseCSSPrefix + 'pickerfield-open',
62 * @property isExpanded
64 * True if the picker is currently expanded, false if not.
68 * @cfg {Boolean} editable <tt>false</tt> to prevent the user from typing text directly into the field;
69 * the field can only have its value set via selecting a value from the picker. In this state, the picker
70 * can also be opened by clicking directly on the input field itself.
71 * (defaults to <tt>true</tt>).
76 initComponent: function() {
83 * Fires when the field's picker is expanded.
84 * @param {Ext.form.field.Picker} field This field instance
89 * Fires when the field's picker is collapsed.
90 * @param {Ext.form.field.Picker} field This field instance
95 * Fires when a value is selected via the picker.
96 * @param {Ext.form.field.Picker} field This field instance
97 * @param {Mixed} value The value that was selected. The exact type of this value is dependent on
98 * the individual field and picker implementations.
105 initEvents: function() {
109 // Add handlers for keys to expand/collapse the picker
110 me.keyNav = Ext.create('Ext.util.KeyNav', me.inputEl, {
112 if (!me.isExpanded) {
113 // Don't call expand() directly as there may be additional processing involved before
114 // expanding, e.g. in the case of a ComboBox query.
123 // Non-editable allows opening the picker by clicking the field
125 me.mon(me.inputEl, 'click', me.onTriggerClick, me);
128 // Disable native browser autocomplete
130 me.inputEl.dom.setAttribute('autocomplete', 'off');
136 * Expand this field's picker dropdown.
140 bodyEl, picker, collapseIf;
142 if (me.rendered && !me.isExpanded && !me.isDestroyed) {
144 picker = me.getPicker();
145 collapseIf = me.collapseIf;
147 // show the picker and set isExpanded flag
149 me.isExpanded = true;
151 bodyEl.addCls(me.openCls);
153 // monitor clicking and mousewheel
154 me.mon(Ext.getDoc(), {
155 mousewheel: collapseIf,
156 mousedown: collapseIf,
159 Ext.EventManager.onWindowResize(me.alignPicker, me);
160 me.fireEvent('expand', me);
165 onExpand: Ext.emptyFn,
169 * Aligns the picker to the
171 alignPicker: function() {
176 if (this.isExpanded) {
177 picker = me.getPicker();
178 if (me.matchFieldWidth) {
179 // Auto the height (it will be constrained by min and max width) unless there are no records to display.
180 picker.setSize(me.bodyEl.getWidth(), picker.store && picker.store.getCount() ? null : 0);
182 if (picker.isFloating()) {
183 picker.alignTo(me.inputEl, me.pickerAlign, me.pickerOffset);
185 // add the {openCls}-above class if the picker was aligned above
186 // the field due to hitting the bottom of the viewport
187 isAbove = picker.el.getY() < me.inputEl.getY();
188 me.bodyEl[isAbove ? 'addCls' : 'removeCls'](me.openCls + aboveSfx);
189 picker.el[isAbove ? 'addCls' : 'removeCls'](picker.baseCls + aboveSfx);
195 * Collapse this field's picker dropdown.
197 collapse: function() {
198 if (this.isExpanded && !this.isDestroyed) {
200 openCls = me.openCls,
203 collapseIf = me.collapseIf,
206 // hide the picker and set isExpanded flag
208 me.isExpanded = false;
210 // remove the openCls
211 me.bodyEl.removeCls([openCls, openCls + aboveSfx]);
212 picker.el.removeCls(picker.baseCls + aboveSfx);
214 // remove event listeners
215 doc.un('mousewheel', collapseIf, me);
216 doc.un('mousedown', collapseIf, me);
217 Ext.EventManager.removeResizeListener(me.alignPicker, me);
218 me.fireEvent('collapse', me);
223 onCollapse: Ext.emptyFn,
228 * Runs on mousewheel and mousedown of doc to check to see if we should collapse the picker
230 collapseIf: function(e) {
232 if (!me.isDestroyed && !e.within(me.bodyEl, false, true) && !e.within(me.picker.el, false, true)) {
238 * Return a reference to the picker component for this field, creating it if necessary by
239 * calling {@link #createPicker}.
240 * @return {Ext.Component} The picker component
242 getPicker: function() {
244 return me.picker || (me.picker = me.createPicker());
248 * Create and return the component to be used as this field's picker. Must be implemented
249 * by subclasses of Picker.
250 * @return {Ext.Component} The picker component
252 createPicker: Ext.emptyFn,
255 * Handles the trigger click; by default toggles between expanding and collapsing the
258 onTriggerClick: function() {
260 if (!me.readOnly && !me.disabled) {
270 mimicBlur: function(e) {
273 // ignore mousedown events within the picker element
274 if (!picker || !e.within(picker.el, false, true)) {
275 me.callParent(arguments);
279 onDestroy : function(){
281 Ext.EventManager.removeResizeListener(me.alignPicker, me);
282 Ext.destroy(me.picker, me.keyNav);