Commit cc806102ee31daab4943cdf5117630a49e393f00
1 parent
a443efbf
Exists in
minimize
Fix errors detected by sencha cmd
Showing
34 changed files
with
3036 additions
and
1178 deletions
Show diff stats
js/app/controllers/SampModule.js
js/app/models/DerivedParamNode.js
@@ -36,7 +36,7 @@ Ext.define('amdaModel.DerivedParamComponentNode', { | @@ -36,7 +36,7 @@ Ext.define('amdaModel.DerivedParamComponentNode', { | ||
36 | }, | 36 | }, |
37 | getAllContextMenuItems: function(){ | 37 | getAllContextMenuItems: function(){ |
38 | return this.localMenuItems (); | 38 | return this.localMenuItems (); |
39 | -}, | 39 | +} |
40 | }); | 40 | }); |
41 | 41 | ||
42 | Ext.define('amdaModel.DerivedParamNode', { | 42 | Ext.define('amdaModel.DerivedParamNode', { |
js/app/models/FilterDef.js
@@ -82,7 +82,7 @@ Ext.define('amdaModel.FilterDef', { | @@ -82,7 +82,7 @@ Ext.define('amdaModel.FilterDef', { | ||
82 | reader: | 82 | reader: |
83 | { | 83 | { |
84 | type: 'json', | 84 | type: 'json', |
85 | - root: 'filters', | 85 | + root: 'filters' |
86 | }, | 86 | }, |
87 | writer: new Ext.data.JsonWriter({ | 87 | writer: new Ext.data.JsonWriter({ |
88 | encode: false, | 88 | encode: false, |
@@ -116,4 +116,4 @@ Ext.define('amdaModel.FilterDef', { | @@ -116,4 +116,4 @@ Ext.define('amdaModel.FilterDef', { | ||
116 | } | 116 | } |
117 | }) | 117 | }) |
118 | } | 118 | } |
119 | -}); | ||
120 | \ No newline at end of file | 119 | \ No newline at end of file |
120 | +}); |
js/app/models/FilterInfo.js
@@ -157,7 +157,7 @@ Ext.define('amdaModel.FilterInfo', { | @@ -157,7 +157,7 @@ Ext.define('amdaModel.FilterInfo', { | ||
157 | 157 | ||
158 | fields : [ | 158 | fields : [ |
159 | {name: 'id', mapping: '@id', type:'string'}, | 159 | {name: 'id', mapping: '@id', type:'string'}, |
160 | - {name: 'name', mapping: '@name', type:'string'}, | 160 | + {name: 'name', mapping: '@name', type:'string'} |
161 | ], | 161 | ], |
162 | 162 | ||
163 | hasMany : { | 163 | hasMany : { |
@@ -175,4 +175,4 @@ Ext.define('amdaModel.FilterInfo', { | @@ -175,4 +175,4 @@ Ext.define('amdaModel.FilterInfo', { | ||
175 | record: 'filter' | 175 | record: 'filter' |
176 | } | 176 | } |
177 | } | 177 | } |
178 | - }); | ||
179 | \ No newline at end of file | 178 | \ No newline at end of file |
179 | + }); |
js/app/models/PlotObjects/PlotBaseSerieObject.js
@@ -66,7 +66,7 @@ Ext.define('amdaPlotObj.PlotBaseSerieObject', { | @@ -66,7 +66,7 @@ Ext.define('amdaPlotObj.PlotBaseSerieObject', { | ||
66 | {name: 'serie-intervaltick-font-name', type: 'string'}, | 66 | {name: 'serie-intervaltick-font-name', type: 'string'}, |
67 | {name: 'serie-intervaltick-font-size', type: 'int'}, | 67 | {name: 'serie-intervaltick-font-size', type: 'int'}, |
68 | {name: 'serie-intervaltick-font-bold', type: 'boolean'}, | 68 | {name: 'serie-intervaltick-font-bold', type: 'boolean'}, |
69 | - {name: 'serie-intervaltick-font-italic', type: 'boolean'}, | 69 | + {name: 'serie-intervaltick-font-italic', type: 'boolean'} |
70 | ], | 70 | ], |
71 | 71 | ||
72 | constructor: function(){ | 72 | constructor: function(){ |
js/app/models/PlotTabNode.js
js/app/models/RequestParamObject.js
@@ -37,7 +37,7 @@ Ext.define('amdaModel.RequestParamObject', { | @@ -37,7 +37,7 @@ Ext.define('amdaModel.RequestParamObject', { | ||
37 | 'dim2-max-index': 0, | 37 | 'dim2-max-index': 0, |
38 | 'template_args': {} | 38 | 'template_args': {} |
39 | }; | 39 | }; |
40 | - }, | 40 | + } |
41 | }, | 41 | }, |
42 | 42 | ||
43 | idProperty: 'id', | 43 | idProperty: 'id', |
js/app/views/FiltersUI.js
@@ -523,7 +523,7 @@ Ext.define('amdaUI.FilterGridPanel', { | @@ -523,7 +523,7 @@ Ext.define('amdaUI.FilterGridPanel', { | ||
523 | viewConfig: { | 523 | viewConfig: { |
524 | getRowClass: function(record, rowIndex, rowParams, store){ | 524 | getRowClass: function(record, rowIndex, rowParams, store){ |
525 | if (record.get('index') == -1) return 'x-hide-display'; | 525 | if (record.get('index') == -1) return 'x-hide-display'; |
526 | - }, | 526 | + } |
527 | }, | 527 | }, |
528 | 528 | ||
529 | listeners : { | 529 | listeners : { |
@@ -1143,4 +1143,4 @@ Ext.define('amdaUI.FiltersUI', { | @@ -1143,4 +1143,4 @@ Ext.define('amdaUI.FiltersUI', { | ||
1143 | } | 1143 | } |
1144 | }); | 1144 | }); |
1145 | } | 1145 | } |
1146 | -}); | ||
1147 | \ No newline at end of file | 1146 | \ No newline at end of file |
1147 | +}); |
js/app/views/ParamArgumentsUI.js
@@ -31,7 +31,7 @@ Ext.define('amdaUI.ParamArgumentsUI', { | @@ -31,7 +31,7 @@ Ext.define('amdaUI.ParamArgumentsUI', { | ||
31 | layout: { | 31 | layout: { |
32 | type: 'vbox', | 32 | type: 'vbox', |
33 | align: 'stretch' | 33 | align: 'stretch' |
34 | - }, | 34 | + } |
35 | }; | 35 | }; |
36 | 36 | ||
37 | Ext.apply (this , Ext.apply (arguments, myConf)); | 37 | Ext.apply (this , Ext.apply (arguments, myConf)); |
js/app/views/PlotComponents/PlotLegendSeriesForm.js
@@ -22,7 +22,7 @@ Ext.define('amdaPlotComp.PlotLegendSeriesForm', { | @@ -22,7 +22,7 @@ Ext.define('amdaPlotComp.PlotLegendSeriesForm', { | ||
22 | 22 | ||
23 | getFormItems: function() { | 23 | getFormItems: function() { |
24 | var borderItems = [ | 24 | var borderItems = [ |
25 | - this.addStandardColor('legend-series-border-color', 'Border Color', amdaPlotObj.PlotObjectConfig.availableColors), | 25 | + this.addStandardColor('legend-series-border-color', 'Border Color', amdaPlotObj.PlotObjectConfig.availableColors) |
26 | ]; | 26 | ]; |
27 | 27 | ||
28 | var intervalInfoItems = [ | 28 | var intervalInfoItems = [ |
@@ -48,4 +48,4 @@ Ext.define('amdaPlotComp.PlotLegendSeriesForm', { | @@ -48,4 +48,4 @@ Ext.define('amdaPlotComp.PlotLegendSeriesForm', { | ||
48 | }) | 48 | }) |
49 | ]; | 49 | ]; |
50 | } | 50 | } |
51 | -}); | ||
52 | \ No newline at end of file | 51 | \ No newline at end of file |
52 | +}); |
js/app/views/PlotComponents/PlotOrbitSerieForm.js
@@ -20,7 +20,7 @@ Ext.define('amdaPlotComp.PlotOrbitSerieForm', { | @@ -20,7 +20,7 @@ Ext.define('amdaPlotComp.PlotOrbitSerieForm', { | ||
20 | this.addStandardCombo('serie-projection', 'Projection', amdaPlotObj.PlotObjectConfig.availableOrbitSerieProjections, function(name, value, oldValue) { | 20 | this.addStandardCombo('serie-projection', 'Projection', amdaPlotObj.PlotObjectConfig.availableOrbitSerieProjections, function(name, value, oldValue) { |
21 | me.object.set('serie-projection', value); | 21 | me.object.set('serie-projection', value); |
22 | me.crtTree.refresh(); | 22 | me.crtTree.refresh(); |
23 | - }), | 23 | + }) |
24 | ]; | 24 | ]; |
25 | 25 | ||
26 | Ext.each(baseSerieItems, function(item) { | 26 | Ext.each(baseSerieItems, function(item) { |
@@ -29,4 +29,4 @@ Ext.define('amdaPlotComp.PlotOrbitSerieForm', { | @@ -29,4 +29,4 @@ Ext.define('amdaPlotComp.PlotOrbitSerieForm', { | ||
29 | 29 | ||
30 | return orbitSerieItems; | 30 | return orbitSerieItems; |
31 | } | 31 | } |
32 | -}); | ||
33 | \ No newline at end of file | 32 | \ No newline at end of file |
33 | +}); |
js/app/views/PlotUI.js
@@ -263,7 +263,7 @@ Ext.define('amdaUI.PlotUI', { | @@ -263,7 +263,7 @@ Ext.define('amdaUI.PlotUI', { | ||
263 | }); | 263 | }); |
264 | }, | 264 | }, |
265 | 265 | ||
266 | - savePlotRequest : function(allTabs = false) { | 266 | + savePlotRequest : function(allTabs) { |
267 | var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | 267 | var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); |
268 | if (!plotModule) | 268 | if (!plotModule) |
269 | return; | 269 | return; |
@@ -425,7 +425,7 @@ Ext.define('amdaUI.PlotUI', { | @@ -425,7 +425,7 @@ Ext.define('amdaUI.PlotUI', { | ||
425 | handler: function() { | 425 | handler: function() { |
426 | this.savePlotRequest(false); | 426 | this.savePlotRequest(false); |
427 | } | 427 | } |
428 | - }, | 428 | + } |
429 | ] | 429 | ] |
430 | }, | 430 | }, |
431 | scope: this, | 431 | scope: this, |
js/app/views/ResourcesMgrUI.js
@@ -309,7 +309,7 @@ Ext.define('amdaUI.ResourcesMgrUI', { | @@ -309,7 +309,7 @@ Ext.define('amdaUI.ResourcesMgrUI', { | ||
309 | icon: 'js/resources/images/32x32/1309360076_misc_22.png', | 309 | icon: 'js/resources/images/32x32/1309360076_misc_22.png', |
310 | width: 32, | 310 | width: 32, |
311 | heigth: 32, | 311 | heigth: 32, |
312 | - tooltip: 'Add to my Ws', | 312 | + tooltip: 'Add to my Ws' |
313 | // width: 50 | 313 | // width: 50 |
314 | },{// remove from my Ws | 314 | },{// remove from my Ws |
315 | xtype: 'button', | 315 | xtype: 'button', |
@@ -318,7 +318,7 @@ Ext.define('amdaUI.ResourcesMgrUI', { | @@ -318,7 +318,7 @@ Ext.define('amdaUI.ResourcesMgrUI', { | ||
318 | // text: 'Gauche', | 318 | // text: 'Gauche', |
319 | // iconCls: 'icon-removeRsrc', | 319 | // iconCls: 'icon-removeRsrc', |
320 | icon: 'js/resources/images/32x32/1309360153_misc_21.png', | 320 | icon: 'js/resources/images/32x32/1309360153_misc_21.png', |
321 | - tooltip: 'remove from my Ws', | 321 | + tooltip: 'remove from my Ws' |
322 | // width: 50 | 322 | // width: 50 |
323 | }, | 323 | }, |
324 | { | 324 | { |
js/app/views/ShareObjectUI.js
@@ -92,7 +92,7 @@ Ext.define('amdaUI.ShareObjectUI',{ | @@ -92,7 +92,7 @@ Ext.define('amdaUI.ShareObjectUI',{ | ||
92 | this.infoTextArea = Ext.create('Ext.form.field.TextArea', { | 92 | this.infoTextArea = Ext.create('Ext.form.field.TextArea', { |
93 | xtype : 'textareafield', | 93 | xtype : 'textareafield', |
94 | hideLabel : true, | 94 | hideLabel : true, |
95 | - autoScroll : true, | 95 | + autoScroll : true |
96 | }); | 96 | }); |
97 | 97 | ||
98 | this.folderStore = Ext.create('Ext.data.Store', { | 98 | this.folderStore = Ext.create('Ext.data.Store', { |
@@ -226,4 +226,4 @@ Ext.define('amdaUI.ShareObjectUI',{ | @@ -226,4 +226,4 @@ Ext.define('amdaUI.ShareObjectUI',{ | ||
226 | 226 | ||
227 | Ext.apply (this , Ext.apply (arguments, myConf)); | 227 | Ext.apply (this , Ext.apply (arguments, myConf)); |
228 | } | 228 | } |
229 | -}); | ||
230 | \ No newline at end of file | 229 | \ No newline at end of file |
230 | +}); |
js/lib/ux/desktop/FitAllLayout.js deleted
@@ -1,63 +0,0 @@ | @@ -1,63 +0,0 @@ | ||
1 | -/* | ||
2 | - | ||
3 | -This file is part of Ext JS 4 | ||
4 | - | ||
5 | -Copyright (c) 2011 Sencha Inc | ||
6 | - | ||
7 | -Contact: http://www.sencha.com/contact | ||
8 | - | ||
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. | ||
11 | - | ||
12 | -If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact. | ||
13 | - | ||
14 | -*/ | ||
15 | -/*! | ||
16 | - * Ext JS Library 4.0 | ||
17 | - * Copyright(c) 2006-2011 Sencha Inc. | ||
18 | - * licensing@sencha.com | ||
19 | - * http://www.sencha.com/license | ||
20 | - */ | ||
21 | - | ||
22 | -/** | ||
23 | - * @class Ext.ux.desktop.FitAllLayout | ||
24 | - * @extends Ext.layout.container.AbstractFit | ||
25 | - * <p>This layout applies a "fit" layout to all items, overlaying them on top of each | ||
26 | - * other.</p> | ||
27 | - */ | ||
28 | -Ext.define('Ext.ux.desktop.FitAllLayout', { | ||
29 | - extend: 'Ext.layout.container.AbstractFit', | ||
30 | - alias: 'layout.fitall', | ||
31 | - | ||
32 | - // @private | ||
33 | - onLayout : function() { | ||
34 | - var me = this; | ||
35 | - me.callParent(); | ||
36 | - | ||
37 | - var size = me.getLayoutTargetSize(); | ||
38 | - | ||
39 | - me.owner.items.each(function (item) { | ||
40 | - me.setItemBox(item, size); | ||
41 | - }); | ||
42 | - }, | ||
43 | - | ||
44 | - getTargetBox : function() { | ||
45 | - return this.getLayoutTargetSize(); | ||
46 | - }, | ||
47 | - | ||
48 | - setItemBox : function(item, box) { | ||
49 | - var me = this; | ||
50 | - if (item && box.height > 0) { | ||
51 | - if (item.layoutManagedWidth == 2) { | ||
52 | - box.width = undefined; | ||
53 | - } | ||
54 | - if (item.layoutManagedHeight == 2) { | ||
55 | - box.height = undefined; | ||
56 | - } | ||
57 | - | ||
58 | - item.getEl().position('absolute', null, 0, 0); | ||
59 | - me.setItemSize(item, box.width, box.height); | ||
60 | - } | ||
61 | - } | ||
62 | -}); | ||
63 | - |
js/lib/ux/desktop/exampleModules/app.jsb3 deleted
@@ -1,1050 +0,0 @@ | @@ -1,1050 +0,0 @@ | ||
1 | -{ | ||
2 | - "projectName": "Example - Desktop", | ||
3 | - "licenseText": "Copyright(c) 2011 Sencha Inc.\nlicensing@sencha.com", | ||
4 | - "builds": [ | ||
5 | - { | ||
6 | - "name": "All Classes Needed", | ||
7 | - "target": "classes.js", | ||
8 | - "compress": true, | ||
9 | - "files": [ | ||
10 | - { | ||
11 | - "path": "../../../platform/src/util/", | ||
12 | - "name": "Observable.js" | ||
13 | - }, | ||
14 | - { | ||
15 | - "path": "js/", | ||
16 | - "name": "Module.js" | ||
17 | - }, | ||
18 | - { | ||
19 | - "path": "../../../platform/src/chart/", | ||
20 | - "name": "Callout.js" | ||
21 | - }, | ||
22 | - { | ||
23 | - "path": "../../../platform/src/chart/", | ||
24 | - "name": "Mask.js" | ||
25 | - }, | ||
26 | - { | ||
27 | - "path": "../../../platform/src/chart/", | ||
28 | - "name": "Navigation.js" | ||
29 | - }, | ||
30 | - { | ||
31 | - "path": "../../../platform/src/chart/", | ||
32 | - "name": "Shape.js" | ||
33 | - }, | ||
34 | - { | ||
35 | - "path": "../../src/form/field/", | ||
36 | - "name": "VTypes.js" | ||
37 | - }, | ||
38 | - { | ||
39 | - "path": "../../src/util/", | ||
40 | - "name": "ClickRepeater.js" | ||
41 | - }, | ||
42 | - { | ||
43 | - "path": "../../src/util/", | ||
44 | - "name": "TextMetrics.js" | ||
45 | - }, | ||
46 | - { | ||
47 | - "path": "../../src/util/", | ||
48 | - "name": "KeyMap.js" | ||
49 | - }, | ||
50 | - { | ||
51 | - "path": "../../../platform/src/", | ||
52 | - "name": "Template.js" | ||
53 | - }, | ||
54 | - { | ||
55 | - "path": "../../../platform/src/data/", | ||
56 | - "name": "Operation.js" | ||
57 | - }, | ||
58 | - { | ||
59 | - "path": "../../../platform/src/data/", | ||
60 | - "name": "validations.js" | ||
61 | - }, | ||
62 | - { | ||
63 | - "path": "../../../platform/src/draw/", | ||
64 | - "name": "Color.js" | ||
65 | - }, | ||
66 | - { | ||
67 | - "path": "../../../platform/src/draw/", | ||
68 | - "name": "Draw.js" | ||
69 | - }, | ||
70 | - { | ||
71 | - "path": "../../../platform/src/data/", | ||
72 | - "name": "Tree.js" | ||
73 | - }, | ||
74 | - { | ||
75 | - "path": "../../src/form/field/", | ||
76 | - "name": "Field.js" | ||
77 | - }, | ||
78 | - { | ||
79 | - "path": "../../src/dd/", | ||
80 | - "name": "DragTracker.js" | ||
81 | - }, | ||
82 | - { | ||
83 | - "path": "../../../platform/src/util/", | ||
84 | - "name": "Offset.js" | ||
85 | - }, | ||
86 | - { | ||
87 | - "path": "../../../platform/src/", | ||
88 | - "name": "ComponentQuery.js" | ||
89 | - }, | ||
90 | - { | ||
91 | - "path": "../../../platform/src/util/", | ||
92 | - "name": "HashMap.js" | ||
93 | - }, | ||
94 | - { | ||
95 | - "path": "../../src/util/", | ||
96 | - "name": "KeyNav.js" | ||
97 | - }, | ||
98 | - { | ||
99 | - "path": "../../src/util/", | ||
100 | - "name": "Floating.js" | ||
101 | - }, | ||
102 | - { | ||
103 | - "path": "../../src/layout/container/boxOverflow/", | ||
104 | - "name": "None.js" | ||
105 | - }, | ||
106 | - { | ||
107 | - "path": "../../src/layout/container/boxOverflow/", | ||
108 | - "name": "Scroller.js" | ||
109 | - }, | ||
110 | - { | ||
111 | - "path": "../../../platform/src/", | ||
112 | - "name": "AbstractManager.js" | ||
113 | - }, | ||
114 | - { | ||
115 | - "path": "../../../platform/src/data/", | ||
116 | - "name": "Association.js" | ||
117 | - }, | ||
118 | - { | ||
119 | - "path": "../../../platform/src/data/", | ||
120 | - "name": "SortTypes.js" | ||
121 | - }, | ||
122 | - { | ||
123 | - "path": "../../../platform/src/fx/", | ||
124 | - "name": "CubicBezier.js" | ||
125 | - }, | ||
126 | - { | ||
127 | - "path": "../../../platform/src/fx/", | ||
128 | - "name": "PropertyHandler.js" | ||
129 | - }, | ||
130 | - { | ||
131 | - "path": "../../src/util/", | ||
132 | - "name": "Animate.js" | ||
133 | - }, | ||
134 | - { | ||
135 | - "path": "../../../platform/src/util/", | ||
136 | - "name": "Filter.js" | ||
137 | - }, | ||
138 | - { | ||
139 | - "path": "../../src/", | ||
140 | - "name": "ZIndexManager.js" | ||
141 | - }, | ||
142 | - { | ||
143 | - "path": "../../src/panel/", | ||
144 | - "name": "Proxy.js" | ||
145 | - }, | ||
146 | - { | ||
147 | - "path": "../../../platform/src/", | ||
148 | - "name": "PluginManager.js" | ||
149 | - }, | ||
150 | - { | ||
151 | - "path": "../../../platform/src/layout/", | ||
152 | - "name": "Layout.js" | ||
153 | - }, | ||
154 | - { | ||
155 | - "path": "../../../platform/src/data/", | ||
156 | - "name": "Connection.js" | ||
157 | - }, | ||
158 | - { | ||
159 | - "path": "../../../platform/src/util/", | ||
160 | - "name": "Sorter.js" | ||
161 | - }, | ||
162 | - { | ||
163 | - "path": "../../../platform/src/fx/", | ||
164 | - "name": "Queue.js" | ||
165 | - }, | ||
166 | - { | ||
167 | - "path": "../../src/dd/", | ||
168 | - "name": "StatusProxy.js" | ||
169 | - }, | ||
170 | - { | ||
171 | - "path": "../../../platform/src/", | ||
172 | - "name": "ElementLoader.js" | ||
173 | - }, | ||
174 | - { | ||
175 | - "path": "../../../platform/src/fx/target/", | ||
176 | - "name": "Target.js" | ||
177 | - }, | ||
178 | - { | ||
179 | - "path": "../../../platform/src/state/", | ||
180 | - "name": "Provider.js" | ||
181 | - }, | ||
182 | - { | ||
183 | - "path": "../../../platform/src/data/writer/", | ||
184 | - "name": "Writer.js" | ||
185 | - }, | ||
186 | - { | ||
187 | - "path": "../../../platform/src/data/", | ||
188 | - "name": "ResultSet.js" | ||
189 | - }, | ||
190 | - { | ||
191 | - "path": "", | ||
192 | - "name": "VideoWindow.js" | ||
193 | - }, | ||
194 | - { | ||
195 | - "path": "", | ||
196 | - "name": "BogusModule.js" | ||
197 | - }, | ||
198 | - { | ||
199 | - "path": "", | ||
200 | - "name": "BogusMenuModule.js" | ||
201 | - }, | ||
202 | - { | ||
203 | - "path": "../../../platform/src/chart/", | ||
204 | - "name": "Label.js" | ||
205 | - }, | ||
206 | - { | ||
207 | - "path": "../../../platform/src/chart/theme/", | ||
208 | - "name": "Theme.js" | ||
209 | - }, | ||
210 | - { | ||
211 | - "path": "../../../platform/src/chart/theme/", | ||
212 | - "name": "Base.js" | ||
213 | - }, | ||
214 | - { | ||
215 | - "path": "../../src/util/", | ||
216 | - "name": "ComponentDragger.js" | ||
217 | - }, | ||
218 | - { | ||
219 | - "path": "../../../platform/src/util/", | ||
220 | - "name": "Region.js" | ||
221 | - }, | ||
222 | - { | ||
223 | - "path": "../../../platform/src/", | ||
224 | - "name": "XTemplate.js" | ||
225 | - }, | ||
226 | - { | ||
227 | - "path": "../../../platform/src/", | ||
228 | - "name": "ModelManager.js" | ||
229 | - }, | ||
230 | - { | ||
231 | - "path": "../../src/form/", | ||
232 | - "name": "Labelable.js" | ||
233 | - }, | ||
234 | - { | ||
235 | - "path": "../../../platform/src/", | ||
236 | - "name": "ComponentManager.js" | ||
237 | - }, | ||
238 | - { | ||
239 | - "path": "../../src/", | ||
240 | - "name": "FocusManager.js" | ||
241 | - }, | ||
242 | - { | ||
243 | - "path": "../../../platform/src/layout/component/", | ||
244 | - "name": "Component.js" | ||
245 | - }, | ||
246 | - { | ||
247 | - "path": "../../src/layout/component/", | ||
248 | - "name": "Button.js" | ||
249 | - }, | ||
250 | - { | ||
251 | - "path": "../../src/layout/component/", | ||
252 | - "name": "ProgressBar.js" | ||
253 | - }, | ||
254 | - { | ||
255 | - "path": "../../src/layout/component/field/", | ||
256 | - "name": "Field.js" | ||
257 | - }, | ||
258 | - { | ||
259 | - "path": "../../src/layout/component/field/", | ||
260 | - "name": "Text.js" | ||
261 | - }, | ||
262 | - { | ||
263 | - "path": "../../src/layout/component/field/", | ||
264 | - "name": "TextArea.js" | ||
265 | - }, | ||
266 | - { | ||
267 | - "path": "../../src/layout/component/field/", | ||
268 | - "name": "HtmlEditor.js" | ||
269 | - }, | ||
270 | - { | ||
271 | - "path": "../../../platform/src/layout/container/", | ||
272 | - "name": "AbstractContainer.js" | ||
273 | - }, | ||
274 | - { | ||
275 | - "path": "../../src/layout/container/", | ||
276 | - "name": "Container.js" | ||
277 | - }, | ||
278 | - { | ||
279 | - "path": "../../src/layout/container/", | ||
280 | - "name": "Anchor.js" | ||
281 | - }, | ||
282 | - { | ||
283 | - "path": "../../src/dd/", | ||
284 | - "name": "DragDropManager.js" | ||
285 | - }, | ||
286 | - { | ||
287 | - "path": "../../../platform/src/data/", | ||
288 | - "name": "Types.js" | ||
289 | - }, | ||
290 | - { | ||
291 | - "path": "../../../platform/src/data/", | ||
292 | - "name": "Field.js" | ||
293 | - }, | ||
294 | - { | ||
295 | - "path": "../../../platform/src/data/", | ||
296 | - "name": "NodeInterface.js" | ||
297 | - }, | ||
298 | - { | ||
299 | - "path": "../../../platform/src/", | ||
300 | - "name": "Ajax.js" | ||
301 | - }, | ||
302 | - { | ||
303 | - "path": "../../../platform/src/util/", | ||
304 | - "name": "AbstractMixedCollection.js" | ||
305 | - }, | ||
306 | - { | ||
307 | - "path": "../../../platform/src/util/", | ||
308 | - "name": "Sortable.js" | ||
309 | - }, | ||
310 | - { | ||
311 | - "path": "../../../platform/src/util/", | ||
312 | - "name": "MixedCollection.js" | ||
313 | - }, | ||
314 | - { | ||
315 | - "path": "../../src/menu/", | ||
316 | - "name": "Manager.js" | ||
317 | - }, | ||
318 | - { | ||
319 | - "path": "../../../platform/src/data/", | ||
320 | - "name": "Errors.js" | ||
321 | - }, | ||
322 | - { | ||
323 | - "path": "../../../platform/src/data/", | ||
324 | - "name": "StoreManager.js" | ||
325 | - }, | ||
326 | - { | ||
327 | - "path": "../../../platform/src/draw/", | ||
328 | - "name": "CompositeSprite.js" | ||
329 | - }, | ||
330 | - { | ||
331 | - "path": "../../../platform/src/chart/", | ||
332 | - "name": "LegendItem.js" | ||
333 | - }, | ||
334 | - { | ||
335 | - "path": "../../../platform/src/chart/", | ||
336 | - "name": "Legend.js" | ||
337 | - }, | ||
338 | - { | ||
339 | - "path": "../../../platform/src/data/", | ||
340 | - "name": "AbstractStore.js" | ||
341 | - }, | ||
342 | - { | ||
343 | - "path": "../../../platform/src/draw/", | ||
344 | - "name": "Surface.js" | ||
345 | - }, | ||
346 | - { | ||
347 | - "path": "../../../platform/src/fx/", | ||
348 | - "name": "Easing.js" | ||
349 | - }, | ||
350 | - { | ||
351 | - "path": "../../../platform/src/util/", | ||
352 | - "name": "Grouper.js" | ||
353 | - }, | ||
354 | - { | ||
355 | - "path": "../../../platform/src/layout/container/", | ||
356 | - "name": "Auto.js" | ||
357 | - }, | ||
358 | - { | ||
359 | - "path": "../../../platform/src/layout/component/", | ||
360 | - "name": "AbstractDock.js" | ||
361 | - }, | ||
362 | - { | ||
363 | - "path": "../../src/layout/component/", | ||
364 | - "name": "Dock.js" | ||
365 | - }, | ||
366 | - { | ||
367 | - "path": "../../../platform/src/", | ||
368 | - "name": "LoadMask.js" | ||
369 | - }, | ||
370 | - { | ||
371 | - "path": "../../../platform/src/", | ||
372 | - "name": "ComponentLoader.js" | ||
373 | - }, | ||
374 | - { | ||
375 | - "path": "../../../platform/src/layout/component/", | ||
376 | - "name": "Auto.js" | ||
377 | - }, | ||
378 | - { | ||
379 | - "path": "../../../platform/src/layout/component/", | ||
380 | - "name": "Draw.js" | ||
381 | - }, | ||
382 | - { | ||
383 | - "path": "../../../platform/src/fx/target/", | ||
384 | - "name": "Element.js" | ||
385 | - }, | ||
386 | - { | ||
387 | - "path": "../../../platform/src/fx/target/", | ||
388 | - "name": "CompositeElement.js" | ||
389 | - }, | ||
390 | - { | ||
391 | - "path": "../../../platform/src/fx/target/", | ||
392 | - "name": "Sprite.js" | ||
393 | - }, | ||
394 | - { | ||
395 | - "path": "../../../platform/src/fx/target/", | ||
396 | - "name": "CompositeSprite.js" | ||
397 | - }, | ||
398 | - { | ||
399 | - "path": "../../../platform/src/fx/target/", | ||
400 | - "name": "Component.js" | ||
401 | - }, | ||
402 | - { | ||
403 | - "path": "../../../platform/src/fx/", | ||
404 | - "name": "Manager.js" | ||
405 | - }, | ||
406 | - { | ||
407 | - "path": "../../../platform/src/fx/", | ||
408 | - "name": "Animator.js" | ||
409 | - }, | ||
410 | - { | ||
411 | - "path": "../../../platform/src/fx/", | ||
412 | - "name": "Anim.js" | ||
413 | - }, | ||
414 | - { | ||
415 | - "path": "../../../platform/src/chart/", | ||
416 | - "name": "Highlight.js" | ||
417 | - }, | ||
418 | - { | ||
419 | - "path": "../../src/layout/component/", | ||
420 | - "name": "Tip.js" | ||
421 | - }, | ||
422 | - { | ||
423 | - "path": "../../src/layout/component/", | ||
424 | - "name": "Tab.js" | ||
425 | - }, | ||
426 | - { | ||
427 | - "path": "../../../platform/src/selection/", | ||
428 | - "name": "Model.js" | ||
429 | - }, | ||
430 | - { | ||
431 | - "path": "../../src/selection/", | ||
432 | - "name": "RowModel.js" | ||
433 | - }, | ||
434 | - { | ||
435 | - "path": "../../src/selection/", | ||
436 | - "name": "TreeModel.js" | ||
437 | - }, | ||
438 | - { | ||
439 | - "path": "../../../platform/src/state/", | ||
440 | - "name": "Manager.js" | ||
441 | - }, | ||
442 | - { | ||
443 | - "path": "../../../platform/src/state/", | ||
444 | - "name": "Stateful.js" | ||
445 | - }, | ||
446 | - { | ||
447 | - "path": "../../../platform/src/", | ||
448 | - "name": "AbstractComponent.js" | ||
449 | - }, | ||
450 | - { | ||
451 | - "path": "../../src/", | ||
452 | - "name": "Component.js" | ||
453 | - }, | ||
454 | - { | ||
455 | - "path": "../../src/button/", | ||
456 | - "name": "Button.js" | ||
457 | - }, | ||
458 | - { | ||
459 | - "path": "../../src/", | ||
460 | - "name": "ProgressBar.js" | ||
461 | - }, | ||
462 | - { | ||
463 | - "path": "../../../platform/src/chart/", | ||
464 | - "name": "MaskLayer.js" | ||
465 | - }, | ||
466 | - { | ||
467 | - "path": "../../src/toolbar/", | ||
468 | - "name": "Spacer.js" | ||
469 | - }, | ||
470 | - { | ||
471 | - "path": "../../src/toolbar/", | ||
472 | - "name": "Fill.js" | ||
473 | - }, | ||
474 | - { | ||
475 | - "path": "../../src/form/field/", | ||
476 | - "name": "Base.js" | ||
477 | - }, | ||
478 | - { | ||
479 | - "path": "../../src/form/field/", | ||
480 | - "name": "Text.js" | ||
481 | - }, | ||
482 | - { | ||
483 | - "path": "../../src/form/field/", | ||
484 | - "name": "TextArea.js" | ||
485 | - }, | ||
486 | - { | ||
487 | - "path": "../../../platform/src/draw/", | ||
488 | - "name": "Component.js" | ||
489 | - }, | ||
490 | - { | ||
491 | - "path": "../../../platform/src/chart/", | ||
492 | - "name": "Chart.js" | ||
493 | - }, | ||
494 | - { | ||
495 | - "path": "../../../platform/src/chart/", | ||
496 | - "name": "TipSurface.js" | ||
497 | - }, | ||
498 | - { | ||
499 | - "path": "../../../platform/src/chart/axis/", | ||
500 | - "name": "Abstract.js" | ||
501 | - }, | ||
502 | - { | ||
503 | - "path": "../../../platform/src/chart/axis/", | ||
504 | - "name": "Axis.js" | ||
505 | - }, | ||
506 | - { | ||
507 | - "path": "../../../platform/src/chart/axis/", | ||
508 | - "name": "Category.js" | ||
509 | - }, | ||
510 | - { | ||
511 | - "path": "../../../platform/src/chart/axis/", | ||
512 | - "name": "Gauge.js" | ||
513 | - }, | ||
514 | - { | ||
515 | - "path": "../../../platform/src/chart/axis/", | ||
516 | - "name": "Numeric.js" | ||
517 | - }, | ||
518 | - { | ||
519 | - "path": "../../../platform/src/chart/axis/", | ||
520 | - "name": "Radial.js" | ||
521 | - }, | ||
522 | - { | ||
523 | - "path": "../../src/picker/", | ||
524 | - "name": "Color.js" | ||
525 | - }, | ||
526 | - { | ||
527 | - "path": "../../src/toolbar/", | ||
528 | - "name": "Item.js" | ||
529 | - }, | ||
530 | - { | ||
531 | - "path": "../../../platform/src/container/", | ||
532 | - "name": "AbstractContainer.js" | ||
533 | - }, | ||
534 | - { | ||
535 | - "path": "../../src/container/", | ||
536 | - "name": "Container.js" | ||
537 | - }, | ||
538 | - { | ||
539 | - "path": "../../src/container/", | ||
540 | - "name": "Viewport.js" | ||
541 | - }, | ||
542 | - { | ||
543 | - "path": "../../src/panel/", | ||
544 | - "name": "Header.js" | ||
545 | - }, | ||
546 | - { | ||
547 | - "path": "../../src/grid/header/", | ||
548 | - "name": "Container.js" | ||
549 | - }, | ||
550 | - { | ||
551 | - "path": "../../src/grid/column/", | ||
552 | - "name": "Column.js" | ||
553 | - }, | ||
554 | - { | ||
555 | - "path": "../../src/grid/", | ||
556 | - "name": "RowNumberer.js" | ||
557 | - }, | ||
558 | - { | ||
559 | - "path": "../../src/tree/", | ||
560 | - "name": "Column.js" | ||
561 | - }, | ||
562 | - { | ||
563 | - "path": "../../src/tab/", | ||
564 | - "name": "Tab.js" | ||
565 | - }, | ||
566 | - { | ||
567 | - "path": "../../src/tab/", | ||
568 | - "name": "Bar.js" | ||
569 | - }, | ||
570 | - { | ||
571 | - "path": "../../src/toolbar/", | ||
572 | - "name": "Separator.js" | ||
573 | - }, | ||
574 | - { | ||
575 | - "path": "../../src/layout/container/boxOverflow/", | ||
576 | - "name": "Menu.js" | ||
577 | - }, | ||
578 | - { | ||
579 | - "path": "../../src/layout/container/", | ||
580 | - "name": "Box.js" | ||
581 | - }, | ||
582 | - { | ||
583 | - "path": "../../src/layout/container/", | ||
584 | - "name": "HBox.js" | ||
585 | - }, | ||
586 | - { | ||
587 | - "path": "../../src/layout/container/", | ||
588 | - "name": "VBox.js" | ||
589 | - }, | ||
590 | - { | ||
591 | - "path": "../../src/toolbar/", | ||
592 | - "name": "Toolbar.js" | ||
593 | - }, | ||
594 | - { | ||
595 | - "path": "../../src/layout/container/", | ||
596 | - "name": "Accordion.js" | ||
597 | - }, | ||
598 | - { | ||
599 | - "path": "../../../platform/src/panel/", | ||
600 | - "name": "AbstractPanel.js" | ||
601 | - }, | ||
602 | - { | ||
603 | - "path": "../../../platform/src/data/writer/", | ||
604 | - "name": "Json.js" | ||
605 | - }, | ||
606 | - { | ||
607 | - "path": "../../../platform/src/layout/container/", | ||
608 | - "name": "AbstractFit.js" | ||
609 | - }, | ||
610 | - { | ||
611 | - "path": "../../src/layout/container/", | ||
612 | - "name": "Fit.js" | ||
613 | - }, | ||
614 | - { | ||
615 | - "path": "../../../platform/src/layout/container/", | ||
616 | - "name": "AbstractCard.js" | ||
617 | - }, | ||
618 | - { | ||
619 | - "path": "../../src/layout/container/", | ||
620 | - "name": "Card.js" | ||
621 | - }, | ||
622 | - { | ||
623 | - "path": "../../../platform/src/data/reader/", | ||
624 | - "name": "Reader.js" | ||
625 | - }, | ||
626 | - { | ||
627 | - "path": "../../../platform/src/data/reader/", | ||
628 | - "name": "Json.js" | ||
629 | - }, | ||
630 | - { | ||
631 | - "path": "../../../platform/src/data/proxy/", | ||
632 | - "name": "Proxy.js" | ||
633 | - }, | ||
634 | - { | ||
635 | - "path": "../../../platform/src/data/proxy/", | ||
636 | - "name": "Server.js" | ||
637 | - }, | ||
638 | - { | ||
639 | - "path": "../../../platform/src/data/proxy/", | ||
640 | - "name": "Ajax.js" | ||
641 | - }, | ||
642 | - { | ||
643 | - "path": "../../../platform/src/data/", | ||
644 | - "name": "Model.js" | ||
645 | - }, | ||
646 | - { | ||
647 | - "path": "js/", | ||
648 | - "name": "ShortcutModel.js" | ||
649 | - }, | ||
650 | - { | ||
651 | - "path": "../../../platform/src/data/", | ||
652 | - "name": "Store.js" | ||
653 | - }, | ||
654 | - { | ||
655 | - "path": "../../../platform/src/data/", | ||
656 | - "name": "ArrayStore.js" | ||
657 | - }, | ||
658 | - { | ||
659 | - "path": "../../../platform/src/data/", | ||
660 | - "name": "JsonStore.js" | ||
661 | - }, | ||
662 | - { | ||
663 | - "path": "../../../platform/src/chart/axis/", | ||
664 | - "name": "Time.js" | ||
665 | - }, | ||
666 | - { | ||
667 | - "path": "../../../platform/src/data/", | ||
668 | - "name": "NodeStore.js" | ||
669 | - }, | ||
670 | - { | ||
671 | - "path": "../../../platform/src/data/", | ||
672 | - "name": "TreeStore.js" | ||
673 | - }, | ||
674 | - { | ||
675 | - "path": "../../../platform/src/selection/", | ||
676 | - "name": "DataViewModel.js" | ||
677 | - }, | ||
678 | - { | ||
679 | - "path": "../../../platform/src/view/", | ||
680 | - "name": "AbstractView.js" | ||
681 | - }, | ||
682 | - { | ||
683 | - "path": "../../src/view/", | ||
684 | - "name": "View.js" | ||
685 | - }, | ||
686 | - { | ||
687 | - "path": "../../src/view/", | ||
688 | - "name": "Table.js" | ||
689 | - }, | ||
690 | - { | ||
691 | - "path": "../../src/grid/", | ||
692 | - "name": "View.js" | ||
693 | - }, | ||
694 | - { | ||
695 | - "path": "../../src/tree/", | ||
696 | - "name": "View.js" | ||
697 | - }, | ||
698 | - { | ||
699 | - "path": "../../src/dd/", | ||
700 | - "name": "DragDrop.js" | ||
701 | - }, | ||
702 | - { | ||
703 | - "path": "../../src/dd/", | ||
704 | - "name": "DD.js" | ||
705 | - }, | ||
706 | - { | ||
707 | - "path": "../../src/dd/", | ||
708 | - "name": "DDProxy.js" | ||
709 | - }, | ||
710 | - { | ||
711 | - "path": "../../src/dd/", | ||
712 | - "name": "DragSource.js" | ||
713 | - }, | ||
714 | - { | ||
715 | - "path": "../../src/panel/", | ||
716 | - "name": "DD.js" | ||
717 | - }, | ||
718 | - { | ||
719 | - "path": "../../src/panel/", | ||
720 | - "name": "Panel.js" | ||
721 | - }, | ||
722 | - { | ||
723 | - "path": "js/", | ||
724 | - "name": "Desktop.js" | ||
725 | - }, | ||
726 | - { | ||
727 | - "path": "js/", | ||
728 | - "name": "App.js" | ||
729 | - }, | ||
730 | - { | ||
731 | - "path": "../../src/window/", | ||
732 | - "name": "Window.js" | ||
733 | - }, | ||
734 | - { | ||
735 | - "path": "../../src/window/", | ||
736 | - "name": "MessageBox.js" | ||
737 | - }, | ||
738 | - { | ||
739 | - "path": "", | ||
740 | - "name": "Settings.js" | ||
741 | - }, | ||
742 | - { | ||
743 | - "path": "../../src/tab/", | ||
744 | - "name": "Panel.js" | ||
745 | - }, | ||
746 | - { | ||
747 | - "path": "", | ||
748 | - "name": "TabWindow.js" | ||
749 | - }, | ||
750 | - { | ||
751 | - "path": "../../src/panel/", | ||
752 | - "name": "Table.js" | ||
753 | - }, | ||
754 | - { | ||
755 | - "path": "../../src/grid/", | ||
756 | - "name": "Panel.js" | ||
757 | - }, | ||
758 | - { | ||
759 | - "path": "", | ||
760 | - "name": "GridWindow.js" | ||
761 | - }, | ||
762 | - { | ||
763 | - "path": "../../src/tree/", | ||
764 | - "name": "Panel.js" | ||
765 | - }, | ||
766 | - { | ||
767 | - "path": "", | ||
768 | - "name": "AccordionWindow.js" | ||
769 | - }, | ||
770 | - { | ||
771 | - "path": "../../src/tip/", | ||
772 | - "name": "Tip.js" | ||
773 | - }, | ||
774 | - { | ||
775 | - "path": "../../src/tip/", | ||
776 | - "name": "ToolTip.js" | ||
777 | - }, | ||
778 | - { | ||
779 | - "path": "../../../platform/src/chart/", | ||
780 | - "name": "Tip.js" | ||
781 | - }, | ||
782 | - { | ||
783 | - "path": "../../../platform/src/chart/series/", | ||
784 | - "name": "Series.js" | ||
785 | - }, | ||
786 | - { | ||
787 | - "path": "../../../platform/src/chart/series/", | ||
788 | - "name": "Cartesian.js" | ||
789 | - }, | ||
790 | - { | ||
791 | - "path": "../../../platform/src/chart/series/", | ||
792 | - "name": "Area.js" | ||
793 | - }, | ||
794 | - { | ||
795 | - "path": "../../../platform/src/chart/series/", | ||
796 | - "name": "Bar.js" | ||
797 | - }, | ||
798 | - { | ||
799 | - "path": "../../../platform/src/chart/series/", | ||
800 | - "name": "Column.js" | ||
801 | - }, | ||
802 | - { | ||
803 | - "path": "../../../platform/src/chart/series/", | ||
804 | - "name": "Gauge.js" | ||
805 | - }, | ||
806 | - { | ||
807 | - "path": "../../../platform/src/chart/series/", | ||
808 | - "name": "Line.js" | ||
809 | - }, | ||
810 | - { | ||
811 | - "path": "../../../platform/src/chart/series/", | ||
812 | - "name": "Pie.js" | ||
813 | - }, | ||
814 | - { | ||
815 | - "path": "../../../platform/src/chart/series/", | ||
816 | - "name": "Radar.js" | ||
817 | - }, | ||
818 | - { | ||
819 | - "path": "../../../platform/src/chart/series/", | ||
820 | - "name": "Scatter.js" | ||
821 | - }, | ||
822 | - { | ||
823 | - "path": "", | ||
824 | - "name": "SystemStatus.js" | ||
825 | - }, | ||
826 | - { | ||
827 | - "path": "../../src/tip/", | ||
828 | - "name": "QuickTip.js" | ||
829 | - }, | ||
830 | - { | ||
831 | - "path": "../../src/tip/", | ||
832 | - "name": "QuickTipManager.js" | ||
833 | - }, | ||
834 | - { | ||
835 | - "path": "../../src/form/field/", | ||
836 | - "name": "HtmlEditor.js" | ||
837 | - }, | ||
838 | - { | ||
839 | - "path": "", | ||
840 | - "name": "Notepad.js" | ||
841 | - }, | ||
842 | - { | ||
843 | - "path": "", | ||
844 | - "name": "App.js" | ||
845 | - }, | ||
846 | - { | ||
847 | - "path": "../../../platform/src/util/", | ||
848 | - "name": "Point.js" | ||
849 | - }, | ||
850 | - { | ||
851 | - "path": "../../src/", | ||
852 | - "name": "Layer.js" | ||
853 | - }, | ||
854 | - { | ||
855 | - "path": "js/", | ||
856 | - "name": "Video.js" | ||
857 | - }, | ||
858 | - { | ||
859 | - "path": "../../src/resizer/", | ||
860 | - "name": "Resizer.js" | ||
861 | - }, | ||
862 | - { | ||
863 | - "path": "../../src/panel/", | ||
864 | - "name": "Tool.js" | ||
865 | - }, | ||
866 | - { | ||
867 | - "path": "../../src/util/", | ||
868 | - "name": "CSS.js" | ||
869 | - }, | ||
870 | - { | ||
871 | - "path": "../../src/grid/", | ||
872 | - "name": "ColumnLayout.js" | ||
873 | - }, | ||
874 | - { | ||
875 | - "path": "../../src/grid/plugin/", | ||
876 | - "name": "HeaderResizer.js" | ||
877 | - }, | ||
878 | - { | ||
879 | - "path": "../../../platform/src/data/", | ||
880 | - "name": "Batch.js" | ||
881 | - }, | ||
882 | - { | ||
883 | - "path": "../../../platform/src/data/", | ||
884 | - "name": "Request.js" | ||
885 | - }, | ||
886 | - { | ||
887 | - "path": "../../../platform/src/data/reader/", | ||
888 | - "name": "Array.js" | ||
889 | - }, | ||
890 | - { | ||
891 | - "path": "../../src/view/", | ||
892 | - "name": "TableChunker.js" | ||
893 | - }, | ||
894 | - { | ||
895 | - "path": "js/", | ||
896 | - "name": "Wallpaper.js" | ||
897 | - }, | ||
898 | - { | ||
899 | - "path": "js/", | ||
900 | - "name": "FitAllLayout.js" | ||
901 | - }, | ||
902 | - { | ||
903 | - "path": "", | ||
904 | - "name": "WallpaperModel.js" | ||
905 | - }, | ||
906 | - { | ||
907 | - "path": "../../src/grid/", | ||
908 | - "name": "Scroller.js" | ||
909 | - }, | ||
910 | - { | ||
911 | - "path": "../../src/menu/", | ||
912 | - "name": "Item.js" | ||
913 | - }, | ||
914 | - { | ||
915 | - "path": "../../src/menu/", | ||
916 | - "name": "KeyNav.js" | ||
917 | - }, | ||
918 | - { | ||
919 | - "path": "../../../platform/src/draw/", | ||
920 | - "name": "Matrix.js" | ||
921 | - }, | ||
922 | - { | ||
923 | - "path": "../../../platform/src/data/proxy/", | ||
924 | - "name": "Client.js" | ||
925 | - }, | ||
926 | - { | ||
927 | - "path": "../../src/resizer/", | ||
928 | - "name": "Splitter.js" | ||
929 | - }, | ||
930 | - { | ||
931 | - "path": "../../src/toolbar/", | ||
932 | - "name": "TextItem.js" | ||
933 | - }, | ||
934 | - { | ||
935 | - "path": "../../src/form/", | ||
936 | - "name": "CheckboxManager.js" | ||
937 | - }, | ||
938 | - { | ||
939 | - "path": "../../src/grid/", | ||
940 | - "name": "LockingView.js" | ||
941 | - }, | ||
942 | - { | ||
943 | - "path": "../../../platform/src/draw/", | ||
944 | - "name": "SpriteDD.js" | ||
945 | - }, | ||
946 | - { | ||
947 | - "path": "../../src/dd/", | ||
948 | - "name": "DragZone.js" | ||
949 | - }, | ||
950 | - { | ||
951 | - "path": "../../src/dd/", | ||
952 | - "name": "Registry.js" | ||
953 | - }, | ||
954 | - { | ||
955 | - "path": "../../src/dd/", | ||
956 | - "name": "DDTarget.js" | ||
957 | - }, | ||
958 | - { | ||
959 | - "path": "../../src/dd/", | ||
960 | - "name": "ScrollManager.js" | ||
961 | - }, | ||
962 | - { | ||
963 | - "path": "../../src/menu/", | ||
964 | - "name": "CheckItem.js" | ||
965 | - }, | ||
966 | - { | ||
967 | - "path": "../../src/menu/", | ||
968 | - "name": "Separator.js" | ||
969 | - }, | ||
970 | - { | ||
971 | - "path": "../../src/menu/", | ||
972 | - "name": "Menu.js" | ||
973 | - }, | ||
974 | - { | ||
975 | - "path": "../../../platform/src/data/proxy/", | ||
976 | - "name": "Memory.js" | ||
977 | - }, | ||
978 | - { | ||
979 | - "path": "../../src/form/field/", | ||
980 | - "name": "Checkbox.js" | ||
981 | - }, | ||
982 | - { | ||
983 | - "path": "../../src/layout/container/", | ||
984 | - "name": "Border.js" | ||
985 | - }, | ||
986 | - { | ||
987 | - "path": "../../src/grid/", | ||
988 | - "name": "Lockable.js" | ||
989 | - }, | ||
990 | - { | ||
991 | - "path": "../../../platform/src/draw/", | ||
992 | - "name": "Sprite.js" | ||
993 | - }, | ||
994 | - { | ||
995 | - "path": "../../../platform/src/draw/engine/", | ||
996 | - "name": "Svg.js" | ||
997 | - }, | ||
998 | - { | ||
999 | - "path": "../../../platform/src/draw/engine/", | ||
1000 | - "name": "Vml.js" | ||
1001 | - }, | ||
1002 | - { | ||
1003 | - "path": "../../src/grid/header/", | ||
1004 | - "name": "DragZone.js" | ||
1005 | - }, | ||
1006 | - { | ||
1007 | - "path": "js/", | ||
1008 | - "name": "StartMenu.js" | ||
1009 | - }, | ||
1010 | - { | ||
1011 | - "path": "js/", | ||
1012 | - "name": "TaskBar.js" | ||
1013 | - }, | ||
1014 | - { | ||
1015 | - "path": "../../src/dd/", | ||
1016 | - "name": "DropTarget.js" | ||
1017 | - }, | ||
1018 | - { | ||
1019 | - "path": "../../src/dd/", | ||
1020 | - "name": "DropZone.js" | ||
1021 | - }, | ||
1022 | - { | ||
1023 | - "path": "../../src/grid/header/", | ||
1024 | - "name": "DropZone.js" | ||
1025 | - }, | ||
1026 | - { | ||
1027 | - "path": "../../src/grid/plugin/", | ||
1028 | - "name": "HeaderReorderer.js" | ||
1029 | - }, | ||
1030 | - { | ||
1031 | - "path": "../../src/resizer/", | ||
1032 | - "name": "ResizeTracker.js" | ||
1033 | - }, | ||
1034 | - { | ||
1035 | - "path": "../../src/resizer/", | ||
1036 | - "name": "SplitterTracker.js" | ||
1037 | - }, | ||
1038 | - { | ||
1039 | - "path": "../../src/", | ||
1040 | - "name": "ShadowPool.js" | ||
1041 | - }, | ||
1042 | - { | ||
1043 | - "path": "../../src/", | ||
1044 | - "name": "Shadow.js" | ||
1045 | - } | ||
1046 | - ] | ||
1047 | - } | ||
1048 | - ], | ||
1049 | - "resources": [] | ||
1050 | -} | ||
1051 | \ No newline at end of file | 0 | \ No newline at end of file |
@@ -0,0 +1,868 @@ | @@ -0,0 +1,868 @@ | ||
1 | +/** | ||
2 | + * FiltersFeature is a grid {@link Ext.grid.feature.Feature feature} that allows for a slightly more | ||
3 | + * robust representation of filtering than what is provided by the default store. | ||
4 | + * | ||
5 | + * Filtering is adjusted by the user using the grid's column header menu (this menu can be | ||
6 | + * disabled through configuration). Through this menu users can configure, enable, and | ||
7 | + * disable filters for each column. | ||
8 | + * | ||
9 | + * #Features# | ||
10 | + * | ||
11 | + * ##Filtering implementations:## | ||
12 | + * | ||
13 | + * Default filtering for Strings, Numeric Ranges, Date Ranges, Lists (which can be backed by a | ||
14 | + * {@link Ext.data.Store}), and Boolean. Additional custom filter types and menus are easily | ||
15 | + * created by extending {@link Ext.ux.grid.filter.Filter}. | ||
16 | + * | ||
17 | + * ##Graphical Indicators:## | ||
18 | + * | ||
19 | + * Columns that are filtered have {@link #filterCls a configurable css class} applied to the column headers. | ||
20 | + * | ||
21 | + * ##Automatic Reconfiguration:## | ||
22 | + * | ||
23 | + * Filters automatically reconfigure when the grid 'reconfigure' event fires. | ||
24 | + * | ||
25 | + * ##Stateful:## | ||
26 | + * | ||
27 | + * Filter information will be persisted across page loads by specifying a `stateId` | ||
28 | + * in the Grid configuration. | ||
29 | + * | ||
30 | + * The filter collection binds to the {@link Ext.grid.Panel#beforestaterestore beforestaterestore} | ||
31 | + * and {@link Ext.grid.Panel#beforestatesave beforestatesave} events in order to be stateful. | ||
32 | + * | ||
33 | + * ##GridPanel Changes:## | ||
34 | + * | ||
35 | + * - A `filters` property is added to the GridPanel using this feature. | ||
36 | + * - A `filterupdate` event is added to the GridPanel and is fired upon onStateChange completion. | ||
37 | + * | ||
38 | + * ##Server side code examples:## | ||
39 | + * | ||
40 | + * - [PHP](http://www.vinylfox.com/extjs/grid-filter-php-backend-code.php) - (Thanks VinylFox) | ||
41 | + * - [Ruby on Rails](http://extjs.com/forum/showthread.php?p=77326#post77326) - (Thanks Zyclops) | ||
42 | + * - [Ruby on Rails](http://extjs.com/forum/showthread.php?p=176596#post176596) - (Thanks Rotomaul) | ||
43 | + * | ||
44 | + * #Example usage:# | ||
45 | + * | ||
46 | + * var store = Ext.create('Ext.data.Store', { | ||
47 | + * pageSize: 15 | ||
48 | + * ... | ||
49 | + * }); | ||
50 | + * | ||
51 | + * var filtersCfg = { | ||
52 | + * ftype: 'filters', | ||
53 | + * autoReload: false, //don't reload automatically | ||
54 | + * local: true, //only filter locally | ||
55 | + * // filters may be configured through the plugin, | ||
56 | + * // or in the column definition within the headers configuration | ||
57 | + * filters: [{ | ||
58 | + * type: 'numeric', | ||
59 | + * dataIndex: 'id' | ||
60 | + * }, { | ||
61 | + * type: 'string', | ||
62 | + * dataIndex: 'name' | ||
63 | + * }, { | ||
64 | + * type: 'numeric', | ||
65 | + * dataIndex: 'price' | ||
66 | + * }, { | ||
67 | + * type: 'date', | ||
68 | + * dataIndex: 'dateAdded' | ||
69 | + * }, { | ||
70 | + * type: 'list', | ||
71 | + * dataIndex: 'size', | ||
72 | + * options: ['extra small', 'small', 'medium', 'large', 'extra large'], | ||
73 | + * phpMode: true | ||
74 | + * }, { | ||
75 | + * type: 'boolean', | ||
76 | + * dataIndex: 'visible' | ||
77 | + * }] | ||
78 | + * }; | ||
79 | + * | ||
80 | + * var grid = Ext.create('Ext.grid.Panel', { | ||
81 | + * store: store, | ||
82 | + * columns: ..., | ||
83 | + * features: [filtersCfg], | ||
84 | + * height: 400, | ||
85 | + * width: 700, | ||
86 | + * bbar: Ext.create('Ext.PagingToolbar', { | ||
87 | + * store: store | ||
88 | + * }) | ||
89 | + * }); | ||
90 | + * | ||
91 | + * // a filters property is added to the GridPanel | ||
92 | + * grid.filters | ||
93 | + */ | ||
94 | +Ext.define('Ext.ux.grid.FiltersFeature', { | ||
95 | + extend: 'Ext.grid.feature.Feature', | ||
96 | + alias: 'feature.filters', | ||
97 | + uses: [ | ||
98 | + 'Ext.ux.grid.menu.ListMenu', | ||
99 | + 'Ext.ux.grid.menu.RangeMenu', | ||
100 | + 'Ext.ux.grid.filter.BooleanFilter', | ||
101 | + 'Ext.ux.grid.filter.DateFilter', | ||
102 | + 'Ext.ux.grid.filter.DateTimeFilter', | ||
103 | + 'Ext.ux.grid.filter.ListFilter', | ||
104 | + 'Ext.ux.grid.filter.NumericFilter', | ||
105 | + 'Ext.ux.grid.filter.StringFilter' | ||
106 | + ], | ||
107 | + | ||
108 | + /** | ||
109 | + * @cfg {Boolean} autoReload | ||
110 | + * Defaults to true, reloading the datasource when a filter change happens. | ||
111 | + * Set this to false to prevent the datastore from being reloaded if there | ||
112 | + * are changes to the filters. See `{@link #updateBuffer}`. | ||
113 | + */ | ||
114 | + autoReload : true, | ||
115 | + /** | ||
116 | + * @cfg {Boolean} encode | ||
117 | + * Specify true for {@link #buildQuery} to use Ext.util.JSON.encode to | ||
118 | + * encode the filter query parameter sent with a remote request. | ||
119 | + * Defaults to false. | ||
120 | + */ | ||
121 | + /** | ||
122 | + * @cfg {Array} filters | ||
123 | + * An Array of filters config objects. Refer to each filter type class for | ||
124 | + * configuration details specific to each filter type. Filters for Strings, | ||
125 | + * Numeric Ranges, Date Ranges, Lists, and Boolean are the standard filters | ||
126 | + * available. | ||
127 | + */ | ||
128 | + /** | ||
129 | + * @cfg {String} filterCls | ||
130 | + * The css class to be applied to column headers with active filters. | ||
131 | + * Defaults to `'ux-filterd-column'` | ||
132 | + */ | ||
133 | + filterCls : 'ux-filtered-column', | ||
134 | + /** | ||
135 | + * @cfg {Boolean} local | ||
136 | + * <tt>true</tt> to use Ext.data.Store filter functions (local filtering) | ||
137 | + * instead of the default (<tt>false</tt>) server side filtering. | ||
138 | + */ | ||
139 | + local : false, | ||
140 | + /** | ||
141 | + * @cfg {String} menuFilterText | ||
142 | + * defaults to `'Filters'`. | ||
143 | + */ | ||
144 | + menuFilterText : 'Filters', | ||
145 | + /** | ||
146 | + * @cfg {String} paramPrefix | ||
147 | + * The url parameter prefix for the filters. | ||
148 | + * Defaults to `'filter'`. | ||
149 | + */ | ||
150 | + paramPrefix : 'filter', | ||
151 | + /** | ||
152 | + * @cfg {Boolean} showMenu | ||
153 | + * Defaults to true, including a filter submenu in the default header menu. | ||
154 | + */ | ||
155 | + showMenu : true, | ||
156 | + /** | ||
157 | + * @cfg {String} stateId | ||
158 | + * Name of the value to be used to store state information. | ||
159 | + */ | ||
160 | + stateId : undefined, | ||
161 | + /** | ||
162 | + * @cfg {Number} updateBuffer | ||
163 | + * Number of milliseconds to defer store updates since the last filter change. | ||
164 | + */ | ||
165 | + updateBuffer : 500, | ||
166 | + | ||
167 | + // doesn't handle grid body events | ||
168 | + hasFeatureEvent: false, | ||
169 | + | ||
170 | + /** @private */ | ||
171 | + constructor : function (config) { | ||
172 | + var me = this; | ||
173 | + | ||
174 | + me.callParent(arguments); | ||
175 | + | ||
176 | + me.deferredUpdate = Ext.create('Ext.util.DelayedTask', me.reload, me); | ||
177 | + | ||
178 | + // Init filters | ||
179 | + me.filters = me.createFiltersCollection(); | ||
180 | + me.filterConfigs = config.filters; | ||
181 | + }, | ||
182 | + | ||
183 | + init: function(grid) { | ||
184 | + var me = this, | ||
185 | + view = me.view, | ||
186 | + headerCt = view.headerCt; | ||
187 | + | ||
188 | + me.bindStore(view.getStore(), true); | ||
189 | + | ||
190 | + // Listen for header menu being created | ||
191 | + headerCt.on({ | ||
192 | + scope: me, | ||
193 | + menucreate: me.onMenuCreate, | ||
194 | + add: me.onAddRemoveColumn, | ||
195 | + remove: me.onAddRemoveColumn | ||
196 | + }); | ||
197 | + | ||
198 | + view.on('refresh', me.onRefresh, me); | ||
199 | + grid.on({ | ||
200 | + scope: me, | ||
201 | + beforestaterestore: me.applyState, | ||
202 | + beforestatesave: me.saveState, | ||
203 | + beforedestroy: me.destroy | ||
204 | + }); | ||
205 | + | ||
206 | + // Add event and filters shortcut on grid panel | ||
207 | + grid.filters = me; | ||
208 | + grid.addEvents('filterupdate'); | ||
209 | + me.createFilters(); | ||
210 | + }, | ||
211 | + | ||
212 | + createFiltersCollection: function () { | ||
213 | + return Ext.create('Ext.util.MixedCollection', false, function (o) { | ||
214 | + return o ? o.dataIndex : null; | ||
215 | + }); | ||
216 | + }, | ||
217 | + | ||
218 | + /** | ||
219 | + * @private Create the Filter objects for the current configuration, destroying any existing ones first. | ||
220 | + */ | ||
221 | + createFilters: function() { | ||
222 | + var me = this, | ||
223 | + hadFilters = me.filters.getCount(), | ||
224 | + grid = me.getGridPanel(), | ||
225 | + filters = me.createFiltersCollection(), | ||
226 | + model = grid.store.model, | ||
227 | + fields = model.prototype.fields, | ||
228 | + field, | ||
229 | + filter, | ||
230 | + state; | ||
231 | + | ||
232 | + if (hadFilters) { | ||
233 | + state = {}; | ||
234 | + me.saveState(null, state); | ||
235 | + } | ||
236 | + | ||
237 | + function add (dataIndex, config, filterable) { | ||
238 | + if (dataIndex && (filterable || config)) { | ||
239 | + field = fields.get(dataIndex); | ||
240 | + filter = { | ||
241 | + dataIndex: dataIndex, | ||
242 | + type: (field && field.type && field.type.type) || 'auto' | ||
243 | + }; | ||
244 | + | ||
245 | + if (Ext.isObject(config)) { | ||
246 | + Ext.apply(filter, config); | ||
247 | + } | ||
248 | + | ||
249 | + filters.replace(filter); | ||
250 | + } | ||
251 | + } | ||
252 | + | ||
253 | + // We start with filters from our config. | ||
254 | + // Note that we will not recreate filters that are defined in the filters feature config block when | ||
255 | + // reconfiguring the grid, but we must recreate any filters that are defined on the columns themselves. | ||
256 | + if (!me.grid.reconfiguring) { | ||
257 | + Ext.Array.each(me.filterConfigs, function (filterConfig) { | ||
258 | + add(filterConfig.dataIndex, filterConfig); | ||
259 | + }); | ||
260 | + } | ||
261 | + | ||
262 | + // Then we merge on filters from the columns in the grid. The columns' filters take precedence. | ||
263 | + Ext.Array.each(grid.columnManager.getColumns(), function (column) { | ||
264 | + if (column.filterable === false) { | ||
265 | + filters.removeAtKey(column.dataIndex); | ||
266 | + } else { | ||
267 | + add(column.dataIndex, column.filter, column.filterable); | ||
268 | + } | ||
269 | + }); | ||
270 | + | ||
271 | + me.removeAll(); | ||
272 | + | ||
273 | + if (filters.items.length) { | ||
274 | + me.initializeFilters(filters.items); | ||
275 | + } | ||
276 | + | ||
277 | + if (hadFilters) { | ||
278 | + me.applyState(null, state); | ||
279 | + } | ||
280 | + }, | ||
281 | + | ||
282 | + /** | ||
283 | + * @private | ||
284 | + */ | ||
285 | + initializeFilters: function(filters) { | ||
286 | + var me = this, | ||
287 | + filtersLength = filters.length, | ||
288 | + i, filter, FilterClass; | ||
289 | + | ||
290 | + for (i = 0; i < filtersLength; i++) { | ||
291 | + filter = filters[i]; | ||
292 | + if (filter) { | ||
293 | + FilterClass = me.getFilterClass(filter.type); | ||
294 | + filter = filter.menu ? filter : new FilterClass(Ext.apply({ | ||
295 | + grid: me.grid | ||
296 | + }, filter)); | ||
297 | + me.filters.add(filter); | ||
298 | + Ext.util.Observable.capture(filter, me.onStateChange, me); | ||
299 | + } | ||
300 | + } | ||
301 | + }, | ||
302 | + | ||
303 | + onAddRemoveColumn: function () { | ||
304 | + this.createFilters(); | ||
305 | + }, | ||
306 | + | ||
307 | + /** | ||
308 | + * @private Handle creation of the grid's header menu. Initializes the filters and listens | ||
309 | + * for the menu being shown. | ||
310 | + */ | ||
311 | + onMenuCreate: function(headerCt, menu) { | ||
312 | + var me = this; | ||
313 | + | ||
314 | + // If the menu is ever destroyed, the filters need recreating because | ||
315 | + // the filters' menu structures will be destroyed. | ||
316 | + if (me.filtersNeedReCreating) { | ||
317 | + me.createFilters(); | ||
318 | + me.filtersNeedReCreating = false; | ||
319 | + } | ||
320 | + | ||
321 | + menu.on({ | ||
322 | + beforeshow: me.onMenuBeforeShow, | ||
323 | + destroy: me.onMenuDestroy, | ||
324 | + scope: me | ||
325 | + }); | ||
326 | + }, | ||
327 | + | ||
328 | + // The filters at first have to be created at init time so that state can be restored if the grid subsequently | ||
329 | + // fires a beforestaterestore event. | ||
330 | + // However after that, they may need recreating if the column menu is ever destroyed (due to column movement) because | ||
331 | + // that tears down the whole filter item and submenu structure. | ||
332 | + onMenuDestroy: function() { | ||
333 | + this.filtersNeedReCreating = true; | ||
334 | + }, | ||
335 | + | ||
336 | + /** | ||
337 | + * @private Handle showing of the grid's header menu. Sets up the filter item and menu | ||
338 | + * appropriate for the target column. | ||
339 | + */ | ||
340 | + onMenuBeforeShow: function(menu) { | ||
341 | + var me = this, | ||
342 | + menuItem, filter; | ||
343 | + | ||
344 | + if (me.showMenu) { | ||
345 | + menuItem = me.menuItem; | ||
346 | + if (!menuItem || menuItem.isDestroyed) { | ||
347 | + me.createMenuItem(menu); | ||
348 | + menuItem = me.menuItem; | ||
349 | + } | ||
350 | + | ||
351 | + filter = me.getMenuFilter(); | ||
352 | + | ||
353 | + if (filter) { | ||
354 | + menuItem.setMenu(filter.menu, false); | ||
355 | + menuItem.setChecked(filter.active); | ||
356 | + // disable the menu if filter.disabled explicitly set to true | ||
357 | + menuItem.setDisabled(filter.disabled === true); | ||
358 | + } | ||
359 | + menuItem.setVisible(!!filter); | ||
360 | + me.sep.setVisible(!!filter); | ||
361 | + } | ||
362 | + }, | ||
363 | + | ||
364 | + createMenuItem: function(menu) { | ||
365 | + var me = this; | ||
366 | + me.sep = menu.add('-'); | ||
367 | + me.menuItem = menu.add({ | ||
368 | + checked: false, | ||
369 | + itemId: 'filters', | ||
370 | + text: me.menuFilterText, | ||
371 | + listeners: { | ||
372 | + scope: me, | ||
373 | + checkchange: me.onCheckChange, | ||
374 | + beforecheckchange: me.onBeforeCheck | ||
375 | + } | ||
376 | + }); | ||
377 | + }, | ||
378 | + | ||
379 | + getGridPanel: function() { | ||
380 | + // This reference is injected in TableView.initFeatures | ||
381 | + return this.grid; | ||
382 | + }, | ||
383 | + | ||
384 | + /** | ||
385 | + * @private | ||
386 | + * Handler for the grid's beforestaterestore event (fires before the state of the | ||
387 | + * grid is restored). | ||
388 | + * @param {Object} grid The grid object | ||
389 | + * @param {Object} state The hash of state values returned from the StateProvider. | ||
390 | + */ | ||
391 | + applyState : function (grid, state) { | ||
392 | + var me = this, | ||
393 | + key, filter; | ||
394 | + me.applyingState = true; | ||
395 | + me.clearFilters(); | ||
396 | + if (state.filters) { | ||
397 | + for (key in state.filters) { | ||
398 | + if (state.filters.hasOwnProperty(key)) { | ||
399 | + filter = me.filters.get(key); | ||
400 | + if (filter) { | ||
401 | + filter.setValue(state.filters[key]); | ||
402 | + filter.setActive(true); | ||
403 | + } | ||
404 | + } | ||
405 | + } | ||
406 | + } | ||
407 | + me.deferredUpdate.cancel(); | ||
408 | + | ||
409 | + delete me.applyingState; | ||
410 | + delete state.filters; | ||
411 | + }, | ||
412 | + | ||
413 | + /** | ||
414 | + * Saves the state of all active filters | ||
415 | + * @param {Object} grid | ||
416 | + * @param {Object} state | ||
417 | + * @return {Boolean} | ||
418 | + */ | ||
419 | + saveState : function (grid, state) { | ||
420 | + var filters = {}; | ||
421 | + this.filters.each(function (filter) { | ||
422 | + if (filter.active) { | ||
423 | + filters[filter.dataIndex] = filter.getValue(); | ||
424 | + } | ||
425 | + }); | ||
426 | + | ||
427 | + return (state.filters = filters); | ||
428 | + }, | ||
429 | + | ||
430 | + /** | ||
431 | + * @private | ||
432 | + * Handler called by the grid 'beforedestroy' event | ||
433 | + */ | ||
434 | + destroy : function () { | ||
435 | + var me = this; | ||
436 | + | ||
437 | + me.deferredUpdate.cancel(); | ||
438 | + Ext.destroyMembers(me, 'menuItem', 'sep'); | ||
439 | + me.removeAll(); | ||
440 | + me.clearListeners(); | ||
441 | + }, | ||
442 | + | ||
443 | + /** | ||
444 | + * Remove all filters, permanently destroying them. | ||
445 | + */ | ||
446 | + removeAll : function () { | ||
447 | + if(this.filters){ | ||
448 | + Ext.destroy.apply(Ext, this.filters.items); | ||
449 | + // remove all items from the collection | ||
450 | + this.filters.clear(); | ||
451 | + } | ||
452 | + }, | ||
453 | + | ||
454 | + /** | ||
455 | + * Changes the data store bound to this view and refreshes it. | ||
456 | + * @param {Ext.data.Store} store The store to bind to this view | ||
457 | + */ | ||
458 | + bindStore : function(store) { | ||
459 | + var me = this; | ||
460 | + | ||
461 | + // Unbind from the old Store | ||
462 | + if (me.store && me.storeListeners) { | ||
463 | + me.store.un(me.storeListeners); | ||
464 | + } | ||
465 | + | ||
466 | + // Set up correct listeners | ||
467 | + if (store) { | ||
468 | + me.storeListeners = { | ||
469 | + scope: me | ||
470 | + }; | ||
471 | + if (me.local) { | ||
472 | + me.storeListeners.load = me.onLoad; | ||
473 | + } else { | ||
474 | + me.storeListeners['before' + (store.buffered ? 'prefetch' : 'load')] = me.onBeforeLoad; | ||
475 | + } | ||
476 | + store.on(me.storeListeners); | ||
477 | + } else { | ||
478 | + delete me.storeListeners; | ||
479 | + } | ||
480 | + me.store = store; | ||
481 | + }, | ||
482 | + | ||
483 | + getFilterByDataIndex: function (dataIndex) { | ||
484 | + return Ext.Array.findBy(this.getFilterItems(), function (item) { | ||
485 | + return item.dataIndex === dataIndex; | ||
486 | + }); | ||
487 | + }, | ||
488 | + | ||
489 | + /** | ||
490 | + * @private | ||
491 | + * Get the filter menu from the filters MixedCollection based on the clicked header | ||
492 | + */ | ||
493 | + getMenuFilter : function () { | ||
494 | + var header = this.view.headerCt.getMenu().activeHeader; | ||
495 | + return header ? this.getFilterByDataIndex(header.dataIndex) : null; | ||
496 | + }, | ||
497 | + | ||
498 | + /** @private */ | ||
499 | + onCheckChange : function (item, value) { | ||
500 | + this.getMenuFilter().setActive(value); | ||
501 | + }, | ||
502 | + | ||
503 | + /** @private */ | ||
504 | + onBeforeCheck : function (check, value) { | ||
505 | + return !value || this.getMenuFilter().isActivatable(); | ||
506 | + }, | ||
507 | + | ||
508 | + /** | ||
509 | + * @private | ||
510 | + * Handler for all events on filters. | ||
511 | + * @param {String} event Event name | ||
512 | + * @param {Object} filter Standard signature of the event before the event is fired | ||
513 | + */ | ||
514 | + onStateChange : function (event, filter) { | ||
515 | + if (event !== 'serialize') { | ||
516 | + var me = this, | ||
517 | + grid = me.getGridPanel(); | ||
518 | + | ||
519 | + if (filter == me.getMenuFilter()) { | ||
520 | + me.menuItem.setChecked(filter.active, false); | ||
521 | + } | ||
522 | + | ||
523 | + if ((me.autoReload || me.local) && !me.applyingState) { | ||
524 | + me.deferredUpdate.delay(me.updateBuffer); | ||
525 | + } | ||
526 | + me.updateColumnHeadings(); | ||
527 | + | ||
528 | + if (!me.applyingState) { | ||
529 | + grid.saveState(); | ||
530 | + } | ||
531 | + grid.fireEvent('filterupdate', me, filter); | ||
532 | + } | ||
533 | + }, | ||
534 | + | ||
535 | + /** | ||
536 | + * @private | ||
537 | + * Handler for store's beforeload event when configured for remote filtering | ||
538 | + * @param {Object} store | ||
539 | + * @param {Object} options | ||
540 | + */ | ||
541 | + onBeforeLoad : function (store, options) { | ||
542 | + var params; | ||
543 | + | ||
544 | + options.params = options.params || {}; | ||
545 | + this.cleanParams(options.params); | ||
546 | + params = this.buildQuery(this.getFilterData()); | ||
547 | + | ||
548 | + // Memory proxy | ||
549 | + if (store.getProxy().isSynchronous && this.hasActiveFilter()) { | ||
550 | + options.filters = [new Ext.util.Filter({ | ||
551 | + filterFn: this.getRecordFilter() | ||
552 | + })]; | ||
553 | + } | ||
554 | + | ||
555 | + Ext.apply(options.params, params); | ||
556 | + }, | ||
557 | + | ||
558 | + /** | ||
559 | + * @private | ||
560 | + * Handler for store's load event when configured for local filtering | ||
561 | + * @param {Object} store | ||
562 | + */ | ||
563 | + onLoad : function (store) { | ||
564 | + if (this.filters.length) { | ||
565 | + store.filterBy(this.getRecordFilter()); | ||
566 | + } | ||
567 | + }, | ||
568 | + | ||
569 | + /** | ||
570 | + * @private | ||
571 | + * Handler called when the grid's view is refreshed | ||
572 | + */ | ||
573 | + onRefresh : function () { | ||
574 | + this.updateColumnHeadings(); | ||
575 | + }, | ||
576 | + | ||
577 | + /** | ||
578 | + * Update the styles for the header row based on the active filters | ||
579 | + */ | ||
580 | + updateColumnHeadings: function (headerCt) { | ||
581 | + var me = this, | ||
582 | + headerCt = headerCt || me.view.headerCt; | ||
583 | + | ||
584 | + if (headerCt) { | ||
585 | + headerCt.items.each(function (header) { | ||
586 | + var filter; | ||
587 | + | ||
588 | + if (header.isGroupHeader) { | ||
589 | + me.updateColumnHeadings(header); | ||
590 | + } | ||
591 | + | ||
592 | + filter = me.getFilter(header.dataIndex); | ||
593 | + header[filter && filter.active ? 'addCls' : 'removeCls'](me.filterCls); | ||
594 | + }); | ||
595 | + } | ||
596 | + }, | ||
597 | + | ||
598 | + /** @private */ | ||
599 | + reload : function () { | ||
600 | + var me = this, | ||
601 | + store = me.view.getStore(); | ||
602 | + | ||
603 | + if (me.local) { | ||
604 | + store.clearFilter(true); | ||
605 | + store.filterBy(me.getRecordFilter()); | ||
606 | + store.sort(); | ||
607 | + } else { | ||
608 | + me.deferredUpdate.cancel(); | ||
609 | + if (store.buffered) { | ||
610 | + store.data.clear(); | ||
611 | + } | ||
612 | + store.loadPage(1); | ||
613 | + } | ||
614 | + }, | ||
615 | + | ||
616 | + /** | ||
617 | + * Method factory that generates a record validator for the filters active at the time | ||
618 | + * of invokation. | ||
619 | + * @private | ||
620 | + */ | ||
621 | + getRecordFilter : function () { | ||
622 | + var f = [], len, i, | ||
623 | + lockingPartner = this.lockingPartner; | ||
624 | + | ||
625 | + this.filters.each(function (filter) { | ||
626 | + if (filter.active) { | ||
627 | + f.push(filter); | ||
628 | + } | ||
629 | + }); | ||
630 | + | ||
631 | + // Be sure to check the active filters on a locking partner as well. | ||
632 | + if (lockingPartner) { | ||
633 | + lockingPartner.filters.each(function (filter) { | ||
634 | + if (filter.active) { | ||
635 | + f.push(filter); | ||
636 | + } | ||
637 | + }); | ||
638 | + } | ||
639 | + | ||
640 | + len = f.length; | ||
641 | + return function (record) { | ||
642 | + for (i = 0; i < len; i++) { | ||
643 | + if (!f[i].validateRecord(record)) { | ||
644 | + return false; | ||
645 | + } | ||
646 | + } | ||
647 | + return true; | ||
648 | + }; | ||
649 | + }, | ||
650 | + | ||
651 | + hasActiveFilter: function(){ | ||
652 | + var result = false; | ||
653 | + this.filters.each(function (filter) { | ||
654 | + if (filter.active) { | ||
655 | + result = true; | ||
656 | + return false; | ||
657 | + } | ||
658 | + }); | ||
659 | + return result; | ||
660 | + }, | ||
661 | + | ||
662 | + /** | ||
663 | + * Adds a filter to the collection and observes it for state change. | ||
664 | + * @param {Object/Ext.ux.grid.filter.Filter} config A filter configuration or a filter object. | ||
665 | + * @return {Ext.ux.grid.filter.Filter} The existing or newly created filter object. | ||
666 | + */ | ||
667 | + addFilter : function (config) { | ||
668 | + var me = this, | ||
669 | + columns = me.getGridPanel().columnManager.getColumns(), | ||
670 | + i, columnsLength, column, filtersLength, filter; | ||
671 | + | ||
672 | + | ||
673 | + for (i = 0, columnsLength = columns.length; i < columnsLength; i++) { | ||
674 | + column = columns[i]; | ||
675 | + if (column.dataIndex === config.dataIndex) { | ||
676 | + column.filter = config; | ||
677 | + } | ||
678 | + } | ||
679 | + | ||
680 | + if (me.view.headerCt.menu) { | ||
681 | + me.createFilters(); | ||
682 | + } else { | ||
683 | + // Call getMenu() to ensure the menu is created, and so, also are the filters. We cannot call | ||
684 | + // createFilters() withouth having a menu because it will cause in a recursion to applyState() | ||
685 | + // that ends up to clear all the filter values. This is likely to happen when we reorder a column | ||
686 | + // and then add a new filter before the menu is recreated. | ||
687 | + me.view.headerCt.getMenu(); | ||
688 | + } | ||
689 | + | ||
690 | + for (i = 0, filtersLength = me.filters.items.length; i < filtersLength; i++) { | ||
691 | + filter = me.filters.items[i]; | ||
692 | + if (filter.dataIndex === config.dataIndex) { | ||
693 | + return filter; | ||
694 | + } | ||
695 | + } | ||
696 | + }, | ||
697 | + | ||
698 | + /** | ||
699 | + * Adds filters to the collection. | ||
700 | + * @param {Array} filters An Array of filter configuration objects. | ||
701 | + */ | ||
702 | + addFilters : function (filters) { | ||
703 | + if (filters) { | ||
704 | + var me = this, | ||
705 | + i, filtersLength; | ||
706 | + for (i = 0, filtersLength = filters.length; i < filtersLength; i++) { | ||
707 | + me.addFilter(filters[i]); | ||
708 | + } | ||
709 | + } | ||
710 | + }, | ||
711 | + | ||
712 | + /** | ||
713 | + * Returns a filter for the given dataIndex, if one exists. | ||
714 | + * @param {String} dataIndex The dataIndex of the desired filter object. | ||
715 | + * @return {Ext.ux.grid.filter.Filter} | ||
716 | + */ | ||
717 | + getFilter : function (dataIndex) { | ||
718 | + return this.filters.get(dataIndex); | ||
719 | + }, | ||
720 | + | ||
721 | + /** | ||
722 | + * Turns all filters off. This does not clear the configuration information | ||
723 | + * (see {@link #removeAll}). | ||
724 | + */ | ||
725 | + clearFilters : function () { | ||
726 | + this.filters.each(function (filter) { | ||
727 | + filter.setActive(false); | ||
728 | + }); | ||
729 | + }, | ||
730 | + | ||
731 | + getFilterItems: function () { | ||
732 | + var me = this; | ||
733 | + | ||
734 | + // If there's a locked grid then we must get the filter items for each grid. | ||
735 | + if (me.lockingPartner) { | ||
736 | + return me.filters.items.concat(me.lockingPartner.filters.items); | ||
737 | + } | ||
738 | + | ||
739 | + return me.filters.items; | ||
740 | + }, | ||
741 | + | ||
742 | + /** | ||
743 | + * Returns an Array of the currently active filters. | ||
744 | + * @return {Array} filters Array of the currently active filters. | ||
745 | + */ | ||
746 | + getFilterData : function () { | ||
747 | + var items = this.getFilterItems(), | ||
748 | + filters = [], | ||
749 | + n, nlen, item, d, i, len; | ||
750 | + | ||
751 | + for (n = 0, nlen = items.length; n < nlen; n++) { | ||
752 | + item = items[n]; | ||
753 | + if (item.active) { | ||
754 | + d = [].concat(item.serialize()); | ||
755 | + for (i = 0, len = d.length; i < len; i++) { | ||
756 | + filters.push({ | ||
757 | + field: item.dataIndex, | ||
758 | + data: d[i] | ||
759 | + }); | ||
760 | + } | ||
761 | + } | ||
762 | + } | ||
763 | + return filters; | ||
764 | + }, | ||
765 | + | ||
766 | + /** | ||
767 | + * Function to take the active filters data and build it into a query. | ||
768 | + * The format of the query depends on the {@link #encode} configuration: | ||
769 | + * | ||
770 | + * - `false` (Default) : | ||
771 | + * Flatten into query string of the form (assuming <code>{@link #paramPrefix}='filters'</code>: | ||
772 | + * | ||
773 | + * filters[0][field]="someDataIndex"& | ||
774 | + * filters[0][data][comparison]="someValue1"& | ||
775 | + * filters[0][data][type]="someValue2"& | ||
776 | + * filters[0][data][value]="someValue3"& | ||
777 | + * | ||
778 | + * | ||
779 | + * - `true` : | ||
780 | + * JSON encode the filter data | ||
781 | + * | ||
782 | + * {filters:[{"field":"someDataIndex","comparison":"someValue1","type":"someValue2","value":"someValue3"}]} | ||
783 | + * | ||
784 | + * Override this method to customize the format of the filter query for remote requests. | ||
785 | + * | ||
786 | + * @param {Array} filters A collection of objects representing active filters and their configuration. | ||
787 | + * Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured | ||
788 | + * to be unique as any one filter may be a composite of more basic filters for the same dataIndex. | ||
789 | + * | ||
790 | + * @return {Object} Query keys and values | ||
791 | + */ | ||
792 | + buildQuery : function (filters) { | ||
793 | + var p = {}, i, f, root, dataPrefix, key, tmp, | ||
794 | + len = filters.length; | ||
795 | + | ||
796 | + if (!this.encode){ | ||
797 | + for (i = 0; i < len; i++) { | ||
798 | + f = filters[i]; | ||
799 | + root = [this.paramPrefix, '[', i, ']'].join(''); | ||
800 | + p[root + '[field]'] = f.field; | ||
801 | + | ||
802 | + dataPrefix = root + '[data]'; | ||
803 | + for (key in f.data) { | ||
804 | + p[[dataPrefix, '[', key, ']'].join('')] = f.data[key]; | ||
805 | + } | ||
806 | + } | ||
807 | + } else { | ||
808 | + tmp = []; | ||
809 | + for (i = 0; i < len; i++) { | ||
810 | + f = filters[i]; | ||
811 | + tmp.push(Ext.apply( | ||
812 | + {}, | ||
813 | + {field: f.field}, | ||
814 | + f.data | ||
815 | + )); | ||
816 | + } | ||
817 | + // only build if there is active filter | ||
818 | + if (tmp.length > 0){ | ||
819 | + p[this.paramPrefix] = Ext.JSON.encode(tmp); | ||
820 | + } | ||
821 | + } | ||
822 | + return p; | ||
823 | + }, | ||
824 | + | ||
825 | + /** | ||
826 | + * Removes filter related query parameters from the provided object. | ||
827 | + * @param {Object} p Query parameters that may contain filter related fields. | ||
828 | + */ | ||
829 | + cleanParams : function (p) { | ||
830 | + // if encoding just delete the property | ||
831 | + if (this.encode) { | ||
832 | + delete p[this.paramPrefix]; | ||
833 | + // otherwise scrub the object of filter data | ||
834 | + } else { | ||
835 | + var regex, key; | ||
836 | + regex = new RegExp('^' + this.paramPrefix + '\[[0-9]+\]'); | ||
837 | + for (key in p) { | ||
838 | + if (regex.test(key)) { | ||
839 | + delete p[key]; | ||
840 | + } | ||
841 | + } | ||
842 | + } | ||
843 | + }, | ||
844 | + | ||
845 | + /** | ||
846 | + * Function for locating filter classes, overwrite this with your favorite | ||
847 | + * loader to provide dynamic filter loading. | ||
848 | + * @param {String} type The type of filter to load ('Filter' is automatically | ||
849 | + * appended to the passed type; eg, 'string' becomes 'StringFilter'). | ||
850 | + * @return {Function} The Ext.ux.grid.filter.Class | ||
851 | + */ | ||
852 | + getFilterClass : function (type) { | ||
853 | + // map the supported Ext.data.Field type values into a supported filter | ||
854 | + switch(type) { | ||
855 | + case 'auto': | ||
856 | + type = 'string'; | ||
857 | + break; | ||
858 | + case 'int': | ||
859 | + case 'float': | ||
860 | + type = 'numeric'; | ||
861 | + break; | ||
862 | + case 'bool': | ||
863 | + type = 'boolean'; | ||
864 | + break; | ||
865 | + } | ||
866 | + return Ext.ClassManager.getByAlias('gridfilter.' + type); | ||
867 | + } | ||
868 | +}); |
js/lib/ux/grid/HeaderToolTip.js deleted
@@ -1,43 +0,0 @@ | @@ -1,43 +0,0 @@ | ||
1 | -/** | ||
2 | - * Project : AMDA-NG | ||
3 | - * Name : HeaderToolTip.js | ||
4 | - * @class Ext.ux.grid.HeaderToolTip | ||
5 | - * @author SENCHA | ||
6 | - * @version $ | ||
7 | - ****************************************************************************** | ||
8 | - * FT Id : Date : Name - Description | ||
9 | - ****************************************************************************** | ||
10 | - * : | ||
11 | - */ | ||
12 | -Ext.define('Ext.ux.amdaGrid.HeaderToolTip', { | ||
13 | - | ||
14 | - alias: 'plugin.headertooltip', | ||
15 | - | ||
16 | - init : function(grid) { | ||
17 | - | ||
18 | - var headerCt = grid.headerCt; | ||
19 | - | ||
20 | - grid.headerCt.on("afterrender", function(g) { | ||
21 | - | ||
22 | - grid.tip = Ext.create('Ext.tip.ToolTip', { | ||
23 | - target: headerCt.el, | ||
24 | - delegate: ".x-column-header", | ||
25 | - trackMouse: false, | ||
26 | - renderTo: Ext.getBody(), | ||
27 | - listeners: { | ||
28 | - beforeshow: function(tip) { | ||
29 | - var c = headerCt.down('gridcolumn[id=' + tip.triggerElement.id +']'); | ||
30 | - if (c && c.tooltip) { | ||
31 | - tip.update(c.tooltip); | ||
32 | - return true; | ||
33 | - } | ||
34 | - else { | ||
35 | - tip.clearTimers(); | ||
36 | - return false; | ||
37 | - } | ||
38 | - } | ||
39 | - } | ||
40 | - }); | ||
41 | - }); | ||
42 | - } | ||
43 | -}); |
@@ -0,0 +1,94 @@ | @@ -0,0 +1,94 @@ | ||
1 | +/** | ||
2 | + * A Grid which creates itself from an existing HTML table element. | ||
3 | + */ | ||
4 | +Ext.define('Ext.ux.grid.TransformGrid', { | ||
5 | + extend: 'Ext.grid.Panel', | ||
6 | + | ||
7 | + /** | ||
8 | + * Creates the grid from HTML table element. | ||
9 | + * @param {String/HTMLElement/Ext.Element} table The table element from which this grid will be created - | ||
10 | + * The table MUST have some type of size defined for the grid to fill. The container will be | ||
11 | + * automatically set to position relative if it isn't already. | ||
12 | + * @param {Object} [config] A config object that sets properties on this grid and has two additional (optional) | ||
13 | + * properties: fields and columns which allow for customizing data fields and columns for this grid. | ||
14 | + */ | ||
15 | + constructor: function(table, config) { | ||
16 | + config = Ext.apply({}, config); | ||
17 | + table = this.table = Ext.get(table); | ||
18 | + | ||
19 | + var configFields = config.fields || [], | ||
20 | + configColumns = config.columns || [], | ||
21 | + fields = [], | ||
22 | + cols = [], | ||
23 | + headers = table.query("thead th"), | ||
24 | + i = 0, | ||
25 | + len = headers.length, | ||
26 | + data = table.dom, | ||
27 | + width, | ||
28 | + height, | ||
29 | + store, | ||
30 | + col, | ||
31 | + text, | ||
32 | + name; | ||
33 | + | ||
34 | + for (; i < len; ++i) { | ||
35 | + col = headers[i]; | ||
36 | + | ||
37 | + text = col.innerHTML; | ||
38 | + name = 'tcol-' + i; | ||
39 | + | ||
40 | + fields.push(Ext.applyIf(configFields[i] || {}, { | ||
41 | + name: name, | ||
42 | + mapping: 'td:nth(' + (i + 1) + ')/@innerHTML' | ||
43 | + })); | ||
44 | + | ||
45 | + cols.push(Ext.applyIf(configColumns[i] || {}, { | ||
46 | + text: text, | ||
47 | + dataIndex: name, | ||
48 | + width: col.offsetWidth, | ||
49 | + tooltip: col.title, | ||
50 | + sortable: true | ||
51 | + })); | ||
52 | + } | ||
53 | + | ||
54 | + if (config.width) { | ||
55 | + width = config.width; | ||
56 | + } else { | ||
57 | + width = table.getWidth() + 1; | ||
58 | + } | ||
59 | + | ||
60 | + if (config.height) { | ||
61 | + height = config.height; | ||
62 | + } | ||
63 | + | ||
64 | + Ext.applyIf(config, { | ||
65 | + store: { | ||
66 | + data: data, | ||
67 | + fields: fields, | ||
68 | + proxy: { | ||
69 | + type: 'memory', | ||
70 | + reader: { | ||
71 | + record: 'tbody tr', | ||
72 | + type: 'xml' | ||
73 | + } | ||
74 | + } | ||
75 | + }, | ||
76 | + columns: cols, | ||
77 | + width: width, | ||
78 | + height: height | ||
79 | + }); | ||
80 | + this.callParent([config]); | ||
81 | + | ||
82 | + if (config.remove !== false) { | ||
83 | + // Don't use table.remove() as that destroys the row/cell data in the table in | ||
84 | + // IE6-7 so it cannot be read by the data reader. | ||
85 | + data.parentNode.removeChild(data); | ||
86 | + } | ||
87 | + }, | ||
88 | + | ||
89 | + onDestroy: function() { | ||
90 | + this.callParent(); | ||
91 | + this.table.remove(); | ||
92 | + delete this.table; | ||
93 | + } | ||
94 | +}); | ||
0 | \ No newline at end of file | 95 | \ No newline at end of file |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +/* | ||
2 | + * RangeMenu Styles | ||
3 | + */ | ||
4 | + | ||
5 | +.ux-rangemenu-icon { | ||
6 | + display: block; | ||
7 | + height: 16px; | ||
8 | + background: no-repeat 5px center; | ||
9 | +} | ||
10 | + | ||
11 | +.ux-rangemenu-gt { | ||
12 | + background-image: url(../images/greater_than.png) !important; | ||
13 | +} | ||
14 | + | ||
15 | +.ux-rangemenu-lt { | ||
16 | + background-image: url(../images/less_than.png) !important; | ||
17 | +} | ||
18 | + | ||
19 | +.ux-rangemenu-eq { | ||
20 | + background-image: url(../images/equals.png) !important; | ||
21 | +} |
@@ -0,0 +1,98 @@ | @@ -0,0 +1,98 @@ | ||
1 | +/** | ||
2 | + * Boolean filters use unique radio group IDs (so you can have more than one!) | ||
3 | + * <p><b><u>Example Usage:</u></b></p> | ||
4 | + * <pre><code> | ||
5 | +var filters = Ext.create('Ext.ux.grid.GridFilters', { | ||
6 | + ... | ||
7 | + filters: [{ | ||
8 | + // required configs | ||
9 | + type: 'boolean', | ||
10 | + dataIndex: 'visible' | ||
11 | + | ||
12 | + // optional configs | ||
13 | + defaultValue: null, // leave unselected (false selected by default) | ||
14 | + yesText: 'Yes', // default | ||
15 | + noText: 'No' // default | ||
16 | + }] | ||
17 | +}); | ||
18 | + * </code></pre> | ||
19 | + */ | ||
20 | +Ext.define('Ext.ux.grid.filter.BooleanFilter', { | ||
21 | + extend: 'Ext.ux.grid.filter.Filter', | ||
22 | + alias: 'gridfilter.boolean', | ||
23 | + | ||
24 | + /** | ||
25 | + * @cfg {Boolean} defaultValue | ||
26 | + * Set this to null if you do not want either option to be checked by default. Defaults to false. | ||
27 | + */ | ||
28 | + defaultValue : false, | ||
29 | + /** | ||
30 | + * @cfg {String} yesText | ||
31 | + * Defaults to 'Yes'. | ||
32 | + */ | ||
33 | + yesText : 'Yes', | ||
34 | + /** | ||
35 | + * @cfg {String} noText | ||
36 | + * Defaults to 'No'. | ||
37 | + */ | ||
38 | + noText : 'No', | ||
39 | + | ||
40 | + /** | ||
41 | + * @private | ||
42 | + * Template method that is to initialize the filter and install required menu items. | ||
43 | + */ | ||
44 | + init : function (config) { | ||
45 | + var gId = Ext.id(); | ||
46 | + this.options = [ | ||
47 | + Ext.create('Ext.menu.CheckItem', {text: this.yesText, group: gId, checked: this.defaultValue === true}), | ||
48 | + Ext.create('Ext.menu.CheckItem', {text: this.noText, group: gId, checked: this.defaultValue === false})]; | ||
49 | + | ||
50 | + this.menu.add(this.options[0], this.options[1]); | ||
51 | + | ||
52 | + for(var i=0; i<this.options.length; i++){ | ||
53 | + this.options[i].on('click', this.fireUpdate, this); | ||
54 | + this.options[i].on('checkchange', this.fireUpdate, this); | ||
55 | + } | ||
56 | + }, | ||
57 | + | ||
58 | + /** | ||
59 | + * @private | ||
60 | + * Template method that is to get and return the value of the filter. | ||
61 | + * @return {String} The value of this filter | ||
62 | + */ | ||
63 | + getValue : function () { | ||
64 | + return this.options[0].checked; | ||
65 | + }, | ||
66 | + | ||
67 | + /** | ||
68 | + * @private | ||
69 | + * Template method that is to set the value of the filter. | ||
70 | + * @param {Object} value The value to set the filter | ||
71 | + */ | ||
72 | + setValue : function (value) { | ||
73 | + this.options[value ? 0 : 1].setChecked(true); | ||
74 | + }, | ||
75 | + | ||
76 | + /** | ||
77 | + * @private | ||
78 | + * Template method that is to get and return serialized filter data for | ||
79 | + * transmission to the server. | ||
80 | + * @return {Object/Array} An object or collection of objects containing | ||
81 | + * key value pairs representing the current configuration of the filter. | ||
82 | + */ | ||
83 | + getSerialArgs : function () { | ||
84 | + var args = {type: 'boolean', value: this.getValue()}; | ||
85 | + return args; | ||
86 | + }, | ||
87 | + | ||
88 | + /** | ||
89 | + * Template method that is to validate the provided Ext.data.Record | ||
90 | + * against the filters configuration. | ||
91 | + * @param {Ext.data.Record} record The record to validate | ||
92 | + * @return {Boolean} true if the record is valid within the bounds | ||
93 | + * of the filter, false otherwise. | ||
94 | + */ | ||
95 | + validateRecord : function (record) { | ||
96 | + return record.get(this.dataIndex) == this.getValue(); | ||
97 | + } | ||
98 | +}); |
@@ -0,0 +1,340 @@ | @@ -0,0 +1,340 @@ | ||
1 | +/** | ||
2 | + * Filter by a configurable Ext.picker.DatePicker menu | ||
3 | + * | ||
4 | + * Example Usage: | ||
5 | + * | ||
6 | + * var filters = Ext.create('Ext.ux.grid.GridFilters', { | ||
7 | + * ... | ||
8 | + * filters: [{ | ||
9 | + * // required configs | ||
10 | + * type: 'date', | ||
11 | + * dataIndex: 'dateAdded', | ||
12 | + * | ||
13 | + * // optional configs | ||
14 | + * dateFormat: 'm/d/Y', // default | ||
15 | + * beforeText: 'Before', // default | ||
16 | + * afterText: 'After', // default | ||
17 | + * onText: 'On', // default | ||
18 | + * pickerOpts: { | ||
19 | + * // any DatePicker configs | ||
20 | + * }, | ||
21 | + * | ||
22 | + * active: true // default is false | ||
23 | + * }] | ||
24 | + * }); | ||
25 | + */ | ||
26 | +Ext.define('Ext.ux.grid.filter.DateFilter', { | ||
27 | + extend: 'Ext.ux.grid.filter.Filter', | ||
28 | + alias: 'gridfilter.date', | ||
29 | + uses: ['Ext.picker.Date', 'Ext.menu.Menu'], | ||
30 | + | ||
31 | + /** | ||
32 | + * @cfg {String} afterText | ||
33 | + * Defaults to 'After'. | ||
34 | + */ | ||
35 | + afterText : 'After', | ||
36 | + /** | ||
37 | + * @cfg {String} beforeText | ||
38 | + * Defaults to 'Before'. | ||
39 | + */ | ||
40 | + beforeText : 'Before', | ||
41 | + /** | ||
42 | + * @cfg {Object} compareMap | ||
43 | + * Map for assigning the comparison values used in serialization. | ||
44 | + */ | ||
45 | + compareMap : { | ||
46 | + before: 'lt', | ||
47 | + after: 'gt', | ||
48 | + on: 'eq' | ||
49 | + }, | ||
50 | + /** | ||
51 | + * @cfg {String} dateFormat | ||
52 | + * The date format to return when using getValue. | ||
53 | + * Defaults to 'm/d/Y'. | ||
54 | + */ | ||
55 | + dateFormat : 'm/d/Y', | ||
56 | + | ||
57 | + /** | ||
58 | + * @cfg {Date} maxDate | ||
59 | + * Allowable date as passed to the Ext.DatePicker | ||
60 | + * Defaults to undefined. | ||
61 | + */ | ||
62 | + /** | ||
63 | + * @cfg {Date} minDate | ||
64 | + * Allowable date as passed to the Ext.DatePicker | ||
65 | + * Defaults to undefined. | ||
66 | + */ | ||
67 | + /** | ||
68 | + * @cfg {Array} menuItems | ||
69 | + * The items to be shown in this menu | ||
70 | + * Defaults to:<pre> | ||
71 | + * menuItems : ['before', 'after', '-', 'on'], | ||
72 | + * </pre> | ||
73 | + */ | ||
74 | + menuItems : ['before', 'after', '-', 'on'], | ||
75 | + | ||
76 | + /** | ||
77 | + * @cfg {Object} menuItemCfgs | ||
78 | + * Default configuration options for each menu item | ||
79 | + */ | ||
80 | + menuItemCfgs : { | ||
81 | + selectOnFocus: true, | ||
82 | + width: 125 | ||
83 | + }, | ||
84 | + | ||
85 | + /** | ||
86 | + * @cfg {String} onText | ||
87 | + * Defaults to 'On'. | ||
88 | + */ | ||
89 | + onText : 'On', | ||
90 | + | ||
91 | + /** | ||
92 | + * @cfg {Object} pickerOpts | ||
93 | + * Configuration options for the date picker associated with each field. | ||
94 | + */ | ||
95 | + pickerOpts : {}, | ||
96 | + | ||
97 | + /** | ||
98 | + * @private | ||
99 | + * Template method that is to initialize the filter and install required menu items. | ||
100 | + */ | ||
101 | + init : function (config) { | ||
102 | + var me = this, | ||
103 | + pickerCfg, i, len, item, cfg; | ||
104 | + | ||
105 | + pickerCfg = Ext.apply(me.pickerOpts, { | ||
106 | + xtype: 'datepicker', | ||
107 | + minDate: me.minDate, | ||
108 | + maxDate: me.maxDate, | ||
109 | + format: me.dateFormat, | ||
110 | + border: 0, | ||
111 | + listeners: { | ||
112 | + scope: me, | ||
113 | + select: me.onMenuSelect | ||
114 | + } | ||
115 | + }); | ||
116 | + | ||
117 | + me.fields = {}; | ||
118 | + for (i = 0, len = me.menuItems.length; i < len; i++) { | ||
119 | + item = me.menuItems[i]; | ||
120 | + if (item !== '-') { | ||
121 | + cfg = { | ||
122 | + itemId: 'range-' + item, | ||
123 | + text: me[item + 'Text'], | ||
124 | + menu: Ext.create('Ext.menu.Menu', { | ||
125 | + layout: 'auto', | ||
126 | + plain: true, | ||
127 | + items: [ | ||
128 | + Ext.apply(pickerCfg, { | ||
129 | + itemId: item | ||
130 | + }) | ||
131 | + ] | ||
132 | + }), | ||
133 | + listeners: { | ||
134 | + scope: me, | ||
135 | + checkchange: me.onCheckChange | ||
136 | + } | ||
137 | + }; | ||
138 | + item = me.fields[item] = Ext.create('Ext.menu.CheckItem', cfg); | ||
139 | + } | ||
140 | + //me.add(item); | ||
141 | + me.menu.add(item); | ||
142 | + } | ||
143 | + me.values = {}; | ||
144 | + }, | ||
145 | + | ||
146 | + onCheckChange : function (item, checked) { | ||
147 | + var me = this, | ||
148 | + picker = item.menu.items.first(), | ||
149 | + itemId = picker.itemId; | ||
150 | + | ||
151 | + me.setFieldValue(itemId, checked ? picker.getValue() : null); | ||
152 | + me.setActive(me.isActivatable()); | ||
153 | + me.fireEvent('update', me); | ||
154 | + }, | ||
155 | + | ||
156 | + /** | ||
157 | + * @private | ||
158 | + * Handler method called when there is a keyup event on an input | ||
159 | + * item of this menu. | ||
160 | + */ | ||
161 | + onInputKeyUp : function (field, e) { | ||
162 | + var k = e.getKey(); | ||
163 | + if (k == e.RETURN && field.isValid()) { | ||
164 | + e.stopEvent(); | ||
165 | + this.menu.hide(); | ||
166 | + } | ||
167 | + }, | ||
168 | + | ||
169 | + /** | ||
170 | + * Handler for when the DatePicker for a field fires the 'select' event | ||
171 | + * @param {Ext.picker.Date} picker | ||
172 | + * @param {Object} date | ||
173 | + */ | ||
174 | + onMenuSelect : function (picker, date) { | ||
175 | + var fields = this.fields, | ||
176 | + field = this.fields[picker.itemId]; | ||
177 | + | ||
178 | + field.setChecked(true); | ||
179 | + | ||
180 | + if (field == fields.on) { | ||
181 | + fields.before.setChecked(false, true); | ||
182 | + fields.after.setChecked(false, true); | ||
183 | + } else { | ||
184 | + fields.on.setChecked(false, true); | ||
185 | + if (field == fields.after && this.getFieldValue('before') < date) { | ||
186 | + fields.before.setChecked(false, true); | ||
187 | + } else if (field == fields.before && this.getFieldValue('after') > date) { | ||
188 | + fields.after.setChecked(false, true); | ||
189 | + } | ||
190 | + } | ||
191 | + | ||
192 | + // keep track of the picker value separately because the menu gets destroyed | ||
193 | + // when columns order changes. We return this value from getValue() instead | ||
194 | + // of picker.getValue() | ||
195 | + this.setFieldValue(picker.itemId, date); | ||
196 | + | ||
197 | + this.fireEvent('update', this); | ||
198 | + | ||
199 | + picker.up('menu').hide(); | ||
200 | + }, | ||
201 | + | ||
202 | + /** | ||
203 | + * @private | ||
204 | + * Template method that is to get and return the value of the filter. | ||
205 | + * @return {String} The value of this filter | ||
206 | + */ | ||
207 | + getValue : function () { | ||
208 | + var key, result = {}; | ||
209 | + for (key in this.fields) { | ||
210 | + if (this.fields[key].checked) { | ||
211 | + result[key] = this.getFieldValue(key); | ||
212 | + } | ||
213 | + } | ||
214 | + return result; | ||
215 | + }, | ||
216 | + | ||
217 | + /** | ||
218 | + * @private | ||
219 | + * Template method that is to set the value of the filter. | ||
220 | + * @param {Object} value The value to set the filter | ||
221 | + * @param {Boolean} preserve true to preserve the checked status | ||
222 | + * of the other fields. Defaults to false, unchecking the | ||
223 | + * other fields | ||
224 | + */ | ||
225 | + setValue: function (value, preserve) { | ||
226 | + var key, val; | ||
227 | + | ||
228 | + for (key in this.fields) { | ||
229 | + val = value[key]; | ||
230 | + | ||
231 | + if (val) { | ||
232 | + this.getPicker(key).setValue(val); | ||
233 | + // keep track of the picker value separately because the menu gets destroyed | ||
234 | + // when columns order changes. We return this value from getValue() instead | ||
235 | + // of picker.getValue() | ||
236 | + this.setFieldValue(key, val); | ||
237 | + this.fields[key].setChecked(true); | ||
238 | + } else if (!preserve) { | ||
239 | + this.fields[key].setChecked(false); | ||
240 | + } | ||
241 | + } | ||
242 | + this.fireEvent('update', this); | ||
243 | + }, | ||
244 | + | ||
245 | + /** | ||
246 | + * Template method that is to return <tt>true</tt> if the filter | ||
247 | + * has enough configuration information to be activated. | ||
248 | + * @return {Boolean} | ||
249 | + */ | ||
250 | + isActivatable : function () { | ||
251 | + var key; | ||
252 | + for (key in this.fields) { | ||
253 | + if (this.fields[key].checked) { | ||
254 | + return true; | ||
255 | + } | ||
256 | + } | ||
257 | + return false; | ||
258 | + }, | ||
259 | + | ||
260 | + /** | ||
261 | + * @private | ||
262 | + * Template method that is to get and return serialized filter data for | ||
263 | + * transmission to the server. | ||
264 | + * @return {Object/Array} An object or collection of objects containing | ||
265 | + * key value pairs representing the current configuration of the filter. | ||
266 | + */ | ||
267 | + getSerialArgs : function () { | ||
268 | + var args = []; | ||
269 | + for (var key in this.fields) { | ||
270 | + if(this.fields[key].checked){ | ||
271 | + args.push({ | ||
272 | + type: 'date', | ||
273 | + comparison: this.compareMap[key], | ||
274 | + value: Ext.Date.format(this.getFieldValue(key), this.dateFormat) | ||
275 | + }); | ||
276 | + } | ||
277 | + } | ||
278 | + return args; | ||
279 | + }, | ||
280 | + | ||
281 | + /** | ||
282 | + * Get and return the date menu picker value | ||
283 | + * @param {String} item The field identifier ('before', 'after', 'on') | ||
284 | + * @return {Date} Gets the current selected value of the date field | ||
285 | + */ | ||
286 | + getFieldValue : function(item){ | ||
287 | + return this.values[item]; | ||
288 | + }, | ||
289 | + | ||
290 | + /** | ||
291 | + * @private | ||
292 | + */ | ||
293 | + setFieldValue: function (item, value) { | ||
294 | + this.values[item] = value; | ||
295 | + }, | ||
296 | + | ||
297 | + /** | ||
298 | + * Gets the menu picker associated with the passed field | ||
299 | + * @param {String} item The field identifier ('before', 'after', 'on') | ||
300 | + * @return {Object} The menu picker | ||
301 | + */ | ||
302 | + getPicker : function(item){ | ||
303 | + return this.fields[item].menu.items.first(); | ||
304 | + }, | ||
305 | + | ||
306 | + /** | ||
307 | + * Template method that is to validate the provided Ext.data.Record | ||
308 | + * against the filters configuration. | ||
309 | + * @param {Ext.data.Record} record The record to validate | ||
310 | + * @return {Boolean} true if the record is valid within the bounds | ||
311 | + * of the filter, false otherwise. | ||
312 | + */ | ||
313 | + validateRecord : function (record) { | ||
314 | + var key, | ||
315 | + pickerValue, | ||
316 | + val = record.get(this.dataIndex), | ||
317 | + clearTime = Ext.Date.clearTime; | ||
318 | + | ||
319 | + if(!Ext.isDate(val)){ | ||
320 | + return false; | ||
321 | + } | ||
322 | + val = clearTime(val, true).getTime(); | ||
323 | + | ||
324 | + for (key in this.fields) { | ||
325 | + if (this.fields[key].checked) { | ||
326 | + pickerValue = clearTime(this.getFieldValue(key), true).getTime(); | ||
327 | + if (key == 'before' && pickerValue <= val) { | ||
328 | + return false; | ||
329 | + } | ||
330 | + if (key == 'after' && pickerValue >= val) { | ||
331 | + return false; | ||
332 | + } | ||
333 | + if (key == 'on' && pickerValue != val) { | ||
334 | + return false; | ||
335 | + } | ||
336 | + } | ||
337 | + } | ||
338 | + return true; | ||
339 | + } | ||
340 | +}); |
@@ -0,0 +1,451 @@ | @@ -0,0 +1,451 @@ | ||
1 | +/** | ||
2 | + * Filter by a configurable Ext.picker.DatePicker menu | ||
3 | + * | ||
4 | + * This filter allows for the following configurations: | ||
5 | + * | ||
6 | + * - Any of the normal configs will be passed through to either component. | ||
7 | + * - There can be a docked config. | ||
8 | + * - The timepicker can be on the right or left (datepicker, too, of course). | ||
9 | + * - Choose which component will initiate the filtering, i.e., the event can be | ||
10 | + * configured to be bound to either the datepicker or the timepicker, or if | ||
11 | + * there is a docked config it be automatically have the handler bound to it. | ||
12 | + * | ||
13 | + * Although not shown here, this class accepts all configuration options | ||
14 | + * for {@link Ext.picker.Date} and {@link Ext.picker.Time}. | ||
15 | + * | ||
16 | + * In the case that a custom dockedItems config is passed in, the | ||
17 | + * class will handle binding the default listener to it so the | ||
18 | + * developer need not worry about having to do it. | ||
19 | + * | ||
20 | + * The default dockedItems position and the toolbar's | ||
21 | + * button text can be passed a config for convenience, i.e.,: | ||
22 | + * | ||
23 | + * dock: { | ||
24 | + * buttonText: 'Click to Filter', | ||
25 | + * dock: 'left' | ||
26 | + * } | ||
27 | + * | ||
28 | + * Or, pass in a full dockedItems config: | ||
29 | + * | ||
30 | + * dock: { | ||
31 | + * dockedItems: { | ||
32 | + * xtype: 'toolbar', | ||
33 | + * dock: 'bottom', | ||
34 | + * ... | ||
35 | + * } | ||
36 | + * } | ||
37 | + * | ||
38 | + * Or, give a value of `true` to accept dock defaults: | ||
39 | + * | ||
40 | + * dock: true | ||
41 | + * | ||
42 | + * But, it must be one or the other. | ||
43 | + * | ||
44 | + * Example Usage: | ||
45 | + * | ||
46 | + * var filters = Ext.create('Ext.ux.grid.FiltersFeature', { | ||
47 | + * ... | ||
48 | + * filters: [{ | ||
49 | + * // required configs | ||
50 | + * type: 'datetime', | ||
51 | + * dataIndex: 'date', | ||
52 | + * | ||
53 | + * // optional configs | ||
54 | + * positionDatepickerFirst: false, | ||
55 | + * //selectDateToFilter: false, // this is overridden b/c of the presence of the dock cfg object | ||
56 | + * | ||
57 | + * date: { | ||
58 | + * format: 'm/d/Y', | ||
59 | + * }, | ||
60 | + * | ||
61 | + * time: { | ||
62 | + * format: 'H:i:s A', | ||
63 | + * increment: 1 | ||
64 | + * }, | ||
65 | + * | ||
66 | + * dock: { | ||
67 | + * buttonText: 'Click to Filter', | ||
68 | + * dock: 'left' | ||
69 | + * | ||
70 | + * // allows for custom dockedItems cfg | ||
71 | + * //dockedItems: {} | ||
72 | + * } | ||
73 | + * }] | ||
74 | + * }); | ||
75 | + * | ||
76 | + * In the above example, note that the filter is being passed a {@link #date} config object, | ||
77 | + * a {@link #time} config object and a {@link #dock} config. These are all optional. | ||
78 | + * | ||
79 | + * As for positioning, the datepicker will be on the right, the timepicker on the left | ||
80 | + * and the docked items will be docked on the left. In addition, since there's a {@link #dock} | ||
81 | + * config, clicking the button in the dock will trigger the filtering. | ||
82 | + */ | ||
83 | +Ext.define('Ext.ux.grid.filter.DateTimeFilter', { | ||
84 | + extend: 'Ext.ux.grid.filter.DateFilter', | ||
85 | + alias: 'gridfilter.datetime', | ||
86 | + | ||
87 | + /** | ||
88 | + * @private | ||
89 | + */ | ||
90 | + dateDefaults: { | ||
91 | + xtype: 'datepicker', | ||
92 | + format: 'm/d/Y' | ||
93 | + }, | ||
94 | + | ||
95 | + /** | ||
96 | + * @private | ||
97 | + */ | ||
98 | + timeDefaults: { | ||
99 | + xtype: 'timepicker', | ||
100 | + width: 100, | ||
101 | + height: 200, | ||
102 | + format: 'g:i A' | ||
103 | + }, | ||
104 | + | ||
105 | + /** | ||
106 | + * @private | ||
107 | + */ | ||
108 | + dockDefaults: { | ||
109 | + dock: 'top', | ||
110 | + buttonText: 'Filter' | ||
111 | + }, | ||
112 | + | ||
113 | + /** | ||
114 | + * @cfg {Object} date | ||
115 | + * A {@link Ext.picker.Date} can be configured here. | ||
116 | + * Uses {@link #dateDefaults} by default. | ||
117 | + */ | ||
118 | + | ||
119 | + /** | ||
120 | + * @cfg {Object} time | ||
121 | + * A {@link Ext.picker.Time} can be configured here. | ||
122 | + * Uses {@link #timeDefaults} by default. | ||
123 | + */ | ||
124 | + | ||
125 | + /** | ||
126 | + * @cfg {Boolean/Object} dock | ||
127 | + * A {@link Ext.panel.AbstractPanel#cfg-dockedItems} can be configured here. | ||
128 | + * A `true` value will use the {@link #dockDefaults} default configuration. | ||
129 | + * If present, the button in the docked items will initiate the filtering. | ||
130 | + */ | ||
131 | + | ||
132 | + /** | ||
133 | + * @cfg {Boolean} [selectDateToFilter=true] | ||
134 | + * By default, the datepicker has the default event listener bound to it. | ||
135 | + * Setting to `false` will bind it to the timepicker. | ||
136 | + * | ||
137 | + * The config will be ignored if there is a `dock` config. | ||
138 | + */ | ||
139 | + selectDateToFilter: true, | ||
140 | + | ||
141 | + /** | ||
142 | + * @cfg {Boolean} [positionDatepickerFirst=true] | ||
143 | + * Positions the datepicker within its container. | ||
144 | + * A `true` value will place it on the left in the container. | ||
145 | + * Set to `false` if the timepicker should be placed on the left. | ||
146 | + * Defaults to `true`. | ||
147 | + */ | ||
148 | + positionDatepickerFirst: true, | ||
149 | + | ||
150 | + reTime: /\s(am|pm)/i, | ||
151 | + | ||
152 | + /** | ||
153 | + * Mix the value for the timepicker into the datepicker's date. | ||
154 | + * @private | ||
155 | + * @param {Ext.picker.Date} datepicker | ||
156 | + * @param {Ext.picker.Time} timepicker | ||
157 | + * @return Date object | ||
158 | + */ | ||
159 | + addTimeSelection: function (datepicker, timepicker) { | ||
160 | + var me = this, | ||
161 | + date = datepicker.value, | ||
162 | + selection = timepicker.getSelectionModel().getSelection(), | ||
163 | + time, len, fn, val, | ||
164 | + i = 0, | ||
165 | + arr = [], | ||
166 | + timeFns = ['setHours', 'setMinutes', 'setSeconds', 'setMilliseconds']; | ||
167 | + | ||
168 | + | ||
169 | + if (selection.length) { | ||
170 | + time = selection[0].get('disp'); | ||
171 | + | ||
172 | + // Loop through all of the splits and add the time values. | ||
173 | + arr = time.replace(me.reTime, '').split(':'); | ||
174 | + | ||
175 | + for (len = arr.length; i < len; i++) { | ||
176 | + fn = timeFns[i]; | ||
177 | + val = arr[i]; | ||
178 | + | ||
179 | + if (val) { | ||
180 | + date[fn](parseInt(val, 10)); | ||
181 | + } | ||
182 | + } | ||
183 | + } | ||
184 | + | ||
185 | + return date; | ||
186 | + }, | ||
187 | + | ||
188 | + /** | ||
189 | + * @private | ||
190 | + * Template method that is to initialize the filter and install required menu items. | ||
191 | + */ | ||
192 | + init: function (config) { | ||
193 | + var me = this, | ||
194 | + dateCfg = Ext.applyIf(me.date || {}, me.dateDefaults), | ||
195 | + timeCfg = Ext.applyIf(me.time || {}, me.timeDefaults), | ||
196 | + dockCfg = me.dock, // should not default to empty object | ||
197 | + defaultListeners = { | ||
198 | + click: { | ||
199 | + scope: me, | ||
200 | + click: me.onMenuSelect | ||
201 | + }, | ||
202 | + select: { | ||
203 | + scope: me, | ||
204 | + select: me.onMenuSelect | ||
205 | + } | ||
206 | + }, | ||
207 | + pickerCtnCfg, i, len, item, cfg, | ||
208 | + items = [dateCfg, timeCfg], | ||
209 | + | ||
210 | + // we need to know the datepicker's position in the items array | ||
211 | + // for when the itemId name is bound to it before adding to the menu | ||
212 | + datepickerPosition = 0; | ||
213 | + | ||
214 | + if (!me.positionDatepickerFirst) { | ||
215 | + items = items.reverse(); | ||
216 | + datepickerPosition = 1; | ||
217 | + } | ||
218 | + | ||
219 | + pickerCtnCfg = Ext.apply(me.pickerOpts, { | ||
220 | + xtype: !dockCfg ? 'container' : 'panel', | ||
221 | + border: 0, | ||
222 | + layout: 'hbox', | ||
223 | + items: items | ||
224 | + }); | ||
225 | + | ||
226 | + // If there's no dock config then bind the default listener to the desired picker. | ||
227 | + if (!dockCfg) { | ||
228 | + if (me.selectDateToFilter) { | ||
229 | + dateCfg.listeners = defaultListeners.select; | ||
230 | + } else { | ||
231 | + timeCfg.listeners = defaultListeners.select; | ||
232 | + } | ||
233 | + } else if (dockCfg) { | ||
234 | + me.selectDateToFilter = null; | ||
235 | + | ||
236 | + if (dockCfg.dockedItems) { | ||
237 | + pickerCtnCfg.dockedItems = dockCfg.dockedItems; | ||
238 | + // TODO: allow config that will tell which item to bind the listener to | ||
239 | + // right now, it's using the first item | ||
240 | + pickerCtnCfg.dockedItems.items[dockCfg.bindToItem || 0].listeners = defaultListeners.click; | ||
241 | + } else { | ||
242 | + // dockCfg can be `true` if button text and dock position defaults are wanted | ||
243 | + if (Ext.isBoolean(dockCfg)) { | ||
244 | + dockCfg = {}; | ||
245 | + } | ||
246 | + dockCfg = Ext.applyIf(dockCfg, me.dockDefaults); | ||
247 | + pickerCtnCfg.dockedItems = { | ||
248 | + xtype: 'toolbar', | ||
249 | + dock: dockCfg.dock, | ||
250 | + items: [{ | ||
251 | + xtype: 'button', | ||
252 | + text: dockCfg.buttonText, | ||
253 | + flex: 1, | ||
254 | + listeners: defaultListeners.click | ||
255 | + }] | ||
256 | + }; | ||
257 | + } | ||
258 | + } | ||
259 | + | ||
260 | + me.fields = {}; | ||
261 | + for (i = 0, len = me.menuItems.length; i < len; i++) { | ||
262 | + item = me.menuItems[i]; | ||
263 | + if (item !== '-') { | ||
264 | + pickerCtnCfg.items[datepickerPosition].itemId = item; | ||
265 | + | ||
266 | + cfg = { | ||
267 | + itemId: item, | ||
268 | + text: me[item + 'Text'], | ||
269 | + menu: Ext.create('Ext.menu.Menu', { | ||
270 | + layout: 'auto', | ||
271 | + plain: true, | ||
272 | + items: pickerCtnCfg | ||
273 | + }), | ||
274 | + listeners: { | ||
275 | + scope: me, | ||
276 | + checkchange: me.onCheckChange | ||
277 | + } | ||
278 | + }; | ||
279 | + item = me.fields[item] = Ext.create('Ext.menu.CheckItem', cfg); | ||
280 | + } | ||
281 | + me.menu.add(item); | ||
282 | + } | ||
283 | + me.values = {}; | ||
284 | + }, | ||
285 | + | ||
286 | + /** | ||
287 | + * @private | ||
288 | + */ | ||
289 | + getCacheValues: function (item, checked) { | ||
290 | + var menu = item.menu, | ||
291 | + timepicker = menu.down('timepicker'), | ||
292 | + datepicker = menu.down('datepicker'), | ||
293 | + key = datepicker.itemId; | ||
294 | + | ||
295 | + return [key, checked ? this.addTimeSelection(datepicker, timepicker) : null]; | ||
296 | + }, | ||
297 | + | ||
298 | + /** | ||
299 | + * @private | ||
300 | + */ | ||
301 | + onCheckChange: function (item, checked) { | ||
302 | + var me = this; | ||
303 | + | ||
304 | + me.setFieldValue.apply(me, me.getCacheValues(item, checked)); | ||
305 | + me.setActive(me.isActivatable()); | ||
306 | + me.fireEvent('update', me); | ||
307 | + }, | ||
308 | + | ||
309 | + /** | ||
310 | + * Handler for when the DatePicker for a field fires the 'select' event | ||
311 | + * @param {Ext.picker.Date} picker | ||
312 | + * @param {Object} date | ||
313 | + */ | ||
314 | + onMenuSelect: function (picker, date) { | ||
315 | + var me = this, | ||
316 | + menu = me.menu, | ||
317 | + fields = me.fields, | ||
318 | + field; | ||
319 | + | ||
320 | + if (me.dock) { | ||
321 | + // If there is a dock config then the button will trigger the menu select. In these cases, the picker | ||
322 | + // function arg isn't actually a picker but the button that was clicked, so redefine the picker. | ||
323 | + // Similarly, the date function argument will not be a Date type, so get it from the datepicker. | ||
324 | + // The focusEl is going to be the check item. | ||
325 | + picker = menu.getFocusEl().down('datepicker'); | ||
326 | + date = picker.value; | ||
327 | + } | ||
328 | + | ||
329 | + field = me.fields[picker.itemId]; | ||
330 | + field.setChecked(true); | ||
331 | + | ||
332 | + if (field == fields.on) { | ||
333 | + fields.before.setChecked(false, true); | ||
334 | + fields.after.setChecked(false, true); | ||
335 | + } else { | ||
336 | + fields.on.setChecked(false, true); | ||
337 | + if (field == fields.after && me.getFieldValue('before') < date) { | ||
338 | + fields.before.setChecked(false, true); | ||
339 | + } else if (field == fields.before && me.getFieldValue('after') > date) { | ||
340 | + fields.after.setChecked(false, true); | ||
341 | + } | ||
342 | + } | ||
343 | + | ||
344 | + // Note that the date will not have the H:i:s info mixed into it. getCacheValues() will handle this. | ||
345 | + me.setFieldValue.apply(me, me.getCacheValues(field, true)); | ||
346 | + | ||
347 | + me.fireEvent('update', me); | ||
348 | + | ||
349 | + picker.up('menu').hide(); | ||
350 | + }, | ||
351 | + | ||
352 | + /** | ||
353 | + * @private | ||
354 | + * Template method that is to get and return serialized filter data for | ||
355 | + * transmission to the server. | ||
356 | + * @return {Object/Array} An object or collection of objects containing | ||
357 | + * key value pairs representing the current configuration of the filter. | ||
358 | + */ | ||
359 | + getSerialArgs: function () { | ||
360 | + var me = this, | ||
361 | + key, | ||
362 | + fields = me.fields, | ||
363 | + args = [], | ||
364 | + date = Ext.apply(me.dateDefaults, me.date || {}), | ||
365 | + time = Ext.apply(me.timeDefaults, me.time || {}); | ||
366 | + | ||
367 | + for (key in fields) { | ||
368 | + if (fields[key].checked) { | ||
369 | + args.push({ | ||
370 | + type: 'datetime', | ||
371 | + comparison: me.compareMap[key], | ||
372 | + value: Ext.Date.format(me.getFieldValue(key), date.format + ' ' + time.format) | ||
373 | + }); | ||
374 | + } | ||
375 | + } | ||
376 | + return args; | ||
377 | + }, | ||
378 | + | ||
379 | + /** | ||
380 | + * @private | ||
381 | + * Template method that is to set the value of the filter. | ||
382 | + * @param {Object} value The value to set the filter | ||
383 | + * @param {Boolean} preserve true to preserve the checked status | ||
384 | + * of the other fields. Defaults to false, unchecking the | ||
385 | + * other fields | ||
386 | + */ | ||
387 | + setValue: function (value, preserve) { | ||
388 | + var me = this, | ||
389 | + fields = me.fields, | ||
390 | + key, | ||
391 | + val, | ||
392 | + datepicker; | ||
393 | + | ||
394 | + for (key in fields) { | ||
395 | + val = value[key]; | ||
396 | + if (val) { | ||
397 | + datepicker = me.menu.down('datepicker[itemId="' + key + '"]'); | ||
398 | + // Note that calling the Ext.picker.Date:setValue() calls Ext.Date.clearTime(), | ||
399 | + // which we don't want, so just call update() instead and set the value on the component. | ||
400 | + datepicker.update(val); | ||
401 | + datepicker.value = val; | ||
402 | + // keep track of the picker value separately because the menu gets destroyed | ||
403 | + // when columns order changes. We return this value from getValue() instead | ||
404 | + // of picker.getValue() | ||
405 | + me.setFieldValue(key, val); | ||
406 | + | ||
407 | + fields[key].setChecked(true); | ||
408 | + } else if (!preserve) { | ||
409 | + fields[key].setChecked(false); | ||
410 | + } | ||
411 | + } | ||
412 | + me.fireEvent('update', me); | ||
413 | + }, | ||
414 | + | ||
415 | + /** | ||
416 | + * Template method that is to validate the provided Ext.data.Record | ||
417 | + * against the filters configuration. | ||
418 | + * @param {Ext.data.Record} record The record to validate | ||
419 | + * @return {Boolean} true if the record is valid within the bounds | ||
420 | + * of the filter, false otherwise. | ||
421 | + */ | ||
422 | + validateRecord: function (record) { | ||
423 | + // remove calls to Ext.Date.clearTime | ||
424 | + var me = this, | ||
425 | + key, | ||
426 | + pickerValue, | ||
427 | + val = record.get(me.dataIndex); | ||
428 | + | ||
429 | + if (!Ext.isDate(val)) { | ||
430 | + return false; | ||
431 | + } | ||
432 | + | ||
433 | + val = val.getTime(); | ||
434 | + | ||
435 | + for (key in me.fields) { | ||
436 | + if (me.fields[key].checked) { | ||
437 | + pickerValue = me.getFieldValue(key).getTime(); | ||
438 | + if (key == 'before' && pickerValue <= val) { | ||
439 | + return false; | ||
440 | + } | ||
441 | + if (key == 'after' && pickerValue >= val) { | ||
442 | + return false; | ||
443 | + } | ||
444 | + if (key == 'on' && pickerValue != val) { | ||
445 | + return false; | ||
446 | + } | ||
447 | + } | ||
448 | + } | ||
449 | + return true; | ||
450 | + } | ||
451 | +}); |
@@ -0,0 +1,181 @@ | @@ -0,0 +1,181 @@ | ||
1 | +/** | ||
2 | + * Abstract base class for filter implementations. | ||
3 | + */ | ||
4 | +Ext.define('Ext.ux.grid.filter.Filter', { | ||
5 | + extend: 'Ext.util.Observable', | ||
6 | + | ||
7 | + /** | ||
8 | + * @cfg {Boolean} active | ||
9 | + * Indicates the initial status of the filter (defaults to false). | ||
10 | + */ | ||
11 | + active : false, | ||
12 | + /** | ||
13 | + * @property {Boolean} active | ||
14 | + * True if this filter is active. Use setActive() to alter after configuration. | ||
15 | + */ | ||
16 | + /** | ||
17 | + * @cfg {String} dataIndex | ||
18 | + * The {@link Ext.data.Store} dataIndex of the field this filter represents. | ||
19 | + * The dataIndex does not actually have to exist in the store. | ||
20 | + */ | ||
21 | + dataIndex : null, | ||
22 | + /** | ||
23 | + * @property {Ext.menu.Menu} menu | ||
24 | + * The filter configuration menu that will be installed into the filter submenu of a column menu. | ||
25 | + */ | ||
26 | + menu : null, | ||
27 | + /** | ||
28 | + * @cfg {Number} updateBuffer | ||
29 | + * Number of milliseconds to wait after user interaction to fire an update. Only supported | ||
30 | + * by filters: 'list', 'numeric', and 'string'. | ||
31 | + */ | ||
32 | + updateBuffer : 500, | ||
33 | + | ||
34 | + constructor : function (config) { | ||
35 | + Ext.apply(this, config); | ||
36 | + | ||
37 | + this.addEvents( | ||
38 | + /** | ||
39 | + * @event activate | ||
40 | + * Fires when an inactive filter becomes active | ||
41 | + * @param {Ext.ux.grid.filter.Filter} this | ||
42 | + */ | ||
43 | + 'activate', | ||
44 | + /** | ||
45 | + * @event deactivate | ||
46 | + * Fires when an active filter becomes inactive | ||
47 | + * @param {Ext.ux.grid.filter.Filter} this | ||
48 | + */ | ||
49 | + 'deactivate', | ||
50 | + /** | ||
51 | + * @event serialize | ||
52 | + * Fires after the serialization process. Use this to attach additional parameters to serialization | ||
53 | + * data before it is encoded and sent to the server. | ||
54 | + * @param {Array/Object} data A map or collection of maps representing the current filter configuration. | ||
55 | + * @param {Ext.ux.grid.filter.Filter} filter The filter being serialized. | ||
56 | + */ | ||
57 | + 'serialize', | ||
58 | + /** | ||
59 | + * @event update | ||
60 | + * Fires when a filter configuration has changed | ||
61 | + * @param {Ext.ux.grid.filter.Filter} this The filter object. | ||
62 | + */ | ||
63 | + 'update' | ||
64 | + ); | ||
65 | + Ext.ux.grid.filter.Filter.superclass.constructor.call(this); | ||
66 | + | ||
67 | + this.menu = this.createMenu(config); | ||
68 | + this.init(config); | ||
69 | + if(config && config.value){ | ||
70 | + this.setValue(config.value); | ||
71 | + this.setActive(config.active !== false, true); | ||
72 | + delete config.value; | ||
73 | + } | ||
74 | + }, | ||
75 | + | ||
76 | + /** | ||
77 | + * Destroys this filter by purging any event listeners, and removing any menus. | ||
78 | + */ | ||
79 | + destroy : function(){ | ||
80 | + if (this.menu){ | ||
81 | + this.menu.destroy(); | ||
82 | + } | ||
83 | + this.clearListeners(); | ||
84 | + }, | ||
85 | + | ||
86 | + /** | ||
87 | + * Template method to be implemented by all subclasses that is to | ||
88 | + * initialize the filter and install required menu items. | ||
89 | + * Defaults to Ext.emptyFn. | ||
90 | + */ | ||
91 | + init : Ext.emptyFn, | ||
92 | + | ||
93 | + /** | ||
94 | + * @private | ||
95 | + * Creates the Menu for this filter. | ||
96 | + * @param {Object} config Filter configuration | ||
97 | + * @return {Ext.menu.Menu} | ||
98 | + */ | ||
99 | + createMenu: function(config) { | ||
100 | + config.plain = true; | ||
101 | + return Ext.create('Ext.menu.Menu', config); | ||
102 | + }, | ||
103 | + | ||
104 | + /** | ||
105 | + * Template method to be implemented by all subclasses that is to | ||
106 | + * get and return the value of the filter. | ||
107 | + * @return {Object} The 'serialized' form of this filter | ||
108 | + * @template | ||
109 | + */ | ||
110 | + getValue : Ext.emptyFn, | ||
111 | + | ||
112 | + /** | ||
113 | + * Template method to be implemented by all subclasses that is to | ||
114 | + * set the value of the filter and fire the 'update' event. | ||
115 | + * @param {Object} data The value to set the filter | ||
116 | + * @template | ||
117 | + */ | ||
118 | + setValue : Ext.emptyFn, | ||
119 | + | ||
120 | + /** | ||
121 | + * Template method to be implemented by all subclasses that is to | ||
122 | + * return true if the filter has enough configuration information to be activated. | ||
123 | + * Defaults to always returning true. | ||
124 | + * @return {Boolean} | ||
125 | + */ | ||
126 | + isActivatable : function(){ | ||
127 | + return true; | ||
128 | + }, | ||
129 | + | ||
130 | + /** | ||
131 | + * Template method to be implemented by all subclasses that is to | ||
132 | + * get and return serialized filter data for transmission to the server. | ||
133 | + */ | ||
134 | + getSerialArgs : Ext.emptyFn, | ||
135 | + | ||
136 | + /** | ||
137 | + * Template method to be implemented by all subclasses that is to | ||
138 | + * validates the provided Ext.data.Record against the filters configuration. | ||
139 | + * Defaults to always returning true. | ||
140 | + * @param {Ext.data.Record} record The record to validate | ||
141 | + * @return {Boolean} true if the record is valid within the bounds | ||
142 | + * of the filter, false otherwise. | ||
143 | + */ | ||
144 | + validateRecord : function(){ | ||
145 | + return true; | ||
146 | + }, | ||
147 | + | ||
148 | + /** | ||
149 | + * Returns the serialized filter data for transmission to the server | ||
150 | + * and fires the 'serialize' event. | ||
151 | + * @return {Object/Array} An object or collection of objects containing | ||
152 | + * key value pairs representing the current configuration of the filter. | ||
153 | + */ | ||
154 | + serialize : function(){ | ||
155 | + var args = this.getSerialArgs(); | ||
156 | + this.fireEvent('serialize', args, this); | ||
157 | + return args; | ||
158 | + }, | ||
159 | + | ||
160 | + /** @private */ | ||
161 | + fireUpdate : function(){ | ||
162 | + if (this.active) { | ||
163 | + this.fireEvent('update', this); | ||
164 | + } | ||
165 | + this.setActive(this.isActivatable()); | ||
166 | + }, | ||
167 | + | ||
168 | + /** | ||
169 | + * Sets the status of the filter and fires the appropriate events. | ||
170 | + * @param {Boolean} active The new filter state. | ||
171 | + * @param {Boolean} suppressEvent True to prevent events from being fired. | ||
172 | + */ | ||
173 | + setActive : function(active, suppressEvent){ | ||
174 | + if(this.active != active){ | ||
175 | + this.active = active; | ||
176 | + if (suppressEvent !== true) { | ||
177 | + this.fireEvent(active ? 'activate' : 'deactivate', this); | ||
178 | + } | ||
179 | + } | ||
180 | + } | ||
181 | +}); |
@@ -0,0 +1,202 @@ | @@ -0,0 +1,202 @@ | ||
1 | +/** | ||
2 | + * List filters are able to be preloaded/backed by an Ext.data.Store to load | ||
3 | + * their options the first time they are shown. ListFilter utilizes the | ||
4 | + * {@link Ext.ux.grid.menu.ListMenu} component. | ||
5 | + * | ||
6 | + * List filters are also able to create their own list of values from all unique values of | ||
7 | + * the specified {@link #dataIndex} field in the store at first time of filter invocation. | ||
8 | + * | ||
9 | + * Although not shown here, this class accepts all configuration options | ||
10 | + * for {@link Ext.ux.grid.menu.ListMenu}. | ||
11 | + * | ||
12 | + * Example Usage: | ||
13 | + * | ||
14 | + * var filters = Ext.create('Ext.ux.grid.GridFilters', { | ||
15 | + * ... | ||
16 | + * filters: [{ | ||
17 | + * type: 'list', | ||
18 | + * dataIndex: 'size', | ||
19 | + * phpMode: true, | ||
20 | + * // options will be used as data to implicitly creates an ArrayStore | ||
21 | + * options: ['extra small', 'small', 'medium', 'large', 'extra large'] | ||
22 | + * }] | ||
23 | + * }); | ||
24 | + * | ||
25 | + */ | ||
26 | +Ext.define('Ext.ux.grid.filter.ListFilter', { | ||
27 | + extend: 'Ext.ux.grid.filter.Filter', | ||
28 | + alias: 'gridfilter.list', | ||
29 | + | ||
30 | + /** | ||
31 | + * @cfg {Array} [options] | ||
32 | + * `data` to be used to implicitly create a data store | ||
33 | + * to back this list when the data source is **local**. If the | ||
34 | + * data for the list is remote, use the {@link #store} | ||
35 | + * config instead. | ||
36 | + * | ||
37 | + * If neither store nor {@link #options} is specified, then the choices list is automatically | ||
38 | + * populated from all unique values of the specified {@link #dataIndex} field in the store at first | ||
39 | + * time of filter invocation. | ||
40 | + * | ||
41 | + * Each item within the provided array may be in one of the | ||
42 | + * following formats: | ||
43 | + * | ||
44 | + * - **Array** : | ||
45 | + * | ||
46 | + * options: [ | ||
47 | + * [11, 'extra small'], | ||
48 | + * [18, 'small'], | ||
49 | + * [22, 'medium'], | ||
50 | + * [35, 'large'], | ||
51 | + * [44, 'extra large'] | ||
52 | + * ] | ||
53 | + * | ||
54 | + * - **Object** : | ||
55 | + * | ||
56 | + * labelField: 'name', // override default of 'text' | ||
57 | + * options: [ | ||
58 | + * {id: 11, name:'extra small'}, | ||
59 | + * {id: 18, name:'small'}, | ||
60 | + * {id: 22, name:'medium'}, | ||
61 | + * {id: 35, name:'large'}, | ||
62 | + * {id: 44, name:'extra large'} | ||
63 | + * ] | ||
64 | + * | ||
65 | + * - **String** : | ||
66 | + * | ||
67 | + * options: ['extra small', 'small', 'medium', 'large', 'extra large'] | ||
68 | + * | ||
69 | + */ | ||
70 | + /** | ||
71 | + * @cfg {Boolean} phpMode | ||
72 | + * Adjust the format of this filter. Defaults to false. | ||
73 | + * | ||
74 | + * When GridFilters `@cfg encode = false` (default): | ||
75 | + * | ||
76 | + * // phpMode == false (default): | ||
77 | + * filter[0][data][type] list | ||
78 | + * filter[0][data][value] value1 | ||
79 | + * filter[0][data][value] value2 | ||
80 | + * filter[0][field] prod | ||
81 | + * | ||
82 | + * // phpMode == true: | ||
83 | + * filter[0][data][type] list | ||
84 | + * filter[0][data][value] value1, value2 | ||
85 | + * filter[0][field] prod | ||
86 | + * | ||
87 | + * When GridFilters `@cfg encode = true`: | ||
88 | + * | ||
89 | + * // phpMode == false (default): | ||
90 | + * filter : [{"type":"list","value":["small","medium"],"field":"size"}] | ||
91 | + * | ||
92 | + * // phpMode == true: | ||
93 | + * filter : [{"type":"list","value":"small,medium","field":"size"}] | ||
94 | + * | ||
95 | + */ | ||
96 | + phpMode : false, | ||
97 | + /** | ||
98 | + * @cfg {Ext.data.Store} [store] | ||
99 | + * The {@link Ext.data.Store} this list should use as its data source | ||
100 | + * when the data source is **remote**. If the data for the list | ||
101 | + * is local, use the {@link #options} config instead. | ||
102 | + * | ||
103 | + * If neither store nor {@link #options} is specified, then the choices list is automatically | ||
104 | + * populated from all unique values of the specified {@link #dataIndex} field in the store at first | ||
105 | + * time of filter invocation. | ||
106 | + */ | ||
107 | + | ||
108 | + /** | ||
109 | + * @private | ||
110 | + * Template method that is to initialize the filter. | ||
111 | + * @param {Object} config | ||
112 | + */ | ||
113 | + init : function (config) { | ||
114 | + var me = this, | ||
115 | + menu; | ||
116 | + | ||
117 | + me.dt = Ext.create('Ext.util.DelayedTask', me.fireUpdate, me); | ||
118 | + | ||
119 | + // If the List filter is auto-creating its store from the unique values in the grid store (i.e., no `options` or `store` | ||
120 | + // configs), it will need to listen to grid store events to properly sync its options when the grid store changes. | ||
121 | + if (!me.options && !me.store) { | ||
122 | + menu = me.menu; | ||
123 | + // Needed for when options are auto-generated from the grid store. | ||
124 | + // See the comments in #onDataChanged. | ||
125 | + me.autoGeneratedOptions = []; | ||
126 | + | ||
127 | + me.grid.store.on({ | ||
128 | + scope: me, | ||
129 | + datachanged: menu.onDataChanged, | ||
130 | + update: menu.onDataChanged | ||
131 | + }); | ||
132 | + } | ||
133 | + }, | ||
134 | + | ||
135 | + /** | ||
136 | + * @private | ||
137 | + * Creates the Menu for this filter. | ||
138 | + * @param {Object} config Filter configuration | ||
139 | + * @return {Ext.menu.Menu} | ||
140 | + */ | ||
141 | + createMenu: function(config) { | ||
142 | + var menu = Ext.create('Ext.ux.grid.menu.ListMenu', config); | ||
143 | + menu.on('checkchange', this.onCheckChange, this); | ||
144 | + return menu; | ||
145 | + }, | ||
146 | + | ||
147 | + /** | ||
148 | + * @private | ||
149 | + * Template method that is to get and return the value of the filter. | ||
150 | + * @return {String} The value of this filter | ||
151 | + */ | ||
152 | + getValue : function () { | ||
153 | + return this.menu.getSelected(); | ||
154 | + }, | ||
155 | + /** | ||
156 | + * @private | ||
157 | + * Template method that is to set the value of the filter. | ||
158 | + * @param {Object} value The value to set the filter | ||
159 | + */ | ||
160 | + setValue : function (value) { | ||
161 | + this.menu.setSelected(value); | ||
162 | + this.fireEvent('update', this); | ||
163 | + }, | ||
164 | + | ||
165 | + /** | ||
166 | + * Template method that is to return true if the filter | ||
167 | + * has enough configuration information to be activated. | ||
168 | + * @return {Boolean} | ||
169 | + */ | ||
170 | + isActivatable : function () { | ||
171 | + return this.getValue().length > 0; | ||
172 | + }, | ||
173 | + | ||
174 | + /** | ||
175 | + * @private | ||
176 | + * Template method that is to get and return serialized filter data for | ||
177 | + * transmission to the server. | ||
178 | + * @return {Object/Array} An object or collection of objects containing | ||
179 | + * key value pairs representing the current configuration of the filter. | ||
180 | + */ | ||
181 | + getSerialArgs : function () { | ||
182 | + return {type: 'list', value: this.phpMode ? this.getValue().join(',') : this.getValue()}; | ||
183 | + }, | ||
184 | + | ||
185 | + /** @private */ | ||
186 | + onCheckChange : function(){ | ||
187 | + this.dt.delay(this.updateBuffer); | ||
188 | + }, | ||
189 | + | ||
190 | + | ||
191 | + /** | ||
192 | + * Template method that is to validate the provided Ext.data.Record | ||
193 | + * against the filters configuration. | ||
194 | + * @param {Ext.data.Record} record The record to validate | ||
195 | + * @return {Boolean} true if the record is valid within the bounds | ||
196 | + * of the filter, false otherwise. | ||
197 | + */ | ||
198 | + validateRecord : function (record) { | ||
199 | + var valuesArray = this.getValue(); | ||
200 | + return Ext.Array.indexOf(valuesArray, record.get(this.dataIndex)) > -1; | ||
201 | + } | ||
202 | +}); |
@@ -0,0 +1,112 @@ | @@ -0,0 +1,112 @@ | ||
1 | +/** | ||
2 | + * Filters using an Ext.ux.grid.menu.RangeMenu. | ||
3 | + * <p><b><u>Example Usage:</u></b></p> | ||
4 | + * <pre><code> | ||
5 | +var filters = Ext.create('Ext.ux.grid.GridFilters', { | ||
6 | + ... | ||
7 | + filters: [{ | ||
8 | + type: 'numeric', | ||
9 | + dataIndex: 'price' | ||
10 | + }] | ||
11 | +}); | ||
12 | + * </code></pre> | ||
13 | + * <p>Any of the configuration options for {@link Ext.ux.grid.menu.RangeMenu} can also be specified as | ||
14 | + * configurations to NumericFilter, and will be copied over to the internal menu instance automatically.</p> | ||
15 | + */ | ||
16 | +Ext.define('Ext.ux.grid.filter.NumericFilter', { | ||
17 | + extend: 'Ext.ux.grid.filter.Filter', | ||
18 | + alias: 'gridfilter.numeric', | ||
19 | + uses: ['Ext.form.field.Number'], | ||
20 | + | ||
21 | + /** | ||
22 | + * @private | ||
23 | + * Creates the Menu for this filter. | ||
24 | + * @param {Object} config Filter configuration | ||
25 | + * @return {Ext.menu.Menu} | ||
26 | + */ | ||
27 | + createMenu: function(config) { | ||
28 | + var me = this, | ||
29 | + menu; | ||
30 | + menu = Ext.create('Ext.ux.grid.menu.RangeMenu', config); | ||
31 | + menu.on('update', me.fireUpdate, me); | ||
32 | + return menu; | ||
33 | + }, | ||
34 | + | ||
35 | + /** | ||
36 | + * @private | ||
37 | + * Template method that is to get and return the value of the filter. | ||
38 | + * @return {String} The value of this filter | ||
39 | + */ | ||
40 | + getValue : function () { | ||
41 | + return this.menu.getValue(); | ||
42 | + }, | ||
43 | + | ||
44 | + /** | ||
45 | + * @private | ||
46 | + * Template method that is to set the value of the filter. | ||
47 | + * @param {Object} value The value to set the filter | ||
48 | + */ | ||
49 | + setValue : function (value) { | ||
50 | + this.menu.setValue(value); | ||
51 | + }, | ||
52 | + | ||
53 | + /** | ||
54 | + * Template method that is to return <tt>true</tt> if the filter | ||
55 | + * has enough configuration information to be activated. | ||
56 | + * @return {Boolean} | ||
57 | + */ | ||
58 | + isActivatable : function () { | ||
59 | + var values = this.getValue(), | ||
60 | + key; | ||
61 | + for (key in values) { | ||
62 | + if (values[key] !== undefined) { | ||
63 | + return true; | ||
64 | + } | ||
65 | + } | ||
66 | + return false; | ||
67 | + }, | ||
68 | + | ||
69 | + /** | ||
70 | + * @private | ||
71 | + * Template method that is to get and return serialized filter data for | ||
72 | + * transmission to the server. | ||
73 | + * @return {Object/Array} An object or collection of objects containing | ||
74 | + * key value pairs representing the current configuration of the filter. | ||
75 | + */ | ||
76 | + getSerialArgs : function () { | ||
77 | + var key, | ||
78 | + args = [], | ||
79 | + values = this.menu.getValue(); | ||
80 | + for (key in values) { | ||
81 | + args.push({ | ||
82 | + type: 'numeric', | ||
83 | + comparison: key, | ||
84 | + value: values[key] | ||
85 | + }); | ||
86 | + } | ||
87 | + return args; | ||
88 | + }, | ||
89 | + | ||
90 | + /** | ||
91 | + * Template method that is to validate the provided Ext.data.Record | ||
92 | + * against the filters configuration. | ||
93 | + * @param {Ext.data.Record} record The record to validate | ||
94 | + * @return {Boolean} true if the record is valid within the bounds | ||
95 | + * of the filter, false otherwise. | ||
96 | + */ | ||
97 | + validateRecord : function (record) { | ||
98 | + var val = record.get(this.dataIndex), | ||
99 | + values = this.getValue(), | ||
100 | + isNumber = Ext.isNumber; | ||
101 | + if (isNumber(values.eq) && val != values.eq) { | ||
102 | + return false; | ||
103 | + } | ||
104 | + if (isNumber(values.lt) && val >= values.lt) { | ||
105 | + return false; | ||
106 | + } | ||
107 | + if (isNumber(values.gt) && val <= values.gt) { | ||
108 | + return false; | ||
109 | + } | ||
110 | + return true; | ||
111 | + } | ||
112 | +}); |
@@ -0,0 +1,134 @@ | @@ -0,0 +1,134 @@ | ||
1 | +/** | ||
2 | + * Filter by a configurable Ext.form.field.Text | ||
3 | + * <p><b><u>Example Usage:</u></b></p> | ||
4 | + * <pre><code> | ||
5 | +var filters = Ext.create('Ext.ux.grid.GridFilters', { | ||
6 | + ... | ||
7 | + filters: [{ | ||
8 | + // required configs | ||
9 | + type: 'string', | ||
10 | + dataIndex: 'name', | ||
11 | + | ||
12 | + // optional configs | ||
13 | + value: 'foo', | ||
14 | + active: true, // default is false | ||
15 | + iconCls: 'ux-gridfilter-text-icon' // default | ||
16 | + // any Ext.form.field.Text configs accepted | ||
17 | + }] | ||
18 | +}); | ||
19 | + * </code></pre> | ||
20 | + */ | ||
21 | +Ext.define('Ext.ux.grid.filter.StringFilter', { | ||
22 | + extend: 'Ext.ux.grid.filter.Filter', | ||
23 | + alias: 'gridfilter.string', | ||
24 | + | ||
25 | + /** | ||
26 | + * @cfg {String} iconCls | ||
27 | + * The iconCls to be applied to the menu item. | ||
28 | + * Defaults to <tt>'ux-gridfilter-text-icon'</tt>. | ||
29 | + */ | ||
30 | + iconCls : 'ux-gridfilter-text-icon', | ||
31 | + | ||
32 | + emptyText: 'Enter Filter Text...', | ||
33 | + selectOnFocus: true, | ||
34 | + width: 125, | ||
35 | + | ||
36 | + /** | ||
37 | + * @private | ||
38 | + * Template method that is to initialize the filter and install required menu items. | ||
39 | + */ | ||
40 | + init : function (config) { | ||
41 | + Ext.applyIf(config, { | ||
42 | + enableKeyEvents: true, | ||
43 | + labelCls: 'ux-rangemenu-icon ' + this.iconCls, | ||
44 | + hideEmptyLabel: false, | ||
45 | + labelSeparator: '', | ||
46 | + labelWidth: 29, | ||
47 | + listeners: { | ||
48 | + scope: this, | ||
49 | + keyup: this.onInputKeyUp, | ||
50 | + el: { | ||
51 | + click: function(e) { | ||
52 | + e.stopPropagation(); | ||
53 | + } | ||
54 | + } | ||
55 | + } | ||
56 | + }); | ||
57 | + | ||
58 | + this.inputItem = Ext.create('Ext.form.field.Text', config); | ||
59 | + this.menu.add(this.inputItem); | ||
60 | + this.menu.showSeparator = false; | ||
61 | + this.updateTask = Ext.create('Ext.util.DelayedTask', this.fireUpdate, this); | ||
62 | + }, | ||
63 | + | ||
64 | + /** | ||
65 | + * @private | ||
66 | + * Template method that is to get and return the value of the filter. | ||
67 | + * @return {String} The value of this filter | ||
68 | + */ | ||
69 | + getValue : function () { | ||
70 | + return this.inputItem.getValue(); | ||
71 | + }, | ||
72 | + | ||
73 | + /** | ||
74 | + * @private | ||
75 | + * Template method that is to set the value of the filter. | ||
76 | + * @param {Object} value The value to set the filter | ||
77 | + */ | ||
78 | + setValue : function (value) { | ||
79 | + this.inputItem.setValue(value); | ||
80 | + this.fireEvent('update', this); | ||
81 | + }, | ||
82 | + | ||
83 | + /** | ||
84 | + * Template method that is to return <tt>true</tt> if the filter | ||
85 | + * has enough configuration information to be activated. | ||
86 | + * @return {Boolean} | ||
87 | + */ | ||
88 | + isActivatable : function () { | ||
89 | + return this.inputItem.getValue().length > 0; | ||
90 | + }, | ||
91 | + | ||
92 | + /** | ||
93 | + * @private | ||
94 | + * Template method that is to get and return serialized filter data for | ||
95 | + * transmission to the server. | ||
96 | + * @return {Object/Array} An object or collection of objects containing | ||
97 | + * key value pairs representing the current configuration of the filter. | ||
98 | + */ | ||
99 | + getSerialArgs : function () { | ||
100 | + return {type: 'string', value: this.getValue()}; | ||
101 | + }, | ||
102 | + | ||
103 | + /** | ||
104 | + * Template method that is to validate the provided Ext.data.Record | ||
105 | + * against the filters configuration. | ||
106 | + * @param {Ext.data.Record} record The record to validate | ||
107 | + * @return {Boolean} true if the record is valid within the bounds | ||
108 | + * of the filter, false otherwise. | ||
109 | + */ | ||
110 | + validateRecord : function (record) { | ||
111 | + var val = record.get(this.dataIndex); | ||
112 | + | ||
113 | + if(typeof val != 'string') { | ||
114 | + return (this.getValue().length === 0); | ||
115 | + } | ||
116 | + | ||
117 | + return val.toLowerCase().indexOf(this.getValue().toLowerCase()) > -1; | ||
118 | + }, | ||
119 | + | ||
120 | + /** | ||
121 | + * @private | ||
122 | + * Handler method called when there is a keyup event on this.inputItem | ||
123 | + */ | ||
124 | + onInputKeyUp : function (field, e) { | ||
125 | + var k = e.getKey(); | ||
126 | + if (k == e.RETURN && field.isValid()) { | ||
127 | + e.stopEvent(); | ||
128 | + this.menu.hide(); | ||
129 | + return; | ||
130 | + } | ||
131 | + // restart the timer | ||
132 | + this.updateTask.delay(this.updateBuffer); | ||
133 | + } | ||
134 | +}); |
217 Bytes
659 Bytes
359 Bytes
354 Bytes
@@ -0,0 +1,241 @@ | @@ -0,0 +1,241 @@ | ||
1 | +/** | ||
2 | + * This is a supporting class for {@link Ext.ux.grid.filter.ListFilter}. | ||
3 | + * Although not listed as configuration options for this class, this class | ||
4 | + * also accepts all configuration options from {@link Ext.ux.grid.filter.ListFilter}. | ||
5 | + */ | ||
6 | +Ext.define('Ext.ux.grid.menu.ListMenu', { | ||
7 | + extend: 'Ext.menu.Menu', | ||
8 | + | ||
9 | + /** | ||
10 | + * @cfg {String} idField | ||
11 | + * Defaults to 'id'. | ||
12 | + */ | ||
13 | + idField : 'id', | ||
14 | + | ||
15 | + /** | ||
16 | + * @cfg {String} labelField | ||
17 | + * Defaults to 'text'. | ||
18 | + */ | ||
19 | + labelField : 'text', | ||
20 | + /** | ||
21 | + * @cfg {String} paramPrefix | ||
22 | + * Defaults to 'Loading...'. | ||
23 | + */ | ||
24 | + loadingText : 'Loading...', | ||
25 | + /** | ||
26 | + * @cfg {Boolean} loadOnShow | ||
27 | + * Defaults to true. | ||
28 | + */ | ||
29 | + loadOnShow : true, | ||
30 | + /** | ||
31 | + * @cfg {Boolean} single | ||
32 | + * Specify true to group all items in this list into a single-select | ||
33 | + * radio button group. Defaults to false. | ||
34 | + */ | ||
35 | + single : false, | ||
36 | + | ||
37 | + plain: true, | ||
38 | + | ||
39 | + constructor: function (cfg) { | ||
40 | + var me = this, | ||
41 | + gridStore; | ||
42 | + | ||
43 | + me.selected = []; | ||
44 | + me.addEvents( | ||
45 | + /** | ||
46 | + * @event checkchange | ||
47 | + * Fires when there is a change in checked items from this list | ||
48 | + * @param {Object} item Ext.menu.CheckItem | ||
49 | + * @param {Object} checked The checked value that was set | ||
50 | + */ | ||
51 | + 'checkchange' | ||
52 | + ); | ||
53 | + | ||
54 | + me.callParent(arguments); | ||
55 | + | ||
56 | + gridStore = me.grid.store; | ||
57 | + | ||
58 | + if (me.store) { | ||
59 | + me.add({ | ||
60 | + text: me.loadingText, | ||
61 | + iconCls: 'loading-indicator' | ||
62 | + }); | ||
63 | + me.store.on('load', me.onLoad, me); | ||
64 | + | ||
65 | + // A ListMenu which is completely unconfigured acquires its store from the unique values of its field in the store. | ||
66 | + // If there are no records in the grid store, then we know it's async and we need to listen for its 'load' event. | ||
67 | + } else if (gridStore.data.length) { | ||
68 | + me.createMenuStore(); | ||
69 | + } else { | ||
70 | + gridStore.on('load', me.createMenuStore, me, {single: true}); | ||
71 | + } | ||
72 | + }, | ||
73 | + | ||
74 | + destroy : function () { | ||
75 | + var me = this, | ||
76 | + store = me.store; | ||
77 | + | ||
78 | + if (store) { | ||
79 | + if (me.autoStore) { | ||
80 | + store.destroyStore(); | ||
81 | + } else { | ||
82 | + store.un('unload', me.onLoad, me); | ||
83 | + } | ||
84 | + } | ||
85 | + | ||
86 | + if (me.autoGeneratedOptions) { | ||
87 | + me.autoGeneratedOptions = null; | ||
88 | + | ||
89 | + me.grid.store.un({ | ||
90 | + scope: me, | ||
91 | + datachanged: me.onDataChanged, | ||
92 | + update: me.onDataChanged | ||
93 | + }); | ||
94 | + } | ||
95 | + | ||
96 | + me.callParent(); | ||
97 | + }, | ||
98 | + | ||
99 | + /** | ||
100 | + * Lists will initially show a 'loading' item while the data is retrieved from the store. | ||
101 | + * In some cases the loaded data will result in a list that goes off the screen to the | ||
102 | + * right (as placement calculations were done with the loading item). This adapter will | ||
103 | + * allow show to be called with no arguments to show with the previous arguments and | ||
104 | + * thus recalculate the width and potentially hang the menu from the left. | ||
105 | + */ | ||
106 | + show : function () { | ||
107 | + var me = this; | ||
108 | + if (me.loadOnShow && !me.loaded && !me.store.loading) { | ||
109 | + me.store.load(); | ||
110 | + } | ||
111 | + me.callParent(); | ||
112 | + }, | ||
113 | + | ||
114 | + onDataChanged: function (store) { | ||
115 | + // If the menu item options (and the options store) are being auto-generated from the grid store, then it | ||
116 | + // needs to know when the grid store has changed its data so it can remain in sync. | ||
117 | + // | ||
118 | + // We need to gather the `autoGeneratedOptions` every time the menu items are created so we can compare values. | ||
119 | + var autoGeneratedOptions = this.autoGeneratedOptions; | ||
120 | + | ||
121 | + // Note that autoGeneratedOptions won't be populated with values until the menu is shown and the Filter item's | ||
122 | + // items are created. | ||
123 | + if (autoGeneratedOptions) { | ||
124 | + // Get all unique values, including nulls, either from .data or ._source (if filtered) and compare to the | ||
125 | + // unique options gathered when the menu items are instanced. | ||
126 | + if (!Ext.Array.equals(store.collect(this.idField, true, store.isFiltered()).sort(), autoGeneratedOptions.sort())) { | ||
127 | + this.menu.createMenuStore(store); | ||
128 | + } | ||
129 | + } | ||
130 | + }, | ||
131 | + | ||
132 | + /** @private */ | ||
133 | + onLoad: function (store, records) { | ||
134 | + var me = this, | ||
135 | + gid, itemValue, i, len, | ||
136 | + listeners = { | ||
137 | + checkchange: me.checkChange, | ||
138 | + scope: me | ||
139 | + }; | ||
140 | + | ||
141 | + Ext.suspendLayouts(); | ||
142 | + me.removeAll(true); | ||
143 | + gid = me.single ? Ext.id() : null; | ||
144 | + for (i = 0, len = records.length; i < len; i++) { | ||
145 | + itemValue = records[i].get(me.idField); | ||
146 | + me.add(Ext.create('Ext.menu.CheckItem', { | ||
147 | + text: records[i].get(me.labelField), | ||
148 | + group: gid, | ||
149 | + checked: Ext.Array.contains(me.selected, itemValue), | ||
150 | + hideOnClick: false, | ||
151 | + value: itemValue, | ||
152 | + listeners: listeners | ||
153 | + })); | ||
154 | + } | ||
155 | + | ||
156 | + me.loaded = true; | ||
157 | + Ext.resumeLayouts(true); | ||
158 | + me.fireEvent('load', me, records); | ||
159 | + }, | ||
160 | + | ||
161 | + createMenuStore: function () { | ||
162 | + var me = this, | ||
163 | + options = me.options || me.grid.store.collect(me.dataIndex, false, true), | ||
164 | + i = 0, | ||
165 | + len = options.length, | ||
166 | + storeOptions = [], | ||
167 | + idField = me.idField, | ||
168 | + labelField = me.labelField, | ||
169 | + value; | ||
170 | + | ||
171 | + for (; i < len; i++) { | ||
172 | + value = options[i]; | ||
173 | + | ||
174 | + switch (Ext.type(value)) { | ||
175 | + case 'array': | ||
176 | + storeOptions.push(value); | ||
177 | + break; | ||
178 | + case 'object': | ||
179 | + storeOptions.push([value[idField], value[labelField]]); | ||
180 | + break; | ||
181 | + default: | ||
182 | + if (value != null) { | ||
183 | + storeOptions.push([value, value]); | ||
184 | + } | ||
185 | + } | ||
186 | + } | ||
187 | + | ||
188 | + me.store = Ext.create('Ext.data.ArrayStore', { | ||
189 | + fields: [idField, labelField], | ||
190 | + data: storeOptions, | ||
191 | + listeners: { | ||
192 | + load: me.onLoad, | ||
193 | + scope: me | ||
194 | + } | ||
195 | + }); | ||
196 | + | ||
197 | + me.loaded = true; | ||
198 | + me.autoStore = true; | ||
199 | + }, | ||
200 | + | ||
201 | + /** | ||
202 | + * Get the selected items. | ||
203 | + * @return {Array} selected | ||
204 | + */ | ||
205 | + getSelected : function () { | ||
206 | + return this.selected; | ||
207 | + }, | ||
208 | + | ||
209 | + /** @private */ | ||
210 | + setSelected : function (value) { | ||
211 | + value = this.selected = [].concat(value); | ||
212 | + | ||
213 | + if (this.loaded) { | ||
214 | + this.items.each(function(item){ | ||
215 | + item.setChecked(false, true); | ||
216 | + for (var i = 0, len = value.length; i < len; i++) { | ||
217 | + if (item.value == value[i]) { | ||
218 | + item.setChecked(true, true); | ||
219 | + } | ||
220 | + } | ||
221 | + }); | ||
222 | + } | ||
223 | + }, | ||
224 | + | ||
225 | + /** | ||
226 | + * Handler for the 'checkchange' event from an check item in this menu | ||
227 | + * @param {Object} item Ext.menu.CheckItem | ||
228 | + * @param {Object} checked The checked value that was set | ||
229 | + */ | ||
230 | + checkChange : function (item, checked) { | ||
231 | + var value = []; | ||
232 | + this.items.each(function(item){ | ||
233 | + if (item.checked) { | ||
234 | + value.push(item.value); | ||
235 | + } | ||
236 | + }); | ||
237 | + this.selected = value; | ||
238 | + | ||
239 | + this.fireEvent('checkchange', item, checked); | ||
240 | + } | ||
241 | +}); |
@@ -0,0 +1,260 @@ | @@ -0,0 +1,260 @@ | ||
1 | +/** | ||
2 | + * Custom implementation of {@link Ext.menu.Menu} that has preconfigured items for entering numeric | ||
3 | + * range comparison values: less-than, greater-than, and equal-to. This is used internally | ||
4 | + * by {@link Ext.ux.grid.filter.NumericFilter} to create its menu. | ||
5 | + */ | ||
6 | +Ext.define('Ext.ux.grid.menu.RangeMenu', { | ||
7 | + extend: 'Ext.menu.Menu', | ||
8 | + | ||
9 | + /** | ||
10 | + * @cfg {String} fieldCls | ||
11 | + * The Class to use to construct each field item within this menu | ||
12 | + * Defaults to:<pre> | ||
13 | + * fieldCls : Ext.form.field.Number | ||
14 | + * </pre> | ||
15 | + */ | ||
16 | + fieldCls : 'Ext.form.field.Number', | ||
17 | + | ||
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 | + /** | ||
34 | + * @cfg {Object} fields | ||
35 | + * The field items may be configured individually | ||
36 | + * Defaults to <tt>undefined</tt>. | ||
37 | + * Example usage: | ||
38 | + * <pre><code> | ||
39 | +fields : { | ||
40 | + gt: { // override fieldCfg options | ||
41 | + width: 200, | ||
42 | + fieldCls: Ext.ux.form.CustomNumberField // to override default {@link #fieldCls} | ||
43 | + } | ||
44 | +}, | ||
45 | + * </code></pre> | ||
46 | + */ | ||
47 | + | ||
48 | + /** | ||
49 | + * @cfg {Object} itemIconCls | ||
50 | + * The itemIconCls to be applied to each comparator field item. | ||
51 | + * Defaults to:<pre> | ||
52 | +itemIconCls : { | ||
53 | + gt : 'ux-rangemenu-gt', | ||
54 | + lt : 'ux-rangemenu-lt', | ||
55 | + eq : 'ux-rangemenu-eq' | ||
56 | +} | ||
57 | + * </pre> | ||
58 | + */ | ||
59 | + itemIconCls : { | ||
60 | + gt : 'ux-rangemenu-gt', | ||
61 | + lt : 'ux-rangemenu-lt', | ||
62 | + eq : 'ux-rangemenu-eq' | ||
63 | + }, | ||
64 | + | ||
65 | + /** | ||
66 | + * @cfg {Object} fieldLabels | ||
67 | + * Accessible label text for each comparator field item. Can be overridden by localization | ||
68 | + * files. Defaults to:<pre> | ||
69 | +fieldLabels : { | ||
70 | + gt: 'Greater Than', | ||
71 | + lt: 'Less Than', | ||
72 | + eq: 'Equal To' | ||
73 | +}</pre> | ||
74 | + */ | ||
75 | + fieldLabels: { | ||
76 | + gt: 'Greater Than', | ||
77 | + lt: 'Less Than', | ||
78 | + eq: 'Equal To' | ||
79 | + }, | ||
80 | + | ||
81 | + /** | ||
82 | + * @cfg {Object} menuItemCfgs | ||
83 | + * Default configuration options for each menu item | ||
84 | + * Defaults to:<pre> | ||
85 | +menuItemCfgs : { | ||
86 | + emptyText: 'Enter Filter Text...', | ||
87 | + selectOnFocus: true, | ||
88 | + width: 125 | ||
89 | +} | ||
90 | + * </pre> | ||
91 | + */ | ||
92 | + menuItemCfgs : { | ||
93 | + emptyText: 'Enter Number...', | ||
94 | + selectOnFocus: false, | ||
95 | + width: 155 | ||
96 | + }, | ||
97 | + | ||
98 | + /** | ||
99 | + * @cfg {Array} menuItems | ||
100 | + * The items to be shown in this menu. Items are added to the menu | ||
101 | + * according to their position within this array. Defaults to:<pre> | ||
102 | + * menuItems : ['lt','gt','-','eq'] | ||
103 | + * </pre> | ||
104 | + */ | ||
105 | + menuItems : ['lt', 'gt', '-', 'eq'], | ||
106 | + | ||
107 | + plain: true, | ||
108 | + | ||
109 | + constructor : function (config) { | ||
110 | + var me = this, | ||
111 | + fields, fieldCfg, i, len, item, cfg, Cls; | ||
112 | + | ||
113 | + me.callParent(arguments); | ||
114 | + | ||
115 | + fields = me.fields = me.fields || {}; | ||
116 | + fieldCfg = me.fieldCfg = me.fieldCfg || {}; | ||
117 | + | ||
118 | + me.addEvents( | ||
119 | + /** | ||
120 | + * @event update | ||
121 | + * Fires when a filter configuration has changed | ||
122 | + * @param {Ext.ux.grid.filter.Filter} this The filter object. | ||
123 | + */ | ||
124 | + 'update' | ||
125 | + ); | ||
126 | + | ||
127 | + me.updateTask = Ext.create('Ext.util.DelayedTask', me.fireUpdate, me); | ||
128 | + | ||
129 | + for (i = 0, len = me.menuItems.length; i < len; i++) { | ||
130 | + item = me.menuItems[i]; | ||
131 | + if (item !== '-') { | ||
132 | + // defaults | ||
133 | + cfg = { | ||
134 | + itemId: 'range-' + item, | ||
135 | + enableKeyEvents: true, | ||
136 | + hideEmptyLabel: false, | ||
137 | + labelCls: 'ux-rangemenu-icon ' + me.itemIconCls[item], | ||
138 | + labelSeparator: '', | ||
139 | + labelWidth: 29, | ||
140 | + listeners: { | ||
141 | + scope: me, | ||
142 | + change: me.onInputChange, | ||
143 | + keyup: me.onInputKeyUp, | ||
144 | + el: { | ||
145 | + click: this.stopFn | ||
146 | + } | ||
147 | + }, | ||
148 | + activate: Ext.emptyFn, | ||
149 | + deactivate: Ext.emptyFn | ||
150 | + }; | ||
151 | + Ext.apply( | ||
152 | + cfg, | ||
153 | + // custom configs | ||
154 | + Ext.applyIf(fields[item] || {}, fieldCfg[item]), | ||
155 | + // configurable defaults | ||
156 | + me.menuItemCfgs | ||
157 | + ); | ||
158 | + Cls = cfg.fieldCls || me.fieldCls; | ||
159 | + item = fields[item] = Ext.create(Cls, cfg); | ||
160 | + } | ||
161 | + me.add(item); | ||
162 | + } | ||
163 | + }, | ||
164 | + | ||
165 | + stopFn: function(e) { | ||
166 | + e.stopPropagation(); | ||
167 | + }, | ||
168 | + | ||
169 | + /** | ||
170 | + * @private | ||
171 | + * called by this.updateTask | ||
172 | + */ | ||
173 | + fireUpdate : function () { | ||
174 | + this.fireEvent('update', this); | ||
175 | + }, | ||
176 | + | ||
177 | + /** | ||
178 | + * Get and return the value of the filter. | ||
179 | + * @return {String} The value of this filter | ||
180 | + */ | ||
181 | + getValue : function () { | ||
182 | + var result = {}, | ||
183 | + fields = this.fields, | ||
184 | + key, field; | ||
185 | + | ||
186 | + for (key in fields) { | ||
187 | + if (fields.hasOwnProperty(key)) { | ||
188 | + field = fields[key]; | ||
189 | + if (field.isValid() && field.getValue() !== null) { | ||
190 | + result[key] = field.getValue(); | ||
191 | + } | ||
192 | + } | ||
193 | + } | ||
194 | + return result; | ||
195 | + }, | ||
196 | + | ||
197 | + /** | ||
198 | + * Set the value of this menu and fires the 'update' event. | ||
199 | + * @param {Object} data The data to assign to this menu | ||
200 | + */ | ||
201 | + setValue : function (data) { | ||
202 | + var me = this, | ||
203 | + fields = me.fields, | ||
204 | + key, | ||
205 | + field; | ||
206 | + | ||
207 | + for (key in fields) { | ||
208 | + if (fields.hasOwnProperty(key)) { | ||
209 | + // Prevent field's change event from tiggering a Store filter. The final upate event will do that | ||
210 | + field =fields[key]; | ||
211 | + field.suspendEvents(); | ||
212 | + field.setValue(key in data ? data[key] : ''); | ||
213 | + field.resumeEvents(); | ||
214 | + } | ||
215 | + } | ||
216 | + | ||
217 | + // Trigger the filering of the Store | ||
218 | + me.fireEvent('update', me); | ||
219 | + }, | ||
220 | + | ||
221 | + /** | ||
222 | + * @private | ||
223 | + * Handler method called when there is a keyup event on an input | ||
224 | + * item of this menu. | ||
225 | + */ | ||
226 | + onInputKeyUp: function(field, e) { | ||
227 | + if (e.getKey() === e.RETURN && field.isValid()) { | ||
228 | + e.stopEvent(); | ||
229 | + this.hide(); | ||
230 | + } | ||
231 | + }, | ||
232 | + | ||
233 | + /** | ||
234 | + * @private | ||
235 | + * Handler method called when the user changes the value of one of the input | ||
236 | + * items in this menu. | ||
237 | + */ | ||
238 | + onInputChange: function(field) { | ||
239 | + var me = this, | ||
240 | + fields = me.fields, | ||
241 | + eq = fields.eq, | ||
242 | + gt = fields.gt, | ||
243 | + lt = fields.lt; | ||
244 | + | ||
245 | + if (field == eq) { | ||
246 | + if (gt) { | ||
247 | + gt.setValue(null); | ||
248 | + } | ||
249 | + if (lt) { | ||
250 | + lt.setValue(null); | ||
251 | + } | ||
252 | + } | ||
253 | + else { | ||
254 | + eq.setValue(null); | ||
255 | + } | ||
256 | + | ||
257 | + // restart the timer | ||
258 | + this.updateTask.delay(this.updateBuffer); | ||
259 | + } | ||
260 | +}); |