WackoWiki: Action: imageslider

https://wackowiki.org/doc     Version: 34 (21.05.2023 11:25)

Action: imageslider

Compatible with: R6.1
Current version: 0.9
Credits: WikiAdmin[link1]

Repo: action/imageslider.php[link2]

CSS image slider

{{imageslider}}

action/imageslider.php

<?php

if (!defined('IN_WACKO'))
{
    exit;
}

/*
    Showing images as slider for uploaded by {{upload}} files

    The sole condition is that all the images must be exactly the same size.

    version: 0.9

    {{imageslider
        [page="PageName" or global=1]
        [order="time|name_desc|size|size_desc|ext"]
        [owner="UserName"]
        [media=1]
        [max=number]
    }}

    https://wackowiki.org/doc/Dev/PatchesHacks/ImageSlider
 */

$page_id '';

// set defaults
$order        ??= '';
$global        ??= 0;
$owner        ??= '';
$page        ??= '';
$track        ??= 0;
$media        ??= 1;
$max        ??= null;

if (
$max)
{
    
$limit $max;
}
else
{
    
$limit    50;
}

$order_by        = match($order) {
    
'ext'            => 'file_ext ASC',
    
'name_desc'        => 'file_name DESC',
    
'size'            => 'file_size ASC',
    
'size_desc'        => 'file_size DESC',
    
'time'            => 'created ASC',
    
'time_desc'        => 'created DESC',
    default            => 
'file_name ASC',
};

$width_settings            '100%'// 100%, 300px, etc.
$files                    = [];

// default options for slider
$time_on_slide            6;
$time_between_slides    1;
$animation_timing        'ease';
$slidy_direction        'left';
$css_animation_name        'slidy';

// options: data-caption, alt, none
$caption_source            'data-caption';
$caption_background        'rgba(0,0,0,0.3)';
$caption_color            '#fff';
$caption_font            'Avenir, Avenir Next, Droid Sans, DroidSansRegular, Corbel, Tahoma, Geneva, sans-serif';

// options: top, bottom
$caption_position        'bottom';

// options: slide, perm, fade
$caption_appear            'slide';
$caption_size            '1.6rem';

// same units
$caption_padding        '.6rem';

if (!
$global)
{
    if (
$page == '')
    {
        
$tag        $this->tag;
        
$page_id    $this->page['page_id'];
    }
    else
    {
        
$tag        $this->unwrap_link($page);

        if (
$_page_id $this->get_page_id($tag))
        {
            
$page_id    $_page_id;
        }
    }

    
$can_view    $this->has_access('read'$page_id) || $this->is_admin() || $this->is_owner($page_id);
}
else
{
    
$can_view    1;
    
$tag        $this->tag;
}

