rails_admin 3.2.1 → 4.0.0.beta

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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +8 -6
  3. data/README.md +11 -11
  4. data/Rakefile +3 -11
  5. data/app/assets/builds/rails_admin.css +10 -0
  6. data/app/assets/builds/rails_admin.js +34 -0
  7. data/app/controllers/rails_admin/main_controller.rb +3 -3
  8. data/app/helpers/rails_admin/application_helper.rb +3 -15
  9. data/app/helpers/rails_admin/form_builder.rb +10 -9
  10. data/app/views/layouts/rails_admin/_head.html.erb +10 -27
  11. data/app/views/layouts/rails_admin/_head_custom.html.erb +3 -0
  12. data/app/views/layouts/rails_admin/_secondary_navigation.html.erb +1 -1
  13. data/app/views/rails_admin/main/_dashboard_history.html.erb +1 -1
  14. data/app/views/rails_admin/main/_delete_notice.html.erb +3 -3
  15. data/app/views/rails_admin/main/_form_boolean.html.erb +9 -13
  16. data/app/views/rails_admin/main/_submit_buttons.html.erb +4 -4
  17. data/app/views/rails_admin/main/bulk_delete.html.erb +2 -2
  18. data/app/views/rails_admin/main/dashboard.html.erb +3 -3
  19. data/app/views/rails_admin/main/delete.html.erb +2 -2
  20. data/app/views/rails_admin/main/export.html.erb +2 -2
  21. data/app/views/rails_admin/main/history.html.erb +2 -2
  22. data/app/views/rails_admin/main/index.html.erb +3 -3
  23. data/config/initializers/active_record_extensions.rb +1 -4
  24. data/lib/generators/rails_admin/install_generator.rb +37 -92
  25. data/lib/generators/rails_admin/templates/rails_admin.scss.erb +1 -1
  26. data/lib/rails_admin/abstract_model.rb +69 -191
  27. data/lib/rails_admin/adapters/active_record/association.rb +1 -1
  28. data/lib/rails_admin/adapters/active_record/property.rb +7 -0
  29. data/lib/rails_admin/adapters/active_record/reflection.rb +87 -0
  30. data/lib/rails_admin/adapters/active_record/repository.rb +216 -0
  31. data/lib/rails_admin/adapters/active_record/statement_builder.rb +148 -0
  32. data/lib/rails_admin/adapters/active_record/where_builder.rb +40 -0
  33. data/lib/rails_admin/adapters/active_record.rb +7 -356
  34. data/lib/rails_admin/adapters/mongoid/association.rb +1 -1
  35. data/lib/rails_admin/adapters/mongoid/extension.rb +16 -6
  36. data/lib/rails_admin/adapters/mongoid/property.rb +7 -0
  37. data/lib/rails_admin/adapters/mongoid/reflection.rb +58 -0
  38. data/lib/rails_admin/adapters/mongoid/repository.rb +237 -0
  39. data/lib/rails_admin/adapters/mongoid/statement_builder.rb +93 -0
  40. data/lib/rails_admin/adapters/mongoid.rb +7 -300
  41. data/lib/rails_admin/adapters/reflection.rb +105 -0
  42. data/lib/rails_admin/adapters/repository.rb +169 -0
  43. data/lib/rails_admin/adapters/statement_builder.rb +109 -0
  44. data/lib/rails_admin/adapters.rb +94 -0
  45. data/lib/rails_admin/config/actions/base.rb +8 -0
  46. data/lib/rails_admin/config/actions/bulk_delete.rb +4 -4
  47. data/lib/rails_admin/config/actions/dashboard.rb +1 -1
  48. data/lib/rails_admin/config/actions/edit.rb +3 -2
  49. data/lib/rails_admin/config/actions/index.rb +1 -1
  50. data/lib/rails_admin/config/actions/new.rb +3 -2
  51. data/lib/rails_admin/config/actions/show.rb +1 -1
  52. data/lib/rails_admin/config/configurable.rb +4 -3
  53. data/lib/rails_admin/config/fields/association.rb +9 -8
  54. data/lib/rails_admin/config/fields/base.rb +55 -37
  55. data/lib/rails_admin/config/fields/collection_association.rb +2 -2
  56. data/lib/rails_admin/config/fields/factories/carrierwave.rb +35 -20
  57. data/lib/rails_admin/config/fields/factories/dragonfly.rb +30 -18
  58. data/lib/rails_admin/config/fields/factories/enum.rb +14 -8
  59. data/lib/rails_admin/config/fields/factories/paperclip.rb +29 -19
  60. data/lib/rails_admin/config/fields/factories/shrine.rb +19 -8
  61. data/lib/rails_admin/config/fields/singular_association.rb +6 -1
  62. data/lib/rails_admin/config/fields/types/active_record_enum.rb +3 -7
  63. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +8 -4
  64. data/lib/rails_admin/config/fields/types/bson_object_id.rb +1 -1
  65. data/lib/rails_admin/config/fields/types/datetime.rb +0 -4
  66. data/lib/rails_admin/config/fields/types/dragonfly.rb +1 -1
  67. data/lib/rails_admin/config/fields/types/enum.rb +11 -2
  68. data/lib/rails_admin/config/fields/types/multiple_file_upload.rb +0 -2
  69. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +4 -4
  70. data/lib/rails_admin/config/fields/types/time.rb +1 -1
  71. data/lib/rails_admin/config/model.rb +27 -5
  72. data/lib/rails_admin/config/sections/list.rb +0 -8
  73. data/lib/rails_admin/config.rb +7 -21
  74. data/lib/rails_admin/criteria/path.rb +66 -0
  75. data/lib/rails_admin/criteria/period.rb +67 -0
  76. data/lib/rails_admin/engine.rb +11 -15
  77. data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +2 -2
  78. data/lib/rails_admin/extensions/url_for_extension.rb +8 -0
  79. data/lib/rails_admin/support/asset_source.rb +42 -0
  80. data/lib/rails_admin/support/composite_keys_serializer.rb +28 -2
  81. data/lib/rails_admin/support/csv_converter.rb +3 -10
  82. data/lib/rails_admin/version.rb +8 -7
  83. data/lib/rails_admin.rb +7 -0
  84. data/lib/tasks/assets.rake +23 -0
  85. data/package.json +12 -7
  86. data/src/rails_admin/base.js +18 -15
  87. data/src/rails_admin/filter-box.js +7 -4
  88. data/src/rails_admin/filtering-multiselect.js +1 -1
  89. data/src/rails_admin/filtering-select.js +8 -8
  90. data/src/rails_admin/flatpickr.js +14 -0
  91. data/src/rails_admin/remote-form.js +74 -48
  92. data/src/rails_admin/styles/base/theming.scss +48 -25
  93. data/src/rails_admin/styles/base.scss +25 -1
  94. data/src/rails_admin/styles/filtering-select.scss +23 -62
  95. data/src/rails_admin/ui.js +1 -1
  96. data/src/rails_admin/vendor/jquery_nested_form.js +4 -4
  97. data/src/rails_admin/widgets.js +44 -11
  98. metadata +34 -130
  99. data/app/assets/javascripts/rails_admin/application.js.erb +0 -30
  100. data/app/assets/javascripts/rails_admin/custom/ui.js +0 -1
  101. data/app/assets/stylesheets/rails_admin/application.scss.erb +0 -35
  102. data/app/assets/stylesheets/rails_admin/custom/mixins.scss +0 -11
  103. data/app/assets/stylesheets/rails_admin/custom/theming.scss +0 -13
  104. data/app/assets/stylesheets/rails_admin/custom/variables.scss +0 -15
  105. data/lib/generators/rails_admin/importmap_formatter.rb +0 -28
  106. data/lib/generators/rails_admin/templates/rails_admin.vite.js +0 -2
  107. data/lib/generators/rails_admin/templates/rails_admin.webpacker.js +0 -2
  108. data/lib/rails_admin/adapters/active_record/object_extension.rb +0 -13
  109. data/lib/rails_admin/adapters/active_record.rb.bak +0 -348
  110. data/lib/rails_admin/adapters/mongoid/object_extension.rb +0 -29
  111. data/lib/rails_admin/support/es_module_processor.rb +0 -23
  112. data/vendor/assets/fonts/rails_admin/fa-solid-900.ttf +0 -0
  113. data/vendor/assets/javascripts/rails_admin/bootstrap.js +0 -5046
  114. data/vendor/assets/javascripts/rails_admin/flatpickr-with-locales.js +0 -11246
  115. data/vendor/assets/javascripts/rails_admin/jquery-ui/data.js +0 -41
  116. data/vendor/assets/javascripts/rails_admin/jquery-ui/effect.js +0 -1637
  117. data/vendor/assets/javascripts/rails_admin/jquery-ui/ie.js +0 -17
  118. data/vendor/assets/javascripts/rails_admin/jquery-ui/keycode.js +0 -47
  119. data/vendor/assets/javascripts/rails_admin/jquery-ui/position.js +0 -500
  120. data/vendor/assets/javascripts/rails_admin/jquery-ui/safe-active-element.js +0 -42
  121. data/vendor/assets/javascripts/rails_admin/jquery-ui/scroll-parent.js +0 -47
  122. data/vendor/assets/javascripts/rails_admin/jquery-ui/unique-id.js +0 -51
  123. data/vendor/assets/javascripts/rails_admin/jquery-ui/version.js +0 -17
  124. data/vendor/assets/javascripts/rails_admin/jquery-ui/widget.js +0 -735
  125. data/vendor/assets/javascripts/rails_admin/jquery-ui/widgets/autocomplete.js +0 -689
  126. data/vendor/assets/javascripts/rails_admin/jquery-ui/widgets/menu.js +0 -680
  127. data/vendor/assets/javascripts/rails_admin/jquery-ui/widgets/mouse.js +0 -230
  128. data/vendor/assets/javascripts/rails_admin/jquery-ui/widgets/sortable.js +0 -1561
  129. data/vendor/assets/javascripts/rails_admin/jquery3.js +0 -10881
  130. data/vendor/assets/javascripts/rails_admin/popper.js +0 -1974
  131. data/vendor/assets/stylesheets/rails_admin/bootstrap/_accordion.scss +0 -118
  132. data/vendor/assets/stylesheets/rails_admin/bootstrap/_alert.scss +0 -57
  133. data/vendor/assets/stylesheets/rails_admin/bootstrap/_badge.scss +0 -29
  134. data/vendor/assets/stylesheets/rails_admin/bootstrap/_breadcrumb.scss +0 -28
  135. data/vendor/assets/stylesheets/rails_admin/bootstrap/_button-group.scss +0 -139
  136. data/vendor/assets/stylesheets/rails_admin/bootstrap/_buttons.scss +0 -111
  137. data/vendor/assets/stylesheets/rails_admin/bootstrap/_card.scss +0 -216
  138. data/vendor/assets/stylesheets/rails_admin/bootstrap/_carousel.scss +0 -229
  139. data/vendor/assets/stylesheets/rails_admin/bootstrap/_close.scss +0 -40
  140. data/vendor/assets/stylesheets/rails_admin/bootstrap/_containers.scss +0 -41
  141. data/vendor/assets/stylesheets/rails_admin/bootstrap/_dropdown.scss +0 -240
  142. data/vendor/assets/stylesheets/rails_admin/bootstrap/_forms.scss +0 -9
  143. data/vendor/assets/stylesheets/rails_admin/bootstrap/_functions.scss +0 -302
  144. data/vendor/assets/stylesheets/rails_admin/bootstrap/_grid.scss +0 -33
  145. data/vendor/assets/stylesheets/rails_admin/bootstrap/_helpers.scss +0 -9
  146. data/vendor/assets/stylesheets/rails_admin/bootstrap/_images.scss +0 -42
  147. data/vendor/assets/stylesheets/rails_admin/bootstrap/_list-group.scss +0 -174
  148. data/vendor/assets/stylesheets/rails_admin/bootstrap/_mixins.scss +0 -43
  149. data/vendor/assets/stylesheets/rails_admin/bootstrap/_modal.scss +0 -209
  150. data/vendor/assets/stylesheets/rails_admin/bootstrap/_nav.scss +0 -139
  151. data/vendor/assets/stylesheets/rails_admin/bootstrap/_navbar.scss +0 -335
  152. data/vendor/assets/stylesheets/rails_admin/bootstrap/_offcanvas.scss +0 -83
  153. data/vendor/assets/stylesheets/rails_admin/bootstrap/_pagination.scss +0 -64
  154. data/vendor/assets/stylesheets/rails_admin/bootstrap/_placeholders.scss +0 -51
  155. data/vendor/assets/stylesheets/rails_admin/bootstrap/_popover.scss +0 -158
  156. data/vendor/assets/stylesheets/rails_admin/bootstrap/_progress.scss +0 -48
  157. data/vendor/assets/stylesheets/rails_admin/bootstrap/_reboot.scss +0 -625
  158. data/vendor/assets/stylesheets/rails_admin/bootstrap/_root.scss +0 -54
  159. data/vendor/assets/stylesheets/rails_admin/bootstrap/_spinners.scss +0 -69
  160. data/vendor/assets/stylesheets/rails_admin/bootstrap/_tables.scss +0 -155
  161. data/vendor/assets/stylesheets/rails_admin/bootstrap/_toasts.scss +0 -51
  162. data/vendor/assets/stylesheets/rails_admin/bootstrap/_tooltip.scss +0 -115
  163. data/vendor/assets/stylesheets/rails_admin/bootstrap/_transitions.scss +0 -27
  164. data/vendor/assets/stylesheets/rails_admin/bootstrap/_type.scss +0 -104
  165. data/vendor/assets/stylesheets/rails_admin/bootstrap/_utilities.scss +0 -630
  166. data/vendor/assets/stylesheets/rails_admin/bootstrap/_variables.scss +0 -1641
  167. data/vendor/assets/stylesheets/rails_admin/bootstrap/bootstrap.scss +0 -53
  168. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_floating-labels.scss +0 -63
  169. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_form-check.scss +0 -152
  170. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_form-control.scss +0 -219
  171. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_form-range.scss +0 -91
  172. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_form-select.scss +0 -72
  173. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_form-text.scss +0 -11
  174. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_input-group.scss +0 -121
  175. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_labels.scss +0 -36
  176. data/vendor/assets/stylesheets/rails_admin/bootstrap/forms/_validation.scss +0 -12
  177. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_clearfix.scss +0 -3
  178. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_colored-links.scss +0 -12
  179. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_position.scss +0 -30
  180. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_ratio.scss +0 -26
  181. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_stacks.scss +0 -15
  182. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_stretched-link.scss +0 -15
  183. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_text-truncation.scss +0 -7
  184. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_visually-hidden.scss +0 -8
  185. data/vendor/assets/stylesheets/rails_admin/bootstrap/helpers/_vr.scss +0 -8
  186. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_alert.scss +0 -11
  187. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_backdrop.scss +0 -14
  188. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_border-radius.scss +0 -78
  189. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_box-shadow.scss +0 -18
  190. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_breakpoints.scss +0 -127
  191. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_buttons.scss +0 -133
  192. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_caret.scss +0 -64
  193. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_clearfix.scss +0 -9
  194. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_color-scheme.scss +0 -7
  195. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_container.scss +0 -9
  196. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_deprecate.scss +0 -10
  197. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_forms.scss +0 -144
  198. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_gradients.scss +0 -47
  199. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_grid.scss +0 -151
  200. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_image.scss +0 -16
  201. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_list-group.scss +0 -24
  202. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_lists.scss +0 -7
  203. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_pagination.scss +0 -31
  204. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_reset-text.scss +0 -17
  205. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_resize.scss +0 -6
  206. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_table-variants.scss +0 -21
  207. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_text-truncate.scss +0 -8
  208. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_transition.scss +0 -26
  209. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_utilities.scss +0 -89
  210. data/vendor/assets/stylesheets/rails_admin/bootstrap/mixins/_visually-hidden.scss +0 -29
  211. data/vendor/assets/stylesheets/rails_admin/bootstrap/utilities/_api.scss +0 -47
  212. data/vendor/assets/stylesheets/rails_admin/bootstrap/vendor/_rfs.scss +0 -354
  213. data/vendor/assets/stylesheets/rails_admin/flatpickr.css +0 -791
  214. data/vendor/assets/stylesheets/rails_admin/font-awesome.scss +0 -6351
