phcthemes_admin_panel_pack 5.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/smarty/core.js +28154 -0
  3. data/app/assets/javascripts/smarty/core.min.js +2 -0
  4. data/app/assets/javascripts/smarty/core.sow_builder.js +84 -0
  5. data/app/assets/javascripts/smarty/core.sow_builder.min.js +1 -0
  6. data/app/assets/javascripts/smarty/phcthemes_admin_panel_pack_smarty.js +3 -0
  7. data/app/assets/javascripts/smarty/vendor.chartjs.js +20776 -0
  8. data/app/assets/javascripts/smarty/vendor.chartjs.min.js +1 -0
  9. data/app/assets/javascripts/smarty/vendor.cocoen.js +1 -0
  10. data/app/assets/javascripts/smarty/vendor.cocoen.min.js +1 -0
  11. data/app/assets/javascripts/smarty/vendor.colorpicker.js +3 -0
  12. data/app/assets/javascripts/smarty/vendor.colorpicker.min.js +1 -0
  13. data/app/assets/javascripts/smarty/vendor.datatables.js +42928 -0
  14. data/app/assets/javascripts/smarty/vendor.datatables.min.js +1 -0
  15. data/app/assets/javascripts/smarty/vendor.datepicker.js +2039 -0
  16. data/app/assets/javascripts/smarty/vendor.datepicker.min.js +1 -0
  17. data/app/assets/javascripts/smarty/vendor.daterangepicker.js +1578 -0
  18. data/app/assets/javascripts/smarty/vendor.daterangepicker.min.js +1 -0
  19. data/app/assets/javascripts/smarty/vendor.easypie.js +364 -0
  20. data/app/assets/javascripts/smarty/vendor.easypie.min.js +1 -0
  21. data/app/assets/javascripts/smarty/vendor.fancybox.js +5632 -0
  22. data/app/assets/javascripts/smarty/vendor.fancybox.min.js +1 -0
  23. data/app/assets/javascripts/smarty/vendor.flickity.js +4597 -0
  24. data/app/assets/javascripts/smarty/vendor.flickity.min.js +1 -0
  25. data/app/assets/javascripts/smarty/vendor.flot.js +11921 -0
  26. data/app/assets/javascripts/smarty/vendor.flot.min.js +1 -0
  27. data/app/assets/javascripts/smarty/vendor.fullcalendar.js +14597 -0
  28. data/app/assets/javascripts/smarty/vendor.fullcalendar.min.js +1 -0
  29. data/app/assets/javascripts/smarty/vendor.leaflet.js +6 -0
  30. data/app/assets/javascripts/smarty/vendor.leaflet.min.js +1 -0
  31. data/app/assets/javascripts/smarty/vendor.markdowneditor.js +7 -0
  32. data/app/assets/javascripts/smarty/vendor.markdowneditor.min.js +1 -0
  33. data/app/assets/javascripts/smarty/vendor.mediumeditor.js +7893 -0
  34. data/app/assets/javascripts/smarty/vendor.mediumeditor.min.js +1 -0
  35. data/app/assets/javascripts/smarty/vendor.pdfmake.js +79493 -0
  36. data/app/assets/javascripts/smarty/vendor.pdfmake.min.js +1 -0
  37. data/app/assets/javascripts/smarty/vendor.photoswipe.js +4595 -0
  38. data/app/assets/javascripts/smarty/vendor.photoswipe.min.js +1 -0
  39. data/app/assets/javascripts/smarty/vendor.prismjs.js +7219 -0
  40. data/app/assets/javascripts/smarty/vendor.prismjs.min.js +1 -0
  41. data/app/assets/javascripts/smarty/vendor.quilleditor.js +11562 -0
  42. data/app/assets/javascripts/smarty/vendor.quilleditor.min.js +1 -0
  43. data/app/assets/javascripts/smarty/vendor.sparkline.js +3068 -0
  44. data/app/assets/javascripts/smarty/vendor.sparkline.min.js +1 -0
  45. data/app/assets/javascripts/smarty/vendor.summernoteeditor.js +10235 -0
  46. data/app/assets/javascripts/smarty/vendor.summernoteeditor.min.js +1 -0
  47. data/app/assets/javascripts/smarty/vendor.swiper.js +9899 -0
  48. data/app/assets/javascripts/smarty/vendor.swiper.min.js +1 -0
  49. data/app/assets/javascripts/smarty/vendor_bundle.js +30514 -0
  50. data/app/assets/javascripts/smarty/vendor_bundle.min.js +2 -0
  51. data/app/assets/stylesheets/smarty/default/phcthemes_admin_panel_pack_smarty.scss +7 -0
  52. data/app/assets/stylesheets/smarty/theme/css/core.css +20170 -0
  53. data/app/assets/stylesheets/smarty/theme/css/core.min.css +2 -0
  54. data/app/assets/stylesheets/smarty/theme/css/vendor.chartjs.css +55 -0
  55. data/app/assets/stylesheets/smarty/theme/css/vendor.chartjs.min.css +1 -0
  56. data/app/assets/stylesheets/smarty/theme/css/vendor.cocoen.css +59 -0
  57. data/app/assets/stylesheets/smarty/theme/css/vendor.cocoen.min.css +1 -0
  58. data/app/assets/stylesheets/smarty/theme/css/vendor.colorpicker.css +1196 -0
  59. data/app/assets/stylesheets/smarty/theme/css/vendor.colorpicker.min.css +1 -0
  60. data/app/assets/stylesheets/smarty/theme/css/vendor.datatables.css +1258 -0
  61. data/app/assets/stylesheets/smarty/theme/css/vendor.datatables.min.css +1 -0
  62. data/app/assets/stylesheets/smarty/theme/css/vendor.datepicker.css +173 -0
  63. data/app/assets/stylesheets/smarty/theme/css/vendor.datepicker.min.css +1 -0
  64. data/app/assets/stylesheets/smarty/theme/css/vendor.daterangepicker.css +545 -0
  65. data/app/assets/stylesheets/smarty/theme/css/vendor.daterangepicker.min.css +1 -0
  66. data/app/assets/stylesheets/smarty/theme/css/vendor.fancybox.css +927 -0
  67. data/app/assets/stylesheets/smarty/theme/css/vendor.fancybox.min.css +1 -0
  68. data/app/assets/stylesheets/smarty/theme/css/vendor.flickity.css +263 -0
  69. data/app/assets/stylesheets/smarty/theme/css/vendor.flickity.min.css +1 -0
  70. data/app/assets/stylesheets/smarty/theme/css/vendor.flot.css +17 -0
  71. data/app/assets/stylesheets/smarty/theme/css/vendor.flot.min.css +1 -0
  72. data/app/assets/stylesheets/smarty/theme/css/vendor.fullcalendar.css +1685 -0
  73. data/app/assets/stylesheets/smarty/theme/css/vendor.fullcalendar.min.css +1 -0
  74. data/app/assets/stylesheets/smarty/theme/css/vendor.leaflet.css +653 -0
  75. data/app/assets/stylesheets/smarty/theme/css/vendor.leaflet.min.css +1 -0
  76. data/app/assets/stylesheets/smarty/theme/css/vendor.markdowneditor.css +7 -0
  77. data/app/assets/stylesheets/smarty/theme/css/vendor.markdowneditor.min.css +1 -0
  78. data/app/assets/stylesheets/smarty/theme/css/vendor.mediumeditor.css +308 -0
  79. data/app/assets/stylesheets/smarty/theme/css/vendor.mediumeditor.min.css +1 -0
  80. data/app/assets/stylesheets/smarty/theme/css/vendor.photoswipe.css +436 -0
  81. data/app/assets/stylesheets/smarty/theme/css/vendor.photoswipe.min.css +1 -0
  82. data/app/assets/stylesheets/smarty/theme/css/vendor.prismjs.css +364 -0
  83. data/app/assets/stylesheets/smarty/theme/css/vendor.prismjs.min.css +1 -0
  84. data/app/assets/stylesheets/smarty/theme/css/vendor.quilleditor.css +953 -0
  85. data/app/assets/stylesheets/smarty/theme/css/vendor.quilleditor.min.css +1 -0
  86. data/app/assets/stylesheets/smarty/theme/css/vendor.summernoteeditor.css +710 -0
  87. data/app/assets/stylesheets/smarty/theme/css/vendor.summernoteeditor.min.css +1 -0
  88. data/app/assets/stylesheets/smarty/theme/css/vendor.swiper.css +762 -0
  89. data/app/assets/stylesheets/smarty/theme/css/vendor.swiper.min.css +1 -0
  90. data/app/assets/stylesheets/smarty/theme/css/vendor_bundle.css +168 -0
  91. data/app/assets/stylesheets/smarty/theme/css/vendor_bundle.min.css +2 -0
  92. data/app/assets/stylesheets/smarty/theme/fonts/flaticon/Flaticon.eot +0 -0
  93. data/app/assets/stylesheets/smarty/theme/fonts/flaticon/Flaticon.svg +250 -0
  94. data/app/assets/stylesheets/smarty/theme/fonts/flaticon/Flaticon.ttf +0 -0
  95. data/app/assets/stylesheets/smarty/theme/fonts/flaticon/Flaticon.woff +0 -0
  96. data/app/assets/stylesheets/smarty/theme/fonts/flaticon/Flaticon.woff2 +0 -0
  97. data/app/assets/stylesheets/smarty/theme/fonts/summernote.eot +0 -0
  98. data/app/assets/stylesheets/smarty/theme/fonts/summernote.hash +1 -0
  99. data/app/assets/stylesheets/smarty/theme/fonts/summernote.ttf +0 -0
  100. data/app/assets/stylesheets/smarty/theme/fonts/summernote.woff +0 -0
  101. data/app/assets/stylesheets/smarty/theme/fonts/summernote.woff2 +0 -0
  102. data/app/assets/stylesheets/smarty/theme/images/credit_card/2co.svg +1 -0
  103. data/app/assets/stylesheets/smarty/theme/images/credit_card/amazon.svg +1 -0
  104. data/app/assets/stylesheets/smarty/theme/images/credit_card/amazon_pay_logo.svg +1 -0
  105. data/app/assets/stylesheets/smarty/theme/images/credit_card/american_express.svg +1 -0
  106. data/app/assets/stylesheets/smarty/theme/images/credit_card/apple_pay.svg +1 -0
  107. data/app/assets/stylesheets/smarty/theme/images/credit_card/bitcoin.svg +1 -0
  108. data/app/assets/stylesheets/smarty/theme/images/credit_card/dinners_club.svg +1 -0
  109. data/app/assets/stylesheets/smarty/theme/images/credit_card/discover.svg +1 -0
  110. data/app/assets/stylesheets/smarty/theme/images/credit_card/ebay.svg +1 -0
  111. data/app/assets/stylesheets/smarty/theme/images/credit_card/jcb.svg +1 -0
  112. data/app/assets/stylesheets/smarty/theme/images/credit_card/mastercard.svg +1 -0
  113. data/app/assets/stylesheets/smarty/theme/images/credit_card/paypal.svg +1 -0
  114. data/app/assets/stylesheets/smarty/theme/images/credit_card/paypal_logo.svg +1 -0
  115. data/app/assets/stylesheets/smarty/theme/images/credit_card/shopify.svg +1 -0
  116. data/app/assets/stylesheets/smarty/theme/images/credit_card/skrill.svg +1 -0
  117. data/app/assets/stylesheets/smarty/theme/images/credit_card/switch.svg +1 -0
  118. data/app/assets/stylesheets/smarty/theme/images/credit_card/visa.svg +1 -0
  119. data/app/assets/stylesheets/smarty/theme/images/credit_card/western_union.svg +1 -0
  120. data/app/assets/stylesheets/smarty/theme/images/flags.png +0 -0
  121. data/app/assets/stylesheets/smarty/theme/images/logo/logo_dark.svg +2 -0
  122. data/app/assets/stylesheets/smarty/theme/images/logo/logo_light.svg +2 -0
  123. data/app/assets/stylesheets/smarty/theme/images/logo/logo_sm.svg +1 -0
  124. data/app/assets/stylesheets/smarty/theme/images/manifest/icon_192x192.png +0 -0
  125. data/app/assets/stylesheets/smarty/theme/images/manifest/icon_512x512.png +0 -0
  126. data/app/assets/stylesheets/smarty/theme/images/manifest/manifest.json +20 -0
  127. data/app/assets/stylesheets/smarty/theme/images/masks/shape-line-lense.svg +1 -0
  128. data/lib/phcthemes_admin_panel_pack/version.rb +1 -1
  129. metadata +128 -2
