active_scaffold 4.3.2 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +26 -0
  3. data/README.md +4 -6
  4. data/app/assets/javascripts/active_scaffold/active_scaffold.js +104 -12
  5. data/app/assets/javascripts/active_scaffold/draggable_lists.js +4 -3
  6. data/app/assets/javascripts/active_scaffold/load.js +20 -5
  7. data/app/assets/stylesheets/active_scaffold/_images.scss +53 -1
  8. data/app/assets/stylesheets/active_scaffold/_layout.scss +1 -66
  9. data/app/views/active_scaffold_overrides/_add_existing_form.html.erb +17 -11
  10. data/app/views/active_scaffold_overrides/_base_form.html.erb +29 -19
  11. data/app/views/active_scaffold_overrides/_field_search.html.erb +9 -9
  12. data/app/views/active_scaffold_overrides/_field_search_columns.html.erb +29 -33
  13. data/app/views/active_scaffold_overrides/_form.html.erb +43 -34
  14. data/app/views/active_scaffold_overrides/_form_association.html.erb +3 -3
  15. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +20 -16
  16. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +3 -4
  17. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +2 -1
  18. data/app/views/active_scaffold_overrides/_list.html.erb +6 -4
  19. data/app/views/active_scaffold_overrides/_list_calculations.html.erb +1 -1
  20. data/app/views/active_scaffold_overrides/_list_header.html.erb +3 -3
  21. data/app/views/active_scaffold_overrides/_list_messages.html.erb +19 -19
  22. data/app/views/active_scaffold_overrides/_list_messages_content.html.erb +5 -5
  23. data/app/views/active_scaffold_overrides/_list_pagination.html.erb +7 -5
  24. data/app/views/active_scaffold_overrides/_list_pagination_links.html.erb +5 -3
  25. data/app/views/active_scaffold_overrides/_list_record.html.erb +13 -8
  26. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +8 -8
  27. data/app/views/active_scaffold_overrides/_messages.html.erb +3 -3
  28. data/app/views/active_scaffold_overrides/_render_field.js.erb +8 -11
  29. data/app/views/active_scaffold_overrides/_search.html.erb +7 -6
  30. data/app/views/active_scaffold_overrides/_show.html.erb +4 -4
  31. data/app/views/active_scaffold_overrides/_show_actions.html.erb +2 -2
  32. data/app/views/active_scaffold_overrides/_show_columns.html.erb +28 -30
  33. data/app/views/active_scaffold_overrides/add_existing.js.erb +7 -4
  34. data/app/views/active_scaffold_overrides/render_field.js.erb +1 -1
  35. data/config/locales/de.yml +2 -1
  36. data/config/locales/en.yml +33 -32
  37. data/config/locales/es.yml +15 -14
  38. data/config/locales/fr.yml +3 -2
  39. data/config/locales/hu.yml +3 -2
  40. data/config/locales/ja.yml +2 -1
  41. data/config/locales/ro.yml +169 -0
  42. data/config/locales/ru.yml +8 -7
  43. data/config/locales/ta.yml +7 -6
  44. data/config/locales/zh_Hans.yml +14 -13
  45. data/lib/active_scaffold/actions/common_search.rb +1 -14
  46. data/lib/active_scaffold/actions/core.rb +55 -16
  47. data/lib/active_scaffold/actions/field_search.rb +2 -2
  48. data/lib/active_scaffold/actions/list.rb +35 -13
  49. data/lib/active_scaffold/actions/nested.rb +31 -7
  50. data/lib/active_scaffold/actions/show.rb +1 -1
  51. data/lib/active_scaffold/active_record_permissions.rb +1 -1
  52. data/lib/active_scaffold/attribute_params.rb +2 -1
  53. data/lib/active_scaffold/bridges/date_picker/helper.rb +14 -0
  54. data/lib/active_scaffold/bridges/date_picker.rb +10 -0
  55. data/lib/active_scaffold/config/list.rb +10 -1
  56. data/lib/active_scaffold/core.rb +9 -6
  57. data/lib/active_scaffold/data_structures/action_columns.rb +2 -0
  58. data/lib/active_scaffold/data_structures/column.rb +27 -6
  59. data/lib/active_scaffold/data_structures/filter.rb +4 -0
  60. data/lib/active_scaffold/data_structures/nested_info.rb +8 -1
  61. data/lib/active_scaffold/data_structures/sorting.rb +1 -1
  62. data/lib/active_scaffold/engine.rb +6 -0
  63. data/lib/active_scaffold/extensions/action_view_rendering.rb +1 -1
  64. data/lib/active_scaffold/extensions/active_record_session_store.rb +49 -0
  65. data/lib/active_scaffold/finder.rb +73 -21
  66. data/lib/active_scaffold/helpers/action_link_helpers.rb +43 -18
  67. data/lib/active_scaffold/helpers/assets_helpers.rb +4 -4
  68. data/lib/active_scaffold/helpers/filter_helpers.rb +3 -3
  69. data/lib/active_scaffold/helpers/form_column_helpers.rb +34 -22
  70. data/lib/active_scaffold/helpers/form_ui_helpers.rb +15 -10
  71. data/lib/active_scaffold/helpers/framework_ui_helpers.rb +22 -0
  72. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -0
  73. data/lib/active_scaffold/helpers/list_column_helpers.rb +19 -0
  74. data/lib/active_scaffold/helpers/pagination_helpers.rb +28 -7
  75. data/lib/active_scaffold/helpers/search_column_helpers.rb +32 -5
  76. data/lib/active_scaffold/helpers/tabs_helpers.rb +7 -7
  77. data/lib/active_scaffold/helpers/view_helpers.rb +12 -0
  78. data/lib/active_scaffold/tableless.rb +11 -8
  79. data/lib/active_scaffold/version.rb +2 -2
  80. data/lib/active_scaffold.rb +169 -0
  81. data/lib/generators/active_scaffold/install/install_generator.rb +216 -111
  82. data/lib/tasks/bundle.rake +2 -1
  83. data/lib/tasks/mock_app.rake +43 -0
  84. metadata +21 -7
  85. data/shoulda_macros/macros.rb +0 -145
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d91707ceb87840fe28313d879f1c013d577ee96ed32bebe8943a39179cdbf380
4
- data.tar.gz: 43e8949c1b351f672f11c99f6df2cf274262df5e3fbd7ce1c75b10f49c290ef3
3
+ metadata.gz: 62f92c20382d4b5a33b53bb1525e677d81259a2d89a51996caefcb68ab314ed2
4
+ data.tar.gz: 2b8b5f59b6bdf856af6bdb4cfd5697caca0095960c41278bdb16ea5d51e0d03b
5
5
  SHA512:
