├── .babelrc
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── LICENSE
├── README.EN.md
├── README.md
├── dist
├── index.js
└── static
│ └── fonts
│ ├── iconfont.0f693eba.eot
│ ├── iconfont.35e220a6.svg
│ ├── iconfont.a614fc0f.ttf
│ └── iconfont.fe07082d.woff
├── doc
└── UPDATELOG.md
├── example
├── globals.d.ts
├── index.html
├── index.scss
├── index.tsx
├── src
│ ├── app.module.scss
│ ├── app.module.scss.d.ts
│ └── app.tsx
└── static
│ └── help.md
├── index.d.ts
├── package.json
├── src
├── components
│ ├── toolbar_left.tsx
│ └── toolbar_right.tsx
├── index.tsx
└── lib
│ ├── css
│ ├── index.scss
│ └── index.scss.d.ts
│ ├── fonts
│ ├── iconfont.css
│ ├── iconfont.css.d.ts
│ ├── iconfont.eot
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ └── iconfont.woff2
│ ├── helpers
│ ├── function.ts
│ ├── highlight.ts
│ ├── keydownListen.ts
│ └── marked.ts
│ ├── index.ts
│ └── lang
│ ├── en
│ └── index.json
│ └── zh-CN
│ └── index.json
├── tsconfig.json
└── webpack
├── webpack.base.config.js
├── webpack.dev.config.js
├── webpack.dist.config.js
└── webpack.prod.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-react"
4 | ],
5 | "plugins": [
6 | "@babel/plugin-proposal-class-properties",
7 | "@babel/plugin-transform-modules-commonjs"
8 | ]
9 | }
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['eslint-config-for/react', 'eslint-config-for/typescript']
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | playground/
3 | .DS_Store
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // 一行最多 100 字符
3 | printWidth: 100,
4 | // 使用 2 个空格缩进
5 | tabWidth: 2,
6 | // 不使用缩进符,而使用空格
7 | useTabs: false,
8 | // 行尾需要有分号
9 | semi: false,
10 | // 使用单引号
11 | singleQuote: true,
12 | // jsx 不使用单引号,而使用双引号
13 | jsxSingleQuote: false,
14 | // 末尾不需要逗号
15 | trailingComma: 'none',
16 | // 大括号内的首尾需要空格
17 | bracketSpacing: true,
18 | // jsx 标签的反尖括号需要换行
19 | jsxBracketSameLine: false,
20 | // 箭头函数,只有一个参数的时候,也需要括号
21 | arrowParens: 'always',
22 | // 每个文件格式化的范围是文件的全部内容
23 | rangeStart: 0,
24 | rangeEnd: Infinity,
25 | // 不需要写文件开头的 @prettier
26 | requirePragma: false,
27 | // 不需要自动在文件开头插入 @prettier
28 | insertPragma: false,
29 | // 使用默认的折行标准
30 | proseWrap: 'preserve',
31 | // 根据显示样式决定 html 要不要折行
32 | htmlWhitespaceSensitivity: 'css',
33 | // 换行符使用 lf
34 | endOfLine: 'lf'
35 | };
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 kkfor
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.
--------------------------------------------------------------------------------
/README.EN.md:
--------------------------------------------------------------------------------
1 | # for-editor
2 |
3 | > for-editor-A markdown editor based on React
4 |
5 | - [demo](https://md.kkfor.com)
6 | - [github](https://github.com/kkfor/for-editor)
7 |
8 | ### Install
9 |
10 | ```js
11 | npm install for-editor -S
12 | ```
13 |
14 | ### Use
15 |
16 | ```js
17 | import React, { Component } from 'react'
18 | import ReactDOM from 'react-dom'
19 | import Editor from 'for-editor'
20 |
21 | class App extends Component {
22 | constructor() {
23 | super()
24 | this.state = {
25 | value: ''
26 | }
27 | }
28 |
29 | handleChange(value) {
30 | this.setState({
31 | value
32 | })
33 | }
34 |
35 | render() {
36 | const { value } = this.state
37 | return this.handleChange()} />
38 | }
39 | }
40 |
41 | ReactDOM.render(, document.getElementById('root'))
42 | ```
43 |
44 | ### Api
45 |
46 | #### props
47 |
48 | | name | type | default | description |
49 | | ----------- | ------- | --------------------------- | ------------------------------------------------------------------------------------------------------ |
50 | | value | String | - | value |
51 | | language | String | zh-CN | Language switch, zh-CN: Simplified Chinese, en: English |
52 | | placeholder | String | Begin editing... | The default prompt text when the textarea is empty |
53 | | lineNum | Boolean | true | Show lineNum |
54 | | style | Object | - | editor styles |
55 | | height | String | 600px | editor height |
56 | | preview | Boolean | false | preview switch |
57 | | expand | Boolean | false | fullscreen switch |
58 | | subfield | Boolean | false | true: Double columns - Edit preview same screen(notice: preview: true), Single Columns - otherwise not |
59 | | toolbar | Object | As in the following example | toolbars |
60 |
61 | ```js
62 | /*
63 | The default toolbar properties are all true,
64 | You can customize the object to cover them.
65 | eg: {
66 | h1: true,
67 | code: true,
68 | preview: true,
69 | }
70 | At this point, the toolbar only displays the three function keys.
71 | notice: Toolbar will be hidden when empty object.
72 | */
73 |
74 | toolbar: {
75 | h1: true,
76 | h2: true,
77 | h3: true,
78 | h4: true,
79 | img: true,
80 | link: true,
81 | code: true,
82 | preview: true,
83 | expand: true,
84 | /* v0.0.9 */
85 | undo: true,
86 | redo: true,
87 | save: true,
88 | /* v0.2.3 */
89 | subfield: true
90 | }
91 | ```
92 |
93 | #### events
94 |
95 | | name | params | default | description |
96 | | -------- | ------------- | ------- | ------------------------------------------- |
97 | | onChange | String: value | - | Edit area change callback event |
98 | | onSave | String: value | - | Ctrl+s and click save button callback event |
99 | | addImg | File: file | - | upload image callback event |
100 |
101 | ##### upload image
102 |
103 | ```js
104 | class App extends Component {
105 | constructor() {
106 | super()
107 | this.state = {
108 | value: ''
109 | }
110 | this.$vm = React.createRef()
111 | }
112 |
113 | handleChange(value) {
114 | this.setState({
115 | value
116 | })
117 | }
118 |
119 | addImg($file) {
120 | this.$vm.current.$img2Url($file.name, 'file_url')
121 | console.log($file)
122 | }
123 |
124 | render() {
125 | const { value } = this.state
126 |
127 | return (
128 | this.addImg($file)}
132 | onChange={(value) => this.handleChange(value)}
133 | />
134 | )
135 | }
136 | }
137 | ```
138 |
139 | #### hot key
140 |
141 | | name | description |
142 | | ------ | ----------- |
143 | | tab | two space |
144 | | ctrl+s | save |
145 | | ctrl+z | undo |
146 | | ctrl+y | redo |
147 |
148 | ### Update
149 |
150 | - [Update Log](./doc/UPDATELOG.md)
151 |
152 | # Licence
153 |
154 | for-editor is [MIT Licence](./LICENSE).
155 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # for-editor
2 |
3 | > for-editor 是一个基于 react 的 markdown 语法编辑器
4 |
5 | ### [English Documents](./README.EN.md)
6 |
7 | - [demo](https://md.kkfor.com)
8 | - [github](https://github.com/kkfor/for-editor)
9 |
10 | ### 安装
11 |
12 | ```js
13 | npm install for-editor -S
14 | ```
15 |
16 | ### 使用
17 |
18 | ```js
19 | import React, { Component } from 'react'
20 | import ReactDOM from 'react-dom'
21 | import Editor from 'for-editor'
22 |
23 | class App extends Component {
24 | constructor() {
25 | super()
26 | this.state = {
27 | value: ''
28 | }
29 | }
30 |
31 | handleChange(value) {
32 | this.setState({
33 | value
34 | })
35 | }
36 |
37 | render() {
38 | const { value } = this.state
39 | return this.handleChange()} />
40 | }
41 | }
42 |
43 | ReactDOM.render(, document.getElementById('root'))
44 | ```
45 |
46 | ### Api
47 |
48 | #### 属性
49 |
50 | | name | type | default | description |
51 | | ----------- | ------- | ----------- | ---------------------------------- |
52 | | value | String | - | 输入框内容 |
53 | | placeholder | String | 开始编辑... | 占位文本 |
54 | | lineNum | Boolean | true | 是否显示行号 |
55 | | style | Object | - | 编辑器样式 |
56 | | height | String | 600px | 编辑器高度 |
57 | | preview | Boolean | false | 预览模式 |
58 | | expand | Boolean | false | 全屏模式 |
59 | | subfield | Boolean | false | 双栏模式(预览模式激活下有效) |
60 | | language | String | zh-CN | 语言(支持 zh-CN:中文简体, en:英文) |
61 | | toolbar | Object | 如下 | 自定义工具栏 |
62 |
63 | ```js
64 | /*
65 | 默认工具栏按钮全部开启, 传入自定义对象
66 | 例如: {
67 | h1: true, // h1
68 | code: true, // 代码块
69 | preview: true, // 预览
70 | }
71 | 此时, 仅仅显示此三个功能键
72 | 注:传入空对象则不显示工具栏
73 | */
74 |
75 | toolbar: {
76 | h1: true, // h1
77 | h2: true, // h2
78 | h3: true, // h3
79 | h4: true, // h4
80 | img: true, // 图片
81 | link: true, // 链接
82 | code: true, // 代码块
83 | preview: true, // 预览
84 | expand: true, // 全屏
85 | /* v0.0.9 */
86 | undo: true, // 撤销
87 | redo: true, // 重做
88 | save: true, // 保存
89 | /* v0.2.3 */
90 | subfield: true, // 单双栏模式
91 | }
92 | ```
93 |
94 | #### 事件
95 |
96 | | name | params 参数 | default | description |
97 | | -------- | ------------- | ------- | -------------- |
98 | | onChange | String: value | - | 内容改变时回调 |
99 | | onSave | String: value | - | 保存时回调 |
100 | | addImg | File: file | - | 添加图片时回调 |
101 |
102 | ##### 图片上传
103 |
104 | ```js
105 | class App extends Component {
106 | constructor() {
107 | super()
108 | this.state = {
109 | value: '',
110 | }
111 | this.$vm = React.createRef()
112 | }
113 |
114 | handleChange(value) {
115 | this.setState({
116 | value
117 | })
118 | }
119 |
120 | addImg($file) {
121 | this.$vm.current.$img2Url($file.name, 'file_url')
122 | console.log($file)
123 | }
124 |
125 | render() {
126 | const { value } = this.state
127 |
128 | return (
129 | this.addImg($file)}
133 | onChange={value => this.handleChange(value)}
134 | />
135 | )
136 | }
137 | }
138 | ```
139 |
140 | #### 快捷键
141 |
142 | | name | description |
143 | | ------ | ------------ |
144 | | tab | 两个空格缩进 |
145 | | ctrl+s | 保存 |
146 | | ctrl+z | 上一步 |
147 | | ctrl+y | 下一步 |
148 |
149 | ### 更新
150 |
151 | - [Update Log](./doc/UPDATELOG.md)
152 |
153 | ### Licence
154 |
155 | for-editor is [MIT Licence](./LICENSE).
156 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | !function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var n=t();for(var r in n)("object"==typeof exports?exports:e)[r]=n[r]}}(window,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=5)}([function(e,t,n){"use strict";e.exports=n(6)},function(e,t,n){"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var n=function(e,t){var n=e[1]||"",r=e[3];if(!r)return n;if(t&&"function"==typeof btoa){var o=(a=r,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(a))))+" */"),i=r.sources.map(function(e){return"/*# sourceURL="+r.sourceRoot+e+" */"});return[n].concat(i).concat([o]).join("\n")}var a;return[n].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n}).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var r={},o=0;o=0&&u.splice(t,1)}function m(e){var t=document.createElement("style");if(void 0===e.attrs.type&&(e.attrs.type="text/css"),void 0===e.attrs.nonce){var r=function(){0;return n.nc}();r&&(e.attrs.nonce=r)}return b(t,e.attrs),h(e,t),t}function b(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function v(e,t){var n,r,o,i;if(t.transform&&e.css){if(!(i="function"==typeof t.transform?t.transform(e.css):t.transform.default(e.css)))return function(){};e.css=i}if(t.singleton){var a=c++;n=l||(l=m(t)),r=x.bind(null,n,a,!1),o=x.bind(null,n,a,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return void 0===e.attrs.type&&(e.attrs.type="text/css"),e.attrs.rel="stylesheet",b(t,e.attrs),h(e,t),t}(t),r=function(e,t,n){var r=n.css,o=n.sourceMap,i=void 0===t.convertToAbsoluteUrls&&o;(t.convertToAbsoluteUrls||i)&&(r=f(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),s=e.href;e.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,t),o=function(){g(n),n.href&&URL.revokeObjectURL(n.href)}):(n=m(t),r=function(e,t){var n=t.css,r=t.media;r&&e.setAttribute("media",r);if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){g(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=a()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=p(e,t);return d(n,t),function(e){for(var r=[],o=0;o=0?e:"zh-CN";n.setState({words:g.CONFIG.language[t]})},n.handleChange=function(e){var t=e.target.value;n.props.onChange(t)},n.saveHistory=function(e){var t=n.state,r=t.history,o=t.historyIndex;r.splice(o+1,r.length),r.length>=20&&r.shift(),o=r.length,r.push(e),n.setState({history:r,historyIndex:o})},n.save=function(){n.props.onSave(n.$vm.current.value)},n.undo=function(){var e=n.state,t=e.history,r=e.historyIndex;(r-=1)<0||(n.props.onChange(t[r]),n.setState({historyIndex:r}))},n.redo=function(){var e=n.state,t=e.history,r=e.historyIndex;(r+=1)>=t.length||(n.props.onChange(t[r]),n.setState({historyIndex:r}))},n.toolBarLeftClick=function(e){var t=n.state.words,r={h1:{prefix:"# ",subfix:"",str:t.h1},h2:{prefix:"## ",subfix:"",str:t.h2},h3:{prefix:"### ",subfix:"",str:t.h3},h4:{prefix:"#### ",subfix:"",str:t.h4},img:{prefix:"",str:"url"},link:{prefix:"[title](",subfix:")",str:"url"},code:{prefix:"```",subfix:"\n\n```",str:"language"},tab:{prefix:" ",subfix:"",str:""}};if(r.hasOwnProperty(e)&&n.$vm.current){var o=h.insertText(n.$vm.current,r[e]);n.props.onChange(o)}var i={undo:n.undo,redo:n.redo,save:n.save};i.hasOwnProperty(e)&&i[e]()},n.addImg=function(e,t){n.props.addImg(e,t)},n.$img2Url=function(e,t){var r=h.insertText(n.$vm.current,{prefix:"",subfix:"",str:""});n.props.onChange(r)},n.toolBarRightClick=function(e){var t={preview:function(){n.setState({preview:!n.state.preview})},expand:function(){n.setState({expand:!n.state.expand})},subfield:function(){var e=n.state,t=e.preview,r=e.subfield;t?r?n.setState({subfield:!1,preview:!1}):n.setState({subfield:!0}):r?n.setState({subfield:!1}):n.setState({preview:!0,subfield:!0})}};t.hasOwnProperty(e)&&t[e]()},n.focusText=function(){n.$vm.current.focus()},n.handleScoll=function(e){var t=n.$blockEdit.current.scrollTop/(n.$scrollEdit.current.scrollHeight-e.currentTarget.offsetHeight);n.$blockPreview.current.scrollTop=(n.$scrollPreview.current.scrollHeight-n.$blockPreview.current.offsetHeight)*t},n.state={preview:t.preview,expand:t.expand,subfield:t.subfield,history:[],historyIndex:0,lineIndex:1,value:t.value,words:{}},n}return o(t,e),t.prototype.componentDidMount=function(){var e=this,t=this.props.value;f.default(this.$vm.current,function(t){e.toolBarLeftClick(t)}),this.reLineNum(t),this.initLanguage()},t.prototype.componentDidUpdate=function(e){var t=this,n=this.props,r=n.value,o=n.preview,i=n.expand,a=n.subfield,s=this.state,l=s.history,c=s.historyIndex;e.value!==r&&this.reLineNum(r),r!==l[c]&&(window.clearTimeout(this.currentTimeout),this.currentTimeout=window.setTimeout(function(){t.saveHistory(r)},500)),a!==e.subfield&&this.state.subfield!==a&&this.setState({subfield:a}),o!==e.preview&&this.state.preview!==o&&this.setState({preview:o}),i!==e.expand&&this.state.expand!==i&&this.setState({expand:i})},t.prototype.reLineNum=function(e){var t=e?e.split("\n").length:1;this.setState({lineIndex:t})},t.prototype.render=function(){var e=this.state,t=e.preview,n=e.expand,r=e.subfield,o=e.lineIndex,a=e.words,s=this.props,f=s.value,h=s.placeholder,g=s.fontSize,m=s.disabled,b=s.height,v=s.style,y=s.toolbar,w=c.default({"for-editor-edit":!0,"for-panel":!0,"for-active":t&&r,"for-edit-preview":t&&!r}),x=c.default({"for-panel":!0,"for-editor-preview":!0,"for-active":t&&r}),k=c.default({"for-container":!0,"for-fullscreen":n}),_=c.default({"for-line-num":!0,hidden:!this.props.lineNum});return l.createElement("div",{className:k,style:i({height:b},v)},Boolean(Object.keys(y).length)&&l.createElement("div",{className:"for-toolbar"},l.createElement(d.default,i({toolbar:y,words:a,onClick:this.toolBarLeftClick,addImg:this.addImg},this.props)),l.createElement(p.default,{toolbar:y,words:a,preview:t,expand:n,subfield:r,onClick:this.toolBarRightClick})),l.createElement("div",{className:"for-editor",style:{fontSize:g}},l.createElement("div",{className:w,ref:this.$blockEdit,onScroll:this.handleScoll,onClick:this.focusText},l.createElement("div",{className:"for-editor-block",ref:this.$scrollEdit},function(){for(var e=[],t=0;tT.length&&T.push(e)}function L(e,t,n){return null==e?0:function e(t,n,r,o){var s=typeof t;"undefined"!==s&&"boolean"!==s||(t=null);var l=!1;if(null===t)l=!0;else switch(s){case"string":case"number":l=!0;break;case"object":switch(t.$$typeof){case i:case a:l=!0}}if(l)return r(o,t,""===n?"."+D(t,0):n),1;if(l=0,n=""===n?".":n+":",Array.isArray(t))for(var c=0;c"+e+"
"},a.link=function(e,t,n){return""+n+""},t.default=function(e){return"string"!=typeof e?"":o.default(e,{renderer:a})}},function(e,t,n){(function(t){!function(t){"use strict";var n={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:m,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,nptable:m,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:m,lheading:/^([^\n]+)\n {0,3}(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,text:/^[^\n]+/};function r(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||x.defaults,this.rules=n.normal,this.options.pedantic?this.rules=n.pedantic:this.options.gfm&&(this.options.tables?this.rules=n.tables:this.rules=n.gfm)}n._label=/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,n._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/,n.def=d(n.def).replace("label",n._label).replace("title",n._title).getRegex(),n.bullet=/(?:[*+-]|\d{1,9}\.)/,n.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,n.item=d(n.item,"gm").replace(/bull/g,n.bullet).getRegex(),n.list=d(n.list).replace(/bull/g,n.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+n.def.source+")").getRegex(),n._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",n._comment=//,n.html=d(n.html,"i").replace("comment",n._comment).replace("tag",n._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),n.paragraph=d(n.paragraph).replace("hr",n.hr).replace("heading",n.heading).replace("lheading",n.lheading).replace("tag",n._tag).getRegex(),n.blockquote=d(n.blockquote).replace("paragraph",n.paragraph).getRegex(),n.normal=b({},n),n.gfm=b({},n.normal,{fences:/^ {0,3}(`{3,}|~{3,})([^`\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),n.gfm.paragraph=d(n.paragraph).replace("(?!","(?!"+n.gfm.fences.source.replace("\\1","\\2")+"|"+n.list.source.replace("\\1","\\3")+"|").getRegex(),n.tables=b({},n.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),n.pedantic=b({},n.normal,{html:d("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?\\1> *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",n._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),r.rules=n,r.lex=function(e,t){return new r(t).lex(e)},r.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},r.prototype.token=function(e,t){var r,o,i,a,s,l,c,u,f,d,p,h,g,m,b,w;for(e=e.replace(/^ +$/gm,"");e;)if((i=this.rules.newline.exec(e))&&(e=e.substring(i[0].length),i[0].length>1&&this.tokens.push({type:"space"})),i=this.rules.code.exec(e)){var x=this.tokens[this.tokens.length-1];e=e.substring(i[0].length),x&&"paragraph"===x.type?x.text+="\n"+i[0].trimRight():(i=i[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",codeBlockStyle:"indented",text:this.options.pedantic?i:y(i,"\n")}))}else if(i=this.rules.fences.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"code",lang:i[2]?i[2].trim():i[2],text:i[3]||""});else if(i=this.rules.heading.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:i[1].length,text:i[2]});else if((i=this.rules.nptable.exec(e))&&(l={type:"table",header:v(i[1].replace(/^ *| *\| *$/g,"")),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3]?i[3].replace(/\n$/,"").split("\n"):[]}).header.length===l.align.length){for(e=e.substring(i[0].length),p=0;p ?/gm,""),this.token(i,t),this.tokens.push({type:"blockquote_end"});else if(i=this.rules.list.exec(e)){for(e=e.substring(i[0].length),c={type:"list_start",ordered:m=(a=i[2]).length>1,start:m?+a:"",loose:!1},this.tokens.push(c),u=[],r=!1,g=(i=i[0].match(this.rules.item)).length,p=0;p1?1===s.length:s.length>1||this.options.smartLists&&s!==a)&&(e=i.slice(p+1).join("\n")+e,p=g-1)),o=r||/\n\n(?!\s*$)/.test(l),p!==g-1&&(r="\n"===l.charAt(l.length-1),o||(o=r)),o&&(c.loose=!0),w=void 0,(b=/^\[[ xX]\] /.test(l))&&(w=" "!==l[1],l=l.replace(/^\[[ xX]\] +/,"")),f={type:"list_item_start",task:b,checked:w,loose:o},u.push(f),this.tokens.push(f),this.token(l,!1),this.tokens.push({type:"list_item_end"});if(c.loose)for(g=u.length,p=0;p?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:m,tag:"^comment|^[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:m,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~",o.em=d(o.em).replace(/punctuation/g,o._punctuation).getRegex(),o._escapes=/\\([!"#$%&'()*+,\-.\/:;<=>?@\[\]\\^_`{|}~])/g,o._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,o._email=/[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,o.autolink=d(o.autolink).replace("scheme",o._scheme).replace("email",o._email).getRegex(),o._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,o.tag=d(o.tag).replace("comment",n._comment).replace("attribute",o._attribute).getRegex(),o._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|`(?!`)|[^\[\]\\`])*?/,o._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*)/,o._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,o.link=d(o.link).replace("label",o._label).replace("href",o._href).replace("title",o._title).getRegex(),o.reflink=d(o.reflink).replace("label",o._label).getRegex(),o.normal=b({},o),o.pedantic=b({},o.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:d(/^!?\[(label)\]\((.*?)\)/).replace("label",o._label).getRegex(),reflink:d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",o._label).getRegex()}),o.gfm=b({},o.normal,{escape:d(o.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\/i.test(a[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(a[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(a[0])&&(this.inRawBlock=!1),e=e.substring(a[0].length),l+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):u(a[0]):a[0];else if(a=this.rules.link.exec(e)){var c=w(a[2],"()");if(c>-1){var f=a[0].length-(a[2].length-c)-(a[3]||"").length;a[2]=a[2].substring(0,c),a[0]=a[0].substring(0,f).trim(),a[3]=""}e=e.substring(a[0].length),this.inLink=!0,r=a[2],this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r))?(r=t[1],o=t[3]):o="":o=a[3]?a[3].slice(1,-1):"",r=r.trim().replace(/^<([\s\S]*)>$/,"$1"),l+=this.outputLink(a,{href:i.escapes(r),title:i.escapes(o)}),this.inLink=!1}else if((a=this.rules.reflink.exec(e))||(a=this.rules.nolink.exec(e))){if(e=e.substring(a[0].length),t=(a[2]||a[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){l+=a[0].charAt(0),e=a[0].substring(1)+e;continue}this.inLink=!0,l+=this.outputLink(a,t),this.inLink=!1}else if(a=this.rules.strong.exec(e))e=e.substring(a[0].length),l+=this.renderer.strong(this.output(a[4]||a[3]||a[2]||a[1]));else if(a=this.rules.em.exec(e))e=e.substring(a[0].length),l+=this.renderer.em(this.output(a[6]||a[5]||a[4]||a[3]||a[2]||a[1]));else if(a=this.rules.code.exec(e))e=e.substring(a[0].length),l+=this.renderer.codespan(u(a[2].trim(),!0));else if(a=this.rules.br.exec(e))e=e.substring(a[0].length),l+=this.renderer.br();else if(a=this.rules.del.exec(e))e=e.substring(a[0].length),l+=this.renderer.del(this.output(a[1]));else if(a=this.rules.autolink.exec(e))e=e.substring(a[0].length),r="@"===a[2]?"mailto:"+(n=u(this.mangle(a[1]))):n=u(a[1]),l+=this.renderer.link(r,null,n);else if(this.inLink||!(a=this.rules.url.exec(e))){if(a=this.rules.text.exec(e))e=e.substring(a[0].length),this.inRawBlock?l+=this.renderer.text(a[0]):l+=this.renderer.text(u(this.smartypants(a[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else{if("@"===a[2])r="mailto:"+(n=u(a[0]));else{do{s=a[0],a[0]=this.rules._backpedal.exec(a[0])[0]}while(s!==a[0]);n=u(a[0]),r="www."===a[1]?"http://"+n:n}e=e.substring(a[0].length),l+=this.renderer.link(r,null,n)}return l},i.escapes=function(e){return e?e.replace(i.rules._escapes,"$1"):e},i.prototype.outputLink=function(e,t){var n=t.href,r=t.title?u(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,u(e[1]))},i.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014\/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014\/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},i.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,o=0;o.5&&(t="x"+t.toString(16)),n+=""+t+";";return n},a.prototype.code=function(e,t,n){var r=(t||"").match(/\S*/)[0];if(this.options.highlight){var o=this.options.highlight(e,r);null!=o&&o!==e&&(n=!0,e=o)}return r?''+(n?e:u(e,!0))+"
\n":""+(n?e:u(e,!0))+"
"},a.prototype.blockquote=function(e){return"\n"+e+"
\n"},a.prototype.html=function(e){return e},a.prototype.heading=function(e,t,n,r){return this.options.headerIds?"\n":""+e+"\n"},a.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},a.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+""+r+">\n"},a.prototype.listitem=function(e){return""+e+"\n"},a.prototype.checkbox=function(e){return" "},a.prototype.paragraph=function(e){return""+e+"
\n"},a.prototype.table=function(e,t){return t&&(t=""+t+""),"\n"},a.prototype.tablerow=function(e){return"\n"+e+"
\n"},a.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+""+n+">\n"},a.prototype.strong=function(e){return""+e+""},a.prototype.em=function(e){return""+e+""},a.prototype.codespan=function(e){return""+e+"
"},a.prototype.br=function(){return this.options.xhtml?"
":"
"},a.prototype.del=function(e){return""+e+""},a.prototype.link=function(e,t,n){if(null===(e=p(this.options.sanitize,this.options.baseUrl,e)))return n;var r='"+n+""},a.prototype.image=function(e,t,n){if(null===(e=p(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
":">"},a.prototype.text=function(e){return e},s.prototype.strong=s.prototype.em=s.prototype.codespan=s.prototype.del=s.prototype.text=function(e){return e},s.prototype.link=s.prototype.image=function(e,t,n){return""+n},s.prototype.br=function(){return""},l.parse=function(e,t){return new l(t).parse(e)},l.prototype.parse=function(e){this.inline=new i(e.links,this.options),this.inlineText=new i(e.links,b({},this.options,{renderer:new s})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},l.prototype.next=function(){return this.token=this.tokens.pop(),this.token},l.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},l.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},l.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,f(this.inlineText.output(this.token.text)),this.slugger);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,o="",i="";for(n="",e=0;e?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t)){var n=t;do{this.seen[n]++,t=n+"-"+this.seen[n]}while(this.seen.hasOwnProperty(t))}return this.seen[t]=0,t},u.escapeTest=/[&<>"']/,u.escapeReplace=/[&<>"']/g,u.replacements={"&":"&","<":"<",">":">",'"':""","'":"'"},u.escapeTestNoEncode=/[<>"']|&(?!#?\w+;)/,u.escapeReplaceNoEncode=/[<>"']|&(?!#?\w+;)/g;var h={},g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function m(){}function b(e){for(var t,n,r=1;r=0&&"\\"===n[o];)r=!r;return r?"|":" |"}).split(/ \|/),r=0;if(n.length>t)n.splice(t);else for(;n.lengthAn error occurred:"+u(e.message+"",!0)+"
";throw e}}m.exec=m,x.options=x.setOptions=function(e){return b(x.defaults,e),x},x.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:new a,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},x.defaults=x.getDefaults(),x.Parser=l,x.parser=l.parse,x.Renderer=a,x.TextRenderer=s,x.Lexer=r,x.lexer=r.lex,x.InlineLexer=i,x.inlineLexer=i.output,x.Slugger=c,x.parse=x,e.exports=x}(this||"undefined"!=typeof window&&window)}).call(this,n(10))},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";t.__esModule=!0;var r=n(12);r.registerLanguage("css",n(13)),r.registerLanguage("json",n(14)),r.registerLanguage("less",n(15)),r.registerLanguage("scss",n(16)),r.registerLanguage("javascript",n(17)),r.registerLanguage("typescript",n(18)),t.default=r},function(e,t,n){!function(e){"object"==typeof window&&window||"object"==typeof self&&self;(function(e){var t,n=[],r=Object.keys,o={},i={},a=/^(no-?highlight|plain|text)$/i,s=/\blang(?:uage)?-([\w-]+)\b/i,l=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,c="",u={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};function f(e){return e.replace(/&/g,"&").replace(//g,">")}function d(e){return e.nodeName.toLowerCase()}function p(e,t){var n=e&&e.exec(t);return n&&0===n.index}function h(e){return a.test(e)}function g(e){var t,n={},r=Array.prototype.slice.call(arguments,1);for(t in e)n[t]=e[t];return r.forEach(function(e){for(t in e)n[t]=e[t]}),n}function m(e){var t=[];return function e(n,r){for(var o=n.firstChild;o;o=o.nextSibling)3===o.nodeType?r+=o.nodeValue.length:1===o.nodeType&&(t.push({event:"start",offset:r,node:o}),r=e(o,r),d(o).match(/br|hr|img|input/)||t.push({event:"stop",offset:r,node:o}));return r}(e,0),t}function b(e){if(t&&!e.langApiRestored){for(var n in e.langApiRestored=!0,t)e[n]&&(e[t[n]]=e[n]);(e.contains||[]).concat(e.variants||[]).forEach(b)}}function v(e){function t(e){return e&&e.source||e}function n(n,r){return new RegExp(t(n),"m"+(e.case_insensitive?"i":"")+(r?"g":""))}!function o(i,a){if(i.compiled)return;i.compiled=!0;i.keywords=i.keywords||i.beginKeywords;if(i.keywords){var s={},l=function(t,n){e.case_insensitive&&(n=n.toLowerCase()),n.split(" ").forEach(function(e){var n=e.split("|");s[n[0]]=[t,n[1]?Number(n[1]):1]})};"string"==typeof i.keywords?l("keyword",i.keywords):r(i.keywords).forEach(function(e){l(e,i.keywords[e])}),i.keywords=s}i.lexemesRe=n(i.lexemes||/\w+/,!0);a&&(i.beginKeywords&&(i.begin="\\b("+i.beginKeywords.split(" ").join("|")+")\\b"),i.begin||(i.begin=/\B|\b/),i.beginRe=n(i.begin),i.endSameAsBegin&&(i.end=i.begin),i.end||i.endsWithParent||(i.end=/\B|\b/),i.end&&(i.endRe=n(i.end)),i.terminator_end=t(i.end)||"",i.endsWithParent&&a.terminator_end&&(i.terminator_end+=(i.end?"|":"")+a.terminator_end));i.illegal&&(i.illegalRe=n(i.illegal));null==i.relevance&&(i.relevance=1);i.contains||(i.contains=[]);i.contains=Array.prototype.concat.apply([],i.contains.map(function(e){return function(e){e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map(function(t){return g(e,{variants:null},t)}));return e.cached_variants||e.endsWithParent&&[g(e)]||[e]}("self"===e?i:e)}));i.contains.forEach(function(e){o(e,i)});i.starts&&o(i.starts,a);var c=i.contains.map(function(e){return e.beginKeywords?"\\.?(?:"+e.begin+")\\.?":e.begin}).concat([i.terminator_end,i.illegal]).map(t).filter(Boolean);i.terminators=c.length?n(function(e,n){for(var r=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,o=0,i="",a=0;a0&&(i+=n);l.length>0;){var c=r.exec(l);if(null==c){i+=l;break}i+=l.substring(0,c.index),l=l.substring(c.index+c[0].length),"\\"==c[0][0]&&c[1]?i+="\\"+String(Number(c[1])+s):(i+=c[0],"("==c[0]&&o++)}}return i}(c,"|"),!0):{exec:function(){return null}}}(e)}function y(e,t,n,r){function i(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function a(e,t){var n=g.case_insensitive?t[0].toLowerCase():t[0];return e.keywords.hasOwnProperty(n)&&e.keywords[n]}function s(e,t,n,r){var o=r?"":u.classPrefix,i='',e?i+t+a:t}function l(){k+=null!=b.subLanguage?function(){var e="string"==typeof b.subLanguage;if(e&&!o[b.subLanguage])return f(_);var t=e?y(b.subLanguage,_,!0,x[b.subLanguage]):w(_,b.subLanguage.length?b.subLanguage:void 0);b.relevance>0&&(O+=t.relevance);e&&(x[b.subLanguage]=t.top);return s(t.language,t.value,!1,!0)}():function(){var e,t,n,r;if(!b.keywords)return f(_);r="",t=0,b.lexemesRe.lastIndex=0,n=b.lexemesRe.exec(_);for(;n;)r+=f(_.substring(t,n.index)),(e=a(b,n))?(O+=e[1],r+=s(e[0],f(n[0]))):r+=f(n[0]),t=b.lexemesRe.lastIndex,n=b.lexemesRe.exec(_);return r+f(_.substr(t))}(),_=""}function d(e){k+=e.className?s(e.className,"",!0):"",b=Object.create(e,{parent:{value:b}})}function h(e,t){if(_+=e,null==t)return l(),0;var r=function(e,t){var n,r;for(n=0,r=t.contains.length;n")+'"');return _+=t,t.length||1}var g=E(e);if(!g)throw new Error('Unknown language: "'+e+'"');v(g);var m,b=r||g,x={},k="";for(m=b;m!==g;m=m.parent)m.className&&(k=s(m.className,"",!0)+k);var _="",O=0;try{for(var N,S,C=0;b.terminators.lastIndex=C,N=b.terminators.exec(t);)S=h(t.substring(C,N.index),N[0]),C=N.index+S;for(h(t.substr(C)),m=b;m.parent;m=m.parent)m.className&&(k+=c);return{relevance:O,value:k,language:e,top:b}}catch(e){if(e.message&&-1!==e.message.indexOf("Illegal"))return{relevance:0,value:f(t)};throw e}}function w(e,t){t=t||u.languages||r(o);var n={relevance:0,value:f(e)},i=n;return t.filter(E).filter(O).forEach(function(t){var r=y(t,e,!1);r.language=t,r.relevance>i.relevance&&(i=r),r.relevance>n.relevance&&(i=n,n=r)}),i.language&&(n.second_best=i),n}function x(e){return u.tabReplace||u.useBR?e.replace(l,function(e,t){return u.useBR&&"\n"===e?"
":u.tabReplace?t.replace(/\t/g,u.tabReplace):""}):e}function k(e){var t,r,o,a,l,c=function(e){var t,n,r,o,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",n=s.exec(i))return E(n[1])?n[1]:"no-highlight";for(i=i.split(/\s+/),t=0,r=i.length;t/g,"\n"):t=e,l=t.textContent,o=c?y(c,l,!0):w(l),(r=m(t)).length&&((a=document.createElementNS("http://www.w3.org/1999/xhtml","div")).innerHTML=o.value,o.value=function(e,t,r){var o=0,i="",a=[];function s(){return e.length&&t.length?e[0].offset!==t[0].offset?e[0].offset"}function c(e){i+=""+d(e)+">"}function u(e){("start"===e.event?l:c)(e.node)}for(;e.length||t.length;){var p=s();if(i+=f(r.substring(o,p[0].offset)),o=p[0].offset,p===e){a.reverse().forEach(c);do{u(p.splice(0,1)[0]),p=s()}while(p===e&&p.length&&p[0].offset===o);a.reverse().forEach(l)}else"start"===p[0].event?a.push(p[0].node):a.pop(),u(p.splice(0,1)[0])}return i+f(r.substr(o))}(r,m(a),l)),o.value=x(o.value),e.innerHTML=o.value,e.className=function(e,t,n){var r=t?i[t]:n,o=[e.trim()];e.match(/\bhljs\b/)||o.push("hljs");-1===e.indexOf(r)&&o.push(r);return o.join(" ").trim()}(e.className,c,o.language),e.result={language:o.language,re:o.relevance},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.relevance}))}function _(){if(!_.called){_.called=!0;var e=document.querySelectorAll("pre code");n.forEach.call(e,k)}}function E(e){return e=(e||"").toLowerCase(),o[e]||o[i[e]]}function O(e){var t=E(e);return t&&!t.disableAutodetect}e.highlight=y,e.highlightAuto=w,e.fixMarkup=x,e.highlightBlock=k,e.configure=function(e){u=g(u,e)},e.initHighlighting=_,e.initHighlightingOnLoad=function(){addEventListener("DOMContentLoaded",_,!1),addEventListener("load",_,!1)},e.registerLanguage=function(t,n){var r=o[t]=n(e);b(r),r.aliases&&r.aliases.forEach(function(e){i[e]=t})},e.listLanguages=function(){return r(o)},e.getLanguage=E,e.autoDetection=O,e.inherit=g,e.IDENT_RE="[a-zA-Z]\\w*",e.UNDERSCORE_IDENT_RE="[a-zA-Z_]\\w*",e.NUMBER_RE="\\b\\d+(\\.\\d+)?",e.C_NUMBER_RE="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BINARY_NUMBER_RE="\\b(0b[01]+)",e.RE_STARTERS_RE="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BACKSLASH_ESCAPE={begin:"\\\\[\\s\\S]",relevance:0},e.APOS_STRING_MODE={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},e.QUOTE_STRING_MODE={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},e.PHRASAL_WORDS_MODE={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.COMMENT=function(t,n,r){var o=e.inherit({className:"comment",begin:t,end:n,contains:[]},r||{});return o.contains.push(e.PHRASAL_WORDS_MODE),o.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),o},e.C_LINE_COMMENT_MODE=e.COMMENT("//","$"),e.C_BLOCK_COMMENT_MODE=e.COMMENT("/\\*","\\*/"),e.HASH_COMMENT_MODE=e.COMMENT("#","$"),e.NUMBER_MODE={className:"number",begin:e.NUMBER_RE,relevance:0},e.C_NUMBER_MODE={className:"number",begin:e.C_NUMBER_RE,relevance:0},e.BINARY_NUMBER_MODE={className:"number",begin:e.BINARY_NUMBER_RE,relevance:0},e.CSS_NUMBER_MODE={className:"number",begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},e.REGEXP_MODE={className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0,contains:[e.BACKSLASH_ESCAPE]}]},e.TITLE_MODE={className:"title",begin:e.IDENT_RE,relevance:0},e.UNDERSCORE_TITLE_MODE={className:"title",begin:e.UNDERSCORE_IDENT_RE,relevance:0},e.METHOD_GUARD={begin:"\\.\\s*"+e.UNDERSCORE_IDENT_RE,relevance:0}})(t)}()},function(e,t){e.exports=function(e){var t={begin:/[A-Z\_\.\-]+\s*:/,returnBegin:!0,end:";",endsWithParent:!0,contains:[{className:"attribute",begin:/\S/,end:":",excludeEnd:!0,starts:{endsWithParent:!0,excludeEnd:!0,contains:[{begin:/[\w-]+\(/,returnBegin:!0,contains:[{className:"built_in",begin:/[\w-]+/},{begin:/\(/,end:/\)/,contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]}]},e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{className:"number",begin:"#[0-9A-Fa-f]+"},{className:"meta",begin:"!important"}]}}]};return{case_insensitive:!0,illegal:/[=\/|'\$]/,contains:[e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/},{className:"selector-class",begin:/\.[A-Za-z0-9_-]+/},{className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"@(font-face|page)",lexemes:"[a-z-]+",keywords:"font-face page"},{begin:"@",end:"[{;]",illegal:/:/,contains:[{className:"keyword",begin:/\w+/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},{begin:"{",end:"}",illegal:/\S/,contains:[e.C_BLOCK_COMMENT_MODE,t]}]}}},function(e,t){e.exports=function(e){var t={literal:"true false null"},n=[e.QUOTE_STRING_MODE,e.C_NUMBER_MODE],r={end:",",endsWithParent:!0,excludeEnd:!0,contains:n,keywords:t},o={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE],illegal:"\\n"},e.inherit(r,{begin:/:/})],illegal:"\\S"},i={begin:"\\[",end:"\\]",contains:[e.inherit(r)],illegal:"\\S"};return n.splice(n.length,0,o,i),{contains:n,keywords:t,illegal:"\\S"}}},function(e,t){e.exports=function(e){var t="([\\w-]+|@{[\\w-]+})",n=[],r=[],o=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},i=function(e,t,n){return{className:e,begin:t,relevance:n}},a={begin:"\\(",end:"\\)",contains:r,relevance:0};r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},i("number","#[0-9A-Fa-f]+\\b"),a,i("variable","@@?[\\w-]+",10),i("variable","@{[\\w-]+}"),i("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var s=r.concat({begin:"{",end:"}",contains:n}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(r)},c={begin:t+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:t,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:r}}]},u={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:r,relevance:0}},f={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:s}},d={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:t,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,i("keyword","all\\b"),i("variable","@{[\\w-]+}"),i("selector-tag",t+"%?",0),i("selector-id","#"+t),i("selector-class","\\."+t,0),i("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:s},{begin:"!important"}]};return n.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,f,c,d),{case_insensitive:!0,illegal:"[=>'/<($\"]",contains:n}}},function(e,t){e.exports=function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},n={className:"number",begin:"#[0-9A-Fa-f]+"};e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE;return{case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,n,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@",end:"[{;]",keywords:"mixin include extend for if else each while charset import debug media page content font-face namespace warn",contains:[t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n,e.CSS_NUMBER_MODE,{begin:"\\s[A-Za-z0-9_.-]+",relevance:0}]}]}}},function(e,t){e.exports=function(e){var t="[A-Za-z$_][0-9A-Za-z$_]*",n={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},r={className:"number",variants:[{begin:"\\b(0[bB][01]+)"},{begin:"\\b(0[oO][0-7]+)"},{begin:e.C_NUMBER_RE}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:n,contains:[]},i={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,o]};o.contains=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,r,e.REGEXP_MODE];var a=o.contains.concat([e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]);return{aliases:["js","jsx"],keywords:n,contains:[{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},{className:"meta",begin:/^#!/,end:/$/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,r,{begin:/[{,]\s*/,relevance:0,contains:[{begin:t+"\\s*:",returnBegin:!0,relevance:0,contains:[{className:"attr",begin:t,relevance:0}]}]},{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.REGEXP_MODE,{className:"function",begin:"(\\(.*?\\)|"+t+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t},{begin:/\(\s*\)/},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,contains:a}]}]},{className:"",begin:/\s/,end:/\s*/,skip:!0},{begin:/,end:/(\/[A-Za-z0-9\\._:-]+|[A-Za-z0-9\\._:-]+\/)>/,subLanguage:"xml",contains:[{begin:/<[A-Za-z0-9\\._:-]+\s*\/>/,skip:!0},{begin:/<[A-Za-z0-9\\._:-]+/,end:/(\/[A-Za-z0-9\\._:-]+|[A-Za-z0-9\\._:-]+\/)>/,skip:!0,contains:[{begin:/<[A-Za-z0-9\\._:-]+\s*\/>/,skip:!0},"self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:t}),{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:a}],illegal:/\[|%/},{begin:/\$[(.]/},e.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor get set",end:/\{/,excludeEnd:!0}],illegal:/#(?!!)/}}},function(e,t){e.exports=function(e){var t={keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class public private protected get set super static implements enum export import declare type namespace abstract as from extends async await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document any number boolean string void Promise"},n={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},r={begin:"\\(",end:/\)/,keywords:t,contains:["self",e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.NUMBER_MODE]},o={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n,r]};return{aliases:["ts"],keywords:t,contains:[{className:"meta",begin:/^\s*['"]use strict['"]/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,{className:"subst",begin:"\\$\\{",end:"\\}"}]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"number",variants:[{begin:"\\b(0[bB][01]+)"},{begin:"\\b(0[oO][0-7]+)"},{begin:e.C_NUMBER_RE}],relevance:0},{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.REGEXP_MODE,{className:"function",begin:"(\\(.*?\\)|"+e.IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.IDENT_RE},{begin:/\(\s*\)/},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]}]}]}],relevance:0},{className:"function",begin:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",e.inherit(e.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),o],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0,contains:["self",o]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+e.IDENT_RE,relevance:0},n,r]}}},function(e,t,n){"use strict";t.__esModule=!0;var r=83,o=90,i=89,a=9;t.default=function(e,t){e.addEventListener("keydown",function(e){if(e.ctrlKey||e.metaKey||e.altKey||e.shiftKey){if((e.ctrlKey||e.metaKey)&&!e.altKey&&!e.shiftKey)switch(e.keyCode){case o:e.preventDefault(),t("undo");break;case i:e.preventDefault(),t("redo");break;case r:e.preventDefault(),t("save")}}else switch(e.keyCode){case a:e.preventDefault(),t("tab")}})}},function(e,t,n){"use strict";var r,o=this&&this.__extends||(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t};t.__esModule=!0;var a=i(n(0)),s=function(e){function t(t){var n=e.call(this,t)||this;return n.state={imgHidden:!0,imgList:[]},n}return o(t,e),t.prototype.onClick=function(e){this.props.onClick(e)},t.prototype.imgClick=function(){this.setState({imgHidden:!this.state.imgHidden})},t.prototype.imgMouseOver=function(){window.clearTimeout(this.timer),this.setState({imgHidden:!1})},t.prototype.imgMouseOut=function(){var e=this;this.timer=window.setTimeout(function(){e.setState({imgHidden:!0})},150)},t.prototype.addImgUrl=function(){this.props.onClick("img")},t.prototype.addImgFile=function(e){var t=this.state.imgList,n=t.length;t.push(e.target.files[0]),this.setState({imgList:t}),this.props.addImg(e.target.files[0],n),e.target.value=""},t.prototype.render=function(){var e=this,t=this.props,n=t.toolbar,r=t.words,o=this.state.imgHidden;return a.createElement("ul",null,n.undo&&a.createElement("li",{onClick:function(){return e.onClick("undo")},title:r.undo+" (ctrl+z)"},a.createElement("i",{className:"foricon for-undo"})),n.redo&&a.createElement("li",{onClick:function(){return e.onClick("redo")},title:r.redo+" (ctrl+y)"},a.createElement("i",{className:"foricon for-redo"})),n.h1&&a.createElement("li",{onClick:function(){return e.onClick("h1")},title:r.h1},"H1"),n.h2&&a.createElement("li",{onClick:function(){return e.onClick("h2")},title:r.h2},"H2"),n.h3&&a.createElement("li",{onClick:function(){return e.onClick("h3")},title:r.h3},"H3"),n.h4&&a.createElement("li",{onClick:function(){return e.onClick("h4")},title:r.h4},"H4"),n.img&&a.createElement("li",{className:"for-toolbar-img",onMouseOver:function(){return e.imgMouseOver()},onMouseOut:function(){return e.imgMouseOut()}},a.createElement("i",{className:"foricon for-image"}),a.createElement("ul",{style:o?{display:"none"}:{}},a.createElement("li",{onClick:function(){return e.addImgUrl()}},r.addImgLink),a.createElement("li",null,r.addImg,a.createElement("input",{type:"file",accept:"image/gif,image/jpeg,image/jpg,image/png,image/svg",onChange:function(t){return e.addImgFile(t)}})))),n.link&&a.createElement("li",{onClick:function(){return e.onClick("link")},title:r.link},a.createElement("i",{className:"foricon for-link"})),n.code&&a.createElement("li",{onClick:function(){return e.onClick("code")},title:r.code},a.createElement("i",{className:"foricon for-code"})),n.save&&a.createElement("li",{onClick:function(){return e.onClick("save")},title:r.save+" (ctrl+s)"},a.createElement("i",{className:"foricon for-save"})))},t.defaultProps={onClick:function(){},toolbar:{},words:{}},t}(a.Component);t.default=s},function(e,t,n){"use strict";var r,o=this&&this.__extends||(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var s=i(n(0)),l=a(n(3)),c=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.onClick=function(e){this.props.onClick(e)},t.prototype.render=function(){var e=this,t=this.props,n=t.preview,r=t.expand,o=t.subfield,i=t.toolbar,a=t.words,c=l.default({"for-active":n}),u=l.default({"for-active":r}),f=l.default({"for-active":o});return s.createElement("ul",null,i.expand&&s.createElement("li",{className:u,onClick:function(){return e.onClick("expand")},title:u?a.fullscreenOff:a.fullscreenOn},u?s.createElement("i",{className:"foricon for-contract"}):s.createElement("i",{className:"foricon for-expand"})),i.preview&&s.createElement("li",{className:c,onClick:function(){return e.onClick("preview")},title:a.preview},c?s.createElement("i",{className:"foricon for-eye-off"}):s.createElement("i",{className:"foricon for-eye"})),i.subfield&&s.createElement("li",{className:f,onClick:function(){return e.onClick("subfield")},title:f?a.singleColumn:a.doubleColumn},s.createElement("i",{className:"foricon for-subfield"})))},t.defaultProps={onClick:function(){},toolbars:{},words:{}},t}(s.Component);t.default=c},function(e,t,n){"use strict";t.__esModule=!0,t.insertText=function(e,t){var n=t.prefix,r=t.str,o=void 0===r?"":r,i=t.subfix,a=void 0===i?"":i,s=e.value;if(e.selectionStart||0===e.selectionStart){var l=e.selectionStart,c=e.selectionEnd,u=e.scrollTop;l===c?(e.value=s.substring(0,l)+n+o+a+s.substring(c,s.length),e.selectionStart=l+n.length,e.selectionEnd=c+n.length+o.length):(e.value=s.substring(0,l)+n+s.substring(l,c)+a+s.substring(c,s.length),e.selectionStart=l+n.length,e.selectionEnd=c+n.length),e.focus(),u>=0&&(e.scrollTop=u)}return e.value}},function(e,t,n){var r=n(24);"string"==typeof r&&(r=[[e.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(2)(r,o);r.locals&&(e.exports=r.locals)},function(e,t,n){(e.exports=n(1)(!1)).push([e.i,"/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */\n\n/* Tomorrow Comment */\n.hljs-comment,\n.hljs-quote {\n color: #8e908c;\n}\n\n/* Tomorrow Red */\n.hljs-variable,\n.hljs-template-variable,\n.hljs-tag,\n.hljs-name,\n.hljs-selector-id,\n.hljs-selector-class,\n.hljs-regexp,\n.hljs-deletion {\n color: #c82829;\n}\n\n/* Tomorrow Orange */\n.hljs-number,\n.hljs-built_in,\n.hljs-builtin-name,\n.hljs-literal,\n.hljs-type,\n.hljs-params,\n.hljs-meta,\n.hljs-link {\n color: #f5871f;\n}\n\n/* Tomorrow Yellow */\n.hljs-attribute {\n color: #eab700;\n}\n\n/* Tomorrow Green */\n.hljs-string,\n.hljs-symbol,\n.hljs-bullet,\n.hljs-addition {\n color: #718c00;\n}\n\n/* Tomorrow Blue */\n.hljs-title,\n.hljs-section {\n color: #4271ae;\n}\n\n/* Tomorrow Purple */\n.hljs-keyword,\n.hljs-selector-tag {\n color: #8959a8;\n}\n\n.hljs {\n display: block;\n overflow-x: auto;\n background: white;\n color: #4d4d4c;\n padding: 0.5em;\n}\n\n.hljs-emphasis {\n font-style: italic;\n}\n\n.hljs-strong {\n font-weight: bold;\n}\n",""])},function(e,t){e.exports=function(e){var t="undefined"!=typeof window&&window.location;if(!t)throw new Error("fixUrls requires window.location");if(!e||"string"!=typeof e)return e;var n=t.protocol+"//"+t.host,r=n+t.pathname.replace(/\/[^\/]*$/,"/");return e.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi,function(e,t){var o,i=t.trim().replace(/^"(.*)"$/,function(e,t){return t}).replace(/^'(.*)'$/,function(e,t){return t});return/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/|\s*$)/i.test(i)?e:(o=0===i.indexOf("//")?i:0===i.indexOf("/")?n+i:r+i.replace(/^\.\//,""),"url("+JSON.stringify(o)+")")})}},function(e,t,n){var r=n(27);"string"==typeof r&&(r=[[e.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(2)(r,o);r.locals&&(e.exports=r.locals)},function(e,t,n){t=e.exports=n(1)(!1);var r=n(28),o=r(n(4)),i=r(n(4)+"#iefix"),a=r(n(29)),s=r(n(30)),l=r(n(31)+"#foricon");t.push([e.i,'@font-face {font-family: "foricon";\n src: url('+o+"); /* IE9 */\n src: url("+i+") format('embedded-opentype'), \n url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),\n url("+a+") format('woff'),\n url("+s+") format('truetype'), \n url("+l+') format(\'svg\'); /* iOS 4.1- */\n}\n\n.foricon {\n font-family: "foricon" !important;\n font-size: inherit;\n font-style: normal;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n.for-code:before {\n content: "\\e620";\n}\n\n.for-image:before {\n content: "\\e621";\n}\n\n.for-eye:before {\n content: "\\e622";\n}\n\n.for-expand:before {\n content: "\\e623";\n}\n\n.for-redo:before {\n content: "\\e624";\n}\n\n.for-undo:before {\n content: "\\e625";\n}\n\n.for-quote:before {\n content: "\\e626";\n}\n\n.for-link:before {\n content: "\\e627";\n}\n\n.for-save:before {\n content: "\\e628";\n}\n\n.for-contract:before {\n content: "\\e629";\n}\n\n.for-eye-off:before {\n content: "\\e62a";\n}\n\n.for-subfield:before {\n content: "\\e62b";\n}\n\n',""])},function(e,t,n){"use strict";e.exports=function(e,t){return"string"!=typeof e?e:(/^['"].*['"]$/.test(e)&&(e=e.slice(1,-1)),/["'() \t\n]/.test(e)||t?'"'+e.replace(/"/g,'\\"').replace(/\n/g,"\\n")+'"':e)}},function(e,t,n){e.exports=n.p+"static/fonts/iconfont.fe07082d.woff"},function(e,t,n){e.exports=n.p+"static/fonts/iconfont.a614fc0f.ttf"},function(e,t,n){e.exports=n.p+"static/fonts/iconfont.35e220a6.svg"},function(e,t,n){var r=n(33);"string"==typeof r&&(r=[[e.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(2)(r,o);r.locals&&(e.exports=r.locals)},function(e,t,n){(e.exports=n(1)(!1)).push([e.i,".for-container {\n font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;\n display: flex;\n flex-direction: column;\n height: 600px;\n border: 1px solid #ddd;\n border-radius: 8px;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 12px;\n background: #fff;\n font-size: 14px; }\n .for-container ul,\n .for-container ol,\n .for-container li {\n margin: 0;\n padding: 0; }\n .for-container.for-fullscreen {\n position: fixed;\n z-index: 99999;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n height: 100% !important; }\n .for-container > div:first-child {\n border-top-left-radius: 8px;\n border-top-right-radius: 8px; }\n .for-container .for-hidden {\n display: none; }\n .for-container .for-toolbar {\n font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;\n display: flex;\n justify-content: space-between;\n padding: 0 6px;\n border-bottom: 1px solid #ddd;\n color: #555;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none; }\n .for-container .for-toolbar > ul {\n display: flex; }\n .for-container .for-toolbar > ul > li {\n display: flex;\n align-items: center;\n padding: 4px 6px;\n margin: 8px 4px;\n border-radius: 4px;\n line-height: normal; }\n .for-container .for-toolbar > ul > li.for-toolbar-img {\n position: relative; }\n .for-container .for-toolbar > ul > li.for-toolbar-img > ul {\n position: absolute;\n top: 100%;\n left: -50px;\n width: 140px;\n margin-top: 4px;\n background: #fff;\n border-radius: 4px;\n box-shadow: rgba(0, 0, 0, 0.1) 0 2px 8px 0;\n z-index: 99;\n line-height: 2.8;\n text-align: center; }\n .for-container .for-toolbar > ul > li.for-toolbar-img > ul li {\n position: relative; }\n .for-container .for-toolbar > ul > li.for-toolbar-img > ul li:hover {\n background: #e9e9e9; }\n .for-container .for-toolbar > ul > li.for-toolbar-img > ul li:first-child {\n border-radius: 4px 4px 0 0; }\n .for-container .for-toolbar > ul > li.for-toolbar-img > ul li:last-child {\n border-radius: 0 0 4px 4px; }\n .for-container .for-toolbar > ul > li.for-toolbar-img > ul li input {\n position: absolute;\n width: 100%;\n opacity: 0;\n left: 0;\n top: 0;\n bottom: 0;\n cursor: pointer; }\n .for-container .for-toolbar > ul > li.for-active {\n background: #ddd; }\n .for-container .for-toolbar > ul > li:hover {\n cursor: pointer;\n background: #e9e9e9; }\n .for-container .for-toolbar > ul > li i {\n font-size: 1.2em; }\n .for-container .for-editor {\n display: flex;\n justify-content: space-between;\n height: 100%;\n color: #2c3e50;\n border-radius: 0 0 8px 8px;\n overflow: hidden; }\n .for-container .for-editor .for-panel {\n height: 100%;\n flex: 0 0 100%;\n overflow: auto;\n transition: all 0.2s linear 0s; }\n .for-container .for-editor .for-panel.for-active {\n flex: 0 0 50%; }\n .for-container .for-editor .for-panel .for-preview {\n min-height: 100%;\n box-sizing: border-box;\n padding: 10px 14px;\n background: #fcfcfc; }\n .for-container .for-editor .for-editor-edit {\n line-height: 1.6;\n height: 100%; }\n .for-container .for-editor .for-editor-edit.for-edit-preview {\n width: 0;\n flex: 0 0 0; }\n .for-container .for-editor .for-editor-edit .for-editor-block {\n display: flex;\n min-height: 100%; }\n .for-container .for-editor .for-editor-edit .for-line-num {\n list-style: none;\n background: #eee;\n padding: 8px 0 120px;\n min-width: 30px;\n text-align: center; }\n .for-container .for-editor .for-editor-edit .for-line-num.hidden {\n display: none; }\n .for-container .for-editor .for-editor-edit .for-line-num li {\n list-style: none; }\n .for-container .for-editor .for-editor-edit .for-editor-content {\n flex: 1;\n position: relative;\n height: 100%;\n margin-left: 10px; }\n .for-container .for-editor .for-editor-edit .for-editor-content pre {\n padding: 8px 0;\n display: block;\n white-space: pre-wrap;\n word-wrap: break-word;\n visibility: hidden;\n margin: 0;\n font-family: inherit; }\n .for-container textarea {\n font-family: 'Consolas', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;\n box-sizing: border-box;\n position: absolute;\n top: 0;\n bottom: 0;\n padding: 8px 0;\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n resize: none;\n border: none;\n outline: none;\n font-size: inherit;\n color: inherit;\n background: none;\n line-height: inherit; }\n .for-container .for-markdown-preview {\n line-height: 2; }\n .for-container .for-markdown-preview p,\n .for-container .for-markdown-preview blockquote,\n .for-container .for-markdown-preview ul,\n .for-container .for-markdown-preview ol,\n .for-container .for-markdown-preview dl,\n .for-container .for-markdown-preview pre {\n margin-top: 0;\n margin-bottom: 0.6em; }\n .for-container .for-markdown-preview h1,\n .for-container .for-markdown-preview h2 {\n border-bottom: 1px solid #e2e2e2; }\n .for-container .for-markdown-preview h1,\n .for-container .for-markdown-preview h2,\n .for-container .for-markdown-preview h3,\n .for-container .for-markdown-preview h4,\n .for-container .for-markdown-preview h5,\n .for-container .for-markdown-preview h6 {\n padding: 0;\n margin: 0 0 0.6em;\n font-weight: 600;\n text-indent: 0; }\n .for-container .for-markdown-preview h1:target,\n .for-container .for-markdown-preview h2:target,\n .for-container .for-markdown-preview h3:target,\n .for-container .for-markdown-preview h4:target,\n .for-container .for-markdown-preview h5:target,\n .for-container .for-markdown-preview h6:target {\n padding-top: 4.5rem; }\n .for-container .for-markdown-preview a {\n color: #0366d6;\n text-decoration: none; }\n .for-container .for-markdown-preview a:hover {\n text-decoration: underline; }\n .for-container .for-markdown-preview ul,\n .for-container .for-markdown-preview ol {\n padding: 0.2em 0.8em; }\n .for-container .for-markdown-preview ul > li,\n .for-container .for-markdown-preview ol > li {\n line-height: 2;\n padding-left: 0.2em;\n margin-left: 0.2em;\n list-style-type: disc; }\n .for-container .for-markdown-preview ul > li > p,\n .for-container .for-markdown-preview ol > li > p {\n text-indent: 0; }\n .for-container .for-markdown-preview ul > li > ul:last-child,\n .for-container .for-markdown-preview ol > li > ul:last-child {\n margin-bottom: 0; }\n .for-container .for-markdown-preview ul > li > ul li,\n .for-container .for-markdown-preview ol > li > ul li {\n list-style-type: circle; }\n .for-container .for-markdown-preview ul > li > ul li > ul li,\n .for-container .for-markdown-preview ol > li > ul li > ul li {\n list-style-type: square; }\n .for-container .for-markdown-preview > ul,\n .for-container .for-markdown-preview ol {\n padding: 0 20px; }\n .for-container .for-markdown-preview ol > li {\n list-style-type: decimal; }\n .for-container .for-markdown-preview blockquote {\n margin: 0;\n margin-bottom: 0.6em;\n padding: 0 1em;\n color: #6a737d;\n border-left: 0.25em solid #dfe2e5; }\n .for-container .for-markdown-preview blockquote p {\n text-indent: 0; }\n .for-container .for-markdown-preview blockquote p:first-child {\n margin-top: 0; }\n .for-container .for-markdown-preview blockquote p:last-child {\n margin-bottom: 0; }\n .for-container .for-markdown-preview pre {\n padding: 0.6em;\n overflow: auto;\n line-height: 1.6;\n background-color: #f0f0f0;\n border-radius: 3px; }\n .for-container .for-markdown-preview pre code {\n padding: 0;\n margin: 0;\n font-size: 100%;\n background: transparent; }\n .for-container .for-markdown-preview code {\n padding: 0.2em 0.4em;\n margin: 0;\n background-color: #f0f0f0;\n border-radius: 3px; }\n .for-container .for-markdown-preview hr {\n margin-bottom: 0.6em;\n height: 1px;\n background: #dadada;\n border: none; }\n .for-container .for-markdown-preview table {\n width: 100%;\n border: 1px solid #ddd;\n margin-bottom: 0.6em;\n border-collapse: collapse;\n text-align: left; }\n .for-container .for-markdown-preview table thead {\n background: #eee; }\n .for-container .for-markdown-preview table th,\n .for-container .for-markdown-preview table td {\n padding: 0.1em 0.4em;\n border: 1px solid #ddd; }\n .for-container .for-markdown-preview img {\n display: block;\n margin: 0 auto;\n max-width: 100%;\n margin-bottom: 0.6em; }\n",""])},function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var o=r(n(35)),i=r(n(36));t.CONFIG={language:{"zh-CN":o.default,en:i.default},langList:["zh-CN","en"],toolbar:{h1:!0,h2:!0,h3:!0,h4:!0,img:!0,link:!0,code:!0,preview:!0,expand:!0,undo:!0,redo:!0,save:!0,subfield:!0}}},function(e){e.exports=JSON.parse('{"placeholder":"开始编辑...","undo":"上一步","redo":"下一步","h1":"一级标题","h2":"二级标题","h3":"三级标题","h4":"四级标题","img":"添加图片链接","link":"链接","code":"代码块","save":"保存","preview":"预览","singleColumn":"单栏","doubleColumn":"双栏","fullscreenOn":"全屏编辑","fullscreenOff":"退出全屏","addImgLink":"添加图片链接","addImg":"上传图片"}')},function(e){e.exports=JSON.parse('{"placeholder":"Begin editing...","undo":"Undo","redo":"Redo","h1":"Header 1","h2":"Header 2","h3":"Header 3","h4":"Header 4","img":"Image Link","link":"Link","code":"Code","save":"Save","preview":"Preview","singleColumn":"Single Column","doubleColumn":"Double Columns","fullscreenOn":"FullScreen ON","fullscreenOff":"FullScreen OFF","addImgLink":"Add Image Link","addImg":"Upload Image"}')}])});
--------------------------------------------------------------------------------
/dist/static/fonts/iconfont.0f693eba.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kkfor/for-editor/d97c009dd13c39c02163327a85500cf4de1cc90a/dist/static/fonts/iconfont.0f693eba.eot
--------------------------------------------------------------------------------
/dist/static/fonts/iconfont.35e220a6.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
63 |
--------------------------------------------------------------------------------
/dist/static/fonts/iconfont.a614fc0f.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kkfor/for-editor/d97c009dd13c39c02163327a85500cf4de1cc90a/dist/static/fonts/iconfont.a614fc0f.ttf
--------------------------------------------------------------------------------
/dist/static/fonts/iconfont.fe07082d.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kkfor/for-editor/d97c009dd13c39c02163327a85500cf4de1cc90a/dist/static/fonts/iconfont.fe07082d.woff
--------------------------------------------------------------------------------
/doc/UPDATELOG.md:
--------------------------------------------------------------------------------
1 | - 2019-12-11 v0.3.5
2 | - 修复双栏,预览,全屏bug [#45](https://github.com/kkfor/for-editor/pull/45)
3 | - 2019-08-20 v0.3.4
4 | - 修复typescrit定义问题 [#36](https://github.com/kkfor/for-editor/issues/35)
5 | - 2019-08-20 v0.3.2
6 | - 修复图片上传bug
7 | - 优化typescript d.ts声明 [#35](https://github.com/kkfor/for-editor/issues/35)
8 | - 2019-08-19 v0.3.1
9 | - 添加图片上传功能 [#32](https://github.com/kkfor/for-editor/issues/32)
10 | - 优化代码
11 | - 2019-07-05 v0.3.0
12 | - 添加d.ts声明文件,修复bug [#27](https://github.com/kkfor/for-editor/issues/27)
13 | - 2019-07-03 v0.2.9
14 | - 修复bug [#26](https://github.com/kkfor/for-editor/issues/26)
15 | - 2019-07-03 v0.2.8
16 | - 新增预览设置,支持中文、英文
17 | - 2019-07-01 v0.2.7
18 | - 修复bug [#24](https://github.com/kkfor/for-editor/issues/24)
19 | - 优化样式
20 | - 2019-06-21 v0.2.6
21 | - 优化一些样式
22 | - 2019-06-20 v0.2.5
23 | - 新增工具栏按钮显示隐藏功能
24 | - 优化预览过渡效果
25 | - 2019-06-19 v0.2.3
26 | - 修复双栏模式bug
27 | - 2019-06-19 v0.2.2
28 | - 增加同步滚动功能
29 | - 增加双栏模式
30 | - 2019-06-17 v0.2.1
31 | - 修复预览样式bug
32 | - 2019-06-17 v0.2.0
33 | - 重构项目,优化页面结构
34 | - 2019-02-02 v0.0.12
35 | - 修复编辑器自定义高度bug
36 | - 2019-01-10 v0.0.11
37 | - 优化代码预览样式
38 | - 2019-01-09 v0.0.10
39 | - 优化代码结构
40 | - 2019-01-07 v0.0.9
41 | - 新增上一步,下一步,tab快捷键功能
42 | - 新增保存功能
43 | - 优化图标状态
44 | - 优化页面样式
45 | - 2018-12-29 v0.0.8
46 | - 添加行号显示功能
47 | - 优化快捷插入标签时,光标选中文本内容
48 | - 修复异步加载数据时编辑框回显问题
49 | - 优化编辑区域行间距
50 | - 2018-12-27 v0.0.6
51 | - 优化图标按钮
52 | - 修改组件UnMount时错误bug
53 | - 新增组件placeholder属性
54 | - 2018-12-26 v0.0.5
55 | - 添加上一步,下一步按钮及功能
56 | - 2018-12-25 v0.0.4
57 | - 修复firefox下显示bug
58 | - 2018-12-24 v0.0.3
59 | - 增加全屏功能
60 | - 修改onChange参数为输入框内容
61 | - 优化编辑框输入字体
62 | - 修复快捷插入标签时,滚动条位置bug
63 | - 修复firefox下显示问题
64 | - 2018-12-23 v0.0.0
65 | - 编辑器基础功能,快捷插入markdown标签,预览功能
--------------------------------------------------------------------------------
/example/globals.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.md'
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | for-editor | 基于react的markdown编辑器
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/example/index.scss:
--------------------------------------------------------------------------------
1 | #root {
2 | height: 100%;
3 | }
--------------------------------------------------------------------------------
/example/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './src/app'
4 | import './index.scss'
5 |
6 | ReactDOM.render(, document.getElementById('root'))
7 |
--------------------------------------------------------------------------------
/example/src/app.module.scss:
--------------------------------------------------------------------------------
1 | html {
2 | height: 100%;
3 | }
4 |
5 | body {
6 | height: 100%;
7 | margin: 0;
8 | }
9 |
10 | .main {
11 | padding-bottom: 40px;
12 |
13 | h1,
14 | ul,
15 | li {
16 | margin: 0;
17 | padding: 0;
18 | }
19 |
20 | ul,
21 | li {
22 | list-style: none;
23 | }
24 |
25 | a {
26 | color: inherit;
27 | }
28 |
29 | .top {
30 | display: flex;
31 | justify-content: space-between;
32 | height: 80px;
33 | line-height: 80px;
34 | padding: 0 20px;
35 | margin-bottom: 30px;
36 | font-size: 18px;
37 | color: #fff;
38 | background: linear-gradient(160deg, #852178, #019845);
39 | }
40 |
41 | .editor {
42 | width: 90%;
43 | max-width: 1400px;
44 | margin: 0 auto;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/example/src/app.module.scss.d.ts:
--------------------------------------------------------------------------------
1 | // This file is automatically generated.
2 | // Please do not change this file!
3 | interface CssExports {
4 | 'editor': string;
5 | 'main': string;
6 | 'top': string;
7 | }
8 | declare var cssExports: CssExports;
9 | export = cssExports;
10 |
--------------------------------------------------------------------------------
/example/src/app.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Editor from '../../src/index'
3 | // import Editor from '../../dist'
4 | import * as styles from './app.module.scss'
5 | import value from '../static/help.md'
6 |
7 | interface IS {
8 | value: string
9 | mobile: boolean
10 | }
11 |
12 |
13 | class App extends Component<{}, IS> {
14 |
15 | private $vm = React.createRef()
16 |
17 | constructor(props: any) {
18 | super(props)
19 |
20 | this.state = {
21 | value: '',
22 | mobile: false
23 | }
24 | }
25 |
26 | componentDidMount() {
27 | this.resize()
28 | window.addEventListener('resize', () => {
29 | this.resize()
30 | })
31 | setTimeout(() => {
32 | this.setState({
33 | value
34 | })
35 | }, 200)
36 | }
37 |
38 | resize() {
39 | if (window.matchMedia('(min-width: 768px)').matches) {
40 | this.setState({
41 | mobile: false
42 | })
43 | } else {
44 | this.setState({
45 | mobile: true
46 | })
47 | }
48 | }
49 |
50 | handleChange(value: string) {
51 | this.setState({
52 | value
53 | })
54 | }
55 |
56 | handleSave(value: string) {
57 | console.log('触发保存事件', value)
58 | }
59 |
60 | addImg($file: File) {
61 | this.$vm.current.$img2Url($file.name, 'file_url')
62 | console.log($file)
63 | }
64 |
65 | render() {
66 | const { value, mobile } = this.state
67 |
68 | return (
69 |
70 |
71 |
for-editor
72 |
83 |
84 |
85 | {mobile && (
86 | this.handleChange(value)}
99 | onSave={value => this.handleSave(value)}
100 | />
101 | )}
102 | {!mobile && (
103 | this.addImg($file)}
109 | onChange={value => this.handleChange(value)}
110 | onSave={value => this.handleSave(value)}
111 | />
112 | )}
113 |
114 |
115 | )
116 | }
117 | }
118 |
119 | export default App
120 |
--------------------------------------------------------------------------------
/example/static/help.md:
--------------------------------------------------------------------------------
1 | > `for-editor` is a markdown editor
2 |
3 | # for-editor
4 |
5 | this is a markdown editor
6 |
7 | ## for-editor
8 |
9 | this is a markdown editor
10 |
11 | ### for-editor
12 |
13 | ```js
14 | const editor = 'for-editor'
15 | ```
16 |
17 | - item1
18 | - subitem1
19 | - subitem2
20 | - subitem3
21 | - item2
22 | - item3
23 |
24 | ---
25 |
26 | 1. item1
27 | 2. item2
28 | 3. item3
29 |
30 | ### table
31 |
32 | | title | description |
33 | | ---------- | --------------- |
34 | | for-editor | markdown editor |
35 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | export interface IToolbar {
3 | h1?: boolean
4 | h2?: boolean
5 | h3?: boolean
6 | h4?: boolean
7 | img?: boolean
8 | link?: boolean
9 | code?: boolean
10 | preview?: boolean
11 | expand?: boolean
12 | undo?: boolean
13 | redo?: boolean
14 | save?: boolean
15 | subfield?: boolean
16 | }
17 | export interface IWords {
18 | placeholder?: string
19 | h1?: string
20 | h2?: string
21 | h3?: string
22 | h4?: string
23 | undo?: string
24 | redo?: string
25 | img?: string
26 | link?: string
27 | code?: string
28 | save?: string
29 | preview?: string
30 | singleColumn?: string
31 | doubleColumn?: string
32 | fullscreenOn?: string
33 | fullscreenOff?: string
34 | addImgLink?: string
35 | addImg?: string
36 | }
37 | interface IP {
38 | value?: string
39 | lineNum?: number
40 | onChange?: (value: string) => void
41 | onSave?: (value: string) => void
42 | placeholder?: string
43 | fontSize?: string
44 | disabled?: boolean
45 | style?: object
46 | height?: string
47 | preview?: boolean
48 | expand?: boolean
49 | subfield?: boolean
50 | toolbar?: IToolbar
51 | language?: string
52 | addImg?: (file: File, index: number) => void
53 | }
54 | interface IS {
55 | preview: boolean
56 | expand: boolean
57 | subfield: boolean
58 | history: string[]
59 | historyIndex: number
60 | lineIndex: number
61 | value: string
62 | words: IWords
63 | }
64 | declare class MdEditor extends React.Component {
65 | static defaultProps: {
66 | lineNum: boolean
67 | onChange: () => void
68 | onSave: () => void
69 | addImg: () => void
70 | fontSize: string
71 | disabled: boolean
72 | preview: boolean
73 | expand: boolean
74 | subfield: boolean
75 | style: {}
76 | toolbar: IToolbar
77 | language: string
78 | };
79 |
80 | $img2Url: (name: string, url: string) => void;
81 |
82 | private $vm;
83 | private $scrollEdit;
84 | private $scrollPreview;
85 | private $blockEdit;
86 | private $blockPreview;
87 | private currentTimeout;
88 | }
89 | export default MdEditor
90 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "for-editor",
3 | "version": "0.3.5",
4 | "description": "react markdown editor",
5 | "main": "dist/index.js",
6 | "scripts": {
7 | "start": "npm run dev",
8 | "dev": "webpack-dev-server --config webpack/webpack.dev.config.js",
9 | "build": "webpack --config webpack/webpack.prod.config.js",
10 | "dist": "webpack --config webpack/webpack.dist.config.js",
11 | "lint": "eslint --ext .js,.jsx --ignore-path .gitignore ."
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/kkfor/for-editor.git"
16 | },
17 | "keywords": [
18 | "javascript",
19 | "react",
20 | "markdown",
21 | "editor"
22 | ],
23 | "author": "kkfor",
24 | "license": "MIT",
25 | "bugs": {
26 | "url": "https://github.com/kkfor/for-editor/issues"
27 | },
28 | "files": [
29 | "dist/",
30 | "index.d.ts",
31 | "LICENSE"
32 | ],
33 | "homepage": "https://github.com/kkfor/for-editor#readme",
34 | "devDependencies": {
35 | "@babel/core": "^7.2.2",
36 | "@babel/plugin-proposal-class-properties": "^7.2.3",
37 | "@babel/preset-env": "^7.2.3",
38 | "@babel/preset-react": "^7.0.0",
39 | "@types/classnames": "^2.2.9",
40 | "@types/marked": "^0.6.5",
41 | "@types/react": "^16.8.16",
42 | "@types/react-dom": "^16.8.4",
43 | "@typescript-eslint/eslint-plugin": "^1.13.0",
44 | "@typescript-eslint/parser": "^1.13.0",
45 | "autoprefixer": "^9.5.1",
46 | "babel-core": "^7.0.0-bridge.0",
47 | "babel-eslint": "^10.0.2",
48 | "babel-loader": "^8.0.4",
49 | "classnames": "^2.2.6",
50 | "clean-webpack-plugin": "^3.0.0",
51 | "css-loader": "^2.0.2",
52 | "css-modules-typescript-loader": "^2.0.4",
53 | "eslint": "^6.1.0",
54 | "eslint-config-for": "^0.0.1",
55 | "eslint-plugin-react": "^7.14.3",
56 | "file-loader": "^4.0.0",
57 | "html-webpack-plugin": "^3.2.0",
58 | "node-sass": "^4.11.0",
59 | "postcss-loader": "^3.0.0",
60 | "prettier": "^1.15.3",
61 | "raw-loader": "^3.0.0",
62 | "react": "^16.7.0",
63 | "react-dom": "^16.7.0",
64 | "sass-loader": "^7.1.0",
65 | "style-loader": "^0.23.1",
66 | "ts-loader": "^6.0.0",
67 | "typescript": "^3.5.3",
68 | "uglifyjs-webpack-plugin": "^2.1.0",
69 | "webpack": "^4.28.1",
70 | "webpack-cli": "^3.1.2",
71 | "webpack-dev-server": "^3.1.10",
72 | "webpack-merge": "^4.1.5"
73 | },
74 | "dependencies": {
75 | "highlight.js": "^9.13.1",
76 | "marked": "^1.1.1"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/components/toolbar_left.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import { IToolbar, IWords } from '../index'
3 | interface IP {
4 | onClick: (type: string) => void
5 | addImg: (file: File, index: number) => void
6 | toolbar: IToolbar
7 | words: IWords
8 | }
9 |
10 | interface IS {
11 | imgHidden: boolean
12 | imgList: File[]
13 | }
14 |
15 | class Toolbars extends React.Component {
16 | static defaultProps = {
17 | onClick: () => {},
18 | toolbar: {},
19 | words: {}
20 | }
21 |
22 | private timer: number
23 |
24 | constructor(props: IP) {
25 | super(props)
26 |
27 | this.state = {
28 | imgHidden: true,
29 | imgList: []
30 | }
31 | }
32 |
33 | onClick(type: string) {
34 | this.props.onClick(type)
35 | }
36 |
37 | imgClick() {
38 | this.setState({
39 | imgHidden: !this.state.imgHidden
40 | })
41 | }
42 |
43 | imgMouseOver() {
44 | window.clearTimeout(this.timer)
45 | this.setState({
46 | imgHidden: false
47 | })
48 | }
49 |
50 | imgMouseOut() {
51 | this.timer = window.setTimeout(() => {
52 | this.setState({
53 | imgHidden: true
54 | })
55 | }, 150)
56 | }
57 |
58 | addImgUrl() {
59 | this.props.onClick('img')
60 | }
61 |
62 | addImgFile(e: any) {
63 | let { imgList } = this.state
64 | const index = imgList.length
65 | imgList.push(e.target.files[0])
66 | this.setState({
67 | imgList
68 | })
69 | this.props.addImg(e.target.files[0], index)
70 | e.target.value = ''
71 | }
72 |
73 | render() {
74 | const { toolbar, words } = this.props
75 | const { imgHidden } = this.state
76 | return (
77 |
78 | {toolbar.undo && (
79 | - this.onClick('undo')} title={`${words.undo} (ctrl+z)`}>
80 |
81 |
82 | )}
83 | {toolbar.redo && (
84 | - this.onClick('redo')} title={`${words.redo} (ctrl+y)`}>
85 |
86 |
87 | )}
88 | {toolbar.h1 && (
89 | - this.onClick('h1')} title={words.h1}>
90 | H1
91 |
92 | )}
93 | {toolbar.h2 && (
94 | - this.onClick('h2')} title={words.h2}>
95 | H2
96 |
97 | )}
98 | {toolbar.h3 && (
99 | - this.onClick('h3')} title={words.h3}>
100 | H3
101 |
102 | )}
103 | {toolbar.h4 && (
104 | - this.onClick('h4')} title={words.h4}>
105 | H4
106 |
107 | )}
108 | {toolbar.img && (
109 | - this.imgMouseOver()} onMouseOut={() => this.imgMouseOut()}>
110 |
111 |
118 |
119 | )}
120 | {toolbar.link && (
121 | - this.onClick('link')} title={words.link}>
122 |
123 |
124 | )}
125 | {toolbar.code && (
126 | - this.onClick('code')} title={words.code}>
127 |
128 |
129 | )}
130 | {toolbar.save && (
131 | - this.onClick('save')} title={`${words.save} (ctrl+s)`}>
132 |
133 |
134 | )}
135 |
136 | )
137 | }
138 | }
139 |
140 | export default Toolbars
141 |
--------------------------------------------------------------------------------
/src/components/toolbar_right.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import classNames from 'classnames'
3 | import { IToolbar, IWords } from '../index'
4 |
5 | interface IP {
6 | onClick: (type: string) => void
7 | toolbar: IToolbar
8 | preview: boolean
9 | expand: boolean
10 | subfield: boolean
11 | words: IWords
12 | }
13 |
14 | class Toolbars extends React.Component {
15 | static defaultProps = {
16 | onClick: () => {},
17 | toolbars: {},
18 | words: {}
19 | }
20 |
21 | onClick(type: string) {
22 | this.props.onClick(type)
23 | }
24 |
25 | render() {
26 | const { preview, expand, subfield, toolbar, words } = this.props
27 |
28 | const previewActive = classNames({
29 | 'for-active': preview
30 | })
31 | const expandActive = classNames({
32 | 'for-active': expand
33 | })
34 | const subfieldActive = classNames({
35 | 'for-active': subfield
36 | })
37 | return (
38 |
39 | {toolbar.expand && (
40 | - this.onClick('expand')}
43 | title={expandActive ? words.fullscreenOff : words.fullscreenOn}
44 | >
45 | {expandActive ? (
46 |
47 | ) : (
48 |
49 | )}
50 |
51 | )}
52 | {toolbar.preview && (
53 | - this.onClick('preview')}
56 | title={words.preview}
57 | >
58 | {previewActive ? (
59 |
60 | ) : (
61 |
62 | )}
63 |
64 | )}
65 | {toolbar.subfield && (
66 | - this.onClick('subfield')}
69 | title={subfieldActive ? words.singleColumn : words.doubleColumn}
70 | >
71 |
72 |
73 | )}
74 |
75 | )
76 | }
77 | }
78 |
79 | export default Toolbars
80 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import classNames from 'classnames'
3 | import marked from './lib/helpers/marked'
4 | import keydownListen from './lib/helpers/keydownListen'
5 | import ToolbarLeft from './components/toolbar_left'
6 | import ToolbarRight from './components/toolbar_right'
7 | import { insertText } from './lib/helpers/function'
8 | import 'highlight.js/styles/tomorrow.css'
9 | import './lib/fonts/iconfont.css'
10 | import './lib/css/index.scss'
11 | import { CONFIG } from './lib'
12 |
13 | export interface IToolbar {
14 | h1?: boolean
15 | h2?: boolean
16 | h3?: boolean
17 | h4?: boolean
18 | img?: boolean
19 | link?: boolean
20 | code?: boolean
21 | preview?: boolean
22 | expand?: boolean
23 | undo?: boolean
24 | redo?: boolean
25 | save?: boolean
26 | subfield?: boolean
27 | }
28 |
29 | export interface IWords {
30 | placeholder?: string
31 | h1?: string
32 | h2?: string
33 | h3?: string
34 | h4?: string
35 | undo?: string
36 | redo?: string
37 | img?: string
38 | link?: string
39 | code?: string
40 | save?: string
41 | preview?: string
42 | singleColumn?: string
43 | doubleColumn?: string
44 | fullscreenOn?: string
45 | fullscreenOff?: string
46 | addImgLink?: string
47 | addImg?: string
48 | }
49 |
50 | interface ILeft {
51 | prefix: string
52 | subfix: string
53 | str: string
54 | }
55 | interface IP {
56 | value?: string
57 | lineNum?: number
58 | onChange?: (value: string) => void
59 | onSave?: (value: string) => void
60 | placeholder?: string
61 | fontSize?: string
62 | disabled?: boolean
63 | style?: object
64 | height?: string
65 | preview?: boolean
66 | expand?: boolean
67 | subfield?: boolean
68 | toolbar?: IToolbar
69 | language?: string
70 | addImg?: (file: File, index: number) => void
71 | }
72 |
73 | interface IS {
74 | preview: boolean
75 | expand: boolean
76 | subfield: boolean
77 | history: string[]
78 | historyIndex: number
79 | lineIndex: number
80 | value: string
81 | words: IWords
82 | }
83 |
84 | class MdEditor extends React.Component {
85 | static defaultProps = {
86 | lineNum: true,
87 | onChange: () => { },
88 | onSave: () => { },
89 | addImg: () => { },
90 | fontSize: '14px',
91 | disabled: false,
92 | preview: false,
93 | expand: false,
94 | subfield: false,
95 | style: {},
96 | toolbar: CONFIG.toolbar,
97 | language: 'zh-CN'
98 | }
99 | private $vm = React.createRef()
100 | private $scrollEdit = React.createRef()
101 | private $scrollPreview = React.createRef()
102 | private $blockEdit = React.createRef()
103 | private $blockPreview = React.createRef()
104 | private currentTimeout: number
105 | constructor(props: IP) {
106 | super(props)
107 |
108 | this.state = {
109 | preview: props.preview,
110 | expand: props.expand,
111 | subfield: props.subfield,
112 | history: [],
113 | historyIndex: 0,
114 | lineIndex: 1,
115 | value: props.value,
116 | words: {}
117 | }
118 | }
119 |
120 | componentDidMount() {
121 | const { value } = this.props
122 | keydownListen(this.$vm.current, (type: string) => {
123 | this.toolBarLeftClick(type)
124 | })
125 | this.reLineNum(value)
126 | this.initLanguage()
127 | }
128 |
129 | componentDidUpdate(preProps: IP) {
130 | const { value, preview, expand, subfield } = this.props
131 | const { history, historyIndex } = this.state
132 | if (preProps.value !== value) {
133 | this.reLineNum(value)
134 | }
135 | if (value !== history[historyIndex]) {
136 | window.clearTimeout(this.currentTimeout)
137 | this.currentTimeout = window.setTimeout(() => {
138 | this.saveHistory(value)
139 | }, 500)
140 | }
141 | if (subfield !== preProps.subfield && this.state.subfield !== subfield) {
142 | this.setState({ subfield });
143 | }
144 | if (preview !== preProps.preview && this.state.preview !== preview) {
145 | this.setState({ preview });
146 | }
147 | if (expand !== preProps.expand && this.state.expand !== expand) {
148 | this.setState({ expand });
149 | }
150 | }
151 |
152 | initLanguage = (): void => {
153 | const { language } = this.props
154 | const lang = CONFIG.langList.indexOf(language) >= 0 ? language : 'zh-CN'
155 | this.setState({
156 | words: CONFIG.language[lang]
157 | })
158 | }
159 |
160 | // 输入框改变
161 | handleChange = (e: React.ChangeEvent): void => {
162 | const value = e.target.value
163 | this.props.onChange(value)
164 | }
165 |
166 | // 保存记录
167 | saveHistory = (value: string): void => {
168 | let { history, historyIndex } = this.state
169 | // 撤销后修改,删除当前以后记录
170 | history.splice(historyIndex + 1, history.length)
171 | if (history.length >= 20) {
172 | history.shift()
173 | }
174 | // 记录当前位置
175 | historyIndex = history.length
176 | history.push(value)
177 | this.setState({
178 | history,
179 | historyIndex
180 | })
181 | }
182 |
183 | // 重新计算行号
184 | reLineNum(value: string) {
185 | const lineIndex = value ? value.split('\n').length : 1
186 | this.setState({
187 | lineIndex
188 | })
189 | }
190 |
191 | // 保存
192 | save = (): void => {
193 | this.props.onSave(this.$vm.current!.value)
194 | }
195 |
196 | // 撤销
197 | undo = (): void => {
198 | let { history, historyIndex } = this.state
199 | historyIndex = historyIndex - 1
200 | if (historyIndex < 0) return
201 | this.props.onChange(history[historyIndex])
202 | this.setState({
203 | historyIndex
204 | })
205 | }
206 |
207 | // 重做
208 | redo = (): void => {
209 | let { history, historyIndex } = this.state
210 | historyIndex = historyIndex + 1
211 | if (historyIndex >= history.length) return
212 | this.props.onChange(history[historyIndex])
213 | this.setState({
214 | historyIndex
215 | })
216 | }
217 |
218 | // 菜单点击
219 | toolBarLeftClick = (type: string): void => {
220 | const { words } = this.state
221 | const insertTextObj: any = {
222 | h1: {
223 | prefix: '# ',
224 | subfix: '',
225 | str: words.h1
226 | },
227 | h2: {
228 | prefix: '## ',
229 | subfix: '',
230 | str: words.h2
231 | },
232 | h3: {
233 | prefix: '### ',
234 | subfix: '',
235 | str: words.h3
236 | },
237 | h4: {
238 | prefix: '#### ',
239 | subfix: '',
240 | str: words.h4
241 | },
242 | img: {
243 | prefix: '',
245 | str: 'url'
246 | },
247 | link: {
248 | prefix: '[title](',
249 | subfix: ')',
250 | str: 'url'
251 | },
252 | code: {
253 | prefix: '```',
254 | subfix: '\n\n```',
255 | str: 'language'
256 | },
257 | tab: {
258 | prefix: ' ',
259 | subfix: '',
260 | str: ''
261 | }
262 | }
263 |
264 | if (insertTextObj.hasOwnProperty(type)) {
265 | if (this.$vm.current) {
266 | const value = insertText(this.$vm.current, insertTextObj[type])
267 | this.props.onChange(value)
268 | }
269 | }
270 |
271 | const otherLeftClick: any = {
272 | undo: this.undo,
273 | redo: this.redo,
274 | save: this.save
275 | }
276 | if (otherLeftClick.hasOwnProperty(type)) {
277 | otherLeftClick[type]()
278 | }
279 | }
280 |
281 | // 添加图片
282 | addImg = (file: File, index: number) => {
283 | this.props.addImg(file, index)
284 | }
285 |
286 | $img2Url = (name: string, url: string) => {
287 | const value = insertText(this.$vm.current, {
288 | prefix: ``,
289 | subfix: '',
290 | str: ''
291 | })
292 | this.props.onChange(value)
293 | }
294 |
295 | // 右侧菜单
296 | toolBarRightClick = (type: string): void => {
297 | const toolbarRightPreviewClick = () => {
298 | this.setState({
299 | preview: !this.state.preview
300 | })
301 | }
302 | const toolbarRightExpandClick = () => {
303 | this.setState({
304 | expand: !this.state.expand
305 | })
306 | }
307 |
308 | const toolbarRightSubfieldClick = () => {
309 | const { preview, subfield } = this.state
310 | if (preview) {
311 | if (subfield) {
312 | this.setState({
313 | subfield: false,
314 | preview: false
315 | })
316 | } else {
317 | this.setState({
318 | subfield: true
319 | })
320 | }
321 | } else {
322 | if (subfield) {
323 | this.setState({
324 | subfield: false
325 | })
326 | } else {
327 | this.setState({
328 | preview: true,
329 | subfield: true
330 | })
331 | }
332 | }
333 | }
334 |
335 | const rightClick: any = {
336 | preview: toolbarRightPreviewClick,
337 | expand: toolbarRightExpandClick,
338 | subfield: toolbarRightSubfieldClick
339 | }
340 | if (rightClick.hasOwnProperty(type)) {
341 | rightClick[type]()
342 | }
343 | }
344 |
345 | focusText = (): void => {
346 | this.$vm.current!.focus()
347 | }
348 |
349 | handleScoll = (e: React.UIEvent): void => {
350 | const radio =
351 | this.$blockEdit.current!.scrollTop /
352 | (this.$scrollEdit.current!.scrollHeight - e.currentTarget.offsetHeight)
353 | this.$blockPreview.current!.scrollTop =
354 | (this.$scrollPreview.current!.scrollHeight - this.$blockPreview.current!.offsetHeight) * radio
355 | }
356 |
357 | render() {
358 | const { preview, expand, subfield, lineIndex, words } = this.state
359 | const { value, placeholder, fontSize, disabled, height, style, toolbar } = this.props
360 | const editorClass = classNames({
361 | 'for-editor-edit': true,
362 | 'for-panel': true,
363 | 'for-active': preview && subfield,
364 | 'for-edit-preview': preview && !subfield
365 | })
366 | const previewClass = classNames({
367 | 'for-panel': true,
368 | 'for-editor-preview': true,
369 | 'for-active': preview && subfield
370 | })
371 | const fullscreen = classNames({
372 | 'for-container': true,
373 | 'for-fullscreen': expand
374 | })
375 | const lineNumStyles = classNames({
376 | 'for-line-num': true,
377 | hidden: !this.props.lineNum
378 | })
379 |
380 | // 行号
381 | function lineNum() {
382 | const list = []
383 | for (let i = 0; i < lineIndex; i++) {
384 | list.push({i + 1})
385 | }
386 | return
387 | }
388 |
389 | return (
390 |
391 | {/* 菜单栏 */}
392 | {Boolean(Object.keys(toolbar).length) && (
393 |
394 |
401 |
409 |
410 | )}
411 | {/* 内容区 */}
412 |
413 | {/* 编辑区 */}
414 |
420 |
421 | {lineNum()}
422 |
423 |
{value}
424 |
431 |
432 |
433 |
434 | {/* 预览区 */}
435 |
442 |
443 |
444 | )
445 | }
446 | }
447 |
448 | export default MdEditor
449 |
--------------------------------------------------------------------------------
/src/lib/css/index.scss:
--------------------------------------------------------------------------------
1 | .for-container {
2 | font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
3 | display: flex;
4 | flex-direction: column;
5 | height: 600px;
6 | border: 1px solid #ddd;
7 | border-radius: 8px;
8 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 12px;
9 | background: #fff;
10 | font-size: 14px;
11 |
12 | ul,
13 | ol,
14 | li {
15 | margin: 0;
16 | padding: 0;
17 | }
18 |
19 | &.for-fullscreen {
20 | position: fixed;
21 | z-index: 99999;
22 | top: 0;
23 | right: 0;
24 | bottom: 0;
25 | left: 0;
26 | height: 100% !important;
27 | }
28 |
29 | > div {
30 | &:first-child {
31 | border-top-left-radius: 8px;
32 | border-top-right-radius: 8px;
33 | }
34 | }
35 |
36 | .for-hidden {
37 | display: none;
38 | }
39 |
40 | .for-toolbar {
41 | font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
42 | display: flex;
43 | justify-content: space-between;
44 | padding: 0 6px;
45 | border-bottom: 1px solid #ddd;
46 | color: #555;
47 | user-select: none;
48 |
49 | > ul {
50 | display: flex;
51 |
52 | > li {
53 | display: flex;
54 | align-items: center;
55 | padding: 4px 6px;
56 | margin: 8px 4px;
57 | border-radius: 4px;
58 | line-height: normal;
59 |
60 | &.for-toolbar-img {
61 | position: relative;
62 |
63 | > ul {
64 | position: absolute;
65 | top: 100%;
66 | left: -50px;
67 | width: 140px;
68 | margin-top: 4px;
69 | background: #fff;
70 | border-radius: 4px;
71 | box-shadow: rgba(0, 0, 0, 0.1) 0 2px 8px 0;
72 | z-index: 99;
73 | line-height: 2.8;
74 | text-align: center;
75 |
76 | li {
77 | position: relative;
78 |
79 | &:hover {
80 | background: #e9e9e9;
81 | }
82 |
83 | &:first-child {
84 | border-radius: 4px 4px 0 0;
85 | }
86 |
87 | &:last-child {
88 | border-radius: 0 0 4px 4px;
89 | }
90 |
91 | input {
92 | position: absolute;
93 | width: 100%;
94 | opacity: 0;
95 | left: 0;
96 | top: 0;
97 | bottom: 0;
98 | cursor: pointer;
99 | }
100 | }
101 | }
102 | }
103 |
104 | &.for-active {
105 | background: #ddd;
106 | }
107 |
108 | &:hover {
109 | cursor: pointer;
110 | background: #e9e9e9;
111 | }
112 |
113 | i {
114 | font-size: 1.2em;
115 | }
116 | }
117 | }
118 | }
119 |
120 | .for-editor {
121 | display: flex;
122 | justify-content: space-between;
123 | height: 100%;
124 | color: #2c3e50;
125 | border-radius: 0 0 8px 8px;
126 | overflow: hidden;
127 |
128 | .for-panel {
129 | height: 100%;
130 | flex: 0 0 100%;
131 | overflow: auto;
132 | transition: all 0.2s linear 0s;
133 |
134 | &.for-active {
135 | flex: 0 0 50%;
136 | }
137 |
138 | .for-preview {
139 | min-height: 100%;
140 | box-sizing: border-box;
141 | padding: 10px 14px;
142 | background: #fcfcfc;
143 | }
144 | }
145 |
146 | // 编辑区域
147 | .for-editor-edit {
148 | line-height: 1.6;
149 | height: 100%;
150 |
151 | &.for-edit-preview {
152 | width: 0;
153 | flex: 0 0 0;
154 | }
155 | .for-editor-block {
156 | display: flex;
157 | min-height: 100%;
158 | }
159 |
160 | .for-line-num {
161 | list-style: none;
162 | background: #eee;
163 | padding: 8px 0 120px;
164 | min-width: 30px;
165 | text-align: center;
166 | &.hidden {
167 | display: none;
168 | }
169 | li {
170 | list-style: none;
171 | }
172 | }
173 |
174 | .for-editor-content {
175 | flex: 1;
176 | position: relative;
177 | height: 100%;
178 | margin-left: 10px;
179 |
180 | pre {
181 | padding: 8px 0;
182 | display: block;
183 | white-space: pre-wrap;
184 | word-wrap: break-word;
185 | visibility: hidden;
186 | margin: 0;
187 | font-family: inherit;
188 | }
189 | }
190 | }
191 | }
192 |
193 | textarea {
194 | font-family: 'Consolas', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
195 | box-sizing: border-box;
196 | position: absolute;
197 | top: 0;
198 | bottom: 0;
199 | padding: 8px 0;
200 | display: block;
201 | height: 100%;
202 | width: 100%;
203 | overflow: hidden;
204 | resize: none;
205 | border: none;
206 | outline: none;
207 | font-size: inherit;
208 | color: inherit;
209 | background: none;
210 | line-height: inherit;
211 | }
212 |
213 | .for-markdown-preview {
214 | line-height: 2;
215 |
216 | p,
217 | blockquote,
218 | ul,
219 | ol,
220 | dl,
221 | pre {
222 | margin-top: 0;
223 | margin-bottom: 0.6em;
224 | }
225 |
226 | h1,
227 | h2 {
228 | border-bottom: 1px solid #e2e2e2;
229 | }
230 |
231 | h1,
232 | h2,
233 | h3,
234 | h4,
235 | h5,
236 | h6 {
237 | padding: 0;
238 | margin: 0 0 0.6em;
239 | font-weight: 600;
240 |
241 | text-indent: 0;
242 |
243 | &:target {
244 | padding-top: 4.5rem;
245 | }
246 | }
247 |
248 | a {
249 | color: #0366d6;
250 | text-decoration: none;
251 |
252 | &:hover {
253 | text-decoration: underline;
254 | }
255 | }
256 |
257 | ul,
258 | ol {
259 | padding: 0.2em 0.8em;
260 |
261 | > li {
262 | line-height: 2;
263 | padding-left: 0.2em;
264 | margin-left: 0.2em;
265 | list-style-type: disc;
266 |
267 | > p {
268 | text-indent: 0;
269 | }
270 |
271 | > ul {
272 | &:last-child {
273 | margin-bottom: 0;
274 | }
275 |
276 | li {
277 | list-style-type: circle;
278 |
279 | > ul li {
280 | list-style-type: square;
281 | }
282 | }
283 | }
284 | }
285 | }
286 |
287 | > ul,
288 | ol {
289 | padding: 0 20px;
290 | }
291 |
292 | ol > li {
293 | list-style-type: decimal;
294 | }
295 |
296 | blockquote {
297 | margin: 0;
298 | margin-bottom: 0.6em;
299 | padding: 0 1em;
300 | color: #6a737d;
301 | border-left: 0.25em solid #dfe2e5;
302 |
303 | p {
304 | text-indent: 0;
305 |
306 | &:first-child {
307 | margin-top: 0;
308 | }
309 |
310 | &:last-child {
311 | margin-bottom: 0;
312 | }
313 | }
314 | }
315 |
316 | pre {
317 | padding: 0.6em;
318 | overflow: auto;
319 | line-height: 1.6;
320 | background-color: #f0f0f0;
321 | border-radius: 3px;
322 |
323 | code {
324 | padding: 0;
325 | margin: 0;
326 | font-size: 100%;
327 | background: transparent;
328 | }
329 | }
330 |
331 | code {
332 | padding: 0.2em 0.4em;
333 | margin: 0;
334 | background-color: #f0f0f0;
335 | border-radius: 3px;
336 | }
337 |
338 | hr {
339 | margin-bottom: 0.6em;
340 | height: 1px;
341 | background: #dadada;
342 | border: none;
343 | }
344 |
345 | table {
346 | width: 100%;
347 | border: 1px solid #ddd;
348 | margin-bottom: 0.6em;
349 | border-collapse: collapse;
350 | text-align: left;
351 |
352 | thead {
353 | background: #eee;
354 | }
355 |
356 | th,
357 | td {
358 | padding: 0.1em 0.4em;
359 | border: 1px solid #ddd;
360 | }
361 | }
362 |
363 | img {
364 | display: block;
365 | margin: 0 auto;
366 | max-width: 100%;
367 | margin-bottom: 0.6em;
368 | }
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/src/lib/css/index.scss.d.ts:
--------------------------------------------------------------------------------
1 | // This file is automatically generated.
2 | // Please do not change this file!
3 | interface CssExports {
4 |
5 | }
6 | declare var cssExports: CssExports;
7 | export = cssExports;
8 |
--------------------------------------------------------------------------------
/src/lib/fonts/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "foricon";
2 | src: url('iconfont.eot?t=1560850902819'); /* IE9 */
3 | src: url('iconfont.eot?t=1560850902819#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
5 | url('iconfont.woff?t=1560850902819') format('woff'),
6 | url('iconfont.ttf?t=1560850902819') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
7 | url('iconfont.svg?t=1560850902819#foricon') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .foricon {
11 | font-family: "foricon" !important;
12 | font-size: inherit;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .for-code:before {
19 | content: "\e620";
20 | }
21 |
22 | .for-image:before {
23 | content: "\e621";
24 | }
25 |
26 | .for-eye:before {
27 | content: "\e622";
28 | }
29 |
30 | .for-expand:before {
31 | content: "\e623";
32 | }
33 |
34 | .for-redo:before {
35 | content: "\e624";
36 | }
37 |
38 | .for-undo:before {
39 | content: "\e625";
40 | }
41 |
42 | .for-quote:before {
43 | content: "\e626";
44 | }
45 |
46 | .for-link:before {
47 | content: "\e627";
48 | }
49 |
50 | .for-save:before {
51 | content: "\e628";
52 | }
53 |
54 | .for-contract:before {
55 | content: "\e629";
56 | }
57 |
58 | .for-eye-off:before {
59 | content: "\e62a";
60 | }
61 |
62 | .for-subfield:before {
63 | content: "\e62b";
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/src/lib/fonts/iconfont.css.d.ts:
--------------------------------------------------------------------------------
1 | // This file is automatically generated.
2 | // Please do not change this file!
3 | interface CssExports {
4 |
5 | }
6 | declare var cssExports: CssExports;
7 | export = cssExports;
8 |
--------------------------------------------------------------------------------
/src/lib/fonts/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kkfor/for-editor/d97c009dd13c39c02163327a85500cf4de1cc90a/src/lib/fonts/iconfont.eot
--------------------------------------------------------------------------------
/src/lib/fonts/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
63 |
--------------------------------------------------------------------------------
/src/lib/fonts/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kkfor/for-editor/d97c009dd13c39c02163327a85500cf4de1cc90a/src/lib/fonts/iconfont.ttf
--------------------------------------------------------------------------------
/src/lib/fonts/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kkfor/for-editor/d97c009dd13c39c02163327a85500cf4de1cc90a/src/lib/fonts/iconfont.woff
--------------------------------------------------------------------------------
/src/lib/fonts/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kkfor/for-editor/d97c009dd13c39c02163327a85500cf4de1cc90a/src/lib/fonts/iconfont.woff2
--------------------------------------------------------------------------------
/src/lib/helpers/function.ts:
--------------------------------------------------------------------------------
1 | function insertText($vm: HTMLTextAreaElement, params: any): string {
2 | const { prefix, str = '', subfix = '' } = params
3 | const value = $vm.value
4 | if ($vm.selectionStart || $vm.selectionStart === 0) {
5 | const start = $vm.selectionStart
6 | const end = $vm.selectionEnd
7 |
8 | const restoreTop = $vm.scrollTop
9 |
10 | if (start === end) {
11 | $vm.value =
12 | value.substring(0, start) +
13 | prefix +
14 | str +
15 | subfix +
16 | value.substring(end, value.length)
17 | $vm.selectionStart = start + prefix.length
18 | $vm.selectionEnd = end + prefix.length + str.length
19 | } else {
20 | $vm.value =
21 | value.substring(0, start) +
22 | prefix +
23 | value.substring(start, end) +
24 | subfix +
25 | value.substring(end, value.length)
26 | $vm.selectionStart = start + prefix.length
27 | $vm.selectionEnd = end + prefix.length
28 | }
29 |
30 | $vm.focus()
31 | if (restoreTop >= 0) {
32 | $vm.scrollTop = restoreTop
33 | }
34 | }
35 | return $vm.value
36 | }
37 |
38 | export {
39 | insertText
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/helpers/highlight.ts:
--------------------------------------------------------------------------------
1 | const Hljs = require('highlight.js/lib/highlight')
2 |
3 | Hljs.registerLanguage('css', require('highlight.js/lib/languages/css'))
4 | Hljs.registerLanguage('json', require('highlight.js/lib/languages/json'))
5 | Hljs.registerLanguage('less', require('highlight.js/lib/languages/less'))
6 | Hljs.registerLanguage('scss', require('highlight.js/lib/languages/scss'))
7 | Hljs.registerLanguage(
8 | 'javascript',
9 | require('highlight.js/lib/languages/javascript')
10 | )
11 | Hljs.registerLanguage(
12 | 'typescript',
13 | require('highlight.js/lib/languages/typescript')
14 | )
15 |
16 | export default Hljs
17 |
--------------------------------------------------------------------------------
/src/lib/helpers/keydownListen.ts:
--------------------------------------------------------------------------------
1 | const KEY_CODE = {
2 | F8: 119,
3 | F9: 120,
4 | F10: 121,
5 | F11: 122,
6 | F12: 123,
7 | B: 66,
8 | I: 73,
9 | H: 72,
10 | U: 85,
11 | D: 68,
12 | M: 77,
13 | Q: 81,
14 | O: 79,
15 | L: 76,
16 | S: 83,
17 | Z: 90,
18 | Y: 89,
19 | C: 67,
20 | T: 84,
21 | R: 82,
22 | DELETE: 8,
23 | TAB: 9,
24 | ENTER: 13,
25 | ONE: 97,
26 | TWO: 98,
27 | THREE: 99,
28 | FOUR: 100,
29 | FIVE: 101,
30 | SIX: 102,
31 | _ONE: 49,
32 | _TWO: 50,
33 | _THREE: 51,
34 | _FOUR: 52,
35 | _FIVE: 53,
36 | _SIX: 54
37 | }
38 |
39 | export default ($vm: HTMLTextAreaElement, func: any) => {
40 | $vm.addEventListener('keydown', e => {
41 | if (!(e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey) {
42 | switch (e.keyCode) {
43 | case KEY_CODE.TAB: {
44 | e.preventDefault()
45 | func('tab')
46 | break
47 | }
48 | }
49 | } else if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey) {
50 | // ctrl +
51 | switch (e.keyCode) {
52 | case KEY_CODE.Z: {
53 | // Z
54 | e.preventDefault()
55 | func('undo')
56 | break
57 | }
58 | case KEY_CODE.Y: {
59 | // Y
60 | e.preventDefault()
61 | func('redo')
62 | break
63 | }
64 | case KEY_CODE.S: {
65 | // S
66 | e.preventDefault()
67 | func('save')
68 | break
69 | }
70 | }
71 | }
72 | })
73 | }
74 |
--------------------------------------------------------------------------------
/src/lib/helpers/marked.ts:
--------------------------------------------------------------------------------
1 | import marked from 'marked'
2 | import Hljs from './highlight'
3 |
4 | marked.setOptions({
5 | renderer: new marked.Renderer(),
6 | gfm: true,
7 | tables: true,
8 | breaks: false,
9 | pedantic: false,
10 | sanitize: false,
11 | smartLists: true,
12 | smartypants: false,
13 | highlight(code: string) {
14 | return Hljs.highlightAuto(code).value
15 | }
16 | })
17 |
18 | const renderer = new marked.Renderer()
19 |
20 | // 段落解析
21 | const paragraphParse = (text: string) => `${text}
`
22 |
23 | // 链接解析
24 | const linkParse = (href: string, title: string, text: string) => {
25 | return `${text}`
29 | }
30 |
31 | renderer.paragraph = paragraphParse
32 | renderer.link = linkParse
33 |
34 | export default (content: string) => {
35 | if (typeof content !== 'string') return ''
36 |
37 | return marked(content, { renderer })
38 | }
39 |
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | import zhCN from './lang/zh-CN/index.json'
2 | import en from './lang/en/index.json'
3 | import { IToolbar, IWords } from '../index'
4 | export interface ICONFIG {
5 | language: {
6 | 'zh-CN': IWords
7 | en: IWords
8 | [key: string]: IWords
9 | }
10 | langList: string[]
11 | toolbar: IToolbar
12 | }
13 |
14 | export const CONFIG: ICONFIG = {
15 | language: {
16 | 'zh-CN': zhCN,
17 | en,
18 | },
19 | langList: ['zh-CN', 'en'],
20 | toolbar: {
21 | h1: true,
22 | h2: true,
23 | h3: true,
24 | h4: true,
25 | img: true,
26 | link: true,
27 | code: true,
28 | preview: true,
29 | expand: true,
30 | undo: true,
31 | redo: true,
32 | save: true,
33 | subfield: true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/lib/lang/en/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "placeholder": "Begin editing...",
3 | "undo": "Undo",
4 | "redo": "Redo",
5 | "h1": "Header 1",
6 | "h2": "Header 2",
7 | "h3": "Header 3",
8 | "h4": "Header 4",
9 | "img": "Image Link",
10 | "link": "Link",
11 | "code": "Code",
12 | "save": "Save",
13 | "preview": "Preview",
14 | "singleColumn": "Single Column",
15 | "doubleColumn": "Double Columns",
16 | "fullscreenOn": "FullScreen ON",
17 | "fullscreenOff": "FullScreen OFF",
18 | "addImgLink": "Add Image Link",
19 | "addImg": "Upload Image"
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/lang/zh-CN/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "placeholder": "开始编辑...",
3 | "undo": "上一步",
4 | "redo": "下一步",
5 | "h1": "一级标题",
6 | "h2": "二级标题",
7 | "h3": "三级标题",
8 | "h4": "四级标题",
9 | "img": "添加图片链接",
10 | "link": "链接",
11 | "code": "代码块",
12 | "save": "保存",
13 | "preview": "预览",
14 | "singleColumn": "单栏",
15 | "doubleColumn": "双栏",
16 | "fullscreenOn": "全屏编辑",
17 | "fullscreenOff": "退出全屏",
18 | "addImgLink": "添加图片链接",
19 | "addImg": "上传图片"
20 | }
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": true,
4 | "resolveJsonModule": true,
5 | "esModuleInterop": true,
6 | "jsx": "react",
7 | "noImplicitAny": true
8 | },
9 | "exclude": ["node_modules"]
10 | }
--------------------------------------------------------------------------------
/webpack/webpack.base.config.js:
--------------------------------------------------------------------------------
1 | // const isProd = process.env.NODE_ENV === 'production'
2 | const isDev = process.env.NODE_ENV === 'development'
3 |
4 | module.exports = {
5 | entry: './example/index.tsx',
6 | devtool: isDev && 'source-map',
7 | resolve: {
8 | extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.(js|jsx)$/,
14 | exclude: /node_modules/,
15 | use: {
16 | loader: 'babel-loader',
17 | options: {
18 | presets: ['@babel/preset-env', '@babel/preset-react'],
19 | plugins: ['@babel/plugin-proposal-class-properties']
20 | }
21 | }
22 | },
23 | {
24 | test: /\.tsx?$/,
25 | exclude: /node_modules/,
26 | use: {
27 | loader: 'ts-loader'
28 | }
29 | },
30 | {
31 | test: /\.css$/,
32 | use: [
33 | {
34 | loader: 'style-loader'
35 | },
36 | {
37 | loader: 'css-loader',
38 | options: {
39 | sourceMap: isDev,
40 | importLoaders: 1
41 | }
42 | },
43 | {
44 | loader: 'postcss-loader',
45 | options: {
46 | plugins: [require('autoprefixer')],
47 | sourceMap: isDev
48 | }
49 | }
50 | ]
51 | },
52 | {
53 | test: /\.scss$/,
54 | exclude: /\.module\.(sass|scss)$/,
55 | use: [
56 | 'style-loader',
57 | {
58 | loader: 'css-loader',
59 | options: {
60 | sourceMap: isDev
61 | }
62 | },
63 | {
64 | loader: 'postcss-loader',
65 | options: {
66 | plugins: [require('autoprefixer')],
67 | sourceMap: isDev
68 | }
69 | },
70 | {
71 | loader: 'sass-loader',
72 | options: {
73 | sourceMap: isDev
74 | }
75 | }
76 | ]
77 | },
78 | {
79 | test: /\.module\.(sass|scss)$/,
80 | use: [
81 | require.resolve('style-loader'),
82 | require.resolve('css-modules-typescript-loader'),
83 | {
84 | loader: require.resolve('css-loader'),
85 | options: {
86 | importLoaders: 2,
87 | modules: true
88 | }
89 | },
90 | {
91 | loader: 'postcss-loader',
92 | options: {
93 | plugins: [require('autoprefixer')],
94 | sourceMap: isDev
95 | }
96 | },
97 | require.resolve('sass-loader')
98 | ]
99 | },
100 | {
101 | test: /\.(woff2?|eot|ttf|svg)$/,
102 | loader: require.resolve('file-loader'),
103 | options: {
104 | name: 'static/fonts/[name].[hash:8].[ext]'
105 | }
106 | },
107 | {
108 | test: /\.md$/,
109 | loader: require.resolve('raw-loader')
110 | }
111 | ]
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/webpack/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const webpackBaseConfig = require('./webpack.base.config')
2 | const merge = require('webpack-merge')
3 | const path = require('path')
4 | const webpack = require('webpack')
5 | const HtmlWebpackPlugin = require('html-webpack-plugin')
6 |
7 | module.exports = merge(webpackBaseConfig, {
8 | mode: 'development',
9 | devtool: 'cheap-module-source-map',
10 | entry: ['./example/index.tsx'],
11 | output: {
12 | path: path.resolve(__dirname, '../dist'),
13 | filename: 'index.js'
14 | },
15 | plugins: [
16 | new HtmlWebpackPlugin({
17 | template: './example/index.html'
18 | }),
19 | new webpack.HotModuleReplacementPlugin()
20 | ],
21 | devServer: {
22 | historyApiFallback: true,
23 | disableHostCheck: true,
24 | inline: true,
25 | host: '0.0.0.0',
26 | port: 3020,
27 | hot: true
28 | }
29 | })
30 |
--------------------------------------------------------------------------------
/webpack/webpack.dist.config.js:
--------------------------------------------------------------------------------
1 | const webpackBaseConfig = require('./webpack.base.config')
2 | const merge = require('webpack-merge')
3 | const path = require('path')
4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin')
5 |
6 | module.exports = merge(webpackBaseConfig, {
7 | mode: 'production',
8 | entry: './src/index.tsx',
9 | output: {
10 | path: path.resolve(__dirname, '../dist'),
11 | filename: 'index.js',
12 | publicPath: '/',
13 | libraryTarget: 'umd'
14 | },
15 | plugins: [new CleanWebpackPlugin()]
16 | })
17 |
--------------------------------------------------------------------------------
/webpack/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | const webpackBaseConfig = require('./webpack.base.config')
2 | const merge = require('webpack-merge')
3 | const path = require('path')
4 | const HtmlWebpackPlugin = require('html-webpack-plugin')
5 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
6 | const { CleanWebpackPlugin } = require('clean-webpack-plugin')
7 | const webpack = require('webpack')
8 |
9 | module.exports = merge(webpackBaseConfig, {
10 | mode: 'development',
11 | entry: ['./example/index.tsx'],
12 | output: {
13 | path: path.resolve(__dirname, '../playground'),
14 | filename: 'index.js',
15 | publicPath: '/',
16 | libraryTarget: 'umd'
17 | },
18 | plugins: [
19 | new CleanWebpackPlugin(),
20 | new HtmlWebpackPlugin({
21 | template: './example/index.html'
22 | }),
23 | new webpack.DefinePlugin({
24 | 'process.env.NODE_ENV': JSON.stringify('production')
25 | }),
26 | new UglifyJsPlugin()
27 | ]
28 | })
29 |
--------------------------------------------------------------------------------