• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

naver / egjs-infinitegrid / 3869242514

pending completion
3869242514

Pull #527

github

GitHub
Merge 42f03d580 into 6db0bffc8
Pull Request #527: feat: upgrade to Angular 15 and enable partial compilation

523 of 649 branches covered (80.59%)

Branch coverage included in aggregate %.

1349 of 1446 relevant lines covered (93.29%)

114.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.21
/packages/infinitegrid/src/ScrollManager.ts
1
import { findTarget, Ref } from "@cfcs/core";
1✔
2
import Component, { ComponentEvent } from "@egjs/component";
1✔
3
import { CONTAINER_CLASS_NAME, IS_IOS } from "./consts";
1✔
4
import { OnChangeScroll } from "./types";
5
import { isWindow, toArray } from "./utils";
1✔
6

7
export interface ScrollManagerOptions {
8
  scrollContainer?: HTMLElement | string | Ref<HTMLElement> | null;
9
  container?: boolean | HTMLElement | string | Ref<HTMLElement>;
10
  containerTag?: string;
11
  horizontal?: boolean;
12
}
13

14
export interface ScrollManagerStatus {
15
  contentSize: number;
16
  scrollOffset: number;
17
  prevScrollPos: number;
18
}
19

20

21
export interface ScrollManagerEvents {
22
  scroll: OnChangeScroll;
23
}
24

