1
0
mirror of https://github.com/webslides/WebSlides.git synced 2025-08-20 03:41:38 +02:00

Finishing the core bits

This commit is contained in:
Antonio Laguna
2017-01-27 12:28:45 +01:00
parent 70bde2f4ae
commit 01fa93d50e
8 changed files with 302 additions and 14 deletions

25
src/modules/hash.js Normal file
View File

@@ -0,0 +1,25 @@
const HASH = '#slide';
const slideRegex = /#slide=(\d+)/;
export default class Hash {
static getSlideNumber() {
let results = document.location.hash.match(slideRegex);
let slide = 0;
if (Array.isArray(results)) {
slide = parseInt(results[1], 10);
}
if (!Number.isInteger(slide) || slide < 0 || !Array.isArray(results)) {
slide = null;
} else {
slide--; // Convert to 0 index
}
return slide;
}
static setSlideNumber(number) {
history.pushState(null, `Slide ${number}`, `${HASH}=${number}`);
}
}

View File

@@ -9,12 +9,12 @@ const ELEMENT_ID = {
const LABELS = {
VERTICAL: {
NEXT: '&darr;',
PREV: '&rarr;'
NEXT: '',
PREV: ''
},
HORIZONTAL: {
NEXT: '&uarr;',
PREV: '&larr;'
NEXT: '',
PREV: ''
}
};
@@ -31,7 +31,6 @@ export default class Navigation {
this.el.appendChild(this.next);
this.el.appendChild(this.prev);
this.el.appendChild(this.counter);
console.log(this);
}
updateCounter(current, max) {

46
src/modules/slide.js Normal file
View File

@@ -0,0 +1,46 @@
import DOM from '../utils/dom';
const CLASSES = {
SLIDE: 'slide',
CURRENT: 'current'
};
export default class Slide {
constructor(el, i) {
this.el = el;
this.parent = el.parentNode;
this.i = i;
this.el.id = 'section-' + (i + 1);
this.el.classList.add(CLASSES.SLIDE);
// Hide slides by default
this.hide();
}
hide() {
DOM.hide(this.el);
this.el.classList.remove(CLASSES.CURRENT);
}
show() {
DOM.show(this.el);
this.el.classList.add(CLASSES.CURRENT);
}
moveAfterLast() {
const last = this.parent.childNodes[this.parent.childElementCount - 1];
this.parent.insertBefore(this.el, last.nextSibling);
}
moveBeforeFirst() {
const first = this.parent.childNodes[0];
this.parent.insertBefore(this.el, first);
}
static isCandidate(el) {
return el.nodeType === 1 && el.tagName === 'SECTION';
}
}

View File

@@ -1,33 +1,167 @@
import Hash from './hash';
import Navigation from './navigation';
import Slide from './slide';
import DOM from '../utils/dom';
import ScrollHelper from '../utils/scroll-to';
const CLASSES = {
VERTICAL: 'vertical'
};
export default class WebSlides {
constructor() {
this.el = document.getElementById('webslides');
this.moving = false;
this.currentSlide = 0;
this.isMoving = false;
this.slides = null;
this.navigation = null;
this.currentSlideI_ = -1;
this.currentSlide_ = null;
this.maxSlide_ = 0;
this.isVertical = this.el.classList.contains(CLASSES.VERTICAL);
if (!this.el) {
throw new Error('Couldn\'t find the webslides container!');
}
this.removeChildren_();
this.grabSlides_();
this.createNav_();
this.navigation.updateCounter(this.currentSlide + 1, this.slides.length);
this.initSlides_();
window.st = ScrollHelper;
}
removeChildren_() {
const nodes = this.el.childNodes;
let i = nodes.length;
while (i--) {
const node = nodes[i];
if (!Slide.isCandidate(node)) {
this.el.removeChild(node);
}
}
}
createNav_() {
this.navigation = new Navigation({
isVertical: true
isVertical: this.isVertical
});
this.el.appendChild(this.navigation.el);
}
grabSlides_() {
this.slides = Array.from(this.el.getElementsByClassName('slide'));
this.slides = Array.from(this.el.childNodes)
.map((slide, i) => new Slide(slide, i));
this.maxSlide_ = this.slides.length;
}
goToSlide(slide) {
if (slide >= 0 && slide < this.slides.length) {
console.log('Foo');
goToSlide(slideI, forward = null) {
if (this.isValidIndexSlide_(slideI) && !this.isMoving) {
this.isMoving = true;
let isMovingForward = false;
if (forward !== null) {
isMovingForward = forward;
} else {
if (Number.isInteger(this.currentSlideI_)) {
isMovingForward = slideI > this.currentSlideI_;
}
}
const nextSlide = this.slides[slideI];
if (this.currentSlide_ !== null) {
this.animateToSlide_(isMovingForward, nextSlide, this.onSlideChange_);
} else {
this.transitionToSlide_(
isMovingForward, nextSlide, this.onSlideChange_);
nextSlide.moveBeforeFirst();
}
}
}
animateToSlide_(isMovingForward, nextSlide, callback) {
DOM.lockScroll();
nextSlide.show();
ScrollHelper.scrollTo(nextSlide.el.offsetTop, 500, () => {
this.currentSlide_.hide();
if (isMovingForward) {
this.currentSlide_.moveAfterLast();
} else {
nextSlide.moveBeforeFirst();
}
DOM.unlockScroll();
callback.call(this, nextSlide);
});
}
transitionToSlide_(isMovingForward, nextSlide, callback) {
ScrollHelper.scrollTo(0, 0);
nextSlide.show();
if (this.currentSlide_) {
if (isMovingForward) {
this.currentSlide_.moveAfterLast();
} else {
nextSlide.moveBeforeFirst();
}
}
callback.call(this, nextSlide);
}
onSlideChange_(slide) {
this.currentSlide_ = slide;
this.currentSlideI_ = slide.i;
this.navigation.updateCounter(
this.currentSlideI_ + 1, this.maxSlide_);
this.isMoving = false;
Hash.setSlideNumber(this.currentSlideI_ + 1);
}
goNext() {
let nextIndex = this.currentSlideI_ + 1;
if (nextIndex >= this.maxSlide_) {
nextIndex = 0;
}
this.goToSlide(nextIndex, true);
}
goPrev() {
let prevIndex = this.currentSlideI_ - 1;
if (prevIndex < 0) {
prevIndex = this.maxSlide_ - 1;
}
this.goToSlide(prevIndex, false);
}
isValidIndexSlide_(i) {
return i >= 0 && i < this.maxSlide_;
}
initSlides_() {
let slideNumber = Hash.getSlideNumber();
// Not valid
if (slideNumber === null ||
slideNumber >= this.maxSlide_) {
slideNumber = 0;
}
this.goToSlide(slideNumber);
}
}

View File

@@ -9,4 +9,20 @@ export default class DOM {
return node;
}
static hide(el) {
el.style.display = 'none';
}
static show(el) {
el.style.display = '';
}
static lockScroll() {
document.documentElement.style.overflow = 'hidden';
}
static unlockScroll() {
document.documentElement.style.overflow = 'auto';
}
}

9
src/utils/easing.js Normal file
View File

@@ -0,0 +1,9 @@
function swing (p) {
return 0.5 - Math.cos(p * Math.PI) / 2;
}
function linear(p) {
return p;
}
export default { swing, linear };

58
src/utils/scroll-to.js Normal file
View File

@@ -0,0 +1,58 @@
import Easings from './easing';
let SCROLLABLE_CONTAINER;
/**
* Returns the correct DOM element to be used for scrolling the
* page, due to Firefox not scrolling on document.body.
* @return {Element} Scrollable Element.
*/
function getScrollableContainer() {
if (SCROLLABLE_CONTAINER) {
return SCROLLABLE_CONTAINER;
}
const documentElement = window.document.documentElement;
let scrollableContainer;
documentElement.scrollTop = 1;
if (documentElement.scrollTop === 1) {
documentElement.scrollTop = 0;
scrollableContainer = documentElement;
} else {
scrollableContainer = document.body;
}
SCROLLABLE_CONTAINER = scrollableContainer;
return scrollableContainer;
}
function scrollTo(y, duration = 500, cb = () => {}) {
const scrollableContainer = getScrollableContainer();
const delta = y - scrollableContainer.scrollTop;
const increment = 20;
const animateScroll = elapsedTime => {
elapsedTime += increment;
const percent = elapsedTime / duration;
scrollableContainer.scrollTop = Easings.swing(
percent,
elapsedTime * percent,
y,
delta,
duration) * delta;
if (elapsedTime < duration) {
setTimeout(() => animateScroll(elapsedTime), increment);
} else {
cb();
}
};
animateScroll(0);
}
export default { getScrollableContainer, scrollTo };

View File

@@ -10,7 +10,8 @@ module.exports = {
},
output: {
filename: '[name].js',
path: path.join(__dirname, 'dist')
path: path.join(__dirname, 'dist'),
publicPath: '/dist',
},
devServer: {
contentBase: __dirname,