Merge "Whitelist the <wbr> element."
[mediawiki.git] / resources / mediawiki.action / mediawiki.action.edit.preview.js
blob0566a87c66dbce5c4a4cd0d3fccada54c1cdc5b2
1 /**
2  * Live edit preview.
3  */
4 ( function ( mw, $ ) {
6         /**
7          * @param {jQuery.Event} e
8          */
9         function doLivePreview( e ) {
10                 var $wikiPreview, copySelectors, removeSelectors, $copyElements, $spinner,
11                         targetUrl, postData, $previewDataHolder;
13                 e.preventDefault();
15                 // Deprecated: Use mw.hook instead
16                 $( mw ).trigger( 'LivePreviewPrepare' );
18                 $wikiPreview = $( '#wikiPreview' );
20                 // Show #wikiPreview if it's hidden to be able to scroll to it
21                 // (if it is hidden, it's also empty, so nothing changes in the rendering)
22                 $wikiPreview.show();
24                 // Jump to where the preview will appear
25                 $wikiPreview[0].scrollIntoView();
27                 // List of selectors matching elements that we will
28                 // update from from the ajax-loaded preview page.
29                 copySelectors = [
30                         // Main
31                         '#wikiPreview',
32                         '#wikiDiff',
33                         '#catlinks',
34                         '.hiddencats',
35                         '#p-lang',
36                         // Editing-related
37                         '.templatesUsed',
38                         '.mw-summary-preview'
39                 ];
40                 $copyElements = $( copySelectors.join( ',' ) );
42                 // Not shown during normal preview, to be removed if present
43                 removeSelectors = [
44                         '.mw-newarticletext'
45                 ];
47                 $( removeSelectors.join( ',' ) ).remove();
49                 $spinner = $.createSpinner( {
50                         size: 'large',
51                         type: 'block'
52                 });
53                 $wikiPreview.before( $spinner );
54                 $spinner.css( {
55                         position: 'absolute',
56                         marginTop: $spinner.height()
57                 } );
58                 // Make sure preview area is at least as tall as 2x the height of the spinner.
59                 // 1x because if its smaller, it will spin behind the edit toolbar.
60                 // (this happens on the first preview when editPreview is still empty)
61                 // 2x because the spinner has 1x margin top breathing room.
62                 $wikiPreview.css( 'minHeight', $spinner.height() * 2 );
64                 // Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
65                 // (e.g. empty #catlinks)
66                 $copyElements.animate( {
67                         opacity: 0.4
68                 }, 'fast' );
70                 $previewDataHolder = $( '<div>' );
71                 targetUrl = $( '#editform' ).attr( 'action' );
73                 // Gather all the data from the form
74                 postData = $( '#editform' ).formToArray();
75                 postData.push( {
76                         name: e.target.name,
77                         value: ''
78                 } );
80                 // Load new preview data.
81                 // TODO: This should use the action=parse API instead of loading the entire page
82                 // Though that requires figuring out how to convert that raw data into proper HTML.
83                 $previewDataHolder.load( targetUrl + ' ' + copySelectors.join( ',' ), postData, function () {
84                         var i, $from;
85                         // Copy the contents of the specified elements from the loaded page to the real page.
86                         // Also copy their class attributes.
87                         for ( i = 0; i < copySelectors.length; i++ ) {
88                                 $from = $previewDataHolder.find( copySelectors[i] );
90                                 $( copySelectors[i] )
91                                         .empty()
92                                         .append( $from.contents() )
93                                         .attr( 'class', $from.attr( 'class' ) );
94                         }
96                         // Deprecated: Use mw.hook instead
97                         $( mw ).trigger( 'LivePreviewDone', [copySelectors] );
99                         mw.hook( 'wikipage.content' ).fire( $wikiPreview );
101                         $spinner.remove();
102                         $copyElements.animate( {
103                                 opacity: 1
104                         }, 'fast' );
105                 } );
106         }
108         $( function () {
109                 // Do not enable on user .js/.css pages, as there's no sane way of "previewing"
110                 // the scripts or styles without reloading the page.
111                 if ( $( '#mw-userjsyoucanpreview' ).length || $( '#mw-usercssyoucanpreview' ).length ) {
112                         return;
113                 }
115                 // The following elements can change in a preview but are not output
116                 // by the server when they're empty until the preview reponse.
117                 // TODO: Make the server output these always (in a hidden state), so we don't
118                 // have to fish and (hopefully) put them in the right place (since skins
119                 // can change where they are output).
121                 if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) {
122                         $( '#p-tb' ).after(
123                                 $( '<div>' ).prop( 'id', 'p-lang' )
124                         );
125                 }
127                 if ( !$( '.mw-summary-preview' ).length ) {
128                         $( '.editCheckboxes' ).before(
129                                 $( '<div>' ).prop( 'className', 'mw-summary-preview' )
130                         );
131                 }
133                 if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
134                         $( '#wikiPreview' ).after(
135                                 $( '<div>' ).prop( 'id', 'wikiDiff')
136                         );
137                 }
139                 // Make sure diff styles are loaded
140                 mw.loader.load( 'mediawiki.action.history.diff' );
142                 $( document.body ).on( 'click', '#wpPreview, #wpDiff', doLivePreview );
143         } );
145 }( mediaWiki, jQuery ) );