6
- metadata.gz: a28f9c8088844f67c7cd5dea3c9221f15d998d6fcb89617639bb5092501e21a5ac2d5c49927877244d5b2b99579da370272203caec7b3159c9035dafdc02f7c1
7
- data.tar.gz: c49905306ccda62812b8ca6ed24d25fc4c490948f56cfd2a1ab9e403fc483962080f4b0911e29db9dce97572fd82473a5a65de3f0c5a26bce95a1449058fcece
6
+ metadata.gz: cffce904d4531775442f630fe004153a6ff602fdf7d1d416601712038324d0ad27b75c0e075dca01cefe0cc05d103769de538c2295ae5ab0d670a85944bf59c7
7
+ data.tar.gz: d7b32cbea9ac2da0d506de89ccd6dd5fbfefd7f3565780e4c93d97308bf2e1808d3a4bf396e63d7f7aeaedef7b72efaa2dd03c1d9f63fb7f49390a23382e8bdf
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,29 @@
1
+ = 4.4.1
2
+ - Avoid unnecessary DISTINCT in searches without joins or with only belongs_to joins, fixing PostgreSQL searches on models with json columns
3
+ - Update install generator for the supported rails versions and asset pipelines
4
+ - Fix rendering field descriptions and tabbed forms when custom input helpers return frozen strings
5
+ - Fix inline action links with rails-ujs on Rails 8.1 by inserting the raw HTML response instead of its parsed Document
6
+ - Preserve nested ActiveScaffold session changes with activerecord-session_store 2.3.0
7
+
8
+ = 4.4.0
9
+ - Add support for local sorting using JS when the list has no pagination
10
+ - Add UI rendering customization for CSS framework and theme integration: configure tags and HTML attributes for named elements, use context-aware procs, and override focused helpers when structural markup must change
11
+ - Fix draggable lists to set hover class on the list while dragging
12
+ - Support defining more options for jQuery.sortable with ActiveScaffold.js_config[:draggable_lists_options]
13
+ - Support changing highlight duration with ActiveScaffold.js_config[:highlight]
14
+ - ActiveScaffold now calls order with hash, leaving the quoting of tables and columns to rails, Arel.sql must be called on the values set on sort_by if rails requires it
15
+ - Column search_sql accepts a symbol and uses symbol by default, delay quoting until query is generated, strings are still supported for cross-table columns or functions
16
+ - Use nonce: true in active_scaffold_javascript_tag so rails app can setup CSP with nonce in script-src
17
+ - Filtering by params support using range syntax (A..B) supports infinite ranges now, such as ..A or A..
18
+ - Speed up listing when all records fit in the first page and it's not full, count query can be avoided.
19
+ - Better PostgreSQL support, accept condition from URL for timestamp and timestamptz columns from PostgreSQL, as done with datetime MySQL columns
20
+ - Applied and ignored filters (due to be disallowed or unknown) are tracked with @filter_states
21
+ - Fix cache column counts on PostgreSQL when the association has order
22
+ - Fix list with ordering using sql functions and left joins in PostgreSQL
23
+ - Columns with includes and searching in other table won't have includes eager loaded in the same query when they are in the list columns, as may load only the records matching the search. Also, makes aliases when searching in multiple associations on the same table not depending on what columns are in the list columns.
24
+ - Support configuring the text search operator per column, defaulting to LIKE for collated PostgreSQL columns
25
+ - return empty collection for out-of-range method-sorted pages
26
+
1
27
  = 4.3.2