@@ -1,7 +1,7 @@
1
1
  import jQuery from "jquery";
2
2
  import "jquery-ui/ui/widget.js";
3
3
  import "jquery-ui/ui/widgets/autocomplete.js";
4
- import I18n from "./i18n";
4
+ import I18n from "./i18n.js";
5
5
 
6
6
  (function ($) {
7
7
  "use strict";
@@ -30,7 +30,7 @@ import I18n from "./i18n";
30
30
  // to be generated.
31
31
  if (this.filtering_select.length > 0) {
32
32
  this.input = this.filtering_select.children("input");
33
- this.button = this.filtering_select.children(".input-group-btn");
33
+ this.button = this.filtering_select.children(".btn");
34
34
  } else {
35
35
  this.element.hide();
36
36
  this.filtering_select = this._inputGroup(this.element.attr("id"));
@@ -106,7 +106,7 @@ import I18n from "./i18n";
106
106
  var self = this;
107
107
  var requestIndex = 0;
108
108
 
109
- if ($.isArray(source)) {
109
+ if (Array.isArray(source)) {
110
110
  return function (request, response) {
111
111
  response(self._getResultSet(request, source, false));
112
112
  };
@@ -152,11 +152,9 @@ import I18n from "./i18n";
152
152
  },
153
153
 
154
154
  _buttonField: function () {
155
+ // A direct child of .input-group, so Bootstrap joins it to the input.
155
156
  return $(
156
- '<span class="input-group-btn">' +
157
- '<label class="btn btn-info dropdown-toggle" title="Show All Items" role="button">' +
158
- "</label>" +
159
- "</span>"
157
+ '<label class="btn btn-info dropdown-toggle" title="Show All Items" role="button"></label>'
160
158
  );
161
159
  },
162
160
 
@@ -212,6 +210,8 @@ import I18n from "./i18n";
212
210
  delay: this.options.searchDelay,
213
211
  minLength: this.options.minLength,
214
212
  source: this._getSourceFunction(this.options.source),
213
+ // Render the menu as a Bootstrap dropdown, so it follows the app's theme.
214
+ classes: { "ui-autocomplete": "ui-front dropdown-menu" },
215
215
  select: function (event, ui) {
216
216
  var option = self.element.find(
217
217
  `option[value="${CSS.escape(ui.item.id)}"]`
@@ -289,7 +289,7 @@ import I18n from "./i18n";
289
289
  this.input.data("ui-autocomplete")._renderItem = function (ul, item) {
290
290
  return $("<li></li>")
291
291
  .data("ui-autocomplete-item", item)
292
- .append($("<a></a>").html(item.html || item.id))
292
+ .append($('<a class="dropdown-item"></a>').html(item.html || item.id))
293
293
  .appendTo(ul);
294
294
  };
295
295
  },
@@ -0,0 +1,14 @@
1
+ // flatpickr with every locale registered onto its shared `l10ns` singleton, so the
2
+ // date/time widgets can honour `locale: I18n.locale`. This is the equivalent of the
3
+ // Sprockets manifest's old `flatpickr-with-locales` require. Import this instead of
4
+ // "flatpickr" directly.
5
+ //
6
+ // flatpickr assigns itself to `window.flatpickr` on load, and the l10n bundle
7
+ // self-registers onto that global - so the "flatpickr" import has to come first to
8
+ // win the evaluation-order race. Assigning the locales by hand instead does not
9
+ // work: esbuild's Node interop hands back the wrapped module namespace, which
10
+ // clobbers `l10ns.default` and breaks every picker.
11
+ import flatpickr from "flatpickr";
12
+ import "flatpickr/dist/l10n/index.js";
13
+
14
+ export default flatpickr;
@@ -1,4 +1,3 @@
1
- import Rails from "@rails/ujs";
2
1
  import jQuery from "jquery";
3
2
  import "jquery-ui/ui/widget.js";
4
3
  import * as bootstrap from "bootstrap";
@@ -79,7 +78,13 @@ import * as bootstrap from "bootstrap";
79
78
  cancelButtonText = dialog.find(":submit[name=_continue]").html();
80
79
  dialog.find(".form-actions").remove();
81
80
 
82
- form.attr("data-remote", true).attr("data-type", "json");
81
+ // We submit this form ourselves (see _submitForm) and want the JSON back,
82
+ // not a Turbo navigation - catch both the save button and an Enter keypress.
83
+ form.attr("data-turbo", "false");
84
+ form.off("submit.raRemoteForm").on("submit.raRemoteForm", function (e) {
85
+ e.preventDefault();
86
+ widget._submitForm(form);
87
+ });
83
88
  dialog.find(".modal-header-title").text(form.data("title"));
84
89
  dialog
85
90
  .find(".cancel-action")
@@ -96,63 +101,84 @@ import * as bootstrap from "bootstrap";
96
101
  .find(".save-action")
97
102
  .unbind()
98
103
  .click(function () {
99
- Rails.fire(form[0], "submit");
104
+ form.trigger("submit.raRemoteForm");
100
105
  return false;
101
106
  })
102
107
  .html(saveButtonText);
103
108
 
104
109
  const event = new CustomEvent("rails_admin.dom_ready", { detail: form });
105
110
  document.dispatchEvent(event);
111
+ },
112
+
113
+ _submitForm: function (form) {
114
+ var widget = this;
115
+ var csrf = document.querySelector('meta[name="csrf-token"]');
116
+ // We read the form without submitting it, so let widgets write back first.
117
+ form[0].dispatchEvent(
118
+ new CustomEvent("rails_admin.before_remote_submit")
119
+ );
120
+ jQuery.ajax({
121
+ url: form.attr("action"),
122
+ method: (form.attr("method") || "post").toUpperCase(),
123
+ data: new FormData(form[0]),
124
+ processData: false,
125
+ contentType: false,
126
+ headers: {
127
+ "X-CSRF-Token": csrf ? csrf.content : "",
128
+ // JSON on success, the modal HTML (format.js) on validation errors.
129
+ Accept: "application/json, text/javascript",
130
+ },
131
+ complete: function (xhr) {
132
+ widget._handleFormResponse(xhr);
133
+ },
134
+ });
135
+ },
106
136
 
107
- form.bind("ajax:complete", function (event) {
108
- var data = event.detail[0];
109
- if (data.status == 200) {
110
- var json = $.parseJSON(data.responseText);
111
- var option =
112
- '<option value="' +
113
- json.id +
114
- '" selected>' +
115
- json.label +
116
- "</option>";
117
- var select = widget.element.find("select").filter(":hidden");
137
+ _handleFormResponse: function (xhr) {
138
+ var widget = this,
139
+ dialog = this._getModal();
140
+ if (xhr.status == 200) {
141
+ var json = JSON.parse(xhr.responseText);
142
+ var option =
143
+ '<option value="' +
144
+ json.id +
145
+ '" selected>' +
146
+ json.label +
147
+ "</option>";
148
+ var select = widget.element.find("select").filter(":hidden");
118
149
 
119
- if (widget.element.find(".filtering-select").length) {
120
- // select input
121
- var input = widget.element
122
- .find(".filtering-select")
123
- .children(".ra-filtering-select-input");
124
- input.val(json.label);
125
- if (!select.find("option[value=" + json.id + "]").length) {
126
- // not a replace
127
- select.html(option).val(json.id);
128
- widget.element.find(".update").removeClass("disabled");
129
- }
130
- } else {
131
- // multi-select input
132
- var multiselect = widget.element.find(".ra-multiselect");
133
- if (multiselect.find("option[value=" + json.id + "]").length) {
134
- // replace
135
- select.find("option[value=" + json.id + "]").text(json.label);
136
- multiselect
137
- .find("option[value= " + json.id + "]")
138
- .text(json.label);
139
- } else {
140
- // add
141
- select.append(option);
142
- multiselect
143
- .find("select.ra-multiselect-selection")
144
- .append(option);
145
- }
150
+ if (widget.element.find(".filtering-select").length) {
151
+ // select input
152
+ var input = widget.element
153
+ .find(".filtering-select")
154
+ .children(".ra-filtering-select-input");
155
+ input.val(json.label);
156
+ if (!select.find("option[value=" + json.id + "]").length) {
157
+ // not a replace
158
+ select.html(option).val(json.id);
159
+ widget.element.find(".update").removeClass("disabled");
146
160
  }
147
- widget._trigger("success");
148
- dialog.each(function (index, element) {
149
- bootstrap.Modal.getInstance(element).hide();
150
- });
151
161
  } else {
152
- dialog.find(".modal-body").html(data.responseText);
153
- widget._bindFormEvents();
162
+ // multi-select input
163
+ var multiselect = widget.element.find(".ra-multiselect");
164
+ if (multiselect.find("option[value=" + json.id + "]").length) {
165
+ // replace
166
+ select.find("option[value=" + json.id + "]").text(json.label);
167
+ multiselect.find("option[value= " + json.id + "]").text(json.label);
168
+ } else {
169
+ // add
170
+ select.append(option);
171
+ multiselect.find("select.ra-multiselect-selection").append(option);
172
+ }
154
173
  }
155
- });
174
+ widget._trigger("success");
175
+ dialog.each(function (index, element) {
176
+ bootstrap.Modal.getInstance(element).hide();
177
+ });
178
+ } else {
179
+ dialog.find(".modal-body").html(xhr.responseText);
180
+ widget._bindFormEvents();
181
+ }
156
182
  },
157
183
 
158
184
  _getModal: function () {
@@ -3,9 +3,38 @@
3
3
  Keep it clean, people
4
4
  */
5
5
 
6
- $avatar-size: 30px;
7
-
8
6
  body.rails_admin {
7
+ /*
8
+ Theming custom properties. Override these from the host app (an
9
+ app/views/layouts/rails_admin/_head_custom.html.erb <style> block, or a
10
+ stylesheet targeting `body.rails_admin`) to retheme RailsAdmin without
11
+ rebuilding its CSS. Defaults reproduce the compiled-in Bootstrap theme.
12
+ */
13
+ --ra-avatar-size: 30px;
14
+ --ra-nav-link-active-bg: #{map-get($theme-colors, primary)};
15
+ --ra-nav-link-active-color: #{color-contrast(map-get($theme-colors, primary))};
16
+ --ra-nav-toggle-color: #{$gray-600};
17
+ --ra-nav-toggle-active-color: #{$gray-700};
18
+ --ra-nested-form-border-color: #{map-get($theme-colors, primary)};
19
+ --ra-nested-form-border-color-2: #{lighten(map-get($theme-colors, info), 20%)};
20
+ --ra-nested-form-border-color-3: #{lighten(
21
+ map-get($theme-colors, warning),
22
+ 30%
23
+ )};
24
+ --ra-nested-form-border-color-4: #{lighten(
25
+ map-get($theme-colors, success),
26
+ 40%
27
+ )};
28
+ --ra-table-sort-caret-color: #{$dark};
29
+ --ra-table-sort-active-bg: #{rgba($info, 0.25)};
30
+ --ra-table-sticky-bg: #{if(
31
+ $table-bg == transparent,
32
+ if($body-bg == transparent, #fff, $body-bg),
33
+ $table-bg
34
+ )};
35
+ --ra-table-sort-sticky-bg: #e2eff6;
36
+ --ra-autocomplete-font-size: #{$font-size-base * 1.1};
37
+
9
38
  .thumbnail {
10
39
  display: inline-block;
11
40
  }
@@ -19,10 +48,10 @@ body.rails_admin {
19
48
 
20
49
  img {
21
50
  position: absolute;
22
- top: calc((40px - $avatar-size) / 2);
51
+ top: calc((40px - var(--ra-avatar-size)) / 2);
23
52
 
24
53
  & + span {
25
- margin-left: ($avatar-size + 5px);
54
+ margin-left: calc(var(--ra-avatar-size) + 5px);
26
55
  }
27
56
  }
28
57
  }
@@ -36,24 +65,24 @@ body.rails_admin {
36
65
  margin-top: calc(#{$grid-gutter-width} / 2);
37
66
  padding: 3px calc(#{$grid-gutter-width} / 2);
38
67
  font-weight: bold;
39
- color: $gray-600;
68
+ color: var(--ra-nav-toggle-color);
40
69
  }
41
70
 
42
71
  .btn-toggle[aria-expanded="true"] {
43
- color: $gray-700;
72
+ color: var(--ra-nav-toggle-active-color);
44
73
  }
45
74
 
46
75
  .btn-toggle-nav > li > a {
47
76
  padding: calc(#{$navbar-padding-y} / 2) calc(#{$grid-gutter-width} / 2);
48
77
 
49
78
  &.active {
50
- background-color: map-get($theme-colors, primary);
51
- color: color-contrast(map-get($theme-colors, primary));
79
+ background-color: var(--ra-nav-link-active-bg);
80
+ color: var(--ra-nav-link-active-color);
52
81
  }
53
82
 
54
83
  &:hover {
55
- background-color: map-get($theme-colors, primary);
56
- color: color-contrast(map-get($theme-colors, primary));
84
+ background-color: var(--ra-nav-link-active-bg);
85
+ color: var(--ra-nav-link-active-color);
57
86
  }
58
87
 
59
88
  &.nav-level-1 {
@@ -80,7 +109,7 @@ body.rails_admin {
80
109
  /* nested forms */
81
110
  .tab-content {
82
111
  .tab-pane {
83
- border-left: 5px solid map-get($theme-colors, primary);
112
+ border-left: 5px solid var(--ra-nested-form-border-color);
84
113
  position: relative;
85
114
 
86
115
  fieldset {
@@ -111,7 +140,7 @@ body.rails_admin {
111
140
 
112
141
  /* double nesting, guys. Easy. */
113
142
  .tab-content .tab-content .tab-pane {
114
- border-color: lighten(map-get($theme-colors, info), 20%);
143
+ border-color: var(--ra-nested-form-border-color-2);
115
144
  margin-left: 10px;
116
145
 
117
146
  .form-group {
@@ -121,7 +150,7 @@ body.rails_admin {
121
150
 
122
151
  /* triple nesting!*/
123
152
  .tab-content .tab-content .tab-content .tab-pane {
124
- border-color: lighten(map-get($theme-colors, warning), 30%);
153
+ border-color: var(--ra-nested-form-border-color-3);
125
154
  margin-left: 20px;
126
155
 
127
156
  .form-group {
@@ -131,7 +160,7 @@ body.rails_admin {
131
160
 
132
161
  /* totally awesome! nesting on 4 levels! */
133
162
  .tab-content .tab-content .tab-content .tab-content .tab-pane {
134
- border-color: lighten(map-get($theme-colors, success), 40%);
163
+ border-color: var(--ra-nested-form-border-color-4);
135
164
  margin-left: 30px;
136
165
 
137
166
  .form-group {
@@ -183,13 +212,13 @@ body.rails_admin {
183
212
  margin-right: -16px;
184
213
  border-width: 0 4px 4px;
185
214
  border-style: solid;
186
- border-color: $dark transparent;
215
+ border-color: var(--ra-table-sort-caret-color) transparent;
187
216
  visibility: hidden;
188
217
  }
189
218
  }
190
219
  .headerSortUp,
191
220
  .headerSortDown {
192
- background-color: rgba($info, 0.25);
221
+ background-color: var(--ra-table-sort-active-bg);
193
222
  text-shadow: 0 1px 1px rgba($light, 0.75);
194
223
  }
195
224
  .header:hover {
@@ -209,7 +238,7 @@ body.rails_admin {
209
238
  border-bottom: none;
210
239
  border-left: 4px solid transparent;
211
240
  border-right: 4px solid transparent;
212
- border-top: 4px solid $dark;
241
+ border-top: 4px solid var(--ra-table-sort-caret-color);
213
242
  visibility: visible;
214
243
  @include box-shadow(none);
215
244
  opacity: 60;
@@ -299,21 +328,15 @@ body.rails_admin {
299
328
  }
300
329
 
301
330
  // Remove transparency on sticky cells.
302
- $table-bg-default: if(
303
- $table-bg == transparent,
304
- if($body-bg == transparent, #fff, $body-bg),
305
- $table-bg
306
- ) !default;
307
331
  .table-striped > tbody > tr > td,
308
332
  .table-striped > thead > tr > th {
309
- background-color: $table-bg-default;
333
+ background-color: var(--ra-table-sticky-bg);
310
334
  }
311
- $table-bg-header-sort: #e2eff6 !default;
312
335
  .table .sticky,
313
336
  .table .last {
314
337
  &.headerSortUp,
315
338
  &.headerSortDown {
316
- background-color: $table-bg-header-sort;
339
+ background-color: var(--ra-table-sort-sticky-bg);
317
340
  }
318
341
  }
319
342
  }
@@ -12,7 +12,31 @@
12
12
  /*** Font-awesome ***/
13
13
 
14
14
  $fa-font-path: "~@fortawesome/fontawesome-free/webfonts" !default;
15
- @import "@fortawesome/fontawesome-free/scss/solid";
15
+ @import "@fortawesome/fontawesome-free/scss/functions";
16
+ @import "@fortawesome/fontawesome-free/scss/variables";
17
+
18
+ // Font Awesome's scss/solid, inlined so we can ship the woff2 face without the
19
+ // .ttf fallback (388 KB of dead weight - every browser that can run RailsAdmin
20
+ // supports woff2). Keep in sync with node_modules/@fortawesome/fontawesome-free/scss/solid.scss.
21
+ :root,
22
+ :host {
23
+ --#{$fa-css-prefix}-style-family-classic: "#{$fa-style-family}";
24
+ --#{$fa-css-prefix}-font-solid: normal 900 1em/1 "#{$fa-style-family}";
25
+ }
26
+
27
+ @font-face {
28
+ font-family: "Font Awesome 6 Free";
29
+ font-style: normal;
30
+ font-weight: 900;
31
+ font-display: $fa-font-display;
32
+ src: url("#{$fa-font-path}/fa-solid-900.woff2") format("woff2");
33
+ }
34
+
35
+ .fas,
36
+ .#{$fa-css-prefix}-solid {
37
+ font-weight: 900;
38
+ }
39
+
16
40
  @import "@fortawesome/fontawesome-free/scss/fontawesome";
17
41
 
18
42
  /*** Bootstrap ***/
@@ -1,68 +1,29 @@
1
- .ui-widget {
2
- font-family: Arial, sans-serif;
3
- font-size: 1.1em;
4
- }
5
- .ui-widget .ui-widget {
6
- font-size: 1em;
7
- }
8
- .ui-widget input,
9
- .ui-widget select,
10
- .ui-widget textarea,
11
- .ui-widget button {
12
- font-family: Arial, sans-serif;
13
- font-size: 1em;
14
- }
15
- .ui-widget-content {
16
- border: 1px solid #b6b6b6;
17
- background: #ffffff;
18
- color: #4f4f4f;
19
- }
20
- .ui-widget-content a {
21
- color: #4f4f4f;
22
- }
23
-
24
- .ui-menu {
25
- list-style: none;
26
- padding: 2px;
27
- margin: 0;
28
- display: block;
29
- float: left;
30
- }
31
- .ui-menu .ui-menu {
32
- margin-top: -3px;
33
- }
34
- .ui-menu .ui-menu-item {
35
- margin: 0;
36
- padding: 0;
37
- zoom: 1;
38
- float: left;
39
- clear: left;
40
- width: 100%;
41
- }
42
- .ui-menu .ui-menu-item a {
43
- text-decoration: none;
44
- display: block;
45
- padding: 0.2em 0.4em;
46
- line-height: 1.5;
47
- zoom: 1;
48
- }
49
- .ui-menu .ui-menu-item a.ui-state-hover,
50
- .ui-menu .ui-menu-item a.ui-state-active {
51
- font-weight: normal;
52
- margin: -1px;
53
- background: #5f83b9;
54
- color: #ffffff;
55
- text-shadow: 0px 1px 1px #234386;
56
- border-color: #466086;
57
- border-radius: 0;
58
- }
59
-
1
+ /*
2
+ The jQuery UI autocomplete menu. filtering-select.js renders it with Bootstrap's
3
+ .dropdown-menu / .dropdown-item classes, so only what Bootstrap does not cover
4
+ belongs here.
5
+ */
60
6
  .ui-autocomplete {
61
- position: absolute;
62
7
  cursor: default;
8
+
9
+ /* A touch larger than the surrounding form, as the pre-Bootstrap menu was. */
10
+ --bs-dropdown-font-size: var(--ra-autocomplete-font-size);
11
+
12
+ /* Above .modal (1055), so the menu is usable in the nested-form modal. */
63
13
  z-index: 1056 !important;
64
- border-radius: 0;
65
- box-shadow: 0 1px 5px rgba(0, 0, 0, 0.3);
14
+
15
+ /* Bootstrap only emits this with $enable-shadows; the menu floats over the form. */
16
+ box-shadow: var(--bs-dropdown-box-shadow);
17
+
18
+ /*
19
+ jQuery UI marks the focused item - by keyboard or by pointer - as
20
+ .ui-state-active rather than leaving it to :hover, so it takes the styling
21
+ Bootstrap gives .dropdown-item.active.
22
+ */
23
+ .dropdown-item.ui-state-active {
24
+ color: var(--bs-dropdown-link-active-color);
25
+ background-color: var(--bs-dropdown-link-active-bg);
26
+ }
66
27
  }
67
28
 
68
29
  .ui-helper-hidden-accessible {
@@ -1,6 +1,6 @@
1
1
  import jQuery from "jquery";
2
2
  import "jquery-ui/ui/effect.js";
3
- import I18n from "./i18n";
3
+ import I18n from "./i18n.js";
4
4
 
5
5
  (function ($) {
6
6
  $(document).on("click", "#list input.toggle", function () {
@@ -48,7 +48,7 @@ import jQuery from 'jquery';
48
48
  // Make a unique ID for the new child
49
49
  var regexp = new RegExp('new_' + assoc, 'g');
50
50
  var new_id = this.newId();
51
- content = $.trim(content.replace(regexp, new_id));
51
+ content = content.replace(regexp, new_id).trim();
52
52
 
53
53
  var field = this.insertFields(content, assoc, link);
54
54
  // bubble up event upto document (through form)
@@ -71,13 +71,13 @@ import jQuery from 'jquery';
71
71
  removeFields: function(e) {
72
72
  var $link = $(e.currentTarget),
73
73
  assoc = $link.data('association'); // Name of child to be removed
74
-
74
+
75
75
  var hiddenField = $link.prev('input[type=hidden]');
76
76
  hiddenField.val('1');
77
-
77
+
78
78
  var field = $link.closest('.fields');
79
79
  field.hide();
80
-
80
+
81
81
  field
82
82
  .trigger({ type: 'nested:fieldRemoved', field: field })
83
83
  .trigger({ type: 'nested:fieldRemoved:' + assoc, field: field });
@@ -1,10 +1,18 @@
1
1
  import jQuery from "jquery";
2
2
  import "jquery-ui/ui/widgets/sortable.js";
3
3
  import * as bootstrap from "bootstrap";
4
- import flatpickr from "flatpickr";
5
- import I18n from "./i18n";
4
+ import flatpickr from "./flatpickr.js";
5
+ import I18n from "./i18n.js";
6
6
 
7
7
  (function ($) {
8
+ // Editors write back to their textarea on native submit, which modals skip.
9
+ function flushBeforeRemoteSubmit(element, flush) {
10
+ var form = element.closest("form");
11
+ if (form) {
12
+ form.addEventListener("rails_admin.before_remote_submit", flush);
13
+ }
14
+ }
15
+
8
16
  document.addEventListener("rails_admin.dom_ready", function (event) {
9
17
  var $editors,
10
18
  array,
@@ -267,10 +275,10 @@ import I18n from "./i18n";
267
275
  .find("[data-richtext=simplemde]")
268
276
  .not(".simplemded")
269
277
  .each(function (index, domEle) {
270
- var instance_config, options;
278
+ var instance_config, options, editor;
271
279
  options = $(this).data("options");
272
280
  instance_config = options.instance_config;
273
- new window.SimpleMDE(
281
+ editor = new window.SimpleMDE(
274
282
  $.extend(
275
283
  true,
276
284
  {
@@ -282,7 +290,14 @@ import I18n from "./i18n";
282
290
  instance_config
283
291
  )
284
292
  );
293
+ flushBeforeRemoteSubmit(this, function () {
294
+ editor.codemirror.save();
295
+ });
285
296
  $(this).addClass("simplemded");
297
+ // CodeMirror mismeasures itself while hidden; refresh() once it's actually laid out.
298
+ new ResizeObserver(function () {
299
+ editor.codemirror.refresh();
300
+ }).observe(editor.codemirror.getWrapperElement());
286
301
  });
287
302
  };
288
303
  $editors = content.find("[data-richtext=simplemde]").not(".simplemded");
@@ -315,7 +330,13 @@ import I18n from "./i18n";
315
330
  instance.destroy(true);
316
331
  }
317
332
  } catch (error1) {}
318
- window.CKEDITOR.replace(this, $(this).data("options").options);
333
+ var editor = window.CKEDITOR.replace(
334
+ this,
335
+ $(this).data("options").options
336
+ );
337
+ flushBeforeRemoteSubmit(this, function () {
338
+ editor.updateElement();
339
+ });
319
340
  $(this).addClass("ckeditored");
320
341
  });
321
342
  };
@@ -351,7 +372,13 @@ import I18n from "./i18n";
351
372
  options["locations"]["theme"] +
352
373
  '" rel="stylesheet" media="all" type="text/css">'
353
374
  );
354
- CodeMirror.fromTextArea(textarea, options["options"]);
375
+ var editor = CodeMirror.fromTextArea(
376
+ textarea,
377
+ options["options"]
378
+ );
379
+ flushBeforeRemoteSubmit(textarea, function () {
380
+ editor.save();
381
+ });
355
382
  return $(textarea).addClass("codemirrored");
356
383
  }
357
384
  );
@@ -385,7 +412,10 @@ import I18n from "./i18n";
385
412
  return array.each(function () {
386
413
  $(this).addClass("bootstrap-wysihtml5ed");
387
414
  $(this).closest(".controls").addClass("well");
388
- $(this).wysihtml5(config_options);
415
+ var $textarea = $(this).wysihtml5(config_options);
416
+ flushBeforeRemoteSubmit(this, function () {
417
+ $textarea.val($textarea.data("wysihtml5").editor.getValue());
418
+ });
389
419
  });
390
420
  };
391
421
  })(this);
@@ -395,7 +425,7 @@ import I18n from "./i18n";
395
425
  if (array.length) {
396
426
  this.array = array;
397
427
  options = $(array[0]).data("options");
398
- config_options = $.parseJSON(options["config_options"]);
428
+ config_options = JSON.parse(options["config_options"]);
399
429
  if (!window.wysihtml5) {
400
430
  $("head").append(
401
431
  '<link href="' +
@@ -419,7 +449,7 @@ import I18n from "./i18n";
419
449
  return array.each(function () {
420
450
  var uploadEnabled;
421
451
  options = $(this).data("options");
422
- config_options = $.parseJSON(options["config_options"]);
452
+ config_options = JSON.parse(options["config_options"]);
423
453
  if (config_options) {
424
454
  if (!config_options["inlineMode"]) {
425
455
  config_options["inlineMode"] = false;
@@ -437,7 +467,10 @@ import I18n from "./i18n";
437
467
  })
438
468
  : void 0;
439
469
  $(this).addClass("froala-wysiwyged");
440
- $(this).froalaEditor(config_options);
470
+ var $textarea = $(this).froalaEditor(config_options);
471
+ flushBeforeRemoteSubmit(this, function () {
472
+ $textarea.val($textarea.froalaEditor("html.get"));
473
+ });
441
474
  if (uploadEnabled) {
442
475
  $(this)
443
476
  .on("froalaEditor.image.error", function (e, editor, error) {
@@ -468,7 +501,7 @@ import I18n from "./i18n";
468
501
  .not(".froala-wysiwyged");
469
502
  if (array.length) {
470
503
  options = $(array[0]).data("options");
471
- if (!$.isFunction($.fn.editable)) {
504
+ if (typeof $.fn.editable !== "function") {
472
505
  $("head").append(
473
506
  '<link href="' +
474
507
  options["csspath"] +