Seditio Source
Root |
./othercms/ips_4.3.4/applications/gallery/modules/front/gallery/view.php
<?php
/**
 * @brief        View image
 * @author        <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
 * @copyright    (c) Invision Power Services, Inc.
 * @license        https://www.invisioncommunity.com/legal/standards/
 * @package        Invision Community
 * @subpackage    Gallery
 * @since        04 Mar 2014
 */

namespace IPS\gallery\modules\front\gallery;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
   
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * View image or movie
 */
class _view extends \IPS\Content\Controller
{
   
/**
     * [Content\Controller]    Class
     */
   
protected static $contentModel = 'IPS\gallery\Image';
   
   
/**
     * @brief    Should views and item markers be updated by AJAX requests?
     * @note    For Gallery images, AJAX requests handle the next/previous links and using those needs to mark as read, etc.
     */
   
protected $updateViewsAndMarkersOnAjax = TRUE;

   
/**
     * Init
     *
     * @return    void
     */
   
public function execute()
    {
        if ( \
IPS\Request::i()->do != 'embed' )
        {
            try
            {
               
$this->image = \IPS\gallery\Image::load( \IPS\Request::i()->id );
               
                if ( !
$this->image->canView( \IPS\Member::loggedIn() ) )
                {
                    \
IPS\Output::i()->error( $this->image->container()->errorMessage(), '2G188/1', 403, '' );
                }                
            }
            catch ( \
OutOfRangeException $e )
            {
                \
IPS\Output::i()->error( 'node_error', '2G188/2', 404, '' );
            }
        }

       
parent::execute();
    }
   
   
/**
     * View Image
     *
     * @return    void
     * @link    http://www.videojs.com/projects/mimes.html
     * @note    Only HTML5 and some flash-based video formats will work. MP4, webm and ogg are relatively safe bets but anything else isn't likely to play correctly.
     *    The above link will allow you to check what is supported in the browser you are using.
     * @note    As of RC1 we fall back to a generic 'embed' for non-standard formats for better upgrade compatibility...need to look into transcoding in the future
     */
   
protected function manage()
    {
       
/* Init */
       
parent::manage();

       
/* Check restrictions */
       
if( \IPS\Settings::i()->gallery_detailed_bandwidth AND ( \IPS\Member::loggedIn()->group['g_max_transfer'] OR \IPS\Member::loggedIn()->group['g_max_views'] ) )
        {
           
$lastDay        = \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp();

            if( \
IPS\Member::loggedIn()->group['g_max_views'] )
            {
                if( \
IPS\Db::i()->select( 'COUNT(*) as total', 'gallery_bandwidth', array( 'member_id=? AND bdate > ?', (int) \IPS\Member::loggedIn()->member_id, $lastDay ) )->first() >= \IPS\Member::loggedIn()->group['g_max_views'] )
                {
                    \
IPS\Output::i()->error( 'maximum_daily_views', '1G188/7', 403, 'maximum_daily_views_admin' );
                }
            }

            if( \
IPS\Member::loggedIn()->group['g_max_transfer'] )
            {
                if( \
IPS\Db::i()->select( 'SUM(bsize) as total', 'gallery_bandwidth', array( 'member_id=? AND bdate > ?', (int) \IPS\Member::loggedIn()->member_id, $lastDay ) )->first() >= ( \IPS\Member::loggedIn()->group['g_max_transfer'] * 1024 ) )
                {
                    \
IPS\Output::i()->error( 'maximum_daily_transfer', '1G188/8', 403, 'maximum_daily_transfer_admin' );
                }
            }
        }

       
/* Set some meta tags */
       
if( $this->image->media )
        {
            \
IPS\Output::i()->metaTags['og:video']        = \IPS\File::get( 'gallery_Images', $this->image->original_file_name )->url;
            \
IPS\Output::i()->metaTags['og:video:type']    = $this->image->file_type;
            \
IPS\Output::i()->metaTags['og:type']        = 'video';

            if(
count( $this->image->tags() ) )
            {
                \
IPS\Output::i()->metaTags['og:video:tag']    = $this->image->tags();
            }

            if(
$this->image->masked_file_name )
            {
                \
IPS\Output::i()->metaTags['og:image']        = \IPS\File::get( 'gallery_Images', $this->image->masked_file_name )->url;
            }
        }
        else
        {
            \
IPS\Output::i()->metaTags['og:image']        = \IPS\File::get( 'gallery_Images', $this->image->masked_file_name )->url;
            \
IPS\Output::i()->metaTags['og:image:type']    = $this->image->file_type;

            if(
count( $this->image->tags() ) )
            {
                \
IPS\Output::i()->metaTags['og:object:tag']    = $this->image->tags();
            }
        }

        \
IPS\Output::i()->linkTags[]    = array(
           
'rel'    => 'preload',
           
'href'    => (string) \IPS\File::get( 'gallery_Images', $this->image->masked_file_name )->url,
           
'as'    => $this->image->media ? 'video' : 'image',
           
'type'    => $this->image->file_type
       
);

       
/* Sort out comments and reviews */
       
$tabs = $this->image->commentReviewTabs();
       
$_tabs = array_keys( $tabs );
       
$tab = isset( \IPS\Request::i()->tab ) ? \IPS\Request::i()->tab : array_shift( $_tabs );
       
$activeTabContents = $this->image->commentReviews( $tab, \IPS\Request::i()->lightbox );

        if (
count( $tabs ) > 1 )
        {
           
$commentsAndReviews = count( $tabs ) ? \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $tab, $activeTabContents, \IPS\Request::i()->lightbox ? $this->image->url()->setQueryString( 'lightbox', 1 ) : $this->image->url(), 'tab', FALSE, TRUE, \IPS\Request::i()->lightbox ? 'ipsTabs_small ipsTabs_stretch' : '' ) : NULL;
        }
        else
        {
           
$commentsAndReviews = $activeTabContents;
        }

       
/* Set the session location */
       
\IPS\Session::i()->setLocation( $this->image->url(), $this->image->onlineListPermissions(), 'loc_gallery_viewing_image', array( $this->image->caption => FALSE ) );

       
/* Store bandwidth log */
       
if( \IPS\Settings::i()->gallery_detailed_bandwidth )
        {
           
/* Media items should get the file size of the original file instead of a thumbnail */
           
if( $this->image->media )
            {
               
$displayedImage = \IPS\File::get( 'gallery_Images', $this->image->original_file_name );
            }
           
/* Otherwise, fetch the thumbnails */
           
else
            {
               
$displayedImage    = \IPS\File::get( 'gallery_Images', $this->image->masked_file_name );
            }

           
/* Get filesize, but don't error out if there is a problem fetching it at this point */
           
try
            {
               
$filesize = ( ( isset( $displayedImage ) AND $displayedImage->filesize() ) ? $displayedImage->filesize() : $this->image->file_size );
            }
            catch( \
Exception $e )
            {
               
$filesize = $this->image->file_size;
            }

            \
IPS\Db::i()->insert( 'gallery_bandwidth', array(
               
'member_id'        => (int) \IPS\Member::loggedIn()->member_id,
               
'bdate'            => time(),
               
'bsize'            => (int) $filesize,
               
'image_id'        => $this->image->id
           
)    );
        }

       
/* Add JSON-ld */
       
\IPS\Output::i()->jsonLd['gallery']    = array(
           
'@context'        => "http://schema.org",
           
'@type'            => $this->image->media ? "VideoObject" : "VisualArtwork",
           
'@id'            => (string) $this->image->url(),
           
'url'            => (string) $this->image->url(),
           
'name'            => $this->image->mapped('title'),
           
'description'    => strip_tags( $this->image->truncated() ),
           
'dateCreated'    => \IPS\DateTime::ts( $this->image->date )->format( \IPS\DateTime::ISO8601 ),
           
'fileFormat'    => $this->image->file_type,
           
'keywords'        => $this->image->tags(),
           
'author'        => array(
               
'@type'        => 'Person',
               
'name'        => \IPS\Member::load( $this->image->member_id )->name,
               
'image'        => \IPS\Member::load( $this->image->member_id )->get_photo()
            ),
           
'interactionStatistic'    => array(
                array(
                   
'@type'                    => 'InteractionCounter',
                   
'interactionType'        => "http://schema.org/ViewAction",
                   
'userInteractionCount'    => $this->image->views
               
)
            )
        );

       
/* Do we have a real author? */
       
if( $this->image->member_id )
        {
            \
IPS\Output::i()->jsonLd['gallery']['author']['url']    = (string) \IPS\Member::load( $this->image->member_id )->url();
        }

