activeadmin_addons 1.10.2 → 2.0.0.beta.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.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -17
  3. data/app/inputs/active_admin/inputs/select_input.rb +5 -1
  4. data/app/inputs/nested_level_input.rb +3 -2
  5. data/app/inputs/search_select_input.rb +2 -2
  6. data/app/inputs/selected_list_input.rb +2 -1
  7. data/app/inputs/tags_input.rb +1 -1
  8. data/app/javascript/activeadmin_addons/addons/slim-select-interactive-tag.js +78 -0
  9. data/app/javascript/activeadmin_addons/all.js +2 -7
  10. data/app/javascript/activeadmin_addons/config.js +8 -5
  11. data/app/javascript/activeadmin_addons/inputs/slim-select-nested.js +93 -0
  12. data/app/javascript/activeadmin_addons/inputs/slim-select-search.js +37 -0
  13. data/app/javascript/activeadmin_addons/inputs/slim-select-selected-list.js +103 -0
  14. data/app/javascript/activeadmin_addons/inputs/slim-select-simple-tags.js +22 -0
  15. data/app/javascript/activeadmin_addons/inputs/slim-select-tags.js +67 -0
  16. data/app/javascript/activeadmin_addons/inputs/slim-select-utils.js +70 -0
  17. data/app/javascript/activeadmin_addons/inputs/slim-select.js +75 -0
  18. data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/all.scss +5 -11
  19. data/app/javascript/activeadmin_addons/stylesheets/imports/slimselect.css +1 -0
  20. data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/selected-list.scss +0 -1
  21. data/app/javascript/activeadmin_addons/stylesheets/inputs/slim-select.scss +9 -0
  22. data/lib/activeadmin_addons/addons/image_builder.rb +2 -9
  23. data/lib/activeadmin_addons/addons/tag_builder.rb +3 -22
  24. data/lib/activeadmin_addons/engine.rb +0 -5
  25. data/lib/activeadmin_addons/support/input_helpers/select_helpers.rb +1 -1
  26. data/lib/activeadmin_addons/version.rb +1 -1
  27. data/lib/activeadmin_addons.rb +1 -1
  28. data/lib/generators/activeadmin_addons/install/install_generator.rb +2 -1
  29. data/lib/generators/activeadmin_addons/install/templates/initializer.rb +1 -1
  30. data/lib/generators/activeadmin_addons/webpacker/webpacker_generator.rb +1 -1
  31. metadata +49 -220
  32. data/app/assets/images/fileicons/file_extension_3gp.png +0 -0
  33. data/app/assets/images/fileicons/file_extension_7z.png +0 -0
  34. data/app/assets/images/fileicons/file_extension_ace.png +0 -0
  35. data/app/assets/images/fileicons/file_extension_ai.png +0 -0
  36. data/app/assets/images/fileicons/file_extension_aif.png +0 -0
  37. data/app/assets/images/fileicons/file_extension_aiff.png +0 -0
  38. data/app/assets/images/fileicons/file_extension_amr.png +0 -0
  39. data/app/assets/images/fileicons/file_extension_asf.png +0 -0
  40. data/app/assets/images/fileicons/file_extension_asx.png +0 -0
  41. data/app/assets/images/fileicons/file_extension_bat.png +0 -0
  42. data/app/assets/images/fileicons/file_extension_bin.png +0 -0
  43. data/app/assets/images/fileicons/file_extension_bmp.png +0 -0
  44. data/app/assets/images/fileicons/file_extension_bup.png +0 -0
  45. data/app/assets/images/fileicons/file_extension_cab.png +0 -0
  46. data/app/assets/images/fileicons/file_extension_cbr.png +0 -0
  47. data/app/assets/images/fileicons/file_extension_cda.png +0 -0
  48. data/app/assets/images/fileicons/file_extension_cdl.png +0 -0
  49. data/app/assets/images/fileicons/file_extension_cdr.png +0 -0
  50. data/app/assets/images/fileicons/file_extension_chm.png +0 -0
  51. data/app/assets/images/fileicons/file_extension_dat.png +0 -0
  52. data/app/assets/images/fileicons/file_extension_divx.png +0 -0
  53. data/app/assets/images/fileicons/file_extension_dll.png +0 -0
  54. data/app/assets/images/fileicons/file_extension_dmg.png +0 -0
  55. data/app/assets/images/fileicons/file_extension_doc.png +0 -0
  56. data/app/assets/images/fileicons/file_extension_docx.png +0 -0
  57. data/app/assets/images/fileicons/file_extension_dss.png +0 -0
  58. data/app/assets/images/fileicons/file_extension_dvf.png +0 -0
  59. data/app/assets/images/fileicons/file_extension_dwg.png +0 -0
  60. data/app/assets/images/fileicons/file_extension_eml.png +0 -0
  61. data/app/assets/images/fileicons/file_extension_eps.png +0 -0
  62. data/app/assets/images/fileicons/file_extension_exe.png +0 -0
  63. data/app/assets/images/fileicons/file_extension_fla.png +0 -0
  64. data/app/assets/images/fileicons/file_extension_flv.png +0 -0
  65. data/app/assets/images/fileicons/file_extension_gif.png +0 -0
  66. data/app/assets/images/fileicons/file_extension_gz.png +0 -0
  67. data/app/assets/images/fileicons/file_extension_hqx.png +0 -0
  68. data/app/assets/images/fileicons/file_extension_htm.png +0 -0
  69. data/app/assets/images/fileicons/file_extension_html.png +0 -0
  70. data/app/assets/images/fileicons/file_extension_ifo.png +0 -0
  71. data/app/assets/images/fileicons/file_extension_indd.png +0 -0
  72. data/app/assets/images/fileicons/file_extension_iso.png +0 -0
  73. data/app/assets/images/fileicons/file_extension_jar.png +0 -0
  74. data/app/assets/images/fileicons/file_extension_jpeg.png +0 -0
  75. data/app/assets/images/fileicons/file_extension_jpg.png +0 -0
  76. data/app/assets/images/fileicons/file_extension_lnk.png +0 -0
  77. data/app/assets/images/fileicons/file_extension_log.png +0 -0
  78. data/app/assets/images/fileicons/file_extension_m4a.png +0 -0
  79. data/app/assets/images/fileicons/file_extension_m4b.png +0 -0
  80. data/app/assets/images/fileicons/file_extension_m4p.png +0 -0
  81. data/app/assets/images/fileicons/file_extension_m4v.png +0 -0
  82. data/app/assets/images/fileicons/file_extension_mcd.png +0 -0
  83. data/app/assets/images/fileicons/file_extension_mdb.png +0 -0
  84. data/app/assets/images/fileicons/file_extension_mid.png +0 -0
  85. data/app/assets/images/fileicons/file_extension_mov.png +0 -0
  86. data/app/assets/images/fileicons/file_extension_mp2.png +0 -0
  87. data/app/assets/images/fileicons/file_extension_mp3.png +0 -0
  88. data/app/assets/images/fileicons/file_extension_mp4.png +0 -0
  89. data/app/assets/images/fileicons/file_extension_mpeg.png +0 -0
  90. data/app/assets/images/fileicons/file_extension_mpg.png +0 -0
  91. data/app/assets/images/fileicons/file_extension_msi.png +0 -0
  92. data/app/assets/images/fileicons/file_extension_mswmm.png +0 -0
  93. data/app/assets/images/fileicons/file_extension_ogg.png +0 -0
  94. data/app/assets/images/fileicons/file_extension_pdf.png +0 -0
  95. data/app/assets/images/fileicons/file_extension_png.png +0 -0
  96. data/app/assets/images/fileicons/file_extension_pps.png +0 -0
  97. data/app/assets/images/fileicons/file_extension_ppt.png +0 -0
  98. data/app/assets/images/fileicons/file_extension_pptx.png +0 -0
  99. data/app/assets/images/fileicons/file_extension_ps.png +0 -0
  100. data/app/assets/images/fileicons/file_extension_psd.png +0 -0
  101. data/app/assets/images/fileicons/file_extension_pst.png +0 -0
  102. data/app/assets/images/fileicons/file_extension_ptb.png +0 -0
  103. data/app/assets/images/fileicons/file_extension_pub.png +0 -0
  104. data/app/assets/images/fileicons/file_extension_qbb.png +0 -0
  105. data/app/assets/images/fileicons/file_extension_qbw.png +0 -0
  106. data/app/assets/images/fileicons/file_extension_qxd.png +0 -0
  107. data/app/assets/images/fileicons/file_extension_ram.png +0 -0
  108. data/app/assets/images/fileicons/file_extension_rar.png +0 -0
  109. data/app/assets/images/fileicons/file_extension_rm.png +0 -0
  110. data/app/assets/images/fileicons/file_extension_rmvb.png +0 -0
  111. data/app/assets/images/fileicons/file_extension_rtf.png +0 -0
  112. data/app/assets/images/fileicons/file_extension_sea.png +0 -0
  113. data/app/assets/images/fileicons/file_extension_ses.png +0 -0
  114. data/app/assets/images/fileicons/file_extension_sit.png +0 -0
  115. data/app/assets/images/fileicons/file_extension_sitx.png +0 -0
  116. data/app/assets/images/fileicons/file_extension_ss.png +0 -0
  117. data/app/assets/images/fileicons/file_extension_swf.png +0 -0
  118. data/app/assets/images/fileicons/file_extension_tgz.png +0 -0
  119. data/app/assets/images/fileicons/file_extension_thm.png +0 -0
  120. data/app/assets/images/fileicons/file_extension_tif.png +0 -0
  121. data/app/assets/images/fileicons/file_extension_tmp.png +0 -0
  122. data/app/assets/images/fileicons/file_extension_torrent.png +0 -0
  123. data/app/assets/images/fileicons/file_extension_ttf.png +0 -0
  124. data/app/assets/images/fileicons/file_extension_txt.png +0 -0
  125. data/app/assets/images/fileicons/file_extension_unknown.png +0 -0
  126. data/app/assets/images/fileicons/file_extension_vcd.png +0 -0
  127. data/app/assets/images/fileicons/file_extension_vob.png +0 -0
  128. data/app/assets/images/fileicons/file_extension_wav.png +0 -0
  129. data/app/assets/images/fileicons/file_extension_wma.png +0 -0
  130. data/app/assets/images/fileicons/file_extension_wmv.png +0 -0
  131. data/app/assets/images/fileicons/file_extension_wps.png +0 -0
  132. data/app/assets/images/fileicons/file_extension_xls.png +0 -0
  133. data/app/assets/images/fileicons/file_extension_xlsx.png +0 -0
  134. data/app/assets/images/fileicons/file_extension_xpi.png +0 -0
  135. data/app/assets/images/fileicons/file_extension_zip.png +0 -0
  136. data/app/assets/images/material/icons/keyboard_arrow_down.svg +0 -4
  137. data/app/assets/images/material/icons/keyboard_arrow_left.svg +0 -4
  138. data/app/assets/images/material/icons/keyboard_arrow_right.svg +0 -4
  139. data/app/assets/images/material/icons/keyboard_arrow_up.svg +0 -4
  140. data/app/assets/images/material/icons/today.svg +0 -4
  141. data/app/assets/javascripts/activeadmin_addons/all.js +0 -757
  142. data/app/assets/stylesheets/activeadmin_addons/addons/material-datepicker.scss +0 -173
  143. data/app/assets/stylesheets/activeadmin_addons/addons/material-toggle_bool.scss +0 -52
  144. data/app/assets/stylesheets/activeadmin_addons/inputs/select2.scss +0 -3
  145. data/app/assets/stylesheets/activeadmin_addons/material.scss +0 -53
  146. data/app/javascript/activeadmin_addons/addons/interactive_select_tag.js +0 -95
  147. data/app/javascript/activeadmin_addons/inputs/nested-select.js +0 -170
  148. data/app/javascript/activeadmin_addons/inputs/search-select.js +0 -76
  149. data/app/javascript/activeadmin_addons/inputs/select2.js +0 -52
  150. data/app/javascript/activeadmin_addons/inputs/selected-list.js +0 -111
  151. data/app/javascript/activeadmin_addons/inputs/tags.js +0 -76
  152. data/lib/activeadmin_addons/addons/attachment_builder.rb +0 -60
  153. data/lib/activeadmin_addons/support/enumerize_formtastic_support.rb +0 -18
  154. data/lib/generators/activeadmin_addons/assets/assets_generator.rb +0 -53
  155. data/vendor/assets/select2/select2.css +0 -481
  156. data/vendor/assets/select2/select2.full.js +0 -6820
  157. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/addons/interactive_select_tag.scss +0 -0
  158. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/addons/toggle_bool.scss +0 -0
  159. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/imports/jquery-datepicker.scss +0 -0
  160. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/color-picker.scss +0 -0
  161. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/date-time-picker-filter.scss +0 -0
  162. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/date-time-picker.scss +0 -0
  163. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/numeric-range-filter.scss +0 -0
  164. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/vendor/palette-color-picker.scss +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6fc13e5fdaeb949d49a7ec0a3330885ef1ec2e0b6b35179ea696b016eb9d0c9
