Ivan - add topic viewer drag n drop functionality [skip ci]
This commit is contained in:
parent
fb43e904d6
commit
0862889039
|
@ -1,4 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import classNames from 'classnames';
|
||||||
import {Link} from 'react-router';
|
import {Link} from 'react-router';
|
||||||
|
|
||||||
import i18n from 'lib-app/i18n';
|
import i18n from 'lib-app/i18n';
|
||||||
|
@ -27,6 +29,11 @@ class TopicViewer extends React.Component {
|
||||||
editable: true
|
editable: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
articles: this.props.articles,
|
||||||
|
currentDraggedId: 0
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="topic-viewer">
|
<div className="topic-viewer">
|
||||||
|
@ -37,7 +44,7 @@ class TopicViewer extends React.Component {
|
||||||
{(this.props.editable) ? this.renderDeleteButton() : null}
|
{(this.props.editable) ? this.renderDeleteButton() : null}
|
||||||
</div>
|
</div>
|
||||||
<ul className="topic-viewer__list">
|
<ul className="topic-viewer__list">
|
||||||
{this.props.articles.map(this.renderArticleItem.bind(this))}
|
{this.state.articles.map(this.renderArticleItem.bind(this))}
|
||||||
<li className="topic-viewer__list-item">
|
<li className="topic-viewer__list-item">
|
||||||
<Button type="link" className="topic-viewer__add-item" onClick={() => ModalContainer.openModal(this.renderAddNewArticle())}>
|
<Button type="link" className="topic-viewer__add-item" onClick={() => ModalContainer.openModal(this.renderAddNewArticle())}>
|
||||||
{i18n('ADD_NEW_ARTICLE')}
|
{i18n('ADD_NEW_ARTICLE')}
|
||||||
|
@ -67,7 +74,7 @@ class TopicViewer extends React.Component {
|
||||||
renderArticleItem(article, index) {
|
renderArticleItem(article, index) {
|
||||||
return (
|
return (
|
||||||
<li className="topic-viewer__list-item" key={index}>
|
<li className="topic-viewer__list-item" key={index}>
|
||||||
<Link className="topic-viewer__list-item-button" to={this.props.articlePath + article.id}>
|
<Link {...this.getArticleLinkProps(article, index)}>
|
||||||
{article.title}
|
{article.title}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
@ -101,6 +108,33 @@ class TopicViewer extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getArticleLinkProps(article, index) {
|
||||||
|
let classes = {
|
||||||
|
'topic-viewer__list-item-button': true,
|
||||||
|
'topic-viewer__list-item-hidden': article.hidden
|
||||||
|
};
|
||||||
|
|
||||||
|
let props = {
|
||||||
|
className: classNames(classes),
|
||||||
|
to: this.props.articlePath + article.id
|
||||||
|
};
|
||||||
|
|
||||||
|
if(this.props.editable) {
|
||||||
|
_.extend(props, {
|
||||||
|
onDragOver: this.onItemDragOver.bind(this, article, index),
|
||||||
|
onDrop: this.onItemDrop.bind(this, article, index),
|
||||||
|
onDragStart: () => this.setState({currentDraggedId: article.id}),
|
||||||
|
onDragEnd: () => {
|
||||||
|
if(this.state.currentDraggedId) {
|
||||||
|
this.setState({articles: this.props.articles});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
onDeleteClick() {
|
onDeleteClick() {
|
||||||
API.call({
|
API.call({
|
||||||
path: '/article/delete-topic',
|
path: '/article/delete-topic',
|
||||||
|
@ -110,6 +144,94 @@ class TopicViewer extends React.Component {
|
||||||
}).then(this.onChange.bind(this));
|
}).then(this.onChange.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onItemDragOver(article, index, event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if(!article.hidden) {
|
||||||
|
let articles = [];
|
||||||
|
let draggedId = this.state.currentDraggedId;
|
||||||
|
let draggedIndex = _.findIndex(this.props.articles, {id: draggedId});
|
||||||
|
|
||||||
|
_.forEach(this.props.articles, (current, currentIndex) => {
|
||||||
|
if(draggedIndex < index) {
|
||||||
|
if(current.id !== draggedId) {
|
||||||
|
articles.push(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index === currentIndex) {
|
||||||
|
articles.push({
|
||||||
|
id: article.id,
|
||||||
|
title: 'X',
|
||||||
|
hidden: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(index === currentIndex) {
|
||||||
|
articles.push({
|
||||||
|
id: article.id,
|
||||||
|
title: 'X',
|
||||||
|
hidden: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current.id !== draggedId) {
|
||||||
|
articles.push(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({articles});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onItemDrop(article, index, event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
let articles = [];
|
||||||
|
let draggedId = this.state.currentDraggedId;
|
||||||
|
let dragged = _.find(this.props.articles, {id: draggedId});
|
||||||
|
let draggedIndex = _.findIndex(this.props.articles, {id: draggedId});
|
||||||
|
|
||||||
|
_.forEach(this.props.articles, (current) => {
|
||||||
|
if(current.id !== draggedId) {
|
||||||
|
if(draggedIndex < index) {
|
||||||
|
articles.push(current);
|
||||||
|
|
||||||
|
if(current.id === article.id) {
|
||||||
|
articles.push(dragged);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(current.id === article.id) {
|
||||||
|
articles.push(dragged);
|
||||||
|
}
|
||||||
|
|
||||||
|
articles.push(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(draggedIndex === index) {
|
||||||
|
this.setState({articles: this.props.articles, currentDraggedId: 0});
|
||||||
|
} else {
|
||||||
|
this.updatePositions(articles.map((article) => article.id));
|
||||||
|
this.setState({articles, currentDraggedId: 0}, this.onChange.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePositions(positions) {
|
||||||
|
_.forEach(positions, (id, index) => {
|
||||||
|
if(this.props.articles[index].id !== id) {
|
||||||
|
API.call({
|
||||||
|
path: '/article/edit',
|
||||||
|
data: {
|
||||||
|
articleId: id,
|
||||||
|
position: index
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onChange() {
|
onChange() {
|
||||||
if(this.props.onChange) {
|
if(this.props.onChange) {
|
||||||
this.props.onChange();
|
this.props.onChange();
|
||||||
|
|
|
@ -38,6 +38,12 @@
|
||||||
width: 50%;
|
width: 50%;
|
||||||
color: $secondary-blue;
|
color: $secondary-blue;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
&-hidden {
|
||||||
|
width: 80%;
|
||||||
|
display: inline-block;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-item:before {
|
&-item:before {
|
||||||
|
|
Loading…
Reference in New Issue