        if (
$this->image->container()->allow_comments AND $this->image->directContainer()->allow_comments )
        {
            \
IPS\Output::i()->jsonLd['gallery']['interactionStatistic'][] = array(
               
'@type'                    => 'InteractionCounter',
               
'interactionType'        => "http://schema.org/CommentAction",
               
'userInteractionCount'    => $this->image->mapped('num_comments')
            );

            \
IPS\Output::i()->jsonLd['gallery']['commentCount'] = $this->image->mapped('num_comments');
        }

        if (
$this->image->container()->allow_reviews AND $this->image->directContainer()->allow_reviews )
        {
            \
IPS\Output::i()->jsonLd['gallery']['interactionStatistic'][] = array(
               
'@type'                    => 'InteractionCounter',
               
'interactionType'        => "http://schema.org/ReviewAction",
               
'userInteractionCount'    => $this->image->mapped('num_reviews')
            );

            \
IPS\Output::i()->jsonLd['gallery']['aggregateRating'] = array(
               
'@type'            => 'AggregateRating',
               
'ratingValue'    => $this->image->averageReviewRating(),
               
'reviewCount'    => $this->image->reviews,
               
'bestRating'    => \IPS\Settings::i()->reviews_rating_out_of
           
);
        }

        if(
$this->image->media )
        {
            if(
$this->image->masked_file_name )
            {
                \
IPS\Output::i()->jsonLd['gallery']['thumbnail']    = (string) \IPS\File::get( 'gallery_Images', $this->image->masked_file_name )->url;
                \
IPS\Output::i()->jsonLd['gallery']['thumbnailUrl']    = (string) \IPS\File::get( 'gallery_Images', $this->image->masked_file_name )->url;
            }

            \
IPS\Output::i()->jsonLd['gallery']['contentSize'] = (string) \IPS\File::get( 'gallery_Images', $this->image->original_file_name )->filesize();
        }
        else
        {
            try
            {
               
$largeFile    = \IPS\File::get( 'gallery_Images', $this->image->masked_file_name );
               
$dimensions    = $this->image->_dimensions;

                \
IPS\Output::i()->jsonLd['gallery']['artMedium']    = 'Digital';
                \
IPS\Output::i()->jsonLd['gallery']['width']         = $dimensions['large'][0];
                \
IPS\Output::i()->jsonLd['gallery']['height']         = $dimensions['large'][1];
                \
IPS\Output::i()->jsonLd['gallery']['image']        = array(
                   
'@type'        => 'ImageObject',
                   
'url'        => (string) $largeFile->url,
                   
'caption'    => $this->image->mapped('title'),
                   
'thumbnail'    => (string) \IPS\File::get( 'gallery_Images', $this->image->small_file_name )->url,
                   
'width'        => $dimensions['large'][0],
                   
'height'    => $dimensions['large'][1],
                );

                if(
count( $this->image->metadata ) )
                {
                    \
IPS\Output::i()->jsonLd['gallery']['image']['exifData'] = array();

                    foreach(
$this->image->metadata as $k => $v )
                    {
                        \
IPS\Output::i()->jsonLd['gallery']['image']['exifData'][] = array(
                           
'@type'        => 'PropertyValue',
                           
'name'        => $k,
                           
'value'        => $v
                       
);
                    }
                }
                \
IPS\Output::i()->jsonLd['gallery']['thumbnailUrl']    = (string) \IPS\File::get( 'gallery_Images', $this->image->small_file_name )->url;
            }
           
/* File doesn't exist */
           
catch ( \RuntimeException $e ){}
        }

       
/* Display */
       
if( \IPS\Request::i()->isAjax() && isset( \IPS\Request::i()->browse ) )
        {
           
$return = array(
               
'title' => htmlspecialchars( $this->image->mapped('title'), ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
               
'image' => \IPS\Request::i()->lightbox ? \IPS\Theme::i()->getTemplate( 'view' )->imageLightboxFrame( $this->image ) : \IPS\Theme::i()->getTemplate( 'view' )->imageFrame( $this->image ),
               
'info' => \IPS\Request::i()->lightbox ? \IPS\Theme::i()->getTemplate( 'view' )->imageLightboxInfo( $this->image, $commentsAndReviews ) : \IPS\Theme::i()->getTemplate( 'view' )->imageInfo( $this->image )
            );

            if(
$this->image->directContainer()->allow_comments )
            {
               
$return['comments'] = $commentsAndReviews;
            }

            \
IPS\Output::i()->json( $return );
        }
       
/* Switching comments only */
       
elseif( \IPS\Request::i()->isAjax() AND !isset( \IPS\Request::i()->rating_submitted ) AND \IPS\Request::i()->tab )
        {
            \
IPS\Output::i()->output = $activeTabContents;
            return;
        }
        else
        {
            \
IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_view.js', 'gallery' ) );
            \
IPS\Output::i()->jsFiles    = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_browse.js', 'gallery' ) );

            if( \
IPS\Request::i()->lightbox )
            {
                \
IPS\Output::i()->sidebar['enabled'] = FALSE;
                \
IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'view' )->imageLightbox( $this->image, $commentsAndReviews );
                return;
            }
            else
            {
                \
IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'view' )->image( $this->image, $commentsAndReviews );
            }
        }
    }

   
