Merge branch 'master' into Wikidata
authorJens Ohlig <jens.ohlig@wikimedia.de>
Wed, 11 Apr 2012 12:24:29 +0000 (14:24 +0200)
committerJens Ohlig <jens.ohlig@wikimedia.de>
Wed, 11 Apr 2012 12:24:29 +0000 (14:24 +0200)
Conflicts:
.gitreview
includes/Article.php
includes/AutoLoader.php
includes/EditPage.php
includes/LinksUpdate.php
includes/WikiPage.php
includes/installer/Ibm_db2Updater.php
includes/installer/MysqlUpdater.php
includes/installer/OracleUpdater.php
includes/installer/SqliteUpdater.php
maintenance/refreshLinks.php

29 files changed:
1  2 
includes/Article.php
includes/AutoLoader.php
includes/DefaultSettings.php
includes/Defines.php
includes/EditPage.php
includes/FeedUtils.php
includes/ImagePage.php
includes/LinksUpdate.php
includes/Revision.php
includes/Title.php
includes/WikiPage.php
includes/actions/RawAction.php
includes/actions/RollbackAction.php
includes/api/ApiComparePages.php
includes/api/ApiDelete.php
includes/api/ApiEditPage.php
includes/api/ApiParse.php
includes/diff/DairikiDiff.php
includes/diff/DifferenceEngine.php
includes/installer/Ibm_db2Updater.php
includes/installer/MysqlUpdater.php
includes/installer/OracleUpdater.php
includes/installer/SqliteUpdater.php
includes/parser/ParserOutput.php
includes/resourceloader/ResourceLoaderWikiModule.php
includes/specials/SpecialUndelete.php
languages/messages/MessagesEn.php
maintenance/refreshLinks.php
maintenance/tables.sql

Simple merge
@@@ -189,8 -195,7 +195,9 @@@ $wgAutoloadLocalClasses = array
        'RevisionList' => 'includes/RevisionList.php',
        'RSSFeed' => 'includes/Feed.php',
        'Sanitizer' => 'includes/Sanitizer.php',
 +    'SecondaryDataUpdate' => 'includes/SecondaryDataUpdate.php',
 +    'SecondaryDBDataUpdate' => 'includes/SecondaryDBDataUpdate.php',
+       'ScopedPHPTimeout' => 'includes/ScopedPHPTimeout.php',
        'SiteConfiguration' => 'includes/SiteConfiguration.php',
        'SiteStats' => 'includes/SiteStats.php',
        'SiteStatsInit' => 'includes/SiteStats.php',
Simple merge
Simple merge
@@@ -574,11 -568,11 +580,11 @@@ class EditPage 
                                // Skip this if wpTextbox2 has input, it indicates that we came
                                // from a conflict page with raw page text, not a custom form
                                // modified by subclasses
 -                              wfProfileIn( get_class( $this ) . "::importContentFormData" );
 -                              $textbox1 = $this->importContentFormData( $request );
 -                              if ( isset( $textbox1 ) )
 +                              wfProfileIn( get_class($this)."::importContentFormData" );
 +                              $textbox1 = $this->importContentFormData( $request ); #FIXME: what should this return??
 +                              if ( isset($textbox1) )
                                        $this->textbox1 = $textbox1;
-                               wfProfileOut( get_class($this)."::importContentFormData" );
+                               wfProfileOut( get_class( $this ) . "::importContentFormData" );
                        }
  
                        # Truncate for whole multibyte characters. +5 bytes for ellipsis
  
                                        # Sanity check, make sure it's the right page,
                                        # the revisions exist and they were not deleted.
 -                                      # Otherwise, $text will be left as-is.
 +                                      # Otherwise, $content will be left as-is.
                                        if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
                                                $undorev->getPage() == $oldrev->getPage() &&
-                                               $undorev->getPage() == $this->mTitle->getArticleId() &&
+                                               $undorev->getPage() == $this->mTitle->getArticleID() &&
                                                !$undorev->isDeleted( Revision::DELETED_TEXT ) &&
                                                !$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
  
                $aid = $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE );
                $new = ( $aid == 0 );
  
 -              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;
 -                      }
 +              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;
 +                              }
  
 -                      # 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;
 -                      }
