@egjs/flicking 4.3.0 → 4.4.2

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.
Files changed (78) hide show
  1. package/README.md +1 -2
  2. package/declaration/Flicking.d.ts +23 -11
  3. package/declaration/camera/Camera.d.ts +3 -2
  4. package/declaration/camera/CircularCamera.d.ts +2 -1
  5. package/declaration/const/error.d.ts +3 -1
  6. package/declaration/const/external.d.ts +5 -0
  7. package/declaration/core/AutoResizer.d.ts +13 -0
  8. package/declaration/core/VirtualManager.d.ts +37 -0
  9. package/declaration/core/index.d.ts +2 -1
  10. package/declaration/core/panel/Panel.d.ts +13 -7
  11. package/declaration/core/panel/VirtualPanel.d.ts +19 -0
  12. package/declaration/core/panel/index.d.ts +4 -4
  13. package/declaration/core/panel/provider/ElementProvider.d.ts +8 -0
  14. package/declaration/core/panel/provider/VanillaElementProvider.d.ts +12 -0
  15. package/declaration/core/panel/provider/VirtualElementProvider.d.ts +15 -0
  16. package/declaration/core/panel/provider/index.d.ts +5 -0
  17. package/declaration/index.d.ts +11 -1
  18. package/declaration/renderer/ExternalRenderer.d.ts +1 -1
  19. package/declaration/renderer/Renderer.d.ts +17 -12
  20. package/declaration/renderer/VanillaRenderer.d.ts +2 -7
  21. package/declaration/renderer/index.d.ts +1 -0
  22. package/declaration/renderer/strategy/NormalRenderingStrategy.d.ts +23 -0
  23. package/declaration/renderer/strategy/RenderingStrategy.d.ts +15 -0
  24. package/declaration/renderer/strategy/VirtualRenderingStrategy.d.ts +17 -0
  25. package/declaration/renderer/strategy/index.d.ts +5 -0
  26. package/declaration/utils.d.ts +7 -1
  27. package/dist/flicking.esm.js +1401 -421
  28. package/dist/flicking.esm.js.map +1 -1
  29. package/dist/flicking.js +1429 -425
  30. package/dist/flicking.js.map +1 -1
  31. package/dist/flicking.min.js +2 -2
  32. package/dist/flicking.min.js.map +1 -1
  33. package/dist/flicking.pkgd.js +8683 -8061
  34. package/dist/flicking.pkgd.js.map +1 -1
  35. package/dist/flicking.pkgd.min.js +2 -2
  36. package/dist/flicking.pkgd.min.js.map +1 -1
  37. package/package.json +9 -22
  38. package/src/Flicking.ts +146 -30
  39. package/src/camera/BoundCamera.ts +2 -2
  40. package/src/camera/Camera.ts +50 -27
  41. package/src/camera/CircularCamera.ts +52 -27
  42. package/src/camera/LinearCamera.ts +1 -1
  43. package/src/cfc/sync.ts +10 -5
  44. package/src/const/error.ts +6 -3
  45. package/src/const/external.ts +6 -0
  46. package/src/control/AxesController.ts +11 -6
  47. package/src/control/Control.ts +6 -6
  48. package/src/control/FreeControl.ts +2 -2
  49. package/src/control/SnapControl.ts +3 -3
  50. package/src/control/StrictControl.ts +2 -2
  51. package/src/core/AutoResizer.ts +81 -0
  52. package/src/core/Viewport.ts +4 -4
  53. package/src/core/VirtualManager.ts +188 -0
  54. package/src/core/index.ts +3 -1
  55. package/src/core/panel/Panel.ts +54 -34
  56. package/src/core/panel/VirtualPanel.ts +110 -0
  57. package/src/core/panel/index.ts +5 -7
  58. package/src/core/panel/provider/ElementProvider.ts +14 -0
  59. package/src/core/panel/provider/VanillaElementProvider.ts +45 -0
  60. package/src/core/panel/provider/VirtualElementProvider.ts +48 -0
  61. package/src/core/panel/provider/index.ts +16 -0
  62. package/src/index.ts +12 -1
  63. package/src/index.umd.ts +2 -0
  64. package/src/renderer/ExternalRenderer.ts +7 -7
  65. package/src/renderer/Renderer.ts +106 -65
  66. package/src/renderer/VanillaRenderer.ts +28 -86
  67. package/src/renderer/index.ts +2 -0
  68. package/src/renderer/strategy/NormalRenderingStrategy.ts +106 -0
  69. package/src/renderer/strategy/RenderingStrategy.ts +21 -0
  70. package/src/renderer/strategy/VirtualRenderingStrategy.ts +110 -0
  71. package/src/renderer/strategy/index.ts +17 -0
  72. package/src/utils.ts +36 -2
  73. package/declaration/core/panel/ElementPanel.d.ts +0 -14
  74. package/declaration/core/panel/ExternalPanel.d.ts +0 -9
  75. package/declaration/exports.d.ts +0 -10
  76. package/src/core/panel/ElementPanel.ts +0 -52
  77. package/src/core/panel/ExternalPanel.ts +0 -32
  78. package/src/exports.ts +0 -16
