Notes/src/mathediting.js

194 lines
5.5 KiB
JavaScript
Raw Normal View History

2019-08-31 20:48:37 +03:00
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
2020-04-05 17:24:46 +03:00
import { toWidget, viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget/src/utils';
2019-08-31 20:48:37 +03:00
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import MathCommand from './mathcommand';
2020-04-05 17:24:46 +03:00
import { renderEquation, extractDelimiters } from './utils';
2019-08-31 20:48:37 +03:00
export default class MathEditing extends Plugin {
static get requires() {
return [ Widget ];
}
static get pluginName() {
return 'MathEditing';
}
init() {
const editor = this.editor;
editor.commands.add( 'math', new MathCommand( editor ) );
this._defineSchema();
this._defineConverters();
2020-04-05 17:24:46 +03:00
editor.editing.mapper.on(
'viewToModelPosition',
viewToModelPositionOutsideModelElement( editor.model, viewElement => viewElement.hasClass( 'math' ) )
);
editor.config.define( 'math', {
engine: 'mathjax',
outputType: 'script',
forceOutputType: false,
enablePreview: true
} );
2019-08-31 20:48:37 +03:00
}
_defineSchema() {
const schema = this.editor.model.schema;
2020-08-29 17:33:41 +03:00
schema.register( 'mathtex-inline', {
2019-08-31 20:48:37 +03:00
allowWhere: '$text',
isInline: true,
isObject: true,
allowAttributes: [ 'equation', 'type', 'display' ]
} );
2020-08-29 17:33:41 +03:00
schema.register( 'mathtex-display', {
allowWhere: '$block',
isInline: false,
isObject: true,
allowAttributes: [ 'equation', 'type', 'display' ]
} );
2019-08-31 20:48:37 +03:00
}
_defineConverters() {
const conversion = this.editor.conversion;
2020-04-05 17:24:46 +03:00
const mathConfig = this.editor.config.get( 'math' );
2019-09-28 13:02:32 +03:00
2019-08-31 20:48:37 +03:00
// View -> Model
conversion.for( 'upcast' )
// MathJax inline way (e.g. <script type="math/tex">\sqrt{\frac{a}{b}}</script>)
.elementToElement( {
view: {
name: 'script',
attributes: {
type: 'math/tex'
}
},
2020-08-29 17:33:41 +03:00
model: ( viewElement, { writer } ) => {
2019-08-31 20:48:37 +03:00
const equation = viewElement.getChild( 0 ).data.trim();
2020-08-29 17:33:41 +03:00
return writer.createElement( 'mathtex-inline', {
2019-09-28 13:02:32 +03:00
equation,
type: mathConfig.forceOutputType ? mathConfig.outputType : 'script',
display: false
} );
2019-08-31 20:48:37 +03:00
}
} )
// MathJax display way (e.g. <script type="math/tex; mode=display">\sqrt{\frac{a}{b}}</script>)
.elementToElement( {
view: {
name: 'script',
attributes: {
type: 'math/tex; mode=display'
}
},
2020-08-29 17:33:41 +03:00
model: ( viewElement, { writer } ) => {
2019-08-31 20:48:37 +03:00
const equation = viewElement.getChild( 0 ).data.trim();
2020-08-29 17:33:41 +03:00
return writer.createElement( 'mathtex-display', {
2019-09-28 13:02:32 +03:00
equation,
type: mathConfig.forceOutputType ? mathConfig.outputType : 'script',
display: true
} );
}
} )
2019-08-31 20:48:37 +03:00
// CKEditor 4 way (e.g. <span class="math-tex">\( \sqrt{\frac{a}{b}} \)</span>)
.elementToElement( {
view: {
name: 'span',
classes: [ 'math-tex' ]
},
2020-08-29 17:33:41 +03:00
model: ( viewElement, { writer } ) => {
const equation = viewElement.getChild( 0 ).data.trim();
2019-08-31 20:48:37 +03:00
2019-10-03 12:43:46 +03:00
const params = Object.assign( extractDelimiters( equation ), {
type: mathConfig.forceOutputType ? mathConfig.outputType : 'span'
2019-10-03 12:43:46 +03:00
} );
2019-08-31 20:48:37 +03:00
2020-08-29 17:33:41 +03:00
return writer.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params );
2019-08-31 20:48:37 +03:00
}
} );
// Model -> View (element)
2020-08-29 17:33:41 +03:00
conversion.for( 'editingDowncast' )
.elementToElement( {
model: 'mathtex-inline',
view: ( modelItem, { writer } ) => {
const widgetElement = createMathtexEditingView( modelItem, writer );
return toWidget( widgetElement, writer, 'span' );
}
} ).elementToElement( {
model: 'mathtex-display',
view: ( modelItem, { writer } ) => {
const widgetElement = createMathtexEditingView( modelItem, writer );
return toWidget( widgetElement, writer, 'div' );
}
} );
2019-08-31 20:48:37 +03:00
// Model -> Data
2020-08-29 17:33:41 +03:00
conversion.for( 'dataDowncast' )
.elementToElement( {
model: 'mathtex-inline',
view: createMathtexView
} )
.elementToElement( {
model: 'mathtex-display',
view: createMathtexView
} );
2019-08-31 20:48:37 +03:00
// Create view for editor
2020-08-29 17:33:41 +03:00
function createMathtexEditingView( modelItem, writer ) {
2019-08-31 20:48:37 +03:00
const equation = modelItem.getAttribute( 'equation' );
const display = modelItem.getAttribute( 'display' );
2019-10-01 23:11:51 +03:00
const styles = 'user-select: none; ' + ( display ? '' : 'display: inline-block;' );
2019-09-28 13:02:32 +03:00
const classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' );
2019-08-31 20:48:37 +03:00
2020-08-29 17:33:41 +03:00
const mathtexView = writer.createContainerElement( display ? 'div' : 'span', {
2019-09-17 15:47:58 +03:00
style: styles,
class: classes
2019-08-31 20:48:37 +03:00
} );
2020-08-29 17:33:41 +03:00
const uiElement = writer.createUIElement( 'div', null, function( domDocument ) {
2019-08-31 20:48:37 +03:00
const domElement = this.toDomElement( domDocument );
renderEquation( equation, domElement, mathConfig.engine, mathConfig.lazyLoad, display, false );
2019-08-31 20:48:37 +03:00
return domElement;
} );
2020-08-29 17:33:41 +03:00
writer.insert( writer.createPositionAt( mathtexView, 0 ), uiElement );
2019-08-31 20:48:37 +03:00
return mathtexView;
}
// Create view for data
2020-08-29 17:33:41 +03:00
function createMathtexView( modelItem, { writer } ) {
2019-08-31 20:48:37 +03:00
const equation = modelItem.getAttribute( 'equation' );
const type = modelItem.getAttribute( 'type' );
const display = modelItem.getAttribute( 'display' );
if ( type === 'span' ) {
2020-08-29 17:33:41 +03:00
const mathtexView = writer.createContainerElement( 'span', {
2019-08-31 20:48:37 +03:00
class: 'math-tex'
} );
2019-09-28 13:02:32 +03:00
2019-08-31 20:48:37 +03:00
if ( display ) {
2020-08-29 17:33:41 +03:00
writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\[' + equation + '\\]' ) );
2019-08-31 20:48:37 +03:00
} else {
2020-08-29 17:33:41 +03:00
writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\(' + equation + '\\)' ) );
2019-08-31 20:48:37 +03:00
}
return mathtexView;
2019-10-01 23:11:51 +03:00
} else {
2020-08-29 17:33:41 +03:00
const mathtexView = writer.createContainerElement( 'script', {
2019-09-28 13:02:32 +03:00
type: display ? 'math/tex; mode=display' : 'math/tex'
2019-08-31 20:48:37 +03:00
} );
2019-09-28 13:02:32 +03:00
2020-08-29 17:33:41 +03:00
writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( equation ) );
2019-08-31 20:48:37 +03:00
return mathtexView;
}
}
}
}