headmin 0.3.3 → 0.4.1

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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +27 -0
  3. data/.gitignore +14 -0
  4. data/.nvmrc +1 -0
  5. data/CHANGELOG.md +24 -0
  6. data/Gemfile +7 -4
  7. data/Gemfile.lock +171 -3
  8. data/README.md +9 -1
  9. data/Rakefile +1 -7
  10. data/app/assets/javascripts/headmin/config/i18n.js +9 -9
  11. data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +318 -0
  12. data/app/assets/javascripts/headmin/controllers/blocks_controller.js +74 -79
  13. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +24 -24
  14. data/app/assets/javascripts/headmin/controllers/dropzone_controller.js +23 -25
  15. data/app/assets/javascripts/headmin/controllers/file_preview_controller.js +237 -237
  16. data/app/assets/javascripts/headmin/controllers/filter_controller.js +44 -44
  17. data/app/assets/javascripts/headmin/controllers/filters_controller.js +57 -61
  18. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +29 -29
  19. data/app/assets/javascripts/headmin/controllers/hello_controller.js +3 -3
  20. data/app/assets/javascripts/headmin/controllers/notification_controller.js +7 -6
  21. data/app/assets/javascripts/headmin/controllers/popup_controller.js +57 -51
  22. data/app/assets/javascripts/headmin/controllers/redactorx_controller.js +36 -9
  23. data/app/assets/javascripts/headmin/controllers/repeater_controller.js +122 -125
  24. data/app/assets/javascripts/headmin/controllers/select_controller.js +40 -39
  25. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +88 -77
  26. data/app/assets/javascripts/headmin/controllers/table_controller.js +115 -116
  27. data/app/assets/javascripts/headmin/index.js +38 -35
  28. data/app/assets/javascripts/headmin.js +309 -42
  29. data/app/assets/stylesheets/headmin/forms/autocomplete.scss +21 -0
  30. data/app/assets/stylesheets/headmin/forms/file.scss +46 -0
  31. data/app/assets/stylesheets/headmin/forms/repeater.scss +62 -0
  32. data/app/assets/stylesheets/headmin/forms/search.scss +12 -0
  33. data/app/assets/stylesheets/headmin/forms.scss +11 -0
  34. data/app/assets/stylesheets/headmin/general.scss +14 -0
  35. data/app/assets/stylesheets/headmin/overrides/bootstrap.scss +5 -3
  36. data/app/assets/stylesheets/headmin/overrides/redactorx.scss +74 -0
  37. data/app/assets/stylesheets/headmin/popup.scss +1 -0
  38. data/app/assets/stylesheets/headmin/syntax.scss +36 -349
  39. data/app/assets/stylesheets/headmin/table.scss +1 -1
  40. data/app/assets/stylesheets/headmin/utilities/buttons.scss +19 -0
  41. data/app/assets/stylesheets/headmin/utilities/dropzone.scss +72 -0
  42. data/app/assets/stylesheets/headmin/utilities.scss +2 -68
  43. data/app/assets/stylesheets/headmin.css +209 -205
  44. data/app/assets/stylesheets/headmin.scss +1 -1
  45. data/app/helpers/headmin/admin_helper.rb +0 -1
  46. data/app/helpers/headmin/form_helper.rb +2 -8
  47. data/app/models/concerns/headmin/blockable.rb +1 -1
  48. data/app/models/concerns/headmin/field.rb +1 -0
  49. data/app/models/concerns/headmin/form/autocompletable.rb +38 -0
  50. data/app/models/concerns/headmin/form/hintable.rb +19 -0
  51. data/app/models/concerns/headmin/form/input_groupable.rb +23 -0
  52. data/app/models/concerns/headmin/form/labelable.rb +33 -0
  53. data/app/models/concerns/headmin/form/listable.rb +28 -0
  54. data/app/models/concerns/headmin/form/placeholderable.rb +13 -0
  55. data/app/models/concerns/headmin/form/validatable.rb +40 -0
  56. data/app/models/concerns/headmin/form/wrappable.rb +21 -0
  57. data/app/models/headmin/.DS_Store +0 -0
  58. data/app/models/headmin/blocks_view.rb +15 -0
  59. data/app/models/headmin/form/blocks_view.rb +29 -0
  60. data/app/models/headmin/form/checkbox_view.rb +52 -0
  61. data/app/models/headmin/form/date_range_view.rb +25 -0
  62. data/app/models/headmin/form/date_view.rb +45 -0
  63. data/app/models/headmin/form/email_view.rb +48 -0
  64. data/app/models/headmin/form/file_view.rb +116 -0
  65. data/app/models/headmin/form/flatpickr_range_view.rb +102 -0
  66. data/app/models/headmin/form/flatpickr_view.rb +37 -0
  67. data/app/models/headmin/form/hidden_view.rb +10 -0
  68. data/app/models/headmin/form/hint_view.rb +6 -0
  69. data/app/models/headmin/form/input_group_view.rb +19 -0
  70. data/app/models/headmin/form/label_view.rb +24 -0
  71. data/app/models/headmin/form/number_view.rb +49 -0
  72. data/app/models/headmin/form/password_view.rb +44 -0
  73. data/app/models/headmin/form/redactorx_view.rb +59 -0
  74. data/app/models/headmin/form/search_view.rb +48 -0
  75. data/app/models/headmin/form/select_view.rb +62 -0
  76. data/app/models/headmin/form/switch_view.rb +23 -0
  77. data/app/models/headmin/form/text_view.rb +48 -0
  78. data/app/models/headmin/form/textarea_view.rb +44 -0
  79. data/app/models/headmin/form/url_view.rb +48 -0
  80. data/app/models/headmin/form/wrapper_view.rb +19 -0
  81. data/app/models/headmin/form/wysiwyg_view.rb +17 -0
  82. data/app/models/headmin/{thumbnail.rb → thumbnail_view.rb} +6 -1
  83. data/app/models/view_model.rb +58 -0
  84. data/app/views/headmin/_blocks.html.erb +13 -9
  85. data/app/views/headmin/_heading.html.erb +7 -1
  86. data/app/views/headmin/_thumbnail.html.erb +1 -37
  87. data/app/views/headmin/forms/_autocomplete.html.erb +11 -0
  88. data/app/views/headmin/forms/_blocks.html.erb +16 -17
  89. data/app/views/headmin/forms/_checkbox.html.erb +24 -29
  90. data/app/views/headmin/forms/_datalist.html.erb +3 -0
  91. data/app/views/headmin/forms/_date.html.erb +24 -24
  92. data/app/views/headmin/forms/_date_range.html.erb +19 -21
  93. data/app/views/headmin/forms/_email.html.erb +27 -32
  94. data/app/views/headmin/forms/_errors.html.erb +2 -3
  95. data/app/views/headmin/forms/_file.html.erb +84 -181
  96. data/app/views/headmin/forms/_flatpickr.html.erb +19 -20
  97. data/app/views/headmin/forms/_flatpickr_range.html.erb +28 -37
  98. data/app/views/headmin/forms/_hidden.html.erb +9 -10
  99. data/app/views/headmin/forms/_hint.html.erb +16 -0
  100. data/app/views/headmin/forms/_input_group.html.erb +21 -0
  101. data/app/views/headmin/forms/_label.html.erb +5 -13
  102. data/app/views/headmin/forms/_number.html.erb +23 -35
  103. data/app/views/headmin/forms/_password.html.erb +21 -30
  104. data/app/views/headmin/forms/_redactorx.html.erb +21 -40
  105. data/app/views/headmin/forms/_repeater.html.erb +55 -60
  106. data/app/views/headmin/forms/_search.html.erb +43 -0
  107. data/app/views/headmin/forms/_select.html.erb +24 -49
  108. data/app/views/headmin/forms/_switch.html.erb +29 -0
  109. data/app/views/headmin/forms/_text.html.erb +42 -96
  110. data/app/views/headmin/forms/_textarea.html.erb +21 -32
  111. data/app/views/headmin/forms/_url.html.erb +26 -31
  112. data/app/views/headmin/forms/_validation.html.erb +10 -13
  113. data/app/views/headmin/forms/_wrapper.html.erb +9 -0
  114. data/app/views/headmin/forms/_wysiwyg.html.erb +28 -0
  115. data/app/views/headmin/forms/autocomplete/_item.html.erb +3 -0
  116. data/app/views/headmin/forms/autocomplete/_list.html.erb +3 -0
  117. data/app/views/headmin/forms/fields/_group.html.erb +9 -2
  118. data/app/views/headmin/forms/repeater/_row.html.erb +4 -4
  119. data/app/views/headmin/table/_actions.html.erb +1 -1
  120. data/app/views/headmin/table/actions/_action.html.erb +2 -1
  121. data/app/views/headmin/table/actions/_delete.html.erb +1 -1
  122. data/bin/console +0 -1
  123. data/config/locales/headmin/forms/en.yml +1 -12
  124. data/config/locales/headmin/forms/nl.yml +1 -12
  125. data/esbuild-css.js +18 -18
  126. data/esbuild-js.js +8 -8
  127. data/headmin.gemspec +1 -3
  128. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +0 -2
  129. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +0 -2
  130. data/lib/generators/templates/controllers/auth/passwords_controller.rb +0 -2
  131. data/lib/generators/templates/controllers/auth/registrations_controller.rb +0 -2
  132. data/lib/generators/templates/controllers/auth/sessions_controller.rb +0 -2
  133. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +0 -2
  134. data/lib/headmin/version.rb +1 -3
  135. data/lib/headmin.rb +0 -2
  136. data/package-lock.json +5359 -0
  137. data/package.json +13 -6
  138. data/view_model_benchmark.rb +74 -0
  139. data/yarn-error.log +367 -0
  140. data/yarn.lock +1575 -31
  141. metadata +63 -24
  142. data/app/assets/stylesheets/headmin/form.scss +0 -132
  143. data/app/assets/stylesheets/headmin/overrides/redactorx.css +0 -3
  144. data/app/helpers/headmin/documentation_helper.rb +0 -35
  145. data/app/models/headmin/documentation_renderer.rb +0 -32
  146. data/app/models/headmin/form/base.rb +0 -78
  147. data/app/models/headmin/form/text.rb +0 -51
  148. data/app/services/block_service.rb +0 -72
  149. data/app/views/headmin/_card.html.erb +0 -52
  150. data/app/views/headmin/forms/_actions.html.erb +0 -28
  151. data/app/views/headmin/forms/_base.html.erb +0 -114
  152. data/app/views/headmin/forms/_image.html.erb +0 -21
  153. data/app/views/headmin/forms/_video.html.erb +0 -21
  154. data/app/views/headmin/forms/actions/_destroy.html.erb +0 -13
  155. data/app/views/headmin/forms/actions/_save.html.erb +0 -12
  156. data/app/views/headmin/forms/actions/_view.html.erb +0 -15
  157. data/docs/blocks-and-fields.md +0 -54
  158. data/docs/blocks.md +0 -48
  159. data/docs/devise.md +0 -41
  160. data/docs/fields.md +0 -79