/**
     * Download the full size image
     *
     * @return    void
     */
   
protected function download()
    {
        try
        {
           
/* Get file and data */
           
$file        = \IPS\File::get( 'gallery_Images', $this->image->original_file_name ?: $this->image->masked_file_name );
           
$headers    = array_merge( \IPS\Output::getCacheHeaders( time(), 360 ), array( "Content-Disposition" => \IPS\Output::getContentDisposition( 'attachment', $file->originalFilename ), "X-Content-Type-Options" => "nosniff" ) );

           
/* Send headers and print file */
           
\IPS\Output::i()->sendStatusCodeHeader( 200 );
            \
IPS\Output::i()->sendHeader( "Content-type: " . \IPS\File::getMimeType( $file->originalFilename ) . ";charset=UTF-8" );

            foreach(
$headers as $key => $header )
            {
                \
IPS\Output::i()->sendHeader( $key . ': ' . $header );
            }

            \
IPS\Output::i()->sendHeader( "Content-Length: " . $file->filesize() );

           
$file->printFile();
            exit;
        }
        catch ( \
UnderflowException $e )
        {
            \
IPS\Output::i()->sendOutput( '', 404 );
        }
    }

   
/**
     * View all of the metadata for this image
     *
     * @return    void
     */
   
protected function metadata()
    {
       
/* Set navigation and title */
       
$this->_setBreadcrumbAndTitle( $this->image );

        \
IPS\Output::i()->title        = \IPS\Member::loggedIn()->language()->addToStack( 'gallery_metadata', FALSE, array( 'sprintf' => $this->image->caption ) );
        \
IPS\Output::i()->output    = \IPS\Theme::i()->getTemplate( 'view' )->metadata( $this->image );
    }

   
