Notes/src/utils.js

232 lines
7.0 KiB
JavaScript
Raw Normal View History

2019-10-09 12:21:55 +03:00
import global from '@ckeditor/ckeditor5-utils/src/dom/global';
import BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';
2019-10-09 12:21:55 +03:00
2019-10-01 23:11:51 +03:00
export function getSelectedMathModelWidget( selection ) {
const selectedElement = selection.getSelectedElement();
2020-08-29 17:33:41 +03:00
if ( selectedElement && ( selectedElement.is( 'element', 'mathtex-inline' ) || selectedElement.is( 'element', 'mathtex-display' ) ) ) {
2019-10-01 23:11:51 +03:00
return selectedElement;
}
2019-10-01 23:11:51 +03:00
return null;
}
2019-10-06 11:13:17 +03:00
// Simple MathJax 3 version check
export function isMathJaxVersion3( version ) {
return version && typeof version === 'string' && version.split( '.' ).length === 3 && version.split( '.' )[ 0 ] === '3';
}
2020-04-05 17:24:46 +03:00
// Check if equation has delimiters.
2019-10-06 11:13:17 +03:00
export function hasDelimiters( text ) {
return text.match( /^(\\\[.*?\\\]|\\\(.*?\\\))$/ );
}
2019-10-11 18:10:41 +03:00
// Find delimiters count
export function delimitersCounts( text ) {
return text.match( /(\\\[|\\\]|\\\(|\\\))/g ).length;
}
2019-10-06 11:13:17 +03:00
// Extract delimiters and figure display mode for the model
export function extractDelimiters( equation ) {
equation = equation.trim();
// Remove delimiters (e.g. \( \) or \[ \])
const hasInlineDelimiters = equation.includes( '\\(' ) && equation.includes( '\\)' );
const hasDisplayDelimiters = equation.includes( '\\[' ) && equation.includes( '\\]' );
if ( hasInlineDelimiters || hasDisplayDelimiters ) {
equation = equation.substring( 2, equation.length - 2 ).trim();
}
return {
equation,
display: hasDisplayDelimiters
};
}
export async function renderEquation(
equation, element, engine = 'katex', lazyLoad, display = false, preview = false, previewUid, previewClassName = []
) {
2019-09-17 20:07:01 +03:00
if ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) {
2019-10-01 23:11:51 +03:00
if ( isMathJaxVersion3( MathJax.version ) ) {
selectRenderMode( element, preview, previewUid, previewClassName, el => {
2019-10-03 03:47:26 +03:00
renderMathJax3( equation, el, display, () => {
2019-10-03 12:43:58 +03:00
if ( preview ) {
2019-10-03 03:47:26 +03:00
moveAndScaleElement( element, el );
2019-10-09 10:50:12 +03:00
el.style.visibility = 'visible';
2019-10-01 23:11:51 +03:00
}
} );
2019-10-03 03:47:26 +03:00
} );
2019-08-31 20:48:37 +03:00
} else {
selectRenderMode( element, preview, previewUid, previewClassName, el => {
2019-10-03 18:32:31 +03:00
// Fixme: MathJax typesetting cause occasionally math processing error without asynchronous call
2019-10-09 12:21:55 +03:00
global.window.setTimeout( () => {
2019-10-03 18:32:31 +03:00
renderMathJax2( equation, el, display );
// Move and scale after rendering
if ( preview ) {
// eslint-disable-next-line
MathJax.Hub.Queue( () => {
moveAndScaleElement( element, el );
2019-10-09 10:50:12 +03:00
el.style.visibility = 'visible';
2019-10-03 18:32:31 +03:00
} );
}
} );
2019-10-01 23:11:51 +03:00
} );
2019-08-31 20:48:37 +03:00
}
2019-09-17 16:19:35 +03:00
} else if ( engine === 'katex' && typeof katex !== 'undefined' ) {
selectRenderMode( element, preview, previewUid, previewClassName, el => {
2019-10-03 03:47:26 +03:00
katex.render( equation, el, {
throwOnError: false,
displayMode: display
} );
2019-10-03 12:43:58 +03:00
if ( preview ) {
moveAndScaleElement( element, el );
2019-10-09 10:50:12 +03:00
el.style.visibility = 'visible';
2019-10-03 12:43:58 +03:00
}
2019-10-01 23:11:51 +03:00
} );
2019-09-17 16:19:35 +03:00
} else if ( typeof engine === 'function' ) {
2019-10-03 23:25:16 +03:00
engine( equation, element, display );
2019-08-31 20:48:37 +03:00
} else {
if ( typeof lazyLoad !== 'undefined' ) {
try {
if ( !global.window.CKEDITOR_MATH_LAZY_LOAD ) {
global.window.CKEDITOR_MATH_LAZY_LOAD = lazyLoad();
}
element.innerHTML = equation;
await global.window.CKEDITOR_MATH_LAZY_LOAD;
renderEquation( equation, element, engine, undefined, display, preview, previewUid, previewClassName );
}
catch ( err ) {
element.innerHTML = equation;
console.error( `math-tex-typesetting-lazy-load-failed: Lazy load failed: ${ err }` );
}
} else {
element.innerHTML = equation;
console.warn( `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${ engine }) for tex.` );
}
2019-08-31 20:48:37 +03:00
}
2019-09-28 13:01:08 +03:00
}
export function getBalloonPositionData( editor ) {
const view = editor.editing.view;
const defaultPositions = BalloonPanelView.defaultPositions;
const selectedElement = view.document.selection.getSelectedElement();
if ( selectedElement ) {
return {
target: view.domConverter.viewToDom( selectedElement ),
positions: [
2021-02-28 12:50:24 +02:00
defaultPositions.southArrowNorth,
defaultPositions.southArrowNorthWest,
2021-04-16 17:00:22 -05:00
defaultPositions.southArrowNorthEast
]
};
}
else {
const viewDocument = view.document;
return {
target: view.domConverter.viewRangeToDom( viewDocument.selection.getFirstRange() ),
positions: [
2021-02-28 12:50:24 +02:00
defaultPositions.southArrowNorth,
defaultPositions.southArrowNorthWest,
2021-04-16 17:00:22 -05:00
defaultPositions.southArrowNorthEast
]
};
}
}
function selectRenderMode( element, preview, previewUid, previewClassName, cb ) {
2019-10-03 03:47:26 +03:00
if ( preview ) {
createPreviewElement( element, previewUid, previewClassName, previewEl => {
2021-04-16 17:00:22 -05:00
cb( previewEl );
2019-10-03 03:47:26 +03:00
} );
} else {
cb( element );
}
}
2020-04-05 17:24:46 +03:00
function renderMathJax3( equation, element, display, cb ) {
2019-10-03 03:47:26 +03:00
let promiseFunction = undefined;
if ( typeof MathJax.tex2chtmlPromise !== 'undefined' ) {
promiseFunction = MathJax.tex2chtmlPromise;
} else if ( typeof MathJax.tex2svgPromise !== 'undefined' ) {
promiseFunction = MathJax.tex2svgPromise;
}
if ( typeof promiseFunction !== 'undefined' ) {
2019-10-04 20:01:28 +03:00
promiseFunction( equation, { display } ).then( node => {
2019-10-03 03:47:26 +03:00
if ( element.firstChild ) {
2019-10-04 20:01:28 +03:00
element.removeChild( element.firstChild );
2019-10-03 03:47:26 +03:00
}
2019-10-04 20:01:28 +03:00
element.appendChild( node );
2020-04-05 17:24:46 +03:00
cb();
2019-10-03 03:47:26 +03:00
} );
}
}
function renderMathJax2( equation, element, display ) {
2019-10-03 18:32:31 +03:00
if ( display ) {
element.innerHTML = '\\[' + equation + '\\]';
} else {
element.innerHTML = '\\(' + equation + '\\)';
}
2019-10-09 12:21:55 +03:00
// eslint-disable-next-line
MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] );
2019-10-03 03:47:26 +03:00
}
function createPreviewElement( element, previewUid, previewClassName, render ) {
const previewEl = getPreviewElement( element, previewUid, previewClassName );
2021-04-16 17:00:22 -05:00
render( previewEl );
2019-10-03 03:47:26 +03:00
}
function getPreviewElement( element, previewUid, previewClassName ) {
2021-04-16 17:00:22 -05:00
let previewEl = global.document.getElementById( previewUid );
2019-10-06 11:13:17 +03:00
// Create if not found
2021-04-16 17:00:22 -05:00
if ( !previewEl ) {
previewEl = global.document.createElement( 'div' );
previewEl.setAttribute( 'id', previewUid );
previewEl.classList.add( ...previewClassName );
2021-04-16 17:00:22 -05:00
previewEl.style.visibility = 'hidden';
global.document.body.appendChild( previewEl );
2019-10-03 03:47:26 +03:00
let ticking = false;
const renderTransformation = () => {
if ( !ticking ) {
2019-10-09 12:21:55 +03:00
global.window.requestAnimationFrame( () => {
2021-04-16 17:00:22 -05:00
moveElement( element, previewEl );
2019-10-03 03:47:26 +03:00
ticking = false;
} );
ticking = true;
}
};
// Create scroll listener for following
2019-10-09 12:21:55 +03:00
global.window.addEventListener( 'resize', renderTransformation );
global.window.addEventListener( 'scroll', renderTransformation );
2019-10-03 03:47:26 +03:00
}
2021-04-16 17:00:22 -05:00
return previewEl;
2019-10-03 03:47:26 +03:00
}
2019-10-04 20:01:28 +03:00
function moveAndScaleElement( parent, child ) {
// Move to right place
moveElement( parent, child );
2019-10-03 03:47:26 +03:00
// Scale parent element same as preview
2019-10-04 20:01:28 +03:00
const domRect = child.getBoundingClientRect();
2019-10-04 18:45:32 +03:00
parent.style.width = domRect.width + 'px';
2019-10-03 03:47:26 +03:00
parent.style.height = domRect.height + 'px';
}
2019-10-04 20:01:28 +03:00
function moveElement( parent, child ) {
2019-10-03 03:47:26 +03:00
const domRect = parent.getBoundingClientRect();
2019-10-09 12:21:55 +03:00
const left = global.window.scrollX + domRect.left;
const top = global.window.scrollY + domRect.top;
2019-10-04 20:01:28 +03:00
child.style.position = 'absolute';
child.style.left = left + 'px';
child.style.top = top + 'px';
child.style.zIndex = 'var(--ck-z-modal)';
child.style.pointerEvents = 'none';
2019-10-03 03:47:26 +03:00
}