Commit 9bf333db authored by Curtis Adam's avatar Curtis Adam

Refactor the markdeep content converter

parent ad145b53
......@@ -11,9 +11,8 @@ sonarqube {
property "sonar.sourceEncoding", "UTF-8"
property "sonar.language", "js"
property "sonar.sources", "./"
// client/lib.js causes ClassNotFoundException.
// See https://github.com/SonarSource/sonar-javascript/issues/552.
property "sonar.exclusions", "**/node_modules/**,client/lib.js"
property "sonar.exclusions", "**/node_modules/**"
property "sonar.host.url", "https://scm.thm.de/sonar/"
}
}
let customMathJaxDefinitions = [
"{\\n}{\\hat{n}}",
"{\\thetai}{\\theta_\\mathrm{i}}",
"{\\thetao}{\\theta_\\mathrm{o}}",
"{\\d}[1]{\\mathrm{d}#1}",
"{\\w}{\\hat{\\omega}}",
"{\\wi}{\\w_\\mathrm{i}}",
"{\\wo}{\\w_\\mathrm{o}}",
"{\\wh}{\\w_\\mathrm{h}}",
"{\\Li}{L_\\mathrm{i}}",
"{\\Lo}{L_\\mathrm{o}}",
"{\\Le}{L_\\mathrm{e}}",
"{\\Lr}{L_\\mathrm{r}}",
"{\\Lt}{L_\\mathrm{t}}",
"{\\O}{\\mathrm{O}}",
"{\\degrees}{{^{\\large\\circ}}}",
"{\\T}{\\mathsf{T}}",
"{\\mathset}[1]{\\mathbb{#1}}",
"{\\Real}{\\mathset{R}}",
"{\\Integer}{\\mathset{Z}}",
"{\\Boolean}{\\mathset{B}}",
"{\\Complex}{\\mathset{C}}",
"{\\un}[1]{\\,\\mathrm{#1}}"
];
/** Wraps image files inside a lightbox-img class
* @param {string} content - Text that contains the image
* @returns {string} - The wrapped text
* */
export function setLightBoxes(content) {
var element = $(content);
let item_id = Math.random().toString(36).substr(2);
$(element).find('img').each(function () {
let imageTitleElement = $(this).closest('.image');
imageTitleElement = imageTitleElement.last();
let imageTitle = imageTitleElement.text();
let imageUrl = $(this).attr('src');
$(this).attr('data-type', 'cardImage');
let wrapped = $(this).wrap('<div class="lightbox-container"><a href="' + imageUrl + '" class="lightbox-img" title="' + imageTitle + '" target="_blank" data-lightbox="' + item_id + '"></a></div>').parent().prop('outerHTML');
$(this).text(wrapped);
});
//NOTE:
// The jQueryObject -content- needs to be wrapped in an seperate element,
// otherwise only the first element in content will be returned by .html()
return $('<div/>').append(element).html();
}
export function adjustIframe(content) {
let element = $(content);
$(element).find('iframe').each(function () {
$(this).attr('frameBorder', 0);
});
return $('<div/>').append(element).html();
}
export function addCustomMathJax() {
let mathJaxJoinString = '\\newcommand';
let mathJaxCostumCommands = '<span style="display:none">$$';
mathJaxCostumCommands += (mathJaxJoinString + customMathJaxDefinitions.join(mathJaxJoinString));
return (mathJaxCostumCommands + '$$\n</span>\n');
}
export function displayMediaControls(content) {
let element = $(content);
$(element).find('video').each(function () {
$(this).attr('controls', true);
});
$(element).find('audio').each(function () {
$(this).attr('controls', true);
});
return $('<div/>').append(element).html();
}
/** Adds target _blank to all links
* @param {string} content - Text that contains the href
* @returns {string} - The modified text
* */
export function setLinkTarget(content) {
var element = $(content);
$(element).find('a').each(function () {
let href = $(this).attr('href');
if (/^#/.test(href) === false && /^mailto/.test(href) === false) {
$(this).attr('target', '_blank');
}
});
return $('<div/>').append(element).html();
}
import {MeteorMathJax} from 'meteor/mrt:mathjax';
import DOMPurify from 'dompurify';
import {DOMPurifyConfig} from "./dompurify";
import {CardVisuals} from "./cardVisuals";
import "/client/markdeep.min.js";
let customMathJaxDefinitions = [
"{\\n}{\\hat{n}}",
"{\\thetai}{\\theta_\\mathrm{i}}",
"{\\thetao}{\\theta_\\mathrm{o}}",
"{\\d}[1]{\\mathrm{d}#1}",
"{\\w}{\\hat{\\omega}}",
"{\\wi}{\\w_\\mathrm{i}}",
"{\\wo}{\\w_\\mathrm{o}}",
"{\\wh}{\\w_\\mathrm{h}}",
"{\\Li}{L_\\mathrm{i}}",
"{\\Lo}{L_\\mathrm{o}}",
"{\\Le}{L_\\mathrm{e}}",
"{\\Lr}{L_\\mathrm{r}}",
"{\\Lt}{L_\\mathrm{t}}",
"{\\O}{\\mathrm{O}}",
"{\\degrees}{{^{\\large\\circ}}}",
"{\\T}{\\mathsf{T}}",
"{\\mathset}[1]{\\mathbb{#1}}",
"{\\Real}{\\mathset{R}}",
"{\\Integer}{\\mathset{Z}}",
"{\\Boolean}{\\mathset{B}}",
"{\\Complex}{\\mathset{C}}",
"{\\un}[1]{\\,\\mathrm{#1}}"
];
MeteorMathJax.sourceUrl = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS_SVG';
MeteorMathJax.defaultConfig = {
TeX: {equationNumbers: {autoNumber: "AMS"}},
menuSettings: {
zoom: "Hover",
zscale: "250%",
locale: "de"
}
};
export let MarkdeepContent = class MarkdeepContent {
/** Wraps image files inside a lightbox-img class
* @param {string} content - Text that contains the image
* @returns {string} - The wrapped text
* */
static setLightBoxes (content) {
var element = $(content);
let item_id = Math.random().toString(36).substr(2);
$(element).find('img').each(function () {
let imageTitleElement = $(this).closest('.image');
imageTitleElement = imageTitleElement.last();
let imageTitle = imageTitleElement.text();
let imageUrl = $(this).attr('src');
$(this).attr('data-type', 'cardImage');
let wrapped = $(this).wrap('<div class="lightbox-container"><a href="' + imageUrl + '" class="lightbox-img" title="' + imageTitle + '" target="_blank" data-lightbox="' + item_id + '"></a></div>').parent().prop('outerHTML');
$(this).text(wrapped);
});
//NOTE:
// The jQueryObject -content- needs to be wrapped in an seperate element,
// otherwise only the first element in content will be returned by .html()
return $('<div/>').append(element).html();
}
static adjustIframe (content) {
let element = $(content);
$(element).find('iframe').each(function () {
$(this).attr('frameBorder', 0);
});
return $('<div/>').append(element).html();
}
static addCustomMathJax () {
let mathJaxJoinString = '\\newcommand';
let mathJaxCostumCommands = '<span style="display:none">$$';
mathJaxCostumCommands += (mathJaxJoinString + customMathJaxDefinitions.join(mathJaxJoinString));
return (mathJaxCostumCommands + '$$\n</span>\n');
}
static displayMediaControls (content) {
let element = $(content);
$(element).find('video').each(function () {
$(this).attr('controls', true);
});
$(element).find('audio').each(function () {
$(this).attr('controls', true);
});
return $('<div/>').append(element).html();
}
/** Adds target _blank to all links
* @param {string} content - Text that contains the href
* @returns {string} - The modified text
* */
static setLinkTarget (content) {
var element = $(content);
$(element).find('a').each(function () {
let href = $(this).attr('href');
if (/^#/.test(href) === false && /^mailto/.test(href) === false) {
$(this).attr('target', '_blank');
}
});
return $('<div/>').append(element).html();
}
static convert (content) {
content += "\n\n";
content = window.markdeep.format(content, true);
content = DOMPurify.sanitize(content, DOMPurifyConfig);
content = this.setLightBoxes(content);
content = this.displayMediaControls(content);
content = this.adjustIframe(content);
CardVisuals.setTextZoom();
content = this.setLinkTarget(content);
content += this.addCustomMathJax();
return content;
}
};
......@@ -5,19 +5,17 @@ import {CollegesCourses} from "../../api/colleges_courses.js";
import {Leitner} from "../../api/learned.js";
import {Session} from "meteor/session";
import {MeteorMathJax} from 'meteor/mrt:mathjax';
import * as lib from '/client/lib.js';
import {Paid} from "../../api/paid";
import {CardType} from "../../api/cardTypes";
import DOMPurify from 'dompurify';
import {DOMPurifyConfig} from "../../api/dompurify.js";
import "/client/markdeep.min.js";
import {getAuthorName} from "../../api/userdata";
import {Route} from "../../api/route";
import {CardVisuals} from "../../api/cardVisuals";
import {UserPermissions} from "../../api/permissions";
import {Bonus} from "../../api/bonus";
import {Profile} from "../../api/profile";
import {BonusForm} from "../../api/bonusForm";
import {MarkdeepContent} from "../../api/markdeep";
Meteor.subscribe("collegesCourses");
......@@ -697,30 +695,11 @@ Template.registerHelper("getMaximumText", function (text) {
return text;
});
const helper = new MeteorMathJax.Helper({
const markdeepHelper = new MeteorMathJax.Helper({
useCache: true,
transform: function (x) {
x += "\n\n";
x = window.markdeep.format(x, true);
x = DOMPurify.sanitize(x, DOMPurifyConfig);
x = lib.setLightBoxes(x);
x = lib.displayMediaControls(x);
x = lib.adjustIframe(x);
CardVisuals.setTextZoom();
x = lib.setLinkTarget(x);
x += lib.addCustomMathJax();
return x;
}
});
Template.registerHelper('mathjax', helper.getTemplate());
MeteorMathJax.sourceUrl = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS_SVG';
MeteorMathJax.defaultConfig = {
TeX: {equationNumbers: {autoNumber: "AMS"}},
menuSettings: {
zoom: "Hover",
zscale: "250%",
locale: "de"
}
};
transform: function (content) {
return MarkdeepContent.convert(content);
}
});
Template.registerHelper('markdeep', markdeepHelper.getTemplate());
......@@ -36,7 +36,7 @@
<span class="{{#if gotContent}}{{#if
isCentered}}center-align {{#if isLeftAlign}}left-text-align{{/if}}{{/if}}{{else}}placeholder{{/if}}">
{{#if gotContent}}
{{#mathjax}}{{getContent}}{{/mathjax}}
{{#markdeep}}{{getContent}}{{/markdeep}}
{{else}}
{{getPlaceholder}}
{{/if}}
......@@ -47,7 +47,7 @@
<span class="{{#if gotContent}}{{#if
isCentered}}center-align {{#if isLeftAlign}}left-text-align{{/if}}{{/if}}{{else}}placeholder{{/if}}">
{{#if gotContent}}
{{#mathjax}}{{getContent}}{{/mathjax}}
{{#markdeep}}{{getContent}}{{/markdeep}}
{{else}}
{{getPlaceholder}}
{{/if}}
......
......@@ -8,13 +8,13 @@
</h4>
</div>
<div class="modal-body">
{{#mathjax}}
{{#markdeep}}
{{#if isActiveLanguage 'de'}}
{{> demoHelpModalContentGerman}}
{{else}}
{{> demoHelpModalContentEnglish}}
{{/if}}
{{/mathjax}}
{{/markdeep}}
<button class="btn btn-raised btn-success btn-block"
id="demoHelpConfirm">{{_ "demo.help.button.confirm"}}</button>
</div>
......
......@@ -24,7 +24,7 @@
</div>
<div class="row markdeepCardset markdeepCardsetContent">
<hr class="markdeepCardsetHeader">
{{#mathjax}}{{description}}{{/mathjax}}
{{#markdeep}}{{description}}{{/markdeep}}
</div>
</div>
{{#if isLecturerAndHasRequest}}
......
......@@ -220,7 +220,7 @@
<div class="col-xs-12">
{{#if this.description}}
<div class="resultDescription">
{{#mathjax}}{{this.description}}{{/mathjax}}
{{#markdeep}}{{this.description}}{{/markdeep}}
</div>
{{/if}}
</div>
......
......@@ -8,13 +8,13 @@
</h4>
</div>
<div class="modal-body">
{{#mathjax}}
{{#markdeep}}
{{#if isActiveLanguage 'de'}}
{{> leitnerHelpModalContentGerman}}
{{else}}
{{> leitnerHelpModalContentEnglish}}
{{/if}}
{{/mathjax}}
{{/markdeep}}
<button class="btn btn-raised btn-success"
id="leitnerHelpConfirm">{{_ "leitner.help.button.confirm"}}</button>
</div>
......
......@@ -8,13 +8,13 @@
</h4>
</div>
<div class="modal-body">
{{#mathjax}}
{{#markdeep}}
{{#if isActiveLanguage 'de'}}
{{> wozniakHelpModalContentGerman}}
{{else}}
{{> wozniakHelpModalContentEnglish}}
{{/if}}
{{/mathjax}}
{{/markdeep}}
<button class="btn btn-raised btn-success"
id="wozniakHelpConfirm">{{_ "wozniak.help.button.confirm"}}</button>
</div>
......
......@@ -36,7 +36,7 @@
{{#each searchCategories}}
<a href="/cardset/{{_id}}" class="list-group-item clearfix">
<h4 class="list-group-item-heading search-subject search-subject-{{kind}}">{{name}}</h4>
<p class="list-group-item-text search-content">{{#mathjax}}{{description}}{{/mathjax}}</p>
<p class="list-group-item-text search-content">{{#markdeep}}{{description}}{{/markdeep}}</p>
{{#with getAuthor this.owner}}
<p class="list-group-item-text search-author">{{_
"cardset.info.author"}}
......
......@@ -8,13 +8,13 @@
</h4>
</div>
<div class="modal-body">
{{#mathjax}}
{{#markdeep}}
{{#if isActiveLanguage 'de'}}
{{> presentationHelpModalContentGerman}}
{{else}}
{{> presentationHelpModalContentEnglish}}
{{/if}}
{{/mathjax}}
{{/markdeep}}
<button class="btn btn-raised btn-success btn-block"
id="presentationHelpConfirm">{{_ "presentation.help.button.confirm"}}</button>
</div>
......
......@@ -32,9 +32,9 @@
<table class="table">
<tr>
<td>
{{#mathjax}}
{{#markdeep}}
{{this.description}}
{{/mathjax}}
{{/markdeep}}
</td>
</tr>
</table>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment