X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FEditPage.php;h=1696b26a6afcc548723fddc093184c59d86fb14a;hb=e0afa3b22c8e4367d2e0ffe18a7ee8388248a799;hp=fad212cfc06a0fac8ffdd7cadeb08c33b60a3e62;hpb=aa9bc3ba41273f911bad6a3ac754c98e1dde229a;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/EditPage.php b/includes/EditPage.php index fad212cfc0..1696b26a6a 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -15,6 +15,9 @@ * redirects go to, etc. $this->mTitle (as well as $mArticle) is the * page in the database that is actually being edited. These are * usually the same, but they are now allowed to be different. + * + * Surgeon General's Warning: prolonged exposure to this class is known to cause + * headaches, which may be fatal. */ class EditPage { const AS_SUCCESS_UPDATE = 200; @@ -166,7 +169,7 @@ class EditPage { * Fetch initial editing page content. * * @param $def_text string - * @returns mixed string on success, $def_text for invalid sections + * @return mixed string on success, $def_text for invalid sections * @private */ function getContent( $def_text = '' ) { @@ -225,15 +228,22 @@ class EditPage { $undotext = $this->mArticle->getUndoText( $undorev, $oldrev ); if ( $undotext === false ) { # Warn the user that something went wrong - $this->editFormPageTop .= $wgOut->parse( '
' . wfMsgNoTrans( 'undo-failure' ) . '
' ); + $this->editFormPageTop .= $wgOut->parse( '
' . + wfMsgNoTrans( 'undo-failure' ) . '
', true, /* interface */true ); } else { $text = $undotext; # Inform the user of our success and set an automatic edit summary - $this->editFormPageTop .= $wgOut->parse( '
' . wfMsgNoTrans( 'undo-success' ) . '
' ); + $this->editFormPageTop .= $wgOut->parse( '
' . + wfMsgNoTrans( 'undo-success' ) . '
', true, /* interface */true ); $firstrev = $oldrev->getNext(); # If we just undid one rev, use an autosummary - if ( $firstrev->mId == $undo ) { - $this->summary = wfMsgForContent( 'undo-summary', $undo, $undorev->getUserText() ); + if ( $firstrev->getId() == $undo ) { + $undoSummary = wfMsgForContent( 'undo-summary', $undo, $undorev->getUserText() ); + if ( $this->summary === '' ) { + $this->summary = $undoSummary; + } else { + $this->summary = $undoSummary . wfMsgForContent( 'colon-separator' ) . $this->summary; + } $this->undidRev = $undo; } $this->formtype = 'diff'; @@ -242,9 +252,10 @@ class EditPage { // Failed basic sanity checks. // Older revisions may have been removed since the link // was created, or we may simply have got bogus input. - $this->editFormPageTop .= $wgOut->parse( '
' . wfMsgNoTrans( 'undo-norev' ) . '
' ); + $this->editFormPageTop .= $wgOut->parse( '
' . + wfMsgNoTrans( 'undo-norev' ) . '
', true, /* interface */true ); } - } else if ( $section != '' ) { + } elseif ( $section != '' ) { if ( $section == 'new' ) { $text = $this->getPreloadedText( $preload ); } else { @@ -374,9 +385,6 @@ class EditPage { wfProfileIn( __METHOD__ ); wfDebug( __METHOD__.": enter\n" ); - // This is not an article - $wgOut->setArticleFlag( false ); - $this->importFormData( $wgRequest ); $this->firsttime = false; @@ -402,6 +410,9 @@ class EditPage { $permErrors = $this->getEditPermissionErrors(); if ( $permErrors ) { + // Auto-block user's IP if the account was "hard" blocked + $wgUser->spreadAnyEditBlock(); + wfDebug( __METHOD__ . ": User can't edit\n" ); $content = $this->getContent( null ); $content = $content === '' ? null : $content; @@ -411,9 +422,9 @@ class EditPage { } else { if ( $this->save ) { $this->formtype = 'save'; - } else if ( $this->preview ) { + } elseif ( $this->preview ) { $this->formtype = 'preview'; - } else if ( $this->diff ) { + } elseif ( $this->diff ) { $this->formtype = 'diff'; } else { # First time through $this->firsttime = true; @@ -464,6 +475,13 @@ class EditPage { $wgOut->addWikiText( $editnotice_base_msg->plain() ); } } + } else { + # Even if there are no subpages in namespace, we still don't want / in MW ns. + $editnoticeText = $editnotice_ns . '-' . str_replace( '/', '-', $this->mTitle->getDBkey() ); + $editnoticeMsg = wfMessage( $editnoticeText )->inContentLanguage(); + if ( $editnoticeMsg->exists() ) { + $wgOut->addWikiText( $editnoticeMsg->plain() ); + } } # Attempt submission here. This will check for edit conflicts, @@ -553,7 +571,7 @@ class EditPage { } elseif ( $wgRequest->getVal( 'preview' ) == 'no' ) { // Explicit override from request return false; - } elseif ( $this->section == 'new' ) { + } elseif ( $this->section == 'new' ) { // Nothing *to* preview for new sections return false; } elseif ( ( $wgRequest->getVal( 'preload' ) !== null || $this->mTitle->exists() ) && $wgUser->getOption( 'previewonfirst' ) ) { @@ -662,7 +680,7 @@ class EditPage { # The unmarked state will be assumed to be a save, # if the form seems otherwise complete. wfDebug( __METHOD__ . ": Passed token check.\n" ); - } else if ( $this->diff ) { + } elseif ( $this->diff ) { # Failed token check, but only requested "Show Changes". wfDebug( __METHOD__ . ": Failed token check; Show Changes requested.\n" ); } else { @@ -792,12 +810,12 @@ class EditPage { $ip = User::isIP( $username ); if ( !$user->isLoggedIn() && !$ip ) { # User does not exist $wgOut->wrapWikiMsg( "
\n$1\n
", - array( 'userpage-userdoesnotexist', $username ) ); - } else if ( $user->isBlocked() ) { # Show log extract if the user is currently blocked + array( 'userpage-userdoesnotexist', wfEscapeWikiText( $username ) ) ); + } elseif ( $user->isBlocked() ) { # Show log extract if the user is currently blocked LogEventsList::showLogExtract( $wgOut, 'block', - $user->getUserPage()->getPrefixedText(), + $user->getUserPage(), '', array( 'lim' => 1, @@ -820,7 +838,7 @@ class EditPage { } # Give a notice if the user is editing a deleted/moved page... if ( !$this->mTitle->exists() ) { - LogEventsList::showLogExtract( $wgOut, array( 'delete', 'move' ), $this->mTitle->getPrefixedText(), + LogEventsList::showLogExtract( $wgOut, array( 'delete', 'move' ), $this->mTitle, '', array( 'lim' => 10, 'conds' => array( "log_action != 'revision'" ), 'showIfEmpty' => false, @@ -856,32 +874,41 @@ class EditPage { * @param $result * @param $bot bool * - * @return int one of the constants describing the result + * @return Status object, possibly with a message, but always with one of the AS_* constants in $status->value, + * + * FIXME: This interface is TERRIBLE, but hard to get rid of due to various error display idiosyncrasies. There are + * also lots of cases where error metadata is set in the object and retrieved later instead of being returned, e.g. + * AS_CONTENT_TOO_BIG and AS_BLOCKED_PAGE_FOR_USER. All that stuff needs to be cleaned up some time. */ function internalAttemptSave( &$result, $bot = false ) { - global $wgFilterCallback, $wgUser, $wgParser; + global $wgFilterCallback, $wgUser, $wgRequest, $wgParser; global $wgMaxArticleSize; + $status = Status::newGood(); + wfProfileIn( __METHOD__ ); wfProfileIn( __METHOD__ . '-checks' ); if ( !wfRunHooks( 'EditPage::attemptSave', array( $this ) ) ) { wfDebug( "Hook 'EditPage::attemptSave' aborted article saving\n" ); + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR; wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_HOOK_ERROR; + return $status; } # Check image redirect if ( $this->mTitle->getNamespace() == NS_FILE && Title::newFromRedirect( $this->textbox1 ) instanceof Title && !$wgUser->isAllowed( 'upload' ) ) { - $isAnon = $wgUser->isAnon(); + $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED; + $status->setResult( false, $code ); wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return $isAnon ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED; + return $status; } # Check for spam @@ -891,75 +918,96 @@ class EditPage { } if ( $match !== false ) { $result['spam'] = $match; - $ip = wfGetIP(); + $ip = $wgRequest->getIP(); $pdbk = $this->mTitle->getPrefixedDBkey(); $match = str_replace( "\n", '', $match ); wfDebugLog( 'SpamRegex', "$ip spam regex hit [[$pdbk]]: \"$match\"" ); + $status->fatal( 'spamprotectionmatch', $match ); + $status->value = self::AS_SPAM_ERROR; wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_SPAM_ERROR; + return $status; } - if ( $wgFilterCallback && $wgFilterCallback( $this->mTitle, $this->textbox1, $this->section, $this->hookError, $this->summary ) ) { + if ( $wgFilterCallback && is_callable( $wgFilterCallback ) && $wgFilterCallback( $this->mTitle, $this->textbox1, $this->section, $this->hookError, $this->summary ) ) { # Error messages or other handling should be performed by the filter function + $status->setResult( false, self::AS_FILTERING ); wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_FILTERING; + return $status; } if ( !wfRunHooks( 'EditFilter', array( $this, $this->textbox1, $this->section, &$this->hookError, $this->summary ) ) ) { # Error messages etc. could be handled within the hook... + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR; wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_HOOK_ERROR; + return $status; } elseif ( $this->hookError != '' ) { # ...or the hook could be expecting us to produce an error + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR_EXPECTED; wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_HOOK_ERROR_EXPECTED; + return $status; } + if ( $wgUser->isBlockedFrom( $this->mTitle, false ) ) { + // Auto-block user's IP if the account was "hard" blocked + $wgUser->spreadAnyEditBlock(); # Check block state against master, thus 'false'. + $status->setResult( false, self::AS_BLOCKED_PAGE_FOR_USER ); wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_BLOCKED_PAGE_FOR_USER; + return $status; } + $this->kblength = (int)( strlen( $this->textbox1 ) / 1024 ); if ( $this->kblength > $wgMaxArticleSize ) { // Error will be displayed by showEditForm() $this->tooBig = true; + $status->setResult( false, self::AS_CONTENT_TOO_BIG ); wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_CONTENT_TOO_BIG; + return $status; } if ( !$wgUser->isAllowed( 'edit' ) ) { if ( $wgUser->isAnon() ) { + $status->setResult( false, self::AS_READ_ONLY_PAGE_ANON ); wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_READ_ONLY_PAGE_ANON; + return $status; } else { + $status->fatal( 'readonlytext' ); + $status->value = self::AS_READ_ONLY_PAGE_LOGGED; wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_READ_ONLY_PAGE_LOGGED; + return $status; } } if ( wfReadOnly() ) { + $status->fatal( 'readonlytext' ); + $status->value = self::AS_READ_ONLY_PAGE; wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_READ_ONLY_PAGE; + return $status; } if ( $wgUser->pingLimiter() ) { + $status->fatal( 'actionthrottledtext' ); + $status->value = self::AS_RATE_LIMITED; wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_RATE_LIMITED; + return $status; } # If the article has been deleted while editing, don't save it without # confirmation if ( $this->wasDeletedSinceLastEdit() && !$this->recreate ) { + $status->setResult( false, self::AS_ARTICLE_WAS_DELETED ); wfProfileOut( __METHOD__ . '-checks' ); wfProfileOut( __METHOD__ ); - return self::AS_ARTICLE_WAS_DELETED; + return $status; } wfProfileOut( __METHOD__ . '-checks' ); @@ -971,43 +1019,52 @@ class EditPage { if ( $new ) { // Late check for create permission, just in case *PARANOIA* if ( !$this->mTitle->userCan( 'create' ) ) { + $status->fatal( 'nocreatetext' ); + $status->value = self::AS_NO_CREATE_PERMISSION; wfDebug( __METHOD__ . ": no create permission\n" ); wfProfileOut( __METHOD__ ); - return self::AS_NO_CREATE_PERMISSION; + return $status; } # Don't save a new article if it's blank. if ( $this->textbox1 == '' ) { + $status->setResult( false, self::AS_BLANK_ARTICLE ); wfProfileOut( __METHOD__ ); - return self::AS_BLANK_ARTICLE; + return $status; } // Run post-section-merge edit filter if ( !wfRunHooks( 'EditFilterMerged', array( $this, $this->textbox1, &$this->hookError, $this->summary ) ) ) { # Error messages etc. could be handled within the hook... + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR; wfProfileOut( __METHOD__ ); - return self::AS_HOOK_ERROR; + return $status; } elseif ( $this->hookError != '' ) { # ...or the hook could be expecting us to produce an error + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR_EXPECTED; wfProfileOut( __METHOD__ ); - return self::AS_HOOK_ERROR_EXPECTED; + return $status; } # Handle the user preference to force summaries here. Check if it's not a redirect. if ( !$this->allowBlankSummary && !Title::newFromRedirect( $this->textbox1 ) ) { if ( md5( $this->summary ) == $this->autoSumm ) { $this->missingSummary = true; + $status->fatal( 'missingsummary' ); // or 'missingcommentheader' if $section == 'new'. Blegh + $status->value = self::AS_SUMMARY_NEEDED; wfProfileOut( __METHOD__ ); - return self::AS_SUMMARY_NEEDED; + return $status; } } $text = $this->textbox1; - if ( $this->section == 'new' && $this->summary != '' ) { + if ( $this->section == 'new' && $this->summary != '' ) { $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $text; } - $retval = self::AS_SUCCESS_NEW_ARTICLE; + $status->value = self::AS_SUCCESS_NEW_ARTICLE; } else { @@ -1031,15 +1088,12 @@ class EditPage { $this->isConflict = false; wfDebug( __METHOD__ .": conflict suppressed; new section\n" ); } + } elseif ( $this->section == '' && $this->userWasLastToEdit( $wgUser->getId(), $this->edittime ) ) { + # Suppress edit conflict with self, except for section edits where merging is required. + wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" ); + $this->isConflict = false; } } - $userid = $wgUser->getId(); - - # Suppress edit conflict with self, except for section edits where merging is required. - if ( $this->isConflict && $this->section == '' && $this->userWasLastToEdit( $userid, $this->edittime ) ) { - wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" ); - $this->isConflict = false; - } if ( $this->isConflict ) { wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '" . @@ -1053,7 +1107,7 @@ class EditPage { wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" ); $this->isConflict = true; $text = $this->textbox1; // do not try to merge here! - } else if ( $this->isConflict ) { + } elseif ( $this->isConflict ) { # Attempt merge if ( $this->mergeChangesInto( $text ) ) { // Successful merge! Maybe we should tell the user the good news? @@ -1067,52 +1121,62 @@ class EditPage { } if ( $this->isConflict ) { + $status->setResult( false, self::AS_CONFLICT_DETECTED ); wfProfileOut( __METHOD__ ); - return self::AS_CONFLICT_DETECTED; + return $status; } - $oldtext = $this->mArticle->getContent(); - // Run post-section-merge edit filter if ( !wfRunHooks( 'EditFilterMerged', array( $this, $text, &$this->hookError, $this->summary ) ) ) { # Error messages etc. could be handled within the hook... + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR; wfProfileOut( __METHOD__ ); - return self::AS_HOOK_ERROR; + return $status; } elseif ( $this->hookError != '' ) { # ...or the hook could be expecting us to produce an error + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR_EXPECTED; wfProfileOut( __METHOD__ ); - return self::AS_HOOK_ERROR_EXPECTED; + return $status; } # Handle the user preference to force summaries here, but not for null edits - if ( $this->section != 'new' && !$this->allowBlankSummary && 0 != strcmp( $oldtext, $text ) + if ( $this->section != 'new' && !$this->allowBlankSummary + && 0 != strcmp( $this->mArticle->getContent(), $text ) && !Title::newFromRedirect( $text ) ) # check if it's not a redirect { if ( md5( $this->summary ) == $this->autoSumm ) { $this->missingSummary = true; + $status->fatal( 'missingsummary' ); + $status->value = self::AS_SUMMARY_NEEDED; wfProfileOut( __METHOD__ ); - return self::AS_SUMMARY_NEEDED; + return $status; } } # And a similar thing for new sections - if ( $this->section == 'new' && !$this->allowBlankSummary ) { + if ( $this->section == 'new' && !$this->allowBlankSummary ) { if ( trim( $this->summary ) == '' ) { $this->missingSummary = true; + $status->fatal( 'missingsummary' ); // or 'missingcommentheader' if $section == 'new'. Blegh + $status->value = self::AS_SUMMARY_NEEDED; wfProfileOut( __METHOD__ ); - return self::AS_SUMMARY_NEEDED; + return $status; } } # All's well wfProfileIn( __METHOD__ . '-sectionanchor' ); $sectionanchor = ''; - if ( $this->section == 'new' ) { + if ( $this->section == 'new' ) { if ( $this->textbox1 == '' ) { $this->missingComment = true; + $status->fatal( 'missingcommenttext' ); + $status->value = self::AS_TEXTBOX_EMPTY; wfProfileOut( __METHOD__ . '-sectionanchor' ); wfProfileOut( __METHOD__ ); - return self::AS_TEXTBOX_EMPTY; + return $status; } if ( $this->summary != '' ) { $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary ); @@ -1142,15 +1206,16 @@ class EditPage { $this->textbox1 = $text; $this->section = ''; - $retval = self::AS_SUCCESS_UPDATE; + $status->value = self::AS_SUCCESS_UPDATE; } // Check for length errors again now that the section is merged in $this->kblength = (int)( strlen( $text ) / 1024 ); if ( $this->kblength > $wgMaxArticleSize ) { $this->tooBig = true; + $status->setResult( false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED ); wfProfileOut( __METHOD__ ); - return self::AS_MAX_ARTICLE_SIZE_EXCEEDED; + return $status; } $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY | @@ -1158,17 +1223,18 @@ class EditPage { ( ( $this->minoredit && !$this->isNew ) ? EDIT_MINOR : 0 ) | ( $bot ? EDIT_FORCE_BOT : 0 ); - $status = $this->mArticle->doEdit( $text, $this->summary, $flags ); + $doEditStatus = $this->mArticle->doEdit( $text, $this->summary, $flags ); - if ( $status->isOK() ) { + if ( $doEditStatus->isOK() ) { $result['redirect'] = Title::newFromRedirect( $text ) !== null; $this->commitWatch(); wfProfileOut( __METHOD__ ); - return $retval; + return $status; } else { $this->isConflict = true; + $doEditStatus->value = self::AS_END; // Destroys data doEdit() put in $status->value but who cares wfProfileOut( __METHOD__ ); - return self::AS_END; + return $doEditStatus; } } @@ -1176,13 +1242,14 @@ class EditPage { * Commit the change of watch status */ protected function commitWatch() { + global $wgUser; if ( $this->watchthis xor $this->mTitle->userIsWatching() ) { $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); if ( $this->watchthis ) { - Action::factory( 'watch', $this->mArticle )->execute(); + WatchAction::doWatch( $this->mTitle, $wgUser ); } else { - Action::factory( 'unwatch', $this->mArticle )->execute(); + WatchAction::doUnwatch( $this->mTitle, $wgUser ); } $dbw->commit(); } @@ -1293,14 +1360,11 @@ class EditPage { function setHeaders() { global $wgOut; $wgOut->setRobotPolicy( 'noindex,nofollow' ); - if ( $this->formtype == 'preview' ) { - $wgOut->setPageTitleActionText( wfMsg( 'preview' ) ); - } if ( $this->isConflict ) { - $wgOut->setPageTitle( wfMsg( 'editconflict', $this->getContextTitle()->getPrefixedText() ) ); + $wgOut->setPageTitle( wfMessage( 'editconflict', $this->getContextTitle()->getPrefixedText() ) ); } elseif ( $this->section != '' ) { $msg = $this->section == 'new' ? 'editingcomment' : 'editingsection'; - $wgOut->setPageTitle( wfMsg( $msg, $this->getContextTitle()->getPrefixedText() ) ); + $wgOut->setPageTitle( wfMessage( $msg, $this->getContextTitle()->getPrefixedText() ) ); } else { # Use the title defined by DISPLAYTITLE magic word when present if ( isset( $this->mParserOutput ) @@ -1309,7 +1373,7 @@ class EditPage { } else { $title = $this->getContextTitle()->getPrefixedText(); } - $wgOut->setPageTitle( wfMsg( 'editing', $title ) ); + $wgOut->setPageTitle( wfMessage( 'editing', $title ) ); } } @@ -1323,8 +1387,6 @@ class EditPage { wfProfileIn( __METHOD__ ); - $sk = $wgUser->getSkin(); - #need to parse the preview early so that we know which templates are used, #otherwise users with "show preview after edit box" will get a blank list #we parse this near the beginning so that setHeaders can do the title @@ -1365,10 +1427,10 @@ class EditPage { $wgOut->addHTML( $this->editFormTextTop ); $templates = $this->getTemplates(); - $formattedtemplates = $sk->formatTemplates( $templates, $this->preview, $this->section != ''); + $formattedtemplates = Linker::formatTemplates( $templates, $this->preview, $this->section != ''); $hiddencats = $this->mArticle->getHiddenCategories(); - $formattedhiddencats = $sk->formatHiddenCategories( $hiddencats ); + $formattedhiddencats = Linker::formatHiddenCategories( $hiddencats ); if ( $this->wasDeletedSinceLastEdit() && 'save' != $this->formtype ) { $wgOut->wrapWikiMsg( @@ -1407,7 +1469,7 @@ HTML '
' . wfMsgExt( $key, 'parseinline', $username, "$comment" ) . Xml::checkLabel( wfMsg( 'recreate' ), 'wpRecreate', 'wpRecreate', false, - array( 'title' => $sk->titleAttrib( 'recreate' ), 'tabindex' => 1, 'id' => 'wpRecreate' ) + array( 'title' => Linker::titleAttrib( 'recreate' ), 'tabindex' => 1, 'id' => 'wpRecreate' ) ) . '
' ); @@ -1434,7 +1496,7 @@ HTML } $wgOut->addHTML( $this->editFormTextBeforeContent ); - + $wgOut->addHTML( $toolbar ); if ( $this->isConflict ) { @@ -1535,7 +1597,7 @@ HTML if ( !$this->mArticle->mRevision->userCan( Revision::DELETED_TEXT ) ) { $wgOut->wrapWikiMsg( "\n", 'rev-deleted-text-permission' ); - } else if ( $this->mArticle->mRevision->isDeleted( Revision::DELETED_TEXT ) ) { + } elseif ( $this->mArticle->mRevision->isDeleted( Revision::DELETED_TEXT ) ) { $wgOut->wrapWikiMsg( "\n", 'rev-deleted-text-view' ); } @@ -1558,7 +1620,7 @@ HTML if ( $this->isCssJsSubpage ) { # Check the skin exists if ( $this->isWrongCaseCssJsPage ) { - $wgOut->wrapWikiMsg( "
\n$1\n
", array( 'userinvalidcssjstitle', $this->getContextTitle()->getSkinFromCssJsSubpage() ) ); + $wgOut->wrapWikiMsg( "
\n$1\n
", array( 'userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage() ) ); } if ( $this->formtype !== 'preview' ) { if ( $this->isCssSubpage ) @@ -1577,7 +1639,7 @@ HTML # Then it must be protected based on static groups (regular) $noticeMsg = 'protectedpagewarning'; } - LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle->getPrefixedText(), '', + LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle, '', array( 'lim' => 1, 'msgKey' => array( $noticeMsg ) ) ); } if ( $this->mTitle->isCascadeProtected() ) { @@ -1595,7 +1657,7 @@ HTML $wgOut->wrapWikiMsg( $notice, array( 'cascadeprotectedwarning', $cascadeSourcesCount ) ); } if ( !$this->mTitle->exists() && $this->mTitle->getRestrictions( 'create' ) ) { - LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle->getPrefixedText(), '', + LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle, '', array( 'lim' => 1, 'showIfEmpty' => false, 'msgKey' => array( 'titleprotectedwarning' ), @@ -1633,7 +1695,6 @@ HTML * @return array An array in the format array( $label, $input ) */ function getSummaryInput($summary = "", $labelText = null, $inputAttrs = null, $spanLabelAttrs = null) { - global $wgUser; //Note: the maxlength is overriden in JS to 250 and to make it use UTF-8 bytes, not characters. $inputAttrs = ( is_array($inputAttrs) ? $inputAttrs : array() ) + array( 'id' => 'wpSummary', @@ -1641,7 +1702,7 @@ HTML 'tabindex' => '1', 'size' => 60, 'spellcheck' => 'true', - ) + $wgUser->getSkin()->tooltipAndAccessKeyAttribs( 'summary' ); + ) + Linker::tooltipAndAccesskeyAttribs( 'summary' ); $spanLabelAttrs = ( is_array($spanLabelAttrs) ? $spanLabelAttrs : array() ) + array( 'class' => $this->missingSummary ? 'mw-summarymissed' : 'mw-summary', @@ -1696,15 +1757,14 @@ HTML if ( !$summary || ( !$this->preview && !$this->diff ) ) return ""; - global $wgParser, $wgUser; - $sk = $wgUser->getSkin(); + global $wgParser; if ( $isSubjectPreview ) $summary = wfMsgForContent( 'newsectionsummary', $wgParser->stripSectionName( $summary ) ); $message = $isSubjectPreview ? 'subject-preview' : 'summary-preview'; - $summary = wfMsgExt( $message, 'parseinline' ) . $sk->commentBlock( $summary, $this->mTitle, $isSubjectPreview ); + $summary = wfMsgExt( $message, 'parseinline' ) . Linker::commentBlock( $summary, $this->mTitle, $isSubjectPreview ); return Xml::tags( 'div', array( 'class' => 'mw-summary-preview' ), $summary ); } @@ -1798,7 +1858,7 @@ HTML global $wgOut, $wgUser; $wikitext = $this->safeUnicodeOutput( $content ); - if ( $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 ext is empty, or Firefox in XHTML @@ -1814,6 +1874,10 @@ HTML 'style' => '' // avoid php notices when appending preferences (appending allows customAttribs['style'] to still work ); + $pageLang = $this->mTitle->getPageLanguage(); + $attribs['lang'] = $pageLang->getCode(); + $attribs['dir'] = $pageLang->getDir(); + $wgOut->addHTML( Html::textarea( $name, $wikitext, $attribs ) ); } @@ -1875,16 +1939,16 @@ HTML if( !wfMessage( $msg )->isDisabled() ) { global $wgOut; $wgOut->addHTML( '
' ); - $wgOut->addWikiMsgArray( $msg, array() ); + $wgOut->addWikiMsg( $msg ); $wgOut->addHTML( '
' ); } } protected function showEditTools() { global $wgOut; - $wgOut->addHTML( '
' ); - $wgOut->addWikiMsgArray( 'edittools', array(), array( 'content' ) ); - $wgOut->addHTML( '
' ); + $wgOut->addHTML( '
' . + wfMessage( 'edittools' )->inContentLanguage()->parse() . + '
' ); } protected function getCopywarn() { @@ -1905,7 +1969,7 @@ HTML } protected function showStandardInputs( &$tabindex = 2 ) { - global $wgOut, $wgUser; + global $wgOut; $wgOut->addHTML( "
\n" ); if ( $this->section != 'new' ) { @@ -1913,19 +1977,21 @@ HTML $wgOut->addHTML( $this->getSummaryPreview( false, $this->summary ) ); } - $checkboxes = $this->getCheckboxes( $tabindex, $wgUser->getSkin(), + $checkboxes = $this->getCheckboxes( $tabindex, array( 'minor' => $this->minoredit, 'watch' => $this->watchthis ) ); $wgOut->addHTML( "
" . implode( $checkboxes, "\n" ) . "
\n" ); $wgOut->addHTML( "
\n" ); $wgOut->addHTML( implode( $this->getEditButtons( $tabindex ), "\n" ) . "\n" ); $cancel = $this->getCancelLink(); - $separator = wfMsgExt( 'pipe-separator' , 'escapenoentities' ); + if ( $cancel !== '' ) { + $cancel .= wfMsgExt( 'pipe-separator' , 'escapenoentities' ); + } $edithelpurl = Skin::makeInternalOrExternalUrl( wfMsgForContent( 'edithelppage' ) ); $edithelp = ''. htmlspecialchars( wfMsg( 'edithelp' ) ).' '. htmlspecialchars( wfMsg( 'newwindow' ) ); - $wgOut->addHTML( " {$cancel}{$separator}{$edithelp}\n" ); + $wgOut->addHTML( " {$cancel}{$edithelp}\n" ); $wgOut->addHTML( "
\n
\n" ); } @@ -1942,7 +2008,7 @@ HTML $de = new DifferenceEngine( $this->mTitle ); $de->setText( $this->textbox2, $this->textbox1 ); - $de->showDiff( wfMsg( "yourtext" ), wfMsg( "storedversion" ) ); + $de->showDiff( wfMsgExt( 'yourtext', 'parseinline' ), wfMsg( 'storedversion' ) ); $wgOut->wrapWikiMsg( '

$1

', "yourtext" ); $this->showTextbox2(); @@ -1996,7 +2062,7 @@ HTML } else { $note = wfMsg( 'session_fail_preview' ); } - } else if ( $this->incompleteForm ) { + } elseif ( $this->incompleteForm ) { $note = wfMsg( 'edit_form_incomplete' ); } else { $note = wfMsg( 'previewnote' ); @@ -2011,31 +2077,42 @@ HTML if ( $wgRawHtml && !$this->mTokenOk ) { // Could be an offsite preview attempt. This is very unsafe if // HTML is enabled, as it could be an attack. - $parsedNote = $wgOut->parse( "
" . - wfMsg( 'session_fail_preview_html' ) . "
" ); + $parsedNote = ''; + if ( $this->textbox1 !== '' ) { + // Do not put big scary notice, if previewing the empty + // string, which happens when you initially edit + // a category page, due to automatic preview-on-open. + $parsedNote = $wgOut->parse( "
" . + wfMsg( 'session_fail_preview_html' ) . "
", true, /* interface */true ); + } wfProfileOut( __METHOD__ ); return $parsedNote; } - # don't parse user css/js, show message about preview + # don't parse non-wikitext pages, show message about preview # XXX: stupid php bug won't let us use $this->getContextTitle()->isCssJsSubpage() here -- This note has been there since r3530. Sure the bug was fixed time ago? - if ( $this->isCssJsSubpage || $this->mTitle->isCssOrJsPage() ) { - $level = 'user'; - if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { + if ( $this->isCssJsSubpage || !$this->mTitle->isWikitextPage() ) { + if( $this->mTitle->isCssJsSubpage() ) { + $level = 'user'; + } elseif( $this->mTitle->isCssOrJsPage() ) { $level = 'site'; + } else { + $level = false; } # Used messages to make sure grep find them: # Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview - if (preg_match( "/\\.css$/", $this->mTitle->getText() ) ) { - $previewtext = "
\n" . wfMsg( "{$level}csspreview" ) . "\n
"; - $class = "mw-code mw-css"; - } elseif (preg_match( "/\\.js$/", $this->mTitle->getText() ) ) { - $previewtext = "
\n" . wfMsg( "{$level}jspreview" ) . "\n
"; - $class = "mw-code mw-js"; - } else { - throw new MWException( 'A CSS/JS (sub)page but which is not css nor js!' ); + if( $level ) { + if (preg_match( "/\\.css$/", $this->mTitle->getText() ) ) { + $previewtext = "
\n" . wfMsg( "{$level}csspreview" ) . "\n
"; + $class = "mw-code mw-css"; + } elseif (preg_match( "/\\.js$/", $this->mTitle->getText() ) ) { + $previewtext = "
\n" . wfMsg( "{$level}jspreview" ) . "\n
"; + $class = "mw-code mw-js"; + } else { + throw new MWException( 'A CSS/JS (sub)page but which is not css nor js!' ); + } } $parserOptions->setTidy( true ); @@ -2057,13 +2134,6 @@ HTML wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) ); - // Parse mediawiki messages with correct target language - if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { - list( /* $unused */, $lang ) = MessageCache::singleton()->figureMessage( $this->mTitle->getText() ); - $obj = wfGetLangObj( $lang ); - $parserOptions->setTargetLanguage( $obj ); - } - $parserOptions->setTidy( true ); $parserOptions->enableLimitReport(); $parserOutput = $wgParser->parse( $this->mArticle->preSaveTransform( $toparse ), @@ -2087,7 +2157,12 @@ HTML $previewhead = "
\n" . '

' . htmlspecialchars( wfMsg( 'preview' ) ) . "

" . - $wgOut->parse( $note ) . $conflict . "
\n"; + $wgOut->parse( $note, true, /* interface */true ) . $conflict . "\n"; + + $pageLang = $this->mTitle->getPageLanguage(); + $attribs = array( 'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(), + 'class' => 'mw-content-'.$pageLang->getDir() ); + $previewHTML = Html::rawElement( 'div', $attribs, $previewHTML ); wfProfileOut( __METHOD__ ); return $previewhead . $previewHTML . $this->previewTextAfterContent; @@ -2141,23 +2216,21 @@ HTML * Produce the stock "please login to edit pages" page */ function userNotLoggedInPage() { - global $wgUser, $wgOut; - $skin = $wgUser->getSkin(); + global $wgOut; $loginTitle = SpecialPage::getTitleFor( 'Userlogin' ); - $loginLink = $skin->link( + $loginLink = Linker::linkKnown( $loginTitle, wfMsgHtml( 'loginreqlink' ), array(), - array( 'returnto' => $this->getContextTitle()->getPrefixedText() ), - array( 'known', 'noclasses' ) + array( 'returnto' => $this->getContextTitle()->getPrefixedText() ) ); - $wgOut->setPageTitle( wfMsg( 'whitelistedittitle' ) ); + $wgOut->setPageTitle( wfMessage( 'whitelistedittitle' ) ); $wgOut->setRobotPolicy( 'noindex,nofollow' ); $wgOut->setArticleRelated( false ); - $wgOut->addWikiMsgArray( 'whitelistedittext', array( $loginLink ), array( 'replaceafter' ) ); + $wgOut->addHTML( wfMessage( 'whitelistedittext' )->rawParams( $loginLink )->parse() ); $wgOut->returnToMain( false, $this->getContextTitle() ); } @@ -2168,7 +2241,7 @@ HTML function noSuchSectionPage() { global $wgOut; - $wgOut->setPageTitle( wfMsg( 'nosuchsectiontitle' ) ); + $wgOut->setPageTitle( wfMessage( 'nosuchsectiontitle' ) ); $wgOut->setRobotPolicy( 'noindex,nofollow' ); $wgOut->setArticleRelated( false ); @@ -2188,7 +2261,7 @@ HTML static function spamPage( $match = false ) { global $wgOut, $wgTitle; - $wgOut->setPageTitle( wfMsg( 'spamprotectiontitle' ) ); + $wgOut->setPageTitle( wfMessage( 'spamprotectiontitle' ) ); $wgOut->setRobotPolicy( 'noindex,nofollow' ); $wgOut->setArticleRelated( false ); @@ -2211,7 +2284,7 @@ HTML global $wgOut; $this->textbox2 = $this->textbox1; - $wgOut->setPageTitle( wfMsg( 'spamprotectiontitle' ) ); + $wgOut->setPageTitle( wfMessage( 'spamprotectiontitle' ) ); $wgOut->setRobotPolicy( 'noindex,nofollow' ); $wgOut->setArticleRelated( false ); @@ -2225,7 +2298,7 @@ HTML $wgOut->wrapWikiMsg( '

$1

', "yourdiff" ); $de = new DifferenceEngine( $this->mTitle ); $de->setText( $this->getContent(), $this->textbox2 ); - $de->showDiff( wfMsg( "storedversion" ), wfMsg( "yourtext" ) ); + $de->showDiff( wfMsg( "storedversion" ), wfMsgExt( 'yourtext', 'parseinline' ) ); $wgOut->wrapWikiMsg( '

$1

', "yourtext" ); $this->showTextbox2(); @@ -2325,10 +2398,8 @@ HTML * filename of the button image (without path), the opening * tag, the closing tag, optionally a sample text that is * inserted between the two when no selection is highlighted - * and an option to select which switches the automatic - * selection of inserted text (default is true, see - * mw-editbutton-image). The tip text is shown when the user - * moves the mouse over the button. + * and. The tip text is shown when the user moves the mouse + * over the button. * * Also here: accesskeys (key), which are not used yet until * someone can figure out a way to make them work in @@ -2389,7 +2460,6 @@ HTML 'sample' => wfMsg( 'image_sample' ), 'tip' => wfMsg( 'image_tip' ), 'key' => 'D', - 'select' => true ) : false, $imagesAvailable ? array( 'image' => $wgLang->getImageFile( 'button-media' ), @@ -2437,7 +2507,6 @@ HTML 'key' => 'R' ) ); - $toolbar = "
\n"; $script = ''; foreach ( $toolarray as $tool ) { @@ -2445,10 +2514,6 @@ HTML continue; } - if( !isset( $tool['select'] ) ) { - $tool['select'] = true; - } - $params = array( $image = $wgStylePath . '/common/images/' . $tool['image'], // Note that we use the tip both for the ALT tag and the TITLE tag of the image. @@ -2462,15 +2527,11 @@ HTML $cssId = $tool['id'], ); - $paramList = implode( ',', - array_map( array( 'Xml', 'encodeJsVar' ), $params ) ); - $script .= "mw.toolbar.addButton($paramList);\n"; + $script .= Xml::encodeJsCall( 'mw.toolbar.addButton', $params ); } - $wgOut->addScript( Html::inlineScript( - "if ( window.mediaWiki ) {{$script}}" - ) ); + $wgOut->addScript( Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( $script ) ) ); - $toolbar .= "\n
"; + $toolbar = '
'; wfRunHooks( 'EditPageBeforeEditToolbar', array( &$toolbar ) ); @@ -2482,13 +2543,12 @@ HTML * minor and watch * * @param $tabindex Current tabindex - * @param $skin Skin object * @param $checked Array of checkbox => bool, where bool indicates the checked * status of the checkbox * * @return array */ - public function getCheckboxes( &$tabindex, $skin, $checked ) { + public function getCheckboxes( &$tabindex, $checked ) { global $wgUser; $checkboxes = array(); @@ -2506,7 +2566,7 @@ HTML $checkboxes['minor'] = Xml::check( 'wpMinoredit', $checked['minor'], $attribs ) . " "; } } @@ -2522,7 +2582,7 @@ HTML $checkboxes['watch'] = Xml::check( 'wpWatchthis', $checked['watch'], $attribs ) . " "; } wfRunHooks( 'EditPageBeforeEditChecks', array( &$this, &$checkboxes, &$tabindex ) ); @@ -2613,19 +2673,16 @@ HTML * @return string */ public function getCancelLink() { - global $wgUser; - $cancelParams = array(); if ( !$this->isConflict && $this->mArticle->getOldID() > 0 ) { $cancelParams['oldid'] = $this->mArticle->getOldID(); } - return $wgUser->getSkin()->link( + return Linker::linkKnown( $this->getContextTitle(), wfMsgExt( 'cancel', array( 'parseinline' ) ), array( 'id' => 'mw-editform-cancel' ), - $cancelParams, - array( 'known', 'noclasses' ) + $cancelParams ); } @@ -2788,7 +2845,7 @@ HTML function noCreatePermission() { global $wgOut; - $wgOut->setPageTitle( wfMsg( 'nocreatetitle' ) ); + $wgOut->setPageTitle( wfMessage( 'nocreatetitle' ) ); $wgOut->addWikiMsg( 'nocreatetext' ); } @@ -2802,13 +2859,14 @@ HTML $resultDetails = false; # Allow bots to exempt some edits from bot flagging $bot = $wgUser->isAllowed( 'bot' ) && $this->bot; - $value = $this->internalAttemptSave( $resultDetails, $bot ); + $status = $this->internalAttemptSave( $resultDetails, $bot ); + // FIXME: once the interface for internalAttemptSave() is made nicer, this should use the message in $status - if ( $value == self::AS_SUCCESS_UPDATE || $value == self::AS_SUCCESS_NEW_ARTICLE ) { + if ( $status->value == self::AS_SUCCESS_UPDATE || $status->value == self::AS_SUCCESS_NEW_ARTICLE ) { $this->didSave = true; } - switch ( $value ) { + switch ( $status->value ) { case self::AS_HOOK_ERROR_EXPECTED: case self::AS_CONTENT_TOO_BIG: case self::AS_ARTICLE_WAS_DELETED: @@ -2882,6 +2940,7 @@ HTML $wgOut->permissionRequired( 'upload' ); return false; } + return false; } /**