rails_admin 1.0.0.rc → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rails_admin might be problematic. Click here for more details.

Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/README.md +1 -14
  4. data/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js +15 -10
  5. data/app/assets/javascripts/rails_admin/ra.filtering-select.js +205 -110
  6. data/app/assets/javascripts/rails_admin/ra.remote-form.js +1 -4
  7. data/app/controllers/rails_admin/application_controller.rb +5 -5
  8. data/app/controllers/rails_admin/main_controller.rb +2 -2
  9. data/app/helpers/rails_admin/application_helper.rb +2 -2
  10. data/app/helpers/rails_admin/form_builder.rb +9 -2
  11. data/app/helpers/rails_admin/main_helper.rb +1 -1
  12. data/app/views/layouts/rails_admin/application.html.haml +1 -0
  13. data/app/views/rails_admin/main/_delete_notice.html.haml +14 -9
  14. data/app/views/rails_admin/main/index.html.haml +2 -2
  15. data/config/initializers/active_record_extensions.rb +2 -2
  16. data/config/locales/rails_admin.en.yml +1 -0
  17. data/lib/rails_admin/abstract_model.rb +6 -7
  18. data/lib/rails_admin/adapters/active_record.rb +30 -11
  19. data/lib/rails_admin/adapters/mongoid.rb +2 -2
  20. data/lib/rails_admin/adapters/mongoid/association.rb +2 -2
  21. data/lib/rails_admin/adapters/mongoid/extension.rb +1 -1
  22. data/lib/rails_admin/adapters/mongoid/property.rb +1 -1
  23. data/lib/rails_admin/bootstrap-sass.rb +1 -3
  24. data/lib/rails_admin/bootstrap-sass/compass_functions.rb +1 -1
  25. data/lib/rails_admin/config.rb +12 -8
  26. data/lib/rails_admin/config/actions.rb +1 -1
  27. data/lib/rails_admin/config/actions/base.rb +3 -4
  28. data/lib/rails_admin/config/actions/bulk_delete.rb +1 -3
  29. data/lib/rails_admin/config/actions/index.rb +3 -5
  30. data/lib/rails_admin/config/configurable.rb +4 -6
  31. data/lib/rails_admin/config/fields/association.rb +1 -1
  32. data/lib/rails_admin/config/fields/base.rb +15 -26
  33. data/lib/rails_admin/config/fields/factories/carrierwave.rb +1 -1
  34. data/lib/rails_admin/config/fields/types.rb +1 -1
  35. data/lib/rails_admin/config/fields/types/active_record_enum.rb +17 -2
  36. data/lib/rails_admin/config/fields/types/file_upload.rb +1 -1
  37. data/lib/rails_admin/config/fields/types/has_many_association.rb +1 -1
  38. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +1 -1
  39. data/lib/rails_admin/config/fields/types/string.rb +6 -5
  40. data/lib/rails_admin/config/fields/types/text.rb +3 -3
  41. data/lib/rails_admin/config/hideable.rb +1 -1
  42. data/lib/rails_admin/config/inspectable.rb +39 -0
  43. data/lib/rails_admin/config/model.rb +4 -17
  44. data/lib/rails_admin/config/sections/base.rb +4 -17
  45. data/lib/rails_admin/engine.rb +3 -2
  46. data/lib/rails_admin/extension.rb +4 -4
  47. data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +10 -2
  48. data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +11 -1
  49. data/lib/rails_admin/support/datetime.rb +1 -1
  50. data/lib/rails_admin/version.rb +1 -1
  51. metadata +7 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad179cb9f029df989c979439f2e5debb9b2a8f23
4
- data.tar.gz: 2a148ec6c217c0dc67369cb0164bed57db97b953
3
+ metadata.gz: b5f7c910bef240049b818e4189a241c41e68e180
4
+ data.tar.gz: ea59f46605ddef6defbe19c6846d3d9ee6419166
5
5
  SHA512:
