Basic integrated audio/video support, with Ogg implementation.

* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.

Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
This commit is contained in:
Tim Starling 2007-08-15 10:50:09 +00:00
parent baa6cfc46b
commit 164bb322f2
31 changed files with 824 additions and 279 deletions

View file

@ -173,6 +173,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
* (bug 10872) Fall back to sane defaults when generating protection selector
labels for custom restriction levels
* Show edit count in user preferences
* Improved support for audio/video extensions
== Bugfixes since 1.10 ==

View file

@ -118,6 +118,7 @@ function __autoload($className) {
'LogPage' => 'includes/LogPage.php',
'MacBinary' => 'includes/MacBinary.php',
'MagicWord' => 'includes/MagicWord.php',
'MagicWordArray' => 'includes/MagicWord.php',
'MathRenderer' => 'includes/Math.php',
'MediaTransformOutput' => 'includes/MediaTransformOutput.php',
'ThumbnailImage' => 'includes/MediaTransformOutput.php',
@ -385,3 +386,4 @@ function wfLoadAllExtensions() {
}

View file

@ -1916,6 +1916,28 @@ $wgExtensionFunctions = array();
*/
$wgSkinExtensionFunctions = array();
/**
* Extension messages files
* Associative array mapping extension name to the filename where messages can be found.
* The file must create a variable called $messages.
* When the messages are needed, the extension should call wfLoadMessagesFile()
*/
$wgExtensionMessagesFiles = array();
/**
* Parser output hooks.
* This is an associative array where the key is an extension-defined tag
* (typically the extension name), and the value is a PHP callback.
* These will be called as an OutputPageParserOutput hook, if the relevant
* tag has been registered with the parser output object.
*
* Registration is done with $pout->addOutputHook( $tag, $data ).
*
* The callback has the form:
* function outputHook( $outputPage, $parserOutput, $data ) { ... }
*/
$wgParserOutputHooks = array();
/**
* List of valid skin names.
* The key should be the name in all lower case, the value should be a display name.

View file

@ -2297,3 +2297,17 @@ function wfScript( $script = 'index' ) {
function wfBoolToStr( $value ) {
return $value ? 'true' : 'false';
}
/**
* Load an extension messages file
*/
function wfLoadExtensionMessages( $extensionName ) {
global $wgExtensionMessagesFiles, $wgMessageCache;
if ( !empty( $wgExtensionMessagesFiles[$extensionName] ) ) {
$wgMessageCache->loadMessagesFile( $wgExtensionMessagesFiles[$extensionName] );
// Prevent double-loading
$wgExtensionMessagesFiles[$extensionName] = false;
}
}

View file

@ -16,6 +16,7 @@ if( !defined( 'MEDIAWIKI' ) )
class ImagePage extends Article {
/* private */ var $img; // Image object this page is shown for
/* private */ var $repo;
var $mExtraDescription = false;
function __construct( $title ) {
@ -24,6 +25,7 @@ class ImagePage extends Article {
if ( !$this->img ) {
$this->img = wfLocalFile( $this->mTitle );
}
$this->repo = $this->img->repo;
}
/**
@ -46,6 +48,7 @@ class ImagePage extends Article {
return Article::view();
if ($wgShowEXIF && $this->img->exists()) {
// FIXME: bad interface, see note on MediaHandler::formatMetadata().
$formattedMetadata = $this->img->formatMetadata();
$showmeta = $formattedMetadata !== false;
} else {
@ -115,6 +118,8 @@ class ImagePage extends Article {
/**
* Make a table with metadata to be shown in the output page.
*
* FIXME: bad interface, see note on MediaHandler::formatMetadata().
*
* @access private
*
* @param array $exif The array containing the EXIF data
@ -188,14 +193,15 @@ class ImagePage extends Article {
$mime = $this->img->getMimeType();
$showLink = false;
$linkAttribs = array( 'href' => $full_url );
$longDesc = $this->img->getLongDesc();
wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this , &$wgOut ) ) ;
wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this , &$wgOut ) ) ;
if ( $this->img->allowInlineDisplay() and $width and $height) {
if ( $this->img->allowInlineDisplay() ) {
# image
# "Download high res version" link below the image
$msgsize = wfMsgHtml('file-info-size', $width_orig, $height_orig, $sk->formatSize( $this->img->getSize() ), $mime );
#$msgsize = wfMsgHtml('file-info-size', $width_orig, $height_orig, $sk->formatSize( $this->img->getSize() ), $mime );
# We'll show a thumbnail of this image
if ( $width > $maxWidth || $height > $maxHeight ) {
# Calculate the thumbnail size.
@ -229,7 +235,7 @@ class ImagePage extends Article {
} else {
$anchorclose .=
$msgsmall .
'<br />' . Xml::tags( 'a', $linkAttribs, $msgbig ) . ' ' . $msgsize;
'<br />' . Xml::tags( 'a', $linkAttribs, $msgbig ) . ' ' . $longDesc;
}
if ( $this->img->isMultipage() ) {
@ -301,26 +307,17 @@ class ImagePage extends Article {
if ($showLink) {
// Workaround for incorrect MIME type on SVGs uploaded in previous versions
if ($mime == 'image/svg') $mime = 'image/svg+xml';
$filename = wfEscapeWikiText( $this->img->getName() );
$info = wfMsg( 'file-info', $sk->formatSize( $this->img->getSize() ), $mime );
$infores = '';
// Check for MIME type. Other types may have more information in the future.
if (substr($mime,0,9) == 'image/svg' ) {
$infores = wfMsg('file-svg', $width_orig, $height_orig ) . '<br />';
}
global $wgContLang;
$dirmark = $wgContLang->getDirMark();
if (!$this->img->isSafeFile()) {
$warning = wfMsg( 'mediawarning' );
$wgOut->addWikiText( <<<EOT
<div class="fullMedia">$infores
<div class="fullMedia">
<span class="dangerousLink">[[Media:$filename|$filename]]</span>$dirmark
<span class="fileInfo"> $info</span>
<span class="fileInfo"> $longDesc</span>
</div>
<div class="mediaWarning">$warning</div>
@ -328,8 +325,8 @@ EOT
);
} else {
$wgOut->addWikiText( <<<EOT
<div class="fullMedia">$infores
[[Media:$filename|$filename]]$dirmark <span class="fileInfo"> $info</span>
<div class="fullMedia">
[[Media:$filename|$filename]]$dirmark <span class="fileInfo"> $longDesc</span>
</div>
EOT
);
@ -421,18 +418,22 @@ EOT
if ( $line ) {
$list = new ImageHistoryList( $sk, $this->img );
$file = $this->repo->newFileFromRow( $line );
$dims = $file->getDimensionsString();
$s = $list->beginImageHistoryList() .
$list->imageHistoryLine( true, wfTimestamp(TS_MW, $line->img_timestamp),
$this->mTitle->getDBkey(), $line->img_user,
$line->img_user_text, $line->img_size, $line->img_description,
$line->img_width, $line->img_height
$dims
);
while ( $line = $this->img->nextHistoryLine() ) {
$s .= $list->imageHistoryLine( false, $line->img_timestamp,
$line->oi_archive_name, $line->img_user,
$line->img_user_text, $line->img_size, $line->img_description,
$line->img_width, $line->img_height
$file = $this->repo->newFileFromRow( $line );
$dims = $file->getDimensionsString();
$s .= $list->imageHistoryLine( false, $line->oi_timestamp,
$line->oi_archive_name, $line->oi_user,
$line->oi_user_text, $line->oi_size, $line->oi_description,
$dims
);
}
$s .= $list->endImageHistoryList();
@ -655,7 +656,7 @@ EOT
*/
class ImageHistoryList {
protected $img, $skin, $title;
protected $img, $skin, $title, $repo;
public function __construct( $skin, $img ) {
$this->skin = $skin;
@ -682,7 +683,7 @@ class ImageHistoryList {
return "</table>\n";
}
public function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description, $width, $height ) {
public function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description, $dims ) {
global $wgUser, $wgLang, $wgTitle, $wgContLang;
$local = $this->img->isLocal();
$row = '';
@ -740,10 +741,7 @@ class ImageHistoryList {
$row .= '</td>';
// Image dimensions
// FIXME: It would be nice to show the duration (sound files) or
// width/height/duration (video files) here, but this needs some
// additional media handler work
$row .= '<td>' . wfMsgHtml( 'widthheight', $width, $height ) . '</td>';
$row .= '<td>' . htmlspecialchars( $dims ) . '</td>';
// File size
$row .= '<td class="mw-imagepage-filesize">' . $this->skin->formatSize( $size ) . '</td>';
@ -754,4 +752,4 @@ class ImageHistoryList {
return "<tr>{$row}</tr>\n";
}
}
}

View file

@ -433,42 +433,96 @@ class Linker {
return $s;
}
/** Creates the HTML source for images
* @param object $nt
* @param string $label label text
* @param string $alt alt text
* @param string $align horizontal alignment: none, left, center, right)
* @param array $params some format keywords: width, height, page, upright, upright_factor, frameless, border
* @param boolean $framed shows image in original size in a frame
* @param boolean $thumb shows image as thumbnail in a frame
* @param string $manual_thumb image name for the manual thumbnail
* @param string $valign vertical alignment: baseline, sub, super, top, text-top, middle, bottom, text-bottom
* @return string
*/
function makeImageLinkObj( $nt, $label, $alt, $align = '', $params = array(), $framed = false,
$thumb = false, $manual_thumb = '', $valign = '', $time = false )
/**
* Creates the HTML source for images
* @deprecated use makeImageLink2
*
* @param object $title
* @param string $label label text
* @param string $alt alt text
* @param string $align horizontal alignment: none, left, center, right)
* @param array $handlerParams Parameters to be passed to the media handler
* @param boolean $framed shows image in original size in a frame
* @param boolean $thumb shows image as thumbnail in a frame
* @param string $manualthumb image name for the manual thumbnail
* @param string $valign vertical alignment: baseline, sub, super, top, text-top, middle, bottom, text-bottom
* @return string
*/
function makeImageLinkObj( $title, $label, $alt, $align = '', $handlerParams = array(), $framed = false,
$thumb = false, $manualthumb = '', $valign = '', $time = false )
{
$frameParams = array( 'alt' => $alt, 'caption' => $label );
if ( $align ) {
$frameParams['align'] = $align;
}
if ( $framed ) {
$frameParams['framed'] = true;
}
if ( $thumb ) {
$frameParams['thumb'] = true;
}
if ( $manualthumb ) {
$frameParams['manualthumb'] = $manualthumb;
}
if ( $valign ) {
$frameParams['valign'] = $valign;
}
$file = wfFindFile( $title, $time );
return $this->makeImageLink2( $title, $file, $label, $alt, $frameParams, $handlerParams );
}
/**
* Make an image link
* @param Title $title Title object
* @param File $file File object, or false if it doesn't exist
*
* @param array $frameParams Associative array of parameters external to the media handler.
* Boolean parameters are indicated by presence or absence, the value is arbitrary and
* will often be false.
* thumbnail If present, downscale and frame
* manualthumb Image name to use as a thumbnail, instead of automatic scaling
* framed Shows image in original size in a frame
* frameless Downscale but don't frame
* upright If present, tweak default sizes for portrait orientation
* upright_factor Fudge factor for "upright" tweak (default 0.75)
* border If present, show a border around the image
* align Horizontal alignment (left, right, center, none)
* valign Vertical alignment (baseline, sub, super, top, text-top, middle,
* bottom, text-bottom)
* alt Alternate text for image (i.e. alt attribute). Plain text.
* caption HTML for image caption.
*
* @param array $handlerParams Associative array of media handler parameters, to be passed
* to transform(). Typical keys are "width" and "page".
*/
function makeImageLink2( Title $title, $file, $frameParams = array(), $handlerParams = array() ) {
global $wgContLang, $wgUser, $wgThumbLimits, $wgThumbUpright;
$img = wfFindFile( $nt, $time );
if ( $img && !$img->allowInlineDisplay() ) {
wfDebug( __METHOD__.': '.$nt->getPrefixedDBkey()." does not allow inline display\n" );
return $this->makeKnownLinkObj( $nt );
if ( $file && !$file->allowInlineDisplay() ) {
wfDebug( __METHOD__.': '.$title->getPrefixedDBkey()." does not allow inline display\n" );
return $this->makeKnownLinkObj( $title );
}
$error = $prefix = $postfix = '';
$page = isset( $params['page'] ) ? $params['page'] : false;
// Shortcuts
$fp =& $frameParams;
$hp =& $handlerParams;
if ( 'center' == $align )
// Clean up parameters
$page = isset( $hp['page'] ) ? $hp['page'] : false;
if ( !isset( $fp['align'] ) ) $fp['align'] = '';
if ( !isset( $fp['alt'] ) ) $fp['alt'] = '';
$prefix = $postfix = '';
if ( 'center' == $fp['align'] )
{
$prefix = '<div class="center">';
$postfix = '</div>';
$align = 'none';
$fp['align'] = 'none';
}
if ( $img && !isset( $params['width'] ) ) {
$params['width'] = $img->getWidth( $page );
if( $thumb || $framed || isset( $params['frameless'] ) ) {
if ( $file && !isset( $hp['width'] ) ) {
$hp['width'] = $file->getWidth( $page );
if( isset( $fp['thumbnail'] ) || isset( $fp['framed'] ) || isset( $fp['frameless'] ) || !$hp['width'] ) {
$wopt = $wgUser->getOption( 'thumbsize' );
if( !isset( $wgThumbLimits[$wopt] ) ) {
@ -476,16 +530,21 @@ class Linker {
}
// Reduce width for upright images when parameter 'upright' is used
if ( !isset( $params['upright_factor'] ) || $params['upright_factor'] == 0 ) {
$params['upright_factor'] = $wgThumbUpright;
if ( !isset( $fp['upright_factor'] ) || $fp['upright_factor'] == 0 ) {
$fp['upright_factor'] = $wgThumbUpright;
}
// Use width which is smaller: real image width or user preference width
// 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
$params['width'] = min( $params['width'], isset( $params['upright'] ) ? round( $wgThumbLimits[$wopt] * $params['upright_factor'], -1 ) : $wgThumbLimits[$wopt] );
$prefWidth = isset( $fp['upright'] ) ?
round( $wgThumbLimits[$wopt] * $fp['upright_factor'], -1 ) :
$wgThumbLimits[$wopt];
if ( $hp['width'] <= 0 || $prefWidth < $hp['width'] ) {
$hp['width'] = $prefWidth;
}
}
}
if ( $thumb || $framed ) {
if ( isset( $fp['thumbnail'] ) || isset( $fp['framed'] ) ) {
# Create a thumbnail. Alignment depends on language
# writing direction, # right aligned for left-to-right-
@ -494,15 +553,15 @@ class Linker {
#
# If thumbnail width has not been provided, it is set
# to the default user option as specified in Language*.php
if ( $align == '' ) {
$align = $wgContLang->isRTL() ? 'left' : 'right';
if ( $fp['align'] == '' ) {
$fp['align'] = $wgContLang->isRTL() ? 'left' : 'right';
}
return $prefix.$this->makeThumbLinkObj( $nt, $img, $label, $alt, $align, $params, $framed, $manual_thumb ).$postfix;
return $prefix.$this->makeThumbLink2( $title, $file, $fp, $hp ).$postfix;
}
if ( $img && $params['width'] ) {
if ( $file && $hp['width'] ) {
# Create a resized image, without the additional thumbnail features
$thumb = $img->transform( $params );
$thumb = $file->transform( $hp );
} else {
$thumb = false;
}
@ -512,58 +571,76 @@ class Linker {
} else {
$query = '';
}
$u = $nt->getLocalURL( $query );
$url = $title->getLocalURL( $query );
$imgAttribs = array(
'alt' => $alt,
'longdesc' => $u
'alt' => $fp['alt'],
'longdesc' => $url
);
if ( $valign ) {
$imgAttribs['style'] = "vertical-align: $valign";
if ( isset( $fp['valign'] ) ) {
$imgAttribs['style'] = "vertical-align: {$fp['valign']}";
}
if ( isset( $params['border'] ) ) {
if ( isset( $fp['border'] ) ) {
$imgAttribs['class'] = "thumbborder";
}
$linkAttribs = array(
'href' => $u,
'href' => $url,
'class' => 'image',
'title' => $alt
'title' => $fp['alt']
);
if ( !$thumb ) {
$s = $this->makeBrokenImageLinkObj( $nt );
$s = $this->makeBrokenImageLinkObj( $title );
} else {
$s = $thumb->toHtml( $imgAttribs, $linkAttribs );
}
if ( '' != $align ) {
$s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
if ( '' != $fp['align'] ) {
$s = "<div class=\"float{$fp['align']}\"><span>{$s}</span></div>";
}
return str_replace("\n", ' ',$prefix.$s.$postfix);
}
/**
* Make HTML for a thumbnail including image, border and caption
* @param Title $nt
* @param Image $img Image object or false if it doesn't exist
* @param Title $title
* @param File $file File object or false if it doesn't exist
*/
function makeThumbLinkObj( Title $nt, $img, $label = '', $alt, $align = 'right', $params = array(), $framed=false , $manual_thumb = "" ) {
function makeThumbLinkObj( Title $title, $file, $label = '', $alt, $align = 'right', $params = array(), $framed=false , $manualthumb = "" ) {
$frameParams = array(
'alt' => $alt,
'caption' => $label,
'align' => $align
);
if ( $framed ) $frameParams['framed'] = true;
if ( $manualthumb ) $frameParams['manualthumb'] = $manualthumb;
return $this->makeThumbLink2( $title, $file, $frameParams, $handlerParams );
}
function makeThumbLink2( Title $title, $file, $frameParams = array(), $handlerParams = array() ) {
global $wgStylePath, $wgContLang;
$exists = $img && $img->exists();
$exists = $file && $file->exists();
$page = isset( $params['page'] ) ? $params['page'] : false;
# Shortcuts
$fp =& $frameParams;
$hp =& $handlerParams;
if ( empty( $params['width'] ) ) {
$page = isset( $hp['page'] ) ? $hp['page'] : false;
if ( !isset( $fp['align'] ) ) $fp['align'] = 'right';
if ( !isset( $fp['alt'] ) ) $fp['alt'] = '';
if ( !isset( $fp['caption'] ) ) $fp['caption'] = '';
if ( empty( $hp['width'] ) ) {
// Reduce width for upright images when parameter 'upright' is used
$params['width'] = isset( $params['upright'] ) ? 130 : 180;
$hp['width'] = isset( $fp['upright'] ) ? 130 : 180;
}
$thumb = false;
if ( !$exists ) {
$outerWidth = $params['width'] + 2;
$outerWidth = $hp['width'] + 2;
} else {
if ( $manual_thumb != '' ) {
if ( isset( $fp['manualthumb'] ) ) {
# Use manually specified thumbnail
$manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb );
$manual_title = Title::makeTitleSafe( NS_IMAGE, $fp['manualthumb'] );
if( $manual_title ) {
$manual_img = wfFindFile( $manual_title );
if ( $manual_img ) {
@ -572,63 +649,63 @@ class Linker {
$exists = false;
}
}
} elseif ( $framed ) {
} elseif ( isset( $fp['framed'] ) ) {
// Use image dimensions, don't scale
$thumb = $img->getUnscaledThumb( $page );
$thumb = $file->getUnscaledThumb( $page );
} else {
# Do not present an image bigger than the source, for bitmap-style images
# This is a hack to maintain compatibility with arbitrary pre-1.10 behaviour
$srcWidth = $img->getWidth( $page );
if ( $srcWidth && !$img->mustRender() && $params['width'] > $srcWidth ) {
$params['width'] = $srcWidth;
$srcWidth = $file->getWidth( $page );
if ( $srcWidth && !$file->mustRender() && $hp['width'] > $srcWidth ) {
$hp['width'] = $srcWidth;
}
$thumb = $img->transform( $params );
$thumb = $file->transform( $hp );
}
if ( $thumb ) {
$outerWidth = $thumb->getWidth() + 2;
} else {
$outerWidth = $params['width'] + 2;
$outerWidth = $hp['width'] + 2;
}
}
$query = $page ? 'page=' . urlencode( $page ) : '';
$u = $nt->getLocalURL( $query );
$url = $title->getLocalURL( $query );
$more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
$magnifyalign = $wgContLang->isRTL() ? 'left' : 'right';
$textalign = $wgContLang->isRTL() ? ' style="text-align:right"' : '';
$s = "<div class=\"thumb t{$align}\"><div class=\"thumbinner\" style=\"width:{$outerWidth}px;\">";
$s = "<div class=\"thumb t{$fp['align']}\"><div class=\"thumbinner\" style=\"width:{$outerWidth}px;\">";
if( !$exists ) {
$s .= $this->makeBrokenImageLinkObj( $nt );
$s .= $this->makeBrokenImageLinkObj( $title );
$zoomicon = '';
} elseif ( !$thumb ) {
$s .= htmlspecialchars( wfMsg( 'thumbnail_error', '' ) );
$zoomicon = '';
} else {
$imgAttribs = array(
'alt' => $alt,
'longdesc' => $u,
'alt' => $fp['alt'],
'longdesc' => $url,
'class' => 'thumbimage'
);
$linkAttribs = array(
'href' => $u,
'href' => $url,
'class' => 'internal',
'title' => $alt
'title' => $fp['alt']
);
$s .= $thumb->toHtml( $imgAttribs, $linkAttribs );
if ( $framed ) {
if ( isset( $fp['framed'] ) ) {
$zoomicon="";
} else {
$zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
'<a href="'.$u.'" class="internal" title="'.$more.'">'.
'<a href="'.$url.'" class="internal" title="'.$more.'">'.
'<img src="'.$wgStylePath.'/common/images/magnify-clip.png" ' .
'width="15" height="11" alt="" /></a></div>';
}
}
$s .= ' <div class="thumbcaption"'.$textalign.'>'.$zoomicon.$label."</div></div></div>";
$s .= ' <div class="thumbcaption"'.$textalign.'>'.$zoomicon.$fp['caption']."</div></div></div>";
return str_replace("\n", ' ', $s);
}
@ -1269,28 +1346,7 @@ class Linker {
*/
public function formatSize( $size ) {
global $wgLang;
// For small sizes no decimal places necessary
$round = 0;
if( $size > 1024 ) {
$size = $size / 1024;
if( $size > 1024 ) {
$size = $size / 1024;
// For MB and bigger two decimal places are smarter
$round = 2;
if( $size > 1024 ) {
$size = $size / 1024;
$msg = 'size-gigabytes';
} else {
$msg = 'size-megabytes';
}
} else {
$msg = 'size-kilobytes';
}
} else {
$msg = 'size-bytes';
}
$size = round( $size, $round );
return wfMsgHtml( $msg, $wgLang->formatNum( $size ) );
return htmlspecialchars( $wgLang->formatSize( $size ) );
}
/**
@ -1346,3 +1402,4 @@ class Linker {

View file

@ -386,6 +386,181 @@ class MagicWord {
function isCaseSensitive() {
return $this->mCaseSensitive;
}
function getId() {
return $this->mId;
}
}
/**
* Class for handling an array of magic words
*/
class MagicWordArray {
var $names = array();
var $hash;
var $baseRegex, $regex;
function __construct( $names = array() ) {
$this->names = $names;
}
/**
* Add a magic word by name
*/
public function add( $name ) {
global $wgContLang;
$this->names[] = $name;
$this->hash = $this->baseRegex = $this->regex = null;
}
/**
* Add a number of magic words by name
*/
public function addArray( $names ) {
$this->names = array_merge( $this->names, array_values( $names ) );
$this->hash = $this->baseRegex = $this->regex = null;
}
/**
* Get a 2-d hashtable for this array
*/
function getHash() {
if ( is_null( $this->hash ) ) {
global $wgContLang;
$this->hash = array( 0 => array(), 1 => array() );
foreach ( $this->names as $name ) {
$magic = MagicWord::get( $name );
$case = intval( $magic->isCaseSensitive() );
foreach ( $magic->getSynonyms() as $syn ) {
if ( !$case ) {
$syn = $wgContLang->lc( $syn );
}
$this->hash[$case][$syn] = $name;
}
}
}
return $this->hash;
}
/**
* Get the base regex
*/
function getBaseRegex() {
if ( is_null( $this->baseRegex ) ) {
$this->baseRegex = array( 0 => '', 1 => '' );
foreach ( $this->names as $name ) {
$magic = MagicWord::get( $name );
$case = intval( $magic->isCaseSensitive() );
foreach ( $magic->getSynonyms() as $i => $syn ) {
$group = "(?P<{$i}_{$name}>" . preg_quote( $syn, '/' ) . ')';
if ( $this->baseRegex[$case] === '' ) {
$this->baseRegex[$case] = $group;
} else {
$this->baseRegex[$case] .= '|' . $group;
}
}
}
}
return $this->baseRegex;
}
/**
* Get an unanchored regex
*/
function getRegex() {
if ( is_null( $this->regex ) ) {
$base = $this->getBaseRegex();
$this->regex = array( '', '' );
if ( $this->baseRegex[0] !== '' ) {
$this->regex[0] = "/{$base[0]}/iuS";
}
if ( $this->baseRegex[1] !== '' ) {
$this->regex[1] = "/{$base[1]}/S";
}
}
return $this->regex;
}
/**
* Get a regex for matching variables
*/
function getVariableRegex() {
return str_replace( "\\$1", "(.*?)", $this->getRegex() );
}
/**
* Get an anchored regex for matching variables
*/
function getVariableStartToEndRegex() {
$base = $this->getBaseRegex();
$newRegex = array( '', '' );
if ( $base[0] !== '' ) {
$newRegex[0] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[0]})$/iuS" );
}
if ( $base[1] !== '' ) {
$newRegex[1] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[1]})$/S" );
}
return $newRegex;
}
/**
* Parse a match array from preg_match
*/
function parseMatch( $m ) {
reset( $m );
while ( list( $key, $value ) = each( $m ) ) {
if ( $key === 0 || $value === '' ) {
continue;
}
$parts = explode( '_', $key, 2 );
if ( count( $parts ) != 2 ) {
// This shouldn't happen
// continue;
throw new MWException( __METHOD__ . ': bad parameter name' );
}
list( $synIndex, $magicName ) = $parts;
$paramValue = next( $m );
return array( $magicName, $paramValue );
}
// This shouldn't happen either
throw new MWException( __METHOD__.': parameter not found' );
return array( false, false );
}
/**
* Match some text, with parameter capture
* Returns an array with the magic word name in the first element and the
* parameter in the second element.
* Both elements are false if there was no match.
*/
public function matchVariableStartToEnd( $text ) {
global $wgContLang;
$regexes = $this->getVariableStartToEndRegex();
foreach ( $regexes as $case => $regex ) {
if ( $regex !== '' ) {
$m = false;
if ( preg_match( $regex, $text, $m ) ) {
return $this->parseMatch( $m );
}
}
}
return array( false, false );
}
/**
* Match some text, without parameter capture
* Returns the magic word name, or false if there was no capture
*/
public function matchStartToEnd( $text ) {
$hash = $this->getHash();
if ( isset( $hash[1][$text] ) ) {
return $hash[1][$text];
}
global $wgContLang;
$lc = $wgContLang->lc( $text );
if ( isset( $hash[0][$lc] ) ) {
return $hash[0][$lc];
}
return false;
}
}

View file

@ -23,6 +23,7 @@ class MessageCache {
var $mExtensionMessages = array();
var $mInitialised = false;
var $mDeferred = true;
var $mAllMessagesLoaded;
function __construct( &$memCached, $useDB, $expiry, $memcPrefix) {
wfProfileIn( __METHOD__ );
@ -669,12 +670,33 @@ class MessageCache {
}
}
static function loadAllMessages() {
function loadAllMessages() {
global $wgExtensionMessagesFiles;
if ( $this->mAllMessagesLoaded ) {
return;
}
$this->mAllMessagesLoaded = true;
# Some extensions will load their messages when you load their class file
wfLoadAllExtensions();
# Others will respond to this hook
wfRunHooks( 'LoadAllMessages' );
# Some register their messages in $wgExtensionMessagesFiles
foreach ( $wgExtensionMessagesFiles as $name => $file ) {
if ( $file ) {
$this->loadMessagesFile( $file );
$wgExtensionMessagesFiles[$name] = false;
}
}
# Still others will respond to neither, they are EVIL. We sometimes need to know!
}
/**
* Load messages from a given file
*/
function loadMessagesFile( $filename ) {
require( $filename );
$this->addMessagesByLang( $messages );
}
}

View file

@ -374,7 +374,9 @@ class MimeMagic {
$mime = $this->detectMimeType( $file, $ext );
// Read a chunk of the file
wfSuppressWarnings();
$f = fopen( $file, "rt" );
wfRestoreWarnings();
if( !$f ) return "unknown/unknown";
$head = fread( $f, 1024 );
fclose( $f );

View file

@ -109,6 +109,10 @@ class OutputPage {
$this->mHeadItems[$name] = $value;
}
function hasHeadItem( $name ) {
return isset( $this->mHeadItems[$name] );
}
function setETag($tag) { $this->mETag = $tag; }
function setArticleBodyOnly($only) { $this->mArticleBodyOnly = $only; }
function getArticleBodyOnly($only) { return $this->mArticleBodyOnly; }
@ -377,7 +381,16 @@ class OutputPage {
# Display title
if( ( $dt = $parserOutput->getDisplayTitle() ) !== false )
$this->setPageTitle( $dt );
# Hooks registered in the object
global $wgParserOutputHooks;
foreach ( $parserOutput->getOutputHooks() as $hookInfo ) {
list( $hookName, $data ) = $hookInfo;
if ( isset( $wgParserOutputHooks[$hookName] ) ) {
call_user_func( $wgParserOutputHooks[$hookName], $this, $parserOutput, $data );
}
}
wfRunHooks( 'OutputPageParserOutput', array( &$this, $parserOutput ) );
}

View file

@ -97,7 +97,8 @@ class Parser
* @private
*/
# Persistent:
var $mTagHooks, $mTransparentTagHooks, $mFunctionHooks, $mFunctionSynonyms, $mVariables;
var $mTagHooks, $mTransparentTagHooks, $mFunctionHooks, $mFunctionSynonyms, $mVariables,
$mImageParams, $mImageParamsMagicArray;
# Cleared with clearState():
var $mOutput, $mAutonumber, $mDTopen, $mStripState;
@ -4473,10 +4474,50 @@ class Parser
return $ig->toHTML();
}
function getImageParams( $handler ) {
if ( $handler ) {
$handlerClass = get_class( $handler );
} else {
$handlerClass = '';
}
if ( !isset( $this->mImageParams[$handlerClass] ) ) {
// Initialise static lists
static $internalParamNames = array(
'horizAlign' => array( 'left', 'right', 'center', 'none' ),
'vertAlign' => array( 'baseline', 'sub', 'super', 'top', 'text-top', 'middle',
'bottom', 'text-bottom' ),
'frame' => array( 'thumbnail', 'manualthumb', 'framed', 'frameless',
'upright', 'border' ),
);
static $internalParamMap;
if ( !$internalParamMap ) {
$internalParamMap = array();
foreach ( $internalParamNames as $type => $names ) {
foreach ( $names as $name ) {
$magicName = str_replace( '-', '_', "img_$name" );
$internalParamMap[$magicName] = array( $type, $name );
}
}
}
// Add handler params
$paramMap = $internalParamMap;
if ( $handler ) {
$handlerParamMap = $handler->getParamMap();
foreach ( $handlerParamMap as $magic => $paramName ) {
$paramMap[$magic] = array( 'handler', $paramName );
}
}
$this->mImageParams[$handlerClass] = $paramMap;
$this->mImageParamsMagicArray[$handlerClass] = new MagicWordArray( array_keys( $paramMap ) );
}
return array( $this->mImageParams[$handlerClass], $this->mImageParamsMagicArray[$handlerClass] );
}
/**
* Parse image options text and use it to make an image
*/
function makeImage( $nt, $options ) {
function makeImage( $title, $options ) {
# @TODO: let the MediaHandler specify its transform parameters
#
# Check if the options text is of the form "options|alt text"
@ -4500,77 +4541,55 @@ class Parser
# * middle
# * bottom
# * text-bottom
$part = array_map( 'trim', explode( '|', $options) );
$mwAlign = array();
$alignments = array( 'left', 'right', 'center', 'none', 'baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom' );
foreach ( $alignments as $alignment ) {
$mwAlign[$alignment] =& MagicWord::get( 'img_'.$alignment );
}
$mwThumb =& MagicWord::get( 'img_thumbnail' );
$mwManualThumb =& MagicWord::get( 'img_manualthumb' );
$mwWidth =& MagicWord::get( 'img_width' );
$mwFramed =& MagicWord::get( 'img_framed' );
$mwFrameless =& MagicWord::get( 'img_frameless' );
$mwUpright =& MagicWord::get( 'img_upright' );
$mwBorder =& MagicWord::get( 'img_border' );
$mwPage =& MagicWord::get( 'img_page' );
$caption = '';
$params = array();
$framed = $thumb = false;
$manual_thumb = '' ;
$align = $valign = '';
$parts = array_map( 'trim', explode( '|', $options) );
$sk = $this->mOptions->getSkin();
foreach( $part as $val ) {
if ( !is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
$thumb=true;
} elseif ( !is_null( $match = $mwUpright->matchVariableStartToEnd( $val ) ) ) {
$params['upright'] = true;
$params['upright_factor'] = floatval( $match );
} elseif ( !is_null( $match = $mwFrameless->matchVariableStartToEnd( $val ) ) ) {
$params['frameless'] = true;
} elseif ( !is_null( $mwBorder->matchVariableStartToEnd( $val ) ) ) {
$params['border'] = true;
} elseif ( ! is_null( $match = $mwManualThumb->matchVariableStartToEnd($val) ) ) {
# use manually specified thumbnail
$thumb=true;
$manual_thumb = $match;
# Give extensions a chance to select the file revision for us
$skip = $time = false;
wfRunHooks( 'BeforeParserMakeImageLinkObj', array( &$this, &$title, &$skip, &$time ) );
if ( $skip ) {
return $sk->makeLinkObj( $title );
}
# Get parameter map
$file = wfFindFile( $title, $time );
$handler = $file ? $file->getHandler() : false;
list( $paramMap, $mwArray ) = $this->getImageParams( $handler );
# Process the input parameters
$caption = '';
$params = array( 'frame' => array(), 'handler' => array(),
'horizAlign' => array(), 'vertAlign' => array() );
foreach( $parts as $part ) {
list( $magicName, $value ) = $mwArray->matchVariableStartToEnd( $part );
if ( isset( $paramMap[$magicName] ) ) {
list( $type, $paramName ) = $paramMap[$magicName];
$params[$type][$paramName] = $value;
} else {
foreach( $alignments as $alignment ) {
if ( ! is_null( $mwAlign[$alignment]->matchVariableStartToEnd($val) ) ) {
switch ( $alignment ) {
case 'left': case 'right': case 'center': case 'none':
$align = $alignment; break;
default:
$valign = $alignment;
}
continue 2;
}
}
if ( ! is_null( $match = $mwPage->matchVariableStartToEnd($val) ) ) {
# Select a page in a multipage document
$params['page'] = $match;
} elseif ( !isset( $params['width'] ) && ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
wfDebug( "img_width match: $match\n" );
# $match is the image width in pixels
$m = array();
if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
$params['width'] = intval( $m[1] );
$params['height'] = intval( $m[2] );
} else {
$params['width'] = intval($match);
}
} elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
$framed=true;
} else {
$caption = $val;
$caption = $part;
}
}
# Process alignment parameters
if ( $params['horizAlign'] ) {
$params['frame']['align'] = key( $params['horizAlign'] );
}
if ( $params['vertAlign'] ) {
$params['frame']['valign'] = key( $params['vertAlign'] );
}
# Validate the handler parameters
if ( $handler ) {
foreach ( $params['handler'] as $name => $value ) {
if ( !$handler->validateParam( $name, $value ) ) {
unset( $params['handler'][$name] );
}
}
}
# Strip bad stuff out of the alt text
$alt = $this->replaceLinkHoldersText( $caption );
@ -4580,18 +4599,18 @@ class Parser
$alt = $this->mStripState->unstripBoth( $alt );
$alt = Sanitizer::stripAllTags( $alt );
# Give extensions a chance to select the file revision for us
$skip = $time = false;
wfRunHooks( 'BeforeParserMakeImageLinkObj', array( &$this, &$nt, &$skip, &$time ) );
$params['frame']['alt'] = $alt;
$params['frame']['caption'] = $caption;
# Linker does the rest
if( $skip ) {
$link = $sk->makeLinkObj( $nt );
} else {
$link = $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $params, $framed, $thumb, $manual_thumb, $valign, $time );
$ret = $sk->makeImageLink2( $title, $file, $params['frame'], $params['handler'] );
# Give the handler a chance to modify the parser object
if ( $handler ) {
$handler->parserTransformHook( $this, $file );
}
return $link;
return $ret;
}
/**

View file

@ -19,7 +19,8 @@ class ParserOutput
$mExternalLinks, # External link URLs, in the key only
$mNewSection, # Show a new section link?
$mNoGallery, # No gallery on category page? (__NOGALLERY__)
$mHeadItems; # Items to put in the <head> section
$mHeadItems, # Items to put in the <head> section
$mOutputHooks; # Hook tags as per $wgParserOutputHooks
/**
* Overridden title for display
@ -44,6 +45,7 @@ class ParserOutput
$this->mNoGallery = false;
$this->mHeadItems = array();
$this->mTemplateIds = array();
$this->mOutputHooks = array();
}
function getText() { return $this->mText; }
@ -58,6 +60,7 @@ class ParserOutput
function &getExternalLinks() { return $this->mExternalLinks; }
function getNoGallery() { return $this->mNoGallery; }
function getSubtitle() { return $this->mSubtitle; }
function getOutputHooks() { return $this->mOutputHooks; }
function containsOldMagic() { return $this->mContainsOldMagic; }
function setText( $text ) { return wfSetVar( $this->mText, $text ); }
@ -71,6 +74,10 @@ class ParserOutput
function addLanguageLink( $t ) { $this->mLanguageLinks[] = $t; }
function addExternalLink( $url ) { $this->mExternalLinks[$url] = 1; }
function addOutputHook( $hook, $data = false ) {
$this->mOutputHooks[] = array( $hook, $data );
}
function setNewSection( $value ) {
$this->mNewSection = (bool)$value;
}

View file

@ -25,7 +25,8 @@ function wfSpecialAllmessages() {
$navText = wfMsg( 'allmessagestext' );
# Make sure all extension messages are available
MessageCache::loadAllMessages();
$wgMessageCache->loadAllMessages();
$sortedArray = array_merge( Language::getMessagesFor( 'en' ), $wgMessageCache->getExtensionMessagesFor( 'en' ) );
ksort( $sortedArray );

View file

@ -8,9 +8,9 @@
*
*/
function wfSpecialSpecialpages() {
global $wgOut, $wgUser;
global $wgOut, $wgUser, $wgMessageCache;
MessageCache::loadAllMessages();
$wgMessageCache->loadAllMessages();
$wgOut->setRobotpolicy( 'index,nofollow' );
$sk = $wgUser->getSkin();

View file

@ -2527,7 +2527,8 @@ class User {
* @static
*/
static function getGroupName( $group ) {
MessageCache::loadAllMessages();
global $wgMessageCache;
$wgMessageCache->loadAllMessages();
$key = "group-$group";
$name = wfMsg( $key );
return $name == '' || wfEmptyMsg( $key, $name )
@ -2541,7 +2542,8 @@ class User {
* @static
*/
static function getGroupMember( $group ) {
MessageCache::loadAllMessages();
global $wgMessageCache;
$wgMessageCache->loadAllMessages();
$key = "group-$group-member";
$name = wfMsg( $key );
return $name == '' || wfEmptyMsg( $key, $name )
@ -2586,7 +2588,8 @@ class User {
* @return mixed
*/
static function getGroupPage( $group ) {
MessageCache::loadAllMessages();
global $wgMessageCache;
$wgMessageCache->loadAllMessages();
$page = wfMsgForContent( 'grouppage-' . $group );
if( !wfEmptyMsg( 'grouppage-' . $group, $page ) ) {
$title = Title::newFromText( $page );

View file

@ -209,6 +209,18 @@ abstract class File {
*/
public function getHeight( $page = 1 ) { return false; }
/**
* Get the duration of a media file in seconds
*/
public function getLength() {
$handler = $this->getHandler();
if ( $handler ) {
return $handler->getLength( $this );
} else {
return 0;
}
}
/**
* Get handler-specific metadata
* Overridden by LocalFile, UnregisteredLocalFile
@ -239,7 +251,9 @@ abstract class File {
function getMediaType() { return MEDIATYPE_UNKNOWN; }
/**
* Checks if the file can be presented to the browser as a bitmap.
* Checks if the output of transform() for this file is likely
* to be valid. If this is false, various user elements will
* display a placeholder instead.
*
* Currently, this checks if the file is an image format
* that can be converted to a format
@ -248,7 +262,7 @@ abstract class File {
*/
function canRender() {
if ( !isset( $this->canRender ) ) {
$this->canRender = $this->getHandler() && $this->handler->canRender();
$this->canRender = $this->getHandler() && $this->handler->canRender( $this );
}
return $this->canRender;
}
@ -271,16 +285,11 @@ abstract class File {
* @return bool
*/
function mustRender() {
return $this->getHandler() && $this->handler->mustRender();
return $this->getHandler() && $this->handler->mustRender( $this );
}
/**
* Determines if this media file may be shown inline on a page.
*
* This is currently synonymous to canRender(), but this could be
* extended to also allow inline display of other media,
* like flash animations or videos. If you do so, please keep in mind that
* that could be a security risk.
* Alias for canRender()
*/
function allowInlineDisplay() {
return $this->canRender();
@ -470,7 +479,7 @@ abstract class File {
wfProfileIn( __METHOD__ );
do {
if ( !$this->getHandler() || !$this->handler->canRender() ) {
if ( !$this->canRender() ) {
// not a bitmap or renderable image, don't try.
$thumb = $this->iconThumb();
break;
@ -906,7 +915,7 @@ abstract class File {
* @return Bool
*/
function isMultipage() {
return $this->getHandler() && $this->handler->isMultiPage();
return $this->getHandler() && $this->handler->isMultiPage( $this );
}
/**
@ -915,7 +924,7 @@ abstract class File {
*/
function pageCount() {
if ( !isset( $this->pageCount ) ) {
if ( $this->getHandler() && $this->handler->isMultiPage() ) {
if ( $this->getHandler() && $this->handler->isMultiPage( $this ) ) {
$this->pageCount = $this->handler->pageCount( $this );
} else {
$this->pageCount = false;
@ -1014,7 +1023,9 @@ abstract class File {
static function getPropsFromPath( $path, $ext = true ) {
wfProfileIn( __METHOD__ );
wfDebug( __METHOD__.": Getting file info for $path\n" );
$info = array( 'fileExists' => file_exists( $path ) );
$info = array(
'fileExists' => file_exists( $path ) && !is_dir( $path )
);
$gis = false;
if ( $info['fileExists'] ) {
$magic = MimeMagic::singleton();
@ -1030,8 +1041,8 @@ abstract class File {
$handler = MediaHandler::getHandler( $info['mime'] );
if ( $handler ) {
$tempImage = (object)array();
$gis = $handler->getImageSize( $tempImage, $path );
$info['metadata'] = $handler->getMetadata( $tempImage, $path );
$gis = $handler->getImageSize( $tempImage, $path, $info['metadata'] );
} else {
$gis = false;
$info['metadata'] = '';
@ -1074,13 +1085,42 @@ abstract class File {
* Returns false on failure
*/
static function sha1Base36( $path ) {
wfSuppressWarnings();
$hash = sha1_file( $path );
wfRestoreWarnings();
if ( $hash === false ) {
return false;
} else {
return wfBaseConvert( $hash, 16, 36, 31 );
}
}
function getLongDesc() {
$handler = $this->getHandler();
if ( $handler ) {
return $handler->getLongDesc( $this );
} else {
return MediaHandler::getLongDesc( $this );
}
}
function getShortDesc() {
$handler = $this->getHandler();
if ( $handler ) {
return $handler->getShortDesc( $this );
} else {
return MediaHandler::getShortDesc( $this );
}
}
function getDimensionsString() {
$handler = $this->getHandler();
if ( $handler ) {
return $handler->getDimensionsString( $this );
} else {
return '';
}
}
}
/**
* Aliases for backwards compatibility with 1.6
@ -1090,3 +1130,4 @@ define( 'MW_IMG_DELETED_COMMENT', File::DELETED_COMMENT );
define( 'MW_IMG_DELETED_USER', File::DELETED_USER );
define( 'MW_IMG_DELETED_RESTRICTED', File::DELETED_RESTRICTED );

View file

@ -39,7 +39,7 @@ class LocalFile extends File
$media_type, # MEDIATYPE_xxx (bitmap, drawing, audio...)
$mime, # MIME type, determined by MimeMagic::guessMimeType
$major_mime, # Major mime type
$minor_mine, # Minor mime type
$minor_mime, # Minor mime type
$size, # Size in bytes (loadFromXxx)
$metadata, # Handler-specific metadata
$timestamp, # Upload timestamp
@ -231,6 +231,7 @@ class LocalFile extends File
* Load file metadata from a DB result row
*/
function loadFromRow( $row, $prefix = 'img_' ) {
$this->dataLoaded = true;
$array = $this->decodeRow( $row, $prefix );
foreach ( $array as $name => $value ) {
$this->$name = $value;
@ -287,6 +288,11 @@ class LocalFile extends File
$this->loadFromFile();
# Don't destroy file info of missing files
if ( !$this->fileExists ) {
wfDebug( __METHOD__.": file does not exist, aborting\n" );
return;
}
$dbw = $this->repo->getMasterDB();
list( $major, $minor ) = self::splitMime( $this->mime );
@ -318,6 +324,12 @@ class LocalFile extends File
$this->$field = $info[$field];
}
}
// Fix up mime fields
if ( isset( $info['major_mime'] ) ) {
$this->mime = "{$info['major_mime']}/{$info['minor_mime']}";
} elseif ( isset( $info['mime'] ) ) {
list( $this->major_mime, $this->minor_mime ) = self::splitMime( $this->mime );
}
}
/** splitMime inherited */
@ -560,14 +572,9 @@ class LocalFile extends File
$dbr = $this->repo->getSlaveDB();
if ( $this->historyLine == 0 ) {// called for the first time, return line from cur
$this->historyRes = $dbr->select( 'image',
$this->historyRes = $dbr->select( 'image',
array(
'img_size',
'img_description',
'img_user','img_user_text',
'img_timestamp',
'img_width',
'img_height',
'*',
"'' AS oi_archive_name"
),
array( 'img_name' => $this->title->getDBkey() ),
@ -580,17 +587,7 @@ class LocalFile extends File
}
} else if ( $this->historyLine == 1 ) {
$dbr->freeResult($this->historyRes);
$this->historyRes = $dbr->select( 'oldimage',
array(
'oi_size AS img_size',
'oi_description AS img_description',
'oi_user AS img_user',
'oi_user_text AS img_user_text',
'oi_timestamp AS img_timestamp',
'oi_width as img_width',
'oi_height as img_height',
'oi_archive_name'
),
$this->historyRes = $dbr->select( 'oldimage', '*',
array( 'oi_name' => $this->title->getDBkey() ),
__METHOD__,
array( 'ORDER BY' => 'oi_timestamp DESC' )

View file

@ -118,7 +118,10 @@ class OldLocalFile extends LocalFile {
}
function saveToCache() {
// Cache the entire history of the image (up to MAX_CACHE_ROWS).
// If a timestamp was specified, cache the entire history of the image (up to MAX_CACHE_ROWS).
if ( is_null( $this->requestedTime ) ) {
return;
}
// This is expensive, so we only do it if $wgMemc is real
global $wgMemc;
if ( $wgMemc instanceof FakeMemcachedClient ) {
@ -155,6 +158,7 @@ class OldLocalFile extends LocalFile {
function loadFromDB() {
wfProfileIn( __METHOD__ );
$this->dataLoaded = true;
$dbr = $this->repo->getSlaveDB();
$conds = array( 'oi_name' => $this->getName() );
if ( is_null( $this->requestedTime ) ) {
@ -169,7 +173,6 @@ class OldLocalFile extends LocalFile {
} else {
$this->fileExists = false;
}
$this->dataLoaded = true;
wfProfileOut( __METHOD__ );
}
@ -178,8 +181,8 @@ class OldLocalFile extends LocalFile {
$fields[] = $prefix . 'archive_name';
// XXX: Temporary hack before schema update
$fields = array_diff( $fields, array(
'oi_media_type', 'oi_major_mime', 'oi_minor_mime', 'oi_metadata' ) );
//$fields = array_diff( $fields, array(
// 'oi_media_type', 'oi_major_mime', 'oi_minor_mime', 'oi_metadata' ) );
return $fields;
}
@ -193,11 +196,18 @@ class OldLocalFile extends LocalFile {
function upgradeRow() {
wfProfileIn( __METHOD__ );
$this->loadFromFile();
# Don't destroy file info of missing files
if ( !$this->fileExists ) {
wfDebug( __METHOD__.": file does not exist, aborting\n" );
wfProfileOut( __METHOD__ );
return;
}
$dbw = $this->repo->getMasterDB();
list( $major, $minor ) = self::splitMime( $this->mime );
$mime = $this->mime;
wfDebug(__METHOD__.': upgrading '.$this->archive_name." to the current schema\n");
$dbw->update( 'oldimage',
@ -205,10 +215,10 @@ class OldLocalFile extends LocalFile {
'oi_width' => $this->width,
'oi_height' => $this->height,
'oi_bits' => $this->bits,
#'oi_media_type' => $this->media_type,
#'oi_major_mime' => $major,
#'oi_minor_mime' => $minor,
#'oi_metadata' => $this->metadata,
'oi_media_type' => $this->media_type,
'oi_major_mime' => $major,
'oi_minor_mime' => $minor,
'oi_metadata' => $this->metadata,
'oi_sha1' => $this->sha1,
), array(
'oi_name' => $this->getName(),

View file

@ -17,6 +17,13 @@ class DjVuHandler extends ImageHandler {
function mustRender() { return true; }
function isMultiPage() { return true; }
function getParamMap() {
return array(
'img_width' => 'width',
'img_page' => 'page',
);
}
function validateParam( $name, $value ) {
if ( in_array( $name, array( 'width', 'height', 'page' ) ) ) {
if ( $value <= 0 ) {

View file

@ -36,6 +36,12 @@ abstract class MediaHandler {
return self::$handlers[$class];
}
/**
* Get an associative array mapping magic word IDs to parameter names.
* Will be used by the parser to identify parameters.
*/
abstract function getParamMap();
/*
* Validate a thumbnail parameter at parse time.
* Return true to accept the parameter, and false to reject it.
@ -126,20 +132,20 @@ abstract class MediaHandler {
/**
* True if the handled types can be transformed
*/
function canRender() { return true; }
function canRender( $file ) { return true; }
/**
* True if handled types cannot be displayed directly in a browser
* but can be rendered
*/
function mustRender() { return false; }
function mustRender( $file ) { return false; }
/**
* True if the type has multi-page capabilities
*/
function isMultiPage() { return false; }
function isMultiPage( $file ) { return false; }
/**
* Page count for a multi-page document, false if unsupported or unknown
*/
function pageCount() { return false; }
function pageCount( $file ) { return false; }
/**
* False if the handler is disabled for all files
*/
@ -177,10 +183,18 @@ abstract class MediaHandler {
*
* The function should return false if there is no metadata to display.
*/
/**
* FIXME: I don't really like this interface, it's not very flexible
* I think the media handler should generate HTML instead. It can do
* all the formatting according to some standard. That makes it possible
* to do things like visual indication of grouped and chained streams
* in ogg container files.
*/
function formatMetadata( $image, $metadata ) {
return false;
}
protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
$array[$visibility][] = array(
'id' => "$type-$id",
@ -189,6 +203,26 @@ abstract class MediaHandler {
);
}
function getShortDesc( $file ) {
global $wgLang;
$nbytes = '(' . wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ),
$wgLang->formatNum( $file->getSize() ) ) . ')';
}
function getLongDesc( $file ) {
global $wgUser;
$sk = $wgUser->getSkin();
return wfMsg( 'file-info', $sk->formatSize( $file->getSize() ), $file->getMimeType() );
}
function getDimensionsString() {
return '';
}
/**
* Modify the parser object post-transform
*/
function parserTransformHook( $parser, $file ) {}
}
/**
@ -197,6 +231,18 @@ abstract class MediaHandler {
* @addtogroup Media
*/
abstract class ImageHandler extends MediaHandler {
function canRender( $file ) {
if ( $file->getWidth() && $file->getHeight() ) {
return true;
} else {
return false;
}
}
function getParamMap() {
return array( 'img_width' => 'width' );
}
function validateParam( $name, $value ) {
if ( in_array( $name, array( 'width', 'height' ) ) ) {
if ( $value <= 0 ) {
@ -325,6 +371,31 @@ abstract class ImageHandler extends MediaHandler {
wfRestoreWarnings();
return $gis;
}
function getShortDesc( $file ) {
global $wgLang;
$nbytes = '(' . wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ),
$wgLang->formatNum( $file->getSize() ) ) . ')';
$widthheight = wfMsgHtml( 'widthheight', $file->getWidth(), $file->getHeight() );
return "$widthheight ($nbytes)";
}
function getLongDesc( $file ) {
global $wgLang;
return wfMsgHtml('file-info-size', $file->getWidth(), $file->getHeight(),
$wgLang->formatSize( $file->getSize() ), $file->getMimeType() );
}
function getDimensionsString( $file ) {
$pages = $file->pageCount();
if ( $pages > 1 ) {
return wfMsg( 'widthheightpage', $file->getWidth(), $file->getHeight(), $pages );
} else {
return wfMsg( 'widthheight', $file->getWidth(), $file->getHeight() );
}
}
}

View file

@ -14,7 +14,7 @@ class SvgHandler extends ImageHandler {
}
}
function mustRender() {
function mustRender( $file ) {
return true;
}
@ -91,5 +91,12 @@ class SvgHandler extends ImageHandler {
function getThumbType( $ext, $mime ) {
return array( 'png', 'image/png' );
}
function getLongDesc( $file ) {
global $wgLang;
return wfMsg( 'svg-long-desc', $file->getWidth(), $file->getHeight(),
$wgLang->formatSize( $file->getSize() ) );
}
}

View file

@ -1824,6 +1824,73 @@ class Language {
wfProfileOut( __METHOD__ );
return array( $wikiUpperChars, $wikiLowerChars );
}
function formatTimePeriod( $seconds ) {
if ( $seconds < 10 ) {
return $this->formatNum( sprintf( "%.1f", $seconds ) ) . wfMsg( 'seconds-abbrev' );
} elseif ( $seconds < 60 ) {
return $this->formatNum( round( $seconds ) ) . wfMsg( 'seconds-abbrev' );
} elseif ( $seconds < 3600 ) {
return $this->formatNum( floor( $seconds / 60 ) ) . wfMsg( 'minutes-abbrev' ) .
$this->formatNum( round( fmod( $seconds, 60 ) ) ) . wfMsg( 'seconds-abbrev' );
} else {
$hours = floor( $seconds / 3600 );
$minutes = floor( ( $seconds - $hours * 3600 ) / 60 );
$secondsPart = round( $seconds - $hours * 3600 - $minutes * 60 );
return $this->formatNum( $hours ) . wfMsg( 'hours-abbrev' ) .
$this->formatNum( $minutes ) . wfMsg( 'minutes-abbrev' ) .
$this->formatNum( $secondsPart ) . wfMsg( 'seconds-abbrev' );
}
}
function formatBitrate( $bps ) {
$units = array( 'bps', 'kbps', 'Mbps', 'Gbps' );
if ( $bps <= 0 ) {
return $this->formatNum( $bps ) . $units[0];
}
$unitIndex = floor( log10( $bps ) / 3 );
$mantissa = $bps / pow( 1000, $unitIndex );
if ( $mantissa < 10 ) {
$mantissa = round( $mantissa, 1 );
} else {
$mantissa = round( $mantissa );
}
return $this->formatNum( $mantissa ) . $units[$unitIndex];
}
/**
* Format a size in bytes for output, using an appropriate
* unit (B, KB, MB or GB) according to the magnitude in question
*
* @param $size Size to format
* @return string Plain text (not HTML)
*/
function formatSize( $size ) {
// For small sizes no decimal places necessary
$round = 0;
if( $size > 1024 ) {
$size = $size / 1024;
if( $size > 1024 ) {
$size = $size / 1024;
// For MB and bigger two decimal places are smarter
$round = 2;
if( $size > 1024 ) {
$size = $size / 1024;
$msg = 'size-gigabytes';
} else {
$msg = 'size-megabytes';
}
} else {
$msg = 'size-kilobytes';
}
} else {
$msg = 'size-bytes';
}
$size = round( $size, $round );
$text = $this->getMessageFromDB( $msg );
return str_replace( '$1', $this->formatNum( $size ), $text );
}
}

View file

@ -156,10 +156,10 @@ $magicWords = array(
'img_page' => array( 1, "صفحة=$1", "صفحة $1", "page=$1", "page $1" ),
'img_border' => array( 1, "حد", "حدود", "border" ),
'img_top' => array( 1, "أعلى", "top" ),
'img_text-top' => array( 1, "نص_أعلى", "text-top" ),
'img_text_top' => array( 1, "نص_أعلى", "text-top" ),
'img_middle' => array( 1, "وسط", "middle" ),
'img_bottom' => array( 1, "أسفل", "bottom" ),
'img_text-bottom' => array( 1, "نص_أسفل", "text-bottom" ),
'img_text_bottom' => array( 1, "نص_أسفل", "text-bottom" ),
'int' => array( 0, "محتوى:", "INT:" ),
'sitename' => array( 1, "اسم_الموقع", "اسم_موقع", "SITENAME" ),
'ns' => array( 0, "نط:", "NS:" ),

View file

@ -114,10 +114,10 @@ $magicWords = array(
'img_sub' => array( 1, 'sub' ),
'img_super' => array( 1, 'super', 'sup' ),
'img_top' => array( 1, 'top' ),
'img_text-top' => array( 1, 'text-top' ),
'img_text_top' => array( 1, 'text-top' ),
'img_middle' => array( 1, 'middle' ),
'img_bottom' => array( 1, 'bottom' ),
'img_text-bottom' => array( 1, 'text-bottom' ),
'img_text_bottom' => array( 1, 'text-bottom' ),
'int' => array( 0, 'INT:', 'ВЪТР:'),
'sitename' => array( 1, 'SITENAME', 'ИМЕНАСАЙТА'),
'ns' => array( 0, 'NS:', 'ИП:' ),

View file

@ -133,10 +133,10 @@ $bookstoreList = array(
'img_sub' => array( 1, 'sub' ),
'img_super' => array( 1, 'super', 'sup' ),
'img_top' => array( 1, 'top' ),
'img_text-top' => array( 1, 'text-top' ),
'img_text_top' => array( 1, 'text-top' ),
'img_middle' => array( 1, 'middle' ),
'img_bottom' => array( 1, 'bottom' ),
'img_text-bottom' => array( 1, 'text-bottom' ),
'img_text_bottom' => array( 1, 'text-bottom' ),
'int' => array( 0, 'INT:' ),
'sitename' => array( 1, 'SITENAME', 'NÁZEVSERVERU' ),
'ns' => array( 0, 'NS:' ),

View file

@ -209,7 +209,9 @@ $bookstoreList = array(
/**
* Magic words
* Customisable syntax for wikitext and elsewhere
* Customisable syntax for wikitext and elsewhere.
*
* IDs must be valid identifiers, they can't contain hyphens.
*
* Note to translators:
* Please include the English words as synonyms. This allows people
@ -287,10 +289,10 @@ $magicWords = array(
'img_sub' => array( 1, 'sub' ),
'img_super' => array( 1, 'super', 'sup' ),
'img_top' => array( 1, 'top' ),
'img_text-top' => array( 1, 'text-top' ),
'img_text_top' => array( 1, 'text-top' ),
'img_middle' => array( 1, 'middle' ),
'img_bottom' => array( 1, 'bottom' ),
'img_text-bottom' => array( 1, 'text-bottom' ),
'img_text_bottom' => array( 1, 'text-bottom' ),
'int' => array( 0, 'INT:' ),
'sitename' => array( 1, 'SITENAME' ),
'ns' => array( 0, 'NS:' ),
@ -2422,10 +2424,11 @@ All transwiki import actions are logged at the [[Special:Log/import|import log]]
'imagemaxsize' => 'Limit images on image description pages to:',
'thumbsize' => 'Thumbnail size:',
'widthheight' => '$1×$2', # only translate this message to other languages if you have to change it
'widthheightpage' => '$1×$2, $3 pages',
'file-info' => '(file size: $1, MIME type: $2)',
'file-info-size' => '($1 × $2 pixel, file size: $3, MIME type: $4)',
'file-nohires' => '<small>No higher resolution available.</small>',
'file-svg' => '<small>This is a lossless scalable vector image. Base size: $1 × $2 pixels.</small>',
'svg-long-desc' => '(SVG file, nominally $1 × $2 pixels, file size: $3)',
'show-big-image' => 'Full resolution',
'show-big-image-thumb' => '<small>Size of this preview: $1 × $2 pixels</small>',
@ -2434,6 +2437,12 @@ All transwiki import actions are logged at the [[Special:Log/import|import log]]
'showhidebots' => '($1 bots)',
'noimages' => 'Nothing to see.',
'video-dims' => '$1, $2×$3',
# Used by Language::formatTimePeriod() to format lengths in the above messages
'seconds-abbrev' => 's',
'minutes-abbrev' => 'm',
'hours-abbrev' => 'h',
# Bad image list
'bad_image_list' => 'The format is as follows:

View file

@ -147,10 +147,10 @@ $magicWords = array(
'img_sub' => array( 1, 'sub' ),
'img_super' => array( 1, 'super', 'sup' ),
'img_top' => array( 1, 'atas', 'top' ),
'img_text-top' => array( 1, 'atas-teks', 'text-top' ),
'img_text_top' => array( 1, 'atas-teks', 'text-top' ),
'img_middle' => array( 1, 'tengah', 'middle' ),
'img_bottom' => array( 1, 'bawah', 'bottom' ),
'img_text-bottom' => array( 1, 'bawah-teks', 'text-bottom' ),
'img_text_bottom' => array( 1, 'bawah-teks', 'text-bottom' ),
'int' => array( 0, 'INT:' ),
'sitename' => array( 1, 'NAMASITUS', 'SITENAME' ),
'ns' => array( 0, 'RN:', 'NS:' ),

View file

@ -223,10 +223,10 @@ $magicWords = array(
'img_sub' => array( 1, 'استىلىعى', 'است', 'sub'),
'img_super' => array( 1, 'ٷستٸلٸگٸ', 'ٷست', 'sup', 'super', 'sup' ),
'img_top' => array( 1, 'ٷستٸنە', 'top' ),
'img_text-top' => array( 1, 'مٵتٸن-ٷستٸندە', 'text-top' ),
'img_text_top' => array( 1, 'مٵتٸن-ٷستٸندە', 'text-top' ),
'img_middle' => array( 1, 'ارالىعىنا', 'middle' ),
'img_bottom' => array( 1, 'استىنا', 'bottom' ),
'img_text-bottom' => array( 1, 'مٵتٸن-استىندا', 'text-bottom' ),
'img_text_bottom' => array( 1, 'مٵتٸن-استىندا', 'text-bottom' ),
'int' => array( 0, 'ٸشكٸ:', 'INT:' ),
'sitename' => array( 1, 'توراپاتاۋى', 'SITENAME' ),
'ns' => array( 0, 'ەا:', 'ەسٸمايا:', 'NS:' ),

View file

@ -215,10 +215,10 @@ $magicWords = array(
'img_sub' => array( 1, 'астылығы', 'аст', 'sub'),
'img_super' => array( 1, 'үстілігі', 'үст', 'sup', 'super', 'sup' ),
'img_top' => array( 1, 'үстіне', 'top' ),
'img_text-top' => array( 1, 'мәтін-үстінде', 'text-top' ),
'img_text_top' => array( 1, 'мәтін-үстінде', 'text-top' ),
'img_middle' => array( 1, 'аралығына', 'middle' ),
'img_bottom' => array( 1, 'астына', 'bottom' ),
'img_text-bottom' => array( 1, 'мәтін-астында', 'text-bottom' ),
'img_text_bottom' => array( 1, 'мәтін-астында', 'text-bottom' ),
'int' => array( 0, 'ІШКІ:', 'INT:' ),
'sitename' => array( 1, 'ТОРАПАТАУЫ', 'SITENAME' ),
'ns' => array( 0, 'ЕА:', 'ЕСІМАЯ:', 'NS:' ),

View file

@ -216,10 +216,10 @@ $magicWords = array(
'img_sub' => array( 1, 'astılığı', 'ast', 'sub'),
'img_super' => array( 1, 'üstiligi', 'üst', 'sup', 'super', 'sup' ),
'img_top' => array( 1, 'üstine', 'top' ),
'img_text-top' => array( 1, 'mätin-üstinde', 'text-top' ),
'img_text_top' => array( 1, 'mätin-üstinde', 'text-top' ),
'img_middle' => array( 1, 'aralığına', 'middle' ),
'img_bottom' => array( 1, 'astına', 'bottom' ),
'img_text-bottom' => array( 1, 'mätin-astında', 'text-bottom' ),
'img_text_bottom' => array( 1, 'mätin-astında', 'text-bottom' ),
'int' => array( 0, 'İŞKİ:', 'INT:' ),
'sitename' => array( 1, 'TORAPATAWI', 'SITENAME' ),
'ns' => array( 0, 'EA:', 'ESİMAYA:', 'NS:' ),

View file

@ -165,10 +165,10 @@ $magicWords = array(
'img_sub' => array( 1, 'sub' ),
'img_super' => array( 1, 'super', 'sup' ),
'img_top' => array( 1, 'top', 'boven' ),
'img_text-top' => array( 1, 'text-top', 'tekst-boven' ),
'img_text_top' => array( 1, 'text-top', 'tekst-boven' ),
'img_middle' => array( 1, 'middle', 'midden' ),
'img_bottom' => array( 1, 'bottom', 'beneden' ),
'img_text-bottom' => array( 1, 'text-bottom', 'tekst-beneden' ),
'img_text_bottom' => array( 1, 'text-bottom', 'tekst-beneden' ),
'int' => array( 0, 'INT:' ),
'sitename' => array( 1, 'SITENAME', 'SITENAAM' ),
'ns' => array( 0, 'NS:', 'NR:' ),