/** * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or http://ckeditor.com/license */ /** * @fileOverview [Mathematical Formulas] LON-CAPA ckeditor plugin for the m element, derived from ckeditor mathjax plugin. */ 'use strict'; ( function() { var cdn = 'http:\/\/cdn.mathjax.org\/mathjax\/2.2-latest\/MathJax.js?config=TeX-AMS_HTML'; CKEDITOR.plugins.add( 'lcm', { 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: 'lcm', hidpi: true, // %REMOVE_LINE_CORE% init: function( editor ) { var cls = editor.config.mathJaxClass || 'math-tex'; editor.widgets.add( 'lcm', { inline: true, dialog: 'lcm', button: editor.lang.lcm.button, mask: true, allowedContent: 'span(!' + cls + ')', // Allow style classes only on spans having lcm class. styleToAllowedContentRules: function( style ) { var classes = style.getClassesArray(); if ( !classes ) return null; classes.push( '!' + cls ); return 'span(' + classes.join( ',' ) + ')'; }, pathName: editor.lang.lcm.pathName, template: '', parts: { span: 'span' }, defaults: { math: '$ x $' // the default helps to show the $...$ syntax }, 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.lcm.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.lcm.fixSrc ); this.frameWrapper = new CKEDITOR.plugins.lcm.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 == 'm' ) ) return; if ( el.children.length > 1 || el.children[ 0 ].type != CKEDITOR.NODE_TEXT ) return; data.math = CKEDITOR.tools.htmlDecode( el.children[ 0 ].value ); // NOTE: we do not preserve the display attribute, because only MathJax is used for preview var span = new CKEDITOR.htmlParser.element('span'); span.addClass(cls); // Add style display:inline-block to have proper height of widget wrapper and mask. var attrs = span.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; if (el.attributes.eval) attrs['data-eval'] = el.attributes.eval; // NOTE: the display attribute is not preserved el.replaceWith(span); return span; }, downcast: function( el ) { var m = new CKEDITOR.htmlParser.element('m'); if (el.attributes['data-eval']) m.attributes.eval = el.attributes['data-eval']; m.add(new CKEDITOR.htmlParser.text(CKEDITOR.tools.htmlEncode(this.data.math))); return m; } } ); // Add dialog. CKEDITOR.dialog.add( 'lcm', this.path + 'dialogs/lcm.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.lcm.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 ) { if (/^\s*\$\$.*\$\$\s*$/.test(value)) { // replace $$...$$ by \[...\] value = value.replace(/^\s*\$\$(.*)\$\$\s*$/, '\\[$1\\]'); } else if (/^\s*\$.*\$\s*$/.test(value)) { // replace $...$ by \(...\) value = value.replace(/^\s*\$(.*)\$\s*$/, '\\($1\\)'); } else if (/^\s*\\\(.*\\\)\s*$/.test(value)) { // leave \( \) as is } else if (/^\s*\\\[.*\\\]\s*$/.test(value)) { // leave \[ \] as is } else { // add \( \) // value = '\\(' + value + '\\)'; // actually, we do not want to display things too well in this case // (if this is math, it would not work well with other math renderings like tth) } 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.lcm.frameWrapper = function( iFrame, editor ) { iFrame.getFrameDocument().write( '' + '' + '' + '' + '' + '' + '' + '' + '' ); return { setValue: function( value ) { var doc = iFrame.getFrameDocument(), tex = doc.getById( 'tex' ); tex.setHtml( CKEDITOR.plugins.lcm.trim( CKEDITOR.tools.htmlEncode( value ) ) ); CKEDITOR.plugins.lcm.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 */