sigal 2.3__py3-none-any.whl → 2.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. sigal/__init__.py +2 -285
  2. sigal/__main__.py +312 -0
  3. sigal/gallery.py +188 -158
  4. sigal/image.py +113 -115
  5. sigal/log.py +11 -11
  6. sigal/plugins/adjust.py +4 -4
  7. sigal/plugins/compress_assets.py +26 -25
  8. sigal/plugins/copyright.py +8 -8
  9. sigal/plugins/encrypt/encrypt.py +7 -7
  10. sigal/plugins/encrypt/endec.py +2 -2
  11. sigal/plugins/extended_caching.py +26 -22
  12. sigal/plugins/feeds.py +19 -21
  13. sigal/plugins/media_page.py +1 -1
  14. sigal/plugins/nomedia.py +1 -1
  15. sigal/plugins/nonmedia_files.py +59 -93
  16. sigal/plugins/titleregexp.py +98 -0
  17. sigal/plugins/watermark.py +13 -13
  18. sigal/plugins/zip_gallery.py +17 -8
  19. sigal/settings.py +92 -78
  20. sigal/signals.py +10 -10
  21. sigal/templates/sigal.conf.py +18 -14
  22. sigal/themes/default/templates/decrypt.html +1 -0
  23. sigal/themes/default/templates/description.html +29 -0
  24. sigal/themes/default/templates/footer.html +3 -0
  25. sigal/themes/galleria/templates/album_items.html +4 -23
  26. sigal/themes/photoswipe/static/photoswipe-dynamic-caption-plugin.esm.js +414 -0
  27. sigal/themes/photoswipe/static/photoswipe-dynamic-caption-plugin.esm.min.js +5 -0
  28. sigal/themes/photoswipe/static/photoswipe-fullscreen.esm.js +129 -0
  29. sigal/themes/photoswipe/static/photoswipe-fullscreen.esm.min.js +8 -0
  30. sigal/themes/photoswipe/static/photoswipe-lightbox.esm.js +1960 -0
  31. sigal/themes/photoswipe/static/photoswipe-lightbox.esm.js.map +1 -0
  32. sigal/themes/photoswipe/static/photoswipe-lightbox.esm.min.js +5 -0
  33. sigal/themes/photoswipe/static/photoswipe-video-plugin.esm.js +257 -0
  34. sigal/themes/photoswipe/static/photoswipe-video-plugin.esm.min.js +1 -0
  35. sigal/themes/photoswipe/static/photoswipe.css +385 -140
  36. sigal/themes/photoswipe/static/photoswipe.esm.js +7081 -0
  37. sigal/themes/photoswipe/static/photoswipe.esm.js.map +1 -0
  38. sigal/themes/photoswipe/static/photoswipe.esm.min.js +5 -0
  39. sigal/themes/photoswipe/static/styles.css +53 -0
  40. sigal/themes/photoswipe/templates/album.html +69 -74
  41. sigal/utils.py +80 -12
  42. sigal/version.py +20 -4
  43. sigal/video.py +43 -24
  44. sigal/writer.py +26 -8
  45. {sigal-2.3.dist-info → sigal-2.5.dist-info}/LICENSE +1 -1
  46. {sigal-2.3.dist-info → sigal-2.5.dist-info}/METADATA +23 -30
  47. {sigal-2.3.dist-info → sigal-2.5.dist-info}/RECORD +50 -50
  48. {sigal-2.3.dist-info → sigal-2.5.dist-info}/WHEEL +1 -1
  49. sigal-2.5.dist-info/entry_points.txt +2 -0
  50. sigal/plugins/upload_s3.py +0 -106
  51. sigal/themes/photoswipe/static/app.js +0 -214
  52. sigal/themes/photoswipe/static/default-skin/default-skin.css +0 -485
  53. sigal/themes/photoswipe/static/default-skin/default-skin.css.map +0 -10
  54. sigal/themes/photoswipe/static/default-skin/default-skin.png +0 -0
  55. sigal/themes/photoswipe/static/default-skin/default-skin.svg +0 -36
  56. sigal/themes/photoswipe/static/default-skin/preloader.gif +0 -0
  57. sigal/themes/photoswipe/static/echo/blank.gif +0 -0
  58. sigal/themes/photoswipe/static/echo/echo.js +0 -135
  59. sigal/themes/photoswipe/static/echo/echo.min.js +0 -2
  60. sigal/themes/photoswipe/static/photoswipe-ui-default.js +0 -871
  61. sigal/themes/photoswipe/static/photoswipe-ui-default.min.js +0 -1
  62. sigal/themes/photoswipe/static/photoswipe.css.map +0 -10
  63. sigal/themes/photoswipe/static/photoswipe.js +0 -3592
  64. sigal/themes/photoswipe/static/photoswipe.min.js +0 -1
  65. sigal-2.3.dist-info/entry_points.txt +0 -2
  66. {sigal-2.3.dist-info → sigal-2.5.dist-info}/top_level.txt +0 -0
@@ -1,3592 +0,0 @@
1
- /*!
2
- * PhotoSwipe - v4.4.0 - 2020-12-06
3
- * http://photoswipe.com
4
- * Copyright (c) 2020 Dmitry Semenov;
5
- */
6
-
7
- (function (root, factory) {
8
- if (root === undefined && window !== undefined) {
9
- root = window;
10
- }
11
- if (typeof define === 'function' && define.amd) {
12
- define(factory);
13
- } else if (typeof exports === 'object') {
14
- module.exports = factory();
15
- } else {
16
- root.PhotoSwipe = factory();
17
- }
18
- })(this, function () {
19
-
20
- 'use strict';
21
- var PhotoSwipe = function(template, UiClass, items, options){
22
-
23
- /*>>framework-bridge*/
24
- /**
25
- *
26
- * Set of generic functions used by gallery.
27
- *
28
- * You're free to modify anything here as long as functionality is kept.
29
- *
30
- */
31
- var framework = {
32
- features: null,
33
- bind: function (target, type, listener, unbind) {
34
- var methodName = (unbind ? 'remove' : 'add') + 'EventListener';
35
- type = type.split(' ');
36
- for (var i = 0; i < type.length; i++) {
37
- if (type[i]) {
38
- target[methodName](type[i], listener, false);
39
- }
40
- }
41
- },
42
- isArray: function (obj) {
43
- return obj instanceof Array;
44
- },
45
- createEl: function (classes, tag) {
46
- var el = document.createElement(tag || 'div');
47
- if (classes) {
48
- el.className = classes;
49
- }
50
- return el;
51
- },
52
- resetEl: function (el) {
53
- while (el.firstChild) {
54
- el.removeChild(el.firstChild);
55
- }
56
- },
57
- getScrollY: function () {
58
- var yOffset = window.pageYOffset;
59
- return yOffset !== undefined ? yOffset : document.documentElement.scrollTop;
60
- },
61
- unbind: function (target, type, listener) {
62
- framework.bind(target, type, listener, true);
63
- },
64
- removeClass: function (el, className) {
65
- var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
66
- el.className = el.className
67
- .replace(reg, ' ')
68
- .replace(/^\s\s*/, '')
69
- .replace(/\s\s*$/, '');
70
- },
71
- addClass: function (el, className) {
72
- if (!framework.hasClass(el, className)) {
73
- el.className += (el.className ? ' ' : '') + className;
74
- }
75
- },
76
- hasClass: function (el, className) {
77
- return el.className && new RegExp('(^|\\s)' + className + '(\\s|$)').test(el.className);
78
- },
79
- getChildByClass: function (parentEl, childClassName) {
80
- var node = parentEl.firstChild;
81
- while (node) {
82
- if (framework.hasClass(node, childClassName)) {
83
- return node;
84
- }
85
- node = node.nextSibling;
86
- }
87
- },
88
- arraySearch: function (array, value, key) {
89
- var i = array.length;
90
- while (i--) {
91
- if (array[i][key] === value) {
92
- return i;
93
- }
94
- }
95
- return -1;
96
- },
97
- extend: function (o1, o2, preventOverwrite) {
98
- for (var prop in o2) {
99
- if (o2.hasOwnProperty(prop)) {
100
- if (preventOverwrite && o1.hasOwnProperty(prop)) {
101
- continue;
102
- }
103
- o1[prop] = o2[prop];
104
- }
105
- }
106
- },
107
- easing: {
108
- sine: {
109
- out: function (k) {
110
- return Math.sin(k * (Math.PI / 2));
111
- },
112
- inOut: function (k) {
113
- return -(Math.cos(Math.PI * k) - 1) / 2;
114
- }
115
- },
116
- cubic: {
117
- out: function (k) {
118
- return --k * k * k + 1;
119
- }
120
- }
121
- /*
122
- elastic: {
123
- out: function ( k ) {
124
-
125
- var s, a = 0.1, p = 0.4;
126
- if ( k === 0 ) return 0;
127
- if ( k === 1 ) return 1;
128
- if ( !a || a < 1 ) { a = 1; s = p / 4; }
129
- else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
130
- return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
131
-
132
- },
133
- },
134
- back: {
135
- out: function ( k ) {
136
- var s = 1.70158;
137
- return --k * k * ( ( s + 1 ) * k + s ) + 1;
138
- }
139
- }
140
- */
141
- },
142
-
143
- /**
144
- *
145
- * @return {object}
146
- *
147
- * {
148
- * raf : request animation frame function
149
- * caf : cancel animation frame function
150
- * transfrom : transform property key (with vendor), or null if not supported
151
- * oldIE : IE8 or below
152
- * }
153
- *
154
- */
155
- detectFeatures: function () {
156
- if (framework.features) {
157
- return framework.features;
158
- }
159
- var helperEl = framework.createEl(),
160
- helperStyle = helperEl.style,
161
- vendor = '',
162
- features = {};
163
-
164
- // IE8 and below
165
- features.oldIE = document.all && !document.addEventListener;
166
-
167
- features.touch = 'ontouchstart' in window;
168
-
169
- if (window.requestAnimationFrame) {
170
- features.raf = window.requestAnimationFrame;
171
- features.caf = window.cancelAnimationFrame;
172
- }
173
-
174
- features.pointerEvent = !!window.PointerEvent || navigator.msPointerEnabled;
175
-
176
- // fix false-positive detection of old Android in new IE
177
- // (IE11 ua string contains "Android 4.0")
178
-
179
- if (!features.pointerEvent) {
180
- var ua = navigator.userAgent;
181
-
182
- // Detect if device is iPhone or iPod and if it's older than iOS 8
183
- // http://stackoverflow.com/a/14223920
184
- //
185
- // This detection is made because of buggy top/bottom toolbars
186
- // that don't trigger window.resize event.
187
- // For more info refer to _isFixedPosition variable in core.js
188
-
189
- if (/iP(hone|od)/.test(navigator.platform)) {
190
- var v = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
191
- if (v && v.length > 0) {
192
- v = parseInt(v[1], 10);
193
- if (v >= 1 && v < 8) {
194
- features.isOldIOSPhone = true;
195
- }
196
- }
197
- }
198
-
199
- // Detect old Android (before KitKat)
200
- // due to bugs related to position:fixed
201
- // http://stackoverflow.com/questions/7184573/pick-up-the-android-version-in-the-browser-by-javascript
202
-
203
- var match = ua.match(/Android\s([0-9\.]*)/);
204
- var androidversion = match ? match[1] : 0;
205
- androidversion = parseFloat(androidversion);
206
- if (androidversion >= 1) {
207
- if (androidversion < 4.4) {
208
- features.isOldAndroid = true; // for fixed position bug & performance
209
- }
210
- features.androidVersion = androidversion; // for touchend bug
211
- }
212
- features.isMobileOpera = /opera mini|opera mobi/i.test(ua);
213
-
214
- // p.s. yes, yes, UA sniffing is bad, propose your solution for above bugs.
215
- }
216
-
217
- var styleChecks = ['transform', 'perspective', 'animationName'],
218
- vendors = ['', 'webkit', 'Moz', 'ms', 'O'],
219
- styleCheckItem,
220
- styleName;
221
-
222
- for (var i = 0; i < 4; i++) {
223
- vendor = vendors[i];
224
-
225
- for (var a = 0; a < 3; a++) {
226
- styleCheckItem = styleChecks[a];
227
-
228
- // uppercase first letter of property name, if vendor is present
229
- styleName = vendor + (vendor ? styleCheckItem.charAt(0).toUpperCase() + styleCheckItem.slice(1) : styleCheckItem);
230
-
231
- if (!features[styleCheckItem] && styleName in helperStyle) {
232
- features[styleCheckItem] = styleName;
233
- }
234
- }
235
-
236
- if (vendor && !features.raf) {
237
- vendor = vendor.toLowerCase();
238
- features.raf = window[vendor + 'RequestAnimationFrame'];
239
- if (features.raf) {
240
- features.caf = window[vendor + 'CancelAnimationFrame'] || window[vendor + 'CancelRequestAnimationFrame'];
241
- }
242
- }
243
- }
244
-
245
- if (!features.raf) {
246
- var lastTime = 0;
247
- features.raf = function (fn) {
248
- var currTime = new Date().getTime();
249
- var timeToCall = Math.max(0, 16 - (currTime - lastTime));
250
- var id = window.setTimeout(function () {
251
- fn(currTime + timeToCall);
252
- }, timeToCall);
253
- lastTime = currTime + timeToCall;
254
- return id;
255
- };
256
- features.caf = function (id) {
257
- clearTimeout(id);
258
- };
259
- }
260
-
261
- // Detect SVG support
262
- features.svg = !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;
263
-
264
- framework.features = features;
265
-
266
- return features;
267
- }
268
- };
269
-
270
- framework.detectFeatures();
271
-
272
- // Override addEventListener for old versions of IE
273
- if (framework.features.oldIE) {
274
- framework.bind = function (target, type, listener, unbind) {
275
- type = type.split(' ');
276
-
277
- var methodName = (unbind ? 'detach' : 'attach') + 'Event',
278
- evName,
279
- _handleEv = function () {
280
- listener.handleEvent.call(listener);
281
- };
282
-
283
- for (var i = 0; i < type.length; i++) {
284
- evName = type[i];
285
- if (evName) {
286
- if (typeof listener === 'object' && listener.handleEvent) {
287
- if (!unbind) {
288
- listener['oldIE' + evName] = _handleEv;
289
- } else {
290
- if (!listener['oldIE' + evName]) {
291
- return false;
292
- }
293
- }
294
-
295
- target[methodName]('on' + evName, listener['oldIE' + evName]);
296
- } else {
297
- target[methodName]('on' + evName, listener);
298
- }
299
- }
300
- }
301
- };
302
- }
303
-
304
-
305
- /*>>framework-bridge*/
306
-
307
- /*>>core*/
308
- //function(template, UiClass, items, options)
309
-
310
- var self = this;
311
-
312
- /**
313
- * Static vars, don't change unless you know what you're doing.
314
- */
315
- var DOUBLE_TAP_RADIUS = 25,
316
- NUM_HOLDERS = 3;
317
-
318
- /**
319
- * Options
320
- */
321
- var _options = {
322
- allowPanToNext: true,
323
- preventSwiping: false,
324
- spacing: 0.12,
325
- bgOpacity: 1,
326
- mouseUsed: false,
327
- loop: true,
328
- pinchToClose: true,
329
- closeOnScroll: true,
330
- closeOnVerticalDrag: true,
331
- verticalDragRange: 0.75,
332
- hideAnimationDuration: 333,
333
- showAnimationDuration: 333,
334
- showHideOpacity: false,
335
- focus: true,
336
- escKey: true,
337
- arrowKeys: true,
338
- mainScrollEndFriction: 0.35,
339
- panEndFriction: 0.35,
340
- animateTransitions: false,
341
- isClickableElement: function (el) {
342
- return el.tagName === 'A';
343
- },
344
- getDoubleTapZoom: function (isMouseClick, item) {
345
- if (isMouseClick) {
346
- return 1;
347
- } else {
348
- return item.initialZoomLevel < 0.7 ? 1 : 1.33;
349
- }
350
- },
351
- maxSpreadZoom: 1.33,
352
- modal: true,
353
-
354
- // not fully implemented yet
355
- scaleMode: 'fit' // TODO
356
- };
357
- framework.extend(_options, options);
358
-
359
- /**
360
- * Private helper variables & functions
361
- */
362
-
363
- var _getEmptyPoint = function () {
364
- return {x: 0, y: 0};
365
- };
366
-
367
- var _isOpen,
368
- _isDestroying,
369
- _closedByScroll,
370
- _currentItemIndex,
371
- _containerStyle,
372
- _containerShiftIndex,
373
- _currPanDist = _getEmptyPoint(),
374
- _startPanOffset = _getEmptyPoint(),
375
- _panOffset = _getEmptyPoint(),
376
- _upMoveEvents, // drag move, drag end & drag cancel events array
377
- _downEvents, // drag start events array
378
- _globalEventHandlers,
379
- _viewportSize = {},
380
- _currZoomLevel,
381
- _startZoomLevel,
382
- _translatePrefix,
383
- _translateSufix,
384
- _updateSizeInterval,
385
- _itemsNeedUpdate,
386
- _currPositionIndex = 0,
387
- _offset = {},
388
- _slideSize = _getEmptyPoint(), // size of slide area, including spacing
389
- _itemHolders,
390
- _prevItemIndex,
391
- _indexDiff = 0, // difference of indexes since last content update
392
- _dragStartEvent,
393
- _dragMoveEvent,
394
- _dragEndEvent,
395
- _dragCancelEvent,
396
- _transformKey,
397
- _pointerEventEnabled,
398
- _isFixedPosition = true,
399
- _likelyTouchDevice,
400
- _modules = [],
401
- _requestAF,
402
- _cancelAF,
403
- _initalClassName,
404
- _initalWindowScrollY,
405
- _oldIE,
406
- _currentWindowScrollY,
407
- _features,
408
- _windowVisibleSize = {},
409
- _renderMaxResolution = false,
410
- _orientationChangeTimeout,
411
- // Registers PhotoSWipe module (History, Controller ...)
412
- _registerModule = function (name, module) {
413
- framework.extend(self, module.publicMethods);
414
- _modules.push(name);
415
- },
416
- _getLoopedId = function (index) {
417
- var numSlides = _getNumItems();
418
- if (index > numSlides - 1) {
419
- return index - numSlides;
420
- } else if (index < 0) {
421
- return numSlides + index;
422
- }
423
- return index;
424
- },
425
- // Micro bind/trigger
426
- _listeners = {},
427
- _listen = function (name, fn) {
428
- if (!_listeners[name]) {
429
- _listeners[name] = [];
430
- }
431
- return _listeners[name].push(fn);
432
- },
433
- _shout = function (name) {
434
- var listeners = _listeners[name];
435
-
436
- if (listeners) {
437
- var args = Array.prototype.slice.call(arguments);
438
- args.shift();
439
-
440
- for (var i = 0; i < listeners.length; i++) {
441
- listeners[i].apply(self, args);
442
- }
443
- }
444
- },
445
- _getCurrentTime = function () {
446
- return new Date().getTime();
447
- },
448
- _applyBgOpacity = function (opacity) {
449
- _bgOpacity = opacity;
450
- self.bg.style.opacity = opacity * _options.bgOpacity;
451
- },
452
- _applyZoomTransform = function (styleObj, x, y, zoom, item) {
453
- if (!_renderMaxResolution || (item && item !== self.currItem)) {
454
- zoom = zoom / (item ? item.fitRatio : self.currItem.fitRatio);
455
- }
456
-
457
- styleObj[_transformKey] = _translatePrefix + x + 'px, ' + y + 'px' + _translateSufix + ' scale(' + zoom + ')';
458
- },
459
- _applyCurrentZoomPan = function (allowRenderResolution) {
460
- if (_currZoomElementStyle && !self.currItem.loadError) {
461
- if (allowRenderResolution) {
462
- if (_currZoomLevel > self.currItem.fitRatio) {
463
- if (!_renderMaxResolution) {
464
- _setImageSize(self.currItem, false, true);
465
- _renderMaxResolution = true;
466
- }
467
- } else {
468
- if (_renderMaxResolution) {
469
- _setImageSize(self.currItem);
470
- _renderMaxResolution = false;
471
- }
472
- }
473
- }
474
-
475
- _applyZoomTransform(_currZoomElementStyle, _panOffset.x, _panOffset.y, _currZoomLevel);
476
- }
477
- },
478
- _applyZoomPanToItem = function (item) {
479
- if (item.container) {
480
- _applyZoomTransform(item.container.style, item.initialPosition.x, item.initialPosition.y, item.initialZoomLevel, item);
481
- }
482
- },
483
- _setTranslateX = function (x, elStyle) {
484
- elStyle[_transformKey] = _translatePrefix + x + 'px, 0px' + _translateSufix;
485
- },
486
- _moveMainScroll = function (x, dragging) {
487
- if (!_options.loop && dragging) {
488
- var newSlideIndexOffset = _currentItemIndex + (_slideSize.x * _currPositionIndex - x) / _slideSize.x,
489
- delta = Math.round(x - _mainScrollPos.x);
490
-
491
- if ((newSlideIndexOffset < 0 && delta > 0) || (newSlideIndexOffset >= _getNumItems() - 1 && delta < 0)) {
492
- x = _mainScrollPos.x + delta * _options.mainScrollEndFriction;
493
- }
494
- }
495
-
496
- _mainScrollPos.x = x;
497
- _setTranslateX(x, _containerStyle);
498
- },
499
- _calculatePanOffset = function (axis, zoomLevel) {
500
- var m = _midZoomPoint[axis] - _offset[axis];
501
- return _startPanOffset[axis] + _currPanDist[axis] + m - m * (zoomLevel / _startZoomLevel);
502
- },
503
- _equalizePoints = function (p1, p2) {
504
- p1.x = p2.x;
505
- p1.y = p2.y;
506
- if (p2.id) {
507
- p1.id = p2.id;
508
- }
509
- },
510
- _roundPoint = function (p) {
511
- p.x = Math.round(p.x);
512
- p.y = Math.round(p.y);
513
- },
514
- _mouseMoveTimeout = null,
515
- _onFirstMouseMove = function () {
516
- // Wait until mouse move event is fired at least twice during 100ms
517
- // We do this, because some mobile browsers trigger it on touchstart
518
- if (_mouseMoveTimeout) {
519
- framework.unbind(document, 'mousemove', _onFirstMouseMove);
520
- framework.addClass(template, 'pswp--has_mouse');
521
- _options.mouseUsed = true;
522
- _shout('mouseUsed');
523
- }
524
- _mouseMoveTimeout = setTimeout(function () {
525
- _mouseMoveTimeout = null;
526
- }, 100);
527
- },
528
- _bindEvents = function () {
529
- framework.bind(document, 'keydown', self);
530
-
531
- if (_features.transform) {
532
- // don't bind click event in browsers that don't support transform (mostly IE8)
533
- framework.bind(self.scrollWrap, 'click', self);
534
- }
535
-
536
- if (!_options.mouseUsed) {
537
- framework.bind(document, 'mousemove', _onFirstMouseMove);
538
- }
539
-
540
- framework.bind(window, 'resize scroll orientationchange', self);
541
-
542
- _shout('bindEvents');
543
- },
544
- _unbindEvents = function () {
545
- setTimeout(function () {
546
- framework.unbind(window, 'resize scroll orientationchange', self);
547
- }, 400);
548
- framework.unbind(window, 'scroll', _globalEventHandlers.scroll);
549
- framework.unbind(document, 'keydown', self);
550
- framework.unbind(document, 'mousemove', _onFirstMouseMove);
551
-
552
- if (_features.transform) {
553
- framework.unbind(self.scrollWrap, 'click', self);
554
- }
555
-
556
- if (_isDragging) {
557
- framework.unbind(window, _upMoveEvents, self);
558
- }
559
-
560
- clearTimeout(_orientationChangeTimeout);
561
-
562
- _shout('unbindEvents');
563
- },
564
- _calculatePanBounds = function (zoomLevel, update) {
565
- var bounds = _calculateItemSize(self.currItem, _viewportSize, zoomLevel);
566
- if (update) {
567
- _currPanBounds = bounds;
568
- }
569
- return bounds;
570
- },
571
- _getMinZoomLevel = function (item) {
572
- if (!item) {
573
- item = self.currItem;
574
- }
575
- return item.initialZoomLevel;
576
- },
577
- _getMaxZoomLevel = function (item) {
578
- if (!item) {
579
- item = self.currItem;
580
- }
581
- return item.w > 0 ? _options.maxSpreadZoom : 1;
582
- },
583
- // Return true if offset is out of the bounds
584
- _modifyDestPanOffset = function (axis, destPanBounds, destPanOffset, destZoomLevel) {
585
- if (destZoomLevel === self.currItem.initialZoomLevel) {
586
- destPanOffset[axis] = self.currItem.initialPosition[axis];
587
- return true;
588
- } else {
589
- destPanOffset[axis] = _calculatePanOffset(axis, destZoomLevel);
590
-
591
- if (destPanOffset[axis] > destPanBounds.min[axis]) {
592
- destPanOffset[axis] = destPanBounds.min[axis];
593
- return true;
594
- } else if (destPanOffset[axis] < destPanBounds.max[axis]) {
595
- destPanOffset[axis] = destPanBounds.max[axis];
596
- return true;
597
- }
598
- }
599
- return false;
600
- },
601
- _setupTransforms = function () {
602
- if (_transformKey) {
603
- // setup 3d transforms
604
- var allow3dTransform = _features.perspective && !_likelyTouchDevice;
605
- _translatePrefix = 'translate' + (allow3dTransform ? '3d(' : '(');
606
- _translateSufix = _features.perspective ? ', 0px)' : ')';
607
- return;
608
- }
609
-
610
- // Override zoom/pan/move functions in case old browser is used (most likely IE)
611
- // (so they use left/top/width/height, instead of CSS transform)
612
-
613
- _transformKey = 'left';
614
- framework.addClass(template, 'pswp--ie');
615
-
616
- _setTranslateX = function (x, elStyle) {
617
- elStyle.left = x + 'px';
618
- };
619
- _applyZoomPanToItem = function (item) {
620
- var zoomRatio = item.fitRatio > 1 ? 1 : item.fitRatio,
621
- s = item.container.style,
622
- w = zoomRatio * item.w,
623
- h = zoomRatio * item.h;
624
-
625
- s.width = w + 'px';
626
- s.height = h + 'px';
627
- s.left = item.initialPosition.x + 'px';
628
- s.top = item.initialPosition.y + 'px';
629
- };
630
- _applyCurrentZoomPan = function () {
631
- if (_currZoomElementStyle) {
632
- var s = _currZoomElementStyle,
633
- item = self.currItem,
634
- zoomRatio = item.fitRatio > 1 ? 1 : item.fitRatio,
635
- w = zoomRatio * item.w,
636
- h = zoomRatio * item.h;
637
-
638
- s.width = w + 'px';
639
- s.height = h + 'px';
640
-
641
- s.left = _panOffset.x + 'px';
642
- s.top = _panOffset.y + 'px';
643
- }
644
- };
645
- },
646
- _onKeyDown = function (e) {
647
- var keydownAction = '';
648
- if (_options.escKey && e.keyCode === 27) {
649
- keydownAction = 'close';
650
- } else if (_options.arrowKeys) {
651
- if (e.keyCode === 37) {
652
- keydownAction = 'prev';
653
- } else if (e.keyCode === 39) {
654
- keydownAction = 'next';
655
- }
656
- }
657
-
658
- if (keydownAction) {
659
- // don't do anything if special key pressed to prevent from overriding default browser actions
660
- // e.g. in Chrome on Mac cmd+arrow-left returns to previous page
661
- if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
662
- if (e.preventDefault) {
663
- e.preventDefault();
664
- } else {
665
- e.returnValue = false;
666
- }
667
- self[keydownAction]();
668
- }
669
- }
670
- },
671
- _onGlobalClick = function (e) {
672
- if (!e) {
673
- return;
674
- }
675
-
676
- // don't allow click event to pass through when triggering after drag or some other gesture
677
- if (_moved || _zoomStarted || _mainScrollAnimating || _verticalDragInitiated) {
678
- e.preventDefault();
679
- e.stopPropagation();
680
- }
681
- },
682
- _updatePageScrollOffset = function () {
683
- self.setScrollOffset(0, framework.getScrollY());
684
- };
685
-
686
- // Micro animation engine
687
- var _animations = {},
688
- _numAnimations = 0,
689
- _stopAnimation = function (name) {
690
- if (_animations[name]) {
691
- if (_animations[name].raf) {
692
- _cancelAF(_animations[name].raf);
693
- }
694
- _numAnimations--;
695
- delete _animations[name];
696
- }
697
- },
698
- _registerStartAnimation = function (name) {
699
- if (_animations[name]) {
700
- _stopAnimation(name);
701
- }
702
- if (!_animations[name]) {
703
- _numAnimations++;
704
- _animations[name] = {};
705
- }
706
- },
707
- _stopAllAnimations = function () {
708
- for (var prop in _animations) {
709
- if (_animations.hasOwnProperty(prop)) {
710
- _stopAnimation(prop);
711
- }
712
- }
713
- },
714
- _animateProp = function (name, b, endProp, d, easingFn, onUpdate, onComplete) {
715
- var startAnimTime = _getCurrentTime(),
716
- t;
717
- _registerStartAnimation(name);
718
-
719
- var animloop = function () {
720
- if (_animations[name]) {
721
- t = _getCurrentTime() - startAnimTime; // time diff
722
- //b - beginning (start prop)
723
- //d - anim duration
724
-
725
- if (t >= d) {
726
- _stopAnimation(name);
727
- onUpdate(endProp);
728
- if (onComplete) {
729
- onComplete();
730
- }
731
- return;
732
- }
733
- onUpdate((endProp - b) * easingFn(t / d) + b);
734
-
735
- _animations[name].raf = _requestAF(animloop);
736
- }
737
- };
738
- animloop();
739
- };
740
-
741
- var publicMethods = {
742
- // make a few local variables and functions public
743
- shout: _shout,
744
- listen: _listen,
745
- viewportSize: _viewportSize,
746
- options: _options,
747
-
748
- isMainScrollAnimating: function () {
749
- return _mainScrollAnimating;
750
- },
751
- getZoomLevel: function () {
752
- return _currZoomLevel;
753
- },
754
- getCurrentIndex: function () {
755
- return _currentItemIndex;
756
- },
757
- isDragging: function () {
758
- return _isDragging;
759
- },
760
- isZooming: function () {
761
- return _isZooming;
762
- },
763
- setScrollOffset: function (x, y) {
764
- _offset.x = x;
765
- _currentWindowScrollY = _offset.y = y;
766
- _shout('updateScrollOffset', _offset);
767
- },
768
- applyZoomPan: function (zoomLevel, panX, panY, allowRenderResolution) {
769
- _panOffset.x = panX;
770
- _panOffset.y = panY;
771
- _currZoomLevel = zoomLevel;
772
- _applyCurrentZoomPan(allowRenderResolution);
773
- },
774
-
775
- init: function () {
776
- if (_isOpen || _isDestroying) {
777
- return;
778
- }
779
-
780
- var i;
781
-
782
- self.framework = framework; // basic functionality
783
- self.template = template; // root DOM element of PhotoSwipe
784
- self.bg = framework.getChildByClass(template, 'pswp__bg');
785
-
786
- _initalClassName = template.className;
787
- _isOpen = true;
788
-
789
- _features = framework.detectFeatures();
790
- _requestAF = _features.raf;
791
- _cancelAF = _features.caf;
792
- _transformKey = _features.transform;
793
- _oldIE = _features.oldIE;
794
-
795
- self.scrollWrap = framework.getChildByClass(template, 'pswp__scroll-wrap');
796
- self.container = framework.getChildByClass(self.scrollWrap, 'pswp__container');
797
-
798
- _containerStyle = self.container.style; // for fast access
799
-
800
- // Objects that hold slides (there are only 3 in DOM)
801
- self.itemHolders = _itemHolders = [
802
- {el: self.container.children[0], wrap: 0, index: -1},
803
- {el: self.container.children[1], wrap: 0, index: -1},
804
- {el: self.container.children[2], wrap: 0, index: -1}
805
- ];
806
-
807
- // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)
808
- _itemHolders[0].el.style.display = _itemHolders[2].el.style.display = 'none';
809
-
810
- _setupTransforms();
811
-
812
- // Setup global events
813
- _globalEventHandlers = {
814
- resize: self.updateSize,
815
-
816
- // Fixes: iOS 10.3 resize event
817
- // does not update scrollWrap.clientWidth instantly after resize
818
- // https://github.com/dimsemenov/PhotoSwipe/issues/1315
819
- orientationchange: function () {
820
- clearTimeout(_orientationChangeTimeout);
821
- _orientationChangeTimeout = setTimeout(function () {
822
- if (_viewportSize.x !== self.scrollWrap.clientWidth) {
823
- self.updateSize();
824
- }
825
- }, 500);
826
- },
827
- scroll: _updatePageScrollOffset,
828
- keydown: _onKeyDown,
829
- click: _onGlobalClick
830
- };
831
-
832
- // disable show/hide effects on old browsers that don't support CSS animations or transforms,
833
- // old IOS, Android and Opera mobile. Blackberry seems to work fine, even older models.
834
- var oldPhone = _features.isOldIOSPhone || _features.isOldAndroid || _features.isMobileOpera;
835
- if (!_features.animationName || !_features.transform || oldPhone) {
836
- _options.showAnimationDuration = _options.hideAnimationDuration = 0;
837
- }
838
-
839
- // init modules
840
- for (i = 0; i < _modules.length; i++) {
841
- self['init' + _modules[i]]();
842
- }
843
-
844
- // init
845
- if (UiClass) {
846
- var ui = (self.ui = new UiClass(self, framework));
847
- ui.init();
848
- }
849
-
850
- _shout('firstUpdate');
851
- _currentItemIndex = _currentItemIndex || _options.index || 0;
852
- // validate index
853
- if (isNaN(_currentItemIndex) || _currentItemIndex < 0 || _currentItemIndex >= _getNumItems()) {
854
- _currentItemIndex = 0;
855
- }
856
- self.currItem = _getItemAt(_currentItemIndex);
857
-
858
- if (_features.isOldIOSPhone || _features.isOldAndroid) {
859
- _isFixedPosition = false;
860
- }
861
-
862
- template.setAttribute('aria-hidden', 'false');
863
- if (_options.modal) {
864
- if (!_isFixedPosition) {
865
- template.style.position = 'absolute';
866
- template.style.top = framework.getScrollY() + 'px';
867
- } else {
868
- template.style.position = 'fixed';
869
- }
870
- }
871
-
872
- if (_currentWindowScrollY === undefined) {
873
- _shout('initialLayout');
874
- _currentWindowScrollY = _initalWindowScrollY = framework.getScrollY();
875
- }
876
-
877
- // add classes to root element of PhotoSwipe
878
- var rootClasses = 'pswp--open ';
879
- if (_options.mainClass) {
880
- rootClasses += _options.mainClass + ' ';
881
- }
882
- if (_options.showHideOpacity) {
883
- rootClasses += 'pswp--animate_opacity ';
884
- }
885
- rootClasses += _likelyTouchDevice ? 'pswp--touch' : 'pswp--notouch';
886
- rootClasses += _options.preventSwiping ? ' pswp--preventswipe' : '';
887
- rootClasses += _features.animationName ? ' pswp--css_animation' : '';
888
- rootClasses += _features.svg ? ' pswp--svg' : '';
889
- framework.addClass(template, rootClasses);
890
-
891
- self.updateSize();
892
-
893
- // initial update
894
- _containerShiftIndex = -1;
895
- _indexDiff = null;
896
- for (i = 0; i < NUM_HOLDERS; i++) {
897
- _setTranslateX((i + _containerShiftIndex) * _slideSize.x, _itemHolders[i].el.style);
898
- }
899
-
900
- if (!_oldIE) {
901
- framework.bind(self.scrollWrap, _downEvents, self); // no dragging for old IE
902
- }
903
-
904
- _listen('initialZoomInEnd', function () {
905
- self.setContent(_itemHolders[0], _currentItemIndex - 1);
906
- self.setContent(_itemHolders[2], _currentItemIndex + 1);
907
-
908
- _itemHolders[0].el.style.display = _itemHolders[2].el.style.display = 'block';
909
-
910
- if (_options.focus) {
911
- // focus causes layout,
912
- // which causes lag during the animation,
913
- // that's why we delay it until the initial zoom transition ends
914
- template.focus();
915
- }
916
-
917
- _bindEvents();
918
- });
919
-
920
- // set content for center slide (first time)
921
- self.setContent(_itemHolders[1], _currentItemIndex);
922
-
923
- self.updateCurrItem();
924
-
925
- _shout('afterInit');
926
-
927
- if (!_isFixedPosition) {
928
- // On all versions of iOS lower than 8.0, we check size of viewport every second.
929
- //
930
- // This is done to detect when Safari top & bottom bars appear,
931
- // as this action doesn't trigger any events (like resize).
932
- //
933
- // On iOS8 they fixed this.
934
- //
935
- // 10 Nov 2014: iOS 7 usage ~40%. iOS 8 usage 56%.
936
-
937
- _updateSizeInterval = setInterval(function () {
938
- if (!_numAnimations && !_isDragging && !_isZooming && _currZoomLevel === self.currItem.initialZoomLevel) {
939
- self.updateSize();
940
- }
941
- }, 1000);
942
- }
943
-
944
- framework.addClass(template, 'pswp--visible');
945
- },
946
-
947
- // Close the gallery, then destroy it
948
- close: function () {
949
- if (!_isOpen) {
950
- return;
951
- }
952
-
953
- _isOpen = false;
954
- _isDestroying = true;
955
- _shout('close');
956
- _unbindEvents();
957
-
958
- _showOrHide(self.currItem, null, true, self.destroy);
959
- },
960
-
961
- // destroys the gallery (unbinds events, cleans up intervals and timeouts to avoid memory leaks)
962
- destroy: function () {
963
- _shout('destroy');
964
-
965
- if (_showOrHideTimeout) {
966
- clearTimeout(_showOrHideTimeout);
967
- }
968
-
969
- template.setAttribute('aria-hidden', 'true');
970
- template.className = _initalClassName;
971
-
972
- if (_updateSizeInterval) {
973
- clearInterval(_updateSizeInterval);
974
- }
975
-
976
- framework.unbind(self.scrollWrap, _downEvents, self);
977
-
978
- // we unbind scroll event at the end, as closing animation may depend on it
979
- framework.unbind(window, 'scroll', self);
980
-
981
- _stopDragUpdateLoop();
982
-
983
- _stopAllAnimations();
984
-
985
- _listeners = {};
986
- },
987
-
988
- /**
989
- * Pan image to position
990
- * @param {Number} x
991
- * @param {Number} y
992
- * @param {Boolean} force Will ignore bounds if set to true.
993
- */
994
- panTo: function (x, y, force) {
995
- if (!force) {
996
- if (x > _currPanBounds.min.x) {
997
- x = _currPanBounds.min.x;
998
- } else if (x < _currPanBounds.max.x) {
999
- x = _currPanBounds.max.x;
1000
- }
1001
-
1002
- if (y > _currPanBounds.min.y) {
1003
- y = _currPanBounds.min.y;
1004
- } else if (y < _currPanBounds.max.y) {
1005
- y = _currPanBounds.max.y;
1006
- }
1007
- }
1008
-
1009
- _panOffset.x = x;
1010
- _panOffset.y = y;
1011
- _applyCurrentZoomPan();
1012
- },
1013
-
1014
- handleEvent: function (e) {
1015
- e = e || window.event;
1016
- if (_globalEventHandlers[e.type]) {
1017
- _globalEventHandlers[e.type](e);
1018
- }
1019
- },
1020
-
1021
- goTo: function (index) {
1022
- if (_options.animateTransitions) {
1023
- _finishSwipeMainScrollGesture('swipe', 80 * index, {
1024
- lastFlickDist: {
1025
- x: 80,
1026
- y: 0
1027
- },
1028
- lastFlickOffset: {
1029
- x: 80 * index,
1030
- y: 0
1031
- },
1032
- lastFlickSpeed: {
1033
- x: 2 * index,
1034
- y: 0
1035
- }
1036
- });
1037
- } else {
1038
- index = _getLoopedId(index);
1039
-
1040
- var diff = index - _currentItemIndex;
1041
- _indexDiff = diff;
1042
-
1043
- _currentItemIndex = index;
1044
- self.currItem = _getItemAt(_currentItemIndex);
1045
- _currPositionIndex -= diff;
1046
-
1047
- _moveMainScroll(_slideSize.x * _currPositionIndex);
1048
-
1049
- _stopAllAnimations();
1050
- _mainScrollAnimating = false;
1051
-
1052
- self.updateCurrItem();
1053
- }
1054
- },
1055
- next: function () {
1056
- if (!_options.loop && _currentItemIndex === _getNumItems() - 1) {
1057
- return;
1058
- }
1059
- if (_options.animateTransitions) {
1060
- self.goTo(-1);
1061
- } else {
1062
- self.goTo(parseInt(_currentItemIndex) + 1);
1063
- }
1064
- },
1065
-
1066
- prev: function () {
1067
- if (!_options.loop && _currentItemIndex === 0) {
1068
- return;
1069
- }
1070
- if (_options.animateTransitions) {
1071
- self.goTo(1);
1072
- } else {
1073
- self.goTo(parseInt(_currentItemIndex) - 1);
1074
- }
1075
- },
1076
-
1077
- setItems: function (items) {
1078
- var last = items.length - 1;
1079
- var currItem = self.currItem;
1080
- var prevItem = self.items[_prevItemIndex];
1081
- self.items.splice(0, self.items.length);
1082
- var newIndex;
1083
- for (var i = 0; i < items.length; i++) {
1084
- self.items.push(items[i]);
1085
- if (items[i] === currItem) {
1086
- newIndex = i;
1087
- }
1088
- }
1089
- if (!newIndex) {
1090
- if (_currentItemIndex >= last) {
1091
- _currentItemIndex = last;
1092
- }
1093
- } else {
1094
- _currentItemIndex = newIndex;
1095
- }
1096
- if (self.items[_currentItemIndex - 1] === prevItem) {
1097
- _prevItemIndex = _currentItemIndex - 1;
1098
- } else {
1099
- _prevItemIndex = _currentItemIndex;
1100
- }
1101
-
1102
- self.invalidateCurrItems();
1103
- self.updateSize(true);
1104
- },
1105
-
1106
- // update current zoom/pan objects
1107
- updateCurrZoomItem: function (emulateSetContent) {
1108
- if (emulateSetContent) {
1109
- _shout('beforeChange', 0);
1110
- }
1111
-
1112
- // itemHolder[1] is middle (current) item
1113
- if (_itemHolders[1].el.children.length) {
1114
- var zoomElement = _itemHolders[1].el.children[0];
1115
- if (framework.hasClass(zoomElement, 'pswp__zoom-wrap')) {
1116
- _currZoomElementStyle = zoomElement.style;
1117
- } else {
1118
- _currZoomElementStyle = null;
1119
- }
1120
- } else {
1121
- _currZoomElementStyle = null;
1122
- }
1123
-
1124
- _currPanBounds = self.currItem.bounds;
1125
- _startZoomLevel = _currZoomLevel = self.currItem.initialZoomLevel;
1126
-
1127
- _panOffset.x = _currPanBounds.center.x;
1128
- _panOffset.y = _currPanBounds.center.y;
1129
-
1130
- if (emulateSetContent) {
1131
- _shout('afterChange');
1132
- }
1133
- },
1134
-
1135
- invalidateCurrItems: function () {
1136
- _itemsNeedUpdate = true;
1137
- for (var i = 0; i < NUM_HOLDERS; i++) {
1138
- if (_itemHolders[i].item) {
1139
- _itemHolders[i].item.needsUpdate = true;
1140
- }
1141
- }
1142
- },
1143
-
1144
- updateCurrItem: function (beforeAnimation) {
1145
- if (_indexDiff === 0) {
1146
- return;
1147
- }
1148
-
1149
- var diffAbs = Math.abs(_indexDiff),
1150
- tempHolder;
1151
-
1152
- if (beforeAnimation && diffAbs < 2) {
1153
- return;
1154
- }
1155
-
1156
- self.currItem = _getItemAt(_currentItemIndex);
1157
- _renderMaxResolution = false;
1158
-
1159
- _shout('beforeChange', _indexDiff);
1160
-
1161
- if (diffAbs >= NUM_HOLDERS) {
1162
- _containerShiftIndex += _indexDiff + (_indexDiff > 0 ? -NUM_HOLDERS : NUM_HOLDERS);
1163
- diffAbs = NUM_HOLDERS;
1164
- }
1165
- for (var i = 0; i < diffAbs; i++) {
1166
- if (_indexDiff > 0) {
1167
- tempHolder = _itemHolders.shift();
1168
- _itemHolders[NUM_HOLDERS - 1] = tempHolder; // move first to last
1169
-
1170
- _containerShiftIndex++;
1171
- _setTranslateX((_containerShiftIndex + 2) * _slideSize.x, tempHolder.el.style);
1172
- self.setContent(tempHolder, _currentItemIndex - diffAbs + i + 1 + 1);
1173
- } else {
1174
- tempHolder = _itemHolders.pop();
1175
- _itemHolders.unshift(tempHolder); // move last to first
1176
-
1177
- _containerShiftIndex--;
1178
- _setTranslateX(_containerShiftIndex * _slideSize.x, tempHolder.el.style);
1179
- self.setContent(tempHolder, _currentItemIndex + diffAbs - i - 1 - 1);
1180
- }
1181
- }
1182
-
1183
- // reset zoom/pan on previous item
1184
- if (_currZoomElementStyle && Math.abs(_indexDiff) === 1) {
1185
- var prevItem = _getItemAt(_prevItemIndex);
1186
- if (prevItem.initialZoomLevel !== _currZoomLevel) {
1187
- _calculateItemSize(prevItem, _viewportSize);
1188
- _setImageSize(prevItem);
1189
- _applyZoomPanToItem(prevItem);
1190
- }
1191
- }
1192
-
1193
- // reset diff after update
1194
- _indexDiff = 0;
1195
-
1196
- self.updateCurrZoomItem();
1197
-
1198
- _prevItemIndex = _currentItemIndex;
1199
-
1200
- _shout('afterChange');
1201
- },
1202
-
1203
- updateSize: function (force) {
1204
- if (!_isFixedPosition && _options.modal) {
1205
- var windowScrollY = framework.getScrollY();
1206
- if (_currentWindowScrollY !== windowScrollY) {
1207
- template.style.top = windowScrollY + 'px';
1208
- _currentWindowScrollY = windowScrollY;
1209
- }
1210
- if (!force && _windowVisibleSize.x === window.innerWidth && _windowVisibleSize.y === window.innerHeight) {
1211
- return;
1212
- }
1213
- _windowVisibleSize.x = window.innerWidth;
1214
- _windowVisibleSize.y = window.innerHeight;
1215
-
1216
- //template.style.width = _windowVisibleSize.x + 'px';
1217
- template.style.height = _windowVisibleSize.y + 'px';
1218
- }
1219
-
1220
- _viewportSize.x = self.scrollWrap.clientWidth;
1221
- _viewportSize.y = self.scrollWrap.clientHeight;
1222
-
1223
- _updatePageScrollOffset();
1224
-
1225
- _slideSize.x = _viewportSize.x + Math.round(_viewportSize.x * _options.spacing);
1226
- _slideSize.y = _viewportSize.y;
1227
-
1228
- _moveMainScroll(_slideSize.x * _currPositionIndex);
1229
-
1230
- _shout('beforeResize'); // even may be used for example to switch image sources
1231
-
1232
- // don't re-calculate size on inital size update
1233
- if (_containerShiftIndex !== undefined) {
1234
- var holder, item, hIndex;
1235
-
1236
- for (var i = 0; i < NUM_HOLDERS; i++) {
1237
- holder = _itemHolders[i];
1238
- _setTranslateX((i + _containerShiftIndex) * _slideSize.x, holder.el.style);
1239
-
1240
- hIndex = _currentItemIndex + i - 1;
1241
-
1242
- if (_options.loop && _getNumItems() > 2) {
1243
- hIndex = _getLoopedId(hIndex);
1244
- }
1245
-
1246
- // update zoom level on items and refresh source (if needsUpdate)
1247
- item = _getItemAt(hIndex);
1248
-
1249
- // re-render gallery item if `needsUpdate`,
1250
- // or doesn't have `bounds` (entirely new slide object)
1251
- if (item && (_itemsNeedUpdate || item.needsUpdate || !item.bounds)) {
1252
- self.cleanSlide(item);
1253
-
1254
- self.setContent(holder, hIndex);
1255
-
1256
- // if "center" slide
1257
- if (i === 1) {
1258
- self.currItem = item;
1259
- self.updateCurrZoomItem(true);
1260
- }
1261
-
1262
- item.needsUpdate = false;
1263
- } else if (holder.index === -1 && hIndex >= 0) {
1264
- // add content first time
1265
- self.setContent(holder, hIndex);
1266
- }
1267
- if (item && item.container) {
1268
- _calculateItemSize(item, _viewportSize);
1269
- _setImageSize(item);
1270
- _applyZoomPanToItem(item);
1271
- }
1272
- }
1273
- _itemsNeedUpdate = false;
1274
- }
1275
-
1276
- _startZoomLevel = _currZoomLevel = self.currItem.initialZoomLevel;
1277
- _currPanBounds = self.currItem.bounds;
1278
-
1279
- if (_currPanBounds) {
1280
- _panOffset.x = _currPanBounds.center.x;
1281
- _panOffset.y = _currPanBounds.center.y;
1282
- _applyCurrentZoomPan(true);
1283
- }
1284
-
1285
- _shout('resize');
1286
- },
1287
-
1288
- // Zoom current item to
1289
- zoomTo: function (destZoomLevel, centerPoint, speed, easingFn, updateFn) {
1290
- /*
1291
- if(destZoomLevel === 'fit') {
1292
- destZoomLevel = self.currItem.fitRatio;
1293
- } else if(destZoomLevel === 'fill') {
1294
- destZoomLevel = self.currItem.fillRatio;
1295
- }
1296
- */
1297
-
1298
- if (centerPoint) {
1299
- _startZoomLevel = _currZoomLevel;
1300
- _midZoomPoint.x = Math.abs(centerPoint.x) - _panOffset.x;
1301
- _midZoomPoint.y = Math.abs(centerPoint.y) - _panOffset.y;
1302
- _equalizePoints(_startPanOffset, _panOffset);
1303
- }
1304
-
1305
- var destPanBounds = _calculatePanBounds(destZoomLevel, false),
1306
- destPanOffset = {};
1307
-
1308
- _modifyDestPanOffset('x', destPanBounds, destPanOffset, destZoomLevel);
1309
- _modifyDestPanOffset('y', destPanBounds, destPanOffset, destZoomLevel);
1310
-
1311
- var initialZoomLevel = _currZoomLevel;
1312
- var initialPanOffset = {
1313
- x: _panOffset.x,
1314
- y: _panOffset.y
1315
- };
1316
-
1317
- _roundPoint(destPanOffset);
1318
-
1319
- var onUpdate = function (now) {
1320
- if (now === 1) {
1321
- _currZoomLevel = destZoomLevel;
1322
- _panOffset.x = destPanOffset.x;
1323
- _panOffset.y = destPanOffset.y;
1324
- } else {
1325
- _currZoomLevel = (destZoomLevel - initialZoomLevel) * now + initialZoomLevel;
1326
- _panOffset.x = (destPanOffset.x - initialPanOffset.x) * now + initialPanOffset.x;
1327
- _panOffset.y = (destPanOffset.y - initialPanOffset.y) * now + initialPanOffset.y;
1328
- }
1329
-
1330
- if (updateFn) {
1331
- updateFn(now);
1332
- }
1333
-
1334
- _applyCurrentZoomPan(now === 1);
1335
- };
1336
-
1337
- if (speed) {
1338
- _animateProp('customZoomTo', 0, 1, speed, easingFn || framework.easing.sine.inOut, onUpdate);
1339
- } else {
1340
- onUpdate(1);
1341
- }
1342
- }
1343
- };
1344
-
1345
-
1346
- /*>>core*/
1347
-
1348
- /*>>gestures*/
1349
- /**
1350
- * Mouse/touch/pointer event handlers.
1351
- *
1352
- * separated from @core.js for readability
1353
- */
1354
-
1355
- var MIN_SWIPE_DISTANCE = 30,
1356
- DIRECTION_CHECK_OFFSET = 10; // amount of pixels to drag to determine direction of swipe
1357
-
1358
- var _gestureStartTime,
1359
- _gestureCheckSpeedTime,
1360
- // pool of objects that are used during dragging of zooming
1361
- p = {}, // first point
1362
- p2 = {}, // second point (for zoom gesture)
1363
- delta = {},
1364
- _currPoint = {},
1365
- _startPoint = {},
1366
- _currPointers = [],
1367
- _startMainScrollPos = {},
1368
- _releaseAnimData,
1369
- _posPoints = [], // array of points during dragging, used to determine type of gesture
1370
- _tempPoint = {},
1371
- _isZoomingIn,
1372
- _verticalDragInitiated,
1373
- _oldAndroidTouchEndTimeout,
1374
- _currZoomedItemIndex = 0,
1375
- _centerPoint = _getEmptyPoint(),
1376
- _lastReleaseTime = 0,
1377
- _isDragging, // at least one pointer is down
1378
- _isMultitouch, // at least two _pointers are down
1379
- _zoomStarted, // zoom level changed during zoom gesture
1380
- _moved,
1381
- _dragAnimFrame,
1382
- _mainScrollShifted,
1383
- _currentPoints, // array of current touch points
1384
- _isZooming,
1385
- _currPointsDistance,
1386
- _startPointsDistance,
1387
- _currPanBounds,
1388
- _mainScrollPos = _getEmptyPoint(),
1389
- _currZoomElementStyle,
1390
- _mainScrollAnimating, // true, if animation after swipe gesture is running
1391
- _midZoomPoint = _getEmptyPoint(),
1392
- _currCenterPoint = _getEmptyPoint(),
1393
- _direction,
1394
- _isFirstMove,
1395
- _opacityChanged,
1396
- _bgOpacity,
1397
- _wasOverInitialZoom,
1398
- _isEqualPoints = function (p1, p2) {
1399
- return p1.x === p2.x && p1.y === p2.y;
1400
- },
1401
- _isNearbyPoints = function (touch0, touch1) {
1402
- return Math.abs(touch0.x - touch1.x) < DOUBLE_TAP_RADIUS && Math.abs(touch0.y - touch1.y) < DOUBLE_TAP_RADIUS;
1403
- },
1404
- _calculatePointsDistance = function (p1, p2) {
1405
- _tempPoint.x = Math.abs(p1.x - p2.x);
1406
- _tempPoint.y = Math.abs(p1.y - p2.y);
1407
- return Math.sqrt(_tempPoint.x * _tempPoint.x + _tempPoint.y * _tempPoint.y);
1408
- },
1409
- _stopDragUpdateLoop = function () {
1410
- if (_dragAnimFrame) {
1411
- _cancelAF(_dragAnimFrame);
1412
- _dragAnimFrame = null;
1413
- }
1414
- },
1415
- _dragUpdateLoop = function () {
1416
- if (_isDragging) {
1417
- _dragAnimFrame = _requestAF(_dragUpdateLoop);
1418
- _renderMovement();
1419
- }
1420
- },
1421
- _canPan = function () {
1422
- return !(_options.scaleMode === 'fit' && _currZoomLevel === self.currItem.initialZoomLevel);
1423
- },
1424
- // find the closest parent DOM element
1425
- _closestElement = function (el, fn) {
1426
- if (!el || el === document) {
1427
- return false;
1428
- }
1429
-
1430
- // don't search elements above pswp__scroll-wrap
1431
- if (el.getAttribute('class') && el.getAttribute('class').indexOf('pswp__scroll-wrap') > -1) {
1432
- return false;
1433
- }
1434
-
1435
- if (fn(el)) {
1436
- return el;
1437
- }
1438
-
1439
- return _closestElement(el.parentNode, fn);
1440
- },
1441
- _preventObj = {},
1442
- _preventDefaultEventBehaviour = function (e, isDown) {
1443
- _preventObj.prevent = !_closestElement(e.target, _options.isClickableElement);
1444
-
1445
- _shout('preventDragEvent', e, isDown, _preventObj);
1446
- return _preventObj.prevent;
1447
- },
1448
- _convertTouchToPoint = function (touch, p) {
1449
- p.x = touch.pageX;
1450
- p.y = touch.pageY;
1451
- p.id = touch.identifier;
1452
- return p;
1453
- },
1454
- _findCenterOfPoints = function (p1, p2, pCenter) {
1455
- pCenter.x = (p1.x + p2.x) * 0.5;
1456
- pCenter.y = (p1.y + p2.y) * 0.5;
1457
- },
1458
- _pushPosPoint = function (time, x, y) {
1459
- if (time - _gestureCheckSpeedTime > 50) {
1460
- var o = _posPoints.length > 2 ? _posPoints.shift() : {};
1461
- o.x = x;
1462
- o.y = y;
1463
- _posPoints.push(o);
1464
- _gestureCheckSpeedTime = time;
1465
- }
1466
- },
1467
- _calculateVerticalDragOpacityRatio = function () {
1468
- var yOffset = _panOffset.y - self.currItem.initialPosition.y; // difference between initial and current position
1469
- return 1 - Math.abs(yOffset / (_viewportSize.y / 2));
1470
- },
1471
- // points pool, reused during touch events
1472
- _ePoint1 = {},
1473
- _ePoint2 = {},
1474
- _tempPointsArr = [],
1475
- _tempCounter,
1476
- _getTouchPoints = function (e) {
1477
- // clean up previous points, without recreating array
1478
- while (_tempPointsArr.length > 0) {
1479
- _tempPointsArr.pop();
1480
- }
1481
-
1482
- if (!_pointerEventEnabled) {
1483
- if (e.type.indexOf('touch') > -1) {
1484
- if (e.touches && e.touches.length > 0) {
1485
- _tempPointsArr[0] = _convertTouchToPoint(e.touches[0], _ePoint1);
1486
- if (e.touches.length > 1) {
1487
- _tempPointsArr[1] = _convertTouchToPoint(e.touches[1], _ePoint2);
1488
- }
1489
- }
1490
- } else {
1491
- _ePoint1.x = e.pageX;
1492
- _ePoint1.y = e.pageY;
1493
- _ePoint1.id = '';
1494
- _tempPointsArr[0] = _ePoint1; //_ePoint1;
1495
- }
1496
- } else {
1497
- _tempCounter = 0;
1498
- // we can use forEach, as pointer events are supported only in modern browsers
1499
- _currPointers.forEach(function (p) {
1500
- if (_tempCounter === 0) {
1501
- _tempPointsArr[0] = p;
1502
- } else if (_tempCounter === 1) {
1503
- _tempPointsArr[1] = p;
1504
- }
1505
- _tempCounter++;
1506
- });
1507
- }
1508
- return _tempPointsArr;
1509
- },
1510
- _panOrMoveMainScroll = function (axis, delta) {
1511
- var panFriction,
1512
- overDiff = 0,
1513
- newOffset = _panOffset[axis] + delta[axis],
1514
- startOverDiff,
1515
- dir = delta[axis] > 0,
1516
- newMainScrollPosition = _mainScrollPos.x + delta.x,
1517
- mainScrollDiff = _mainScrollPos.x - _startMainScrollPos.x,
1518
- newPanPos,
1519
- newMainScrollPos;
1520
-
1521
- // calculate fdistance over the bounds and friction
1522
- if (newOffset > _currPanBounds.min[axis] || newOffset < _currPanBounds.max[axis]) {
1523
- panFriction = _options.panEndFriction;
1524
- // Linear increasing of friction, so at 1/4 of viewport it's at max value.
1525
- // Looks not as nice as was expected. Left for history.
1526
- // panFriction = (1 - (_panOffset[axis] + delta[axis] + panBounds.min[axis]) / (_viewportSize[axis] / 4) );
1527
- } else {
1528
- panFriction = 1;
1529
- }
1530
-
1531
- newOffset = _panOffset[axis] + delta[axis] * panFriction;
1532
-
1533
- // move main scroll or start panning
1534
- if (_options.allowPanToNext || _currZoomLevel === self.currItem.initialZoomLevel) {
1535
- if (!_currZoomElementStyle) {
1536
- newMainScrollPos = newMainScrollPosition;
1537
- } else if (_direction === 'h' && axis === 'x' && !_zoomStarted) {
1538
- if (dir) {
1539
- if (newOffset > _currPanBounds.min[axis]) {
1540
- panFriction = _options.panEndFriction;
1541
- overDiff = _currPanBounds.min[axis] - newOffset;
1542
- startOverDiff = _currPanBounds.min[axis] - _startPanOffset[axis];
1543
- }
1544
-
1545
- // drag right
1546
- if ((startOverDiff <= 0 || mainScrollDiff < 0) && _getNumItems() > 1) {
1547
- newMainScrollPos = newMainScrollPosition;
1548
- if (mainScrollDiff < 0 && newMainScrollPosition > _startMainScrollPos.x) {
1549
- newMainScrollPos = _startMainScrollPos.x;
1550
- }
1551
- } else {
1552
- if (_currPanBounds.min.x !== _currPanBounds.max.x) {
1553
- newPanPos = newOffset;
1554
- }
1555
- }
1556
- } else {
1557
- if (newOffset < _currPanBounds.max[axis]) {
1558
- panFriction = _options.panEndFriction;
1559
- overDiff = newOffset - _currPanBounds.max[axis];
1560
- startOverDiff = _startPanOffset[axis] - _currPanBounds.max[axis];
1561
- }
1562
-
1563
- if ((startOverDiff <= 0 || mainScrollDiff > 0) && _getNumItems() > 1) {
1564
- newMainScrollPos = newMainScrollPosition;
1565
-
1566
- if (mainScrollDiff > 0 && newMainScrollPosition < _startMainScrollPos.x) {
1567
- newMainScrollPos = _startMainScrollPos.x;
1568
- }
1569
- } else {
1570
- if (_currPanBounds.min.x !== _currPanBounds.max.x) {
1571
- newPanPos = newOffset;
1572
- }
1573
- }
1574
- }
1575
-
1576
- //
1577
- }
1578
-
1579
- if (axis === 'x') {
1580
- if (newMainScrollPos !== undefined) {
1581
- _moveMainScroll(newMainScrollPos, true);
1582
- if (newMainScrollPos === _startMainScrollPos.x) {
1583
- _mainScrollShifted = false;
1584
- } else {
1585
- _mainScrollShifted = true;
1586
- }
1587
- }
1588
-
1589
- if (_currPanBounds.min.x !== _currPanBounds.max.x) {
1590
- if (newPanPos !== undefined) {
1591
- _panOffset.x = newPanPos;
1592
- } else if (!_mainScrollShifted) {
1593
- _panOffset.x += delta.x * panFriction;
1594
- }
1595
- }
1596
-
1597
- return newMainScrollPos !== undefined;
1598
- }
1599
- }
1600
-
1601
- if (!_mainScrollAnimating) {
1602
- if (!_mainScrollShifted) {
1603
- if (_currZoomLevel > self.currItem.fitRatio) {
1604
- _panOffset[axis] += delta[axis] * panFriction;
1605
- }
1606
- }
1607
- }
1608
- },
1609
- // Pointerdown/touchstart/mousedown handler
1610
- _onDragStart = function (e) {
1611
- // Allow dragging only via left mouse button.
1612
- // As this handler is not added in IE8 - we ignore e.which
1613
- //
1614
- // http://www.quirksmode.org/js/events_properties.html
1615
- // https://developer.mozilla.org/en-US/docs/Web/API/event.button
1616
- if (e.type === 'mousedown' && (e.button > 0 || e.buttons === 0)) {
1617
- return;
1618
- }
1619
-
1620
- if (_options.preventSwiping) {
1621
- return;
1622
- }
1623
-
1624
- if (_initialZoomRunning) {
1625
- e.preventDefault();
1626
- return;
1627
- }
1628
-
1629
- if (_oldAndroidTouchEndTimeout && e.type === 'mousedown') {
1630
- return;
1631
- }
1632
-
1633
- if (_preventDefaultEventBehaviour(e, true)) {
1634
- e.preventDefault();
1635
- }
1636
-
1637
- _shout('pointerDown');
1638
-
1639
- if (_pointerEventEnabled) {
1640
- var pointerIndex = framework.arraySearch(_currPointers, e.pointerId, 'id');
1641
- if (pointerIndex < 0) {
1642
- pointerIndex = _currPointers.length;
1643
- }
1644
- _currPointers[pointerIndex] = {x: e.pageX, y: e.pageY, id: e.pointerId};
1645
- }
1646
-
1647
- var startPointsList = _getTouchPoints(e),
1648
- numPoints = startPointsList.length;
1649
-
1650
- _currentPoints = null;
1651
-
1652
- _stopAllAnimations();
1653
-
1654
- // init drag
1655
- if (!_isDragging || numPoints === 1) {
1656
- _isDragging = _isFirstMove = true;
1657
- framework.bind(window, _upMoveEvents, self);
1658
-
1659
- _isZoomingIn = _wasOverInitialZoom = _opacityChanged = _verticalDragInitiated = _mainScrollShifted = _moved = _isMultitouch = _zoomStarted = false;
1660
-
1661
- _direction = null;
1662
-
1663
- _shout('firstTouchStart', startPointsList);
1664
-
1665
- _equalizePoints(_startPanOffset, _panOffset);
1666
-
1667
- _currPanDist.x = _currPanDist.y = 0;
1668
- _equalizePoints(_currPoint, startPointsList[0]);
1669
- _equalizePoints(_startPoint, _currPoint);
1670
-
1671
- //_equalizePoints(_startMainScrollPos, _mainScrollPos);
1672
- _startMainScrollPos.x = _slideSize.x * _currPositionIndex;
1673
-
1674
- _posPoints = [
1675
- {
1676
- x: _currPoint.x,
1677
- y: _currPoint.y
1678
- }
1679
- ];
1680
-
1681
- _gestureCheckSpeedTime = _gestureStartTime = _getCurrentTime();
1682
-
1683
- //_mainScrollAnimationEnd(true);
1684
- _calculatePanBounds(_currZoomLevel, true);
1685
-
1686
- // Start rendering
1687
- _stopDragUpdateLoop();
1688
- _dragUpdateLoop();
1689
- }
1690
-
1691
- // init zoom
1692
- if (!_isZooming && numPoints > 1 && !_mainScrollAnimating && !_mainScrollShifted) {
1693
- _startZoomLevel = _currZoomLevel;
1694
- _zoomStarted = false; // true if zoom changed at least once
1695
-
1696
- _isZooming = _isMultitouch = true;
1697
- _currPanDist.y = _currPanDist.x = 0;
1698
-
1699
- _equalizePoints(_startPanOffset, _panOffset);
1700
-
1701
- _equalizePoints(p, startPointsList[0]);
1702
- _equalizePoints(p2, startPointsList[1]);
1703
-
1704
- _findCenterOfPoints(p, p2, _currCenterPoint);
1705
-
1706
- _midZoomPoint.x = Math.abs(_currCenterPoint.x) - _panOffset.x;
1707
- _midZoomPoint.y = Math.abs(_currCenterPoint.y) - _panOffset.y;
1708
- _currPointsDistance = _startPointsDistance = _calculatePointsDistance(p, p2);
1709
- }
1710
- },
1711
- // Pointermove/touchmove/mousemove handler
1712
- _onDragMove = function (e) {
1713
- if (_options.preventSwiping) {
1714
- return;
1715
- }
1716
-
1717
- e.preventDefault();
1718
-
1719
- if (_pointerEventEnabled) {
1720
- var pointerIndex = framework.arraySearch(_currPointers, e.pointerId, 'id');
1721
- if (pointerIndex > -1) {
1722
- var p = _currPointers[pointerIndex];
1723
- p.x = e.pageX;
1724
- p.y = e.pageY;
1725
- }
1726
- }
1727
-
1728
- if (_isDragging) {
1729
- var touchesList = _getTouchPoints(e);
1730
- if (!_direction && !_moved && !_isZooming) {
1731
- if (_mainScrollPos.x !== _slideSize.x * _currPositionIndex) {
1732
- // if main scroll position is shifted – direction is always horizontal
1733
- _direction = 'h';
1734
- } else {
1735
- var diff = Math.abs(touchesList[0].x - _currPoint.x) - Math.abs(touchesList[0].y - _currPoint.y);
1736
- // check the direction of movement
1737
- if (Math.abs(diff) >= DIRECTION_CHECK_OFFSET) {
1738
- _direction = diff > 0 ? 'h' : 'v';
1739
- _currentPoints = touchesList;
1740
- }
1741
- }
1742
- } else {
1743
- _currentPoints = touchesList;
1744
- }
1745
- }
1746
- },
1747
- //
1748
- _renderMovement = function () {
1749
- if (!_currentPoints) {
1750
- return;
1751
- }
1752
-
1753
- var numPoints = _currentPoints.length;
1754
-
1755
- if (numPoints === 0) {
1756
- return;
1757
- }
1758
-
1759
- _equalizePoints(p, _currentPoints[0]);
1760
-
1761
- delta.x = p.x - _currPoint.x;
1762
- delta.y = p.y - _currPoint.y;
1763
-
1764
- if (_isZooming && numPoints > 1) {
1765
- // Handle behaviour for more than 1 point
1766
-
1767
- _currPoint.x = p.x;
1768
- _currPoint.y = p.y;
1769
-
1770
- // check if one of two points changed
1771
- if (!delta.x && !delta.y && _isEqualPoints(_currentPoints[1], p2)) {
1772
- return;
1773
- }
1774
-
1775
- _equalizePoints(p2, _currentPoints[1]);
1776
-
1777
- if (!_zoomStarted) {
1778
- _zoomStarted = true;
1779
- _shout('zoomGestureStarted');
1780
- }
1781
-
1782
- // Distance between two points
1783
- var pointsDistance = _calculatePointsDistance(p, p2);
1784
-
1785
- var zoomLevel = _calculateZoomLevel(pointsDistance);
1786
-
1787
- // slightly over the of initial zoom level
1788
- if (zoomLevel > self.currItem.initialZoomLevel + self.currItem.initialZoomLevel / 15) {
1789
- _wasOverInitialZoom = true;
1790
- }
1791
-
1792
- // Apply the friction if zoom level is out of the bounds
1793
- var zoomFriction = 1,
1794
- minZoomLevel = _getMinZoomLevel(),
1795
- maxZoomLevel = _getMaxZoomLevel();
1796
-
1797
- if (zoomLevel < minZoomLevel) {
1798
- if (_options.pinchToClose && !_wasOverInitialZoom && _startZoomLevel <= self.currItem.initialZoomLevel) {
1799
- // fade out background if zooming out
1800
- var minusDiff = minZoomLevel - zoomLevel;
1801
- var percent = 1 - minusDiff / (minZoomLevel / 1.2);
1802
-
1803
- _applyBgOpacity(percent);
1804
- _shout('onPinchClose', percent);
1805
- _opacityChanged = true;
1806
- } else {
1807
- zoomFriction = (minZoomLevel - zoomLevel) / minZoomLevel;
1808
- if (zoomFriction > 1) {
1809
- zoomFriction = 1;
1810
- }
1811
- zoomLevel = minZoomLevel - zoomFriction * (minZoomLevel / 3);
1812
- }
1813
- } else if (zoomLevel > maxZoomLevel) {
1814
- // 1.5 - extra zoom level above the max. E.g. if max is x6, real max 6 + 1.5 = 7.5
1815
- zoomFriction = (zoomLevel - maxZoomLevel) / (minZoomLevel * 6);
1816
- if (zoomFriction > 1) {
1817
- zoomFriction = 1;
1818
- }
1819
- zoomLevel = maxZoomLevel + zoomFriction * minZoomLevel;
1820
- }
1821
-
1822
- if (zoomFriction < 0) {
1823
- zoomFriction = 0;
1824
- }
1825
-
1826
- // distance between touch points after friction is applied
1827
- _currPointsDistance = pointsDistance;
1828
-
1829
- // _centerPoint - The point in the middle of two pointers
1830
- _findCenterOfPoints(p, p2, _centerPoint);
1831
-
1832
- // paning with two pointers pressed
1833
- _currPanDist.x += _centerPoint.x - _currCenterPoint.x;
1834
- _currPanDist.y += _centerPoint.y - _currCenterPoint.y;
1835
- _equalizePoints(_currCenterPoint, _centerPoint);
1836
-
1837
- _panOffset.x = _calculatePanOffset('x', zoomLevel);
1838
- _panOffset.y = _calculatePanOffset('y', zoomLevel);
1839
-
1840
- _isZoomingIn = zoomLevel > _currZoomLevel;
1841
- _currZoomLevel = zoomLevel;
1842
- _applyCurrentZoomPan();
1843
- } else {
1844
- // handle behaviour for one point (dragging or panning)
1845
-
1846
- if (!_direction) {
1847
- return;
1848
- }
1849
-
1850
- if (_isFirstMove) {
1851
- _isFirstMove = false;
1852
-
1853
- // subtract drag distance that was used during the detection direction
1854
-
1855
- if (Math.abs(delta.x) >= DIRECTION_CHECK_OFFSET) {
1856
- delta.x -= _currentPoints[0].x - _startPoint.x;
1857
- }
1858
-
1859
- if (Math.abs(delta.y) >= DIRECTION_CHECK_OFFSET) {
1860
- delta.y -= _currentPoints[0].y - _startPoint.y;
1861
- }
1862
- }
1863
-
1864
- _currPoint.x = p.x;
1865
- _currPoint.y = p.y;
1866
-
1867
- // do nothing if pointers position hasn't changed
1868
- if (delta.x === 0 && delta.y === 0) {
1869
- return;
1870
- }
1871
-
1872
- if (_direction === 'v' && _options.closeOnVerticalDrag) {
1873
- if (!_canPan()) {
1874
- _currPanDist.y += delta.y;
1875
- _panOffset.y += delta.y;
1876
-
1877
- var opacityRatio = _calculateVerticalDragOpacityRatio();
1878
-
1879
- _verticalDragInitiated = true;
1880
- _shout('onVerticalDrag', opacityRatio);
1881
-
1882
- _applyBgOpacity(opacityRatio);
1883
- _applyCurrentZoomPan();
1884
- return;
1885
- }
1886
- }
1887
-
1888
- _pushPosPoint(_getCurrentTime(), p.x, p.y);
1889
-
1890
- _moved = true;
1891
- _currPanBounds = self.currItem.bounds;
1892
-
1893
- var mainScrollChanged = _panOrMoveMainScroll('x', delta);
1894
- if (!mainScrollChanged) {
1895
- _panOrMoveMainScroll('y', delta);
1896
-
1897
- _roundPoint(_panOffset);
1898
- _applyCurrentZoomPan();
1899
- }
1900
- }
1901
- },
1902
- // Pointerup/pointercancel/touchend/touchcancel/mouseup event handler
1903
- _onDragRelease = function (e) {
1904
- if (_features.isOldAndroid) {
1905
- if (_oldAndroidTouchEndTimeout && e.type === 'mouseup') {
1906
- return;
1907
- }
1908
-
1909
- // on Android (v4.1, 4.2, 4.3 & possibly older)
1910
- // ghost mousedown/up event isn't preventable via e.preventDefault,
1911
- // which causes fake mousedown event
1912
- // so we block mousedown/up for 600ms
1913
- if (e.type.indexOf('touch') > -1) {
1914
- clearTimeout(_oldAndroidTouchEndTimeout);
1915
- _oldAndroidTouchEndTimeout = setTimeout(function () {
1916
- _oldAndroidTouchEndTimeout = 0;
1917
- }, 600);
1918
- }
1919
- }
1920
-
1921
- _shout('pointerUp');
1922
-
1923
- if (_preventDefaultEventBehaviour(e, false)) {
1924
- e.preventDefault();
1925
- }
1926
-
1927
- var releasePoint;
1928
-
1929
- if (_pointerEventEnabled) {
1930
- var pointerIndex = framework.arraySearch(_currPointers, e.pointerId, 'id');
1931
-
1932
- if (pointerIndex > -1) {
1933
- releasePoint = _currPointers.splice(pointerIndex, 1)[0];
1934
-
1935
- if (navigator.msPointerEnabled) {
1936
- var MSPOINTER_TYPES = {
1937
- 4: 'mouse', // event.MSPOINTER_TYPE_MOUSE
1938
- 2: 'touch', // event.MSPOINTER_TYPE_TOUCH
1939
- 3: 'pen' // event.MSPOINTER_TYPE_PEN
1940
- };
1941
- releasePoint.type = MSPOINTER_TYPES[e.pointerType];
1942
-
1943
- if (!releasePoint.type) {
1944
- releasePoint.type = e.pointerType || 'mouse';
1945
- }
1946
- } else {
1947
- releasePoint.type = e.pointerType || 'mouse';
1948
- }
1949
- }
1950
- }
1951
-
1952
- var touchList = _getTouchPoints(e),
1953
- gestureType,
1954
- numPoints = touchList.length;
1955
-
1956
- if (e.type === 'mouseup') {
1957
- numPoints = 0;
1958
- }
1959
-
1960
- // Do nothing if there were 3 touch points or more
1961
- if (numPoints === 2) {
1962
- _currentPoints = null;
1963
- return true;
1964
- }
1965
-
1966
- // if second pointer released
1967
- if (numPoints === 1) {
1968
- _equalizePoints(_startPoint, touchList[0]);
1969
- }
1970
-
1971
- // pointer hasn't moved, send "tap release" point
1972
- if (numPoints === 0 && !_direction && !_mainScrollAnimating) {
1973
- if (!releasePoint) {
1974
- if (e.type === 'mouseup') {
1975
- releasePoint = {x: e.pageX, y: e.pageY, type: 'mouse'};
1976
- } else if (e.changedTouches && e.changedTouches[0]) {
1977
- releasePoint = {x: e.changedTouches[0].pageX, y: e.changedTouches[0].pageY, type: 'touch'};
1978
- }
1979
- }
1980
-
1981
- _shout('touchRelease', e, releasePoint);
1982
- }
1983
-
1984
- // Difference in time between releasing of two last touch points (zoom gesture)
1985
- var releaseTimeDiff = -1;
1986
-
1987
- // Gesture completed, no pointers left
1988
- if (numPoints === 0) {
1989
- _isDragging = false;
1990
- framework.unbind(window, _upMoveEvents, self);
1991
-
1992
- _stopDragUpdateLoop();
1993
-
1994
- if (_isZooming) {
1995
- // Two points released at the same time
1996
- releaseTimeDiff = 0;
1997
- } else if (_lastReleaseTime !== -1) {
1998
- releaseTimeDiff = _getCurrentTime() - _lastReleaseTime;
1999
- }
2000
- }
2001
- _lastReleaseTime = numPoints === 1 ? _getCurrentTime() : -1;
2002
-
2003
- if (releaseTimeDiff !== -1 && releaseTimeDiff < 150) {
2004
- gestureType = 'zoom';
2005
- } else {
2006
- gestureType = 'swipe';
2007
- }
2008
-
2009
- if (_isZooming && numPoints < 2) {
2010
- _isZooming = false;
2011
-
2012
- // Only second point released
2013
- if (numPoints === 1) {
2014
- gestureType = 'zoomPointerUp';
2015
- }
2016
- _shout('zoomGestureEnded');
2017
- }
2018
-
2019
- _currentPoints = null;
2020
- if (!_moved && !_zoomStarted && !_mainScrollAnimating && !_verticalDragInitiated) {
2021
- // nothing to animate
2022
- return;
2023
- }
2024
-
2025
- _stopAllAnimations();
2026
-
2027
- if (!_releaseAnimData) {
2028
- _releaseAnimData = _initDragReleaseAnimationData();
2029
- }
2030
-
2031
- _releaseAnimData.calculateSwipeSpeed('x');
2032
-
2033
- if (_verticalDragInitiated) {
2034
- var opacityRatio = _calculateVerticalDragOpacityRatio();
2035
-
2036
- if (opacityRatio < _options.verticalDragRange) {
2037
- self.close();
2038
- } else {
2039
- var initalPanY = _panOffset.y,
2040
- initialBgOpacity = _bgOpacity;
2041
-
2042
- _animateProp('verticalDrag', 0, 1, 300, framework.easing.cubic.out, function (now) {
2043
- _panOffset.y = (self.currItem.initialPosition.y - initalPanY) * now + initalPanY;
2044
-
2045
- _applyBgOpacity((1 - initialBgOpacity) * now + initialBgOpacity);
2046
- _applyCurrentZoomPan();
2047
- });
2048
-
2049
- _shout('onVerticalDrag', 1);
2050
- }
2051
-
2052
- return;
2053
- }
2054
-
2055
- // main scroll
2056
- if ((_mainScrollShifted || _mainScrollAnimating) && numPoints === 0) {
2057
- var totalShiftDist = _currPoint.x - _startPoint.x,
2058
- itemChanged = _finishSwipeMainScrollGesture(gestureType, totalShiftDist, _releaseAnimData);
2059
- if (itemChanged) {
2060
- return;
2061
- }
2062
- gestureType = 'zoomPointerUp';
2063
- }
2064
-
2065
- // prevent zoom/pan animation when main scroll animation runs
2066
- if (_mainScrollAnimating) {
2067
- return;
2068
- }
2069
-
2070
- // Complete simple zoom gesture (reset zoom level if it's out of the bounds)
2071
- if (gestureType !== 'swipe') {
2072
- _completeZoomGesture();
2073
- return;
2074
- }
2075
-
2076
- // Complete pan gesture if main scroll is not shifted, and it's possible to pan current image
2077
- if (!_mainScrollShifted && _currZoomLevel > self.currItem.fitRatio) {
2078
- _completePanGesture(_releaseAnimData);
2079
- }
2080
- },
2081
- // Returns object with data about gesture
2082
- // It's created only once and then reused
2083
- _initDragReleaseAnimationData = function () {
2084
- // temp local vars
2085
- var lastFlickDuration, tempReleasePos;
2086
-
2087
- // s = this
2088
- var s = {
2089
- lastFlickOffset: {},
2090
- lastFlickDist: {},
2091
- lastFlickSpeed: {},
2092
- slowDownRatio: {},
2093
- slowDownRatioReverse: {},
2094
- speedDecelerationRatio: {},
2095
- speedDecelerationRatioAbs: {},
2096
- distanceOffset: {},
2097
- backAnimDestination: {},
2098
- backAnimStarted: {},
2099
- calculateSwipeSpeed: function (axis) {
2100
- if (_posPoints.length > 1) {
2101
- lastFlickDuration = _getCurrentTime() - _gestureCheckSpeedTime + 50;
2102
- tempReleasePos = _posPoints[_posPoints.length - 2][axis];
2103
- } else {
2104
- lastFlickDuration = _getCurrentTime() - _gestureStartTime; // total gesture duration
2105
- tempReleasePos = _startPoint[axis];
2106
- }
2107
- s.lastFlickOffset[axis] = _currPoint[axis] - tempReleasePos;
2108
- s.lastFlickDist[axis] = Math.abs(s.lastFlickOffset[axis]);
2109
- if (s.lastFlickDist[axis] > 20) {
2110
- s.lastFlickSpeed[axis] = s.lastFlickOffset[axis] / lastFlickDuration;
2111
- } else {
2112
- s.lastFlickSpeed[axis] = 0;
2113
- }
2114
- if (Math.abs(s.lastFlickSpeed[axis]) < 0.1) {
2115
- s.lastFlickSpeed[axis] = 0;
2116
- }
2117
-
2118
- s.slowDownRatio[axis] = 0.95;
2119
- s.slowDownRatioReverse[axis] = 1 - s.slowDownRatio[axis];
2120
- s.speedDecelerationRatio[axis] = 1;
2121
- },
2122
-
2123
- calculateOverBoundsAnimOffset: function (axis, speed) {
2124
- if (!s.backAnimStarted[axis]) {
2125
- if (_panOffset[axis] > _currPanBounds.min[axis]) {
2126
- s.backAnimDestination[axis] = _currPanBounds.min[axis];
2127
- } else if (_panOffset[axis] < _currPanBounds.max[axis]) {
2128
- s.backAnimDestination[axis] = _currPanBounds.max[axis];
2129
- }
2130
-
2131
- if (s.backAnimDestination[axis] !== undefined) {
2132
- s.slowDownRatio[axis] = 0.7;
2133
- s.slowDownRatioReverse[axis] = 1 - s.slowDownRatio[axis];
2134
- if (s.speedDecelerationRatioAbs[axis] < 0.05) {
2135
- s.lastFlickSpeed[axis] = 0;
2136
- s.backAnimStarted[axis] = true;
2137
-
2138
- _animateProp(
2139
- 'bounceZoomPan' + axis,
2140
- _panOffset[axis],
2141
- s.backAnimDestination[axis],
2142
- speed || 300,
2143
- framework.easing.sine.out,
2144
- function (pos) {
2145
- _panOffset[axis] = pos;
2146
- _applyCurrentZoomPan();
2147
- }
2148
- );
2149
- }
2150
- }
2151
- }
2152
- },
2153
-
2154
- // Reduces the speed by slowDownRatio (per 10ms)
2155
- calculateAnimOffset: function (axis) {
2156
- if (!s.backAnimStarted[axis]) {
2157
- s.speedDecelerationRatio[axis] =
2158
- s.speedDecelerationRatio[axis] *
2159
- (s.slowDownRatio[axis] + s.slowDownRatioReverse[axis] - (s.slowDownRatioReverse[axis] * s.timeDiff) / 10);
2160
-
2161
- s.speedDecelerationRatioAbs[axis] = Math.abs(s.lastFlickSpeed[axis] * s.speedDecelerationRatio[axis]);
2162
- s.distanceOffset[axis] = s.lastFlickSpeed[axis] * s.speedDecelerationRatio[axis] * s.timeDiff;
2163
- _panOffset[axis] += s.distanceOffset[axis];
2164
- }
2165
- },
2166
-
2167
- panAnimLoop: function () {
2168
- if (_animations.zoomPan) {
2169
- _animations.zoomPan.raf = _requestAF(s.panAnimLoop);
2170
-
2171
- s.now = _getCurrentTime();
2172
- s.timeDiff = s.now - s.lastNow;
2173
- s.lastNow = s.now;
2174
-
2175
- s.calculateAnimOffset('x');
2176
- s.calculateAnimOffset('y');
2177
-
2178
- _applyCurrentZoomPan();
2179
-
2180
- s.calculateOverBoundsAnimOffset('x');
2181
- s.calculateOverBoundsAnimOffset('y');
2182
-
2183
- if (s.speedDecelerationRatioAbs.x < 0.05 && s.speedDecelerationRatioAbs.y < 0.05) {
2184
- // round pan position
2185
- _panOffset.x = Math.round(_panOffset.x);
2186
- _panOffset.y = Math.round(_panOffset.y);
2187
- _applyCurrentZoomPan();
2188
-
2189
- _stopAnimation('zoomPan');
2190
- return;
2191
- }
2192
- }
2193
- }
2194
- };
2195
- return s;
2196
- },
2197
- _completePanGesture = function (animData) {
2198
- // calculate swipe speed for Y axis (paanning)
2199
- animData.calculateSwipeSpeed('y');
2200
-
2201
- _currPanBounds = self.currItem.bounds;
2202
-
2203
- animData.backAnimDestination = {};
2204
- animData.backAnimStarted = {};
2205
-
2206
- // Avoid acceleration animation if speed is too low
2207
- if (Math.abs(animData.lastFlickSpeed.x) <= 0.05 && Math.abs(animData.lastFlickSpeed.y) <= 0.05) {
2208
- animData.speedDecelerationRatioAbs.x = animData.speedDecelerationRatioAbs.y = 0;
2209
-
2210
- // Run pan drag release animation. E.g. if you drag image and release finger without momentum.
2211
- animData.calculateOverBoundsAnimOffset('x');
2212
- animData.calculateOverBoundsAnimOffset('y');
2213
- return true;
2214
- }
2215
-
2216
- // Animation loop that controls the acceleration after pan gesture ends
2217
- _registerStartAnimation('zoomPan');
2218
- animData.lastNow = _getCurrentTime();
2219
- animData.panAnimLoop();
2220
- },
2221
- _finishSwipeMainScrollGesture = function (gestureType, totalShiftDist, _releaseAnimData) {
2222
- var itemChanged;
2223
- if (!_mainScrollAnimating) {
2224
- _currZoomedItemIndex = _currentItemIndex;
2225
- }
2226
-
2227
- var itemsDiff;
2228
-
2229
- if (gestureType === 'swipe') {
2230
- var isFastLastFlick = _releaseAnimData.lastFlickDist.x < 10;
2231
-
2232
- // if container is shifted for more than MIN_SWIPE_DISTANCE,
2233
- // and last flick gesture was in right direction
2234
- if (totalShiftDist > MIN_SWIPE_DISTANCE && (isFastLastFlick || _releaseAnimData.lastFlickOffset.x > 20)) {
2235
- // go to prev item
2236
- itemsDiff = -1;
2237
- } else if (totalShiftDist < -MIN_SWIPE_DISTANCE && (isFastLastFlick || _releaseAnimData.lastFlickOffset.x < -20)) {
2238
- // go to next item
2239
- itemsDiff = 1;
2240
- }
2241
- }
2242
-
2243
- var nextCircle;
2244
-
2245
- if (itemsDiff) {
2246
- _currentItemIndex += itemsDiff;
2247
-
2248
- if (_currentItemIndex < 0) {
2249
- _currentItemIndex = _options.loop ? _getNumItems() - 1 : 0;
2250
- nextCircle = true;
2251
- } else if (_currentItemIndex >= _getNumItems()) {
2252
- _currentItemIndex = _options.loop ? 0 : _getNumItems() - 1;
2253
- nextCircle = true;
2254
- }
2255
-
2256
- if (!nextCircle || _options.loop) {
2257
- _indexDiff += itemsDiff;
2258
- _currPositionIndex -= itemsDiff;
2259
- itemChanged = true;
2260
- }
2261
- }
2262
-
2263
- var animateToX = _slideSize.x * _currPositionIndex;
2264
- var animateToDist = Math.abs(animateToX - _mainScrollPos.x);
2265
- var finishAnimDuration;
2266
-
2267
- if (!itemChanged && animateToX > _mainScrollPos.x !== _releaseAnimData.lastFlickSpeed.x > 0) {
2268
- // "return to current" duration, e.g. when dragging from slide 0 to -1
2269
- finishAnimDuration = 333;
2270
- } else {
2271
- finishAnimDuration =
2272
- Math.abs(_releaseAnimData.lastFlickSpeed.x) > 0 ? animateToDist / Math.abs(_releaseAnimData.lastFlickSpeed.x) : 333;
2273
-
2274
- finishAnimDuration = Math.min(finishAnimDuration, 400);
2275
- finishAnimDuration = Math.max(finishAnimDuration, 250);
2276
- }
2277
-
2278
- if (_currZoomedItemIndex === _currentItemIndex) {
2279
- itemChanged = false;
2280
- }
2281
-
2282
- _mainScrollAnimating = true;
2283
-
2284
- _shout('mainScrollAnimStart');
2285
-
2286
- _animateProp(
2287
- 'mainScroll',
2288
- _mainScrollPos.x,
2289
- animateToX,
2290
- finishAnimDuration,
2291
- framework.easing.cubic.out,
2292
- _moveMainScroll,
2293
- function () {
2294
- _stopAllAnimations();
2295
- _mainScrollAnimating = false;
2296
- _currZoomedItemIndex = -1;
2297
-
2298
- if (itemChanged || _currZoomedItemIndex !== _currentItemIndex) {
2299
- self.updateCurrItem();
2300
- }
2301
-
2302
- _shout('mainScrollAnimComplete');
2303
- }
2304
- );
2305
-
2306
- if (itemChanged) {
2307
- self.updateCurrItem(true);
2308
- }
2309
-
2310
- return itemChanged;
2311
- },
2312
- _calculateZoomLevel = function (touchesDistance) {
2313
- return (1 / _startPointsDistance) * touchesDistance * _startZoomLevel;
2314
- },
2315
- // Resets zoom if it's out of bounds
2316
- _completeZoomGesture = function () {
2317
- var destZoomLevel = _currZoomLevel,
2318
- minZoomLevel = _getMinZoomLevel(),
2319
- maxZoomLevel = _getMaxZoomLevel();
2320
-
2321
- if (_currZoomLevel < minZoomLevel) {
2322
- destZoomLevel = minZoomLevel;
2323
- } else if (_currZoomLevel > maxZoomLevel) {
2324
- destZoomLevel = maxZoomLevel;
2325
- }
2326
-
2327
- var destOpacity = 1,
2328
- onUpdate,
2329
- initialOpacity = _bgOpacity;
2330
-
2331
- if (_opacityChanged && !_isZoomingIn && !_wasOverInitialZoom && _currZoomLevel < minZoomLevel) {
2332
- //_closedByScroll = true;
2333
- self.close();
2334
- return true;
2335
- }
2336
-
2337
- if (_opacityChanged) {
2338
- onUpdate = function (now) {
2339
- _applyBgOpacity((destOpacity - initialOpacity) * now + initialOpacity);
2340
- };
2341
- }
2342
-
2343
- self.zoomTo(destZoomLevel, 0, 200, framework.easing.cubic.out, onUpdate);
2344
- return true;
2345
- };
2346
-
2347
- _registerModule('Gestures', {
2348
- publicMethods: {
2349
- initGestures: function () {
2350
- // helper function that builds touch/pointer/mouse events
2351
- var addEventNames = function (pref, down, move, up, cancel) {
2352
- _dragStartEvent = pref + down;
2353
- _dragMoveEvent = pref + move;
2354
- _dragEndEvent = pref + up;
2355
- if (cancel) {
2356
- _dragCancelEvent = pref + cancel;
2357
- } else {
2358
- _dragCancelEvent = '';
2359
- }
2360
- };
2361
-
2362
- _pointerEventEnabled = _features.pointerEvent;
2363
- if (_pointerEventEnabled && _features.touch) {
2364
- // we don't need touch events, if browser supports pointer events
2365
- _features.touch = false;
2366
- }
2367
-
2368
- if (_pointerEventEnabled) {
2369
- if (navigator.msPointerEnabled) {
2370
- // IE10 pointer events are case-sensitive
2371
- addEventNames('MSPointer', 'Down', 'Move', 'Up', 'Cancel');
2372
- } else {
2373
- addEventNames('pointer', 'down', 'move', 'up', 'cancel');
2374
- }
2375
- } else if (_features.touch) {
2376
- addEventNames('touch', 'start', 'move', 'end', 'cancel');
2377
- _likelyTouchDevice = true;
2378
- } else {
2379
- addEventNames('mouse', 'down', 'move', 'up');
2380
- }
2381
-
2382
- _upMoveEvents = _dragMoveEvent + ' ' + _dragEndEvent + ' ' + _dragCancelEvent;
2383
- _downEvents = _dragStartEvent;
2384
-
2385
- if (_pointerEventEnabled && !_likelyTouchDevice) {
2386
- _likelyTouchDevice = navigator.maxTouchPoints > 1 || navigator.msMaxTouchPoints > 1;
2387
- }
2388
- // make variable public
2389
- self.likelyTouchDevice = _likelyTouchDevice;
2390
-
2391
- _globalEventHandlers[_dragStartEvent] = _onDragStart;
2392
- _globalEventHandlers[_dragMoveEvent] = _onDragMove;
2393
- _globalEventHandlers[_dragEndEvent] = _onDragRelease; // the Kraken
2394
-
2395
- if (_dragCancelEvent) {
2396
- _globalEventHandlers[_dragCancelEvent] = _globalEventHandlers[_dragEndEvent];
2397
- }
2398
-
2399
- // Bind mouse events on device with detected hardware touch support, in case it supports multiple types of input.
2400
- if (_features.touch) {
2401
- _downEvents += ' mousedown';
2402
- _upMoveEvents += ' mousemove mouseup';
2403
- _globalEventHandlers.mousedown = _globalEventHandlers[_dragStartEvent];
2404
- _globalEventHandlers.mousemove = _globalEventHandlers[_dragMoveEvent];
2405
- _globalEventHandlers.mouseup = _globalEventHandlers[_dragEndEvent];
2406
- }
2407
-
2408
- if (!_likelyTouchDevice) {
2409
- // don't allow pan to next slide from zoomed state on Desktop
2410
- _options.allowPanToNext = false;
2411
- }
2412
- }
2413
- }
2414
- });
2415
-
2416
-
2417
- /*>>gestures*/
2418
-
2419
- /*>>show-hide-transition*/
2420
- /**
2421
- * show-hide-transition.js:
2422
- *
2423
- * Manages initial opening or closing transition.
2424
- *
2425
- * If you're not planning to use transition for gallery at all,
2426
- * you may set options hideAnimationDuration and showAnimationDuration to 0,
2427
- * and just delete startAnimation function.
2428
- *
2429
- */
2430
-
2431
- var _showOrHideTimeout,
2432
- _showOrHide = function (item, img, out, completeFn) {
2433
- if (_showOrHideTimeout) {
2434
- clearTimeout(_showOrHideTimeout);
2435
- }
2436
-
2437
- _initialZoomRunning = true;
2438
- _initialContentSet = true;
2439
-
2440
- // dimensions of small thumbnail {x:,y:,w:}.
2441
- // Height is optional, as calculated based on large image.
2442
- var thumbBounds;
2443
- if (item.initialLayout) {
2444
- thumbBounds = item.initialLayout;
2445
- item.initialLayout = null;
2446
- } else {
2447
- thumbBounds = _options.getThumbBoundsFn && _options.getThumbBoundsFn(_currentItemIndex);
2448
- }
2449
-
2450
- var duration = out ? _options.hideAnimationDuration : _options.showAnimationDuration;
2451
-
2452
- var onComplete = function () {
2453
- _stopAnimation('initialZoom');
2454
- if (!out) {
2455
- _applyBgOpacity(1);
2456
- if (img) {
2457
- img.style.display = 'block';
2458
- }
2459
- framework.addClass(template, 'pswp--animated-in');
2460
- } else {
2461
- self.template.removeAttribute('style');
2462
- self.bg.removeAttribute('style');
2463
- }
2464
- _shout('initialZoom' + (out ? 'OutEnd' : 'InEnd'));
2465
-
2466
- if (completeFn) {
2467
- completeFn();
2468
- }
2469
- _initialZoomRunning = false;
2470
- };
2471
-
2472
- // if bounds aren't provided, just open gallery without animation
2473
- if (!duration || !thumbBounds || thumbBounds.x === undefined) {
2474
- _shout('initialZoom' + (out ? 'Out' : 'In'));
2475
-
2476
- if (!out) {
2477
- _currZoomLevel = item.initialZoomLevel;
2478
- _equalizePoints(_panOffset, item.initialPosition);
2479
- _applyCurrentZoomPan();
2480
-
2481
- template.style.opacity = 1;
2482
- _applyBgOpacity(1);
2483
- } else {
2484
- template.style.opacity = 0;
2485
- }
2486
-
2487
- if (duration) {
2488
- setTimeout(function () {
2489
- onComplete();
2490
- }, duration);
2491
- } else {
2492
- onComplete();
2493
- }
2494
-
2495
- return;
2496
- }
2497
-
2498
- var startAnimation = function () {
2499
- var closeWithRaf = _closedByScroll,
2500
- fadeEverything = !self.currItem.src || self.currItem.loadError || _options.showHideOpacity;
2501
-
2502
- // apply hw-acceleration to image
2503
- if (item.miniImg) {
2504
- item.miniImg.style.webkitBackfaceVisibility = 'hidden';
2505
- }
2506
-
2507
- if (!out) {
2508
- _currZoomLevel = thumbBounds.w / item.w;
2509
- _panOffset.x = thumbBounds.x;
2510
- _panOffset.y = thumbBounds.y - _initalWindowScrollY;
2511
-
2512
- self[fadeEverything ? 'template' : 'bg'].style.opacity = 0.001;
2513
- _applyCurrentZoomPan();
2514
- }
2515
-
2516
- _registerStartAnimation('initialZoom');
2517
-
2518
- if (out && !closeWithRaf) {
2519
- framework.removeClass(template, 'pswp--animated-in');
2520
- }
2521
-
2522
- if (fadeEverything) {
2523
- if (out) {
2524
- framework[(closeWithRaf ? 'remove' : 'add') + 'Class'](template, 'pswp--animate_opacity');
2525
- } else {
2526
- setTimeout(function () {
2527
- framework.addClass(template, 'pswp--animate_opacity');
2528
- }, 30);
2529
- }
2530
- }
2531
-
2532
- _showOrHideTimeout = setTimeout(
2533
- function () {
2534
- _shout('initialZoom' + (out ? 'Out' : 'In'));
2535
-
2536
- if (!out) {
2537
- // "in" animation always uses CSS transitions (instead of rAF).
2538
- // CSS transition work faster here,
2539
- // as developer may also want to animate other things,
2540
- // like ui on top of sliding area, which can be animated just via CSS
2541
-
2542
- _currZoomLevel = item.initialZoomLevel;
2543
- _equalizePoints(_panOffset, item.initialPosition);
2544
- _applyCurrentZoomPan();
2545
- _applyBgOpacity(1);
2546
-
2547
- if (fadeEverything) {
2548
- template.style.opacity = 1;
2549
- } else {
2550
- _applyBgOpacity(1);
2551
- }
2552
-
2553
- _showOrHideTimeout = setTimeout(onComplete, duration + 20);
2554
- } else {
2555
- // "out" animation uses rAF only when PhotoSwipe is closed by browser scroll, to recalculate position
2556
- var destZoomLevel = thumbBounds.w / item.w,
2557
- initialPanOffset = {
2558
- x: _panOffset.x,
2559
- y: _panOffset.y
2560
- },
2561
- initialZoomLevel = _currZoomLevel,
2562
- initalBgOpacity = _bgOpacity,
2563
- onUpdate = function (now) {
2564
- if (now === 1) {
2565
- _currZoomLevel = destZoomLevel;
2566
- _panOffset.x = thumbBounds.x;
2567
- _panOffset.y = thumbBounds.y - _currentWindowScrollY;
2568
- } else {
2569
- _currZoomLevel = (destZoomLevel - initialZoomLevel) * now + initialZoomLevel;
2570
- _panOffset.x = (thumbBounds.x - initialPanOffset.x) * now + initialPanOffset.x;
2571
- _panOffset.y = (thumbBounds.y - _currentWindowScrollY - initialPanOffset.y) * now + initialPanOffset.y;
2572
- }
2573
-
2574
- _applyCurrentZoomPan();
2575
- if (fadeEverything) {
2576
- template.style.opacity = 1 - now;
2577
- } else {
2578
- _applyBgOpacity(initalBgOpacity - now * initalBgOpacity);
2579
- }
2580
- };
2581
-
2582
- if (closeWithRaf) {
2583
- _animateProp('initialZoom', 0, 1, duration, framework.easing.cubic.out, onUpdate, onComplete);
2584
- } else {
2585
- onUpdate(1);
2586
- _showOrHideTimeout = setTimeout(onComplete, duration + 20);
2587
- }
2588
- }
2589
- },
2590
- out ? 25 : 90
2591
- ); // Main purpose of this delay is to give browser time to paint and
2592
- // create composite layers of PhotoSwipe UI parts (background, controls, caption, arrows).
2593
- // Which avoids lag at the beginning of scale transition.
2594
- };
2595
- startAnimation();
2596
- };
2597
-
2598
-
2599
- /*>>show-hide-transition*/
2600
-
2601
- /*>>items-controller*/
2602
- /**
2603
- *
2604
- * Controller manages gallery items, their dimensions, and their content.
2605
- *
2606
- */
2607
-
2608
- var _items,
2609
- _tempPanAreaSize = {},
2610
- _imagesToAppendPool = [],
2611
- _initialContentSet,
2612
- _initialZoomRunning,
2613
- _controllerDefaultOptions = {
2614
- index: 0,
2615
- errorMsg: '<div class="pswp__error-msg"><a href="%url%" target="_blank">The image</a> could not be loaded.</div>',
2616
- forceProgressiveLoading: false, // TODO
2617
- preload: [1, 1],
2618
- getNumItemsFn: function () {
2619
- return _items.length;
2620
- }
2621
- };
2622
-
2623
- var _getItemAt,
2624
- _getNumItems,
2625
- _initialIsLoop,
2626
- _getZeroBounds = function () {
2627
- return {
2628
- center: {x: 0, y: 0},
2629
- max: {x: 0, y: 0},
2630
- min: {x: 0, y: 0}
2631
- };
2632
- },
2633
- _calculateSingleItemPanBounds = function (item, realPanElementW, realPanElementH) {
2634
- var bounds = item.bounds;
2635
-
2636
- // position of element when it's centered
2637
- bounds.center.x = Math.round((_tempPanAreaSize.x - realPanElementW) / 2);
2638
- bounds.center.y = Math.round((_tempPanAreaSize.y - realPanElementH) / 2) + item.vGap.top;
2639
-
2640
- // maximum pan position
2641
- bounds.max.x = realPanElementW > _tempPanAreaSize.x ? Math.round(_tempPanAreaSize.x - realPanElementW) : bounds.center.x;
2642
-
2643
- bounds.max.y =
2644
- realPanElementH > _tempPanAreaSize.y ? Math.round(_tempPanAreaSize.y - realPanElementH) + item.vGap.top : bounds.center.y;
2645
-
2646
- // minimum pan position
2647
- bounds.min.x = realPanElementW > _tempPanAreaSize.x ? 0 : bounds.center.x;
2648
- bounds.min.y = realPanElementH > _tempPanAreaSize.y ? item.vGap.top : bounds.center.y;
2649
- },
2650
- _calculateItemSize = function (item, viewportSize, zoomLevel) {
2651
- if (item.src && !item.loadError) {
2652
- var isInitial = !zoomLevel;
2653
-
2654
- if (isInitial) {
2655
- if (!item.vGap) {
2656
- item.vGap = {top: 0, bottom: 0};
2657
- }
2658
- // allows overriding vertical margin for individual items
2659
- _shout('parseVerticalMargin', item);
2660
- }
2661
-
2662
- _tempPanAreaSize.x = viewportSize.x;
2663
- _tempPanAreaSize.y = viewportSize.y - item.vGap.top - item.vGap.bottom;
2664
-
2665
- if (isInitial) {
2666
- var hRatio = _tempPanAreaSize.x / item.w;
2667
- var vRatio = _tempPanAreaSize.y / item.h;
2668
-
2669
- item.fitRatio = hRatio < vRatio ? hRatio : vRatio;
2670
- //item.fillRatio = hRatio > vRatio ? hRatio : vRatio;
2671
-
2672
- var scaleMode = _options.scaleMode;
2673
-
2674
- if (scaleMode === 'orig') {
2675
- zoomLevel = 1;
2676
- } else if (scaleMode === 'fit') {
2677
- zoomLevel = item.fitRatio;
2678
- }
2679
-
2680
- if (zoomLevel > 1) {
2681
- zoomLevel = 1;
2682
- }
2683
-
2684
- item.initialZoomLevel = zoomLevel;
2685
-
2686
- if (!item.bounds) {
2687
- // reuse bounds object
2688
- item.bounds = _getZeroBounds();
2689
- }
2690
- }
2691
-
2692
- if (!zoomLevel) {
2693
- return;
2694
- }
2695
-
2696
- _calculateSingleItemPanBounds(item, item.w * zoomLevel, item.h * zoomLevel);
2697
-
2698
- if (isInitial && zoomLevel === item.initialZoomLevel) {
2699
- item.initialPosition = item.bounds.center;
2700
- }
2701
-
2702
- return item.bounds;
2703
- } else {
2704
- item.w = item.h = 0;
2705
- item.initialZoomLevel = item.fitRatio = 1;
2706
- item.bounds = _getZeroBounds();
2707
- item.initialPosition = item.bounds.center;
2708
-
2709
- // if it's not image, we return zero bounds (content is not zoomable)
2710
- return item.bounds;
2711
- }
2712
- },
2713
- _appendImage = function (index, item, baseDiv, img, preventAnimation, keepPlaceholder) {
2714
- if (item.loadError) {
2715
- return;
2716
- }
2717
-
2718
- if (img) {
2719
- item.imageAppended = true;
2720
- _setImageSize(item, img, item === self.currItem && _renderMaxResolution);
2721
-
2722
- baseDiv.appendChild(img);
2723
-
2724
- if (keepPlaceholder) {
2725
- setTimeout(function () {
2726
- if (item && item.loaded && item.placeholder) {
2727
- item.placeholder.style.display = 'none';
2728
- item.placeholder = null;
2729
- }
2730
- }, 500);
2731
- }
2732
- }
2733
- },
2734
- _preloadImage = function (item) {
2735
- item.loading = true;
2736
- item.loaded = false;
2737
- var img = (item.img = framework.createEl('pswp__img', 'img'));
2738
- var onComplete = function () {
2739
- item.loading = false;
2740
- item.loaded = true;
2741
-
2742
- // set natural image size
2743
- if (item.autoSize) {
2744
- item.w = img.naturalWidth;
2745
- item.h = img.naturalHeight;
2746
- item.autoSize = false;
2747
- self.updateSize();
2748
- }
2749
-
2750
- if (item.loadComplete) {
2751
- item.loadComplete(item);
2752
- } else {
2753
- item.img = null; // no need to store image object
2754
- }
2755
- img.onload = img.onerror = null;
2756
- img = null;
2757
- };
2758
- img.onload = onComplete;
2759
- img.onerror = function () {
2760
- item.loadError = true;
2761
- onComplete();
2762
- };
2763
-
2764
- img.src = item.src; // + '?a=' + Math.random();
2765
-
2766
- return img;
2767
- },
2768
- _checkForError = function (item, cleanUp) {
2769
- if (item.src && item.loadError && item.container) {
2770
- if (cleanUp) {
2771
- framework.resetEl(item.container);
2772
- }
2773
-
2774
- item.container.innerHTML = _options.errorMsg.replace('%url%', item.src);
2775
- return true;
2776
- }
2777
- },
2778
- _setImageSize = function (item, img, maxRes) {
2779
- if (!item.src) {
2780
- return;
2781
- }
2782
-
2783
- if (!img) {
2784
- img = item.container.lastChild;
2785
- }
2786
-
2787
- var w = maxRes ? item.w : Math.round(item.w * item.fitRatio),
2788
- h = maxRes ? item.h : Math.round(item.h * item.fitRatio);
2789
-
2790
- // ensure correct aspect ratio
2791
- if (img.naturalHeight && img.naturalWidth) {
2792
- var newHeight = w * (img.naturalHeight / img.naturalWidth);
2793
- if (newHeight > h) {
2794
- var newWidth = h * (img.naturalWidth / img.naturalHeight);
2795
- img.style.marginLeft = (w - newWidth) / 2 + 'px';
2796
- w = newWidth;
2797
- } else {
2798
- img.style.marginTop = (h - newHeight) / 2 + 'px';
2799
- h = newHeight;
2800
- }
2801
- }
2802
-
2803
- if (item.placeholder && !item.loaded) {
2804
- item.placeholder.style.width = w + 'px';
2805
- item.placeholder.style.height = h + 'px';
2806
- }
2807
-
2808
- img.style.width = w + 'px';
2809
- img.style.height = h + 'px';
2810
- },
2811
- _appendImagesPool = function () {
2812
- if (_imagesToAppendPool.length) {
2813
- var poolItem;
2814
-
2815
- for (var i = 0; i < _imagesToAppendPool.length; i++) {
2816
- poolItem = _imagesToAppendPool[i];
2817
- if (poolItem.holder.index === poolItem.index) {
2818
- _appendImage(poolItem.index, poolItem.item, poolItem.baseDiv, poolItem.img, false, poolItem.clearPlaceholder);
2819
- }
2820
- }
2821
- _imagesToAppendPool = [];
2822
- }
2823
- };
2824
-
2825
- _registerModule('Controller', {
2826
- publicMethods: {
2827
- lazyLoadItem: function (index) {
2828
- index = _getLoopedId(index);
2829
- var item = _getItemAt(index);
2830
-
2831
- if (!item || ((item.loaded || item.loading) && !_itemsNeedUpdate)) {
2832
- return;
2833
- }
2834
-
2835
- _shout('gettingData', index, item);
2836
-
2837
- if (!item.src) {
2838
- return;
2839
- }
2840
-
2841
- _preloadImage(item);
2842
- },
2843
- initController: function () {
2844
- framework.extend(_options, _controllerDefaultOptions, true);
2845
- self.items = _items = items;
2846
- _getItemAt = self.getItemAt;
2847
- _getNumItems = _options.getNumItemsFn; //self.getNumItems;
2848
-
2849
- _initialIsLoop = _options.loop;
2850
- if (_getNumItems() < 3) {
2851
- _options.loop = false; // disable loop if less then 3 items
2852
- }
2853
-
2854
- _listen('beforeChange', function (diff) {
2855
- var p = _options.preload,
2856
- isNext = diff === null ? true : diff >= 0,
2857
- preloadBefore = Math.min(p[0], _getNumItems()),
2858
- preloadAfter = Math.min(p[1], _getNumItems()),
2859
- i;
2860
-
2861
- for (i = 1; i <= (isNext ? preloadAfter : preloadBefore); i++) {
2862
- self.lazyLoadItem(_currentItemIndex + i);
2863
- }
2864
- for (i = 1; i <= (isNext ? preloadBefore : preloadAfter); i++) {
2865
- self.lazyLoadItem(_currentItemIndex - i);
2866
- }
2867
- });
2868
-
2869
- _listen('initialLayout', function () {
2870
- self.currItem.initialLayout = _options.getThumbBoundsFn && _options.getThumbBoundsFn(_currentItemIndex);
2871
- });
2872
-
2873
- _listen('mainScrollAnimComplete', _appendImagesPool);
2874
- _listen('initialZoomInEnd', _appendImagesPool);
2875
-
2876
- _listen('destroy', function () {
2877
- var item;
2878
- for (var i = 0; i < _items.length; i++) {
2879
- item = _items[i];
2880
- // remove reference to DOM elements, for GC
2881
- if (item.container) {
2882
- item.container = null;
2883
- }
2884
- if (item.placeholder) {
2885
- item.placeholder = null;
2886
- }
2887
- if (item.img) {
2888
- item.img = null;
2889
- }
2890
- if (item.preloader) {
2891
- item.preloader = null;
2892
- }
2893
- if (item.loadError) {
2894
- item.loaded = item.loadError = false;
2895
- }
2896
- }
2897
- _imagesToAppendPool = null;
2898
- });
2899
- },
2900
-
2901
- getItemAt: function (index) {
2902
- if (index >= 0) {
2903
- var item = _items[index] !== undefined ? _items[index] : false;
2904
- if (item && item.autoSize) {
2905
- if (item.w == null) {
2906
- item.w = 0;
2907
- }
2908
- if (item.h == null) {
2909
- item.h = 0;
2910
- }
2911
- }
2912
- return item;
2913
- }
2914
- return false;
2915
- },
2916
-
2917
- allowProgressiveImg: function () {
2918
- // 1. Progressive image loading isn't working on webkit/blink
2919
- // when hw-acceleration (e.g. translateZ) is applied to IMG element.
2920
- // That's why in PhotoSwipe parent element gets zoom transform, not image itself.
2921
- //
2922
- // 2. Progressive image loading sometimes blinks in webkit/blink when applying animation to parent element.
2923
- // That's why it's disabled on touch devices (mainly because of swipe transition)
2924
- //
2925
- // 3. Progressive image loading sometimes doesn't work in IE (up to 11).
2926
-
2927
- // Don't allow progressive loading on non-large touch devices
2928
- return _options.forceProgressiveLoading || !_likelyTouchDevice || _options.mouseUsed || screen.width > 1200;
2929
- // 1200 - to eliminate touch devices with large screen (like Chromebook Pixel)
2930
- },
2931
-
2932
- setContent: function (holder, index) {
2933
- if (_options.loop) {
2934
- index = _getLoopedId(index);
2935
- }
2936
-
2937
- var prevItem = self.getItemAt(holder.index);
2938
- if (prevItem) {
2939
- prevItem.container = null;
2940
- }
2941
-
2942
- var item = self.getItemAt(index),
2943
- img;
2944
-
2945
- if (!item) {
2946
- framework.resetEl(holder.el);
2947
- return;
2948
- }
2949
-
2950
- // allow to override data
2951
- _shout('gettingData', index, item);
2952
-
2953
- holder.index = index;
2954
- holder.item = item;
2955
-
2956
- // base container DIV is created only once for each of 3 holders
2957
- var baseDiv = (item.container = framework.createEl('pswp__zoom-wrap'));
2958
-
2959
- if (!item.src && item.html) {
2960
- if (item.html.tagName) {
2961
- baseDiv.appendChild(item.html);
2962
- } else {
2963
- baseDiv.innerHTML = item.html;
2964
- }
2965
- }
2966
-
2967
- _checkForError(item);
2968
-
2969
- _calculateItemSize(item, _viewportSize);
2970
-
2971
- if (item.src && !item.loadError && !item.loaded) {
2972
- item.loadComplete = function (item) {
2973
- // gallery closed before image finished loading
2974
- if (!_isOpen) {
2975
- return;
2976
- }
2977
-
2978
- // check if holder hasn't changed while image was loading
2979
- if (holder && holder.index === index) {
2980
- if (_checkForError(item, true)) {
2981
- item.loadComplete = item.img = null;
2982
- _calculateItemSize(item, _viewportSize);
2983
- _applyZoomPanToItem(item);
2984
-
2985
- if (holder.index === _currentItemIndex) {
2986
- // recalculate dimensions
2987
- self.updateCurrZoomItem();
2988
- }
2989
- return;
2990
- }
2991
- if (!item.imageAppended) {
2992
- if (_features.transform && (_mainScrollAnimating || _initialZoomRunning)) {
2993
- _imagesToAppendPool.push({
2994
- item: item,
2995
- baseDiv: baseDiv,
2996
- img: item.img,
2997
- index: index,
2998
- holder: holder,
2999
- clearPlaceholder: true
3000
- });
3001
- } else {
3002
- _appendImage(index, item, baseDiv, item.img, _mainScrollAnimating || _initialZoomRunning, true);
3003
- }
3004
- } else {
3005
- // remove preloader & mini-img
3006
- if (!_initialZoomRunning && item.placeholder) {
3007
- item.placeholder.style.display = 'none';
3008
- item.placeholder = null;
3009
- }
3010
- }
3011
- }
3012
-
3013
- item.loadComplete = null;
3014
- item.img = null; // no need to store image element after it's added
3015
-
3016
- _shout('imageLoadComplete', index, item);
3017
- };
3018
-
3019
- if (framework.features.transform) {
3020
- var placeholderClassName = 'pswp__img pswp__img--placeholder';
3021
- placeholderClassName += item.msrc ? '' : ' pswp__img--placeholder--blank';
3022
-
3023
- var placeholder = framework.createEl(placeholderClassName, item.msrc ? 'img' : '');
3024
- if (item.msrc) {
3025
- placeholder.src = item.msrc;
3026
- }
3027
-
3028
- _setImageSize(item, placeholder);
3029
-
3030
- baseDiv.appendChild(placeholder);
3031
- item.placeholder = placeholder;
3032
- }
3033
-
3034
- if (!item.loading) {
3035
- _preloadImage(item);
3036
- }
3037
-
3038
- if (self.allowProgressiveImg()) {
3039
- // just append image
3040
- if (!_initialContentSet && _features.transform) {
3041
- _imagesToAppendPool.push({
3042
- item: item,
3043
- baseDiv: baseDiv,
3044
- img: item.img,
3045
- index: index,
3046
- holder: holder
3047
- });
3048
- } else {
3049
- _appendImage(index, item, baseDiv, item.img, true, true);
3050
- }
3051
- }
3052
- } else if (item.src && !item.loadError) {
3053
- // image object is created every time, due to bugs of image loading & delay when switching images
3054
- img = framework.createEl('pswp__img', 'img');
3055
- img.style.opacity = 1;
3056
- img.src = item.src;
3057
- _setImageSize(item, img);
3058
- _appendImage(index, item, baseDiv, img, true);
3059
- }
3060
-
3061
- if (!_initialContentSet && index === _currentItemIndex) {
3062
- _currZoomElementStyle = baseDiv.style;
3063
- _showOrHide(item, img || item.img);
3064
- } else {
3065
- _applyZoomPanToItem(item);
3066
- }
3067
-
3068
- framework.resetEl(holder.el);
3069
- holder.el.appendChild(baseDiv);
3070
- },
3071
-
3072
- cleanSlide: function (item) {
3073
- if (item.img) {
3074
- item.img.onload = item.img.onerror = null;
3075
- }
3076
- item.loaded = item.loading = item.img = item.imageAppended = false;
3077
- }
3078
- }
3079
- });
3080
-
3081
-
3082
- /*>>items-controller*/
3083
-
3084
- /*>>tap*/
3085
- /**
3086
- * tap.js:
3087
- *
3088
- * Displatches tap and double-tap events.
3089
- *
3090
- */
3091
-
3092
- var tapTimer,
3093
- tapReleasePoint = {},
3094
- _dispatchTapEvent = function (origEvent, releasePoint, pointerType) {
3095
- var e = document.createEvent('CustomEvent'),
3096
- eDetail = {
3097
- origEvent: origEvent,
3098
- pointerType: pointerType || 'touch',
3099
- releasePoint: releasePoint,
3100
- target: origEvent.target,
3101
- rightClick: pointerType === 'mouse' && origEvent.which === 3
3102
- };
3103
-
3104
- e.initCustomEvent('pswpTap', true, true, eDetail);
3105
- origEvent.target.dispatchEvent(e);
3106
- };
3107
-
3108
- _registerModule('Tap', {
3109
- publicMethods: {
3110
- initTap: function () {
3111
- _listen('firstTouchStart', self.onTapStart);
3112
- _listen('touchRelease', self.onTapRelease);
3113
- _listen('destroy', function () {
3114
- tapReleasePoint = {};
3115
- tapTimer = null;
3116
- });
3117
- },
3118
- onTapStart: function (touchList) {
3119
- if (touchList.length > 1) {
3120
- clearTimeout(tapTimer);
3121
- tapTimer = null;
3122
- }
3123
- },
3124
- onTapRelease: function (e, releasePoint) {
3125
- if (!releasePoint) {
3126
- return;
3127
- }
3128
-
3129
- if (!_moved && !_isMultitouch && !_numAnimations && self.container.contains(e.target)) {
3130
- var p0 = releasePoint;
3131
- if (tapTimer) {
3132
- clearTimeout(tapTimer);
3133
- tapTimer = null;
3134
-
3135
- // Check if taped on the same place
3136
- if (_isNearbyPoints(p0, tapReleasePoint)) {
3137
- _shout('doubleTap', p0);
3138
- return;
3139
- }
3140
- }
3141
-
3142
- if (releasePoint.type === 'mouse') {
3143
- _dispatchTapEvent(e, releasePoint, 'mouse');
3144
- return;
3145
- }
3146
-
3147
- // Fix for share buttons zooming image.
3148
- // @see https://github.com/dimsemenov/PhotoSwipe/issues/1198
3149
- var clickedTagName = e.target.tagName.toUpperCase();
3150
- if (clickedTagName === 'A') {
3151
- return;
3152
- }
3153
-
3154
- // avoid double tap delay on buttons and elements that have class pswp__single-tap
3155
- if (clickedTagName === 'BUTTON' || framework.hasClass(e.target, 'pswp__single-tap')) {
3156
- _dispatchTapEvent(e, releasePoint);
3157
- return;
3158
- }
3159
-
3160
- _equalizePoints(tapReleasePoint, p0);
3161
-
3162
- tapTimer = setTimeout(function () {
3163
- _dispatchTapEvent(e, releasePoint);
3164
- tapTimer = null;
3165
- }, 300);
3166
- }
3167
- }
3168
- }
3169
- });
3170
-
3171
-
3172
- /*>>tap*/
3173
-
3174
- /*>>desktop-zoom*/
3175
- /**
3176
- *
3177
- * desktop-zoom.js:
3178
- *
3179
- * - Binds mousewheel event for paning zoomed image.
3180
- * - Manages "dragging", "zoomed-in", "zoom-out" classes.
3181
- * (which are used for cursors and zoom icon)
3182
- * - Adds toggleDesktopZoom function.
3183
- *
3184
- */
3185
-
3186
- var _wheelDelta;
3187
-
3188
- _registerModule('DesktopZoom', {
3189
- publicMethods: {
3190
- initDesktopZoom: function () {
3191
- if (_oldIE) {
3192
- // no zoom for old IE (<=8)
3193
- return;
3194
- }
3195
-
3196
- if (_likelyTouchDevice) {
3197
- // if detected hardware touch support, we wait until mouse is used,
3198
- // and only then apply desktop-zoom features
3199
- _listen('mouseUsed', function () {
3200
- self.setupDesktopZoom();
3201
- });
3202
- } else {
3203
- self.setupDesktopZoom(true);
3204
- }
3205
- },
3206
-
3207
- setupDesktopZoom: function (onInit) {
3208
- _wheelDelta = {};
3209
-
3210
- var events = 'wheel mousewheel DOMMouseScroll';
3211
-
3212
- _listen('bindEvents', function () {
3213
- framework.bind(template, events, self.handleMouseWheel);
3214
- });
3215
-
3216
- _listen('unbindEvents', function () {
3217
- if (_wheelDelta) {
3218
- framework.unbind(template, events, self.handleMouseWheel);
3219
- }
3220
- });
3221
-
3222
- self.mouseZoomedIn = false;
3223
-
3224
- var hasDraggingClass,
3225
- updateZoomable = function () {
3226
- if (self.mouseZoomedIn) {
3227
- framework.removeClass(template, 'pswp--zoomed-in');
3228
- self.mouseZoomedIn = false;
3229
- }
3230
- if (_currZoomLevel < 1) {
3231
- framework.addClass(template, 'pswp--zoom-allowed');
3232
- } else {
3233
- framework.removeClass(template, 'pswp--zoom-allowed');
3234
- }
3235
- removeDraggingClass();
3236
- },
3237
- removeDraggingClass = function () {
3238
- if (hasDraggingClass) {
3239
- framework.removeClass(template, 'pswp--dragging');
3240
- hasDraggingClass = false;
3241
- }
3242
- };
3243
-
3244
- _listen('resize', updateZoomable);
3245
- _listen('afterChange', updateZoomable);
3246
- _listen('pointerDown', function () {
3247
- if (self.mouseZoomedIn) {
3248
- hasDraggingClass = true;
3249
- framework.addClass(template, 'pswp--dragging');
3250
- }
3251
- });
3252
- _listen('pointerUp', removeDraggingClass);
3253
-
3254
- if (!onInit) {
3255
- updateZoomable();
3256
- }
3257
- },
3258
-
3259
- handleMouseWheel: function (e) {
3260
- if (_currZoomLevel <= self.currItem.fitRatio) {
3261
- if (_options.modal) {
3262
- if (!_options.closeOnScroll || _numAnimations || _isDragging) {
3263
- e.preventDefault();
3264
- } else if (_transformKey && Math.abs(e.deltaY) > 2) {
3265
- // close PhotoSwipe
3266
- // if browser supports transforms & scroll changed enough
3267
- _closedByScroll = true;
3268
- self.close();
3269
- }
3270
- }
3271
- return true;
3272
- }
3273
-
3274
- // allow just one event to fire
3275
- e.stopPropagation();
3276
-
3277
- // https://developer.mozilla.org/en-US/docs/Web/Events/wheel
3278
- _wheelDelta.x = 0;
3279
-
3280
- if ('deltaX' in e) {
3281
- if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {
3282
- // 18 - average line height
3283
- _wheelDelta.x = e.deltaX * 18;
3284
- _wheelDelta.y = e.deltaY * 18;
3285
- } else {
3286
- _wheelDelta.x = e.deltaX;
3287
- _wheelDelta.y = e.deltaY;
3288
- }
3289
- } else if ('wheelDelta' in e) {
3290
- if (e.wheelDeltaX) {
3291
- _wheelDelta.x = -0.16 * e.wheelDeltaX;
3292
- }
3293
- if (e.wheelDeltaY) {
3294
- _wheelDelta.y = -0.16 * e.wheelDeltaY;
3295
- } else {
3296
- _wheelDelta.y = -0.16 * e.wheelDelta;
3297
- }
3298
- } else if ('detail' in e) {
3299
- _wheelDelta.y = e.detail;
3300
- } else {
3301
- return;
3302
- }
3303
-
3304
- _calculatePanBounds(_currZoomLevel, true);
3305
-
3306
- var newPanX = _panOffset.x - _wheelDelta.x,
3307
- newPanY = _panOffset.y - _wheelDelta.y;
3308
-
3309
- // only prevent scrolling in nonmodal mode when not at edges
3310
- if (
3311
- _options.modal ||
3312
- (newPanX <= _currPanBounds.min.x &&
3313
- newPanX >= _currPanBounds.max.x &&
3314
- newPanY <= _currPanBounds.min.y &&
3315
- newPanY >= _currPanBounds.max.y)
3316
- ) {
3317
- e.preventDefault();
3318
- }
3319
-
3320
- // TODO: use rAF instead of mousewheel?
3321
- self.panTo(newPanX, newPanY);
3322
- },
3323
-
3324
- toggleDesktopZoom: function (centerPoint) {
3325
- centerPoint = centerPoint || {x: _viewportSize.x / 2 + _offset.x, y: _viewportSize.y / 2 + _offset.y};
3326
-
3327
- var doubleTapZoomLevel = _options.getDoubleTapZoom(true, self.currItem);
3328
- var zoomOut = _currZoomLevel === doubleTapZoomLevel;
3329
-
3330
- self.mouseZoomedIn = !zoomOut;
3331
-
3332
- self.zoomTo(zoomOut ? self.currItem.initialZoomLevel : doubleTapZoomLevel, centerPoint, 333);
3333
- framework[(!zoomOut ? 'add' : 'remove') + 'Class'](template, 'pswp--zoomed-in');
3334
- }
3335
- }
3336
- });
3337
-
3338
-
3339
- /*>>desktop-zoom*/
3340
-
3341
- /*>>history*/
3342
- /**
3343
- *
3344
- * history.js:
3345
- *
3346
- * - Back button to close gallery.
3347
- *
3348
- * - Unique URL for each slide: example.com/&pid=1&gid=3
3349
- * (where PID is picture index, and GID and gallery index)
3350
- *
3351
- * - Switch URL when slides change.
3352
- *
3353
- */
3354
-
3355
- var _historyDefaultOptions = {
3356
- history: true,
3357
- galleryUID: 1
3358
- };
3359
-
3360
- var _historyUpdateTimeout,
3361
- _hashChangeTimeout,
3362
- _hashAnimCheckTimeout,
3363
- _hashChangedByScript,
3364
- _hashChangedByHistory,
3365
- _hashReseted,
3366
- _initialHash,
3367
- _historyChanged,
3368
- _closedFromURL,
3369
- _urlChangedOnce,
3370
- _windowLoc,
3371
- _supportsPushState,
3372
- _getHash = function () {
3373
- return _windowLoc.hash.substring(1);
3374
- },
3375
- _cleanHistoryTimeouts = function () {
3376
- if (_historyUpdateTimeout) {
3377
- clearTimeout(_historyUpdateTimeout);
3378
- }
3379
-
3380
- if (_hashAnimCheckTimeout) {
3381
- clearTimeout(_hashAnimCheckTimeout);
3382
- }
3383
- },
3384
- // pid - Picture index
3385
- // gid - Gallery index
3386
- _parseItemIndexFromURL = function () {
3387
- var hash = _getHash(),
3388
- params = {};
3389
-
3390
- if (hash.length < 5) {
3391
- // pid=1
3392
- return params;
3393
- }
3394
-
3395
- var i,
3396
- vars = hash.split('&');
3397
- for (i = 0; i < vars.length; i++) {
3398
- if (!vars[i]) {
3399
- continue;
3400
- }
3401
- var pair = vars[i].split('=');
3402
- if (pair.length < 2) {
3403
- continue;
3404
- }
3405
- params[pair[0]] = pair[1];
3406
- }
3407
- if (_options.galleryPIDs) {
3408
- // detect custom pid in hash and search for it among the items collection
3409
- var searchfor = params.pid;
3410
- params.pid = 0; // if custom pid cannot be found, fallback to the first item
3411
- for (i = 0; i < _items.length; i++) {
3412
- if (_items[i].pid === searchfor) {
3413
- params.pid = i;
3414
- break;
3415
- }
3416
- }
3417
- } else {
3418
- params.pid = parseInt(params.pid, 10) - 1;
3419
- }
3420
- if (params.pid < 0) {
3421
- params.pid = 0;
3422
- }
3423
- return params;
3424
- },
3425
- _updateHash = function () {
3426
- if (_hashAnimCheckTimeout) {
3427
- clearTimeout(_hashAnimCheckTimeout);
3428
- }
3429
-
3430
- if (_numAnimations || _isDragging) {
3431
- // changing browser URL forces layout/paint in some browsers, which causes noticable lag during animation
3432
- // that's why we update hash only when no animations running
3433
- _hashAnimCheckTimeout = setTimeout(_updateHash, 500);
3434
- return;
3435
- }
3436
-
3437
- if (_hashChangedByScript) {
3438
- clearTimeout(_hashChangeTimeout);
3439
- } else {
3440
- _hashChangedByScript = true;
3441
- }
3442
-
3443
- var pid = _currentItemIndex + 1;
3444
- var item = _getItemAt(_currentItemIndex);
3445
- if (item.hasOwnProperty('pid')) {
3446
- // carry forward any custom pid assigned to the item
3447
- pid = item.pid;
3448
- }
3449
- var newHash = _initialHash + '&' + 'gid=' + _options.galleryUID + '&' + 'pid=' + pid;
3450
-
3451
- if (!_historyChanged) {
3452
- if (_windowLoc.hash.indexOf(newHash) === -1) {
3453
- _urlChangedOnce = true;
3454
- }
3455
- // first time - add new hisory record, then just replace
3456
- }
3457
-
3458
- var newURL = _windowLoc.href.split('#')[0] + '#' + newHash;
3459
-
3460
- if (_supportsPushState) {
3461
- if ('#' + newHash !== window.location.hash) {
3462
- history[_historyChanged ? 'replaceState' : 'pushState']('', document.title, newURL);
3463
- }
3464
- } else {
3465
- if (_historyChanged) {
3466
- _windowLoc.replace(newURL);
3467
- } else {
3468
- _windowLoc.hash = newHash;
3469
- }
3470
- }
3471
-
3472
- _historyChanged = true;
3473
- _hashChangeTimeout = setTimeout(function () {
3474
- _hashChangedByScript = false;
3475
- }, 60);
3476
- };
3477
-
3478
- _registerModule('History', {
3479
- publicMethods: {
3480
- initHistory: function () {
3481
- framework.extend(_options, _historyDefaultOptions, true);
3482
-
3483
- if (!_options.history) {
3484
- return;
3485
- }
3486
-
3487
- _windowLoc = window.location;
3488
- _urlChangedOnce = false;
3489
- _closedFromURL = false;
3490
- _historyChanged = false;
3491
- _initialHash = _getHash();
3492
- _supportsPushState = 'pushState' in history;
3493
-
3494
- if (_initialHash.indexOf('gid=') > -1) {
3495
- _initialHash = _initialHash.split('&gid=')[0];
3496
- _initialHash = _initialHash.split('?gid=')[0];
3497
- }
3498
-
3499
- _listen('afterChange', self.updateURL);
3500
- _listen('unbindEvents', function () {
3501
- framework.unbind(window, 'hashchange', self.onHashChange);
3502
- });
3503
-
3504
- var returnToOriginal = function () {
3505
- _hashReseted = true;
3506
- if (!_closedFromURL) {
3507
- if (_urlChangedOnce) {
3508
- history.back();
3509
- } else {
3510
- if (_initialHash) {
3511
- _windowLoc.hash = _initialHash;
3512
- } else {
3513
- if (_supportsPushState) {
3514
- // remove hash from url without refreshing it or scrolling to top
3515
- history.pushState('', document.title, _windowLoc.pathname + _windowLoc.search);
3516
- } else {
3517
- _windowLoc.hash = '';
3518
- }
3519
- }
3520
- }
3521
- }
3522
-
3523
- _cleanHistoryTimeouts();
3524
- };
3525
-
3526
- _listen('unbindEvents', function () {
3527
- if (_closedByScroll) {
3528
- // if PhotoSwipe is closed by scroll, we go "back" before the closing animation starts
3529
- // this is done to keep the scroll position
3530
- returnToOriginal();
3531
- }
3532
- });
3533
- _listen('destroy', function () {
3534
- if (!_hashReseted) {
3535
- returnToOriginal();
3536
- }
3537
- });
3538
- _listen('firstUpdate', function () {
3539
- _currentItemIndex = _parseItemIndexFromURL().pid;
3540
- });
3541
-
3542
- var index = _initialHash.indexOf('pid=');
3543
- if (index > -1) {
3544
- _initialHash = _initialHash.substring(0, index);
3545
- if (_initialHash.slice(-1) === '&') {
3546
- _initialHash = _initialHash.slice(0, -1);
3547
- }
3548
- }
3549
-
3550
- setTimeout(function () {
3551
- if (_isOpen) {
3552
- // hasn't destroyed yet
3553
- framework.bind(window, 'hashchange', self.onHashChange);
3554
- }
3555
- }, 40);
3556
- },
3557
- onHashChange: function () {
3558
- if (_getHash() === _initialHash) {
3559
- _closedFromURL = true;
3560
- self.close();
3561
- return;
3562
- }
3563
- if (!_hashChangedByScript) {
3564
- _hashChangedByHistory = true;
3565
- self.goTo(_parseItemIndexFromURL().pid);
3566
- _hashChangedByHistory = false;
3567
- }
3568
- },
3569
- updateURL: function () {
3570
- // Delay the update of URL, to avoid lag during transition,
3571
- // and to not to trigger actions like "refresh page sound" or "blinking favicon" to often
3572
-
3573
- _cleanHistoryTimeouts();
3574
-
3575
- if (_hashChangedByHistory) {
3576
- return;
3577
- }
3578
-
3579
- if (!_historyChanged) {
3580
- _updateHash(); // first time
3581
- } else {
3582
- _historyUpdateTimeout = setTimeout(_updateHash, 800);
3583
- }
3584
- }
3585
- }
3586
- });
3587
-
3588
-
3589
- /*>>history*/
3590
- framework.extend(self, publicMethods); };
3591
- return PhotoSwipe;
3592
- });