diff --git a/CHANGES.md b/CHANGES.md
index 1501a4548b4..5296fef8da3 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -12,6 +12,7 @@ CKEditor 4 Changelog
* [#6504](http://dev.ckeditor.com/ticket/6504): Resolved race condition while loading several customConfig files.
* [#10298](http://dev.ckeditor.com/ticket/10298): Data processor breaks attributes containing protected parts.
* [#9945](http://dev.ckeditor.com/ticket/9945): [iOS] Scrolling not possible on iPad.
+* [#10165](http://dev.ckeditor.com/ticket/10165): [IE] Access denied error if document.domain has been altered.
## CKEditor 4.1.1
diff --git a/core/dom/document.js b/core/dom/document.js
index ec7e6d5c1f4..9ba43d927f4 100644
--- a/core/dom/document.js
+++ b/core/dom/document.js
@@ -261,7 +261,12 @@ CKEDITOR.tools.extend( CKEDITOR.dom.document.prototype, {
this.$.open( 'text/html', 'replace' );
// Support for custom document.domain in IE.
- CKEDITOR.env.isCustomDomain() && ( this.$.domain = document.domain );
+ //
+ // The script must be appended because if placed before the
+ // doctype, IE will go into quirks mode and mess with
+ // the editable, e.g. by changing its default height.
+ if ( CKEDITOR.env.ie )
+ html = html.replace( /(?:^\s*]*?>)|^/i, '$&\n' );
this.$.write( html );
this.$.close();
diff --git a/core/env.js b/core/env.js
index b04fcc70280..88de856decd 100644
--- a/core/env.js
+++ b/core/env.js
@@ -109,6 +109,7 @@ if ( !CKEDITOR.env ) {
* alert( 'I\'m in a custom domain!' );
*
* @returns {Boolean} `true` if a custom domain is enabled.
+ * @deprecated
*/
isCustomDomain: function() {
if ( !this.ie )
diff --git a/core/tools.js b/core/tools.js
index 7c69e73903f..5e9e0890ef5 100644
--- a/core/tools.js
+++ b/core/tools.js
@@ -971,6 +971,45 @@
obj[ arr[ i ] ] = fillWith;
return obj;
+ },
+
+ /**
+ * Tries to fix the document.domain of the current document to match the
+ * parent window domain, avoiding "Same Origin" policy issues.
+ * This is a IE only requirement.
+ *
+ * @since 4.1.2
+ * @returns {boolean} True if the current domain is already good or if
+ * it has been fixed successfully.
+ */
+ fixDomain: function() {
+ var domain;
+
+ while( 1 ) {
+ try {
+ // Try to access the parent document. It throws
+ // "access denied" if restricted by the "Same Origin" policy.
+ domain = parent.document.domain;
+ return true;
+ } catch ( e ) {
+ // Calculate the value to set to document.domain.
+ domain = domain ?
+
+ // If it is not the first pass, strip one part of the
+ // name. E.g. "test.example.com" => "example.com"
+ domain.replace( /.+?(?:\.|$)/, '' ) :
+
+ // In the first pass, we'll handle the
+ // "document.domain = document.domain" case.
+ document.domain;
+
+ // Stop here if there is no more domain parts available.
+ if ( !domain )
+ return false;
+
+ document.domain = domain;
+ }
+ }
}
};
})();
diff --git a/plugins/clipboard/dialogs/paste.js b/plugins/clipboard/dialogs/paste.js
index 793f759a962..aeb7b00f208 100644
--- a/plugins/clipboard/dialogs/paste.js
+++ b/plugins/clipboard/dialogs/paste.js
@@ -5,7 +5,6 @@
CKEDITOR.dialog.add( 'paste', function( editor ) {
var lang = editor.lang.clipboard;
- var isCustomDomain = CKEDITOR.env.isCustomDomain();
function onPasteFrameLoad( win ) {
var doc = new CKEDITOR.dom.document( win.document ),
@@ -130,12 +129,12 @@ CKEDITOR.dialog.add( 'paste', function( editor ) {
var src =
CKEDITOR.env.air ?
'javascript:void(0)' :
- isCustomDomain ?
- 'javascript:void((function(){' +
+ CKEDITOR.env.ie ?
+ 'javascript:void((function(){' + encodeURIComponent(
'document.open();' +
- 'document.domain=\'' + document.domain + '\';' +
- 'document.close();' +
- '})())"'
+ '(' + CKEDITOR.tools.fixDomain + ')();' +
+ 'document.close();'
+ ) + '})())"'
: '';
var iframe = CKEDITOR.dom.element.createFromHtml( '