active_scaffold 4.3.2 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +19 -0
  3. data/README.md +1 -1
  4. data/app/assets/javascripts/active_scaffold/active_scaffold.js +98 -11
  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/extensions/action_view_rendering.rb +1 -1
  63. data/lib/active_scaffold/finder.rb +66 -21
  64. data/lib/active_scaffold/helpers/action_link_helpers.rb +43 -18
  65. data/lib/active_scaffold/helpers/assets_helpers.rb +4 -4
  66. data/lib/active_scaffold/helpers/filter_helpers.rb +3 -3
  67. data/lib/active_scaffold/helpers/form_column_helpers.rb +34 -22
  68. data/lib/active_scaffold/helpers/form_ui_helpers.rb +15 -10
  69. data/lib/active_scaffold/helpers/framework_ui_helpers.rb +22 -0
  70. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -0
  71. data/lib/active_scaffold/helpers/list_column_helpers.rb +19 -0
  72. data/lib/active_scaffold/helpers/pagination_helpers.rb +28 -7
  73. data/lib/active_scaffold/helpers/search_column_helpers.rb +32 -5
  74. data/lib/active_scaffold/helpers/tabs_helpers.rb +3 -5
  75. data/lib/active_scaffold/helpers/view_helpers.rb +12 -0
  76. data/lib/active_scaffold/tableless.rb +11 -8
  77. data/lib/active_scaffold/version.rb +2 -2
  78. data/lib/active_scaffold.rb +169 -0
  79. data/lib/tasks/bundle.rake +2 -1
  80. data/lib/tasks/mock_app.rake +43 -0
  81. metadata +20 -7
  82. 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: cafbb1cbb0273e33d48ba6efb723a4ac6abd3678c559031bbc10d1b608f61ad5
4
+ data.tar.gz: 7e835a08a8b21df39301360a62db0257826b5e1a654c18ef2e8fbc92d4278436
5
5
  SHA512:
6
- metadata.gz: a28f9c8088844f67c7cd5dea3c9221f15d998d6fcb89617639bb5092501e21a5ac2d5c49927877244d5b2b99579da370272203caec7b3159c9035dafdc02f7c1
7
- data.tar.gz: c49905306ccda62812b8ca6ed24d25fc4c490948f56cfd2a1ab9e403fc483962080f4b0911e29db9dce97572fd82473a5a65de3f0c5a26bce95a1449058fcece
6
+ metadata.gz: 475d62edc638cfefd7d43bf86a033d842f387968d9e90fc83b61b3da5cfc3f688e3ab8ee200ba7a56f7cebfe9659ad108494618207104ff65b1c9bad67a738c9
7
+ data.tar.gz: b4eb39a97611806f10c625111a41aa67061d35093c5caae3f89673516f3785c1692d04a3e87de3f7e8174a0b286818c10a253ec449d10f1ab8aada1ef1547cbd
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,22 @@
1
+ = 4.4.0
2
+ - Add support for local sorting using JS when the list has no pagination
3
+ - 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
4
+ - Fix draggable lists to set hover class on the list while dragging
5
+ - Support defining more options for jQuery.sortable with ActiveScaffold.js_config[:draggable_lists_options]
6
+ - Support changing highlight duration with ActiveScaffold.js_config[:highlight]
7
+ - 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
8
+ - 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
9
+ - Use nonce: true in active_scaffold_javascript_tag so rails app can setup CSP with nonce in script-src
10
+ - Filtering by params support using range syntax (A..B) supports infinite ranges now, such as ..A or A..
11
+ - Speed up listing when all records fit in the first page and it's not full, count query can be avoided.
12
+ - Better PostgreSQL support, accept condition from URL for timestamp and timestamptz columns from PostgreSQL, as done with datetime MySQL columns
13
+ - Applied and ignored filters (due to be disallowed or unknown) are tracked with @filter_states
14
+ - Fix cache column counts on PostgreSQL when the association has order
15
+ - Fix list with ordering using sql functions and left joins in PostgreSQL
16
+ - 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.
17
+ - Support configuring the text search operator per column, defaulting to LIKE for collated PostgreSQL columns
18
+ - return empty collection for out-of-range method-sorted pages
19
+
1
20
  = 4.3.2
2
21
  - Fix adding tab in tabbed forms
3
22
 
