Merge "SpecialPrefixindex: Try not to generate unclickable links"
[lhc/web/wiklou.git] / resources / 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, copySelectors, removeSelectors, $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
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();
23
24 // Jump to where the preview will appear
25 $wikiPreview[0].scrollIntoView();
26
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 '.limitreport',
39 '.mw-summary-preview'
40 ];
41 $copyElements = $( copySelectors.join( ',' ) );
42
43 // Not shown during normal preview, to be removed if present
44 removeSelectors = [
45 '.mw-newarticletext'
46 ];
47
48 $( removeSelectors.join( ',' ) ).remove();
49
50 $spinner = $.createSpinner( {
51 size: 'large',
52 type: 'block'
53 });
54 $wikiPreview.before( $spinner );
55 $spinner.css( {
56 position: 'absolute',
57 marginTop: $spinner.height()
58 } );
59 // Make sure preview area is at least as tall as 2x the height of the spinner.
60 // 1x because if its smaller, it will spin behind the edit toolbar.
61 // (this happens on the first preview when editPreview is still empty)
62 // 2x because the spinner has 1x margin top breathing room.
63 $wikiPreview.css( 'minHeight', $spinner.height() * 2 );
64
65 // Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
66 // (e.g. empty #catlinks)
67 $copyElements.animate( {
68 opacity: 0.4
69 }, 'fast' );
70
71 $previewDataHolder = $( '<div>' );
72 targetUrl = $( '#editform' ).attr( 'action' );
73
74 // Gather all the data from the form
75 postData = $( '#editform' ).formToArray();
76 postData.push( {
77 name: e.target.name,
78 value: ''
79 } );
80
81 // Load new preview data.
82 // TODO: This should use the action=parse API instead of loading the entire page,
83 // although that requires figuring out how to convert that raw data into proper HTML.
84 $previewDataHolder.load( targetUrl + ' ' + copySelectors.join( ',' ), postData, function () {
85 var i, $from;
86 // Copy the contents of the specified elements from the loaded page to the real page.
87 // Also copy their class attributes.
88 for ( i = 0; i < copySelectors.length; i++ ) {
89 $from = $previewDataHolder.find( copySelectors[i] );
90
91 $( copySelectors[i] )
92 .empty()
93 .append( $from.contents() )
94 .attr( 'class', $from.attr( 'class' ) );
95 }
96
97 // Deprecated: Use mw.hook instead
98 $( mw ).trigger( 'LivePreviewDone', [copySelectors] );
99
100 mw.hook( 'wikipage.content' ).fire( $wikiPreview );
101
102 $spinner.remove();
103 $copyElements.animate( {
104 opacity: 1
105 }, 'fast' );
106 } );
107 }
108
109 $( function () {
110 // Do not enable on user .js/.css pages, as there's no sane way of "previewing"
111 // the scripts or styles without reloading the page.
112 if ( $( '#mw-userjsyoucanpreview' ).length || $( '#mw-usercssyoucanpreview' ).length ) {
113 return;
114 }
115
116 // The following elements can change in a preview but are not output
117 // by the server when they're empty until the preview response.
118 // TODO: Make the server output these always (in a hidden state), so we don't
119 // have to fish and (hopefully) put them in the right place (since skins
120 // can change where they are output).
121
122 if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) {
123 $( '#p-tb' ).after(
124 $( '<div>' ).attr( 'id', 'p-lang' )
125 );
126 }
127
128 if ( !$( '.mw-summary-preview' ).length ) {
129 $( '.editCheckboxes' ).before(
130 $( '<div>' ).addClass( 'mw-summary-preview' )
131 );
132 }
133
134 if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
135 $( '#wikiPreview' ).after(
136 $( '<div>' ).attr( 'id', 'wikiDiff')
137 );
138 }
139
140 $( document.body ).on( 'click', '#wpPreview, #wpDiff', doLivePreview );
141 } );
142
143 }( mediaWiki, jQuery ) );