X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FEditPage.php;h=bcaab3a3d70e6bc69df5801f93d7bfb731971c68;hb=4eff5204d9ec6eb09df70d2fe017a2146cfa4238;hp=3fc12ced8c64981dca2a62f1ebd6819ac6a7f400;hpb=b476029e2dedbb9674e78b509f704f013c1bea0f;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/EditPage.php b/includes/EditPage.php index 3fc12ced8c..d49f2051e9 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -20,6 +20,8 @@ * @file */ +use MediaWiki\EditPage\TextboxBuilder; +use MediaWiki\EditPage\TextConflictHelper; use MediaWiki\Logger\LoggerFactory; use MediaWiki\MediaWikiServices; use Wikimedia\ScopedCallback; @@ -446,6 +448,18 @@ class EditPage { */ private $unicodeCheck; + /** + * Factory function to create an edit conflict helper + * + * @var callable + */ + private $editConflictHelperFactory; + + /** + * @var TextConflictHelper|null + */ + private $editConflictHelper; + /** * @param Article $article */ @@ -459,6 +473,7 @@ class EditPage { $handler = ContentHandler::getForModelID( $this->contentModel ); $this->contentFormat = $handler->getDefaultFormat(); + $this->editConflictHelperFactory = [ $this, 'newTextConflictHelper' ]; } /** @@ -765,7 +780,7 @@ class EditPage { /** * Display a read-only View Source page - * @param Content $content content object + * @param Content $content * @param string $errorMessage additional wikitext error message to display */ protected function displayViewSourcePage( Content $content, $errorMessage = '' ) { @@ -1534,8 +1549,7 @@ class EditPage { return; } - $stats = MediaWikiServices::getInstance()->getStatsdDataFactory(); - $stats->increment( 'edit.failures.conflict.resolved' ); + $this->getEditConflictHelper()->incrementResolvedStats(); } /** @@ -1703,7 +1717,7 @@ class EditPage { // being set. This is used by ConfirmEdit to display a captcha // without any error message cruft. } else { - $this->hookError = $status->getWikiText(); + $this->hookError = $this->formatStatusErrors( $status ); } // Use the existing $status->value if the hook set it if ( !$status->value ) { @@ -1713,7 +1727,7 @@ class EditPage { } elseif ( !$status->isOK() ) { # ...or the hook could be expecting us to produce an error // FIXME this sucks, we should just use the Status object throughout - $this->hookError = $status->getWikiText(); + $this->hookError = $this->formatStatusErrors( $status ); $status->fatal( 'hookaborted' ); $status->value = self::AS_HOOK_ERROR_EXPECTED; return false; @@ -1722,6 +1736,26 @@ class EditPage { return true; } + /** + * Wrap status errors in an errorbox for increased visiblity + * + * @param Status $status + * @return string Wikitext + */ + private function formatStatusErrors( Status $status ) { + $errmsg = $status->getWikiText( + 'edit-error-short', + 'edit-error-long', + $this->context->getLanguage() + ); + return << +{$errmsg} + +
+ERROR; + } + /** * Return the summary to be used for a new section. * @@ -2394,6 +2428,7 @@ class EditPage { $out->addModules( 'mediawiki.action.edit' ); $out->addModuleStyles( 'mediawiki.action.edit.styles' ); + $out->addModuleStyles( 'mediawiki.editfont.styles' ); $user = $this->context->getUser(); if ( $user->getOption( 'showtoolbar' ) ) { @@ -2818,6 +2853,20 @@ class EditPage { } $out->addHTML( $this->editFormTextBeforeContent ); + if ( $this->isConflict ) { + // In an edit conflict, we turn textbox2 into the user's text, + // and textbox1 into the stored version + $this->textbox2 = $this->textbox1; + + $content = $this->getCurrentContent(); + $this->textbox1 = $this->toEditText( $content ); + + $editConflictHelper = $this->getEditConflictHelper(); + $editConflictHelper->setTextboxes( $this->textbox2, $this->textbox1 ); + $editConflictHelper->setContentModel( $this->contentModel ); + $editConflictHelper->setContentFormat( $this->contentFormat ); + $out->addHTML( $editConflictHelper->getEditFormHtmlBeforeContent() ); + } if ( !$this->mTitle->isCssJsSubpage() && $showToolbar && $user->getOption( 'showtoolbar' ) ) { $out->addHTML( self::getEditToolbar( $this->mTitle ) ); @@ -2832,12 +2881,15 @@ class EditPage { // and fallback to the raw wpTextbox1 since editconflicts can't be // resolved between page source edits and custom ui edits using the // custom edit ui. - $this->textbox2 = $this->textbox1; - - $content = $this->getCurrentContent(); - $this->textbox1 = $this->toEditText( $content ); + $conflictTextBoxAttribs = []; + if ( $this->wasDeletedSinceLastEdit() ) { + $conflictTextBoxAttribs['style'] = 'display:none;'; + } elseif ( $this->isOldRev ) { + $conflictTextBoxAttribs['class'] = 'mw-textarea-oldrev'; + } - $this->showTextbox1(); + $out->addHTML( $editConflictHelper->getEditConflictMainTextBox( $conflictTextBoxAttribs ) ); + $out->addHTML( $editConflictHelper->getEditFormHtmlAfterContent() ); } else { $this->showContentForm(); } @@ -3166,7 +3218,7 @@ class EditPage { */ function getSummaryInputOOUI( $summary = "", $labelText = null, $inputAttrs = null ) { wfDeprecated( __METHOD__, '1.30' ); - $this->getSummaryInputWidget( $summary, $labelText, $inputAttrs ); + return $this->getSummaryInputWidget( $summary, $labelText, $inputAttrs ); } /** @@ -3263,7 +3315,7 @@ class EditPage { protected function showFormBeforeText() { $out = $this->context->getOutput(); - $out->addHTML( Html::hidden( 'wpSection', htmlspecialchars( $this->section ) ) ); + $out->addHTML( Html::hidden( 'wpSection', $this->section ) ); $out->addHTML( Html::hidden( 'wpStarttime', $this->starttime ) ); $out->addHTML( Html::hidden( 'wpEdittime', $this->edittime ) ); $out->addHTML( Html::hidden( 'editRevId', $this->editRevId ) ); @@ -3314,22 +3366,9 @@ class EditPage { if ( $this->wasDeletedSinceLastEdit() && $this->formtype == 'save' ) { $attribs = [ 'style' => 'display:none;' ]; } else { - $classes = []; // Textarea CSS - if ( $this->mTitle->isProtected( 'edit' ) && - MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) !== [ '' ] - ) { - # Is the title semi-protected? - if ( $this->mTitle->isSemiProtected() ) { - $classes[] = 'mw-textarea-sprotected'; - } else { - # Then it must be protected based on static groups (regular) - $classes[] = 'mw-textarea-protected'; - } - # Is the title cascade-protected? - if ( $this->mTitle->isCascadeProtected() ) { - $classes[] = 'mw-textarea-cprotected'; - } - } + $builder = new TextboxBuilder(); + $classes = $builder->getTextboxProtectionCSSClasses( $this->getTitle() ); + # Is an old revision being edited? if ( $this->isOldRev ) { $classes[] = 'mw-textarea-oldrev'; @@ -3341,12 +3380,7 @@ class EditPage { $attribs += $customAttribs; } - if ( count( $classes ) ) { - if ( isset( $attribs['class'] ) ) { - $classes[] = $attribs['class']; - } - $attribs['class'] = implode( ' ', $classes ); - } + $attribs = $builder->mergeClassesIntoAttributes( $classes, $attribs ); } $this->showTextbox( @@ -3361,11 +3395,17 @@ class EditPage { } protected function showTextbox( $text, $name, $customAttribs = [] ) { - $wikitext = $this->addNewLineAtEnd( $text ); - - $attribs = $this->buildTextboxAttribs( $name, $customAttribs, $this->context->getUser() ); + $builder = new TextboxBuilder(); + $attribs = $builder->buildTextboxAttribs( + $name, + $customAttribs, + $this->context->getUser(), + $this->mTitle + ); - $this->context->getOutput()->addHTML( Html::textarea( $name, $wikitext, $attribs ) ); + $this->context->getOutput()->addHTML( + Html::textarea( $name, $builder->addNewLineAtEnd( $text ), $attribs ) + ); } protected function displayPreviewArea( $previewOutput, $isOnTop = false ) { @@ -3584,6 +3624,8 @@ class EditPage { * @return string HTML */ public static function getPreviewLimitReport( $output ) { + global $wgLang; + if ( !$output || !$output->getLimitReportData() ) { return ''; } @@ -3612,7 +3654,9 @@ class EditPage { if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) { $limitReport .= Html::openElement( 'tr' ) . Html::rawElement( 'th', null, $keyMsg->parse() ) . - Html::rawElement( 'td', null, $valueMsg->params( $value )->parse() ) . + Html::rawElement( 'td', null, + $wgLang->formatNum( $valueMsg->params( $value )->parse() ) + ) . Html::closeElement( 'tr' ); } } @@ -3650,11 +3694,6 @@ class EditPage { $out->addHTML( implode( $this->getEditButtons( $tabindex ), "\n" ) . "\n" ); $cancel = $this->getCancelLink(); - if ( $cancel !== '' ) { - $cancel .= Html::element( 'span', - [ 'class' => 'mw-editButtons-pipe-separator' ], - $this->context->msg( 'pipe-separator' )->text() ); - } $message = $this->context->msg( 'edithelppage' )->inContentLanguage()->text(); $edithelpurl = Skin::makeInternalOrExternalUrl( $message ); @@ -3687,34 +3726,12 @@ class EditPage { if ( Hooks::run( 'EditPageBeforeConflictDiff', [ &$editPage, &$out ] ) ) { $this->incrementConflictStats(); - $out->wrapWikiMsg( '

$1

', "yourdiff" ); - - $content1 = $this->toEditContent( $this->textbox1 ); - $content2 = $this->toEditContent( $this->textbox2 ); - - $handler = ContentHandler::getForModelID( $this->contentModel ); - $de = $handler->createDifferenceEngine( $this->context ); - $de->setContent( $content2, $content1 ); - $de->showDiff( - $this->context->msg( 'yourtext' )->parse(), - $this->context->msg( 'storedversion' )->text() - ); - - $out->wrapWikiMsg( '

$1

', "yourtext" ); - $this->showTextbox2(); + $this->getEditConflictHelper()->showEditFormTextAfterFooters(); } } protected function incrementConflictStats() { - $stats = MediaWikiServices::getInstance()->getStatsdDataFactory(); - $stats->increment( 'edit.failures.conflict' ); - // 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() ); - } + $this->getEditConflictHelper()->incrementConflictStats(); } /** @@ -3730,7 +3747,7 @@ class EditPage { return new OOUI\ButtonWidget( [ 'id' => 'mw-editform-cancel', - 'href' => $this->getContextTitle()->getLinkUrl( $cancelParams ), + 'href' => $this->getContextTitle()->getLinkURL( $cancelParams ), 'label' => new OOUI\HtmlSnippet( $this->context->msg( 'cancel' )->parse() ), 'framed' => false, 'infusable' => true, @@ -4003,7 +4020,10 @@ class EditPage { $parserOutput->setEditSectionTokens( false ); // no section edit links return [ 'parserOutput' => $parserOutput, - 'html' => $parserOutput->getText() ]; + 'html' => $parserOutput->getText( [ + 'enableSectionEditLinks' => false + ] ) + ]; } /** @@ -4392,34 +4412,32 @@ class EditPage { public function getEditButtons( &$tabindex ) { $buttons = []; - $buttonLabel = $this->context->msg( $this->getSubmitButtonLabel() )->text(); + $labelAsPublish = + $this->context->getConfig()->get( 'EditSubmitButtonLabelPublish' ); - $attribs = [ - 'name' => 'wpSave', - 'tabindex' => ++$tabindex, - ]; + $buttonLabel = $this->context->msg( $this->getSubmitButtonLabel() )->text(); + $buttonTooltip = $labelAsPublish ? 'publish' : 'save'; - $saveConfig = OOUI\Element::configFromHtmlAttributes( $attribs ); $buttons['save'] = new OOUI\ButtonInputWidget( [ + 'name' => 'wpSave', + 'tabIndex' => ++$tabindex, 'id' => 'wpSaveWidget', 'inputId' => 'wpSave', // Support: IE 6 – Use , otherwise it can't distinguish which button was clicked 'useInputTag' => true, - 'flags' => [ 'constructive', 'primary' ], + 'flags' => [ 'progressive', 'primary' ], 'label' => $buttonLabel, 'infusable' => true, 'type' => 'submit', - 'title' => Linker::titleAttrib( 'save' ), - 'accessKey' => Linker::accesskey( 'save' ), - ] + $saveConfig ); - - $attribs = [ - 'name' => 'wpPreview', - 'tabindex' => ++$tabindex, - ]; + // Messages used: tooltip-save, tooltip-publish + 'title' => Linker::titleAttrib( $buttonTooltip ), + // Messages used: accesskey-save, accesskey-publish + 'accessKey' => Linker::accesskey( $buttonTooltip ), + ] ); - $previewConfig = OOUI\Element::configFromHtmlAttributes( $attribs ); $buttons['preview'] = new OOUI\ButtonInputWidget( [ + 'name' => 'wpPreview', + 'tabIndex' => ++$tabindex, 'id' => 'wpPreviewWidget', 'inputId' => 'wpPreview', // Support: IE 6 – Use , otherwise it can't distinguish which button was clicked @@ -4427,17 +4445,15 @@ class EditPage { 'label' => $this->context->msg( 'showpreview' )->text(), 'infusable' => true, 'type' => 'submit', + // Message used: tooltip-preview 'title' => Linker::titleAttrib( 'preview' ), + // Message used: accesskey-preview 'accessKey' => Linker::accesskey( 'preview' ), - ] + $previewConfig ); - - $attribs = [ - 'name' => 'wpDiff', - 'tabindex' => ++$tabindex, - ]; + ] ); - $diffConfig = OOUI\Element::configFromHtmlAttributes( $attribs ); $buttons['diff'] = new OOUI\ButtonInputWidget( [ + 'name' => 'wpDiff', + 'tabIndex' => ++$tabindex, 'id' => 'wpDiffWidget', 'inputId' => 'wpDiff', // Support: IE 6 – Use , otherwise it can't distinguish which button was clicked @@ -4445,9 +4461,11 @@ class EditPage { 'label' => $this->context->msg( 'showdiff' )->text(), 'infusable' => true, 'type' => 'submit', + // Message used: tooltip-diff 'title' => Linker::titleAttrib( 'diff' ), + // Message used: accesskey-diff 'accessKey' => Linker::accesskey( 'diff' ), - ] + $diffConfig ); + ] ); // Avoid PHP 7.1 warning of passing $this by reference $editPage = $this; @@ -4639,9 +4657,8 @@ class EditPage { * @since 1.29 */ protected function addExplainConflictHeader( OutputPage $out ) { - $out->wrapWikiMsg( - "
\n$1\n
", - [ 'explainconflict', $this->context->msg( $this->getSubmitButtonLabel() )->text() ] + $out->addHTML( + $this->getEditConflictHelper()->getExplainHeader() ); } @@ -4653,37 +4670,9 @@ class EditPage { * @since 1.29 */ protected function buildTextboxAttribs( $name, array $customAttribs, User $user ) { - $attribs = $customAttribs + [ - 'accesskey' => ',', - 'id' => $name, - 'cols' => 80, - 'rows' => 25, - // Avoid PHP notices when appending preferences - // (appending allows customAttribs['style'] to still work). - 'style' => '' - ]; - - // The following classes can be used here: - // * mw-editfont-monospace - // * mw-editfont-sans-serif - // * mw-editfont-serif - $class = 'mw-editfont-' . $user->getOption( 'editfont' ); - - if ( isset( $attribs['class'] ) ) { - if ( is_string( $attribs['class'] ) ) { - $attribs['class'] .= ' ' . $class; - } elseif ( is_array( $attribs['class'] ) ) { - $attribs['class'][] = $class; - } - } else { - $attribs['class'] = $class; - } - - $pageLang = $this->mTitle->getPageLanguage(); - $attribs['lang'] = $pageLang->getHtmlCode(); - $attribs['dir'] = $pageLang->getDir(); - - return $attribs; + return ( new TextboxBuilder() )->buildTextboxAttribs( + $name, $customAttribs, $user, $this->mTitle + ); } /** @@ -4692,15 +4681,7 @@ class EditPage { * @since 1.29 */ protected function addNewLineAtEnd( $wikitext ) { - if ( strval( $wikitext ) !== '' ) { - // Ensure there's a newline at the end, otherwise adding lines - // is awkward. - // But don't add a newline if the text is empty, or Firefox in XHTML - // mode will show an extra newline. A bit annoying. - $wikitext .= "\n"; - return $wikitext; - } - return $wikitext; + return ( new TextboxBuilder() )->addNewLineAtEnd( $wikitext ); } /** @@ -4725,4 +4706,42 @@ class EditPage { // Meanwhile, real browsers get real anchors return $wgParser->guessSectionNameFromWikiText( $text ); } + + /** + * Set a factory function to create an EditConflictHelper + * + * @param callable $factory Factory function + * @since 1.31 + */ + public function setEditConflictHelperFactory( callable $factory ) { + $this->editConflictHelperFactory = $factory; + $this->editConflictHelper = null; + } + + /** + * @return TextConflictHelper + */ + private function getEditConflictHelper() { + if ( !$this->editConflictHelper ) { + $this->editConflictHelper = call_user_func( + $this->editConflictHelperFactory, + $this->getSubmitButtonLabel() + ); + } + + return $this->editConflictHelper; + } + + /** + * @param string $submitButtonLabel + * @return TextConflictHelper + */ + private function newTextConflictHelper( $submitButtonLabel ) { + return new TextConflictHelper( + $this->getTitle(), + $this->getContext()->getOutput(), + MediaWikiServices::getInstance()->getStatsdDataFactory(), + $submitButtonLabel + ); + } }