Add code block actions plugin extensibility (#24348)
* Add code block actions plugin extensibility * Fixing tests * Fixing linter errors * Move Plugin components left of label --------- Co-authored-by: Christopher Speller <crspeller@gmail.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
dbb39e44cc
Коммит
8c8b8b7e79
@@ -1,6 +1,18 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`codeBlock should render html code block with proper indentation after syntax highlighting 1`] = `
|
exports[`codeBlock should render html code block with proper indentation after syntax highlighting 1`] = `
|
||||||
|
<Provider
|
||||||
|
store={
|
||||||
|
Object {
|
||||||
|
"clearActions": [Function],
|
||||||
|
"dispatch": [Function],
|
||||||
|
"getActions": [Function],
|
||||||
|
"getState": [Function],
|
||||||
|
"replaceReducer": [Function],
|
||||||
|
"subscribe": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
<IntlProvider
|
<IntlProvider
|
||||||
defaultFormats={Object {}}
|
defaultFormats={Object {}}
|
||||||
defaultLocale="en"
|
defaultLocale="en"
|
||||||
@@ -175,9 +187,42 @@ exports[`codeBlock should render html code block with proper indentation after s
|
|||||||
</div>
|
</div>
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
|
</Provider>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`codeBlock should render html code block with proper indentation before syntax highlighting 1`] = `
|
exports[`codeBlock should render html code block with proper indentation before syntax highlighting 1`] = `
|
||||||
|
<Provider
|
||||||
|
store={
|
||||||
|
Object {
|
||||||
|
"clearActions": [Function],
|
||||||
|
"dispatch": [Function],
|
||||||
|
"getActions": [Function],
|
||||||
|
"getState": [Function],
|
||||||
|
"replaceReducer": [Function],
|
||||||
|
"subscribe": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IntlProvider
|
||||||
|
defaultFormats={Object {}}
|
||||||
|
defaultLocale="en"
|
||||||
|
fallbackOnEmptyString={true}
|
||||||
|
formats={Object {}}
|
||||||
|
locale="en"
|
||||||
|
messages={Object {}}
|
||||||
|
onError={[Function]}
|
||||||
|
onWarn={[Function]}
|
||||||
|
textComponent={Symbol(react.fragment)}
|
||||||
|
>
|
||||||
|
<CodeBlock
|
||||||
|
code="\`\`\`html
|
||||||
|
<div className='myClass'>
|
||||||
|
<a href='https://randomgibberishurl.com'>ClickMe</a>
|
||||||
|
</div>
|
||||||
|
\`\`\`
|
||||||
|
"
|
||||||
|
language="html"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className="post-code"
|
className="post-code"
|
||||||
>
|
>
|
||||||
@@ -193,7 +238,110 @@ exports[`codeBlock should render html code block with proper indentation before
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
"
|
"
|
||||||
placement="top"
|
placement="top"
|
||||||
|
>
|
||||||
|
<OverlayTrigger
|
||||||
|
defaultOverlayShown={false}
|
||||||
|
delayShow={400}
|
||||||
|
overlay={
|
||||||
|
<Tooltip
|
||||||
|
bsClass="tooltip"
|
||||||
|
id="copyButton"
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Copy code"
|
||||||
|
id="copy.code.message"
|
||||||
/>
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
shouldUpdatePosition={true}
|
||||||
|
trigger={
|
||||||
|
Array [
|
||||||
|
"hover",
|
||||||
|
"focus",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<OverlayTrigger
|
||||||
|
defaultOverlayShown={false}
|
||||||
|
delayShow={400}
|
||||||
|
overlay={
|
||||||
|
<OverlayWrapper
|
||||||
|
bsClass="tooltip"
|
||||||
|
id="copyButton"
|
||||||
|
intl={
|
||||||
|
Object {
|
||||||
|
"$t": [Function],
|
||||||
|
"defaultFormats": Object {},
|
||||||
|
"defaultLocale": "en",
|
||||||
|
"defaultRichTextElements": undefined,
|
||||||
|
"fallbackOnEmptyString": true,
|
||||||
|
"formatDate": [Function],
|
||||||
|
"formatDateTimeRange": [Function],
|
||||||
|
"formatDateToParts": [Function],
|
||||||
|
"formatDisplayName": [Function],
|
||||||
|
"formatList": [Function],
|
||||||
|
"formatListToParts": [Function],
|
||||||
|
"formatMessage": [Function],
|
||||||
|
"formatNumber": [Function],
|
||||||
|
"formatNumberToParts": [Function],
|
||||||
|
"formatPlural": [Function],
|
||||||
|
"formatRelativeTime": [Function],
|
||||||
|
"formatTime": [Function],
|
||||||
|
"formatTimeToParts": [Function],
|
||||||
|
"formats": Object {},
|
||||||
|
"formatters": Object {
|
||||||
|
"getDateTimeFormat": [Function],
|
||||||
|
"getDisplayNames": [Function],
|
||||||
|
"getListFormat": [Function],
|
||||||
|
"getMessageFormat": [Function],
|
||||||
|
"getNumberFormat": [Function],
|
||||||
|
"getPluralRules": [Function],
|
||||||
|
"getRelativeTimeFormat": [Function],
|
||||||
|
},
|
||||||
|
"locale": "en",
|
||||||
|
"messages": Object {},
|
||||||
|
"onError": [Function],
|
||||||
|
"onWarn": [Function],
|
||||||
|
"textComponent": Symbol(react.fragment),
|
||||||
|
"timeZone": undefined,
|
||||||
|
"wrapRichTextChunksInFragment": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Copy code"
|
||||||
|
id="copy.code.message"
|
||||||
|
/>
|
||||||
|
</OverlayWrapper>
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
shouldUpdatePosition={true}
|
||||||
|
trigger={
|
||||||
|
Array [
|
||||||
|
"hover",
|
||||||
|
"focus",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="post-code__clipboard"
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onMouseOut={[Function]}
|
||||||
|
onMouseOver={[Function]}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="icon icon-content-copy"
|
||||||
|
role="button"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</CopyButton>
|
||||||
<span
|
<span
|
||||||
className="post-code__language"
|
className="post-code__language"
|
||||||
>
|
>
|
||||||
@@ -217,9 +365,9 @@ exports[`codeBlock should render html code block with proper indentation before
|
|||||||
dangerouslySetInnerHTML={
|
dangerouslySetInnerHTML={
|
||||||
Object {
|
Object {
|
||||||
"__html": "\`\`\`html
|
"__html": "\`\`\`html
|
||||||
<div className='myClass'>
|
<span class=\\"hljs-tag\\"><<span class=\\"hljs-name\\">div</span> <span class=\\"hljs-attr\\">className</span>=<span class=\\"hljs-string\\">'myClass'</span>></span>
|
||||||
<a href='https://randomgibberishurl.com'>ClickMe</a>
|
<span class=\\"hljs-tag\\"><<span class=\\"hljs-name\\">a</span> <span class=\\"hljs-attr\\">href</span>=<span class=\\"hljs-string\\">'https://randomgibberishurl.com'</span>></span>ClickMe<span class=\\"hljs-tag\\"></<span class=\\"hljs-name\\">a</span>></span>
|
||||||
</div>
|
<span class=\\"hljs-tag\\"></<span class=\\"hljs-name\\">div</span>></span>
|
||||||
\`\`\`
|
\`\`\`
|
||||||
",
|
",
|
||||||
}
|
}
|
||||||
@@ -227,9 +375,24 @@ exports[`codeBlock should render html code block with proper indentation before
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</CodeBlock>
|
||||||
|
</IntlProvider>
|
||||||
|
</Provider>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`codeBlock should render typescript code block after syntax highlighting 1`] = `
|
exports[`codeBlock should render typescript code block after syntax highlighting 1`] = `
|
||||||
|
<Provider
|
||||||
|
store={
|
||||||
|
Object {
|
||||||
|
"clearActions": [Function],
|
||||||
|
"dispatch": [Function],
|
||||||
|
"getActions": [Function],
|
||||||
|
"getState": [Function],
|
||||||
|
"replaceReducer": [Function],
|
||||||
|
"subscribe": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
<IntlProvider
|
<IntlProvider
|
||||||
defaultFormats={Object {}}
|
defaultFormats={Object {}}
|
||||||
defaultLocale="en"
|
defaultLocale="en"
|
||||||
@@ -404,9 +567,42 @@ const myFunction = () => {
|
|||||||
</div>
|
</div>
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
|
</Provider>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`codeBlock should render typescript code block before syntax highlighting 1`] = `
|
exports[`codeBlock should render typescript code block before syntax highlighting 1`] = `
|
||||||
|
<Provider
|
||||||
|
store={
|
||||||
|
Object {
|
||||||
|
"clearActions": [Function],
|
||||||
|
"dispatch": [Function],
|
||||||
|
"getActions": [Function],
|
||||||
|
"getState": [Function],
|
||||||
|
"replaceReducer": [Function],
|
||||||
|
"subscribe": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IntlProvider
|
||||||
|
defaultFormats={Object {}}
|
||||||
|
defaultLocale="en"
|
||||||
|
fallbackOnEmptyString={true}
|
||||||
|
formats={Object {}}
|
||||||
|
locale="en"
|
||||||
|
messages={Object {}}
|
||||||
|
onError={[Function]}
|
||||||
|
onWarn={[Function]}
|
||||||
|
textComponent={Symbol(react.fragment)}
|
||||||
|
>
|
||||||
|
<CodeBlock
|
||||||
|
code="\`\`\`typescript
|
||||||
|
const myFunction = () => {
|
||||||
|
console.log('This is a meaningful function');
|
||||||
|
};
|
||||||
|
\`\`\`
|
||||||
|
"
|
||||||
|
language="typescript"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className="post-code"
|
className="post-code"
|
||||||
>
|
>
|
||||||
@@ -422,7 +618,110 @@ const myFunction = () => {
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
"
|
"
|
||||||
placement="top"
|
placement="top"
|
||||||
|
>
|
||||||
|
<OverlayTrigger
|
||||||
|
defaultOverlayShown={false}
|
||||||
|
delayShow={400}
|
||||||
|
overlay={
|
||||||
|
<Tooltip
|
||||||
|
bsClass="tooltip"
|
||||||
|
id="copyButton"
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Copy code"
|
||||||
|
id="copy.code.message"
|
||||||
/>
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
shouldUpdatePosition={true}
|
||||||
|
trigger={
|
||||||
|
Array [
|
||||||
|
"hover",
|
||||||
|
"focus",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<OverlayTrigger
|
||||||
|
defaultOverlayShown={false}
|
||||||
|
delayShow={400}
|
||||||
|
overlay={
|
||||||
|
<OverlayWrapper
|
||||||
|
bsClass="tooltip"
|
||||||
|
id="copyButton"
|
||||||
|
intl={
|
||||||
|
Object {
|
||||||
|
"$t": [Function],
|
||||||
|
"defaultFormats": Object {},
|
||||||
|
"defaultLocale": "en",
|
||||||
|
"defaultRichTextElements": undefined,
|
||||||
|
"fallbackOnEmptyString": true,
|
||||||
|
"formatDate": [Function],
|
||||||
|
"formatDateTimeRange": [Function],
|
||||||
|
"formatDateToParts": [Function],
|
||||||
|
"formatDisplayName": [Function],
|
||||||
|
"formatList": [Function],
|
||||||
|
"formatListToParts": [Function],
|
||||||
|
"formatMessage": [Function],
|
||||||
|
"formatNumber": [Function],
|
||||||
|
"formatNumberToParts": [Function],
|
||||||
|
"formatPlural": [Function],
|
||||||
|
"formatRelativeTime": [Function],
|
||||||
|
"formatTime": [Function],
|
||||||
|
"formatTimeToParts": [Function],
|
||||||
|
"formats": Object {},
|
||||||
|
"formatters": Object {
|
||||||
|
"getDateTimeFormat": [Function],
|
||||||
|
"getDisplayNames": [Function],
|
||||||
|
"getListFormat": [Function],
|
||||||
|
"getMessageFormat": [Function],
|
||||||
|
"getNumberFormat": [Function],
|
||||||
|
"getPluralRules": [Function],
|
||||||
|
"getRelativeTimeFormat": [Function],
|
||||||
|
},
|
||||||
|
"locale": "en",
|
||||||
|
"messages": Object {},
|
||||||
|
"onError": [Function],
|
||||||
|
"onWarn": [Function],
|
||||||
|
"textComponent": Symbol(react.fragment),
|
||||||
|
"timeZone": undefined,
|
||||||
|
"wrapRichTextChunksInFragment": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Copy code"
|
||||||
|
id="copy.code.message"
|
||||||
|
/>
|
||||||
|
</OverlayWrapper>
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
shouldUpdatePosition={true}
|
||||||
|
trigger={
|
||||||
|
Array [
|
||||||
|
"hover",
|
||||||
|
"focus",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="post-code__clipboard"
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onMouseOut={[Function]}
|
||||||
|
onMouseOver={[Function]}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="icon icon-content-copy"
|
||||||
|
role="button"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</CopyButton>
|
||||||
<span
|
<span
|
||||||
className="post-code__language"
|
className="post-code__language"
|
||||||
>
|
>
|
||||||
@@ -445,20 +744,35 @@ const myFunction = () => {
|
|||||||
<code
|
<code
|
||||||
dangerouslySetInnerHTML={
|
dangerouslySetInnerHTML={
|
||||||
Object {
|
Object {
|
||||||
"__html": "\`\`\`typescript
|
"__html": "<span class=\\"hljs-string\\">\`\`</span><span class=\\"hljs-string\\">\`typescript
|
||||||
const myFunction = () => {
|
const myFunction = () => {
|
||||||
console.log('This is a meaningful function');
|
console.log('This is a meaningful function');
|
||||||
};
|
};
|
||||||
\`\`\`
|
\`</span><span class=\\"hljs-string\\">\`\`</span>
|
||||||
",
|
",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</CodeBlock>
|
||||||
|
</IntlProvider>
|
||||||
|
</Provider>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`codeBlock should render unknown language after syntax highlighting 1`] = `
|
exports[`codeBlock should render unknown language after syntax highlighting 1`] = `
|
||||||
|
<Provider
|
||||||
|
store={
|
||||||
|
Object {
|
||||||
|
"clearActions": [Function],
|
||||||
|
"dispatch": [Function],
|
||||||
|
"getActions": [Function],
|
||||||
|
"getState": [Function],
|
||||||
|
"replaceReducer": [Function],
|
||||||
|
"subscribe": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
<IntlProvider
|
<IntlProvider
|
||||||
defaultFormats={Object {}}
|
defaultFormats={Object {}}
|
||||||
defaultLocale="en"
|
defaultLocale="en"
|
||||||
@@ -615,9 +929,41 @@ it shouldn't highlight, it's just garbage
|
|||||||
</div>
|
</div>
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
|
</Provider>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`codeBlock should render unknown language before syntax highlighting 1`] = `
|
exports[`codeBlock should render unknown language before syntax highlighting 1`] = `
|
||||||
|
<Provider
|
||||||
|
store={
|
||||||
|
Object {
|
||||||
|
"clearActions": [Function],
|
||||||
|
"dispatch": [Function],
|
||||||
|
"getActions": [Function],
|
||||||
|
"getState": [Function],
|
||||||
|
"replaceReducer": [Function],
|
||||||
|
"subscribe": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IntlProvider
|
||||||
|
defaultFormats={Object {}}
|
||||||
|
defaultLocale="en"
|
||||||
|
fallbackOnEmptyString={true}
|
||||||
|
formats={Object {}}
|
||||||
|
locale="en"
|
||||||
|
messages={Object {}}
|
||||||
|
onError={[Function]}
|
||||||
|
onWarn={[Function]}
|
||||||
|
textComponent={Symbol(react.fragment)}
|
||||||
|
>
|
||||||
|
<CodeBlock
|
||||||
|
code="\`\`\`unknownLanguage
|
||||||
|
this is my unknown language
|
||||||
|
it shouldn't highlight, it's just garbage
|
||||||
|
\`\`\`
|
||||||
|
"
|
||||||
|
language="unknownLanguage"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className="post-code"
|
className="post-code"
|
||||||
>
|
>
|
||||||
@@ -632,7 +978,110 @@ it shouldn't highlight, it's just garbage
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
"
|
"
|
||||||
placement="top"
|
placement="top"
|
||||||
|
>
|
||||||
|
<OverlayTrigger
|
||||||
|
defaultOverlayShown={false}
|
||||||
|
delayShow={400}
|
||||||
|
overlay={
|
||||||
|
<Tooltip
|
||||||
|
bsClass="tooltip"
|
||||||
|
id="copyButton"
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Copy code"
|
||||||
|
id="copy.code.message"
|
||||||
/>
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
shouldUpdatePosition={true}
|
||||||
|
trigger={
|
||||||
|
Array [
|
||||||
|
"hover",
|
||||||
|
"focus",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<OverlayTrigger
|
||||||
|
defaultOverlayShown={false}
|
||||||
|
delayShow={400}
|
||||||
|
overlay={
|
||||||
|
<OverlayWrapper
|
||||||
|
bsClass="tooltip"
|
||||||
|
id="copyButton"
|
||||||
|
intl={
|
||||||
|
Object {
|
||||||
|
"$t": [Function],
|
||||||
|
"defaultFormats": Object {},
|
||||||
|
"defaultLocale": "en",
|
||||||
|
"defaultRichTextElements": undefined,
|
||||||
|
"fallbackOnEmptyString": true,
|
||||||
|
"formatDate": [Function],
|
||||||
|
"formatDateTimeRange": [Function],
|
||||||
|
"formatDateToParts": [Function],
|
||||||
|
"formatDisplayName": [Function],
|
||||||
|
"formatList": [Function],
|
||||||
|
"formatListToParts": [Function],
|
||||||
|
"formatMessage": [Function],
|
||||||
|
"formatNumber": [Function],
|
||||||
|
"formatNumberToParts": [Function],
|
||||||
|
"formatPlural": [Function],
|
||||||
|
"formatRelativeTime": [Function],
|
||||||
|
"formatTime": [Function],
|
||||||
|
"formatTimeToParts": [Function],
|
||||||
|
"formats": Object {},
|
||||||
|
"formatters": Object {
|
||||||
|
"getDateTimeFormat": [Function],
|
||||||
|
"getDisplayNames": [Function],
|
||||||
|
"getListFormat": [Function],
|
||||||
|
"getMessageFormat": [Function],
|
||||||
|
"getNumberFormat": [Function],
|
||||||
|
"getPluralRules": [Function],
|
||||||
|
"getRelativeTimeFormat": [Function],
|
||||||
|
},
|
||||||
|
"locale": "en",
|
||||||
|
"messages": Object {},
|
||||||
|
"onError": [Function],
|
||||||
|
"onWarn": [Function],
|
||||||
|
"textComponent": Symbol(react.fragment),
|
||||||
|
"timeZone": undefined,
|
||||||
|
"wrapRichTextChunksInFragment": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Copy code"
|
||||||
|
id="copy.code.message"
|
||||||
|
/>
|
||||||
|
</OverlayWrapper>
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
shouldUpdatePosition={true}
|
||||||
|
trigger={
|
||||||
|
Array [
|
||||||
|
"hover",
|
||||||
|
"focus",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="post-code__clipboard"
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onMouseOut={[Function]}
|
||||||
|
onMouseOver={[Function]}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="icon icon-content-copy"
|
||||||
|
role="button"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</CopyButton>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="hljs"
|
className="hljs"
|
||||||
@@ -650,4 +1099,7 @@ it shouldn't highlight, it's just garbage
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</CodeBlock>
|
||||||
|
</IntlProvider>
|
||||||
|
</Provider>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {mount, ReactWrapper, shallow} from 'enzyme';
|
import {mount, ReactWrapper} from 'enzyme';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {act} from 'react-dom/test-utils';
|
import {act} from 'react-dom/test-utils';
|
||||||
import {IntlProvider} from 'react-intl';
|
import {IntlProvider} from 'react-intl';
|
||||||
|
import {Provider as ReduxProvider} from 'react-redux';
|
||||||
|
|
||||||
|
import mockStore from 'tests/test_store';
|
||||||
|
|
||||||
import CodeBlock from './code_block';
|
import CodeBlock from './code_block';
|
||||||
|
|
||||||
@@ -20,6 +23,11 @@ const actImmediate = (wrapper: ReactWrapper) =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
describe('codeBlock', () => {
|
describe('codeBlock', () => {
|
||||||
|
const state = {
|
||||||
|
plugins: {components: {CodeBlockAction: []}},
|
||||||
|
};
|
||||||
|
const store = mockStore(state);
|
||||||
|
|
||||||
test('should render typescript code block before syntax highlighting', async () => {
|
test('should render typescript code block before syntax highlighting', async () => {
|
||||||
const language = 'typescript';
|
const language = 'typescript';
|
||||||
const input = `\`\`\`${language}
|
const input = `\`\`\`${language}
|
||||||
@@ -29,12 +37,17 @@ const myFunction = () => {
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const wrapper = shallow(
|
const wrapper = mount(
|
||||||
|
<ReduxProvider store={store}>
|
||||||
|
<IntlProvider locale='en'>
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
code={input}
|
code={input}
|
||||||
language={language}
|
language={language}
|
||||||
/>,
|
/>
|
||||||
|
</IntlProvider>
|
||||||
|
</ReduxProvider>,
|
||||||
);
|
);
|
||||||
|
await actImmediate(wrapper);
|
||||||
|
|
||||||
const languageHeader = wrapper.find('span.post-code__language').text();
|
const languageHeader = wrapper.find('span.post-code__language').text();
|
||||||
const lineNumbersDiv = wrapper.find('.post-code__line-numbers').exists();
|
const lineNumbersDiv = wrapper.find('.post-code__line-numbers').exists();
|
||||||
@@ -55,12 +68,14 @@ const myFunction = () => {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
|
<ReduxProvider store={store}>
|
||||||
<IntlProvider locale='en'>
|
<IntlProvider locale='en'>
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
code={input}
|
code={input}
|
||||||
language={language}
|
language={language}
|
||||||
/>
|
/>
|
||||||
</IntlProvider>,
|
</IntlProvider>
|
||||||
|
</ReduxProvider>,
|
||||||
);
|
);
|
||||||
await actImmediate(wrapper);
|
await actImmediate(wrapper);
|
||||||
|
|
||||||
@@ -73,7 +88,7 @@ const myFunction = () => {
|
|||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render html code block with proper indentation before syntax highlighting', () => {
|
test('should render html code block with proper indentation before syntax highlighting', async () => {
|
||||||
const language = 'html';
|
const language = 'html';
|
||||||
const input = `\`\`\`${language}
|
const input = `\`\`\`${language}
|
||||||
<div className='myClass'>
|
<div className='myClass'>
|
||||||
@@ -82,12 +97,17 @@ const myFunction = () => {
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const wrapper = shallow(
|
const wrapper = mount(
|
||||||
|
<ReduxProvider store={store}>
|
||||||
|
<IntlProvider locale='en'>
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
code={input}
|
code={input}
|
||||||
language={language}
|
language={language}
|
||||||
/>,
|
/>
|
||||||
|
</IntlProvider>
|
||||||
|
</ReduxProvider>,
|
||||||
);
|
);
|
||||||
|
await actImmediate(wrapper);
|
||||||
|
|
||||||
const languageHeader = wrapper.find('span.post-code__language').text();
|
const languageHeader = wrapper.find('span.post-code__language').text();
|
||||||
const lineNumbersDiv = wrapper.find('.post-code__line-numbers').exists();
|
const lineNumbersDiv = wrapper.find('.post-code__line-numbers').exists();
|
||||||
@@ -107,12 +127,14 @@ const myFunction = () => {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
|
<ReduxProvider store={store}>
|
||||||
<IntlProvider locale='en'>
|
<IntlProvider locale='en'>
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
code={input}
|
code={input}
|
||||||
language={language}
|
language={language}
|
||||||
/>
|
/>
|
||||||
</IntlProvider>,
|
</IntlProvider>
|
||||||
|
</ReduxProvider>,
|
||||||
);
|
);
|
||||||
await actImmediate(wrapper);
|
await actImmediate(wrapper);
|
||||||
|
|
||||||
@@ -124,7 +146,7 @@ const myFunction = () => {
|
|||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render unknown language before syntax highlighting', () => {
|
test('should render unknown language before syntax highlighting', async () => {
|
||||||
const language = 'unknownLanguage';
|
const language = 'unknownLanguage';
|
||||||
const input = `\`\`\`${language}
|
const input = `\`\`\`${language}
|
||||||
this is my unknown language
|
this is my unknown language
|
||||||
@@ -132,12 +154,17 @@ it shouldn't highlight, it's just garbage
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const wrapper = shallow(
|
const wrapper = mount(
|
||||||
|
<ReduxProvider store={store}>
|
||||||
|
<IntlProvider locale='en'>
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
code={input}
|
code={input}
|
||||||
language={language}
|
language={language}
|
||||||
/>,
|
/>
|
||||||
|
</IntlProvider>
|
||||||
|
</ReduxProvider>,
|
||||||
);
|
);
|
||||||
|
await actImmediate(wrapper);
|
||||||
|
|
||||||
const languageHeader = wrapper.find('span.post-code__language').exists();
|
const languageHeader = wrapper.find('span.post-code__language').exists();
|
||||||
const lineNumbersDiv = wrapper.find('.post-code__line-numbers').exists();
|
const lineNumbersDiv = wrapper.find('.post-code__line-numbers').exists();
|
||||||
@@ -156,12 +183,14 @@ it shouldn't highlight, it's just garbage
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
|
<ReduxProvider store={store}>
|
||||||
<IntlProvider locale='en'>
|
<IntlProvider locale='en'>
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
code={input}
|
code={input}
|
||||||
language={language}
|
language={language}
|
||||||
/>
|
/>
|
||||||
</IntlProvider>,
|
</IntlProvider>
|
||||||
|
</ReduxProvider>,
|
||||||
);
|
);
|
||||||
await actImmediate(wrapper);
|
await actImmediate(wrapper);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
import React, {useCallback, useEffect, useState} from 'react';
|
||||||
|
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
|
import {GlobalState} from 'types/store';
|
||||||
|
|
||||||
import CopyButton from 'components/copy_button';
|
import CopyButton from 'components/copy_button';
|
||||||
|
|
||||||
import * as SyntaxHighlighting from 'utils/syntax_highlighting';
|
import * as SyntaxHighlighting from 'utils/syntax_highlighting';
|
||||||
@@ -67,10 +71,27 @@ const CodeBlock: React.FC<Props> = ({code, language, searchedContent}: Props) =>
|
|||||||
htmlContent = `${searchedContent} ${content}`;
|
htmlContent = `${searchedContent} ${content}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const codeBlockActions = useSelector((state: GlobalState) => state.plugins.components.CodeBlockAction);
|
||||||
|
const pluginItems = codeBlockActions?.
|
||||||
|
map((item) => {
|
||||||
|
if (!item.component) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Component = item.component as any;
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
key={item.id}
|
||||||
|
code={code}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<div className='post-code__overlay'>
|
<div className='post-code__overlay'>
|
||||||
<CopyButton content={code}/>
|
<CopyButton content={code}/>
|
||||||
|
{pluginItems}
|
||||||
{header}
|
{header}
|
||||||
</div>
|
</div>
|
||||||
<div className='hljs'>
|
<div className='hljs'>
|
||||||
|
|||||||
@@ -508,6 +508,12 @@ export default class PluginRegistry {
|
|||||||
return dispatchPluginComponentAction('PostEditorAction', this.id, component);
|
return dispatchPluginComponentAction('PostEditorAction', this.id, component);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Register a component to the add to the code block header.
|
||||||
|
// Accepts a React component. Returns a unique identifier.
|
||||||
|
registerCodeBlockActionComponent = reArg(['component'], ({component}: DPluginComponentProp) => {
|
||||||
|
return dispatchPluginComponentAction('CodeBlockAction', this.id, component);
|
||||||
|
});
|
||||||
|
|
||||||
// Register a component to the add to the new messages separator.
|
// Register a component to the add to the new messages separator.
|
||||||
// Accepts a React component. Returns a unique identifier.
|
// Accepts a React component. Returns a unique identifier.
|
||||||
registerNewMessagesSeparatorActionComponent = reArg(['component'], ({component}: DPluginComponentProp) => {
|
registerNewMessagesSeparatorActionComponent = reArg(['component'], ({component}: DPluginComponentProp) => {
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ const initialComponents: PluginsState['components'] = {
|
|||||||
PostDropdownMenu: [],
|
PostDropdownMenu: [],
|
||||||
PostAction: [],
|
PostAction: [],
|
||||||
PostEditorAction: [],
|
PostEditorAction: [],
|
||||||
|
CodeBlockAction: [],
|
||||||
NewMessagesSeparatorAction: [],
|
NewMessagesSeparatorAction: [],
|
||||||
Product: [],
|
Product: [],
|
||||||
RightHandSidebarComponent: [],
|
RightHandSidebarComponent: [],
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export type PluginsState = {
|
|||||||
PostDropdownMenu: PluginComponent[];
|
PostDropdownMenu: PluginComponent[];
|
||||||
PostAction: PluginComponent[];
|
PostAction: PluginComponent[];
|
||||||
PostEditorAction: PluginComponent[];
|
PostEditorAction: PluginComponent[];
|
||||||
|
CodeBlockAction: PluginComponent[];
|
||||||
NewMessagesSeparatorAction: PluginComponent[];
|
NewMessagesSeparatorAction: PluginComponent[];
|
||||||
FilePreview: PluginComponent[];
|
FilePreview: PluginComponent[];
|
||||||
MainMenu: PluginComponent[];
|
MainMenu: PluginComponent[];
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user