Browse Source

新規ページ作成モーダル画面のページ名入力を検索できるよう変更

tatsurou 8 years ago
parent
commit
b42aa15b71

+ 5 - 1
lib/views/modal/create_page.html

@@ -33,7 +33,11 @@
               <h4>{{ t('Create under', parentPath(path)) }}</h4>
             </div>
             <div class="col-xs-10">
-              <input type="text" value="{{ parentPath(path) }}" class="page-name-input form-control " placeholder="{{ t('Input page name') }}" required>
+              {% if searchConfigured() %}
+              <div id="page-name-inputter"></div>
+              {% else %}
+              <input type="text" value="{{ parentPath(path) }}" class="page-name-input form-control " placeholder="{{ t('Input page name') }}" required />
+              {% endif %}
             </div>
             <div class="col-xs-2">
               <button type="submit" class="btn btn-primary">{{ t('Create') }}</button>

+ 3 - 0
resource/css/crowi.scss

@@ -165,6 +165,9 @@ footer {
         // width: 100%;
         display: inline-block;
       }
+      .rbt-input input, #page-name-inputter {
+        width: 538px !important;
+      }
     }
   }
 }

+ 3 - 0
resource/js/app.js

@@ -15,6 +15,7 @@ import SeenUserList     from './components/SeenUserList';
 import RevisionPath     from './components/Page/RevisionPath';
 import RevisionUrl      from './components/Page/RevisionUrl';
 import BookmarkButton   from './components/BookmarkButton';
+import NewPageNameInputter from './components/NewPageNameInputter';
 
 if (!window) {
   window = {};
@@ -71,6 +72,8 @@ const componentMappings = {
   //'revision-history': <PageHistory pageId={pageId} />,
   'seen-user-list': <SeenUserList pageId={pageId} crowi={crowi} />,
   'bookmark-button': <BookmarkButton pageId={pageId} crowi={crowi} />,
+
+  'page-name-inputter': <NewPageNameInputter crowi={crowi} />,
 };
 // additional definitions if pagePath exists
 if (pagePath) {

+ 143 - 0
resource/js/components/NewPageNameInputter.js

@@ -0,0 +1,143 @@
+import React from 'react';
+import { FormGroup, Button, InputGroup } from 'react-bootstrap';
+
+import { AsyncTypeahead } from 'react-bootstrap-typeahead';
+
+import UserPicture from './User/UserPicture';
+import PageListMeta from './PageList/PageListMeta';
+import PagePath from './PageList/PagePath';
+import PropTypes from 'prop-types';
+
+// Header.SearchForm
+export default class NewPageNameInputter extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.crowi = window.crowi; // FIXME
+
+    this.state = {
+      input: '',
+      keyword: '',
+      searchedKeyword: '',
+      pages: [],
+      isLoading: false,
+      searchError: null,
+    };
+
+    this.search = this.search.bind(this);
+    this.clearForm = this.clearForm.bind(this);
+    this.getFormClearComponent = this.getFormClearComponent.bind(this);
+    this.renderMenuItemChildren = this.renderMenuItemChildren.bind(this);
+    this.onInputChange = this.onInputChange.bind(this);
+  }
+
+  componentDidMount() {
+  }
+
+  componentWillUnmount() {
+  }
+
+  search(keyword) {
+
+    if (keyword === '') {
+      this.setState({
+        keyword: '',
+        searchedKeyword: '',
+      });
+      return;
+    }
+
+    this.setState({isLoading: true});
+
+    this.crowi.apiGet('/search', {q: keyword})
+      .then(res => {
+        this.setState({
+          isLoading: false,
+          keyword: '',
+          pages: res.data,
+        });
+      })
+      .catch(err => {
+        this.setState({
+          isLoading: false,
+          searchError: err,
+        });
+      });
+  }
+
+  getFormClearComponent() {
+    let isHidden = (this.state.input.length === 0);
+
+    return isHidden ? <span></span> : (
+      <a className="btn btn-link search-top-clear" onClick={this.clearForm} hidden={isHidden}>
+        <i className="fa fa-times-circle" />
+      </a>
+    );
+  }
+
+  clearForm() {
+    this._typeahead.getInstance().clear();
+    this.setState({keyword: ''});
+  }
+
+  onInputChange(text) {
+    this.setState({input: text});
+  }
+
+  renderMenuItemChildren(option, props, index) {
+    const page = option;
+    return (
+      <span>
+        <UserPicture user={page.revision.author} />
+        <PagePath page={page} />
+        <PageListMeta page={page} />
+      </span>
+    );
+  }
+
+  render() {
+    const emptyLabel = (this.state.searchError !== null)
+        ? 'Error on searching.'
+        : 'No matches found on title...';
+    const formClear = this.getFormClearComponent();
+
+    return (
+      <form
+        action="/_search"
+        className="search-form input-group"
+      >
+        <InputGroup>
+        <AsyncTypeahead
+            ref={ref => this._typeahead = ref}
+            inputProps={{name: "q", autoComplete: "off"}}
+            isLoading={this.state.isLoading}
+            labelKey="path"
+            minLength={2}
+            options={this.state.pages}
+            placeholder="Input page name"
+            emptyLabel={emptyLabel}
+            align='left'
+            submitFormOnEnter={true}
+            onSearch={this.search}
+            onInputChange={this.onInputChange}
+            renderMenuItemChildren={this.renderMenuItemChildren}
+        />
+        {formClear}
+        <input
+            type="hidden"
+            value={this.state.searchedKeyword}
+            required />
+        </InputGroup>
+
+      </form>
+
+    );
+  }
+}
+
+NewPageNameInputter.propTypes = {
+};
+
+NewPageNameInputter.defaultProps = {
+};