/*
* Copyright 2024, Theia Post Slider, Liviu Cristian Mirea Ghiban.
*/
var tps = tps || {};
tps.slideshowsOnPage = 0;
tps.createSlideshowDefaults = {
'src': '',
'dest': '',
'nav': [],
'navText': '%{currentSlide} of %{totalSlides}',
'helperText': '',
'defaultSlide': 0,
'transitionEffect': 'none',
'transitionSpeed': 400,
'keyboardShortcuts': false,
'slides': [],
'prevPost': null,
'nextPost': null,
'prevText': null,
'nextText': null,
'buttonWidth': 0,
'prevText_post': null,
'nextText_post': null,
'buttonWidth_post': 0,
onShowPost: null,
postUrl: null
};
tps.createSlideshow = function(options) {
tps.slideshowsOnPage++;
var i,
me = this,
$ = jQuery,
defaults = tps.createSlideshowDefaults;
me.options = $.extend(defaults, options);
me.srcE = $(me.options.src);
me.destE = $(me.options.dest);
if (me.destE.length == 0) {
return;
}
me.navEl = [];
for (i = 0; i < me.options.nav.length; i++) {
var e = $(me.options.nav[i]);
if (e.length == 1) {
me.navEl.push({
container: e
});
}
}
me.currentPost = null;
me.isLoadingPost = false;
me.cachedPosts = {};
// The current slide
me.currentSlide = null;
// The slide that is currently displayed. This may lag behind me.currentSlide because of the animations.
me.currentlyDisplayedSlide = null;
// The number of animations that are currently running.
me.animations = 0;
me.navEffect = tps.transitions[me.options.transitionEffect];
// A queue that is executed when no animation is running.
me.queue = [];
me.asyncQueue = async.queue(function (task, callback) {
callback();
}, 1);
// Initialization function
me.init = function() {
var i;
// Get slides from me.options.slides
me.slides = [];
for (i = 0; i < me.options.slides.length; i++) {
if (me.options.defaultSlide == i) {
//me.options.slides[i].content = me.srcE;
}
else {
var e = $('
');
e.html(me.options.slides[i].content);
me.options.slides[i].content = e;
}
me.slides[i] = me.options.slides[i];
}
// Get slides from me.options.src element.
var srcSlides = $(me.options.src);
for (i = 0; i < srcSlides.length; i++) {
var s = $(srcSlides[i]);
s.detach();
var index = me.options.defaultSlide + i;
me.slides[index] = me.slides[index] || {};
me.slides[index].content = s;
}
// Count the slides.
me.numberOfSlides = me.slides.length;
// Setup the navigation bars.
for (i = 0; i < me.navEl.length; i++) {
var navEl = me.navEl[i];
navEl.text = navEl.container.find('._text');
navEl.prev = navEl.container.find('._prev')
.click(function(that) {
return function() {
that.setPrev();
return false;
}
}(me));
navEl.next = navEl.container.find('._next')
.click(function(that) {
return function() {
that.setNext();
return false;
}
}(me));
navEl.title = navEl.container.find('._title');
// Get the default slide's title. The title will be the same for all navigation bars, so get it only from the first.
if (i === 0) {
me.slides[me.options.defaultSlide].shortCodeTitle = navEl.title.html();
}
/*
Add _active class on mousedown. This is a fix for IE and Opera which don't match :active on container elements.
Also, return false to prevent double click context menu in Opera.
*/
navEl.container.find('._prev, ._next')
.mousedown(function() {
$(this).addClass('_active');
return false;
})
.mouseup(function() {
$(this).removeClass('_active');
});
}
// Show the first slide
me.setSlide(me.options.defaultSlide);
// Enable keyboard shortcuts
if (me.options.keyboardShortcuts) {
$(document).keydown(function(me) {
return function(e) {
// Disable shortcut if there is more than one slideshow on the page.
if (tps.slideshowsOnPage > 1) {
return;
}
// Disable shortcut if the target element is editable (input boxes, textareas, etc.).
if (
this !== e.target &&
(
/textarea|select/i.test( e.target.nodeName ) ||
e.target.type === "text" ||
(
$(e.target).prop &&
$(e.target).prop('contenteditable') == 'true'
)
)
) {
return;
}
switch (e.which) {
case 37:
me.setPrev();
return false;
case 39:
me.setNext();
return false;
}
};
}(me));
}
}
// Enqueue a function to be executed when no animation is running.
me.addToQueue = function(type, merge, func) {
if (merge) {
// If there is another call enqueued of the same type, then remove it.
// This is useful in case the user clicks the back/next buttons very fast and the slider lags behind because of the animations.
// Basically, this will skip the intermediary slides and display the last one.
for (var i = 0; i < me.queue.length; i++) {
if (me.queue[i].type == type) {
me.queue.splice(i, 1);
}
}
}
me.queue.push({
type: type,
func: func
});
me.executeQueue();
}
// Execute the queue while there are no active animations.
me.executeQueue = function() {
me.asyncQueue.push({name: 'foo'}, function(me) {
return function(err) {
while (me.animations == 0 && me.queue.length > 0) {
var q = me.queue.shift();
q.func(me);
}
};
}(me));
}
// Attach an animation (i.e. an animation has started). The queue won't be executed until the animations have all finished.
me.attachAnimation = function() {
me.animations++;
}
// Detach an animation (i.e. an animation has finished).
me.detachAnimation = function() {
me.animations--;
me.executeQueue();
}
// Set the current slide.
me.setSlide = function(index, force) {
if (me.isLoadingPost == true && force != true) {
return;
}
var i;
if (me.currentSlide == index) {
return;
}
var previousSlide = me.currentSlide;
me.currentSlide = index;
// Scroll the window up, if the beginning of the slide is out-of-view.
if (previousSlide != null) {
// Get the lowest offset.top
var scrollTop = me.destE.offset().top;
for (i = 0; i < me.navEl.length; i++) {
scrollTop = Math.min(scrollTop, me.navEl[i].container.offset().top);
}
if ($(window).scrollTop() > scrollTop) {
//$('body,html').scrollTop(scrollTop);
$('body,html').animate({scrollTop: scrollTop}, me.options.transitionSpeed);
}
}
// Set the title text.
me.updateTitleText();
// Set the navigation bars.
me.updateNavigationBars();
// Change URL, but only if this isn't the first slide set (i.e. the default slide).
if (previousSlide != null) {
var history = window.History;
if (history.enabled) {
var url = me.slides[me.currentSlide].permalink;
// Don't do anything if the slide doesn't have a permalink.
if (url) {
// TODO: move this somewhere else.
history.Adapter.bind(window, 'statechange', function(me) {
return function() {
var state = History.getState();
if (state.data.currentSlide != undefined) {
me.setSlide(state.data.currentSlide);
}
else {
me.setSlide(me.options.defaultSlide);
}
};
}(me));
history.pushState({
currentSlide: index
}, me.slides[me.currentSlide].title, url);
}
}
}
// Show the slide.
me.addToQueue('showSlide', true, function(me) {
me.showSlide();
});
}
// Show (display) the current slide using the chosen animation.
me.showSlide = function() {
// Don't do anything if the current slide is already shown.
if (me.currentlyDisplayedSlide == me.currentSlide) {
return;
}
// Track the pageview if this isn't the first slide displayed.
if (me.currentlyDisplayedSlide != null && me.slides[me.currentSlide]['permalink']) {
// URL Path
var path = me.slides[me.currentSlide]['permalink'].split('/');
if (path.length >= 4) {
path = '/' + path.slice(3).join('/');
// Google Analytics Async.
if (typeof _gaq !== 'undefined' && typeof _gaq.push !== 'undefined') {
_gaq.push(['_trackPageview', path]);
}
else {
// Google Analytics Traditional (ga.js).
if (typeof pageTracker !== 'undefined' && typeof pageTracker._trackPageview !== 'undefined') {
pageTracker._trackPageview(path);
}
}
// Piwik
if (typeof piwikTracker !== 'undefined' && typeof piwikTracker.trackPageView !== 'undefined') {
piwikTracker.trackPageView(path);
}
// StatCounter
if (typeof sc_project !== 'undefined' && typeof sc_security !== 'undefined') {
var img = new Image();
img.src = '//c.statcounter.com/' + sc_project + '/0/' + sc_security + '/1/';
}
// Quantcast
if (typeof _qacct !== 'undefined') {
var img = new Image();
img.src = '//pixel.quantserve.com/pixel/' + _qacct + '.gif';
}
}
}
var previousIndex = me.currentlyDisplayedSlide;
me.currentlyDisplayedSlide = me.currentSlide;
// Change the slide while applying a certain effect/animation.
me.navEffect(me, previousIndex, me.currentlyDisplayedSlide);
}
// Function that is called right after a new slide has been added to the DOM. The animation, if present, had just begun.
me.onNewSlide = function() {
// "BJ Lazy Load" plugin.
$(".lazy-hidden").not(".data-lazy-ready").one("scrollin.bj_lazy_load", {
distance: 200
}, function() {
var b =$(this),
d = b.attr("data-lazy-type");
if (d == "image") {
b.hide().attr("src", b.attr("data-lazy-src")).removeClass("lazy-hidden").fadeIn()
} else if (d == "iframe") {
b.replaceWith(c(b.attr("data-lazy-src")))
}
}).addClass("data-lazy-ready");
// "Lazy Load" plugin.
var events = $('body').data('events');
if (events && events['post-load']) {
for (var i = 0; i < events['post-load'].length; i++) {
if (events['post-load'][i].handler.name == 'lazy_load_init') {
events['post-load'][i].handler();
}
}
}
}
// Update the title text.
me.updateTitleText = function() {
var shortCodeTitle = me.slides[me.currentSlide].shortCodeTitle;
if (!shortCodeTitle) {
shortCodeTitle = '' + me.options['helperText'] + '';
}
for (i = 0; i < me.navEl.length; i++) {
me.navEl[i].title.html(shortCodeTitle);
}
}
// Update the navigation bar's text and buttons.
me.updateNavigationBars = function() {
for (var i = 0; i < me.navEl.length; i++) {
var navEl = me.navEl[i];
var navText = me.options.navText;
navText = navText.replace('%{currentSlide}', me.currentSlide + 1);
navText = navText.replace('%{totalSlides}', me.numberOfSlides);
navEl.text.html(navText);
// Update buttons.
me.updateNavigationBarButton(navEl, false);
me.updateNavigationBarButton(navEl, true);
}
}
// Update a button from a navigation bar.
me.updateNavigationBarButton = function(navEl, direction) {
var width,
html,
directionName = direction ? 'next' : 'prev',
buttonEl = navEl[directionName];
if (
(direction == false && me.options.prevPost && me.currentSlide == 0) ||
(direction == true && me.options.nextPost && me.currentSlide == me.numberOfSlides - 1)
) {
width = me.options.buttonWidth_post;
html = me.options[directionName + 'Text_post'];
}
else {
width = me.options.buttonWidth;
html = me.options[directionName + 'Text'];
}
buttonEl.find('._2')
.css('width', width > 0 ? width : '')
.html(html);
// Disable or enable
if (
(direction == false && me.options.prevPost == null && me.currentSlide == 0) ||
(direction == true && me.options.nextPost == null && me.currentSlide == me.numberOfSlides - 1)
) {
buttonEl.addClass('_disabled');
}
else {
buttonEl.removeClass('_disabled');
}
}
// Go to the previous slide.
me.setPrev = function() {
if (me.currentSlide == 0) {
if (me.options.prevPost) {
me.showPost(me.options.prevPost);
}
}
else {
me.setSlide(me.currentSlide - 1);
}
}
// Go to the next slide.
me.setNext = function() {
if (me.currentSlide == me.numberOfSlides - 1) {
if (me.options.nextPost) {
me.showPost(me.options.nextPost);
}
}
else {
me.setSlide(me.currentSlide + 1);
}
}
me.showPost = function(postUrl) {
if (me.isLoadingPost) {
return;
}
me.isLoadingPost = true;
window.location = postUrl;
};
// Set the transition properties (used in Live Preview).
me.setTransition = function(options) {
var defaults = {
'effect': me.options.transitionEffect,
'speed': me.options.transitionSpeed
};
options = $.extend(defaults, options);
me.options.transitionEffect = options.effect;
me.options.transitionSpeed = options.speed;
me.navEffect = tps.transitions[me.options.transitionEffect];
}
// Set the navigation bar's text template (used in Live Preview).
me.setNavText = function(text) {
me.options.navText = text;
me.updateNavigationBars();
}
// Set the title for all slides (used in Live Preview).
me.setTitleText = function(text) {
for (i = 0; i < me.slides.length; i++) {
me.slides[i].shortCodeTitle = '';
}
me.options.helperText = text;
me.updateTitleText();
}
// Initialize the slider.
me.init();
};
tps.createSlideshowDefaults.onShowPost = function(options) {
var $ = jQuery;
$('iframe').each(function(index) {
var src = $(this).attr('src');
if (!src) {
return;
}
src = src.replace(options.oldUrl, options.newUrl);
src = src.replace(encodeURIComponent(options.oldUrl), encodeURIComponent(options.newUrl));
if ($(this).attr('src') != src) {
$(this).attr('src', src);
}
});
};