formstrap 0.4.0 → 0.4.2
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/formstrap/controllers/media_controller.js +40 -20
- data/app/assets/javascripts/formstrap/controllers/nested_preview_controller.js +2 -1
- data/app/assets/javascripts/formstrap/controllers/repeater_controller.js +18 -39
- data/app/assets/javascripts/formstrap/controllers/select_controller.js +1 -1
- data/app/assets/javascripts/formstrap.js +50 -46
- data/app/assets/stylesheets/formstrap/vendor/overrides/redactor.scss +0 -1
- data/app/assets/stylesheets/formstrap.css +0 -1
- data/app/models/formstrap/media_view.rb +1 -2
- data/app/models/formstrap/redactor_view.rb +0 -2
- data/app/models/formstrap/wysiwyg_view.rb +5 -2
- data/app/views/formstrap/_repeater.html.erb +4 -3
- data/app/views/formstrap/repeater/_row.html.erb +1 -1
- data/lib/formstrap/version.rb +1 -1
- data/package.json +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee49a6e7a9f068d3403b4ebfd46c19cf07b6c293e8893f1e561e8ae20ed0af77
|
4
|
+
data.tar.gz: f85517d919e6c9360ac31c7f1aa7b8f2ff3705ea31a2a6a76f0b72ae82f58c30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab80f8fd25603f0c9ce6f5ea6c92dc025b62f7b932f0b0e7bd7867bd4432845f902a6f5f7ba6492a6455ae9f3eb93fe411497a9dc2cf346538e3a610a05fd253
|
7
|
+
data.tar.gz: a5db302d1730c5f0cb801ddf248d24a0c5111ec0f8ae6d7aaa24d5a36c0e50913f1939a71df275c47429016162b59e47024a4be0e186e23b661c3393321cb9e4
|
@@ -1,23 +1,22 @@
|
|
1
|
+
/* global crypto */
|
1
2
|
import { Controller } from '@hotwired/stimulus'
|
2
3
|
import Sortable from 'sortablejs'
|
3
4
|
|
4
5
|
export default class extends Controller {
|
6
|
+
static get values () {
|
7
|
+
return {
|
8
|
+
name: String
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
5
12
|
static get targets () {
|
6
13
|
return ['item', 'template', 'thumbnails', 'modalButton', 'placeholder', 'count', 'editButton', 'validationInput']
|
7
14
|
}
|
8
15
|
|
9
16
|
connect () {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
}
|
14
|
-
})
|
15
|
-
|
16
|
-
// Init sorting
|
17
|
-
if (this.hasSorting()) {
|
18
|
-
this.initSortable()
|
19
|
-
}
|
20
|
-
|
17
|
+
this.randomizeName()
|
18
|
+
this.listenForMediaSelection()
|
19
|
+
this.initializeSorting()
|
21
20
|
this.validate()
|
22
21
|
}
|
23
22
|
|
@@ -47,6 +46,34 @@ export default class extends Controller {
|
|
47
46
|
}
|
48
47
|
|
49
48
|
// Methods
|
49
|
+
randomizeName () {
|
50
|
+
this.nameValue = crypto.randomUUID().substring(0, 8)
|
51
|
+
this.updateModalButtonUrls()
|
52
|
+
}
|
53
|
+
|
54
|
+
updateModalButtonUrls () {
|
55
|
+
this.modalButtonTargets.forEach((button) => {
|
56
|
+
const url = new URL(button.getAttribute('href'))
|
57
|
+
url.searchParams.set('name', this.nameValue)
|
58
|
+
button.setAttribute('href', url.toString())
|
59
|
+
})
|
60
|
+
}
|
61
|
+
|
62
|
+
listenForMediaSelection () {
|
63
|
+
document.addEventListener('mediaSelectionSubmitted', (event) => {
|
64
|
+
if (event.detail.name === this.nameValue) {
|
65
|
+
this.selectItems(event.detail.items)
|
66
|
+
this.updateModalButtonUrls()
|
67
|
+
}
|
68
|
+
})
|
69
|
+
}
|
70
|
+
|
71
|
+
initializeSorting () {
|
72
|
+
if (this.hasSorting()) {
|
73
|
+
this.initSortable()
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
50
77
|
initSortable () {
|
51
78
|
Sortable.create(this.thumbnailsTarget, {
|
52
79
|
handle: '.media-drag-sort-handle',
|
@@ -170,9 +197,8 @@ export default class extends Controller {
|
|
170
197
|
|
171
198
|
createItem (item) {
|
172
199
|
// Copy template
|
173
|
-
const
|
174
|
-
|
175
|
-
this.thumbnailsTarget.insertAdjacentHTML('beforeend', html)
|
200
|
+
const templateHtml = this.templateTarget.innerHTML
|
201
|
+
this.thumbnailsTarget.insertAdjacentHTML('beforeend', templateHtml)
|
176
202
|
|
177
203
|
// Set new values
|
178
204
|
const newItem = this.itemTargets.pop()
|
@@ -191,12 +217,6 @@ export default class extends Controller {
|
|
191
217
|
oldThumbnail.parentNode.replaceChild(newThumbnail, oldThumbnail)
|
192
218
|
}
|
193
219
|
|
194
|
-
randomizeIds (template) {
|
195
|
-
const regex = new RegExp(template.dataset.templateIdRegex, 'g')
|
196
|
-
const randomNumber = Math.floor(100000000 + Math.random() * 900000000)
|
197
|
-
return template.innerHTML.replace(regex, randomNumber)
|
198
|
-
}
|
199
|
-
|
200
220
|
removeAllDeselectedItems (items) {
|
201
221
|
this.removeDeselectedItems(items, this.itemTargets)
|
202
222
|
}
|
@@ -126,7 +126,8 @@ export default class extends Controller {
|
|
126
126
|
const formData = new FormData()
|
127
127
|
|
128
128
|
// Replace all occurrences of "page[blocks_attributes][0]" with "block"
|
129
|
-
|
129
|
+
// Replace all occurrences of "form[fields_attributes][random]" with "field"
|
130
|
+
const regex = /\w+\[([^\]]+)s_attributes]\[[^\]]+]/g
|
130
131
|
const formElements = fields.querySelectorAll('input[name]:not([name$="[id]"]), select[name]:not([name$="[id]"]), textarea[name]:not([name$="[id]"]), button[name]:not([name$="[id]"])')
|
131
132
|
formElements.forEach((element) => {
|
132
133
|
const currentName = element.getAttribute('name')
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/* global crypto */
|
1
2
|
import { Controller } from '@hotwired/stimulus'
|
2
3
|
import Sortable from 'sortablejs'
|
3
4
|
|
@@ -23,7 +24,6 @@ export default class extends Controller {
|
|
23
24
|
this.resetPositions()
|
24
25
|
}
|
25
26
|
})
|
26
|
-
|
27
27
|
this.toggleEmpty()
|
28
28
|
}
|
29
29
|
|
@@ -38,8 +38,7 @@ export default class extends Controller {
|
|
38
38
|
}
|
39
39
|
|
40
40
|
updatePopupButtonIndices (index) {
|
41
|
-
const
|
42
|
-
const buttons = popup.querySelectorAll('[data-popup-target="button"]')
|
41
|
+
const buttons = document.querySelectorAll(`[data-popup-target="button"][data-popup-id="repeater-buttons-${this.idValue}"]`)
|
43
42
|
buttons.forEach((button) => {
|
44
43
|
button.dataset.rowIndex = index
|
45
44
|
})
|
@@ -53,7 +52,7 @@ export default class extends Controller {
|
|
53
52
|
|
54
53
|
// Prepare html from template
|
55
54
|
let template = this.getTemplate(templateName).content.cloneNode(true)
|
56
|
-
template = this.
|
55
|
+
template = this.randomizeIds(template)
|
57
56
|
|
58
57
|
// Fallback to last row if no index is set
|
59
58
|
if (rowIndex) {
|
@@ -107,44 +106,24 @@ export default class extends Controller {
|
|
107
106
|
})[0]
|
108
107
|
}
|
109
108
|
|
110
|
-
|
111
|
-
const
|
112
|
-
const
|
109
|
+
randomizeIds (template) {
|
110
|
+
const randomNumber = crypto.randomUUID().substring(0, 8)
|
111
|
+
const pattern = `_${this.idValue}_`
|
113
112
|
const regex = new RegExp(pattern, 'g')
|
114
113
|
|
115
|
-
//
|
116
|
-
template.querySelectorAll(
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
node.innerHTML = node.innerHTML.replace(regex, replacement)
|
124
|
-
})
|
125
|
-
|
126
|
-
// Replace labels
|
127
|
-
template.querySelectorAll(`label[for*="${pattern}"]`).forEach((node) => {
|
128
|
-
const forValue = node.getAttribute('for')
|
129
|
-
node.setAttribute('for', forValue.replace(pattern, replacement))
|
130
|
-
})
|
131
|
-
|
132
|
-
// Replace names
|
133
|
-
template.querySelectorAll(`input[name*="${pattern}"], select[name*="${pattern}"], textarea[name*="${pattern}"], button[name*="${pattern}"]`).forEach((node) => {
|
134
|
-
const nameValue = node.getAttribute('name')
|
135
|
-
node.setAttribute('name', nameValue.replace(pattern, replacement))
|
136
|
-
})
|
137
|
-
|
138
|
-
// Replace offcanvas targets
|
139
|
-
template.querySelectorAll(`div[data-bs-target="#offcanvas-${pattern}"]`).forEach((node) => {
|
140
|
-
const targetValue = node.getAttribute('data-bs-target')
|
141
|
-
node.setAttribute('data-bs-target', targetValue.replace(pattern, replacement))
|
142
|
-
})
|
114
|
+
// Loop through each node in the template
|
115
|
+
template.querySelectorAll('*').forEach(node => {
|
116
|
+
// Replace attribute values
|
117
|
+
for (const attribute of node.attributes) {
|
118
|
+
if (attribute.value.includes(pattern)) {
|
119
|
+
attribute.value = attribute.value.replace(pattern, randomNumber)
|
120
|
+
}
|
121
|
+
}
|
143
122
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
123
|
+
// Replace template content
|
124
|
+
if (node.nodeName === 'TEMPLATE' && node.innerHTML.includes(pattern)) {
|
125
|
+
node.innerHTML = node.innerHTML.replace(regex, randomNumber)
|
126
|
+
}
|
148
127
|
})
|
149
128
|
|
150
129
|
return template
|
@@ -11076,18 +11076,18 @@ var sortable_esm_default = Sortable;
|
|
11076
11076
|
|
11077
11077
|
// app/assets/javascripts/formstrap/controllers/media_controller.js
|
11078
11078
|
var media_controller_default = class extends Controller {
|
11079
|
+
static get values() {
|
11080
|
+
return {
|
11081
|
+
name: String
|
11082
|
+
};
|
11083
|
+
}
|
11079
11084
|
static get targets() {
|
11080
11085
|
return ["item", "template", "thumbnails", "modalButton", "placeholder", "count", "editButton", "validationInput"];
|
11081
11086
|
}
|
11082
11087
|
connect() {
|
11083
|
-
|
11084
|
-
|
11085
|
-
|
11086
|
-
}
|
11087
|
-
});
|
11088
|
-
if (this.hasSorting()) {
|
11089
|
-
this.initSortable();
|
11090
|
-
}
|
11088
|
+
this.randomizeName();
|
11089
|
+
this.listenForMediaSelection();
|
11090
|
+
this.initializeSorting();
|
11091
11091
|
this.validate();
|
11092
11092
|
}
|
11093
11093
|
destroy(event) {
|
@@ -11106,6 +11106,30 @@ var media_controller_default = class extends Controller {
|
|
11106
11106
|
button.setAttribute("href", url.toString());
|
11107
11107
|
});
|
11108
11108
|
}
|
11109
|
+
randomizeName() {
|
11110
|
+
this.nameValue = crypto.randomUUID().substring(0, 8);
|
11111
|
+
this.updateModalButtonUrls();
|
11112
|
+
}
|
11113
|
+
updateModalButtonUrls() {
|
11114
|
+
this.modalButtonTargets.forEach((button) => {
|
11115
|
+
const url = new URL(button.getAttribute("href"));
|
11116
|
+
url.searchParams.set("name", this.nameValue);
|
11117
|
+
button.setAttribute("href", url.toString());
|
11118
|
+
});
|
11119
|
+
}
|
11120
|
+
listenForMediaSelection() {
|
11121
|
+
document.addEventListener("mediaSelectionSubmitted", (event) => {
|
11122
|
+
if (event.detail.name === this.nameValue) {
|
11123
|
+
this.selectItems(event.detail.items);
|
11124
|
+
this.updateModalButtonUrls();
|
11125
|
+
}
|
11126
|
+
});
|
11127
|
+
}
|
11128
|
+
initializeSorting() {
|
11129
|
+
if (this.hasSorting()) {
|
11130
|
+
this.initSortable();
|
11131
|
+
}
|
11132
|
+
}
|
11109
11133
|
initSortable() {
|
11110
11134
|
sortable_esm_default.create(this.thumbnailsTarget, {
|
11111
11135
|
handle: ".media-drag-sort-handle",
|
@@ -11197,9 +11221,8 @@ var media_controller_default = class extends Controller {
|
|
11197
11221
|
item.classList.remove("d-none");
|
11198
11222
|
}
|
11199
11223
|
createItem(item) {
|
11200
|
-
const
|
11201
|
-
|
11202
|
-
this.thumbnailsTarget.insertAdjacentHTML("beforeend", html);
|
11224
|
+
const templateHtml = this.templateTarget.innerHTML;
|
11225
|
+
this.thumbnailsTarget.insertAdjacentHTML("beforeend", templateHtml);
|
11203
11226
|
const newItem = this.itemTargets.pop();
|
11204
11227
|
newItem.querySelector('input[name*="[blob_id]"]').value = item.blobId;
|
11205
11228
|
newItem.querySelector('input[name*="[_destroy]"]').value = false;
|
@@ -11211,11 +11234,6 @@ var media_controller_default = class extends Controller {
|
|
11211
11234
|
const newThumbnail = item.thumbnail.cloneNode(true);
|
11212
11235
|
oldThumbnail.parentNode.replaceChild(newThumbnail, oldThumbnail);
|
11213
11236
|
}
|
11214
|
-
randomizeIds(template) {
|
11215
|
-
const regex = new RegExp(template.dataset.templateIdRegex, "g");
|
11216
|
-
const randomNumber = Math.floor(1e8 + Math.random() * 9e8);
|
11217
|
-
return template.innerHTML.replace(regex, randomNumber);
|
11218
|
-
}
|
11219
11237
|
removeAllDeselectedItems(items) {
|
11220
11238
|
this.removeDeselectedItems(items, this.itemTargets);
|
11221
11239
|
}
|
@@ -11498,7 +11516,7 @@ var nested_preview_controller_default = class extends Controller {
|
|
11498
11516
|
buildFormData() {
|
11499
11517
|
const fields = this.fieldsTarget;
|
11500
11518
|
const formData = new FormData();
|
11501
|
-
const regex = /\w+\[([^\]]+)s_attributes]\[
|
11519
|
+
const regex = /\w+\[([^\]]+)s_attributes]\[[^\]]+]/g;
|
11502
11520
|
const formElements = fields.querySelectorAll('input[name]:not([name$="[id]"]), select[name]:not([name$="[id]"]), textarea[name]:not([name$="[id]"]), button[name]:not([name$="[id]"])');
|
11503
11521
|
formElements.forEach((element) => {
|
11504
11522
|
const currentName = element.getAttribute("name");
|
@@ -13276,8 +13294,7 @@ var repeater_controller_default = class extends Controller {
|
|
13276
13294
|
return this.rowTargets.includes(row);
|
13277
13295
|
}
|
13278
13296
|
updatePopupButtonIndices(index2) {
|
13279
|
-
const
|
13280
|
-
const buttons = popup.querySelectorAll('[data-popup-target="button"]');
|
13297
|
+
const buttons = document.querySelectorAll(`[data-popup-target="button"][data-popup-id="repeater-buttons-${this.idValue}"]`);
|
13281
13298
|
buttons.forEach((button) => {
|
13282
13299
|
button.dataset.rowIndex = index2;
|
13283
13300
|
});
|
@@ -13288,7 +13305,7 @@ var repeater_controller_default = class extends Controller {
|
|
13288
13305
|
const templateName = button.dataset.templateName;
|
13289
13306
|
const rowIndex = button.dataset.rowIndex;
|
13290
13307
|
let template = this.getTemplate(templateName).content.cloneNode(true);
|
13291
|
-
template = this.
|
13308
|
+
template = this.randomizeIds(template);
|
13292
13309
|
if (rowIndex) {
|
13293
13310
|
const row = this.rowTargets[rowIndex];
|
13294
13311
|
this.listTarget.insertBefore(template, row.nextSibling);
|
@@ -13324,32 +13341,19 @@ var repeater_controller_default = class extends Controller {
|
|
13324
13341
|
return template.dataset.templateName === name;
|
13325
13342
|
})[0];
|
13326
13343
|
}
|
13327
|
-
|
13328
|
-
const
|
13329
|
-
const
|
13344
|
+
randomizeIds(template) {
|
13345
|
+
const randomNumber = crypto.randomUUID().substring(0, 8);
|
13346
|
+
const pattern = `_${this.idValue}_`;
|
13330
13347
|
const regex = new RegExp(pattern, "g");
|
13331
|
-
template.querySelectorAll(
|
13332
|
-
const
|
13333
|
-
|
13334
|
-
|
13335
|
-
|
13336
|
-
|
13337
|
-
|
13338
|
-
|
13339
|
-
|
13340
|
-
node.setAttribute("for", forValue.replace(pattern, replacement));
|
13341
|
-
});
|
13342
|
-
template.querySelectorAll(`input[name*="${pattern}"], select[name*="${pattern}"], textarea[name*="${pattern}"], button[name*="${pattern}"]`).forEach((node) => {
|
13343
|
-
const nameValue = node.getAttribute("name");
|
13344
|
-
node.setAttribute("name", nameValue.replace(pattern, replacement));
|
13345
|
-
});
|
13346
|
-
template.querySelectorAll(`div[data-bs-target="#offcanvas-${pattern}"]`).forEach((node) => {
|
13347
|
-
const targetValue = node.getAttribute("data-bs-target");
|
13348
|
-
node.setAttribute("data-bs-target", targetValue.replace(pattern, replacement));
|
13349
|
-
});
|
13350
|
-
template.querySelectorAll(`.offcanvas[id="offcanvas-${pattern}"]`).forEach((node) => {
|
13351
|
-
const idValue = node.getAttribute("id");
|
13352
|
-
node.setAttribute("id", idValue.replace(pattern, replacement));
|
13348
|
+
template.querySelectorAll("*").forEach((node) => {
|
13349
|
+
for (const attribute of node.attributes) {
|
13350
|
+
if (attribute.value.includes(pattern)) {
|
13351
|
+
attribute.value = attribute.value.replace(pattern, randomNumber);
|
13352
|
+
}
|
13353
|
+
}
|
13354
|
+
if (node.nodeName === "TEMPLATE" && node.innerHTML.includes(pattern)) {
|
13355
|
+
node.innerHTML = node.innerHTML.replace(regex, randomNumber);
|
13356
|
+
}
|
13353
13357
|
});
|
13354
13358
|
return template;
|
13355
13359
|
}
|
@@ -13388,7 +13392,7 @@ var repeater_controller_default = class extends Controller {
|
|
13388
13392
|
var import_tom_select = __toESM(require_tom_select_complete());
|
13389
13393
|
var select_controller_default = class extends Controller {
|
13390
13394
|
connect() {
|
13391
|
-
if (this.element.hasAttribute("multiple")) {
|
13395
|
+
if (this.element.hasAttribute("multiple") || this.element.dataset.tomSelect === "true") {
|
13392
13396
|
this.initTomSelect();
|
13393
13397
|
}
|
13394
13398
|
}
|
@@ -1299,7 +1299,6 @@ span.flatpickr-weekday {
|
|
1299
1299
|
--bs-input-focus-color: var(--bs-body-color);
|
1300
1300
|
}
|
1301
1301
|
.rx-container {
|
1302
|
-
overflow: hidden;
|
1303
1302
|
padding: 0 !important;
|
1304
1303
|
border: var(--bs-border-width) solid var(--bs-border-color);
|
1305
1304
|
border-radius: var(--bs-border-radius);
|
@@ -18,7 +18,6 @@ module Formstrap
|
|
18
18
|
class: ["mb-3", ("form-floating" if float)],
|
19
19
|
data: {
|
20
20
|
controller: "media",
|
21
|
-
name: name,
|
22
21
|
sort: sort,
|
23
22
|
accept: accept,
|
24
23
|
required: required.nil? ? 0 : required
|
@@ -122,7 +121,7 @@ module Formstrap
|
|
122
121
|
end
|
123
122
|
|
124
123
|
def modal_url
|
125
|
-
|
124
|
+
formstrap_media_url(
|
126
125
|
name: name,
|
127
126
|
ids: blob_ids,
|
128
127
|
min: min,
|
@@ -11,13 +11,16 @@ module Formstrap
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def default_options
|
14
|
-
{
|
14
|
+
options = {
|
15
15
|
redactor: {
|
16
16
|
context: !toolbar,
|
17
17
|
extrabar: toolbar,
|
18
|
-
toolbar: toolbar
|
19
18
|
}
|
20
19
|
}
|
20
|
+
|
21
|
+
options[:redactor][:toolbar] = false if @toolbar == false
|
22
|
+
|
23
|
+
options
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
@@ -106,8 +106,9 @@
|
|
106
106
|
class="btn btn-sm btn-outline-secondary"
|
107
107
|
data-repeater-target="addButton"
|
108
108
|
data-popup-target="button"
|
109
|
-
data-popup-id="
|
109
|
+
data-popup-id="repeater-buttons-<%= repeater_id %>"
|
110
110
|
data-popup-pass-thru="<%= pass_thru %>"
|
111
|
+
data-row-index=""
|
111
112
|
data-action="click->repeater#resetButtonIndices click->popup#open"
|
112
113
|
>
|
113
114
|
<%= bootstrap_icon("plus") %>
|
@@ -121,7 +122,7 @@
|
|
121
122
|
<div
|
122
123
|
class="btn btn-sm btn-outline-secondary"
|
123
124
|
data-popup-target="button"
|
124
|
-
data-popup-id="
|
125
|
+
data-popup-id="repeater-buttons-<%= repeater_id %>"
|
125
126
|
data-action="click->repeater#addRow click->popup#close"
|
126
127
|
data-row-index=""
|
127
128
|
data-template-name="<%= name %>"
|
@@ -135,7 +136,7 @@
|
|
135
136
|
<!-- Templates -->
|
136
137
|
<% template_names.each do |template_name| %>
|
137
138
|
<template data-repeater-target="template" data-template-name="<%= template_name %>">
|
138
|
-
<%= form.fields_for attribute, association_object, child_index: "
|
139
|
+
<%= form.fields_for attribute, association_object, child_index: "_#{repeater_id}_" do |ff| %>
|
139
140
|
<%= render "formstrap/repeater/row", row_options.merge(form: ff, pass_thru: pass_thru, repeater_id: repeater_id, index: nil, template_name: template_name) do %>
|
140
141
|
<%= yield(ff, template_name) %>
|
141
142
|
<% end %>
|
@@ -41,7 +41,7 @@
|
|
41
41
|
title="<%= t(".add") %>"
|
42
42
|
data-repeater-target="addButton"
|
43
43
|
data-popup-target="button"
|
44
|
-
data-popup-id="
|
44
|
+
data-popup-id="repeater-buttons-<%= repeater_id %>"
|
45
45
|
data-popup-pass-thru="<%= pass_thru %>"
|
46
46
|
data-action="click->repeater#resetButtonIndices click->popup#open"
|
47
47
|
>
|
data/lib/formstrap/version.rb
CHANGED
data/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: formstrap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jef Vlamings
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: An extensive Bootstrap form library to power your Ruby On Rails application.
|
14
14
|
email:
|