1 |
|
2 |
|
3 |
|
4 | import { proxyCustomElement, HTMLElement, createEvent, writeTask, readTask, h, Host } from '@stencil/core/internal/client';
|
5 | import { b as getIonMode } from './ionic-global.js';
|
6 | import { c as componentOnReady } from './helpers.js';
|
7 |
|
8 | const infiniteScrollCss = "ion-infinite-scroll{display:none;width:100%}.infinite-scroll-enabled{display:block}";
|
9 |
|
10 | const InfiniteScroll = proxyCustomElement(class extends HTMLElement {
|
11 | constructor() {
|
12 | super();
|
13 | this.__registerHost();
|
14 | this.ionInfinite = createEvent(this, "ionInfinite", 7);
|
15 | this.thrPx = 0;
|
16 | this.thrPc = 0;
|
17 | this.didFire = false;
|
18 | this.isBusy = false;
|
19 | this.isLoading = false;
|
20 | |
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | this.threshold = '15%';
|
30 | |
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | this.disabled = false;
|
40 | |
41 |
|
42 |
|
43 |
|
44 | this.position = 'bottom';
|
45 | this.onScroll = () => {
|
46 | const scrollEl = this.scrollEl;
|
47 | if (!scrollEl || !this.canStart()) {
|
48 | return 1;
|
49 | }
|
50 | const infiniteHeight = this.el.offsetHeight;
|
51 | if (infiniteHeight === 0) {
|
52 |
|
53 | return 2;
|
54 | }
|
55 | const scrollTop = scrollEl.scrollTop;
|
56 | const scrollHeight = scrollEl.scrollHeight;
|
57 | const height = scrollEl.offsetHeight;
|
58 | const threshold = this.thrPc !== 0 ? (height * this.thrPc) : this.thrPx;
|
59 | const distanceFromInfinite = (this.position === 'bottom')
|
60 | ? scrollHeight - infiniteHeight - scrollTop - threshold - height
|
61 | : scrollTop - infiniteHeight - threshold;
|
62 | if (distanceFromInfinite < 0) {
|
63 | if (!this.didFire) {
|
64 | this.isLoading = true;
|
65 | this.didFire = true;
|
66 | this.ionInfinite.emit();
|
67 | return 3;
|
68 | }
|
69 | }
|
70 | else {
|
71 | this.didFire = false;
|
72 | }
|
73 | return 4;
|
74 | };
|
75 | }
|
76 | thresholdChanged() {
|
77 | const val = this.threshold;
|
78 | if (val.lastIndexOf('%') > -1) {
|
79 | this.thrPx = 0;
|
80 | this.thrPc = (parseFloat(val) / 100);
|
81 | }
|
82 | else {
|
83 | this.thrPx = parseFloat(val);
|
84 | this.thrPc = 0;
|
85 | }
|
86 | }
|
87 | disabledChanged() {
|
88 | const disabled = this.disabled;
|
89 | if (disabled) {
|
90 | this.isLoading = false;
|
91 | this.isBusy = false;
|
92 | }
|
93 | this.enableScrollEvents(!disabled);
|
94 | }
|
95 | async connectedCallback() {
|
96 | const contentEl = this.el.closest('ion-content');
|
97 | if (!contentEl) {
|
98 | console.error('<ion-infinite-scroll> must be used inside an <ion-content>');
|
99 | return;
|
100 | }
|
101 | await new Promise(resolve => componentOnReady(contentEl, resolve));
|
102 | this.scrollEl = await contentEl.getScrollElement();
|
103 | this.thresholdChanged();
|
104 | this.disabledChanged();
|
105 | if (this.position === 'top') {
|
106 | writeTask(() => {
|
107 | if (this.scrollEl) {
|
108 | this.scrollEl.scrollTop = this.scrollEl.scrollHeight - this.scrollEl.clientHeight;
|
109 | }
|
110 | });
|
111 | }
|
112 | }
|
113 | disconnectedCallback() {
|
114 | this.enableScrollEvents(false);
|
115 | this.scrollEl = undefined;
|
116 | }
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | async complete() {
|
128 | const scrollEl = this.scrollEl;
|
129 | if (!this.isLoading || !scrollEl) {
|
130 | return;
|
131 | }
|
132 | this.isLoading = false;
|
133 | if (this.position === 'top') {
|
134 | |
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | this.isBusy = true;
|
154 |
|
155 |
|
156 | const prev = scrollEl.scrollHeight - scrollEl.scrollTop;
|
157 |
|
158 | requestAnimationFrame(() => {
|
159 | readTask(() => {
|
160 |
|
161 | const scrollHeight = scrollEl.scrollHeight;
|
162 |
|
163 | const newScrollTop = scrollHeight - prev;
|
164 |
|
165 | requestAnimationFrame(() => {
|
166 | writeTask(() => {
|
167 | scrollEl.scrollTop = newScrollTop;
|
168 | this.isBusy = false;
|
169 | });
|
170 | });
|
171 | });
|
172 | });
|
173 | }
|
174 | }
|
175 | canStart() {
|
176 | return (!this.disabled &&
|
177 | !this.isBusy &&
|
178 | !!this.scrollEl &&
|
179 | !this.isLoading);
|
180 | }
|
181 | enableScrollEvents(shouldListen) {
|
182 | if (this.scrollEl) {
|
183 | if (shouldListen) {
|
184 | this.scrollEl.addEventListener('scroll', this.onScroll);
|
185 | }
|
186 | else {
|
187 | this.scrollEl.removeEventListener('scroll', this.onScroll);
|
188 | }
|
189 | }
|
190 | }
|
191 | render() {
|
192 | const mode = getIonMode(this);
|
193 | const disabled = this.disabled;
|
194 | return (h(Host, { class: {
|
195 | [mode]: true,
|
196 | 'infinite-scroll-loading': this.isLoading,
|
197 | 'infinite-scroll-enabled': !disabled
|
198 | } }));
|
199 | }
|
200 | get el() { return this; }
|
201 | static get watchers() { return {
|
202 | "threshold": ["thresholdChanged"],
|
203 | "disabled": ["disabledChanged"]
|
204 | }; }
|
205 | static get style() { return infiniteScrollCss; }
|
206 | }, [0, "ion-infinite-scroll", {
|
207 | "threshold": [1],
|
208 | "disabled": [4],
|
209 | "position": [1],
|
210 | "isLoading": [32],
|
211 | "complete": [64]
|
212 | }]);
|
213 | function defineCustomElement$1() {
|
214 | if (typeof customElements === "undefined") {
|
215 | return;
|
216 | }
|
217 | const components = ["ion-infinite-scroll"];
|
218 | components.forEach(tagName => { switch (tagName) {
|
219 | case "ion-infinite-scroll":
|
220 | if (!customElements.get(tagName)) {
|
221 | customElements.define(tagName, InfiniteScroll);
|
222 | }
|
223 | break;
|
224 | } });
|
225 | }
|
226 |
|
227 | const IonInfiniteScroll = InfiniteScroll;
|
228 | const defineCustomElement = defineCustomElement$1;
|
229 |
|
230 | export { IonInfiniteScroll, defineCustomElement };
|