├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .github ├── FUNDING.yml └── workflows │ ├── codeql-analysis.yml │ └── publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── dist ├── vue-markdown.common.js ├── vue-markdown.common.js.LICENSE.txt ├── vue-markdown.js └── vue-markdown.js.LICENSE.txt ├── example ├── simple │ └── index.html └── webpack-simple │ ├── .babelrc │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.vue │ └── main.js │ └── webpack.config.js ├── index.d.ts ├── index.html ├── package.json ├── renovate.json ├── src ├── VueMarkdown.js └── build.js ├── webpack.common.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": ["@babel/plugin-transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "plugin:vue/essential", 8 | "standard" 9 | ], 10 | "parserOptions": { 11 | "ecmaVersion": 12, 12 | "sourceType": "module" 13 | }, 14 | "plugins": [ 15 | "vue" 16 | ], 17 | "rules": { 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [milindsingh] 4 | patreon: adapttive 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ next ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ next ] 20 | schedule: 21 | - cron: '21 19 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | jobs: 4 | publish: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - uses: actions/setup-node@v3 9 | with: 10 | node-version: 16 11 | - run: npm install 12 | - run: npm test 13 | - run: npm run build 14 | - uses: JS-DevTools/npm-publish@v1 15 | with: 16 | token: ${{ secrets.NPM_TOKEN }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | package-lock.json 35 | 36 | <<<<<<< HEAD 37 | # Ignore IDE files 38 | ======= 39 | # removing idea 40 | >>>>>>> 068da8e... readme updated 41 | .idea 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Chao Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-markdown 2 | 3 | [![npm](https://img.shields.io/npm/v/@adapttive/vue-markdown.svg?style=flat)](https://www.npmjs.com/package/vue-markdown@adapttive/) 4 | [![npm](https://img.shields.io/npm/l/@adapttive/vue-markdown.svg?style=flat)](https://www.npmjs.com/package/vue-markdown@adapttive/) 5 | [![npm](https://img.shields.io/david/adapttive/vue-markdown)](https://www.npmjs.com/package/@adapttive/vue-markdown) 6 | [![npm](https://img.shields.io/bundlephobia/min/@adapttive/vue-markdown)](https://www.npmjs.com/package/@adapttive/vue-markdown) 7 | [![npm](https://img.shields.io/npm/dt/@adapttive/vue-markdown.svg?style=flat)](https://www.npmjs.com/package/@adapttive/vue-markdown) 8 | 9 | > If you want vue-markdown for `vue1.X.X`, please checkout [vue-markdown1.X.X](https://github.com/adapttive/vue-markdown/tree/v1). 10 | 11 | A Powerful and Highspeed Markdown Parser for Vue. 12 | 13 | Quick start: `i am a ~~tast~~ **test**.` 14 | 15 | Supported Markdown Syntax: 16 | 17 | * [x] automatic table of contents 18 | * [x] table & class customize 19 | * [x] *SyntaxHighlighter 20 | * [x] definition list 21 | * [x] strikethrough 22 | * [x] GFM task list 23 | * [x] abbreviation 24 | * [x] superscript 25 | * [x] subscript 26 | * [x] footnote 27 | * [x] insert 28 | * [x] emoji 29 | * [x] mark 30 | * [x] *katex 31 | 32 | `*SyntaxHighlighter` work with [Prism](https://prismjs.com) recommend 33 | 34 | `*katex` need add [katex css](https://unpkg.com/katex/dist/katex.min.css). 35 | 36 | # Example 37 | 38 | [simple](https://github.com/adapttive/vue-markdown/blob/master/example/simple) 39 | 40 | [webpack-simple](https://github.com/adapttive/vue-markdown/blob/master/example/webpack-simple) 41 | 42 | [Live Demo](https://adapttive.github.io/vue-markdown/) 43 | 44 | # Installation 45 | 46 | ### Browser globals 47 | 48 | > The **dist** folder contains `vue-markdown.js` with the component exported in the `window.VueMarkdown` object. 49 | 50 | ```html 51 | 52 | i am a ~~tast~~ **test**. 53 | 54 | 55 | 56 | 62 | ``` 63 | 64 | ### NPM 65 | 66 | ```shell 67 | $ npm install --save @adapttive/vue-markdown 68 | ``` 69 | 70 | ### Yarn 71 | 72 | ```shell 73 | $ yarn add @adapttive/vue-markdown --save 74 | ``` 75 | 76 | ### Migrating from vue-markdown 2.3 77 | 78 | - You just need to replace the dependencies in `package.json`: 79 | 80 | ``` 81 | { 82 | "dependencies": { 83 | - "vue-markdown": "^2.2.4 84 | + "vue-markdown": "npm:@adapttive/vue-markdown@^X.X.X" 85 | } 86 | } 87 | ``` 88 | 89 | ## CommonJS 90 | 91 | ```js 92 | var VueMarkdown = require('@adapttive/vue-markdown'); 93 | 94 | new Vue({ 95 | components: { 96 | 'vue-markdown': VueMarkdown 97 | } 98 | }) 99 | ``` 100 | 101 | ## ES6 (Vue-CLI users) 102 | 103 | After installing via Yarn or NPM, use the following snippet in the script portion of the Vue component which you wish to render the Markdown. 104 | 105 | ```js 106 | import VueMarkdown from '@adapttive/vue-markdown' 107 | 108 | new Vue({ 109 | components: { 110 | VueMarkdown 111 | } 112 | }) 113 | ``` 114 | 115 | # Slots 116 | 117 | ```html 118 | this is the default slot 119 | ``` 120 | 121 | After setting up the middleware in your vue component above, using the embedded markdown is as easy as writing it between the `vue-markdown` tags. 122 | 123 | VueMarkdown has a default slot which is used to write the `markdown` source. 124 | 125 | TIP: The default slot only renders **once** at the beginning, and it will overwrite the prop of `source`! 126 | 127 | # Props 128 | 129 | | Prop | Type | Default | Describe | 130 | | ---------------------- | ------------------------ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | 131 | | watches | Array | `["source", "show", "toc"]` | HTML refresh automatically when the prop in this array changed | 132 | | source | String | `null` | the markdown source code | 133 | | show | Boolean | `true` | enable render to the default slot automatically | 134 | | html | Boolean | `true` | enable HTML syntax in source | 135 | | xhtml-out | Boolean | `true` | `

