Deal with Parsoid's protocol-relative <base> tags in a DOMParser world

Protocol-relative <base> tags are fine when the iframe trick is used
because the iframe inherits a default base URL from the parent document,
so if the <base> is relative it can be resolved against that. However,
a document created with DOMParser (or document.implementation, oops!)
won't inherit anything, so anything other than a fully absolute <base>
will just break.

To make Parsoid's relative <base> work anyway, resolve it in the
context of the main document, then write the resolved version
back into the <base> tag.

Change-Id: I7261bd5dbe9ec1f4077a4e5a00bd2a03ac237ca0
This commit is contained in:
Roan Kattouw 2014-03-26 21:49:59 -07:00
parent c149b1c071
commit c06a86587c

View file

@ -309,6 +309,27 @@ ve.init.mw.Target.static.apiRequest = function ( data, settings ) {
return $.ajax( settings );
};
/**
* Take a target document with a possibly relative base URL, and modify it to be absolute.
* The base URL of the target document is resolved using the base URL of the source document.
* @param {HTMLDocument} targetDoc Document whose base URL should be resolved
* @param {HTMLDocument} sourceDoc Document whose base URL should be used for resolution
*/
ve.init.mw.Target.static.fixBase = function ( targetDoc, sourceDoc ) {
var $base;
if ( !targetDoc.baseURI ) {
$base = $( 'base', targetDoc );
if ( $base.length ) {
// Modify the existing <base> tag
$base.attr( 'href', ve.resolveUrl( $base.attr( 'href' ), sourceDoc ) );
} else {
// No <base> tag, add one
$base = $( '<base>', targetDoc ).attr( 'href', sourceDoc.baseURI );
$( 'head', sourceDoc ).append( $base );
}
}
};
/**
* Handle the RL modules for VE and registered plugin modules being loaded.
*
@ -367,6 +388,9 @@ ve.init.mw.Target.onLoad = function ( response ) {
this.originalHtml = data.content;
this.doc = ve.createDocumentFromHtml( this.originalHtml );
// Parsoid outputs a protocol-relative <base> tag, so absolutize it
this.constructor.static.fixBase( this.doc, document );
this.remoteNotices = ve.getObjectValues( data.notices );
this.$checkboxes = $( ve.getObjectValues( data.checkboxes ).join( '' ) );
// Populate checkboxes with default values for minor and watch