++<<<<<<< HEAD
 +                              // 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 );
  
 +                              # Handle the user preference to force summaries here. Check if it's not a redirect.
 +                              if ( !$this->allowBlankSummary && !$content->isRedirect() ) {
 +                                      if ( md5( $this->summary ) == $this->autoSumm ) {
 +                                              $this->missingSummary = true;
 +                                              $status->fatal( 'missingsummary' ); // or 'missingcommentheader' if $section == 'new'. Blegh
 +                                              $status->value = self::AS_SUMMARY_NEEDED;
 +                                              wfProfileOut( __METHOD__ );
 +                                              return $status;
 +                                      }
++=======
+                       $text = $this->textbox1;
+                       $result['sectionanchor'] = '';
+                       if ( $this->section == 'new' ) {
+                               if ( $this->sectiontitle !== '' ) {
+                                       // Insert the section title above the content.
+                                       $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->sectiontitle ) . "\n\n" . $text;
+                                       // 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.
+                                       $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $text;
+                                       // 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 );
++>>>>>>> master
                                }
 -                      }
  
 -                      $status->value = self::AS_SUCCESS_NEW_ARTICLE;
 +                              $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 );
 +
 +                                              // Jump to the new section
 +                                              $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
  
 -              } else {
 +                                              // Create a link to the new section from the edit summary.
 +                                              $cleanSummary = $wgParser->stripSectionName( $this->summary );
 +                                              $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary );
 +                                      }
 +                              }
  
 -                      # Article exists. Check for edit conflict.
 +                              $status->value = self::AS_SUCCESS_NEW_ARTICLE;
  
 -                      $this->mArticle->clear(); # Force reload of dates, etc.
 -                      $timestamp = $this->mArticle->getTimestamp();
 +                      } else {
  
 -                      wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}\n" );
 +                              # Article exists. Check for edit conflict.
  
 -                      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->mArticle->clear(); # Force reload of dates, etc.
 +                              $timestamp = $this->mArticle->getTimestamp();
 +
 +                              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" );
                                                $this->isConflict = false;
++<<<<<<< HEAD
++=======
+                                               wfDebug( __METHOD__ . ": conflict suppressed; new section\n" );
++>>>>>>> master
                                        }
 -                              } 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;
                                }
++<<<<<<< HEAD
 +
 +                              // 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;
++=======
+                       }
+                       // 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 ( $this->isConflict ) {
+                               wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" );
+                               $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle, $this->edittime );
+                       } else {
+                               wfDebug( __METHOD__ . ": getting section '$this->section'\n" );
+                               $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle );
+                       }
+                       if ( is_null( $text ) ) {
+                               wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" );
+                               $this->isConflict = true;
+                               $text = $this->textbox1; // do not try to merge here!
+                       } elseif ( $this->isConflict ) {
+                               # Attempt merge
+                               if ( $this->mergeChangesInto( $text ) ) {
+                                       // Successful merge! Maybe we should tell the user the good news?
+                                       $this->isConflict = false;
+                                       wfDebug( __METHOD__ . ": Suppressing edit conflict, successful merge.\n" );
++>>>>>>> master
                                } else {
 -                                      $this->section = '';
 -                                      $this->textbox1 = $text;
 -                                      wfDebug( __METHOD__ . ": Keeping edit conflict, failed merge.\n" );
 +                                      $sectionTitle = $this->summary;
                                }
 -                      }
  
 -                      if ( $this->isConflict ) {
 -                              $status->setResult( false, self::AS_CONFLICT_DETECTED );
 -                              wfProfileOut( __METHOD__ );
 -                              return $status;
 -                      }
 +                              $textbox_content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format );
 +                              $content = false;
  
 -                      // Run post-section-merge edit filter
 -                      if ( !wfRunHooks( 'EditFilterMerged', array( $this, $text, &$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;
 -                      }
 +                              if ( $this->isConflict ) {
 +                                      wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" );
  
 -                      # Handle the user preference to force summaries here, but not for null edits
 -                      if ( $this->section != 'new' && !$this->allowBlankSummary
 -                              && $this->getOriginalContent() != $text
 -                              && !Title::newFromRedirect( $text ) ) # 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;
 +                                      $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 );
                                }
 -                      }
  
 -                      # 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;
 +                              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?
 +                                              $content = $textbox_content;
 +                                              $this->isConflict = false;
 +                                              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;
                                }
                # Enabled article-related sidebar, toplinks, etc.
                $wgOut->setArticleRelated( true );
  
