netzke-basepack 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/.travis.yml +15 -10
  2. data/{CHANGELOG.rdoc → CHANGELOG.md} +146 -110
  3. data/LICENSE +7 -1
  4. data/README.md +47 -56
  5. data/Rakefile +5 -5
  6. data/config/before-travis.sh +10 -0
  7. data/javascripts/basepack.js +0 -130
  8. data/javascripts/netzkeremotecombo.js +59 -0
  9. data/lib/netzke/basepack.rb +9 -14
  10. data/lib/netzke/basepack/accordion.rb +45 -0
  11. data/lib/netzke/basepack/active_record.rb +12 -0
  12. data/lib/netzke/basepack/active_record/relation_extensions.rb +27 -0
  13. data/lib/netzke/basepack/columns.rb +309 -0
  14. data/lib/netzke/basepack/data_accessor.rb +22 -12
  15. data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +75 -11
  16. data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +154 -49
  17. data/lib/netzke/basepack/fields.rb +162 -0
  18. data/lib/netzke/basepack/form.rb +136 -0
  19. data/lib/netzke/basepack/{form_panel → form}/javascripts/comma_list_cbg.js +0 -1
  20. data/lib/netzke/basepack/{form_panel/javascripts/form_panel.js → form/javascripts/form.js} +20 -26
  21. data/lib/netzke/basepack/{form_panel → form}/javascripts/n_radio_group.js +0 -1
  22. data/lib/netzke/basepack/{form_panel → form}/javascripts/readonly_mode.js +0 -0
  23. data/lib/netzke/basepack/form/services.rb +115 -0
  24. data/lib/netzke/basepack/{form_panel → form}/stylesheets/readonly_mode.css +0 -0
  25. data/lib/netzke/basepack/grid.rb +355 -0
  26. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/advanced_search.js +1 -1
  27. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/check_column_fix.js +0 -0
  28. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/edit_in_form.js +3 -3
  29. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/event_handling.js +5 -2
  30. data/lib/netzke/basepack/{grid_panel/javascripts/grid_panel.js → grid/javascripts/grid.js} +120 -132
  31. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/misc.js +0 -0
  32. data/lib/netzke/basepack/grid/services.rb +216 -0
  33. data/lib/netzke/basepack/item_persistence.rb +44 -0
  34. data/lib/netzke/basepack/item_persistence/events_plugin.rb +47 -0
  35. data/lib/netzke/basepack/{paging_form_panel.rb → paging_form.rb} +24 -30
  36. data/lib/netzke/basepack/{paging_form_panel/javascripts/paging_form_panel.js → paging_form/javascripts/paging_form.js} +2 -4
  37. data/lib/netzke/basepack/query_builder.rb +44 -73
  38. data/lib/netzke/basepack/query_builder/javascripts/query_builder.js +16 -2
  39. data/lib/netzke/basepack/record_form_window.rb +67 -0
  40. data/lib/netzke/basepack/search_panel.rb +22 -24
  41. data/lib/netzke/basepack/search_panel/javascripts/condition_field.js +2 -2
  42. data/lib/netzke/basepack/search_window.rb +47 -53
  43. data/lib/netzke/basepack/simple_app.rb +10 -13
  44. data/lib/netzke/basepack/simple_app/javascripts/simple_app.js +2 -8
  45. data/lib/netzke/basepack/tab_panel.rb +5 -4
  46. data/lib/netzke/basepack/tab_panel/javascripts/tab_panel.js +5 -5
  47. data/lib/netzke/basepack/version.rb +2 -2
  48. data/lib/netzke/basepack/viewport.rb +16 -0
  49. data/lib/netzke/basepack/window.rb +27 -18
  50. data/lib/netzke/basepack/window/javascripts/window.js +7 -1
  51. data/lib/netzke/basepack/wrap_lazy_loaded.rb +18 -18
  52. data/locales/en.yml +40 -24
  53. data/netzke-basepack.gemspec +51 -82
  54. data/stylesheets/basepack.css +0 -41
  55. data/test/basepack_test_app/Gemfile +9 -46
  56. data/test/basepack_test_app/Gemfile.lock +61 -96
  57. data/test/basepack_test_app/app/components/author_form.rb +8 -5
  58. data/test/basepack_test_app/app/components/author_grid.rb +2 -2
  59. data/test/basepack_test_app/app/components/book_form.rb +34 -31
  60. data/test/basepack_test_app/app/components/book_form_with_defaults.rb +6 -7
  61. data/test/basepack_test_app/app/components/book_form_with_file_upload.rb +10 -0
  62. data/test/basepack_test_app/app/components/book_form_with_nested_attributes.rb +5 -6
  63. data/test/basepack_test_app/app/components/book_grid.rb +19 -8
  64. data/test/basepack_test_app/app/components/book_grid_filtering.rb +4 -7
  65. data/test/basepack_test_app/app/components/book_grid_loader.rb +28 -15
  66. data/test/basepack_test_app/app/components/book_grid_with_custom_columns.rb +45 -21
  67. data/test/basepack_test_app/app/components/book_grid_with_default_values.rb +26 -8
  68. data/test/basepack_test_app/app/components/book_grid_with_excluded_columns.rb +11 -0
  69. data/test/basepack_test_app/app/components/book_grid_with_extra_feedback.rb +2 -2
  70. data/test/basepack_test_app/app/components/book_grid_with_extra_filters.rb +7 -6
  71. data/test/basepack_test_app/app/components/book_grid_with_mass_assignment_security.rb +9 -0
  72. data/test/basepack_test_app/app/components/book_grid_with_nested_attributes.rb +9 -9
  73. data/test/basepack_test_app/app/components/book_grid_with_overridden_columns.rb +5 -3
  74. data/test/basepack_test_app/app/components/book_grid_with_paging.rb +6 -8
  75. data/test/basepack_test_app/app/components/book_grid_with_persistence.rb +6 -4
  76. data/test/basepack_test_app/app/components/book_grid_with_scope.rb +6 -0
  77. data/test/basepack_test_app/app/components/book_grid_with_scoped_authors.rb +10 -7
  78. data/test/basepack_test_app/app/components/book_grid_with_virtual_attributes.rb +21 -13
  79. data/test/basepack_test_app/app/components/book_paging_form.rb +21 -0
  80. data/test/basepack_test_app/app/components/book_query_builder.rb +7 -6
  81. data/test/basepack_test_app/app/components/book_with_custom_primary_key_grid.rb +6 -7
  82. data/test/basepack_test_app/app/components/books_bound_to_author.rb +9 -7
  83. data/test/basepack_test_app/app/components/border_layout_panel_with_persistence.rb +12 -0
  84. data/test/basepack_test_app/app/components/double_book_grid.rb +19 -14
  85. data/test/basepack_test_app/app/components/form_without_model.rb +15 -16
  86. data/test/basepack_test_app/app/components/grid_with_initial_sorting.rb +7 -0
  87. data/test/basepack_test_app/app/components/grid_with_inline_data.rb +7 -0
  88. data/test/basepack_test_app/app/components/paging_form_with_search.rb +2 -2
  89. data/test/basepack_test_app/app/components/panel_with_persistent_regions.rb +35 -0
  90. data/test/basepack_test_app/app/components/query_builder.rb +7 -0
  91. data/test/basepack_test_app/app/components/simple_panel.rb +16 -11
  92. data/test/basepack_test_app/app/components/simple_window.rb +7 -6
  93. data/test/basepack_test_app/app/components/some_accordion.rb +18 -0
  94. data/test/basepack_test_app/app/components/some_auth_app.rb +5 -5
  95. data/test/basepack_test_app/app/components/some_border_layout.rb +20 -20
  96. data/test/basepack_test_app/app/components/some_search_panel.rb +6 -0
  97. data/test/basepack_test_app/app/components/some_simple_app.rb +30 -16
  98. data/test/basepack_test_app/app/components/some_tab_panel.rb +18 -15
  99. data/test/basepack_test_app/app/components/user_form.rb +18 -16
  100. data/test/basepack_test_app/app/components/user_form_with_default_fields.rb +5 -6
  101. data/test/basepack_test_app/app/components/user_grid.rb +11 -6
  102. data/test/basepack_test_app/app/components/user_grid_with_customized_form_fields.rb +5 -3
  103. data/test/basepack_test_app/app/components/window_component_loader.rb +25 -21
  104. data/test/basepack_test_app/app/models/address.rb +0 -26
  105. data/test/basepack_test_app/app/models/author.rb +0 -31
  106. data/test/basepack_test_app/app/models/book.rb +1 -42
  107. data/test/basepack_test_app/app/models/book_with_custom_primary_key.rb +1 -23
  108. data/test/basepack_test_app/app/models/role.rb +0 -21
  109. data/test/basepack_test_app/app/models/user.rb +0 -24
  110. data/test/basepack_test_app/app/views/layouts/components.html.erb +1 -1
  111. data/test/basepack_test_app/config/application.rb +1 -1
  112. data/test/basepack_test_app/config/database.yml.travis +2 -6
  113. data/test/basepack_test_app/config/initializers/netzke.rb +1 -6
  114. data/test/basepack_test_app/db/schema.rb +14 -14
  115. data/test/basepack_test_app/features/accordion_panel.feature +2 -2
  116. data/test/basepack_test_app/features/form_panel.feature +7 -7
  117. data/test/basepack_test_app/features/grid_panel.feature +93 -39
  118. data/test/basepack_test_app/features/grid_panel_with_custom_primary_key.feature +2 -1
  119. data/test/basepack_test_app/features/grid_sorting.feature +30 -6
  120. data/test/basepack_test_app/features/paging_form_panel.feature +7 -7
  121. data/test/basepack_test_app/features/persistent_regions.feature +30 -0
  122. data/test/basepack_test_app/features/search_in_grid.feature +5 -5
  123. data/test/basepack_test_app/features/simple_app.feature +6 -7
  124. data/test/basepack_test_app/features/step_definitions/form_panel_steps.rb +1 -1
  125. data/test/basepack_test_app/features/step_definitions/generic_steps.rb +109 -4
  126. data/test/basepack_test_app/features/step_definitions/grid_panel_steps.rb +8 -10
  127. data/test/basepack_test_app/features/step_definitions/window_steps.rb +27 -0
  128. data/test/basepack_test_app/features/tab_panel.feature +1 -1
  129. data/test/basepack_test_app/features/window.feature +17 -0
  130. data/test/unit/accordion_panel_test.rb +2 -2
  131. data/test/unit/grid_panel_test.rb +4 -4
  132. metadata +57 -83
  133. data/TODO.rdoc +0 -8
  134. data/lib/generators/netzke/basepack_generator.rb +0 -10
  135. data/lib/generators/netzke/templates/assets/ts-checkbox.gif +0 -0
  136. data/lib/generators/netzke/templates/create_netzke_field_lists.rb +0 -18
  137. data/lib/netzke/active_record.rb +0 -20
  138. data/lib/netzke/active_record/attributes.rb +0 -259
  139. data/lib/netzke/active_record/combobox_options.rb +0 -16
  140. data/lib/netzke/active_record/relation_extensions.rb +0 -37
  141. data/lib/netzke/basepack/accordion_panel.rb +0 -39
  142. data/lib/netzke/basepack/action_column.rb +0 -68
  143. data/lib/netzke/basepack/action_column/javascripts/action_column.js +0 -61
  144. data/lib/netzke/basepack/auth_app.rb +0 -159
  145. data/lib/netzke/basepack/basic_app.rb +0 -7
  146. data/lib/netzke/basepack/border_layout_panel.rb +0 -53
  147. data/lib/netzke/basepack/border_layout_panel/javascripts/border_layout_panel.js +0 -40
  148. data/lib/netzke/basepack/data_adapters/data_mapper_adapter.rb +0 -264
  149. data/lib/netzke/basepack/data_adapters/sequel_adapter.rb +0 -260
  150. data/lib/netzke/basepack/form_panel.rb +0 -144
  151. data/lib/netzke/basepack/form_panel/fields.rb +0 -208
  152. data/lib/netzke/basepack/form_panel/javascripts/misc.js +0 -4
  153. data/lib/netzke/basepack/form_panel/services.rb +0 -142
  154. data/lib/netzke/basepack/grid_panel.rb +0 -441
  155. data/lib/netzke/basepack/grid_panel/columns.rb +0 -400
  156. data/lib/netzke/basepack/grid_panel/javascripts/rows-dd.js +0 -281
  157. data/lib/netzke/basepack/grid_panel/record_form_window.rb +0 -41
  158. data/lib/netzke/basepack/grid_panel/services.rb +0 -235
  159. data/lib/netzke/basepack/panel.rb +0 -11
  160. data/lib/netzke/basepack/wrapper.rb +0 -28
  161. data/lib/netzke/data_mapper.rb +0 -18
  162. data/lib/netzke/data_mapper/attributes.rb +0 -273
  163. data/lib/netzke/data_mapper/combobox_options.rb +0 -11
  164. data/lib/netzke/data_mapper/relation_extensions.rb +0 -38
  165. data/lib/netzke/sequel.rb +0 -18
  166. data/lib/netzke/sequel/attributes.rb +0 -274
  167. data/lib/netzke/sequel/combobox_options.rb +0 -10
  168. data/lib/netzke/sequel/relation_extensions.rb +0 -40
  169. data/locales/zh-cn.yml +0 -79
  170. data/test/basepack_test_app/app/components/book_form_with_custom_fields.rb +0 -21
  171. data/test/basepack_test_app/app/components/book_grid_with_column_actions.rb +0 -15
  172. data/test/basepack_test_app/app/components/book_grid_with_defaults.rb +0 -6
  173. data/test/basepack_test_app/app/components/book_paging_form_panel.rb +0 -22
  174. data/test/basepack_test_app/app/components/generic_user_form.rb +0 -12
  175. data/test/basepack_test_app/app/components/simple_accordion.rb +0 -11
  176. data/test/basepack_test_app/app/components/simple_tab_panel.rb +0 -11
  177. data/test/basepack_test_app/app/components/simple_wrapper.rb +0 -7
  178. data/test/basepack_test_app/app/components/some_accordion_panel.rb +0 -22
  179. data/test/basepack_test_app/app/presenters/forms/generic_user.rb +0 -6
  180. data/test/basepack_test_app/app/views/components/loadable_window.html.erb +0 -9
  181. data/test/basepack_test_app/app/views/components/simple_panel.html.erb +0 -1
  182. data/test/basepack_test_app/features/components_in_view.feature +0 -11
  183. data/test/basepack_test_app/features/simple_panel.feature +0 -11
  184. data/test/basepack_test_app/features/validations_in_grid.feature +0 -13
  185. data/test/basepack_test_app/features/virtual_attributes.feature +0 -16
  186. data/test/basepack_test_app/spec/components/form_panel_spec.rb +0 -53
  187. data/test/basepack_test_app/spec/components/grid_panel_spec.rb +0 -10
  188. data/test/basepack_test_app/spec/data_adapter/adapter_spec.rb +0 -68
  189. data/test/basepack_test_app/spec/data_adapter/attributes_spec.rb +0 -56
  190. data/test/basepack_test_app/spec/data_adapter/relation_extensions_spec.rb +0 -125
  191. data/test/basepack_test_app/spec/factories.rb +0 -28
  192. data/test/basepack_test_app/spec/spec_helper.rb +0 -39