4
- data.tar.gz: aeea860c39cd59ccb6a4c6c141a42a5b29d8bdc19e8679147175238ec2afa67e
3
+ metadata.gz: aed38304ff68795198eb34b4fb634a5f8e55143b4f159b04698d0852d32e36ef
4
+ data.tar.gz: 6c4637ae03b38a74d1d06831fea506de8d13a996002d1770a0d5d80372242906
5
5
  SHA512:
6
- metadata.gz: 2e336a0da29c1f1a2717a7a577d7c22c81afd02510e166a33d0dbaca003be506ce38d1d793916adfb4b1c56ba4d8353ca805e65fb32468fe2443f8fd789ee3da
7
- data.tar.gz: 29314fd56a40f6f5353dbf90072128f580c0aa99a2d44519355c51a89d82aa216adfba999d583f3496d49ab8a6727f00e7fc680f5cec56c4992cdda24505a461
6
+ metadata.gz: 5c955ceb1fedfefd561237ba63e433b0013be0debad0750b70932e82141ae41c323c970041317720caed90cdff1820bda25d667cf00c4110d63fe6ebfcfbc3a1
7
+ data.tar.gz: d9522cb0cab4b42be862e0451efbba5156a5b85cde8a8dfddd359b613c21638b216eff53b5a4e899e9b4b4d6fbae614dc238d0c72b4a35266350743e70214b6a
data/Rakefile CHANGED
@@ -18,29 +18,13 @@ task :prepare_assets do
18
18
  system "rm -rf spec/dummy/public/packs"
