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