| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; | 
					
						
							|  |  |  | import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard'; | 
					
						
							|  |  |  | 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'; | 
					
						
							| 
									
										
										
										
											2019-10-09 12:21:55 +03:00
										 |  |  | import global from '@ckeditor/ckeditor5-utils/src/dom/global'; | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-11 18:10:41 +03:00
										 |  |  | import { defaultConfig, extractDelimiters, hasDelimiters, delimitersCounts } from './utils'; | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 ) { | 
					
						
							| 
									
										
										
										
											2019-10-09 12:21:55 +03:00
										 |  |  | 				global.window.clearTimeout( this._timeoutId ); | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 				this._positionToInsert.detach(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				this._timeoutId = null; | 
					
						
							|  |  |  | 				this._positionToInsert = null; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, { priority: 'high' } ); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_mathBetweenPositions( leftPosition, rightPosition ) { | 
					
						
							|  |  |  | 		const editor = this.editor; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-03 12:43:46 +03:00
										 |  |  | 		const mathConfig = Object.assign( defaultConfig, this.editor.config.get( 'math' ) ); | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		const equationRange = new LiveRange( leftPosition, rightPosition ); | 
					
						
							|  |  |  | 		const walker = equationRange.getWalker( { ignoreElementEnd: true } ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-01 23:11:51 +03:00
										 |  |  | 		let text = ''; | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Get equation text
 | 
					
						
							|  |  |  | 		for ( const node of walker ) { | 
					
						
							|  |  |  | 			if ( node.item.is( 'textProxy' ) ) { | 
					
						
							| 
									
										
										
										
											2019-10-01 23:11:51 +03:00
										 |  |  | 				text += node.item.data; | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-01 23:11:51 +03:00
										 |  |  | 		text = text.trim(); | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-01 23:11:51 +03:00
										 |  |  | 		// Skip if don't have delimiters
 | 
					
						
							| 
									
										
										
										
											2019-10-11 18:10:41 +03:00
										 |  |  | 		if ( !hasDelimiters( text ) || delimitersCounts( text ) !== 2 ) { | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 			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
 | 
					
						
							| 
									
										
										
										
											2019-10-09 12:21:55 +03:00
										 |  |  | 		this._timeoutId = global.window.setTimeout( () => { | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 			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( writer => { | 
					
						
							| 
									
										
										
										
											2019-10-03 12:43:46 +03:00
										 |  |  | 					const params = Object.assign( extractDelimiters( text ), { | 
					
						
							|  |  |  | 						type: mathConfig.outputType | 
					
						
							|  |  |  | 					} ); | 
					
						
							| 
									
										
										
										
											2019-09-28 18:03:05 +03:00
										 |  |  | 					const mathElement = writer.createElement( 'mathtex', params ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					editor.model.insertContent( mathElement, insertPosition ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					writer.setSelection( mathElement, 'on' ); | 
					
						
							|  |  |  | 				} ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				this._positionToInsert.detach(); | 
					
						
							|  |  |  | 				this._positionToInsert = null; | 
					
						
							|  |  |  | 			} ); | 
					
						
							|  |  |  | 		}, 100 ); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |