headmin 0.3.2 → 0.4.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 +4 -4
- data/.github/workflows/ci.yml +27 -0
- data/.gitignore +14 -0
- data/.nvmrc +1 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile +8 -5
- data/Gemfile.lock +197 -25
- data/README.md +9 -1
- data/Rakefile +1 -7
- 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/headmin/config/i18n.js +9 -9
- data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +255 -0
- data/app/assets/javascripts/headmin/controllers/blocks_controller.js +74 -79
- data/app/assets/javascripts/headmin/controllers/date_range_controller.js +24 -24
- data/app/assets/javascripts/headmin/controllers/dropzone_controller.js +23 -25
- data/app/assets/javascripts/headmin/controllers/file_preview_controller.js +237 -237
- data/app/assets/javascripts/headmin/controllers/filter_controller.js +44 -44
- data/app/assets/javascripts/headmin/controllers/filters_controller.js +57 -61
- data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +29 -29
- data/app/assets/javascripts/headmin/controllers/hello_controller.js +3 -3
- data/app/assets/javascripts/headmin/controllers/notification_controller.js +7 -6
- data/app/assets/javascripts/headmin/controllers/popup_controller.js +51 -52
- data/app/assets/javascripts/headmin/controllers/redactorx_controller.js +36 -9
- data/app/assets/javascripts/headmin/controllers/repeater_controller.js +122 -125
- data/app/assets/javascripts/headmin/controllers/select_controller.js +40 -39
- data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +88 -77
- data/app/assets/javascripts/headmin/controllers/table_controller.js +103 -89
- data/app/assets/javascripts/headmin/index.js +38 -39
- data/app/assets/javascripts/headmin.js +287 -732
- data/app/assets/stylesheets/headmin/forms/autocomplete.scss +21 -0
- data/app/assets/stylesheets/headmin/forms/file.scss +46 -0
- data/app/assets/stylesheets/headmin/forms/repeater.scss +62 -0
- data/app/assets/stylesheets/headmin/forms/search.scss +12 -0
- data/app/assets/stylesheets/headmin/forms.scss +11 -0
- data/app/assets/stylesheets/headmin/general.scss +5 -0
- data/app/assets/stylesheets/headmin/overrides/bootstrap.scss +5 -3
- data/app/assets/stylesheets/headmin/overrides/redactorx.scss +74 -0
- data/app/assets/stylesheets/headmin/popup.scss +1 -0
- data/app/assets/stylesheets/headmin/syntax.scss +36 -349
- data/app/assets/stylesheets/headmin/table.scss +1 -1
- data/app/assets/stylesheets/headmin/utilities/buttons.scss +19 -0
- data/app/assets/stylesheets/headmin/utilities/dropzone.scss +72 -0
- data/app/assets/stylesheets/headmin/utilities.scss +2 -68
- data/app/assets/stylesheets/headmin/vendor/tom-select-bootstrap.css +1 -2
- data/app/assets/stylesheets/headmin.css +206 -206
- data/app/assets/stylesheets/headmin.scss +1 -1
- data/app/controllers/concerns/headmin/authentication.rb +1 -1
- data/app/controllers/concerns/headmin/searchable.rb +1 -1
- data/app/controllers/concerns/headmin/sortable.rb +7 -7
- data/app/helpers/headmin/admin_helper.rb +1 -2
- data/app/helpers/headmin/bootstrap_helper.rb +2 -24
- data/app/helpers/headmin/filter_helper.rb +1 -1
- data/app/helpers/headmin/form_helper.rb +5 -11
- data/app/helpers/headmin/notification_helper.rb +21 -21
- data/app/helpers/headmin/request_helper.rb +3 -3
- data/app/models/concerns/headmin/block.rb +1 -2
- data/app/models/concerns/headmin/blockable.rb +2 -2
- data/app/models/concerns/headmin/field.rb +2 -1
- data/app/models/concerns/headmin/fieldable.rb +8 -8
- data/app/models/concerns/headmin/form/autocompletable.rb +38 -0
- data/app/models/concerns/headmin/form/hintable.rb +19 -0
- data/app/models/concerns/headmin/form/input_groupable.rb +23 -0
- data/app/models/concerns/headmin/form/labelable.rb +33 -0
- data/app/models/concerns/headmin/form/listable.rb +28 -0
- data/app/models/concerns/headmin/form/placeholderable.rb +13 -0
- data/app/models/concerns/headmin/form/validatable.rb +40 -0
- data/app/models/concerns/headmin/form/wrappable.rb +21 -0
- data/app/models/headmin/.DS_Store +0 -0
- data/app/models/headmin/blocks_view.rb +15 -0
- data/app/models/headmin/form/blocks_view.rb +29 -0
- data/app/models/headmin/form/checkbox_view.rb +52 -0
- data/app/models/headmin/form/date_range_view.rb +25 -0
- data/app/models/headmin/form/date_view.rb +45 -0
- data/app/models/headmin/form/email_view.rb +48 -0
- data/app/models/headmin/form/file_view.rb +116 -0
- data/app/models/headmin/form/flatpickr_range_view.rb +102 -0
- data/app/models/headmin/form/flatpickr_view.rb +37 -0
- data/app/models/headmin/form/hidden_view.rb +10 -0
- data/app/models/headmin/form/hint_view.rb +6 -0
- data/app/models/headmin/form/input_group_view.rb +19 -0
- data/app/models/headmin/form/label_view.rb +24 -0
- data/app/models/headmin/form/number_view.rb +49 -0
- data/app/models/headmin/form/password_view.rb +44 -0
- data/app/models/headmin/form/redactorx_view.rb +59 -0
- data/app/models/headmin/form/search_view.rb +48 -0
- data/app/models/headmin/form/select_view.rb +62 -0
- data/app/models/headmin/form/switch_view.rb +23 -0
- data/app/models/headmin/form/text_view.rb +48 -0
- data/app/models/headmin/form/textarea_view.rb +44 -0
- data/app/models/headmin/form/url_view.rb +48 -0
- data/app/models/headmin/form/wrapper_view.rb +19 -0
- data/app/models/headmin/form/wysiwyg_view.rb +17 -0
- data/app/models/headmin/thumbnail_view.rb +66 -0
- data/app/models/view_model.rb +58 -0
- data/app/views/headmin/_blocks.html.erb +13 -9
- data/app/views/headmin/_heading.html.erb +7 -1
- data/app/views/headmin/_thumbnail.html.erb +5 -39
- data/app/views/headmin/dropdown/_item.html.erb +1 -1
- data/app/views/headmin/forms/_autocomplete.html.erb +11 -0
- data/app/views/headmin/forms/_blocks.html.erb +16 -17
- data/app/views/headmin/forms/_checkbox.html.erb +24 -29
- data/app/views/headmin/forms/_datalist.html.erb +3 -0
- data/app/views/headmin/forms/_date.html.erb +24 -24
- data/app/views/headmin/forms/_date_range.html.erb +19 -21
- data/app/views/headmin/forms/_email.html.erb +27 -32
- data/app/views/headmin/forms/_errors.html.erb +2 -3
- data/app/views/headmin/forms/_file.html.erb +84 -181
- data/app/views/headmin/forms/_flatpickr.html.erb +19 -20
- data/app/views/headmin/forms/_flatpickr_range.html.erb +28 -37
- data/app/views/headmin/forms/_hidden.html.erb +9 -10
- data/app/views/headmin/forms/_hint.html.erb +16 -0
- data/app/views/headmin/forms/_input_group.html.erb +21 -0
- data/app/views/headmin/forms/_label.html.erb +5 -13
- data/app/views/headmin/forms/_number.html.erb +23 -35
- data/app/views/headmin/forms/_password.html.erb +21 -30
- data/app/views/headmin/forms/_redactorx.html.erb +21 -40
- data/app/views/headmin/forms/_repeater.html.erb +55 -60
- data/app/views/headmin/forms/_search.html.erb +43 -0
- data/app/views/headmin/forms/_select.html.erb +24 -49
- data/app/views/headmin/forms/_switch.html.erb +29 -0
- data/app/views/headmin/forms/_text.html.erb +42 -96
- data/app/views/headmin/forms/_textarea.html.erb +21 -32
- data/app/views/headmin/forms/_url.html.erb +26 -31
- data/app/views/headmin/forms/_validation.html.erb +10 -13
- data/app/views/headmin/forms/_wrapper.html.erb +9 -0
- data/app/views/headmin/forms/_wysiwyg.html.erb +28 -0
- data/app/views/headmin/forms/autocomplete/_item.html.erb +3 -0
- data/app/views/headmin/forms/autocomplete/_list.html.erb +3 -0
- data/app/views/headmin/forms/fields/_group.html.erb +6 -4
- data/app/views/headmin/forms/repeater/_row.html.erb +4 -4
- data/app/views/headmin/nav/item/_devise.html.erb +1 -1
- data/app/views/headmin/table/_actions.html.erb +1 -1
- data/app/views/headmin/table/actions/_action.html.erb +2 -1
- data/app/views/headmin/table/actions/_delete.html.erb +1 -1
- data/app/views/headmin/views/devise/registrations/_edit.html.erb +2 -2
- data/bin/console +0 -1
- data/config/initializers/customize_input_error.rb +4 -4
- data/config/locales/headmin/forms/en.yml +0 -11
- data/config/locales/headmin/forms/nl.yml +0 -11
- data/esbuild-css.js +18 -18
- data/esbuild-js.js +8 -8
- data/headmin.gemspec +1 -3
- data/lib/generators/headmin/blocks_generator.rb +8 -8
- data/lib/generators/headmin/devise_generator.rb +4 -4
- data/lib/generators/headmin/fields_generator.rb +9 -9
- data/lib/generators/templates/controllers/auth/confirmations_controller.rb +1 -3
- data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +1 -3
- data/lib/generators/templates/controllers/auth/passwords_controller.rb +1 -3
- data/lib/generators/templates/controllers/auth/registrations_controller.rb +1 -3
- data/lib/generators/templates/controllers/auth/sessions_controller.rb +1 -3
- data/lib/generators/templates/controllers/auth/unlocks_controller.rb +1 -3
- data/lib/generators/templates/models/block.rb +1 -1
- data/lib/headmin/engine.rb +6 -6
- data/lib/headmin/version.rb +1 -3
- data/lib/headmin.rb +0 -2
- data/package-lock.json +5359 -0
- data/package.json +13 -7
- data/view_model_benchmark.rb +74 -0
- data/yarn-error.log +367 -0
- data/yarn.lock +1448 -161
- metadata +69 -25
- data/.rubocop.yml +0 -13
- data/app/assets/stylesheets/headmin/form.scss +0 -132
- data/app/assets/stylesheets/headmin/overrides/redactorx.css +0 -3
- data/app/helpers/headmin/documentation_helper.rb +0 -35
- data/app/models/headmin/documentation_renderer.rb +0 -32
- data/app/models/headmin/form/base.rb +0 -79
- data/app/models/headmin/form/text.rb +0 -53
- data/app/services/block_service.rb +0 -72
- data/app/views/headmin/_card.html.erb +0 -52
- data/app/views/headmin/forms/_actions.html.erb +0 -28
- data/app/views/headmin/forms/_base.html.erb +0 -114
- data/app/views/headmin/forms/_image.html.erb +0 -21
- data/app/views/headmin/forms/_video.html.erb +0 -21
- data/app/views/headmin/forms/actions/_destroy.html.erb +0 -13
- data/app/views/headmin/forms/actions/_save.html.erb +0 -12
- data/app/views/headmin/forms/actions/_view.html.erb +0 -15
- data/docs/blocks-and-fields.md +0 -54
- data/docs/blocks.md +0 -48
- data/docs/devise.md +0 -41
- data/docs/fields.md +0 -79
@@ -1,64 +1,60 @@
|
|
1
|
-
import {Controller} from
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
replaceIdsWithTimestamps(html) {
|
61
|
-
const regex = new RegExp('template_id', "g");
|
62
|
-
return html.replace(regex, new Date().getTime())
|
63
|
-
}
|
4
|
+
static get targets () {
|
5
|
+
return ['form', 'list', 'input', 'template', 'button', 'menuItem']
|
6
|
+
}
|
7
|
+
|
8
|
+
add (event) {
|
9
|
+
event.preventDefault()
|
10
|
+
const name = event.target.dataset.filterName
|
11
|
+
const button = this.getButtonByName(name)
|
12
|
+
if (button) {
|
13
|
+
this.openFilter(button)
|
14
|
+
} else {
|
15
|
+
this.createFilter(name)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
createFilter (name) {
|
20
|
+
let html = this.getTemplateHTML(name)
|
21
|
+
html = this.replaceIdsWithTimestamps(html)
|
22
|
+
this.listTarget.insertAdjacentHTML('beforeend', html)
|
23
|
+
}
|
24
|
+
|
25
|
+
remove (event) {
|
26
|
+
const filter = event.currentTarget.closest('.h-filter')
|
27
|
+
filter.remove()
|
28
|
+
this.formTarget.submit()
|
29
|
+
}
|
30
|
+
|
31
|
+
removeAll (event) {
|
32
|
+
this.listTarget.innerHTML = ''
|
33
|
+
this.formTarget.submit()
|
34
|
+
}
|
35
|
+
|
36
|
+
update (event) {
|
37
|
+
this.formTarget.submit()
|
38
|
+
}
|
39
|
+
|
40
|
+
getButtonByName (name) {
|
41
|
+
return this.buttonTargets.find(function (element) {
|
42
|
+
return element.dataset.filterName === name
|
43
|
+
})
|
44
|
+
}
|
45
|
+
|
46
|
+
openFilter (button) {
|
47
|
+
button.controller.open()
|
48
|
+
}
|
49
|
+
|
50
|
+
getTemplateHTML (name) {
|
51
|
+
const template = this.templateTargets.filter((element) => {
|
52
|
+
return element.dataset.filterName === name
|
53
|
+
})[0]
|
54
|
+
return template.innerHTML
|
55
|
+
}
|
56
|
+
|
57
|
+
replaceIdsWithTimestamps (html) {
|
58
|
+
return html.replace(/template_id/g, new Date().getTime())
|
59
|
+
}
|
64
60
|
}
|
@@ -1,39 +1,39 @@
|
|
1
|
-
import {Controller} from
|
2
|
-
import flatpickr from
|
3
|
-
import {Dutch} from
|
4
|
-
import I18n from
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import flatpickr from 'flatpickr'
|
3
|
+
import { Dutch } from 'flatpickr/dist/esm/l10n/nl.js'
|
4
|
+
import I18n from '../config/i18n'
|
5
5
|
|
6
6
|
export default class extends Controller {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
static get targets () {
|
8
|
+
return ['input']
|
9
|
+
}
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
connect () {
|
12
|
+
const options = { ...this.defaultOptions(), ...this.options() }
|
13
|
+
flatpickr(this.inputTarget, options)
|
14
|
+
}
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
options () {
|
17
|
+
return JSON.parse(this.inputTarget.getAttribute('data-flatpickr'))
|
18
|
+
}
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
}
|
20
|
+
defaultOptions () {
|
21
|
+
return {
|
22
|
+
allowInput: true,
|
23
|
+
dateFormat: 'd/m/Y',
|
24
|
+
locale: this.getLocale(I18n.locale)
|
26
25
|
}
|
26
|
+
}
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
getLocale (locale) {
|
29
|
+
const locales = this.locales()
|
30
|
+
return locales[locale]
|
31
|
+
}
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
}
|
33
|
+
locales () {
|
34
|
+
return {
|
35
|
+
en: null,
|
36
|
+
nl: Dutch
|
38
37
|
}
|
38
|
+
}
|
39
39
|
}
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import {Controller} from
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
|
-
connect() {
|
5
|
-
this.element.textContent =
|
4
|
+
connect () {
|
5
|
+
this.element.textContent = 'Hello world'
|
6
6
|
}
|
7
7
|
}
|
@@ -1,8 +1,9 @@
|
|
1
|
-
import {Controller} from
|
2
|
-
import {Toast} from
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import { Toast } from 'bootstrap'
|
3
3
|
|
4
4
|
export default class extends Controller {
|
5
|
-
|
6
|
-
|
7
|
-
}
|
8
|
-
}
|
5
|
+
connect () {
|
6
|
+
/* eslint-disable no-new */
|
7
|
+
new Toast(this.element, {})
|
8
|
+
}
|
9
|
+
}
|
@@ -1,67 +1,66 @@
|
|
1
|
-
import {Controller} from
|
2
|
-
import {createPopper} from '@popperjs/core'
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import { createPopper } from '@popperjs/core'
|
3
3
|
|
4
4
|
export default class extends Controller {
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
static get targets () {
|
6
|
+
return ['popup', 'button']
|
7
|
+
}
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
static get values () {
|
10
|
+
return { id: String }
|
11
|
+
}
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
connect () {
|
14
|
+
// Clicked outside popup
|
15
|
+
document.addEventListener('click', (event) => {
|
16
|
+
this.handleOutsideClick(event)
|
17
|
+
})
|
18
|
+
}
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
handleOutsideClick (event) {
|
21
|
+
const inPopup = event.target.closest('[data-popup-target="popup"]') !== null
|
22
|
+
const inButton = event.target.closest('[data-popup-target="button"]') !== null
|
23
|
+
const openPopup = document.querySelector('[data-popup-target="popup"]:not(.closed)')
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
}
|
25
|
+
if (!inButton && !inPopup && openPopup) {
|
26
|
+
this.closePopup(openPopup)
|
28
27
|
}
|
28
|
+
}
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if (passThru) {
|
36
|
-
// Pass click event to an element inside the popup
|
37
|
-
const passThruElement = popup.querySelector(passThru)
|
38
|
-
passThruElement.click()
|
30
|
+
open (event) {
|
31
|
+
const button = event.target.closest('[data-popup-target="button"]')
|
32
|
+
const popup = this.popupById(button.dataset.popupId)
|
33
|
+
const passThru = button.dataset.popupPassThru
|
39
34
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
35
|
+
if (passThru) {
|
36
|
+
// Pass click event to an element inside the popup
|
37
|
+
const passThruElement = popup.querySelector(passThru)
|
38
|
+
passThruElement.click()
|
39
|
+
} else {
|
40
|
+
// Open the popup
|
41
|
+
createPopper(button, popup)
|
42
|
+
this.openPopup(popup)
|
45
43
|
}
|
44
|
+
}
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
close (event) {
|
47
|
+
const button = event.target.closest('[data-popup-target="button"]')
|
48
|
+
const popup = this.popupById(button.dataset.popupId)
|
50
49
|
|
51
|
-
|
52
|
-
|
50
|
+
this.closePopup(popup)
|
51
|
+
}
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
popupById (id) {
|
54
|
+
return this.popupTargets.find((popup) => {
|
55
|
+
return popup.dataset.popupId === id
|
56
|
+
})
|
57
|
+
}
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
openPopup (popup) {
|
60
|
+
popup.classList.remove('closed')
|
61
|
+
}
|
63
62
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
}
|
63
|
+
closePopup (popup) {
|
64
|
+
popup.classList.add('closed')
|
65
|
+
}
|
66
|
+
}
|
@@ -1,13 +1,40 @@
|
|
1
|
-
|
1
|
+
/* global RedactorX */
|
2
|
+
import { Controller } from '@hotwired/stimulus'
|
2
3
|
|
3
4
|
export default class extends Controller {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
+
}
|
9
14
|
|
10
|
-
|
11
|
-
|
15
|
+
const defaultOptions = {
|
16
|
+
editor: {
|
17
|
+
minHeight: '57px'
|
18
|
+
},
|
19
|
+
subscribe: {
|
20
|
+
'app.start': () => {
|
21
|
+
this.stylize()
|
22
|
+
}
|
23
|
+
}
|
12
24
|
}
|
13
|
-
|
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
|
+
}
|
@@ -1,139 +1,136 @@
|
|
1
|
-
import {Controller} from
|
2
|
-
import Sortable from
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import Sortable from 'sortablejs'
|
3
3
|
|
4
4
|
export default class extends Controller {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
}
|
5
|
+
static get values () {
|
6
|
+
return {
|
7
|
+
id: String
|
9
8
|
}
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
let 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
|
-
// Dispatch an event
|
69
|
-
document.dispatchEvent(new CustomEvent('headmin:reinit', {bubbles: true}))
|
70
|
-
|
71
|
-
this.resetIndices()
|
72
|
-
this.resetPositions()
|
73
|
-
this.toggleEmpty()
|
74
|
-
}
|
75
|
-
|
76
|
-
removeRow(event) {
|
77
|
-
event.preventDefault()
|
78
|
-
|
79
|
-
const row = event.target.closest(".repeater-row")
|
80
|
-
|
81
|
-
if (row.dataset.newRecord === "true") {
|
82
|
-
// New records are simply removed from the page
|
83
|
-
row.remove()
|
84
|
-
} else {
|
85
|
-
// Existing records are hidden and flagged for deletion
|
86
|
-
row.querySelector("input[name*='_destroy']").value = 1
|
87
|
-
row.style.display = 'none'
|
88
|
-
}
|
89
|
-
|
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: () => {
|
90
22
|
this.resetIndices()
|
91
23
|
this.resetPositions()
|
92
|
-
|
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)
|
93
66
|
}
|
94
67
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
}
|
68
|
+
this.resetIndices()
|
69
|
+
this.resetPositions()
|
70
|
+
this.toggleEmpty()
|
71
|
+
}
|
100
72
|
|
101
|
-
|
102
|
-
|
103
|
-
return template.innerHTML.replace(regex, new Date().getTime())
|
104
|
-
}
|
105
|
-
|
106
|
-
visibleRowsCount() {
|
107
|
-
return this.visibleRows().length
|
108
|
-
}
|
73
|
+
removeRow (event) {
|
74
|
+
event.preventDefault()
|
109
75
|
|
110
|
-
|
111
|
-
const rows = this.rowTargets
|
112
|
-
return rows.filter((row) => {
|
113
|
-
return row.querySelector("input[name*='_destroy']").value !== '1'
|
114
|
-
})
|
115
|
-
}
|
116
|
-
|
117
|
-
toggleEmpty() {
|
118
|
-
if (this.visibleRowsCount() > 0) {
|
119
|
-
this.emptyTarget.classList.add('invisible')
|
120
|
-
} else {
|
121
|
-
this.emptyTarget.classList.remove('invisible')
|
122
|
-
}
|
123
|
-
}
|
76
|
+
const row = event.target.closest('.repeater-row')
|
124
77
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
+
row.querySelector("input[name*='_destroy']").value = 1
|
84
|
+
row.style.display = 'none'
|
132
85
|
}
|
133
86
|
|
134
|
-
resetIndices()
|
135
|
-
|
136
|
-
|
137
|
-
|
87
|
+
this.resetIndices()
|
88
|
+
this.resetPositions()
|
89
|
+
this.toggleEmpty()
|
90
|
+
}
|
91
|
+
|
92
|
+
getTemplate (name) {
|
93
|
+
return this.templateTargets.filter((template) => {
|
94
|
+
return template.dataset.templateName === name
|
95
|
+
})[0]
|
96
|
+
}
|
97
|
+
|
98
|
+
replaceIdsWithTimestamps (template) {
|
99
|
+
const regex = new RegExp(template.dataset.templateIdRegex, 'g')
|
100
|
+
return template.innerHTML.replace(regex, new Date().getTime())
|
101
|
+
}
|
102
|
+
|
103
|
+
visibleRowsCount () {
|
104
|
+
return this.visibleRows().length
|
105
|
+
}
|
106
|
+
|
107
|
+
visibleRows () {
|
108
|
+
const rows = this.rowTargets
|
109
|
+
return rows.filter((row) => {
|
110
|
+
return row.querySelector("input[name*='_destroy']").value !== '1'
|
111
|
+
})
|
112
|
+
}
|
113
|
+
|
114
|
+
toggleEmpty () {
|
115
|
+
if (this.visibleRowsCount() > 0) {
|
116
|
+
this.emptyTarget.classList.add('invisible')
|
117
|
+
} else {
|
118
|
+
this.emptyTarget.classList.remove('invisible')
|
138
119
|
}
|
120
|
+
}
|
121
|
+
|
122
|
+
resetPositions () {
|
123
|
+
this.visibleRows().forEach((row, index) => {
|
124
|
+
const positionInput = row.querySelector("input[name*='position']")
|
125
|
+
if (positionInput) {
|
126
|
+
positionInput.value = index
|
127
|
+
}
|
128
|
+
})
|
129
|
+
}
|
130
|
+
|
131
|
+
resetIndices () {
|
132
|
+
this.visibleRows().forEach((row, index) => {
|
133
|
+
row.dataset.rowIndex = index
|
134
|
+
})
|
135
|
+
}
|
139
136
|
}
|