19
19
  system "rm -rf spec/dummy/public/packs-test"
20
20
  system "yarn install"
21
- system "yarn build"
22
21
  system "(cd spec/dummy && yarn install)"
23
22
  end
24
23
 
25
24
  task :tests do
26
25
  system "rspec ./spec/lib"
27
- end
28
-
29
- task :sprockets_tests do
30
- system "rake prepare_assets"
31
- system "export SPROCKETS=true; rspec ./spec/features"
32
- end
33
-
34
- task :webpack_tests do
35
- system "rake prepare_assets"
36
- system "export SPROCKETS=false; rspec ./spec/features"
37
- end
38
-
39
- task :all_tests do
40
26
  system "rake prepare_assets"
41
- system "rake tests"
42
- system "export SPROCKETS=true; rspec ./spec/features"
43
- system "export SPROCKETS=false; rspec ./spec/features"
27
+ system "rspec ./spec/features"
44
28
  end
45
29
 
46
30
  Bundler::GemHelper.install_tasks
@@ -1,6 +1,10 @@
1
1
  class ActiveAdmin::Inputs::SelectInput < Formtastic::Inputs::SelectInput
2
2
  def input_html_options
3
- super.merge(data: { tags: @options[:tags].present? })
3
+ if @options[:tags].present?
4
+ super.deep_merge(class: 'simple-tags-input')
5
+ else
6
+ super
7
+ end
4
8
  end
