netzke-basepack 0.5.14 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (196) hide show
  1. data/.gitignore +3 -2
  2. data/CHANGELOG.rdoc +15 -0
  3. data/README.rdoc +45 -50
  4. data/Rakefile +8 -8
  5. data/TODO.rdoc +1 -6
  6. data/app/components/netzke/basepack/accordion_panel.rb +37 -0
  7. data/app/components/netzke/basepack/basic_app.rb +267 -0
  8. data/{lib/netzke → app/components/netzke/basepack}/basic_app/statusbar_ext.js +0 -0
  9. data/app/components/netzke/basepack/border_layout_panel.rb +39 -0
  10. data/app/components/netzke/basepack/form_panel.rb +102 -0
  11. data/app/components/netzke/basepack/form_panel/fields.rb +206 -0
  12. data/{lib/netzke → app/components/netzke/basepack}/form_panel/javascripts/netzkefileupload.js +0 -0
  13. data/app/components/netzke/basepack/form_panel/javascripts/pre.js +76 -0
  14. data/{lib/netzke → app/components/netzke/basepack}/form_panel/javascripts/xcheckbox.js +0 -0
  15. data/app/components/netzke/basepack/form_panel/services.rb +99 -0
  16. data/app/components/netzke/basepack/grid_panel.rb +374 -0
  17. data/app/components/netzke/basepack/grid_panel/columns.rb +233 -0
  18. data/app/components/netzke/basepack/grid_panel/javascript.rb +69 -0
  19. data/app/components/netzke/basepack/grid_panel/javascripts/advanced_search.js +96 -0
  20. data/{lib/netzke → app/components/netzke/basepack}/grid_panel/javascripts/edit_in_form.js +5 -4
  21. data/{lib/netzke/grid_panel/javascripts/grid_panel_pre.js → app/components/netzke/basepack/grid_panel/javascripts/pre.js} +17 -37
  22. data/{lib/netzke → app/components/netzke/basepack}/grid_panel/javascripts/rows-dd.js +0 -0
  23. data/app/components/netzke/basepack/grid_panel/multi_edit_form.rb +16 -0
  24. data/app/components/netzke/basepack/grid_panel/record_form_window.rb +36 -0
  25. data/app/components/netzke/basepack/grid_panel/search_window.rb +56 -0
  26. data/app/components/netzke/basepack/grid_panel/services.rb +356 -0
  27. data/app/components/netzke/basepack/panel.rb +11 -0
  28. data/app/components/netzke/basepack/search_panel.rb +59 -0
  29. data/app/components/netzke/basepack/tab_panel.rb +32 -0
  30. data/app/components/netzke/basepack/window.rb +73 -0
  31. data/app/components/netzke/basepack/wrapper.rb +28 -0
  32. data/{lib/app → app}/models/netzke_field_list.rb +1 -1
  33. data/{lib/app → app}/models/netzke_model_attr_list.rb +0 -0
  34. data/{lib/app → app}/models/netzke_persistent_array_auto_model.rb +0 -0
  35. data/config/database.yml +35 -0
  36. data/features/accordion_panel.feature +15 -0
  37. data/features/basic_app.feature +12 -0
  38. data/features/form_panel.feature +40 -0
  39. data/features/grid_panel.feature +62 -0
  40. data/features/search_in_grid.feature +35 -0
  41. data/features/simple_panel.feature +15 -0
  42. data/features/step_definitions/accordion_steps.rb +9 -0
  43. data/features/step_definitions/generic_steps.rb +15 -0
  44. data/features/step_definitions/grid_panel_steps.rb +26 -0
  45. data/features/step_definitions/pickle_steps.rb +100 -0
  46. data/features/step_definitions/web_steps.rb +219 -0
  47. data/features/support/env.rb +66 -0
  48. data/features/support/paths.rb +59 -0
  49. data/features/support/pickle.rb +25 -0
  50. data/features/tab_panel.feature +15 -0
  51. data/features/window.feature +11 -0
  52. data/from_05_to_06.rdoc +2 -0
  53. data/javascripts/basepack.js +54 -2
  54. data/lib/netzke-basepack.rb +38 -25
  55. data/lib/netzke/active_record.rb +12 -4
  56. data/lib/netzke/active_record/attributes.rb +60 -5
  57. data/lib/netzke/active_record/combobox_options.rb +3 -2
  58. data/lib/netzke/active_record/relation_extensions.rb +35 -0
  59. data/lib/netzke/basepack.rb +27 -0
  60. data/lib/netzke/basepack/version.rb +11 -0
  61. data/lib/netzke/basepack/wrap_lazy_loaded.rb +26 -0
  62. data/lib/netzke/data_accessor.rb +60 -32
  63. data/lib/netzke/fields_configurator.rb +5 -9
  64. data/lib/netzke/masquerade_selector.rb +1 -1
  65. data/locale/en.yml +16 -0
  66. data/netzke-basepack.gemspec +298 -0
  67. data/spec/active_record/attributes_spec.rb +14 -0
  68. data/spec/active_record/relation_extensions_spec.rb +44 -0
  69. data/spec/components/form_panel_spec.rb +70 -0
  70. data/spec/components/grid_panel_spec.rb +10 -0
  71. data/spec/factories.rb +9 -0
  72. data/spec/spec_helper.rb +35 -0
  73. data/test/rails_app/.gitignore +4 -0
  74. data/test/rails_app/Gemfile +32 -0
  75. data/test/rails_app/Gemfile.lock +171 -0
  76. data/test/rails_app/README +256 -0
  77. data/test/rails_app/Rakefile +7 -0
  78. data/test/rails_app/app/components/generic_user_form.rb +12 -0
  79. data/test/rails_app/app/components/simple_accordion.rb +11 -0
  80. data/test/rails_app/app/components/simple_basic_app.rb +32 -0
  81. data/test/rails_app/app/components/simple_panel.rb +17 -0
  82. data/test/rails_app/app/components/simple_tab_panel.rb +11 -0
  83. data/test/rails_app/app/components/simple_wrapper.rb +7 -0
  84. data/test/rails_app/app/components/some_border_layout.rb +24 -0
  85. data/test/rails_app/app/components/some_search_panel.rb +34 -0
  86. data/test/rails_app/app/components/some_tab_panel.rb +15 -0
  87. data/test/rails_app/app/components/user_form.rb +21 -0
  88. data/test/rails_app/app/components/user_form_with_default_fields.rb +8 -0
  89. data/test/rails_app/app/components/user_grid.rb +4 -0
  90. data/test/rails_app/app/components/window_component_loader.rb +17 -0
  91. data/test/{app_root/app/controllers/application.rb → rails_app/app/controllers/application_controller.rb} +1 -0
  92. data/test/rails_app/app/controllers/components_controller.rb +6 -0
  93. data/test/rails_app/app/controllers/welcome_controller.rb +5 -0
  94. data/test/rails_app/app/helpers/application_helper.rb +2 -0
  95. data/test/{app_root → rails_app}/app/models/role.rb +0 -0
  96. data/test/rails_app/app/models/user.rb +6 -0
  97. data/test/rails_app/app/presenters/forms/generic_user.rb +6 -0
  98. data/test/rails_app/app/views/layouts/application.html.erb +13 -0
  99. data/test/rails_app/config.ru +4 -0
  100. data/test/rails_app/config/application.rb +45 -0
  101. data/test/rails_app/config/boot.rb +13 -0
  102. data/test/rails_app/config/database.yml +35 -0
  103. data/test/rails_app/config/environment.rb +6 -0
  104. data/test/rails_app/config/environments/development.rb +22 -0
  105. data/test/rails_app/config/environments/production.rb +49 -0
  106. data/test/rails_app/config/environments/test.rb +35 -0
  107. data/test/rails_app/config/initializers/backtrace_silencers.rb +8 -0
  108. data/test/rails_app/config/initializers/inflections.rb +10 -0
  109. data/test/rails_app/config/initializers/mime_types.rb +5 -0
  110. data/test/rails_app/config/initializers/netzke.rb +7 -0
  111. data/test/rails_app/config/initializers/secret_token.rb +7 -0
  112. data/test/rails_app/config/initializers/session_store.rb +8 -0
  113. data/test/rails_app/config/locales/es.yml +12 -0
  114. data/test/rails_app/config/routes.rb +65 -0
  115. data/test/rails_app/db/development_structure.sql +39 -0
  116. data/test/{app_root/db/migrate/20081222035855_create_netzke_preferences.rb → rails_app/db/migrate/20100905214933_create_netzke_preferences.rb} +2 -4
  117. data/test/{app_root/db/migrate/20090423222114_create_users.rb → rails_app/db/migrate/20100914104207_create_users.rb} +4 -1
  118. data/test/{app_root/db/migrate/20090423214303_create_roles.rb → rails_app/db/migrate/20100914104236_create_roles.rb} +2 -0
  119. data/test/rails_app/db/schema.rb +38 -0
  120. data/test/rails_app/db/seeds.rb +20 -0
  121. data/test/rails_app/features/support/paths.rb +47 -0
  122. data/test/{app_root/config/environments/in_memory.rb → rails_app/lib/tasks/.gitkeep} +0 -0
  123. data/test/rails_app/public/404.html +26 -0
  124. data/test/rails_app/public/422.html +26 -0
  125. data/test/rails_app/public/500.html +26 -0
  126. data/test/{app_root/config/environments/mysql.rb → rails_app/public/favicon.ico} +0 -0
  127. data/test/rails_app/public/images/header-deco.gif +0 -0
  128. data/test/rails_app/public/images/rails.png +0 -0
  129. data/test/rails_app/public/javascripts/application.js +2 -0
  130. data/test/rails_app/public/javascripts/controls.js +965 -0
  131. data/test/rails_app/public/javascripts/dragdrop.js +974 -0
  132. data/test/rails_app/public/javascripts/effects.js +1123 -0
  133. data/test/rails_app/public/javascripts/prototype.js +6001 -0
  134. data/test/rails_app/public/javascripts/rails.js +175 -0
  135. data/test/rails_app/public/robots.txt +5 -0
  136. data/test/{app_root/config/environments/postgresql.rb → rails_app/public/stylesheets/.gitkeep} +0 -0
  137. data/test/rails_app/script/rails +6 -0
  138. data/test/rails_app/spec/models/role_spec.rb +5 -0
  139. data/test/rails_app/spec/models/user_spec.rb +5 -0
  140. data/test/rails_app/test/performance/browsing_test.rb +9 -0
  141. data/test/rails_app/test/test_helper.rb +13 -0
  142. data/test/{app_root/config/environments/sqlite.rb → rails_app/vendor/plugins/.gitkeep} +0 -0
  143. data/test/unit/accordion_panel_test.rb +3 -3
  144. data/test/unit/active_record_basepack_test.rb +4 -4
  145. data/test/unit/tab_panel_test.rb +4 -4
  146. metadata +199 -119
  147. data/lib/netzke/accordion_panel.rb +0 -115
  148. data/lib/netzke/active_record/data_accessor.rb +0 -25
  149. data/lib/netzke/attributes_configurator.rb +0 -195
  150. data/lib/netzke/basic_app.rb +0 -368
  151. data/lib/netzke/border_layout_panel.rb +0 -130
  152. data/lib/netzke/configuration_panel.rb +0 -24
  153. data/lib/netzke/form_panel.rb +0 -138
  154. data/lib/netzke/form_panel/form_panel_api.rb +0 -81
  155. data/lib/netzke/form_panel/form_panel_fields.rb +0 -149
  156. data/lib/netzke/form_panel/form_panel_js.rb +0 -163
  157. data/lib/netzke/grid_panel.rb +0 -367
  158. data/lib/netzke/grid_panel/grid_panel_api.rb +0 -364
  159. data/lib/netzke/grid_panel/grid_panel_columns.rb +0 -232
  160. data/lib/netzke/grid_panel/grid_panel_js.rb +0 -73
  161. data/lib/netzke/grid_panel/javascripts/advanced_search.js +0 -65
  162. data/lib/netzke/grid_panel/multi_edit_form.rb +0 -14
  163. data/lib/netzke/grid_panel/record_form_window.rb +0 -50
  164. data/lib/netzke/panel.rb +0 -11
  165. data/lib/netzke/plugins/configuration_tool.rb +0 -121
  166. data/lib/netzke/property_editor.rb +0 -111
  167. data/lib/netzke/property_editor/helper_model.rb +0 -122
  168. data/lib/netzke/search_panel.rb +0 -199
  169. data/lib/netzke/tab_panel.rb +0 -174
  170. data/lib/netzke/table_editor.rb +0 -118
  171. data/lib/netzke/tree_panel.rb +0 -25
  172. data/lib/netzke/window.rb +0 -82
  173. data/lib/netzke/wrapper.rb +0 -42
  174. data/test/app_root/app/models/book.rb +0 -9
  175. data/test/app_root/app/models/category.rb +0 -2
  176. data/test/app_root/app/models/city.rb +0 -3
  177. data/test/app_root/app/models/continent.rb +0 -2
  178. data/test/app_root/app/models/country.rb +0 -3
  179. data/test/app_root/app/models/genre.rb +0 -3
  180. data/test/app_root/app/models/user.rb +0 -3
  181. data/test/app_root/config/boot.rb +0 -114
  182. data/test/app_root/config/database.yml +0 -21
  183. data/test/app_root/config/environment.rb +0 -14
  184. data/test/app_root/config/environments/sqlite3.rb +0 -0
  185. data/test/app_root/config/routes.rb +0 -4
  186. data/test/app_root/db/migrate/20081222033343_create_books.rb +0 -15
  187. data/test/app_root/db/migrate/20081222033440_create_genres.rb +0 -15
  188. data/test/app_root/db/migrate/20081223024935_create_categories.rb +0 -13
  189. data/test/app_root/db/migrate/20081223025635_create_countries.rb +0 -14
  190. data/test/app_root/db/migrate/20081223025653_create_continents.rb +0 -13
  191. data/test/app_root/db/migrate/20081223025732_create_cities.rb +0 -15
  192. data/test/app_root/db/migrate/20090102223630_create_netzke_field_lists.rb +0 -18
  193. data/test/app_root/script/console +0 -7
  194. data/test/app_root/vendor/plugins/acts_as_list/README +0 -23
  195. data/test/app_root/vendor/plugins/acts_as_list/init.rb +0 -3
  196. data/test/app_root/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +0 -256
