katalyst-tables 3.0.0.beta1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -2
- data/README.md +56 -190
- data/app/assets/builds/katalyst/tables.esm.js +17 -47
- data/app/assets/builds/katalyst/tables.js +17 -47
- data/app/assets/builds/katalyst/tables.min.js +1 -1
- data/app/assets/builds/katalyst/tables.min.js.map +1 -1
- data/app/components/concerns/katalyst/tables/has_table_content.rb +17 -8
- data/app/components/concerns/katalyst/tables/identifiable.rb +51 -0
- data/app/components/concerns/katalyst/tables/orderable.rb +35 -105
- data/app/components/concerns/katalyst/tables/selectable.rb +18 -75
- data/app/components/concerns/katalyst/tables/sortable.rb +51 -17
- data/app/components/katalyst/table_component.html.erb +4 -4
- data/app/components/katalyst/table_component.rb +271 -53
- data/app/components/katalyst/tables/body_row_component.html.erb +5 -0
- data/app/components/katalyst/tables/body_row_component.rb +4 -31
- data/app/components/katalyst/tables/cell_component.rb +85 -0
- data/app/components/katalyst/tables/{body → cells}/boolean_component.rb +8 -2
- data/app/components/katalyst/tables/{body → cells}/currency_component.rb +7 -7
- data/app/components/katalyst/tables/{body → cells}/date_component.rb +12 -9
- data/app/components/katalyst/tables/{body → cells}/date_time_component.rb +13 -10
- data/app/components/katalyst/tables/{body → cells}/number_component.rb +5 -5
- data/app/components/katalyst/tables/cells/ordinal_component.rb +44 -0
- data/app/components/katalyst/tables/{body → cells}/rich_text_component.rb +8 -5
- data/app/components/katalyst/tables/cells/select_component.rb +39 -0
- data/app/components/katalyst/tables/data.rb +30 -0
- data/app/components/katalyst/tables/header_row_component.html.erb +5 -0
- data/app/components/katalyst/tables/header_row_component.rb +4 -25
- data/app/components/katalyst/tables/label.rb +37 -0
- data/app/components/katalyst/tables/orderable/form_component.rb +38 -0
- data/app/components/katalyst/tables/selectable/form_component.html.erb +3 -3
- data/app/components/katalyst/tables/selectable/form_component.rb +8 -11
- data/app/controllers/concerns/katalyst/tables/backend.rb +2 -28
- data/app/helpers/katalyst/tables/frontend.rb +48 -2
- data/app/javascript/tables/application.js +0 -5
- data/app/javascript/tables/orderable/form_controller.js +8 -6
- data/app/javascript/tables/orderable/item_controller.js +9 -0
- data/app/models/concerns/katalyst/tables/collection/core.rb +6 -1
- data/app/models/concerns/katalyst/tables/collection/sorting.rb +85 -17
- data/app/models/katalyst/tables/collection/array.rb +38 -0
- data/app/models/katalyst/tables/collection/base.rb +4 -0
- data/config/locales/tables.en.yml +0 -6
- data/lib/katalyst/tables/config.rb +23 -0
- data/lib/katalyst/tables.rb +9 -0
- metadata +22 -29
- data/app/components/concerns/katalyst/tables/body/typed_columns.rb +0 -132
- data/app/components/concerns/katalyst/tables/configurable_component.rb +0 -52
- data/app/components/concerns/katalyst/tables/header/typed_columns.rb +0 -179
- data/app/components/katalyst/tables/body/attachment_component.rb +0 -58
- data/app/components/katalyst/tables/body/link_component.rb +0 -40
- data/app/components/katalyst/tables/body_cell_component.rb +0 -55
- data/app/components/katalyst/tables/header/attachment_component.rb +0 -15
- data/app/components/katalyst/tables/header/boolean_component.rb +0 -15
- data/app/components/katalyst/tables/header/currency_component.rb +0 -15
- data/app/components/katalyst/tables/header/date_component.rb +0 -15
- data/app/components/katalyst/tables/header/date_time_component.rb +0 -15
- data/app/components/katalyst/tables/header/link_component.rb +0 -15
- data/app/components/katalyst/tables/header/number_component.rb +0 -15
- data/app/components/katalyst/tables/header/rich_text_component.rb +0 -15
- data/app/components/katalyst/tables/header_cell_component.rb +0 -97
- data/app/helpers/katalyst/tables/frontend/helper.rb +0 -31
- data/app/javascript/tables/turbo/collection_controller.js +0 -38
- data/app/models/katalyst/tables/collection/sort_form.rb +0 -120
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cda2701479ecd72f9964ab539c5203bd0c300aeb962cf926552904575474ddea
|
4
|
+
data.tar.gz: 6f43fc5e31c8536811e28cba0db4be3c0967db24d06ad22f2a72c89512030d87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14acdb5b09216c84c06b2082ed2a11888f0930b1807f7ade14cbc7fa02751f3c888a69b5397df7eb028395b7902eaad47abaa710e33fa24ecc6d6ed98757616f
|
7
|
+
data.tar.gz: f3721287c65a5aa0d4e81c36d5f704b90e2995cf372376ba19c9b03cb5b0129a5f4c8a56b369a09b2c62e72eb585163d656abb303a8dd62aa8b7912193f710b5
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,18 @@
|
|
1
|
-
## [3.0.0
|
2
|
-
|
1
|
+
## [3.0.0]
|
2
|
+
|
3
|
+
- Breaking change: remove Turbo Streams from table and pagination components,
|
4
|
+
focus preservation is handled via Turbo Morph
|
3
5
|
- Improve spec coverage
|
6
|
+
- Re-write internals to make it easier to extend and customize
|
4
7
|
- Update examples in [README](README.md) and [docs](/docs) to reflect changes
|
5
8
|
|
9
|
+
If you're upgrading from 2.x, you'll need to change your controllers to use
|
10
|
+
the recommendations from the README. The changes should be straightforward,
|
11
|
+
but you will need to enable morphing to allow focus preservation.
|
12
|
+
|
13
|
+
In general, we don't recommend using row partials anymore, as it's easier to
|
14
|
+
read the code when the row is defined in the index view.
|
15
|
+
|
6
16
|
## [2.6.0]
|
7
17
|
|
8
18
|
- Added table row selection
|
data/README.md
CHANGED
@@ -24,33 +24,48 @@ import tables from "@katalyst/tables";
|
|
24
24
|
application.load(tables);
|
25
25
|
```
|
26
26
|
|
27
|
+
```scss
|
28
|
+
// app/assets/stylesheets/application.scss
|
29
|
+
@use "@katalyst/tables";
|
30
|
+
```
|
31
|
+
|
27
32
|
## Usage
|
28
33
|
|
29
34
|
This gem provides entry points for backend and frontend concerns:
|
30
|
-
* `Katalyst::TableComponent` can be used render encapsulated tables
|
31
|
-
partial for each row.
|
35
|
+
* `Katalyst::TableComponent` can be used render encapsulated tables.
|
32
36
|
* `Katalyst::Tables::Frontend` provides `table_with` for inline table generation
|
33
37
|
* `Katalyst::Tables::Collection::Base` provides a default entry point for
|
34
38
|
building collections in your controller actions.
|
35
39
|
|
36
|
-
|
40
|
+
### Frontend
|
41
|
+
|
42
|
+
Add `include Katalyst::Tables::Frontend` to your `ApplicationHelper` or similar.
|
43
|
+
|
44
|
+
You can use the `table_with` helper to generate a table inline in your view without explicitly interacting with the
|
45
|
+
table component. This is the preferred approach when creating tables. However, if the table is complex or you need to
|
46
|
+
reuse it, you should consider moving the definition of the row into a partial.
|
37
47
|
|
38
|
-
|
39
|
-
collection
|
48
|
+
```erb
|
49
|
+
<%= table_with collection: @people do |row, person| %>
|
50
|
+
<% row.text :name do |cell| %>
|
51
|
+
<%= link_to cell.value, [:edit, person] %>
|
52
|
+
<% end %>
|
53
|
+
<% row.text :email %>
|
54
|
+
<% end %>
|
55
|
+
```
|
40
56
|
|
41
|
-
|
42
|
-
|
43
|
-
render it for each row (and once for the header row).
|
57
|
+
By not providing a block to the `table_with` call, the gem will look for a partial called `_person.html+row.erb` to
|
58
|
+
render each row:
|
44
59
|
|
45
60
|
```erb
|
46
61
|
<%# locals: { row:, person: nil } %>
|
47
|
-
<% row.
|
62
|
+
<% row.text :name do |cell| %>
|
48
63
|
<%= link_to cell.value, [:edit, person] %>
|
49
64
|
<% end %>
|
50
|
-
<% row.
|
65
|
+
<% row.text :email %>
|
51
66
|
```
|
52
67
|
|
53
|
-
The table
|
68
|
+
The table will call your block / partial once per row and accumulate the cells
|
54
69
|
you generate into rows, including a header row:
|
55
70
|
|
56
71
|
```html
|
@@ -79,52 +94,36 @@ You can customize the partial and/or the name of the resource in a similar style
|
|
79
94
|
to view partials:
|
80
95
|
|
81
96
|
```erb
|
82
|
-
<%=
|
83
|
-
```
|
84
|
-
|
85
|
-
### Inline tables
|
86
|
-
|
87
|
-
You can use the `table_with` helper to generate a table inline in your view without explicitly interacting with the
|
88
|
-
table component. This is primarily intended for backwards compatibility, but it can be useful for simple tables.
|
89
|
-
|
90
|
-
Add `include Katalyst::Tables::Frontend` to your `ApplicationHelper` or similar.
|
91
|
-
|
92
|
-
```erb
|
93
|
-
<%= table_with collection: @people do |row, person| %>
|
94
|
-
<% row.cell :name do |cell| %>
|
95
|
-
<%= link_to cell.value, [:edit, person] %>
|
96
|
-
<% end %>
|
97
|
-
<% row.cell :email %>
|
98
|
-
<% end %>
|
97
|
+
<%= table_with(collection: @employees, as: :person, partial: "person") %>
|
99
98
|
```
|
100
99
|
|
101
100
|
### HTML Attributes
|
102
101
|
|
103
102
|
You can add custom attributes on table, row, and cell tags.
|
104
103
|
|
105
|
-
The table tag takes attributes passed to `
|
104
|
+
The table tag takes attributes passed to `table_with` helper, similar to `form_with`:
|
106
105
|
|
107
106
|
```erb
|
108
|
-
<%=
|
107
|
+
<%= table_with(collection: @people, id: "people-table")
|
109
108
|
```
|
110
109
|
|
111
110
|
Cells support the same approach:
|
112
111
|
|
113
112
|
```erb
|
114
|
-
<%= row.
|
113
|
+
<%= row.text :name, class: "name" %>
|
115
114
|
```
|
116
115
|
|
117
116
|
Rows do not get called directly, so instead you can assign to `html_attributes` on the row builder to customize row tag
|
118
117
|
generation.
|
119
118
|
|
120
119
|
```erb
|
121
|
-
<% row.
|
120
|
+
<% row.update_html_attributes(id: person.id) if row.body? %>
|
122
121
|
```
|
123
122
|
|
124
123
|
Note: because the row builder gets called to generate the header row, you may need to guard calls that access the
|
125
124
|
`person` directly as shown in the previous example. You could also check whether `person` is present.
|
126
125
|
|
127
|
-
|
126
|
+
### Headers
|
128
127
|
|
129
128
|
Tables will automatically generate a header row for you by calling your row partial or provided block with no object.
|
130
129
|
During this call, `row.header?` is true, `row.body?` is false, and the object (`person`) is nil.
|
@@ -133,14 +132,14 @@ All cells generated in the table header iteration will automatically be header c
|
|
133
132
|
in your body rows by passing `heading: true` when you generate the cell.
|
134
133
|
|
135
134
|
```erb
|
136
|
-
<% row.
|
135
|
+
<% row.number :id, heading: true %>
|
137
136
|
```
|
138
137
|
|
139
138
|
The table header cells default to showing the capitalized column name, but you can customize this in one of two ways:
|
140
139
|
|
141
140
|
* Set the value inline
|
142
141
|
```erb
|
143
|
-
<% row.
|
142
|
+
<% row.number :id, label: "ID" %>
|
144
143
|
```
|
145
144
|
* Define a translation for the attribute
|
146
145
|
```yml
|
@@ -163,194 +162,61 @@ the table cell. This is often all you need to do, but if you do want to customis
|
|
163
162
|
the value you can pass a block instead:
|
164
163
|
|
165
164
|
```erb
|
166
|
-
<% row.
|
165
|
+
<% row.text :status do %>
|
167
166
|
<%= person.password.present? ? "Active" : "Invited" %>
|
168
167
|
<% end %>
|
169
168
|
```
|
170
169
|
|
171
|
-
In the context of the block you have access the cell
|
170
|
+
In the context of the block you have access the cell component if you simply
|
172
171
|
want to extend the default behaviour:
|
173
172
|
|
174
173
|
```erb
|
175
|
-
|
176
|
-
|
174
|
+
<%# @type [Katalyst::Tables::CellComponent] cell %>
|
175
|
+
<% row.text :name do |cell| %>
|
176
|
+
<%= link_to cell, person %>
|
177
177
|
<% end %>
|
178
178
|
```
|
179
179
|
|
180
|
-
You can also
|
181
|
-
builder,
|
182
|
-
as arguments.
|
180
|
+
You can also update `html_attributes` on the cell builder, similar to the row
|
181
|
+
builder, see `katalyst-html-attributes` for details.
|
183
182
|
|
184
183
|
## Collections
|
185
184
|
|
186
185
|
The `Katalyst::Tables::Collection::Base` class provides a convenient way to
|
187
186
|
manage collections in your controller actions. It is designed to be used with
|
188
187
|
Pagy for pagination and provides built-in sorting when used with ActiveRecord
|
189
|
-
collections. Sorting and Pagination are off by default,
|
190
|
-
a custom `
|
188
|
+
collections. Sorting and Pagination are off by default, you can either set them
|
189
|
+
on creation or create a custom `Collection` class that sets them on by default:
|
191
190
|
|
192
191
|
```ruby
|
193
|
-
|
194
|
-
|
192
|
+
# in #index
|
193
|
+
Katalyst::Tables::Collection::Base.new(sorting: "name asc", pagination: true)
|
194
|
+
# or as a nested class in your controller
|
195
|
+
class Collection < Katalyst::Tables::Collection::Base
|
196
|
+
config.sorting = "name asc" # requires models have a name attribute
|
195
197
|
config.pagination = true
|
196
198
|
end
|
197
199
|
```
|
198
200
|
|
199
|
-
|
200
|
-
|
201
|
-
```ruby
|
202
|
-
class PeopleController < ApplicationController
|
203
|
-
def index
|
204
|
-
@people = ApplicationCollection.new.with_params(params).apply(People.all)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
```
|
208
|
-
|
209
|
-
Collections can be passed directly to `TableComponent` and it will automatically
|
201
|
+
Collections can be passed directly to `table_with` method and it will automatically
|
210
202
|
detect features such as sorting and generate the appropriate table header links.
|
211
203
|
|
212
204
|
```erb
|
213
|
-
<%=
|
214
|
-
```
|
215
|
-
|
216
|
-
## Sort
|
217
|
-
|
218
|
-
When sort is enabled, table columns will be automatically sortable in the
|
219
|
-
frontend for any column that corresponds to an attribute on the model. You can
|
220
|
-
also add sorting to non-attribute columns by defining a scope in your
|
221
|
-
model:
|
222
|
-
|
223
|
-
```
|
224
|
-
scope :order_by_status, ->(direction) { ... }
|
225
|
-
```
|
226
|
-
|
227
|
-
You can also use sort without using collections, this was the primary backend
|
228
|
-
interface for V1 and takes design cues from Pagy. Start by including the backend
|
229
|
-
in your controller(s):
|
230
|
-
|
231
|
-
```ruby
|
232
|
-
include Katalyst::Tables::Backend
|
233
|
-
```
|
234
|
-
|
235
|
-
Now, in your controller index actions, you can sort your active record
|
236
|
-
collections based on the `sort` param which is appended to the current URL as a
|
237
|
-
get parameter when a user clicks on a column header.
|
238
|
-
|
239
|
-
Building on our example from earlier:
|
240
|
-
|
241
|
-
```ruby
|
242
|
-
class PeopleController < ApplicationController
|
243
|
-
include Katalyst::Tables::Backend
|
244
|
-
|
245
|
-
def index
|
246
|
-
@people = People.all
|
247
|
-
|
248
|
-
@sort, @people = table_sort(@people) # sort
|
249
|
-
end
|
250
|
-
end
|
251
|
-
```
|
252
|
-
|
253
|
-
You then add the sort form object to your view so that it can add column header
|
254
|
-
links and show the current sort state:
|
255
|
-
|
256
|
-
```erb
|
257
|
-
<%= table_with collection: @people, sort: @sort do |row, person| %>
|
258
|
-
<%= row.cell :name %>
|
259
|
-
<%= row.cell :email %>
|
260
|
-
<% end %>
|
261
|
-
```
|
262
|
-
|
263
|
-
## Pagination
|
264
|
-
|
265
|
-
This gem designed to work with [pagy](https://github.com/ddnexus/pagy/).
|
266
|
-
|
267
|
-
If you use collections and enable pagination then pagy will be called internally
|
268
|
-
and the pagy metadata will be available as `pagination` on the collection.
|
269
|
-
|
270
|
-
`Katalyst::Tables::PagyNavComponent` can be used to render the pagination links
|
271
|
-
for a collection.
|
272
|
-
|
273
|
-
```erb
|
274
|
-
<%= render Katalyst::Tables::PagyNavComponent.new(collection: @people) %>
|
205
|
+
<%= table_with(collection:) %>
|
275
206
|
```
|
276
207
|
|
277
208
|
## Extensions
|
278
209
|
|
279
|
-
The following extensions are available:
|
210
|
+
The following extensions are available and activated by default:
|
280
211
|
|
212
|
+
* [Identifiable](docs/identifiable.md) - adds default dom ids to the table and data rows.
|
281
213
|
* [Orderable](docs/orderable.md) - adds bulk-update for 'ordinal' columns via dragging rows in the table.
|
214
|
+
* [Pagination](docs/pagination.md) - handles paginating of data in the collection.
|
282
215
|
* [Selectable](docs/selectable.md) - adds bulk-action support for rows in the table.
|
216
|
+
* [Sortable](docs/sortable.md) - table column headers that can be sorted will be wrapped in links.
|
217
|
+
* [Customization](docs/customization.md) - customize the table and cell rendering.
|
283
218
|
|
284
|
-
|
285
|
-
|
286
|
-
A common pattern we use is to have a cell at the end of the table for actions. For example:
|
287
|
-
|
288
|
-
```html
|
289
|
-
<table class="action-table">
|
290
|
-
<thead>
|
291
|
-
<tr>
|
292
|
-
<th>Name</th>
|
293
|
-
<th class="actions"></th>
|
294
|
-
</tr>
|
295
|
-
</thead>
|
296
|
-
<tbody>
|
297
|
-
<tr>
|
298
|
-
<td>Alice</td>
|
299
|
-
<td class="actions">
|
300
|
-
<a href="/people/1/edit">Edit</a>
|
301
|
-
<a href="/people/1" method="delete">Delete</a>
|
302
|
-
</td>
|
303
|
-
</tr>
|
304
|
-
</tbody>
|
305
|
-
</table>
|
306
|
-
```
|
307
|
-
|
308
|
-
You can write a custom component that helps generate this type of table by
|
309
|
-
adding the required classes and adding helpers for generating the actions.
|
310
|
-
This allows for a declarative table syntax, something like this:
|
311
|
-
|
312
|
-
```erb
|
313
|
-
<%= render ActionTableComponent.new(collection:) do |row| %>
|
314
|
-
<% row.cell :name %>
|
315
|
-
<% row.actions do |cell| %>
|
316
|
-
<%= cell.action "Edit", :edit %>
|
317
|
-
<%= cell.action "Delete", :delete, method: :delete %>
|
318
|
-
<% end %>
|
319
|
-
<% end %>
|
320
|
-
```
|
321
|
-
|
322
|
-
And the customized component:
|
323
|
-
|
324
|
-
```ruby
|
325
|
-
class ActionTableComponent < Katalyst::TableComponent
|
326
|
-
|
327
|
-
config.header_row = "ActionHeaderRow"
|
328
|
-
config.body_row = "ActionBodyRow"
|
329
|
-
config.body_cell = "ActionBodyCell"
|
330
|
-
|
331
|
-
def default_html_attributes
|
332
|
-
{ class: "action-table" }
|
333
|
-
end
|
334
|
-
|
335
|
-
class ActionHeaderRow < Katalyst::Tables::HeaderRowComponent
|
336
|
-
def actions(&block)
|
337
|
-
cell(:actions, class: "actions", label: "", &block)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
class ActionBodyRow < Katalyst::Tables::BodyRowComponent
|
342
|
-
def actions(&block)
|
343
|
-
cell(:actions, class: "actions", &block)
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
class ActionBodyCell < Katalyst::Tables::BodyCellComponent
|
348
|
-
def action(label, href, **attrs)
|
349
|
-
content_tag(:a, label, href: href, **attrs)
|
350
|
-
end
|
351
|
-
end
|
352
|
-
end
|
353
|
-
```
|
219
|
+
You can disable extensions by altering the `Katalyst::Tables.config.component_extensions` before initialization.
|
354
220
|
|
355
221
|
## Development
|
356
222
|
|
@@ -1,41 +1,4 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
2
|
-
import { Turbo } from '@hotwired/turbo-rails';
|
3
|
-
|
4
|
-
class TurboCollectionController extends Controller {
|
5
|
-
static values = {
|
6
|
-
query: String,
|
7
|
-
sort: String,
|
8
|
-
};
|
9
|
-
|
10
|
-
queryValueChanged(query) {
|
11
|
-
Turbo.navigator.history.replace(this.#url(query));
|
12
|
-
}
|
13
|
-
|
14
|
-
sortValueChanged(sort) {
|
15
|
-
document.querySelectorAll(this.#sortSelector).forEach((input) => {
|
16
|
-
if (input) input.value = sort;
|
17
|
-
});
|
18
|
-
}
|
19
|
-
|
20
|
-
get #sortSelector() {
|
21
|
-
return "input[name='sort']";
|
22
|
-
}
|
23
|
-
|
24
|
-
#url(query) {
|
25
|
-
const frame = this.element.closest("turbo-frame");
|
26
|
-
let url;
|
27
|
-
|
28
|
-
if (frame) {
|
29
|
-
url = new URL(frame.baseURI);
|
30
|
-
} else {
|
31
|
-
url = new URL(window.location.href);
|
32
|
-
}
|
33
|
-
|
34
|
-
url.search = query;
|
35
|
-
|
36
|
-
return url;
|
37
|
-
}
|
38
|
-
}
|
39
2
|
|
40
3
|
class OrderableRowController extends Controller {
|
41
4
|
static values = {
|
@@ -85,6 +48,15 @@ class OrderableRowController extends Controller {
|
|
85
48
|
this.index = index;
|
86
49
|
}
|
87
50
|
|
51
|
+
/** Retrieve params for use in the form */
|
52
|
+
params(scope) {
|
53
|
+
const { id_name, id_value, index_name } = this.paramsValue;
|
54
|
+
return [
|
55
|
+
{ name: `${scope}[${id_value}][${id_name}]`, value: this.id },
|
56
|
+
{ name: `${scope}[${id_value}][${index_name}]`, value: this.index },
|
57
|
+
];
|
58
|
+
}
|
59
|
+
|
88
60
|
/**
|
89
61
|
* Restore any visual changes made during drag and remove the drag state.
|
90
62
|
*/
|
@@ -450,13 +422,15 @@ class DragState {
|
|
450
422
|
}
|
451
423
|
|
452
424
|
class OrderableFormController extends Controller {
|
425
|
+
static values = { scope: String };
|
426
|
+
|
453
427
|
add(item) {
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
);
|
428
|
+
item.params(this.scopeValue).forEach(({ name, value }) => {
|
429
|
+
this.element.insertAdjacentHTML(
|
430
|
+
"beforeend",
|
431
|
+
`<input type="hidden" name="${name}" value="${value}" data-generated>`,
|
432
|
+
);
|
433
|
+
});
|
460
434
|
}
|
461
435
|
|
462
436
|
submit() {
|
@@ -560,10 +534,6 @@ class SelectionItemController extends Controller {
|
|
560
534
|
}
|
561
535
|
|
562
536
|
const Definitions = [
|
563
|
-
{
|
564
|
-
identifier: "tables--turbo--collection",
|
565
|
-
controllerConstructor: TurboCollectionController,
|
566
|
-
},
|
567
537
|
{
|
568
538
|
identifier: "tables--orderable--item",
|
569
539
|
controllerConstructor: OrderableRowController,
|
@@ -1,41 +1,4 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
2
|
-
import { Turbo } from '@hotwired/turbo-rails';
|
3
|
-
|
4
|
-
class TurboCollectionController extends Controller {
|
5
|
-
static values = {
|
6
|
-
query: String,
|
7
|
-
sort: String,
|
8
|
-
};
|
9
|
-
|
10
|
-
queryValueChanged(query) {
|
11
|
-
Turbo.navigator.history.replace(this.#url(query));
|
12
|
-
}
|
13
|
-
|
14
|
-
sortValueChanged(sort) {
|
15
|
-
document.querySelectorAll(this.#sortSelector).forEach((input) => {
|
16
|
-
if (input) input.value = sort;
|
17
|
-
});
|
18
|
-
}
|
19
|
-
|
20
|
-
get #sortSelector() {
|
21
|
-
return "input[name='sort']";
|
22
|
-
}
|
23
|
-
|
24
|
-
#url(query) {
|
25
|
-
const frame = this.element.closest("turbo-frame");
|
26
|
-
let url;
|
27
|
-
|
28
|
-
if (frame) {
|
29
|
-
url = new URL(frame.baseURI);
|
30
|
-
} else {
|
31
|
-
url = new URL(window.location.href);
|
32
|
-
}
|
33
|
-
|
34
|
-
url.search = query;
|
35
|
-
|
36
|
-
return url;
|
37
|
-
}
|
38
|
-
}
|
39
2
|
|
40
3
|
class OrderableRowController extends Controller {
|
41
4
|
static values = {
|
@@ -85,6 +48,15 @@ class OrderableRowController extends Controller {
|
|
85
48
|
this.index = index;
|
86
49
|
}
|
87
50
|
|
51
|
+
/** Retrieve params for use in the form */
|
52
|
+
params(scope) {
|
53
|
+
const { id_name, id_value, index_name } = this.paramsValue;
|
54
|
+
return [
|
55
|
+
{ name: `${scope}[${id_value}][${id_name}]`, value: this.id },
|
56
|
+
{ name: `${scope}[${id_value}][${index_name}]`, value: this.index },
|
57
|
+
];
|
58
|
+
}
|
59
|
+
|
88
60
|
/**
|
89
61
|
* Restore any visual changes made during drag and remove the drag state.
|
90
62
|
*/
|
@@ -450,13 +422,15 @@ class DragState {
|
|
450
422
|
}
|
451
423
|
|
452
424
|
class OrderableFormController extends Controller {
|
425
|
+
static values = { scope: String };
|
426
|
+
|
453
427
|
add(item) {
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
);
|
428
|
+
item.params(this.scopeValue).forEach(({ name, value }) => {
|
429
|
+
this.element.insertAdjacentHTML(
|
430
|
+
"beforeend",
|
431
|
+
`<input type="hidden" name="${name}" value="${value}" data-generated>`,
|
432
|
+
);
|
433
|
+
});
|
460
434
|
}
|
461
435
|
|
462
436
|
submit() {
|
@@ -560,10 +534,6 @@ class SelectionItemController extends Controller {
|
|
560
534
|
}
|
561
535
|
|
562
536
|
const Definitions = [
|
563
|
-
{
|
564
|
-
identifier: "tables--turbo--collection",
|
565
|
-
controllerConstructor: TurboCollectionController,
|
566
|
-
},
|
567
537
|
{
|
568
538
|
identifier: "tables--orderable--item",
|
569
539
|
controllerConstructor: OrderableRowController,
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{Controller as t}from"@hotwired/stimulus";
|
1
|
+
import{Controller as t}from"@hotwired/stimulus";class e{constructor(t,e,s){this.cursorOffset=e.offsetY,this.initialPosition=e.target.offsetTop-t.offsetTop,this.targetId=s}updateCursor(t,e,s,i){this.listOffset=t.getBoundingClientRect().top;let r=s.clientY-this.listOffset-this.cursorOffset;this.#t(t,e,r,i)}updateScroll(t,e,s){const i=this.listOffset;this.listOffset=t.getBoundingClientRect().top;const r=i-this.listOffset,a=this.position+r;this.#t(t,e,a,s)}#t(t,e,s,i){s=Math.max(s,0),s=Math.min(s,t.offsetHeight-e.offsetHeight),this.position=s;i(s-this.initialPosition)}}class s extends t{static outlets=["tables--selection--form"];static values={params:Object,checked:Boolean};tablesSelectionFormOutletConnected(t){this.checkedValue=t.isSelected(this.id)}change(t){t.preventDefault(),this.checkedValue=this.tablesSelectionFormOutlet.toggle(this.id)}get id(){return this.paramsValue.id}checkedValueChanged(t){this.element.querySelector("input").checked=t}}const i=[{identifier:"tables--orderable--item",controllerConstructor:class extends t{static values={params:Object};connect(){var t;this.index=(t=this.row,Array.from(t.parentElement.children).indexOf(t))}paramsValueChanged(t){this.id=t.id_value}dragUpdate(t){this.dragOffset=t,this.row.style.position="relative",this.row.style.top=t+"px",this.row.style.zIndex="1",this.row.toggleAttribute("dragging",!0)}updateVisually(t){this.row.style.position="relative",this.row.style.top=this.row.offsetHeight*(t-this.dragIndex)+"px"}updateIndex(t){this.index=t}params(t){const{id_name:e,id_value:s,index_name:i}=this.paramsValue;return[{name:`${t}[${s}][${e}]`,value:this.id},{name:`${t}[${s}][${i}]`,value:this.index}]}reset(){delete this.dragOffset,this.row.removeAttribute("style"),this.row.removeAttribute("dragging")}get hasChanges(){return this.paramsValue.index_value!==this.index}get dragIndex(){return this.dragOffset&&0!==this.dragOffset?this.index+Math.round(this.dragOffset/this.row.offsetHeight):this.index}get comparisonIndex(){return this.dragOffset?this.dragIndex+(this.dragOffset>0?.5:-.5):this.index}get row(){return this.element.parentElement}}},{identifier:"tables--orderable--list",controllerConstructor:class extends t{static outlets=["tables--orderable--item","tables--orderable--form"];startDragging(t){this.dragState=t,document.addEventListener("mousemove",this.mousemove),document.addEventListener("mouseup",this.mouseup),window.addEventListener("scroll",this.scroll,!0),this.element.style.position="relative"}stopDragging(){const t=this.dragState;return delete this.dragState,document.removeEventListener("mousemove",this.mousemove),document.removeEventListener("mouseup",this.mouseup),window.removeEventListener("scroll",this.scroll,!0),this.element.removeAttribute("style"),this.tablesOrderableItemOutlets.forEach((t=>t.reset())),t}drop(){const t=this.dragItem;if(!t)return;const e=t.dragIndex,s=this.tablesOrderableItemOutlets[e];s&&(e<t.index?s.row.insertAdjacentElement("beforebegin",t.row):e>t.index&&s.row.insertAdjacentElement("afterend",t.row),this.tablesOrderableItemOutlets.forEach(((t,e)=>t.updateIndex(e))),this.commitChanges())}commitChanges(){this.tablesOrderableFormOutlet.clear(),this.tablesOrderableItemOutlets.forEach((t=>{t.hasChanges&&this.tablesOrderableFormOutlet.add(t)})),this.tablesOrderableFormOutlet.submit()}mousedown(t){if(this.isDragging)return;const s=this.#e(t.target);s&&(t.preventDefault(),this.startDragging(new e(this.element,t,s.id)),this.dragState.updateCursor(this.element,s.row,t,this.animate))}mousemove=t=>{this.isDragging&&(t.preventDefault(),this.ticking||(this.ticking=!0,window.requestAnimationFrame((()=>{this.ticking=!1,this.dragState.updateCursor(this.element,this.dragItem.row,t,this.animate)}))))};scroll=t=>{this.isDragging&&!this.ticking&&(this.ticking=!0,window.requestAnimationFrame((()=>{this.ticking=!1,this.dragState.updateScroll(this.element,this.dragItem.row,this.animate)})))};mouseup=t=>{this.isDragging&&(this.drop(),this.stopDragging(),this.tablesOrderableFormOutlets.forEach((t=>delete t.dragState)))};tablesOrderableFormOutletConnected(t,e){t.dragState&&this.startDragging(t.dragState)}tablesOrderableFormOutletDisconnected(t,e){this.isDragging&&(t.dragState=this.stopDragging())}animate=t=>{const e=this.dragItem;e.dragUpdate(t),this.#s.forEach(((t,s)=>{t!==e&&t.updateVisually(s)}))};get isDragging(){return!!this.dragState}get dragItem(){return this.isDragging?this.tablesOrderableItemOutlets.find((t=>t.id===this.dragState.targetId)):null}get#s(){return this.tablesOrderableItemOutlets.toSorted(((t,e)=>t.comparisonIndex-e.comparisonIndex))}#e(t){return this.tablesOrderableItemOutlets.find((e=>e.element===t))}}},{identifier:"tables--orderable--form",controllerConstructor:class extends t{static values={scope:String};add(t){t.params(this.scopeValue).forEach((({name:t,value:e})=>{this.element.insertAdjacentHTML("beforeend",`<input type="hidden" name="${t}" value="${e}" data-generated>`)}))}submit(){0!==this.inputs.length&&this.element.requestSubmit()}clear(){this.inputs.forEach((t=>t.remove()))}get inputs(){return this.element.querySelectorAll("input[data-generated]")}}},{identifier:"tables--selection--form",controllerConstructor:class extends t{static values={count:Number,primaryKey:{type:String,default:"id"}};static targets=["count","singular","plural"];connect(){this.countValue=this.inputs.length}toggle(t){const e=this.input(t);return e?e.remove():this.element.insertAdjacentHTML("beforeend",`<input type="hidden" name="${this.primaryKeyValue}[]" value="${t}">`),this.countValue=this.inputs.length,!e}isSelected(t){return!!this.input(t)}get inputs(){return this.element.querySelectorAll(`input[name="${this.primaryKeyValue}[]"]`)}input(t){return this.element.querySelector(`input[name="${this.primaryKeyValue}[]"][value="${t}"]`)}countValueChanged(t){this.element.toggleAttribute("hidden",0===t),this.countTarget.textContent=t,this.singularTarget.toggleAttribute("hidden",1!==t),this.pluralTarget.toggleAttribute("hidden",1===t)}}},{identifier:"tables--selection--item",controllerConstructor:s}];export{i as default};
|
2
2
|
//# sourceMappingURL=tables.min.js.map
|