Re-duplicate deduplicated TemplateStyles

Bug: T287675
Bug: T299251
Change-Id: I7711c30131cb441f84b3e2137983f0ba2a50b46f
This commit is contained in:
Bartosz Dziewoński 2022-01-04 16:09:09 +01:00
parent 3c02dbcc7f
commit 005a8d24ef
3 changed files with 76 additions and 0 deletions

View file

@ -229,6 +229,9 @@ ve.init.mw.Target.static.parseDocument = function ( documentString, mode, sectio
}
// Strip legacy IDs, for example in section headings
mw.libs.ve.stripParsoidFallbackIds( doc.body );
// Re-duplicate deduplicated TemplateStyles, for correct rendering when editing a section or
// when templates are removed during the edit
mw.libs.ve.reduplicateStyles( doc.body );
// Fix relative or missing base URL if needed
this.fixBase( doc );
}

View file

@ -91,6 +91,10 @@
// Remove these to avoid triggering selser.
$( newDoc ).find( '[data-mw-section-id]:not( section )' ).removeAttr( 'data-mw-section-id' );
// Deduplicate styles (we re-duplicated them in ve.init.mw.Target.static.parseDocument)
// to let selser recognize the nodes and avoid dirty diffs.
mw.libs.ve.deduplicateStyles( newDoc.body );
// Add doctype manually
// ve.serializeXhtml is loaded separately from utils.parsing
// eslint-disable-next-line no-undef

View file

@ -93,6 +93,75 @@ mw.libs.ve.stripRestbaseIds = function ( doc ) {
} );
};
/**
* Re-duplicate deduplicated TemplateStyles, for correct rendering when editing a section or
* when templates are removed during the edit.
*
* @param {HTMLElement} element Parent element, e.g. document body
*/
mw.libs.ve.reduplicateStyles = function ( element ) {
Array.prototype.forEach.call( element.querySelectorAll( 'link[rel="mw-deduplicated-inline-style"]' ), function ( link ) {
var href = link.getAttribute( 'href' );
if ( !href || href.slice( 0, 'mw-data:'.length ) !== 'mw-data:' ) {
return;
}
var key = href.slice( 'mw-data:'.length );
var style = element.querySelector( 'style[data-mw-deduplicate="' + key + '"]' );
if ( !style ) {
return;
}
var newStyle = link.ownerDocument.createElement( 'style' );
newStyle.setAttribute( 'data-mw-deduplicate', key );
// Copy content from the old `style` node (for rendering)
for ( var i = 0; i < style.childNodes.length; i++ ) {
newStyle.appendChild( style.childNodes[ i ].cloneNode( true ) );
}
// Copy attributes from the old `link` node (for selser)
Array.prototype.forEach.call( link.attributes, function ( attr ) {
if ( attr.name !== 'rel' && attr.name !== 'href' ) {
newStyle.setAttribute( attr.name, attr.value );
}
} );
link.parentNode.replaceChild( newStyle, link );
} );
};
/**
* De-duplicate TemplateStyles, like Parsoid does.
*
* @param {HTMLElement} element Parent element, e.g. document body
*/
mw.libs.ve.deduplicateStyles = function ( element ) {
var styleTagKeys = {};
Array.prototype.forEach.call( element.querySelectorAll( 'style[data-mw-deduplicate]' ), function ( style ) {
var key = style.getAttribute( 'data-mw-deduplicate' );
if ( !styleTagKeys[ key ] ) {
// Not a dupe
styleTagKeys[ key ] = true;
return;
}
// Dupe - replace with a placeholder <link> reference
var link = style.ownerDocument.createElement( 'link' );
link.setAttribute( 'rel', 'mw-deduplicated-inline-style' );
link.setAttribute( 'href', 'mw-data:' + key );
// Copy attributes from the old `link` node (for selser)
Array.prototype.forEach.call( style.attributes, function ( attr ) {
if ( attr.name !== 'rel' && attr.name !== 'data-mw-deduplicate' ) {
link.setAttribute( attr.name, attr.value );
}
} );
style.parentNode.replaceChild( link, style );
} );
};
/**
* Fix fragment links which should be relative to the current document
*