mediawiki.action.edit.preview: New module replacing preview.js
authorTimo Tijhof <ttijhof@wikimedia.org>
Mon, 17 Sep 2012 17:35:04 +0000 (19:35 +0200)
committerMatmaRex <matma.rex@gmail.com>
Fri, 21 Sep 2012 14:47:30 +0000 (16:47 +0200)
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
includes/EditPage.php
resources/Resources.php
resources/mediawiki.action/mediawiki.action.edit.preview.js [new file with mode: 0644]
skins/common/preview.js [deleted file]

index b28cc70..5dc6718 100644 (file)
@@ -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 ==
 
index 782b763..b762cad 100644 (file)
@@ -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' );
index 3549eb8..0c52f16 100644 (file)
@@ -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 (file)
index 0000000..cddf6cc
--- /dev/null
@@ -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 = $( '<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 () {
+               // 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 ) );
diff --git a/skins/common/preview.js b/skins/common/preview.js
deleted file mode 100644 (file)
index 5b5a3c6..0000000
+++ /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 = $( '<div>' ).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 = $( '<div>' );
-               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( $( '<div>' ).attr( 'id', 'p-lang' ) );
-               }
-
-               // summary preview
-               if ( $( '.mw-summary-preview' ).length === 0 ) {
-                       $( '.editCheckboxes' ).before( $( '<div>' ).addClass( 'mw-summary-preview' ) );
-               }
-
-               // diff
-               if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
-                       $( '#wikiPreview' ).after( $( '<div>' ).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 );