Refactor code

This commit is contained in:
Sauli Anto 2019-10-01 23:11:51 +03:00
parent 5011fe40b0
commit f89affbc3f
8 changed files with 126 additions and 116 deletions

View File

@ -3,5 +3,9 @@
'use strict';
module.exports = {
extends: 'ckeditor5'
extends: 'ckeditor5',
globals: {
'MathJax': true,
'katex': true
}
};

View File

@ -54,7 +54,7 @@ Styles requires PostCSS like offical CKEditor plugins.
### Available typesetting engines
__MathJax__
- Tested by using version __2.7.5__ and __TeX-MML-AM_HTMLorMML__ configuration. It works also with version __3.0.0__ or newer!
- Tested by using version __2.7.5__ and __TeX-MML-AM_HTMLorMML__ configuration. It has also experimental (__CHTML__, __SVG__) support for __3.0.0__ or newer version.
- Use __\\( \\)__ delimiters for inline and __\\[ \\]__ delimiters for display
__KaTeX__

View File

@ -4,7 +4,7 @@ import Undo from '@ckeditor/ckeditor5-undo/src/undo';
import LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';
import LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition';
import { defaultConfig, removeDelimiters, EQUATION_REGEXP } from './utils';
import { defaultConfig, extractDelimiters, hasDelimiters } from './utils';
export default class AutoMath extends Plugin {
static get requires() {
@ -66,19 +66,19 @@ export default class AutoMath extends Plugin {
const equationRange = new LiveRange( leftPosition, rightPosition );
const walker = equationRange.getWalker( { ignoreElementEnd: true } );
let equation = '';
let text = '';
// Get equation text
for ( const node of walker ) {
if ( node.item.is( 'textProxy' ) ) {
equation += node.item.data;
text += node.item.data;
}
}
equation = equation.trim();
text = text.trim();
// Check if equation
if ( !equation.match( EQUATION_REGEXP ) ) {
// Skip if don't have delimiters
if ( !hasDelimiters( text ) ) {
return;
}
@ -107,7 +107,7 @@ export default class AutoMath extends Plugin {
editor.model.change( writer => {
const params = {
...removeDelimiters( equation ),
...extractDelimiters( text ),
type: mathConfig.outputType,
};
const mathElement = writer.createElement( 'mathtex', params );

View File

@ -1,11 +1,10 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import MathCommand from './mathcommand';
import { defaultConfig, renderEquation, removeDelimiters } from './utils';
import { defaultConfig, renderEquation, extractDelimiters } from './utils';
export default class MathEditing extends Plugin {
static get requires() {
@ -78,26 +77,6 @@ export default class MathEditing extends Plugin {
} );
}
} )
// Todo: Implement input conversion
/*
// MathML (e.g. <math type="math/tex; mode=display" alttext="\sqrt{\frac{a}{b}}">...</script>)
.elementToElement( {
view: {
name: 'math',
},
model: ( viewElement, modelWriter ) => {
const equation = viewElement.getAttribute( 'alttext' );
const display = viewElement.getAttribute( 'display' );
if ( equation ) {
return modelWriter.createElement( 'mathtex', {
equation,
type: mathConfig.forceOutputType ? mathConfig.outputType : 'math',
display: display === 'block' ? true : false
} );
}
}
} )
*/
// CKEditor 4 way (e.g. <span class="math-tex">\( \sqrt{\frac{a}{b}} \)</span>)
.elementToElement( {
view: {
@ -108,7 +87,7 @@ export default class MathEditing extends Plugin {
const equation = viewElement.getChild( 0 ).data.trim();
const params = {
...removeDelimiters( equation ),
...extractDelimiters( equation ),
type: mathConfig.forceOutputType ? mathConfig.outputType : 'span'
};
@ -136,7 +115,7 @@ export default class MathEditing extends Plugin {
const equation = modelItem.getAttribute( 'equation' );
const display = modelItem.getAttribute( 'display' );
const styles = 'user-select: none; ' + ( display ? 'display: block;' : 'display: inline-block;' );
const styles = 'user-select: none; ' + ( display ? '' : 'display: inline-block;' );
const classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' );
// CKEngine render multiple times if using span instead of div
@ -177,19 +156,7 @@ export default class MathEditing extends Plugin {
}
return mathtexView;
}
/*
else if ( type === 'math' ) {
const mathtexView = viewWriter.createContainerElement( 'math', {
display: display ? 'block' : 'inline',
alttex: equation
} );
// Todo: Implement output conversion
return mathtexView;
}
*/
else {
} else {
const mathtexView = viewWriter.createContainerElement( 'script', {
type: display ? 'math/tex; mode=display' : 'math/tex'
} );

View File

@ -15,7 +15,7 @@ import cancelIcon from '@ckeditor/ckeditor5-core/theme/icons/cancel.svg';
import submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';
import { removeDelimiters, EQUATION_REGEXP } from '../utils';
import { extractDelimiters, hasDelimiters } from '../utils';
import MathView from './mathview';
@ -33,8 +33,9 @@ export default class MainFormView extends View {
// Equation input
this.mathInputView = this._createMathInput();
// Fixme:
// Preview isn't available in katex, because .ck-reset_all * css rule breaks it
this.previewEnabled = engine !== 'katex';
this.previewEnabled = engine !== 'katex' || true;
// Display button
this.displayButtonView = this._createDisplayButton();
@ -166,9 +167,9 @@ export default class MainFormView extends View {
const equationInput = inputView.element.value.trim();
// If input has delimiters
if ( equationInput.match( EQUATION_REGEXP ) ) {
if ( hasDelimiters( equationInput ) ) {
// Get equation without delimiters
const params = removeDelimiters( equationInput );
const params = extractDelimiters( equationInput );
// Remove delimiters from input field
inputView.element.value = params.equation;

View File

@ -1,4 +1,5 @@
import View from '@ckeditor/ckeditor5-ui/src/view';
import { renderEquation } from '../utils';
export default class MathView extends View {
@ -15,7 +16,7 @@ export default class MathView extends View {
} );
this.setTemplate( {
tag: 'div',
tag: 'iframe',
attributes: {
class: [
'ck',
@ -26,7 +27,43 @@ export default class MathView extends View {
}
updateMath() {
renderEquation( this.value, this.element, this.engine, this.display );
const el = this.element;
if ( el ) {
// Fixme
// eslint-disable-next-line
setTimeout( () => {
let docEl = ( el.contentWindow || el.contentDocument );
if ( docEl.document ) {
docEl = docEl.document;
}
const headEl = docEl.head;
// Remove old styles
while ( headEl.hasChildNodes() ) {
headEl.removeChild( headEl.firstChild );
}
// Add all MathJax styles
const styles = document.head.getElementsByTagName( 'style' ); // eslint-disable-line
for ( const style of styles ) {
const id = style.getAttribute( 'id' );
if ( id && id.startsWith( 'MJX' ) ) {
headEl.appendChild( style.cloneNode( true ) );
}
}
const links = document.head.getElementsByTagName( 'link' ); // eslint-disable-line
for ( const link of links ) {
headEl.appendChild( link.cloneNode( true ) );
}
const bodyEl = docEl.body;
bodyEl.setAttribute( 'style', 'margin-left: 0; margin-right: 0; user-select: none;' );
renderEquation( this.value, bodyEl, this.engine, this.display );
}, 100 );
}
}
render() {

View File

@ -1,62 +1,9 @@
export const EQUATION_REGEXP = /^(\\\[.*?\\\]|\\\(.*?\\\))$/;
export const defaultConfig = {
engine: 'mathjax',
outputType: 'script',
forceOutputType: false
};
export function renderEquation( equation, element, engine = 'katex', display = false ) {
if ( !element ) {
return;
}
/* eslint-disable */
if ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) {
const version = MathJax.version;
// If major version is 3
if ( isMathJaxVersion3( version ) ) {
const options = MathJax.getMetricsFor( element );
MathJax.texReset();
MathJax.tex2chtmlPromise( equation, options ).then( node => {
if ( element.firstChild ) {
element.firstChild.replaceWith( node );
} else {
element.appendChild( node );
}
MathJax.startup.document.clear();
MathJax.startup.document.updateDocument();
} );
} else {
// Fixme: MathJax typesetting cause occasionally math processing error without timeout
setTimeout( () => {
if ( display ) {
element.innerHTML = '\\[' + equation + '\\]';
} else {
element.innerHTML = '\\(' + equation + '\\)';
}
MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] );
}, 50);
}
} else if ( engine === 'katex' && typeof katex !== 'undefined' ) {
katex.render( equation, element, {
throwOnError: false,
displayMode: display
} );
} else if ( typeof engine === 'function' ) {
engine( equation, element, display );
} else {
element.innerHTML = equation;
console.warn( `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${engine}) for tex.` );
}
/* eslint-enable */
}
// Simple MathJax 3 version check
export function isMathJaxVersion3( version ) {
return version && typeof version === 'string' && version.split( '.' ).length === 3 && version.split( '.' )[ 0 ] === '3';
}
export function getSelectedMathModelWidget( selection ) {
const selectedElement = selection.getSelectedElement();
@ -67,8 +14,66 @@ export function getSelectedMathModelWidget( selection ) {
return null;
}
// Remove delimiters and figure display mode for the model
export function removeDelimiters( equation ) {
export function renderEquation( equation, element, engine = 'katex', display = false ) {
if ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) {
if ( isMathJaxVersion3( MathJax.version ) ) {
const options = MathJax.getMetricsFor( element, display );
let promiseFunction = undefined;
if ( typeof MathJax.tex2chtmlPromise !== 'undefined' ) {
promiseFunction = MathJax.tex2chtmlPromise;
} else if ( typeof MathJax.tex2svgPromise !== 'undefined' ) {
promiseFunction = MathJax.tex2svgPromise;
}
if ( typeof promiseFunction !== 'undefined' ) {
promiseFunction( equation, options ).then( node => {
if ( element.firstChild ) {
element.firstChild.replaceWith( node );
} else {
element.appendChild( node );
}
MathJax.startup.document.clear();
MathJax.startup.document.updateDocument();
} );
}
} else {
// Fixme: MathJax typesetting cause occasionally math processing error without asynchronous call
// eslint-disable-next-line
setTimeout( () => {
if ( display ) {
element.innerHTML = '\\[' + equation + '\\]';
} else {
element.innerHTML = '\\(' + equation + '\\)';
}
MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] ); // eslint-disable-line
} );
}
} else if ( engine === 'katex' && typeof katex !== 'undefined' ) {
katex.render( equation, element, {
throwOnError: false,
displayMode: display
} );
} else if ( typeof engine === 'function' ) {
engine( equation, element, display );
} else {
element.innerHTML = equation;
// eslint-disable-next-line
console.warn( `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${engine}) for tex.` );
}
}
// Simple MathJax 3 version check
export function isMathJaxVersion3( version ) {
return version && typeof version === 'string' && version.split( '.' ).length === 3 && version.split( '.' )[ 0 ] === '3';
}
// Check if equation has delimiters
export function hasDelimiters( text ) {
return text.match( /^(\\\[.*?\\\]|\\\(.*?\\\))$/ );
}
// Extract delimiters and figure display mode for the model
export function extractDelimiters( equation ) {
equation = equation.trim();
// Remove delimiters (e.g. \( \) or \[ \])

View File

@ -7,13 +7,9 @@
flex-wrap: nowrap;
& .ck.ck-math-preview {
user-select: none;
}
/* FIXME: mathjax isn't working with .ck.ck-reset_all * without this fix*/
& .ck.ck-math-preview * {
vertical-align: initial;
text-align: center;
// Todo: calculate content size
width: 234px;
height: 10em;
}
@mixin ck-media-phone {