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