headmin 0.2.2 → 0.2.6

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.nvmrc +1 -1
  3. data/Gemfile.lock +3 -3
  4. data/README.md +17 -7
  5. data/app/helpers/headmin/admin_helper.rb +3 -59
  6. data/app/helpers/headmin/bootstrap_helper.rb +9 -0
  7. data/app/helpers/headmin/filter_helper.rb +7 -3
  8. data/app/helpers/headmin/form_helper.rb +36 -0
  9. data/app/helpers/headmin/request_helper.rb +39 -0
  10. data/app/models/concerns/headmin/fieldable.rb +53 -23
  11. data/app/services/block_service.rb +8 -4
  12. data/app/views/headmin/_blocks.html.erb +1 -1
  13. data/app/views/headmin/_filters.html.erb +1 -1
  14. data/app/views/headmin/_pagination.html.erb +4 -1
  15. data/app/views/headmin/dropdown/_devise.html.erb +20 -10
  16. data/app/views/headmin/dropdown/_list.html.erb +17 -7
  17. data/app/views/headmin/filters/_select.html.erb +3 -2
  18. data/app/views/headmin/filters/filter/_button.html.erb +0 -1
  19. data/app/views/headmin/forms/_blocks.html.erb +11 -4
  20. data/app/views/headmin/forms/_date.html.erb +1 -1
  21. data/app/views/headmin/forms/_label.html.erb +2 -2
  22. data/app/views/headmin/forms/_repeater.html.erb +6 -10
  23. data/app/views/headmin/table/_actions.html.erb +37 -11
  24. data/app/views/headmin/views/devise/confirmations/_new.html.erb +1 -1
  25. data/app/views/headmin/views/devise/passwords/_edit.html.erb +2 -2
  26. data/app/views/headmin/views/devise/passwords/_new.html.erb +1 -1
  27. data/app/views/headmin/views/devise/registrations/_edit.html.erb +4 -4
  28. data/app/views/headmin/views/devise/registrations/_new.html.erb +3 -3
  29. data/app/views/headmin/views/devise/shared/_links.html.erb +7 -7
  30. data/app/views/headmin/views/devise/unlocks/_new.html.erb +1 -1
  31. data/config/locales/activerecord/en.yml +9 -0
  32. data/config/locales/activerecord/nl.yml +9 -0
  33. data/config/locales/headmin/table/en.yml +5 -1
  34. data/config/locales/headmin/table/nl.yml +5 -1
  35. data/config/locales/headmin/views/en.yml +1 -1
  36. data/config/locales/headmin/views/nl.yml +14 -14
  37. data/dist/css/headmin.css +54 -13
  38. data/dist/js/headmin.js +45 -513
  39. data/docs/blocks-and-fields.md +54 -0
  40. data/docs/blocks.md +1 -54
  41. data/docs/devise.md +40 -2
  42. data/docs/fields.md +31 -9
  43. data/headmin.gemspec +1 -1
  44. data/lib/generators/headmin/blocks_generator.rb +4 -1
  45. data/lib/generators/headmin/devise_generator.rb +16 -0
  46. data/lib/generators/headmin/fields_generator.rb +5 -1
  47. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +31 -0
  48. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +31 -0
  49. data/lib/generators/templates/controllers/auth/passwords_controller.rb +35 -0
  50. data/lib/generators/templates/controllers/auth/registrations_controller.rb +63 -0
  51. data/lib/generators/templates/controllers/auth/sessions_controller.rb +28 -0
  52. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +31 -0
  53. data/lib/generators/templates/migrations/create_field_hierarchies.rb +16 -0
  54. data/lib/generators/templates/views/auth/confirmations/new.html.erb +1 -0
  55. data/lib/generators/templates/views/auth/mailer/confirmation_instructions.html.erb +1 -0
  56. data/lib/generators/templates/views/auth/mailer/email_changed.html.erb +1 -0
  57. data/lib/generators/templates/views/auth/mailer/password_change.html.erb +1 -0
  58. data/lib/generators/templates/views/auth/mailer/reset_password_instructions.html.erb +1 -0
  59. data/lib/generators/templates/views/auth/mailer/unlock_instructions.html.erb +1 -0
  60. data/lib/generators/templates/views/auth/passwords/edit.html.erb +1 -0
  61. data/lib/generators/templates/views/auth/passwords/new.html.erb +1 -0
  62. data/lib/generators/templates/views/auth/registrations/edit.html.erb +1 -0
  63. data/lib/generators/templates/views/auth/registrations/new.html.erb +1 -0
  64. data/lib/generators/templates/views/auth/sessions/new.html.erb +1 -0
  65. data/lib/generators/templates/views/auth/unlocks/new.html.erb +1 -0
  66. data/lib/generators/templates/views/layouts/auth.html.erb +20 -0
  67. data/lib/headmin/engine.rb +2 -0
  68. data/lib/headmin/version.rb +1 -1
  69. data/package.json +4 -3
  70. data/src/js/headmin/controllers/blocks_controller.js +1 -1
  71. data/src/js/headmin/controllers/filter_controller.js +1 -1
  72. data/src/js/headmin/controllers/filters_controller.js +1 -1
  73. data/src/js/headmin/controllers/popup_controller.js +1 -1
  74. data/src/js/headmin/controllers/repeater_controller.js +9 -10
  75. data/src/js/headmin/controllers/table_actions_controller.js +104 -9
  76. data/src/js/headmin/controllers/table_controller.js +28 -57
  77. data/src/js/headmin/headmin.js +2 -2
  78. data/src/scss/headmin/table.scss +1 -0
  79. data/yarn.lock +1159 -1237
  80. metadata +33 -7
  81. data/docs/README.md +0 -5
@@ -1,4 +1,4 @@
1
- import {Controller} from "stimulus"
1
+ import {Controller} from "@hotwired/stimulus"
2
2
  import Sortable from "sortablejs";
3
3
  import {createPopper} from '@popperjs/core';
4
4
 
@@ -1,4 +1,4 @@
1
- import {Controller} from "stimulus"
1
+ import {Controller} from "@hotwired/stimulus"
2
2
  import Sortable from "sortablejs";
3
3
 
4
4
  export default class extends Controller {
@@ -38,7 +38,6 @@ export default class extends Controller {
38
38
  }
39
39
 
40
40
  updatePopupButtonIndices(index) {
41
- console.log(index)
42
41
  const popup = document.querySelector(`[data-popup-target="popup"][data-popup-id="repeater-buttons-${this.idValue}"]`)
43
42
  const buttons = popup.querySelectorAll('a')
44
43
  buttons.forEach((button) => {
@@ -53,8 +52,8 @@ export default class extends Controller {
53
52
  let rowIndex = button.dataset.rowIndex
54
53
 
55
54
  // Prepare html from template
56
- let html = this.getTemplateHTML(templateName)
57
- html = this.replaceIdsWithTimestamps(html)
55
+ const template = this.getTemplate(templateName)
56
+ const html = this.replaceIdsWithTimestamps(template)
58
57
 
59
58
  // Fallback to last row if no index is set
60
59
  if (rowIndex) {
@@ -93,16 +92,16 @@ export default class extends Controller {
93
92
  this.toggleEmpty()
94
93
  }
95
94
 
96
- getTemplateHTML(name) {
97
- const template = this.templateTargets.filter((template) => {
95
+ getTemplate(name) {
96
+ return this.templateTargets.filter((template) => {
98
97
  return template.dataset.templateName === name
99
98
  })[0]
100
- return template.innerHTML
101
99
  }
102
100
 
103
- replaceIdsWithTimestamps(html) {
104
- const regex = new RegExp('template_id', "g");
105
- return html.replace(regex, new Date().getTime())
101
+ replaceIdsWithTimestamps(template) {
102
+ console.log(template)
103
+ const regex = new RegExp(template.dataset.templateIdRegex, "g")
104
+ return template.innerHTML.replace(regex, new Date().getTime())
106
105
  }
107
106
 
108
107
  visibleRowsCount() {
@@ -1,33 +1,128 @@
1
- import {Controller} from "stimulus"
1
+ import {Controller} from "@hotwired/stimulus"
2
2
 
3
3
  export default class extends Controller {
4
+ static get values() {
5
+ return {
6
+ count: {type: Number, default: 0}
7
+ }
8
+ }
9
+
4
10
  static get targets() {
5
- return ["form", "select", "method", "button"]
11
+ return ["wrapper", "form", "select", "method", "button", "idInputTemplate", "id", "counter"]
6
12
  }
7
13
 
8
14
  connect() {
9
- this.wrapperClass = "table-actions"
15
+ this.wrapperTarget.addEventListener('idSelectionChanged', (event) => {
16
+ const ids = event.detail.ids
17
+ this.updateIdFields(ids)
18
+ this.updateCountValueWithIds(ids)
19
+ })
20
+
10
21
  }
11
22
 
12
23
  update(event) {
13
24
  event.preventDefault()
14
- const option = this.selectTarget.options[this.selectTarget.selectedIndex]
25
+ this.updateFormAction()
26
+ this.updateFormMethod()
27
+ this.updateButton()
28
+ }
29
+
30
+ updateIdFields(ids) {
31
+ this.removeIds()
32
+ if (ids instanceof Array) {
33
+ this.countValue = ids.length
34
+ ids.forEach((id) => {
35
+ this.addId(id)
36
+ })
37
+ } else {
38
+ this.countValue = Infinity
39
+ this.addId('')
40
+ }
41
+ }
15
42
 
16
- // Replace form action
43
+ updateCounter() {
44
+ let htmlString = ''
45
+ switch (this.countValue) {
46
+ case 0:
47
+ htmlString = this.counterTarget.getAttribute('data-items-zero')
48
+ break;
49
+ case 1:
50
+ htmlString = this.counterTarget.getAttribute('data-items-one')
51
+ break;
52
+ case Infinity:
53
+ htmlString = this.counterTarget.getAttribute('data-items-other')
54
+ htmlString = htmlString.replace(/<b>[\s\S]*?<\/b>/, '<b>' + this.totalCount() + '<\/b>');
55
+ break;
56
+ default:
57
+ htmlString = this.counterTarget.getAttribute('data-items-other')
58
+ let count = this.countValue === Infinity ? this.totalCount() : this.countValue
59
+ htmlString = htmlString.replace(/<b>[\s\S]*?<\/b>/, `<b>${count}<\/b>`);
60
+ }
61
+ this.counterTarget.innerHTML = htmlString;
62
+ }
63
+
64
+ totalCount() {
65
+ return this.counterTarget.getAttribute('data-total-count')
66
+ }
67
+
68
+ updateCountValueWithIds(ids) {
69
+ if (ids instanceof Array) {
70
+ this.countValue = ids.length
71
+ } else {
72
+ this.countValue = Infinity
73
+ }
74
+ }
75
+
76
+ countValueChanged() {
77
+ this.updateCounter()
78
+ this.toggle()
79
+ }
80
+
81
+ toggle() {
82
+ if (this.countValue > 0) {
83
+ this.wrapperTarget.classList.remove('d-none')
84
+ } else {
85
+ this.wrapperTarget.classList.add('d-none')
86
+ }
87
+ }
88
+
89
+ updateFormAction() {
17
90
  this.formTarget.action = this.selectTarget.value
91
+ }
18
92
 
19
- // Replace form method
93
+ updateFormMethod() {
94
+ const option = this.selectedOption()
20
95
  this.methodTarget.value = option.dataset.method
96
+ }
21
97
 
22
- // Set confirm on form button
98
+ updateButton() {
99
+ const option = this.selectedOption()
23
100
  const confirm = option.dataset.confirm
24
- if(confirm) {
101
+ if (confirm) {
25
102
  this.buttonTarget.dataset.confirm = confirm
26
103
  } else {
27
104
  this.buttonTarget.removeAttribute('data-confirm')
28
105
  }
106
+ this.enableButton()
107
+ }
108
+
109
+ selectedOption() {
110
+ return this.selectTarget.options[this.selectTarget.selectedIndex]
111
+ }
29
112
 
30
- // Enable button
113
+ enableButton() {
31
114
  this.buttonTarget.removeAttribute('disabled')
32
115
  }
116
+
117
+ addId(id) {
118
+ const template = this.idInputTemplateTarget
119
+ const input = template.innerHTML.replace(/ID/g, id)
120
+ this.formTarget.insertAdjacentHTML('afterbegin', input)
121
+ }
122
+
123
+ removeIds() {
124
+ this.idTargets.forEach((input) => {
125
+ this.formTarget.removeChild(input)
126
+ });
127
+ }
33
128
  }
@@ -1,4 +1,4 @@
1
- import {Controller} from "stimulus"
1
+ import {Controller} from "@hotwired/stimulus"
2
2
  import Sortable from "sortablejs";
3
3
  import Rails from "@rails/ujs";
4
4
 
@@ -38,25 +38,43 @@ export default class extends Controller {
38
38
  const checkbox = event.target
39
39
  this.toggleIdsCheckboxes(checkbox.checked)
40
40
  this.toggleIdCheckboxes(checkbox.checked)
41
- this.syncFields()
42
- this.toggleActions()
41
+ this.updateActions()
43
42
  }
44
43
 
45
44
  toggleId(event) {
46
45
  this.toggleIdsCheckboxes(false)
47
- this.syncFields()
48
- this.toggleActions()
46
+ this.updateActions()
49
47
  }
50
48
 
51
- toggleActions() {
52
- const idFields = this.getIdFields()
53
- if(idFields.length > 0) {
54
- this.actionsTarget.classList.remove('d-none')
49
+ updateActions() {
50
+ this.actionsTarget.dispatchEvent(
51
+ new CustomEvent(
52
+ 'idSelectionChanged',
53
+ {
54
+ detail: {
55
+ ids: this.ids()
56
+ }
57
+ }
58
+ )
59
+ )
60
+ }
61
+
62
+ ids() {
63
+ if (this.idsCheckboxTarget.checked) {
64
+ return null
55
65
  } else {
56
- this.actionsTarget.classList.add('d-none')
66
+ return this.selectedIdCheckboxes().map((checkbox) => {
67
+ return checkbox.value
68
+ })
57
69
  }
58
70
  }
59
71
 
72
+ selectedIdCheckboxes() {
73
+ return this.idCheckboxTargets.filter((checkbox) => {
74
+ return checkbox.checked
75
+ })
76
+ }
77
+
60
78
  toggleIdsCheckboxes(checked) {
61
79
  this.idsCheckboxTargets.forEach((checkbox) => {
62
80
  checkbox.checked = checked
@@ -69,51 +87,4 @@ export default class extends Controller {
69
87
  });
70
88
  }
71
89
 
72
- syncFields() {
73
- this.removeIds()
74
- if(this.idsCheckboxTarget.checked) {
75
- this.addId('')
76
- } else {
77
- this.idCheckboxTargets.forEach((checkbox) => {
78
- if(checkbox.checked) {
79
- this.addId(checkbox.value)
80
- }
81
- });
82
- }
83
- }
84
-
85
- addId(id) {
86
- let field = this.getIdField(id)
87
- if (!field) {
88
- field = this.newIdField(id)
89
- this.actionsTarget.querySelector('form').insertAdjacentHTML('afterbegin', field)
90
- }
91
- }
92
-
93
- removeIds() {
94
- const fields = this.getIdFields()
95
- fields.forEach((field) => {
96
- this.actionsTarget.querySelector('form').removeChild(field)
97
- });
98
- }
99
-
100
- removeId(id) {
101
- const field = this.getIdField(id)
102
- if (field) {
103
- this.actionsTarget.querySelector('form').removeChild(field)
104
- }
105
- }
106
-
107
- newIdField(id) {
108
- const template = this.actionsTarget.querySelector('[data-table-target="idFieldTemplate"]')
109
- return template.innerHTML.replace(/ID/g, id)
110
- }
111
-
112
- getIdFields() {
113
- return this.actionsTarget.querySelectorAll(`input[name="ids[]"]`);
114
- }
115
-
116
- getIdField(id) {
117
- return this.actionsTarget.querySelector(`input[name="ids[]"][value="${id}"]`);
118
- }
119
90
  }
@@ -4,8 +4,8 @@ import flatpickr from "flatpickr";
4
4
  import bootstrap from "bootstrap/dist/js/bootstrap.bundle";
5
5
  import Rails from "@rails/ujs";
6
6
 
7
- import {Application} from "stimulus";
8
- import {definitionsFromContext} from "stimulus/webpack-helpers";
7
+ import {Application} from "@hotwired/stimulus"
8
+ import {definitionsFromContext} from "@hotwired/stimulus-webpack-helpers"
9
9
 
10
10
  export class Headmin {
11
11
  static start() {
@@ -4,6 +4,7 @@
4
4
  color: $table-color;
5
5
  letter-spacing: 0.05em;
6
6
  font-size: $font-size-base * 0.85;
7
+ position: relative;
7
8
  }
8
9
 
9
10
  a {