This is my first jQuery plugin (used the jQuery ui widget factory). All code improvements are welcome.
The plugin creates a gallery with one big picture and a given amount of clickable thumbnails. When the last thumbnail of set has been clicked it fades into the next thumbnail set.
;(function ($, window, document, undefined) {
$.widget("company.imageSlider", {
options: {
debug: false,
templateId: "",
thumbAmount: 4,
photos: [],
imagePath: "./img/landscape/",
thumbPath: "./img/thumbs/"
},
thumbSetPosition: {
val: 0
},
thumbSetZindex: {
val: 0
},
_create: function () {
this.options.debug == true && console.log("Create has been called");
this.thumbSetPosition = 1;
this.thumbSetZindex = 999;
this.element.addClass("plugin-is-active");
},
_getPhotosByRange: function (from, to) {
return this.options.photos.slice(from, to)
},
_getPhotoCount: function() {
return this.options.photos.length;
},
_buildMainFrame: function () {
this.options.debug == true && console.log("Building main image frame");
var widget = this;
var container = $(".company-image-slider__main-image");
// Add mouse over events
container.on("mouseenter", function () {
$(this).find(".company-image-slider__nav").fadeIn(500);
}).on("mouseleave", function () {
$(this).find(".company-image-slider__nav").fadeOut(500);
});
// Add on click event
container.find(".company-image-slider__nav").on("click", function () {
if ($(this).data("direction") == "next") {
widget._nextImage();
} else {
widget._prevImage();
}
});
},
_nextImage: function () {
this.options.debug == true && console.log("Selecting next image");
var activeImage = $(".company-image-slider__thumb-container").find(".is-active");
var nextImage = activeImage.next();
activeImage.removeClass("is-active");
nextImage.addClass("is-active");
if (nextImage.hasClass("is-last")) {
nextImage.trigger("click", {widget: this, direction: "next"}, this._scrollToThumbSet);
return false;
}
this._refreshMainFrame(activeImage.next().find("img"));
},
_prevImage: function () {
this.options.debug == true && console.log("Selecting previous image");
var activeImage = $(".company-image-slider__thumb-container").find(".is-active");
var prevImage = activeImage.prev();
activeImage.removeClass("is-active");
prevImage.addClass("is-active");
// when the first image was auto-selected,
// we need to go back as well.
if (activeImage.hasClass("is-first")) {
activeImage.trigger("click", {widget: this, direction: "prev"}, this._scrollToThumbSet);
return false;
}
if (prevImage.hasClass("is-first")) {
prevImage.trigger("click", {widget: this, direction: "prev"}, this._scrollToThumbSet);
return false;
}
this._refreshMainFrame(activeImage.prev().find("img"));
},
_refreshMainFrame: function (image) {
var currentImage = $('.company-image-slider__main-image').find("img");
currentImage.attr("src", this.options.imagePath + image.data("origin"));
},
_buildThumbs: function (photos) {
var widget = this;
var options = this.options;
options.debug == true && console.log("Building thumbnails");
var template = $(options.templateId);
template.addClass("is-loaded");
var container = $(".company-image-slider__thumb-container");
$.each(photos, function (i, photo) {
var thumb;
if (i == 0) {
// clone the thumb-set container once
thumb = template.clone();
} else {
thumb = template.find(".company-image-slider__thumb-container__thumb-set").clone();
}
var img = thumb.find( "img" );
img.attr({src: options.thumbPath + photo.src, alt: photo.alt});
img.attr("data-origin", photo.src);
img.attr("data-index", i);
// Add first and last classes to the thumbnail html
i == 0 && thumb.find( ".company-image-slider__thumb--small" ).addClass( "is-active" ).addClass( "is-first" );
i == options.thumbAmount - 1 && thumb.find( ".company-image-slider__thumb--small" ).addClass( "is-last" );
if (i == 0) {
// only apply the thumb-set container once
thumb.find(".company-image-slider__thumb-container__thumb-set").css("z-index", widget.thumbSetZindex);
widget.thumbSetZindex--;
container.append($.trim(thumb.html()));
} else {
// place the thumbnail html inside the thumb-set container
// and remove all the white spaces
$( ".company-image-slider__thumb-container > .company-image-slider__thumb-container__thumb-set:last-child" ).append(
$.trim(thumb.html())).contents().filter(function () {
return this.nodeType === 3;
}).remove();
}
});
// Add click events
$( ".company-image-slider__thumb--small" ).on(
"click", { widget: this }, this._handleThumbClick
);
$( ".company-image-slider__thumb--small.is-first" ).on(
"click", { widget: this, direction: "prev" }, function (e) {
widget._scrollToThumbSet(e);
widget._clearThumbs();
}
);
$( ".company-image-slider__thumb--small.is-last" ).on(
"click", { widget: this, direction: "next" }, function (e) {
widget._scrollToThumbSet(e);
widget._clearThumbs();
}
);
// Load remaining images message container
widget._showRemainingImages($( ".company-image-slider__thumb--small.is-last" ));
},
_showRemainingImages: function(element) {
var html = $( "<div></div>" );
html.addClass( "company-image-slider__message--block" );
var i = $(element).find( "img" ).data( "index" ) + 1;
var nextInLine = this._getPhotoCount() - i * this.thumbSetPosition;
if(nextInLine > 0) {
html.text( nextInLine + " more " );
$(element).prepend( html );
html.fadeIn( 500 );
}
},
_scrollToThumbSet: function (e) {
var widget = e.data.widget;
widget.options.debug == true && console.log("Scrolling to next slides");
if (e.data.direction == "next") {
if (widget.thumbSetPosition < widget.options.photos.length / widget.options.thumbAmount) {
widget.thumbSetPosition++;
}
} else {
if (widget.thumbSetPosition > 1) {
widget.thumbSetPosition--;
}
}
var nextSetEnd = widget.thumbSetPosition * widget.options.thumbAmount;
var nextSetStart = nextSetEnd - widget.options.thumbAmount;
var photos = widget._getPhotosByRange(nextSetStart, nextSetEnd);
widget._buildThumbs(photos);
},
_handleThumbClick: function (event) {
event.data.widget.options.debug == true && console.log("Handling thumbnail click");
$(this).siblings().removeClass("is-active");
$(this).addClass("is-active");
event.data.widget._refreshMainFrame($(this).find("img"));
},
_clearThumbs: function () {
this.options.debug == true && console.log("Clearing old thumbs nails");
var oldContainer = $( ".company-image-slider__thumb-container > div:nth-child(3)" );
oldContainer.fadeOut(1000, function () {
$(this).remove();
});
},
_destroy: function () {
this.options.debug == true && console.log("Destroy has been called");
if (this.element.hasClass("plugin-is-active")) {
this.element.removeClass("plugin-is-active");
}
},
start: function () {
this.options.debug == true && console.log("Plugin Company Image Slider running");
this._buildMainFrame();
var photos = this._getPhotosByRange(0, 4);
var image = $( ".company-image-slider__main-image img" ).attr("src", photos[0].src).attr("alt", photos[0].alt).attr("data-origin", photos[0].src);
this._refreshMainFrame(image);
this._buildThumbs(photos);
this._trigger("complete", null, {value: image});
}
});
})(jQuery, window, document);