PageSourceSearch

https://www.dharmadrum.org/script/lightcase.js

js dharmadrum.org collected 2026-10-02 10:45:03 UTC 52,036 bytes, 1,891 lines download raw bytes

1/*
2 * Lightcase - jQuery Plugin
3 * The smart and flexible Lightbox Plugin.
4 *
5 * @author		Cornel Boppart <[email protected]>
6 * @copyright	Author
7 *
8 * @version		2.5.0 (11/03/2018)
9 */
10
11;(function ($) {
12
13	'use strict';
14
15	var _self = {
16		cache: {},
17
18		support: {},
19
20		objects: {},
21
22		/**
23		 * Initializes the plugin
24		 *
25		 * @param	{object}	options
26		 * @return	{object}
27		 */
28		init: function (options) {
29			return this.each(function () {
30				$(this).unbind('click.lightcase').bind('click.lightcase', function (event) {
31					event.preventDefault();
32					$(this).lightcase('start', options);
33				});
34			});
35		},
36
37		/**
38		 * Starts the plugin
39		 *
40		 * @param	{object}	options
41		 * @return	{void}
42		 */
43		start: function (options) {
44			_self.origin = lightcase.origin = this;
45
46			_self.settings = lightcase.settings = $.extend(true, {
47				idPrefix: 'lightcase-',
48				classPrefix: 'lightcase-',
49				attrPrefix: 'lc-',
50				transition: 'elastic',
51				transitionOpen: null,
52				transitionClose: null,
53				transitionIn: null,
54				transitionOut: null,
55				cssTransitions: true,
56				speedIn: 250,
57				speedOut: 250,
58				width: null,
59				height: null,
60				maxWidth: 800,
61				maxHeight: 500,
62				forceWidth: false,
63				forceHeight: false,
64				liveResize: true,
65				fullScreenModeForMobile: true,
66				mobileMatchExpression: /(iphone|ipod|ipad|android|blackberry|symbian)/,
67				disableShrink: false,
68				fixedRatio: true,
69				shrinkFactor: .75,
70				overlayOpacity: .9,
71				slideshow: false,
72				slideshowAutoStart: true,
73				breakBeforeShow: false,
74				timeout: 5000,
75				swipe: true,
76				useKeys: true,
77				useCategories: true,
78				useAsCollection: false,
79				navigateEndless: true,
80				closeOnOverlayClick: true,
81				title: null,
82				caption: null,
83				showTitle: true,
84				showCaption: true,
85				showSequenceInfo: true,
86				inline: {
87					width: 'auto',
88					height: 'auto'
89				},
90				ajax: {
91					width: 'auto',
92					height: 'auto',
93					type: 'get',
94					dataType: 'html',
95					data: {}
96				},
97				iframe: {
98					width: 800,
99					height: 500,
100					frameborder: 0
101				},
102				flash: {
103					width: 400,
104					height: 205,
105					wmode: 'transparent'
106				},
107				video: {
108					width: 400,
109					height: 225,
110					poster: '',
111					preload: 'auto',
112					controls: true,
113					autobuffer: true,
114					autoplay: true,
115					loop: false
116				},
117				attr: 'data-rel',
118				href: null,
119				type: null,
120				typeMapping: {
121					'image': 'jpg,jpeg,gif,png,bmp',
122					'flash': 'swf',
123					'video': 'mp4,mov,ogv,ogg,webm',
124					'iframe': 'html,php',
125					'ajax': 'json,txt',
126					'inline': '#'
127				},
128				errorMessage: function () {
129					return '<p class="' + _self.settings.classPrefix + 'error">' + _self.settings.labels['errorMessage'] + '</p>';
130				},
131				labels: {
132					'errorMessage': 'Source could not be found...',
133					'sequenceInfo.of': ' of ',
134					'close': 'Close',
135					'navigator.prev': 'Prev',
136					'navigator.next': 'Next',
137 					'navigator.play': 'Play',
138					'navigator.pause': 'Pause'
139				},
140				markup: function () {
141					_self.objects.body.append(
142						_self.objects.overlay = $('<div id="' + _self.settings.idPrefix + 'overlay"></div>'),
143						_self.objects.loading = $('<div id="' + _self.settings.idPrefix + 'loading" class="' + _self.settings.classPrefix + 'icon-spin"></div>'),
144						_self.objects.case = $('<div id="' + _self.settings.idPrefix + 'case" aria-hidden="true" role="dialog"></div>')
145					);
146					_self.objects.case.append(
147						_self.objects.content = $('<div id="' + _self.settings.idPrefix + 'content"></div>'),
148						_self.objects.info = $('<div id="' + _self.settings.idPrefix + 'info"></div>'),
149						_self.objects.close = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-close"><span>' + _self.settings.labels['close'] + '</span></a>'),
150						_self.objects.nav = $('<div id="' + _self.settings.idPrefix + 'nav"></div>')
151					);
152					_self.objects.content.append(
153						_self.objects.contentInner = $('<div class="' + _self.settings.classPrefix + 'contentInner"></div>')
154					);
155					_self.objects.info.append(
156						_self.objects.sequenceInfo = $('<div id="' + _self.settings.idPrefix + 'sequenceInfo"></div>'),
157						_self.objects.title = $('<h4 id="' + _self.settings.idPrefix + 'title"></h4>'),
158						_self.objects.caption = $('<p id="' + _self.settings.idPrefix + 'caption"></p>')
159					);
160					_self.objects.nav.append(
161						_self.objects.prev = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-prev"><span>' + _self.settings.labels['navigator.prev'] + '</span></a>').hide(),
162						_self.objects.next = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-next"><span>' + _self.settings.labels['navigator.next'] + '</span></a>').hide(),
163						_self.objects.play = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-play"><span>' + _self.settings.labels['navigator.play'] + '</span></a>').hide(),
164						_self.objects.pause = $('<a href="#" class="' + _self.settings.classPrefix + 'icon-pause"><span>' + _self.settings.labels['navigator.pause'] + '</span></a>').hide()
165					);
166				},
167				onInit: {},
168				onStart: {},
169				onBeforeCalculateDimensions: {},
170				onAfterCalculateDimensions: {},
171				onBeforeShow: {},
172				onFinish: {},
173				onResize: {},
174				onClose: {},
175				onCleanup: {}
176			},
177			options,
178			// Load options from data-lc-options attribute
179			_self.origin.data ? _self.origin.data('lc-options') : {});
180
181			_self.objects.document = $('html');
182			_self.objects.body = $('body');
183
184			// Call onInit hook functions
185			_self._callHooks(_self.settings.onInit);
186
187			_self.objectData = _self._setObjectData(this);
188
189			_self._addElements();
190			_self._open();
191
192			_self.dimensions = _self.getViewportDimensions();
193		},
194
195		/**
196		 * Getter method for objects
197		 *
198		 * @param	{string}	name
199		 * @return	{object}
200		 */
201		get: function (name) {
202			return _self.objects[name];
203		},
204
205		/**
206		 * Getter method for objectData
207		 *
208		 * @return	{object}
209		 */
210		getObjectData: function () {
211			return _self.objectData;
212		},
213
214		/**
215		 * Sets the object data
216		 *
217		 * @param	{object}	object
218		 * @return	{object}	objectData
219		 */
220		_setObjectData: function (object) {
221		 	var $object = $(object),
222				objectData = {
223				this: $(object),
224				title: _self.settings.title || $object.attr(_self._prefixAttributeName('title')) || $object.attr('title'),
225				caption: _self.settings.caption || $object.attr(_self._prefixAttributeName('caption')) || $object.children('img').attr('alt'),
226				url: _self._determineUrl(),
227				requestType: _self.settings.ajax.type,
228				requestData: _self.settings.ajax.data,
229				requestDataType: _self.settings.ajax.dataType,
230				rel: $object.attr(_self._determineAttributeSelector()),
231				type: _self.settings.type || _self._verifyDataType(_self._determineUrl()),
232				isPartOfSequence: _self.settings.useAsCollection || _self._isPartOfSequence($object.attr(_self.settings.attr), ':'),
233				isPartOfSequenceWithSlideshow: _self._isPartOfSequence($object.attr(_self.settings.attr), ':slideshow'),
234				currentIndex: $(_self._determineAttributeSelector()).index($object),
235				sequenceLength: $(_self._determineAttributeSelector()).length
236			};
237
238			// Add sequence info to objectData
239			objectData.sequenceInfo = (objectData.currentIndex + 1) + _self.settings.labels['sequenceInfo.of'] + objectData.sequenceLength;
240
241			// Add next/prev index
242			objectData.prevIndex = objectData.currentIndex - 1;
243			objectData.nextIndex = objectData.currentIndex + 1;
244
245			return objectData;
246		},
247
248		/**
249		 * Prefixes a data attribute name with defined name from 'settings.attrPrefix'
250		 * to ensure more uniqueness for all lightcase related/used attributes.
251		 *
252		 * @param	{string}	name
253		 * @return	{string}
254		 */
255		_prefixAttributeName: function (name) {
256			return 'data-' + _self.settings.attrPrefix + name;
257		},
258
259		/**
260		 * Determines the link target considering 'settings.href' and data attributes
261		 * but also with a fallback to the default 'href' value.
262		 *
263		 * @return	{string}
264		 */
265		_determineLinkTarget: function () {
266			return _self.settings.href || $(_self.origin).attr(_self._prefixAttributeName('href')) || $(_self.origin).attr('href');
267		},
268
269		/**
270		 * Determines the attribute selector to use, depending on
271		 * whether categorized collections are beeing used or not.
272		 *
273		 * @return	{string}	selector
274		 */
275		_determineAttributeSelector: function () {
276			var	$origin = $(_self.origin),
277				selector = '';
278
279			if (typeof _self.cache.selector !== 'undefined') {
280				selector = _self.cache.selector;
281			} else if (_self.settings.useCategories === true && $origin.attr(_self._prefixAttributeName('categories'))) {
282				var	categories = $origin.attr(_self._prefixAttributeName('categories')).split(' ');
283
284				$.each(categories, function (index, category) {
285					if (index > 0) {
286						selector += ',';
287					}
288					selector += '[' + _self._prefixAttributeName('categories') + '~="' + category + '"]';
289				});
290			} else {
291				selector = '[' + _self.settings.attr + '="' + $origin.attr(_self.settings.attr) + '"]';
292			}
293
294			_self.cache.selector = selector;
295
296			return selector;
297		},
298
299		/**
300		 * Determines the correct resource according to the
301		 * current viewport and density.
302		 *
303		 * @return	{string}	url
304		 */
305		_determineUrl: function () {
306			var	dataUrl = _self._verifyDataUrl(_self._determineLinkTarget()),
307				width = 0,
308				density = 0,
309				supportLevel = '',
310				url;
311
312			$.each(dataUrl, function (index, src) {
313				switch (_self._verifyDataType(src.url)) {
314					case 'video':
315						var	video = document.createElement('video'),
316							videoType = _self._verifyDataType(src.url) + '/' + _self._getFileUrlSuffix(src.url);
317
318						// Check if browser can play this type of video format
319						if (supportLevel !== 'probably' && supportLevel !== video.canPlayType(videoType) && video.canPlayType(videoType) !== '') {
320							supportLevel = video.canPlayType(videoType);
321							url = src.url;
322						}
323						break;
324					default:
325						if (
326							// Check density
327							_self._devicePixelRatio() >= src.density &&
328							src.density >= density &&
329							// Check viewport width
330							_self._matchMedia()('screen and (min-width:' + src.width + 'px)').matches &&
331							src.width >= width
332						) {
333							width = src.width;
334							density = src.density;
335							url = src.url;
336						}
337						break;
338				}
339			});
340
341			return url;
342		},
343
344		/**
345		 * Normalizes an url and returns information about the resource path,
346		 * the viewport width as well as density if defined.
347		 *
348		 * @param	{string}	url	Path to resource in format of an url or srcset
349		 * @return	{object}
350		 */
351		_normalizeUrl: function (url) {
352			var srcExp = /^\d+$/;
353
354			return url.split(',').map(function (str) {
355				var src = {
356					width: 0,
357					density: 0
358				};
359
360				str.trim().split(/\s+/).forEach(function (url, i) {
361					if (i === 0) {
362						return src.url = url;
363					}
364
365					var value = url.substring(0, url.length - 1),
366						lastChar = url[url.length - 1],
367						intVal = parseInt(value, 10),
368						floatVal = parseFloat(value);
369					if (lastChar === 'w' && srcExp.test(value)) {
370						src.width = intVal;
371					} else if (lastChar === 'h' && srcExp.test(value)) {
372						src.height = intVal;
373					} else if (lastChar === 'x' && !isNaN(floatVal)) {
374						src.density = floatVal;
375					}
376				});
377
378				return src;
379			});
380		},
381
382		/**
383		 * Verifies if the link is part of a sequence
384		 *
385		 * @param	{string}	rel
386		 * @param	{string}	expression
387		 * @return	{boolean}
388		 */
389		_isPartOfSequence: function (rel, expression) {
390			var getSimilarLinks = $('[' + _self.settings.attr + '="' + rel + '"]'),
391				regexp = new RegExp(expression);
392
393			return (regexp.test(rel) && getSimilarLinks.length > 1);
394		},
395
396		/**
397		 * Verifies if the slideshow should be enabled
398		 *
399		 * @return	{boolean}
400		 */
401		isSlideshowEnabled: function () {
402			return (_self.objectData.isPartOfSequence && (_self.settings.slideshow === true || _self.objectData.isPartOfSequenceWithSlideshow === true));
403		},
404
405		/**
406		 * Loads the new content to show
407		 *
408		 * @return	{void}
409		 */
410		_loadContent: function () {
411			if (_self.cache.originalObject) {
412				_self._restoreObject();
413			}
414
415			_self._createObject();
416		},
417
418		/**
419		 * Creates a new object
420		 *
421		 * @return	{void}
422		 */
423		_createObject: function () {
424			var $object;
425
426			// Create object
427			switch (_self.objectData.type) {
428				case 'image':
429					$object = $(new Image());
430					$object.attr({
431						// The time expression is required to prevent the binding of an image load
432						'src': _self.objectData.url,
433						'alt': _self.objectData.title
434					});
435					break;
436				case 'inline':
437					$object = $('<div class="' + _self.settings.classPrefix + 'inlineWrap"></div>');
438					$object.html(_self._cloneObject($(_self.objectData.url)));
439
440					// Add custom attributes from _self.settings
441					$.each(_self.settings.inline, function (name, value) {
442						$object.attr(_self._prefixAttributeName(name), value);
443					});
444					break;
445				case 'ajax':
446					$object = $('<div class="' + _self.settings.classPrefix + 'inlineWrap"></div>');
447
448					// Add custom attributes from _self.settings
449					$.each(_self.settings.ajax, function (name, value) {
450						if (name !== 'data') {
451							$object.attr(_self._prefixAttributeName(name), value);
452						}
453					});
454					break;
455				case 'flash':
456					$object = $('<embed src="' + _self.objectData.url + '" type="application/x-shockwave-flash"></embed>');
457
458					// Add custom attributes from _self.settings
459					$.each(_self.settings.flash, function (name, value) {
460						$object.attr(name, value);
461					});
462					break;
463				case 'video':
464					$object = $('<video></video>');
465					$object.attr('src', _self.objectData.url);
466
467					// Add custom attributes from _self.settings
468					$.each(_self.settings.video, function (name, value) {
469						$object.attr(name, value);
470					});
471					break;
472				default:
473					$object = $('<iframe></iframe>');
474					$object.attr({
475						'src': _self.objectData.url
476					});
477
478					// Add custom attributes from _self.settings
479					$.each(_self.settings.iframe, function (name, value) {
480						$object.attr(name, value);
481					});
482					break;
483			}
484
485			_self._addObject($object);
486			_self._loadObject($object);
487		},
488
489		/**
490		 * Adds the new object to the markup
491		 *
492		 * @param	{object}	$object
493		 * @return	{void}
494		 */
495		_addObject: function ($object) {
496			// Add object to content holder
497			_self.objects.contentInner.html($object);
498
499			// Start loading
500			_self._loading('start');
501
502			// Call onStart hook functions
503			_self._callHooks(_self.settings.onStart);
504
505			// Add sequenceInfo to the content holder or hide if its empty
506			if (_self.settings.showSequenceInfo === true && _self.objectData.isPartOfSequence) {
507				_self.objects.sequenceInfo.html(_self.objectData.sequenceInfo);
508				_self.objects.sequenceInfo.show();
509			} else {
510				_self.objects.sequenceInfo.empty();
511				_self.objects.sequenceInfo.hide();
512			}
513			// Add title to the content holder or hide if its empty
514			if (_self.settings.showTitle === true && _self.objectData.title !== undefined && _self.objectData.title !== '') {
515				_self.objects.title.html(_self.objectData.title);
516				_self.objects.title.show();
517			} else {
518				_self.objects.title.empty();
519				_self.objects.title.hide();
520			}
521			// Add caption to the content holder or hide if its empty
522			if (_self.settings.showCaption === true && _self.objectData.caption !== undefined && _self.objectData.caption !== '') {
523				_self.objects.caption.html(_self.objectData.caption);
524				_self.objects.caption.show();
525			} else {
526				_self.objects.caption.empty();
527				_self.objects.caption.hide();
528			}
529		},
530
531		/**
532		 * Loads the new object
533		 *
534		 * @param	{object}	$object
535		 * @return	{void}
536		 */
537		_loadObject: function ($object) {
538			// Load the object
539			switch (_self.objectData.type) {
540				case 'inline':
541					if ($(_self.objectData.url)) {
542						_self._showContent($object);
543					} else {
544						_self.error();
545					}
546					break;
547				case 'ajax':
548					$.ajax(
549						$.extend({}, _self.settings.ajax, {
550							url: _self.objectData.url,
551							type: _self.objectData.requestType,
552							dataType: _self.objectData.requestDataType,
553							data: _self.objectData.requestData,
554							success: function (data, textStatus, jqXHR) {
555								// Check for X-Ajax-Location
556								if (jqXHR.getResponseHeader('X-Ajax-Location')) {
557									_self.objectData.url = jqXHR.getResponseHeader('X-Ajax-Location');
558									_self._loadObject($object);
559								}
560								else {
561									// Unserialize if data is transferred as json
562									if (_self.objectData.requestDataType === 'json') {
563										_self.objectData.data = data;
564									} else {
565										$object.html(data);
566									}
567									_self._showContent($object);
568								}
569							},
570							error: function (jqXHR, textStatus, errorThrown) {
571								_self.error();
572							}
573						})
574					);
575					break;
576				case 'flash':
577					_self._showContent($object);
578					break;
579				case 'video':
580					if (typeof($object.get(0).canPlayType) === 'function' || _self.objects.case.find('video').length === 0) {
581						_self._showContent($object);
582					} else {
583						_self.error();
584					}
585					break;
586				default:
587					if (_self.objectData.url) {
588						$object.on('load', function () {
589							_self._showContent($object);
590						});
591						$object.on('error', function () {
592							_self.error();
593						});
594					} else {
595						_self.error();
596					}
597					break;
598			}
599		},
600
601		/**
602		 * Throws an error message if something went wrong
603		 *
604		 * @return	{void}
605		 */
606		error: function () {
607			_self.objectData.type = 'error';
608			var $object = $('<div class="' + _self.settings.classPrefix + 'inlineWrap"></div>');
609
610			$object.html(_self.settings.errorMessage);
611			_self.objects.contentInner.html($object);
612
613			_self._showContent(_self.objects.contentInner);
614		},
615
616		/**
617		 * Calculates the dimensions to fit content
618		 *
619		 * @param	{object}	$object
620		 * @return	{void}
621		 */
622		_calculateDimensions: function ($object) {
623			_self._cleanupDimensions();
624
625			if (!$object) return;
626
627			// Set default dimensions
628			var dimensions = {
629				ratio: 1,
630				objectWidth: $object.attr('width') ? $object.attr('width') : $object.attr(_self._prefixAttributeName('width')),
631				objectHeight: $object.attr('height') ? $object.attr('height') : $object.attr(_self._prefixAttributeName('height'))
632			};
633
634			if (!_self.settings.disableShrink) {
635				// Add calculated maximum width/height to dimensions
636				dimensions.maxWidth = parseInt(_self.dimensions.windowWidth * _self.settings.shrinkFactor);
637				dimensions.maxHeight = parseInt(_self.dimensions.windowHeight * _self.settings.shrinkFactor);
638
639				// If the auto calculated maxWidth/maxHeight greather than the user-defined one, use that.
640				if (dimensions.maxWidth > _self.settings.maxWidth) {
641					dimensions.maxWidth = _self.settings.maxWidth;
642				}
643				if (dimensions.maxHeight > _self.settings.maxHeight) {
644					dimensions.maxHeight = _self.settings.maxHeight;
645				}
646
647				// Calculate the difference between screen width/height and image width/height
648				dimensions.differenceWidthAsPercent = parseInt(100 / dimensions.maxWidth * dimensions.objectWidth);
649				dimensions.differenceHeightAsPercent = parseInt(100 / dimensions.maxHeight * dimensions.objectHeight);
650
651				switch (_self.objectData.type) {
652					case 'image':
653					case 'flash':
654					case 'video':
655					case 'iframe':
656					case 'ajax':
657					case 'inline':
658						if (_self.objectData.type === 'image' || _self.settings.fixedRatio === true) {
659							if (dimensions.differenceWidthAsPercent > 100 && dimensions.differenceWidthAsPercent > dimensions.differenceHeightAsPercent) {
660								dimensions.objectWidth = dimensions.maxWidth;
661								dimensions.objectHeight = parseInt(dimensions.objectHeight / dimensions.differenceWidthAsPercent * 100);
662							}
663							if (dimensions.differenceHeightAsPercent > 100 && dimensions.differenceHeightAsPercent > dimensions.differenceWidthAsPercent) {
664								dimensions.objectWidth = parseInt(dimensions.objectWidth / dimensions.differenceHeightAsPercent * 100);
665								dimensions.objectHeight = dimensions.maxHeight;
666							}
667							if (dimensions.differenceHeightAsPercent > 100 && dimensions.differenceWidthAsPercent < dimensions.differenceHeightAsPercent) {
668								dimensions.objectWidth = parseInt(dimensions.maxWidth / dimensions.differenceHeightAsPercent * dimensions.differenceWidthAsPercent);
669								dimensions.objectHeight = dimensions.maxHeight;
670							}
671							break;
672						}
673					case 'error':
674						if (!isNaN(dimensions.objectWidth) && dimensions.objectWidth > dimensions.maxWidth) {
675							dimensions.objectWidth = dimensions.maxWidth;
676						}
677						break;
678					default:
679						if ((isNaN(dimensions.objectWidth) || dimensions.objectWidth > dimensions.maxWidth) && !_self.settings.forceWidth) {
680							dimensions.objectWidth = dimensions.maxWidth;
681						}
682						if (((isNaN(dimensions.objectHeight) && dimensions.objectHeight !== 'auto') || dimensions.objectHeight > dimensions.maxHeight) && !_self.settings.forceHeight) {
683							dimensions.objectHeight = dimensions.maxHeight;
684						}
685						break;
686				}
687			}
688
689			if (_self.settings.forceWidth) {
690				try {
691					dimensions.objectWidth = _self.settings[_self.objectData.type].width;
692				} catch (e) {
693					dimensions.objectWidth = _self.settings.width || dimensions.objectWidth;
694				}
695
696				dimensions.maxWidth = null;
697			}
698			if ($object.attr(_self._prefixAttributeName('max-width'))) {
699				dimensions.maxWidth = $object.attr(_self._prefixAttributeName('max-width'));
700			}
701
702			if (_self.settings.forceHeight) {
703				try {
704					dimensions.objectHeight = _self.settings[_self.objectData.type].height;
705				} catch (e) {
706					dimensions.objectHeight = _self.settings.height || dimensions.objectHeight;
707				}
708
709				dimensions.maxHeight = null;
710			}
711			if ($object.attr(_self._prefixAttributeName('max-height'))) {
712				dimensions.maxHeight = $object.attr(_self._prefixAttributeName('max-height'));
713			}
714			_self._adjustDimensions($object, dimensions);
715		},
716
717		/**
718		 * Adjusts the dimensions
719		 *
720		 * @param	{object}	$object
721		 * @param	{object}	dimensions
722		 * @return	{void}
723		 */
724		_adjustDimensions: function ($object, dimensions) {
725			// Adjust width and height
726			$object.css({
727				'width': dimensions.objectWidth,
728				'height': dimensions.objectHeight,
729				'max-width': dimensions.maxWidth,
730				'max-height': dimensions.maxHeight
731			});
732
733			_self.objects.contentInner.css({
734				'width': $object.outerWidth(),
735				'height': $object.outerHeight(),
736				'max-width': '100%'
737			});
738
739			_self.objects.case.css({
740				'width': _self.objects.contentInner.outerWidth(),
741				'max-width': '100%'
742			});
743
744			// Adjust margin
745			_self.objects.case.css({
746				'margin-top': parseInt(-(_self.objects.case.outerHeight() / 2)),
747				'margin-left': parseInt(-(_self.objects.case.outerWidth() / 2))
748			});
749		},
750
751		/**
752		 * Handles the _loading
753		 *
754		 * @param	{string}	process
755		 * @return	{void}
756		 */
757		_loading: function (process) {
758			if (process === 'start') {
759				_self.objects.case.addClass(_self.settings.classPrefix + 'loading');
760				_self.objects.loading.show();
761			} else if (process === 'end') {
762				_self.objects.case.removeClass(_self.settings.classPrefix + 'loading');
763				_self.objects.loading.hide();
764			}
765		},
766
767
768		/**
769		 * Gets the client screen dimensions
770		 *
771		 * @return	{object}	dimensions
772		 */
773		getViewportDimensions: function () {
774			return {
775				windowWidth: $(window).innerWidth(),
776				windowHeight: $(window).innerHeight()
777			};
778		},
779
780		/**
781		 * Verifies the url
782		 *
783		 * @param	{string}	dataUrl
784		 * @return	{object}	dataUrl	Clean url for processing content
785		 */
786		_verifyDataUrl: function (dataUrl) {
787			if (!dataUrl || dataUrl === undefined || dataUrl === '') {
788				return false;
789			}
790
791			if (dataUrl.indexOf('#') > -1) {
792				dataUrl = dataUrl.split('#');
793				dataUrl = '#' + dataUrl[dataUrl.length - 1];
794			}
795
796			return _self._normalizeUrl(dataUrl.toString());
797		},
798
799			//
800		/**
801		 * Tries to get the (file) suffix of an url
802		 *
803		 * @param	{string}	url
804		 * @return	{string}
805		 */
806		_getFileUrlSuffix: function (url) {
807			var re = /(?:\.([^.]+))?$/;
808			return re.exec(url.toLowerCase())[1];
809		},
810
811		/**
812		 * Verifies the data type of the content to load
813		 *
814		 * @param	{string}			url
815		 * @return	{string|boolean}	Array key if expression matched, else false
816		 */
817		_verifyDataType: function (url) {
818			var typeMapping = _self.settings.typeMapping;
819
820			// Early abort if dataUrl couldn't be verified
821			if (!url) {
822				return false;
823			}
824
825			// Verify the dataType of url according to typeMapping which
826			// has been defined in settings.
827			for (var key in typeMapping) {
828				if (typeMapping.hasOwnProperty(key)) {
829					var suffixArr = typeMapping[key].split(',');
830
831					for (var i = 0; i < suffixArr.length; i++) {
832						var suffix = suffixArr[i].toLowerCase(),
833							regexp = new RegExp('\.(' + suffix + ')$', 'i'),
834							str = url.toLowerCase().split('?')[0].substr(-5);
835
836						if (regexp.test(str) === true || (key === 'inline' && (url.indexOf(suffix) > -1))) {
837							return key;
838						}
839					}
840				}
841			}
842
843			// If no expression matched, return 'iframe'.
844			return 'iframe';
845		},
846
847		/**
848		 * Extends html markup with the essential tags
849		 *
850		 * @return	{void}
851		 */
852		_addElements: function () {
853			if (typeof _self.objects.case !== 'undefined' && $('#' + _self.objects.case.attr('id')).length) {
854				return;
855			}
856
857			_self.settings.markup();
858		},
859
860		/**
861		 * Shows the loaded content
862		 *
863		 * @param	{object}	$object
864		 * @return	{void}
865		 */
866		_showContent: function ($object) {
867			// Add data attribute with the object type
868			_self.objects.document.attr(_self._prefixAttributeName('type'), _self.objectData.type);
869
870			_self.cache.object = $object;
871
872			// Call onBeforeShow hook functions
873			_self._callHooks(_self.settings.onBeforeShow);
874
875			if (_self.settings.breakBeforeShow) return;
876			_self.show();
877		},
878
879		/**
880		 * Starts the 'inTransition'
881		 * @return	{void}
882		 */
883		_startInTransition: function () {
884			switch (_self.transition.in()) {
885				case 'scrollTop':
886				case 'scrollRight':
887				case 'scrollBottom':
888				case 'scrollLeft':
889				case 'scrollHorizontal':
890				case 'scrollVertical':
891					_self.transition.scroll(_self.objects.case, 'in', _self.settings.speedIn);
892					_self.transition.fade(_self.objects.contentInner, 'in', _self.settings.speedIn);
893					break;
894				case 'elastic':
895					if (_self.objects.case.css('opacity') < 1) {
896						_self.transition.zoom(_self.objects.case, 'in', _self.settings.speedIn);
897						_self.transition.fade(_self.objects.contentInner, 'in', _self.settings.speedIn);
898				}
899				case 'fade':
900				case 'fadeInline':
901					_self.transition.fade(_self.objects.case, 'in', _self.settings.speedIn);
902					_self.transition.fade(_self.objects.contentInner, 'in', _self.settings.speedIn);
903					break;
904				default:
905					_self.transition.fade(_self.objects.case, 'in', 0);
906					break;
907			}
908
909			// End loading.
910			_self._loading('end');
911			_self.isBusy = false;
912
913			// Set index of the first item opened
914			if (!_self.cache.firstOpened) {
915				_self.cache.firstOpened = _self.objectData.this;
916			}
917
918			// Fade in the info with delay
919			_self.objects.info.hide();
920			setTimeout(function () {
921				 _self.transition.fade(_self.objects.info, 'in', _self.settings.speedIn);
922			}, _self.settings.speedIn);
923
924			// Call onFinish hook functions
925			_self._callHooks(_self.settings.onFinish);
926		},
927
928		/**
929		 * Processes the content to show
930		 *
931		 * @return	{void}
932		 */
933		_processContent: function () {
934			_self.isBusy = true;
935
936			// Fade out the info at first
937			_self.transition.fade(_self.objects.info, 'out', 0);
938
939			switch (_self.settings.transitionOut) {
940				case 'scrollTop':
941				case 'scrollRight':
942				case 'scrollBottom':
943				case 'scrollLeft':
944				case 'scrollVertical':
945				case 'scrollHorizontal':
946					if (_self.objects.case.is(':hidden')) {
947						_self.transition.fade(_self.objects.contentInner, 'out', 0);
948						_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
949							_self._loadContent();
950						});
951					} else {
952						_self.transition.scroll(_self.objects.case, 'out', _self.settings.speedOut, function () {
953							_self._loadContent();
954						});
955					}
956					break;
957				case 'fade':
958					if (_self.objects.case.is(':hidden')) {
959						_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
960							_self._loadContent();
961						});
962					} else {
963						_self.transition.fade(_self.objects.case, 'out', _self.settings.speedOut, 0, function () {
964							_self._loadContent();
965						});
966					}
967					break;
968				case 'fadeInline':
969				case 'elastic':
970					if (_self.objects.case.is(':hidden')) {
971						_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
972							_self._loadContent();
973						});
974					} else {
975						_self.transition.fade(_self.objects.contentInner, 'out', _self.settings.speedOut, 0, function () {
976							_self._loadContent();
977						});
978					}
979					break;
980				default:
981					_self.transition.fade(_self.objects.case, 'out', 0, 0, function () {
982						_self._loadContent();
983					});
984					break;
985			}
986		},
987
988		/**
989		 * Handles events for gallery buttons
990		 *
991		 * @return	{void}
992		 */
993		_handleEvents: function () {
994			_self._unbindEvents();
995
996			_self.objects.nav.children().not(_self.objects.close).hide();
997
998			// If slideshow is enabled, show play/pause and start timeout.
999			if (_self.isSlideshowEnabled()) {
1000				// Only start the timeout if slideshow autostart is enabled and slideshow is not pausing
1001				if (
1002					(_self.settings.slideshowAutoStart === true || _self.isSlideshowStarted) &&
1003					!_self.objects.nav.hasClass(_self.settings.classPrefix + 'paused')
1004				) {
1005					_self._startTimeout();
1006				} else {
1007					_self._stopTimeout();
1008				}
1009			}
1010
1011			if (_self.settings.liveResize) {
1012				_self._watchResizeInteraction();
1013			}
1014
1015			_self.objects.close.click(function (event) {
1016				event.preventDefault();
1017				_self.close();
1018			});
1019
1020			if (_self.settings.closeOnOverlayClick === true) {
1021				_self.objects.overlay.css('cursor', 'pointer').click(function (event) {
1022					event.preventDefault();
1023
1024					_self.close();
1025				});
1026			}
1027
1028			if (_self.settings.useKeys === true) {
1029				_self._addKeyEvents();
1030			}
1031
1032			if (_self.objectData.isPartOfSequence) {
1033				_self.objects.nav.attr(_self._prefixAttributeName('ispartofsequence'), true);
1034				_self.objects.nav.data('items', _self._setNavigation());
1035
1036				_self.objects.prev.click(function (event) {
1037					event.preventDefault();
1038
1039					if (_self.settings.navigateEndless === true || !_self.item.isFirst()) {
1040						_self.objects.prev.unbind('click');
1041						_self.cache.action = 'prev';
1042						_self.objects.nav.data('items').prev.click();
1043
1044						if (_self.isSlideshowEnabled()) {
1045							_self._stopTimeout();
1046						}
1047					}
1048				});
1049
1050				_self.objects.next.click(function (event) {
1051					event.preventDefault();
1052
1053					if (_self.settings.navigateEndless === true || !_self.item.isLast()) {
1054						_self.objects.next.unbind('click');
1055						_self.cache.action = 'next';
1056						_self.objects.nav.data('items').next.click();
1057
1058						if (_self.isSlideshowEnabled()) {
1059							_self._stopTimeout();
1060						}
1061					}
1062				});
1063
1064				if (_self.isSlideshowEnabled()) {
1065					_self.objects.play.click(function (event) {
1066						event.preventDefault();
1067						_self._startTimeout();
1068					});
1069					_self.objects.pause.click(function (event) {
1070						event.preventDefault();
1071						_self._stopTimeout();
1072					});
1073				}
1074
1075				// Enable swiping if activated
1076				if (_self.settings.swipe === true) {
1077					if ($.isPlainObject($.event.special.swipeleft)) {
1078						_self.objects.case.on('swipeleft', function (event) {
1079							event.preventDefault();
1080							_self.objects.next.click();
1081							if (_self.isSlideshowEnabled()) {
1082								_self._stopTimeout();
1083							}
1084						});
1085					}
1086					if ($.isPlainObject($.event.special.swiperight)) {
1087						_self.objects.case.on('swiperight', function (event) {
1088							event.preventDefault();
1089							_self.objects.prev.click();
1090							if (_self.isSlideshowEnabled()) {
1091								_self._stopTimeout();
1092							}
1093						});
1094					}
1095				}
1096			}
1097		},
1098
1099		/**
1100		 * Adds the key events
1101		 *
1102		 * @return	{void}
1103		 */
1104		_addKeyEvents: function () {
1105			$(document).bind('keyup.lightcase', function (event) {
1106				// Do nothing if lightcase is in process
1107				if (_self.isBusy) {
1108					return;
1109				}
1110
1111				switch (event.keyCode) {
1112					// Escape key
1113					case 27:
1114						_self.objects.close.click();
1115						break;
1116					// Backward key
1117					case 37:
1118						if (_self.objectData.isPartOfSequence) {
1119							_self.objects.prev.click();
1120						}
1121						break;
1122					// Forward key
1123					case 39:
1124						if (_self.objectData.isPartOfSequence) {
1125							_self.objects.next.click();
1126						}
1127						break;
1128				}
1129			});
1130		},
1131
1132		/**
1133		 * Starts the slideshow timeout
1134		 *
1135		 * @return	{void}
1136		 */
1137		_startTimeout: function () {
1138			_self.isSlideshowStarted = true;
1139
1140			_self.objects.play.hide();
1141			_self.objects.pause.show();
1142
1143			_self.cache.action = 'next';
1144			_self.objects.nav.removeClass(_self.settings.classPrefix + 'paused');
1145
1146			_self.timeout = setTimeout(function () {
1147				_self.objects.nav.data('items').next.click();
1148			}, _self.settings.timeout);
1149		},
1150
1151		/**
1152		 * Stops the slideshow timeout
1153		 *
1154		 * @return	{void}
1155		 */
1156		_stopTimeout: function () {
1157			_self.objects.play.show();
1158			_self.objects.pause.hide();
1159
1160			_self.objects.nav.addClass(_self.settings.classPrefix + 'paused');
1161
1162			clearTimeout(_self.timeout);
1163		},
1164
1165		/**
1166		 * Sets the navigator buttons (prev/next)
1167		 *
1168		 * @return	{object}	items
1169		 */
1170		_setNavigation: function () {
1171			var $links = $((_self.cache.selector || _self.settings.attr)),
1172				sequenceLength = _self.objectData.sequenceLength - 1,
1173				items = {
1174					prev: $links.eq(_self.objectData.prevIndex),
1175					next: $links.eq(_self.objectData.nextIndex)
1176				};
1177
1178			if (_self.objectData.currentIndex > 0) {
1179				_self.objects.prev.show();
1180			} else {
1181				items.prevItem = $links.eq(sequenceLength);
1182			}
1183			if (_self.objectData.nextIndex <= sequenceLength) {
1184				_self.objects.next.show();
1185			} else {
1186				items.next = $links.eq(0);
1187			}
1188
1189			if (_self.settings.navigateEndless === true) {
1190				_self.objects.prev.show();
1191				_self.objects.next.show();
1192			}
1193
1194			return items;
1195		},
1196
1197		/**
1198		 * Item information/status
1199		 *
1200		 */
1201		item: {
1202			/**
1203			 * Verifies if the current item is first item.
1204			 *
1205			 * @return	{boolean}
1206			 */
1207			isFirst: function () {
1208				return (_self.objectData.currentIndex === 0);
1209			},
1210
1211			/**
1212			 * Verifies if the current item is first item opened.
1213			 *
1214			 * @return	{boolean}
1215			 */
1216			isFirstOpened: function () {
1217				return _self.objectData.this.is(_self.cache.firstOpened);
1218			},
1219
1220			/**
1221			 * Verifies if the current item is last item.
1222			 *
1223			 * @return	{boolean}
1224			 */
1225			isLast: function () {
1226				return (_self.objectData.currentIndex === (_self.objectData.sequenceLength - 1));
1227			}
1228		},
1229
1230		/**
1231		 * Clones the object for inline elements
1232		 *
1233		 * @param	{object}	$object
1234		 * @return	{object}	$clone
1235		 */
1236		_cloneObject: function ($object) {
1237			var $clone = $object.clone(),
1238				objectId = $object.attr('id');
1239
1240			// If element is hidden, cache the object and remove
1241			if ($object.is(':hidden')) {
1242				_self._cacheObjectData($object);
1243				$object.attr('id', _self.settings.idPrefix + 'temp-' + objectId).empty();
1244			} else {
1245				// Prevent duplicated id's
1246				$clone.removeAttr('id');
1247			}
1248
1249			return $clone.show();
1250		},
1251
1252		/**
1253		 * Verifies if it is a mobile device
1254		 *
1255		 * @return	{boolean}
1256		 */
1257		isMobileDevice: function () {
1258			var deviceAgent = navigator.userAgent.toLowerCase(),
1259				agentId = deviceAgent.match(_self.settings.mobileMatchExpression);
1260
1261			return agentId ? true : false;
1262		},
1263
1264		/**
1265		 * Verifies if css transitions are supported
1266		 *
1267		 * @return	{string|boolean}	The transition prefix if supported, else false.
1268		 */
1269		isTransitionSupported: function () {
1270			var body = _self.objects.body.get(0),
1271				isTransitionSupported = false,
1272				transitionMapping = {
1273					'transition': '',
1274					'WebkitTransition': '-webkit-',
1275					'MozTransition': '-moz-',
1276					'OTransition': '-o-',
1277					'MsTransition': '-ms-'
1278				};
1279
1280			for (var key in transitionMapping) {
1281				if (transitionMapping.hasOwnProperty(key) && key in body.style) {
1282					_self.support.transition = transitionMapping[key];
1283					isTransitionSupported = true;
1284				}
1285			}
1286
1287			return isTransitionSupported;
1288		},
1289
1290		/**
1291		 * Transition types
1292		 *
1293		 */
1294		transition: {
1295			/**
1296			 * Returns the correct transition type according to the status of interaction.
1297			 *
1298			 * @return	{string}	Transition type
1299			 */
1300			in: function () {
1301				if (_self.settings.transitionOpen && !_self.cache.firstOpened) {
1302					return _self.settings.transitionOpen;
1303				}
1304				return _self.settings.transitionIn;
1305			},
1306
1307			/**
1308			 * Fades in/out the object
1309			 *
1310			 * @param	{object}	$object
1311			 * @param	{string}	type
1312			 * @param	{number}	speed
1313			 * @param	{number}	opacity
1314			 * @param	{function}	callback
1315			 * @return	{void}		Animates an object
1316			 */
1317			fade: function ($object, type, speed, opacity, callback) {
1318				var isInTransition = type === 'in',
1319					startTransition = {},
1320					startOpacity = $object.css('opacity'),
1321					endTransition = {},
1322					endOpacity = opacity ? opacity: isInTransition ? 1 : 0;
1323
1324				if (!_self.isOpen && isInTransition) return;
1325
1326				startTransition['opacity'] = startOpacity;
1327				endTransition['opacity'] = endOpacity;
1328
1329				$object.css(_self.support.transition + 'transition', 'none');
1330				$object.css(startTransition).show();
1331
1332				// Css transition
1333				if (_self.support.transitions) {
1334					endTransition[_self.support.transition + 'transition'] = speed + 'ms ease';
1335
1336					setTimeout(function () {
1337						$object.css(endTransition);
1338
1339						setTimeout(function () {
1340							$object.css(_self.support.transition + 'transition', '');
1341
1342							if (callback && (_self.isOpen || !isInTransition)) {
1343								callback();
1344							}
1345						}, speed);
1346					}, 15);
1347				} else {
1348					// Fallback to js transition
1349					$object.stop();
1350					$object.animate(endTransition, speed, callback);
1351				}
1352			},
1353
1354			/**
1355			 * Scrolls in/out the object
1356			 *
1357			 * @param	{object}	$object
1358			 * @param	{string}	type
1359			 * @param	{number}	speed
1360			 * @param	{function}	callback
1361			 * @return	{void}		Animates an object
1362			 */
1363			scroll: function ($object, type, speed, callback) {
1364				var isInTransition = type === 'in',
1365					transition = isInTransition ? _self.settings.transitionIn : _self.settings.transitionOut,
1366					direction = 'left',
1367					startTransition = {},
1368					startOpacity = isInTransition ? 0 : 1,
1369					startOffset = isInTransition ? '-50%' : '50%',
1370					endTransition = {},
1371					endOpacity = isInTransition ? 1 : 0,
1372					endOffset = isInTransition ? '50%' : '-50%';
1373
1374				if (!_self.isOpen && isInTransition) return;
1375
1376				switch (transition) {
1377					case 'scrollTop':
1378						direction = 'top';
1379						break;
1380					case 'scrollRight':
1381						startOffset = isInTransition ? '150%' : '50%';
1382						endOffset = isInTransition ? '50%' : '150%';
1383						break;
1384					case 'scrollBottom':
1385						direction = 'top';
1386						startOffset = isInTransition ? '150%' : '50%';
1387						endOffset = isInTransition ? '50%' : '150%';
1388						break;
1389					case 'scrollHorizontal':
1390						startOffset = isInTransition ? '150%' : '50%';
1391						endOffset = isInTransition ? '50%' : '-50%';
1392						break;
1393					case 'scrollVertical':
1394						direction = 'top';
1395						startOffset = isInTransition ? '-50%' : '50%';
1396						endOffset = isInTransition ? '50%' : '150%';
1397						break;
1398				}
1399
1400				if (_self.cache.action === 'prev') {
1401					switch (transition) {
1402						case 'scrollHorizontal':
1403							startOffset = isInTransition ? '-50%' : '50%';
1404							endOffset = isInTransition ? '50%' : '150%';
1405							break;
1406						case 'scrollVertical':
1407							startOffset = isInTransition ? '150%' : '50%';
1408							endOffset = isInTransition ? '50%' : '-50%';
1409							break;
1410					}
1411				}
1412
1413				startTransition['opacity'] = startOpacity;
1414				startTransition[direction] = startOffset;
1415
1416				endTransition['opacity'] = endOpacity;
1417				endTransition[direction] = endOffset;
1418
1419				$object.css(_self.support.transition + 'transition', 'none');
1420				$object.css(startTransition).show();
1421
1422				// Css transition
1423				if (_self.support.transitions) {
1424					endTransition[_self.support.transition + 'transition'] = speed + 'ms ease';
1425
1426					setTimeout(function () {
1427						$object.css(endTransition);
1428
1429						setTimeout(function () {
1430							$object.css(_self.support.transition + 'transition', '');
1431
1432							if (callback && (_self.isOpen || !isInTransition)) {
1433								callback();
1434							}
1435						}, speed);
1436					}, 15);
1437				} else {
1438					// Fallback to js transition
1439					$object.stop();
1440					$object.animate(endTransition, speed, callback);
1441				}
1442			},
1443
1444			/**
1445			 * Zooms in/out the object
1446			 *
1447			 * @param	{object}	$object
1448			 * @param	{string}	type
1449			 * @param	{number}	speed
1450			 * @param	{function}	callback
1451			 * @return	{void}		Animates an object
1452			 */
1453			zoom: function ($object, type, speed, callback) {
1454				var isInTransition = type === 'in',
1455					startTransition = {},
1456					startOpacity = $object.css('opacity'),
1457					startScale = isInTransition ? 'scale(0.75)' : 'scale(1)',
1458					endTransition = {},
1459					endOpacity = isInTransition ? 1 : 0,
1460					endScale = isInTransition ? 'scale(1)' : 'scale(0.75)';
1461
1462				if (!_self.isOpen && isInTransition) return;
1463
1464				startTransition['opacity'] = startOpacity;
1465				startTransition[_self.support.transition + 'transform'] = startScale;
1466
1467				endTransition['opacity'] = endOpacity;
1468
1469				$object.css(_self.support.transition + 'transition', 'none');
1470				$object.css(startTransition).show();
1471
1472				// Css transition
1473				if (_self.support.transitions) {
1474					endTransition[_self.support.transition + 'transform'] = endScale;
1475					endTransition[_self.support.transition + 'transition'] = speed + 'ms ease';
1476
1477					setTimeout(function () {
1478						$object.css(endTransition);
1479
1480						setTimeout(function () {
1481							$object.css(_self.support.transition + 'transform', '');
1482							$object.css(_self.support.transition + 'transition', '');
1483
1484							if (callback && (_self.isOpen || !isInTransition)) {
1485								callback();
1486							}
1487						}, speed);
1488					}, 15);
1489				} else {
1490					// Fallback to js transition
1491					$object.stop();
1492					$object.animate(endTransition, speed, callback);
1493				}
1494			}
1495		},
1496
1497		/**
1498		 * Calls all the registered functions of a specific hook
1499		 *
1500		 * @param	{object}	hooks
1501		 * @return	{void}
1502		 */
1503		_callHooks: function (hooks) {
1504			if (typeof(hooks) === 'object') {
1505				$.each(hooks, function(index, hook) {
1506					if (typeof(hook) === 'function') {
1507						hook.call(_self.origin);
1508					}
1509				});
1510			}
1511		},
1512
1513		/**
1514		 * Caches the object data
1515		 *
1516		 * @param	{object}	$object
1517		 * @return	{void}
1518		 */
1519		_cacheObjectData: function ($object) {
1520			$.data($object, 'cache', {
1521				id: $object.attr('id'),
1522				content: $object.html()
1523			});
1524
1525			_self.cache.originalObject = $object;
1526		},
1527
1528		/**
1529		 * Restores the object from cache
1530		 *
1531		 * @return	void
1532		 */
1533		_restoreObject: function () {
1534			var $object = $('[id^="' + _self.settings.idPrefix + 'temp-"]');
1535
1536			$object.attr('id', $.data(_self.cache.originalObject, 'cache').id);
1537			$object.html($.data(_self.cache.originalObject, 'cache').content);
1538		},
1539
1540		/**
1541		 * Executes functions for a window resize.
1542		 * It stops an eventual timeout and recalculates dimensions.
1543		 *
1544		 * @param	{object}	dimensions
1545		 * @return	{void}
1546		 */
1547		resize: function (event, dimensions) {
1548			if (!_self.isOpen) return;
1549
1550			if (_self.isSlideshowEnabled()) {
1551				_self._stopTimeout();
1552			}
1553
1554			if (typeof dimensions === 'object' && dimensions !== null) {
1555				if (dimensions.width) {
1556					_self.cache.object.attr(
1557						_self._prefixAttributeName('width'),
1558						dimensions.width
1559					);
1560				}
1561				if (dimensions.maxWidth) {
1562					_self.cache.object.attr(
1563						_self._prefixAttributeName('max-width'),
1564						dimensions.maxWidth
1565					);
1566				}
1567				if (dimensions.height) {
1568					_self.cache.object.attr(
1569						_self._prefixAttributeName('height'),
1570						dimensions.height
1571					);
1572				}
1573				if (dimensions.maxHeight) {
1574					_self.cache.object.attr(
1575						_self._prefixAttributeName('max-height'),
1576						dimensions.maxHeight
1577					);
1578				}
1579			}
1580
1581			_self.dimensions = _self.getViewportDimensions();
1582			_self._calculateDimensions(_self.cache.object);
1583
1584			// Call onResize hook functions
1585			_self._callHooks(_self.settings.onResize);
1586		},
1587
1588		/**
1589		 * Watches for any resize interaction and caches the new sizes.
1590		 *
1591		 * @return	{void}
1592		 */
1593		_watchResizeInteraction: function () {
1594			$(window).resize(_self.resize);
1595		},
1596
1597		/**
1598		 * Stop watching any resize interaction related to _self.
1599		 *
1600		 * @return	{void}
1601		 */
1602		_unwatchResizeInteraction: function () {
1603			$(window).off('resize', _self.resize);
1604		},
1605
1606		/**
1607		 * Switches to the fullscreen mode
1608		 *
1609		 * @return	{void}
1610		 */
1611		_switchToFullScreenMode: function () {
1612			_self.settings.shrinkFactor = 1;
1613			_self.settings.overlayOpacity = 1;
1614
1615			$('html').addClass(_self.settings.classPrefix + 'fullScreenMode');
1616		},
1617
1618		/**
1619		 * Enters into the lightcase view
1620		 *
1621		 * @return	{void}
1622		 */
1623		_open: function () {
1624			_self.isOpen = true;
1625
1626			_self.support.transitions = _self.settings.cssTransitions ? _self.isTransitionSupported() : false;
1627			_self.support.mobileDevice = _self.isMobileDevice();
1628
1629			if (_self.support.mobileDevice) {
1630				$('html').addClass(_self.settings.classPrefix + 'isMobileDevice');
1631
1632				if (_self.settings.fullScreenModeForMobile) {
1633					_self._switchToFullScreenMode();
1634				}
1635			}
1636
1637			if (!_self.settings.transitionIn) {
1638				_self.settings.transitionIn = _self.settings.transition;
1639			}
1640			if (!_self.settings.transitionOut) {
1641				_self.settings.transitionOut = _self.settings.transition;
1642			}
1643
1644			switch (_self.transition.in()) {
1645				case 'fade':
1646				case 'fadeInline':
1647				case 'elastic':
1648				case 'scrollTop':
1649				case 'scrollRight':
1650				case 'scrollBottom':
1651				case 'scrollLeft':
1652				case 'scrollVertical':
1653				case 'scrollHorizontal':
1654					if (_self.objects.case.is(':hidden')) {
1655						_self.objects.close.css('opacity', 0);
1656						_self.objects.overlay.css('opacity', 0);
1657						_self.objects.case.css('opacity', 0);
1658						_self.objects.contentInner.css('opacity', 0);
1659					}
1660					_self.transition.fade(_self.objects.overlay, 'in', _self.settings.speedIn, _self.settings.overlayOpacity, function () {
1661						_self.transition.fade(_self.objects.close, 'in', _self.settings.speedIn);
1662						_self._handleEvents();
1663						_self._processContent();
1664					});
1665					break;
1666				default:
1667					_self.transition.fade(_self.objects.overlay, 'in', 0, _self.settings.overlayOpacity, function () {
1668						_self.transition.fade(_self.objects.close, 'in', 0);
1669						_self._handleEvents();
1670						_self._processContent();
1671					});
1672					break;
1673			}
1674
1675			_self.objects.document.addClass(_self.settings.classPrefix + 'open');
1676			_self.objects.case.attr('aria-hidden', 'false');
1677		},
1678
1679		/**
1680		 * Shows the lightcase by starting the transition
1681		 */
1682		show: function () {
1683			// Call onCalculateDimensions hook functions
1684			_self._callHooks(_self.settings.onBeforeCalculateDimensions);
1685
1686			_self._calculateDimensions(_self.cache.object);
1687
1688			// Call onAfterCalculateDimensions hook functions
1689			_self._callHooks(_self.settings.onAfterCalculateDimensions);
1690
1691			_self._startInTransition();
1692		},
1693
1694		/**
1695		 * Escapes from the lightcase view
1696		 *
1697		 * @return	{void}
1698		 */
1699		close: function () {
1700			_self.isOpen = false;
1701
1702			if (_self.isSlideshowEnabled()) {
1703				_self._stopTimeout();
1704				_self.isSlideshowStarted = false;
1705				_self.objects.nav.removeClass(_self.settings.classPrefix + 'paused');
1706			}
1707
1708			_self.objects.loading.hide();
1709
1710			_self._unbindEvents();
1711
1712			_self._unwatchResizeInteraction();
1713
1714			$('html').removeClass(_self.settings.classPrefix + 'open');
1715			_self.objects.case.attr('aria-hidden', 'true');
1716
1717			_self.objects.nav.children().hide();
1718			_self.objects.close.hide();
1719
1720			// Call onClose hook functions
1721			_self._callHooks(_self.settings.onClose);
1722
1723			// Fade out the info at first
1724			_self.transition.fade(_self.objects.info, 'out', 0);
1725
1726			switch (_self.settings.transitionClose || _self.settings.transitionOut) {
1727				case 'fade':
1728				case 'fadeInline':
1729				case 'scrollTop':
1730				case 'scrollRight':
1731				case 'scrollBottom':
1732				case 'scrollLeft':
1733				case 'scrollHorizontal':
1734				case 'scrollVertical':
1735					_self.transition.fade(_self.objects.case, 'out', _self.settings.speedOut, 0, function () {
1736						_self.transition.fade(_self.objects.overlay, 'out', _self.settings.speedOut, 0, function () {
1737							_self.cleanup();
1738						});
1739					});
1740					break;
1741				case 'elastic':
1742					_self.transition.zoom(_self.objects.case, 'out', _self.settings.speedOut, function () {
1743						_self.transition.fade(_self.objects.overlay, 'out', _self.settings.speedOut, 0, function () {
1744							_self.cleanup();
1745						});
1746					});
1747					break;
1748				default:
1749					_self.cleanup();
1750					break;
1751			}
1752		},
1753
1754		/**
1755		 * Unbinds all given events
1756		 *
1757		 * @return	{void}
1758		 */
1759		_unbindEvents: function () {
1760			// Unbind overlay event
1761			_self.objects.overlay.unbind('click');
1762
1763			// Unbind key events
1764			$(document).unbind('keyup.lightcase');
1765
1766			// Unbind swipe events
1767			_self.objects.case.unbind('swipeleft').unbind('swiperight');
1768
1769			// Unbind navigator events
1770			_self.objects.prev.unbind('click');
1771			_self.objects.next.unbind('click');
1772			_self.objects.play.unbind('click');
1773			_self.objects.pause.unbind('click');
1774
1775			// Unbind close event
1776			_self.objects.close.unbind('click');
1777		},
1778
1779		/**
1780		 * Cleans up the dimensions
1781		 *
1782		 * @return	{void}
1783		 */
1784		_cleanupDimensions: function () {
1785			var opacity = _self.objects.contentInner.css('opacity');
1786
1787			_self.objects.case.css({
1788				'width': '',
1789				'height': '',
1790				'top': '',
1791				'left': '',
1792				'margin-top': '',
1793				'margin-left': ''
1794			});
1795
1796			_self.objects.contentInner.removeAttr('style').css('opacity', opacity);
1797			_self.objects.contentInner.children().removeAttr('style');
1798		},
1799
1800		/**
1801		 * Cleanup after aborting lightcase
1802		 *
1803		 * @return	{void}
1804		 */
1805		cleanup: function () {
1806			_self._cleanupDimensions();
1807
1808			_self.objects.loading.hide();
1809			_self.objects.overlay.hide();
1810			_self.objects.case.hide();
1811			_self.objects.prev.hide();
1812			_self.objects.next.hide();
1813			_self.objects.play.hide();
1814			_self.objects.pause.hide();
1815
1816			_self.objects.document.removeAttr(_self._prefixAttributeName('type'));
1817			_self.objects.nav.removeAttr(_self._prefixAttributeName('ispartofsequence'));
1818
1819			_self.objects.contentInner.empty().hide();
1820			_self.objects.info.children().empty();
1821
1822			if (_self.cache.originalObject) {
1823				_self._restoreObject();
1824			}
1825
1826			// Call onCleanup hook functions
1827			_self._callHooks(_self.settings.onCleanup);
1828
1829			// Restore cache
1830			_self.cache = {};
1831		},
1832
1833		/**
1834		 * Returns the supported match media or undefined if the browser
1835		 * doesn't support match media.
1836		 *
1837		 * @return	{mixed}
1838		 */
1839		_matchMedia: function () {
1840			return window.matchMedia || window.msMatchMedia;
1841		},
1842
1843		/**
1844		 * Returns the devicePixelRatio if supported. Else, it simply returns
1845		 * 1 as the default.
1846		 *
1847		 * @return	{number}
1848		 */
1849		_devicePixelRatio: function () {
1850			return window.devicePixelRatio || 1;
1851		},
1852
1853		/**
1854		 * Checks if method is public
1855		 *
1856		 * @return	{boolean}
1857		 */
1858		_isPublicMethod: function (method) {
1859			return (typeof _self[method] === 'function' && method.charAt(0) !== '_');
1860		},
1861
1862		/**
1863		 * Exports all public methods to be accessible, callable
1864		 * from global scope.
1865		 *
1866		 * @return	{void}
1867		 */
1868		_export: function () {
1869			window.lightcase = {};
1870
1871			$.each(_self, function (property) {
1872				if (_self._isPublicMethod(property)) {
1873					lightcase[property] = _self[property];
1874				}
1875			});
1876		}
1877	};
1878
1879	_self._export();
1880
1881	$.fn.lightcase = function (method) {
1882		// Method calling logic (only public methods are applied)
1883		if (_self._isPublicMethod(method)) {
1884			return _self[method].apply(this, Array.prototype.slice.call(arguments, 1));
1885		} else if (typeof method === 'object' || !method) {
1886			return _self.init.apply(this, arguments);
1887		} else {
1888			$.error('Method ' + method + ' does not exist on jQuery.lightcase');
1889		}
1890	};
1891})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.