extjs-mvc 0.4.0.j → 0.4.0.k

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. data/Rakefile +1 -1
  2. data/VERSION +1 -1
  3. data/lib/extjs-mvc.rb +0 -14
  4. data/lib/extjs-mvc/api.rb +14 -27
  5. data/lib/extjs-mvc/src/App.js +219 -0
  6. data/lib/extjs-mvc/src/MVC.js +260 -0
  7. data/lib/extjs-mvc/src/Presenter.js +52 -0
  8. data/lib/extjs-mvc/src/README.rdoc +69 -0
  9. data/lib/extjs-mvc/src/controller/Controller.js +278 -0
  10. data/lib/extjs-mvc/src/controller/CrudController.js +460 -0
  11. data/lib/extjs-mvc/src/lib/Array.js +26 -0
  12. data/lib/extjs-mvc/src/lib/Booter.js +417 -0
  13. data/lib/extjs-mvc/src/lib/ClassManager.js +191 -0
  14. data/lib/extjs-mvc/src/lib/ControllerClassManager.js +95 -0
  15. data/lib/extjs-mvc/src/lib/Dependencies.js +44 -0
  16. data/lib/extjs-mvc/src/lib/DispatchMatcher.js +98 -0
  17. data/lib/extjs-mvc/src/lib/Dispatcher.js +129 -0
  18. data/lib/extjs-mvc/src/lib/Environment.js +43 -0
  19. data/lib/extjs-mvc/src/lib/Inflector.js +155 -0
  20. data/lib/extjs-mvc/src/lib/ModelClassManager.js +19 -0
  21. data/lib/extjs-mvc/src/lib/Route.js +139 -0
  22. data/lib/extjs-mvc/src/lib/Router.js +282 -0
  23. data/lib/extjs-mvc/src/lib/String.js +94 -0
  24. data/lib/extjs-mvc/src/lib/ViewClassManager.js +229 -0
  25. data/lib/extjs-mvc/src/lib/notes.txt +32 -0
  26. data/lib/extjs-mvc/src/model/AdapterManager.js +30 -0
  27. data/lib/extjs-mvc/src/model/Association.js +26 -0
  28. data/lib/extjs-mvc/src/model/Base.js +63 -0
  29. data/lib/extjs-mvc/src/model/BelongsToAssociation.js +116 -0
  30. data/lib/extjs-mvc/src/model/Cache.js +131 -0
  31. data/lib/extjs-mvc/src/model/HasManyAssociation.js +160 -0
  32. data/lib/extjs-mvc/src/model/Model.js +331 -0
  33. data/lib/extjs-mvc/src/model/UrlBuilder.js +106 -0
  34. data/lib/extjs-mvc/src/model/adapters/AbstractAdapter.js +296 -0
  35. data/lib/extjs-mvc/src/model/adapters/MemoryAdapter.js +103 -0
  36. data/lib/extjs-mvc/src/model/adapters/RESTAdapter.js +345 -0
  37. data/lib/extjs-mvc/src/model/adapters/RESTJSONAdapter.js +68 -0
  38. data/lib/extjs-mvc/src/model/adapters/notes.txt +42 -0
  39. data/lib/extjs-mvc/src/model/associations/Association.js +192 -0
  40. data/lib/extjs-mvc/src/model/associations/notes.txt +87 -0
  41. data/lib/extjs-mvc/src/model/validations/Errors.js +136 -0
  42. data/lib/extjs-mvc/src/model/validations/Plugin.js +139 -0
  43. data/lib/extjs-mvc/src/model/validations/Validations.js +276 -0
  44. data/lib/extjs-mvc/src/notes/Charts.graffle +0 -0
  45. data/lib/extjs-mvc/src/overrides/Ext.Component.js +21 -0
  46. data/lib/extjs-mvc/src/overrides/Ext.extend.js +142 -0
  47. data/lib/extjs-mvc/src/spec/Array.spec.js +15 -0
  48. data/lib/extjs-mvc/src/spec/ExtMVC.spec.js +65 -0
  49. data/lib/extjs-mvc/src/spec/Model.spec.js +370 -0
  50. data/lib/extjs-mvc/src/spec/OS.spec.js +83 -0
  51. data/lib/extjs-mvc/src/spec/Router.spec.js +99 -0
  52. data/lib/extjs-mvc/src/spec/SpecHelper.js +106 -0
  53. data/lib/extjs-mvc/src/spec/String.spec.js +83 -0
  54. data/lib/extjs-mvc/src/spec/model/AbstractAdapter.spec.js +49 -0
  55. data/lib/extjs-mvc/src/spec/model/Associations.spec.js +99 -0
  56. data/lib/extjs-mvc/src/spec/model/Cache.spec.js +5 -0
  57. data/lib/extjs-mvc/src/spec/model/RESTAdapter.spec.js +19 -0
  58. data/lib/extjs-mvc/src/spec/model/ValidationErrors.spec.js +64 -0
  59. data/lib/extjs-mvc/src/spec/model/Validations.spec.js +166 -0
  60. data/lib/extjs-mvc/src/spec/model/ValidationsPlugin.spec.js +108 -0
  61. data/lib/extjs-mvc/src/spec/suite.html +60 -0
  62. data/lib/extjs-mvc/src/specs-old/JSSpec.css +216 -0
  63. data/lib/extjs-mvc/src/specs-old/JSSpec.js +1512 -0
  64. data/lib/extjs-mvc/src/specs-old/all.html +66 -0
  65. data/lib/extjs-mvc/src/specs-old/base.js +14 -0
  66. data/lib/extjs-mvc/src/specs-old/controller.js +17 -0
  67. data/lib/extjs-mvc/src/specs-old/diff_match_patch.js +1 -0
  68. data/lib/extjs-mvc/src/specs-old/model.js +70 -0
  69. data/lib/extjs-mvc/src/specs-old/route.js +38 -0
  70. data/lib/extjs-mvc/src/specs-old/router.js +59 -0
  71. data/lib/extjs-mvc/src/specs-old/string.js +22 -0
  72. data/lib/extjs-mvc/src/testrunner/JSpecFormatter.js +111 -0
  73. data/lib/extjs-mvc/src/testrunner/TestClient.js +181 -0
  74. data/lib/extjs-mvc/src/testrunner/TestGrid.js +351 -0
  75. data/lib/extjs-mvc/src/testrunner/TestRunner.js +110 -0
  76. data/lib/extjs-mvc/src/testrunner/TestViewport.js +94 -0
  77. data/lib/extjs-mvc/src/vendor.yml +30 -0
  78. data/lib/extjs-mvc/src/vendor/ext-3.1.1/vendor.yml +16 -0
  79. data/lib/extjs-mvc/src/view/FormWindow.js +184 -0
  80. data/lib/extjs-mvc/src/view/HasManyEditorGridPanel.js +211 -0
  81. data/lib/extjs-mvc/src/view/scaffold/Edit.js +46 -0
  82. data/lib/extjs-mvc/src/view/scaffold/Index.js +561 -0
  83. data/lib/extjs-mvc/src/view/scaffold/New.js +20 -0
  84. data/lib/extjs-mvc/src/view/scaffold/ScaffoldFormPanel.js +255 -0
  85. data/lib/{vendor.yml → extjs-mvc/vendor.yml} +0 -0
  86. data/test/app/vendor/extjs-mvc/App.js +219 -0
  87. data/test/app/vendor/extjs-mvc/MVC.js +260 -0
  88. data/test/app/vendor/extjs-mvc/Presenter.js +52 -0
  89. data/test/app/vendor/extjs-mvc/README.rdoc +69 -0
  90. data/test/app/vendor/extjs-mvc/controller/Controller.js +278 -0
  91. data/test/app/vendor/extjs-mvc/controller/CrudController.js +460 -0
  92. data/test/app/vendor/extjs-mvc/lib/Array.js +26 -0
  93. data/test/app/vendor/extjs-mvc/lib/Booter.js +417 -0
  94. data/test/app/vendor/extjs-mvc/lib/ClassManager.js +191 -0
  95. data/test/app/vendor/extjs-mvc/lib/ControllerClassManager.js +95 -0
  96. data/test/app/vendor/extjs-mvc/lib/Dependencies.js +44 -0
  97. data/test/app/vendor/extjs-mvc/lib/DispatchMatcher.js +98 -0
  98. data/test/app/vendor/extjs-mvc/lib/Dispatcher.js +129 -0
  99. data/test/app/vendor/extjs-mvc/lib/Environment.js +43 -0
  100. data/test/app/vendor/extjs-mvc/lib/Inflector.js +155 -0
  101. data/test/app/vendor/extjs-mvc/lib/ModelClassManager.js +19 -0
  102. data/test/app/vendor/extjs-mvc/lib/Route.js +139 -0
  103. data/test/app/vendor/extjs-mvc/lib/Router.js +282 -0
  104. data/test/app/vendor/extjs-mvc/lib/String.js +94 -0
  105. data/test/app/vendor/extjs-mvc/lib/ViewClassManager.js +229 -0
  106. data/test/app/vendor/extjs-mvc/lib/notes.txt +32 -0
  107. data/test/app/vendor/extjs-mvc/model/AdapterManager.js +30 -0
  108. data/test/app/vendor/extjs-mvc/model/Association.js +26 -0
  109. data/test/app/vendor/extjs-mvc/model/Base.js +63 -0
  110. data/test/app/vendor/extjs-mvc/model/BelongsToAssociation.js +116 -0
  111. data/test/app/vendor/extjs-mvc/model/Cache.js +131 -0
  112. data/test/app/vendor/extjs-mvc/model/HasManyAssociation.js +160 -0
  113. data/test/app/vendor/extjs-mvc/model/Model.js +331 -0
  114. data/test/app/vendor/extjs-mvc/model/UrlBuilder.js +106 -0
  115. data/test/app/vendor/extjs-mvc/model/adapters/AbstractAdapter.js +296 -0
  116. data/test/app/vendor/extjs-mvc/model/adapters/MemoryAdapter.js +103 -0
  117. data/test/app/vendor/extjs-mvc/model/adapters/RESTAdapter.js +345 -0
  118. data/test/app/vendor/extjs-mvc/model/adapters/RESTJSONAdapter.js +68 -0
  119. data/test/app/vendor/extjs-mvc/model/adapters/notes.txt +42 -0
  120. data/test/app/vendor/extjs-mvc/model/associations/Association.js +192 -0
  121. data/test/app/vendor/extjs-mvc/model/associations/notes.txt +87 -0
  122. data/test/app/vendor/extjs-mvc/model/validations/Errors.js +136 -0
  123. data/test/app/vendor/extjs-mvc/model/validations/Plugin.js +139 -0
  124. data/test/app/vendor/extjs-mvc/model/validations/Validations.js +276 -0
  125. data/test/app/vendor/extjs-mvc/notes/Charts.graffle +0 -0
  126. data/test/app/vendor/extjs-mvc/overrides/Ext.Component.js +21 -0
  127. data/test/app/vendor/extjs-mvc/overrides/Ext.extend.js +142 -0
  128. data/test/app/vendor/extjs-mvc/spec/Array.spec.js +15 -0
  129. data/test/app/vendor/extjs-mvc/spec/ExtMVC.spec.js +65 -0
  130. data/test/app/vendor/extjs-mvc/spec/Model.spec.js +370 -0
  131. data/test/app/vendor/extjs-mvc/spec/OS.spec.js +83 -0
  132. data/test/app/vendor/extjs-mvc/spec/Router.spec.js +99 -0
  133. data/test/app/vendor/extjs-mvc/spec/SpecHelper.js +106 -0
  134. data/test/app/vendor/extjs-mvc/spec/String.spec.js +83 -0
  135. data/test/app/vendor/extjs-mvc/spec/model/AbstractAdapter.spec.js +49 -0
  136. data/test/app/vendor/extjs-mvc/spec/model/Associations.spec.js +99 -0
  137. data/test/app/vendor/extjs-mvc/spec/model/Cache.spec.js +5 -0
  138. data/test/app/vendor/extjs-mvc/spec/model/RESTAdapter.spec.js +19 -0
  139. data/test/app/vendor/extjs-mvc/spec/model/ValidationErrors.spec.js +64 -0
  140. data/test/app/vendor/extjs-mvc/spec/model/Validations.spec.js +166 -0
  141. data/test/app/vendor/extjs-mvc/spec/model/ValidationsPlugin.spec.js +108 -0
  142. data/test/app/vendor/extjs-mvc/spec/suite.html +60 -0
  143. data/test/app/vendor/extjs-mvc/specs-old/JSSpec.css +216 -0
  144. data/test/app/vendor/extjs-mvc/specs-old/JSSpec.js +1512 -0
  145. data/test/app/vendor/extjs-mvc/specs-old/all.html +66 -0
  146. data/test/app/vendor/extjs-mvc/specs-old/base.js +14 -0
  147. data/test/app/vendor/extjs-mvc/specs-old/controller.js +17 -0
  148. data/test/app/vendor/extjs-mvc/specs-old/diff_match_patch.js +1 -0
  149. data/test/app/vendor/extjs-mvc/specs-old/model.js +70 -0
  150. data/test/app/vendor/extjs-mvc/specs-old/route.js +38 -0
  151. data/test/app/vendor/extjs-mvc/specs-old/router.js +59 -0
  152. data/test/app/vendor/extjs-mvc/specs-old/string.js +22 -0
  153. data/test/app/vendor/extjs-mvc/testrunner/JSpecFormatter.js +111 -0
  154. data/test/app/vendor/extjs-mvc/testrunner/TestClient.js +181 -0
  155. data/test/app/vendor/extjs-mvc/testrunner/TestGrid.js +351 -0
  156. data/test/app/vendor/extjs-mvc/testrunner/TestRunner.js +110 -0
  157. data/test/app/vendor/extjs-mvc/testrunner/TestViewport.js +94 -0
  158. data/test/app/vendor/extjs-mvc/vendor.yml +30 -0
  159. data/test/app/vendor/extjs-mvc/vendor/ext-3.1.1/vendor.yml +16 -0
  160. data/test/app/vendor/extjs-mvc/view/FormWindow.js +184 -0
  161. data/test/app/vendor/extjs-mvc/view/HasManyEditorGridPanel.js +211 -0
  162. data/test/app/vendor/extjs-mvc/view/scaffold/Edit.js +46 -0
  163. data/test/app/vendor/extjs-mvc/view/scaffold/Index.js +561 -0
  164. data/test/app/vendor/extjs-mvc/view/scaffold/New.js +20 -0
  165. data/test/app/vendor/extjs-mvc/view/scaffold/ScaffoldFormPanel.js +255 -0
  166. data/test/helper.rb +7 -1
  167. data/test/test_extjs-mvc.rb +46 -0
  168. metadata +167 -7
  169. data/test/test_extjs-mvc-gem.rb +0 -7
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @class ExtMVC.view.scaffold.Edit
3
+ * @extends ExtMVC.view.scaffold.ScaffoldFormPanel
4
+ * Shows a generic edit form for a given model
5
+ */
6
+ ExtMVC.registerView('scaffold', 'edit', {
7
+ xtype : 'scaffold_form',
8
+ registerXType: 'scaffold_edit',
9
+
10
+ /**
11
+ * Sets the panel's title, if not already set
12
+ */
13
+ initComponent: function() {
14
+ Ext.applyIf(this, {
15
+ title: 'Edit ' + this.model.prototype.singularHumanName
16
+ });
17
+
18
+ ExtMVC.getView('scaffold', 'form').prototype.initComponent.apply(this, arguments);
19
+ },
20
+
21
+ /**
22
+ * Loads the given record into the form and maintains a reference to it so that it can be returned
23
+ * when the 'save' event is fired
24
+ * @param {ExtMVC.Model.Base} instance The model instance to load into this form
25
+ */
26
+ loadRecord: function(instance) {
27
+ this.instance = instance;
28
+ this.getForm().loadRecord(instance);
29
+ },
30
+
31
+ /**
32
+ * Called when the save button is clicked or CTRL + s pressed. By default this simply fires
33
+ * the 'save' event, passing this.getForm().getValues() as the sole argument
34
+ */
35
+ onSave: function() {
36
+ this.fireEvent('save', this.instance, this.getFormValues(), this);
37
+ }
38
+
39
+ /**
40
+ * @event save
41
+ * Fired when the user clicks the save button, or presses ctrl + s
42
+ * @param {ExtMVC.model.Base} instance The existing instance that is to be updated
43
+ * @param {Object} values The values entered into the form
44
+ * @param {ExtMVC.view.scaffold.ScaffoldFormPanel} this The form panel
45
+ */
46
+ });
@@ -0,0 +1,561 @@
1
+ /**
2
+ * @class ExtMVC.view.scaffold.Index
3
+ * @extends Ext.grid.GridPanel
4
+ * A default index view for a scaffold (a paging grid with double-click to edit)
5
+ */
6
+ // ExtMVC.view.scaffold.Index = Ext.extend(Ext.grid.GridPanel, {
7
+ ExtMVC.registerView('scaffold', 'index', {
8
+ xtype : 'grid',
9
+ registerXType: 'scaffold_grid',
10
+
11
+ constructor: function(config) {
12
+ config = config || {};
13
+
14
+ this.model = config.model;
15
+
16
+ if (this.model == undefined) throw new Error("No model supplied to scaffold Index view");
17
+
18
+ this.controller = this.controller || config.controller;
19
+
20
+ //we can't put these in applyIf block below as the functions are executed immediately
21
+ if (config.columns == undefined && config.colModel == undefined && config.cm == undefined) {
22
+ config.columns = this.buildColumns(this.model);
23
+ }
24
+ config.store = config.store || this.model.find();
25
+
26
+ Ext.applyIf(config, {
27
+ viewConfig: { forceFit: true },
28
+ id: String.format("{0}_index", this.model.prototype.tableName),
29
+
30
+ loadMask: true,
31
+
32
+ /**
33
+ * @property dblClickToEdit
34
+ * @type Boolean
35
+ * True to edit a record when it is double clicked (defaults to true)
36
+ */
37
+ dblClickToEdit: true
38
+ });
39
+
40
+ Ext.grid.GridPanel.prototype.constructor.call(this, config);
41
+
42
+ this.initListeners();
43
+ },
44
+
45
+ initComponent: function() {
46
+ var tbarConfig = this.hasTopToolbar ? this.buildTopToolbar() : null;
47
+ var bbar = this.hasBottomToolbar ? this.buildBottomToolbar(this.store) : null;
48
+
49
+ Ext.applyIf(this, {
50
+ title: this.getTitle(),
51
+ tbar: tbarConfig,
52
+ bbar: bbar,
53
+
54
+ keys: [
55
+ {
56
+ key: 'a',
57
+ scope: this,
58
+ handler: this.onAdd
59
+ },
60
+ {
61
+ key: 'e',
62
+ scope: this,
63
+ handler: this.onEdit
64
+ },
65
+ {
66
+ key: Ext.EventObject.DELETE,
67
+ scope: this,
68
+ handler: this.onDelete
69
+ }
70
+ ]
71
+ });
72
+
73
+ Ext.grid.GridPanel.prototype.initComponent.apply(this, arguments);
74
+ },
75
+
76
+ /**
77
+ * Sets up events emitted by the grid panel
78
+ */
79
+ initEvents: function() {
80
+ this.addEvents(
81
+ /**
82
+ * @event edit
83
+ * Fired when the user wishes to edit a particular record
84
+ * @param {ExtMVC.Model.Base} instance The instance of the model the user wishes to edit
85
+ */
86
+ 'edit',
87
+
88
+ /**
89
+ * @event new
90
+ * Fired when the user wishes to add a new record
91
+ */
92
+ 'new',
93
+
94
+ /**
95
+ * @event delete
96
+ * Fired when the user wishes to destroy a particular record
97
+ * @param {ExtMVC.Model.Base} instance The instance fo the model the user wishes to destroy
98
+ */
99
+ 'delete'
100
+ );
101
+
102
+ Ext.grid.GridPanel.prototype.initEvents.apply(this, arguments);
103
+ },
104
+
105
+ /**
106
+ * Listens to clicks in the grid and contained components and takes action accordingly.
107
+ * Mostly, this is simply a case of capturing events received and re-emitting normalized events
108
+ */
109
+ initListeners: function() {
110
+ if (this.dblClickToEdit === true) {
111
+ this.on({
112
+ scope : this,
113
+ 'rowdblclick': this.onEdit
114
+ });
115
+ }
116
+
117
+ if (this.controller != undefined) {
118
+ this.controller.on('delete', this.refreshStore, this);
119
+ }
120
+ },
121
+
122
+ //removes any controller listeners added by initListeners
123
+ destroy: function() {
124
+ if (this.controller != undefined) {
125
+ this.controller.un('delete', this.refreshStore, this);
126
+ }
127
+
128
+ Ext.grid.GridPanel.prototype.destroy.apply(this, arguments);
129
+ },
130
+
131
+ /**
132
+ * Calls reload on the grid's store
133
+ */
134
+ refreshStore: function() {
135
+ //NOTE: For some reason this.store is undefined here, but getCmp on this.id works :/
136
+ var store = Ext.getCmp(this.id).store;
137
+ store.reload();
138
+ },
139
+
140
+ /**
141
+ * Returns the title to give to this grid. If this view is currently representing a model called User,
142
+ * this will return "All Users". Override to set your own grid title
143
+ * @return {String} The title to give the grid
144
+ */
145
+ getTitle: function() {
146
+ return String.format("All {0}", this.model.prototype.pluralHumanName);
147
+ },
148
+
149
+ /**
150
+ * @property preferredColumns
151
+ * @type Array
152
+ * An array of columns to show first in the grid, if they exist
153
+ * Overwrite ExtMVC.view.scaffold.Index.preferredColumns if required
154
+ */
155
+ preferredColumns: ['id', 'title', 'name', 'first_name', 'last_name', 'login', 'username', 'email', 'email_address', 'content', 'message', 'body'],
156
+
157
+ /**
158
+ * @property ignoreColumns
159
+ * @type Array
160
+ * An array of columns not to show in the grid (defaults to empty)
161
+ */
162
+ ignoreColumns: ['password', 'password_confirmation'],
163
+
164
+ /**
165
+ * @property useColumns
166
+ * @type Array
167
+ * An array of fields to use to generate the column model. This defaults to undefined, but if added in a
168
+ * subclass then these fields are used to make the column model.
169
+ */
170
+ useColumns: undefined,
171
+
172
+ /**
173
+ * @property narrowColumns
174
+ * @type Array
175
+ * An array of columns to render at half the average width
176
+ */
177
+ narrowColumns: ['id'],
178
+
179
+ /**
180
+ * @property wideColumns
181
+ * @type Array
182
+ * An array of columns to render at double the average width
183
+ */
184
+ wideColumns: ['message', 'content', 'description', 'bio', 'body'],
185
+
186
+ /**
187
+ * @property narrowColumnWidth
188
+ * @type Number
189
+ * The width to make columns in the narrowColumns array (defaults to 30)
190
+ */
191
+ narrowColumnWidth: 30,
192
+
193
+ /**
194
+ * @property normalColumnWidth
195
+ * @type Number
196
+ * The width to make columns not marked as narrow or wide (defaults to 100)
197
+ */
198
+ normalColumnWidth: 100,
199
+
200
+ /**
201
+ * @property wideColumnWidth
202
+ * @type Number
203
+ * The width to make wide columns (defaults to 200)
204
+ */
205
+ wideColumnWidth: 200,
206
+
207
+ /**
208
+ * @property hasTopToolbar
209
+ * @type Boolean
210
+ * True to automatically include a default top toolbar (defaults to true)
211
+ */
212
+ hasTopToolbar: true,
213
+
214
+ /**
215
+ * @property hasBottomToolbar
216
+ * @type Boolean
217
+ * True to automatically include a paging bottom toolbar (defaults to true)
218
+ */
219
+ hasBottomToolbar: true,
220
+
221
+ /**
222
+ * Takes a model definition and returns a column array to use for a columnModel
223
+ */
224
+ buildColumns: function(model) {
225
+ //check to see if GridColumns have been created for this model
226
+ //e.g. for a MyApp.models.User model, checks for existence of MyApp.views.users.GridColumns
227
+ if (this.viewsPackage && this.viewsPackage.GridColumns) {
228
+ var columns = this.viewsPackage.GridColumns;
229
+ } else {
230
+ var fields = this.getFields(),
231
+ columns = [];
232
+ wideColumns = [];
233
+
234
+ //put any preferred columns at the front
235
+ Ext.each(fields, function(field) {
236
+ if (this.preferredColumns.indexOf(field.name) > -1) {
237
+ columns.push(this.buildColumn(field.name));
238
+ }
239
+ }, this);
240
+
241
+ //add the rest of the columns to the end
242
+ Ext.each(fields, function(field) {
243
+ if (this.preferredColumns.indexOf(field.name) == -1 && this.ignoreColumns.indexOf(field.name) == -1) {
244
+ columns.push(this.buildColumn(field.name));
245
+ };
246
+
247
+ //if it's been declared as a wide column, add it to the wideColumns array
248
+ if (this.wideColumns.indexOf(field.name)) {
249
+ wideColumns.push(field.name);
250
+ }
251
+ }, this);
252
+
253
+ //add default widths to each
254
+ for (var i = columns.length - 1; i >= 0; i--){
255
+ var col = columns[i];
256
+
257
+ if (this.narrowColumns.indexOf(col.id) > -1) {
258
+ //id col is extra short
259
+ Ext.applyIf(col, { width: this.narrowColumnWidth });
260
+ } else if(this.wideColumns.indexOf(col.id) > -1) {
261
+ //we have a wide column
262
+ Ext.applyIf(col, { width: this.wideColumnWidth });
263
+ } else {
264
+ //we have a normal column
265
+ Ext.applyIf(col, { width: this.normalColumnWidth });
266
+ }
267
+ };
268
+ }
269
+
270
+ return columns;
271
+ },
272
+
273
+ /**
274
+ * Returns the array of field names the buildColumns() should use to generate the column model.
275
+ * This will return this.useColumns if defined, otherwise it will return all fields
276
+ * @return {Array} The array of field names to use to generate the column model
277
+ */
278
+ getFields: function() {
279
+ if (this.useColumns === undefined) {
280
+ return this.model.prototype.fields.items;
281
+ } else {
282
+ var fields = [];
283
+ Ext.each(this.useColumns, function(column) {
284
+ fields.push({name: column});
285
+ }, this);
286
+
287
+ return fields;
288
+ }
289
+ },
290
+
291
+ /**
292
+ * Build a single column object based on a name, adds default properties
293
+ * @param {Object/String} cfg Column config object (can just include a 'name' property). Also accepts a string, which is translated into the name property
294
+ * @return {Object} A fully-formed column config with default properties set
295
+ */
296
+ buildColumn: function(cfg) {
297
+ var cfg = cfg || {};
298
+ if (typeof(cfg) == 'string') {cfg = {name: cfg};}
299
+
300
+ return Ext.applyIf(cfg, {
301
+ id : cfg.name,
302
+ header : cfg.name.replace(/_/g, " ").titleize(),
303
+ sortable : true,
304
+ dataIndex: cfg.name
305
+ });
306
+ },
307
+
308
+ /**
309
+ * @property hasAddButton
310
+ * @type Boolean
311
+ * Defines whether or not there should be an 'Add' button on the top toolbar (defaults to true)
312
+ */
313
+ hasAddButton: true,
314
+
315
+ /**
316
+ * @property hasEditButton
317
+ * @type Boolean
318
+ * Defines whether or not there should be a 'Edit' button on the top toolbar (defaults to true)
319
+ */
320
+ hasEditButton: true,
321
+
322
+ /**
323
+ * @property hasDeleteButton
324
+ * @type Boolean
325
+ * Defines whether or not there should be a 'Delete' button on the top toolbar (defaults to true)
326
+ */
327
+ hasDeleteButton: true,
328
+
329
+ /**
330
+ * Builds the Add button for the top toolbar. Override to create your own
331
+ * @param {Object} config An optional config object used to customise the button
332
+ * @return {Ext.Button} The Add Button
333
+ */
334
+ buildAddButton: function(config) {
335
+ return new Ext.Button(
336
+ Ext.applyIf(config || {}, {
337
+ text: 'New ' + this.model.prototype.singularHumanName,
338
+ scope: this,
339
+ iconCls: 'add',
340
+ handler: this.onAdd
341
+ }
342
+ ));
343
+ },
344
+
345
+ /**
346
+ * Builds the Edit button for the top toolbar. Override to create your own
347
+ * @param {Object} config An optional config object used to customise the button
348
+ * @return {Ext.Button} The Edit button
349
+ */
350
+ buildEditButton: function(config) {
351
+ return new Ext.Button(
352
+ Ext.applyIf(config || {}, {
353
+ text: 'Edit selected',
354
+ scope: this,
355
+ iconCls: 'edit',
356
+ disabled: true,
357
+ handler: this.onEdit
358
+ }
359
+ ));
360
+ },
361
+
362
+ /**
363
+ * Builds the Delete button for the top toolbar. Override to create your own
364
+ * @param {Object} config An optional config object used to customise the button
365
+ * @return {Ext.Button} The Delete button
366
+ */
367
+ buildDeleteButton: function(config) {
368
+ return new Ext.Button(
369
+ Ext.applyIf(config || {}, {
370
+ text: 'Delete selected',
371
+ disabled: true,
372
+ scope: this,
373
+ iconCls: 'delete',
374
+ handler: this.onDelete
375
+ }
376
+ ));
377
+ },
378
+
379
+ /**
380
+ * Creates Add, Edit and Delete buttons for the top toolbar and sets up listeners to
381
+ * activate/deactivate them as appropriate
382
+ * @return {Array} An array of buttons
383
+ */
384
+ buildTopToolbar: function() {
385
+ var items = [];
386
+
387
+ if (this.hasAddButton === true) {
388
+ this.addButton = this.buildAddButton();
389
+ items.push(this.addButton, '-');
390
+ }
391
+
392
+ if (this.hasEditButton === true) {
393
+ this.editButton = this.buildEditButton();
394
+ items.push(this.editButton, '-');
395
+ }
396
+
397
+ if (this.hasDeleteButton === true) {
398
+ this.deleteButton = this.buildDeleteButton();
399
+ items.push(this.deleteButton, '-');
400
+ }
401
+
402
+ if (this.hasSearchField === true) {
403
+ this.searchField = this.buildSearchField();
404
+ items.push(this.searchField, '-');
405
+ }
406
+
407
+ this.getSelectionModel().on('selectionchange', function(selModel) {
408
+ if (selModel.getCount() > 0) {
409
+ if (this.deleteButton != undefined) this.deleteButton.enable();
410
+ if (this.editButton != undefined) this.editButton.enable();
411
+ } else {
412
+ if (this.deleteButton != undefined) this.deleteButton.disable();
413
+ if (this.editButton != undefined) this.editButton.disable();
414
+ };
415
+ }, this);
416
+
417
+ return items;
418
+ },
419
+
420
+ /**
421
+ * @property pageSize
422
+ * @type Number
423
+ * The pageSize to use in the PagingToolbar bottom Toolbar (defaults to 25)
424
+ */
425
+ pageSize: 25,
426
+
427
+ /**
428
+ * Creates a paging toolbar to be placed at the bottom of this grid
429
+ * @param {Ext.data.Store} store The store to bind to this paging toolbar (should be the same as for the main grid)
430
+ * @return {Ext.PagingToolbar} The Paging Toolbar
431
+ */
432
+ buildBottomToolbar: function(store) {
433
+ return new Ext.PagingToolbar({
434
+ store: store,
435
+ displayInfo: true,
436
+ pageSize: this.pageSize,
437
+ emptyMsg: String.format("No {0} to display", this.model.prototype.pluralHumanName)
438
+ });
439
+ },
440
+
441
+ /**
442
+ * @property hasSearchField
443
+ * @type Boolean
444
+ * True to add a search input box to the end of the top toolbar (defaults to false)
445
+ */
446
+ hasSearchField: false,
447
+
448
+ /**
449
+ * @property searchParamName
450
+ * @type String
451
+ * The name of the param to send as the search variable in the GET request (defaults to 'q')
452
+ */
453
+ searchParamName: 'q',
454
+
455
+ /**
456
+ * Builds the search field component which can be added to the top toolbar of a grid
457
+ * @return {Ext.form.TwinTriggerField} The search field object
458
+ */
459
+ buildSearchField: function() {
460
+ /**
461
+ * @property searchField
462
+ * @type Ext.form.TwinTriggerField
463
+ * The search field that is added to the top toolbar
464
+ */
465
+ this.searchField = new Ext.form.TwinTriggerField({
466
+ width : 200,
467
+ validationEvent : false,
468
+ validateOnBlur : false,
469
+ hideTrigger1 : true,
470
+ onTrigger1Click : this.clearSearchField.createDelegate(this, []),
471
+ onTrigger2Click : this.onSearch.createDelegate(this, []),
472
+
473
+ trigger1Class :'x-form-clear-trigger',
474
+ trigger2Class :'x-form-search-trigger'
475
+ });
476
+
477
+ this.searchField.on('specialkey', function(field, e) {
478
+ if (e.getKey() === e.ESC) this.clearSearchField(); e.stopEvent();
479
+ if (e.getKey() === e.ENTER) this.onSearch();
480
+ }, this);
481
+
482
+ return this.searchField;
483
+ },
484
+
485
+ /**
486
+ * Clears the search field in the top toolbar and hides the clear button
487
+ */
488
+ clearSearchField: function() {
489
+ var f = this.searchField;
490
+
491
+ f.el.dom.value = '';
492
+ f.triggers[0].hide();
493
+ this.doSearch();
494
+ },
495
+
496
+ /**
497
+ * Attached to the search fields trigger2Click and Enter key events. Calls doSearch if the
498
+ * user has actually entered anything.
499
+ */
500
+ onSearch: function() {
501
+ var f = this.searchField,
502
+ v = f.getRawValue();
503
+
504
+ if (v.length < 1) {
505
+ this.clearSearchField();
506
+ } else {
507
+ f.triggers[0].show();
508
+ this.doSearch(v);
509
+ }
510
+ },
511
+
512
+ /**
513
+ * Performs the actual search operation by updating the store bound to this grid
514
+ * TODO: Move this to the controller if possible (might not be...)
515
+ * @param {String} value The string to search for
516
+ */
517
+ doSearch: function(value) {
518
+ value = value || this.searchField.getRawValue() || "";
519
+
520
+ var o = {start: 0};
521
+ this.store.baseParams = this.store.baseParams || {};
522
+ this.store.baseParams[this.searchParamName] = value;
523
+ this.store.reload({params:o});
524
+ },
525
+
526
+ /**
527
+ * Called when the add button is pressed, or when the 'a' key is pressed. By default this will simply fire the 'add' event
528
+ */
529
+ onAdd: function() {
530
+ this.fireEvent('new');
531
+ },
532
+
533
+ /**
534
+ * Called when a row in this grid panel is double clicked. By default this will find the associated
535
+ * record and fire the 'edit' event. Override to provide your own logic
536
+ * @param {Ext.EventObject} e The Event object
537
+ */
538
+ onEdit: function(e) {
539
+ var obj = this.getSelectionModel().getSelected();
540
+
541
+ if (obj) this.fireEvent('edit', obj);
542
+ },
543
+
544
+ /**
545
+ * Called when the delete button is pressed, or the delete key is pressed. By default this will ask the user to confirm,
546
+ * then fire the delete action with the selected record as the sole argument
547
+ */
548
+ onDelete: function() {
549
+ Ext.Msg.confirm(
550
+ 'Are you sure?',
551
+ String.format("Are you sure you want to delete this {0}? This cannot be undone.", this.model.prototype.modelName.humanize()),
552
+ function(btn) {
553
+ if (btn == 'yes') {
554
+ var selected = this.getSelectionModel().getSelected();
555
+ if (selected) this.fireEvent('delete', selected);
556
+ };
557
+ },
558
+ this
559
+ );
560
+ }
561
+ });