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