Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/behaviors/markdown/render_math.js')
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_math.js99
1 files changed, 64 insertions, 35 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_math.js b/app/assets/javascripts/behaviors/markdown/render_math.js
index 5479866c99a..8238f5523f3 100644
--- a/app/assets/javascripts/behaviors/markdown/render_math.js
+++ b/app/assets/javascripts/behaviors/markdown/render_math.js
@@ -1,6 +1,6 @@
-import { deprecatedCreateFlash as flash } from '~/flash';
+import { spriteIcon } from '~/lib/utils/common_utils';
import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
-import { s__, sprintf } from '~/locale';
+import { s__ } from '~/locale';
// Renders math using KaTeX in any element with the
// `js-render-math` class
@@ -13,30 +13,10 @@ import { s__, sprintf } from '~/locale';
const MAX_MATH_CHARS = 1000;
const MAX_RENDER_TIME_MS = 2000;
-// These messages might be used with inline errors in the future. Keep them around. For now, we will
-// display a single error message using flash().
-
-// const CHAR_LIMIT_EXCEEDED_MSG = sprintf(
-// s__(
-// 'math|The following math is too long. For performance reasons, math blocks are limited to %{maxChars} characters. Try splitting up this block, or include an image instead.',
-// ),
-// { maxChars: MAX_MATH_CHARS },
-// );
-// const RENDER_TIME_EXCEEDED_MSG = s__(
-// "math|The math in this entry is taking too long to render. Any math below this point won't be shown. Consider splitting it among multiple entries.",
-// );
-
-const RENDER_FLASH_MSG = sprintf(
- s__(
- 'math|The math in this entry is taking too long to render and may not be displayed as expected. For performance reasons, math blocks are also limited to %{maxChars} characters. Consider splitting up large formulae, splitting math blocks among multiple entries, or using an image instead.',
- ),
- { maxChars: MAX_MATH_CHARS },
-);
-
// Wait for the browser to reflow the layout. Reflowing SVG takes time.
// This has to wrap the inner function, otherwise IE/Edge throw "invalid calling object".
const waitForReflow = (fn) => {
- window.requestAnimationFrame(fn);
+ window.requestIdleCallback(fn);
};
/**
@@ -67,37 +47,69 @@ class SafeMathRenderer {
this.renderElement = this.renderElement.bind(this);
this.render = this.render.bind(this);
+ this.attachEvents = this.attachEvents.bind(this);
}
- renderElement() {
- if (!this.queue.length) {
+ renderElement(chosenEl) {
+ if (!this.queue.length && !chosenEl) {
return;
}
- const el = this.queue.shift();
+ const el = chosenEl || this.queue.shift();
+ const forceRender = Boolean(chosenEl);
const text = el.textContent;
el.removeAttribute('style');
-
- if (this.totalMS >= MAX_RENDER_TIME_MS || text.length > MAX_MATH_CHARS) {
- if (!this.flashShown) {
- flash(RENDER_FLASH_MSG);
- this.flashShown = true;
- }
-
+ if (!forceRender && (this.totalMS >= MAX_RENDER_TIME_MS || text.length > MAX_MATH_CHARS)) {
// Show unrendered math code
+ const wrapperElement = document.createElement('div');
const codeElement = document.createElement('pre');
+
codeElement.className = 'code';
codeElement.textContent = el.textContent;
- el.parentNode.replaceChild(codeElement, el);
+
+ const { parentNode } = el;
+ parentNode.replaceChild(wrapperElement, el);
+
+ const html = `
+ <div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-math-container js-lazy-render-math-container fade show" role="alert">
+ ${spriteIcon('warning', 'text-warning-600 s16 gl-alert-icon')}
+ <div class="display-flex gl-alert-content">
+ <div>${s__(
+ 'math|Displaying this math block may cause performance issues on this page',
+ )}</div>
+ <div class="gl-alert-actions">
+ <button class="js-lazy-render-math btn gl-alert-action btn-primary btn-md gl-button">Display anyway</button>
+ </div>
+ </div>
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+ ${spriteIcon('close', 's16')}
+ </button>
+ </div>
+ `;
+
+ if (!wrapperElement.classList.contains('lazy-alert-shown')) {
+ wrapperElement.innerHTML = html;
+ wrapperElement.append(codeElement);
+ wrapperElement.classList.add('lazy-alert-shown');
+ }
// Render the next math
this.renderElement();
} else {
this.startTime = Date.now();
+ /* Get the correct reference to the display container when:
+ * a.) Happy path: when the math block is present, and
+ * b.) When we've replace the block with <pre> for lazy rendering
+ */
+ let displayContainer = el;
+ if (el.tagName === 'PRE') {
+ displayContainer = el.parentElement;
+ }
+
try {
- el.innerHTML = this.katex.renderToString(text, {
+ displayContainer.innerHTML = this.katex.renderToString(text, {
displayMode: el.getAttribute('data-math-style') === 'display',
throwOnError: true,
maxSize: 20,
@@ -135,6 +147,22 @@ class SafeMathRenderer {
// and less prone to timeouts.
setTimeout(this.renderElement, 400);
}
+
+ attachEvents() {
+ document.body.addEventListener('click', (event) => {
+ if (!event.target.classList.contains('js-lazy-render-math')) {
+ return;
+ }
+
+ const parent = event.target.closest('.js-lazy-render-math-container');
+
+ const pre = parent.nextElementSibling;
+
+ parent.remove();
+
+ this.renderElement(pre);
+ });
+ }
}
export default function renderMath($els) {
@@ -146,6 +174,7 @@ export default function renderMath($els) {
.then(([katex]) => {
const renderer = new SafeMathRenderer($els.get(), katex);
renderer.render();
+ renderer.attachEvents();
})
.catch(() => {});
}