merged master
[lhc/web/wiklou.git] / includes / EditPage.php
index 8225d5a..94fda9e 100644 (file)
@@ -603,8 +603,8 @@ class EditPage {
                                wfProfileOut( get_class( $this ) . "::importContentFormData" );
                        }
 
-                       # Truncate for whole multibyte characters. +5 bytes for ellipsis
-                       $this->summary = $wgLang->truncate( $request->getText( 'wpSummary' ), 250 );
+                       # Truncate for whole multibyte characters
+                       $this->summary = $wgLang->truncate( $request->getText( 'wpSummary' ), 255 );
 
                        # If the summary consists of a heading, e.g. '==Foobar==', extract the title from the
                        # header syntax, e.g. 'Foobar'. This is mainly an issue when we are using wpSummary for
@@ -616,7 +616,7 @@ class EditPage {
                        # currently doing double duty as both edit summary and section title. Right now this
                        # is just to allow API edits to work around this limitation, but this should be
                        # incorporated into the actual edit form when EditPage is rewritten (Bugs 18654, 26312).
-                       $this->sectiontitle = $wgLang->truncate( $request->getText( 'wpSectionTitle' ), 250 );
+                       $this->sectiontitle = $wgLang->truncate( $request->getText( 'wpSectionTitle' ), 255 );
                        $this->sectiontitle = preg_replace( '/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->sectiontitle );
 
                        $this->edittime = $request->getVal( 'wpEdittime' );
@@ -691,7 +691,7 @@ class EditPage {
                } else {
                        # Not a posted form? Start with nothing.
                        wfDebug( __METHOD__ . ": Not a posted form.\n" );
-                       $this->textbox1     = ''; #FIXME: track content object
+                       $this->textbox1     = '';
                        $this->summary      = '';
                        $this->sectiontitle = '';
                        $this->edittime     = '';
@@ -778,7 +778,7 @@ class EditPage {
                } elseif ( $wgUser->getOption( 'watchcreations' ) && !$this->mTitle->exists() ) {
                        # Watch creations
                        $this->watchthis = true;
-               } elseif ( $this->mTitle->userIsWatching() ) {
+               } elseif ( $wgUser->isWatched( $this->mTitle ) ) {
                        # Already watched
                        $this->watchthis = true;
                }
@@ -799,8 +799,9 @@ class EditPage {
         * @return mixed string on success, $def_text for invalid sections
         * @private
         * @deprecated since 1.WD
+        * @todo: deprecated, replace usage everywhere
         */
-       function getContent( $def_text = false ) { #FIXME: deprecated, replace usage!
+       function getContent( $def_text = false ) {
                wfDeprecated( __METHOD__, '1.WD' );
 
                if ( $def_text !== null && $def_text !== false && $def_text !== '' ) {
@@ -811,10 +812,11 @@ class EditPage {
 
                $content = $this->getContentObject( $def_content );
 
-               return $content->serialize( $this->content_format ); #XXX: really use serialized form? use ContentHandler::getContentText() instead?
+               // Note: EditPage should only be used with text based content anyway.
+               return $content->serialize( $this->content_format );
        }
 
-       private function getContentObject( $def_content = null ) { #FIXME: use this!
+       private function getContentObject( $def_content = null ) {
                global $wgOut, $wgRequest;
 
                wfProfileIn( __METHOD__ );
@@ -880,11 +882,12 @@ class EditPage {
                                                        # If we just undid one rev, use an autosummary
                                                        $firstrev = $oldrev->getNext();
                                                        if ( $firstrev && $firstrev->getId() == $undo ) {
-                                                               $undoSummary = wfMsgForContent( 'undo-summary', $undo, $undorev->getUserText() );
+                                                               $undoSummary = wfMessage( 'undo-summary', $undo, $undorev->getUserText() )->inContentLanguage()->text();
                                                                if ( $this->summary === '' ) {
                                                                        $this->summary = $undoSummary;
                                                                } else {
-                                                                       $this->summary = $undoSummary . wfMsgForContent( 'colon-separator' ) . $this->summary;
+                                                                       $this->summary = $undoSummary . wfMessage( 'colon-separator' )
+                                                                               ->inContentLanguage()->text() . $this->summary;
                                                                }
                                                                $this->undidRev = $undo;
                                                        }
@@ -899,7 +902,7 @@ class EditPage {
 
                                        $class = ( $undoMsg == 'success' ? '' : 'error ' ) . "mw-undo-{$undoMsg}";
                                        $this->editFormPageTop .= $wgOut->parse( "<div class=\"{$class}\">" .
-                                               wfMsgNoTrans( 'undo-' . $undoMsg ) . '</div>', true, /* interface */true );
+                                               wfMessage( 'undo-' . $undoMsg )->plain() . '</div>', true, /* interface */true );
                                }
 
                                if ( $content === false ) {
@@ -921,7 +924,7 @@ class EditPage {
         *
         * This difers from Article::getContent() that when a missing revision is
         * encountered the result will be an empty string and not the
-        * 'missing-article' message.
+        * 'missing-revision' message.
         *
         * @since 1.19
         * @return string
@@ -959,7 +962,7 @@ class EditPage {
 
                        return $handler->makeEmptyContent();
                } else {
-                       #FIXME: nasty side-effect!
+                       # nasty side-effect, but needed for consistency
                        $this->content_model = $rev->getContentModel();
                        $this->content_format = $rev->getContentFormat();
 
@@ -1007,7 +1010,7 @@ class EditPage {
                wfDeprecated( __METHOD__, "1.WD" );
 
                $content = $this->getPreloadedContent( $preload );
-               $text = $content->serialize( $this->content_format ); #XXX: really use serialized form? use ContentHandler::getContentText() instead?!
+               $text = $content->serialize( $this->content_format );
 
                return $text;
        }
@@ -1104,8 +1107,7 @@ class EditPage {
 
                        case self::AS_PARSE_ERROR:
                                $wgOut->addWikiText( '<div class="error">' . $status->getWikiText() . '</div>');
-                               #FIXME: cause editform to be shown again, not just an error!
-                               return false;
+                               return true;
 
                        case self::AS_SUCCESS_NEW_ARTICLE:
                                $query = $resultDetails['redirect'] ? 'redirect=no' : '';
@@ -1199,9 +1201,20 @@ class EditPage {
                        return $status;
                }
 
+               try {
+                       # Construct Content object
+                       $textbox_content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(),
+                                                                                                                       $this->content_model, $this->content_format );
+               } catch (MWContentSerializationException $ex) {
+                       $status->fatal( 'content-failed-to-parse', $this->content_model, $this->content_format, $ex->getMessage() );
+                       $status->value = self::AS_PARSE_ERROR;
+                       wfProfileOut( __METHOD__ );
+                       return $status;
+               }
+
                # Check image redirect
                if ( $this->mTitle->getNamespace() == NS_FILE &&
-                       Title::newFromRedirect( $this->textbox1 ) instanceof Title && #FIXME: use content handler to check for redirect
+                       $textbox_content->isRedirect() &&
                        !$wgUser->isAllowed( 'upload' ) ) {
                                $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
                                $status->setResult( false, $code );
@@ -1306,286 +1319,285 @@ class EditPage {
 
                wfProfileOut( __METHOD__ . '-checks' );
 
-               // Use SELECT FOR UPDATE here to avoid transaction collision in
-               // WikiPage::updateRevisionOn() and ending in the self::AS_END case.
-               $this->mArticle->loadPageData( 'forupdate' );
+               # Load the page data from the master. If anything changes in the meantime,
+               # we detect it by using page_latest like a token in a 1 try compare-and-swap.
+               $this->mArticle->loadPageData( 'fromdbmaster' );
                $new = !$this->mArticle->exists();
 
-               try {
-                       if ( $new ) {
-                               // Late check for create permission, just in case *PARANOIA*
-                               if ( !$this->mTitle->userCan( 'create' ) ) {
-                                       $status->fatal( 'nocreatetext' );
-                                       $status->value = self::AS_NO_CREATE_PERMISSION;
-                                       wfDebug( __METHOD__ . ": no create permission\n" );
-                                       wfProfileOut( __METHOD__ );
-                                       return $status;
-                               }
+               if ( $new ) {
+                       // Late check for create permission, just in case *PARANOIA*
+                       if ( !$this->mTitle->userCan( 'create' ) ) {
+                               $status->fatal( 'nocreatetext' );
+                               $status->value = self::AS_NO_CREATE_PERMISSION;
+                               wfDebug( __METHOD__ . ": no create permission\n" );
+                               wfProfileOut( __METHOD__ );
+                               return $status;
+                       }
 
-                               # Don't save a new article if it's blank.
-                               if ( $this->textbox1 == '' ) {
-                                       $status->setResult( false, self::AS_BLANK_ARTICLE );
-                                       wfProfileOut( __METHOD__ );
-                                       return $status;
-                               }
+                       # Don't save a new article if it's blank.
+                       if ( $this->textbox1 == '' ) {
+                               $status->setResult( false, self::AS_BLANK_ARTICLE );
+                               wfProfileOut( __METHOD__ );
+                               return $status;
+                       }
 
-                               // Run post-section-merge edit filter
-                               if ( !wfRunHooks( 'EditFilterMerged', array( $this, $this->textbox1, &$this->hookError, $this->summary ) ) ) {
-                                       # Error messages etc. could be handled within the hook...
-                                       $status->fatal( 'hookaborted' );
-                                       $status->value = self::AS_HOOK_ERROR;
-                                       wfProfileOut( __METHOD__ );
-                                       return $status;
-                               } elseif ( $this->hookError != '' ) {
-                                       # ...or the hook could be expecting us to produce an error
-                                       $status->fatal( 'hookaborted' );
-                                       $status->value = self::AS_HOOK_ERROR_EXPECTED;
-                                       wfProfileOut( __METHOD__ );
-                                       return $status;
-                               }
+                       // Run post-section-merge edit filter
+                       if ( !wfRunHooks( 'EditFilterMerged', array( $this, $this->textbox1, &$this->hookError, $this->summary ) ) ) {
+                               # Error messages etc. could be handled within the hook...
+                               $status->fatal( 'hookaborted' );
+                               $status->value = self::AS_HOOK_ERROR;
+                               wfProfileOut( __METHOD__ );
+                               return $status;
+                       } elseif ( $this->hookError != '' ) {
+                               # ...or the hook could be expecting us to produce an error
+                               $status->fatal( 'hookaborted' );
+                               $status->value = self::AS_HOOK_ERROR_EXPECTED;
+                               wfProfileOut( __METHOD__ );
+                               return $status;
+                       }
 
-                               $content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format );
+                       $content = $textbox_content;
 
-                               $result['sectionanchor'] = '';
-                               if ( $this->section == 'new' ) {
-                                       if ( $this->sectiontitle !== '' ) {
-                                               // Insert the section title above the content.
-                                               $content = $content->addSectionHeader( $this->sectiontitle );
-
-                                               // Jump to the new section
-                                               $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
-
-                                               // If no edit summary was specified, create one automatically from the section
-                                               // title and have it link to the new section. Otherwise, respect the summary as
-                                               // passed.
-                                               if ( $this->summary === '' ) {
-                                                       $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
-                                                       $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle );
-                                               }
-                                       } elseif ( $this->summary !== '' ) {
-                                               // Insert the section title above the content.
-                                               $content = $content->addSectionHeader( $this->sectiontitle );
+                       $result['sectionanchor'] = '';
+                       if ( $this->section == 'new' ) {
+                               if ( $this->sectiontitle !== '' ) {
+                                       // Insert the section title above the content.
+                                       $content = $content->addSectionHeader( $this->sectiontitle );
+
+                                       // Jump to the new section
+                                       $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
+
+                                       // If no edit summary was specified, create one automatically from the section
+                                       // title and have it link to the new section. Otherwise, respect the summary as
+                                       // passed.
+                                       if ( $this->summary === '' ) {
+                                               $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
+                                               $this->summary = wfMessage( 'newsectionsummary', $cleanSectionTitle )
+                                                       ->inContentLanguage()->text() ;
+                                       }
+                               } elseif ( $this->summary !== '' ) {
+                                       // Insert the section title above the content.
+                                       $content = $content->addSectionHeader( $this->sectiontitle );
 
-                                               // Jump to the new section
-                                               $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
+                                       // Jump to the new section
+                                       $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
 
-                                               // Create a link to the new section from the edit summary.
-                                               $cleanSummary = $wgParser->stripSectionName( $this->summary );
-                                               $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary );
-                                       }
+                                       // Create a link to the new section from the edit summary.
+                                       $cleanSummary = $wgParser->stripSectionName( $this->summary );
+                                       $this->summary = wfMessage( 'newsectionsummary', $cleanSummary )->inContentLanguage()->text() ;
                                }
+                       }
 
-                               $status->value = self::AS_SUCCESS_NEW_ARTICLE;
+                       $status->value = self::AS_SUCCESS_NEW_ARTICLE;
 
-                       } else { # not $new
+               } else { # not $new
 
-                               # Article exists. Check for edit conflict.
+                       # Article exists. Check for edit conflict.
 
-                               $this->mArticle->clear(); # Force reload of dates, etc.
-                               $timestamp = $this->mArticle->getTimestamp();
+                       $this->mArticle->clear(); # Force reload of dates, etc.
+                       $timestamp = $this->mArticle->getTimestamp();
 
-                               wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}\n" );
+                       wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}\n" );
 
-                               if ( $timestamp != $this->edittime ) {
-                                       $this->isConflict = true;
-                                       if ( $this->section == 'new' ) {
-                                               if ( $this->mArticle->getUserText() == $wgUser->getName() &&
-                                                       $this->mArticle->getComment() == $this->summary ) {
-                                                       // Probably a duplicate submission of a new comment.
-                                                       // This can happen when squid resends a request after
-                                                       // a timeout but the first one actually went through.
-                                                       wfDebug( __METHOD__ . ": duplicate new section submission; trigger edit conflict!\n" );
-                                               } else {
-                                                       // New comment; suppress conflict.
-                                                       $this->isConflict = false;
-                                                       wfDebug( __METHOD__ . ": conflict suppressed; new section\n" );
-                                               }
-                                       } elseif ( $this->section == '' && $this->userWasLastToEdit( $wgUser->getId(), $this->edittime ) ) {
-                                               # Suppress edit conflict with self, except for section edits where merging is required.
-                                               wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" );
+                       if ( $timestamp != $this->edittime ) {
+                               $this->isConflict = true;
+                               if ( $this->section == 'new' ) {
+                                       if ( $this->mArticle->getUserText() == $wgUser->getName() &&
+                                               $this->mArticle->getComment() == $this->summary ) {
+                                               // Probably a duplicate submission of a new comment.
+                                               // This can happen when squid resends a request after
+                                               // a timeout but the first one actually went through.
+                                               wfDebug( __METHOD__ . ": duplicate new section submission; trigger edit conflict!\n" );
+                                       } else {
+                                               // New comment; suppress conflict.
                                                $this->isConflict = false;
+                                               wfDebug( __METHOD__ . ": conflict suppressed; new section\n" );
                                        }
+                               } elseif ( $this->section == '' && $this->userWasLastToEdit( $wgUser->getId(), $this->edittime ) ) {
+                                       # Suppress edit conflict with self, except for section edits where merging is required.
+                                       wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" );
+                                       $this->isConflict = false;
                                }
+                       }
 
-                               // If sectiontitle is set, use it, otherwise use the summary as the section title (for
-                               // backwards compatibility with old forms/bots).
-                               if ( $this->sectiontitle !== '' ) {
-                                       $sectionTitle = $this->sectiontitle;
-                               } else {
-                                       $sectionTitle = $this->summary;
-                               }
+                       // If sectiontitle is set, use it, otherwise use the summary as the section title (for
+                       // backwards compatibility with old forms/bots).
+                       if ( $this->sectiontitle !== '' ) {
+                               $sectionTitle = $this->sectiontitle;
+                       } else {
+                               $sectionTitle = $this->summary;
+                       }
+
+                       $content = null;
 
-                               $textbox_content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format );
-                               $content = null;
+                       if ( $this->isConflict ) {
+                               wfDebug( __METHOD__ . ": conflict! getting section '{$this->section}' for time '{$this->edittime}'"
+                                               . " (article time '{$timestamp}')\n" );
 
-                               if ( $this->isConflict ) {
-                                       wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" );
-                                       $content = $this->mArticle->replaceSectionContent( $this->section, $textbox_content, $sectionTitle, $this->edittime );
+                               $content = $this->mArticle->replaceSectionContent( $this->section, $textbox_content,
+                                                                                                                                       $sectionTitle, $this->edittime );
+                       } else {
+                               wfDebug( __METHOD__ . ": getting section '{$this->section}'\n" );
+                               $content = $this->mArticle->replaceSectionContent( $this->section, $textbox_content, $sectionTitle );
+                       }
+
+                       if ( is_null( $content ) ) {
+                               wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" );
+                               $this->isConflict = true;
+                               $content = $textbox_content; // do not try to merge here!
+                       } elseif ( $this->isConflict ) {
+                               # Attempt merge
+                               if ( $this->mergeChangesIntoContent( $textbox_content ) ) {
+                                       // Successful merge! Maybe we should tell the user the good news?
+                                       $this->isConflict = false;
+                                       $content = $textbox_content;
+                                       wfDebug( __METHOD__ . ": Suppressing edit conflict, successful merge.\n" );
                                } else {
-                                       wfDebug( __METHOD__ . ": getting section '$this->section'\n" );
-                                       $content = $this->mArticle->replaceSectionContent( $this->section, $textbox_content, $sectionTitle );
+                                       $this->section = '';
+                                       #$this->textbox1 = $text; #redundant, nothing to do here?
+                                       wfDebug( __METHOD__ . ": Keeping edit conflict, failed merge.\n" );
                                }
+                       }
 
-                               if ( is_null( $content ) ) {
-                                       wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" );
-                                       $this->isConflict = true;
-                                       $content = $textbox_content; // do not try to merge here!
-                               } elseif ( $this->isConflict ) {
-                                       # Attempt merge
-                                       if ( $this->mergeChangesIntoContent( $textbox_content ) ) {
-                                               // Successful merge! Maybe we should tell the user the good news?
-                                               $this->isConflict = false;
-                                               $content = $textbox_content;
-                                               wfDebug( __METHOD__ . ": Suppressing edit conflict, successful merge.\n" );
-                                       } else {
-                                               $this->section = '';
-                                               #$this->textbox1 = $text; #redundant, nothing to do here?
-                                               wfDebug( __METHOD__ . ": Keeping edit conflict, failed merge.\n" );
-                                       }
-                               }
+                       if ( $this->isConflict ) {
+                               $status->setResult( false, self::AS_CONFLICT_DETECTED );
+                               wfProfileOut( __METHOD__ );
+                               return $status;
+                       }
+
+                       // Run post-section-merge edit filter
+                       $hook_args = array( $this, $content, &$this->hookError, $this->summary );
 
-                               if ( $this->isConflict ) {
-                                       $status->setResult( false, self::AS_CONFLICT_DETECTED );
+                       if ( !ContentHandler::runLegacyHooks( 'EditFilterMerged', $hook_args )
+                               || !wfRunHooks( 'EditFilterMergedContent', $hook_args ) ) {
+                               # Error messages etc. could be handled within the hook...
+                               $status->fatal( 'hookaborted' );
+                               $status->value = self::AS_HOOK_ERROR;
+                               wfProfileOut( __METHOD__ );
+                               return $status;
+                       } elseif ( $this->hookError != '' ) {
+                               # ...or the hook could be expecting us to produce an error
+                               $status->fatal( 'hookaborted' );
+                               $status->value = self::AS_HOOK_ERROR_EXPECTED;
+                               wfProfileOut( __METHOD__ );
+                               return $status;
+                       }
+
+                       # Handle the user preference to force summaries here, but not for null edits
+                       if ( $this->section != 'new' && !$this->allowBlankSummary
+                               && !$content->equals( $this->getOriginalContent() )
+                               && !$content->isRedirect() ) # check if it's not a redirect
+                       {
+                               if ( md5( $this->summary ) == $this->autoSumm ) {
+                                       $this->missingSummary = true;
+                                       $status->fatal( 'missingsummary' );
+                                       $status->value = self::AS_SUMMARY_NEEDED;
                                        wfProfileOut( __METHOD__ );
                                        return $status;
                                }
+                       }
 
-                               // Run post-section-merge edit filter
-                               if ( !wfRunHooks( 'EditFilterMerged', array( $this, $content->serialize( $this->content_format ), &$this->hookError, $this->summary ) )
-                                               || !wfRunHooks( 'EditFilterMergedContent', array( $this, $content, &$this->hookError, $this->summary ) ) ) {
-                                       # Error messages etc. could be handled within the hook...
-                                       $status->fatal( 'hookaborted' );
-                                       $status->value = self::AS_HOOK_ERROR;
+                       # And a similar thing for new sections
+                       if ( $this->section == 'new' && !$this->allowBlankSummary ) {
+                               if ( trim( $this->summary ) == '' ) {
+                                       $this->missingSummary = true;
+                                       $status->fatal( 'missingsummary' ); // or 'missingcommentheader' if $section == 'new'. Blegh
+                                       $status->value = self::AS_SUMMARY_NEEDED;
                                        wfProfileOut( __METHOD__ );
                                        return $status;
-                               } elseif ( $this->hookError != '' ) {
-                                       # ...or the hook could be expecting us to produce an error
-                                       $status->fatal( 'hookaborted' );
-                                       $status->value = self::AS_HOOK_ERROR_EXPECTED;
+                               }
+                       }
+
+                       # All's well
+                       wfProfileIn( __METHOD__ . '-sectionanchor' );
+                       $sectionanchor = '';
+                       if ( $this->section == 'new' ) {
+                               if ( $this->textbox1 == '' ) {
+                                       $this->missingComment = true;
+                                       $status->fatal( 'missingcommenttext' );
+                                       $status->value = self::AS_TEXTBOX_EMPTY;
+                                       wfProfileOut( __METHOD__ . '-sectionanchor' );
                                        wfProfileOut( __METHOD__ );
                                        return $status;
                                }
-
-                               $content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format );
-
-                               # Handle the user preference to force summaries here, but not for null edits
-                               if ( $this->section != 'new' && !$this->allowBlankSummary
-                                       && !$content->equals( $this->getOriginalContent() )
-                                       && !$content->isRedirect() ) # check if it's not a redirect
-                               {
-                                       if ( md5( $this->summary ) == $this->autoSumm ) {
-                                               $this->missingSummary = true;
-                                               $status->fatal( 'missingsummary' );
-                                               $status->value = self::AS_SUMMARY_NEEDED;
-                                               wfProfileOut( __METHOD__ );
-                                               return $status;
+                               if ( $this->sectiontitle !== '' ) {
+                                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
+                                       // If no edit summary was specified, create one automatically from the section
+                                       // title and have it link to the new section. Otherwise, respect the summary as
+                                       // passed.
+                                       if ( $this->summary === '' ) {
+                                               $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
+                                               $this->summary = wfMessage( 'newsectionsummary', $cleanSectionTitle )
+                                                       ->inContentLanguage()->text();
                                        }
+                               } elseif ( $this->summary !== '' ) {
+                                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
+                                       # This is a new section, so create a link to the new section
+                                       # in the revision summary.
+                                       $cleanSummary = $wgParser->stripSectionName( $this->summary );
+                                       $this->summary = wfMessage( 'newsectionsummary', $cleanSummary )
+                                               ->inContentLanguage()->text();
                                }
-
-                               # And a similar thing for new sections
-                               if ( $this->section == 'new' && !$this->allowBlankSummary ) {
-                                       if ( trim( $this->summary ) == '' ) {
-                                               $this->missingSummary = true;
-                                               $status->fatal( 'missingsummary' ); // or 'missingcommentheader' if $section == 'new'. Blegh
-                                               $status->value = self::AS_SUMMARY_NEEDED;
-                                               wfProfileOut( __METHOD__ );
-                                               return $status;
-                                       }
+                       } elseif ( $this->section != '' ) {
+                               # Try to get a section anchor from the section source, redirect to edited section if header found
+                               # XXX: might be better to integrate this into Article::replaceSection
+                               # for duplicate heading checking and maybe parsing
+                               $hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches );
+                               # we can't deal with anchors, includes, html etc in the header for now,
+                               # headline would need to be parsed to improve this
+                               if ( $hasmatch && strlen( $matches[2] ) > 0 ) {
+                                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $matches[2] );
                                }
+                       }
+                       $result['sectionanchor'] = $sectionanchor;
+                       wfProfileOut( __METHOD__ . '-sectionanchor' );
 
-                               # All's well
-                               wfProfileIn( __METHOD__ . '-sectionanchor' );
-                               $sectionanchor = '';
-                               if ( $this->section == 'new' ) {
-                                       if ( $this->textbox1 == '' ) {
-                                               $this->missingComment = true;
-                                               $status->fatal( 'missingcommenttext' );
-                                               $status->value = self::AS_TEXTBOX_EMPTY;
-                                               wfProfileOut( __METHOD__ . '-sectionanchor' );
-                                               wfProfileOut( __METHOD__ );
-                                               return $status;
-                                       }
-                                       if ( $this->sectiontitle !== '' ) {
-                                               $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
-                                               // If no edit summary was specified, create one automatically from the section
-                                               // title and have it link to the new section. Otherwise, respect the summary as
-                                               // passed.
-                                               if ( $this->summary === '' ) {
-                                                       $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
-                                                       $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle );
-                                               }
-                                       } elseif ( $this->summary !== '' ) {
-                                               $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
-                                               # This is a new section, so create a link to the new section
-                                               # in the revision summary.
-                                               $cleanSummary = $wgParser->stripSectionName( $this->summary );
-                                               $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary );
-                                       }
-                               } elseif ( $this->section != '' ) {
-                                       # Try to get a section anchor from the section source, redirect to edited section if header found
-                                       # XXX: might be better to integrate this into Article::replaceSection
-                                       # for duplicate heading checking and maybe parsing
-                                       $hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches );
-                                       # we can't deal with anchors, includes, html etc in the header for now,
-                                       # headline would need to be parsed to improve this
-                                       if ( $hasmatch && strlen( $matches[2] ) > 0 ) {
-                                               $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $matches[2] );
-                                       }
-                               }
-                               $result['sectionanchor'] = $sectionanchor;
-                               wfProfileOut( __METHOD__ . '-sectionanchor' );
-
-                               // Save errors may fall down to the edit form, but we've now
-                               // merged the section into full text. Clear the section field
-                               // so that later submission of conflict forms won't try to
-                               // replace that into a duplicated mess.
-                                       $this->textbox1 = $content->serialize( $this->content_format );
-                               $this->section = '';
+                       // Save errors may fall down to the edit form, but we've now
+                       // merged the section into full text. Clear the section field
+                       // so that later submission of conflict forms won't try to
+                       // replace that into a duplicated mess.
+                       $this->textbox1 = $content->serialize( $this->content_format );
+                       $this->section = '';
 
-                               $status->value = self::AS_SUCCESS_UPDATE;
-                       }
+                       $status->value = self::AS_SUCCESS_UPDATE;
+               }
 
-                       // Check for length errors again now that the section is merged in
-                               $this->kblength = (int)( strlen( $content->serialize( $this->content_format ) ) / 1024 );
-                       if ( $this->kblength > $wgMaxArticleSize ) {
-                               $this->tooBig = true;
-                               $status->setResult( false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED );
-                               wfProfileOut( __METHOD__ );
-                               return $status;
-                       }
+               // Check for length errors again now that the section is merged in
+                       $this->kblength = (int)( strlen( $content->serialize( $this->content_format ) ) / 1024 );
+               if ( $this->kblength > $wgMaxArticleSize ) {
+                       $this->tooBig = true;
+                       $status->setResult( false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED );
+                       wfProfileOut( __METHOD__ );
+                       return $status;
+               }
 
-                       $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY |
-                               ( $new ? EDIT_NEW : EDIT_UPDATE ) |
-                               ( ( $this->minoredit && !$this->isNew ) ? EDIT_MINOR : 0 ) |
-                               ( $bot ? EDIT_FORCE_BOT : 0 );
+               $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY |
+                       ( $new ? EDIT_NEW : EDIT_UPDATE ) |
+                       ( ( $this->minoredit && !$this->isNew ) ? EDIT_MINOR : 0 ) |
+                       ( $bot ? EDIT_FORCE_BOT : 0 );
 
-                               $doEditStatus = $this->mArticle->doEditContent( $content, $this->summary, $flags, false, null, $this->content_format );
+                       $doEditStatus = $this->mArticle->doEditContent( $content, $this->summary, $flags,
+                                                                                                                       false, null, $this->content_format );
 
-                       if ( $doEditStatus->isOK() ) {
-                                       $result['redirect'] = $content->isRedirect();
-                               $this->commitWatch();
-                               wfProfileOut( __METHOD__ );
-                               return $status;
-                       } else {
-                               // Failure from doEdit()
-                               // Show the edit conflict page for certain recognized errors from doEdit(),
-                               // but don't show it for errors from extension hooks
-                               $errors = $doEditStatus->getErrorsArray();
-                               if ( in_array( $errors[0][0], array( 'edit-gone-missing', 'edit-conflict',
-                                       'edit-already-exists' ) ) )
-                               {
-                                       $this->isConflict = true;
-                                       // Destroys data doEdit() put in $status->value but who cares
-                                       $doEditStatus->value = self::AS_END;
-                               }
-                               wfProfileOut( __METHOD__ );
-                               return $doEditStatus;
-                       }
-               } catch (MWContentSerializationException $ex) {
-                       $status->fatal( 'content-failed-to-parse', $this->content_model, $this->content_format, $ex->getMessage() );
-                       $status->value = self::AS_PARSE_ERROR;
+               if ( $doEditStatus->isOK() ) {
+                               $result['redirect'] = $content->isRedirect();
+                       $this->commitWatch();
                        wfProfileOut( __METHOD__ );
                        return $status;
+               } else {
+                       // Failure from doEdit()
+                       // Show the edit conflict page for certain recognized errors from doEdit(),
+                       // but don't show it for errors from extension hooks
+                       $errors = $doEditStatus->getErrorsArray();
+                       if ( in_array( $errors[0][0], array( 'edit-gone-missing', 'edit-conflict',
+                               'edit-already-exists' ) ) )
+                       {
+                               $this->isConflict = true;
+                               // Destroys data doEdit() put in $status->value but who cares
+                               $doEditStatus->value = self::AS_END;
+                       }
+                       wfProfileOut( __METHOD__ );
+                       return $doEditStatus;
                }
        }
 
@@ -1594,7 +1606,7 @@ class EditPage {
         */
        protected function commitWatch() {
                global $wgUser;
-               if ( $this->watchthis xor $this->mTitle->userIsWatching() ) {
+               if ( $wgUser->isLoggedIn() && $this->watchthis != $wgUser->isWatched( $this->mTitle ) ) {
                        $dbw = wfGetDB( DB_MASTER );
                        $dbw->begin( __METHOD__ );
                        if ( $this->watchthis ) {
@@ -1639,7 +1651,7 @@ class EditPage {
         * @private
         * @todo document
         *
-        * @parma $editText string
+        * @param $editText string
         *
         * @return bool
         * @deprecated since 1.WD, use mergeChangesIntoContent() instead
@@ -1647,12 +1659,13 @@ class EditPage {
        function mergeChangesInto( &$editText ){
                wfDebug( __METHOD__, "1.WD" );
 
-               $editContent = ContentHandler::makeContent( $editText, $this->getTitle(), $this->content_model, $this->content_format );
+               $editContent = ContentHandler::makeContent( $editText, $this->getTitle(),
+                                                                                                       $this->content_model, $this->content_format );
 
                $ok = $this->mergeChangesIntoContent( $editContent );
 
                if ( $ok ) {
-                       $editText = $editContent->serialize( $this->content_format ); #XXX: really serialize?!
+                       $editText = $editContent->serialize( $this->content_format );
                        return true;
                } else {
                        return false;
@@ -1734,7 +1747,7 @@ class EditPage {
        /**
         * Check given input text against $wgSpamRegex, and return the text of the first match.
         *
-        * @parma $text string
+        * @param $text string
         *
         * @return string|bool  matching string or false
         */
@@ -1941,7 +1954,8 @@ class EditPage {
                        }
                }
 
-               #FIXME: add EditForm plugin interface and use it here! #FIXME: search for textarea1 and textares2, and allow EditForm to override all uses.
+               //@todo: add EditForm plugin interface and use it here!
+               //       search for textarea1 and textares2, and allow EditForm to override all uses.
                $wgOut->addHTML( Html::openElement( 'form', array( 'id' => self::EDITFORM_ID, 'name' => self::EDITFORM_ID,
                        'method' => 'post', 'action' => $this->getActionURL( $this->getContextTitle() ),
                        'enctype' => 'multipart/form-data' ) ) );
@@ -1966,8 +1980,8 @@ class EditPage {
                                : 'confirmrecreate';
                        $wgOut->addHTML(
                                '<div class="mw-confirm-recreate">' .
-                               wfMsgExt( $key, 'parseinline', $username, "<nowiki>$comment</nowiki>" ) .
-                               Xml::checkLabel( wfMsg( 'recreate' ), 'wpRecreate', 'wpRecreate', false,
+                                       wfMessage( $key, $username, "<nowiki>$comment</nowiki>" )->parse() .
+                               Xml::checkLabel( wfMessage( 'recreate' )->text(), 'wpRecreate', 'wpRecreate', false,
                                        array( 'title' => Linker::titleAttrib( 'recreate' ), 'tabindex' => 1, 'id' => 'wpRecreate' )
                                ) .
                                '</div>'
@@ -1990,6 +2004,10 @@ class EditPage {
                        $wgOut->addHTML( Html::hidden( 'wpIgnoreBlankSummary', true ) );
                }
 
+               if ( $this->undidRev ) {
+                       $wgOut->addHTML( Html::hidden( 'wpUndidRevision', $this->undidRev ) );
+               }
+
                if ( $this->hasPresetSummary ) {
                        // If a summary has been preset using &summary= we dont want to prompt for
                        // a different summary. Only prompt for a summary if the summary is blanked.
@@ -2054,7 +2072,13 @@ class EditPage {
                        Linker::formatHiddenCategories( $this->mArticle->getHiddenCategories() ) ) );
 
                if ( $this->isConflict ) {
-                       $this->showConflict();
+                       try {
+                               $this->showConflict();
+                       } catch ( MWContentSerializationException $ex ) {
+                               // this can't really happen, but be nice if it does.
+                               $msg = wfMessage( 'content-failed-to-parse', $this->content_model, $this->content_format, $ex->getMessage() );
+                               $wgOut->addWikiText( '<div class="error">' . $msg->text() . '</div>');
+                       }
                }
 
                $wgOut->addHTML( $this->editFormTextBottom . "\n</form>\n" );
@@ -2128,7 +2152,7 @@ class EditPage {
 
                        if ( $this->section != '' && $this->section != 'new' ) {
                                if ( !$this->summary && !$this->preview && !$this->diff ) {
-                                       $sectionTitle = self::extractSectionTitle( $this->textbox1 );
+                                       $sectionTitle = self::extractSectionTitle( $this->textbox1 ); //FIXME: use Content object
                                        if ( $sectionTitle !== false ) {
                                                $this->summary = "/* $sectionTitle */ ";
                                        }
@@ -2174,8 +2198,7 @@ class EditPage {
                                        // Something went wrong
 
                                        $wgOut->wrapWikiMsg( "<div class='errorbox'>\n$1\n</div>\n",
-                                               array( 'missing-article', $this->mTitle->getPrefixedText(),
-                                               wfMsgNoTrans( 'missingarticle-rev', $this->oldid ) ) );
+                                               array( 'missing-revision', $this->oldid ) );
                                }
                        }
                }
@@ -2267,7 +2290,7 @@ class EditPage {
         * @return array An array in the format array( $label, $input )
         */
        function getSummaryInput( $summary = "", $labelText = null, $inputAttrs = null, $spanLabelAttrs = null ) {
-               // Note: the maxlength is overriden in JS to 250 and to make it use UTF-8 bytes, not characters.
+               // Note: the maxlength is overriden in JS to 255 and to make it use UTF-8 bytes, not characters.
                $inputAttrs = ( is_array( $inputAttrs ) ? $inputAttrs : array() ) + array(
                        'id' => 'wpSummary',
                        'maxlength' => '200',
@@ -2313,7 +2336,7 @@ class EditPage {
                        }
                }
                $summary = $wgContLang->recodeForEdit( $summary );
-               $labelText = wfMsgExt( $isSubjectPreview ? 'subject' : 'summary', 'parseinline' );
+               $labelText = wfMessage( $isSubjectPreview ? 'subject' : 'summary' )->parse();
                list( $label, $input ) = $this->getSummaryInput( $summary, $labelText, array( 'class' => $summaryClass ), array() );
                $wgOut->addHTML( "{$label} {$input}" );
        }
@@ -2332,11 +2355,12 @@ class EditPage {
                global $wgParser;
 
                if ( $isSubjectPreview )
-                       $summary = wfMsgForContent( 'newsectionsummary', $wgParser->stripSectionName( $summary ) );
+                       $summary = wfMessage( 'newsectionsummary', $wgParser->stripSectionName( $summary ) )
+                               ->inContentLanguage()->text();
 
                $message = $isSubjectPreview ? 'subject-preview' : 'summary-preview';
 
-               $summary = wfMsgExt( $message, 'parseinline' ) . Linker::commentBlock( $summary, $this->mTitle, $isSubjectPreview );
+               $summary = wfMessage( $message )->parse() . Linker::commentBlock( $summary, $this->mTitle, $isSubjectPreview );
                return Xml::tags( 'div', array( 'class' => 'mw-summary-preview' ), $summary );
        }
 
@@ -2479,7 +2503,12 @@ HTML
                $wgOut->addHTML( '</div>' );
 
                if ( $this->formtype == 'diff' ) {
-                       $this->showDiff();
+                       try {
+                               $this->showDiff();
+                       } catch ( MWContentSerializationException $ex ) {
+                               $msg = wfMessage( 'content-failed-to-parse', $this->content_model, $this->content_format, $ex->getMessage() );
+                               $wgOut->addWikiText( '<div class="error">' . $msg->text() . '</div>');
+                       }
                }
        }
 
@@ -2528,30 +2557,21 @@ HTML
                }
 
                $textboxContent = ContentHandler::makeContent( $this->textbox1, $this->getTitle(),
-                                                                                                               $this->content_model, $this->content_format ); #XXX: handle parse errors ?
+                                                                                                               $this->content_model, $this->content_format );
 
                $newContent = $this->mArticle->replaceSectionContent(
                                                                                        $this->section, $textboxContent,
                                                                                        $this->summary, $this->edittime );
 
-               # hanlde legacy text-based hook
-               $newtext_orig = $newContent->serialize( $this->content_format );
-               $newtext = $newtext_orig; #clone
-               wfRunHooks( 'EditPageGetDiffText', array( $this, &$newtext ) );
-
-               if ( $newtext != $newtext_orig ) {
-                                               #if the hook changed the text, create a new Content object accordingly.
-                                               $newContent = ContentHandler::makeContent( $newtext, $this->getTitle(), $newContent->getModel() ); #XXX: handle parse errors ?
-               }
-
+               ContentHandler::runLegacyHooks( 'EditPageGetDiffText', array( $this, &$newContent ) );
                wfRunHooks( 'EditPageGetDiffContent', array( $this, &$newContent ) );
 
                $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
                $newContent = $newContent->preSaveTransform( $this->mTitle, $wgUser, $popts );
 
                if ( ( $oldContent && !$oldContent->isEmpty() ) || ( $newContent && !$newContent->isEmpty() ) ) {
-                       $oldtitle = wfMsgExt( $oldtitlemsg, array( 'parseinline' ) );
-                       $newtitle = wfMsgExt( 'yourtext', array( 'parseinline' ) );
+                       $oldtitle = wfMessage( $oldtitlemsg )->parse();
+                       $newtitle = wfMessage( 'yourtext' )->parse();
 
                        $de = $oldContent->getContentHandler()->createDifferenceEngine( $this->mArticle->getContext() );
                        $de->setContent( $oldContent, $newContent );
@@ -2591,21 +2611,31 @@ HTML
                        '</div>' );
        }
 
+       /**
+        * Get the copyright warning
+        *
+        * Renamed to getCopyrightWarning(), old name kept around for backwards compatibility
+        */
        protected function getCopywarn() {
+               return self::getCopyrightWarning( $this->mTitle );
+       }
+
+       public static function getCopyrightWarning( $title ) {
                global $wgRightsText;
                if ( $wgRightsText ) {
                        $copywarnMsg = array( 'copyrightwarning',
-                               '[[' . wfMsgForContent( 'copyrightpage' ) . ']]',
+                               '[[' . wfMessage( 'copyrightpage' )->inContentLanguage()->text() . ']]',
                                $wgRightsText );
                } else {
                        $copywarnMsg = array( 'copyrightwarning2',
-                               '[[' . wfMsgForContent( 'copyrightpage' ) . ']]' );
+                               '[[' . wfMessage( 'copyrightpage' )->inContentLanguage()->text() . ']]' );
                }
                // Allow for site and per-namespace customization of contribution/copyright notice.
-               wfRunHooks( 'EditPageCopyrightWarning', array( $this->mTitle, &$copywarnMsg ) );
+               wfRunHooks( 'EditPageCopyrightWarning', array( $title, &$copywarnMsg ) );
 
+               $msg = call_user_func_array( "wfMessage", $copywarnMsg );
                return "<div id=\"editpage-copywarn\">\n" .
-                       call_user_func_array( "wfMsgNoTrans", $copywarnMsg ) . "\n</div>";
+                       $msg->plain() . "\n</div>";
        }
 
        protected function showStandardInputs( &$tabindex = 2 ) {
@@ -2625,12 +2655,12 @@ HTML
 
                $cancel = $this->getCancelLink();
                if ( $cancel !== '' ) {
-                       $cancel .= wfMsgExt( 'pipe-separator' , 'escapenoentities' );
+                       $cancel .= wfMessage( 'pipe-separator' )->text();
                }
-               $edithelpurl = Skin::makeInternalOrExternalUrl( wfMsgForContent( 'edithelppage' ) );
+               $edithelpurl = Skin::makeInternalOrExternalUrl( wfMessage( 'edithelppage' )->inContentLanguage()->text() );
                $edithelp = '<a target="helpwindow" href="' . $edithelpurl . '">' .
-                       htmlspecialchars( wfMsg( 'edithelp' ) ) . '</a> ' .
-                       htmlspecialchars( wfMsg( 'newwindow' ) );
+                       wfMessage( 'edithelp' )->escaped() . '</a> ' .
+                       wfMessage( 'newwindow' )->escaped();
                $wgOut->addHTML( "      <span class='editHelp'>{$cancel}{$edithelp}</span>\n" );
                $wgOut->addHTML( "</div><!-- editButtons -->\n</div><!-- editOptions -->\n" );
        }
@@ -2645,13 +2675,16 @@ HTML
                if ( wfRunHooks( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
                        $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
 
-                       $content1 = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format ); #XXX: handle parse errors?
-                       $content2 = ContentHandler::makeContent( $this->textbox2, $this->getTitle(), $this->content_model, $this->content_format ); #XXX: handle parse errors?
+                       $content1 = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format );
+                       $content2 = ContentHandler::makeContent( $this->textbox2, $this->getTitle(), $this->content_model, $this->content_format );
 
                        $handler = ContentHandler::getForModelID( $this->content_model );
                        $de = $handler->createDifferenceEngine( $this->mArticle->getContext() );
                        $de->setContent( $content2, $content1 );
-                       $de->showDiff( wfMsgExt( 'yourtext', 'parseinline' ), wfMsg( 'storedversion' ) );
+                       $de->showDiff( 
+                               wfMessage( 'yourtext' )->parse(),
+                               wfMessage( 'storedversion' )->text()
+                       );
 
                        $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
                        $this->showTextbox2();
@@ -2669,7 +2702,7 @@ HTML
 
                return Linker::linkKnown(
                        $this->getContextTitle(),
-                       wfMsgExt( 'cancel', array( 'parseinline' ) ),
+                       wfMessage( 'cancel' )->parse(),
                        array( 'id' => 'mw-editform-cancel' ),
                        $cancelParams
                );
@@ -2739,9 +2772,9 @@ HTML
                // Quick paranoid permission checks...
                if ( is_object( $data ) ) {
                        if ( $data->log_deleted & LogPage::DELETED_USER )
-                               $data->user_name = wfMsgHtml( 'rev-deleted-user' );
+                               $data->user_name = wfMessage( 'rev-deleted-user' )->escaped();
                        if ( $data->log_deleted & LogPage::DELETED_COMMENT )
-                               $data->log_comment = wfMsgHtml( 'rev-deleted-comment' );
+                               $data->log_comment = wfMessage( 'rev-deleted-comment' )->escaped();
                }
                return $data;
        }
@@ -2764,7 +2797,7 @@ HTML
                                // string, which happens when you initially edit
                                // a category page, due to automatic preview-on-open.
                                $parsedNote = $wgOut->parse( "<div class='previewnote'>" .
-                                       wfMsg( 'session_fail_preview_html' ) . "</div>", true, /* interface */true );
+                                       wfMessage( 'session_fail_preview_html' )->text() . "</div>", true, /* interface */true );
                        }
                        wfProfileOut( __METHOD__ );
                        return $parsedNote;
@@ -2773,19 +2806,20 @@ HTML
                $note = '';
 
                try {
-                       $content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format );
+                       $content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(),
+                                                                                                       $this->content_model, $this->content_format );
 
                        if ( $this->mTriedSave && !$this->mTokenOk ) {
                                if ( $this->mTokenOkExceptSuffix ) {
-                                       $note = wfMsg( 'token_suffix_mismatch' );
+                                       $note = wfMessage( 'token_suffix_mismatch' )->plain() ;
                                } else {
-                                       $note = wfMsg( 'session_fail_preview' );
+                                       $note = wfMessage( 'session_fail_preview' )->plain() ;
                                }
                        } elseif ( $this->incompleteForm ) {
-                               $note = wfMsg( 'edit_form_incomplete' );
+                               $note = wfMessage( 'edit_form_incomplete' )->plain() ;
                        } else {
-                               $note = wfMsg( 'previewnote' ) .
-                                       ' [[#' . self::EDITFORM_ID . '|' . $wgLang->getArrow() . ' ' . wfMsg( 'continue-editing' ) . ']]';
+                               $note = wfMessage( 'previewnote' )->plain() .
+                                       ' [[#' . self::EDITFORM_ID . '|' . $wgLang->getArrow() . ' ' . wfMessage( 'continue-editing' )->text() . ']]';
                        }
 
                        $parserOptions = ParserOptions::newFromUser( $wgUser );
@@ -2794,8 +2828,8 @@ HTML
                        $parserOptions->setIsPreview( true );
                        $parserOptions->setIsSectionPreview( !is_null($this->section) && $this->section !== '' );
 
+                       # don't parse non-wikitext pages, show message about preview
                        if ( $this->mTitle->isCssJsSubpage() || $this->mTitle->isCssOrJsPage() ) {
-                               # don't parse non-wikitext pages, show message about preview
                                if( $this->mTitle->isCssJsSubpage() ) {
                                        $level = 'user';
                                } elseif( $this->mTitle->isCssOrJsPage() ) {
@@ -2815,12 +2849,12 @@ HTML
                                # Used messages to make sure grep find them:
                                # Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview
                                if( $level && $format ) {
-                                       $note = "<div id='mw-{$level}{$format}preview'>" . wfMsg( "{$level}{$format}preview" ) . "</div>";
+                                       $note = "<div id='mw-{$level}{$format}preview'>" . wfMessage( "{$level}{$format}preview" )->text()  . "</div>";
                                } else {
-                                       $note = wfMsg( 'previewnote' );
+                                       $note = wfMessage( 'previewnote' )->text() ;
                                }
                        } else {
-                               $note = wfMsg( 'previewnote' );
+                               $note = wfMessage( 'previewnote' )->text() ;
                        }
 
                        $rt = $content->getRedirectChain();
@@ -2835,23 +2869,16 @@ HTML
                                        $content = $content->addSectionHeader( $this->summary );
                                }
 
-                               $toparse_orig = $content->serialize( $this->content_format );
-                               $toparse = $toparse_orig;
-                               wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
-
-                               if ( $toparse !== $toparse_orig ) {
-                                       #hook changed the text, create new Content object
-                                       $content = ContentHandler::makeContent( $toparse, $this->getTitle(), $this->content_model, $this->content_format );
-                               }
-
-                               wfRunHooks( 'EditPageGetPreviewContent', array( $this, &$content ) );
+                               $hook_args = array( $this, &$content );
+                               ContentHandler::runLegacyHooks( 'EditPageGetPreviewText', $hook_args );
+                               wfRunHooks( 'EditPageGetPreviewContent', $hook_args );
 
                                $parserOptions->enableLimitReport();
 
-                               #XXX: For CSS/JS pages, we should have called the ShowRawCssJs hook here. But it's now deprecated, so never mind
-                               $content = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
+                               # For CSS/JS pages, we should have called the ShowRawCssJs hook here.
+                               # But it's now deprecated, so never mind
 
-                               // TODO: might be a saner way to get a meaningfull context here?
+                               $content = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
                                $parserOutput = $content->getParserOutput( $this->getArticle()->getTitle(), null, $parserOptions );
 
                                $previewHTML = $parserOutput->getText();
@@ -2863,18 +2890,19 @@ HTML
                                }
                        }
                } catch (MWContentSerializationException $ex) {
-                       $note .= "\n\n" . wfMsg('content-failed-to-parse', $this->content_model, $this->content_format, $ex->getMessage() );
+                       $m = wfMessage('content-failed-to-parse', $this->content_model, $this->content_format, $ex->getMessage() );
+                       $note .= "\n\n" . $m->parse();
                        $previewHTML = '';
                }
 
                if ( $this->isConflict ) {
-                       $conflict = '<h2 id="mw-previewconflict">' . htmlspecialchars( wfMsg( 'previewconflict' ) ) . "</h2>\n";
+                       $conflict = '<h2 id="mw-previewconflict">' . wfMessage( 'previewconflict' )->escaped() . "</h2>\n";
                } else {
                        $conflict = '<hr />';
                }
 
                $previewhead = "<div class='previewnote'>\n" .
-                       '<h2 id="mw-previewheader">' . htmlspecialchars( wfMsg( 'preview' ) ) . "</h2>" .
+                       '<h2 id="mw-previewheader">' . wfMessage( 'preview' )->escaped() . "</h2>" .
                        $wgOut->parse( $note, true, /* interface */true ) . $conflict . "</div>\n";
 
                $pageLang = $this->mTitle->getPageLanguage();
@@ -2938,8 +2966,8 @@ HTML
                                'id'     => 'mw-editbutton-bold',
                                'open'   => '\'\'\'',
                                'close'  => '\'\'\'',
-                               'sample' => wfMsg( 'bold_sample' ),
-                               'tip'    => wfMsg( 'bold_tip' ),
+                               'sample' => wfMessage( 'bold_sample' )->text(),
+                               'tip'    => wfMessage( 'bold_tip' )->text(),
                                'key'    => 'B'
                        ),
                        array(
@@ -2947,8 +2975,8 @@ HTML
                                'id'     => 'mw-editbutton-italic',
                                'open'   => '\'\'',
                                'close'  => '\'\'',
-                               'sample' => wfMsg( 'italic_sample' ),
-                               'tip'    => wfMsg( 'italic_tip' ),
+                               'sample' => wfMessage( 'italic_sample' )->text(),
+                               'tip'    => wfMessage( 'italic_tip' )->text(),
                                'key'    => 'I'
                        ),
                        array(
@@ -2956,8 +2984,8 @@ HTML
                                'id'     => 'mw-editbutton-link',
                                'open'   => '[[',
                                'close'  => ']]',
-                               'sample' => wfMsg( 'link_sample' ),
-                               'tip'    => wfMsg( 'link_tip' ),
+                               'sample' => wfMessage( 'link_sample' )->text(),
+                               'tip'    => wfMessage( 'link_tip' )->text(),
                                'key'    => 'L'
                        ),
                        array(
@@ -2965,8 +2993,8 @@ HTML
                                'id'     => 'mw-editbutton-extlink',
                                'open'   => '[',
                                'close'  => ']',
-                               'sample' => wfMsg( 'extlink_sample' ),
-                               'tip'    => wfMsg( 'extlink_tip' ),
+                               'sample' => wfMessage( 'extlink_sample' )->text(),
+                               'tip'    => wfMessage( 'extlink_tip' )->text(),
                                'key'    => 'X'
                        ),
                        array(
@@ -2974,8 +3002,8 @@ HTML
                                'id'     => 'mw-editbutton-headline',
                                'open'   => "\n== ",
                                'close'  => " ==\n",
-                               'sample' => wfMsg( 'headline_sample' ),
-                               'tip'    => wfMsg( 'headline_tip' ),
+                               'sample' => wfMessage( 'headline_sample' )->text(),
+                               'tip'    => wfMessage( 'headline_tip' )->text(),
                                'key'    => 'H'
                        ),
                        $imagesAvailable ? array(
@@ -2983,8 +3011,8 @@ HTML
                                'id'     => 'mw-editbutton-image',
                                'open'   => '[[' . $wgContLang->getNsText( NS_FILE ) . ':',
                                'close'  => ']]',
-                               'sample' => wfMsg( 'image_sample' ),
-                               'tip'    => wfMsg( 'image_tip' ),
+                               'sample' => wfMessage( 'image_sample' )->text(),
+                               'tip'    => wfMessage( 'image_tip' )->text(),
                                'key'    => 'D',
                        ) : false,
                        $imagesAvailable ? array(
@@ -2992,8 +3020,8 @@ HTML
                                'id'     => 'mw-editbutton-media',
                                'open'   => '[[' . $wgContLang->getNsText( NS_MEDIA ) . ':',
                                'close'  => ']]',
-                               'sample' => wfMsg( 'media_sample' ),
-                               'tip'    => wfMsg( 'media_tip' ),
+                               'sample' => wfMessage( 'media_sample' )->text(),
+                               'tip'    => wfMessage( 'media_tip' )->text(),
                                'key'    => 'M'
                        ) : false,
                        $wgUseTeX ? array(
@@ -3001,8 +3029,8 @@ HTML
                                'id'     => 'mw-editbutton-math',
                                'open'   => "<math>",
                                'close'  => "</math>",
-                               'sample' => wfMsg( 'math_sample' ),
-                               'tip'    => wfMsg( 'math_tip' ),
+                               'sample' => wfMessage( 'math_sample' )->text(),
+                               'tip'    => wfMessage( 'math_tip' )->text(),
                                'key'    => 'C'
                        ) : false,
                        array(
@@ -3010,8 +3038,8 @@ HTML
                                'id'     => 'mw-editbutton-nowiki',
                                'open'   => "<nowiki>",
                                'close'  => "</nowiki>",
-                               'sample' => wfMsg( 'nowiki_sample' ),
-                               'tip'    => wfMsg( 'nowiki_tip' ),
+                               'sample' => wfMessage( 'nowiki_sample' )->text(),
+                               'tip'    => wfMessage( 'nowiki_tip' )->text(),
                                'key'    => 'N'
                        ),
                        array(
@@ -3020,7 +3048,7 @@ HTML
                                'open'   => '--~~~~',
                                'close'  => '',
                                'sample' => '',
-                               'tip'    => wfMsg( 'sig_tip' ),
+                               'tip'    => wfMessage( 'sig_tip' )->text(),
                                'key'    => 'Y'
                        ),
                        array(
@@ -3029,7 +3057,7 @@ HTML
                                'open'   => "\n----\n",
                                'close'  => '',
                                'sample' => '',
-                               'tip'    => wfMsg( 'hr_tip' ),
+                               'tip'    => wfMessage( 'hr_tip' )->text(),
                                'key'    => 'R'
                        )
                );
@@ -3090,11 +3118,11 @@ HTML
                // don't show the minor edit checkbox if it's a new page or section
                if ( !$this->isNew ) {
                        $checkboxes['minor'] = '';
-                       $minorLabel = wfMsgExt( 'minoredit', array( 'parseinline' ) );
+                       $minorLabel = wfMessage( 'minoredit' )->parse();
                        if ( $wgUser->isAllowed( 'minoredit' ) ) {
                                $attribs = array(
                                        'tabindex'  => ++$tabindex,
-                                       'accesskey' => wfMsg( 'accesskey-minoredit' ),
+                                       'accesskey' => wfMessage( 'accesskey-minoredit' )->text(),
                                        'id'        => 'wpMinoredit',
                                );
                                $checkboxes['minor'] =
@@ -3105,12 +3133,12 @@ HTML
                        }
                }
 
-               $watchLabel = wfMsgExt( 'watchthis', array( 'parseinline' ) );
+               $watchLabel = wfMessage( 'watchthis' )->parse();
                $checkboxes['watch'] = '';
                if ( $wgUser->isLoggedIn() ) {
                        $attribs = array(
                                'tabindex'  => ++$tabindex,
-                               'accesskey' => wfMsg( 'accesskey-watch' ),
+                               'accesskey' => wfMessage( 'accesskey-watch' )->text(),
                                'id'        => 'wpWatchthis',
                        );
                        $checkboxes['watch'] =
@@ -3139,9 +3167,9 @@ HTML
                        'name'      => 'wpSave',
                        'type'      => 'submit',
                        'tabindex'  => ++$tabindex,
-                       'value'     => wfMsg( 'savearticle' ),
-                       'accesskey' => wfMsg( 'accesskey-save' ),
-                       'title'     => wfMsg( 'tooltip-save' ) . ' [' . wfMsg( 'accesskey-save' ) . ']',
+                       'value'     => wfMessage( 'savearticle' )->text(),
+                       'accesskey' => wfMessage( 'accesskey-save' )->text(),
+                       'title'     => wfMessage( 'tooltip-save' )->text() . ' [' . wfMessage( 'accesskey-save' )->text() . ']',
                );
                $buttons['save'] = Xml::element( 'input', $temp, '' );
 
@@ -3151,9 +3179,9 @@ HTML
                        'name'      => 'wpPreview',
                        'type'      => 'submit',
                        'tabindex'  => $tabindex,
-                       'value'     => wfMsg( 'showpreview' ),
-                       'accesskey' => wfMsg( 'accesskey-preview' ),
-                       'title'     => wfMsg( 'tooltip-preview' ) . ' [' . wfMsg( 'accesskey-preview' ) . ']',
+                       'value'     => wfMessage( 'showpreview' )->text(),
+                       'accesskey' => wfMessage( 'accesskey-preview' )->text(),
+                       'title'     => wfMessage( 'tooltip-preview' )->text() . ' [' . wfMessage( 'accesskey-preview' )->text() . ']',
                );
                $buttons['preview'] = Xml::element( 'input', $temp, '' );
                $buttons['live'] = '';
@@ -3163,9 +3191,9 @@ HTML
                        'name'      => 'wpDiff',
                        'type'      => 'submit',
                        'tabindex'  => ++$tabindex,
-                       'value'     => wfMsg( 'showdiff' ),
-                       'accesskey' => wfMsg( 'accesskey-diff' ),
-                       'title'     => wfMsg( 'tooltip-diff' ) . ' [' . wfMsg( 'accesskey-diff' ) . ']',
+                       'value'     => wfMessage( 'showdiff' )->text(),
+                       'accesskey' => wfMessage( 'accesskey-diff' )->text(),
+                       'title'     => wfMessage( 'tooltip-diff' )->text() . ' [' . wfMessage( 'accesskey-diff' )->text() . ']',
                );
                $buttons['diff'] = Xml::element( 'input', $temp, '' );
 
@@ -3181,8 +3209,8 @@ HTML
         * failure, etc).
         *
         * @todo This doesn't include category or interlanguage links.
-        *       Would need to enhance it a bit, <s>maybe wrap them in XML
-        *       or something...</s> that might also require more skin
+        *       Would need to enhance it a bit, "<s>maybe wrap them in XML
+        *       or something...</s>" that might also require more skin
         *       initialization, so check whether that's a problem.
         */
        function livePreview() {
@@ -3246,7 +3274,7 @@ HTML
 
                $wgOut->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) );
 
-               $res = wfMsgExt( 'nosuchsectiontext', 'parse', $this->section );
+               $res = wfMessage( 'nosuchsectiontext', $this->section )->parseAsBlock();
                wfRunHooks( 'EditPageNoSuchSection', array( &$this, &$res ) );
                $wgOut->addHTML( $res );
 
@@ -3325,12 +3353,14 @@ HTML
         * @private
         */
        function checkUnicodeCompliantBrowser() {
-               global $wgBrowserBlackList;
-               if ( empty( $_SERVER["HTTP_USER_AGENT"] ) ) {
+               global $wgBrowserBlackList, $wgRequest;
+
+               $currentbrowser = $wgRequest->getHeader( 'User-Agent' );
+               if ( $currentbrowser === false ) {
                        // No User-Agent header sent? Trust it by default...
                        return true;
                }
-               $currentbrowser = $_SERVER["HTTP_USER_AGENT"];
+
                foreach ( $wgBrowserBlackList as $browser ) {
                        if ( preg_match( $browser, $currentbrowser ) ) {
                                return false;