data/README.md CHANGED
@@ -124,7 +124,7 @@ import 'jquery_ujs'
124
124
  import 'active_scaffold'
125
125
  ```
126
126
 
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):
127
+ 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
128
 
129
129
  ```erb
130
130
  <%= javascript_importmap_tags %>
@@ -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) {
@@ -1354,9 +1428,22 @@
1354
1428
  return true;
1355
1429
  });
1356
1430
  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;
1431
+ var as_sort = jQuery(this), table = as_sort.closest('.list-table'),
1432
+ header_cell = as_sort.closest('[class$="-column_heading"],[class*="-column_heading "]'),
1433
+ ascending = header_cell.is('.sorted.asc');
1434
+ if (!header_cell.is('.skip-local-sorting') && table.is('.local-sorting')) {
1435
+ var match = header_cell.attr('class').match(/\b([^\s]+)-column_heading\b/);
1436
+ if (match) {
1437
+ ActiveScaffold.sort_table(table, match[1], ascending);
1438
+ header_cell.siblings().addBack().removeClass('sorted asc desc');
1439
+ header_cell.addClass('sorted ' + (ascending ? 'desc' : 'asc'));
1440
+ event.preventDefault();
1441
+ return false;
1442
+ }
1443
+ } else {
1444
+ as_sort.closest('th').addClass('loading');
1445
+ return true;
1446
+ }
1360
1447
  });
1361
1448
  jQuery(document).on('ajax:error', 'a.as_sort', function(event, xhr, status, error) {
1362
1449
  if (event.detail && !xhr) {
@@ -1521,8 +1608,8 @@
1521
1608
  return true;
1522
1609
  });
1523
1610
 
1524
- jQuery(document).on('click', '.message a.close', function(e) {
1525
- ActiveScaffold.hide(jQuery(this).closest('.message'));
1611
+ jQuery(document).on('click', '.as-msg .msg-close', function(e) {
1612
+ ActiveScaffold.hide(jQuery(this).closest('.as-msg'));
1526
1613
  e.preventDefault();
1527
1614
  });
1528
1615
 
@@ -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>
@@ -2,14 +2,14 @@
2
2
  url_options ||= params_for(action: :index, id: nil, search: nil)
3
3
  submit_text ||= :search
4
4
  xhr ||= request.xhr?
5
- options = {
5
+ options = as_element_attributes(
6
+ :field_search_form,
6
7
  id: element_form_id(action: 'search'),
7
- class: 'as_form search',
8
+ class: "as_form search#{' floating-footer' if active_scaffold_config.field_search.floating_footer}",
8
9
  remote: xhr,
9
10
  data: {loading: true},
10
11
  method: :get
11
- }
12
- options[:class] += ' floating-footer' if active_scaffold_config.field_search.floating_footer
12
+ )
13
13
 
14
14
  hidden_params = url_options.except(:controller, :action, :id, :search).to_query.split(Rack::Utils::DEFAULT_SEP)
15
15
  -%>
@@ -22,9 +22,9 @@
22
22
 
23
23
  <%= render 'field_search_columns', columns: active_scaffold_config.field_search.columns %>
24
24
 
25
- <p class="form-footer">
25
+ <%= as_element :field_search_footer, class: 'form-footer' do %>
26
26
  <%
27
- reset_attrs = {class: 'reset'}
27
+ reset_attrs = {class: ''}
28
28
  if active_scaffold_config.field_search.reset_form
29
29
  reset_attrs[:data] = {reset: true}
30
30
  else
@@ -32,8 +32,8 @@
32
32
  reset_attrs.merge! remote: true, data: {refresh: true}
33
33
  end
34
34
  %>
35
- <%= submit_tag as_(submit_text), class: 'submit' %>
36
- <%= link_to as_(:reset), url_for(url_options.merge(search: '')), reset_attrs unless local_assigns[:skip_reset] %>
35
+ <%= submit_tag as_(submit_text), as_element_attributes(:field_search_submit) %>
36
+ <%= link_to as_(:reset), url_for(url_options.merge(search: '')), as_element_attributes(:field_search_reset, **reset_attrs) unless local_assigns[:skip_reset] %>
37
37
  <%= loading_indicator_tag(action: :search) %>
38
- </p>
38
+ <% end %>
39
39
  </form>