Index: trunk/phase3/includes/EditPage.php |
— | — | @@ -161,201 +161,6 @@ |
162 | 162 | } |
163 | 163 | } |
164 | 164 | |
165 | | - /** |
166 | | - * Fetch initial editing page content. |
167 | | - * |
168 | | - * @param $def_text string |
169 | | - * @return mixed string on success, $def_text for invalid sections |
170 | | - * @private |
171 | | - */ |
172 | | - function getContent( $def_text = '' ) { |
173 | | - global $wgOut, $wgRequest, $wgParser; |
174 | | - |
175 | | - wfProfileIn( __METHOD__ ); |
176 | | - # Get variables from query string :P |
177 | | - $section = $wgRequest->getVal( 'section' ); |
178 | | - |
179 | | - $preload = $wgRequest->getVal( 'preload', |
180 | | - // Custom preload text for new sections |
181 | | - $section === 'new' ? 'MediaWiki:addsection-preload' : '' ); |
182 | | - $undoafter = $wgRequest->getVal( 'undoafter' ); |
183 | | - $undo = $wgRequest->getVal( 'undo' ); |
184 | | - |
185 | | - // For message page not locally set, use the i18n message. |
186 | | - // For other non-existent articles, use preload text if any. |
187 | | - if ( !$this->mTitle->exists() ) { |
188 | | - if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { |
189 | | - # If this is a system message, get the default text. |
190 | | - $text = $this->mTitle->getDefaultMessageText(); |
191 | | - if( $text === false ) { |
192 | | - $text = $this->getPreloadedText( $preload ); |
193 | | - } |
194 | | - } else { |
195 | | - # If requested, preload some text. |
196 | | - $text = $this->getPreloadedText( $preload ); |
197 | | - } |
198 | | - // For existing pages, get text based on "undo" or section parameters. |
199 | | - } else { |
200 | | - $text = $this->mArticle->getContent(); |
201 | | - if ( $undo > 0 && $undoafter > 0 && $undo < $undoafter ) { |
202 | | - # If they got undoafter and undo round the wrong way, switch them |
203 | | - list( $undo, $undoafter ) = array( $undoafter, $undo ); |
204 | | - } |
205 | | - if ( $undo > 0 && $undo > $undoafter ) { |
206 | | - # Undoing a specific edit overrides section editing; section-editing |
207 | | - # doesn't work with undoing. |
208 | | - if ( $undoafter ) { |
209 | | - $undorev = Revision::newFromId( $undo ); |
210 | | - $oldrev = Revision::newFromId( $undoafter ); |
211 | | - } else { |
212 | | - $undorev = Revision::newFromId( $undo ); |
213 | | - $oldrev = $undorev ? $undorev->getPrevious() : null; |
214 | | - } |
215 | | - |
216 | | - # Sanity check, make sure it's the right page, |
217 | | - # the revisions exist and they were not deleted. |
218 | | - # Otherwise, $text will be left as-is. |
219 | | - if ( !is_null( $undorev ) && !is_null( $oldrev ) && |
220 | | - $undorev->getPage() == $oldrev->getPage() && |
221 | | - $undorev->getPage() == $this->mArticle->getID() && |
222 | | - !$undorev->isDeleted( Revision::DELETED_TEXT ) && |
223 | | - !$oldrev->isDeleted( Revision::DELETED_TEXT ) ) { |
224 | | - |
225 | | - $undotext = $this->mArticle->getUndoText( $undorev, $oldrev ); |
226 | | - if ( $undotext === false ) { |
227 | | - # Warn the user that something went wrong |
228 | | - $this->editFormPageTop .= $wgOut->parse( '<div class="error mw-undo-failure">' . |
229 | | - wfMsgNoTrans( 'undo-failure' ) . '</div>', true, /* interface */true ); |
230 | | - } else { |
231 | | - $text = $undotext; |
232 | | - # Inform the user of our success and set an automatic edit summary |
233 | | - $this->editFormPageTop .= $wgOut->parse( '<div class="mw-undo-success">' . |
234 | | - wfMsgNoTrans( 'undo-success' ) . '</div>', true, /* interface */true ); |
235 | | - $firstrev = $oldrev->getNext(); |
236 | | - # If we just undid one rev, use an autosummary |
237 | | - if ( $firstrev->getId() == $undo ) { |
238 | | - $undoSummary = wfMsgForContent( 'undo-summary', $undo, $undorev->getUserText() ); |
239 | | - if ( $this->summary === '' ) { |
240 | | - $this->summary = $undoSummary; |
241 | | - } else { |
242 | | - $this->summary = $undoSummary . wfMsgForContent( 'colon-separator' ) . $this->summary; |
243 | | - } |
244 | | - $this->undidRev = $undo; |
245 | | - } |
246 | | - $this->formtype = 'diff'; |
247 | | - } |
248 | | - } else { |
249 | | - // Failed basic sanity checks. |
250 | | - // Older revisions may have been removed since the link |
251 | | - // was created, or we may simply have got bogus input. |
252 | | - $this->editFormPageTop .= $wgOut->parse( '<div class="error mw-undo-norev">' . |
253 | | - wfMsgNoTrans( 'undo-norev' ) . '</div>', true, /* interface */true ); |
254 | | - } |
255 | | - } elseif ( $section != '' ) { |
256 | | - if ( $section == 'new' ) { |
257 | | - $text = $this->getPreloadedText( $preload ); |
258 | | - } else { |
259 | | - // Get section edit text (returns $def_text for invalid sections) |
260 | | - $text = $wgParser->getSection( $text, $section, $def_text ); |
261 | | - } |
262 | | - } |
263 | | - } |
264 | | - |
265 | | - wfProfileOut( __METHOD__ ); |
266 | | - return $text; |
267 | | - } |
268 | | - |
269 | | - /** |
270 | | - * Use this method before edit() to preload some text into the edit box |
271 | | - * |
272 | | - * @param $text string |
273 | | - */ |
274 | | - public function setPreloadedText( $text ) { |
275 | | - $this->mPreloadText = $text; |
276 | | - } |
277 | | - |
278 | | - /** |
279 | | - * Get the contents to be preloaded into the box, either set by |
280 | | - * an earlier setPreloadText() or by loading the given page. |
281 | | - * |
282 | | - * @param $preload String: representing the title to preload from. |
283 | | - * @return String |
284 | | - */ |
285 | | - protected function getPreloadedText( $preload ) { |
286 | | - global $wgUser, $wgParser; |
287 | | - if ( !empty( $this->mPreloadText ) ) { |
288 | | - return $this->mPreloadText; |
289 | | - } elseif ( $preload !== '' ) { |
290 | | - $title = Title::newFromText( $preload ); |
291 | | - # Check for existence to avoid getting MediaWiki:Noarticletext |
292 | | - if ( isset( $title ) && $title->exists() && $title->userCanRead() ) { |
293 | | - $article = new Article( $title ); |
294 | | - |
295 | | - if ( $article->isRedirect() ) { |
296 | | - $title = Title::newFromRedirectRecurse( $article->getContent() ); |
297 | | - # Redirects to missing titles are displayed, to hidden pages are followed |
298 | | - # Copying observed behaviour from ?action=view |
299 | | - if ( $title->exists() ) { |
300 | | - if ($title->userCanRead() ) { |
301 | | - $article = new Article( $title ); |
302 | | - } else { |
303 | | - return ""; |
304 | | - } |
305 | | - } |
306 | | - } |
307 | | - $parserOptions = ParserOptions::newFromUser( $wgUser ); |
308 | | - return $wgParser->getPreloadText( $article->getContent(), $title, $parserOptions ); |
309 | | - } |
310 | | - } |
311 | | - return ''; |
312 | | - } |
313 | | - |
314 | | - /** |
315 | | - * Check if a page was deleted while the user was editing it, before submit. |
316 | | - * Note that we rely on the logging table, which hasn't been always there, |
317 | | - * but that doesn't matter, because this only applies to brand new |
318 | | - * deletes. |
319 | | - */ |
320 | | - protected function wasDeletedSinceLastEdit() { |
321 | | - if ( $this->deletedSinceEdit !== null ) { |
322 | | - return $this->deletedSinceEdit; |
323 | | - } |
324 | | - |
325 | | - $this->deletedSinceEdit = false; |
326 | | - |
327 | | - if ( $this->mTitle->isDeletedQuick() ) { |
328 | | - $this->lastDelete = $this->getLastDelete(); |
329 | | - if ( $this->lastDelete ) { |
330 | | - $deleteTime = wfTimestamp( TS_MW, $this->lastDelete->log_timestamp ); |
331 | | - if ( $deleteTime > $this->starttime ) { |
332 | | - $this->deletedSinceEdit = true; |
333 | | - } |
334 | | - } |
335 | | - } |
336 | | - |
337 | | - return $this->deletedSinceEdit; |
338 | | - } |
339 | | - |
340 | | - /** |
341 | | - * Checks whether the user entered a skin name in uppercase, |
342 | | - * e.g. "User:Example/Monobook.css" instead of "monobook.css" |
343 | | - * |
344 | | - * @return bool |
345 | | - */ |
346 | | - protected function isWrongCaseCssJsPage() { |
347 | | - if( $this->mTitle->isCssJsSubpage() ) { |
348 | | - $name = $this->mTitle->getSkinFromCssJsSubpage(); |
349 | | - $skins = array_merge( |
350 | | - array_keys( Skin::getSkinNames() ), |
351 | | - array( 'common' ) |
352 | | - ); |
353 | | - return !in_array( $name, $skins ) |
354 | | - && in_array( strtolower( $name ), $skins ); |
355 | | - } else { |
356 | | - return false; |
357 | | - } |
358 | | - } |
359 | | - |
360 | 165 | function submit() { |
361 | 166 | $this->edit(); |
362 | 167 | } |
— | — | @@ -643,26 +448,33 @@ |
644 | 449 | } |
645 | 450 | |
646 | 451 | /** |
647 | | - * Does this EditPage class support section editing? |
648 | | - * This is used by EditPage subclasses to indicate their ui cannot handle section edits |
| 452 | + * Checks whether the user entered a skin name in uppercase, |
| 453 | + * e.g. "User:Example/Monobook.css" instead of "monobook.css" |
649 | 454 | * |
650 | 455 | * @return bool |
651 | 456 | */ |
652 | | - protected function isSectionEditSupported() { |
653 | | - return true; |
| 457 | + protected function isWrongCaseCssJsPage() { |
| 458 | + if( $this->mTitle->isCssJsSubpage() ) { |
| 459 | + $name = $this->mTitle->getSkinFromCssJsSubpage(); |
| 460 | + $skins = array_merge( |
| 461 | + array_keys( Skin::getSkinNames() ), |
| 462 | + array( 'common' ) |
| 463 | + ); |
| 464 | + return !in_array( $name, $skins ) |
| 465 | + && in_array( strtolower( $name ), $skins ); |
| 466 | + } else { |
| 467 | + return false; |
| 468 | + } |
654 | 469 | } |
655 | 470 | |
656 | 471 | /** |
657 | | - * Returns the URL to use in the form's action attribute. |
658 | | - * This is used by EditPage subclasses when simply customizing the action |
659 | | - * variable in the constructor is not enough. This can be used when the |
660 | | - * EditPage lives inside of a Special page rather than a custom page action. |
| 472 | + * Does this EditPage class support section editing? |
| 473 | + * This is used by EditPage subclasses to indicate their ui cannot handle section edits |
661 | 474 | * |
662 | | - * @param $title Title object for which is being edited (where we go to for &action= links) |
663 | | - * @return string |
| 475 | + * @return bool |
664 | 476 | */ |
665 | | - protected function getActionURL( Title $title ) { |
666 | | - return $title->getLocalURL( array( 'action' => $this->action ) ); |
| 477 | + protected function isSectionEditSupported() { |
| 478 | + return true; |
667 | 479 | } |
668 | 480 | |
669 | 481 | /** |
— | — | @@ -825,6 +637,186 @@ |
826 | 638 | } |
827 | 639 | |
828 | 640 | /** |
| 641 | + * Initialise form fields in the object |
| 642 | + * Called on the first invocation, e.g. when a user clicks an edit link |
| 643 | + * @return bool -- if the requested section is valid |
| 644 | + */ |
| 645 | + function initialiseForm() { |
| 646 | + global $wgUser; |
| 647 | + $this->edittime = $this->mArticle->getTimestamp(); |
| 648 | + $this->textbox1 = $this->getContent( false ); |
| 649 | + // activate checkboxes if user wants them to be always active |
| 650 | + # Sort out the "watch" checkbox |
| 651 | + if ( $wgUser->getOption( 'watchdefault' ) ) { |
| 652 | + # Watch all edits |
| 653 | + $this->watchthis = true; |
| 654 | + } elseif ( $wgUser->getOption( 'watchcreations' ) && !$this->mTitle->exists() ) { |
| 655 | + # Watch creations |
| 656 | + $this->watchthis = true; |
| 657 | + } elseif ( $this->mTitle->userIsWatching() ) { |
| 658 | + # Already watched |
| 659 | + $this->watchthis = true; |
| 660 | + } |
| 661 | + if ( $wgUser->getOption( 'minordefault' ) && !$this->isNew ) { |
| 662 | + $this->minoredit = true; |
| 663 | + } |
| 664 | + if ( $this->textbox1 === false ) { |
| 665 | + return false; |
| 666 | + } |
| 667 | + wfProxyCheck(); |
| 668 | + return true; |
| 669 | + } |
| 670 | + |
| 671 | + /** |
| 672 | + * Fetch initial editing page content. |
| 673 | + * |
| 674 | + * @param $def_text string |
| 675 | + * @return mixed string on success, $def_text for invalid sections |
| 676 | + * @private |
| 677 | + */ |
| 678 | + function getContent( $def_text = '' ) { |
| 679 | + global $wgOut, $wgRequest, $wgParser; |
| 680 | + |
| 681 | + wfProfileIn( __METHOD__ ); |
| 682 | + # Get variables from query string :P |
| 683 | + $section = $wgRequest->getVal( 'section' ); |
| 684 | + |
| 685 | + $preload = $wgRequest->getVal( 'preload', |
| 686 | + // Custom preload text for new sections |
| 687 | + $section === 'new' ? 'MediaWiki:addsection-preload' : '' ); |
| 688 | + $undoafter = $wgRequest->getVal( 'undoafter' ); |
| 689 | + $undo = $wgRequest->getVal( 'undo' ); |
| 690 | + |
| 691 | + // For message page not locally set, use the i18n message. |
| 692 | + // For other non-existent articles, use preload text if any. |
| 693 | + if ( !$this->mTitle->exists() ) { |
| 694 | + if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { |
| 695 | + # If this is a system message, get the default text. |
| 696 | + $text = $this->mTitle->getDefaultMessageText(); |
| 697 | + if( $text === false ) { |
| 698 | + $text = $this->getPreloadedText( $preload ); |
| 699 | + } |
| 700 | + } else { |
| 701 | + # If requested, preload some text. |
| 702 | + $text = $this->getPreloadedText( $preload ); |
| 703 | + } |
| 704 | + // For existing pages, get text based on "undo" or section parameters. |
| 705 | + } else { |
| 706 | + $text = $this->mArticle->getContent(); |
| 707 | + if ( $undo > 0 && $undoafter > 0 && $undo < $undoafter ) { |
| 708 | + # If they got undoafter and undo round the wrong way, switch them |
| 709 | + list( $undo, $undoafter ) = array( $undoafter, $undo ); |
| 710 | + } |
| 711 | + if ( $undo > 0 && $undo > $undoafter ) { |
| 712 | + # Undoing a specific edit overrides section editing; section-editing |
| 713 | + # doesn't work with undoing. |
| 714 | + if ( $undoafter ) { |
| 715 | + $undorev = Revision::newFromId( $undo ); |
| 716 | + $oldrev = Revision::newFromId( $undoafter ); |
| 717 | + } else { |
| 718 | + $undorev = Revision::newFromId( $undo ); |
| 719 | + $oldrev = $undorev ? $undorev->getPrevious() : null; |
| 720 | + } |
| 721 | + |
| 722 | + # Sanity check, make sure it's the right page, |
| 723 | + # the revisions exist and they were not deleted. |
| 724 | + # Otherwise, $text will be left as-is. |
| 725 | + if ( !is_null( $undorev ) && !is_null( $oldrev ) && |
| 726 | + $undorev->getPage() == $oldrev->getPage() && |
| 727 | + $undorev->getPage() == $this->mArticle->getID() && |
| 728 | + !$undorev->isDeleted( Revision::DELETED_TEXT ) && |
| 729 | + !$oldrev->isDeleted( Revision::DELETED_TEXT ) ) { |
| 730 | + |
| 731 | + $undotext = $this->mArticle->getUndoText( $undorev, $oldrev ); |
| 732 | + if ( $undotext === false ) { |
| 733 | + # Warn the user that something went wrong |
| 734 | + $this->editFormPageTop .= $wgOut->parse( '<div class="error mw-undo-failure">' . |
| 735 | + wfMsgNoTrans( 'undo-failure' ) . '</div>', true, /* interface */true ); |
| 736 | + } else { |
| 737 | + $text = $undotext; |
| 738 | + # Inform the user of our success and set an automatic edit summary |
| 739 | + $this->editFormPageTop .= $wgOut->parse( '<div class="mw-undo-success">' . |
| 740 | + wfMsgNoTrans( 'undo-success' ) . '</div>', true, /* interface */true ); |
| 741 | + $firstrev = $oldrev->getNext(); |
| 742 | + # If we just undid one rev, use an autosummary |
| 743 | + if ( $firstrev->getId() == $undo ) { |
| 744 | + $undoSummary = wfMsgForContent( 'undo-summary', $undo, $undorev->getUserText() ); |
| 745 | + if ( $this->summary === '' ) { |
| 746 | + $this->summary = $undoSummary; |
| 747 | + } else { |
| 748 | + $this->summary = $undoSummary . wfMsgForContent( 'colon-separator' ) . $this->summary; |
| 749 | + } |
| 750 | + $this->undidRev = $undo; |
| 751 | + } |
| 752 | + $this->formtype = 'diff'; |
| 753 | + } |
| 754 | + } else { |
| 755 | + // Failed basic sanity checks. |
| 756 | + // Older revisions may have been removed since the link |
| 757 | + // was created, or we may simply have got bogus input. |
| 758 | + $this->editFormPageTop .= $wgOut->parse( '<div class="error mw-undo-norev">' . |
| 759 | + wfMsgNoTrans( 'undo-norev' ) . '</div>', true, /* interface */true ); |
| 760 | + } |
| 761 | + } elseif ( $section != '' ) { |
| 762 | + if ( $section == 'new' ) { |
| 763 | + $text = $this->getPreloadedText( $preload ); |
| 764 | + } else { |
| 765 | + // Get section edit text (returns $def_text for invalid sections) |
| 766 | + $text = $wgParser->getSection( $text, $section, $def_text ); |
| 767 | + } |
| 768 | + } |
| 769 | + } |
| 770 | + |
| 771 | + wfProfileOut( __METHOD__ ); |
| 772 | + return $text; |
| 773 | + } |
| 774 | + |
| 775 | + /** |
| 776 | + * Use this method before edit() to preload some text into the edit box |
| 777 | + * |
| 778 | + * @param $text string |
| 779 | + */ |
| 780 | + public function setPreloadedText( $text ) { |
| 781 | + $this->mPreloadText = $text; |
| 782 | + } |
| 783 | + |
| 784 | + /** |
| 785 | + * Get the contents to be preloaded into the box, either set by |
| 786 | + * an earlier setPreloadText() or by loading the given page. |
| 787 | + * |
| 788 | + * @param $preload String: representing the title to preload from. |
| 789 | + * @return String |
| 790 | + */ |
| 791 | + protected function getPreloadedText( $preload ) { |
| 792 | + global $wgUser, $wgParser; |
| 793 | + if ( !empty( $this->mPreloadText ) ) { |
| 794 | + return $this->mPreloadText; |
| 795 | + } elseif ( $preload !== '' ) { |
| 796 | + $title = Title::newFromText( $preload ); |
| 797 | + # Check for existence to avoid getting MediaWiki:Noarticletext |
| 798 | + if ( isset( $title ) && $title->exists() && $title->userCanRead() ) { |
| 799 | + $article = new Article( $title ); |
| 800 | + |
| 801 | + if ( $article->isRedirect() ) { |
| 802 | + $title = Title::newFromRedirectRecurse( $article->getContent() ); |
| 803 | + # Redirects to missing titles are displayed, to hidden pages are followed |
| 804 | + # Copying observed behaviour from ?action=view |
| 805 | + if ( $title->exists() ) { |
| 806 | + if ($title->userCanRead() ) { |
| 807 | + $article = new Article( $title ); |
| 808 | + } else { |
| 809 | + return ""; |
| 810 | + } |
| 811 | + } |
| 812 | + } |
| 813 | + $parserOptions = ParserOptions::newFromUser( $wgUser ); |
| 814 | + return $wgParser->getPreloadText( $article->getContent(), $title, $parserOptions ); |
| 815 | + } |
| 816 | + } |
| 817 | + return ''; |
| 818 | + } |
| 819 | + |
| 820 | + /** |
829 | 821 | * Make sure the form isn't faking a user's credentials. |
830 | 822 | * |
831 | 823 | * @param $request WebRequest |
— | — | @@ -840,86 +832,90 @@ |
841 | 833 | } |
842 | 834 | |
843 | 835 | /** |
844 | | - * Show all applicable editing introductions |
| 836 | + * Attempt submission |
| 837 | + * @return bool false if output is done, true if the rest of the form should be displayed |
845 | 838 | */ |
846 | | - protected function showIntro() { |
847 | | - global $wgOut, $wgUser; |
848 | | - if ( $this->suppressIntro ) { |
849 | | - return; |
850 | | - } |
| 839 | + function attemptSave() { |
| 840 | + global $wgUser, $wgOut; |
851 | 841 | |
852 | | - $namespace = $this->mTitle->getNamespace(); |
| 842 | + $resultDetails = false; |
| 843 | + # Allow bots to exempt some edits from bot flagging |
| 844 | + $bot = $wgUser->isAllowed( 'bot' ) && $this->bot; |
| 845 | + $status = $this->internalAttemptSave( $resultDetails, $bot ); |
| 846 | + // FIXME: once the interface for internalAttemptSave() is made nicer, this should use the message in $status |
853 | 847 | |
854 | | - if ( $namespace == NS_MEDIAWIKI ) { |
855 | | - # Show a warning if editing an interface message |
856 | | - $wgOut->wrapWikiMsg( "<div class='mw-editinginterface'>\n$1\n</div>", 'editinginterface' ); |
| 848 | + if ( $status->value == self::AS_SUCCESS_UPDATE || $status->value == self::AS_SUCCESS_NEW_ARTICLE ) { |
| 849 | + $this->didSave = true; |
857 | 850 | } |
858 | 851 | |
859 | | - # Show a warning message when someone creates/edits a user (talk) page but the user does not exist |
860 | | - # Show log extract when the user is currently blocked |
861 | | - if ( $namespace == NS_USER || $namespace == NS_USER_TALK ) { |
862 | | - $parts = explode( '/', $this->mTitle->getText(), 2 ); |
863 | | - $username = $parts[0]; |
864 | | - $user = User::newFromName( $username, false /* allow IP users*/ ); |
865 | | - $ip = User::isIP( $username ); |
866 | | - if ( !$user->isLoggedIn() && !$ip ) { # User does not exist |
867 | | - $wgOut->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>", |
868 | | - array( 'userpage-userdoesnotexist', wfEscapeWikiText( $username ) ) ); |
869 | | - } elseif ( $user->isBlocked() ) { # Show log extract if the user is currently blocked |
870 | | - LogEventsList::showLogExtract( |
871 | | - $wgOut, |
872 | | - 'block', |
873 | | - $user->getUserPage(), |
874 | | - '', |
875 | | - array( |
876 | | - 'lim' => 1, |
877 | | - 'showIfEmpty' => false, |
878 | | - 'msgKey' => array( |
879 | | - 'blocked-notice-logextract', |
880 | | - $user->getName() # Support GENDER in notice |
881 | | - ) |
882 | | - ) |
883 | | - ); |
884 | | - } |
885 | | - } |
886 | | - # Try to add a custom edit intro, or use the standard one if this is not possible. |
887 | | - if ( !$this->showCustomIntro() && !$this->mTitle->exists() ) { |
888 | | - if ( $wgUser->isLoggedIn() ) { |
889 | | - $wgOut->wrapWikiMsg( "<div class=\"mw-newarticletext\">\n$1\n</div>", 'newarticletext' ); |
890 | | - } else { |
891 | | - $wgOut->wrapWikiMsg( "<div class=\"mw-newarticletextanon\">\n$1\n</div>", 'newarticletextanon' ); |
892 | | - } |
893 | | - } |
894 | | - # Give a notice if the user is editing a deleted/moved page... |
895 | | - if ( !$this->mTitle->exists() ) { |
896 | | - LogEventsList::showLogExtract( $wgOut, array( 'delete', 'move' ), $this->mTitle, |
897 | | - '', array( 'lim' => 10, |
898 | | - 'conds' => array( "log_action != 'revision'" ), |
899 | | - 'showIfEmpty' => false, |
900 | | - 'msgKey' => array( 'recreate-moveddeleted-warn') ) |
901 | | - ); |
902 | | - } |
903 | | - } |
904 | | - |
905 | | - /** |
906 | | - * Attempt to show a custom editing introduction, if supplied |
907 | | - * |
908 | | - * @return bool |
909 | | - */ |
910 | | - protected function showCustomIntro() { |
911 | | - if ( $this->editintro ) { |
912 | | - $title = Title::newFromText( $this->editintro ); |
913 | | - if ( $title instanceof Title && $title->exists() && $title->userCanRead() ) { |
914 | | - global $wgOut; |
915 | | - // Added using template syntax, to take <noinclude>'s into account. |
916 | | - $wgOut->addWikiTextTitleTidy( '{{:' . $title->getFullText() . '}}', $this->mTitle ); |
| 852 | + switch ( $status->value ) { |
| 853 | + case self::AS_HOOK_ERROR_EXPECTED: |
| 854 | + case self::AS_CONTENT_TOO_BIG: |
| 855 | + case self::AS_ARTICLE_WAS_DELETED: |
| 856 | + case self::AS_CONFLICT_DETECTED: |
| 857 | + case self::AS_SUMMARY_NEEDED: |
| 858 | + case self::AS_TEXTBOX_EMPTY: |
| 859 | + case self::AS_MAX_ARTICLE_SIZE_EXCEEDED: |
| 860 | + case self::AS_END: |
917 | 861 | return true; |
918 | | - } else { |
| 862 | + |
| 863 | + case self::AS_HOOK_ERROR: |
| 864 | + case self::AS_FILTERING: |
919 | 865 | return false; |
920 | | - } |
921 | | - } else { |
922 | | - return false; |
| 866 | + |
| 867 | + case self::AS_SUCCESS_NEW_ARTICLE: |
| 868 | + $query = $resultDetails['redirect'] ? 'redirect=no' : ''; |
| 869 | + $wgOut->redirect( $this->mTitle->getFullURL( $query ) ); |
| 870 | + return false; |
| 871 | + |
| 872 | + case self::AS_SUCCESS_UPDATE: |
| 873 | + $extraQuery = ''; |
| 874 | + $sectionanchor = $resultDetails['sectionanchor']; |
| 875 | + |
| 876 | + // Give extensions a chance to modify URL query on update |
| 877 | + wfRunHooks( 'ArticleUpdateBeforeRedirect', array( $this->mArticle, &$sectionanchor, &$extraQuery ) ); |
| 878 | + |
| 879 | + if ( $resultDetails['redirect'] ) { |
| 880 | + if ( $extraQuery == '' ) { |
| 881 | + $extraQuery = 'redirect=no'; |
| 882 | + } else { |
| 883 | + $extraQuery = 'redirect=no&' . $extraQuery; |
| 884 | + } |
| 885 | + } |
| 886 | + $wgOut->redirect( $this->mTitle->getFullURL( $extraQuery ) . $sectionanchor ); |
| 887 | + return false; |
| 888 | + |
| 889 | + case self::AS_BLANK_ARTICLE: |
| 890 | + $wgOut->redirect( $this->getContextTitle()->getFullURL() ); |
| 891 | + return false; |
| 892 | + |
| 893 | + case self::AS_SPAM_ERROR: |
| 894 | + $this->spamPageWithContent( $resultDetails['spam'] ); |
| 895 | + return false; |
| 896 | + |
| 897 | + case self::AS_BLOCKED_PAGE_FOR_USER: |
| 898 | + throw new UserBlockedError( $wgUser->mBlock ); |
| 899 | + |
| 900 | + case self::AS_IMAGE_REDIRECT_ANON: |
| 901 | + case self::AS_IMAGE_REDIRECT_LOGGED: |
| 902 | + throw new PermissionsError( 'upload' ); |
| 903 | + |
| 904 | + case self::AS_READ_ONLY_PAGE_ANON: |
| 905 | + case self::AS_READ_ONLY_PAGE_LOGGED: |
| 906 | + throw new PermissionsError( 'edit' ); |
| 907 | + |
| 908 | + case self::AS_READ_ONLY_PAGE: |
| 909 | + throw new ReadOnlyError; |
| 910 | + |
| 911 | + case self::AS_RATE_LIMITED: |
| 912 | + throw new ThrottledError(); |
| 913 | + |
| 914 | + case self::AS_NO_CREATE_PERMISSION: |
| 915 | + $permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage'; |
| 916 | + throw new PermissionsError( $permission ); |
| 917 | + |
923 | 918 | } |
| 919 | + return false; |
924 | 920 | } |
925 | 921 | |
926 | 922 | /** |
— | — | @@ -1339,6 +1335,60 @@ |
1340 | 1336 | } |
1341 | 1337 | |
1342 | 1338 | /** |
| 1339 | + * @private |
| 1340 | + * @todo document |
| 1341 | + * |
| 1342 | + * @parma $editText string |
| 1343 | + * |
| 1344 | + * @return bool |
| 1345 | + */ |
| 1346 | + function mergeChangesInto( &$editText ){ |
| 1347 | + wfProfileIn( __METHOD__ ); |
| 1348 | + |
| 1349 | + $db = wfGetDB( DB_MASTER ); |
| 1350 | + |
| 1351 | + // This is the revision the editor started from |
| 1352 | + $baseRevision = $this->getBaseRevision(); |
| 1353 | + if ( is_null( $baseRevision ) ) { |
| 1354 | + wfProfileOut( __METHOD__ ); |
| 1355 | + return false; |
| 1356 | + } |
| 1357 | + $baseText = $baseRevision->getText(); |
| 1358 | + |
| 1359 | + // The current state, we want to merge updates into it |
| 1360 | + $currentRevision = Revision::loadFromTitle( $db, $this->mTitle ); |
| 1361 | + if ( is_null( $currentRevision ) ) { |
| 1362 | + wfProfileOut( __METHOD__ ); |
| 1363 | + return false; |
| 1364 | + } |
| 1365 | + $currentText = $currentRevision->getText(); |
| 1366 | + |
| 1367 | + $result = ''; |
| 1368 | + if ( wfMerge( $baseText, $editText, $currentText, $result ) ) { |
| 1369 | + $editText = $result; |
| 1370 | + wfProfileOut( __METHOD__ ); |
| 1371 | + return true; |
| 1372 | + } else { |
| 1373 | + wfProfileOut( __METHOD__ ); |
| 1374 | + return false; |
| 1375 | + } |
| 1376 | + } |
| 1377 | + |
| 1378 | + /** |
| 1379 | + * @return Revision |
| 1380 | + */ |
| 1381 | + function getBaseRevision() { |
| 1382 | + if ( !$this->mBaseRevision ) { |
| 1383 | + $db = wfGetDB( DB_MASTER ); |
| 1384 | + $baseRevision = Revision::loadFromTimestamp( |
| 1385 | + $db, $this->mTitle, $this->edittime ); |
| 1386 | + return $this->mBaseRevision = $baseRevision; |
| 1387 | + } else { |
| 1388 | + return $this->mBaseRevision; |
| 1389 | + } |
| 1390 | + } |
| 1391 | + |
| 1392 | + /** |
1343 | 1393 | * Check given input text against $wgSpamRegex, and return the text of the first match. |
1344 | 1394 | * |
1345 | 1395 | * @param $text string |
— | — | @@ -1380,37 +1430,6 @@ |
1381 | 1431 | return false; |
1382 | 1432 | } |
1383 | 1433 | |
1384 | | - /** |
1385 | | - * Initialise form fields in the object |
1386 | | - * Called on the first invocation, e.g. when a user clicks an edit link |
1387 | | - * @return bool -- if the requested section is valid |
1388 | | - */ |
1389 | | - function initialiseForm() { |
1390 | | - global $wgUser; |
1391 | | - $this->edittime = $this->mArticle->getTimestamp(); |
1392 | | - $this->textbox1 = $this->getContent( false ); |
1393 | | - // activate checkboxes if user wants them to be always active |
1394 | | - # Sort out the "watch" checkbox |
1395 | | - if ( $wgUser->getOption( 'watchdefault' ) ) { |
1396 | | - # Watch all edits |
1397 | | - $this->watchthis = true; |
1398 | | - } elseif ( $wgUser->getOption( 'watchcreations' ) && !$this->mTitle->exists() ) { |
1399 | | - # Watch creations |
1400 | | - $this->watchthis = true; |
1401 | | - } elseif ( $this->mTitle->userIsWatching() ) { |
1402 | | - # Already watched |
1403 | | - $this->watchthis = true; |
1404 | | - } |
1405 | | - if ( $wgUser->getOption( 'minordefault' ) && !$this->isNew ) { |
1406 | | - $this->minoredit = true; |
1407 | | - } |
1408 | | - if ( $this->textbox1 === false ) { |
1409 | | - return false; |
1410 | | - } |
1411 | | - wfProxyCheck(); |
1412 | | - return true; |
1413 | | - } |
1414 | | - |
1415 | 1434 | function setHeaders() { |
1416 | 1435 | global $wgOut; |
1417 | 1436 | $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
— | — | @@ -1432,6 +1451,89 @@ |
1433 | 1452 | } |
1434 | 1453 | |
1435 | 1454 | /** |
| 1455 | + * Show all applicable editing introductions |
| 1456 | + */ |
| 1457 | + protected function showIntro() { |
| 1458 | + global $wgOut, $wgUser; |
| 1459 | + if ( $this->suppressIntro ) { |
| 1460 | + return; |
| 1461 | + } |
| 1462 | + |
| 1463 | + $namespace = $this->mTitle->getNamespace(); |
| 1464 | + |
| 1465 | + if ( $namespace == NS_MEDIAWIKI ) { |
| 1466 | + # Show a warning if editing an interface message |
| 1467 | + $wgOut->wrapWikiMsg( "<div class='mw-editinginterface'>\n$1\n</div>", 'editinginterface' ); |
| 1468 | + } |
| 1469 | + |
| 1470 | + # Show a warning message when someone creates/edits a user (talk) page but the user does not exist |
| 1471 | + # Show log extract when the user is currently blocked |
| 1472 | + if ( $namespace == NS_USER || $namespace == NS_USER_TALK ) { |
| 1473 | + $parts = explode( '/', $this->mTitle->getText(), 2 ); |
| 1474 | + $username = $parts[0]; |
| 1475 | + $user = User::newFromName( $username, false /* allow IP users*/ ); |
| 1476 | + $ip = User::isIP( $username ); |
| 1477 | + if ( !$user->isLoggedIn() && !$ip ) { # User does not exist |
| 1478 | + $wgOut->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>", |
| 1479 | + array( 'userpage-userdoesnotexist', wfEscapeWikiText( $username ) ) ); |
| 1480 | + } elseif ( $user->isBlocked() ) { # Show log extract if the user is currently blocked |
| 1481 | + LogEventsList::showLogExtract( |
| 1482 | + $wgOut, |
| 1483 | + 'block', |
| 1484 | + $user->getUserPage(), |
| 1485 | + '', |
| 1486 | + array( |
| 1487 | + 'lim' => 1, |
| 1488 | + 'showIfEmpty' => false, |
| 1489 | + 'msgKey' => array( |
| 1490 | + 'blocked-notice-logextract', |
| 1491 | + $user->getName() # Support GENDER in notice |
| 1492 | + ) |
| 1493 | + ) |
| 1494 | + ); |
| 1495 | + } |
| 1496 | + } |
| 1497 | + # Try to add a custom edit intro, or use the standard one if this is not possible. |
| 1498 | + if ( !$this->showCustomIntro() && !$this->mTitle->exists() ) { |
| 1499 | + if ( $wgUser->isLoggedIn() ) { |
| 1500 | + $wgOut->wrapWikiMsg( "<div class=\"mw-newarticletext\">\n$1\n</div>", 'newarticletext' ); |
| 1501 | + } else { |
| 1502 | + $wgOut->wrapWikiMsg( "<div class=\"mw-newarticletextanon\">\n$1\n</div>", 'newarticletextanon' ); |
| 1503 | + } |
| 1504 | + } |
| 1505 | + # Give a notice if the user is editing a deleted/moved page... |
| 1506 | + if ( !$this->mTitle->exists() ) { |
| 1507 | + LogEventsList::showLogExtract( $wgOut, array( 'delete', 'move' ), $this->mTitle, |
| 1508 | + '', array( 'lim' => 10, |
| 1509 | + 'conds' => array( "log_action != 'revision'" ), |
| 1510 | + 'showIfEmpty' => false, |
| 1511 | + 'msgKey' => array( 'recreate-moveddeleted-warn') ) |
| 1512 | + ); |
| 1513 | + } |
| 1514 | + } |
| 1515 | + |
| 1516 | + /** |
| 1517 | + * Attempt to show a custom editing introduction, if supplied |
| 1518 | + * |
| 1519 | + * @return bool |
| 1520 | + */ |
| 1521 | + protected function showCustomIntro() { |
| 1522 | + if ( $this->editintro ) { |
| 1523 | + $title = Title::newFromText( $this->editintro ); |
| 1524 | + if ( $title instanceof Title && $title->exists() && $title->userCanRead() ) { |
| 1525 | + global $wgOut; |
| 1526 | + // Added using template syntax, to take <noinclude>'s into account. |
| 1527 | + $wgOut->addWikiTextTitleTidy( '{{:' . $title->getFullText() . '}}', $this->mTitle ); |
| 1528 | + return true; |
| 1529 | + } else { |
| 1530 | + return false; |
| 1531 | + } |
| 1532 | + } else { |
| 1533 | + return false; |
| 1534 | + } |
| 1535 | + } |
| 1536 | + |
| 1537 | + /** |
1436 | 1538 | * Send the edit form and related headers to $wgOut |
1437 | 1539 | * @param $formCallback Callback that takes an OutputPage parameter; will be called |
1438 | 1540 | * during form output near the top, for captchas and the like. |
— | — | @@ -1980,6 +2082,36 @@ |
1981 | 2083 | } |
1982 | 2084 | |
1983 | 2085 | /** |
| 2086 | + * Get a diff between the current contents of the edit box and the |
| 2087 | + * version of the page we're editing from. |
| 2088 | + * |
| 2089 | + * If this is a section edit, we'll replace the section as for final |
| 2090 | + * save and then make a comparison. |
| 2091 | + */ |
| 2092 | + function showDiff() { |
| 2093 | + $oldtext = $this->mArticle->fetchContent(); |
| 2094 | + $newtext = $this->mArticle->replaceSection( |
| 2095 | + $this->section, $this->textbox1, $this->summary, $this->edittime ); |
| 2096 | + |
| 2097 | + wfRunHooks( 'EditPageGetDiffText', array( $this, &$newtext ) ); |
| 2098 | + |
| 2099 | + $newtext = $this->mArticle->preSaveTransform( $newtext ); |
| 2100 | + $oldtitle = wfMsgExt( 'currentrev', array( 'parseinline' ) ); |
| 2101 | + $newtitle = wfMsgExt( 'yourtext', array( 'parseinline' ) ); |
| 2102 | + if ( $oldtext !== false || $newtext != '' ) { |
| 2103 | + $de = new DifferenceEngine( $this->mArticle->getContext() ); |
| 2104 | + $de->setText( $oldtext, $newtext ); |
| 2105 | + $difftext = $de->getDiff( $oldtitle, $newtitle ); |
| 2106 | + $de->showDiffStyle(); |
| 2107 | + } else { |
| 2108 | + $difftext = ''; |
| 2109 | + } |
| 2110 | + |
| 2111 | + global $wgOut; |
| 2112 | + $wgOut->addHTML( '<div id="wikiDiff">' . $difftext . '</div>' ); |
| 2113 | + } |
| 2114 | + |
| 2115 | + /** |
1984 | 2116 | * Give a chance for site and per-namespace customizations of |
1985 | 2117 | * terms of service summary link that might exist separately |
1986 | 2118 | * from the copyright notice. |
— | — | @@ -2069,6 +2201,62 @@ |
2070 | 2202 | } |
2071 | 2203 | } |
2072 | 2204 | |
| 2205 | + /** |
| 2206 | + * @return string |
| 2207 | + */ |
| 2208 | + public function getCancelLink() { |
| 2209 | + $cancelParams = array(); |
| 2210 | + if ( !$this->isConflict && $this->mArticle->getOldID() > 0 ) { |
| 2211 | + $cancelParams['oldid'] = $this->mArticle->getOldID(); |
| 2212 | + } |
| 2213 | + |
| 2214 | + return Linker::linkKnown( |
| 2215 | + $this->getContextTitle(), |
| 2216 | + wfMsgExt( 'cancel', array( 'parseinline' ) ), |
| 2217 | + array( 'id' => 'mw-editform-cancel' ), |
| 2218 | + $cancelParams |
| 2219 | + ); |
| 2220 | + } |
| 2221 | + |
| 2222 | + /** |
| 2223 | + * Returns the URL to use in the form's action attribute. |
| 2224 | + * This is used by EditPage subclasses when simply customizing the action |
| 2225 | + * variable in the constructor is not enough. This can be used when the |
| 2226 | + * EditPage lives inside of a Special page rather than a custom page action. |
| 2227 | + * |
| 2228 | + * @param $title Title object for which is being edited (where we go to for &action= links) |
| 2229 | + * @return string |
| 2230 | + */ |
| 2231 | + protected function getActionURL( Title $title ) { |
| 2232 | + return $title->getLocalURL( array( 'action' => $this->action ) ); |
| 2233 | + } |
| 2234 | + |
| 2235 | + /** |
| 2236 | + * Check if a page was deleted while the user was editing it, before submit. |
| 2237 | + * Note that we rely on the logging table, which hasn't been always there, |
| 2238 | + * but that doesn't matter, because this only applies to brand new |
| 2239 | + * deletes. |
| 2240 | + */ |
| 2241 | + protected function wasDeletedSinceLastEdit() { |
| 2242 | + if ( $this->deletedSinceEdit !== null ) { |
| 2243 | + return $this->deletedSinceEdit; |
| 2244 | + } |
| 2245 | + |
| 2246 | + $this->deletedSinceEdit = false; |
| 2247 | + |
| 2248 | + if ( $this->mTitle->isDeletedQuick() ) { |
| 2249 | + $this->lastDelete = $this->getLastDelete(); |
| 2250 | + if ( $this->lastDelete ) { |
| 2251 | + $deleteTime = wfTimestamp( TS_MW, $this->lastDelete->log_timestamp ); |
| 2252 | + if ( $deleteTime > $this->starttime ) { |
| 2253 | + $this->deletedSinceEdit = true; |
| 2254 | + } |
| 2255 | + } |
| 2256 | + } |
| 2257 | + |
| 2258 | + return $this->deletedSinceEdit; |
| 2259 | + } |
| 2260 | + |
2073 | 2261 | protected function getLastDelete() { |
2074 | 2262 | $dbr = wfGetDB( DB_SLAVE ); |
2075 | 2263 | $data = $dbr->selectRow( |
— | — | @@ -2243,177 +2431,6 @@ |
2244 | 2432 | } |
2245 | 2433 | |
2246 | 2434 | /** |
2247 | | - * Call the stock "user is blocked" page |
2248 | | - * |
2249 | | - * @deprecated in 1.19; throw an exception directly instead |
2250 | | - */ |
2251 | | - function blockedPage() { |
2252 | | - global $wgUser; |
2253 | | - |
2254 | | - throw new UserBlockedError( $wgUser->mBlock ); |
2255 | | - } |
2256 | | - |
2257 | | - /** |
2258 | | - * Produce the stock "please login to edit pages" page |
2259 | | - * |
2260 | | - * @deprecated in 1.19; throw an exception directly instead |
2261 | | - */ |
2262 | | - function userNotLoggedInPage() { |
2263 | | - throw new PermissionsError( 'edit' ); |
2264 | | - } |
2265 | | - |
2266 | | - /** |
2267 | | - * Show an error page saying to the user that he has insufficient permissions |
2268 | | - * to create a new page |
2269 | | - * |
2270 | | - * @deprecated in 1.19; throw an exception directly instead |
2271 | | - */ |
2272 | | - function noCreatePermission() { |
2273 | | - $permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage'; |
2274 | | - throw new PermissionsError( $permission ); |
2275 | | - } |
2276 | | - |
2277 | | - /** |
2278 | | - * Creates a basic error page which informs the user that |
2279 | | - * they have attempted to edit a nonexistent section. |
2280 | | - */ |
2281 | | - function noSuchSectionPage() { |
2282 | | - global $wgOut; |
2283 | | - |
2284 | | - $wgOut->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) ); |
2285 | | - |
2286 | | - $res = wfMsgExt( 'nosuchsectiontext', 'parse', $this->section ); |
2287 | | - wfRunHooks( 'EditPageNoSuchSection', array( &$this, &$res ) ); |
2288 | | - $wgOut->addHTML( $res ); |
2289 | | - |
2290 | | - $wgOut->returnToMain( false, $this->mTitle ); |
2291 | | - } |
2292 | | - |
2293 | | - /** |
2294 | | - * Produce the stock "your edit contains spam" page |
2295 | | - * |
2296 | | - * @param $match Text which triggered one or more filters |
2297 | | - * @deprecated since 1.17 Use method spamPageWithContent() instead |
2298 | | - */ |
2299 | | - static function spamPage( $match = false ) { |
2300 | | - global $wgOut, $wgTitle; |
2301 | | - |
2302 | | - $wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) ); |
2303 | | - |
2304 | | - $wgOut->addHTML( '<div id="spamprotected">' ); |
2305 | | - $wgOut->addWikiMsg( 'spamprotectiontext' ); |
2306 | | - if ( $match ) { |
2307 | | - $wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) ); |
2308 | | - } |
2309 | | - $wgOut->addHTML( '</div>' ); |
2310 | | - |
2311 | | - $wgOut->returnToMain( false, $wgTitle ); |
2312 | | - } |
2313 | | - |
2314 | | - /** |
2315 | | - * Show "your edit contains spam" page with your diff and text |
2316 | | - * |
2317 | | - * @param $match Text which triggered one or more filters |
2318 | | - */ |
2319 | | - public function spamPageWithContent( $match = false ) { |
2320 | | - global $wgOut; |
2321 | | - $this->textbox2 = $this->textbox1; |
2322 | | - |
2323 | | - $wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) ); |
2324 | | - |
2325 | | - $wgOut->addHTML( '<div id="spamprotected">' ); |
2326 | | - $wgOut->addWikiMsg( 'spamprotectiontext' ); |
2327 | | - if ( $match ) { |
2328 | | - $wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) ); |
2329 | | - } |
2330 | | - $wgOut->addHTML( '</div>' ); |
2331 | | - |
2332 | | - $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" ); |
2333 | | - $de = new DifferenceEngine( $this->mArticle->getContext() ); |
2334 | | - $de->setText( $this->getContent(), $this->textbox2 ); |
2335 | | - $de->showDiff( wfMsg( "storedversion" ), wfMsgExt( 'yourtext', 'parseinline' ) ); |
2336 | | - |
2337 | | - $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" ); |
2338 | | - $this->showTextbox2(); |
2339 | | - |
2340 | | - $wgOut->addReturnTo( $this->getContextTitle(), array( 'action' => 'edit' ) ); |
2341 | | - } |
2342 | | - |
2343 | | - |
2344 | | - /** |
2345 | | - * @private |
2346 | | - * @todo document |
2347 | | - * |
2348 | | - * @parma $editText string |
2349 | | - * |
2350 | | - * @return bool |
2351 | | - */ |
2352 | | - function mergeChangesInto( &$editText ){ |
2353 | | - wfProfileIn( __METHOD__ ); |
2354 | | - |
2355 | | - $db = wfGetDB( DB_MASTER ); |
2356 | | - |
2357 | | - // This is the revision the editor started from |
2358 | | - $baseRevision = $this->getBaseRevision(); |
2359 | | - if ( is_null( $baseRevision ) ) { |
2360 | | - wfProfileOut( __METHOD__ ); |
2361 | | - return false; |
2362 | | - } |
2363 | | - $baseText = $baseRevision->getText(); |
2364 | | - |
2365 | | - // The current state, we want to merge updates into it |
2366 | | - $currentRevision = Revision::loadFromTitle( $db, $this->mTitle ); |
2367 | | - if ( is_null( $currentRevision ) ) { |
2368 | | - wfProfileOut( __METHOD__ ); |
2369 | | - return false; |
2370 | | - } |
2371 | | - $currentText = $currentRevision->getText(); |
2372 | | - |
2373 | | - $result = ''; |
2374 | | - if ( wfMerge( $baseText, $editText, $currentText, $result ) ) { |
2375 | | - $editText = $result; |
2376 | | - wfProfileOut( __METHOD__ ); |
2377 | | - return true; |
2378 | | - } else { |
2379 | | - wfProfileOut( __METHOD__ ); |
2380 | | - return false; |
2381 | | - } |
2382 | | - } |
2383 | | - |
2384 | | - /** |
2385 | | - * Check if the browser is on a blacklist of user-agents known to |
2386 | | - * mangle UTF-8 data on form submission. Returns true if Unicode |
2387 | | - * should make it through, false if it's known to be a problem. |
2388 | | - * @return bool |
2389 | | - * @private |
2390 | | - */ |
2391 | | - function checkUnicodeCompliantBrowser() { |
2392 | | - global $wgBrowserBlackList; |
2393 | | - if ( empty( $_SERVER["HTTP_USER_AGENT"] ) ) { |
2394 | | - // No User-Agent header sent? Trust it by default... |
2395 | | - return true; |
2396 | | - } |
2397 | | - $currentbrowser = $_SERVER["HTTP_USER_AGENT"]; |
2398 | | - foreach ( $wgBrowserBlackList as $browser ) { |
2399 | | - if ( preg_match($browser, $currentbrowser) ) { |
2400 | | - return false; |
2401 | | - } |
2402 | | - } |
2403 | | - return true; |
2404 | | - } |
2405 | | - |
2406 | | - /** |
2407 | | - * Format an anchor fragment as it would appear for a given section name |
2408 | | - * @param $text String |
2409 | | - * @return String |
2410 | | - * @private |
2411 | | - */ |
2412 | | - function sectionAnchor( $text ) { |
2413 | | - global $wgParser; |
2414 | | - return $wgParser->guessSectionNameFromWikiText( $text ); |
2415 | | - } |
2416 | | - |
2417 | | - /** |
2418 | 2435 | * Shows a bulletin board style toolbar for common editing functions. |
2419 | 2436 | * It can be disabled in the user preferences. |
2420 | 2437 | * The necessary JavaScript code can be found in skins/common/edit.js. |
— | — | @@ -2703,53 +2720,136 @@ |
2704 | 2721 | } |
2705 | 2722 | |
2706 | 2723 | /** |
2707 | | - * @return string |
| 2724 | + * Call the stock "user is blocked" page |
| 2725 | + * |
| 2726 | + * @deprecated in 1.19; throw an exception directly instead |
2708 | 2727 | */ |
2709 | | - public function getCancelLink() { |
2710 | | - $cancelParams = array(); |
2711 | | - if ( !$this->isConflict && $this->mArticle->getOldID() > 0 ) { |
2712 | | - $cancelParams['oldid'] = $this->mArticle->getOldID(); |
2713 | | - } |
| 2728 | + function blockedPage() { |
| 2729 | + global $wgUser; |
2714 | 2730 | |
2715 | | - return Linker::linkKnown( |
2716 | | - $this->getContextTitle(), |
2717 | | - wfMsgExt( 'cancel', array( 'parseinline' ) ), |
2718 | | - array( 'id' => 'mw-editform-cancel' ), |
2719 | | - $cancelParams |
2720 | | - ); |
| 2731 | + throw new UserBlockedError( $wgUser->mBlock ); |
2721 | 2732 | } |
2722 | 2733 | |
2723 | 2734 | /** |
2724 | | - * Get a diff between the current contents of the edit box and the |
2725 | | - * version of the page we're editing from. |
| 2735 | + * Produce the stock "please login to edit pages" page |
2726 | 2736 | * |
2727 | | - * If this is a section edit, we'll replace the section as for final |
2728 | | - * save and then make a comparison. |
| 2737 | + * @deprecated in 1.19; throw an exception directly instead |
2729 | 2738 | */ |
2730 | | - function showDiff() { |
2731 | | - $oldtext = $this->mArticle->fetchContent(); |
2732 | | - $newtext = $this->mArticle->replaceSection( |
2733 | | - $this->section, $this->textbox1, $this->summary, $this->edittime ); |
| 2739 | + function userNotLoggedInPage() { |
| 2740 | + throw new PermissionsError( 'edit' ); |
| 2741 | + } |
2734 | 2742 | |
2735 | | - wfRunHooks( 'EditPageGetDiffText', array( $this, &$newtext ) ); |
| 2743 | + /** |
| 2744 | + * Show an error page saying to the user that he has insufficient permissions |
| 2745 | + * to create a new page |
| 2746 | + * |
| 2747 | + * @deprecated in 1.19; throw an exception directly instead |
| 2748 | + */ |
| 2749 | + function noCreatePermission() { |
| 2750 | + $permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage'; |
| 2751 | + throw new PermissionsError( $permission ); |
| 2752 | + } |
2736 | 2753 | |
2737 | | - $newtext = $this->mArticle->preSaveTransform( $newtext ); |
2738 | | - $oldtitle = wfMsgExt( 'currentrev', array( 'parseinline' ) ); |
2739 | | - $newtitle = wfMsgExt( 'yourtext', array( 'parseinline' ) ); |
2740 | | - if ( $oldtext !== false || $newtext != '' ) { |
2741 | | - $de = new DifferenceEngine( $this->mArticle->getContext() ); |
2742 | | - $de->setText( $oldtext, $newtext ); |
2743 | | - $difftext = $de->getDiff( $oldtitle, $newtitle ); |
2744 | | - $de->showDiffStyle(); |
2745 | | - } else { |
2746 | | - $difftext = ''; |
| 2754 | + /** |
| 2755 | + * Creates a basic error page which informs the user that |
| 2756 | + * they have attempted to edit a nonexistent section. |
| 2757 | + */ |
| 2758 | + function noSuchSectionPage() { |
| 2759 | + global $wgOut; |
| 2760 | + |
| 2761 | + $wgOut->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) ); |
| 2762 | + |
| 2763 | + $res = wfMsgExt( 'nosuchsectiontext', 'parse', $this->section ); |
| 2764 | + wfRunHooks( 'EditPageNoSuchSection', array( &$this, &$res ) ); |
| 2765 | + $wgOut->addHTML( $res ); |
| 2766 | + |
| 2767 | + $wgOut->returnToMain( false, $this->mTitle ); |
| 2768 | + } |
| 2769 | + |
| 2770 | + /** |
| 2771 | + * Produce the stock "your edit contains spam" page |
| 2772 | + * |
| 2773 | + * @param $match Text which triggered one or more filters |
| 2774 | + * @deprecated since 1.17 Use method spamPageWithContent() instead |
| 2775 | + */ |
| 2776 | + static function spamPage( $match = false ) { |
| 2777 | + global $wgOut, $wgTitle; |
| 2778 | + |
| 2779 | + $wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) ); |
| 2780 | + |
| 2781 | + $wgOut->addHTML( '<div id="spamprotected">' ); |
| 2782 | + $wgOut->addWikiMsg( 'spamprotectiontext' ); |
| 2783 | + if ( $match ) { |
| 2784 | + $wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) ); |
2747 | 2785 | } |
| 2786 | + $wgOut->addHTML( '</div>' ); |
2748 | 2787 | |
| 2788 | + $wgOut->returnToMain( false, $wgTitle ); |
| 2789 | + } |
| 2790 | + |
| 2791 | + /** |
| 2792 | + * Show "your edit contains spam" page with your diff and text |
| 2793 | + * |
| 2794 | + * @param $match Text which triggered one or more filters |
| 2795 | + */ |
| 2796 | + public function spamPageWithContent( $match = false ) { |
2749 | 2797 | global $wgOut; |
2750 | | - $wgOut->addHTML( '<div id="wikiDiff">' . $difftext . '</div>' ); |
| 2798 | + $this->textbox2 = $this->textbox1; |
| 2799 | + |
| 2800 | + $wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) ); |
| 2801 | + |
| 2802 | + $wgOut->addHTML( '<div id="spamprotected">' ); |
| 2803 | + $wgOut->addWikiMsg( 'spamprotectiontext' ); |
| 2804 | + if ( $match ) { |
| 2805 | + $wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) ); |
| 2806 | + } |
| 2807 | + $wgOut->addHTML( '</div>' ); |
| 2808 | + |
| 2809 | + $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" ); |
| 2810 | + $de = new DifferenceEngine( $this->mArticle->getContext() ); |
| 2811 | + $de->setText( $this->getContent(), $this->textbox2 ); |
| 2812 | + $de->showDiff( wfMsg( "storedversion" ), wfMsgExt( 'yourtext', 'parseinline' ) ); |
| 2813 | + |
| 2814 | + $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" ); |
| 2815 | + $this->showTextbox2(); |
| 2816 | + |
| 2817 | + $wgOut->addReturnTo( $this->getContextTitle(), array( 'action' => 'edit' ) ); |
2751 | 2818 | } |
2752 | 2819 | |
2753 | 2820 | /** |
| 2821 | + * Format an anchor fragment as it would appear for a given section name |
| 2822 | + * @param $text String |
| 2823 | + * @return String |
| 2824 | + * @private |
| 2825 | + */ |
| 2826 | + function sectionAnchor( $text ) { |
| 2827 | + global $wgParser; |
| 2828 | + return $wgParser->guessSectionNameFromWikiText( $text ); |
| 2829 | + } |
| 2830 | + |
| 2831 | + /** |
| 2832 | + * Check if the browser is on a blacklist of user-agents known to |
| 2833 | + * mangle UTF-8 data on form submission. Returns true if Unicode |
| 2834 | + * should make it through, false if it's known to be a problem. |
| 2835 | + * @return bool |
| 2836 | + * @private |
| 2837 | + */ |
| 2838 | + function checkUnicodeCompliantBrowser() { |
| 2839 | + global $wgBrowserBlackList; |
| 2840 | + if ( empty( $_SERVER["HTTP_USER_AGENT"] ) ) { |
| 2841 | + // No User-Agent header sent? Trust it by default... |
| 2842 | + return true; |
| 2843 | + } |
| 2844 | + $currentbrowser = $_SERVER["HTTP_USER_AGENT"]; |
| 2845 | + foreach ( $wgBrowserBlackList as $browser ) { |
| 2846 | + if ( preg_match($browser, $currentbrowser) ) { |
| 2847 | + return false; |
| 2848 | + } |
| 2849 | + } |
| 2850 | + return true; |
| 2851 | + } |
| 2852 | + |
| 2853 | + /** |
2754 | 2854 | * Filter an input field through a Unicode de-armoring process if it |
2755 | 2855 | * came from an old browser with known broken Unicode editing issues. |
2756 | 2856 | * |
— | — | @@ -2875,105 +2975,4 @@ |
2876 | 2976 | // reverse the transform that we made for reversability reasons. |
2877 | 2977 | return strtr( $result, array( "�" => "&#x" ) ); |
2878 | 2978 | } |
2879 | | - |
2880 | | - /** |
2881 | | - * Attempt submission |
2882 | | - * @return bool false if output is done, true if the rest of the form should be displayed |
2883 | | - */ |
2884 | | - function attemptSave() { |
2885 | | - global $wgUser, $wgOut; |
2886 | | - |
2887 | | - $resultDetails = false; |
2888 | | - # Allow bots to exempt some edits from bot flagging |
2889 | | - $bot = $wgUser->isAllowed( 'bot' ) && $this->bot; |
2890 | | - $status = $this->internalAttemptSave( $resultDetails, $bot ); |
2891 | | - // FIXME: once the interface for internalAttemptSave() is made nicer, this should use the message in $status |
2892 | | - |
2893 | | - if ( $status->value == self::AS_SUCCESS_UPDATE || $status->value == self::AS_SUCCESS_NEW_ARTICLE ) { |
2894 | | - $this->didSave = true; |
2895 | | - } |
2896 | | - |
2897 | | - switch ( $status->value ) { |
2898 | | - case self::AS_HOOK_ERROR_EXPECTED: |
2899 | | - case self::AS_CONTENT_TOO_BIG: |
2900 | | - case self::AS_ARTICLE_WAS_DELETED: |
2901 | | - case self::AS_CONFLICT_DETECTED: |
2902 | | - case self::AS_SUMMARY_NEEDED: |
2903 | | - case self::AS_TEXTBOX_EMPTY: |
2904 | | - case self::AS_MAX_ARTICLE_SIZE_EXCEEDED: |
2905 | | - case self::AS_END: |
2906 | | - return true; |
2907 | | - |
2908 | | - case self::AS_HOOK_ERROR: |
2909 | | - case self::AS_FILTERING: |
2910 | | - return false; |
2911 | | - |
2912 | | - case self::AS_SUCCESS_NEW_ARTICLE: |
2913 | | - $query = $resultDetails['redirect'] ? 'redirect=no' : ''; |
2914 | | - $wgOut->redirect( $this->mTitle->getFullURL( $query ) ); |
2915 | | - return false; |
2916 | | - |
2917 | | - case self::AS_SUCCESS_UPDATE: |
2918 | | - $extraQuery = ''; |
2919 | | - $sectionanchor = $resultDetails['sectionanchor']; |
2920 | | - |
2921 | | - // Give extensions a chance to modify URL query on update |
2922 | | - wfRunHooks( 'ArticleUpdateBeforeRedirect', array( $this->mArticle, &$sectionanchor, &$extraQuery ) ); |
2923 | | - |
2924 | | - if ( $resultDetails['redirect'] ) { |
2925 | | - if ( $extraQuery == '' ) { |
2926 | | - $extraQuery = 'redirect=no'; |
2927 | | - } else { |
2928 | | - $extraQuery = 'redirect=no&' . $extraQuery; |
2929 | | - } |
2930 | | - } |
2931 | | - $wgOut->redirect( $this->mTitle->getFullURL( $extraQuery ) . $sectionanchor ); |
2932 | | - return false; |
2933 | | - |
2934 | | - case self::AS_BLANK_ARTICLE: |
2935 | | - $wgOut->redirect( $this->getContextTitle()->getFullURL() ); |
2936 | | - return false; |
2937 | | - |
2938 | | - case self::AS_SPAM_ERROR: |
2939 | | - $this->spamPageWithContent( $resultDetails['spam'] ); |
2940 | | - return false; |
2941 | | - |
2942 | | - case self::AS_BLOCKED_PAGE_FOR_USER: |
2943 | | - throw new UserBlockedError( $wgUser->mBlock ); |
2944 | | - |
2945 | | - case self::AS_IMAGE_REDIRECT_ANON: |
2946 | | - case self::AS_IMAGE_REDIRECT_LOGGED: |
2947 | | - throw new PermissionsError( 'upload' ); |
2948 | | - |
2949 | | - case self::AS_READ_ONLY_PAGE_ANON: |
2950 | | - case self::AS_READ_ONLY_PAGE_LOGGED: |
2951 | | - throw new PermissionsError( 'edit' ); |
2952 | | - |
2953 | | - case self::AS_READ_ONLY_PAGE: |
2954 | | - throw new ReadOnlyError; |
2955 | | - |
2956 | | - case self::AS_RATE_LIMITED: |
2957 | | - throw new ThrottledError(); |
2958 | | - |
2959 | | - case self::AS_NO_CREATE_PERMISSION: |
2960 | | - $permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage'; |
2961 | | - throw new PermissionsError( $permission ); |
2962 | | - |
2963 | | - } |
2964 | | - return false; |
2965 | | - } |
2966 | | - |
2967 | | - /** |
2968 | | - * @return Revision |
2969 | | - */ |
2970 | | - function getBaseRevision() { |
2971 | | - if ( !$this->mBaseRevision ) { |
2972 | | - $db = wfGetDB( DB_MASTER ); |
2973 | | - $baseRevision = Revision::loadFromTimestamp( |
2974 | | - $db, $this->mTitle, $this->edittime ); |
2975 | | - return $this->mBaseRevision = $baseRevision; |
2976 | | - } else { |
2977 | | - return $this->mBaseRevision; |
2978 | | - } |
2979 | | - } |
2980 | 2979 | } |