/**
     * Set this image as a cover photo
     *
     * @return    void
     */
   
protected function cover()
    {
        switch( \
IPS\Request::i()->set )
        {
            case
'album':
               
$check = $this->image->canSetAsAlbumCover();
            break;

            case
'category':
               
$check = $this->image->canSetAsCategoryCover();
            break;

            case
'both':
               
$check = ( $this->image->canSetAsAlbumCover() AND $this->image->canSetAsCategoryCover() );
            break;
        }

        if ( !
$check )
        {
            \
IPS\Output::i()->error( 'node_error', '2G188/5', 403, '' );
        }

        \
IPS\Session::i()->csrfCheck();
       
$lang = '';

        if(
$this->image->canSetAsAlbumCover() && ( \IPS\Request::i()->set == 'album' or \IPS\Request::i()->set == 'both' ) )
        {
           
$this->image->directContainer()->cover_img_id    = $this->image->id;
           
$this->image->directContainer()->save();

           
$lang = \IPS\Member::loggedIn()->language()->addToStack('set_as_album_done');
        }

        if(
$this->image->canSetAsCategoryCover() && ( \IPS\Request::i()->set == 'category' or \IPS\Request::i()->set == 'both' ) )
        {
           
$this->image->container()->cover_img_id    = $this->image->id;
           
$this->image->container()->save();

            if(
$lang )
            {
               
$lang = \IPS\Member::loggedIn()->language()->addToStack('set_as_both_done');
            }
            else
            {
               
$lang = \IPS\Member::loggedIn()->language()->addToStack('set_as_category_done');
            }
        }

       
/* Redirect back to image */
       
if( \IPS\Request::i()->isAjax() )
        {
            \
IPS\Output::i()->json( array( 'message' => $lang ) );
        }
        else
        {
            \
IPS\Output::i()->redirect( $this->image->url() );    
        }        
    }

   
