Merge "Make $wgMWLoggerDefaultSpi more expressive"
[mediawiki.git] / resources / src / mediawiki.action / mediawiki.action.edit.preview.js
blob6b212c28de961817546e7e3fe955ca9a0bd2ddfb
1 /*!
2  * Live edit preview.
3  */
4 ( function ( mw, $ ) {
6         /**
7          * @ignore
8          * @param {jQuery.Event} e
9          */
10         function doLivePreview( e ) {
11                 var $wikiPreview, $editform, copySelectors, $copyElements, $spinner,
12                         targetUrl, postData, $previewDataHolder;
14                 e.preventDefault();
16                 // Deprecated: Use mw.hook instead
17                 $( mw ).trigger( 'LivePreviewPrepare' );
19                 $wikiPreview = $( '#wikiPreview' );
20                 $editform = $( '#editform' );
22                 // Show #wikiPreview if it's hidden to be able to scroll to it
23                 // (if it is hidden, it's also empty, so nothing changes in the rendering)
24                 $wikiPreview.show();
26                 // Jump to where the preview will appear
27                 $wikiPreview[0].scrollIntoView();
29                 // List of selectors matching elements that we will
30                 // update from from the ajax-loaded preview page.
31                 copySelectors = [
32                         // Main
33                         '#firstHeading',
34                         '#wikiPreview',
35                         '#wikiDiff',
36                         '#catlinks',
37                         '.hiddencats',
38                         '#p-lang',
39                         // Editing-related
40                         '.templatesUsed',
41                         '.limitreport',
42                         '.mw-summary-preview'
43                 ];
44                 $copyElements = $( copySelectors.join( ',' ) );
46                 // Not shown during normal preview, to be removed if present
47                 $( '.mw-newarticletext' ).remove();
49                 $spinner = $.createSpinner( {
50                         size: 'large',
51                         type: 'block'
52                 } );
53                 $wikiPreview.before( $spinner );
54                 $spinner.css( {
55                         marginTop: $spinner.height()
56                 } );
58                 // Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
59                 // (e.g. empty #catlinks)
60                 $copyElements.animate( { opacity: 0.4 }, 'fast' );
62                 $previewDataHolder = $( '<div>' );
63                 targetUrl = $editform.attr( 'action' );
64                 targetUrl += targetUrl.indexOf( '?' ) !== -1 ? '&' : '?';
65                 targetUrl += $.param( {
66                         debug: mw.config.get( 'debug' ),
67                         uselang: mw.config.get( 'wgUserLanguage' ),
68                         useskin: mw.config.get( 'skin' )
69                 } );
71                 // Gather all the data from the form
72                 postData = $editform.formToArray();
73                 postData.push( {
74                         name: e.target.name,
75                         value: ''
76                 } );
78                 // Load new preview data.
79                 // TODO: This should use the action=parse API instead of loading the entire page,
80                 // although that requires figuring out how to convert that raw data into proper HTML.
81                 $previewDataHolder.load( targetUrl + ' ' + copySelectors.join( ',' ), postData, function () {
82                         var i, $from, $next, $parent;
84                         // Copy the contents of the specified elements from the loaded page to the real page.
85                         // Also copy their class attributes.
86                         for ( i = 0; i < copySelectors.length; i++ ) {
87                                 $from = $previewDataHolder.find( copySelectors[i] );
89                                 if ( copySelectors[i] === '#wikiPreview' ) {
90                                         $next = $wikiPreview.next();
91                                         // If there is no next node, use parent instead.
92                                         // Only query parent if needed, false otherwise.
93                                         $parent = !$next.length && $wikiPreview.parent();
95                                         $wikiPreview
96                                                 .detach()
97                                                 .empty()
98                                                 .append( $from.contents() )
99                                                 .attr( 'class', $from.attr( 'class' ) );
101                                         mw.hook( 'wikipage.content' ).fire( $wikiPreview );
103                                         // Reattach
104                                         if ( $parent ) {
105                                                 $parent.append( $wikiPreview );
106                                         } else {
107                                                 $next.before( $wikiPreview );
108                                         }
110                                 } else {
111                                         $( copySelectors[i] )
112                                                 .empty()
113                                                 .append( $from.contents() )
114                                                 .attr( 'class', $from.attr( 'class' ) );
115                                 }
116                         }
118                         // Deprecated: Use mw.hook instead
119                         $( mw ).trigger( 'LivePreviewDone', [copySelectors] );
121                         $spinner.remove();
122                         $copyElements.animate( {
123                                 opacity: 1
124                         }, 'fast' );
125                 } );
126         }
128         $( function () {
129                 // Do not enable on user .js/.css pages, as there's no sane way of "previewing"
130                 // the scripts or styles without reloading the page.
131                 if ( $( '#mw-userjsyoucanpreview' ).length || $( '#mw-usercssyoucanpreview' ).length ) {
132                         return;
133                 }
135                 // The following elements can change in a preview but are not output
136                 // by the server when they're empty until the preview response.
137                 // TODO: Make the server output these always (in a hidden state), so we don't
138                 // have to fish and (hopefully) put them in the right place (since skins
139                 // can change where they are output).
141                 if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) {
142                         $( '#p-tb' ).after(
143                                 $( '<div>' ).attr( 'id', 'p-lang' )
144                         );
145                 }
147                 if ( !$( '.mw-summary-preview' ).length ) {
148                         $( '.editCheckboxes' ).before(
149                                 $( '<div>' ).addClass( 'mw-summary-preview' )
150                         );
151                 }
153                 if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
154                         $( '#wikiPreview' ).after(
155                                 $( '<div>' ).attr( 'id', 'wikiDiff' )
156                         );
157                 }
159                 // This should be moved down to '#editform', but is kept on the body for now
160                 // because the LiquidThreads extension is re-using this module with only half
161                 // the EditPage (doesn't include #editform presumably, bug 55463).
162                 $( document.body ).on( 'click', '#wpPreview, #wpDiff', doLivePreview );
163         } );
165 }( mediaWiki, jQuery ) );