MediaWiki master
TextConflictHelper.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\EditPage;
8
19
27
32
37
41 protected $yourtext = '';
42
46 protected $storedversion = '';
47
57 public function __construct(
58 protected readonly Title $title,
59 protected readonly OutputPage $out,
60 protected readonly IBufferingStatsdDataFactory|StatsFactory $stats,
61 protected readonly string $submitLabel,
62 private readonly IContentHandlerFactory $contentHandlerFactory
63 ) {
64 $this->contentModel = $title->getContentModel();
65
66 $this->contentFormat = $this->contentHandlerFactory
67 ->getContentHandler( $this->contentModel )
68 ->getDefaultFormat();
69 }
70
76 $this->yourtext = $yourtext;
77 $this->storedversion = $storedversion;
78 }
79
83 public function setContentModel( $contentModel ) {
84 $this->contentModel = $contentModel;
85 }
86
90 public function setContentFormat( $contentFormat ) {
91 $this->contentFormat = $contentFormat;
92 }
93
98 public function incrementConflictStats( ?User $user = null ) {
99 $namespace = 'n/a';
100 $userBucket = 'n/a';
101
102 // Only include 'standard' namespaces to avoid creating unknown numbers of statsd metrics
103 if (
104 $this->title->getNamespace() >= NS_MAIN &&
105 $this->title->getNamespace() <= NS_CATEGORY_TALK
106 ) {
107 // getNsText() returns empty string if getNamespace() === NS_MAIN
108 $namespace = $this->title->getNsText() ?: 'Main';
109 }
110 if ( $user ) {
111 $userBucket = $this->getUserBucket( $user->getEditCount() );
112 }
113 if ( $this->stats instanceof StatsFactory ) {
114 $this->stats->getCounter( 'edit_failure_total' )
115 ->setLabel( 'cause', 'conflict' )
116 ->setLabel( 'namespace', $namespace )
117 ->setLabel( 'user_bucket', $userBucket )
118 ->increment();
119 }
120 }
121
126 public function incrementResolvedStats( ?User $user = null ) {
127 $namespace = 'n/a';
128 $userBucket = 'n/a';
129
130 // Only include 'standard' namespaces to avoid creating unknown numbers of statsd metrics
131 if (
132 $this->title->getNamespace() >= NS_MAIN &&
133 $this->title->getNamespace() <= NS_CATEGORY_TALK
134 ) {
135 // getNsText() returns empty string if getNamespace() === NS_MAIN
136 $namespace = $this->title->getNsText() ?: 'Main';
137 }
138
139 if ( $user ) {
140 $userBucket = $this->getUserBucket( $user->getEditCount() );
141 }
142
143 if ( $this->stats instanceof StatsFactory ) {
144 $this->stats->getCounter( 'edit_failure_resolved_total' )
145 ->setLabel( 'cause', 'conflict' )
146 ->setLabel( 'namespace', $namespace )
147 ->setLabel( 'user_bucket', $userBucket )
148 ->increment();
149 }
150 }
151
161 protected function incrementStatsByUserEdits( $userEdits, $keyPrefixBase ) {
162 if ( $this->stats instanceof IBufferingStatsdDataFactory ) {
163 $this->stats->increment( $keyPrefixBase . '.byUserEdits.' . $this->getUserBucket( $userEdits ) );
164 }
165 }
166
171 protected function getUserBucket( ?int $userEdits ): string {
172 if ( $userEdits === null ) {
173 return 'anon';
174 } elseif ( $userEdits > 200 ) {
175 return 'over200';
176 } elseif ( $userEdits > 100 ) {
177 return 'over100';
178 } elseif ( $userEdits > 10 ) {
179 return 'over10';
180 } else {
181 return 'under11';
182 }
183 }
184
188 public function getExplainHeader() {
189 return Html::rawElement(
190 'div',
191 [ 'class' => 'mw-explainconflict' ],
192 $this->out->msg( 'explainconflict', $this->out->msg( $this->submitLabel ) )->parse()
193 );
194 }
195
202 public function getEditConflictMainTextBox( array $customAttribs = [] ) {
203 $builder = new TextboxBuilder();
204 $classes = $builder->getTextboxProtectionCSSClasses( $this->title );
205
206 $attribs = [
207 'aria-label' => $this->out->msg( 'edit-textarea-aria-label' )->text(),
208 'tabindex' => 1,
209 ];
210 $attribs += $customAttribs;
211 foreach ( $classes as $class ) {
212 Html::addClass( $attribs['class'], $class );
213 }
214
215 $attribs = $builder->buildTextboxAttribs(
216 'wpTextbox1',
217 $attribs,
218 $this->out->getUser(),
219 $this->title
220 );
221
222 return Html::textarea(
223 'wpTextbox1',
224 $builder->addNewLineAtEnd( $this->storedversion ),
225 $attribs
226 );
227 }
228
236 return '';
237 }
238
245 public function getEditFormHtmlAfterContent() {
246 return '';
247 }
248
254 $this->out->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
255
256 $yourContent = $this->toEditContent( $this->yourtext );
257 $storedContent = $this->toEditContent( $this->storedversion );
258 $handler = $this->contentHandlerFactory->getContentHandler( $this->contentModel );
259 $diffEngine = $handler->createDifferenceEngine( $this->out );
260
261 $diffEngine->setContent( $yourContent, $storedContent );
262 $diffEngine->showDiff(
263 $this->out->msg( 'yourtext' )->parse(),
264 $this->out->msg( 'storedversion' )->text()
265 );
266
267 $this->out->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
268
269 $builder = new TextboxBuilder();
270 $attribs = $builder->buildTextboxAttribs(
271 'wpTextbox2',
272 [ 'tabindex' => 6, 'readonly' ],
273 $this->out->getUser(),
274 $this->title
275 );
276
277 $this->out->addHTML(
278 Html::textarea( 'wpTextbox2', $builder->addNewLineAtEnd( $this->yourtext ), $attribs )
279 );
280 }
281
286 private function toEditContent( $text ) {
287 return ContentHandler::makeContent(
288 $text,
289 $this->title,
290 $this->contentModel,
291 $this->contentFormat
292 );
293 }
294}
const NS_MAIN
Definition Defines.php:51
const NS_CATEGORY_TALK
Definition Defines.php:66
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:69
Base class for content handling.
Exception thrown when an unregistered content model is requested.
Helper for displaying edit conflicts in text content models to users.
incrementConflictStats(?User $user=null)
Record a user encountering an edit conflict.
__construct(protected readonly Title $title, protected readonly OutputPage $out, protected readonly IBufferingStatsdDataFactory|StatsFactory $stats, protected readonly string $submitLabel, private readonly IContentHandlerFactory $contentHandlerFactory)
getEditFormHtmlAfterContent()
Content to go in the edit form after textbox1.
getEditConflictMainTextBox(array $customAttribs=[])
HTML to build the textbox1 on edit conflicts.
showEditFormTextAfterFooters()
Content to go in the edit form after the footers (templates on this page, hidden categories,...
incrementResolvedStats(?User $user=null)
Record when a user has resolved an edit conflict.
setTextboxes( $yourtext, $storedversion)
incrementStatsByUserEdits( $userEdits, $keyPrefixBase)
Retained temporarily for backwards-compatibility.
getEditFormHtmlBeforeContent()
Content to go in the edit form before textbox1.
Helps EditPage build textboxes.
This class is a collection of static functions that serve two purposes:
Definition Html.php:44
This is one of the Core classes and should be read at least once by any new developers.
Represents a title within MediaWiki.
Definition Title.php:69
User class for the MediaWiki software.
Definition User.php:130
This is the primary interface for validating metrics definitions, caching defined metrics,...
Content objects represent page content, e.g.
Definition Content.php:28
MediaWiki adaptation of StatsdDataFactory that provides buffering functionality.