From 4d4bfc27a1bedf6b0d1670707ac812fe36fe85ad Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Mon, 17 Sep 2012 19:35:04 +0200 Subject: [PATCH] mediawiki.action.edit.preview: New module replacing preview.js With all the recent improvements, it's time this module got promoted away from legacy. Its no longer just an old script to that provides preview functionality and is minimally maintained within "legacy", its reborn! Minor clean up follows-up: * e75054174c944d8a78a2c2822abe2fe161f7d6ad * b12dc64a1198f6b094a5a60307412ff91f0bbf49 Change-Id: I85ca97a1d8df25a09baad78030d6da379a06c0f1 --- RELEASE-NOTES-1.20 | 3 + includes/EditPage.php | 2 +- resources/Resources.php | 16 +-- .../mediawiki.action.edit.preview.js | 135 ++++++++++++++++++ skins/common/preview.js | 106 -------------- 5 files changed, 146 insertions(+), 116 deletions(-) create mode 100644 resources/mediawiki.action/mediawiki.action.edit.preview.js delete mode 100644 skins/common/preview.js diff --git a/RELEASE-NOTES-1.20 b/RELEASE-NOTES-1.20 index b28cc70c10..5dc6718be7 100644 --- a/RELEASE-NOTES-1.20 +++ b/RELEASE-NOTES-1.20 @@ -320,6 +320,9 @@ changes to languages because of Bugzilla reports. * Use of __DIR__ instead of dirname( __FILE__ ). * OutputPage::wrapWikiMsg() no longer supports the 'options' parameter. It was not used and complicated migration to Message class. +* Live preview functionality has been improved and moved into the + 'mediawiki.action.edit.preview' module. The old 'mediawiki.legacy.preview' module + has been removed. == Compatibility == diff --git a/includes/EditPage.php b/includes/EditPage.php index 782b76388b..b762cad11b 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -1591,7 +1591,7 @@ class EditPage { $wgOut->addModules( 'mediawiki.action.edit' ); if ( $wgUser->getOption( 'uselivepreview', false ) ) { - $wgOut->addModules( 'mediawiki.legacy.preview' ); + $wgOut->addModules( 'mediawiki.action.edit.preview' ); } // Bug #19334: textarea jumps when editing articles in IE8 $wgOut->addStyle( 'common/IE80Fixes.css', 'screen', 'IE 8' ); diff --git a/resources/Resources.php b/resources/Resources.php index 3549eb8c74..0c52f16ac1 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -652,6 +652,13 @@ return array( ), 'position' => 'top', ), + 'mediawiki.action.edit.preview' => array( + 'scripts' => 'resources/mediawiki.action/mediawiki.action.edit.preview.js', + 'dependencies' => array( + 'jquery.form', + 'jquery.spinner', + ), + ), 'mediawiki.action.history' => array( 'scripts' => 'resources/mediawiki.action/mediawiki.action.history.js', 'group' => 'mediawiki.action.history', @@ -934,15 +941,6 @@ return array( 'dependencies' => 'mediawiki.legacy.wikibits', 'messages' => array( 'search-mwsuggest-enabled', 'search-mwsuggest-disabled' ), ), - 'mediawiki.legacy.preview' => array( - 'scripts' => 'common/preview.js', - 'remoteBasePath' => $GLOBALS['wgStylePath'], - 'localBasePath' => $GLOBALS['wgStyleDirectory'], - 'dependencies' => array( - 'mediawiki.legacy.wikibits', - 'jquery.form', - ) - ), 'mediawiki.legacy.protect' => array( 'scripts' => 'common/protect.js', 'remoteBasePath' => $GLOBALS['wgStylePath'], diff --git a/resources/mediawiki.action/mediawiki.action.edit.preview.js b/resources/mediawiki.action/mediawiki.action.edit.preview.js new file mode 100644 index 0000000000..cddf6ccf53 --- /dev/null +++ b/resources/mediawiki.action/mediawiki.action.edit.preview.js @@ -0,0 +1,135 @@ +/** + * 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 = $( '
' ); + 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 () { + // 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( + $( '
' ).prop( 'id', 'p-lang' ) + ); + } + + if ( !$( '.mw-summary-preview' ).length ) { + $( '.editCheckboxes' ).before( + $( '
' ).prop( 'className', 'mw-summary-preview' ) + ); + } + + if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) { + $( '#wikiPreview' ).after( + $( '
' ).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 ) ); diff --git a/skins/common/preview.js b/skins/common/preview.js deleted file mode 100644 index 5b5a3c643f..0000000000 --- a/skins/common/preview.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Live preview script for MediaWiki - */ -( function( mw, $ ) { - var doLivePreview = function( e ) { - e.preventDefault(); - - $( mw ).trigger( 'LivePreviewPrepare' ); - - var $wikiPreview = $( '#wikiPreview' ); - - // this needs to be checked before we unconditionally show the preview - var overlaySpinner = false; - if ( $wikiPreview.is( ':visible' ) || $( '.mw-newarticletext:visible' ).length > 0 ) { - overlaySpinner = true; - } - - // 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 elements that will be loaded from the preview page - // elements absent in the preview page (such as .mw-newarticletext) will be cleared using .empty() - var copySelectors = [ - '#wikiPreview', '#wikiDiff', '#catlinks', '.hiddencats', '#p-lang', // the meat - '.templatesUsed', '.mw-summary-preview', // editing-related - '.mw-newarticletext' // it is not shown during normal preview, and looks weird with throbber overlaid - ]; - var $copyElements = $( copySelectors.join( ',' ) ); - - var $loadSpinner = $( '
' ).addClass( 'mw-ajax-loader' ); - $loadSpinner.css( 'top', '0' ); // move away from header (default is -16px) - - // If the preview is already visible, overlay the spinner on top of it. - if ( overlaySpinner ) { - $( '#mw-content-text' ).css( 'position', 'relative' ); // FIXME this seems like a bad idea - - $loadSpinner.css( { - 'position': 'absolute', - 'z-index': '3', - 'left': '50%', - 'margin-left': '-16px' - } ); - } - - // fade out the elements and display the throbber - $( '#mw-content-text' ).prepend( $loadSpinner ); - // we 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' ); - - var $previewDataHolder = $( '
' ); - var target = $( '#editform' ).attr( 'action' ) || window.location.href; - - // gather all the data from the form - var postData = $( '#editform' ).formToArray(); // formToArray: from jquery.form - postData.push( { 'name' : e.target.name, 'value' : '1' } ); - - // load new preview data - // FIXME this should use the action=parse API instead of loading the entire page - $previewDataHolder.load( target + ' ' + copySelectors.join( ',' ), postData, function() { - // Copy the contents of the specified elements from the loaded page to the real page. - // Also copy their class attributes. - for ( var i = 0; i < copySelectors.length; i++ ) { - var $from = $previewDataHolder.find( copySelectors[i] ); - var $to = $( copySelectors[i] ); - - $to.empty().append( $from.contents() ); - $to.attr( 'class', $from.attr( 'class' ) ); - } - - $loadSpinner.remove(); - $copyElements.animate( { 'opacity': 1 }, 'fast' ); - - $( mw ).trigger( 'LivePreviewDone', [copySelectors] ); - } ); - }; - - $( document ).ready( function() { - // construct the elements we need if they are missing (usually when action=edit) - // we don't need to hide them, because they are empty when created - - // interwiki links - if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) { - $( '#p-tb' ).after( $( '
' ).attr( 'id', 'p-lang' ) ); - } - - // summary preview - if ( $( '.mw-summary-preview' ).length === 0 ) { - $( '.editCheckboxes' ).before( $( '
' ).addClass( 'mw-summary-preview' ) ); - } - - // diff - if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) { - $( '#wikiPreview' ).after( $( '
' ).attr( 'id', 'wikiDiff' ) ); - } - - // diff styles are usually only loaded during, well, diff, and we might need them - // (mw.loader takes care of stuff if they happen to be loaded already) - mw.loader.load( 'mediawiki.action.history.diff' ); - - $( document.body ).on( 'click', '#wpPreview, #wpDiff', doLivePreview ); - } ); -} )( mediaWiki, jQuery ); -- 2.20.1