mirror of
https://github.com/ascribe/onion.git
synced 2024-11-15 09:35:10 +01:00
Merge branch 'AD-540-chunked-edition-list-loading-to-a'
This commit is contained in:
commit
bc53b4b54c
@ -15,21 +15,30 @@ class EditionListActions {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchEditionList(pieceId, orderBy, orderAsc) {
|
fetchEditionList(pieceId, page, pageSize, orderBy, orderAsc) {
|
||||||
if(!orderBy && typeof orderAsc == 'undefined') {
|
if(!orderBy && typeof orderAsc == 'undefined') {
|
||||||
orderBy = 'edition_number';
|
orderBy = 'edition_number';
|
||||||
orderAsc = true;
|
orderAsc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taken from: http://stackoverflow.com/a/519157/1263876
|
||||||
|
if(typeof page === 'undefined' && typeof pageSize === 'undefined') {
|
||||||
|
page = 1;
|
||||||
|
pageSize = 10;
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
EditionListFetcher
|
EditionListFetcher
|
||||||
.fetch(pieceId, orderBy, orderAsc)
|
.fetch(pieceId, page, pageSize, orderBy, orderAsc)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.actions.updateEditionList({
|
this.actions.updateEditionList({
|
||||||
'editionListOfPiece': res.editions,
|
|
||||||
pieceId,
|
pieceId,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
orderBy,
|
orderBy,
|
||||||
orderAsc
|
orderAsc,
|
||||||
|
'editionListOfPiece': res.editions,
|
||||||
|
'count': res.count
|
||||||
});
|
});
|
||||||
resolve(res);
|
resolve(res);
|
||||||
})
|
})
|
||||||
|
@ -22,25 +22,22 @@ let AccordionListItemTable = React.createClass({
|
|||||||
render() {
|
render() {
|
||||||
if(this.props.show && this.props.itemList) {
|
if(this.props.show && this.props.itemList) {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.className}>
|
<Table
|
||||||
<Table
|
responsive
|
||||||
responsive
|
className="ascribe-table"
|
||||||
className="ascribe-table"
|
columnList={this.props.columnList}
|
||||||
columnList={this.props.columnList}
|
itemList={this.props.itemList}
|
||||||
itemList={this.props.itemList}
|
changeOrder={this.props.changeOrder}
|
||||||
changeOrder={this.props.changeOrder}
|
orderBy={this.props.orderBy}
|
||||||
orderBy={this.props.orderBy}
|
orderAsc={this.props.orderAsc}>
|
||||||
orderAsc={this.props.orderAsc}>
|
{this.props.itemList.map((item, i) => {
|
||||||
{this.props.itemList.map((item, i) => {
|
return (
|
||||||
return (
|
<TableItem
|
||||||
<TableItem
|
className="ascribe-table-item-selectable"
|
||||||
className="ascribe-table-item-selectable"
|
key={i} />
|
||||||
key={i} />
|
);
|
||||||
);
|
})}
|
||||||
})}
|
</Table>
|
||||||
</Table>
|
|
||||||
{this.props.children}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
@ -16,6 +16,7 @@ import TableItemCheckbox from '../ascribe_table/table_item_checkbox';
|
|||||||
import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered';
|
import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered';
|
||||||
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
import { mergeOptions } from '../../utils/general_utils';
|
||||||
|
|
||||||
let AccordionListItemTableEditions = React.createClass({
|
let AccordionListItemTableEditions = React.createClass({
|
||||||
|
|
||||||
@ -25,7 +26,12 @@ let AccordionListItemTableEditions = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return EditionListStore.getState();
|
return mergeOptions(
|
||||||
|
EditionListStore.getState(),
|
||||||
|
{
|
||||||
|
showMoreLoading: false
|
||||||
|
}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -37,6 +43,12 @@ let AccordionListItemTableEditions = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onChange(state) {
|
onChange(state) {
|
||||||
|
if(this.state.showMoreLoading) {
|
||||||
|
this.setState({
|
||||||
|
showMoreLoading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -67,6 +79,16 @@ let AccordionListItemTableEditions = React.createClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loadFurtherEditions() {
|
||||||
|
// trigger loading animation
|
||||||
|
this.setState({
|
||||||
|
showMoreLoading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
let editionList = this.state.editionList[this.props.parentId];
|
||||||
|
EditionListActions.fetchEditionList(this.props.parentId, editionList.page + 1, editionList.pageSize);
|
||||||
|
},
|
||||||
|
|
||||||
changeEditionListOrder(orderBy, orderAsc) {
|
changeEditionListOrder(orderBy, orderAsc) {
|
||||||
EditionListActions.fetchEditionList(this.props.parentId, orderBy, orderAsc);
|
EditionListActions.fetchEditionList(this.props.parentId, orderBy, orderAsc);
|
||||||
},
|
},
|
||||||
@ -76,22 +98,31 @@ let AccordionListItemTableEditions = React.createClass({
|
|||||||
let allEditionsCount = 0;
|
let allEditionsCount = 0;
|
||||||
let orderBy;
|
let orderBy;
|
||||||
let orderAsc;
|
let orderAsc;
|
||||||
let show;
|
let show = false;
|
||||||
|
let showExpandOption = false;
|
||||||
|
|
||||||
|
let editionsForPiece = this.state.editionList[this.props.parentId];
|
||||||
|
|
||||||
// here we need to check if all editions of a specific
|
// here we need to check if all editions of a specific
|
||||||
// piece are already defined. Otherwise .length will throw an error and we'll not
|
// piece are already defined. Otherwise .length will throw an error and we'll not
|
||||||
// be notified about it.
|
// be notified about it.
|
||||||
if(this.state.editionList[this.props.parentId]) {
|
if(editionsForPiece) {
|
||||||
selectedEditionsCount = this.filterSelectedEditions().length;
|
selectedEditionsCount = this.filterSelectedEditions().length;
|
||||||
allEditionsCount = this.state.editionList[this.props.parentId].length;
|
allEditionsCount = editionsForPiece.length;
|
||||||
orderBy = this.state.editionList[this.props.parentId].orderBy;
|
orderBy = editionsForPiece.orderBy;
|
||||||
orderAsc = this.state.editionList[this.props.parentId].orderAsc;
|
orderAsc = editionsForPiece.orderAsc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.props.parentId in this.state.isEditionListOpenForPieceId) {
|
if(this.props.parentId in this.state.isEditionListOpenForPieceId) {
|
||||||
show = this.state.isEditionListOpenForPieceId[this.props.parentId].show;
|
show = this.state.isEditionListOpenForPieceId[this.props.parentId].show;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the number of editions in the array is equal to the maximum number of editions,
|
||||||
|
// then the "Show me more" dialog should be hidden from the user's view
|
||||||
|
if(editionsForPiece && editionsForPiece.count > editionsForPiece.length) {
|
||||||
|
showExpandOption = true;
|
||||||
|
}
|
||||||
|
|
||||||
let transition = new TransitionModel('edition', 'editionId', 'bitcoin_id');
|
let transition = new TransitionModel('edition', 'editionId', 'bitcoin_id');
|
||||||
|
|
||||||
let columnList = [
|
let columnList = [
|
||||||
@ -155,23 +186,26 @@ let AccordionListItemTableEditions = React.createClass({
|
|||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let loadingSpinner = <span className="glyph-ascribe-spool-chunked ascribe-color spin"/> ;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={this.props.className}>
|
||||||
|
<AccordionListItemTableToggle
|
||||||
|
className="ascribe-accordion-list-table-toggle"
|
||||||
|
onClick={this.toggleTable}
|
||||||
|
message={show && typeof editionsForPiece !== 'undefined' ? <span><span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span> Hide editions</span> : <span><span className="glyphicon glyphicon-menu-down" aria-hidden="true" style={{top: 2}}></span> Show editions {show && typeof editionsForPiece === 'undefined' ? loadingSpinner : null}</span>} />
|
||||||
<AccordionListItemTable
|
<AccordionListItemTable
|
||||||
className={this.props.className}
|
|
||||||
parentId={this.props.parentId}
|
parentId={this.props.parentId}
|
||||||
itemList={this.state.editionList[this.props.parentId]}
|
itemList={editionsForPiece}
|
||||||
columnList={columnList}
|
columnList={columnList}
|
||||||
show={show}
|
show={show}
|
||||||
orderBy={orderBy}
|
orderBy={orderBy}
|
||||||
orderAsc={orderAsc}
|
orderAsc={orderAsc}
|
||||||
changeOrder={this.changeEditionListOrder}>
|
changeOrder={this.changeEditionListOrder} />
|
||||||
<AccordionListItemTableToggle
|
<AccordionListItemTableToggle
|
||||||
className="ascribe-accordion-list-table-toggle"
|
className="ascribe-accordion-list-table-toggle"
|
||||||
onClick={this.toggleTable}
|
onClick={this.loadFurtherEditions}
|
||||||
show={show} />
|
message={show && showExpandOption ? <span><span className="glyphicon glyphicon-option-horizontal" aria-hidden="true" style={{top: 3}}></span> Show me more {this.state.showMoreLoading ? loadingSpinner : null}</span> : ''} />
|
||||||
</AccordionListItemTable>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@ let AccordionListItemTableToggle = React.createClass({
|
|||||||
propTypes: {
|
propTypes: {
|
||||||
className: React.PropTypes.string,
|
className: React.PropTypes.string,
|
||||||
onClick: React.PropTypes.func,
|
onClick: React.PropTypes.func,
|
||||||
show: React.PropTypes.bool
|
message: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.string,
|
||||||
|
React.PropTypes.element
|
||||||
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -14,7 +17,7 @@ let AccordionListItemTableToggle = React.createClass({
|
|||||||
<span
|
<span
|
||||||
className={this.props.className}
|
className={this.props.className}
|
||||||
onClick={this.props.onClick}>
|
onClick={this.props.onClick}>
|
||||||
{this.props.show ? 'Hide all Editions' : 'Show all Editions'}
|
{this.props.message}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,11 @@ let PieceListBulkModal = React.createClass({
|
|||||||
handleSuccess() {
|
handleSuccess() {
|
||||||
this.fetchSelectedPieceEditionList()
|
this.fetchSelectedPieceEditionList()
|
||||||
.forEach((pieceId) => {
|
.forEach((pieceId) => {
|
||||||
EditionListActions.fetchEditionList(pieceId, this.state.orderBy, this.state.orderAsc);
|
let editionsForPiece = this.state.editionList[pieceId];
|
||||||
|
for(let i = 1; i <= editionsForPiece.page; i++) {
|
||||||
|
EditionListActions.fetchEditionList(pieceId, i, editionsForPiece.pageSize, editionsForPiece.orderBy, editionsForPiece.orderAsc);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
EditionListActions.clearAllEditionSelections();
|
EditionListActions.clearAllEditionSelections();
|
||||||
},
|
},
|
||||||
|
@ -9,9 +9,14 @@ let EditionListFetcher = {
|
|||||||
/**
|
/**
|
||||||
* Fetches a list of editions from the API.
|
* Fetches a list of editions from the API.
|
||||||
*/
|
*/
|
||||||
fetch(pieceId, orderBy, orderAsc) {
|
fetch(pieceId, page, pageSize, orderBy, orderAsc) {
|
||||||
let ordering = generateOrderingQueryParams(orderBy, orderAsc);
|
let ordering = generateOrderingQueryParams(orderBy, orderAsc);
|
||||||
return requests.get('editions_list', { 'piece_id': pieceId, ordering });
|
return requests.get('editions_list', {
|
||||||
|
'piece_id': pieceId,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
ordering
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,27 +12,48 @@ class EditionListStore {
|
|||||||
this.bindActions(EditionsListActions);
|
this.bindActions(EditionsListActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateEditionList({pieceId, editionListOfPiece, orderBy, orderAsc}) {
|
onUpdateEditionList({pieceId, editionListOfPiece, page, pageSize, orderBy, orderAsc, count}) {
|
||||||
if(this.editionList[pieceId]) {
|
|
||||||
this.editionList[pieceId].forEach((edition, i) => {
|
/*
|
||||||
// This uses the index of the new editionList for determining the edition.
|
Basically there are two modes an edition list can be updated.
|
||||||
// If the list of editions can be sorted in the future, this needs to be changed!
|
|
||||||
if (editionListOfPiece[i]) {
|
1. The elements that have been requested from the server are not yet defined in the store => just assign them
|
||||||
editionListOfPiece[i] = React.addons.update(edition, {$merge: editionListOfPiece[i]});
|
2. The elements are already defined => merge current objects with the new ones from the server
|
||||||
}
|
|
||||||
});
|
*/
|
||||||
|
for(let i = 0; i < editionListOfPiece.length; i++) {
|
||||||
|
|
||||||
|
// if editionList for a specific piece does not exist yet,
|
||||||
|
// just initialize a new array
|
||||||
|
if(!this.editionList[pieceId]) {
|
||||||
|
this.editionList[pieceId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the index formula for accessing an edition of a specific
|
||||||
|
// page
|
||||||
|
let storeEditionIndex = (page - 1) * pageSize + i;
|
||||||
|
let editionsForPieces = this.editionList[pieceId];
|
||||||
|
|
||||||
|
// if edition already exists, just merge
|
||||||
|
if(editionsForPieces[storeEditionIndex]) {
|
||||||
|
editionsForPieces[storeEditionIndex] = React.addons.update(editionsForPieces[storeEditionIndex], {$merge: editionListOfPiece[i]});
|
||||||
|
} else {
|
||||||
|
// if does not exist, assign
|
||||||
|
editionsForPieces[storeEditionIndex] = editionListOfPiece[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.editionList[pieceId] = editionListOfPiece;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* orderBy and orderAsc are specific to a single list of editions
|
* page, pageSize, orderBy, orderAsc and count are specific to a single list of editions
|
||||||
* therefore they need to be saved in relation to their parent-piece.
|
* therefore they need to be saved in relation to their parent-piece.
|
||||||
*
|
*
|
||||||
* Default values for both are set in the editon_list-actions.
|
* Default values for both are set in the editon_list_actions.
|
||||||
*/
|
*/
|
||||||
|
this.editionList[pieceId].page = page;
|
||||||
|
this.editionList[pieceId].pageSize = pageSize;
|
||||||
this.editionList[pieceId].orderBy = orderBy;
|
this.editionList[pieceId].orderBy = orderBy;
|
||||||
this.editionList[pieceId].orderAsc = orderAsc;
|
this.editionList[pieceId].orderAsc = orderAsc;
|
||||||
|
this.editionList[pieceId].count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectEdition({pieceId, editionId, toValue}) {
|
onSelectEdition({pieceId, editionId, toValue}) {
|
||||||
|
@ -284,3 +284,39 @@ html {
|
|||||||
margin-right: 1px;
|
margin-right: 1px;
|
||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spin {
|
||||||
|
display:inline-block;
|
||||||
|
-webkit-animation: spin 1s infinite linear;
|
||||||
|
-moz-animation: spin 1s infinite linear;
|
||||||
|
-o-animation: spin 1s infinite linear;
|
||||||
|
-ms-animation: spin 1s infinite linear;
|
||||||
|
animation: spin 1s infinite linear;
|
||||||
|
-webkit-transform-origin: 55% 70%;
|
||||||
|
-moz-transform-origin: 55% 70%;
|
||||||
|
-o-transform-origin: 55% 70%;
|
||||||
|
transform-origin: 55% 70%;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% { -webkit-transform: rotate(0deg);}
|
||||||
|
100% { -webkit-transform: rotate(360deg);}
|
||||||
|
}
|
||||||
|
@-moz-keyframes spin {
|
||||||
|
0% { -moz-transform: rotate(0deg); }
|
||||||
|
100% { -moz-transform: rotate(360deg);}
|
||||||
|
}
|
||||||
|
@-o-keyframes spin {
|
||||||
|
0% { -o-transform: rotate(0deg);}
|
||||||
|
100% { -o-transform: rotate(360deg);}
|
||||||
|
}
|
||||||
|
@-ms-keyframes spin {
|
||||||
|
0% { -ms-transform: rotate(0deg);}
|
||||||
|
100% { -ms-transform: rotate(360deg);}
|
||||||
|
}
|
||||||
|
@-keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg);}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user