Browse Source

Implv/125 Selective batch deletion in search result page
* Create the selectbox component for batch deletion which use in search result page.
* Add selectboxes for page deletion check in search result page.
* Add a deletion mode button in search result page.
* Add a page-select-deletion confirm modal window in search result page.

Tatsuya Ise 8 years ago
parent
commit
566b4e3280

+ 40 - 0
lib/views/modal/delete_pages.html

@@ -0,0 +1,40 @@
+  <div class="modal" id="deletePages">
+    <div class="modal-dialog">
+      <div class="modal-content">
+
+      <form role="form" id="delete-page-form" onsubmit="return false;">
+
+        <div class="modal-header">
+          <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+          <h4 class="modal-title"><i class="fa fa-trash-o"></i> Delete Page</h4>
+        </div>
+        <div class="modal-body">
+          <div class="form-group">
+            <label for="">Deleting page:</label><br>
+            <code>{{ page.path }}</code>
+          </div>
+        </div>
+        <div class="modal-footer">
+          <p><small class="pull-left" id="delete-errors"></small></p>
+          <input type="hidden" name="_csrf" value="{{ csrf() }}">
+          <input type="hidden" name="path" value="{{ page.path }}">
+          <input type="hidden" name="page_id" value="{{ page._id.toString() }}">
+          <input type="hidden" name="revision_id" value="{{ page.revision._id.toString() }}">
+          <label class="checkbox-inline text-danger">
+            <input type="checkbox" name="recursively" checked>recursively
+          </label>
+          {% if page.isDeleted() %}
+            <input type="hidden" name="completely" value="true">
+            <button type="submit" class="btn btn-danger delete-button"><i class="fa fa-times-circle" aria-hidden="true"></i> Delete Completely</button>
+          {% else %}
+            <label class="checkbox-inline text-danger">
+              <input type="checkbox" name="completely">completely
+            </label>
+            <button type="submit" class="btn btn-danger delete-button">Delete</button>
+          {% endif %}
+        </div>
+
+      </form>
+      </div><!-- /.modal-content -->
+    </div><!-- /.modal-dialog -->
+  </div><!-- /.modal -->

+ 3 - 0
lib/views/search.html

@@ -13,4 +13,7 @@
 <div class="" id="search-page">
 </div>
 
+<div id="crowi-modals">
+  {% include 'modal/delete_pages.html' %}
+</div>
 {% endblock %}

+ 52 - 0
resource/js/components/SearchPage/SearchResult.js

@@ -3,9 +3,16 @@ import PropTypes from 'prop-types';
 
 import Page from '../PageList/Page';
 import SearchResultList from './SearchResultList';
+import SearchResultInput from './SearchResultInput';
 
 // Search.SearchResult
 export default class SearchResult extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      deletionMode : false,
+    }
+  }
 
   isNotSearchedYet() {
     return !this.props.searchResultMeta.took;
@@ -22,6 +29,30 @@ export default class SearchResult extends React.Component {
     return false;
   }
 
+  componentWillMount() {
+    this.selectedCheckboxes = new Set();
+  }
+
+  toggleCheckbox(page) {
+    if (this.selectedCheckboxes.has(page)) {
+      this.selectedCheckboxes.delete(page);
+    } else {
+      this.selectedCheckboxes.add(page);
+    }
+  }
+
+  handleFormSubmit(formSubmitEvent) {
+    formSubmitEvent.preventDefault();
+
+    for (const checkbox of this.selectedCheckboxes) {
+      console.log(checkbox, 'is selected.');
+    }
+  }
+
+  handleDeletionModeChange() {
+    this.setState({deletionMode: !this.state.deletionMode});
+  }
+
   render() {
     const excludePathString = this.props.tree;
 
@@ -52,6 +83,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" data-target="#deletePages" data-toggle="modal"><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 +107,10 @@ export default class SearchResult extends React.Component {
           key={page._id}
           excludePathString={excludePathString}
           >
+          <SearchResultInput
+            selectablePage={page}
+            deletionMode={this.state.deletionMode}
+            handleCheckboxChange={this.toggleCheckbox}/>
           <div className="page-list-option">
             <a href={page.path}><i className="fa fa-arrow-circle-right" /></a>
           </div>
@@ -81,6 +132,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>

+ 48 - 0
resource/js/components/SearchPage/SearchResultInput.js

@@ -0,0 +1,48 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class SearchResultInput extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      isChecked: false,
+    }
+  }
+
+  toggleCheckboxChange() {
+    const { handleCheckboxChange, selectablePage } = this.props;
+
+    this.setState(({ isChecked }) => (
+      {
+        isChecked: !isChecked,
+      }
+    ));
+
+    handleCheckboxChange(selectablePage);
+  }
+
+  render() {
+    let deletionMode = this.props.deletionMode;
+    let pageId = this.props.selectablePage.id;
+    const { isChecked } = this.state;
+
+    const checkBoxInput = deletionMode ? (
+      <input
+        type="checkbox"
+        value={pageId}
+        checked={isChecked}
+        onChange={this.toggleCheckboxChange} />
+    ) : null;
+    return (
+      <div>
+        {checkBoxInput}
+      </div>
+    );
+  }
+}
+
+SearchResultInput.propTypes = {
+  selectablePage: PropTypes.object.isRequired,
+  deletionMode: PropTypes.bool.isRequired,
+  handleCheckboxChange: PropTypes.func.isRequired,
+};