25
export class ScrollManager extends Component<ScrollManagerEvents> {
1✔
26
  public options: Required<ScrollManagerOptions>;
27
  protected prevScrollPos: number | null = null;
70✔
28
  protected eventTarget: HTMLElement | Window;
29
  protected scrollOffset = 0;
70✔
30
  protected contentSize = 0;
70✔
31
  protected container: HTMLElement;
32
  protected scrollContainer: HTMLElement;
33
  private _orgCSSText: string;
34
  private _isScrollIssue = IS_IOS;
70✔
35
  private _isCreateElement: boolean;
36

37
  constructor(
71✔
38
    protected wrapper: HTMLElement,
70✔
39
    options: ScrollManagerOptions,
40
  ) {
41
    super();
140✔
42
    this.options = {
70✔
43
      container: false,
44
      containerTag: "div",
45
      horizontal: false,
46
      scrollContainer: null,
47
      ...options,
48
    };
49

50
    this._init();
70✔
51
  }
52
  public getWrapper() {
1✔
53
    return this.wrapper;
6✔
54
  }
55
  public getContainer() {
1✔
56
    return this.container;
102✔
57
  }
58
  public getScrollContainer() {
1✔
59
    return this.scrollContainer;
27✔
60
  }
61
  public getScrollOffset() {
1✔
62
    return this.scrollOffset;
1✔
63
  }
64
  public getContentSize() {
1✔
65
    return this.contentSize;
166✔
66
  }
67
  public getRelativeScrollPos() {
1✔
68
    return (this.prevScrollPos || 0) - this.scrollOffset;
223✔
69
  }
70
  public getScrollPos() {
1✔
71
    return this.prevScrollPos;
20✔
72
  }
73
  public setScrollPos(pos: number) {
1✔
74
    this.prevScrollPos = pos;
90✔
75
  }
76
  public getOrgScrollPos() {
1✔
77
    const eventTarget = this.eventTarget;
90✔
78
    const horizontal = this.options.horizontal;
90✔
79

80
    const prop = `scroll${horizontal ? "Left" : "Top"}` as "scrollLeft" | "scrollTop";
90✔
81

82
    if (isWindow(eventTarget)) {
90✔
83
      return window[horizontal ? "pageXOffset" : "pageYOffset"]
1!
84
        || document.documentElement[prop] || document.body[prop];
85
    } else {
86
      return eventTarget[prop];
89✔
87
    }
88
  }
89
  public setStatus(status: ScrollManagerStatus) {
1✔
90
    this.contentSize = status.contentSize;
13✔
91
    this.scrollOffset = status.scrollOffset;
13✔
92
    this.prevScrollPos = status.prevScrollPos;
13✔
93

94
    this.scrollTo(this.prevScrollPos);
13✔
95
  }
96
  public getStatus(): ScrollManagerStatus {
1✔
97
    return {
15✔
98
      contentSize: this.contentSize,
99
      scrollOffset: this.scrollOffset,
100
      prevScrollPos: this.prevScrollPos!,
101
    };
102
  }
103
  public scrollTo(pos: number) {
1✔
104
    const eventTarget = this.eventTarget;
15✔
105
    const horizontal = this.options.horizontal;
15✔
106
    const [x, y] = horizontal ? [pos, 0] : [0, pos];
15!
107

108
    if (isWindow(eventTarget)) {
15!
109
      eventTarget.scroll(x, y);
×
110
    } else {
111
      eventTarget.scrollLeft = x;
15✔
112
      eventTarget.scrollTop = y;
15✔
113
    }
114
  }
115
  public scrollBy(pos: number) {
1✔
116
    if (!pos) {
71✔
117
      return;
66✔
118
    }
119
    const eventTarget = this.eventTarget;
5✔
120
    const horizontal = this.options.horizontal;
5✔
121
    const [x, y] = horizontal ? [pos, 0] : [0, pos];
5!
122

123

124
    this.prevScrollPos! += pos;
5✔
125

126
    if (isWindow(eventTarget)) {
5!
127
      eventTarget.scrollBy(x, y);
×
128
    } else {
129
      eventTarget.scrollLeft += x;
5✔
130
      eventTarget.scrollTop += y;
5✔
131
    }
132
  }
133
  public resize() {
1✔
134
    const scrollContainer = this.scrollContainer;
96✔
135
    const horizontal = this.options.horizontal;
96✔
136
    const isBody = scrollContainer === document.body;
96✔
137
    const scrollContainerRect = isBody
96✔
138
      ? { top: 0, left: 0 }
96✔
139
      : scrollContainer.getBoundingClientRect();
140
    const containerRect = this.container.getBoundingClientRect();
96✔
141

142
    this.scrollOffset = (this.prevScrollPos! || 0) + (horizontal
96✔
143
      ? containerRect.left - scrollContainerRect.left
96✔
144
      : containerRect.top - scrollContainerRect.top);
145

146
    if (isBody) {
96✔
147
      this.contentSize = horizontal ? window.innerWidth : window.innerHeight;
1!
148
    } else {
149
      this.contentSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight;
95✔
150
    }
151
  }
152
  public destroy() {
1✔
153
    const container = this.container;
70✔
154

155
    this.eventTarget.removeEventListener("scroll", this._onCheck);
70✔
156

157
    if (this._isCreateElement) {
70✔
158
      const scrollContainer = this.scrollContainer;
66✔
159

160
      const fragment = document.createDocumentFragment();
66✔
161
      const childNodes = toArray(container.childNodes);
66✔
162

163
      scrollContainer.removeChild(container);
66✔
164
      childNodes.forEach((childNode) => {
66✔
165
        fragment.appendChild(childNode);
479✔
166
      });
167
      scrollContainer.appendChild(fragment);
66✔
168
    } else if (this.options.container) {
4✔
169
      container.style.cssText = this._orgCSSText;
2✔
170
    }
171
  }
172
  private _init() {
1✔
173
    const {
70✔
174
      container: containerOption,
175
      containerTag,
176
      horizontal,
177
      scrollContainer: scrollContainerOption,
178
    } = this.options;
179
    const wrapper = this.wrapper;
70✔
180
    let scrollContainer = wrapper;
70✔
181
    let container = wrapper;
70✔
182
    let containerCSSText = "";
70✔
183

184
    if (!containerOption) {
70✔
185
      scrollContainer = findTarget(scrollContainerOption) || document.body;
2✔
186
      containerCSSText = container.style.cssText;
2✔
187
    } else {
188
      if (containerOption === true) {
68✔
189
        // Create Container
190
        container = document.createElement(containerTag) as HTMLElement;
66✔
191

192
        container.style.position = "relative";
66✔
193
        container.className = CONTAINER_CLASS_NAME;
66✔
194
        const childNodes = toArray(scrollContainer.childNodes);
66✔
195

196
        childNodes.forEach((childNode) => {
66✔
197
          container.appendChild(childNode);
74✔
198
        });
199
        scrollContainer.appendChild(container);
66✔
200

201
        this._isCreateElement = true;
66✔
202
      } else {
203
        // Find Container
204
        container = findTarget(containerOption)!;
2✔
205
      }
206
      containerCSSText = container.style.cssText;
68✔
207

208
      const style = scrollContainer.style;
68✔
209

210
      [style.overflowX, style.overflowY] = horizontal ? ["scroll", "hidden"] : ["hidden", "scroll"];
68✔
211

212
      if (horizontal) {
68✔
213
        container.style.height = "100%";
1✔
214
      }
215
    }
216
    const eventTarget = scrollContainer === document.body ? window : scrollContainer;
70✔
217

218
    eventTarget.addEventListener("scroll", this._onCheck);
70✔
219
    this._orgCSSText = containerCSSText;
70✔
220
    this.container = container;
70✔
221
    this.scrollContainer = scrollContainer;
70✔
222
    this.eventTarget = eventTarget;
70✔
223
    this.resize();
70✔
224
    this.setScrollPos(this.getOrgScrollPos());
70✔
225
  }
226
  private _onCheck = () => {
70✔
227
    const prevScrollPos = this.getScrollPos();
20✔
228
    const nextScrollPos = this.getOrgScrollPos();
20✔
229

230
    this.setScrollPos(nextScrollPos);
20✔
231

232
    if (prevScrollPos === null || (this._isScrollIssue && nextScrollPos === 0) || prevScrollPos === nextScrollPos) {
20✔
233
      nextScrollPos && (this._isScrollIssue = false);
1!
234
      return;
1✔
235
    }
236
    this._isScrollIssue = false;
19✔
237
    this.trigger(new ComponentEvent("scroll", {
19✔
238
      direction: prevScrollPos < nextScrollPos ? "end" : "start",
19✔
239
      scrollPos: nextScrollPos,
240
      relativeScrollPos: this.getRelativeScrollPos(),
241
    }));
242
  }
243
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc