's into account.
+ $wgOut->addWikiTextTitleTidy( '{{:' . $title->getFullText() . '}}', $this->mTitle );
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Send the edit form and related headers to $wgOut
* @param $formCallback Callback that takes an OutputPage parameter; will be called
* during form output near the top, for captchas and the like.
*/
@@ -1317,37 +1713,24 @@ class EditPage {
wfProfileIn( __METHOD__ );
- #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
- #setting work instead of leaving it in getPreviewText
+ # 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
+ # setting work instead of leaving it in getPreviewText
$previewOutput = '';
if ( $this->formtype == 'preview' ) {
$previewOutput = $this->getPreviewText();
}
- wfRunHooks( 'EditPage::showEditForm:initial', array( &$this ) );
+ wfRunHooks( 'EditPage::showEditForm:initial', array( &$this, &$wgOut ) );
$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' ) ) {
@@ -1356,26 +1739,21 @@ class EditPage {
$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(
- "\n$1\n
",
- '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( "\n$1\n
",
+ 'deletedwhileediting' );
+ }
}
- $wgOut->addHTML( <<
-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 ) );
@@ -1412,13 +1790,21 @@ HTML
#####
# 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 = 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 );
@@ -1427,14 +1813,19 @@ HTML
$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();
}
@@ -1442,32 +1833,31 @@ HTML
$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( <<editFormTextAfterTools}
-
-{$formattedtemplates}
-
-
-{$formattedhiddencats}
-
-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\n" );
- $wgOut->addHTML( $this->editFormTextBottom );
- $wgOut->addHTML( "\n" );
if ( !$wgUser->getOption( 'previewontop' ) ) {
$this->displayPreviewArea( $previewOutput, false );
}
@@ -1475,8 +1865,54 @@ HTML
wfProfileOut( __METHOD__ );
}
+ /**
+ * Extract the section title from current section text, if any.
+ *
+ * @param string $text
+ * @return Mixed|string or false
+ */
+ public static function extractSectionTitle( $text ) {
+ preg_match( "/^(=+)(.+)\\1\\s*(\n|$)/i", $text, $matches );
+ if ( !empty( $matches[2] ) ) {
+ global $wgParser;
+ return $wgParser->stripSectionName( trim( $matches[2] ) );
+ } else {
+ return 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( "\n$1\n
", 'explainconflict' );
$this->edittime = $this->mArticle->getTimestamp();
@@ -1490,14 +1926,10 @@ HTML
}
if ( $this->section != '' && $this->section != 'new' ) {
- $matches = array();
if ( !$this->summary && !$this->preview && !$this->diff ) {
- preg_match( "/^(=+)(.+)\\1/mi", $this->textbox1, $matches );
- if ( !empty( $matches[2] ) ) {
- global $wgParser;
- $this->summary = "/* " .
- $wgParser->stripSectionName(trim($matches[2])) .
- " */ ";
+ $sectionTitle = self::extractSectionTitle( $this->textbox1 );
+ if ( $sectionTitle !== false ) {
+ $this->summary = "/* $sectionTitle */ ";
}
}
}
@@ -1522,18 +1954,27 @@ HTML
$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( "\n$1\n
\n", 'rev-deleted-text-permission' );
- } elseif ( $this->mArticle->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
- $wgOut->wrapWikiMsg( "\n$1\n
\n", 'rev-deleted-text-view' );
- }
+ if ( !$revision->userCan( Revision::DELETED_TEXT ) ) {
+ $wgOut->wrapWikiMsg( "\n$1\n
\n", 'rev-deleted-text-permission' );
+ } elseif ( $revision->isDeleted( Revision::DELETED_TEXT ) ) {
+ $wgOut->wrapWikiMsg( "\n$1\n
\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( "\n$1\n
\n",
+ array( 'missing-article', $this->mTitle->getPrefixedText(),
+ wfMsgNoTrans( 'missingarticle-rev', $this->oldid ) ) );
}
}
}
@@ -1550,7 +1991,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 )
@@ -1569,17 +2010,17 @@ 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() ) {
# Is this page under cascading protection from some source pages?
- list($cascadeSources, /* $restrictions */) = $this->mTitle->getCascadeProtectionSources();
+ list( $cascadeSources, /* $restrictions */ ) = $this->mTitle->getCascadeProtectionSources();
$notice = "\n$1\n";
$cascadeSourcesCount = count( $cascadeSources );
if ( $cascadeSourcesCount > 0 ) {
# Explain, and list the titles responsible
- foreach( $cascadeSources as $page ) {
+ foreach ( $cascadeSources as $page ) {
$notice .= '* [[:' . $page->getPrefixedText() . "]]\n";
}
}
@@ -1587,8 +2028,8 @@ HTML
$wgOut->wrapWikiMsg( $notice, array( 'cascadeprotectedwarning', $cascadeSourcesCount ) );
}
if ( !$this->mTitle->exists() && $this->mTitle->getRestrictions( 'create' ) ) {
- LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle->getPrefixedText(), '',
- array( 'lim' => 1,
+ LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle, '',
+ array( 'lim' => 1,
'showIfEmpty' => false,
'msgKey' => array( 'titleprotectedwarning' ),
'wrap' => "
\n$1
" ) );
@@ -1602,7 +2043,7 @@ HTML
$wgOut->wrapWikiMsg( "
\n$1\n
",
array( 'longpageerror', $wgLang->formatNum( $this->kblength ), $wgLang->formatNum( $wgMaxArticleSize ) ) );
} else {
- if( !wfMessage('longpage-hint')->isDisabled() ) {
+ if ( !wfMessage( 'longpage-hint' )->isDisabled() ) {
$wgOut->wrapWikiMsg( "
\n$1\n
",
array( 'longpage-hint', $wgLang->formatSize( strlen( $this->textbox1 ) ), strlen( $this->textbox1 ) )
);
@@ -1624,9 +2065,9 @@ HTML
*
* @return array An array in the format array( $label, $input )
*/
- function getSummaryInput($summary = "", $labelText = null, $inputAttrs = null, $spanLabelAttrs = null) {
- //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(
+ function getSummaryInput( $summary = "", $labelText = null, $inputAttrs = null, $spanLabelAttrs = null ) {
+ // 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',
'maxlength' => '200',
'tabindex' => '1',
@@ -1634,7 +2075,7 @@ HTML
'spellcheck' => 'true',
) + Linker::tooltipAndAccesskeyAttribs( 'summary' );
- $spanLabelAttrs = ( is_array($spanLabelAttrs) ? $spanLabelAttrs : array() ) + array(
+ $spanLabelAttrs = ( is_array( $spanLabelAttrs ) ? $spanLabelAttrs : array() ) + array(
'class' => $this->missingSummary ? 'mw-summarymissed' : 'mw-summary',
'id' => "wpSummaryLabel"
);
@@ -1672,8 +2113,8 @@ HTML
}
$summary = $wgContLang->recodeForEdit( $summary );
$labelText = wfMsgExt( $isSubjectPreview ? 'subject' : 'summary', 'parseinline' );
- list($label, $input) = $this->getSummaryInput($summary, $labelText, array( 'class' => $summaryClass ), array());
- $wgOut->addHTML("{$label} {$input}");
+ list( $label, $input ) = $this->getSummaryInput( $summary, $labelText, array( 'class' => $summaryClass ), array() );
+ $wgOut->addHTML( "{$label} {$input}" );
}
/**
@@ -1710,7 +2151,7 @@ HTML
HTML
);
if ( !$this->checkUnicodeCompliantBrowser() )
- $wgOut->addHTML(Html::hidden( 'safemode', '1' ));
+ $wgOut->addHTML( Html::hidden( 'safemode', '1' ) );
}
protected function showFormAfterText() {
@@ -1727,7 +2168,7 @@ HTML
* include the constant suffix to prevent editing from
* broken text-mangling proxies.
*/
- $wgOut->addHTML( "\n" . Html::hidden( "wpEditToken", $wgUser->editToken() ) . "\n" );
+ $wgOut->addHTML( "\n" . Html::hidden( "wpEditToken", $wgUser->getEditToken() ) . "\n" );
}
/**
@@ -1747,37 +2188,43 @@ HTML
* 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() {
@@ -1788,7 +2235,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
@@ -1830,7 +2277,7 @@ HTML
$wgOut->addHTML( '
' );
- if ( $this->formtype == 'diff') {
+ if ( $this->formtype == 'diff' ) {
$this->showDiff();
}
}
@@ -1843,18 +2290,52 @@ HTML
*/
protected function showPreview( $text ) {
global $wgOut;
- if ( $this->mTitle->getNamespace() == NS_CATEGORY) {
+ if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
$this->mArticle->openShowCategory();
}
# This hook seems slightly odd here, but makes things more
# consistent for extensions.
- wfRunHooks( 'OutputPageBeforeHTML',array( &$wgOut, &$text ) );
+ wfRunHooks( 'OutputPageBeforeHTML', array( &$wgOut, &$text ) );
$wgOut->addHTML( $text );
if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
$this->mArticle->closeShowCategory();
}
}
+ /**
+ * Get a diff between the current contents of the edit box and the
+ * version of the page we're editing from.
+ *
+ * If this is a section edit, we'll replace the section as for final
+ * save and then make a comparison.
+ */
+ function showDiff() {
+ global $wgUser, $wgContLang, $wgParser, $wgOut;
+
+ $oldtext = $this->mArticle->getRawText();
+ $newtext = $this->mArticle->replaceSection(
+ $this->section, $this->textbox1, $this->summary, $this->edittime );
+
+ wfRunHooks( 'EditPageGetDiffText', array( $this, &$newtext ) );
+
+ $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
+ $newtext = $wgParser->preSaveTransform( $newtext, $this->mTitle, $wgUser, $popts );
+
+ 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 );
+ $de->showDiffStyle();
+ } else {
+ $difftext = '';
+ }
+
+ $wgOut->addHTML( '' . $difftext . '
' );
+ }
+
/**
* Give a chance for site and per-namespace customizations of
* terms of service summary link that might exist separately
@@ -1866,7 +2347,7 @@ HTML
protected function showTosSummary() {
$msg = 'editpage-tos-summary';
wfRunHooks( 'EditPageTosSummary', array( $this->mTitle, &$msg ) );
- if( !wfMessage( $msg )->isDisabled() ) {
+ if ( !wfMessage( $msg )->isDisabled() ) {
global $wgOut;
$wgOut->addHTML( '' );
$wgOut->addWikiMsg( $msg );
@@ -1895,7 +2376,7 @@ HTML
wfRunHooks( 'EditPageCopyrightWarning', array( $this->mTitle, &$copywarnMsg ) );
return "
\n" .
- call_user_func_array("wfMsgNoTrans", $copywarnMsg) . "\n
";
+ call_user_func_array( "wfMsgNoTrans", $copywarnMsg ) . "\n
";
}
protected function showStandardInputs( &$tabindex = 2 ) {
@@ -1918,8 +2399,8 @@ HTML
$cancel .= wfMsgExt( 'pipe-separator' , 'escapenoentities' );
}
$edithelpurl = Skin::makeInternalOrExternalUrl( wfMsgForContent( 'edithelppage' ) );
- $edithelp = ''.
- htmlspecialchars( wfMsg( 'edithelp' ) ).' '.
+ $edithelp = '' .
+ htmlspecialchars( wfMsg( 'edithelp' ) ) . ' ' .
htmlspecialchars( wfMsg( 'newwindow' ) );
$wgOut->addHTML( " {$cancel}{$edithelp}\n" );
$wgOut->addHTML( "\n\n" );
@@ -1931,20 +2412,75 @@ HTML
*/
protected function showConflict() {
global $wgOut;
- $this->textbox2 = $this->textbox1;
- $this->textbox1 = $this->getContent();
+
if ( wfRunHooks( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
$wgOut->wrapWikiMsg( '$1
', "yourdiff" );
- $de = new DifferenceEngine( $this->mTitle );
+ $de = new DifferenceEngine( $this->mArticle->getContext() );
$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();
}
}
+ /**
+ * @return string
+ */
+ public function getCancelLink() {
+ $cancelParams = array();
+ if ( !$this->isConflict && $this->oldid > 0 ) {
+ $cancelParams['oldid'] = $this->oldid;
+ }
+
+ return Linker::linkKnown(
+ $this->getContextTitle(),
+ wfMsgExt( 'cancel', array( 'parseinline' ) ),
+ array( 'id' => 'mw-editform-cancel' ),
+ $cancelParams
+ );
+ }
+
+ /**
+ * Returns the URL to use in the form's action attribute.
+ * This is used by EditPage subclasses when simply customizing the action
+ * variable in the constructor is not enough. This can be used when the
+ * EditPage lives inside of a Special page rather than a custom page action.
+ *
+ * @param $title Title object for which is being edited (where we go to for &action= links)
+ * @return string
+ */
+ protected function getActionURL( Title $title ) {
+ return $title->getLocalURL( array( 'action' => $this->action ) );
+ }
+
+ /**
+ * Check if a page was deleted while the user was editing it, before submit.
+ * Note that we rely on the logging table, which hasn't been always there,
+ * but that doesn't matter, because this only applies to brand new
+ * deletes.
+ */
+ protected function wasDeletedSinceLastEdit() {
+ if ( $this->deletedSinceEdit !== null ) {
+ return $this->deletedSinceEdit;
+ }
+
+ $this->deletedSinceEdit = false;
+
+ if ( $this->mTitle->isDeletedQuick() ) {
+ $this->lastDelete = $this->getLastDelete();
+ if ( $this->lastDelete ) {
+ $deleteTime = wfTimestamp( TS_MW, $this->lastDelete->log_timestamp );
+ if ( $deleteTime > $this->starttime ) {
+ $this->deletedSinceEdit = true;
+ }
+ }
+ }
+
+ return $this->deletedSinceEdit;
+ }
+
protected function getLastDelete() {
$dbr = wfGetDB( DB_SLAVE );
$data = $dbr->selectRow(
@@ -1968,10 +2504,10 @@ HTML
array( 'LIMIT' => 1, 'ORDER BY' => 'log_timestamp DESC' )
);
// Quick paranoid permission checks...
- if( is_object( $data ) ) {
- if( $data->log_deleted & LogPage::DELETED_USER )
+ if ( is_object( $data ) ) {
+ if ( $data->log_deleted & LogPage::DELETED_USER )
$data->user_name = wfMsgHtml( 'rev-deleted-user' );
- if( $data->log_deleted & LogPage::DELETED_COMMENT )
+ if ( $data->log_deleted & LogPage::DELETED_COMMENT )
$data->log_comment = wfMsgHtml( 'rev-deleted-comment' );
}
return $data;
@@ -1982,10 +2518,25 @@ HTML
* @return string
*/
function getPreviewText() {
- global $wgOut, $wgUser, $wgParser;
+ global $wgOut, $wgUser, $wgParser, $wgRawHtml;
wfProfileIn( __METHOD__ );
+ 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 = '';
+ 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;
+ }
+
if ( $this->mTriedSave && !$this->mTokenOk ) {
if ( $this->mTokenOkExceptSuffix ) {
$note = wfMsg( 'token_suffix_mismatch' );
@@ -2000,309 +2551,107 @@ HTML
$parserOptions = ParserOptions::newFromUser( $wgUser );
$parserOptions->setEditSection( false );
+ $parserOptions->setTidy( true );
$parserOptions->setIsPreview( true );
- $parserOptions->setIsSectionPreview( !is_null($this->section) && $this->section !== '' );
-
- global $wgRawHtml;
- 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 = '';
- 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' ) . "
" );
- }
- wfProfileOut( __METHOD__ );
- return $parsedNote;
- }
+ $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
- # 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 );
$parserOutput = $wgParser->parse( $previewtext, $this->mTitle, $parserOptions );
$previewHTML = $parserOutput->mText;
$previewHTML .= "\n" . htmlspecialchars( $this->textbox1 ) . "\n
\n";
} else {
- $rt = Title::newFromRedirectArray( $this->textbox1 );
- if ( $rt ) {
- $previewHTML = $this->mArticle->viewRedirect( $rt, false );
- } else {
- $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;
- }
-
- wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
-
- $parserOptions->setTidy( true );
- $parserOptions->enableLimitReport();
- $parserOutput = $wgParser->parse( $this->mArticle->preSaveTransform( $toparse ),
- $this->mTitle, $parserOptions );
-
- $previewHTML = $parserOutput->getText();
- $this->mParserOutput = $parserOutput;
- $wgOut->addParserOutputNoText( $parserOutput );
+ $toparse = $this->textbox1;
- if ( count( $parserOutput->getWarnings() ) ) {
- $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
- }
+ # 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;
}
- }
- if( $this->isConflict ) {
- $conflict = '' . htmlspecialchars( wfMsg( 'previewconflict' ) ) . "
\n";
- } else {
- $conflict = '
';
- }
+ wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
- $previewhead = "\n" .
- '" .
- $wgOut->parse( $note ) . $conflict . "
\n";
+ $parserOptions->enableLimitReport();
- $pageLang = $this->mTitle->getPageLanguage();
- $attribs = array( 'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(),
- 'class' => 'mw-content-'.$pageLang->getDir() );
- $previewHTML = Html::rawElement( 'div', $attribs, $previewHTML );
+ $toparse = $wgParser->preSaveTransform( $toparse, $this->mTitle, $wgUser, $parserOptions );
+ $parserOutput = $wgParser->parse( $toparse, $this->mTitle, $parserOptions );
- wfProfileOut( __METHOD__ );
- return $previewhead . $previewHTML . $this->previewTextAfterContent;
- }
-
- /**
- * @return Array
- */
- function getTemplates() {
- if ( $this->preview || $this->section != '' ) {
- $templates = array();
- if ( !isset( $this->mParserOutput ) ) {
- return $templates;
- }
- foreach( $this->mParserOutput->getTemplates() as $ns => $template) {
- foreach( array_keys( $template ) as $dbk ) {
- $templates[] = Title::makeTitle($ns, $dbk);
- }
+ $rt = Title::newFromRedirectArray( $this->textbox1 );
+ if ( $rt ) {
+ $previewHTML = $this->mArticle->viewRedirect( $rt, false );
+ } else {
+ $previewHTML = $parserOutput->getText();
}
- return $templates;
- } else {
- return $this->mArticle->getUsedTemplates();
- }
- }
-
- /**
- * Call the stock "user is blocked" page
- */
- function blockedPage() {
- global $wgOut;
- $wgOut->blockedPage( false ); # Standard block notice on the top, don't 'return'
-
- # If the user made changes, preserve them when showing the markup
- # (This happens when a user is blocked during edit, for instance)
- $first = $this->firsttime || ( !$this->save && $this->textbox1 == '' );
- if ( $first ) {
- $source = $this->mTitle->exists() ? $this->getContent() : false;
- } else {
- $source = $this->textbox1;
- }
-
- # Spit out the source or the user's modified version
- if ( $source !== false ) {
- $wgOut->addHTML( '
' );
- $wgOut->addWikiMsg( $first ? 'blockedoriginalsource' : 'blockededitsource', $this->mTitle->getPrefixedText() );
- $this->showTextbox1( array( 'readonly' ), $source );
- }
- }
-
- /**
- * Produce the stock "please login to edit pages" page
- */
- function userNotLoggedInPage() {
- global $wgOut;
-
- $loginTitle = SpecialPage::getTitleFor( 'Userlogin' );
- $loginLink = Linker::linkKnown(
- $loginTitle,
- wfMsgHtml( 'loginreqlink' ),
- array(),
- array( 'returnto' => $this->getContextTitle()->getPrefixedText() )
- );
-
- $wgOut->setPageTitle( wfMsg( 'whitelistedittitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
-
- $wgOut->addHTML( wfMessage( 'whitelistedittext' )->rawParams( $loginLink )->parse() );
- $wgOut->returnToMain( false, $this->getContextTitle() );
- }
-
- /**
- * Creates a basic error page which informs the user that
- * they have attempted to edit a nonexistent section.
- */
- function noSuchSectionPage() {
- global $wgOut;
-
- $wgOut->setPageTitle( wfMsg( 'nosuchsectiontitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
-
- $res = wfMsgExt( 'nosuchsectiontext', 'parse', $this->section );
- wfRunHooks( 'EditPageNoSuchSection', array( &$this, &$res ) );
- $wgOut->addHTML( $res );
-
- $wgOut->returnToMain( false, $this->mTitle );
- }
-
- /**
- * Produce the stock "your edit contains spam" page
- *
- * @param $match Text which triggered one or more filters
- * @deprecated since 1.17 Use method spamPageWithContent() instead
- */
- static function spamPage( $match = false ) {
- global $wgOut, $wgTitle;
-
- $wgOut->setPageTitle( wfMsg( 'spamprotectiontitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
-
- $wgOut->addHTML( '' );
- $wgOut->addWikiMsg( 'spamprotectiontext' );
- if ( $match ) {
- $wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) );
- }
- $wgOut->addHTML( '
' );
-
- $wgOut->returnToMain( false, $wgTitle );
- }
-
- /**
- * Show "your edit contains spam" page with your diff and text
- *
- * @param $match Text which triggered one or more filters
- */
- public function spamPageWithContent( $match = false ) {
- global $wgOut;
- $this->textbox2 = $this->textbox1;
-
- $wgOut->setPageTitle( wfMsg( 'spamprotectiontitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
-
- $wgOut->addHTML( '' );
- $wgOut->addWikiMsg( 'spamprotectiontext' );
- if ( $match ) {
- $wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) );
- }
- $wgOut->addHTML( '
' );
-
- $wgOut->wrapWikiMsg( '$1
', "yourdiff" );
- $de = new DifferenceEngine( $this->mTitle );
- $de->setText( $this->getContent(), $this->textbox2 );
- $de->showDiff( wfMsg( "storedversion" ), wfMsg( "yourtext" ) );
-
- $wgOut->wrapWikiMsg( '$1
', "yourtext" );
- $this->showTextbox2();
-
- $wgOut->addReturnTo( $this->getContextTitle(), array( 'action' => 'edit' ) );
- }
+ $this->mParserOutput = $parserOutput;
+ $wgOut->addParserOutputNoText( $parserOutput );
- /**
- * @private
- * @todo document
- *
- * @parma $editText string
- *
- * @return bool
- */
- function mergeChangesInto( &$editText ){
- wfProfileIn( __METHOD__ );
-
- $db = wfGetDB( DB_MASTER );
-
- // This is the revision the editor started from
- $baseRevision = $this->getBaseRevision();
- if ( is_null( $baseRevision ) ) {
- wfProfileOut( __METHOD__ );
- return false;
- }
- $baseText = $baseRevision->getText();
-
- // The current state, we want to merge updates into it
- $currentRevision = Revision::loadFromTitle( $db, $this->mTitle );
- if ( is_null( $currentRevision ) ) {
- wfProfileOut( __METHOD__ );
- return false;
- }
- $currentText = $currentRevision->getText();
-
- $result = '';
- if ( wfMerge( $baseText, $editText, $currentText, $result ) ) {
- $editText = $result;
- wfProfileOut( __METHOD__ );
- return true;
- } else {
- wfProfileOut( __METHOD__ );
- return false;
+ if ( count( $parserOutput->getWarnings() ) ) {
+ $note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
+ }
}
- }
- /**
- * Check if the browser is on a blacklist of user-agents known to
- * mangle UTF-8 data on form submission. Returns true if Unicode
- * should make it through, false if it's known to be a problem.
- * @return bool
- * @private
- */
- function checkUnicodeCompliantBrowser() {
- global $wgBrowserBlackList;
- if ( empty( $_SERVER["HTTP_USER_AGENT"] ) ) {
- // No User-Agent header sent? Trust it by default...
- return true;
- }
- $currentbrowser = $_SERVER["HTTP_USER_AGENT"];
- foreach ( $wgBrowserBlackList as $browser ) {
- if ( preg_match($browser, $currentbrowser) ) {
- return false;
- }
+ if ( $this->isConflict ) {
+ $conflict = '' . htmlspecialchars( wfMsg( 'previewconflict' ) ) . "
\n";
+ } else {
+ $conflict = '
';
}
- return true;
+
+ $previewhead = "\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;
}
/**
- * Format an anchor fragment as it would appear for a given section name
- * @param $text String
- * @return String
- * @private
+ * @return Array
*/
- function sectionAnchor( $text ) {
- global $wgParser;
- return $wgParser->guessSectionNameFromWikiText( $text );
+ function getTemplates() {
+ if ( $this->preview || $this->section != '' ) {
+ $templates = array();
+ if ( !isset( $this->mParserOutput ) ) {
+ return $templates;
+ }
+ foreach ( $this->mParserOutput->getTemplates() as $ns => $template ) {
+ foreach ( array_keys( $template ) as $dbk ) {
+ $templates[] = Title::makeTitle( $ns, $dbk );
+ }
+ }
+ return $templates;
+ } else {
+ return $this->mTitle->getTemplateLinksFrom();
+ }
}
/**
@@ -2395,7 +2744,7 @@ HTML
'tip' => wfMsg( 'media_tip' ),
'key' => 'M'
) : false,
- $wgUseTeX ? array(
+ $wgUseTeX ? array(
'image' => $wgLang->getImageFile( 'button-math' ),
'id' => 'mw-editbutton-math',
'open' => "