datagrid 1.8.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +11 -1
  4. data/{Readme.markdown → README.md} +44 -29
  5. data/app/assets/stylesheets/datagrid.css +145 -0
  6. data/app/views/datagrid/_enum_checkboxes.html.erb +5 -3
  7. data/app/views/datagrid/_form.html.erb +4 -4
  8. data/app/views/datagrid/_head.html.erb +26 -3
  9. data/app/views/datagrid/_range_filter.html.erb +5 -3
  10. data/app/views/datagrid/_row.html.erb +12 -1
  11. data/app/views/datagrid/_table.html.erb +4 -4
  12. data/datagrid.gemspec +8 -7
  13. data/lib/datagrid/active_model.rb +9 -17
  14. data/lib/datagrid/base.rb +39 -0
  15. data/lib/datagrid/column_names_attribute.rb +9 -11
  16. data/lib/datagrid/columns/column.rb +155 -133
  17. data/lib/datagrid/columns.rb +325 -115
  18. data/lib/datagrid/configuration.rb +33 -4
  19. data/lib/datagrid/core.rb +89 -54
  20. data/lib/datagrid/deprecated_object.rb +20 -0
  21. data/lib/datagrid/drivers/abstract_driver.rb +12 -23
  22. data/lib/datagrid/drivers/active_record.rb +24 -26
  23. data/lib/datagrid/drivers/array.rb +22 -14
  24. data/lib/datagrid/drivers/mongo_mapper.rb +15 -14
  25. data/lib/datagrid/drivers/mongoid.rb +15 -17
  26. data/lib/datagrid/drivers/sequel.rb +14 -19
  27. data/lib/datagrid/drivers.rb +2 -1
  28. data/lib/datagrid/engine.rb +11 -3
  29. data/lib/datagrid/filters/base_filter.rb +166 -143
  30. data/lib/datagrid/filters/boolean_filter.rb +19 -5
  31. data/lib/datagrid/filters/date_filter.rb +33 -35
  32. data/lib/datagrid/filters/date_time_filter.rb +24 -16
  33. data/lib/datagrid/filters/default_filter.rb +9 -3
  34. data/lib/datagrid/filters/dynamic_filter.rb +151 -105
  35. data/lib/datagrid/filters/enum_filter.rb +43 -19
  36. data/lib/datagrid/filters/extended_boolean_filter.rb +39 -31
  37. data/lib/datagrid/filters/float_filter.rb +15 -5
  38. data/lib/datagrid/filters/integer_filter.rb +21 -10
  39. data/lib/datagrid/filters/ranged_filter.rb +66 -45
  40. data/lib/datagrid/filters/select_options.rb +58 -49
  41. data/lib/datagrid/filters/string_filter.rb +9 -4
  42. data/lib/datagrid/filters.rb +204 -79
  43. data/lib/datagrid/form_builder.rb +116 -128
  44. data/lib/datagrid/generators/scaffold.rb +184 -0
  45. data/lib/datagrid/generators/views.rb +20 -0
  46. data/lib/datagrid/helper.rb +436 -69
  47. data/lib/datagrid/ordering.rb +26 -29
  48. data/lib/datagrid/rspec.rb +6 -10
  49. data/lib/datagrid/utils.rb +37 -30
  50. data/lib/datagrid/version.rb +3 -1
  51. data/lib/datagrid.rb +8 -28
  52. data/templates/base.rb.erb +6 -4
  53. data/templates/grid.rb.erb +1 -1
  54. metadata +17 -17
  55. data/app/assets/stylesheets/datagrid.sass +0 -134
  56. data/lib/datagrid/filters/composite_filters.rb +0 -49
  57. data/lib/datagrid/renderer.rb +0 -157
  58. data/lib/datagrid/scaffold.rb +0 -129
  59. data/lib/tasks/datagrid_tasks.rake +0 -15
  60. data/templates/controller.rb.erb +0 -6
  61. data/templates/index.html.erb +0 -5
@@ -1,10 +1,248 @@
1
- require "datagrid/engine"
1
+ # frozen_string_literal: true
2
+
2
3
  require "action_view"
3
4
 
4
5
  module Datagrid
6
+ # # Datagrid Frontend Guide
7
+ #
8
+ # ## Description
9
+ #
10
+ # The easiest way to start with Datagrid frontend is by using the generator:
11
+ #
12
+ # ``` sh
13
+ # rails generate datagrid:scaffold users
14
+ # ```
15
+ #
16
+ # This command builds the controller, view, route, and adds
17
+ # [built-in CSS](https://github.com/bogdan/datagrid/blob/master/app/assets/stylesheets/datagrid.sass).
18
+ #
19
+ # Datagrid includes helpers and a form builder for easy frontend generation.
20
+ # If you need a fully-featured custom GUI, create your templates manually
21
+ # with the help of the {Datagrid::Columns} API.
22
+ #
23
+ # ## Controller and Routing
24
+ #
25
+ # Grids usually implement the `index` action of a Rails REST resource. Here's an example:
26
+ #
27
+ # resources :models, only: [:index]
28
+ #
29
+ # Use the `GET` method in the form, and the controller becomes straightforward:
30
+ #
31
+ # class ModelsController < ApplicationController
32
+ # def index
33
+ # @grid = ModelsGrid.new(params[:my_report]) do |scope|
34
+ # scope.page(params[:page]) # See pagination section
35
+ # end
36
+ # end
37
+ # end
38
+ #
39
+ # To apply additional scoping conditions, such as visibility based on the current user:
40
+ #
41
+ # ModelsGrid.new(params[:my_report]) do |scope|
42
+ # scope.where(owner_id: current_user.id).page(params[:page])
43
+ # end
44
+ #
45
+ # To pass an object to a grid instance, define it as an accessible attribute:
46
+ #
47
+ # class ModelsGrid
48
+ # attr_accessor :current_user
49
+ # end
50
+ #
51
+ # Then pass it when initializing the grid:
52
+ #
53
+ # ModelsGrid.new(params[:models_grid].merge(current_user: current_user))
54
+ #
55
+ # ## Form Builder
56
+ #
57
+ # ### Basic Method
58
+ #
59
+ # Use the built-in partial:
60
+ #
61
+ # = datagrid_form_with model: @grid, url: report_path, other_form_for_option: value
62
+ #
63
+ # {#datagrid_form_with} supports the same options as Rails `form_with`.
64
+ #
65
+ # ### Advanced Method
66
+ #
67
+ # You can use Rails built-in tools to create a form.
68
+ # Additionally, Datagrid provides helpers to generate input/select elements for filters:
69
+ #
70
+ # ``` haml
71
+ # - form_with model: UserGrid.new, method: :get, url: users_path do |f|
72
+ # %div
73
+ # = f.datagrid_label :name
74
+ # = f.datagrid_filter :name # => <input name="grid[name]" type="text"/>
75
+ # %div
76
+ # = f.datagrid_label :category_id
77
+ # = f.datagrid_filter :category_id # => <select name="grid[category_id]">....</select>
78
+ # ```
79
+ #
80
+ # For more flexibility, use Rails default helpers:
81
+ #
82
+ # %div
83
+ # = f.label :name
84
+ # = f.text_field :name
85
+ #
86
+ # See the localization section of {Datagrid::Filters}.
87
+ #
88
+ # ## Datagrid Table
89
+ #
90
+ # Use the helper to display a report:
91
+ #
92
+ # %div== Total #{@grid.assets.total}
93
+ # = datagrid_table(@report)
94
+ # = will_paginate @report.assets
95
+ #
96
+ # Options:
97
+ #
98
+ # - `:html` - Attributes for the `<table>` tag.
99
+ # - `:order` - Set to `false` to disable ordering controls (default: `true`).
100
+ # - `:columns` - Specify an array of column names to display.
101
+ #
102
+ # ## Pagination
103
+ #
104
+ # Datagrid is abstracted from pagination but integrates seamlessly with tools like Kaminari, WillPaginate, or Pagy:
105
+ #
106
+ # # Kaminari
107
+ # @grid = MyGrid.new(params[:grid]) do |scope|
108
+ # scope.page(params[:page]).per(10)
109
+ # end
110
+ #
111
+ # # WillPaginate
112
+ # @grid = MyGrid.new(params[:grid]) do |scope|
113
+ # scope.page(params[:page]).per_page(10)
114
+ # end
115
+ #
116
+ # # Pagy
117
+ # @grid = MyGrid.new(params[:grid])
118
+ # @pagy, @records = pagy(@grid.assets)
119
+ #
120
+ # Render the paginated collection:
121
+ #
122
+ # # WillPaginate or Kaminari
123
+ # <%= datagrid_table(@grid, options) %>
124
+ # # Pagy
125
+ # <%= datagrid_table(@grid, @records, options) %>
126
+ #
127
+ # ## CSV Export
128
+ #
129
+ # Add CSV support to your controller:
130
+ #
131
+ # class UsersController < ApplicationController
132
+ # def index
133
+ # @grid = UsersGrid.new(params[:users_grid])
134
+ # respond_to do |f|
135
+ # f.html { @grid.scope { |scope| scope.page(params[:page]) } }
136
+ # f.csv do
137
+ # send_data @grid.to_csv, type: "text/csv", disposition: 'inline', filename: "grid-#{Time.now.to_s}.csv"
138
+ # end
139
+ # end
140
+ # end
141
+ # end
142
+ #
143
+ # Add a button in your interface:
144
+ #
145
+ # link_to "Get CSV", url_for(format: 'csv', users_grid: params[:users_grid])
146
+ #
147
+ # ## AJAX
148
+ #
149
+ # Datagrid supports asynchronous data loading. Add this to your controller:
150
+ #
151
+ # if request.xhr?
152
+ # render json: {table: view_context.datagrid_table(@grid)}
153
+ # end
154
+ #
155
+ # Modify the form for AJAX:
156
+ #
157
+ # = datagrid_form_with model: @grid, html: {class: 'js-datagrid-form'}
158
+ # .js-datagrid-table
159
+ # = datagrid_table @grid
160
+ # .js-pagination
161
+ # = paginate @grid.assets
162
+ # :javascript
163
+ # $('.js-datagrid-form').submit(function(event) {
164
+ # event.preventDefault();
165
+ # $.get($(this).attr("action"), $(this).serialize(), function (data) {
166
+ # $('.js-datagrid-table').html(data.table);
167
+ # });
168
+ # });
169
+ #
170
+ # ## Modifying Built-In Partials
171
+ #
172
+ # To customize Datagrid views:
173
+ #
174
+ # rake datagrid:copy_partials
175
+ #
176
+ # This creates files in `app/views/datagrid/`, which you can modify to suit your needs:
177
+ #
178
+ # app/views/datagrid/
179
+ # ├── _enum_checkboxes.html.erb # datagrid_filter for filter(name, :enum, checkboxes: true)
180
+ # ├── _form.html.erb # datagrid_form_with
181
+ # ├── _head.html.erb # datagrid_header
182
+ # ├── _range_filter.html.erb # datagrid_filter for filter(name, type, range: true)
183
+ # ├── _row.html.erb # datagrid_rows/datagrid_rows
184
+ # └── _table.html.erb # datagrid_table
185
+ #
186
+ # ## Custom Options
187
+ #
188
+ # You can add custom options to Datagrid columns and filters and implement their support on the frontend.
189
+ # For example, you might want to add a `description` option to a column that appears as a tooltip on mouseover.
190
+ #
191
+ # column(
192
+ # :aov, header: 'AOV',
193
+ # description: 'Average order value: sum of orders subtotal divided by their count'
194
+ # ) do |category|
195
+ # category.orders.sum(:subtotal) / category.orders.count
196
+ # end
197
+ #
198
+ # The `:description` option is not built into Datagrid, but you can implement it
199
+ # by adding the following to partial `app/views/datagrid/_header.html.erb`:
200
+ #
201
+ # <% if column.options[:description] %>
202
+ # <a data-toggle="tooltip" title="<%= column.options[:description] %>">
203
+ # <i class="icon-question-sign"></i>
204
+ # </a>
205
+ # <% end %>
206
+ #
207
+ # This modification allows the `:description` tooltip to work with your chosen UI and JavaScript library.
208
+ # The same technique can be applied to filters by calling `filter.options` in corresponding partials.
209
+ #
210
+ # ## Highlight Rows
211
+ #
212
+ # To add custom HTML classes to each row for styling, modify the `_row.html.erb` partial:
213
+ #
214
+ # ``` diff
215
+ # -<tr>
216
+ # +<tr class="<%= grid.respond_to?(:row_class) ? grid.row_class(asset) : "" %>">
217
+ # <% grid.html_columns(*options[:columns]).each do |column| %>
218
+ # <td class="<%= datagrid_column_classes(grid, column) %>">
219
+ # <%= datagrid_value(grid, column, asset) %>
220
+ # </td>
221
+ # <% end %>
222
+ # ```
223
+ #
224
+ # This allows you to define a custom `row_class` method in your grid class, like this:
225
+ #
226
+ # class IssuesGrid < ApplicationGrid
227
+ # scope { Issue }
228
+ #
229
+ # def row_class(issue)
230
+ # case issue.status
231
+ # when "fixed" then "green"
232
+ # when "rejected" then "red"
233
+ # else "blue"
234
+ # end
235
+ # end
236
+ # end
237
+ #
238
+ # ## Localization
239
+ #
240
+ # You can overwrite Datagrid’s custom localization keys at the application level.
241
+ # See the localization keys here:
242
+ #
243
+ # https://github.com/bogdan/datagrid/blob/master/lib/datagrid/locale/en.yml
5
244
  module Helper
