/* Library for dealing with user generated content */ $(function () { var imageViewRe = /^#image-view\[src="(([^"]|\")+)"\]/; var $window = $(window); var $body = $(document.body); function ImageView() { var $viewRoot, $view, $animImage, $panzoom; var _open, _close, hashChange; var toolbarHeight = 36; var isOpen = false; var self = this; $viewRoot = $( '
' + '
' + '
Close
' + '
Download
' + '
×
' + '
' + '
' + '
' ); $view = { image: $viewRoot.find('img'), closeBtn: $viewRoot.find('.image-view-close, .image-view-close-icon'), downloadBtn: $viewRoot.find('.image-view-download') }; $body.append($viewRoot); $viewRoot.hide(); $animImage = $('', {'class': 'image-view-anim-image'}); $body.append($animImage); $animImage.hide(); $panzoom = $view.image.panzoom(); // Get the absolute geometry for an image, relative to the window. var getGeometry = function (image) { var offset = $(image).offset(); return { top: offset.top - $window.scrollTop(), left: offset.left - $window.scrollLeft(), width: image.width, height: image.height }; }; // Get the absolute geometry of the initial image position on screen. var getZoomedGeometry = function (imgElement) { var winWidth = $window.width(); var winHeight = $window.height() - toolbarHeight; var winRatio = winWidth / winHeight; var imgRatio = imgElement.width / imgElement.height; if (winRatio < imgRatio) { return { top: toolbarHeight + (winHeight - (winWidth / imgRatio))/2, left: 0, width: winWidth, height: winWidth / imgRatio }; } else { return { top: toolbarHeight, left: (winWidth - (imgRatio * winHeight))/2, width: imgRatio * winHeight, height: winHeight }; } }; _open = function(image) { var domGeometry, zoomGeometry; // Ensure that we can actually use this image. if (!image || image.src === undefined || image.width < 1) return false; // Handle openness state. if (isOpen) obj.close(); isOpen = true; zoomGeometry = getZoomedGeometry(image); domGeometry = getGeometry(image); // Set up viewimage. We're using padding, because then our element's center remains the same. $view.image.attr('src', image.src); $view.image.css({ paddingTop: zoomGeometry.top, paddingLeft: zoomGeometry.left, width: zoomGeometry.width, height: zoomGeometry.height }); // Image in DOM? Perform fancy transition. if ($.contains(document, image)) { $view.image.hide(); $viewRoot.fadeIn(1000); $animImage.attr('src', image.src); $animImage.show(); $animImage.css(domGeometry); $animImage.animate(zoomGeometry, 1000, 'swing', function() { $animImage.hide(); $view.image.show(); $view.image.panzoom('reset'); $view.image.panzoom('resetDimensions'); }); } else { $view.image.show(); $view.image.panzoom('reset'); $view.image.panzoom('resetDimensions'); $viewRoot.fadeIn(1000); } }; _close = function() { isOpen = false; $viewRoot.fadeOut(200); }; this.open = function(img) { var hash; _open(img); // Set up history: when possible, use pushState. hash = 'image-view[src="' + img.src + '"]'; if (history && history.pushState) history.pushState('', document.title, location.pathname + location.search + '#' + hash); else window.location.hash = hash; }; this.close = function() { if (isOpen) history.back(); }; // Handles hash changes. hashChange = function() { var matches = imageViewRe.exec(window.location.hash); if (isOpen) { // If we're open and we move off of an image-view URL, close. if (!matches) _close(); } else { // If we're closed and we move on an image-view URL, open. if (matches && matches.length >= 2) { var image = $(''); image.on('load', function () { _open(image[0]); }); image.attr('src', matches[1]); } } }; // Event handling. $panzoom.parent().on('mousewheel.focal', function(e) { e.preventDefault(); var delta = e.delta || e.originalEvent.wheelDelta; var zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; $panzoom.panzoom('zoom', zoomOut, { increment: 0.025, animate: false, focal: e }); }); $window.resize(function() { $view.image.panzoom('resetDimensions'); }); $window.on('hashchange', function () { return hashChange(); }); $view.closeBtn.click(function() { self.close(); }); $view.downloadBtn.click(function() { location.href = $view.image.attr('src'); }); hashChange(); } var setupNaturalImageSize = function (image, callback) { /* Polyfill for browsers that don't setup native image size properties * @imgElement - Given image to setup native properties for */ var $image = $(image); if ($image.prop('naturalWidth') === undefined) { var $origImg = $(''); $origImg.on('load', function () { $image.prop('naturalWidth', $origImg[0].width); $image.prop('naturalHeight', $origImg[0].height); callback($image[0]); }); $origImg.attr('src', $image.attr('src')); } else { if ($image.prop('naturalWidth') !== 0) { callback($image[0]); } else { $image.on('load', function () { callback($image[0]); }); } } }; /* Loop through all images in user-content * If max-width: 100% is being used, make it clickable */ var userImages = $('.user-content img, .platform-content img'); var imageView = new ImageView(); if (userImages.length > 0) { userImages.each(function () { // Make images that are shrunken, bigger. setupNaturalImageSize(this, function (image) { var $image = $(image); if ($image.width() < $image.prop('naturalWidth')) { $image.css('cursor', 'pointer'); } $image.on('click', function () { imageView.open(image); }); }); }); } });