edit.jsx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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('list_updated', list => {
  72. let hosts = list.find(i => i.id === this.state.id)
  73. if (hosts) {
  74. this.current_hosts = hosts
  75. this.setState({last_refresh: hosts.last_refresh})
  76. setTimeout(() => this.setState({is_loading: false}), 500)
  77. }
  78. })
  79. Agent.on('refresh_end', (id) => {
  80. if (this.state.is_loading) {
  81. this.setState({
  82. is_loading: false
  83. })
  84. if (id && id === this.current_hosts.id) {
  85. this.setState({
  86. last_refresh: this.current_hosts.last_refresh
  87. })
  88. }
  89. }
  90. })
  91. }
  92. onOK () {
  93. this.setState({
  94. title: (this.state.title || '').replace(/^\s+|\s+$/g, ''),
  95. url: (this.state.url || '').replace(/^\s+|\s+$/g, '')
  96. })
  97. if (this.state.title === '') {
  98. this.refs.title.focus()
  99. return false
  100. }
  101. if (this.state.where === 'remote' && this.state.url === '') {
  102. this.refs.url.focus()
  103. return false
  104. }
  105. let new_id = makeId()
  106. let data = Object.assign({}, this.current_hosts, this.state,
  107. this.state.is_add ? {
  108. id: new_id,
  109. content: `# ${this.state.title}`,
  110. on: false
  111. } : {})
  112. if (!data.id) data.id = new_id
  113. if (this.state.is_add) {
  114. this.props.justAdd(new_id)
  115. }
  116. delete data['is_add']
  117. Agent.emit('update_hosts', data)
  118. this.setState({
  119. show: false
  120. })
  121. this.clear()
  122. }
  123. onCancel () {
  124. this.setState({
  125. show: false
  126. })
  127. this.clear()
  128. }
  129. confirmDel () {
  130. let {lang} = this.props
  131. if (!confirm(lang.confirm_del)) return
  132. Agent.emit('del_hosts', this.current_hosts)
  133. this.setState({
  134. show: false
  135. })
  136. this.clear()
  137. }
  138. updateInclude (include) {
  139. this.setState({include})
  140. }
  141. getRefreshOptions () {
  142. let {lang} = this.props
  143. let k = [
  144. [0, `${lang.never}`],
  145. [1, `1 ${lang.hour}`],
  146. [24, `24 ${lang.hours}`],
  147. [168, `7 ${lang.days}`]
  148. ]
  149. if (Agent.IS_DEV) {
  150. k.splice(1, 0, [0.002778, `10s (for DEV)`]) // dev test only
  151. }
  152. return k.map(([v, n], idx) => {
  153. return (
  154. <option value={v} key={idx}>{n}</option>
  155. )
  156. })
  157. }
  158. getEditOperations () {
  159. if (this.state.is_add) return null
  160. let {lang} = this.props
  161. return (
  162. <div>
  163. <div className="ln">
  164. <a href="#" className="del"
  165. onClick={this.confirmDel.bind(this)}
  166. >
  167. <i className="iconfont icon-delete"/>
  168. <span>{lang.del_hosts}</span>
  169. </a>
  170. </div>
  171. </div>
  172. )
  173. }
  174. refresh () {
  175. if (this.state.is_loading) return
  176. Agent.emit('check_hosts_refresh', this.current_hosts)
  177. this.setState({
  178. is_loading: true
  179. })
  180. }
  181. renderGroup () {
  182. if (this.state.where !== 'group') return null
  183. return <Group
  184. list={this.props.list}
  185. include={this.state.include}
  186. updateInclude={this.updateInclude.bind(this)}
  187. />
  188. }
  189. renderRemoteInputs () {
  190. if (this.state.where !== 'remote') return null
  191. let {lang} = this.props
  192. return (
  193. <div className="remote-ipts">
  194. <div className="ln">
  195. <div className="title">{lang.url}</div>
  196. <div className="cnt">
  197. <input
  198. type="text"
  199. ref="url"
  200. value={this.state.url}
  201. placeholder="http://"
  202. onChange={(e) => this.setState({url: e.target.value})}
  203. onKeyDown={(e) => (e.keyCode === 13 && this.onOK()) || (e.keyCode === 27 && this.onCancel())}
  204. />
  205. </div>
  206. </div>
  207. <div className="ln">
  208. <div className="title">{lang.auto_refresh}</div>
  209. <div className="cnt">
  210. <select
  211. value={this.state.refresh_interval}
  212. onChange={(e) => this.setState(
  213. {refresh_interval: parseFloat(e.target.value) || 0})}
  214. >
  215. {this.getRefreshOptions()}
  216. </select>
  217. <i
  218. className={classnames({
  219. iconfont: 1,
  220. 'icon-refresh': 1,
  221. 'invisible': !this.current_hosts || this.state.url !== this.current_hosts.url,
  222. 'loading': this.state.is_loading
  223. })}
  224. title={lang.refresh}
  225. onClick={() => this.refresh()}
  226. />
  227. <span className="last-refresh">
  228. {lang.last_refresh}
  229. {this.state.last_refresh || 'N/A'}
  230. </span>
  231. </div>
  232. </div>
  233. </div>
  234. )
  235. }
  236. body () {
  237. let {lang} = this.props
  238. return (
  239. <div ref="body">
  240. <div className="ln">
  241. <input id="ipt-local" type="radio" name="where" value="local"
  242. checked={this.state.where === 'local'}
  243. onChange={(e) => this.setState({where: e.target.value})}
  244. />
  245. <label htmlFor="ipt-local">{lang.where_local}</label>
  246. <input id="ipt-remote" type="radio" name="where" value="remote"
  247. checked={this.state.where === 'remote'}
  248. onChange={(e) => this.setState({where: e.target.value})}
  249. />
  250. <label htmlFor="ipt-remote">{lang.where_remote}</label>
  251. <input id="ipt-group" type="radio" name="where" value="group"
  252. checked={this.state.where === 'group'}
  253. onChange={(e) => this.setState({where: e.target.value})}
  254. />
  255. <label htmlFor="ipt-group">{lang.where_group}</label>
  256. </div>
  257. <div className="ln">
  258. <div className="title">{lang.hosts_title}</div>
  259. <div className="cnt">
  260. <input
  261. type="text"
  262. ref="title"
  263. name="text"
  264. value={this.state.title}
  265. onChange={(e) => this.setState({title: e.target.value})}
  266. onKeyDown={(e) => (e.keyCode === 13 && this.onOK() || e.keyCode === 27 && this.onCancel())}
  267. />
  268. </div>
  269. </div>
  270. {this.renderRemoteInputs()}
  271. {this.renderGroup()}
  272. {this.getEditOperations()}
  273. </div>
  274. )
  275. }
  276. render () {
  277. let {lang} = this.props
  278. return (
  279. <MyFrame
  280. show={this.state.show}
  281. head={lang[this.state.is_add ? 'add_hosts' : 'edit_hosts']}
  282. body={this.body()}
  283. onOK={() => this.onOK()}
  284. onCancel={() => this.onCancel()}
  285. lang={this.props.lang}
  286. />
  287. )
  288. }
  289. }