X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FArticle.php;h=792fd7e66522b229c215515db109ec78dee32ee4;hb=4a3cd50cba4aefba6e32c2a3de3de56eb368ad9e;hp=dd563ba0c6aed49fdff6a1616de7cbe6fcce3dc1;hpb=1f3284da900157b85a5fdba1dd3362d489cd8b68;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Article.php b/includes/Article.php index dd563ba0c6..792fd7e665 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -35,6 +35,7 @@ class Article { var $mForUpdate; var $mOldId; var $mRevIdFetched; + var $mRevision; /**#@-*/ /** @@ -51,7 +52,7 @@ class Article { * @public */ function getTitle() { - return $this->mTitle; + return $this->mTitle; } /** @@ -61,7 +62,7 @@ class Article { function clear() { $this->mDataLoaded = false; $this->mContentLoaded = false; - + $this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded $this->mRedirectedFrom = $this->mUserText = $this->mTimestamp = $this->mComment = $this->mFileCache = ''; @@ -80,11 +81,12 @@ class Article { * @return Return the text of this revision */ function getContent( $noredir ) { - global $wgRequest, $wgUser; + global $wgRequest, $wgUser, $wgOut; # Get variables from query string :P $action = $wgRequest->getText( 'action', 'view' ); $section = $wgRequest->getText( 'section' ); + $preload = $wgRequest->getText( 'preload' ); $fname = 'Article::getContent'; wfProfileIn( $fname ); @@ -92,10 +94,20 @@ class Article { if ( 0 == $this->getID() ) { if ( 'edit' == $action ) { wfProfileOut( $fname ); - return ''; # was "newarticletext", now moved above the box) + + # If requested, preload some text. + $text=$this->getPreloadedText($preload); + + # We used to put MediaWiki:Newarticletext here if + # $text was empty at this point. + # This is now shown above the edit box instead. + return $text; } wfProfileOut( $fname ); - return wfMsg( 'noarticletext' ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); + + $ret = wfMsg( $wgUser->isLoggedIn() ? 'noarticletext' : 'noarticletextanon' ); + return "
$ret
"; } else { $this->loadContent( $noredir ); # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page @@ -110,7 +122,8 @@ class Article { if($section!='') { if($section=='new') { wfProfileOut( $fname ); - return ''; + $text=$this->getPreloadedText($preload); + return $text; } # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML @@ -126,6 +139,27 @@ class Article { } } + /** + This function accepts a title string as parameter + ($preload). If this string is non-empty, it attempts + to fetch the current revision text. It respects + . + */ + function getPreloadedText($preload) { + if($preload) { + $preloadTitle=Title::newFromText($preload); + if(isset($preloadTitle) && $preloadTitle->userCanRead()) { + $rev=Revision::newFromTitle($preloadTitle); + if($rev) { + $text=$rev->getText(); + $text=preg_replace('/<\/?includeonly>/i','',$text); + return $text; + } + } + } + return ''; + } + /** * This function returns the text of a section, specified by a number ($section). * A section is text under a heading like == Heading == or

Heading

, or @@ -144,6 +178,7 @@ class Article { $striparray=array(); $parser=new Parser(); $parser->mOutputType=OT_WIKI; + $parser->mOptions = new ParserOptions(); $striptext=$parser->strip($text, $striparray, true); # now that we can be sure that no pseudo-sections are in the source, @@ -195,16 +230,6 @@ class Article { } - /** - * Return an array of the columns of the "cur"-table - */ - function getContentFields() { - return $wgArticleContentFields = array( - 'old_text','old_flags', - 'rev_timestamp','rev_user', 'rev_user_text', 'rev_comment','page_counter', - 'page_namespace', 'page_title', 'page_restrictions','page_touched','page_is_redirect' ); - } - /** * Return the oldid of the article that is to be shown. * For requests with a "direction", this is not the oldid of the @@ -213,14 +238,14 @@ class Article { function getOldID() { global $wgRequest, $wgOut; static $lastid; - + if ( isset( $lastid ) ) { return $lastid; } # Query variables :P $oldid = $wgRequest->getVal( 'oldid' ); if ( isset( $oldid ) ) { - $oldid = IntVal( $oldid ); + $oldid = intval( $oldid ); if ( $wgRequest->getVal( 'direction' ) == 'next' ) { $nextid = $this->mTitle->getNextRevisionID( $oldid ); if ( $nextid ) { @@ -249,7 +274,7 @@ class Article { global $wgOut, $wgRequest; if ( $this->mContentLoaded ) return; - + # Query variables :P $oldid = $this->getOldID(); $redirect = $wgRequest->getVal( 'redirect' ); @@ -266,8 +291,8 @@ class Article { $this->mOldId = $oldid; $this->fetchContent( $oldid, $noredir, true ); } - - + + /** * Fetch a page record with the given conditions * @param Database $dbr @@ -275,8 +300,7 @@ class Article { * @access private */ function pageData( &$dbr, $conditions ) { - return $dbr->selectRow( 'page', - array( + $fields = array( 'page_id', 'page_namespace', 'page_title', @@ -287,22 +311,27 @@ class Article { 'page_random', 'page_touched', 'page_latest', - 'page_len' ), + 'page_len' ) ; + wfRunHooks( 'ArticlePageDataBefore', array( &$this , &$fields ) ) ; + $row = $dbr->selectRow( 'page', + $fields, $conditions, 'Article::pageData' ); + wfRunHooks( 'ArticlePageDataAfter', array( &$this , &$row ) ) ; + return $row ; } - + function pageDataFromTitle( &$dbr, $title ) { return $this->pageData( $dbr, array( 'page_namespace' => $title->getNamespace(), 'page_title' => $title->getDBkey() ) ); } - + function pageDataFromId( &$dbr, $id ) { return $this->pageData( $dbr, array( - 'page_id' => IntVal( $id ) ) ); + 'page_id' => intval( $id ) ) ); } - + /** * Set the general counter, title etc data loaded from * some source. @@ -311,25 +340,25 @@ class Article { * @access private */ function loadPageData( $data ) { - $this->mTitle->mRestrictions = explode( ',', trim( $data->page_restrictions ) ); + $this->mTitle->loadRestrictions( $data->page_restrictions ); $this->mTitle->mRestrictionsLoaded = true; - + $this->mCounter = $data->page_counter; $this->mTouched = wfTimestamp( TS_MW, $data->page_touched ); $this->mIsRedirect = $data->page_is_redirect; $this->mLatest = $data->page_latest; - + $this->mDataLoaded = true; } - + /** * Get text of an article from database * @param int $oldid 0 for whatever the latest revision is - * @param bool $noredir Set to true to avoid following redirects + * @param bool $noredir Set to false to follow redirects * @param bool $globalTitle Set to true to change the global $wgTitle object when following redirects or other unexpected title changes * @return string */ - function fetchContent( $oldid = 0, $noredir = false, $globalTitle = false ) { + function fetchContent( $oldid = 0, $noredir = true, $globalTitle = false ) { if ( $this->mContentLoaded ) { return $this->mContent; } @@ -399,15 +428,17 @@ class Article { return false; } } - $redirData = $this->pageDataFromTitle( $dbr, $rt ); - if( $redirData ) { - $redirRev = Revision::newFromId( $redirData->page_latest ); - if( !is_null( $redirRev ) ) { - $this->mRedirectedFrom = $this->mTitle->getPrefixedText(); - $this->mTitle = $rt; - $data = $redirData; - $this->loadPageData( $data ); - $revision = $redirRev; + if( $rt->getInterwiki() == '' ) { + $redirData = $this->pageDataFromTitle( $dbr, $rt ); + if( $redirData ) { + $redirRev = Revision::newFromId( $redirData->page_latest ); + if( !is_null( $redirRev ) ) { + $this->mRedirectedFrom = $this->mTitle->getPrefixedText(); + $this->mTitle = $rt; + $data = $redirData; + $this->loadPageData( $data ); + $revision = $redirRev; + } } } } @@ -420,18 +451,19 @@ class Article { $wgTitle = $this->mTitle; } } - + # Back to the business at hand... $this->mContent = $revision->getText(); - + $this->mUser = $revision->getUser(); $this->mUserText = $revision->getUserText(); $this->mComment = $revision->getComment(); $this->mTimestamp = wfTimestamp( TS_MW, $revision->getTimestamp() ); - + $this->mRevIdFetched = $revision->getID(); $this->mContentLoaded = true; - + $this->mRevision =& $revision; + return $this->mContent; } @@ -456,11 +488,14 @@ class Article { * Get the database which should be used for reads */ function &getDB() { + $ret =& wfGetDB( DB_MASTER ); + return $ret; #if ( $this->mForUpdate ) { - return wfGetDB( DB_MASTER ); + $ret =& wfGetDB( DB_MASTER ); #} else { - # return wfGetDB( DB_SLAVE ); + # $ret =& wfGetDB( DB_SLAVE ); #} + return $ret; } /** @@ -489,6 +524,14 @@ class Article { } } + /** + * Returns true if this article exists in the database. + * @return bool + */ + function exists() { + return $this->getId() != 0; + } + /** * Get the view count for this article */ @@ -518,19 +561,30 @@ class Article { return 1; } - /** + /** * Tests if the article text represents a redirect */ function isRedirect( $text = false ) { if ( $text === false ) { $this->loadContent(); - $titleObj = Title::newFromRedirect( $this->fetchRevisionText() ); + $titleObj = Title::newFromRedirect( $this->fetchContent() ); } else { $titleObj = Title::newFromRedirect( $text ); } return $titleObj !== NULL; } + /** + * Returns true if the currently-referenced revision is the current edit + * to this page (and it exists). + * @return bool + */ + function isCurrent() { + return $this->exists() && + isset( $this->mRevision ) && + $this->mRevision->isCurrent(); + } + /** * Loads everything except the text * This isn't necessary for all uses, so it's only done if needed. @@ -538,7 +592,7 @@ class Article { */ function loadLastEdit() { global $wgOut; - + if ( -1 != $this->mUser ) return; @@ -558,7 +612,7 @@ class Article { function getTimestamp() { $this->loadLastEdit(); - return $this->mTimestamp; + return wfTimestamp(TS_MW, $this->mTimestamp); } function getUser() { @@ -580,7 +634,7 @@ class Article { $this->loadLastEdit(); return $this->mMinorEdit; } - + function getRevIdFetched() { $this->loadLastEdit(); return $this->mRevIdFetched; @@ -626,9 +680,9 @@ class Article { * the given title. */ function view() { - global $wgUser, $wgOut, $wgRequest, $wgOnlySysopsCanPatrol, $wgLang; - global $wgLinkCache, $IP, $wgEnableParserCache, $wgStylePath, $wgUseRCPatrol; - global $wgEnotif, $wgParser; + global $wgUser, $wgOut, $wgRequest, $wgOnlySysopsCanPatrol, $wgContLang; + global $wgEnableParserCache, $wgStylePath, $wgUseRCPatrol, $wgParser; + global $wgParserCache, $wgUseTrackbacks; $sk = $wgUser->getSkin(); $fname = 'Article::view'; @@ -647,8 +701,8 @@ class Article { if ( !is_null( $diff ) ) { require_once( 'DifferenceEngine.php' ); $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); - - $de = new DifferenceEngine( $oldid, $diff, $rcid ); + + $de = new DifferenceEngine( $this->mTitle, $oldid, $diff, $rcid ); // DifferenceEngine directly fetched the revision: $this->mRevIdFetched = $de->mNewid; $de->showDiffPage(); @@ -660,7 +714,10 @@ class Article { wfProfileOut( $fname ); return; } + if ( empty( $oldid ) && $this->checkTouched() ) { + $wgOut->setETag($wgParserCache->getETag($this, $wgUser)); + if( $wgOut->checkLastModified( $this->mTouched ) ){ wfProfileOut( $fname ); return; @@ -673,11 +730,11 @@ class Article { } } # Should the parser cache be used? - if ( $wgEnableParserCache && intval($wgUser->getOption( 'stubthreshold' )) == 0 && empty( $oldid ) && $this->getID() ) { - $pcache = true; - } else { - $pcache = false; - } + $pcache = $wgEnableParserCache && + intval( $wgUser->getOption( 'stubthreshold' ) ) == 0 && + $this->exists() && + empty( $oldid ); + wfDebug( 'Article::view using parser cache: ' . ($pcache ? 'yes' : 'no' ) . "\n" ); $outputDone = false; if ( $pcache ) { @@ -695,22 +752,28 @@ class Article { exit; } - # We're looking at an old revision if ( !empty( $oldid ) ) { $this->setOldSubtitle( isset($this->mOldId) ? $this->mOldId : $oldid ); $wgOut->setRobotpolicy( 'noindex,follow' ); } + $wasRedirected = false; if ( '' != $this->mRedirectedFrom ) { - $sk = $wgUser->getSkin(); - $redir = $sk->makeKnownLink( $this->mRedirectedFrom, '', - 'redirect=no' ); - $s = wfMsg( 'redirectedfrom', $redir ); - $wgOut->setSubtitle( $s ); - - # Can't cache redirects - $pcache = false; + if ( wfRunHooks( 'ArticleViewRedirect', array( &$this ) ) ) { + $sk = $wgUser->getSkin(); + $redir = $sk->makeKnownLink( $this->mRedirectedFrom, '', 'redirect=no' ); + $s = wfMsg( 'redirectedfrom', $redir ); + $wgOut->setSubtitle( $s ); + + // Check the parser cache again, for the target page + if( $pcache ) { + if( $wgOut->tryParserCache( $this, $wgUser ) ) { + $outputDone = true; + } + } + $wasRedirected = true; + } } elseif ( !empty( $rdfrom ) ) { global $wgRedirectSources; if( $wgRedirectSources && preg_match( $wgRedirectSources, $rdfrom ) ) { @@ -718,9 +781,12 @@ class Article { $redir = $sk->makeExternalLink( $rdfrom, $rdfrom ); $s = wfMsg( 'redirectedfrom', $redir ); $wgOut->setSubtitle( $s ); + $wasRedirected = true; } } - + } + if( !$outputDone ) { + wfRunHooks( 'ArticleViewHeader', array( &$this ) ) ; # wrap user css and user js in pre and don't parse # XXX: use $this->mTitle->usCssJsSubpage() when php is fixed/ a workaround is found if ( @@ -731,28 +797,43 @@ class Article { $wgOut->addHTML( '
'.htmlspecialchars($this->mContent)."\n
" ); } else if ( $rt = Title::newFromRedirect( $text ) ) { # Display redirect - $imageUrl = $wgStylePath.'/common/images/redirect.png'; + $imageDir = $wgContLang->isRTL() ? 'rtl' : 'ltr'; + $imageUrl = $wgStylePath.'/common/images/redirect' . $imageDir . '.png'; + if( !$wasRedirected ) { + $wgOut->setSubtitle( wfMsgHtml( 'redirectpagesub' ) ); + } $targetUrl = $rt->escapeLocalURL(); $titleText = htmlspecialchars( $rt->getPrefixedText() ); $link = $sk->makeLinkObj( $rt ); - $wgOut->addHTML( '#REDIRECT' . + $wgOut->addHTML( '#REDIRECT' . ''.$link.'' ); - + $parseout = $wgParser->parse($text, $this->mTitle, ParserOptions::newFromUser($wgUser)); $catlinks = $parseout->getCategoryLinks(); $wgOut->addCategoryLinks($catlinks); $skin = $wgUser->getSkin(); } else if ( $pcache ) { # Display content and save to parser cache + $wgOut->setRevisionId( $this->getRevIdFetched() ); $wgOut->addPrimaryWikiText( $text, $this ); } else { # Display content, don't attempt to save to parser cache + + # Don't show section-edit links on old revisions... this way lies madness. + if( !$this->isCurrent() ) { + $oldEditSectionSetting = $wgOut->mParserOptions->setEditSection( false ); + } + $wgOut->setRevisionId( $this->getRevIdFetched() ); $wgOut->addWikiText( $text ); + + if( !$this->isCurrent() ) { + $wgOut->mParserOptions->setEditSection( $oldEditSectionSetting ); + } } } /* title may have been set from the cache */ - $t = $wgOut->getPageTitle(); + $t = $wgOut->getPageTitle(); if( empty( $t ) ) { $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); } @@ -774,8 +855,9 @@ class Article { ); } - # Put link titles into the link cache - $wgOut->transformBuffer(); + # Trackbacks + if ($wgUseTrackbacks) + $this->addTrackbacks(); # Add link titles as META keywords $wgOut->addMetaTags() ; @@ -784,6 +866,100 @@ class Article { wfProfileOut( $fname ); } + function addTrackbacks() { + global $wgOut, $wgUser; + + $dbr =& wfGetDB(DB_SLAVE); + $tbs = $dbr->select( + /* FROM */ 'trackbacks', + /* SELECT */ array('tb_id', 'tb_title', 'tb_url', 'tb_ex', 'tb_name'), + /* WHERE */ array('tb_page' => $this->getID()) + ); + + if (!$dbr->numrows($tbs)) + return; + + $tbtext = ""; + while ($o = $dbr->fetchObject($tbs)) { + $rmvtxt = ""; + if ($wgUser->isSysop()) { + $delurl = $this->mTitle->getFullURL("action=deletetrackback&tbid=" + . $o->tb_id . "&token=" . $wgUser->editToken()); + $rmvtxt = wfMsg('trackbackremove', $delurl); + } + $tbtext .= wfMsg(strlen($o->tb_ex) ? 'trackbackexcerpt' : 'trackback', + $o->tb_title, + $o->tb_url, + $o->tb_ex, + $o->tb_name, + $rmvtxt); + } + $wgOut->addWikitext(wfMsg('trackbackbox', $tbtext)); + } + + function deletetrackback() { + global $wgUser, $wgRequest, $wgOut, $wgTitle; + + if (!$wgUser->matchEditToken($wgRequest->getVal('token'))) { + $wgOut->addWikitext(wfMsg('sessionfailure')); + return; + } + + if ((!$wgUser->isAllowed('delete'))) { + $wgOut->sysopRequired(); + return; + } + + if (wfReadOnly()) { + $wgOut->readOnlyPage(); + return; + } + + $db =& wfGetDB(DB_MASTER); + $db->delete('trackbacks', array('tb_id' => $wgRequest->getInt('tbid'))); + $wgTitle->invalidateCache(); + $wgOut->addWikiText(wfMsg('trackbackdeleteok')); + } + + function render() { + global $wgOut; + + $wgOut->setArticleBodyOnly(true); + $this->view(); + } + + function purge() { + global $wgUser, $wgRequest, $wgOut, $wgUseSquid; + + if ( $wgUser->isLoggedIn() || $wgRequest->wasPosted() ) { + // Invalidate the cache + $this->mTitle->invalidateCache(); + + if ( $wgUseSquid ) { + // Commit the transaction before the purge is sent + $dbw = wfGetDB( DB_MASTER ); + $dbw->immediateCommit(); + + // Send purge + $update = SquidUpdate::newSimplePurge( $this->mTitle ); + $update->doUpdate(); + } + $this->view(); + } else { + $msg = $wgOut->parse( wfMsg( 'confirm_purge' ) ); + $action = $this->mTitle->escapeLocalURL( 'action=purge' ); + $button = htmlspecialchars( wfMsg( 'confirm_purge_button' ) ); + $msg = str_replace( '$1', + "
\n" . + "\n" . + "
\n", $msg ); + + $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); + $wgOut->addHTML( $msg ); + } + } + /** * Insert a new empty page record for this article. * This *must* be followed up by creating a revision @@ -799,7 +975,7 @@ class Article { function insertOn( &$dbw, $restrictions = '' ) { $fname = 'Article::insertOn'; wfProfileIn( $fname ); - + $page_id = $dbw->nextSequenceValue( 'page_page_id_seq' ); $dbw->insert( 'page', array( 'page_id' => $page_id, @@ -812,15 +988,16 @@ class Article { 'page_random' => wfRandom(), 'page_touched' => $dbw->timestamp(), 'page_latest' => 0, # Fill this in shortly... + 'page_len' => 0, # Fill this in shortly... ), $fname ); $newid = $dbw->insertId(); - + $this->mTitle->resetArticleId( $newid ); - + wfProfileOut( $fname ); return $newid; } - + /** * Update the page record to point to a newly saved revision. * @@ -837,28 +1014,29 @@ class Article { function updateRevisionOn( &$dbw, $revision, $lastRevision = null ) { $fname = 'Article::updateToRevision'; wfProfileIn( $fname ); - + $conditions = array( 'page_id' => $this->getId() ); if( !is_null( $lastRevision ) ) { # An extra check against threads stepping on each other $conditions['page_latest'] = $lastRevision; } + $text = $revision->getText(); $dbw->update( 'page', array( /* SET */ 'page_latest' => $revision->getId(), 'page_touched' => $dbw->timestamp(), 'page_is_new' => ($lastRevision === 0) ? 1 : 0, - 'page_is_redirect' => Article::isRedirect( $text ), + 'page_is_redirect' => Article::isRedirect( $text ) ? 1 : 0, 'page_len' => strlen( $text ), ), $conditions, $fname ); - + wfProfileOut( $fname ); return ( $dbw->affectedRows() != 0 ); } - + /** * If the given revision is newer than the currently set page_latest, * update the page record. Otherwise, do nothing. @@ -869,7 +1047,7 @@ class Article { function updateIfNewerOn( &$dbw, $revision ) { $fname = 'Article::updateIfNewerOn'; wfProfileIn( $fname ); - + $row = $dbw->selectRow( array( 'revision', 'page' ), array( 'rev_id', 'rev_timestamp' ), @@ -878,7 +1056,7 @@ class Article { 'page_latest=rev_id' ), $fname ); if( $row ) { - if( $row->rev_timestamp >= $revision->getTimestamp() ) { + if( wfTimestamp(TS_MW, $row->rev_timestamp) >= $revision->getTimestamp() ) { wfProfileOut( $fname ); return false; } @@ -887,12 +1065,12 @@ class Article { # No or missing previous revision; mark the page as new $prev = 0; } - + $ret = $this->updateRevisionOn( $dbw, $revision, $prev ); wfProfileOut( $fname ); return $ret; } - + /** * Theoretically we could defer these whole insert and update * functions for after display, but that's taking a big leap @@ -900,17 +1078,29 @@ class Article { * errors at some point. * @private */ - function insertNewArticle( $text, $summary, $isminor, $watchthis, $suppressRC=false ) { - global $wgOut, $wgUser; - global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer; + function insertNewArticle( $text, $summary, $isminor, $watchthis, $suppressRC=false, $comment=false ) { + global $wgOut, $wgUser, $wgUseSquid; $fname = 'Article::insertNewArticle'; + wfProfileIn( $fname ); + if( !wfRunHooks( 'ArticleSave', array( &$this, &$wgUser, &$text, + &$summary, &$isminor, &$watchthis, NULL ) ) ) { + wfDebug( "$fname: ArticleSave hook aborted save!\n" ); + wfProfileOut( $fname ); + return false; + } + $this->mGoodAdjustment = $this->isCountable( $text ); $this->mTotalAdjustment = 1; $ns = $this->mTitle->getNamespace(); $ttl = $this->mTitle->getDBkey(); + + # If this is a comment, add the summary as headline + if($comment && $summary!="") { + $text="== {$summary} ==\n\n".$text; + } $text = $this->preSaveTransform( $text ); $isminor = ( $isminor && $wgUser->isLoggedIn() ) ? 1 : 0; $now = wfTimestampNow(); @@ -919,7 +1109,7 @@ class Article { # Add the page record; stake our claim on this title! $newid = $this->insertOn( $dbw ); - + # Save the revision text... $revision = new Revision( array( 'page' => $newid, @@ -930,13 +1120,14 @@ class Article { $revisionId = $revision->insertOn( $dbw ); $this->mTitle->resetArticleID( $newid ); - + # Update the page record with revision data $this->updateRevisionOn( $dbw, $revision, 0 ); Article::onArticleCreate( $this->mTitle ); if(!$suppressRC) { - RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary ); + RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary, 'default', + '', strlen( $text ), $revisionId ); } if ($watchthis) { @@ -959,43 +1150,25 @@ class Article { $this->editUpdates( $text, $summary, $isminor, $now ); $oldid = 0; # new article - $this->showArticle( $text, wfMsg( 'newarticle' ), false, $isminor, $now, $summary, $oldid ); + $this->showArticle( $text, wfMsg( 'newarticle' ), false, $isminor, $now, $summary, $oldid, $revisionId ); + + wfRunHooks( 'ArticleSaveComplete', array( &$this, &$wgUser, $text, + $summary, $isminor, + $watchthis, NULL ) ); + wfProfileOut( $fname ); + } + + function getTextOfLastEditWithSectionReplacedOrAdded($section, $text, $summary = '', $edittime = NULL) { + $this->replaceSection( $section, $text, $summary, $edittime ); } /** - * Fetch and uncompress the text for a given revision. - * Can ask by rev_id number or timestamp (set $field) - * FIXME: This function is broken. Eliminate all uses and remove. - * Use Revision class in place. + * @return string Complete article text, or null if error */ - function fetchRevisionText( $revId = null, $field = 'rev_id' ) { - $fname = 'Article::fetchRevisionText'; - $dbw =& wfGetDB( DB_MASTER ); - if( $revId ) { - $rev = $dbw->addQuotes( $revId ); - } else { - $rev = 'page_latest'; - } - $result = $dbw->query( - sprintf( "SELECT old_text, old_flags - FROM %s,%s,%s - WHERE old_id=rev_id AND rev_page=page_id AND page_id=%d - AND %s=%s", - $dbw->tableName( 'page' ), - $dbw->tableName( 'revision' ), - $dbw->tableName( 'text' ), - IntVal( $this->mTitle->getArticleId() ), - $field, - $rev ), - $fname ); - $obj = $dbw->fetchObject( $result ); - $dbw->freeResult( $result ); - $oldtext = Revision::getRevisionText( $obj ); - return $oldtext; - } - - function getTextOfLastEditWithSectionReplacedOrAdded($section, $text, $summary = '', $edittime = NULL) { - $fname = 'Article::getTextOfLastEditWithSectionReplacedOrAdded'; + function replaceSection($section, $text, $summary = '', $edittime = NULL) { + $fname = 'Article::replaceSection'; + wfProfileIn( $fname ); + if ($section != '') { if( is_null( $edittime ) ) { $rev = Revision::newFromTitle( $this->mTitle ); @@ -1003,8 +1176,13 @@ class Article { $dbw =& wfGetDB( DB_MASTER ); $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime ); } + if( is_null( $rev ) ) { + wfDebug( "Article::replaceSection asked for bogus section (page: " . + $this->getId() . "; section: $section; edittime: $edittime)\n" ); + return null; + } $oldtext = $rev->getText(); - + if($section=='new') { if($summary) $subject="== {$summary} ==\n\n"; $text=$oldtext."\n\n".$subject.$text; @@ -1015,6 +1193,7 @@ class Article { $striparray=array(); $parser=new Parser(); $parser->mOutputType=OT_WIKI; + $parser->mOptions = new ParserOptions(); $oldtext=$parser->strip($oldtext, $striparray, true); # now that we can be sure that no pseudo-sections are in the source, @@ -1073,28 +1252,37 @@ class Article { } } + wfProfileOut( $fname ); return $text; } /** - * Change an existing article. Puts the previous version back into the old table, updates RC + * Change an existing article. Puts the previous version back into the old table, updates RC * and all necessary caches, mostly via the deferred update array. * - * It is possible to call this function from a command-line script, but note that you should + * It is possible to call this function from a command-line script, but note that you should * first set $wgUser, and clean up $wgDeferredUpdates after each edit. */ function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = '' ) { - global $wgOut, $wgUser; - global $wgDBtransactions, $wgMwRedir; - global $wgUseSquid, $wgInternalServer, $wgPostCommitUpdateList; + global $wgOut, $wgUser, $wgDBtransactions, $wgMwRedir, $wgUseSquid; + global $wgPostCommitUpdateList, $wgUseFileCache; $fname = 'Article::updateArticle'; + wfProfileIn( $fname ); $good = true; + if( !wfRunHooks( 'ArticleSave', array( &$this, &$wgUser, &$text, + &$summary, &$minor, + &$watchthis, &$sectionanchor ) ) ) { + wfDebug( "$fname: ArticleSave hook aborted save!\n" ); + wfProfileOut( $fname ); + return false; + } + $isminor = ( $minor && $wgUser->isLoggedIn() ); if ( $this->isRedirect( $text ) ) { # Remove all content but redirect - # This could be done by reconstructing the redirect from a title given by + # This could be done by reconstructing the redirect from a title given by # Title::newFromRedirect(), but then we wouldn't know which synonym the user # wants to see if ( preg_match( "/^((" . $wgMwRedir->getBaseRegex() . ')[^\\n]+)/i', $text, $m ) ) { @@ -1118,7 +1306,10 @@ class Article { } $oldtext = $this->getContent( true ); + $oldsize = strlen( $oldtext ); + $newsize = strlen( $text ); $lastRevision = 0; + $revisionId = 0; if ( 0 != strcmp( $text, $oldtext ) ) { $this->mGoodAdjustment = $this->isCountable( $text ) @@ -1128,26 +1319,34 @@ class Article { $lastRevision = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $this->getId() ) ); - + $revision = new Revision( array( 'page' => $this->getId(), 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text ) ); - $revisionId = $revision->insertOn( $dbw ); + $dbw->immediateCommit(); + $dbw->begin(); + $revisionId = $revision->insertOn( $dbw ); + # Update page $ok = $this->updateRevisionOn( $dbw, $revision, $lastRevision ); if( !$ok ) { /* Belated edit conflict! Run away!! */ $good = false; + $dbw->rollback(); } else { # Update recentchanges and purge cache and whatnot $bot = (int)($wgUser->isBot() || $forceBot); RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $wgUser, $summary, - $lastRevision, $this->getTimestamp(), $bot ); + $lastRevision, $this->getTimestamp(), $bot, '', $oldsize, $newsize, + $revisionId ); + $dbw->commit(); + + // Update caches outside the main transaction Article::onArticleEdit( $this->mTitle ); } } @@ -1158,38 +1357,31 @@ class Article { if ( $good ) { if ($watchthis) { - if (!$this->mTitle->userIsWatching()) $this->watch(); + if (!$this->mTitle->userIsWatching()) { + $dbw->immediateCommit(); + $dbw->begin(); + $this->watch(); + $dbw->commit(); + } } else { if ( $this->mTitle->userIsWatching() ) { + $dbw->immediateCommit(); + $dbw->begin(); $this->unwatch(); + $dbw->commit(); } } # standard deferred updates $this->editUpdates( $text, $summary, $minor, $now ); - - - $urls = array(); - # Template namespace - # Purge all articles linking here - if ( $this->mTitle->getNamespace() == NS_TEMPLATE) { - $titles = $this->mTitle->getLinksTo(); - Title::touchArray( $titles ); - if ( $wgUseSquid ) { - foreach ( $titles as $title ) { - $urls[] = $title->getInternalURL(); - } - } - } - - # Squid updates - if ( $wgUseSquid ) { - $urls = array_merge( $urls, $this->mTitle->getSquidURLs() ); - $u = new SquidUpdate( $urls ); - array_push( $wgPostCommitUpdateList, $u ); - } - - $this->showArticle( $text, wfMsg( 'updated' ), $sectionanchor, $isminor, $now, $summary, $lastRevision ); + + + $this->showArticle( $text, wfMsg( 'updated' ), $sectionanchor, $isminor, $now, $summary, $lastRevision, $revisionId ); } + wfRunHooks( 'ArticleSaveComplete', + array( &$this, &$wgUser, $text, + $summary, $minor, + $watchthis, $sectionanchor ) ); + wfProfileOut( $fname ); return $good; } @@ -1197,12 +1389,15 @@ class Article { * After we've either updated or inserted the article, update * the link tables and redirect to the new page. */ - function showArticle( $text, $subtitle , $sectionanchor = '', $me2, $now, $summary, $oldid ) { - global $wgUseDumbLinkUpdate, $wgAntiLockFlags, $wgOut, $wgUser, $wgLinkCache, $wgEnotif; + function showArticle( $text, $subtitle , $sectionanchor = '', $me2, $now, $summary, $oldid, $newid ) { + global $wgUseDumbLinkUpdate, $wgAntiLockFlags, $wgOut, $wgUser, $wgLinkCache; global $wgUseEnotif; + $fname = 'Article::showArticle'; + wfProfileIn( $fname ); + $wgLinkCache = new LinkCache(); - + if ( !$wgUseDumbLinkUpdate ) { # Preload links to reduce lock time if ( $wgAntiLockFlags & ALF_PRELOAD_LINKS ) { @@ -1210,28 +1405,12 @@ class Article { $wgLinkCache->clear(); } } - # Parse the text and replace links with placeholders - # Do this outside the locks on the links table - # The existence test queries need to be FOR UPDATE - #$oldUpdate = $wgParser->forUpdate( true ); - $wgOut = new OutputPage(); - $wgOut->addWikiTextWithTitle( $text, $this->mTitle ); - # Select for update - $wgLinkCache->forUpdate( true ); - - # Get old version of link table to allow incremental link updates - $wgLinkCache->preFill( $this->mTitle ); - $wgLinkCache->clear(); - - # Parse the text and replace links with placeholders + # Parse the text and save it to the parser cache $wgOut = new OutputPage(); - - # Pass the current title along in case we're creating a wiki page - # which is different than the currently displayed one (e.g. image - # pages created on file uploads); otherwise, link updates will - # go wrong. - $wgOut->addWikiTextWithTitle( $text, $this->mTitle ); + $wgOut->setParserOptions( ParserOptions::newFromUser( $wgUser ) ); + $wgOut->setRevisionId( $newid ); + $wgOut->addPrimaryWikiText( $text, $this ); if ( !$wgUseDumbLinkUpdate ) { # Move the current links back to the second register @@ -1245,19 +1424,14 @@ class Article { # Swap this old version back into its rightful place $wgLinkCache->swapRegisters(); } - + if( $this->isRedirect( $text ) ) $r = 'redirect=no'; else $r = ''; $wgOut->redirect( $this->mTitle->getFullURL( $r ).$sectionanchor ); - - if ( $wgUseEnotif ) { - # this would be better as an extension hook - include_once( "UserMailer.php" ); - $wgEnotif = new EmailNotification (); - $wgEnotif->notifyOnPageChange( $this->mTitle, $now, $summary, $me2, $oldid ); - } + + wfProfileOut( $fname ); } /** @@ -1303,18 +1477,18 @@ class Article { */ function validate() { global $wgOut, $wgUser, $wgRequest, $wgUseValidation; - + if ( !$wgUseValidation ) # Are we using article validation at all? { $wgOut->errorpage( "nosuchspecialpage", "nospecialpagetext" ); return ; } - + $wgOut->setRobotpolicy( 'noindex,follow' ); $revision = $wgRequest->getVal( 'revision' ); - + include_once ( "SpecialValidate.php" ) ; # The "Validation" class - + $v = new Validation ; if ( $wgRequest->getVal ( "mode" , "" ) == "list" ) $t = $v->showList ( $this ) ; @@ -1322,16 +1496,16 @@ class Article { $t = $v->showDetails ( $this , $wgRequest->getVal( 'revision' ) ) ; else $t = $v->validatePageForm ( $this , $revision ) ; - + $wgOut->addHTML ( $t ) ; } /** * Add this page to $wgUser's watchlist */ - + function watch() { - + global $wgUser, $wgOut; if ( $wgUser->isAnon() ) { @@ -1344,7 +1518,7 @@ class Article { } if (wfRunHooks('WatchArticle', array(&$wgUser, &$this))) { - + $wgUser->addWatch( $this->mTitle ); $wgUser->saveSettings(); @@ -1352,19 +1526,19 @@ class Article { $wgOut->setPagetitle( wfMsg( 'addedwatch' ) ); $wgOut->setRobotpolicy( 'noindex,follow' ); - + $link = $this->mTitle->getPrefixedText(); $text = wfMsg( 'addedwatchtext', $link ); $wgOut->addWikiText( $text ); } - + $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); } /** * Stop watching a page */ - + function unwatch() { global $wgUser, $wgOut; @@ -1379,20 +1553,20 @@ class Article { } if (wfRunHooks('UnwatchArticle', array(&$wgUser, &$this))) { - + $wgUser->removeWatch( $this->mTitle ); $wgUser->saveSettings(); - + wfRunHooks('UnwatchArticleComplete', array(&$wgUser, &$this)); - + $wgOut->setPagetitle( wfMsg( 'removedwatch' ) ); $wgOut->setRobotpolicy( 'noindex,follow' ); - + $link = $this->mTitle->getPrefixedText(); $text = wfMsg( 'removedwatchtext', $link ); $wgOut->addWikiText( $text ); } - + $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); } @@ -1437,7 +1611,7 @@ class Article { $restrictions .= ":edit=" . $limit; } if (wfRunHooks('ArticleProtect', array(&$this, &$wgUser, $limit == 'sysop', $reason, $moveonly))) { - + $dbw =& wfGetDB( DB_MASTER ); $dbw->update( 'page', array( /* SET */ @@ -1447,9 +1621,9 @@ class Article { 'page_id' => $id ), 'Article::protect' ); - + wfRunHooks('ArticleProtectComplete', array(&$this, &$wgUser, $limit == 'sysop', $reason, $moveonly)); - + $log = new LogPage( 'protect' ); if ( $limit === '' ) { $log->addEntry( 'unprotect', $this->mTitle, $reason ); @@ -1460,8 +1634,7 @@ class Article { } return; } else { - $reason = htmlspecialchars( wfMsg( 'protectreason' ) ); - return $this->confirmProtect( '', $reason, $limit ); + return $this->confirmProtect( '', '', $limit ); } } @@ -1473,7 +1646,7 @@ class Article { wfDebug( "Article::confirmProtect\n" ); - $sub = $this->mTitle->getPrefixedText(); + $sub = htmlspecialchars( $this->mTitle->getPrefixedText() ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $check = ''; @@ -1495,7 +1668,7 @@ class Article { $formaction = $this->mTitle->escapeLocalURL( 'action=protect' . $par ); } - $confirm = htmlspecialchars( wfMsg( 'confirm' ) ); + $confirm = htmlspecialchars( wfMsg( 'protectpage' ) ); $token = htmlspecialchars( $wgUser->editToken() ); $wgOut->addHTML( " @@ -1545,7 +1718,7 @@ class Article { * UI entry point for page deletion */ function delete() { - global $wgUser, $wgOut, $wgMessageCache, $wgRequest; + global $wgUser, $wgOut, $wgRequest; $fname = 'Article::delete'; $confirm = $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ); @@ -1597,8 +1770,8 @@ class Article { } # Fetch cur_text - $rev =& Revision::newFromTitle( $this->mTitle ); - + $rev = Revision::newFromTitle( $this->mTitle ); + # Fetch name(s) of contributors $rev_name = ''; $all_same_user = true; @@ -1609,7 +1782,7 @@ class Article { $rev_name = $row->rev_user_text; } } - + if( !is_null( $rev ) ) { # if this is a mini-text, we can paste part of it into the deletion reason $text = $rev->getText(); @@ -1618,7 +1791,7 @@ class Article { $blanked = false; if( $text == '' ) { $prev = $rev->getPrevious(); - if( $prev ) { + if( $prev ) { $text = $prev->getText(); $blanked = true; } @@ -1629,7 +1802,7 @@ class Article { # this should not happen, since it is not possible to store an empty, new # page. Let's insert a standard text in case it does, though if( $length == 0 && $reason === '' ) { - $reason = wfMsg( 'exblank' ); + $reason = wfMsgForContent( 'exblank' ); } if( $length < 500 && $reason === '' ) { @@ -1637,18 +1810,18 @@ class Article { # space left global $wgContLang; $text = $wgContLang->truncate( $text, 150, '...' ); - + # let's strip out newlines $text = preg_replace( "/[\n\r]/", '', $text ); - + if( !$blanked ) { if( !$all_same_user ) { - $reason = wfMsg( 'excontent', $text ); + $reason = wfMsgForContent( 'excontent', $text ); } else { - $reason = wfMsg( 'excontentauthor', $text, $rev_name ); + $reason = wfMsgForContent( 'excontentauthor', $text, $rev_name ); } } else { - $reason = wfMsg( 'exbeforeblank', $text ); + $reason = wfMsgForContent( 'exbeforeblank', $text ); } } } @@ -1671,7 +1844,7 @@ class Article { $formaction = $this->mTitle->escapeLocalURL( 'action=delete' . $par ); - $confirm = htmlspecialchars( wfMsg( 'confirm' ) ); + $confirm = htmlspecialchars( wfMsg( 'deletepage' ) ); $delcom = htmlspecialchars( wfMsg( 'deletecomment' ) ); $token = htmlspecialchars( $wgUser->editToken() ); @@ -1711,13 +1884,13 @@ class Article { if (wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason))) { if ( $this->doDeleteArticle( $reason ) ) { $deleted = $this->mTitle->getPrefixedText(); - + $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); - + $loglink = '[[Special:Log/delete|' . wfMsg( 'deletionlog' ) . ']]'; $text = wfMsg( 'deletedtext', $deleted, $loglink ); - + $wgOut->addWikiText( $text ); $wgOut->returnToMain( false ); wfRunHooks('ArticleDeleteComplete', array(&$this, &$wgUser, $reason)); @@ -1733,8 +1906,8 @@ class Article { * Returns success */ function doDeleteArticle( $reason ) { - global $wgUser; - global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer, $wgPostCommitUpdateList; + global $wgUser, $wgUseSquid, $wgDeferredUpdateList; + global $wgPostCommitUpdateList, $wgUseTrackbacks; $fname = 'Article::doDeleteArticle'; wfDebug( $fname."\n" ); @@ -1795,11 +1968,14 @@ class Article { 'page_id = rev_page' ), $fname ); - + # Now that it's safely backed up, delete it $dbw->delete( 'revision', array( 'rev_page' => $id ), $fname ); $dbw->delete( 'page', array( 'page_id' => $id ), $fname); - + + if ($wgUseTrackbacks) + $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), $fname ); + # Clean up recentchanges entries... $dbw->delete( 'recentchanges', array( 'rc_namespace' => $ns, 'rc_title' => $t ), $fname ); @@ -1866,7 +2042,7 @@ class Article { $from = str_replace( '_', ' ', $wgRequest->getVal( 'from' ) ); if( $from != $current->getUserText() ) { - $wgOut->setPageTitle(wfmsg('rollbackfailed')); + $wgOut->setPageTitle( wfMsg('rollbackfailed') ); $wgOut->addWikiText( wfMsg( 'alreadyrolled', htmlspecialchars( $this->mTitle->getPrefixedText()), htmlspecialchars( $from ), @@ -1880,7 +2056,7 @@ class Article { } # Get the last edit not by this guy - $user = IntVal( $current->getUser() ); + $user = intval( $current->getUser() ); $user_text = $dbw->addQuotes( $current->getUserText() ); $s = $dbw->selectRow( 'revision', array( 'rev_id', 'rev_timestamp' ), @@ -1899,7 +2075,7 @@ class Article { $wgOut->addHTML( wfMsg( 'cantrollback' ) ); return; } - + if ( $bot ) { # Mark all reverted edits as bot $dbw->update( 'recentchanges', @@ -1913,17 +2089,19 @@ class Article { ); } - # Save it! + # Get the edit summary $target = Revision::newFromId( $s->rev_id ); - $newcomment = wfMsg( 'revertpage', $target->getUserText(), $from ); - + $newComment = wfMsgForContent( 'revertpage', $target->getUserText(), $from ); + $newComment = $wgRequest->getText( 'summary', $newComment ); + + # Save it! $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); - $wgOut->addHTML( '

' . htmlspecialchars( $newcomment ) . "

\n
\n" ); - - $this->updateArticle( $target->getText(), $newcomment, 1, $this->mTitle->userIsWatching(), $bot ); + $wgOut->addHTML( '

' . htmlspecialchars( $newComment ) . "

\n
\n" ); + + $this->updateArticle( $target->getText(), $newComment, 1, $this->mTitle->userIsWatching(), $bot ); Article::onArticleEdit( $this->mTitle ); - + $dbw->commit(); $wgOut->returnToMain( false ); } @@ -1934,8 +2112,8 @@ class Article { * @private */ function viewUpdates() { - global $wgDeferredUpdateList, $wgUseEnotif; - + global $wgDeferredUpdateList; + if ( 0 != $this->getID() ) { global $wgDisableCounters; if( !$wgDisableCounters ) { @@ -1944,25 +2122,10 @@ class Article { array_push( $wgDeferredUpdateList, $u ); } } - - # Update newtalk status if user is reading their own - # talk page + # Update newtalk / watchlist notification status global $wgUser; - if ($this->mTitle->getNamespace() == NS_USER_TALK && - $this->mTitle->getText() == $wgUser->getName()) - { - if ( $wgUseEnotif ) { - require_once( 'UserTalkUpdate.php' ); - $u = new UserTalkUpdate( 0, $this->mTitle->getNamespace(), $this->mTitle->getDBkey(), false, false, false ); - } else { - $wgUser->setNewtalk(0); - $wgUser->saveNewtalk(); - } - } elseif ( $wgUseEnotif ) { - $wgUser->clearNotification( $this->mTitle ); - } - + $wgUser->clearNotification( $this->mTitle ); } /** @@ -1972,19 +2135,22 @@ class Article { * @param string $text */ function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange) { - global $wgDeferredUpdateList, $wgDBname, $wgMemc; - global $wgMessageCache, $wgUser, $wgUseEnotif; + global $wgDeferredUpdateList, $wgMessageCache, $wgUser; - wfSeedRandom(); - if ( 0 == mt_rand( 0, 999 ) ) { - # Periodically flush old entries from the recentchanges table. - global $wgRCMaxAge; - $dbw =& wfGetDB( DB_MASTER ); - $cutoff = $dbw->timestamp( time() - $wgRCMaxAge ); - $recentchanges = $dbw->tableName( 'recentchanges' ); - $sql = "DELETE FROM $recentchanges WHERE rc_timestamp < '{$cutoff}'"; - $dbw->query( $sql ); + if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) { + wfSeedRandom(); + if ( 0 == mt_rand( 0, 999 ) ) { + # Periodically flush old entries from the recentchanges table. + global $wgRCMaxAge; + + $dbw =& wfGetDB( DB_MASTER ); + $cutoff = $dbw->timestamp( time() - $wgRCMaxAge ); + $recentchanges = $dbw->tableName( 'recentchanges' ); + $sql = "DELETE FROM $recentchanges WHERE rc_timestamp < '{$cutoff}'"; + $dbw->query( $sql ); + } } + $id = $this->getID(); $title = $this->mTitle->getPrefixedDBkey(); $shortTitle = $this->mTitle->getDBkey(); @@ -1998,16 +2164,16 @@ class Article { array_push( $wgDeferredUpdateList, $u ); # If this is another user's talk page, update newtalk - + if ($this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $wgUser->getName()) { - if ( $wgUseEnotif ) { - require_once( 'UserTalkUpdate.php' ); - $u = new UserTalkUpdate( 1, $this->mTitle->getNamespace(), $shortTitle, $summary, - $minoredit, $timestamp_of_pagechange); - } else { - $other = User::newFromName($shortTitle); - $other->setNewtalk(1); - $other->saveNewtalk(); + $other = User::newFromName( $shortTitle ); + if( is_null( $other ) && User::isIP( $shortTitle ) ) { + // An anonymous user + $other = new User(); + $other->setName( $shortTitle ); + } + if( $other ) { + $other->setNewtalk( true ); } } @@ -2025,11 +2191,16 @@ class Article { function setOldSubtitle( $oldid=0 ) { global $wgLang, $wgOut, $wgUser; + $current = ( $oldid == $this->mLatest ); $td = $wgLang->timeanddate( $this->mTimestamp, true ); $sk = $wgUser->getSkin(); - $lnk = $sk->makeKnownLinkObj ( $this->mTitle, wfMsg( 'currentrevisionlink' ) ); + $lnk = $current + ? wfMsg( 'currentrevisionlink' ) + : $lnk = $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'currentrevisionlink' ) ); $prevlink = $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'previousrevision' ), 'direction=prev&oldid='.$oldid ); - $nextlink = $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'nextrevision' ), 'direction=next&oldid='.$oldid ); + $nextlink = $current + ? wfMsg( 'nextrevision' ) + : $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'nextrevision' ), 'direction=next&oldid='.$oldid ); $r = wfMsg( 'revisionasofwithlink', $td, $lnk, $prevlink, $nextlink ); $wgOut->setSubtitle( $r ); } @@ -2075,7 +2246,7 @@ class Article { wfDebug( " tryFileCache() - not cacheable\n" ); } } - + /** * Check if the page can be cached * @return bool @@ -2138,7 +2309,7 @@ class Article { $revisionId = $revision->insertOn( $dbw ); $this->updateRevisionOn( $dbw, $revision ); $dbw->commit(); - + wfProfileOut( $fname ); } @@ -2201,9 +2372,9 @@ class Article { * The onArticle*() functions are supposed to be a kind of hooks * which should be called whenever any of the specified actions * are done. - * + * * This is a good place to put code to clear caches, for instance. - * + * * This is called on page move and undelete, as well as edit * @static * @param $title_obj a title object @@ -2226,15 +2397,50 @@ class Article { } } - function onArticleDelete($title_obj) { - $title_obj->touchLinks(); + function onArticleDelete( $title ) { + global $wgMessageCache; + + $title->touchLinks(); + + if( $title->getNamespace() == NS_MEDIAWIKI) { + $wgMessageCache->replace( $title->getDBkey(), false ); + } } - - function onArticleEdit($title_obj) { - // This would be an appropriate place to purge caches. - // Why's this not in here now? + + /** + * Purge caches on page update etc + */ + function onArticleEdit( $title ) { + global $wgUseSquid, $wgPostCommitUpdateList, $wgUseFileCache; + + $urls = array(); + + // Template namespace? Purge all articles linking here. + // FIXME: When a templatelinks table arrives, use it for all includes. + if ( $title->getNamespace() == NS_TEMPLATE) { + $titles = $title->getLinksTo(); + Title::touchArray( $titles ); + if ( $wgUseSquid ) { + foreach ( $titles as $link ) { + $urls[] = $link->getInternalURL(); + } + } + } + + # Squid updates + if ( $wgUseSquid ) { + $urls = array_merge( $urls, $title->getSquidURLs() ); + $u = new SquidUpdate( $urls ); + array_push( $wgPostCommitUpdateList, $u ); + } + + # File cache + if ( $wgUseFileCache ) { + $cm = new CacheManager( $title ); + @unlink( $cm->fileCacheName() ); + } } - + /**#@-*/ /** @@ -2244,7 +2450,7 @@ class Article { * @access public */ function info() { - global $wgLang, $wgOut, $wgAllowPageInfo; + global $wgLang, $wgOut, $wgAllowPageInfo, $wgUser; $fname = 'Article::info'; if ( !$wgAllowPageInfo ) { @@ -2253,16 +2459,16 @@ class Article { } $page = $this->mTitle->getSubjectPage(); - + $wgOut->setPagetitle( $page->getPrefixedText() ); $wgOut->setSubtitle( wfMsg( 'infosubtitle' )); # first, see if the page exists at all. $exists = $page->getArticleId() != 0; if( !$exists ) { - $wgOut->addHTML( wfMsg('noarticletext') ); + $wgOut->addHTML( wfMsg( $wgUser->isLoggedIn() ? 'noarticletext' : 'noarticletextanon' ) ); } else { - $dbr =& $this->getDB( DB_SLAVE ); + $dbr =& $this->getDB( DB_SLAVE ); $wl_clause = array( 'wl_title' => $page->getDBkey(), 'wl_namespace' => $page->getNamespace() ); @@ -2275,7 +2481,7 @@ class Article { $pageInfo = $this->pageCountInfo( $page ); $talkInfo = $this->pageCountInfo( $page->getTalkPage() ); - + $wgOut->addHTML( "