Merge "resources: Strip '$' and 'mw' from file closures"
[lhc/web/wiklou.git] / includes / EditPage.php
index 16f1c5a..f1f0572 100644 (file)
@@ -236,7 +236,7 @@ class EditPage {
        public $action = 'submit';
 
        /** @var bool Whether an edit conflict needs to be resolved. Detected based on whether
-        * $editRevId is different from the current revision. When a conflict has successfully
+        * $editRevId is different than the latest revision. When a conflict has successfully
         * been resolved by a 3-way-merge, this field is set to false.
         */
        public $isConflict = false;
@@ -250,7 +250,10 @@ class EditPage {
        /** @var string */
        public $formtype;
 
-       /** @var bool */
+       /** @var bool
+        * True the first time the edit form is rendered, false after re-rendering
+        * with diff, save prompts, etc.
+        */
        public $firsttime;
 
        /** @var bool|stdClass */
@@ -330,7 +333,9 @@ class EditPage {
        /** @var bool */
        public $recreate = false;
 
-       /** @var string */
+       /** @var string
+        * Page content input field.
+        */
        public $textbox1 = '';
 
        /** @var string */
@@ -339,18 +344,24 @@ class EditPage {
        /** @var string */
        public $summary = '';
 
-       /** @var bool */
+       /** @var bool
+        * If true, hide the summary field.
+        */
        public $nosummary = false;
 
-       /** @var string */
+       /** @var string
+        * Timestamp of the latest revision of the page when editing was initiated
+        * on the client.
+        */
        public $edittime = '';
 
-       /** @var int ID of the current revision at the time editing was initiated on the client.
-        * This is used to detect and resolve edit conflicts.
+       /** @var int Revision ID of the latest revision of the page when editing
+        * was initiated on the client.  This is used to detect and resolve edit
+        * conflicts.
         *
         * @note 0 if the page did not exist at that time.
         * @note When starting an edit from an old revision, this still records the current
-        * revision at the time , not the one the edit is based on.
+        * revision at the time, not the one the edit is based on.
         *
         * @see $oldid
         * @see getBaseRevision()
@@ -363,10 +374,14 @@ class EditPage {
        /** @var string */
        public $sectiontitle = '';
 
-       /** @var string */
+       /** @var string
+        * Timestamp from the first time the edit form was rendered.
+        */
        public $starttime = '';
 
        /** @var int Revision ID the edit is based on, or 0 if it's the current revision.
+        * FIXME: This isn't used in conflict resolution--provide a better
+        * justification or merge with parentRevId.
         * @see $editRevId
         */
        public $oldid = 0;
@@ -669,7 +684,10 @@ class EditPage {
                # checking, etc.
                if ( 'initial' == $this->formtype || $this->firsttime ) {
                        if ( $this->initialiseForm() === false ) {
-                               $this->noSuchSectionPage();
+                               $out = $this->context->getOutput();
+                               if ( $out->getRedirect() === '' ) { // mcrundo hack redirects, don't override it
+                                       $this->noSuchSectionPage();
+                               }
                                return;
                        }
 
@@ -1040,7 +1058,7 @@ class EditPage {
                                $this->sectiontitle = $request->getVal( 'preloadtitle' );
                                // Once wpSummary isn't being use for setting section titles, we should delete this.
                                $this->summary = $request->getVal( 'preloadtitle' );
-                       } elseif ( $this->section != 'new' && $request->getVal( 'summary' ) ) {
+                       } elseif ( $this->section != 'new' && $request->getVal( 'summary' ) !== '' ) {
                                $this->summary = $request->getText( 'summary' );
                                if ( $this->summary !== '' ) {
                                        $this->hasPresetSummary = true;
@@ -1156,8 +1174,6 @@ class EditPage {
         * @since 1.21
         */
        protected function getContentObject( $def_content = null ) {
-               global $wgContLang;
-
                $content = false;
 
                $user = $this->context->getUser();
@@ -1207,8 +1223,13 @@ class EditPage {
                                                !$oldrev->isDeleted( Revision::DELETED_TEXT )
                                        ) {
                                                if ( WikiPage::hasDifferencesOutsideMainSlot( $undorev, $oldrev ) ) {
-                                                       // Cannot yet undo edits that involve anything other the main slot.
-                                                       $undoMsg = 'main-slot-only';
+                                                       // Hack for undo while EditPage can't handle multi-slot editing
+                                                       $this->context->getOutput()->redirect( $this->mTitle->getFullURL( [
+                                                               'action' => 'mcrundo',
+                                                               'undo' => $undo,
+                                                               'undoafter' => $undoafter,
+                                                       ] ) );
+                                                       return false;
                                                } else {
                                                        $content = $this->page->getUndoContent( $undorev, $oldrev );
 
@@ -1220,7 +1241,8 @@ class EditPage {
 
                                                if ( $undoMsg === null ) {
                                                        $oldContent = $this->page->getContent( Revision::RAW );
-                                                       $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
+                                                       $popts = ParserOptions::newFromUserAndLang(
+                                                               $user, MediaWikiServices::getInstance()->getContentLanguage() );
                                                        $newContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
                                                        if ( $newContent->getModel() !== $oldContent->getModel() ) {
                                                                // The undo may change content
@@ -1667,7 +1689,7 @@ class EditPage {
                                // 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">' ."\n" . $status->getWikiText() .
+                               $this->hookError = '<div class="error">' . "\n" . $status->getWikiText() .
                                        '</div>';
                                return true;
                }
@@ -1760,7 +1782,7 @@ ERROR;
                        if ( $this->summary === '' ) {
                                $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
                                return $this->context->msg( 'newsectionsummary' )
-                                       ->rawParams( $cleanSectionTitle )->inContentLanguage()->text();
+                                       ->plaintextParams( $cleanSectionTitle )->inContentLanguage()->text();
                        }
                } elseif ( $this->summary !== '' ) {
                        $sectionanchor = $this->guessSectionName( $this->summary );
@@ -1768,7 +1790,7 @@ ERROR;
                        # in the revision summary.
                        $cleanSummary = $wgParser->stripSectionName( $this->summary );
                        return $this->context->msg( 'newsectionsummary' )
-                               ->rawParams( $cleanSummary )->inContentLanguage()->text();
+                               ->plaintextParams( $cleanSummary )->inContentLanguage()->text();
                }
                return $this->summary;
        }
@@ -2468,6 +2490,8 @@ ERROR;
                $displayTitle = isset( $this->mParserOutput ) ? $this->mParserOutput->getDisplayTitle() : false;
                if ( $displayTitle === false ) {
                        $displayTitle = $contextTitle->getPrefixedText();
+               } else {
+                       $out->setDisplayTitle( $displayTitle );
                }
                $out->setPageTitle( $this->context->msg( $msg, $displayTitle ) );
 
@@ -2847,7 +2871,7 @@ ERROR;
                        $this->autoSumm = md5( '' );
                }
 
-               $autosumm = $this->autoSumm ?: md5( $this->summary );
+               $autosumm = $this->autoSumm !== '' ? $this->autoSumm : md5( $this->summary );
                $out->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) );
 
                $out->addHTML( Html::hidden( 'oldid', $this->oldid ) );
@@ -3167,7 +3191,7 @@ ERROR;
        }
 
        /**
-        * Helper function for summary input functions, which returns the neccessary
+        * Helper function for summary input functions, which returns the necessary
         * attributes for the input.
         *
         * @param array|null $inputAttrs Array of attrs to use on the input
@@ -3446,8 +3470,6 @@ ERROR;
         * save and then make a comparison.
         */
        public function showDiff() {
-               global $wgContLang;
-
                $oldtitlemsg = 'currentrev';
                # if message does not exist, show diff against the preloaded default
                if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !$this->mTitle->exists() ) {
@@ -3477,7 +3499,8 @@ ERROR;
                        Hooks::run( 'EditPageGetDiffContent', [ $this, &$newContent ] );
 
                        $user = $this->context->getUser();
-                       $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
+                       $popts = ParserOptions::newFromUserAndLang( $user,
+                               MediaWikiServices::getInstance()->getContentLanguage() );
                        $newContent = $newContent->preSaveTransform( $this->mTitle, $user, $popts );
                }
 
@@ -3588,10 +3611,10 @@ ERROR;
         * Get the Limit report for page previews
         *
         * @since 1.22
-        * @param ParserOutput $output ParserOutput object from the parse
+        * @param ParserOutput|null $output ParserOutput object from the parse
         * @return string HTML
         */
-       public static function getPreviewLimitReport( $output ) {
+       public static function getPreviewLimitReport( ParserOutput $output = null ) {
                global $wgLang;
 
                if ( !$output || !$output->getLimitReportData() ) {
@@ -3764,6 +3787,8 @@ ERROR;
        }
 
        /**
+        * Get the last log record of this page being deleted, if ever.  This is
+        * used to detect whether a delete occurred during editing.
         * @return bool|stdClass
         */
        protected function getLastDelete() {
@@ -3974,6 +3999,12 @@ ERROR;
                $parserOptions->setIsPreview( true );
                $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
                $parserOptions->enableLimitReport();
+
+               // XXX: we could call $parserOptions->setCurrentRevisionCallback here to force the
+               // current revision to be null during PST, until setupFakeRevision is called on
+               // the ParserOptions. Currently, we rely on Parser::getRevisionObject() to ignore
+               // existing revisions in preview mode.
+
                return $parserOptions;
        }
 
@@ -3989,9 +4020,14 @@ ERROR;
        protected function doPreviewParse( Content $content ) {
                $user = $this->context->getUser();
                $parserOptions = $this->getPreviewParserOptions();
+
+               // NOTE: preSaveTransform doesn't have a fake revision to operate on.
+               // Parser::getRevisionObject() will return null in preview mode,
+               // causing the context user to be used for {{subst:REVISIONUSER}}.
+               // XXX: Alternatively, we could also call setupFakeRevision() a second time:
+               // once before PST with $content, and then after PST with $pstContent.
                $pstContent = $content->preSaveTransform( $this->mTitle, $user, $parserOptions );
-               $scopedCallback = $parserOptions->setupFakeRevision(
-                       $this->mTitle, $pstContent, $user );
+               $scopedCallback = $parserOptions->setupFakeRevision( $this->mTitle, $pstContent, $user );
                $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
                ScopedCallback::consume( $scopedCallback );
                return [
@@ -4030,8 +4066,7 @@ ERROR;
         * @return string
         */
        public static function getEditToolbar( $title = null ) {
-               global $wgContLang, $wgOut;
-               global $wgEnableUploads, $wgForeignFileRepos;
+               global $wgOut, $wgEnableUploads, $wgForeignFileRepos;
 
                $imagesAvailable = $wgEnableUploads || count( $wgForeignFileRepos );
                $showSignature = true;
@@ -4039,6 +4074,8 @@ ERROR;
                        $showSignature = MWNamespace::wantSignatures( $title->getNamespace() );
                }
 
+               $contLang = MediaWikiServices::getInstance()->getContentLanguage();
+
                /**
                 * $toolarray is an array of arrays each of which includes the
                 * opening tag, the closing tag, optionally a sample text that is
@@ -4086,14 +4123,14 @@ ERROR;
                        ],
                        $imagesAvailable ? [
                                'id'     => 'mw-editbutton-image',
-                               'open'   => '[[' . $wgContLang->getNsText( NS_FILE ) . ':',
+                               'open'   => '[[' . $contLang->getNsText( NS_FILE ) . ':',
                                'close'  => ']]',
                                'sample' => wfMessage( 'image_sample' )->text(),
                                'tip'    => wfMessage( 'image_tip' )->text(),
                        ] : false,
                        $imagesAvailable ? [
                                'id'     => 'mw-editbutton-media',
-                               'open'   => '[[' . $wgContLang->getNsText( NS_MEDIA ) . ':',
+                               'open'   => '[[' . $contLang->getNsText( NS_MEDIA ) . ':',
                                'close'  => ']]',
                                'sample' => wfMessage( 'media_sample' )->text(),
                                'tip'    => wfMessage( 'media_tip' )->text(),
@@ -4121,7 +4158,7 @@ ERROR;
                        ]
                ];
 
-               $script = 'mw.loader.using("mediawiki.toolbar", function () {';
+               $script = '';
                foreach ( $toolarray as $tool ) {
                        if ( !$tool ) {
                                continue;
@@ -4148,15 +4185,16 @@ ERROR;
                        );
                }
 
-               $script .= '});';
-
                $toolbar = '<div id="toolbar"></div>';
 
                if ( Hooks::run( 'EditPageBeforeEditToolbar', [ &$toolbar ] ) ) {
                        // Only add the old toolbar cruft to the page payload if the toolbar has not
                        // been over-written by a hook caller
                        $nonce = $wgOut->getCSPNonce();
-                       $wgOut->addScript( ResourceLoader::makeInlineScript( $script, $nonce ) );
+                       $wgOut->addScript( Html::inlineScript(
+                               ResourceLoader::makeInlineCodeWithModule( 'mediawiki.toolbar', $script ),
+                               $nonce
+                       ) );
                };
 
                return $toolbar;