6
-
7
- # @param grid [Datagrid] grid object
245
+ # @param grid [Datagrid::Base] grid object
8
246
  # @param column [Datagrid::Columns::Column, String, Symbol] column name
9
247
  # @param model [Object] an object from grid scope
10
248
  # @return [Object] individual cell value from the given grid, column name and model
@@ -15,7 +253,9 @@ module Datagrid
15
253
  # <% end %>
16
254
  # </ul>
17
255
  def datagrid_value(grid, column, model)
18
- datagrid_renderer.format_value(grid, column, model)
256
+ column = grid.column_by_name(column) if column.is_a?(String) || column.is_a?(Symbol)
257
+
258
+ grid.html_value(column, self, model)
19
259
  end
20
260
 
21
261
  # @!visibility private
@@ -26,133 +266,260 @@ module Datagrid
26
266
  # Renders html table with columns defined in grid class.
27
267
  # In the most common used you need to pass paginated collection
28
268
  # to datagrid table because datagrid do not have pagination compatibilities:
29
- # Supported options:
30
- #
31
- # * <tt>:html</tt> - hash of attributes for <table> tag
32
- # * <tt>:order</tt> - If false do not generate ordering controlls.
33
- # Default: true.
34
- # * <tt>:columns</tt> - Array of column names to display.
35
- # Used in case when same grid class is used in different places
36
- # and needs different columns. Default: all defined columns.
37
- # * <tt>:partials</tt> - Path for partials lookup.
38
- # Default: 'datagrid'.
39
- # @param grid [Datagrid] grid object
269
+ # @param grid [Datagrid::Base] grid object
40
270
  # @param assets [Array] objects from grid scope
