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