activeadmin_addons 1.9.0 → 2.0.0.beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) 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 +2 -1
  5. data/app/inputs/search_select_input.rb +1 -1
  6. data/app/inputs/tags_input.rb +1 -1
  7. data/app/javascript/activeadmin_addons/addons/slim-select-interactive-tag.js +78 -0
  8. data/app/javascript/activeadmin_addons/addons/toggle_bool.js +1 -1
  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/color-picker.js +1 -1
  12. data/app/javascript/activeadmin_addons/inputs/date-time-picker.js +1 -1
  13. data/app/javascript/activeadmin_addons/inputs/slim-select-nested.js +93 -0
  14. data/app/javascript/activeadmin_addons/inputs/slim-select-search.js +37 -0
  15. data/app/javascript/activeadmin_addons/inputs/slim-select-selected-list.js +103 -0
  16. data/app/javascript/activeadmin_addons/inputs/slim-select-simple-tags.js +22 -0
  17. data/app/javascript/activeadmin_addons/inputs/slim-select-tags.js +67 -0
  18. data/app/javascript/activeadmin_addons/inputs/slim-select-utils.js +70 -0
  19. data/app/javascript/activeadmin_addons/inputs/slim-select.js +75 -0
  20. data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/all.scss +5 -11
  21. data/app/javascript/activeadmin_addons/stylesheets/imports/slimselect.css +1 -0
  22. data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/selected-list.scss +0 -1
  23. data/app/javascript/activeadmin_addons/stylesheets/inputs/slim-select.scss +9 -0
  24. data/lib/activeadmin_addons/addons/image_builder.rb +21 -3
  25. data/lib/activeadmin_addons/addons/markdown_builder.rb +38 -0
  26. data/lib/activeadmin_addons/addons/tag_builder.rb +6 -21
  27. data/lib/activeadmin_addons/engine.rb +0 -5
  28. data/lib/activeadmin_addons/support/enum_utils.rb +19 -0
  29. data/lib/activeadmin_addons/support/input_helpers/select_helpers.rb +1 -1
  30. data/lib/activeadmin_addons/support/select_filter_input_extension.rb +19 -0
  31. data/lib/activeadmin_addons/version.rb +1 -1
  32. data/lib/activeadmin_addons.rb +1 -1
  33. data/lib/generators/activeadmin_addons/install/install_generator.rb +2 -1
  34. data/lib/generators/activeadmin_addons/install/templates/initializer.rb +1 -1
  35. data/lib/generators/activeadmin_addons/webpacker/webpacker_generator.rb +1 -1
  36. metadata +83 -181
  37. data/app/assets/images/fileicons/file_extension_3gp.png +0 -0
  38. data/app/assets/images/fileicons/file_extension_7z.png +0 -0
  39. data/app/assets/images/fileicons/file_extension_ace.png +0 -0
  40. data/app/assets/images/fileicons/file_extension_ai.png +0 -0
  41. data/app/assets/images/fileicons/file_extension_aif.png +0 -0
  42. data/app/assets/images/fileicons/file_extension_aiff.png +0 -0
  43. data/app/assets/images/fileicons/file_extension_amr.png +0 -0
  44. data/app/assets/images/fileicons/file_extension_asf.png +0 -0
  45. data/app/assets/images/fileicons/file_extension_asx.png +0 -0
  46. data/app/assets/images/fileicons/file_extension_bat.png +0 -0
  47. data/app/assets/images/fileicons/file_extension_bin.png +0 -0
  48. data/app/assets/images/fileicons/file_extension_bmp.png +0 -0
  49. data/app/assets/images/fileicons/file_extension_bup.png +0 -0
  50. data/app/assets/images/fileicons/file_extension_cab.png +0 -0
  51. data/app/assets/images/fileicons/file_extension_cbr.png +0 -0
  52. data/app/assets/images/fileicons/file_extension_cda.png +0 -0
  53. data/app/assets/images/fileicons/file_extension_cdl.png +0 -0
  54. data/app/assets/images/fileicons/file_extension_cdr.png +0 -0
  55. data/app/assets/images/fileicons/file_extension_chm.png +0 -0
  56. data/app/assets/images/fileicons/file_extension_dat.png +0 -0
  57. data/app/assets/images/fileicons/file_extension_divx.png +0 -0
  58. data/app/assets/images/fileicons/file_extension_dll.png +0 -0
  59. data/app/assets/images/fileicons/file_extension_dmg.png +0 -0
  60. data/app/assets/images/fileicons/file_extension_doc.png +0 -0
  61. data/app/assets/images/fileicons/file_extension_docx.png +0 -0
  62. data/app/assets/images/fileicons/file_extension_dss.png +0 -0
  63. data/app/assets/images/fileicons/file_extension_dvf.png +0 -0
  64. data/app/assets/images/fileicons/file_extension_dwg.png +0 -0
  65. data/app/assets/images/fileicons/file_extension_eml.png +0 -0
  66. data/app/assets/images/fileicons/file_extension_eps.png +0 -0
  67. data/app/assets/images/fileicons/file_extension_exe.png +0 -0
  68. data/app/assets/images/fileicons/file_extension_fla.png +0 -0
  69. data/app/assets/images/fileicons/file_extension_flv.png +0 -0
  70. data/app/assets/images/fileicons/file_extension_gif.png +0 -0
  71. data/app/assets/images/fileicons/file_extension_gz.png +0 -0
  72. data/app/assets/images/fileicons/file_extension_hqx.png +0 -0
  73. data/app/assets/images/fileicons/file_extension_htm.png +0 -0
  74. data/app/assets/images/fileicons/file_extension_html.png +0 -0
  75. data/app/assets/images/fileicons/file_extension_ifo.png +0 -0
  76. data/app/assets/images/fileicons/file_extension_indd.png +0 -0
  77. data/app/assets/images/fileicons/file_extension_iso.png +0 -0
  78. data/app/assets/images/fileicons/file_extension_jar.png +0 -0
  79. data/app/assets/images/fileicons/file_extension_jpeg.png +0 -0
  80. data/app/assets/images/fileicons/file_extension_jpg.png +0 -0
  81. data/app/assets/images/fileicons/file_extension_lnk.png +0 -0
  82. data/app/assets/images/fileicons/file_extension_log.png +0 -0
  83. data/app/assets/images/fileicons/file_extension_m4a.png +0 -0
  84. data/app/assets/images/fileicons/file_extension_m4b.png +0 -0
  85. data/app/assets/images/fileicons/file_extension_m4p.png +0 -0
  86. data/app/assets/images/fileicons/file_extension_m4v.png +0 -0
  87. data/app/assets/images/fileicons/file_extension_mcd.png +0 -0
  88. data/app/assets/images/fileicons/file_extension_mdb.png +0 -0
  89. data/app/assets/images/fileicons/file_extension_mid.png +0 -0
  90. data/app/assets/images/fileicons/file_extension_mov.png +0 -0
  91. data/app/assets/images/fileicons/file_extension_mp2.png +0 -0
  92. data/app/assets/images/fileicons/file_extension_mp3.png +0 -0
  93. data/app/assets/images/fileicons/file_extension_mp4.png +0 -0
  94. data/app/assets/images/fileicons/file_extension_mpeg.png +0 -0
  95. data/app/assets/images/fileicons/file_extension_mpg.png +0 -0
  96. data/app/assets/images/fileicons/file_extension_msi.png +0 -0
  97. data/app/assets/images/fileicons/file_extension_mswmm.png +0 -0
  98. data/app/assets/images/fileicons/file_extension_ogg.png +0 -0
  99. data/app/assets/images/fileicons/file_extension_pdf.png +0 -0
  100. data/app/assets/images/fileicons/file_extension_png.png +0 -0
  101. data/app/assets/images/fileicons/file_extension_pps.png +0 -0
  102. data/app/assets/images/fileicons/file_extension_ppt.png +0 -0
  103. data/app/assets/images/fileicons/file_extension_pptx.png +0 -0
  104. data/app/assets/images/fileicons/file_extension_ps.png +0 -0
  105. data/app/assets/images/fileicons/file_extension_psd.png +0 -0
  106. data/app/assets/images/fileicons/file_extension_pst.png +0 -0
  107. data/app/assets/images/fileicons/file_extension_ptb.png +0 -0
  108. data/app/assets/images/fileicons/file_extension_pub.png +0 -0
  109. data/app/assets/images/fileicons/file_extension_qbb.png +0 -0
  110. data/app/assets/images/fileicons/file_extension_qbw.png +0 -0
  111. data/app/assets/images/fileicons/file_extension_qxd.png +0 -0
  112. data/app/assets/images/fileicons/file_extension_ram.png +0 -0
  113. data/app/assets/images/fileicons/file_extension_rar.png +0 -0
  114. data/app/assets/images/fileicons/file_extension_rm.png +0 -0
  115. data/app/assets/images/fileicons/file_extension_rmvb.png +0 -0
  116. data/app/assets/images/fileicons/file_extension_rtf.png +0 -0
  117. data/app/assets/images/fileicons/file_extension_sea.png +0 -0
  118. data/app/assets/images/fileicons/file_extension_ses.png +0 -0
  119. data/app/assets/images/fileicons/file_extension_sit.png +0 -0
  120. data/app/assets/images/fileicons/file_extension_sitx.png +0 -0
  121. data/app/assets/images/fileicons/file_extension_ss.png +0 -0
  122. data/app/assets/images/fileicons/file_extension_swf.png +0 -0
  123. data/app/assets/images/fileicons/file_extension_tgz.png +0 -0
  124. data/app/assets/images/fileicons/file_extension_thm.png +0 -0
  125. data/app/assets/images/fileicons/file_extension_tif.png +0 -0
  126. data/app/assets/images/fileicons/file_extension_tmp.png +0 -0
  127. data/app/assets/images/fileicons/file_extension_torrent.png +0 -0
  128. data/app/assets/images/fileicons/file_extension_ttf.png +0 -0
  129. data/app/assets/images/fileicons/file_extension_txt.png +0 -0
  130. data/app/assets/images/fileicons/file_extension_unknown.png +0 -0
  131. data/app/assets/images/fileicons/file_extension_vcd.png +0 -0
  132. data/app/assets/images/fileicons/file_extension_vob.png +0 -0
  133. data/app/assets/images/fileicons/file_extension_wav.png +0 -0
  134. data/app/assets/images/fileicons/file_extension_wma.png +0 -0
  135. data/app/assets/images/fileicons/file_extension_wmv.png +0 -0
  136. data/app/assets/images/fileicons/file_extension_wps.png +0 -0
  137. data/app/assets/images/fileicons/file_extension_xls.png +0 -0
  138. data/app/assets/images/fileicons/file_extension_xlsx.png +0 -0
  139. data/app/assets/images/fileicons/file_extension_xpi.png +0 -0
  140. data/app/assets/images/fileicons/file_extension_zip.png +0 -0
  141. data/app/assets/images/material/icons/keyboard_arrow_down.svg +0 -4
  142. data/app/assets/images/material/icons/keyboard_arrow_left.svg +0 -4
  143. data/app/assets/images/material/icons/keyboard_arrow_right.svg +0 -4
  144. data/app/assets/images/material/icons/keyboard_arrow_up.svg +0 -4
  145. data/app/assets/images/material/icons/today.svg +0 -4
  146. data/app/assets/javascripts/activeadmin_addons/all.js +0 -753
  147. data/app/assets/stylesheets/activeadmin_addons/addons/material-datepicker.scss +0 -173
  148. data/app/assets/stylesheets/activeadmin_addons/addons/material-toggle_bool.scss +0 -52
  149. data/app/assets/stylesheets/activeadmin_addons/inputs/select2.scss +0 -3
  150. data/app/assets/stylesheets/activeadmin_addons/material.scss +0 -53
  151. data/app/javascript/activeadmin_addons/addons/interactive_select_tag.js +0 -95
  152. data/app/javascript/activeadmin_addons/inputs/nested-select.js +0 -170
  153. data/app/javascript/activeadmin_addons/inputs/search-select.js +0 -76
  154. data/app/javascript/activeadmin_addons/inputs/select2.js +0 -52
  155. data/app/javascript/activeadmin_addons/inputs/selected-list.js +0 -107
  156. data/app/javascript/activeadmin_addons/inputs/tags.js +0 -76
  157. data/lib/activeadmin_addons/addons/attachment_builder.rb +0 -60
  158. data/lib/activeadmin_addons/support/enumerize_formtastic_support.rb +0 -18
  159. data/lib/generators/activeadmin_addons/assets/assets_generator.rb +0 -53
  160. data/vendor/assets/select2/select2.css +0 -481
  161. data/vendor/assets/select2/select2.full.js +0 -6820
  162. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/addons/interactive_select_tag.scss +0 -0
  163. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/addons/toggle_bool.scss +0 -0
  164. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/imports/jquery-datepicker.scss +0 -0
  165. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/color-picker.scss +0 -0
  166. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/date-time-picker-filter.scss +0 -0
  167. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/date-time-picker.scss +0 -0
  168. /data/app/{assets/stylesheets/activeadmin_addons → javascript/activeadmin_addons/stylesheets}/inputs/numeric-range-filter.scss +0 -0
  169. /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: 31434452186d9b02e7d7272b27d06d1e4831b1c4c6de9c068e973cf5311da476
