smart_table 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +49 -0
- data/app/assets/javascripts/smart_table.js +115 -13
- data/app/controllers/concerns/smart_table/smart_table_concern.rb +3 -2
- data/app/helpers/smart_table/smart_table_helper.rb +47 -5
- data/app/views/kaminari/smart_table/_first_page.html.erb +1 -1
- data/app/views/kaminari/smart_table/_last_page.html.erb +1 -1
- data/app/views/kaminari/smart_table/_next_page.html.erb +1 -1
- data/app/views/kaminari/smart_table/_page.html.erb +1 -1
- data/app/views/kaminari/smart_table/_paginator.html.erb +3 -3
- data/app/views/kaminari/smart_table/_prev_page.html.erb +1 -1
- data/lib/smart_table/version.rb +1 -1
- data/smart_table-0.0.8.gem +0 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4e47371d7d1983b8b3576b2a68bfcf2cbb49fa205cd53a279fa7c8c9f32ec49
|
4
|
+
data.tar.gz: e8c894597e4f0f542312b1c16a3307421b00c287316bd98bfa57b485cc886b90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8b691fca8052f533664b7a448066a1d132263fc63287ee36b659195c8ab1fb63370e380f6f0128c614acf6dfe5ffb567e14803f91263838f50a366d49181b4d
|
7
|
+
data.tar.gz: b3ed85987781f88f6108603cbf5194beb517e9b3028e604bdc0f24754dc4df75cc7272f3a4589baeb66dcc4806ab0aac0866d649d8e44923ca403ed75394ea2f
|
data/README.md
CHANGED
@@ -142,3 +142,52 @@ The following snippet shows how to use different input types to make custom filt
|
|
142
142
|
initial_sort_order: :desc
|
143
143
|
)
|
144
144
|
```
|
145
|
+
|
146
|
+
### Ajax Updates
|
147
|
+
|
148
|
+
In its normal mode, smart_table works by refreshing the page with different url query parameters. The main advantage of this method, is that the url completely determines the state of the table in the page, and you can easily share the url with someone else and they will have the view of the same page with the same sorting and so on (you can't guarantee the table content will be the same though, as it depends on your data source).
|
149
|
+
|
150
|
+
On the other hand, this has the side-effect of refreshing the rest of the page, wiping out all the eventual state you have in your DOM, what might be a problem depending on how your app is structured. The solution to this problem is to refresh only the part of your page that must be refreshed when the user interacts with the smart_table.
|
151
|
+
|
152
|
+
To enable all the links related to the smart_table to generate AJAX requests, set the following option in your controller:
|
153
|
+
```ruby
|
154
|
+
smart_table_params = smart_table_params(
|
155
|
+
remote: true,
|
156
|
+
...
|
157
|
+
)
|
158
|
+
```
|
159
|
+
|
160
|
+
Then in your view, use the following helper to enclose everything that must be update when the user changes a page, changes page size or does some search:
|
161
|
+
```html
|
162
|
+
<h1>Users</h1>
|
163
|
+
|
164
|
+
<div><%= smart_table_search %></div>
|
165
|
+
|
166
|
+
<%= smart_table_remote_updatable_content do %>
|
167
|
+
<table class='table'>
|
168
|
+
...
|
169
|
+
</table>
|
170
|
+
|
171
|
+
<%= smart_table_paginate @current_page_users, @total_users_count, User.model_name.human %>
|
172
|
+
<%= smart_table_page_size_selector @total_user_count, User.model_name.human %>
|
173
|
+
<% end %>
|
174
|
+
```
|
175
|
+
|
176
|
+
Usually, all you need to enclose in this scope is the table and the pagination controls.
|
177
|
+
|
178
|
+
If you want, you can prevent the controller of rendering the view inside the layout when the request is xhr, this will spare your server some work, as the only part of the page that is actually necessary for it to render is the one enclosed by the `smart_table_remote_updatable_content` helper.
|
179
|
+
|
180
|
+
smart_table will automatically identify the content to be updated and replace that part of the page by the new content. Sometimes you need to execute some javascript after replacing this content (`<script>` tags inside the replaced content will not run automatically!). In this case, use the `smart_table:ajax_update` event that is triggered on the document, as showed below:
|
181
|
+
```javascript
|
182
|
+
$(document).on('smart_table:ajax_update', function(event) {
|
183
|
+
var replacedElementSelector = event.detail.replacedElementSelector;
|
184
|
+
// do whatever you need to do
|
185
|
+
});
|
186
|
+
```
|
187
|
+
|
188
|
+
Usually you have to setup event listeners on your table content, both after initial rendering and after an ajax update. In this case, just do your setup both on document ready and after the ajax update event:
|
189
|
+
```javascript
|
190
|
+
$(document).on('ready smart_table:ajax_update', function(event) {
|
191
|
+
// do whatever here
|
192
|
+
});
|
193
|
+
```
|
@@ -7,9 +7,12 @@ var SmartTable = function() {
|
|
7
7
|
SmartTable.onPageLoad = function(callback){
|
8
8
|
// modern browsers
|
9
9
|
if (document.addEventListener) {
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
if (typeof Turbolinks !== 'undefined') {
|
11
|
+
document.addEventListener("turbolinks:load", callback); // Turbolinks 5
|
12
|
+
document.addEventListener("page:load", callback); // Turbolinks classic
|
13
|
+
} else {
|
14
|
+
document.addEventListener('DOMContentLoaded', callback);
|
15
|
+
}
|
13
16
|
}
|
14
17
|
// IE <= 8
|
15
18
|
else {
|
@@ -19,10 +22,29 @@ SmartTable.onPageLoad = function(callback){
|
|
19
22
|
}
|
20
23
|
};
|
21
24
|
|
22
|
-
//
|
23
|
-
|
24
|
-
|
25
|
-
|
25
|
+
// make the initial setup of smart table links, filters, search, scoped under the
|
26
|
+
// selector parameter. If no selector parameter is passed, make the setup on the
|
27
|
+
// whole document
|
28
|
+
SmartTable.setupSmartTableInScope = function(selector) {
|
29
|
+
var scopeElement;
|
30
|
+
if (typeof selector == 'undefined') {
|
31
|
+
scopeElement = document;
|
32
|
+
} else {
|
33
|
+
scopeElement = document.querySelector(selector);
|
34
|
+
}
|
35
|
+
if (scopeElement == null) {
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
|
39
|
+
// call individual setup methods
|
40
|
+
SmartTable.setupSmartTableSearch(scopeElement);
|
41
|
+
SmartTable.setupSmartTableExtraFilters(scopeElement);
|
42
|
+
SmartTable.setupRemoteTableUpdate(scopeElement);
|
43
|
+
}
|
44
|
+
|
45
|
+
// On page load, we setup all JS elements on the whole document
|
46
|
+
SmartTable.onPageLoad(function(event) {
|
47
|
+
SmartTable.setupSmartTableInScope();
|
26
48
|
})
|
27
49
|
|
28
50
|
// Gets the current page url and merges some query parameters to this url. If a
|
@@ -84,14 +106,75 @@ SmartTable.refreshPageWithParam = function(key, value) {
|
|
84
106
|
params[key] = null;
|
85
107
|
}
|
86
108
|
|
87
|
-
//
|
88
|
-
|
109
|
+
// if there is section to be updated dynamically, does AJAX request, otherwise
|
110
|
+
// just makes the browser load the new page
|
111
|
+
var url = SmartTable.currentUrlWithMergedQueryParams(params);
|
112
|
+
if (!!document.querySelector('.smart_table_remote_updatable_content')) {
|
113
|
+
SmartTable.ajaxUpdate(url, '.smart_table_remote_updatable_content');
|
114
|
+
} else {
|
115
|
+
window.location = url;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
// Updates table via ajax.
|
120
|
+
// 1) Does XHR HTTP GET to get new content
|
121
|
+
// 2) Uses replaceableElementSelector to select the element to be replaced in the current DOM,
|
122
|
+
// by the element with the same selector in the received content
|
123
|
+
// 3) Replaces current browser url (necessary for smart_table to work properly)
|
124
|
+
// 4) Fires the "smart_table:ajax_update" event on the document, with the newly
|
125
|
+
// added element as target
|
126
|
+
SmartTable.ajaxUpdate = function(url, replaceableElementSelector) {
|
127
|
+
// makes AJAX get request
|
128
|
+
var xhr = new XMLHttpRequest();
|
129
|
+
xhr.open('GET', url);
|
130
|
+
xhr.onload = function() {
|
131
|
+
if (xhr.status === 200) {
|
132
|
+
// parses response
|
133
|
+
var domParser = new DOMParser();
|
134
|
+
var receivedDocument = domParser.parseFromString(xhr.responseText, "text/html");
|
135
|
+
var replacingElement = receivedDocument.querySelector(replaceableElementSelector);
|
136
|
+
if (replacingElement == null) {
|
137
|
+
console.log("smart_table: element with selector '" + replaceableElementSelector + "' not found in xhr response");
|
138
|
+
return;
|
139
|
+
}
|
140
|
+
|
141
|
+
// finds element to be replaced
|
142
|
+
var replacedElement = document.querySelector(replaceableElementSelector);
|
143
|
+
if (replacedElement == null) {
|
144
|
+
console.log("smart_table: element with selector '" + replaceableElementSelector + "' not found in current document");
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
|
148
|
+
// replaces element
|
149
|
+
replacedElement.parentNode.replaceChild(replacingElement, replacedElement);
|
150
|
+
|
151
|
+
// re-do setup of smart_table, as it is probably inside the replaced element
|
152
|
+
SmartTable.setupSmartTableInScope(replaceableElementSelector);
|
153
|
+
|
154
|
+
// updates url (requires HTML5)
|
155
|
+
history.replaceState({}, "", url)
|
156
|
+
|
157
|
+
// fires "smart_table:ajax_update" event on document, in case there are
|
158
|
+
// custom user actions to be done
|
159
|
+
var ajaxUpdateEvent = new CustomEvent("smart_table:ajax_update", {
|
160
|
+
detail: {
|
161
|
+
replacedElementSelector: replaceableElementSelector
|
162
|
+
}
|
163
|
+
})
|
164
|
+
document.dispatchEvent(ajaxUpdateEvent);
|
165
|
+
}
|
166
|
+
else {
|
167
|
+
console.log("smart_table: xhr update failed. Response status: " + xhr.status);
|
168
|
+
}
|
169
|
+
};
|
170
|
+
xhr.send();
|
89
171
|
}
|
90
172
|
|
91
173
|
// Prepares table search field, so the table is refreshed when the field changes
|
92
|
-
|
174
|
+
// scopeElement: scope under which all search fields will be setup. May be the document object
|
175
|
+
SmartTable.setupSmartTableSearch = function(scopeElement) {
|
93
176
|
// gets search text field
|
94
|
-
var smartTableSearch =
|
177
|
+
var smartTableSearch = scopeElement.getElementsByClassName('smart_table_search')[0];
|
95
178
|
if (!smartTableSearch) return;
|
96
179
|
|
97
180
|
// refreshes page every time search field changes
|
@@ -104,8 +187,9 @@ SmartTable.setupSmartTableSearch = function() {
|
|
104
187
|
|
105
188
|
// Prepares table extra filters section, so the table is refreshed when the
|
106
189
|
// any of the input fields are changed
|
107
|
-
|
108
|
-
|
190
|
+
// scopeElement: scope under which all search fields will be setup. May be the document object
|
191
|
+
SmartTable.setupSmartTableExtraFilters = function(scopeElement) {
|
192
|
+
var smartTableExtraFilters = scopeElement.getElementsByClassName('smart_table_extra_filters')[0];
|
109
193
|
if (!smartTableExtraFilters) return;
|
110
194
|
|
111
195
|
// all input fields
|
@@ -135,3 +219,21 @@ SmartTable.setupSmartTableExtraFilters = function() {
|
|
135
219
|
}
|
136
220
|
}
|
137
221
|
}
|
222
|
+
|
223
|
+
// Prepares all links with data-smart-table-remote-link to trigger ajax requests
|
224
|
+
// and replace part of the document only.
|
225
|
+
// scopeElement: scope under which all search fields will be setup. May be the document object
|
226
|
+
SmartTable.setupRemoteTableUpdate = function(scopeElement) {
|
227
|
+
var remoteLinkNodes = scopeElement.querySelectorAll('a.smart-table-link[data-smart-table-remote-link]');
|
228
|
+
if (remoteLinkNodes.length == 0) return;
|
229
|
+
|
230
|
+
// refreshes page every time any field changes
|
231
|
+
for (var i=0; i<remoteLinkNodes.length; i++) {
|
232
|
+
var linkNode = remoteLinkNodes[i];
|
233
|
+
linkNode.addEventListener('click', function(event) {
|
234
|
+
event.preventDefault();
|
235
|
+
SmartTable.ajaxUpdate(event.target.href, '.smart_table_remote_updatable_content');
|
236
|
+
return false;
|
237
|
+
});
|
238
|
+
}
|
239
|
+
}
|
@@ -8,7 +8,7 @@ module SmartTable
|
|
8
8
|
end
|
9
9
|
|
10
10
|
class Params
|
11
|
-
attr_accessor :sort, :page_size, :page_number, :search
|
11
|
+
attr_accessor :sort, :page_size, :page_number, :search, :remote
|
12
12
|
|
13
13
|
def initialize
|
14
14
|
self.sort = nil
|
@@ -26,10 +26,11 @@ module SmartTable
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
def smart_table_params(initial_page_size: 25, initial_sort_attribute: nil, initial_sort_order: :asc)
|
29
|
+
def smart_table_params(initial_page_size: 25, initial_sort_attribute: nil, initial_sort_order: :asc, remote: false)
|
30
30
|
return @st_params if @st_params
|
31
31
|
|
32
32
|
@st_params = Params.new
|
33
|
+
@st_params.remote = remote
|
33
34
|
|
34
35
|
@st_params.sort = params[SORT_PARAM]
|
35
36
|
if @st_params.sort.nil? && initial_sort_attribute
|
@@ -30,7 +30,11 @@ module SmartTable
|
|
30
30
|
html_elements = []
|
31
31
|
|
32
32
|
# call to Kaminari view helper
|
33
|
-
html_elements << paginate(paginatable_array,
|
33
|
+
html_elements << paginate(paginatable_array,
|
34
|
+
param_name: PAGE_PARAM,
|
35
|
+
theme: 'smart_table',
|
36
|
+
remote: get_cached_smart_table_params.remote
|
37
|
+
)
|
34
38
|
|
35
39
|
html_elements << content_tag(:div, class: 'text-center') do
|
36
40
|
# call to Kaminari view helper
|
@@ -71,7 +75,7 @@ module SmartTable
|
|
71
75
|
end
|
72
76
|
|
73
77
|
link_url = current_request_url_with_merged_query_params(SORT_PARAM => "#{attribute} #{next_sort_order}")
|
74
|
-
link_to link_url do
|
78
|
+
link_to link_url, class: 'smart-table-link', data: {smart_table_remote_link: (true if get_cached_smart_table_params.remote)} do
|
75
79
|
text.html_safe + ' ' + (
|
76
80
|
if current_sort_attribute == attribute && current_sort_order == 'asc'
|
77
81
|
"<span class='fa fa-sort-down'></span>".html_safe
|
@@ -115,7 +119,7 @@ module SmartTable
|
|
115
119
|
if page_sizes.last >= total_records_count
|
116
120
|
page_sizes.reject! {|size| size > total_records_count}
|
117
121
|
end
|
118
|
-
|
122
|
+
|
119
123
|
page_sizes << SHOW_ALL
|
120
124
|
|
121
125
|
content_tag(:div, class: 'text-center') do
|
@@ -127,7 +131,12 @@ module SmartTable
|
|
127
131
|
if page_size == get_cached_smart_table_params.page_size || page_size == SHOW_ALL && get_cached_smart_table_params.page_size.nil?
|
128
132
|
human_page_size
|
129
133
|
else
|
130
|
-
link_to
|
134
|
+
link_to(
|
135
|
+
human_page_size,
|
136
|
+
current_request_url_with_merged_query_params(PAGE_SIZE_PARAM => page_size, PAGE_PARAM => 1),
|
137
|
+
class: 'smart-table-link',
|
138
|
+
data: {smart_table_remote_link: (true if get_cached_smart_table_params.remote)}
|
139
|
+
)
|
131
140
|
end
|
132
141
|
end.join(' ')
|
133
142
|
).html_safe
|
@@ -163,7 +172,7 @@ module SmartTable
|
|
163
172
|
text_field_tag(
|
164
173
|
SEARCH_PARAM,
|
165
174
|
get_cached_smart_table_params.search,
|
166
|
-
type: 'search', placeholder: I18n.t('smart_table.search'), class: 'smart_table_search'
|
175
|
+
type: 'search', placeholder: I18n.t('smart_table.search'), class: 'smart_table_search'
|
167
176
|
)
|
168
177
|
end
|
169
178
|
|
@@ -195,6 +204,39 @@ module SmartTable
|
|
195
204
|
)
|
196
205
|
end
|
197
206
|
|
207
|
+
# Delimits part of the page to me replaced via AJAX requests when smart_table
|
208
|
+
# is configured with option 'remote: true'. Usage:
|
209
|
+
#
|
210
|
+
# In controller:
|
211
|
+
# smart_table_params = smart_table_params(
|
212
|
+
# remote: true,
|
213
|
+
# ...
|
214
|
+
# )
|
215
|
+
#
|
216
|
+
# In views
|
217
|
+
# <%= smart_table_remote_updatable_content do %>
|
218
|
+
# ...
|
219
|
+
# <% end %>
|
220
|
+
#
|
221
|
+
# smart_table will automatically replace the content within this block with
|
222
|
+
# the content of the corresponding block within the response of the AJAX request
|
223
|
+
|
224
|
+
def smart_table_remote_updatable_content(&block)
|
225
|
+
raise 'smart_table_params must be called on the controller, before using smart_table_remote_updatable_content helper' unless get_cached_smart_table_params
|
226
|
+
|
227
|
+
content = capture(&block)
|
228
|
+
|
229
|
+
# only encloses content in span if remote update is enabled
|
230
|
+
if get_cached_smart_table_params.remote
|
231
|
+
content_tag(:span,
|
232
|
+
content,
|
233
|
+
class: 'smart_table_remote_updatable_content'
|
234
|
+
)
|
235
|
+
else
|
236
|
+
content
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
198
240
|
private
|
199
241
|
|
200
242
|
# generates url merging parameters to the current url
|
@@ -8,5 +8,5 @@
|
|
8
8
|
-%>
|
9
9
|
|
10
10
|
<% unless current_page.first? %>
|
11
|
-
<%= link_to t('views.pagination.first').html_safe, url, class: 'first', :remote
|
11
|
+
<%= link_to t('views.pagination.first').html_safe, url, class: 'first smart-table-link', data: {smart_table_remote_link: (remote if remote)} %>
|
12
12
|
<% end %>
|
@@ -8,5 +8,5 @@
|
|
8
8
|
-%>
|
9
9
|
|
10
10
|
<% unless current_page.last? %>
|
11
|
-
<%= link_to t('views.pagination.last').html_safe, url, class: 'last', :remote
|
11
|
+
<%= link_to t('views.pagination.last').html_safe, url, class: 'last smart-table-link', data: {smart_table_remote_link: (remote if remote)} %>
|
12
12
|
<% end %>
|
@@ -8,5 +8,5 @@
|
|
8
8
|
-%>
|
9
9
|
|
10
10
|
<% unless current_page.last? %>
|
11
|
-
<%= link_to t('views.pagination.next').html_safe, url, class: 'next', :rel => 'next', :remote
|
11
|
+
<%= link_to t('views.pagination.next').html_safe, url, class: 'next smart-table-link', :rel => 'next', data: {smart_table_remote_link: (remote if remote)} %>
|
12
12
|
<% end %>
|
@@ -7,4 +7,4 @@
|
|
7
7
|
per_page: number of items to fetch per page
|
8
8
|
remote: data-remote
|
9
9
|
-%>
|
10
|
-
<%= link_to page, url, {
|
10
|
+
<%= link_to page, url, {class: "page smart-table-link#{ ' current' if page.current? }", :rel => (page.next? ? 'next' : page.prev? ? 'prev' : nil), data: {smart_table_remote_link: (remote if remote)}} %>
|
@@ -12,10 +12,10 @@
|
|
12
12
|
<%= first_page_tag unless current_page.first? || total_pages <= 2 %>
|
13
13
|
<%= prev_page_tag unless current_page.first? %>
|
14
14
|
<% each_page do |page| -%>
|
15
|
-
|
16
|
-
|
15
|
+
<% if page.left_outer? || page.right_outer? || page.inside_window? -%>
|
16
|
+
<%= page_tag page %>
|
17
17
|
<% elsif !page.was_truncated? -%>
|
18
|
-
|
18
|
+
<%= gap_tag %>
|
19
19
|
<% end -%>
|
20
20
|
<% end -%>
|
21
21
|
<%= next_page_tag unless current_page.last? %>
|
@@ -8,5 +8,5 @@
|
|
8
8
|
-%>
|
9
9
|
|
10
10
|
<% unless current_page.first? %>
|
11
|
-
<%= link_to t('views.pagination.previous').html_safe, url, class: 'prev', rel: 'prev', :remote
|
11
|
+
<%= link_to t('views.pagination.previous').html_safe, url, class: 'prev smart-table-link', rel: 'prev', data: {smart_table_remote_link: (remote if remote)} %>
|
12
12
|
<% end %>
|
data/lib/smart_table/version.rb
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_table
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrique Gubert
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -187,6 +187,7 @@ files:
|
|
187
187
|
- "./lib/smart_table/engine.rb"
|
188
188
|
- "./lib/smart_table/version.rb"
|
189
189
|
- "./smart_table-0.0.7.gem"
|
190
|
+
- "./smart_table-0.0.8.gem"
|
190
191
|
- "./smart_table.gemspec"
|
191
192
|
- "./spec/dummy_app/Rakefile"
|
192
193
|
- "./spec/dummy_app/app/assets/config/manifest.js"
|