diff --git a/src/main/java/org/olat/core/gui/render/StringOutput.java b/src/main/java/org/olat/core/gui/render/StringOutput.java index 412d7433c221ca65b2fb9712038445fd086ff987..0118b2ea155809d4f10fa95160b36813248b0592 100644 --- a/src/main/java/org/olat/core/gui/render/StringOutput.java +++ b/src/main/java/org/olat/core/gui/render/StringOutput.java @@ -207,6 +207,10 @@ public class StringOutput extends Writer { return sb.length(); } + public boolean contains(String str) { + return sb.indexOf(str) >= 0; + } + public Reader getReader() { return new StringOutputReader(); } diff --git a/src/main/java/org/olat/core/util/Formatter.java b/src/main/java/org/olat/core/util/Formatter.java index a4356f856ae82b665312ec876973eaab32a45142..28b0ad2caaa5fb74cc8df3be14ed5afbbce4f748 100644 --- a/src/main/java/org/olat/core/util/Formatter.java +++ b/src/main/java/org/olat/core/util/Formatter.java @@ -68,9 +68,6 @@ public class Formatter { private static final Map<Locale,Formatter> localToFormatterMap = new HashMap<>(); - // Pattern to find math classes - private static final Pattern classMathPattern = Pattern.compile(".*class[ ]*=[ ]*(math|(['\"])([a-zA-Z0-9_\\- ]* )*math( [a-zA-Z0-9_\\- ]*)*\\2).*"); - private final Locale locale; private final DateFormat shortDateFormat; private final DateFormat longDateFormat; diff --git a/src/main/java/org/olat/core/util/WebappHelper.java b/src/main/java/org/olat/core/util/WebappHelper.java index 9b9431688e968da772d580a15e8ac3b1ab8ff70a..0aa920f952ac8ac8497ac97dbcce21185660c0c6 100644 --- a/src/main/java/org/olat/core/util/WebappHelper.java +++ b/src/main/java/org/olat/core/util/WebappHelper.java @@ -77,6 +77,8 @@ public class WebappHelper implements Initializable, Destroyable, ServletContextA private static String mathJaxCdn; private static String mathJaxConfig; + private static boolean mathJaxMarkers; + private static String mobileContext; /** need to set this at least once before the actual request, since we cannot extract it from the servletContext, @@ -312,6 +314,14 @@ public class WebappHelper implements Initializable, Destroyable, ServletContextA public void setMathJaxConfig(String mathJaxConfig) { WebappHelper.mathJaxConfig = mathJaxConfig; } + + public static boolean isMathJaxMarkers() { + return mathJaxMarkers; + } + + public void setMathJaxMarkers(boolean mathJaxMarkers) { + WebappHelper.mathJaxMarkers = mathJaxMarkers; + } public void setFullPathToSrc(String fullPathToSrc) { File path = new File(fullPathToSrc); diff --git a/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml b/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml index 8574eb3e3131b43fa9d13c5e6e2011f87862151b..32f47349095d8f06a2a97f6a4bb889861abff38c 100644 --- a/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml +++ b/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml @@ -49,6 +49,7 @@ <property name="mobileContext" value="${mobile.context}" /> <property name="mathJaxCdn" value="${mathjax.cdn}"/> <property name="mathJaxConfig" value="${mathjax.config}"/> + <property name="mathJaxMarkers" value="${mathjax.markers}"/> </bean> <bean id="org.olat.core.helpers.Settings" class="org.olat.core.helpers.Settings" depends-on="org.olat.core.util.WebappHelper"> diff --git a/src/main/java/org/olat/core/util/filter/impl/NekoHTMLMathScanner.java b/src/main/java/org/olat/core/util/filter/impl/NekoHTMLMathScanner.java index 68c23ea336c9868a747ec535a1a51de559566c6f..f2a0ef1aa36f330d9d47813e23cc494697fc6619 100644 --- a/src/main/java/org/olat/core/util/filter/impl/NekoHTMLMathScanner.java +++ b/src/main/java/org/olat/core/util/filter/impl/NekoHTMLMathScanner.java @@ -24,8 +24,10 @@ import java.io.StringReader; import org.cyberneko.html.parsers.SAXParser; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.WebappHelper; import org.xml.sax.Attributes; import org.xml.sax.InputSource; +import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** @@ -80,5 +82,15 @@ public class NekoHTMLMathScanner { } } } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if(!mathFound && WebappHelper.isMathJaxMarkers()) { + String content = new String(ch, start, length); + if(content.contains("\\(") || content.contains("\\[") || content.contains("$$")) { + mathFound = true; + } + } + } } } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java index 2cfa1a044ce1700da89288305387c951170f3309..cf61e54aaa4daab522cd8f9a710d9cb146d2bb37 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java @@ -30,7 +30,9 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; +import org.olat.core.util.WebappHelper; import org.olat.ims.qti21.AssessmentTestSession; import org.olat.ims.qti21.model.audit.CandidateEvent; import org.olat.ims.qti21.model.audit.CandidateItemEventType; @@ -90,6 +92,11 @@ public class AssessmentItemComponentRenderer extends AssessmentObjectComponentRe /* Render event */ AssessmentRenderer renderHints = new AssessmentRenderer(renderer); renderItemEvent(renderHints, sb, cmp, latestEvent, itemSessionState, ubu, translator); + + if(renderHints.isMathJax() + || (WebappHelper.isMathJaxMarkers() && ((sb.contains("\\(") || sb.contains("\\[") || sb.contains("&&"))))) { + sb.append(Formatter.elementLatexFormattingScript("itemBody")); + } } sb.append("</div>"); diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java index d56f17be9db0aa7b57e5db10247cf2f657b0b695..0a5ca8b2f956858945463e5675ab2557bcd5f13f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java @@ -83,7 +83,6 @@ import org.olat.core.helpers.Settings; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.CodeHelper; -import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.ims.qti21.QTI21Constants; @@ -472,27 +471,20 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent } case RubricBlock.QTI_CLASS_NAME: break; //never rendered automatically case Math.QTI_CLASS_NAME: { - String domid = "mw_" + CodeHelper.getRAMUniqueID(); - sb.append("<div id=\"").append(domid).append("\">"); + sb.append("<div>"); renderMath(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (Math)block); - sb.append("</div>") - .append(Formatter.elementLatexFormattingScript(domid)); + sb.append("</div>"); + renderer.setMathJax(true); break; } case Div.QTI_CLASS_NAME: { - String domid = null; if (containsClass(block, "math")) { - domid = "mw_" + CodeHelper.getRAMUniqueID(); - sb.append("<div id=\"").append(domid).append("\">"); + renderer.setMathJax(true); } renderStartHtmlTag(sb, component, resolvedAssessmentItem, block, null); ((Div)block).getFlows().forEach((flow) -> renderFlow(renderer, sb, component, resolvedAssessmentItem, itemSessionState, flow, ubu, translator)); renderEndTag(sb, block); - if (domid != null) { - sb.append("</div>") - .append(Formatter.elementLatexFormattingScript(domid)); - } break; } case Ul.QTI_CLASS_NAME: @@ -688,11 +680,10 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent break; } case Math.QTI_CLASS_NAME: { - String domid = "mw_" + CodeHelper.getRAMUniqueID(); - sb.append("<span id=\"").append(domid).append("\">"); + sb.append("<span>"); renderMath(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (Math)inline); - sb.append("</span>") - .append(Formatter.elementLatexFormattingScript(domid)); + sb.append("</span>"); + renderer.setMathJax(true); break; } case Img.QTI_CLASS_NAME: { @@ -730,22 +721,12 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent protected final void renderSpan(AssessmentRenderer renderer, StringOutput sb, Span span, AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, URLBuilder ubu, Translator translator) { if (containsClass(span,"math")) { - String domid = "mw_" + CodeHelper.getRAMUniqueID(); - sb.append("<span id=\"").append(domid).append("\">"); - - renderStartHtmlTag(sb, component, resolvedAssessmentItem, span, null); - span.getInlines().forEach((child) - -> renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator)); - renderEndTag(sb, span); - - sb.append("</span>") - .append(Formatter.elementLatexFormattingScript(domid)); - } else { - renderStartHtmlTag(sb, component, resolvedAssessmentItem, span, null); - span.getInlines().forEach((child) - -> renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator)); - renderEndTag(sb, span); + renderer.setMathJax(true); } + renderStartHtmlTag(sb, component, resolvedAssessmentItem, span, null); + span.getInlines().forEach((child) + -> renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator)); + renderEndTag(sb, span); } protected final void renderA(AssessmentRenderer renderer, StringOutput sb, A a, AssessmentObjectComponent component, diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderer.java index 5e773414c4cda504eb35662abf276596f60427fc..c02ac5c605e0171dd6923b787970f537eff160f4 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderer.java @@ -32,6 +32,7 @@ import org.olat.core.gui.render.URLBuilder; public class AssessmentRenderer { private Renderer renderer; + private boolean mathJax; private boolean mathXsltDisabled; private boolean solutionMode; private boolean reviewMode; @@ -145,6 +146,14 @@ public class AssessmentRenderer { this.showTitles = showTitles; } + public boolean isMathJax() { + return mathJax; + } + + public void setMathJax(boolean mathJax) { + this.mathJax = mathJax; + } + public void setRenderer(Renderer renderer) { this.renderer = renderer; } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java index df888483943013e99fd4004ca158bb35e216fb23..3c48cf5ca2b6ae1ce11c3e26183d5601fdacdc04 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java @@ -51,7 +51,9 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; +import org.olat.core.util.WebappHelper; import org.olat.course.assessment.AssessmentHelper; import org.olat.ims.qti21.AssessmentTestSession; import org.olat.ims.qti21.QTI21Constants; @@ -127,6 +129,11 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe /* Render event */ AssessmentRenderer renderHints = new AssessmentRenderer(renderer); renderTestEvent(testSessionController, renderHints, sb, cmp, ubu, translator); + + if(renderHints.isMathJax() + || (WebappHelper.isMathJaxMarkers() && ((sb.contains("\\(") || sb.contains("\\[") || sb.contains("&&"))))) { + sb.append(Formatter.elementLatexFormattingScript("itemBody")); + } } } } diff --git a/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java b/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java index 2b78d36222d7562c4e9e74cf5ee1874d302dfaa8..cdf4682d6d141ec2844eb8cf8d463912aa11b61a 100644 --- a/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java +++ b/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java @@ -55,14 +55,6 @@ import org.olat.core.util.Formatter; */ public class WikiMarkupRenderer extends DefaultComponentRenderer { - /** - * @see org.olat.core.gui.components.ComponentRenderer#render(org.olat.core.gui.render.Renderer, - * org.olat.core.gui.render.StringOutput, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.render.URLBuilder, - * org.olat.core.gui.translator.Translator, - * org.olat.core.gui.render.RenderResult, java.lang.String[]) - */ @Override public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator, RenderResult renderResult, String[] args) { @@ -97,9 +89,9 @@ public class WikiMarkupRenderer extends DefaultComponentRenderer { String targetUrl = " onclick=\"o_XHREvent(jQuery(this).attr('href'),false,true); return false;\""; input.setURLTarget(targetUrl); } - sb.append("<div style=\"min-height:"+ wikiComp.getMinHeight() +"px\" id=\""); - sb.append(uniqueId); - sb.append("\">"); + sb.append("<div style=\"min-height:").append(wikiComp.getMinHeight()).append("px\" id=\"") + .append(uniqueId) + .append("\">"); JFlexParser parser = new JFlexParser(input); parsedDoc = parser.parseHTML(wikiComp.getWikiContent()); @@ -109,12 +101,11 @@ public class WikiMarkupRenderer extends DefaultComponentRenderer { throw new OLATRuntimeException(this.getClass(), "error while rendering wiki page with content:"+ wikiComp.getWikiContent(), e); } // Use global js math formatter for latex formulas - sb.append(Formatter.formatLatexFormulas(parsedDoc.getContent())); - sb.append("</div>"); + sb.append(Formatter.formatLatexFormulas(parsedDoc.getContent())) + .append("</div>"); //set targets of media, image and external links to target "_blank" - sb.append("<script type=\"text/javascript\">/* <![CDATA[ */ "); - String instanceUrl = Settings.getServerContextPathURI(); - sb.append("changeAnchorTargets('").append(uniqueId).append("','").append(instanceUrl).append("');"); - sb.append("/* ]]> */</script>"); + sb.append("<script type=\"text/javascript\">/* <![CDATA[ */ ") + .append("changeAnchorTargets('").append(uniqueId).append("','").append(Settings.getServerContextPathURI()).append("');") + .append("/* ]]> */</script>"); } } diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties index dcf02261fa2a1f0e44b2d7e05a824d2389029bad..3e6c1604b599cde59871d8cca4e1a7af7314cf67 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -517,6 +517,8 @@ jmx.rmi.port=3000 mathjax.cdn=//mathjax.openolat.org/mathjax/2.7-latest/ mathjax.config=TeX-AMS-MML_HTMLorMML +# find \( \), \[ \], $$ to trigger MathJax rendering +mathjax.markers=true ######################################################################## # Database settings