Skip to content

Commit 95bd2fe

Browse files
author
Piotr Jasiun
committed
Merge branch 't/10937' into major
2 parents 2849cd0 + 2052f8b commit 95bd2fe

File tree

7 files changed

+175
-86
lines changed

7 files changed

+175
-86
lines changed

CHANGES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ CKEditor 4 Changelog
55

66
New Features:
77

8+
* [#10937](http://dev.ckeditor.com/ticket/10937): MathJax widget improvements:
9+
* loading indicator,
10+
* IE8 support,
11+
* apply paragraph changes (like font color change) to iframe,
12+
* FF and IE9 clipboard fixes,
13+
* fix same origin policy issue,
14+
* fix undo bug,
15+
* fix minor bugs,
816
* [#10028](http://dev.ckeditor.com/ticket/10028): New [`config.dialog_noConfirmCancel`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-dialog_noConfirmCancel) configuration option that eliminates the need to confirm closing of a dialog window when the user changed any of its fields.
917

1018
Fixed Issues:

core/htmlparser/fragment.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ CKEDITOR.htmlParser.fragment = function() {
4545
var rootDtd = CKEDITOR.tools.extend( {}, { html:1 }, CKEDITOR.dtd.html, CKEDITOR.dtd.body, CKEDITOR.dtd.head, { style:1,script:1 } );
4646

4747
function isRemoveEmpty( node ) {
48+
// Keep marked element event if it is empty.
49+
if ( node.attributes[ 'data-cke-survive' ] )
50+
return false;
51+
4852
// Empty link is to be removed when empty but not anchor. (#7894)
4953
return node.name == 'a' && node.attributes.href || CKEDITOR.dtd.$removeEmpty[ node.name ];
5054
}

plugins/mathjax/dev/mathjax.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<meta name="ckeditor-sample-isnew" content="1">
1616
<script>
1717
CKEDITOR.disableAutoInline = true;
18+
document.domain = 'ckeditor.dev';
1819
</script>
1920
</head>
2021
<body>

plugins/mathjax/dialogs/mathjax.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ CKEDITOR.dialog.add( 'mathjax', function( editor ) {
6060
type: 'html',
6161
html:
6262
'<div style="width:100%;text-align:center;">' +
63-
'<iframe style="border:0;width:0;height:0;font-size:20px" scrolling="no" frameborder="0" allowTransparency="true"></iframe>' +
63+
'<iframe style="border:0;width:0;height:0;font-size:20px" scrolling="no" frameborder="0" allowTransparency="true" src="' + CKEDITOR.plugins.mathjax.fixSrc + '"></iframe>' +
6464
'</div>',
6565

6666
onLoad: function( widget ) {

plugins/mathjax/images/loader.gif

1.01 KB
Loading

plugins/mathjax/lang/en.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ CKEDITOR.plugins.setLang( 'mathjax', 'en', {
77
button: 'Math',
88
dialogInput: 'Write you TeX here',
99
docUrl: 'http://en.wikibooks.org/wiki/LaTeX/Mathematics',
10-
docLabel: 'TeX documentation'
10+
docLabel: 'TeX documentation',
11+
loading: 'loading...'
1112
} );

plugins/mathjax/plugin.js

Lines changed: 159 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,42 @@
2929
mask: true,
3030
allowedContent: 'span(!' + cls + ')',
3131

32-
template:
33-
'<span class="' + cls + '" style="display:inline-block">' +
34-
'<iframe style="border:0;width:0;height:0" scrolling="no" frameborder="0" allowTransparency="true"></iframe>' +
35-
'</span>',
32+
template: '<span class="' + cls + '" style="display:inline-block" data-cke-survive=1></span>',
3633

3734
parts: {
38-
iframe: 'iframe'
35+
span: 'span'
3936
},
4037

4138
defaults: {
4239
math: '\\(x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}\\)'
4340
},
4441

4542
init: function() {
43+
var iframe = this.parts.span.getChild( 0 );
44+
45+
// Check if span contains iframe and create it otherwise.
46+
if ( !iframe || iframe.type != CKEDITOR.NODE_ELEMENT || !iframe.is( 'iframe' ) ) {
47+
iframe = new CKEDITOR.dom.element( 'iframe' );
48+
iframe.setAttributes( {
49+
style: 'border:0;width:0;height:0',
50+
scrolling: 'no',
51+
frameborder: 0,
52+
allowTransparency: true,
53+
src: CKEDITOR.plugins.mathjax.fixSrc
54+
} );
55+
this.parts.span.append( iframe );
56+
}
57+
4658
// Wait for ready because on some browsers iFrame will not
4759
// have document element until it is put into document.
4860
// This is a problem when you crate widget using dialog.
4961
this.once( 'ready', function() {
50-
this.frameWrapper = new CKEDITOR.plugins.mathjax.frameWrapper( this.parts.iframe, editor );
62+
// Src attribute must be recreated to fix custom domain error after undo
63+
// (see iFrame.removeAttribute( 'src' ) in frameWrapper.load).
64+
if ( CKEDITOR.env.ie )
65+
iframe.setAttribute( 'src', CKEDITOR.plugins.mathjax.fixSrc );
66+
67+
this.frameWrapper = new CKEDITOR.plugins.mathjax.frameWrapper( iframe, editor );
5168
this.frameWrapper.setValue( this.data.math );
5269
} );
5370
},
@@ -68,17 +85,16 @@
6885

6986
// Add style display:inline-block to have proper height of widget wrapper and mask.
7087
var attrs = el.attributes;
88+
7189
if ( attrs.style )
7290
attrs.style += ';display:inline-block';
7391
else
7492
attrs.style = 'display:inline-block';
7593

76-
el.children[ 0 ].replaceWith( new CKEDITOR.htmlParser.element( 'iframe', {
77-
style: 'border:0;width:0;height:0',
78-
scrolling: 'no',
79-
frameborder: 0,
80-
allowTransparency: true
81-
} ) );
94+
// Add attribute to prevent deleting empty span in data processing.
95+
attrs[ 'data-cke-survive' ] = 1;
96+
97+
el.children[ 0 ].remove();
8298

8399
return el;
84100
},
@@ -104,11 +120,46 @@
104120
evt.data.dataValue = evt.data.dataValue.replace( /<\/head>/,
105121
'<script src="' + ( editor.config.mathJaxLib ? CKEDITOR.getUrl( editor.config.mathJaxLib ) : cdn ) + '"><\/script><\/head>' );
106122
} );
123+
124+
editor.on( 'paste', function( evt ) {
125+
// Firefox does remove iFrame elements from pasted content so this event do the same on other browsers.
126+
// Also iFrame in paste content is reason of "Unspecified error" in IE9 (#10857).
127+
var regex = new RegExp( '<span[^>]*?' + cls + '.*?<\/span>', 'ig' );
128+
evt.data.dataValue = evt.data.dataValue.replace( regex, function( match ) {
129+
return match.replace( /(<iframe.*?\/iframe>)/i, '' );
130+
} );
131+
} );
107132
}
108133
} );
109134