@@ -3,7 +3,7 @@
3
3
  if (this.searchWindow) {
4
4
  this.searchWindow.show();
5
5
  } else {
6
- this.loadNetzkeComponent({name: 'search_form', callback: function(win){
6
+ this.netzkeLoadComponent('search_window', {callback: function(win){
7
7
  this.searchWindow = win;
8
8
  win.show();
9
9
 
@@ -3,7 +3,7 @@
3
3
  var selModel = this.getSelectionModel();
4
4
  if (selModel.getCount() > 1) {
5
5
  var recordId = selModel.selected.first().getId();
6
- this.loadNetzkeComponent({name: "multi_edit_form",
6
+ this.netzkeLoadComponent("multi_edit_window", {
7
7
  params: {record_id: recordId},
8
8
  callback: function(w){
9
9
  w.show();
@@ -25,7 +25,7 @@
25
25
  }, scope: this});
26
26
  } else {
27
27
  var recordId = selModel.selected.first().getId();
28
- this.loadNetzkeComponent({name: "edit_form",
28
+ this.netzkeLoadComponent("edit_window", {
29
29
  params: {record_id: recordId},
30
30
  callback: function(w){
31
31
  w.show();
@@ -39,7 +39,7 @@
39
39
  },
40
40
 
41
41
  onAddInForm: function(){
42
- this.loadNetzkeComponent({name: "add_form", callback: function(w){
42
+ this.netzkeLoadComponent("add_window", {callback: function(w){
43
43
  w.show();
44
44
  w.on('close', function(){
45
45
  if (w.closeRes === "ok") {
@@ -113,6 +113,9 @@
113
113
  },
114
114
 
115
115
  onColumnMove: function(ct, cl, oldIndex, newIndex){
116
+ // when moving a column forwards, the new index appears to be 1 too high; a bug in Ext JS? Fixing.
117
+ if (newIndex > oldIndex) newIndex--;
118
+
116
119
  this.moveColumn({
117
120
  old_index: oldIndex,
118
121
  new_index: newIndex
@@ -138,7 +141,7 @@
138
141
  var ids = [];
139
142
  // collect records ids
140
143
  Ext.each(records, function(r){ids.push(r.id)});
141
- // call GridPanel's API
144
+ // call Grid's API
142
145
  this.moveRows({ids: Ext.encode(ids), new_index: newIndex});
143
146
  },
144
147
 
@@ -169,7 +172,7 @@
169
172
 
170
173
  // Not a very clean approach to clean-up. The problem is that this way the advanced search functionality stops being really pluggable. With Ext JS 4 find the way to make it truely so.
171
174
  onDestroy: function(){
172
- Netzke.classes.Basepack.GridPanel.superclass.onDestroy.call(this);
175
+ this.callParent();
173
176
 
174
177
  // Destroy the search window (here's the problem: we are not supposed to know it exists)
175
178
  if (this.searchWindow) {
@@ -8,92 +8,28 @@
8
8
  multiSelect: true,
9
9
 
10
10
  initComponent: function(){
11
- var metaColumn;
12
- var fields = []; // field configs for the underlying data model
13
-
14
11
  this.plugins = this.plugins || [];
15
12
  this.features = this.features || [];
16
13
 
17
14
  // Enable filters feature
18
- this.features.push({
19
- encode: true,
20
- ftype: 'filters'
21
- });
22
-
23
- // Run through columns and set up different configuration for each
24
- Ext.each(this.columns, function(c, i){
25
-
26
- this.normalizeRenderer(c);
27
-
28
- // Build the field configuration for this column
29
- var fieldConfig = {name: c.name, defaultValue: c.defaultValue, useNull: true}; // useNull is needed to not convert nils to 0 in associations!
30
-
31
- if (c.name !== 'meta') fieldConfig.type = this.fieldTypeForAttrType(c.attrType); // field type (grid editors need this to function well)
32
-
33
- if (c.attrType == 'datetime') {
34
- fieldConfig.dateFormat = 'Y-m-d H:i:s'; // set the format in which we receive datetime from the server (so that the model can parse it)
35
-
36
- // While for 'date' columns the renderer is set up automatically (through using column's xtype), there's no appropriate xtype for our custom datetime column.
37
- // Thus, we need to set the renderer manually.
38
- // NOTE: for Ext there's no distinction b/w date and datetime; date fields can include time.
39
- if (!c.renderer) {
40
- // format in which the data will be rendered; if c.format is nil, Ext.Date.defaultFormat extended with time will be used
41
- c.renderer = Ext.util.Format.dateRenderer(c.format || Ext.Date.defaultFormat + " H:i:s");
42
- }
43
- };
44
-
45
- fields.push(fieldConfig);
46
-
47
- // We will not use meta columns as actual columns (not even hidden) - only to create the records
48
- if (c.meta) {
49
- metaColumn = c;
50
- return;
51
- }
52
-
53
- // if comboboxOptions are provided, we render a combobox instead of textfield
54
- // if (c.comboboxOptions && c.editor.xtype === "textfield") {
55
- // c.editor = {xtype: "combobox", options: c.comboboxOptions.split('\\n')}
56
- // }
57
-
58
-
59
- // Set rendeder for association columns (the one displaying associations by the specified method instead of id)
60
-
61
- if (c.assoc) {
62
- // Editor for association column
63
- c.editor = Ext.apply({
64
- parentId: this.id,
65
- name: c.name
66
- }, c.editor);
67
-
68
- // Renderer for association column
69
- this.normalizeAssociationRenderer(c);
70
- }
71
-
72
- if (c.editor) {
73
- Ext.applyIf(c.editor, {selectOnFocus: true});
74
- }
75
-
76
- // Setting the default filter type
77
- if (c.filterable && !c.filter) {
78
- c.filter = {type: c.assoc ? 'string' : this.fieldTypeForAttrType(c.attrType)};
79
- }
80
-
81
- // setting dataIndex
82
- c.dataIndex = c.name;
83
-
84
- }, this);
15
+ if (this.enableColumnFilters) {
16
+ this.features.push({
17
+ encode: true,
18
+ ftype: 'filters'
19
+ });
20
+ }
85
21
 
86
- /* ... and done with the columns */
22
+ // Normalize columns. Extract data fields and meta column.
23
+ this.processColumns();
87
24
 
88
25
  // Define the model
89
26
  Ext.define(this.id, {
90
27
  extend: 'Ext.data.Model',
91
28
  idProperty: this.pri, // Primary key
92
- fields: fields
29
+ fields: this.fields
93
30
  });
94
-
95
- // After we created the record (model), we can get rid of the meta column
96
- Ext.Array.remove(this.columns, metaColumn);
31
+ delete this.pri;
32
+ delete this.fields;
97
33
 
98
34
  // Prepare column model config with columns in the correct order; columns out of order go to the end.
99
35
  var colModelConfig = [];
@@ -117,49 +53,12 @@
117
53
  // ... instead, define own column model
118
54
  this.columns = colModelConfig;
119
55
 
120
- var reader = Ext.create('Ext.data.reader.Array', {root: 'data', totalProperty: 'total'});
121
-
122
- // DirectProxy that uses our Ext.direct provider
123
- var proxy = Ext.create('Ext.data.proxy.Direct', {
124
- directFn: Netzke.providers[this.id].getData,
125
- reader: reader,
126
- listeners: {
127
- exception: {
128
- fn: this.loadExceptionHandler,
129
- scope: this
130
- },
131
- load: { // Netzke-introduced event; this will also be fired when an exception occurs.
132
- fn: function(proxy, response, operation) {
133
- // besides getting data into the store, we may also get commands to execute
134
- response = response.result;
135
- if (response) { // or did we have an exception?
136
- Ext.each(['data', 'total', 'success'], function(property){delete response[property];});
137
- this.bulkExecute(response);
138
- }
139
- },
140
- scope: this
141
- }
142
- }
143
- });
144
-
145
- this.store = Ext.create('Ext.data.Store', {
146
- model: this.id,
147
- proxy: proxy,
148
- pruneModifiedRecords: true,
149
- remoteSort: true,
150
- pageSize: this.rowsPerPage
151
- });
56
+ // data store
57
+ this.store = this.buildStore();
152
58
 
59
+ // load inline data if available
153
60
  if (this.inlineData) this.store.loadRawData(this.inlineData);
154
61
 
155
- // Drag'n'Drop
156
- if (this.enableRowsReordering){
157
- this.ddPlugin = new Ext.ux.dd.GridDragDropRowOrder({
158
- scrollable: true // enable scrolling support (default is false)
159
- });
160
- this.plugins.push(this.ddPlugin);
161
- }
162
-
163
62
  // Cell editing
164
63
  if (!this.prohibitUpdate) {
165
64
  this.plugins.push(Ext.create('Ext.grid.plugin.CellEditing', {pluginId: 'celleditor'}));
@@ -172,7 +71,7 @@
172
71
  xtype: 'pagingtoolbar',
173
72
  dock: 'bottom',
174
73
  store: this.store,
175
- items: this.bbar && ["-"].concat(this.bbar) // append the old bbar
74
+ items: this.bbar && ["-"].concat(this.bbar) // append the passed bbar
176
75
  });
177
76
  } else if (this.bbar) {
178
77
  this.dockedItems.push({
@@ -182,10 +81,8 @@
182
81
  });
183
82
  }
184
83
 
185
-
186
84
  delete this.bbar;
187
85
 
188
- // Now let Ext.grid.EditorGridPanel do the rest (original initComponent)
189
86
  this.callParent();
190
87
 
191
88
  // Context menu
@@ -215,21 +112,9 @@
215
112
  if (this.actions.edit) this.actions.edit.setDisabled(selModel.getCount() != 1 || this.prohibitUpdate);
216
113
  }, this);
217
114
 
218
- // Drag n Drop event
219
- if (this.enableRowsReordering){
220
- this.ddPlugin.on('afterrowmove', this.onAfterRowMove, this);
221
- }
222
-
223
115
  // WIP: GridView
224
116
  this.getView().getRowClass = this.defaultGetRowClass;
225
117
 
226
- // this.on('edit', function(editor, e) {
227
- // if (e.column.assoc && e.record.get('meta')) {
228
- // console.log("editor:", editor);
229
- // editor.setRawValue("");
230
- // }
231
- // });
232
-
233
118
  // When starting editing as assocition column, pre-load the combobox store from the meta column, so that we don't see the real value of this cell (the id of the associated record), but rather the associated record by the configured method.
234
119
  this.on('beforeedit', function(editor, e){
235
120
  if (e.column.assoc && e.record.get('meta')) {
@@ -246,7 +131,7 @@
246
131
  }
247
132
  }, this);
248
133
 
249
- this.on('afterrender', function() {
134
+ this.on('afterlayout', function() {
250
135
  // Persistence-related events (afterrender to avoid blank event firing on render)
251
136
  if (this.persistence) {
252
137
  // Inform the server part about column operations
@@ -258,6 +143,109 @@
258
143
  }, this);
259
144
  },
260
145
 
146
+ processColumns: function() {
147
+ this.fields = [];
148
+
149
+ // Run through columns and set up different configuration for each
150
+ Ext.each(this.columns, function(c, i){
151
+
152
+ this.normalizeRenderer(c);
153
+
154
+ // Build the field configuration for this column
155
+ var fieldConfig = {name: c.name, defaultValue: c.defaultValue, useNull: true}; // useNull is needed to not convert nils to 0 in associations!
156
+
157
+ if (c.name !== 'meta') fieldConfig.type = this.fieldTypeForAttrType(c.attrType); // field type (grid editors need this to function well)
158
+
159
+ if (c.attrType == 'datetime') {
160
+ fieldConfig.dateFormat = 'Y-m-d H:i:s'; // set the format in which we receive datetime from the server (so that the model can parse it)
161
+
162
+ // While for 'date' columns the renderer is set up automatically (through using column's xtype), there's no appropriate xtype for our custom datetime column.
163
+ // Thus, we need to set the renderer manually.
164
+ // NOTE: for Ext there's no distinction b/w date and datetime; date fields can include time.
165
+ if (!c.renderer) {
166
+ // format in which the data will be rendered; if c.format is nil, Ext.Date.defaultFormat extended with time will be used
167
+ c.renderer = Ext.util.Format.dateRenderer(c.format || Ext.Date.defaultFormat + " H:i:s");
168
+ }
169
+ };
170
+
171
+ this.fields.push(fieldConfig);
172
+
173
+ // We will not use meta columns as actual columns (not even hidden) - only to create the records
174
+ if (c.meta) {
175
+ this.metaColumn = c;
176
+ return;
177
+ }
178
+
179
+ // Set rendeder for association columns (the one displaying associations by the specified method instead of id)
180
+ if (c.assoc) {
181
+ // Editor for association column
182
+ c.editor = Ext.apply({
183
+ name: c.name
184
+ }, c.editor);
185
+
186
+ // Renderer for association column
187
+ this.normalizeAssociationRenderer(c);
188
+ }
189
+
190
+ if (c.editor) {
191
+ Ext.applyIf(c.editor, {selectOnFocus: true, parentId: this.id});
192
+ }
193
+
194
+ // Setting the default filter type
195
+ if (c.filterable && !c.filter) {
196
+ c.filter = {type: c.assoc ? 'string' : this.fieldTypeForAttrType(c.attrType)};
197
+ }
198
+
199
+ // setting dataIndex
200
+ c.dataIndex = c.name;
201
+
202
+ }, this);
203
+ },
204
+
205
+ buildStore: function() {
206
+ var store = Ext.create('Ext.data.Store', Ext.apply({
207
+ model: this.id,
208
+ proxy: this.buildProxy(),
209
+ pruneModifiedRecords: true,
210
+ remoteSort: true,
211
+ pageSize: this.rowsPerPage,
212
+ autoLoad: !this.loadInlineData
213
+ }, this.dataStore));
214
+
215
+ delete this.dataStore;
216
+
217
+ return store;
218
+ },
219
+
220
+ buildProxy: function() {
221
+ // DirectProxy that uses our Ext.direct provider
222
+ return Ext.create('Ext.data.proxy.Direct', {
223
+ directFn: Netzke.providers[this.id].getData,
224
+ reader: this.buildReader(),
225
+ listeners: {
226
+ exception: {
227
+ fn: this.loadExceptionHandler,
228
+ scope: this
229
+ },
230
+ load: { // Netzke-introduced event; this will also be fired when an exception occurs.
231
+ fn: function(proxy, response, operation) {
232
+ // besides getting data into the store, we may also get commands to execute
233
+ response = response.result;
234
+ if (response) { // or did we have an exception?
235
+ Ext.each(['data', 'total', 'success'], function(property){delete response[property];});
236
+ this.netzkeBulkExecute(response);
237
+ }
238
+ },
239
+ scope: this
240
+ }
241
+ }
242
+ });
243
+ },
244
+
245
+ buildReader: function() {
246
+ return Ext.create('Ext.data.reader.Array', {root: 'data', totalProperty: 'total'});
247
+ },
248
+
261
249
  fieldTypeForAttrType: function(attrType){
262
250
  var map = {
263
251
  integer : 'int',
@@ -279,7 +267,7 @@
279
267
  var dataRecords = this.getStore().getProxy().getReader().read(data);
280
268
  this.getStore().loadData(dataRecords.records);
281
269
  Ext.each(['data', 'total', 'success'], function(property){delete data[property];}, this);
282
- this.bulkExecute(data);
270
+ this.netzkeBulkExecute(data);
283
271
  },
284
272
 
285
273
  // Tries editing the first editable (i.e. not hidden, not read-only) sell
@@ -0,0 +1,216 @@
1
+ module Netzke
2
+ module Basepack
3
+ class Grid < Netzke::Base
4
+ module Services
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ endpoint :get_data do |params, this|
9
+ # not a usual Netzke endpoint, as it's being used by the Ext.data.DirectStore
10
+ this.merge! get_data(params)
11
+ end
12
+
13
+ endpoint :post_data do |params, this|
14
+ mod_records = {}
15
+ [:create, :update].each do |operation|
16
+ data = ActiveSupport::JSON.decode(params["#{operation}d_records"]) if params["#{operation}d_records"]
17
+ if !data.nil? && !data.empty? # data may be nil for one of the operations
18
+ mod_records[operation] = process_data(data, operation)
19
+ mod_records[operation] = nil if mod_records[operation].empty?
20
+ end
21
+ end
22
+
23
+ on_data_changed
24
+
25
+ this.update_new_records mod_records[:create]
26
+ this.update_mod_records mod_records[:update] if mod_records[:update]
27
+ this.netzke_feedback @flash
28
+ end
29
+
30
+ endpoint :delete_data do |params, this|
31
+ if !config[:prohibit_delete]
32
+ record_ids = ActiveSupport::JSON.decode(params[:records])
33
+ data_adapter.destroy(record_ids)
34
+ on_data_changed
35
+ this.netzke_feedback I18n.t('netzke.basepack.grid.deleted_n_records', :n => record_ids.size)
36
+ this.load_store_data get_data
37
+ else
38
+ this.netzke_feedback I18n.t('netzke.basepack.grid.cannot_delete')
39
+ end
40
+ end
41
+
42
+ endpoint :resize_column do |params, this|
43
+ raise "Called resize_column endpoint while not configured to do so" if !config[:persistence]
44
+
45
+ current_columns_order = state[:columns_order] || initial_columns_order
46
+ current_columns_order[normalize_index(params[:index].to_i)][:width] = params[:size].to_i
47
+ state[:columns_order] = current_columns_order
48
+ end
49
+
50
+ endpoint :move_column do |params, this|
51
+ raise "Called move_column endpoint while not configured to do so" if !config[:persistence]
52
+
53
+ remove_from = normalize_index(params[:old_index].to_i)
54
+ insert_to = normalize_index(params[:new_index].to_i)
55
+
56
+ current_columns_order = state[:columns_order] || initial_columns_order
57
+
58
+ column_to_move = current_columns_order.delete_at(remove_from)
59
+ current_columns_order.insert(insert_to, column_to_move)
60
+
61
+ state[:columns_order] = current_columns_order
62
+ end
63
+
64
+ endpoint :hide_column do |params, this|
65
+ raise "Called hide_column endpoint while not configured to do so" if !config[:persistence]
66
+ current_columns_order = state[:columns_order] || initial_columns_order
67
+ current_columns_order[normalize_index(params[:index].to_i)][:hidden] = params[:hidden]
68
+ state[:columns_order] = current_columns_order
69
+ end
70
+
71
+ # Returns options for a combobox
72
+ # params receive:
73
+ # +attr+ - column's name
74
+ # +query+ - what's typed-in in the combobox
75
+ # +id+ - selected record id
76
+ endpoint :get_combobox_options do |params, this|
77
+ column = final_columns.detect{ |c| c[:name] == params[:attr] }
78
+ this.data = data_adapter.combo_data(column, params[:query])
79
+ end
80
+
81
+ endpoint :move_rows do |params, this|
82
+ data_adapter.move_records(params)
83
+ end
84
+
85
+ # When providing the edit_form component, fill in the form with the requested record
86
+ endpoint :deliver_component do |params, this|
87
+ if params[:name] == 'edit_window'
88
+ components[:edit_window].form_config.record_id = params[:record_id].to_i
89
+ end
90
+
91
+ super(params, this)
92
+ end
93
+
94
+ # TODO: functionality of the following 2 endpoints could probably be improved by subclassing Basepack::Form as a dedicated form for adding/editing records in a grid.
95
+ # Process the submit of multi-editing form ourselves
96
+ endpoint :multi_edit_window__multi_edit_form__netzke_submit do |params, this|
97
+ ids = ActiveSupport::JSON.decode(params.delete(:ids))
98
+ data = ids.collect{ |id| ActiveSupport::JSON.decode(params[:data]).merge("id" => id) }
99
+
100
+ data.map!{|el| el.delete_if{ |k,v| v.is_a?(String) && v.blank? }} # only interested in set values
101
+
102
+ mod_records_count = process_data(data, :update).count
103
+
104
+ # remove duplicated flash messages
105
+ @flash = @flash.inject([]){ |r,hsh| r.include?(hsh) ? r : r.push(hsh) }
106
+
107
+ if mod_records_count > 0
108
+ on_data_changed
109
+ this.netzke_set_result("ok")
110
+ this.on_submit_success
111
+ end
112
+
113
+ this.netzke_feedback(@flash)
114
+ end
115
+
116
+ # The following two look a bit hackish, but serve to invoke on_data_changed when a form gets successfully submitted
117
+ endpoint :add_window__add_form__netzke_submit do |params, this|
118
+ this.merge!(component_instance(:add_window__add_form).invoke_endpoint(:netzke_submit, params))
119
+ on_data_changed if this.set_form_values.present?
120
+ this.delete(:set_form_values)
121
+ end
122
+
123
+ endpoint :edit_window__edit_form__netzke_submit do |params, this|
124
+ this.merge!(component_instance(:edit_window__edit_form).invoke_endpoint(:netzke_submit, params))
125
+ on_data_changed if this.set_form_values.present?
126
+ this.delete(:set_form_values)
127
+ end
128
+ end # included
129
+
130
+ # Implementation for the "get_data" endpoint
131
+ def get_data(*args)
132
+ params = args.first || {} # params are optional!
133
+ if !config[:prohibit_read]
134
+ {}.tap do |res|
135
+ records = get_records(params)
136
+ res[:data] = records.map{|r| data_adapter.record_to_array(r, final_columns(:with_meta => true))}
137
+ res[:total] = count_records(params) if config[:enable_pagination]
138
+ end
139
+ else
140
+ flash :error => "You don't have permissions to read data"
141
+ { :netzke_feedback => @flash }
142
+ end
143
+ end
144
+
145
+ protected
146
+
147
+ # Returns an array of records.
148
+ def get_records(params)
149
+ params[:limit] = config[:rows_per_page] if config[:enable_pagination]
150
+ params[:scope] = config[:scope] # note, params[:scope] becomes ActiveSupport::HashWithIndifferentAccess
151
+
152
+ data_adapter.get_records(params, final_columns)
153
+ end
154
+
155
+ def count_records(params)
156
+ params[:scope] = config[:scope] # note, params[:scope] becomes ActiveSupport::HashWithIndifferentAccess
157
+
158
+ data_adapter.count_records(params, final_columns)
159
+ end
160
+
161
+ # Override this method to react on each operation that caused changing of data
162
+ def on_data_changed
163
+ end
164
+
165
+ # Given an index of a column among enabled (non-excluded) columns, provides the index (position) in the table
166
+ def normalize_index(index)
167
+ norm_index = 0
168
+ index.times do
169
+ while true do
170
+ norm_index += 1
171
+ break unless final_columns[norm_index][:included] == false
172
+ end
173
+ end
174
+ norm_index
175
+ end
176
+
177
+ # Params:
178
+ # <tt>:operation</tt>: :update or :create
179
+ def process_data(data, operation)
180
+ success = true
181
+ mod_records = {}
182
+ if !config[:"prohibit_#{operation}"]
183
+ modified_records = 0
184
+ data.each do |record_hash|
185
+ id = record_hash.delete('id')
186
+ record = operation == :create ? data_adapter.new_record : data_adapter.find_record(id)
187
+ success = true
188
+
189
+ # merge with strong default attirbutes
190
+ record_hash.merge!(config[:strong_default_attrs]) if config[:strong_default_attrs]
191
+
192
+ record_hash.each_pair do |k,v|
193
+ data_adapter.set_record_value_for_attribute(record, final_columns_hash[k.to_sym].nil? ? {:name => k} : final_columns_hash[k.to_sym], v, config.role || :default)
194
+ end
195
+
196
+ # try to save
197
+ mod_records[id] = data_adapter.record_to_array(record, final_columns(:with_meta => true)) if success && record.save
198
+
199
+ # flash eventual errors
200
+ if !record.errors.empty?
201
+ success = false
202
+ record.errors.to_a.each do |msg|
203
+ flash :error => msg
204
+ end
205
+ end
206
+ end
207
+ else
208
+ success = false
209
+ flash :error => "You don't have permissions to #{operation} data"
210
+ end
211
+ mod_records
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end