auto_select2 0.1.2 → 0.2.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.

Potentially problematic release.


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

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a68cb3144bf87121bda7928fbd8a21924253eafb
4
- data.tar.gz: ed7470fa356f8003f5bd3f259ee4bb73da03f908
3
+ metadata.gz: 1959785b4c590ab8a899b2ae4d04ae92877bff2d
4
+ data.tar.gz: ec11ae6b9ab6bea151a90327d444e9a1188283ea
5
5
  SHA512:
6
- metadata.gz: ea72345387f6253f7ab2fe1c3b25d30ef0a0587d2358cf292747b5f71a64e188a6e5c12bb3cccce15f887efb7085d28d79fc106cd106c6a3faccb18db012ca73
7
- data.tar.gz: 427c82d917c6accd35c66fa5fc908eb66060870ecabfd8d87f405be0eaa697095bb8e8ecc340437b88155a3b58c5c8fbafb2c3ce67f8f809895df0d5831c82f5
6
+ metadata.gz: c51d13d9a225ccbff420e2aefacbafeb2ed86db076af426a701f75f5d4bd309c2744d556f356e38ceae2c3c1eda1f03f57a7180daa7cdee349dcdabfa3fa22c2
7
+ data.tar.gz: a9de852f51f7573b7ae71d7c20ec17a7007cd49f0820659153cb674b3c1b2a8aefe6299a8f37829fe216da68d1d5e6d295d80ddbe2c481e7d9fcf46c9c64046a
data/README.md CHANGED
@@ -1,9 +1,23 @@
1
1
  # AutoSelect2
2
2
 