271
+ # @param [Hash{Symbol => Object}] options HTML attributes to be passed to `<table>` tag
272
+ # @option options [Hash] html A hash of attributes for the `<table>` tag.
273
+ # @option options [Boolean] order Whether to generate ordering controls.
274
+ # If set to `false`, ordering controls are not generated. Default: `true`.
275
+ # @option options [Array<Symbol>] columns An array of column names to display.
276
+ # Use this when the same grid class is used in different contexts and requires different columns.
277
+ # Default: all defined columns.
278
+ # @option options [String] partials The path for partials lookup. Default: `'datagrid'`.
41
279
  # @return [String] table tag HTML markup
42
280
  # @example
43
281
  # assets = grid.assets.page(params[:page])
44
282
  # datagrid_table(grid, assets, options)
45
283
  def datagrid_table(grid, assets = grid.assets, **options)
46
- datagrid_renderer.table(grid, assets, **options)
284
+ _render_partial(
285
+ "table", options[:partials],
286
+ {
287
+ grid: grid,
288
+ options: options,
289
+ assets: assets,
290
+ },
291
+ )
47
292
  end
48
293
 
49
294
  # Renders HTML table header for given grid instance using columns defined in it
50
295
  #
51
- # Supported options:
52
- #
53
- # * <tt>:order</tt> - display ordering controls built-in into header
54
- # Default: true
55
- # * <tt>:columns</tt> - Array of column names to display.
56
- # Used in case when same grid class is used in different places
57
- # and needs different columns. Default: all defined columns.
58
- # * <tt>:partials</tt> - Path for partials lookup.
59
- # Default: 'datagrid'.
60
- # @param grid [Datagrid] grid object
296
+ # @option options [Boolean] order Whether to display ordering controls built into the header.
297
+ # Default: `true`.
298
+ # @option options [Array<Symbol,String>] columns An array of column names to display.
299
+ # Use this when the same grid class is used in different contexts and requires different columns.
300
+ # Default: all defined columns.
301
+ # @option options [String] partials The path for partials lookup.
302
+ # Default: `'datagrid'`.
303
+ # @param grid [Datagrid::Base] grid object
304
+ # @param [Object] opts (deprecated) pass keyword arguments instead
305
+ # @param [Hash] options
61
306
  # @return [String] HTML table header tag markup