+               $contextTitle = $this->getContextTitle();
                if ( $this->isConflict ) {
-                       $wgOut->setPageTitle( wfMessage( 'editconflict', $this->getContextTitle()->getPrefixedText() ) );
-               } elseif ( $this->section != '' ) {
+                       $msg = 'editconflict';
+               } elseif ( $contextTitle->exists() && $this->section != '' ) {
                        $msg = $this->section == 'new' ? 'editingcomment' : 'editingsection';
-                       $wgOut->setPageTitle( wfMessage( $msg, $this->getContextTitle()->getPrefixedText() ) );
                } else {
-                       # Use the title defined by DISPLAYTITLE magic word when present
-                       if ( isset( $this->mParserOutput )
-                        && ( $dt = $this->mParserOutput->getDisplayTitle() ) !== false ) {
-                               $title = $dt;
-                       } else {
-                               $title = $this->getContextTitle()->getPrefixedText();
-                       }
-                       $wgOut->setPageTitle( wfMessage( 'editing', $title ) );
 -                      $msg = $contextTitle->exists() || ( $contextTitle->getNamespace() == NS_MEDIAWIKI && $contextTitle->getDefaultMessageText() !== false ) ?\r
 -                              'editing' : 'creating';\r
++                      $msg = $contextTitle->exists() || ( $contextTitle->getNamespace() == NS_MEDIAWIKI && $contextTitle->getDefaultMessageText() !== false ) ?
++                              'editing' : 'creating';
+               }
+               # Use the title defined by DISPLAYTITLE magic word when present
 -              $displayTitle = isset( $this->mParserOutput ) ? $this->mParserOutput->getDisplayTitle() : false;\r
 -              if ( $displayTitle === false ) {\r
 -                      $displayTitle = $contextTitle->getPrefixedText();\r
++              $displayTitle = isset( $this->mParserOutput ) ? $this->mParserOutput->getDisplayTitle() : false;
++              if ( $displayTitle === false ) {
++                      $displayTitle = $contextTitle->getPrefixedText();
                }
+               $wgOut->setPageTitle( wfMessage( $msg, $displayTitle ) );
        }
  
        /**
                $this->showTextbox( $this->textbox2, 'wpTextbox2', array( 'tabindex' => 6, 'readonly' ) );
        }
  
 -      protected function showTextbox( $content, $name, $customAttribs = array() ) {
 +      protected function showTextbox( $text, $name, $customAttribs = array() ) {
                global $wgOut, $wgUser;
  
-               $wikitext = $this->safeUnicodeOutput( $text );
-               if ( strval($wikitext) !== '' ) {
+               $wikitext = $this->safeUnicodeOutput( $content );
+               if ( strval( $wikitext ) !== '' ) {
                        // Ensure there's a newline at the end, otherwise adding lines
                        // is awkward.
                        // But don't add a newline if the ext is empty, or Firefox in XHTML
         * save and then make a comparison.
         */
        function showDiff() {
 -              global $wgUser, $wgContLang, $wgParser, $wgOut;
 +              global $wgUser, $wgContLang, $wgOut;
 +
 +              $oldContent = $this->getOriginalContent();
 +
 +              $textboxContent = ContentHandler::makeContent( $this->textbox1, $this->getTitle(),
 +                                                                                                              $this->content_model, $this->content_format ); #XXX: handle parse errors ?
  
 +              $newContent = $this->mArticle->replaceSectionContent(
 +                                                                                      $this->section, $textboxContent,
 +                                                                                      $this->summary, $this->edittime );
+               $oldtitlemsg = 'currentrev';
+               # if message does not exist, show diff against the preloaded default
+               if( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !$this->mTitle->exists() ) {
+                       $oldtext = $this->mTitle->getDefaultMessageText();
+                       if( $oldtext !== false ) {
+                               $oldtitlemsg = 'defaultmessagetext';
+                       }
+               } else {
+                       $oldtext = $this->mArticle->getRawText();
+               }
+               $newtext = $this->mArticle->replaceSection(
+                       $this->section, $this->textbox1, $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->getModelName() ); #XXX: handle parse errors ?
 +              }
 +
 +              wfRunHooks( 'EditPageGetDiffContent', array( $this, &$newContent ) ); #FIXME: document new hook
 +
                $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
 -              $newtext = $wgParser->preSaveTransform( $newtext, $this->mTitle, $wgUser, $popts );
 +              $newContent = $newContent->preSaveTransform( $this->mTitle, $wgUser, $popts );
  
 +              if ( ( $oldContent && !$oldContent->isEmpty() ) || ( $newContent && !$newContent->isEmpty() ) ) {
 +                      $oldtitle = wfMsgExt( 'currentrev', array( 'parseinline' ) );
+               if ( $oldtext !== false  || $newtext != '' ) {
+                       $oldtitle = wfMsgExt( $oldtitlemsg, array( 'parseinline' ) );
                        $newtitle = wfMsgExt( 'yourtext', array( 'parseinline' ) );
  
 -                      $de = new DifferenceEngine( $this->mArticle->getContext() );
 -                      $de->setText( $oldtext, $newtext );
 +                      $de = $oldContent->getContentHandler()->getDifferenceEngine( $this->mArticle->getContext() );
 +                      $de->setContent( $oldContent, $newContent );
 +
                        $difftext = $de->getDiff( $oldtitle, $newtitle );
                        $de->showDiffStyle();
                } else {
                        return $parsedNote;
                }
  
 +        try {
 +            $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' );
 +                } else {
 +                    $note = wfMsg( 'session_fail_preview' );
 +                }
 +            } elseif ( $this->incompleteForm ) {
 +                $note = wfMsg( 'edit_form_incomplete' );
 +            } elseif ( $this->isCssJsSubpage || $this->mTitle->isCssOrJsPage() ) {
 +                # if this is a CSS or JS page used in the UI, show a special notice
 +                # XXX: stupid php bug won't let us use $this->getContextTitle()->isCssJsSubpage() here -- This note has been there since r3530. Sure the bug was fixed time ago?
 +
 +                if( $this->mTitle->isCssJsSubpage() ) {
 +                    $level = 'user';
 +                } elseif( $this->mTitle->isCssOrJsPage() ) {
 +                    $level = 'site';
 +                } else {
 +                    $level = false;
 +                }
 +
 +                if ( $content->getModelName() == CONTENT_MODEL_CSS ) {
 +                    $format = 'css';
 +                } elseif ( $content->getModelName() == CONTENT_MODEL_JAVASCRIPT ) {
 +                    $format = 'js';
 +                } else {
 +                    $format = false;
 +                }
 +
 +                # 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>";
 +                } else {
 +                    $note = wfMsg( 'previewnote' );
 +                }
 +            } else {
 +                $note = wfMsg( 'previewnote' );
 +            }
 +
 +            $parserOptions = ParserOptions::newFromUser( $wgUser );
 +            $parserOptions->setEditSection( false );
 +            $parserOptions->setTidy( true );
 +            $parserOptions->setIsPreview( true );
 +            $parserOptions->setIsSectionPreview( !is_null($this->section) && $this->section !== '' );
 +
 +            $rt = $content->getRedirectChain();
 +
 +            if ( $rt ) {
 +                $previewHTML = $this->mArticle->viewRedirect( $rt, false );
 +            } else {
 +
 +                # If we're adding a comment, we need to show the
 +                # summary as the headline
 +                if ( $this->section == "new" && $this->summary != "" ) {
 +                    $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 ) ); # FIXME: document new hook
 +
 +                $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 );
 +                $parserOutput = $content->getParserOutput( $this->mTitle, null, $parserOptions );
 +
 +                $previewHTML = $parserOutput->getText();
 +                $this->mParserOutput = $parserOutput;
 +                $wgOut->addParserOutputNoText( $parserOutput );
 +
 +                if ( count( $parserOutput->getWarnings() ) ) {
 +                    $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
 +                }
 +            }
 +        } catch (MWContentSerializationException $ex) {
 +            $note .= "\n\n" . wfMsg('content-failed-to-parse', $this->content_model, $this->content_format, $ex->getMessage() );
 +            $previewHTML = '';
 +        }
