diff --git a/src/autoformatmath.js b/src/autoformatmath.js
deleted file mode 100644
index 18b55015a..000000000
--- a/src/autoformatmath.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { Plugin } from 'ckeditor5/src/core';
-import { global, logWarning } from 'ckeditor5/src/utils';
-import blockAutoformatEditing from '@ckeditor/ckeditor5-autoformat/src/blockautoformatediting';
-import Math from './math';
-
-export default class AutoformatMath extends Plugin {
- static get requires() {
- return [ Math, 'Autoformat' ];
- }
-
- /**
- * @inheritDoc
- */
- init() {
- const editor = this.editor;
-
- if ( !editor.plugins.has( 'Math' ) ) {
- logWarning( 'autoformat-math-feature-missing', editor );
- }
- }
-
- afterInit() {
- const editor = this.editor;
- const command = editor.commands.get( 'math' );
-
- if ( command ) {
- const callback = () => {
- if ( !command.isEnabled ) {
- return false;
- }
-
- command.display = true;
-
- // Wait until selection is removed.
- global.window.setTimeout(
- () => editor.plugins.get( 'MathUI' )._showUI(),
- 50
- );
- };
-
- blockAutoformatEditing( editor, this, /^\$\$$/, callback );
- blockAutoformatEditing( editor, this, /^\\\[$/, callback );
- }
- }
-
- static get pluginName() {
- return 'AutoformatMath';
- }
-}
diff --git a/src/automath.js b/src/automath.js
deleted file mode 100644
index a3b06ddc5..000000000
--- a/src/automath.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import { Clipboard } from 'ckeditor5/src/clipboard';
-import { Plugin } from 'ckeditor5/src/core';
-import { LivePosition, LiveRange } from 'ckeditor5/src/engine';
-import { Undo } from 'ckeditor5/src/undo';
-import { global } from 'ckeditor5/src/utils';
-import { extractDelimiters, hasDelimiters, delimitersCounts } from './utils';
-
-export default class AutoMath extends Plugin {
- static get requires() {
- return [ Clipboard, Undo ];
- }
-
- static get pluginName() {
- return 'AutoMath';
- }
-
- constructor( editor ) {
- super( editor );
-
- this._timeoutId = null;
-
- this._positionToInsert = null;
- }
-
- init() {
- const editor = this.editor;
- const modelDocument = editor.model.document;
-
- this.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => {
- const firstRange = modelDocument.selection.getFirstRange();
-
- const leftLivePosition = LivePosition.fromPosition( firstRange.start );
- leftLivePosition.stickiness = 'toPrevious';
-
- const rightLivePosition = LivePosition.fromPosition( firstRange.end );
- rightLivePosition.stickiness = 'toNext';
-
- modelDocument.once( 'change:data', () => {
- this._mathBetweenPositions( leftLivePosition, rightLivePosition );
-
- leftLivePosition.detach();
- rightLivePosition.detach();
- }, { priority: 'high' } );
- } );
-
- editor.commands.get( 'undo' ).on( 'execute', () => {
- if ( this._timeoutId ) {
- global.window.clearTimeout( this._timeoutId );
- this._positionToInsert.detach();
-
- this._timeoutId = null;
- this._positionToInsert = null;
- }
- }, { priority: 'high' } );
- }
-
- _mathBetweenPositions( leftPosition, rightPosition ) {
- const editor = this.editor;
-
- const mathConfig = this.editor.config.get( 'math' );
-
- const equationRange = new LiveRange( leftPosition, rightPosition );
- const walker = equationRange.getWalker( { ignoreElementEnd: true } );
-
- let text = '';
-
- // Get equation text
- for ( const node of walker ) {
- if ( node.item.is( '$textProxy' ) ) {
- text += node.item.data;
- }
- }
-
- text = text.trim();
-
- // Skip if don't have delimiters
- if ( !hasDelimiters( text ) || delimitersCounts( text ) !== 2 ) {
- return;
- }
-
- const mathCommand = editor.commands.get( 'math' );
-
- // Do not anything if math element cannot be inserted at the current position
- if ( !mathCommand.isEnabled ) {
- return;
- }
-
- this._positionToInsert = LivePosition.fromPosition( leftPosition );
-
- // With timeout user can undo conversation if want use plain text
- this._timeoutId = global.window.setTimeout( () => {
- editor.model.change( writer => {
- this._timeoutId = null;
-
- writer.remove( equationRange );
-
- let insertPosition;
-
- // Check if position where the math element should be inserted is still valid.
- if ( this._positionToInsert.root.rootName !== '$graveyard' ) {
- insertPosition = this._positionToInsert;
- }
-
- editor.model.change( innerWriter => {
- const params = Object.assign( extractDelimiters( text ), {
- type: mathConfig.outputType
- } );
- const mathElement = innerWriter.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params );
-
- editor.model.insertContent( mathElement, insertPosition );
-
- innerWriter.setSelection( mathElement, 'on' );
- } );
-
- this._positionToInsert.detach();
- this._positionToInsert = null;
- } );
- }, 100 );
- }
-}
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index 433ed384f..000000000
--- a/src/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * @module math
- */
-
-export { default as Math } from './math';
-export { default as AutoformatMath } from './autoformatmath';
diff --git a/src/math.js b/src/math.js
deleted file mode 100644
index 3a3b05ee1..000000000
--- a/src/math.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Plugin } from 'ckeditor5/src/core';
-import { Widget } from 'ckeditor5/src/widget';
-
-import MathUI from './mathui';
-import MathEditing from './mathediting';
-import AutoMath from './automath';
-
-export default class Math extends Plugin {
- static get requires() {
- return [ MathEditing, MathUI, AutoMath, Widget ];
- }
-
- static get pluginName() {
- return 'Math';
- }
-}
diff --git a/src/mathcommand.js b/src/mathcommand.js
deleted file mode 100644
index 3d032f671..000000000
--- a/src/mathcommand.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { Command } from 'ckeditor5/src/core';
-import { getSelectedMathModelWidget } from './utils';
-
-export default class MathCommand extends Command {
- execute( equation, display, outputType, forceOutputType ) {
- const model = this.editor.model;
- const selection = model.document.selection;
- const selectedElement = selection.getSelectedElement();
-
- model.change( writer => {
- let mathtex;
- if ( selectedElement && ( selectedElement.is( 'element', 'mathtex-inline' ) ||
- selectedElement.is( 'element', 'mathtex-display' ) ) ) {
- // Update selected element
- const typeAttr = selectedElement.getAttribute( 'type' );
-
- // Use already set type if found and is not forced
- const type = forceOutputType ? outputType : typeAttr || outputType;
-
- mathtex = writer.createElement( display ? 'mathtex-display' : 'mathtex-inline', { equation, type, display } );
- } else {
- // Create new model element
- mathtex = writer.createElement( display ? 'mathtex-display' : 'mathtex-inline', { equation, type: outputType, display } );
- }
- model.insertContent( mathtex );
- } );
- }
-
- refresh() {
- const model = this.editor.model;
- const selection = model.document.selection;
- const selectedElement = selection.getSelectedElement();
-
- this.isEnabled = selectedElement === null || ( selectedElement.is( 'element', 'mathtex-inline' ) ||
- selectedElement.is( 'element', 'mathtex-display' ) );
-
- const selectedEquation = getSelectedMathModelWidget( selection );
- this.value = selectedEquation ? selectedEquation.getAttribute( 'equation' ) : null;
- this.display = selectedEquation ? selectedEquation.getAttribute( 'display' ) : null;
- }
-}
diff --git a/src/mathediting.js b/src/mathediting.js
deleted file mode 100644
index 31d14f49a..000000000
--- a/src/mathediting.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import MathCommand from './mathcommand';
-import { Plugin } from 'ckeditor5/src/core';
-import { toWidget, Widget, viewToModelPositionOutsideModelElement } from 'ckeditor5/src/widget';
-import { renderEquation, extractDelimiters } from './utils';
-
-export default class MathEditing extends Plugin {
- static get requires() {
- return [ Widget ];
- }
-
- static get pluginName() {
- return 'MathEditing';
- }
-
- constructor( editor ) {
- super( editor );
- editor.config.define( 'math', {
- engine: 'mathjax',
- outputType: 'script',
- className: 'math-tex',
- forceOutputType: false,
- enablePreview: true,
- previewClassName: [],
- popupClassName: [],
- katexRenderOptions: {}
- } );
- }
-
- init() {
- const editor = this.editor;
- editor.commands.add( 'math', new MathCommand( editor ) );
-
- this._defineSchema();
- this._defineConverters();
-
- editor.editing.mapper.on(
- 'viewToModelPosition',
- viewToModelPositionOutsideModelElement( editor.model, viewElement => viewElement.hasClass( 'math' ) )
- );
- }
-
- _defineSchema() {
- const schema = this.editor.model.schema;
- schema.register( 'mathtex-inline', {
- allowWhere: '$text',
- isInline: true,
- isObject: true,
- allowAttributes: [ 'equation', 'type', 'display' ]
- } );
-
- schema.register( 'mathtex-display', {
- allowWhere: '$block',
- isInline: false,
- isObject: true,
- allowAttributes: [ 'equation', 'type', 'display' ]
- } );
- }
-
- _defineConverters() {
- const conversion = this.editor.conversion;
- const mathConfig = this.editor.config.get( 'math' );
-
- // View -> Model
- conversion.for( 'upcast' )
- // MathJax inline way (e.g. )
- .elementToElement( {
- view: {
- name: 'script',
- attributes: {
- type: 'math/tex'
- }
- },
- model: ( viewElement, { writer } ) => {
- const equation = viewElement.getChild( 0 ).data.trim();
- return writer.createElement( 'mathtex-inline', {
- equation,
- type: mathConfig.forceOutputType ? mathConfig.outputType : 'script',
- display: false
- } );
- }
- } )
- // MathJax display way (e.g. )
- .elementToElement( {
- view: {
- name: 'script',
- attributes: {
- type: 'math/tex; mode=display'
- }
- },
- model: ( viewElement, { writer } ) => {
- const equation = viewElement.getChild( 0 ).data.trim();
- return writer.createElement( 'mathtex-display', {
- equation,
- type: mathConfig.forceOutputType ? mathConfig.outputType : 'script',
- display: true
- } );
- }
- } )
- // CKEditor 4 way (e.g. \( \sqrt{\frac{a}{b}} \))
- .elementToElement( {
- view: {
- name: 'span',
- classes: [ mathConfig.className ]
- },
- model: ( viewElement, { writer } ) => {
- const equation = viewElement.getChild( 0 ).data.trim();
-
- const params = Object.assign( extractDelimiters( equation ), {
- type: mathConfig.forceOutputType ? mathConfig.outputType : 'span'
- } );
-
- return writer.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params );
- }
- } )
- // KaTeX from Quill: https://github.com/quilljs/quill/blob/develop/formats/formula.js
- .elementToElement( {
- view: {
- name: 'span',
- classes: [ 'ql-formula' ]
- },
- model: ( viewElement, { writer } ) => {
- const equation = viewElement.getAttribute( 'data-value' ).trim();
- return writer.createElement( 'mathtex-inline', {
- equation,
- type: mathConfig.forceOutputType ? mathConfig.outputType : 'script',
- display: false
- } );
- }
- } );
-
- // Model -> View (element)
- 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' );
- }
- } );
-
- // Model -> Data
- conversion.for( 'dataDowncast' )
- .elementToElement( {
- model: 'mathtex-inline',
- view: createMathtexView
- } )
- .elementToElement( {
- model: 'mathtex-display',
- view: createMathtexView
- } );
-
- // Create view for editor
- function createMathtexEditingView( modelItem, writer ) {
- const equation = modelItem.getAttribute( 'equation' );
- const display = modelItem.getAttribute( 'display' );
-
- const styles = 'user-select: none; ' + ( display ? '' : 'display: inline-block;' );
- const classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' );
-
- const mathtexView = writer.createContainerElement( display ? 'div' : 'span', {
- style: styles,
- class: classes
- } );
-
- const uiElement = writer.createUIElement( 'div', null, function( domDocument ) {
- const domElement = this.toDomElement( domDocument );
-
- renderEquation( equation, domElement, mathConfig.engine, mathConfig.lazyLoad, display, false, mathConfig.previewClassName,
- null, mathConfig.katexRenderOptions );
-
- return domElement;
- } );
-
- writer.insert( writer.createPositionAt( mathtexView, 0 ), uiElement );
-
- return mathtexView;
- }
-
- // Create view for data
- function createMathtexView( modelItem, { writer } ) {
- const equation = modelItem.getAttribute( 'equation' );
- const type = modelItem.getAttribute( 'type' );
- const display = modelItem.getAttribute( 'display' );
-
- if ( type === 'span' ) {
- const mathtexView = writer.createContainerElement( 'span', {
- class: mathConfig.className
- } );
-
- if ( display ) {
- writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\[' + equation + '\\]' ) );
- } else {
- writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\(' + equation + '\\)' ) );
- }
-
- return mathtexView;
- } else {
- const mathtexView = writer.createContainerElement( 'script', {
- type: display ? 'math/tex; mode=display' : 'math/tex'
- } );
-
- writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( equation ) );
-
- return mathtexView;
- }
- }
- }
-}
diff --git a/src/mathui.js b/src/mathui.js
deleted file mode 100644
index cba4f5d8e..000000000
--- a/src/mathui.js
+++ /dev/null
@@ -1,246 +0,0 @@
-import MathEditing from './mathediting';
-import MainFormView from './ui/mainformview';
-import mathIcon from '../theme/icons/math.svg';
-import { Plugin } from 'ckeditor5/src/core';
-import { ClickObserver } from 'ckeditor5/src/engine';
-import { ButtonView, ContextualBalloon, clickOutsideHandler } from 'ckeditor5/src/ui';
-import { global, uid } from 'ckeditor5/src/utils';
-import { getBalloonPositionData } from './utils';
-
-const mathKeystroke = 'Ctrl+M';
-
-export default class MathUI extends Plugin {
- static get requires() {
- return [ ContextualBalloon, MathEditing ];
- }
-
- static get pluginName() {
- return 'MathUI';
- }
-
- init() {
- const editor = this.editor;
- editor.editing.view.addObserver( ClickObserver );
-
- this._previewUid = `math-preview-${ uid() }`;
-
- this.formView = this._createFormView();
-
- this._balloon = editor.plugins.get( ContextualBalloon );
-
- this._createToolbarMathButton();
-
- this._enableUserBalloonInteractions();
- }
-
- destroy() {
- super.destroy();
-
- this.formView.destroy();
-
- // Destroy preview element
- const previewEl = global.document.getElementById( this._previewUid );
- if ( previewEl ) {
- previewEl.parentNode.removeChild( previewEl );
- }
- }
-
- _showUI() {
- const editor = this.editor;
- const mathCommand = editor.commands.get( 'math' );
-
- if ( !mathCommand.isEnabled ) {
- return;
- }
-
- this._addFormView();
-
- this._balloon.showStack( 'main' );
- }
-
- _createFormView() {
- const editor = this.editor;
- const mathCommand = editor.commands.get( 'math' );
-
- const mathConfig = editor.config.get( 'math' );
-
- const formView = new MainFormView(
- editor.locale,
- mathConfig.engine,
- mathConfig.lazyLoad,
- mathConfig.enablePreview,
- this._previewUid,
- mathConfig.previewClassName,
- mathConfig.popupClassName,
- mathConfig.katexRenderOptions
- );
-
- formView.mathInputView.bind( 'value' ).to( mathCommand, 'value' );
- formView.displayButtonView.bind( 'isOn' ).to( mathCommand, 'display' );
-
- // Form elements should be read-only when corresponding commands are disabled.
- formView.mathInputView.bind( 'isReadOnly' ).to( mathCommand, 'isEnabled', value => !value );
- formView.saveButtonView.bind( 'isEnabled' ).to( mathCommand );
- formView.displayButtonView.bind( 'isEnabled' ).to( mathCommand );
-
- // Listen to submit button click
- this.listenTo( formView, 'submit', () => {
- editor.execute( 'math', formView.equation, formView.displayButtonView.isOn, mathConfig.outputType, mathConfig.forceOutputType );
- this._closeFormView();
- } );
-
- // Listen to cancel button click
- this.listenTo( formView, 'cancel', () => {
- this._closeFormView();
- } );
-
- // Close plugin ui, if esc is pressed (while ui is focused)
- formView.keystrokes.set( 'esc', ( data, cancel ) => {
- this._closeFormView();
- cancel();
- } );
-
- return formView;
- }
-
- _addFormView() {
- if ( this._isFormInPanel ) {
- return;
- }
-
- const editor = this.editor;
- const mathCommand = editor.commands.get( 'math' );
-
- this._balloon.add( {
- view: this.formView,
- position: getBalloonPositionData( editor )
- } );
-
- if ( this._balloon.visibleView === this.formView ) {
- this.formView.mathInputView.fieldView.element.select();
- }
-
- // Show preview element
- const previewEl = global.document.getElementById( this._previewUid );
- if ( previewEl && this.formView.previewEnabled ) {
- // Force refresh preview
- this.formView.mathView.updateMath();
- }
-
- this.formView.equation = mathCommand.value || '';
- this.formView.displayButtonView.isOn = mathCommand.display || false;
- }
-
- _hideUI() {
- if ( !this._isFormInPanel ) {
- return;
- }
-
- const editor = this.editor;
-
- this.stopListening( editor.ui, 'update' );
- this.stopListening( this._balloon, 'change:visibleView' );
-
- editor.editing.view.focus();
-
- // Remove form first because it's on top of the stack.
- this._removeFormView();
- }
-
- _closeFormView() {
- const mathCommand = this.editor.commands.get( 'math' );
- if ( mathCommand.value !== undefined ) {
- this._removeFormView();
- } else {
- this._hideUI();
- }
- }
-
- _removeFormView() {
- if ( this._isFormInPanel ) {
- this.formView.saveButtonView.focus();
-
- this._balloon.remove( this.formView );
-
- // Hide preview element
- const previewEl = global.document.getElementById( this._previewUid );
- if ( previewEl ) {
- previewEl.style.visibility = 'hidden';
- }
-
- this.editor.editing.view.focus();
- }
- }
-
- _createToolbarMathButton() {
- const editor = this.editor;
- const mathCommand = editor.commands.get( 'math' );
- const t = editor.t;
-
- // Handle the `Ctrl+M` keystroke and show the panel.
- editor.keystrokes.set( mathKeystroke, ( keyEvtData, cancel ) => {
- // Prevent focusing the search bar in FF and opening new tab in Edge. #153, #154.
- cancel();
-
- if ( mathCommand.isEnabled ) {
- this._showUI();
- }
- } );
-
- this.editor.ui.componentFactory.add( 'math', locale => {
- const button = new ButtonView( locale );
-
- button.isEnabled = true;
- button.label = t( 'Insert math' );
- button.icon = mathIcon;
- button.keystroke = mathKeystroke;
- button.tooltip = true;
- button.isToggleable = true;
-
- button.bind( 'isEnabled' ).to( mathCommand, 'isEnabled' );
-
- this.listenTo( button, 'execute', () => this._showUI() );
-
- return button;
- } );
- }
-
- _enableUserBalloonInteractions() {
- const editor = this.editor;
- const viewDocument = this.editor.editing.view.document;
- this.listenTo( viewDocument, 'click', () => {
- const mathCommand = editor.commands.get( 'math' );
- if ( mathCommand.value ) {
- if ( mathCommand.isEnabled ) {
- this._showUI();
- }
- }
- } );
-
- // Close the panel on the Esc key press when the editable has focus and the balloon is visible.
- editor.keystrokes.set( 'Esc', ( data, cancel ) => {
- if ( this._isUIVisible ) {
- this._hideUI();
- cancel();
- }
- } );
-
- // Close on click outside of balloon panel element.
- clickOutsideHandler( {
- emitter: this.formView,
- activator: () => this._isFormInPanel,
- contextElements: [ this._balloon.view.element ],
- callback: () => this._hideUI()
- } );
- }
-
- get _isUIVisible() {
- const visibleView = this._balloon.visibleView;
-
- return visibleView == this.formView;
- }
-
- get _isFormInPanel() {
- return this._balloon.hasView( this.formView );
- }
-}
diff --git a/src/ui/mainformview.js b/src/ui/mainformview.js
deleted file mode 100644
index 8f25efabb..000000000
--- a/src/ui/mainformview.js
+++ /dev/null
@@ -1,234 +0,0 @@
-import { icons } from 'ckeditor5/src/core';
-import {
- ButtonView, createLabeledInputText, FocusCycler, LabelView, LabeledFieldView,
- submitHandler, SwitchButtonView, View, ViewCollection
-} from 'ckeditor5/src/ui';
-import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';
-import { extractDelimiters, hasDelimiters } from '../utils';
-import MathView from './mathview';
-import '../../theme/mathform.css';
-
-const { check: checkIcon, cancel: cancelIcon } = icons;
-
-export default class MainFormView extends View {
- constructor( locale, engine, lazyLoad, previewEnabled, previewUid, previewClassName, popupClassName, katexRenderOptions ) {
- super( locale );
-
- const t = locale.t;
-
- // Create key event & focus trackers
- this._createKeyAndFocusTrackers();
-
- // Submit button
- this.saveButtonView = this._createButton( t( 'Save' ), checkIcon, 'ck-button-save', null );
- this.saveButtonView.type = 'submit';
-
- // Equation input
- this.mathInputView = this._createMathInput();
-
- // Display button
- this.displayButtonView = this._createDisplayButton();
-
- // Cancel button
- this.cancelButtonView = this._createButton( t( 'Cancel' ), cancelIcon, 'ck-button-cancel', 'cancel' );
-
- this.previewEnabled = previewEnabled;
-
- let children = [];
- if ( this.previewEnabled ) {
- // Preview label
- this.previewLabel = new LabelView( locale );
- this.previewLabel.text = t( 'Equation preview' );
-
- // Math element
- this.mathView = new MathView( engine, lazyLoad, locale, previewUid, previewClassName, katexRenderOptions );
- this.mathView.bind( 'display' ).to( this.displayButtonView, 'isOn' );
-
- children = [
- this.mathInputView,
- this.displayButtonView,
- this.previewLabel,
- this.mathView
- ];
- } else {
- children = [
- this.mathInputView,
- this.displayButtonView
- ];
- }
-
- // Add UI elements to template
- this.setTemplate( {
- tag: 'form',
- attributes: {
- class: [
- 'ck',
- 'ck-math-form',
- ...popupClassName
- ],
- tabindex: '-1',
- spellcheck: 'false'
- },
- children: [
- {
- tag: 'div',
- attributes: {
- class: [
- 'ck-math-view'
- ]
- },
- children
- },
- this.saveButtonView,
- this.cancelButtonView
- ]
- } );
- }
-
- render() {
- super.render();
-
- // Prevent default form submit event & trigger custom 'submit'
- submitHandler( {
- view: this
- } );
-
- // Register form elements to focusable elements
- const childViews = [
- this.mathInputView,
- this.displayButtonView,
- this.saveButtonView,
- this.cancelButtonView
- ];
-
- childViews.forEach( v => {
- this._focusables.add( v );
- this.focusTracker.add( v.element );
- } );
-
- // Listen to keypresses inside form element
- this.keystrokes.listenTo( this.element );
- }
-
- focus() {
- this._focusCycler.focusFirst();
- }
-
- get equation() {
- return this.mathInputView.fieldView.element.value;
- }
-
- set equation( equation ) {
- this.mathInputView.fieldView.element.value = equation;
- if ( this.previewEnabled ) {
- this.mathView.value = equation;
- }
- }
-
- _createKeyAndFocusTrackers() {
- this.focusTracker = new FocusTracker();
- this.keystrokes = new KeystrokeHandler();
- this._focusables = new ViewCollection();
-
- this._focusCycler = new FocusCycler( {
- focusables: this._focusables,
- focusTracker: this.focusTracker,
- keystrokeHandler: this.keystrokes,
- actions: {
- focusPrevious: 'shift + tab',
- focusNext: 'tab'
- }
- } );
- }
-
- _createMathInput() {
- const t = this.locale.t;
-
- // Create equation input
- const mathInput = new LabeledFieldView( this.locale, createLabeledInputText );
- const fieldView = mathInput.fieldView;
- mathInput.infoText = t( 'Insert equation in TeX format.' );
-
- const onInput = () => {
- if ( fieldView.element != null ) {
- let equationInput = fieldView.element.value.trim();
-
- // If input has delimiters
- if ( hasDelimiters( equationInput ) ) {
- // Get equation without delimiters
- const params = extractDelimiters( equationInput );
-
- // Remove delimiters from input field
- fieldView.element.value = params.equation;
-
- equationInput = params.equation;
-
- // update display button and preview
- this.displayButtonView.isOn = params.display;
- }
- if ( this.previewEnabled ) {
- // Update preview view
- this.mathView.value = equationInput;
- }
-
- this.saveButtonView.isEnabled = !!equationInput;
- }
- };
-
- fieldView.on( 'render', onInput );
- fieldView.on( 'input', onInput );
-
- return mathInput;
- }
-
- _createButton( label, icon, className, eventName ) {
- const button = new ButtonView( this.locale );
-
- button.set( {
- label,
- icon,
- tooltip: true
- } );
-
- button.extendTemplate( {
- attributes: {
- class: className
- }
- } );
-
- if ( eventName ) {
- button.delegate( 'execute' ).to( this, eventName );
- }
-
- return button;
- }
-
- _createDisplayButton() {
- const t = this.locale.t;
-
- const switchButton = new SwitchButtonView( this.locale );
-
- switchButton.set( {
- label: t( 'Display mode' ),
- withText: true
- } );
-
- switchButton.extendTemplate( {
- attributes: {
- class: 'ck-button-display-toggle'
- }
- } );
-
- switchButton.on( 'execute', () => {
- // Toggle state
- switchButton.isOn = !switchButton.isOn;
-
- if ( this.previewEnabled ) {
- // Update preview view
- this.mathView.display = switchButton.isOn;
- }
- } );
-
- return switchButton;
- }
-}
diff --git a/src/ui/mathview.js b/src/ui/mathview.js
deleted file mode 100644
index 0badcd37b..000000000
--- a/src/ui/mathview.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { View } from 'ckeditor5/src/ui';
-import { renderEquation } from '../utils';
-
-export default class MathView extends View {
- constructor( engine, lazyLoad, locale, previewUid, previewClassName, katexRenderOptions ) {
- super( locale );
-
- this.engine = engine;
- this.lazyLoad = lazyLoad;
- this.previewUid = previewUid;
- this.katexRenderOptions = katexRenderOptions;
- this.previewClassName = previewClassName;
-
- this.set( 'value', '' );
- this.set( 'display', false );
-
- this.on( 'change', () => {
- if ( this.isRendered ) {
- this.updateMath();
- }
- } );
-
- this.setTemplate( {
- tag: 'div',
- attributes: {
- class: [
- 'ck',
- 'ck-math-preview'
- ]
- }
- } );
- }
-
- updateMath() {
- renderEquation( this.value, this.element, this.engine, this.lazyLoad, this.display, true, this.previewUid, this.previewClassName,
- this.katexRenderOptions );
- }
-
- render() {
- super.render();
- this.updateMath();
- }
-}
diff --git a/src/utils.js b/src/utils.js
deleted file mode 100644
index f4aed49a1..000000000
--- a/src/utils.js
+++ /dev/null
@@ -1,233 +0,0 @@
-import { BalloonPanelView } from 'ckeditor5/src/ui';
-import { global } from 'ckeditor5/src/utils';
-
-export function getSelectedMathModelWidget( selection ) {
- const selectedElement = selection.getSelectedElement();
-
- if ( selectedElement && ( selectedElement.is( 'element', 'mathtex-inline' ) || selectedElement.is( 'element', 'mathtex-display' ) ) ) {
- return selectedElement;
- }
-
- return null;
-}
-
-// 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( /^(\\\[.*?\\\]|\\\(.*?\\\))$/ );
-}
-
-// Find delimiters count
-export function delimitersCounts( text ) {
- return text.match( /(\\\[|\\\]|\\\(|\\\))/g ).length;
-}
-
-// 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 = [],
- katexRenderOptions = {}
-) {
- if ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) {
- if ( isMathJaxVersion3( MathJax.version ) ) {
- selectRenderMode( element, preview, previewUid, previewClassName, el => {
- renderMathJax3( equation, el, display, () => {
- if ( preview ) {
- moveAndScaleElement( element, el );
- el.style.visibility = 'visible';
- }
- } );
- } );
- } else {
- selectRenderMode( element, preview, previewUid, previewClassName, el => {
- // Fixme: MathJax typesetting cause occasionally math processing error without asynchronous call
- global.window.setTimeout( () => {
- renderMathJax2( equation, el, display );
-
- // Move and scale after rendering
- if ( preview ) {
- // eslint-disable-next-line
- MathJax.Hub.Queue( () => {
- moveAndScaleElement( element, el );
- el.style.visibility = 'visible';
- } );
- }
- } );
- } );
- }
- } else if ( engine === 'katex' && typeof katex !== 'undefined' ) {
- selectRenderMode( element, preview, previewUid, previewClassName, el => {
- katex.render( equation, el, {
- throwOnError: false,
- displayMode: display,
- ...katexRenderOptions
- } );
- if ( preview ) {
- moveAndScaleElement( element, el );
- el.style.visibility = 'visible';
- }
- } );
- } else if ( typeof engine === 'function' ) {
- engine( equation, element, display );
- } 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, katexRenderOptions );
- }
- 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.` );
- }
- }
-}
-
-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: [
- defaultPositions.southArrowNorth,
- defaultPositions.southArrowNorthWest,
- defaultPositions.southArrowNorthEast
- ]
- };
- }
- else {
- const viewDocument = view.document;
- return {
- target: view.domConverter.viewRangeToDom( viewDocument.selection.getFirstRange() ),
- positions: [
- defaultPositions.southArrowNorth,
- defaultPositions.southArrowNorthWest,
- defaultPositions.southArrowNorthEast
- ]
- };
- }
-}
-
-function selectRenderMode( element, preview, previewUid, previewClassName, cb ) {
- if ( preview ) {
- createPreviewElement( element, previewUid, previewClassName, previewEl => {
- cb( previewEl );
- } );
- } else {
- cb( element );
- }
-}
-
-function renderMathJax3( equation, element, display, cb ) {
- 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, { display } ).then( node => {
- if ( element.firstChild ) {
- element.removeChild( element.firstChild );
- }
- element.appendChild( node );
- cb();
- } );
- }
-}
-
-function renderMathJax2( equation, element, display ) {
- if ( display ) {
- element.innerHTML = '\\[' + equation + '\\]';
- } else {
- element.innerHTML = '\\(' + equation + '\\)';
- }
- // eslint-disable-next-line
- MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] );
-}
-
-function createPreviewElement( element, previewUid, previewClassName, render ) {
- const previewEl = getPreviewElement( element, previewUid, previewClassName );
- render( previewEl );
-}
-
-function getPreviewElement( element, previewUid, previewClassName ) {
- let previewEl = global.document.getElementById( previewUid );
- // Create if not found
- if ( !previewEl ) {
- previewEl = global.document.createElement( 'div' );
- previewEl.setAttribute( 'id', previewUid );
- previewEl.classList.add( ...previewClassName );
- previewEl.style.visibility = 'hidden';
- global.document.body.appendChild( previewEl );
-
- let ticking = false;
-
- const renderTransformation = () => {
- if ( !ticking ) {
- global.window.requestAnimationFrame( () => {
- moveElement( element, previewEl );
- ticking = false;
- } );
-
- ticking = true;
- }
- };
-
- // Create scroll listener for following
- global.window.addEventListener( 'resize', renderTransformation );
- global.window.addEventListener( 'scroll', renderTransformation );
- }
- return previewEl;
-}
-
-function moveAndScaleElement( parent, child ) {
- // Move to right place
- moveElement( parent, child );
-
- // Scale parent element same as preview
- const domRect = child.getBoundingClientRect();
- parent.style.width = domRect.width + 'px';
- parent.style.height = domRect.height + 'px';
-}
-
-function moveElement( parent, child ) {
- const domRect = parent.getBoundingClientRect();
- const left = global.window.scrollX + domRect.left;
- const top = global.window.scrollY + domRect.top;
- child.style.position = 'absolute';
- child.style.left = left + 'px';
- child.style.top = top + 'px';
- child.style.zIndex = 'var(--ck-z-panel)';
- child.style.pointerEvents = 'none';
-}