flex_infinite_scroll 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []