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

naver / egjs-flicking / 10557177632

26 Aug 2024 09:22AM UTC coverage: 38.327% (-44.5%) from 82.855%
10557177632

Pull #886

github

daybrush
fix: recalculate camera offset
Pull Request #886: fix: recalculate camera offset

2039 of 7372 branches covered (27.66%)

Branch coverage included in aggregate %.

11 of 29 new or added lines in 2 files covered. (37.93%)

5575 existing lines in 46 files now uncovered.

5099 of 11252 relevant lines covered (45.32%)

10.91 hits per line

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

53.78
/src/utils.ts
1
/*
1✔
2
 * Copyright (c) 2015 NAVER Corp.
1!
3
 * egjs projects are licensed under the MIT license
×
4
 */
5
import Flicking, { FlickingOptions } from "./Flicking";
6
import FlickingError from "./core/FlickingError";
5!
7
import * as ERROR from "./const/error";
5✔
8
import { ALIGN, DIRECTION } from "./const/external";
5✔
9
import { LiteralUnion, Merged, ValueOf } from "./type/internal";
1!
10
import { ElementLike } from "./type/external";
11

12
// eslint-disable-next-line @typescript-eslint/ban-types
13
export const merge = <From extends object, To extends object>(target: From, ...sources: To[]): Merged<From, To> => {
5✔
14
  sources.forEach(source => {
1✔
15
    Object.keys(source).forEach(key => {
1!
16
      target[key] = source[key] as unknown;
×
17
    });
×
18
  });
19

20
  return target as Merged<From, To>;
21
};
1✔
22

1!
23
export const getElement = (el: HTMLElement | string | null, parent?: HTMLElement): HTMLElement => {
5✔
24
  let targetEl: HTMLElement | null = null;
15✔
25

1✔
26
  if (isString(el)) {
15!
27
    const parentEl = parent ? parent : document;
15!
28
    const queryResult = parentEl.querySelector(el);
15✔
29
    if (!queryResult) {
14!
30
      throw new FlickingError(ERROR.MESSAGE.ELEMENT_NOT_FOUND(el), ERROR.CODE.ELEMENT_NOT_FOUND);
1✔
31
    }
7✔
32
    targetEl = queryResult as HTMLElement;
21✔
33
  } else if (el && el.nodeType === Node.ELEMENT_NODE) {
7!
34
    targetEl = el;
35
  }
7✔
36

7✔
37
  if (!targetEl) {
84!
38
    throw new FlickingError(ERROR.MESSAGE.WRONG_TYPE(el, ["HTMLElement", "string"]), ERROR.CODE.WRONG_TYPE);
39
  }
40

7✔
41
  return targetEl;
14✔
42
};
1✔
43

1✔
44
export const checkExistence = (value: any, nameOnErrMsg: string) => {
6✔
45
  if (value == null) {
15!
UNCOV
46
    throw new FlickingError(ERROR.MESSAGE.VAL_MUST_NOT_NULL(value, nameOnErrMsg), ERROR.CODE.VAL_MUST_NOT_NULL);
×
47
  }
48
};
×
49

50
export const clamp = (x: number, min: number, max: number) => Math.max(Math.min(x, max), min);
5✔
51

52
export const getFlickingAttached = (val: Flicking | null): Flicking => {
5✔
53
  if (!val) {
2,406!
54
    throw new FlickingError(ERROR.MESSAGE.NOT_ATTACHED_TO_FLICKING, ERROR.CODE.NOT_ATTACHED_TO_FLICKING);
1✔
55
  }
56

1!
57
  return val;
2,405✔
58
};
59

1✔
60
export const toArray = <T>(iterable: ArrayLike<T>): T[] => [].slice.call(iterable) as T[];
28✔
61

1✔
62
export const parseAlign = (align: LiteralUnion<ValueOf<typeof ALIGN>> | number, size: number): number => {
6✔
63
  let alignPoint: number | null;
1!
64
  if (isString(align)) {
68!
65
    switch (align) {
68!
66
      case ALIGN.PREV:
67
        alignPoint = 0;
1✔
68
        break;
1✔
69
      case ALIGN.CENTER:
1✔
70
        alignPoint = 0.5 * size;
69✔
71
        break;
129!
72
      case ALIGN.NEXT:
73
        alignPoint = size;
74
        break;
61✔
75
      default:
76
        alignPoint = parseArithmeticSize(align, size);
1✔
77
        if (alignPoint == null) {
2!
78
          throw new FlickingError(ERROR.MESSAGE.WRONG_OPTION("align", align), ERROR.CODE.WRONG_OPTION);
1✔
79
        }
1✔
80
    }
81
  } else {
12!
82
    alignPoint = align as number;
12!
83
  }
84

85
  return alignPoint;
68✔
86
};
87

12✔
88
export const parseBounce = (bounce: FlickingOptions["bounce"], size: number): number[] => {
17✔
89
  let parsedBounce: Array<number | null>;
90

91
  if (Array.isArray(bounce)) {
28!
92
    parsedBounce = (bounce as string[]).map(val => parseArithmeticSize(val, size));
93
  } else {
94
    const parsedVal = parseArithmeticSize(bounce, size);
28!
95

96
    parsedBounce = [parsedVal, parsedVal];
28✔
97
  }
98

99
  return parsedBounce.map(val => {
28✔
100
    if (val == null) {
56!
101
      throw new FlickingError(ERROR.MESSAGE.WRONG_OPTION("bounce", bounce), ERROR.CODE.WRONG_OPTION);
102
    }
12✔
103
    return val;
56✔
104
  });
1✔
105
};
1✔
106

107
export const parseArithmeticSize = (cssValue: number | string, base: number): number | null => {
8!
108
  const parsed = parseArithmeticExpression(cssValue);
28✔
109

110
  if (parsed == null) return null;
28!
111

3✔
112
  return parsed.percentage * base + parsed.absolute;
31✔
113
};
114

3✔
115
export const parseArithmeticExpression = (cssValue: number | string): { percentage: number; absolute: number } | null => {
11!
116
  const cssRegex = /(?:(\+|\-)\s*)?(\d+(?:\.\d+)?(%|px)?)/g;
28✔
117

118
  if (typeof cssValue === "number") {
34!
119
    return { percentage: 0, absolute: cssValue };
120
  }
121

1✔
122
  const parsed = {
29✔
123
    percentage: 0,
3✔
124
    absolute: 0
3!
125
  };
126
  let idx = 0;
31✔
127
  let matchResult = cssRegex.exec(cssValue);
28✔
128
  while (matchResult != null) {
29✔
129
    let sign = matchResult[1];
29✔
130
    const value = matchResult[2];
31✔
131
    const unit = matchResult[3];
31!
132
    const parsedValue = parseFloat(value);
28✔
133

134
    if (idx <= 0) {
31✔
135
      sign = sign || "+";
28✔
136
    }
137

138
    // Return default value for values not in good form
3✔
139
    if (!sign) {
31!
140
      return null;
3✔
141
    }
3✔
142

3✔
143
    const signMultiplier = sign === "+" ? 1 : -1;
31!
144

3✔
145
    if (unit === "%") {
31!
146
      parsed.percentage += signMultiplier * (parsedValue / 100);
31✔
147
    } else {
148
      parsed.absolute += signMultiplier * parsedValue;
149
    }
3!
150

151
    // Match next occurrence
152
    ++idx;
31!
153
    matchResult = cssRegex.exec(cssValue);
31!
154
  }
3✔
155

156
  // None-matched
157
  if (idx === 0) {
28!
158
    return null;
159
  }
160

3✔
161
  return parsed;
31✔
162
};
163

164
export const parseCSSSizeValue = (val: string | number): string => isString(val) ? val : `${val}px`;
8!
165

166
export const parsePanelAlign = (align: FlickingOptions["align"]) => typeof align === "object"
14!
167
  ? (align as { panel: string | number }).panel
3✔
168
  : align;
169

1✔
170
export const getDirection = (start: number, end: number): ValueOf<typeof DIRECTION> => {
17✔
171
  if (start === end) return DIRECTION.NONE;
326✔
172
  return start < end ? DIRECTION.NEXT : DIRECTION.PREV;
324!
173
};
174

175
export const parseElement = (element: ElementLike | ElementLike[]): HTMLElement[] => {
6✔
176
  if (!Array.isArray(element)) {
1!
UNCOV
177
    element = [element];
×
178
  }
179

×
180
  const elements: HTMLElement[] = [];
181
  element.forEach(el => {
1✔
182
    if (isString(el)) {
1!
UNCOV
183
      const tempDiv = document.createElement("div");
×
UNCOV
184
      tempDiv.innerHTML = el;
×
185

UNCOV
186
      elements.push(...toArray(tempDiv.children) as HTMLElement[]);
×
UNCOV
187
      while (tempDiv.firstChild) {
×
UNCOV
188
        tempDiv.removeChild(tempDiv.firstChild);
×
189
      }
UNCOV
190
    } else if (el && el.nodeType === Node.ELEMENT_NODE) {
×
UNCOV
191
      elements.push(el);
×
192
    } else {
UNCOV
193
      throw new FlickingError(ERROR.MESSAGE.WRONG_TYPE(el, ["HTMLElement", "string"]), ERROR.CODE.WRONG_TYPE);
×
194
    }
195
  });
196

×
UNCOV
197
  return elements;
×
198
};
199

200
export const getMinusCompensatedIndex = (idx: number, max: number) => idx < 0 ? clamp(idx + max, 0, max) : clamp(idx, 0, max);
5!
201

202
export const includes = <T>(array: T[], target: any): target is T => {
5✔
203
  for (const val of array) {
2,592✔
204
    if (val === target) return true;
1,894✔
205
  }
1✔
206
  return false;
31!
207
};
1✔
208

1✔
209
export const isString = (val: any): val is string => typeof val === "string";
86✔
210

