/* Lens by HTML5 UP html5up.net | @n33co Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) */ var main = (function($) { var _ = { /** * Settings. * @var {object} */ settings: { // Preload all images. preload: false, // Slide duration (must match "duration.slide" in _vars.scss). slideDuration: 500, // Layout duration (must match "duration.layout" in _vars.scss). layoutDuration: 750, // Thumbnails per "row" (must match "misc.thumbnails-per-row" in _vars.scss). thumbnailsPerRow: 2, // Side of main wrapper (must match "misc.main-side" in _vars.scss). mainSide: 'right' }, /** * Window. * @var {jQuery} */ $window: null, /** * Body. * @var {jQuery} */ $body: null, /** * Main wrapper. * @var {jQuery} */ $main: null, /** * Thumbnails. * @var {jQuery} */ $thumbnails: null, /** * Viewer. * @var {jQuery} */ $viewer: null, /** * Toggle. * @var {jQuery} */ $toggle: null, /** * Nav (next). * @var {jQuery} */ $navNext: null, /** * Nav (previous). * @var {jQuery} */ $navPrevious: null, /** * Slides. * @var {array} */ slides: [], /** * Current slide index. * @var {integer} */ current: null, /** * Lock state. * @var {bool} */ locked: false, /** * Keyboard shortcuts. * @var {object} */ keys: { // Escape: Toggle main wrapper. 27: function() { _.toggle(); }, // Up: Move up. 38: function() { _.up(); }, // Down: Move down. 40: function() { _.down(); }, // Space: Next. 32: function() { _.next(); }, // Right Arrow: Next. 39: function() { _.next(); }, // Left Arrow: Previous. 37: function() { _.previous(); } }, /** * Initialize properties. */ initProperties: function() { // Window, body. _.$window = $(window); _.$body = $('body'); // Thumbnails. _.$thumbnails = $('#thumbnails'); // Viewer. _.$viewer = $( '
' + '
' + '' + '' + '
' + '
' + '
' ).appendTo(_.$body); // Nav. _.$navNext = _.$viewer.find('.nav-next'); _.$navPrevious = _.$viewer.find('.nav-previous'); // Main wrapper. _.$main = $('#main'); // Toggle. $('
') .appendTo(_.$main); _.$toggle = $('.toggle'); // IE<9: Fix viewer width (no calc support). if (skel.vars.IEVersion < 9) _.$window .on('resize', function() { window.setTimeout(function() { _.$viewer.css('width', _.$window.width() - _.$main.width()); }, 100); }) .trigger('resize'); }, /** * Initialize events. */ initEvents: function() { // Window. // Remove is-loading-* classes on load. _.$window.on('load', function() { _.$body.removeClass('is-loading-0'); window.setTimeout(function() { _.$body.removeClass('is-loading-1'); }, 100); window.setTimeout(function() { _.$body.removeClass('is-loading-2'); }, 100 + Math.max(_.settings.layoutDuration - 150, 0)); }); // Disable animations/transitions on resize. var resizeTimeout; _.$window.on('resize', function() { _.$body.addClass('is-loading-0'); window.clearTimeout(resizeTimeout); resizeTimeout = window.setTimeout(function() { _.$body.removeClass('is-loading-0'); }, 100); }); // Viewer. // Hide main wrapper on tap (<= medium only). _.$viewer.on('touchend', function() { if (skel.breakpoint('medium').active) _.hide(); }); // Touch gestures. _.$viewer .on('touchstart', function(event) { // Record start position. _.$viewer.touchPosX = event.originalEvent.touches[0].pageX; _.$viewer.touchPosY = event.originalEvent.touches[0].pageY; }) .on('touchmove', function(event) { // No start position recorded? Bail. if (_.$viewer.touchPosX === null || _.$viewer.touchPosY === null) return; // Calculate stuff. var diffX = _.$viewer.touchPosX - event.originalEvent.touches[0].pageX, diffY = _.$viewer.touchPosY - event.originalEvent.touches[0].pageY; boundary = 20, delta = 50; // Swipe left (next). if ( (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta) ) _.next(); // Swipe right (previous). else if ( (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta)) ) _.previous(); // Overscroll fix. var th = _.$viewer.outerHeight(), ts = (_.$viewer.get(0).scrollHeight - _.$viewer.scrollTop()); if ((_.$viewer.scrollTop() <= 0 && diffY < 0) || (ts > (th - 2) && ts < (th + 2) && diffY > 0)) { event.preventDefault(); event.stopPropagation(); } }); // Main. // Touch gestures. _.$main .on('touchstart', function(event) { // Bail on xsmall. if (skel.breakpoint('xsmall').active) return; // Record start position. _.$main.touchPosX = event.originalEvent.touches[0].pageX; _.$main.touchPosY = event.originalEvent.touches[0].pageY; }) .on('touchmove', function(event) { // Bail on xsmall. if (skel.breakpoint('xsmall').active) return; // No start position recorded? Bail. if (_.$main.touchPosX === null || _.$main.touchPosY === null) return; // Calculate stuff. var diffX = _.$main.touchPosX - event.originalEvent.touches[0].pageX, diffY = _.$main.touchPosY - event.originalEvent.touches[0].pageY; boundary = 20, delta = 50, result = false; // Swipe to close. switch (_.settings.mainSide) { case 'left': result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta); break; case 'right': result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta)); break; default: break; } if (result) _.hide(); // Overscroll fix. var th = _.$main.outerHeight(), ts = (_.$main.get(0).scrollHeight - _.$main.scrollTop()); if ((_.$main.scrollTop() <= 0 && diffY < 0) || (ts > (th - 2) && ts < (th + 2) && diffY > 0)) { event.preventDefault(); event.stopPropagation(); } }); // Toggle. _.$toggle.on('click', function() { _.toggle(); }); // Prevent event from bubbling up to "hide event on tap" event. _.$toggle.on('touchend', function(event) { event.stopPropagation(); }); // Nav. _.$navNext.on('click', function() { _.next(); }); _.$navPrevious.on('click', function() { _.previous(); }); // Keyboard shortcuts. // Ignore shortcuts within form elements. _.$body.on('keydown', 'input,select,textarea', function(event) { event.stopPropagation(); }); _.$window.on('keydown', function(event) { // Ignore if xsmall is active. if (skel.breakpoint('xsmall').active) return; // Check keycode. if (event.keyCode in _.keys) { // Stop other events. event.stopPropagation(); event.preventDefault(); // Call shortcut. (_.keys[event.keyCode])(); } }); }, /** * Initialize viewer. */ initViewer: function() { // Bind thumbnail click event. _.$thumbnails .on('click', '.thumbnail', function(event) { var $this = $(this); // Stop other events. event.preventDefault(); event.stopPropagation(); // Locked? Blur. if (_.locked) $this.blur(); // Switch to this thumbnail's slide. _.switchTo($this.data('index')); }); // Create slides from thumbnails. _.$thumbnails.children() .each(function() { var $this = $(this), $thumbnail = $this.children('.thumbnail'), s; // Slide object. s = { $parent: $this, $slide: null, $slideImage: null, $slideCaption: null, url: $thumbnail.attr('href'), loaded: false }; // Parent. $this.attr('tabIndex', '-1'); // Slide. // Create elements. s.$slide = $('
'); // Image. s.$slideImage = s.$slide.children('.image'); // Set background stuff. s.$slideImage .css('background-image', '') .css('background-position', ($thumbnail.data('position') || 'center')); // Caption. s.$slideCaption = s.$slide.find('.caption'); // Move everything *except* the thumbnail itself to the caption. $this.children().not($thumbnail) .appendTo(s.$slideCaption); // Preload? if (_.settings.preload) { // Force image to download. var $img = $(''); // Set slide's background image to it. s.$slideImage .css('background-image', 'url(' + s.url + ')'); // Mark slide as loaded. s.$slide.addClass('loaded'); s.loaded = true; } // Add to slides array. _.slides.push(s); // Set thumbnail's index. $thumbnail.data('index', _.slides.length - 1); }); }, /** * Initialize stuff. */ init: function() { // IE<10: Zero out transition delays. if (skel.vars.IEVersion < 10) { _.settings.slideDuration = 0; _.settings.layoutDuration = 0; } // Skel. skel.breakpoints({ xlarge: '(max-width: 1680px)', large: '(max-width: 1280px)', medium: '(max-width: 980px)', small: '(max-width: 736px)', xsmall: '(max-width: 480px)' }); // Everything else. _.initProperties(); _.initViewer(); _.initEvents(); // Initial slide. window.setTimeout(function() { // Show first slide if xsmall isn't active or it just deactivated. skel.on('-xsmall !xsmall', function() { if (_.current === null) _.switchTo(0, true); }); }, 0); }, /** * Switch to a specific slide. * @param {integer} index Index. */ switchTo: function(index, noHide) { // Already at index and xsmall isn't active? Bail. if (_.current == index && !skel.breakpoint('xsmall').active) return; // Locked? Bail. if (_.locked) return; // Lock. _.locked = true; // Hide main wrapper if medium is active. if (!noHide && skel.breakpoint('medium').active && skel.vars.IEVersion > 8) _.hide(); // Get slides. var oldSlide = (_.current !== null ? _.slides[_.current] : null), newSlide = _.slides[index]; // Update current. _.current = index; // Deactivate old slide (if there is one). if (oldSlide) { // Thumbnail. oldSlide.$parent .removeClass('active'); // Slide. oldSlide.$slide.removeClass('active'); } // Activate new slide. // Thumbnail. newSlide.$parent .addClass('active') .focus(); // Slide. var f = function() { // Old slide exists? Detach it. if (oldSlide) oldSlide.$slide.detach(); // Attach new slide. newSlide.$slide.appendTo(_.$viewer); // New slide not yet loaded? if (!newSlide.loaded) { window.setTimeout(function() { // Mark as loading. newSlide.$slide.addClass('loading'); // Wait for it to load. $('').on('load', function() { //window.setTimeout(function() { // Set background image. newSlide.$slideImage .css('background-image', 'url(' + newSlide.url + ')'); // Mark as loaded. newSlide.loaded = true; newSlide.$slide.removeClass('loading'); // Mark as active. newSlide.$slide.addClass('active'); // Unlock. window.setTimeout(function() { _.locked = false; }, 100); //}, 1000); }); }, 100); } // Otherwise ... else { window.setTimeout(function() { // Mark as active. newSlide.$slide.addClass('active'); // Unlock. window.setTimeout(function() { _.locked = false; }, 100); }, 100); } }; // No old slide? Switch immediately. if (!oldSlide) (f)(); // Otherwise, wait for old slide to disappear first. else window.setTimeout(f, _.settings.slideDuration); }, /** * Switches to the next slide. */ next: function() { // Calculate new index. var i, c = _.current, l = _.slides.length; if (c >= l - 1) i = 0; else i = c + 1; // Switch. _.switchTo(i); }, /** * Switches to the previous slide. */ previous: function() { // Calculate new index. var i, c = _.current, l = _.slides.length; if (c <= 0) i = l - 1; else i = c - 1; // Switch. _.switchTo(i); }, /** * Switches to slide "above" current. */ up: function() { // Fullscreen? Bail. if (_.$body.hasClass('fullscreen')) return; // Calculate new index. var i, c = _.current, l = _.slides.length, tpr = _.settings.thumbnailsPerRow; if (c <= (tpr - 1)) i = l - (tpr - 1 - c) - 1; else i = c - tpr; // Switch. _.switchTo(i); }, /** * Switches to slide "below" current. */ down: function() { // Fullscreen? Bail. if (_.$body.hasClass('fullscreen')) return; // Calculate new index. var i, c = _.current, l = _.slides.length, tpr = _.settings.thumbnailsPerRow; if (c >= l - tpr) i = c - l + tpr; else i = c + tpr; // Switch. _.switchTo(i); }, /** * Shows the main wrapper. */ show: function() { // Already visible? Bail. if (!_.$body.hasClass('fullscreen')) return; // Show main wrapper. _.$body.removeClass('fullscreen'); // Focus. _.$main.focus(); }, /** * Hides the main wrapper. */ hide: function() { // Already hidden? Bail. if (_.$body.hasClass('fullscreen')) return; // Hide main wrapper. _.$body.addClass('fullscreen'); // Blur. _.$main.blur(); }, /** * Toggles main wrapper. */ toggle: function() { if (_.$body.hasClass('fullscreen')) _.show(); else _.hide(); }, }; return _; })(jQuery); main.init();