6
- metadata.gz: c5c61a2c10d83cdbc00fb163974026eba3a940bd998e674a2e0a256b41f7a9aec821e6aca93a3904bc801d6ee240022bc736b04764bea11953f64ef705ed1d7e
7
- data.tar.gz: aa9a9cfb2e7eda6f0fd9b3bc2fe16430eb83120499da7e87f0361a93a3b3734e458ec6ac0a0bd553bb6d25fa7f4829f3e717ad15d6cf195efd4771e3b62b0738
6
+ metadata.gz: c9c9d4bc637f60e21978c7ce73f693987de692177f79a61ab27757cd75b3ee531575d5bff729361d57c2fad35e82eb48763b5dc4a0c8615394569af7a2a5da5f
7
+ data.tar.gz: 9f16f21be6393621ee9e3b3de88fa3c4c11e75d2d972b88fe411acc04625568adba1c580ede46ae97c012b637b1d75730b49515d3e0379ea8949806e78f851b2
data/Gemfile CHANGED
@@ -2,7 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  gem 'appraisal', '>= 2.0'
4
4
  gem 'devise'
5
- gem 'remotipart', github: 'mshibuya/remotipart'
6
5
 
7
6
  group :active_record do
8
7
  platforms :jruby do
@@ -43,7 +42,7 @@ group :test do
43
42
  gem 'pundit'
44
43
  gem 'rack-cache', require: 'rack/cache'
45
44
  gem 'rspec-rails', '>= 2.14'
46
- gem 'rubocop', '~> 0.31.0'
45
+ gem 'rubocop', '~> 0.41.2'
47
46
  gem 'simplecov', '>= 0.9', require: false
48
47
  gem 'timecop', '>= 0.5'
49
48
 
data/README.md CHANGED
@@ -33,20 +33,7 @@ RailsAdmin is a Rails engine that provides an easy-to-use interface for managing
33
33
 
34
34
  ## Installation
35
35
 
36
- 1. On your gemfile:
37
- - For Rails 5 project:
38
-
39
- ```
40
- gem 'remotipart', github: 'mshibuya/remotipart'
41
- gem 'rails_admin', '>= 1.0.0.rc'
42
- ```
43
-
44
- - For Rails 4 project:
45
-
46
- ```
47
- gem 'rails_admin'
48
- ```
49
-
36
+ 1. On your gemfile: `gem 'rails_admin', '~> 1.0'`
50
37
  2. Run `bundle install`
51
38
  3. Run `rails g rails_admin:install`
52
39
  4. Provide a namespace for the routes when asked
