* (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 ==
'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',
}
+
*/
$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.
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;
+ }
+}
+
+
class ImagePage extends Article {
/* private */ var $img; // Image object this page is shown for
+ /* private */ var $repo;
var $mExtraDescription = false;
function __construct( $title ) {
if ( !$this->img ) {
$this->img = wfLocalFile( $this->mTitle );
}
+ $this->repo = $this->img->repo;
}
/**
return Article::view();
if ($wgShowEXIF && $this->img->exists()) {
+ // FIXME: bad interface, see note on MediaHandler::formatMetadata().
$formattedMetadata = $this->img->formatMetadata();
$showmeta = $formattedMetadata !== false;
} else {
/**
* 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
$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.
} else {
$anchorclose .=
$msgsmall .
- '<br />' . Xml::tags( 'a', $linkAttribs, $msgbig ) . ' ' . $msgsize;
+ '<br />' . Xml::tags( 'a', $linkAttribs, $msgbig ) . ' ' . $longDesc;
}
if ( $this->img->isMultipage() ) {
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>
);
} 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
);
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();
*/
class ImageHistoryList {
- protected $img, $skin, $title;
+ protected $img, $skin, $title, $repo;
public function __construct( $skin, $img ) {
$this->skin = $skin;
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 = '';
$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>';
return "<tr>{$row}</tr>\n";
}
-}
\ No newline at end of file
+}
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;
+ if ( $file && !$file->allowInlineDisplay() ) {
+ wfDebug( __METHOD__.': '.$title->getPrefixedDBkey()." does not allow inline display\n" );
+ return $this->makeKnownLinkObj( $title );
+ }
- $img = wfFindFile( $nt, $time );
+ // Shortcuts
+ $fp =& $frameParams;
+ $hp =& $handlerParams;
- if ( $img && !$img->allowInlineDisplay() ) {
- wfDebug( __METHOD__.': '.$nt->getPrefixedDBkey()." does not allow inline display\n" );
- return $this->makeKnownLinkObj( $nt );
- }
+ // Clean up parameters
+ $page = isset( $hp['page'] ) ? $hp['page'] : false;
+ if ( !isset( $fp['align'] ) ) $fp['align'] = '';
+ if ( !isset( $fp['alt'] ) ) $fp['alt'] = '';
- $error = $prefix = $postfix = '';
- $page = isset( $params['page'] ) ? $params['page'] : false;
+ $prefix = $postfix = '';
- if ( 'center' == $align )
+ 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] ) ) {
}
// 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-
#
# 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;
}
} 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 ) {
$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);
}
*/
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 ) );
}
/**
+
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;
+ }
+}
var $mExtensionMessages = array();
var $mInitialised = false;
var $mDeferred = true;
+ var $mAllMessagesLoaded;
function __construct( &$memCached, $useDB, $expiry, $memcPrefix) {
wfProfileIn( __METHOD__ );
}
}
- 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 );
+ }
}
$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 );
$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; }
# 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 ) );
}
* @private
*/
# Persistent:
- var $mTagHooks, $mTransparentTagHooks, $mFunctionHooks, $mFunctionSynonyms, $mVariables;
+ var $mTagHooks, $mTransparentTagHooks, $mFunctionHooks, $mFunctionSynonyms, $mVariables,
+ $mImageParams, $mImageParamsMagicArray;
# Cleared with clearState():
var $mOutput, $mAutonumber, $mDTopen, $mStripState;
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"
# * middle
# * bottom
# * text-bottom
+
+ $parts = array_map( 'trim', explode( '|', $options) );
+ $sk = $this->mOptions->getSkin();
+ # Give extensions a chance to select the file revision for us
+ $skip = $time = false;
+ wfRunHooks( 'BeforeParserMakeImageLinkObj', array( &$this, &$title, &$skip, &$time ) );
- $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 );
+ if ( $skip ) {
+ return $sk->makeLinkObj( $title );
}
- $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 = '';
- $sk = $this->mOptions->getSkin();
+ # Get parameter map
+ $file = wfFindFile( $title, $time );
+ $handler = $file ? $file->getHandler() : false;
- 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;
+ 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 );
$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;
}
/**
$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
$this->mNoGallery = false;
$this->mHeadItems = array();
$this->mTemplateIds = array();
+ $this->mOutputHooks = array();
}
function getText() { return $this->mText; }
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 ); }
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;
}
$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 );
*
*/
function wfSpecialSpecialpages() {
- global $wgOut, $wgUser;
+ global $wgOut, $wgUser, $wgMessageCache;
- MessageCache::loadAllMessages();
+ $wgMessageCache->loadAllMessages();
$wgOut->setRobotpolicy( 'index,nofollow' );
$sk = $wgUser->getSkin();
* @static
*/
static function getGroupName( $group ) {
- MessageCache::loadAllMessages();
+ global $wgMessageCache;
+ $wgMessageCache->loadAllMessages();
$key = "group-$group";
$name = wfMsg( $key );
return $name == '' || wfEmptyMsg( $key, $name )
* @static
*/
static function getGroupMember( $group ) {
- MessageCache::loadAllMessages();
+ global $wgMessageCache;
+ $wgMessageCache->loadAllMessages();
$key = "group-$group-member";
$name = wfMsg( $key );
return $name == '' || wfEmptyMsg( $key, $name )
* @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 );
*/
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
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
*/
function canRender() {
if ( !isset( $this->canRender ) ) {
- $this->canRender = $this->getHandler() && $this->handler->canRender();
+ $this->canRender = $this->getHandler() && $this->handler->canRender( $this );
}
return $this->canRender;
}
* @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();
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;
* @return Bool
*/
function isMultipage() {
- return $this->getHandler() && $this->handler->isMultiPage();
+ return $this->getHandler() && $this->handler->isMultiPage( $this );
}
/**
*/
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;
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();
$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'] = '';
* 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
define( 'MW_IMG_DELETED_USER', File::DELETED_USER );
define( 'MW_IMG_DELETED_RESTRICTED', File::DELETED_RESTRICTED );
+
$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
* 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;
$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 );
$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 */
$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() ),
}
} 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' )
}
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 ) {
function loadFromDB() {
wfProfileIn( __METHOD__ );
+ $this->dataLoaded = true;
$dbr = $this->repo->getSlaveDB();
$conds = array( 'oi_name' => $this->getName() );
if ( is_null( $this->requestedTime ) ) {
} else {
$this->fileExists = false;
}
- $this->dataLoaded = true;
wfProfileOut( __METHOD__ );
}
$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;
}
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',
'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(),
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 ) {
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.
/**
* 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
*/
*
* 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",
);
}
+ 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 ) {}
}
/**
* @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 ) {
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() );
+ }
+ }
}
+
}
}
- function mustRender() {
+ function mustRender( $file ) {
return true;
}
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() ) );
+ }
}
+
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 );
+ }
}
+
'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:" ),
'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:', 'ИП:' ),
'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:' ),
/**
* 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
'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:' ),
'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>',
'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:
'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:' ),
'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:' ),
'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:' ),
'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:' ),
'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:' ),