@@ -4962,6 +4962,248 @@ Controller.blessings = [ClassPropertiesBlessing, TargetPropertiesBlessing, Value
4962
4962
  Controller.targets = [];
4963
4963
  Controller.values = {};
4964
4964
 
4965
+ // app/assets/javascripts/headmin/controllers/autocomplete_controller.js
4966
+ var autocomplete_controller_default = class extends Controller {
4967
+ static get targets() {
4968
+ return ["input", "dropdown", "dropdownItem"];
4969
+ }
4970
+ static get values() {
4971
+ return {
4972
+ url: String
4973
+ };
4974
+ }
4975
+ connect() {
4976
+ this.inputTarget.addEventListener("focus", (event) => {
4977
+ this.show();
4978
+ });
4979
+ this.inputTarget.addEventListener("keydown", (event) => {
4980
+ this.handleKeydown(event);
4981
+ });
4982
+ this.inputTarget.addEventListener("keyup", (event) => {
4983
+ this.handleKeyup(event);
4984
+ });
4985
+ document.addEventListener("click", (event) => {
4986
+ this.handleOutsideClick(event);
4987
+ });
4988
+ }
4989
+ handleKeydown(event) {
4990
+ const keyCode = parseInt(event.keyCode, 10);
4991
+ if (this.isArrowKey(keyCode)) {
4992
+ this.handleArrowKey(keyCode);
4993
+ }
4994
+ if (this.isEnterKey(keyCode)) {
4995
+ this.selectActiveItem(event);
4996
+ }
4997
+ }
4998
+ handleKeyup(event) {
4999
+ const keyCode = parseInt(event.keyCode, 10);
5000
+ if (this.isArrowKey(keyCode) || this.isEnterKey(keyCode)) {
5001
+ return false;
5002
+ }
5003
+ this.handleTextKey();
5004
+ }
5005
+ selectActiveItem(event) {
5006
+ const activeItem = this.activeItem();
5007
+ if (activeItem) {
5008
+ this.deselectAll();
5009
+ this.setValue(activeItem.getAttribute("value"));
5010
+ event.preventDefault();
5011
+ }
5012
+ }
5013
+ isEnterKey(keyCode) {
5014
+ return keyCode === 13;
5015
+ }
5016
+ handleArrowKey(keyCode) {
5017
+ this.show();
5018
+ switch (keyCode) {
5019
+ case 38:
5020
+ this.handleArrowUp();
5021
+ break;
5022
+ case 40:
5023
+ this.handleArrowDown();
5024
+ break;
5025
+ default:
5026
+ }
5027
+ }
5028
+ handleArrowUp() {
5029
+ this.selectPreviousItem();
5030
+ }
5031
+ handleArrowDown() {
5032
+ this.selectNextItem();
5033
+ }
5034
+ selectNextItem() {
5035
+ const next = this.nextItem();
5036
+ if (next) {
5037
+ this.deselectAll();
5038
+ next.classList.add("active");
5039
+ }
5040
+ }
5041
+ nextItem() {
5042
+ const current = this.activeItem();
5043
+ if (!this.hasSelectedItem()) {
5044
+ return this.firstItem();
5045
+ }
5046
+ if (this.isItemLast(current)) {
5047
+ return this.firstItem();
5048
+ } else {
5049
+ const index2 = this.itemIndex(current);
5050
+ return this.itemAtIndex(index2 + 1);
5051
+ }
5052
+ }
5053
+ selectPreviousItem() {
5054
+ const previous = this.previousItem();
5055
+ if (previous) {
5056
+ this.deselectAll();
5057
+ previous.classList.add("active");
5058
+ }
5059
+ }
5060
+ previousItem() {
5061
+ const current = this.activeItem();
5062
+ if (!this.hasSelectedItem()) {
5063
+ return this.lastItem();
5064
+ }
5065
+ if (this.isItemFirst(current)) {
5066
+ return this.lastItem();
5067
+ } else {
5068
+ const index2 = this.itemIndex(current);
5069
+ return this.itemAtIndex(index2 - 1);
5070
+ }
5071
+ }
5072
+ deselectAll() {
5073
+ this.dropdownItemTargets.forEach((dropdownItem) => {
5074
+ dropdownItem.classList.remove("active");
5075
+ });
5076
+ }
5077
+ itemAtIndex(index2) {
5078
+ return this.dropdownItemTargets[index2];
5079
+ }
5080
+ firstItem() {
5081
+ return this.itemAtIndex(0);
5082
+ }
5083
+ lastItem() {
5084
+ return this.itemAtIndex(this.dropdownItemTargets.length - 1);
5085
+ }
5086
+ hasSelectedItem() {
5087
+ return this.activeItem() !== void 0;
5088
+ }
5089
+ activeItem() {
5090
+ return this.dropdownItemTargets.find((item) => {
5091
+ return item.classList.contains("active");
5092
+ });
5093
+ }
5094
+ isItemLast(item) {
5095
+ return this.itemIndex(item) === this.dropdownItemTargets.length - 1;
5096
+ }
5097
+ isItemFirst(item) {
5098
+ return this.itemIndex(item) === 0;
5099
+ }
5100
+ itemIndex(item) {
5101
+ return Array.from(this.dropdownItemTargets).indexOf(item);
5102
+ }
5103
+ handleTextKey() {
5104
+ this.fetchCollection().then((html) => {
5105
+ this.renderCollection(html);
5106
+ }).then(() => {
5107
+ this.highlight();
5108
+ }).then(() => {
5109
+ this.activateFirstItem();
5110
+ }).then(() => {
5111
+ this.show();
5112
+ });
5113
+ }
5114
+ activateFirstItem() {
5115
+ this.deselectAll();
5116
+ this.firstItem().classList.add("active");
5117
+ }
5118
+ show() {
5119
+ if (this.isDropdownEmpty()) {
5120
+ this.dropdownTarget.classList.remove("d-none");
5121
+ } else {
5122
+ this.hide();
5123
+ }
5124
+ }
5125
+ hide() {
5126
+ this.dropdownTarget.classList.add("d-none");
5127
+ }
5128
+ isDropdownEmpty() {
5129
+ return this.dropdownTarget.textContent.trim().length > 0;
5130
+ }
5131
+ isArrowKey(keyCode) {
5132
+ const arrowKeyCodes = [37, 38, 39, 40];
5133
+ return arrowKeyCodes.includes(keyCode);
5134
+ }
5135
+ fetchCollection() {
5136
+ if (this.isRemote()) {
5137
+ return fetch(this.remoteURL()).then((response) => {
5138
+ return response.text();
5139
+ }).catch((error2) => {
5140
+ console.error("The URL you provided for the autocomplete collection didn't return a successful result", error2);
5141
+ });
5142
+ } else {
5143
+ return Promise.resolve(this.dropdownTarget.innerHTML);
5144
+ }
5145
+ }
5146
+ remoteURL() {
5147
+ const base = "https://example.com";
5148
+ const url = new URL(this.urlValue, base);
5149
+ const params = new URLSearchParams(url.search);
5150
+ params.set("search", this.value());
5151
+ params.set("page", "1");
5152
+ params.set("per_page", "6");
5153
+ url.search = params.toString();
5154
+ let urlString = url.toString();
5155
+ if (urlString.includes(base)) {
5156
+ urlString = urlString.replace(base, "");
5157
+ }
5158
+ return urlString;
5159
+ }
5160
+ renderCollection(html) {
5161
+ this.dropdownTarget.innerHTML = html;
5162
+ }
5163
+ isRemote() {
5164
+ return this.hasUrlValue;
5165
+ }
5166
+ highlight() {
5167
+ const query = this.value();
5168
+ this.dropdownItemTargets.forEach((dropdownItem) => {
5169
+ let text = dropdownItem.innerHTML;
5170
+ text = text.replace(/<mark.*?>(.*?)<\/mark>/ig, "$1");
5171
+ if (query && query.length > 0) {
5172
+ const regex2 = new RegExp(`(?<!<[^>]*?)(&nbsp;)?(${query})`, "gi");
5173
+ text = text.replace(regex2, "<mark>$2</mark>");
5174
+ }
5175
+ dropdownItem.innerHTML = text;
5176
+ });
5177
+ }
5178
+ select(event) {
5179
+ this.setValue(event.currentTarget.getAttribute("value"));
5180
+ }
5181
+ setValue(value) {
5182
+ this.inputTarget.value = value;
5183
+ this.inputTarget.dispatchEvent(new Event("change"));
5184
+ this.hide();
5185
+ }
5186
+ value() {
5187
+ return this.inputTarget.value;
5188
+ }
5189
+ numberOfCharacters() {
5190
+ return this.value().length;
5191
+ }
5192
+ handleOutsideClick(event) {
5193
+ if (!this.isClickedInside(event)) {
5194
+ this.hide();
5195
+ }
5196
+ }
5197
+ isClickedInside(event) {
5198
+ if (!event) {
5199
+ return false;
5200
+ }
5201
+ const inInput = this.inputTarget.contains(event.target);
5202
+ const inDropdown = this.dropdownTarget.contains(event.target);
5203
+ return inInput || inDropdown;
5204
+ }
5205
+ };
5206
+
4965
5207
  // node_modules/sortablejs/modular/sortable.esm.js
4966
5208
  function ownKeys(object, enumerableOnly) {
4967
5209
  var keys = Object.keys(object);
@@ -7142,7 +7384,7 @@ var blocks_controller_default = class extends Controller {
7142
7384
  return ["templateBlock", "block", "blocks", "templateEmpty", "button", "buttons"];
7143
7385
  }
7144
7386
  connect() {
7145
- new sortable_esm_default(this.blocksTarget, {
7387
+ sortable_esm_default.create(this.blocksTarget, {
7146
7388
  onEnd: () => {
7147
7389
  this.reorderPositions();
7148
7390
  }
@@ -7171,7 +7413,6 @@ var blocks_controller_default = class extends Controller {
7171
7413
  } else {
7172
7414
  this.blocksTarget.insertAdjacentHTML("afterbegin", html);
7173
7415
  }
7174
- this.blocksTarget.dispatchEvent(new CustomEvent("headmin:reinit", { bubbles: true }));
7175
7416
  this.reorderPositions();
7176
7417
  this.toggleEmpty();
7177
7418
  }
@@ -7190,8 +7431,7 @@ var blocks_controller_default = class extends Controller {
7190
7431
  }
7191
7432
  setPosition(html) {
7192
7433
  const position = this.retrieveLastPosition() + 1;
7193
- const regex = new RegExp("99999", "g");
7194
- return html.replace(regex, position);
7434
+ return html.replace(/99999/g, position);
7195
7435
  }
7196
7436
  retrieveLastPosition() {
7197
7437
  const blocks = Array.from(this.blockTargets);
@@ -7202,7 +7442,7 @@ var blocks_controller_default = class extends Controller {
7202
7442
  return parseInt(lastBlock.querySelector("[name*='position']").value);
7203
7443
  }
7204
7444
  reorderPositions() {
7205
- for (let [index2, block] of this.blockTargets.entries()) {
7445
+ for (const [index2, block] of this.blockTargets.entries()) {
7206
7446
  this.changePositionInfo(block, index2);
7207
7447
  }
7208
7448
  }
@@ -7248,21 +7488,20 @@ var dropzone_controller_default = class extends Controller {
7248
7488
  return ["input"];
7249
7489
  }
7250
7490
  connect() {
7251
- this.element.classList.add("h-dropzone");
7252
7491
  this.inputTarget.addEventListener("dragover", (event) => {
7253
- this.element.classList.add("dragover");
7492
+ this.element.classList.add("focus");
7254
7493
  });
7255
7494
  this.inputTarget.addEventListener("dragleave", (event) => {
7256
- this.element.classList.remove("dragover");
7495
+ this.element.classList.remove("focus");
7257
7496
  });
7258
7497
  this.inputTarget.addEventListener("drop", (event) => {
7259
- this.element.classList.remove("dragover");
7498
+ this.element.classList.remove("focus");
7260
7499
  });
7261
7500
  this.inputTarget.addEventListener("focusin", (event) => {
7262
- this.element.classList.add("active");
7501
+ this.element.classList.add("focus");
7263
7502
  });
7264
7503
  this.inputTarget.addEventListener("focusout", (event) => {
7265
- this.element.classList.remove("active");
7504
+ this.element.classList.remove("focus");
7266
7505
  });
7267
7506
  }
7268
7507
  };
@@ -7362,7 +7601,7 @@ var file_preview_controller_default = class extends Controller {
7362
7601
  addThumbnails() {
7363
7602
  const files = this.inputFiles();
7364
7603
  files.forEach((file) => {
7365
- let thumbnail = this.generateDummyThumbnail();
7604
+ const thumbnail = this.generateDummyThumbnail();
7366
7605
  this.appendThumbnail(thumbnail);
7367
7606
  this.updateThumbnail(this.lastThumbnail(), file);
7368
7607
  });
@@ -7407,7 +7646,7 @@ var file_preview_controller_default = class extends Controller {
7407
7646
  thumbnail.title = title;
7408
7647
  }
7409
7648
  updateThumbnailBackground(thumbnail, url) {
7410
- let thumbnailBackground = thumbnail.querySelector(".h-thumbnail-bg");
7649
+ const thumbnailBackground = thumbnail.querySelector(".h-thumbnail-bg");
7411
7650
  thumbnailBackground.style.backgroundImage = `url('${url}')`;
7412
7651
  }
7413
7652
  removeThumbnailIcon(thumbnail) {
@@ -7430,9 +7669,9 @@ var file_preview_controller_default = class extends Controller {
7430
7669
  zip: ["application/zip application/x-7z-compressed", "application/x-bzip application/x-bzip2 application/gzip application/vnd.rar"],
7431
7670
  pdf: ["application/pdf"]
7432
7671
  };
7433
- const icon_name = Object.keys(typeMap).find((key) => typeMap[key].includes(mimeType));
7434
- const full_icon_name = ["bi", "file", "earmark", icon_name].filter((e) => typeof e === "string" && e !== "").join("-");
7435
- return `<i class="bi ${full_icon_name} h-thumbnail-icon"></i>`;
7672
+ const iconName = Object.keys(typeMap).find((key) => typeMap[key].includes(mimeType));
7673
+ const fullIconName = ["bi", "file", "earmark", iconName].filter((e) => typeof e === "string" && e !== "").join("-");
7674
+ return `<i class="bi ${fullIconName} h-thumbnail-icon"></i>`;
7436
7675
  }
7437
7676
  isImage(file) {
7438
7677
  return file.type.match(/^image/) !== null;
@@ -7468,7 +7707,7 @@ var filter_controller_default = class extends Controller {
7468
7707
  return ["button", "popup"];
7469
7708
  }
7470
7709
  connect() {
7471
- this.element["controller"] = this;
7710
+ this.element.controller = this;
7472
7711
  document.addEventListener("click", (event) => {
7473
7712
  this.handleOutsideClick(event);
7474
7713
  });
@@ -7524,7 +7763,6 @@ var filters_controller_default = class extends Controller {
7524
7763
  let html = this.getTemplateHTML(name);
7525
7764
  html = this.replaceIdsWithTimestamps(html);
7526
7765
  this.listTarget.insertAdjacentHTML("beforeend", html);
7527
- this.menuItemTarget.dispatchEvent(new CustomEvent("headmin:reinit", { bubbles: true }));
7528
7766
  }
7529
7767
  remove(event) {
7530
7768
  const filter = event.currentTarget.closest(".h-filter");
@@ -7553,8 +7791,7 @@ var filters_controller_default = class extends Controller {
7553
7791
  return template.innerHTML;
7554
7792
  }
7555
7793
  replaceIdsWithTimestamps(html) {
7556
- const regex = new RegExp("template_id", "g");
7557
- return html.replace(regex, new Date().getTime());
7794
+ return html.replace(/template_id/g, new Date().getTime());
7558
7795
  }
7559
7796
  };
7560
7797
 
@@ -9746,7 +9983,7 @@ var flatpickr_controller_default = class extends Controller {
9746
9983
  esm_default(this.inputTarget, options);
9747
9984
  }
9748
9985
  options() {
9749
- return JSON.parse(this.inputTarget.getAttribute("data-flatpickr-options"));
9986
+ return JSON.parse(this.inputTarget.getAttribute("data-flatpickr"));
9750
9987
  }
9751
9988
  defaultOptions() {
9752
9989
  return {
@@ -14853,24 +15090,27 @@ var popup_controller_default = class extends Controller {
14853
15090
  }
14854
15091
  open(event) {
14855
15092
  const button = event.target.closest('[data-popup-target="button"]');
14856
- const popup = this.popupById(button.dataset["popupId"]);
14857
- const passThru = button.dataset["popupPassThru"];
15093
+ const popup = this.popupById(button.dataset.popupId);
15094
+ const passThru = button.dataset.popupPassThru;
15095
+ createPopper3(button, popup);
15096
+ this.openPopup(popup);
14858
15097
  if (passThru) {
14859
15098
  const passThruElement = popup.querySelector(passThru);
14860
15099
  passThruElement.click();
14861
- } else {
14862
- createPopper3(button, popup);
14863
- this.openPopup(popup);
15100
+ if (passThruElement instanceof HTMLInputElement) {
15101
+ passThruElement.focus();
15102
+ passThruElement.select();
15103
+ }
14864
15104
  }
14865
15105
  }
14866
15106
  close(event) {
14867
15107
  const button = event.target.closest('[data-popup-target="button"]');
14868
- const popup = this.popupById(button.dataset["popupId"]);
15108
+ const popup = this.popupById(button.dataset.popupId);
14869
15109
  this.closePopup(popup);
14870
15110
  }
14871
15111
  popupById(id) {
14872
15112
  return this.popupTargets.find((popup) => {
14873
- return popup.dataset["popupId"] === id;
15113
+ return popup.dataset.popupId === id;
14874
15114
  });
14875
15115
  }
14876
15116
  openPopup(popup) {
@@ -14884,12 +15124,30 @@ var popup_controller_default = class extends Controller {
14884
15124
  // app/assets/javascripts/headmin/controllers/redactorx_controller.js
14885
15125
  var redactorx_controller_default = class extends Controller {
14886
15126
  connect() {
14887
- if (typeof RedactorX == "undefined") {
15127
+ this.initRedactor();
15128
+ }
15129
+ initRedactor() {
15130
+ if (typeof RedactorX === "undefined") {
14888
15131
  console.error("RedactorX is a paid module and is not included in Headmin. Please purchase it and import it as a JS module");
14889
15132
  return false;
14890
15133
  }
15134
+ const defaultOptions = {
15135
+ editor: {
15136
+ minHeight: "57px"
15137
+ },
15138
+ subscribe: {
15139
+ "app.start": () => {
15140
+ this.stylize();
15141
+ }
15142
+ }
15143
+ };
14891
15144
  const options = JSON.parse(this.element.getAttribute("data-redactor-options"));
14892
- RedactorX(this.element, options);
15145
+ RedactorX(this.element, { ...defaultOptions, ...options });
15146
+ }
15147
+ stylize() {
15148
+ const container = this.element.nextElementSibling;
15149
+ const inputClasses = this.element.classList;
15150
+ container.classList.add(...inputClasses);
14893
15151
  }
14894
15152
  };
14895
15153
 
@@ -14904,7 +15162,7 @@ var repeater_controller_default = class extends Controller {
14904
15162
  return ["repeater", "footer", "template", "row", "list", "empty", "addButton"];
14905
15163
  }
14906
15164
  connect() {
14907
- new sortable_esm_default(this.listTarget, {
15165
+ sortable_esm_default.create(this.listTarget, {
14908
15166
  animation: 150,
14909
15167
  ghostClass: "list-group-item-dark",
14910
15168
  draggable: ".repeater-row",
@@ -14935,7 +15193,7 @@ var repeater_controller_default = class extends Controller {
14935
15193
  event.preventDefault();
14936
15194
  const button = event.target;
14937
15195
  const templateName = button.dataset.templateName;
14938
- let rowIndex = button.dataset.rowIndex;
15196
+ const rowIndex = button.dataset.rowIndex;
14939
15197
  const template = this.getTemplate(templateName);
14940
15198
  const html = this.replaceIdsWithTimestamps(template);
14941
15199
  if (rowIndex) {
@@ -14944,7 +15202,6 @@ var repeater_controller_default = class extends Controller {
14944
15202
  } else {
14945
15203
  this.footerTarget.insertAdjacentHTML("beforebegin", html);
14946
15204
  }
14947
- document.dispatchEvent(new CustomEvent("headmin:reinit", { bubbles: true }));
14948
15205
  this.resetIndices();
14949
15206
  this.resetPositions();
14950
15207
  this.toggleEmpty();
@@ -15036,7 +15293,7 @@ var select_controller_default = class extends Controller {
15036
15293
  return defaultOptions[locale];
15037
15294
  }
15038
15295
  hasTags() {
15039
- return this.element.dataset["tags"] === "true";
15296
+ return this.element.dataset.tags === "true";
15040
15297
  }
15041
15298
  initTomSelect() {
15042
15299
  const defaultOptions = this.defaultOptions(i18n_default.locale);
@@ -15061,7 +15318,8 @@ var table_actions_controller_default = class extends Controller {
15061
15318
  event.preventDefault();
15062
15319
  this.updateFormAction();
15063
15320
  this.updateFormMethod();
15064
- this.updateButton();
15321
+ this.updateFormDataAttributes();
15322
+ this.enableButton();
15065
15323
  }
15066
15324
  updateIdFields(ids) {
15067
15325
  this.removeIds();
@@ -15102,15 +15360,24 @@ var table_actions_controller_default = class extends Controller {
15102
15360
  const option2 = this.selectedOption();
15103
15361
  this.methodTarget.value = option2.dataset.method;
15104
15362
  }
15105
- updateButton() {
15363
+ updateFormDataAttributes() {
15106
15364
  const option2 = this.selectedOption();
15107
- const confirm = option2.dataset.confirm;
15365
+ this.updateFormDataConfirm(option2.dataset.turboConfirm);
15366
+ this.updateFormDataTurbo(option2.dataset.turbo);
15367
+ }
15368
+ updateFormDataConfirm(confirm) {
15108
15369
  if (confirm) {
15109
15370
  this.formTarget.dataset.turboConfirm = confirm;
15110
15371
  } else {
15111
15372
  this.formTarget.removeAttribute("data-turbo-confirm");
15112
15373
  }
15113
- this.enableButton();
15374
+ }
15375
+ updateFormDataTurbo(turbo) {
15376
+ if (turbo) {
15377
+ this.formTarget.dataset.turbo = turbo;
15378
+ } else {
15379
+ this.formTarget.removeAttribute("data-turbo");
15380
+ }
15114
15381
  }
15115
15382
  selectedOption() {
15116
15383
  return this.selectTarget.options[this.selectTarget.selectedIndex];
@@ -15142,7 +15409,7 @@ var table_controller_default = class extends Controller {
15142
15409
  return ["table", "body", "actions", "idCheckbox", "idsCheckbox", "row"];
15143
15410
  }
15144
15411
  connect() {
15145
- new sortable_esm_default(this.bodyTarget, {
15412
+ sortable_esm_default.create(this.bodyTarget, {
15146
15413
  handle: ".table-drag-sort-handle",
15147
15414
  onEnd: (event) => {
15148
15415
  this.submitPositions();
@@ -15169,8 +15436,7 @@ var table_controller_default = class extends Controller {
15169
15436
  });
15170
15437
  }
15171
15438
  idsFormData() {
15172
- let formData = new FormData();
15173
- console.log(this.positions());
15439
+ const formData = new FormData();
15174
15440
  this.positions().forEach((id) => {
15175
15441
  formData.append("ids[]", id);
15176
15442
  });
@@ -15238,8 +15504,9 @@ var table_controller_default = class extends Controller {
15238
15504
  var Headmin = class {
15239
15505
  static start() {
15240
15506
  window.Stimulus = window.Stimulus || Application.start();
15507
+ Stimulus.register("autocomplete", autocomplete_controller_default);
15241
15508
  Stimulus.register("blocks", blocks_controller_default);
15242
- Stimulus.register("date_range", date_range_controller_default);
15509
+ Stimulus.register("date-range", date_range_controller_default);
15243
15510
  Stimulus.register("dropzone", dropzone_controller_default);
15244
15511
  Stimulus.register("file-preview", file_preview_controller_default);
15245
15512
  Stimulus.register("filter", filter_controller_default);
@@ -0,0 +1,21 @@
1
+ .h-autocomplete {
2
+ position: absolute;
3
+ top: calc(100% + 2px);
4
+ left: 0;
5
+ z-index: $zindex-dropdown;
6
+ width: 100%;
7
+ @include reset-text();
8
+ @include font-size($dropdown-font-size);
9
+ word-wrap: break-word;
10
+ background-color: $dropdown-bg;
11
+ background-clip: padding-box;
12
+ border-radius: $dropdown-border-radius !important;
13
+ @include box-shadow($dropdown-box-shadow);
14
+ border: $dropdown-border-width solid $dropdown-border-color;
15
+ overflow: hidden;
16
+
17
+ .list-group-flush {
18
+ margin: 0;
19
+ padding: 0;
20
+ }
21
+ }
@@ -0,0 +1,46 @@
1
+ .h-form-file {
2
+ .h-form-file-thumbnails {
3
+ margin-bottom: map-get($spacers, 2);
4
+ }
5
+
6
+ &.h-dropzone {
7
+ padding: map-get($spacers, 2);
8
+
9
+ .h-form-file-thumbnails {
10
+ margin-bottom: 0;
11
+ }
12
+ }
13
+ }
14
+
15
+ .h-form-file-thumbnails {
16
+ position: relative;
17
+ display: flex;
18
+ flex-wrap: wrap;
19
+ gap: map-get($spacers, 2);
20
+ }
21
+
22
+ .h-form-file-thumbnail {
23
+ position: relative;
24
+ pointer-events: initial !important;
25
+ display: flex;
26
+ }
27
+
28
+ .h-form-file-thumbnail-remove {
29
+ position: absolute;
30
+ top: 0;
31
+ right: 0;
32
+ background: $danger;
33
+ width: 20px;
34
+ height: 20px;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ color: white;
39
+ border-radius: $border-radius;
40
+ z-index: 3;
41
+ cursor: pointer;
42
+
43
+ &:hover {
44
+ background: tint-color($danger, $btn-hover-bg-tint-amount)
45
+ }
46
+ }
@@ -0,0 +1,62 @@
1
+ .repeater {
2
+ position: relative;
3
+ }
4
+
5
+ .repeater-row {
6
+ position: relative;
7
+
8
+ &:hover {
9
+ .repeater-row-remove {
10
+ visibility: visible;
11
+ }
12
+
13
+ .repeater-row-add {
14
+ visibility: visible;
15
+ }
16
+
17
+ .repeater-row-handle {
18
+ visibility: visible;
19
+ }
20
+ }
21
+ }
22
+
23
+ .repeater-row-remove {
24
+ position: absolute;
25
+ top: calc(50% - 17px);
26
+ right: -22px;
27
+ z-index: 2;
28
+ visibility: hidden;
29
+
30
+ i.bi {
31
+ background: white;
32
+ border-radius: 50%;
33
+ }
34
+ }
35
+
36
+ .repeater-row-add {
37
+ position: absolute;
38
+ top: calc(100% - 18px);
39
+ right: calc(50% - 17px);
40
+ z-index: 2;
41
+ visibility: hidden;
42
+
43
+ i.bi {
44
+ background: white;
45
+ border-radius: 50%;
46
+ }
47
+ }
48
+
49
+ .repeater-row-handle {
50
+ position: absolute;
51
+ top: 0;
52
+ left: 0;
53
+ height: 100%;
54
+ width: 18px;
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ z-index: 2;
59
+ visibility: hidden;
60
+ cursor: move;
61
+ }
62
+
@@ -0,0 +1,12 @@
1
+ input[type="search"] {
2
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='%236c757d' viewBox='0 0 16 16'%3E%3Cpath d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E%0A");
3
+ background-repeat: no-repeat;
4
+ background-position: 10px center;
5
+ padding-left: 35px !important;
6
+ }
7
+
8
+ .form-floating {
9
+ input[type="search"] ~ label {
10
+ padding-left: 35px;
11
+ }
12
+ }
@@ -0,0 +1,11 @@
1
+ .form-label[required="required"], .form-check-label[required="required"] {
2
+ &:after {
3
+ content: ' *';
4
+ color: $danger;
5
+ }
6
+ }
7
+
8
+ @import "forms/autocomplete";
9
+ @import "forms/file";
10
+ @import "forms/repeater";
11
+ @import "forms/search";