pig-media-server 2 → 100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.babelrc +3 -0
  3. data/Gemfile +1 -0
  4. data/front/application.js +71 -0
  5. data/front/components/custom.js +35 -0
  6. data/front/components/head.js +38 -0
  7. data/front/components/index.js +23 -0
  8. data/front/components/item.js +63 -0
  9. data/front/components/latest.js +32 -0
  10. data/front/components/new_flag.js +29 -0
  11. data/front/components/no_match.js +10 -0
  12. data/front/components/pager.js +38 -0
  13. data/{javascripts → front}/components/player.js +7 -11
  14. data/{javascripts → front}/components/query_list.js +6 -23
  15. data/front/components/recommend.js +41 -0
  16. data/front/components/search.js +87 -0
  17. data/front/components/search_box.js +56 -0
  18. data/{javascripts → front}/components/watch.js +8 -5
  19. data/front/controller.js +22 -0
  20. data/{javascripts/event_dispatcher.js → front/models/base.js} +1 -5
  21. data/front/models/config.js +12 -0
  22. data/front/models/custom.js +41 -0
  23. data/front/models/custom_list.js +12 -0
  24. data/front/models/latest.js +60 -0
  25. data/front/models/list.js +76 -0
  26. data/front/models/playing.js +11 -0
  27. data/front/models/recent.js +34 -0
  28. data/front/models/recommend.js +13 -0
  29. data/front/models/session.js +16 -0
  30. data/lib/pig-media-server/api.rb +35 -3
  31. data/lib/pig-media-server/backup.rb +3 -7
  32. data/lib/pig-media-server/model/comic.rb +1 -1
  33. data/lib/pig-media-server/model/data.rb +85 -81
  34. data/lib/pig-media-server/model/data_use_rdb.rb +124 -0
  35. data/lib/pig-media-server/version.rb +1 -1
  36. data/lib/pig-media-server/views/bundle.js +48 -13
  37. data/package.json +13 -18
  38. data/webpack.build.js +25 -0
  39. data/webpack.config.js +30 -0
  40. metadata +34 -19
  41. data/gulpfile.js +0 -33
  42. data/javascripts/application.js +0 -117
  43. data/javascripts/components/head.js +0 -106
  44. data/javascripts/components/list.js +0 -104
  45. data/javascripts/components/new_flag.js +0 -23
  46. data/javascripts/components/sort.js +0 -64
  47. data/javascripts/controller.js +0 -62
  48. data/javascripts/custom_list.js +0 -14
  49. data/javascripts/recent.js +0 -34
  50. data/javascripts/utils.js +0 -22
  51. data/javascripts/video.js +0 -10
  52. /data/{javascripts → front}/chromecast.js +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 03172c241d9a720259504c431a3f24d3226dae28
4
- data.tar.gz: cbd95152cf18824e2898e32562d61942d1ac525a
3
+ metadata.gz: 1450f2afe845735323e207d6ca9c4aee910c8e86
4
+ data.tar.gz: 742fd37ce519d014b1cedd7d0b6a23a80fc43c21
5
5
  SHA512:
6
- metadata.gz: 3e086f8d14b480451cd612f665b3971862601eaae32c43bf7771337befc492653b68fd1d132873e10a6408896519956145bb331f76c0c0ef8273605cb0e7cf9a
7
- data.tar.gz: a95b3789b246eff2c3a0937def42c8983793b36696eec54229d52c2cc6b37d3687b38fccbf1d776e758b4e121fa4e851b94b338698d85d6defac8723b7a021dd
6
+ metadata.gz: e722dfe919ff6bbcc51c6b6ca5f4b428e92a4ccf000ed6c052a57772eebcacba43df284c20c26f5e0374b9be3130b9fe9d65531d5b2757cf1c1d81f4c27a08aa
7
+ data.tar.gz: 75f4766423d66479199963b34d50e15ff3ed9757636c24b93da160c3dec49c6dbe65943d1860a619d0579df69b8af00547e24eb58d2126b3ac0764eb2c9a21e2
data/.babelrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "presets": ["es2016-node5", "react", "es2015"]
3
+ }
data/Gemfile CHANGED
@@ -2,3 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in pig-media-server.gemspec
4
4
  gemspec
