intranet-pictures 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/intranet/pictures/responder.rb +27 -18
- data/lib/intranet/pictures/version.rb +1 -1
- data/lib/intranet/resources/haml/pictures_browse.haml +0 -1
- data/lib/intranet/resources/haml/pictures_home.haml +0 -3
- data/lib/intranet/resources/locales/en.yml +0 -1
- data/lib/intranet/resources/locales/fr.yml +0 -1
- data/lib/intranet/resources/www/jpictures.js +32 -14
- data/lib/intranet/resources/www/photoswipe/photoswipe-dynamic-caption-plugin.css +47 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe-dynamic-caption-plugin.esm.js +400 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe-lightbox.esm.js +1382 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe-lightbox.esm.js.map +1 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe-lightbox.esm.min.js +5 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe.css +383 -142
- data/lib/intranet/resources/www/photoswipe/photoswipe.esm.js +5279 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe.esm.js.map +1 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe.esm.min.js +5 -0
- data/lib/intranet/resources/www/style.css +13 -0
- data/spec/intranet/pictures/responder_spec.rb +78 -58
- metadata +26 -28
- data/lib/intranet/resources/haml/pictures_photoswipe.haml +0 -23
- data/lib/intranet/resources/www/photoswipe/LICENSE +0 -21
- data/lib/intranet/resources/www/photoswipe/default-skin/default-skin.css +0 -484
- data/lib/intranet/resources/www/photoswipe/default-skin/default-skin.png +0 -0
- data/lib/intranet/resources/www/photoswipe/default-skin/default-skin.svg +0 -1
- data/lib/intranet/resources/www/photoswipe/default-skin/preloader.gif +0 -0
- data/lib/intranet/resources/www/photoswipe/photoswipe-ui-default.js +0 -861
- data/lib/intranet/resources/www/photoswipe/photoswipe-ui-default.min.js +0 -4
- data/lib/intranet/resources/www/photoswipe/photoswipe.js +0 -3734
- data/lib/intranet/resources/www/photoswipe/photoswipe.min.js +0 -4
@@ -1,3734 +0,0 @@
|
|
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
|
-
});
|