b4um_generators 0.2.16 → 0.3.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.
@@ -0,0 +1,166 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ static values = {
5
+ updateUrl: String
6
+ }
7
+
8
+ connect() {
9
+ this.draggedItem = null
10
+ this.draggedFromPosition = null
11
+ }
12
+
13
+ dragStart(event) {
14
+ const item = event.currentTarget.closest('[data-sortable-id]')
15
+
16
+ if (!item) return
17
+
18
+ this.draggedItem = item
19
+ this.draggedFromPosition = this.positionFor(item)
20
+
21
+ event.dataTransfer.effectAllowed = 'move'
22
+ event.dataTransfer.setData('text/plain', item.dataset.sortableId)
23
+
24
+ item.classList.add('b4um-sortable__item--dragging')
25
+ }
26
+
27
+ dragEnd() {
28
+ if (this.draggedItem) {
29
+ this.draggedItem.classList.remove('b4um-sortable__item--dragging')
30
+ }
31
+
32
+ this.draggedItem = null
33
+ this.draggedFromPosition = null
34
+ }
35
+
36
+ dragOver(event) {
37
+ event.preventDefault()
38
+
39
+ if (!this.draggedItem) return
40
+
41
+ const target = event.currentTarget
42
+
43
+ if (target === this.draggedItem) return
44
+
45
+ const bounds = target.getBoundingClientRect()
46
+ const insertAfter = event.clientY > bounds.top + bounds.height / 2
47
+
48
+ if (insertAfter) {
49
+ target.after(this.draggedItem)
50
+ } else {
51
+ target.before(this.draggedItem)
52
+ }
53
+ }
54
+
55
+ drop(event) {
56
+ event.preventDefault()
57
+
58
+ if (!this.draggedItem) return
59
+
60
+ const item = this.draggedItem
61
+ const position = this.positionAfterDrop(item)
62
+
63
+ if (!position) {
64
+ window.location.reload()
65
+ return
66
+ }
67
+
68
+ this.persist(item.dataset.sortableId, position)
69
+ }
70
+
71
+ positionKeydown(event) {
72
+ if (event.key !== 'Enter') return
73
+
74
+ event.preventDefault()
75
+ event.currentTarget.blur()
76
+ }
77
+
78
+ positionChanged(event) {
79
+ const input = event.currentTarget
80
+ const item = input.closest('[data-sortable-id]')
81
+
82
+ if (!item) return
83
+
84
+ const position = Number.parseInt(input.value, 10)
85
+
86
+ if (Number.isNaN(position) || position < 1) {
87
+ window.location.reload()
88
+ return
89
+ }
90
+
91
+ this.persist(item.dataset.sortableId, position)
92
+ }
93
+
94
+ positionFor(item) {
95
+ const input = item.querySelector('.b4um-sortable__position')
96
+
97
+ if (!input) return null
98
+
99
+ const position = Number.parseInt(input.value, 10)
100
+
101
+ return Number.isNaN(position) ? null : position
102
+ }
103
+
104
+ positionAfterDrop(item) {
105
+ const previousItem = item.previousElementSibling
106
+ const nextItem = item.nextElementSibling
107
+
108
+ if (previousItem?.matches('[data-sortable-id]')) {
109
+ const previousPosition = this.positionFor(previousItem)
110
+
111
+ if (previousPosition) {
112
+ if (this.draggedFromPosition && this.draggedFromPosition < previousPosition) {
113
+ return previousPosition
114
+ }
115
+
116
+ return previousPosition + 1
117
+ }
118
+ }
119
+
120
+ if (nextItem?.matches('[data-sortable-id]')) {
121
+ const nextPosition = this.positionFor(nextItem)
122
+
123
+ if (nextPosition) {
124
+ if (this.draggedFromPosition && this.draggedFromPosition > nextPosition) {
125
+ return nextPosition
126
+ }
127
+
128
+ return Math.max(1, nextPosition - 1)
129
+ }
130
+ }
131
+
132
+ return this.draggedFromPosition
133
+ }
134
+
135
+ async persist(id, position) {
136
+ if (!this.hasUpdateUrlValue || !this.updateUrlValue) return
137
+
138
+ try {
139
+ const response = await fetch(this.updateUrlValue, {
140
+ method: 'PATCH',
141
+ headers: {
142
+ 'Content-Type': 'application/json',
143
+ Accept: 'application/json',
144
+ 'X-CSRF-Token': this.csrfToken()
145
+ },
146
+ body: JSON.stringify({
147
+ id,
148
+ position
149
+ })
150
+ })
151
+
152
+ if (!response.ok) {
153
+ throw new Error(`Sortable update failed: ${response.status}`)
154
+ }
155
+
156
+ window.location.reload()
157
+ } catch (error) {
158
+ console.error(error)
159
+ window.location.reload()
160
+ }
161
+ }
162
+
163
+ csrfToken() {
164
+ return document.querySelector('meta[name="csrf-token"]')?.content || ''
165
+ }
166
+ }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: b4um_generators
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.16
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Baum
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-10-09 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: railties
@@ -115,6 +115,7 @@ files:
115
115
  - lib/generators/b4um/install/templates/b4um/pagination.css
116
116
  - lib/generators/b4um/install/templates/b4um/resources.css
117
117
  - lib/generators/b4um/install/templates/b4um/search.css
118
+ - lib/generators/b4um/install/templates/b4um/sortable.css
118
119
  - lib/generators/b4um/install/templates/b4um/tables.css
119
120
  - lib/generators/b4um/install/templates/b4um/theme-switcher.css
120
121
  - lib/generators/b4um/install/templates/b4um/theme.css
@@ -145,6 +146,11 @@ files:
145
146
  - lib/generators/b4um/search/search_generator.rb
146
147
  - lib/generators/b4um/search/templates/search.rb
147
148
  - lib/generators/b4um/search/templates/search_form.html.erb.tt
149
+ - lib/generators/b4um/sortable/sortable_generator.rb
150
+ - lib/generators/b4um/sortable/templates/_sortable.html.erb.tt
151
+ - lib/generators/b4um/sortable/templates/add_position_migration.rb.tt
152
+ - lib/generators/b4um/sortable/templates/sort.html.erb.tt
153
+ - lib/generators/b4um/sortable/templates/sortable_controller.js
148
154
  - lib/generators/b4um/table/table_generator.rb
149
155
  - lib/generators/b4um/table/templates/_table.html.erb.tt
150
156
  - lib/generators/b4um/trix/templates/b4um_rich_text_helper.rb
@@ -171,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
177
  - !ruby/object:Gem::Version
172
178
  version: '0'
173
179
  requirements: []
174
- rubygems_version: 3.6.2
180
+ rubygems_version: 3.6.9
175
181
  specification_version: 4
176
182
  summary: Rails generators for b4um applications
177
183
  test_files: []