1<?php
2/**
3 * Embed an image gallery
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Andreas Gohr <andi@splitbrain.org>
7 * @author     Joe Lapp <joe.lapp@pobox.com>
8 * @author     Dave Doyle <davedoyle.canadalawbook.ca>
9 * @author     Gerry Weissbach <gerry.w@gammaproduction.de>
10 */
11
12if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
13if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
14require_once(DOKU_PLUGIN.'syntax.php');
15require_once(DOKU_INC.'inc/search.php');
16require_once(DOKU_INC.'inc/JpegMeta.php');
17
18class syntax_plugin_gallery extends DokuWiki_Syntax_Plugin {
19    /**
20     * return some info
21     */
22    function getInfo(){
23        return array(
24            'author' => 'Andreas Gohr',
25            'email'  => 'andi@splitbrain.org',
26            'date'   => '2007-11-06',
27            'name'   => 'Gallery Plugin',
28            'desc'   => 'Creates a gallery of images from a namespace',
29            'url'    => 'http://wiki.splitbrain.org/plugin:gallery',
30        );
31    }
32
33    /**
34     * What kind of syntax are we?
35     */
36    function getType(){
37        return 'substition';
38    }
39
40    /**
41     * What about paragraphs?
42     */
43    function getPType(){
44        return 'block';
45    }
46
47    /**
48     * Where to sort in?
49     */
50    function getSort(){
51        return 301;
52    }
53
54
55    /**
56     * Connect pattern to lexer
57     */
58    function connectTo($mode) {
59        $this->Lexer->addSpecialPattern('\{\{gallery>[^}]*\}\}',$mode,'plugin_gallery');
60    }
61
62
63    /**
64     * Parse option
65     */
66    function parseOpt($params, $name) {
67        if(preg_match('/\b'.$name.'\b/i',$params,$match)) {
68	    return true;
69        }else if(preg_match('/\bno'.$name.'\b/i',$params,$match)) {
70	    return false;
71	}else{
72            return $this->getConf($name);
73        }
74    }
75
76    /**
77     * Handle the match
78     */
79    function handle($match, $state, $pos, &$handler){
80        $match = substr($match,10,-2); //strip markup from start and end
81
82        $data = array();
83
84        //handle params
85        list($ns,$params) = explode('?',$match,2);
86
87        if ( substr($ns, 0, 1) == ' ' )
88        	$data['float']="right";
89        else if ( substr($ns, -1) == ' ' )
90        	$data['float']="left";
91        else
92        	$data['float'] = null;
93
94        //namespace
95        $data['ns'] = $ns;
96
97        //max thumb dimensions
98        if(preg_match('/\b(\d+)x(\d+)\b/',$params,$match)){
99            $data['w'] = $match[1];
100            $data['h'] = $match[2];
101        }else{
102            $data['w'] = $this->getConf('thumbnail_width');
103            $data['h'] = $this->getConf('thumbnail_height');
104        }
105
106        //max lightbox dimensions
107        if(preg_match('/\b(\d+)X(\d+)\b/',$params,$match)){
108            $data['w_lightbox'] = $match[1];
109            $data['h_lightbox'] = $match[2];
110        }else{
111            $data['w_lightbox'] = $this->getConf('image_width');
112            $data['h_lightbox'] = $this->getConf('image_height');
113        }
114
115        //number of images per row
116        if(preg_match('/\b(\d+)\b/i',$params,$match)){
117            $data['cols'] = $match[1];
118        }else{
119            $data['cols'] = $this->getConf('cols');
120        }
121
122        //show the filename
123		$data['showname'] = $this->parseOpt($params, 'showname');
124
125        //lightbox style?
126		$data['lightbox'] = $this->parseOpt($params, 'lightbox');
127
128        //direct linking?
129		if($data['lightbox']) {
130            $data['direct']   = true; //implicit direct linking
131		}else{
132	    	$data['direct'] = $this->parseOpt($params, 'direct');
133		}
134
135        //reverse sort?
136		$data['reverse'] = $this->parseOpt($params, 'reverse');
137
138        //resize thing?
139        if(preg_match('/\bnoresize\b/i',$params,$match)) {
140            $data['noresize'] = true;
141        }else{
142            $data['noresize'] = false;
143        }
144
145        //Layout thing?
146        if(preg_match('/\bmagazine\b/i',$params,$match)) {
147            $data['magazine'] = true;
148        }else{
149            $data['magazine'] = false;
150        }
151
152        //Layout thing?
153        if(preg_match('/\bdiashow\b/i',$params,$match)) {
154            $data['diashow'] = true;
155        }else{
156            $data['diashow'] = false;
157        }
158
159        //Layout thing?
160        if(preg_match('/\bpageAmount=(\d+)\b/i',$params,$match)) {
161            $data['pageAmount'] = $match[1];
162        }else{
163            $data['pageAmount'] = -1;
164        }
165
166        return $data;
167    }
168
169    /**
170     * Create output
171     */
172    function render($mode, &$renderer, $data) {
173		if ( $data['pageAmount'] > 0 ) $renderer->info['cache'] = FALSE;
174
175        if($mode == 'xhtml'){
176            $renderer->doc .= $this->_gallery($data);
177            return true;
178        }
179        return false;
180    }
181
182    /**
183     * Does the gallery formatting
184     */
185    function _gallery($data){
186        global $conf;
187        global $lang;
188        $ret = '';
189
190        //use the search to get all files
191        $ns = cleanID($data['ns']);
192        $dir = utf8_encodeFN(str_replace(':','/',$ns));
193        $files = array();
194        search($files,$conf['mediadir'],'search_media',array(),$dir);
195
196        //anything found?
197        if(!count($files)){
198            $ret .= '<div class="nothing">'.$lang['nothingfound'].'</div>';
199            return $ret;
200        }
201
202        //reverse if wanted
203        if($data['reverse']) rsort($files);
204
205        //startPoint of Pages
206        $startPoint = intval($_REQUEST['startPoint']);
207
208
209		// build magazine
210		if ($data['magazine'])
211		{
212			require_once(realpath(dirname(__FILE__)).'/inc/magazinelayout.class.php');
213
214			$template = '<img src="/lib/plugins/gallery/inc/image.php?size=[size]&file=[image]" alt="" />';
215			$mag = new magazinelayout($data['w'], $data['h']!=120?$data['h']:5, $template);
216			$cols = $data['cols'];
217			$cols = $cols > 8 ? 8 : $cols;
218
219//			$content = '<div class="gallery">';
220
221			$amount = 0;
222			foreach($files as $img){
223				if(!$img['isimg']) continue;
224				$amount ++;
225				if ( $amount < $startPoint ) continue;
226				if ( $data['pageAmount'] > 0 && $amount-$startPoint >= $data['pageAmount'] ) break;
227
228				$img['lightbox'] = $data['lightbox'];
229				$img['h_lightbox'] = $data['h_lightbox'];
230				$img['w_lightbox'] = $data['w_lightbox'];
231				$img['direct'] =  $data['direct'];
232				$img['float'] =  $data['float'];
233
234				$mag->addImage($img);
235
236				$cols --;
237				if ($cols <= 0 )
238				{
239					$content .= $mag->getHtml();
240					$mag = new magazinelayout($data['w'], $data['h']!=120?$data['h']:5, $template);
241					$cols = $data['cols'];
242				}
243
244			}
245
246			if ($mag->_numimages > 0) $content .= $mag->getHtml();
247
248//			$content .= '<br style="clear:both" /></div></div></div>';
249
250			$content .= $this->_pageSelect(count($files), $data['pageAmount'], $startPoint);
251			return $content;
252		}
253
254
255        // build gallery
256        if($data['cols'] > 0){ // format as table
257            $ret .= '<table class="gallery"' . (!empty($data['float']) ? ' style="float: '.$data['float'].';"' : '') . '>';
258            $i = 0;
259            $amount = 0;
260            foreach($files as $img){
261                if(!$img['isimg']) continue;
262				$amount ++;
263				if ( $amount < $startPoint ) continue;
264				if ( $data['pageAmount'] > 0 && $amount-$startPoint >= $data['pageAmount'] ) break;
265
266                if($i == 0){
267                    $ret .= '<tr>';
268                }
269
270                $ret .= '<td>';
271                $ret .= $this->_image($img,$data);
272                $ret .= $this->_showname($img,$data);
273                $ret .= '</td>';
274
275                $i++;
276
277                $close_tr = true;
278                if($i == $data['cols']){
279                    $ret .= '</tr>';
280                    $close_tr = false;
281                    $i = 0;
282                }
283            }
284
285            if ($close_tr){
286                // add remaining empty cells
287                for(;$i < $data['cols']; $i++){
288                    $ret .= '<td></td>';
289                }
290                $ret .= '</tr>';
291            }
292
293            $ret .= '</table>';
294        }else{ // format as div sequence
295            $ret .= '<div class="gallery"' . (!empty($data['float']) ? ' style="float: '.$data['float'].';"' : '') . '>';
296
297			$amount = 0;
298            foreach($files as $img){
299                if(!$img['isimg']) continue;
300				$amount ++;
301				if ( $amount < $startPoint ) continue;
302				if ( $data['pageAmount'] > 0 && $amount-$startPoint >= $data['pageAmount'] ) break;
303
304                $ret .= '<div>';
305                $ret .= $this->_image($img,$data);
306                $ret .= $this->_showname($img,$data);
307                $ret .= '</div> ';
308            }
309
310            $ret .= '<br style="clear:both" /></div>';
311        }
312
313		$ret .= $this->_pageSelect(count($files), $data['pageAmount'], $startPoint);
314        return $ret;
315    }
316
317    /**
318     * Defines how a thumbnail should look like
319     */
320    function _image($img,$data){
321        global $ID;
322
323        $w = $img['meta']->getField('File.Width');
324        $h = $img['meta']->getField('File.Height');
325        $dim = array();
326
327        if ( $data['noresize'])
328        {
329            $w = $data['w'];
330            $h = $data['h'];
331        }
332        else if($w > $data['w'] || $h > $data['h']){
333            $ratio = $img['meta']->getResizeRatio($data['w'],$data['h']);
334            $w = floor($w * $ratio);
335            $h = floor($h * $ratio);
336            $dim = array('w'=>$w,'h'=>$h);
337        }
338
339        //prepare img attributes
340        $i           = array();
341        $i['width']  = $w;
342        $i['height'] = $h;
343        $i['border'] = 0;
344        $i['alt']    = $img['meta']->getField('Simple.Title');
345        $i['class']  = 'tn';
346        $iatt = buildAttributes($i);
347        $src  = ml($img['id'],$dim);
348
349        // prepare lightbox dimensions
350        $w_lightbox = $img['meta']->getField('File.Width');
351        $h_lightbox = $img['meta']->getField('File.Height');
352        $dim_lightbox = array();
353        if($w_lightbox > $data['w_lightbox'] || $h_lightbox > $data['h_lightbox']){
354            $ratio = $img['meta']->getResizeRatio($data['w_lightbox'],$data['h_lightbox']);
355            $w_lightbox = floor($w_lightbox * $ratio);
356            $h_lightbox = floor($h_lightbox * $ratio);
357            $dim_lightbox = array('w'=>$w_lightbox,'h'=>$h_lightbox);
358        }
359
360        //prepare link attributes
361        $a           = array();
362        $a['title']  = $img['meta']->getField('Simple.Title');
363        if($data['lightbox']){
364            $href   = ml($img['id'],$dim_lightbox);
365            $a['class'] = "lightbox JSnocheck";
366            $a['rel']   = "lightbox";
367        }else{
368            $href   = ml($img['id'],array('id'=>$ID),$data['direct']);
369        }
370        $aatt = buildAttributes($a);
371
372        // prepare output
373        $ret  = '';
374        $ret .= '<a href="'.$href.'" '.$aatt.'>';
375        $ret .= '<img src="'.$src.'" '.$iatt.' />';
376        $ret .= '</a>';
377        return $ret;
378    }
379
380
381    /**
382     * Defines how a filename + link should look
383     */
384    function _showname($img,$data){
385        global $ID;
386
387        if(!$data['showname']) { return ''; }
388
389        //prepare link
390        $lnk = ml($img['id'],array('id'=>$ID),false);
391
392        // prepare output
393        $ret  = '';
394        $ret .= '<br /><a href="'.$lnk.'">';
395        $ret .= $img['file']; // see fix posted on the wiki
396        $ret .= '</a>';
397        return $ret;
398    }
399
400    function _pageSelect($fileCount, $showCount, $startPoint)
401    {
402    	global $ID;
403    	$content = '<div id="pageSelect">';
404
405    	$pages = ceil($fileCount / $showCount);
406    	if ( $pages <= 1 ) return "";
407
408    	for ($i=0; $i<$pages; $i++)
409    	{
410	        $lnk = wl($ID, array('startPoint'=>$i*$showCount));
411	        $content .= '<a href="' . $lnk . '">';
412	        $content .= $i+1;
413	        $content .= '</a>';
414
415	        if ( $i < $pages -1 )
416	        	$content .= '&nbsp;-&nbsp;';
417    	}
418
419    	$content .= '</div>';
420    	return $content;
421    }
422}
423
424//Setup VIM: ex: et ts=4 enc=utf-8 :
425