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