record_collection 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +217 -0
- data/Rakefile +16 -0
- data/app/assets/images/record_collection/.keep +0 -0
- data/app/assets/javascripts/record_collection/application.js.coffee +1 -0
- data/app/assets/javascripts/record_collection/multi_select.js.coffee +66 -0
- data/app/assets/javascripts/record_collection/optionals.js.coffee +101 -0
- data/app/assets/stylesheets/record_collection/application.css +15 -0
- data/app/assets/stylesheets/record_collection/multi_select.css.sass +20 -0
- data/app/assets/stylesheets/record_collection/optionals.css.sass +48 -0
- data/app/controllers/record_collection/application_controller.rb +4 -0
- data/app/helpers/record_collection/application_helper.rb +4 -0
- data/app/views/layouts/record_collection/application.html.erb +14 -0
- data/lib/record_collection.rb +12 -0
- data/lib/record_collection/base.rb +98 -0
- data/lib/record_collection/engine.rb +5 -0
- data/lib/record_collection/name.rb +7 -0
- data/lib/record_collection/rails/form_options_helper.rb +48 -0
- data/lib/record_collection/rails/routes.rb +21 -0
- data/lib/record_collection/version.rb +3 -0
- data/record_collection.gemspec +43 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js.coffee +10 -0
- data/spec/dummy/app/assets/stylesheets/application.css.sass +4 -0
- data/spec/dummy/app/assets/stylesheets/components/_forms.css.sass +0 -0
- data/spec/dummy/app/assets/stylesheets/components/_structure.css.sass +0 -0
- data/spec/dummy/app/assets/stylesheets/scaffolds.scss +69 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/controllers/employees_controller.rb +75 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/employee.rb +2 -0
- data/spec/dummy/app/models/employee/collection.rb +6 -0
- data/spec/dummy/app/models/project.rb +2 -0
- data/spec/dummy/app/views/application/_form_errors.html.slim +8 -0
- data/spec/dummy/app/views/employees/_form.html.erb +25 -0
- data/spec/dummy/app/views/employees/batch_actions.html.slim +13 -0
- data/spec/dummy/app/views/employees/edit.html.erb +6 -0
- data/spec/dummy/app/views/employees/index.html.slim +25 -0
- data/spec/dummy/app/views/employees/new.html.erb +5 -0
- data/spec/dummy/app/views/employees/show.html.erb +14 -0
- data/spec/dummy/app/views/layouts/application.html.slim +10 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/locales/models.en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/migrate/20150203124634_create_employees.rb +10 -0
- data/spec/dummy/db/migrate/20150204103712_add_vegan_to_employees.rb +5 -0
- data/spec/dummy/db/migrate/20150204103925_add_admin_to_employees.rb +5 -0
- data/spec/dummy/db/migrate/20150204125014_create_projects.rb +11 -0
- data/spec/dummy/db/schema.rb +33 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/features/multi_select_spec.rb +23 -0
- data/spec/fixtures/collections.rb +0 -0
- data/spec/record_selection/base_spec.rb +113 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/validations_spec.rb +19 -0
- metadata +482 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 57c83b9fc9b46bcfed66a78f8966f8a71a48cee6
|
4
|
+
data.tar.gz: 0c28f323778b1c26db44f619ebe7814cdc435263
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0833cd40aa97cf4c08af7be2feff96543b776eb024bb2ccd287b8b081fd3d492eb919e5b97ae7b29669fdced058c1191b49b1eb2f4b97f8da3e4b9b6c9160441
|
7
|
+
data.tar.gz: 9e7768139cba271ec1d58fb48c8e166609547708ee341d41a599d3de05751dfcfd15ae7aa87edc8961b92f17419d744126e55cb0a9ad9ebec11dcf17b9ae6c2c
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
/.yardoc
|
2
|
+
/Gemfile.lock
|
3
|
+
/_yardoc/
|
4
|
+
/coverage/
|
5
|
+
/doc/
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/tmp/
|
9
|
+
*.bundle
|
10
|
+
*.so
|
11
|
+
*.o
|
12
|
+
*.a
|
13
|
+
mkmf.log
|
14
|
+
/temt
|
15
|
+
.bundle/
|
16
|
+
log/*.log
|
17
|
+
pkg/
|
18
|
+
spec/dummy/db/*.sqlite3
|
19
|
+
spec/dummy/db/*.sqlite3-journal
|
20
|
+
spec/dummy/log/*.log
|
21
|
+
spec/dummy/tmp/
|
22
|
+
spec/dummy/spec/
|
23
|
+
spec/dummy/.sass-cache
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Benjamin ter Kuile
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# RecordCollection
|
2
|
+
[<img src="https://secure.travis-ci.org/bterkuile/record_collection.png?branch=master" alt="Build Status" />](http://travis-ci.org/bterkuile/record_collection)
|
3
|
+
|
4
|
+
record\_collection is a gem that adds functionality to rails to work
|
5
|
+
with collections. This consists of a few components:
|
6
|
+
|
7
|
+
* Collection objects containing some active record models and acting on
|
8
|
+
that collection.
|
9
|
+
* the multi\_select helpers for selecting records from the index page
|
10
|
+
* the optionals helpers for managing attributes on the collection of
|
11
|
+
records you may or may not want to edit in the collection form
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'record_collection'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install record_collection
|
28
|
+
|
29
|
+
## Adding routes
|
30
|
+
Add two collection routes to the normal resources definition.
|
31
|
+
This call behaves exactly as the normal resources :... call,
|
32
|
+
but adds:
|
33
|
+
```ruby
|
34
|
+
collection do
|
35
|
+
get :batch_actions
|
36
|
+
post :process_batch
|
37
|
+
end
|
38
|
+
```
|
39
|
+
So the route definition in `config/routes.rb` defined as:
|
40
|
+
```ruby
|
41
|
+
batch_resources :employees, except: [:new]
|
42
|
+
```
|
43
|
+
is exactly the same as:
|
44
|
+
```ruby
|
45
|
+
resources :employees, except: [:new] do
|
46
|
+
collection do
|
47
|
+
get :batch_actions
|
48
|
+
post :process_batch
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
## Defining the collection
|
54
|
+
A good practice is to define your collection as a subclass of your
|
55
|
+
resource class. So an employees collection should be defined like:
|
56
|
+
`app/models/employee.rb`:
|
57
|
+
```ruby
|
58
|
+
class Employee < ActiveRecord::Base
|
59
|
+
# attribute :admin, type: Boolean (defined by database)
|
60
|
+
validates :name, presence: true
|
61
|
+
|
62
|
+
end
|
63
|
+
```
|
64
|
+
`app/models/employee/collection.rb`:
|
65
|
+
```ruby
|
66
|
+
class Employee::Collection < RecordCollection::Base
|
67
|
+
attribute :name
|
68
|
+
validates :section, format: {with: /\A\w{3}\Z/, if: 'section.present?' }
|
69
|
+
attribute :admin, type: Boolean
|
70
|
+
attribute :vegan, type: Boolean
|
71
|
+
end
|
72
|
+
```
|
73
|
+
See the [active_attr](https://github.com/cgriego/active_attr) gem for
|
74
|
+
attribute definitions.
|
75
|
+
|
76
|
+
## Defining your controllers
|
77
|
+
If you already used the specification `batch_resources :employees` in
|
78
|
+
your [config/routes.rb](spec/dummy/config/routes.rb) file you can add
|
79
|
+
the actions in your controller typically looking like:
|
80
|
+
```ruby
|
81
|
+
class EmployeesController < ApplicationController
|
82
|
+
# your standard actions here
|
83
|
+
|
84
|
+
# GET /employees/batch_actions?ids[]=1&ids[]=3&...
|
85
|
+
def batch_actions
|
86
|
+
@employees = Employee.find(Array.wrap(params[:ids]))
|
87
|
+
@collection = Employee::Collection.new(@employees)
|
88
|
+
redirect_to employees_path, alert: 'No employees selected' if @collection.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
# POST /employees/process_batch
|
92
|
+
def process_batch
|
93
|
+
@employees = Employee.find(Array.wrap(params[:ids]))
|
94
|
+
@collection = Employee::Collection.new(@employees, params[:collection])
|
95
|
+
if @collection.save
|
96
|
+
redirect_to employees_path, notice: 'Collection is updated'
|
97
|
+
else
|
98
|
+
render 'batch_actions'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
```
|
103
|
+
For more advanced use of the collection the pattern above can of course
|
104
|
+
be different eg: different collection objects for the same active record
|
105
|
+
model types.
|
106
|
+
|
107
|
+
## Creating your views
|
108
|
+
The
|
109
|
+
[app/views/employess/batch_actions.html.slim](spec/dummy/app/views/employees/batch_actions.html.slim) view is a tricky one.
|
110
|
+
Since we are working on a collection of record, and want to edit those
|
111
|
+
attributes we just want a normal form for editing the attributes,
|
112
|
+
treating the collection as the record itself. The problem however is
|
113
|
+
that some attributes can be in a mixed state, say two employees, one
|
114
|
+
having `admin => true`, the other one `admin => false`. If I only want
|
115
|
+
to update the section they are both in, I want to leave the admin
|
116
|
+
attribute allone. To accomplish this, this gem provides the `optional`
|
117
|
+
helpers. These helpers make it easy to manage a form of attributes where
|
118
|
+
you can determine which attributes you want to manage for this
|
119
|
+
particular collection of records. This gem also support [simple_form](https://github.com/plataformatec/simple_form)
|
120
|
+
gem where you can replace `f.input :attribute, ...etc` with
|
121
|
+
`f.optional_input :attribute, ...etc`. Our current example works with
|
122
|
+
the standard [form_helpers](http://guides.rubyonrails.org/form_helpers.html)<br>
|
123
|
+
### currently supported helpers:
|
124
|
+
* `optional_boolean`
|
125
|
+
* `optional_text_field`
|
126
|
+
* `optional_input` ([simple_form](https://github.com/plataformatec/simple_form))
|
127
|
+
|
128
|
+
The form you create typically looks like:
|
129
|
+
```slim
|
130
|
+
h1 Edit multiple employees
|
131
|
+
= form_for @collection, url: [:process_batch, @collection.record_class] do |f|
|
132
|
+
= f.collection_ids
|
133
|
+
.form-inputs= f.optional_text_field :section
|
134
|
+
.form-inputs= f.optional_boolean :admin
|
135
|
+
.form-inputs= f.optional_boolean :vegan
|
136
|
+
.form-actions= f.submit
|
137
|
+
.page-actions
|
138
|
+
= link_to 'Back', employees_path
|
139
|
+
```
|
140
|
+
|
141
|
+
That is the view part. Be sure to read the optionals section for a
|
142
|
+
better understanding of how the optional fields work.
|
143
|
+
|
144
|
+
## Selecting records from the index using checkboxes (multi_select)
|
145
|
+
The idea behind working with collections is that you end up as a `GET` request at:
|
146
|
+
`+controller+/batch_actions?ids[]=2&ids[]=3` etc. How you achieve this
|
147
|
+
is totally up to yourself, but this gem provides you with a nice
|
148
|
+
standard way of selecting records from the index page. To filter records
|
149
|
+
to a specific subset the [ransack](https://github.com/activerecord-hackery/ransack)
|
150
|
+
gem also provides a nice way to add filtering to the index page. To add
|
151
|
+
checkbox selecting to your page this gem assumes the following
|
152
|
+
structure using the [Slim lang](http://slim-lang.com/):
|
153
|
+
```slim
|
154
|
+
table.with-selection
|
155
|
+
thead
|
156
|
+
tr
|
157
|
+
th Name
|
158
|
+
th Section
|
159
|
+
tbody
|
160
|
+
- @employees.each do |employee|
|
161
|
+
tr data-record=employee.attributes.to_json
|
162
|
+
```
|
163
|
+
Note that each row needs a json version of the record at least
|
164
|
+
containing its id.<br>
|
165
|
+
Implement the multiselect dependencies in your manifest files, typically
|
166
|
+
being `app/assets/javascripts/application.js`:
|
167
|
+
```javascript
|
168
|
+
//= require record_collection/multi_select
|
169
|
+
```
|
170
|
+
And for the styling provided by this gem ([app/assets/stylesheets/application.css](spec/dummy/app/assets/stylesheets/application.css.sass)):
|
171
|
+
```css
|
172
|
+
/*
|
173
|
+
*= require record_collection/multi_select
|
174
|
+
*/
|
175
|
+
```
|
176
|
+
The styling uses the [font-awesome-rails](http://fortawesome.github.io/Font-Awesome/) gem, so this gem should be
|
177
|
+
present in your `Gemfile`:
|
178
|
+
```ruby
|
179
|
+
gem 'font-awesome-rails'
|
180
|
+
```
|
181
|
+
Of course you are welcome to create your own awesome styling and send it
|
182
|
+
to me so I can add it as a theme :smile:.
|
183
|
+
|
184
|
+
## Optionals
|
185
|
+
Optionals is the name for the feature in this gem that activates
|
186
|
+
collection attributes to be sumitted in the form or not. Since for a
|
187
|
+
mixed collection on an attribute you might not want to edit, but another
|
188
|
+
attribute you do want to edit you add the optionals functionality to
|
189
|
+
your manifests. This is similar to the `multi_select` feature:
|
190
|
+
```javascript
|
191
|
+
//= require record_collection/optionals
|
192
|
+
```
|
193
|
+
And for the styling provided by this gem ([app/assets/stylesheets/application.css](spec/dummy/app/assets/stylesheets/application.css.sass)):
|
194
|
+
```css
|
195
|
+
/*
|
196
|
+
*= require record_collection/optionals
|
197
|
+
*/
|
198
|
+
```
|
199
|
+
|
200
|
+
**TODO: more explanation about optionals**
|
201
|
+
|
202
|
+
## Special thanks
|
203
|
+
|
204
|
+
Special thanks for this project goes to:<br>
|
205
|
+
<a href="http://companytools.nl/" target="_blank"><img src="http://companytools.nl/assets/logo2-f5f9a19c745e753a4d52b5c0a1a7c6d7.png" alt="Companytools"></a>
|
206
|
+
|
207
|
+
<a href="http://fourstack.nl" target="_blank"><img src="http://fourstack.nl/logo1.png" alt="FourStack"></a>
|
208
|
+
|
209
|
+
<a href="http://www.kpn.com" target="_blank"><img src="http://www.kpn.com/ss/Satellite/yavUnLl8hN7yMh6Gh2IPWqYD60HbUkXsNK4iD8PcUpR0bnBXyZZtwQUuCgSUG72CJE/MungoBlobs/kpn_logo.png"></a>
|
210
|
+
|
211
|
+
## Contributing
|
212
|
+
|
213
|
+
1. Fork it ( https://github.com/bterkuile/record_collection/fork )
|
214
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
215
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
216
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
217
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
require "bundler/gem_tasks"
|
7
|
+
|
8
|
+
require 'rspec/core'
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
|
11
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
12
|
+
#RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
|
13
|
+
RSpec::Core::RakeTask.new(:spec)
|
14
|
+
|
15
|
+
task default: :spec
|
16
|
+
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
#= require_tree .
|
@@ -0,0 +1,66 @@
|
|
1
|
+
class MultiSelect
|
2
|
+
setup: (table) ->
|
3
|
+
return unless table and table.length
|
4
|
+
table.data 'multi_select', @
|
5
|
+
@set 'table', table
|
6
|
+
|
7
|
+
@set 'resource', table.data('resource')
|
8
|
+
# Add an extra th to all header rows
|
9
|
+
table.find('thead tr').each -> $(this).prepend("<th></th>")
|
10
|
+
|
11
|
+
# Create a toggle for selecting an deselecting all records
|
12
|
+
# and add it to the last header row
|
13
|
+
#toggle_all = $("<input type='checkbox'></input>").addClass('selection-toggle-all').click ->
|
14
|
+
#checked = $(this).is(':checked')
|
15
|
+
#table.find('td.selection input').prop 'checked', checked
|
16
|
+
toggle_all = $("<span></span>").addClass('selection-toggle-all unchecked').click ->
|
17
|
+
if $(this).hasClass('checked')
|
18
|
+
table.find('td.selection .checker').removeClass('checked').addClass('unchecked')
|
19
|
+
$(this).removeClass('checked').addClass('unchecked')
|
20
|
+
else
|
21
|
+
table.find('td.selection .checker').removeClass('unchecked').addClass('checked')
|
22
|
+
$(this).removeClass('unchecked').addClass('checked')
|
23
|
+
table.find('thead tr:last th:first').append toggle_all
|
24
|
+
|
25
|
+
# Create a toggle/checkbox for all records and add it to the row
|
26
|
+
#record_toggle = $("<input type='checkbox'></input>")
|
27
|
+
record_toggle = $("<span></span>").addClass('checker unchecked').click ->
|
28
|
+
if $(this).hasClass('checked')
|
29
|
+
$(this).removeClass('checked').addClass('unchecked')
|
30
|
+
else
|
31
|
+
$(this).removeClass('unchecked').addClass('checked')
|
32
|
+
record_td = $('<td></td>').addClass('selection').append(record_toggle)
|
33
|
+
table.find('tbody tr').prepend record_td
|
34
|
+
|
35
|
+
@setup_selection_actions()
|
36
|
+
|
37
|
+
toggle_all.click() if table.data('preselected')
|
38
|
+
|
39
|
+
# Find all buttons in the table footer and attach the action given their action data attribute
|
40
|
+
setup_selection_actions: ->
|
41
|
+
selector = this
|
42
|
+
@table.find('tfoot button').click ->
|
43
|
+
$.post Routes["actions_#{selector.get('resource')}_path"](),
|
44
|
+
ids: selector.selected_ids().toArray()
|
45
|
+
selection_action: $(this).data('action')
|
46
|
+
|
47
|
+
# use set and get as a good reactive pattern
|
48
|
+
# implement the raw version, can become more complex int the future
|
49
|
+
set: (path, value) -> @[path] = value
|
50
|
+
get: (path) -> @[path]
|
51
|
+
|
52
|
+
#selected_records: -> @table.find("td.selection input:checked").map( -> $(this).parents('tr').data('record') )
|
53
|
+
selected_records: -> @table.find("td.selection .checked").map( -> $(this).parents('tr').data('record') )
|
54
|
+
selected_ids: -> @selected_records().map( -> this.id ).toArray()
|
55
|
+
root = @
|
56
|
+
root.MultiSelect = new MultiSelect()
|
57
|
+
$.fn.multi_select = ->
|
58
|
+
if @.hasClass('with-selection') or @.prop('tagName') is 'TABLE'
|
59
|
+
select = new MultiSelect()
|
60
|
+
root.MultiSelect = select
|
61
|
+
select.setup @
|
62
|
+
else
|
63
|
+
@.find('table.with-selection').each (i, el)->
|
64
|
+
select = new MultiSelect()
|
65
|
+
root.MultiSelect = select
|
66
|
+
select.setup $(el)
|
@@ -0,0 +1,101 @@
|
|
1
|
+
class Optionals
|
2
|
+
setup: (target)->
|
3
|
+
@setup_inputs(target)
|
4
|
+
|
5
|
+
setup_inputs: (target)->
|
6
|
+
target.find('.optional-attribute-container').each (i, el)=>
|
7
|
+
container = $(el)
|
8
|
+
if container.hasClass('optional-boolean')
|
9
|
+
@optionalBoolean container
|
10
|
+
else
|
11
|
+
@prependActivator(container)
|
12
|
+
|
13
|
+
# Replace the <input type="checkbox"> for a <input type="hidden" # value="0|1"> fields
|
14
|
+
# managed by the javascript
|
15
|
+
optionalBoolean: (container)->
|
16
|
+
check_box = container.find('input')
|
17
|
+
initially_checked = check_box.is(':checked')
|
18
|
+
field_name = check_box.attr('name')
|
19
|
+
|
20
|
+
label_text = container.find('label').text()
|
21
|
+
|
22
|
+
value_field = $('<input>').attr('type', 'hidden').val(0)
|
23
|
+
# Set name based on activated state
|
24
|
+
if container.hasClass('active')
|
25
|
+
value_field.attr 'name', field_name
|
26
|
+
else
|
27
|
+
value_field.attr 'name', "disabled_#{field_name}"
|
28
|
+
|
29
|
+
# Clear the container and initialize to inactive
|
30
|
+
container.html('')
|
31
|
+
|
32
|
+
label = $('<span></span>').addClass('optional-boolean-label').text label_text
|
33
|
+
|
34
|
+
activator_toggle = $('<span></span>').addClass('optional-boolean-activator-toggle').click ->
|
35
|
+
container.toggleClass('active').toggleClass('inactive')
|
36
|
+
if container.hasClass('active')
|
37
|
+
value_field.attr 'name', value_field.attr('name').replace(/^disabled_/, '')
|
38
|
+
else
|
39
|
+
value_field.attr 'name', "disabled_#{value_field.attr('name')}"
|
40
|
+
|
41
|
+
value_toggle = $('<span></span>').addClass('optional-boolean-toggle').click ->
|
42
|
+
return if container.hasClass('inactive')
|
43
|
+
if $(@).hasClass('active')
|
44
|
+
value_field.val(0)
|
45
|
+
$(@).removeClass('active').addClass('inactive')
|
46
|
+
else
|
47
|
+
value_field.val(1)
|
48
|
+
$(@).addClass('active').removeClass('inactive')
|
49
|
+
|
50
|
+
if initially_checked
|
51
|
+
value_toggle.addClass('active')
|
52
|
+
value_field.val(1)
|
53
|
+
else
|
54
|
+
value_toggle.addClass('inactive')
|
55
|
+
|
56
|
+
container.append activator_toggle
|
57
|
+
container.append label
|
58
|
+
container.append value_toggle
|
59
|
+
container.append value_field
|
60
|
+
|
61
|
+
prependActivator: (container)->
|
62
|
+
value_field = container.find('select,input')
|
63
|
+
# INITIAL STATE IS DISABLED, Activation by triggering click if needed
|
64
|
+
value_field.attr 'name', "disabled_#{value_field.attr('name')}"
|
65
|
+
|
66
|
+
label_text = container.find('label').text()
|
67
|
+
|
68
|
+
# Activator container
|
69
|
+
activator_container = $('<div></div>').addClass('optional-input-activator-container inactive')
|
70
|
+
activator_container.addClass container.data('attribute')
|
71
|
+
activator_container.addClass('error') if container.hasClass('error')
|
72
|
+
activator_toggle = $('<span></span>').addClass('optional-input-activator-toggle').click ->
|
73
|
+
activator_container.toggleClass('active').toggleClass('inactive')
|
74
|
+
#label.toggleClass('inactive')
|
75
|
+
if activator_container.hasClass('active')
|
76
|
+
value_field.attr 'name', value_field.attr('name').replace(/^disabled_/, '')
|
77
|
+
#value_toggle.show()
|
78
|
+
container.removeClass('inactive')
|
79
|
+
else
|
80
|
+
value_field.attr 'name', "disabled_#{value_field.attr('name')}"
|
81
|
+
#value_toggle.hide()
|
82
|
+
container.addClass('inactive')
|
83
|
+
activator_label = $('<span></span>').addClass('optional-input-activator-label').text label_text
|
84
|
+
activator_container.append activator_toggle
|
85
|
+
activator_container.append activator_label
|
86
|
+
|
87
|
+
container.before(activator_container)
|
88
|
+
|
89
|
+
container.find('label').remove()
|
90
|
+
|
91
|
+
activator_toggle.click() if container.hasClass('active')
|
92
|
+
|
93
|
+
root = @
|
94
|
+
root.Optionals = new Optionals()
|
95
|
+
$.fn.optionals = (action_or_options = {})->
|
96
|
+
if typeof action_or_options is 'string'
|
97
|
+
#nothing
|
98
|
+
else
|
99
|
+
optionals = new Optionals(action_or_options)
|
100
|
+
optionals.setup(@)
|
101
|
+
root.Optionals = optionals
|