From 0604c86779cdea98ace30bdd78eb4db6888ffc40 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sat, 19 Sep 2020 15:30:00 +0100 Subject: [PATCH 01/32] added katex package and import --- package.json | 1 + src/HtmlUtils.tsx | 1 + yarn.lock | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/package.json b/package.json index 156cbb1bc8..7aa3df136b 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "highlight.js": "^10.1.2", "html-entities": "^1.3.1", "is-ip": "^2.0.0", + "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.19", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index bd314c2e5f..99acbfcb0c 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -26,6 +26,7 @@ import _linkifyString from 'linkifyjs/string'; import classNames from 'classnames'; import EMOJIBASE_REGEX from 'emojibase-regex'; import url from 'url'; +import katex from 'katex'; import {MatrixClientPeg} from './MatrixClientPeg'; import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; diff --git a/yarn.lock b/yarn.lock index efc1f0eae1..34b99708fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5607,6 +5607,13 @@ jsx-ast-utils@^2.4.1: array-includes "^3.1.1" object.assign "^4.1.0" +katex@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.12.0.tgz#2fb1c665dbd2b043edcf8a1f5c555f46beaa0cb9" + integrity sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg== + dependencies: + commander "^2.19.0" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" From becc79d67a29a0886f4a6f800daabebae16d655c Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sun, 20 Sep 2020 12:59:22 +0100 Subject: [PATCH 02/32] send tex math as data-mx-maths attribute --- src/HtmlUtils.tsx | 26 +++++++++++++++++++++++++- src/editor/serialize.ts | 23 ++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 99acbfcb0c..344fb3514c 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -27,6 +27,7 @@ import classNames from 'classnames'; import EMOJIBASE_REGEX from 'emojibase-regex'; import url from 'url'; import katex from 'katex'; +import { AllHtmlEntities } from 'html-entities'; import {MatrixClientPeg} from './MatrixClientPeg'; import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; @@ -236,7 +237,8 @@ const sanitizeHtmlParams: sanitizeHtml.IOptions = { allowedAttributes: { // custom ones first: font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix - span: ['data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'style'], // custom to matrix + span: ['data-mx-maths', 'data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'style'], // custom to matrix + div: ['data-mx-maths'], a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix img: ['src', 'width', 'height', 'alt', 'title'], ol: ['start'], @@ -409,6 +411,27 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts if (isHtmlMessage) { isDisplayedWithHtml = true; safeBody = sanitizeHtml(formattedBody, sanitizeParams); + if (true) { // TODO: add katex setting + const mathDelimiters = [ + { left: "
.*?
", display: true }, + { left: ".*?", display: false } + ]; + + mathDelimiters.forEach(function (d) { + var reg = RegExp(d.left + "(.*?)" + d.right, "g"); + + safeBody = safeBody.replace(reg, function(match, p1) { + return katex.renderToString( + AllHtmlEntities.decode(p1), + { + throwOnError: false, + displayMode: d.display, + output: "mathml" + }) + }); + }); + } + } } finally { delete sanitizeParams.textFilter; @@ -450,6 +473,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts 'markdown-body': isHtmlMessage && !emojiBody, }); + return isDisplayedWithHtml ? { @@ -38,7 +39,27 @@ export function mdSerialize(model: EditorModel) { } export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = {}) { - const md = mdSerialize(model); + var md = mdSerialize(model); + + if (true) { // TODO: add katex setting + const mathDelimiters = [ // TODO: make customizable + { left: "\\$\\$\\$", right: "\\$\\$\\$", display: true }, + { left: "\\$\\$", right: "\\$\\$", display: false } + ]; + + mathDelimiters.forEach(function (d) { + var reg = RegExp(d.left + "(.*?)" + d.right, "g"); + md = md.replace(reg, function(match, p1) { + const p1e = AllHtmlEntities.encode(p1); + if (d.display == true) { + return `
${p1e}
`; + } else { + return `${p1e}`; + } + }); + }); + } + const parser = new Markdown(md); if (!parser.isPlainText() || forceHTML) { return parser.toHTML(); From e78734bbf6b2fbf1ebee530921998ff97c56f203 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sun, 20 Sep 2020 14:20:35 +0100 Subject: [PATCH 03/32] Deserialize back to math delimiters for editing --- src/HtmlUtils.tsx | 4 +++- src/editor/deserialize.ts | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 344fb3514c..46bc7b441c 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -534,7 +534,6 @@ export function checkBlockNode(node: Node) { case "H6": case "PRE": case "BLOCKQUOTE": - case "DIV": case "P": case "UL": case "OL": @@ -547,6 +546,9 @@ export function checkBlockNode(node: Node) { case "TH": case "TD": return true; + case "DIV": + // don't treat math nodes as block nodes for deserializing + return !(node as HTMLElement).hasAttribute("data-mx-maths"); default: return false; } diff --git a/src/editor/deserialize.ts b/src/editor/deserialize.ts index ec697b193c..edaa330e50 100644 --- a/src/editor/deserialize.ts +++ b/src/editor/deserialize.ts @@ -130,6 +130,18 @@ function parseElement(n: HTMLElement, partCreator: PartCreator, lastNode: HTMLEl } break; } + case "DIV": + case "SPAN": { + // math nodes are translated back into delimited latex strings + if (n.hasAttribute("data-mx-maths")) { + const delim = (n.nodeName == "SPAN") ? "$$" : "$$$"; + const tex = n.getAttribute("data-mx-maths"); + return partCreator.plain(delim + tex + delim); + } else if (!checkDescendInto(n)) { + return partCreator.plain(n.textContent); + } + break; + } case "OL": state.listIndex.push((n).start || 1); /* falls through */ From 428a6b94ff5c34533b8684e5ae8b019a4dbec07c Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sun, 20 Sep 2020 15:07:12 +0100 Subject: [PATCH 04/32] math off by default, enable with latex_maths flag --- src/HtmlUtils.tsx | 4 +++- src/editor/serialize.ts | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 46bc7b441c..047a891847 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -28,6 +28,7 @@ import EMOJIBASE_REGEX from 'emojibase-regex'; import url from 'url'; import katex from 'katex'; import { AllHtmlEntities } from 'html-entities'; +import SdkConfig from './SdkConfig'; import {MatrixClientPeg} from './MatrixClientPeg'; import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; @@ -50,6 +51,7 @@ const ZWJ_REGEX = new RegExp("\u200D|\u2003", "g"); // Regex pattern for whitespace characters const WHITESPACE_REGEX = new RegExp("\\s", "g"); + const BIGEMOJI_REGEX = new RegExp(`^(${EMOJIBASE_REGEX.source})+$`, 'i'); const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/; @@ -411,7 +413,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts if (isHtmlMessage) { isDisplayedWithHtml = true; safeBody = sanitizeHtml(formattedBody, sanitizeParams); - if (true) { // TODO: add katex setting + if (SdkConfig.get()['latex_maths']) { const mathDelimiters = [ { left: "
.*?
", display: true }, { left: ".*?", display: false } diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index 8ec590cba5..72a551a4a3 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -19,6 +19,7 @@ import Markdown from '../Markdown'; import {makeGenericPermalink} from "../utils/permalinks/Permalinks"; import EditorModel from "./model"; import { AllHtmlEntities } from 'html-entities'; +import SdkConfig from '../SdkConfig'; export function mdSerialize(model: EditorModel) { return model.parts.reduce((html, part) => { @@ -41,7 +42,7 @@ export function mdSerialize(model: EditorModel) { export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = {}) { var md = mdSerialize(model); - if (true) { // TODO: add katex setting + if (SdkConfig.get()['latex_maths']) { const mathDelimiters = [ // TODO: make customizable { left: "\\$\\$\\$", right: "\\$\\$\\$", display: true }, { left: "\\$\\$", right: "\\$\\$", display: false } From e4448ae1ad87cbd3e47c73a589012494ec7d4189 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sun, 20 Sep 2020 16:52:29 +0100 Subject: [PATCH 05/32] send fallback in pre tags, not code --- src/editor/serialize.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index 72a551a4a3..c0d9509ffa 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -53,9 +53,9 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = md = md.replace(reg, function(match, p1) { const p1e = AllHtmlEntities.encode(p1); if (d.display == true) { - return `
${p1e}
`; + return `
${p1e}
`; } else { - return `${p1e}`; + return `
${p1e}
`; } }); }); From 7e6d7053e0a6c55f082153a521de079c7db2d77c Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sun, 20 Sep 2020 17:02:27 +0100 Subject: [PATCH 06/32] Revert "send fallback in pre tags, not code" (code looks better) This reverts commit e4448ae1ad87cbd3e47c73a589012494ec7d4189. --- src/editor/serialize.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index c0d9509ffa..72a551a4a3 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -53,9 +53,9 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = md = md.replace(reg, function(match, p1) { const p1e = AllHtmlEntities.encode(p1); if (d.display == true) { - return `
${p1e}
`; + return `
${p1e}
`; } else { - return `
${p1e}
`; + return `${p1e}`; } }); }); From 1f24b5b90c9fe6a743db17d14b726e1aefd15f6f Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sun, 20 Sep 2020 17:48:42 +0100 Subject: [PATCH 07/32] made math display slightly larger --- res/css/structures/_RoomView.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 572c7166d2..571c34fcb0 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -205,6 +205,10 @@ limitations under the License. clear: both; } +.mx_RoomView_MessageList .katex { + font-size: 1.3em; +} + li.mx_RoomView_myReadMarker_container { height: 0px; margin: 0px; From 24a1834f9b37993b79ec92c1c3081d6aa7777d37 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Mon, 21 Sep 2020 09:00:24 +0100 Subject: [PATCH 08/32] support multi-line and escaped $ --- src/HtmlUtils.tsx | 6 +++--- src/editor/serialize.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 047a891847..569b1662fe 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -415,12 +415,12 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts safeBody = sanitizeHtml(formattedBody, sanitizeParams); if (SdkConfig.get()['latex_maths']) { const mathDelimiters = [ - { left: "
.*?
", display: true }, - { left: ".*?", display: false } + { pattern: "
(.|\\s)*?
", display: true }, + { pattern: "(.|\\s)*?", display: false } ]; mathDelimiters.forEach(function (d) { - var reg = RegExp(d.left + "(.*?)" + d.right, "g"); + var reg = RegExp(d.pattern, "gm"); safeBody = safeBody.replace(reg, function(match, p1) { return katex.renderToString( diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index 72a551a4a3..d0a28266eb 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -44,12 +44,12 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = if (SdkConfig.get()['latex_maths']) { const mathDelimiters = [ // TODO: make customizable - { left: "\\$\\$\\$", right: "\\$\\$\\$", display: true }, - { left: "\\$\\$", right: "\\$\\$", display: false } + { pattern: "\\$\\$\\$(([^$]|\\\\\\$)*)\\$\\$\\$", display: true }, + { pattern: "\\$\\$(([^$]|\\\\\\$)*)\\$\\$", display: false } ]; mathDelimiters.forEach(function (d) { - var reg = RegExp(d.left + "(.*?)" + d.right, "g"); + var reg = RegExp(d.pattern, "gm"); md = md.replace(reg, function(match, p1) { const p1e = AllHtmlEntities.encode(p1); if (d.display == true) { From 4df8754aad0333c840eceb1892faa9f3c90f2405 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Mon, 21 Sep 2020 11:00:39 +0100 Subject: [PATCH 09/32] allow custom latex delimiters in config.json --- src/editor/deserialize.ts | 10 ++++++++-- src/editor/serialize.ts | 26 ++++++++++++-------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/editor/deserialize.ts b/src/editor/deserialize.ts index edaa330e50..e27eecd2db 100644 --- a/src/editor/deserialize.ts +++ b/src/editor/deserialize.ts @@ -21,6 +21,7 @@ import { walkDOMDepthFirst } from "./dom"; import { checkBlockNode } from "../HtmlUtils"; import { getPrimaryPermalinkEntity } from "../utils/permalinks/Permalinks"; import { PartCreator } from "./parts"; +import SdkConfig from "../SdkConfig"; function parseAtRoomMentions(text: string, partCreator: PartCreator) { const ATROOM = "@room"; @@ -134,9 +135,14 @@ function parseElement(n: HTMLElement, partCreator: PartCreator, lastNode: HTMLEl case "SPAN": { // math nodes are translated back into delimited latex strings if (n.hasAttribute("data-mx-maths")) { - const delim = (n.nodeName == "SPAN") ? "$$" : "$$$"; + const delimLeft = (n.nodeName == "SPAN") ? + (SdkConfig.get()['latex_maths_delims'] || {})['inline_left'] || "$$" : + (SdkConfig.get()['latex_maths_delims'] || {})['display_left'] || "$$$"; + const delimRight = (n.nodeName == "SPAN") ? + (SdkConfig.get()['latex_maths_delims'] || {})['inline_right'] || "$$" : + (SdkConfig.get()['latex_maths_delims'] || {})['display_right'] || "$$$"; const tex = n.getAttribute("data-mx-maths"); - return partCreator.plain(delim + tex + delim); + return partCreator.plain(delimLeft + tex + delimRight); } else if (!checkDescendInto(n)) { return partCreator.plain(n.textContent); } diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index d0a28266eb..da8ae4e820 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -43,21 +43,19 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = var md = mdSerialize(model); if (SdkConfig.get()['latex_maths']) { - const mathDelimiters = [ // TODO: make customizable - { pattern: "\\$\\$\\$(([^$]|\\\\\\$)*)\\$\\$\\$", display: true }, - { pattern: "\\$\\$(([^$]|\\\\\\$)*)\\$\\$", display: false } - ]; + const displayPattern = (SdkConfig.get()['latex_maths_delims'] || {})['display_pattern'] || + "\\$\\$\\$(([^$]|\\\\\\$)*)\\$\\$\\$"; + const inlinePattern = (SdkConfig.get()['latex_maths_delims'] || {})['inline_pattern'] || + "\\$\\$(([^$]|\\\\\\$)*)\\$\\$"; - mathDelimiters.forEach(function (d) { - var reg = RegExp(d.pattern, "gm"); - md = md.replace(reg, function(match, p1) { - const p1e = AllHtmlEntities.encode(p1); - if (d.display == true) { - return `
${p1e}
`; - } else { - return `${p1e}`; - } - }); + md = md.replace(RegExp(displayPattern, "gm"), function(m,p1) { + const p1e = AllHtmlEntities.encode(p1); + return `
${p1e}
`; + }); + + md = md.replace(RegExp(inlinePattern, "gm"), function(m,p1) { + const p1e = AllHtmlEntities.encode(p1); + return `${p1e}`; }); } From 1b689bb4e11c1329072a85002ea90abfaf9043df Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Mon, 21 Sep 2020 22:02:19 +0100 Subject: [PATCH 10/32] tell markdown to ignore math tags --- src/Markdown.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Markdown.js b/src/Markdown.js index 492450e87d..dc15e7d6b3 100644 --- a/src/Markdown.js +++ b/src/Markdown.js @@ -16,13 +16,19 @@ limitations under the License. import commonmark from 'commonmark'; import {escape} from "lodash"; +import SdkConfig from './SdkConfig'; -const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u']; +const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u', 'code']; // These types of node are definitely text const TEXT_NODES = ['text', 'softbreak', 'linebreak', 'paragraph', 'document']; function is_allowed_html_tag(node) { + if (SdkConfig.get()['latex_maths'] && + node.literal.match(/^<\/?(div|span)( data-mx-maths="[^"]*")?>$/) != null) { + return true; + } + // Regex won't work for tags with attrs, but we only // allow anyway. const matches = /^<\/?(.*)>$/.exec(node.literal); @@ -30,6 +36,7 @@ function is_allowed_html_tag(node) { const tag = matches[1]; return ALLOWED_HTML_TAGS.indexOf(tag) > -1; } + return false; } From aded3c9de2b14010612b7d9581b10366d9dc3be2 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Tue, 22 Sep 2020 11:54:23 +0100 Subject: [PATCH 11/32] cosmetic changes (lint) --- src/HtmlUtils.tsx | 13 +++++-------- src/editor/serialize.ts | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 569b1662fe..7bccd47622 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -416,24 +416,21 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts if (SdkConfig.get()['latex_maths']) { const mathDelimiters = [ { pattern: "
(.|\\s)*?
", display: true }, - { pattern: "(.|\\s)*?", display: false } + { pattern: "(.|\\s)*?", display: false }, ]; - mathDelimiters.forEach(function (d) { - var reg = RegExp(d.pattern, "gm"); - - safeBody = safeBody.replace(reg, function(match, p1) { + mathDelimiters.forEach(function(d) { + safeBody = safeBody.replace(RegExp(d.pattern, "gm"), function(m, p1) { return katex.renderToString( AllHtmlEntities.decode(p1), { throwOnError: false, displayMode: d.display, - output: "mathml" + output: "mathml", }) }); }); - } - + } } } finally { delete sanitizeParams.textFilter; diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index da8ae4e820..02194a1d59 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -40,7 +40,7 @@ export function mdSerialize(model: EditorModel) { } export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = {}) { - var md = mdSerialize(model); + let md = mdSerialize(model); if (SdkConfig.get()['latex_maths']) { const displayPattern = (SdkConfig.get()['latex_maths_delims'] || {})['display_pattern'] || @@ -48,12 +48,12 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = const inlinePattern = (SdkConfig.get()['latex_maths_delims'] || {})['inline_pattern'] || "\\$\\$(([^$]|\\\\\\$)*)\\$\\$"; - md = md.replace(RegExp(displayPattern, "gm"), function(m,p1) { + md = md.replace(RegExp(displayPattern, "gm"), function(m, p1) { const p1e = AllHtmlEntities.encode(p1); return `
${p1e}
`; }); - md = md.replace(RegExp(inlinePattern, "gm"), function(m,p1) { + md = md.replace(RegExp(inlinePattern, "gm"), function(m, p1) { const p1e = AllHtmlEntities.encode(p1); return `${p1e}`; }); From d2054ea685bad49af11ec9a64b5aa4218bc204c0 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 25 Sep 2020 09:05:22 +0100 Subject: [PATCH 12/32] HTML output for cross-browser support --- res/css/structures/_RoomView.scss | 4 ---- src/HtmlUtils.tsx | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 571c34fcb0..572c7166d2 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -205,10 +205,6 @@ limitations under the License. clear: both; } -.mx_RoomView_MessageList .katex { - font-size: 1.3em; -} - li.mx_RoomView_myReadMarker_container { height: 0px; margin: 0px; diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 7bccd47622..70a2a3f000 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -426,7 +426,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts { throwOnError: false, displayMode: d.display, - output: "mathml", + output: "htmlAndMathml", }) }); }); From 65c4460abcdb64bac14bdd72e3b970a96dd52299 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 9 Oct 2020 15:47:11 +0100 Subject: [PATCH 13/32] whitespace fixes --- src/HtmlUtils.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 70a2a3f000..da3eb3b128 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -51,7 +51,6 @@ const ZWJ_REGEX = new RegExp("\u200D|\u2003", "g"); // Regex pattern for whitespace characters const WHITESPACE_REGEX = new RegExp("\\s", "g"); - const BIGEMOJI_REGEX = new RegExp(`^(${EMOJIBASE_REGEX.source})+$`, 'i'); const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/; @@ -472,7 +471,6 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts 'markdown-body': isHtmlMessage && !emojiBody, }); - return isDisplayedWithHtml ? Date: Sat, 10 Oct 2020 09:12:53 +0100 Subject: [PATCH 14/32] only allow code tags inside math tag --- src/Markdown.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Markdown.js b/src/Markdown.js index dc15e7d6b3..9914cff85a 100644 --- a/src/Markdown.js +++ b/src/Markdown.js @@ -18,14 +18,21 @@ import commonmark from 'commonmark'; import {escape} from "lodash"; import SdkConfig from './SdkConfig'; -const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u', 'code']; +const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u']; // These types of node are definitely text const TEXT_NODES = ['text', 'softbreak', 'linebreak', 'paragraph', 'document']; +function is_math_node(node) { + return node != null && + node.literal != null && + node.literal.match(/^<((div|span) data-mx-maths="[^"]*"|\/(div|span))>$/) != null; +} + function is_allowed_html_tag(node) { if (SdkConfig.get()['latex_maths'] && - node.literal.match(/^<\/?(div|span)( data-mx-maths="[^"]*")?>$/) != null) { + (is_math_node(node) || + (node.literal.match(/^<\/?code>$/) && is_math_node(node.parent)))) { return true; } From 96742fc3093cc88cd609d731d932a05ab094262f Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sat, 10 Oct 2020 16:32:49 +0100 Subject: [PATCH 15/32] latex math as labs setting --- src/HtmlUtils.tsx | 4 ++-- src/Markdown.js | 4 ++-- src/editor/serialize.ts | 3 ++- src/settings/Settings.ts | 6 ++++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index da3eb3b128..ca718cd9aa 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -28,7 +28,7 @@ import EMOJIBASE_REGEX from 'emojibase-regex'; import url from 'url'; import katex from 'katex'; import { AllHtmlEntities } from 'html-entities'; -import SdkConfig from './SdkConfig'; +import SettingsStore from './settings/SettingsStore'; import {MatrixClientPeg} from './MatrixClientPeg'; import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; @@ -412,7 +412,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts if (isHtmlMessage) { isDisplayedWithHtml = true; safeBody = sanitizeHtml(formattedBody, sanitizeParams); - if (SdkConfig.get()['latex_maths']) { + if (SettingsStore.getValue("feature_latex_maths")) { const mathDelimiters = [ { pattern: "
(.|\\s)*?
", display: true }, { pattern: "(.|\\s)*?", display: false }, diff --git a/src/Markdown.js b/src/Markdown.js index 9914cff85a..329dcdd996 100644 --- a/src/Markdown.js +++ b/src/Markdown.js @@ -16,7 +16,7 @@ limitations under the License. import commonmark from 'commonmark'; import {escape} from "lodash"; -import SdkConfig from './SdkConfig'; +import SettingsStore from './settings/SettingsStore'; const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u']; @@ -30,7 +30,7 @@ function is_math_node(node) { } function is_allowed_html_tag(node) { - if (SdkConfig.get()['latex_maths'] && + if (SettingsStore.getValue("feature_latex_maths") && (is_math_node(node) || (node.literal.match(/^<\/?code>$/) && is_math_node(node.parent)))) { return true; diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index 02194a1d59..9f24cd5eb2 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -19,6 +19,7 @@ import Markdown from '../Markdown'; import {makeGenericPermalink} from "../utils/permalinks/Permalinks"; import EditorModel from "./model"; import { AllHtmlEntities } from 'html-entities'; +import SettingsStore from '../settings/SettingsStore'; import SdkConfig from '../SdkConfig'; export function mdSerialize(model: EditorModel) { @@ -42,7 +43,7 @@ export function mdSerialize(model: EditorModel) { export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = {}) { let md = mdSerialize(model); - if (SdkConfig.get()['latex_maths']) { + if (SettingsStore.getValue("feature_latex_maths")) { const displayPattern = (SdkConfig.get()['latex_maths_delims'] || {})['display_pattern'] || "\\$\\$\\$(([^$]|\\\\\\$)*)\\$\\$\\$"; const inlinePattern = (SdkConfig.get()['latex_maths_delims'] || {})['inline_pattern'] || diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 737c882919..2f817c264c 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -116,6 +116,12 @@ export interface ISetting { } export const SETTINGS: {[setting: string]: ISetting} = { + "feature_latex_maths": { + isFeature: true, + displayName: _td("LaTeX math in messages"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "feature_communities_v2_prototypes": { isFeature: true, displayName: _td( From a89adb86a5912d3ce71171583181175fe2564a23 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sat, 10 Oct 2020 16:33:25 +0100 Subject: [PATCH 16/32] i18n en+nl for latex math labs setting --- src/i18n/strings/en_EN.json | 1 + src/i18n/strings/en_US.json | 1 + src/i18n/strings/nl.json | 1 + 3 files changed, 3 insertions(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d7360430ae..d7b40fc198 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -856,6 +856,7 @@ "click to reveal": "click to reveal", "Clear cache and reload": "Clear cache and reload", "Labs": "Labs", + "LaTeX math in messages": "LaTeX math in messages", "Customise your experience with experimental labs features. Learn more.": "Customise your experience with experimental labs features. Learn more.", "Ignored/Blocked": "Ignored/Blocked", "Error adding ignored user/server": "Error adding ignored user/server", diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index a1275fb089..c00bf03b29 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -128,6 +128,7 @@ "Kick": "Kick", "Kicks user with given id": "Kicks user with given id", "Labs": "Labs", + "LaTeX math in messages": "LaTeX math in messages", "Ignore": "Ignore", "Unignore": "Unignore", "You are now ignoring %(userId)s": "You are now ignoring %(userId)s", diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index bb0fb5def6..d991962eec 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -199,6 +199,7 @@ "%(targetName)s joined the room.": "%(targetName)s is tot het gesprek toegetreden.", "Jump to first unread message.": "Spring naar het eerste ongelezen bericht.", "Labs": "Experimenteel", + "LaTeX math in messages": "LaTeX wiskunde in berichten", "Last seen": "Laatst gezien", "Leave room": "Gesprek verlaten", "%(targetName)s left the room.": "%(targetName)s heeft het gesprek verlaten.", From bdd332c8b5366398d4af166b49b3eaf1cddb6230 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sat, 10 Oct 2020 20:05:35 +0100 Subject: [PATCH 17/32] ran yarn i18n --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a33104ab12..b41a19aa21 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -438,6 +438,7 @@ "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", "Change notification settings": "Change notification settings", + "LaTeX math in messages": "LaTeX math in messages", "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.", "New spinner design": "New spinner design", "Message Pinning": "Message Pinning", @@ -848,7 +849,6 @@ "click to reveal": "click to reveal", "Clear cache and reload": "Clear cache and reload", "Labs": "Labs", - "LaTeX math in messages": "LaTeX math in messages", "Customise your experience with experimental labs features. Learn more.": "Customise your experience with experimental labs features. Learn more.", "Ignored/Blocked": "Ignored/Blocked", "Error adding ignored user/server": "Error adding ignored user/server", From f0c4473107d0c3589479809d8accd79b9c4dba08 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Mon, 12 Oct 2020 21:01:11 +0100 Subject: [PATCH 18/32] tell markdown parser to ignore properly-formatted math tags --- src/Markdown.js | 51 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/Markdown.js b/src/Markdown.js index 329dcdd996..564a2ed0a8 100644 --- a/src/Markdown.js +++ b/src/Markdown.js @@ -23,19 +23,47 @@ const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u']; // These types of node are definitely text const TEXT_NODES = ['text', 'softbreak', 'linebreak', 'paragraph', 'document']; -function is_math_node(node) { - return node != null && - node.literal != null && - node.literal.match(/^<((div|span) data-mx-maths="[^"]*"|\/(div|span))>$/) != null; +// prevent renderer from interpreting contents of AST node +function freeze_node(walker, node) { + const newNode = new commonmark.Node('custom_inline', node.sourcepos); + newNode.onEnter = node.literal; + node.insertAfter(newNode); + node.unlink(); + walker.resumeAt(newNode.next, true); +} + +// prevent renderer from interpreting contents of latex math tags +function freeze_math(parsed) { + const walker = parsed.walker(); + let ev; + let inMath = false; + while ( (ev = walker.next()) ) { + const node = ev.node; + if (ev.entering) { + if (!inMath) { + // entering a math tag + if (node.literal != null && node.literal.match('^<(div|span) data-mx-maths="[^"]*">$') != null) { + inMath = true; + freeze_node(walker, node); + } + } else { + // math tags should only contain a single code block, with URL-escaped latex as fallback output + if (node.literal != null && node.literal.match('^(||[^<>]*)$')) { + freeze_node(walker, node); + // leave when span or div is closed + } else if (node.literal == '
' || node.literal == '') { + inMath = false; + freeze_node(walker, node); + // this case only happens if we have improperly formatted math tags, so bail + } else { + inMath = false; + } + } + } + } } function is_allowed_html_tag(node) { - if (SettingsStore.getValue("feature_latex_maths") && - (is_math_node(node) || - (node.literal.match(/^<\/?code>$/) && is_math_node(node.parent)))) { - return true; - } - // Regex won't work for tags with attrs, but we only // allow anyway. const matches = /^<\/?(.*)>$/.exec(node.literal); @@ -173,6 +201,9 @@ export default class Markdown { */ }; + // prevent strange behaviour when mixing latex math and markdown + freeze_math(this.parsed); + return renderer.render(this.parsed); } From 38d1aac978d49160bed9c96b2a1205a4e7fb707f Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Mon, 12 Oct 2020 21:15:38 +0100 Subject: [PATCH 19/32] removed useless import and whitespace --- src/Markdown.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Markdown.js b/src/Markdown.js index 564a2ed0a8..2e6f391818 100644 --- a/src/Markdown.js +++ b/src/Markdown.js @@ -16,7 +16,6 @@ limitations under the License. import commonmark from 'commonmark'; import {escape} from "lodash"; -import SettingsStore from './settings/SettingsStore'; const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u']; @@ -71,7 +70,6 @@ function is_allowed_html_tag(node) { const tag = matches[1]; return ALLOWED_HTML_TAGS.indexOf(tag) > -1; } - return false; } From cc713aff72c56478edb4f1eafbdc55b8c9fd4248 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Wed, 14 Oct 2020 09:35:57 +0100 Subject: [PATCH 20/32] add fallback output in code block AFTER markdown processing --- src/Markdown.js | 49 +++++------------------------------------ src/editor/serialize.ts | 18 ++++++++++++--- 2 files changed, 21 insertions(+), 46 deletions(-) diff --git a/src/Markdown.js b/src/Markdown.js index 2e6f391818..dc4d442aff 100644 --- a/src/Markdown.js +++ b/src/Markdown.js @@ -22,47 +22,12 @@ const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u']; // These types of node are definitely text const TEXT_NODES = ['text', 'softbreak', 'linebreak', 'paragraph', 'document']; -// prevent renderer from interpreting contents of AST node -function freeze_node(walker, node) { - const newNode = new commonmark.Node('custom_inline', node.sourcepos); - newNode.onEnter = node.literal; - node.insertAfter(newNode); - node.unlink(); - walker.resumeAt(newNode.next, true); -} - -// prevent renderer from interpreting contents of latex math tags -function freeze_math(parsed) { - const walker = parsed.walker(); - let ev; - let inMath = false; - while ( (ev = walker.next()) ) { - const node = ev.node; - if (ev.entering) { - if (!inMath) { - // entering a math tag - if (node.literal != null && node.literal.match('^<(div|span) data-mx-maths="[^"]*">$') != null) { - inMath = true; - freeze_node(walker, node); - } - } else { - // math tags should only contain a single code block, with URL-escaped latex as fallback output - if (node.literal != null && node.literal.match('^(||[^<>]*)$')) { - freeze_node(walker, node); - // leave when span or div is closed - } else if (node.literal == '
' || node.literal == '') { - inMath = false; - freeze_node(walker, node); - // this case only happens if we have improperly formatted math tags, so bail - } else { - inMath = false; - } - } - } - } -} - function is_allowed_html_tag(node) { + if (node.literal != null && + node.literal.match('^<((div|span) data-mx-maths="[^"]*"|\/(div|span))>$') != null) { + return true; + } + // Regex won't work for tags with attrs, but we only // allow anyway. const matches = /^<\/?(.*)>$/.exec(node.literal); @@ -70,6 +35,7 @@ function is_allowed_html_tag(node) { const tag = matches[1]; return ALLOWED_HTML_TAGS.indexOf(tag) > -1; } + return false; } @@ -199,9 +165,6 @@ export default class Markdown { */ }; - // prevent strange behaviour when mixing latex math and markdown - freeze_math(this.parsed); - return renderer.render(this.parsed); } diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index 9f24cd5eb2..88fd1c90fc 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -21,6 +21,7 @@ import EditorModel from "./model"; import { AllHtmlEntities } from 'html-entities'; import SettingsStore from '../settings/SettingsStore'; import SdkConfig from '../SdkConfig'; +import cheerio from 'cheerio'; export function mdSerialize(model: EditorModel) { return model.parts.reduce((html, part) => { @@ -51,18 +52,29 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = md = md.replace(RegExp(displayPattern, "gm"), function(m, p1) { const p1e = AllHtmlEntities.encode(p1); - return `
${p1e}
`; + return `
`; }); md = md.replace(RegExp(inlinePattern, "gm"), function(m, p1) { const p1e = AllHtmlEntities.encode(p1); - return `${p1e}`; + return ``; }); } const parser = new Markdown(md); if (!parser.isPlainText() || forceHTML) { - return parser.toHTML(); + // feed Markdown output to HTML parser + const phtml = cheerio.load(parser.toHTML(), + { _useHtmlParser2: true, decodeEntities: false }) + + // add fallback output for latex math, which should not be interpreted as markdown + phtml('div, span').each(function() { + const tex = phtml(this).attr('data-mx-maths') + if (tex) { + phtml(this).html(`${tex}`) + } + }); + return phtml.html(); } // ensure removal of escape backslashes in non-Markdown messages if (md.indexOf("\\") > -1) { From 10b732131a7315aca652677857a285d7dabb243b Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Wed, 14 Oct 2020 22:16:28 +0100 Subject: [PATCH 21/32] use html parser rather than regexes --- src/HtmlUtils.tsx | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 6bae0b25b6..dc2f45210b 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -30,6 +30,7 @@ import url from 'url'; import katex from 'katex'; import { AllHtmlEntities } from 'html-entities'; import SettingsStore from './settings/SettingsStore'; +import cheerio from 'cheerio'; import {MatrixClientPeg} from './MatrixClientPeg'; import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; @@ -414,23 +415,20 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts if (isHtmlMessage) { isDisplayedWithHtml = true; safeBody = sanitizeHtml(formattedBody, sanitizeParams); - if (SettingsStore.getValue("feature_latex_maths")) { - const mathDelimiters = [ - { pattern: "
(.|\\s)*?
", display: true }, - { pattern: "(.|\\s)*?", display: false }, - ]; + const phtml = cheerio.load(safeBody, + { _useHtmlParser2: true, decodeEntities: false }) - mathDelimiters.forEach(function(d) { - safeBody = safeBody.replace(RegExp(d.pattern, "gm"), function(m, p1) { - return katex.renderToString( - AllHtmlEntities.decode(p1), - { - throwOnError: false, - displayMode: d.display, - output: "htmlAndMathml", - }) - }); + if (SettingsStore.getValue("feature_latex_maths")) { + phtml('div, span[data-mx-maths!=""]').replaceWith(function(i, e) { + return katex.renderToString( + AllHtmlEntities.decode(phtml(e).attr('data-mx-maths')), + { + throwOnError: false, + displayMode: e.name == 'div', + output: "htmlAndMathml", + }); }); + safeBody = phtml.html(); } } } finally { From 173d79886544bc57c8de0b1ae4b16a346cd73bae Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 23 Oct 2020 18:41:24 +0100 Subject: [PATCH 22/32] added cheerio as explicit dep in package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0a3fd7a8b7..ca7d6ee0b7 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "html-entities": "^1.3.1", "is-ip": "^2.0.0", "katex": "^0.12.0", + "cheerio": "^1.0.0-rc.3", "linkifyjs": "^2.1.9", "lodash": "^4.17.19", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", From 06b20fad9543063409823540fcd4416a12c3ee21 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 23 Oct 2020 18:49:56 +0100 Subject: [PATCH 23/32] removed implicit "this" --- src/editor/serialize.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index 88fd1c90fc..f31dd67ae7 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -68,10 +68,10 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = { _useHtmlParser2: true, decodeEntities: false }) // add fallback output for latex math, which should not be interpreted as markdown - phtml('div, span').each(function() { - const tex = phtml(this).attr('data-mx-maths') + phtml('div, span').each(function(i, e) { + const tex = phtml(e).attr('data-mx-maths') if (tex) { - phtml(this).html(`${tex}`) + phtml(e).html(`${tex}`) } }); return phtml.html(); From 2204e6c64e0042e0b937cf7d42e07816608e0234 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sun, 25 Oct 2020 18:32:24 +0000 Subject: [PATCH 24/32] generate valid block html for commonmark spec --- src/editor/serialize.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index f31dd67ae7..bd7845315e 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -52,13 +52,17 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = md = md.replace(RegExp(displayPattern, "gm"), function(m, p1) { const p1e = AllHtmlEntities.encode(p1); - return `
`; + return `
\n\n
\n\n`; }); md = md.replace(RegExp(inlinePattern, "gm"), function(m, p1) { const p1e = AllHtmlEntities.encode(p1); return ``; }); + + // make sure div tags always start on a new line, otherwise it will confuse + // the markdown parser + md = md.replace(/(.)
Date: Thu, 29 Oct 2020 13:22:09 +0000 Subject: [PATCH 25/32] stubbed isGuest for unit tests --- test/components/views/messages/TextualBody-test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index 07cd51edbd..bf55e9c430 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -36,6 +36,7 @@ describe("", () => { MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, + isGuest: () => false, }; const ev = mkEvent({ @@ -59,6 +60,7 @@ describe("", () => { MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, + isGuest: () => false, }; const ev = mkEvent({ @@ -83,6 +85,7 @@ describe("", () => { MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, + isGuest: () => false, }; }); @@ -135,6 +138,7 @@ describe("", () => { getHomeserverUrl: () => "https://my_server/", on: () => undefined, removeListener: () => undefined, + isGuest: () => false, }; }); From 839bae21ae5078e25b7e6a03cc4a99725014b029 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Tue, 10 Nov 2020 18:18:53 +0000 Subject: [PATCH 26/32] made single and double $ default delimiters --- src/editor/deserialize.ts | 8 ++++---- src/editor/serialize.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/editor/deserialize.ts b/src/editor/deserialize.ts index e27eecd2db..6336b4c46b 100644 --- a/src/editor/deserialize.ts +++ b/src/editor/deserialize.ts @@ -136,11 +136,11 @@ function parseElement(n: HTMLElement, partCreator: PartCreator, lastNode: HTMLEl // math nodes are translated back into delimited latex strings if (n.hasAttribute("data-mx-maths")) { const delimLeft = (n.nodeName == "SPAN") ? - (SdkConfig.get()['latex_maths_delims'] || {})['inline_left'] || "$$" : - (SdkConfig.get()['latex_maths_delims'] || {})['display_left'] || "$$$"; + (SdkConfig.get()['latex_maths_delims'] || {})['inline_left'] || "$" : + (SdkConfig.get()['latex_maths_delims'] || {})['display_left'] || "$$"; const delimRight = (n.nodeName == "SPAN") ? - (SdkConfig.get()['latex_maths_delims'] || {})['inline_right'] || "$$" : - (SdkConfig.get()['latex_maths_delims'] || {})['display_right'] || "$$$"; + (SdkConfig.get()['latex_maths_delims'] || {})['inline_right'] || "$" : + (SdkConfig.get()['latex_maths_delims'] || {})['display_right'] || "$$"; const tex = n.getAttribute("data-mx-maths"); return partCreator.plain(delimLeft + tex + delimRight); } else if (!checkDescendInto(n)) { diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index bd7845315e..c1f4da306b 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -46,9 +46,9 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} = if (SettingsStore.getValue("feature_latex_maths")) { const displayPattern = (SdkConfig.get()['latex_maths_delims'] || {})['display_pattern'] || - "\\$\\$\\$(([^$]|\\\\\\$)*)\\$\\$\\$"; - const inlinePattern = (SdkConfig.get()['latex_maths_delims'] || {})['inline_pattern'] || "\\$\\$(([^$]|\\\\\\$)*)\\$\\$"; + const inlinePattern = (SdkConfig.get()['latex_maths_delims'] || {})['inline_pattern'] || + "\\$(([^$]|\\\\\\$)*)\\$"; md = md.replace(RegExp(displayPattern, "gm"), function(m, p1) { const p1e = AllHtmlEntities.encode(p1); From 8233ce77cbeda9706932a5ff5d7083a6775a52e0 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Tue, 10 Nov 2020 18:26:09 +0000 Subject: [PATCH 27/32] fixed duplicate import from merge --- src/HtmlUtils.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index d25c420bc9..44fbffb97f 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -33,7 +33,6 @@ import SettingsStore from './settings/SettingsStore'; import cheerio from 'cheerio'; import {MatrixClientPeg} from './MatrixClientPeg'; -import SettingsStore from './settings/SettingsStore'; import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; import {SHORTCODE_TO_EMOJI, getEmojiFromUnicode} from "./emoji"; import ReplyThread from "./components/views/elements/ReplyThread"; From ca9e43f118bb7386e3bd65e0c92755b0fd26a8bb Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 19 Nov 2020 07:58:37 +0000 Subject: [PATCH 28/32] reverted translation --- src/i18n/strings/nl.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 000beb915d..1ec887c364 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -199,7 +199,6 @@ "%(targetName)s joined the room.": "%(targetName)s is tot het gesprek toegetreden.", "Jump to first unread message.": "Spring naar het eerste ongelezen bericht.", "Labs": "Experimenteel", - "LaTeX math in messages": "LaTeX wiskunde in berichten", "Last seen": "Laatst gezien", "Leave room": "Gesprek verlaten", "%(targetName)s left the room.": "%(targetName)s heeft het gesprek verlaten.", From dacef10fa605107ab6b512a0e5e255c5696e051c Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 26 Nov 2020 16:22:10 +0000 Subject: [PATCH 29/32] reverted US translation --- src/i18n/strings/en_US.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index c00bf03b29..a1275fb089 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -128,7 +128,6 @@ "Kick": "Kick", "Kicks user with given id": "Kicks user with given id", "Labs": "Labs", - "LaTeX math in messages": "LaTeX math in messages", "Ignore": "Ignore", "Unignore": "Unignore", "You are now ignoring %(userId)s": "You are now ignoring %(userId)s", From 7013483dadfeea29d4aa9a942537d30aff240f24 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 26 Nov 2020 17:26:42 +0000 Subject: [PATCH 30/32] UK spelling maths --- src/i18n/strings/en_EN.json | 2 +- src/settings/Settings.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e8a2fb53c2..faa376f333 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -699,7 +699,7 @@ "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", "Change notification settings": "Change notification settings", - "LaTeX math in messages": "LaTeX math in messages", + "Render LaTeX maths in messages": "Render LaTeX maths in messages", "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.", "New spinner design": "New spinner design", "Message Pinning": "Message Pinning", diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 5600a1346d..a7c1f849fc 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -118,7 +118,7 @@ export interface ISetting { export const SETTINGS: {[setting: string]: ISetting} = { "feature_latex_maths": { isFeature: true, - displayName: _td("LaTeX math in messages"), + displayName: _td("Render LaTeX maths in messages"), supportedLevels: LEVELS_FEATURE, default: false, }, From 494ae3e4215cc2fe0583c316b8ea1d895503d39e Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 26 Nov 2020 17:45:11 +0000 Subject: [PATCH 31/32] parse html for latex rendering inside settings block --- src/HtmlUtils.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 44fbffb97f..43aeae24e6 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -418,10 +418,10 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts if (isHtmlMessage) { isDisplayedWithHtml = true; safeBody = sanitizeHtml(formattedBody, sanitizeParams); - const phtml = cheerio.load(safeBody, - { _useHtmlParser2: true, decodeEntities: false }) if (SettingsStore.getValue("feature_latex_maths")) { + const phtml = cheerio.load(safeBody, + { _useHtmlParser2: true, decodeEntities: false }) phtml('div, span[data-mx-maths!=""]').replaceWith(function(i, e) { return katex.renderToString( AllHtmlEntities.decode(phtml(e).attr('data-mx-maths')), From 79baea9c4a7c236e63622b5189806016ecd5f999 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 26 Nov 2020 17:54:11 +0000 Subject: [PATCH 32/32] fixed indent --- src/HtmlUtils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 43aeae24e6..2301ad250b 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -421,7 +421,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts if (SettingsStore.getValue("feature_latex_maths")) { const phtml = cheerio.load(safeBody, - { _useHtmlParser2: true, decodeEntities: false }) + { _useHtmlParser2: true, decodeEntities: false }) phtml('div, span[data-mx-maths!=""]').replaceWith(function(i, e) { return katex.renderToString( AllHtmlEntities.decode(phtml(e).attr('data-mx-maths')),