diff --git a/README.md b/README.md index be31176b1..7df88727d 100644 --- a/README.md +++ b/README.md @@ -150,15 +150,19 @@ yarn run start [Windows 商店下载](https://www.microsoft.com/zh-cn/p/yank-note-%e4%b8%80%e6%ac%be%e9%9d%a2%e5%90%91%e7%a8%8b%e5%ba%8f%e5%91%98%e7%9a%84-markdown-%e7%ac%94%e8%ae%b0%e5%ba%94%e7%94%a8/9n08bq8k8681?rtc=1#activetab=pivot:overviewtab) +### [v2.2.1](https://github.com/purocean/yn/releases/tag/v2.2.1) 2019-12-25 +1. 修复跳转中文路径处理 +1. 优化插入文档文件链接 + +
+展开查看更多版本记录 + ### [v2.2.0](https://github.com/purocean/yn/releases/tag/v2.2.0) 2019-12-25 1. 增加文档之间跳转功能 1. 增加复制文档标题链接功能 1. 调整文档插入选择面板 1. 修复高分辨率下目录树箭头消失问题 -
-展开查看更多版本记录 - ### [v2.1.1](https://github.com/purocean/yn/releases/tag/v2.1.1) 2019-12-24 1. 增加在当前目录创建文件菜单 1. 限制快捷跳转列表数量以提高性能 diff --git a/frontend/src/components/Editor.vue b/frontend/src/components/Editor.vue index 20d5d6ce8..3b480d1bc 100644 --- a/frontend/src/components/Editor.vue +++ b/frontend/src/components/Editor.vue @@ -20,6 +20,7 @@ import { mapState } from 'vuex' import dayjs from 'dayjs' import File from '@/lib/file' import Storage from '@/lib/Storage' +import { encodeMarkdownLink } from '@/lib/utils' import MonacoEditor from './MonacoEditor' const FILE_POSITION_KEY = 'filePosition' @@ -185,13 +186,13 @@ export default { async pasteImg (file) { const { relativePath } = await File.upload(this.currentFile.repo, this.currentFile.path, file) this.$bus.emit('file-uploaded', relativePath) - this.$refs.editor.insert(`![图片](${encodeURI(relativePath)})\n`) + this.$refs.editor.insert(`![图片](${encodeMarkdownLink(relativePath)})\n`) }, async uploadFile (file) { const filename = `${dayjs().format('YYYYMMDDHHmmss')}.${file.name}` const { relativePath } = await File.upload(this.currentFile.repo, this.currentFile.path, file, filename) this.$bus.emit('file-uploaded', relativePath) - 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`) + this.$refs.editor.insert(`附件 [${dayjs().format('YYYY-MM-DD HH:mm')}]:[${file.name} (${(file.size / 1024).toFixed(2)}KiB)](${encodeMarkdownLink(relativePath)}){class=open target=_blank}\n`) }, async changeFile (current, previous) { this.clearTimer() diff --git a/frontend/src/components/Filter.vue b/frontend/src/components/Filter.vue index 9afce3d92..192dec4a1 100644 --- a/frontend/src/components/Filter.vue +++ b/frontend/src/components/Filter.vue @@ -8,6 +8,7 @@ import { mapState } from 'vuex' import XMask from './Mask' import QuickOpen from './QuickOpen' +import { encodeMarkdownLink } from '@/lib/utils' export default { name: 'x-filter', @@ -29,7 +30,7 @@ export default { this.show = f => { if (this.currentFile) { const relativePath = f.path.replace(this.currentFile.path.substr(0, this.currentFile.path.lastIndexOf('/')), '.') - this.$bus.emit('editor-insert-value', `[${f.name.replace(/\.[^.]$/, '')}](${encodeURI(relativePath)})`) + this.$bus.emit('editor-insert-value', `[${f.name.replace(/\.[^.]$/, '')}](${encodeMarkdownLink(relativePath)})`) } this.show = false } diff --git a/frontend/src/components/Preview.vue b/frontend/src/components/Preview.vue index 8589977b8..3c8d8d410 100644 --- a/frontend/src/components/Preview.vue +++ b/frontend/src/components/Preview.vue @@ -60,6 +60,7 @@ import PlantumlPlugin from '../plugins/PlantumlPlugin' import MermaidPlugin from '../plugins/MermaidPlugin' import file from '@/lib/file' import env from '@/lib/env' +import { encodeMarkdownLink } from '@/lib/utils' import 'github-markdown-css/github-markdown.css' import 'highlight.js/styles/atom-one-dark.css' @@ -205,7 +206,7 @@ export default { return match } - return `[${alt}](api/attachment/${encodeURIComponent(fileName)}?repo=${repo}&path=${encodeURI(filePath)})` + return `[${alt}](api/attachment/${encodeURIComponent(fileName)}?repo=${repo}&path=${encodeURIComponent(filePath)})` }) }, updatePlantuml () { @@ -273,12 +274,12 @@ export default { img.src.startsWith('http://') || img.src.startsWith('https://') ) { - window.fetch(`api/proxy?url=${encodeURI(img.src)}`).then(r => { + window.fetch(`api/proxy?url=${encodeURIComponent(img.src)}`).then(r => { r.blob().then(async blob => { const imgFile = new File([blob], 'file.' + mime.extension(r.headers.get('content-type'))) const { relativePath } = await file.upload(this.fileRepo, this.filePath, imgFile) this.$bus.emit('tree-refresh') - this.$bus.emit('editor-replace-value', img.src, encodeURI(relativePath)) + this.$bus.emit('editor-replace-value', img.src, encodeMarkdownLink(relativePath)) }) }) } @@ -308,7 +309,7 @@ export default { } } else { // 处理相对链接 if (/(\.md$|\.md#)/.test(href)) { // 处理打开相对 md 文件 - const tmp = href.split('#') + const tmp = decodeURI(href).split('#') let path = tmp[0] if (path.startsWith('.')) { // 将相对路径转换为绝对路径 @@ -324,17 +325,18 @@ export default { }) // 跳转锚点 - const hash = tmp[1] + const hash = tmp.slice(1).join('#') if (hash) { this.$bus.once('preview-rendered', () => { - const el = document.getElementById(hash) + const el = document.getElementById(hash) || + document.getElementById(encodeURIComponent(hash)) + if (el) { // 如果是标题的话,也顺便将编辑器滚动到可视区域 if (hash.startsWith('h-')) { el.click() - } else { - el.scrollIntoView() } + el.scrollIntoView() } }) } @@ -353,7 +355,7 @@ export default { // 复制标题链接 if (['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].indexOf(target.tagName) > -1 && target.id && e.ctrlKey) { - this.$bus.emit('copy-text', encodeURI(this.filePath) + '#' + target.id) + this.$bus.emit('copy-text', encodeMarkdownLink(this.filePath) + '#' + encodeMarkdownLink(decodeURIComponent(target.id))) return preventEvent() } diff --git a/frontend/src/lib/file.js b/frontend/src/lib/file.js index d867c8238..e87d788b5 100644 --- a/frontend/src/lib/file.js +++ b/frontend/src/lib/file.js @@ -133,7 +133,10 @@ const upload = async (repo, belongPath, uploadFile, name = null) => { const filename = name || Crypto.binMd5(fr.result).substr(0, 8) + extname(uploadFile.name) const formData = new FormData() - const path = belongPath.replace(/\/([^/]*)$/, (_, capture) => `/FILES/${slugify(capture)}/` + filename) + const path = belongPath.replace(/\/([^/]*)$/, (_, capture) => { + const dirName = slugify(capture) + return `/FILES/${dirName.startsWith('.') ? 'upload' : dirName}/` + filename + }) formData.append('repo', repo) formData.append('path', path) formData.append('attachment', uploadFile) diff --git a/frontend/src/lib/utils.js b/frontend/src/lib/utils.js new file mode 100644 index 000000000..612605ecc --- /dev/null +++ b/frontend/src/lib/utils.js @@ -0,0 +1,6 @@ +export const encodeMarkdownLink = path => { + return path + .replace(/\(/g, '%28') + .replace(/\)/g, '%29') + .replace(/ /g, '%20') +} diff --git a/package.json b/package.json index 6d3dd9f81..96e622dec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yank.note.yang", - "version": "2.2.0", + "version": "2.2.1", "description": "Yank Note 一款面向程序员的 Markdown 笔记应用", "main": "dist/app.js", "license": "Apache-2.0",