@electerm/electerm-react 1.34.30

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 (273) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/client/common/auto-complete-data-mapper.js +6 -0
  4. package/client/common/byte-format.js +14 -0
  5. package/client/common/class.js +52 -0
  6. package/client/common/clipboard.js +49 -0
  7. package/client/common/constants.js +308 -0
  8. package/client/common/create-lang-edit-link.js +7 -0
  9. package/client/common/create-title.js +29 -0
  10. package/client/common/db-fix.js +24 -0
  11. package/client/common/db.js +155 -0
  12. package/client/common/download-mirrors.js +10 -0
  13. package/client/common/download.js +16 -0
  14. package/client/common/error-handler.jsx +27 -0
  15. package/client/common/fetch-from-server.js +47 -0
  16. package/client/common/fetch.jsx +71 -0
  17. package/client/common/find-bookmark-group-id.js +15 -0
  18. package/client/common/find-parent.js +30 -0
  19. package/client/common/form-layout.js +27 -0
  20. package/client/common/fs.js +21 -0
  21. package/client/common/get-proxy.js +8 -0
  22. package/client/common/id-with-stamp.js +10 -0
  23. package/client/common/index-sorter.js +4 -0
  24. package/client/common/init-setting-item.js +32 -0
  25. package/client/common/is-absolute-path.js +3 -0
  26. package/client/common/is-ip.js +16 -0
  27. package/client/common/is-valid-path.js +7 -0
  28. package/client/common/key-control-pressed.js +13 -0
  29. package/client/common/key-pressed.js +13 -0
  30. package/client/common/key-shift-pressed.js +7 -0
  31. package/client/common/mode2permission.js +81 -0
  32. package/client/common/new-terminal.js +31 -0
  33. package/client/common/parse-int10.js +3 -0
  34. package/client/common/parse-json-safe.js +11 -0
  35. package/client/common/pass-enc.js +25 -0
  36. package/client/common/post-msg.js +3 -0
  37. package/client/common/pre.js +156 -0
  38. package/client/common/promise-timeout.js +27 -0
  39. package/client/common/resolve.js +31 -0
  40. package/client/common/run-idle.js +1 -0
  41. package/client/common/safe-local-storage.js +35 -0
  42. package/client/common/safe-name.js +19 -0
  43. package/client/common/sftp.js +74 -0
  44. package/client/common/terminal-theme.js +158 -0
  45. package/client/common/test-connection.js +12 -0
  46. package/client/common/time.js +30 -0
  47. package/client/common/to-simple-obj.js +5 -0
  48. package/client/common/track.js +7 -0
  49. package/client/common/transfer.js +76 -0
  50. package/client/common/trzsz.js +62 -0
  51. package/client/common/ui-theme.js +44 -0
  52. package/client/common/uid.js +5 -0
  53. package/client/common/update-check.js +79 -0
  54. package/client/common/upgrade.js +68 -0
  55. package/client/common/wait.js +8 -0
  56. package/client/common/ws.js +161 -0
  57. package/client/components/batch-op/batch-op.jsx +650 -0
  58. package/client/components/bookmark-form/bookmark-form.styl +8 -0
  59. package/client/components/bookmark-form/bookmark-group-tree-format.js +39 -0
  60. package/client/components/bookmark-form/encodes.js +44 -0
  61. package/client/components/bookmark-form/form-ssh-common.jsx +208 -0
  62. package/client/components/bookmark-form/form-tabs.jsx +69 -0
  63. package/client/components/bookmark-form/index.jsx +159 -0
  64. package/client/components/bookmark-form/local-form-ui.jsx +152 -0
  65. package/client/components/bookmark-form/local-form.jsx +16 -0
  66. package/client/components/bookmark-form/proxy.jsx +49 -0
  67. package/client/components/bookmark-form/quick-command-list.jsx +31 -0
  68. package/client/components/bookmark-form/quick-command.jsx +228 -0
  69. package/client/components/bookmark-form/render-auth-ssh.jsx +104 -0
  70. package/client/components/bookmark-form/render-connection-hopping.jsx +229 -0
  71. package/client/components/bookmark-form/render-delayed-scripts.jsx +88 -0
  72. package/client/components/bookmark-form/render-ssh-tunnel.jsx +116 -0
  73. package/client/components/bookmark-form/serial-form-ui.jsx +311 -0
  74. package/client/components/bookmark-form/serial-form.jsx +20 -0
  75. package/client/components/bookmark-form/sftp-enable.jsx +33 -0
  76. package/client/components/bookmark-form/ssh-form-ui.jsx +100 -0
  77. package/client/components/bookmark-form/ssh-form.jsx +348 -0
  78. package/client/components/bookmark-form/telnet-form-ui.jsx +154 -0
  79. package/client/components/bookmark-form/telnet-form.jsx +16 -0
  80. package/client/components/bookmark-form/tree-delete.jsx +87 -0
  81. package/client/components/bookmark-form/use-form-funcs.jsx +50 -0
  82. package/client/components/bookmark-form/use-quick-commands.jsx +83 -0
  83. package/client/components/bookmark-form/use-submit.jsx +77 -0
  84. package/client/components/bookmark-form/use-ui.jsx +82 -0
  85. package/client/components/bookmark-form/x11.jsx +23 -0
  86. package/client/components/common/animate-text.jsx +37 -0
  87. package/client/components/common/animate-text.styl +54 -0
  88. package/client/components/common/external-link.jsx +28 -0
  89. package/client/components/common/help-icon.jsx +25 -0
  90. package/client/components/common/highlight.jsx +23 -0
  91. package/client/components/common/highlight.styl +3 -0
  92. package/client/components/common/input-auto-focus.jsx +68 -0
  93. package/client/components/common/input-confirm.jsx +66 -0
  94. package/client/components/common/logo-elem.jsx +22 -0
  95. package/client/components/common/markdown.jsx +27 -0
  96. package/client/components/common/react-subx.jsx +1 -0
  97. package/client/components/common/resize-wrap.jsx +222 -0
  98. package/client/components/common/resize-wrap.styl +9 -0
  99. package/client/components/common/search.jsx +9 -0
  100. package/client/components/common/show-item.jsx +27 -0
  101. package/client/components/context-menu/boomarks.jsx +15 -0
  102. package/client/components/context-menu/context-menu.jsx +340 -0
  103. package/client/components/context-menu/context-menu.styl +90 -0
  104. package/client/components/context-menu/history.jsx +27 -0
  105. package/client/components/context-menu/icon-holder.jsx +5 -0
  106. package/client/components/context-menu/menu-btn.jsx +224 -0
  107. package/client/components/context-menu/sub-tab-menu.jsx +23 -0
  108. package/client/components/context-menu/tabs.jsx +22 -0
  109. package/client/components/context-menu/zoom.jsx +40 -0
  110. package/client/components/footer/batch-input.jsx +177 -0
  111. package/client/components/footer/footer-entry.jsx +141 -0
  112. package/client/components/footer/footer.styl +47 -0
  113. package/client/components/icons/match-case.jsx +10 -0
  114. package/client/components/icons/match-whole-word.jsx +13 -0
  115. package/client/components/icons/regular-exp.jsx +10 -0
  116. package/client/components/main/css-overwrite.jsx +92 -0
  117. package/client/components/main/error-wrapper.jsx +59 -0
  118. package/client/components/main/index.jsx +11 -0
  119. package/client/components/main/loading.jsx +25 -0
  120. package/client/components/main/main.jsx +149 -0
  121. package/client/components/main/term-fullscreen-control.jsx +21 -0
  122. package/client/components/main/term-fullscreen.styl +27 -0
  123. package/client/components/main/ui-theme.jsx +31 -0
  124. package/client/components/main/upgrade.jsx +351 -0
  125. package/client/components/main/upgrade.styl +27 -0
  126. package/client/components/main/wrapper.styl +41 -0
  127. package/client/components/quick-commands/qm.styl +29 -0
  128. package/client/components/quick-commands/quick-command-item.jsx +36 -0
  129. package/client/components/quick-commands/quick-command-transport-mod.jsx +54 -0
  130. package/client/components/quick-commands/quick-command-transport.jsx +12 -0
  131. package/client/components/quick-commands/quick-commands-box.jsx +233 -0
  132. package/client/components/quick-commands/quick-commands-form-elem.jsx +119 -0
  133. package/client/components/quick-commands/quick-commands-form.jsx +33 -0
  134. package/client/components/quick-commands/quick-commands-list.jsx +128 -0
  135. package/client/components/quick-commands/quick-commands-select.jsx +38 -0
  136. package/client/components/session/session.jsx +533 -0
  137. package/client/components/session/session.styl +53 -0
  138. package/client/components/session/sessions.jsx +445 -0
  139. package/client/components/setting-panel/bookmark-transport.jsx +148 -0
  140. package/client/components/setting-panel/bookmark-tree-list.jsx +14 -0
  141. package/client/components/setting-panel/col.jsx +18 -0
  142. package/client/components/setting-panel/list.jsx +186 -0
  143. package/client/components/setting-panel/list.styl +33 -0
  144. package/client/components/setting-panel/on-tree-drop.js +222 -0
  145. package/client/components/setting-panel/setting-modal.jsx +163 -0
  146. package/client/components/setting-panel/setting-wrap.jsx +37 -0
  147. package/client/components/setting-panel/setting-wrap.styl +52 -0
  148. package/client/components/setting-panel/setting.jsx +858 -0
  149. package/client/components/setting-panel/setting.styl +4 -0
  150. package/client/components/setting-panel/start-session-select.jsx +91 -0
  151. package/client/components/setting-panel/tab-bookmarks.jsx +37 -0
  152. package/client/components/setting-panel/tab-history.jsx +44 -0
  153. package/client/components/setting-panel/tab-quick-commands.jsx +38 -0
  154. package/client/components/setting-panel/tab-settings.jsx +42 -0
  155. package/client/components/setting-panel/tab-themes.jsx +34 -0
  156. package/client/components/setting-panel/tree-list.jsx +978 -0
  157. package/client/components/setting-panel/tree-list.styl +57 -0
  158. package/client/components/setting-sync/data-import.jsx +65 -0
  159. package/client/components/setting-sync/setting-sync-form.jsx +271 -0
  160. package/client/components/setting-sync/setting-sync.jsx +81 -0
  161. package/client/components/setting-sync/sync.styl +7 -0
  162. package/client/components/sftp/address-bar.jsx +139 -0
  163. package/client/components/sftp/address-bookmark-item.jsx +47 -0
  164. package/client/components/sftp/address-bookmark.jsx +81 -0
  165. package/client/components/sftp/address-bookmark.styl +8 -0
  166. package/client/components/sftp/confirm-modal.jsx +184 -0
  167. package/client/components/sftp/file-icon.jsx +22 -0
  168. package/client/components/sftp/file-item.jsx +1226 -0
  169. package/client/components/sftp/file-mode-modal.jsx +205 -0
  170. package/client/components/sftp/file-props-modal.jsx +211 -0
  171. package/client/components/sftp/file-read.js +81 -0
  172. package/client/components/sftp/list-table-ui.jsx +547 -0
  173. package/client/components/sftp/owner-list.js +97 -0
  174. package/client/components/sftp/paged-list.jsx +60 -0
  175. package/client/components/sftp/permission-render.jsx +42 -0
  176. package/client/components/sftp/sftp-entry.jsx +1069 -0
  177. package/client/components/sftp/sftp.styl +217 -0
  178. package/client/components/sftp/transfer-common.js +9 -0
  179. package/client/components/sftp/transfer-conflict.jsx +315 -0
  180. package/client/components/sftp/transfer-speed-format.js +60 -0
  181. package/client/components/sftp/transfer-tag.jsx +40 -0
  182. package/client/components/sftp/transfer-tag.styl +11 -0
  183. package/client/components/sftp/transfer.styl +55 -0
  184. package/client/components/sftp/transport-action.jsx +410 -0
  185. package/client/components/sftp/transport-entry.jsx +108 -0
  186. package/client/components/sftp/transport-types.js +8 -0
  187. package/client/components/sftp/transports-action.jsx +111 -0
  188. package/client/components/sftp/transports-ui.jsx +93 -0
  189. package/client/components/sftp/zip.js +42 -0
  190. package/client/components/sidebar/bookmark-select.jsx +48 -0
  191. package/client/components/sidebar/bookmark.jsx +82 -0
  192. package/client/components/sidebar/history.jsx +66 -0
  193. package/client/components/sidebar/index.jsx +230 -0
  194. package/client/components/sidebar/info-modal.jsx +250 -0
  195. package/client/components/sidebar/info.styl +27 -0
  196. package/client/components/sidebar/side-icon.jsx +25 -0
  197. package/client/components/sidebar/sidebar.styl +128 -0
  198. package/client/components/sidebar/transfer-history-modal.jsx +110 -0
  199. package/client/components/sidebar/transfer-history.styl +3 -0
  200. package/client/components/sidebar/transfer-list-control.jsx +205 -0
  201. package/client/components/sidebar/transfer-list.jsx +55 -0
  202. package/client/components/sidebar/transfer-modal.jsx +76 -0
  203. package/client/components/sidebar/transfer.styl +8 -0
  204. package/client/components/sidebar/transport-ui.jsx +109 -0
  205. package/client/components/tabs/index.jsx +320 -0
  206. package/client/components/tabs/tab.jsx +427 -0
  207. package/client/components/tabs/tabs.styl +220 -0
  208. package/client/components/tabs/window-control.jsx +55 -0
  209. package/client/components/terminal/attach-addon-custom.js +70 -0
  210. package/client/components/terminal/build-ls-term-id.js +5 -0
  211. package/client/components/terminal/index.jsx +1358 -0
  212. package/client/components/terminal/normal-buffer.jsx +33 -0
  213. package/client/components/terminal/term-search.jsx +224 -0
  214. package/client/components/terminal/term-search.styl +15 -0
  215. package/client/components/terminal/terminal-apis.js +31 -0
  216. package/client/components/terminal/terminal-interactive.jsx +148 -0
  217. package/client/components/terminal/terminal.styl +96 -0
  218. package/client/components/terminal/xterm-zmodem.js +48 -0
  219. package/client/components/terminal/zmodem-transfer.jsx +98 -0
  220. package/client/components/terminal/zmodem.styl +14 -0
  221. package/client/components/terminal-info/activity.jsx +54 -0
  222. package/client/components/terminal-info/base.jsx +25 -0
  223. package/client/components/terminal-info/content.jsx +101 -0
  224. package/client/components/terminal-info/data-cols-parser.jsx +50 -0
  225. package/client/components/terminal-info/disk.jsx +29 -0
  226. package/client/components/terminal-info/index.jsx +25 -0
  227. package/client/components/terminal-info/network.jsx +114 -0
  228. package/client/components/terminal-info/resource.jsx +80 -0
  229. package/client/components/terminal-info/run-cmd.jsx +273 -0
  230. package/client/components/terminal-info/terminal-info.styl +29 -0
  231. package/client/components/terminal-info/up.jsx +15 -0
  232. package/client/components/terminal-theme/index.jsx +264 -0
  233. package/client/components/terminal-theme/terminal-theme-list.styl +3 -0
  234. package/client/components/terminal-theme/theme-list.jsx +146 -0
  235. package/client/components/text-editor/text-editor-form.jsx +97 -0
  236. package/client/components/text-editor/text-editor.jsx +182 -0
  237. package/client/css/antd-overwrite.styl +14 -0
  238. package/client/css/basic.styl +38 -0
  239. package/client/css/includes/box.styl +154 -0
  240. package/client/css/includes/font-size.styl +6 -0
  241. package/client/css/includes/index.styl +3 -0
  242. package/client/css/includes/text.styl +31 -0
  243. package/client/css/includes/theme-default.styl +20 -0
  244. package/client/entry/basic.js +58 -0
  245. package/client/entry/index.jsx +15 -0
  246. package/client/entry/worker.js +137 -0
  247. package/client/store/address-bookmark.js +25 -0
  248. package/client/store/app-upgrade.js +23 -0
  249. package/client/store/batch-input-history.js +26 -0
  250. package/client/store/bookmark-group.js +128 -0
  251. package/client/store/bookmark.js +22 -0
  252. package/client/store/common.js +140 -0
  253. package/client/store/context-menu.js +23 -0
  254. package/client/store/db-upgrade.js +43 -0
  255. package/client/store/event.js +70 -0
  256. package/client/store/index.js +335 -0
  257. package/client/store/init-state.js +191 -0
  258. package/client/store/item.js +120 -0
  259. package/client/store/load-data.js +198 -0
  260. package/client/store/quick-command.js +43 -0
  261. package/client/store/session.js +54 -0
  262. package/client/store/setting.js +208 -0
  263. package/client/store/sidebar.js +48 -0
  264. package/client/store/sync.js +390 -0
  265. package/client/store/system-menu.js +120 -0
  266. package/client/store/tab.js +74 -0
  267. package/client/store/terminal-theme.js +116 -0
  268. package/client/store/transfer-history.js +27 -0
  269. package/client/store/transfer-list.js +20 -0
  270. package/client/store/ui-theme.js +71 -0
  271. package/client/store/watch.js +116 -0
  272. package/client/views/index.pug +58 -0
  273. package/package.json +34 -0
