1 |
|
2 | (function(global, factory) {
|
3 | typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = global || self,
|
4 | global.mediumZoom = factory());
|
5 | })(this, function() {
|
6 | "use strict";
|
7 | var _extends = Object.assign || function(target) {
|
8 | for (var i = 1; i < arguments.length; i++) {
|
9 | var source = arguments[i];
|
10 | for (var key in source) {
|
11 | if (Object.prototype.hasOwnProperty.call(source, key)) {
|
12 | target[key] = source[key];
|
13 | }
|
14 | }
|
15 | }
|
16 | return target;
|
17 | };
|
18 | var isSupported = function isSupported(node) {
|
19 | return node.tagName === "IMG";
|
20 | };
|
21 | var isNodeList = function isNodeList(selector) {
|
22 | return NodeList.prototype.isPrototypeOf(selector);
|
23 | };
|
24 | var isNode = function isNode(selector) {
|
25 | return selector && selector.nodeType === 1;
|
26 | };
|
27 | var isSvg = function isSvg(image) {
|
28 | var source = image.currentSrc || image.src;
|
29 | return source.substr(-4).toLowerCase() === ".svg";
|
30 | };
|
31 | var getImagesFromSelector = function getImagesFromSelector(selector) {
|
32 | try {
|
33 | if (Array.isArray(selector)) {
|
34 | return selector.filter(isSupported);
|
35 | }
|
36 | if (isNodeList(selector)) {
|
37 | return [].slice.call(selector).filter(isSupported);
|
38 | }
|
39 | if (isNode(selector)) {
|
40 | return [ selector ].filter(isSupported);
|
41 | }
|
42 | if (typeof selector === "string") {
|
43 | return [].slice.call(document.querySelectorAll(selector)).filter(isSupported);
|
44 | }
|
45 | return [];
|
46 | } catch (err) {
|
47 | throw new TypeError("The provided selector is invalid.\n" + "Expects a CSS selector, a Node element, a NodeList or an array.\n" + "See: https://github.com/francoischalifour/medium-zoom");
|
48 | }
|
49 | };
|
50 | var createOverlay = function createOverlay(background) {
|
51 | var overlay = document.createElement("div");
|
52 | overlay.classList.add("medium-zoom-overlay");
|
53 | overlay.style.background = background;
|
54 | return overlay;
|
55 | };
|
56 | var cloneTarget = function cloneTarget(template) {
|
57 | var _template$getBounding = template.getBoundingClientRect(), top = _template$getBounding.top, left = _template$getBounding.left, width = _template$getBounding.width, height = _template$getBounding.height;
|
58 | var clone = template.cloneNode();
|
59 | var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
|
60 | var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
|
61 | clone.removeAttribute("id");
|
62 | clone.style.position = "absolute";
|
63 | clone.style.top = top + scrollTop + "px";
|
64 | clone.style.left = left + scrollLeft + "px";
|
65 | clone.style.width = width + "px";
|
66 | clone.style.height = height + "px";
|
67 | clone.style.transform = "";
|
68 | return clone;
|
69 | };
|
70 | var createCustomEvent = function createCustomEvent(type, params) {
|
71 | var eventParams = _extends({
|
72 | bubbles: false,
|
73 | cancelable: false,
|
74 | detail: undefined
|
75 | }, params);
|
76 | if (typeof window.CustomEvent === "function") {
|
77 | return new CustomEvent(type, eventParams);
|
78 | }
|
79 | var customEvent = document.createEvent("CustomEvent");
|
80 | customEvent.initCustomEvent(type, eventParams.bubbles, eventParams.cancelable, eventParams.detail);
|
81 | return customEvent;
|
82 | };
|
83 | var mediumZoom = function mediumZoom(selector) {
|
84 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
85 | var Promise = window.Promise || function Promise(fn) {
|
86 | function noop() {}
|
87 | fn(noop, noop);
|
88 | };
|
89 | var _handleClick = function _handleClick(event) {
|
90 | var target = event.target;
|
91 | if (target === overlay) {
|
92 | close();
|
93 | return;
|
94 | }
|
95 | if (images.indexOf(target) === -1) {
|
96 | return;
|
97 | }
|
98 | toggle({
|
99 | target: target
|
100 | });
|
101 | };
|
102 | var _handleScroll = function _handleScroll() {
|
103 | if (isAnimating || !active.original) {
|
104 | return;
|
105 | }
|
106 | var currentScroll = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
|
107 | if (Math.abs(scrollTop - currentScroll) > zoomOptions.scrollOffset) {
|
108 | setTimeout(close, 150);
|
109 | }
|
110 | };
|
111 | var _handleKeyUp = function _handleKeyUp(event) {
|
112 | var key = event.key || event.keyCode;
|
113 | if (key === "Escape" || key === "Esc" || key === 27) {
|
114 | close();
|
115 | }
|
116 | };
|
117 | var update = function update() {
|
118 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
119 | var newOptions = options;
|
120 | if (options.background) {
|
121 | overlay.style.background = options.background;
|
122 | }
|
123 | if (options.container && options.container instanceof Object) {
|
124 | newOptions.container = _extends({}, zoomOptions.container, options.container);
|
125 | }
|
126 | if (options.template) {
|
127 | var template = isNode(options.template) ? options.template : document.querySelector(options.template);
|
128 | newOptions.template = template;
|
129 | }
|
130 | zoomOptions = _extends({}, zoomOptions, newOptions);
|
131 | images.forEach(function(image) {
|
132 | image.dispatchEvent(createCustomEvent("medium-zoom:update", {
|
133 | detail: {
|
134 | zoom: zoom
|
135 | }
|
136 | }));
|
137 | });
|
138 | return zoom;
|
139 | };
|
140 | var clone = function clone() {
|
141 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
142 | return mediumZoom(_extends({}, zoomOptions, options));
|
143 | };
|
144 | var attach = function attach() {
|
145 | for (var _len = arguments.length, selectors = Array(_len), _key = 0; _key < _len; _key++) {
|
146 | selectors[_key] = arguments[_key];
|
147 | }
|
148 | var newImages = selectors.reduce(function(imagesAccumulator, currentSelector) {
|
149 | return [].concat(imagesAccumulator, getImagesFromSelector(currentSelector));
|
150 | }, []);
|
151 | newImages.filter(function(newImage) {
|
152 | return images.indexOf(newImage) === -1;
|
153 | }).forEach(function(newImage) {
|
154 | images.push(newImage);
|
155 | newImage.classList.add("medium-zoom-image");
|
156 | });
|
157 | eventListeners.forEach(function(_ref) {
|
158 | var type = _ref.type, listener = _ref.listener, options = _ref.options;
|
159 | newImages.forEach(function(image) {
|
160 | image.addEventListener(type, listener, options);
|
161 | });
|
162 | });
|
163 | return zoom;
|
164 | };
|
165 | var detach = function detach() {
|
166 | for (var _len2 = arguments.length, selectors = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
167 | selectors[_key2] = arguments[_key2];
|
168 | }
|
169 | if (active.zoomed) {
|
170 | close();
|
171 | }
|
172 | var imagesToDetach = selectors.length > 0 ? selectors.reduce(function(imagesAccumulator, currentSelector) {
|
173 | return [].concat(imagesAccumulator, getImagesFromSelector(currentSelector));
|
174 | }, []) : images;
|
175 | imagesToDetach.forEach(function(image) {
|
176 | image.classList.remove("medium-zoom-image");
|
177 | image.dispatchEvent(createCustomEvent("medium-zoom:detach", {
|
178 | detail: {
|
179 | zoom: zoom
|
180 | }
|
181 | }));
|
182 | });
|
183 | images = images.filter(function(image) {
|
184 | return imagesToDetach.indexOf(image) === -1;
|
185 | });
|
186 | return zoom;
|
187 | };
|
188 | var on = function on(type, listener) {
|
189 | var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
190 | images.forEach(function(image) {
|
191 | image.addEventListener("medium-zoom:" + type, listener, options);
|
192 | });
|
193 | eventListeners.push({
|
194 | type: "medium-zoom:" + type,
|
195 | listener: listener,
|
196 | options: options
|
197 | });
|
198 | return zoom;
|
199 | };
|
200 | var off = function off(type, listener) {
|
201 | var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
202 | images.forEach(function(image) {
|
203 | image.removeEventListener("medium-zoom:" + type, listener, options);
|
204 | });
|
205 | eventListeners = eventListeners.filter(function(eventListener) {
|
206 | return !(eventListener.type === "medium-zoom:" + type && eventListener.listener.toString() === listener.toString());
|
207 | });
|
208 | return zoom;
|
209 | };
|
210 | var open = function open() {
|
211 | var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, target = _ref2.target;
|
212 | var _animate = function _animate() {
|
213 | var container = {
|
214 | width: document.documentElement.clientWidth,
|
215 | height: document.documentElement.clientHeight,
|
216 | left: 0,
|
217 | top: 0,
|
218 | right: 0,
|
219 | bottom: 0
|
220 | };
|
221 | var viewportWidth = void 0;
|
222 | var viewportHeight = void 0;
|
223 | if (zoomOptions.container) {
|
224 | if (zoomOptions.container instanceof Object) {
|
225 | container = _extends({}, container, zoomOptions.container);
|
226 | viewportWidth = container.width - container.left - container.right - zoomOptions.margin * 2;
|
227 | viewportHeight = container.height - container.top - container.bottom - zoomOptions.margin * 2;
|
228 | } else {
|
229 | var zoomContainer = isNode(zoomOptions.container) ? zoomOptions.container : document.querySelector(zoomOptions.container);
|
230 | var _zoomContainer$getBou = zoomContainer.getBoundingClientRect(), _width = _zoomContainer$getBou.width, _height = _zoomContainer$getBou.height, _left = _zoomContainer$getBou.left, _top = _zoomContainer$getBou.top;
|
231 | container = _extends({}, container, {
|
232 | width: _width,
|
233 | height: _height,
|
234 | left: _left,
|
235 | top: _top
|
236 | });
|
237 | }
|
238 | }
|
239 | viewportWidth = viewportWidth || container.width - zoomOptions.margin * 2;
|
240 | viewportHeight = viewportHeight || container.height - zoomOptions.margin * 2;
|
241 | var zoomTarget = active.zoomedHd || active.original;
|
242 | var naturalWidth = isSvg(zoomTarget) ? viewportWidth : zoomTarget.naturalWidth || viewportWidth;
|
243 | var naturalHeight = isSvg(zoomTarget) ? viewportHeight : zoomTarget.naturalHeight || viewportHeight;
|
244 | var _zoomTarget$getBoundi = zoomTarget.getBoundingClientRect(), top = _zoomTarget$getBoundi.top, left = _zoomTarget$getBoundi.left, width = _zoomTarget$getBoundi.width, height = _zoomTarget$getBoundi.height;
|
245 | var scaleX = Math.min(naturalWidth, viewportWidth) / width;
|
246 | var scaleY = Math.min(naturalHeight, viewportHeight) / height;
|
247 | var scale = Math.min(scaleX, scaleY);
|
248 | var translateX = (-left + (viewportWidth - width) / 2 + zoomOptions.margin + container.left) / scale;
|
249 | var translateY = (-top + (viewportHeight - height) / 2 + zoomOptions.margin + container.top) / scale;
|
250 | var transform = "scale(" + scale + ") translate3d(" + translateX + "px, " + translateY + "px, 0)";
|
251 | active.zoomed.style.transform = transform;
|
252 | if (active.zoomedHd) {
|
253 | active.zoomedHd.style.transform = transform;
|
254 | }
|
255 | };
|
256 | return new Promise(function(resolve) {
|
257 | if (target && images.indexOf(target) === -1) {
|
258 | resolve(zoom);
|
259 | return;
|
260 | }
|
261 | var _handleOpenEnd = function _handleOpenEnd() {
|
262 | isAnimating = false;
|
263 | active.zoomed.removeEventListener("transitionend", _handleOpenEnd);
|
264 | active.original.dispatchEvent(createCustomEvent("medium-zoom:opened", {
|
265 | detail: {
|
266 | zoom: zoom
|
267 | }
|
268 | }));
|
269 | resolve(zoom);
|
270 | };
|
271 | if (active.zoomed) {
|
272 | resolve(zoom);
|
273 | return;
|
274 | }
|
275 | if (target) {
|
276 | active.original = target;
|
277 | } else if (images.length > 0) {
|
278 | var _images = images;
|
279 | active.original = _images[0];
|
280 | } else {
|
281 | resolve(zoom);
|
282 | return;
|
283 | }
|
284 | active.original.dispatchEvent(createCustomEvent("medium-zoom:open", {
|
285 | detail: {
|
286 | zoom: zoom
|
287 | }
|
288 | }));
|
289 | scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
|
290 | isAnimating = true;
|
291 | active.zoomed = cloneTarget(active.original);
|
292 | document.body.appendChild(overlay);
|
293 | if (zoomOptions.template) {
|
294 | var template = isNode(zoomOptions.template) ? zoomOptions.template : document.querySelector(zoomOptions.template);
|
295 | active.template = document.createElement("div");
|
296 | active.template.appendChild(template.content.cloneNode(true));
|
297 | document.body.appendChild(active.template);
|
298 | }
|
299 | document.body.appendChild(active.zoomed);
|
300 | window.requestAnimationFrame(function() {
|
301 | document.body.classList.add("medium-zoom--opened");
|
302 | });
|
303 | active.original.classList.add("medium-zoom-image--hidden");
|
304 | active.zoomed.classList.add("medium-zoom-image--opened");
|
305 | active.zoomed.addEventListener("click", close);
|
306 | active.zoomed.addEventListener("transitionend", _handleOpenEnd);
|
307 | if (active.original.getAttribute("data-zoom-src")) {
|
308 | active.zoomedHd = active.zoomed.cloneNode();
|
309 | active.zoomedHd.removeAttribute("srcset");
|
310 | active.zoomedHd.removeAttribute("sizes");
|
311 | active.zoomedHd.src = active.zoomed.getAttribute("data-zoom-src");
|
312 | active.zoomedHd.onerror = function() {
|
313 | clearInterval(getZoomTargetSize);
|
314 | console.warn("Unable to reach the zoom image target " + active.zoomedHd.src);
|
315 | active.zoomedHd = null;
|
316 | _animate();
|
317 | };
|
318 | var getZoomTargetSize = setInterval(function() {
|
319 | if (active.zoomedHd.complete) {
|
320 | clearInterval(getZoomTargetSize);
|
321 | active.zoomedHd.classList.add("medium-zoom-image--opened");
|
322 | active.zoomedHd.addEventListener("click", close);
|
323 | document.body.appendChild(active.zoomedHd);
|
324 | _animate();
|
325 | }
|
326 | }, 10);
|
327 | } else if (active.original.hasAttribute("srcset")) {
|
328 | active.zoomedHd = active.zoomed.cloneNode();
|
329 | active.zoomedHd.removeAttribute("sizes");
|
330 | active.zoomedHd.removeAttribute("loading");
|
331 | var loadEventListener = active.zoomedHd.addEventListener("load", function() {
|
332 | active.zoomedHd.removeEventListener("load", loadEventListener);
|
333 | active.zoomedHd.classList.add("medium-zoom-image--opened");
|
334 | active.zoomedHd.addEventListener("click", close);
|
335 | document.body.appendChild(active.zoomedHd);
|
336 | _animate();
|
337 | });
|
338 | } else {
|
339 | _animate();
|
340 | }
|
341 | });
|
342 | };
|
343 | var close = function close() {
|
344 | return new Promise(function(resolve) {
|
345 | if (isAnimating || !active.original) {
|
346 | resolve(zoom);
|
347 | return;
|
348 | }
|
349 | var _handleCloseEnd = function _handleCloseEnd() {
|
350 | active.original.classList.remove("medium-zoom-image--hidden");
|
351 | document.body.removeChild(active.zoomed);
|
352 | if (active.zoomedHd) {
|
353 | document.body.removeChild(active.zoomedHd);
|
354 | }
|
355 | document.body.removeChild(overlay);
|
356 | active.zoomed.classList.remove("medium-zoom-image--opened");
|
357 | if (active.template) {
|
358 | document.body.removeChild(active.template);
|
359 | }
|
360 | isAnimating = false;
|
361 | active.zoomed.removeEventListener("transitionend", _handleCloseEnd);
|
362 | active.original.dispatchEvent(createCustomEvent("medium-zoom:closed", {
|
363 | detail: {
|
364 | zoom: zoom
|
365 | }
|
366 | }));
|
367 | active.original = null;
|
368 | active.zoomed = null;
|
369 | active.zoomedHd = null;
|
370 | active.template = null;
|
371 | resolve(zoom);
|
372 | };
|
373 | isAnimating = true;
|
374 | document.body.classList.remove("medium-zoom--opened");
|
375 | active.zoomed.style.transform = "";
|
376 | if (active.zoomedHd) {
|
377 | active.zoomedHd.style.transform = "";
|
378 | }
|
379 | if (active.template) {
|
380 | active.template.style.transition = "opacity 150ms";
|
381 | active.template.style.opacity = 0;
|
382 | }
|
383 | active.original.dispatchEvent(createCustomEvent("medium-zoom:close", {
|
384 | detail: {
|
385 | zoom: zoom
|
386 | }
|
387 | }));
|
388 | active.zoomed.addEventListener("transitionend", _handleCloseEnd);
|
389 | });
|
390 | };
|
391 | var toggle = function toggle() {
|
392 | var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, target = _ref3.target;
|
393 | if (active.original) {
|
394 | return close();
|
395 | }
|
396 | return open({
|
397 | target: target
|
398 | });
|
399 | };
|
400 | var getOptions = function getOptions() {
|
401 | return zoomOptions;
|
402 | };
|
403 | var getImages = function getImages() {
|
404 | return images;
|
405 | };
|
406 | var getZoomedImage = function getZoomedImage() {
|
407 | return active.original;
|
408 | };
|
409 | var images = [];
|
410 | var eventListeners = [];
|
411 | var isAnimating = false;
|
412 | var scrollTop = 0;
|
413 | var zoomOptions = options;
|
414 | var active = {
|
415 | original: null,
|
416 | zoomed: null,
|
417 | zoomedHd: null,
|
418 | template: null
|
419 | };
|
420 | if (Object.prototype.toString.call(selector) === "[object Object]") {
|
421 | zoomOptions = selector;
|
422 | } else if (selector || typeof selector === "string") {
|
423 | attach(selector);
|
424 | }
|
425 | zoomOptions = _extends({
|
426 | margin: 0,
|
427 | background: "#fff",
|
428 | scrollOffset: 40,
|
429 | container: null,
|
430 | template: null
|
431 | }, zoomOptions);
|
432 | var overlay = createOverlay(zoomOptions.background);
|
433 | document.addEventListener("click", _handleClick);
|
434 | document.addEventListener("keyup", _handleKeyUp);
|
435 | document.addEventListener("scroll", _handleScroll);
|
436 | window.addEventListener("resize", close);
|
437 | var zoom = {
|
438 | open: open,
|
439 | close: close,
|
440 | toggle: toggle,
|
441 | update: update,
|
442 | clone: clone,
|
443 | attach: attach,
|
444 | detach: detach,
|
445 | on: on,
|
446 | off: off,
|
447 | getOptions: getOptions,
|
448 | getImages: getImages,
|
449 | getZoomedImage: getZoomedImage
|
450 | };
|
451 | return zoom;
|
452 | };
|
453 | function styleInject(css, ref) {
|
454 | if (ref === void 0) ref = {};
|
455 | var insertAt = ref.insertAt;
|
456 | if (!css || typeof document === "undefined") {
|
457 | return;
|
458 | }
|
459 | var head = document.head || document.getElementsByTagName("head")[0];
|
460 | var style = document.createElement("style");
|
461 | style.type = "text/css";
|
462 | if (insertAt === "top") {
|
463 | if (head.firstChild) {
|
464 | head.insertBefore(style, head.firstChild);
|
465 | } else {
|
466 | head.appendChild(style);
|
467 | }
|
468 | } else {
|
469 | head.appendChild(style);
|
470 | }
|
471 | if (style.styleSheet) {
|
472 | style.styleSheet.cssText = css;
|
473 | } else {
|
474 | style.appendChild(document.createTextNode(css));
|
475 | }
|
476 | }
|
477 | var css = ".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}";
|
478 | styleInject(css);
|
479 | return mediumZoom;
|
480 | });
|