summaryrefslogtreecommitdiff
path: root/resources/mediawiki.action/mediawiki.action.edit.preview.js
blob: 602aadb0badb8bb65ea062770d98edff7b08a260 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
 * Live edit preview.
 */
( function ( mw, $ ) {

	/**
	 * @param {jQuery.Event} e
	 */
	function doLivePreview( e ) {
		var $wikiPreview, copySelectors, removeSelectors, $copyElements, $spinner,
			targetUrl, postData, $previewDataHolder;

		e.preventDefault();

		$( mw ).trigger( 'LivePreviewPrepare' );

		$wikiPreview = $( '#wikiPreview' );

		// Show #wikiPreview if it's hidden to be able to scroll to it
		// (if it is hidden, it's also empty, so nothing changes in the rendering)
		$wikiPreview.show();

		// Jump to where the preview will appear
		$wikiPreview[0].scrollIntoView();

		// List of selectors matching elements that we will
		// update from from the ajax-loaded preview page.
		copySelectors = [
			// Main
			'#wikiPreview',
			'#wikiDiff',
			'#catlinks',
			'.hiddencats',
			'#p-lang',
			// Editing-related
			'.templatesUsed',
			'.mw-summary-preview'
		];
		$copyElements = $( copySelectors.join( ',' ) );

		// Not shown during normal preview, to be removed if present
		removeSelectors = [
			'.mw-newarticletext'
		];

		$( removeSelectors.join( ',' ) ).remove();

		$spinner = $.createSpinner( {
			size: 'large',
			type: 'block'
		});
		$wikiPreview.before( $spinner );
		$spinner.css( {
			position: 'absolute',
			marginTop: $spinner.height()
		} );
		// Make sure preview area is at least as tall as 2x the height of the spinner.
		// 1x because if its smaller, it will spin behind the edit toolbar.
		// (this happens on the first preview when editPreview is still empty)
		// 2x because the spinner has 1x margin top breathing room.
		$wikiPreview.css( 'minHeight', $spinner.height() * 2 );

		// Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
		// (e.g. empty #catlinks)
		$copyElements.animate( {
			opacity: 0.4
		}, 'fast' );

		$previewDataHolder = $( '<div>' );
		targetUrl = $( '#editform' ).attr( 'action' );

		// Gather all the data from the form
		postData = $( '#editform' ).formToArray();
		postData.push( {
			name: e.target.name,
			value: ''
		} );

		// Load new preview data.
		// TODO: This should use the action=parse API instead of loading the entire page
		// Though that requires figuring out how to conver that raw data into proper HTML.
		$previewDataHolder.load( targetUrl + ' ' + copySelectors.join( ',' ), postData, function () {
			var i, $from;
			// Copy the contents of the specified elements from the loaded page to the real page.
			// Also copy their class attributes.
			for ( i = 0; i < copySelectors.length; i++ ) {
				$from = $previewDataHolder.find( copySelectors[i] );

				$( copySelectors[i] )
					.empty()
					.append( $from.contents() )
					.attr( 'class', $from.attr( 'class' ) );
			}

			$spinner.remove();
			$copyElements.animate( {
				opacity: 1
			}, 'fast' );

			$( mw ).trigger( 'LivePreviewDone', [copySelectors] );
		} );
	}

	$( document ).ready( function () {
		// Do not enable on user .js/.css pages, as there's no sane way of "previewing"
		// the scripts or styles without reloading the page.
		if ( $( '#mw-userjsyoucanpreview' ).length || $( '#mw-usercssyoucanpreview' ).length ) {
			return;
		}

		// The following elements can change in a preview but are not output
		// by the server when they're empty until the preview reponse.
		// TODO: Make the server output these always (in a hidden state), so we don't
		// have to fish and (hopefully) put them in the right place (since skins
		// can change where they are output).

		if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) {
			$( '#p-tb' ).after(
				$( '<div>' ).prop( 'id', 'p-lang' )
			);
		}

		if ( !$( '.mw-summary-preview' ).length ) {
			$( '.editCheckboxes' ).before(
				$( '<div>' ).prop( 'className', 'mw-summary-preview' )
			);
		}

		if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
			$( '#wikiPreview' ).after(
				$( '<div>' ).prop( 'id', 'wikiDiff')
			);
		}

		// Make sure diff styles are loaded
		mw.loader.load( 'mediawiki.action.history.diff' );

		$( document.body ).on( 'click', '#wpPreview, #wpDiff', doLivePreview );
	} );

}( mediaWiki, jQuery ) );