vendor: 9,362 bytes, lines 1-342
1(function (root, factory) { 2 'use strict'; 3 if(typeof define === 'function' && define.amd) { 4 define(['jquery'], function($){ 5 factory($); 6 }); 7 } else if(typeof module === 'object' && module.exports) { 8 module.exports = (root.EasyZoom = factory(require('jquery'))); 9 } else { 10 root.EasyZoom = factory(root.jQuery); 11 } 12}(this, function ($) { 13 14 'use strict'; 15 16 var zoomImgOverlapX; 17 var zoomImgOverlapY; 18 var ratioX; 19 var ratioY; 20 var pointerPositionX; 21 var pointerPositionY; 22 23 var defaults = { 24 25 // The text to display within the notice box while loading the zoom image. 26 loadingNotice: 'Loading image', 27 28 // The text to display within the notice box if an error occurs when loading the zoom image. 29 errorNotice: 'The image could not be loaded', 30 31 // The time (in milliseconds) to display the error notice. 32 errorDuration: 2500, 33 34 // Attribute to retrieve the zoom image URL from. 35 linkAttribute: 'href', 36 37 // Prevent clicks on the zoom image link. 38 preventClicks: true, 39 40 // Callback function to execute before the flyout is displayed. 41 beforeShow: $.noop, 42 43 // Callback function to execute before the flyout is removed. 44 beforeHide: $.noop, 45 46 // Callback function to execute when the flyout is displayed. 47 onShow: $.noop, 48 49 // Callback function to execute when the flyout is removed. 50 onHide: $.noop, 51 52 // Callback function to execute when the cursor is moved while over the image. 53 onMove: $.noop 54 55 }; 56 57 /** 58 * EasyZoom 59 * @constructor 60 * @param {Object} target 61 * @param {Object} options (Optional) 62 */ 63 function EasyZoom(target, options) { 64 this.$target = $(target); 65 this.opts = $.extend({}, defaults, options, this.$target.data()); 66 67 this.isOpen === undefined && this._init(); 68 } 69 70 /** 71 * Init 72 * @private 73 */ 74 EasyZoom.prototype._init = function() { 75 this.$link = this.$target.find('a'); 76 this.$image = this.$target.find('img'); 77 78 this.$flyout = $('<div class="easyzoom-flyout" />'); 79 this.$notice = $('<div class="easyzoom-notice" />'); 80 81 this.$target.on({ 82 'mousemove.easyzoom touchmove.easyzoom': $.proxy(this._onMove, this), 83 'mouseleave.easyzoom touchend.easyzoom': $.proxy(this._onLeave, this), 84 'mouseenter.easyzoom touchstart.easyzoom': $.proxy(this._onEnter, this) 85 }); 86 87 this.opts.preventClicks && this.$target.on('click.easyzoom', function(e) { 88 e.preventDefault(); 89 }); 90 }; 91 92 /** 93 * Show 94 * @param {MouseEvent|TouchEvent} e 95 * @param {Boolean} testMouseOver (Optional) 96 */ 97 EasyZoom.prototype.show = function(e, testMouseOver) { 98 var self = this; 99 100 if (this.opts.beforeShow.call(this) === false) return; 101 102 if (!this.isReady) { 103 return this._loadImage(this.$link.attr(this.opts.linkAttribute), function() { 104 if (self.isMouseOver || !testMouseOver) { 105 self.show(e); 106 } 107 }); 108 } 109 110 this.$target.append(this.$flyout); 111 112 var targetWidth = this.$target.outerWidth(); 113 var targetHeight = this.$target.outerHeight(); 114 115 var flyoutInnerWidth = this.$flyout.width(); 116 var flyoutInnerHeight = this.$flyout.height(); 117 118 var zoomImgWidth = this.$zoom.width(); 119 var zoomImgHeight = this.$zoom.height(); 120 121 zoomImgOverlapX = Math.ceil(zoomImgWidth - flyoutInnerWidth); 122 zoomImgOverlapY = Math.ceil(zoomImgHeight - flyoutInnerHeight); 123 124 // For when the zoom image is smaller than the flyout element. 125 if (zoomImgOverlapX < 0) zoomImgOverlapX = 0; 126 if (zoomImgOverlapY < 0) zoomImgOverlapY = 0; 127 128 ratioX = zoomImgOverlapX / targetWidth; 129 ratioY = zoomImgOverlapY / targetHeight; 130 131 this.isOpen = true; 132 133 this.opts.onShow.call(this); 134 135 e && this._move(e); 136 }; 137 138 /** 139 * On enter 140 * @private 141 * @param {Event} e 142 */ 143 EasyZoom.prototype._onEnter = function(e) { 144 var touches = e.originalEvent.touches; 145 146 this.isMouseOver = true; 147 148 if (!touches || touches.length == 1) { 149 e.preventDefault(); 150 this.show(e, true); 151 } 152 }; 153 154 /** 155 * On move 156 * @private 157 * @param {Event} e 158 */ 159 EasyZoom.prototype._onMove = function(e) { 160 if (!this.isOpen) return; 161 162 e.preventDefault(); 163 this._move(e); 164 }; 165 166 /** 167 * On leave 168 * @private 169 */ 170 EasyZoom.prototype._onLeave = function() { 171 this.isMouseOver = false; 172 this.isOpen && this.hide(); 173 }; 174 175 /** 176 * On load 177 * @private 178 * @param {Event} e 179 */ 180 EasyZoom.prototype._onLoad = function(e) { 181 // IE may fire a load event even on error so test the image dimensions 182 if (!e.currentTarget.width) return; 183 184 this.isReady = true; 185 186 this.$notice.detach(); 187 this.$flyout.html(this.$zoom); 188 this.$target.removeClass('is-loading').addClass('is-ready'); 189 190 e.data.call && e.data(); 191 }; 192 193 /** 194 * On error 195 * @private 196 */ 197 EasyZoom.prototype._onError = function() { 198 var self = this; 199 200 this.$notice.text(this.opts.errorNotice); 201 this.$target.removeClass('is-loading').addClass('is-error'); 202 203 this.detachNotice = setTimeout(function() { 204 self.$notice.detach(); 205 self.detachNotice = null; 206 }, this.opts.errorDuration); 207 }; 208 209 /** 210 * Load image 211 * @private 212 * @param {String} href 213 * @param {Function} callback 214 */ 215 EasyZoom.prototype._loadImage = function(href, callback) { 216 var zoom = new Image(); 217 218 this.$target 219 .addClass('is-loading') 220 .append(this.$notice.text(this.opts.loadingNotice)); 221 222 this.$zoom = $(zoom) 223 .on('error', $.proxy(this._onError, this)) 224 .on('load', callback, $.proxy(this._onLoad, this)); 225 226 zoom.style.position = 'absolute'; 227 zoom.src = href; 228 }; 229 230 /** 231 * Move 232 * @private 233 * @param {Event} e 234 */ 235 EasyZoom.prototype._move = function(e) { 236 237 if (e.type.indexOf('touch') === 0) { 238 var touchlist = e.touches || e.originalEvent.touches; 239 pointerPositionX = touchlist[0].pageX; 240 pointerPositionY = touchlist[0].pageY; 241 } else { 242 pointerPositionX = e.pageX || pointerPositionX; 243 pointerPositionY = e.pageY || pointerPositionY; 244 } 245 246 var targetOffset = this.$target.offset(); 247 var relativePositionX = pointerPositionX - targetOffset.left; 248 var relativePositionY = pointerPositionY - targetOffset.top; 249 var moveX = Math.ceil(relativePositionX * ratioX); 250 var moveY = Math.ceil(relativePositionY * ratioY); 251 252 // Close if outside 253 if (moveX < 0 || moveY < 0 || moveX > zoomImgOverlapX || moveY > zoomImgOverlapY) { 254 this.hide(); 255 } else { 256 var top = moveY * -1; 257 var left = moveX * -1; 258 259 if ('transform' in document.body.style) { 260 this.$zoom.css({ transform: 'translate(' + left + 'px, ' + top + 'px)' }); 261 } else { 262 this.$zoom.css({ top: top, left: left }); 263 } 264 265 this.opts.onMove.call(this, top, left); 266 } 267 }; 268 269 /** 270 * Hide 271 */ 272 EasyZoom.prototype.hide = function() { 273 if (!this.isOpen) return; 274 if (this.opts.beforeHide.call(this) === false) return; 275 276 this.$flyout.detach(); 277 this.isOpen = false; 278 279 this.opts.onHide.call(this); 280 }; 281 282 /** 283 * Swap 284 * @param {String} standardSrc 285 * @param {String} zoomHref 286 * @param {String|Array} srcset (Optional) 287 */ 288 EasyZoom.prototype.swap = function(standardSrc, zoomHref, srcset) { 289 this.hide(); 290 this.isReady = false; 291 292 this.detachNotice && clearTimeout(this.detachNotice); 293 294 this.$notice.parent().length && this.$notice.detach(); 295 296 this.$target.removeClass('is-loading is-ready is-error'); 297 298 this.$image.attr({ 299 src: standardSrc, 300 srcset: $.isArray(srcset) ? srcset.join() : srcset 301 }); 302 303 this.$link.attr(this.opts.linkAttribute, zoomHref); 304 }; 305 306 /** 307 * Teardown 308 */ 309 EasyZoom.prototype.teardown = function() { 310 this.hide(); 311 312 this.$target 313 .off('.easyzoom') 314 .removeClass('is-loading is-ready is-error'); 315 316 this.detachNotice && clearTimeout(this.detachNotice); 317 318 delete this.$link; 319 delete this.$zoom; 320 delete this.$image; 321 delete this.$notice; 322 delete this.$flyout; 323 324 delete this.isOpen; 325 delete this.isReady; 326 }; 327 328 // jQuery plugin wrapper 329 $.fn.easyZoom = function(options) { 330 return this.each(function() { 331 var api = $.data(this, 'easyZoom'); 332 333 if (!api) { 334 $.data(this, 'easyZoom', new EasyZoom(this, options)); 335 } else if (api.isOpen === undefined) { 336 api._init(); 337 } 338 }); 339 }; 340 341 return EasyZoom; 342}));
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.