mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
Refactor SlidesContainer to only use queryParams to keep slidepage state
This commit is contained in:
parent
d6b7060f39
commit
dab7503601
@ -1,94 +1,42 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react/addons';
|
||||||
import { History } from 'react-router';
|
import { History } from 'react-router';
|
||||||
import ReactAddons from 'react/addons';
|
|
||||||
|
|
||||||
import SlidesContainerBreadcrumbs from './slides_container_breadcrumbs';
|
import SlidesContainerBreadcrumbs from './slides_container_breadcrumbs';
|
||||||
|
|
||||||
|
|
||||||
let SlidesContainer = React.createClass({
|
const { arrayOf, element, bool, shape, string, object } = React.PropTypes;
|
||||||
propTypes: {
|
|
||||||
children: React.PropTypes.arrayOf(React.PropTypes.element),
|
|
||||||
forwardProcess: React.PropTypes.bool.isRequired,
|
|
||||||
|
|
||||||
glyphiconClassNames: React.PropTypes.shape({
|
const SlidesContainer = React.createClass({
|
||||||
pending: React.PropTypes.string,
|
propTypes: {
|
||||||
complete: React.PropTypes.string
|
children: arrayOf(element),
|
||||||
|
forwardProcess: bool.isRequired,
|
||||||
|
|
||||||
|
glyphiconClassNames: shape({
|
||||||
|
pending: string,
|
||||||
|
complete: string
|
||||||
}),
|
}),
|
||||||
location: React.PropTypes.object
|
location: object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [History],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
// handle queryParameters
|
|
||||||
let queryParams = this.props.location.query;
|
|
||||||
let slideNum = -1;
|
|
||||||
let startFrom = -1;
|
|
||||||
|
|
||||||
// We can actually need to check if slide_num is present as a key in queryParams.
|
|
||||||
// We do not really care about its value though...
|
|
||||||
if(queryParams && 'slide_num' in queryParams) {
|
|
||||||
slideNum = parseInt(queryParams.slide_num, 10);
|
|
||||||
}
|
|
||||||
// if slide_num is not set, this will be done in componentDidMount
|
|
||||||
|
|
||||||
// the query param 'start_from' removes all slide children before the respective number
|
|
||||||
// Also, we use the 'in' keyword for the same reason as above in 'slide_num'
|
|
||||||
if(queryParams && 'start_from' in queryParams) {
|
|
||||||
startFrom = parseInt(queryParams.start_from, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
slideNum,
|
containerWidth: 0
|
||||||
startFrom,
|
|
||||||
containerWidth: 0,
|
|
||||||
historyLength: window.history.length
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// check if slide_num was defined, and if not then default to 0
|
|
||||||
let queryParams = this.props.location.query;
|
|
||||||
|
|
||||||
// We use 'in' to check if the key is present in the user's browser url bar,
|
|
||||||
// we do not really care about its value at this point
|
|
||||||
if(!('slide_num' in queryParams)) {
|
|
||||||
|
|
||||||
// we're first requiring all the other possible queryParams and then set
|
|
||||||
// the specific one we need instead of overwriting them
|
|
||||||
queryParams.slide_num = 0;
|
|
||||||
|
|
||||||
this.history.replaceState(null, this.props.location.pathname, queryParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
// init container width
|
|
||||||
this.handleContainerResize();
|
this.handleContainerResize();
|
||||||
|
|
||||||
// we're using an event listener on window here,
|
// we're using an event listener on window here,
|
||||||
// as it was not possible to listen to the resize events of a dom node
|
// as it was not possible to listen to the resize events of a dom node
|
||||||
window.addEventListener('resize', this.handleContainerResize);
|
window.addEventListener('resize', this.handleContainerResize);
|
||||||
},
|
|
||||||
|
|
||||||
componentWillReceiveProps() {
|
// Initially, we need to dispatch 'resize' once to render correctly
|
||||||
let queryParams = this.props.location.query;
|
window.dispatchEvent(new Event('resize'));
|
||||||
|
|
||||||
// also check if start_from was updated
|
|
||||||
// This applies for example when the user tries to submit a already existing piece
|
|
||||||
// (starting from slide 1 for example) and then clicking on + NEW WORK
|
|
||||||
if(queryParams && !('start_from' in queryParams)) {
|
|
||||||
this.setState({
|
|
||||||
startFrom: -1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
let queryParams = this.props.location.query;
|
|
||||||
|
|
||||||
// check if slide_num was defined, and if not then default to 0
|
|
||||||
this.setSlideNum(queryParams.slide_num);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -104,79 +52,26 @@ let SlidesContainer = React.createClass({
|
|||||||
|
|
||||||
// When the start_from parameter is used, this.setSlideNum can not simply be used anymore.
|
// When the start_from parameter is used, this.setSlideNum can not simply be used anymore.
|
||||||
nextSlide() {
|
nextSlide() {
|
||||||
let nextSlide = this.state.slideNum + 1;
|
const slideNum = parseInt(this.props.location.query.slide_num, 10);
|
||||||
|
let nextSlide = slideNum + 1;
|
||||||
this.setSlideNum(nextSlide);
|
this.setSlideNum(nextSlide);
|
||||||
},
|
},
|
||||||
|
|
||||||
// We let every one from the outsite set the page number of the slider,
|
setSlideNum(nextSlideNum) {
|
||||||
// though only if the slideNum is actually in the range of our children-list.
|
|
||||||
setSlideNum(slideNum) {
|
|
||||||
|
|
||||||
// we do not want to overwrite other queryParams
|
|
||||||
let queryParams = this.props.location.query;
|
let queryParams = this.props.location.query;
|
||||||
|
queryParams.slide_num = nextSlideNum;
|
||||||
|
|
||||||
// slideNum can in some instances be not a number,
|
this.history.pushState(null, this.props.location.pathname, queryParams);
|
||||||
// therefore we have to parse it to one and make sure that its not NaN
|
|
||||||
slideNum = parseInt(slideNum, 10);
|
|
||||||
|
|
||||||
// if slideNum is not a number (even after we parsed it to one) and there has
|
|
||||||
// never been a transition to another slide (this.state.slideNum ==== -1 indicates that)
|
|
||||||
// then we want to "replace" (in this case append) the current url with ?slide_num=0
|
|
||||||
if(isNaN(slideNum) && this.state.slideNum === -1) {
|
|
||||||
slideNum = 0;
|
|
||||||
queryParams.slide_num = slideNum;
|
|
||||||
|
|
||||||
this.history.replaceState(null, this.props.location.pathname, queryParams);
|
|
||||||
this.setState({slideNum: slideNum});
|
|
||||||
return;
|
|
||||||
|
|
||||||
// slideNum always represents the future state. So if slideNum and
|
|
||||||
// this.state.slideNum are equal, there is no sense in redirecting
|
|
||||||
} else if(slideNum === this.state.slideNum) {
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if slideNum is within the range of slides and none of the previous cases
|
|
||||||
// where matched, we can actually do transitions
|
|
||||||
} else if(slideNum >= 0 || slideNum < this.customChildrenCount()) {
|
|
||||||
|
|
||||||
if(slideNum !== this.state.slideNum - 1) {
|
|
||||||
// Bootstrapping the component, getInitialState is called once to save
|
|
||||||
// the tabs history length.
|
|
||||||
// In order to know if we already pushed a new state on the history stack or not,
|
|
||||||
// we're comparing the old history length with the new one and if it didn't change then
|
|
||||||
// we push a new state on it ONCE (ever).
|
|
||||||
// Otherwise, we're able to use the browsers history.forward() method
|
|
||||||
// to keep the stack clean
|
|
||||||
|
|
||||||
if(this.props.forwardProcess) {
|
|
||||||
queryParams.slide_num = slideNum;
|
|
||||||
this.history.pushState(null, this.props.location.pathname, queryParams);
|
|
||||||
} else {
|
|
||||||
if(this.state.historyLength === window.history.length) {
|
|
||||||
queryParams.slide_num = slideNum;
|
|
||||||
this.history.pushState(null, this.props.location.pathname, queryParams);
|
|
||||||
} else {
|
|
||||||
window.history.forward();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
slideNum: slideNum
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Error('You\'re calling a page number that is out of range: ' + slideNum);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// breadcrumbs are defined as attributes of the slides.
|
// breadcrumbs are defined as attributes of the slides.
|
||||||
// To extract them we have to read the DOM element's attributes
|
// To extract them we have to read the DOM element's attributes
|
||||||
extractBreadcrumbs() {
|
extractBreadcrumbs() {
|
||||||
|
const startFrom = parseInt(this.props.location.query.start_from, 10) || -1;
|
||||||
let breadcrumbs = [];
|
let breadcrumbs = [];
|
||||||
|
|
||||||
ReactAddons.Children.map(this.props.children, (child, i) => {
|
React.Children.map(this.props.children, (child, i) => {
|
||||||
if(child && i >= this.state.startFrom && child.props['data-slide-title']) {
|
if(child && i >= startFrom && child.props['data-slide-title']) {
|
||||||
breadcrumbs.push(child.props['data-slide-title']);
|
breadcrumbs.push(child.props['data-slide-title']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -189,9 +84,11 @@ let SlidesContainer = React.createClass({
|
|||||||
// Therefore React.Children.count does not work anymore and we
|
// Therefore React.Children.count does not work anymore and we
|
||||||
// need to implement our own method.
|
// need to implement our own method.
|
||||||
customChildrenCount() {
|
customChildrenCount() {
|
||||||
|
const startFrom = parseInt(this.props.location.query.start_from, 10) || -1;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
React.Children.forEach(this.props.children, (child, i) => {
|
React.Children.forEach(this.props.children, (child, i) => {
|
||||||
if(i >= this.state.startFrom) {
|
if(i >= startFrom) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -210,7 +107,7 @@ let SlidesContainer = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<SlidesContainerBreadcrumbs
|
<SlidesContainerBreadcrumbs
|
||||||
breadcrumbs={breadcrumbs}
|
breadcrumbs={breadcrumbs}
|
||||||
slideNum={this.state.slideNum}
|
slideNum={parseInt(this.props.location.query.slide_num, 10)}
|
||||||
numOfSlides={breadcrumbs.length}
|
numOfSlides={breadcrumbs.length}
|
||||||
containerWidth={this.state.containerWidth}
|
containerWidth={this.state.containerWidth}
|
||||||
glyphiconClassNames={this.props.glyphiconClassNames}/>
|
glyphiconClassNames={this.props.glyphiconClassNames}/>
|
||||||
@ -223,12 +120,13 @@ let SlidesContainer = React.createClass({
|
|||||||
// Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps
|
// Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps
|
||||||
// Also, a key is nice to have!
|
// Also, a key is nice to have!
|
||||||
renderChildren() {
|
renderChildren() {
|
||||||
return ReactAddons.Children.map(this.props.children, (child, i) => {
|
const startFrom = parseInt(this.props.location.query.start_from, 10) || -1;
|
||||||
|
|
||||||
|
return React.Children.map(this.props.children, (child, i) => {
|
||||||
// since the default parameter of startFrom is -1, we do not need to check
|
// since the default parameter of startFrom is -1, we do not need to check
|
||||||
// if its actually present in the url bar, as it will just not match
|
// if its actually present in the url bar, as it will just not match
|
||||||
if(child && i >= this.state.startFrom) {
|
if(child && i >= startFrom) {
|
||||||
return ReactAddons.addons.cloneWithProps(child, {
|
return React.addons.cloneWithProps(child, {
|
||||||
className: 'ascribe-slide',
|
className: 'ascribe-slide',
|
||||||
style: {
|
style: {
|
||||||
width: this.state.containerWidth
|
width: this.state.containerWidth
|
||||||
@ -244,7 +142,7 @@ let SlidesContainer = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let spacing = this.state.containerWidth * this.state.slideNum;
|
let spacing = this.state.containerWidth * parseInt(this.props.location.query.slide_num, 10);
|
||||||
let translateXValue = 'translateX(' + (-1) * spacing + 'px)';
|
let translateXValue = 'translateX(' + (-1) * spacing + 'px)';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user