$renderLang = $request->getVal( 'lang' );
if ( !is_null( $renderLang ) ) {
- $params['lang'] = $renderLang;
+ $handler = $this->displayImg->getHandler();
+ if ( $handler && $handler->validateParam( 'lang', $renderLang ) ) {
+ $params['lang'] = $renderLang;
+ } else {
+ $renderLang = null;
+ }
}
$width_orig = $this->displayImg->getWidth( $page );
if ( !$haveDefaultLang ) {
// Its hard to know if the content is really in the default language, or
// if its just unmarked content that could be in any language.
- $opts = Xml::option( wfMessage( 'img-lang-default' )->text(), '', $defaultLang === $curLang ) . $opts;
+ $opts = Xml::option( wfMessage( 'img-lang-default' )->text(), $defaultLang, $defaultLang === $curLang ) . $opts;
}
if ( !$haveCurrentLang && $defaultLang !== $curLang ) {
$name = Language::fetchLanguageName( $curLang, $this->getContext()->getLanguage()->getCode() );
$applyMatchingFiles = function( ResultWrapper $res, &$searchSet, &$finalFiles )
use ( $repo, $fileMatchesSearch, $flags )
{
+ global $wgContLang;
+ $info = $repo->getInfo();
foreach ( $res as $row ) {
$file = $repo->newFileFromRow( $row );
- $dbKey = $file->getTitle()->getDBkey();
- // There must have been a search for this exact DB Key
- if ( $fileMatchesSearch( $file, $searchSet[$dbKey] ) ) {
- $finalFiles[$dbKey] = ( $flags & FileRepo::NAME_AND_TIME_ONLY )
- ? array( 'title' => $dbKey, 'timestamp' => $file->getTimestamp() )
- : $file;
- unset( $searchSet[$dbKey] );
+ // There must have been a search for this DB key, but this has to handle the
+ // cases were title capitalization is different on the client and repo wikis.
+ $dbKeysLook = array( str_replace( ' ', '_', $file->getName() ) );
+ if ( !empty( $info['initialCapital'] ) ) {
+ // Search keys for "hi.png" and "Hi.png" should use the "Hi.png file"
+ $dbKeysLook[] = $wgContLang->lcfirst( $file->getName() );
+ }
+ foreach ( $dbKeysLook as $dbKey ) {
+ if ( isset( $searchSet[$dbKey])
+ && $fileMatchesSearch( $file, $searchSet[$dbKey] )
+ ) {
+ $finalFiles[$dbKey] = ( $flags & FileRepo::NAME_AND_TIME_ONLY )
+ ? array( 'title' => $dbKey, 'timestamp' => $file->getTimestamp() )
+ : $file;
+ unset( $searchSet[$dbKey] );
+ }
}
}
};
return false;
}
+ $empty = true;
+ $failed = 0;
foreach ( $this->partitionQueues as $queue ) {
try {
- if ( !$queue->doIsEmpty() ) {
- $this->cache->add( $key, 'false', self::CACHE_TTL_LONG );
-
- return false;
- }
+ $empty = $empty && $queue->doIsEmpty();
} catch ( JobQueueError $e ) {
+ ++$failed;
MWExceptionHandler::logException( $e );
}
}
+ $this->throwErrorIfAllPartitionsDown( $failed );
- $this->cache->add( $key, 'true', self::CACHE_TTL_LONG );
-
- return true;
+ $this->cache->add( $key, $empty ? 'true' : 'false', self::CACHE_TTL_LONG );
+ return !$empty;
}
protected function doGetSize() {
return $count;
}
- $count = 0;
+ $failed = 0;
foreach ( $this->partitionQueues as $queue ) {
try {
$count += $queue->$method();
} catch ( JobQueueError $e ) {
+ ++$failed;
MWExceptionHandler::logException( $e );
}
}
+ $this->throwErrorIfAllPartitionsDown( $failed );
$this->cache->set( $key, $count, self::CACHE_TTL_SHORT );
} else {
$partitionRing = $partitionRing->newWithoutLocation( $partition ); // blacklist
if ( !$partitionRing ) {
- throw new JobQueueError( "Could not insert job(s), all partitions are down." );
+ throw new JobQueueError( "Could not insert job(s), no partitions available." );
}
$jobsLeft = array_merge( $jobsLeft, $jobBatch ); // not inserted
}
} else {
$partitionRing = $partitionRing->newWithoutLocation( $partition ); // blacklist
if ( !$partitionRing ) {
- throw new JobQueueError( "Could not insert job(s), all partitions are down." );
+ throw new JobQueueError( "Could not insert job(s), no partitions available." );
}
$jobsLeft = array_merge( $jobsLeft, $jobBatch ); // not inserted
}
$partitionsTry = $this->partitionMap; // (partition => weight)
+ $failed = 0;
while ( count( $partitionsTry ) ) {
$partition = ArrayUtils::pickRandom( $partitionsTry );
if ( $partition === false ) {
try {
$job = $queue->pop();
} catch ( JobQueueError $e ) {
- $job = false;
+ ++$failed;
MWExceptionHandler::logException( $e );
+ $job = false;
}
if ( $job ) {
$job->metadata['QueuePartition'] = $partition;
unset( $partitionsTry[$partition] ); // blacklist partition
}
}
+ $this->throwErrorIfAllPartitionsDown( $failed );
$this->cache->set( $key, 'true', JobQueueDB::CACHE_TTL_LONG );
}
protected function doDelete() {
+ $failed = 0;
/** @var JobQueue $queue */
foreach ( $this->partitionQueues as $queue ) {
try {
$queue->doDelete();
} catch ( JobQueueError $e ) {
+ ++$failed;
MWExceptionHandler::logException( $e );
}
}
+ $this->throwErrorIfAllPartitionsDown( $failed );
+ return true;
}
protected function doWaitForBackups() {
+ $failed = 0;
/** @var JobQueue $queue */
foreach ( $this->partitionQueues as $queue ) {
try {
$queue->waitForBackups();
} catch ( JobQueueError $e ) {
+ ++$failed;
MWExceptionHandler::logException( $e );
}
}
+ $this->throwErrorIfAllPartitionsDown( $failed );
}
protected function doGetPeriodicTasks() {
protected function doGetSiblingQueuesWithJobs( array $types ) {
$result = array();
+ $failed = 0;
/** @var JobQueue $queue */
foreach ( $this->partitionQueues as $queue ) {
try {
break; // short-circuit
}
} catch ( JobQueueError $e ) {
+ ++$failed;
MWExceptionHandler::logException( $e );
}
}
+ $this->throwErrorIfAllPartitionsDown( $failed );
return array_values( $result );
}
protected function doGetSiblingQueueSizes( array $types ) {
$result = array();
-
+ $failed = 0;
/** @var JobQueue $queue */
foreach ( $this->partitionQueues as $queue ) {
try {
return null; // not supported on all partitions; bail
}
} catch ( JobQueueError $e ) {
+ ++$failed;
MWExceptionHandler::logException( $e );
}
}
+ $this->throwErrorIfAllPartitionsDown( $failed );
return $result;
}
+ /**
+ * Throw an error if no partitions available
+ *
+ * @param int $down The number of up partitions down
+ * @return void
+ * @throws JobQueueError
+ */
+ protected function throwErrorIfAllPartitionsDown( $down ) {
+ if ( $down >= count( $this->partitionQueues ) ) {
+ throw new JobQueueError( 'No queue partitions available.' );
+ }
+ }
+
public function setTestingPrefix( $key ) {
/** @var JobQueue $queue */
foreach ( $this->partitionQueues as $queue ) {
return ( $value > 0 );
} elseif ( $name == 'lang' ) {
// Validate $code
- if ( !Language::isValidBuiltinCode( $value ) ) {
+ if ( $value === '' || !Language::isValidBuiltinCode( $value ) ) {
wfDebug( "Invalid user language code\n" );
return false;
function getFieldNames() {
static $headers = null;
- if ( $headers == array() ) {
+ if ( $headers === null ) {
$headers = array(
'ipb_timestamp' => 'blocklist-timestamp',
'ipb_target' => 'blocklist-target',
/**
* Items per page dropdown. Essentially a crap workaround for bug 32603.
- *
- * @todo Do not release 1.19 with this.
*/
class HTMLBlockedUsersItemSelect extends HTMLSelectField {
/**
/** @var boolean whether or not to show the XML parse tree */
protected $generateXML;
+ /** @var boolean whether or not to show the raw HTML code */
+ protected $generateRawHtml;
+
/** @var boolean whether or not to remove comments in the expanded wikitext */
protected $removeComments;
}
$input = $request->getText( 'wpInput' );
$this->generateXML = $request->getBool( 'wpGenerateXml' );
+ $this->generateRawHtml = $request->getBool( 'wpGenerateRawHtml' );
if ( strlen( $input ) ) {
$this->removeComments = $request->getBool( 'wpRemoveComments', false );
}
$out->addHTML( $tmp );
- $this->showHtmlPreview( $title, $output, $out );
+
+ $rawhtml = $this->generateHtml( $title, $output );
+
+ if ( $this->generateRawHtml && strlen( $rawhtml ) > 0 ) {
+ $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) );
+ }
+
+ $this->showHtmlPreview( $title, $rawhtml, $out );
+
}
}
'generate_xml',
$this->generateXML
) . '</p>';
+ $form .= '<p>' . Xml::checkLabel(
+ $this->msg( 'expand_templates_generate_rawhtml' )->text(),
+ 'wpGenerateRawHtml',
+ 'generate_rawhtml',
+ $this->generateRawHtml
+ ) . '</p>';
$form .= '<p>' . Xml::submitButton(
$this->msg( 'expand_templates_ok' )->text(),
array( 'accesskey' => 's' )
}
/**
- * Render the supplied wiki text and append to the page as a preview
+ * Renders the supplied wikitext as html
*
* @param Title $title
* @param string $text
- * @param OutputPage $out
+ * @return string
*/
- private function showHtmlPreview( Title $title, $text, OutputPage $out ) {
+ private function generateHtml( Title $title, $text ) {
global $wgParser;
$popts = ParserOptions::newFromContext( $this->getContext() );
$popts->setTargetLanguage( $title->getPageLanguage() );
$pout = $wgParser->parse( $text, $title, $popts );
- $lang = $title->getPageViewLanguage();
+ return $pout->getText();
+ }
+
+ /**
+ * Wraps the provided html code in a div and outputs it to the page
+ *
+ * @param Title $title
+ * @param string $html
+ * @param OutputPage $out
+ */
+ private function showHtmlPreview( Title $title, $html, OutputPage $out ) {
+ $lang = $title->getPageViewLanguage();
$out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
$out->addHTML( Html::openElement( 'div', array(
'class' => 'mw-content-' . $lang->getDir(),
'dir' => $lang->getDir(),
'lang' => $lang->getHtmlCode(),
) ) );
-
- $out->addHTML( $pout->getText() );
+ $out->addHTML( $html );
$out->addHTML( Html::closeElement( 'div' ) );
}
}
'limitreport-expensivefunctioncount-value' => '$1/$2', # only translate this message to other languages if you have to change it
# ExpandTemplates
-'expandtemplates' => 'Expand templates',
-'expand_templates_intro' => 'This special page takes text and expands all templates in it recursively.
+'expandtemplates' => 'Expand templates',
+'expand_templates_intro' => 'This special page takes text and expands all templates in it recursively.
It also expands supported parser functions like
<code><nowiki>{{</nowiki>#language:…}}</code> and variables like
<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.
In fact, it expands pretty much everything in double-braces.',
-'expand_templates_title' => 'Context title, for {{FULLPAGENAME}}, etc.:',
-'expand_templates_input' => 'Input text:',
-'expand_templates_output' => 'Result',
-'expand_templates_xml_output' => 'XML output',
-'expand_templates_ok' => 'OK',
-'expand_templates_remove_comments' => 'Remove comments',
-'expand_templates_remove_nowiki' => 'Suppress <nowiki> tags in result',
-'expand_templates_generate_xml' => 'Show XML parse tree',
-'expand_templates_preview' => 'Preview',
+'expand_templates_title' => 'Context title, for {{FULLPAGENAME}}, etc.:',
+'expand_templates_input' => 'Input text:',
+'expand_templates_output' => 'Result',
+'expand_templates_xml_output' => 'XML output',
+'expand_templates_html_output' => 'Raw HTML output',
+'expand_templates_ok' => 'OK',
+'expand_templates_remove_comments' => 'Remove comments',
+'expand_templates_remove_nowiki' => 'Suppress <nowiki> tags in result',
+'expand_templates_generate_xml' => 'Show XML parse tree',
+'expand_templates_generate_rawhtml' => 'Show raw HTML',
+'expand_templates_preview' => 'Preview',
);
'expand_templates_input' => '{{Identical|Input text}}',
'expand_templates_output' => '{{Identical|Result}}',
'expand_templates_xml_output' => 'Used as HTML <code><nowiki><h2></nowiki></code> heading.',
+'expand_templates_html_output' => 'Used as HTML <code><nowiki><h2></nowiki></code> heading.',
'expand_templates_ok' => '{{Identical|OK}}',
'expand_templates_remove_comments' => 'Check box to tell [[mw:Extension:ExpandTemplates]] to not show comments in the expanded template.',
'expand_templates_remove_nowiki' => "Option on [[Special:Expandtemplates]]
test
</pre>",
'expand_templates_generate_xml' => 'Used as checkbox label.',
+'expand_templates_generate_rawhtml' => 'Used as checkbox label.',
'expand_templates_preview' => '{{Identical|Preview}}',
);
'expand_templates_input',
'expand_templates_output',
'expand_templates_xml_output',
+ 'expand_templates_html_output',
'expand_templates_ok',
'expand_templates_remove_comments',
'expand_templates_remove_nowiki',
'expand_templates_generate_xml',
+ 'expand_templates_generate_rawhtml',
'expand_templates_preview',
),
);
/**
* Run pending jobs.
*
- * Options:
- * --maxjobs <num> (default 10000)
- * --type <job_cmd>
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
/**** Special:BlockList ****/
table.mw-blocklist span.mw-usertoollinks,
-span.mw-blocklist-actions{
+span.mw-blocklist-actions {
white-space: nowrap;
font-size: 90%;
}
return $cases;
}
+ /**
+ * @dataProvider provider_testGetFileStat
+ * @covers FileBackend::streamFile
+ */
+ public function testStreamFile( $path, $content, $alreadyExists ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestStreamFile( $path, $content, $alreadyExists );
+ $this->tearDownFiles();
+ }
+
+ private function doTestStreamFile( $path, $content ) {
+ $backendName = $this->backendClass();
+
+ // Test doStreamFile() directly to avoid header madness
+ $class = new ReflectionClass( $this->backend );
+ $method = $class->getMethod( 'doStreamFile' );
+ $method->setAccessible( true );
+
+ if ( $content !== null ) {
+ $this->prepare( array( 'dir' => dirname( $path ) ) );
+ $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
+ $this->assertGoodStatus( $status,
+ "Creation of file at $path succeeded ($backendName)." );
+
+ ob_start();
+ $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
+ $data = ob_get_contents();
+ ob_end_clean();
+
+ $this->assertEquals( $content, $data, "Correct content streamed from '$path'" );
+ } else { // 404 case
+ ob_start();
+ $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
+ $data = ob_get_contents();
+ ob_end_clean();
+
+ $this->assertEquals( '', $data, "Correct content streamed from '$path' ($backendName)" );
+ }
+ }
+
+ public static function provider_testStreamFile() {
+ $cases = array();
+
+ $base = self::baseStorePath();
+ $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
+ $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", null );
+
+ return $cases;
+ }
+
/**
* @dataProvider provider_testGetFileContents
* @covers FileBackend::getFileContents