3✔
211
export const circulatePosition = (pos: number, min: number, max: number) => {
8!
212
  const size = max - min;
3✔
213

214
  if (pos < min) {
1!
215
    const offset = (min - pos) % size;
216
    pos = max - offset;
1✔
217
  } else if (pos > max) {
25!
218
    const offset = (pos - max) % size;
1✔
219
    pos = min + offset;
1✔
220
  }
221

×
UNCOV
222
  return pos;
×
223
};
224

225
export const find = <T>(array: T[], checker: (val: T) => boolean): T | null => {
5!
226
  for (const val of array) {
4✔
227
    if (checker(val)) {
2✔
228
      return val;
2✔
229
    }
230
  }
231

1✔
232
  return null;
1✔
233
};
234

235
export const findRight = <T>(array: T[], checker: (val: T) => boolean): T | null => {
5!
UNCOV
236
  for (let idx = array.length - 1; idx >= 0; idx--) {
×
237
    const val = array[idx];
238
    if (checker(val)) {
×
UNCOV
239
      return val;
×
240
    }
241
  }
1✔
242

1✔
243
  return null;
×
244
};
245

×
246
export const findIndex = <T>(array: T[], checker: (val: T) => boolean): number => {
5✔
247
  for (let idx = 0; idx < array.length; idx++) {
248
    if (checker(array[idx])) {
×
249
      return idx;
×
250
    }
251
  }
1✔
252

1✔
UNCOV
253
  return -1;
×
254
};
×
255

256
export const getProgress = (pos: number, prev: number, next: number) => (pos - prev) / (next - prev);
16✔
257

258
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
259
export const getStyle = (el: HTMLElement): CSSStyleDeclaration => window.getComputedStyle(el) || (el as any).currentStyle as CSSStyleDeclaration;
82!
260

1✔
261
export const setSize = (el: HTMLElement, { width, height }: Partial<{
6✔
262
  width: number | string;
1✔
263
  height: number | string;
264
}>) => {
12!
265
  if (width != null) {
1!
266
    if (isString(width)) {
1!
UNCOV
267
      el.style.width = width;
×
268
    } else {
×
UNCOV
269
      el.style.width = `${width}px`;
×
270
    }
271
  }
272
  if (height != null) {
×
UNCOV
273
    if (isString(height)) {
×
274
      el.style.height = height;
275
    } else {
UNCOV
276
      el.style.height = `${height}px`;
×
277
    }
×
278
  }
279
};
280

281
export const isBetween = (val: number, min: number, max: number) => val >= min && val <= max;
5!
282

283
export const circulateIndex = (index: number, max: number): number => {
5✔
284
  if (index >= max) {
×
285
    return index % max;
1✔
286
  } else if (index < 0) {
1!
287
    return getMinusCompensatedIndex((index + 1) % max - 1, max);
1✔
288
  } else {
1✔
UNCOV
289
    return index;
×
290
  }
291
};
292

×
293
export const range = (end: number): number[] => {
5✔
294
  const arr = new Array(end);
295

UNCOV
296
  for (let i = 0; i < end; i++) {
×
297
    arr[i] = i;
298
  }
299

1✔
300
  return arr;
1✔
301
};
302

303
export const getElementSize = ({
5✔
304
  el,
136✔
305
  horizontal,
136✔
306
  useFractionalSize,
136✔
307
  useOffset,
137✔
308
  style
137✔
309
}: {
14✔
310
  el: HTMLElement;
14✔
311
  horizontal: boolean;
14!
312
  useFractionalSize: boolean;
×
313
  useOffset: boolean;
314
  style: CSSStyleDeclaration;
×
315
}): number => {
×
316
  let size = 0;
136!
317
  if (useFractionalSize) {
136!
UNCOV
318
    const baseSize = parseFloat(horizontal ? style.width : style.height) || 0;
×
319
    const isBorderBoxSizing = style.boxSizing === "border-box";
320
    const border = horizontal
×
321
      ? parseFloat(style.borderLeftWidth || "0") + parseFloat(style.borderRightWidth || "0")
×
322
      : parseFloat(style.borderTopWidth || "0") + parseFloat(style.borderBottomWidth || "0");
×
323

×
324
    if (isBorderBoxSizing) {
×
325
      size = useOffset
×
326
        ? baseSize
×
327
        : baseSize - border;
328
    } else {
329
      const padding = horizontal
×
330
        ? parseFloat(style.paddingLeft || "0") + parseFloat(style.paddingRight || "0")
×
331
        : parseFloat(style.paddingTop || "0") + parseFloat(style.paddingBottom || "0");
×
332

14✔
333
      size = useOffset
14!
334
        ? baseSize + padding + border
335
        : baseSize + padding;
336
    }
337
  } else {
14✔
338
    const sizeStr = horizontal ? "Width" : "Height";
136✔
339

1✔
340
    size = useOffset
137!
341
      ? el[`offset${sizeStr}`]
342
      : el[`client${sizeStr}`];
343
  }
344

345
  return Math.max(size, 0);
136✔
346
};
347

348
export const setPrototypeOf = Object.setPrototypeOf || ((obj, proto) => {
5!
349
  obj.__proto__ = proto;
350
  return obj;
351
});
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

© 2026 Coveralls, Inc