4
- data.tar.gz: 0a43f7f1d45b50c01eeb4b4f7a56f5ff9bcb4329a24adb4f77fc1d1ca28fa0e7
3
+ metadata.gz: aed38304ff68795198eb34b4fb634a5f8e55143b4f159b04698d0852d32e36ef
4
+ data.tar.gz: 6c4637ae03b38a74d1d06831fea506de8d13a996002d1770a0d5d80372242906
5
5
  SHA512:
6
- metadata.gz: 10db20adc03c85569ab16debe8edffd16115b348baf7779e79544fa42a265058cc60d3d24ac77dea5e85591297a6daeb2ede226141cb7dbb4e34d0776966462a
7
- data.tar.gz: b911e25eeb0801b2bbe7857c012f4c93fa71a2bf77d574d552461e39cdedfcdd698673ed625a4034c749852f2d1b47e1387a7b7c0a4f754cdb3311c753beab6a
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,6 +15,7 @@ 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
20
  load_data_attr(:predicate, default: "contains")
20
21
  load_data_attr(:filters)
@@ -23,7 +24,7 @@ class NestedLevelInput < ActiveAdminAddons::InputBase
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")
@@ -19,7 +19,7 @@ class SearchSelectInput < ActiveAdminAddons::InputBase
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],
@@ -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
+ });
@@ -36,4 +36,4 @@ var initializer = function() {
36
36
  };
37
37
 
38
38
  $(initializer);
39
- $(document).on('turbolinks:load', initializer);
39
+ $(document).on('turbolinks:load turbo:load', initializer);
@@ -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', initializer);
11
+ loadEvents.forEach((event) => {
12
+ document.addEventListener(event, initializer);
13
+ });
@@ -13,4 +13,4 @@ var initializer = function() {
13
13
  };
14
14
 
15
15
  $(initializer);
16
- $(document).on('turbolinks:load', initializer);
16
+ $(document).on('turbolinks:load turbo:load', initializer);
@@ -25,4 +25,4 @@ var initializer = function() {
25
25
  };
26
26
 
27
27
  $(initializer);
28
- $(document).on('turbolinks:load', initializer);
28
+ $(document).on('turbolinks:load turbo:load', initializer);
@@ -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
+ }