mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-30 12:13:52 +08:00 
			
		
		
		
	Refactor code
This commit is contained in:
		
							parent
							
								
									5011fe40b0
								
							
						
					
					
						commit
						f89affbc3f
					
				| @ -3,5 +3,9 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
| 	extends: 'ckeditor5' | 	extends: 'ckeditor5', | ||||||
|  | 	globals: { | ||||||
|  | 		'MathJax': true, | ||||||
|  | 		'katex': true | ||||||
|  | 	} | ||||||
| }; | }; | ||||||
| @ -54,7 +54,7 @@ Styles requires PostCSS like offical CKEditor plugins. | |||||||
| 
 | 
 | ||||||
| ### Available typesetting engines | ### Available typesetting engines | ||||||
| __MathJax__ | __MathJax__ | ||||||
| - Tested by using version __2.7.5__ and __TeX-MML-AM_HTMLorMML__ configuration. It works also with version __3.0.0__ or newer! | - Tested by using version __2.7.5__ and __TeX-MML-AM_HTMLorMML__ configuration. It has also experimental (__CHTML__, __SVG__) support for __3.0.0__ or newer version. | ||||||
| - Use __\\( \\)__ delimiters for inline and __\\[ \\]__ delimiters for display | - Use __\\( \\)__ delimiters for inline and __\\[ \\]__ delimiters for display | ||||||
| 
 | 
 | ||||||
| __KaTeX__ | __KaTeX__ | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import Undo from '@ckeditor/ckeditor5-undo/src/undo'; | |||||||
| import LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange'; | import LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange'; | ||||||
| import LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition'; | import LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition'; | ||||||
| 
 | 
 | ||||||
| import { defaultConfig, removeDelimiters, EQUATION_REGEXP } from './utils'; | import { defaultConfig, extractDelimiters, hasDelimiters } from './utils'; | ||||||
| 
 | 
 | ||||||
| export default class AutoMath extends Plugin { | export default class AutoMath extends Plugin { | ||||||
| 	static get requires() { | 	static get requires() { | ||||||
| @ -66,19 +66,19 @@ export default class AutoMath extends Plugin { | |||||||
| 		const equationRange = new LiveRange( leftPosition, rightPosition ); | 		const equationRange = new LiveRange( leftPosition, rightPosition ); | ||||||
| 		const walker = equationRange.getWalker( { ignoreElementEnd: true } ); | 		const walker = equationRange.getWalker( { ignoreElementEnd: true } ); | ||||||
| 
 | 
 | ||||||
| 		let equation = ''; | 		let text = ''; | ||||||
| 
 | 
 | ||||||
| 		// Get equation text
 | 		// Get equation text
 | ||||||
| 		for ( const node of walker ) { | 		for ( const node of walker ) { | ||||||
| 			if ( node.item.is( 'textProxy' ) ) { | 			if ( node.item.is( 'textProxy' ) ) { | ||||||
| 				equation += node.item.data; | 				text += node.item.data; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		equation = equation.trim(); | 		text = text.trim(); | ||||||
| 
 | 
 | ||||||
| 		// Check if equation
 | 		// Skip if don't have delimiters
 | ||||||
| 		if ( !equation.match( EQUATION_REGEXP ) ) { | 		if ( !hasDelimiters( text ) ) { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| @ -107,7 +107,7 @@ export default class AutoMath extends Plugin { | |||||||
| 
 | 
 | ||||||
| 				editor.model.change( writer => { | 				editor.model.change( writer => { | ||||||
| 					const params = { | 					const params = { | ||||||
| 						...removeDelimiters( equation ), | 						...extractDelimiters( text ), | ||||||
| 						type: mathConfig.outputType, | 						type: mathConfig.outputType, | ||||||
| 					}; | 					}; | ||||||
| 					const mathElement = writer.createElement( 'mathtex', params ); | 					const mathElement = writer.createElement( 'mathtex', params ); | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; | import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; | ||||||
| 
 |  | ||||||
| import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; | import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; | ||||||
| import Widget from '@ckeditor/ckeditor5-widget/src/widget'; | import Widget from '@ckeditor/ckeditor5-widget/src/widget'; | ||||||
| 
 | 
 | ||||||
| import MathCommand from './mathcommand'; | import MathCommand from './mathcommand'; | ||||||
| 
 | 
 | ||||||
| import { defaultConfig, renderEquation, removeDelimiters } from './utils'; | import { defaultConfig, renderEquation, extractDelimiters } from './utils'; | ||||||
| 
 | 
 | ||||||
| export default class MathEditing extends Plugin { | export default class MathEditing extends Plugin { | ||||||
| 	static get requires() { | 	static get requires() { | ||||||
| @ -78,26 +77,6 @@ export default class MathEditing extends Plugin { | |||||||
| 					} ); | 					} ); | ||||||
| 				} | 				} | ||||||
| 			} ) | 			} ) | ||||||
| 			// Todo: Implement input conversion
 |  | ||||||
| 			/* |  | ||||||
| 			// MathML (e.g. <math type="math/tex; mode=display" alttext="\sqrt{\frac{a}{b}}">...</script>)
 |  | ||||||
| 			.elementToElement( { |  | ||||||
| 				view: { |  | ||||||
| 					name: 'math', |  | ||||||
| 				}, |  | ||||||
| 				model: ( viewElement, modelWriter ) => { |  | ||||||
| 					const equation = viewElement.getAttribute( 'alttext' ); |  | ||||||
| 					const display = viewElement.getAttribute( 'display' ); |  | ||||||
| 					if ( equation ) { |  | ||||||
| 						return modelWriter.createElement( 'mathtex', { |  | ||||||
| 							equation, |  | ||||||
| 							type: mathConfig.forceOutputType ? mathConfig.outputType : 'math', |  | ||||||
| 							display: display === 'block' ? true : false |  | ||||||
| 						} ); |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} ) |  | ||||||
| 			*/ |  | ||||||
| 			// CKEditor 4 way (e.g. <span class="math-tex">\( \sqrt{\frac{a}{b}} \)</span>)
 | 			// CKEditor 4 way (e.g. <span class="math-tex">\( \sqrt{\frac{a}{b}} \)</span>)
 | ||||||
| 			.elementToElement( { | 			.elementToElement( { | ||||||
| 				view: { | 				view: { | ||||||
| @ -108,7 +87,7 @@ export default class MathEditing extends Plugin { | |||||||
| 					const equation = viewElement.getChild( 0 ).data.trim(); | 					const equation = viewElement.getChild( 0 ).data.trim(); | ||||||
| 
 | 
 | ||||||
| 					const params = { | 					const params = { | ||||||
| 						...removeDelimiters( equation ), | 						...extractDelimiters( equation ), | ||||||
| 						type: mathConfig.forceOutputType ? mathConfig.outputType : 'span' | 						type: mathConfig.forceOutputType ? mathConfig.outputType : 'span' | ||||||
| 					}; | 					}; | ||||||
| 
 | 
 | ||||||
| @ -136,7 +115,7 @@ export default class MathEditing extends Plugin { | |||||||
| 			const equation = modelItem.getAttribute( 'equation' ); | 			const equation = modelItem.getAttribute( 'equation' ); | ||||||
| 			const display = modelItem.getAttribute( 'display' ); | 			const display = modelItem.getAttribute( 'display' ); | ||||||
| 
 | 
 | ||||||
| 			const styles = 'user-select: none; ' + ( display ? 'display: block;' : 'display: inline-block;' ); | 			const styles = 'user-select: none; ' + ( display ? '' : 'display: inline-block;' ); | ||||||
| 			const classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' ); | 			const classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' ); | ||||||
| 
 | 
 | ||||||
| 			// CKEngine render multiple times if using span instead of div
 | 			// CKEngine render multiple times if using span instead of div
 | ||||||
| @ -177,19 +156,7 @@ export default class MathEditing extends Plugin { | |||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				return mathtexView; | 				return mathtexView; | ||||||
| 			} | 			} else { | ||||||
| 
 |  | ||||||
| 			/* |  | ||||||
| 			else if ( type === 'math' ) { |  | ||||||
| 				const mathtexView = viewWriter.createContainerElement( 'math', { |  | ||||||
| 					display: display ? 'block' : 'inline', |  | ||||||
| 					alttex: equation |  | ||||||
| 				} ); |  | ||||||
| 				// Todo: Implement output conversion
 |  | ||||||
| 				return mathtexView; |  | ||||||
| 			} |  | ||||||
| 			*/ |  | ||||||
| 			else { |  | ||||||
| 				const mathtexView = viewWriter.createContainerElement( 'script', { | 				const mathtexView = viewWriter.createContainerElement( 'script', { | ||||||
| 					type: display ? 'math/tex; mode=display' : 'math/tex' | 					type: display ? 'math/tex; mode=display' : 'math/tex' | ||||||
| 				} ); | 				} ); | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ import cancelIcon from '@ckeditor/ckeditor5-core/theme/icons/cancel.svg'; | |||||||
| 
 | 
 | ||||||
| import submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler'; | import submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler'; | ||||||
| 
 | 
 | ||||||
| import { removeDelimiters, EQUATION_REGEXP } from '../utils'; | import { extractDelimiters, hasDelimiters } from '../utils'; | ||||||
| 
 | 
 | ||||||
| import MathView from './mathview'; | import MathView from './mathview'; | ||||||
| 
 | 
 | ||||||
| @ -33,8 +33,9 @@ export default class MainFormView extends View { | |||||||
| 		// Equation input
 | 		// Equation input
 | ||||||
| 		this.mathInputView = this._createMathInput(); | 		this.mathInputView = this._createMathInput(); | ||||||
| 
 | 
 | ||||||
|  | 		// Fixme:
 | ||||||
| 		// Preview isn't available in katex, because .ck-reset_all * css rule breaks it
 | 		// Preview isn't available in katex, because .ck-reset_all * css rule breaks it
 | ||||||
| 		this.previewEnabled = engine !== 'katex'; | 		this.previewEnabled = engine !== 'katex' || true; | ||||||
| 
 | 
 | ||||||
| 		// Display button
 | 		// Display button
 | ||||||
| 		this.displayButtonView = this._createDisplayButton(); | 		this.displayButtonView = this._createDisplayButton(); | ||||||
| @ -166,9 +167,9 @@ export default class MainFormView extends View { | |||||||
| 				const equationInput = inputView.element.value.trim(); | 				const equationInput = inputView.element.value.trim(); | ||||||
| 
 | 
 | ||||||
| 				// If input has delimiters
 | 				// If input has delimiters
 | ||||||
| 				if ( equationInput.match( EQUATION_REGEXP ) ) { | 				if ( hasDelimiters( equationInput ) ) { | ||||||
| 					// Get equation without delimiters
 | 					// Get equation without delimiters
 | ||||||
| 					const params = removeDelimiters( equationInput ); | 					const params = extractDelimiters( equationInput ); | ||||||
| 
 | 
 | ||||||
| 					// Remove delimiters from input field
 | 					// Remove delimiters from input field
 | ||||||
| 					inputView.element.value = params.equation; | 					inputView.element.value = params.equation; | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import View from '@ckeditor/ckeditor5-ui/src/view'; | import View from '@ckeditor/ckeditor5-ui/src/view'; | ||||||
|  | 
 | ||||||
| import { renderEquation } from '../utils'; | import { renderEquation } from '../utils'; | ||||||
| 
 | 
 | ||||||
| export default class MathView extends View { | export default class MathView extends View { | ||||||
| @ -15,7 +16,7 @@ export default class MathView extends View { | |||||||
| 		} ); | 		} ); | ||||||
| 
 | 
 | ||||||
| 		this.setTemplate( { | 		this.setTemplate( { | ||||||
| 			tag: 'div', | 			tag: 'iframe', | ||||||
| 			attributes: { | 			attributes: { | ||||||
| 				class: [ | 				class: [ | ||||||
| 					'ck', | 					'ck', | ||||||
| @ -26,7 +27,43 @@ export default class MathView extends View { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	updateMath() { | 	updateMath() { | ||||||
| 		renderEquation( this.value, this.element, this.engine, this.display ); | 		const el = this.element; | ||||||
|  | 		if ( el ) { | ||||||
|  | 			// Fixme
 | ||||||
|  | 			// eslint-disable-next-line
 | ||||||
|  | 			setTimeout( () => { | ||||||
|  | 				let docEl = ( el.contentWindow || el.contentDocument ); | ||||||
|  | 				if ( docEl.document ) { | ||||||
|  | 					docEl = docEl.document; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				const headEl = docEl.head; | ||||||
|  | 
 | ||||||
|  | 				// Remove old styles
 | ||||||
|  | 				while ( headEl.hasChildNodes() ) { | ||||||
|  | 					headEl.removeChild( headEl.firstChild ); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				// Add all MathJax styles
 | ||||||
|  | 				const styles = document.head.getElementsByTagName( 'style' ); // eslint-disable-line
 | ||||||
|  | 				for ( const style of styles ) { | ||||||
|  | 					const id = style.getAttribute( 'id' ); | ||||||
|  | 					if ( id && id.startsWith( 'MJX' ) ) { | ||||||
|  | 						headEl.appendChild( style.cloneNode( true ) ); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				const links = document.head.getElementsByTagName( 'link' ); // eslint-disable-line
 | ||||||
|  | 				for ( const link of links ) { | ||||||
|  | 					headEl.appendChild( link.cloneNode( true ) ); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				const bodyEl = docEl.body; | ||||||
|  | 				bodyEl.setAttribute( 'style', 'margin-left: 0; margin-right: 0; user-select: none;' ); | ||||||
|  | 
 | ||||||
|  | 				renderEquation( this.value, bodyEl, this.engine, this.display ); | ||||||
|  | 			}, 100 ); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	render() { | 	render() { | ||||||
|  | |||||||
							
								
								
									
										115
									
								
								src/utils.js
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								src/utils.js
									
									
									
									
									
								
							| @ -1,62 +1,9 @@ | |||||||
| export const EQUATION_REGEXP = /^(\\\[.*?\\\]|\\\(.*?\\\))$/; |  | ||||||
| 
 |  | ||||||
| export const defaultConfig = { | export const defaultConfig = { | ||||||
| 	engine: 'mathjax', | 	engine: 'mathjax', | ||||||
| 	outputType: 'script', | 	outputType: 'script', | ||||||
| 	forceOutputType: false | 	forceOutputType: false | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export function renderEquation( equation, element, engine = 'katex', display = false ) { |  | ||||||
| 	if ( !element ) { |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	/* eslint-disable */ |  | ||||||
| 	if ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) { |  | ||||||
| 		const version = MathJax.version; |  | ||||||
| 		// If major version is 3
 |  | ||||||
| 		if ( isMathJaxVersion3( version ) ) { |  | ||||||
| 			const options = MathJax.getMetricsFor( element ); |  | ||||||
| 
 |  | ||||||
| 			MathJax.texReset(); |  | ||||||
| 			MathJax.tex2chtmlPromise( equation, options ).then( node => { |  | ||||||
| 				if ( element.firstChild ) { |  | ||||||
| 					element.firstChild.replaceWith( node ); |  | ||||||
| 				} else { |  | ||||||
| 					element.appendChild( node ); |  | ||||||
| 				} |  | ||||||
| 				MathJax.startup.document.clear(); |  | ||||||
| 				MathJax.startup.document.updateDocument(); |  | ||||||
| 			  } ); |  | ||||||
| 		} else { |  | ||||||
| 			// Fixme: MathJax typesetting cause occasionally math processing error without timeout
 |  | ||||||
| 			setTimeout( () => { |  | ||||||
| 				if ( display ) { |  | ||||||
| 					element.innerHTML = '\\[' + equation + '\\]'; |  | ||||||
| 				} else { |  | ||||||
| 					element.innerHTML = '\\(' + equation + '\\)'; |  | ||||||
| 				} |  | ||||||
| 				MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] ); |  | ||||||
| 			}, 50); |  | ||||||
| 		} |  | ||||||
| 	} else if ( engine === 'katex' && typeof katex !== 'undefined' ) { |  | ||||||
|         katex.render( equation, element, { |  | ||||||
| 			throwOnError: false, |  | ||||||
| 			displayMode: display |  | ||||||
|         } ); |  | ||||||
| 	} else if ( typeof engine === 'function' ) { |  | ||||||
| 		engine( equation, element, display ); |  | ||||||
| 	} else { |  | ||||||
| 		element.innerHTML = equation; |  | ||||||
| 		console.warn( `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${engine}) for tex.` ); |  | ||||||
| 	} |  | ||||||
| 	/* eslint-enable */ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Simple MathJax 3 version check
 |  | ||||||
| export function isMathJaxVersion3( version ) { |  | ||||||
| 	return version && typeof version === 'string' && version.split( '.' ).length === 3 && version.split( '.' )[ 0 ] === '3'; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export function getSelectedMathModelWidget( selection ) { | export function getSelectedMathModelWidget( selection ) { | ||||||
| 	const selectedElement = selection.getSelectedElement(); | 	const selectedElement = selection.getSelectedElement(); | ||||||
| 
 | 
 | ||||||
| @ -67,8 +14,66 @@ export function getSelectedMathModelWidget( selection ) { | |||||||
| 	return null; | 	return null; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Remove delimiters and figure display mode for the model
 | export function renderEquation( equation, element, engine = 'katex', display = false ) { | ||||||
| export function removeDelimiters( equation ) { | 	if ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) { | ||||||
|  | 		if ( isMathJaxVersion3( MathJax.version ) ) { | ||||||
|  | 			const options = MathJax.getMetricsFor( element, display ); | ||||||
|  | 			let promiseFunction = undefined; | ||||||
|  | 			if ( typeof MathJax.tex2chtmlPromise !== 'undefined' ) { | ||||||
|  | 				promiseFunction = MathJax.tex2chtmlPromise; | ||||||
|  | 			} else if ( typeof MathJax.tex2svgPromise !== 'undefined' ) { | ||||||
|  | 				promiseFunction = MathJax.tex2svgPromise; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if ( typeof promiseFunction !== 'undefined' ) { | ||||||
|  | 				promiseFunction( equation, options ).then( node => { | ||||||
|  | 					if ( element.firstChild ) { | ||||||
|  | 						element.firstChild.replaceWith( node ); | ||||||
|  | 					} else { | ||||||
|  | 						element.appendChild( node ); | ||||||
|  | 					} | ||||||
|  | 					MathJax.startup.document.clear(); | ||||||
|  | 					MathJax.startup.document.updateDocument(); | ||||||
|  | 				} ); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			// Fixme: MathJax typesetting cause occasionally math processing error without asynchronous call
 | ||||||
|  | 			// eslint-disable-next-line
 | ||||||
|  | 			setTimeout( () => { | ||||||
|  | 				if ( display ) { | ||||||
|  | 					element.innerHTML = '\\[' + equation + '\\]'; | ||||||
|  | 				} else { | ||||||
|  | 					element.innerHTML = '\\(' + equation + '\\)'; | ||||||
|  | 				} | ||||||
|  | 				MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] ); // eslint-disable-line
 | ||||||
|  | 			} ); | ||||||
|  | 		} | ||||||
|  | 	} else if ( engine === 'katex' && typeof katex !== 'undefined' ) { | ||||||
|  | 		katex.render( equation, element, { | ||||||
|  | 			throwOnError: false, | ||||||
|  | 			displayMode: display | ||||||
|  | 		} ); | ||||||
|  | 	} else if ( typeof engine === 'function' ) { | ||||||
|  | 		engine( equation, element, display ); | ||||||
|  | 	} else { | ||||||
|  | 		element.innerHTML = equation; | ||||||
|  | 		// eslint-disable-next-line
 | ||||||
|  | 		console.warn( `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${engine}) for tex.` ); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Simple MathJax 3 version check
 | ||||||
|  | export function isMathJaxVersion3( version ) { | ||||||
|  | 	return version && typeof version === 'string' && version.split( '.' ).length === 3 && version.split( '.' )[ 0 ] === '3'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Check if equation has delimiters
 | ||||||
|  | export function hasDelimiters( text ) { | ||||||
|  | 	return text.match( /^(\\\[.*?\\\]|\\\(.*?\\\))$/ ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Extract delimiters and figure display mode for the model
 | ||||||
|  | export function extractDelimiters( equation ) { | ||||||
| 	equation = equation.trim(); | 	equation = equation.trim(); | ||||||
| 
 | 
 | ||||||
| 	// Remove delimiters (e.g. \( \) or \[ \])
 | 	// Remove delimiters (e.g. \( \) or \[ \])
 | ||||||
|  | |||||||
| @ -7,13 +7,9 @@ | |||||||
|     flex-wrap: nowrap; |     flex-wrap: nowrap; | ||||||
| 
 | 
 | ||||||
| 	& .ck.ck-math-preview { | 	& .ck.ck-math-preview { | ||||||
| 		user-select: none; | 		// Todo: calculate content size | ||||||
| 	} | 		width: 234px; | ||||||
| 
 | 		height: 10em; | ||||||
| 	/* FIXME: mathjax isn't working with .ck.ck-reset_all * without this fix*/ |  | ||||||
| 	& .ck.ck-math-preview * { |  | ||||||
| 		vertical-align: initial; |  | ||||||
| 		text-align: center; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|     @mixin ck-media-phone { |     @mixin ck-media-phone { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Sauli Anto
						Sauli Anto