Merge branch 'release/2.0.0-beta9.0'

This commit is contained in:
purocean
2019-09-02 22:08:49 +08:00
11 changed files with 2767 additions and 82 deletions
+3 -2
View File
@@ -49,13 +49,14 @@
+ 样式风格:Markdown 使用 GitHub 风格样式和特性
+ 数据仓库:可定义多个数据位置以便文档分类
+ 外链转换:将外链或 BASE64 图片转换为本地图片:`Ctrl + Shift + 单击图片` `Ctrl + Alt + L` 转换所有外链图片到本地
+ HTML 解析:可以直接在文档里面使用 HTML 代码,也可以使用快捷键 `Ctrl + B + V` 粘贴复制 HTMl 为 Markdown
+ HTML 解析:可以直接在文档里面使用 HTML 代码,也可以使用快捷键 `Ctrl + B + V` 粘贴复制 HTML 为 Markdown
+ docx 导出:后端使用 pandoc 做转换器
+ TOC 支持:生成 TOC 在需要生成目录的地方写入 `[toc]{type: "ol", level: [1,2,3]}` 即可,,示例见 FEATURE.md
+ 嵌入小工具:文档支持内嵌 HTML 小工具,示例见 FEATURE.md
+ 嵌入 Plantuml 图形:需要安装 Java,graphviz ,示例见 FEATURE.md
+ 嵌入 drawio 图形:文档支持内嵌 drawio 图形,示例见 FEATURE.md
+ 嵌入 ECharts 图形:在文档中嵌入 Echarts 图形,示例见 FEATURE.md
+ 嵌入 Mermaid 图形:在文档中嵌入 Mermaid 图形,示例见 FEATURE.md
+ 元素属性书写:可自定义元素的任意属性,示例见 FEATURE.md
+ 表格解析增强:表格支持表格标题多行文本,列表等特性,示例见 FEATURE.md
@@ -147,7 +148,7 @@ yarn run start
## 更新日志
[最新发布](https://github.com/purocean/yn/releases)
### [v2.0.0-beta8.4](https://github.com/purocean/yn/releases/tag/v2.0.0-beta8.4) 2019-08-28
### [v2.0.0-beta9.0](https://github.com/purocean/yn/releases/tag/v2.0.0-beta9.0) 2019-09-02
1. 增加 2.0 计划
1. Electron 打包
1. 增加 HTML 小工具渲染
+1
View File
@@ -21,6 +21,7 @@
"markdown-it-katex": "^2.0.3",
"markdown-it-multimd-table": "^3.1.3",
"markdown-it-task-lists": "^2.1.1",
"mermaid": "^8.2.6",
"mime-types": "^2.1.24",
"monaco-editor": "^0.17.1",
"normalize.css": "^8.0.1",
+16 -5
View File
@@ -3,7 +3,7 @@
<MonacoEditor
ref="editor"
class="editor"
@change="val => $store.commit('app/setCurrentContent', val)"
@change="setCurrentValue"
@ready="editorReady"
@scroll-view="syncScrollView"
@paste-img="pasteImg"
@@ -52,6 +52,11 @@ export default {
this.$bus.off('file-new', this.createFile)
},
methods: {
setCurrentValue ({ uri, value }) {
if (this.toUri(this.currentFile) === uri) {
this.$store.commit('app/setCurrentContent', value)
}
},
saveFileOpenPosition (top) {
if (this.currentFile) {
const map = Storage.get(FILE_POSITION_KEY, {})
@@ -126,6 +131,13 @@ export default {
this.$emit('scroll-line', line)
this.saveFileOpenPositionDebounce(top)
},
toUri (file) {
if (file) {
return `yank-note://${file.repo}/${file.path.replace(/^\//, '')}`
} else {
return 'yank-note://system/blank.md'
}
},
async saveFile (f = null) {
const file = f || this.currentFile
@@ -186,7 +198,6 @@ export default {
this.$refs.editor.insert(`附件 [${dayjs().format('YYYY-MM-DD HH:mm')}]:[${file.name} (${(file.size / 1024).toFixed(2)}KiB)](${encodeURI(relativePath).replace('(', '%28').replace(')', '%29')}){class=open target=_blank}\n`)
},
async changeFile (current, previous) {
this.$refs.editor.setScrollToTop(0)
this.clearTimer()
if (previous && previous.repo && previous.path) {
@@ -195,7 +206,7 @@ export default {
if (!current) {
this.$store.commit('app/setPreviousContent', '\n')
this.$refs.editor.setValue('\n')
this.$refs.editor.setModel(this.toUri(current), '\n')
this.$store.commit('app/setCurrentFile', null)
return
}
@@ -203,7 +214,7 @@ export default {
if (current.content) { // 系统文件
this.$store.commit('app/setPreviousContent', current.content)
this.$store.commit('app/setSavedAt', null)
this.$refs.editor.setValue(current.content)
this.$refs.editor.setModel(this.toUri(current), current.content)
return
}
@@ -222,7 +233,7 @@ export default {
this.$store.commit('app/setPreviousContent', content)
this.$store.commit('app/setPreviousHash', hash)
this.$store.commit('app/setSavedAt', null)
this.$refs.editor.setValue(content)
this.$refs.editor.setModel(this.toUri(current), content)
} catch (error) {
this.$store.commit('app/setCurrentFile', null)
this.$toast.show('warning', error.message)
+39 -25
View File
@@ -6,19 +6,14 @@
import dayjs from 'dayjs'
import TurndownService from 'turndown'
const models = {}
const keys = {}
export default {
name: 'monaco-editor',
props: {
value: String
},
data () {
return {
editor: null
}
},
mounted () {
this.editor = null
if (!window.require) {
const loaderScript = document.createElement('script')
loaderScript.type = 'text/javascript'
@@ -38,6 +33,30 @@ export default {
window.removeEventListener('keyup', this.recordKeys)
},
methods: {
getModel (uri, value) {
let model = models[uri]
if (!model) {
model = window.monaco.editor.createModel(value, undefined, window.monaco.Uri.parse(uri))
model.onDidChangeContent(e => {
let value = model.getValue()
const eol = model.getEOL()
if (!value.endsWith(eol)) {
value += eol
model.setValue(value)
}
this.$emit('change', { uri, value })
})
}
// TODO 不用 set value 保留编辑状态
model.setValue(value)
// TODO 缓存 model
models[uri] = model
return model
},
recordKeys (e) {
if (e.type === 'keydown') {
keys[e.key] = true
@@ -56,9 +75,12 @@ export default {
})
},
initMonaco () {
window.supportedExtensions = window.monaco.languages.getLanguages().flatMap(x => x.extensions)
const model = this.getModel('yank-note://system/blank.md', '')
this.editor = window.monaco.editor.create(window.document.getElementById('editor'), {
value: this.value,
language: 'markdown',
value: '',
theme: 'vs-dark',
fontSize: 18,
wordWrap: false,
@@ -73,23 +95,14 @@ export default {
scrollbar: {
vertical: 'hidden',
verticalScrollbarSize: 0
}
},
model,
})
this.editor.onDidChangeCursorSelection(e => {
this.$emit('change-document', this.getDucumentInfo())
})
this.editor.onDidChangeModelContent(e => {
let val = this.getValue()
const eol = this.editor.getModel().getEOL()
if (!val.endsWith(eol)) {
val += eol
this.setValue(val)
}
this.$emit('change', val)
})
this.editor.onDidScrollChange(e => {
const line = this.editor.getVisibleRanges()[0].startLineNumber
const top = this.editor.getScrollTop()
@@ -248,11 +261,12 @@ export default {
getValue () {
return this.editor.getModel().getValue(window.monaco.editor.DefaultEndOfLine.LF)
},
setValue (val) {
this.editor.getModel().setValue(val)
setModel (uri, value) {
const model = this.getModel(uri, value || '')
this.editor.setModel(model)
},
replaceValue (oldValue, newValue) {
this.setValue(this.getValue().replace(oldValue, newValue))
this.editor.getModel().setValue(this.getValue().replace(oldValue, newValue))
},
getDucumentInfo () {
const selection = this.editor.getSelection()
@@ -269,7 +283,7 @@ export default {
const isWrapping = this.editor.getConfiguration().wrappingInfo.isViewportWrapping
this.editor.updateOptions({ wordWrap: !isWrapping })
}
}
},
}
</script>
+15 -3
View File
@@ -57,6 +57,7 @@ import SourceLinePlugin from '../plugins/SourceLinePlugin'
import LinkTargetPlugin from '../plugins/LinkTargetPlugin'
import DrawioPlugin from '../plugins/DrawioPlugin'
import PlantumlPlugin from '../plugins/PlantumlPlugin'
import MermaidPlugin from '../plugins/MermaidPlugin'
import file from '@/lib/file'
import env from '@/lib/env'
@@ -91,6 +92,7 @@ const markdown = Markdown({
.use(MultimdTable, { enableMultilineRows: true })
.use(MarkdownItToc)
.use(MarkdownItECharts)
.use(MermaidPlugin)
export default {
name: 'xview',
@@ -115,13 +117,18 @@ export default {
}, 1000, { leading: true })
this.render = _.debounce(() => {
this.$refs.view.innerHTML = markdown.render(this.replaceRelativeLink(this.currentContent))
MarkdownItECharts.update()
// 编辑非 markdown 文件预览直接显示代码
const content = (this.filePath || '').endsWith('.md')
? this.currentContent
: '```' + file.extname(this.fileName || '').replace(/^\./, '') + '\n' + this.currentContent + '```'
this.$refs.view.innerHTML = markdown.render(this.replaceRelativeLink(content))
this.runAppletScriptDebounce()
this.initDrawio()
this.updateOutline()
this.updateTodoCount()
this.updatePlantumlDebounce()
MarkdownItECharts.update()
MermaidPlugin.update()
for (let ele of document.querySelectorAll('code[class^="language-"]')) {
HighlightLineNumber.lineNumbersBlock(ele)
@@ -282,7 +289,6 @@ export default {
env.require && env.require('opn')(link.href)
e.preventDefault()
e.stopPropagation()
return
}
}
@@ -416,6 +422,7 @@ export default {
background: #303133;
}
.markdown-body /deep/ div.mermaid,
.markdown-body /deep/ div.drawio-wrapper,
.markdown-body /deep/ input,
.markdown-body /deep/ img
@@ -424,6 +431,7 @@ export default {
filter: brightness(70%);
}
.markdown-body /deep/ div.mermaid:hover,
.markdown-body /deep/ div.drawio-wrapper:hover,
.markdown-body /deep/ img:hover
{
@@ -683,4 +691,8 @@ button:hover {
.view .hljs-ln td.hljs-ln-code {
padding-left: 10px;
}
.view .mermaid {
background: #fff;
}
</style>
+2 -2
View File
@@ -43,6 +43,7 @@
<script>
import { mapState } from 'vuex'
import File from '@/lib/file'
import Extensions from '@/lib/extensions'
import DrawioPlugin from '@/plugins/DrawioPlugin'
import 'vue-awesome/icons/folder-plus'
@@ -110,14 +111,13 @@ export default {
},
select (item) {
if (item.type !== 'dir') {
if (item.name.endsWith('.md')) {
if (Extensions.supported(item.name)) {
this.$store.commit('app/setCurrentFile', item)
} else {
if (item.path.toLowerCase().endsWith('.drawio')) {
DrawioPlugin.open(item)
} else {
File.openInOS(this.item)
// window.open(`api/attachment/${encodeURIComponent(item.name)}?repo=${item.repo}&path=${encodeURIComponent(item.path)}`)
}
}
}
+153
View File
@@ -0,0 +1,153 @@
import file from './file'
const extensions = [
'.txt',
'.gitignore',
'.json',
'.bowerrc',
'.jshintrc',
'.jscsrc',
'.eslintrc',
'.babelrc',
'.bat',
'.cmd',
'.coffee',
'.c',
'.h',
'.cpp',
'.cc',
'.cxx',
'.hpp',
'.hh',
'.hxx',
'.cs',
'.csx',
'.cake',
'.css',
'.dockerfile',
'.fs',
'.fsi',
'.ml',
'.mli',
'.fsx',
'.fsscript',
'.go',
'.handlebars',
'.hbs',
'.html',
'.htm',
'.shtml',
'.xhtml',
'.mdoc',
'.jsp',
'.asp',
'.aspx',
'.jshtm',
'.ini',
'.properties',
'.gitconfig',
'.java',
'.jav',
'.js',
'.es6',
'.jsx',
'.kt',
'.less',
'.lua',
'.md',
'.markdown',
'.mdown',
'.mkdn',
'.mkd',
'.mdwn',
'.mdtxt',
'.mdtext',
'.dax',
'.msdax',
'.m',
'.pas',
'.p',
'.pp',
'.php',
'.php4',
'.php5',
'.phtml',
'.ctp',
'.dats',
'.sats',
'.hats',
'.pq',
'.pqm',
'.ps1',
'.psm1',
'.psd1',
'.jade',
'.pug',
'.py',
'.rpy',
'.pyw',
'.cpy',
'.gyp',
'.gypi',
'.r',
'.rhistory',
'.rprofile',
'.rt',
'.cshtml',
'.redis',
'.rb',
'.rbx',
'.rjs',
'.gemspec',
'.pp',
'.rs',
'.rlib',
'.sb',
'.scss',
'.sol',
'.sql',
'.st',
'.iecst',
'.iecplc',
'.lc3lib',
'.swift',
'.tcl',
'.ts',
'.tsx',
'.vb',
'.xml',
'.dtd',
'.ascx',
'.csproj',
'.config',
'.wxi',
'.wxl',
'.wxs',
'.xaml',
'.svg',
'.svgz',
'.yaml',
'.yml',
'.scm',
'.ss',
'.sch',
'.rkt',
'.clj',
'.cljs',
'.cljc',
'.edn',
'.sh',
'.bash',
'.pl',
'.azcli',
'.cls',
'.graphql',
'.gql'
]
const supported = name => {
return extensions.includes(file.extname(name.toLowerCase()))
}
export default {
supported
}
+56
View File
@@ -0,0 +1,56 @@
import mermaid from 'mermaid'
const mermaidChart = (code) => {
try {
mermaid.parse(code)
return `<div class="mermaid">${code}</div>`
} catch ({ str, hash }) {
return `<pre>${str}</pre>`
}
}
const MermaidPlugin = (md) => {
md.mermaid = mermaid
mermaid.loadPreferences = (preferenceStore) => {
let mermaidTheme = preferenceStore.get('mermaid-theme')
if (mermaidTheme === undefined) {
mermaidTheme = 'default'
}
let ganttAxisFormat = preferenceStore.get('gantt-axis-format')
if (ganttAxisFormat === undefined) {
ganttAxisFormat = '%Y-%m-%d'
}
mermaid.initialize({
theme: mermaidTheme,
gantt: { axisFormatter: [
[ganttAxisFormat, (d) => {
return d.getDay() === 1
}]
] }
})
return {
'mermaid-theme': mermaidTheme,
'gantt-axis-format': ganttAxisFormat
}
}
const temp = md.renderer.rules.fence.bind(md.renderer.rules)
md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
const token = tokens[idx]
const code = token.content.trim()
if (token.info === 'mermaid') {
return mermaidChart(code)
}
const firstLine = code.split(/\n/)[0].trim()
if (firstLine === 'gantt' || firstLine === 'sequenceDiagram' || firstLine.match(/^graph (?:TB|BT|RL|LR|TD);?$/)) {
return mermaidChart(code)
}
return temp(tokens, idx, options, env, slf)
}
}
MermaidPlugin.update = () => {
mermaid.init()
}
export default MermaidPlugin
+2466 -44
View File
File diff suppressed because it is too large Load Diff
+15
View File
@@ -32,6 +32,21 @@ Yank-Note 很多功能可以直接使用的快捷键操作
2. 加密和解密过程均在前端完成
3. 请务必保管好文档密码,密码一旦丢失就只能自己暴力破解了。
## Mermaid 图形解析
```mermaid
sequenceDiagram
participant Alice
participant Bob
Alice->>John: Hello John, how are you?
loop Healthcheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts <br/>prevail!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## Plantuml 图形解析
系统需要有 Java 环境,并安装有 graphviz
示例如下
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "yank.note.yang",
"version": "2.0.0-beta8.4",
"version": "2.0.0-beta9.0",
"description": "Yank-Note",
"main": "dist/app.js",
"license": "Apache-2.0",