E dopo questo script, tutti a nanna

..è un carosello.

Contesto: un’applicazione iniziata con cakephp 1.2 e prototype (sempre quella). Aggiornata a cake 1.3, ma mantenendo i vecchi helper (come AjaxHelper invece del nuovo Js). Quindi, niente jQuery. Una limitazione? un po’, ma anche un’ottima opportunità per provare un po’ di codice lato client o ajax basato su prototype/scriptaculous o indipendente dalle maggiori librerie.

Un ottimo esempio è Prototype Carousel. Semplice, leggero ma abbastanza configurabile. Utilizzabile con qualsiasi tipo di contenuto (non solo immagini).

Pensavo di realizzare qualcosa implementando le “immagini copertina” (come in questo blog) ma alla fine ho optato per una soluzione semplice e veloce ma accettabile: mostrare titolo e intro dei vari contenuti, che ci siano immagini oppure no. (più immediato da implementare, ed una opzione in meno per chi inserisce i contenuti: cosa che conta parecchio..)

Letteralmente semplice e veloce.

Ecco l’element che fa il grosso del lavoro (carousel.ctp), implementando lo slideshow dei contenuti scelti ed i comandi manuali (avanti / indietro / sommario delle slide).
Notare che gli stili sono inclusi inline, essendo così immediatamente configurabili –  il contenitore deve essere n volte la larghezza della singola slide, dove n è il numero di contenuti (in questo caso un banale count($contents)); in questo modo il carosello si adegua ad un numero variabile di slide:

  1. <div class="entry">
  2. <?php
  3.  
  4. [..]
  5. //some conditions based on variables set for the action - not relevant for our example
  6. ?>
  7. <?php
  8. //using old 1.2 helpers
  9. echo $javascript->link('prototype.js',false);
  10. echo $javascript->link('scriptaculous', false);
  11. echo $javascript->link('carousel-min.js',false);
  12. ?>
  13. <?php
  14.  
  15. //set some value if needed
  16. $slides_number = count($contents);
  17. if(!isset($width)) $width = 600;
  18. if(!isset($height)) $height= 450;
  19. $totalsize = $slides_number * $width;
  20. ?>
  21. <style type="text/css" media="screen">
  22. /*here are the carousel styles - leave them here, ifyou don't want to lose the configuration options */
  23. #carousel-wrapper {
  24. position: relative;
  25. width: <?php echo $width; ?>px;
  26. height: <?php echo $height; ?>px;
  27. overflow: hidden;
  28. border: 2px dotted #E9EBE5;
  29. }
  30. #carousel-content {
  31. position: relative;
  32. _height : 1%; /* trick for display IE 7 bug - it shows owerflown content that should be hidden */
  33. width: <?php echo $totalsize; ?>px;
  34. }
  35. #carousel-content .slide {
  36. position: relative;
  37. float: left;
  38. width: <?php echo $width-20; ?>px;
  39. height: <?php echo $height; ?>px;
  40. padding: 8px;
  41. overflow: hidden;
  42. }
  43. .carousel-selected {
  44. border: 1px dashed #DEDEDE;
  45. background-color: #FFF5B3
  46. }
  47.  
  48. .controls {
  49.  
  50. width: <?php echo $width; ?>px;
  51. padding: 6px;
  52. overflow: hidden;
  53. border: 1px solid #E9EBE5;
  54. }
  55. /* #carousel-content h2 {
  56.  
  57. } */
  58. </style>
  59.  
  60. <!-- needed div ids -->
  61. <div id="carousel-wrapper">
  62. <div id="carousel-content">
  63. <?php
  64.  
  65. // other variables/ default settings for the carousel
  66. if(!isset($transition)) $transition = 'sinoidal'; //sinoidal or spring
  67. if(!isset($effect)) $effect = 'scroll'; //scroll or fade
  68. if(!isset($frequency)) $frequency = "8";
  69. if( $effect == 'scroll') $circular= 'true'; else $circular = 'false'
  70. ?>
  71. <?php
  72. // content loop
  73.  
  74. if($effect == 'scroll') {
  75. $contents[] = $contents[0];
  76. //repeating the first slide after the last one is a trick to provide smooth circular scrolling
  77. //
  78. }
  79.  
  80. foreach ($contents as $content):
  81. ?>
  82. <?php
  83. //other things you don't care about in this example..
  84. [..]
  85.  
  86. // set a list of titles for the go to slide # commands
  87. $titles[$id] = $content[$Type]['title'];
  88. ?>
  89. <div class="slide" id="slide-<?php echo $id;?>">
  90. <h2>
  91. <?php echo $html->link($content['Content']['title'],"/content/view/$id"); ?>
  92. </h2>
  93. <div>
  94. <?php
  95. echo $content['Content']['summary'];
  96. ?>
  97. </div>
  98.  
  99. </div>
  100. <?php endforeach; ?>
  101. </div>
  102. </div>
  103. <!-- Menu for manual control: previous slide, next slide, and index (-> go to slide N) -->
  104. <div class="controls">
  105. <a href="javascript:" class="carousel-control ico-next" rel="next" style="float: right;">
  106. <?php echo $icons->next('small'); ?>
  107. </a>
  108.  
  109. <a href="javascript:" class="carousel-control ico-prev" rel="prev" style="float: left;">
  110. <?php echo $icons->back('small'); ?>
  111. </a>
  112. <ul style="margin-left:10px; margin-right: 30px;">
  113. <?php
  114. // if($effect == 'scroll') {
  115. // array_pop($titles);
  116. // }
  117. ?>
  118. <?php foreach ($titles as $id => $title): ?>
  119. <li>
  120. <a href="javascript:" rel="slide-<?php echo $id; ?>" class="carousel-jumper">
  121. <?php echo $text->truncate($title,76,array('ending' => '[..]', 'exact' => false)); ?>
  122. </a>
  123. </li>
  124. <?php endforeach; ?>
  125. </ul>
  126.  
  127. </div>
  128. <!-- finally, here it is. Our carousel call with settings -->
  129. <script type="text/javascript">
  130. new Carousel('carousel-wrapper', $$('#carousel-content .slide'), $$('a.carousel-control', 'a.carousel-jumper'),{duration: 0.8, circular: <?php echo $circular; ?>, effect: '<?php echo $effect; ?>', transition:'<?php echo $transition; ?>', wheel: true, auto: true, frequency: <?php echo $frequency; ?>});
  131. </script>
  132. </div>

