formstrap 0.1.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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +33 -0
- data/CHANGELOG.md +1 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +28 -0
- data/LICENSE.txt +21 -0
- data/README.md +118 -0
- data/Rakefile +10 -0
- data/app/assets/config/headmin_manifest.js +2 -0
- data/app/assets/images/avatar.jpg +0 -0
- data/app/assets/images/document.docx +0 -0
- data/app/assets/images/document.pdf +0 -0
- data/app/assets/images/image.jpg +0 -0
- data/app/assets/images/spreadsheet.xls +0 -0
- data/app/assets/images/video.mp4 +0 -0
- data/app/assets/javascripts/formstrap/config/i18n.js +11 -0
- data/app/assets/javascripts/formstrap/controllers/autocomplete_controller.js +318 -0
- data/app/assets/javascripts/formstrap/controllers/date_range_controller.js +38 -0
- data/app/assets/javascripts/formstrap/controllers/dropzone_controller.js +31 -0
- data/app/assets/javascripts/formstrap/controllers/file_preview_controller.js +244 -0
- data/app/assets/javascripts/formstrap/controllers/flatpickr_controller.js +35 -0
- data/app/assets/javascripts/formstrap/controllers/infinite_scroller_controller.js +28 -0
- data/app/assets/javascripts/formstrap/controllers/media_controller.js +252 -0
- data/app/assets/javascripts/formstrap/controllers/media_modal_controller.js +147 -0
- data/app/assets/javascripts/formstrap/controllers/redactorx_controller.js +40 -0
- data/app/assets/javascripts/formstrap/controllers/repeater_controller.js +148 -0
- data/app/assets/javascripts/formstrap/controllers/select_controller.js +49 -0
- data/app/assets/javascripts/formstrap/controllers/textarea_controller.js +48 -0
- data/app/assets/javascripts/formstrap/index.js +32 -0
- data/app/assets/javascripts/formstrap.js +11515 -0
- data/app/assets/stylesheets/formstrap/forms/autocomplete.scss +27 -0
- data/app/assets/stylesheets/formstrap/forms/file.scss +83 -0
- data/app/assets/stylesheets/formstrap/forms/media.scss +10 -0
- data/app/assets/stylesheets/formstrap/forms/repeater.scss +62 -0
- data/app/assets/stylesheets/formstrap/forms/search.scss +12 -0
- data/app/assets/stylesheets/formstrap/forms.scss +12 -0
- data/app/assets/stylesheets/formstrap/general.scss +18 -0
- data/app/assets/stylesheets/formstrap/media/index.scss +9 -0
- data/app/assets/stylesheets/formstrap/media.scss +1 -0
- data/app/assets/stylesheets/formstrap/utilities/buttons.scss +27 -0
- data/app/assets/stylesheets/formstrap/utilities/dropzone.scss +72 -0
- data/app/assets/stylesheets/formstrap/utilities.scss +2 -0
- data/app/assets/stylesheets/formstrap/vendor/flatpickr.css +903 -0
- data/app/assets/stylesheets/formstrap/vendor/tom-select-bootstrap.scss +535 -0
- data/app/assets/stylesheets/formstrap.css +1559 -0
- data/app/assets/stylesheets/formstrap.scss +11 -0
- data/app/controllers/concerns/formstrap/pagination.rb +27 -0
- data/app/controllers/formstrap/media_controller.rb +68 -0
- data/app/controllers/formstrap_controller.rb +2 -0
- data/app/models/concerns/formstrap/autocompletable.rb +36 -0
- data/app/models/concerns/formstrap/hintable.rb +22 -0
- data/app/models/concerns/formstrap/input_groupable.rb +21 -0
- data/app/models/concerns/formstrap/labelable.rb +31 -0
- data/app/models/concerns/formstrap/listable.rb +26 -0
- data/app/models/concerns/formstrap/placeholderable.rb +11 -0
- data/app/models/concerns/formstrap/validatable.rb +38 -0
- data/app/models/concerns/formstrap/wrappable.rb +19 -0
- data/app/models/formstrap/.DS_Store +0 -0
- data/app/models/formstrap/association_view.rb +100 -0
- data/app/models/formstrap/blocks_view.rb +43 -0
- data/app/models/formstrap/checkbox_view.rb +50 -0
- data/app/models/formstrap/color_view.rb +45 -0
- data/app/models/formstrap/date_range_view.rb +23 -0
- data/app/models/formstrap/date_view.rb +43 -0
- data/app/models/formstrap/datetime_range_view.rb +23 -0
- data/app/models/formstrap/datetime_view.rb +43 -0
- data/app/models/formstrap/email_view.rb +46 -0
- data/app/models/formstrap/file_view.rb +106 -0
- data/app/models/formstrap/flatpickr_range_view.rb +89 -0
- data/app/models/formstrap/flatpickr_view.rb +27 -0
- data/app/models/formstrap/hidden_view.rb +8 -0
- data/app/models/formstrap/hint_view.rb +4 -0
- data/app/models/formstrap/input_group_view.rb +17 -0
- data/app/models/formstrap/label_view.rb +22 -0
- data/app/models/formstrap/media_item_view.rb +41 -0
- data/app/models/formstrap/media_view.rb +143 -0
- data/app/models/formstrap/number_view.rb +47 -0
- data/app/models/formstrap/password_view.rb +42 -0
- data/app/models/formstrap/redactorx_view.rb +57 -0
- data/app/models/formstrap/search_view.rb +46 -0
- data/app/models/formstrap/select_view.rb +61 -0
- data/app/models/formstrap/switch_view.rb +21 -0
- data/app/models/formstrap/text_view.rb +46 -0
- data/app/models/formstrap/textarea_view.rb +47 -0
- data/app/models/formstrap/url_view.rb +46 -0
- data/app/models/formstrap/wrapper_view.rb +17 -0
- data/app/models/formstrap/wysiwyg_view.rb +15 -0
- data/app/models/view_model.rb +62 -0
- data/app/views/formstrap/_association.html.erb +30 -0
- data/app/views/formstrap/_autocomplete.html.erb +11 -0
- data/app/views/formstrap/_blocks.html.erb +45 -0
- data/app/views/formstrap/_checkbox.html.erb +34 -0
- data/app/views/formstrap/_color.html.erb +32 -0
- data/app/views/formstrap/_datalist.html.erb +3 -0
- data/app/views/formstrap/_date.html.erb +41 -0
- data/app/views/formstrap/_date_range.html.erb +40 -0
- data/app/views/formstrap/_datetime.html.erb +41 -0
- data/app/views/formstrap/_datetime_range.html.erb +40 -0
- data/app/views/formstrap/_email.html.erb +43 -0
- data/app/views/formstrap/_errors.html.erb +19 -0
- data/app/views/formstrap/_file.html.erb +94 -0
- data/app/views/formstrap/_flatpickr.html.erb +33 -0
- data/app/views/formstrap/_flatpickr_range.html.erb +40 -0
- data/app/views/formstrap/_hidden.html.erb +23 -0
- data/app/views/formstrap/_hint.html.erb +21 -0
- data/app/views/formstrap/_input_group.html.erb +21 -0
- data/app/views/formstrap/_label.html.erb +22 -0
- data/app/views/formstrap/_media.html.erb +60 -0
- data/app/views/formstrap/_number.html.erb +41 -0
- data/app/views/formstrap/_password.html.erb +39 -0
- data/app/views/formstrap/_redactorx.html.erb +31 -0
- data/app/views/formstrap/_repeater.html.erb +128 -0
- data/app/views/formstrap/_search.html.erb +43 -0
- data/app/views/formstrap/_select.html.erb +43 -0
- data/app/views/formstrap/_switch.html.erb +29 -0
- data/app/views/formstrap/_text.html.erb +42 -0
- data/app/views/formstrap/_textarea.html.erb +39 -0
- data/app/views/formstrap/_to_ary.html.erb +0 -0
- data/app/views/formstrap/_url.html.erb +43 -0
- data/app/views/formstrap/_validation.html.erb +18 -0
- data/app/views/formstrap/_wrapper.html.erb +8 -0
- data/app/views/formstrap/_wysiwyg.html.erb +28 -0
- data/app/views/formstrap/autocomplete/_item.html.erb +3 -0
- data/app/views/formstrap/autocomplete/_list.html.erb +3 -0
- data/app/views/formstrap/blocks/_modal.html.erb +20 -0
- data/app/views/formstrap/fields/_base.html.erb +25 -0
- data/app/views/formstrap/fields/_file.html.erb +17 -0
- data/app/views/formstrap/fields/_files.html.erb +17 -0
- data/app/views/formstrap/fields/_group.html.erb +52 -0
- data/app/views/formstrap/fields/_list.html.erb +31 -0
- data/app/views/formstrap/fields/_text.html.erb +17 -0
- data/app/views/formstrap/media/_item.html.erb +38 -0
- data/app/views/formstrap/media/_media_item_modal.html.erb +77 -0
- data/app/views/formstrap/media/_modal.html.erb +40 -0
- data/app/views/formstrap/media/_thumbnail.html.erb +20 -0
- data/app/views/formstrap/media/_validation.html.erb +10 -0
- data/app/views/formstrap/media/create.turbo_stream.erb +5 -0
- data/app/views/formstrap/media/index.html.erb +3 -0
- data/app/views/formstrap/media/index.turbo_stream.erb +11 -0
- data/app/views/formstrap/media/show.html.erb +9 -0
- data/app/views/formstrap/media/thumbnail.html.erb +3 -0
- data/app/views/formstrap/media/update.turbo_stream.erb +3 -0
- data/app/views/formstrap/pagination/_infinite.html.erb +7 -0
- data/app/views/formstrap/repeater/_row.html.erb +53 -0
- data/app/views/formstrap/shared/_notifications.html.erb +20 -0
- data/app/views/formstrap/shared/_popup.html.erb +32 -0
- data/app/views/formstrap/shared/_thumbnail.html.erb +35 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/importmap.rb +2 -0
- data/config/locales/activerecord/en.yml +12 -0
- data/config/locales/activerecord/nl.yml +13 -0
- data/config/locales/defaults/en.yml +215 -0
- data/config/locales/defaults/nl.yml +213 -0
- data/config/locales/devise/en.yml +65 -0
- data/config/locales/devise/nl.yml +85 -0
- data/config/locales/en.yml +6 -0
- data/config/locales/formstrap/forms/en.yml +39 -0
- data/config/locales/formstrap/forms/nl.yml +39 -0
- data/config/locales/formstrap/media/en.yml +24 -0
- data/config/locales/formstrap/media/nl.yml +24 -0
- data/config/locales/formstrap/thumbnail/en.yml +4 -0
- data/config/locales/formstrap/thumbnail/nl.yml +4 -0
- data/config/locales/nl.yml +6 -0
- data/config/routes.rb +11 -0
- data/esbuild-css.js +25 -0
- data/esbuild-js.js +11 -0
- data/formstrap.gemspec +37 -0
- data/formstrap.iml +34 -0
- data/lib/formstrap/engine.rb +27 -0
- data/lib/formstrap/form_builder.rb +177 -0
- data/lib/formstrap/form_helper.rb +19 -0
- data/lib/formstrap/version.rb +3 -0
- data/lib/formstrap.rb +6 -0
- data/package.json +54 -0
- data/src/js/formstrap.js +1 -0
- data/src/scss/formstrap.scss +1 -0
- data/yarn.lock +1998 -0
- metadata +224 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
/* global CustomEvent */
|
2
|
+
import { Controller } from '@hotwired/stimulus'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
static get targets () {
|
6
|
+
return ['idCheckbox', 'item', 'form', 'selectButton', 'placeholder', 'count']
|
7
|
+
}
|
8
|
+
|
9
|
+
static get values () {
|
10
|
+
return { ids: Array }
|
11
|
+
}
|
12
|
+
|
13
|
+
connect () {
|
14
|
+
this.validate()
|
15
|
+
this.updateCount()
|
16
|
+
}
|
17
|
+
|
18
|
+
// Actions
|
19
|
+
select () {
|
20
|
+
this.dispatchSelectionEvent()
|
21
|
+
}
|
22
|
+
|
23
|
+
submitForm () {
|
24
|
+
this.hidePlaceholder()
|
25
|
+
this.triggerFormSubmission()
|
26
|
+
}
|
27
|
+
|
28
|
+
inputChange (event) {
|
29
|
+
this.handleIdsUpdate(event.target)
|
30
|
+
this.updateCount()
|
31
|
+
}
|
32
|
+
|
33
|
+
// Methods
|
34
|
+
hidePlaceholder () {
|
35
|
+
this.placeholderTarget.classList.add('d-none')
|
36
|
+
}
|
37
|
+
|
38
|
+
handleIdsUpdate (element) {
|
39
|
+
if (element.checked) {
|
40
|
+
const arr = this.idsValue
|
41
|
+
arr.push(element.value)
|
42
|
+
this.idsValue = arr
|
43
|
+
} else {
|
44
|
+
this.idsValue = this.idsValue.filter((value) => {
|
45
|
+
return element.value !== value
|
46
|
+
})
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
itemTargetConnected (element) {
|
51
|
+
this.updateItem(element.querySelector('input'))
|
52
|
+
}
|
53
|
+
|
54
|
+
updateItem (element) {
|
55
|
+
const arr = this.idsValue
|
56
|
+
|
57
|
+
if (arr.includes(element.value)) {
|
58
|
+
element.checked = true
|
59
|
+
} else {
|
60
|
+
element.checked = false
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
idsValueChanged () {
|
65
|
+
for (const item of this.itemTargets) {
|
66
|
+
this.updateItem(item.querySelector('input'))
|
67
|
+
}
|
68
|
+
this.validate()
|
69
|
+
}
|
70
|
+
|
71
|
+
dispatchSelectionEvent () {
|
72
|
+
document.dispatchEvent(
|
73
|
+
new CustomEvent(
|
74
|
+
'mediaSelectionSubmitted',
|
75
|
+
{
|
76
|
+
detail: {
|
77
|
+
name: this.element.dataset.name,
|
78
|
+
items: this.renderItemsForEvent()
|
79
|
+
}
|
80
|
+
}
|
81
|
+
)
|
82
|
+
)
|
83
|
+
}
|
84
|
+
|
85
|
+
triggerFormSubmission () {
|
86
|
+
this.formTarget.requestSubmit()
|
87
|
+
}
|
88
|
+
|
89
|
+
renderItemsForEvent () {
|
90
|
+
return this.idsValue.map((item) => this.renderItemForEvent(item)).filter((i) => { return i !== undefined })
|
91
|
+
}
|
92
|
+
|
93
|
+
renderItemForEvent (item) {
|
94
|
+
const id = parseInt(item)
|
95
|
+
const blobId = `#blob_${id}`
|
96
|
+
const element = this.element.querySelector(blobId)
|
97
|
+
|
98
|
+
return {
|
99
|
+
blobId: id,
|
100
|
+
thumbnail: element ? element.querySelector('.h-thumbnail') : ''
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
selectedItems () {
|
105
|
+
return this.itemTargets.filter((item) => {
|
106
|
+
const checkbox = item.querySelector('input[type="checkbox"]')
|
107
|
+
return checkbox.checked
|
108
|
+
})
|
109
|
+
}
|
110
|
+
|
111
|
+
selectedItemsCount () {
|
112
|
+
return this.idsValue.length
|
113
|
+
}
|
114
|
+
|
115
|
+
minSelectedItems () {
|
116
|
+
return parseInt(this.element.dataset.min, 10) || 0
|
117
|
+
}
|
118
|
+
|
119
|
+
maxSelectedItems () {
|
120
|
+
return parseInt(this.element.dataset.max, 10) || Infinity
|
121
|
+
}
|
122
|
+
|
123
|
+
validate () {
|
124
|
+
if (this.isValid()) {
|
125
|
+
this.enableSelectButton()
|
126
|
+
} else {
|
127
|
+
this.disableSelectButton()
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
enableSelectButton () {
|
132
|
+
this.selectButtonTarget.removeAttribute('disabled')
|
133
|
+
}
|
134
|
+
|
135
|
+
disableSelectButton () {
|
136
|
+
this.selectButtonTarget.setAttribute('disabled', '')
|
137
|
+
}
|
138
|
+
|
139
|
+
isValid () {
|
140
|
+
const count = this.selectedItemsCount()
|
141
|
+
return count >= this.minSelectedItems() && count <= this.maxSelectedItems()
|
142
|
+
}
|
143
|
+
|
144
|
+
updateCount () {
|
145
|
+
this.countTarget.innerHTML = this.selectedItemsCount()
|
146
|
+
}
|
147
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
/* global RedactorX */
|
2
|
+
import { Controller } from '@hotwired/stimulus'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
connect () {
|
6
|
+
this.initRedactor()
|
7
|
+
}
|
8
|
+
|
9
|
+
initRedactor () {
|
10
|
+
if (typeof RedactorX === 'undefined') {
|
11
|
+
console.error('RedactorX is a paid module and is not included in Headmin. Please purchase it and import it as a JS module')
|
12
|
+
return false
|
13
|
+
}
|
14
|
+
|
15
|
+
const defaultOptions = {
|
16
|
+
editor: {
|
17
|
+
minHeight: '57px'
|
18
|
+
},
|
19
|
+
subscribe: {
|
20
|
+
'app.start': () => {
|
21
|
+
this.stylize()
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
const options = JSON.parse(this.element.getAttribute('data-redactor-options'))
|
26
|
+
RedactorX(this.element, { ...defaultOptions, ...options })
|
27
|
+
}
|
28
|
+
|
29
|
+
stylize () {
|
30
|
+
const container = this.element.nextElementSibling
|
31
|
+
|
32
|
+
// Copy textarea classes
|
33
|
+
const inputClasses = this.element.classList
|
34
|
+
container.classList.add(...inputClasses)
|
35
|
+
|
36
|
+
// Add top margin to input group
|
37
|
+
// const inputGroup = container.closest('.input-group')
|
38
|
+
// inputGroup.classList.add('mt-4')
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import Sortable from 'sortablejs'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
static get values () {
|
6
|
+
return {
|
7
|
+
id: String
|
8
|
+
}
|
9
|
+
}
|
10
|
+
|
11
|
+
static get targets () {
|
12
|
+
return ['repeater', 'footer', 'template', 'row', 'list', 'empty', 'addButton']
|
13
|
+
}
|
14
|
+
|
15
|
+
connect () {
|
16
|
+
Sortable.create(this.listTarget, {
|
17
|
+
animation: 150,
|
18
|
+
ghostClass: 'list-group-item-dark',
|
19
|
+
draggable: '.repeater-row',
|
20
|
+
handle: '.repeater-row-handle',
|
21
|
+
onEnd: () => {
|
22
|
+
this.resetIndices()
|
23
|
+
this.resetPositions()
|
24
|
+
}
|
25
|
+
})
|
26
|
+
|
27
|
+
this.toggleEmpty()
|
28
|
+
}
|
29
|
+
|
30
|
+
resetButtonIndices (event) {
|
31
|
+
const row = event.target.closest('.repeater-row')
|
32
|
+
const index = this.containsRow(row) ? row.dataset.rowIndex : ''
|
33
|
+
this.updatePopupButtonIndices(index)
|
34
|
+
}
|
35
|
+
|
36
|
+
containsRow (row) {
|
37
|
+
return this.rowTargets.includes(row)
|
38
|
+
}
|
39
|
+
|
40
|
+
updatePopupButtonIndices (index) {
|
41
|
+
const popup = document.querySelector(`[data-popup-target="popup"][data-popup-id="repeater-buttons-${this.idValue}"]`)
|
42
|
+
const buttons = popup.querySelectorAll('a')
|
43
|
+
buttons.forEach((button) => {
|
44
|
+
button.dataset.rowIndex = index
|
45
|
+
})
|
46
|
+
}
|
47
|
+
|
48
|
+
addRow (event) {
|
49
|
+
event.preventDefault()
|
50
|
+
const button = event.target
|
51
|
+
const templateName = button.dataset.templateName
|
52
|
+
const rowIndex = button.dataset.rowIndex
|
53
|
+
|
54
|
+
// Prepare html from template
|
55
|
+
const template = this.getTemplate(templateName)
|
56
|
+
const html = this.replaceIdsWithTimestamps(template)
|
57
|
+
|
58
|
+
// Fallback to last row if no index is set
|
59
|
+
if (rowIndex) {
|
60
|
+
// Insert new row after defined row
|
61
|
+
const row = this.rowTargets[rowIndex]
|
62
|
+
row.insertAdjacentHTML('afterend', html)
|
63
|
+
} else {
|
64
|
+
// Insert before footer
|
65
|
+
this.footerTarget.insertAdjacentHTML('beforebegin', html)
|
66
|
+
}
|
67
|
+
|
68
|
+
this.resetIndices()
|
69
|
+
this.resetPositions()
|
70
|
+
this.toggleEmpty()
|
71
|
+
}
|
72
|
+
|
73
|
+
removeRow (event) {
|
74
|
+
event.preventDefault()
|
75
|
+
|
76
|
+
const row = event.target.closest('.repeater-row')
|
77
|
+
|
78
|
+
if (row.dataset.newRecord === 'true') {
|
79
|
+
// New records are simply removed from the page
|
80
|
+
row.remove()
|
81
|
+
} else {
|
82
|
+
// Existing records are hidden and flagged for deletion
|
83
|
+
this.flagRowForDeletion(row)
|
84
|
+
row.remove()
|
85
|
+
}
|
86
|
+
|
87
|
+
this.resetIndices()
|
88
|
+
this.resetPositions()
|
89
|
+
this.toggleEmpty()
|
90
|
+
}
|
91
|
+
|
92
|
+
flagRowForDeletion (row) {
|
93
|
+
const destroyInput = row.querySelector('input[name*=\'_destroy\']')
|
94
|
+
const idInput = row.querySelector('input[name*=\'[id]\']')
|
95
|
+
|
96
|
+
// Update _destroy value
|
97
|
+
destroyInput.value = 1
|
98
|
+
|
99
|
+
// Move away from row
|
100
|
+
this.listTarget.parentNode.appendChild(destroyInput)
|
101
|
+
this.listTarget.parentNode.appendChild(idInput)
|
102
|
+
}
|
103
|
+
|
104
|
+
getTemplate (name) {
|
105
|
+
return this.templateTargets.filter((template) => {
|
106
|
+
return template.dataset.templateName === name
|
107
|
+
})[0]
|
108
|
+
}
|
109
|
+
|
110
|
+
replaceIdsWithTimestamps (template) {
|
111
|
+
const regex = new RegExp(template.dataset.templateIdRegex, 'g')
|
112
|
+
return template.innerHTML.replace(regex, new Date().getTime())
|
113
|
+
}
|
114
|
+
|
115
|
+
visibleRowsCount () {
|
116
|
+
return this.visibleRows().length
|
117
|
+
}
|
118
|
+
|
119
|
+
visibleRows () {
|
120
|
+
const rows = this.rowTargets
|
121
|
+
return rows.filter((row) => {
|
122
|
+
return row.querySelector('input[name*=\'_destroy\']').value !== '1'
|
123
|
+
})
|
124
|
+
}
|
125
|
+
|
126
|
+
toggleEmpty () {
|
127
|
+
if (this.visibleRowsCount() > 0) {
|
128
|
+
this.emptyTarget.classList.add('invisible')
|
129
|
+
} else {
|
130
|
+
this.emptyTarget.classList.remove('invisible')
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
resetPositions () {
|
135
|
+
this.visibleRows().forEach((row, index) => {
|
136
|
+
const positionInput = row.querySelector('input[name*=\'position\']')
|
137
|
+
if (positionInput) {
|
138
|
+
positionInput.value = index
|
139
|
+
}
|
140
|
+
})
|
141
|
+
}
|
142
|
+
|
143
|
+
resetIndices () {
|
144
|
+
this.visibleRows().forEach((row, index) => {
|
145
|
+
row.dataset.rowIndex = index
|
146
|
+
})
|
147
|
+
}
|
148
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import TomSelect from 'tom-select'
|
3
|
+
import I18n from '../config/i18n'
|
4
|
+
|
5
|
+
export default class extends Controller {
|
6
|
+
connect () {
|
7
|
+
if (this.element.hasAttribute('multiple')) {
|
8
|
+
this.initTomSelect()
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
defaultOptions (locale) {
|
13
|
+
const defaultOptions = {
|
14
|
+
en: {
|
15
|
+
render: {
|
16
|
+
option_create: function (data, escape) {
|
17
|
+
return '<div class="create">Add <strong>' + escape(data.input) + '</strong>…</div>'
|
18
|
+
},
|
19
|
+
no_results: function (data, escape) {
|
20
|
+
return '<div class="no-results">No results found</div>'
|
21
|
+
}
|
22
|
+
}
|
23
|
+
},
|
24
|
+
nl: {
|
25
|
+
render: {
|
26
|
+
option_create: function (data, escape) {
|
27
|
+
return '<div class="create">Voeg <strong>' + escape(data.input) + '</strong> toe …</div>'
|
28
|
+
},
|
29
|
+
no_results: function (data, escape) {
|
30
|
+
return '<div class="no-results">Geen resultaten gevonden</div>'
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
return defaultOptions[locale]
|
36
|
+
}
|
37
|
+
|
38
|
+
hasTags () {
|
39
|
+
return this.element.dataset.tags === 'true'
|
40
|
+
}
|
41
|
+
|
42
|
+
initTomSelect () {
|
43
|
+
const defaultOptions = this.defaultOptions(I18n.locale)
|
44
|
+
const options = { create: this.hasTags() }
|
45
|
+
|
46
|
+
/* eslint-disable no-new */
|
47
|
+
new TomSelect(this.element, { ...defaultOptions, ...options })
|
48
|
+
}
|
49
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
/* global IntersectionObserver */
|
2
|
+
import { Controller } from '@hotwired/stimulus'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
static get targets () {
|
6
|
+
return ['textarea', 'count']
|
7
|
+
}
|
8
|
+
|
9
|
+
connect () {
|
10
|
+
onVisible(this.textareaTarget, () => { this.update() })
|
11
|
+
}
|
12
|
+
|
13
|
+
update () {
|
14
|
+
this.resize()
|
15
|
+
this.updateCount()
|
16
|
+
}
|
17
|
+
|
18
|
+
resize () {
|
19
|
+
this.textareaTarget.style.height = 'auto'
|
20
|
+
this.textareaTarget.setAttribute('style', 'height:' + (this.textareaTarget.scrollHeight) + 'px;overflow-y:hidden;')
|
21
|
+
}
|
22
|
+
|
23
|
+
updateCount () {
|
24
|
+
if (this.textareaTarget.getAttribute('maxlength')) {
|
25
|
+
this.updateCountLength()
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
updateCountLength () {
|
30
|
+
const currentLength = this.textareaTarget.value.length
|
31
|
+
const maximumLength = this.textareaTarget.getAttribute('maxlength')
|
32
|
+
|
33
|
+
this.countTarget.textContent = `${currentLength}/${maximumLength}`
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
// Custom callback event that triggers when an element becomes visible.
|
38
|
+
// Solves the bug where textarea fields are not properly sized when they (or their parent) or hidden.
|
39
|
+
function onVisible (element, callback) {
|
40
|
+
new IntersectionObserver((entries, observer) => {
|
41
|
+
entries.forEach(entry => {
|
42
|
+
if (entry.intersectionRatio > 0) {
|
43
|
+
callback(element)
|
44
|
+
observer.disconnect()
|
45
|
+
}
|
46
|
+
})
|
47
|
+
}).observe(element)
|
48
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
/* global Stimulus */
|
2
|
+
import { Application } from '@hotwired/stimulus'
|
3
|
+
import AutocompleteController from './controllers/autocomplete_controller'
|
4
|
+
import DateRangeController from './controllers/date_range_controller'
|
5
|
+
import DropzoneController from './controllers/dropzone_controller'
|
6
|
+
import FilePreviewController from './controllers/file_preview_controller'
|
7
|
+
import FlatpickrController from './controllers/flatpickr_controller'
|
8
|
+
import InfiniteScrollerController from './controllers/infinite_scroller_controller'
|
9
|
+
import MediaController from './controllers/media_controller'
|
10
|
+
import MediaModalController from './controllers/media_modal_controller'
|
11
|
+
import RedactorxController from './controllers/redactorx_controller'
|
12
|
+
import RepeaterController from './controllers/repeater_controller'
|
13
|
+
import SelectController from './controllers/select_controller'
|
14
|
+
import TextareaController from './controllers/textarea_controller'
|
15
|
+
|
16
|
+
export class Formstrap {
|
17
|
+
static start () {
|
18
|
+
window.Stimulus = window.Stimulus || Application.start()
|
19
|
+
Stimulus.register('autocomplete', AutocompleteController)
|
20
|
+
Stimulus.register('date-range', DateRangeController)
|
21
|
+
Stimulus.register('dropzone', DropzoneController)
|
22
|
+
Stimulus.register('file-preview', FilePreviewController)
|
23
|
+
Stimulus.register('flatpickr', FlatpickrController)
|
24
|
+
Stimulus.register('infinite-scroller', InfiniteScrollerController)
|
25
|
+
Stimulus.register('media', MediaController)
|
26
|
+
Stimulus.register('media-modal', MediaModalController)
|
27
|
+
Stimulus.register('redactorx', RedactorxController)
|
28
|
+
Stimulus.register('repeater', RepeaterController)
|
29
|
+
Stimulus.register('select', SelectController)
|
30
|
+
Stimulus.register('textarea', TextareaController)
|
31
|
+
}
|
32
|
+
}
|