3
- TODO: Write a gem description
3
+ Gem provide API (scripts, helpers, controller and base class for ajax-search)
4
+ for initialize different select2 elements: static, ajax and multi-ajax.
5
+
6
+ The `AutoSelect2` based on [select2-rails](https://github.com/argerim/select2-rails) gem.
7
+
8
+ [![Gem Version](https://badge.fury.io/rb/auto_select2.png)](http://badge.fury.io/rb/auto_select2)
4
9
 
5
10
  ## Installation
6
11
 
12
+ ### First
13
+
14
+ Install [select2-rails](https://github.com/argerim/select2-rails#install-select2-rails-gem)
15
+ and include javascript and stylesheet assets as
16
+ [described](https://github.com/argerim/select2-rails#include-select2-rails-javascript-assets)
17
+ on `select2-rails` page.
18
+
19
+ ### Second
20
+
7
21
  Add this line to your application's Gemfile:
8
22
 
9
23
  gem 'auto-select2'
@@ -12,13 +26,224 @@ And then execute:
12
26
 
13
27
  $ bundle
14
28
 
15
- Or install it yourself as:
29
+ ### Third
30
+
31
+ Select one of ways to include js in pipeline. Ways described below in section `Javascript include variants`
32
+
33
+ ### Fourth
34
+
35
+ Check controller and route collation. Gem contain controller `Select2AutocompletesController` and
36
+ route
37
+
38
+ get 'select2_autocompletes/:class_name'
39
+
40
+ ### Fifth
41
+
42
+ Prepare folder `app/select2_search_adapter` if you want to use `ajax-select2`. This folder needed
43
+ for storage custom `SearchAdapter`.
44
+
45
+ ## Compatibility
46
+
47
+ Gem tested and works in Rails 3.2 and Rails 4.0. You can test compatibility with other versions by yourself.
48
+
49
+ ## Easiest way to use
50
+
51
+ Use [AutoSelect2Tag](https://github.com/Loriowar/auto_select2_tag). It provide helpers:
52
+
53
+ * select2_tag
54
+ * select2_ajax_tag
55
+
56
+ and you can define select2 element like any other view elements in rails.
57
+
58
+ ## Example
16
59
 
17
- $ gem install auto-select2
60
+ You can find example project [here](https://github.com/Loriowar/auto-select2_tag_example).
18
61
 
19
62
  ## Usage
20
63
 
21
- TODO: Write usage instructions here
64
+ ### Element types
65
+
66
+ Gem provides 3 types of select2 elements:
67
+
68
+ * static
69
+ * ajax
70
+ * multi-ajax
71
+
72
+ For each of it exist javascript initializer. This is:
73
+
74
+ * static_select2.js
75
+ * ajax_select2.js
76
+ * multi_ajax_select2_value_parser.js
77
+
78
+ **Note:** `multi_ajax_select2_value_parser.js` work only together with `ajax_select2.js`
79
+
80
+ ### Javascript include variants
81
+
82
+ You have two ways to include javascript files. First: in gem presents helper methods
83
+
84
+ * static_select2_init_header_tags
85
+ * ajax_select2_init_header_tags
86
+ * ajax_multi_select2_init_header_tags
87
+
88
+ This helpers call `javascript_include_tag` and it is useful for initialize select2
89
+ scripts on a single page. Example of usage in a view:
90
+
91
+ - static_select2_init_header_tags
92
+
93
+ %div
94
+ = select_tag :my_select, my_options_for_select, class: 'small'
95
+
96
+ Second variant: include files in javascript asset. For this add the
97
+ following to your `app/assets/javascripts/application.js`:
98
+
99
+ //= require auto_select2/static_select2
100
+ //= require auto_select2/ajax_select2
101
+ //= require auto_select2/multi_ajax_select2_value_parser
102
+
103
+ ### Select2 options
104
+
105
+ If you want to specify any parameters for [select2 constructor](http://ivaynberg.github.io/select2/)
106
+ you can pass it as hash into data-attribute `s2options`. This parameter handle most options
107
+ but you can't pass through js-functions.
108
+
109
+ ### Static select2 usage
110
+
111
+ For initialize static select2 you must set `auto-static-select2` css-class for select element:
112
+
113
+ = select_tag :my_select, my_options_for_select, class: 'my-class auto-static-select2'
114
+
115
+ ### Ajax select2 usage
116
+
117
+ For initialize ajax select 2 you must set `auto-ajax-select2` css-class for hidden-input element.
118
+ Then you have two ways. Easy way for simple selection: specify `default_class_name`, `default_text_column` and
119
+ `default_id_column` as params for `:href` within data-attribute `s2options` (look at the end of this section).
120
+ Other way for custom selection: create `SearchAdapter`. This adapter has following requirements:
121
+
122
+ * class must be inherited from `AutoSelect2::Select2SearchAdapter::Base`
123
+ * file must be put in folder `app/select2_search_adapter`
124
+ * name of a adapter class must end with `SearchAdapter`
125
+ * must has function `search_default(term, page, options)`
126
+ (description of the function and return value goes below)
127
+
128
+ Returned value of `search_default` function must be follow:
129
+
130
+ * if options contain `:init` key function must return hash
131
+ `{text: 'displayed text', id: 'id_of_initial_element'}`
132
+ * otherwise function must return the follow hash:
133
+
134
+
135
+ { items:
136
+ [
137
+ { text: 'first element', id: 'first_id' },
138
+ { text: 'second element', id: 'second_id' }
139
+ ],
140
+ total: count
141
+ }
142
+
143
+ Here in total must be specified amount of all select variants. For example you have select
144
+ element with 42 variants. Function `search_default` return part of it in `items` and in
145
+ `total` each time you must set 42.
146
+
147
+ **TIP:** in `search_default` you can use functions from `Select2SearchAdapter::Base`:
148
+
149
+ * `default_finder(searched_class, term, options)`
150
+ * `default_count(searched_class, term, options = {})`
151
+ * `get_init_values(searched_class, ids, title_method=nil)`
152
+
153
+ More about this function you can find in [example project](https://github.com/Loriowar/auto-select2_tag_example),
154
+ in example below and in source code.
155
+
156
+ Finally hidden-input must has `:href` parameter in data-attribute `s2options`. This
157
+ parameter specify url for ajax load select options. You can use helper
158
+
159
+ select2_autocompletes_path(class_name: :my_class_name)
160
+ or
161
+
162
+ select2_autocompletes_path(default_class_name: my_class,
163
+ default_text_column: :name,
164
+ default_id_column: :id)
165
+
166
+ ### Example of minimalistic SearchAdapter
167
+ class SystemRoleSearchAdapter < AutoSelect2::Select2SearchAdapter::Base
168
+ class << self
169
+ def search_default(term, page, options)
170
+ if options[:init].nil?
171
+ roles = default_finder(SystemRole, term, page: page)
172
+ count = default_count(SystemRole, term)
173
+ {
174
+ items: roles.map do |role|
175
+ { text: role.name, id: role.id.to_s } # here is optional parameter 'class_name'
176
+ end,
177
+ total: count
178
+ }
179
+ else
180
+ get_init_values(SystemRole, options[:item_ids])
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ ### More about SearchAdapter
187
+
188
+ `SearchAdapter` has some additional functions. First, you can define multiple search
189
+ functions in one adapter. For example in adapter for User you want to find among all
190
+ users, find users only in one department and so on. For this purpose define methods like
191
+
192
+ def search_unusual_case(term, page, options)
193
+ # must has same behavior as search_default
194
+ end
195
+
196
+ near the `search_default` in `SearchAdapter`. Requirement for non-default search methods:
197
+
198
+ * it must has same behavior as search_default
199
+ * name of methods must start with `search_`
200
+
201
+ For use custom searcher specify it into `:href` within data-attribute `s2options`:
202
+
203
+ select2_autocompletes_path(class_name: MyClassName, search_method: :unusual_case)
204
+
205
+ Second, you may want to pass additional parameters in `SearchAdapter`. For example
206
+ select options depend from another field on page. For this purpose you can specify
207
+
208
+ additional_ajax_data: {selector: 'input.css-class'}
209
+
210
+ inside data-attribute `s2options`. In this case in options of `SearchAdapter` appear
211
+ additional values. It construct from name and value of html-elements. Example:
212
+
213
+ = hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@', class: 'add-to-select2'
214
+ = hidden_field_tag 'select2element', '',
215
+ class: 'auto-ajax-select2',
216
+ data: {s2options: { href: select2_autocompletes_path(class_name: :adapter_name,
217
+ search_method: :unusual_case),
218
+ additional_ajax_data: {selector: '.add-to-select2'}}}
219
+
220
+ Here we initialize ajax select2 and during load select variants in `SearchAdapter` options hash
221
+ appear key :token with value 'VUBJKB23UIVI1UU1VOBVI@'.
222
+
223
+ Third, in hash with items from search method exist additional optional parameter `class_name`.
224
+ This parameter specify css-class for result element in select2. It useful for show different
225
+ icons for different select variants.
226
+
227
+ ### Multi ajax select2 usage
228
+
229
+ This feature require absolutely same things as ajax select2. Additionally you must
230
+ add `multiple` css-class for input element, doesn't forget about
231
+ `multi_ajax_select2_value_parser.js` script and pass `multiple: true` into
232
+ data-attribute `s2options`.
233
+
234
+ ### Different multi ajax select2
235
+
236
+ Honestly speaking you can just pass `multiple: true` into data-attribute `s2options` and
237
+ ajax-select2 become multiple. But in this case selected options from select2 become as
238
+ comma separated string. As opposed to it `multi_ajax_select2_value_parser.js` make array
239
+ of multiple ids. This is more comfortable for use in controller.
240
+
241
+ ### Initializing
242
+
243
+ Scripts automatically initialize on `$(document).ready()` and after `ajaxSuccess`. Moreover
244
+ script handle [cocoon](https://github.com/nathanvda/cocoon) events and run on
245
+ `cocoon:after-insert`. If you for any reasons want to manually initializing select2,
246
+ you can call `initAutoAjaxSelect2()` and/or `initAutoStaticSelect2()`.
22
247
 
23
248
  ## Contributing
24
249
 
@@ -1,7 +1,17 @@
1
1
  class Select2AutocompletesController < ApplicationController
2
2
  def search
3
3
  begin
4
- adapter = "::Select2SearchAdapter::#{params[:class_name].camelize}SearchAdapter".constantize
4
+ if params[:class_name].present?
5
+ adapter = "::#{params[:class_name].camelize}SearchAdapter".constantize
6
+ elsif params[:default_class_name].present? &&
7
+ params[:default_text_column].present? &&
8
+ params[:default_id_column].present?
9
+ adapter = ::AutoSelect2::Select2SearchAdapter::Default
10
+ else
11
+ render json: {error: "not enough search parameters'"}.to_json,
12
+ status: 500
13
+ return
14
+ end
5
15
  rescue NameError
6
16
  render json: {error: "not found search adapter for '#{params[:class_name]}'"}.to_json,
7
17
  status: 500
data/config/routes.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  Rails.application.routes.draw do
2
- get 'select2_autocompletes/:class_name', to: 'select2_autocompletes#search',
3
- as: 'select2_autocompletes'
2
+ get 'select2_autocompletes/(:class_name)', to: 'select2_autocompletes#search',
3
+ as: 'select2_autocompletes'
4
4
  end
data/lib/auto_select2.rb CHANGED
@@ -1,16 +1,9 @@
1
1
  require 'auto_select2/version'
2
2
  require 'auto_select2/helpers'
3
- require 'select2_search_adapter/base'
3
+ require 'auto_select2/engine'
4
4
 
5
5
  module AutoSelect2
6
- class Engine < ::Rails::Engine
7
- # Get rails to add app, lib, vendor to load path
6
+ extend ActiveSupport::Autoload
8
7
 
9
- initializer :javascripts do |app|
10
- app.config.assets.precompile +=
11
- %w(auto_select2/ajax_select2.js
12
- auto_select2/multi_ajax_select2_value_parser.js
13
- auto_select2/static_select2.js)
14
- end
15
- end
8
+ autoload :Select2SearchAdapter
16
9
  end
@@ -0,0 +1,12 @@
1
+ module AutoSelect2
2
+ class Engine < ::Rails::Engine
3
+ # Get rails to add app, lib, vendor to load path
4
+
5
+ initializer :javascripts do |app|
6
+ app.config.assets.precompile +=
7
+ %w(auto_select2/ajax_select2.js
8
+ auto_select2/multi_ajax_select2_value_parser.js
9
+ auto_select2/static_select2.js)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module AutoSelect2
2
+ module Select2SearchAdapter
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Base
6
+ autoload :Default
7
+ end
8
+ end
@@ -0,0 +1,97 @@
1
+ module AutoSelect2
2
+ module Select2SearchAdapter
3
+ class Base
4
+ class << self
5
+ # Amount rows per ajax-request
6
+ def limit
7
+ 25 # TODO: move to settings/config
8
+ end
9
+
10
+ def search_from_autocomplete(term, page, search_method, options)
11
+ if search_method.nil?
12
+ search_default(term, page, options)
13
+ else
14
+ self.public_send("search_#{search_method}", term, page, options)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def default_finder(searched_class, term, options)
21
+ column = options[:column].present? ? options[:column] : 'name'
22
+ conditions = default_search_conditions(term, options[:basic_conditions], column)
23
+ if term.nil?
24
+ [ searched_class.where(options[:basic_conditions]) ]
25
+ else
26
+ skip_count = 0
27
+ unless options.nil? || options[:page].nil?
28
+ page = options[:page].to_i > 0 ? options[:page].to_i : 1
29
+ skip_count = limit * ( page - 1 )
30
+ end
31
+ query = searched_class.where( conditions ).limit( limit ).offset(skip_count).order(column)
32
+ query = query.select(options[:select]) if options[:select].present?
33
+ options[:uniq] ? query.uniq : query
34
+ end
35
+ end
36
+
37
+ def default_count(searched_class, term, options = {})
38
+ conditions = default_search_conditions(term, options[:basic_conditions], options[:column] || 'name')
39
+ query = searched_class.where(conditions)
40
+ query = query.select(options[:select]) if options[:select].present?
41
+ query = options[:uniq] ? query.uniq : query
42
+ query.count
43
+ end
44
+
45
+ def default_search_conditions(term, basic_conditions, columns)
46
+ term_filter = ''
47
+ conditions = []
48
+ columns = [columns] unless columns.is_a?(Array)
49
+ unless term.nil?
50
+ words = term.split(' ')
51
+ words.each_with_index do |word, index|
52
+ term_filter += ' AND ' if index > 0
53
+ columns.each_with_index do |column, idx|
54
+ term_filter += ' OR ' if idx > 0
55
+ term_filter += "#{column} LIKE ?"
56
+ conditions << "%#{word}%"
57
+ end
58
+ end
59
+ term_filter = term_filter.empty? ? nil : "(#{term_filter})"
60
+ basic_conditions_part = basic_conditions.present? ? "(#{basic_conditions }) " : nil
61
+ conditions.unshift([term_filter, basic_conditions_part].compact.join(' AND '))
62
+ end
63
+ end
64
+
65
+ def get_init_values(searched_class, ids, options = {})
66
+ title_method = options[:title_method]
67
+ id_column = options[:id_column] || searched_class.primary_key
68
+ ids = ids.split(',')
69
+ if ids.size > 1
70
+ result = []
71
+ ids.each do |id|
72
+ item = searched_class.where(id_column => id).first
73
+ if item.present?
74
+ result << get_select2_hash(item, title_method, id)
75
+ end
76
+ end
77
+ result
78
+ elsif ids.size == 1
79
+ item = searched_class.where(id_column => ids[0]).first
80
+ get_select2_hash(item, title_method, ids[0]) if item.present?
81
+ else
82
+ nil
83
+ end
84
+ end
85
+
86
+ def get_select2_hash(item, title_method, id)
87
+ if item.respond_to?(:to_select2) && title_method.blank?
88
+ item.to_select2
89
+ else
90
+ title_method ||= :name
91
+ { text: item.public_send(title_method), id: id }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,31 @@
1
+ module AutoSelect2
2
+ module Select2SearchAdapter
3
+ class Default < Base
4
+ class << self
5
+ def search_default(term, page, options)
6
+ begin
7
+ default_arel = options[:default_class_name].camelize.constantize
8
+ rescue NameError
9
+ return {error: "not found class '#{options[:default_class_name]}'"}.to_json
10
+ end
11
+
12
+ if options[:init].nil?
13
+ default_values = default_finder(default_arel, term, page: page,
14
+ column: options[:default_text_column])
15
+ default_count = default_count(default_arel, term, column: options[:default_text_column])
16
+ {
17
+ items: default_values.map do |default_value|
18
+ { text: default_value.public_send(options[:default_text_column]),
19
+ id: default_value.public_send(options[:default_id_column]) }
20
+ end,
21
+ total: default_count
22
+ }
23
+ else
24
+ get_init_values(default_arel, options[:item_ids], id_column: options[:default_id_column])
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -1,3 +1,3 @@
1
1
  module AutoSelect2
2
- VERSION = '0.1.2'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: auto_select2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitriy Lisichkin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-24 00:00:00.000000000 Z
12
+ date: 2014-12-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -116,10 +116,13 @@ files:
116
116
  - auto_select2.gemspec
117
117
  - config/routes.rb
118
118
  - lib/auto_select2.rb
119
+ - lib/auto_select2/engine.rb
119
120
  - lib/auto_select2/helpers.rb
120
121
  - lib/auto_select2/helpers/select2_helpers.rb
122
+ - lib/auto_select2/select2_search_adapter.rb
123
+ - lib/auto_select2/select2_search_adapter/base.rb
124
+ - lib/auto_select2/select2_search_adapter/default.rb
121
125
  - lib/auto_select2/version.rb
122
- - lib/select2_search_adapter/base.rb
123
126
  - vendor/assets/javascripts/auto_select2/ajax_select2.js.coffee
124
127
  - vendor/assets/javascripts/auto_select2/multi_ajax_select2_value_parser.js.coffee
125
128
  - vendor/assets/javascripts/auto_select2/static_select2.js.coffee
@@ -1,97 +0,0 @@
1
- module Select2SearchAdapter
2
- class Base
3
- class << self
4
- # Amount rows per ajax-request
5
- def limit
6
- 25 # TODO: move to settings/config
7
- end
8
-
9
- def search_from_autocomplete(term, page, search_method, options)
10
- if search_method.nil?
11
- search_default(term, page, options)
12
- else
13
- self.send("search_#{search_method}", term, page, options)
14
- end
15
- end
16
-
17
- private
18
-
19
- def default_finder(searched_class, term, options)
20
- column = options[:column].present? ? options[:column] : 'name'
21
- conditions = default_search_conditions(term, options[:basic_conditions], column)
22
- if term.nil?
23
- [ searched_class.where(options[:basic_conditions]) ]
24
- else
25
- skip_count = 0
26
- unless options.nil? || options[:page].nil?
27
- page = options[:page].to_i > 0 ? options[:page].to_i : 1
28
- skip_count = limit * ( page - 1 )
29
- end
30
- query = searched_class.where( conditions ).limit( limit ).offset(skip_count).order(column)
31
- query = query.select(options[:select]) if options[:select].present?
32
- options[:uniq] ? query.uniq : query
33
- end
34
- end
35
-
36
- def default_count(searched_class, term, options = {})
37
- conditions = default_search_conditions(term, options[:basic_conditions], options[:column] || 'name')
38
- query = searched_class.where(conditions)
39
- query = query.select(options[:select]) if options[:select].present?
40
- query = options[:uniq] ? query.uniq : query
41
- query.count
42
- end
43
-
44
- def default_search_conditions(term, basic_conditions, columns)
45
- term_filter = ''
46
- conditions = []
47
- columns = [columns] unless columns.is_a?(Array)
48
- unless term.nil?
49
- words = term.split(' ')
50
- words.each_with_index do |word, index|
51
- term_filter += ' AND ' if index > 0
52
- columns.each_with_index do |column, idx|
53
- term_filter += ' OR ' if idx > 0
54
- term_filter += "#{column} LIKE ?"
55
- conditions << "%#{word}%"
56
- end
57
- end
58
- term_filter = term_filter.empty? ? nil : "(#{term_filter})"
59
- basic_conditions_part = basic_conditions.present? ? "(#{basic_conditions }) " : nil
60
- conditions.unshift([term_filter, basic_conditions_part].compact.join(' AND '))
61
- end
62
- end
63
-
64
- def get_init_values(searched_class, ids, title_method=nil)
65
- ids = ids.split(',')
66
- if ids.size > 1
67
- result = []
68
- ids.each do |id|
69
- item = searched_class.find_by_id(id)
70
- if item.present?
71
- result << get_select2_hash(item, title_method, id)
72
- end
73
- end
74
- result
75
- elsif ids.size == 1
76
- item = searched_class.find_by_id(ids[0])
77
- if item.present?
78
- get_select2_hash(item, title_method, ids[0])
79
- else
80
- nil
81
- end
82
- else
83
- nil
84
- end
85
- end
86
-
87
- def get_select2_hash(item, title_method, id)
88
- if item.respond_to?(:to_select2) && title_method.nil?
89
- item.to_select2
90
- else
91
- title_method ||= :name
92
- { text: item.send(title_method), id: id }
93
- end
94
- end
95
- end
96
- end
97
- end