- 欢迎来到THBWiki!如果您是第一次来到这里,请点击右上角注册一个帐户
- 有任何意见、建议、求助、反馈都可以在 讨论板 提出
- THBWiki以专业性和准确性为目标,如果你发现了任何确定的错误或疏漏,可在登录后直接进行改正
帮助:核心修改记录
本页面用于记录一些对Mediawiki本体的修改记录,扩展的修改记录可以参看帮助:扩展修改记录。
includes
\actions\PurgeAction.php
PurgeAction::show
public function PurgeAction::show
内增加了一个条件,设定拥有freepurge权限的用户无需点击确认按钮便可以刷新页面缓存。
public function show() {
$this->setHeaders();
// This will throw exceptions if there's a problem
$this->checkCanExecute( $this->getUser() );
$user = $this->getUser();
if ( $user->pingLimiter( 'purge' ) ) {
// TODO: Display actionthrottledtext
return;
}
if ( $this->getRequest()->wasPosted() || $user->isAllowed( 'freepurge' ) ) {
$this->redirectParams = wfArrayToCgi( array_diff_key(
$this->getRequest()->getQueryValues(),
[ 'title' => null, 'action' => null ]
) );
if ( $this->onSubmit( [] ) ) {
$this->onSuccess();
}
} else {
$this->redirectParams = $this->getRequest()->getVal( 'redirectparams', '' );
$form = $this->getForm();
if ( $form->show() ) {
$this->onSuccess();
}
}
}
\api\ApiOpenSearch.php
ApiOpenSearch::search
private function ApiOpenSearch::search
内将$wgSearchType暂时设为null,规避有时CirrusSearch在$wgSearchType不是null时不能工作的bug。
private function search( $search, array $params ) {
global $wgSearchType;
$stsave = $wgSearchType;
$wgSearchType = null;
$searchEngine = $this->buildSearchEngine( $params );
$titles = $searchEngine->extractTitles( $searchEngine->completionSearchWithVariants( $search ) );
$results = [];
$wgSearchType = $stsave;
if ( !$titles ) {
return $results;
}
// Special pages need unique integer ids in the return list, so we just
// assign them negative numbers because those won't clash with the
// always positive articleIds that non-special pages get.
$nextSpecialPageId = -1;
if ( $params['redirects'] === null ) {
// Backwards compatibility, don't resolve for JSON.
$resolveRedir = $this->getFormat() !== 'json';
} else {
$resolveRedir = $params['redirects'] === 'resolve';
}
if ( $resolveRedir ) {
// Query for redirects
$redirects = [];
$lb = new LinkBatch( $titles );
if ( !$lb->isEmpty() ) {
$db = $this->getDB();
$res = $db->select(
[ 'page', 'redirect' ],
[ 'page_namespace', 'page_title', 'rd_namespace', 'rd_title' ],
[
'rd_from = page_id',
'rd_interwiki IS NULL OR rd_interwiki = ' . $db->addQuotes( '' ),
$lb->constructSet( 'page', $db ),
],
__METHOD__
);
foreach ( $res as $row ) {
$redirects[$row->page_namespace][$row->page_title] =
[ $row->rd_namespace, $row->rd_title ];
}
}
// Bypass any redirects
$seen = [];
foreach ( $titles as $title ) {
$ns = $title->getNamespace();
$dbkey = $title->getDBkey();
$from = null;
if ( isset( $redirects[$ns][$dbkey] ) ) {
list( $ns, $dbkey ) = $redirects[$ns][$dbkey];
$from = $title;
$title = Title::makeTitle( $ns, $dbkey );
}
if ( !isset( $seen[$ns][$dbkey] ) ) {
$seen[$ns][$dbkey] = true;
$resultId = $title->getArticleID();
if ( $resultId === 0 ) {
$resultId = $nextSpecialPageId;
$nextSpecialPageId -= 1;
}
$results[$resultId] = [
'title' => $title,
'redirect from' => $from,
'extract' => false,
'extract trimmed' => false,
'image' => false,
'url' => wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ),
];
}
}
} else {
foreach ( $titles as $title ) {
$resultId = $title->getArticleID();
if ( $resultId === 0 ) {
$resultId = $nextSpecialPageId;
$nextSpecialPageId -= 1;
}
$results[$resultId] = [
'title' => $title,
'redirect from' => null,
'extract' => false,
'extract trimmed' => false,
'image' => false,
'url' => wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ),
];
}
}
return $results;
}
\cache\FileCacheBase.php
FileCacheBase::cachePath
protected function FileCacheBase::cachePath
内增加了一个判断,修正了页面标题太长(长于linux内文件名最大长度)时FileCache会无法创建对应缓存文件的bug。
protected function cachePath() {
if ( $this->mFilePath !== null ) {
return $this->mFilePath;
}
$dir = $this->cacheDirectory();
# Build directories (methods include the trailing "/")
$subDirs = $this->typeSubdirectory() . $this->hashSubdirectory();
# Avoid extension confusion
$key = str_replace( '.', '%2E', urlencode( $this->mKey ) );
# Check if file name is too long (typically 255 is the maximum length of file names in linux)
if ( strlen( $key ) + strlen( $this->mExt ) + 1 > 255 ) {
# If file name is too long, shorten it
$key = substr( $key, 0, 255 - 32 - strlen( $this->mExt ) - 1 ) . md5( $key );
}
# Build the full file path
$this->mFilePath = "{$dir}/{$subDirs}{$key}.{$this->mExt}";
if ( $this->useGzip() ) {
$this->mFilePath .= '.gz';
}
return $this->mFilePath;
}
\content\WikiTextStructure.php
WikiTextStructure::$excludedElementSelectors
private function WikiTextStructure::$excludedElementSelectors
内增加了一个项,方便标记不可搜索内容。
private $excludedElementSelectors = [
'audio', 'video', // "it looks like you don't have javascript enabled..."
// do not need to index
'sup.reference', // The [1] for references
'.mw-cite-backlink', // The ↑ next to references in the references section
'h1', 'h2', 'h3', // Headings are already indexed in their own field.
'h5', 'h6', 'h4',
'.autocollapse', // Collapsed fields are hidden by default so we don't want them
// showing up.
'.searchexclude', // Class for non searchable contents
];
WikiTextStructure::$auxiliaryElementSelectors
private function WikiTextStructure::$auxiliaryElementSelectors
内增加了一个项,标记头部模板为辅助搜索内容。
private $auxiliaryElementSelectors = [
'.thumbcaption', // Thumbnail captions aren't really part of the text proper
'table', // Neither are tables
'.rellink', // Common style for "See also:".
'.dablink', // Common style for calling out helpful links at the top
// of the article.
'.page-content-header', // Page content header
'.searchaux', // New class users can use to mark stuff as auxiliary to searches.
];
\exception\MWExceptionHandler.php
MWExceptionHandler
已不需要。
class MWExceptionHandler
内把所有Exception替换成Throwable,配合PHP7。
\gallery\NolinesImageGallery.php
NolinesImageGallery
class NolinesImageGallery
内修改了几个参数,让Gallery看起来更紧致。
class NolinesImageGallery extends TraditionalImageGallery {
protected function getThumbPadding() {
return 0;
}
protected function getGBBorders() {
// This accounts for extra space between <li> elements.
return 0;
}
protected function getVPad( $boxHeight, $thumbHeight ) {
return 0;
}
protected function getGBPadding() {
return 2;
}
}
\gallery\TraditionalImageGallery.php
TraditionalImageGallery::toHTML
function TraditionalImageGallery::toHTML
内修复了因不必要的换行导致在Gallery中出现无意义空格的bug。修改了BeforeParserFetchFileAndTitle的运作方式,用处详见对Parser.php的修改。
function toHTML() {
if ( $this->mPerRow > 0 ) {
$maxwidth = $this->mPerRow * ( $this->mWidths + $this->getAllPadding() );
$oldStyle = isset( $this->mAttribs['style'] ) ? $this->mAttribs['style'] : '';
# _width is ignored by any sane browser. IE6 doesn't know max-width
# so it uses _width instead
$this->mAttribs['style'] = "max-width: {$maxwidth}px;_width: {$maxwidth}px;" .
$oldStyle;
}
$attribs = Sanitizer::mergeAttributes(
array( 'class' => 'gallery mw-gallery-' . $this->mMode ), $this->mAttribs );
$modules = $this->getModules();
if ( $this->mParser ) {
$this->mParser->getOutput()->addModules( $modules );
} else {
$this->getOutput()->addModules( $modules );
}
$output = Xml::openElement( 'ul', $attribs );
if ( $this->mCaption ) {
$output .= "<li class='gallerycaption'>{$this->mCaption}</li>";
}
$lang = $this->getRenderLang();
# Output each image...
foreach ( $this->mImages as $pair ) {
/** @var Title $nt */
$nt = $pair[0];
$text = $pair[1]; # "text" means "caption" here
$alt = $pair[2];
$link = $pair[3];
$descQuery = false;
if ( $nt->getNamespace() === NS_FILE ) {
# Get the file...
if ( $this->mParser instanceof Parser ) {
# Give extensions a chance to select the file revision for us
$options = array();
wfRunHooks( 'BeforeParserFetchFileAndTitle',
array( $this->mParser, &$nt, &$options, &$descQuery ) );
# Fetch and register the file (file title may be different via hooks)
list( $img, $nt ) = $this->mParser->fetchFileAndTitle( $nt, $options );
} else {
$img = wfFindFile( $nt );
}
} else {
$img = false;
}
$params = $this->getThumbParams( $img );
// $pair[4] is per image handler options
$transformOptions = $params + $pair[4];
$thumb = false;
if ( !$img ) {
# We're dealing with a non-image, spit out the name and be done with it.
$thumbhtml = '<div class="thumb" style="height: '
. ( $this->getThumbPadding() + $this->mHeights ) . 'px;">'
. htmlspecialchars( $nt->getText() ) . '</div>';
if ( $this->mParser instanceof Parser ) {
$this->mParser->addTrackingCategory( 'broken-file-category' );
}
} elseif ( $this->mHideBadImages
&& wfIsBadImage( $nt->getDBkey(), $this->getContextTitle() )
) {
# The image is blacklisted, just show it as a text link.
$thumbhtml = '<div class="thumb" style="height: ' .
( $this->getThumbPadding() + $this->mHeights ) . 'px;">' .
Linker::linkKnown(
$nt,
htmlspecialchars( $nt->getText() )
) .
'</div>';
} elseif ( !( $thumb = $img->transform( $transformOptions ) ) ) {
# Error generating thumbnail.
$thumbhtml = '<div class="thumb" style="height: '
. ( $this->getThumbPadding() + $this->mHeights ) . 'px;">'
. htmlspecialchars( $img->getLastError() ) . '</div>';
} else {
/** @var MediaTransformOutput $thumb */
$vpad = $this->getVPad( $this->mHeights, $thumb->getHeight() );
$imageParameters = array(
'desc-link' => true,
'desc-query' => $descQuery,
'alt' => $alt,
'custom-url-link' => $link
);
// In the absence of both alt text and caption, fall back on
// providing screen readers with the filename as alt text
if ( $alt == '' && $text == '' ) {
$imageParameters['alt'] = $nt->getText();
}
$this->adjustImageParameters( $thumb, $imageParameters );
# Set both fixed width and min-height.
$thumbhtml = '<div class="thumb" style="width: '
. $this->getThumbDivWidth( $thumb->getWidth() ) . 'px;">'
# Auto-margin centering for block-level elements. Needed
# now that we have video handlers since they may emit block-
# level elements as opposed to simple <img> tags. ref
# http://css-discuss.incutio.com/?page=CenteringBlockElement
. '<div style="margin:' . $vpad . 'px auto;">'
. $thumb->toHtml( $imageParameters ) . '</div></div>';
// Call parser transform hook
/** @var MediaHandler $handler */
$handler = $img->getHandler();
if ( $this->mParser && $handler ) {
$handler->parserTransformHook( $this->mParser, $img );
}
}
// @todo Code is incomplete.
// $linkTarget = Title::newFromText( $wgContLang->getNsText( MWNamespace::getUser() ) .
// ":{$ut}" );
// $ul = Linker::link( $linkTarget, $ut );
if ( $this->mShowBytes ) {
if ( $img ) {
$fileSize = htmlspecialchars( $lang->formatSize( $img->getSize() ) );
} else {
$fileSize = $this->msg( 'filemissing' )->escaped();
}
$fileSize = "$fileSize<br />";
} else {
$fileSize = '';
}
$textlink = $this->mShowFilename ?
Linker::linkKnown(
$nt,
htmlspecialchars( $lang->truncate( $nt->getText(), $this->mCaptionLength ) )
) . "<br />" :
'';
$galleryText = $textlink . $text . $fileSize;
$galleryText = $this->wrapGalleryText( $galleryText, $thumb );
# Weird double wrapping (the extra div inside the li) needed due to FF2 bug
# Can be safely removed if FF2 falls completely out of existence
$output .= '<li class="gallerybox" style="width: '
. $this->getGBWidth( $thumb ) . 'px">'
. '<div style="width: ' . $this->getGBWidth( $thumb ) . 'px">'
. $thumbhtml
. $galleryText
. "</div></li>";
}
$output .= "</ul>";
return $output;
}
TraditionalImageGallery::wrapGalleryText
protected function TraditionalImageGallery::wrapGalleryText
内修复了因不必要的换行导致在Gallery中出现无意义空格的bug。
protected function wrapGalleryText( $galleryText, $thumb ) {
# ATTENTION: The newline after <div class="gallerytext"> is needed to
# accommodate htmltidy which in version 4.8.6 generated crackpot html in
# its absence, see: http://bugzilla.wikimedia.org/show_bug.cgi?id=1765
# -Ævar
return '<div class="gallerytext">'
. $galleryText
. "</div>";
}
TraditionalImageGallery::getThumbPadding
protected function TraditionalImageGallery::getThumbPadding
内修改了一个参数,让Gallery看起来更紧致。
protected function getThumbPadding() {
return 10;
}
\jobqueue\jobs\RefreshLinksJob.php
RefreshLinksJob::runForTitle
protected function RefreshLinksJob::runForTitle
内增加针对SMW的补丁。可能在新版本中不需要。
protected function runForTitle( Title $title ) {
$services = MediaWikiServices::getInstance();
$stats = $services->getStatsdDataFactory();
$lbFactory = $services->getDBLoadBalancerFactory();
$ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
$page = WikiPage::factory( $title );
$page->loadPageData( WikiPage::READ_LATEST );
// Serialize links updates by page ID so they see each others' changes
$dbw = $lbFactory->getMainLB()->getConnection( DB_MASTER );
/** @noinspection PhpUnusedLocalVariableInspection */
$scopedLock = LinksUpdate::acquirePageLock( $dbw, $page->getId(), 'job' );
// Get the latest ID *after* acquirePageLock() flushed the transaction.
// This is used to detect edits/moves after loadPageData() but before the scope lock.
// The works around the chicken/egg problem of determining the scope lock key.
$latest = $title->getLatestRevID( Title::GAID_FOR_UPDATE );
if ( !empty( $this->params['triggeringRevisionId'] ) ) {
// Fetch the specified revision; lockAndGetLatest() below detects if the page
// was edited since and aborts in order to avoid corrupting the link tables
$revision = Revision::newFromId(
$this->params['triggeringRevisionId'],
Revision::READ_LATEST
);
} else {
// Fetch current revision; READ_LATEST reduces lockAndGetLatest() check failures
$revision = Revision::newFromTitle( $title, false, Revision::READ_LATEST );
}
if ( !$revision ) {
$stats->increment( 'refreshlinks.rev_not_found' );
$this->setLastError( "Revision not found for {$title->getPrefixedDBkey()}" );
return false; // just deleted?
} elseif ( $revision->getId() != $latest || $revision->getPage() !== $page->getId() ) {
// Do not clobber over newer updates with older ones. If all jobs where FIFO and
// serialized, it would be OK to update links based on older revisions since it
// would eventually get to the latest. Since that is not the case (by design),
// only update the link tables to a state matching the current revision's output.
$stats->increment( 'refreshlinks.rev_not_current' );
$this->setLastError( "Revision {$revision->getId()} is not current" );
return false;
}
$content = $revision->getContent( Revision::RAW );
if ( !$content ) {
// If there is no content, pretend the content is empty
$content = $revision->getContentHandler()->makeEmptyContent();
}
$parserOutput = false;
$parserOptions = $page->makeParserOptions( 'canonical' );
// If page_touched changed after this root job, then it is likely that
// any views of the pages already resulted in re-parses which are now in
// cache. The cache can be reused to avoid expensive parsing in some cases.
if ( isset( $this->params['rootJobTimestamp'] ) ) {
$opportunistic = !empty( $this->params['isOpportunistic'] );
$skewedTimestamp = $this->params['rootJobTimestamp'];
if ( $opportunistic ) {
// Neither clock skew nor DB snapshot/replica DB lag matter much for such
// updates; focus on reusing the (often recently updated) cache
} else {
// For transclusion updates, the template changes must be reflected
$skewedTimestamp = wfTimestamp( TS_MW,
wfTimestamp( TS_UNIX, $skewedTimestamp ) + self::CLOCK_FUDGE
);
}
if ( $page->getLinksTimestamp() > $skewedTimestamp ) {
// Something already updated the backlinks since this job was made
$stats->increment( 'refreshlinks.update_skipped' );
return true;
}
if ( $page->getTouched() >= $this->params['rootJobTimestamp'] || $opportunistic ) {
// Cache is suspected to be up-to-date. As long as the cache rev ID matches
// and it reflects the job's triggering change, then it is usable.
$parserOutput = ParserCache::singleton()->getDirty( $page, $parserOptions );
if ( !$parserOutput
|| $parserOutput->getCacheRevisionId() != $revision->getId()
|| $parserOutput->getCacheTime() < $skewedTimestamp
) {
$parserOutput = false; // too stale
}
}
}
// Fetch the current revision and parse it if necessary...
if ( $parserOutput ) {
$stats->increment( 'refreshlinks.parser_cached' );
} else {
$start = microtime( true );
// Revision ID must be passed to the parser output to get revision variables correct
$parserOutput = $content->getParserOutput(
$title, $revision->getId(), $parserOptions, false );
$elapsed = microtime( true ) - $start;
// If it took a long time to render, then save this back to the cache to avoid
// wasted CPU by other apaches or job runners. We don't want to always save to
// cache as this can cause high cache I/O and LRU churn when a template changes.
if ( $elapsed >= self::PARSE_THRESHOLD_SEC
&& $page->shouldCheckParserCache( $parserOptions, $revision->getId() )
&& $parserOutput->isCacheable()
) {
$ctime = wfTimestamp( TS_MW, (int)$start ); // cache time
ParserCache::singleton()->save(
$parserOutput, $page, $parserOptions, $ctime, $revision->getId()
);
}
$stats->increment( 'refreshlinks.parser_uncached' );
}
$updates = $content->getSecondaryDataUpdates(
$title,
null,
!empty( $this->params['useRecursiveLinksUpdate'] ),
$parserOutput
);
// For legacy hook handlers doing updates via LinksUpdateConstructed, make sure
// any pending writes they made get flushed before the doUpdate() calls below.
// This avoids snapshot-clearing errors in LinksUpdate::acquirePageLock().
$lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
foreach ( $updates as $key => $update ) {
// FIXME: This code probably shouldn't be here?
// Needed by things like Echo notifications which need
// to know which user caused the links update
if ( $update instanceof LinksUpdate ) {
$update->setRevision( $revision );
if ( !empty( $this->params['triggeringUser'] ) ) {
$userInfo = $this->params['triggeringUser'];
if ( $userInfo['userId'] ) {
$user = User::newFromId( $userInfo['userId'] );
} else {
// Anonymous, use the username
$user = User::newFromName( $userInfo['userName'], false );
}
$update->setTriggeringUser( $user );
}
}
}
foreach ( $updates as $update ) {
$update->setTransactionTicket( $ticket );
$update->doUpdate();
}
InfoAction::invalidateCache( $title );
return true;
}
\jobqueue\JobQueueGroup.php
JobQueueGroup::__destruct
function JobQueueGroup::__destruct
中避免烦人的报错。
function __destruct() {
$n = count( $this->bufferedJobs );
if ( $n > 0 ) {
//$type = implode( ', ', array_unique( array_map( 'get_class', $this->bufferedJobs ) ) );
//trigger_error( __METHOD__ . ": $n buffered job(s) of type(s) $type never inserted." );
}
}
\parser\BlockLevelPass.php
BlockLevelPass::normalizePrefix
class BlockLevelPass
内增加函数BlockLevelPass::normalizePrefix,用于判断li款色和兼容全形冒号和分号。
public function normalizePrefix( $prefix ) {
return strtr( $prefix,
array(
'*b'=>'*', // blue bullet, same as normal '*'
'*d'=>'d', // disc bullet
'*c'=>'c', // circle bullet
'*s'=>'s', // square bullet
'*x'=>'x', // cross bullet
':'=> ':',
';'=>';',
)
);
}
BlockLevelPass::openList
private function BlockLevelPass::openList
内增加判断li款色的功能,效果如下:
- d
- c
- s
- x
。
private function openList( $char ) {
$result = $this->closeParagraph();
if ( '*' === $char ) {
$result .= "<ul><li>";
} elseif ( '#' === $char ) {
$result .= "<ol><li>";
} elseif ( ':' === $char ) {
$result .= "<dl><dd>";
} elseif ( ';' === $char ) {
$result .= "<dl><dt>";
$this->DTopen = true;
} elseif ( strpos( 'dcsx', $char ) !== false ) {
$result .= "<ul><li class=\"$char\">";
} else {
$result = '<!-- ERR 1 -->';
}
return $result;
}
BlockLevelPass::nextItem
private function BlockLevelPass::nextItem
内增加判断li款色的功能。
private function nextItem( $char ) {
if ( '*' === $char || '#' === $char ) {
return "</li>\n<li>";
} elseif ( ':' === $char || ';' === $char ) {
$close = "</dd>\n";
if ( $this->DTopen ) {
$close = "</dt>\n";
}
if ( ';' === $char ) {
$this->DTopen = true;
return $close . '<dt>';
} else {
$this->DTopen = false;
return $close . '<dd>';
}
} elseif ( strpos( 'dcsx', $char ) !== false ) {
return "</li>\n<li class=\"$char\">";
}
return '<!-- ERR 2 -->';
}
BlockLevelPass::closeList
private function BlockLevelPass::closeList
内增加判断li款色的功能。
private function closeList( $char ) {
if ( '*' === $char || strpos( 'dcsx', $char ) !== false ) {
$text = "</li></ul>";
} elseif ( '#' === $char ) {
$text = "</li></ol>";
} elseif ( ':' === $char ) {
if ( $this->DTopen ) {
$this->DTopen = false;
$text = "</dt></dl>";
} else {
$text = "</dd></dl>";
}
} else {
return '<!-- ERR 3 -->';
}
return $text;
}
BlockLevelPass::execute
private function BlockLevelPass::execute
内增加判断li款色和兼容全形冒号和分号的功能。
private function execute() {
$text = $this->text;
# Parsing through the text line by line. The main thing
# happening here is handling of block-level elements p, pre,
# and making lists from lines starting with * # : etc.
$textLines = StringUtils::explode( "\n", $text );
$lastPrefix = $output = '';
$this->DTopen = $inBlockElem = false;
$prefixLength = 0;
$pendingPTag = false;
$inBlockquote = false;
foreach ( $textLines as $inputLine ) {
# Fix up $lineStart
if ( !$this->lineStart ) {
$output .= $inputLine;
$this->lineStart = true;
continue;
}
# * = ul
# # = ol
# ; = dt
# : = dd
$lastPrefixLength = strlen( $lastPrefix );
$preCloseMatch = preg_match( '/<\\/pre/i', $inputLine );
$preOpenMatch = preg_match( '/<pre/i', $inputLine );
# If not in a <pre> element, scan for and figure out what prefixes are there.
if ( !$this->inPre ) {
# Multiple prefixes may abut each other for nested lists.
$prefix = null;
preg_match( '/^(\*([bdcsx](?=$| |\*|#|:|:|;|;))?|#|:|:|;|;)*/u', $inputLine, $prefix );
$prefix = !is_null( $prefix ) && isset( $prefix[0] ) ? $prefix[0] : '';
$t = substr( $inputLine, strlen( $prefix ) );
$prefix = self::normalizePrefix( $prefix );
$prefixLength = strlen( $prefix );
# eh?
# ; and : are both from definition-lists, so they're equivalent
# for the purposes of determining whether or not we need to open/close
# elements.
$prefix2 = strtr( $prefix, ';dcsx', ':****' );
$this->inPre = (bool)$preOpenMatch;
} else {
# Don't interpret any other prefixes in preformatted text
$prefixLength = 0;
$prefix = $prefix2 = '';
$t = $inputLine;
}
# List generation
if ( $prefixLength && $lastPrefix === $prefix2 ) {
# Same as the last item, so no need to deal with nesting or opening stuff
$output .= $this->nextItem( substr( $prefix, -1 ) );
$pendingPTag = false;
if ( substr( $prefix, -1 ) === ';' ) {
# The one nasty exception: definition lists work like this:
# ; title : definition text
# So we check for : in the remainder text to split up the
# title and definition, without b0rking links.
$t = preg_replace( '/:/u', ':', $t, 1 );
$term = $t2 = '';
if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
$t = $t3 = '';
while ( $this->findColonNoLinks( $t2, $t3, $t2 ) !== false ) $t .= $t3 . '<br />';
$t .= $t2;
$output .= $term . $this->nextItem( ':' );
}
}
} elseif ( $prefixLength || $lastPrefixLength ) {
# We need to open or close prefixes, or both.
# Either open or close a level...
$commonPrefixLength = $this->getCommon( $prefix, $lastPrefix );
$pendingPTag = false;
# Close all the prefixes which aren't shared.
while ( $commonPrefixLength < $lastPrefixLength ) {
$output .= $this->closeList( $lastPrefix[$lastPrefixLength - 1] );
--$lastPrefixLength;
}
# Continue the current prefix if appropriate.
if ( $prefixLength <= $commonPrefixLength && $commonPrefixLength > 0 ) {
$output .= $this->nextItem( $prefix[$commonPrefixLength - 1] );
}
# Open prefixes where appropriate.
if ( $lastPrefix && $prefixLength > $commonPrefixLength ) {
$output .= "\n";
}
while ( $prefixLength > $commonPrefixLength ) {
$char = substr( $prefix, $commonPrefixLength, 1 );
$output .= $this->openList( $char );
if ( ';' === $char ) {
# @todo FIXME: This is dupe of code above
if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
$t = $t2;
$output .= $term . $this->nextItem( ':' );
}
}
++$commonPrefixLength;
}
if ( !$prefixLength && $lastPrefix ) {
$output .= "\n";
}
$lastPrefix = $prefix2;
}
# If we have no prefixes, go to paragraph mode.
if ( 0 == $prefixLength ) {
# No prefix (not in list)--go to paragraph mode
# @todo consider using a stack for nestable elements like span, table and div
$openMatch = preg_match(
'/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
. '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS',
$t
);
$closeMatch = preg_match(
'/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
. '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
. Parser::MARKER_PREFIX
. '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
$t
);
if ( $openMatch || $closeMatch ) {
$pendingPTag = false;
# @todo bug 5718: paragraph closed
$output .= $this->closeParagraph();
if ( $preOpenMatch && !$preCloseMatch ) {
$this->inPre = true;
}
$bqOffset = 0;
while ( preg_match( '/<(\\/?)blockquote[\s>]/i', $t,
$bqMatch, PREG_OFFSET_CAPTURE, $bqOffset )
) {
$inBlockquote = !$bqMatch[1][0]; // is this a close tag?
$bqOffset = $bqMatch[0][1] + strlen( $bqMatch[0][0] );
}
$inBlockElem = !$closeMatch;
} elseif ( !$inBlockElem && !$this->inPre ) {
if ( ' ' == substr( $t, 0, 1 )
&& ( $this->lastSection === 'pre' || trim( $t ) != '' )
&& !$inBlockquote
) {
# pre
if ( $this->lastSection !== 'pre' ) {
$pendingPTag = false;
$output .= $this->closeParagraph() . '<pre>';
$this->lastSection = 'pre';
}
$t = substr( $t, 1 );
} else {
# paragraph
if ( trim( $t ) === '' ) {
if ( $pendingPTag ) {
$output .= $pendingPTag . '<br />';
$pendingPTag = false;
$this->lastSection = 'p';
} else {
if ( $this->lastSection !== 'p' ) {
$output .= $this->closeParagraph();
$this->lastSection = '';
$pendingPTag = '<p>';
} else {
$pendingPTag = '</p><p>';
}
}
} else {
if ( $pendingPTag ) {
$output .= $pendingPTag;
$pendingPTag = false;
$this->lastSection = 'p';
} elseif ( $this->lastSection !== 'p' ) {
$output .= $this->closeParagraph() . '<p>';
$this->lastSection = 'p';
}
}
}
}
}
# somewhere above we forget to get out of pre block (bug 785)
if ( $preCloseMatch && $this->inPre ) {
$this->inPre = false;
}
if ( $pendingPTag === false ) {
$output .= $t;
if ( $prefixLength === 0 ) {
$output .= "\n";
}
}
}
while ( $prefixLength ) {
$output .= $this->closeList( $prefix2[$prefixLength - 1] );
--$prefixLength;
if ( !$prefixLength ) {
$output .= "\n";
}
}
if ( $this->lastSection !== '' ) {
$output .= '</' . $this->lastSection . '>';
$this->lastSection = '';
}
return $output;
}
\parser\Parser.php
Parser
class Parser
内修改了所有BeforeParserFetchFileAndTitle的运作方式。在不修改此项目的情况下,正则重定向、模糊重定向、忽略文件扩展名重定向等重定向功能只能作用在词条链接、输入网址时的重定向、模板引用上,原生MW并没有提供让扩展可以修改文件引用的Hook,也就是说当一个页面嵌入一个文件时,系统里没有方法可以把这个文件(不管存不存在)换成别的文件。这里的改动则更正了这个缺陷。
wfRunHooks( 'BeforeParserFetchFileAndTitle',
array( $this, &$nt, &$options, &$descQuery ) );
Parser::__construct
public function Parser::__construct
内修改了判断单[]链接的正则,增加识别[/沙盒?action=edit 编辑]及[/api.php]等格式的自由内链的功能,实际效果为编辑及[1],并会作为内链显示。
public function __construct( $conf = [] ) {
$this->mConf = $conf;
$this->mUrlProtocols = wfUrlProtocols();
$this->mExtLinkBracketedRegex = '/\[(((?i)' . $this->mUrlProtocols . '|\\/)' .
self::EXT_LINK_ADDR .
self::EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/Su';
if ( isset( $conf['preprocessorClass'] ) ) {
$this->mPreprocessorClass = $conf['preprocessorClass'];
} elseif ( defined( 'HPHP_VERSION' ) ) {
# Preprocessor_Hash is much faster than Preprocessor_DOM under HipHop
$this->mPreprocessorClass = 'Preprocessor_Hash';
} elseif ( extension_loaded( 'domxml' ) ) {
# PECL extension that conflicts with the core DOM extension (bug 13770)
wfDebug( "Warning: you have the obsolete domxml extension for PHP. Please remove it!\n" );
$this->mPreprocessorClass = 'Preprocessor_Hash';
} elseif ( extension_loaded( 'dom' ) ) {
$this->mPreprocessorClass = 'Preprocessor_DOM';
} else {
$this->mPreprocessorClass = 'Preprocessor_Hash';
}
wfDebug( __CLASS__ . ": using preprocessor: {$this->mPreprocessorClass}\n" );
}
Parser::replaceExternalLinks
public function Parser::replaceExternalLinks
内修复方括号判断bug和增加自由内链的控制。
public function replaceExternalLinks( $text ) {
$bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
if ( $bits === false ) {
throw new MWException( "PCRE needs to be compiled with "
. "--enable-unicode-properties in order for MediaWiki to function" );
}
$s = array_shift( $bits );
$i = 0;
while ( $i < count( $bits ) ) {
$url = $bits[$i++];
$protocol = $bits[$i++]; // protocol
$text = str_replace( [ '[', ']' ], [ '[', ']' ], $bits[$i++] );
$trail = str_replace( [ '[', ']' ], [ '[', ']' ], $bits[$i++] );
//echo '<div style="display:none;">';
//var_dump($m);
//echo '</div>';
# If we get a ] at the beginning of $m[3] that means we have a link that's something like:
# [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row fucks up,
# the real problem is with the $e1 regex
# See bug 1300.
# Still some problems for cases where the ] is meant to be outside punctuation,
# and no image is in sight. See bug 2095.
if ( $text !== '' &&
($squareCount = min( strspn( $trail, ']' ), substr_count( $text, '[' )-substr_count( $text, ']' ) )) > 0
) {
$text .= str_repeat( ']', $squareCount ); # so that replaceExternalLinks($text) works later
$trail = substr( $trail, $squareCount );
}
# The characters '<' and '>' (which were escaped by
# removeHTMLtags()) should not be included in
# URLs, per RFC 2396.
$m2 = [];
if ( preg_match( '/&(lt|gt);/', $url, $m2, PREG_OFFSET_CAPTURE ) ) {
$text = substr( $url, $m2[0][1] ) . ' ' . $text;
$url = substr( $url, 0, $m2[0][1] );
}
# If the link text is an image URL, replace it with an <img> tag
# This happened by accident in the original parser, but some people used it extensively
$img = $this->maybeMakeExternalImage( $text );
if ( $img !== false ) {
$text = $img;
}
$dtrail = '';
# Set linktype for CSS - if URL==text, link is essentially free
$linktype = ( $text === $url ) ? 'free' : 'text';
# No link text, e.g. [http://domain.tld/some.link]
if ( $text == '' ) {
# Autonumber
$langObj = $this->getTargetLanguage();
$text = '[' . $langObj->formatNum( ++$this->mAutonumber ) . ']';
$linktype = 'autonumber';
} else {
# Have link text, e.g. [http://domain.tld/some.link text]s
# Check for trail
list( $dtrail, $trail ) = Linker::splitTrail( $trail );
}
$text = $this->getConverterLanguage()->markNoConversion( $text );
$url = Sanitizer::cleanUrl( $url );
# Use the encoded URL
# This means that users can paste URLs directly into the text
# Funny characters like ö aren't valid in URLs anyway
# This was changed in August 2004
if ( $protocol == '/' ) {
$s .= Linker::makeInternalLink( $url, $text, false, $linktype );
} else {
$s .= Linker::makeExternalLink( $url, $text, false, $linktype,
$this->getExternalLinkAttribs( $url ) );
}
$s .= $dtrail . $trail;
# Register link in the output object.
# Replace unnecessary URL escape codes with the referenced character
# This prevents spammers from hiding links from the filters
$pasteurized = self::normalizeLinkUrl( $url );
$this->mOutput->addExternalLink( $pasteurized );
}
return $s;
}
Parser::replaceInternalLinks2
public function Parser::replaceInternalLinks2
内修复方括号判断bug和增加自由内链的控制。
public function replaceInternalLinks2( &$s ) {
global $wgExtraInterlanguageLinkPrefixes;
static $tc = false, $e1, $e1_img;
# the % is needed to support urlencoded titles as well
if ( !$tc ) {
$tc = Title::legalChars() . '#%';
# Match a link having the form [[namespace:link|alternate]]trail
$e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD";
# Match cases where there is no "]]", which might still be images
$e1_img = "/^([{$tc}]+)\\|(.*)\$/sD";
}
$holders = new LinkHolderArray( $this );
# split the entire text string on occurrences of [[
$a = StringUtils::explode( '[[', ' ' . $s );
# get the first element (all text up to first [[), and remove the space we added
$s = $a->current();
$a->next();
$line = $a->current(); # Workaround for broken ArrayIterator::next() that returns "void"
$s = substr( $s, 1 );
$useLinkPrefixExtension = $this->getTargetLanguage()->linkPrefixExtension();
$e2 = null;
if ( $useLinkPrefixExtension ) {
# Match the end of a line for a word that's not followed by whitespace,
# e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched
global $wgContLang;
$charset = $wgContLang->linkPrefixCharset();
$e2 = "/^((?>.*[^$charset]|))(.+)$/sDu";
}
if ( is_null( $this->mTitle ) ) {
throw new MWException( __METHOD__ . ": \$this->mTitle is null\n" );
}
$nottalk = !$this->mTitle->isTalkPage();
if ( $useLinkPrefixExtension ) {
$m = [];
if ( preg_match( $e2, $s, $m ) ) {
$first_prefix = $m[2];
} else {
$first_prefix = false;
}
} else {
$prefix = '';
}
$useSubpages = $this->areSubpagesAllowed();
// @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
# Loop for each link
for ( ; $line !== false && $line !== null; $a->next(), $line = $a->current() ) {
// @codingStandardsIgnoreEnd
# Check for excessive memory usage
if ( $holders->isBig() ) {
# Too big
# Do the existence check, replace the link holders and clear the array
$holders->replace( $s );
$holders->clear();
}
if ( $useLinkPrefixExtension ) {
if ( preg_match( $e2, $s, $m ) ) {
$prefix = $m[2];
$s = $m[1];
} else {
$prefix = '';
}
# first link
if ( $first_prefix ) {
$prefix = $first_prefix;
$first_prefix = false;
}
}
$might_be_img = false;
if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt
$text = str_replace( [ '[', ']' ], [ '[', ']' ], $m[2] );
$m[3] = str_replace( [ '[', ']' ], [ '[', ']' ], $m[3] );
//echo '<div style="display:none;">';
//var_dump($m);
//echo '</div>';
# If we get a ] at the beginning of $m[3] that means we have a link that's something like:
# [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row fucks up,
# the real problem is with the $e1 regex
# See bug 1300.
# Still some problems for cases where the ] is meant to be outside punctuation,
# and no image is in sight. See bug 2095.
if ( $text !== '' &&
($squareCount = min( strspn( $m[3], ']' ), substr_count( $text, '[' )-substr_count( $text, ']' ) )) > 0
) {
$text .= str_repeat( ']', $squareCount ); # so that replaceExternalLinks($text) works later
$m[3] = substr( $m[3], $squareCount );
}
# fix up urlencoded title texts
if ( strpos( $m[1], '%' ) !== false ) {
# Should anchors '#' also be rejected?
$m[1] = str_replace( [ '<', '>' ], [ '<', '>' ], rawurldecode( $m[1] ) );
}
$trail = $m[3];
} elseif ( preg_match( $e1_img, $line, $m ) ) {
# Invalid, but might be an image with a link in its caption
$might_be_img = true;
$text = $m[2];
if ( strpos( $m[1], '%' ) !== false ) {
$m[1] = str_replace( [ '<', '>' ], [ '<', '>' ], rawurldecode( $m[1] ) );
}
$trail = "";
} else { # Invalid form; output directly
$s .= $prefix . '[[' . $line;
continue;
}
$origLink = $m[1];
# Don't allow internal links to pages containing
# PROTO: where PROTO is a valid URL protocol; these
# should be external links.
if ( preg_match( '/^(?i:' . $this->mUrlProtocols . ')/', $origLink ) ) {
$s .= $prefix . '[[' . $line;
continue;
}
# Make subpage if necessary
if ( $useSubpages ) {
$link = $this->maybeDoSubpageLink( $origLink, $text );
} else {
$link = $origLink;
}
$noforce = ( substr( $origLink, 0, 1 ) !== ':' );
if ( !$noforce ) {
# Strip off leading ':'
$link = substr( $link, 1 );
}
$unstrip = $this->mStripState->unstripNoWiki( $link );
$nt = is_string( $unstrip ) ? Title::newFromText( $unstrip ) : null;
if ( $nt === null ) {
$s .= $prefix . '[[' . $line;
continue;
}
$ns = $nt->getNamespace();
$iw = $nt->getInterwiki();
if ( $might_be_img ) { # if this is actually an invalid link
if ( $ns == NS_FILE && $noforce ) { # but might be an image
$found = false;
while ( true ) {
# look at the next 'line' to see if we can close it there
$a->next();
$next_line = $a->current();
if ( $next_line === false || $next_line === null ) {
break;
}
$m = explode( ']]', $next_line, 3 );
if ( count( $m ) == 3 ) {
# the first ]] closes the inner link, the second the image
$found = true;
$text .= "[[{$m[0]}]]{$m[1]}";
$trail = $m[2];
break;
} elseif ( count( $m ) == 2 ) {
# if there's exactly one ]] that's fine, we'll keep looking
$text .= "[[{$m[0]}]]{$m[1]}";
} else {
# if $next_line is invalid too, we need look no further
$text .= '[[' . $next_line;
break;
}
}
if ( !$found ) {
# we couldn't find the end of this imageLink, so output it raw
# but don't ignore what might be perfectly normal links in the text we've examined
$holders->merge( $this->replaceInternalLinks2( $text ) );
$s .= "{$prefix}[[$link|$text";
# note: no $trail, because without an end, there *is* no trail
continue;
}
} else { # it's not an image, so output it raw
$s .= "{$prefix}[[$link|$text";
# note: no $trail, because without an end, there *is* no trail
continue;
}
}
$wasblank = ( $text == '' );
if ( $wasblank ) {
$text = $link;
} else {
# Bug 4598 madness. Handle the quotes only if they come from the alternate part
# [[Lista d''e paise d''o munno]] -> <a href="...">Lista d''e paise d''o munno</a>
# [[Criticism of Harry Potter|Criticism of ''Harry Potter'']]
# -> <a href="Criticism of Harry Potter">Criticism of <i>Harry Potter</i></a>
$text = $this->doQuotes( $text );
}
# Link not escaped by : , create the various objects
if ( $noforce && !$nt->wasLocalInterwiki() ) {
# Interwikis
if (
$iw && $this->mOptions->getInterwikiMagic() && $nottalk && (
Language::fetchLanguageName( $iw, null, 'mw' ) ||
in_array( $iw, $wgExtraInterlanguageLinkPrefixes )
)
) {
# Bug 24502: filter duplicates
if ( !isset( $this->mLangLinkLanguages[$iw] ) ) {
$this->mLangLinkLanguages[$iw] = true;
$this->mOutput->addLanguageLink( $nt->getFullText() );
}
$s = rtrim( $s . $prefix );
$s .= trim( $trail, "\n" ) == '' ? '': $prefix . $trail;
continue;
}
if ( $ns == NS_FILE ) {
if ( !wfIsBadImage( $nt->getDBkey(), $this->mTitle ) ) {
if ( $wasblank ) {
# if no parameters were passed, $text
# becomes something like "File:Foo.png",
# which we don't want to pass on to the
# image generator
$text = '';
} else {
# recursively parse links inside the image caption
# actually, this will parse them in any other parameters, too,
# but it might be hard to fix that, and it doesn't matter ATM
$text = $this->replaceExternalLinks( $text );
$holders->merge( $this->replaceInternalLinks2( $text ) );
}
# cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them
$s .= $prefix . $this->armorLinks(
$this->makeImage( $nt, $text, $holders ) ) . $trail;
continue;
}
} elseif ( $ns == NS_CATEGORY ) {
$s = rtrim( $s . "\n" ); # bug 87
if ( $wasblank ) {
$sortkey = $this->getDefaultSort();
} else {
$sortkey = $text;
}
$sortkey = Sanitizer::decodeCharReferences( $sortkey );
$sortkey = str_replace( "\n", '', $sortkey );
$sortkey = $this->getConverterLanguage()->convertCategoryKey( $sortkey );
$this->mOutput->addCategory( $nt->getDBkey(), $sortkey );
/**
* Strip the whitespace Category links produce, see bug 87
*/
$s .= trim( $prefix . $trail, "\n" ) == '' ? '' : $prefix . $trail;
continue;
}
}
# Self-link checking. For some languages, variants of the title are checked in
# LinkHolderArray::doVariants() to allow batching the existence checks necessary
# for linking to a different variant.
if ( $ns != NS_SPECIAL && $nt->equals( $this->mTitle ) && !$nt->hasFragment() ) {
$s .= $prefix . Linker::makeSelfLinkObj( $nt, $text, '', $trail );
continue;
}
# NS_MEDIA is a pseudo-namespace for linking directly to a file
# @todo FIXME: Should do batch file existence checks, see comment below
if ( $ns == NS_MEDIA ) {
# Give extensions a chance to select the file revision for us
$options = [];
$descQuery = false;
Hooks::run( 'BeforeParserFetchFileAndTitle',
[ $this, &$nt, &$options, &$descQuery ] );
# Fetch and register the file (file title may be different via hooks)
list( $file, $nt ) = $this->fetchFileAndTitle( $nt, $options );
# Cloak with NOPARSE to avoid replacement in replaceExternalLinks
$s .= $prefix . $this->armorLinks(
Linker::makeMediaLinkFile( $nt, $file, $text ) ) . $trail;
continue;
}
# Some titles, such as valid special pages or files in foreign repos, should
# be shown as bluelinks even though they're not included in the page table
# @todo FIXME: isAlwaysKnown() can be expensive for file links; we should really do
# batch file existence checks for NS_FILE and NS_MEDIA
if ( $iw == '' && $nt->isAlwaysKnown() ) {
$this->mOutput->addLink( $nt );
$s .= $this->makeKnownLinkHolder( $nt, $text, $trail, $prefix );
} else {
# Links will be added to the output link list after checking
$s .= $holders->makeHolder( $nt, $text, [], $trail, $prefix );
}
}
return $holders;
}
\skins\Skin.php
Skin::buildSidebar<
function Skin::buildSidebar
内注释掉了原生侧边栏的运算语句,禁用掉原生侧边栏好让MenuSidebar可以更自如地显示。
function buildSidebar() {
global $wgEnableSidebarCache, $wgSidebarCacheExpiry;
$that = $this;
$callback = function () use ( $that ) {
$bar = [];
//$that->addToSidebar( $bar, 'sidebar' );
Hooks::run( 'SkinBuildSidebar', [ $that, &$bar ] );
return $bar;
};
if ( $wgEnableSidebarCache ) {
$cache = ObjectCache::getMainWANInstance();
$sidebar = $cache->getWithSetCallback(
$cache->makeKey( 'sidebar', $this->getLanguage()->getCode() ),
MessageCache::singleton()->isDisabled()
? $cache::TTL_UNCACHEABLE // bug T133069
: $wgSidebarCacheExpiry,
$callback,
[ 'lockTSE' => 30 ]
);
} else {
$sidebar = $callback();
}
// Apply post-processing to the cached value
Hooks::run( 'SidebarBeforeOutput', [ $this, &$sidebar ] );
return $sidebar;
}
\specials\SpecialEditWatchlist.php
SpecialEditWatchlist::execute
private function SpecialEditWatchlist::clearWatchlist
内增加了Hook。
private function clearWatchlist() {
$dbw = wfGetDB( DB_MASTER );
$dbw->delete(
'watchlist',
[ 'wl_user' => $this->getUser()->getId() ],
__METHOD__
);
Hooks::run( 'WatchArticleClearComplete', [ $this->getUser() ] );
}
\specials\SpecialMovepage.php
MovePageForm::execute
public function MovePageForm::execute
内修改了移动页面时保留重定向选项的默认勾选状态,现在保留重定向默认是否勾选会视乎用户设定而改变。
public function execute( $par ) {
$this->useTransactionalTimeLimit();
$this->checkReadOnly();
$this->setHeaders();
$this->outputHeader();
$request = $this->getRequest();
$target = !is_null( $par ) ? $par : $request->getVal( 'target' );
// Yes, the use of getVal() and getText() is wanted, see bug 20365
$oldTitleText = $request->getVal( 'wpOldTitle', $target );
$this->oldTitle = Title::newFromText( $oldTitleText );
if ( !$this->oldTitle ) {
// Either oldTitle wasn't passed, or newFromText returned null
throw new ErrorPageError( 'notargettitle', 'notargettext' );
}
if ( !$this->oldTitle->exists() ) {
throw new ErrorPageError( 'nopagetitle', 'nopagetext' );
}
$newTitleTextMain = $request->getText( 'wpNewTitleMain' );
$newTitleTextNs = $request->getInt( 'wpNewTitleNs', $this->oldTitle->getNamespace() );
// Backwards compatibility for forms submitting here from other sources
// which is more common than it should be..
$newTitleText_bc = $request->getText( 'wpNewTitle' );
$this->newTitle = strlen( $newTitleText_bc ) > 0
? Title::newFromText( $newTitleText_bc )
: Title::makeTitleSafe( $newTitleTextNs, $newTitleTextMain );
$user = $this->getUser();
# Check rights
$permErrors = $this->oldTitle->getUserPermissionsErrors( 'move', $user );
if ( count( $permErrors ) ) {
// Auto-block user's IP if the account was "hard" blocked
DeferredUpdates::addCallableUpdate( function() use ( $user ) {
$user->spreadAnyEditBlock();
} );
throw new PermissionsError( 'move', $permErrors );
}
$def = !$request->wasPosted();
$this->reason = $request->getText( 'wpReason' );
$this->moveTalk = $request->getBool( 'wpMovetalk', $def );
$this->fixRedirects = $request->getBool( 'wpFixRedirects', $def );
$this->leaveRedirect = $request->getBool( 'wpLeaveRedirect', $def && !$user->getOption( 'ap-prefs-not-dcr' ) );
$this->moveSubpages = $request->getBool( 'wpMovesubpages' );
$this->deleteAndMove = $request->getBool( 'wpDeleteAndMove' );
$this->moveOverShared = $request->getBool( 'wpMoveOverSharedFile' );
$this->watch = $request->getCheck( 'wpWatch' ) && $user->isLoggedIn();
if ( 'submit' == $request->getVal( 'action' ) && $request->wasPosted()
&& $user->matchEditToken( $request->getVal( 'wpEditToken' ) )
) {
$this->doSubmit();
} else {
$this->showForm( [] );
}
}
\specials\SpecialUpload.php
SpecialUpload::getDescriptionSection
protected function SpecialUpload::getDescriptionSection
内修改了上传文件时文件描述的内容,现在可以通过Message“uploaddescription”来修改默认的文件描述,并可以根据文件名称来改变文件描述。
protected function getDescriptionSection() {
$config = $this->getConfig();
if ( $this->mSessionKey ) {
$stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash( $this->getUser() );
try {
$file = $stash->getFile( $this->mSessionKey );
} catch ( Exception $e ) {
$file = null;
}
if ( $file ) {
global $wgContLang;
$mto = $file->transform( [ 'width' => 120 ] );
$this->addHeaderText(
'<div class="thumb t' . $wgContLang->alignEnd() . '">' .
Html::element( 'img', [
'src' => $mto->getUrl(),
'class' => 'thumbimage',
] ) . '</div>', 'description' );
}
}
$descriptor = [
'DestFile' => [
'type' => 'text',
'section' => 'description',
'id' => 'wpDestFile',
'label-message' => 'destfilename',
'size' => 60,
'default' => $this->mDestFile,
# @todo FIXME: Hack to work around poor handling of the 'default' option in HTMLForm
'nodata' => strval( $this->mDestFile ) !== '',
],
'UploadDescription' => [
'type' => 'textarea',
'section' => 'description',
'id' => 'wpUploadDescription',
'label-message' => $this->mForReUpload
? 'filereuploadsummary'
: 'fileuploadsummary',
'default' => $this->msg( 'uploaddescription', array( $this->mDestFile ) )->parse() . $this->mComment,
'cols' => $this->getUser()->getIntOption( 'cols' ),
'rows' => 8,
]
];
if ( $this->mTextAfterSummary ) {
$descriptor['UploadFormTextAfterSummary'] = [
'type' => 'info',
'section' => 'description',
'default' => $this->mTextAfterSummary,
'raw' => true,
];
}
$descriptor += [
'EditTools' => [
'type' => 'edittools',
'section' => 'description',
'message' => 'edittools-upload',
]
];
if ( $this->mForReUpload ) {
$descriptor['DestFile']['readonly'] = true;
} else {
$descriptor['License'] = [
'type' => 'select',
'class' => 'Licenses',
'section' => 'description',
'id' => 'wpLicense',
'label-message' => 'license',
];
}
if ( $config->get( 'UseCopyrightUpload' ) ) {
$descriptor['UploadCopyStatus'] = [
'type' => 'text',
'section' => 'description',
'id' => 'wpUploadCopyStatus',
'label-message' => 'filestatus',
];
$descriptor['UploadSource'] = [
'type' => 'text',
'section' => 'description',
'id' => 'wpUploadSource',
'label-message' => 'filesource',
];
}
return $descriptor;
}
\specials\SpecialVersion.php
SpecialVersion::getParserTags
protected function SpecialVersion::getParserTags
内增加了辅助换行的空格。
protected function getParserTags() {
global $wgParser;
$tags = $wgParser->getTags();
if ( count( $tags ) ) {
$out = Html::rawElement(
'h2',
[
'class' => 'mw-headline plainlinks',
'id' => 'mw-version-parser-extensiontags',
],
Linker::makeExternalLink(
'https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Tag_extensions',
$this->msg( 'version-parser-extensiontags' )->parse(),
false /* msg()->parse() already escapes */
)
);
array_walk( $tags, function ( &$value ) {
// Bidirectional isolation improves readability in RTL wikis
$value = Html::element(
'bdi',
// Prevent < and > from slipping to another line
[
'style' => 'white-space: nowrap;',
],
" <$value>"
);
} );
$out .= $this->listToText( $tags );
} else {
$out = '';
}
return $out;
}
\Linker.php
Linker
class Linker
内增加了自由内链的制作函数。
public static function makeInternalLink( $url, $text, $escape = true,
$linktype = '', $attribs = array(), $title = null
) {
$class = '';
if ( isset( $attribs['class'] ) && $attribs['class'] ) {
$class .= " {$attribs['class']}";
}
$attribs['class'] = $class;
if ( $escape ) {
$text = htmlspecialchars( $text );
}
$link = '';
$success = wfRunHooks( 'LinkerMakeInternalLink',
array( &$url, &$text, &$link, &$attribs, $linktype ) );
if ( !$success ) {
return $link;
}
$attribs['href'] = $url;
return Html::rawElement( 'a', $attribs, $text );
}
Linker::makeImageLink
public static function Linker::makeImageLink
内增加了自订$prefix和$postfix的功能。
public static function makeImageLink( Parser $parser, Title $title,
$file, $frameParams = [], $handlerParams = [], $time = false,
$query = "", $widthOption = null
) {
$res = null;
$dummy = new DummyLinker;
if ( !Hooks::run( 'ImageBeforeProduceHTML', [ &$dummy, &$title,
&$file, &$frameParams, &$handlerParams, &$time, &$res ] ) ) {
return $res;
}
if ( $file && !$file->allowInlineDisplay() ) {
wfDebug( __METHOD__ . ': ' . $title->getPrefixedDBkey() . " does not allow inline display\n" );
return self::link( $title );
}
// Clean up parameters
$page = isset( $handlerParams['page'] ) ? $handlerParams['page'] : false;
if ( !isset( $frameParams['align'] ) ) {
$frameParams['align'] = '';
}
if ( !isset( $frameParams['alt'] ) ) {
$frameParams['alt'] = '';
}
if ( !isset( $frameParams['title'] ) ) {
$frameParams['title'] = '';
}
if ( !isset( $frameParams['class'] ) ) {
$frameParams['class'] = '';
}
if ( isset( $frameParams['prefix'] ) ) {
$prefix = $frameParams['prefix'];
} else {
$prefix = '';
}
if ( isset( $frameParams['postfix'] ) ) {
$postfix = $frameParams['postfix'];
} else {
$postfix = '';
}
if ( 'center' == $frameParams['align'] ) {
$prefix .= '<div class="center">';
$postfix = '</div>' . $postfix;
$frameParams['align'] = 'none';
}
if ( $file && !isset( $handlerParams['width'] ) ) {
if ( isset( $handlerParams['height'] ) && $file->isVectorized() ) {
// If its a vector image, and user only specifies height
// we don't want it to be limited by its "normal" width.
global $wgSVGMaxSize;
$handlerParams['width'] = $wgSVGMaxSize;
} else {
$handlerParams['width'] = $file->getWidth( $page );
}
if ( isset( $frameParams['thumbnail'] )
|| isset( $frameParams['manualthumb'] )
|| isset( $frameParams['framed'] )
|| isset( $frameParams['frameless'] )
|| !$handlerParams['width']
) {
global $wgThumbLimits, $wgThumbUpright;
if ( $widthOption === null || !isset( $wgThumbLimits[$widthOption] ) ) {
$widthOption = User::getDefaultOption( 'thumbsize' );
}
// Reduce width for upright images when parameter 'upright' is used
if ( isset( $frameParams['upright'] ) && $frameParams['upright'] == 0 ) {
$frameParams['upright'] = $wgThumbUpright;
}
// For caching health: If width scaled down due to upright
// parameter, round to full __0 pixel to avoid the creation of a
// lot of odd thumbs.
$prefWidth = isset( $frameParams['upright'] ) ?
round( $wgThumbLimits[$widthOption] * $frameParams['upright'], -1 ) :
$wgThumbLimits[$widthOption];
// Use width which is smaller: real image width or user preference width
// Unless image is scalable vector.
if ( !isset( $handlerParams['height'] ) && ( $handlerParams['width'] <= 0 ||
$prefWidth < $handlerParams['width'] || $file->isVectorized() ) ) {
$handlerParams['width'] = $prefWidth;
}
}
}
if ( isset( $frameParams['thumbnail'] ) || isset( $frameParams['manualthumb'] )
|| isset( $frameParams['framed'] )
) {
# Create a thumbnail. Alignment depends on the writing direction of
# the page content language (right-aligned for LTR languages,
# left-aligned for RTL languages)
# If a thumbnail width has not been provided, it is set
# to the default user option as specified in Language*.php
if ( $frameParams['align'] == '' ) {
$frameParams['align'] = $parser->getTargetLanguage()->alignEnd();
}
return $prefix .
self::makeThumbLink2( $title, $file, $frameParams, $handlerParams, $time, $query ) .
$postfix;
}
if ( $file && isset( $frameParams['frameless'] ) ) {
$srcWidth = $file->getWidth( $page );
# For "frameless" option: do not present an image bigger than the
# source (for bitmap-style images). This is the same behavior as the
# "thumb" option does it already.
if ( $srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth ) {
$handlerParams['width'] = $srcWidth;
}
}
if ( $file && isset( $handlerParams['width'] ) ) {
# Create a resized image, without the additional thumbnail features
$thumb = $file->transform( $handlerParams );
} else {
$thumb = false;
}
if ( !$thumb ) {
$s = self::makeBrokenImageLinkObj( $title, $frameParams['title'], '', '', '', $time == true );
} else {
self::processResponsiveImages( $file, $thumb, $handlerParams );
$params = [
'alt' => $frameParams['alt'],
'title' => $frameParams['title'],
'valign' => isset( $frameParams['valign'] ) ? $frameParams['valign'] : false,
'img-class' => $frameParams['class'] ];
if ( isset( $frameParams['border'] ) ) {
$params['img-class'] .= ( $params['img-class'] !== '' ? ' ' : '' ) . 'thumbborder';
}
$params = self::getImageLinkMTOParams( $frameParams, $query, $parser ) + $params;
$s = $thumb->toHtml( $params );
}
if ( $frameParams['align'] != '' ) {
$s = "<div class=\"float{$frameParams['align']}\">{$s}</div>";
}
return str_replace( "\n", ' ', $prefix . $s . $postfix );
}
\PrefixSearch.php
PrefixSearch::searchWithVariants
public function PrefixSearch::searchWithVariants
内注释掉了繁简互换搜索功能,因为修改后的TitleKey扩展能更有效地处理这类型的问题。
public function searchWithVariants( $search, $limit, array $namespaces, $offset = 0 ) {
$searches = $this->search( $search, $limit, $namespaces, $offset );
// if the content language has variants, try to retrieve fallback results
/*$fallbackLimit = $limit - count( $searches );
if ( $fallbackLimit > 0 ) {
global $wgContLang;
$fallbackSearches = $wgContLang->autoConvertToAllVariants( $search );
$fallbackSearches = array_diff( array_unique( $fallbackSearches ), [ $search ] );
foreach ( $fallbackSearches as $fbs ) {
$fallbackSearchResult = $this->search( $fbs, $fallbackLimit, $namespaces );
$searches = array_merge( $searches, $fallbackSearchResult );
$fallbackLimit -= count( $fallbackSearchResult );
if ( $fallbackLimit == 0 ) {
break;
}
}
}*/
return $searches;
}
\WebStart.php
PrefixSearch::searchWithVariants
在header( 'X-Content-Type-Options: nosniff' );
后增加机器人过滤功能。
header( 'X-Content-Type-Options: nosniff' );
require_once( __DIR__ . '/deny/deny.php' );
testRestriction();
/**
* @var float Request start time as fractional seconds since epoch
* @deprecated since 1.25; use $_SERVER['REQUEST_TIME_FLOAT'] or
* WebRequest::getElapsedTime() instead.
*/
$wgRequestTime = $_SERVER['REQUEST_TIME_FLOAT'];
languages
\LanguageConverter.php
LanguageConverter::markNoConversion
public function LanguageConverter::markNoConversion
内禁用此功能。
public function markNoConversion( $text, $noParse = false ) {
# don't mark if already marked
return $text;
if ( strpos( $text, '-{' ) || strpos( $text, '}-' ) ) {
return $text;
}
$ret = "-{R|$text}-";
return $ret;
}
其他
由于以下文件太琐碎这里就不一一详述了。
- \resources\src\jquery\jquery.makeCollapsible.js
- \resources\src\jquery\jquery.suggestions.css
- \resources\src\jquery\jquery.suggestions.js
- \resources\src\mediawiki\mediawiki.searchSuggest.css
- \resources\src\mediawiki\mediawiki.searchSuggest.js
- \resources\src\mediawiki.action\mediawiki.action.edit.collapsibleFooter.js
- \resources\src\mediawiki.skinning\content.css
- \resources\src\mediawiki.skinning\elements.css
- \resources\src\mediawiki.skinning\interface.css
- \resources\src\mediawiki.widgets\mw.widgets.SearchInputWidget.js