-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Amp slidescroll experiment - Handling Native Snapping #3798
Changes from all commits
571970c
ce21408
44933d7
9178020
a0ac984
6c0d199
530e03d
7b215b5
e7cdb31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
import {BaseCarousel} from './base-carousel'; | ||
import {Layout} from '../../../src/layout'; | ||
import {getStyle, setStyle} from '../../../src/style'; | ||
import {timer} from '../../../src/timer'; | ||
|
||
/** @const {string} */ | ||
const SHOWN_CSS_CLASS = '-amp-slide-item-show'; | ||
|
@@ -30,6 +31,9 @@ export class AmpSlideScroll extends BaseCarousel { | |
/** @private @const {!Window} */ | ||
this.win_ = this.getWin(); | ||
|
||
/** @const @private {!Vsync} */ | ||
this.vsync_ = this.getVsync(); | ||
|
||
/** @private @const {!boolean} */ | ||
this.hasNativeSnapPoints_ = ( | ||
getStyle(this.element, 'scrollSnapType') != undefined); | ||
|
@@ -38,6 +42,13 @@ export class AmpSlideScroll extends BaseCarousel { | |
/** @private {!Array<!Element>} */ | ||
this.slides_ = this.getRealChildren(); | ||
|
||
/** @private {number} */ | ||
this.noOfSlides_ = this.slides_.length; | ||
|
||
/** @private @const {boolean} */ | ||
this.hasLooping_ = | ||
this.element.hasAttribute('loop') && this.noOfSlides_ > 1; | ||
|
||
/** @private {!Element} */ | ||
this.slidesContainer_ = this.win_.document.createElement('div'); | ||
this.slidesContainer_.classList.add('-amp-slides-container'); | ||
|
@@ -67,12 +78,14 @@ export class AmpSlideScroll extends BaseCarousel { | |
|
||
this.element.appendChild(this.slidesContainer_); | ||
|
||
/** @private {number} */ | ||
this.noOfSlides_ = this.slides_.length; | ||
|
||
/** @private @const {boolean} */ | ||
this.hasLooping_ = | ||
this.element.hasAttribute('loop') && this.noOfSlides_ > 1; | ||
this.snappingInProgress_ = false; | ||
|
||
/** @private {?number}*/ | ||
this.scrollTimeout_ = null; | ||
|
||
this.slidesContainer_.addEventListener( | ||
'scroll', this.scrollHandler_.bind(this)); | ||
} | ||
|
||
/** @override */ | ||
|
@@ -99,10 +112,6 @@ export class AmpSlideScroll extends BaseCarousel { | |
} | ||
} | ||
|
||
/** @override */ | ||
setupGestures() { | ||
} | ||
|
||
/** @override */ | ||
hasPrev() { | ||
return this.hasLooping_ || this.slideIndex_ > 0; | ||
|
@@ -129,6 +138,82 @@ export class AmpSlideScroll extends BaseCarousel { | |
} | ||
} | ||
|
||
/** | ||
* Handles scroll on the slides container. | ||
* @param {!Event} unusedEvent Event object. | ||
* @private | ||
*/ | ||
scrollHandler_(unusedEvent) { | ||
if (this.scrollTimeout_) { | ||
timer.cancel(this.scrollTimeout_); | ||
} | ||
const currentScrollLeft = this.slidesContainer_./*OK*/scrollLeft; | ||
if (currentScrollLeft != this.previousScrollLeft_ && | ||
!this.hasNativeSnapPoints_) { | ||
// TODO(sriramkrish85): Handle custom scroll here. | ||
} | ||
|
||
// Timer that detects scroll end and/or end of snap scroll. | ||
this.scrollTimeout_ = timer.delay(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add some docs as to why this delay. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done - let me know if that looks okay. |
||
if (this.snappingInProgress_) { | ||
return; | ||
} | ||
if (this.hasNativeSnapPoints_) { | ||
this.updateOnScroll_(currentScrollLeft); | ||
} | ||
}, 100); | ||
this.previousScrollLeft_ = currentScrollLeft; | ||
} | ||
|
||
|
||
/** | ||
* Updates to the right state of the new index on scroll. | ||
* @param {number} currentScrollLeft scrollLeft value of the slides container. | ||
*/ | ||
updateOnScroll_(currentScrollLeft) { | ||
this.snappingInProgress_ = true; | ||
// This can be only 0, 1 or 2, since only a max of 3 slides are shown at | ||
// a time. | ||
const scrolledSlideIndex = Math.round(currentScrollLeft / this.slideWidth_); | ||
// Update value can be -1, 0 or 1 depending upon the index of the current | ||
// shown slide. | ||
let updateValue = 0; | ||
|
||
const hasPrev_ = this.hasPrev(); | ||
const hasNext_ = this.hasNext(); | ||
|
||
if (hasPrev_ && hasNext_) { | ||
updateValue = scrolledSlideIndex - 1; | ||
} else if (hasNext_) { | ||
// Has next and does not have a prev. (slideIndex 0) | ||
updateValue = scrolledSlideIndex; | ||
} else if (hasPrev_) { | ||
// Has prev and no next slide (last slide) | ||
updateValue = scrolledSlideIndex - 1; | ||
} | ||
|
||
let newIndex = this.slideIndex_ + updateValue; | ||
|
||
if (this.hasLooping_) { | ||
newIndex = (newIndex < 0) ? this.noOfSlides_ - 1 : | ||
(newIndex >= this.noOfSlides_) ? 0 : newIndex; | ||
} else { | ||
newIndex = (newIndex < 0) ? 0 : | ||
(newIndex >= this.noOfSlides_) ? this.noOfSlides_ - 1 : newIndex; | ||
} | ||
this.vsync_.mutate(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document this nested mutate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
// Make the container non scrollable to stop scroll events. | ||
this.slidesContainer_.classList.add('no-scroll'); | ||
// Scroll to new slide and update scrollLeft to the correct slide. | ||
this.showSlide_(newIndex); | ||
this.vsync_.mutate(() => { | ||
// Make the container scrollable again to enable user swiping. | ||
this.slidesContainer_.classList.remove('no-scroll'); | ||
this.snappingInProgress_ = false; | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Makes the slide corresponding to the given index and the slides surrounding | ||
* it available for display. | ||
|
@@ -138,11 +223,10 @@ export class AmpSlideScroll extends BaseCarousel { | |
showSlide_(newIndex) { | ||
const noOfSlides_ = this.noOfSlides_; | ||
if (newIndex < 0 || | ||
newIndex >= noOfSlides_ || | ||
this.slideIndex_ == newIndex) { | ||
newIndex >= noOfSlides_ || | ||
this.slideIndex_ == newIndex) { | ||
return; | ||
} | ||
|
||
const prevIndex = (newIndex - 1 >= 0) ? newIndex - 1 : | ||
(this.hasLooping_) ? noOfSlides_ - 1 : null; | ||
const nextIndex = (newIndex + 1 < noOfSlides_) ? newIndex + 1 : | ||
|
@@ -179,6 +263,7 @@ export class AmpSlideScroll extends BaseCarousel { | |
if (!this.hasLooping_ && newIndex == 0) { | ||
newScrollLeft = 0; | ||
} | ||
|
||
this.slidesContainer_./*OK*/scrollLeft = newScrollLeft; | ||
this.slideIndex_ = newIndex; | ||
this.hideRestOfTheSlides_(showIndexArr); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already assigned to above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done