--- /dev/null
+/**
+ * @class Ext.ux.grid.menu.RangeMenu
+ * @extends Ext.menu.Menu
+ * Custom implementation of {@link Ext.menu.Menu} that has preconfigured items for entering numeric
+ * range comparison values: less-than, greater-than, and equal-to. This is used internally
+ * by {@link Ext.ux.grid.filter.NumericFilter} to create its menu.
+ */
+Ext.define('Ext.ux.grid.menu.RangeMenu', {
+ extend: 'Ext.menu.Menu',
+
+ /**
+ * @cfg {String} fieldCls
+ * The Class to use to construct each field item within this menu
+ * Defaults to:<pre>
+ * fieldCls : Ext.form.field.Number
+ * </pre>
+ */
+ fieldCls : 'Ext.form.field.Number',
+
+ /**
+ * @cfg {Object} fieldCfg
+ * The default configuration options for any field item unless superseded
+ * by the <code>{@link #fields}</code> configuration.
+ * Defaults to:<pre>
+ * fieldCfg : {}
+ * </pre>
+ * Example usage:
+ * <pre><code>
+fieldCfg : {
+ width: 150,
+},
+ * </code></pre>
+ */
+
+ /**
+ * @cfg {Object} fields
+ * The field items may be configured individually
+ * Defaults to <tt>undefined</tt>.
+ * Example usage:
+ * <pre><code>
+fields : {
+ gt: { // override fieldCfg options
+ width: 200,
+ fieldCls: Ext.ux.form.CustomNumberField // to override default {@link #fieldCls}
+ }
+},
+ * </code></pre>
+ */
+
+ /**
+ * @cfg {Object} iconCls
+ * The iconCls to be applied to each comparator field item.
+ * Defaults to:<pre>
+iconCls : {
+ gt : 'ux-rangemenu-gt',
+ lt : 'ux-rangemenu-lt',
+ eq : 'ux-rangemenu-eq'
+}
+ * </pre>
+ */
+ iconCls : {
+ gt : 'ux-rangemenu-gt',
+ lt : 'ux-rangemenu-lt',
+ eq : 'ux-rangemenu-eq'
+ },
+
+ /**
+ * @cfg {Object} fieldLabels
+ * Accessible label text for each comparator field item. Can be overridden by localization
+ * files. Defaults to:<pre>
+fieldLabels : {
+ gt: 'Greater Than',
+ lt: 'Less Than',
+ eq: 'Equal To'
+}</pre>
+ */
+ fieldLabels: {
+ gt: 'Greater Than',
+ lt: 'Less Than',
+ eq: 'Equal To'
+ },
+
+ /**
+ * @cfg {Object} menuItemCfgs
+ * Default configuration options for each menu item
+ * Defaults to:<pre>
+menuItemCfgs : {
+ emptyText: 'Enter Filter Text...',
+ selectOnFocus: true,
+ width: 125
+}
+ * </pre>
+ */
+ menuItemCfgs : {
+ emptyText: 'Enter Number...',
+ selectOnFocus: false,
+ width: 155
+ },
+
+ /**
+ * @cfg {Array} menuItems
+ * The items to be shown in this menu. Items are added to the menu
+ * according to their position within this array. Defaults to:<pre>
+ * menuItems : ['lt','gt','-','eq']
+ * </pre>
+ */
+ menuItems : ['lt', 'gt', '-', 'eq'],
+
+
+ constructor : function (config) {
+ var me = this,
+ fields, fieldCfg, i, len, item, cfg, Cls;
+
+ me.callParent(arguments);
+
+ fields = me.fields = me.fields || {};
+ fieldCfg = me.fieldCfg = me.fieldCfg || {};
+
+ me.addEvents(
+ /**
+ * @event update
+ * Fires when a filter configuration has changed
+ * @param {Ext.ux.grid.filter.Filter} this The filter object.
+ */
+ 'update'
+ );
+
+ me.updateTask = Ext.create('Ext.util.DelayedTask', me.fireUpdate, me);
+
+ for (i = 0, len = me.menuItems.length; i < len; i++) {
+ item = me.menuItems[i];
+ if (item !== '-') {
+ // defaults
+ cfg = {
+ itemId: 'range-' + item,
+ enableKeyEvents: true,
+ hideLabel: false,
+ fieldLabel: me.iconTpl.apply({
+ cls: me.iconCls[item] || 'no-icon',
+ text: me.fieldLabels[item] || '',
+ src: Ext.BLANK_IMAGE_URL
+ }),
+ labelSeparator: '',
+ labelWidth: 29,
+ listeners: {
+ scope: me,
+ change: me.onInputChange,
+ keyup: me.onInputKeyUp,
+ el: {
+ click: function(e) {
+ e.stopPropagation();
+ }
+ }
+ },
+ activate: Ext.emptyFn,
+ deactivate: Ext.emptyFn
+ };
+ Ext.apply(
+ cfg,
+ // custom configs
+ Ext.applyIf(fields[item] || {}, fieldCfg[item]),
+ // configurable defaults
+ me.menuItemCfgs
+ );
+ Cls = cfg.fieldCls || me.fieldCls;
+ item = fields[item] = Ext.create(Cls, cfg);
+ }
+ me.add(item);
+ }
+ },
+
+ /**
+ * @private
+ * called by this.updateTask
+ */
+ fireUpdate : function () {
+ this.fireEvent('update', this);
+ },
+
+ /**
+ * Get and return the value of the filter.
+ * @return {String} The value of this filter
+ */
+ getValue : function () {
+ var result = {}, key, field;
+ for (key in this.fields) {
+ field = this.fields[key];
+ if (field.isValid() && field.getValue() !== null) {
+ result[key] = field.getValue();
+ }
+ }
+ return result;
+ },
+
+ /**
+ * Set the value of this menu and fires the 'update' event.
+ * @param {Object} data The data to assign to this menu
+ */
+ setValue : function (data) {
+ var key;
+ for (key in this.fields) {
+ this.fields[key].setValue(key in data ? data[key] : '');
+ }
+ this.fireEvent('update', this);
+ },
+
+ /**
+ * @private
+ * Handler method called when there is a keyup event on an input
+ * item of this menu.
+ */
+ onInputKeyUp: function(field, e) {
+ if (e.getKey() === e.RETURN && field.isValid()) {
+ e.stopEvent();
+ this.hide();
+ }
+ },
+
+ /**
+ * @private
+ * Handler method called when the user changes the value of one of the input
+ * items in this menu.
+ */
+ onInputChange: function(field) {
+ var me = this,
+ fields = me.fields,
+ eq = fields.eq,
+ gt = fields.gt,
+ lt = fields.lt;
+
+ if (field == eq) {
+ if (gt) {
+ gt.setValue(null);
+ }
+ if (lt) {
+ lt.setValue(null);
+ }
+ }
+ else {
+ eq.setValue(null);
+ }
+
+ // restart the timer
+ this.updateTask.delay(this.updateBuffer);
+ }
+}, function() {
+
+ /**
+ * @cfg {Ext.XTemplate} iconTpl
+ * A template for generating the label for each field in the menu
+ */
+ this.prototype.iconTpl = Ext.create('Ext.XTemplate',
+ '<img src="{src}" alt="{text}" class="' + Ext.baseCSSPrefix + 'menu-item-icon ux-rangemenu-icon {cls}" />'
+ );
+
+});