* headaches, which may be fatal.
*/
class EditPage {
+
+ /**
+ * Status: Article successfully updated
+ */
const AS_SUCCESS_UPDATE = 200;
+
+ /**
+ * Status: Article successfully created
+ */
const AS_SUCCESS_NEW_ARTICLE = 201;
+
+ /**
+ * Status: Article update aborted by a hook function
+ */
const AS_HOOK_ERROR = 210;
+
+ /**
+ * Status: The filter function set in $wgFilterCallback returned true (= block it)
+ */
const AS_FILTERING = 211;
+
+ /**
+ * Status: A hook function returned an error
+ */
const AS_HOOK_ERROR_EXPECTED = 212;
+
+ /**
+ * Status: User is blocked from editting this page
+ */
const AS_BLOCKED_PAGE_FOR_USER = 215;
+
+ /**
+ * Status: Content too big (> $wgMaxArticleSize)
+ */
const AS_CONTENT_TOO_BIG = 216;
+
+ /**
+ * Status: User cannot edit? (not used)
+ */
const AS_USER_CANNOT_EDIT = 217;
+
+ /**
+ * Status: this anonymous user is not allowed to edit this page
+ */
const AS_READ_ONLY_PAGE_ANON = 218;
+
+ /**
+ * Status: this logged in user is not allowed to edit this page
+ */
const AS_READ_ONLY_PAGE_LOGGED = 219;
+
+ /**
+ * Status: wiki is in readonly mode (wfReadOnly() == true)
+ */
const AS_READ_ONLY_PAGE = 220;
+
+ /**
+ * Status: rate limiter for action 'edit' was tripped
+ */
const AS_RATE_LIMITED = 221;
+
+ /**
+ * Status: article was deleted while editting and param wpRecreate == false or form
+ * was not posted
+ */
const AS_ARTICLE_WAS_DELETED = 222;
+
+ /**
+ * Status: user tried to create this page, but is not allowed to do that
+ * ( Title->usercan('create') == false )
+ */
const AS_NO_CREATE_PERMISSION = 223;
+
+ /**
+ * Status: user tried to create a blank page
+ */
const AS_BLANK_ARTICLE = 224;
+
+ /**
+ * Status: (non-resolvable) edit conflict
+ */
const AS_CONFLICT_DETECTED = 225;
+
+ /**
+ * Status: no edit summary given and the user has forceeditsummary set and the user is not
+ * editting in his own userspace or talkspace and wpIgnoreBlankSummary == false
+ */
const AS_SUMMARY_NEEDED = 226;
+
+ /**
+ * Status: user tried to create a new section without content
+ */
const AS_TEXTBOX_EMPTY = 228;
+
+ /**
+ * Status: article is too big (> $wgMaxArticleSize), after merging in the new section
+ */
const AS_MAX_ARTICLE_SIZE_EXCEEDED = 229;
+
+ /**
+ * not used
+ */
const AS_OK = 230;
+
+ /**
+ * Status: WikiPage::doEdit() was unsuccessfull
+ */
const AS_END = 231;
+
+ /**
+ * Status: summary contained spam according to one of the regexes in $wgSummarySpamRegex
+ */
const AS_SPAM_ERROR = 232;
+
+ /**
+ * Status: anonymous user is not allowed to upload (User::isAllowed('upload') == false)
+ */
const AS_IMAGE_REDIRECT_ANON = 233;
+
+ /**
+ * Status: logged in user is not allowed to upload (User::isAllowed('upload') == false)
+ */
const AS_IMAGE_REDIRECT_LOGGED = 234;
/**
*/
var $mParserOutput;
+ /**
+ * Has a summary been preset using GET parameter &summary= ?
+ * @var Bool
+ */
+ var $hasPresetSummary = false;
+
var $mBaseRevision = false;
var $mShowSummaryField = true;
var $save = false, $preview = false, $diff = false;
var $minoredit = false, $watchthis = false, $recreate = false;
var $textbox1 = '', $textbox2 = '', $summary = '', $nosummary = false;
- var $edittime = '', $section = '', $starttime = '';
+ var $edittime = '', $section = '', $sectiontitle = '', $starttime = '';
var $oldid = 0, $editintro = '', $scrolltop = null, $bot = true;
# Placeholders for text injection by hooks (must be HTML)
public $suppressIntro = false;
/**
- * @todo document
* @param $article Article
*/
- public function __construct( $article ) {
+ public function __construct( Article $article ) {
$this->mArticle = $article;
$this->mTitle = $article->getTitle();
}
return;
}
- $wgOut->addModules( array( 'mediawiki.action.edit' ) );
-
- if ( $wgUser->getOption( 'uselivepreview', false ) ) {
- $wgOut->addModules( 'mediawiki.legacy.preview' );
- }
- // Bug #19334: textarea jumps when editing articles in IE8
- $wgOut->addStyle( 'common/IE80Fixes.css', 'screen', 'IE 8' );
-
wfProfileIn( __METHOD__."-business-end" );
$this->isConflict = false;
$this->isNew = !$this->mTitle->exists() || $this->section == 'new';
# Show applicable editing introductions
- if ( $this->formtype == 'initial' || $this->firsttime )
+ if ( $this->formtype == 'initial' || $this->firsttime ) {
$this->showIntro();
-
- if ( $this->mTitle->isTalkPage() ) {
- $wgOut->addWikiMsg( 'talkpagetext' );
- }
-
- # Optional notices on a per-namespace and per-page basis
- $editnotice_ns = 'editnotice-'.$this->mTitle->getNamespace();
- $editnotice_ns_message = wfMessage( $editnotice_ns )->inContentLanguage();
- if ( $editnotice_ns_message->exists() ) {
- $wgOut->addWikiText( $editnotice_ns_message->plain() );
- }
- if ( MWNamespace::hasSubpages( $this->mTitle->getNamespace() ) ) {
- $parts = explode( '/', $this->mTitle->getDBkey() );
- $editnotice_base = $editnotice_ns;
- while ( count( $parts ) > 0 ) {
- $editnotice_base .= '-'.array_shift( $parts );
- $editnotice_base_msg = wfMessage( $editnotice_base )->inContentLanguage();
- if ( $editnotice_base_msg->exists() ) {
- $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,
/**
* Display a permissions error page, like OutputPage::showPermissionsErrorPage(),
* but with the following differences:
- * - If redlink=1, the user will be redirect to the page
+ * - If redlink=1, the user will be redirected to the page
* - If there is content to display or the error occurs while either saving,
* previewing or showing the difference, it will be a
* "View source for ..." page displaying the source code after the error message.
# Use the normal message if there's nothing to display
if ( $this->firsttime && $content === '' ) {
$action = $this->mTitle->exists() ? 'edit' :
- ( $permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage' );
+ ( $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage' );
throw new PermissionsError( $action, $permErrors );
}
* @deprecated in 1.19; use displayPermissionsError() instead
*/
function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) {
+ wfDeprecated( __METHOD__, '1.19' );
+
global $wgRequest, $wgOut;
if ( $wgRequest->getBool( 'redlink' ) ) {
// The edit page was reached via a red link.
}
/**
- * @todo document
+ * This function collects the form data and uses it to populate various member variables.
* @param $request WebRequest
*/
function importFormData( &$request ) {
# Truncate for whole multibyte characters. +5 bytes for ellipsis
$this->summary = $wgLang->truncate( $request->getText( 'wpSummary' ), 250 );
- # Remove extra headings from summaries and new sections.
- $this->summary = preg_replace('/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->summary);
+ # If the summary consists of a heading, e.g. '==Foobar==', extract the title from the
+ # header syntax, e.g. 'Foobar'. This is mainly an issue when we are using wpSummary for
+ # section titles.
+ $this->summary = preg_replace( '/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->summary );
+
+ # Treat sectiontitle the same way as summary.
+ # Note that wpSectionTitle is not yet a part of the actual edit form, as wpSummary is
+ # currently doing double duty as both edit summary and section title. Right now this
+ # is just to allow API edits to work around this limitation, but this should be
+ # incorporated into the actual edit form when EditPage is rewritten (Bugs 18654, 26312).
+ $this->sectiontitle = $wgLang->truncate( $request->getText( 'wpSectionTitle' ), 250 );
+ $this->sectiontitle = preg_replace( '/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->sectiontitle );
$this->edittime = $request->getVal( 'wpEdittime' );
$this->starttime = $request->getVal( 'wpStarttime' );
$this->scrolltop = $request->getIntOrNull( 'wpScrolltop' );
- if ($this->textbox1 === '' && $request->getVal( 'wpTextbox1' ) === null) {
+ if ( $this->textbox1 === '' && $request->getVal( 'wpTextbox1' ) === null ) {
// wpTextbox1 field is missing, possibly due to being "too big"
// according to some filter rules such as Suhosin's setting for
// suhosin.request.max_value_length (d'oh)
} else {
# Not a posted form? Start with nothing.
wfDebug( __METHOD__ . ": Not a posted form.\n" );
- $this->textbox1 = '';
- $this->summary = '';
- $this->edittime = '';
- $this->starttime = wfTimestampNow();
- $this->edit = false;
- $this->preview = false;
- $this->save = false;
- $this->diff = false;
- $this->minoredit = false;
- $this->watchthis = $request->getBool( 'watchthis', false ); // Watch may be overriden by request parameters
- $this->recreate = false;
-
+ $this->textbox1 = '';
+ $this->summary = '';
+ $this->sectiontitle = '';
+ $this->edittime = '';
+ $this->starttime = wfTimestampNow();
+ $this->edit = false;
+ $this->preview = false;
+ $this->save = false;
+ $this->diff = false;
+ $this->minoredit = false;
+ $this->watchthis = $request->getBool( 'watchthis', false ); // Watch may be overriden by request parameters
+ $this->recreate = false;
+
+ // When creating a new section, we can preload a section title by passing it as the
+ // preloadtitle parameter in the URL (Bug 13100)
if ( $this->section == 'new' && $request->getVal( 'preloadtitle' ) ) {
+ $this->sectiontitle = $request->getVal( 'preloadtitle' );
+ // Once wpSummary isn't being use for setting section titles, we should delete this.
$this->summary = $request->getVal( 'preloadtitle' );
}
elseif ( $this->section != 'new' && $request->getVal( 'summary' ) ) {
$this->summary = $request->getText( 'summary' );
+ if ( $this->summary !== '' ) {
+ $this->hasPresetSummary = true;
+ }
}
if ( $request->getVal( 'minor' ) ) {
$this->bot = $request->getBool( 'bot', true );
$this->nosummary = $request->getBool( 'nosummary' );
- // @todo FIXME: Unused variable?
$this->oldid = $request->getInt( 'oldid' );
$this->live = $request->getCheck( 'live' );
global $wgOut, $wgRequest, $wgParser;
wfProfileIn( __METHOD__ );
- # Get variables from query string :P
- $section = $wgRequest->getVal( 'section' );
- $preload = $wgRequest->getVal( 'preload',
- // Custom preload text for new sections
- $section === 'new' ? 'MediaWiki:addsection-preload' : '' );
- $undoafter = $wgRequest->getVal( 'undoafter' );
- $undo = $wgRequest->getVal( 'undo' );
+ $text = false;
// For message page not locally set, use the i18n message.
// For other non-existent articles, use preload text if any.
- if ( !$this->mTitle->exists() ) {
- if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
+ if ( !$this->mTitle->exists() || $this->section == 'new' ) {
+ if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && $this->section != 'new' ) {
# If this is a system message, get the default text.
$text = $this->mTitle->getDefaultMessageText();
- if( $text === false ) {
- $text = $this->getPreloadedText( $preload );
- }
- } else {
+ }
+ if ( $text === false ) {
# If requested, preload some text.
+ $preload = $wgRequest->getVal( 'preload',
+ // Custom preload text for new sections
+ $this->section === 'new' ? 'MediaWiki:addsection-preload' : '' );
$text = $this->getPreloadedText( $preload );
}
// For existing pages, get text based on "undo" or section parameters.
} else {
- $text = $this->mArticle->getContent();
- if ( $undo > 0 && $undoafter > 0 && $undo < $undoafter ) {
- # If they got undoafter and undo round the wrong way, switch them
- list( $undo, $undoafter ) = array( $undoafter, $undo );
- }
- if ( $undo > 0 && $undo > $undoafter ) {
- # Undoing a specific edit overrides section editing; section-editing
- # doesn't work with undoing.
- if ( $undoafter ) {
+ if ( $this->section != '' ) {
+ // Get section edit text (returns $def_text for invalid sections)
+ $text = $wgParser->getSection( $this->getOriginalContent(), $this->section, $def_text );
+ } else {
+ $undoafter = $wgRequest->getInt( 'undoafter' );
+ $undo = $wgRequest->getInt( 'undo' );
+
+ if ( $undo > 0 && $undoafter > 0 ) {
+ if ( $undo < $undoafter ) {
+ # If they got undoafter and undo round the wrong way, switch them
+ list( $undo, $undoafter ) = array( $undoafter, $undo );
+ }
+
$undorev = Revision::newFromId( $undo );
$oldrev = Revision::newFromId( $undoafter );
- } else {
- $undorev = Revision::newFromId( $undo );
- $oldrev = $undorev ? $undorev->getPrevious() : null;
- }
- # Sanity check, make sure it's the right page,
- # the revisions exist and they were not deleted.
- # Otherwise, $text will be left as-is.
- if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
- $undorev->getPage() == $oldrev->getPage() &&
- $undorev->getPage() == $this->mArticle->getID() &&
- !$undorev->isDeleted( Revision::DELETED_TEXT ) &&
- !$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
-
- $undotext = $this->mArticle->getUndoText( $undorev, $oldrev );
- if ( $undotext === false ) {
- # Warn the user that something went wrong
- $this->editFormPageTop .= $wgOut->parse( '<div class="error mw-undo-failure">' .
- wfMsgNoTrans( 'undo-failure' ) . '</div>', true, /* interface */true );
- } else {
- $text = $undotext;
- # Inform the user of our success and set an automatic edit summary
- $this->editFormPageTop .= $wgOut->parse( '<div class="mw-undo-success">' .
- wfMsgNoTrans( 'undo-success' ) . '</div>', true, /* interface */true );
- $firstrev = $oldrev->getNext();
- # If we just undid one rev, use an autosummary
- 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;
+ # Sanity check, make sure it's the right page,
+ # the revisions exist and they were not deleted.
+ # Otherwise, $text will be left as-is.
+ if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
+ $undorev->getPage() == $oldrev->getPage() &&
+ $undorev->getPage() == $this->mTitle->getArticleId() &&
+ !$undorev->isDeleted( Revision::DELETED_TEXT ) &&
+ !$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
+
+ $text = $this->mArticle->getUndoText( $undorev, $oldrev );
+ if ( $text === false ) {
+ # Warn the user that something went wrong
+ $undoMsg = 'failure';
+ } else {
+ # Inform the user of our success and set an automatic edit summary
+ $undoMsg = 'success';
+
+ # If we just undid one rev, use an autosummary
+ $firstrev = $oldrev->getNext();
+ 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->undidRev = $undo;
+ $this->formtype = 'diff';
}
- $this->formtype = 'diff';
+ } else {
+ // Failed basic sanity checks.
+ // Older revisions may have been removed since the link
+ // was created, or we may simply have got bogus input.
+ $undoMsg = 'norev';
}
- } else {
- // 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( '<div class="error mw-undo-norev">' .
- wfMsgNoTrans( 'undo-norev' ) . '</div>', true, /* interface */true );
+
+ $this->editFormPageTop .= $wgOut->parse( "<div class=\"error mw-undo-{$undoMsg}\">" .
+ wfMsgNoTrans( 'undo-' . $undoMsg ) . '</div>', true, /* interface */true );
}
- } elseif ( $section != '' ) {
- if ( $section == 'new' ) {
- $text = $this->getPreloadedText( $preload );
- } else {
- // Get section edit text (returns $def_text for invalid sections)
- $text = $wgParser->getSection( $text, $section, $def_text );
+
+ if ( $text === false ) {
+ $text = $this->getOriginalContent();
}
}
}
return $text;
}
+ /**
+ * Get the content of the wanted revision, without section extraction.
+ *
+ * The result of this function can be used to compare user's input with
+ * section replaced in its context (using WikiPage::replaceSection())
+ * to the original text of the edit.
+ *
+ * This difers from Article::getContent() that when a missing revision is
+ * encountered the result will be an empty string and not the
+ * 'missing-article' message.
+ *
+ * @since 1.19
+ * @return string
+ */
+ private function getOriginalContent() {
+ if ( $this->section == 'new' ) {
+ return $this->getCurrentText();
+ }
+ $revision = $this->mArticle->getRevisionFetched();
+ if ( $revision === null ) {
+ return '';
+ }
+ return $this->mArticle->getContent();
+ }
+
+ /**
+ * Get the actual text of the page. This is basically similar to
+ * WikiPage::getRawText() except that when the page doesn't exist an empty
+ * string is returned instead of false.
+ *
+ * @since 1.19
+ * @return string
+ */
+ private function getCurrentText() {
+ $text = $this->mArticle->getRawText();
+ if ( $text === false ) {
+ return '';
+ } else {
+ return $text;
+ }
+ }
+
/**
* Use this method before edit() to preload some text into the edit box
*
if ( !empty( $this->mPreloadText ) ) {
return $this->mPreloadText;
}
-
+
if ( $preload === '' ) {
return '';
}
}
$text = $this->textbox1;
- $result['sectionanchor'] == '';
- if ( $this->section == 'new' && $this->summary != '' ) {
- $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $text;
-
- # Jump to the new section
- $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
+ $result['sectionanchor'] = '';
+ if ( $this->section == 'new' ) {
+ if ( $this->sectiontitle !== '' ) {
+ // Insert the section title above the content.
+ $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->sectiontitle ) . "\n\n" . $text;
+
+ // Jump to the new section
+ $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
+
+ // If no edit summary was specified, create one automatically from the section
+ // title and have it link to the new section. Otherwise, respect the summary as
+ // passed.
+ if ( $this->summary === '' ) {
+ $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
+ $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle );
+ }
+ } elseif ( $this->summary !== '' ) {
+ // Insert the section title above the content.
+ $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $text;
+
+ // Jump to the new section
+ $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
- # This is a new section, so create a link to the new section
- # in the revision summary.
- $cleanSummary = $wgParser->stripSectionName( $this->summary );
- $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary );
+ // Create a link to the new section from the edit summary.
+ $cleanSummary = $wgParser->stripSectionName( $this->summary );
+ $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary );
+ }
}
$status->value = self::AS_SUCCESS_NEW_ARTICLE;
# Article exists. Check for edit conflict.
$this->mArticle->clear(); # Force reload of dates, etc.
+ $timestamp = $this->mArticle->getTimestamp();
- wfDebug( "timestamp: {$this->mArticle->getTimestamp()}, edittime: {$this->edittime}\n" );
+ wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}\n" );
- if ( $this->mArticle->getTimestamp() != $this->edittime ) {
+ if ( $timestamp != $this->edittime ) {
$this->isConflict = true;
if ( $this->section == 'new' ) {
if ( $this->mArticle->getUserText() == $wgUser->getName() &&
}
}
+ // If sectiontitle is set, use it, otherwise use the summary as the section title (for
+ // backwards compatibility with old forms/bots).
+ if ( $this->sectiontitle !== '' ) {
+ $sectionTitle = $this->sectiontitle;
+ } else {
+ $sectionTitle = $this->summary;
+ }
+
if ( $this->isConflict ) {
- wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '" .
- $this->mArticle->getTimestamp() . "')\n" );
- $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $this->summary, $this->edittime );
+ wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" );
+ $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle, $this->edittime );
} else {
wfDebug( __METHOD__ . ": getting section '$this->section'\n" );
- $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $this->summary );
+ $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle );
}
if ( is_null( $text ) ) {
wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" );
# Handle the user preference to force summaries here, but not for null edits
if ( $this->section != 'new' && !$this->allowBlankSummary
- && 0 != strcmp( $this->mArticle->getContent(), $text )
+ && $this->getOriginalContent() != $text
&& !Title::newFromRedirect( $text ) ) # check if it's not a redirect
{
if ( md5( $this->summary ) == $this->autoSumm ) {
wfProfileOut( __METHOD__ );
return $status;
}
- if ( $this->summary != '' ) {
+ if ( $this->sectiontitle !== '' ) {
+ $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
+ // If no edit summary was specified, create one automatically from the section
+ // title and have it link to the new section. Otherwise, respect the summary as
+ // passed.
+ if ( $this->summary === '' ) {
+ $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
+ $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle );
+ }
+ } elseif ( $this->summary !== '' ) {
$sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
# This is a new section, so create a link to the new section
# in the revision summary.
$res = $dbw->select( 'revision',
'rev_user',
array(
- 'rev_page' => $this->mArticle->getId(),
+ 'rev_page' => $this->mTitle->getArticleId(),
'rev_timestamp > '.$dbw->addQuotes( $dbw->timestamp($edittime) )
),
__METHOD__,
*
* @param $text string
*
- * @return string|false matching string or false
+ * @return string|bool matching string or false
*/
public static function matchSpamRegex( $text ) {
global $wgSpamRegex;
*
* @parma $text string
*
- * @return string|false matching string or false
+ * @return string|bool matching string or false
*/
public static function matchSummarySpamRegex( $text ) {
global $wgSummarySpamRegex;
}
function setHeaders() {
- global $wgOut;
+ global $wgOut, $wgUser;
+
+ $wgOut->addModules( 'mediawiki.action.edit' );
+
+ if ( $wgUser->getOption( 'uselivepreview', false ) ) {
+ $wgOut->addModules( 'mediawiki.legacy.preview' );
+ }
+ // Bug #19334: textarea jumps when editing articles in IE8
+ $wgOut->addStyle( 'common/IE80Fixes.css', 'screen', 'IE 8' );
+
$wgOut->setRobotPolicy( 'noindex,nofollow' );
+
+ # Enabled article-related sidebar, toplinks, etc.
+ $wgOut->setArticleRelated( true );
+
if ( $this->isConflict ) {
$wgOut->setPageTitle( wfMessage( 'editconflict', $this->getContextTitle()->getPrefixedText() ) );
} elseif ( $this->section != '' ) {
protected function showCustomIntro() {
if ( $this->editintro ) {
$title = Title::newFromText( $this->editintro );
- if ( $title instanceof Title && $title->exists() && $title->userCanRead() ) {
+ if ( $title instanceof Title && $title->exists() && $title->userCan( 'read' ) ) {
global $wgOut;
// Added using template syntax, to take <noinclude>'s into account.
$wgOut->addWikiTextTitleTidy( '{{:' . $title->getFullText() . '}}', $this->mTitle );
$this->setHeaders();
- # Enabled article-related sidebar, toplinks, etc.
- $wgOut->setArticleRelated( true );
-
if ( $this->showHeader() === false ) {
wfProfileOut( __METHOD__ );
return;
}
- $action = htmlspecialchars( $this->getActionURL( $this->getContextTitle() ) );
-
- if ( $wgUser->getOption( 'showtoolbar' ) and !$this->isCssJsSubpage ) {
- # prepare toolbar for edit buttons
- $toolbar = EditPage::getEditToolbar();
- } else {
- $toolbar = '';
- }
-
-
$wgOut->addHTML( $this->editFormPageTop );
if ( $wgUser->getOption( 'previewontop' ) ) {
$wgOut->addHTML( $this->editFormTextTop );
- $templates = $this->getTemplates();
- $formattedtemplates = Linker::formatTemplates( $templates, $this->preview, $this->section != '');
-
- $hiddencats = $this->mArticle->getHiddenCategories();
- $formattedhiddencats = Linker::formatHiddenCategories( $hiddencats );
-
- if ( $this->wasDeletedSinceLastEdit() && 'save' != $this->formtype ) {
- $wgOut->wrapWikiMsg(
- "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
- 'deletedwhileediting' );
- } elseif ( $this->wasDeletedSinceLastEdit() ) {
- // Hide the toolbar and edit area, user can click preview to get it back
- // Add an confirmation checkbox and explanation.
- $toolbar = '';
- // @todo move this to a cleaner conditional instead of blanking a variable
+ $showToolbar = true;
+ if ( $this->wasDeletedSinceLastEdit() ) {
+ if ( $this->formtype == 'save' ) {
+ // Hide the toolbar and edit area, user can click preview to get it back
+ // Add an confirmation checkbox and explanation.
+ $showToolbar = false;
+ } else {
+ $wgOut->wrapWikiMsg( "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
+ 'deletedwhileediting' );
+ }
}
- $wgOut->addHTML( <<<HTML
-<form id="editform" name="editform" method="post" action="$action" enctype="multipart/form-data">
-HTML
-);
+
+ $wgOut->addHTML( Html::openElement( 'form', array( 'id' => 'editform', 'name' => 'editform',
+ 'method' => 'post', 'action' => $this->getActionURL( $this->getContextTitle() ),
+ 'enctype' => 'multipart/form-data' ) ) );
if ( is_callable( $formCallback ) ) {
call_user_func_array( $formCallback, array( &$wgOut ) );
#####
# For a bit more sophisticated detection of blank summaries, hash the
# automatic one and pass that in the hidden field wpAutoSummary.
- if ( $this->missingSummary ||
- ( $this->section == 'new' && $this->nosummary ) )
- $wgOut->addHTML( Html::hidden( 'wpIgnoreBlankSummary', true ) );
+ if ( $this->missingSummary || ( $this->section == 'new' && $this->nosummary ) ) {
+ $wgOut->addHTML( Html::hidden( 'wpIgnoreBlankSummary', true ) );
+ }
+
+ if ( $this->hasPresetSummary ) {
+ // If a summary has been preset using &summary= we dont want to prompt for
+ // a different summary. Only prompt for a summary if the summary is blanked.
+ // (Bug 17416)
+ $this->autoSumm = 'd41d8cd98f00b204e9800998ecf8427e'; # == md5('')
+ }
+
$autosumm = $this->autoSumm ? $this->autoSumm : md5( $this->summary );
$wgOut->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) );
- $wgOut->addHTML( Html::hidden( 'oldid', $this->mArticle->getOldID() ) );
+ $wgOut->addHTML( Html::hidden( 'oldid', $this->oldid ) );
if ( $this->section == 'new' ) {
$this->showSummaryInput( true, $this->summary );
$wgOut->addHTML( $this->editFormTextBeforeContent );
- $wgOut->addHTML( $toolbar );
+ if ( !$this->isCssJsSubpage && $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) {
+ $wgOut->addHTML( EditPage::getEditToolbar() );
+ }
if ( $this->isConflict ) {
// In an edit conflict bypass the overrideable content form method
// and fallback to the raw wpTextbox1 since editconflicts can't be
// resolved between page source edits and custom ui edits using the
// custom edit ui.
- $this->showTextbox1( null, $this->getContent() );
+ $this->textbox2 = $this->textbox1;
+ $this->textbox1 = $this->getCurrentText();
+
+ $this->showTextbox1();
} else {
$this->showContentForm();
}
$wgOut->addHTML( $this->editFormTextAfterContent );
$wgOut->addWikiText( $this->getCopywarn() );
- if ( isset($this->editFormTextAfterWarn) && $this->editFormTextAfterWarn !== '' )
- $wgOut->addHTML( $this->editFormTextAfterWarn );
+
+ $wgOut->addHTML( $this->editFormTextAfterWarn );
$this->showStandardInputs();
$this->showFormAfterText();
$this->showTosSummary();
+
$this->showEditTools();
- $wgOut->addHTML( <<<HTML
-{$this->editFormTextAfterTools}
-<div class='templatesUsed'>
-{$formattedtemplates}
-</div>
-<div class='hiddencats'>
-{$formattedhiddencats}
-</div>
-HTML
-);
+ $wgOut->addHTML( $this->editFormTextAfterTools . "\n" );
+
+ $wgOut->addHTML( Html::rawElement( 'div', array( 'class' => 'templatesUsed' ),
+ Linker::formatTemplates( $this->getTemplates(), $this->preview, $this->section != '' ) ) );
+
+ $wgOut->addHTML( Html::rawElement( 'div', array( 'class' => 'hiddencats' ),
+ Linker::formatHiddenCategories( $this->mArticle->getHiddenCategories() ) ) );
- if ( $this->isConflict )
+ if ( $this->isConflict ) {
$this->showConflict();
+ }
+
+ $wgOut->addHTML( $this->editFormTextBottom . "\n</form>\n" );
- $wgOut->addHTML( $this->editFormTextBottom );
- $wgOut->addHTML( "</form>\n" );
if ( !$wgUser->getOption( 'previewontop' ) ) {
$this->displayPreviewArea( $previewOutput, false );
}
protected function showHeader() {
global $wgOut, $wgUser, $wgMaxArticleSize, $wgLang;
+
+ if ( $this->mTitle->isTalkPage() ) {
+ $wgOut->addWikiMsg( 'talkpagetext' );
+ }
+
+ # Optional notices on a per-namespace and per-page basis
+ $editnotice_ns = 'editnotice-'.$this->mTitle->getNamespace();
+ $editnotice_ns_message = wfMessage( $editnotice_ns )->inContentLanguage();
+ if ( $editnotice_ns_message->exists() ) {
+ $wgOut->addWikiText( $editnotice_ns_message->plain() );
+ }
+ if ( MWNamespace::hasSubpages( $this->mTitle->getNamespace() ) ) {
+ $parts = explode( '/', $this->mTitle->getDBkey() );
+ $editnotice_base = $editnotice_ns;
+ while ( count( $parts ) > 0 ) {
+ $editnotice_base .= '-'.array_shift( $parts );
+ $editnotice_base_msg = wfMessage( $editnotice_base )->inContentLanguage();
+ if ( $editnotice_base_msg->exists() ) {
+ $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() );
+ }
+ }
+
if ( $this->isConflict ) {
$wgOut->wrapWikiMsg( "<div class='mw-explainconflict'>\n$1\n</div>", 'explainconflict' );
$this->edittime = $this->mArticle->getTimestamp();
}
if ( $this->section != '' && $this->section != 'new' ) {
- $matches = array();
if ( !$this->summary && !$this->preview && !$this->diff ) {
$sectionTitle = self::extractSectionTitle( $this->textbox1 );
if ( $sectionTitle !== false ) {
$wgOut->addWikiMsg( 'nonunicodebrowser' );
}
- if ( isset( $this->mArticle ) && isset( $this->mArticle->mRevision ) ) {
- // Let sysop know that this will make private content public if saved
+ if ( $this->section != 'new' ) {
+ $revision = $this->mArticle->getRevisionFetched();
+ if ( $revision ) {
+ // Let sysop know that this will make private content public if saved
- if ( !$this->mArticle->mRevision->userCan( Revision::DELETED_TEXT ) ) {
- $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-permission' );
- } elseif ( $this->mArticle->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
- $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-view' );
- }
+ if ( !$revision->userCan( Revision::DELETED_TEXT ) ) {
+ $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-permission' );
+ } elseif ( $revision->isDeleted( Revision::DELETED_TEXT ) ) {
+ $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-view' );
+ }
- if ( !$this->mArticle->mRevision->isCurrent() ) {
- $this->mArticle->setOldSubtitle( $this->mArticle->mRevision->getId() );
- $wgOut->addWikiMsg( 'editingold' );
+ if ( !$revision->isCurrent() ) {
+ $this->mArticle->setOldSubtitle( $revision->getId() );
+ $wgOut->addWikiMsg( 'editingold' );
+ }
+ } elseif ( $this->mTitle->exists() ) {
+ // Something went wrong
+
+ $wgOut->wrapWikiMsg( "<div class='errorbox'>\n$1\n</div>\n",
+ array( 'missing-article', $this->mTitle->getPrefixedText(),
+ wfMsgNoTrans( 'missingarticle-rev', $this->oldid ) ) );
}
}
}
* The $textoverride method can be used by subclasses overriding showContentForm
* to pass back to this method.
*
- * @param $customAttribs An array of html attributes to use in the textarea
+ * @param $customAttribs array of html attributes to use in the textarea
* @param $textoverride String: optional text to override $this->textarea1 with
*/
- protected function showTextbox1($customAttribs = null, $textoverride = null) {
- $classes = array(); // Textarea CSS
- if ( $this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected( 'edit' ) ) {
- # Is the title semi-protected?
- if ( $this->mTitle->isSemiProtected() ) {
- $classes[] = 'mw-textarea-sprotected';
- } else {
- # Then it must be protected based on static groups (regular)
- $classes[] = 'mw-textarea-protected';
+ protected function showTextbox1( $customAttribs = null, $textoverride = null ) {
+ if ( $this->wasDeletedSinceLastEdit() && $this->formtype == 'save' ) {
+ $attribs = array( 'style' => 'display:none;' );
+ } else {
+ $classes = array(); // Textarea CSS
+ if ( $this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected( 'edit' ) ) {
+ # Is the title semi-protected?
+ if ( $this->mTitle->isSemiProtected() ) {
+ $classes[] = 'mw-textarea-sprotected';
+ } else {
+ # Then it must be protected based on static groups (regular)
+ $classes[] = 'mw-textarea-protected';
+ }
+ # Is the title cascade-protected?
+ if ( $this->mTitle->isCascadeProtected() ) {
+ $classes[] = 'mw-textarea-cprotected';
+ }
}
- # Is the title cascade-protected?
- if ( $this->mTitle->isCascadeProtected() ) {
- $classes[] = 'mw-textarea-cprotected';
+
+ $attribs = array( 'tabindex' => 1 );
+
+ if ( is_array( $customAttribs ) ) {
+ $attribs += $customAttribs;
}
- }
- $attribs = array( 'tabindex' => 1 );
- if ( is_array($customAttribs) )
- $attribs += $customAttribs;
- if ( $this->wasDeletedSinceLastEdit() )
- $attribs['type'] = 'hidden';
- if ( !empty( $classes ) ) {
- if ( isset($attribs['class']) )
- $classes[] = $attribs['class'];
- $attribs['class'] = implode( ' ', $classes );
+ if ( count( $classes ) ) {
+ if ( isset( $attribs['class'] ) ) {
+ $classes[] = $attribs['class'];
+ }
+ $attribs['class'] = implode( ' ', $classes );
+ }
}
- $this->showTextbox( isset($textoverride) ? $textoverride : $this->textbox1, 'wpTextbox1', $attribs );
+ $this->showTextbox( $textoverride !== null ? $textoverride : $this->textbox1, 'wpTextbox1', $attribs );
}
protected function showTextbox2() {
* save and then make a comparison.
*/
function showDiff() {
- global $wgUser, $wgContLang, $wgParser;
+ global $wgUser, $wgContLang, $wgParser, $wgOut;
- $oldtext = $this->mArticle->fetchContent();
+ $oldtext = $this->getOriginalContent();
$newtext = $this->mArticle->replaceSection(
$this->section, $this->textbox1, $this->summary, $this->edittime );
$popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
$newtext = $wgParser->preSaveTransform( $newtext, $this->mTitle, $wgUser, $popts );
- $oldtitle = wfMsgExt( 'currentrev', array( 'parseinline' ) );
- $newtitle = wfMsgExt( 'yourtext', array( 'parseinline' ) );
+
if ( $oldtext !== false || $newtext != '' ) {
+ $oldtitle = wfMsgExt( 'currentrev', array( 'parseinline' ) );
+ $newtitle = wfMsgExt( 'yourtext', array( 'parseinline' ) );
+
$de = new DifferenceEngine( $this->mArticle->getContext() );
$de->setText( $oldtext, $newtext );
$difftext = $de->getDiff( $oldtitle, $newtitle );
$difftext = '';
}
- global $wgOut;
$wgOut->addHTML( '<div id="wikiDiff">' . $difftext . '</div>' );
}
*/
protected function showConflict() {
global $wgOut;
- $this->textbox2 = $this->textbox1;
- $this->textbox1 = $this->getContent();
+
if ( wfRunHooks( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
*/
public function getCancelLink() {
$cancelParams = array();
- if ( !$this->isConflict && $this->mArticle->getOldID() > 0 ) {
- $cancelParams['oldid'] = $this->mArticle->getOldID();
+ if ( !$this->isConflict && $this->oldid > 0 ) {
+ $cancelParams['oldid'] = $this->oldid;
}
return Linker::linkKnown(
$previewHTML = $parserOutput->mText;
$previewHTML .= "<pre class=\"$class\" dir=\"ltr\">\n" . htmlspecialchars( $this->textbox1 ) . "\n</pre>\n";
} else {
- $rt = Title::newFromRedirectArray( $this->textbox1 );
- if ( $rt ) {
- $previewHTML = $this->mArticle->viewRedirect( $rt, false );
- } else {
- $toparse = $this->textbox1;
+ $toparse = $this->textbox1;
- # If we're adding a comment, we need to show the
- # summary as the headline
- if ( $this->section == "new" && $this->summary != "" ) {
- $toparse = "== {$this->summary} ==\n\n" . $toparse;
- }
+ # If we're adding a comment, we need to show the
+ # summary as the headline
+ if ( $this->section == "new" && $this->summary != "" ) {
+ $toparse = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $toparse;
+ }
- wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
+ wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
- $parserOptions->enableLimitReport();
+ $parserOptions->enableLimitReport();
- $toparse = $wgParser->preSaveTransform( $toparse, $this->mTitle, $wgUser, $parserOptions );
- $parserOutput = $wgParser->parse( $toparse, $this->mTitle, $parserOptions );
+ $toparse = $wgParser->preSaveTransform( $toparse, $this->mTitle, $wgUser, $parserOptions );
+ $parserOutput = $wgParser->parse( $toparse, $this->mTitle, $parserOptions );
+ $rt = Title::newFromRedirectArray( $this->textbox1 );
+ if ( $rt ) {
+ $previewHTML = $this->mArticle->viewRedirect( $rt, false );
+ } else {
$previewHTML = $parserOutput->getText();
- $this->mParserOutput = $parserOutput;
- $wgOut->addParserOutputNoText( $parserOutput );
+ }
- if ( count( $parserOutput->getWarnings() ) ) {
- $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
- }
+ $this->mParserOutput = $parserOutput;
+ $wgOut->addParserOutputNoText( $parserOutput );
+
+ if ( count( $parserOutput->getWarnings() ) ) {
+ $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
}
}
}
return $templates;
} else {
- return $this->mArticle->getUsedTemplates();
+ return $this->mTitle->getTemplateLinksFrom();
}
}
)
);
- $script = '';
+ $script = 'mw.loader.using("mediawiki.action.edit", function() {';
foreach ( $toolarray as $tool ) {
if ( !$tool ) {
continue;
$script .= Xml::encodeJsCall( 'mw.toolbar.addButton', $params );
}
+
+ // This used to be called on DOMReady from mediawiki.action.edit, which
+ // ended up causing race conditions with the setup code above.
+ $script .= "\n" .
+ "// Create button bar\n" .
+ "$(function() { mw.toolbar.init(); } );\n";
+
+ $script .= '});';
$wgOut->addScript( Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( $script ) ) );
$toolbar = '<div id="toolbar"></div>';
* Returns an array of html code of the following checkboxes:
* minor and watch
*
- * @param $tabindex Current tabindex
+ * @param $tabindex int Current tabindex
* @param $checked Array of checkbox => bool, where bool indicates the checked
* status of the checkbox
*
* Returns an array of html code of the following buttons:
* save, diff, preview and live
*
- * @param $tabindex Current tabindex
+ * @param $tabindex int Current tabindex
*
* @return array
*/
* @deprecated in 1.19; throw an exception directly instead
*/
function blockedPage() {
+ wfDeprecated( __METHOD__, '1.19' );
global $wgUser;
throw new UserBlockedError( $wgUser->mBlock );
* @deprecated in 1.19; throw an exception directly instead
*/
function userNotLoggedInPage() {
+ wfDeprecated( __METHOD__, '1.19' );
throw new PermissionsError( 'edit' );
}
* @deprecated in 1.19; throw an exception directly instead
*/
function noCreatePermission() {
+ wfDeprecated( __METHOD__, '1.19' );
$permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage';
throw new PermissionsError( $permission );
}
/**
* Produce the stock "your edit contains spam" page
*
- * @param $match Text which triggered one or more filters
+ * @param $match string Text which triggered one or more filters
* @deprecated since 1.17 Use method spamPageWithContent() instead
*/
static function spamPage( $match = false ) {
+ wfDeprecated( __METHOD__, '1.17' );
+
global $wgOut, $wgTitle;
$wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) );
/**
* Show "your edit contains spam" page with your diff and text
*
- * @param $match Text which triggered one or more filters
+ * @param $match array|string|bool Text (or array of texts) which triggered one or more filters
*/
public function spamPageWithContent( $match = false ) {
global $wgOut;
$this->textbox2 = $this->textbox1;
+ if( is_array( $match ) ){
+ $match = $wgLang->listToText( $match );
+ }
+
$wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) );
$wgOut->addHTML( '<div id="spamprotected">' );
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
$de = new DifferenceEngine( $this->mArticle->getContext() );
- $de->setText( $this->getContent(), $this->textbox2 );
+ $de->setText( $this->getCurrentText(), $this->textbox2 );
$de->showDiff( wfMsg( "storedversion" ), wfMsgExt( 'yourtext', 'parseinline' ) );
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );