flex_infinite_scroll 0.2.2 → 0.3.0

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
  SHA1:
3
- metadata.gz: d2fd414bc8323c2bb367697232a7e2e259cfed15
4
- data.tar.gz: 1f5f35932d20c2049a2e28734677e41a466338df
3
+ metadata.gz: 566821164973e19e83ef507c84b5b77f0d66e148
4
+ data.tar.gz: e22f3d0148db3746989eef48649e82376c12f02d
5
5
  SHA512:
6
- metadata.gz: 78ddf99585b446ec32503783b6a300904dec526a8489e8de03bf1d0aeac1f2291ceb26d84ad452eb23d28c1387c1b5ec3efb64370e366e78312275bf8f825473
7
- data.tar.gz: dac2a3773a6f1538873f57d20ec97ad85b98afeef77e2bf8a90c2e5672157a5081f1ee84d4efd552b76dfeec6bf7ea1e3aba68b42a316a3c95d925c56e1155d5
6
+ metadata.gz: b8a8bf1db18cdb92f26ef9953c5fee972f64c43de1e05f1fe0afae24fe21bbd07e425032d5675a8db5921c4bdab062ae80f2d6914bb542da046e9645be0a0c49
7
+ data.tar.gz: 4b6567f7892c2bc453d32a45a3a1866c8dd2eade75192f8386c3c7502262febd9e5295e6cad57c59a94f872619887eaaa734839ecd5241b5741c975e2b9fb61b
@@ -3,3 +3,6 @@
3
3
  module FlexInfiniteScroll
4
4
  class Engine < ::Rails::Engine; end
5
5
  end
6
+
7
+ require 'flex_infinite_scroll/activerecord'
8
+ require 'flex_infinite_scroll/actionview'
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveSupport.on_load :action_view do
4
+ require 'flex_infinite_scroll/actionview/extension'
5
+ ::ActionView::Base.include FlexInfiniteScroll::ActionViewExtension
6
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexInfiniteScroll
4
+ module ActionViewExtension
5
+ def fis_tag(data = nil, fis_config = {}, container_config = {})
6
+ container_config[:data] ||= {}
7
+ container_config[:class] = "fis-container #{container_config[:class]}"
8
+
9
+ virtual_el_size = fis_config[:virtualScrollElementSize]
10
+
11
+ page = fis_config[:startPage] || 1
12
+ fis_config[:startPage] = page + 1
13
+
14
+ fis_config.each do |k, _v|
15
+ container_config[:data][k.to_s.underscore] = fis_config[k]
16
+ end
17
+
18
+ content_tag :div, container_config do
19
+ data = data.fis(page: page, per_page: fis_config[:perPage])
20
+ data_html = data.map { |el| yield el }.join
21
+
22
+ baloons = []
23
+ if virtual_el_size
24
+ (fis_config[:startPage]..data.total_pages).each do |page_number|
25
+ baloons.push(
26
+ content_tag(:div, nil,
27
+ class: 'fis-baloon',
28
+ data: {
29
+ baloon_page: page_number
30
+ },
31
+ style: "height: #{virtual_el_size * data.per_page}px")
32
+ )
33
+ end
34
+ end
35
+ (data_html + baloons.join).html_safe
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveSupport.on_load :active_record do
4
+ require 'flex_infinite_scroll/activerecord/extension'
5
+ ::ActiveRecord::Base.include FlexInfiniteScroll::ActiveRecordExtension
6
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexInfiniteScroll
4
+ module ActiveRecordExtension
5
+ extend ActiveSupport::Concern
6
+
7
+ require 'flex_infinite_scroll/activerecord/helpers'
8
+
9
+ included do
10
+ def self.fis(config = { page: 1 })
11
+ page = config[:page].to_i
12
+ per_page = config[:per_page] ? config[:per_page].to_i : 20
13
+ offset(per_page * (page - 1)).limit(per_page).extending do
14
+ include FlexInfiniteScroll::ActiveRecordHelpers
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexInfiniteScroll
4
+ module ActiveRecordHelpers
5
+ def render_json
6
+ prepare_render.merge(data: as_json)
7
+ end
8
+
9
+ def render_html
10
+ prepare_render.merge(data: map { |el| yield el }.join.html_safe)
11
+ end
12
+
13
+ def per_page
14
+ values[:limit]
15
+ end
16
+
17
+ def page
18
+ (values[:offset] / per_page) + 1
19
+ end
20
+
21
+ def next_page
22
+ page == total_pages ? nil : page + 1
23
+ end
24
+
25
+ def total_pages
26
+ (except(:offset, :limit, :order).count / per_page).ceil
27
+ end
28
+
29
+ private
30
+
31
+ def prepare_render
32
+ {
33
+ next_page: next_page,
34
+ total_pages: total_pages
35
+ }
36
+ end
37
+ end
38
+ end
@@ -43,30 +43,39 @@ class flexIS {
43
43
 
44
44
  function prepareEventTarget(object) {
45
45
  var eventTarget = document.querySelector(object.config.eventTarget) || object.targetObject;
46
- if (object.config.windowScroll) {
46
+ if (["true", true].includes(object.config.windowScroll)) {
47
47
  return window;
48
48
  } else {
49
49
  return eventTarget;
50
50
  }
51
51
  }
52
52
 
53
- if (this.config.perfectScrollbarSupport) {
53
+ if (["true", true].includes(this.config.perfectScrollbarSupport)) {
54
54
  let PSConfig = this.config.perfectScrollbarConfig || {}
55
55
  PSConfig.minScrollbarLength = PSConfig.minScrollbarLength || 40
56
56
  this.perfectScrollbar = new PerfectScrollbar(
57
57
  this.targetObject,
58
58
  PSConfig
59
- )
59
+ );
60
60
  }
61
61
  }
62
62
 
63
63
  // Init infinite scroll
64
64
  init() {
65
- this.#getData();
65
+ if(this.#virtualScroll().enabled()) {
66
+ this.#virtualScroll().pagesLoad();
67
+ } else {
68
+ this.#getData();
69
+ }
70
+
66
71
  this.config.eventTarget.addEventListener('scroll', () => {
67
- if (this.#scrollHitBottom() && this.nextPage) {
68
- this.#getData();
69
- };
72
+ if(this.#virtualScroll().enabled()) {
73
+ this.#virtualScroll().pagesLoad();
74
+ } else {
75
+ if (this.#scrollHitBottom() && this.nextPage) {
76
+ this.#getData();
77
+ };
78
+ }
70
79
  this.#hideInvisibleContent();
71
80
  });
72
81
  return this;
@@ -89,13 +98,13 @@ class flexIS {
89
98
  // Private methods
90
99
 
91
100
  // Run data request for next page
92
- #getData = (page = this.nextPage ) => {
101
+ #getData = (page = this.nextPage, forceLoad = false) => {
93
102
  var xhr = new XMLHttpRequest();
94
103
  var params;
95
104
  const beforeLoadEvent = new CustomEvent('FlexIS:beforeLoad');
96
105
  const afterLoadEvent = new CustomEvent('FlexIS:afterLoad');
97
106
 
98
- if (!page || this.loading) return false;
107
+ if (!page || (this.loading && !forceLoad)) return false;
99
108
 
100
109
  this.loading = true;
101
110
 
@@ -109,13 +118,11 @@ class flexIS {
109
118
  this.loading = false;
110
119
 
111
120
  if (xhr.status === 200) {
112
- this.#customResponse(json);
113
- this.nextPage = json[this.config.customResponseAttributes.next_page];
114
- if (this.config.virtualScroll) {
115
- this.elementsLeft = json[this.config.customResponseAttributes.elements_left];
116
- this.#virtualScroll().update();
121
+ this.#customResponse(json, page);
122
+ if (!this.#virtualScroll().enabled()) {
123
+ this.nextPage = json[this.config.customResponseAttributes.next_page];
124
+ if (this.#scrollHitBottom()) this.#getData();
117
125
  }
118
- if (this.#scrollHitBottom()) this.#getData();
119
126
  }
120
127
 
121
128
  this.targetObject.dispatchEvent(afterLoadEvent);
@@ -141,7 +148,7 @@ class flexIS {
141
148
 
142
149
  // Container position
143
150
  #containerPosition = () => {
144
- return this.#scrollTop() + this.#containerSize() + this.config.loadMargin
151
+ return this.#scrollTop() + this.#containerSize() + this.config.loadMargin;
145
152
  }
146
153
 
147
154
  // Add custom params to request
@@ -160,12 +167,12 @@ class flexIS {
160
167
  }
161
168
 
162
169
  // Response handling
163
- #customResponse = (json) => {
170
+ #customResponse = (json, page) => {
164
171
  var customResponse = this.config.customResponse;
165
172
  var data = json[this.config.customResponseAttributes.data];
166
173
  var div;
167
174
 
168
- delete json[this.config.customResponseAttributes.data]
175
+ delete json[this.config.customResponseAttributes.data];
169
176
 
170
177
  if (data.constructor === Array) {
171
178
  data.forEach((el) => {
@@ -173,32 +180,37 @@ class flexIS {
173
180
  if (typeof customResponse === "function") {
174
181
  htmlEl = customResponse(el, json);
175
182
  } else {
176
- htmlEl = el;
183
+ let div = document.createElement('div');
184
+ div.innerHTML = el;
185
+ htmlEl = div.children[0];
177
186
  }
178
- this.#appendElementToContainer(htmlEl)
187
+ this.#appendElementToContainer(htmlEl, page);
179
188
  })
180
189
  } else if (data.constructor === String) {
181
190
  div = document.createElement('div');
182
191
  div.innerHTML = data;
183
192
  while (div.children.length > 0) {
184
- this.#appendElementToContainer(div.children[0])
193
+ this.#appendElementToContainer(div.children[0], page);
185
194
  }
186
195
  }
187
196
 
188
197
  this.#hideInvisibleContent();
189
198
 
199
+ if (this.#virtualScroll().enabled()) {
200
+ this.#virtualScroll().destroyBaloon(page);
201
+ }
202
+
190
203
  if (this.perfectScrollbar) {
191
204
  this.perfectScrollbar.update();
192
205
  }
193
206
  }
194
207
 
195
- #appendElementToContainer = (el) => {
196
- if (this.#virtualScroll().baloon()) {
197
- this.targetObject.insertBefore(el, this.#virtualScroll().baloon());
208
+ #appendElementToContainer = (el, page) => {
209
+ if (this.#virtualScroll().enabled()) {
210
+ this.#virtualScroll().insertBeforeBaloon(page, el);
198
211
  } else {
199
212
  this.targetObject.appendChild(el);
200
213
  }
201
- this.elementHeight = el.offsetHeight;
202
214
  }
203
215
 
204
216
  // Hide invisible content, when leaving active zone
@@ -222,45 +234,33 @@ class flexIS {
222
234
  }
223
235
 
224
236
  #virtualScroll = () => {
225
- // Find baloon
226
- var baloon = this.targetObject.getElementsByClassName('fis-baloon')[0];
227
-
228
- // Create new baloon
229
- var createBaloon = () => {
230
- baloon = document.createElement('div');
231
- baloon.className = 'fis-baloon';
232
- this.targetObject.appendChild(baloon);
233
- return baloon;
234
- }
235
-
236
- // Check if baloon exist and return it
237
- var baloonAdded = () => {
238
- if (baloon) {
239
- return baloon;
240
- }
241
- return false
242
- }
243
-
244
- // Update baloon size
245
- var updateScroll = () => {
246
- var elementHeight = this.config.virtualScrollElementSize || this.elementHeight;
247
- if (!baloonAdded()) {
248
- baloon = createBaloon();
249
- }
250
- if (this.elementsLeft > 0) {
251
- baloon.style.height = (elementHeight * this.elementsLeft) + 'px';
252
- } else {
253
- // Remove baloon, if no more elements to load.
254
- baloon.remove();
255
- }
256
- }
257
-
258
237
  return {
259
- update: () => {
260
- updateScroll()
238
+ enabled: () => {
239
+ return ["true", true].includes(this.config.virtualScroll);
261
240
  },
262
- baloon: () => {
263
- return baloonAdded();
241
+ insertBeforeBaloon: (page, el) => {
242
+ var baloon = this.targetObject.querySelector(`[data-baloon-page="${page}"]`)
243
+ var newHeight;
244
+ this.targetObject.insertBefore(el, baloon);
245
+ newHeight = baloon.offsetHeight - el.offsetHeight;
246
+ baloon.style.height = newHeight + 'px';
247
+
248
+ },
249
+ pagesLoad: () => {
250
+ var baloons = [...this.targetObject.getElementsByClassName('fis-baloon')];
251
+ var containerPosition = this.#containerPosition();
252
+ baloons.forEach(baloon => {
253
+ var visibleBottom = this.#containerPosition() > baloon.offsetTop;
254
+ var visibleTop = this.#scrollTop() < baloon.offsetTop + baloon.offsetHeight;
255
+ if (baloon.dataset.loading) return;
256
+ if (visibleBottom && visibleTop) {
257
+ baloon.dataset.loading = true;
258
+ this.#getData(baloon.dataset.baloonPage, true);
259
+ }
260
+ })
261
+ },
262
+ destroyBaloon: (page) => {
263
+ this.targetObject.querySelector(`[data-baloon-page="${page}"]`).remove();
264
264
  }
265
265
  }
266
266
  }
@@ -287,13 +287,7 @@ class flexIS {
287
287
 
288
288
  // Check when load next page
289
289
  #scrollHitBottom = () => {
290
- var hitBottom;
291
- if (this.#virtualScroll().baloon()) {
292
- hitBottom = this.#containerPosition() > this.#virtualScroll().baloon().offsetTop;
293
- } else {
294
- hitBottom = this.#scrollHeight() - this.#containerPosition() <= 0;
295
- }
296
- return hitBottom;
290
+ return this.#scrollHeight() - this.#containerPosition() <= 0;
297
291
  }
298
292
  }
299
293
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flex_infinite_scroll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Ignatov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-21 00:00:00.000000000 Z
11
+ date: 2020-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -31,6 +31,11 @@ extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
33
  - lib/flex_infinite_scroll.rb
34
+ - lib/flex_infinite_scroll/actionview.rb
35
+ - lib/flex_infinite_scroll/actionview/extension.rb
36
+ - lib/flex_infinite_scroll/activerecord.rb
37
+ - lib/flex_infinite_scroll/activerecord/extension.rb
38
+ - lib/flex_infinite_scroll/activerecord/helpers.rb
34
39
  - vendor/assets/javascript/flex_infinite_scroll.js
35
40
  homepage: https://github.com/aignatov-bio/flex_infinite_scroll
36
41
  licenses:
@@ -55,7 +60,5 @@ rubyforge_project:
55
60
  rubygems_version: 2.6.14.3
56
61
  signing_key:
57
62
  specification_version: 4
58
- summary: 'Infinite scroll for Ruby on Rails applications on pure JavaScript. Supported
59
- features: - Custom response handling. - Virtual scrollbar. - Perfect scrollbar support.
60
- - Kaminari support.'
63
+ summary: Infinite scroll for Ruby on Rails applications on pure JavaScript.
61
64
  test_files: []