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 * An abstract class for fields that have a single trigger which opens a "picker" popup below the field, e.g. a combobox
17 * menu list or a date picker. It provides a base implementation for toggling the picker's visibility when the trigger
18 * is clicked, as well as keyboard navigation and some basic events. Sizing and alignment of the picker can be
19 * controlled via the {@link #matchFieldWidth} and {@link #pickerAlign}/{@link #pickerOffset} config properties
22 * You would not normally use this class directly, but instead use it as the parent class for a specific picker field
23 * implementation. Subclasses must implement the {@link #createPicker} method to create a picker component appropriate
26 Ext.define('Ext.form.field.Picker', {
27 extend: 'Ext.form.field.Trigger',
28 alias: 'widget.pickerfield',
29 alternateClassName: 'Ext.form.Picker',
30 requires: ['Ext.util.KeyNav'],
33 * @cfg {Boolean} matchFieldWidth
34 * Whether the picker dropdown's width should be explicitly set to match the width of the field. Defaults to true.
36 matchFieldWidth: true,
39 * @cfg {String} pickerAlign
40 * The {@link Ext.Element#alignTo alignment position} with which to align the picker. Defaults to "tl-bl?"
42 pickerAlign: 'tl-bl?',
45 * @cfg {Number[]} pickerOffset
46 * An offset [x,y] to use in addition to the {@link #pickerAlign} when positioning the picker.
47 * Defaults to undefined.
51 * @cfg {String} openCls
52 * A class to be added to the field's {@link #bodyEl} element when the picker is opened.
53 * Defaults to 'x-pickerfield-open'.
55 openCls: Ext.baseCSSPrefix + 'pickerfield-open',
58 * @property {Boolean} isExpanded
59 * True if the picker is currently expanded, false if not.
63 * @cfg {Boolean} editable
64 * False to prevent the user from typing text directly into the field; the field can only have its value set via
65 * selecting a value from the picker. In this state, the picker can also be opened by clicking directly on the input
71 initComponent: function() {
78 * Fires when the field's picker is expanded.
79 * @param {Ext.form.field.Picker} field This field instance
84 * Fires when the field's picker is collapsed.
85 * @param {Ext.form.field.Picker} field This field instance
90 * Fires when a value is selected via the picker.
91 * @param {Ext.form.field.Picker} field This field instance
92 * @param {Object} value The value that was selected. The exact type of this value is dependent on
93 * the individual field and picker implementations.
100 initEvents: function() {
104 // Add handlers for keys to expand/collapse the picker
105 me.keyNav = Ext.create('Ext.util.KeyNav', me.inputEl, {
107 if (!me.isExpanded) {
108 // Don't call expand() directly as there may be additional processing involved before
109 // expanding, e.g. in the case of a ComboBox query.
118 // Non-editable allows opening the picker by clicking the field
120 me.mon(me.inputEl, 'click', me.onTriggerClick, me);
123 // Disable native browser autocomplete
125 me.inputEl.dom.setAttribute('autocomplete', 'off');
131 * Expands this field's picker dropdown.
135 bodyEl, picker, collapseIf;
137 if (me.rendered && !me.isExpanded && !me.isDestroyed) {
139 picker = me.getPicker();
140 collapseIf = me.collapseIf;
142 // show the picker and set isExpanded flag
144 me.isExpanded = true;
146 bodyEl.addCls(me.openCls);
148 // monitor clicking and mousewheel
149 me.mon(Ext.getDoc(), {
150 mousewheel: collapseIf,
151 mousedown: collapseIf,
154 Ext.EventManager.onWindowResize(me.alignPicker, me);
155 me.fireEvent('expand', me);
160 onExpand: Ext.emptyFn,
163 * Aligns the picker to the input element
166 alignPicker: function() {
171 picker = me.getPicker();
172 if (me.matchFieldWidth) {
173 // Auto the height (it will be constrained by min and max width) unless there are no records to display.
174 picker.setSize(me.bodyEl.getWidth(), picker.store && picker.store.getCount() ? null : 0);
176 if (picker.isFloating()) {
183 * Performs the alignment on the picker using the class defaults
192 me.picker.alignTo(me.inputEl, me.pickerAlign, me.pickerOffset);
193 // add the {openCls}-above class if the picker was aligned above
194 // the field due to hitting the bottom of the viewport
195 isAbove = picker.el.getY() < me.inputEl.getY();
196 me.bodyEl[isAbove ? 'addCls' : 'removeCls'](me.openCls + aboveSfx);
197 picker[isAbove ? 'addCls' : 'removeCls'](picker.baseCls + aboveSfx);
201 * Collapses this field's picker dropdown.
203 collapse: function() {
204 if (this.isExpanded && !this.isDestroyed) {
206 openCls = me.openCls,
209 collapseIf = me.collapseIf,
212 // hide the picker and set isExpanded flag
214 me.isExpanded = false;
216 // remove the openCls
217 me.bodyEl.removeCls([openCls, openCls + aboveSfx]);
218 picker.el.removeCls(picker.baseCls + aboveSfx);
220 // remove event listeners
221 doc.un('mousewheel', collapseIf, me);
222 doc.un('mousedown', collapseIf, me);
223 Ext.EventManager.removeResizeListener(me.alignPicker, me);
224 me.fireEvent('collapse', me);
229 onCollapse: Ext.emptyFn,
234 * Runs on mousewheel and mousedown of doc to check to see if we should collapse the picker
236 collapseIf: function(e) {
238 if (!me.isDestroyed && !e.within(me.bodyEl, false, true) && !e.within(me.picker.el, false, true)) {
244 * Returns a reference to the picker component for this field, creating it if necessary by
245 * calling {@link #createPicker}.
246 * @return {Ext.Component} The picker component
248 getPicker: function() {
250 return me.picker || (me.picker = me.createPicker());
255 * Creates and returns the component to be used as this field's picker. Must be implemented by subclasses of Picker.
256 * The current field should also be passed as a configuration option to the picker component as the pickerField
259 createPicker: Ext.emptyFn,
262 * Handles the trigger click; by default toggles between expanding and collapsing the picker component.
265 onTriggerClick: function() {
267 if (!me.readOnly && !me.disabled) {
277 mimicBlur: function(e) {
280 // ignore mousedown events within the picker element
281 if (!picker || !e.within(picker.el, false, true)) {
282 me.callParent(arguments);
286 onDestroy : function(){
290 Ext.EventManager.removeResizeListener(me.alignPicker, me);
291 Ext.destroy(me.keyNav);
293 delete picker.pickerField;