diff --git a/src/renderer/plugins/copy-rendered-content.tsx b/src/renderer/plugins/copy-rendered-content.tsx index 6c9ae069..9fefcb7c 100644 --- a/src/renderer/plugins/copy-rendered-content.tsx +++ b/src/renderer/plugins/copy-rendered-content.tsx @@ -1,4 +1,5 @@ import type { Plugin } from '@fe/context' +import type Token from 'markdown-it/lib/token' export default { name: 'copy-rendered-content', @@ -8,7 +9,7 @@ export default { inlineLocalImage: false, uploadLocalImage: false, highlightCode: false, - type: 'rtf' as 'html' | 'rtf', + type: 'rtf' as 'html' | 'rtf' | 'markdown', }) const panel = ctx.lib.vue.defineComponent({ @@ -24,26 +25,76 @@ export default { }) return () =>
-
-
{ctx.i18n.t('copy-rendered-content.options')}
-
- - - - -
-
{ctx.i18n.t('copy-rendered-content.type')}
+ +
+
+
+
{ctx.i18n.t('copy-rendered-content.options')}
+
+ + + {options.type !== 'markdown' && } + {options.type !== 'markdown' && }
} }) + async function transformMarkdown () { + let markdown = ctx.store.state.currentContent + const tokens = ctx.view.getRenderEnv()?.tokens + if (!markdown || !tokens) { + return + } + + const processImg = async (tokens: Token[]) => { + for (let token of tokens) { + if (token.children) { + await processImg(token.children) + } + + + if (token.tag === 'img' && token.attrGet(ctx.constant.DOM_ATTR_NAME.LOCAL_IMAGE)) { + const srcAttr = token.attrGet('src') + const originSrc = token.attrGet(ctx.constant.DOM_ATTR_NAME.ORIGIN_SRC) + if (srcAttr && originSrc) { + const res: Response = await ctx.api.fetchHttp(srcAttr) + const fileName = ctx.utils.path.basename(originSrc) + const file = new File( + [await res.blob()], + fileName, + { type: ctx.lib.mime.getType(fileName) || undefined } + ) + + let url: string | undefined + if (options.inlineLocalImage) { + url = await ctx.utils.fileToBase64URL(file) + } else if (options.uploadLocalImage) { + url = await ctx.action.getActionHandler('plugin.image-hosting-picgo.upload')(file) + } + + if (url) { + markdown = markdown.replace( + new RegExp(ctx.utils.encodeMarkdownLink(originSrc), 'g'), + ctx.utils.encodeMarkdownLink(url) + ) + } + } + } + } + } + + await processImg(tokens) + + return markdown + } + async function copyContent () { if (await ctx.ui.useModal().confirm({ title: ctx.i18n.t('status-bar.tool.copy-content'), @@ -52,17 +103,19 @@ export default { try { const startedAt = Date.now() ctx.ui.useToast().show('info', ctx.i18n.t('loading'), 10000) - const html = await ctx.view.getContentHtml(options) + const content = options.type === 'markdown' + ? await transformMarkdown() + : await ctx.view.getContentHtml(options) if (Date.now() - startedAt > 3000) { await ctx.ui.useModal().alert({ content: ctx.i18n.t('copy-rendered-content.complete') }) } if (options.type === 'rtf') { - await ctx.base.writeToClipboard('text/html', html) + await ctx.base.writeToClipboard('text/html', content) ctx.ui.useToast().show('info', ctx.i18n.t('copied')) } else { - ctx.utils.copyText(html) + ctx.utils.copyText(content) } } catch (error: any) { console.error(error) diff --git a/src/renderer/services/markdown.ts b/src/renderer/services/markdown.ts index ba43657d..c664bedd 100644 --- a/src/renderer/services/markdown.ts +++ b/src/renderer/services/markdown.ts @@ -49,5 +49,6 @@ markdown.block.tokenize = function (state, startLine, endLine) { markdown.core.ruler.after('normalize', 'after_normalize', state => { state.env.source = state.src + state.env.tokens = state.tokens return true }) diff --git a/src/renderer/types.ts b/src/renderer/types.ts index 63b38e2c..62915eed 100644 --- a/src/renderer/types.ts +++ b/src/renderer/types.ts @@ -1,4 +1,5 @@ import type { Language } from '@share/i18n' +import type Token from 'markdown-it/lib/token' import type * as Monaco from 'monaco-editor' export interface PathItem { @@ -92,7 +93,13 @@ export type ThemeName = 'system' | 'dark' | 'light' export type LanguageName = 'system' | Language export type ExportTypes = 'pdf' | 'docx' | 'html' | 'rst' | 'adoc' -export type RenderEnv = { source: string, file: Doc | null, renderCount: number, attributes?: Record } +export type RenderEnv = { + source: string, + file: Doc | null, + renderCount: number, + attributes?: Record, + tokens: Token[] +} export type BuildInSettings = { 'repos': Repo[], diff --git a/src/share/i18n/languages/en.ts b/src/share/i18n/languages/en.ts index 8ac58f6b..52ea27c6 100644 --- a/src/share/i18n/languages/en.ts +++ b/src/share/i18n/languages/en.ts @@ -294,7 +294,6 @@ const data = { 'use-html': 'Use the rendered HTML source', 'use-markdown': 'Use markdown source', 'loading': 'Converting, please wait...', - 'include-css': 'Include CSS', }, 'title-bar': { 'pin': 'Pin', diff --git a/src/share/i18n/languages/zh-CN.ts b/src/share/i18n/languages/zh-CN.ts index 0200e393..ff568cb1 100644 --- a/src/share/i18n/languages/zh-CN.ts +++ b/src/share/i18n/languages/zh-CN.ts @@ -295,7 +295,6 @@ const data: BaseLanguage = { 'use-html': '使用渲染后的 HTML 转换', 'use-markdown': '使用 Markdown 转换', 'loading': '转换中,请稍候……', - 'include-css': '包含 CSS', }, 'title-bar': { 'pin': '置顶窗口',