Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / examples / ux / grid / menu / RangeMenu.js
diff --git a/examples/ux/grid/menu/RangeMenu.js b/examples/ux/grid/menu/RangeMenu.js
new file mode 100644 (file)
index 0000000..0130a9e
--- /dev/null
@@ -0,0 +1,256 @@
+/**
+ * @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}" />'
+    );
+
+});