62
- def datagrid_header(grid, options = {})
63
- datagrid_renderer.header(grid, options)
64
- end
307
+ def datagrid_header(grid, opts = :__unspecified__, **options)
308
+ unless opts == :__unspecified__
309
+ Datagrid::Utils.warn_once("datagrid_header now requires ** operator when passing options.")
310
+ options.reverse_merge!(opts)
311
+ end
312
+ options[:order] = true unless options.key?(:order)
65
313
 
314
+ _render_partial("head", options[:partials],
315
+ { grid: grid, options: options },)
316
+ end
66
317
 
67
318
  # Renders HTML table rows using given grid definition using columns defined in it.
68
319
  # Allows to provide a custom layout for each for in place with a block
69
320
  #
70
- # Supported options:
71
- #
72
- # * <tt>:columns</tt> - Array of column names to display.
73
- # Used in case when same grid class is used in different places
74
- # and needs different columns. Default: all defined columns.
75
- # * <tt>:partials</tt> - Path for partials lookup.
76
- # Default: 'datagrid'.
77
- #
78
- # @example
79
- # = datagrid_rows(grid) # Generic table rows Layout
80
- #
81
- # = datagrid_rows(grid) do |row| # Custom Layout
321
+ # @option options [Array<Symbol>] columns An array of column names to display.
322
+ # Use this when the same grid class is used in different contexts and requires different columns.
323
+ # Default: all defined columns.
324
+ # @option options [String] partials The path for partials lookup.
325
+ # Default: `'datagrid'`.
326
+ # @return [String]
327
+ # @example Generic table rows Layout
328
+ # = datagrid_rows(grid)
329
+ # @example Custom Layout
330
+ # = datagrid_rows(grid) do |row|
82
331
  # %tr
83
332
  # %td= row.project_name
84
333
  # %td.project-status{class: row.status}= row.status
334
+ # @param [Datagrid::Base] grid datagrid object
335
+ # @param [Array<Object>] assets assets as per defined in grid scope
85
336
  def datagrid_rows(grid, assets = grid.assets, **options, &block)
86
- datagrid_renderer.rows(grid, assets, **options, &block)
337
+ safe_join(
338
+ assets.map do |asset|
339
+ datagrid_row(grid, asset, **options, &block)
340
+ end.to_a,
341
+ )
87
342
  end
88
343
 
89
- # Renders ordering controls for the given column name
90
- #
91
- # Supported options:
92
- #
93
- # * <tt>:partials</tt> - Path for partials lookup.
94
- # Default: 'datagrid'.
344
+ # @return [String] renders ordering controls for the given column name
345
+ # @option options [String] partials The path for partials lookup.
346
+ # Default: `'datagrid'`.
347
+ # @param [Datagrid::Base] grid datagrid object
348
+ # @param [Datagrid::Columns::Column] column
349
+ # @deprecated Put necessary code inline inside datagrid/head partial.
350
+ # See built-in partial for example.
95
351
  def datagrid_order_for(grid, column, options = {})