2
28
  - Fix adding tab in tabbed forms
3
29
 
data/README.md CHANGED
@@ -41,11 +41,9 @@ Add jquery-rails to Gemfile, or handle jquery with other tools like webpack or i
41
41
  gem 'jquery-rails'
42
42
  ```
43
43
 
44
- For rails 7.x, install generator will add `active_scaffold` to `config/importmap.rb`, `app/javascript/application.js`, and `active_scaffold/manifest.js` to `app/assets/config/manifest.js`. It will add `jquery` and `jquery_ujs` to all the 3 files if jquery-rails gem is available.
44
+ On supported Rails versions (7.2 and 8.x), the install generator adds the ActiveScaffold route concerns and the lines required to load its JavaScript and stylesheets for the detected asset pipeline. With import maps, this includes both the pins in `config/importmap.rb` and the imports in `app/javascript/application.js`. With Propshaft, it adds the required helpers to the application layout; with Sprockets, it updates the asset manifests instead.
45
45
 
46
- For rails 6.1, install generator will create `app/assets/javascripts/application.js`, add it, and `active_scaffold/manifest.js`, to `app/assets/config/manifest.js` and add `javascript_include_tag` in the layout, as ActiveScaffold doesn't work with webpack. It will add `jquery` to `app/assets/javascripts/application.js` too if query-rails gem is available, although Jquery may be loaded by packs too and it will work, it won't add `jquery_ujs` or `@rails/ujs` as it's added to `app/javascript/packs/application.js` by default.
47
-
48
- -- TODO: Add notes about dartsass-rails for propshaft or dartsass-sprockets for sprockets.
46
+ For Dart Sass, the generator adds the appropriate `@use` line to `app/assets/stylesheets/application.scss`. It can also update an older `application.css` or `application.css.erb` that contains Sprockets require directives. If `jquery-rails` is installed, the generator adds `jquery` and `jquery_ujs` to the same JavaScript setup. The exact lines for each supported setup are described in [Stylesheet Loading](#stylesheet-loading) and [Javascript Loading](#javascript-loading).
49
47
 
50
48
  Run the following commands
51
49
 
@@ -124,14 +122,14 @@ import 'jquery_ujs'
124
122
  import 'active_scaffold'
125
123
  ```
126
124
 
127
- In the layout, load the importmap modules and call active_scaffold_javascript_tag, that includes some script tags which was in js.erb when using sprockets, so JS ActiveScaffold dependencies are loaded (jquery UI if using jquery-ui-rails, and JS for other ActiveScaffold plugins and bridges):
125
+ In the layout, load the importmap modules and call active_scaffold_javascript_tag, that includes some script tags that were in js.erb when using sprockets, so JS ActiveScaffold dependencies are loaded (jquery UI if using jquery-ui-rails, and JS for other ActiveScaffold plugins and bridges):
128
126
 
129
127
  ```erb
130
128
  <%= javascript_importmap_tags %>
131
129
  <%= active_scaffold_javascript_tag %>
132
130
  ```
133
131
 
134
- ### Propshaft
132
+ ### Propshaft without import maps
135
133
 
136
134
  If you're not using importmaps, then you can load the JS files individually, but you only need to load jquery and jquery_ujs or rails_ujs, and then call active_scaffold_javascript_tag:
137
135
 
@@ -90,7 +90,7 @@
90
90
  },