+               if ( $this->mTriedSave && !$this->mTokenOk ) {
+                       if ( $this->mTokenOkExceptSuffix ) {
+                               $note = wfMsg( 'token_suffix_mismatch' );
+                       } else {
+                               $note = wfMsg( 'session_fail_preview' );
+                       }
+               } elseif ( $this->incompleteForm ) {
+                       $note = wfMsg( 'edit_form_incomplete' );
+               } else {
+                       $note = wfMsg( 'previewnote' );
+               }
+               $parserOptions = ParserOptions::newFromUser( $wgUser );
+               $parserOptions->setEditSection( false );
+               $parserOptions->setTidy( true );
+               $parserOptions->setIsPreview( true );
+               $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
+               # don't parse non-wikitext pages, show message about preview
+               # XXX: stupid php bug won't let us use $this->getContextTitle()->isCssJsSubpage() here -- This note has been there since r3530. Sure the bug was fixed time ago?
+               if ( $this->isCssJsSubpage || !$this->mTitle->isWikitextPage() ) {
+                       if ( $this->mTitle->isCssJsSubpage() ) {
+                               $level = 'user';
+                       } elseif ( $this->mTitle->isCssOrJsPage() ) {
+                               $level = 'site';
+                       } else {
+                               $level = false;
+                       }
+                       # Used messages to make sure grep find them:
+                       # Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview
+                       if ( $level ) {
+                               if ( preg_match( "/\\.css$/", $this->mTitle->getText() ) ) {
+                                       $previewtext = "<div id='mw-{$level}csspreview'>\n" . wfMsg( "{$level}csspreview" ) . "\n</div>";
+                                       $class = "mw-code mw-css";
+                               } elseif ( preg_match( "/\\.js$/", $this->mTitle->getText() ) ) {
+                                       $previewtext = "<div id='mw-{$level}jspreview'>\n" . wfMsg( "{$level}jspreview" ) . "\n</div>";
+                                       $class = "mw-code mw-js";
+                               } else {
+                                       throw new MWException( 'A CSS/JS (sub)page but which is not css nor js!' );
+                               }
+                       }
+                       $parserOutput = $wgParser->parse( $previewtext, $this->mTitle, $parserOptions );
+                       $previewHTML = $parserOutput->mText;
+                       $previewHTML .= "<pre class=\"$class\" dir=\"ltr\">\n" . htmlspecialchars( $this->textbox1 ) . "\n</pre>\n";
+               } else {
+                       $toparse = $this->textbox1;
  
-               if( $this->isConflict ) {
+                       # If we're adding a comment, we need to show the
+                       # summary as the headline
+                       if ( $this->section == "new" && $this->summary != "" ) {
+                               $toparse = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $toparse;
+                       }
+                       wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
+                       $parserOptions->enableLimitReport();
+                       $toparse = $wgParser->preSaveTransform( $toparse, $this->mTitle, $wgUser, $parserOptions );
+                       $parserOutput = $wgParser->parse( $toparse, $this->mTitle, $parserOptions );
+                       $rt = Title::newFromRedirectArray( $this->textbox1 );
+                       if ( $rt ) {
+                               $previewHTML = $this->mArticle->viewRedirect( $rt, false );
+                       } else {
+                               $previewHTML = $parserOutput->getText();
+                       }
+                       $this->mParserOutput = $parserOutput;
+                       $wgOut->addParserOutputNoText( $parserOutput );
+                       if ( count( $parserOutput->getWarnings() ) ) {
+                               $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
+                       }
+               }
+               if ( $this->isConflict ) {
                        $conflict = '<h2 id="mw-previewconflict">' . htmlspecialchars( wfMsg( 'previewconflict' ) ) . "</h2>\n";
                } else {
                        $conflict = '<hr />';
                                // Do some sanity checks. These aren't needed for reversability,
                                // but should help keep the breakage down if the editor
                                // breaks one of the entities whilst editing.
+                               if ( ( substr( $invalue, $i, 1 ) == ";" ) and ( strlen( $hexstring ) <= 6 ) ) {
+                                       $codepoint = hexdec( $hexstring );
 +                              if ( (substr($invalue,$i,1)==";") and (strlen($hexstring) <= 6) ) {
 +                                      $codepoint = hexdec($hexstring);
                                        $result .= codepointToUtf8( $codepoint );
                                } else {
                                        $result .= "&#x" . $hexstring . substr( $invalue, $i, 1 );
@@@ -115,10 -114,10 +114,11 @@@ class FeedUtils 
                        #       $wgLang->time( $timestamp ) ),
                        #       wfMsg( 'currentrev' ) );
  
+                       $diffText = '';
                        // Don't bother generating the diff if we won't be able to show it
                        if ( $wgFeedDiffCutoff > 0 ) {
 -                              $de = new DifferenceEngine( $title, $oldid, $newid );
 +                $contentHandler = ContentHandler::getForTitle( $title );
 +                $de = $contentHandler->getDifferenceEngine( $title, $oldid, $newid );
                                $diffText = $de->getDiff(
                                        wfMsg( 'previousrevision' ), // hack
                                        wfMsg( 'revisionasof',
Simple merge
@@@ -45,18 -47,23 +45,22 @@@ class LinksUpdate extends SecondaryDBDa
         * @param $recursive Boolean: queue jobs for recursive updates?
         */
        function __construct( $title, $parserOutput, $recursive = true ) {
 -              global $wgAntiLockFlags;
 +        parent::__construct( );
  
 -              if ( $wgAntiLockFlags & ALF_NO_LINK_LOCK ) {
 -                      $this->mOptions = array();
 -              } else {
 -                      $this->mOptions = array( 'FOR UPDATE' );
 -              }
 -              $this->mDb = wfGetDB( DB_MASTER );
 +        if ( !is_object( $title ) ) {
 +            throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " .
 +                "Please see Article::editUpdates() for an invocation example.\n" );
 +        }
  
 -              if ( !is_object( $title ) ) {
 -                      throw new MWException( "The calling convention to LinksUpdate::__construct() has changed. " .
++              if ( !is_object( $title ) ) {
++                      throw new MWException( "The calling convention to LinksUpdate::__construct() has changed. " .
+                               "Please see WikiPage::doEditUpdates() for an invocation example.\n" );
 -              }
 -              $this->mTitle = $title;
 -              $this->mId = $title->getArticleID();
++              }
 +        $this->mTitle = $title;
 +        $this->mId = $title->getArticleID();
 +
 +        $this->mParserOutput = $parserOutput;
  
 -              $this->mParserOutput = $parserOutput;
                $this->mLinks = $parserOutput->getLinks();
                $this->mImages = $parserOutput->getImages();
                $this->mTemplates = $parserOutput->getTemplates();
Simple merge
Simple merge
@@@ -437,24 -427,16 +461,24 @@@ class WikiPage extends Page 
        /**
         * Get the text of the current revision. No side-effects...
         *
-        * @return String|false The text of the current revision
+        * @return String|bool The text of the current revision. False on failure
         */
 -      public function getRawText() {
 -              $this->loadLastEdit();
 -              if ( $this->mLastRevision ) {
 -                      return $this->mLastRevision->getRawText();
 -              }
 -              return false;
 +      public function getRawText() { #FIXME: deprecated, replace usage!
 +              return $this->getText( Revision::RAW );
        }
  
 +    /**
 +     * Get the content of the current revision. No side-effects...
 +     *
 +     * @return Contet|false The text of the current revision
 +     */
 +    protected function getNativeData() { #FIXME: examine all uses carefully! caller must be aware of content model!
 +        $content = $this->getContent( Revision::RAW );
 +        if ( !$content ) return null;
 +
 +        return $content->getNativeData();
 +    }
 +
        /**
         * @return string MW timestamp of last article revision
         */
                                'parent_id'  => $oldid,
                                'user'       => $user->getId(),
                                'user_text'  => $user->getName(),
 -                              'timestamp'  => $now
 +                              'timestamp'  => $now,
 +                'content_model' => $content->getModelName(),
 +                'content_format' => $serialisation_format,
                        ) );
  
 -                      $changed = ( strcmp( $text, $oldtext ) != 0 );
 +                      $changed = !$content->equals( $old_content );
  
                        if ( $changed ) {
-                               $dbw->begin();
+                               $dbw->begin( __METHOD__ );
                                $revisionId = $revision->insertOn( $dbw );
  
                                # Update page
         * @param &$hasHistory Boolean: whether the page has a history
         * @return mixed String containing deletion reason or empty string, or boolean false
         *    if no revision occurred
 +     * @deprecated since 1.20, use ContentHandler::getAutoDeleteReason() instead
         */
        public function getAutoDeleteReason( &$hasHistory ) {
 +        #NOTE: stub for backwards-compatibility.
 +
 +              $handler = ContentHandler::getForTitle( $this->getTitle() );
 +        $handler->getAutoDeleteReason( $this->getTitle(), $hasHistory );
+               global $wgContLang;
+               // Get the last revision
+               $rev = $this->getRevision();
+               if ( is_null( $rev ) ) {
+                       return false;
+               }
+               // Get the article's contents
+               $contents = $rev->getText();
+               $blank = false;
+               // If the page is blank, use the text from the previous revision,
+               // which can only be blank if there's a move/import/protect dummy revision involved
+               if ( $contents == '' ) {
+                       $prev = $rev->getPrevious();
+                       if ( $prev )    {
+                               $contents = $prev->getText();
+                               $blank = true;
+                       }
+               }
+               $dbw = wfGetDB( DB_MASTER );
+               // Find out if there was only one contributor
+               // Only scan the last 20 revisions
+               $res = $dbw->select( 'revision', 'rev_user_text',
+                       array( 'rev_page' => $this->getID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
+                       __METHOD__,
+                       array( 'LIMIT' => 20 )
+               );
+               if ( $res === false ) {
+                       // This page has no revisions, which is very weird
+                       return false;
+               }
+               $hasHistory = ( $res->numRows() > 1 );
+               $row = $dbw->fetchObject( $res );
+               if ( $row ) { // $row is false if the only contributor is hidden
+                       $onlyAuthor = $row->rev_user_text;
+                       // Try to find a second contributor
+                       foreach ( $res as $row ) {
+                               if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
+                                       $onlyAuthor = false;
+                                       break;
+                               }
+                       }
+               } else {
+                       $onlyAuthor = false;
+               }
+               // Generate the summary with a '$1' placeholder
+               if ( $blank ) {
+                       // The current revision is blank and the one before is also
+                       // blank. It's just not our lucky day
+                       $reason = wfMsgForContent( 'exbeforeblank', '$1' );
+               } else {
+                       if ( $onlyAuthor ) {
+                               $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+                       } else {
+                               $reason = wfMsgForContent( 'excontent', '$1' );
+                       }
+               }
+               if ( $reason == '-' ) {
+                       // Allow these UI messages to be blanked out cleanly
+                       return '';
+               }
+               // Replace newlines with spaces to prevent uglyness
+               $contents = preg_replace( "/[\n\r]/", ' ', $contents );
+               // Calculate the maximum amount of chars to get
+               // Max content length = max comment length - length of the comment (excl. $1)
+               $maxLength = 255 - ( strlen( $reason ) - 2 );
+               $contents = $wgContLang->truncate( $contents, $maxLength );
+               // Remove possible unfinished links
+               $contents = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $contents );
+               // Now replace the '$1' placeholder
+               $reason = str_replace( '$1', $contents, $reason );
+               return $reason;
        }
  
        /**
@@@ -2932,12 -2914,13 +3071,16 @@@ class PoolWorkArticleView extends PoolC
                        if ( $rev === null ) {
                                return false;
                        }
 -                      $text = $rev->getText();
 +            $content = $rev->getContent(); #XXX: why use PUBLIC audience here (default), and RAW above?
                }
  
 +              $time = - wfTime();
 +              $this->parserOutput = $content->getParserOutput( $this->page->getTitle(), $this->revid, $this->parserOptions );
 +              $time += wfTime();
+               $time = - microtime( true );
+               $this->parserOutput = $wgParser->parse( $text, $this->page->getTitle(),
+                       $this->parserOptions, true, true, $this->revid );
+               $time += microtime( true );
  
                # Timing hack
                if ( $time > 3 ) {
Simple merge
Simple merge
@@@ -32,11 -32,10 +32,11 @@@ class ApiComparePages extends ApiBase 
        public function execute() {
                $params = $this->extractRequestParams();
  
-               $rev1 = $this->revisionOrTitle( $params['fromrev'], $params['fromtitle'] );
-               $rev2 = $this->revisionOrTitle( $params['torev'], $params['totitle'] );
+               $rev1 = $this->revisionOrTitleOrId( $params['fromrev'], $params['fromtitle'], $params['fromid'] );
+               $rev2 = $this->revisionOrTitleOrId( $params['torev'], $params['totitle'], $params['toid'] );
  
 -              $de = new DifferenceEngine( $this->getContext(),
 +        $contentHandler = ContentHandler::getForModelName( $rev1->getContentModelName() );
 +        $de = $contentHandler->getDifferenceEngine( $this->getContext(),
                        $rev1,
                        $rev2,
                        null, // rcid
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -705,12 -670,11 +705,13 @@@ class DifferenceEngine extends ContextS
        /**
         * Generate a diff, no caching
         *
 +     * @todo move this to TextDifferenceEngine, make DifferenceEngine abstract. At some point.
 +     *
         * @param $otext String: old text, must be already segmented
         * @param $ntext String: new text, must be already segmented
+        * @return bool|string
         */
 -      function generateDiffBody( $otext, $ntext ) {
 +      function generateTextDiffBody( $otext, $ntext ) {
                global $wgExternalDiffEngine, $wgContLang;
  
                wfProfileIn( __METHOD__ );
@@@ -71,13 -70,8 +70,15 @@@ class Ibm_db2Updater extends DatabaseUp
                        array( 'addField', 'revision',      'rev_sha1',         'patch-rev_sha1.sql' ),
                        array( 'addField', 'archive',       'ar_sha1',          'patch-ar_sha1.sql' ),
  
 +            // 1.20
 +            // content model stuff for WikiData
 +            array( 'addField',        'revision',     'rev_content_format',           'patch-revision-rev_content_format.sql' ),
 +            array( 'addField',        'revision',     'rev_content_model',            'patch-revision-rev_content_model.sql' ),
 +            array( 'addField',        'archive',      'ar_content_format',            'patch-archive-ar_content_format.sql' ),
 +            array( 'addField',        'archive',      'ar_content_model',                 'patch-archive-ar_content_model.sql' ),
 +            array( 'addField',        'page',     'page_content_model',               'patch-page-page_content_model.sql' ),
+                       // 1.20
+                       array( 'addTable', 'config',                            'patch-config.sql' ),
                );
        }
  }
@@@ -189,17 -188,14 +188,22 @@@ class MysqlUpdater extends DatabaseUpda
                        array( 'addField', 'revision',      'rev_sha1',         'patch-rev_sha1.sql' ),
                        array( 'addField', 'archive',       'ar_sha1',          'patch-ar_sha1.sql' ),
                        array( 'addIndex', 'page', 'page_redirect_namespace_len', 'patch-page_redirect_namespace_len.sql' ),
-                       array( 'modifyField', 'user', 'ug_group', 'patch-ug_group-length-increase.sql' ),
+                       array( 'modifyField', 'user_groups', 'ug_group', 'patch-ug_group-length-increase.sql' ),
                        array( 'addField',      'uploadstash',  'us_chunk_inx',         'patch-uploadstash_chunk.sql' ),
                        array( 'addfield', 'job',           'job_timestamp',    'patch-jobs-add-timestamp.sql' ),
 +
 +            // 1.20
 +            // content model stuff for WikiData
 +            array( 'addField',        'revision',     'rev_content_format',           'patch-revision-rev_content_format.sql' ),
 +            array( 'addField',        'revision',     'rev_content_model',            'patch-revision-rev_content_model.sql' ),
 +            array( 'addField',        'archive',      'ar_content_format',            'patch-archive-ar_content_format.sql' ),
 +            array( 'addField',        'archive',      'ar_content_model',                 'patch-archive-ar_content_model.sql' ),
 +            array( 'addField',        'page',     'page_content_model',               'patch-page-page_content_model.sql' ),
+                       array( 'modifyField', 'user_former_groups', 'ufg_group', 'patch-ufg_group-length-increase.sql' ),
+                       // 1.20
+                       array( 'addTable', 'config',                            'patch-config.sql' ),
+                       array( 'addIndex', 'revision', 'page_user_timestamp', 'patch-revision-user-page-index.sql' ),
                );
        }
  
@@@ -53,13 -52,8 +52,15 @@@ class OracleUpdater extends DatabaseUpd
                        array( 'addField', 'job', 'job_timestamp', 'patch-job_timestamp_field.sql' ),
                        array( 'addIndex', 'job', 'i02', 'patch-job_timestamp_index.sql' ),
  
 +            // 1.20
 +            // content model stuff for WikiData
 +            array( 'addField',        'revision',     'rev_content_format',           'patch-revision-rev_content_format.sql' ),
 +            array( 'addField',        'revision',     'rev_content_model',            'patch-revision-rev_content_model.sql' ),
 +            array( 'addField',        'archive',      'ar_content_format',            'patch-archive-ar_content_format.sql' ),
 +            array( 'addField',        'archive',      'ar_content_model',                 'patch-archive-ar_content_model.sql' ),
 +            array( 'addField',        'page',     'page_content_model',               'patch-page-page_content_model.sql' ),
+                       //1.20
+                       array( 'addTable', 'config', 'patch-config.sql' ),
  
                        // KEEP THIS AT THE BOTTOM!!
                        array( 'doRebuildDuplicateFunction' ),
@@@ -68,17 -67,14 +67,22 @@@ class SqliteUpdater extends DatabaseUpd
                        array( 'addField', 'revision',      'rev_sha1',         'patch-rev_sha1.sql' ),
                        array( 'addField', 'archive',       'ar_sha1',          'patch-ar_sha1.sql' ),
                        array( 'addIndex', 'page', 'page_redirect_namespace_len', 'patch-page_redirect_namespace_len.sql' ),
-                       array( 'modifyField', 'user', 'ug_group', 'patch-ug_group-length-increase.sql' ),
+                       array( 'modifyField', 'user_groups', 'ug_group', 'patch-ug_group-length-increase.sql' ),
                        array( 'addField',      'uploadstash',  'us_chunk_inx',         'patch-uploadstash_chunk.sql' ),
                        array( 'addfield', 'job',           'job_timestamp',    'patch-jobs-add-timestamp.sql' ),
 +
 +            // 1.20
 +            // content model stuff for WikiData
 +            array( 'addField',        'revision',     'rev_content_format',           'patch-revision-rev_content_format.sql' ),
 +            array( 'addField',        'revision',     'rev_content_model',            'patch-revision-rev_content_model.sql' ),
 +            array( 'addField',        'archive',      'ar_content_format',            'patch-archive-ar_content_format.sql' ),
 +            array( 'addField',        'archive',      'ar_content_model',                 'patch-archive-ar_content_model.sql' ),
 +            array( 'addField',        'page',     'page_content_model',               'patch-page-page_content_model.sql' ),
+                       array( 'modifyField', 'user_former_groups', 'ufg_group', 'patch-ug_group-length-increase.sql' ),
+                       // 1.20
+                       array( 'addTable', 'config',                            'patch-config.sql' ),
+                       array( 'addIndex', 'revision', 'page_user_timestamp', 'patch-revision-user-page-index.sql' ),
                );
        }
  
Simple merge
Simple merge
Simple merge
@@@ -221,11 -221,9 +221,15 @@@ class RefreshLinks extends Maintenance 
  
                $options = new ParserOptions;
                $parserOutput = $wgParser->parse( $revision->getText(), $title, $options, true, true, $revision->getId() );
 +
 +        $updates = $parserOutput->getLinksUpdateAndOtherUpdates( $title, false );
 +        SecondaryDataUpdate::runUpdates( $updates );
 +
 +        $dbw->commit();
++        // TODO: We don't know what happens here.
+               $update = new LinksUpdate( $title, $parserOutput, false );
+               $update->doUpdate();
+               $dbw->commit( __METHOD__ );
        }
  
        /**
Simple merge