diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 8af1894c79..5e8cfc3755 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -345,6 +345,7 @@ export function bodyToHtml(content, highlights, opts) { } safeBody = sanitizeHtml(body, sanitizeHtmlParams); safeBody = unicodeToImage(safeBody); + safeBody = addCodeCopyButton(safeBody); } finally { delete sanitizeHtmlParams.textFilter; @@ -363,6 +364,18 @@ export function bodyToHtml(content, highlights, opts) { return ; } +function addCodeCopyButton(safeBody) { + const el = document.createElement("div"); + el.innerHTML = safeBody; + const codeBlocks = Array.from(el.getElementsByTagName("pre")); + codeBlocks.forEach(p => { + const button = document.createElement("span"); + button.className = "mx_EventTile_copyButton"; + p.appendChild(button); + }); + return el.innerHTML; +} + export function emojifyText(text) { return { __html: unicodeToImage(escape(text)), diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 9595c2b850..45fca566b9 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -63,6 +63,19 @@ module.exports = React.createClass({ }; }, + copyToClipboard: function(text) { + const textArea = document.createElement("textarea"); + textArea.value = text; + document.body.appendChild(textArea); + textArea.select(); + try { + const successful = document.execCommand('copy'); + } catch (err) { + console.log('Unable to copy'); + } + document.body.removeChild(textArea); + }, + componentDidMount: function() { this._unmounted = false; @@ -81,6 +94,15 @@ module.exports = React.createClass({ } }, 10); } + const buttons = ReactDOM.findDOMNode(this).getElementsByClassName("mx_EventTile_copyButton"); + if (buttons.length > 0) { + for (let i = 0; i < buttons.length; i++) { + buttons[i].onclick = (e) => { + const copyCode = buttons[i].parentNode.getElementsByTagName("code")[0]; + this.copyToClipboard(copyCode.textContent); + }; + } + } } },