mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	Remove JavaScript files
This commit is contained in:
		| @@ -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'; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										120
									
								
								src/automath.js
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								src/automath.js
									
									
									
									
									
								
							| @@ -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 ); | ||||
| 	} | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| /** | ||||
|  * @module math | ||||
|  */ | ||||
|  | ||||
| export { default as Math } from './math'; | ||||
| export { default as AutoformatMath } from './autoformatmath'; | ||||
							
								
								
									
										16
									
								
								src/math.js
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/math.js
									
									
									
									
									
								
							| @@ -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'; | ||||
| 	} | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
| } | ||||
| @@ -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. <script type="math/tex">\sqrt{\frac{a}{b}}</script>) | ||||
| 			.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. <script type="math/tex; mode=display">\sqrt{\frac{a}{b}}</script>) | ||||
| 			.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. <span class="math-tex">\( \sqrt{\frac{a}{b}} \)</span>) | ||||
| 			.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; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										246
									
								
								src/mathui.js
									
									
									
									
									
								
							
							
						
						
									
										246
									
								
								src/mathui.js
									
									
									
									
									
								
							| @@ -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 ); | ||||
| 	} | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
| } | ||||
| @@ -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(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										233
									
								
								src/utils.js
									
									
									
									
									
								
							
							
						
						
									
										233
									
								
								src/utils.js
									
									
									
									
									
								
							| @@ -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'; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user