package/src/index.umd.ts CHANGED
@@ -9,6 +9,7 @@ import * as Control from "./control";
9
9
  import * as Renderer from "./renderer";
10
10
  import * as Constants from "./const/external";
11
11
  import * as CFC from "./cfc";
12
+ import * as Utils from "./utils";
12
13
  import { merge } from "./utils";
13
14
 
14
15
  merge(Flicking, Core);
@@ -17,5 +18,6 @@ merge(Flicking, Control);
17
18
  merge(Flicking, Renderer);
18
19
  merge(Flicking, Constants);
19
20
  merge(Flicking, CFC);
21
+ merge(Flicking, Utils);
20
22
 
21
23
  export default Flicking;
@@ -7,18 +7,18 @@ import Panel from "../core/panel/Panel";
7
7
  import Renderer from "./Renderer";
8
8
 
9
9
  /**
10
- *
10
+ * @internal
11
11
  */
12
12
  abstract class ExternalRenderer extends Renderer {
13
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
14
- protected _insertPanelElements(panels: Panel[], nextSibling: Panel | null): void {
15
- // DO NOTHING
13
+ /* eslint-disable @typescript-eslint/no-unused-vars */
14
+ protected _removePanelElements(panels: Panel[]): void {
15
+ // DO NOTHING, overrided to prevent an unexpected error
16
16
  }
17
17
 
18
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
19
- protected _removePanelElements(panels: Panel[]): void {
20
- // DO NOTHING
18
+ protected _removeAllChildsFromCamera(): void {
19
+ // DO NOTHING, overrided to prevent an unexpected error
21
20
  }
21
+ /* eslint-enable @typescript-eslint/no-unused-vars */
22
22
  }
23
23
 
24
24
  export default ExternalRenderer;
@@ -10,10 +10,13 @@ import Panel, { PanelOptions } from "../core/panel/Panel";
10
10
  import FlickingError from "../core/FlickingError";
11
11
  import { ALIGN, EVENTS } from "../const/external";
12
12
  import * as ERROR from "../const/error";
13
- import { getFlickingAttached, getMinusCompensatedIndex, includes } from "../utils";
13
+ import { getFlickingAttached, getMinusCompensatedIndex, includes, parsePanelAlign } from "../utils";
14
+
15
+ import RenderingStrategy from "./strategy/RenderingStrategy";
14
16
 
15
17
  export interface RendererOptions {
16
- align: FlickingOptions["align"];
18
+ align?: FlickingOptions["align"];
19
+ strategy: RenderingStrategy;
17
20
  }
18
21
 
19
22
  /**
@@ -26,7 +29,8 @@ abstract class Renderer {
26
29
  protected _panels: Panel[];
27
30
 
28
31
  // Options
29
- protected _align: RendererOptions["align"];
32
+ protected _align: NonNullable<RendererOptions["align"]>;
33
+ protected _strategy: RendererOptions["strategy"];
30
34
 
31
35
  // Internal states Getter
32
36
  /**
@@ -44,6 +48,10 @@ abstract class Renderer {
44
48
  * @readonly
45
49
  */
46
50
  public get panelCount() { return this._panels.length; }
51
+ /**
52
+ * @internal
53
+ */
54
+ public get strategy() { return this._strategy; }
47
55
 
48
56
  // Options Getter
49
57
  /**
@@ -54,25 +62,28 @@ abstract class Renderer {
54
62
  public get align() { return this._align; }
55
63
 
56
64
  // Options Setter
57
- public set align(val: RendererOptions["align"]) {
65
+ public set align(val: NonNullable<RendererOptions["align"]>) {
58
66
  this._align = val;
59
67
 
60
- const panelAlign = this._getPanelAlign();
68
+ const panelAlign = parsePanelAlign(val);
61
69
  this._panels.forEach(panel => { panel.align = panelAlign; });
62
70
  }
63
71
 
64
72
  /**
65
73
  * @param {object} options An options object<ko>옵션 오브젝트</ko>
66
- * @param {Constants.ALIGN | string | number} [options.align] An {@link Flicking#align align} value that will be applied to all panels<ko>전체 패널에 적용될 {@link Flicking#align align} 값</ko>
74
+ * @param {Constants.ALIGN | string | number} [options.align="center"] An {@link Flicking#align align} value that will be applied to all panels<ko>전체 패널에 적용될 {@link Flicking#align align} 값</ko>
75
+ * @param {object} [options.strategy] An instance of RenderingStrategy(internal module)<ko>RenderingStrategy의 인스턴스(내부 모듈)</ko>
67
76
  */
68
77
  public constructor({
69
- align = ALIGN.CENTER
70
- }: Partial<RendererOptions> = {}) {
78
+ align = ALIGN.CENTER,
79
+ strategy
80
+ }: RendererOptions) {
71
81
  this._flicking = null;
72
82
  this._panels = [];
73
83
 
74
84
  // Bind options
75
85
  this._align = align;
86
+ this._strategy = strategy;
76
87
  }
77
88
 
78
89
  /**
@@ -87,12 +98,9 @@ abstract class Renderer {
87
98
  * @return {this}
88
99
  */
89
100
  public abstract render(): Promise<void>;
90
- public abstract forceRenderAllPanels(): Promise<void>;
91
101
 
92
102
  protected abstract _collectPanels(): void;
93
- protected abstract _createPanel(el: any, options: PanelOptions): Panel;
94
- protected abstract _insertPanelElements(panels: Panel[], nextSibling: Panel | null): void;
95
- protected abstract _removePanelElements(panels: Panel[]): void;
103
+ protected abstract _createPanel(el: any, options: Omit<PanelOptions, "elementProvider">): Panel;
96
104
 
97
105
  /**
98
106
  * Initialize Renderer
@@ -128,6 +136,12 @@ abstract class Renderer {
128
136
  return this._panels[index] || null;
129
137
  }
130
138
 
139
+ public forceRenderAllPanels(): Promise<void> {
140
+ this._panels.forEach(panel => panel.markForShow());
141
+
142
+ return Promise.resolve();
143
+ }
144
+
131
145
  /**
132
146
  * Update all panel sizes
133
147
  * @ko 모든 패널의 크기를 업데이트합니다
@@ -135,10 +149,16 @@ abstract class Renderer {
135
149
  * @return {this}
136
150
  */
137
151
  public updatePanelSize(): this {
138
- const flicking = getFlickingAttached(this._flicking, "Renderer");
152
+ const flicking = getFlickingAttached(this._flicking);
153
+ const panels = this._panels;
154
+
155
+ if (panels.length <= 0) return this;
139
156
 
140
157
  if (flicking.panelsPerView > 0) {
141
- this._updatePanelSizeByGrid(flicking);
158
+ const firstPanel = panels[0];
159
+ firstPanel.resize();
160
+
161
+ this._updatePanelSizeByGrid(firstPanel, panels);
142
162
  } else {
143
163
  flicking.panels.forEach(panel => panel.resize());
144
164
  }
@@ -151,19 +171,23 @@ abstract class Renderer {
151
171
  * This will increase index of panels after by the number of panels added
152
172
  * @ko 주어진 인덱스에 새로운 패널들을 추가합니다
153
173
  * 해당 인덱스보다 같거나 큰 인덱스를 가진 기존 패널들은 추가한 패널의 개수만큼 인덱스가 증가합니다.
154
- * @param {number} index Index to insert new panels at<ko>새로 패널들을 추가할 인덱스</ko>
155
- * @param {any[]} elements An array of element or framework component with element in it<ko>엘리먼트의 배열 혹은 프레임워크에서 엘리먼트를 포함한 컴포넌트들의 배열</ko>
174
+ * @param {Array<object>} items An array of items to insert<ko>추가할 아이템들의 배열</ko>
175
+ * @param {number} [items.index] Index to insert new panels at<ko>새로 패널들을 추가할 인덱스</ko>
176
+ * @param {any[]} [items.elements] An array of element or framework component with element in it<ko>엘리먼트의 배열 혹은 프레임워크에서 엘리먼트를 포함한 컴포넌트들의 배열</ko>
177
+ * @param {boolean} [items.hasDOMInElements] Whether it contains actual DOM elements. If set to true, renderer will add them to the camera element<ko>내부에 실제 DOM 엘리먼트들을 포함하고 있는지 여부. true로 설정할 경우, 렌더러는 해당 엘리먼트들을 카메라 엘리먼트 내부에 추가합니다</ko>
156
178
  * @return {Panel[]} An array of prepended panels<ko>추가된 패널들의 배열</ko>
157
179
  */
158
180
  public batchInsert(...items: Array<{
159
181
  index: number;
160
182
  elements: any[];
183
+ hasDOMInElements: boolean;
161
184
  }>): Panel[] {
162
185
  const panels = this._panels;
163
- const flicking = getFlickingAttached(this._flicking, "Renderer");
186
+ const flicking = getFlickingAttached(this._flicking);
164
187
 
165
188
  const { control } = flicking;
166
- const align = this._getPanelAlign();
189
+ const prevFirstPanel = panels[0];
190
+ const align = parsePanelAlign(this._align);
167
191
 
168
192
  const allPanelsInserted = items.reduce((addedPanels, item) => {
169
193
  const insertingIdx = getMinusCompensatedIndex(item.index, panels.length);
@@ -172,11 +196,19 @@ abstract class Renderer {
172
196
 
173
197
  panels.splice(insertingIdx, 0, ...panelsInserted);
174
198
 
175
- // Insert the actual elements as camera element's children
176
- this._insertPanelElements(panelsInserted, panelsPushed[0] ?? null);
199
+ if (item.hasDOMInElements) {
200
+ // Insert the actual elements as camera element's children
201
+ this._insertPanelElements(panelsInserted, panelsPushed[0] ?? null);
202
+ }
177
203
 
178
204
  // Resize the newly added panels
179
- panelsInserted.forEach(panel => panel.resize());
205
+ if (flicking.panelsPerView > 0) {
206
+ const firstPanel = prevFirstPanel || panelsInserted[0].resize();
207
+
208
+ this._updatePanelSizeByGrid(firstPanel, panelsInserted);
209
+ } else {
210
+ panelsInserted.forEach(panel => panel.resize());
211
+ }
180
212
 
181
213
  // Update panel indexes & positions
182
214
  panelsPushed.forEach(panel => {
@@ -219,13 +251,15 @@ abstract class Renderer {
219
251
  * This will decrease index of panels after by the number of panels removed
220
252
  * @ko 주어진 인덱스의 패널을 제거합니다
221
253
  * 해당 인덱스보다 큰 인덱스를 가진 기존 패널들은 제거한 패널의 개수만큼 인덱스가 감소합니다
222
- * @param {number} index Index of panel to remove<ko>제거할 패널의 인덱스</ko>
223
- * @param {number} [deleteCount=1] Number of panels to remove from index<ko>`index` 이후로 제거할 패널의 개수</ko>
254
+ * @param {Array<object>} items An array of items to remove<ko>제거할 아이템들의 배열</ko>
255
+ * @param {number} [items.index] Index of panel to remove<ko>제거할 패널의 인덱스</ko>
256
+ * @param {number} [items.deleteCount=1] Number of panels to remove from index<ko>`index` 이후로 제거할 패널의 개수</ko>
257
+ * @param {boolean} [items.hasDOMInElements=1] Whether it contains actual DOM elements. If set to true, renderer will remove them from the camera element<ko>내부에 실제 DOM 엘리먼트들을 포함하고 있는지 여부. true로 설정할 경우, 렌더러는 해당 엘리먼트들을 카메라 엘리먼트 내부에서 제거합니다</ko>
224
258
  * @return An array of removed panels<ko>제거된 패널들의 배열</ko>
225
259
  */
226
- public batchRemove(...items: Array<{ index: number; deleteCount: number }>): Panel[] {
260
+ public batchRemove(...items: Array<{ index: number; deleteCount: number; hasDOMInElements: boolean }>): Panel[] {
227
261
  const panels = this._panels;
228
- const flicking = getFlickingAttached(this._flicking, "Renderer");
262
+ const flicking = getFlickingAttached(this._flicking);
229
263
 
230
264
  const { camera, control } = flicking;
231
265
  const activePanel = control.activePanel;
@@ -246,14 +280,13 @@ abstract class Renderer {
246
280
  panel.updatePosition();
247
281
  });
248
282
 
249
- this._removePanelElements(panelsRemoved);
283
+ if (item.hasDOMInElements) {
284
+ this._removePanelElements(panelsRemoved);
285
+ }
250
286
 
251
287
  // Remove panel elements
252
288
  panelsRemoved.forEach(panel => panel.destroy());
253
289
 
254
- // Update camera & control
255
- this._updateCameraAndControl();
256
-
257
290
  if (includes(panelsRemoved, activePanel)) {
258
291
  control.resetActive();
259
292
  }
@@ -261,6 +294,9 @@ abstract class Renderer {
261
294
  return [...removed, ...panelsRemoved];
262
295
  }, []);
263
296
 
297
+ // Update camera & control
298
+ this._updateCameraAndControl();
299
+
264
300
  void this.render();
265
301
 
266
302
  // FIXME: fix for animating case
@@ -293,10 +329,11 @@ abstract class Renderer {
293
329
  * @internal
294
330
  */
295
331
  public checkPanelContentsReady(checkingPanels: Panel[]) {
296
- const resizeOnContentsReady = getFlickingAttached(this._flicking, "Renderer").resizeOnContentsReady;
332
+ const flicking = getFlickingAttached(this._flicking);
333
+ const resizeOnContentsReady = flicking.resizeOnContentsReady;
297
334
  const panels = this._panels;
298
335
 
299
- if (!resizeOnContentsReady) return;
336
+ if (!resizeOnContentsReady || flicking.virtualEnabled) return;
300
337
 
301
338
  const hasContents = (panel: Panel) => !!panel.element.querySelector("img, video");
302
339
  checkingPanels = checkingPanels.filter(panel => hasContents(panel));
@@ -310,9 +347,7 @@ abstract class Renderer {
310
347
  });
311
348
 
312
349
  contentsReadyChecker.on("readyElement", e => {
313
- const flicking = this._flicking;
314
-
315
- if (!flicking) {
350
+ if (!this._flicking) {
316
351
  // Renderer's destroy() is called before
317
352
  contentsReadyChecker.destroy();
318
353
  return;
@@ -362,16 +397,8 @@ abstract class Renderer {
362
397
  contentsReadyChecker.check(checkingPanels.map(panel => panel.element));
363
398
  }
364
399
 
365
- protected _getPanelAlign() {
366
- const align = this._align;
367
-
368
- return typeof align === "object"
369
- ? (align as { panel: string | number }).panel
370
- : align;
371
- }
372
-
373
400
  protected _updateCameraAndControl() {
374
- const flicking = getFlickingAttached(this._flicking, "Renderer");
401
+ const flicking = getFlickingAttached(this._flicking);
375
402
  const { camera, control } = flicking;
376
403
 
377
404
  camera.updateRange();
@@ -380,16 +407,6 @@ abstract class Renderer {
380
407
  control.updateInput();
381
408
  }
382
409
 
383
- protected _updateRenderingPanels(): void {
384
- const flicking = getFlickingAttached(this._flicking, "Renderer");
385
-
386
- if (flicking.renderOnlyVisible) {
387
- this._showOnlyVisiblePanels(flicking);
388
- } else {
389
- flicking.panels.forEach(panel => panel.markForShow());
390
- }
391
- }
392
-
393
410
  protected _showOnlyVisiblePanels(flicking: Flicking) {
394
411
  const panels = flicking.renderer.panels;
395
412
  const camera = flicking.camera;
@@ -408,12 +425,10 @@ abstract class Renderer {
408
425
  panel.markForHide();
409
426
  }
410
427
  });
411
-
412
- camera.updateOffset();
413
428
  }
414
429
 
415
- protected _updatePanelSizeByGrid(flicking: Flicking) {
416
- const panels = flicking.panels;
430
+ protected _updatePanelSizeByGrid(referencePanel: Panel, panels: Panel[]) {
431
+ const flicking = getFlickingAttached(this._flicking);
417
432
  const panelsPerView = flicking.panelsPerView;
418
433
 
419
434
  if (panelsPerView <= 0) {
@@ -421,12 +436,8 @@ abstract class Renderer {
421
436
  }
422
437
  if (panels.length <= 0) return;
423
438
 
424
- // resize only the first panel
425
- const firstPanel = panels[0];
426
- firstPanel.resize();
427
-
428
439
  const viewportSize = flicking.camera.size;
429
- const gap = firstPanel.margin.prev + firstPanel.margin.next;
440
+ const gap = referencePanel.margin.prev + referencePanel.margin.next;
430
441
 
431
442
  const panelSize = (viewportSize - gap * (panelsPerView - 1)) / panelsPerView;
432
443
  const panelSizeObj = flicking.horizontal
@@ -434,16 +445,46 @@ abstract class Renderer {
434
445
  : { height: panelSize };
435
446
  const firstPanelSizeObj = {
436
447
  size: panelSize,
437
- height: firstPanel.height,
438
- margin: firstPanel.margin
448
+ height: referencePanel.height,
449
+ margin: referencePanel.margin
439
450
  };
440
451
 
441
452
  if (!flicking.noPanelStyleOverride) {
442
- flicking.panels.forEach(panel => panel.setSize(panelSizeObj));
453
+ this._strategy.updatePanelSizes(flicking, panelSizeObj);
443
454
  }
444
455
 
445
456
  flicking.panels.forEach(panel => panel.resize(firstPanelSizeObj));
446
457
  }
458
+
459
+ protected _removeAllChildsFromCamera() {
460
+ const flicking = getFlickingAttached(this._flicking);
461
+ const cameraElement = flicking.camera.element;
462
+
463
+ // Remove other elements
464
+ while (cameraElement.firstChild) {
465
+ cameraElement.removeChild(cameraElement.firstChild);
466
+ }
467
+ }
468
+
469
+ protected _insertPanelElements(panels: Panel[], nextSibling: Panel | null = null) {
470
+ const flicking = getFlickingAttached(this._flicking);
471
+ const camera = flicking.camera;
472
+ const cameraElement = camera.element;
473
+ const nextSiblingElement = nextSibling?.element || null;
474
+ const fragment = document.createDocumentFragment();
475
+
476
+ panels.forEach(panel => fragment.appendChild(panel.element));
477
+ cameraElement.insertBefore(fragment, nextSiblingElement);
478
+ }
479
+
480
+ protected _removePanelElements(panels: Panel[]) {
481
+ const flicking = getFlickingAttached(this._flicking);
482
+ const cameraElement = flicking.camera.element;
483
+
484
+ panels.forEach(panel => {
485
+ cameraElement.removeChild(panel.element);
486
+ });
487
+ }
447
488
  }
448
489
 
449
490
  export default Renderer;
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import { getFlickingAttached, toArray } from "../utils";
6
6
  import Panel, { PanelOptions } from "../core/panel/Panel";
7
- import ElementPanel from "../core/panel/ElementPanel";
8
7
 
9
8
  import Renderer from "./Renderer";
10
9
 
@@ -14,112 +13,55 @@ import Renderer from "./Renderer";
14
13
  class VanillaRenderer extends Renderer {
15
14
  // eslint-disable-next-line @typescript-eslint/require-await
16
15
  public async render() {
17
- const flicking = getFlickingAttached(this._flicking, "Renderer");
18
- const cameraEl = flicking.camera.element;
19
- const wasRenderedPanels = this._panels.filter(panel => panel.element.parentElement === cameraEl);
20
-
21
- this._updateRenderingPanels();
22
- const renderingPanels = this._getRenderingPanelsByOrder();
23
-
24
- this._removePanelElements(wasRenderedPanels.filter(panel => !panel.rendered));
25
- this._insertPanelElements(renderingPanels.filter(panel => panel.element.parentElement !== cameraEl), null);
26
- this._resetPanelElementOrder(renderingPanels);
27
- }
28
-
29
- // eslint-disable-next-line @typescript-eslint/require-await
30
- public async forceRenderAllPanels() {
31
- const flicking = getFlickingAttached(this._flicking, "Renderer");
32
- const camera = flicking.camera;
33
- const cameraElement = camera.element;
34
- const fragment = document.createDocumentFragment();
35
-
36
- this._panels.forEach(panel => fragment.appendChild(panel.element));
16
+ const flicking = getFlickingAttached(this._flicking);
17
+ const strategy = this._strategy;
37
18
 
38
- this._removeAllChildsFromCamera();
19
+ strategy.updateRenderingPanels(flicking);
20
+ strategy.renderPanels(flicking);
39
21
 
40
- cameraElement.appendChild(fragment);
22
+ this._resetPanelElementOrder();
41
23
  }
42
24
 
43
25
  protected _collectPanels() {
44
- const flicking = getFlickingAttached(this._flicking, "Renderer");
45
-
46
- const cameraElement = flicking.camera.element;
47
-
48
- // Remove all text nodes in the camera element
49
- toArray(cameraElement.childNodes).forEach(node => {
50
- if (node.nodeType === Node.TEXT_NODE) {
51
- cameraElement.removeChild(node);
52
- }
53
- });
54
-
55
- const align = this._getPanelAlign();
56
- const cameraChilds = toArray(cameraElement.children);
57
-
58
- this._panels = cameraChilds.map(
59
- (el: HTMLElement, index: number) => new ElementPanel({ flicking, el, index, align })
60
- );
61
- }
62
-
63
- protected _createPanel(el: HTMLElement, options: PanelOptions): ElementPanel {
64
- return new ElementPanel({ el, ...options });
65
- }
66
-
67
- protected _insertPanelElements(panels: Panel[], nextSibling: Panel | null) {
68
- const flicking = getFlickingAttached(this._flicking, "Renderer");
26
+ const flicking = getFlickingAttached(this._flicking);
69
27
  const camera = flicking.camera;
70
- const cameraElement = camera.element;
71
- const nextSiblingElement = nextSibling?.element || null;
72
- const fragment = document.createDocumentFragment();
73
-
74
- panels.forEach(panel => fragment.appendChild(panel.element));
75
- cameraElement.insertBefore(fragment, nextSiblingElement);
76
28
 
77
- return this;
29
+ this._removeAllTextNodes();
30
+ this._panels = this._strategy.collectPanels(flicking, camera.children);
78
31
  }
79
32
 
80
- protected _removePanelElements(panels: Panel[]): this {
81
- const flicking = getFlickingAttached(this._flicking, "Renderer");
82
- const cameraElement = flicking.camera.element;
83
-
84
- panels.forEach(panel => {
85
- cameraElement.removeChild(panel.element);
86
- });
87
-
88
- return this;
33
+ protected _createPanel(el: HTMLElement, options: Omit<PanelOptions, "elementProvider">): Panel {
34
+ return this._strategy.createPanel(el, options);
89
35
  }
90
36
 
91
- private _resetPanelElementOrder(panels: Panel[]) {
92
- const flicking = getFlickingAttached(this._flicking, "Renderer");
37
+ private _resetPanelElementOrder() {
38
+ const flicking = getFlickingAttached(this._flicking);
93
39
  const cameraEl = flicking.camera.element;
94
40
 
95
41
  // We're using reversed panels here as last panel should be the last element of camera element
96
- const reversedPanels = [...panels].reverse();
97
- reversedPanels.forEach((panel, idx) => {
98
- const nextPanel = reversedPanels[idx - 1];
99
- const nextPanelEl = nextPanel ? nextPanel.element : null;
42
+ const reversedElements = this._strategy
43
+ .getRenderingElementsByOrder(flicking)
44
+ .reverse();
45
+
46
+ reversedElements.forEach((el, idx) => {
47
+ const nextEl = reversedElements[idx - 1] ? reversedElements[idx - 1] : null;
100
48
 
101
- if (panel.element.nextElementSibling !== nextPanelEl) {
102
- cameraEl.insertBefore(panel.element, nextPanelEl);
49
+ if (el.nextElementSibling !== nextEl) {
50
+ cameraEl.insertBefore(el, nextEl);
103
51
  }
104
52
  });
105
53
  }
106
54
 
107
- private _removeAllChildsFromCamera() {
108
- const flicking = getFlickingAttached(this._flicking, "Renderer");
55
+ private _removeAllTextNodes() {
56
+ const flicking = getFlickingAttached(this._flicking);
109
57
  const cameraElement = flicking.camera.element;
110
58
 
111
- // Remove other elements
112
- while (cameraElement.firstChild) {
113
- cameraElement.removeChild(cameraElement.firstChild);
114
- }
115
- }
116
-
117
- private _getRenderingPanelsByOrder(): Panel[] {
118
- const flicking = getFlickingAttached(this._flicking, "Renderer");
119
- const panels = flicking.renderer.panels;
120
-
121
- return panels.filter(panel => panel.rendered)
122
- .sort((a, b) => (a.position + a.offset) - (b.position + b.offset));
59
+ // Remove all text nodes in the camera element
60
+ toArray(cameraElement.childNodes).forEach(node => {
61
+ if (node.nodeType === Node.TEXT_NODE) {
62
+ cameraElement.removeChild(node);
63
+ }
64
+ });
123
65
  }
124
66
  }
125
67
 
@@ -6,6 +6,8 @@ import Renderer, { RendererOptions } from "./Renderer";
6
6
  import VanillaRenderer from "./VanillaRenderer";
7
7
  import ExternalRenderer from "./ExternalRenderer";
8
8
 
9
+ export * from "./strategy";
10
+
9
11
  export {
10
12
  Renderer,
11
13
  VanillaRenderer,
@@ -0,0 +1,106 @@
1
+ /*
2
+ * Copyright (c) 2015 NAVER Corp.
3
+ * egjs projects are licensed under the MIT license
4
+ */
5
+ import Flicking from "../../Flicking";
6
+ import Panel, { PanelOptions } from "../../core/panel/Panel";
7
+ import ElementProvider from "../../core/panel/provider/ElementProvider";
8
+ import { DIRECTION } from "../../const/external";
9
+ import { parsePanelAlign } from "../../utils";
10
+
11
+ import RenderingStrategy from "./RenderingStrategy";
12
+
13
+ export interface NormalRenderingStrategyOptions {
14
+ providerCtor: new (...args: any) => ElementProvider;
15
+ }
16
+
17
+
18
+ class NormalRenderingStrategy implements RenderingStrategy {
19
+ private _providerCtor: NormalRenderingStrategyOptions["providerCtor"];
20
+
21
+ public constructor({ providerCtor }: NormalRenderingStrategyOptions) {
22
+ this._providerCtor = providerCtor;
23
+ }
24
+
25
+ public renderPanels() {
26
+ // DO_NOTHING
27
+ }
28
+
29
+ public getRenderingIndexesByOrder(flicking: Flicking) {
30
+ const renderedPanels = flicking.renderer.panels.filter(panel => panel.rendered);
31
+ const toggledPrev = renderedPanels.filter(panel => panel.toggled && panel.toggleDirection === DIRECTION.PREV);
32
+ const toggledNext = renderedPanels.filter(panel => panel.toggled && panel.toggleDirection === DIRECTION.NEXT);
33
+ const notToggled = renderedPanels.filter(panel => !panel.toggled);
34
+
35
+ return [...toggledPrev, ...notToggled, ...toggledNext].map(panel => panel.index);
36
+ }
37
+
38
+ public getRenderingElementsByOrder(flicking: Flicking) {
39
+ const panels = flicking.panels;
40
+
41
+ return this.getRenderingIndexesByOrder(flicking).map(index => panels[index].element);
42
+ }
43
+
44
+ public updateRenderingPanels(flicking: Flicking) {
45
+ if (flicking.renderOnlyVisible) {
46
+ this._showOnlyVisiblePanels(flicking);
47
+ } else {
48
+ flicking.panels.forEach(panel => panel.markForShow());
49
+ }
50
+ }
51
+
52
+ public collectPanels(
53
+ flicking: Flicking,
54
+ elements: any[]
55
+ ) {
56
+ const align = parsePanelAlign(flicking.renderer.align);
57
+
58
+ return elements.map((el, index) => new Panel({
59
+ index,
60
+ elementProvider: new this._providerCtor(el),
61
+ align,
62
+ flicking
63
+ }));
64
+ }
65
+
66
+ public createPanel(
67
+ element: any,
68
+ options: Omit<PanelOptions, "elementProvider">
69
+ ) {
70
+ return new Panel({
71
+ ...options,
72
+ elementProvider: new this._providerCtor(element)
73
+ });
74
+ }
75
+
76
+ public updatePanelSizes(flicking: Flicking, size: Partial<{
77
+ width: number | string;
78
+ height: number | string;
79
+ }>) {
80
+ flicking.panels.forEach(panel => panel.setSize(size));
81
+ }
82
+
83
+ private _showOnlyVisiblePanels(flicking: Flicking) {
84
+ const panels = flicking.renderer.panels;
85
+ const camera = flicking.camera;
86
+
87
+ const visibleIndexes = camera.visiblePanels.reduce((visibles, panel) => {
88
+ visibles[panel.index] = true;
89
+ return visibles;
90
+ }, {});
91
+
92
+ panels.forEach(panel => {
93
+ if (panel.index in visibleIndexes || panel.loading) {
94
+ panel.markForShow();
95
+ } else if (!flicking.holding) {
96
+ // During the input sequence,
97
+ // Do not remove panel elements as it won't trigger touchend event.
98
+ panel.markForHide();
99
+ }
100
+ });
101
+
102
+ camera.updateOffset();
103
+ }
104
+ }
105
+
106
+ export default NormalRenderingStrategy;
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright (c) 2015 NAVER Corp.
3
+ * egjs projects are licensed under the MIT license
4
+ */
5
+ import Flicking from "../../Flicking";
6
+ import Panel, { PanelOptions } from "../../core/panel/Panel";
7
+
8
+ /**
9
+ * @internal
10
+ */
11
+ interface RenderingStrategy {
12
+ renderPanels(flicking: Flicking): void;
13
+ getRenderingIndexesByOrder(flicking: Flicking): number[];
14
+ getRenderingElementsByOrder(flicking: Flicking): HTMLElement[];
15
+ updateRenderingPanels(flicking: Flicking): void;
16
+ createPanel(element: any, options: Omit<PanelOptions, "elementProvider">): Panel;
17
+ collectPanels(flicking: Flicking, elements: any[]): Panel[];
18
+ updatePanelSizes(flicking: Flicking, size: Partial<{ width: number | string; height: number | string }>): void;
19
+ }
20
+
21
+ export default RenderingStrategy;