/**
     * Rotate image
     *
     * @return    void
     */
   
protected function rotate()
    {
       
/* Check permission */
       
if( !$this->image->canEdit() )
        {
            \
IPS\Output::i()->error( 'node_error', '2G188/3', 403, '' );
        }

        \
IPS\Session::i()->csrfCheck();

       
/* Determine angle to rotate */
       
if( \IPS\Request::i()->direction == 'right' )
        {
           
$angle = ( \IPS\Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) ) ? 90 : -90;
        }
        else
        {
           
$angle = ( \IPS\Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) ) ? -90 : 90;
        }

       
/* Rotate the image and rebuild thumbnails */
       
$file    = \IPS\File::get( 'gallery_Images', $this->image->original_file_name );
       
$image    = \IPS\Image::create( $file->contents() );
       
$image->rotate( $angle );
       
$file->replace( (string) $image );
       
$this->image->buildThumbnails( $file );
       
$this->image->original_file_name = (string) $file;
       
$this->image->save();

       
/* Respond or redirect */
       
if ( \IPS\Request::i()->isAjax() )
        {
            \
IPS\Output::i()->json( array(
               
'src'        => (string) \IPS\File::get( 'gallery_Images', $this->image->masked_file_name )->url,
               
'message'    => \IPS\Member::loggedIn()->language()->addToStack('gallery_image_rotated'),
               
'width'        => $this->image->_dimensions['large'][0],
               
'height'    => $this->image->_dimensions['large'][1],
            ) );
        }
        else
        {
            \
IPS\Output::i()->redirect( $this->image->url() );
        }
    }

   
/**
     * Change Author
     *
     * @return    void
     */
   
public function changeAuthor()
    {
       
/* Permission check */
       
if ( !$this->image->canChangeAuthor() )
        {
            \
IPS\Output::i()->error( 'no_module_permission', '2G188/6', 403, '' );
        }
       
       
/* Build form */
       
$form = new \IPS\Helpers\Form;
       
$form->add( new \IPS\Helpers\Form\Member( 'author', NULL, TRUE ) );
       
$form->class .= 'ipsForm_vertical';

       
/* Handle submissions */
       
if ( $values = $form->values() )
        {
           
$this->image->changeAuthor( $values['author'] );
           
$this->image->save();
           
            \
IPS\Output::i()->redirect( $this->image->url() );
        }
       
       
/* Display form */
       
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
    }

   
/**
     * Set this image as a profile image
     *
     * @return    void
     */
   
public function setAsPhoto()
    {
       
/* Permission check */
       
if ( !\IPS\Member::loggedIn()->member_id )
        {
            \
IPS\Output::i()->error( 'no_module_permission', '2G188/9', 403, '' );
        }

       
/* Only images... */
       
if ( $this->image->media )
        {
            \
IPS\Output::i()->error( 'no_photo_for_media', '2G188/A', 403, '' );
        }
       
        \
IPS\Session::i()->csrfCheck();
       
       
/* Update profile photo */
       
$file    = \IPS\File::get( 'gallery_Images', $this->image->masked_file_name );
       
$image    = \IPS\Image::create( $file->contents() );
       
$photo    = \IPS\File::create( 'core_Profile', $file->filename, (string) $image );

        \
IPS\Member::loggedIn()->pp_main_photo = (string) $photo;
        \
IPS\Member::loggedIn()->pp_thumb_photo = (string) $photo->thumbnail( 'core_Profile', \IPS\PHOTO_THUMBNAIL_SIZE, \IPS\PHOTO_THUMBNAIL_SIZE );
        \
IPS\Member::loggedIn()->pp_photo_type = "custom";
        \
IPS\Member::loggedIn()->photo_last_update = time();
        \
IPS\Member::loggedIn()->save();
        \
IPS\Member::loggedIn()->logHistory( 'core', 'photo', array( 'action' => 'new', 'type' => 'gallery', 'id' => $this->image->id ) );

       
/* Redirect back to image */
       
if( \IPS\Request::i()->isAjax() )
        {
            \
IPS\Output::i()->json( array( 'message' => \IPS\Member::loggedIn()->language()->addToStack('set_as_profile_photo') ) );
        }
        else
        {
            \
IPS\Output::i()->redirect( $this->image->url() );    
        }
    }

   