@@ -0,0 +1,4595 @@
1
+ /*! PhotoSwipe - v4.1.3 - 2019-01-08
2
+ * http://photoswipe.com
3
+ * Copyright (c) 2019 Dmitry Semenov; */
4
+ (function (root, factory) {
5
+ if (typeof define === 'function' && define.amd) {
6
+ define(factory);
7
+ } else if (typeof exports === 'object') {
8
+ module.exports = factory();
9
+ } else {
10
+ root.PhotoSwipe = factory();
11
+ }
12
+ })(this, function () {
13
+
14
+ 'use strict';
15
+ var PhotoSwipe = function(template, UiClass, items, options){
16
+
17
+ /*>>framework-bridge*/
18
+ /**
19
+ *
20
+ * Set of generic functions used by gallery.
21
+ *
22
+ * You're free to modify anything here as long as functionality is kept.
23
+ *
24
+ */
25
+ var framework = {
26
+ features: null,
27
+ bind: function(target, type, listener, unbind) {
28
+ var methodName = (unbind ? 'remove' : 'add') + 'EventListener';
29
+ type = type.split(' ');
30
+ for(var i = 0; i < type.length; i++) {
31
+ if(type[i]) {
32
+ target[methodName]( type[i], listener, false);
33
+ }
34
+ }
35
+ },
36
+ isArray: function(obj) {
37
+ return (obj instanceof Array);
38
+ },
39
+ createEl: function(classes, tag) {
40
+ var el = document.createElement(tag || 'div');
41
+ if(classes) {
42
+ el.className = classes;
43
+ }
44
+ return el;
45
+ },
46
+ getScrollY: function() {
47
+ var yOffset = window.pageYOffset;
48
+ return yOffset !== undefined ? yOffset : document.documentElement.scrollTop;
49
+ },
50
+ unbind: function(target, type, listener) {
51
+ framework.bind(target,type,listener,true);
52
+ },
53
+ removeClass: function(el, className) {
54
+ var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
55
+ el.className = el.className.replace(reg, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
56
+ },
57
+ addClass: function(el, className) {
58
+ if( !framework.hasClass(el,className) ) {
59
+ el.className += (el.className ? ' ' : '') + className;
60
+ }
61
+ },
62
+ hasClass: function(el, className) {
63
+ return el.className && new RegExp('(^|\\s)' + className + '(\\s|$)').test(el.className);
64
+ },
65
+ getChildByClass: function(parentEl, childClassName) {
66
+ var node = parentEl.firstChild;
67
+ while(node) {
68
+ if( framework.hasClass(node, childClassName) ) {
69
+ return node;
70
+ }
71
+ node = node.nextSibling;
72
+ }
73
+ },
74
+ arraySearch: function(array, value, key) {
75
+ var i = array.length;
76
+ while(i--) {
77
+ if(array[i][key] === value) {
78
+ return i;
79
+ }
80
+ }
81
+ return -1;
82
+ },
83
+ extend: function(o1, o2, preventOverwrite) {
84
+ for (var prop in o2) {
85
+ if (o2.hasOwnProperty(prop)) {
86
+ if(preventOverwrite && o1.hasOwnProperty(prop)) {
87
+ continue;
88
+ }
89
+ o1[prop] = o2[prop];
90
+ }
91
+ }
92
+ },
93
+ easing: {
94
+ sine: {
95
+ out: function(k) {
96
+ return Math.sin(k * (Math.PI / 2));
97
+ },
98
+ inOut: function(k) {
99
+ return - (Math.cos(Math.PI * k) - 1) / 2;
100
+ }
101
+ },
102
+ cubic: {
103
+ out: function(k) {
104
+ return --k * k * k + 1;
105
+ }
106
+ }
107
+ /*
108
+ elastic: {
109
+ out: function ( k ) {
110
+
111
+ var s, a = 0.1, p = 0.4;
112
+ if ( k === 0 ) return 0;
113
+ if ( k === 1 ) return 1;
114
+ if ( !a || a < 1 ) { a = 1; s = p / 4; }
115
+ else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
116
+ return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
117
+
118
+ },
119
+ },
120
+ back: {
121
+ out: function ( k ) {
122
+ var s = 1.70158;
123
+ return --k * k * ( ( s + 1 ) * k + s ) + 1;
124
+ }
125
+ }
126
+ */
127
+ },
128
+
129
+ /**
130
+ *
131
+ * @return {object}
132
+ *
133
+ * {
134
+ * raf : request animation frame function
135
+ * caf : cancel animation frame function
136
+ * transfrom : transform property key (with vendor), or null if not supported
137
+ * oldIE : IE8 or below
138
+ * }
139
+ *
140
+ */
141
+ detectFeatures: function() {
142
+ if(framework.features) {
143
+ return framework.features;
144
+ }
145
+ var helperEl = framework.createEl(),
146
+ helperStyle = helperEl.style,
147
+ vendor = '',
148
+ features = {};
149
+
150
+ // IE8 and below
151
+ features.oldIE = document.all && !document.addEventListener;
152
+
153
+ features.touch = 'ontouchstart' in window;
154
+
155
+ if(window.requestAnimationFrame) {
156
+ features.raf = window.requestAnimationFrame;
157
+ features.caf = window.cancelAnimationFrame;
158
+ }
159
+
160
+ features.pointerEvent = !!(window.PointerEvent) || navigator.msPointerEnabled;
161
+
162
+ // fix false-positive detection of old Android in new IE
163
+ // (IE11 ua string contains "Android 4.0")
164
+
165
+ if(!features.pointerEvent) {
166
+
167
+ var ua = navigator.userAgent;
168
+
169
+ // Detect if device is iPhone or iPod and if it's older than iOS 8
170
+ // http://stackoverflow.com/a/14223920
171
+ //
172
+ // This detection is made because of buggy top/bottom toolbars
173
+ // that don't trigger window.resize event.
174
+ // For more info refer to _isFixedPosition variable in core.js
175
+
176
+ if (/iP(hone|od)/.test(navigator.platform)) {
177
+ var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
178
+ if(v && v.length > 0) {
179
+ v = parseInt(v[1], 10);
180
+ if(v >= 1 && v < 8 ) {
181
+ features.isOldIOSPhone = true;
182
+ }
183
+ }
184
+ }
185
+
186
+ // Detect old Android (before KitKat)
187
+ // due to bugs related to position:fixed
188
+ // http://stackoverflow.com/questions/7184573/pick-up-the-android-version-in-the-browser-by-javascript
189
+
190
+ var match = ua.match(/Android\s([0-9\.]*)/);
191
+ var androidversion = match ? match[1] : 0;
192
+ androidversion = parseFloat(androidversion);
193
+ if(androidversion >= 1 ) {
194
+ if(androidversion < 4.4) {
195
+ features.isOldAndroid = true; // for fixed position bug & performance
196
+ }
197
+ features.androidVersion = androidversion; // for touchend bug
198
+ }
199
+ features.isMobileOpera = /opera mini|opera mobi/i.test(ua);
200
+
201
+ // p.s. yes, yes, UA sniffing is bad, propose your solution for above bugs.
202
+ }
203
+
204
+ var styleChecks = ['transform', 'perspective', 'animationName'],
205
+ vendors = ['', 'webkit','Moz','ms','O'],
206
+ styleCheckItem,
207
+ styleName;
208
+
209
+ for(var i = 0; i < 4; i++) {
210
+ vendor = vendors[i];
211
+
212
+ for(var a = 0; a < 3; a++) {
213
+ styleCheckItem = styleChecks[a];
214
+
215
+ // uppercase first letter of property name, if vendor is present
216
+ styleName = vendor + (vendor ?
217
+ styleCheckItem.charAt(0).toUpperCase() + styleCheckItem.slice(1) :
218
+ styleCheckItem);
219
+
220
+ if(!features[styleCheckItem] && styleName in helperStyle ) {
221
+ features[styleCheckItem] = styleName;
222
+ }
223
+ }
224
+
225
+ if(vendor && !features.raf) {
226
+ vendor = vendor.toLowerCase();
227
+ features.raf = window[vendor+'RequestAnimationFrame'];
228
+ if(features.raf) {
229
+ features.caf = window[vendor+'CancelAnimationFrame'] ||
230
+ window[vendor+'CancelRequestAnimationFrame'];
231
+ }
232
+ }
233
+ }
234
+
235
+ if(!features.raf) {
236
+ var lastTime = 0;
237
+ features.raf = function(fn) {
238
+ var currTime = new Date().getTime();
239
+ var timeToCall = Math.max(0, 16 - (currTime - lastTime));
240
+ var id = window.setTimeout(function() { fn(currTime + timeToCall); }, timeToCall);
241
+ lastTime = currTime + timeToCall;
242
+ return id;
243
+ };
244
+ features.caf = function(id) { clearTimeout(id); };
245
+ }
246
+
247
+ // Detect SVG support
248
+ features.svg = !!document.createElementNS &&
249
+ !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;
250
+
251
+ framework.features = features;
252
+
253
+ return features;
254
+ }
255
+ };
256
+
257
+ framework.detectFeatures();
258
+
259
+ // Override addEventListener for old versions of IE
260
+ if(framework.features.oldIE) {
261
+
262
+ framework.bind = function(target, type, listener, unbind) {
263
+
264
+ type = type.split(' ');
265
+
266
+ var methodName = (unbind ? 'detach' : 'attach') + 'Event',
267
+ evName,
268
+ _handleEv = function() {
269
+ listener.handleEvent.call(listener);
270
+ };
271
+
272
+ for(var i = 0; i < type.length; i++) {
273
+ evName = type[i];
274
+ if(evName) {
275
+
276
+ if(typeof listener === 'object' && listener.handleEvent) {
277
+ if(!unbind) {
278
+ listener['oldIE' + evName] = _handleEv;
279
+ } else {
280
+ if(!listener['oldIE' + evName]) {
281
+ return false;
282
+ }
283
+ }
284
+
285
+ target[methodName]( 'on' + evName, listener['oldIE' + evName]);
286
+ } else {
287
+ target[methodName]( 'on' + evName, listener);
288
+ }
289
+
290
+ }
291
+ }
292
+ };
293
+
294
+ }
295
+
296
+ /*>>framework-bridge*/
297
+
298
+ /*>>core*/
299
+ //function(template, UiClass, items, options)
300
+
301
+ var self = this;
302
+
303
+ /**
304
+ * Static vars, don't change unless you know what you're doing.
305
+ */
306
+ var DOUBLE_TAP_RADIUS = 25,
307
+ NUM_HOLDERS = 3;
308
+
309
+ /**
310
+ * Options
311
+ */
312
+ var _options = {
313
+ allowPanToNext:true,
314
+ spacing: 0.12,
315
+ bgOpacity: 1,
316
+ mouseUsed: false,
317
+ loop: true,
318
+ pinchToClose: true,
319
+ closeOnScroll: true,
320
+ closeOnVerticalDrag: true,
321
+ verticalDragRange: 0.75,
322
+ hideAnimationDuration: 333,
323
+ showAnimationDuration: 333,
324
+ showHideOpacity: false,
325
+ focus: true,
326
+ escKey: true,
327
+ arrowKeys: true,
328
+ mainScrollEndFriction: 0.35,
329
+ panEndFriction: 0.35,
330
+ isClickableElement: function(el) {
331
+ return el.tagName === 'A';
332
+ },
333
+ getDoubleTapZoom: function(isMouseClick, item) {
334
+ if(isMouseClick) {
335
+ return 1;
336
+ } else {
337
+ return item.initialZoomLevel < 0.7 ? 1 : 1.33;
338
+ }
339
+ },
340
+ maxSpreadZoom: 1.33,
341
+ modal: true,
342
+
343
+ // not fully implemented yet
344
+ scaleMode: 'fit' // TODO
345
+ };
346
+ framework.extend(_options, options);
347
+
348
+
349
+ /**
350
+ * Private helper variables & functions
351
+ */
352
+
353
+ var _getEmptyPoint = function() {
354
+ return {x:0,y:0};
355
+ };
356
+
357
+ var _isOpen,
358
+ _isDestroying,
359
+ _closedByScroll,
360
+ _currentItemIndex,
361
+ _containerStyle,
362
+ _containerShiftIndex,
363
+ _currPanDist = _getEmptyPoint(),
364
+ _startPanOffset = _getEmptyPoint(),
365
+ _panOffset = _getEmptyPoint(),
366
+ _upMoveEvents, // drag move, drag end & drag cancel events array
367
+ _downEvents, // drag start events array
368
+ _globalEventHandlers,
369
+ _viewportSize = {},
370
+ _currZoomLevel,
371
+ _startZoomLevel,
372
+ _translatePrefix,
373
+ _translateSufix,
374
+ _updateSizeInterval,
375
+ _itemsNeedUpdate,
376
+ _currPositionIndex = 0,
377
+ _offset = {},
378
+ _slideSize = _getEmptyPoint(), // size of slide area, including spacing
379
+ _itemHolders,
380
+ _prevItemIndex,
381
+ _indexDiff = 0, // difference of indexes since last content update
382
+ _dragStartEvent,
383
+ _dragMoveEvent,
384
+ _dragEndEvent,
385
+ _dragCancelEvent,
386
+ _transformKey,
387
+ _pointerEventEnabled,
388
+ _isFixedPosition = true,
389
+ _likelyTouchDevice,
390
+ _modules = [],
391
+ _requestAF,
392
+ _cancelAF,
393
+ _initalClassName,
394
+ _initalWindowScrollY,
395
+ _oldIE,
396
+ _currentWindowScrollY,
397
+ _features,
398
+ _windowVisibleSize = {},
399
+ _renderMaxResolution = false,
400
+ _orientationChangeTimeout,
401
+
402
+
403
+ // Registers PhotoSWipe module (History, Controller ...)
404
+ _registerModule = function(name, module) {
405
+ framework.extend(self, module.publicMethods);
406
+ _modules.push(name);
407
+ },
408
+
409
+ _getLoopedId = function(index) {
410
+ var numSlides = _getNumItems();
411
+ if(index > numSlides - 1) {
412
+ return index - numSlides;
413
+ } else if(index < 0) {
414
+ return numSlides + index;
415
+ }
416
+ return index;
417
+ },
418
+
419
+ // Micro bind/trigger
420
+ _listeners = {},
421
+ _listen = function(name, fn) {
422
+ if(!_listeners[name]) {
423
+ _listeners[name] = [];
424
+ }
425
+ return _listeners[name].push(fn);
426
+ },
427
+ _shout = function(name) {
428
+ var listeners = _listeners[name];
429
+
430
+ if(listeners) {
431
+ var args = Array.prototype.slice.call(arguments);
432
+ args.shift();
433
+
434
+ for(var i = 0; i < listeners.length; i++) {
435
+ listeners[i].apply(self, args);
436
+ }
437
+ }
438
+ },
439
+
440
+ _getCurrentTime = function() {
441
+ return new Date().getTime();
442
+ },
443
+ _applyBgOpacity = function(opacity) {
444
+ _bgOpacity = opacity;
445
+ self.bg.style.opacity = opacity * _options.bgOpacity;
446
+ },
447
+
448
+ _applyZoomTransform = function(styleObj,x,y,zoom,item) {
449
+ if(!_renderMaxResolution || (item && item !== self.currItem) ) {
450
+ zoom = zoom / (item ? item.fitRatio : self.currItem.fitRatio);
451
+ }
452
+
453
+ styleObj[_transformKey] = _translatePrefix + x + 'px, ' + y + 'px' + _translateSufix + ' scale(' + zoom + ')';
454
+ },
455
+ _applyCurrentZoomPan = function( allowRenderResolution ) {
456
+ if(_currZoomElementStyle) {
457
+
458
+ if(allowRenderResolution) {
459
+ if(_currZoomLevel > self.currItem.fitRatio) {
460
+ if(!_renderMaxResolution) {
461
+ _setImageSize(self.currItem, false, true);
462
+ _renderMaxResolution = true;
463
+ }
464
+ } else {
465
+ if(_renderMaxResolution) {
466
+ _setImageSize(self.currItem);
467
+ _renderMaxResolution = false;
468
+ }
469
+ }
470
+ }
471
+
472
+
473
+ _applyZoomTransform(_currZoomElementStyle, _panOffset.x, _panOffset.y, _currZoomLevel);
474
+ }
475
+ },
476
+ _applyZoomPanToItem = function(item) {
477
+ if(item.container) {
478
+
479
+ _applyZoomTransform(item.container.style,
480
+ item.initialPosition.x,
481
+ item.initialPosition.y,
482
+ item.initialZoomLevel,
483
+ item);
484
+ }
485
+ },
486
+ _setTranslateX = function(x, elStyle) {
487
+ elStyle[_transformKey] = _translatePrefix + x + 'px, 0px' + _translateSufix;
488
+ },
489
+ _moveMainScroll = function(x, dragging) {
490
+
491
+ if(!_options.loop && dragging) {
492
+ var newSlideIndexOffset = _currentItemIndex + (_slideSize.x * _currPositionIndex - x) / _slideSize.x,
493
+ delta = Math.round(x - _mainScrollPos.x);
494
+
495
+ if( (newSlideIndexOffset < 0 && delta > 0) ||
496
+ (newSlideIndexOffset >= _getNumItems() - 1 && delta < 0) ) {
497
+ x = _mainScrollPos.x + delta * _options.mainScrollEndFriction;
498
+ }
499
+ }
500
+
501
+ _mainScrollPos.x = x;
502
+ _setTranslateX(x, _containerStyle);
503
+ },
504
+ _calculatePanOffset = function(axis, zoomLevel) {
505
+ var m = _midZoomPoint[axis] - _offset[axis];
506
+ return _startPanOffset[axis] + _currPanDist[axis] + m - m * ( zoomLevel / _startZoomLevel );
507
+ },
508
+
509
+ _equalizePoints = function(p1, p2) {
510
+ p1.x = p2.x;
511
+ p1.y = p2.y;
512
+ if(p2.id) {
513
+ p1.id = p2.id;
514
+ }
515
+ },
516
+ _roundPoint = function(p) {
517
+ p.x = Math.round(p.x);
518
+ p.y = Math.round(p.y);
519
+ },
520
+
521
+ _mouseMoveTimeout = null,
522
+ _onFirstMouseMove = function() {
523
+ // Wait until mouse move event is fired at least twice during 100ms
524
+ // We do this, because some mobile browsers trigger it on touchstart
525
+ if(_mouseMoveTimeout ) {
526
+ framework.unbind(document, 'mousemove', _onFirstMouseMove);
527
+ framework.addClass(template, 'pswp--has_mouse');
528
+ _options.mouseUsed = true;
529
+ _shout('mouseUsed');
530
+ }
531
+ _mouseMoveTimeout = setTimeout(function() {
532
+ _mouseMoveTimeout = null;
533
+ }, 100);
534
+ },
535
+
536
+ _bindEvents = function() {
537
+ framework.bind(document, 'keydown', self);
538
+
539
+ if(_features.transform) {
540
+ // don't bind click event in browsers that don't support transform (mostly IE8)
541
+ framework.bind(self.scrollWrap, 'click', self);
542
+ }
543
+
544
+
545
+ if(!_options.mouseUsed) {
546
+ framework.bind(document, 'mousemove', _onFirstMouseMove);
547
+ }
548
+
549
+ framework.bind(window, 'resize scroll orientationchange', self);
550
+
551
+ _shout('bindEvents');
552
+ },
553
+
554
+ _unbindEvents = function() {
555
+ framework.unbind(window, 'resize scroll orientationchange', self);
556
+ framework.unbind(window, 'scroll', _globalEventHandlers.scroll);
557
+ framework.unbind(document, 'keydown', self);
558
+ framework.unbind(document, 'mousemove', _onFirstMouseMove);
559
+
560
+ if(_features.transform) {
561
+ framework.unbind(self.scrollWrap, 'click', self);
562
+ }
563
+
564
+ if(_isDragging) {
565
+ framework.unbind(window, _upMoveEvents, self);
566
+ }
567
+
568
+ clearTimeout(_orientationChangeTimeout);
569
+
570
+ _shout('unbindEvents');
571
+ },
572
+
573
+ _calculatePanBounds = function(zoomLevel, update) {
574
+ var bounds = _calculateItemSize( self.currItem, _viewportSize, zoomLevel );
575
+ if(update) {
576
+ _currPanBounds = bounds;
577
+ }
578
+ return bounds;
579
+ },
580
+
581
+ _getMinZoomLevel = function(item) {
582
+ if(!item) {
583
+ item = self.currItem;
584
+ }
585
+ return item.initialZoomLevel;
586
+ },
587
+ _getMaxZoomLevel = function(item) {
588
+ if(!item) {
589
+ item = self.currItem;
590
+ }
591
+ return item.w > 0 ? _options.maxSpreadZoom : 1;
592
+ },
593
+
594
+ // Return true if offset is out of the bounds
595
+ _modifyDestPanOffset = function(axis, destPanBounds, destPanOffset, destZoomLevel) {
596
+ if(destZoomLevel === self.currItem.initialZoomLevel) {
597
+ destPanOffset[axis] = self.currItem.initialPosition[axis];
598
+ return true;
599
+ } else {
600
+ destPanOffset[axis] = _calculatePanOffset(axis, destZoomLevel);
601
+
602
+ if(destPanOffset[axis] > destPanBounds.min[axis]) {
603
+ destPanOffset[axis] = destPanBounds.min[axis];
604
+ return true;
605
+ } else if(destPanOffset[axis] < destPanBounds.max[axis] ) {
606
+ destPanOffset[axis] = destPanBounds.max[axis];
607
+ return true;
608
+ }
609
+ }
610
+ return false;
611
+ },
612
+
613
+ _setupTransforms = function() {
614
+
615
+ if(_transformKey) {
616
+ // setup 3d transforms
617
+ var allow3dTransform = _features.perspective && !_likelyTouchDevice;
618
+ _translatePrefix = 'translate' + (allow3dTransform ? '3d(' : '(');
619
+ _translateSufix = _features.perspective ? ', 0px)' : ')';
620
+ return;
621
+ }
622
+
623
+ // Override zoom/pan/move functions in case old browser is used (most likely IE)
624
+ // (so they use left/top/width/height, instead of CSS transform)
625
+
626
+ _transformKey = 'left';
627
+ framework.addClass(template, 'pswp--ie');
628
+
629
+ _setTranslateX = function(x, elStyle) {
630
+ elStyle.left = x + 'px';
631
+ };
632
+ _applyZoomPanToItem = function(item) {
633
+
634
+ var zoomRatio = item.fitRatio > 1 ? 1 : item.fitRatio,
635
+ s = item.container.style,
636
+ w = zoomRatio * item.w,
637
+ h = zoomRatio * item.h;
638
+
639
+ s.width = w + 'px';
640
+ s.height = h + 'px';
641
+ s.left = item.initialPosition.x + 'px';
642
+ s.top = item.initialPosition.y + 'px';
643
+
644
+ };
645
+ _applyCurrentZoomPan = function() {
646
+ if(_currZoomElementStyle) {
647
+
648
+ var s = _currZoomElementStyle,
649
+ item = self.currItem,
650
+ zoomRatio = item.fitRatio > 1 ? 1 : item.fitRatio,
651
+ w = zoomRatio * item.w,
652
+ h = zoomRatio * item.h;
653
+
654
+ s.width = w + 'px';
655
+ s.height = h + 'px';
656
+
657
+
658
+ s.left = _panOffset.x + 'px';
659
+ s.top = _panOffset.y + 'px';
660
+ }
661
+
662
+ };
663
+ },
664
+
665
+ _onKeyDown = function(e) {
666
+ var keydownAction = '';
667
+ if(_options.escKey && e.keyCode === 27) {
668
+ keydownAction = 'close';
669
+ } else if(_options.arrowKeys) {
670
+ if(e.keyCode === 37) {
671
+ keydownAction = 'prev';
672
+ } else if(e.keyCode === 39) {
673
+ keydownAction = 'next';
674
+ }
675
+ }
676
+
677
+ if(keydownAction) {
678
+ // don't do anything if special key pressed to prevent from overriding default browser actions
679
+ // e.g. in Chrome on Mac cmd+arrow-left returns to previous page
680
+ if( !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey ) {
681
+ if(e.preventDefault) {
682
+ e.preventDefault();
683
+ } else {
684
+ e.returnValue = false;
685
+ }
686
+ self[keydownAction]();
687
+ }
688
+ }
689
+ },
690
+
691
+ _onGlobalClick = function(e) {
692
+ if(!e) {
693
+ return;
694
+ }
695
+
696
+ // don't allow click event to pass through when triggering after drag or some other gesture
697
+ if(_moved || _zoomStarted || _mainScrollAnimating || _verticalDragInitiated) {
698
+ e.preventDefault();
699
+ e.stopPropagation();
700
+ }
701
+ },
702
+
703
+ _updatePageScrollOffset = function() {
704
+ self.setScrollOffset(0, framework.getScrollY());
705
+ };
706
+
707
+
708
+
709
+
710
+
711
+
712
+
713
+ // Micro animation engine
714
+ var _animations = {},
715
+ _numAnimations = 0,
716
+ _stopAnimation = function(name) {
717
+ if(_animations[name]) {
718
+ if(_animations[name].raf) {
719
+ _cancelAF( _animations[name].raf );
720
+ }
721
+ _numAnimations--;
722
+ delete _animations[name];
723
+ }
724
+ },
725
+ _registerStartAnimation = function(name) {
726
+ if(_animations[name]) {
727
+ _stopAnimation(name);
728
+ }
729
+ if(!_animations[name]) {
730
+ _numAnimations++;
731
+ _animations[name] = {};
732
+ }
733
+ },
734
+ _stopAllAnimations = function() {
735
+ for (var prop in _animations) {
736
+
737
+ if( _animations.hasOwnProperty( prop ) ) {
738
+ _stopAnimation(prop);
739
+ }
740
+
741
+ }
742
+ },
743
+ _animateProp = function(name, b, endProp, d, easingFn, onUpdate, onComplete) {
744
+ var startAnimTime = _getCurrentTime(), t;
745
+ _registerStartAnimation(name);
746
+
747
+ var animloop = function(){
748
+ if ( _animations[name] ) {
749
+
750
+ t = _getCurrentTime() - startAnimTime; // time diff
751
+ //b - beginning (start prop)
752
+ //d - anim duration
753
+
754
+ if ( t >= d ) {
755
+ _stopAnimation(name);
756
+ onUpdate(endProp);
757
+ if(onComplete) {
758
+ onComplete();
759
+ }
760
+ return;
761
+ }
762
+ onUpdate( (endProp - b) * easingFn(t/d) + b );
763
+
764
+ _animations[name].raf = _requestAF(animloop);
765
+ }
766
+ };
767
+ animloop();
768
+ };
769
+
770
+
771
+
772
+ var publicMethods = {
773
+
774
+ // make a few local variables and functions public
775
+ shout: _shout,
776
+ listen: _listen,
777
+ viewportSize: _viewportSize,
778
+ options: _options,
779
+
780
+ isMainScrollAnimating: function() {
781
+ return _mainScrollAnimating;
782
+ },
783
+ getZoomLevel: function() {
784
+ return _currZoomLevel;
785
+ },
786
+ getCurrentIndex: function() {
787
+ return _currentItemIndex;
788
+ },
789
+ isDragging: function() {
790
+ return _isDragging;
791
+ },
792
+ isZooming: function() {
793
+ return _isZooming;
794
+ },
795
+ setScrollOffset: function(x,y) {
796
+ _offset.x = x;
797
+ _currentWindowScrollY = _offset.y = y;
798
+ _shout('updateScrollOffset', _offset);
799
+ },
800
+ applyZoomPan: function(zoomLevel,panX,panY,allowRenderResolution) {
801
+ _panOffset.x = panX;
802
+ _panOffset.y = panY;
803
+ _currZoomLevel = zoomLevel;
804
+ _applyCurrentZoomPan( allowRenderResolution );
805
+ },
806
+
807
+ init: function() {
808
+
809
+ if(_isOpen || _isDestroying) {
810
+ return;
811
+ }
812
+
813
+ var i;
814
+
815
+ self.framework = framework; // basic functionality
816
+ self.template = template; // root DOM element of PhotoSwipe
817
+ self.bg = framework.getChildByClass(template, 'pswp__bg');
818
+
819
+ _initalClassName = template.className;
820
+ _isOpen = true;
821
+
822
+ _features = framework.detectFeatures();
823
+ _requestAF = _features.raf;
824
+ _cancelAF = _features.caf;
825
+ _transformKey = _features.transform;
826
+ _oldIE = _features.oldIE;
827
+
828
+ self.scrollWrap = framework.getChildByClass(template, 'pswp__scroll-wrap');
829
+ self.container = framework.getChildByClass(self.scrollWrap, 'pswp__container');
830
+
831
+ _containerStyle = self.container.style; // for fast access
832
+
833
+ // Objects that hold slides (there are only 3 in DOM)
834
+ self.itemHolders = _itemHolders = [
835
+ {el:self.container.children[0] , wrap:0, index: -1},
836
+ {el:self.container.children[1] , wrap:0, index: -1},
837
+ {el:self.container.children[2] , wrap:0, index: -1}
838
+ ];
839
+
840
+ // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)
841
+ _itemHolders[0].el.style.display = _itemHolders[2].el.style.display = 'none';
842
+
843
+ _setupTransforms();
844
+
845
+ // Setup global events
846
+ _globalEventHandlers = {
847
+ resize: self.updateSize,
848
+
849
+ // Fixes: iOS 10.3 resize event
850
+ // does not update scrollWrap.clientWidth instantly after resize
851
+ // https://github.com/dimsemenov/PhotoSwipe/issues/1315
852
+ orientationchange: function() {
853
+ clearTimeout(_orientationChangeTimeout);
854
+ _orientationChangeTimeout = setTimeout(function() {
855
+ if(_viewportSize.x !== self.scrollWrap.clientWidth) {
856
+ self.updateSize();
857
+ }
858
+ }, 500);
859
+ },
860
+ scroll: _updatePageScrollOffset,
861
+ keydown: _onKeyDown,
862
+ click: _onGlobalClick
863
+ };
864
+
865
+ // disable show/hide effects on old browsers that don't support CSS animations or transforms,
866
+ // old IOS, Android and Opera mobile. Blackberry seems to work fine, even older models.
867
+ var oldPhone = _features.isOldIOSPhone || _features.isOldAndroid || _features.isMobileOpera;
868
+ if(!_features.animationName || !_features.transform || oldPhone) {
869
+ _options.showAnimationDuration = _options.hideAnimationDuration = 0;
870
+ }
871
+
872
+ // init modules
873
+ for(i = 0; i < _modules.length; i++) {
874
+ self['init' + _modules[i]]();
875
+ }
876
+
877
+ // init
878
+ if(UiClass) {
879
+ var ui = self.ui = new UiClass(self, framework);
880
+ ui.init();
881
+ }
882
+
883
+ _shout('firstUpdate');
884
+ _currentItemIndex = _currentItemIndex || _options.index || 0;
885
+ // validate index
886
+ if( isNaN(_currentItemIndex) || _currentItemIndex < 0 || _currentItemIndex >= _getNumItems() ) {
887
+ _currentItemIndex = 0;
888
+ }
889
+ self.currItem = _getItemAt( _currentItemIndex );
890
+
891
+
892
+ if(_features.isOldIOSPhone || _features.isOldAndroid) {
893
+ _isFixedPosition = false;
894
+ }
895
+
896
+ template.setAttribute('aria-hidden', 'false');
897
+ if(_options.modal) {
898
+ if(!_isFixedPosition) {
899
+ template.style.position = 'absolute';
900
+ template.style.top = framework.getScrollY() + 'px';
901
+ } else {
902
+ template.style.position = 'fixed';
903
+ }
904
+ }
905
+
906
+ if(_currentWindowScrollY === undefined) {
907
+ _shout('initialLayout');
908
+ _currentWindowScrollY = _initalWindowScrollY = framework.getScrollY();
909
+ }
910
+
911
+ // add classes to root element of PhotoSwipe
912
+ var rootClasses = 'pswp--open ';
913
+ if(_options.mainClass) {
914
+ rootClasses += _options.mainClass + ' ';
915
+ }
916
+ if(_options.showHideOpacity) {
917
+ rootClasses += 'pswp--animate_opacity ';
918
+ }
919
+ rootClasses += _likelyTouchDevice ? 'pswp--touch' : 'pswp--notouch';
920
+ rootClasses += _features.animationName ? ' pswp--css_animation' : '';
921
+ rootClasses += _features.svg ? ' pswp--svg' : '';
922
+ framework.addClass(template, rootClasses);
923
+
924
+ self.updateSize();
925
+
926
+ // initial update
927
+ _containerShiftIndex = -1;
928
+ _indexDiff = null;
929
+ for(i = 0; i < NUM_HOLDERS; i++) {
930
+ _setTranslateX( (i+_containerShiftIndex) * _slideSize.x, _itemHolders[i].el.style);
931
+ }
932
+
933
+ if(!_oldIE) {
934
+ framework.bind(self.scrollWrap, _downEvents, self); // no dragging for old IE
935
+ }
936
+
937
+ _listen('initialZoomInEnd', function() {
938
+ self.setContent(_itemHolders[0], _currentItemIndex-1);
939
+ self.setContent(_itemHolders[2], _currentItemIndex+1);
940
+
941
+ _itemHolders[0].el.style.display = _itemHolders[2].el.style.display = 'block';
942
+
943
+ if(_options.focus) {
944
+ // focus causes layout,
945
+ // which causes lag during the animation,
946
+ // that's why we delay it untill the initial zoom transition ends
947
+ template.focus();
948
+ }
949
+
950
+
951
+ _bindEvents();
952
+ });
953
+
954
+ // set content for center slide (first time)
955
+ self.setContent(_itemHolders[1], _currentItemIndex);
956
+
957
+ self.updateCurrItem();
958
+
959
+ _shout('afterInit');
960
+
961
+ if(!_isFixedPosition) {
962
+
963
+ // On all versions of iOS lower than 8.0, we check size of viewport every second.
964
+ //
965
+ // This is done to detect when Safari top & bottom bars appear,
966
+ // as this action doesn't trigger any events (like resize).
967
+ //
968
+ // On iOS8 they fixed this.
969
+ //
970
+ // 10 Nov 2014: iOS 7 usage ~40%. iOS 8 usage 56%.
971
+
972
+ _updateSizeInterval = setInterval(function() {
973
+ if(!_numAnimations && !_isDragging && !_isZooming && (_currZoomLevel === self.currItem.initialZoomLevel) ) {
974
+ self.updateSize();
975
+ }
976
+ }, 1000);
977
+ }
978
+
979
+ framework.addClass(template, 'pswp--visible');
980
+ },
981
+
982
+ // Close the gallery, then destroy it
983
+ close: function() {
984
+ if(!_isOpen) {
985
+ return;
986
+ }
987
+
988
+ _isOpen = false;
989
+ _isDestroying = true;
990
+ _shout('close');
991
+ _unbindEvents();
992
+
993
+ _showOrHide(self.currItem, null, true, self.destroy);
994
+ },
995
+
996
+ // destroys the gallery (unbinds events, cleans up intervals and timeouts to avoid memory leaks)
997
+ destroy: function() {
998
+ _shout('destroy');
999
+
1000
+ if(_showOrHideTimeout) {
1001
+ clearTimeout(_showOrHideTimeout);
1002
+ }
1003
+
1004
+ template.setAttribute('aria-hidden', 'true');
1005
+ template.className = _initalClassName;
1006
+
1007
+ if(_updateSizeInterval) {
1008
+ clearInterval(_updateSizeInterval);
1009
+ }
1010
+
1011
+ framework.unbind(self.scrollWrap, _downEvents, self);
1012
+
1013
+ // we unbind scroll event at the end, as closing animation may depend on it
1014
+ framework.unbind(window, 'scroll', self);
1015
+
1016
+ _stopDragUpdateLoop();
1017
+
1018
+ _stopAllAnimations();
1019
+
1020
+ _listeners = null;
1021
+ },
1022
+
1023
+ /**
1024
+ * Pan image to position
1025
+ * @param {Number} x
1026
+ * @param {Number} y
1027
+ * @param {Boolean} force Will ignore bounds if set to true.
1028
+ */
1029
+ panTo: function(x,y,force) {
1030
+ if(!force) {
1031
+ if(x > _currPanBounds.min.x) {
1032
+ x = _currPanBounds.min.x;
1033
+ } else if(x < _currPanBounds.max.x) {
1034
+ x = _currPanBounds.max.x;
1035
+ }
1036
+
1037
+ if(y > _currPanBounds.min.y) {
1038
+ y = _currPanBounds.min.y;
1039
+ } else if(y < _currPanBounds.max.y) {
1040
+ y = _currPanBounds.max.y;
1041
+ }
1042
+ }
1043
+
1044
+ _panOffset.x = x;
1045
+ _panOffset.y = y;
1046
+ _applyCurrentZoomPan();
1047
+ },
1048
+
1049
+ handleEvent: function (e) {
1050
+ e = e || window.event;
1051
+ if(_globalEventHandlers[e.type]) {
1052
+ _globalEventHandlers[e.type](e);
1053
+ }
1054
+ },
1055
+
1056
+
1057
+ goTo: function(index) {
1058
+
1059
+ index = _getLoopedId(index);
1060
+
1061
+ var diff = index - _currentItemIndex;
1062
+ _indexDiff = diff;
1063
+
1064
+ _currentItemIndex = index;
1065
+ self.currItem = _getItemAt( _currentItemIndex );
1066
+ _currPositionIndex -= diff;
1067
+
1068
+ _moveMainScroll(_slideSize.x * _currPositionIndex);
1069
+
1070
+
1071
+ _stopAllAnimations();
1072
+ _mainScrollAnimating = false;
1073
+
1074
+ self.updateCurrItem();
1075
+ },
1076
+ next: function() {
1077
+ self.goTo( _currentItemIndex + 1);
1078
+ },
1079
+ prev: function() {
1080
+ self.goTo( _currentItemIndex - 1);
1081
+ },
1082
+
1083
+ // update current zoom/pan objects
1084
+ updateCurrZoomItem: function(emulateSetContent) {
1085
+ if(emulateSetContent) {
1086
+ _shout('beforeChange', 0);
1087
+ }
1088
+
1089
+ // itemHolder[1] is middle (current) item
1090
+ if(_itemHolders[1].el.children.length) {
1091
+ var zoomElement = _itemHolders[1].el.children[0];
1092
+ if( framework.hasClass(zoomElement, 'pswp__zoom-wrap') ) {
1093
+ _currZoomElementStyle = zoomElement.style;
1094
+ } else {
1095
+ _currZoomElementStyle = null;
1096
+ }
1097
+ } else {
1098
+ _currZoomElementStyle = null;
1099
+ }
1100
+
1101
+ _currPanBounds = self.currItem.bounds;
1102
+ _startZoomLevel = _currZoomLevel = self.currItem.initialZoomLevel;
1103
+
1104
+ _panOffset.x = _currPanBounds.center.x;
1105
+ _panOffset.y = _currPanBounds.center.y;
1106
+
1107
+ if(emulateSetContent) {
1108
+ _shout('afterChange');
1109
+ }
1110
+ },
1111
+
1112
+
1113
+ invalidateCurrItems: function() {
1114
+ _itemsNeedUpdate = true;
1115
+ for(var i = 0; i < NUM_HOLDERS; i++) {
1116
+ if( _itemHolders[i].item ) {
1117
+ _itemHolders[i].item.needsUpdate = true;
1118
+ }
1119
+ }
1120
+ },
1121
+
1122
+ updateCurrItem: function(beforeAnimation) {
1123
+
1124
+ if(_indexDiff === 0) {
1125
+ return;
1126
+ }
1127
+
1128
+ var diffAbs = Math.abs(_indexDiff),
1129
+ tempHolder;
1130
+
1131
+ if(beforeAnimation && diffAbs < 2) {
1132
+ return;
1133
+ }
1134
+
1135
+
1136
+ self.currItem = _getItemAt( _currentItemIndex );
1137
+ _renderMaxResolution = false;
1138
+
1139
+ _shout('beforeChange', _indexDiff);
1140
+
1141
+ if(diffAbs >= NUM_HOLDERS) {
1142
+ _containerShiftIndex += _indexDiff + (_indexDiff > 0 ? -NUM_HOLDERS : NUM_HOLDERS);
1143
+ diffAbs = NUM_HOLDERS;
1144
+ }
1145
+ for(var i = 0; i < diffAbs; i++) {
1146
+ if(_indexDiff > 0) {
1147
+ tempHolder = _itemHolders.shift();
1148
+ _itemHolders[NUM_HOLDERS-1] = tempHolder; // move first to last
1149
+
1150
+ _containerShiftIndex++;
1151
+ _setTranslateX( (_containerShiftIndex+2) * _slideSize.x, tempHolder.el.style);
1152
+ self.setContent(tempHolder, _currentItemIndex - diffAbs + i + 1 + 1);
1153
+ } else {
1154
+ tempHolder = _itemHolders.pop();
1155
+ _itemHolders.unshift( tempHolder ); // move last to first
1156
+
1157
+ _containerShiftIndex--;
1158
+ _setTranslateX( _containerShiftIndex * _slideSize.x, tempHolder.el.style);
1159
+ self.setContent(tempHolder, _currentItemIndex + diffAbs - i - 1 - 1);
1160
+ }
1161
+
1162
+ }
1163
+
1164
+ // reset zoom/pan on previous item
1165
+ if(_currZoomElementStyle && Math.abs(_indexDiff) === 1) {
1166
+
1167
+ var prevItem = _getItemAt(_prevItemIndex);
1168
+ if(prevItem.initialZoomLevel !== _currZoomLevel) {
1169
+ _calculateItemSize(prevItem , _viewportSize );
1170
+ _setImageSize(prevItem);
1171
+ _applyZoomPanToItem( prevItem );
1172
+ }
1173
+
1174
+ }
1175
+
1176
+ // reset diff after update
1177
+ _indexDiff = 0;
1178
+
1179
+ self.updateCurrZoomItem();
1180
+
1181
+ _prevItemIndex = _currentItemIndex;
1182
+
1183
+ _shout('afterChange');
1184
+
1185
+ },
1186
+
1187
+
1188
+
1189
+ updateSize: function(force) {
1190
+
1191
+ if(!_isFixedPosition && _options.modal) {
1192
+ var windowScrollY = framework.getScrollY();
1193
+ if(_currentWindowScrollY !== windowScrollY) {
1194
+ template.style.top = windowScrollY + 'px';
1195
+ _currentWindowScrollY = windowScrollY;
1196
+ }
1197
+ if(!force && _windowVisibleSize.x === window.innerWidth && _windowVisibleSize.y === window.innerHeight) {
1198
+ return;
1199
+ }
1200
+ _windowVisibleSize.x = window.innerWidth;
1201
+ _windowVisibleSize.y = window.innerHeight;
1202
+
1203
+ //template.style.width = _windowVisibleSize.x + 'px';
1204
+ template.style.height = _windowVisibleSize.y + 'px';
1205
+ }
1206
+
1207
+
1208
+
1209
+ _viewportSize.x = self.scrollWrap.clientWidth;
1210
+ _viewportSize.y = self.scrollWrap.clientHeight;
1211
+
1212
+ _updatePageScrollOffset();
1213
+
1214
+ _slideSize.x = _viewportSize.x + Math.round(_viewportSize.x * _options.spacing);
1215
+ _slideSize.y = _viewportSize.y;
1216
+
1217
+ _moveMainScroll(_slideSize.x * _currPositionIndex);
1218
+
1219
+ _shout('beforeResize'); // even may be used for example to switch image sources
1220
+
1221
+
1222
+ // don't re-calculate size on inital size update
1223
+ if(_containerShiftIndex !== undefined) {
1224
+
1225
+ var holder,
1226
+ item,
1227
+ hIndex;
1228
+
1229
+ for(var i = 0; i < NUM_HOLDERS; i++) {
1230
+ holder = _itemHolders[i];
1231
+ _setTranslateX( (i+_containerShiftIndex) * _slideSize.x, holder.el.style);
1232
+
1233
+ hIndex = _currentItemIndex+i-1;
1234
+
1235
+ if(_options.loop && _getNumItems() > 2) {
1236
+ hIndex = _getLoopedId(hIndex);
1237
+ }
1238
+
1239
+ // update zoom level on items and refresh source (if needsUpdate)
1240
+ item = _getItemAt( hIndex );
1241
+
1242
+ // re-render gallery item if `needsUpdate`,
1243
+ // or doesn't have `bounds` (entirely new slide object)
1244
+ if( item && (_itemsNeedUpdate || item.needsUpdate || !item.bounds) ) {
1245
+
1246
+ self.cleanSlide( item );
1247
+
1248
+ self.setContent( holder, hIndex );
1249
+
1250
+ // if "center" slide
1251
+ if(i === 1) {
1252
+ self.currItem = item;
1253
+ self.updateCurrZoomItem(true);
1254
+ }
1255
+
1256
+ item.needsUpdate = false;
1257
+
1258
+ } else if(holder.index === -1 && hIndex >= 0) {
1259
+ // add content first time
1260
+ self.setContent( holder, hIndex );
1261
+ }
1262
+ if(item && item.container) {
1263
+ _calculateItemSize(item, _viewportSize);
1264
+ _setImageSize(item);
1265
+ _applyZoomPanToItem( item );
1266
+ }
1267
+
1268
+ }
1269
+ _itemsNeedUpdate = false;
1270
+ }
1271
+
1272
+ _startZoomLevel = _currZoomLevel = self.currItem.initialZoomLevel;
1273
+ _currPanBounds = self.currItem.bounds;
1274
+
1275
+ if(_currPanBounds) {
1276
+ _panOffset.x = _currPanBounds.center.x;
1277
+ _panOffset.y = _currPanBounds.center.y;
1278
+ _applyCurrentZoomPan( true );
1279
+ }
1280
+
1281
+ _shout('resize');
1282
+ },
1283
+
1284
+ // Zoom current item to
1285
+ zoomTo: function(destZoomLevel, centerPoint, speed, easingFn, updateFn) {
1286
+ /*
1287
+ if(destZoomLevel === 'fit') {
1288
+ destZoomLevel = self.currItem.fitRatio;
1289
+ } else if(destZoomLevel === 'fill') {
1290
+ destZoomLevel = self.currItem.fillRatio;
1291
+ }
1292
+ */
1293
+
1294
+ if(centerPoint) {
1295
+ _startZoomLevel = _currZoomLevel;
1296
+ _midZoomPoint.x = Math.abs(centerPoint.x) - _panOffset.x ;
1297
+ _midZoomPoint.y = Math.abs(centerPoint.y) - _panOffset.y ;
1298
+ _equalizePoints(_startPanOffset, _panOffset);
1299
+ }
1300
+
1301
+ var destPanBounds = _calculatePanBounds(destZoomLevel, false),
1302
+ destPanOffset = {};
1303
+
1304
+ _modifyDestPanOffset('x', destPanBounds, destPanOffset, destZoomLevel);
1305
+ _modifyDestPanOffset('y', destPanBounds, destPanOffset, destZoomLevel);
1306
+
1307
+ var initialZoomLevel = _currZoomLevel;
1308
+ var initialPanOffset = {
1309
+ x: _panOffset.x,
1310
+ y: _panOffset.y
1311
+ };
1312
+
1313
+ _roundPoint(destPanOffset);
1314
+
1315
+ var onUpdate = function(now) {
1316
+ if(now === 1) {
1317
+ _currZoomLevel = destZoomLevel;
1318
+ _panOffset.x = destPanOffset.x;
1319
+ _panOffset.y = destPanOffset.y;
1320
+ } else {
1321
+ _currZoomLevel = (destZoomLevel - initialZoomLevel) * now + initialZoomLevel;
1322
+ _panOffset.x = (destPanOffset.x - initialPanOffset.x) * now + initialPanOffset.x;
1323
+ _panOffset.y = (destPanOffset.y - initialPanOffset.y) * now + initialPanOffset.y;
1324
+ }
1325
+
1326
+ if(updateFn) {
1327
+ updateFn(now);
1328
+ }
1329
+
1330
+ _applyCurrentZoomPan( now === 1 );
1331
+ };
1332
+
1333
+ if(speed) {
1334
+ _animateProp('customZoomTo', 0, 1, speed, easingFn || framework.easing.sine.inOut, onUpdate);
1335
+ } else {
1336
+ onUpdate(1);
1337
+ }
1338
+ }
1339
+
1340
+
1341
+ };
1342
+
1343
+
1344
+ /*>>core*/
1345
+
1346
+ /*>>gestures*/
1347
+ /**
1348
+ * Mouse/touch/pointer event handlers.
1349
+ *
1350
+ * separated from @core.js for readability
1351
+ */
1352
+
1353
+ var MIN_SWIPE_DISTANCE = 30,
1354
+ DIRECTION_CHECK_OFFSET = 10; // amount of pixels to drag to determine direction of swipe
1355
+
1356
+ var _gestureStartTime,
1357
+ _gestureCheckSpeedTime,
1358
+
1359
+ // pool of objects that are used during dragging of zooming
1360
+ p = {}, // first point
1361
+ p2 = {}, // second point (for zoom gesture)
1362
+ delta = {},
1363
+ _currPoint = {},
1364
+ _startPoint = {},
1365
+ _currPointers = [],
1366
+ _startMainScrollPos = {},
1367
+ _releaseAnimData,
1368
+ _posPoints = [], // array of points during dragging, used to determine type of gesture
1369
+ _tempPoint = {},
1370
+
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
+
1399
+ _isEqualPoints = function(p1, p2) {
1400
+ return p1.x === p2.x && p1.y === p2.y;
1401
+ },
1402
+ _isNearbyPoints = function(touch0, touch1) {
1403
+ return Math.abs(touch0.x - touch1.x) < DOUBLE_TAP_RADIUS && Math.abs(touch0.y - touch1.y) < DOUBLE_TAP_RADIUS;
1404
+ },
1405
+ _calculatePointsDistance = function(p1, p2) {
1406
+ _tempPoint.x = Math.abs( p1.x - p2.x );
1407
+ _tempPoint.y = Math.abs( p1.y - p2.y );
1408
+ return Math.sqrt(_tempPoint.x * _tempPoint.x + _tempPoint.y * _tempPoint.y);
1409
+ },
1410
+ _stopDragUpdateLoop = function() {
1411
+ if(_dragAnimFrame) {
1412
+ _cancelAF(_dragAnimFrame);
1413
+ _dragAnimFrame = null;
1414
+ }
1415
+ },
1416
+ _dragUpdateLoop = function() {
1417
+ if(_isDragging) {
1418
+ _dragAnimFrame = _requestAF(_dragUpdateLoop);
1419
+ _renderMovement();
1420
+ }
1421
+ },
1422
+ _canPan = function() {
1423
+ return !(_options.scaleMode === 'fit' && _currZoomLevel === self.currItem.initialZoomLevel);
1424
+ },
1425
+
1426
+ // find the closest parent DOM element
1427
+ _closestElement = function(el, fn) {
1428
+ if(!el || el === document) {
1429
+ return false;
1430
+ }
1431
+
1432
+ // don't search elements above pswp__scroll-wrap
1433
+ if(el.getAttribute('class') && el.getAttribute('class').indexOf('pswp__scroll-wrap') > -1 ) {
1434
+ return false;
1435
+ }
1436
+
1437
+ if( fn(el) ) {
1438
+ return el;
1439
+ }
1440
+
1441
+ return _closestElement(el.parentNode, fn);
1442
+ },
1443
+
1444
+ _preventObj = {},
1445
+ _preventDefaultEventBehaviour = function(e, isDown) {
1446
+ _preventObj.prevent = !_closestElement(e.target, _options.isClickableElement);
1447
+
1448
+ _shout('preventDragEvent', e, isDown, _preventObj);
1449
+ return _preventObj.prevent;
1450
+
1451
+ },
1452
+ _convertTouchToPoint = function(touch, p) {
1453
+ p.x = touch.pageX;
1454
+ p.y = touch.pageY;
1455
+ p.id = touch.identifier;
1456
+ return p;
1457
+ },
1458
+ _findCenterOfPoints = function(p1, p2, pCenter) {
1459
+ pCenter.x = (p1.x + p2.x) * 0.5;
1460
+ pCenter.y = (p1.y + p2.y) * 0.5;
1461
+ },
1462
+ _pushPosPoint = function(time, x, y) {
1463
+ if(time - _gestureCheckSpeedTime > 50) {
1464
+ var o = _posPoints.length > 2 ? _posPoints.shift() : {};
1465
+ o.x = x;
1466
+ o.y = y;
1467
+ _posPoints.push(o);
1468
+ _gestureCheckSpeedTime = time;
1469
+ }
1470
+ },
1471
+
1472
+ _calculateVerticalDragOpacityRatio = function() {
1473
+ var yOffset = _panOffset.y - self.currItem.initialPosition.y; // difference between initial and current position
1474
+ return 1 - Math.abs( yOffset / (_viewportSize.y / 2) );
1475
+ },
1476
+
1477
+
1478
+ // points pool, reused during touch events
1479
+ _ePoint1 = {},
1480
+ _ePoint2 = {},
1481
+ _tempPointsArr = [],
1482
+ _tempCounter,
1483
+ _getTouchPoints = function(e) {
1484
+ // clean up previous points, without recreating array
1485
+ while(_tempPointsArr.length > 0) {
1486
+ _tempPointsArr.pop();
1487
+ }
1488
+
1489
+ if(!_pointerEventEnabled) {
1490
+ if(e.type.indexOf('touch') > -1) {
1491
+
1492
+ if(e.touches && e.touches.length > 0) {
1493
+ _tempPointsArr[0] = _convertTouchToPoint(e.touches[0], _ePoint1);
1494
+ if(e.touches.length > 1) {
1495
+ _tempPointsArr[1] = _convertTouchToPoint(e.touches[1], _ePoint2);
1496
+ }
1497
+ }
1498
+
1499
+ } else {
1500
+ _ePoint1.x = e.pageX;
1501
+ _ePoint1.y = e.pageY;
1502
+ _ePoint1.id = '';
1503
+ _tempPointsArr[0] = _ePoint1;//_ePoint1;
1504
+ }
1505
+ } else {
1506
+ _tempCounter = 0;
1507
+ // we can use forEach, as pointer events are supported only in modern browsers
1508
+ _currPointers.forEach(function(p) {
1509
+ if(_tempCounter === 0) {
1510
+ _tempPointsArr[0] = p;
1511
+ } else if(_tempCounter === 1) {
1512
+ _tempPointsArr[1] = p;
1513
+ }
1514
+ _tempCounter++;
1515
+
1516
+ });
1517
+ }
1518
+ return _tempPointsArr;
1519
+ },
1520
+
1521
+ _panOrMoveMainScroll = function(axis, delta) {
1522
+
1523
+ var panFriction,
1524
+ overDiff = 0,
1525
+ newOffset = _panOffset[axis] + delta[axis],
1526
+ startOverDiff,
1527
+ dir = delta[axis] > 0,
1528
+ newMainScrollPosition = _mainScrollPos.x + delta.x,
1529
+ mainScrollDiff = _mainScrollPos.x - _startMainScrollPos.x,
1530
+ newPanPos,
1531
+ newMainScrollPos;
1532
+
1533
+ // calculate fdistance over the bounds and friction
1534
+ if(newOffset > _currPanBounds.min[axis] || newOffset < _currPanBounds.max[axis]) {
1535
+ panFriction = _options.panEndFriction;
1536
+ // Linear increasing of friction, so at 1/4 of viewport it's at max value.
1537
+ // Looks not as nice as was expected. Left for history.
1538
+ // panFriction = (1 - (_panOffset[axis] + delta[axis] + panBounds.min[axis]) / (_viewportSize[axis] / 4) );
1539
+ } else {
1540
+ panFriction = 1;
1541
+ }
1542
+
1543
+ newOffset = _panOffset[axis] + delta[axis] * panFriction;
1544
+
1545
+ // move main scroll or start panning
1546
+ if(_options.allowPanToNext || _currZoomLevel === self.currItem.initialZoomLevel) {
1547
+
1548
+
1549
+ if(!_currZoomElementStyle) {
1550
+
1551
+ newMainScrollPos = newMainScrollPosition;
1552
+
1553
+ } else if(_direction === 'h' && axis === 'x' && !_zoomStarted ) {
1554
+
1555
+ if(dir) {
1556
+ if(newOffset > _currPanBounds.min[axis]) {
1557
+ panFriction = _options.panEndFriction;
1558
+ overDiff = _currPanBounds.min[axis] - newOffset;
1559
+ startOverDiff = _currPanBounds.min[axis] - _startPanOffset[axis];
1560
+ }
1561
+
1562
+ // drag right
1563
+ if( (startOverDiff <= 0 || mainScrollDiff < 0) && _getNumItems() > 1 ) {
1564
+ newMainScrollPos = newMainScrollPosition;
1565
+ if(mainScrollDiff < 0 && newMainScrollPosition > _startMainScrollPos.x) {
1566
+ newMainScrollPos = _startMainScrollPos.x;
1567
+ }
1568
+ } else {
1569
+ if(_currPanBounds.min.x !== _currPanBounds.max.x) {
1570
+ newPanPos = newOffset;
1571
+ }
1572
+
1573
+ }
1574
+
1575
+ } else {
1576
+
1577
+ if(newOffset < _currPanBounds.max[axis] ) {
1578
+ panFriction =_options.panEndFriction;
1579
+ overDiff = newOffset - _currPanBounds.max[axis];
1580
+ startOverDiff = _startPanOffset[axis] - _currPanBounds.max[axis];
1581
+ }
1582
+
1583
+ if( (startOverDiff <= 0 || mainScrollDiff > 0) && _getNumItems() > 1 ) {
1584
+ newMainScrollPos = newMainScrollPosition;
1585
+
1586
+ if(mainScrollDiff > 0 && newMainScrollPosition < _startMainScrollPos.x) {
1587
+ newMainScrollPos = _startMainScrollPos.x;
1588
+ }
1589
+
1590
+ } else {
1591
+ if(_currPanBounds.min.x !== _currPanBounds.max.x) {
1592
+ newPanPos = newOffset;
1593
+ }
1594
+ }
1595
+
1596
+ }
1597
+
1598
+
1599
+ //
1600
+ }
1601
+
1602
+ if(axis === 'x') {
1603
+
1604
+ if(newMainScrollPos !== undefined) {
1605
+ _moveMainScroll(newMainScrollPos, true);
1606
+ if(newMainScrollPos === _startMainScrollPos.x) {
1607
+ _mainScrollShifted = false;
1608
+ } else {
1609
+ _mainScrollShifted = true;
1610
+ }
1611
+ }
1612
+
1613
+ if(_currPanBounds.min.x !== _currPanBounds.max.x) {
1614
+ if(newPanPos !== undefined) {
1615
+ _panOffset.x = newPanPos;
1616
+ } else if(!_mainScrollShifted) {
1617
+ _panOffset.x += delta.x * panFriction;
1618
+ }
1619
+ }
1620
+
1621
+ return newMainScrollPos !== undefined;
1622
+ }
1623
+
1624
+ }
1625
+
1626
+ if(!_mainScrollAnimating) {
1627
+
1628
+ if(!_mainScrollShifted) {
1629
+ if(_currZoomLevel > self.currItem.fitRatio) {
1630
+ _panOffset[axis] += delta[axis] * panFriction;
1631
+
1632
+ }
1633
+ }
1634
+
1635
+
1636
+ }
1637
+
1638
+ },
1639
+
1640
+ // Pointerdown/touchstart/mousedown handler
1641
+ _onDragStart = function(e) {
1642
+
1643
+ // Allow dragging only via left mouse button.
1644
+ // As this handler is not added in IE8 - we ignore e.which
1645
+ //
1646
+ // http://www.quirksmode.org/js/events_properties.html
1647
+ // https://developer.mozilla.org/en-US/docs/Web/API/event.button
1648
+ if(e.type === 'mousedown' && e.button > 0 ) {
1649
+ return;
1650
+ }
1651
+
1652
+ if(_initialZoomRunning) {
1653
+ e.preventDefault();
1654
+ return;
1655
+ }
1656
+
1657
+ if(_oldAndroidTouchEndTimeout && e.type === 'mousedown') {
1658
+ return;
1659
+ }
1660
+
1661
+ if(_preventDefaultEventBehaviour(e, true)) {
1662
+ e.preventDefault();
1663
+ }
1664
+
1665
+
1666
+
1667
+ _shout('pointerDown');
1668
+
1669
+ if(_pointerEventEnabled) {
1670
+ var pointerIndex = framework.arraySearch(_currPointers, e.pointerId, 'id');
1671
+ if(pointerIndex < 0) {
1672
+ pointerIndex = _currPointers.length;
1673
+ }
1674
+ _currPointers[pointerIndex] = {x:e.pageX, y:e.pageY, id: e.pointerId};
1675
+ }
1676
+
1677
+
1678
+
1679
+ var startPointsList = _getTouchPoints(e),
1680
+ numPoints = startPointsList.length;
1681
+
1682
+ _currentPoints = null;
1683
+
1684
+ _stopAllAnimations();
1685
+
1686
+ // init drag
1687
+ if(!_isDragging || numPoints === 1) {
1688
+
1689
+
1690
+
1691
+ _isDragging = _isFirstMove = true;
1692
+ framework.bind(window, _upMoveEvents, self);
1693
+
1694
+ _isZoomingIn =
1695
+ _wasOverInitialZoom =
1696
+ _opacityChanged =
1697
+ _verticalDragInitiated =
1698
+ _mainScrollShifted =
1699
+ _moved =
1700
+ _isMultitouch =
1701
+ _zoomStarted = false;
1702
+
1703
+ _direction = null;
1704
+
1705
+ _shout('firstTouchStart', startPointsList);
1706
+
1707
+ _equalizePoints(_startPanOffset, _panOffset);
1708
+
1709
+ _currPanDist.x = _currPanDist.y = 0;
1710
+ _equalizePoints(_currPoint, startPointsList[0]);
1711
+ _equalizePoints(_startPoint, _currPoint);
1712
+
1713
+ //_equalizePoints(_startMainScrollPos, _mainScrollPos);
1714
+ _startMainScrollPos.x = _slideSize.x * _currPositionIndex;
1715
+
1716
+ _posPoints = [{
1717
+ x: _currPoint.x,
1718
+ y: _currPoint.y
1719
+ }];
1720
+
1721
+ _gestureCheckSpeedTime = _gestureStartTime = _getCurrentTime();
1722
+
1723
+ //_mainScrollAnimationEnd(true);
1724
+ _calculatePanBounds( _currZoomLevel, true );
1725
+
1726
+ // Start rendering
1727
+ _stopDragUpdateLoop();
1728
+ _dragUpdateLoop();
1729
+
1730
+ }
1731
+
1732
+ // init zoom
1733
+ if(!_isZooming && numPoints > 1 && !_mainScrollAnimating && !_mainScrollShifted) {
1734
+ _startZoomLevel = _currZoomLevel;
1735
+ _zoomStarted = false; // true if zoom changed at least once
1736
+
1737
+ _isZooming = _isMultitouch = true;
1738
+ _currPanDist.y = _currPanDist.x = 0;
1739
+
1740
+ _equalizePoints(_startPanOffset, _panOffset);
1741
+
1742
+ _equalizePoints(p, startPointsList[0]);
1743
+ _equalizePoints(p2, startPointsList[1]);
1744
+
1745
+ _findCenterOfPoints(p, p2, _currCenterPoint);
1746
+
1747
+ _midZoomPoint.x = Math.abs(_currCenterPoint.x) - _panOffset.x;
1748
+ _midZoomPoint.y = Math.abs(_currCenterPoint.y) - _panOffset.y;
1749
+ _currPointsDistance = _startPointsDistance = _calculatePointsDistance(p, p2);
1750
+ }
1751
+
1752
+
1753
+ },
1754
+
1755
+ // Pointermove/touchmove/mousemove handler
1756
+ _onDragMove = function(e) {
1757
+
1758
+ e.preventDefault();
1759
+
1760
+ if(_pointerEventEnabled) {
1761
+ var pointerIndex = framework.arraySearch(_currPointers, e.pointerId, 'id');
1762
+ if(pointerIndex > -1) {
1763
+ var p = _currPointers[pointerIndex];
1764
+ p.x = e.pageX;
1765
+ p.y = e.pageY;
1766
+ }
1767
+ }
1768
+
1769
+ if(_isDragging) {
1770
+ var touchesList = _getTouchPoints(e);
1771
+ if(!_direction && !_moved && !_isZooming) {
1772
+
1773
+ if(_mainScrollPos.x !== _slideSize.x * _currPositionIndex) {
1774
+ // if main scroll position is shifted – direction is always horizontal
1775
+ _direction = 'h';
1776
+ } else {
1777
+ var diff = Math.abs(touchesList[0].x - _currPoint.x) - Math.abs(touchesList[0].y - _currPoint.y);
1778
+ // check the direction of movement
1779
+ if(Math.abs(diff) >= DIRECTION_CHECK_OFFSET) {
1780
+ _direction = diff > 0 ? 'h' : 'v';
1781
+ _currentPoints = touchesList;
1782
+ }
1783
+ }
1784
+
1785
+ } else {
1786
+ _currentPoints = touchesList;
1787
+ }
1788
+ }
1789
+ },
1790
+ //
1791
+ _renderMovement = function() {
1792
+
1793
+ if(!_currentPoints) {
1794
+ return;
1795
+ }
1796
+
1797
+ var numPoints = _currentPoints.length;
1798
+
1799
+ if(numPoints === 0) {
1800
+ return;
1801
+ }
1802
+
1803
+ _equalizePoints(p, _currentPoints[0]);
1804
+
1805
+ delta.x = p.x - _currPoint.x;
1806
+ delta.y = p.y - _currPoint.y;
1807
+
1808
+ if(_isZooming && numPoints > 1) {
1809
+ // Handle behaviour for more than 1 point
1810
+
1811
+ _currPoint.x = p.x;
1812
+ _currPoint.y = p.y;
1813
+
1814
+ // check if one of two points changed
1815
+ if( !delta.x && !delta.y && _isEqualPoints(_currentPoints[1], p2) ) {
1816
+ return;
1817
+ }
1818
+
1819
+ _equalizePoints(p2, _currentPoints[1]);
1820
+
1821
+
1822
+ if(!_zoomStarted) {
1823
+ _zoomStarted = true;
1824
+ _shout('zoomGestureStarted');
1825
+ }
1826
+
1827
+ // Distance between two points
1828
+ var pointsDistance = _calculatePointsDistance(p,p2);
1829
+
1830
+ var zoomLevel = _calculateZoomLevel(pointsDistance);
1831
+
1832
+ // slightly over the of initial zoom level
1833
+ if(zoomLevel > self.currItem.initialZoomLevel + self.currItem.initialZoomLevel / 15) {
1834
+ _wasOverInitialZoom = true;
1835
+ }
1836
+
1837
+ // Apply the friction if zoom level is out of the bounds
1838
+ var zoomFriction = 1,
1839
+ minZoomLevel = _getMinZoomLevel(),
1840
+ maxZoomLevel = _getMaxZoomLevel();
1841
+
1842
+ if ( zoomLevel < minZoomLevel ) {
1843
+
1844
+ if(_options.pinchToClose && !_wasOverInitialZoom && _startZoomLevel <= self.currItem.initialZoomLevel) {
1845
+ // fade out background if zooming out
1846
+ var minusDiff = minZoomLevel - zoomLevel;
1847
+ var percent = 1 - minusDiff / (minZoomLevel / 1.2);
1848
+
1849
+ _applyBgOpacity(percent);
1850
+ _shout('onPinchClose', percent);
1851
+ _opacityChanged = true;
1852
+ } else {
1853
+ zoomFriction = (minZoomLevel - zoomLevel) / minZoomLevel;
1854
+ if(zoomFriction > 1) {
1855
+ zoomFriction = 1;
1856
+ }
1857
+ zoomLevel = minZoomLevel - zoomFriction * (minZoomLevel / 3);
1858
+ }
1859
+
1860
+ } else if ( zoomLevel > maxZoomLevel ) {
1861
+ // 1.5 - extra zoom level above the max. E.g. if max is x6, real max 6 + 1.5 = 7.5
1862
+ zoomFriction = (zoomLevel - maxZoomLevel) / ( minZoomLevel * 6 );
1863
+ if(zoomFriction > 1) {
1864
+ zoomFriction = 1;
1865
+ }
1866
+ zoomLevel = maxZoomLevel + zoomFriction * minZoomLevel;
1867
+ }
1868
+
1869
+ if(zoomFriction < 0) {
1870
+ zoomFriction = 0;
1871
+ }
1872
+
1873
+ // distance between touch points after friction is applied
1874
+ _currPointsDistance = pointsDistance;
1875
+
1876
+ // _centerPoint - The point in the middle of two pointers
1877
+ _findCenterOfPoints(p, p2, _centerPoint);
1878
+
1879
+ // paning with two pointers pressed
1880
+ _currPanDist.x += _centerPoint.x - _currCenterPoint.x;
1881
+ _currPanDist.y += _centerPoint.y - _currCenterPoint.y;
1882
+ _equalizePoints(_currCenterPoint, _centerPoint);
1883
+
1884
+ _panOffset.x = _calculatePanOffset('x', zoomLevel);
1885
+ _panOffset.y = _calculatePanOffset('y', zoomLevel);
1886
+
1887
+ _isZoomingIn = zoomLevel > _currZoomLevel;
1888
+ _currZoomLevel = zoomLevel;
1889
+ _applyCurrentZoomPan();
1890
+
1891
+ } else {
1892
+
1893
+ // handle behaviour for one point (dragging or panning)
1894
+
1895
+ if(!_direction) {
1896
+ return;
1897
+ }
1898
+
1899
+ if(_isFirstMove) {
1900
+ _isFirstMove = false;
1901
+
1902
+ // subtract drag distance that was used during the detection direction
1903
+
1904
+ if( Math.abs(delta.x) >= DIRECTION_CHECK_OFFSET) {
1905
+ delta.x -= _currentPoints[0].x - _startPoint.x;
1906
+ }
1907
+
1908
+ if( Math.abs(delta.y) >= DIRECTION_CHECK_OFFSET) {
1909
+ delta.y -= _currentPoints[0].y - _startPoint.y;
1910
+ }
1911
+ }
1912
+
1913
+ _currPoint.x = p.x;
1914
+ _currPoint.y = p.y;
1915
+
1916
+ // do nothing if pointers position hasn't changed
1917
+ if(delta.x === 0 && delta.y === 0) {
1918
+ return;
1919
+ }
1920
+
1921
+ if(_direction === 'v' && _options.closeOnVerticalDrag) {
1922
+ if(!_canPan()) {
1923
+ _currPanDist.y += delta.y;
1924
+ _panOffset.y += delta.y;
1925
+
1926
+ var opacityRatio = _calculateVerticalDragOpacityRatio();
1927
+
1928
+ _verticalDragInitiated = true;
1929
+ _shout('onVerticalDrag', opacityRatio);
1930
+
1931
+ _applyBgOpacity(opacityRatio);
1932
+ _applyCurrentZoomPan();
1933
+ return ;
1934
+ }
1935
+ }
1936
+
1937
+ _pushPosPoint(_getCurrentTime(), p.x, p.y);
1938
+
1939
+ _moved = true;
1940
+ _currPanBounds = self.currItem.bounds;
1941
+
1942
+ var mainScrollChanged = _panOrMoveMainScroll('x', delta);
1943
+ if(!mainScrollChanged) {
1944
+ _panOrMoveMainScroll('y', delta);
1945
+
1946
+ _roundPoint(_panOffset);
1947
+ _applyCurrentZoomPan();
1948
+ }
1949
+
1950
+ }
1951
+
1952
+ },
1953
+
1954
+ // Pointerup/pointercancel/touchend/touchcancel/mouseup event handler
1955
+ _onDragRelease = function(e) {
1956
+
1957
+ if(_features.isOldAndroid ) {
1958
+
1959
+ if(_oldAndroidTouchEndTimeout && e.type === 'mouseup') {
1960
+ return;
1961
+ }
1962
+
1963
+ // on Android (v4.1, 4.2, 4.3 & possibly older)
1964
+ // ghost mousedown/up event isn't preventable via e.preventDefault,
1965
+ // which causes fake mousedown event
1966
+ // so we block mousedown/up for 600ms
1967
+ if( e.type.indexOf('touch') > -1 ) {
1968
+ clearTimeout(_oldAndroidTouchEndTimeout);
1969
+ _oldAndroidTouchEndTimeout = setTimeout(function() {
1970
+ _oldAndroidTouchEndTimeout = 0;
1971
+ }, 600);
1972
+ }
1973
+
1974
+ }
1975
+
1976
+ _shout('pointerUp');
1977
+
1978
+ if(_preventDefaultEventBehaviour(e, false)) {
1979
+ e.preventDefault();
1980
+ }
1981
+
1982
+ var releasePoint;
1983
+
1984
+ if(_pointerEventEnabled) {
1985
+ var pointerIndex = framework.arraySearch(_currPointers, e.pointerId, 'id');
1986
+
1987
+ if(pointerIndex > -1) {
1988
+ releasePoint = _currPointers.splice(pointerIndex, 1)[0];
1989
+
1990
+ if(navigator.msPointerEnabled) {
1991
+ var MSPOINTER_TYPES = {
1992
+ 4: 'mouse', // event.MSPOINTER_TYPE_MOUSE
1993
+ 2: 'touch', // event.MSPOINTER_TYPE_TOUCH
1994
+ 3: 'pen' // event.MSPOINTER_TYPE_PEN
1995
+ };
1996
+ releasePoint.type = MSPOINTER_TYPES[e.pointerType];
1997
+
1998
+ if(!releasePoint.type) {
1999
+ releasePoint.type = e.pointerType || 'mouse';
2000
+ }
2001
+ } else {
2002
+ releasePoint.type = e.pointerType || 'mouse';
2003
+ }
2004
+
2005
+ }
2006
+ }
2007
+
2008
+ var touchList = _getTouchPoints(e),
2009
+ gestureType,
2010
+ numPoints = touchList.length;
2011
+
2012
+ if(e.type === 'mouseup') {
2013
+ numPoints = 0;
2014
+ }
2015
+
2016
+ // Do nothing if there were 3 touch points or more
2017
+ if(numPoints === 2) {
2018
+ _currentPoints = null;
2019
+ return true;
2020
+ }
2021
+
2022
+ // if second pointer released
2023
+ if(numPoints === 1) {
2024
+ _equalizePoints(_startPoint, touchList[0]);
2025
+ }
2026
+
2027
+
2028
+ // pointer hasn't moved, send "tap release" point
2029
+ if(numPoints === 0 && !_direction && !_mainScrollAnimating) {
2030
+ if(!releasePoint) {
2031
+ if(e.type === 'mouseup') {
2032
+ releasePoint = {x: e.pageX, y: e.pageY, type:'mouse'};
2033
+ } else if(e.changedTouches && e.changedTouches[0]) {
2034
+ releasePoint = {x: e.changedTouches[0].pageX, y: e.changedTouches[0].pageY, type:'touch'};
2035
+ }
2036
+ }
2037
+
2038
+ _shout('touchRelease', e, releasePoint);
2039
+ }
2040
+
2041
+ // Difference in time between releasing of two last touch points (zoom gesture)
2042
+ var releaseTimeDiff = -1;
2043
+
2044
+ // Gesture completed, no pointers left
2045
+ if(numPoints === 0) {
2046
+ _isDragging = false;
2047
+ framework.unbind(window, _upMoveEvents, self);
2048
+
2049
+ _stopDragUpdateLoop();
2050
+
2051
+ if(_isZooming) {
2052
+ // Two points released at the same time
2053
+ releaseTimeDiff = 0;
2054
+ } else if(_lastReleaseTime !== -1) {
2055
+ releaseTimeDiff = _getCurrentTime() - _lastReleaseTime;
2056
+ }
2057
+ }
2058
+ _lastReleaseTime = numPoints === 1 ? _getCurrentTime() : -1;
2059
+
2060
+ if(releaseTimeDiff !== -1 && releaseTimeDiff < 150) {
2061
+ gestureType = 'zoom';
2062
+ } else {
2063
+ gestureType = 'swipe';
2064
+ }
2065
+
2066
+ if(_isZooming && numPoints < 2) {
2067
+ _isZooming = false;
2068
+
2069
+ // Only second point released
2070
+ if(numPoints === 1) {
2071
+ gestureType = 'zoomPointerUp';
2072
+ }
2073
+ _shout('zoomGestureEnded');
2074
+ }
2075
+
2076
+ _currentPoints = null;
2077
+ if(!_moved && !_zoomStarted && !_mainScrollAnimating && !_verticalDragInitiated) {
2078
+ // nothing to animate
2079
+ return;
2080
+ }
2081
+
2082
+ _stopAllAnimations();
2083
+
2084
+
2085
+ if(!_releaseAnimData) {
2086
+ _releaseAnimData = _initDragReleaseAnimationData();
2087
+ }
2088
+
2089
+ _releaseAnimData.calculateSwipeSpeed('x');
2090
+
2091
+
2092
+ if(_verticalDragInitiated) {
2093
+
2094
+ var opacityRatio = _calculateVerticalDragOpacityRatio();
2095
+
2096
+ if(opacityRatio < _options.verticalDragRange) {
2097
+ self.close();
2098
+ } else {
2099
+ var initalPanY = _panOffset.y,
2100
+ initialBgOpacity = _bgOpacity;
2101
+
2102
+ _animateProp('verticalDrag', 0, 1, 300, framework.easing.cubic.out, function(now) {
2103
+
2104
+ _panOffset.y = (self.currItem.initialPosition.y - initalPanY) * now + initalPanY;
2105
+
2106
+ _applyBgOpacity( (1 - initialBgOpacity) * now + initialBgOpacity );
2107
+ _applyCurrentZoomPan();
2108
+ });
2109
+
2110
+ _shout('onVerticalDrag', 1);
2111
+ }
2112
+
2113
+ return;
2114
+ }
2115
+
2116
+
2117
+ // main scroll
2118
+ if( (_mainScrollShifted || _mainScrollAnimating) && numPoints === 0) {
2119
+ var itemChanged = _finishSwipeMainScrollGesture(gestureType, _releaseAnimData);
2120
+ if(itemChanged) {
2121
+ return;
2122
+ }
2123
+ gestureType = 'zoomPointerUp';
2124
+ }
2125
+
2126
+ // prevent zoom/pan animation when main scroll animation runs
2127
+ if(_mainScrollAnimating) {
2128
+ return;
2129
+ }
2130
+
2131
+ // Complete simple zoom gesture (reset zoom level if it's out of the bounds)
2132
+ if(gestureType !== 'swipe') {
2133
+ _completeZoomGesture();
2134
+ return;
2135
+ }
2136
+
2137
+ // Complete pan gesture if main scroll is not shifted, and it's possible to pan current image
2138
+ if(!_mainScrollShifted && _currZoomLevel > self.currItem.fitRatio) {
2139
+ _completePanGesture(_releaseAnimData);
2140
+ }
2141
+ },
2142
+
2143
+
2144
+ // Returns object with data about gesture
2145
+ // It's created only once and then reused
2146
+ _initDragReleaseAnimationData = function() {
2147
+ // temp local vars
2148
+ var lastFlickDuration,
2149
+ tempReleasePos;
2150
+
2151
+ // s = this
2152
+ var s = {
2153
+ lastFlickOffset: {},
2154
+ lastFlickDist: {},
2155
+ lastFlickSpeed: {},
2156
+ slowDownRatio: {},
2157
+ slowDownRatioReverse: {},
2158
+ speedDecelerationRatio: {},
2159
+ speedDecelerationRatioAbs: {},
2160
+ distanceOffset: {},
2161
+ backAnimDestination: {},
2162
+ backAnimStarted: {},
2163
+ calculateSwipeSpeed: function(axis) {
2164
+
2165
+
2166
+ if( _posPoints.length > 1) {
2167
+ lastFlickDuration = _getCurrentTime() - _gestureCheckSpeedTime + 50;
2168
+ tempReleasePos = _posPoints[_posPoints.length-2][axis];
2169
+ } else {
2170
+ lastFlickDuration = _getCurrentTime() - _gestureStartTime; // total gesture duration
2171
+ tempReleasePos = _startPoint[axis];
2172
+ }
2173
+ s.lastFlickOffset[axis] = _currPoint[axis] - tempReleasePos;
2174
+ s.lastFlickDist[axis] = Math.abs(s.lastFlickOffset[axis]);
2175
+ if(s.lastFlickDist[axis] > 20) {
2176
+ s.lastFlickSpeed[axis] = s.lastFlickOffset[axis] / lastFlickDuration;
2177
+ } else {
2178
+ s.lastFlickSpeed[axis] = 0;
2179
+ }
2180
+ if( Math.abs(s.lastFlickSpeed[axis]) < 0.1 ) {
2181
+ s.lastFlickSpeed[axis] = 0;
2182
+ }
2183
+
2184
+ s.slowDownRatio[axis] = 0.95;
2185
+ s.slowDownRatioReverse[axis] = 1 - s.slowDownRatio[axis];
2186
+ s.speedDecelerationRatio[axis] = 1;
2187
+ },
2188
+
2189
+ calculateOverBoundsAnimOffset: function(axis, speed) {
2190
+ if(!s.backAnimStarted[axis]) {
2191
+
2192
+ if(_panOffset[axis] > _currPanBounds.min[axis]) {
2193
+ s.backAnimDestination[axis] = _currPanBounds.min[axis];
2194
+
2195
+ } else if(_panOffset[axis] < _currPanBounds.max[axis]) {
2196
+ s.backAnimDestination[axis] = _currPanBounds.max[axis];
2197
+ }
2198
+
2199
+ if(s.backAnimDestination[axis] !== undefined) {
2200
+ s.slowDownRatio[axis] = 0.7;
2201
+ s.slowDownRatioReverse[axis] = 1 - s.slowDownRatio[axis];
2202
+ if(s.speedDecelerationRatioAbs[axis] < 0.05) {
2203
+
2204
+ s.lastFlickSpeed[axis] = 0;
2205
+ s.backAnimStarted[axis] = true;
2206
+
2207
+ _animateProp('bounceZoomPan'+axis,_panOffset[axis],
2208
+ s.backAnimDestination[axis],
2209
+ speed || 300,
2210
+ framework.easing.sine.out,
2211
+ function(pos) {
2212
+ _panOffset[axis] = pos;
2213
+ _applyCurrentZoomPan();
2214
+ }
2215
+ );
2216
+
2217
+ }
2218
+ }
2219
+ }
2220
+ },
2221
+
2222
+ // Reduces the speed by slowDownRatio (per 10ms)
2223
+ calculateAnimOffset: function(axis) {
2224
+ if(!s.backAnimStarted[axis]) {
2225
+ s.speedDecelerationRatio[axis] = s.speedDecelerationRatio[axis] * (s.slowDownRatio[axis] +
2226
+ s.slowDownRatioReverse[axis] -
2227
+ s.slowDownRatioReverse[axis] * s.timeDiff / 10);
2228
+
2229
+ s.speedDecelerationRatioAbs[axis] = Math.abs(s.lastFlickSpeed[axis] * s.speedDecelerationRatio[axis]);
2230
+ s.distanceOffset[axis] = s.lastFlickSpeed[axis] * s.speedDecelerationRatio[axis] * s.timeDiff;
2231
+ _panOffset[axis] += s.distanceOffset[axis];
2232
+
2233
+ }
2234
+ },
2235
+
2236
+ panAnimLoop: function() {
2237
+ if ( _animations.zoomPan ) {
2238
+ _animations.zoomPan.raf = _requestAF(s.panAnimLoop);
2239
+
2240
+ s.now = _getCurrentTime();
2241
+ s.timeDiff = s.now - s.lastNow;
2242
+ s.lastNow = s.now;
2243
+
2244
+ s.calculateAnimOffset('x');
2245
+ s.calculateAnimOffset('y');
2246
+
2247
+ _applyCurrentZoomPan();
2248
+
2249
+ s.calculateOverBoundsAnimOffset('x');
2250
+ s.calculateOverBoundsAnimOffset('y');
2251
+
2252
+
2253
+ if (s.speedDecelerationRatioAbs.x < 0.05 && s.speedDecelerationRatioAbs.y < 0.05) {
2254
+
2255
+ // round pan position
2256
+ _panOffset.x = Math.round(_panOffset.x);
2257
+ _panOffset.y = Math.round(_panOffset.y);
2258
+ _applyCurrentZoomPan();
2259
+
2260
+ _stopAnimation('zoomPan');
2261
+ return;
2262
+ }
2263
+ }
2264
+
2265
+ }
2266
+ };
2267
+ return s;
2268
+ },
2269
+
2270
+ _completePanGesture = function(animData) {
2271
+ // calculate swipe speed for Y axis (paanning)
2272
+ animData.calculateSwipeSpeed('y');
2273
+
2274
+ _currPanBounds = self.currItem.bounds;
2275
+
2276
+ animData.backAnimDestination = {};
2277
+ animData.backAnimStarted = {};
2278
+
2279
+ // Avoid acceleration animation if speed is too low
2280
+ if(Math.abs(animData.lastFlickSpeed.x) <= 0.05 && Math.abs(animData.lastFlickSpeed.y) <= 0.05 ) {
2281
+ animData.speedDecelerationRatioAbs.x = animData.speedDecelerationRatioAbs.y = 0;
2282
+
2283
+ // Run pan drag release animation. E.g. if you drag image and release finger without momentum.
2284
+ animData.calculateOverBoundsAnimOffset('x');
2285
+ animData.calculateOverBoundsAnimOffset('y');
2286
+ return true;
2287
+ }
2288
+
2289
+ // Animation loop that controls the acceleration after pan gesture ends
2290
+ _registerStartAnimation('zoomPan');
2291
+ animData.lastNow = _getCurrentTime();
2292
+ animData.panAnimLoop();
2293
+ },
2294
+
2295
+
2296
+ _finishSwipeMainScrollGesture = function(gestureType, _releaseAnimData) {
2297
+ var itemChanged;
2298
+ if(!_mainScrollAnimating) {
2299
+ _currZoomedItemIndex = _currentItemIndex;
2300
+ }
2301
+
2302
+
2303
+
2304
+ var itemsDiff;
2305
+
2306
+ if(gestureType === 'swipe') {
2307
+ var totalShiftDist = _currPoint.x - _startPoint.x,
2308
+ isFastLastFlick = _releaseAnimData.lastFlickDist.x < 10;
2309
+
2310
+ // if container is shifted for more than MIN_SWIPE_DISTANCE,
2311
+ // and last flick gesture was in right direction
2312
+ if(totalShiftDist > MIN_SWIPE_DISTANCE &&
2313
+ (isFastLastFlick || _releaseAnimData.lastFlickOffset.x > 20) ) {
2314
+ // go to prev item
2315
+ itemsDiff = -1;
2316
+ } else if(totalShiftDist < -MIN_SWIPE_DISTANCE &&
2317
+ (isFastLastFlick || _releaseAnimData.lastFlickOffset.x < -20) ) {
2318
+ // go to next item
2319
+ itemsDiff = 1;
2320
+ }
2321
+ }
2322
+
2323
+ var nextCircle;
2324
+
2325
+ if(itemsDiff) {
2326
+
2327
+ _currentItemIndex += itemsDiff;
2328
+
2329
+ if(_currentItemIndex < 0) {
2330
+ _currentItemIndex = _options.loop ? _getNumItems()-1 : 0;
2331
+ nextCircle = true;
2332
+ } else if(_currentItemIndex >= _getNumItems()) {
2333
+ _currentItemIndex = _options.loop ? 0 : _getNumItems()-1;
2334
+ nextCircle = true;
2335
+ }
2336
+
2337
+ if(!nextCircle || _options.loop) {
2338
+ _indexDiff += itemsDiff;
2339
+ _currPositionIndex -= itemsDiff;
2340
+ itemChanged = true;
2341
+ }
2342
+
2343
+
2344
+
2345
+ }
2346
+
2347
+ var animateToX = _slideSize.x * _currPositionIndex;
2348
+ var animateToDist = Math.abs( animateToX - _mainScrollPos.x );
2349
+ var finishAnimDuration;
2350
+
2351
+
2352
+ if(!itemChanged && animateToX > _mainScrollPos.x !== _releaseAnimData.lastFlickSpeed.x > 0) {
2353
+ // "return to current" duration, e.g. when dragging from slide 0 to -1
2354
+ finishAnimDuration = 333;
2355
+ } else {
2356
+ finishAnimDuration = Math.abs(_releaseAnimData.lastFlickSpeed.x) > 0 ?
2357
+ animateToDist / Math.abs(_releaseAnimData.lastFlickSpeed.x) :
2358
+ 333;
2359
+
2360
+ finishAnimDuration = Math.min(finishAnimDuration, 400);
2361
+ finishAnimDuration = Math.max(finishAnimDuration, 250);
2362
+ }
2363
+
2364
+ if(_currZoomedItemIndex === _currentItemIndex) {
2365
+ itemChanged = false;
2366
+ }
2367
+
2368
+ _mainScrollAnimating = true;
2369
+
2370
+ _shout('mainScrollAnimStart');
2371
+
2372
+ _animateProp('mainScroll', _mainScrollPos.x, animateToX, finishAnimDuration, framework.easing.cubic.out,
2373
+ _moveMainScroll,
2374
+ function() {
2375
+ _stopAllAnimations();
2376
+ _mainScrollAnimating = false;
2377
+ _currZoomedItemIndex = -1;
2378
+
2379
+ if(itemChanged || _currZoomedItemIndex !== _currentItemIndex) {
2380
+ self.updateCurrItem();
2381
+ }
2382
+
2383
+ _shout('mainScrollAnimComplete');
2384
+ }
2385
+ );
2386
+
2387
+ if(itemChanged) {
2388
+ self.updateCurrItem(true);
2389
+ }
2390
+
2391
+ return itemChanged;
2392
+ },
2393
+
2394
+ _calculateZoomLevel = function(touchesDistance) {
2395
+ return 1 / _startPointsDistance * touchesDistance * _startZoomLevel;
2396
+ },
2397
+
2398
+ // Resets zoom if it's out of bounds
2399
+ _completeZoomGesture = function() {
2400
+ var destZoomLevel = _currZoomLevel,
2401
+ minZoomLevel = _getMinZoomLevel(),
2402
+ maxZoomLevel = _getMaxZoomLevel();
2403
+
2404
+ if ( _currZoomLevel < minZoomLevel ) {
2405
+ destZoomLevel = minZoomLevel;
2406
+ } else if ( _currZoomLevel > maxZoomLevel ) {
2407
+ destZoomLevel = maxZoomLevel;
2408
+ }
2409
+
2410
+ var destOpacity = 1,
2411
+ onUpdate,
2412
+ initialOpacity = _bgOpacity;
2413
+
2414
+ if(_opacityChanged && !_isZoomingIn && !_wasOverInitialZoom && _currZoomLevel < minZoomLevel) {
2415
+ //_closedByScroll = true;
2416
+ self.close();
2417
+ return true;
2418
+ }
2419
+
2420
+ if(_opacityChanged) {
2421
+ onUpdate = function(now) {
2422
+ _applyBgOpacity( (destOpacity - initialOpacity) * now + initialOpacity );
2423
+ };
2424
+ }
2425
+
2426
+ self.zoomTo(destZoomLevel, 0, 200, framework.easing.cubic.out, onUpdate);
2427
+ return true;
2428
+ };
2429
+
2430
+
2431
+ _registerModule('Gestures', {
2432
+ publicMethods: {
2433
+
2434
+ initGestures: function() {
2435
+
2436
+ // helper function that builds touch/pointer/mouse events
2437
+ var addEventNames = function(pref, down, move, up, cancel) {
2438
+ _dragStartEvent = pref + down;
2439
+ _dragMoveEvent = pref + move;
2440
+ _dragEndEvent = pref + up;
2441
+ if(cancel) {
2442
+ _dragCancelEvent = pref + cancel;
2443
+ } else {
2444
+ _dragCancelEvent = '';
2445
+ }
2446
+ };
2447
+
2448
+ _pointerEventEnabled = _features.pointerEvent;
2449
+ if(_pointerEventEnabled && _features.touch) {
2450
+ // we don't need touch events, if browser supports pointer events
2451
+ _features.touch = false;
2452
+ }
2453
+
2454
+ if(_pointerEventEnabled) {
2455
+ if(navigator.msPointerEnabled) {
2456
+ // IE10 pointer events are case-sensitive
2457
+ addEventNames('MSPointer', 'Down', 'Move', 'Up', 'Cancel');
2458
+ } else {
2459
+ addEventNames('pointer', 'down', 'move', 'up', 'cancel');
2460
+ }
2461
+ } else if(_features.touch) {
2462
+ addEventNames('touch', 'start', 'move', 'end', 'cancel');
2463
+ _likelyTouchDevice = true;
2464
+ } else {
2465
+ addEventNames('mouse', 'down', 'move', 'up');
2466
+ }
2467
+
2468
+ _upMoveEvents = _dragMoveEvent + ' ' + _dragEndEvent + ' ' + _dragCancelEvent;
2469
+ _downEvents = _dragStartEvent;
2470
+
2471
+ if(_pointerEventEnabled && !_likelyTouchDevice) {
2472
+ _likelyTouchDevice = (navigator.maxTouchPoints > 1) || (navigator.msMaxTouchPoints > 1);
2473
+ }
2474
+ // make variable public
2475
+ self.likelyTouchDevice = _likelyTouchDevice;
2476
+
2477
+ _globalEventHandlers[_dragStartEvent] = _onDragStart;
2478
+ _globalEventHandlers[_dragMoveEvent] = _onDragMove;
2479
+ _globalEventHandlers[_dragEndEvent] = _onDragRelease; // the Kraken
2480
+
2481
+ if(_dragCancelEvent) {
2482
+ _globalEventHandlers[_dragCancelEvent] = _globalEventHandlers[_dragEndEvent];
2483
+ }
2484
+
2485
+ // Bind mouse events on device with detected hardware touch support, in case it supports multiple types of input.
2486
+ if(_features.touch) {
2487
+ _downEvents += ' mousedown';
2488
+ _upMoveEvents += ' mousemove mouseup';
2489
+ _globalEventHandlers.mousedown = _globalEventHandlers[_dragStartEvent];
2490
+ _globalEventHandlers.mousemove = _globalEventHandlers[_dragMoveEvent];
2491
+ _globalEventHandlers.mouseup = _globalEventHandlers[_dragEndEvent];
2492
+ }
2493
+
2494
+ if(!_likelyTouchDevice) {
2495
+ // don't allow pan to next slide from zoomed state on Desktop
2496
+ _options.allowPanToNext = false;
2497
+ }
2498
+ }
2499
+
2500
+ }
2501
+ });
2502
+
2503
+
2504
+ /*>>gestures*/
2505
+
2506
+ /*>>show-hide-transition*/
2507
+ /**
2508
+ * show-hide-transition.js:
2509
+ *
2510
+ * Manages initial opening or closing transition.
2511
+ *
2512
+ * If you're not planning to use transition for gallery at all,
2513
+ * you may set options hideAnimationDuration and showAnimationDuration to 0,
2514
+ * and just delete startAnimation function.
2515
+ *
2516
+ */
2517
+
2518
+
2519
+ var _showOrHideTimeout,
2520
+ _showOrHide = function(item, img, out, completeFn) {
2521
+
2522
+ if(_showOrHideTimeout) {
2523
+ clearTimeout(_showOrHideTimeout);
2524
+ }
2525
+
2526
+ _initialZoomRunning = true;
2527
+ _initialContentSet = true;
2528
+
2529
+ // dimensions of small thumbnail {x:,y:,w:}.
2530
+ // Height is optional, as calculated based on large image.
2531
+ var thumbBounds;
2532
+ if(item.initialLayout) {
2533
+ thumbBounds = item.initialLayout;
2534
+ item.initialLayout = null;
2535
+ } else {
2536
+ thumbBounds = _options.getThumbBoundsFn && _options.getThumbBoundsFn(_currentItemIndex);
2537
+ }
2538
+
2539
+ var duration = out ? _options.hideAnimationDuration : _options.showAnimationDuration;
2540
+
2541
+ var onComplete = function() {
2542
+ _stopAnimation('initialZoom');
2543
+ if(!out) {
2544
+ _applyBgOpacity(1);
2545
+ if(img) {
2546
+ img.style.display = 'block';
2547
+ }
2548
+ framework.addClass(template, 'pswp--animated-in');
2549
+ _shout('initialZoom' + (out ? 'OutEnd' : 'InEnd'));
2550
+ } else {
2551
+ self.template.removeAttribute('style');
2552
+ self.bg.removeAttribute('style');
2553
+ }
2554
+
2555
+ if(completeFn) {
2556
+ completeFn();
2557
+ }
2558
+ _initialZoomRunning = false;
2559
+ };
2560
+
2561
+ // if bounds aren't provided, just open gallery without animation
2562
+ if(!duration || !thumbBounds || thumbBounds.x === undefined) {
2563
+
2564
+ _shout('initialZoom' + (out ? 'Out' : 'In') );
2565
+
2566
+ _currZoomLevel = item.initialZoomLevel;
2567
+ _equalizePoints(_panOffset, item.initialPosition );
2568
+ _applyCurrentZoomPan();
2569
+
2570
+ template.style.opacity = out ? 0 : 1;
2571
+ _applyBgOpacity(1);
2572
+
2573
+ if(duration) {
2574
+ setTimeout(function() {
2575
+ onComplete();
2576
+ }, duration);
2577
+ } else {
2578
+ onComplete();
2579
+ }
2580
+
2581
+ return;
2582
+ }
2583
+
2584
+ var startAnimation = function() {
2585
+ var closeWithRaf = _closedByScroll,
2586
+ fadeEverything = !self.currItem.src || self.currItem.loadError || _options.showHideOpacity;
2587
+
2588
+ // apply hw-acceleration to image
2589
+ if(item.miniImg) {
2590
+ item.miniImg.style.webkitBackfaceVisibility = 'hidden';
2591
+ }
2592
+
2593
+ if(!out) {
2594
+ _currZoomLevel = thumbBounds.w / item.w;
2595
+ _panOffset.x = thumbBounds.x;
2596
+ _panOffset.y = thumbBounds.y - _initalWindowScrollY;
2597
+
2598
+ self[fadeEverything ? 'template' : 'bg'].style.opacity = 0.001;
2599
+ _applyCurrentZoomPan();
2600
+ }
2601
+
2602
+ _registerStartAnimation('initialZoom');
2603
+
2604
+ if(out && !closeWithRaf) {
2605
+ framework.removeClass(template, 'pswp--animated-in');
2606
+ }
2607
+
2608
+ if(fadeEverything) {
2609
+ if(out) {
2610
+ framework[ (closeWithRaf ? 'remove' : 'add') + 'Class' ](template, 'pswp--animate_opacity');
2611
+ } else {
2612
+ setTimeout(function() {
2613
+ framework.addClass(template, 'pswp--animate_opacity');
2614
+ }, 30);
2615
+ }
2616
+ }
2617
+
2618
+ _showOrHideTimeout = setTimeout(function() {
2619
+
2620
+ _shout('initialZoom' + (out ? 'Out' : 'In') );
2621
+
2622
+
2623
+ if(!out) {
2624
+
2625
+ // "in" animation always uses CSS transitions (instead of rAF).
2626
+ // CSS transition work faster here,
2627
+ // as developer may also want to animate other things,
2628
+ // like ui on top of sliding area, which can be animated just via CSS
2629
+
2630
+ _currZoomLevel = item.initialZoomLevel;
2631
+ _equalizePoints(_panOffset, item.initialPosition );
2632
+ _applyCurrentZoomPan();
2633
+ _applyBgOpacity(1);
2634
+
2635
+ if(fadeEverything) {
2636
+ template.style.opacity = 1;
2637
+ } else {
2638
+ _applyBgOpacity(1);
2639
+ }
2640
+
2641
+ _showOrHideTimeout = setTimeout(onComplete, duration + 20);
2642
+ } else {
2643
+
2644
+ // "out" animation uses rAF only when PhotoSwipe is closed by browser scroll, to recalculate position
2645
+ var destZoomLevel = thumbBounds.w / item.w,
2646
+ initialPanOffset = {
2647
+ x: _panOffset.x,
2648
+ y: _panOffset.y
2649
+ },
2650
+ initialZoomLevel = _currZoomLevel,
2651
+ initalBgOpacity = _bgOpacity,
2652
+ onUpdate = function(now) {
2653
+
2654
+ if(now === 1) {
2655
+ _currZoomLevel = destZoomLevel;
2656
+ _panOffset.x = thumbBounds.x;
2657
+ _panOffset.y = thumbBounds.y - _currentWindowScrollY;
2658
+ } else {
2659
+ _currZoomLevel = (destZoomLevel - initialZoomLevel) * now + initialZoomLevel;
2660
+ _panOffset.x = (thumbBounds.x - initialPanOffset.x) * now + initialPanOffset.x;
2661
+ _panOffset.y = (thumbBounds.y - _currentWindowScrollY - initialPanOffset.y) * now + initialPanOffset.y;
2662
+ }
2663
+
2664
+ _applyCurrentZoomPan();
2665
+ if(fadeEverything) {
2666
+ template.style.opacity = 1 - now;
2667
+ } else {
2668
+ _applyBgOpacity( initalBgOpacity - now * initalBgOpacity );
2669
+ }
2670
+ };
2671
+
2672
+ if(closeWithRaf) {
2673
+ _animateProp('initialZoom', 0, 1, duration, framework.easing.cubic.out, onUpdate, onComplete);
2674
+ } else {
2675
+ onUpdate(1);
2676
+ _showOrHideTimeout = setTimeout(onComplete, duration + 20);
2677
+ }
2678
+ }
2679
+
2680
+ }, out ? 25 : 90); // Main purpose of this delay is to give browser time to paint and
2681
+ // create composite layers of PhotoSwipe UI parts (background, controls, caption, arrows).
2682
+ // Which avoids lag at the beginning of scale transition.
2683
+ };
2684
+ startAnimation();
2685
+
2686
+
2687
+ };
2688
+
2689
+ /*>>show-hide-transition*/
2690
+
2691
+ /*>>items-controller*/
2692
+ /**
2693
+ *
2694
+ * Controller manages gallery items, their dimensions, and their content.
2695
+ *
2696
+ */
2697
+
2698
+ var _items,
2699
+ _tempPanAreaSize = {},
2700
+ _imagesToAppendPool = [],
2701
+ _initialContentSet,
2702
+ _initialZoomRunning,
2703
+ _controllerDefaultOptions = {
2704
+ index: 0,
2705
+ errorMsg: '<div class="pswp__error-msg"><a href="%url%" target="_blank">The image</a> could not be loaded.</div>',
2706
+ forceProgressiveLoading: false, // TODO
2707
+ preload: [1,1],
2708
+ getNumItemsFn: function() {
2709
+ return _items.length;
2710
+ }
2711
+ };
2712
+
2713
+
2714
+ var _getItemAt,
2715
+ _getNumItems,
2716
+ _initialIsLoop,
2717
+ _getZeroBounds = function() {
2718
+ return {
2719
+ center:{x:0,y:0},
2720
+ max:{x:0,y:0},
2721
+ min:{x:0,y:0}
2722
+ };
2723
+ },
2724
+ _calculateSingleItemPanBounds = function(item, realPanElementW, realPanElementH ) {
2725
+ var bounds = item.bounds;
2726
+
2727
+ // position of element when it's centered
2728
+ bounds.center.x = Math.round((_tempPanAreaSize.x - realPanElementW) / 2);
2729
+ bounds.center.y = Math.round((_tempPanAreaSize.y - realPanElementH) / 2) + item.vGap.top;
2730
+
2731
+ // maximum pan position
2732
+ bounds.max.x = (realPanElementW > _tempPanAreaSize.x) ?
2733
+ Math.round(_tempPanAreaSize.x - realPanElementW) :
2734
+ bounds.center.x;
2735
+
2736
+ bounds.max.y = (realPanElementH > _tempPanAreaSize.y) ?
2737
+ Math.round(_tempPanAreaSize.y - realPanElementH) + item.vGap.top :
2738
+ bounds.center.y;
2739
+
2740
+ // minimum pan position
2741
+ bounds.min.x = (realPanElementW > _tempPanAreaSize.x) ? 0 : bounds.center.x;
2742
+ bounds.min.y = (realPanElementH > _tempPanAreaSize.y) ? item.vGap.top : bounds.center.y;
2743
+ },
2744
+ _calculateItemSize = function(item, viewportSize, zoomLevel) {
2745
+
2746
+ if (item.src && !item.loadError) {
2747
+ var isInitial = !zoomLevel;
2748
+
2749
+ if(isInitial) {
2750
+ if(!item.vGap) {
2751
+ item.vGap = {top:0,bottom:0};
2752
+ }
2753
+ // allows overriding vertical margin for individual items
2754
+ _shout('parseVerticalMargin', item);
2755
+ }
2756
+
2757
+
2758
+ _tempPanAreaSize.x = viewportSize.x;
2759
+ _tempPanAreaSize.y = viewportSize.y - item.vGap.top - item.vGap.bottom;
2760
+
2761
+ if (isInitial) {
2762
+ var hRatio = _tempPanAreaSize.x / item.w;
2763
+ var vRatio = _tempPanAreaSize.y / item.h;
2764
+
2765
+ item.fitRatio = hRatio < vRatio ? hRatio : vRatio;
2766
+ //item.fillRatio = hRatio > vRatio ? hRatio : vRatio;
2767
+
2768
+ var scaleMode = _options.scaleMode;
2769
+
2770
+ if (scaleMode === 'orig') {
2771
+ zoomLevel = 1;
2772
+ } else if (scaleMode === 'fit') {
2773
+ zoomLevel = item.fitRatio;
2774
+ }
2775
+
2776
+ if (zoomLevel > 1) {
2777
+ zoomLevel = 1;
2778
+ }
2779
+
2780
+ item.initialZoomLevel = zoomLevel;
2781
+
2782
+ if(!item.bounds) {
2783
+ // reuse bounds object
2784
+ item.bounds = _getZeroBounds();
2785
+ }
2786
+ }
2787
+
2788
+ if(!zoomLevel) {
2789
+ return;
2790
+ }
2791
+
2792
+ _calculateSingleItemPanBounds(item, item.w * zoomLevel, item.h * zoomLevel);
2793
+
2794
+ if (isInitial && zoomLevel === item.initialZoomLevel) {
2795
+ item.initialPosition = item.bounds.center;
2796
+ }
2797
+
2798
+ return item.bounds;
2799
+ } else {
2800
+ item.w = item.h = 0;
2801
+ item.initialZoomLevel = item.fitRatio = 1;
2802
+ item.bounds = _getZeroBounds();
2803
+ item.initialPosition = item.bounds.center;
2804
+
2805
+ // if it's not image, we return zero bounds (content is not zoomable)
2806
+ return item.bounds;
2807
+ }
2808
+
2809
+ },
2810
+
2811
+
2812
+
2813
+
2814
+ _appendImage = function(index, item, baseDiv, img, preventAnimation, keepPlaceholder) {
2815
+
2816
+
2817
+ if(item.loadError) {
2818
+ return;
2819
+ }
2820
+
2821
+ if(img) {
2822
+
2823
+ item.imageAppended = true;
2824
+ _setImageSize(item, img, (item === self.currItem && _renderMaxResolution) );
2825
+
2826
+ baseDiv.appendChild(img);
2827
+
2828
+ if(keepPlaceholder) {
2829
+ setTimeout(function() {
2830
+ if(item && item.loaded && item.placeholder) {
2831
+ item.placeholder.style.display = 'none';
2832
+ item.placeholder = null;
2833
+ }
2834
+ }, 500);
2835
+ }
2836
+ }
2837
+ },
2838
+
2839
+
2840
+
2841
+ _preloadImage = function(item) {
2842
+ item.loading = true;
2843
+ item.loaded = false;
2844
+ var img = item.img = framework.createEl('pswp__img', 'img');
2845
+ var onComplete = function() {
2846
+ item.loading = false;
2847
+ item.loaded = true;
2848
+
2849
+ if(item.loadComplete) {
2850
+ item.loadComplete(item);
2851
+ } else {
2852
+ item.img = null; // no need to store image object
2853
+ }
2854
+ img.onload = img.onerror = null;
2855
+ img = null;
2856
+ };
2857
+ img.onload = onComplete;
2858
+ img.onerror = function() {
2859
+ item.loadError = true;
2860
+ onComplete();
2861
+ };
2862
+
2863
+ img.src = item.src;// + '?a=' + Math.random();
2864
+
2865
+ return img;
2866
+ },
2867
+ _checkForError = function(item, cleanUp) {
2868
+ if(item.src && item.loadError && item.container) {
2869
+
2870
+ if(cleanUp) {
2871
+ item.container.innerHTML = '';
2872
+ }
2873
+
2874
+ item.container.innerHTML = _options.errorMsg.replace('%url%', item.src );
2875
+ return true;
2876
+
2877
+ }
2878
+ },
2879
+ _setImageSize = function(item, img, maxRes) {
2880
+ if(!item.src) {
2881
+ return;
2882
+ }
2883
+
2884
+ if(!img) {
2885
+ img = item.container.lastChild;
2886
+ }
2887
+
2888
+ var w = maxRes ? item.w : Math.round(item.w * item.fitRatio),
2889
+ h = maxRes ? item.h : Math.round(item.h * item.fitRatio);
2890
+
2891
+ if(item.placeholder && !item.loaded) {
2892
+ item.placeholder.style.width = w + 'px';
2893
+ item.placeholder.style.height = h + 'px';
2894
+ }
2895
+
2896
+ img.style.width = w + 'px';
2897
+ img.style.height = h + 'px';
2898
+ },
2899
+ _appendImagesPool = function() {
2900
+
2901
+ if(_imagesToAppendPool.length) {
2902
+ var poolItem;
2903
+
2904
+ for(var i = 0; i < _imagesToAppendPool.length; i++) {
2905
+ poolItem = _imagesToAppendPool[i];
2906
+ if( poolItem.holder.index === poolItem.index ) {
2907
+ _appendImage(poolItem.index, poolItem.item, poolItem.baseDiv, poolItem.img, false, poolItem.clearPlaceholder);
2908
+ }
2909
+ }
2910
+ _imagesToAppendPool = [];
2911
+ }
2912
+ };
2913
+
2914
+
2915
+
2916
+ _registerModule('Controller', {
2917
+
2918
+ publicMethods: {
2919
+
2920
+ lazyLoadItem: function(index) {
2921
+ index = _getLoopedId(index);
2922
+ var item = _getItemAt(index);
2923
+
2924
+ if(!item || ((item.loaded || item.loading) && !_itemsNeedUpdate)) {
2925
+ return;
2926
+ }
2927
+
2928
+ _shout('gettingData', index, item);
2929
+
2930
+ if (!item.src) {
2931
+ return;
2932
+ }
2933
+
2934
+ _preloadImage(item);
2935
+ },
2936
+ initController: function() {
2937
+ framework.extend(_options, _controllerDefaultOptions, true);
2938
+ self.items = _items = items;
2939
+ _getItemAt = self.getItemAt;
2940
+ _getNumItems = _options.getNumItemsFn; //self.getNumItems;
2941
+
2942
+
2943
+
2944
+ _initialIsLoop = _options.loop;
2945
+ if(_getNumItems() < 3) {
2946
+ _options.loop = false; // disable loop if less then 3 items
2947
+ }
2948
+
2949
+ _listen('beforeChange', function(diff) {
2950
+
2951
+ var p = _options.preload,
2952
+ isNext = diff === null ? true : (diff >= 0),
2953
+ preloadBefore = Math.min(p[0], _getNumItems() ),
2954
+ preloadAfter = Math.min(p[1], _getNumItems() ),
2955
+ i;
2956
+
2957
+
2958
+ for(i = 1; i <= (isNext ? preloadAfter : preloadBefore); i++) {
2959
+ self.lazyLoadItem(_currentItemIndex+i);
2960
+ }
2961
+ for(i = 1; i <= (isNext ? preloadBefore : preloadAfter); i++) {
2962
+ self.lazyLoadItem(_currentItemIndex-i);
2963
+ }
2964
+ });
2965
+
2966
+ _listen('initialLayout', function() {
2967
+ self.currItem.initialLayout = _options.getThumbBoundsFn && _options.getThumbBoundsFn(_currentItemIndex);
2968
+ });
2969
+
2970
+ _listen('mainScrollAnimComplete', _appendImagesPool);
2971
+ _listen('initialZoomInEnd', _appendImagesPool);
2972
+
2973
+
2974
+
2975
+ _listen('destroy', function() {
2976
+ var item;
2977
+ for(var i = 0; i < _items.length; i++) {
2978
+ item = _items[i];
2979
+ // remove reference to DOM elements, for GC
2980
+ if(item.container) {
2981
+ item.container = null;
2982
+ }
2983
+ if(item.placeholder) {
2984
+ item.placeholder = null;
2985
+ }
2986
+ if(item.img) {
2987
+ item.img = null;
2988
+ }
2989
+ if(item.preloader) {
2990
+ item.preloader = null;
2991
+ }
2992
+ if(item.loadError) {
2993
+ item.loaded = item.loadError = false;
2994
+ }
2995
+ }
2996
+ _imagesToAppendPool = null;
2997
+ });
2998
+ },
2999
+
3000
+
3001
+ getItemAt: function(index) {
3002
+ if (index >= 0) {
3003
+ return _items[index] !== undefined ? _items[index] : false;
3004
+ }
3005
+ return false;
3006
+ },
3007
+
3008
+ allowProgressiveImg: function() {
3009
+ // 1. Progressive image loading isn't working on webkit/blink
3010
+ // when hw-acceleration (e.g. translateZ) is applied to IMG element.
3011
+ // That's why in PhotoSwipe parent element gets zoom transform, not image itself.
3012
+ //
3013
+ // 2. Progressive image loading sometimes blinks in webkit/blink when applying animation to parent element.
3014
+ // That's why it's disabled on touch devices (mainly because of swipe transition)
3015
+ //
3016
+ // 3. Progressive image loading sometimes doesn't work in IE (up to 11).
3017
+
3018
+ // Don't allow progressive loading on non-large touch devices
3019
+ return _options.forceProgressiveLoading || !_likelyTouchDevice || _options.mouseUsed || screen.width > 1200;
3020
+ // 1200 - to eliminate touch devices with large screen (like Chromebook Pixel)
3021
+ },
3022
+
3023
+ setContent: function(holder, index) {
3024
+
3025
+ if(_options.loop) {
3026
+ index = _getLoopedId(index);
3027
+ }
3028
+
3029
+ var prevItem = self.getItemAt(holder.index);
3030
+ if(prevItem) {
3031
+ prevItem.container = null;
3032
+ }
3033
+
3034
+ var item = self.getItemAt(index),
3035
+ img;
3036
+
3037
+ if(!item) {
3038
+ holder.el.innerHTML = '';
3039
+ return;
3040
+ }
3041
+
3042
+ // allow to override data
3043
+ _shout('gettingData', index, item);
3044
+
3045
+ holder.index = index;
3046
+ holder.item = item;
3047
+
3048
+ // base container DIV is created only once for each of 3 holders
3049
+ var baseDiv = item.container = framework.createEl('pswp__zoom-wrap');
3050
+
3051
+
3052
+
3053
+ if(!item.src && item.html) {
3054
+ if(item.html.tagName) {
3055
+ baseDiv.appendChild(item.html);
3056
+ } else {
3057
+ baseDiv.innerHTML = item.html;
3058
+ }
3059
+ }
3060
+
3061
+ _checkForError(item);
3062
+
3063
+ _calculateItemSize(item, _viewportSize);
3064
+
3065
+ if(item.src && !item.loadError && !item.loaded) {
3066
+
3067
+ item.loadComplete = function(item) {
3068
+
3069
+ // gallery closed before image finished loading
3070
+ if(!_isOpen) {
3071
+ return;
3072
+ }
3073
+
3074
+ // check if holder hasn't changed while image was loading
3075
+ if(holder && holder.index === index ) {
3076
+ if( _checkForError(item, true) ) {
3077
+ item.loadComplete = item.img = null;
3078
+ _calculateItemSize(item, _viewportSize);
3079
+ _applyZoomPanToItem(item);
3080
+
3081
+ if(holder.index === _currentItemIndex) {
3082
+ // recalculate dimensions
3083
+ self.updateCurrZoomItem();
3084
+ }
3085
+ return;
3086
+ }
3087
+ if( !item.imageAppended ) {
3088
+ if(_features.transform && (_mainScrollAnimating || _initialZoomRunning) ) {
3089
+ _imagesToAppendPool.push({
3090
+ item:item,
3091
+ baseDiv:baseDiv,
3092
+ img:item.img,
3093
+ index:index,
3094
+ holder:holder,
3095
+ clearPlaceholder:true
3096
+ });
3097
+ } else {
3098
+ _appendImage(index, item, baseDiv, item.img, _mainScrollAnimating || _initialZoomRunning, true);
3099
+ }
3100
+ } else {
3101
+ // remove preloader & mini-img
3102
+ if(!_initialZoomRunning && item.placeholder) {
3103
+ item.placeholder.style.display = 'none';
3104
+ item.placeholder = null;
3105
+ }
3106
+ }
3107
+ }
3108
+
3109
+ item.loadComplete = null;
3110
+ item.img = null; // no need to store image element after it's added
3111
+
3112
+ _shout('imageLoadComplete', index, item);
3113
+ };
3114
+
3115
+ if(framework.features.transform) {
3116
+
3117
+ var placeholderClassName = 'pswp__img pswp__img--placeholder';
3118
+ placeholderClassName += (item.msrc ? '' : ' pswp__img--placeholder--blank');
3119
+
3120
+ var placeholder = framework.createEl(placeholderClassName, item.msrc ? 'img' : '');
3121
+ if(item.msrc) {
3122
+ placeholder.src = item.msrc;
3123
+ }
3124
+
3125
+ _setImageSize(item, placeholder);
3126
+
3127
+ baseDiv.appendChild(placeholder);
3128
+ item.placeholder = placeholder;
3129
+
3130
+ }
3131
+
3132
+
3133
+
3134
+
3135
+ if(!item.loading) {
3136
+ _preloadImage(item);
3137
+ }
3138
+
3139
+
3140
+ if( self.allowProgressiveImg() ) {
3141
+ // just append image
3142
+ if(!_initialContentSet && _features.transform) {
3143
+ _imagesToAppendPool.push({
3144
+ item:item,
3145
+ baseDiv:baseDiv,
3146
+ img:item.img,
3147
+ index:index,
3148
+ holder:holder
3149
+ });
3150
+ } else {
3151
+ _appendImage(index, item, baseDiv, item.img, true, true);
3152
+ }
3153
+ }
3154
+
3155
+ } else if(item.src && !item.loadError) {
3156
+ // image object is created every time, due to bugs of image loading & delay when switching images
3157
+ img = framework.createEl('pswp__img', 'img');
3158
+ img.style.opacity = 1;
3159
+ img.src = item.src;
3160
+ _setImageSize(item, img);
3161
+ _appendImage(index, item, baseDiv, img, true);
3162
+ }
3163
+
3164
+
3165
+ if(!_initialContentSet && index === _currentItemIndex) {
3166
+ _currZoomElementStyle = baseDiv.style;
3167
+ _showOrHide(item, (img ||item.img) );
3168
+ } else {
3169
+ _applyZoomPanToItem(item);
3170
+ }
3171
+
3172
+ holder.el.innerHTML = '';
3173
+ holder.el.appendChild(baseDiv);
3174
+ },
3175
+
3176
+ cleanSlide: function( item ) {
3177
+ if(item.img ) {
3178
+ item.img.onload = item.img.onerror = null;
3179
+ }
3180
+ item.loaded = item.loading = item.img = item.imageAppended = false;
3181
+ }
3182
+
3183
+ }
3184
+ });
3185
+
3186
+ /*>>items-controller*/
3187
+
3188
+ /*>>tap*/
3189
+ /**
3190
+ * tap.js:
3191
+ *
3192
+ * Displatches tap and double-tap events.
3193
+ *
3194
+ */
3195
+
3196
+ var tapTimer,
3197
+ tapReleasePoint = {},
3198
+ _dispatchTapEvent = function(origEvent, releasePoint, pointerType) {
3199
+ var e = document.createEvent( 'CustomEvent' ),
3200
+ eDetail = {
3201
+ origEvent:origEvent,
3202
+ target:origEvent.target,
3203
+ releasePoint: releasePoint,
3204
+ pointerType:pointerType || 'touch'
3205
+ };
3206
+
3207
+ e.initCustomEvent( 'pswpTap', true, true, eDetail );
3208
+ origEvent.target.dispatchEvent(e);
3209
+ };
3210
+
3211
+ _registerModule('Tap', {
3212
+ publicMethods: {
3213
+ initTap: function() {
3214
+ _listen('firstTouchStart', self.onTapStart);
3215
+ _listen('touchRelease', self.onTapRelease);
3216
+ _listen('destroy', function() {
3217
+ tapReleasePoint = {};
3218
+ tapTimer = null;
3219
+ });
3220
+ },
3221
+ onTapStart: function(touchList) {
3222
+ if(touchList.length > 1) {
3223
+ clearTimeout(tapTimer);
3224
+ tapTimer = null;
3225
+ }
3226
+ },
3227
+ onTapRelease: function(e, releasePoint) {
3228
+ if(!releasePoint) {
3229
+ return;
3230
+ }
3231
+
3232
+ if(!_moved && !_isMultitouch && !_numAnimations) {
3233
+ var p0 = releasePoint;
3234
+ if(tapTimer) {
3235
+ clearTimeout(tapTimer);
3236
+ tapTimer = null;
3237
+
3238
+ // Check if taped on the same place
3239
+ if ( _isNearbyPoints(p0, tapReleasePoint) ) {
3240
+ _shout('doubleTap', p0);
3241
+ return;
3242
+ }
3243
+ }
3244
+
3245
+ if(releasePoint.type === 'mouse') {
3246
+ _dispatchTapEvent(e, releasePoint, 'mouse');
3247
+ return;
3248
+ }
3249
+
3250
+ var clickedTagName = e.target.tagName.toUpperCase();
3251
+ // avoid double tap delay on buttons and elements that have class pswp__single-tap
3252
+ if(clickedTagName === 'BUTTON' || framework.hasClass(e.target, 'pswp__single-tap') ) {
3253
+ _dispatchTapEvent(e, releasePoint);
3254
+ return;
3255
+ }
3256
+
3257
+ _equalizePoints(tapReleasePoint, p0);
3258
+
3259
+ tapTimer = setTimeout(function() {
3260
+ _dispatchTapEvent(e, releasePoint);
3261
+ tapTimer = null;
3262
+ }, 300);
3263
+ }
3264
+ }
3265
+ }
3266
+ });
3267
+
3268
+ /*>>tap*/
3269
+
3270
+ /*>>desktop-zoom*/
3271
+ /**
3272
+ *
3273
+ * desktop-zoom.js:
3274
+ *
3275
+ * - Binds mousewheel event for paning zoomed image.
3276
+ * - Manages "dragging", "zoomed-in", "zoom-out" classes.
3277
+ * (which are used for cursors and zoom icon)
3278
+ * - Adds toggleDesktopZoom function.
3279
+ *
3280
+ */
3281
+
3282
+ var _wheelDelta;
3283
+
3284
+ _registerModule('DesktopZoom', {
3285
+
3286
+ publicMethods: {
3287
+
3288
+ initDesktopZoom: function() {
3289
+
3290
+ if(_oldIE) {
3291
+ // no zoom for old IE (<=8)
3292
+ return;
3293
+ }
3294
+
3295
+ if(_likelyTouchDevice) {
3296
+ // if detected hardware touch support, we wait until mouse is used,
3297
+ // and only then apply desktop-zoom features
3298
+ _listen('mouseUsed', function() {
3299
+ self.setupDesktopZoom();
3300
+ });
3301
+ } else {
3302
+ self.setupDesktopZoom(true);
3303
+ }
3304
+
3305
+ },
3306
+
3307
+ setupDesktopZoom: function(onInit) {
3308
+
3309
+ _wheelDelta = {};
3310
+
3311
+ var events = 'wheel mousewheel DOMMouseScroll';
3312
+
3313
+ _listen('bindEvents', function() {
3314
+ framework.bind(template, events, self.handleMouseWheel);
3315
+ });
3316
+
3317
+ _listen('unbindEvents', function() {
3318
+ if(_wheelDelta) {
3319
+ framework.unbind(template, events, self.handleMouseWheel);
3320
+ }
3321
+ });
3322
+
3323
+ self.mouseZoomedIn = false;
3324
+
3325
+ var hasDraggingClass,
3326
+ updateZoomable = function() {
3327
+ if(self.mouseZoomedIn) {
3328
+ framework.removeClass(template, 'pswp--zoomed-in');
3329
+ self.mouseZoomedIn = false;
3330
+ }
3331
+ if(_currZoomLevel < 1) {
3332
+ framework.addClass(template, 'pswp--zoom-allowed');
3333
+ } else {
3334
+ framework.removeClass(template, 'pswp--zoom-allowed');
3335
+ }
3336
+ removeDraggingClass();
3337
+ },
3338
+ removeDraggingClass = function() {
3339
+ if(hasDraggingClass) {
3340
+ framework.removeClass(template, 'pswp--dragging');
3341
+ hasDraggingClass = false;
3342
+ }
3343
+ };
3344
+
3345
+ _listen('resize' , updateZoomable);
3346
+ _listen('afterChange' , updateZoomable);
3347
+ _listen('pointerDown', function() {
3348
+ if(self.mouseZoomedIn) {
3349
+ hasDraggingClass = true;
3350
+ framework.addClass(template, 'pswp--dragging');
3351
+ }
3352
+ });
3353
+ _listen('pointerUp', removeDraggingClass);
3354
+
3355
+ if(!onInit) {
3356
+ updateZoomable();
3357
+ }
3358
+
3359
+ },
3360
+
3361
+ handleMouseWheel: function(e) {
3362
+
3363
+ if(_currZoomLevel <= self.currItem.fitRatio) {
3364
+ if( _options.modal ) {
3365
+
3366
+ if (!_options.closeOnScroll || _numAnimations || _isDragging) {
3367
+ e.preventDefault();
3368
+ } else if(_transformKey && Math.abs(e.deltaY) > 2) {
3369
+ // close PhotoSwipe
3370
+ // if browser supports transforms & scroll changed enough
3371
+ _closedByScroll = true;
3372
+ self.close();
3373
+ }
3374
+
3375
+ }
3376
+ return true;
3377
+ }
3378
+
3379
+ // allow just one event to fire
3380
+ e.stopPropagation();
3381
+
3382
+ // https://developer.mozilla.org/en-US/docs/Web/Events/wheel
3383
+ _wheelDelta.x = 0;
3384
+
3385
+ if('deltaX' in e) {
3386
+ if(e.deltaMode === 1 /* DOM_DELTA_LINE */) {
3387
+ // 18 - average line height
3388
+ _wheelDelta.x = e.deltaX * 18;
3389
+ _wheelDelta.y = e.deltaY * 18;
3390
+ } else {
3391
+ _wheelDelta.x = e.deltaX;
3392
+ _wheelDelta.y = e.deltaY;
3393
+ }
3394
+ } else if('wheelDelta' in e) {
3395
+ if(e.wheelDeltaX) {
3396
+ _wheelDelta.x = -0.16 * e.wheelDeltaX;
3397
+ }
3398
+ if(e.wheelDeltaY) {
3399
+ _wheelDelta.y = -0.16 * e.wheelDeltaY;
3400
+ } else {
3401
+ _wheelDelta.y = -0.16 * e.wheelDelta;
3402
+ }
3403
+ } else if('detail' in e) {
3404
+ _wheelDelta.y = e.detail;
3405
+ } else {
3406
+ return;
3407
+ }
3408
+
3409
+ _calculatePanBounds(_currZoomLevel, true);
3410
+
3411
+ var newPanX = _panOffset.x - _wheelDelta.x,
3412
+ newPanY = _panOffset.y - _wheelDelta.y;
3413
+
3414
+ // only prevent scrolling in nonmodal mode when not at edges
3415
+ if (_options.modal ||
3416
+ (
3417
+ newPanX <= _currPanBounds.min.x && newPanX >= _currPanBounds.max.x &&
3418
+ newPanY <= _currPanBounds.min.y && newPanY >= _currPanBounds.max.y
3419
+ ) ) {
3420
+ e.preventDefault();
3421
+ }
3422
+
3423
+ // TODO: use rAF instead of mousewheel?
3424
+ self.panTo(newPanX, newPanY);
3425
+ },
3426
+
3427
+ toggleDesktopZoom: function(centerPoint) {
3428
+ centerPoint = centerPoint || {x:_viewportSize.x/2 + _offset.x, y:_viewportSize.y/2 + _offset.y };
3429
+
3430
+ var doubleTapZoomLevel = _options.getDoubleTapZoom(true, self.currItem);
3431
+ var zoomOut = _currZoomLevel === doubleTapZoomLevel;
3432
+
3433
+ self.mouseZoomedIn = !zoomOut;
3434
+
3435
+ self.zoomTo(zoomOut ? self.currItem.initialZoomLevel : doubleTapZoomLevel, centerPoint, 333);
3436
+ framework[ (!zoomOut ? 'add' : 'remove') + 'Class'](template, 'pswp--zoomed-in');
3437
+ }
3438
+
3439
+ }
3440
+ });
3441
+
3442
+
3443
+ /*>>desktop-zoom*/
3444
+
3445
+ /*>>history*/
3446
+ /**
3447
+ *
3448
+ * history.js:
3449
+ *
3450
+ * - Back button to close gallery.
3451
+ *
3452
+ * - Unique URL for each slide: example.com/&pid=1&gid=3
3453
+ * (where PID is picture index, and GID and gallery index)
3454
+ *
3455
+ * - Switch URL when slides change.
3456
+ *
3457
+ */
3458
+
3459
+
3460
+ var _historyDefaultOptions = {
3461
+ history: true,
3462
+ galleryUID: 1
3463
+ };
3464
+
3465
+ var _historyUpdateTimeout,
3466
+ _hashChangeTimeout,
3467
+ _hashAnimCheckTimeout,
3468
+ _hashChangedByScript,
3469
+ _hashChangedByHistory,
3470
+ _hashReseted,
3471
+ _initialHash,
3472
+ _historyChanged,
3473
+ _closedFromURL,
3474
+ _urlChangedOnce,
3475
+ _windowLoc,
3476
+
3477
+ _supportsPushState,
3478
+
3479
+ _getHash = function() {
3480
+ return _windowLoc.hash.substring(1);
3481
+ },
3482
+ _cleanHistoryTimeouts = function() {
3483
+
3484
+ if(_historyUpdateTimeout) {
3485
+ clearTimeout(_historyUpdateTimeout);
3486
+ }
3487
+
3488
+ if(_hashAnimCheckTimeout) {
3489
+ clearTimeout(_hashAnimCheckTimeout);
3490
+ }
3491
+ },
3492
+
3493
+ // pid - Picture index
3494
+ // gid - Gallery index
3495
+ _parseItemIndexFromURL = function() {
3496
+ var hash = _getHash(),
3497
+ params = {};
3498
+
3499
+ if(hash.length < 5) { // pid=1
3500
+ return params;
3501
+ }
3502
+
3503
+ var i, vars = hash.split('&');
3504
+ for (i = 0; i < vars.length; i++) {
3505
+ if(!vars[i]) {
3506
+ continue;
3507
+ }
3508
+ var pair = vars[i].split('=');
3509
+ if(pair.length < 2) {
3510
+ continue;
3511
+ }
3512
+ params[pair[0]] = pair[1];
3513
+ }
3514
+ if(_options.galleryPIDs) {
3515
+ // detect custom pid in hash and search for it among the items collection
3516
+ var searchfor = params.pid;
3517
+ params.pid = 0; // if custom pid cannot be found, fallback to the first item
3518
+ for(i = 0; i < _items.length; i++) {
3519
+ if(_items[i].pid === searchfor) {
3520
+ params.pid = i;
3521
+ break;
3522
+ }
3523
+ }
3524
+ } else {
3525
+ params.pid = parseInt(params.pid,10)-1;
3526
+ }
3527
+ if( params.pid < 0 ) {
3528
+ params.pid = 0;
3529
+ }
3530
+ return params;
3531
+ },
3532
+ _updateHash = function() {
3533
+
3534
+ if(_hashAnimCheckTimeout) {
3535
+ clearTimeout(_hashAnimCheckTimeout);
3536
+ }
3537
+
3538
+
3539
+ if(_numAnimations || _isDragging) {
3540
+ // changing browser URL forces layout/paint in some browsers, which causes noticable lag during animation
3541
+ // that's why we update hash only when no animations running
3542
+ _hashAnimCheckTimeout = setTimeout(_updateHash, 500);
3543
+ return;
3544
+ }
3545
+
3546
+ if(_hashChangedByScript) {
3547
+ clearTimeout(_hashChangeTimeout);
3548
+ } else {
3549
+ _hashChangedByScript = true;
3550
+ }
3551
+
3552
+
3553
+ var pid = (_currentItemIndex + 1);
3554
+ var item = _getItemAt( _currentItemIndex );
3555
+ if(item.hasOwnProperty('pid')) {
3556
+ // carry forward any custom pid assigned to the item
3557
+ pid = item.pid;
3558
+ }
3559
+ var newHash = _initialHash + '&' + 'gid=' + _options.galleryUID + '&' + 'pid=' + pid;
3560
+
3561
+ if(!_historyChanged) {
3562
+ if(_windowLoc.hash.indexOf(newHash) === -1) {
3563
+ _urlChangedOnce = true;
3564
+ }
3565
+ // first time - add new hisory record, then just replace
3566
+ }
3567
+
3568
+ var newURL = _windowLoc.href.split('#')[0] + '#' + newHash;
3569
+
3570
+ if( _supportsPushState ) {
3571
+
3572
+ if('#' + newHash !== window.location.hash) {
3573
+ history[_historyChanged ? 'replaceState' : 'pushState']('', document.title, newURL);
3574
+ }
3575
+
3576
+ } else {
3577
+ if(_historyChanged) {
3578
+ _windowLoc.replace( newURL );
3579
+ } else {
3580
+ _windowLoc.hash = newHash;
3581
+ }
3582
+ }
3583
+
3584
+
3585
+
3586
+ _historyChanged = true;
3587
+ _hashChangeTimeout = setTimeout(function() {
3588
+ _hashChangedByScript = false;
3589
+ }, 60);
3590
+ };
3591
+
3592
+
3593
+
3594
+
3595
+
3596
+ _registerModule('History', {
3597
+
3598
+
3599
+
3600
+ publicMethods: {
3601
+ initHistory: function() {
3602
+
3603
+ framework.extend(_options, _historyDefaultOptions, true);
3604
+
3605
+ if( !_options.history ) {
3606
+ return;
3607
+ }
3608
+
3609
+
3610
+ _windowLoc = window.location;
3611
+ _urlChangedOnce = false;
3612
+ _closedFromURL = false;
3613
+ _historyChanged = false;
3614
+ _initialHash = _getHash();
3615
+ _supportsPushState = ('pushState' in history);
3616
+
3617
+
3618
+ if(_initialHash.indexOf('gid=') > -1) {
3619
+ _initialHash = _initialHash.split('&gid=')[0];
3620
+ _initialHash = _initialHash.split('?gid=')[0];
3621
+ }
3622
+
3623
+
3624
+ _listen('afterChange', self.updateURL);
3625
+ _listen('unbindEvents', function() {
3626
+ framework.unbind(window, 'hashchange', self.onHashChange);
3627
+ });
3628
+
3629
+
3630
+ var returnToOriginal = function() {
3631
+ _hashReseted = true;
3632
+ if(!_closedFromURL) {
3633
+
3634
+ if(_urlChangedOnce) {
3635
+ history.back();
3636
+ } else {
3637
+
3638
+ if(_initialHash) {
3639
+ _windowLoc.hash = _initialHash;
3640
+ } else {
3641
+ if (_supportsPushState) {
3642
+
3643
+ // remove hash from url without refreshing it or scrolling to top
3644
+ history.pushState('', document.title, _windowLoc.pathname + _windowLoc.search );
3645
+ } else {
3646
+ _windowLoc.hash = '';
3647
+ }
3648
+ }
3649
+ }
3650
+
3651
+ }
3652
+
3653
+ _cleanHistoryTimeouts();
3654
+ };
3655
+
3656
+
3657
+ _listen('unbindEvents', function() {
3658
+ if(_closedByScroll) {
3659
+ // if PhotoSwipe is closed by scroll, we go "back" before the closing animation starts
3660
+ // this is done to keep the scroll position
3661
+ returnToOriginal();
3662
+ }
3663
+ });
3664
+ _listen('destroy', function() {
3665
+ if(!_hashReseted) {
3666
+ returnToOriginal();
3667
+ }
3668
+ });
3669
+ _listen('firstUpdate', function() {
3670
+ _currentItemIndex = _parseItemIndexFromURL().pid;
3671
+ });
3672
+
3673
+
3674
+
3675
+
3676
+ var index = _initialHash.indexOf('pid=');
3677
+ if(index > -1) {
3678
+ _initialHash = _initialHash.substring(0, index);
3679
+ if(_initialHash.slice(-1) === '&') {
3680
+ _initialHash = _initialHash.slice(0, -1);
3681
+ }
3682
+ }
3683
+
3684
+
3685
+ setTimeout(function() {
3686
+ if(_isOpen) { // hasn't destroyed yet
3687
+ framework.bind(window, 'hashchange', self.onHashChange);
3688
+ }
3689
+ }, 40);
3690
+
3691
+ },
3692
+ onHashChange: function() {
3693
+
3694
+ if(_getHash() === _initialHash) {
3695
+
3696
+ _closedFromURL = true;
3697
+ self.close();
3698
+ return;
3699
+ }
3700
+ if(!_hashChangedByScript) {
3701
+
3702
+ _hashChangedByHistory = true;
3703
+ self.goTo( _parseItemIndexFromURL().pid );
3704
+ _hashChangedByHistory = false;
3705
+ }
3706
+
3707
+ },
3708
+ updateURL: function() {
3709
+
3710
+ // Delay the update of URL, to avoid lag during transition,
3711
+ // and to not to trigger actions like "refresh page sound" or "blinking favicon" to often
3712
+
3713
+ _cleanHistoryTimeouts();
3714
+
3715
+
3716
+ if(_hashChangedByHistory) {
3717
+ return;
3718
+ }
3719
+
3720
+ if(!_historyChanged) {
3721
+ _updateHash(); // first time
3722
+ } else {
3723
+ _historyUpdateTimeout = setTimeout(_updateHash, 800);
3724
+ }
3725
+ }
3726
+
3727
+ }
3728
+ });
3729
+
3730
+
3731
+ /*>>history*/
3732
+ framework.extend(self, publicMethods); };
3733
+ return PhotoSwipe;
3734
+ });
3735
+ /*! PhotoSwipe Default UI - 4.1.3 - 2019-01-08
3736
+ * http://photoswipe.com
3737
+ * Copyright (c) 2019 Dmitry Semenov; */
3738
+ /**
3739
+ *
3740
+ * UI on top of main sliding area (caption, arrows, close button, etc.).
3741
+ * Built just using public methods/properties of PhotoSwipe.
3742
+ *
3743
+ */
3744
+ (function (root, factory) {
3745
+ if (typeof define === 'function' && define.amd) {
3746
+ define(factory);
3747
+ } else if (typeof exports === 'object') {
3748
+ module.exports = factory();
3749
+ } else {
3750
+ root.PhotoSwipeUI_Default = factory();
3751
+ }
3752
+ })(this, function () {
3753
+
3754
+ 'use strict';
3755
+
3756
+
3757
+
3758
+ var PhotoSwipeUI_Default =
3759
+ function(pswp, framework) {
3760
+
3761
+ var ui = this;
3762
+ var _overlayUIUpdated = false,
3763
+ _controlsVisible = true,
3764
+ _fullscrenAPI,
3765
+ _controls,
3766
+ _captionContainer,
3767
+ _fakeCaptionContainer,
3768
+ _indexIndicator,
3769
+ _shareButton,
3770
+ _shareModal,
3771
+ _shareModalHidden = true,
3772
+ _initalCloseOnScrollValue,
3773
+ _isIdle,
3774
+ _listen,
3775
+
3776
+ _loadingIndicator,
3777
+ _loadingIndicatorHidden,
3778
+ _loadingIndicatorTimeout,
3779
+
3780
+ _galleryHasOneSlide,
3781
+
3782
+ _options,
3783
+ _defaultUIOptions = {
3784
+ barsSize: {top:44, bottom:'auto'},
3785
+ closeElClasses: ['item', 'caption', 'zoom-wrap', 'ui', 'top-bar'],
3786
+ timeToIdle: 4000,
3787
+ timeToIdleOutside: 1000,
3788
+ loadingIndicatorDelay: 1000, // 2s
3789
+
3790
+ addCaptionHTMLFn: function(item, captionEl /*, isFake */) {
3791
+ if(!item.title) {
3792
+ captionEl.children[0].innerHTML = '';
3793
+ return false;
3794
+ }
3795
+ captionEl.children[0].innerHTML = item.title;
3796
+ return true;
3797
+ },
3798
+
3799
+ closeEl:true,
3800
+ captionEl: true,
3801
+ fullscreenEl: true,
3802
+ zoomEl: true,
3803
+ shareEl: true,
3804
+ counterEl: true,
3805
+ arrowEl: true,
3806
+ preloaderEl: true,
3807
+
3808
+ tapToClose: false,
3809
+ tapToToggleControls: true,
3810
+
3811
+ clickToCloseNonZoomable: true,
3812
+
3813
+ shareButtons: [
3814
+ {id:'facebook', label:'Share on Facebook', url:'https://www.facebook.com/sharer/sharer.php?u={{url}}'},
3815
+ {id:'twitter', label:'Tweet', url:'https://twitter.com/intent/tweet?text={{text}}&url={{url}}'},
3816
+ {id:'pinterest', label:'Pin it', url:'http://www.pinterest.com/pin/create/button/'+
3817
+ '?url={{url}}&media={{image_url}}&description={{text}}'},
3818
+ {id:'download', label:'Download image', url:'{{raw_image_url}}', download:true}
3819
+ ],
3820
+ getImageURLForShare: function( /* shareButtonData */ ) {
3821
+ return pswp.currItem.src || '';
3822
+ },
3823
+ getPageURLForShare: function( /* shareButtonData */ ) {
3824
+ return window.location.href;
3825
+ },
3826
+ getTextForShare: function( /* shareButtonData */ ) {
3827
+ return pswp.currItem.title || '';
3828
+ },
3829
+
3830
+ indexIndicatorSep: ' / ',
3831
+ fitControlsWidth: 1200
3832
+
3833
+ },
3834
+ _blockControlsTap,
3835
+ _blockControlsTapTimeout;
3836
+
3837
+
3838
+
3839
+ var _onControlsTap = function(e) {
3840
+ if(_blockControlsTap) {
3841
+ return true;
3842
+ }
3843
+
3844
+
3845
+ e = e || window.event;
3846
+
3847
+ if(_options.timeToIdle && _options.mouseUsed && !_isIdle) {
3848
+ // reset idle timer
3849
+ _onIdleMouseMove();
3850
+ }
3851
+
3852
+
3853
+ var target = e.target || e.srcElement,
3854
+ uiElement,
3855
+ clickedClass = target.getAttribute('class') || '',
3856
+ found;
3857
+
3858
+ for(var i = 0; i < _uiElements.length; i++) {
3859
+ uiElement = _uiElements[i];
3860
+ if(uiElement.onTap && clickedClass.indexOf('pswp__' + uiElement.name ) > -1 ) {
3861
+ uiElement.onTap();
3862
+ found = true;
3863
+
3864
+ }
3865
+ }
3866
+
3867
+ if(found) {
3868
+ if(e.stopPropagation) {
3869
+ e.stopPropagation();
3870
+ }
3871
+ _blockControlsTap = true;
3872
+
3873
+ // Some versions of Android don't prevent ghost click event
3874
+ // when preventDefault() was called on touchstart and/or touchend.
3875
+ //
3876
+ // This happens on v4.3, 4.2, 4.1,
3877
+ // older versions strangely work correctly,
3878
+ // but just in case we add delay on all of them)
3879
+ var tapDelay = framework.features.isOldAndroid ? 600 : 30;
3880
+ _blockControlsTapTimeout = setTimeout(function() {
3881
+ _blockControlsTap = false;
3882
+ }, tapDelay);
3883
+ }
3884
+
3885
+ },
3886
+ _fitControlsInViewport = function() {
3887
+ return !pswp.likelyTouchDevice || _options.mouseUsed || screen.width > _options.fitControlsWidth;
3888
+ },
3889
+ _togglePswpClass = function(el, cName, add) {
3890
+ framework[ (add ? 'add' : 'remove') + 'Class' ](el, 'pswp__' + cName);
3891
+ },
3892
+
3893
+ // add class when there is just one item in the gallery
3894
+ // (by default it hides left/right arrows and 1ofX counter)
3895
+ _countNumItems = function() {
3896
+ var hasOneSlide = (_options.getNumItemsFn() === 1);
3897
+
3898
+ if(hasOneSlide !== _galleryHasOneSlide) {
3899
+ _togglePswpClass(_controls, 'ui--one-slide', hasOneSlide);
3900
+ _galleryHasOneSlide = hasOneSlide;
3901
+ }
3902
+ },
3903
+ _toggleShareModalClass = function() {
3904
+ _togglePswpClass(_shareModal, 'share-modal--hidden', _shareModalHidden);
3905
+ },
3906
+ _toggleShareModal = function() {
3907
+
3908
+ _shareModalHidden = !_shareModalHidden;
3909
+
3910
+
3911
+ if(!_shareModalHidden) {
3912
+ _toggleShareModalClass();
3913
+ setTimeout(function() {
3914
+ if(!_shareModalHidden) {
3915
+ framework.addClass(_shareModal, 'pswp__share-modal--fade-in');
3916
+ }
3917
+ }, 30);
3918
+ } else {
3919
+ framework.removeClass(_shareModal, 'pswp__share-modal--fade-in');
3920
+ setTimeout(function() {
3921
+ if(_shareModalHidden) {
3922
+ _toggleShareModalClass();
3923
+ }
3924
+ }, 300);
3925
+ }
3926
+
3927
+ if(!_shareModalHidden) {
3928
+ _updateShareURLs();
3929
+ }
3930
+ return false;
3931
+ },
3932
+
3933
+ _openWindowPopup = function(e) {
3934
+ e = e || window.event;
3935
+ var target = e.target || e.srcElement;
3936
+
3937
+ pswp.shout('shareLinkClick', e, target);
3938
+
3939
+ if(!target.href) {
3940
+ return false;
3941
+ }
3942
+
3943
+ if( target.hasAttribute('download') ) {
3944
+ return true;
3945
+ }
3946
+
3947
+ window.open(target.href, 'pswp_share', 'scrollbars=yes,resizable=yes,toolbar=no,'+
3948
+ 'location=yes,width=550,height=420,top=100,left=' +
3949
+ (window.screen ? Math.round(screen.width / 2 - 275) : 100) );
3950
+
3951
+ if(!_shareModalHidden) {
3952
+ _toggleShareModal();
3953
+ }
3954
+
3955
+ return false;
3956
+ },
3957
+ _updateShareURLs = function() {
3958
+ var shareButtonOut = '',
3959
+ shareButtonData,
3960
+ shareURL,
3961
+ image_url,
3962
+ page_url,
3963
+ share_text;
3964
+
3965
+ for(var i = 0; i < _options.shareButtons.length; i++) {
3966
+ shareButtonData = _options.shareButtons[i];
3967
+
3968
+ image_url = _options.getImageURLForShare(shareButtonData);
3969
+ page_url = _options.getPageURLForShare(shareButtonData);
3970
+ share_text = _options.getTextForShare(shareButtonData);
3971
+
3972
+ shareURL = shareButtonData.url.replace('{{url}}', encodeURIComponent(page_url) )
3973
+ .replace('{{image_url}}', encodeURIComponent(image_url) )
3974
+ .replace('{{raw_image_url}}', image_url )
3975
+ .replace('{{text}}', encodeURIComponent(share_text) );
3976
+
3977
+ shareButtonOut += '<a href="' + shareURL + '" target="_blank" '+
3978
+ 'class="pswp__share--' + shareButtonData.id + '"' +
3979
+ (shareButtonData.download ? 'download' : '') + '>' +
3980
+ shareButtonData.label + '</a>';
3981
+
3982
+ if(_options.parseShareButtonOut) {
3983
+ shareButtonOut = _options.parseShareButtonOut(shareButtonData, shareButtonOut);
3984
+ }
3985
+ }
3986
+ _shareModal.children[0].innerHTML = shareButtonOut;
3987
+ _shareModal.children[0].onclick = _openWindowPopup;
3988
+
3989
+ },
3990
+ _hasCloseClass = function(target) {
3991
+ for(var i = 0; i < _options.closeElClasses.length; i++) {
3992
+ if( framework.hasClass(target, 'pswp__' + _options.closeElClasses[i]) ) {
3993
+ return true;
3994
+ }
3995
+ }
3996
+ },
3997
+ _idleInterval,
3998
+ _idleTimer,
3999
+ _idleIncrement = 0,
4000
+ _onIdleMouseMove = function() {
4001
+ clearTimeout(_idleTimer);
4002
+ _idleIncrement = 0;
4003
+ if(_isIdle) {
4004
+ ui.setIdle(false);
4005
+ }
4006
+ },
4007
+ _onMouseLeaveWindow = function(e) {
4008
+ e = e ? e : window.event;
4009
+ var from = e.relatedTarget || e.toElement;
4010
+ if (!from || from.nodeName === 'HTML') {
4011
+ clearTimeout(_idleTimer);
4012
+ _idleTimer = setTimeout(function() {
4013
+ ui.setIdle(true);
4014
+ }, _options.timeToIdleOutside);
4015
+ }
4016
+ },
4017
+ _setupFullscreenAPI = function() {
4018
+ if(_options.fullscreenEl && !framework.features.isOldAndroid) {
4019
+ if(!_fullscrenAPI) {
4020
+ _fullscrenAPI = ui.getFullscreenAPI();
4021
+ }
4022
+ if(_fullscrenAPI) {
4023
+ framework.bind(document, _fullscrenAPI.eventK, ui.updateFullscreen);
4024
+ ui.updateFullscreen();
4025
+ framework.addClass(pswp.template, 'pswp--supports-fs');
4026
+ } else {
4027
+ framework.removeClass(pswp.template, 'pswp--supports-fs');
4028
+ }
4029
+ }
4030
+ },
4031
+ _setupLoadingIndicator = function() {
4032
+ // Setup loading indicator
4033
+ if(_options.preloaderEl) {
4034
+
4035
+ _toggleLoadingIndicator(true);
4036
+
4037
+ _listen('beforeChange', function() {
4038
+
4039
+ clearTimeout(_loadingIndicatorTimeout);
4040
+
4041
+ // display loading indicator with delay
4042
+ _loadingIndicatorTimeout = setTimeout(function() {
4043
+
4044
+ if(pswp.currItem && pswp.currItem.loading) {
4045
+
4046
+ if( !pswp.allowProgressiveImg() || (pswp.currItem.img && !pswp.currItem.img.naturalWidth) ) {
4047
+ // show preloader if progressive loading is not enabled,
4048
+ // or image width is not defined yet (because of slow connection)
4049
+ _toggleLoadingIndicator(false);
4050
+ // items-controller.js function allowProgressiveImg
4051
+ }
4052
+
4053
+ } else {
4054
+ _toggleLoadingIndicator(true); // hide preloader
4055
+ }
4056
+
4057
+ }, _options.loadingIndicatorDelay);
4058
+
4059
+ });
4060
+ _listen('imageLoadComplete', function(index, item) {
4061
+ if(pswp.currItem === item) {
4062
+ _toggleLoadingIndicator(true);
4063
+ }
4064
+ });
4065
+
4066
+ }
4067
+ },
4068
+ _toggleLoadingIndicator = function(hide) {
4069
+ if( _loadingIndicatorHidden !== hide ) {
4070
+ _togglePswpClass(_loadingIndicator, 'preloader--active', !hide);
4071
+ _loadingIndicatorHidden = hide;
4072
+ }
4073
+ },
4074
+ _applyNavBarGaps = function(item) {
4075
+ var gap = item.vGap;
4076
+
4077
+ if( _fitControlsInViewport() ) {
4078
+
4079
+ var bars = _options.barsSize;
4080
+ if(_options.captionEl && bars.bottom === 'auto') {
4081
+ if(!_fakeCaptionContainer) {
4082
+ _fakeCaptionContainer = framework.createEl('pswp__caption pswp__caption--fake');
4083
+ _fakeCaptionContainer.appendChild( framework.createEl('pswp__caption__center') );
4084
+ _controls.insertBefore(_fakeCaptionContainer, _captionContainer);
4085
+ framework.addClass(_controls, 'pswp__ui--fit');
4086
+ }
4087
+ if( _options.addCaptionHTMLFn(item, _fakeCaptionContainer, true) ) {
4088
+
4089
+ var captionSize = _fakeCaptionContainer.clientHeight;
4090
+ gap.bottom = parseInt(captionSize,10) || 44;
4091
+ } else {
4092
+ gap.bottom = bars.top; // if no caption, set size of bottom gap to size of top
4093
+ }
4094
+ } else {
4095
+ gap.bottom = bars.bottom === 'auto' ? 0 : bars.bottom;
4096
+ }
4097
+
4098
+ // height of top bar is static, no need to calculate it
4099
+ gap.top = bars.top;
4100
+ } else {
4101
+ gap.top = gap.bottom = 0;
4102
+ }
4103
+ },
4104
+ _setupIdle = function() {
4105
+ // Hide controls when mouse is used
4106
+ if(_options.timeToIdle) {
4107
+ _listen('mouseUsed', function() {
4108
+
4109
+ framework.bind(document, 'mousemove', _onIdleMouseMove);
4110
+ framework.bind(document, 'mouseout', _onMouseLeaveWindow);
4111
+
4112
+ _idleInterval = setInterval(function() {
4113
+ _idleIncrement++;
4114
+ if(_idleIncrement === 2) {
4115
+ ui.setIdle(true);
4116
+ }
4117
+ }, _options.timeToIdle / 2);
4118
+ });
4119
+ }
4120
+ },
4121
+ _setupHidingControlsDuringGestures = function() {
4122
+
4123
+ // Hide controls on vertical drag
4124
+ _listen('onVerticalDrag', function(now) {
4125
+ if(_controlsVisible && now < 0.95) {
4126
+ ui.hideControls();
4127
+ } else if(!_controlsVisible && now >= 0.95) {
4128
+ ui.showControls();
4129
+ }
4130
+ });
4131
+
4132
+ // Hide controls when pinching to close
4133
+ var pinchControlsHidden;
4134
+ _listen('onPinchClose' , function(now) {
4135
+ if(_controlsVisible && now < 0.9) {
4136
+ ui.hideControls();
4137
+ pinchControlsHidden = true;
4138
+ } else if(pinchControlsHidden && !_controlsVisible && now > 0.9) {
4139
+ ui.showControls();
4140
+ }
4141
+ });
4142
+
4143
+ _listen('zoomGestureEnded', function() {
4144
+ pinchControlsHidden = false;
4145
+ if(pinchControlsHidden && !_controlsVisible) {
4146
+ ui.showControls();
4147
+ }
4148
+ });
4149
+
4150
+ };
4151
+
4152
+
4153
+
4154
+ var _uiElements = [
4155
+ {
4156
+ name: 'caption',
4157
+ option: 'captionEl',
4158
+ onInit: function(el) {
4159
+ _captionContainer = el;
4160
+ }
4161
+ },
4162
+ {
4163
+ name: 'share-modal',
4164
+ option: 'shareEl',
4165
+ onInit: function(el) {
4166
+ _shareModal = el;
4167
+ },
4168
+ onTap: function() {
4169
+ _toggleShareModal();
4170
+ }
4171
+ },
4172
+ {
4173
+ name: 'button--share',
4174
+ option: 'shareEl',
4175
+ onInit: function(el) {
4176
+ _shareButton = el;
4177
+ },
4178
+ onTap: function() {
4179
+ _toggleShareModal();
4180
+ }
4181
+ },
4182
+ {
4183
+ name: 'button--zoom',
4184
+ option: 'zoomEl',
4185
+ onTap: pswp.toggleDesktopZoom
4186
+ },
4187
+ {
4188
+ name: 'counter',
4189
+ option: 'counterEl',
4190
+ onInit: function(el) {
4191
+ _indexIndicator = el;
4192
+ }
4193
+ },
4194
+ {
4195
+ name: 'button--close',
4196
+ option: 'closeEl',
4197
+ onTap: pswp.close
4198
+ },
4199
+ {
4200
+ name: 'button--arrow--left',
4201
+ option: 'arrowEl',
4202
+ onTap: pswp.prev
4203
+ },
4204
+ {
4205
+ name: 'button--arrow--right',
4206
+ option: 'arrowEl',
4207
+ onTap: pswp.next
4208
+ },
4209
+ {
4210
+ name: 'button--fs',
4211
+ option: 'fullscreenEl',
4212
+ onTap: function() {
4213
+ if(_fullscrenAPI.isFullscreen()) {
4214
+ _fullscrenAPI.exit();
4215
+ } else {
4216
+ _fullscrenAPI.enter();
4217
+ }
4218
+ }
4219
+ },
4220
+ {
4221
+ name: 'preloader',
4222
+ option: 'preloaderEl',
4223
+ onInit: function(el) {
4224
+ _loadingIndicator = el;
4225
+ }
4226
+ }
4227
+
4228
+ ];
4229
+
4230
+ var _setupUIElements = function() {
4231
+ var item,
4232
+ classAttr,
4233
+ uiElement;
4234
+
4235
+ var loopThroughChildElements = function(sChildren) {
4236
+ if(!sChildren) {
4237
+ return;
4238
+ }
4239
+
4240
+ var l = sChildren.length;
4241
+ for(var i = 0; i < l; i++) {
4242
+ item = sChildren[i];
4243
+ classAttr = item.className;
4244
+
4245
+ for(var a = 0; a < _uiElements.length; a++) {
4246
+ uiElement = _uiElements[a];
4247
+
4248
+ if(classAttr.indexOf('pswp__' + uiElement.name) > -1 ) {
4249
+
4250
+ if( _options[uiElement.option] ) { // if element is not disabled from options
4251
+
4252
+ framework.removeClass(item, 'pswp__element--disabled');
4253
+ if(uiElement.onInit) {
4254
+ uiElement.onInit(item);
4255
+ }
4256
+
4257
+ //item.style.display = 'block';
4258
+ } else {
4259
+ framework.addClass(item, 'pswp__element--disabled');
4260
+ //item.style.display = 'none';
4261
+ }
4262
+ }
4263
+ }
4264
+ }
4265
+ };
4266
+ loopThroughChildElements(_controls.children);
4267
+
4268
+ var topBar = framework.getChildByClass(_controls, 'pswp__top-bar');
4269
+ if(topBar) {
4270
+ loopThroughChildElements( topBar.children );
4271
+ }
4272
+ };
4273
+
4274
+
4275
+
4276
+
4277
+ ui.init = function() {
4278
+
4279
+ // extend options
4280
+ framework.extend(pswp.options, _defaultUIOptions, true);
4281
+
4282
+ // create local link for fast access
4283
+ _options = pswp.options;
4284
+
4285
+ // find pswp__ui element
4286
+ _controls = framework.getChildByClass(pswp.scrollWrap, 'pswp__ui');
4287
+
4288
+ // create local link
4289
+ _listen = pswp.listen;
4290
+
4291
+
4292
+ _setupHidingControlsDuringGestures();
4293
+
4294
+ // update controls when slides change
4295
+ _listen('beforeChange', ui.update);
4296
+
4297
+ // toggle zoom on double-tap
4298
+ _listen('doubleTap', function(point) {
4299
+ var initialZoomLevel = pswp.currItem.initialZoomLevel;
4300
+ if(pswp.getZoomLevel() !== initialZoomLevel) {
4301
+ pswp.zoomTo(initialZoomLevel, point, 333);
4302
+ } else {
4303
+ pswp.zoomTo(_options.getDoubleTapZoom(false, pswp.currItem), point, 333);
4304
+ }
4305
+ });
4306
+
4307
+ // Allow text selection in caption
4308
+ _listen('preventDragEvent', function(e, isDown, preventObj) {
4309
+ var t = e.target || e.srcElement;
4310
+ if(
4311
+ t &&
4312
+ t.getAttribute('class') && e.type.indexOf('mouse') > -1 &&
4313
+ ( t.getAttribute('class').indexOf('__caption') > 0 || (/(SMALL|STRONG|EM)/i).test(t.tagName) )
4314
+ ) {
4315
+ preventObj.prevent = false;
4316
+ }
4317
+ });
4318
+
4319
+ // bind events for UI
4320
+ _listen('bindEvents', function() {
4321
+ framework.bind(_controls, 'pswpTap click', _onControlsTap);
4322
+ framework.bind(pswp.scrollWrap, 'pswpTap', ui.onGlobalTap);
4323
+
4324
+ if(!pswp.likelyTouchDevice) {
4325
+ framework.bind(pswp.scrollWrap, 'mouseover', ui.onMouseOver);
4326
+ }
4327
+ });
4328
+
4329
+ // unbind events for UI
4330
+ _listen('unbindEvents', function() {
4331
+ if(!_shareModalHidden) {
4332
+ _toggleShareModal();
4333
+ }
4334
+
4335
+ if(_idleInterval) {
4336
+ clearInterval(_idleInterval);
4337
+ }
4338
+ framework.unbind(document, 'mouseout', _onMouseLeaveWindow);
4339
+ framework.unbind(document, 'mousemove', _onIdleMouseMove);
4340
+ framework.unbind(_controls, 'pswpTap click', _onControlsTap);
4341
+ framework.unbind(pswp.scrollWrap, 'pswpTap', ui.onGlobalTap);
4342
+ framework.unbind(pswp.scrollWrap, 'mouseover', ui.onMouseOver);
4343
+
4344
+ if(_fullscrenAPI) {
4345
+ framework.unbind(document, _fullscrenAPI.eventK, ui.updateFullscreen);
4346
+ if(_fullscrenAPI.isFullscreen()) {
4347
+ _options.hideAnimationDuration = 0;
4348
+ _fullscrenAPI.exit();
4349
+ }
4350
+ _fullscrenAPI = null;
4351
+ }
4352
+ });
4353
+
4354
+
4355
+ // clean up things when gallery is destroyed
4356
+ _listen('destroy', function() {
4357
+ if(_options.captionEl) {
4358
+ if(_fakeCaptionContainer) {
4359
+ _controls.removeChild(_fakeCaptionContainer);
4360
+ }
4361
+ framework.removeClass(_captionContainer, 'pswp__caption--empty');
4362
+ }
4363
+
4364
+ if(_shareModal) {
4365
+ _shareModal.children[0].onclick = null;
4366
+ }
4367
+ framework.removeClass(_controls, 'pswp__ui--over-close');
4368
+ framework.addClass( _controls, 'pswp__ui--hidden');
4369
+ ui.setIdle(false);
4370
+ });
4371
+
4372
+
4373
+ if(!_options.showAnimationDuration) {
4374
+ framework.removeClass( _controls, 'pswp__ui--hidden');
4375
+ }
4376
+ _listen('initialZoomIn', function() {
4377
+ if(_options.showAnimationDuration) {
4378
+ framework.removeClass( _controls, 'pswp__ui--hidden');
4379
+ }
4380
+ });
4381
+ _listen('initialZoomOut', function() {
4382
+ framework.addClass( _controls, 'pswp__ui--hidden');
4383
+ });
4384
+
4385
+ _listen('parseVerticalMargin', _applyNavBarGaps);
4386
+
4387
+ _setupUIElements();
4388
+
4389
+ if(_options.shareEl && _shareButton && _shareModal) {
4390
+ _shareModalHidden = true;
4391
+ }
4392
+
4393
+ _countNumItems();
4394
+
4395
+ _setupIdle();
4396
+
4397
+ _setupFullscreenAPI();
4398
+
4399
+ _setupLoadingIndicator();
4400
+ };
4401
+
4402
+ ui.setIdle = function(isIdle) {
4403
+ _isIdle = isIdle;
4404
+ _togglePswpClass(_controls, 'ui--idle', isIdle);
4405
+ };
4406
+
4407
+ ui.update = function() {
4408
+ // Don't update UI if it's hidden
4409
+ if(_controlsVisible && pswp.currItem) {
4410
+
4411
+ ui.updateIndexIndicator();
4412
+
4413
+ if(_options.captionEl) {
4414
+ _options.addCaptionHTMLFn(pswp.currItem, _captionContainer);
4415
+
4416
+ _togglePswpClass(_captionContainer, 'caption--empty', !pswp.currItem.title);
4417
+ }
4418
+
4419
+ _overlayUIUpdated = true;
4420
+
4421
+ } else {
4422
+ _overlayUIUpdated = false;
4423
+ }
4424
+
4425
+ if(!_shareModalHidden) {
4426
+ _toggleShareModal();
4427
+ }
4428
+
4429
+ _countNumItems();
4430
+ };
4431
+
4432
+ ui.updateFullscreen = function(e) {
4433
+
4434
+ if(e) {
4435
+ // some browsers change window scroll position during the fullscreen
4436
+ // so PhotoSwipe updates it just in case
4437
+ setTimeout(function() {
4438
+ pswp.setScrollOffset( 0, framework.getScrollY() );
4439
+ }, 50);
4440
+ }
4441
+
4442
+ // toogle pswp--fs class on root element
4443
+ framework[ (_fullscrenAPI.isFullscreen() ? 'add' : 'remove') + 'Class' ](pswp.template, 'pswp--fs');
4444
+ };
4445
+
4446
+ ui.updateIndexIndicator = function() {
4447
+ if(_options.counterEl) {
4448
+ _indexIndicator.innerHTML = (pswp.getCurrentIndex()+1) +
4449
+ _options.indexIndicatorSep +
4450
+ _options.getNumItemsFn();
4451
+ }
4452
+ };
4453
+
4454
+ ui.onGlobalTap = function(e) {
4455
+ e = e || window.event;
4456
+ var target = e.target || e.srcElement;
4457
+
4458
+ if(_blockControlsTap) {
4459
+ return;
4460
+ }
4461
+
4462
+ if(e.detail && e.detail.pointerType === 'mouse') {
4463
+
4464
+ // close gallery if clicked outside of the image
4465
+ if(_hasCloseClass(target)) {
4466
+ pswp.close();
4467
+ return;
4468
+ }
4469
+
4470
+ if(framework.hasClass(target, 'pswp__img')) {
4471
+ if(pswp.getZoomLevel() === 1 && pswp.getZoomLevel() <= pswp.currItem.fitRatio) {
4472
+ if(_options.clickToCloseNonZoomable) {
4473
+ pswp.close();
4474
+ }
4475
+ } else {
4476
+ pswp.toggleDesktopZoom(e.detail.releasePoint);
4477
+ }
4478
+ }
4479
+
4480
+ } else {
4481
+
4482
+ // tap anywhere (except buttons) to toggle visibility of controls
4483
+ if(_options.tapToToggleControls) {
4484
+ if(_controlsVisible) {
4485
+ ui.hideControls();
4486
+ } else {
4487
+ ui.showControls();
4488
+ }
4489
+ }
4490
+
4491
+ // tap to close gallery
4492
+ if(_options.tapToClose && (framework.hasClass(target, 'pswp__img') || _hasCloseClass(target)) ) {
4493
+ pswp.close();
4494
+ return;
4495
+ }
4496
+
4497
+ }
4498
+ };
4499
+ ui.onMouseOver = function(e) {
4500
+ e = e || window.event;
4501
+ var target = e.target || e.srcElement;
4502
+
4503
+ // add class when mouse is over an element that should close the gallery
4504
+ _togglePswpClass(_controls, 'ui--over-close', _hasCloseClass(target));
4505
+ };
4506
+
4507
+ ui.hideControls = function() {
4508
+ framework.addClass(_controls,'pswp__ui--hidden');
4509
+ _controlsVisible = false;
4510
+ };
4511
+
4512
+ ui.showControls = function() {
4513
+ _controlsVisible = true;
4514
+ if(!_overlayUIUpdated) {
4515
+ ui.update();
4516
+ }
4517
+ framework.removeClass(_controls,'pswp__ui--hidden');
4518
+ };
4519
+
4520
+ ui.supportsFullscreen = function() {
4521
+ var d = document;
4522
+ return !!(d.exitFullscreen || d.mozCancelFullScreen || d.webkitExitFullscreen || d.msExitFullscreen);
4523
+ };
4524
+
4525
+ ui.getFullscreenAPI = function() {
4526
+ var dE = document.documentElement,
4527
+ api,
4528
+ tF = 'fullscreenchange';
4529
+
4530
+ if (dE.requestFullscreen) {
4531
+ api = {
4532
+ enterK: 'requestFullscreen',
4533
+ exitK: 'exitFullscreen',
4534
+ elementK: 'fullscreenElement',
4535
+ eventK: tF
4536
+ };
4537
+
4538
+ } else if(dE.mozRequestFullScreen ) {
4539
+ api = {
4540
+ enterK: 'mozRequestFullScreen',
4541
+ exitK: 'mozCancelFullScreen',
4542
+ elementK: 'mozFullScreenElement',
4543
+ eventK: 'moz' + tF
4544
+ };
4545
+
4546
+
4547
+
4548
+ } else if(dE.webkitRequestFullscreen) {
4549
+ api = {
4550
+ enterK: 'webkitRequestFullscreen',
4551
+ exitK: 'webkitExitFullscreen',
4552
+ elementK: 'webkitFullscreenElement',
4553
+ eventK: 'webkit' + tF
4554
+ };
4555
+
4556
+ } else if(dE.msRequestFullscreen) {
4557
+ api = {
4558
+ enterK: 'msRequestFullscreen',
4559
+ exitK: 'msExitFullscreen',
4560
+ elementK: 'msFullscreenElement',
4561
+ eventK: 'MSFullscreenChange'
4562
+ };
4563
+ }
4564
+
4565
+ if(api) {
4566
+ api.enter = function() {
4567
+ // disable close-on-scroll in fullscreen
4568
+ _initalCloseOnScrollValue = _options.closeOnScroll;
4569
+ _options.closeOnScroll = false;
4570
+
4571
+ if(this.enterK === 'webkitRequestFullscreen') {
4572
+ pswp.template[this.enterK]( Element.ALLOW_KEYBOARD_INPUT );
4573
+ } else {
4574
+ return pswp.template[this.enterK]();
4575
+ }
4576
+ };
4577
+ api.exit = function() {
4578
+ _options.closeOnScroll = _initalCloseOnScrollValue;
4579
+
4580
+ return document[this.exitK]();
4581
+
4582
+ };
4583
+ api.isFullscreen = function() { return document[this.elementK]; };
4584
+ }
4585
+
4586
+ return api;
4587
+ };
4588
+
4589
+
4590
+
4591
+ };
4592
+ return PhotoSwipeUI_Default;
4593
+
4594
+
4595
+ });