if (
$can_view)
{
    if (
$global || ($tag == $this->tag))
    {
        
$filepage $this->page;
    }
    else
    {
        
$filepage $this->load_page($tag0nullLOAD_CACHELOAD_META);
    }

    if (!
$global && !isset($filepage['page_id']))
    {
        return;
    }

    
$selector =
        
"FROM " $this->prefix "file f " .
            
"INNER JOIN " $this->prefix "user u ON (f.user_id = u.user_id) " .
        
"WHERE f.page_id = " . ($global : (int) $filepage['page_id']) . " " .
            
"AND f.picture_w <> 0 " .
            (
$owner
                
"AND u.user_name = " $this->db->q($owner) . " "
                
'') .
            
"AND f.deleted <> 1 ";

    
$count $this->db->load_single(
        
"SELECT COUNT(f.file_id) AS n " .
        
$selectortrue);

    
$pagination $this->pagination($count['n'], $limit'f');

    
// load files list
    
$files $this->db->load_all(
        
"SELECT f.file_id, f.page_id, f.user_id, f.file_size, f.picture_w, f.picture_h, f.file_ext, f.file_lang, f.file_name, f.file_description, f.created, u.user_name AS user " .
        
$selector .
        
"ORDER BY f." $order_by " " .
        
"LIMIT {$pagination['offset']}{$limit}"true);

    
// display
    
if (!$global)
    {
        
$path2 'file:/' $tag '/';
    }
    else
    {
        
$path2 'file:/';
    }

    if (
$factor count($files))
    {
        
// calculate data for image slider CSS

        // count the number of images in the slide, including the new cloned element
        
$img_count            $factor 1;
        
// calculate the total length of the animation by multiplying the number of _actual_ images by the amount of time for both static display of each image and motion between them
        
$total_time            = ($time_on_slide $time_between_slides) * ($img_count 1);
        
// determine the percentage of time an individual image is held static during the animation
        
$slide_ratio        = ($time_on_slide $total_time) * 100;
        
// determine the percentage of time for an individual movement
        
$move_ratio            = ($time_between_slides $total_time) * 100;
        
// work out how wide each image should be in the slidy, as a percentage.
        
$base_percentage    100 $img_count;
        
// set the initial position of the slidy element
        
$position            0;

        
$img_width    $img_count 100;
        
$slidy        '';

        if (
$slidy_direction == 'right')
        {
            
$slidy .= "0% \t{ left: -" . (($img_count 1) * 100) . "%; }\n";

            for (
$i $img_count 1$i 0$i--)
            {
                
$position += $slide_ratio;
                
// make the keyframe the position of the image
                
$slidy .= "\t\t" $position "% \t{ left: -" . ($i 100) . "%; }\n";
                
$position += $move_ratio;
                
// make the postion for the _next_ slide
                
$slidy .= "\t\t" $position "% \t{ left: -" . (($i 1) * 100) . "%; }\n";
            }
        }
        else
        {
            
$slidy .= "0% \t{ left: 0%; }\n";

            
// the slider is moving to the left
            
for ($i 0$i < ($img_count 1); $i++)
            {
                
$position += $slide_ratio;
                
// make the keyframe the position of the image
                
$slidy .= "\t\t" $position "% \t{ left: -" . ($i 100) . "%; }\n";
                
$position += $move_ratio;
                
// make the postion for the _next_ slide
                
$slidy .= "\t\t" $position "% \t{ left: -" . (($i 1) * 100) . "%; }\n";
            }
        }

        
$tpl->css = <<<EOD
    <style>

    div#captioned-gallery {
        width: 100%;
        overflow: hidden;
    }
    figure {
        margin: 0;
    }
    figure.slider {
        position: relative;
        width: 
{$img_width}%;
        font-size: 0;
        animation: 
{$total_time}{$animation_timing} slidy infinite;
    }
    figure.slider:hover {
        /* animation: animation 1s  16 ease; */
        animation-play-state: paused;
    }
    figure.slider figure {
        width: 
{$base_percentage}%;
        height: auto;
        display: inline-block;
        position: inherit;
    }
    figure.slider img {
        width: 
{$width_settings};
        height: auto;
    }
    figure.slider figure figcaption {
        position: absolute;
        bottom: 0;
        background: rgba(0,0,0,0.3);
        color: #fff;
        width: 100%;
        font-size: 1rem;
        padding: .6rem;
    }
    div#slider figure {
        position: relative;
        width: 
{$img_width}%;
        margin: 0;
        padding: 0;
        font-size: 0;
        left: 0;
        text-align: left;
        animation: 
{$total_time}{$animation_timing} slidy infinite;
    }

    @media screen and (max-width: 500px) {
        figure.slider figure figcaption {
            font-size: 1.2rem;
        }
    }

    /* figure.slider figure figcaption {
        position: absolute;
        bottom: -3.5rem;
        background: rgba(0,0,0,0.3);
        color: #fff;
        width: 100%;
        font-size: 2rem;
        padding: .6rem;
        transition: .5s bottom;
    }
    figure.slider figure:hover figcaption {
        bottom: 0;
    }

    figure.slider figure:hover + figure figcaption {
        bottom: 0;
    } */

    @keyframes slidy {
        
{$slidy}
    }

    </style>
EOD;

        
// adding at the end a clone of the first array for transition loop
        
$files[]    = $files[0];
        
$n            0;

        
$tpl->enter('n_');

        foreach(
$files as $file)
        {
            if (
$file['picture_h']) // missing: svg!
            
{
                
$n++;

                
$this->file_cache[$file['page_id']][$file['file_name']] = $file;

                
$desc        $this->format($file['file_description'], 'typografica', ['lang' => $file['file_lang']]);

                if (
$desc == '')
                {
                    
$desc "\u{00A0}";    // No-Break Space
                
}

                
$file_name    $file['file_name'];
                
$text        $media '' $file_name;

                
$tpl->image        $this->link($path2 $file_name''$text''$track);
                
$tpl->n            $n;
                
$tpl->count        $count['n'];
                
$tpl->desc        $desc;
            }
        }

        
$tpl->leave();    // n
    
}
    else
    {
        
$tpl->nofile =  $this->_t('FileNotFound');
    }

    unset(
$files);
}
else
{
    
$tpl->noaccess true;
}


action/template/imageslider.tpl
[ === main === ]
	[ ' css ' ][ ' nofile ' ]

	<div id="captioned-gallery">
		<figure class="slider">
		[= n _ =
			<figure>
				[ ' image ' ]
				<figcaption>[ ' n ' ]/[ ' count ' ] [ ' desc ' ]</figcaption>
			</figure>
		=]
		</figure>
	</div>

	[= noaccess _ =
		[ ' _t: ActionDenied ' ]
	=]	

1. Documentation

The sole condition is that all the images must be exactly the same size.

2. How to



%%(wacko wrapper=page wrapper_width=600)
{{imageslider}}
%%

2.1. local usage of repository

symlink the gallery action from community action folder in wacko/action and wacko/action/template folder in repo
ln -s ../../community/action/imageslider.php imageslider.php
ln -s ../../../community/action/template/imageslider.tpl imageslider.tpl

3. Changelog

0.1 Initial version
0.7 Updated to work with R.6.1 (PHP 8.0, Null coalescing assignment operator)
0.8 added order="name_desc" and changed time field names
0.9 added template

4. To Do


Referring pages:

  1. Dev/PatchesHacks[link3]