vendor: 15,210 bytes, lines 1-340
1/*! 2 * jQuery Magnify Plugin v2.3.2 by T. H. Doan (https://thdoan.github.io/magnify/) 3 * Based on http://thecodeplayer.com/walkthrough/magnifying-glass-for-images-using-jquery-and-css3 4 * 5 * jQuery Magnify by T. H. Doan is licensed under the MIT License. 6 * Read a copy of the license in the LICENSE file or at https://choosealicense.com/licenses/mit/ 7 */ 8 9(function($) { 10 $.fn.magnify = function(oOptions) { 11 // Default options 12 oOptions = $.extend({ 13 'src': '', 14 'speed': 100, 15 'timeout': -1, 16 'touchBottomOffset': 0, 17 'finalWidth': null, 18 'finalHeight': null, 19 'magnifiedWidth': null, 20 'magnifiedHeight': null, 21 'limitBounds': false, 22 'mobileCloseEvent': 'touchstart', 23 'afterLoad': function(){} 24 }, oOptions); 25 26 var $that = this, // Preserve scope 27 $html = $('html'), 28 29 // Initiate 30 init = function(el) { 31 var $image = $(el), 32 $anchor = $image.closest('a'), 33 oDataAttr = {}; 34 35 // Get data attributes 36 for (var i in oOptions) { 37 oDataAttr[i] = $image.attr('data-magnify-' + i.toLowerCase()); 38 } 39 40 // Disable zooming if no valid large image source 41 var sZoomSrc = oDataAttr['src'] || oOptions['src'] || $anchor.attr('href') || ''; 42 if (!sZoomSrc) return; 43 44 var $container, 45 $lens, 46 nImageWidth, 47 nImageHeight, 48 nMagnifiedWidth, 49 nMagnifiedHeight, 50 nLensWidth, 51 nLensHeight, 52 nBoundX = 0, 53 nBoundY = 0, 54 oContainerOffset, // Relative to document 55 oImageOffset, // Relative to container 56 // Get true offsets 57 getOffset = function() { 58 var o = $container.offset(); 59 // Store offsets from container border to image inside 60 // NOTE: .offset() does NOT take into consideration image border and padding. 61 oImageOffset = { 62 'top': ($image.offset().top-o.top) + parseInt($image.css('border-top-width')) + parseInt($image.css('padding-top')), 63 'left': ($image.offset().left-o.left) + parseInt($image.css('border-left-width')) + parseInt($image.css('padding-left')) 64 }; 65 o.top += oImageOffset['top']; 66 o.left += oImageOffset['left']; 67 return o; 68 }, 69 // Hide the lens 70 hideLens = function() { 71 if ($lens.is(':visible')) $lens.fadeOut(oOptions['speed'], function() { 72 $html.removeClass('magnifying').trigger('magnifyend'); // Reset overflow-x 73 }); 74 }, 75 moveLens = function(e) { 76 // Reinitialize if image initially hidden 77 if (!nImageHeight) { 78 refresh(); 79 return; 80 } 81 if (e) { 82 e.preventDefault(); 83 // Save last coordinates in case we need to call this function directly (required when 84 // updating magnifiedWidth/magnifiedHeight while the lens is visible). 85 nPosX = e.pageX || e.originalEvent.touches[0].pageX; 86 nPosY = e.pageY || e.originalEvent.touches[0].pageY; 87 $image.data('lastPos', { 88 'x': nPosX, 89 'y': nPosY 90 }); 91 } else { 92 nPosX = $image.data('lastPos').x; 93 nPosY = $image.data('lastPos').y; 94 } 95 // x/y coordinates of the mouse pointer or touch point. This is the position of 96 // .magnify relative to the document. 97 // 98 // We deduct the positions of .magnify from the mouse or touch positions relative to 99 // the document to get the mouse or touch positions relative to the container. 100 nX = nPosX - oContainerOffset['left'], 101 nY = (nPosY - oContainerOffset['top']) - oOptions['touchBottomOffset']; 102 // Toggle magnifying lens 103 if (!$lens.is(':animated')) { 104 if (nX>nBoundX && nX<nImageWidth-nBoundX && nY>nBoundY && nY<nImageHeight-nBoundY) { 105 if ($lens.is(':hidden')) { 106 $html.addClass('magnifying').trigger('magnifystart'); // Hide overflow-x while zooming 107 $lens.fadeIn(oOptions['speed']); 108 } 109 } else { 110 hideLens(); 111 } 112 } 113 if ($lens.is(':visible')) { 114 // Move the magnifying lens with the mouse 115 var sBgPos = ''; 116 if (nMagnifiedWidth && nMagnifiedHeight) { 117 // Change the background position of .magnify-lens according to the position of 118 // the mouse over the .magnify-image image. This allows us to get the ratio of 119 // the pixel under the mouse pointer with respect to the image and use that to 120 // position the large image inside the magnifying lens. 121 var nRatioX = -Math.round(nX/nImageWidth*nMagnifiedWidth-nLensWidth/2), 122 nRatioY = -Math.round(nY/nImageHeight*nMagnifiedHeight-nLensHeight/2); 123 if (oOptions['limitBounds']) { 124 // Enforce bounds to ensure only image is visible in lens 125 var nBoundRight = -Math.round((nImageWidth-nBoundX)/nImageWidth*nMagnifiedWidth-nLensWidth/2), 126 nBoundBottom = -Math.round((nImageHeight-nBoundY)/nImageHeight*nMagnifiedHeight-nLensHeight/2); 127 // Left and right edges 128 if (nRatioX>0) nRatioX = 0; 129 else if (nRatioX<nBoundRight) nRatioX = nBoundRight; 130 // Top and bottom edges 131 if (nRatioY>0) nRatioY = 0; 132 else if (nRatioY<nBoundBottom) nRatioY = nBoundBottom; 133 } 134 sBgPos = nRatioX + 'px ' + nRatioY + 'px'; 135 } 136 // Now the lens moves with the mouse. The logic is to deduct half of the lens's 137 // width and height from the mouse coordinates to place it with its center at the 138 // mouse coordinates. If you hover on the image now, you should see the magnifying 139 // lens in action. 140 $lens.css({ 141 'top': Math.round(nY-nLensHeight/2) + oImageOffset['top'] + 'px', 142 'left': Math.round(nX-nLensWidth/2) + oImageOffset['left'] + 'px', 143 'background-position': sBgPos 144 }); 145 } 146 }; 147 148 // Data attributes have precedence over options object 149 if (!isNaN(+oDataAttr['speed'])) oOptions['speed'] = +oDataAttr['speed']; 150 if (!isNaN(+oDataAttr['timeout'])) oOptions['timeout'] = +oDataAttr['timeout']; 151 if (!isNaN(+oDataAttr['finalWidth'])) oOptions['finalWidth'] = +oDataAttr['finalWidth']; 152 if (!isNaN(+oDataAttr['finalHeight'])) oOptions['finalHeight'] = +oDataAttr['finalHeight']; 153 if (!isNaN(+oDataAttr['magnifiedWidth'])) oOptions['magnifiedWidth'] = +oDataAttr['magnifiedWidth']; 154 if (!isNaN(+oDataAttr['magnifiedHeight'])) oOptions['magnifiedHeight'] = +oDataAttr['magnifiedHeight']; 155 if (oDataAttr['limitBounds']==='true') oOptions['limitBounds'] = true; 156 if (typeof window[oDataAttr['afterLoad']]==='function') oOptions.afterLoad = window[oDataAttr['afterLoad']]; 157 158 // Implement touch point bottom offset only on mobile devices 159 if (/\b(Android|BlackBerry|IEMobile|iPad|iPhone|Mobile|Opera Mini)\b/.test(navigator.userAgent)) { 160 if (!isNaN(+oDataAttr['touchBottomOffset'])) oOptions['touchBottomOffset'] = +oDataAttr['touchBottomOffset']; 161 } else { 162 oOptions['touchBottomOffset'] = 0; 163 } 164 165 // Save any inline styles for resetting 166 $image.data('originalStyle', $image.attr('style')); 167 168 // Activate magnification: 169 // 1. Try to get large image dimensions 170 // 2. Proceed only if able to get large image dimensions OK 171 172 // [1] Calculate the native (magnified) image dimensions. The zoomed version is only shown 173 // after the native dimensions are available. To get the actual dimensions we have to create 174 // this image object. 175 var elZoomImage = new Image(); 176 $(elZoomImage).on({ 177 'load': function() { 178 // [2] Got image dimensions OK. 179 180 var nPosX, nPosY, nX, nY; 181 182 // Fix overlap bug at the edges during magnification 183 $image.css('display', 'block'); 184 // Create container div if necessary 185 if (!$image.parent('.magnify').length) { 186 $image.wrap('<div class="magnify"></div>'); 187 } 188 $container = $image.parent('.magnify'); 189 // Create the magnifying lens div if necessary 190 if ($image.prev('.magnify-lens').length) { 191 $container.children('.magnify-lens').css('background-image', 'url(\'' + sZoomSrc + '\')'); 192 } else { 193 $image.before('<div class="magnify-lens loading" style="background:url(\'' + sZoomSrc + '\') 0 0 no-repeat"></div>'); 194 } 195 $lens = $container.children('.magnify-lens'); 196 // Remove the "Loading..." text 197 $lens.removeClass('loading'); 198 // Cache dimensions and offsets for improved performance 199 // NOTE: This code is inside the load() function, which is important. The width and 200 // height of the object would return 0 if accessed before the image is fully loaded. 201 nImageWidth = oOptions['finalWidth'] || $image.width(); 202 nImageHeight = oOptions['finalHeight'] || $image.height(); 203 nMagnifiedWidth = oOptions['magnifiedWidth'] || elZoomImage.width; 204 nMagnifiedHeight = oOptions['magnifiedHeight'] || elZoomImage.height; 205 nLensWidth = $lens.width(); 206 nLensHeight = $lens.height(); 207 oContainerOffset = getOffset(); // Required by refresh() 208 // Set zoom boundaries 209 if (oOptions['limitBounds']) { 210 nBoundX = (nLensWidth/2) / (nMagnifiedWidth/nImageWidth); 211 nBoundY = (nLensHeight/2) / (nMagnifiedHeight/nImageHeight); 212 } 213 // Enforce non-native large image size? 214 if (nMagnifiedWidth!==elZoomImage.width || nMagnifiedHeight!==elZoomImage.height) { 215 $lens.css('background-size', nMagnifiedWidth + 'px ' + nMagnifiedHeight + 'px'); 216 } 217 // Store zoom dimensions for mobile plugin 218 $image.data('zoomSize', { 219 'width': nMagnifiedWidth, 220 'height': nMagnifiedHeight 221 }); 222 // Store mobile close event for mobile plugin 223 $container.data('mobileCloseEvent', oDataAttr['mobileCloseEvent'] || oOptions['mobileCloseEvent']); 224 // Clean up 225 elZoomImage = null; 226 // Execute callback 227 oOptions.afterLoad(); 228 // Simulate a lens move to update positioning if magnifiedWidth/magnifiedHeight is 229 // updated while the lens is visible 230 if ($lens.is(':visible')) moveLens(); 231 // Handle mouse movements 232 $container.off().on({ 233 'mousemove touchmove': moveLens, 234 'mouseenter': function() { 235 // Need to update offsets here to support accordions 236 oContainerOffset = getOffset(); 237 }, 238 'mouseleave': hideLens 239 }); 240 241 // Prevent magnifying lens from getting "stuck" 242 if (oOptions['timeout']>=0) { 243 $container.on('touchend', function() { 244 setTimeout(hideLens, oOptions['timeout']); 245 }); 246 } 247 // Ensure lens is closed when tapping outside of it 248 $('body').not($container).on('touchstart', hideLens); 249 250 // Support image map click-throughs while zooming 251 var sUsemap = $image.attr('usemap'); 252 if (sUsemap) { 253 var $map = $('map[name=' + sUsemap.slice(1) + ']'); 254 // Image map needs to be on the same DOM level as image source 255 $image.after($map); 256 $container.click(function(e) { 257 // Trigger click on image below lens at current cursor position 258 if (e.clientX || e.clientY) { 259 $lens.hide(); 260 var elPoint = document.elementFromPoint( 261 e.clientX || e.originalEvent.touches[0].clientX, 262 e.clientY || e.originalEvent.touches[0].clientY 263 ); 264 if (elPoint.nodeName==='AREA') { 265 elPoint.click(); 266 } else { 267 // Workaround for buggy implementation of elementFromPoint() 268 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1227469 269 $('area', $map).each(function() { 270 var a = $(this).attr('coords').split(','); 271 if (nX>=a[0] && nX<=a[2] && nY>=a[1] && nY<=a[3]) { 272 this.click(); 273 return false; 274 } 275 }); 276 } 277 } 278 }); 279 } 280 281 if ($anchor.length) { 282 // Make parent anchor inline-block to have correct dimensions 283 $anchor.css('display', 'inline-block'); 284 // Disable parent anchor if it's sourcing the large image 285 if ($anchor.attr('href') && !(oDataAttr['src'] || oOptions['src'])) { 286 $anchor.click(function(e) { 287 e.preventDefault(); 288 }); 289 } 290 } 291 292 }, 293 'error': function() { 294 // Clean up 295 elZoomImage = null; 296 } 297 }); 298 299 elZoomImage.src = sZoomSrc; 300 }, // END init() 301 302 // Simple debounce 303 nTimer = 0, 304 refresh = function() { 305 clearTimeout(nTimer); 306 nTimer = setTimeout(function() { 307 $that.destroy(); 308 $that.magnify(oOptions); 309 }, 100); 310 }; 311 312 /** 313 * Public Methods 314 */ 315 316 // Turn off zoom and reset to original state 317 this.destroy = function() { 318 this.each(function() { 319 var $this = $(this), 320 $lens = $this.prev('div.magnify-lens'), 321 sStyle = $this.data('originalStyle'); 322 if ($this.parent('div.magnify').length && $lens.length) { 323 if (sStyle) $this.attr('style', sStyle); 324 else $this.removeAttr('style'); 325 $this.unwrap(); 326 $lens.remove(); 327 } 328 }); 329 // Unregister event handler 330 $(window).off('resize', refresh); 331 return $that; 332 } 333 334 // Handle window resizing 335 $(window).resize(refresh); 336 337 return this.each(function() { 338 // Initiate magnification powers 339 init(this); 340 });
341 342 }; 343}(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.