96
- datagrid_renderer.order_for(grid, column, options)
352
+ Datagrid::Utils.warn_once(<<~MSG)
353
+ datagrid_order_for is deprecated.
354
+ Put necessary code inline inside datagrid/head partial.
355
+ See built-in partial for example.
356
+ MSG
357
+ _render_partial("order_for", options[:partials],
358
+ { grid: grid, column: column },)
97
359
  end
98
360
 
99
- # Renders HTML for for grid with all filters inputs and lables defined in it
361
+ # Renders HTML for grid with all filters inputs and labels defined in it
362
+ # @option options [String] partials Path for form partial lookup.
363
+ # Default: `'datagrid'`, which uses `app/views/datagrid/` partials.
364
+ # Example: `'datagrid_admin'` uses `app/views/datagrid_admin` partials.
365
+ # @option options [Datagrid::Base] model a Datagrid object to be rendered.
366
+ # @option options [Hash] All options supported by Rails `form_with` helper.
367
+ # @param [Hash{Symbol => Object}] options
368
+ # @return [String] form HTML tag markup
369
+ def datagrid_form_with(**options)
370
+ raise ArgumentError, "datagrid_form_with block argument is invalid. Use form_with instead." if block_given?
371
+
372
+ grid = options[:model]
373
+ raise ArgumentError, "Grid has no available filters" if grid&.filters&.empty?
374
+
375
+ _render_partial("form", options[:partials], { grid: options[:model], options: options })
376
+ end
377
+
378
+ # Renders HTML for grid with all filters inputs and labels defined in it
100
379
  #
101
380
  # Supported options:
102
381
  #
103
382
  # * <tt>:partials</tt> - Path for form partial lookup.
104
383
  # Default: 'datagrid'.
105
- # * All options supported by Rails <tt>form_for</tt> helper
106
- # @param grid [Datagrid] grid object
384
+ # * All options supported by Rails <tt>form_with</tt> helper
385
+ # @deprecated Use {#datagrid_form_with} instead.
386
+ # @param grid [Datagrid::Base] grid object
387
+ # @param [Hash] options
107
388
  # @return [String] form HTML tag markup
108
389
  def datagrid_form_for(grid, options = {})
109
- datagrid_renderer.form_for(grid, options)
390
+ Datagrid::Utils.warn_once("datagrid_form_for is deprecated if favor of datagrid_form_with.")
391
+ _render_partial(
392
+ "form", options[:partials],
393
+ grid: grid,
394
+ options: {
395
+ method: :get,
396
+ as: grid.param_name,
397
+ local: true,
398
+ **options,
399
+ },
400
+ )
110
401
  end
111
402
 
112
403
  # Provides access to datagrid columns data.
113
404
  # Used in case you want to build html table completelly manually
114
- # @param grid [Datagrid] grid object
405
+ # @param grid [Datagrid::Base] grid object
115
406
  # @param asset [Object] object from grid scope
116
407
  # @param block [Proc] block with Datagrid::Helper::HtmlRow as an argument returning a HTML markup as a String
408
+ # @param [Hash{Symbol => Object}] options
117
409
  # @return [Datagrid::Helper::HtmlRow, String] captured HTML markup if block given otherwise row object
118
- # @example
119
- # # Suppose that grid has first_name and last_name columns
410
+ # @example Render default layout for row
411
+ # <%= datagrid_row(grid, user, columns: [:first_name, :last_name, :actions]) %>
412
+ # @example Rendering custom layout for `first_name` and `last_name` columns
120
413
  # <%= datagrid_row(grid, user) do |row| %>
121
414
  # <tr>
122
415
  # <td><%= row.first_name %></td>
123
416
  # <td><%= row.last_name %></td>
124
417
  # </tr>
125
418
  # <% end %>
126
- # @example
419
+ # @example Rendering custom layout passing a block
127
420
  # <% row = datagrid_row(grid, user) %>
128
421
  # First Name: <%= row.first_name %>
129
422
  # Last Name: <%= row.last_name %>
130
- # @example
131
- # <%= datagrid_row(grid, user, columns: [:first_name, :last_name, :actions]) %>
132
423
  def datagrid_row(grid, asset, **options, &block)
