/**
* Live edit preview.
*/
( function ( mw, $ ) {
/**
* @param {jQuery.Event} e
*/
function doLivePreview( e ) {
var $wikiPreview, copySelectors, removeSelectors, $copyElements, $spinner,
targetUrl, postData, $previewDataHolder;
e.preventDefault();
$( mw ).trigger( 'LivePreviewPrepare' );
$wikiPreview = $( '#wikiPreview' );
// Show #wikiPreview if it's hidden to be able to scroll to it
// (if it is hidden, it's also empty, so nothing changes in the rendering)
$wikiPreview.show();
// Jump to where the preview will appear
$wikiPreview[0].scrollIntoView();
// List of selectors matching elements that we will
// update from from the ajax-loaded preview page.
copySelectors = [
// Main
'#wikiPreview',
'#wikiDiff',
'#catlinks',
'.hiddencats',
'#p-lang',
// Editing-related
'.templatesUsed',
'.mw-summary-preview'
];
$copyElements = $( copySelectors.join( ',' ) );
// Not shown during normal preview, to be removed if present
removeSelectors = [
'.mw-newarticletext'
];
$( removeSelectors.join( ',' ) ).remove();
$spinner = $.createSpinner( {
size: 'large',
type: 'block'
});
$wikiPreview.before( $spinner );
$spinner.css( {
position: 'absolute',
marginTop: $spinner.height()
} );
// Make sure preview area is at least as tall as 2x the height of the spinner.
// 1x because if its smaller, it will spin behind the edit toolbar.
// (this happens on the first preview when editPreview is still empty)
// 2x because the spinner has 1x margin top breathing room.
$wikiPreview.css( 'minHeight', $spinner.height() * 2 );
// Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
// (e.g. empty #catlinks)
$copyElements.animate( {
opacity: 0.4
}, 'fast' );
$previewDataHolder = $( '
' );
targetUrl = $( '#editform' ).attr( 'action' );
// Gather all the data from the form
postData = $( '#editform' ).formToArray();
postData.push( {
name: e.target.name,
value: ''
} );
// Load new preview data.
// TODO: This should use the action=parse API instead of loading the entire page
// Though that requires figuring out how to conver that raw data into proper HTML.
$previewDataHolder.load( targetUrl + ' ' + copySelectors.join( ',' ), postData, function () {
var i, $from;
// Copy the contents of the specified elements from the loaded page to the real page.
// Also copy their class attributes.
for ( i = 0; i < copySelectors.length; i++ ) {
$from = $previewDataHolder.find( copySelectors[i] );
$( copySelectors[i] )
.empty()
.append( $from.contents() )
.attr( 'class', $from.attr( 'class' ) );
}
$spinner.remove();
$copyElements.animate( {
opacity: 1
}, 'fast' );
$( mw ).trigger( 'LivePreviewDone', [copySelectors] );
} );
}
$( document ).ready( function () {
// Do not enable on user .js/.css pages, as there's no sane way of "previewing"
// the scripts or styles without reloading the page.
if ( $( '#mw-userjsyoucanpreview' ).length || $( '#mw-usercssyoucanpreview' ).length ) {
return;
}
// The following elements can change in a preview but are not output
// by the server when they're empty until the preview reponse.
// TODO: Make the server output these always (in a hidden state), so we don't
// have to fish and (hopefully) put them in the right place (since skins
// can change where they are output).
if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) {
$( '#p-tb' ).after(
$( '
' ).prop( 'id', 'p-lang' )
);
}
if ( !$( '.mw-summary-preview' ).length ) {
$( '.editCheckboxes' ).before(
$( '
' ).prop( 'className', 'mw-summary-preview' )
);
}
if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
$( '#wikiPreview' ).after(
$( '
' ).prop( 'id', 'wikiDiff')
);
}
// Make sure diff styles are loaded
mw.loader.load( 'mediawiki.action.history.diff' );
$( document.body ).on( 'click', '#wpPreview, #wpDiff', doLivePreview );
} );
}( mediaWiki, jQuery ) );