91
91
  setup_history_state: function() {
92
92
  if (!jQuery('.active-scaffold').length) return;
93
- var data = {}, current_search_item = jQuery('.active-scaffold .filtered-message[data-search]');
93
+ var data = {}, current_search_item = jQuery('.active-scaffold .messages-container [data-search]');
94
94
  if (current_search_item.length) {
95
95
  // store user settings enabled, update state with current page, search and sorting
96
96
  var sorted_columns = jQuery('th.sorted');
@@ -117,6 +117,80 @@
117
117
  auto_load_page: function(href, params) {
118
118
  jQuery.get(href, params, null, 'script');
119
119
  },
120
+ sort_table: function(table, column, descending) {
121
+ // Group rows: each group starts with a sortable row + its adapter rows
122
+ var groups = [], currentGroup = [], $tbody = table.find('.records:first');
123
+
124
+ $tbody.children('tr').each(function() {
125
+ var $row = $(this);
126
+ if (!$row.hasClass('as_adapter')) {
127
+ // Start a new group for sortable rows
128
+ if (currentGroup.length > 0) {
129
+ groups.push(currentGroup);
130
+ }
131
+ currentGroup = [$row];
132
+ } else {
133
+ // Add adapter row to current group (or create orphan group if none exists)
134
+ if (currentGroup.length > 0) {
135
+ currentGroup.push($row);
136
+ } else {
137
+ //groups.push([$row]); // Orphaned adapter
138
+ }
139
+ }
140
+ });
141
+ if (currentGroup.length > 0) {
142
+ groups.push(currentGroup);
143
+ }
144
+
145
+ // Sort groups by the first row's cell value
146
+ groups.sort(function(groupA, groupB) {
147
+ // Get sort key for group A (empty string if adapter-only group)
148
+ var keyA = ActiveScaffold.sort_value(groupA[0], column),
149
+ keyB = ActiveScaffold.sort_value(groupB[0], column),
150
+ comparison;
151
+
152
+ if (Array.isArray(keyA) && Array.isArray(keyB)) {
153
+ comparison = ActiveScaffold.compare_arrays(keyA, keyB);
154
+ } else if (typeof keyA === 'number' && typeof keyB === 'number') {
155
+ comparison = keyA - keyB;
156
+ } else {
157
+ comparison = keyA.toString().toLowerCase().localeCompare(keyB.toString().toLowerCase());
158
+ }
159
+
160
+ return descending ? -comparison : comparison;
161
+ });
162
+
163
+ // Rebuild tbody with sorted groups
164
+ $tbody.children().detach();
165
+ var fragment = document.createDocumentFragment(); // Create a DocumentFragment to minimize reflows
166
+ groups.forEach(function(group) {
167
+ group.forEach(function($row) {
168
+ fragment.appendChild($row[0]); // $row[0] is the DOM element
169
+ });
170
+ });
171
+ $tbody[0].appendChild(fragment);
172
+ },
173
+ sort_value: function(row, column) {
174
+ var $cell = row.find(`> .${column}-column`), value = $cell.data('sort-value');
175
+ if (value === undefined) value = $cell.text(); // Automatically strips HTML
176
+ return value;
177
+ },
178
+ compare_arrays: function(arrA, arrB) {
179
+ var len = Math.min(arrA.length, arrB.length);
180
+ for (var i = 0; i < len; i++) {
181
+ var a = arrA[i], b = arrB[i];
182
+
183
+ var isNumA = typeof a === 'number', isNumB = typeof b === 'number';
184
+ if (typeof a === 'number' && typeof b === 'number') {
185
+ if (a !== b) return a - b;
186
+ } else {
187
+ var cmp = a.toString().toLowerCase().localeCompare(b.toString().toLowerCase());
188
+ if (cmp !== 0) return cmp;
189
+ }
190
+ }
191
+ // If all elements so far are equal, shorter array comes first
192
+ return arrA.length - arrB.length;
193
+ },
120
194
  enable_js_form_buttons: function(element) {
121
195
  jQuery('.as-js-button', element).show();
122
196
  },
@@ -166,7 +240,7 @@
166
240
  item.closest('.active-scaffold-component').load(item.attr('href'), function(response, status, xhr) {
167
241
  if (status == 'error') {
168
242
  indicator.css({visibility: 'hidden'});
169
- indicator.after(jQuery('<p>').html(item.data('error-msg')).addClass("error-message message server-error"));
243
+ indicator.after(item.data('error-msg'));
170
244
  } else jQuery(this).trigger('as:element_updated');
171
245
  });
172
246
  });
@@ -203,12 +277,12 @@
203
277
  },
204
278
  hide_empty_message: function(tbody) {
205
279
  if (this.records_for(tbody).length != 0) {
206
- jQuery(tbody).parent().find('tbody.messages p.empty-message').hide();
280
+ jQuery(tbody).parent().find('.messages-container .empty-message').hide();
207
281
  }
208
282
  },
209
283
  show_empty_message: function(tbody) {
210
284
  if (this.records_for(tbody).length != 0) {
211
- jQuery(tbody).parent().find('tbody.messages p.empty-message').hide();
285
+ jQuery(tbody).parent().find('.messages-container .empty-message').hide();
212
286
  }
213
287
  },
214
288
  reload_if_empty: function(tbody, url) {
@@ -503,7 +577,7 @@
503
577
  highlight: function(element) {
504
578
  if (typeof(element) == 'string') element = jQuery('#' + element);
505
579
  if (typeof(element.effect) == 'function') {
506
- element.effect("highlight", jQuery.extend({}, ActiveScaffold.config.highlight), 3000);
580
+ element.effect("highlight", jQuery.extend({duration: 3000}, ActiveScaffold.config.highlight));
507
581
  }
508
582
  },
509
583
 
@@ -534,7 +608,7 @@
534
608
  var source = jQuery(source);
535
609
  var element, container = source.closest('.sub-form-record'), selector = '';
536
610
  if (container.length === 0) {
537
- container = source.closest('form > ol.form');
611
+ container = source.closest('form > .form');
538
612
  selector = '>';
539
613
  }
540
614
  if (options.traverse) {
@@ -1265,7 +1339,12 @@
1265
1339
  return true;
1266
1340
  });
