Skip to content

Commit

Permalink
improve(clone) Add clone component
Browse files Browse the repository at this point in the history
  • Loading branch information
berndartmueller committed Apr 16, 2020
1 parent a7dc15c commit 78e9710
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 44 deletions.
164 changes: 164 additions & 0 deletions src/components/clone/clone.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { addClass, append, before, remove, removeAttribute } from '../../utils/dom';
import TrackComponent from '../track/track.component';
import VirtualComponent from '../virtual/virtual.component';
import { LOOP } from './../../constants/types';
import { Event } from './../../core/event';
import VirtualSwiper, { VirtualSwiperComponents, VirtualSwiperOptions } from './../../virtual-swiper';
import { BaseComponent } from './../base-component';
import { SlideComponent } from './../virtual/slide.component';

export default class CloneComponent implements BaseComponent {
/**
* Store information of clones.
*/
private _clonesBefore: SlideComponent[] = [];
private _clonesAfter: SlideComponent[] = [];

private swiperInstance: VirtualSwiper;
private virtual: VirtualComponent;
private track: TrackComponent;

constructor(private options: VirtualSwiperOptions) {}

mount(instance: VirtualSwiper, components: VirtualSwiperComponents) {
this.swiperInstance = instance;
this.virtual = components.Virtual as VirtualComponent;
this.track = components.Track as TrackComponent;

if (this.swiperInstance.is(LOOP)) {
this.generateClones();

Event.on('refresh', () => {
this.destroy();
this.generateClones();
});

Event.on('move', () => {
this.generateClones();
});
}
}

/**
* Destroy.
*/
destroy() {
remove(this.clones.map(clone => clone.slide));

this._clonesBefore = [];
this._clonesAfter = [];
}

/**
* Return all clones.
*
* @return {Element[]} - Cloned elements.
*/
get clones() {
return [...this._clonesBefore, ...this._clonesAfter];
}

/**
* Return clone length.
*
* @return {number} - A length of clones.
*/
get length() {
return this.clones.length;
}

/**
* Return before clone length.
*
* @return {number} - A length of before clones.
*/
get lengthBefore() {
return this._clonesBefore.length;
}

/**
* Return after clone length.
*
* @return {number} - A length of after clones.
*/
get lengthAfter() {
return this._clonesAfter.length;
}

private generateClones() {
const length = this.virtual.length;

if (!length) {
return;
}

const count = this.getCloneCount();
let slides = this.virtual.getSlides();

while (slides.length < count) {
slides = slides.concat(slides);
}

const currentIndex = this.swiperInstance.index;

if (currentIndex > 0 && this.lengthAfter === 0) {
slides.slice(0, count).forEach((slide, index) => {
const clone = this.cloneDeeply(slide);

append(this.track.list, clone);

const slideClone = this.virtual.register(clone, index + length, index);

this._clonesAfter.push(slideClone);
});
}

if (this.lengthBefore === 0) {
slides.slice(-count).forEach((elm, index) => {
const clone = this.cloneDeeply(elm);

before(clone, slides[0].slide);

const slideClone = this.virtual.register(clone, index - count, index);

this._clonesBefore.push(slideClone);
});
}
}

/**
* Return half count of clones to be generated.
* Clone count is determined by:
* - Max pages a flick action can move.
* - Whether the slide length is enough for perPage.
*
* @return {number} - Count for clones.
*/
private getCloneCount() {
const options = this.options;

if (options.autoWidth) {
return this.virtual.length;
}

return options.perPage * (options.drag ? options.flickMaxPages : 1);
}

/**
* Clone deeply the given element.
*
* @param slide - An element being duplicated.
*
* @return {Node} - A cloned node(element).
*/
private cloneDeeply(slide: SlideComponent): HTMLElement {
const clone = slide.slide.cloneNode(true) as HTMLElement;

addClass(clone, this.swiperInstance.classes.clone);

// ID should not be duplicated.
removeAttribute(clone, 'id');

return clone as HTMLElement;
}
}
2 changes: 1 addition & 1 deletion src/components/layout/directions/horizontal-layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class HorizontalLayout extends BaseLayout {
*/
totalWidth(index: number): number {
return this.virtual
.getSlides()
.getSlides(true)
.filter(slide => slide.index <= index)
.reduce((accumulator, slide) => {
return accumulator + this.slideWidth(slide.index) + this.gap;
Expand Down
2 changes: 1 addition & 1 deletion src/components/track/directions/horizontal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class HorizontalDirection {
position = between(position, this.layout.totalWidth(this.virtual.total), 0);
}

const slides = this.virtual.getSlides();
const slides = this.virtual.getSlides(true);

for (const i in slides) {
const slide = slides[i];
Expand Down
4 changes: 2 additions & 2 deletions src/components/virtual/slide.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ export class SlideComponent implements BaseComponent {
/**
* Container element if available.
*/
container: Element;
container: HTMLElement;

/**
* Whether this is a cloned slide or not.
*/
private isClone: boolean;
isClone: boolean;

/**
* Hold the original styles.
Expand Down
44 changes: 26 additions & 18 deletions src/components/virtual/virtual.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,37 @@ export default class VirtualComponent implements BaseComponent {
return this.virtualSlides.filter((slide, slideIndex) => slideIndex === index)[0];
}

getSlides() {
return this.virtualSlides;
/**
* Return all Slide objects.
*
* @param includeClones - Whether to include cloned slides or not.
* @return Slide objects.
*/
getSlides(includeClones: boolean = false): SlideComponent[] {
return includeClones ? this.virtualSlides : this.virtualSlides.filter(slide => !slide.isClone);
}

each(callback: (slide: SlideComponent) => void) {
this.virtualSlides.forEach(callback);
}

/**
* Register a slide to create a Slide object and handle its behavior.
*
* @param slide - A slide element.
* @param index - A unique index. This can be negative.
* @param realIndex - A real index for clones. Set -1 for real slides.
*/
register(slide: HTMLElement, index: number, realIndex: number) {
const slideInstance = new SlideComponent(this.options, index, realIndex, slide);

slideInstance.mount(this.swiperInstance, { Track: this.track });

this.virtualSlides.push(slideInstance);

return slideInstance;
}

private init() {
this.virtualSlides = [];

Expand All @@ -53,27 +76,12 @@ export default class VirtualComponent implements BaseComponent {
this.slides = this.options.slides;
}

this.slides.slice(0, 4).forEach((slide, index) => {
this.slides.slice(0, 2).forEach((slide, index) => {
const node = domify(`<div class='vswiper-slide'>${slide}</div>`);

append(this.track.list, node);

this.register(node, index, -1);
});
}

/**
* Register a slide to create a Slide object and handle its behavior.
*
* @param slide - A slide element.
* @param index - A unique index. This can be negative.
* @param realIndex - A real index for clones. Set -1 for real slides.
*/
private register(slide: HTMLElement, index: number, realIndex: number) {
const slideInstance = new SlideComponent(this.options, index, realIndex, slide);

slideInstance.mount(this.swiperInstance, { Track: this.track });

this.virtualSlides.push(slideInstance);
}
}
Loading

0 comments on commit 78e9710

Please sign in to comment.