Photo Slideshow Codebase

Markup


<html>
<head>
  <link rel="stylesheet" type="text/css" href="/content/styles/slideshow.css" />
</head>
<body class="body-example">
  <h3 class="center-aligned-block">Photo Slideshow: 2009 Tolt River Flood</h3>
  <div class="ss-wrapper">
    <div class="ss-toolbar">
      <span class="ss-button" id="ss-prev" title="previous image">
        <a href="#" onclick="return false">
          <span>prev</span>
        </a>
      </span>
      <span class="ss-button" id="ss-pause" title="pause slidshow">
        <a href="#" onclick="return false">
          <span>pause</span>
        </a>
      </span>
      <span class="ss-button hidden" id="ss-play" title="play slideshow">
        <a href="#" onclick="return false">
          <span>play</span>
        </a>
      </span>
      <span class="ss-button" id="ss-next" title="next image">
        <a href="#" onclick="return false">
          <span>next</span>
        </a>
      </span>
    </div>
    <div id="ss-img-title"></div>
    <div id="ss-img-wrapper"></div>
  </div>
  <script type="text/javascript" src="/content/scripts/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="/content/scripts/slideshow.js"></script>
</body>
</html>

Javascript, JQuery


/* -----------------------------
   /content/scripts/slideshow.js
   ----------------------------- */

$(function () {
    var images = [],
        $wrapper = $("#ss-img-wrapper"),
        $title = $("#ss-img-title"),
        $img = $("#ss-img"),
        $prev = $("#ss-prev"),
        $pause = $("#ss-pause"),
        $play = $("#ss-play"),
        $next = $("#ss-next");

    images.timer = null;
    images.preloader = null;
    images.currentIndex = 0;
    images.loadDelay = 2000;
    images.transitionRate = 4000;
    images.errorMessage = "unable to load slideshow";
    images.waitMessage = "loading images. please wait...";

    function imageItem(src, title) {
        this.src = src;
        this.title = title;
    }

    function preloadImage(i, ms) {
        if (i < images.length) {
            (new Image()).src = images[i].src;
            images.preloader = setTimeout(function () {
                i++;
                preloadImage(images, i, ms);
            }, ms);
        } else {
            images.preloader = clearTimeout(images.preloader);
        }
    }

    function renderImage(fadeType) {
        $wrapper.empty();
        $img = $('<img id="ss-img" />');
        $img.addClass("ss-fade-in" + (fadeType === 1 ? "-out" : ""));
        $img.css('animation-duration', (images.transitionRate + 'ms'));
        $img.attr("src", images[images.currentIndex].src);
        $wrapper.append($img);
        $title.text(images[images.currentIndex].title);
    }

    function pauseSlideshow() {
        images.timer = clearTimeout(images.timer);
        $img.removeClass("ss-fade-in-out");
    }

    function moveAdjacent(dir) {
        var i = images.currentIndex + (dir === 1 ? 1 : -1);
        images.currentIndex = i > images.length - 1 ? 0 : (i < 0 ? images.length - 1 : i);
        renderImage();
    }

    function playSlideshow() {
        // adjust index if playing after pausing
        if ($img.hasClass("ss-fade-in")) {
            images.currentIndex++;
        }
        if (images.currentIndex < images.length) {
            renderImage(1);
            images.timer = setTimeout(function () {
                images.currentIndex++;
                playSlideshow();
            }, images.transitionRate);
        } else {
            images.timer = clearTimeout(images.timer);
            images.currentIndex = 0;
            playSlideshow();
        }
    }

    function playOnClick(e) {
        $(this).addClass("hidden");
        $pause.removeClass("hidden");
        playSlideshow();
        e.stopPropagation();
    }

    function pauseOnClick(e) {
        $(this).addClass("hidden");
        $play.removeClass("hidden");
        pauseSlideshow();
        e.stopPropagation();
    }

    function prevOnClick(e) {
        $pause.trigger("click");
        moveAdjacent(-1);
        e.stopPropagation();
    }

    function nextOnClick(e) {
        $pause.trigger("click");
        moveAdjacent(1);
        e.stopPropagation();
    }

    // set button event handlers
    function setButtonEvents() {
        $play.on("click", playOnClick);
        $pause.on("click", pauseOnClick);
        $prev.on("click", prevOnClick);
        $next.on("click", nextOnClick);
    }

    function ajaxDone(xml) {
        var src, title,
            // xmlString = (new XMLSerializer()).serializeToString(xml),
            $xml = $(xml),
            $entry = $xml.find("entry");

        $entry.each(function (i) {
            title = $(this).find("title").text();
            if (title.length) src = $(this).find("link[rel=enclosure]").attr("href");
            if (src.length) images[i] = new imageItem(src, title);
        });

        if (images.length) {
            $title.text(images.waitMessage);
            preloadImage(0, images.transitionRate / images.length);
            setButtonEvents();
            setTimeout(function () {
                playSlideshow()
            }, images.loadDelay);
        }
    }

    function ajaxFail() {
        $title.text(images.errorMessage);
    }

    $.ajax({
        type: "GET",
        url: "/content/resources/flickrfeed.xml",
        dataType: "xml"
    })
        .done(ajaxDone)
        .fail(ajaxFail);
});
   

CSS


/* -----------------------------
   /content/styles/slideshow.css
   ----------------------------- */

.body-example {
	font: bold .76em verdana !important;
}

.body-example .center-aligned-block {
    width: 100%;
    text-align: center;
}

.ss-wrapper {
    width: 100%;
    text-align: center;
    margin: 0 auto;
}

.ss-toolbar {
    padding: 1em 0;
}

#ss-img-title {
    font-weight: bold;
    padding-bottom: 1em;
}

.ss-toolbar .ss-button {
    display: inline-block;
    width: 60px;
    height: 26px;
    text-align: center;
    background: #e0e0e0;
    line-height: 1em;
    cursor: pointer;
    border: 1px solid #bbb;
    white-space: nowrap;
}

.ss-toolbar .ss-button:hover {
    background: #f0f0f0;
}

.ss-button a {
    width: 18px;
    height: 18px;
    margin-top: 3px;
    display: inline-block;
    color: #000;
    background: url('data:image/gif;base64,R0lGODlhSAASAKIBAAkJCf39/a+vr5OTk/Pz81xcXNXV1R4eHiH5BAEAAAEALAAAAABIABIAAAPVGLrc/jDKSau9OFchrADgsHyh5gyH+Bhd8xUGRQJqMNcLCwmpSz8onILUk9xGoF8j+PgInY5CyZeERY7DpNAGsjJ4z+LwACBvZyAxVcmdfsvlVvapNAzSbiS8GlvXsG9JAAVIdCIGZIJseop5bWyAI4lwBzFgPoeTWg5oSWZ+jGeNBx1QbzVSnqKjfYGQm2tdhZhfZJ+xZVtZuZKONomktYYNBqmrXa2csG1qu16zp0DNzHI7yzy+l8phugE6PoQy18s51dEmDN8yiX+J5ujw8fLz9PQJADs=') 0 0 no-repeat; 
}

#ss-play a {
	background-position: -18px 0;
}

#ss-pause a {
	background-position: -36px 0;
}

#ss-next a {
	background-position: -54px 0;
}

.ss-button a span {
    position: absolute;
    width: 54px;
    opacity: 0.3;
    margin-top: -20px;
    margin-left: -28px;
    visibility: hidden;
}

.ss-button:hover a span {
    visibility: visible;
}

#ss-img {
    max-width: 70%;
    height: auto;
    border: 1px solid #111;
}

#ss-pause.hidden,
#ss-play.hidden {
    display: none;
}

.ss-fade-in {
    animation: ssFadeIn ease 1s;
}

.ss-fade-in-out {
    animation: ssFadeInOut ease 1s;
}

@keyframes ssFadeIn {
    0%   { 
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

@keyframes ssFadeInOut {
    0%   { 
        opacity: 0;
    }
    70% {
        opacity: 1;
    }
    100% {
        opacity: 0;
    }
}