forked from Gitlink/forgeplus-react
md p标签不换行
This commit is contained in:
parent
efc96cfc8c
commit
cefd974498
|
@ -66,6 +66,7 @@ body {
|
|||
margin:10px 0px!important;
|
||||
font-size: 16px !important;
|
||||
line-height: 2 !important;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.markdown-body>p {
|
||||
|
|
|
@ -78,14 +78,6 @@ export function setImagesUrl(path){
|
|||
}
|
||||
|
||||
export function getUrl(path, goTest) {
|
||||
// https://www.educoder.net
|
||||
// https://testbdweb.trustie.net
|
||||
|
||||
// 如果想所有url定位到测试版,可以反注释掉下面这行
|
||||
//goTest = true
|
||||
// testbdweb.educoder.net testbdweb.trustie.net
|
||||
// const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000'
|
||||
// const local = 'https://testeduplus2.educoder.net'
|
||||
const local = 'https://testforgeplus.trustie.net'
|
||||
if (isDev) {
|
||||
return `${local}${path?path:''}`
|
||||
|
|
|
@ -1,8 +1,55 @@
|
|||
import marked from 'marked'
|
||||
import { escape, unescape } from 'marked/src/helpers'
|
||||
import { renderToString } from 'katex';
|
||||
import { escape, rtrim } from 'marked/src/helpers'
|
||||
import { renderToString } from 'katex'
|
||||
|
||||
const latexRegex = /\$+([^\$\n]+?)\$+/g
|
||||
function unescape(str) {
|
||||
str = str
|
||||
.replace(/( |\u00a0| )/g, '')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/</g, '<')
|
||||
.replace(/\\$/g, '')
|
||||
.replace(/^\\(?:{)/, '\\\\{')
|
||||
if (!str.match(/\S/)) {
|
||||
return '';
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
function toKatex(str) {
|
||||
return renderToString(unescape(str), {
|
||||
throwOnError: false
|
||||
})
|
||||
}
|
||||
|
||||
function indentCodeCompensation(raw, text) {
|
||||
const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
|
||||
|
||||
if (matchIndentToCode === null) {
|
||||
return text;
|
||||
}
|
||||
|
||||
const indentToCode = matchIndentToCode[1];
|
||||
|
||||
return text
|
||||
.split('\n')
|
||||
.map(node => {
|
||||
const matchIndentInNode = node.match(/^\s+/);
|
||||
if (matchIndentInNode === null) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const [indentInNode] = matchIndentInNode;
|
||||
|
||||
if (indentInNode.length >= indentToCode.length) {
|
||||
return node.slice(indentToCode.length);
|
||||
}
|
||||
|
||||
return node;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
const latexRegex = /\`?\${2}([^\$\n]+?)\${2}\`?/g
|
||||
//兼容之前的 ##标题式写法
|
||||
const headingRegex = /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/
|
||||
let toc = []
|
||||
|
@ -40,36 +87,75 @@ export function getTocContent() {
|
|||
|
||||
const tokenizer = {
|
||||
heading(src) {
|
||||
const cap = headingRegex.exec(src);
|
||||
const cap = headingRegex.exec(src)
|
||||
if (cap) {
|
||||
return {
|
||||
type: 'heading',
|
||||
raw: cap[0],
|
||||
depth: cap[1].length,
|
||||
text: cap[2]
|
||||
}
|
||||
}
|
||||
},
|
||||
paragraph(src) {
|
||||
const cap = this.rules.block.paragraph.exec(src)
|
||||
let text = cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
|
||||
let match = text.match(latexRegex)
|
||||
if (match) {
|
||||
text = text.replace(latexRegex, (_, $1) => {
|
||||
return toKatex($1)
|
||||
})
|
||||
}
|
||||
if (cap) {
|
||||
return {
|
||||
type: 'paragraph',
|
||||
raw: cap[0],
|
||||
text
|
||||
};
|
||||
}
|
||||
},
|
||||
codespan(src) {
|
||||
const cap = this.rules.inline.code.exec(src);
|
||||
code(src, tokens) {
|
||||
const cap = this.rules.block.code.exec(src)
|
||||
if (cap) {
|
||||
let text = cap[2].replace(/\n/g, ' ');
|
||||
const hasNonSpaceChars = /[^ ]/.test(text);
|
||||
const hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
|
||||
if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
|
||||
text = text.substring(1, text.length - 1)
|
||||
const lastToken = tokens[tokens.length - 1];
|
||||
// An indented code block cannot interrupt a paragraph.
|
||||
if (lastToken && lastToken.type === 'paragraph') {
|
||||
return {
|
||||
raw: cap[0],
|
||||
text: cap[0].trimRight()
|
||||
}
|
||||
}
|
||||
|
||||
let text = cap[0].replace(/^ {4}/gm, '')
|
||||
text = !this.options.pedantic ? rtrim(text, '\n') : text
|
||||
let match = text.match(latexRegex)
|
||||
if (match) {
|
||||
text = text.replace(latexRegex, (_, $1) => {
|
||||
return renderToString(unescape($1))
|
||||
return toKatex($1)
|
||||
})
|
||||
} else {
|
||||
text = escape(text, true);
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'code',
|
||||
raw: cap[0],
|
||||
codeBlockStyle: 'indented',
|
||||
text
|
||||
}
|
||||
}
|
||||
},
|
||||
fences(src) {
|
||||
const cap = this.rules.block.fences.exec(src)
|
||||
if (cap) {
|
||||
const raw = cap[0]
|
||||
let text = indentCodeCompensation(raw, cap[3] || '')
|
||||
const lang = cap[2] ? cap[2].trim() : cap[2]
|
||||
if (['latex', 'katex', 'math'].indexOf(lang) >= 0) {
|
||||
text = toKatex(text)
|
||||
}
|
||||
return {
|
||||
type: 'codespan',
|
||||
raw: cap[0],
|
||||
type: 'code',
|
||||
raw,
|
||||
lang,
|
||||
text
|
||||
}
|
||||
}
|
||||
|
@ -86,19 +172,10 @@ const renderer = {
|
|||
}
|
||||
|
||||
if (['latex', 'katex', 'math'].indexOf(lang) >= 0) {
|
||||
return `<p class='editormd-tex'>${renderToString(unescape(code))}</p>`
|
||||
return `<p class='editormd-tex'>${code}</p>`
|
||||
} else {
|
||||
return `<pre class="prettyprint linenums"><code class="language-${infostring}">${escaped ? code : escape(code, true)}</code></pre>\n`
|
||||
}
|
||||
}
|
||||
, paragraph(text) {
|
||||
let match = text.match(latexRegex)
|
||||
if (match) {
|
||||
text = text.replace(latexRegex, (_, $1) => {
|
||||
return renderToString(unescape($1))
|
||||
})
|
||||
}
|
||||
return '<p>' + text + '</p>\n';
|
||||
},
|
||||
heading(text, level, raw, slugger) {
|
||||
let anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w\\u4e00-\\u9fa5]]+/g, '-');
|
||||
|
|
|
@ -14,7 +14,7 @@ export default ({ value = "", is_md = true, className, style = {} }) => {
|
|||
}
|
||||
|
||||
html = html.replace(/▁/g, "▁▁▁");
|
||||
// html = html.replace(/\n/g,"<br/>");
|
||||
// html = html.replace(/\n/g,"<br />");
|
||||
const el = useRef();
|
||||
|
||||
function onAncherHandler(e) {
|
||||
|
|
|
@ -73,7 +73,7 @@ class Index extends Component {
|
|||
array && this.props.load && this.props.load(array);
|
||||
}
|
||||
|
||||
beforeUpload = (file)=>{
|
||||
beforeUpload = (file) => {
|
||||
const { size } = this.props;
|
||||
const isLt100M = file.size / 1024 / 1024 < size;
|
||||
if (!isLt100M) {
|
||||
|
@ -84,7 +84,7 @@ class Index extends Component {
|
|||
|
||||
render() {
|
||||
//判断是否已经提交,如已提交评论则上一条评论数据清除
|
||||
const { isComplete , icon } = this.props;
|
||||
const { isComplete, icon } = this.props;
|
||||
const { fileList } = this.state;
|
||||
|
||||
let list = isComplete === true ? fileList : undefined;
|
||||
|
@ -94,14 +94,14 @@ class Index extends Component {
|
|||
action: `${getUploadActionUrl()}`,
|
||||
onChange: this.handleChange,
|
||||
onRemove: this.onAttachmentRemove,
|
||||
beforeUpload:this.beforeUpload
|
||||
beforeUpload: this.beforeUpload
|
||||
};
|
||||
|
||||
return (
|
||||
<Dragger {...upload} className={this.props.className}>
|
||||
{ icon || <Icon type="inbox" />}
|
||||
<p className="ant-upload-text font-14">拖动文件或<span className="color-blue">点击此处上传</span></p>
|
||||
</Dragger>
|
||||
{icon || <Icon type="inbox" />}
|
||||
<p className="ant-upload-text font-14">拖动文件或<span className="color-blue">点击此处上传</span></p>
|
||||
</Dragger>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import RenderHtml from "../../components/render-html";
|
|||
import ChildrenComments from "./children_comments";
|
||||
import "../Order/order.css";
|
||||
const { TabPane } = Tabs;
|
||||
class comments extends Component {
|
||||
class comments extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
|
|
@ -75,14 +75,14 @@ function md_elocalStorage(editor, mdu, id) {
|
|||
}
|
||||
|
||||
|
||||
export default ({ mdID,onChange,autoFocus,onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch, showNullButton = false, showResizeBar = false, startInit = true }) => {
|
||||
export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch, showNullButton = false, showResizeBar = false, startInit = true }) => {
|
||||
|
||||
const editorEl = useRef()
|
||||
const resizeBarEl = useRef()
|
||||
const [editorInstance, setEditorInstance] = useState()
|
||||
const containerId = `mdEditor_${mdID}`
|
||||
const editorBodyId = `mdEditors_${mdID}`
|
||||
const tipId = `e_tips_mdEditor_${mdID}`
|
||||
const tipId = `e_tips_mdEditor_${mdID}`
|
||||
|
||||
function onLayout() {
|
||||
let ro
|
||||
|
@ -92,10 +92,7 @@ export default ({ mdID,onChange,autoFocus,onCMBeforeChange, onCMBlur, error = fa
|
|||
if (entry.target.offsetHeight > 0 || entry.target.offsetWidth > 0) {
|
||||
editorInstance.resize()
|
||||
editorInstance.cm.refresh()
|
||||
// if(autofocus){
|
||||
// editorInstance.cm.focus()
|
||||
// }
|
||||
|
||||
editorInstance.cm.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -105,7 +102,6 @@ export default ({ mdID,onChange,autoFocus,onCMBeforeChange, onCMBlur, error = fa
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (editorInstance) {
|
||||
return
|
||||
}
|
||||
|
@ -124,7 +120,7 @@ export default ({ mdID,onChange,autoFocus,onCMBeforeChange, onCMBlur, error = fa
|
|||
searchReplace: true,
|
||||
htmlDecode: "style,script,iframe",
|
||||
sequenceDiagram: true,
|
||||
autoFocus: autoFocus === undefined ? false : autoFocus,
|
||||
autoFocus: false,
|
||||
watch: watch === undefined ? true : watch,
|
||||
|
||||
saveHTMLToTextarea: true,
|
||||
|
@ -256,8 +252,8 @@ export default ({ mdID,onChange,autoFocus,onCMBeforeChange, onCMBlur, error = fa
|
|||
}
|
||||
}
|
||||
}, [
|
||||
editorInstance, resizeBarEl
|
||||
])
|
||||
editorInstance, resizeBarEl
|
||||
])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
|
Loading…
Reference in New Issue