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