110135
CKEDITOR.plugins.mathjax = {};
111136

137+
/**
138+
* Variable to fix problems with iFrame. This variable is global
139+
* because it is used in both widget and dialog.
140+
*
141+
* @private
142+
*/
143+
CKEDITOR.plugins.mathjax.fixSrc =
144+
// In Firefox src must exist and be different than about:blank to emit load event.
145+
CKEDITOR.env.gecko ? 'javascript:true' :
146+
// Support for custom document.domain in IE.
147+
CKEDITOR.env.ie ? 'javascript:' +
148+
'void((function(){' + encodeURIComponent(
149+
'document.open();' +
150+
'(' + CKEDITOR.tools.fixDomain + ')();' +
151+
'document.close();'
152+
) + '})())' :
153+
// In Chrome src must be undefined to emit load event.
154+
'javascript:void(0)';
155+
156+
/**
157+
* Loading indicator image generated by preloaders.net.
158+
*
159+
* @private
160+
*/
161+
CKEDITOR.plugins.mathjax.loadingIcon = CKEDITOR.plugins.get( 'mathjax' ).path + 'images/loader.gif',
162+
112163
/**
113164
* FrameWrapper is responsible for communication between the MathJax library
114165
* and the `iframe` element that is used for rendering mathematical formulas
@@ -148,38 +199,113 @@
148199

149200
// Function called when MathJax finish his job.
150201
updateDoneHandler = CKEDITOR.tools.addFunction( function() {
202+
203+
// Copy styles from iFrame to body inside iFrame.
204+
var stylesToCopy = [ 'color', 'font-family', 'font-style', 'font-weight', 'font-variant', 'font-size' ];
205+
206+
for ( var i = 0; i < stylesToCopy.length; i++ ) {
207+
var key = stylesToCopy[ i ],
208+
val = iFrame.getComputedStyle( key );
209+
if ( val )
210+
preview.setStyle( key, val );
211+
}
212+
213+
// Set preview content.
151214
preview.setHtml( buffer.getHtml() );
152215

216+
editor.fire( 'lockSnapshot' );
217+
218+
iFrame.setStyles( {
219+
height: 0,
220+
width: 0
221+
} );
222+
223+
// Set iFrame dimensions.
153224
var height = Math.max( doc.$.body.offsetHeight, doc.$.documentElement.offsetHeight ),
154225
width = Math.max( preview.$.offsetWidth, doc.$.body.scrollWidth );
155226

156-
editor.fire( 'lockSnapshot' );
157-
158227
iFrame.setStyles( {
159228
height: height + 'px',
160-
width: width + 'px',
161-
display: 'inline'
229+
width: width + 'px'
162230
} );
163231

164232
editor.fire( 'unlockSnapshot' );
165233

166234
// Private! For test usage only.
167235
iFrame.fire( 'mathJaxUpdateDone' );
168236

237+
// If value changed in the meantime update it again.
169238
if ( value != newValue )
170239
update();
171240
else
172241
isRunning = false;
173-
} ),
174-
stylesToCopy = [ 'color', 'font-family', 'font-style', 'font-weight', 'font-variant', 'font-size' ],
175-
style = '';
176-
177-
// Copy styles from iFrame to body inside iFrame.
178-
for ( var i = 0; i < stylesToCopy.length; i++ ) {
179-
var key = stylesToCopy[ i ],
180-
val = iFrame.getComputedStyle( key );
181-
if ( val )
182-
style += key + ': ' + val + ';';
242+
} );
243+
244+
iFrame.on( 'load', load );
245+
246+
load();
247+
248+
function load() {
249+
doc = iFrame.getFrameDocument();
250+
251+
if ( doc.getById( 'preview' ) )
252+
return;
253+
254+
// Because of IE9 bug in a src attribute can not be javascript
255+
// when you undo (#10930). If you have iFrame with javascript in src
256+
// and call insertBefore on such element then IE9 will see crash.
257+
if ( CKEDITOR.env.ie )
258+
iFrame.removeAttribute( 'src' );
259+
260+
doc.write( '<!DOCTYPE html>' +
261+
'<html>' +
262+
'<head>' +
263+
'<meta charset="utf-8">' +
264+
'<script type="text/x-mathjax-config">' +
265+
266+
// MathJax configuration, disable messages.
267+
'MathJax.Hub.Config( {' +
268+
'showMathMenu: false,' +
269+
'messageStyle: "none"' +
270+
'} );' +
271+
272+
// Get main CKEDITOR form parent.
273+
'function getCKE() {' +
274+
'if ( typeof window.parent.CKEDITOR == \'object\' ) {' +
275+
'return window.parent.CKEDITOR;' +
276+
'} else {' +
277+
'return window.parent.parent.CKEDITOR;' +
278+
'}' +
279+
'}' +
280+
281+
// Run MathJax.Hub with its actual parser and call callback function after that.
282+
// Because MathJax.Hub is asynchronous create MathJax.Hub.Queue to wait with callback.
283+
'function update() {' +
284+
'MathJax.Hub.Queue(' +
285+
'[ \'Typeset\', MathJax.Hub, this.buffer ],' +
286+
'function() {' +
287+
'getCKE().tools.callFunction( ' + updateDoneHandler + ' );' +
288+
'}' +
289+
');' +
290+
'}' +
291+
292+
// Run MathJax for the first time, when the script is loaded.
293+
// Callback function will be called then it's done.
294+
'MathJax.Hub.Queue( function() {' +
295+
'getCKE().tools.callFunction(' + loadedHandler + ');' +
296+
'} );' +
297+
'</script>' +
298+
299+
// Load MathJax lib.
300+
'<script src="' + ( editor.config.mathJaxLib || cdn ) + '"></script>' +
301+
'</head>' +
302+
'<body style="padding:0;margin:0;background:transparent;overflow:hidden">' +
303+
'<span id="preview"></span>' +
304+
305+
// Render everything here and after that copy it to the preview.
306+
'<span id="buffer" style="display:none"></span>' +
307+
'</body>' +
308+
'</html>' );
183309
}
184310

185311
// Run MathJax parsing Tex.
@@ -188,13 +314,17 @@
188314

189315
value = newValue;
190316

317+
editor.fire( 'lockSnapshot' );
318+
191319
buffer.setHtml( value );
192320

193-
editor.fire( 'lockSnapshot' );
321+
// Set loading indicator.
322+
preview.setHtml( '<img src=' + CKEDITOR.plugins.mathjax.loadingIcon + ' alt=' + editor.lang.mathjax.loading + '>' );
194323

195324
iFrame.setStyles( {
196-
height: 0,
197-
width: 0,
325+
height: '16px',
326+
width: '16px',
327+
display: 'inline',
198328
'vertical-align': 'middle'
199329
} );
200330

@@ -204,61 +334,6 @@
204334
doc.getWindow().$.update( value );
205335
}
206336

207-
doc.write( '<!DOCTYPE html>' +
208-
'<html>' +
209-
'<head>' +
210-
'<meta charset="utf-8">' +
211-
'<style type="text/css">' +
212-
'span#preview {' +
213-
style +
214-
'}' +
215-
'</style>' +
216-
'<script type="text/x-mathjax-config">' +
217-
218-
// MathJax configuration, disable messages.
219-
'MathJax.Hub.Config( {' +
220-
'showMathMenu: false,' +
221-
'messageStyle: "none"' +
222-
'} );' +
223-
224-
// Get main CKEDITOR form parent.
225-
'function getCKE() {' +
226-
'if ( typeof window.parent.CKEDITOR == \'object\' ) {' +
227-
'return window.parent.CKEDITOR;' +
228-
'} else {' +
229-
'return window.parent.parent.CKEDITOR;' +
230-
'}' +
231-
'}' +
232-
233-
// Run MathJax.Hub with its actual parser and call callback function after that.
234-
// Because MathJax.Hub is asynchronous create MathJax.Hub.Queue to wait with callback.
235-
'function update() {' +
236-
'MathJax.Hub.Queue(' +
237-
'[\'Typeset\',MathJax.Hub,this.buffer],' +
238-
'function() {' +
239-
'getCKE().tools.callFunction( ' + updateDoneHandler + ' );' +
240-
'}' +
241-
');' +
242-
'}' +
243-
244-
// Run MathJax for the first time, when the script is loaded.
245-
// Callback function will be called then it's done.
246-
'MathJax.Hub.Queue( function() {' +
247-
'getCKE().tools.callFunction(' + loadedHandler + ');' +
248-
'} );' +
249-
'</script>' +
250-
251-
// Load MathJax lib.
252-
'<script src="' + ( editor.config.mathJaxLib || cdn ) + '"></script>' +
253-
'</head>' +
254-
'<body style="padding:0;margin:0;background:transparent;overflow:hidden">' +
255-
'<span id="preview"></span>' +
256-
257-
// Render everything here and after that copy it to the preview.
258-
'<span id="buffer" style="display:none"></span>' +
259-
'</body>' +
260-
'</html>' );
261-
262337
return {
263338
/**
264339
* Sets the TeX value to be displayed in the `iframe` element inside

0 commit comments

Comments
 (0)