Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix fire print on Firefox #4813

Merged
merged 17 commits into from
Aug 27, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions plugins/preview/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
modes: { wysiwyg: 1 },
canUndo: false,
readOnly: 1,
exec: CKEDITOR.plugins.preview.createPreview
exec: function() {
CKEDITOR.plugins.preview.createPreview( editor );
}
} );
editor.ui.addButton && editor.ui.addButton( 'Preview', {
label: editor.lang.preview.preview,
Expand All @@ -49,15 +51,17 @@
* **Note**: This function will open a new browser window with the editor's content HTML.
*
* @param {CKEDITOR.editor} editor The editor instance.
KarolDawidziuk marked this conversation as resolved.
Show resolved Hide resolved
* @param {Function} [callback] The function that will be fired after preview window is loaded.
* @returns {CKEDITOR.dom.window} A newly created window that contains the preview HTML.
*/
createPreview: function( editor ) {
var previewHtml = createPreviewHtml( editor ),
createPreview: function( editor, callback ) {
var previewHtml = createPreviewHtml( editor, callback ),
eventData = { dataValue: previewHtml },
windowDimensions = getWindowDimensions(),
// For IE we should use window.location rather than setting url in window.open (https://dev.ckeditor.com/ticket/11146).
previewLocation = getPreviewLocation(),
previewUrl = getPreviewUrl(),
nativePreviewWindow,
previewWindow,
doc;

Expand All @@ -74,27 +78,41 @@
window._cke_htmlToLoad = eventData.dataValue;
}

previewWindow = window.open( previewUrl, null, generateWindowOptions( windowDimensions ) );
nativePreviewWindow = window.open( previewUrl, null, generateWindowOptions( windowDimensions ) );
previewWindow = new CKEDITOR.dom.window( nativePreviewWindow );

// For IE we want to assign whole js stored in previewLocation, but in case of
// popup blocker activation oWindow variable will be null (https://dev.ckeditor.com/ticket/11597).
if ( previewLocation && previewWindow ) {
previewWindow.location = previewLocation;
if ( previewLocation && nativePreviewWindow ) {
nativePreviewWindow.location = previewLocation;
}

if ( !window._cke_htmlToLoad ) {
doc = previewWindow.document;
doc = nativePreviewWindow.document;

doc.open();
doc.write( eventData.dataValue );
doc.close();
}

return new CKEDITOR.dom.window( previewWindow );
if ( callback ) {
nativePreviewWindow.fireCallback = function() {
// In several browsers (e.g. Safari or Chrome on Linux) print command
// seems to be blocking loading of the preview page. Because of that
// print must be performed after the document is complete.
if ( nativePreviewWindow.document.readyState === 'complete' ) {
callback( previewWindow );
}
};

nativePreviewWindow.fireCallback();
KarolDawidziuk marked this conversation as resolved.
Show resolved Hide resolved
}

return previewWindow;
}
};

function createPreviewHtml( editor ) {
function createPreviewHtml( editor, callback ) {
var pluginPath = CKEDITOR.plugins.getPath( 'preview' ),
config = editor.config,
title = editor.lang.preview.preview,
Expand All @@ -113,6 +131,7 @@
'<link rel="stylesheet" media="screen" href="' + pluginPath + 'styles/screen.css">' +
'</head>' + createBodyHtml() +
editor.getData() +
setPrintCallback( callback ) +
'</body></html>';

function generateBaseTag() {
Expand Down Expand Up @@ -155,6 +174,17 @@

return html;
}

function setPrintCallback( callback ) {
if ( !callback ) {
return '';
}

// On IE onreadystatechange does not change document.readyState to complete if there are any images in the content.
// So we need introduce a two flows. One for IE and second for all other browsers. (#4790)
var event = CKEDITOR.env.ie ? 'window.onload' : 'document.onreadystatechange';
return '<script>' + event + ' = function() { fireCallback(); } </script>';
}
}

function getWindowDimensions() {
Expand Down Expand Up @@ -182,7 +212,8 @@
}

function getPreviewLocation() {
if ( !CKEDITOR.env.ie ) {
// #(4444)
if ( !CKEDITOR.env.ie && !CKEDITOR.env.gecko ) {
return null;
}

Expand Down
22 changes: 3 additions & 19 deletions plugins/print/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,33 +52,17 @@
*/
CKEDITOR.plugins.print = {
exec: function( editor ) {
var previewWindow = CKEDITOR.plugins.preview.createPreview( editor ),
nativePreviewWindow;
CKEDITOR.plugins.preview.createPreview( editor, function( previewWindow ) {
var nativePreviewWindow = previewWindow.$;

if ( !previewWindow ) {
return;
}

nativePreviewWindow = previewWindow.$;

// In several browsers (e.g. Safari or Chrome on Linux) print command
// seems to be blocking loading of the preview page. Because of that
// print must be performed after the document is complete.
if ( nativePreviewWindow.document.readyState === 'complete' ) {
return print();
}

previewWindow.once( 'load', print );

function print() {
if ( CKEDITOR.env.gecko ) {
nativePreviewWindow.print();
} else {
nativePreviewWindow.document.execCommand( 'Print' );
}

nativePreviewWindow.close();
}
} );
},
canUndo: false,
readOnly: 1,
Expand Down
100 changes: 100 additions & 0 deletions tests/plugins/preview/manual/previewcdn.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<div id="editor"></div>
<div id="loading_box" style="margin: 20px 0"></div>
<div id="editor_cdn">
<h1>Sample <span style="color: red;">document</span></h1>
<p>Lorem ipsum</p>
<div style="page-break-after:always">
<span style="display:none">&nbsp;</span>
</div>
<p>dolor sit amet.</p>
</div>

<script>
if ( bender.env.mobile ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ( bender.env.mobile ) {
if ( bender.tools.env.mobile ) {

bender.ignore();
}

// 1. Load local editor by default with bender.
// 2. Remove existing instance and add script with editor from CDN.
// 3. Wait for the new editor to be loaded from CDN and initialize it.
// 4. Add icons in IE <11 from local.
var editorVersion = '',
path = getCKEditorCORSLink( window.location );

CKEDITOR.replace( 'editor' );

CKEDITOR.once( 'instanceReady', function() {
var scripts = document.querySelectorAll( 'script' ),
head = CKEDITOR.document.getHead();
pluginsList = CKEDITOR.tools.object.keys( this.plugins.registered ).join();

CKEDITOR.tools.array.forEach( scripts, function( script ){
script.parentNode.removeChild( script );
} );

CKEDITOR.instances.editor.destroy();
window.CKEDITOR = null;

var newScript = document.createElement( 'script' ),
loadingBox = document.getElementById( 'loading_box' ),
loadingText = 'Simulating loading editor from CDN';

newScript.type = 'text/javascript';
newScript.src = path + '/ckeditor.js';
document.getElementsByTagName('head')[0].appendChild( newScript );

var interval = setInterval( function() {
try {
if( CKEDITOR.status === 'loaded' ){
clearInterval( interval );

CKEDITOR.replace( 'editor_cdn', { plugins: pluginsList } );
loadingBox.innerText = editorVersion + ' editor version was loaded successfully!';

// There is problem in IE <11 with receiving icons from githack so we must add it manually.
if( CKEDITOR.env.ie && CKEDITOR.env.version < 11 ){
CKEDITOR.once( 'instanceReady', function() {
fixButtonsIcons();
} );
}
} else {
loadingText += '.';
loadingBox.innerText = loadingText;
}
} catch ( e ) {}
}, 200 );
} );

function fixButtonsIcons() {
var buttons = document.querySelectorAll( '.cke_button .cke_button_icon' );

CKEDITOR.tools.array.forEach( buttons, function( button ){
var actualPath = button.style.backgroundImage,
origin = window.location.protocol + '//' + window.location.host,
fixedPath = actualPath.split( path ).join( origin );

button.style.backgroundImage = fixedPath;
} );
}

function getCKEditorCORSLink( location ){
var protocol = location.protocol,
hostName = location.hostname,
port = location.port,
pathName = '/apps/ckeditor',
possibleNewHostNames = [ '0.0.0.0', '127.0.0.1', 'localhost' ],
isLocalHostName = CKEDITOR.tools.indexOf( possibleNewHostNames, hostName ) !== -1;

// If we are not on localhost, simulate CORS via Githack.
if ( isLocalHostName ) {
editorVersion = 'Local';
var newHostName = CKEDITOR.tools.array.find( possibleNewHostNames , function( value ) {
return value != hostName;
} );
return protocol + '//' + newHostName + ':' + port + pathName;
}

editorVersion = 'Recent master';
return 'https://raw.githack.com/ckeditor/ckeditor4/master';
}
</script>
18 changes: 18 additions & 0 deletions tests/plugins/preview/manual/previewcdn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@bender-tags: 4.16.3, bug, 4444
@bender-ui: collapsed
@bender-ckeditor-plugins: wysiwygarea, preview, font, colorbutton, format, clipboard, pagebreak, toolbar, floatingspace, link, image2

1. Wait for the editor to load.
2. Click preview button.

**Expected result** New browser tab/window with preview is opened correctly. The content is the same as in editor.

3. Open browser console in the newly opened tab.

**Expected result** There is no error in the browser console.

**Unexpected result** There is an error in the browser console: `Permission denied to access property "_cke_htmlToLoad" on cross-origin object`

## Notes

You can add more content into editable or just copy existing to check if the preview still opens e.g. add 50 pages and click preview.
41 changes: 41 additions & 0 deletions tests/plugins/preview/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,46 @@ bender.test( {
assert.isNotUndefined( previewCommand, 'Command is registered' );
assert.areSame( previewCommand.state, CKEDITOR.TRISTATE_DISABLED, 'Command is disabled' );
} );
},

// (#4790)
'test callback should be called when document.readyState is complete': function() {
// It's not possible to overwrite window.open in IE8.
if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {
assert.ignore();
}

var documentReadyState = 'complete',
// We need to prevent the opening of a new as browsers block it and the test will fall.
openStub = sinon.stub( window, 'open', function() {
return {
document: {
open: function() {},
write: function() {},
close: function() {},
readyState: documentReadyState
}
};
} );

bender.editorBot.create( {
name: 'callback-execute-test',
config: {
plugins: 'print,image'
}
}, function( bot ) {
var editor = bot.editor,
preview = CKEDITOR.plugins.preview;

preview.createPreview( editor, function( previewWindow ) {
resume( function() {
assert.areSame( 'complete', previewWindow.$.document.readyState, 'callback was not called because document.readyState is other than complete' );
} );
} );

openStub.restore();

wait();
} );
}
} );
Loading