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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 224c0be14daa5e13ef122e4aeea2066df005abd593bd452960ae8f36d6ed3f11
4
- data.tar.gz: e3cb3b5ff817ddf96700c39cdc036f06b1f89ed94bcbf8e50903e5d2887f0b55
3
+ metadata.gz: f4e47371d7d1983b8b3576b2a68bfcf2cbb49fa205cd53a279fa7c8c9f32ec49
4
+ data.tar.gz: e8c894597e4f0f542312b1c16a3307421b00c287316bd98bfa57b485cc886b90
5
5
  SHA512:
6
- metadata.gz: e1d77e21f232f87f2e26f7f95e42c7b2aaa44c047bb5062f09ea2ea3625b21b8fbf6223f30fcce367c85cc0749c9a1949ef865e551a1e62a45ab361d0b71d99b
7
- data.tar.gz: 928f648e82098247902534638b3c812a75c990d38e82cae55df9223d4a0e8e048690e71209c48fb038437bc549a74dba8ad48bc03d33b7e7f8ec1ba3da977609
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
- document.addEventListener('DOMContentLoaded', callback);
11
- document.addEventListener("turbolinks:load", callback); // Turbolinks 5
12
- document.addEventListener("page:load", callback); // Turbolinks classic
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
- // On page load, we setup search field and extra filters
23
- SmartTable.onPageLoad(function() {
24
- SmartTable.setupSmartTableSearch();
25
- SmartTable.setupSmartTableExtraFilters();
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
- // makes the request
88
- window.location = SmartTable.currentUrlWithMergedQueryParams(params);
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
- SmartTable.setupSmartTableSearch = function() {
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 = document.getElementById('smart_table_search');
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
- SmartTable.setupSmartTableExtraFilters = function() {
108
- var smartTableExtraFilters = document.getElementById('smart_table_extra_filters');
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, param_name: PAGE_PARAM, theme: "smart_table")
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 human_page_size, current_request_url_with_merged_query_params(PAGE_SIZE_PARAM => page_size, PAGE_PARAM => 1)
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', id: '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 => 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 => 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 => 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, {:remote => remote, class: "page#{ ' current' if page.current? }", :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
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
- <% if page.left_outer? || page.right_outer? || page.inside_window? -%>
16
- <%= page_tag page %>
15
+ <% if page.left_outer? || page.right_outer? || page.inside_window? -%>
16
+ <%= page_tag page %>
17
17
  <% elsif !page.was_truncated? -%>
18
- <%= gap_tag %>
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 => 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 %>
@@ -1,3 +1,3 @@
1
1
  module SmartTable
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
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.8
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-18 00:00:00.000000000 Z
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"