active_scaffold 4.3.1 → 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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +26 -1
  3. data/README.md +1 -1
  4. data/app/assets/javascripts/active_scaffold/active_scaffold.js +107 -16
  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/add_tab.js.erb +2 -3
  35. data/app/views/active_scaffold_overrides/render_field.js.erb +1 -1
  36. data/config/locales/de.yml +2 -1
  37. data/config/locales/en.yml +33 -32
  38. data/config/locales/es.yml +15 -14
  39. data/config/locales/fr.yml +3 -2
  40. data/config/locales/hu.yml +3 -2
  41. data/config/locales/ja.yml +2 -1
  42. data/config/locales/ro.yml +169 -0
  43. data/config/locales/ru.yml +8 -7
  44. data/config/locales/ta.yml +7 -6
  45. data/config/locales/zh_Hans.yml +14 -13
  46. data/lib/active_scaffold/actions/common_search.rb +1 -14
  47. data/lib/active_scaffold/actions/core.rb +55 -16
  48. data/lib/active_scaffold/actions/field_search.rb +2 -2
  49. data/lib/active_scaffold/actions/list.rb +35 -13
  50. data/lib/active_scaffold/actions/nested.rb +31 -7
  51. data/lib/active_scaffold/actions/show.rb +1 -1
  52. data/lib/active_scaffold/active_record_permissions.rb +1 -1
  53. data/lib/active_scaffold/attribute_params.rb +2 -1
  54. data/lib/active_scaffold/bridges/date_picker/helper.rb +14 -0
  55. data/lib/active_scaffold/bridges/date_picker.rb +10 -0
  56. data/lib/active_scaffold/config/list.rb +10 -1
  57. data/lib/active_scaffold/core.rb +9 -6
  58. data/lib/active_scaffold/data_structures/action_columns.rb +2 -0
  59. data/lib/active_scaffold/data_structures/column.rb +27 -6
  60. data/lib/active_scaffold/data_structures/filter.rb +4 -0
  61. data/lib/active_scaffold/data_structures/nested_info.rb +8 -1
  62. data/lib/active_scaffold/data_structures/sorting.rb +1 -1
  63. data/lib/active_scaffold/extensions/action_view_rendering.rb +1 -1
  64. data/lib/active_scaffold/finder.rb +66 -21
  65. data/lib/active_scaffold/helpers/action_link_helpers.rb +43 -18
  66. data/lib/active_scaffold/helpers/assets_helpers.rb +4 -4
  67. data/lib/active_scaffold/helpers/filter_helpers.rb +3 -3
  68. data/lib/active_scaffold/helpers/form_column_helpers.rb +34 -22
  69. data/lib/active_scaffold/helpers/form_ui_helpers.rb +15 -10
  70. data/lib/active_scaffold/helpers/framework_ui_helpers.rb +22 -0
  71. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -0
  72. data/lib/active_scaffold/helpers/list_column_helpers.rb +19 -0
  73. data/lib/active_scaffold/helpers/pagination_helpers.rb +28 -7
  74. data/lib/active_scaffold/helpers/search_column_helpers.rb +32 -5
  75. data/lib/active_scaffold/helpers/tabs_helpers.rb +4 -6
  76. data/lib/active_scaffold/helpers/view_helpers.rb +12 -0
  77. data/lib/active_scaffold/tableless.rb +11 -8
  78. data/lib/active_scaffold/version.rb +2 -2
  79. data/lib/active_scaffold.rb +169 -0
  80. data/lib/tasks/bundle.rake +2 -1
  81. data/lib/tasks/mock_app.rake +43 -0
  82. metadata +20 -7
  83. data/shoulda_macros/macros.rb +0 -145
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8426370774f998d440d6ba62749ce0debb8b5caf5a050330b21c77eb34849e17
4
- data.tar.gz: 60f8897a05d79cc248c5059321b42152361f5f79b24069586e46b2bd209e738e
3
+ metadata.gz: cafbb1cbb0273e33d48ba6efb723a4ac6abd3678c559031bbc10d1b608f61ad5
4
+ data.tar.gz: 7e835a08a8b21df39301360a62db0257826b5e1a654c18ef2e8fbc92d4278436
5
5
  SHA512:
6
- metadata.gz: be457e4b9bc57e9e4f657642912ff5396bad888107ef9a9e27ee3cf0457e5cf8e872f2d20ee08379fa1c42105e223f8e4fd9ae43d64c6f7eececa1c6212250e4
7
- data.tar.gz: 7c764c174e950240a3da87b096ed7891ed571c81880e7f42161744a591c3de626f5b14914ddb0d7b7c9500b12e48d2be2b06bd11d071f3174467da42d3627cbf
6
+ metadata.gz: 475d62edc638cfefd7d43bf86a033d842f387968d9e90fc83b61b3da5cfc3f688e3ab8ee200ba7a56f7cebfe9659ad108494618207104ff65b1c9bad67a738c9
7
+ data.tar.gz: b4eb39a97611806f10c625111a41aa67061d35093c5caae3f89673516f3785c1692d04a3e87de3f7e8174a0b286818c10a253ec449d10f1ab8aada1ef1547cbd
data/CHANGELOG.rdoc CHANGED
@@ -1,4 +1,29 @@
1
- - Fix escaping URL in JS response, fixing auto paginate and response for actions with render_parent
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
+
20
+ = 4.3.2
21
+ - Fix adding tab in tabbed forms
22
+
23
+ = 4.3.1
24
+ - Support Ruby 4
25
+ - Fix date picker options translated as strings, preserving boolean and integer values
26
+ - Fix escaping URLs in JavaScript responses, fixing auto pagination and actions with render_parent
2
27
 
