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.
Custom dynamically generated slide show container
javascript;html;css
Most of the issues with your code revolve around not using jQuery to its full potential. Looping through some set of nodes, working only with those that are elements of a certain type, is what jQuery was made for, and is intended to provide a framework that behaves the same on all browsers.There is a lot of stuff around assigning and tracking ids that isn't really necessary. It is almost always possible to refer to variables locally in a way that avoids the need for adding new properties to DOM elements.The code below hasn't been tested but is intended to show different ways to achieve the same effects usually with simplification courtesy of jQuery. All of the global Image and Button id stuff is gone and replaced with an array local to each slide show group that keeps track of which button goes with each image. Everything that was being done with native JS but could be done with jQuery uses jQuery for consistencyThere were a couple of things in your code worth mentioning specifically as they aren't covered in the code example.The error checking while laudable was poorly handled. While its good to test for situations that will cause errors, when you find then simply throwing an exception that halts execution is little better than simply letting the errors happen. The example provided doesn't test for errors but if it did it would quietly return from the current function without throwing anything. The CSS is neat and easy to read but don't forget that it can contain comments which are often more important that in JS. Once JS code is written and works it probably won't need changing for some considerable time. CSS on the other hand might be fiddled with at any time on the whim of some design aesthetic. Having comments in CSS to explain why certain values were chosen, which can be tweaked and which mustn't be change on pain of death, is very useful for anyone hoping to quickly made a few changes.$(function () {        // define all of the Magic Numbers at the beginning  // http://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad    var slideFadeMilliseconds = 300;    var activeButtonClass='slideshow-active-button';    var buttonGroupClass='slideshow-buttons';    var slideShowClass='slideshow-container';            // find all slideshows and iterate them    $( .+slideShowClass ).each(function(index, slideShowContainer) {            // define array to contain the buttons and their            // corresponding images        var buttons=[];            // record which button/image is currently active         var current=0;            // build a div to contain the buttons        var buttonsContainer=$('<div>').addClass(buttonGroupClass);            //  and add it to the page        slideShowContainer.append(buttonsContainer);            // find all images in the slideShowContainer and iterate them        $(slideShowContainer).find('img').each(function(i,img){                // build a button            var button=$('<a>').prop('href','javascript:;');                // if it's the first button it should be active            if(i==0) button.addClass(activeButtonClass);                // record the button and its corresponding image                // as an object with properties button and image            buttons.push( { button:button, image:img } );                // then add it to the page            buttonsContainer.append(button);            button.click(function(){                    // fade out the old current image                $(buttons[current].image).fadeOut(slideFadeMilliseconds,function(){                    // then fade in this button                    $(img).fadeIn(slideFadeMilliseconds);                });                    // set the old current button to be deactivated                $(buttons[current].button).removeClass(activeButtonClass);                    // activate the new current button                $(img).addClass(activeButtonClass);                    // update the current variabe to reflect the change                current=i;            });        }).fadeOut(0).first().fadeIn(0);            // hide all the images the show the first    });});