5
+ gem 'rake'
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { Router, Route, Link, browserHistory, IndexRoute } from 'react-router'
4
+
5
+ require('./chromecast.js');
6
+
7
+ import NoMatch from './components/no_match'
8
+ import Index from './components/index'
9
+ import Player from './components/player'
10
+ import SearchBox from './components/search_box'
11
+ import Head from './components/head'
12
+ import Latest from './components/latest'
13
+ import Recommend from './components/recommend'
14
+ import Custom from './components/custom'
15
+
16
+ import Config from './models/config'
17
+ import Session from './models/session'
18
+ import Recent from './models/recent'
19
+ import Playing from './models/playing'
20
+ import CustomList from './models/custom_list'
21
+
22
+ window.config = new Config();
23
+ window.session = new Session();
24
+ window.recent = new Recent();
25
+ window.custom_list = new CustomList();
26
+
27
+ window.playing = new Playing();
28
+
29
+ config.load();
30
+ session.load();
31
+ recent.load();
32
+ custom_list.load();
33
+
34
+ class Application extends React.Component{
35
+ constructor(props){
36
+ super(props);
37
+ this.state = {}
38
+ config.addEventListener('loaded', ()=>{ this.reload() });
39
+ session.addEventListener('loaded', ()=>{ this.reload() });
40
+ recent.addEventListener('loaded', ()=>{ this.reload() });
41
+ playing.addEventListener('updated', ()=>{ this.reload() });
42
+
43
+ }
44
+ reload(){
45
+ this.setState(this.state);
46
+ }
47
+ render(){
48
+ return <div>
49
+ <Player/>
50
+ <div id='all'>
51
+ <Head />
52
+ <SearchBox/>
53
+ {this.props.children}
54
+ </div>
55
+ </div>
56
+ }
57
+ }
58
+
59
+ var route = <Router history={browserHistory}>
60
+ <Route path="/" name='app' component={Application}>
61
+ <IndexRoute component={Index} />
62
+ <Route path='/recommend' component={Recommend} />
63
+ <Route path='/custom' component={Custom} />
64
+ <Route path='/latest' component={Latest} />
65
+ </Route>
66
+ </Router>
67
+
68
+ ReactDOM.render(route, document.querySelector("#application"));
69
+
70
+
71
+
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import CustomList from '../models/custom';
3
+
4
+ import Item from './item'
5
+
6
+ var custom = new CustomList();
7
+
8
+ export default class Custom extends React.Component {
9
+ constructor(props){
10
+ super(props);
11
+ custom.addEventListener('loaded', ()=>{this.reload()});
12
+ this.mounted = true;
13
+ }
14
+ reload(){ if(this.mounted){this.setState({});} }
15
+ componentDidMount(){
16
+ this.mounted = true;
17
+ $('title').text("Pig Media Server");
18
+ custom.load(this.props.location.query.name);
19
+ window.list = custom;
20
+ }
21
+ componentDidUpdate(prevProps){
22
+ if(this.props.location.query != prevProps.location.query){
23
+ custom.load(this.props.location.query.name);
24
+ }
25
+ }
26
+ componentWillUnmount(){ this.mounted = false; }
27
+ render(){
28
+ var items = custom.list.map((e)=>{
29
+ return <Item key={e.key} item={e} />
30
+ });
31
+ return <div>
32
+ <p>{items}</p>
33
+ </div>
34
+ }
35
+ }
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import {Link} from 'react-router'
3
+
4
+ class LoginAs extends React.Component {
5
+ render(){
6
+ return <span>Login as {this.props.user_id}</span>
7
+ }
8
+ }
9
+
10
+ class LoginLink extends React.Component {
11
+ render(){
12
+ return <a href='/sessions'>Login</a>
13
+ }
14
+ }
15
+
16
+ class Session extends React.Component {
17
+ render(){
18
+ return <div>
19
+ {session.data.user_id ?
20
+ <LoginAs user_id={session.data.user_id} /> :
21
+ <LoginLink />
22
+ }
23
+ </div>
24
+ }
25
+ }
26
+
27
+ export default class Head extends React.Component {
28
+ render(){
29
+ return <div>
30
+ <Session/>
31
+ <h2>
32
+ <Link to='/'>{config.data.page_title}</Link>
33
+ </h2>
34
+ </div>
35
+ }
36
+ }
37
+
38
+
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import Search from './search'
3
+
4
+ import QueryList from './query_list'
5
+
6
+ class Top extends React.Component {
7
+ render(){
8
+ return <div>
9
+ <QueryList query={this.props.query}/>
10
+ </div>
11
+ }
12
+ }
13
+
14
+ export default class Index extends React.Component {
15
+ is_search(){
16
+ return !!this.props.location.query.query;
17
+ }
18
+ render(){
19
+ return <div>
20
+ {this.is_search() ? <Search location={this.props.location}/> : <Top query={this.props.location.query}/> }
21
+ </div>
22
+ }
23
+ }
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+
3
+ import NewFlag from './new_flag'
4
+ import {Watch, ChromeCast} from './watch'
5
+
6
+ class CustomLinks extends React.Component{
7
+ render(){
8
+ return <span dangerouslySetInnerHTML={{__html: this.props.item.custom_links}}/>
9
+ }
10
+ }
11
+
12
+
13
+ export default class Item extends React.Component {
14
+ mtime(){
15
+ return this.props.item.mtime;
16
+ }
17
+
18
+ size_pretty(size){
19
+ var size = parseFloat(String(size));
20
+ var result = size;
21
+ if(size < 1024){
22
+ result = `${size} Bytes`
23
+ } else if(size < 1024*1024){
24
+ result = `${this.round(size / 1024)} KB`
25
+ } else if(size < 1024*1024*1024){
26
+ result = `${this.round(size / (1024*1024))} MB`
27
+ } else if(size < 1024*1024*1024*1024){
28
+ result = `${this.round(size / (1024*1024*1024))} GB`
29
+ }
30
+ return result
31
+ }
32
+
33
+ round(i){
34
+ i = i*10;
35
+ return Math.round(i)/10
36
+ }
37
+
38
+
39
+
40
+ render(){
41
+ var item = this.props.item;
42
+ var meta = `/meta/${this.props.item.key}`;
43
+ var sub = `/sub/${this.props.item.key}`;
44
+ return <span className='main_span'>
45
+ <NewFlag
46
+ item={this.props.item}
47
+ />
48
+ <a href={item.url} className='main_link'>{item.name}</a>&nbsp;
49
+
50
+ <Watch
51
+ item={this.props.item}
52
+ />
53
+ <ChromeCast
54
+ item={this.props.item}
55
+ />
56
+ <span className='mtime'>{this.mtime()}</span>&nbsp;
57
+ <span className='size'>{this.size_pretty(item.size)}</span>&nbsp;
58
+ <a className='meta' href={meta}>Meta</a>
59
+ <a className='meta' href={sub}>Sub</a>
60
+ <CustomLinks item={this.props.item} />
61
+ </span>
62
+ }
63
+ }
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import LatestList from '../models/latest';
3
+
4
+ import Item from './item'
5
+ import Pager from './pager'
6
+
7
+ var latest = new LatestList();
8
+
9
+ export default class Recommend extends React.Component {
10
+ constructor(props){
11
+ super(props);
12
+ latest.addEventListener('loaded', ()=>{this.reload()});
13
+ this.mounted = true;
14
+ }
15
+ reload(){ if(this.mounted){this.setState({});} }
16
+ componentDidMount(){
17
+ this.mounted = true;
18
+ $('title').text("Latest - Pig Media Server");
19
+ latest.load(this.props.location.query.page);
20
+ window.list = latest;
21
+ }
22
+ componentWillUnmount(){ this.mounted = false; }
23
+ render(){
24
+ var items = latest.list.map((e)=>{
25
+ return <Item key={e.key} item={e} />
26
+ });
27
+ return <div>
28
+ <p>{items}</p>
29
+ <Pager location={this.props.location} list={latest}/>
30
+ </div>
31
+ }
32
+ }
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+
3
+ export default class NewFlag extends React.Component {
4
+ constructor(props){
5
+ super(props);
6
+ recent.addEventListener('loaded', ()=>{ this.reload()});
7
+ }
8
+ reload(){
9
+ this.setState({});
10
+ }
11
+ ext(str){ return String(str).split('.').pop().toLowerCase(); }
12
+ is_new(){
13
+ var ext = this.ext(this.props.item.name);
14
+ if(ext == 'mp4' || ext == 'flv'){
15
+ var result = true;
16
+ jQuery.each(recent.data, (k,v)=>{
17
+ if(k == `movie/${this.props.item.key}`){ result = false }
18
+ });
19
+ return result
20
+ } else {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ render(){
26
+ var is_new = this.is_new();
27
+ return <span>{is_new ? <span className='new_flag' style={{color:'lime', "fontWeight":'bold'}}>New</span> : null }</span>
28
+ }
29
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+
3
+ export default class NoMatch extends React.Component {
4
+ render(){
5
+ return <div>
6
+ <h1>404 Not Found</h1>
7
+ <p>But I return 200...</p>
8
+ </div>
9
+ }
10
+ }
@@ -0,0 +1,38 @@
1
+ import React from 'react'
2
+ import jQuery from 'jquery'
3
+ import {browserHistory} from 'react-router'
4
+
5
+ export default class Pager extends React.Component {
6
+ constructor(props){
7
+ super(props);
8
+ this.page = 1;
9
+ var page = this.props.location.query.page;
10
+ if(page){ this.page = parseInt(page)}
11
+ this.bind();
12
+ }
13
+
14
+ bind(){
15
+ //this.click();
16
+ }
17
+ prev(){
18
+ var params = this.props.location.query;
19
+ var page = this.props.location.query.page;
20
+ if(page){ this.page = parseInt(page)}
21
+ page = page - 1;
22
+ if(page < 1){page = 1}
23
+ params.page = page;
24
+ browserHistory.push("/?"+jQuery.param(params));
25
+ }
26
+ click(){
27
+ this.page ++;
28
+ var params = this.props.location.query;
29
+ params.page = this.page;
30
+ this.props.list.paginate(this.page);
31
+ history.pushState('', '', "/?"+jQuery.param(params));
32
+ }
33
+
34
+ render(){ return <span>
35
+ {(this.page > 1) ? <a href='javascript:void(0)' onClick={()=> this.prev()}>Prev</a> : null } <a href='javascript:void(0)' onClick={()=> this.click()}>Next</a>
36
+ </span>
37
+ }
38
+ }
@@ -1,12 +1,14 @@
1
- class Player extends React.Component {
1
+ import React from 'react';
2
+
3
+ export default class Player extends React.Component {
2
4
  constructor(props){
3
5
  super(props);
4
6
  this.current_url = '';
5
7
  }
6
- close(){ this.props.state.models.video.set(null); }
8
+ close(){ playing.set(null); }
7
9
  dom(){ return this.refs.video; }
8
10
 
9
- video(){ return this.props.state.models.video.item; }
11
+ video(){ return playing.item; }
10
12
 
11
13
  video_url(){
12
14
  var url = null;
@@ -28,10 +30,7 @@ class Player extends React.Component {
28
30
  }
29
31
 
30
32
  next(){
31
- var next = false;
32
- var result;
33
- var index = $.map(this.props.state.items, (e,i)=>{return e.key}).indexOf(this.props.state.models.video.item.key);
34
- this.props.state.models.video.set(this.props.state.items[index-1]);
33
+ if(!!list){ list.next() };
35
34
  }
36
35
 
37
36
  play(prev){
@@ -40,8 +39,7 @@ class Player extends React.Component {
40
39
  node.addEventListener('canplay', (e)=>{
41
40
  var target = e.target;
42
41
  target.play();
43
- this.props.state.models.recent.use(`movie/${this.video().key}`);
44
-
42
+ recent.use(`movie/${this.video().key}`);
45
43
  });
46
44
  node.addEventListener('ended', (e)=>{ this.next(); });
47
45
  node.load();
@@ -167,5 +165,3 @@ class Player extends React.Component {
167
165
  </div>
168
166
  }
169
167
  }
170
-
171
- window.Player = Player;
@@ -1,10 +1,9 @@
1
+ import React from 'react'
2
+ import {Link} from 'react-router'
3
+
1
4
  class Item extends React.Component {
2
5
  url(){ return `/?query=${encodeURIComponent(this.props.query)}` }
3
6
 
4
- click(){
5
- this.props.state.open(this.url());
6
- }
7
-
8
7
  delete_query(){
9
8
  if(confirm('Really?')){
10
9
  $.post("/api/r/delete_query_list", {query: this.props.query}).done((data)=>{
@@ -14,9 +13,7 @@ class Item extends React.Component {
14
13
  }
15
14
  render(){
16
15
  return <span className='main_span'>
17
- <a href='javascript:void(0)' onClick={()=> this.click()}>
18
- {this.props.query}
19
- </a>
16
+ <Link to={this.url()}> {this.props.query} </Link>
20
17
  <a href='javascript:void(0)' className='delete' onClick={()=> this.delete_query()}>
21
18
  Delete
22
19
  </a>
@@ -24,12 +21,11 @@ class Item extends React.Component {
24
21
  }
25
22
  }
26
23
 
27
- class QueryList extends React.Component {
24
+ export default class QueryList extends React.Component {
28
25
  constructor(props){
29
26
  super(props);
30
27
  this.state = {};
31
28
  this.state.list = [];
32
- this.controller = new Controller()
33
29
  }
34
30
 
35
31
  update_list(){
@@ -43,26 +39,13 @@ class QueryList extends React.Component {
43
39
  this.update_list();
44
40
  }
45
41
 
46
- show(){
47
- if(location.pathname == '/'){
48
- if(!this.controller.query()){
49
- return true;
50
- } else {
51
- return false;
52
- }
53
- } else {
54
- return false
55
- }
56
- }
57
-
58
42
  render(){
59
43
  var items = $.map(this.state.list, (query)=>{
60
44
  return <Item key={query} query={query} state={this.props.state} update_list={()=> this.update_list()}/>
61
45
  });
62
46
  return <div>
63
- {this.show() ? items : null}
47
+ {items}
64
48
  </div>
65
49
  }
66
50
  }
67
51
 
68
- window.QueryList = QueryList;
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import RecommendList from '../models/recommend';
3
+
4
+ import Item from './item'
5
+
6
+ var recommend = new RecommendList();
7
+
8
+ export default class Recommend extends React.Component {
9
+ constructor(props){
10
+ super(props);
11
+ recommend.addEventListener('loaded', ()=>{this.reload()});
12
+ this.mounted = true;
13
+ }
14
+ reload(){ if(this.mounted){this.setState({});} }
15
+ componentDidMount(){
16
+ this.mounted = true;
17
+ $('title').text("Recommned - Pig Media Server");
18
+ recommend.load(this.props.location.query.name);
19
+ window.list = recommend;
20
+ }
21
+ componentWillUnmount(){ this.mounted = false; }
22
+ render(){
23
+ var items = recommend.list.map((e)=>{
24
+ return <Item key={e.key} item={e} />
25
+ });
26
+ return <div>
27
+ <p>{items}</p>
28
+ </div>
29
+ }
30
+
31
+ next(){
32
+ var index = this.list.map((e,i)=>{return e.key}).indexOf(playing.item.key);
33
+ var item = null
34
+ while(index > -1){
35
+ index = index - 1;
36
+ item = this.list[index];
37
+ if(item.type == 'video'){break}
38
+ }
39
+ if(item){ playing.set(item); }
40
+ }
41
+ }
@@ -0,0 +1,87 @@
1
+ import React from 'react'
2
+ import {Link} from 'react-router'
3
+ import jQuery from 'jquery'
4
+
5
+ import SearchList from '../models/list'
6
+
7
+ import Item from './item'
8
+ import Pager from './pager'
9
+
10
+ var list = new SearchList();
11
+
12
+ class QuerySave extends React.Component{
13
+ constructor(props){
14
+ super(props);
15
+ }
16
+
17
+ click(){
18
+ jQuery.post("/api/r/query_list", {query: this.props.query})
19
+ }
20
+ render(){
21
+ return <span>
22
+ <a href='javascript:void(0)' onClick={()=> this.click()}>Save Query</a>
23
+ </span>
24
+ }
25
+ }
26
+
27
+ class Sort extends React.Component{
28
+ can_change_order(){ return !!this.props.location.query.sort }
29
+ change_order(order){
30
+ var params = this.props.location.query;
31
+ params.order = order;
32
+ history.pushState('','',"/?"+jQuery.param(params));
33
+ list.search(params);
34
+ }
35
+ render(){
36
+ return <p>
37
+ <Link to={`/?query=${this.props.query}&sort=date`}>Sort By Date</Link>
38
+ <Link to={`/?query=${this.props.query}&sort=name`}>Sort By Name</Link>
39
+ {this.can_change_order() ?
40
+ <span>
41
+ <a href="javascript:void(0)" onClick={()=> this.change_order('ascending')}>Ascending</a>
42
+ <a href="javascript:void(0)" onClick={()=> this.change_order('descending')}>Descending</a>
43
+ </span>
44
+ : null
45
+ }
46
+ <QuerySave query={this.props.query} />
47
+ </p>
48
+ }
49
+
50
+ }
51
+
52
+ export default class Search extends React.Component {
53
+ constructor(props){
54
+ super(props);
55
+ this.state = {}
56
+ this.mounted = true;
57
+ list.addEventListener('loaded', ()=>{this.reload()});
58
+ }
59
+ reload(){ if(this.mounted){this.setState({});} }
60
+
61
+ search(){
62
+ list.search(this.props.location.query)
63
+ $('title').text(`${this.props.location.query.query} - Pig Media Server`);
64
+ }
65
+ componentDidMount(){
66
+ this.mounted = true;
67
+ window.list = list;
68
+ this.search();
69
+ }
70
+ componentDidUpdate(prevProps){
71
+ if(this.props.location.query != prevProps.location.query){
72
+ this.search();
73
+ }
74
+ }
75
+ componentWillUnmount(){ this.mounted = false; }
76
+
77
+ render(){
78
+ var items = list.list.map((e)=>{
79
+ return <Item key={e.key} item={e} />
80
+ });
81
+ return <div>
82
+ <Sort query={this.props.location.query.query} location={this.props.location}/>
83
+ <p>{items}</p>
84
+ <Pager location={this.props.location} list={list}/>
85
+ </div>
86
+ }
87
+ }
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import {Link, browserHistory} from 'react-router'
3
+ import jQuery from 'jquery'
4
+
5
+ import Controller from '../controller'
6
+
7
+ var controller = new Controller();
8
+
9
+ class CustomList extends React.Component {
10
+ url(){ return `/custom?name=${encodeURIComponent(this.props.name)}` }
11
+ render(){
12
+ return <Link to={this.url()}>{this.props.name}</Link>
13
+ }
14
+ }
15
+
16
+ class Recommend extends React.Component {
17
+ render(){
18
+ return <span>
19
+ {!!localStorage.user_id ? <Link to={`/recommend?name=${localStorage.user_id}`}><b>Recommend</b></Link> : null}
20
+ </span>
21
+ }
22
+ }
23
+
24
+
25
+ export default class SearchBox extends React.Component {
26
+ submit(event){
27
+ event.preventDefault();
28
+ var query = this.refs.input.value;
29
+ var url = `/?query=${encodeURIComponent(query)}`;
30
+ browserHistory.push(url);
31
+ }
32
+ click(e){ this.props.state.open(e.target.dataset.url); }
33
+
34
+ componentDidUpdate(){
35
+ var query = this.query();
36
+ if(query == 'undefined' || query == 'null' || !query){query = ''}
37
+ this.refs.input.value = query;
38
+ }
39
+
40
+ change(){ }
41
+ query(){ return decodeURIComponent(controller.query()) }
42
+
43
+ render(){
44
+ var query = this.query();
45
+ if(query == 'undefined' || query == 'null' || !query){query = ''}
46
+ var c_list = jQuery.map(custom_list.data, (v,k)=>{return <CustomList key={k} name={k} state={this.props.state}/>});
47
+ return <form onSubmit={(e)=> this.submit(e)}>
48
+ <input ref='input' defaultValue={query} onChange={()=>{this.change()}}/><button>Search</button>
49
+ <Link to='/latest'>Latest</Link>
50
+ <Link to='/config'>Config</Link>
51
+ <Recommend state={this.props.state} />
52
+ <br />
53
+ {c_list}
54
+ </form>
55
+ }
56
+ }