kopia lustrzana https://github.com/OpenDroneMap/WebODM
State history for pagination working
rodzic
ac5e54b56b
commit
23af449853
|
@ -2,6 +2,11 @@ import React from 'react';
|
|||
import './css/Dashboard.scss';
|
||||
import ProjectList from './components/ProjectList';
|
||||
import EditProjectDialog from './components/EditProjectDialog';
|
||||
import Utils from './classes/Utils';
|
||||
import {
|
||||
BrowserRouter as Router,
|
||||
Route
|
||||
} from 'react-router-dom';
|
||||
import $ from 'jquery';
|
||||
|
||||
class Dashboard extends React.Component {
|
||||
|
@ -32,7 +37,20 @@ class Dashboard extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const projectList = ({ location, history }) => {
|
||||
let q = Utils.queryParams(location),
|
||||
page = parseInt(q.page);
|
||||
|
||||
return <ProjectList
|
||||
source={`/api/projects/?ordering=-created_at&page=${page}`}
|
||||
ref={(domNode) => { this.projectList = domNode; }}
|
||||
currentPage={page}
|
||||
history={history}
|
||||
/>;
|
||||
};
|
||||
|
||||
return (
|
||||
<Router basename="/dashboard">
|
||||
<div>
|
||||
<div className="text-right add-button">
|
||||
<button type="button"
|
||||
|
@ -47,10 +65,9 @@ class Dashboard extends React.Component {
|
|||
saveAction={this.addNewProject}
|
||||
ref={(domNode) => { this.projectDialog = domNode; }}
|
||||
/>
|
||||
<ProjectList
|
||||
source="/api/projects/?ordering=-created_at&page=#{PAGE}"
|
||||
ref={(domNode) => { this.projectList = domNode; }} />
|
||||
<Route path="/" component={projectList} />
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import Utils from './Utils';
|
||||
|
||||
class HistoryNav{
|
||||
constructor(history){
|
||||
this.history = history;
|
||||
}
|
||||
|
||||
changeQueryString(param, value){
|
||||
this.history.replace(
|
||||
this.history.location.pathname +
|
||||
Utils.replaceSearchQueryParam(this.history.location, param, value) +
|
||||
this.history.location.hash);
|
||||
}
|
||||
}
|
||||
|
||||
export default HistoryNav;
|
||||
|
|
@ -25,5 +25,30 @@ export default {
|
|||
|
||||
return result;
|
||||
},
|
||||
|
||||
queryParams: function(location){
|
||||
let params = {};
|
||||
let paramsRaw = (location.search.replace("?", "").match(/([^&=]+)=?([^&]*)/g) || []);
|
||||
for (let i in paramsRaw){
|
||||
let parts = paramsRaw[i].split("=");
|
||||
params[parts[0]] = parts[1];
|
||||
}
|
||||
return params;
|
||||
},
|
||||
|
||||
toSearchQuery: function(params){
|
||||
let parts = [];
|
||||
for (let k in params){
|
||||
parts.push(encodeURIComponent(k) + "=" + encodeURIComponent(params[k]));
|
||||
}
|
||||
if (parts.length > 0) return "?" + parts.join("&");
|
||||
else return "";
|
||||
},
|
||||
|
||||
replaceSearchQueryParam: function(location, param, value){
|
||||
let q = this.queryParams(location);
|
||||
q[param] = value;
|
||||
return this.toSearchQuery(q);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,27 +1,33 @@
|
|||
import React from 'react';
|
||||
import update from 'immutability-helper';
|
||||
import HistoryNav from '../classes/HistoryNav';
|
||||
|
||||
class Paginated extends React.Component{
|
||||
constructor(){
|
||||
super();
|
||||
this.handlePageChange = this.handlePageChange.bind(this);
|
||||
static defaultProps = {
|
||||
currentPage: 1
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
history: React.PropTypes.object.isRequired, // reference to the history object coming from the route this component is bound to
|
||||
currentPage: React.PropTypes.number
|
||||
};
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.historyNav = new HistoryNav(props.history);
|
||||
}
|
||||
|
||||
updatePagination(itemsPerPage, totalItems){
|
||||
let currentPage = 1;
|
||||
let currentPage = this.props.currentPage;
|
||||
const totalPages = this.totalPages(itemsPerPage, totalItems);
|
||||
|
||||
if (this.state.pagination && this.state.pagination.currentPage !== undefined){
|
||||
currentPage = this.state.pagination.currentPage;
|
||||
}
|
||||
|
||||
if (currentPage > totalPages) currentPage = totalPages;
|
||||
|
||||
this.setState({pagination: {
|
||||
switchingPages: false,
|
||||
itemsPerPage: itemsPerPage,
|
||||
totalItems: totalItems,
|
||||
currentPage: currentPage
|
||||
totalItems: totalItems
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -30,14 +36,6 @@ class Paginated extends React.Component{
|
|||
return Math.ceil(totalItems / itemsPerPage);
|
||||
}
|
||||
|
||||
getPaginatedUrl(base){
|
||||
const page = this.state.pagination && this.state.pagination.currentPage !== undefined
|
||||
? this.state.pagination.currentPage
|
||||
: 1;
|
||||
|
||||
return base.replace(/#\{PAGE\}/g, page);
|
||||
}
|
||||
|
||||
setPaginationState(props, done){
|
||||
this.setState(update(this.state, {
|
||||
pagination: {
|
||||
|
@ -46,29 +44,17 @@ class Paginated extends React.Component{
|
|||
}), done);
|
||||
}
|
||||
|
||||
handlePageChange(pageNum){
|
||||
return (e) => {
|
||||
// Update current page, once rendering is completed, raise
|
||||
// on page changed event
|
||||
this.setPaginationState({
|
||||
currentPage: pageNum,
|
||||
switchingPages: true
|
||||
}, () => {
|
||||
if (this.onPageChanged) this.onPageChanged(pageNum);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handlePageItemsNumChange(delta, needsRefreshCallback){
|
||||
let currentPage = this.props.currentPage;
|
||||
const pagesBefore = this.totalPages(this.state.pagination.itemsPerPage, this.state.pagination.totalItems),
|
||||
pagesAfter = this.totalPages(this.state.pagination.itemsPerPage, this.state.pagination.totalItems + delta);
|
||||
let currentPage = this.state.pagination.currentPage;
|
||||
|
||||
if (currentPage > pagesAfter) currentPage = pagesAfter;
|
||||
|
||||
this.historyNav.changeQueryString('page', currentPage);
|
||||
|
||||
this.setPaginationState({
|
||||
totalItems: this.state.pagination.totalItems + delta,
|
||||
currentPage: currentPage
|
||||
totalItems: this.state.pagination.totalItems + delta
|
||||
}, () => {
|
||||
if (pagesBefore !== pagesAfter) needsRefreshCallback(pagesAfter);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import $ from 'jquery';
|
||||
|
||||
class Paginator extends React.Component {
|
||||
|
@ -14,20 +15,20 @@ class Paginator extends React.Component {
|
|||
<div className={this.props.className}>
|
||||
<ul className="pagination pagination-sm">
|
||||
<li className={currentPage === 1 ? "disabled" : ""}>
|
||||
<a href="javascript:void(0);" onClick={this.props.handlePageChange(1)}>
|
||||
<Link to={{search: "?page=1"}}>
|
||||
<span>«</span>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{pages.map(page => {
|
||||
return (<li
|
||||
key={page + 1}
|
||||
className={currentPage === (page + 1) ? "active" : ""}
|
||||
><a href="javascript:void(0);" onClick={this.props.handlePageChange(page + 1)}>{page + 1}</a></li>);
|
||||
><Link to={{search: "?page=" + (page + 1)}}>{page + 1}</Link></li>);
|
||||
})}
|
||||
<li className={currentPage === numPages ? "disabled" : ""}>
|
||||
<a href="javascript:void(0);" onClick={this.props.handlePageChange(numPages)}>
|
||||
<Link to={{search: "?page=" + numPages}}>
|
||||
<span>»</span>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -6,10 +6,11 @@ import ProjectListItem from './ProjectListItem';
|
|||
import Paginated from './Paginated';
|
||||
import Paginator from './Paginator';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import { Route } from 'react-router-dom';
|
||||
|
||||
class ProjectList extends Paginated {
|
||||
constructor(){
|
||||
super();
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true,
|
||||
|
@ -27,12 +28,18 @@ class ProjectList extends Paginated {
|
|||
this.refresh();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps){
|
||||
if (prevProps.source !== this.props.source){
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
refresh(){
|
||||
this.setState({refreshing: true});
|
||||
|
||||
// Load projects from API
|
||||
this.serverRequest =
|
||||
$.getJSON(this.getPaginatedUrl(this.props.source), json => {
|
||||
$.getJSON(this.props.source, json => {
|
||||
if (json.results){
|
||||
this.setState({
|
||||
projects: json.results,
|
||||
|
@ -78,8 +85,8 @@ class ProjectList extends Paginated {
|
|||
return (<div className="project-list">Loading projects... <i className="fa fa-refresh fa-spin fa-fw"></i></div>);
|
||||
}else{
|
||||
return (<div className="project-list">
|
||||
<ErrorMessage bind={[this, 'error']} />
|
||||
<Paginator className="text-right" {...this.state.pagination} handlePageChange={this.handlePageChange.bind(this)}>
|
||||
<ErrorMessage bind={[this, 'error']} />
|
||||
<Paginator className="text-right" {...this.state.pagination} {...this.props}>
|
||||
<ul className={"list-group project-list " + (this.state.refreshing ? "refreshing" : "")}>
|
||||
{this.state.projects.map(p => (
|
||||
<ProjectListItem key={p.id} data={p} onDelete={this.handleDelete} />
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
"react": "^15.3.2",
|
||||
"react-dom": "^15.3.2",
|
||||
"react-hot-loader": "^3.0.0-beta.5",
|
||||
"react-router": "^4.1.0",
|
||||
"react-router-dom": "^4.1.0",
|
||||
"sass-loader": "^4.0.2",
|
||||
"style-loader": "^0.13.1",
|
||||
"tween.js": "^16.6.0",
|
||||
|
|
Ładowanie…
Reference in New Issue