auto_select2 0.1.2 → 0.2.0

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

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