UNPKG

vue-markdown-v3

Version:

A Powerful and Highspeed Markdown Parser for Vue

242 lines (226 loc) 5.53 kB
import markdownIt from 'markdown-it' import emoji from 'markdown-it-emoji' import subscript from 'markdown-it-sub' import superscript from 'markdown-it-sup' import footnote from 'markdown-it-footnote' import deflist from 'markdown-it-deflist' import abbreviation from 'markdown-it-abbr' import insert from 'markdown-it-ins' import mark from 'markdown-it-mark' import toc from 'markdown-it-toc-and-anchor' import katex from 'markdown-it-katex' import tasklists from 'markdown-it-task-lists' import {h} from 'vue' export default { md: new markdownIt(), template: '<div><slot></slot></div>', data() { return { sourceData: this.source, } }, props: { watches: { type: Array, default: () => ['source', 'show', 'toc'], }, source: { type: String, default: ``, }, show: { type: Boolean, default: true, }, highlight: { type: Boolean, default: true }, html: { type: Boolean, default: true, }, xhtmlOut: { type: Boolean, default: true, }, breaks: { type: Boolean, default: true, }, linkify: { type: Boolean, default: true, }, emoji: { type: Boolean, default: true, }, typographer: { type: Boolean, default: true, }, langPrefix: { type: String, default: 'language-', }, quotes: { type: String, default: '“”‘’', }, tableClass: { type: String, default: 'table', }, taskLists: { type: Boolean, default: true }, toc: { type: Boolean, default: false, }, tocId: { type: String, }, tocClass: { type: String, default: 'table-of-contents', }, tocFirstLevel: { type: Number, default: 2, }, tocLastLevel: { type: Number, }, tocAnchorLink: { type: Boolean, default: true, }, tocAnchorClass: { type: String, default: 'toc-anchor', }, tocAnchorLinkSymbol: { type: String, default: '#', }, tocAnchorLinkSpace: { type: Boolean, default: true, }, tocAnchorLinkClass: { type: String, default: 'toc-anchor-link', }, anchorAttributes: { type: Object, default: () => ({}) }, prerender: { type: Function, default: (sourceData) => { return sourceData } }, postrender: { type: Function, default: (htmlData) => { return htmlData } } }, computed: { tocLastLevelComputed() { return this.tocLastLevel > this.tocFirstLevel ? this.tocLastLevel : this.tocFirstLevel + 1 } }, render() { this.md = new markdownIt() .use(subscript) .use(superscript) .use(footnote) .use(deflist) .use(abbreviation) .use(insert) .use(mark) .use(katex, { "throwOnError": false, "errorColor": " #cc0000" }) .use(tasklists, { enabled: this.taskLists }) if (this.emoji) { this.md.use(emoji) } this.md.set({ html: this.html, xhtmlOut: this.xhtmlOut, breaks: this.breaks, linkify: this.linkify, typographer: this.typographer, langPrefix: this.langPrefix, quotes: this.quotes, }) this.md.renderer.rules.table_open = () => `<table class="${this.tableClass}">\n` let defaultLinkRenderer = this.md.renderer.rules.link_open || function (tokens, idx, options, env, self) { return self.renderToken(tokens, idx, options) } this.md.renderer.rules.link_open = (tokens, idx, options, env, self) => { Object.keys(this.anchorAttributes).map((attribute) => { let aIndex = tokens[idx].attrIndex(attribute) let value = this.anchorAttributes[attribute] if (aIndex < 0) { tokens[idx].attrPush([attribute, value]) // add new attribute } else { tokens[idx].attrs[aIndex][1] = value } }) return defaultLinkRenderer(tokens, idx, options, env, self) } if (this.toc) { this.md.use(toc, { tocClassName: this.tocClass, tocFirstLevel: this.tocFirstLevel, tocLastLevel: this.tocLastLevelComputed, anchorLink: this.tocAnchorLink, anchorLinkSymbol: this.tocAnchorLinkSymbol, anchorLinkSpace: this.tocAnchorLinkSpace, anchorClassName: this.tocAnchorClass, anchorLinkSymbolClassName: this.tocAnchorLinkClass, tocCallback: (tocMarkdown, tocArray, tocHtml) => { if (tocHtml) { if (this.tocId && document.getElementById(this.tocId)) { document.getElementById(this.tocId).innerHTML = tocHtml } this.$emit('toc-rendered', tocHtml) } }, }) } let outHtml = this.show ? this.md.render( this.prerender(this.sourceData) ) : '' outHtml = this.postrender(outHtml); this.$emit('rendered', outHtml) return h( 'div', { domProps: { innerHTML: outHtml, }, }, ) }, beforeMount() { if (this.$slots.default) { this.sourceData = '' for (let slot of this.$slots.default) { this.sourceData += slot.text } } this.$watch('source', () => { this.sourceData = this.prerender(this.source) this.$forceUpdate() }) this.watches.forEach((v) => { this.$watch(v, () => { this.$forceUpdate() }) }) }, }