edit.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /**
  2. * @author oldj
  3. * @blog https://oldj.net
  4. */
  5. 'use strict'
  6. import React from 'react'
  7. import MyFrame from './frame'
  8. import classnames from 'classnames'
  9. import Group from './group'
  10. import Agent from '../Agent'
  11. import makeId from '../../app/libs/make-id'
  12. import './edit.less'
  13. export default class EditPrompt extends React.Component {
  14. constructor (props) {
  15. super(props)
  16. this.state = {
  17. show: false,
  18. is_add: true,
  19. where: 'local',
  20. title: '',
  21. url: '',
  22. last_refresh: null,
  23. refresh_interval: 0,
  24. is_loading: false,
  25. include: []
  26. }
  27. this.current_hosts = null
  28. }
  29. tryToFocus () {
  30. let el = this.refs.body && this.refs.body.querySelector('input[type=text]')
  31. el && el.focus()
  32. }
  33. clear () {
  34. this.setState({
  35. where: 'local',
  36. title: '',
  37. url: '',
  38. last_refresh: null,
  39. refresh_interval: 0
  40. })
  41. }
  42. componentDidMount () {
  43. Agent.on('add_hosts', () => {
  44. this.setState({
  45. show: true,
  46. is_add: true
  47. })
  48. setTimeout(() => {
  49. this.tryToFocus()
  50. }, 100)
  51. })
  52. Agent.on('edit_hosts', (hosts) => {
  53. this.current_hosts = hosts
  54. let include = hosts.include || []
  55. include = Array.from(new Set(include))
  56. this.setState({
  57. id: hosts.id,
  58. show: true,
  59. is_add: false,
  60. where: hosts.where || 'local',
  61. title: hosts.title || '',
  62. url: hosts.url || '',
  63. last_refresh: hosts.last_refresh || null,
  64. refresh_interval: hosts.refresh_interval || 0,
  65. include
  66. })
  67. setTimeout(() => {
  68. this.tryToFocus()
  69. }, 100)
  70. })
  71. Agent.on('loading_done', (old_hosts, data) => {
  72. if (old_hosts === this.current_hosts) {
  73. this.setState({
  74. last_refresh: data.last_refresh,
  75. is_loading: false
  76. })
  77. Agent.emit('hosts_refreshed', data, this.current_hosts)
  78. }
  79. })
  80. Agent.on('list_updated', list => {
  81. let hosts = list.find(i => i.id === this.state.id)
  82. if (hosts) {
  83. this.current_hosts = hosts
  84. this.setState({
  85. last_refresh: hosts.last_refresh
  86. })
  87. }
  88. })
  89. }
  90. onOK () {
  91. this.setState({
  92. title: (this.state.title || '').replace(/^\s+|\s+$/g, ''),
  93. url: (this.state.url || '').replace(/^\s+|\s+$/g, '')
  94. })
  95. if (this.state.title === '') {
  96. this.refs.title.focus()
  97. return false
  98. }
  99. if (this.state.where === 'remote' && this.state.url === '') {
  100. this.refs.url.focus()
  101. return false
  102. }
  103. let new_id = makeId()
  104. let data = Object.assign({}, this.current_hosts, this.state,
  105. this.state.is_add ? {
  106. id: new_id,
  107. content: `# ${this.state.title}`,
  108. on: false
  109. } : {})
  110. if (!data.id) data.id = new_id
  111. if (this.state.is_add) {
  112. this.props.justAdd(new_id)
  113. }
  114. delete data['is_add']
  115. Agent.emit('update_hosts', data)
  116. this.setState({
  117. show: false
  118. })
  119. this.clear()
  120. }
  121. onCancel () {
  122. this.setState({
  123. show: false
  124. })
  125. this.clear()
  126. }
  127. confirmDel () {
  128. let {lang} = this.props
  129. if (!confirm(lang.confirm_del)) return
  130. Agent.emit('del_hosts', this.current_hosts)
  131. this.setState({
  132. show: false
  133. })
  134. this.clear()
  135. }
  136. updateInclude (include) {
  137. this.setState({include})
  138. }
  139. getRefreshOptions () {
  140. let {lang} = this.props
  141. let k = [
  142. [0, `${lang.never}`],
  143. [1, `1 ${lang.hour}`],
  144. [24, `24 ${lang.hours}`],
  145. [168, `7 ${lang.days}`]
  146. ]
  147. if (Agent.IS_DEV) {
  148. k.splice(1, 0, [0.002778, `10s (for DEV)`]) // dev test only
  149. }
  150. return k.map(([v, n], idx) => {
  151. return (
  152. <option value={v} key={idx}>{n}</option>
  153. )
  154. })
  155. }
  156. getEditOperations () {
  157. if (this.state.is_add) return null
  158. let {lang} = this.props
  159. return (
  160. <div>
  161. <div className="ln">
  162. <a href="#" className="del"
  163. onClick={this.confirmDel.bind(this)}
  164. >
  165. <i className="iconfont icon-delete"/>
  166. <span>{lang.del_hosts}</span>
  167. </a>
  168. </div>
  169. </div>
  170. )
  171. }
  172. refresh () {
  173. if (this.state.is_loading) return
  174. Agent.emit('check_hosts_refresh', this.current_hosts)
  175. this.setState({
  176. is_loading: true
  177. }, () => {
  178. setTimeout(() => {
  179. this.setState({
  180. is_loading: false
  181. })
  182. }, 1000)
  183. })
  184. }
  185. renderGroup () {
  186. if (this.state.where !== 'group') return null
  187. return <Group
  188. list={this.props.list}
  189. include={this.state.include}
  190. updateInclude={this.updateInclude.bind(this)}
  191. />
  192. }
  193. renderRemoteInputs () {
  194. if (this.state.where !== 'remote') return null
  195. let {lang} = this.props
  196. return (
  197. <div className="remote-ipts">
  198. <div className="ln">
  199. <div className="title">{lang.url}</div>
  200. <div className="cnt">
  201. <input
  202. type="text"
  203. ref="url"
  204. value={this.state.url}
  205. placeholder="http://"
  206. onChange={(e) => this.setState({url: e.target.value})}
  207. onKeyDown={(e) => (e.keyCode === 13 && this.onOK()) ||
  208. (e.keyCode === 27 && this.onCancel())}
  209. />
  210. </div>
  211. </div>
  212. <div className="ln">
  213. <div className="title">{lang.auto_refresh}</div>
  214. <div className="cnt">
  215. <select
  216. value={this.state.refresh_interval}
  217. onChange={(e) => this.setState(
  218. {refresh_interval: parseFloat(e.target.value) || 0})}
  219. >
  220. {this.getRefreshOptions()}
  221. </select>
  222. <i
  223. className={classnames({
  224. iconfont: 1,
  225. 'icon-refresh': 1,
  226. 'invisible': !this.current_hosts ||
  227. this.state.url !== this.current_hosts.url,
  228. 'loading': this.state.is_loading
  229. })}
  230. title={lang.refresh}
  231. onClick={() => this.refresh()}
  232. />
  233. <span className="last-refresh">
  234. {lang.last_refresh}
  235. {this.state.last_refresh || 'N/A'}
  236. </span>
  237. </div>
  238. </div>
  239. </div>
  240. )
  241. }
  242. body () {
  243. let {lang} = this.props
  244. return (
  245. <div ref="body">
  246. <div className="ln">
  247. <input id="ipt-local" type="radio" name="where" value="local"
  248. checked={this.state.where === 'local'}
  249. onChange={(e) => this.setState({where: e.target.value})}
  250. />
  251. <label htmlFor="ipt-local">{lang.where_local}</label>
  252. <input id="ipt-remote" type="radio" name="where" value="remote"
  253. checked={this.state.where === 'remote'}
  254. onChange={(e) => this.setState({where: e.target.value})}
  255. />
  256. <label htmlFor="ipt-remote">{lang.where_remote}</label>
  257. <input id="ipt-group" type="radio" name="where" value="group"
  258. checked={this.state.where === 'group'}
  259. onChange={(e) => this.setState({where: e.target.value})}
  260. />
  261. <label htmlFor="ipt-group">{lang.where_group}</label>
  262. </div>
  263. <div className="ln">
  264. <div className="title">{lang.hosts_title}</div>
  265. <div className="cnt">
  266. <input
  267. type="text"
  268. ref="title"
  269. name="text"
  270. value={this.state.title}
  271. onChange={(e) => this.setState({title: e.target.value})}
  272. onKeyDown={(e) => (e.keyCode === 13 && this.onOK() ||
  273. e.keyCode === 27 && this.onCancel())}
  274. />
  275. </div>
  276. </div>
  277. {this.renderRemoteInputs()}
  278. {this.renderGroup()}
  279. {this.getEditOperations()}
  280. </div>
  281. )
  282. }
  283. render () {
  284. let {lang} = this.props
  285. return (
  286. <MyFrame
  287. show={this.state.show}
  288. head={lang[this.state.is_add ? 'add_hosts' : 'edit_hosts']}
  289. body={this.body()}
  290. onOK={() => this.onOK()}
  291. onCancel={() => this.onCancel()}
  292. lang={this.props.lang}
  293. />
  294. )
  295. }
  296. }