@@ -175,22 +175,25 @@
175
175
  _queryFilter: function(val) {
176
176
  var widget = this;
177
177
  widget._query(val, function(matches) {
178
- var i;
178
+
179
179
  var filtered = [];
180
- for (i in matches) {
181
- if (matches.hasOwnProperty(i) && !widget.selected(matches[i].id)) {
180
+ var i;
181
+
182
+ for (i = 0; i < matches.length; i++) {
183
+ if (!widget.selected(matches[i].id)) {
182
184
  filtered.push(i);
183
185
  }
184
186
  }
185
187
  if (filtered.length > 0) {
186
- widget.collection.html('');
187
- for (i in filtered) {
188
- widget.collection.append(
189
- $('<option></option>').attr('value', matches[filtered[i]].id).attr('title', matches[filtered[i]].label).text(matches[filtered[i]].label)
190
- );
188
+ widget.collection[0].innerHTML = '';
189
+ var filteredContainer = [];
190
+ for (i = 0; i < filtered.length; i++) {
191
+ var newOptions = '<option value="'+matches[filtered[i]].id+'" title="'+matches[filtered[i]].label+'">'+matches[filtered[i]].label+'</option>';
192
+ filteredContainer.push(newOptions);
191
193
  }
194
+ widget.collection[0].innerHTML = filteredContainer.join("");
192
195
  } else {
193
- widget.collection.html(widget.noObjectsPlaceholder);
196
+ widget.collection[0].innerHTML = widget.noObjectsPlaceholder;
194
197
  }
195
198
  });
196
199
  },
@@ -314,7 +317,9 @@
314
317
  },
315
318
 
316
319
  selected: function(value) {
317
- return this.element.find('option[value="' + value + '"]').attr("selected");
320
+ if (this.selection[0].querySelectorAll('option[value="' + value + '"]')[0]) {
321
+ return true;
322
+ }
318
323
  },
319
324
 
320
325
  destroy: function() {
@@ -14,7 +14,9 @@
14
14
  * jquery.ui.autocomplete.js
15
15
  */
16
16
  (function($) {
17
- $.widget("ra.filteringSelect", {
17
+ 'use strict';
18
+
19
+ $.widget('ra.filteringSelect', {
18
20
  options: {
19
21
  createQuery: function(query) {
20
22
  return { query: query };
@@ -26,135 +28,90 @@
26
28
  xhr: false
27
29
  },
28
30
 
31
+ button: null,
32
+ input: null,
33
+ select: null,
34
+
29
35
  _create: function() {
30
- var self = this,
31
- select = this.element.hide(),
32
- selected = select.children(":selected"),
33
- value = selected.val() ? selected.text() : "";
36
+ var filtering_select;
34
37
 
35
- if (this.options.xhr) {
36
- this.options.source = this.options.remote_source;
38
+ // When using the browser back and forward buttons, it is possible that
39
+ // the autocomplete field will be cached which causes duplicate fields
40
+ // to be generated.
41
+ if (this.element.is(':visible')) {
42
+ this.element.hide();
43
+ filtering_select = this._inputGroup(this.element.attr('id'));
44
+ this.input = this._inputField();
45
+ this.button = this._buttonField();
37
46
  } else {
38
- this.options.source = select.children("option").map(function() {
39
- return { label: $(this).text(), value: this.value };
40
- }).toArray();
47
+ filtering_select = this.element.siblings(
48
+ '[data-input-for="' + this.element.attr('id') + '"]'
49
+ );
50
+ this.input = filtering_select.children('input');
51
+ this.button = filtering_select.children('.input-group-btn');
41
52
  }
42
- var filtering_select = $('<div class="input-group filtering-select col-sm-2" style="float:left"></div>')
43
- var input = this.input = $('<input type="text">')
44
- .val(value)
45
- .addClass("form-control ra-filtering-select-input")
46
- .attr('style', select.attr('style'))
47
- .show()
48
- .autocomplete({
49
- delay: this.options.searchDelay,
50
- minLength: this.options.minLength,
51
- source: this._getSourceFunction(this.options.source),
52
- select: function(event, ui) {
53
- var option = $('<option></option>').attr('value', ui.item.id).attr('selected', 'selected').text(ui.item.value);
54
- select.html(option);
55
- select.trigger("change", ui.item.id);
56
- self._trigger("selected", event, {
57
- item: option
58
- });
59
- $(self.element.parents('.controls')[0]).find('.update').removeClass('disabled');
60
- },
61
- change: function(event, ui) {
62
- if (!ui.item) {
63
- var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex($(this).val()) + "$", "i"),
64
- valid = false;
65
- select.children("option").each(function() {
66
- if ($(this).text().match(matcher)) {
67
- this.selected = valid = true;
68
- return false;
69
- }
70
- });
71
- if (!valid || $(this).val() == '') {
72
- // remove invalid value, as it didn't match anything
73
- $(this).val(null);
74
- select.html($('<option value="" selected="selected"></option>'));
75
- input.data("ui-autocomplete").term = "";
76
- $(self.element.parents('.controls')[0]).find('.update').addClass('disabled');
77
- return false;
78
- }
79
-
80
- }
81
- }
82
- })
83
- .keyup(function() {
84
- /* Clear select options and trigger change if selected item is deleted */
85
- if ($(this).val().length == 0) {
86
- select.html($('<option value="" selected="selected"></option>'));
87
- select.trigger("change");
88
- }
89
- })
90
-
91
- if(select.attr('placeholder'))
92
- input.attr('placeholder', select.attr('placeholder'))
93
-
94
- input.data("ui-autocomplete")._renderItem = function(ul, item) {
95
- return $("<li></li>")
96
- .data("ui-autocomplete-item", item)
97
- .append( $( "<a></a>" ).html( item.html || item.id ) )
98
- .appendTo(ul);
99
- };
100
-
101
- var button = this.button = $('<span class="input-group-btn"><label class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="Show All Items" role="button"><span class="caret"></span><span class="ui-button-text">&nbsp;</span></label></span>')
102
- .click(function() {
103
- // close if already visible
104
- if (input.autocomplete("widget").is(":visible")) {
105
- input.autocomplete("close");
106
- return;
107
- }
108
-
109
- // pass empty string as value to search for, displaying all results
110
- input.autocomplete("search", "");
111
- input.focus();
112
- });
113
-
114
- filtering_select.append(input).append(button).insertAfter(select);
115
53
 
54
+ this._setOptionsSource();
55
+ this._initAutocomplete();
56
+ this._initKeyEvent();
57
+ this._overloadRenderItem();
58
+ this._autocompleteDropdownEvent(this.button);
116
59
 
60
+ return filtering_select.append(this.input)
61
+ .append(this.button)
62
+ .insertAfter(this.element);
117
63
  },
118
64
 
119
65
  _getResultSet: function(request, data, xhr) {
120
- var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
121
- var highlighter = function(label, word){
122
- if(word.length > 0){
123
- return $.map(label.split(word), function(el, i){
124
- return $('<span></span>').text(el).html();
125
- }).join($('<strong></strong>').text(word)[0].outerHTML);
126
- }else{
127
- return $('<span></span>').text(label).html();
128
- }
66
+ var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), 'i');
67
+
68
+ var spannedContent = function(content) {
69
+ return $('<span>').text(content).html();
129
70
  };
130
71
 
131
- return $.map(data, function(el, i) {
132
- // match regexp only for local requests, remote ones are already filtered, and label may not contain filtered term.
133
- if ((el.id || el.value) && (xhr || matcher.test(el.label))) {
134
- return {
135
- html: highlighter(el.label || el.id, request.term),
136
- value: el.label || el.id,
137
- id: el.id || el.value
138
- };
72
+ var highlighter = function(label, word) {
73
+ if(word.length) {
74
+ return $.map(
75
+ label.split(word),
76
+ function(el) {
77
+ return spannedContent(el);
78
+ })
79
+ .join($('<strong>')
80
+ .text(word)[0]
81
+ .outerHTML
82
+ );
83
+ } else {
84
+ return spannedContent(label);
139
85
  }
86
+ };
87
+
88
+ return $.map(
89
+ data,
90
+ function(el) {
91
+ var id = el.id || el.value;
92
+ var value = el.label || el.id;
93
+ // match regexp only for local requests, remote ones are already
94
+ // filtered, and label may not contain filtered term.
95
+ if (id && (xhr || matcher.test(el.label))) {
96
+ return {
97
+ html: highlighter(value, request.term),
98
+ value: value,
99
+ id: id
100
+ };
101
+ }
140
102
  });
141
103
  },
142
104
 
143
105
  _getSourceFunction: function(source) {
144
-
145
- var self = this,
146
- requestIndex = 0;
106
+ var self = this;
107
+ var requestIndex = 0;
147
108
 
148
109
  if ($.isArray(source)) {
149
-
150
110
  return function(request, response) {
151
111
  response(self._getResultSet(request, source, false));
152
112
  };
153
-
154
- } else if (typeof source === "string") {
155
-
113
+ } else if (typeof source === 'string') {
156
114
  return function(request, response) {
157
-
158
115
  if (this.xhr) {
159
116
  this.xhr.abort();
160
117
  }
@@ -162,7 +119,7 @@
162
119
  this.xhr = $.ajax({
163
120
  url: source,
164
121
  data: self.options.createQuery(request.term),
165
- dataType: "json",
122
+ dataType: 'json',
166
123
  autocompleteRequest: ++requestIndex,
167
124
  success: function(data, status) {
168
125
  if (this.autocompleteRequest === requestIndex) {
@@ -176,11 +133,149 @@
176
133
  }
177
134
  });
178
135
  };
136
+ } else {
137
+ return source;
138
+ }
139
+ },
179
140
 
141
+ _setOptionsSource: function() {
142
+ if (this.options.xhr) {
143
+ this.options.source = this.options.remote_source;
180
144
  } else {
145
+ this.options.source = this.element.children('option').map(function() {
146
+ return { label: $(this).text(), value: this.value };
147
+ }).toArray();
148
+ }
149
+ },
181
150
 
182
- return source;
151
+ _buttonField: function() {
152
+ return $(
153
+ '<span class="input-group-btn">' +
154
+ '<label class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="Show All Items" role="button">' +
155
+ '<span class="caret"></span>' +
156
+ '<span class="ui-button-text">&nbsp;</span>' +
157
+ '</label>' +
158
+ '</span>'
159
+ );
160
+ },
161
+
162
+ _autocompleteDropdownEvent: function(element) {
163
+ var self = this;
164
+
165
+ return element.click(function() {
166
+ // close if already visible
167
+ if (self.input.autocomplete('widget').is(':visible')) {
168
+ self.input.autocomplete('close');
169
+ return;
170
+ }
171
+
172
+ // pass empty string as value to search for, displaying all results
173
+ self.input.autocomplete('search', '');
174
+ self.input.focus();
175
+ });
176
+ },
177
+
178
+ _inputField: function() {
179
+ var input;
180
+ var selected = this.element.children(':selected');
181
+ var value = selected.val() ? selected.text() : '';
182
+
183
+ input = $('<input type="text">')
184
+ .val(value)
185
+ .addClass('form-control ra-filtering-select-input')
186
+ .attr('style', this.element.attr('style'))
187
+ .show();
188
+
189
+ if (this.element.attr('placeholder')) {
190
+ input.attr('placeholder', this.element.attr('placeholder'));
183
191
  }
192
+
193
+ return input;
194
+ },
195
+
196
+ _inputGroup: function(inputFor) {
197
+ return $('<div>')
198
+ .addClass('input-group filtering-select col-sm-2')
199
+ .attr('data-input-for', inputFor)
200
+ .css('float', 'left');
201
+ },
202
+
203
+ _initAutocomplete: function() {
204
+ var self = this;
205
+
206
+ return this.input.autocomplete({
207
+ delay: this.options.searchDelay,
208
+ minLength: this.options.minLength,
209
+ source: this._getSourceFunction(this.options.source),
210
+ select: function(event, ui) {
211
+ var option = $('<option>')
212
+ .attr('value', ui.item.id)
213
+ .attr('selected', 'selected')
214
+ .text(ui.item.value);
215
+ self.element.html(option)
216
+ .trigger('change', ui.item.id);
217
+ self._trigger('selected', event, {
218
+ item: option
219
+ });
220
+ $(self.element.parents('.controls')[0])
221
+ .find('.update')
222
+ .removeClass('disabled');
223
+ },
224
+ change: function(event, ui) {
225
+ if (ui.item) {
226
+ return;
227
+ }
228
+
229
+ var matcher = new RegExp('^' + $.ui.autocomplete.escapeRegex($(this).val()) + '$', 'i');
230
+ var valid = false;
231
+
232
+ self.element.children('option')
233
+ .each(function() {
234
+ if ($(this).text().match(matcher)) {
235
+ valid = true;
236
+ return false;
237
+ }
238
+ });
239
+
240
+ if (valid || $(this).val() !== '') {
241
+ return;
242
+ }
243
+
244
+ // remove invalid value, as it didn't match anything
245
+ $(this).val(null);
246
+ self.element.html($('<option value="" selected="selected"></option>'));
247
+ self.input.data('ui-autocomplete').term = '';
248
+ $(self.element.parents('.controls')[0])
249
+ .find('.update')
250
+ .addClass('disabled');
251
+ return false;
252
+ }
253
+ });
254
+ },
255
+
256
+ _initKeyEvent: function() {
257
+ var self = this;
258
+
259
+ return this.input.keyup(function() {
260
+ if ($(this).val().length) {
261
+ return;
262
+ }
263
+
264
+ /* Clear select options and trigger change if selected item is deleted */
265
+ return self.element
266
+ .html($('<option value="" selected="selected"></option>'))
267
+ .trigger('change');
268
+ });
269
+ },
270
+
271
+ _overloadRenderItem: function() {
272
+ this.input.data('ui-autocomplete')._renderItem = function(ul, item) {
273
+ return $('<li></li>')
274
+ .data('ui-autocomplete-item', item)
275
+ .append($('<a></a>')
276
+ .html(item.html || item.id))
277
+ .appendTo(ul);
278
+ };
184
279
  },
185
280
 
186
281
  destroy: function() {