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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86137e56876a2c8cd92c7a5426a2d30d68e52106
4
- data.tar.gz: 27ec4aae8a07fcebab1cf94ea4f08400e20ba2ef
3
+ metadata.gz: d37787a741c58cce776cf85504379aae6eba7f4f
4
+ data.tar.gz: d0d8b6bdb18ed9d4b096d71994d4f766f3d771a8
5
5
  SHA512:
6
- metadata.gz: 5fc25ec8546c1c0176a2eaadb5646b0d0f0d62a6324816aa354c3c117a9ec9b1d51145a4df991171349b8005965a0e16783ec3a03d00674492f98b39f9770f1b
7
- data.tar.gz: d17dfcde0451c88c888cd4fb24c39f944f28ba3e93275c2b0d76a35297d1f909bee9f241cf9f90f9721aedd77f0945edb28f1490db518777eec27e2ed7e257af
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] + "_desc";
41
+ var order = fields[0] + '_desc';
42
+ var parentId = $(el).data('parent_id') || INVALID_PARENT_ID;
43
+ var selectInstance;
36
44
 
37
- $(el).select2({
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("selected") || "";
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
- ajax: {
48
- url: url,
49
- dataType: 'json',
50
- delay: 250,
51
- data: function (term) {
52
- var query = {m: "or"};
53
- fields.forEach(function(field) {
54
- query[field + "_contains"] = term;
55
- });
56
-
57
- return {
58
- order: order,
59
- q: query
60
- };
61
- },
62
- results: function (data, page) {
63
- return {
64
- results: jQuery.map(data, function(resource) {
65
- return {
66
- id: resource.id,
67
- text: resource[displayName]
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
  });
@@ -11,3 +11,13 @@
11
11
  width: 12px;
12
12
  }
13
13
  }
14
+
15
+ .nested_select {
16
+ .nested-select-container {
17
+ margin-bottom: 20px;
18
+
19
+ &:last-of-type {
20
+ margin-bottom: 0px;
21
+ }
22
+ }
23
+ }
@@ -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] = "select2-ajax"
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
-
@@ -1,3 +1,3 @@
1
1
  module ActiveadminAddons
2
- VERSION = "0.2.8"
2
+ VERSION = "0.3.0"
3
3
  end
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.2.8
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: 2015-10-23 00:00:00.000000000 Z
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.css.scss
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