smart_listing 0.9.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +211 -4
  3. data/app/assets/javascripts/{smart_listing/smart_listing.coffee.erb → smart_listing.coffee.erb} +35 -18
  4. data/app/helpers/smart_listing/helper.rb +50 -36
  5. data/app/views/kaminari/smart_listing/_first_page.html.erb +13 -0
  6. data/app/views/kaminari/smart_listing/_gap.html.erb +8 -0
  7. data/app/views/kaminari/smart_listing/_last_page.html.erb +13 -0
  8. data/app/views/kaminari/smart_listing/_next_page.html.erb +13 -0
  9. data/app/views/kaminari/smart_listing/_page.html.erb +12 -0
  10. data/app/views/kaminari/smart_listing/_paginator.html.erb +25 -0
  11. data/app/views/kaminari/smart_listing/_prev_page.html.erb +13 -0
  12. data/app/views/smart_listing/_action_custom.html.erb +1 -1
  13. data/app/views/smart_listing/_action_delete.html.erb +2 -1
  14. data/app/views/smart_listing/_action_edit.html.erb +2 -1
  15. data/app/views/smart_listing/_action_show.html.erb +2 -1
  16. data/app/views/smart_listing/_pagination_per_page_link.html.erb +1 -1
  17. data/app/views/smart_listing/_sortable.html.erb +3 -3
  18. data/app/views/smart_listing/item/_create.js.erb +1 -0
  19. data/app/views/smart_listing/item/_create_continue.js.erb +1 -1
  20. data/config/locales/en.yml +2 -0
  21. data/lib/generators/smart_listing/templates/initializer.rb +16 -1
  22. data/lib/smart_listing.rb +123 -51
  23. data/lib/smart_listing/config.rb +35 -6
  24. data/lib/smart_listing/version.rb +1 -1
  25. metadata +12 -8
  26. data/app/assets/javascripts/smart_listing/application.js +0 -14
  27. data/app/assets/stylesheets/smart_listing/application.css +0 -13
  28. data/app/views/smart_listing/_action_inactive.html.erb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4fcf22c0d95a61711b265aa25f2a270a3f2b7e1
4
- data.tar.gz: 723a731a8be9bd2b62db1dbf94fe3d2c9b06aeb2
3
+ metadata.gz: 41dcdfa429d72c12038175a0eb1252ad399b2a71
4
+ data.tar.gz: d277995fe1f1474795326b8db38c0fd07b307c0f
5
5
  SHA512:
6
- metadata.gz: 665a03580d6ee2de1251f25623cac4bcb93ca469ca17a9fd60e81314b73cd7558503813d21a85ae687636ff8af701e009200b095e697e7a2988febad8d555b8d
7
- data.tar.gz: 28091b9aa284ee8ae36e3e2b1837547231aeeddc3518dce04f320bc5ac416f86725c30971da4168fff89f44ee6391d5443941f87a270230398753ba3d9e3f9e2
6
+ metadata.gz: 6feb82a31cbe7dfdad359b3427325447a4ea63ad425189c752da1e93a9e1612ca32adb2d0f08f489193f9a29854721cf849b6e78f33c67f8789e8546d937e24c
7
+ data.tar.gz: c958ec953a3b49097490e90affb1785af82fa62c8318feafc7d3a72f37ebd86e8ca977dd9e47171dda0a289633e72c6819befa15995ce3ca0e857b526354544a
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # SmartListing
2
2
 
3
- SmartListing helps creating sortable lists of ActiveRecord collections with pagination, filtering and inline editing.
3
+ SmartListing helps creating AJAX-enabled lists of ActiveRecord collections or arrays with pagination, filtering, sorting and in-place editing.
4
+
5
+ [See it in action](http://showcase.sology.eu/smart_listing)
4
6
 
5
7
  ## Installation
6
8
 
@@ -16,23 +18,228 @@ Then run:
16
18
  $ bundle install
17
19
  ```
18
20
 
21
+ Also, you need to add SmartListing to your asset pipeline:
22
+
23
+ ```
24
+ //= require smart_listing
25
+ ```
26
+
27
+ ### Initializer
28
+
19
29
  Optionally you can also install some configuration initializer:
20
30
 
21
31
  ```sh
22
32
  $ rails generate smart_listing:install
23
33
  ```
24
34
 
25
- and views in order to customize them:
35
+ It will be placed in `config/initializers/smart_listing.rb` and will allow you to tweak some configuration settings like HTML classes and data attributes names.
36
+
37
+ ### Custom views
38
+
39
+ SmartListing comes with some built-in views which are by default compatible with Bootstrap 3. You can easily change them after installing:
26
40
 
27
41
  ```sh
28
42
  $ rails generate smart_listing:views
29
43
  ```
30
44
 
45
+ Files will be placed in `app/views/smart_listing`.
46
+
31
47
  ## Usage
32
48
 
33
- Pending...
49
+ Let's start with a controller. In order to use SmartListing, in most cases you need to include controller extensions and SmartListing helper methods:
50
+
51
+ ```ruby
52
+ include SmartListing::Helper::ControllerExtensions
53
+ helper SmartListing::Helper
54
+ ```
55
+
56
+ Next, put following code in controller action you desire:
57
+
58
+ ```ruby
59
+ @users = smart_listing_create(:users, User.active, partial: "users/listing")
60
+ ```
61
+
62
+ This will create SmartListing named `:users` consisting of ActiveRecord scope `User.active` elements and rendered by partial `users/listing`. You can also use arrays instead of ActiveRecord collections. Just put @array: true@ option just like for Kaminari.
63
+
64
+ In the main view (typically something like `index.html.erb` or `index.html.haml`), use this method to render listing:
65
+
66
+ ```ruby
67
+ smart_listing_render(:users)
68
+ ```
69
+
70
+ `smart_listing_render` does some magic and renders `users/listing` partial which may look like this (in HAML):
71
+
72
+ ```haml
73
+ - unless smart_listing.empty?
74
+ %table
75
+ %thead
76
+ %tr
77
+ %th User name
78
+ %th Email
79
+ %tbody
80
+ - smart_listing.collection.each do |user|
81
+ %tr
82
+ %td= user.name
83
+ %td= user.email
84
+
85
+ = smart_listing.paginate
86
+ - else
87
+ %p.warning No records!
88
+ ```
89
+
90
+ You can see that listing template has access to special `smart_listing` local variable which is basically an instance of `SmartListing::Helper::Builder`. It provides you with some helper methods that ease rendering of SmartListing:
91
+
92
+ * `Builder#paginate` - renders Kaminari pagination,
93
+ * `Builder#pagination_per_page_links` - display some link that allow you to customize Kaminari's `per_page`,
94
+ * `Builder#collection` - accesses underlying list of items,
95
+ * `Builder#empty?` - checks if collection is empty,
96
+ * `Builder#count` - returns collection count,
97
+ * `Builder#render` - basic template's `render` wrapper that automatically adds `smart_listing` local variable,
98
+
99
+ There are also other methods that will be described in detail below.
100
+
101
+ If you are using SmartListing with AJAX on (by default), one last thing required to make pagination (and other features) work is to create JS template for main view (typically something like `index.js.erb`):
102
+
103
+ ```erb
104
+ <%= smart_listing_update(:users) %>
105
+ ```
106
+
107
+ ### Sorting
108
+
109
+ SmartListing supports two modes of sorting: implicit and explicit. Implicit mode is enabled by default. In this mode, you define sort columns directly in the view:
110
+
111
+ ```haml
112
+ - unless smart_listing.empty?
113
+ %table
114
+ %thead
115
+ %tr
116
+ %th= smart_listing.sortable "User name", "name"
117
+ %th= smart_listing.sortable "Email", "email"
118
+ %tbody
119
+ - smart_listing.collection.each do |user|
120
+ %tr
121
+ %td= user.name
122
+ %td= user.email
123
+
124
+ = smart_listing.paginate
125
+ - else
126
+ %p.warning No records!
127
+ ```
128
+
129
+ In this case `"name"` and `"email"` are sorting column names. `Builder#sortable` renders special link containing column name and sort order (either `asc`, `desc`, or empty value).
130
+
131
+ You can also specify default sort order in the controller:
132
+
133
+ ```ruby
134
+ @users = smart_listing_create(:users, User.active, partial: "users/listing", default_sort: {:name: "asc"})
135
+ ```
136
+
137
+ Implicit mode is convenient with simple data sets. In case you want to sort by joined column names, we advise you to use explicit sorting:
138
+ ```ruby
139
+ @users = smart_listing_create :users, User.active.joins(:stats), partial: "users/listing",
140
+ sort_attributes: [[:last_signin, "stats.last_signin_at"]],
141
+ default_sort: {last_signin: "desc"}
142
+ ```
143
+
144
+ Note that `:sort_attributes` are array which of course means, that order of attributes matters.
145
+
146
+ ### List item management and in-place editing
147
+
148
+ In order to allow managing and editing list items, we need to reorganize our views a bit. Basically, each item needs to have its own partial:
149
+
150
+ ```haml
151
+ - unless smart_listing.empty?
152
+ %table
153
+ %thead
154
+ %tr
155
+ %th= smart_listing.sortable "User name", "name"
156
+ %th= smart_listing.sortable "Email", "email"
157
+ %th
158
+ %tbody
159
+ - smart_listing.collection.each do |user|
160
+ %tr.editable{data: {id: user.id}}
161
+ = smart_listing.render partial: 'users/user', locals: {user: user}
162
+ = smart_listing.item_new colspan: 3, link: new_user_path
163
+
164
+ = smart_listing.paginate
165
+ - else
166
+ %p.warning No records!
167
+ ```
168
+
169
+ `<tr>` has now `editable` class and `data-id` attribute. These are essential to make it work. We've used also a new helper: `Builder#new_item`. It renders new row which is used for adding new items. `:link` needs to be valid url to new resource action which renders JS:
170
+
171
+ ```ruby
172
+ <%= smart_listing_item :users, :new, @new_user, "users/form" %>
173
+ ```
174
+
175
+ Note that `new` action does not need to create SmartListing (via `smart_listing_create`). It just initializes `@new_user` and renders JS view.
176
+
177
+ New partial for user (`users/user`) may look like this:
178
+ ```haml
179
+ %td= user.name
180
+ %td= user.email
181
+ %td.actions= smart_listing_item_actions [{name: :edit, url: edit_user_path(user)}, {name: :destroy, url: user_path(user)}]
182
+ ```
183
+
184
+ `smart_listing_item_actions` renders here links that allow to edit and destroy user item. `:edit` and `:destroy` are built-in actions, you can also define your `:custom` actions. Again. `<td>`'s class `actions` is important.
185
+
186
+ Controller actions referenced by above urls are again plain Ruby on Rails actions that render JS like:
187
+
188
+ ```erb
189
+ <%= smart_listing_item :users, :new, @user, "users/form" %>
190
+ <%= smart_listing_item :users, :edit, @user, "users/form" %>
191
+ <%= smart_listing_item :users, :destroy, @user %>
192
+ ```
193
+
194
+ Partial name supplied to `smart_listing_item` (`users/form`) references `@user` as `object` and may look like this:
195
+
196
+ ```haml
197
+ %td{colspan: 3}
198
+ - if object.persisted?
199
+ %p Edit user
200
+ - else
201
+ %p Add user
202
+
203
+ = form_for object, url: object.new_record? ? users_path : user_path(object), remote: true do |f|
204
+ %p
205
+ Name:
206
+ = f.text_field :name
207
+ %p
208
+ Email:
209
+ = f.text_field :email
210
+ %p= f.submit "Save"
211
+ ```
212
+
213
+ And one last thing are `create` and `update` controller actions JS view:
214
+
215
+ ```ruby
216
+ <%= smart_listing_item :users, :create, @user, @user.persisted? ? "users/user" : "users/form" %>
217
+ <%= smart_listing_item :users, :update, @user, @user.valid? ? "users/user" : "users/form" %>
218
+ ```
219
+
220
+ ### Controls (filtering)
221
+
222
+ SmartListing controls allow you to change somehow presented data. This is typically used for filtering records. Let's see how view with controls may look like:
223
+
224
+ ```haml
225
+ = smart_listing_controls_for(:users) do
226
+ .filter.input-append
227
+ = text_field_tag :filter, '', class: "search", placeholder: "Type name here", autocomplete: "off"
228
+ %button.btn.disabled{type: "submit"}
229
+ %i.icon.icon-search
230
+ ```
231
+
232
+ This gives you nice Bootstrap-enabled filter field with keychange handler. Of course you can use any other form fields in controls too.
233
+
234
+ When form field changes its value, form is submitted and request is made. This needs to be handled in controller:
235
+
236
+ ```ruby
237
+ users_scope = User.active.joins(:stats)
238
+ users_scope = users_scope.like(params[:filter]) if params[:filter]
239
+ @users = smart_listing_create :users, users_scope, partial: "users/listing"
240
+ ```
34
241
 
35
- ### View
242
+ Then, JS view is rendered and your SmartListing updated. That's it!
36
243
 
37
244
  ## Credits
38
245
 
@@ -1,6 +1,6 @@
1
1
  # Useful when SmartListing target url is different than current one
2
2
  $.rails.href = (element) ->
3
- element.attr('href') || element.data('<% SmartListing.config.data_attributes(:href) %>')
3
+ element.attr('href') || element.data('<%= SmartListing.config.data_attributes(:href) %>')
4
4
 
5
5
  class SmartListing
6
6
  constructor: (e) ->
@@ -25,6 +25,8 @@ class SmartListing
25
25
  else
26
26
  editable.remove()
27
27
 
28
+ @container.trigger("smart_listing:destroy", editable)
29
+
28
30
  @changeItemCount(-1)
29
31
  @refresh()
30
32
 
@@ -45,16 +47,7 @@ class SmartListing
45
47
  false
46
48
 
47
49
  @container.on 'click', '.<%= SmartListing.config.classes(:item_actions) %> a[data-<%= SmartListing.config.data_attributes(:confirmation) %>]', (event) =>
48
- # Check if we are confirming the right element
49
- if(@confirmed != event.currentTarget)
50
- # We need confirmation
51
- $.fn.smart_listing.showConfirmation $(event.currentTarget), $(event.currentTarget).data('<%= SmartListing.config.data_attributes(:confirmation) %>'), (confirm_elem) =>
52
- @confirmed = confirm_elem[0]
53
- false
54
- else
55
- # Confirmed, reset flag and go ahead with deletion
56
- @confirmed = null
57
- true
50
+ $.fn.smart_listing.confirm $(event.currentTarget), $(event.currentTarget).data('<%= SmartListing.config.data_attributes(:confirmation) %>')
58
51
 
59
52
  @container.on 'click', '.<%= SmartListing.config.classes(:item_actions) %> a[data-<%= SmartListing.config.data_attributes(:popover) %>]', (event) =>
60
53
  name = $(event.currentTarget).data('<%= SmartListing.config.data_attributes(:popover) %>')
@@ -92,7 +85,7 @@ class SmartListing
92
85
  parseInt(@container.data('<%= SmartListing.config.data_attributes(:max_count) %>'))
93
86
 
94
87
  setAutoshow: (v) =>
95
- @container.find('.<%= SmartListing.config.classes(:new_item_placeholder) %>').data('<%= SmartListing.config.data_attributes(:autoshow) %>', v)
88
+ @container.data('<%= SmartListing.config.data_attributes(:autoshow) %>', v)
96
89
 
97
90
  changeItemCount: (value) =>
98
91
  @container.find('.<%= SmartListing.config.classes(:pagination_per_page) %> .<%= SmartListing.config.classes(:pagination_count) %>').html(@itemCount() + value)
@@ -123,7 +116,7 @@ class SmartListing
123
116
  @container.find('.<%= SmartListing.config.classes(:new_item_placeholder) %>').addClass('<%= SmartListing.config.classes(:hidden) %>')
124
117
  @container.find('.<%= SmartListing.config.classes(:new_item_action) %>').addClass('<%= SmartListing.config.classes(:hidden) %>')
125
118
  else
126
- if @container.find('.<%= SmartListing.config.classes(:new_item_placeholder) %>').data('<%= SmartListing.config.data_attributes(:autoshow) %>')
119
+ if @container.data('<%= SmartListing.config.data_attributes(:autoshow) %>')
127
120
  @container.find('.<%= SmartListing.config.classes(:new_item_placeholder) %>').removeClass('<%= SmartListing.config.classes(:hidden) %>')
128
121
  @container.find('.<%= SmartListing.config.classes(:new_item_action) %>').addClass('<%= SmartListing.config.classes(:hidden) %>')
129
122
  else
@@ -146,7 +139,7 @@ class SmartListing
146
139
 
147
140
  registerPopover: (name, callback) =>
148
141
  @popovers[name] = callback
149
-
142
+
150
143
  #################################################################################################
151
144
  # Methods executed by rails UJS:
152
145
 
@@ -178,11 +171,15 @@ class SmartListing
178
171
  new_item.html(content)
179
172
  new_item_placeholder.before(new_item)
180
173
 
174
+ @container.trigger("smart_listing:create:success", new_item)
175
+
181
176
  @changeItemCount(1)
182
177
  @refresh()
183
178
  else
184
179
  new_item_placeholder.html(content)
185
180
 
181
+ @container.trigger("smart_listing:create:fail", new_item_placeholder)
182
+
186
183
  @fadeLoaded()
187
184
 
188
185
  edit: (id, content) =>
@@ -196,6 +193,8 @@ class SmartListing
196
193
  editable.html(content)
197
194
  editable.addClass('<%= SmartListing.config.classes(:inline_editing) %>')
198
195
 
196
+ @container.trigger("smart_listing:edit", editable)
197
+
199
198
  @fadeLoaded()
200
199
 
201
200
  update: (id, success, content) =>
@@ -205,10 +204,14 @@ class SmartListing
205
204
  editable.removeData('<%= SmartListing.config.data_attributes(:inline_edit_backup) %>')
206
205
  editable.html(content)
207
206
 
207
+ @container.trigger("smart_listing:update:success", editable)
208
+
208
209
  @refresh()
209
210
  else
210
211
  editable.html(content)
211
212
 
213
+ @container.trigger("smart_listing:update:fail", editable)
214
+
212
215
  @fadeLoaded()
213
216
 
214
217
  destroy: (id, destroyed) =>
@@ -217,6 +220,8 @@ class SmartListing
217
220
  remove: (id) =>
218
221
  editable = @container.find(".<%= SmartListing.config.classes(:editable) %>[data-<%= SmartListing.config.data_attributes(:id) %>=#{id}]").first()
219
222
  editable.remove()
223
+
224
+ @container.trigger("smart_listing:remove", editable)
220
225
 
221
226
  update_list: (content, data) =>
222
227
  $.each data, (key, value) =>
@@ -294,6 +299,17 @@ $.fn.smart_listing.showConfirmation = (confirmation_elem, msg, confirm_callback)
294
299
 
295
300
  $.fn.smart_listing.showPopover confirmation_elem, buildPopover(confirmation_elem, msg)
296
301
 
302
+ $.fn.smart_listing.confirm = (elem, msg) ->
303
+ if !elem.data("confirmed")
304
+ # We need confirmation
305
+ $.fn.smart_listing.showConfirmation elem, msg, (confirm_elem) =>
306
+ confirm_elem.data("confirmed", true)
307
+ false
308
+ else
309
+ # Confirmed, reset flag and go ahead with deletion
310
+ elem.data("confirmed", false)
311
+ true
312
+
297
313
  $.fn.smart_listing.onLoading = (content, loader) ->
298
314
  content.stop(true).fadeTo(500, 0.2)
299
315
  loader.show()
@@ -335,9 +351,9 @@ $.fn.smart_listing_controls = () ->
335
351
 
336
352
  $.fn.smart_listing_controls.filter = (filter) ->
337
353
  form = filter.closest('form')
338
- button = filter.find('button')
339
- icon = filter.find('<%= SmartListing.config.selectors(:filtering_icon) %>')
340
- field = filter.find('input')
354
+ button = form.find('<%= SmartListing.config.selectors(:filtering_button) %>')
355
+ icon = form.find('<%= SmartListing.config.selectors(:filtering_icon) %>')
356
+ field = form.find('<%= SmartListing.config.selectors(:filtering_input) %>')
341
357
 
342
358
  $.fn.smart_listing.observeField(field,
343
359
  onFilled: ->
@@ -352,10 +368,11 @@ $.fn.smart_listing_controls.filter = (filter) ->
352
368
  form.submit()
353
369
  )
354
370
 
355
- icon.click ->
371
+ button.click ->
356
372
  if field.val().length > 0
357
373
  field.val('')
358
374
  field.trigger('keydown')
375
+ return false
359
376
 
360
377
  $ ->
361
378
  $('.<%= SmartListing.config.classes(:main) %>').smart_listing()
@@ -30,7 +30,7 @@ module SmartListing
30
30
 
31
31
  def paginate options = {}
32
32
  if @smart_listing.collection.respond_to? :current_page
33
- @template.paginate @smart_listing.collection, {:remote => true, :param_name => @smart_listing.param_names[:page], :params => UNSAFE_PARAMS}.merge(@smart_listing.kaminari_options)
33
+ @template.paginate @smart_listing.collection, {:remote => @smart_listing.remote?, :param_name => @smart_listing.param_name(:page), :params => UNSAFE_PARAMS}.merge(@smart_listing.kaminari_options)
34
34
  end
35
35
  end
36
36
 
@@ -38,6 +38,7 @@ module SmartListing
38
38
  @smart_listing.collection
39
39
  end
40
40
 
41
+ # Check if smart list is empty
41
42
  def empty?
42
43
  @smart_listing.count == 0
43
44
  end
@@ -59,7 +60,7 @@ module SmartListing
59
60
 
60
61
  def pagination_per_page_link page
61
62
  if @smart_listing.per_page.to_i != page
62
- url = @template.url_for(sanitize_params(@template.params.merge(@smart_listing.param_names[:per_page] => page, @smart_listing.param_names[:page] => 1)))
63
+ url = @template.url_for(sanitize_params(@template.params.merge(@smart_listing.all_params(:per_page => page, :page => 1))))
63
64
  end
64
65
 
65
66
  locals = {
@@ -71,17 +72,16 @@ module SmartListing
71
72
  end
72
73
 
73
74
  def sortable title, attribute, options = {}
74
- extra = options.delete(:extra)
75
+ dirs = [nil, "asc", "desc"]
76
+ next_index = (dirs.index(@smart_listing.sort_order(attribute)) + 1) % dirs.length
75
77
 
76
78
  sort_params = {
77
- @smart_listing.param_names[:sort_attr] => attribute,
78
- @smart_listing.param_names[:sort_order] => (@smart_listing.sort_order == "asc") ? "desc" : "asc",
79
- @smart_listing.param_names[:sort_extra] => extra
79
+ attribute => dirs[next_index]
80
80
  }
81
81
 
82
82
  locals = {
83
- :ordered => @smart_listing.sort_attr == attribute && (!@smart_listing.sort_extra || @smart_listing.sort_extra == extra.to_s),
84
- :url => @template.url_for(sanitize_params(@template.params.merge(sort_params))),
83
+ :order => @smart_listing.sort_order(attribute),
84
+ :url => @template.url_for(sanitize_params(@template.params.merge(@smart_listing.all_params(:sort => sort_params)))),
85
85
  :container_classes => [SmartListing.config.classes(:sortable)],
86
86
  :attribute => attribute,
87
87
  :title => title
@@ -125,10 +125,10 @@ module SmartListing
125
125
  locals = {
126
126
  :colspan => options.delete(:colspan),
127
127
  :no_items_classes => no_records_classes,
128
- :no_items_text => options.delete(:no_items_text),
128
+ :no_items_text => options.delete(:no_items_text) || @template.t("smart_listing.msgs.no_items"),
129
129
  :new_item_button_url => options.delete(:link),
130
130
  :new_item_button_classes => new_item_button_classes,
131
- :new_item_button_text => options.delete(:text),
131
+ :new_item_button_text => options.delete(:text) || @template.t("smart_listing.actions.new"),
132
132
  :new_item_autoshow => block_given?,
133
133
  :new_item_content => nil,
134
134
  }
@@ -149,9 +149,8 @@ module SmartListing
149
149
  end
150
150
  end
151
151
 
152
- # Check if smart list is empty
153
- def empty?
154
- @smart_listing.count == 0
152
+ def count
153
+ @smart_listing.count
155
154
  end
156
155
 
157
156
  # Check if smart list reached its item max count
@@ -173,6 +172,7 @@ module SmartListing
173
172
 
174
173
  # Outputs smart list container
175
174
  def smart_listing_for name, *args, &block
175
+ puts args.to_yaml
176
176
  raise ArgumentError, "Missing block" unless block_given?
177
177
  name = name.to_sym
178
178
  options = args.extract_options!
@@ -202,46 +202,54 @@ module SmartListing
202
202
  output
203
203
  end
204
204
 
205
+ def smart_listing_render name, *args
206
+ smart_listing_for(name, *args) do |smart_listing|
207
+ concat(smart_listing.render_list)
208
+ end
209
+ end
210
+
211
+ def smart_listing_controls_for name, *args, &block
212
+ smart_listing = @smart_listings.try(:[], name)
213
+
214
+ classes = [SmartListing.config.classes(:controls), args.first.try(:[], :class)]
215
+
216
+ form_tag(smart_listing.try(:href) || {}, :remote => smart_listing.try(:remote?) || true, :method => :get, :class => classes, :data => {:smart_listing => name}) do
217
+ concat(content_tag(:div, :style => "margin:0;padding:0;display:inline") do
218
+ concat(hidden_field_tag("#{smart_listing.try(:base_param)}[_]", 1, :id => nil)) # this forces smart_listing_update to refresh the list
219
+ end)
220
+ concat(capture(&block))
221
+ end
222
+ end
223
+
205
224
  # Render item action buttons (ie. edit, destroy and custom ones)
206
225
  def smart_listing_item_actions actions = []
207
226
  content_tag(:span) do
208
227
  actions.each do |action|
209
228
  next unless action.is_a?(Hash)
210
229
 
211
- if action.has_key?(:if)
212
- unless action[:if]
213
- concat(render(:partial => 'smart_listing/action_inactive'))
214
- next
215
- end
216
- end
230
+ locals = {
231
+ :action_if => action.has_key?(:if) ? action[:if] : true,
232
+ :url => action.delete(:url),
233
+ :icon => action.delete(:icon),
234
+ :title => action.delete(:title),
235
+ }
236
+ locals[:icon] = [locals[:icon], SmartListing.config.classes(:muted)] if !locals[:action_if]
217
237
 
218
238
  action_name = action[:name].to_sym
219
239
  case action_name
220
240
  when :show
221
- locals = {
222
- :url => action.delete(:url),
223
- :icon => action.delete(:icon),
224
- }
225
241
  concat(render(:partial => 'smart_listing/action_show', :locals => locals))
226
242
  when :edit
227
- locals = {
228
- :url => action.delete(:url),
229
- :icon => action.delete(:icon),
230
- }
231
243
  concat(render(:partial => 'smart_listing/action_edit', :locals => locals))
232
244
  when :destroy
233
- locals = {
234
- :url => action.delete(:url),
235
- :icon => action.delete(:icon),
245
+ locals.merge!(
236
246
  :confirmation => action.delete(:confirmation),
237
- }
247
+ )
238
248
  concat(render(:partial => 'smart_listing/action_delete', :locals => locals))
239
249
  when :custom
240
- locals = {
241
- :url => action.delete(:url),
242
- :icon => action.delete(:icon),
250
+ locals.merge!(
243
251
  :html_options => action,
244
- }
252
+ )
245
253
  concat(render(:partial => 'smart_listing/action_custom', :locals => locals))
246
254
  else
247
255
  concat(render(:partial => "smart_listing/action_#{action_name}", :locals => {:action => action}))
@@ -261,9 +269,15 @@ module SmartListing
261
269
  # JS helpers:
262
270
 
263
271
  # Updates the smart list
264
- def smart_listing_update name
272
+ def smart_listing_update name, options = {}
265
273
  name = name.to_sym
266
274
  smart_listing = @smart_listings[name]
275
+
276
+ # don't update list if params are missing (prevents interfering with other lists)
277
+ if params.keys.select{|k| k.include?("smart_listing")}.any? && !params[smart_listing.base_param]
278
+ return unless options[:force]
279
+ end
280
+
267
281
  builder = Builder.new(name, smart_listing, self, {}, nil)
268
282
  render(:partial => 'smart_listing/update_list', :locals => {
269
283
  :name => smart_listing.name,
@@ -0,0 +1,13 @@
1
+ <%# Link to the "First" page
2
+ - available local variables
3
+ url: url to the first page
4
+ current_page: a page object for the currently displayed page
5
+ total_pages: total number of pages
6
+ per_page: number of items to fetch per page
7
+ remote: data-remote
8
+ -%>
9
+ <% unless current_page.first? %>
10
+ <li class="first">
11
+ <%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote %>
12
+ </li>
13
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <%# Non-link tag that stands for skipped pages...
2
+ - available local variables
3
+ current_page: a page object for the currently displayed page
4
+ total_pages: total number of pages
5
+ per_page: number of items to fetch per page
6
+ remote: data-remote
7
+ -%>
8
+ <li class="page gap disabled"><a href="#" onclick="return false;"><%= raw(t 'views.pagination.truncate') %></a></li>
@@ -0,0 +1,13 @@
1
+ <%# Link to the "Last" page
2
+ - available local variables
3
+ url: url to the last page
4
+ current_page: a page object for the currently displayed page
5
+ total_pages: total number of pages
6
+ per_page: number of items to fetch per page
7
+ remote: data-remote
8
+ -%>
9
+ <% unless current_page.last? %>
10
+ <li class="last next"><%# "next" class present for border styling in twitter bootstrap %>
11
+ <%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} %>
12
+ </li>
13
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <%# Link to the "Next" page
2
+ - available local variables
3
+ url: url to the next page
4
+ current_page: a page object for the currently displayed page
5
+ total_pages: total number of pages
6
+ per_page: number of items to fetch per page
7
+ remote: data-remote
8
+ -%>
9
+ <% unless current_page.last? %>
10
+ <li class="next_page">
11
+ <%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote %>
12
+ </li>
13
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <%# Link showing page number
2
+ - available local variables
3
+ page: a page object for "this" page
4
+ url: url to this page
5
+ current_page: a page object for the currently displayed page
6
+ total_pages: total number of pages
7
+ per_page: number of items to fetch per page
8
+ remote: data-remote
9
+ -%>
10
+ <li class="page<%= ' active' if page.current? %>">
11
+ <%= link_to page, url, opts = {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
12
+ </li>
@@ -0,0 +1,25 @@
1
+ <%# The container tag
2
+ - available local variables
3
+ current_page: a page object for the currently displayed page
4
+ total_pages: total number of pages
5
+ per_page: number of items to fetch per page
6
+ remote: data-remote
7
+ paginator: the paginator that renders the pagination tags inside
8
+ -%>
9
+ <%= paginator.render do -%>
10
+ <div class="text-center">
11
+ <ul class="pagination">
12
+ <%= first_page_tag unless current_page.first? %>
13
+ <%= prev_page_tag unless current_page.first? %>
14
+ <% each_page do |page| -%>
15
+ <% if page.left_outer? || page.right_outer? || page.inside_window? -%>
16
+ <%= page_tag page %>
17
+ <% elsif !page.was_truncated? -%>
18
+ <%= gap_tag %>
19
+ <% end -%>
20
+ <% end -%>
21
+ <%= next_page_tag unless current_page.last? %>
22
+ <%= last_page_tag unless current_page.last? %>
23
+ </ul>
24
+ </div>
25
+ <% end -%>
@@ -0,0 +1,13 @@
1
+ <%# Link to the "Previous" page
2
+ - available local variables
3
+ url: url to the previous page
4
+ current_page: a page object for the currently displayed page
5
+ total_pages: total number of pages
6
+ per_page: number of items to fetch per page
7
+ remote: data-remote
8
+ -%>
9
+ <% unless current_page.first? %>
10
+ <li class="prev">
11
+ <%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
12
+ </li>
13
+ <% end %>
@@ -7,4 +7,4 @@
7
7
  html_options: custom html options
8
8
  -%>
9
9
 
10
- <%= link_to(url, html_options) do %><%= content_tag(:i, '', :class => icon) %><% end %>
10
+ <%= link_to_if(action_if, content_tag(:span, '', :class => icon, :title => title), url, html_options) %>
@@ -5,6 +5,7 @@
5
5
  url: destroy url
6
6
  icon
7
7
  confirmation: confrimation text
8
+ title
8
9
  -%>
9
10
 
10
- <%= link_to(url, :remote => true, :class => "destroy", :method => :delete, :title => t("smart_listing.actions.destroy"), :data => {:confirmation => confirmation || t("smart_listing.msgs.destroy_confirmation")} ) do %><%= content_tag(:i, "", :class => icon || SmartListing.config.classes(:icon_trash)) %><% end %>
11
+ <%= link_to_if(action_if, content_tag(:i, "", :class => icon || SmartListing.config.classes(:icon_trash)), url, :remote => true, :class => "destroy", :method => :delete, :title => title || t("smart_listing.actions.destroy"), :data => {:confirmation => confirmation || t("smart_listing.msgs.destroy_confirmation")} ) %>
@@ -4,6 +4,7 @@
4
4
  Available local variables:
5
5
  url
6
6
  icon
7
+ title
7
8
  -%>
8
9
 
9
- <%= link_to(url, :remote => true, :class => "edit", :title => t("smart_listing.actions.edit") ) do %><%= content_tag(:i, '', :class => icon || SmartListing.config.classes(:icon_edit)) %><% end %>
10
+ <%= link_to_if(action_if, content_tag(:i, '', :class => icon || SmartListing.config.classes(:icon_edit)), url, :remote => true, :class => "edit", :title => title || t("smart_listing.actions.edit") ) %>
@@ -4,6 +4,7 @@
4
4
  Available local variables:
5
5
  url
6
6
  icon
7
+ title
7
8
  -%>
8
9
 
9
- <%= link_to(url, :class => "show", :title => t("smart_listing.actions.show") ) do %><%= content_tag(:i, '', :class => icon || SmartListing.config.classes(:icon_show)) %><% end %>
10
+ <%= link_to_if(action_if, content_tag(:i, '', :class => icon || SmartListing.config.classes(:icon_show)), url, :class => "show", :title => title || t("smart_listing.actions.show") ) %>
@@ -9,4 +9,4 @@
9
9
  -%>
10
10
 
11
11
  <% name = page == 0 ? t('views.pagination.unlimited') : page %>
12
- <%= url ? link_to(name, url, :remote => true) : content_tag(:span, name) %>
12
+ <%= url ? link_to(name, url, :remote => smart_listing.remote?) : content_tag(:span, name) %>
@@ -6,15 +6,15 @@
6
6
  url: sortable link url
7
7
  attribute: current attribute name
8
8
  title: current attribute title
9
- ordered: defines whether column is sorted or not
9
+ order: defines column sort order
10
10
  smart_listing: current SmartListing instance
11
11
  builder: current builder instance
12
12
  -%>
13
13
 
14
14
  <%= link_to url, :class => container_classes, :data => {:attr => attribute}, :remote => true do %>
15
15
  <%= title %>
16
- <% if ordered %>
17
- <span class="<%= smart_listing.sort_order == "asc" ? SmartListing.config.classes(:icon_sort_up) : SmartListing.config.classes(:icon_sort_down) %>"></span>
16
+ <% if order %>
17
+ <span class="<%= order == "asc" ? SmartListing.config.classes(:icon_sort_up) : SmartListing.config.classes(:icon_sort_down) %>"></span>
18
18
  <% else %>
19
19
  <span class="<%= SmartListing.config.classes(:icon_sort_none) %>"></span>
20
20
  <% end %>
@@ -1,2 +1,3 @@
1
1
  var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.setAutoshow(false);
2
3
  smart_listing.create(<%= id || 0 %>, <%= object.persisted? %>, "<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
@@ -1,6 +1,6 @@
1
1
  var smart_listing = $('#<%= name %>').smart_listing();
2
- smart_listing.create(<%= id || 0 %>, <%= object.persisted? %>, "<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
3
2
  smart_listing.setAutoshow(true);
3
+ smart_listing.create(<%= id || 0 %>, <%= object.persisted? %>, "<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
4
4
  <% if object.persisted? %>
5
5
  smart_listing.new_item("<%= escape_javascript(render(:partial => new.last, :locals => {object_key => new.first})) %>");
6
6
  <% end %>
@@ -2,10 +2,12 @@ en:
2
2
  smart_listing:
3
3
  msgs:
4
4
  destroy_confirmation: Destroy?
5
+ no_items: No items
5
6
  actions:
6
7
  destroy: Destroy
7
8
  edit: Edit
8
9
  show: Show
10
+ new: New item
9
11
  views:
10
12
  pagination:
11
13
  per_page: Per page
@@ -1,4 +1,19 @@
1
1
  SmartListing.configure do |config|
2
+ config.global_options({
3
+ #:param_names => { # param names
4
+ #:page => :page,
5
+ #:per_page => :per_page,
6
+ #:sort => :sort,
7
+ #},
8
+ #:array => false, # controls whether smart list should be using arrays or AR collections
9
+ #:max_count => nil, # limit number of rows
10
+ #:unlimited_per_page => false, # allow infinite page size
11
+ #:paginate => true, # allow pagination
12
+ #:memorize_per_page => false, # save per page settings in the cookie
13
+ #:page_sizes => DEFAULT_PAGE_SIZES, # set available page sizes array
14
+ #:kaminari_options => {:theme => "smart_listing"}, # Kaminari's paginate helper options
15
+ })
16
+
2
17
  config.constants :classes, {
3
18
  #:main => "smart-listing",
4
19
  #:editable => "editable",
@@ -12,7 +27,7 @@ SmartListing.configure do |config|
12
27
  #:hidden => "hidden",
13
28
  #:autoselect => "autoselect",
14
29
  #:callback => "callback",
15
- #:pagination_per_page => "pagination-per-page",
30
+ #:pagination_per_page => "pagination-per-page text-center",
16
31
  #:pagination_count => "count",
17
32
  #:inline_editing => "info",
18
33
  #:no_records => "no-records",
data/lib/smart_listing.rb CHANGED
@@ -2,6 +2,23 @@ require 'smart_listing/config'
2
2
  require "smart_listing/engine"
3
3
  require "kaminari"
4
4
 
5
+ # Fix parsing nester params
6
+ module Kaminari
7
+ module Helpers
8
+ class Tag
9
+ def page_url_for(page)
10
+ @template.url_for @params.deep_merge(page_param(page)).merge(:only_path => true)
11
+ end
12
+
13
+ private
14
+
15
+ def page_param(page)
16
+ Rack::Utils.parse_nested_query("#{@param_name}=#{page <= 1 ? nil : page}").symbolize_keys
17
+ end
18
+ end
19
+ end
20
+ end
21
+
5
22
  module SmartListing
6
23
  class Base
7
24
  if Rails.env.development?
@@ -10,32 +27,19 @@ module SmartListing
10
27
  DEFAULT_PAGE_SIZES = [10, 20, 50, 100]
11
28
  end
12
29
 
13
- attr_reader :name, :collection, :options, :per_page, :page, :sort_attr, :sort_order, :sort_extra, :partial, :count
30
+ attr_reader :name, :collection, :options, :per_page, :sort, :page, :partial, :count
14
31
 
15
32
  def initialize name, collection, options = {}
16
33
  @name = name
17
34
 
18
35
  @options = {
19
- :param_names => { # param names
20
- :page => "#{@name}_page".to_sym,
21
- :per_page => "#{@name}_per_page".to_sym,
22
- :sort_attr => "#{@name}_sort_attr".to_sym,
23
- :sort_order => "#{@name}_sort_order".to_sym,
24
- :sort_extra => "#{@name}_sort_extra".to_sym,
25
- },
26
- :partial => @name, # smart list partial name
27
- :array => false, # controls whether smart list should be using arrays or AR collections
28
- :max_count => nil, # limit number of rows
29
- :unlimited_per_page => false, # allow infinite page size
30
- :sort => true, # allow sorting
31
- :paginate => true, # allow pagination
32
- :href => nil, # set smart list target url (in case when different than current url)
33
- :callback_href => nil, # set smart list callback url (in case when different than current url)
34
- :default_sort_attr => nil, # default sort by
35
- :memorize_per_page => false,
36
- :page_sizes => DEFAULT_PAGE_SIZES, # set available page sizes array
37
- :kaminari_options => {}, # Kaminari's paginate helper options
38
- }.merge!(options)
36
+ :partial => @name, # SmartListing partial name
37
+ :sort_attributes => :implicit, # allow implicitly setting sort attributes
38
+ :default_sort => {}, # default sorting
39
+ :href => nil, # set SmartListing target url (in case when different than current url)
40
+ :remote => true, # SmartListing is remote by default
41
+ :callback_href => nil, # set SmartListing callback url (in case when different than current url)
42
+ }.merge(SmartListing.config.global_options).merge(options)
39
43
 
40
44
  if @options[:array]
41
45
  @collection = collection.to_a
@@ -45,14 +49,16 @@ module SmartListing
45
49
  end
46
50
 
47
51
  def setup params, cookies
48
- @page = params[param_names[:page]]
49
- @per_page = !params[param_names[:per_page]] || params[param_names[:per_page]].empty? ? (@options[:memorize_per_page] && cookies[param_names[:per_page]].to_i > 0 ? cookies[param_names[:per_page]].to_i : page_sizes.first) : params[param_names[:per_page]].to_i
50
- @per_page = DEFAULT_PAGE_SIZES.first unless DEFAULT_PAGE_SIZES.include?(@per_page)
51
- @sort_attr = params[param_names[:sort_attr]] || @options[:default_sort_attr]
52
- @sort_order = ["asc", "desc"].include?(params[param_names[:sort_order]]) ? params[param_names[:sort_order]] : "desc"
53
- @sort_extra = params[param_names[:sort_extra]]
52
+ @params = params
53
+
54
+ @page = get_param :page
55
+ @per_page = !get_param(:per_page) || get_param(:per_page).empty? ? (@options[:memorize_per_page] && get_param(:per_page, cookies).to_i > 0 ? get_param(:per_page, cookies).to_i : page_sizes.first) : get_param(:per_page).to_i
56
+ @per_page = page_sizes.first unless page_sizes.include?(@per_page)
54
57
 
55
- cookies[param_names[:per_page]] = @per_page if @options[:memorize_per_page]
58
+ @sort = parse_sort(get_param(:sort)) || @options[:default_sort]
59
+ sort_keys = (@options[:sort_attributes] == :implicit ? @sort.keys.collect{|s| [s, s]} : @options[:sort_attributes])
60
+
61
+ set_param(:per_page, @per_page, cookies) if @options[:memorize_per_page]
56
62
 
57
63
  @count = @collection.size
58
64
  @count = @count.length if @count.is_a?(Hash)
@@ -64,26 +70,29 @@ module SmartListing
64
70
  end
65
71
 
66
72
  if @options[:array]
67
- @collection = @collection.sort do |x, y|
68
- xval = x
69
- yval = y
70
- @sort_attr.split(".").each do |m|
71
- xval = xval.try(m)
72
- yval = yval.try(m)
73
- end
74
- xval = xval.upcase if xval.is_a?(String)
75
- yval = yval.upcase if yval.is_a?(String)
76
-
77
- if xval.nil? || yval.nil?
78
- xval.nil? ? 1 : -1
79
- else
80
- if @sort_order == "asc"
81
- (xval <=> yval) || (xval && !yval ? 1 : -1)
82
- else
83
- (yval <=> xval) || (yval && !xval ? 1 : -1)
73
+ if @sort && @sort.any? # when array we sort only by first attribute
74
+ i = sort_keys.index{|x| x[0] == @sort.first[0]}
75
+ @collection = @collection.sort do |x, y|
76
+ xval = x
77
+ yval = y
78
+ sort_keys[i][1].split(".").each do |m|
79
+ xval = xval.try(m)
80
+ yval = yval.try(m)
84
81
  end
85
- end
86
- end if @options[:sort] && @sort_attr && !@sort_attr.empty?
82
+ xval = xval.upcase if xval.is_a?(String)
83
+ yval = yval.upcase if yval.is_a?(String)
84
+
85
+ if xval.nil? || yval.nil?
86
+ xval.nil? ? 1 : -1
87
+ else
88
+ if @sort.first[1] == "asc"
89
+ (xval <=> yval) || (xval && !yval ? 1 : -1)
90
+ else
91
+ (yval <=> xval) || (yval && !xval ? 1 : -1)
92
+ end
93
+ end
94
+ end
95
+ end
87
96
  if @options[:paginate] && @per_page > 0
88
97
  @collection = ::Kaminari.paginate_array(@collection).page(@page).per(@per_page)
89
98
  if @collection.length == 0
@@ -91,7 +100,9 @@ module SmartListing
91
100
  end
92
101
  end
93
102
  else
94
- @collection = @collection.order("#{@sort_attr} #{@sort_order}") if @options[:sort] && @sort_attr && !@sort_attr.empty? && @collection.column_names.include?(@sort_attr) && @sort_order
103
+ # let's sort by all attributes
104
+ @collection = @collection.order(sort_keys.collect{|s| "#{s[1]} #{@sort[s[0]]}" if @sort[s[0]]}.compact) if @sort && @sort.any?
105
+
95
106
  if @options[:paginate] && @per_page > 0
96
107
  @collection = @collection.page(@page).per(@per_page)
97
108
  end
@@ -106,6 +117,10 @@ module SmartListing
106
117
  @options[:param_names]
107
118
  end
108
119
 
120
+ def param_name key
121
+ "#{base_param}[#{param_names[key]}]"
122
+ end
123
+
109
124
  def unlimited_per_page?
110
125
  !!@options[:unlimited_per_page]
111
126
  end
@@ -122,6 +137,10 @@ module SmartListing
122
137
  @options[:callback_href]
123
138
  end
124
139
 
140
+ def remote?
141
+ @options[:remote]
142
+ end
143
+
125
144
  def page_sizes
126
145
  @options[:page_sizes]
127
146
  end
@@ -130,12 +149,65 @@ module SmartListing
130
149
  @options[:kaminari_options]
131
150
  end
132
151
 
133
- def all_params
134
- ap = {}
152
+ def all_params overrides = {}
153
+ ap = {base_param => {}}
135
154
  @options[:param_names].each do |k, v|
136
- ap[v] = self.send(k)
155
+ if overrides[k]
156
+ ap[base_param][v] = overrides[k]
157
+ else
158
+ ap[base_param][v] = self.send(k)
159
+ end
137
160
  end
138
161
  ap
139
162
  end
163
+
164
+ def sort_order attribute
165
+ @sort && @sort[attribute].present? ? @sort[attribute] : nil
166
+ end
167
+
168
+ def base_param
169
+ "#{name}_smart_listing"
170
+ end
171
+
172
+ private
173
+
174
+ def get_param key, store = @params
175
+ if store.is_a?(ActionDispatch::Cookies::CookieJar)
176
+ store["#{base_param}_#{param_names[key]}"]
177
+ else
178
+ store[base_param].try(:[], param_names[key])
179
+ end
180
+ end
181
+
182
+ def set_param key, value, store = @params
183
+ if store.is_a?(ActionDispatch::Cookies::CookieJar)
184
+ store["#{base_param}_#{param_names[key]}"] = value
185
+ else
186
+ store[base_param] ||= {}
187
+ store[base_param][param_names[key]] = value
188
+ end
189
+ end
190
+
191
+ def parse_sort sort_params
192
+ sort = nil
193
+
194
+ if @options[:sort_attributes] == :implicit
195
+ sort = sort_params.dup if sort_params.present?
196
+ elsif @options[:sort_attributes]
197
+ @options[:sort_attributes].each do |a|
198
+ k, v = a
199
+ if sort_params && sort_params[k.to_s]
200
+ dir = ["asc", "desc", ""].delete(sort_params[k.to_s])
201
+
202
+ if dir
203
+ sort ||= {}
204
+ sort[k] = dir
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ sort
211
+ end
140
212
  end
141
213
  end
@@ -8,7 +8,27 @@ module SmartListing
8
8
  end
9
9
 
10
10
  class Configuration
11
+ if Rails.env.development?
12
+ DEFAULT_PAGE_SIZES = [3, 10, 20, 50, 100]
13
+ else
14
+ DEFAULT_PAGE_SIZES = [10, 20, 50, 100]
15
+ end
16
+
11
17
  DEFAULTS = {
18
+ :global_options => {
19
+ :param_names => { # param names
20
+ :page => :page,
21
+ :per_page => :per_page,
22
+ :sort => :sort,
23
+ },
24
+ :array => false, # controls whether smart list should be using arrays or AR collections
25
+ :max_count => nil, # limit number of rows
26
+ :unlimited_per_page => false, # allow infinite page size
27
+ :paginate => true, # allow pagination
28
+ :memorize_per_page => false,
29
+ :page_sizes => DEFAULT_PAGE_SIZES, # set available page sizes array
30
+ :kaminari_options => {:theme => "smart_listing"}, # Kaminari's paginate helper options
31
+ },
12
32
  :constants => {
13
33
  :classes => {
14
34
  :main => "smart-listing",
@@ -23,7 +43,7 @@ module SmartListing
23
43
  :hidden => "hidden",
24
44
  :autoselect => "autoselect",
25
45
  :callback => "callback",
26
- :pagination_per_page => "pagination-per-page",
46
+ :pagination_per_page => "pagination-per-page text-center",
27
47
  :pagination_count => "count",
28
48
  :inline_editing => "info",
29
49
  :no_records => "no-records",
@@ -39,11 +59,12 @@ module SmartListing
39
59
  :icon_new => "glyphicon glyphicon-plus",
40
60
  :icon_edit => "glyphicon glyphicon-pencil",
41
61
  :icon_trash => "glyphicon glyphicon-trash",
42
- :icon_inactive => "glyphicon glyphicon-circle",
62
+ :icon_inactive => "glyphicon glyphicon-remove-circle text-muted",
43
63
  :icon_show => "glyphicon glyphicon-share-alt",
44
64
  :icon_sort_none => "glyphicon glyphicon-resize-vertical",
45
65
  :icon_sort_up => "glyphicon glyphicon-chevron-up",
46
66
  :icon_sort_down => "glyphicon glyphicon-chevron-down",
67
+ :muted => "text-muted",
47
68
  },
48
69
  :data_attributes => {
49
70
  :main => "smart-listing",
@@ -64,7 +85,9 @@ module SmartListing
64
85
  :edit_cancel => "button.cancel",
65
86
  :row => "tr",
66
87
  :head => "thead",
67
- :filtering_icon => "i"
88
+ :filtering_button => "button",
89
+ :filtering_icon => "button span",
90
+ :filtering_input => ".filter input"
68
91
  }
69
92
  }
70
93
  }
@@ -78,11 +101,10 @@ module SmartListing
78
101
  end
79
102
 
80
103
  def constants key, value = nil
81
- if value == nil
82
- @options[:constants][key]
83
- else
104
+ if value
84
105
  @options[:constants][key].merge!(value)
85
106
  end
107
+ @options[:constants][key]
86
108
  end
87
109
 
88
110
  def classes key
@@ -96,5 +118,12 @@ module SmartListing
96
118
  def selectors key
97
119
  @options[:constants][:selectors][key]
98
120
  end
121
+
122
+ def global_options value = nil
123
+ if value
124
+ @options[:global_options].merge!(value)
125
+ end
126
+ @options[:global_options]
127
+ end
99
128
  end
100
129
  end
@@ -1,3 +1,3 @@
1
1
  module SmartListing
2
- VERSION = "0.9.8"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_listing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.8
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sology
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-03 00:00:00.000000000 Z
11
+ date: 2014-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.15.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.15.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: sqlite3
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -76,15 +76,19 @@ files:
76
76
  - LICENSE
77
77
  - README.md
78
78
  - Rakefile
79
- - app/assets/javascripts/smart_listing/application.js
80
- - app/assets/javascripts/smart_listing/smart_listing.coffee.erb
81
- - app/assets/stylesheets/smart_listing/application.css
79
+ - app/assets/javascripts/smart_listing.coffee.erb
82
80
  - app/helpers/smart_listing/application_helper.rb
83
81
  - app/helpers/smart_listing/helper.rb
82
+ - app/views/kaminari/smart_listing/_first_page.html.erb
83
+ - app/views/kaminari/smart_listing/_gap.html.erb
84
+ - app/views/kaminari/smart_listing/_last_page.html.erb
85
+ - app/views/kaminari/smart_listing/_next_page.html.erb
86
+ - app/views/kaminari/smart_listing/_page.html.erb
87
+ - app/views/kaminari/smart_listing/_paginator.html.erb
88
+ - app/views/kaminari/smart_listing/_prev_page.html.erb
84
89
  - app/views/smart_listing/_action_custom.html.erb
85
90
  - app/views/smart_listing/_action_delete.html.erb
86
91
  - app/views/smart_listing/_action_edit.html.erb
87
- - app/views/smart_listing/_action_inactive.html.erb
88
92
  - app/views/smart_listing/_action_show.html.erb
89
93
  - app/views/smart_listing/_item_new.html.erb
90
94
  - app/views/smart_listing/_pagination_per_page_link.html.erb
@@ -1,14 +0,0 @@
1
- // This is a manifest file that'll be compiled into application.js, which will include all the files
2
- // listed below.
3
- //
4
- // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
- // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
- //
7
- // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
- // compiled file.
9
- //
10
- // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
- // about supported directives.
12
- //
13
- //= require_tree .
14
- //= require smart_listing/smart_listing
@@ -1,13 +0,0 @@
1
- /*
2
- * This is a manifest file that'll be compiled into application.css, which will include all the files
3
- * listed below.
4
- *
5
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
- * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
- *
8
- * You're free to add application-wide styles to this file and they'll appear at the top of the
9
- * compiled file, but it's generally better to create a new file per style scope.
10
- *
11
- *= require_self
12
- *= require_tree .
13
- */
@@ -1,5 +0,0 @@
1
- <%#
2
- Inactive action.
3
- -%>
4
-
5
- <%= content_tag(:i, '', :class => SmartListing.config.classes(:icon_inactive)) %>