00001 <?php
00002
00003 if( !defined( 'MEDIAWIKI' ) )
00004 die( 1 );
00005
00011 class ImagePage extends Article {
00012
00013 var $img;
00014 var $displayImg;
00015 var $repo;
00016 var $fileLoaded;
00017 var $mExtraDescription = false;
00018 var $dupes;
00019
00020 function __construct( $title ) {
00021 parent::__construct( $title );
00022 $this->dupes = null;
00023 $this->repo = null;
00024 }
00025
00026 public function setFile( $file ) {
00027 $this->displayImg = $file;
00028 $this->img = $file;
00029 $this->fileLoaded = true;
00030 }
00031
00032 protected function loadFile() {
00033 if( $this->fileLoaded ) {
00034 return true;
00035 }
00036 $this->fileLoaded = true;
00037
00038 $this->displayImg = $this->img = false;
00039 wfRunHooks( 'ImagePageFindFile', array( $this, &$this->img, &$this->displayImg ) );
00040 if( !$this->img ) {
00041 $this->img = wfFindFile( $this->mTitle );
00042 if( !$this->img ) {
00043 $this->img = wfLocalFile( $this->mTitle );
00044 }
00045 }
00046 if( !$this->displayImg ) {
00047 $this->displayImg = $this->img;
00048 }
00049 $this->repo = $this->img->getRepo();
00050 }
00051
00056 public function render() {
00057 global $wgOut;
00058 $wgOut->setArticleBodyOnly( true );
00059 parent::view();
00060 }
00061
00062 public function view() {
00063 global $wgOut, $wgShowEXIF, $wgRequest, $wgUser;
00064 $this->loadFile();
00065
00066 if( $this->mTitle->getNamespace() == NS_FILE && $this->img->getRedirected() ) {
00067 if( $this->mTitle->getDBkey() == $this->img->getName() ) {
00068
00069
00070 return Article::view();
00071 } else {
00072
00073
00074 $wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
00075 $wgOut->addHTML( $this->viewRedirect( Title::makeTitle( NS_FILE, $this->img->getName() ),
00076 true, true ) );
00077 $this->viewUpdates();
00078 return;
00079 }
00080 }
00081
00082 $diff = $wgRequest->getVal( 'diff' );
00083 $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) );
00084
00085 if( $this->mTitle->getNamespace() != NS_FILE || ( isset( $diff ) && $diffOnly ) )
00086 return Article::view();
00087
00088 if( $wgShowEXIF && $this->displayImg->exists() ) {
00089
00090 $formattedMetadata = $this->displayImg->formatMetadata();
00091 $showmeta = $formattedMetadata !== false;
00092 } else {
00093 $showmeta = false;
00094 }
00095
00096 if( !$diff && $this->displayImg->exists() )
00097 $wgOut->addHTML( $this->showTOC($showmeta) );
00098
00099 if( !$diff )
00100 $this->openShowImage();
00101
00102 # No need to display noarticletext, we use our own message, output in openShowImage()
00103 if( $this->getID() ) {
00104 Article::view();
00105 } else {
00106 # Just need to set the right headers
00107 $wgOut->setArticleFlag( true );
00108 $wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
00109 $this->viewUpdates();
00110 }
00111
00112 # Show shared description, if needed
00113 if( $this->mExtraDescription ) {
00114 $fol = wfMsgNoTrans( 'shareddescriptionfollows' );
00115 if( $fol != '-' && !wfEmptyMsg( 'shareddescriptionfollows', $fol ) ) {
00116 $wgOut->addWikiText( $fol );
00117 }
00118 $wgOut->addHTML( '<div id="shared-image-desc">' . $this->mExtraDescription . '</div>' );
00119 }
00120
00121 $this->closeShowImage();
00122 $this->imageHistory();
00123
00124
00125 $wgOut->addHTML( Xml::element( 'h2',
00126 array( 'id' => 'filelinks' ),
00127 wfMsg( 'imagelinks' ) ) . "\n" );
00128 $this->imageDupes();
00129 # TODO! FIXME! For some freaky reason, we can't redirect to foreign images.
00130 # Yet we return metadata about the target. Definitely an issue in the FileRepo
00131 $this->imageRedirects();
00132 $this->imageLinks();
00133
00134 if( $showmeta ) {
00135 global $wgStylePath, $wgStyleVersion;
00136 $expand = htmlspecialchars( Xml::escapeJsString( wfMsg( 'metadata-expand' ) ) );
00137 $collapse = htmlspecialchars( Xml::escapeJsString( wfMsg( 'metadata-collapse' ) ) );
00138 $wgOut->addHTML( Xml::element( 'h2', array( 'id' => 'metadata' ), wfMsg( 'metadata' ) ). "\n" );
00139 $wgOut->addWikiText( $this->makeMetadataTable( $formattedMetadata ) );
00140 $wgOut->addScriptFile( 'metadata.js' );
00141 $wgOut->addHTML(
00142 "<script type=\"text/javascript\">attachMetadataToggle('mw_metadata', '$expand', '$collapse');</script>\n" );
00143 }
00144 }
00145
00146 public function getRedirectTarget() {
00147 $this->loadFile();
00148 if( $this->img->isLocal() ) {
00149 return parent::getRedirectTarget();
00150 }
00151
00152 $from = $this->img->getRedirected();
00153 $to = $this->img->getName();
00154 if( $from == $to ) {
00155 return null;
00156 }
00157 return $this->mRedirectTarget = Title::makeTitle( NS_FILE, $to );
00158 }
00159 public function followRedirect() {
00160 $this->loadFile();
00161 if( $this->img->isLocal() ) {
00162 return parent::followRedirect();
00163 }
00164 $from = $this->img->getRedirected();
00165 $to = $this->img->getName();
00166 if( $from == $to ) {
00167 return false;
00168 }
00169 return Title::makeTitle( NS_FILE, $to );
00170 }
00171 public function isRedirect( $text = false ) {
00172 $this->loadFile();
00173 if( $this->img->isLocal() )
00174 return parent::isRedirect( $text );
00175
00176 return (bool)$this->img->getRedirected();
00177 }
00178
00179 public function isLocal() {
00180 $this->loadFile();
00181 return $this->img->isLocal();
00182 }
00183
00184 public function getFile() {
00185 $this->loadFile();
00186 return $this->img;
00187 }
00188
00189 public function getDisplayedFile() {
00190 $this->loadFile();
00191 return $this->displayImg;
00192 }
00193
00194 public function getDuplicates() {
00195 $this->loadFile();
00196 if( !is_null($this->dupes) ) {
00197 return $this->dupes;
00198 }
00199 if( !( $hash = $this->img->getSha1() ) ) {
00200 return $this->dupes = array();
00201 }
00202 $dupes = RepoGroup::singleton()->findBySha1( $hash );
00203
00204 $self = $this->img->getRepoName().':'.$this->img->getName();
00205 $size = $this->img->getSize();
00206 foreach ( $dupes as $index => $file ) {
00207 $key = $file->getRepoName().':'.$file->getName();
00208 if( $key == $self )
00209 unset( $dupes[$index] );
00210 if( $file->getSize() != $size )
00211 unset( $dupes[$index] );
00212 }
00213 return $this->dupes = $dupes;
00214
00215 }
00216
00217
00224 protected function showTOC( $metadata ) {
00225 global $wgLang;
00226 $r = '<ul id="filetoc">
00227 <li><a href="#file">' . $wgLang->getNsText( NS_FILE ) . '</a></li>
00228 <li><a href="#filehistory">' . wfMsgHtml( 'filehist' ) . '</a></li>
00229 <li><a href="#filelinks">' . wfMsgHtml( 'imagelinks' ) . '</a></li>' .
00230 ($metadata ? ' <li><a href="#metadata">' . wfMsgHtml( 'metadata' ) . '</a></li>' : '') . '
00231 </ul>';
00232 return $r;
00233 }
00234
00243 protected function makeMetadataTable( $metadata ) {
00244 $r = wfMsg( 'metadata-help' ) . "\n\n";
00245 $r .= "{| id=mw_metadata class=mw_metadata\n";
00246 foreach ( $metadata as $type => $stuff ) {
00247 foreach ( $stuff as $v ) {
00248 # FIXME, why is this using escapeId for a class?!
00249 $class = Sanitizer::escapeId( $v['id'] );
00250 if( $type == 'collapsed' ) {
00251 $class .= ' collapsable';
00252 }
00253 $r .= "|- class=\"$class\"\n";
00254 $r .= "!| {$v['name']}\n";
00255 $r .= "|| {$v['value']}\n";
00256 }
00257 }
00258 $r .= '|}';
00259 return $r;
00260 }
00261
00268 public function getContent() {
00269 $this->loadFile();
00270 if( $this->img && !$this->img->isLocal() && 0 == $this->getID() ) {
00271 return '';
00272 }
00273 return Article::getContent();
00274 }
00275
00276 protected function openShowImage() {
00277 global $wgOut, $wgUser, $wgImageLimits, $wgRequest, $wgLang, $wgContLang;
00278
00279 $this->loadFile();
00280
00281 $full_url = $this->displayImg->getURL();
00282 $linkAttribs = false;
00283 $sizeSel = intval( $wgUser->getOption( 'imagesize') );
00284 if( !isset( $wgImageLimits[$sizeSel] ) ) {
00285 $sizeSel = User::getDefaultOption( 'imagesize' );
00286
00287
00288
00289 if( !isset( $wgImageLimits[$sizeSel] ) ) {
00290
00291 $sizeSel = 0;
00292 }
00293 }
00294 $max = $wgImageLimits[$sizeSel];
00295 $maxWidth = $max[0];
00296 $maxHeight = $max[1];
00297 $sk = $wgUser->getSkin();
00298 $dirmark = $wgContLang->getDirMark();
00299
00300 if( $this->displayImg->exists() ) {
00301 # image
00302 $page = $wgRequest->getIntOrNull( 'page' );
00303 if( is_null( $page ) ) {
00304 $params = array();
00305 $page = 1;
00306 } else {
00307 $params = array( 'page' => $page );
00308 }
00309 $width_orig = $this->displayImg->getWidth();
00310 $width = $width_orig;
00311 $height_orig = $this->displayImg->getHeight();
00312 $height = $height_orig;
00313 $mime = $this->displayImg->getMimeType();
00314 $showLink = false;
00315 $linkAttribs = array( 'href' => $full_url );
00316 $longDesc = $this->displayImg->getLongDesc();
00317
00318 wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this , &$wgOut ) ) ;
00319
00320 if( $this->displayImg->allowInlineDisplay() ) {
00321 # image
00322
00323 # "Download high res version" link below the image
00324 #$msgsize = wfMsgHtml('file-info-size', $width_orig, $height_orig, $sk->formatSize( $this->displayImg->getSize() ), $mime );
00325 # We'll show a thumbnail of this image
00326 if( $width > $maxWidth || $height > $maxHeight ) {
00327 # Calculate the thumbnail size.
00328 # First case, the limiting factor is the width, not the height.
00329 if( $width / $height >= $maxWidth / $maxHeight ) {
00330 $height = round( $height * $maxWidth / $width);
00331 $width = $maxWidth;
00332 # Note that $height <= $maxHeight now.
00333 } else {
00334 $newwidth = floor( $width * $maxHeight / $height);
00335 $height = round( $height * $newwidth / $width );
00336 $width = $newwidth;
00337 # Note that $height <= $maxHeight now, but might not be identical
00338 # because of rounding.
00339 }
00340 $msgbig = wfMsgHtml( 'show-big-image' );
00341 $msgsmall = wfMsgExt( 'show-big-image-thumb', 'parseinline',
00342 $wgLang->formatNum( $width ),
00343 $wgLang->formatNum( $height )
00344 );
00345 } else {
00346 # Image is small enough to show full size on image page
00347 $msgbig = htmlspecialchars( $this->displayImg->getName() );
00348 $msgsmall = wfMsgExt( 'file-nohires', array( 'parseinline' ) );
00349 }
00350
00351 $params['width'] = $width;
00352 $thumbnail = $this->displayImg->transform( $params );
00353
00354 $anchorclose = "<br />";
00355 if( $this->displayImg->mustRender() ) {
00356 $showLink = true;
00357 } else {
00358 $anchorclose .=
00359 $msgsmall .
00360 '<br />' . Xml::tags( 'a', $linkAttribs, $msgbig ) . "$dirmark " . $longDesc;
00361 }
00362
00363 if( $this->displayImg->isMultipage() ) {
00364 $wgOut->addHTML( '<table class="multipageimage"><tr><td>' );
00365 }
00366
00367 if( $thumbnail ) {
00368 $options = array(
00369 'alt' => $this->displayImg->getTitle()->getPrefixedText(),
00370 'file-link' => true,
00371 );
00372 $wgOut->addHTML( '<div class="fullImageLink" id="file">' .
00373 $thumbnail->toHtml( $options ) .
00374 $anchorclose . '</div>' );
00375 }
00376
00377 if( $this->displayImg->isMultipage() ) {
00378 $count = $this->displayImg->pageCount();
00379
00380 if( $page > 1 ) {
00381 $label = $wgOut->parse( wfMsg( 'imgmultipageprev' ), false );
00382 $link = $sk->makeKnownLinkObj( $this->mTitle, $label, 'page='. ($page-1) );
00383 $thumb1 = $sk->makeThumbLinkObj( $this->mTitle, $this->displayImg, $link, $label, 'none',
00384 array( 'page' => $page - 1 ) );
00385 } else {
00386 $thumb1 = '';
00387 }
00388
00389 if( $page < $count ) {
00390 $label = wfMsg( 'imgmultipagenext' );
00391 $link = $sk->makeKnownLinkObj( $this->mTitle, $label, 'page='. ($page+1) );
00392 $thumb2 = $sk->makeThumbLinkObj( $this->mTitle, $this->displayImg, $link, $label, 'none',
00393 array( 'page' => $page + 1 ) );
00394 } else {
00395 $thumb2 = '';
00396 }
00397
00398 global $wgScript;
00399
00400 $formParams = array(
00401 'name' => 'pageselector',
00402 'action' => $wgScript,
00403 'onchange' => 'document.pageselector.submit();',
00404 );
00405
00406 $option = array();
00407 for ( $i=1; $i <= $count; $i++ ) {
00408 $options[] = Xml::option( $wgLang->formatNum($i), $i, $i == $page );
00409 }
00410 $select = Xml::tags( 'select',
00411 array( 'id' => 'pageselector', 'name' => 'page' ),
00412 implode( "\n", $options ) );
00413
00414 $wgOut->addHTML(
00415 '</td><td><div class="multipageimagenavbox">' .
00416 Xml::openElement( 'form', $formParams ) .
00417 Xml::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) .
00418 wfMsgExt( 'imgmultigoto', array( 'parseinline', 'replaceafter' ), $select ) .
00419 Xml::submitButton( wfMsg( 'imgmultigo' ) ) .
00420 Xml::closeElement( 'form' ) .
00421 "<hr />$thumb1\n$thumb2<br clear=\"all\" /></div></td></tr></table>"
00422 );
00423 }
00424 } else {
00425 #if direct link is allowed but it's not a renderable image, show an icon.
00426 if( $this->displayImg->isSafeFile() ) {
00427 $icon= $this->displayImg->iconThumb();
00428
00429 $wgOut->addHTML( '<div class="fullImageLink" id="file">' .
00430 $icon->toHtml( array( 'desc-link' => true ) ) .
00431 '</div>' );
00432 }
00433
00434 $showLink = true;
00435 }
00436
00437
00438 if($showLink) {
00439 $filename = wfEscapeWikiText( $this->displayImg->getName() );
00440
00441 if( !$this->displayImg->isSafeFile() ) {
00442 $warning = wfMsgNoTrans( 'mediawarning' );
00443 $wgOut->addWikiText( <<<EOT
00444 <div class="fullMedia">
00445 <span class="dangerousLink">[[Media:$filename|$filename]]</span>$dirmark
00446 <span class="fileInfo"> $longDesc</span>
00447 </div>
00448
00449 <div class="mediaWarning">$warning</div>
00450 EOT
00451 );
00452 } else {
00453 $wgOut->addWikiText( <<<EOT
00454 <div class="fullMedia">
00455 [[Media:$filename|$filename]]$dirmark <span class="fileInfo"> $longDesc</span>
00456 </div>
00457 EOT
00458 );
00459 }
00460 }
00461
00462 if( !$this->displayImg->isLocal() ) {
00463 $this->printSharedImageText();
00464 }
00465 } else {
00466 # Image does not exist
00467
00468 $title = SpecialPage::getTitleFor( 'Upload' );
00469 $link = $sk->makeKnownLinkObj($title, wfMsgHtml('noimage-linktext'),
00470 'wpDestFile=' . urlencode( $this->displayImg->getName() ) );
00471 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00472 $wgOut->addHTML( wfMsgWikiHtml( 'noimage', $link ) );
00473 }
00474 }
00475
00479 protected function printSharedImageText() {
00480 global $wgOut, $wgUser;
00481
00482 $this->loadFile();
00483
00484 $descUrl = $this->img->getDescriptionUrl();
00485 $descText = $this->img->getDescriptionText();
00486 $msg = '';
00487 if( $descUrl ) {
00488 $sk = $wgUser->getSkin();
00489 $link = $sk->makeExternalLink( $descUrl, wfMsg( 'shareduploadwiki-linktext' ) );
00490 $msg = ( $descText ) ? 'shareduploadwiki-desc' : 'shareduploadwiki';
00491 $msg = wfMsgExt( $msg, array( 'parseinline', 'replaceafter' ), $link );
00492 if( $msg == '-' ) {
00493 $msg = '';
00494 }
00495 }
00496 $s = "<div class='sharedUploadNotice'>";
00497 $s .= wfMsgWikiHtml( 'sharedupload', $this->img->getRepo()->getDisplayName(), $msg );
00498 $s .= "</div>";
00499 $wgOut->addHTML( $s );
00500
00501 if( $descText ) {
00502 $this->mExtraDescription = $descText;
00503 }
00504 }
00505
00506 public function getUploadUrl() {
00507 $this->loadFile();
00508 $uploadTitle = SpecialPage::getTitleFor( 'Upload' );
00509 return $uploadTitle->getFullUrl( 'wpDestFile=' . urlencode( $this->img->getName() ) . '&wpForReUpload=1' );
00510 }
00511
00516 protected function uploadLinksBox() {
00517 global $wgUser, $wgOut;
00518
00519 $this->loadFile();
00520 if( !$this->img->isLocal() )
00521 return;
00522
00523 $sk = $wgUser->getSkin();
00524
00525 $wgOut->addHTML( '<br /><ul>' );
00526
00527 # "Upload a new version of this file" link
00528 if( UploadForm::userCanReUpload($wgUser,$this->img->name) ) {
00529 $ulink = $sk->makeExternalLink( $this->getUploadUrl(), wfMsg( 'uploadnewversion-linktext' ) );
00530 $wgOut->addHTML( "<li><div class='plainlinks'>{$ulink}</div></li>" );
00531 }
00532
00533 # External editing link
00534 $elink = $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'edit-externally' ), 'action=edit&externaledit=true&mode=file' );
00535 $wgOut->addHTML( '<li>' . $elink . ' <small>' . wfMsgExt( 'edit-externally-help', array( 'parseinline' ) ) . '</small></li>' );
00536
00537 $wgOut->addHTML( '</ul>' );
00538 }
00539
00540 protected function closeShowImage() {} # For overloading
00541
00546 protected function imageHistory() {
00547 global $wgOut, $wgUseExternalEditor;
00548
00549 $this->loadFile();
00550 $pager = new ImageHistoryPseudoPager( $this );
00551 $wgOut->addHTML( $pager->getBody() );
00552
00553 $this->img->resetHistory();
00554
00555 # Exist check because we don't want to show this on pages where an image
00556 # doesn't exist along with the noimage message, that would suck. -ævar
00557 if( $wgUseExternalEditor && $this->img->exists() ) {
00558 $this->uploadLinksBox();
00559 }
00560 }
00561
00562 protected function imageLinks() {
00563 global $wgUser, $wgOut, $wgLang;
00564
00565 $limit = 100;
00566
00567 $dbr = wfGetDB( DB_SLAVE );
00568
00569 $res = $dbr->select(
00570 array( 'imagelinks', 'page' ),
00571 array( 'page_namespace', 'page_title' ),
00572 array( 'il_to' => $this->mTitle->getDBkey(), 'il_from = page_id' ),
00573 __METHOD__,
00574 array( 'LIMIT' => $limit + 1)
00575 );
00576 $count = $dbr->numRows( $res );
00577 if( $count == 0 ) {
00578 $wgOut->addHTML( "<div id='mw-imagepage-nolinkstoimage'>\n" );
00579 $wgOut->addWikiMsg( 'nolinkstoimage' );
00580 $wgOut->addHTML( "</div>\n" );
00581 return;
00582 }
00583
00584 $wgOut->addHTML( "<div id='mw-imagepage-section-linkstoimage'>\n" );
00585 if( $count <= $limit - 1 ) {
00586 $wgOut->addWikiMsg( 'linkstoimage', $count );
00587 } else {
00588
00589 $wgOut->addWikiMsg( 'linkstoimage-more',
00590 $wgLang->formatNum( $limit ),
00591 $this->mTitle->getPrefixedDBkey()
00592 );
00593 }
00594
00595 $wgOut->addHTML( "<ul class='mw-imagepage-linkstoimage'>\n" );
00596 $sk = $wgUser->getSkin();
00597 $count = 0;
00598 while ( $s = $res->fetchObject() ) {
00599 $count++;
00600 if( $count <= $limit ) {
00601
00602 $name = Title::makeTitle( $s->page_namespace, $s->page_title );
00603 $link = $sk->makeKnownLinkObj( $name, "" );
00604 $wgOut->addHTML( "<li>{$link}</li>\n" );
00605 }
00606 }
00607 $wgOut->addHTML( "</ul></div>\n" );
00608 $res->free();
00609
00610
00611 if( $count > $limit )
00612 $wgOut->addWikiMsg( 'morelinkstoimage', $this->mTitle->getPrefixedDBkey() );
00613 }
00614
00615 protected function imageRedirects() {
00616 global $wgUser, $wgOut, $wgLang;
00617
00618 $redirects = $this->getTitle()->getRedirectsHere( NS_FILE );
00619 if( count( $redirects ) == 0 ) return;
00620
00621 $wgOut->addHTML( "<div id='mw-imagepage-section-redirectstofile'>\n" );
00622 $wgOut->addWikiMsg( 'redirectstofile',
00623 $wgLang->formatNum( count( $redirects ) )
00624 );
00625 $wgOut->addHTML( "<ul class='mw-imagepage-redirectstofile'>\n" );
00626
00627 $sk = $wgUser->getSkin();
00628 foreach ( $redirects as $title ) {
00629 $link = $sk->makeKnownLinkObj( $title, "", "redirect=no" );
00630 $wgOut->addHTML( "<li>{$link}</li>\n" );
00631 }
00632 $wgOut->addHTML( "</ul></div>\n" );
00633
00634 }
00635
00636 protected function imageDupes() {
00637 global $wgOut, $wgUser, $wgLang;
00638
00639 $this->loadFile();
00640
00641 $dupes = $this->getDuplicates();
00642 if( count( $dupes ) == 0 ) return;
00643
00644 $wgOut->addHTML( "<div id='mw-imagepage-section-duplicates'>\n" );
00645 $wgOut->addWikiMsg( 'duplicatesoffile',
00646 $wgLang->formatNum( count( $dupes ) ), $this->mTitle->getDBkey()
00647 );
00648 $wgOut->addHTML( "<ul class='mw-imagepage-duplicates'>\n" );
00649
00650 $sk = $wgUser->getSkin();
00651 foreach ( $dupes as $file ) {
00652 $fromSrc = '';
00653 if( $file->isLocal() )
00654 $link = $sk->makeKnownLinkObj( $file->getTitle(), "" );
00655 else {
00656 $link = $sk->makeExternalLink( $file->getDescriptionUrl(),
00657 $file->getTitle()->getPrefixedText() );
00658 $fromSrc = wfMsg( 'shared-repo-from', $file->getRepo()->getDisplayName() );
00659 }
00660 $wgOut->addHTML( "<li>{$link} {$fromSrc}</li>\n" );
00661 }
00662 $wgOut->addHTML( "</ul></div>\n" );
00663 }
00664
00668 public function delete() {
00669 $this->loadFile();
00670 if( !$this->img->exists() || !$this->img->isLocal() || $this->img->getRedirected() ) {
00671
00672 Article::delete();
00673 return;
00674 }
00675 $deleter = new FileDeleteForm( $this->img );
00676 $deleter->execute();
00677 }
00678
00682 public function revert() {
00683 $this->loadFile();
00684 $reverter = new FileRevertForm( $this->img );
00685 $reverter->execute();
00686 }
00687
00691 public function doPurge() {
00692 $this->loadFile();
00693 if( $this->img->exists() ) {
00694 wfDebug( "ImagePage::doPurge purging " . $this->img->getName() . "\n" );
00695 $update = new HTMLCacheUpdate( $this->mTitle, 'imagelinks' );
00696 $update->doUpdate();
00697 $this->img->upgradeRow();
00698 $this->img->purgeCache();
00699 } else {
00700 wfDebug( "ImagePage::doPurge no image\n" );
00701 }
00702 parent::doPurge();
00703 }
00704
00708 function showError( $description ) {
00709 global $wgOut;
00710 $wgOut->setPageTitle( wfMsg( "internalerror" ) );
00711 $wgOut->setRobotPolicy( "noindex,nofollow" );
00712 $wgOut->setArticleRelated( false );
00713 $wgOut->enableClientCache( false );
00714 $wgOut->addWikiText( $description );
00715 }
00716
00717 }
00718
00724 class ImageHistoryList {
00725
00726 protected $imagePage, $img, $skin, $title, $repo;
00727
00728 public function __construct( $imagePage ) {
00729 global $wgUser;
00730 $this->skin = $wgUser->getSkin();
00731 $this->current = $imagePage->getFile();
00732 $this->img = $imagePage->getDisplayedFile();
00733 $this->title = $imagePage->getTitle();
00734 $this->imagePage = $imagePage;
00735 }
00736
00737 public function getImagePage() {
00738 return $this->imagePage;
00739 }
00740
00741 public function getSkin() {
00742 return $this->skin;
00743 }
00744
00745 public function getFile() {
00746 return $this->img;
00747 }
00748
00749 public function beginImageHistoryList( $navLinks = '' ) {
00750 global $wgOut, $wgUser;
00751 return Xml::element( 'h2', array( 'id' => 'filehistory' ), wfMsg( 'filehist' ) )
00752 . $wgOut->parse( wfMsgNoTrans( 'filehist-help' ) )
00753 . $navLinks
00754 . Xml::openElement( 'table', array( 'class' => 'filehistory' ) ) . "\n"
00755 . '<tr><td></td>'
00756 . ( $this->current->isLocal() && ($wgUser->isAllowed('delete') || $wgUser->isAllowed('deleterevision') ) ? '<td></td>' : '' )
00757 . '<th>' . wfMsgHtml( 'filehist-datetime' ) . '</th>'
00758 . '<th>' . wfMsgHtml( 'filehist-thumb' ) . '</th>'
00759 . '<th>' . wfMsgHtml( 'filehist-dimensions' ) . '</th>'
00760 . '<th>' . wfMsgHtml( 'filehist-user' ) . '</th>'
00761 . '<th>' . wfMsgHtml( 'filehist-comment' ) . '</th>'
00762 . "</tr>\n";
00763 }
00764
00765 public function endImageHistoryList( $navLinks = '' ) {
00766 return "</table>\n$navLinks\n";
00767 }
00768
00769 public function imageHistoryLine( $iscur, $file ) {
00770 global $wgUser, $wgLang, $wgContLang, $wgTitle;
00771
00772 $timestamp = wfTimestamp(TS_MW, $file->getTimestamp());
00773 $img = $iscur ? $file->getName() : $file->getArchiveName();
00774 $user = $file->getUser('id');
00775 $usertext = $file->getUser('text');
00776 $size = $file->getSize();
00777 $description = $file->getDescription();
00778 $dims = $file->getDimensionsString();
00779 $sha1 = $file->getSha1();
00780
00781 $local = $this->current->isLocal();
00782 $row = $css = $selected = '';
00783
00784
00785 if( $local && ($wgUser->isAllowed('delete') || $wgUser->isAllowed('deleterevision') ) ) {
00786 $row .= '<td>';
00787 # Link to remove from history
00788 if( $wgUser->isAllowed( 'delete' ) ) {
00789 $q = array();
00790 $q[] = 'action=delete';
00791 if( !$iscur )
00792 $q[] = 'oldimage=' . urlencode( $img );
00793 $row .= $this->skin->makeKnownLinkObj(
00794 $this->title,
00795 wfMsgHtml( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' ),
00796 implode( '&', $q )
00797 );
00798 }
00799 # Link to hide content
00800 if( $wgUser->isAllowed( 'deleterevision' ) ) {
00801 if( $wgUser->isAllowed('delete') ) {
00802 $row .= '<br/>';
00803 }
00804 $revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
00805
00806 if( $iscur || !$file->userCan(File::DELETED_RESTRICTED) ) {
00807 $del = wfMsgHtml( 'rev-delundel' );
00808 } else {
00809
00810 list($ts,$name) = explode('!',$img,2);
00811 $del = $this->skin->makeKnownLinkObj( $revdel, wfMsg( 'rev-delundel' ),
00812 'target=' . urlencode( $wgTitle->getPrefixedText() ) .
00813 '&oldimage=' . urlencode( $ts ) );
00814
00815 if( $file->isDeleted(File::DELETED_RESTRICTED) )
00816 $del = "<strong>$del</strong>";
00817 }
00818 $row .= "<tt style='white-space: nowrap;'><small>$del</small></tt>";
00819 }
00820 $row .= '</td>';
00821 }
00822
00823
00824 $row .= '<td>';
00825 if( $iscur ) {
00826 $row .= wfMsgHtml( 'filehist-current' );
00827 } elseif( $local && $wgUser->isLoggedIn() && $this->title->userCan( 'edit' ) ) {
00828 if( $file->isDeleted(File::DELETED_FILE) ) {
00829 $row .= wfMsgHtml('filehist-revert');
00830 } else {
00831 $q = array();
00832 $q[] = 'action=revert';
00833 $q[] = 'oldimage=' . urlencode( $img );
00834 $q[] = 'wpEditToken=' . urlencode( $wgUser->editToken( $img ) );
00835 $row .= $this->skin->makeKnownLinkObj( $this->title,
00836 wfMsgHtml( 'filehist-revert' ),
00837 implode( '&', $q ) );
00838 }
00839 }
00840 $row .= '</td>';
00841
00842
00843 if( $file->getTimestamp() === $this->img->getTimestamp() ) {
00844 $selected = "class='filehistory-selected'";
00845 }
00846 $row .= "<td $selected style='white-space: nowrap;'>";
00847 if( !$file->userCan(File::DELETED_FILE) ) {
00848 # Don't link to unviewable files
00849 $row .= '<span class="history-deleted">' . $wgLang->timeAndDate( $timestamp, true ) . '</span>';
00850 } else if( $file->isDeleted(File::DELETED_FILE) ) {
00851 $revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
00852 # Make a link to review the image
00853 $url = $this->skin->makeKnownLinkObj( $revdel, $wgLang->timeAndDate( $timestamp, true ),
00854 "target=".$wgTitle->getPrefixedText()."&file=$sha1.".$this->current->getExtension() );
00855 $row .= '<span class="history-deleted">'.$url.'</span>';
00856 } else {
00857 $url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
00858 $row .= Xml::element( 'a', array( 'href' => $url ), $wgLang->timeAndDate( $timestamp, true ) );
00859 }
00860
00861
00862 if( $file->allowInlineDisplay() && $file->userCan( File::DELETED_FILE ) && !$file->isDeleted( File::DELETED_FILE ) ) {
00863 $params = array(
00864 'width' => '120',
00865 'height' => '120',
00866 );
00867 $thumbnail = $file->transform( $params );
00868 $options = array(
00869 'alt' => wfMsg( 'filehist-thumbtext', $wgLang->timeAndDate( $timestamp, true ) ),
00870 'file-link' => true,
00871 );
00872 $row .= '</td><td>' . ( $thumbnail ? $thumbnail->toHtml( $options ) :
00873 wfMsgHtml( 'filehist-nothumb' ) );
00874 } else {
00875 $row .= '</td><td>' . wfMsgHtml( 'filehist-nothumb' );
00876 }
00877 $row .= "</td><td>";
00878
00879
00880 $row .= htmlspecialchars( $dims );
00881
00882
00883 $row .= " <span style='white-space: nowrap;'>(" . $this->skin->formatSize( $size ) . ')</span>';
00884
00885
00886 $row .= '</td><td>';
00887 if( $local ) {
00888
00889 if( $file->isDeleted(File::DELETED_USER) ) {
00890 $row .= '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>';
00891 } else {
00892 $row .= $this->skin->userLink( $user, $usertext ) . " <span style='white-space: nowrap;'>" .
00893 $this->skin->userToolLinks( $user, $usertext ) . "</span>";
00894 }
00895 } else {
00896 $row .= htmlspecialchars( $usertext );
00897 }
00898 $row .= '</td><td>';
00899
00900
00901 if( $file->isDeleted(File::DELETED_COMMENT) ) {
00902 $row .= '<span class="history-deleted">' . wfMsgHtml('rev-deleted-comment') . '</span>';
00903 } else {
00904 $row .= $this->skin->commentBlock( $description, $this->title );
00905 }
00906 $row .= '</td>';
00907
00908 wfRunHooks( 'ImagePageFileHistoryLine', array( $this, $file, &$row, &$rowClass ) );
00909 $classAttr = $rowClass ? " class='$rowClass'" : "";
00910
00911 return "<tr{$classAttr}>{$row}</tr>\n";
00912 }
00913 }
00914
00915 class ImageHistoryPseudoPager extends ReverseChronologicalPager {
00916 function __construct( $imagePage ) {
00917 parent::__construct();
00918 $this->mImagePage = $imagePage;
00919 $this->mTitle = clone( $imagePage->getTitle() );
00920 $this->mTitle->setFragment( '#filehistory' );
00921 $this->mImg = NULL;
00922 $this->mHist = array();
00923 $this->mRange = array( 0, 0 );
00924 }
00925
00926 function getTitle() {
00927 return $this->mTitle;
00928 }
00929
00930 function getQueryInfo() {
00931 return false;
00932 }
00933
00934 function getIndexField() {
00935 return '';
00936 }
00937
00938 function formatRow( $row ) {
00939 return '';
00940 }
00941
00942 function getBody() {
00943 $s = '';
00944 $this->doQuery();
00945 if( count($this->mHist) ) {
00946 $list = new ImageHistoryList( $this->mImagePage );
00947 # Generate prev/next links
00948 $navLink = $this->getNavigationBar();
00949 $s = $list->beginImageHistoryList($navLink);
00950
00951 for( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
00952 $file = $this->mHist[$i];
00953 $s .= $list->imageHistoryLine( !$file->isOld(), $file );
00954 }
00955 $s .= $list->endImageHistoryList($navLink);
00956 }
00957 return $s;
00958 }
00959
00960 function doQuery() {
00961 if( $this->mQueryDone ) return;
00962 $this->mImg = $this->mImagePage->getFile();
00963 if( !$this->mImg->exists() ) {
00964 return;
00965 }
00966 $queryLimit = $this->mLimit + 1;
00967 if( $this->mIsBackwards ) {
00968
00969 $this->mHist = $this->mImg->getHistory($queryLimit,null,$this->mOffset,false);
00970
00971 $numRows = count($this->mHist);
00972 if( $numRows <= $this->mLimit && $this->mImg->getTimestamp() > $this->mOffset ) {
00973 $this->mHist = array_merge( array($this->mImg), $this->mHist );
00974 }
00975 } else {
00976
00977 if( !$this->mOffset || $this->mImg->getTimestamp() < $this->mOffset ) {
00978 $this->mHist[] = $this->mImg;
00979 }
00980
00981 $oiLimit = count($this->mHist) ? $this->mLimit : $this->mLimit+1;
00982
00983 $this->mHist = array_merge( $this->mHist,
00984 $this->mImg->getHistory($oiLimit,$this->mOffset,null,false) );
00985 }
00986 $numRows = count($this->mHist);
00987 if( $numRows ) {
00988 # Index value of top item in the list
00989 $firstIndex = $this->mIsBackwards ?
00990 $this->mHist[$numRows-1]->getTimestamp() : $this->mHist[0]->getTimestamp();
00991 # Discard the extra result row if there is one
00992 if( $numRows > $this->mLimit && $numRows > 1 ) {
00993 if( $this->mIsBackwards ) {
00994 # Index value of item past the index
00995 $this->mPastTheEndIndex = $this->mHist[0]->getTimestamp();
00996 # Index value of bottom item in the list
00997 $lastIndex = $this->mHist[1]->getTimestamp();
00998 # Display range
00999 $this->mRange = array( 1, $numRows-1 );
01000 } else {
01001 # Index value of item past the index
01002 $this->mPastTheEndIndex = $this->mHist[$numRows-1]->getTimestamp();
01003 # Index value of bottom item in the list
01004 $lastIndex = $this->mHist[$numRows-2]->getTimestamp();
01005 # Display range
01006 $this->mRange = array( 0, $numRows-2 );
01007 }
01008 } else {
01009 # Setting indexes to an empty string means that they will be
01010 # omitted if they would otherwise appear in URLs. It just so
01011 # happens that this is the right thing to do in the standard
01012 # UI, in all the relevant cases.
01013 $this->mPastTheEndIndex = '';
01014 # Index value of bottom item in the list
01015 $lastIndex = $this->mIsBackwards ?
01016 $this->mHist[0]->getTimestamp() : $this->mHist[$numRows-1]->getTimestamp();
01017 # Display range
01018 $this->mRange = array( 0, $numRows-1 );
01019 }
01020 } else {
01021 $firstIndex = '';
01022 $lastIndex = '';
01023 $this->mPastTheEndIndex = '';
01024 }
01025 if( $this->mIsBackwards ) {
01026 $this->mIsFirst = ( $numRows < $queryLimit );
01027 $this->mIsLast = ( $this->mOffset == '' );
01028 $this->mLastShown = $firstIndex;
01029 $this->mFirstShown = $lastIndex;
01030 } else {
01031 $this->mIsFirst = ( $this->mOffset == '' );
01032 $this->mIsLast = ( $numRows < $queryLimit );
01033 $this->mLastShown = $lastIndex;
01034 $this->mFirstShown = $firstIndex;
01035 }
01036 $this->mQueryDone = true;
01037 }
01038 }