Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-book
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-book
Commits
b11b04e1
提交
b11b04e1
authored
7月 22, 2026
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor(admin): establish editor feature registry
上级
d180e973
隐藏空白字符变更
内嵌
并排
正在显示
30 个修改的文件
包含
490 行增加
和
120 行删除
+490
-120
package.json
apps/admin/package.json
+1
-1
EditorDialogHost.jsx
.../src/common/wangeditor-customer/core/EditorDialogHost.jsx
+22
-0
create-feature-registry.js
...ommon/wangeditor-customer/core/create-feature-registry.js
+29
-0
define-editor-feature.js
.../common/wangeditor-customer/core/define-editor-feature.js
+6
-0
editor-dialog.js
...dmin/src/common/wangeditor-customer/core/editor-dialog.js
+14
-0
register-editor-features.js
...mmon/wangeditor-customer/core/register-editor-features.js
+15
-0
useEditorDialog.js
...in/src/common/wangeditor-customer/core/useEditorDialog.js
+22
-0
feature.js
...c/common/wangeditor-customer/features/ai-media/feature.js
+13
-0
feature.js
...ommon/wangeditor-customer/features/ai-question/feature.js
+17
-0
feature.js
...ommon/wangeditor-customer/features/ai-research/feature.js
+13
-0
feature.js
...rc/common/wangeditor-customer/features/ai-text/feature.js
+23
-0
feature.js
.../src/common/wangeditor-customer/features/audio/feature.js
+9
-0
feature.js
...wangeditor-customer/features/chapter-structure/feature.js
+14
-0
feature.js
...mon/wangeditor-customer/features/content-tools/feature.js
+8
-0
feature.js
...ommon/wangeditor-customer/features/expand-read/feature.js
+13
-0
feature.js
...rc/common/wangeditor-customer/features/formula/feature.js
+9
-0
feature.js
...rc/common/wangeditor-customer/features/gallery/feature.js
+14
-0
feature.js
...rc/common/wangeditor-customer/features/history/feature.js
+3
-0
feature.js
...n/src/common/wangeditor-customer/features/icon/feature.js
+4
-0
feature.js
.../src/common/wangeditor-customer/features/image/feature.js
+10
-0
index.js
apps/admin/src/common/wangeditor-customer/features/index.js
+42
-0
feature.js
...n/src/common/wangeditor-customer/features/link/feature.js
+9
-0
feature.js
...c/common/wangeditor-customer/features/practice/feature.js
+9
-0
feature.js
...rc/common/wangeditor-customer/features/preview/feature.js
+3
-0
feature.js
...rc/common/wangeditor-customer/features/tooltip/feature.js
+9
-0
feature.js
.../src/common/wangeditor-customer/features/video/feature.js
+9
-0
index.jsx
apps/admin/src/common/wangeditor-customer/index.jsx
+2
-119
setup.ts
apps/admin/src/test/setup.ts
+3
-0
editor-dialog.test.tsx
...admin/src/test/wangeditor-customer/editor-dialog.test.tsx
+69
-0
feature-registry.test.ts
...min/src/test/wangeditor-customer/feature-registry.test.ts
+76
-0
没有找到文件。
apps/admin/package.json
浏览文件 @
b11b04e1
...
...
@@ -10,7 +10,7 @@
"preview"
:
"vite preview"
,
"lint"
:
"oxlint --fix ."
,
"format"
:
"oxfmt src/"
,
"test"
:
"node --test src/app/route-manifest.test.mjs src/app/routes.boundary.test.mjs src/store/storage-import.test.mjs src/utils/*.test.js src/layout/components/*.test.js"
,
"test"
:
"node --test src/app/route-manifest.test.mjs src/app/routes.boundary.test.mjs src/store/storage-import.test.mjs src/utils/*.test.js src/layout/components/*.test.js
&& vitest run
"
,
"test:unit"
:
"vitest"
,
"test:unit:watch"
:
"vitest --watch"
},
...
...
apps/admin/src/common/wangeditor-customer/core/EditorDialogHost.jsx
0 → 100644
浏览文件 @
b11b04e1
import
{
useEditorDialog
}
from
'./useEditorDialog'
export
const
EditorDialogHost
=
({
editor
,
registry
,
runtime
})
=>
{
const
{
activeDialog
,
closeDialog
,
openDialog
}
=
useEditorDialog
(
editor
)
if
(
!
activeDialog
)
return
null
const
Dialog
=
registry
.
dialogs
.
get
(
activeDialog
.
id
)
if
(
!
Dialog
)
{
console
.
error
(
`Unknown editor dialog:
${
activeDialog
.
id
}
`
)
return
null
}
return
<
Dialog
key=
{
activeDialog
.
instance
}
open
payload=
{
activeDialog
.
payload
}
onClose=
{
closeDialog
}
openDialog=
{
openDialog
}
runtime=
{
runtime
}
/>
}
apps/admin/src/common/wangeditor-customer/core/create-feature-registry.js
0 → 100644
浏览文件 @
b11b04e1
const
assertUnique
=
(
values
,
label
)
=>
{
const
seen
=
new
Set
()
values
.
forEach
(
value
=>
{
if
(
seen
.
has
(
value
))
throw
new
Error
(
`Duplicate
${
label
}
:
${
value
}
`
)
seen
.
add
(
value
)
})
}
const
byOrder
=
(
left
,
right
)
=>
left
.
order
-
right
.
order
export
const
createFeatureRegistry
=
features
=>
{
assertUnique
(
features
.
map
(
feature
=>
feature
.
id
),
'feature id'
)
const
menus
=
features
.
flatMap
(
feature
=>
feature
.
menus
).
sort
(
byOrder
)
const
nodeModules
=
features
.
flatMap
(
feature
=>
feature
.
nodeModules
).
sort
(
byOrder
)
const
dialogEntries
=
features
.
flatMap
(
feature
=>
feature
.
dialogs
)
assertUnique
(
menus
.
map
(
entry
=>
entry
.
config
.
key
),
'menu key'
)
assertUnique
(
nodeModules
.
flatMap
(
entry
=>
entry
.
types
),
'node type'
)
assertUnique
(
dialogEntries
.
map
(
entry
=>
entry
.
id
),
'dialog id'
)
return
{
features
:
[...
features
],
menus
,
nodeModules
,
dialogs
:
new
Map
(
dialogEntries
.
map
(
entry
=>
[
entry
.
id
,
entry
.
component
])),
}
}
apps/admin/src/common/wangeditor-customer/core/define-editor-feature.js
0 → 100644
浏览文件 @
b11b04e1
export
const
defineEditorFeature
=
({
id
,
menus
=
[],
nodeModules
=
[],
dialogs
=
[],
})
=>
({
id
,
menus
,
nodeModules
,
dialogs
})
apps/admin/src/common/wangeditor-customer/core/editor-dialog.js
0 → 100644
浏览文件 @
b11b04e1
export
const
EDITOR_DIALOG_EVENT
=
'wangeditor-customer:dialog'
export
const
openEditorDialog
=
(
editor
,
id
,
payload
=
{})
=>
{
if
(
!
editor
?.
emit
)
throw
new
Error
(
'An editor instance is required to open a dialog'
)
editor
.
emit
(
EDITOR_DIALOG_EVENT
,
{
id
,
payload
})
}
export
const
subscribeEditorDialog
=
(
editor
,
listener
)
=>
{
if
(
!
editor
?.
on
||
!
editor
?.
off
)
return
()
=>
{}
editor
.
on
(
EDITOR_DIALOG_EVENT
,
listener
)
return
()
=>
editor
.
off
(
EDITOR_DIALOG_EVENT
,
listener
)
}
apps/admin/src/common/wangeditor-customer/core/register-editor-features.js
0 → 100644
浏览文件 @
b11b04e1
import
{
editorFeatureRegistry
}
from
'../features'
const
registrationKey
=
Symbol
.
for
(
'ebook.admin.wangeditor-customer.registered'
)
export
const
registerEditorFeatures
=
Boot
=>
{
if
(
Boot
[
registrationKey
])
return
Boot
.
registerModule
({
menus
:
editorFeatureRegistry
.
menus
.
map
(
entry
=>
entry
.
config
),
})
editorFeatureRegistry
.
nodeModules
.
forEach
(
entry
=>
Boot
.
registerModule
(
entry
.
module
))
// Feature registration changes require a page reload during HMR.
Object
.
defineProperty
(
Boot
,
registrationKey
,
{
value
:
true
})
}
apps/admin/src/common/wangeditor-customer/core/useEditorDialog.js
0 → 100644
浏览文件 @
b11b04e1
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
'react'
import
{
openEditorDialog
,
subscribeEditorDialog
}
from
'./editor-dialog'
export
const
useEditorDialog
=
editor
=>
{
const
[
activeDialog
,
setActiveDialog
]
=
useState
(
null
)
const
sequence
=
useRef
(
0
)
useEffect
(()
=>
{
setActiveDialog
(
null
)
return
subscribeEditorDialog
(
editor
,
request
=>
{
sequence
.
current
+=
1
setActiveDialog
({
...
request
,
instance
:
sequence
.
current
})
})
},
[
editor
])
const
closeDialog
=
useCallback
(()
=>
setActiveDialog
(
null
),
[])
const
openDialog
=
useCallback
((
id
,
payload
)
=>
openEditorDialog
(
editor
,
id
,
payload
),
[
editor
])
return
{
activeDialog
,
closeDialog
,
openDialog
}
}
apps/admin/src/common/wangeditor-customer/features/ai-media/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
AIDigitalHuman
from
'../../menu/AIDigitalHuman'
import
AIImage
from
'../../menu/AIImage'
import
AIVideo
from
'../../menu/AIVideo'
export
default
defineEditorFeature
({
id
:
'ai-media'
,
menus
:
[
{
order
:
280
,
config
:
AIDigitalHuman
},
{
order
:
320
,
config
:
AIImage
},
{
order
:
330
,
config
:
AIVideo
},
],
})
apps/admin/src/common/wangeditor-customer/features/ai-question/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
AIQuestionGapFill
from
'../../menu/AIQuestionGapFill'
import
AIQuestionJudge
from
'../../menu/AIQuestionJudge'
import
AIQuestionMultiple
from
'../../menu/AIQuestionMultiple'
import
AIQuestionOpenEnded
from
'../../menu/AIQuestionOpenEnded'
import
AIQuestionSingle
from
'../../menu/AIQuestionSingle'
export
default
defineEditorFeature
({
id
:
'ai-question'
,
menus
:
[
{
order
:
230
,
config
:
AIQuestionSingle
},
{
order
:
240
,
config
:
AIQuestionMultiple
},
{
order
:
250
,
config
:
AIQuestionJudge
},
{
order
:
260
,
config
:
AIQuestionGapFill
},
{
order
:
270
,
config
:
AIQuestionOpenEnded
},
],
})
apps/admin/src/common/wangeditor-customer/features/ai-research/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
AIBaiduSearch
from
'../../menu/AIBaiduSearch'
import
AISearch
from
'../../menu/AISearch'
import
AIWrite
from
'../../menu/AIWrite'
export
default
defineEditorFeature
({
id
:
'ai-research'
,
menus
:
[
{
order
:
300
,
config
:
AISearch
},
{
order
:
310
,
config
:
AIWrite
},
{
order
:
340
,
config
:
AIBaiduSearch
},
],
})
apps/admin/src/common/wangeditor-customer/features/ai-text/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
AIChat
from
'../../menu/AIChat'
import
AIContentInspect
from
'../../menu/AIContentInspect'
import
AIExpand
from
'../../menu/AIExpand'
import
AIPolishing
from
'../../menu/AIPolishing'
import
AIPunctuation
from
'../../menu/AIPunctuation'
import
AIRewrite
from
'../../menu/AIRewrite'
import
AISummary
from
'../../menu/AISummary'
import
AITranslate
from
'../../menu/AITranslate'
export
default
defineEditorFeature
({
id
:
'ai-text'
,
menus
:
[
{
order
:
160
,
config
:
AIChat
},
{
order
:
170
,
config
:
AIRewrite
},
{
order
:
180
,
config
:
AIExpand
},
{
order
:
190
,
config
:
AISummary
},
{
order
:
200
,
config
:
AIPolishing
},
{
order
:
210
,
config
:
AIPunctuation
},
{
order
:
220
,
config
:
AIContentInspect
},
{
order
:
290
,
config
:
AITranslate
},
],
})
apps/admin/src/common/wangeditor-customer/features/audio/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/Audio'
import
nodeModule
from
'../../node/audio'
export
default
defineEditorFeature
({
id
:
'audio'
,
menus
:
[{
order
:
50
,
config
:
menu
}],
nodeModules
:
[{
order
:
50
,
types
:
[
'chapterAudio'
],
module
:
nodeModule
}],
})
apps/admin/src/common/wangeditor-customer/features/chapter-structure/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
itemMenu
from
'../../customer/ChapterItem'
import
titleMenu
from
'../../customer/ChapterTitle'
import
sectionNodeModule
from
'../../node/chapterItem'
import
headerNodeModule
from
'../../node/chapterTitle'
export
default
defineEditorFeature
({
id
:
'chapter-structure'
,
menus
:
[{
order
:
80
,
config
:
titleMenu
},
{
order
:
90
,
config
:
itemMenu
}],
nodeModules
:
[
{
order
:
10
,
types
:
[
'chapterSection'
],
module
:
sectionNodeModule
},
{
order
:
20
,
types
:
[
'chapterHeader'
],
module
:
headerNodeModule
},
],
})
apps/admin/src/common/wangeditor-customer/features/content-tools/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
convertTooltipMenu
from
'../../customer/ConvertTooltipType'
import
removeSpacesMenu
from
'../../customer/RemoveSpaces'
export
default
defineEditorFeature
({
id
:
'content-tools'
,
menus
:
[{
order
:
140
,
config
:
removeSpacesMenu
},
{
order
:
150
,
config
:
convertTooltipMenu
}],
})
apps/admin/src/common/wangeditor-customer/features/expand-read/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/ExpandRead'
import
nodeModule
from
'../../node/expandRead'
import
simpleNodeModule
from
'../../node/expandReadItem'
export
default
defineEditorFeature
({
id
:
'expand-read'
,
menus
:
[{
order
:
130
,
config
:
menu
}],
nodeModules
:
[
{
order
:
120
,
types
:
[
'chapterExpandRead'
],
module
:
nodeModule
},
{
order
:
130
,
types
:
[
'chapterExpandReadSimple'
],
module
:
simpleNodeModule
},
],
})
apps/admin/src/common/wangeditor-customer/features/formula/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/Formula'
import
nodeModule
from
'../../node/formula'
export
default
defineEditorFeature
({
id
:
'formula'
,
menus
:
[{
order
:
60
,
config
:
menu
}],
nodeModules
:
[{
order
:
80
,
types
:
[
'chapterFormula'
],
module
:
nodeModule
}],
})
apps/admin/src/common/wangeditor-customer/features/gallery/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/Gallery'
import
onlineMenu
from
'../../customer/GalleryOnline'
import
nodeModule
from
'../../node/gallery'
import
inlineNodeModule
from
'../../node/galleryInline'
export
default
defineEditorFeature
({
id
:
'gallery'
,
menus
:
[{
order
:
20
,
config
:
menu
},
{
order
:
30
,
config
:
onlineMenu
}],
nodeModules
:
[
{
order
:
60
,
types
:
[
'chapterGallery'
],
module
:
nodeModule
},
{
order
:
70
,
types
:
[
'chapterGalleryInline'
],
module
:
inlineNodeModule
},
],
})
apps/admin/src/common/wangeditor-customer/features/history/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
export
default
defineEditorFeature
({
id
:
'history'
})
apps/admin/src/common/wangeditor-customer/features/icon/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../menu/Icon'
export
default
defineEditorFeature
({
id
:
'icon'
,
menus
:
[{
order
:
360
,
config
:
menu
}]
})
apps/admin/src/common/wangeditor-customer/features/image/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
editMenu
from
'../../customer/ImageEditor'
import
onlineMenu
from
'../../customer/ImageOnline'
import
nodeModule
from
'../../node/image'
export
default
defineEditorFeature
({
id
:
'image'
,
menus
:
[{
order
:
10
,
config
:
onlineMenu
},
{
order
:
110
,
config
:
editMenu
}],
nodeModules
:
[{
order
:
30
,
types
:
[
'chapterImage'
],
module
:
nodeModule
}],
})
apps/admin/src/common/wangeditor-customer/features/index.js
0 → 100644
浏览文件 @
b11b04e1
import
{
createFeatureRegistry
}
from
'../core/create-feature-registry'
import
aiMedia
from
'./ai-media/feature'
import
aiQuestion
from
'./ai-question/feature'
import
aiResearch
from
'./ai-research/feature'
import
aiText
from
'./ai-text/feature'
import
audio
from
'./audio/feature'
import
chapterStructure
from
'./chapter-structure/feature'
import
contentTools
from
'./content-tools/feature'
import
expandRead
from
'./expand-read/feature'
import
formula
from
'./formula/feature'
import
gallery
from
'./gallery/feature'
import
history
from
'./history/feature'
import
icon
from
'./icon/feature'
import
image
from
'./image/feature'
import
link
from
'./link/feature'
import
practice
from
'./practice/feature'
import
preview
from
'./preview/feature'
import
tooltip
from
'./tooltip/feature'
import
video
from
'./video/feature'
export
const
editorFeatures
=
[
image
,
gallery
,
video
,
audio
,
chapterStructure
,
formula
,
practice
,
tooltip
,
link
,
expandRead
,
contentTools
,
icon
,
aiText
,
aiQuestion
,
aiMedia
,
aiResearch
,
preview
,
history
,
]
export
const
editorFeatureRegistry
=
createFeatureRegistry
(
editorFeatures
)
apps/admin/src/common/wangeditor-customer/features/link/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/CustomerLink'
import
nodeModule
from
'../../node/link'
export
default
defineEditorFeature
({
id
:
'link'
,
menus
:
[{
order
:
120
,
config
:
menu
}],
nodeModules
:
[{
order
:
110
,
types
:
[
'chapterLink'
],
module
:
nodeModule
}],
})
apps/admin/src/common/wangeditor-customer/features/practice/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/Practice'
import
nodeModule
from
'../../node/practice'
export
default
defineEditorFeature
({
id
:
'practice'
,
menus
:
[{
order
:
100
,
config
:
menu
}],
nodeModules
:
[{
order
:
90
,
types
:
[
'chapterPractice'
],
module
:
nodeModule
}],
})
apps/admin/src/common/wangeditor-customer/features/preview/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
export
default
defineEditorFeature
({
id
:
'preview'
})
apps/admin/src/common/wangeditor-customer/features/tooltip/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/Tooltip'
import
nodeModule
from
'../../node/tooltip'
export
default
defineEditorFeature
({
id
:
'tooltip'
,
menus
:
[{
order
:
70
,
config
:
menu
}],
nodeModules
:
[{
order
:
100
,
types
:
[
'chapterTooltip'
],
module
:
nodeModule
}],
})
apps/admin/src/common/wangeditor-customer/features/video/feature.js
0 → 100644
浏览文件 @
b11b04e1
import
{
defineEditorFeature
}
from
'../../core/define-editor-feature'
import
menu
from
'../../customer/Video'
import
nodeModule
from
'../../node/video'
export
default
defineEditorFeature
({
id
:
'video'
,
menus
:
[{
order
:
40
,
config
:
menu
}],
nodeModules
:
[{
order
:
40
,
types
:
[
'chapterVideo'
],
module
:
nodeModule
}],
})
apps/admin/src/common/wangeditor-customer/index.jsx
浏览文件 @
b11b04e1
...
...
@@ -9,6 +9,7 @@ import { setPracticeRandom } from "@/store/modules/editor";
// import formulaEditor from 'easy-formula-editor'
import
"./utils/jax.less"
;
import
{
Boot
}
from
"@wangeditor/editor"
;
import
{
registerEditorFeatures
}
from
"./core/register-editor-features"
;
import
{
SlateEditor
,
DomEditor
,
SlateElement
,
SlateTransforms
}
from
"@wangeditor/editor"
;
import
{
Editor
,
Toolbar
}
from
"@wangeditor/editor-for-react"
;
...
...
@@ -21,46 +22,6 @@ dayjs.extend(relativeTime);
import
{
storageChange
}
from
"@/utils/storage.js"
;
import
ImageAutoOnlineConf
from
"./customer/ImageOnline"
;
import
GalleryAutoConf
from
"./customer/Gallery"
;
import
GalleryAutoOnlineConf
from
"./customer/GalleryOnline"
;
import
VideoAutoConf
from
"./customer/Video"
;
import
AudioAutoConf
from
"./customer/Audio"
;
import
ChapterTitleAutoConf
from
"./customer/ChapterTitle"
;
import
ChapterItemAutoConf
from
"./customer/ChapterItem"
;
import
PracticeAutoConf
from
"./customer/Practice"
;
import
FormulaAutoConf
from
"./customer/Formula"
;
import
TooltipAutoConf
from
"./customer/Tooltip"
;
import
ImageEditorConf
from
"./customer/ImageEditor"
;
import
CustomerLinkConf
from
"./customer/CustomerLink"
;
import
ExpandReadConf
from
"./customer/ExpandRead"
;
import
RemoveSpacesConf
from
"./customer/RemoveSpaces"
;
import
ConvertTooltipTypeConf
from
"./customer/ConvertTooltipType"
;
// AI对话
import
AIChat
from
"./menu/AIChat"
;
// AI辅助
import
AIRewrite
from
"./menu/AIRewrite"
;
import
AIExpand
from
"./menu/AIExpand"
;
import
AISummary
from
"./menu/AISummary"
;
import
AIPolishing
from
"./menu/AIPolishing"
;
import
AIPunctuation
from
"./menu/AIPunctuation"
;
import
AIContentInspect
from
"./menu/AIContentInspect"
;
import
AIQuestionSingle
from
"./menu/AIQuestionSingle"
;
import
AIQuestionMultiple
from
"./menu/AIQuestionMultiple"
;
import
AIQuestionJudge
from
"./menu/AIQuestionJudge"
;
import
AIQuestionGapFill
from
"./menu/AIQuestionGapFill"
;
import
AIQuestionOpenEnded
from
"./menu/AIQuestionOpenEnded"
;
import
AIDigitalHuman
from
"./menu/AIDigitalHuman"
;
import
AITranslate
from
"./menu/AITranslate"
;
import
AISearch
from
"./menu/AISearch"
;
import
AIWrite
from
"./menu/AIWrite"
;
import
AIImage
from
"./menu/AIImage"
;
import
AIVideo
from
"./menu/AIVideo"
;
import
AIBaiduSearch
from
"./menu/AIBaiduSearch"
;
import
Icon
from
"./menu/Icon"
;
import
ImageModal
from
"./components/image"
;
import
VideoModal
from
"./components/video"
;
import
GalleryModal
from
"./components/gallery"
;
...
...
@@ -73,20 +34,6 @@ import TooltipModal from "./components/tooltip";
import
LinkModal
from
"./components/link"
;
import
ExpandModal
from
"./components/expand"
;
import
chapterSectionModule
from
"./node/chapterItem"
;
import
chapterHeaderModule
from
"./node/chapterTitle"
;
import
chapterImageModule
from
"./node/image"
;
import
chapterVideoModule
from
"./node/video"
;
import
chapterAudioModule
from
"./node/audio"
;
import
chapterGalleryModule
from
"./node/gallery"
;
import
chapterGalleryInlineModule
from
"./node/galleryInline"
;
import
chapterPracticeModule
from
"./node/practice"
;
import
formulaModule
from
"./node/formula"
;
import
tooltipModule
from
"./node/tooltip"
;
import
linkModule
from
"./node/link"
;
import
expandRead
from
"./node/expandRead"
;
import
expandReadSimple
from
"./node/expandReadItem"
;
import
PracticeSettingModal
from
"./practice/index"
;
import
PreviewModal
from
"./components/preview"
;
...
...
@@ -94,71 +41,7 @@ import HistoryModal from "./history/";
import
"./index.less"
;
const
module
=
{
menus
:
[
// ImageAutoConf,
ImageAutoOnlineConf
,
GalleryAutoConf
,
GalleryAutoOnlineConf
,
VideoAutoConf
,
AudioAutoConf
,
FormulaAutoConf
,
TooltipAutoConf
,
ChapterTitleAutoConf
,
ChapterItemAutoConf
,
PracticeAutoConf
,
ImageEditorConf
,
CustomerLinkConf
,
ExpandReadConf
,
RemoveSpacesConf
,
ConvertTooltipTypeConf
,
AIChat
,
AIRewrite
,
AIExpand
,
AISummary
,
AIPolishing
,
AIPunctuation
,
AIContentInspect
,
AIQuestionSingle
,
AIQuestionMultiple
,
AIQuestionJudge
,
AIQuestionGapFill
,
AIQuestionOpenEnded
,
AIDigitalHuman
,
AITranslate
,
AISearch
,
AIWrite
,
AIImage
,
AIVideo
,
AIBaiduSearch
,
Icon
,
],
};
Boot
.
registerModule
(
module
);
// 注册节头内容
Boot
.
registerModule
(
chapterSectionModule
);
// 注册章头内容
Boot
.
registerModule
(
chapterHeaderModule
);
// 注册图片内容
Boot
.
registerModule
(
chapterImageModule
);
// 注册视频内容
Boot
.
registerModule
(
chapterVideoModule
);
// 注册音频内容
Boot
.
registerModule
(
chapterAudioModule
);
// 注册画廊
Boot
.
registerModule
(
chapterGalleryModule
);
Boot
.
registerModule
(
chapterGalleryInlineModule
);
// 注册公式
Boot
.
registerModule
(
formulaModule
);
// 注册练习
Boot
.
registerModule
(
chapterPracticeModule
);
// 注册气泡
Boot
.
registerModule
(
tooltipModule
);
// 注册链接
Boot
.
registerModule
(
linkModule
);
// 注册扩展阅读
Boot
.
registerModule
(
expandRead
);
Boot
.
registerModule
(
expandReadSimple
);
registerEditorFeatures
(
Boot
);
const
tabsMenu
=
[
{
key
:
"text"
,
title
:
"文本设置"
},
...
...
apps/admin/src/test/setup.ts
浏览文件 @
b11b04e1
import
'@testing-library/jest-dom/vitest'
// The legacy iconfont side-effect reads the final script element while loading.
document
.
head
.
appendChild
(
document
.
createElement
(
'script'
))
apps/admin/src/test/wangeditor-customer/editor-dialog.test.tsx
0 → 100644
浏览文件 @
b11b04e1
import
{
act
,
render
,
screen
}
from
'@testing-library/react'
import
{
describe
,
expect
,
it
,
vi
}
from
'vitest'
import
{
EditorDialogHost
}
from
'@/common/wangeditor-customer/core/EditorDialogHost'
import
{
openEditorDialog
}
from
'@/common/wangeditor-customer/core/editor-dialog'
const
createEditor
=
()
=>
{
const
listeners
=
new
Map
<
string
,
Set
<
(
value
:
unknown
)
=>
void
>>
()
return
{
on
(
type
,
listener
)
{
const
group
=
listeners
.
get
(
type
)
||
new
Set
()
group
.
add
(
listener
)
listeners
.
set
(
type
,
group
)
},
off
(
type
,
listener
)
{
listeners
.
get
(
type
)?.
delete
(
listener
)
},
emit
(
type
,
value
)
{
listeners
.
get
(
type
)?.
forEach
(
listener
=>
listener
(
value
))
},
listenerCount
(
type
)
{
return
listeners
.
get
(
type
)?.
size
||
0
},
}
}
const
TestDialog
=
({
payload
,
onClose
})
=>
(
<
div
>
<
span
>
{
payload
.
title
}
</
span
>
<
button
onClick=
{
onClose
}
>
close
</
button
>
</
div
>
)
describe
(
'EditorDialogHost'
,
()
=>
{
it
(
'routes a request only to the host for the emitting editor'
,
()
=>
{
const
first
=
createEditor
()
const
second
=
createEditor
()
const
registry
=
{
dialogs
:
new
Map
([[
'test.open'
,
TestDialog
]])
}
render
(<>
<
EditorDialogHost
editor=
{
first
}
registry=
{
registry
}
runtime=
{
{
editor
:
first
}
}
/>
<
EditorDialogHost
editor=
{
second
}
registry=
{
registry
}
runtime=
{
{
editor
:
second
}
}
/>
</>)
act
(()
=>
openEditorDialog
(
first
,
'test.open'
,
{
title
:
'first editor'
}))
expect
(
screen
.
getAllByText
(
'first editor'
)).
toHaveLength
(
1
)
})
it
(
'unsubscribes when the host unmounts'
,
()
=>
{
const
editor
=
createEditor
()
const
registry
=
{
dialogs
:
new
Map
()
}
const
view
=
render
(<
EditorDialogHost
editor=
{
editor
}
registry=
{
registry
}
runtime=
{
{
editor
}
}
/>)
expect
(
editor
.
listenerCount
(
'wangeditor-customer:dialog'
)).
toBe
(
1
)
view
.
unmount
()
expect
(
editor
.
listenerCount
(
'wangeditor-customer:dialog'
)).
toBe
(
0
)
})
it
(
'reports an unknown dialog id without crashing the editor'
,
()
=>
{
const
editor
=
createEditor
()
const
error
=
vi
.
spyOn
(
console
,
'error'
).
mockImplementation
(()
=>
{})
render
(<
EditorDialogHost
editor=
{
editor
}
registry=
{
{
dialogs
:
new
Map
()
}
}
runtime=
{
{
editor
}
}
/>)
act
(()
=>
openEditorDialog
(
editor
,
'missing.dialog'
))
expect
(
error
).
toHaveBeenCalledWith
(
'Unknown editor dialog: missing.dialog'
)
error
.
mockRestore
()
})
})
apps/admin/src/test/wangeditor-customer/feature-registry.test.ts
0 → 100644
浏览文件 @
b11b04e1
import
{
describe
,
expect
,
it
}
from
'vitest'
import
{
defineEditorFeature
}
from
'@/common/wangeditor-customer/core/define-editor-feature'
import
{
createFeatureRegistry
}
from
'@/common/wangeditor-customer/core/create-feature-registry'
import
{
registerEditorFeatures
}
from
'@/common/wangeditor-customer/core/register-editor-features'
import
{
editorFeatureRegistry
}
from
'@/common/wangeditor-customer/features'
const
menu
=
key
=>
({
key
,
factory
:
()
=>
({})
})
const
dialog
=
()
=>
null
const
expectedMenuKeys
=
[
'ImageAutoOnline'
,
'GalleryAuto'
,
'GalleryAutoOnline'
,
'VideoAuto'
,
'AudioAuto'
,
'FormulaAuto'
,
'TooltipAuto'
,
'ChapterTitle'
,
'ChapterItem'
,
'Practice'
,
'ImageEditor'
,
'CustomerLink'
,
'ExpandRead'
,
'RemoveSpaces'
,
'ConvertTooltipType'
,
'AIChat'
,
'AIRewrite'
,
'AIExpand'
,
'AISummary'
,
'AIPolishing'
,
'AIPunctuation'
,
'AIContentInspect'
,
'AIQuestionSingle'
,
'AIQuestionMultiple'
,
'AIQuestionJudge'
,
'AIQuestionGapFill'
,
'AIQuestionOpenEnded'
,
'AIDigitalHuman'
,
'AITranslate'
,
'AISearch'
,
'AIWrite'
,
'AIImage'
,
'AIVideo'
,
'AIBaiduSearch'
,
'Icon'
,
]
const
expectedNodeTypes
=
[
'chapterSection'
,
'chapterHeader'
,
'chapterImage'
,
'chapterVideo'
,
'chapterAudio'
,
'chapterGallery'
,
'chapterGalleryInline'
,
'chapterFormula'
,
'chapterPractice'
,
'chapterTooltip'
,
'chapterLink'
,
'chapterExpandRead'
,
'chapterExpandReadSimple'
,
]
describe
(
'createFeatureRegistry'
,
()
=>
{
it
(
'sorts menu and node registrations independently'
,
()
=>
{
const
registry
=
createFeatureRegistry
([
defineEditorFeature
({
id
:
'later-feature'
,
menus
:
[{
order
:
20
,
config
:
menu
(
'later'
)
}],
nodeModules
:
[{
order
:
10
,
types
:
[
'node-a'
],
module
:
{
editorPlugin
()
{}
}
}],
}),
defineEditorFeature
({
id
:
'earlier-feature'
,
menus
:
[{
order
:
10
,
config
:
menu
(
'earlier'
)
}],
nodeModules
:
[{
order
:
20
,
types
:
[
'node-b'
],
module
:
{
editorPlugin
()
{}
}
}],
}),
])
expect
(
registry
.
menus
.
map
(
entry
=>
entry
.
config
.
key
)).
toEqual
([
'earlier'
,
'later'
])
expect
(
registry
.
nodeModules
.
flatMap
(
entry
=>
entry
.
types
)).
toEqual
([
'node-a'
,
'node-b'
])
})
it
(
'rejects duplicate feature, menu, node, and dialog ids'
,
()
=>
{
const
make
=
overrides
=>
defineEditorFeature
({
id
:
'feature-a'
,
menus
:
[{
order
:
10
,
config
:
menu
(
'menu-a'
)
}],
nodeModules
:
[{
order
:
10
,
types
:
[
'node-a'
],
module
:
{}
}],
dialogs
:
[{
id
:
'dialog-a'
,
component
:
dialog
}],
...
overrides
,
})
expect
(()
=>
createFeatureRegistry
([
make
(),
make
()])).
toThrow
(
'Duplicate feature id: feature-a'
)
expect
(()
=>
createFeatureRegistry
([
make
(),
make
({
id
:
'feature-b'
})])).
toThrow
(
'Duplicate menu key: menu-a'
)
expect
(()
=>
createFeatureRegistry
([
make
(),
make
({
id
:
'feature-b'
,
menus
:
[]
})])).
toThrow
(
'Duplicate node type: node-a'
)
expect
(()
=>
createFeatureRegistry
([
make
(),
make
({
id
:
'feature-b'
,
menus
:
[],
nodeModules
:
[]
})])).
toThrow
(
'Duplicate dialog id: dialog-a'
)
})
it
(
'keeps the legacy menu and node registration orders'
,
()
=>
{
expect
(
editorFeatureRegistry
.
menus
.
map
(
entry
=>
entry
.
config
.
key
)).
toEqual
(
expectedMenuKeys
)
expect
(
editorFeatureRegistry
.
nodeModules
.
flatMap
(
entry
=>
entry
.
types
)).
toEqual
(
expectedNodeTypes
)
})
it
(
'registers the menu module first and every node module once'
,
()
=>
{
const
calls
=
[]
const
Boot
=
{
registerModule
:
module
=>
calls
.
push
(
module
)
}
registerEditorFeatures
(
Boot
)
registerEditorFeatures
(
Boot
)
expect
(
calls
).
toHaveLength
(
1
+
expectedNodeTypes
.
length
)
expect
(
calls
[
0
].
menus
.
map
(
menu
=>
menu
.
key
)).
toEqual
(
expectedMenuKeys
)
})
})
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论