123movies-seo/public/js/vendor/lightcase.js

1893 lines
51 KiB
JavaScript

/*
* Lightcase - jQuery Plugin
* The smart and flexible Lightbox Plugin.
*
* @author Cornel Boppart <cornel@bopp-art.com>
* @copyright Author
*
* @version 2.5.0 (11/03/2018)
*/
;(function ($) {
'use strict';
var _self = {
cache: {},
support: {},
objects: {},
/**
* Initializes the plugin
*
* @param {object} options
* @return {object}
*/
init: function (options) {
return this.each(function () {
$(this).unbind('click.lightcase').bind('click.lightcase', function (event) {
event.preventDefault();
$(this).lightcase('start', options);
});
});
},
/**
* Starts the plugin
*
* @param {object} options
* @return {void}
*/
start: function (options) {
_self.origin = lightcase.origin = this;
_self.settings = lightcase.settings = $.extend(true, {
idPrefix: 'lightcase-',
classPrefix: 'lightcase-',
attrPrefix: 'lc-',
transition: 'elastic',
transitionOpen: null,
transitionClose: null,
transitionIn: null,
transitionOut: null,
cssTransitions: true,
speedIn: 250,
speedOut: 250,
width: null,
height: null,
maxWidth: 800,
maxHeight: 500,
forceWidth: false,
forceHeight: false,
liveResize: true,
fullScreenModeForMobile: true,
mobileMatchExpression: /(iphone|ipod|ipad|android|blackberry|symbian)/,
disableShrink: false,
fixedRatio: true,
shrinkFactor: .75,
overlayOpacity: .9,
slideshow: false,
slideshowAutoStart: true,
breakBeforeShow: false,
timeout: 5000,
swipe: true,
useKeys: true,
useCategories: true,
useAsCollection: false,
navigateEndless: true,
closeOnOverlayClick: true,
title: null,
caption: null,
showTitle: true,
showCaption: true,
showSequenceInfo: true,
inline: {
width: 'auto',
height: 'auto'
},
ajax: {
width: 'auto',
height: 'auto',
type: 'get',
dataType: 'html',
data: {}
},
iframe: {
width: 800,
height: 500,
frameborder: 0
},
flash: {
width: 400,
height: 205,
wmode: 'transparent'
},
video: {
width: 400,
height: 225,
poster: '',
preload: 'auto',
controls: true,
autobuffer: true,
autoplay: true,
loop: false
},
attr: 'data-rel',
href: null,
type: null,
typeMapping: {
'image': 'jpg,jpeg,gif,png,bmp',
'flash': 'swf',
'video': 'mp4,mov,ogv,ogg,webm',
'iframe': 'html,php',
'ajax': 'json,txt',
'inline': '#'
},
errorMessage: function () {
return '<p class="' + _self.settings.classPrefix + 'error">' + _self.settings.labels['errorMessage'] + '</p>';
},
labels: {
'errorMessage': 'Source could not be found...',
'sequenceInfo.of': ' of ',
'close': 'Close',
'navigator.prev': 'Prev',
'navigator.next': 'Next',
'navigator.play': 'Play',
'navigator.pause': 'Pause'
},
markup: function () {
_self.objects.body.append(
_self.objects.overlay = $('<div id="' + _self.settings.idPrefix + 'overlay"></div>'),
_self.objects.loading = $('<div id="' + _self.settings.idPrefix + 'loading" class="' + _self.settings.classPrefix + 'icon-spin"></div>'),
_self.objects.case = $('<div id="' + _self.settings.idPrefix + 'case" aria-hidden="true" role="dialog"></div>')
);
_self.objects.case.after(
_self.objects.close = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-close"><span>' + _self.settings.labels['close'] + '</span></a>'),
_self.objects.nav = $('<div id="' + _self.settings.idPrefix + 'nav"></div>')
);
_self.objects.nav.append(
_self.objects.prev = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-prev"><span>' + _self.settings.labels['navigator.prev'] + '</span></a>').hide(),
_self.objects.next = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-next"><span>' + _self.settings.labels['navigator.next'] + '</span></a>').hide(),
_self.objects.play = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-play"><span>' + _self.settings.labels['navigator.play'] + '</span></a>').hide(),
_self.objects.pause = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-pause"><span>' + _self.settings.labels['navigator.pause'] + '</span></a>').hide()
);
_self.objects.case.append(
_self.objects.content = $('<div id="' + _self.settings.idPrefix + 'content"></div>'),
_self.objects.info = $('<div id="' + _self.settings.idPrefix + 'info"></div>')
);
_self.objects.content.append(
_self.objects.contentInner = $('<div class="' + _self.settings.classPrefix + 'contentInner"></div>')
);
_self.objects.info.append(
_self.objects.sequenceInfo = $('<div id="' + _self.settings.idPrefix + 'sequenceInfo"></div>'),
_self.objects.title = $('<h4 id="' + _self.settings.idPrefix + 'title"></h4>'),
_self.objects.caption = $('<p id="' + _self.settings.idPrefix + 'caption"></p>')
);
},
onInit: {},
onStart: {},
onBeforeCalculateDimensions: {},
onAfterCalculateDimensions: {},
onBeforeShow: {},
onFinish: {},
onResize: {},
onClose: {},
onCleanup: {}
},
options,
// Load options from data-lc-options attribute
_self.origin.data ? _self.origin.data('lc-options') : {});
_self.objects.document = $('html');
_self.objects.body = $('body');
// Call onInit hook functions
_self._callHooks(_self.settings.onInit);
_self.objectData = _self._setObjectData(this);
_self._addElements();
_self._open();
_self.dimensions = _self.getViewportDimensions();
},
/**
* Getter method for objects
*
* @param {string} name
* @return {object}
*/
get: function (name) {
return _self.objects[name];
},
/**
* Getter method for objectData
*
* @return {object}
*/
getObjectData: function () {
return _self.objectData;
},
/**
* Sets the object data
*
* @param {object} object
* @return {object} objectData
*/
_setObjectData: function (object) {
var $object = $(object),
objectData = {
this: $(object),
title: _self.settings.title || $object.attr(_self._prefixAttributeName('title')) || $object.attr('title'),
caption: _self.settings.caption || $object.attr(_self._prefixAttributeName('caption')) || $object.children('img').attr('alt'),
url: _self._determineUrl(),
requestType: _self.settings.ajax.type,
requestData: _self.settings.ajax.data,
requestDataType: _self.settings.ajax.dataType,
rel: $object.attr(_self._determineAttributeSelector()),
type: _self.settings.type || _self._verifyDataType(_self._determineUrl()),
isPartOfSequence: _self.settings.useAsCollection || _self._isPartOfSequence($object.attr(_self.settings.attr), ':'),
isPartOfSequenceWithSlideshow: _self._isPartOfSequence($object.attr(_self.settings.attr), ':slideshow'),
currentIndex: $(_self._determineAttributeSelector()).index($object),
sequenceLength: $(_self._determineAttributeSelector()).length
};
// Add sequence info to objectData
objectData.sequenceInfo = (objectData.currentIndex + 1) + _self.settings.labels['sequenceInfo.of'] + objectData.sequenceLength;
// Add next/prev index
objectData.prevIndex = objectData.currentIndex - 1;
objectData.nextIndex = objectData.currentIndex + 1;
return objectData;
},
/**
* Prefixes a data attribute name with defined name from 'settings.attrPrefix'
* to ensure more uniqueness for all lightcase related/used attributes.
*
* @param {string} name
* @return {string}
*/
_prefixAttributeName: function (name) {
return 'data-' + _self.settings.attrPrefix + name;
},
/**
* Determines the link target considering 'settings.href' and data attributes
* but also with a fallback to the default 'href' value.
*
* @return {string}
*/
_determineLinkTarget: function () {
return _self.settings.href || $(_self.origin).attr(_self._prefixAttributeName('href')) || $(_self.origin).attr('href');
},
/**
* Determines the attribute selector to use, depending on
* whether categorized collections are beeing used or not.
*
* @return {string} selector
*/
_determineAttributeSelector: function () {
var $origin = $(_self.origin),
selector = '';
if (typeof _self.cache.selector !== 'undefined') {
selector = _self.cache.selector;
} else if (_self.settings.useCategories === true && $origin.attr(_self._prefixAttributeName('categories'))) {
var categories = $origin.attr(_self._prefixAttributeName('categories')).split(' ');
$.each(categories, function (index, category) {
if (index > 0) {
selector += ',';
}
selector += '[' + _self._prefixAttributeName('categories') + '~="' + category + '"]';
});
} else {
selector = '[' + _self.settings.attr + '="' + $origin.attr(_self.settings.attr) + '"]';
}
_self.cache.selector = selector;
return selector;
},
/**
* Determines the correct resource according to the
* current viewport and density.
*
* @return {string} url
*/
_determineUrl: function () {
var dataUrl = _self._verifyDataUrl(_self._determineLinkTarget()),
width = 0,
density = 0,
supportLevel = '',
url;
$.each(dataUrl, function (index, src) {
switch (_self._verifyDataType(src.url)) {
case 'video':
var video = document.createElement('video'),
videoType = _self._verifyDataType(src.url) + '/' + _self._getFileUrlSuffix(src.url);
// Check if browser can play this type of video format
if (supportLevel !== 'probably' && supportLevel !== video.canPlayType(videoType) && video.canPlayType(videoType) !== '') {
supportLevel = video.canPlayType(videoType);
url = src.url;
}
break;
default:
if (
// Check density
_self._devicePixelRatio() >= src.density &&
src.density >= density &&
// Check viewport width
_self._matchMedia()('screen and (min-width:' + src.width + 'px)').matches &&
src.width >= width
) {
width = src.width;
density = src.density;
url = src.url;
}
break;
}
});
return url;
},
/**
* Normalizes an url and returns information about the resource path,
* the viewport width as well as density if defined.
*
* @param {string} url Path to resource in format of an url or srcset
* @return {object}
*/
_normalizeUrl: function (url) {
var srcExp = /^\d+$/;
return url.split(',').map(function (str) {
var src = {
width: 0,
density: 0
};
str.trim().split(/\s+/).forEach(function (url, i) {
if (i === 0) {
return src.url = url;
}
var value = url.substring(0, url.length - 1),
lastChar = url[url.length - 1],
intVal = parseInt(value, 10),
floatVal = parseFloat(value);
if (lastChar === 'w' && srcExp.test(value)) {
src.width = intVal;
} else if (lastChar === 'h' && srcExp.test(value)) {
src.height = intVal;
} else if (lastChar === 'x' && !isNaN(floatVal)) {
src.density = floatVal;
}
});
return src;
});
},
/**
* Verifies if the link is part of a sequence
*
* @param {string} rel
* @param {string} expression
* @return {boolean}
*/
_isPartOfSequence: function (rel, expression) {
var getSimilarLinks = $('[' + _self.settings.attr + '="' + rel + '"]'),
regexp = new RegExp(expression);
return (regexp.test(rel) && getSimilarLinks.length > 1);
},
/**
* Verifies if the slideshow should be enabled
*
* @return {boolean}
*/
isSlideshowEnabled: function () {
return (_self.objectData.isPartOfSequence && (_self.settings.slideshow === true || _self.objectData.isPartOfSequenceWithSlideshow === true));
},
/**
* Loads the new content to show
*
* @return {void}
*/
_loadContent: function () {
if (_self.cache.originalObject) {
_self._restoreObject();
}
_self._createObject();
},
/**
* Creates a new object
*
* @return {void}
*/
_createObject: function () {
var $object;
// Create object
switch (_self.objectData.type) {
case 'image':
$object = $(new Image());
$object.attr({
// The time expression is required to prevent the binding of an image load
'src': _self.objectData.url,
'alt': _self.objectData.title
});
break;
case 'inline':
$object = $('<div class="' + _self.settings.classPrefix + 'inlineWrap"></div>');
$object.html(_self._cloneObject($(_self.objectData.url)));
// Add custom attributes from _self.settings
$.each(_self.settings.inline, function (name, value) {
$object.attr(_self._prefixAttributeName(name), value);
});
break;
case 'ajax':
$object = $('<div class="' + _self.settings.classPrefix + 'inlineWrap"></div>');
// Add custom attributes from _self.settings
$.each(_self.settings.ajax, function (name, value) {
if (name !== 'data') {
$object.attr(_self._prefixAttributeName(name), value);
}
});
break;
case 'flash':
$object = $('<embed src="' + _self.objectData.url + '" type="application/x-shockwave-flash"></embed>');
// Add custom attributes from _self.settings
$.each(_self.settings.flash, function (name, value) {
$object.attr(name, value);
});
break;
case 'video':
$object = $('<video></video>');
$object.attr('src', _self.objectData.url);
// Add custom attributes from _self.settings
$.each(_self.settings.video, function (name, value) {
$object.attr(name, value);
});
break;
default:
$object = $('<iframe></iframe>');
$object.attr({
'src': _self.objectData.url
});
// Add custom attributes from _self.settings
$.each(_self.settings.iframe, function (name, value) {
$object.attr(name, value);
});
break;
}
_self._addObject($object);
_self._loadObject($object);
},
/**
* Adds the new object to the markup
*
* @param {object} $object
* @return {void}
*/
_addObject: function ($object) {
// Add object to content holder
_self.objects.contentInner.html($object);
// Start loading
_self._loading('start');
// Call onStart hook functions
_self._callHooks(_self.settings.onStart);
// Add sequenceInfo to the content holder or hide if its empty
if (_self.settings.showSequenceInfo === true && _self.objectData.isPartOfSequence) {
_self.objects.sequenceInfo.html(_self.objectData.sequenceInfo);
_self.objects.sequenceInfo.show();
} else {
_self.objects.sequenceInfo.empty();
_self.objects.sequenceInfo.hide();
}
// Add title to the content holder or hide if its empty
if (_self.settings.showTitle === true && _self.objectData.title !== undefined && _self.objectData.title !== '') {
_self.objects.title.html(_self.objectData.title);
_self.objects.title.show();
} else {
_self.objects.title.empty();
_self.objects.title.hide();
}
// Add caption to the content holder or hide if its empty
if (_self.settings.showCaption === true && _self.objectData.caption !== undefined && _self.objectData.caption !== '') {
_self.objects.caption.html(_self.objectData.caption);
_self.objects.caption.show();
} else {
_self.objects.caption.empty();
_self.objects.caption.hide();
}
},
/**
* Loads the new object
*
* @param {object} $object
* @return {void}
*/
_loadObject: function ($object) {
// Load the object
switch (_self.objectData.type) {
case 'inline':
if ($(_self.objectData.url)) {
_self._showContent($object);
} else {
_self.error();
}
break;
case 'ajax':
$.ajax(
$.extend({}, _self.settings.ajax, {
url: _self.objectData.url,
type: _self.objectData.requestType,
dataType: _self.objectData.requestDataType,
data: _self.objectData.requestData,
success: function (data, textStatus, jqXHR) {
// Check for X-Ajax-Location
if (jqXHR.getResponseHeader('X-Ajax-Location')) {
_self.objectData.url = jqXHR.getResponseHeader('X-Ajax-Location');
_self._loadObject($object);
}
else {
// Unserialize if data is transferred as json
if (_self.objectData.requestDataType === 'json') {
_self.objectData.data = data;
} else {
$object.html(data);
}
_self._showContent($object);
}
},
error: function (jqXHR, textStatus, errorThrown) {
_self.error();
}
})
);
break;
case 'flash':
_self._showContent($object);
break;
case 'video':
if (typeof($object.get(0).canPlayType) === 'function' || _self.objects.case.find('video').length === 0) {
_self._showContent($object);
} else {
_self.error();
}
break;
default:
if (_self.objectData.url) {
$object.on('load', function () {
_self._showContent($object);
});
$object.on('error', function () {
_self.error();
});
} else {
_self.error();
}
break;
}
},
/**
* Throws an error message if something went wrong
*
* @return {void}
*/
error: function () {
_self.objectData.type = 'error';
var $object = $('<div class="' + _self.settings.classPrefix + 'inlineWrap"></div>');
$object.html(_self.settings.errorMessage);
_self.objects.contentInner.html($object);
_self._showContent(_self.objects.contentInner);
},
/**
* Calculates the dimensions to fit content
*
* @param {object} $object
* @return {void}
*/
_calculateDimensions: function ($object) {
_self._cleanupDimensions();
if (!$object) return;
// Set default dimensions
var dimensions = {
ratio: 1,
objectWidth: $object.attr('width') ? $object.attr('width') : $object.attr(_self._prefixAttributeName('width')),
objectHeight: $object.attr('height') ? $object.attr('height') : $object.attr(_self._prefixAttributeName('height'))
};
if (!_self.settings.disableShrink) {
// Add calculated maximum width/height to dimensions
dimensions.maxWidth = parseInt(_self.dimensions.windowWidth * _self.settings.shrinkFactor);
dimensions.maxHeight = parseInt(_self.dimensions.windowHeight * _self.settings.shrinkFactor);
// If the auto calculated maxWidth/maxHeight greather than the user-defined one, use that.
if (dimensions.maxWidth > _self.settings.maxWidth) {
dimensions.maxWidth = _self.settings.maxWidth;
}
if (dimensions.maxHeight > _self.settings.maxHeight) {
dimensions.maxHeight = _self.settings.maxHeight;
}
// Calculate the difference between screen width/height and image width/height
dimensions.differenceWidthAsPercent = parseInt(100 / dimensions.maxWidth * dimensions.objectWidth);
dimensions.differenceHeightAsPercent = parseInt(100 / dimensions.maxHeight * dimensions.objectHeight);
switch (_self.objectData.type) {
case 'image':
case 'flash':
case 'video':
case 'iframe':
case 'ajax':
case 'inline':
if (_self.objectData.type === 'image' || _self.settings.fixedRatio === true) {
if (dimensions.differenceWidthAsPercent > 100 && dimensions.differenceWidthAsPercent > dimensions.differenceHeightAsPercent) {
dimensions.objectWidth = dimensions.maxWidth;
dimensions.objectHeight = parseInt(dimensions.objectHeight / dimensions.differenceWidthAsPercent * 100);
}
if (dimensions.differenceHeightAsPercent > 100 && dimensions.differenceHeightAsPercent > dimensions.differenceWidthAsPercent) {
dimensions.objectWidth = parseInt(dimensions.objectWidth / dimensions.differenceHeightAsPercent * 100);
dimensions.objectHeight = dimensions.maxHeight;
}
if (dimensions.differenceHeightAsPercent > 100 && dimensions.differenceWidthAsPercent < dimensions.differenceHeightAsPercent) {
dimensions.objectWidth = parseInt(dimensions.maxWidth / dimensions.differenceHeightAsPercent * dimensions.differenceWidthAsPercent);
dimensions.objectHeight = dimensions.maxHeight;
}
break;
}
case 'error':
if (!isNaN(dimensions.objectWidth) && dimensions.objectWidth > dimensions.maxWidth) {
dimensions.objectWidth = dimensions.maxWidth;
}
break;
default:
if ((isNaN(dimensions.objectWidth) || dimensions.objectWidth > dimensions.maxWidth) && !_self.settings.forceWidth) {
dimensions.objectWidth = dimensions.maxWidth;
}
if (((isNaN(dimensions.objectHeight) && dimensions.objectHeight !== 'auto') || dimensions.objectHeight > dimensions.maxHeight) && !_self.settings.forceHeight) {
dimensions.objectHeight = dimensions.maxHeight;
}
break;
}
}
if (_self.settings.forceWidth) {
try {
dimensions.objectWidth = _self.settings[_self.objectData.type].width;
} catch (e) {
dimensions.objectWidth = _self.settings.width || dimensions.objectWidth;
}
dimensions.maxWidth = null;
}
if ($object.attr(_self._prefixAttributeName('max-width'))) {
dimensions.maxWidth = $object.attr(_self._prefixAttributeName('max-width'));
}
if (_self.settings.forceHeight) {
try {
dimensions.objectHeight = _self.settings[_self.objectData.type].height;
} catch (e) {
dimensions.objectHeight = _self.settings.height || dimensions.objectHeight;
}
dimensions.maxHeight = null;
}
if ($object.attr(_self._prefixAttributeName('max-height'))) {
dimensions.maxHeight = $object.attr(_self._prefixAttributeName('max-height'));
}
_self._adjustDimensions($object, dimensions);
},
/**
* Adjusts the dimensions
*
* @param {object} $object
* @param {object} dimensions
* @return {void}
*/
_adjustDimensions: function ($object, dimensions) {
// Adjust width and height
$object.css({
'width': dimensions.objectWidth,
'height': dimensions.objectHeight,
'max-width': dimensions.maxWidth,
'max-height': dimensions.maxHeight
});
_self.objects.contentInner.css({
'width': $object.outerWidth(),
'height': $object.outerHeight(),
'max-width': '100%'
});
_self.objects.case.css({
'width': _self.objects.contentInner.outerWidth(),
'max-width': '100%'
});
// Adjust margin
_self.objects.case.css({
'margin-top': parseInt(-(_self.objects.case.outerHeight() / 2)),
'margin-left': parseInt(-(_self.objects.case.outerWidth() / 2))
});
},
/**
* Handles the _loading
*
* @param {string} process
* @return {void}
*/
_loading: function (process) {
if (process === 'start') {
_self.objects.case.addClass(_self.settings.classPrefix + 'loading');
_self.objects.loading.show();
} else if (process === 'end') {
_self.objects.case.removeClass(_self.settings.classPrefix + 'loading');
_self.objects.loading.hide();
}
},
/**
* Gets the client screen dimensions
*
* @return {object} dimensions
*/
getViewportDimensions: function () {
return {
windowWidth: $(window).innerWidth(),
windowHeight: $(window).innerHeight()
};
},
/**
* Verifies the url
*
* @param {string} dataUrl
* @return {object} dataUrl Clean url for processing content
*/
_verifyDataUrl: function (dataUrl) {
if (!dataUrl || dataUrl === undefined || dataUrl === '') {
return false;
}
if (dataUrl.indexOf('#') > -1) {
dataUrl = dataUrl.split('#');
dataUrl = '#' + dataUrl[dataUrl.length - 1];
}
return _self._normalizeUrl(dataUrl.toString());
},
//
/**
* Tries to get the (file) suffix of an url
*
* @param {string} url
* @return {string}
*/
_getFileUrlSuffix: function (url) {
var re = /(?:\.([^.]+))?$/;
return re.exec(url.toLowerCase())[1];
},
/**
* Verifies the data type of the content to load
*
* @param {string} url
* @return {string|boolean} Array key if expression matched, else false
*/
_verifyDataType: function (url) {
var typeMapping = _self.settings.typeMapping;
// Early abort if dataUrl couldn't be verified
if (!url) {
return false;
}
// Verify the dataType of url according to typeMapping which
// has been defined in settings.
for (var key in typeMapping) {
if (typeMapping.hasOwnProperty(key)) {
var suffixArr = typeMapping[key].split(',');
for (var i = 0; i < suffixArr.length; i++) {
var suffix = suffixArr[i].toLowerCase(),
regexp = new RegExp('\.(' + suffix + ')$', 'i'),
str = url.toLowerCase().split('?')[0].substr(-5);
if (regexp.test(str) === true || (key === 'inline' && (url.indexOf(suffix) > -1))) {
return key;
}
}
}
}
// If no expression matched, return 'iframe'.
return 'iframe';
},
/**
* Extends html markup with the essential tags
*
* @return {void}
*/
_addElements: function () {
if (typeof _self.objects.case !== 'undefined' && $('#' + _self.objects.case.attr('id')).length) {
return;
}
_self.settings.markup();
},
/**
* Shows the loaded content
*
* @param {object} $object
* @return {void}
*/
_showContent: function ($object) {
// Add data attribute with the object type
_self.objects.document.attr(_self._prefixAttributeName('type'), _self.objectData.type);
_self.cache.object = $object;
// Call onBeforeShow hook functions
_self._callHooks(_self.settings.onBeforeShow);
if (_self.settings.breakBeforeShow) return;
_self.show();
},
/**
* Starts the 'inTransition'
* @return {void}
*/
_startInTransition: function () {
switch (_self.transition.in()) {
case 'scrollTop':
case 'scrollRight':
case 'scrollBottom':
case 'scrollLeft':
case 'scrollHorizontal':
case 'scrollVertical':
_self.transition.scroll(_self.objects.case, 'in', _self.settings.speedIn);
_self.transition.fade(_self.objects.contentInner, 'in', _self.settings.speedIn);
break;
case 'elastic':
if (_self.objects.case.css('opacity') < 1) {
_self.transition.zoom(_self.objects.case, 'in', _self.settings.speedIn);
_self.transition.fade(_self.objects.contentInner, 'in', _self.settings.speedIn);
}
case 'fade':
case 'fadeInline':
_self.transition.fade(_self.objects.case, 'in', _self.settings.speedIn);
_self.transition.fade(_self.objects.contentInner, 'in', _self.settings.speedIn);
break;
default:
_self.transition.fade(_self.objects.case, 'in', 0);
break;
}
// End loading.
_self._loading('end');
_self.isBusy = false;
// Set index of the first item opened
if (!_self.cache.firstOpened) {
_self.cache.firstOpened = _self.objectData.this;
}
// Fade in the info with delay
_self.objects.info.hide();
setTimeout(function () {
_self.transition.fade(_self.objects.info, 'in', _self.settings.speedIn);
}, _self.settings.speedIn);
// Call onFinish hook functions
_self._callHooks(_self.settings.onFinish);
},
/**
* Processes the content to show
*
* @return {void}
*/
_processContent: function () {
_self.isBusy = true;
// Fade out the info at first
_self.transition.fade(_self.objects.info, 'out', 0);
switch (_self.settings.transitionOut) {
case 'scrollTop':
case 'scrollRight':
case 'scrollBottom':
case 'scrollLeft':
case 'scrollVertical':
case 'scrollHorizontal':
if (_self.objects.case.is(':hidden')) {
_self.transition.fade(_self.objects.contentInner, 'out', 0);
_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
_self._loadContent();
});
} else {
_self.transition.scroll(_self.objects.case, 'out', _self.settings.speedOut, function () {
_self._loadContent();
});
}
break;
case 'fade':
if (_self.objects.case.is(':hidden')) {
_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
_self._loadContent();
});
} else {
_self.transition.fade(_self.objects.case, 'out', _self.settings.speedOut, 0, function () {
_self._loadContent();
});
}
break;
case 'fadeInline':
case 'elastic':
if (_self.objects.case.is(':hidden')) {
_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
_self._loadContent();
});
} else {
_self.transition.fade(_self.objects.contentInner, 'out', _self.settings.speedOut, 0, function () {
_self._loadContent();
});
}
break;
default:
_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
_self._loadContent();
});
break;
}
},
/**
* Handles events for gallery buttons
*
* @return {void}
*/
_handleEvents: function () {
_self._unbindEvents();
_self.objects.nav.children().not(_self.objects.close).hide();
// If slideshow is enabled, show play/pause and start timeout.
if (_self.isSlideshowEnabled()) {
// Only start the timeout if slideshow autostart is enabled and slideshow is not pausing
if (
(_self.settings.slideshowAutoStart === true || _self.isSlideshowStarted) &&
!_self.objects.nav.hasClass(_self.settings.classPrefix + 'paused')
) {
_self._startTimeout();
} else {
_self._stopTimeout();
}
}
if (_self.settings.liveResize) {
_self._watchResizeInteraction();
}
_self.objects.close.click(function (event) {
event.preventDefault();
_self.close();
});
if (_self.settings.closeOnOverlayClick === true) {
_self.objects.overlay.css('cursor', 'pointer').click(function (event) {
event.preventDefault();
_self.close();
});
}
if (_self.settings.useKeys === true) {
_self._addKeyEvents();
}
if (_self.objectData.isPartOfSequence) {
_self.objects.nav.attr(_self._prefixAttributeName('ispartofsequence'), true);
_self.objects.nav.data('items', _self._setNavigation());
_self.objects.prev.click(function (event) {
event.preventDefault();
if (_self.settings.navigateEndless === true || !_self.item.isFirst()) {
_self.objects.prev.unbind('click');
_self.cache.action = 'prev';
_self.objects.nav.data('items').prev.click();
if (_self.isSlideshowEnabled()) {
_self._stopTimeout();
}
}
});
_self.objects.next.click(function (event) {
event.preventDefault();
if (_self.settings.navigateEndless === true || !_self.item.isLast()) {
_self.objects.next.unbind('click');
_self.cache.action = 'next';
_self.objects.nav.data('items').next.click();
if (_self.isSlideshowEnabled()) {
_self._stopTimeout();
}
}
});
if (_self.isSlideshowEnabled()) {
_self.objects.play.click(function (event) {
event.preventDefault();
_self._startTimeout();
});
_self.objects.pause.click(function (event) {
event.preventDefault();
_self._stopTimeout();
});
}
// Enable swiping if activated
if (_self.settings.swipe === true) {
if ($.isPlainObject($.event.special.swipeleft)) {
_self.objects.case.on('swipeleft', function (event) {
event.preventDefault();
_self.objects.next.click();
if (_self.isSlideshowEnabled()) {
_self._stopTimeout();
}
});
}
if ($.isPlainObject($.event.special.swiperight)) {
_self.objects.case.on('swiperight', function (event) {
event.preventDefault();
_self.objects.prev.click();
if (_self.isSlideshowEnabled()) {
_self._stopTimeout();
}
});
}
}
}
},
/**
* Adds the key events
*
* @return {void}
*/
_addKeyEvents: function () {
$(document).bind('keyup.lightcase', function (event) {
// Do nothing if lightcase is in process
if (_self.isBusy) {
return;
}
switch (event.keyCode) {
// Escape key
case 27:
_self.objects.close.click();
break;
// Backward key
case 37:
if (_self.objectData.isPartOfSequence) {
_self.objects.prev.click();
}
break;
// Forward key
case 39:
if (_self.objectData.isPartOfSequence) {
_self.objects.next.click();
}
break;
}
});
},
/**
* Starts the slideshow timeout
*
* @return {void}
*/
_startTimeout: function () {
_self.isSlideshowStarted = true;
_self.objects.play.hide();
_self.objects.pause.show();
_self.cache.action = 'next';
_self.objects.nav.removeClass(_self.settings.classPrefix + 'paused');
_self.timeout = setTimeout(function () {
_self.objects.nav.data('items').next.click();
}, _self.settings.timeout);
},
/**
* Stops the slideshow timeout
*
* @return {void}
*/
_stopTimeout: function () {
_self.objects.play.show();
_self.objects.pause.hide();
_self.objects.nav.addClass(_self.settings.classPrefix + 'paused');
clearTimeout(_self.timeout);
},
/**
* Sets the navigator buttons (prev/next)
*
* @return {object} items
*/
_setNavigation: function () {
var $links = $((_self.cache.selector || _self.settings.attr)),
sequenceLength = _self.objectData.sequenceLength - 1,
items = {
prev: $links.eq(_self.objectData.prevIndex),
next: $links.eq(_self.objectData.nextIndex)
};
if (_self.objectData.currentIndex > 0) {
_self.objects.prev.show();
} else {
items.prevItem = $links.eq(sequenceLength);
}
if (_self.objectData.nextIndex <= sequenceLength) {
_self.objects.next.show();
} else {
items.next = $links.eq(0);
}
if (_self.settings.navigateEndless === true) {
_self.objects.prev.show();
_self.objects.next.show();
}
return items;
},
/**
* Item information/status
*
*/
item: {
/**
* Verifies if the current item is first item.
*
* @return {boolean}
*/
isFirst: function () {
return (_self.objectData.currentIndex === 0);
},
/**
* Verifies if the current item is first item opened.
*
* @return {boolean}
*/
isFirstOpened: function () {
return _self.objectData.this.is(_self.cache.firstOpened);
},
/**
* Verifies if the current item is last item.
*
* @return {boolean}
*/
isLast: function () {
return (_self.objectData.currentIndex === (_self.objectData.sequenceLength - 1));
}
},
/**
* Clones the object for inline elements
*
* @param {object} $object
* @return {object} $clone
*/
_cloneObject: function ($object) {
var $clone = $object.clone(),
objectId = $object.attr('id');
// If element is hidden, cache the object and remove
if ($object.is(':hidden')) {
_self._cacheObjectData($object);
$object.attr('id', _self.settings.idPrefix + 'temp-' + objectId).empty();
} else {
// Prevent duplicated id's
$clone.removeAttr('id');
}
return $clone.show();
},
/**
* Verifies if it is a mobile device
*
* @return {boolean}
*/
isMobileDevice: function () {
var deviceAgent = navigator.userAgent.toLowerCase(),
agentId = deviceAgent.match(_self.settings.mobileMatchExpression);
return agentId ? true : false;
},
/**
* Verifies if css transitions are supported
*
* @return {string|boolean} The transition prefix if supported, else false.
*/
isTransitionSupported: function () {
var body = _self.objects.body.get(0),
isTransitionSupported = false,
transitionMapping = {
'transition': '',
'WebkitTransition': '-webkit-',
'MozTransition': '-moz-',
'OTransition': '-o-',
'MsTransition': '-ms-'
};
for (var key in transitionMapping) {
if (transitionMapping.hasOwnProperty(key) && key in body.style) {
_self.support.transition = transitionMapping[key];
isTransitionSupported = true;
}
}
return isTransitionSupported;
},
/**
* Transition types
*
*/
transition: {
/**
* Returns the correct transition type according to the status of interaction.
*
* @return {string} Transition type
*/
in: function () {
if (_self.settings.transitionOpen && !_self.cache.firstOpened) {
return _self.settings.transitionOpen;
}
return _self.settings.transitionIn;
},
/**
* Fades in/out the object
*
* @param {object} $object
* @param {string} type
* @param {number} speed
* @param {number} opacity
* @param {function} callback
* @return {void} Animates an object
*/
fade: function ($object, type, speed, opacity, callback) {
var isInTransition = type === 'in',
startTransition = {},
startOpacity = $object.css('opacity'),
endTransition = {},
endOpacity = opacity ? opacity: isInTransition ? 1 : 0;
if (!_self.isOpen && isInTransition) return;
startTransition['opacity'] = startOpacity;
endTransition['opacity'] = endOpacity;
$object.css(_self.support.transition + 'transition', 'none');
$object.css(startTransition).show();
// Css transition
if (_self.support.transitions) {
endTransition[_self.support.transition + 'transition'] = speed + 'ms ease';
setTimeout(function () {
$object.css(endTransition);
setTimeout(function () {
$object.css(_self.support.transition + 'transition', '');
if (callback && (_self.isOpen || !isInTransition)) {
callback();
}
}, speed);
}, 15);
} else {
// Fallback to js transition
$object.stop();
$object.animate(endTransition, speed, callback);
}
},
/**
* Scrolls in/out the object
*
* @param {object} $object
* @param {string} type
* @param {number} speed
* @param {function} callback
* @return {void} Animates an object
*/
scroll: function ($object, type, speed, callback) {
var isInTransition = type === 'in',
transition = isInTransition ? _self.settings.transitionIn : _self.settings.transitionOut,
direction = 'left',
startTransition = {},
startOpacity = isInTransition ? 0 : 1,
startOffset = isInTransition ? '-50%' : '50%',
endTransition = {},
endOpacity = isInTransition ? 1 : 0,
endOffset = isInTransition ? '50%' : '-50%';
if (!_self.isOpen && isInTransition) return;
switch (transition) {
case 'scrollTop':
direction = 'top';
break;
case 'scrollRight':
startOffset = isInTransition ? '150%' : '50%';
endOffset = isInTransition ? '50%' : '150%';
break;
case 'scrollBottom':
direction = 'top';
startOffset = isInTransition ? '150%' : '50%';
endOffset = isInTransition ? '50%' : '150%';
break;
case 'scrollHorizontal':
startOffset = isInTransition ? '150%' : '50%';
endOffset = isInTransition ? '50%' : '-50%';
break;
case 'scrollVertical':
direction = 'top';
startOffset = isInTransition ? '-50%' : '50%';
endOffset = isInTransition ? '50%' : '150%';
break;
}
if (_self.cache.action === 'prev') {
switch (transition) {
case 'scrollHorizontal':
startOffset = isInTransition ? '-50%' : '50%';
endOffset = isInTransition ? '50%' : '150%';
break;
case 'scrollVertical':
startOffset = isInTransition ? '150%' : '50%';
endOffset = isInTransition ? '50%' : '-50%';
break;
}
}
startTransition['opacity'] = startOpacity;
startTransition[direction] = startOffset;
endTransition['opacity'] = endOpacity;
endTransition[direction] = endOffset;
$object.css(_self.support.transition + 'transition', 'none');
$object.css(startTransition).show();
// Css transition
if (_self.support.transitions) {
endTransition[_self.support.transition + 'transition'] = speed + 'ms ease';
setTimeout(function () {
$object.css(endTransition);
setTimeout(function () {
$object.css(_self.support.transition + 'transition', '');
if (callback && (_self.isOpen || !isInTransition)) {
callback();
}
}, speed);
}, 15);
} else {
// Fallback to js transition
$object.stop();
$object.animate(endTransition, speed, callback);
}
},
/**
* Zooms in/out the object
*
* @param {object} $object
* @param {string} type
* @param {number} speed
* @param {function} callback
* @return {void} Animates an object
*/
zoom: function ($object, type, speed, callback) {
var isInTransition = type === 'in',
startTransition = {},
startOpacity = $object.css('opacity'),
startScale = isInTransition ? 'scale(0.75)' : 'scale(1)',
endTransition = {},
endOpacity = isInTransition ? 1 : 0,
endScale = isInTransition ? 'scale(1)' : 'scale(0.75)';
if (!_self.isOpen && isInTransition) return;
startTransition['opacity'] = startOpacity;
startTransition[_self.support.transition + 'transform'] = startScale;
endTransition['opacity'] = endOpacity;
$object.css(_self.support.transition + 'transition', 'none');
$object.css(startTransition).show();
// Css transition
if (_self.support.transitions) {
endTransition[_self.support.transition + 'transform'] = endScale;
endTransition[_self.support.transition + 'transition'] = speed + 'ms ease';
setTimeout(function () {
$object.css(endTransition);
setTimeout(function () {
$object.css(_self.support.transition + 'transform', '');
$object.css(_self.support.transition + 'transition', '');
if (callback && (_self.isOpen || !isInTransition)) {
callback();
}
}, speed);
}, 15);
} else {
// Fallback to js transition
$object.stop();
$object.animate(endTransition, speed, callback);
}
}
},
/**
* Calls all the registered functions of a specific hook
*
* @param {object} hooks
* @return {void}
*/
_callHooks: function (hooks) {
if (typeof(hooks) === 'object') {
$.each(hooks, function(index, hook) {
if (typeof(hook) === 'function') {
hook.call(_self.origin);
}
});
}
},
/**
* Caches the object data
*
* @param {object} $object
* @return {void}
*/
_cacheObjectData: function ($object) {
$.data($object, 'cache', {
id: $object.attr('id'),
content: $object.html()
});
_self.cache.originalObject = $object;
},
/**
* Restores the object from cache
*
* @return void
*/
_restoreObject: function () {
var $object = $('[id^="' + _self.settings.idPrefix + 'temp-"]');
$object.attr('id', $.data(_self.cache.originalObject, 'cache').id);
$object.html($.data(_self.cache.originalObject, 'cache').content);
},
/**
* Executes functions for a window resize.
* It stops an eventual timeout and recalculates dimensions.
*
* @param {object} dimensions
* @return {void}
*/
resize: function (event, dimensions) {
if (!_self.isOpen) return;
if (_self.isSlideshowEnabled()) {
_self._stopTimeout();
}
if (typeof dimensions === 'object' && dimensions !== null) {
if (dimensions.width) {
_self.cache.object.attr(
_self._prefixAttributeName('width'),
dimensions.width
);
}
if (dimensions.maxWidth) {
_self.cache.object.attr(
_self._prefixAttributeName('max-width'),
dimensions.maxWidth
);
}
if (dimensions.height) {
_self.cache.object.attr(
_self._prefixAttributeName('height'),
dimensions.height
);
}
if (dimensions.maxHeight) {
_self.cache.object.attr(
_self._prefixAttributeName('max-height'),
dimensions.maxHeight
);
}
}
_self.dimensions = _self.getViewportDimensions();
_self._calculateDimensions(_self.cache.object);
// Call onResize hook functions
_self._callHooks(_self.settings.onResize);
},
/**
* Watches for any resize interaction and caches the new sizes.
*
* @return {void}
*/
_watchResizeInteraction: function () {
$(window).resize(_self.resize);
},
/**
* Stop watching any resize interaction related to _self.
*
* @return {void}
*/
_unwatchResizeInteraction: function () {
$(window).off('resize', _self.resize);
},
/**
* Switches to the fullscreen mode
*
* @return {void}
*/
_switchToFullScreenMode: function () {
_self.settings.shrinkFactor = 1;
_self.settings.overlayOpacity = 1;
$('html').addClass(_self.settings.classPrefix + 'fullScreenMode');
},
/**
* Enters into the lightcase view
*
* @return {void}
*/
_open: function () {
_self.isOpen = true;
_self.support.transitions = _self.settings.cssTransitions ? _self.isTransitionSupported() : false;
_self.support.mobileDevice = _self.isMobileDevice();
if (_self.support.mobileDevice) {
$('html').addClass(_self.settings.classPrefix + 'isMobileDevice');
if (_self.settings.fullScreenModeForMobile) {
_self._switchToFullScreenMode();
}
}
if (!_self.settings.transitionIn) {
_self.settings.transitionIn = _self.settings.transition;
}
if (!_self.settings.transitionOut) {
_self.settings.transitionOut = _self.settings.transition;
}
switch (_self.transition.in()) {
case 'fade':
case 'fadeInline':
case 'elastic':
case 'scrollTop':
case 'scrollRight':
case 'scrollBottom':
case 'scrollLeft':
case 'scrollVertical':
case 'scrollHorizontal':
if (_self.objects.case.is(':hidden')) {
_self.objects.close.css('opacity', 0);
_self.objects.overlay.css('opacity', 0);
_self.objects.case.css('opacity', 0);
_self.objects.contentInner.css('opacity', 0);
}
_self.transition.fade(_self.objects.overlay, 'in', _self.settings.speedIn, _self.settings.overlayOpacity, function () {
_self.transition.fade(_self.objects.close, 'in', _self.settings.speedIn);
_self._handleEvents();
_self._processContent();
});
break;
default:
_self.transition.fade(_self.objects.overlay, 'in', 0, _self.settings.overlayOpacity, function () {
_self.transition.fade(_self.objects.close, 'in', 0);
_self._handleEvents();
_self._processContent();
});
break;
}
_self.objects.document.addClass(_self.settings.classPrefix + 'open');
_self.objects.case.attr('aria-hidden', 'false');
},
/**
* Shows the lightcase by starting the transition
*/
show: function () {
// Call onCalculateDimensions hook functions
_self._callHooks(_self.settings.onBeforeCalculateDimensions);
_self._calculateDimensions(_self.cache.object);
// Call onAfterCalculateDimensions hook functions
_self._callHooks(_self.settings.onAfterCalculateDimensions);
_self._startInTransition();
},
/**
* Escapes from the lightcase view
*
* @return {void}
*/
close: function () {
_self.isOpen = false;
if (_self.isSlideshowEnabled()) {
_self._stopTimeout();
_self.isSlideshowStarted = false;
_self.objects.nav.removeClass(_self.settings.classPrefix + 'paused');
}
_self.objects.loading.hide();
_self._unbindEvents();
_self._unwatchResizeInteraction();
$('html').removeClass(_self.settings.classPrefix + 'open');
_self.objects.case.attr('aria-hidden', 'true');
_self.objects.nav.children().hide();
_self.objects.close.hide();
// Call onClose hook functions
_self._callHooks(_self.settings.onClose);
// Fade out the info at first
_self.transition.fade(_self.objects.info, 'out', 0);
switch (_self.settings.transitionClose || _self.settings.transitionOut) {
case 'fade':
case 'fadeInline':
case 'scrollTop':
case 'scrollRight':
case 'scrollBottom':
case 'scrollLeft':
case 'scrollHorizontal':
case 'scrollVertical':
_self.transition.fade(_self.objects.case, 'out', _self.settings.speedOut, 0, function () {
_self.transition.fade(_self.objects.overlay, 'out', _self.settings.speedOut, 0, function () {
_self.cleanup();
});
});
break;
case 'elastic':
_self.transition.zoom(_self.objects.case, 'out', _self.settings.speedOut, function () {
_self.transition.fade(_self.objects.overlay, 'out', _self.settings.speedOut, 0, function () {
_self.cleanup();
});
});
break;
default:
_self.cleanup();
break;
}
},
/**
* Unbinds all given events
*
* @return {void}
*/
_unbindEvents: function () {
// Unbind overlay event
_self.objects.overlay.unbind('click');
// Unbind key events
$(document).unbind('keyup.lightcase');
// Unbind swipe events
_self.objects.case.unbind('swipeleft').unbind('swiperight');
// Unbind navigator events
_self.objects.prev.unbind('click');
_self.objects.next.unbind('click');
_self.objects.play.unbind('click');
_self.objects.pause.unbind('click');
// Unbind close event
_self.objects.close.unbind('click');
},
/**
* Cleans up the dimensions
*
* @return {void}
*/
_cleanupDimensions: function () {
var opacity = _self.objects.contentInner.css('opacity');
_self.objects.case.css({
'width': '',
'height': '',
'top': '',
'left': '',
'margin-top': '',
'margin-left': ''
});
_self.objects.contentInner.removeAttr('style').css('opacity', opacity);
_self.objects.contentInner.children().removeAttr('style');
},
/**
* Cleanup after aborting lightcase
*
* @return {void}
*/
cleanup: function () {
_self._cleanupDimensions();
_self.objects.loading.hide();
_self.objects.overlay.hide();
_self.objects.case.hide();
_self.objects.prev.hide();
_self.objects.next.hide();
_self.objects.play.hide();
_self.objects.pause.hide();
_self.objects.document.removeAttr(_self._prefixAttributeName('type'));
_self.objects.nav.removeAttr(_self._prefixAttributeName('ispartofsequence'));
_self.objects.contentInner.empty().hide();
_self.objects.info.children().empty();
if (_self.cache.originalObject) {
_self._restoreObject();
}
// Call onCleanup hook functions
_self._callHooks(_self.settings.onCleanup);
// Restore cache
_self.cache = {};
},
/**
* Returns the supported match media or undefined if the browser
* doesn't support match media.
*
* @return {mixed}
*/
_matchMedia: function () {
return window.matchMedia || window.msMatchMedia;
},
/**
* Returns the devicePixelRatio if supported. Else, it simply returns
* 1 as the default.
*
* @return {number}
*/
_devicePixelRatio: function () {
return window.devicePixelRatio || 1;
},
/**
* Checks if method is public
*
* @return {boolean}
*/
_isPublicMethod: function (method) {
return (typeof _self[method] === 'function' && method.charAt(0) !== '_');
},
/**
* Exports all public methods to be accessible, callable
* from global scope.
*
* @return {void}
*/
_export: function () {
window.lightcase = {};
$.each(_self, function (property) {
if (_self._isPublicMethod(property)) {
lightcase[property] = _self[property];
}
});
}
};
_self._export();
$.fn.lightcase = function (method) {
// Method calling logic (only public methods are applied)
if (_self._isPublicMethod(method)) {
return _self[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return _self.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.lightcase');
}
};
})(jQuery);