diff --git a/src/components/menus/MainMenu.vue b/src/components/menus/MainMenu.vue index 9aaedb06..d552072b 100644 --- a/src/components/menus/MainMenu.vue +++ b/src/components/menus/MainMenu.vue @@ -21,10 +21,10 @@ {{currentWorkspace.name}}CouchDB 数据库同步。 - {{currentWorkspace.name}}GitHub repo 同步。 + {{currentWorkspace.name}}GitHub 仓库 同步。 - {{currentWorkspace.name}}Gitee repo 同步。 + {{currentWorkspace.name}}Gitee 仓库 同步。 {{currentWorkspace.name}}GitLab 项目同步。 diff --git a/src/components/modals/WorkspaceImgPathModal.vue b/src/components/modals/WorkspaceImgPathModal.vue index ca1c6191..eb78d8c0 100644 --- a/src/components/modals/WorkspaceImgPathModal.vue +++ b/src/components/modals/WorkspaceImgPathModal.vue @@ -36,9 +36,11 @@ export default modalTemplate({ }, methods: { resolve() { - const path = this.path && this.path.replace(/^\//, ''); + if (!this.path) { + this.setError('path'); + } this.config.resolve({ - path: path || '/imgs/{YYYY}-{MM}-{DD}', + path: this.path || '/imgs/{YYYY}-{MM}-{DD}', }); }, }, diff --git a/src/data/defaults/defaultSettings.yml b/src/data/defaults/defaultSettings.yml index 5a64e9a3..27e6ea0f 100644 --- a/src/data/defaults/defaultSettings.yml +++ b/src/data/defaults/defaultSettings.yml @@ -38,6 +38,7 @@ shortcuts: mod+shift+s: strikethrough mod+shift+t: table mod+shift+u: ulist + mod+shift+f: inlineformula '= = > space': method: expand params: diff --git a/src/libs/pagedown.js b/src/libs/pagedown.js index 272edea4..c46345ad 100644 --- a/src/libs/pagedown.js +++ b/src/libs/pagedown.js @@ -40,7 +40,9 @@ var defaultsStrings = { undo: "Undo - Ctrl/Cmd+Z", redo: "Redo - Ctrl/Cmd+Y", - help: "Markdown Editing Help" + help: "Markdown Editing Help", + + formulaexample: "这里输入Latex表达式", }; // options, if given, can have the following properties: @@ -465,6 +467,7 @@ function UIManager(input, commandManager) { buttons.bold = bindCommand("doBold"); buttons.italic = bindCommand("doItalic"); buttons.strikethrough = bindCommand("doStrikethrough"); + buttons.inlineformula = bindCommand("doInlinkeFormula"); buttons.imageUploading = bindCommand("doImageUploading"); buttons.link = bindCommand(function (chunk, postProcessing) { return this.doLinkOrImage(chunk, postProcessing, false); @@ -618,6 +621,49 @@ commandProto.doStrikethrough = function (chunk, postProcessing) { return; }; +commandProto.doInlinkeFormula = function (chunk, postProcessing) { + + // Get rid of whitespace and fixup newlines. + chunk.trimWhitespace(); + chunk.selection = chunk.selection.replace(/\n{2,}/g, "\n"); + + // Look for stars before and after. Is the chunk already marked up? + // note that these regex matches cannot fail + var starsBefore = /(\$*$)/.exec(chunk.before)[0]; + var starsAfter = /(^\$*)/.exec(chunk.after)[0]; + + var prevStars = Math.min(starsBefore.length, starsAfter.length); + + var nStars = 2; + + // Remove stars if we have to since the button acts as a toggle. + if ((prevStars >= nStars) && (prevStars != 2 || nStars != 1)) { + chunk.before = chunk.before.replace(re("[\$]{" + nStars + "}$", ""), ""); + chunk.after = chunk.after.replace(re("^[\$]{" + nStars + "}", ""), ""); + } else if (!chunk.selection && starsAfter) { + // It's not really clear why this code is necessary. It just moves + // some arbitrary stuff around. + chunk.after = chunk.after.replace(/^(\$*)/, ""); + chunk.before = chunk.before.replace(/(\s?)$/, ""); + var whitespace = re.$1; + chunk.before = chunk.before + starsAfter + whitespace; + } else { + + // In most cases, if you don't have any selected text and click the button + // you'll get a selected, marked up region with the default text inserted. + if (!chunk.selection && !starsAfter) { + chunk.selection = this.getString("formulaexample"); + } + + // Add the true markup. + var markup = "$"; // shouldn't the test be = ? + chunk.before = chunk.before + markup; + chunk.after = markup + chunk.after; + } + + return; +}; + commandProto.doImageUploading = function (chunk, postProcessing) { var enteredCallback = function (imgId) { if (imgId !== null) { diff --git a/src/services/editorSvc.js b/src/services/editorSvc.js index b5731987..bed2e8d5 100644 --- a/src/services/editorSvc.js +++ b/src/services/editorSvc.js @@ -46,16 +46,10 @@ class SectionDesc { const pathUrlMap = Object.create(null); -const getCurrAbsolutePath = () => { - const fileId = store.getters['file/current'].id; - const fileSyncData = store.getters['data/syncDataByItemId'][fileId] || { id: '' }; - const fileAbsolutePath = `${store.getters['workspace/currentWorkspace'].path || ''}${fileSyncData.id}`; - return fileAbsolutePath.substring(0, fileAbsolutePath.lastIndexOf('/')); -}; - const getImgUrl = async (uri) => { if (uri.indexOf('http://') !== 0 && uri.indexOf('https://') !== 0) { - const absoluteImgPath = utils.getAbsoluteFilePath(getCurrAbsolutePath(), uri); + const currDirNode = store.getters['explorer/selectedNodeFolder']; + const absoluteImgPath = utils.getAbsoluteFilePath(currDirNode, uri); if (pathUrlMap[absoluteImgPath]) { return pathUrlMap[absoluteImgPath]; } diff --git a/src/services/imageSvc.js b/src/services/imageSvc.js index 757eceea..dbb9601c 100644 --- a/src/services/imageSvc.js +++ b/src/services/imageSvc.js @@ -7,14 +7,7 @@ import giteaHelper from '../services/providers/helpers/giteaHelper'; import githubHelper from '../services/providers/helpers/githubHelper'; import customHelper from '../services/providers/helpers/customHelper'; -function getCurrAbsolutePath() { - const fileId = store.getters['file/current'].id; - const fileSyncData = store.getters['data/syncDataByItemId'][fileId] || { id: '' }; - const fileAbsolutePath = `${store.getters['workspace/currentWorkspace'].path || ''}${fileSyncData.id}`; - return fileAbsolutePath.substring(0, fileAbsolutePath.lastIndexOf('/')); -} - -function getImagePath(confPath, imgType) { +const getImagePath = (confPath, imgType) => { const time = new Date(); const date = time.getDate(); const month = time.getMonth() + 1; @@ -22,7 +15,7 @@ function getImagePath(confPath, imgType) { const path = confPath.replace('{YYYY}', year).replace('{MM}', `0${month}`.slice(-2)) .replace('{DD}', `0${date}`.slice(-2)).replace('{MDNAME}', store.getters['file/current'].name); return `${path}${path.endsWith('/') ? '' : '/'}${utils.uid()}.${imgType.split('/')[1]}`; -} +}; export default { // 上传图片 返回图片链接 @@ -38,13 +31,14 @@ export default { const path = getImagePath(currStorage.sub, imgFile.type); // 保存到indexeddb const base64 = await utils.encodeFiletoBase64(imgFile); - const absolutePath = utils.getAbsoluteFilePath(getCurrAbsolutePath(), path); + const currDirNode = store.getters['explorer/selectedNodeFolder']; + const absolutePath = utils.getAbsoluteFilePath(currDirNode, path); await localDbSvc.saveImg({ id: md5(absolutePath), path: absolutePath, content: base64, }); - return { url: path.replace(' ', '%20') }; + return { url: path.replaceAll(' ', '%20') }; } if (!currStorage.provider) { return { error: '暂无已选择的图床!' }; diff --git a/src/services/optional/shortcuts.js b/src/services/optional/shortcuts.js index eebd022d..b81f7b97 100644 --- a/src/services/optional/shortcuts.js +++ b/src/services/optional/shortcuts.js @@ -32,7 +32,9 @@ const methods = { ulist: pagedownHandler('ulist'), clist: pagedownHandler('clist'), heading: pagedownHandler('heading'), + inline: pagedownHandler('heading'), hr: pagedownHandler('hr'), + inlineformula: pagedownHandler('inlineformula'), sync() { if (syncSvc.isSyncPossible()) { syncSvc.requestSync(); diff --git a/src/services/utils.js b/src/services/utils.js index b8dc52e0..a2c512c3 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -383,21 +383,35 @@ export default { elt.parentNode.removeChild(elt); }); }, + getAbsoluteDir(currDirNode) { + if (!currDirNode) { + return ''; + } + let path = currDirNode.item.name; + if (currDirNode.parentNode) { + const parentPath = this.getAbsoluteDir(currDirNode.parentNode); + if (parentPath) { + path = `${parentPath}/${path}`; + } + } + return path || ''; + }, // 根据当前绝对路径 与 文件路径计算出文件绝对路径 - getAbsoluteFilePath(currAbsolutePath, filePath) { + getAbsoluteFilePath(currDirNode, filePath) { + const currAbsolutePath = this.getAbsoluteDir(currDirNode); // "/"开头说明已经是绝对路径 if (filePath.indexOf('/') === 0) { - return this.encodeUrlPath(filePath); + return filePath.replaceAll(' ', '%20'); } let path = filePath; // 相对上级路径 if (path.indexOf('../') === 0) { - return this.getAbsoluteFilePath(currAbsolutePath.substring(0, currAbsolutePath.lastIndexOf('/')), path.replace('../', '')); + return this.getAbsoluteFilePath(currDirNode && currDirNode.parentNode, path.replace('../', '')); } else if (path.indexOf('./') === 0) { path = `${currAbsolutePath}/${path.replace('./', '')}`; } else { path = `${currAbsolutePath}/${path}`; } - return (path.indexOf('/') === 0 ? path : `/${path}`).replace(' ', '%20'); + return (path.indexOf('/') === 0 ? path : `/${path}`).replaceAll(' ', '%20'); }, };