Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Ya土豆儿~
Awesome-Markdown-Editor
提交
4665e8e3
Awesome-Markdown-Editor
项目概览
Ya土豆儿~
/
Awesome-Markdown-Editor
与 Fork 源项目一致
Fork自
gitcode_dev / Awesome-Markdown-Editor
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Awesome-Markdown-Editor
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
4665e8e3
编写于
11月 01, 2021
作者:
郭
郭维嘉
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat:添加目录
上级
e52f5f9d
变更
17
展开全部
隐藏空白更改
内联
并排
Showing
17 changed file
with
611 addition
and
125 deletion
+611
-125
dist/.DS_Store
dist/.DS_Store
+0
-0
dist/index.html
dist/index.html
+25
-2
dist/markdown-editor.js
dist/markdown-editor.js
+1
-1
src/App.vue
src/App.vue
+32
-3
src/assets/js/utils.js
src/assets/js/utils.js
+21
-2
src/assets/style/font/iconfont.ttf
src/assets/style/font/iconfont.ttf
+0
-0
src/assets/style/global.less
src/assets/style/global.less
+40
-0
src/assets/style/iconfont.less
src/assets/style/iconfont.less
+5
-1
src/components/content/components/doc-frame.vue
src/components/content/components/doc-frame.vue
+207
-0
src/components/content/components/help-doc.vue
src/components/content/components/help-doc.vue
+9
-93
src/components/content/components/toc-doc.vue
src/components/content/components/toc-doc.vue
+138
-0
src/components/content/md-preview.vue
src/components/content/md-preview.vue
+52
-10
src/components/content/md-textarea.vue
src/components/content/md-textarea.vue
+10
-4
src/components/content/mixins/render-mixins.js
src/components/content/mixins/render-mixins.js
+42
-2
src/components/header/components/tool-button.vue
src/components/header/components/tool-button.vue
+4
-1
src/components/header/md-header.vue
src/components/header/md-header.vue
+23
-4
src/main.js
src/main.js
+2
-2
未找到文件。
dist/.DS_Store
浏览文件 @
4665e8e3
无法预览此类型文件
dist/index.html
浏览文件 @
4665e8e3
...
@@ -28,7 +28,10 @@
...
@@ -28,7 +28,10 @@
<div
id=
"app"
></div>
<div
id=
"app"
></div>
<!-- <textarea class="text" name="" id="" cols="30" rows="10"></textarea> -->
<!-- <textarea class="text" name="" id="" cols="30" rows="10"></textarea> -->
<!-- <div contenteditable="true" class="text"></div> -->
<!-- <div contenteditable="true" class="text"></div> -->
<a
href=
"https://codechina.csdn.net/xiongjiamu/jupyter-101/-/blob/master/002-demo.ipynb"
class=
"jupyterEl"
></a>
<a
href=
"https://codechina.csdn.net/xiongjiamu/jupyter-101/-/blob/master/002-demo.ipynb"
class=
"jupyterEl"
></a>
<button
id=
"a"
>
111111
</button>
<button
id=
"a"
>
111111
</button>
<button
id=
"b"
>
2222222
</button>
<button
id=
"b"
>
2222222
</button>
<script
src=
"./markdown-editor.js"
></script>
<script
src=
"./markdown-editor.js"
></script>
...
@@ -261,7 +264,27 @@
...
@@ -261,7 +264,27 @@
return
ee
.
getVideoList
();
return
ee
.
getVideoList
();
}
}
document
.
querySelector
(
"
#a
"
).
onclick
=
async
function
()
{
document
.
querySelector
(
"
#a
"
).
onclick
=
async
function
()
{
console
.
log
(
await
test
());
ee
.
setValue
(
`
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
#### 四级标题2四级标题2四级标题2四级标题2四级标题2四级标题2四级标题2四级标题2
#### 四级标题3
#### 四级标题4
### 三级标题2
### 三级标题3
## 二级标题2
## 二级标题3
## 二级标题4
## 二级标题5
### 三级标题4
[toc]
`
);
// ee.disable();
// ee.disable();
// ee.getVideoList(list => {
// ee.getVideoList(list => {
...
...
dist/markdown-editor.js
浏览文件 @
4665e8e3
此差异已折叠。
点击以展开。
src/App.vue
浏览文件 @
4665e8e3
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
:registerTools=
"registerTools"
:registerTools=
"registerTools"
@
upload=
"handleUpload"
@
upload=
"handleUpload"
@
getFormatType=
"formatType = $event"
@
getFormatType=
"formatType = $event"
@
updateShow
Help
=
"showHelp = $event"
@
updateShow
Doc
=
"showHelp = $event"
@
renderLinks=
"$emit('renderLinks', $event)"
@
renderLinks=
"$emit('renderLinks', $event)"
/>
/>
<input
<input
...
@@ -41,6 +41,9 @@
...
@@ -41,6 +41,9 @@
:height=
"textareaHeight"
:height=
"textareaHeight"
:html.sync=
"html"
:html.sync=
"html"
:htmlMinHeight=
"htmlMinHeight"
:htmlMinHeight=
"htmlMinHeight"
:show-help=
"showHelp"
:dirTags=
"dirTags"
@
updateShowDoc=
"showHelp = $event"
v-if=
"showPreview"
v-if=
"showPreview"
/>
/>
...
@@ -69,8 +72,9 @@
...
@@ -69,8 +72,9 @@
@
submit=
"submit"
@
submit=
"submit"
@
enter=
"handleEnter"
@
enter=
"handleEnter"
@
getFilteredTags=
"filteredTags = $event"
@
getFilteredTags=
"filteredTags = $event"
@
updateShow
Help
=
"showHelp = $event"
@
updateShow
Doc
=
"showHelp = $event"
@
renderLinksHtml=
"renderLinksHtml"
@
renderLinksHtml=
"renderLinksHtml"
@
getDirTags=
"getDirTags"
@
queryUserList=
"queryUserList"
@
queryUserList=
"queryUserList"
@
callUserList=
"callUserList = $event"
@
callUserList=
"callUserList = $event"
v-else
v-else
...
@@ -304,6 +308,7 @@ export default {
...
@@ -304,6 +308,7 @@ export default {
uploadFlePercent
:
0
,
uploadFlePercent
:
0
,
uploadVideoPercent
:
0
,
uploadVideoPercent
:
0
,
textLength
:
""
,
textLength
:
""
,
dirTags
:
[],
userList
:
false
,
userList
:
false
,
callUserList
:
[],
callUserList
:
[],
linkList
:
[],
linkList
:
[],
...
@@ -475,12 +480,36 @@ export default {
...
@@ -475,12 +480,36 @@ export default {
}
}
});
});
},
},
getDirTags
({
vDom
,
dirTags
})
{
this
.
dirTags
=
dirTags
;
const
tocEls
=
Array
.
from
(
vDom
.
querySelectorAll
(
"
.tocEl
"
));
if
(
!
tocEls
.
length
)
return
;
tocEls
.
forEach
(
el
=>
{
el
.
innerHTML
=
`<ul class="md_toc_list">
${
dirTags
.
map
(
tag
=>
{
return
`<li class="md_toc_item" data-type="
${
tag
.
tag
}
" data-id="
${
tag
.
id
}
">
${
tag
.
text
}
</li>`
;
})
.
join
(
""
)}
</ul>`
;
});
this
.
html
=
vDom
.
innerHTML
;
// console.log(document.querySelectorAll(".md_toc_list"));
document
.
querySelector
(
"
body
"
).
addEventListener
(
"
click
"
,
function
(
e
)
{
if
(
!
e
.
target
?.
className
.
includes
(
"
md_toc_item
"
))
return
;
console
.
log
(
e
.
target
.
dataset
.
id
);
const
targetEl
=
document
.
getElementById
(
e
.
target
?.
dataset
?.
id
);
if
(
!
targetEl
)
return
;
targetEl
.
scrollIntoView
({
behavior
:
"
smooth
"
});
});
},
renderLinksHtml
({
vDom
,
links
})
{
renderLinksHtml
({
vDom
,
links
})
{
// 缓存里没有的链接,就发送请求获取信息
// 缓存里没有的链接,就发送请求获取信息
const
emitList
=
links
.
filter
(
const
emitList
=
links
.
filter
(
item
=>
!
this
.
linkList
.
find
(
link
=>
link
&&
link
.
url
===
item
.
url
)
item
=>
!
this
.
linkList
.
find
(
link
=>
link
&&
link
.
url
===
item
.
url
)
);
);
console
.
log
(
"
emit
"
,
emitList
);
this
.
$emit
(
"
renderLinks
"
,
{
this
.
$emit
(
"
renderLinks
"
,
{
links
:
emitList
,
links
:
emitList
,
callback
:
list
=>
{
callback
:
list
=>
{
...
...
src/assets/js/utils.js
浏览文件 @
4665e8e3
...
@@ -183,6 +183,13 @@ export function isNotFalse(val) {
...
@@ -183,6 +183,13 @@ export function isNotFalse(val) {
return
val
!==
false
;
return
val
!==
false
;
}
}
export
function
pick
(
list
,
...
arg
)
{
if
(
!
list
.
length
||
!
arg
?.
length
)
return
;
return
list
.
filter
(
item
=>
{
return
arg
.
find
(
key
=>
key
===
item
.
name
);
});
}
export
function
checktUrl
(
val
,
rule
)
{
export
function
checktUrl
(
val
,
rule
)
{
if
(
!
val
||
!
rule
)
return
;
if
(
!
val
||
!
rule
)
return
;
const
hideEl
=
document
.
createElement
(
"
div
"
);
const
hideEl
=
document
.
createElement
(
"
div
"
);
...
@@ -360,7 +367,7 @@ export function formatElements(html) {
...
@@ -360,7 +367,7 @@ export function formatElements(html) {
}
}
});
});
Array
.
from
(
virtualDom
.
querySelectorAll
(
"
img
"
)).
forEach
(
item
=>
{
Array
.
from
(
virtualDom
.
querySelectorAll
(
"
img
"
)).
forEach
(
item
=>
{
item
.
className
=
'
md_img
'
item
.
className
=
"
md_img
"
;
});
});
const
list
=
Array
.
from
(
new
Set
(
userList
));
// 去重
const
list
=
Array
.
from
(
new
Set
(
userList
));
// 去重
return
{
callUserList
:
list
,
userHtml
:
virtualDom
.
innerHTML
};
return
{
callUserList
:
list
,
userHtml
:
virtualDom
.
innerHTML
};
...
@@ -368,6 +375,7 @@ export function formatElements(html) {
...
@@ -368,6 +375,7 @@ export function formatElements(html) {
export
function
getLinkTags
(
id
,
html
)
{
export
function
getLinkTags
(
id
,
html
)
{
const
virtualDom
=
document
.
createElement
(
"
div
"
);
const
virtualDom
=
document
.
createElement
(
"
div
"
);
virtualDom
.
innerHTML
=
html
;
virtualDom
.
innerHTML
=
html
;
// 获取所有a标签
const
links
=
Array
.
from
(
const
links
=
Array
.
from
(
virtualDom
.
querySelectorAll
(
"
a:not([download])
"
)
virtualDom
.
querySelectorAll
(
"
a:not([download])
"
)
).
map
((
item
,
index
)
=>
{
).
map
((
item
,
index
)
=>
{
...
@@ -378,7 +386,18 @@ export function getLinkTags(id, html) {
...
@@ -378,7 +386,18 @@ export function getLinkTags(id, html) {
url
:
item
.
href
url
:
item
.
href
};
};
});
});
return
{
vDom
:
virtualDom
,
links
};
// 获取所有标题
const
dirTags
=
Array
.
from
(
virtualDom
.
querySelectorAll
(
"
h1:not(.toc_title),h2,h3,h4,h5,h6
"
)
).
map
((
item
,
index
)
=>
{
const
dirItem
=
{
tag
:
item
.
tagName
.
toLowerCase
(),
id
:
item
.
id
,
text
:
item
.
innerText
};
return
dirItem
;
});
return
{
vDom
:
virtualDom
,
links
,
dirTags
};
}
}
export
function
getLinkTitle
(
linkEl
,
item
)
{
export
function
getLinkTitle
(
linkEl
,
item
)
{
...
...
src/assets/style/font/iconfont.ttf
浏览文件 @
4665e8e3
无法预览此类型文件
src/assets/style/global.less
浏览文件 @
4665e8e3
...
@@ -86,6 +86,46 @@ textarea {
...
@@ -86,6 +86,46 @@ textarea {
}
}
}
}
.md_toc_list {
li.md_toc_item {
list-style-type: none;
cursor: pointer;
color: var(--md-editor-border-color-active);
position: relative;
margin: 12px 8px;
&::before {
content: "\·";
font-size: 20px;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
&[data-type="h1"] {
padding-left: 20px;
}
&[data-type="h2"] {
padding-left: 30px;
}
&[data-type="h3"] {
padding-left: 40px;
}
&[data-type="h4"] {
padding-left: 50px;
}
&[data-type="h5"] {
padding-left: 60px;
}
&[data-type="h6"] {
padding-left: 70px;
}
}
}
.relative {
position: relative;
}
a.md_call_user {
a.md_call_user {
color: var(--md-editor-text-color-active) !important;
color: var(--md-editor-text-color-active) !important;
&[href] {
&[href] {
...
...
src/assets/style/iconfont.less
浏览文件 @
4665e8e3
...
@@ -15,6 +15,10 @@
...
@@ -15,6 +15,10 @@
content: "\e63a";
content: "\e63a";
}
}
.icon-dir:before {
content: "\e67f";
}
.icon-renwu:before {
.icon-renwu:before {
content: "\e63f";
content: "\e63f";
}
}
...
@@ -84,7 +88,7 @@
...
@@ -84,7 +88,7 @@
}
}
.icon-aite:before {
.icon-aite:before {
content: "\e6
34
";
content: "\e6
0b
";
}
}
.icon-fengexian:before {
.icon-fengexian:before {
content: "\e60a";
content: "\e60a";
...
...
src/components/content/components/doc-frame.vue
0 → 100644
浏览文件 @
4665e8e3
<
template
>
<div
class=
"doc_frame"
>
<div
class=
"doc_container"
>
<h2>
<slot
name=
"title"
/>
<span
@
click=
"$emit('updateShowDoc', false)"
:class=
"['icon iconfont', `icon-guanbi`]"
></span>
</h2>
<slot
name=
"content"
/>
<!--
<ul
class=
"list"
>
<li
v-for=
"(item, index) in list"
:key=
"index"
>
<span
:class=
"['icon iconfont', `icon-$
{item.icon}`]">
</span>
<span>
{{
item
.
title
}}
</span>
<span
class=
"doc"
>
{{
item
.
doc
}}
</span>
</li>
</ul>
-->
</div>
<div
class=
"before"
></div>
<div
class=
"after"
></div>
</div>
</
template
>
<
script
>
export
default
{
props
:
{
showHelp
:
{
type
:
[
Boolean
,
String
],
default
:
false
}
},
data
()
{
return
{
list
:
[
{
title
:
"
一级标题
"
,
doc
:
"
# 标题
"
,
icon
:
"
yijibiaoti
"
},
{
title
:
"
二级标题
"
,
doc
:
"
## 标题
"
,
icon
:
"
erjibiaoti
"
},
{
title
:
"
三级标题
"
,
doc
:
"
### 标题
"
,
icon
:
"
sanjibiaoti
"
},
{
title
:
"
粗体
"
,
doc
:
"
**内容**
"
,
icon
:
"
bold
"
},
{
title
:
"
斜体
"
,
doc
:
"
_内容_
"
,
icon
:
"
italic
"
},
{
title
:
"
引用
"
,
doc
:
"
> 引用内容
"
,
icon
:
"
yinyong
"
},
{
title
:
"
链接
"
,
doc
:
"
[链接标题](url)
"
,
icon
:
"
lianjie
"
},
{
title
:
"
图片
"
,
doc
:
"
![alt](url)
"
,
icon
:
"
img
"
},
{
title
:
"
图片大小
"
,
doc
:
'
![alt](url "=300x200")
'
,
icon
:
"
img
"
},
{
title
:
"
图片位置
"
,
doc
:
'
![alt](url "#left")
'
,
icon
:
"
img
"
},
{
title
:
"
图片名称
"
,
doc
:
'
![alt](url "%title")
'
,
icon
:
"
img
"
},
{
title
:
"
代码
"
,
doc
:
"
`代码`
"
,
icon
:
"
daimakuai
"
},
{
title
:
"
代码块
"
,
doc
:
"
```编程语言↵代码```
"
,
icon
:
"
code
"
},
{
title
:
"
无序列表
"
,
doc
:
"
- 内容
"
,
icon
:
"
unorderedList
"
},
{
title
:
"
有序列表
"
,
doc
:
"
1. 内容
"
,
icon
:
"
youxuliebiao
"
},
{
title
:
"
任务列表
"
,
doc
:
"
- [ ] 待办事项
"
,
icon
:
"
renwu
"
},
{
title
:
"
分割线
"
,
doc
:
"
---
"
,
icon
:
"
fengexian
"
},
{
title
:
"
删除线
"
,
doc
:
"
~~内容~~
"
,
icon
:
"
shanchuxian
"
}
]
};
}
};
</
script
>
<
style
lang=
"less"
scoped
>
.doc_frame {
position: absolute;
// background: #fff;
background: var(--md-editor-content-bg-color);
height: calc(100% + 10px);
width: 260px;
top: 0;
right: -16px;
box-sizing: border-box;
border-left: 1px solid var(--md-editor-border-color);
padding: 14px;
padding-right: 0;
// border-radius: 4px;
z-index: 9;
.before {
position: absolute;
top: 4px;
left: 0;
width: 100%;
height: 24px;
pointer-events: none;
background: linear-gradient(
to bottom,
var(--md-editor-content-bg-color),
rgba(255, 255, 255, 0)
);
}
.after {
pointer-events: none;
position: absolute;
bottom: 12px;
left: 0;
width: 100%;
height: 24px;
background: linear-gradient(
to top,
var(--md-editor-content-bg-color),
rgba(255, 255, 255, 0)
);
}
.doc_container {
overflow-y: auto;
padding-right: 14px;
height: 100%;
scrollbar-color: transparent transparent;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
h2 {
font-size: 16px;
color: var(--md-editor-text-color-active);
.icon {
float: right;
margin-top: 3px;
cursor: pointer;
font-weight: 400;
}
}
/deep/ul {
margin-top: 14px;
li {
font-size: 14px;
color: var(--md-editor-helpdoc-color);
margin-bottom: 10px;
.icon {
display: inline-block;
vertical-align: middle;
}
.doc {
float: right;
}
}
}
}
}
</
style
>
src/components/content/components/help-doc.vue
浏览文件 @
4665e8e3
<
template
>
<
template
>
<div
class=
"help_doc"
>
<docFrame
@
updateShowDoc=
"$emit('updateShowDoc', $event)"
>
<div
class=
"doc_container"
>
<template
#title
>
Markdown 语法
</
template
>
<h2>
<
template
#content
>
Markdown 语法
<ul>
<span
@
click=
"$emit('updateShowHelp', false)"
:class=
"['icon iconfont', `icon-guanbi`]"
></span>
</h2>
<ul
class=
"list"
>
<li
v-for=
"(item, index) in list"
:key=
"index"
>
<li
v-for=
"(item, index) in list"
:key=
"index"
>
<span
:class=
"['icon iconfont', `icon-$
{item.icon}`]">
</span>
<span
:class=
"['icon iconfont', `icon-$
{item.icon}`]">
</span>
<span>
{{
item
.
title
}}
</span>
<span>
{{
item
.
title
}}
</span>
<span
class=
"doc"
>
{{
item
.
doc
}}
</span>
<span
class=
"doc"
>
{{
item
.
doc
}}
</span>
</li>
</li>
</ul>
</ul>
</div>
</
template
>
<div
class=
"before"
></div>
</docFrame>
<div
class=
"after"
></div>
</div>
</template>
</template>
<
script
>
<
script
>
import
docFrame
from
"
./doc-frame.vue
"
;
export
default
{
export
default
{
components
:
{
docFrame
},
props
:
{
props
:
{
showHelp
:
{
showHelp
:
{
type
:
Boolean
,
type
:
[
Boolean
,
String
]
,
default
:
false
default
:
false
}
}
},
},
...
@@ -126,81 +120,3 @@ export default {
...
@@ -126,81 +120,3 @@ export default {
}
}
};
};
</
script
>
</
script
>
<
style
lang=
"less"
scoped
>
.help_doc {
position: absolute;
// background: #fff;
background: var(--md-editor-content-bg-color);
height: calc(100% + 10px);
width: 260px;
top: 0;
right: -16px;
box-sizing: border-box;
border-left: 1px solid var(--md-editor-border-color);
padding: 14px;
padding-right: 0;
// border-radius: 4px;
z-index: 9;
.before {
position: absolute;
top: 4px;
left: 0;
width: 100%;
height: 24px;
pointer-events: none;
background: linear-gradient(
to bottom,
var(--md-editor-content-bg-color),
rgba(255, 255, 255, 0)
);
}
.after {
pointer-events: none;
position: absolute;
bottom: 12px;
left: 0;
width: 100%;
height: 24px;
background: linear-gradient(
to top,
var(--md-editor-content-bg-color),
rgba(255, 255, 255, 0)
);
}
.doc_container {
overflow-y: auto;
padding-right: 14px;
height: 100%;
scrollbar-color: transparent transparent;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
h2 {
font-size: 16px;
color: var(--md-editor-text-color-active);
.icon {
float: right;
margin-top: 3px;
cursor: pointer;
font-weight: 400;
}
}
ul.list {
margin-top: 14px;
li {
font-size: 14px;
color: var(--md-editor-helpdoc-color);
margin-bottom: 10px;
.icon {
display: inline-block;
vertical-align: middle;
}
.doc {
float: right;
}
}
}
}
}
</
style
>
src/components/content/components/toc-doc.vue
0 → 100644
浏览文件 @
4665e8e3
<
template
>
<docFrame
@
updateShowDoc=
"$emit('updateShowDoc', $event)"
>
<template
#title
>
目录
</
template
>
<
template
#content
>
<ul>
<li
:data-type=
"item.tag"
@
click.prevent.stop=
"scrollToTitle(item)"
:class=
"
{ active: dirItemActive(item) }"
v-for="item in dirTags"
:key="item.id"
>
<a
href=
"javascript:viod(0)"
>
{{
item
.
text
}}
</a>
</li>
</ul>
</
template
>
</docFrame>
</template>
<
script
>
import
docFrame
from
"
./doc-frame.vue
"
;
export
default
{
components
:
{
docFrame
},
props
:
{
showHelp
:
{
type
:
[
Boolean
,
String
],
default
:
false
},
dirTags
:
{
type
:
Array
,
default
:
()
=>
[]
},
scrollBarTop
:
{
type
:
Number
,
default
:
0
}
},
data
()
{
return
{
list
:
[
{
title
:
"
一级标题
"
,
doc
:
"
# 标题
"
,
icon
:
"
yijibiaoti
"
},
{
title
:
"
二级标题
"
,
doc
:
"
## 标题
"
,
icon
:
"
erjibiaoti
"
},
{
title
:
"
三级标题
"
,
doc
:
"
### 标题
"
,
icon
:
"
sanjibiaoti
"
}
]
};
},
computed
:
{
topList
()
{
return
this
.
dirTags
.
map
(
item
=>
Math
.
abs
(
item
?.
top
));
}
},
created
()
{
this
.
$emit
(
"
update:scrollBarTop
"
,
document
.
querySelector
(
"
.md_preview_scroll_container
"
).
scrollTop
);
},
methods
:
{
scrollToTitle
(
item
)
{
const
targetEl
=
document
.
getElementById
(
item
.
id
);
if
(
!
targetEl
)
return
;
const
targetOffsetTop
=
targetEl
.
offsetTop
;
document
.
querySelector
(
"
.md_preview .md_preview_scroll_container
"
).
scrollTop
=
targetOffsetTop
;
},
dirItemActive
(
item
)
{
const
itemScrollTop
=
document
.
getElementById
(
item
.
id
)?.
offsetTop
;
const
top
=
this
.
scrollBarTop
-
itemScrollTop
;
this
.
$set
(
item
,
"
top
"
,
top
);
return
Math
.
abs
(
top
)
===
Math
.
min
(...
this
.
topList
);
}
}
};
</
script
>
<
style
lang=
"less"
scoped
>
/deep/li {
position: relative;
cursor: pointer;
a {
text-decoration: none;
color: inherit;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
&:hover,
&.active {
a {
color: var(--md-editor-border-color-active);
}
&::before {
color: var(--md-editor-border-color-active);
}
}
&::before {
content: "\·";
position: absolute;
left: 0;
top: 50%;
font-size: 20px;
transform: translateY(-50%);
}
&[data-type="h1"] {
padding-left: 20px;
}
&[data-type="h2"] {
padding-left: 30px;
}
&[data-type="h3"] {
padding-left: 40px;
}
&[data-type="h4"] {
padding-left: 50px;
}
&[data-type="h5"] {
padding-left: 60px;
}
&[data-type="h6"] {
padding-left: 70px;
}
}
</
style
>
src/components/content/md-preview.vue
浏览文件 @
4665e8e3
<
template
>
<
template
>
<div
:class=
"['md_preview',
{ fullScreen }]">
<div
class=
"relative"
>
<div
<div
:class=
"['md_preview',
{ fullScreen }]">
v-html=
"html"
<div
:style=
"
{
class=
"md_preview_scroll_container"
height: height > 0 ? height + 'px' : 'auto',
v-html=
"html"
'min-height': htmlMinHeight + 'px'
@
scroll=
"getScrollBarTop"
}"
:style=
"
{
>
</div>
height: height > 0 ? height + 'px' : 'auto',
'min-height': htmlMinHeight + 'px'
}"
>
</div>
</div>
<transition
name=
"slide-fade"
>
<helpDoc
v-if=
"showHelp === 'help'"
@
updateShowDoc=
"$emit('updateShowDoc', $event)"
:showHelp.sync=
"showHelp"
/>
<dirDoc
v-if=
"showHelp === 'dir'"
@
updateShowDoc=
"$emit('updateShowDoc', $event)"
:showHelp.sync=
"showHelp"
:dirTags=
"dirTags"
:scrollBarTop.sync=
"scrollBarTop"
/>
</transition>
</div>
</div>
</
template
>
</
template
>
<
script
>
<
script
>
import
helpDoc
from
"
./components/help-doc.vue
"
;
import
dirDoc
from
"
./components/toc-doc.vue
"
;
export
default
{
export
default
{
components
:
{
helpDoc
,
dirDoc
},
data
()
{
data
()
{
return
{};
return
{
scrollBarTop
:
0
};
},
},
props
:
{
props
:
{
id
:
{
id
:
{
...
@@ -34,6 +57,14 @@ export default {
...
@@ -34,6 +57,14 @@ export default {
type
:
[
String
,
Promise
],
type
:
[
String
,
Promise
],
default
:
""
default
:
""
},
},
showHelp
:
{
type
:
[
Boolean
,
String
],
default
:
false
},
dirTags
:
{
type
:
Array
,
default
:
()
=>
[]
},
fullScreen
:
{
fullScreen
:
{
type
:
Boolean
,
type
:
Boolean
,
default
:
false
default
:
false
...
@@ -65,6 +96,12 @@ export default {
...
@@ -65,6 +96,12 @@ export default {
item
.
setAttribute
(
"
preload
"
,
"
auto
"
);
item
.
setAttribute
(
"
preload
"
,
"
auto
"
);
});
});
},
0
);
},
0
);
},
getScrollBarTop
()
{
if
(
this
.
showHelp
===
"
dir
"
)
this
.
scrollBarTop
=
document
.
querySelector
(
"
.md_preview_scroll_container
"
).
scrollTop
;
}
}
}
}
};
};
...
@@ -77,12 +114,17 @@ export default {
...
@@ -77,12 +114,17 @@ export default {
color: var(--md-editor-text-color);
color: var(--md-editor-text-color);
word-break: break-all;
word-break: break-all;
overflow-y: auto;
overflow-y: auto;
& > div
{
.md_preview_scroll_container
{
overflow-y: auto;
overflow-y: auto;
position: relative;
scroll-behavior: smooth;
}
}
&.fullScreen {
&.fullScreen {
max-height: calc(100% - 42px);
max-height: calc(100% - 42px);
overflow-y: auto;
overflow-y: auto;
}
}
.help_doc {
height: 100%;
}
}
}
</
style
>
</
style
>
src/components/content/md-textarea.vue
浏览文件 @
4665e8e3
...
@@ -39,8 +39,13 @@
...
@@ -39,8 +39,13 @@
</textarea>
</textarea>
<transition
name=
"slide-fade"
>
<transition
name=
"slide-fade"
>
<helpDoc
<helpDoc
v-if=
"showHelp"
v-if=
"showHelp === 'help'"
@
updateShowHelp=
"$emit('updateShowHelp', $event)"
@
updateShowDoc=
"$emit('updateShowDoc', $event)"
:showHelp.sync=
"showHelp"
/>
<dirDoc
v-if=
"showHelp === 'dir'"
@
updateShowDoc=
"$emit('updateShowDoc', $event)"
:showHelp.sync=
"showHelp"
:showHelp.sync=
"showHelp"
/>
/>
</transition>
</transition>
...
@@ -73,11 +78,12 @@ import {
...
@@ -73,11 +78,12 @@ import {
import
selectUser
from
"
./components/user-select.vue
"
;
import
selectUser
from
"
./components/user-select.vue
"
;
import
selectLinkType
from
"
./components/link-type-select.vue
"
;
import
selectLinkType
from
"
./components/link-type-select.vue
"
;
import
helpDoc
from
"
./components/help-doc.vue
"
;
import
helpDoc
from
"
./components/help-doc.vue
"
;
import
dirDoc
from
"
./components/toc-doc.vue
"
;
import
renderMix
from
"
./mixins/render-mixins
"
;
import
renderMix
from
"
./mixins/render-mixins
"
;
import
selectUserMix
from
"
./mixins/select-user-mixins
"
;
import
selectUserMix
from
"
./mixins/select-user-mixins
"
;
import
selectLinkTypeMix
from
"
./mixins/select-link-type-mixins
"
;
import
selectLinkTypeMix
from
"
./mixins/select-link-type-mixins
"
;
export
default
{
export
default
{
components
:
{
helpDoc
,
selectUser
,
selectLinkType
},
components
:
{
helpDoc
,
dirDoc
,
selectUser
,
selectLinkType
},
mixins
:
[
renderMix
,
selectUserMix
,
selectLinkTypeMix
],
mixins
:
[
renderMix
,
selectUserMix
,
selectLinkTypeMix
],
props
:
{
props
:
{
id
:
{
id
:
{
...
@@ -139,7 +145,7 @@ export default {
...
@@ -139,7 +145,7 @@ export default {
default
:
""
default
:
""
},
},
showHelp
:
{
showHelp
:
{
type
:
Boolean
,
type
:
[
Boolean
,
String
]
,
default
:
false
default
:
false
},
},
userList
:
{
userList
:
{
...
...
src/components/content/mixins/render-mixins.js
浏览文件 @
4665e8e3
...
@@ -37,13 +37,15 @@ export default {
...
@@ -37,13 +37,15 @@ export default {
});
// 去除标签
});
// 去除标签
const
filteredTags
=
getFilteredTags
(
html
,
cleanHtml
);
// 计算是否有标签被过滤
const
filteredTags
=
getFilteredTags
(
html
,
cleanHtml
);
// 计算是否有标签被过滤
// 链接转换为卡片
// 链接转换为卡片
const
{
vDom
,
links
}
=
getLinkTags
(
this
.
id
,
cleanHtml
);
// 获取标题列表
const
{
vDom
,
links
,
dirTags
}
=
getLinkTags
(
this
.
id
,
cleanHtml
);
const
{
callUserList
,
userHtml
}
=
formatElements
(
cleanHtml
);
const
{
callUserList
,
userHtml
}
=
formatElements
(
cleanHtml
);
// const videoHtml = await renderVideo(this.id, userHtml);
// const videoHtml = await renderVideo(this.id, userHtml);
this
.
$emit
(
"
callUserList
"
,
callUserList
);
this
.
$emit
(
"
callUserList
"
,
callUserList
);
this
.
$emit
(
"
getFilteredTags
"
,
filteredTags
);
this
.
$emit
(
"
getFilteredTags
"
,
filteredTags
);
this
.
$emit
(
"
update:html
"
,
userHtml
);
this
.
$emit
(
"
update:html
"
,
userHtml
);
if
(
links
.
length
)
this
.
$emit
(
"
renderLinksHtml
"
,
{
vDom
,
links
});
if
(
links
.
length
)
this
.
$emit
(
"
renderLinksHtml
"
,
{
vDom
,
links
});
if
(
dirTags
.
length
)
this
.
$emit
(
"
getDirTags
"
,
{
vDom
,
dirTags
});
},
},
rerender
()
{
rerender
()
{
const
_this
=
this
;
const
_this
=
this
;
...
@@ -79,6 +81,8 @@ export default {
...
@@ -79,6 +81,8 @@ export default {
src="
${
href
}
"
src="
${
href
}
"
></video></p>`
;
></video></p>`
;
}
}
console
.
log
(
"
imgimgimg
"
);
// ![img](...)渲染图片
// ![img](...)渲染图片
let
out
=
let
out
=
'
<p class="md_img_container"><img src="
'
+
'
<p class="md_img_container"><img src="
'
+
...
@@ -116,7 +120,37 @@ export default {
...
@@ -116,7 +120,37 @@ export default {
out
+=
"
/></p>
"
;
out
+=
"
/></p>
"
;
return
out
;
return
out
;
},
},
heading
(
text
,
level
,
raw
,
slugger
)
{
if
(
this
.
options
.
headerIds
)
{
return
(
"
<h
"
+
level
+
'
id="
'
+
"
h
"
+
level
+
"
_
"
+
this
.
options
.
headerPrefix
+
slugger
.
slug
(
raw
)
+
"
_
"
+
new
Date
().
getTime
()
+
'
">
'
+
text
+
"
</h
"
+
level
+
"
>
\n
"
);
}
// ignore IDs
return
"
<h
"
+
level
+
"
>
"
+
text
+
"
</h
"
+
level
+
"
>
\n
"
;
},
link
(
href
,
title
,
text
)
{
link
(
href
,
title
,
text
)
{
console
.
log
(
"
linklink
"
);
if
(
text
?.
toLowerCase
()
===
"
toc
"
)
{
return
`
<h1 class="toc_title">
${
href
}
</h1>
<div class="tocEl"></div>`
;
}
if
(
!
href
&&
!
title
)
return
""
;
if
(
!
href
&&
!
title
)
return
""
;
if
(
href
===
null
)
{
if
(
href
===
null
)
{
return
text
;
return
text
;
...
@@ -155,9 +189,15 @@ export default {
...
@@ -155,9 +189,15 @@ export default {
return
`<a type="user" download data-user="
${
user
&&
return
`<a type="user" download data-user="
${
user
&&
user
.
username
}
" href="
${(
user
&&
user
.
url
)
||
"
javascript:void(0)
"
}
" class="md_call_user">
${
val
}
</a>`
;
user
.
username
}
" href="
${(
user
&&
user
.
url
)
||
"
javascript:void(0)
"
}
" class="md_call_user">
${
val
}
</a>`
;
})
})
// tab缩进
.
replace
(
/^
\s{2,3}(
.+
)
/
,
function
(
val
)
{
.
replace
(
/^
\s{2,3}(
.+
)
/
,
function
(
val
)
{
return
`<span style="display:inline-block;text-indent:2em;">
${
val
}
</span>`
;
return
`<span style="display:inline-block;text-indent:2em;">
${
val
}
</span>`
;
});
})
.
replace
(
/
\[
TOC
\]
/i
,
`<h1 class="toc_title">目录</h1><div class="tocEl"></div>`
);
return
newText
;
return
newText
;
}
}
};
};
...
...
src/components/header/components/tool-button.vue
浏览文件 @
4665e8e3
...
@@ -265,7 +265,10 @@ export default {
...
@@ -265,7 +265,10 @@ export default {
this
.
$emit
(
"
setFullScreen
"
,
false
);
this
.
$emit
(
"
setFullScreen
"
,
false
);
break
;
break
;
case
"
help
"
:
case
"
help
"
:
this
.
$emit
(
"
updateShowHelp
"
,
true
);
this
.
$emit
(
"
updateShowDoc
"
,
"
help
"
);
break
;
case
"
dir
"
:
this
.
$emit
(
"
updateShowDoc
"
,
"
dir
"
);
break
;
break
;
default
:
default
:
break
;
break
;
...
...
src/components/header/md-header.vue
浏览文件 @
4665e8e3
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
<span>
预览
</span>
<span>
预览
</span>
</div>
</div>
</div>
</div>
<div
:class=
"['header_tools',
{ disabled }]"
v-if="!showPreview"
>
<div
:class=
"['header_tools',
{ disabled }]">
<tool-button
<tool-button
:ref=
"item.name"
:ref=
"item.name"
:ulNum.sync=
"ulNum"
:ulNum.sync=
"ulNum"
...
@@ -27,7 +27,7 @@
...
@@ -27,7 +27,7 @@
@
updateText=
"handleUpdateText"
@
updateText=
"handleUpdateText"
@
upload=
"$emit('upload', $event)"
@
upload=
"$emit('upload', $event)"
@
setFormatType=
"setFormatType"
@
setFormatType=
"setFormatType"
@
updateShow
Help=
"$emit('updateShowHelp
', $event)"
@
updateShow
Doc=
"$emit('updateShowDoc
', $event)"
:class=
"
{ active: item.name === 'format'
&&
formatType }"
:class=
"
{ active: item.name === 'format'
&&
formatType }"
v-for="(item, index) in toolsShow"
v-for="(item, index) in toolsShow"
:key="index"
:key="index"
...
@@ -47,7 +47,8 @@ import {
...
@@ -47,7 +47,8 @@ import {
getPosition
,
getPosition
,
removeBlankLine
,
removeBlankLine
,
copyFormatRules
,
copyFormatRules
,
checkBoswer
checkBoswer
,
pick
}
from
"
@/assets/js/utils
"
;
}
from
"
@/assets/js/utils
"
;
import
toolButton
from
"
./components/tool-button
"
;
import
toolButton
from
"
./components/tool-button
"
;
export
default
{
export
default
{
...
@@ -107,10 +108,18 @@ export default {
...
@@ -107,10 +108,18 @@ export default {
}
}
},
},
computed
:
{
computed
:
{
previewTools
()
{
const
list
=
this
.
toolButtonList
;
return
[
this
.
dirBtn
,
...
pick
(
list
,
"
help
"
,
"
fullScreen
"
,
"
cancelFullScreen
"
)
];
},
toolsShow
()
{
toolsShow
()
{
const
toolsList
=
this
.
toolButtonList
;
const
toolsList
=
this
.
toolButtonList
;
const
toolsOptions
=
this
.
toolsOptions
;
const
toolsOptions
=
this
.
toolsOptions
;
if
(
!
toolsOptions
)
return
toolsList
;
if
(
!
toolsOptions
)
return
toolsList
;
if
(
this
.
showPreview
)
return
this
.
previewTools
;
return
toolsList
.
filter
(
item
=>
{
return
toolsList
.
filter
(
item
=>
{
return
isNotFalse
(
toolsOptions
[
item
.
name
]);
return
isNotFalse
(
toolsOptions
[
item
.
name
]);
});
});
...
@@ -179,6 +188,11 @@ export default {
...
@@ -179,6 +188,11 @@ export default {
icon
:
"
fullScreen
"
,
icon
:
"
fullScreen
"
,
tip
:
"
全屏模式
"
tip
:
"
全屏模式
"
},
},
dirBtn
:
{
name
:
"
dir
"
,
icon
:
"
dir
"
,
tip
:
"
目录
"
},
toolButtonList
:
[
toolButtonList
:
[
{
{
name
:
"
call
"
,
name
:
"
call
"
,
...
@@ -298,6 +312,11 @@ export default {
...
@@ -298,6 +312,11 @@ export default {
"
\n\n
| 表头 | 表头 |
\n
| ------ | ------ |
\n
| 单元格 | 单元格 |
\n
| 单元格 | 单元格 |
\n\n
"
,
"
\n\n
| 表头 | 表头 |
\n
| ------ | ------ |
\n
| 单元格 | 单元格 |
\n
| 单元格 | 单元格 |
\n\n
"
,
endStr
:
""
endStr
:
""
},
},
// {
// name: "dir",
// icon: "dir",
// tip: "目录"
// },
{
{
name
:
"
help
"
,
name
:
"
help
"
,
icon
:
"
help
"
,
icon
:
"
help
"
,
...
@@ -408,7 +427,7 @@ export default {
...
@@ -408,7 +427,7 @@ export default {
this
.
updateText
(
newText
,
len
);
this
.
updateText
(
newText
,
len
);
if
(
startStr
===
"
@
"
)
{
if
(
startStr
===
"
@
"
)
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
this
.
$parent
.
$refs
[
"
md_
"
+
this
.
id
].
createSelectUserDialog
(
'
android
'
);
this
.
$parent
.
$refs
[
"
md_
"
+
this
.
id
].
createSelectUserDialog
(
"
android
"
);
},
200
);
},
200
);
}
}
},
},
...
...
src/main.js
浏览文件 @
4665e8e3
...
@@ -4,8 +4,8 @@ import Vtip from "vtip";
...
@@ -4,8 +4,8 @@ import Vtip from "vtip";
import
"
vtip/lib/index.min.css
"
;
import
"
vtip/lib/index.min.css
"
;
import
{
initStyle
,
setzIndex
,
isNotEmpty
}
from
"
@/assets/js/utils
"
;
import
{
initStyle
,
setzIndex
,
isNotEmpty
}
from
"
@/assets/js/utils
"
;
import
"
@/assets/style/global.less
"
;
import
"
@/assets/style/global.less
"
;
import
"
@/assets/jupyter-render/dist/index.js
"
;
//
import "@/assets/jupyter-render/dist/index.js";
import
"
@/assets/jupyter-render/dist/assets/index.css
"
;
//
import "@/assets/jupyter-render/dist/assets/index.css";
Vue
.
use
(
Vtip
.
directive
);
Vue
.
use
(
Vtip
.
directive
);
function
initMdEditor
(
obj
)
{
function
initMdEditor
(
obj
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录