artalk 2.1.4 → 2.1.7
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.
- package/CNAME +1 -0
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +303 -1248
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/index.html +143 -0
- package/package.json +8 -29
- package/postcss.config.js +5 -0
- package/src/api/index.ts +14 -0
- package/src/api/request.ts +4 -2
- package/src/artalk.ts +28 -6
- package/src/components/comment.ts +20 -3
- package/src/components/html/list.html +4 -2
- package/src/components/html/sidebar-layer.html +8 -0
- package/src/components/list.ts +60 -0
- package/src/components/sidebar-layer.ts +143 -0
- package/src/defaults.ts +1 -0
- package/src/lib/detect.js +3 -1
- package/src/lib/utils.ts +25 -0
- package/src/style/_extend.less +0 -80
- package/src/style/comment.less +6 -0
- package/src/style/list.less +66 -0
- package/src/style/main.less +1 -1
- package/src/style/sidebar-layer.less +92 -0
- package/types/artalk-config.d.ts +4 -1
- package/types/artalk-data.d.ts +3 -0
- package/vite-common.config.ts +15 -0
- package/vite-demo.config.ts +14 -0
- package/vite.config.ts +36 -0
- package/LICENSE +0 -674
- package/README.md +0 -84
- package/src/components/admin/page-list.ts +0 -194
- package/src/components/admin/site-list-floater.ts +0 -98
- package/src/components/admin/site-list.ts +0 -289
- package/src/components/html/sidebar.html +0 -22
- package/src/components/item-text-editor.ts +0 -136
- package/src/components/sidebar-view.ts +0 -26
- package/src/components/sidebar-views/comments-view.ts +0 -73
- package/src/components/sidebar-views/pages-view.ts +0 -61
- package/src/components/sidebar-views/setting-view.ts +0 -21
- package/src/components/sidebar-views/sites-view.ts +0 -36
- package/src/components/sidebar-views/transfer-view.ts +0 -218
- package/src/components/sidebar.ts +0 -293
- package/src/lib/md5.js +0 -6
- package/src/style/item-text-editor.less +0 -35
- package/src/style/page-list.less +0 -50
- package/src/style/sidebar.less +0 -420
- package/src/style/site-list.less +0 -208
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import '../style/item-text-editor.less'
|
|
2
|
-
|
|
3
|
-
import * as Utils from '../lib/utils'
|
|
4
|
-
|
|
5
|
-
interface ItemTextEditorConf {
|
|
6
|
-
initValue?: string
|
|
7
|
-
validator?: (value: string) => boolean
|
|
8
|
-
onYes?: (value: string) => boolean|void|Promise<boolean|void>
|
|
9
|
-
onNo?: () => boolean|void|Promise<boolean|void>
|
|
10
|
-
placeholder?: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 通用列表项目文本编辑器
|
|
15
|
-
*/
|
|
16
|
-
export default class ItemTextEditor {
|
|
17
|
-
private conf: ItemTextEditorConf
|
|
18
|
-
public $el: HTMLElement
|
|
19
|
-
|
|
20
|
-
public $input: HTMLInputElement
|
|
21
|
-
public $yesBtn: HTMLElement
|
|
22
|
-
public $noBtn: HTMLElement
|
|
23
|
-
|
|
24
|
-
public value: string = ''
|
|
25
|
-
public allowSubmit = true
|
|
26
|
-
|
|
27
|
-
constructor(conf: ItemTextEditorConf) {
|
|
28
|
-
this.conf = conf
|
|
29
|
-
|
|
30
|
-
this.$el = Utils.createElement(
|
|
31
|
-
`<div class="atk-item-text-editor-layer">
|
|
32
|
-
<div class="atk-edit-form">
|
|
33
|
-
<input class="atk-main-input" type="text" placeholder="输入内容..." autocomplete="off" autofocus>
|
|
34
|
-
</div>
|
|
35
|
-
<div class="atk-actions">
|
|
36
|
-
<div class="atk-item atk-yes-btn">
|
|
37
|
-
<i class="atk-icon atk-icon-yes"></i>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="atk-item atk-no-btn">
|
|
40
|
-
<i class="atk-icon atk-icon-no"></i>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
</div>`)
|
|
44
|
-
|
|
45
|
-
this.$input = this.$el.querySelector('.atk-main-input')!
|
|
46
|
-
this.$yesBtn = this.$el.querySelector('.atk-yes-btn')!
|
|
47
|
-
this.$noBtn = this.$el.querySelector('.atk-no-btn')!
|
|
48
|
-
|
|
49
|
-
this.$input.value = conf.initValue || ''
|
|
50
|
-
this.value = conf.initValue || ''
|
|
51
|
-
if (this.conf.placeholder) this.$input.placeholder = this.conf.placeholder
|
|
52
|
-
|
|
53
|
-
this.$input.oninput = () => this.onInput()
|
|
54
|
-
this.$input.onkeyup = (evt) => {
|
|
55
|
-
if (evt.key === 'Enter' || evt.keyCode === 13) { // 按下回车键
|
|
56
|
-
evt.preventDefault()
|
|
57
|
-
this.submit()
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
window.setTimeout(() => this.$input.focus(), 80)
|
|
62
|
-
|
|
63
|
-
this.$yesBtn.onclick = () => { this.submit() }
|
|
64
|
-
this.$noBtn.onclick = () => { this.cancel() }
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public appendTo(parentDOM: HTMLElement) {
|
|
68
|
-
parentDOM.append(this.$el)
|
|
69
|
-
return this
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private onInput() {
|
|
73
|
-
this.value = this.$input.value
|
|
74
|
-
|
|
75
|
-
// 验证器
|
|
76
|
-
if (this.conf.validator) {
|
|
77
|
-
const ok = this.conf.validator(this.value)
|
|
78
|
-
this.setAllowSubmit(ok)
|
|
79
|
-
if (!ok) {
|
|
80
|
-
this.$input.classList.add('atk-invalid')
|
|
81
|
-
} else {
|
|
82
|
-
this.$input.classList.remove('atk-invalid')
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
public setAllowSubmit(allow: boolean) {
|
|
88
|
-
if (this.allowSubmit === allow) return
|
|
89
|
-
this.allowSubmit = allow
|
|
90
|
-
if (!allow) {
|
|
91
|
-
this.$yesBtn.classList.add('.atk-disabled')
|
|
92
|
-
} else {
|
|
93
|
-
this.$yesBtn.classList.remove('.atk-disabled')
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
public async submit() {
|
|
98
|
-
if (!this.allowSubmit) return
|
|
99
|
-
|
|
100
|
-
if (this.conf.onYes) {
|
|
101
|
-
let isContinue: any
|
|
102
|
-
if (this.conf.onYes instanceof (async () => {}).constructor) {
|
|
103
|
-
isContinue = await this.conf.onYes(this.value)
|
|
104
|
-
} else {
|
|
105
|
-
isContinue = this.conf.onYes(this.value)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (isContinue === undefined || isContinue === true) {
|
|
109
|
-
this.closeEditor()
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
112
|
-
this.closeEditor()
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
public async cancel() {
|
|
117
|
-
if (this.conf.onNo) {
|
|
118
|
-
let isContinue: any
|
|
119
|
-
if (this.conf.onNo instanceof (async () => {}).constructor) {
|
|
120
|
-
isContinue = await this.conf.onNo()
|
|
121
|
-
} else {
|
|
122
|
-
isContinue = this.conf.onNo()
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (isContinue === undefined || isContinue === true) {
|
|
126
|
-
this.closeEditor()
|
|
127
|
-
}
|
|
128
|
-
} else {
|
|
129
|
-
this.closeEditor()
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
public closeEditor() {
|
|
134
|
-
this.$el.remove()
|
|
135
|
-
}
|
|
136
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import Context from '../context'
|
|
2
|
-
import Component from '../lib/component'
|
|
3
|
-
import * as Utils from '../lib/utils'
|
|
4
|
-
import Comment from './comment'
|
|
5
|
-
|
|
6
|
-
export default class SidebarView extends Component {
|
|
7
|
-
static viewName = ''
|
|
8
|
-
static viewTitle = ''
|
|
9
|
-
static viewAdminOnly = false
|
|
10
|
-
|
|
11
|
-
viewTabs = {}
|
|
12
|
-
viewActiveTab = ''
|
|
13
|
-
|
|
14
|
-
protected $parent: HTMLElement
|
|
15
|
-
|
|
16
|
-
constructor(ctx: Context, $parent: HTMLElement) {
|
|
17
|
-
super(ctx)
|
|
18
|
-
|
|
19
|
-
this.$parent = $parent
|
|
20
|
-
this.$el = Utils.createElement(`<div class="atk-sidebar-view"></div>`)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
mount(siteName: string) {}
|
|
24
|
-
|
|
25
|
-
switchTab(tab: string, siteName: string): boolean|void {}
|
|
26
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import Context from '../../context'
|
|
2
|
-
import SidebarView from '../sidebar-view'
|
|
3
|
-
import * as Utils from '../../lib/utils'
|
|
4
|
-
import ListLite from '../list-lite'
|
|
5
|
-
|
|
6
|
-
export default class MessageView extends SidebarView {
|
|
7
|
-
static viewName = 'comments'
|
|
8
|
-
static viewTitle = '评论'
|
|
9
|
-
|
|
10
|
-
viewTabs: any = {}
|
|
11
|
-
viewActiveTab = ''
|
|
12
|
-
|
|
13
|
-
list!: ListLite
|
|
14
|
-
|
|
15
|
-
mount(siteName: string) {
|
|
16
|
-
// tabs
|
|
17
|
-
if (this.ctx.user.data.isAdmin) {
|
|
18
|
-
this.viewTabs = {
|
|
19
|
-
admin_all: '全部',
|
|
20
|
-
admin_pending: '待审',
|
|
21
|
-
all: '个人',
|
|
22
|
-
}
|
|
23
|
-
this.viewActiveTab = 'admin_all'
|
|
24
|
-
} else {
|
|
25
|
-
this.viewTabs = {
|
|
26
|
-
mentions: '提及',
|
|
27
|
-
all: '全部',
|
|
28
|
-
mine: '我的',
|
|
29
|
-
pending: '待审',
|
|
30
|
-
}
|
|
31
|
-
this.viewActiveTab = 'mentions'
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
this.list = new ListLite(this.ctx)
|
|
35
|
-
this.list.flatMode = true
|
|
36
|
-
this.list.unreadHighlight = true
|
|
37
|
-
this.list.scrollListenerAt = this.$parent
|
|
38
|
-
this.list.pageMode = 'pagination'
|
|
39
|
-
this.list.noCommentText = '<div class="atk-sidebar-no-content">无内容</div>'
|
|
40
|
-
this.list.renderComment = (comment) => {
|
|
41
|
-
comment.setOpenURL(`${comment.data.page_key}#atk-comment-${comment.data.id}`)
|
|
42
|
-
comment.onReplyBtnClick = () => {
|
|
43
|
-
if (this.ctx.conf.editorTravel === true) {
|
|
44
|
-
this.ctx.trigger('editor-reply', {data: comment.data, $el: comment.$el, scroll: false})
|
|
45
|
-
} else {
|
|
46
|
-
this.ctx.trigger('sidebar-hide')
|
|
47
|
-
this.ctx.trigger('editor-reply', {data: comment.data, $el: comment.$el, scroll: true})
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
this.list.paramsEditor = (params) => {
|
|
52
|
-
params.site_name = siteName
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.$el.innerHTML = ''
|
|
56
|
-
this.$el.append(this.list.$el)
|
|
57
|
-
|
|
58
|
-
this.switchTab(this.viewActiveTab, siteName)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
switchTab(tab: string, siteName: string): boolean|void {
|
|
62
|
-
//console.log(tab, siteName)
|
|
63
|
-
this.viewActiveTab = tab
|
|
64
|
-
this.list.paramsEditor = (params) => {
|
|
65
|
-
params.type = tab as any
|
|
66
|
-
params.site_name = siteName
|
|
67
|
-
}
|
|
68
|
-
this.list.fetchComments(0)
|
|
69
|
-
|
|
70
|
-
return true
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import Api from '~/src/api'
|
|
2
|
-
import Context from '../../context'
|
|
3
|
-
import Component from '../../lib/component'
|
|
4
|
-
import * as Utils from '../../lib/utils'
|
|
5
|
-
import * as Ui from '../../lib/ui'
|
|
6
|
-
import PageList from '../admin/page-list'
|
|
7
|
-
import Comment from '../comment'
|
|
8
|
-
import Pagination, { PaginationConf } from '../pagination'
|
|
9
|
-
import SidebarView from '../sidebar-view'
|
|
10
|
-
|
|
11
|
-
const PAGE_SIZE = 20
|
|
12
|
-
|
|
13
|
-
export default class PagesView extends SidebarView {
|
|
14
|
-
static viewName = 'pages'
|
|
15
|
-
static viewTitle = '页面'
|
|
16
|
-
static viewAdminOnly = true
|
|
17
|
-
|
|
18
|
-
viewTabs = {}
|
|
19
|
-
viewActiveTab = ''
|
|
20
|
-
|
|
21
|
-
pageList!: PageList
|
|
22
|
-
pagination!: Pagination
|
|
23
|
-
|
|
24
|
-
mount(siteName: string) {
|
|
25
|
-
if (!this.pageList) {
|
|
26
|
-
this.pageList = new PageList(this.ctx)
|
|
27
|
-
this.$el.append(this.pageList.$el)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
this.switchTab(this.viewActiveTab, siteName)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
switchTab(tab: string, siteName: string): boolean|void {
|
|
34
|
-
this.reqPages(siteName, 0)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async reqPages(siteName: string, offset: number) {
|
|
38
|
-
this.pageList.clearAll()
|
|
39
|
-
;(this.$el.parentNode as any)?.scrollTo(0, 0)
|
|
40
|
-
|
|
41
|
-
Ui.showLoading(this.$el)
|
|
42
|
-
|
|
43
|
-
const data = await new Api(this.ctx).pageGet(siteName, offset, PAGE_SIZE)
|
|
44
|
-
this.pageList.importPages(data.pages || [])
|
|
45
|
-
|
|
46
|
-
Ui.hideLoading(this.$el)
|
|
47
|
-
|
|
48
|
-
if (!this.pagination) {
|
|
49
|
-
this.pagination = new Pagination(data.total, {
|
|
50
|
-
pageSize: PAGE_SIZE,
|
|
51
|
-
onChange: (o: number) => {
|
|
52
|
-
this.reqPages(siteName, o)
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
this.$el.append(this.pagination.$el)
|
|
57
|
-
}
|
|
58
|
-
if (this.pagination && offset === 0)
|
|
59
|
-
this.pagination.update(offset, data.total)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import Api from '~/src/api'
|
|
2
|
-
import Context from '../../context'
|
|
3
|
-
import Component from '../../lib/component'
|
|
4
|
-
import * as Utils from '../../lib/utils'
|
|
5
|
-
import SiteList from '../admin/site-list'
|
|
6
|
-
import Comment from '../comment'
|
|
7
|
-
import SidebarView from '../sidebar-view'
|
|
8
|
-
|
|
9
|
-
export default class SettingView extends SidebarView {
|
|
10
|
-
static viewName = 'setting'
|
|
11
|
-
static viewTitle = '配置'
|
|
12
|
-
static viewAdminOnly = true
|
|
13
|
-
|
|
14
|
-
viewTabs = {}
|
|
15
|
-
viewActiveTab = ''
|
|
16
|
-
|
|
17
|
-
mount(siteName: string) {
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
switchTab(tab: string, siteName: string) {}
|
|
21
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import Api from '~/src/api'
|
|
2
|
-
import Context from '../../context'
|
|
3
|
-
import Component from '../../lib/component'
|
|
4
|
-
import * as Utils from '../../lib/utils'
|
|
5
|
-
import SiteList from '../admin/site-list'
|
|
6
|
-
import Comment from '../comment'
|
|
7
|
-
import SidebarView from '../sidebar-view'
|
|
8
|
-
|
|
9
|
-
export default class SitesView extends SidebarView {
|
|
10
|
-
static viewName = 'sites'
|
|
11
|
-
static viewTitle = '站点'
|
|
12
|
-
static viewAdminOnly = true
|
|
13
|
-
|
|
14
|
-
viewTabs = {}
|
|
15
|
-
viewActiveTab = ''
|
|
16
|
-
|
|
17
|
-
siteList!: SiteList
|
|
18
|
-
|
|
19
|
-
mount(siteName: string) {
|
|
20
|
-
if (!this.siteList) {
|
|
21
|
-
this.siteList = new SiteList(this.ctx)
|
|
22
|
-
this.$el.append(this.siteList.$el)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
this.reqSites()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
switchTab(tab: string, siteName: string) {
|
|
29
|
-
this.reqSites()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async reqSites() {
|
|
33
|
-
const sites = await new Api(this.ctx).siteGet()
|
|
34
|
-
this.siteList.loadSites(sites)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import Api from '~/src/api'
|
|
2
|
-
import Context from '../../context'
|
|
3
|
-
import Component from '../../lib/component'
|
|
4
|
-
import * as Utils from '../../lib/utils'
|
|
5
|
-
import * as Ui from '../../lib/ui'
|
|
6
|
-
import SiteList from '../admin/site-list'
|
|
7
|
-
import Comment from '../comment'
|
|
8
|
-
import SidebarView from '../sidebar-view'
|
|
9
|
-
|
|
10
|
-
export default class TransferView extends SidebarView {ß
|
|
11
|
-
static viewName = 'transfer'
|
|
12
|
-
static viewTitle = '迁移'
|
|
13
|
-
static viewAdminOnly = true
|
|
14
|
-
|
|
15
|
-
viewTabs = {
|
|
16
|
-
'import': '导入',
|
|
17
|
-
'export': '导出',
|
|
18
|
-
}
|
|
19
|
-
viewActiveTab = 'import'
|
|
20
|
-
|
|
21
|
-
mount(siteName: string) {
|
|
22
|
-
this.switchTab('import', siteName)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
switchTab(tab: string, siteName: string) {
|
|
26
|
-
if (tab === 'import') {
|
|
27
|
-
this.initImport()
|
|
28
|
-
} else if (tab === 'export') {
|
|
29
|
-
// if (window.confirm(`开始导出?`))
|
|
30
|
-
this.initExport()
|
|
31
|
-
return false
|
|
32
|
-
}
|
|
33
|
-
return true
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
initImport() {
|
|
37
|
-
this.$el.innerHTML =
|
|
38
|
-
`<div class="atk-log-wrap" style="display: none;">
|
|
39
|
-
<div class="atk-log-back-btn">返回</div>
|
|
40
|
-
<div class="atk-log"></div>
|
|
41
|
-
</div>
|
|
42
|
-
<div class="atk-form">
|
|
43
|
-
<div class="atk-label">数据类型</div>
|
|
44
|
-
<select name="AtkDataType">
|
|
45
|
-
<option value="artrans">Artrans (数据行囊)</option>
|
|
46
|
-
<option value="artalk_v1">Artalk v1 (PHP 旧版)</option>
|
|
47
|
-
<option value="typecho">Typecho</option>
|
|
48
|
-
<option value="wordpress">WordPress</option>
|
|
49
|
-
<option value="disqus">Disqus</option>
|
|
50
|
-
<option value="commento">Commento</option>
|
|
51
|
-
<option value="valine">Valine</option>
|
|
52
|
-
<option value="twikoo">Twikoo</option>
|
|
53
|
-
</select>
|
|
54
|
-
<div class="atk-label atk-data-file-label">数据文件</div>
|
|
55
|
-
<input type="file" name="AtkDataFile" accept="text/plain,.json">
|
|
56
|
-
<div class="atk-label">目标站点名</div>
|
|
57
|
-
<input type="text" name="AtkSiteName" placeholder="输入内容..." autocomplete="off">
|
|
58
|
-
<div class="atk-label">目标站点 URL</div>
|
|
59
|
-
<input type="text" name="AtkSiteURL" placeholder="输入内容..." autocomplete="off">
|
|
60
|
-
<div class="atk-label">启动参数(可选)</div>
|
|
61
|
-
<textarea name="AtkPayload"></textarea>
|
|
62
|
-
<span class="atk-desc">启动参数查阅:“<a href="https://artalk.js.org/guide/transfer.html" target="_blank">文档 · 数据搬家</a>”</span>
|
|
63
|
-
<button class="atk-btn" name="AtkSubmit">导入</button>
|
|
64
|
-
</div>`
|
|
65
|
-
|
|
66
|
-
const $form = this.$el.querySelector<HTMLSelectElement>('.atk-form')!
|
|
67
|
-
const $dataType = $form.querySelector<HTMLSelectElement>('[name="AtkDataType"]')!
|
|
68
|
-
const $dataFile = $form.querySelector<HTMLInputElement>('[name="AtkDataFile"]')!
|
|
69
|
-
const $dataFileLabel = $form.querySelector<HTMLInputElement>('.atk-data-file-label')!
|
|
70
|
-
const $siteName = $form.querySelector<HTMLInputElement>('[name="AtkSiteName"]')!
|
|
71
|
-
const $siteURL = $form.querySelector<HTMLInputElement>('[name="AtkSiteURL"]')!
|
|
72
|
-
const $payload = $form.querySelector<HTMLTextAreaElement>('[name="AtkPayload"]')!
|
|
73
|
-
const $submitBtn = $form.querySelector<HTMLButtonElement>('[name="AtkSubmit"]')!
|
|
74
|
-
const setError = (msg: string) => window.alert(msg)
|
|
75
|
-
|
|
76
|
-
$dataType.onchange = () => {
|
|
77
|
-
if (['typecho'].includes($dataType.value)) {
|
|
78
|
-
$dataFile.style.display = 'none'
|
|
79
|
-
$dataFileLabel.style.display = 'none'
|
|
80
|
-
} else {
|
|
81
|
-
$dataFile.style.display = ''
|
|
82
|
-
$dataFileLabel.style.display = ''
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
$submitBtn.onclick = () => {
|
|
87
|
-
const dataType = $dataType.value.trim()
|
|
88
|
-
const siteName = $siteName.value.trim()
|
|
89
|
-
const siteURL = $siteURL.value.trim()
|
|
90
|
-
const payload = $payload.value.trim()
|
|
91
|
-
|
|
92
|
-
if (dataType === '') {
|
|
93
|
-
setError('请选择数据类型')
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 请求 payload 参数制备
|
|
98
|
-
let rData: any = {}
|
|
99
|
-
if (payload) {
|
|
100
|
-
// JSON 格式检验
|
|
101
|
-
try {
|
|
102
|
-
rData = JSON.parse(payload)
|
|
103
|
-
} catch (err) {
|
|
104
|
-
setError(`Payload JSON 格式有误:${String(err)}`)
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (rData !instanceof Object) {
|
|
109
|
-
setError(`Payload 需为 JSON 对象`)
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (siteName) rData.t_name = siteName
|
|
114
|
-
if (siteURL) rData.t_url = siteURL
|
|
115
|
-
|
|
116
|
-
// 创建导入会话
|
|
117
|
-
const createSession = (dataStr?: string) => {
|
|
118
|
-
const $logWrap = this.$el.querySelector<HTMLElement>('.atk-log-wrap')!
|
|
119
|
-
const $log = $logWrap.querySelector<HTMLElement>('.atk-log')!
|
|
120
|
-
const $backBtn = this.$el.querySelector<HTMLElement>('.atk-log-back-btn')!
|
|
121
|
-
|
|
122
|
-
$logWrap.style.display = ''
|
|
123
|
-
$form.style.display = 'none'
|
|
124
|
-
|
|
125
|
-
$backBtn.onclick = () => {
|
|
126
|
-
$logWrap.style.display = 'none'
|
|
127
|
-
$form.style.display = ''
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (dataStr) rData.json_data = dataStr
|
|
131
|
-
|
|
132
|
-
// 创建 iframe
|
|
133
|
-
const frameName = `f_${+new Date()}`
|
|
134
|
-
const $frame = document.createElement('iframe')
|
|
135
|
-
$frame.className = 'atk-iframe'
|
|
136
|
-
$frame.name = frameName
|
|
137
|
-
$log.innerHTML = ''
|
|
138
|
-
$log.append($frame)
|
|
139
|
-
|
|
140
|
-
const formParams: {[k: string]: string} = {
|
|
141
|
-
type: dataType,
|
|
142
|
-
payload: JSON.stringify(rData),
|
|
143
|
-
token: this.ctx.user.data.token || '',
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 创建临时表单,初始化 iframe
|
|
147
|
-
const $formTmp = document.createElement('form')
|
|
148
|
-
$formTmp.style.display = 'none'
|
|
149
|
-
$formTmp.setAttribute('method', 'post')
|
|
150
|
-
$formTmp.setAttribute('action', `${this.ctx.conf.server}/admin/import`)
|
|
151
|
-
$formTmp.setAttribute("target", frameName)
|
|
152
|
-
|
|
153
|
-
Object.entries(formParams).forEach(([key, val]) => {
|
|
154
|
-
const $inputTmp = document.createElement('input')
|
|
155
|
-
$inputTmp.setAttribute('type', 'hidden')
|
|
156
|
-
$inputTmp.setAttribute('name', key)
|
|
157
|
-
$inputTmp.value = val
|
|
158
|
-
$formTmp.appendChild($inputTmp)
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
$logWrap.append($formTmp)
|
|
162
|
-
$formTmp.submit()
|
|
163
|
-
$formTmp.remove()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const reader = new FileReader()
|
|
167
|
-
reader.onload = () => {
|
|
168
|
-
const data = String(reader.result)
|
|
169
|
-
createSession(data)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// 是否已选择文件
|
|
173
|
-
if ($dataFile.files?.length) {
|
|
174
|
-
// 先读取文件
|
|
175
|
-
reader.readAsText($dataFile.files[0])
|
|
176
|
-
} else {
|
|
177
|
-
// 直接开始会话
|
|
178
|
-
createSession()
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async initExport() {
|
|
184
|
-
Ui.showLoading(this.$el)
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
const d = await new Api(this.ctx).export()
|
|
188
|
-
this.download(`artrans-${this.getYmdHisFilename()}.json`, d)
|
|
189
|
-
} catch (err: any) {
|
|
190
|
-
console.log(err)
|
|
191
|
-
window.alert(`${String(err)}`)
|
|
192
|
-
return
|
|
193
|
-
} finally { Ui.hideLoading(this.$el) }
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
download(filename: string, text: string) {
|
|
197
|
-
const el = document.createElement('a')
|
|
198
|
-
el.setAttribute('href', `data:text/json;charset=utf-8,${encodeURIComponent(text)}`);
|
|
199
|
-
el.setAttribute('download', filename)
|
|
200
|
-
el.style.display = 'none'
|
|
201
|
-
document.body.appendChild(el)
|
|
202
|
-
el.click()
|
|
203
|
-
document.body.removeChild(el)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
getYmdHisFilename() {
|
|
207
|
-
const date = new Date()
|
|
208
|
-
|
|
209
|
-
const year = date.getFullYear()
|
|
210
|
-
const month = date.getMonth() + 1
|
|
211
|
-
const day = date.getDate()
|
|
212
|
-
const hours = date.getHours()
|
|
213
|
-
const minutes = date.getMinutes()
|
|
214
|
-
const seconds = date.getSeconds()
|
|
215
|
-
|
|
216
|
-
return `${year}${month}${day}-${hours}${Utils.padWithZeros(minutes, 2)}${Utils.padWithZeros(seconds, 2)}`
|
|
217
|
-
}
|
|
218
|
-
}
|