1267
1341
  jQuery(document).on('ajax:success', 'a.as_action', function(event, response) {
1268
- if (event.detail && !response) response = event.detail[0];
1342
+ if (event.detail && !response) {
1343
+ response = event.detail[0];
1344
+ // rails-ujs parses text/html responses into a Document, which cannot be inserted and
1345
+ // loses table rows parsed outside a table, so use the raw response from the XHR.
1346
+ if (response instanceof Document && event.detail[2]) response = event.detail[2].responseText;
1347
+ }
1269
1348
  var action_link = ActiveScaffold.ActionLink.get(jQuery(this));
1270
1349
  if (action_link) {
1271
1350
  if (action_link.position) {
@@ -1354,9 +1433,22 @@
1354
1433
  return true;
1355
1434
  });
1356
1435
  jQuery(document).on('ajax:before', 'a.as_sort', function(event) {
1357
- var as_sort = jQuery(this);
1358
- as_sort.closest('th').addClass('loading');
1359
- return true;
1436
+ var as_sort = jQuery(this), table = as_sort.closest('.list-table'),
1437
+ header_cell = as_sort.closest('[class$="-column_heading"],[class*="-column_heading "]'),
1438
+ ascending = header_cell.is('.sorted.asc');
1439
+ if (!header_cell.is('.skip-local-sorting') && table.is('.local-sorting')) {
1440
+ var match = header_cell.attr('class').match(/\b([^\s]+)-column_heading\b/);
1441
+ if (match) {
1442
+ ActiveScaffold.sort_table(table, match[1], ascending);
1443
+ header_cell.siblings().addBack().removeClass('sorted asc desc');
1444
+ header_cell.addClass('sorted ' + (ascending ? 'desc' : 'asc'));
1445
+ event.preventDefault();
1446
+ return false;
1447
+ }
1448
+ } else {
1449
+ as_sort.closest('th').addClass('loading');
1450
+ return true;
1451
+ }
1360
1452
  });
1361
1453
  jQuery(document).on('ajax:error', 'a.as_sort', function(event, xhr, status, error) {
1362
1454
  if (event.detail && !xhr) {
@@ -1521,8 +1613,8 @@
1521
1613
  return true;
1522
1614
  });
1523
1615
 
1524
- jQuery(document).on('click', '.message a.close', function(e) {
1525
- ActiveScaffold.hide(jQuery(this).closest('.message'));
1616
+ jQuery(document).on('click', '.as-msg .msg-close', function(e) {
1617
+ ActiveScaffold.hide(jQuery(this).closest('.as-msg'));
1526
1618
  e.preventDefault();
1527
1619
  });
1528
1620
 
@@ -13,15 +13,16 @@
13
13
  });
14
14
  check_buttons.find('.check-all, .uncheck-all').attr('title', function() { return jQuery(this).text() });
15
15
  element.after(check_buttons);
16
- var options = {
17
- hoverClass: 'hover',
16
+ var options = jQuery.extend({
17
+ over: function(event, ui) { jQuery(this).addClass("hover"); },
18
+ out: function(event, ui) { jQuery(this).removeClass("hover"); },
18
19
  containment: '',
19
20
  receive: function(event, ui) {
20
21
  var input = jQuery('input:checkbox', ui.item), selected = input.prop('checked');
21
22
  input.prop('checked', jQuery(this).hasClass('selected'));
22
23
  if (selected != input.prop('checked')) input.trigger('change');
23
24
  }
24
- };
25
+ }, ActiveScaffold.config.draggable_lists_options || {});
25
26
  jQuery(element).sortable(jQuery.extend(options, {connectWith: '#'+list_selected.attr('id')}));
26
27
  jQuery(list_selected).sortable(jQuery.extend(options, {connectWith: '#'+element.attr('id')}));
27
28
  return element;
@@ -76,11 +76,26 @@
76
76
 
77
77
  const initializeJQueryUI = function() {
78
78
  if (config.jqueryUiIncluded && window.jQuery) {
79
- // Check if datepicker exists
80
- if (jQuery.datepicker) {
81
- // Execute the datepicker localization
82
- // This will be replaced by actual generated code
83
- eval(config.datepickerLocalization);
79
+ applyDatepickerLocalization();
80
+ }
81
+ };
82
+
83
+ const applyDatepickerLocalization = () => {
84
+ const localization = config.datepickerLocalization;
85
+ if (!localization) return;
86
+ const { locale, datepickerRegional, timepickerRegional } = localization;
87
+
88
+ if (jQuery.datepicker && datepickerRegional) {
89
+ Object.assign(jQuery.datepicker.regional, datepickerRegional);
90
+ if (jQuery.datepicker.regional[locale]) {
91
+ jQuery.datepicker.setDefaults(jQuery.datepicker.regional[locale]);
92
+ }
93
+ }
94
+
95
+ if (jQuery.timepicker && timepickerRegional) {
96
+ Object.assign(jQuery.timepicker.regional, timepickerRegional);
97
+ if (jQuery.timepicker.regional[locale]) {
98
+ jQuery.timepicker.setDefaults(jQuery.timepicker.regional[locale]);
84
99
  }
85
100
  }
86
101
  };
@@ -1,3 +1,32 @@
1
+ .active-scaffold-header div.actions a.new,
2
+ .active-scaffold-header div.actions a.new_existing,
3
+ .active-scaffold-header div.actions a.show_search,
4
+ .active-scaffold-header div.actions a.show_config_list,
5
+ .active-scaffold div.actions div.action_group div {
6
+ margin: 0;
7
+ padding: 5px 5px 5px 25px;
8
+ background-position: 5px 50%;
9
+ background-repeat: no-repeat;
10
+ }
11
+
12
+ .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.new,
13
+ .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.new_existing,
14
+ .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.show_search,
15
+ .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.show_config_list,
16
+ .active-scaffold .active-scaffold .active-scaffold-header div.actions div.action_group > div {
17
+ margin: 0;
18
+ padding: 1px 5px 1px 20px;
19
+ background-position: 1px 50%;
20
+ background-repeat: no-repeat;
21
+ }
22
+
23
+ .active-scaffold th.asc a,
24
+ .active-scaffold th.desc a,
25
+ .active-scaffold th.loading a {
26
+ background-position: right 50%;
27
+ background-repeat: no-repeat;
28
+ }
29
+
1
30
  .active-scaffold-header div.actions div.action_group div {
2
31
  background-image: url("active_scaffold/gears.png"); /* default icon for actions or override with css */
3
32
  }
@@ -45,10 +74,21 @@
45
74
 
46
75
  .active-scaffold a.inline-adapter-close {
47
76
  background-image: url("active_scaffold/close.png");
77
+ text-indent: 1000px;
78
+ width: 16px;
79
+ height: 17px;
80
+ background-repeat: no-repeat;
81
+ overflow: hidden;
48
82
  }
49
83
 
50
84
  .active-scaffold .sub-form .association-record a.destroy {
51
85
  background-image: url("active_scaffold/cross.png");
86
+ display: inline-block;
87
+ height: 16px;
88
+ width: 16px;
89
+ text-indent: -4000px;
90
+ background-repeat: no-repeat;
91
+ overflow: hidden;
52
92
  }
53
93
 
54
94
  .as_touch a.inline-adapter-close {
@@ -56,10 +96,22 @@
56
96
  }
57
97
  .active-scaffold .refresh-link {
58
98
  background-image: url("active_scaffold/refresh.png");
99
+ background-position: 5px 50%;
100
+ background-repeat: no-repeat;
101
+ display: inline-block;
102
+ width: 25px;
103
+ text-indent: 26px;
104
+ overflow: hidden;
105
+ white-space: nowrap;
106
+ }
107
+
108
+ .active-scaffold .refresh-link.add-tab {
109
+ background-image: url("active_scaffold/add.png");
59
110
  }
60
111
 
61
112
  .ui-dialog .loading::after {
62
- background: url("active_scaffold/indicator.gif") no-repeat;
113
+ background-image: url("active_scaffold/indicator.gif");
114
+ background-repeat: no-repeat;
63
115
  content: 'Loading...';
64
116
  padding-left: 20px;
65
117
  }
@@ -72,8 +72,6 @@ text-decoration: none;
72
72
  padding: 1px 2px;
73
73
  white-space: nowrap;
74
74
  margin-left: 5px;
75
- background-position: 1px 50%;
76
- background-repeat: no-repeat;
77
75
  }
78
76
 
79
77
  .active-scaffold div.actions a {
@@ -120,28 +118,6 @@ top: -3px;
120
118
  opacity: 0.5;
121
119
  }
122
120
 
123
- .active-scaffold-header div.actions a.new,
124
- .active-scaffold-header div.actions a.new_existing,
125
- .active-scaffold-header div.actions a.show_search,
126
- .active-scaffold-header div.actions a.show_config_list,
127
- .active-scaffold div.actions div.action_group div {
128
- margin:0;
129
- padding: 5px 5px 5px 25px;
130
- background-position: 5px 50%;
131
- background-repeat: no-repeat;
132
- }
133
-
134
- .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.new,
135
- .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.new_existing,
136
- .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.show_search,
137
- .active-scaffold .active-scaffold .active-scaffold-header div.actions > a.show_config_list,
138
- .active-scaffold .active-scaffold .active-scaffold-header div.actions div.action_group > div {
139
- margin:0;
140
- padding: 1px 5px 1px 20px;
141
- background-position: 1px 50%;
142
- background-repeat: no-repeat;
143
- }
144
-
145
121
  .active-scaffold div.actions a.disabled:hover,
146
122
  .active-scaffold div.actions a.disabled:hover {
147
123
  background-color: transparent;
@@ -179,12 +155,6 @@ padding: 2px 5px;
179
155
  padding-right: 18px;
180
156
  }
181
157
 
182
- .active-scaffold th.asc a,
183
- .active-scaffold th.desc a,
184
- .active-scaffold th.loading a {
185
- background: right 50% no-repeat;
186
- }
187
-
188
158
  .active-scaffold th .mark_heading {
189
159
  margin-left: 5px;
190
160
  }
@@ -325,20 +295,6 @@ text-align: left;
325
295
  border-top: none;
326
296
  }
327
297
 
328
- .active-scaffold .actions .action_group ul li div {
329
- margin: 0;
330
- padding: 5px 5px 5px 25px;
331
- background-position: 5px 50%;
332
- background-repeat: no-repeat;
333
- }
334
-
335
- .active-scaffold .actions .action_group ul li a {
336
- display: block;
337
- margin: 0;
338
- padding: 5px 5px 5px 25px;
339
- background-position: 5px 50%;
340
- background-repeat: no-repeat;
341
- }
342
298
  .active-scaffold .actions .action_group.dyn > ul li a {
343
299
  padding-left: 5px;
344
300
  }
@@ -376,11 +332,6 @@ border-bottom: none;
376
332
 
377
333
  .active-scaffold a.inline-adapter-close {
378
334
  float: right;
379
- text-indent: -4000px;
380
- width: 16px;
381
- height: 17px;
382
- background: 0 0 no-repeat;
383
- overflow: hidden;
384
335
  }
385
336
 
386
337
  /* Nested
@@ -906,15 +857,6 @@ padding: 1px;
906
857
  border: solid 1px;
907
858
  }
908
859
 
909
- .active-scaffold .refresh-link {
910
- display: inline-block;
911
- width: 25px;
912
- text-indent: 26px;
913
- overflow: hidden;
914
- background-position: 5px 50%;
915
- background-repeat: no-repeat;
916
- }
917
-
918
860
  .active-scaffold .checkbox-list {
919
861
  padding-left: 0px;
920
862
  }
@@ -1078,13 +1020,7 @@ clear: left;
1078
1020
 
1079
1021
  .active-scaffold .sub-form .association-record a.destroy {
1080
1022
  font-weight: bold;
1081
- display: inline-block;
1082
- height: 16px;
1083
1023
  padding: 0;
1084
- width: 16px;
1085
- text-indent: -4000px;
1086
- background: 0 0 no-repeat;
1087
- overflow: hidden;
1088
1024
  }
1089
1025
  .active-scaffold .sub-form .association-record * + a.destroy {
1090
1026
  margin-left: 5px;
@@ -1191,7 +1127,7 @@ font-size: 100%;
1191
1127
  .as_touch a.inline-adapter-close {
1192
1128
  width: 25px;
1193
1129
  height: 27px;
1194
- background: 0 0 no-repeat;
1130
+ background-repeat: no-repeat;
1195
1131
  }
1196
1132
 
1197
1133
  .as_touch .as_paginate {
@@ -1230,7 +1166,6 @@ padding: 7px 5px 7px 25px;
1230
1166
  .as_touch .active-scaffold div.actions > a.show_config_list,
1231
1167
  .as_touch .active-scaffold div.actions div.action_group > div {
1232
1168
  padding: 7px 5px 7px 25px;
1233
- background-position: 5px 50%;
1234
1169
  }
1235
1170
 
1236
1171
  .as_touch .actions .action_group ul li div {
@@ -8,21 +8,27 @@ options = {id: element_form_id(action: :add_existing),
8
8
  options[:remote] = true if xhr
9
9
  form_tag url_options, options -%>
10
10
 
11
- <h4><%= active_scaffold_config.nested.label -%></h4>
11
+ <%= as_element :form_title, active_scaffold_config.nested.label -%>
12
12
 
13
- <% if xhr -%>
14
- <div id="<%= element_messages_id(action: :add_existing) %>" class="messages-container"></div>
15
- <% else -%>
16
- <%= render 'form_messages' %>
13
+ <%= as_element :form_messages_container, id: element_messages_id(action: :add_existing), class: 'messages-container' do %>
14
+ <%= render 'form_messages' unless xhr %>
17
15
  <% end -%>
18
16
 
19
- <label for="<%= "record_#{active_scaffold_config.model}" %>"><%= active_scaffold_add_existing_label %></label>
20
- <%= active_scaffold_add_existing_input(name: 'associated_id', url_options: url_options, object: nested_parent_record) %>
21
17
 
22
- <p class="form-footer">
23
- <%= submit_tag as_(:add), class: 'submit' %>
24
- <%= link_to as_(:cancel), main_path_to_return, class: 'as_cancel', remote: true %>
18
+ <%= as_element :fields_container, class: 'form' do %>
19
+ <%= form_attribute_html(
20
+ nil,
21
+ label_tag("record_#{active_scaffold_config.model}", active_scaffold_add_existing_label),
22
+ active_scaffold_add_existing_input(name: 'associated_id', url_options: url_options, object: nested_parent_record),
23
+ nil,
24
+ {}
25
+ ) %>
26
+ <% end %>
27
+
28
+ <%= as_element :form_footer, class: 'form-footer' do %>
29
+ <%= submit_tag as_(:add), as_element_attributes(:form_submit) %>
30
+ <%= link_to as_(:cancel), main_path_to_return, as_element_attributes(:form_cancel, class: 'as_cancel', remote: true) %>
25
31
  <%= loading_indicator_tag(action: :add_existing, id: params[:id]) %>
26
- </p>
32
+ <% end %>
27
33
 
28
34
  </form>
@@ -25,17 +25,27 @@
25
25
  cancel_link = true if cancel_link.nil?
26
26
  submit_text ||= form_action
27
27
  apply_text ||= :"#{form_action}_apply"
28
+ cancel_text ||= :cancel
29
+ cancel_url ||= main_path_to_return
28
30
  body_partial ||= 'form'
29
31
  form_id = element_form_id(action: form_action, id: @record&.id)
32
+
33
+ if cancel_link
34
+ cancel_options = {class: 'as_cancel'}
35
+ cancel_options[:remote] = true if xhr # cancel link doesn't have to care about multipart forms
36
+ cancel_options = cancel_options.smart_merge cancel_attrs if local_assigns[:cancel_attrs]
37
+ end
30
38
  %>
31
39
  <%=
32
- options = {id: form_id,
33
- multipart: multipart,
34
- class: "as_form #{form_action} #{'floating-footer' if floating_footer} #{"descriptions-#{field_descriptions}" if field_descriptions != :show}",
35
- method: method,
36
- 'data-loading' => defined?(loading) ? loading : true}
37
- cancel_options = {class: 'as_cancel'}
38
- cancel_options[:remote] = true if xhr # cancel link does nt have to care about multipart forms
40
+ options = as_element_attributes(
41
+ :form,
42
+ id: form_id,
43
+ multipart: multipart,
44
+ class: "as_form #{form_action} #{'floating-footer' if floating_footer} #{"descriptions-#{field_descriptions}" if field_descriptions != :show}",
45
+ method: method,
46
+ data: {loading: defined?(loading) ? loading : true}
47
+ )
48
+
39
49
  if xhr && multipart # file_uploads
40
50
  form_remote_upload_tag url_options.merge(iframe: true), options
41
51
  else
@@ -44,26 +54,26 @@ else
44
54
  end
45
55
  -%>
46
56
  <%= hidden_field :record, @record.class.locking_column if add_locking_column && @record.persisted? && @record.locking_enabled? %>
47
- <h4><%= headline -%></h4>
57
+ <%= as_element :form_title, headline -%>
48
58
 
49
- <div id="<%= element_messages_id(action: form_action) %>" class="messages-container">
59
+ <%= as_element :form_messages_container, id: element_messages_id(action: form_action), class: 'messages-container' do %>
50
60
  <% unless xhr %>
51
- <p class="error-message message server-error" style="display:none;">
61
+ <%= server_error_msg class: 'as-msg', style: 'display:none;' do %>
52
62
  <%= as_(:internal_error).html_safe %>
53
- <a href="#" class="close" title="<%= as_(:close).html_safe %>"><%= as_(:close).html_safe %></a>
54
- </p>
63
+ <%= as_element :message_close, as_(:close), class: 'msg-close', title: as_(:close) %>
64
+ <% end %>
55
65
  <% end %>
56
66
  <%= render 'form_messages' %>
57
- </div>
67
+ <% end %>
58
68
 
59
69
  <%= render body_partial, columns: columns, form_action: form_action, scope: scope %>
60
70
 
61
- <p class="form-footer">
62
- <%= submit_tag as_(submit_text), class: 'submit' if !persistent || persistent == :optional %>
63
- <%= submit_tag as_(apply_text), class: 'submit', name: 'dont_close' if persistent %>
64
- <%= link_to(as_(:cancel), main_path_to_return, cancel_options) if cancel_link %>
65
- <%= loading_indicator_tag(action: form_action, id: @record&.id) %>
71
+ <%= as_element :form_footer, class: 'form-footer' do %>
72
+ <%= submit_tag as_(submit_text), as_element_attributes(:form_submit) if !persistent || persistent == :optional %>
73
+ <%= submit_tag as_(apply_text), as_element_attributes(:form_apply, name: 'dont_close') if persistent %>
74
+ <%= link_to as_(cancel_text), cancel_url, as_element_attributes(:form_cancel, **cancel_options) if cancel_link %>
75
+ <%= loading_indicator_tag action: form_action, id: @record&.id %>
66
76
  <%= render footer_extension, form_action: form_action if footer_extension %>
67
- </p>
77
+ <% end %>
68
78
 
69
79
  </form>