/** * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or http://ckeditor.com/license */ /** * @fileOverview [Mathematical Formulas](http://ckeditor.com/addon/mathjax) plugin. */ 'use strict'; ( function() { var cdn = 'http:\/\/cdn.mathjax.org\/mathjax\/2.2-latest\/MathJax.js?config=TeX-AMS_HTML'; CKEDITOR.plugins.add( 'mathjax', { lang: 'af,ar,ca,cs,cy,da,de,el,en,en-gb,eo,es,fa,fi,fr,gl,he,hr,hu,it,ja,km,ku,lt,nb,nl,no,pl,pt,pt-br,ro,ru,sk,sl,sq,sv,tr,tt,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE% requires: 'widget,dialog', icons: 'mathjax', hidpi: true, // %REMOVE_LINE_CORE% init: function( editor ) { var cls = editor.config.mathJaxClass || 'math-tex'; editor.widgets.add( 'mathjax', { inline: true, dialog: 'mathjax', button: editor.lang.mathjax.button, mask: true, allowedContent: 'span(!' + cls + ')', // Allow style classes only on spans having mathjax class. styleToAllowedContentRules: function( style ) { var classes = style.getClassesArray(); if ( !classes ) return null; classes.push( '!' + cls ); return 'span(' + classes.join( ',' ) + ')'; }, pathName: editor.lang.mathjax.pathName, template: '', parts: { span: 'span' }, defaults: { math: '\\(x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}\\)' }, init: function() { var iframe = this.parts.span.getChild( 0 ); // Check if span contains iframe and create it otherwise. if ( !iframe || iframe.type != CKEDITOR.NODE_ELEMENT || !iframe.is( 'iframe' ) ) { iframe = new CKEDITOR.dom.element( 'iframe' ); iframe.setAttributes( { style: 'border:0;width:0;height:0', scrolling: 'no', frameborder: 0, allowTransparency: true, src: CKEDITOR.plugins.mathjax.fixSrc } ); this.parts.span.append( iframe ); } // Wait for ready because on some browsers iFrame will not // have document element until it is put into document. // This is a problem when you crate widget using dialog. this.once( 'ready', function() { // Src attribute must be recreated to fix custom domain error after undo // (see iFrame.removeAttribute( 'src' ) in frameWrapper.load). if ( CKEDITOR.env.ie ) iframe.setAttribute( 'src', CKEDITOR.plugins.mathjax.fixSrc ); this.frameWrapper = new CKEDITOR.plugins.mathjax.frameWrapper( iframe, editor ); this.frameWrapper.setValue( this.data.math ); } ); }, data: function() { if ( this.frameWrapper ) this.frameWrapper.setValue( this.data.math ); }, upcast: function( el, data ) { if ( !( el.name == 'span' && el.hasClass( cls ) ) ) return; if ( el.children.length > 1 || el.children[ 0 ].type != CKEDITOR.NODE_TEXT ) return; data.math = CKEDITOR.tools.htmlDecode( el.children[ 0 ].value ); // Add style display:inline-block to have proper height of widget wrapper and mask. var attrs = el.attributes; if ( attrs.style ) attrs.style += ';display:inline-block'; else attrs.style = 'display:inline-block'; // Add attribute to prevent deleting empty span in data processing. attrs[ 'data-cke-survive' ] = 1; el.children[ 0 ].remove(); return el; }, downcast: function( el ) { el.children[ 0 ].replaceWith( new CKEDITOR.htmlParser.text( CKEDITOR.tools.htmlEncode( this.data.math ) ) ); // Remove style display:inline-block. var attrs = el.attributes; attrs.style = attrs.style.replace( /display:\s?inline-block;?\s?/, '' ); if ( attrs.style === '' ) delete attrs.style; return el; } } ); // Add dialog. CKEDITOR.dialog.add( 'mathjax', this.path + 'dialogs/mathjax.js' ); // Add MathJax script to page preview. editor.on( 'contentPreview', function( evt ) { evt.data.dataValue = evt.data.dataValue.replace( /<\/head>/, '' + // Load MathJax lib. '' + '' + '' + '' + // Render everything here and after that copy it to the preview. '' + '' + '' ); } // Run MathJax parsing Tex. function update() { isRunning = true; value = newValue; editor.fire( 'lockSnapshot' ); buffer.setHtml( value ); // Set loading indicator. preview.setHtml( ' + editor.lang.mathjax.loading + ' ); iFrame.setStyles( { height: '16px', width: '16px', display: 'inline', 'vertical-align': 'middle' } ); editor.fire( 'unlockSnapshot' ); // Run MathJax. doc.getWindow().$.update( value ); } return { /** * Sets the TeX value to be displayed in the `iframe` element inside * the editor. This function will activate the MathJax * library which interprets TeX expressions and converts them into * their representation that is displayed in the editor. * * @param {String} value TeX string. */ setValue: function( value ) { newValue = CKEDITOR.tools.htmlEncode( value ); if ( isInit && !isRunning ) update(); } }; }; } else { // In IE8 MathJax does not work stable so instead of using standard // frame wrapper it is replaced by placeholder to show pure TeX in iframe. CKEDITOR.plugins.mathjax.frameWrapper = function( iFrame, editor ) { iFrame.getFrameDocument().write( '' + '' + '' + '' + '' + '' + '' + '' + '' ); return { setValue: function( value ) { var doc = iFrame.getFrameDocument(), tex = doc.getById( 'tex' ); tex.setHtml( CKEDITOR.plugins.mathjax.trim( CKEDITOR.tools.htmlEncode( value ) ) ); CKEDITOR.plugins.mathjax.copyStyles( iFrame, tex ); editor.fire( 'lockSnapshot' ); iFrame.setStyles( { width: Math.min( 250, tex.$.offsetWidth ) + 'px', height: doc.$.body.offsetHeight + 'px', display: 'inline', 'vertical-align': 'middle' } ); editor.fire( 'unlockSnapshot' ); } }; }; } } )(); /** * Sets the path to the MathJax library. It can be both a local * resource and a location different than the default CDN. * * Please note that this must be a full or absolute path. * * config.mathJaxLib = 'http:\/\/example.com\/libs\/MathJax.js'; * * @cfg {String} [mathJaxLib='http:\/\/cdn.mathjax.org\/mathjax\/2.2-latest\/MathJax.js?config=TeX-AMS_HTML'] * @member CKEDITOR.config */ /** * Sets the default class for `span` elements that will be * converted into [Mathematical Formulas](http://ckeditor.com/addon/mathjax) * widgets. * * If you set it to the following: * * config.mathJaxClass = 'my-math'; * * The code below will be recognized as a Mathematical Formulas widget. * * \( \sqrt{4} = 2 \) * * @cfg {String} [mathJaxClass='math-tex'] * @member CKEDITOR.config */