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: 1000, 61 maxHeight: null, 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: false, 86 inline: { 87 width: '820', 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: '400', 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);
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.