headmin 0.3.4 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +27 -0
  3. data/.gitignore +14 -0
  4. data/.lock-487e157d270f3062a98b7b2a012753708-1272821827 +0 -0
  5. data/.nvmrc +1 -0
  6. data/CHANGELOG.md +31 -0
  7. data/Gemfile +7 -4
  8. data/Gemfile.lock +191 -25
  9. data/README.md +7 -0
  10. data/Rakefile +1 -7
  11. data/app/assets/javascripts/headmin/config/i18n.js +9 -9
  12. data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +318 -0
  13. data/app/assets/javascripts/headmin/controllers/blocks_controller.js +74 -79
  14. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +24 -24
  15. data/app/assets/javascripts/headmin/controllers/dropzone_controller.js +23 -25
  16. data/app/assets/javascripts/headmin/controllers/file_preview_controller.js +237 -237
  17. data/app/assets/javascripts/headmin/controllers/filter_controller.js +44 -44
  18. data/app/assets/javascripts/headmin/controllers/filters_controller.js +57 -61
  19. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +29 -29
  20. data/app/assets/javascripts/headmin/controllers/hello_controller.js +3 -3
  21. data/app/assets/javascripts/headmin/controllers/notification_controller.js +7 -6
  22. data/app/assets/javascripts/headmin/controllers/popup_controller.js +57 -51
  23. data/app/assets/javascripts/headmin/controllers/redactorx_controller.js +36 -9
  24. data/app/assets/javascripts/headmin/controllers/repeater_controller.js +122 -125
  25. data/app/assets/javascripts/headmin/controllers/select_controller.js +40 -39
  26. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +100 -101
  27. data/app/assets/javascripts/headmin/controllers/table_controller.js +115 -115
  28. data/app/assets/javascripts/headmin/index.js +38 -35
  29. data/app/assets/javascripts/headmin.js +295 -37
  30. data/app/assets/stylesheets/headmin/forms/autocomplete.scss +21 -0
  31. data/app/assets/stylesheets/headmin/forms/file.scss +46 -0
  32. data/app/assets/stylesheets/headmin/forms/repeater.scss +62 -0
  33. data/app/assets/stylesheets/headmin/forms/search.scss +12 -0
  34. data/app/assets/stylesheets/headmin/forms.scss +11 -0
  35. data/app/assets/stylesheets/headmin/general.scss +14 -0
  36. data/app/assets/stylesheets/headmin/overrides/bootstrap.scss +5 -3
  37. data/app/assets/stylesheets/headmin/overrides/redactorx.scss +74 -0
  38. data/app/assets/stylesheets/headmin/popup.scss +1 -0
  39. data/app/assets/stylesheets/headmin/syntax.scss +36 -349
  40. data/app/assets/stylesheets/headmin/table.scss +1 -1
  41. data/app/assets/stylesheets/headmin/utilities/buttons.scss +19 -0
  42. data/app/assets/stylesheets/headmin/utilities/dropzone.scss +72 -0
  43. data/app/assets/stylesheets/headmin/utilities.scss +2 -68
  44. data/app/assets/stylesheets/headmin.css +209 -205
  45. data/app/assets/stylesheets/headmin.scss +1 -1
  46. data/app/helpers/headmin/admin_helper.rb +0 -1
  47. data/app/helpers/headmin/form_helper.rb +2 -8
  48. data/app/models/concerns/headmin/blockable.rb +1 -1
  49. data/app/models/concerns/headmin/field.rb +4 -1
  50. data/app/models/concerns/headmin/fieldable.rb +138 -44
  51. data/app/models/concerns/headmin/form/autocompletable.rb +38 -0
  52. data/app/models/concerns/headmin/form/hintable.rb +19 -0
  53. data/app/models/concerns/headmin/form/input_groupable.rb +23 -0
  54. data/app/models/concerns/headmin/form/labelable.rb +33 -0
  55. data/app/models/concerns/headmin/form/listable.rb +28 -0
  56. data/app/models/concerns/headmin/form/placeholderable.rb +13 -0
  57. data/app/models/concerns/headmin/form/validatable.rb +40 -0
  58. data/app/models/concerns/headmin/form/wrappable.rb +21 -0
  59. data/app/models/headmin/.DS_Store +0 -0
  60. data/app/models/headmin/blocks_view.rb +15 -0
  61. data/app/models/headmin/form/blocks_view.rb +29 -0
  62. data/app/models/headmin/form/checkbox_view.rb +52 -0
  63. data/app/models/headmin/form/date_range_view.rb +25 -0
  64. data/app/models/headmin/form/date_view.rb +45 -0
  65. data/app/models/headmin/form/email_view.rb +48 -0
  66. data/app/models/headmin/form/file_view.rb +116 -0
  67. data/app/models/headmin/form/flatpickr_range_view.rb +102 -0
  68. data/app/models/headmin/form/flatpickr_view.rb +37 -0
  69. data/app/models/headmin/form/hidden_view.rb +10 -0
  70. data/app/models/headmin/form/hint_view.rb +6 -0
  71. data/app/models/headmin/form/input_group_view.rb +19 -0
  72. data/app/models/headmin/form/label_view.rb +24 -0
  73. data/app/models/headmin/form/number_view.rb +49 -0
  74. data/app/models/headmin/form/password_view.rb +44 -0
  75. data/app/models/headmin/form/redactorx_view.rb +59 -0
  76. data/app/models/headmin/form/search_view.rb +48 -0
  77. data/app/models/headmin/form/select_view.rb +62 -0
  78. data/app/models/headmin/form/switch_view.rb +23 -0
  79. data/app/models/headmin/form/text_view.rb +48 -0
  80. data/app/models/headmin/form/textarea_view.rb +44 -0
  81. data/app/models/headmin/form/url_view.rb +48 -0
  82. data/app/models/headmin/form/wrapper_view.rb +19 -0
  83. data/app/models/headmin/form/wysiwyg_view.rb +17 -0
  84. data/app/models/headmin/{thumbnail.rb → thumbnail_view.rb} +6 -1
  85. data/app/models/view_model.rb +58 -0
  86. data/app/views/headmin/_blocks.html.erb +13 -9
  87. data/app/views/headmin/_heading.html.erb +7 -1
  88. data/app/views/headmin/_thumbnail.html.erb +1 -37
  89. data/app/views/headmin/forms/_autocomplete.html.erb +11 -0
  90. data/app/views/headmin/forms/_blocks.html.erb +16 -17
  91. data/app/views/headmin/forms/_checkbox.html.erb +24 -29
  92. data/app/views/headmin/forms/_datalist.html.erb +3 -0
  93. data/app/views/headmin/forms/_date.html.erb +24 -24
  94. data/app/views/headmin/forms/_date_range.html.erb +19 -21
  95. data/app/views/headmin/forms/_email.html.erb +27 -32
  96. data/app/views/headmin/forms/_errors.html.erb +2 -3
  97. data/app/views/headmin/forms/_file.html.erb +84 -181
  98. data/app/views/headmin/forms/_flatpickr.html.erb +19 -20
  99. data/app/views/headmin/forms/_flatpickr_range.html.erb +28 -37
  100. data/app/views/headmin/forms/_hidden.html.erb +9 -10
  101. data/app/views/headmin/forms/_hint.html.erb +16 -0
  102. data/app/views/headmin/forms/_input_group.html.erb +21 -0
  103. data/app/views/headmin/forms/_label.html.erb +5 -13
  104. data/app/views/headmin/forms/_number.html.erb +23 -35
  105. data/app/views/headmin/forms/_password.html.erb +21 -30
  106. data/app/views/headmin/forms/_redactorx.html.erb +21 -40
  107. data/app/views/headmin/forms/_repeater.html.erb +55 -60
  108. data/app/views/headmin/forms/_search.html.erb +43 -0
  109. data/app/views/headmin/forms/_select.html.erb +24 -49
  110. data/app/views/headmin/forms/_switch.html.erb +29 -0
  111. data/app/views/headmin/forms/_text.html.erb +42 -96
  112. data/app/views/headmin/forms/_textarea.html.erb +21 -32
  113. data/app/views/headmin/forms/_url.html.erb +26 -31
  114. data/app/views/headmin/forms/_validation.html.erb +10 -13
  115. data/app/views/headmin/forms/_wrapper.html.erb +9 -0
  116. data/app/views/headmin/forms/_wysiwyg.html.erb +28 -0
  117. data/app/views/headmin/forms/autocomplete/_item.html.erb +3 -0
  118. data/app/views/headmin/forms/autocomplete/_list.html.erb +3 -0
  119. data/app/views/headmin/forms/fields/_file.html.erb +1 -1
  120. data/app/views/headmin/forms/fields/_files.html.erb +17 -0
  121. data/app/views/headmin/forms/fields/_group.html.erb +9 -2
  122. data/app/views/headmin/forms/repeater/_row.html.erb +4 -4
  123. data/bin/console +0 -1
  124. data/config/locales/headmin/forms/en.yml +1 -12
  125. data/config/locales/headmin/forms/nl.yml +1 -12
  126. data/esbuild-css.js +18 -18
  127. data/esbuild-js.js +8 -8
  128. data/headmin.gemspec +1 -3
  129. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +0 -2
  130. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +0 -2
  131. data/lib/generators/templates/controllers/auth/passwords_controller.rb +0 -2
  132. data/lib/generators/templates/controllers/auth/registrations_controller.rb +0 -2
  133. data/lib/generators/templates/controllers/auth/sessions_controller.rb +0 -2
  134. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +0 -2
  135. data/lib/headmin/version.rb +1 -3
  136. data/lib/headmin.rb +0 -2
  137. data/package-lock.json +5359 -0
  138. data/package.json +12 -4
  139. data/view_model_benchmark.rb +74 -0
  140. data/yarn-error.log +17 -12
  141. data/yarn.lock +1575 -31
  142. metadata +64 -25
  143. data/app/assets/stylesheets/headmin/form.scss +0 -132
  144. data/app/assets/stylesheets/headmin/overrides/redactorx.css +0 -3
  145. data/app/helpers/headmin/documentation_helper.rb +0 -35
  146. data/app/models/headmin/documentation_renderer.rb +0 -32
  147. data/app/models/headmin/form/base.rb +0 -78
  148. data/app/models/headmin/form/text.rb +0 -51
  149. data/app/services/block_service.rb +0 -72
  150. data/app/views/headmin/_card.html.erb +0 -52
  151. data/app/views/headmin/forms/_actions.html.erb +0 -28
  152. data/app/views/headmin/forms/_base.html.erb +0 -114
  153. data/app/views/headmin/forms/_image.html.erb +0 -21
  154. data/app/views/headmin/forms/_video.html.erb +0 -21
  155. data/app/views/headmin/forms/actions/_destroy.html.erb +0 -13
  156. data/app/views/headmin/forms/actions/_save.html.erb +0 -12
  157. data/app/views/headmin/forms/actions/_view.html.erb +0 -15
  158. data/app/views/headmin/forms/fields/_image.html.erb +0 -17
  159. data/docs/blocks-and-fields.md +0 -54
  160. data/docs/blocks.md +0 -48
  161. data/docs/devise.md +0 -41
  162. 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);
@@ -15152,7 +15409,7 @@ var table_controller_default = class extends Controller {
15152
15409
  return ["table", "body", "actions", "idCheckbox", "idsCheckbox", "row"];
15153
15410
  }
15154
15411
  connect() {
15155
- new sortable_esm_default(this.bodyTarget, {
15412
+ sortable_esm_default.create(this.bodyTarget, {
15156
15413
  handle: ".table-drag-sort-handle",
15157
15414
  onEnd: (event) => {
15158
15415
  this.submitPositions();
@@ -15179,7 +15436,7 @@ var table_controller_default = class extends Controller {
15179
15436
  });
15180
15437
  }
15181
15438
  idsFormData() {
15182
- let formData = new FormData();
15439
+ const formData = new FormData();
15183
15440
  this.positions().forEach((id) => {
15184
15441
  formData.append("ids[]", id);
15185
15442
  });
@@ -15247,8 +15504,9 @@ var table_controller_default = class extends Controller {
15247
15504
  var Headmin = class {
15248
15505
  static start() {
15249
15506
  window.Stimulus = window.Stimulus || Application.start();
15507
+ Stimulus.register("autocomplete", autocomplete_controller_default);
15250
15508
  Stimulus.register("blocks", blocks_controller_default);
15251
- Stimulus.register("date_range", date_range_controller_default);
15509
+ Stimulus.register("date-range", date_range_controller_default);
15252
15510
  Stimulus.register("dropzone", dropzone_controller_default);
15253
15511
  Stimulus.register("file-preview", file_preview_controller_default);
15254
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";
@@ -1,3 +1,17 @@
1
1
  html {
2
2
  height: 100%;
3
+ background: red;
4
+ }
5
+
6
+ .list-group-item {
7
+ &.active {
8
+ .text-muted {
9
+ color: $list-group-active-color !important;
10
+ }
11
+ }
12
+ }
13
+
14
+ mark {
15
+ padding: 0;
16
+ box-shadow: 0 $mark-padding 0 $mark-bg, 0 (-$mark-padding) 0 $mark-bg;
3
17
  }