Merge "EditPage: Show a different label for the button on create vs. modify"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 24 Aug 2016 00:14:38 +0000 (00:14 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 24 Aug 2016 00:14:38 +0000 (00:14 +0000)
1  2 
includes/EditPage.php

diff --combined includes/EditPage.php
@@@ -20,8 -20,6 +20,8 @@@
   * @file
   */
  
 +use MediaWiki\Logger\LoggerFactory;
 +
  /**
   * The edit page/HTML interface (split from Article)
   * The actual database and text munging is still in Article,
@@@ -260,6 -258,9 +260,6 @@@ class EditPage 
        /** @var bool */
        public $tooBig = false;
  
 -      /** @var bool */
 -      public $kblength = false;
 -
        /** @var bool */
        public $missingComment = false;
  
        /** @var bool */
        protected $edit;
  
 +      /** @var bool|int */
 +      protected $contentLength = false;
 +
        /**
         * @var bool Set in ApiEditPage, based on ContentHandler::allowsDirectApiEditing
         */
  
                        return $handler->makeEmptyContent();
                } else {
 -                      # nasty side-effect, but needed for consistency
 -                      $this->contentModel = $rev->getContentModel();
 -                      $this->contentFormat = $rev->getContentFormat();
 +                      // Content models should always be the same since we error
 +                      // out if they are different before this point.
 +                      $logger = LoggerFactory::getInstance( 'editpage' );
 +                      if ( $this->contentModel !== $rev->getContentModel() ) {
 +                              $logger->warning( "Overriding content model from current edit {prev} to {new}", [
 +                                      'prev' => $this->contentModel,
 +                                      'new' => $rev->getContentModel(),
 +                                      'title' => $this->getTitle()->getPrefixedDBkey(),
 +                                      'method' => __METHOD__
 +                              ] );
 +                              $this->contentModel = $rev->getContentModel();
 +                      }
 +
 +                      // Given that the content models should match, the current selected
 +                      // format should be supported.
 +                      if ( !$content->isSupportedFormat( $this->contentFormat ) ) {
 +                              $logger->warning( "Current revision content format unsupported. Overriding {prev} to {new}", [
 +
 +                                      'prev' => $this->contentFormat,
 +                                      'new' => $rev->getContentFormat(),
 +                                      'title' => $this->getTitle()->getPrefixedDBkey(),
 +                                      'method' => __METHOD__
 +                              ] );
 +                              $this->contentFormat = $rev->getContentFormat();
 +                      }
  
                        return $content;
                }
                        return $this->mPreloadContent;
                }
  
 -              $handler = ContentHandler::getForTitle( $this->getTitle() );
 +              $handler = ContentHandler::getForModelID( $this->contentModel );
  
                if ( $preload === '' ) {
                        return $handler->makeEmptyContent();
  
                        case self::AS_CANNOT_USE_CUSTOM_MODEL:
                        case self::AS_PARSE_ERROR:
 -                              $wgOut->addWikiText( '<div class="error">' . $status->getWikiText() . '</div>' );
 +                              $wgOut->addWikiText( '<div class="error">' . "\n" . $status->getWikiText() . '</div>' );
                                return true;
  
                        case self::AS_SUCCESS_NEW_ARTICLE:
                                // is if an extension hook aborted from inside ArticleSave.
                                // Render the status object into $this->hookError
                                // FIXME this sucks, we should just use the Status object throughout
 -                              $this->hookError = '<div class="error">' . $status->getWikiText() .
 +                              $this->hookError = '<div class="error">' ."\n" . $status->getWikiText() .
                                        '</div>';
                                return true;
                }
                        return $status;
                }
  
 -              $this->kblength = (int)( strlen( $this->textbox1 ) / 1024 );
 -              if ( $this->kblength > $wgMaxArticleSize ) {
 +              $this->contentLength = strlen( $this->textbox1 );
 +              if ( $this->contentLength > $wgMaxArticleSize * 1024 ) {
                        // Error will be displayed by showEditForm()
                        $this->tooBig = true;
                        $status->setResult( false, self::AS_CONTENT_TOO_BIG );
                }
  
                // Check for length errors again now that the section is merged in
 -              $this->kblength = (int)( strlen( $this->toEditText( $content ) ) / 1024 );
 -              if ( $this->kblength > $wgMaxArticleSize ) {
 +              $this->contentLength = strlen( $this->toEditText( $content ) );
 +              if ( $this->contentLength > $wgMaxArticleSize * 1024 ) {
                        $this->tooBig = true;
                        $status->setResult( false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED );
                        return $status;
                $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
                        Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
  
 -              $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'limitreport' ],
 -                      self::getPreviewLimitReport( $this->mParserOutput ) ) );
 +              if ( $this->mParserOutput ) {
 +                      $wgOut->setLimitReportData( $this->mParserOutput->getLimitReportData() );
 +              }
  
                $wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
  
                                        );
                                }
                                if ( $this->getTitle()->isSubpageOf( $wgUser->getUserPage() ) ) {
 +                                      $wgOut->wrapWikiMsg( '<div class="mw-usercssjspublic">$1</div>',
 +                                              $this->isCssSubpage ? 'usercssispublic' : 'userjsispublic'
 +                                      );
                                        if ( $this->formtype !== 'preview' ) {
                                                if ( $this->isCssSubpage && $wgAllowUserCss ) {
                                                        $wgOut->wrapWikiMsg(
                                        'wrap' => "<div class=\"mw-titleprotectedwarning\">\n$1</div>" ] );
                }
  
 -              if ( $this->kblength === false ) {
 -                      $this->kblength = (int)( strlen( $this->textbox1 ) / 1024 );
 +              if ( $this->contentLength === false ) {
 +                      $this->contentLength = strlen( $this->textbox1 );
                }
  
 -              if ( $this->tooBig || $this->kblength > $wgMaxArticleSize ) {
 +              if ( $this->tooBig || $this->contentLength > $wgMaxArticleSize * 1024 ) {
                        $wgOut->wrapWikiMsg( "<div class='error' id='mw-edit-longpageerror'>\n$1\n</div>",
                                [
                                        'longpageerror',
 -                                      $wgLang->formatNum( $this->kblength ),
 +                                      $wgLang->formatNum( round( $this->contentLength / 1024, 3 ) ),
                                        $wgLang->formatNum( $wgMaxArticleSize )
                                ]
                        );
         * @param string $summary The text of the summary to display
         */
        protected function showSummaryInput( $isSubjectPreview, $summary = "" ) {
 -              global $wgOut, $wgContLang;
 +              global $wgOut;
                # Add a class if 'missingsummary' is triggered to allow styling of the summary line
                $summaryClass = $this->missingSummary ? 'mw-summarymissed' : 'mw-summary';
                if ( $isSubjectPreview ) {
                                return;
                        }
                }
 -              $summary = $wgContLang->recodeForEdit( $summary );
                $labelText = wfMessage( $isSubjectPreview ? 'subject' : 'summary' )->parse();
                list( $label, $input ) = $this->getSummaryInput(
                        $summary,
                        return '';
                }
  
 -              $limitReport = Html::rawElement( 'div', [ 'class' => 'mw-limitReportExplanation' ],
 -                      wfMessage( 'limitreport-title' )->parseAsBlock()
 +              return ResourceLoader::makeInlineScript(
 +                      ResourceLoader::makeConfigSetScript(
 +                              [ 'wgPageParseReport' => $output->getLimitReportData() ],
 +                              true
 +                      )
                );
 -
 -              // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
 -              $limitReport .= Html::openElement( 'div', [ 'class' => 'preview-limit-report-wrapper' ] );
 -
 -              $limitReport .= Html::openElement( 'table', [
 -                      'class' => 'preview-limit-report wikitable'
 -              ] ) .
 -                      Html::openElement( 'tbody' );
 -
 -              foreach ( $output->getLimitReportData() as $key => $value ) {
 -                      if ( Hooks::run( 'ParserLimitReportFormat',
 -                              [ $key, &$value, &$limitReport, true, true ]
 -                      ) ) {
 -                              $keyMsg = wfMessage( $key );
 -                              $valueMsg = wfMessage( [ "$key-value-html", "$key-value" ] );
 -                              if ( !$valueMsg->exists() ) {
 -                                      $valueMsg = new RawMessage( '$1' );
 -                              }
 -                              if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
 -                                      $limitReport .= Html::openElement( 'tr' ) .
 -                                              Html::rawElement( 'th', null, $keyMsg->parse() ) .
 -                                              Html::rawElement( 'td', null, $valueMsg->params( $value )->parse() ) .
 -                                              Html::closeElement( 'tr' );
 -                              }
 -                      }
 -              }
 -
 -              $limitReport .= Html::closeElement( 'tbody' ) .
 -                      Html::closeElement( 'table' ) .
 -                      Html::closeElement( 'div' );
 -
 -              return $limitReport;
        }
  
        protected function showStandardInputs( &$tabindex = 2 ) {
                if ( Hooks::run( 'EditPageBeforeConflictDiff', [ &$this, &$wgOut ] ) ) {
                        $stats = $wgOut->getContext()->getStats();
                        $stats->increment( 'edit.failures.conflict' );
 -                      if ( $this->mTitle->isTalkPage() ) {
 -                              $stats->increment( 'edit.failures.conflict.byType.talk' );
 -                      } else {
 -                              $stats->increment( 'edit.failures.conflict.byType.subject' );
 -                      }
 -                      if ( $this->mTitle->getNamespace() === NS_PROJECT ) {
 -                              $stats->increment( 'edit.failures.conflict.byNamespace.project' );
 +                      // Only include 'standard' namespaces to avoid creating unknown numbers of statsd metrics
 +                      if (
 +                              $this->mTitle->getNamespace() >= NS_MAIN &&
 +                              $this->mTitle->getNamespace() <= NS_CATEGORY_TALK
 +                      ) {
 +                              $stats->increment( 'edit.failures.conflict.byNamespaceId.' . $this->mTitle->getNamespace() );
                        }
  
                        $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
         * @return string
         */
        function getPreviewText() {
 -              global $wgOut, $wgUser, $wgRawHtml, $wgLang;
 +              global $wgOut, $wgRawHtml, $wgLang;
                global $wgAllowUserCss, $wgAllowUserJs;
  
                $stats = $wgOut->getContext()->getStats();
                                $note = wfMessage( 'previewnote' )->plain() . ' ' . $continueEditing;
                        }
  
 -                      $parserOptions = $this->page->makeParserOptions( $this->mArticle->getContext() );
 -                      $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() ) {
                                if ( $this->mTitle->isCssJsSubpage() ) {
                        ContentHandler::runLegacyHooks( 'EditPageGetPreviewText', $hook_args );
                        Hooks::run( 'EditPageGetPreviewContent', $hook_args );
  
 -                      $parserOptions->enableLimitReport();
 -
 -                      # For CSS/JS pages, we should have called the ShowRawCssJs hook here.
 -                      # But it's now deprecated, so never mind
 -
 -                      $pstContent = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
 -                      $scopedCallback = $parserOptions->setupFakeRevision(
 -                              $this->mTitle, $pstContent, $wgUser );
 -                      $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
 -
 -                      $parserOutput->setEditSectionTokens( false ); // no section edit links
 -                      $previewHTML = $parserOutput->getText();
 +                      $parserResult = $this->doPreviewParse( $content );
 +                      $parserOutput = $parserResult['parserOutput'];
 +                      $previewHTML = $parserResult['html'];
                        $this->mParserOutput = $parserOutput;
                        $wgOut->addParserOutputMetadata( $parserOutput );
  
                                $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
                        }
  
 -                      ScopedCallback::consume( $scopedCallback );
                } catch ( MWContentSerializationException $ex ) {
                        $m = wfMessage(
                                'content-failed-to-parse',
                return $previewhead . $previewHTML . $this->previewTextAfterContent;
        }
  
 +      /**
 +       * Get parser options for a preview
 +       * @return ParserOptions
 +       */
 +      protected function getPreviewParserOptions() {
 +              $parserOptions = $this->page->makeParserOptions( $this->mArticle->getContext() );
 +              $parserOptions->setIsPreview( true );
 +              $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
 +              $parserOptions->enableLimitReport();
 +              return $parserOptions;
 +      }
 +
 +      /**
 +       * Parse the page for a preview. Subclasses may override this class, in order
 +       * to parse with different options, or to otherwise modify the preview HTML.
 +       *
 +       * @param Content @content The page content
 +       * @return Associative array with keys:
 +       *   - parserOutput: The ParserOutput object
 +       *   - html: The HTML to be displayed
 +       */
 +      protected function doPreviewParse( Content $content ) {
 +              global $wgUser;
 +              $parserOptions = $this->getPreviewParserOptions();
 +              $pstContent = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
 +              $scopedCallback = $parserOptions->setupFakeRevision(
 +                      $this->mTitle, $pstContent, $wgUser );
 +              $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
 +              ScopedCallback::consume( $scopedCallback );
 +              $parserOutput->setEditSectionTokens( false ); // no section edit links
 +              return [
 +                      'parserOutput' => $parserOutput,
 +                      'html' => $parserOutput->getText() ];
 +      }
 +
        /**
         * @return array
         */
        public function getEditButtons( &$tabindex ) {
                $buttons = [];
  
+               $buttonLabelKey = $this->isNew ? 'savearticle' : 'savechanges';
+               $buttonLabel = wfMessage( $buttonLabelKey )->text();
                $attribs = [
                        'id' => 'wpSave',
                        'name' => 'wpSave',
                        'tabindex' => ++$tabindex,
                ] + Linker::tooltipAndAccesskeyAttribs( 'save' );
-               $buttons['save'] = Html::submitButton( wfMessage( 'savearticle' )->text(),
-                       $attribs, [ 'mw-ui-constructive' ] );
+               $buttons['save'] = Html::submitButton( $buttonLabel, $attribs, [ 'mw-ui-constructive' ] );
  
                ++$tabindex; // use the same for preview and live preview
                $attribs = [
         * @return string
         */
        protected function safeUnicodeOutput( $text ) {
 -              global $wgContLang;
 -              $codedText = $wgContLang->recodeForEdit( $text );
                return $this->checkUnicodeCompliantBrowser()
 -                      ? $codedText
 -                      : $this->makeSafe( $codedText );
 +                      ? $text
 +                      : $this->makesafe( $text );
        }
  
        /**