3
28
  = 4.3.0
4
29
  - Support translating enums (or options for :select form_ui on any column) nested in the pluralized name of the column, activerecord.attributes.model_name.pluralized_column.enum_value, defaults to old way activerecord.attributes.model_name.enum_value
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
  },
@@ -150,6 +224,14 @@
150
224
  if (opts.disabled) jQuery(this).find('.ui-slider-handle').hide();
151
225
  });
152
226
  },
227
+ activate_tab: function(tab_ctrl) {
228
+ tab_ctrl = jQuery(tab_ctrl);
229
+ var tabbed = tab_ctrl.closest('.tabbed');
230
+ tabbed.find('.nav-tabs .active').removeClass('active');
231
+ tabbed.find('.tab-content .active').removeClass('in active');
232
+ tab_ctrl.addClass('active');
233
+ jQuery(tab_ctrl.attr('href')).addClass('in active');
234
+ },
153
235
  load_embedded: function(element) {
154
236
  jQuery('.active-scaffold-component .load-embedded', element).each(function(index, item) {
155
237
  item = jQuery(item);
@@ -158,7 +240,7 @@
158
240
  item.closest('.active-scaffold-component').load(item.attr('href'), function(response, status, xhr) {
159
241
  if (status == 'error') {
160
242
  indicator.css({visibility: 'hidden'});
161
- indicator.after(jQuery('<p>').html(item.data('error-msg')).addClass("error-message message server-error"));
243
+ indicator.after(item.data('error-msg'));
162
244
  } else jQuery(this).trigger('as:element_updated');
163
245
  });
164
246
  });
@@ -195,12 +277,12 @@
195
277
  },
196
278
  hide_empty_message: function(tbody) {
197
279
  if (this.records_for(tbody).length != 0) {
198
- jQuery(tbody).parent().find('tbody.messages p.empty-message').hide();
280
+ jQuery(tbody).parent().find('.messages-container .empty-message').hide();
199
281
  }
200
282
  },
201
283
  show_empty_message: function(tbody) {
202
284
  if (this.records_for(tbody).length != 0) {
203
- jQuery(tbody).parent().find('tbody.messages p.empty-message').hide();
285
+ jQuery(tbody).parent().find('.messages-container .empty-message').hide();
204
286
  }
205
287
  },
206
288
  reload_if_empty: function(tbody, url) {
@@ -495,7 +577,7 @@
495
577
  highlight: function(element) {
496
578
  if (typeof(element) == 'string') element = jQuery('#' + element);
497
579
  if (typeof(element.effect) == 'function') {
498
- element.effect("highlight", jQuery.extend({}, ActiveScaffold.config.highlight), 3000);
580
+ element.effect("highlight", jQuery.extend({duration: 3000}, ActiveScaffold.config.highlight));
499
581
  }
500
582
  },
501
583
 
@@ -526,7 +608,7 @@
526
608
  var source = jQuery(source);
527
609
  var element, container = source.closest('.sub-form-record'), selector = '';
528
610
  if (container.length === 0) {
529
- container = source.closest('form > ol.form');
611
+ container = source.closest('form > .form');
530
612
  selector = '>';
531
613
  }
532
614
  if (options.traverse) {
@@ -1346,9 +1428,22 @@
1346
1428
  return true;
1347
1429
  });
1348
1430
  jQuery(document).on('ajax:before', 'a.as_sort', function(event) {
1349
- var as_sort = jQuery(this);
1350
- as_sort.closest('th').addClass('loading');
1351
- 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
+ }
1352
1447
  });
1353
1448
  jQuery(document).on('ajax:error', 'a.as_sort', function(event, xhr, status, error) {
1354
1449
  if (event.detail && !xhr) {
@@ -1513,8 +1608,8 @@
1513
1608
  return true;
1514
1609
  });
1515
1610
 
1516
- jQuery(document).on('click', '.message a.close', function(e) {
1517
- 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'));
1518
1613
  e.preventDefault();
1519
1614
  });
1520
1615
 
@@ -1572,11 +1667,7 @@
1572
1667
  jQuery(document).on('click', '.active-scaffold .tabbed .nav-tabs a', function(e) {
1573
1668
  if (typeof jQuery().tab == 'function') return; // bootstrap tab plugin is loaded and will handle tabs
1574
1669
  e.preventDefault();
1575
- var tab_ctrl = jQuery(this), tabbed = tab_ctrl.closest('.tabbed')
1576
- tabbed.find('.nav-tabs .active').removeClass('active');
1577
- tabbed.find('.tab-content .active').removeClass('in active');
1578
- tab_ctrl.closest('li').addClass('active');
1579
- jQuery(tab_ctrl.attr('href')).addClass('in active');
1670
+ ActiveScaffold.activate_tab(this);
1580
1671
  });
1581
1672
 
1582
1673
  jQuery(document).on('turbolinks:before-visit turbo:before-visit', function() {
@@ -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>