@@ -0,0 +1,374 @@
1
+ require "netzke/basepack/grid_panel/columns"
2
+ require "netzke/basepack/grid_panel/services"
3
+ require "netzke/basepack/grid_panel/javascript"
4
+ # require "netzke/basepack/plugins/configuration_tool"
5
+ # require "data_accessor"
6
+
7
+ module Netzke
8
+ module Basepack
9
+ # == GridPanel
10
+ # Ext.grid.EditorGridPanel + server-side code
11
+ #
12
+ # == Features:
13
+ # * multi-line CRUD operations - get, post, delete, create
14
+ # * (multe-record) editing and adding records through a form
15
+ # * column resize, move and hide
16
+ # * permissions
17
+ # * sorting
18
+ # * pagination
19
+ # * filtering
20
+ # * extended configurable search
21
+ # * rows reordering (drag-n-drop)
22
+ # * dynamic configuration of properties and columns
23
+ #
24
+ # == Class configuration
25
+ # Configuration on this level is effective during the life-time of the application. They can be put into a .rb file
26
+ # inside of config/initializers like this:
27
+ #
28
+ # Netzke::GridPanel.column_filters_available = false
29
+ # Netzke::GridPanel.default_config = {:enable_config_tool => false}
30
+ #
31
+ # Most of these options directly influence the amount of JavaScript code that is generated for this component's class.
32
+ # The less functionality is enabled, the less code is generated.
33
+ #
34
+ # The following configuration options are available:
35
+ # * <tt>:column_filters_available</tt> - (default is true) include code for the filters in the column's context menu
36
+ # * <tt>:config_tool_available</tt> - (default is true) include code for the configuration tool that launches the configuration panel
37
+ # * <tt>:edit_in_form_available</tt> - (defaults to true) include code for (multi-record) editing and adding records through a form
38
+ # * <tt>:extended_search_available</tt> - (defaults to true) include code for extended configurable search
39
+ # * <tt>:default_config</tt> - a hash of default configuration options for each instance of the GridPanel component.
40
+ # See the "Instance configuration" section below.
41
+ #
42
+ # == Instance configuration
43
+ # The following config options are available:
44
+ # * <tt>:model</tt> - name of the ActiveRecord model that provides data to this GridPanel.
45
+ # * <tt>:strong_default_attrs</tt> - a hash of attributes to be merged atop of every created/updated record.
46
+ # * <tt>:query</tt> - specifies how the data should be filtered.
47
+ # When it's a symbol, it's used as a scope name.
48
+ # When it's a string, it's a SQL statement (passed directly to +where+).
49
+ # When it's a hash, it's a conditions hash (passed directly to +where+).
50
+ # When it's an array, it's expanded into SQL statement with arguments (passed directly to +where+), e.g.:
51
+ #
52
+ # :query => ["id > ?", 100])
53
+ #
54
+ # When it's a Proc, it's passed the model class, and is expected to return a ActiveRecord::Relation, e.g.:
55
+ #
56
+ # :query => { |klass| klass.where(:id.gt => 100).order(:created_at) }
57
+ #
58
+ # * <tt>:enable_column_filters</tt> - enable filters in column's context menu
59
+ # * <tt>:enable_edit_in_form</tt> - provide buttons into the toolbar that activate editing/adding records via a form
60
+ # * <tt>:enable_extended_search</tt> - provide a button into the toolbar that shows configurable search form
61
+ # * <tt>:enable_context_menu</tt> - enable rows context menu
62
+ # * <tt>:enable_rows_reordering</tt> - enable reordering of rows with drag-n-drop; underlying model (specified in <tt>:model</tt>) must implement "acts_as_list"-compatible functionality; defaults to <tt>false</tt>
63
+ # * <tt>:enable_pagination</tt> - enable pagination; defaults to <tt>true</tt>
64
+ # * <tt>:rows_per_page</tt> - number of rows per page (ignored when <tt>:enable_pagination</tt> is set to <tt>false</tt>)
65
+ # * <tt>:load_inline_data</tt> - load initial data into the grid right after its instantiation (saves a request to server); defaults to <tt>true</tt>
66
+ # * <tt>:mode</tt> - when set to <tt>:config</tt>, GridPanel loads in configuration mode
67
+ # * <tt>:add/edit/multi_edit/search_form_config</tt> - additional configuration for add/edit/multi_edit/search form panel
68
+ # * <tt>:add/edit/multi_edit_form_window_config</tt> - additional configuration for the window that wrapps up add/edit/multi_edit form panel
69
+ #
70
+ # Additionally supports Netzke::Base config options.
71
+ #
72
+ # == Columns
73
+ # Here's how the GridPanel decides which columns in which sequence and with which configuration to display.
74
+ # First, the column configs are aquired from this GridPanel's persistent storage, as an array of hashes, each
75
+ # representing a column configuration, such as:
76
+ #
77
+ # {:name => :created_at, :header => "Created", :tooltip => "When the record was created"}
78
+ #
79
+ # This hash *overrides* (deep_merge) the hard-coded configuration, an example of which can be specifying
80
+ # columns for a GridPanel instance, e.g.:
81
+ #
82
+ # :columns => [{:name => :created_at, :sortable => false}]
83
+ #
84
+ # ... which in its turn overrides the defaults provided by persistent storage managed by the AttributesConfigurator
85
+ # that provides *model-level* (as opposed to a component-level) configuration of a database model
86
+ # (which is used by both grids and forms in Netzke).
87
+ # And lastly, the defaults for AttributesConfigurator are calculated from the database model itself (extended by Netzke).
88
+ # For example, in the model you can specify virtual attributes and their types that will be picked up by Netzke, the default
89
+ # order of columns, or excluded columns. For details see <tt>Netzke::ActiveRecord::Attributes</tt>.
90
+ #
91
+ # Each column supports the option :sorting_scope, which defines a scope used for sorting the column. This option would be
92
+ # useful for virtual columns for example. The scope will get one parameter which contains the direction (:asc or :desc)
93
+ # Example:
94
+ # { :name => complete_user_name, :sorting_scope => :sort_user_by_full_name }
95
+ # class User < ActiveRecord::Base
96
+ # scope :sort_user_by_full_name, lambda { |dir|
97
+ # order("users.first_name #{dir.to_s}, users.last_name #{dir.to_s}")
98
+ # }
99
+ # end
100
+ #
101
+ # The columns are displayed in the order specified by what's found first in the following sequence:
102
+ # GridPanel instance's persistent storage
103
+ # hardcoded config
104
+ # AttributesConfigurator persistent storage
105
+ # netzke_expose_attributes in the database model
106
+ # database columns + (eventually) virtual attributes specified with netzke_attribute
107
+ class GridPanel < Netzke::Base
108
+ # Class-level configuration. These options directly influence the amount of generated
109
+ # javascript code for this component's class. For example, if you don't want filters for the grid,
110
+ # set column_filters_available to false, and the javascript for the filters won't be included at all.
111
+ class_attribute :column_filters_available
112
+ self.column_filters_available = true
113
+
114
+ class_attribute :config_tool_available
115
+ self.config_tool_available = true
116
+
117
+ class_attribute :edit_in_form_available
118
+ self.edit_in_form_available = true
119
+
120
+ class_attribute :extended_search_available
121
+ self.extended_search_available = true
122
+
123
+ class_attribute :rows_reordering_available
124
+ self.rows_reordering_available = true
125
+
126
+ class_attribute :default_config
127
+ self.default_config = {
128
+ :enable_edit_in_form => true,
129
+ :enable_extended_search => true,
130
+ :enable_column_filters => true,
131
+ :load_inline_data => true,
132
+ :enable_rows_reordering => false, # column drag n drop
133
+ :enable_pagination => true,
134
+ :rows_per_page => 25,
135
+ :tools => %w{ refresh },
136
+ }
137
+
138
+ include self::Javascript
139
+ include self::Services
140
+ include self::Columns
141
+
142
+ include Netzke::DataAccessor
143
+
144
+ # def self.enforce_config_consistency
145
+ # default_config[:enable_edit_in_form] &&= edit_in_form_available
146
+ # default_config[:enable_extended_search] &&= extended_search_available
147
+ # default_config[:enable_rows_reordering] &&= rows_reordering_available
148
+ # end
149
+
150
+ # def initialize(*args)
151
+ # # Deprecations
152
+ # config[:scopes] && ActiveSupport::Deprecation.warn(":scopes option is not effective any longer for GridPanel. Use :scope instead.")
153
+ #
154
+ # super(*args)
155
+ # end
156
+
157
+ # Include extra javascript that we depend on
158
+ def self.include_js
159
+ res = ["#{File.dirname(__FILE__)}/grid_panel/javascripts/pre.js"]
160
+
161
+ # Optional edit in form functionality
162
+ res << "#{File.dirname(__FILE__)}/grid_panel/javascripts/edit_in_form.js" if edit_in_form_available
163
+
164
+ # Optional extended search functionality
165
+ res << "#{File.dirname(__FILE__)}/grid_panel/javascripts/advanced_search.js" if extended_search_available
166
+
167
+ ext_examples = Netzke::Core.ext_location.join("examples")
168
+
169
+ # Checkcolumn
170
+ res << ext_examples.join("ux/CheckColumn.js")
171
+
172
+ # Filters
173
+ if column_filters_available
174
+ res << ext_examples + "ux/gridfilters/menu/ListMenu.js"
175
+ res << ext_examples + "ux/gridfilters/menu/RangeMenu.js"
176
+ res << ext_examples + "ux/gridfilters/GridFilters.js"
177
+
178
+ %w{Boolean Date List Numeric String}.unshift("").each do |f|
179
+ res << ext_examples + "ux/gridfilters/filter/#{f}Filter.js"
180
+ end
181
+ end
182
+
183
+ # DD
184
+ if rows_reordering_available
185
+ res << "#{File.dirname(__FILE__)}/grid_panel/javascripts/rows-dd.js"
186
+ end
187
+
188
+ res
189
+ end
190
+
191
+ # Fields to be displayed in the "General" tab of the configuration panel
192
+ def self.property_fields
193
+ [
194
+ # {:name => :ext_config__title, :attr_type => :string},
195
+ # {:name => :ext_config__header, :attr_type => :boolean, :default => true},
196
+ # {:name => :ext_config__enable_context_menu, :attr_type => :boolean, :default => true},
197
+ # {:name => :ext_config__enable_pagination, :attr_type => :boolean, :default => true},
198
+ # {:name => :ext_config__rows_per_page, :attr_type => :integer},
199
+ # {:name => :ext_config__prohibit_create, :attr_type => :boolean},
200
+ # {:name => :ext_config__prohibit_update, :attr_type => :boolean},
201
+ # {:name => :ext_config__prohibit_delete, :attr_type => :boolean},
202
+ # {:name => :ext_config__prohibit_read, :attr_type => :boolean}
203
+ ]
204
+ end
205
+
206
+
207
+ def default_bbar
208
+ res = %w{ add edit apply del }.map(&:to_sym).map(&:action)
209
+ res << "-" << :add_in_form.action << :edit_in_form.action if config[:enable_edit_in_form]
210
+ res << "-" << :search.action if config[:enable_extended_search]
211
+ # config[:enable_extended_search] && res << "-" << {
212
+ # :text => "Search",
213
+ # :handler => :on_search,
214
+ # :enable_toggle => true,
215
+ # :icon => :find
216
+ # }
217
+ res
218
+ end
219
+
220
+ def default_context_menu
221
+ res = %w{ edit del }.map(&:to_sym).map(&:action)
222
+ res << "-" << :edit_in_form.action if config[:enable_edit_in_form]
223
+ res
224
+ end
225
+
226
+ def configuration_components
227
+ res = []
228
+ res << {
229
+ :persistent_config => true,
230
+ :name => 'columns',
231
+ :class_name => "FieldsConfigurator",
232
+ :active => true,
233
+ :owner => self
234
+ }
235
+ res << {
236
+ :name => 'general',
237
+ :class_name => "PropertyEditor",
238
+ :component => self,
239
+ :title => false
240
+ }
241
+ res
242
+ end
243
+
244
+ action :add do
245
+ {
246
+ :text => I18n.t('netzke.basepack.grid_panel.add', :default => "Add"),
247
+ :disabled => config[:prohibit_create],
248
+ :icon => :add
249
+ }
250
+ end
251
+
252
+ action :edit, {
253
+ :text => I18n.t('netzke.basepack.grid_panel.edit', :default => "Edit"),
254
+ :disabled => true,
255
+ :icon => :table_edit
256
+ }
257
+
258
+ action :del, {
259
+ :text => I18n.t('netzke.basepack.grid_panel.delete', :default => "Delete"),
260
+ :disabled => true,
261
+ :icon => :table_row_delete
262
+ }
263
+
264
+ action :apply do
265
+ {
266
+ :text => I18n.t('netzke.basepack.grid_panel.apply', :default => "Apply"),
267
+ :disabled => config[:prohibit_update] && config[:prohibit_create],
268
+ :icon => :tick
269
+ }
270
+ end
271
+
272
+ action :add_in_form, {
273
+ :text => I18n.t('netzke.basepack.grid_panel.add_in_form', :default => "Add in form"),
274
+ :icon => :application_form_add
275
+ }
276
+
277
+ action :edit_in_form, {
278
+ :text => I18n.t('netzke.basepack.grid_panel.edit_in_form', :default => "Edit in form"),
279
+ :disabled => true,
280
+ :icon => :application_form_edit
281
+ }
282
+
283
+ action :search, {
284
+ :text => I18n.t('netzke.basepack.grid_panel.search', :default => "Search"),
285
+ :enable_toggle => true,
286
+ :icon => :find
287
+ }
288
+
289
+ component :add_form do
290
+ {
291
+ :lazy_loading => true,
292
+ :class_name => "Basepack::GridPanel::RecordFormWindow",
293
+ :title => "Add #{data_class.table_name.singularize.humanize}",
294
+ :button_align => "right",
295
+ :items => [{
296
+ :class_name => "Basepack::FormPanel",
297
+ :model => config[:model],
298
+ :items => default_fields_for_forms,
299
+ :persistent_config => config[:persistent_config],
300
+ :strong_default_attrs => config[:strong_default_attrs],
301
+ :border => true,
302
+ :bbar => false,
303
+ :header => false,
304
+ :mode => config[:mode],
305
+ :record => data_class.new
306
+ }.deep_merge(config[:add_form_config] || {})]
307
+ }.deep_merge(config[:add_form_window_config] || {})
308
+ end
309
+
310
+ component :edit_form do
311
+ {
312
+ :lazy_loading => true,
313
+ :class_name => "Basepack::GridPanel::RecordFormWindow",
314
+ :title => "Edit #{data_class.table_name.singularize.humanize}",
315
+ :button_align => "right",
316
+ :items => [{
317
+ :class_name => "Basepack::FormPanel",
318
+ :model => config[:model],
319
+ :items => default_fields_for_forms,
320
+ :persistent_config => config[:persistent_config],
321
+ :bbar => false,
322
+ :header => false,
323
+ :mode => config[:mode]
324
+ # :record_id gets assigned by deliver_component at the moment of loading
325
+ }.deep_merge(config[:edit_form_config] || {})]
326
+ }.deep_merge(config[:edit_form_window_config] || {})
327
+ end
328
+
329
+ component :multi_edit_form do
330
+ {
331
+ :lazy_loading => true,
332
+ :class_name => "Basepack::GridPanel::RecordFormWindow",
333
+ :title => "Edit #{data_class.table_name.humanize}",
334
+ :button_align => "right",
335
+ :items => [{
336
+ :class_name => "Basepack::GridPanel::MultiEditForm",
337
+ :model => config[:model],
338
+ :items => default_fields_for_forms,
339
+ :persistent_config => config[:persistent_config],
340
+ :bbar => false,
341
+ :header => false,
342
+ :mode => config[:mode]
343
+ }.deep_merge(config[:multi_edit_form_config] || {})]
344
+ }.deep_merge(config[:multi_edit_form_window_config] || {})
345
+ end
346
+
347
+ component :search_form do
348
+ {
349
+ :lazy_loading => true,
350
+ :class_name => "Basepack::GridPanel::SearchWindow",
351
+ :model => config[:model],
352
+ :fields => default_fields_for_forms
353
+ }
354
+ end
355
+
356
+
357
+ # def search_panel
358
+ # {
359
+ # :class_name => "Basepack::FormPanel",
360
+ # :model => "User",
361
+ # # :items => default_fields_for_forms,
362
+ # # :search_class_name => cronfig[:model],
363
+ # # :persistent_config => config[:persistent_config],
364
+ # :header => false,
365
+ # :bbar => false,
366
+ # # :mode => config[:mode]
367
+ # }
368
+ # end
369
+
370
+ # include ::Netzke::Plugins::ConfigurationTool if config_tool_available # it will load ConfigurationPanel into a modal window
371
+
372
+ end
373
+ end
374
+ end
@@ -0,0 +1,233 @@
1
+ module Netzke
2
+ module Basepack
3
+ class GridPanel < Netzke::Base
4
+ module Columns
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ # Columns to be displayed by the FieldConfigurator, "meta-columns". Each corresponds to a configuration
9
+ # option for each column in the grid.
10
+ def meta_columns
11
+ [
12
+ # Whether the column will be present in the grid, also in :hidden or :meta state. The value for this column will
13
+ # always be sent to/from the JS grid to the server
14
+ {:name => "included", :attr_type => :boolean, :width => 40, :header => "Incl", :default_value => true},
15
+
16
+ # The name of the column. May be any accessible method or attribute of the data_class.
17
+ {:name => "name", :attr_type => :string, :width => 200},
18
+
19
+ # The header for the column.
20
+ {:name => "label", :attr_type => :string, :width => 200, :header => "Header"},
21
+
22
+ # The default value of this column. Is used when a new row in the grid gets created.
23
+ {:name => "default_value", :attr_type => :string, :width => 200},
24
+
25
+ # Options for drop-downs
26
+ {:name => "combobox_options", :attr_type => :string, :editor => :textarea, :width => 200},
27
+
28
+ # Whether the column is editable in the grid.
29
+ {:name => "read_only", :attr_type => :boolean, :header => "R/O", :tooltip => "Read-only"},
30
+
31
+ # Whether the column will be in the hidden state (hide/show columns from the column menu, if it's enabled).
32
+ {:name => "hidden", :attr_type => :boolean},
33
+
34
+ # Whether the column should have "grid filters" enabled
35
+ # (see here: http://www.extjs.com/deploy/dev/examples/grid-filtering/grid-filter-local.html)
36
+ {:name => "with_filters", :attr_type => :boolean, :default_value => true, :header => "Filters"},
37
+
38
+ #
39
+ # Below some rarely used parameters, hidden by default (you can always un-hide them from the column menu).
40
+ #
41
+
42
+ # The column's width
43
+ {:name => "width", :attr_type => :integer, :hidden => true},
44
+
45
+ # Whether the column should be hideable
46
+ {:name => "hideable", :attr_type => :boolean, :default_value => true, :hidden => true},
47
+
48
+ # Whether the column should be sortable (why change it? normally it's hardcoded)
49
+ {:name => "sortable", :attr_type => :boolean, :default_value => true, :hidden => true},
50
+ ]
51
+ end
52
+
53
+ end
54
+
55
+ # Normalized columns for the grid, e.g.:
56
+ # [{:name => :id, :hidden => true, ...}, {:name => :name, :editable => false, ...}, ...]
57
+ def columns(only_included = true)
58
+ @columns ||= begin
59
+ if cols = load_columns
60
+ filter_out_excluded_columns(cols) if only_included
61
+ reverse_merge_equally_named_columns(cols, initial_columns)
62
+ cols
63
+ else
64
+ initial_columns(only_included)
65
+ end
66
+ end
67
+ end
68
+
69
+ # Columns that we fall back to when neither persistent columns, nor configured columns are present.
70
+ # If there's a model-level field configuration, it's being used.
71
+ # Otherwise the defaults straight from the ActiveRecord model ("netzke_attributes").
72
+ # Override this method if you want to provide a fix set of columns in your subclass.
73
+ def default_columns
74
+ @default_columns ||= load_model_level_attrs || data_class.netzke_attributes
75
+ end
76
+
77
+ # Columns that represent a smart merge of default_columns and columns passed during the configuration.
78
+ def initial_columns(only_included = true)
79
+ # Normalize here, as from the config we can get symbols (names) instead of hashes
80
+ columns_from_config = config[:columns] && normalize_attrs(config[:columns])
81
+
82
+
83
+ if columns_from_config
84
+ # automatically add a column that reflects the primary key (unless specified in the config)
85
+ columns_from_config.insert(0, {:name => data_class.primary_key}) unless columns_from_config.any?{ |c| c[:name] == data_class.primary_key }
86
+
87
+ # reverse-merge each column hash from config with each column hash from exposed_attributes
88
+ # (columns from config have higher priority)
89
+ for c in columns_from_config
90
+ corresponding_default_column = default_columns.find{ |k| k[:name] == c[:name] }
91
+ c.reverse_merge!(corresponding_default_column) if corresponding_default_column
92
+ end
93
+ columns_for_create = columns_from_config
94
+ else
95
+ # we didn't have columns configured in component's config, so, use the columns from the data class
96
+ columns_for_create = default_columns
97
+ end
98
+
99
+ filter_out_excluded_columns(columns_for_create) if only_included
100
+
101
+ # Make the column config complete with the defaults
102
+ columns_for_create.each do |c|
103
+ detect_association(c)
104
+ set_default_header(c)
105
+ set_default_editor(c)
106
+ set_default_width(c)
107
+ set_default_hidden(c)
108
+ set_default_editable(c)
109
+ set_default_sortable(c)
110
+ set_default_filterable(c)
111
+ end
112
+
113
+ columns_for_create
114
+ end
115
+
116
+ private
117
+ def filter_out_excluded_columns(cols)
118
+ cols.reject!{ |c| c[:included] == false }
119
+ end
120
+
121
+ # Stores modified columns in persistent storage
122
+ def save_columns!
123
+ # NetzkeFieldList.update_list_for_current_authority(global_id, columns(false), original_data_class.name) if persistent_config_enabled?
124
+ end
125
+
126
+ def load_columns
127
+ # NetzkeFieldList.read_list(global_id) if persistent_config_enabled?
128
+ end
129
+
130
+ def load_model_level_attrs
131
+ # NetzkeModelAttrList.read_list(data_class.name) if persistent_config_enabled?
132
+ end
133
+
134
+ def set_default_header(c)
135
+ c[:label] ||= c[:name].humanize
136
+ end
137
+
138
+ def set_default_editor(c)
139
+ c[:editor] ||= editor_for_attr_type(c[:attr_type])
140
+ c[:editor] = {:xtype => c[:editor]} if c[:editor].is_a?(Symbol)
141
+ end
142
+
143
+ def set_default_width(c)
144
+ c[:width] ||= 50 if c[:attr_type] == :boolean
145
+ c[:width] ||= 150 if c[:attr_type] == :datetime
146
+ end
147
+
148
+ def set_default_hidden(c)
149
+ c[:hidden] = true if primary_key_attr?(c) && c[:hidden].nil?
150
+ end
151
+
152
+ def set_default_editable(c)
153
+ c[:editable] = c[:read_only].nil? ? !(primary_key_attr?(c) || c[:virtual]) : !c[:read_only]
154
+ c.delete(:read_only)
155
+ end
156
+
157
+ def set_default_sortable(c)
158
+ c[:sortable] = !c[:virtual] if c[:sortable].nil?
159
+ end
160
+
161
+ def set_default_filterable(c)
162
+ c[:filterable] = !c[:virtual] if c[:filterable].nil?
163
+ end
164
+
165
+ # Returns editor's xtype for a column type
166
+ def editor_for_attr_type(type)
167
+ attr_type_to_editor_map[type]
168
+ end
169
+
170
+ def editor_for_association
171
+ :combobox
172
+ end
173
+
174
+ # Returns a hash that maps a column type to the editor xtype. Override if you want different editors.
175
+ def attr_type_to_editor_map
176
+ {
177
+ :integer => :numberfield,
178
+ :boolean => :checkbox,
179
+ :date => :datefield,
180
+ :datetime => :xdatetime,
181
+ :text => :textarea,
182
+ :string => :textfield
183
+ }
184
+ end
185
+
186
+ # Detects an association column and sets up the proper editor.
187
+ def detect_association(c)
188
+ # double-underscore notation? surely an association column
189
+ if c[:name].index('__')
190
+ assoc_name, assoc_method = c[:name].split('__')
191
+ assoc = data_class.reflect_on_association(assoc_name.to_sym)
192
+
193
+ if assoc && assoc_method
194
+ assoc_column = assoc.klass.columns_hash[assoc_method]
195
+ assoc_method_type = assoc_column.try(:type)
196
+
197
+ # if association column is boolean, display a checkbox (or alike), otherwise - a combobox (or alike)
198
+ c[:editor] ||= assoc_method_type == :boolean ? editor_for_attr_type(:boolean) : editor_for_association
199
+ end
200
+ end
201
+ end
202
+
203
+ # Default fields that will be displayed in the Add/Edit/Search forms
204
+ def default_fields_for_forms
205
+ form_klass = "Netzke::ModelExtensions::#{config[:model]}ForFormPanel".constantize rescue nil
206
+ form_klass ||= original_data_class
207
+
208
+ # Select only those fields that are known to the form_klass
209
+ selected_columns = columns.select do |c|
210
+ form_klass.column_names.include?(c[:name]) ||
211
+ form_klass.instance_methods.include?("#{c[:name]}=") ||
212
+ association_attr?(c[:name])
213
+ end
214
+
215
+ selected_columns.map do |c|
216
+ field_config = {:name => c[:name]}
217
+
218
+ # scopes for combobox options
219
+ field_config[:scopes] = c[:editor].is_a?(Hash) && c[:editor][:scopes]
220
+
221
+ field_config
222
+ end
223
+ end
224
+
225
+ # Receives 2 arrays of columns. Merges the missing config from the +source+ into +dest+, matching columns by name
226
+ def reverse_merge_equally_named_columns(dest, source)
227
+ dest.each{ |dc| dc.reverse_merge!(source.detect{ |sc| sc[:name] == dc[:name] } || {}) }
228
+ end
229
+
230
+ end
231
+ end
232
+ end
233
+ end