|
|
@@ -3,9 +3,21 @@ import PropTypes from 'prop-types';
|
|
|
|
|
|
import Page from '../PageList/Page';
|
|
|
import SearchResultList from './SearchResultList';
|
|
|
+import DeletePageListModal from './DeletePageListModal';
|
|
|
|
|
|
// Search.SearchResult
|
|
|
export default class SearchResult extends React.Component {
|
|
|
+ constructor(props) {
|
|
|
+ super(props);
|
|
|
+ this.state = {
|
|
|
+ deletionMode : false,
|
|
|
+ selectedPages : new Set(),
|
|
|
+ isDeleteConfirmModalShown: false,
|
|
|
+ errorMessageForDeleting: undefined,
|
|
|
+ }
|
|
|
+ this.deleteSelectedPages = this.deleteSelectedPages.bind(this);
|
|
|
+ this.closeDeleteConfirmModal = this.closeDeleteConfirmModal.bind(this);
|
|
|
+ }
|
|
|
|
|
|
isNotSearchedYet() {
|
|
|
return !this.props.searchResultMeta.took;
|
|
|
@@ -22,6 +34,84 @@ export default class SearchResult extends React.Component {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * toggle checkbox and add (or delete from) selected pages list
|
|
|
+ *
|
|
|
+ * @param {any} page
|
|
|
+ * @memberof SearchResult
|
|
|
+ */
|
|
|
+ toggleCheckbox(page) {
|
|
|
+ if (this.state.selectedPages.has(page)) {
|
|
|
+ this.state.selectedPages.delete(page);
|
|
|
+ } else {
|
|
|
+ this.state.selectedPages.add(page);
|
|
|
+ }
|
|
|
+ this.setState({isDeleteConfirmModalShown: false});
|
|
|
+ this.setState({selectedPages: this.state.selectedPages});
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * change deletion mode
|
|
|
+ *
|
|
|
+ * @memberof SearchResult
|
|
|
+ */
|
|
|
+ handleDeletionModeChange() {
|
|
|
+ this.state.selectedPages.clear();
|
|
|
+ this.setState({deletionMode: !this.state.deletionMode});
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * delete selected pages
|
|
|
+ *
|
|
|
+ * @memberof SearchResult
|
|
|
+ */
|
|
|
+ deleteSelectedPages() {
|
|
|
+ let isDeleteComplete = true;
|
|
|
+ Array.from(this.state.selectedPages).map((page) => {
|
|
|
+ const pageId = page._id;
|
|
|
+ const revisionId = page.revision._id;
|
|
|
+ this.props.crowi.apiPost('/pages.remove',
|
|
|
+ {page_id: pageId, revision_id: revisionId})
|
|
|
+ .then(res => {
|
|
|
+ if (res.ok) {
|
|
|
+ this.state.selectedPages.delete(page);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ isDeleteComplete = false;
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ console.log(err.message);
|
|
|
+ isDeleteComplete = false;
|
|
|
+ this.setState({errorMessageForDeleting: err.message});
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ if ( isDeleteComplete ) {
|
|
|
+ window.location.reload();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * open confirm modal for page selection delete
|
|
|
+ *
|
|
|
+ * @memberof SearchResult
|
|
|
+ */
|
|
|
+ showDeleteConfirmModal() {
|
|
|
+ this.setState({isDeleteConfirmModalShown: true});
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * close confirm modal for page selection delete
|
|
|
+ *
|
|
|
+ * @memberof SearchResult
|
|
|
+ */
|
|
|
+ closeDeleteConfirmModal() {
|
|
|
+ this.setState({
|
|
|
+ isDeleteConfirmModalShown: false,
|
|
|
+ errorMessageForDeleting: undefined,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
render() {
|
|
|
const excludePathString = this.props.tree;
|
|
|
|
|
|
@@ -52,6 +142,22 @@ export default class SearchResult extends React.Component {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ let deletionModeButtons = '';
|
|
|
+
|
|
|
+ if (this.state.deletionMode) {
|
|
|
+ deletionModeButtons =
|
|
|
+ <div className="btn-group">
|
|
|
+ <button type="button" className="btn btn-danger" onClick={() => this.showDeleteConfirmModal()} disabled={this.state.selectedPages.size == 0}><i className="fa fa-trash-o"/> Delete</button>
|
|
|
+ <button type="button" className="btn btn-default" onClick={() => this.handleDeletionModeChange()}><i className="fa fa-undo"/> Cancel</button>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ deletionModeButtons =
|
|
|
+ <div className="btn-group">
|
|
|
+ <button type="button" className="btn btn-default" onClick={() => this.handleDeletionModeChange()}><i className="fa fa-trash-o"/> DeletionMode</button>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
const listView = this.props.pages.map((page) => {
|
|
|
const pageId = "#" + page._id;
|
|
|
return (
|
|
|
@@ -60,6 +166,13 @@ export default class SearchResult extends React.Component {
|
|
|
key={page._id}
|
|
|
excludePathString={excludePathString}
|
|
|
>
|
|
|
+ { this.state.deletionMode &&
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ value={pageId}
|
|
|
+ checked={this.state.selectedPages.has(page)}
|
|
|
+ onClick={() => this.toggleCheckbox(page)} />
|
|
|
+ }
|
|
|
<div className="page-list-option">
|
|
|
<a href={page.path}><i className="fa fa-arrow-circle-right" /></a>
|
|
|
</div>
|
|
|
@@ -81,6 +194,7 @@ export default class SearchResult extends React.Component {
|
|
|
<div className="search-result row" id="search-result">
|
|
|
<div className="col-md-4 hidden-xs hidden-sm page-list search-result-list" id="search-result-list">
|
|
|
<nav data-spy="affix" data-offset-top="120">
|
|
|
+ {deletionModeButtons}
|
|
|
<ul className="page-list-ul page-list-ul-flat nav">
|
|
|
{listView}
|
|
|
</ul>
|
|
|
@@ -94,7 +208,15 @@ export default class SearchResult extends React.Component {
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ <DeletePageListModal
|
|
|
+ isShown={this.state.isDeleteConfirmModalShown}
|
|
|
+ pages={Array.from(this.state.selectedPages)}
|
|
|
+ errorMessage={this.state.errorMessageForDeleting}
|
|
|
+ cancel={this.closeDeleteConfirmModal}
|
|
|
+ confirmedToDelete={this.deleteSelectedPages}
|
|
|
+ />
|
|
|
+
|
|
|
+ </div>//content-main
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
@@ -104,6 +226,7 @@ SearchResult.propTypes = {
|
|
|
pages: PropTypes.array.isRequired,
|
|
|
searchingKeyword: PropTypes.string.isRequired,
|
|
|
searchResultMeta: PropTypes.object.isRequired,
|
|
|
+ crowi: PropTypes.object.isRequired,
|
|
|
};
|
|
|
SearchResult.defaultProps = {
|
|
|
tree: '',
|