Redo expanding
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
parent
45d0270bca
commit
61281a855c
2 changed files with 91 additions and 59 deletions
|
@ -501,10 +501,12 @@ $left-gutter: 64px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_content_collapsedCode {
|
.mx_EventTile_expandedCodeBlock {
|
||||||
pre {
|
max-height: 100vh;
|
||||||
max-height: 30vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_collapsedCodeBlock {
|
||||||
|
max-height: 30vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile:hover .mx_EventTile_body pre,
|
.mx_EventTile:hover .mx_EventTile_body pre,
|
||||||
|
@ -531,6 +533,35 @@ $left-gutter: 64px;
|
||||||
background-color: $message-action-bar-fg-color;
|
background-color: $message-action-bar-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Inserted adjacent to <pre> blocks, (See TextualBody)
|
||||||
|
.mx_EventTile_expandButton {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
visibility: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 6px;
|
||||||
|
right: 6px;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
mask-image: url($copy-button-url);
|
||||||
|
background-color: $message-action-bar-fg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inserted adjacent to <pre> blocks, (See TextualBody)
|
||||||
|
.mx_EventTile_collapseButton {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
visibility: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 6px;
|
||||||
|
right: 6px;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
mask-image: url($copy-button-url);
|
||||||
|
background-color: $message-action-bar-fg-color;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_copyButton,
|
.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_copyButton,
|
||||||
.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton {
|
.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
|
|
|
@ -35,7 +35,6 @@ import {isPermalinkHost} from "../../../utils/permalinks/Permalinks";
|
||||||
import {toRightOf} from "../../structures/ContextMenu";
|
import {toRightOf} from "../../structures/ContextMenu";
|
||||||
import {copyPlaintext} from "../../../utils/strings";
|
import {copyPlaintext} from "../../../utils/strings";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import classNames from "classnames";
|
|
||||||
|
|
||||||
export default class TextualBody extends React.Component {
|
export default class TextualBody extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -70,7 +69,6 @@ export default class TextualBody extends React.Component {
|
||||||
|
|
||||||
// track whether the preview widget is hidden
|
// track whether the preview widget is hidden
|
||||||
widgetHidden: false,
|
widgetHidden: false,
|
||||||
codeBlockExpanded: SettingsStore.getValue("expandCodeByDefault"),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,31 +91,72 @@ export default class TextualBody extends React.Component {
|
||||||
this.calculateUrlPreview();
|
this.calculateUrlPreview();
|
||||||
|
|
||||||
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html") {
|
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html") {
|
||||||
const blocks = ReactDOM.findDOMNode(this).getElementsByTagName("code");
|
const blocks = ReactDOM.findDOMNode(this).getElementsByTagName("pre");
|
||||||
if (blocks.length > 0) {
|
if (blocks.length > 0) {
|
||||||
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
|
this._handleCodeBlockExpansion(blocks[i]);
|
||||||
|
this._addCodeCopyButton(blocks[i]);
|
||||||
|
}
|
||||||
// Do this asynchronously: parsing code takes time and we don't
|
// Do this asynchronously: parsing code takes time and we don't
|
||||||
// need to block the DOM update on it.
|
// need to block the DOM update on it.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this._unmounted) return;
|
if (this._unmounted) return;
|
||||||
for (let i = 0; i < blocks.length; i++) {
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
|
this._highlightCode(blocks[i].firstChild);
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_addCodeCopyButton(codeBlock) {
|
||||||
|
const button = document.createElement("span");
|
||||||
|
button.className = "mx_EventTile_copyButton";
|
||||||
|
button.onclick = async () => {
|
||||||
|
const copyCode = button.parentNode.getElementsByTagName("pre")[0];
|
||||||
|
const successful = await copyPlaintext(copyCode.textContent);
|
||||||
|
|
||||||
|
const buttonRect = button.getBoundingClientRect();
|
||||||
|
const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu');
|
||||||
|
const {close} = ContextMenu.createMenu(GenericTextContextMenu, {
|
||||||
|
...toRightOf(buttonRect, 2),
|
||||||
|
message: successful ? _t('Copied!') : _t('Failed to copy'),
|
||||||
|
});
|
||||||
|
button.onmouseleave = close;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrap a div around <pre> so that the copy button can be correctly positioned
|
||||||
|
// when the <pre> overflows and is scrolled horizontally.
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.className = "mx_EventTile_pre_container";
|
||||||
|
|
||||||
|
// Insert containing div in place of <pre> block
|
||||||
|
codeBlock.parentNode.replaceChild(div, codeBlock);
|
||||||
|
|
||||||
|
// Append <pre> block and copy button to container
|
||||||
|
div.appendChild(codeBlock);
|
||||||
|
div.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleCodeBlockExpansion(codeBlock) {
|
||||||
|
const expandCodeBlock = SettingsStore.getValue("expandCodeByDefault");
|
||||||
|
codeBlock.className = expandCodeBlock ? "mx_EventTile_expandedCodeBlock" : "mx_EventTile_collapsedCodeBlock";
|
||||||
|
}
|
||||||
|
|
||||||
|
_highlightCode(codeBlock) {
|
||||||
if (SettingsStore.getValue("enableSyntaxHighlightLanguageDetection")) {
|
if (SettingsStore.getValue("enableSyntaxHighlightLanguageDetection")) {
|
||||||
highlight.highlightBlock(blocks[i]);
|
highlight.highlightBlock(codeBlock);
|
||||||
} else {
|
} else {
|
||||||
// Only syntax highlight if there's a class starting with language-
|
// Only syntax highlight if there's a class starting with language-
|
||||||
const classes = blocks[i].className.split(/\s+/).filter(function(cl) {
|
const classes = codeBlock.className.split(/\s+/).filter(function(cl) {
|
||||||
return cl.startsWith('language-') && !cl.startsWith('language-_');
|
return cl.startsWith('language-') && !cl.startsWith('language-_');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (classes.length != 0) {
|
if (classes.length != 0) {
|
||||||
highlight.highlightBlock(blocks[i]);
|
highlight.highlightBlock(codeBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
this._addCodeCopyButton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!this.props.editState) {
|
if (!this.props.editState) {
|
||||||
|
@ -256,38 +295,6 @@ export default class TextualBody extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_addCodeCopyButton() {
|
|
||||||
// Add 'copy' buttons to pre blocks
|
|
||||||
Array.from(ReactDOM.findDOMNode(this).querySelectorAll('.mx_EventTile_body pre')).forEach((p) => {
|
|
||||||
const button = document.createElement("span");
|
|
||||||
button.className = "mx_EventTile_copyButton";
|
|
||||||
button.onclick = async () => {
|
|
||||||
const copyCode = button.parentNode.getElementsByTagName("pre")[0];
|
|
||||||
const successful = await copyPlaintext(copyCode.textContent);
|
|
||||||
|
|
||||||
const buttonRect = button.getBoundingClientRect();
|
|
||||||
const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu');
|
|
||||||
const {close} = ContextMenu.createMenu(GenericTextContextMenu, {
|
|
||||||
...toRightOf(buttonRect, 2),
|
|
||||||
message: successful ? _t('Copied!') : _t('Failed to copy'),
|
|
||||||
});
|
|
||||||
button.onmouseleave = close;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wrap a div around <pre> so that the copy button can be correctly positioned
|
|
||||||
// when the <pre> overflows and is scrolled horizontally.
|
|
||||||
const div = document.createElement("div");
|
|
||||||
div.className = "mx_EventTile_pre_container";
|
|
||||||
|
|
||||||
// Insert containing div in place of <pre> block
|
|
||||||
p.parentNode.replaceChild(div, p);
|
|
||||||
|
|
||||||
// Append <pre> block and copy button to container
|
|
||||||
div.appendChild(p);
|
|
||||||
div.appendChild(button);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onCancelClick = event => {
|
onCancelClick = event => {
|
||||||
this.setState({ widgetHidden: true });
|
this.setState({ widgetHidden: true });
|
||||||
// FIXME: persist this somewhere smarter than local storage
|
// FIXME: persist this somewhere smarter than local storage
|
||||||
|
@ -439,12 +446,6 @@ export default class TextualBody extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultCaseClasses = classNames({
|
|
||||||
mx_MTextBody: true,
|
|
||||||
mx_EventTile_content: true,
|
|
||||||
mx_EventTile_content_collapsedCode: !this.state.codeBlockExpanded,
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (content.msgtype) {
|
switch (content.msgtype) {
|
||||||
case "m.emote":
|
case "m.emote":
|
||||||
return (
|
return (
|
||||||
|
@ -470,7 +471,7 @@ export default class TextualBody extends React.Component {
|
||||||
);
|
);
|
||||||
default: // including "m.text"
|
default: // including "m.text"
|
||||||
return (
|
return (
|
||||||
<span className={defaultCaseClasses}>
|
<span className="mx_MTextBody mx_EventTile_content">
|
||||||
{ body }
|
{ body }
|
||||||
{ widgets }
|
{ widgets }
|
||||||
</span>
|
</span>
|
||||||
|
|
Loading…
Reference in a new issue