@@ -0,0 +1,978 @@
1
+ /**
2
+ * tree list for bookmarks
3
+ */
4
+
5
+ import { Component } from 'react'
6
+ import {
7
+ BookOutlined,
8
+ CheckOutlined,
9
+ CloseOutlined,
10
+ CopyOutlined,
11
+ EditOutlined,
12
+ FolderAddOutlined,
13
+ FolderOutlined,
14
+ FolderOpenOutlined,
15
+ SettingOutlined,
16
+ LoadingOutlined
17
+ } from '@ant-design/icons'
18
+ import {
19
+ readClipboard,
20
+ cut,
21
+ hasBookmarkOrGroupInClipboardText
22
+ } from '../../common/clipboard'
23
+ import {
24
+ Popconfirm,
25
+ Tree,
26
+ Button,
27
+ Tooltip,
28
+ Space
29
+ } from 'antd'
30
+ import createName from '../../common/create-title'
31
+ import classnames from 'classnames'
32
+ import InputAutoFocus from '../common/input-auto-focus'
33
+ import { find, uniq, findIndex, isEqual, filter } from 'lodash-es'
34
+ import {
35
+ maxBookmarkGroupTitleLength,
36
+ defaultBookmarkGroupId,
37
+ settingMap,
38
+ commonActions,
39
+ copyBookmarkItemPrefix,
40
+ copyBookmarkGroupItemPrefix
41
+ } from '../../common/constants'
42
+ import highlight from '../common/highlight'
43
+ import copy from 'json-deep-copy'
44
+ import onDrop from './on-tree-drop'
45
+ import Search from '../common/search'
46
+ import Btns from './bookmark-transport'
47
+ import findBookmarkGroupId from '../../common/find-bookmark-group-id'
48
+ import getInitItem from '../../common/init-setting-item'
49
+ import uid from '../../common/uid'
50
+ import deepEqual from 'fast-deep-equal'
51
+ import './tree-list.styl'
52
+
53
+ const { TreeNode } = Tree
54
+ const { prefix } = window
55
+ const e = prefix('menu')
56
+ const c = prefix('common')
57
+ const s = prefix('setting')
58
+
59
+ export default class ItemListTree extends Component {
60
+ constructor (props) {
61
+ super(props)
62
+ this.state = {
63
+ ready: false,
64
+ keyword: '',
65
+ showNewBookmarkGroupForm: false,
66
+ bookmarkGroupTitle: '',
67
+ categoryTitle: '',
68
+ categoryId: '',
69
+ bookmarkGroupTitleSub: '',
70
+ bookmarkGroupSubParentId: '',
71
+ expandedKeys: window.store.expandedKeys
72
+ }
73
+ }
74
+
75
+ componentDidMount () {
76
+ this.timer = setTimeout(() => {
77
+ this.setState({
78
+ ready: true
79
+ })
80
+ }, 100)
81
+ }
82
+
83
+ componentDidUpdate (prevProps, prevState) {
84
+ if (
85
+ !deepEqual(prevProps.expandedKeys, this.props.expandedKeys) &&
86
+ !deepEqual(this.props.expandedKeys, this.state.expandedKeys)
87
+ ) {
88
+ this.setState({
89
+ expandedKeys: this.props.expandedKeys
90
+ })
91
+ }
92
+ }
93
+
94
+ componentWillUnmount () {
95
+ clearTimeout(this.timer)
96
+ window.removeEventListener('message', this.onContextAction)
97
+ }
98
+
99
+ handleChange = e => {
100
+ this.setState({
101
+ keyword: e.target.value
102
+ })
103
+ }
104
+
105
+ handleCancelNew = () => {
106
+ this.setState({
107
+ showNewBookmarkGroupForm: false,
108
+ bookmarkGroupTitle: ''
109
+ })
110
+ }
111
+
112
+ handleCancelNewSub = () => {
113
+ this.setState({
114
+ bookmarkGroupSubParentId: ''
115
+ })
116
+ }
117
+
118
+ handleCancelEdit = () => {
119
+ this.setState({
120
+ categoryId: '',
121
+ categoryTitle: ''
122
+ })
123
+ }
124
+
125
+ handleChangeEdit = e => {
126
+ let { value } = e.target
127
+ if (value.length > maxBookmarkGroupTitleLength) {
128
+ value = value.slice(0, maxBookmarkGroupTitleLength)
129
+ }
130
+ this.setState({
131
+ categoryTitle: value
132
+ })
133
+ }
134
+
135
+ handleSubmitEdit = () => {
136
+ const {
137
+ categoryTitle,
138
+ categoryId
139
+ } = this.state
140
+ if (!categoryTitle) {
141
+ return
142
+ }
143
+ const bookmarkGroups = copy(
144
+ this.props.bookmarkGroups
145
+ )
146
+ const obj = find(
147
+ bookmarkGroups,
148
+ bg => bg.id === categoryId
149
+ )
150
+ if (!obj) {
151
+ return this.handleCancelEdit()
152
+ }
153
+ obj.title = categoryTitle
154
+ this.setState({
155
+ categoryId: ''
156
+ })
157
+ this.props.store.setBookmarkGroups(
158
+ bookmarkGroups
159
+ )
160
+ this.props.store.batchDbUpdate([{
161
+ id: categoryId,
162
+ db: 'bookmarkGroups',
163
+ upsert: false,
164
+ update: {
165
+ title: categoryTitle
166
+ }
167
+ }])
168
+ }
169
+
170
+ onDrop = (info) => {
171
+ onDrop(info, this.props)
172
+ }
173
+
174
+ onClick = () => {
175
+
176
+ }
177
+
178
+ onSubmit = false
179
+
180
+ onSubmitEdit = false
181
+
182
+ handleChangeBookmarkGroupTitle = e => {
183
+ let { value } = e.target
184
+ if (value.length > maxBookmarkGroupTitleLength) {
185
+ value = value.slice(0, maxBookmarkGroupTitleLength)
186
+ }
187
+ this.setState({
188
+ bookmarkGroupTitle: value
189
+ })
190
+ }
191
+
192
+ handleChangeBookmarkGroupTitleSub = e => {
193
+ let { value } = e.target
194
+ if (value.length > maxBookmarkGroupTitleLength) {
195
+ value = value.slice(0, maxBookmarkGroupTitleLength)
196
+ }
197
+ this.setState({
198
+ bookmarkGroupTitleSub: value
199
+ })
200
+ }
201
+
202
+ handleNewBookmark = () => {
203
+ this.props.onClickItem(getInitItem([], settingMap.bookmarks))
204
+ }
205
+
206
+ handleSubmit = () => {
207
+ if (this.onSubmit) {
208
+ return
209
+ }
210
+ this.onSubmit = true
211
+ this.setState({
212
+ showNewBookmarkGroupForm: false
213
+ }, () => {
214
+ this.onSubmit = false
215
+ this.props.store.addBookmarkGroup({
216
+ id: uid(),
217
+ title: this.state.bookmarkGroupTitle,
218
+ bookmarkIds: []
219
+ })
220
+ })
221
+ }
222
+
223
+ handleSubmitSub = () => {
224
+ if (this.onSubmit) {
225
+ return
226
+ }
227
+ this.onSubmit = true
228
+ const id = this.state.bookmarkGroupSubParentId
229
+ this.setState({
230
+ bookmarkGroupSubParentId: ''
231
+ }, () => {
232
+ this.onSubmit = false
233
+ let bookmarkGroups = copy(
234
+ this.props.bookmarkGroups
235
+ )
236
+ const newCat = {
237
+ id: uid(),
238
+ title: this.state.bookmarkGroupTitleSub,
239
+ level: 2,
240
+ bookmarkIds: []
241
+ }
242
+ bookmarkGroups = [
243
+ newCat,
244
+ ...bookmarkGroups
245
+ ]
246
+ const cat = find(
247
+ bookmarkGroups,
248
+ d => d.id === id
249
+ )
250
+ if (!cat) {
251
+ return
252
+ }
253
+ cat.bookmarkGroupIds = [
254
+ ...(cat.bookmarkGroupIds || []),
255
+ newCat.id
256
+ ]
257
+ this.props.store.setBookmarkGroups(
258
+ bookmarkGroups
259
+ )
260
+ this.props.store.batchDbAdd([{
261
+ db: 'bookmarkGroups',
262
+ obj: newCat
263
+ }])
264
+ this.props.store.batchDbUpdate([{
265
+ upsert: false,
266
+ id,
267
+ update: {
268
+ bookmarkGroupIds: cat.bookmarkGroupIds
269
+ },
270
+ db: 'bookmarkGroups'
271
+ }])
272
+ })
273
+ }
274
+
275
+ handleNewBookmarkGroup = () => {
276
+ this.setState({
277
+ showNewBookmarkGroupForm: true,
278
+ bookmarkGroupTitle: '',
279
+ bookmarkGroupSubParentId: ''
280
+ })
281
+ }
282
+
283
+ del = (item, e) => {
284
+ e.stopPropagation()
285
+ if (item.bookmarkIds) {
286
+ return this.props.store.delBookmarkGroup(item)
287
+ }
288
+ this.props.store.onDelItem(item, this.props.type)
289
+ this.props.store.delItem(item, this.props.type)
290
+ }
291
+
292
+ closeNewGroupForm = () => {
293
+ this.setState({
294
+ showNewBookmarkGroupForm: false,
295
+ bookmarkGroupSubParentId: ''
296
+ })
297
+ }
298
+
299
+ onExpand = (expandedKeys) => {
300
+ this.setState({
301
+ expandedKeys
302
+ })
303
+ this.closeNewGroupForm()
304
+ this.props.store.setState(
305
+ 'expandedKeys', expandedKeys
306
+ )
307
+ }
308
+
309
+ onSelect = (
310
+ selectedKeys,
311
+ {
312
+ node
313
+ }
314
+ ) => {
315
+ const [id] = selectedKeys
316
+ if (!node.isLeaf) {
317
+ this.props.store.storeAssign({
318
+ currentBookmarkGroupId: id
319
+ })
320
+ } else {
321
+ this.props.store.storeAssign({
322
+ currentBookmarkGroupId: findBookmarkGroupId(this.props.store.getBookmarkGroups(), id)
323
+ })
324
+ }
325
+ const bookmarks = copy(this.props.bookmarks)
326
+ const bookmark = find(
327
+ bookmarks,
328
+ d => d.id === id
329
+ )
330
+ if (bookmark) {
331
+ this.props.onClickItem(bookmark)
332
+ }
333
+ }
334
+
335
+ renderSearch = () => {
336
+ return (
337
+ <div className='pd1y pd2r'>
338
+ <Search
339
+ onChange={this.handleChange}
340
+ value={this.state.keyword}
341
+ />
342
+ </div>
343
+ )
344
+ }
345
+
346
+ renderDelBtn = item => {
347
+ if (item.id === defaultBookmarkGroupId || this.props.staticList) {
348
+ return null
349
+ }
350
+ return (
351
+ <Popconfirm
352
+ title={e('del') + '?'}
353
+ onConfirm={e => this.del(item, e)}
354
+ okText={e('del')}
355
+ cancelText={c('cancel')}
356
+ placement='top'
357
+ >
358
+ <CloseOutlined title={e('del')} className='pointer tree-control-btn' />
359
+ </Popconfirm>
360
+ )
361
+ }
362
+
363
+ renderOperationBtn = (item, isGroup) => {
364
+ if (this.props.staticList) {
365
+ return null
366
+ }
367
+ return (
368
+ <SettingOutlined
369
+ className='pointer tree-control-btn'
370
+ onClick={e => this.onContextMenu(e, item, isGroup)}
371
+ />
372
+ )
373
+ }
374
+
375
+ onCut = (item, isGroup) => {
376
+ const str = isGroup
377
+ ? copyBookmarkGroupItemPrefix
378
+ : copyBookmarkItemPrefix
379
+ const txt = str + item.id
380
+ cut(txt, createName(item))
381
+ }
382
+
383
+ onPaste = (item) => {
384
+ const str = readClipboard()
385
+ const id = str.split(':')[1]
386
+ const bookmarkGroups = copy(
387
+ this.props.bookmarkGroups
388
+ )
389
+ const from = bookmarkGroups.find(t => {
390
+ return t.bookmarkIds.includes(id)
391
+ })
392
+ from.bookmarkIds = from.bookmarkIds.filter(d => {
393
+ return d !== id
394
+ })
395
+ const to = bookmarkGroups.find(t => {
396
+ return t.id === item.id
397
+ })
398
+ if (!to.bookmarkIds) {
399
+ to.bookmarkIds = []
400
+ }
401
+ to.bookmarkIds = uniq(
402
+ [
403
+ ...to.bookmarkIds,
404
+ id
405
+ ]
406
+ )
407
+ if (from) {
408
+ this.props.store.editBookmarkGroup(
409
+ from.id,
410
+ {
411
+ bookmarkIds: (from.bookmarkIds || []).filter(d => {
412
+ return d !== id
413
+ })
414
+ }
415
+ )
416
+ }
417
+ this.props.store.editBookmarkGroup(
418
+ item.id,
419
+ {
420
+ bookmarkIds: uniq(
421
+ [
422
+ ...(item.bookmarkIds || []),
423
+ id
424
+ ]
425
+ )
426
+ }
427
+ )
428
+ }
429
+
430
+ computePos = (e) => {
431
+ return {
432
+ left: e.clientX,
433
+ top: e.clientY
434
+ }
435
+ }
436
+
437
+ onContextAction = e => {
438
+ const {
439
+ action,
440
+ id,
441
+ args = [],
442
+ func
443
+ } = e.data || {}
444
+ if (
445
+ action !== commonActions.clickContextMenu ||
446
+ id !== this.uid ||
447
+ !this[func]
448
+ ) {
449
+ return false
450
+ }
451
+ window.removeEventListener('message', this.onContextAction)
452
+ this[func](...args)
453
+ }
454
+
455
+ onContextMenu = (e, item, isGroup) => {
456
+ e.preventDefault()
457
+ if (this.props.staticList) {
458
+ return null
459
+ }
460
+ const menus = this.renderContextItems(item, isGroup)
461
+ this.uid = uid()
462
+ this.props.store.openContextMenu({
463
+ items: menus,
464
+ id: this.uid,
465
+ pos: this.computePos(e)
466
+ })
467
+ window.addEventListener('message', this.onContextAction)
468
+ this.closeNewGroupForm()
469
+ }
470
+
471
+ renderContextItems (item, isGroup) {
472
+ const res = []
473
+ const args = [copy(item), isGroup]
474
+ if (!isGroup) {
475
+ // res.push({
476
+ // func: 'onCopy',
477
+ // icon: 'CopyOutlined',
478
+ // text: e('copy'),
479
+ // args
480
+ // })
481
+ res.push({
482
+ func: 'onCut',
483
+ icon: 'FileExcelOutlined',
484
+ text: e('cut'),
485
+ args
486
+ })
487
+ }
488
+ const canPaste = hasBookmarkOrGroupInClipboardText()
489
+ if (isGroup) {
490
+ res.push({
491
+ func: 'onPaste',
492
+ icon: 'CopyOutlined',
493
+ text: e('paste'),
494
+ disabled: !canPaste,
495
+ args
496
+ })
497
+ }
498
+ return res
499
+ }
500
+
501
+ editItem = (e, item, isGroup) => {
502
+ e.stopPropagation()
503
+ if (isGroup) {
504
+ this.setState({
505
+ categoryTitle: '' + item.title,
506
+ categoryId: item.id + '',
507
+ bookmarkGroupSubParentId: ''
508
+ })
509
+ } else {
510
+ this.props.store.openBookmarkEdit(item)
511
+ }
512
+ }
513
+
514
+ addSubCat = (e, item) => {
515
+ this.setState(old => {
516
+ return {
517
+ showNewBookmarkGroupForm: false,
518
+ bookmarkGroupTitleSub: '',
519
+ bookmarkGroupSubParentId: item.id,
520
+ expandedKeys: uniq([
521
+ ...old.expandedKeys,
522
+ item.id
523
+ ])
524
+ }
525
+ })
526
+ }
527
+
528
+ renderAddNewSubGroupBtn = item => {
529
+ if (this.props.staticList || item.level === 2) {
530
+ return null
531
+ }
532
+ return (
533
+ <FolderAddOutlined
534
+ key='new-tree'
535
+ title={`${s('new')} ${c('bookmarkCategory')}`}
536
+ onClick={(e) => this.addSubCat(e, item)}
537
+ className='pointer tree-control-btn'
538
+ />
539
+ )
540
+ }
541
+
542
+ renderEditBtn = (item, isGroup) => {
543
+ if (
544
+ (this.props.staticList && isGroup) ||
545
+ (!this.props.staticList && !isGroup)
546
+ ) {
547
+ return null
548
+ }
549
+ return (
550
+ <EditOutlined
551
+ title={e('edit')}
552
+ key='edit-tree'
553
+ onClick={(e) => this.editItem(e, item, isGroup)}
554
+ className='pointer tree-control-btn'
555
+ />
556
+ )
557
+ }
558
+
559
+ renderOpenAll = (item, isGroup) => {
560
+ if (
561
+ (this.props.staticList && isGroup) ||
562
+ (!this.props.staticList && !isGroup)
563
+ ) {
564
+ return null
565
+ }
566
+ return (
567
+ <Tooltip title={s('openAll')}>
568
+ <FolderOpenOutlined
569
+ key='open-all-tree'
570
+ onClick={(e) => this.props.store.openAllBookmarkInCategory(item)}
571
+ className='pointer tree-control-btn'
572
+ />
573
+ </Tooltip>
574
+ )
575
+ }
576
+
577
+ editCategory = () => {
578
+ const {
579
+ categoryTitle
580
+ } = this.state
581
+ const confirm = (
582
+ <span>
583
+ <CheckOutlined className='pointer' onClick={this.handleSubmitEdit} />
584
+ <CloseOutlined className='mg1l pointer' onClick={this.handleCancelEdit} />
585
+ </span>
586
+ )
587
+ return (
588
+ <InputAutoFocus
589
+ value={categoryTitle}
590
+ onChange={this.handleChangeEdit}
591
+ onPressEnter={this.handleSubmitEdit}
592
+ addonAfter={confirm}
593
+ />
594
+ )
595
+ }
596
+
597
+ duplicateItem = (e, item) => {
598
+ e.stopPropagation()
599
+ const { addItem } = this.props.store
600
+ const bookmarkGroups = copy(
601
+ this.props.bookmarkGroups
602
+ )
603
+
604
+ const newbookmark = copy(item)
605
+ newbookmark.id = uid()
606
+ const bookmarkWithSameTitle = this.findBookmarkByTitle(this.props.bookmarks, item)
607
+ let deplicateIndex
608
+ if (bookmarkWithSameTitle.length === 1) {
609
+ deplicateIndex = 1
610
+ } else {
611
+ deplicateIndex = bookmarkWithSameTitle.length
612
+ }
613
+ newbookmark.title = item.title + '(' + deplicateIndex + ')'
614
+ const categoryId = findBookmarkGroupId(bookmarkGroups, item.id)
615
+ this.props.store.storeAssign({
616
+ currentBookmarkGroupId: categoryId
617
+ })
618
+ // add bookmark to store
619
+ addItem(newbookmark, settingMap.bookmarks)
620
+ // update bookmark groups
621
+ this.updateBookmarkGroups(
622
+ bookmarkGroups,
623
+ newbookmark,
624
+ categoryId
625
+ )
626
+ this.props.onClickItem(newbookmark)
627
+ }
628
+
629
+ updateBookmarkGroups = (bookmarkGroups, bookmark, categoryId) => {
630
+ let index = findIndex(
631
+ bookmarkGroups,
632
+ bg => bg.id === categoryId
633
+ )
634
+ if (index < 0) {
635
+ index = findIndex(
636
+ bookmarkGroups,
637
+ bg => bg.id === defaultBookmarkGroupId
638
+ )
639
+ }
640
+ const updates = []
641
+ const bid = bookmark.id
642
+ const bg = bookmarkGroups[index]
643
+ const old = copy(bg.bookmarkIds)
644
+ if (!bg.bookmarkIds.includes(bid)) {
645
+ bg.bookmarkIds.unshift(bid)
646
+ }
647
+ bg.bookmarkIds = uniq(bg.bookmarkIds)
648
+ if (!isEqual(old, copy(bg.bookmarkIds))) {
649
+ updates.push({
650
+ id: bg.id,
651
+ db: 'bookmarkGroups',
652
+ upsert: false,
653
+ update: {
654
+ bookmarkIds: bg.bookmarkIds
655
+ }
656
+ })
657
+ }
658
+ bookmarkGroups = bookmarkGroups.map((bg, i) => {
659
+ if (i === index) {
660
+ return bg
661
+ }
662
+ const old = copy(bg.bookmarkIds)
663
+ bg.bookmarkIds = bg.bookmarkIds.filter(
664
+ g => g !== bid
665
+ )
666
+ if (!isEqual(old, copy(bg.bookmarkIds))) {
667
+ updates.push({
668
+ id: bg.id,
669
+ db: 'bookmarkGroups',
670
+ upsert: false,
671
+ update: {
672
+ bookmarkIds: bg.bookmarkIds
673
+ }
674
+ })
675
+ }
676
+ return bg
677
+ })
678
+ this.props.store.setBookmarkGroups(
679
+ bookmarkGroups
680
+ )
681
+ this.props.store.batchDbUpdate(updates)
682
+ }
683
+
684
+ findBookmarkByTitle = (bookmarks, oldBookmark) => {
685
+ return filter(bookmarks, bookmark => {
686
+ return (bookmark.title || '').includes(oldBookmark.title) && bookmark.host === oldBookmark.host && bookmark.port === oldBookmark.port
687
+ })
688
+ }
689
+
690
+ renderDuplicateBtn = (item, isGroup) => {
691
+ if (!item.id || this.props.staticList) {
692
+ return null
693
+ }
694
+ const icon = (
695
+ <CopyOutlined
696
+ title={e('duplicate')}
697
+ className='pointer tree-control-btn'
698
+ onClick={(e) => this.duplicateItem(e, item)}
699
+ />
700
+ )
701
+ return icon
702
+ }
703
+
704
+ renderItemTitle = (item, isGroup) => {
705
+ if (isGroup && item.id === this.state.categoryId) {
706
+ return this.editCategory(item)
707
+ }
708
+ const cls = classnames(
709
+ 'tree-item elli',
710
+ {
711
+ 'is-category': isGroup,
712
+ level2: item.level === 2
713
+ }
714
+ )
715
+ const title = isGroup
716
+ ? item.title
717
+ : createName(item)
718
+ const titleAll = title + (item.description ? ' - ' + item.description : '')
719
+ const titleHighlight = isGroup
720
+ ? item.title || 'no title'
721
+ : highlight(
722
+ title,
723
+ this.state.keyword
724
+ )
725
+ return (
726
+ <div
727
+ className={cls}
728
+ key={item.id || uid()}
729
+ title={titleAll}
730
+ onContextMenu={e => this.onContextMenu(e, item, isGroup)}
731
+ >
732
+ <div
733
+ className='tree-item-title elli'
734
+ >
735
+ {titleHighlight}
736
+ </div>
737
+ {
738
+ isGroup
739
+ ? this.renderGroupBtns(item)
740
+ : null
741
+ }
742
+ {
743
+ !isGroup
744
+ ? this.renderDuplicateBtn(item)
745
+ : null
746
+ }
747
+ {this.renderOperationBtn(item, isGroup)}
748
+ {this.renderDelBtn(item)}
749
+ {this.renderEditBtn(item, isGroup)}
750
+ </div>
751
+ )
752
+ }
753
+
754
+ renderGroupBtns = (item) => {
755
+ return [
756
+ this.renderAddNewSubGroupBtn(item),
757
+ this.renderEditBtn(item),
758
+ this.renderOpenAll(item)
759
+ ]
760
+ }
761
+
762
+ renderChildNodes = bookmarkIds => {
763
+ const bookmarks = this.filter(
764
+ this.props.bookmarks
765
+ )
766
+ const map = bookmarks.reduce((p, b) => {
767
+ return {
768
+ ...p,
769
+ [b.id]: b
770
+ }
771
+ }, {})
772
+ const nodes = bookmarkIds.reduce((prev, id) => {
773
+ return map[id]
774
+ ? [
775
+ ...prev,
776
+ map[id]
777
+ ]
778
+ : prev
779
+ }, [])
780
+ return nodes.map((node, i) => {
781
+ return (
782
+ <TreeNode
783
+ key={node.id}
784
+ isLeaf
785
+ title={this.renderItemTitle(node)}
786
+ />
787
+ )
788
+ })
789
+ }
790
+
791
+ renderGroupChildNodes = bookmarkGroupIds => {
792
+ const bookmarkGroups = bookmarkGroupIds.map(id => {
793
+ return find(this.props.bookmarkGroups, d => d.id === id)
794
+ }).filter(d => d)
795
+ return bookmarkGroups.map((node, i) => {
796
+ const { bookmarkIds = [], id } = node
797
+ return (
798
+ <TreeNode
799
+ key={id}
800
+ title={this.renderItemTitle(node, true)}
801
+ >
802
+ {
803
+ bookmarkIds.length
804
+ ? this.renderChildNodes(bookmarkIds)
805
+ : null
806
+ }
807
+ </TreeNode>
808
+ )
809
+ })
810
+ }
811
+
812
+ renderItem = (item, i) => {
813
+ const {
814
+ bookmarkIds = [],
815
+ bookmarkGroupIds = []
816
+ } = item
817
+ return (
818
+ <TreeNode
819
+ key={item.id}
820
+ title={this.renderItemTitle(item, true)}
821
+ >
822
+ {this.renderNewSubBookmarkGroup(item)}
823
+ {
824
+ bookmarkGroupIds.length
825
+ ? this.renderGroupChildNodes(bookmarkGroupIds)
826
+ : null
827
+ }
828
+ {
829
+ bookmarkIds.length
830
+ ? this.renderChildNodes(bookmarkIds)
831
+ : null
832
+ }
833
+ </TreeNode>
834
+ )
835
+ }
836
+
837
+ filter = list => {
838
+ const { keyword } = this.state
839
+ return keyword
840
+ ? list.filter(item => {
841
+ return createName(item).toLowerCase().includes(keyword.toLowerCase())
842
+ })
843
+ : list
844
+ }
845
+
846
+ renderNewButtons = () => {
847
+ return (
848
+ <div className='pd1b pd2r'>
849
+ <Space.Compact>
850
+ <Button
851
+ onClick={this.handleNewBookmark}
852
+ title={`${s('new')} ${c('bookmarks')}`}
853
+ >
854
+ <BookOutlined className='with-plus' />
855
+ </Button>
856
+ <Button
857
+ onClick={this.handleNewBookmarkGroup}
858
+ title={`${s('new')} ${c('bookmarkCategory')}`}
859
+ >
860
+ <FolderOutlined className='with-plus' />
861
+ </Button>
862
+ <Btns
863
+ store={this.props.store}
864
+ />
865
+ </Space.Compact>
866
+ </div>
867
+ )
868
+ }
869
+
870
+ renderNewSubBookmarkGroup = item => {
871
+ const {
872
+ bookmarkGroupTitleSub,
873
+ bookmarkGroupSubParentId
874
+ } = this.state
875
+ if (!bookmarkGroupSubParentId || item.id !== bookmarkGroupSubParentId) {
876
+ return null
877
+ }
878
+ const confirm = (
879
+ <span>
880
+ <CheckOutlined className='pointer' onClick={this.handleSubmitSub} />
881
+ <CloseOutlined className='mg1l pointer' onClick={this.handleCancelNewSub} />
882
+ </span>
883
+ )
884
+ return (
885
+ <TreeNode
886
+ key={bookmarkGroupSubParentId}
887
+ isLeaf
888
+ title={(
889
+ <InputAutoFocus
890
+ value={bookmarkGroupTitleSub}
891
+ onPressEnter={this.handleSubmitSub}
892
+ onChange={this.handleChangeBookmarkGroupTitleSub}
893
+ addonAfter={confirm}
894
+ />
895
+ )}
896
+ />
897
+ )
898
+ }
899
+
900
+ renderNewBookmarkGroup = () => {
901
+ const {
902
+ bookmarkGroupTitle,
903
+ showNewBookmarkGroupForm
904
+ } = this.state
905
+ if (!showNewBookmarkGroupForm) {
906
+ return null
907
+ }
908
+ const confirm = (
909
+ <span>
910
+ <CheckOutlined className='pointer' onClick={this.handleSubmit} />
911
+ <CloseOutlined className='mg1l pointer' onClick={this.handleCancelNew} />
912
+ </span>
913
+ )
914
+ return (
915
+ <div className='pd1y'>
916
+ <InputAutoFocus
917
+ value={bookmarkGroupTitle}
918
+ onPressEnter={this.handleSubmit}
919
+ onChange={this.handleChangeBookmarkGroupTitle}
920
+ addonAfter={confirm}
921
+ onBlur={this.handleBlurBookmarkGroupTitle}
922
+ />
923
+ </div>
924
+ )
925
+ }
926
+
927
+ render () {
928
+ const { ready } = this.state
929
+ if (!ready) {
930
+ return (
931
+ <div className='pd3 aligncenter'>
932
+ <LoadingOutlined />
933
+ </div>
934
+ )
935
+ }
936
+ const {
937
+ bookmarkGroups,
938
+ type,
939
+ activeItemId,
940
+ staticList,
941
+ listStyle = {}
942
+ } = this.props
943
+ const { keyword, expandedKeys } = this.state
944
+ const level1Bookgroups = ready
945
+ ? bookmarkGroups.filter(
946
+ d => !d.level || d.level < 2
947
+ )
948
+ : []
949
+ const treeProps = {
950
+ onExpand: this.onExpand,
951
+ expandedKeys: keyword ? bookmarkGroups.map(f => f.id) : expandedKeys,
952
+ onSelect: this.onSelect,
953
+ draggable: staticList ? false : { icon: false },
954
+ selectedKeys: [activeItemId],
955
+ onDrop: this.onDrop
956
+ }
957
+ return (
958
+ <div className={`tree-list item-type-${type}`}>
959
+ {
960
+ staticList
961
+ ? null
962
+ : this.renderNewButtons()
963
+ }
964
+ {
965
+ this.renderSearch()
966
+ }
967
+ <div className='item-list-wrap pd2r' style={listStyle}>
968
+ {this.renderNewBookmarkGroup()}
969
+ <Tree
970
+ {...treeProps}
971
+ >
972
+ {level1Bookgroups.map(this.renderItem)}
973
+ </Tree>
974
+ </div>
975
+ </div>
976
+ )
977
+ }
978
+ }