133
- datagrid_renderer.row(grid, asset, **options, &block)
424
+ Datagrid::Helper::HtmlRow.new(self, grid, asset, options).tap do |row|
425
+ return capture(row, &block) if block_given?
426
+ end
134
427
  end
135
428
 
136
429
  # Generates an ascending or descending order url for the given column
137
- # @param grid [Datagrid] grid object
430
+ # @param grid [Datagrid::Base] grid object
138
431
  # @param column [Datagrid::Columns::Column, String, Symbol] column name
139
- # @param descending [Boolean] specifies order direction. Ascending if false, otherwise descending.
432
+ # @param descending [Boolean] order direction, descending if true, otherwise ascending.
140
433
  # @return [String] order layout HTML markup
141
434
  def datagrid_order_path(grid, column, descending)
142
- datagrid_renderer.order_path(grid, column, descending, request)
435
+ column = grid.column_by_name(column)
436
+ query = request&.query_parameters || {}
437
+ ActionDispatch::Http::URL.path_for(
438
+ path: request&.path || "/",
439
+ params: query.merge(grid.query_params(order: column.name, descending: descending)),
440
+ )
143
441
  end
144
442
 
443
+ # @!visibility private
444
+ def datagrid_column_classes(grid, column)
445
+ Datagrid::Utils.warn_once(<<~MSG)
446
+ datagrid_column_classes is deprecated. Assign necessary classes manually.
447
+ Correspond to default datagrid/rows partial for example.)
448
+ MSG
449
+ column = grid.column_by_name(column)
450
+ order_class = if grid.ordered_by?(column)
451
+ ["ordered", grid.descending ? "desc" : "asc"]
452
+ end
453
+ class_names(column.name, order_class, column.options[:class], column.tag_options[:class])
454
+ end
145
455
 
146
456
  protected
147
457
 
148
- def datagrid_renderer
149
- Renderer.for(self)
458
+ def _render_partial(partial_name, partials_path, locals = {})
459
+ render({
460
+ partial: File.join(partials_path || "datagrid", partial_name),
461
+ locals: locals,
462
+ })
150
463
  end
151
464
 
152
- def datagrid_column_classes(grid, column)
153
- order_class = grid.ordered_by?(column) ? ["ordered", grid.descending ? "desc" : "asc"] : nil
154
- [column.name, order_class, column.options[:class]].compact.join(" ")
465
+ # Represents a datagrid row that provides access to column values for the given asset
466
+ # @example
467
+ # row = datagrid_row(grid, user)
468
+ # row.class # => Datagrid::Helper::HtmlRow
469
+ # row.first_name # => "<strong>Bogdan</strong>"
470
+ # row.grid # => Datagrid::Base object
471
+ # row.asset # => User object
472
+ # row.each do |value|
473
+ # puts value
474
+ # end
475
+ class HtmlRow
476
+ include Enumerable
477
+
478
+ attr_reader :grid, :asset, :options
479
+
480
+ # @!visibility private
481
+ def initialize(renderer, grid, asset, options)
482
+ @renderer = renderer
483
+ @grid = grid
484
+ @asset = asset
485
+ @options = options
486
+ end
487
+
488
+ # @return [Object] a column value for given column name
489
+ def get(column)
490
+ @renderer.datagrid_value(@grid, column, @asset)
491
+ end
492
+
493
+ # Iterates over all column values that are available in the row
494
+ # param block [Proc] column value iterator
495
+ def each(&block)
496
+ (@options[:columns] || @grid.html_columns).each do |column|
497
+ block.call(get(column))
498
+ end
499
+ end
500
+
501
+ # @return [String] HTML row format
502
+ def to_s
503
+ @renderer.send(:_render_partial, "row", options[:partials], {
504
+ grid: grid,
505
+ options: options,
506
+ asset: asset,
507
+ },)
508
+ end
509
+
510
+ protected
511
+
512
+ def method_missing(method, *args, &blk)
513
+ if (column = @grid.column_by_name(method))
514
+ get(column)
515
+ else
516
+ super
517
+ end
518
+ end
519
+
520
+ def respond_to_missing?(method, include_private = false)
521
+ !!@grid.column_by_name(method) || super
522
+ end
155
523
  end
156
524
  end
157
525
  end
158
-