I've created a custom slide show container to use with Jekyll. This is the platform used by Github pages. It works by converting plain text Markdown to HTML.
I wanted to be able to embed the slide shows in the Markdown as inline HTML, so the following is a usage example:
some_file.markdown
:
... text ...
<div class="slideshow-container">
<div class="slideshow-img-list">
<img src="path/img-a.png">
<img src="path/img-b.png">
<img src="path/img-c.png">
</div>
</div>
... more text ...
A JavaScript+jQuery function then processes elements with class slideshow-container
when the page finishes loading to expand the above into:
<div class="slideshow-container">
<div class="slideshow-img-list">
<img src="path/img-a.png" id="slideshow-img-0">
<img src="path/img-b.png" id="slideshow-img-1">
<img src="path/img-c.png" id="slideshow-img-2">
</div>
<div class="slideshow-buttons">
<a id="slideshow-btn-0" href="javascript:;" class="slideshow-active-button"></a>
<a id="slideshow-btn-1" href="javascript:;"></a>
<a id="slideshow-btn-2" href="javascript:;"></a>
</div>
</div>
The purpose behind the dynamic processing is to reduce the amount of boilerplate HTML I have to write in the markdown whenever I wish to specify a list of images for a slide show.
Following are the function that does the transformation, plus the styles I'm using and a sample showing the result.
function setUpSlideShowContainers() {
/* The id counters are used to attribute sequential ids to each
* <img>/<a> inside the slide-show containers of a page. */
var globalImageId = 0;
var globalButtonId = 0;
var slideFadeMilliseconds = 300;
function activeButton(button) {
button.className = "slideshow-active-button";
}
function deactivateButtons(buttonsArray) {
for (var i = 0; i < buttonsArray.length; ++i) {
buttonsArray[i].className = "";
}
}
$(".slideshow-container").each(function(index, slideShowContainer) {
if (!slideShowContainer) {
throw "Null 'slideShowContainer'!";
}
var imgContainer = slideShowContainer.firstElementChild;
if (!imgContainer || imgContainer.className != "slideshow-img-list") {
throw "Missing 'slideshow-img-list' div!";
}
/* Append this property to the container so that we can keep
* track of the currently selected image in the slide-show. */
slideShowContainer.currentSlideImgId = globalImageId;
var i;
var imageCount = 0;
var imageIds = [];
var childNodes = imgContainer.childNodes;
for (i = 0; i < childNodes.length; ++i) {
/* Might have text nodes mixed between the images. */
if (childNodes[i].nodeName.toUpperCase() != "IMG") {
continue;
}
/* Give it a sequential name. */
childNodes[i].id = "slideshow-img-" + globalImageId;
imageIds.push(globalImageId);
/* Fade all the images except the fist one,
* so that our transition works properly. */
if (imageCount != 0) {
$("#" + childNodes[i].id).fadeOut(0);
}
++imageCount;
++globalImageId;
}
var allButtons = [];
var buttonsContainer = document.createElement("DIV");
buttonsContainer.className = "slideshow-buttons";
for (i = 0; i < imageCount; ++i) {
var anchorButton = document.createElement("A");
anchorButton.id = "slideshow-btn-" + globalButtonId;
anchorButton.href = "javascript:;";
anchorButton.imageId = imageIds[i];
/* First button/img in a slide-show is the default active one. */
if (i == 0) {
anchorButton.className = "slideshow-active-button";
}
anchorButton.addEventListener("click", function(event) {
var slideShow = slideShowContainer
var otherButtons = allButtons;
var clickedButton = event.target;
if (clickedButton.imageId == slideShow.currentSlideImgId) {
return; /* Clicking the currently active button; Do nothing. */
}
var idCurrent = "#slideshow-img-" + slideShow.currentSlideImgId;
var idClicked = "#slideshow-img-" + clickedButton.imageId;
/* Fade-out the current and fade-in the next one
* once the fade-out effect is finished. */
$(idCurrent).fadeOut(slideFadeMilliseconds,
function() {
$(idClicked).fadeIn(slideFadeMilliseconds);
}
);
slideShow.currentSlideImgId = clickedButton.imageId;
deactivateButtons(otherButtons);
activeButton(clickedButton);
});
allButtons.push(anchorButton);
buttonsContainer.appendChild(anchorButton);
++globalButtonId;
}
slideShowContainer.appendChild(buttonsContainer);
});
}
$(document).ready(function() {
setUpSlideShowContainers();
});
.slideshow-container {
width: 500px;
height: 330px;
overflow: hidden;
position: relative;
margin: 0 auto;
border-radius: 5px;
-webkit-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), 0 0 25px rgba(0, 0, 0, 0.2) inset;
-moz-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), 0 0 25px rgba(0, 0, 0, 0.2) inset;
-o-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), 0 0 25px rgba(0, 0, 0, 0.2) inset;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), 0 0 25px rgba(0, 0, 0, 0.2) inset;
}
.slideshow-img-list {
font-size: 0;
width: auto;
position: absolute;
}
.slideshow-img-list img {
width: 100%;
height: 100%;
max-width: 500px;
max-height: 330px;
margin-top: 0px;
margin-bottom: 0px;
}
.slideshow-buttons {
position: relative;
margin-top: 62%;
display: flex;
justify-content: center;
align-items: center;
}
.slideshow-buttons a {
display: inline-block;
width: 15px;
height: 15px;
border-radius: 10px;
border: 1px solid white;
margin-left: 10px;
margin-right: 10px;
}
.slideshow-active-button {
background-color: white;
cursor: default;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="slideshow-container">
<div class="slideshow-img-list">
<img src="https://bytebucket.org/glampert/ps2dev-tests/raw/f3a137f9030c823d554080ec8bd97b262904bdb9/screens/screen39.png">
<img src="https://bytebucket.org/glampert/ps2dev-tests/raw/f3a137f9030c823d554080ec8bd97b262904bdb9/screens/screen15.png">
<img src="https://bytebucket.org/glampert/ps2dev-tests/raw/f3a137f9030c823d554080ec8bd97b262904bdb9/screens/screen22.png">
</div>
</div>
I'm a weekend warrior when it comes to JavaScript and Web stuff, so I'm looking for any suggestions on how to improve this. Please don't spare any details! In particular, I'd like this to be as cross-browser as possible, so if I'm using something not portable, let me know how it can be fixed.