Una volta a posto (nella directory webroot/js) il file carousel-min.js e le librerie prototype e scriptaculous, è sufficiente passare all’elemento le variabili necessarie: eventuali valori per configurarlo (dimensioni, durata delle singole slide, tipo di animazione nelle transizioni..) e l’array dei contenuti (il classico risultato di un Model->find di cake).

E’ facilmente configurabile a seconda del contesto e quindi riusabile. Ad esempio, nel mio caso, ogni sito di un portale ha le sue configurazioni in un semplice file incluso, mentre l’oggetto Home (per gestire le homepage dei singoli siti) ha una proprietà “caousel” (boolean) che attiva / disattiva il carosello a scelta del redattore.

  1. <?php
  2. // view/home/display.ctp
  3. $carousel = 0;
  4.  
  5. if(isset($home['Home']['carousel']))
  6. $carousel = $home['Home']['carousel'];
  7. }
  8.  
  9. //[..]
  10. if( $carousel){ //if carousel was selected for the
  11. //top stories of this home, load the settings and then the element
  12. $settings_path = WWW_ROOT.'/themed/'.$this->params['site'].'/elements/blocks/home/carousel_settings.ctp';
  13. include($settings_path);
  14.  
  15. echo $this->element('blocks/home/carousel',
  16. array('contents' => $selected['content'],
  17. //other not relevant stuff
  18. // [..]
  19. 'width' => $carousel_width,
  20. 'height' => $carousel_height,
  21. 'effect' => $carousel_effect,
  22. 'transition' => $carousel_transition,
  23. 'frequency' => $frequency
  24.  
  25. )
  26. );
  27.  
  28. } else {
  29. // else load the default element showing the top stories like a blog
  30. echo $this->element('articles',
  31. array('contents' => $selected['content'],
  32. //other stuff
  33.  
  34. )
  35. );
  36. }
  37. }
  38. ?>

Il file carousel_settings è semplicemente:

  1. <?php
  2. $carousel_width = 600;
  3. $carousel_height = 450;
  4. $carousel_effect = 'scroll'; //scroll or fade
  5. $carousel_transition= 'sinoidal'; //sinoidal or spring
  6. //$frequency = 5;
  7. ?>

..per avere impostazioni legate al layout o alla view. Ovviamente a seconda dell’uso può essere meglio impostare i valori nel controller.

Usarlo per un effetto più elegante?
Semplice: forzare i contenuti ad immagini di dimensioni prefissate (quelle delle slide), e giocare un po’ coi css mettendo il div con il titolo in sovrimpressione con un po’ di trasparenza.