From f89affbc3f129a9d33a29bc17e5f32dac322dc4d Mon Sep 17 00:00:00 2001 From: Sauli Anto Date: Tue, 1 Oct 2019 23:11:51 +0300 Subject: [PATCH] Refactor code --- .eslintrc.js | 8 ++- README.md | 2 +- src/automath.js | 14 ++--- src/mathediting.js | 41 ++------------- src/ui/mainformview.js | 9 ++-- src/ui/mathview.js | 41 ++++++++++++++- src/utils.js | 115 +++++++++++++++++++++-------------------- theme/mathform.css | 12 ++--- 8 files changed, 126 insertions(+), 116 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 874c53968..56069ab43 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,5 +3,9 @@ 'use strict'; module.exports = { - extends: 'ckeditor5' -}; \ No newline at end of file + extends: 'ckeditor5', + globals: { + 'MathJax': true, + 'katex': true + } +}; diff --git a/README.md b/README.md index 5aaa1bf92..b1a824f10 100644 --- a/README.md +++ b/README.md @@ -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__ diff --git a/src/automath.js b/src/automath.js index 5f8a7eeb7..30340374c 100644 --- a/src/automath.js +++ b/src/automath.js @@ -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 ); diff --git a/src/mathediting.js b/src/mathediting.js index 480e76717..e7c1422cd 100644 --- a/src/mathediting.js +++ b/src/mathediting.js @@ -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. ...) - .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. \( \sqrt{\frac{a}{b}} \)) .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' } ); diff --git a/src/ui/mainformview.js b/src/ui/mainformview.js index ac7f92322..f433fcf5f 100644 --- a/src/ui/mainformview.js +++ b/src/ui/mainformview.js @@ -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; diff --git a/src/ui/mathview.js b/src/ui/mathview.js index 1ce3fe666..afc75c122 100644 --- a/src/ui/mathview.js +++ b/src/ui/mathview.js @@ -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() { diff --git a/src/utils.js b/src/utils.js index d7240301f..865671c87 100644 --- a/src/utils.js +++ b/src/utils.js @@ -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 \[ \]) diff --git a/theme/mathform.css b/theme/mathform.css index 66268773f..0cb137661 100644 --- a/theme/mathform.css +++ b/theme/mathform.css @@ -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 { @@ -35,4 +31,4 @@ flex-basis: 50%; } } -} \ No newline at end of file +}