Adding Fancybox to an Yii application

Site has moved

This site has moved to a new location. Visit the new site at http://programsdream.nl.

By Ronald van Belzen | June 15, 2013

After showing how to add AD Gallery to an application I am showing here how to use Fancybox in an Yii application for the display of an image gallery. "FancyBox is a tool for displaying images, html content and multi-media in a Mac-style "lightbox" that floats overtop of web page." It is capable of showing much more then just images. In fact the Yii module Gii uses Fancybox to display the generated code in a lightbox. But in this example I am just going to show how to use Fancybox with images to show how it can be used to produce an image gallery.

As with AD Gallery Fancybox is not overly complicated, but it is different. In order not to repeat the former blog post too much I am adding pagination to the example, which is useful when using extremely large sets of images. The controller used in the previous example will be changed to look like this:

class OverviewController extends Controller { 
  const PAGE_SIZE = 50;

  // other action functions 

  public function actionView($id) { 
    $model=Gallery::model()->findByPk($id); 
    if($model===null) 
      throw new CHttpException(404,'The requested page does not exist.'); 

    $criteria = new CDbCriteria; 
    $criteria->condition = "gallery_id = $id"; 

    $count = GalleryImage::model()->count($criteria); 
    $pageCount = ceil($count/self::PAGE_SIZE); 
    $pager = new CPagination($pageCount); 
    $pager->pageSize=1; 

    $criteria->order = 'sort ASC'; 
    $criteria->limit = self::PAGE_SIZE; 
    $criteria->offset = self::PAGE_SIZE*$pager->currentPage; 
    $models = GalleryImage::model()->findAll($criteria); 
    $this->render('view', array( 
      'gallery'=>$model, 
      'models'=>$models, 
      'pager'=>$pager, 
    )); 
  } 
}

The class constant PAGE_SIZE represents the number of thumbnail images that will be displayed on a page. The variable $pageCount contains the number of pages that are needed for pagination and is passed to the CPagination class constructor. The page size for CPagination is set to 1, which is not related to the number of images on a page but chosen to make the offset calculation simpler.

As in the previous blog post example the model Gallery contains the information about different galleries. Most important attribute of this model is storage that contains the location of the directory in which the images are stored. The model GalleryImage links images to a gallery and contains the information about the image file names. The controller action renders the view view that shows the image gallery:

<?php 
/* @var $this OverviewController */ 
/* @var $gallery Gallery */ 
/* @var $models[] GalleryImage */ 
/* @var $pager CPagination */ 

$this->breadcrumbs=array( 
  'Galleries'=>array('index'), 
  $gallery->name, 
); 

$location = Yii::app()->request->baseUrl.$gallery->storage.'/'; 

Yii::app()->clientScript->registerCssFile(Yii::app()->request->baseUrl . '/protected/modules/gallery/js/fancybox/source/jquery.fancybox.css?v=2.1.4'); 
Yii::app()->clientScript->registerCoreScript('jquery'); 
Yii::app()->clientScript->registerScriptFile(Yii::app()->request->baseUrl . '/protected/modules/gallery/js/fancybox/source/jquery.fancybox.pack.js?v=2.1.4.js'); 
Yii::app()->clientScript->registerScriptFile(Yii::app()->request->baseUrl . '/protected/modules/gallery/js/fancybox/lib/jquery.mousewheel-3.0.6.pack.js'); 

Yii::app()->clientScript->registerScript('gallery', "
  $('.fancybox').fancybox({ 
    loop : true, 
    afterLoad: function(current, previous) { 
      if(current && previous) { 
        if(current.index == 0 && previous.index == (current.group.length - 1) && current.group.length > 2) { 
          location = $('.yiiPager .next a').attr('href'); 
          if(location) { 
            window.location = location; 
          } else { 
            window.location = window.location; 
          } 
          return false; 
        } 
        if(previous.index == 0 && current.index == (current.group.length - 1) && current.group.length > 2) { 
          location = $('.yiiPager .previous a').attr('href'); 
          if(location) { 
            window.location = location; 
          } else { 
            window.location = window.location; 
          } 
          return false; 
        } 
      } 
    } 
  }); 
  ", CClientScript::POS_READY); 
?> 
<h1><?php echo $gallery->name; ?></h1> 
<p><?php echo $gallery->description; ?></p> 
<div class="pager" style="text-align:right;"> 
  <?php $this->widget('CLinkPager', array('pages' => $pager)); ?> </div> 
<div class="gallery" style="margin:5px;"> 
  <?php foreach($models as $model): ?> 
    <?php echo CHtml::link( 
      CHtml::image($location.$model->thumbnail, 
        $model->title), 
        $location.$model->mediumsize, 
        array( 
          'class'=>'fancybox', 
          'rel'=>'group', 
          'title'=>$model->title, 
        ) 
      ); 
   ?> 
  <?php endforeach; ?> 
</div> 
<div class="pager" style="text-align:right;"> 
  <?php $this->widget('CLinkPager', array('pages' => $pager)); ?> 
</div>

The CSS file and Javascript files of the Fancybox plugin are included in the page together with a copy of the jQuery file. In lines 19-45 the Fancybox function fancybox() is called for the anchor tags of the images with the class name fancybox. This script places the images in the gallery. Of course, the image anchors need to be loaded before the script executes. For this reason the script that calls fancybox() is executed after the page has been loaded (CClientScript::POS_READY).

The anchors with the same attribute rel are placed in the same gallery through which the user can navigate to next and previous images by default. The images to which the anchors refer are shown. This example passes two settings to the fancybox() function to change the default behaviour of the gallery.

The parameter loop:true causes the navigation to show the first images when the user tries to navigate beyond the last image. The parameter afterLoad:function() offers a callback function that is used here to navigate to the next or previous page when the user tries to navigate beyond the last or first image of the images shown on the present page. The function is limited to pages that show more than 2 images, because only then the attempt to navigate backwards can be determined correct.

Maybe in the future a Fancybox callback function will be included to reliably determine this transition.