Просмотр исходного кода

Add temporary data bind with jQuery and react.js

Sotaro KARASAWA 9 лет назад
Родитель
Сommit
c1aedfe715
3 измененных файлов с 137 добавлено и 5 удалено
  1. 8 4
      lib/views/page_list.html
  2. 2 1
      resource/js/app.js
  3. 127 0
      resource/js/components/PageListSearch.js

+ 8 - 4
lib/views/page_list.html

@@ -15,17 +15,14 @@
     {% endif %}
     {% endif %}
     <h1 class="title">
     <h1 class="title">
       <span class="" id="revision-path">{{ path|insertSpaceToEachSlashes }}</span>
       <span class="" id="revision-path">{{ path|insertSpaceToEachSlashes }}</span>
-      {#
       {% if searchConfigured() && path != '/' %}
       {% if searchConfigured() && path != '/' %}
       <div class="form-group form-group-sm has-feedback search-input-group" data-toggle="tooltip" data-placement="bottom" title="{{ path }} 以下から検索">
       <div class="form-group form-group-sm has-feedback search-input-group" data-toggle="tooltip" data-placement="bottom" title="{{ path }} 以下から検索">
         <label class="control-label sr-only" for="inputSuccess5">Search</label>
         <label class="control-label sr-only" for="inputSuccess5">Search</label>
         <input
         <input
-        type="text" class="search-listpage-input form-control" data-path="{{ path }}"
-        >
+        type="text" class="search-listpage-input form-control" data-path="{{ path }}" id="page-list-search-form" >
         <i class="form-control-feedback search-listpage-icon fa fa-search"></i>
         <i class="form-control-feedback search-listpage-icon fa fa-search"></i>
       </div>
       </div>
       {% endif %}
       {% endif %}
-      #}
     </h1>
     </h1>
   </header>
   </header>
 </div>
 </div>
@@ -37,6 +34,13 @@
 {% block content_main_before %}
 {% block content_main_before %}
 {% endblock %}
 {% endblock %}
 
 
+{# page-list-search should be fully managed by react.js,
+ # but now the header and page list content is rendered separately by the server,
+ # so now bind the values through the hidden fields.
+ #}
+<div id="page-list-search">
+</div>
+
 <div class="page-list content-main {% if req.body.pageForm %}on-edit{% endif %}"
 <div class="page-list content-main {% if req.body.pageForm %}on-edit{% endif %}"
   id="content-main"
   id="content-main"
   data-path="{{ path }}"
   data-path="{{ path }}"

+ 2 - 1
resource/js/app.js

@@ -3,11 +3,12 @@ import ReactDOM from 'react-dom';
 
 
 import HeaderSearchBox  from './components/HeaderSearchBox';
 import HeaderSearchBox  from './components/HeaderSearchBox';
 import SearchPage  from './components/SearchPage';
 import SearchPage  from './components/SearchPage';
-//import ListPageSearch  from './components/ListPageSearch';
+import PageListSearch  from './components/PageListSearch';
 
 
 const componentMappings = {
 const componentMappings = {
   'search-top': <HeaderSearchBox />,
   'search-top': <HeaderSearchBox />,
   'search-page': <SearchPage />,
   'search-page': <SearchPage />,
+  'page-list-search': <PageListSearch />,
 };
 };
 
 
 Object.keys(componentMappings).forEach((key) => {
 Object.keys(componentMappings).forEach((key) => {

+ 127 - 0
resource/js/components/PageListSearch.js

@@ -0,0 +1,127 @@
+// This is the root component for #page-list-search
+
+import React from 'react';
+import axios from 'axios'
+
+export default class PageListSearch extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      keyword: '',
+    }
+
+    //this.changeURL = this.changeURL.bind(this);
+    this.search = this.search.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+    this.ticker = null;
+  }
+
+  componentDidMount() {
+    // This is temporary data bind
+    this.ticker = setInterval(this.pageListObserver.bind(this), 1000);
+  }
+
+  componentWillUnmount() {
+    clearInterval(this.ticker);
+  }
+
+  pageListObserver() {
+    let value = $('#page-list-search-form').val();
+    this.setState({keyword: value});
+    this.search();
+  }
+
+  static getQueryByLocation(location) {
+    let search = location.search || '';
+    let query = {};
+
+    search.replace(/^\?/, '').split('&').forEach(function(element) {
+      let queryParts = element.split('=');
+      query[queryParts[0]] = decodeURIComponent(queryParts[1]).replace(/\+/g, ' ');
+    });
+
+    return query;
+  }
+
+  handleChange(event) {
+    // this is not fired now because of force-data-bound by jQuery
+    const keyword = event.target.value;
+    this.setState({keyword});
+    console.log('Changed');
+  }
+
+  changeURL(keyword, refreshHash) {
+    let hash = location.hash || '';
+    // TODO 整理する
+    if (refreshHash || this.state.searchedKeyword !== '') {
+        hash = '';
+    }
+    if (window.history && window.history.pushState){
+      window.history.pushState('', `Search - ${keyword}`, `/_search?q=${keyword}${hash}`);
+    }
+  }
+
+  search() {
+    const keyword = this.state.keyword;
+
+    console.log('Search with', keyword);
+    return true ;
+
+    if (keyword === '') {
+      this.setState({
+        searchingKeyword: '',
+        searchedPages: [],
+      });
+
+      return true;
+    }
+
+    this.setState({
+      searchingKeyword: keyword,
+    });
+
+    axios.get('/_api/search', {params: {q: keyword}})
+    .then((res) => {
+      if (res.data.ok) {
+        this.changeURL(keyword);
+
+        this.setState({
+          searchedKeyword: keyword,
+          searchedPages: res.data.data,
+          searchResultMeta: res.data.meta,
+        });
+      }
+
+
+      // TODO error
+    })
+    .catch((res) => {
+      // TODO error
+    });
+  };
+
+  render() {
+    return (
+      <div>
+        <input
+          type="hidden"
+          name="q"
+          value={this.state.keyword}
+          onChange={this.handleChange}
+          className="form-control"
+          />
+      </div>
+    );
+  }
+}
+
+PageListSearch.propTypes = {
+  query: React.PropTypes.object,
+};
+PageListSearch.defaultProps = {
+  //pollInterval: 1000,
+  query: PageListSearch.getQueryByLocation(location || {}),
+};
+