` => `
` | 136 | | breaks | Boolean | `true` | `\n` => `
` | 137 | | linkify | Boolean | `true` | autoconvert URL-like text to link | 138 | | emoji | Boolean | `true` | `:)` => `😃` | 139 | | typographer | Boolean | `true` | enable some language-neutral replacement and quotes beautification | 140 | | update-prism | Boolean | `true` | if true, vue-markdown will automatically call a re-render of all code blocks through Prism.js ([Using Prism.js](#using-prism.js)) | 141 | | lang-prefix | String | `language-` | CSS language prefix for fenced blocks | 142 | | quotes | String | `“”‘’` | use `“”‘’` for Chinese, `„“‚‘` for German, `«»„“` for Russian | 143 | | table-class | String | `table` | customize html class of the `` | 144 | | task-lists | Boolean | `true` | Makes GFM task lists mutable, `false` shows GFM as readonly checkboxes | 145 | | toc | Boolean | `false` | enable automatic table of contents | 146 | | toc-id | String | `undefined` | the HTML id to render TOC | 147 | | toc-class | String | `table` | customize html class of the `
\n')};var r,n=this.md.renderer.rules.link_open||function(t,e,r,n,o){return o.renderToken(t,e,r)};return this.md.renderer.rules.link_open=function(t,r,o,i,a){return Object.keys(e.anchorAttributes).map((function(n){var o=t[r].attrIndex(n),i=e.anchorAttributes[n];o<0?t[r].attrPush([n,i]):t[r].attrs[o][1]=i})),n(t,r,o,i,a)},this.toc&&this.md.use(L(),{tocClassName:this.tocClass,tocFirstLevel:this.tocFirstLevel,tocLastLevel:this.tocLastLevelComputed,anchorLink:this.tocAnchorLink,anchorLinkSymbol:this.tocAnchorLinkSymbol,anchorLinkSpace:this.tocAnchorLinkSpace,anchorLinkBefore:this.tocAnchorLinkBefore,anchorClassName:this.tocAnchorClass,anchorLinkSymbolClassName:this.tocAnchorLinkClass,tocCallback:function(t,r,n){n&&(e.tocId&&document.getElementById(e.tocId)&&(document.getElementById(e.tocId).innerHTML=n),e.$emit("toc-rendered",n))}}),this.show?(r=this.prerender(this.sourceData),r=this.inline?this.md.renderInline(r):this.md.render(r),r=this.postrender(r)):r="",this.$emit("rendered",r),this.updatePrism&&window.Prism&&this.$nextTick((function(){Prism.highlightAllUnder(e.$el)})),t("div",{domProps:{innerHTML:r}})},beforeMount:function(){var t=this;if(this.$slots.default){this.sourceData="";var e,r=function(t,e){var r;if("undefined"==typeof Symbol||null==t[Symbol.iterator]){if(Array.isArray(t)||(r=function(t,e){if(t){if("string"==typeof t)return x(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?x(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){r&&(t=r);var n=0,o=function(){};return{s:o,n:function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,s=!1;return{s:function(){r=t[Symbol.iterator]()},n:function(){var t=r.next();return a=t.done,t},e:function(t){s=!0,i=t},f:function(){try{a||null==r.return||r.return()}finally{if(s)throw i}}}}(this.$slots.default);try{for(r.s();!(e=r.n()).done;){var n=e.value;this.sourceData+=n.text}}catch(t){r.e(t)}finally{r.f()}}this.$watch("source",(function(){t.sourceData=t.prerender(t.source),t.$forceUpdate()})),this.watches.forEach((function(e){t.$watch(e,(function(){t.$forceUpdate()}))}))}}},446:e=>{e.exports=t},918:t=>{t.exports=a},822:t=>{t.exports=i},823:t=>{t.exports=e},362:t=>{t.exports=o},557:t=>{t.exports=s},50:t=>{t.exports=u},231:t=>{t.exports=r},897:t=>{t.exports=n},560:t=>{t.exports=l}},c={};function f(t){if(c[t])return c[t].exports;var e=c[t]={exports:{}};return d[t](e,e.exports,f),e.exports}return f.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return f.d(e,{a:e}),e},f.d=(t,e)=>{for(var r in e)f.o(e,r)&&!f.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},f.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),f.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},f(1)})()})); -------------------------------------------------------------------------------- /dist/vue-markdown.common.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * /** 3 | * * vue-markdown v4.0.0 4 | * * https://github.com/adapttive/vue-markdown 5 | * * MIT License 6 | * * / 7 | * 8 | */ 9 | -------------------------------------------------------------------------------- /dist/vue-markdown.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * /** 3 | * * vue-markdown v4.0.0 4 | * * https://github.com/adapttive/vue-markdown 5 | * * MIT License 6 | * * / 7 | * 8 | */ 9 | -------------------------------------------------------------------------------- /example/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | simple 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | The time of **NOW** is : 16 | 17 | [A link to a website](https://google.com) 18 | 19 | SyntaxHighlighter by highlight.js: 20 | 21 | ``` js 22 | function $initHighlight(block, cls) { 23 | try { 24 | if (cls.search(/\bno\-highlight\b/) != -1) 25 | return process(block, true, 0x0F) + 26 | ` class="${cls}"`; 27 | } catch (e) { 28 | /* handle exception */ 29 | } 30 | for (var i = 0 / 2; i < classes.length; i++) { 31 | if (checkCondition(classes[i]) === undefined) 32 | console.log('undefined'); 33 | } 34 | } 35 | ``` 36 | 37 | **Inline Math**: $\sqrt{3x-1}+(1+x)^2$ 38 | 39 | **Block Math** 40 | $$\begin{array}{c} 41 | 42 | \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & 43 | = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ 44 | 45 | \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ 46 | 47 | \nabla \cdot \vec{\mathbf{B}} & = 0 48 | 49 | \end{array}$$ 50 | 51 | 52 | ### Solar System Exploration, 1950s – 1960s 53 | 54 | - [ ] Mercury 55 | - [x] Venus 56 | - [x] Earth (Orbit/Moon) 57 | - [x] Mars 58 | - [ ] Jupiter 59 | - [ ] Saturn 60 | - [ ] Uranus 61 | - [ ] Neptune 62 | - [ ] Comet Haley 63 | 64 | @[external:code:github](https://github.com/milindsingh/magento2-grumphp/blob/2d9be8cf5c9da07256af5194370e9a9326e30881/module/grumphp.yml#L1-L134) 65 |
66 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/webpack-simple/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", { "modules": false }] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /example/webpack-simple/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /example/webpack-simple/README.md: -------------------------------------------------------------------------------- 1 | # webpack-simple 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | ``` 17 | 18 | For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader). 19 | -------------------------------------------------------------------------------- /example/webpack-simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | webpack-simple 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example/webpack-simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-simple", 3 | "description": "A Vue.js project", 4 | "author": "miaolz123 ", 5 | "private": true, 6 | "scripts": { 7 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --inline --hot", 8 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 9 | }, 10 | "dependencies": { 11 | "vue": "^2.0.1", 12 | "vue-markdown": "^2.2.4" 13 | }, 14 | "devDependencies": { 15 | "babel-core": "^6.0.0", 16 | "babel-loader": "^6.0.0", 17 | "babel-preset-es2015": "^6.0.0", 18 | "cross-env": "^3.0.0", 19 | "css-loader": "^0.25.0", 20 | "file-loader": "^0.9.0", 21 | "json-loader": "^0.5.4", 22 | "loglevel": "^1.4.1", 23 | "vue-loader": "^9.7.0", 24 | "webpack": "^2.1.0-beta.25", 25 | "webpack-dev-server": "^2.1.0-beta.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/webpack-simple/src/App.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 80 | -------------------------------------------------------------------------------- /example/webpack-simple/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(App) 7 | }) 8 | -------------------------------------------------------------------------------- /example/webpack-simple/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | entry: './src/main.js', 6 | output: { 7 | path: path.resolve(__dirname, './dist'), 8 | publicPath: '/dist/', 9 | filename: 'build.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.vue$/, 15 | loader: 'vue-loader', 16 | options: { 17 | // vue-loader options go here 18 | } 19 | }, 20 | { 21 | test: /\.json$/, 22 | loader: 'json-loader' 23 | }, 24 | { 25 | test: /\.js$/, 26 | loader: 'babel-loader', 27 | exclude: /node_modules/ 28 | }, 29 | { 30 | test: /\.(png|jpg|gif|svg)$/, 31 | loader: 'file-loader', 32 | options: { 33 | name: '[name].[ext]?[hash]' 34 | } 35 | } 36 | ] 37 | }, 38 | resolve: { 39 | alias: { 40 | 'vue$': 'vue/dist/vue' 41 | } 42 | }, 43 | devServer: { 44 | historyApiFallback: true, 45 | noInfo: true 46 | }, 47 | devtool: '#eval-source-map' 48 | } 49 | 50 | if (process.env.NODE_ENV === 'production') { 51 | module.exports.devtool = '#source-map' 52 | // http://vue-loader.vuejs.org/en/workflow/production.html 53 | module.exports.plugins = (module.exports.plugins || []).concat([ 54 | new webpack.DefinePlugin({ 55 | 'process.env': { 56 | NODE_ENV: '"production"' 57 | } 58 | }), 59 | new webpack.optimize.UglifyJsPlugin({ 60 | sourceMap: true, 61 | compress: { 62 | warnings: false 63 | } 64 | }), 65 | new webpack.LoaderOptionsPlugin({ 66 | minimize: true 67 | }) 68 | ]) 69 | } 70 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default interface VueMarkdown extends Vue { 4 | watches: Array 5 | plugins: Array 6 | source: string 7 | show: boolean 8 | highlight: boolean 9 | html: boolean 10 | xhtmlOut: boolean 11 | breaks: boolean 12 | linkify: boolean 13 | emoji: boolean 14 | typographer: boolean 15 | langPrefix: string 16 | quotes: string 17 | tableClass: string 18 | taskLists: boolean 19 | toc: boolean 20 | tocId: string 21 | tocClass: string 22 | tocFirstLevel: number 23 | tocLastLevel: number 24 | tocAnchorLink: boolean 25 | tocAnchorClass: string 26 | tocAnchorLinkSymbol: string 27 | tocAnchorLinkSpace: boolean 28 | externalPreview: boolean 29 | updatePrism: boolean 30 | tocAnchorLinkClass: string 31 | anchorAttributes: object 32 | prerender: Function 33 | postrender: Function 34 | } 35 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-markdown 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

VueMarkdown Live Demo

15 |
16 |
17 | 18 |
19 |
20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 |
41 | 263 |
264 |
265 | 269 |
270 |
271 |
272 | 273 | 274 | 275 | 276 | 277 | 301 | 302 | 303 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@adapttive/vue-markdown", 3 | "version": "4.0.2", 4 | "description": "A Powerful and High speed Markdown Parser for Vue", 5 | "main": "dist/vue-markdown.common.js", 6 | "types": "index.d.ts", 7 | "files": [ 8 | "dist/vue-markdown.js", 9 | "dist/vue-markdown.common.js", 10 | "src", 11 | "index.d.ts" 12 | ], 13 | "scripts": { 14 | "start": "webpack --config webpack.config.js", 15 | "build": "webpack --config webpack.common.js", 16 | "test": "echo true" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/adapttive/vue-markdown.git" 21 | }, 22 | "keywords": [ 23 | "vue", 24 | "markdown", 25 | "vue-markdown" 26 | ], 27 | "author": "milindsingh", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/adapttive/vue-markdown/issues" 31 | }, 32 | "homepage": "https://github.com/adapttive/vue-markdown#readme", 33 | "devDependencies": { 34 | "@babel/core": "^7.12.10", 35 | "@babel/plugin-transform-runtime": "^7.12.10", 36 | "@babel/preset-env": "^7.12.11", 37 | "babel-loader": "^8.2.2", 38 | "babel-plugin-transform-es2015-parameters": "^6.24.1", 39 | "babel-runtime": "^6.26.0", 40 | "css-loader": "^5.0.1", 41 | "eslint": "^7.15.0", 42 | "eslint-config-standard": "^16.0.2", 43 | "eslint-plugin-import": "^2.22.1", 44 | "eslint-plugin-node": "^11.1.0", 45 | "eslint-plugin-promise": "^4.2.1", 46 | "eslint-plugin-vue": "^7.3.0", 47 | "json-loader": "^0.5.7", 48 | "style-loader": "^2.0.0", 49 | "vue": "^2.6.12", 50 | "webpack": "^5.11.0", 51 | "webpack-cli": "^4.2.0" 52 | }, 53 | "dependencies": { 54 | "markdown-it": "^12.0.3", 55 | "markdown-it-abbr": "^1.0.4", 56 | "markdown-it-deflist": "^2.1.0", 57 | "markdown-it-emoji": "^2.0.0", 58 | "markdown-it-footnote": "^3.0.2", 59 | "markdown-it-ins": "^3.0.0", 60 | "markdown-it-mark": "^3.0.0", 61 | "markdown-it-sub": "^1.0.0", 62 | "markdown-it-sup": "^1.0.0", 63 | "markdown-it-toc-and-anchor": "^4.2.0" 64 | }, 65 | "directories": { 66 | "example": "example" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "packageRules": [ 6 | { 7 | "updateTypes": [ 8 | "minor", 9 | "patch" 10 | ], 11 | "automerge": true 12 | } 13 | ], 14 | "bumpVersion": "minor", 15 | "baseBranches": ["release"], 16 | "timezone": "Asia/Calcutta", 17 | "schedule": [ 18 | "after 10pm every weekday", 19 | "before 5am every weekday", 20 | "every weekend" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/VueMarkdown.js: -------------------------------------------------------------------------------- 1 | import markdownIt from 'markdown-it' 2 | import emoji from 'markdown-it-emoji' 3 | import subscript from 'markdown-it-sub' 4 | import superscript from 'markdown-it-sup' 5 | import footnote from 'markdown-it-footnote' 6 | import deflist from 'markdown-it-deflist' 7 | import abbreviation from 'markdown-it-abbr' 8 | import insert from 'markdown-it-ins' 9 | import mark from 'markdown-it-mark' 10 | import toc from 'markdown-it-toc-and-anchor' 11 | 12 | export default { 13 | md: new markdownIt(), 14 | 15 | template: '
', 16 | 17 | data () { 18 | return { 19 | sourceData: this.source 20 | } 21 | }, 22 | 23 | props: { 24 | watches: { 25 | type: Array, 26 | default: () => ['source', 'show', 'toc'] 27 | }, 28 | source: { 29 | type: String, 30 | default: '' 31 | }, 32 | show: { 33 | type: Boolean, 34 | default: true 35 | }, 36 | highlight: { 37 | type: Boolean, 38 | default: true 39 | }, 40 | html: { 41 | type: Boolean, 42 | default: true 43 | }, 44 | xhtmlOut: { 45 | type: Boolean, 46 | default: true 47 | }, 48 | breaks: { 49 | type: Boolean, 50 | default: true 51 | }, 52 | linkify: { 53 | type: Boolean, 54 | default: true 55 | }, 56 | emoji: { 57 | type: Boolean, 58 | default: true 59 | }, 60 | typographer: { 61 | type: Boolean, 62 | default: true 63 | }, 64 | langPrefix: { 65 | type: String, 66 | default: 'language-' 67 | }, 68 | quotes: { 69 | type: String, 70 | default: '“”‘’' 71 | }, 72 | tableClass: { 73 | type: String, 74 | default: 'table' 75 | }, 76 | taskLists: { 77 | type: Boolean, 78 | default: true 79 | }, 80 | toc: { 81 | type: Boolean, 82 | default: false 83 | }, 84 | tocId: { 85 | type: String 86 | }, 87 | tocClass: { 88 | type: String, 89 | default: 'table-of-contents' 90 | }, 91 | tocFirstLevel: { 92 | type: Number, 93 | default: 2 94 | }, 95 | tocLastLevel: { 96 | type: Number 97 | }, 98 | tocAnchorLink: { 99 | type: Boolean, 100 | default: true 101 | }, 102 | tocAnchorClass: { 103 | type: String, 104 | default: 'toc-anchor' 105 | }, 106 | tocAnchorLinkSymbol: { 107 | type: String, 108 | default: '#' 109 | }, 110 | tocAnchorLinkSpace: { 111 | type: Boolean, 112 | default: true 113 | }, 114 | tocAnchorLinkClass: { 115 | type: String, 116 | default: 'toc-anchor-link' 117 | }, 118 | tocAnchorLinkBefore: { 119 | type: Boolean, 120 | default: true 121 | }, 122 | anchorAttributes: { 123 | type: Object, 124 | default: () => ({}) 125 | }, 126 | prerender: { 127 | type: Function, 128 | default: (sourceData) => { return sourceData } 129 | }, 130 | postrender: { 131 | type: Function, 132 | default: (htmlData) => { return htmlData } 133 | }, 134 | updatePrism: { 135 | type: Boolean, 136 | default: false 137 | }, 138 | inline: { 139 | type: Boolean, 140 | default: false 141 | }, 142 | plugins: { 143 | type: Array, 144 | default: () => [] 145 | }, 146 | }, 147 | 148 | computed: { 149 | tocLastLevelComputed () { 150 | return this.tocLastLevel > this.tocFirstLevel ? this.tocLastLevel : this.tocFirstLevel + 1 151 | } 152 | }, 153 | 154 | render (createElement) { 155 | this.md = new markdownIt() 156 | .use(subscript) 157 | .use(superscript) 158 | .use(footnote) 159 | .use(deflist) 160 | .use(abbreviation) 161 | .use(insert) 162 | .use(mark); 163 | 164 | this.plugins.forEach(({ plugin, options = {} }) => { 165 | this.md.use(plugin, options); 166 | }); 167 | 168 | if (this.emoji) { 169 | this.md.use(emoji) 170 | } 171 | 172 | this.md.set({ 173 | html: this.html, 174 | xhtmlOut: this.xhtmlOut, 175 | breaks: this.breaks, 176 | linkify: this.linkify, 177 | typographer: this.typographer, 178 | langPrefix: this.langPrefix, 179 | quotes: this.quotes 180 | }) 181 | this.md.renderer.rules.table_open = () => `
\n` 182 | const defaultLinkRenderer = this.md.renderer.rules.link_open || 183 | function (tokens, idx, options, env, self) { 184 | return self.renderToken(tokens, idx, options) 185 | } 186 | this.md.renderer.rules.link_open = (tokens, idx, options, env, self) => { 187 | Object.keys(this.anchorAttributes).map((attribute) => { 188 | const aIndex = tokens[idx].attrIndex(attribute) 189 | const value = this.anchorAttributes[attribute] 190 | if (aIndex < 0) { 191 | tokens[idx].attrPush([attribute, value]) // add new attribute 192 | } else { 193 | tokens[idx].attrs[aIndex][1] = value 194 | } 195 | }) 196 | return defaultLinkRenderer(tokens, idx, options, env, self) 197 | } 198 | 199 | if (this.toc) { 200 | this.md.use(toc, { 201 | tocClassName: this.tocClass, 202 | tocFirstLevel: this.tocFirstLevel, 203 | tocLastLevel: this.tocLastLevelComputed, 204 | anchorLink: this.tocAnchorLink, 205 | anchorLinkSymbol: this.tocAnchorLinkSymbol, 206 | anchorLinkSpace: this.tocAnchorLinkSpace, 207 | anchorLinkBefore: this.tocAnchorLinkBefore, 208 | anchorClassName: this.tocAnchorClass, 209 | anchorLinkSymbolClassName: this.tocAnchorLinkClass, 210 | tocCallback: (tocMarkdown, tocArray, tocHtml) => { 211 | if (tocHtml) { 212 | if (this.tocId && document.getElementById(this.tocId)) { 213 | document.getElementById(this.tocId).innerHTML = tocHtml 214 | } 215 | 216 | this.$emit('toc-rendered', tocHtml) 217 | } 218 | } 219 | }) 220 | } 221 | 222 | let outHtml 223 | if (this.show) { 224 | outHtml = this.prerender(this.sourceData) 225 | if (this.inline) { 226 | outHtml = this.md.renderInline(outHtml) 227 | } else { 228 | outHtml = this.md.render(outHtml) 229 | } 230 | outHtml = this.postrender(outHtml) 231 | } else { 232 | outHtml = '' 233 | } 234 | 235 | this.$emit('rendered', outHtml) 236 | 237 | if (this.updatePrism && window.Prism) { 238 | this.$nextTick(() => { 239 | Prism.highlightAllUnder(this.$el) 240 | }) 241 | } 242 | 243 | return createElement( 244 | 'div', { 245 | domProps: { 246 | innerHTML: outHtml 247 | } 248 | } 249 | ) 250 | }, 251 | 252 | beforeMount () { 253 | if (this.$slots.default) { 254 | this.sourceData = '' 255 | for (const slot of this.$slots.default) { 256 | this.sourceData += slot.text 257 | } 258 | } 259 | 260 | this.$watch('source', () => { 261 | this.sourceData = this.prerender(this.source) 262 | this.$forceUpdate() 263 | }) 264 | 265 | this.watches.forEach((v) => { 266 | this.$watch(v, () => { 267 | this.$forceUpdate() 268 | }) 269 | }) 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/build.js: -------------------------------------------------------------------------------- 1 | import VueMarkdownComponent from './VueMarkdown' 2 | 3 | export function install (Vue, options) { 4 | const _options = Object.assign({ 5 | tag: 'vue-markdown' 6 | }, options) 7 | 8 | Vue.component(_options.tag, VueMarkdownComponent) 9 | } 10 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const version = require("./package.json").version; 3 | const banner = 4 | "/**\n" + 5 | " * vue-markdown v" + version + "\n" + 6 | " * https://github.com/adapttive/vue-markdown\n" + 7 | " * MIT License\n" + 8 | " */\n"; 9 | 10 | module.exports = { 11 | entry: "./src/VueMarkdown.js", 12 | target: "node", 13 | output: { 14 | path: __dirname + "/dist", 15 | filename: "vue-markdown.common.js", 16 | library: "VueMarkdown", 17 | libraryTarget: "umd" 18 | }, 19 | externals: /^[^.]/, 20 | plugins: [ 21 | new webpack.BannerPlugin(banner, { raw: true }) 22 | ], 23 | module: { 24 | rules: [{ 25 | test: /\.vue$/, 26 | use: "vue" 27 | }, { 28 | test: /\.js$/, 29 | use: 'babel-loader', 30 | exclude: /node_modules/ 31 | }, { 32 | test: /\.css$/, 33 | use: "style!css" 34 | }] 35 | }, 36 | } 37 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const version = require("./package.json").version; 3 | const banner = 4 | "/**\n" + 5 | " * vue-markdown v" + version + "\n" + 6 | " * https://github.com/adapttive/vue-markdown\n" + 7 | " * MIT License\n" + 8 | " */\n"; 9 | 10 | module.exports = { 11 | entry: './src/build.js', 12 | output: { 13 | path: __dirname + "/dist", 14 | filename: 'vue-markdown.js', 15 | library: 'VueMarkdown', 16 | libraryTarget: 'umd' 17 | }, 18 | plugins: [ 19 | new webpack.BannerPlugin(banner, {raw: true}) 20 | ], 21 | module: { 22 | rules: [{ 23 | test: /\.vue$/, 24 | use: 'vue' 25 | }, { 26 | test: /\.css$/, 27 | use: "style!css" 28 | }, { 29 | test: /\.js$/, 30 | use: 'babel-loader', 31 | exclude: /node_modules/ 32 | }] 33 | }, 34 | } 35 | --------------------------------------------------------------------------------