activeadmin_addons 0.2.8 → 0.3.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/activeadmin_addons/select2.js +92 -34
- data/app/assets/stylesheets/activeadmin_addons/{all.css.scss → all.scss} +10 -0
- data/app/inputs/nested_select_input.rb +144 -0
- data/app/inputs/search_select_input.rb +1 -2
- data/lib/activeadmin_addons/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d37787a741c58cce776cf85504379aae6eba7f4f
|
4
|
+
data.tar.gz: d0d8b6bdb18ed9d4b096d71994d4f766f3d771a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec3fc574dc04e37b47e927561f6f7756ecb0b5c35c8f06e992ad1fe948c8b7c5091ff6d6400b587fd93bc320feb05977f00c4bc236202e4e778e77d2e07611ea
|
7
|
+
data.tar.gz: 043c5e56dbc3ce545e5264caf05ef8142fd634390b14bc842c5046ed5b1a2bdcdd58f33c0c77445028e3f60ca83b71eba60d4fbd5dd360b0df6b384d98e415cb
|
@@ -8,6 +8,8 @@ $(function() {
|
|
8
8
|
$(document).on('has_many_add:after', setupSelect2);
|
9
9
|
|
10
10
|
function setupSelect2() {
|
11
|
+
var INVALID_PARENT_ID = -1;
|
12
|
+
|
11
13
|
$('.select2-tags').each(function(i, el) {
|
12
14
|
$(el).select2({
|
13
15
|
width: '80%',
|
@@ -27,53 +29,109 @@ $(function() {
|
|
27
29
|
}
|
28
30
|
});
|
29
31
|
|
32
|
+
|
30
33
|
$('.select2-ajax').each(function(i, el) {
|
31
34
|
var url = $(el).data('url');
|
32
35
|
var fields = $(el).data('fields');
|
33
36
|
var displayName = $(el).data('display_name');
|
37
|
+
var parent = $(el).data('parent');
|
38
|
+
var model = $(el).data('model');
|
39
|
+
var collection = $(el).data('collection');
|
34
40
|
var minimumInputLength = $(el).data('minimum_input_length');
|
35
|
-
var order = fields[0] +
|
41
|
+
var order = fields[0] + '_desc';
|
42
|
+
var parentId = $(el).data('parent_id') || INVALID_PARENT_ID;
|
43
|
+
var selectInstance;
|
36
44
|
|
37
|
-
|
45
|
+
var ajaxOptions = {
|
46
|
+
url: url,
|
47
|
+
dataType: 'json',
|
48
|
+
delay: 250,
|
49
|
+
data: function(term) {
|
50
|
+
var textQuery = { m: 'or' };
|
51
|
+
fields.forEach(function(field) {
|
52
|
+
textQuery[field + '_contains'] = term;
|
53
|
+
});
|
54
|
+
|
55
|
+
var query = {
|
56
|
+
order: order,
|
57
|
+
q: {
|
58
|
+
groupings: [textQuery],
|
59
|
+
combinator: 'and'
|
60
|
+
}
|
61
|
+
};
|
62
|
+
|
63
|
+
if (!!parent) {
|
64
|
+
query.q[parent + '_eq'] = parentId;
|
65
|
+
}
|
66
|
+
|
67
|
+
return query;
|
68
|
+
},
|
69
|
+
results: function(data, page) {
|
70
|
+
return {
|
71
|
+
results: jQuery.map(data, function(resource) {
|
72
|
+
return {
|
73
|
+
id: resource.id,
|
74
|
+
text: resource[displayName].toString()
|
75
|
+
};
|
76
|
+
})
|
77
|
+
};
|
78
|
+
},
|
79
|
+
cache: true
|
80
|
+
};
|
81
|
+
|
82
|
+
var collectionOptions = function(query) {
|
83
|
+
var data = { results: [] };
|
84
|
+
|
85
|
+
collection.forEach(function(record) {
|
86
|
+
var matched = fields.some(function(field) {
|
87
|
+
var regex = new RegExp(query.term, 'i');
|
88
|
+
return !!record[field] && !!record[field].match(regex);
|
89
|
+
});
|
90
|
+
|
91
|
+
if((!parent || record[parent] == parentId) && matched) {
|
92
|
+
data.results.push({ id: record.id, text: record[displayName].toString() });
|
93
|
+
}
|
94
|
+
});
|
95
|
+
|
96
|
+
query.callback(data);
|
97
|
+
};
|
98
|
+
|
99
|
+
var select2Config = {
|
38
100
|
width: '80%',
|
101
|
+
containerCssClass: 'nested-select-container',
|
102
|
+
minimumInputLength: minimumInputLength,
|
39
103
|
initSelection: function(element, callback) {
|
40
104
|
var id = $(element).val();
|
41
|
-
var text = $(element).data(
|
105
|
+
var text = $(element).data('selected') || '';
|
106
|
+
$(element).data('selected', '');
|
107
|
+
|
42
108
|
callback({
|
43
109
|
id: id,
|
44
110
|
text: text
|
45
111
|
});
|
46
|
-
}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
})
|
70
|
-
};
|
71
|
-
},
|
72
|
-
cache: true
|
73
|
-
},
|
74
|
-
minimumInputLength: minimumInputLength
|
75
|
-
});
|
112
|
+
}
|
113
|
+
};
|
114
|
+
|
115
|
+
if (!!parent) {
|
116
|
+
var parentSelector = '#' + model + '_' + parent;
|
117
|
+
|
118
|
+
$(parentSelector).on('change', function(e) {
|
119
|
+
selectInstance.val(null).trigger('change');
|
120
|
+
parentId = e.val;
|
121
|
+
|
122
|
+
if(!parentId) {
|
123
|
+
parentId = INVALID_PARENT_ID;
|
124
|
+
}
|
125
|
+
});
|
126
|
+
}
|
127
|
+
|
128
|
+
if (collection) {
|
129
|
+
select2Config.query = collectionOptions;
|
130
|
+
} else {
|
131
|
+
select2Config.ajax = ajaxOptions;
|
132
|
+
}
|
133
|
+
|
134
|
+
selectInstance = $(el).select2(select2Config);
|
76
135
|
});
|
77
136
|
}
|
78
|
-
|
79
137
|
});
|
@@ -0,0 +1,144 @@
|
|
1
|
+
class NestedSelectInput < Formtastic::Inputs::StringInput
|
2
|
+
def to_html
|
3
|
+
html_elems = []
|
4
|
+
|
5
|
+
for_each_level do |level_data|
|
6
|
+
a = level_data[:attribute]
|
7
|
+
set_parent_value(level_data)
|
8
|
+
html_elems << builder.text_field(a, select_html_options(level_data))
|
9
|
+
html_elems << builder.label(a, translated_attribute(a))
|
10
|
+
end
|
11
|
+
|
12
|
+
input_wrapping do
|
13
|
+
html_elems.reverse.join("\n").html_safe
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def for_each_level
|
20
|
+
hierarchy = get_hierarchy
|
21
|
+
hierarchy_count = hierarchy.count
|
22
|
+
|
23
|
+
hierarchy.each_with_index do |level_data, idx|
|
24
|
+
next_idx = idx + 1
|
25
|
+
parent_level_data = hierarchy[next_idx] if hierarchy_count != next_idx
|
26
|
+
level_data[:parent_attribute] = parent_level_data[:attribute] if parent_level_data
|
27
|
+
|
28
|
+
yield(level_data)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_hierarchy
|
33
|
+
hierarchy = []
|
34
|
+
levels = @options.keys.select { |key| key.to_s.match(/level_[1-9]$/) }
|
35
|
+
reversed_levels = levels.reverse
|
36
|
+
|
37
|
+
reversed_levels.each_with_index do |level_key, idx|
|
38
|
+
previous_level_key = reversed_levels[idx + 1]
|
39
|
+
validate_level_data!(level_key, previous_level_key)
|
40
|
+
hierarchy << @options[level_key]
|
41
|
+
end
|
42
|
+
|
43
|
+
raise("Undefined levels on nested_select") if hierarchy.empty?
|
44
|
+
|
45
|
+
hierarchy
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_level_data!(level_key, previous_level_key)
|
49
|
+
current_level_number = get_level_number(level_key)
|
50
|
+
previous_level_number = get_level_number(previous_level_key)
|
51
|
+
|
52
|
+
if !(current_level_number == previous_level_number + 1)
|
53
|
+
raise("Missing :level_#{current_level_number - 1} key")
|
54
|
+
end
|
55
|
+
|
56
|
+
attribute = @options[level_key][:attribute]
|
57
|
+
raise("Missing mandatory attribute level_key on #{level_key}") unless attribute
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_level_number(level_key)
|
61
|
+
level_key.to_s.split("_").last.to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def select_html_options(level)
|
65
|
+
attribute = level[:attribute]
|
66
|
+
instance = instance_from_attribute_name(attribute)
|
67
|
+
|
68
|
+
opts = {}
|
69
|
+
opts["class"] = select_classes(level)
|
70
|
+
opts["data-fields"] = get_option(level, :fields, ["name"]).to_json
|
71
|
+
opts["data-model"] = model_name
|
72
|
+
opts["data-display_name"] = get_option(level, :display_name, "name")
|
73
|
+
opts["data-minimum_input_length"] = get_option(level, :minimum_input_length, 1)
|
74
|
+
opts["data-collection"] = (level[:collection] || nil).to_json
|
75
|
+
|
76
|
+
opts["id"] = build_select_id(attribute)
|
77
|
+
opts["data-url"] = build_url(attribute)
|
78
|
+
opts["data-selected"] = instance.try(opts["data-display_name"])
|
79
|
+
|
80
|
+
opts.merge(select_html_parent_options(level[:parent_attribute]))
|
81
|
+
end
|
82
|
+
|
83
|
+
def select_html_parent_options(parent_attribute)
|
84
|
+
opts = {}
|
85
|
+
return opts unless parent_attribute
|
86
|
+
opts["data-parent"] = parent_attribute
|
87
|
+
opts["data-parent_id"] = @object.send(parent_attribute)
|
88
|
+
opts
|
89
|
+
end
|
90
|
+
|
91
|
+
def select_classes(level_data)
|
92
|
+
['select2-ajax'].concat(get_option(level_data, :class, [])).join(' ')
|
93
|
+
end
|
94
|
+
|
95
|
+
def model_name
|
96
|
+
@object.class.to_s.downcase
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_select_id(attribute)
|
100
|
+
[@object.class.to_s.downcase, attribute.to_s].join("_")
|
101
|
+
end
|
102
|
+
|
103
|
+
def get_option(level_data, option, default)
|
104
|
+
level_data[option] || @options[option] || default
|
105
|
+
end
|
106
|
+
|
107
|
+
def set_parent_value(level_data)
|
108
|
+
parent_attribute = level_data[:parent_attribute]
|
109
|
+
add_virtual_accessor(parent_attribute)
|
110
|
+
instance = instance_from_attribute_name(level_data[:attribute])
|
111
|
+
if instance && instance.respond_to?(parent_attribute)
|
112
|
+
@object.send("#{parent_attribute}=", instance.send(parent_attribute))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def instance_from_attribute_name(attribute)
|
117
|
+
return unless attribute
|
118
|
+
attribute_value = @object.send(attribute)
|
119
|
+
return unless attribute_value
|
120
|
+
klass = attribute.to_s.humanize.constantize
|
121
|
+
klass.find_by_id(attribute_value)
|
122
|
+
end
|
123
|
+
|
124
|
+
def add_virtual_accessor(attribute)
|
125
|
+
return unless attribute
|
126
|
+
@object.singleton_class.send(:attr_accessor, attribute) unless @object.respond_to?(attribute)
|
127
|
+
end
|
128
|
+
|
129
|
+
def translated_attribute(attribute)
|
130
|
+
@object.class.human_attribute_name(attribute)
|
131
|
+
end
|
132
|
+
|
133
|
+
def build_url(attribute)
|
134
|
+
url = ["/"]
|
135
|
+
|
136
|
+
if ActiveAdmin.application.default_namespace.present?
|
137
|
+
url << "#{ActiveAdmin.application.default_namespace}/"
|
138
|
+
end
|
139
|
+
|
140
|
+
url << attribute.to_s.humanize.tableize
|
141
|
+
|
142
|
+
url.join("")
|
143
|
+
end
|
144
|
+
end
|
@@ -2,7 +2,7 @@ class SearchSelectInput < Formtastic::Inputs::StringInput
|
|
2
2
|
def input_html_options
|
3
3
|
relation = @object.send(attributized_method_name)
|
4
4
|
opts = {}
|
5
|
-
opts[:class] =
|
5
|
+
opts[:class] = ['select2-ajax'].concat([@options[:class]] || []).join(' ')
|
6
6
|
opts["data-fields"] = (@options[:fields] || []).to_json
|
7
7
|
opts["data-url"] = @options[:url] || ""
|
8
8
|
opts["data-display_name"] = @options[:display_name] || "name"
|
@@ -11,4 +11,3 @@ class SearchSelectInput < Formtastic::Inputs::StringInput
|
|
11
11
|
super.merge opts
|
12
12
|
end
|
13
13
|
end
|
14
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeadmin_addons
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Platanus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -348,7 +348,8 @@ files:
|
|
348
348
|
- app/assets/images/fileicons/file_extension_zip.png
|
349
349
|
- app/assets/javascripts/activeadmin_addons/all.js.coffee
|
350
350
|
- app/assets/javascripts/activeadmin_addons/select2.js
|
351
|
-
- app/assets/stylesheets/activeadmin_addons/all.
|
351
|
+
- app/assets/stylesheets/activeadmin_addons/all.scss
|
352
|
+
- app/inputs/nested_select_input.rb
|
352
353
|
- app/inputs/range_select_input.rb
|
353
354
|
- app/inputs/search_select_input.rb
|
354
355
|
- app/inputs/tags_input.rb
|