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'; 'use strict';
module.exports = { 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 ### Available typesetting engines
__MathJax__ __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 - Use __\\( \\)__ delimiters for inline and __\\[ \\]__ delimiters for display
__KaTeX__ __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 LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';
import LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition'; 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 { export default class AutoMath extends Plugin {
static get requires() { static get requires() {
@ -66,19 +66,19 @@ export default class AutoMath extends Plugin {
const equationRange = new LiveRange( leftPosition, rightPosition ); const equationRange = new LiveRange( leftPosition, rightPosition );
const walker = equationRange.getWalker( { ignoreElementEnd: true } ); const walker = equationRange.getWalker( { ignoreElementEnd: true } );
let equation = ''; let text = '';
// Get equation text // Get equation text
for ( const node of walker ) { for ( const node of walker ) {
if ( node.item.is( 'textProxy' ) ) { if ( node.item.is( 'textProxy' ) ) {
equation += node.item.data; text += node.item.data;
} }
} }
equation = equation.trim(); text = text.trim();
// Check if equation // Skip if don't have delimiters
if ( !equation.match( EQUATION_REGEXP ) ) { if ( !hasDelimiters( text ) ) {
return; return;
} }
@ -107,7 +107,7 @@ export default class AutoMath extends Plugin {
editor.model.change( writer => { editor.model.change( writer => {
const params = { const params = {
...removeDelimiters( equation ), ...extractDelimiters( text ),
type: mathConfig.outputType, type: mathConfig.outputType,
}; };
const mathElement = writer.createElement( 'mathtex', params ); const mathElement = writer.createElement( 'mathtex', params );

View File

@ -1,11 +1,10 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
import Widget from '@ckeditor/ckeditor5-widget/src/widget'; import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import MathCommand from './mathcommand'; import MathCommand from './mathcommand';
import { defaultConfig, renderEquation, removeDelimiters } from './utils'; import { defaultConfig, renderEquation, extractDelimiters } from './utils';
export default class MathEditing extends Plugin { export default class MathEditing extends Plugin {
static get requires() { 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>) // CKEditor 4 way (e.g. <span class="math-tex">\( \sqrt{\frac{a}{b}} \)</span>)
.elementToElement( { .elementToElement( {
view: { view: {
@ -108,7 +87,7 @@ export default class MathEditing extends Plugin {
const equation = viewElement.getChild( 0 ).data.trim(); const equation = viewElement.getChild( 0 ).data.trim();
const params = { const params = {
...removeDelimiters( equation ), ...extractDelimiters( equation ),
type: mathConfig.forceOutputType ? mathConfig.outputType : 'span' type: mathConfig.forceOutputType ? mathConfig.outputType : 'span'
}; };
@ -136,7 +115,7 @@ export default class MathEditing extends Plugin {
const equation = modelItem.getAttribute( 'equation' ); const equation = modelItem.getAttribute( 'equation' );
const display = modelItem.getAttribute( 'display' ); 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' ); const classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' );
// CKEngine render multiple times if using span instead of div // CKEngine render multiple times if using span instead of div
@ -177,19 +156,7 @@ export default class MathEditing extends Plugin {
} }
return mathtexView; return mathtexView;
} } else {
/*
else if ( type === 'math' ) {
const mathtexView = viewWriter.createContainerElement( 'math', {
display: display ? 'block' : 'inline',
alttex: equation
} );
// Todo: Implement output conversion
return mathtexView;
}
*/
else {
const mathtexView = viewWriter.createContainerElement( 'script', { const mathtexView = viewWriter.createContainerElement( 'script', {
type: display ? 'math/tex; mode=display' : 'math/tex' 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 submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';
import { removeDelimiters, EQUATION_REGEXP } from '../utils'; import { extractDelimiters, hasDelimiters } from '../utils';
import MathView from './mathview'; import MathView from './mathview';
@ -33,8 +33,9 @@ export default class MainFormView extends View {
// Equation input // Equation input
this.mathInputView = this._createMathInput(); this.mathInputView = this._createMathInput();
// Fixme:
// Preview isn't available in katex, because .ck-reset_all * css rule breaks it // 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 // Display button
this.displayButtonView = this._createDisplayButton(); this.displayButtonView = this._createDisplayButton();
@ -166,9 +167,9 @@ export default class MainFormView extends View {
const equationInput = inputView.element.value.trim(); const equationInput = inputView.element.value.trim();
// If input has delimiters // If input has delimiters
if ( equationInput.match( EQUATION_REGEXP ) ) { if ( hasDelimiters( equationInput ) ) {
// Get equation without delimiters // Get equation without delimiters
const params = removeDelimiters( equationInput ); const params = extractDelimiters( equationInput );
// Remove delimiters from input field // Remove delimiters from input field
inputView.element.value = params.equation; inputView.element.value = params.equation;

View File

@ -1,4 +1,5 @@
import View from '@ckeditor/ckeditor5-ui/src/view'; import View from '@ckeditor/ckeditor5-ui/src/view';
import { renderEquation } from '../utils'; import { renderEquation } from '../utils';
export default class MathView extends View { export default class MathView extends View {
@ -15,7 +16,7 @@ export default class MathView extends View {
} ); } );
this.setTemplate( { this.setTemplate( {
tag: 'div', tag: 'iframe',
attributes: { attributes: {
class: [ class: [
'ck', 'ck',
@ -26,7 +27,43 @@ export default class MathView extends View {
} }
updateMath() { 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() { render() {

View File

@ -1,62 +1,9 @@
export const EQUATION_REGEXP = /^(\\\[.*?\\\]|\\\(.*?\\\))$/;
export const defaultConfig = { export const defaultConfig = {
engine: 'mathjax', engine: 'mathjax',
outputType: 'script', outputType: 'script',
forceOutputType: false 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 ) { export function getSelectedMathModelWidget( selection ) {
const selectedElement = selection.getSelectedElement(); const selectedElement = selection.getSelectedElement();
@ -67,8 +14,66 @@ export function getSelectedMathModelWidget( selection ) {
return null; return null;
} }
// Remove delimiters and figure display mode for the model export function renderEquation( equation, element, engine = 'katex', display = false ) {
export function removeDelimiters( equation ) { 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(); equation = equation.trim();
// Remove delimiters (e.g. \( \) or \[ \]) // Remove delimiters (e.g. \( \) or \[ \])

View File

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