5
9
 
6
10
  def raw_collection
@@ -15,15 +15,16 @@ class NestedLevelInput < ActiveAdminAddons::InputBase
15
15
 
16
16
  def load_control_attributes
17
17
  load_class(@options[:class])
18
+ load_data_attr(:association, value: association_name)
18
19
  load_data_attr(:fields, default: ["name"], formatter: :to_json)
19
- load_data_attr(:predicate, default: "cont")
20
+ load_data_attr(:predicate, default: "contains")
20
21
  load_data_attr(:filters)
21
22
  load_data_attr(:model, value: model_name)
22
23
  load_data_attr(:display_name, default: "name")
23
24
  load_data_attr(:minimum_input_length, default: 1)
24
25
  load_data_attr(:url, default: url_from_method)
25
26
  load_data_attr(:response_root, default: tableize_method)
26
- load_data_attr(:width, default: "80%")
27
+ load_data_attr(:width)
27
28
  load_data_attr(:order,
28
29
  value: @options[:order_by],
29
30
  default: get_data_attr_value(:fields).first.to_s + "_desc")
@@ -14,12 +14,12 @@ class SearchSelectInput < ActiveAdminAddons::InputBase
14
14
  def load_control_attributes
15
15
  load_class(@options[:class])
16
16
  load_data_attr(:fields, default: ["name"], formatter: :to_json)
17
- load_data_attr(:predicate, default: "cont")
17
+ load_data_attr(:predicate, default: "contains")
18
18
  load_data_attr(:url, default: url_from_method)
19
19
  load_data_attr(:response_root, default: tableize_method)
20
20
  load_data_attr(:display_name, default: "name")
21
21
  load_data_attr(:minimum_input_length, default: 1)
22
- load_data_attr(:width, default: "80%")
22
+ load_data_attr(:width)
23
23
  load_data_attr(
24
24
  :order,
25
25
  value: @options[:order_by],
@@ -11,7 +11,7 @@ class SelectedListInput < ActiveAdminAddons::InputBase
11
11
  load_data_attr(:url, default: url_from_method)
12
12
  load_data_attr(:response_root, default: tableize_method)
13
13
  load_data_attr(:fields, default: ["name"], formatter: :to_json)
14
- load_data_attr(:predicate, default: "cont")
14
+ load_data_attr(:predicate, default: "contains")
15
15
  load_data_attr(:display_name, default: "name")
16
16
  load_data_attr(:minimum_input_length, default: 1)
17
17
  load_data_attr(:width, default: "100%")
@@ -26,6 +26,7 @@ class SelectedListInput < ActiveAdminAddons::InputBase
26
26
 
27
27
  def render_control_wrapper
28
28
  template.content_tag(:div, class: "selected-list-container") do
29
+ template.content_tag(label_html)
29
30
  template.concat(render_items_list)
30
31
  template.concat(builder.select(build_virtual_attr, [], {}, input_html_options))
31
32
  end
@@ -12,7 +12,7 @@ class TagsInput < ActiveAdminAddons::InputBase
12
12
  def load_control_attributes
13
13
  load_data_attr(:model, value: model_name)
14
14
  load_data_attr(:method, value: method)
15
- load_data_attr(:width, default: "80%")
15
+ load_data_attr(:width)
16
16
 
17
17
  if active_record_select?
18
18
  load_data_attr(:relation, value: true)
@@ -0,0 +1,78 @@
1
+ import SlimSelect from 'slim-select';
2
+
3
+ function updateTag(url, data) {
4
+ return fetch(url, {
5
+ method: 'PATCH',
6
+ headers: {
7
+ 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
8
+ 'Accept': 'application/json',
9
+ 'Content-Type': 'application/json',
10
+ },
11
+ body: JSON.stringify(data),
12
+ });
13
+ }
14
+
15
+ function setupSelect(el) {
16
+ if (el.slim) {
17
+ el.slim.destroy();
18
+ }
19
+
20
+ return new SlimSelect({
21
+ select: el,
22
+ events: {
23
+ // eslint-disable-next-line max-statements
24
+ afterClose: () => {
25
+ const containerEl = el.closest('.tag-select-container');
26
+ const selectContainer = containerEl.querySelector('.interactive-tag-select');
27
+ const tagContainer = containerEl.querySelector('.interactive-tag');
28
+ const model = tagContainer.dataset.model;
29
+ const objectId = tagContainer.dataset.objectId;
30
+ const field = tagContainer.dataset.field;
31
+
32
+ if (el.value === tagContainer.dataset.value) {
33
+ selectContainer.classList.add('select-container-hidden');
34
+ containerEl.querySelector('.interactive-tag').classList.remove('interactive-tag-hidden');
35
+ } else {
36
+ const data = { id: objectId };
37
+ data[model] = {};
38
+ data[model][field] = el.value;
39
+ updateTag(tagContainer.dataset.url, data)
40
+ .then(() => {
41
+ const statusTag = tagContainer.querySelector('.status_tag');
42
+ statusTag.innerText = el.selectedOptions[0].text;
43
+ statusTag.classList.remove(tagContainer.dataset.value);
44
+ statusTag.classList.add(el.value);
45
+ tagContainer.dataset.value = el.value;
46
+ selectContainer.dataset.value = el.value;
47
+ })
48
+ .catch(() => {
49
+ const errorMsg = 'Error: Update Unsuccessful';
50
+ console.log(errorMsg);
51
+ })
52
+ .finally(() => {
53
+ selectContainer.classList.add('select-container-hidden');
54
+ containerEl.querySelector('.interactive-tag').classList.remove('interactive-tag-hidden');
55
+ });
56
+ }
57
+ },
58
+ },
59
+ });
60
+ }
61
+
62
+ function setupInteractiveTag(containerEl) {
63
+ const selectContainer = containerEl.querySelector('.interactive-tag-select');
64
+ const slimSelect = setupSelect(selectContainer.querySelector('select'));
65
+ const tag = containerEl.querySelector('.interactive-tag');
66
+
67
+ tag.addEventListener('click', () => {
68
+ selectContainer.classList.remove('select-container-hidden');
69
+ tag.classList.add('interactive-tag-hidden');
70
+ window.setTimeout(() => {
71
+ slimSelect.open();
72
+ }, 0);
73
+ });
74
+ }
75
+
76
+ window.addEventListener('load', () => {
77
+ document.querySelectorAll('.tag-select-container').forEach(setupInteractiveTag);
78
+ });
@@ -1,14 +1,9 @@
1
- import 'select2';
2
1
  import 'jquery-datetimepicker';
3
2
  import './vendor/jquery_palette_color_picker/palette-color-picker';
4
3
 
5
4
  import './config';
6
- import './inputs/select2';
7
- import './inputs/search-select';
8
- import './inputs/nested-select';
9
- import './inputs/tags';
10
- import './inputs/selected-list';
5
+ import './inputs/slim-select';
11
6
  import './inputs/date-time-picker';
12
7
  import './inputs/color-picker';
13
8
  import './addons/toggle_bool';
14
- import './addons/interactive_select_tag';
9
+ import './addons/slim-select-interactive-tag';
@@ -1,10 +1,13 @@
1
- var initializer = function() {
1
+ const loadEvents = ['turbo:load', 'turbolinks:load', 'DOMContentLoaded'];
2
+
3
+ function initializer() {
2
4
  window.ActiveadminAddons = {
3
5
  config: {
4
- defaultSelect: $('body').data('default-select'),
6
+ defaultSelect: document.querySelector('body').dataset.defaultSelect,
5
7
  },
6
8
  };
7
- };
9
+ }
8
10
 
9
- $(initializer);
10
- $(document).on('turbolinks:load turbo:load', initializer);
11
+ loadEvents.forEach((event) => {
12
+ document.addEventListener(event, initializer);
13
+ });
@@ -0,0 +1,93 @@
1
+ import { ransackSearch } from './slim-select-utils';
2
+
3
+ const classes = ['nested-level-input'];
4
+
5
+ function ajaxSearch(search, currentData, args) {
6
+ args.fields.forEach((field) => {
7
+ if (field === 'id') {
8
+ args.textQuery[`${field}_eq`] = search;
9
+ } else {
10
+ args.textQuery[`${field}_${args.predicate}`] = search;
11
+ }
12
+ });
13
+
14
+ if (!!args.parent) {
15
+ args.query.q[`${args.parent}_eq`] = args.parentId;
16
+ }
17
+
18
+ args.query.q = { ...args.query.q, ...args.filters };
19
+
20
+ return ransackSearch(search, currentData, args);
21
+ }
22
+
23
+ function collectionSearch(search, args, collection) {
24
+ if (search.length < args.minimumInputLength) {
25
+ return Promise.reject('Search term too short');
26
+ }
27
+
28
+ const data = JSON.parse(collection).map(
29
+ (item) => ({ value: String(item.id), text: item.text }),
30
+ ).filter(
31
+ (item) => String(item.text).toLowerCase().includes(search.toLowerCase()));
32
+
33
+ return Promise.resolve(data);
34
+ }
35
+
36
+ function settings(el) {
37
+ return {
38
+ settings: {
39
+ allowDeselect: true,
40
+ },
41
+ events: {
42
+ beforeOpen: () => {
43
+ if (Number(el.dataset.minimumInputLength) === 0) {
44
+ el.slim.search('');
45
+ }
46
+ },
47
+ afterChange: () => {
48
+ const { model, association } = el.dataset;
49
+ const child = el.closest('.nested_level')
50
+ .parentNode
51
+ .querySelector(`.nested_level [data-model=${model}][data-parent=${association}_id]`);
52
+
53
+ if (child) {
54
+ child.slim.setSelected();
55
+ child.slim.setData([]);
56
+ if (child.slim.events.afterChange) {
57
+ child.slim.events.afterChange();
58
+ }
59
+ child.dispatchEvent(new Event('change'));
60
+ child.dataset.parentId = el.value;
61
+ }
62
+ },
63
+ search(search, currentData) {
64
+ const args = {
65
+ url: el.dataset.url,
66
+ fields: el.dataset.fields && JSON.parse(el.dataset.fields) || {},
67
+ predicate: el.dataset.predicate,
68
+ filters: el.dataset.filters && JSON.parse(el.dataset.filters) || {},
69
+ displayName: el.dataset.displayName,
70
+ parent: el.dataset.parent,
71
+ parentId: el.dataset.parentId,
72
+ responseRoot: el.dataset.responseRoot,
73
+ minimumInputLength: el.dataset.minimumInputLength,
74
+ order: el.dataset.order,
75
+ textQuery: { m: 'or' },
76
+ query: { q: {} },
77
+ };
78
+
79
+ if (el.dataset.collection) {
80
+ return collectionSearch(search, args, el.dataset.collection);
81
+ }
82
+
83
+ return ajaxSearch(search, currentData, args);
84
+ },
85
+ },
86
+ };
87
+ }
88
+
89
+ export {
90
+ settings,
91
+ classes,
92
+ };
93
+
@@ -0,0 +1,37 @@
1
+ import { ransackSearch } from './slim-select-utils';
2
+
3
+ const classes = ['search-select-input', 'search-select-filter-input', 'ajax-filter-input'];
4
+
5
+ function settings(el) {
6
+ const url = el.dataset.url;
7
+ const fields = JSON.parse(el.dataset.fields);
8
+ const predicate = el.dataset.predicate;
9
+ const displayName = el.dataset.displayName;
10
+ const responseRoot = el.dataset.responseRoot;
11
+ const minimumInputLength = el.dataset.minimumInputLength;
12
+ const order = el.dataset.order;
13
+
14
+ const args = { url, fields, predicate, displayName, responseRoot, minimumInputLength, order };
15
+
16
+ return {
17
+ events: {
18
+ search: (search, currentData) => {
19
+ args.textQuery = { m: 'or' };
20
+ args.fields.forEach((field) => {
21
+ if (field === 'id') {
22
+ args.textQuery[`${field}_eq`] = search;
23
+ } else {
24
+ args.textQuery[`${field}_${args.predicate}`] = search;
25
+ }
26
+ });
27
+
28
+ return ransackSearch(search, currentData, args);
29
+ },
30
+ },
31
+ };
32
+ }
33
+
34
+ export {
35
+ settings,
36
+ classes,
37
+ };
@@ -0,0 +1,103 @@
1
+ import { ransackSearch } from './slim-select-utils';
2
+
3
+ const classes = ['selected-list-input'];
4
+
5
+ // eslint-disable-next-line max-statements
6
+ function settings(el) {
7
+ const url = el.dataset.url;
8
+ const fields = JSON.parse(el.dataset.fields);
9
+ const predicate = el.dataset.predicate;
10
+ const displayName = el.dataset.displayName;
11
+ const method = el.dataset.method;
12
+ const model = el.dataset.model;
13
+ const prefix = `${model}_${method}`;
14
+ const responseRoot = el.dataset.responseRoot;
15
+ const minimumInputLength = el.dataset.minimumInputLength;
16
+ const order = el.dataset.order;
17
+
18
+ const args = { url, fields, predicate, displayName, responseRoot, minimumInputLength, order };
19
+
20
+ return {
21
+ settings: {
22
+ allowDeselect: false,
23
+ },
24
+ events: {
25
+ // eslint-disable-next-line max-statements
26
+ afterChange: (newVal) => {
27
+ if (!newVal || newVal[0] && !newVal[0].value) return;
28
+
29
+ const selectedItemsContainer = document.querySelector(`[id='${prefix}_selected_values']`);
30
+ const itemName = `${model}[${method}][]`;
31
+
32
+ // eslint-disable-next-line max-statements
33
+ newVal.forEach((data) => {
34
+ const itemId = `${prefix}_${data.value}`;
35
+ if (!!document.querySelector(`#${itemId}`)) {
36
+ return;
37
+ }
38
+
39
+ const item = document.createElement('div');
40
+ item.id = itemId;
41
+ item.textContent = data.text;
42
+ item.classList.add('selected-item');
43
+
44
+ const hiddenInput = document.createElement('input');
45
+ hiddenInput.name = itemName;
46
+ hiddenInput.type = 'hidden';
47
+ hiddenInput.value = data.value;
48
+
49
+ item.appendChild(hiddenInput);
50
+ selectedItemsContainer.appendChild(item);
51
+ });
52
+ el.slim.setSelected();
53
+ },
54
+ search: (search, currentData) => {
55
+ args.textQuery = { m: 'or' };
56
+ args.fields.forEach((field) => {
57
+ args.textQuery[`${field}_${predicate}`] = search;
58
+ });
59
+
60
+ return ransackSearch(search, currentData, args);
61
+ },
62
+ },
63
+ };
64
+ }
65
+
66
+ function setupSelectedList(containerEl) {
67
+ containerEl.addEventListener('click', (event) => {
68
+ const item = event.target;
69
+ if (item.classList.contains('selected-item')) {
70
+ item.remove();
71
+ }
72
+ });
73
+ }
74
+
75
+ function setupSelectedLists(node) {
76
+ node.querySelectorAll('.selected-list-container').forEach(setupSelectedList);
77
+ }
78
+
79
+ function mutationObserver() {
80
+ return new MutationObserver((mutations) => {
81
+ mutations.forEach((mutation) => {
82
+ if (mutation.type === 'childList') {
83
+ mutation.addedNodes.forEach((node) => {
84
+ if (node instanceof Element) {
85
+ setupSelectedLists(node);
86
+ }
87
+ });
88
+ }
89
+ });
90
+ });
91
+ }
92
+
93
+ function init() {
94
+ setupSelectedLists(document);
95
+ mutationObserver();
96
+ }
97
+
98
+ export {
99
+ settings,
100
+ classes,
101
+ init,
102
+ };
103
+
@@ -0,0 +1,22 @@
1
+ const classes = ['simple-tags-input'];
2
+
3
+ function init(el) {
4
+ el.multiple = true;
5
+ if (!el.value) {
6
+ el.value = null;
7
+ }
8
+ }
9
+
10
+ function settings() {
11
+ return {
12
+ events: {
13
+ addable: (value) => value,
14
+ },
15
+ };
16
+ }
17
+
18
+ export {
19
+ classes,
20
+ init,
21
+ settings,
22
+ };
@@ -0,0 +1,67 @@
1
+ const classes = ['tags-input'];
2
+
3
+ // eslint-disable-next-line max-statements
4
+ function settings(el) {
5
+ const model = el.dataset.model;
6
+ const method = el.dataset.method;
7
+ const prefix = `${model}_${method}`;
8
+ const isRelation = el.dataset.relation === 'true';
9
+ const collection = el.dataset.collection ? JSON.parse(el.dataset.collection) : null;
10
+
11
+ const parsedCollection = collection && collection.map((item) => {
12
+ const { id, ...rest } = item;
13
+
14
+ return { ...rest, value: id, selected: !!item.selected };
15
+ });
16
+
17
+ function fillHiddenInput(values) {
18
+ const hiddenInput = document.querySelector(`#${prefix}`);
19
+ hiddenInput.value = values.map(val => val.value).join();
20
+ }
21
+
22
+ const events = {
23
+ afterChange: (newVal) => {
24
+ if (isRelation) {
25
+ const selectedItemsContainer = document.querySelector(`#${prefix}_selected_values`);
26
+ const itemName = `${model}[${method}][]`;
27
+ selectedItemsContainer.innerHTML = '';
28
+
29
+ newVal.forEach((data) => {
30
+ const itemId = `${prefix}_${data.value}`;
31
+ if (document.querySelectorAll(`#${itemId}`).length > 0) {
32
+ return;
33
+ }
34
+
35
+ const hiddenInput = document.createElement('input');
36
+ hiddenInput.id = itemId;
37
+ hiddenInput.name = itemName;
38
+ hiddenInput.value = data.value;
39
+ hiddenInput.type = 'hidden';
40
+
41
+ selectedItemsContainer.appendChild(hiddenInput);
42
+ });
43
+ } else {
44
+ fillHiddenInput(newVal);
45
+ }
46
+ },
47
+ };
48
+
49
+ if (!isRelation) {
50
+ events.addable = (value) => value;
51
+ }
52
+
53
+ return {
54
+ data: parsedCollection,
55
+ events,
56
+ };
57
+ }
58
+
59
+ function init(el) {
60
+ el.multiple = true;
61
+ }
62
+
63
+ export {
64
+ settings,
65
+ classes,
66
+ init,
67
+ };
@@ -0,0 +1,70 @@
1
+ import merge from 'lodash.merge';
2
+
3
+ function parseObjectToQuery(obj, prefix) {
4
+ let queryArray = [];
5
+ Object.keys(obj).forEach(key => {
6
+ const value = obj[key];
7
+ const prefixedKey = prefix ? `${prefix}[${key}]` : key;
8
+ if (Array.isArray(value)) {
9
+ value.forEach((v, i) => {
10
+ queryArray = [...queryArray, parseObjectToQuery(v, `${prefixedKey}[${i}]`)];
11
+ });
12
+ } else if (typeof value === 'object') {
13
+ queryArray = [...queryArray, parseObjectToQuery(value, prefixedKey)];
14
+ } else {
15
+ queryArray.push(`${prefixedKey}=${encodeURIComponent(value)}`);
16
+ }
17
+ });
18
+
19
+ return queryArray.join('&');
20
+ }
21
+
22
+ export function ransackSearch(search, currentData, settings) {
23
+ return new Promise((resolve, reject) => {
24
+ if (search.length < settings.minimumInputLength) {
25
+ reject(`Please enter ${settings.minimumInputLength} or more characters`);
26
+ }
27
+
28
+ const defaultQuery = {
29
+ order: settings.order,
30
+ q: {
31
+ groupings: [settings.textQuery],
32
+ combinator: 'and',
33
+ },
34
+ };
35
+
36
+ const finalQuery = merge({}, defaultQuery, settings.query);
37
+ const csrfTokenEl = document.querySelector('meta[name="csrf-token"]');
38
+ const csrfToken = csrfTokenEl ? csrfTokenEl.getAttribute('content') : null;
39
+
40
+ const queryString = parseObjectToQuery(finalQuery);
41
+ fetch(`${settings.url}?${queryString}`, {
42
+ method: 'GET',
43
+ headers: {
44
+ 'X-CSRF-TOKEN': csrfToken,
45
+ 'Accept': 'application/json',
46
+ 'Content-Type': 'application/json',
47
+ },
48
+ })
49
+ .then((response) => response.json())
50
+ .then((res) => {
51
+ let data = res;
52
+ if (data.constructor === Object) {
53
+ data = data[settings.responseRoot];
54
+ }
55
+
56
+ const options = data.map(resource => {
57
+ if (!resource[settings.displayName]) {
58
+ resource[settings.displayName] = `No display name for id #${resource.id.toString()}`;
59
+ }
60
+
61
+ return {
62
+ value: resource.id,
63
+ text: resource[settings.displayName],
64
+ };
65
+ });
66
+
67
+ resolve(options);
68
+ });
69
+ });
70
+ }