/**
     * Move
     *
     * @return    void
     * @note    Overridden so we can show an album selector as well
     */
   
protected function move()
    {
        try
        {
           
$class = static::$contentModel;
           
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
            if ( !
$item->canMove() )
            {
                throw new \
DomainException;
            }
           
           
$form = \IPS\gallery\Image\Table::buildMoveForm( $item->container(), 'IPS\\gallery\\Image', array( 'forceOwner' => $item->author() ) );

            if (
$values = $form->values() )
            {
                if ( isset(
$values['move_to'] ) )
                {
                    if (
$values['move_to'] == 'new_album' )
                    {
                       
$albumValues = $values;
                        unset(
$albumValues['move_to'] );
                        unset(
$albumValues['move_to_category'] );
                        unset(
$albumValues['move_to_album'] );
                       
                       
$target = new \IPS\gallery\Album;
                       
$target->saveForm( $target->formatFormValues( $albumValues ) );
                       
$target->save();
                    }
                    else
                    {                        
                       
$target = ( \IPS\Request::i()->move_to == 'category' ) ? $values['move_to_category'] : $values['move_to_album'];
                    }
                }
                else
                {
                   
$target = isset( $values['move_to_category'] ) ? $values['move_to_category'] : $values['move_to_album'];
                }

               
$item->move( $target, FALSE );
                \
IPS\Output::i()->redirect( $item->url() );
            }
            \
IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
        }
        catch ( \
Exception $e )
        {
            \
IPS\Output::i()->error( 'node_error', '2G188/B', 403, '' );
        }
    }

   
/**
     * Set the breadcrumb and title
     *
     * @param    \IPS\Content\Item    $item    Content item
     * @param    bool                $link    Link the content item element in the breadcrumb
     * @return    void
     */
   
protected function _setBreadcrumbAndTitle( $item, $link=TRUE )
    {
       
$container    = NULL;
        try
        {
           
$container = $this->image->container();
           
            if (
$club = $container->club() )
            {
                \
IPS\core\FrontNavigation::$clubTabActive = TRUE;
                \
IPS\Output::i()->breadcrumb = array();
                \
IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs') );
                \
IPS\Output::i()->breadcrumb[] = array( $club->url(), $club->name );
               
                if ( \
IPS\Settings::i()->clubs_header == 'sidebar' )
                {
                    \
IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'clubs', 'core' )->header( $club, $container, 'sidebar' );
                }
            }
            else
            {
                foreach (
$container->parents() as $parent )
                {
                    \
IPS\Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
                }
            }
            \
IPS\Output::i()->breadcrumb[] = array( $container->url(), $container->_title );
        }
        catch ( \
Exception $e ) { }

       
/* Add album */
       
if( $this->image->album_id )
        {
            \
IPS\Output::i()->breadcrumb[] = array( $this->image->directContainer()->url(), $this->image->directContainer()->_title );
        }

        \
IPS\Output::i()->breadcrumb[] = array( $link ? $this->image->url() : NULL, $this->image->mapped('title') );
       
       
$title = ( isset( \IPS\Request::i()->page ) and \IPS\Request::i()->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $this->image->mapped('title'), intval( \IPS\Request::i()->page ) ) ) ) : $this->image->mapped('title');
        \
IPS\Output::i()->title = $container ? ( $title . ' - ' . $container->_title ) : $title;
    }
}