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