PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 3.33
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v3.33
3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 2.44 All 141 releases
photonic / include / ext / lightcase / lightcase.js

lightcase.js in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 3.33, at include/ext/lightcase/lightcase.js

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