cherry-muse 1.0.1
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/LICENSE +162 -0
- package/README.md +139 -0
- package/dist/addons/cherry-code-block-card-plugin.js +1 -0
- package/dist/addons/cherry-code-block-echarts-plugin.js +1 -0
- package/dist/addons/cherry-code-block-mermaid-plugin.js +1 -0
- package/dist/cherry-markdown.core.common.js +1 -0
- package/dist/cherry-markdown.core.js +1 -0
- package/dist/cherry-markdown.css +4089 -0
- package/dist/cherry-markdown.engine.core.common.js +1 -0
- package/dist/cherry-markdown.engine.core.esm.js +1 -0
- package/dist/cherry-markdown.engine.core.js +1 -0
- package/dist/cherry-markdown.esm.js +1 -0
- package/dist/cherry-markdown.js +70837 -0
- package/dist/cherry-markdown.js.map +1 -0
- package/dist/cherry-markdown.min.css +1 -0
- package/dist/cherry-markdown.min.js +1 -0
- package/dist/stats.html +4838 -0
- package/examples/scripts/pinyin/README.md +53 -0
- package/package.json +167 -0
- package/src/Cherry.config.js +411 -0
- package/src/Cherry.js +788 -0
- package/src/CherryStatic.js +70 -0
- package/src/Editor.js +746 -0
- package/src/Engine.js +334 -0
- package/src/Event.js +74 -0
- package/src/Factory.js +180 -0
- package/src/Logger.js +31 -0
- package/src/Previewer.js +1147 -0
- package/src/Sanitizer.js +4 -0
- package/src/Sanitizer.node.js +7 -0
- package/src/Stats.js +101 -0
- package/src/Theme.js +46 -0
- package/src/UrlCache.js +98 -0
- package/src/addons/cherry-code-block-card-plugin.js +213 -0
- package/src/addons/cherry-code-block-echarts-plugin.js +161 -0
- package/src/addons/cherry-code-block-mermaid-plugin.js +118 -0
- package/src/core/HookCenter.js +303 -0
- package/src/core/HooksConfig.js +106 -0
- package/src/core/ParagraphBase.js +314 -0
- package/src/core/SentenceBase.js +65 -0
- package/src/core/SyntaxBase.js +197 -0
- package/src/core/hooks/AutoLink.js +251 -0
- package/src/core/hooks/BackgroundColor.js +46 -0
- package/src/core/hooks/Badge.js +100 -0
- package/src/core/hooks/Blockquote.js +113 -0
- package/src/core/hooks/Br.js +85 -0
- package/src/core/hooks/CodeBlock.js +876 -0
- package/src/core/hooks/Color.js +78 -0
- package/src/core/hooks/CommentReference.js +96 -0
- package/src/core/hooks/Detail.js +138 -0
- package/src/core/hooks/Emoji.config.js +9388 -0
- package/src/core/hooks/Emoji.js +223 -0
- package/src/core/hooks/Emphasis.js +113 -0
- package/src/core/hooks/Footnote.js +125 -0
- package/src/core/hooks/FrontMatter.js +52 -0
- package/src/core/hooks/FrontMatterVars.js +82 -0
- package/src/core/hooks/Header.js +229 -0
- package/src/core/hooks/HighLight.js +37 -0
- package/src/core/hooks/Hr.js +52 -0
- package/src/core/hooks/HtmlBlock.js +159 -0
- package/src/core/hooks/Iframe.js +80 -0
- package/src/core/hooks/Image.js +276 -0
- package/src/core/hooks/InlineCode.js +45 -0
- package/src/core/hooks/InlineMath.js +142 -0
- package/src/core/hooks/Link.js +169 -0
- package/src/core/hooks/List.js +260 -0
- package/src/core/hooks/Mark.js +55 -0
- package/src/core/hooks/MathBlock.js +97 -0
- package/src/core/hooks/Panel.js +170 -0
- package/src/core/hooks/Paragraph.js +84 -0
- package/src/core/hooks/Ruby.js +34 -0
- package/src/core/hooks/Size.js +84 -0
- package/src/core/hooks/Strikethrough.js +54 -0
- package/src/core/hooks/Sub.js +47 -0
- package/src/core/hooks/SuggestList.js +317 -0
- package/src/core/hooks/Suggester.js +759 -0
- package/src/core/hooks/Sup.js +47 -0
- package/src/core/hooks/Table.js +315 -0
- package/src/core/hooks/Toc.js +290 -0
- package/src/core/hooks/Transfer.js +47 -0
- package/src/core/hooks/Underline.js +37 -0
- package/src/index.core.js +29 -0
- package/src/index.engine.core.js +62 -0
- package/src/index.engine.js +30 -0
- package/src/index.js +28 -0
- package/src/locales/index.js +21 -0
- package/src/locales/zh_CN.js +170 -0
- package/src/sass/cherry.scss +122 -0
- package/src/sass/components/bubble.scss +122 -0
- package/src/sass/components/codemirror.scss +628 -0
- package/src/sass/components/dropdown.scss +37 -0
- package/src/sass/components/editor.scss +78 -0
- package/src/sass/components/preview.scss +71 -0
- package/src/sass/components/prism.scss +142 -0
- package/src/sass/components/stats.scss +32 -0
- package/src/sass/components/toc.scss +184 -0
- package/src/sass/components/toolbar.scss +117 -0
- package/src/sass/core/AutoLink.scss +20 -0
- package/src/sass/core/BackgroundColor.scss +0 -0
- package/src/sass/core/Badge.scss +116 -0
- package/src/sass/core/Blockquote.scss +12 -0
- package/src/sass/core/Br.scss +0 -0
- package/src/sass/core/Card.scss +219 -0
- package/src/sass/core/CodeBlock.scss +205 -0
- package/src/sass/core/Color.scss +37 -0
- package/src/sass/core/CommentReference.scss +0 -0
- package/src/sass/core/Detail.scss +107 -0
- package/src/sass/core/Emoji.scss +127 -0
- package/src/sass/core/Emphasis.scss +9 -0
- package/src/sass/core/Footnote.scss +21 -0
- package/src/sass/core/FrontMatterVars.scss +19 -0
- package/src/sass/core/Header.scss +103 -0
- package/src/sass/core/HighLight.scss +0 -0
- package/src/sass/core/Hr.scss +10 -0
- package/src/sass/core/HtmlBlock.scss +0 -0
- package/src/sass/core/Iframe.scss +36 -0
- package/src/sass/core/Image.scss +59 -0
- package/src/sass/core/InlineCode.scss +10 -0
- package/src/sass/core/InlineMath.scss +11 -0
- package/src/sass/core/Link.scss +16 -0
- package/src/sass/core/List.scss +61 -0
- package/src/sass/core/Mark.scss +15 -0
- package/src/sass/core/MathBlock.scss +0 -0
- package/src/sass/core/Panel.scss +150 -0
- package/src/sass/core/Paragraph.scss +6 -0
- package/src/sass/core/Ruby.scss +0 -0
- package/src/sass/core/Size.scss +8 -0
- package/src/sass/core/Strikethrough.scss +0 -0
- package/src/sass/core/Sub.scss +5 -0
- package/src/sass/core/Suggester.scss +62 -0
- package/src/sass/core/Sup.scss +5 -0
- package/src/sass/core/Table.scss +127 -0
- package/src/sass/core/Toc.scss +28 -0
- package/src/sass/core/Transfer.scss +0 -0
- package/src/sass/core/Underline.scss +0 -0
- package/src/sass/google-fonts.scss +34 -0
- package/src/sass/index.scss +3 -0
- package/src/sass/prism/dark.scss +131 -0
- package/src/sass/prism/light.scss +143 -0
- package/src/sass/variables/colors.scss +96 -0
- package/src/toolbars/Bubble.js +232 -0
- package/src/toolbars/BubbleTable.js +147 -0
- package/src/toolbars/HookCenter.js +185 -0
- package/src/toolbars/MenuBase.js +357 -0
- package/src/toolbars/PreviewerBubble.js +558 -0
- package/src/toolbars/Toc.js +246 -0
- package/src/toolbars/Toolbar.js +401 -0
- package/src/toolbars/hooks/Audio.js +53 -0
- package/src/toolbars/hooks/Badge.js +80 -0
- package/src/toolbars/hooks/BarTable.js +41 -0
- package/src/toolbars/hooks/Bold.js +70 -0
- package/src/toolbars/hooks/Br.js +34 -0
- package/src/toolbars/hooks/Card.js +64 -0
- package/src/toolbars/hooks/CheckList.js +41 -0
- package/src/toolbars/hooks/Code.js +46 -0
- package/src/toolbars/hooks/Color.js +285 -0
- package/src/toolbars/hooks/Copy.js +139 -0
- package/src/toolbars/hooks/Detail.js +70 -0
- package/src/toolbars/hooks/ECharts.js +303 -0
- package/src/toolbars/hooks/Emoji.js +303 -0
- package/src/toolbars/hooks/Export.js +47 -0
- package/src/toolbars/hooks/File.js +54 -0
- package/src/toolbars/hooks/Formula.js +36 -0
- package/src/toolbars/hooks/FullScreen.js +55 -0
- package/src/toolbars/hooks/Graph.js +281 -0
- package/src/toolbars/hooks/H1.js +71 -0
- package/src/toolbars/hooks/H2.js +71 -0
- package/src/toolbars/hooks/H3.js +71 -0
- package/src/toolbars/hooks/Header.js +100 -0
- package/src/toolbars/hooks/Hr.js +35 -0
- package/src/toolbars/hooks/Iframe.js +35 -0
- package/src/toolbars/hooks/Image.js +60 -0
- package/src/toolbars/hooks/Insert.js +36 -0
- package/src/toolbars/hooks/Italic.js +70 -0
- package/src/toolbars/hooks/LineTable.js +41 -0
- package/src/toolbars/hooks/Link.js +46 -0
- package/src/toolbars/hooks/List.js +55 -0
- package/src/toolbars/hooks/Ol.js +41 -0
- package/src/toolbars/hooks/Panel.js +155 -0
- package/src/toolbars/hooks/Quote.js +45 -0
- package/src/toolbars/hooks/Redo.js +33 -0
- package/src/toolbars/hooks/Ruby.js +59 -0
- package/src/toolbars/hooks/Size.js +100 -0
- package/src/toolbars/hooks/Split.js +37 -0
- package/src/toolbars/hooks/Strikethrough.js +65 -0
- package/src/toolbars/hooks/Sub.js +58 -0
- package/src/toolbars/hooks/Sup.js +58 -0
- package/src/toolbars/hooks/SwitchModel.js +78 -0
- package/src/toolbars/hooks/Table.js +56 -0
- package/src/toolbars/hooks/Toc.js +35 -0
- package/src/toolbars/hooks/TogglePreview.js +79 -0
- package/src/toolbars/hooks/Ul.js +41 -0
- package/src/toolbars/hooks/Underline.js +65 -0
- package/src/toolbars/hooks/Undo.js +30 -0
- package/src/toolbars/hooks/Video.js +53 -0
- package/src/utils/LazyLoadImg.js +341 -0
- package/src/utils/autoindent.js +58 -0
- package/src/utils/codeBlockContentHandler.js +351 -0
- package/src/utils/config.js +98 -0
- package/src/utils/copy.js +55 -0
- package/src/utils/dialog.js +196 -0
- package/src/utils/dom.js +162 -0
- package/src/utils/downloadUtil.js +23 -0
- package/src/utils/env.js +22 -0
- package/src/utils/error.js +61 -0
- package/src/utils/event.js +38 -0
- package/src/utils/export.js +115 -0
- package/src/utils/file.js +121 -0
- package/src/utils/formulaUtilsHandler.js +230 -0
- package/src/utils/htmlparser.js +977 -0
- package/src/utils/image.js +99 -0
- package/src/utils/imgSizeHandler.js +279 -0
- package/src/utils/jsonUtils.js +17 -0
- package/src/utils/lineFeed.js +49 -0
- package/src/utils/listContentHandler.js +227 -0
- package/src/utils/lookbehind-replace.js +81 -0
- package/src/utils/mathjax.js +89 -0
- package/src/utils/myersDiff.js +211 -0
- package/src/utils/pasteHelper.js +253 -0
- package/src/utils/recount-pos.js +59 -0
- package/src/utils/regexp.js +295 -0
- package/src/utils/sanitize.js +477 -0
- package/src/utils/selection.js +50 -0
- package/src/utils/svgUtils.js +96 -0
- package/src/utils/tableContentHandler.js +592 -0
- package/tools/README.md +3 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import Toolbar from './Toolbar';
|
|
17
|
+
import Event from '../Event';
|
|
18
|
+
/**
|
|
19
|
+
* 在编辑区域选中文本时浮现的bubble工具栏
|
|
20
|
+
*/
|
|
21
|
+
export default class Bubble extends Toolbar {
|
|
22
|
+
/**
|
|
23
|
+
* @type {'flex' | 'block'}
|
|
24
|
+
*/
|
|
25
|
+
static displayType = 'flex';
|
|
26
|
+
// constructor(options) {
|
|
27
|
+
// super(options);
|
|
28
|
+
// }
|
|
29
|
+
|
|
30
|
+
set visible(visible) {
|
|
31
|
+
const bubbleStyle = window.getComputedStyle(this.bubbleDom);
|
|
32
|
+
if (visible) {
|
|
33
|
+
bubbleStyle.display === 'none' && (this.bubbleDom.style.display = Bubble.displayType);
|
|
34
|
+
// bubbleStyle.visibility !== 'visible' && (this.bubbleBottom.style.visibility = 'visible');
|
|
35
|
+
} else {
|
|
36
|
+
bubbleStyle.display !== 'none' && (this.bubbleDom.style.display = 'none');
|
|
37
|
+
// bubbleStyle.visibility !== 'hidden' && (this.bubbleBottom.style.visibility = 'hidden');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get visible() {
|
|
42
|
+
const bubbleStyle = window.getComputedStyle(this.bubbleDom);
|
|
43
|
+
return bubbleStyle.display !== 'none' && bubbleStyle.visibility !== 'hidden';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
init() {
|
|
47
|
+
this.options.editor = this.$cherry.editor;
|
|
48
|
+
this.addSelectionChangeListener();
|
|
49
|
+
this.bubbleDom = this.options.dom;
|
|
50
|
+
this.editorDom = this.options.editor.getEditorDom();
|
|
51
|
+
this.initBubbleDom();
|
|
52
|
+
this.editorDom.querySelector('.CodeMirror').appendChild(this.bubbleDom);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
appendMenusToDom(menus) {
|
|
56
|
+
this.options.dom.appendChild(menus);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 计算编辑区域的偏移量
|
|
61
|
+
* @returns {number} 编辑区域的滚动区域
|
|
62
|
+
*/
|
|
63
|
+
getScrollTop() {
|
|
64
|
+
return this.options.editor.editor.getScrollInfo().top;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 当编辑区域滚动的时候自动隐藏bubble工具栏和子工具栏
|
|
69
|
+
*/
|
|
70
|
+
updatePositionWhenScroll() {
|
|
71
|
+
if (this.bubbleDom.style.display === Bubble.displayType) {
|
|
72
|
+
this.bubbleDom.style.marginTop = `${parseFloat(this.bubbleDom.dataset.scrollTop) - this.getScrollTop()}px`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 根据高度计算bubble工具栏出现的位置的高度
|
|
78
|
+
* 根据宽度计算bubble工具栏出现的位置的left值,以及bubble工具栏三角箭头的left值
|
|
79
|
+
* @param {number} top 高度
|
|
80
|
+
* @param {number} width 选中文本内容的宽度
|
|
81
|
+
*/
|
|
82
|
+
showBubble(top, width) {
|
|
83
|
+
if (!this.visible) {
|
|
84
|
+
this.visible = true;
|
|
85
|
+
this.bubbleDom.style.marginTop = '0';
|
|
86
|
+
this.bubbleDom.dataset.scrollTop = String(this.getScrollTop());
|
|
87
|
+
}
|
|
88
|
+
const positionLimit = this.editorDom.querySelector('.CodeMirror-lines').firstChild.getBoundingClientRect();
|
|
89
|
+
const editorPosition = this.editorDom.getBoundingClientRect();
|
|
90
|
+
const minLeft = positionLimit.left - editorPosition.left;
|
|
91
|
+
const maxLeft = positionLimit.width + minLeft;
|
|
92
|
+
const minTop = this.bubbleDom.offsetHeight * 2;
|
|
93
|
+
let $top = top;
|
|
94
|
+
if ($top < minTop) {
|
|
95
|
+
// 如果高度小于编辑器的顶部,则让bubble工具栏出现在选中文本的下放
|
|
96
|
+
$top += this.bubbleDom.offsetHeight - this.bubbleTop.getBoundingClientRect().height;
|
|
97
|
+
this.bubbleTop.style.display = 'block';
|
|
98
|
+
this.bubbleBottom.style.display = 'none';
|
|
99
|
+
} else {
|
|
100
|
+
// 反之出现在选中文本内容的上方
|
|
101
|
+
$top -= this.bubbleDom.offsetHeight + 2 * this.bubbleBottom.getBoundingClientRect().height;
|
|
102
|
+
this.bubbleTop.style.display = 'none';
|
|
103
|
+
this.bubbleBottom.style.display = 'block';
|
|
104
|
+
}
|
|
105
|
+
this.bubbleDom.style.top = `${$top}px`;
|
|
106
|
+
let left = width - this.bubbleDom.offsetWidth / 2;
|
|
107
|
+
if (left < minLeft) {
|
|
108
|
+
// 如果位置超过了编辑器的最左边,则控制bubble工具栏不超出编辑器最左边
|
|
109
|
+
// 同时bubble工具栏上的箭头尽量指向选中文本内容的中间位置
|
|
110
|
+
left = minLeft;
|
|
111
|
+
this.$setBubbleCursorPosition(`${width - minLeft}px`);
|
|
112
|
+
} else if (left + this.bubbleDom.offsetWidth > maxLeft) {
|
|
113
|
+
// 如果位置超过了编辑器的最右边,则控制bubble工具栏不超出编辑器最右边
|
|
114
|
+
// 同时bubble工具栏上的箭头尽量指向选中文本内容的中间位置
|
|
115
|
+
left = maxLeft - this.bubbleDom.offsetWidth;
|
|
116
|
+
this.$setBubbleCursorPosition(`${width - left}px`);
|
|
117
|
+
} else {
|
|
118
|
+
// 让bubble工具栏的箭头处于工具栏的中间位置
|
|
119
|
+
this.$setBubbleCursorPosition('50%');
|
|
120
|
+
}
|
|
121
|
+
// 安全边距 20px
|
|
122
|
+
this.bubbleDom.style.left = `${Math.max(20, left)}px`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
hideBubble() {
|
|
126
|
+
this.visible = false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 控制bubble工具栏的箭头的位置
|
|
131
|
+
* @param {string} left 左偏移量
|
|
132
|
+
*/
|
|
133
|
+
$setBubbleCursorPosition(left = '50%') {
|
|
134
|
+
if (left === '50%') {
|
|
135
|
+
this.bubbleTop.style.left = '50%';
|
|
136
|
+
this.bubbleBottom.style.left = '50%';
|
|
137
|
+
} else {
|
|
138
|
+
const $left = parseFloat(left) < 10 ? '10px' : left;
|
|
139
|
+
this.bubbleTop.style.left = $left;
|
|
140
|
+
this.bubbleBottom.style.left = $left;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
initBubbleDom() {
|
|
145
|
+
const top = document.createElement('div');
|
|
146
|
+
top.className = 'cherry-bubble-top';
|
|
147
|
+
const bottom = document.createElement('div');
|
|
148
|
+
bottom.className = 'cherry-bubble-bottom';
|
|
149
|
+
this.bubbleTop = top;
|
|
150
|
+
this.bubbleBottom = bottom;
|
|
151
|
+
this.bubbleDom.appendChild(top);
|
|
152
|
+
this.bubbleDom.appendChild(bottom);
|
|
153
|
+
// 默认不可见
|
|
154
|
+
this.visible = false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
getBubbleDom() {
|
|
158
|
+
return this.bubbleDom;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
addSelectionChangeListener() {
|
|
162
|
+
this.options.editor.addListener('change', (codemirror) => {
|
|
163
|
+
// 当编辑区内容变更时自动隐藏bubble工具栏
|
|
164
|
+
this.hideBubble();
|
|
165
|
+
});
|
|
166
|
+
this.options.editor.addListener('refresh', (codemirror) => {
|
|
167
|
+
// 当编辑区内容刷新时自动隐藏bubble工具栏
|
|
168
|
+
this.hideBubble();
|
|
169
|
+
});
|
|
170
|
+
this.options.editor.addListener('scroll', (codemirror) => {
|
|
171
|
+
// 当编辑区滚动时,需要实时同步bubble工具栏的位置
|
|
172
|
+
this.updatePositionWhenScroll();
|
|
173
|
+
});
|
|
174
|
+
this.options.editor.addListener('beforeSelectionChange', (codemirror, info) => {
|
|
175
|
+
setTimeout(() => {
|
|
176
|
+
const selections = codemirror.getSelections();
|
|
177
|
+
const selectionStr = selections.join('');
|
|
178
|
+
if (selectionStr !== this.lastSelectionsStr && (selectionStr || this.lastSelectionsStr)) {
|
|
179
|
+
this.lastSelections = !this.lastSelections ? [] : this.lastSelections;
|
|
180
|
+
Event.emit('Bubble', 'selectionChange', { selections, lastSelections: this.lastSelections, info });
|
|
181
|
+
this.lastSelections = selections;
|
|
182
|
+
this.lastSelectionsStr = selectionStr;
|
|
183
|
+
}
|
|
184
|
+
}, 10);
|
|
185
|
+
// 当编辑区选中内容改变时,需要展示/隐藏bubble工具栏,并计算工具栏位置
|
|
186
|
+
if (info.origin !== '*mouse' && (info.origin !== null || typeof info.origin === 'undefined')) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
if (!info.ranges[0]) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
const anchor = info.ranges[0].anchor.line * 1000000 + info.ranges[0].anchor.ch;
|
|
193
|
+
const head = info.ranges[0].head.line * 1000000 + info.ranges[0].head.ch;
|
|
194
|
+
let direction = 'asc';
|
|
195
|
+
if (anchor > head) {
|
|
196
|
+
direction = 'desc';
|
|
197
|
+
}
|
|
198
|
+
setTimeout(() => {
|
|
199
|
+
const selections = codemirror.getSelections();
|
|
200
|
+
if (selections.join('').length <= 0) {
|
|
201
|
+
this.hideBubble();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const selectedObjs = codemirror.getWrapperElement().getElementsByClassName('CodeMirror-selected');
|
|
205
|
+
const editorPosition = this.editorDom.getBoundingClientRect();
|
|
206
|
+
let width = 0;
|
|
207
|
+
let top = 0;
|
|
208
|
+
if (typeof selectedObjs !== 'object' || selectedObjs.length <= 0) {
|
|
209
|
+
this.hideBubble();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
for (let key = 0; key < selectedObjs.length; key++) {
|
|
213
|
+
const one = selectedObjs[key];
|
|
214
|
+
const position = one.getBoundingClientRect();
|
|
215
|
+
const targetTop = position.top - editorPosition.top;
|
|
216
|
+
if (direction === 'asc') {
|
|
217
|
+
if (targetTop >= top) {
|
|
218
|
+
top = targetTop;
|
|
219
|
+
width = position.left - editorPosition.left + position.width / 2;
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
if (targetTop <= top || top <= 0) {
|
|
223
|
+
top = targetTop;
|
|
224
|
+
width = position.left - editorPosition.left + position.width / 2;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
this.showBubble(top, width);
|
|
229
|
+
}, 10);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
const createTableItem = (dataset, className) => {
|
|
17
|
+
const dom = document.createElement('td');
|
|
18
|
+
dom.className = className || 'table-item';
|
|
19
|
+
Object.keys(dataset).forEach((prop) => {
|
|
20
|
+
dom.dataset[prop] = dataset[prop];
|
|
21
|
+
});
|
|
22
|
+
return dom;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 插入表格的辅助面板
|
|
27
|
+
*/
|
|
28
|
+
export default class BubbleTableMenu {
|
|
29
|
+
constructor({ row, col }, className) {
|
|
30
|
+
this.init(row, col, className);
|
|
31
|
+
this.initEventListeners();
|
|
32
|
+
this.afterClick = (...args) => {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
init(row, col, className) {
|
|
36
|
+
const container = document.createElement('table');
|
|
37
|
+
const cellArr = [];
|
|
38
|
+
const classNames = ['cherry-insert-table-menu', 'cherry-dropdown'];
|
|
39
|
+
container.className = classNames.join(' ');
|
|
40
|
+
for (let r = 1; r <= row; r++) {
|
|
41
|
+
const rowContainer = document.createElement('tr');
|
|
42
|
+
rowContainer.className = 'cherry-insert-table-menu-row';
|
|
43
|
+
cellArr[r - 1] = [];
|
|
44
|
+
for (let c = 1; c <= col; c++) {
|
|
45
|
+
const cell = createTableItem({ row: r, col: c }, 'cherry-insert-table-menu-item');
|
|
46
|
+
rowContainer.appendChild(cell);
|
|
47
|
+
cellArr[r - 1][c - 1] = cell;
|
|
48
|
+
}
|
|
49
|
+
container.appendChild(rowContainer);
|
|
50
|
+
}
|
|
51
|
+
container.style.display = 'none';
|
|
52
|
+
container.addEventListener('EditorHideToolbarSubMenu', () => {
|
|
53
|
+
this.hide();
|
|
54
|
+
});
|
|
55
|
+
this.dom = container;
|
|
56
|
+
this.cell = cellArr;
|
|
57
|
+
this.maxRow = row;
|
|
58
|
+
this.maxCol = col;
|
|
59
|
+
this.activeRow = 0;
|
|
60
|
+
this.activeCol = 0;
|
|
61
|
+
return this.dom;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
initEventListeners() {
|
|
65
|
+
this.dom.addEventListener('mousemove', this.handleMouseMove.bind(this), false);
|
|
66
|
+
// 不能用click
|
|
67
|
+
this.dom.addEventListener('mouseup', this.handleMouseUp.bind(this));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setActiveCell(row, col) {
|
|
71
|
+
if (this.activeRow === row && this.activeCol === col) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const minRow = Math.min(this.activeRow, row);
|
|
75
|
+
const maxRow = Math.max(this.activeRow, row);
|
|
76
|
+
if (minRow !== maxRow) {
|
|
77
|
+
// 先清空或按照历史列数增减active类
|
|
78
|
+
for (let r = maxRow; r > minRow; r--) {
|
|
79
|
+
for (let c = 1; c <= this.activeCol; c++) {
|
|
80
|
+
this.cell[r - 1][c - 1].classList.toggle('active');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const minCol = Math.min(this.activeCol, col);
|
|
85
|
+
const maxCol = Math.max(this.activeCol, col);
|
|
86
|
+
if (minCol !== maxCol) {
|
|
87
|
+
for (let c = maxCol; c > minCol; c--) {
|
|
88
|
+
for (let r = 1; r <= row; r++) {
|
|
89
|
+
this.cell[r - 1][c - 1].classList.toggle('active');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this.activeRow = row;
|
|
94
|
+
this.activeCol = col;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
handleMouseMove(event) {
|
|
98
|
+
let { target } = event;
|
|
99
|
+
if (target === this.dom) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!target.classList.contains('cherry-insert-table-menu-item')) {
|
|
103
|
+
target = target.querySelector('.cherry-insert-table-menu-item');
|
|
104
|
+
}
|
|
105
|
+
if (!target) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
this.setActiveCell(target.dataset.row, target.dataset.col);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
handleMouseUp(event) {
|
|
112
|
+
let { target } = event;
|
|
113
|
+
if (target === this.dom) {
|
|
114
|
+
this.afterClick(this.activeRow, this.activeCol);
|
|
115
|
+
this.hide();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (!target.classList.contains('cherry-insert-table-menu-item')) {
|
|
119
|
+
target = target.querySelector('.cherry-insert-table-menu-item');
|
|
120
|
+
}
|
|
121
|
+
if (!target) {
|
|
122
|
+
this.afterClick(this.activeRow, this.activeCol);
|
|
123
|
+
this.hide();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// 正中单元格时才使用target的dataset
|
|
127
|
+
this.afterClick(this.activeRow, this.activeCol);
|
|
128
|
+
this.hide();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
show(callback) {
|
|
132
|
+
this.dom.style.display = 'block';
|
|
133
|
+
this.afterClick = callback;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
hide() {
|
|
137
|
+
this.dom.style.display = 'none';
|
|
138
|
+
// reset active status
|
|
139
|
+
for (let r = 0; r < this.maxRow; r++) {
|
|
140
|
+
for (let c = 0; c < this.maxCol; c++) {
|
|
141
|
+
this.cell[r][c].classList.remove('active');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
this.activeRow = 0;
|
|
145
|
+
this.activeCol = 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 工具栏各个实例的注册中心
|
|
18
|
+
*/
|
|
19
|
+
import Bold from './hooks/Bold';
|
|
20
|
+
import Italic from './hooks/Italic';
|
|
21
|
+
import Split from './hooks/Split';
|
|
22
|
+
import Strikethrough from './hooks/Strikethrough';
|
|
23
|
+
import Sub from './hooks/Sub';
|
|
24
|
+
import Sup from './hooks/Sup';
|
|
25
|
+
import Color from './hooks/Color';
|
|
26
|
+
import Header from './hooks/Header';
|
|
27
|
+
import Insert from './hooks/Insert';
|
|
28
|
+
import List from './hooks/List';
|
|
29
|
+
import Ol from './hooks/Ol';
|
|
30
|
+
import Ul from './hooks/Ul';
|
|
31
|
+
import CheckList from './hooks/CheckList';
|
|
32
|
+
import Graph from './hooks/Graph';
|
|
33
|
+
import Size from './hooks/Size';
|
|
34
|
+
import H1 from './hooks/H1';
|
|
35
|
+
import H2 from './hooks/H2';
|
|
36
|
+
import H3 from './hooks/H3';
|
|
37
|
+
import Quote from './hooks/Quote';
|
|
38
|
+
import TogglePreview from './hooks/TogglePreview';
|
|
39
|
+
import FullScreen from './hooks/FullScreen';
|
|
40
|
+
import Undo from './hooks/Undo';
|
|
41
|
+
import Redo from './hooks/Redo';
|
|
42
|
+
import Code from './hooks/Code';
|
|
43
|
+
import Export from './hooks/Export';
|
|
44
|
+
import Underline from './hooks/Underline';
|
|
45
|
+
import SwitchModel from './hooks/SwitchModel';
|
|
46
|
+
import Image from './hooks/Image';
|
|
47
|
+
import Audio from './hooks/Audio';
|
|
48
|
+
import Video from './hooks/Video';
|
|
49
|
+
import Br from './hooks/Br';
|
|
50
|
+
import Hr from './hooks/Hr';
|
|
51
|
+
import Link from './hooks/Link';
|
|
52
|
+
import Table from './hooks/Table';
|
|
53
|
+
import Toc from './hooks/Toc';
|
|
54
|
+
import LineTable from './hooks/LineTable';
|
|
55
|
+
import BarTable from './hooks/BarTable';
|
|
56
|
+
|
|
57
|
+
import File from './hooks/File';
|
|
58
|
+
import Ruby from './hooks/Ruby';
|
|
59
|
+
// SideToc
|
|
60
|
+
import Copy from './hooks/Copy';
|
|
61
|
+
import Panel from './hooks/Panel';
|
|
62
|
+
import Detail from './hooks/Detail';
|
|
63
|
+
import Badge from './hooks/Badge';
|
|
64
|
+
import ECharts from './hooks/ECharts';
|
|
65
|
+
import Card from '@/toolbars/hooks/Card';
|
|
66
|
+
import Formula from '@/toolbars/hooks/Formula';
|
|
67
|
+
import Emoji from '@/toolbars/hooks/Emoji';
|
|
68
|
+
import Iframe from '@/toolbars/hooks/Iframe';
|
|
69
|
+
// 定义默认支持的工具栏
|
|
70
|
+
// 目前不支持按需动态加载
|
|
71
|
+
// 如果对CherryMarkdown构建后的文件大小有比较严格的要求,可以根据实际情况删减hook
|
|
72
|
+
const HookList = {
|
|
73
|
+
bold: Bold,
|
|
74
|
+
italic: Italic,
|
|
75
|
+
'|': Split,
|
|
76
|
+
strikethrough: Strikethrough,
|
|
77
|
+
sub: Sub,
|
|
78
|
+
sup: Sup,
|
|
79
|
+
header: Header,
|
|
80
|
+
insert: Insert,
|
|
81
|
+
list: List,
|
|
82
|
+
ol: Ol,
|
|
83
|
+
ul: Ul,
|
|
84
|
+
checklist: CheckList,
|
|
85
|
+
graph: Graph,
|
|
86
|
+
size: Size,
|
|
87
|
+
h1: H1,
|
|
88
|
+
h2: H2,
|
|
89
|
+
h3: H3,
|
|
90
|
+
color: Color,
|
|
91
|
+
quote: Quote,
|
|
92
|
+
togglePreview: TogglePreview,
|
|
93
|
+
code: Code,
|
|
94
|
+
export: Export,
|
|
95
|
+
fullScreen: FullScreen,
|
|
96
|
+
copy: Copy,
|
|
97
|
+
undo: Undo,
|
|
98
|
+
redo: Redo,
|
|
99
|
+
underline: Underline,
|
|
100
|
+
switchModel: SwitchModel,
|
|
101
|
+
image: Image,
|
|
102
|
+
audio: Audio,
|
|
103
|
+
video: Video,
|
|
104
|
+
br: Br,
|
|
105
|
+
hr: Hr,
|
|
106
|
+
link: Link,
|
|
107
|
+
table: Table,
|
|
108
|
+
toc: Toc,
|
|
109
|
+
lineTable: LineTable,
|
|
110
|
+
barTable: BarTable,
|
|
111
|
+
ruby: Ruby,
|
|
112
|
+
file: File,
|
|
113
|
+
panel: Panel,
|
|
114
|
+
detail: Detail,
|
|
115
|
+
badge: Badge,
|
|
116
|
+
echarts: ECharts,
|
|
117
|
+
card: Card,
|
|
118
|
+
formula: Formula,
|
|
119
|
+
emoji: Emoji,
|
|
120
|
+
iframe: Iframe,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export default class HookCenter {
|
|
124
|
+
constructor(toolbar) {
|
|
125
|
+
this.toolbar = toolbar;
|
|
126
|
+
/**
|
|
127
|
+
* @type {{[key: string]: import('@/toolbars/MenuBase').default}} 保存所有菜单实例
|
|
128
|
+
*/
|
|
129
|
+
this.hooks = {};
|
|
130
|
+
/**
|
|
131
|
+
* @type {string[]} 所有注册的菜单名称
|
|
132
|
+
*/
|
|
133
|
+
this.allMenusName = [];
|
|
134
|
+
/**
|
|
135
|
+
* @type {string[]} 一级菜单的名称
|
|
136
|
+
*/
|
|
137
|
+
this.level1MenusName = [];
|
|
138
|
+
/**
|
|
139
|
+
* @type {{ [parentName: string]: string[]}} 二级菜单的名称, e.g. {一级菜单名称: [二级菜单名称1, 二级菜单名称2]}
|
|
140
|
+
*/
|
|
141
|
+
this.level2MenusName = {};
|
|
142
|
+
this.init();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
$newMenu(name) {
|
|
146
|
+
if (this.hooks[name]) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const { $cherry, customMenu } = this.toolbar.options;
|
|
150
|
+
if (HookList[name]) {
|
|
151
|
+
this.allMenusName.push(name);
|
|
152
|
+
this.hooks[name] = new HookList[name]($cherry);
|
|
153
|
+
} else if (customMenu !== undefined && customMenu !== null && customMenu[name]) {
|
|
154
|
+
this.allMenusName.push(name);
|
|
155
|
+
// 如果是自定义菜单,传参兼容旧版
|
|
156
|
+
this.hooks[name] = new customMenu[name]($cherry);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 根据配置动态渲染、绑定工具栏
|
|
162
|
+
* @returns
|
|
163
|
+
*/
|
|
164
|
+
init() {
|
|
165
|
+
const { buttonConfig } = this.toolbar.options;
|
|
166
|
+
buttonConfig.forEach((item) => {
|
|
167
|
+
if (typeof item === 'string') {
|
|
168
|
+
this.level1MenusName.push(item);
|
|
169
|
+
this.$newMenu(item);
|
|
170
|
+
} else if (typeof item === 'object') {
|
|
171
|
+
const keys = Object.keys(item);
|
|
172
|
+
if (keys.length === 1) {
|
|
173
|
+
// 只接受形如{ name: [ subMenu ] }的参数
|
|
174
|
+
const [name] = keys;
|
|
175
|
+
this.level1MenusName.push(name);
|
|
176
|
+
this.$newMenu(name);
|
|
177
|
+
this.level2MenusName[name] = item[name];
|
|
178
|
+
item[name].forEach((subItem) => {
|
|
179
|
+
this.$newMenu(subItem);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|