RangeMenu.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /**
  2. * @class Ext.ux.grid.menu.RangeMenu
  3. * @extends Ext.menu.Menu
  4. * Custom implementation of {@link Ext.menu.Menu} that has preconfigured items for entering numeric
  5. * range comparison values: less-than, greater-than, and equal-to. This is used internally
  6. * by {@link Ext.ux.grid.filter.NumericFilter} to create its menu.
  7. */
  8. Ext.define('Ext.ux.grid.menu.RangeMenu', {
  9. extend: 'Ext.menu.Menu',
  10. /**
  11. * @cfg {String} fieldCls
  12. * The Class to use to construct each field item within this menu
  13. * Defaults to:<pre>
  14. * fieldCls : Ext.form.field.Number
  15. * </pre>
  16. */
  17. fieldCls : 'Ext.form.field.Number',
  18. /**
  19. * @cfg {Object} fieldCfg
  20. * The default configuration options for any field item unless superseded
  21. * by the <code>{@link #fields}</code> configuration.
  22. * Defaults to:<pre>
  23. * fieldCfg : {}
  24. * </pre>
  25. * Example usage:
  26. * <pre><code>
  27. fieldCfg : {
  28. width: 150,
  29. },
  30. * </code></pre>
  31. */
  32. /**
  33. * @cfg {Object} fields
  34. * The field items may be configured individually
  35. * Defaults to <tt>undefined</tt>.
  36. * Example usage:
  37. * <pre><code>
  38. fields : {
  39. gt: { // override fieldCfg options
  40. width: 200,
  41. fieldCls: Ext.ux.form.CustomNumberField // to override default {@link #fieldCls}
  42. }
  43. },
  44. * </code></pre>
  45. */
  46. /**
  47. * @cfg {Object} iconCls
  48. * The iconCls to be applied to each comparator field item.
  49. * Defaults to:<pre>
  50. iconCls : {
  51. gt : 'ux-rangemenu-gt',
  52. lt : 'ux-rangemenu-lt',
  53. eq : 'ux-rangemenu-eq'
  54. }
  55. * </pre>
  56. */
  57. iconCls : {
  58. gt : 'ux-rangemenu-gt',
  59. lt : 'ux-rangemenu-lt',
  60. eq : 'ux-rangemenu-eq'
  61. },
  62. /**
  63. * @cfg {Object} fieldLabels
  64. * Accessible label text for each comparator field item. Can be overridden by localization
  65. * files. Defaults to:<pre>
  66. fieldLabels : {
  67. gt: 'Greater Than',
  68. lt: 'Less Than',
  69. eq: 'Equal To'
  70. }</pre>
  71. */
  72. fieldLabels: {
  73. gt: 'Greater Than',
  74. lt: 'Less Than',
  75. eq: 'Equal To'
  76. },
  77. /**
  78. * @cfg {Object} menuItemCfgs
  79. * Default configuration options for each menu item
  80. * Defaults to:<pre>
  81. menuItemCfgs : {
  82. emptyText: 'Enter Filter Text...',
  83. selectOnFocus: true,
  84. width: 125
  85. }
  86. * </pre>
  87. */
  88. menuItemCfgs : {
  89. emptyText: 'Enter Number...',
  90. selectOnFocus: false,
  91. width: 155
  92. },
  93. /**
  94. * @cfg {Array} menuItems
  95. * The items to be shown in this menu. Items are added to the menu
  96. * according to their position within this array. Defaults to:<pre>
  97. * menuItems : ['lt','gt','-','eq']
  98. * </pre>
  99. */
  100. menuItems : ['lt', 'gt', '-', 'eq'],
  101. constructor : function (config) {
  102. var me = this,
  103. fields, fieldCfg, i, len, item, cfg, Cls;
  104. me.callParent(arguments);
  105. fields = me.fields = me.fields || {};
  106. fieldCfg = me.fieldCfg = me.fieldCfg || {};
  107. me.addEvents(
  108. /**
  109. * @event update
  110. * Fires when a filter configuration has changed
  111. * @param {Ext.ux.grid.filter.Filter} this The filter object.
  112. */
  113. 'update'
  114. );
  115. me.updateTask = Ext.create('Ext.util.DelayedTask', me.fireUpdate, me);
  116. for (i = 0, len = me.menuItems.length; i < len; i++) {
  117. item = me.menuItems[i];
  118. if (item !== '-') {
  119. // defaults
  120. cfg = {
  121. itemId: 'range-' + item,
  122. enableKeyEvents: true,
  123. hideLabel: false,
  124. fieldLabel: me.iconTpl.apply({
  125. cls: me.iconCls[item] || 'no-icon',
  126. text: me.fieldLabels[item] || '',
  127. src: Ext.BLANK_IMAGE_URL
  128. }),
  129. labelSeparator: '',
  130. labelWidth: 29,
  131. labelStyle: 'position: relative;',
  132. listeners: {
  133. scope: me,
  134. change: me.onInputChange,
  135. keyup: me.onInputKeyUp,
  136. el: {
  137. click: function(e) {
  138. e.stopPropagation();
  139. }
  140. }
  141. },
  142. activate: Ext.emptyFn,
  143. deactivate: Ext.emptyFn
  144. };
  145. Ext.apply(
  146. cfg,
  147. // custom configs
  148. Ext.applyIf(fields[item] || {}, fieldCfg[item]),
  149. // configurable defaults
  150. me.menuItemCfgs
  151. );
  152. Cls = cfg.fieldCls || me.fieldCls;
  153. item = fields[item] = Ext.create(Cls, cfg);
  154. }
  155. me.add(item);
  156. }
  157. },
  158. /**
  159. * @private
  160. * called by this.updateTask
  161. */
  162. fireUpdate : function () {
  163. this.fireEvent('update', this);
  164. },
  165. /**
  166. * Get and return the value of the filter.
  167. * @return {String} The value of this filter
  168. */
  169. getValue : function () {
  170. var result = {}, key, field;
  171. for (key in this.fields) {
  172. field = this.fields[key];
  173. if (field.isValid() && field.getValue() !== null) {
  174. result[key] = field.getValue();
  175. }
  176. }
  177. return result;
  178. },
  179. /**
  180. * Set the value of this menu and fires the 'update' event.
  181. * @param {Object} data The data to assign to this menu
  182. */
  183. setValue : function (data) {
  184. var me = this,
  185. key,
  186. field;
  187. for (key in me.fields) {
  188. // Prevent field's change event from tiggering a Store filter. The final upate event will do that
  189. field = me.fields[key];
  190. field.suspendEvents();
  191. field.setValue(key in data ? data[key] : '');
  192. field.resumeEvents();
  193. }
  194. // Trigger the filering of the Store
  195. me.fireEvent('update', me);
  196. },
  197. /**
  198. * @private
  199. * Handler method called when there is a keyup event on an input
  200. * item of this menu.
  201. */
  202. onInputKeyUp: function(field, e) {
  203. if (e.getKey() === e.RETURN && field.isValid()) {
  204. e.stopEvent();
  205. this.hide();
  206. }
  207. },
  208. /**
  209. * @private
  210. * Handler method called when the user changes the value of one of the input
  211. * items in this menu.
  212. */
  213. onInputChange: function(field) {
  214. var me = this,
  215. fields = me.fields,
  216. eq = fields.eq,
  217. gt = fields.gt,
  218. lt = fields.lt;
  219. if (field == eq) {
  220. if (gt) {
  221. gt.setValue(null);
  222. }
  223. if (lt) {
  224. lt.setValue(null);
  225. }
  226. }
  227. else {
  228. eq.setValue(null);
  229. }
  230. // restart the timer
  231. this.updateTask.delay(this.updateBuffer);
  232. }
  233. }, function() {
  234. /**
  235. * @cfg {Ext.XTemplate} iconTpl
  236. * A template for generating the label for each field in the menu
  237. */
  238. this.prototype.iconTpl = Ext.create('Ext.XTemplate',
  239. '<img src="{src}" alt="{text}" class="' + Ext.baseCSSPrefix + 'menu-item-icon ux-rangemenu-icon {cls}" />'
  240. );
  241. });