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