2 * Ext JS Library 2.2.1
\r
3 * Copyright(c) 2006-2009, Ext JS, LLC.
\r
4 * licensing@extjs.com
\r
6 * http://extjs.com/license
\r
9 Ext.grid.GridFilters = function(config){
\r
10 this.filters = new Ext.util.MixedCollection();
\r
11 this.filters.getKey = function(o) {return o ? o.dataIndex : null};
\r
13 for(var i=0, len=config.filters.length; i<len; i++) {
\r
14 this.addFilter(config.filters[i]);
\r
17 this.deferredUpdate = new Ext.util.DelayedTask(this.reload, this);
\r
19 delete config.filters;
\r
20 Ext.apply(this, config);
\r
22 Ext.extend(Ext.grid.GridFilters, Ext.util.Observable, {
\r
24 * @cfg {Integer} updateBuffer
\r
25 * Number of milisecond to defer store updates since the last filter change.
\r
29 * @cfg {String} paramPrefix
\r
30 * The url parameter prefix for the filters.
\r
32 paramPrefix: 'filter',
\r
34 * @cfg {String} fitlerCls
\r
35 * The css class to be applied to column headers that active filters. Defaults to 'ux-filterd-column'
\r
37 filterCls: 'ux-filtered-column',
\r
39 * @cfg {Boolean} local
\r
40 * True to use Ext.data.Store filter functions instead of server side filtering.
\r
44 * @cfg {Boolean} autoReload
\r
45 * True to automagicly reload the datasource when a filter change happens.
\r
49 * @cfg {String} stateId
\r
50 * Name of the Ext.data.Store value to be used to store state information.
\r
54 * @cfg {Boolean} showMenu
\r
55 * True to show the filter menus
\r
59 * @cfg {String} filtersText
\r
60 * The text displayed for the "Filters" menu item
\r
62 filtersText: 'Filters',
\r
64 init: function(grid){
\r
65 if(grid instanceof Ext.grid.GridPanel){
\r
68 this.store = this.grid.getStore();
\r
70 this.store.on('load', function(store) {
\r
71 store.filterBy(this.getRecordFilter());
\r
74 this.store.on('beforeload', this.onBeforeLoad, this);
\r
77 this.grid.filters = this;
\r
79 this.grid.addEvents('filterupdate');
\r
81 grid.on("render", this.onRender, this);
\r
82 grid.on("beforestaterestore", this.applyState, this);
\r
83 grid.on("beforestatesave", this.saveState, this);
\r
85 } else if(grid instanceof Ext.PagingToolbar) {
\r
86 this.toolbar = grid;
\r
91 applyState: function(grid, state) {
\r
92 this.suspendStateStore = true;
\r
93 this.clearFilters();
\r
95 for(var key in state.filters) {
\r
96 var filter = this.filters.get(key);
\r
98 filter.setValue(state.filters[key]);
\r
99 filter.setActive(true);
\r
104 this.deferredUpdate.cancel();
\r
109 this.suspendStateStore = false;
\r
113 saveState: function(grid, state){
\r
115 this.filters.each(function(filter) {
\r
116 if(filter.active) {
\r
117 filters[filter.dataIndex] = filter.getValue();
\r
120 return state.filters = filters;
\r
124 onRender: function(){
\r
127 if(this.showMenu) {
\r
128 hmenu = this.grid.getView().hmenu;
\r
130 this.sep = hmenu.addSeparator();
\r
131 this.menu = hmenu.add(new Ext.menu.CheckItem({
\r
132 text: this.filtersText,
\r
133 menu: new Ext.menu.Menu()
\r
135 this.menu.on('checkchange', this.onCheckChange, this);
\r
136 this.menu.on('beforecheckchange', this.onBeforeCheck, this);
\r
138 hmenu.on('beforeshow', this.onMenu, this);
\r
141 this.grid.getView().on("refresh", this.onRefresh, this);
\r
142 this.updateColumnHeadings(this.grid.getView());
\r
146 onMenu: function(filterMenu) {
\r
147 var filter = this.getMenuFilter();
\r
149 this.menu.menu = filter.menu;
\r
150 this.menu.setChecked(filter.active, false);
\r
153 this.menu.setVisible(filter !== undefined);
\r
154 this.sep.setVisible(filter !== undefined);
\r
158 onCheckChange: function(item, value) {
\r
159 this.getMenuFilter().setActive(value);
\r
163 onBeforeCheck: function(check, value) {
\r
164 return !value || this.getMenuFilter().isActivatable();
\r
168 onStateChange: function(event, filter) {
\r
169 if(event == "serialize") {
\r
173 if(filter == this.getMenuFilter()) {
\r
174 this.menu.setChecked(filter.active, false);
\r
177 if(this.autoReload || this.local) {
\r
178 this.deferredUpdate.delay(this.updateBuffer);
\r
181 var view = this.grid.getView();
\r
182 this.updateColumnHeadings(view);
\r
184 this.grid.saveState();
\r
186 this.grid.fireEvent('filterupdate', this, filter);
\r
190 onBeforeLoad: function(store, options) {
\r
191 options.params = options.params || {};
\r
192 this.cleanParams(options.params);
\r
193 var params = this.buildQuery(this.getFilterData());
\r
194 Ext.apply(options.params, params);
\r
198 onRefresh: function(view) {
\r
199 this.updateColumnHeadings(view);
\r
203 getMenuFilter: function() {
\r
204 var view = this.grid.getView();
\r
205 if(!view || view.hdCtxIndex === undefined) {
\r
209 return this.filters.get(view.cm.config[view.hdCtxIndex].dataIndex);
\r
213 updateColumnHeadings: function(view) {
\r
214 if(!view || !view.mainHd) {
\r
218 var hds = view.mainHd.select('td').removeClass(this.filterCls);
\r
219 for(var i=0, len=view.cm.config.length; i<len; i++) {
\r
220 var filter = this.getFilter(view.cm.config[i].dataIndex);
\r
221 if(filter && filter.active) {
\r
222 hds.item(i).addClass(this.filterCls);
\r
228 reload: function() {
\r
230 this.grid.store.clearFilter(true);
\r
231 this.grid.store.filterBy(this.getRecordFilter());
\r
233 this.deferredUpdate.cancel();
\r
234 var store = this.grid.store;
\r
236 var start = this.toolbar.paramNames.start;
\r
237 if(store.lastOptions && store.lastOptions.params && store.lastOptions.params[start]) {
\r
238 store.lastOptions.params[start] = 0;
\r
246 * Method factory that generates a record validator for the filters active at the time
\r
251 getRecordFilter: function() {
\r
253 this.filters.each(function(filter) {
\r
254 if(filter.active) {
\r
259 var len = f.length;
\r
260 return function(record) {
\r
261 for(var i=0; i<len; i++) {
\r
262 if(!f[i].validateRecord(record)) {
\r
271 * Adds a filter to the collection.
\r
273 * @param {Object/Ext.grid.filter.Filter} config A filter configuration or a filter object.
\r
275 * @return {Ext.grid.filter.Filter} The existing or newly created filter object.
\r
277 addFilter: function(config) {
\r
278 var filter = config.menu ? config : new (this.getFilterClass(config.type))(config);
\r
279 this.filters.add(filter);
\r
281 Ext.util.Observable.capture(filter, this.onStateChange, this);
\r
286 * Returns a filter for the given dataIndex, if on exists.
\r
288 * @param {String} dataIndex The dataIndex of the desired filter object.
\r
290 * @return {Ext.grid.filter.Filter}
\r
292 getFilter: function(dataIndex){
\r
293 return this.filters.get(dataIndex);
\r
297 * Turns all filters off. This does not clear the configuration information.
\r
299 clearFilters: function() {
\r
300 this.filters.each(function(filter) {
\r
301 filter.setActive(false);
\r
306 getFilterData: function() {
\r
309 this.filters.each(function(f) {
\r
311 var d = [].concat(f.serialize());
\r
312 for(var i=0, len=d.length; i<len; i++) {
\r
313 filters.push({field: f.dataIndex, data: d[i]});
\r
322 * Function to take structured filter data and 'flatten' it into query parameteres. The default function
\r
323 * will produce a query string of the form:
\r
324 * filters[0][field]=dataIndex&filters[0][data][param1]=param&filters[0][data][param2]=param...
\r
326 * @param {Array} filters A collection of objects representing active filters and their configuration.
\r
327 * Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured
\r
328 * to be unique as any one filter may be a composite of more basic filters for the same dataIndex.
\r
330 * @return {Object} Query keys and values
\r
332 buildQuery: function(filters) {
\r
334 for(var i=0, len=filters.length; i<len; i++) {
\r
335 var f = filters[i];
\r
336 var root = [this.paramPrefix, '[', i, ']'].join('');
\r
337 p[root + '[field]'] = f.field;
\r
339 var dataPrefix = root + '[data]';
\r
340 for(var key in f.data) {
\r
341 p[[dataPrefix, '[', key, ']'].join('')] = f.data[key];
\r
349 * Removes filter related query parameters from the provided object.
\r
351 * @param {Object} p Query parameters that may contain filter related fields.
\r
353 cleanParams: function(p) {
\r
354 var regex = new RegExp("^" + this.paramPrefix + "\[[0-9]+\]");
\r
355 for(var key in p) {
\r
356 if(regex.test(key)) {
\r
363 * Function for locating filter classes, overwrite this with your favorite
\r
364 * loader to provide dynamic filter loading.
\r
366 * @param {String} type The type of filter to load.
\r
370 getFilterClass: function(type){
\r
371 return Ext.grid.filter[type.substr(0, 1).toUpperCase() + type.substr(1) + 'Filter'];
\r