promethee 1.7.12 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/promethee/rails/version.rb +1 -1
  3. data/node_modules/@fancyapps/fancybox/README.md +1 -1
  4. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.css +162 -161
  5. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js +1281 -790
  6. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.min.css +1 -1
  7. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.min.js +4 -3
  8. data/node_modules/@fancyapps/fancybox/docs/index.html +1398 -1321
  9. data/node_modules/@fancyapps/fancybox/package.json +52 -43
  10. data/node_modules/@fancyapps/fancybox/src/css/core.css +144 -142
  11. data/node_modules/@fancyapps/fancybox/src/css/thumbs.css +20 -23
  12. data/node_modules/@fancyapps/fancybox/src/js/core.js +883 -536
  13. data/node_modules/@fancyapps/fancybox/src/js/fullscreen.js +67 -64
  14. data/node_modules/@fancyapps/fancybox/src/js/guestures.js +114 -78
  15. data/node_modules/@fancyapps/fancybox/src/js/hash.js +13 -18
  16. data/node_modules/@fancyapps/fancybox/src/js/media.js +118 -29
  17. data/node_modules/@fancyapps/fancybox/src/js/share.js +8 -6
  18. data/node_modules/@fancyapps/fancybox/src/js/slideshow.js +55 -32
  19. data/node_modules/@fancyapps/fancybox/src/js/thumbs.js +22 -26
  20. data/node_modules/@fancyapps/fancybox/src/js/wheel.js +1 -1
  21. metadata +2 -46
  22. data/node_modules/fancybox/CHANGELOG.md +0 -125
  23. data/node_modules/fancybox/README.md +0 -249
  24. data/node_modules/fancybox/bower.json +0 -24
  25. data/node_modules/fancybox/demo/1_b.jpg +0 -0
  26. data/node_modules/fancybox/demo/1_s.jpg +0 -0
  27. data/node_modules/fancybox/demo/2_b.jpg +0 -0
  28. data/node_modules/fancybox/demo/2_s.jpg +0 -0
  29. data/node_modules/fancybox/demo/3_b.jpg +0 -0
  30. data/node_modules/fancybox/demo/3_s.jpg +0 -0
  31. data/node_modules/fancybox/demo/4_b.jpg +0 -0
  32. data/node_modules/fancybox/demo/4_s.jpg +0 -0
  33. data/node_modules/fancybox/demo/5_b.jpg +0 -0
  34. data/node_modules/fancybox/demo/5_s.jpg +0 -0
  35. data/node_modules/fancybox/demo/ajax.txt +0 -15
  36. data/node_modules/fancybox/demo/iframe.html +0 -26
  37. data/node_modules/fancybox/demo/index.html +0 -312
  38. data/node_modules/fancybox/dist/css/jquery.fancybox.css +0 -222
  39. data/node_modules/fancybox/dist/helpers/css/jquery.fancybox-buttons.css +0 -82
  40. data/node_modules/fancybox/dist/helpers/css/jquery.fancybox-thumbs.css +0 -46
  41. data/node_modules/fancybox/dist/helpers/img/fancybox_buttons.png +0 -0
  42. data/node_modules/fancybox/dist/helpers/js/jquery.fancybox-buttons.cjs.js +0 -121
  43. data/node_modules/fancybox/dist/helpers/js/jquery.fancybox-buttons.js +0 -122
  44. data/node_modules/fancybox/dist/helpers/js/jquery.fancybox-media.cjs.js +0 -199
  45. data/node_modules/fancybox/dist/helpers/js/jquery.fancybox-media.js +0 -199
  46. data/node_modules/fancybox/dist/helpers/js/jquery.fancybox-thumbs.cjs.js +0 -164
  47. data/node_modules/fancybox/dist/helpers/js/jquery.fancybox-thumbs.js +0 -165
  48. data/node_modules/fancybox/dist/helpers/scss/jquery.fancybox-buttons.scss +0 -100
  49. data/node_modules/fancybox/dist/helpers/scss/jquery.fancybox-thumbs.scss +0 -55
  50. data/node_modules/fancybox/dist/img/blank.gif +0 -0
  51. data/node_modules/fancybox/dist/img/fancybox_loading.gif +0 -0
  52. data/node_modules/fancybox/dist/img/fancybox_loading@2x.gif +0 -0
  53. data/node_modules/fancybox/dist/img/fancybox_overlay.png +0 -0
  54. data/node_modules/fancybox/dist/img/fancybox_sprite.png +0 -0
  55. data/node_modules/fancybox/dist/img/fancybox_sprite@2x.png +0 -0
  56. data/node_modules/fancybox/dist/js/jquery.fancybox.cjs.js +0 -2027
  57. data/node_modules/fancybox/dist/js/jquery.fancybox.js +0 -2018
  58. data/node_modules/fancybox/dist/js/jquery.fancybox.pack.js +0 -46
  59. data/node_modules/fancybox/dist/scss/jquery.fancybox.scss +0 -276
  60. data/node_modules/fancybox/fancybox.jquery.json +0 -31
  61. data/node_modules/fancybox/lib/jquery-1.10.2.min.js +0 -6
  62. data/node_modules/fancybox/lib/jquery.mousewheel.pack.js +0 -14
  63. data/node_modules/fancybox/package.json +0 -32
  64. data/node_modules/fancybox/sprite.psd +0 -0
  65. data/node_modules/fancybox/test.js +0 -10
@@ -1,7 +1,7 @@
1
1
  /* Thumbs */
2
2
 
3
3
  .fancybox-thumbs {
4
- background: #fff;
4
+ background: #ddd;
5
5
  bottom: 0;
6
6
  display: none;
7
7
  margin: 0;
@@ -29,7 +29,7 @@
29
29
  right: 212px;
30
30
  }
31
31
 
32
- .fancybox-thumbs > ul {
32
+ .fancybox-thumbs__list {
33
33
  font-size: 0;
34
34
  height: 100%;
35
35
  list-style: none;
@@ -43,27 +43,31 @@
43
43
  width: 100%;
44
44
  }
45
45
 
46
- .fancybox-thumbs-x > ul {
46
+ .fancybox-thumbs-x .fancybox-thumbs__list {
47
47
  overflow: hidden;
48
48
  }
49
49
 
50
- .fancybox-thumbs-y > ul::-webkit-scrollbar {
50
+ .fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar {
51
51
  width: 7px;
52
52
  }
53
53
 
54
- .fancybox-thumbs-y > ul::-webkit-scrollbar-track {
54
+ .fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-track {
55
55
  background: #fff;
56
56
  border-radius: 10px;
57
57
  box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
58
58
  }
59
59
 
60
- .fancybox-thumbs-y > ul::-webkit-scrollbar-thumb {
60
+ .fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-thumb {
61
61
  background: #2a2a2a;
62
62
  border-radius: 10px;
63
63
  }
64
64
 
65
- .fancybox-thumbs > ul > li {
65
+ .fancybox-thumbs__list a {
66
66
  backface-visibility: hidden;
67
+ background-color: rgba(0, 0, 0, .1);
68
+ background-position: center center;
69
+ background-repeat: no-repeat;
70
+ background-size: cover;
67
71
  cursor: pointer;
68
72
  float: left;
69
73
  height: 75px;
@@ -78,18 +82,8 @@
78
82
  width: 100px;
79
83
  }
80
84
 
81
- .fancybox-thumbs-loading {
82
- background: rgba(0, 0, 0, .1);
83
- }
84
-
85
- .fancybox-thumbs > ul > li {
86
- background-position: center center;
87
- background-repeat: no-repeat;
88
- background-size: cover;
89
- }
90
-
91
- .fancybox-thumbs > ul > li:before {
92
- border: 4px solid #4ea7f9;
85
+ .fancybox-thumbs__list a::before {
86
+ border: 6px solid #ff5268;
93
87
  bottom: 0;
94
88
  content: '';
95
89
  left: 0;
@@ -101,20 +95,23 @@
101
95
  z-index: 99991;
102
96
  }
103
97
 
104
- .fancybox-thumbs .fancybox-thumbs-active:before {
98
+ .fancybox-thumbs__list a:focus::before {
99
+ opacity: .5;
100
+ }
101
+
102
+ .fancybox-thumbs__list a.fancybox-thumbs-active::before {
105
103
  opacity: 1;
106
104
  }
107
105
 
108
106
  /* Styling for Small-Screen Devices */
109
-
110
- @media all and (max-width: 800px) {
107
+ @media all and (max-width: 576px) {
111
108
  .fancybox-thumbs {
112
109
  width: 110px;
113
110
  }
114
111
  .fancybox-show-thumbs .fancybox-inner {
115
112
  right: 110px;
116
113
  }
117
- .fancybox-thumbs > ul > li {
114
+ .fancybox-thumbs__list a {
118
115
  max-width: calc(100% - 10px);
119
116
  }
120
117
  }
@@ -25,6 +25,10 @@
25
25
  // ========================
26
26
 
27
27
  var defaults = {
28
+ // Close existing modals
29
+ // Set this to false if you do not need to stack multiple instances
30
+ closeExisting: false,
31
+
28
32
  // Enable infinite gallery navigation
29
33
  loop: false,
30
34
 
@@ -34,6 +38,9 @@
34
38
  // Enable keyboard navigation
35
39
  keyboard: true,
36
40
 
41
+ // Should allow caption to overlap the content
42
+ preventCaptionOverlap: true,
43
+
37
44
  // Should display navigation arrows at the screen edges
38
45
  arrows: true,
39
46
 
@@ -56,7 +63,7 @@
56
63
  buttons: [
57
64
  "zoom",
58
65
  //"share",
59
- //"slideShow",
66
+ "slideShow",
60
67
  //"fullScreen",
61
68
  //"download",
62
69
  "thumbs",
@@ -94,7 +101,7 @@
94
101
  iframe: {
95
102
  // Iframe template
96
103
  tpl:
97
- '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" src=""></iframe>',
104
+ '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen allow="autoplay; fullscreen" src=""></iframe>',
98
105
 
99
106
  // Preload iframe before displaying it
100
107
  // This allows to calculate iframe content width and height
@@ -111,6 +118,17 @@
111
118
  }
112
119
  },
113
120
 
121
+ // For HTML5 video only
122
+ video: {
123
+ tpl:
124
+ '<video class="fancybox-video" controls controlsList="nodownload" poster="{{poster}}">' +
125
+ '<source src="{{src}}" type="{{format}}" />' +
126
+ 'Sorry, your browser doesn\'t support embedded videos, <a href="{{src}}">download</a> and watch with your favorite video player!' +
127
+ "</video>",
128
+ format: "", // custom video format
129
+ autoStart: true
130
+ },
131
+
114
132
  // Default content type if cannot be detected automatically
115
133
  defaultType: "image",
116
134
 
@@ -157,9 +175,7 @@
157
175
  '<div class="fancybox-container" role="dialog" tabindex="-1">' +
158
176
  '<div class="fancybox-bg"></div>' +
159
177
  '<div class="fancybox-inner">' +
160
- '<div class="fancybox-infobar">' +
161
- "<span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span>" +
162
- "</div>" +
178
+ '<div class="fancybox-infobar"><span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span></div>' +
163
179
  '<div class="fancybox-toolbar">{{buttons}}</div>' +
164
180
  '<div class="fancybox-navigation">{{arrows}}</div>' +
165
181
  '<div class="fancybox-stage"></div>' +
@@ -176,54 +192,49 @@
176
192
  btnTpl: {
177
193
  download:
178
194
  '<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;">' +
179
- '<svg viewBox="0 0 40 40">' +
180
- '<path d="M13,16 L20,23 L27,16 M20,7 L20,23 M10,24 L10,28 L30,28 L30,24" />' +
181
- "</svg>" +
195
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.62 17.09V19H5.38v-1.91zm-2.97-6.96L17 11.45l-5 4.87-5-4.87 1.36-1.32 2.68 2.64V5h1.92v7.77z"/></svg>' +
182
196
  "</a>",
183
197
 
184
198
  zoom:
185
199
  '<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' +
186
- '<svg viewBox="0 0 40 40">' +
187
- '<path d="M18,17 m-8,0 a8,8 0 1,0 16,0 a8,8 0 1,0 -16,0 M24,22 L31,29" />' +
188
- "</svg>" +
200
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.7 17.3l-3-3a5.9 5.9 0 0 0-.6-7.6 5.9 5.9 0 0 0-8.4 0 5.9 5.9 0 0 0 0 8.4 5.9 5.9 0 0 0 7.7.7l3 3a1 1 0 0 0 1.3 0c.4-.5.4-1 0-1.5zM8.1 13.8a4 4 0 0 1 0-5.7 4 4 0 0 1 5.7 0 4 4 0 0 1 0 5.7 4 4 0 0 1-5.7 0z"/></svg>' +
189
201
  "</button>",
190
202
 
191
203
  close:
192
204
  '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' +
193
- '<svg viewBox="0 0 40 40">' +
194
- '<path d="M10,10 L30,30 M30,10 L10,30" />' +
195
- "</svg>" +
205
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 10.6L6.6 5.2 5.2 6.6l5.4 5.4-5.4 5.4 1.4 1.4 5.4-5.4 5.4 5.4 1.4-1.4-5.4-5.4 5.4-5.4-1.4-1.4-5.4 5.4z"/></svg>' +
196
206
  "</button>",
197
207
 
198
- // This small close button will be appended to your html/inline/ajax content by default,
199
- // if "smallBtn" option is not set to false
200
- smallBtn:
201
- '<button data-fancybox-close class="fancybox-close-small" title="{{CLOSE}}"><svg viewBox="0 0 32 32"><path d="M10,10 L22,22 M22,10 L10,22"></path></svg></button>',
202
-
203
208
  // Arrows
204
209
  arrowLeft:
205
- '<a data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}" href="javascript:;">' +
206
- '<svg viewBox="0 0 40 40">' +
207
- '<path d="M18,12 L10,20 L18,28 M10,20 L30,20"></path>' +
208
- "</svg>" +
209
- "</a>",
210
+ '<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}">' +
211
+ '<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.28 15.7l-1.34 1.37L5 12l4.94-5.07 1.34 1.38-2.68 2.72H19v1.94H8.6z"/></svg></div>' +
212
+ "</button>",
210
213
 
211
214
  arrowRight:
212
- '<a data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}" href="javascript:;">' +
213
- '<svg viewBox="0 0 40 40">' +
214
- '<path d="M10,20 L30,20 M22,12 L30,20 L22,28"></path>' +
215
- "</svg>" +
216
- "</a>"
215
+ '<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}">' +
216
+ '<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.4 12.97l-2.68 2.72 1.34 1.38L19 12l-4.94-5.07-1.34 1.38 2.68 2.72H5v1.94z"/></svg></div>' +
217
+ "</button>",
218
+
219
+ // This small close button will be appended to your html/inline/ajax content by default,
220
+ // if "smallBtn" option is not set to false
221
+ smallBtn:
222
+ '<button type="button" data-fancybox-close class="fancybox-button fancybox-close-small" title="{{CLOSE}}">' +
223
+ '<svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="0 0 24 24"><path d="M13 12l5-5-1-1-5 5-5-5-1 1 5 5-5 5 1 1 5-5 5 5 1-1z"/></svg>' +
224
+ "</button>"
217
225
  },
218
226
 
219
227
  // Container is injected into this element
220
228
  parentEl: "body",
221
229
 
230
+ // Hide browser vertical scrollbars; use at your own risk
231
+ hideScrollbar: true,
232
+
222
233
  // Focus handling
223
234
  // ==============
224
235
 
225
236
  // Try to focus on the first focusable element after opening
226
- autoFocus: false,
237
+ autoFocus: true,
227
238
 
228
239
  // Put focus back to active element after closing
229
240
  backFocus: true,
@@ -238,7 +249,7 @@
238
249
  autoStart: false
239
250
  },
240
251
 
241
- // Set `touch: false` to disable dragging/swiping
252
+ // Set `touch: false` to disable panning/swiping
242
253
  touch: {
243
254
  vertical: true, // Allow to drag content vertically
244
255
  momentum: true // Continue movement after releasing mouse/touch when panning
@@ -251,19 +262,19 @@
251
262
  // Customize or add new media types
252
263
  // Example:
253
264
  /*
254
- media : {
255
- youtube : {
256
- params : {
257
- autoplay : 0
258
- }
259
- }
265
+ media : {
266
+ youtube : {
267
+ params : {
268
+ autoplay : 0
269
+ }
260
270
  }
261
- */
271
+ }
272
+ */
262
273
  media: {},
263
274
 
264
275
  slideShow: {
265
276
  autoStart: false,
266
- speed: 4000
277
+ speed: 3000
267
278
  },
268
279
 
269
280
  thumbs: {
@@ -283,11 +294,11 @@
283
294
  // See Documentation/API/Events for more information
284
295
  // Example:
285
296
  /*
286
- afterShow: function( instance, current ) {
287
- console.info( 'Clicked element:' );
288
- console.info( current.opts.$orig );
289
- }
290
- */
297
+ afterShow: function( instance, current ) {
298
+ console.info( 'Clicked element:' );
299
+ console.info( current.opts.$orig );
300
+ }
301
+ */
291
302
 
292
303
  onInit: $.noop, // When instance has been initialized
293
304
 
@@ -338,6 +349,7 @@
338
349
  // =============================================
339
350
 
340
351
  mobile: {
352
+ preventCaptionOverlap: false,
341
353
  idleTime: false,
342
354
  clickContent: function(current, event) {
343
355
  return current.type === "image" ? "toggleControls" : false;
@@ -416,6 +428,18 @@
416
428
  );
417
429
  })();
418
430
 
431
+ var cancelAFrame = (function() {
432
+ return (
433
+ window.cancelAnimationFrame ||
434
+ window.webkitCancelAnimationFrame ||
435
+ window.mozCancelAnimationFrame ||
436
+ window.oCancelAnimationFrame ||
437
+ function(id) {
438
+ window.clearTimeout(id);
439
+ }
440
+ );
441
+ })();
442
+
419
443
  // Detect the supported transition-end event property name
420
444
  // =======================================================
421
445
  var transitionEnd = (function() {
@@ -459,6 +483,30 @@
459
483
  return rez;
460
484
  };
461
485
 
486
+ // How much of an element is visible in viewport
487
+ // =============================================
488
+
489
+ var inViewport = function(elem) {
490
+ var elemCenter, rez;
491
+
492
+ if (!elem || elem.ownerDocument !== document) {
493
+ return false;
494
+ }
495
+
496
+ $(".fancybox-container").css("pointer-events", "none");
497
+
498
+ elemCenter = {
499
+ x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
500
+ y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
501
+ };
502
+
503
+ rez = document.elementFromPoint(elemCenter.x, elemCenter.y) === elem;
504
+
505
+ $(".fancybox-container").css("pointer-events", "");
506
+
507
+ return rez;
508
+ };
509
+
462
510
  // Class definition
463
511
  // ================
464
512
 
@@ -498,9 +546,6 @@
498
546
  return;
499
547
  }
500
548
 
501
- // Save last active element
502
- self.$lastFocus = $(document.activeElement).trigger("blur");
503
-
504
549
  self.init();
505
550
  };
506
551
 
@@ -512,34 +557,31 @@
512
557
  var self = this,
513
558
  firstItem = self.group[self.currIndex],
514
559
  firstItemOpts = firstItem.opts,
515
- scrollbarWidth = $.fancybox.scrollbarWidth,
516
- $scrollDiv,
517
560
  $container,
518
561
  buttonStr;
519
562
 
563
+ if (firstItemOpts.closeExisting) {
564
+ $.fancybox.close(true);
565
+ }
566
+
520
567
  // Hide scrollbars
521
568
  // ===============
522
569
 
523
- if (!$.fancybox.getInstance() && firstItemOpts.hideScrollbar !== false) {
524
- $("body").addClass("fancybox-active");
525
-
526
- if (!$.fancybox.isMobile && document.body.scrollHeight > window.innerHeight) {
527
- if (scrollbarWidth === undefined) {
528
- $scrollDiv = $('<div style="width:100px;height:100px;overflow:scroll;" />').appendTo("body");
529
-
530
- scrollbarWidth = $.fancybox.scrollbarWidth = $scrollDiv[0].offsetWidth - $scrollDiv[0].clientWidth;
570
+ $("body").addClass("fancybox-active");
531
571
 
532
- $scrollDiv.remove();
533
- }
534
-
535
- $("head").append(
536
- '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar { margin-right: ' +
537
- scrollbarWidth +
538
- "px; }</style>"
539
- );
572
+ if (
573
+ !$.fancybox.getInstance() &&
574
+ firstItemOpts.hideScrollbar !== false &&
575
+ !$.fancybox.isMobile &&
576
+ document.body.scrollHeight > window.innerHeight
577
+ ) {
578
+ $("head").append(
579
+ '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar{margin-right:' +
580
+ (window.innerWidth - document.documentElement.clientWidth) +
581
+ "px;}</style>"
582
+ );
540
583
 
541
- $("body").addClass("compensate-for-scrollbar");
542
- }
584
+ $("body").addClass("compensate-for-scrollbar");
543
585
  }
544
586
 
545
587
  // Build html markup and set references
@@ -563,7 +605,6 @@
563
605
  )
564
606
  )
565
607
  .attr("id", "fancybox-container-" + self.id)
566
- .addClass("fancybox-is-hidden")
567
608
  .addClass(firstItemOpts.baseClass)
568
609
  .data("FancyBox", self)
569
610
  .appendTo(firstItemOpts.parentEl);
@@ -591,7 +632,7 @@
591
632
  // ============================================================
592
633
 
593
634
  translate: function(obj, str) {
594
- var arr = obj.opts.i18n[obj.opts.lang];
635
+ var arr = obj.opts.i18n[obj.opts.lang] || obj.opts.i18n.en;
595
636
 
596
637
  return str.replace(/\{\{(\w+)\}\}/g, function(match, n) {
597
638
  var value = arr[n];
@@ -667,6 +708,10 @@
667
708
  obj.opts.buttons = opts.buttons;
668
709
  }
669
710
 
711
+ if ($.fancybox.isMobile && obj.opts.mobile) {
712
+ obj.opts = mergeOpts(obj.opts, obj.opts.mobile);
713
+ }
714
+
670
715
  // Step 2 - Make sure we have content type, if not - try to guess
671
716
  // ==============================================================
672
717
 
@@ -674,16 +719,17 @@
674
719
  src = obj.src || "";
675
720
 
676
721
  if (!type && src) {
677
- if ((found = src.match(/\.(mp4|mov|ogv)((\?|#).*)?$/i))) {
722
+ if ((found = src.match(/\.(mp4|mov|ogv|webm)((\?|#).*)?$/i))) {
678
723
  type = "video";
679
724
 
680
- if (!obj.opts.videoFormat) {
681
- obj.opts.videoFormat = "video/" + (found[1] === "ogv" ? "ogg" : found[1]);
725
+ if (!obj.opts.video.format) {
726
+ obj.opts.video.format = "video/" + (found[1] === "ogv" ? "ogg" : found[1]);
682
727
  }
683
728
  } else if (src.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)) {
684
729
  type = "image";
685
730
  } else if (src.match(/\.(pdf)((\?|#).*)?$/i)) {
686
731
  type = "iframe";
732
+ obj = $.extend(true, obj, {contentType: "pdf", opts: {iframe: {preload: false}}});
687
733
  } else if (src.charAt(0) === "#") {
688
734
  type = "inline";
689
735
  }
@@ -712,16 +758,28 @@
712
758
  obj.opts.toolbar = !obj.opts.smallBtn;
713
759
  }
714
760
 
715
- // Find thumbnail image
761
+ // Find thumbnail image, check if exists and if is in the viewport
762
+ obj.$thumb = obj.opts.$thumb || null;
763
+
716
764
  if (obj.opts.$trigger && obj.index === self.opts.index) {
717
- obj.opts.$thumb = obj.opts.$trigger.find("img:first");
765
+ obj.$thumb = obj.opts.$trigger.find("img:first");
766
+
767
+ if (obj.$thumb.length) {
768
+ obj.opts.$orig = obj.opts.$trigger;
769
+ }
770
+ }
771
+
772
+ if (!(obj.$thumb && obj.$thumb.length) && obj.opts.$orig) {
773
+ obj.$thumb = obj.opts.$orig.find("img:first");
718
774
  }
719
775
 
720
- if ((!obj.opts.$thumb || !obj.opts.$thumb.length) && obj.opts.$orig) {
721
- obj.opts.$thumb = obj.opts.$orig.find("img:first");
776
+ if (obj.$thumb && !obj.$thumb.length) {
777
+ obj.$thumb = null;
722
778
  }
723
779
 
724
- // "caption" is a "special" option, it can be used to customize caption per gallery item ..
780
+ obj.thumb = obj.opts.thumb || (obj.$thumb ? obj.$thumb[0].src : null);
781
+
782
+ // "caption" is a "special" option, it can be used to customize caption per gallery item
725
783
  if ($.type(obj.opts.caption) === "function") {
726
784
  obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);
727
785
  }
@@ -750,6 +808,7 @@
750
808
  // Hide all buttons and disable interactivity for modal items
751
809
  if (obj.opts.modal) {
752
810
  obj.opts = $.extend(true, obj.opts, {
811
+ trapFocus: true,
753
812
  // Remove buttons
754
813
  infobar: 0,
755
814
  toolbar: 0,
@@ -801,7 +860,7 @@
801
860
  // - browser scrolling, resizing;
802
861
  // - focusing
803
862
  // - keyboard
804
- // - detect idle
863
+ // - detecting inactivity
805
864
  // ======================================
806
865
 
807
866
  addEvents: function() {
@@ -810,6 +869,8 @@
810
869
  self.removeEvents();
811
870
 
812
871
  // Make navigation elements clickable
872
+ // ==================================
873
+
813
874
  self.$refs.container
814
875
  .on("click.fb-close", "[data-fancybox-close]", function(e) {
815
876
  e.stopPropagation();
@@ -835,54 +896,50 @@
835
896
  });
836
897
 
837
898
  // Handle page scrolling and browser resizing
899
+ // ==========================================
900
+
838
901
  $W.on("orientationchange.fb resize.fb", function(e) {
839
902
  if (e && e.originalEvent && e.originalEvent.type === "resize") {
840
- requestAFrame(function() {
841
- self.update();
903
+ if (self.requestId) {
904
+ cancelAFrame(self.requestId);
905
+ }
906
+
907
+ self.requestId = requestAFrame(function() {
908
+ self.update(e);
842
909
  });
843
910
  } else {
844
- self.$refs.stage.hide();
911
+ if (self.current && self.current.type === "iframe") {
912
+ self.$refs.stage.hide();
913
+ }
845
914
 
846
915
  setTimeout(function() {
847
916
  self.$refs.stage.show();
848
917
 
849
- self.update();
918
+ self.update(e);
850
919
  }, $.fancybox.isMobile ? 600 : 250);
851
920
  }
852
921
  });
853
922
 
854
- // Trap keyboard focus inside of the modal, so the user does not accidentally tab outside of the modal
855
- // (a.k.a. "escaping the modal")
856
- $D.on("focusin.fb", function(e) {
857
- var instance = $.fancybox ? $.fancybox.getInstance() : null;
858
-
859
- if (
860
- instance.isClosing ||
861
- !instance.current ||
862
- !instance.current.opts.trapFocus ||
863
- $(e.target).hasClass("fancybox-container") ||
864
- $(e.target).is(document)
865
- ) {
866
- return;
867
- }
868
-
869
- if (instance && $(e.target).css("position") !== "fixed" && !instance.$refs.container.has(e.target).length) {
870
- e.stopPropagation();
871
-
872
- instance.focus();
873
- }
874
- });
875
-
876
- // Enable keyboard navigation
877
923
  $D.on("keydown.fb", function(e) {
878
- var current = self.current,
924
+ var instance = $.fancybox ? $.fancybox.getInstance() : null,
925
+ current = instance.current,
879
926
  keycode = e.keyCode || e.which;
880
927
 
881
- if (!current || !current.opts.keyboard) {
928
+ // Trap keyboard focus inside of the modal
929
+ // =======================================
930
+
931
+ if (keycode == 9) {
932
+ if (current.opts.trapFocus) {
933
+ self.focus(e);
934
+ }
935
+
882
936
  return;
883
937
  }
884
938
 
885
- if (e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is("input") || $(e.target).is("textarea")) {
939
+ // Enable keyboard navigation
940
+ // ==========================
941
+
942
+ if (!current.opts.keyboard || e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is("input") || $(e.target).is("textarea")) {
886
943
  return;
887
944
  }
888
945
 
@@ -953,7 +1010,7 @@
953
1010
  var self = this;
954
1011
 
955
1012
  $W.off("orientationchange.fb resize.fb");
956
- $D.off("focusin.fb keydown.fb .fb-idle");
1013
+ $D.off("keydown.fb .fb-idle");
957
1014
 
958
1015
  this.$refs.container.off(".fb-close .fb-prev .fb-next");
959
1016
 
@@ -985,48 +1042,46 @@
985
1042
  var self = this,
986
1043
  groupLen = self.group.length,
987
1044
  firstRun,
1045
+ isMoved,
988
1046
  loop,
989
1047
  current,
990
1048
  previous,
991
- canvasWidth,
992
- currentPos,
993
- transitionProps;
1049
+ slidePos,
1050
+ stagePos,
1051
+ prop,
1052
+ diff;
994
1053
 
995
1054
  if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) {
996
1055
  return;
997
1056
  }
998
1057
 
999
- pos = parseInt(pos, 10);
1000
-
1001
1058
  // Should loop?
1059
+ pos = parseInt(pos, 10);
1002
1060
  loop = self.current ? self.current.opts.loop : self.opts.loop;
1003
1061
 
1004
1062
  if (!loop && (pos < 0 || pos >= groupLen)) {
1005
1063
  return false;
1006
1064
  }
1007
1065
 
1066
+ // Check if opening for the first time; this helps to speed things up
1008
1067
  firstRun = self.firstRun = !Object.keys(self.slides).length;
1009
1068
 
1010
- if (groupLen < 2 && !firstRun && !!self.isDragging) {
1011
- return;
1012
- }
1013
-
1069
+ // Create slides
1014
1070
  previous = self.current;
1015
1071
 
1016
1072
  self.prevIndex = self.currIndex;
1017
1073
  self.prevPos = self.currPos;
1018
1074
 
1019
- // Create slides
1020
1075
  current = self.createSlide(pos);
1021
1076
 
1022
1077
  if (groupLen > 1) {
1023
- if (loop || current.index > 0) {
1024
- self.createSlide(pos - 1);
1025
- }
1026
-
1027
1078
  if (loop || current.index < groupLen - 1) {
1028
1079
  self.createSlide(pos + 1);
1029
1080
  }
1081
+
1082
+ if (loop || current.index > 0) {
1083
+ self.createSlide(pos - 1);
1084
+ }
1030
1085
  }
1031
1086
 
1032
1087
  self.current = current;
@@ -1037,10 +1092,6 @@
1037
1092
 
1038
1093
  self.updateControls();
1039
1094
 
1040
- currentPos = $.fancybox.getTranslate(current.$slide);
1041
-
1042
- current.isMoved = (currentPos.left !== 0 || currentPos.top !== 0) && !current.$slide.hasClass("fancybox-animated");
1043
-
1044
1095
  // Validate duration length
1045
1096
  current.forcedDuration = undefined;
1046
1097
 
@@ -1052,73 +1103,105 @@
1052
1103
 
1053
1104
  duration = parseInt(duration, 10);
1054
1105
 
1106
+ // Check if user has swiped the slides or if still animating
1107
+ isMoved = self.isMoved(current);
1108
+
1109
+ // Make sure current slide is visible
1110
+ current.$slide.addClass("fancybox-slide--current");
1111
+
1055
1112
  // Fresh start - reveal container, current slide and start loading content
1056
1113
  if (firstRun) {
1057
1114
  if (current.opts.animationEffect && duration) {
1058
1115
  self.$refs.container.css("transition-duration", duration + "ms");
1059
1116
  }
1060
1117
 
1061
- self.$refs.container.removeClass("fancybox-is-hidden");
1118
+ self.$refs.container.addClass("fancybox-is-open").trigger("focus");
1062
1119
 
1063
- forceRedraw(self.$refs.container);
1064
-
1065
- self.$refs.container.addClass("fancybox-is-open");
1066
-
1067
- forceRedraw(self.$refs.container);
1068
-
1069
- // Make current slide visible
1070
- current.$slide.addClass("fancybox-slide--previous");
1071
-
1072
- // Attempt to load content into slide;
1073
- // at this point image would start loading, but inline/html content would load immediately
1120
+ // Attempt to load content into slide
1121
+ // This will later call `afterLoad` -> `revealContent`
1074
1122
  self.loadSlide(current);
1075
1123
 
1076
- current.$slide.removeClass("fancybox-slide--previous").addClass("fancybox-slide--current");
1077
-
1078
1124
  self.preload("image");
1079
1125
 
1080
1126
  return;
1081
1127
  }
1082
1128
 
1083
- // Clean up
1129
+ // Get actual slide/stage positions (before cleaning up)
1130
+ slidePos = $.fancybox.getTranslate(previous.$slide);
1131
+ stagePos = $.fancybox.getTranslate(self.$refs.stage);
1132
+
1133
+ // Clean up all slides
1084
1134
  $.each(self.slides, function(index, slide) {
1085
- $.fancybox.stop(slide.$slide);
1135
+ $.fancybox.stop(slide.$slide, true);
1086
1136
  });
1087
1137
 
1088
- // Make current that slide is visible even if content is still loading
1089
- current.$slide.removeClass("fancybox-slide--next fancybox-slide--previous").addClass("fancybox-slide--current");
1138
+ if (previous.pos !== current.pos) {
1139
+ previous.isComplete = false;
1140
+ }
1141
+
1142
+ previous.$slide.removeClass("fancybox-slide--complete fancybox-slide--current");
1090
1143
 
1091
- // If slides have been dragged, animate them to correct position
1092
- if (current.isMoved) {
1093
- canvasWidth = Math.round(current.$slide.width());
1144
+ // If slides are out of place, then animate them to correct position
1145
+ if (isMoved) {
1146
+ // Calculate horizontal swipe distance
1147
+ diff = slidePos.left - (previous.pos * slidePos.width + previous.pos * previous.opts.gutter);
1094
1148
 
1095
1149
  $.each(self.slides, function(index, slide) {
1096
- var pos = slide.pos - current.pos;
1150
+ slide.$slide.removeClass("fancybox-animated").removeClass(function(index, className) {
1151
+ return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" ");
1152
+ });
1153
+
1154
+ // Make sure that each slide is in equal distance
1155
+ // This is mostly needed for freshly added slides, because they are not yet positioned
1156
+ var leftPos = slide.pos * slidePos.width + slide.pos * slide.opts.gutter;
1157
+
1158
+ $.fancybox.setTranslate(slide.$slide, {top: 0, left: leftPos - stagePos.left + diff});
1159
+
1160
+ if (slide.pos !== current.pos) {
1161
+ slide.$slide.addClass("fancybox-slide--" + (slide.pos > current.pos ? "next" : "previous"));
1162
+ }
1097
1163
 
1164
+ // Redraw to make sure that transition will start
1165
+ forceRedraw(slide.$slide);
1166
+
1167
+ // Animate the slide
1098
1168
  $.fancybox.animate(
1099
1169
  slide.$slide,
1100
1170
  {
1101
1171
  top: 0,
1102
- left: pos * canvasWidth + pos * slide.opts.gutter
1172
+ left: (slide.pos - current.pos) * slidePos.width + (slide.pos - current.pos) * slide.opts.gutter
1103
1173
  },
1104
1174
  duration,
1105
1175
  function() {
1106
- slide.$slide.removeAttr("style").removeClass("fancybox-slide--next fancybox-slide--previous");
1176
+ slide.$slide
1177
+ .css({
1178
+ transform: "",
1179
+ opacity: ""
1180
+ })
1181
+ .removeClass("fancybox-slide--next fancybox-slide--previous");
1107
1182
 
1108
1183
  if (slide.pos === self.currPos) {
1109
- current.isMoved = false;
1110
-
1111
1184
  self.complete();
1112
1185
  }
1113
1186
  }
1114
1187
  );
1115
1188
  });
1116
- } else {
1117
- self.$refs.stage.children().removeAttr("style");
1118
- }
1189
+ } else if (duration && current.opts.transitionEffect) {
1190
+ // Set transition effect for previously active slide
1191
+ prop = "fancybox-animated fancybox-fx-" + current.opts.transitionEffect;
1119
1192
 
1120
- // Start transition that reveals current content
1121
- // or wait when it will be loaded
1193
+ previous.$slide.addClass("fancybox-slide--" + (previous.pos > current.pos ? "next" : "previous"));
1194
+
1195
+ $.fancybox.animate(
1196
+ previous.$slide,
1197
+ prop,
1198
+ duration,
1199
+ function() {
1200
+ previous.$slide.removeClass(prop).removeClass("fancybox-slide--next fancybox-slide--previous");
1201
+ },
1202
+ false
1203
+ );
1204
+ }
1122
1205
 
1123
1206
  if (current.isLoaded) {
1124
1207
  self.revealContent(current);
@@ -1127,33 +1210,6 @@
1127
1210
  }
1128
1211
 
1129
1212
  self.preload("image");
1130
-
1131
- if (previous.pos === current.pos) {
1132
- return;
1133
- }
1134
-
1135
- // Handle previous slide
1136
- // =====================
1137
-
1138
- transitionProps = "fancybox-slide--" + (previous.pos > current.pos ? "next" : "previous");
1139
-
1140
- previous.$slide.removeClass("fancybox-slide--complete fancybox-slide--current fancybox-slide--next fancybox-slide--previous");
1141
-
1142
- previous.isComplete = false;
1143
-
1144
- if (!duration || (!current.isMoved && !current.opts.transitionEffect)) {
1145
- return;
1146
- }
1147
-
1148
- if (current.isMoved) {
1149
- previous.$slide.addClass(transitionProps);
1150
- } else {
1151
- transitionProps = "fancybox-animated " + transitionProps + " fancybox-fx-" + current.opts.transitionEffect;
1152
-
1153
- $.fancybox.animate(previous.$slide, transitionProps, duration, function() {
1154
- previous.$slide.removeClass(transitionProps).removeAttr("style");
1155
- });
1156
- }
1157
1213
  },
1158
1214
 
1159
1215
  // Create new "slide" element
@@ -1201,14 +1257,14 @@
1201
1257
  scaleX,
1202
1258
  scaleY;
1203
1259
 
1204
- if (self.isAnimating || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) {
1260
+ if (self.isAnimating || self.isMoved() || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) {
1205
1261
  return;
1206
1262
  }
1207
1263
 
1208
- $.fancybox.stop($content);
1209
-
1210
1264
  self.isAnimating = true;
1211
1265
 
1266
+ $.fancybox.stop($content);
1267
+
1212
1268
  x = x === undefined ? canvasWidth * 0.5 : x;
1213
1269
  y = y === undefined ? canvasHeight * 0.5 : y;
1214
1270
 
@@ -1280,14 +1336,14 @@
1280
1336
  $content = current.$content,
1281
1337
  end;
1282
1338
 
1283
- if (self.isAnimating || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) {
1339
+ if (self.isAnimating || self.isMoved() || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) {
1284
1340
  return;
1285
1341
  }
1286
1342
 
1287
- $.fancybox.stop($content);
1288
-
1289
1343
  self.isAnimating = true;
1290
1344
 
1345
+ $.fancybox.stop($content);
1346
+
1291
1347
  end = self.getFitPos(current);
1292
1348
 
1293
1349
  self.updateCursor(end.width, end.height);
@@ -1313,12 +1369,12 @@
1313
1369
  getFitPos: function(slide) {
1314
1370
  var self = this,
1315
1371
  $content = slide.$content,
1372
+ $slide = slide.$slide,
1316
1373
  width = slide.width || slide.opts.width,
1317
1374
  height = slide.height || slide.opts.height,
1318
1375
  maxWidth,
1319
1376
  maxHeight,
1320
1377
  minRatio,
1321
- margin,
1322
1378
  aspectRatio,
1323
1379
  rez = {};
1324
1380
 
@@ -1326,16 +1382,20 @@
1326
1382
  return false;
1327
1383
  }
1328
1384
 
1329
- margin = {
1330
- top: parseInt(slide.$slide.css("paddingTop"), 10),
1331
- right: parseInt(slide.$slide.css("paddingRight"), 10),
1332
- bottom: parseInt(slide.$slide.css("paddingBottom"), 10),
1333
- left: parseInt(slide.$slide.css("paddingLeft"), 10)
1334
- };
1385
+ maxWidth = $.fancybox.getTranslate(self.$refs.stage).width;
1386
+ maxHeight = $.fancybox.getTranslate(self.$refs.stage).height;
1387
+
1388
+ maxWidth -=
1389
+ parseFloat($slide.css("paddingLeft")) +
1390
+ parseFloat($slide.css("paddingRight")) +
1391
+ parseFloat($content.css("marginLeft")) +
1392
+ parseFloat($content.css("marginRight"));
1335
1393
 
1336
- // We can not use $slide width here, because it can have different diemensions while in transiton
1337
- maxWidth = parseInt(self.$refs.stage.width(), 10) - (margin.left + margin.right);
1338
- maxHeight = parseInt(self.$refs.stage.height(), 10) - (margin.top + margin.bottom);
1394
+ maxHeight -=
1395
+ parseFloat($slide.css("paddingTop")) +
1396
+ parseFloat($slide.css("paddingBottom")) +
1397
+ parseFloat($content.css("marginTop")) +
1398
+ parseFloat($content.css("marginBottom"));
1339
1399
 
1340
1400
  if (!width || !height) {
1341
1401
  width = maxWidth;
@@ -1344,13 +1404,21 @@
1344
1404
 
1345
1405
  minRatio = Math.min(1, maxWidth / width, maxHeight / height);
1346
1406
 
1347
- // Use floor rounding to make sure it really fits
1348
- width = Math.floor(minRatio * width);
1349
- height = Math.floor(minRatio * height);
1407
+ width = minRatio * width;
1408
+ height = minRatio * height;
1409
+
1410
+ // Adjust width/height to precisely fit into container
1411
+ if (width > maxWidth - 0.5) {
1412
+ width = maxWidth;
1413
+ }
1414
+
1415
+ if (height > maxHeight - 0.5) {
1416
+ height = maxHeight;
1417
+ }
1350
1418
 
1351
1419
  if (slide.type === "image") {
1352
- rez.top = Math.floor((maxHeight - height) * 0.5) + margin.top;
1353
- rez.left = Math.floor((maxWidth - width) * 0.5) + margin.left;
1420
+ rez.top = Math.floor((maxHeight - height) * 0.5) + parseFloat($slide.css("paddingTop"));
1421
+ rez.left = Math.floor((maxWidth - width) * 0.5) + parseFloat($slide.css("paddingLeft"));
1354
1422
  } else if (slide.contentType === "video") {
1355
1423
  // Force aspect ratio for the video
1356
1424
  // "I say the whole world must learn of our peaceful ways… by force!"
@@ -1372,23 +1440,28 @@
1372
1440
  // Update content size and position for all slides
1373
1441
  // ==============================================
1374
1442
 
1375
- update: function() {
1443
+ update: function(e) {
1376
1444
  var self = this;
1377
1445
 
1378
1446
  $.each(self.slides, function(key, slide) {
1379
- self.updateSlide(slide);
1447
+ self.updateSlide(slide, e);
1380
1448
  });
1381
1449
  },
1382
1450
 
1383
1451
  // Update slide content position and size
1384
1452
  // ======================================
1385
1453
 
1386
- updateSlide: function(slide, duration) {
1454
+ updateSlide: function(slide, e) {
1387
1455
  var self = this,
1388
1456
  $content = slide && slide.$content,
1389
1457
  width = slide.width || slide.opts.width,
1390
- height = slide.height || slide.opts.height;
1458
+ height = slide.height || slide.opts.height,
1459
+ $slide = slide.$slide;
1391
1460
 
1461
+ // First, prevent caption overlap, if needed
1462
+ self.adjustCaption(slide);
1463
+
1464
+ // Then resize content to fit inside the slide
1392
1465
  if ($content && (width || height || slide.contentType === "video") && !slide.hasError) {
1393
1466
  $.fancybox.stop($content);
1394
1467
 
@@ -1401,37 +1474,86 @@
1401
1474
  }
1402
1475
  }
1403
1476
 
1404
- slide.$slide.trigger("refresh");
1477
+ // Then some adjustments
1478
+ self.adjustLayout(slide);
1405
1479
 
1406
- self.$refs.toolbar.toggleClass("compensate-for-scrollbar", slide.$slide.get(0).scrollHeight > slide.$slide.get(0).clientHeight);
1480
+ if ($slide.length) {
1481
+ $slide.trigger("refresh");
1407
1482
 
1408
- self.trigger("onUpdate", slide);
1483
+ if (slide.pos === self.currPos) {
1484
+ self.$refs.toolbar
1485
+ .add(self.$refs.navigation.find(".fancybox-button--arrow_right"))
1486
+ .toggleClass("compensate-for-scrollbar", $slide.get(0).scrollHeight > $slide.get(0).clientHeight);
1487
+ }
1488
+ }
1489
+
1490
+ self.trigger("onUpdate", slide, e);
1409
1491
  },
1410
1492
 
1411
1493
  // Horizontally center slide
1412
1494
  // =========================
1413
1495
 
1414
- centerSlide: function(slide, duration) {
1496
+ centerSlide: function(duration) {
1415
1497
  var self = this,
1416
- canvasWidth,
1417
- pos;
1498
+ current = self.current,
1499
+ $slide = current.$slide;
1500
+
1501
+ if (self.isClosing || !current) {
1502
+ return;
1503
+ }
1418
1504
 
1419
- if (self.current) {
1420
- canvasWidth = Math.round(slide.$slide.width());
1421
- pos = slide.pos - self.current.pos;
1505
+ $slide.siblings().css({
1506
+ transform: "",
1507
+ opacity: ""
1508
+ });
1422
1509
 
1423
- $.fancybox.animate(
1424
- slide.$slide,
1425
- {
1426
- top: 0,
1427
- left: pos * canvasWidth + pos * slide.opts.gutter,
1428
- opacity: 1
1429
- },
1430
- duration === undefined ? 0 : duration,
1431
- null,
1432
- false
1433
- );
1510
+ $slide
1511
+ .parent()
1512
+ .children()
1513
+ .removeClass("fancybox-slide--previous fancybox-slide--next");
1514
+
1515
+ $.fancybox.animate(
1516
+ $slide,
1517
+ {
1518
+ top: 0,
1519
+ left: 0,
1520
+ opacity: 1
1521
+ },
1522
+ duration === undefined ? 0 : duration,
1523
+ function() {
1524
+ // Clean up
1525
+ $slide.css({
1526
+ transform: "",
1527
+ opacity: ""
1528
+ });
1529
+
1530
+ if (!current.isComplete) {
1531
+ self.complete();
1532
+ }
1533
+ },
1534
+ false
1535
+ );
1536
+ },
1537
+
1538
+ // Check if current slide is moved (swiped)
1539
+ // ========================================
1540
+
1541
+ isMoved: function(slide) {
1542
+ var current = slide || this.current,
1543
+ slidePos,
1544
+ stagePos;
1545
+
1546
+ if (!current) {
1547
+ return false;
1434
1548
  }
1549
+
1550
+ stagePos = $.fancybox.getTranslate(this.$refs.stage);
1551
+ slidePos = $.fancybox.getTranslate(current.$slide);
1552
+
1553
+ return (
1554
+ !current.$slide.hasClass("fancybox-animated") &&
1555
+ (Math.abs(slidePos.top - stagePos.top) > 0.5 || Math.abs(slidePos.left - stagePos.left) > 0.5)
1556
+ );
1435
1557
  },
1436
1558
 
1437
1559
  // Update cursor style depending if content can be zoomed
@@ -1440,38 +1562,33 @@
1440
1562
  updateCursor: function(nextWidth, nextHeight) {
1441
1563
  var self = this,
1442
1564
  current = self.current,
1443
- $container = self.$refs.container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-drag fancybox-can-zoomOut"),
1565
+ $container = self.$refs.container,
1566
+ canPan,
1444
1567
  isZoomable;
1445
1568
 
1446
- if (!current || self.isClosing) {
1569
+ if (!current || self.isClosing || !self.Guestures) {
1447
1570
  return;
1448
1571
  }
1449
1572
 
1450
- isZoomable = self.isZoomable();
1573
+ $container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan");
1574
+
1575
+ canPan = self.canPan(nextWidth, nextHeight);
1576
+
1577
+ isZoomable = canPan ? true : self.isZoomable();
1451
1578
 
1452
1579
  $container.toggleClass("fancybox-is-zoomable", isZoomable);
1453
1580
 
1454
1581
  $("[data-fancybox-zoom]").prop("disabled", !isZoomable);
1455
1582
 
1456
- // Set cursor to zoom in/out if click event is 'zoom'
1457
- if (
1583
+ if (canPan) {
1584
+ $container.addClass("fancybox-can-pan");
1585
+ } else if (
1458
1586
  isZoomable &&
1459
- (current.opts.clickContent === "zoom" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) === "zoom"))
1587
+ (current.opts.clickContent === "zoom" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) == "zoom"))
1460
1588
  ) {
1461
- if (self.isScaledDown(nextWidth, nextHeight)) {
1462
- // If image is scaled down, then, obviously, it can be zoomed to full size
1463
- $container.addClass("fancybox-can-zoomIn");
1464
- } else {
1465
- if (current.opts.touch) {
1466
- // If image size ir largen than available available and touch module is not disable,
1467
- // then user can do panning
1468
- $container.addClass("fancybox-can-drag");
1469
- } else {
1470
- $container.addClass("fancybox-can-zoomOut");
1471
- }
1472
- }
1473
- } else if (current.opts.touch && current.contentType !== "video") {
1474
- $container.addClass("fancybox-can-drag");
1589
+ $container.addClass("fancybox-can-zoomIn");
1590
+ } else if (current.opts.touch && (current.opts.touch.vertical || self.group.length > 1) && current.contentType !== "video") {
1591
+ $container.addClass("fancybox-can-swipe");
1475
1592
  }
1476
1593
  },
1477
1594
 
@@ -1493,7 +1610,7 @@
1493
1610
 
1494
1611
  fitPos = self.getFitPos(current);
1495
1612
 
1496
- if (current.width > fitPos.width || current.height > fitPos.height) {
1613
+ if (fitPos && (current.width > fitPos.width || current.height > fitPos.height)) {
1497
1614
  return true;
1498
1615
  }
1499
1616
  }
@@ -1523,15 +1640,24 @@
1523
1640
  // Check if image dimensions exceed parent element
1524
1641
  // ===============================================
1525
1642
 
1526
- canPan: function() {
1643
+ canPan: function(nextWidth, nextHeight) {
1527
1644
  var self = this,
1528
- rez = false,
1529
1645
  current = self.current,
1530
- $content;
1646
+ pos = null,
1647
+ rez = false;
1531
1648
 
1532
- if (current.type === "image" && ($content = current.$content) && !current.hasError) {
1649
+ if (current.type === "image" && (current.isComplete || (nextWidth && nextHeight)) && !current.hasError) {
1533
1650
  rez = self.getFitPos(current);
1534
- rez = Math.abs($content.width() - rez.width) > 1 || Math.abs($content.height() - rez.height) > 1;
1651
+
1652
+ if (nextWidth !== undefined && nextHeight !== undefined) {
1653
+ pos = {width: nextWidth, height: nextHeight};
1654
+ } else if (current.isComplete) {
1655
+ pos = $.fancybox.getTranslate(current.$content);
1656
+ }
1657
+
1658
+ if (pos && rez) {
1659
+ rez = Math.abs(pos.width - rez.width) > 1.5 || Math.abs(pos.height - rez.height) > 1.5;
1660
+ }
1535
1661
  }
1536
1662
 
1537
1663
  return rez;
@@ -1552,7 +1678,11 @@
1552
1678
 
1553
1679
  slide.isLoading = true;
1554
1680
 
1555
- self.trigger("beforeLoad", slide);
1681
+ if (self.trigger("beforeLoad", slide) === false) {
1682
+ slide.isLoading = false;
1683
+
1684
+ return false;
1685
+ }
1556
1686
 
1557
1687
  type = slide.type;
1558
1688
  $slide = slide.$slide;
@@ -1582,14 +1712,10 @@
1582
1712
  case "video":
1583
1713
  self.setContent(
1584
1714
  slide,
1585
- '<video class="fancybox-video" controls controlsList="nodownload">' +
1586
- '<source src="' +
1587
- slide.src +
1588
- '" type="' +
1589
- slide.opts.videoFormat +
1590
- '">' +
1591
- "Your browser doesn't support HTML5 video" +
1592
- "</video"
1715
+ slide.opts.video.tpl
1716
+ .replace(/\{\{src\}\}/gi, slide.src)
1717
+ .replace("{{format}}", slide.opts.videoFormat || slide.opts.video.format || "")
1718
+ .replace("{{poster}}", slide.thumb || "")
1593
1719
  );
1594
1720
 
1595
1721
  break;
@@ -1642,21 +1768,61 @@
1642
1768
 
1643
1769
  setImage: function(slide) {
1644
1770
  var self = this,
1645
- srcset = slide.opts.srcset || slide.opts.image.srcset,
1646
- thumbSrc,
1647
- found,
1648
- temp,
1649
- pxRatio,
1650
- windowWidth;
1771
+ ghost;
1651
1772
 
1652
1773
  // Check if need to show loading icon
1653
- slide.timouts = setTimeout(function() {
1774
+ setTimeout(function() {
1654
1775
  var $img = slide.$image;
1655
1776
 
1656
- if (slide.isLoading && (!$img || !$img[0].complete) && !slide.hasError) {
1777
+ if (!self.isClosing && slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) {
1657
1778
  self.showLoading(slide);
1658
1779
  }
1659
- }, 350);
1780
+ }, 50);
1781
+
1782
+ //Check if image has srcset
1783
+ self.checkSrcset(slide);
1784
+
1785
+ // This will be wrapper containing both ghost and actual image
1786
+ slide.$content = $('<div class="fancybox-content"></div>')
1787
+ .addClass("fancybox-is-hidden")
1788
+ .appendTo(slide.$slide.addClass("fancybox-slide--image"));
1789
+
1790
+ // If we have a thumbnail, we can display it while actual image is loading
1791
+ // Users will not stare at black screen and actual image will appear gradually
1792
+ if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && slide.thumb) {
1793
+ slide.width = slide.opts.width;
1794
+ slide.height = slide.opts.height;
1795
+
1796
+ ghost = document.createElement("img");
1797
+
1798
+ ghost.onerror = function() {
1799
+ $(this).remove();
1800
+
1801
+ slide.$ghost = null;
1802
+ };
1803
+
1804
+ ghost.onload = function() {
1805
+ self.afterLoad(slide);
1806
+ };
1807
+
1808
+ slide.$ghost = $(ghost)
1809
+ .addClass("fancybox-image")
1810
+ .appendTo(slide.$content)
1811
+ .attr("src", slide.thumb);
1812
+ }
1813
+
1814
+ // Start loading actual image
1815
+ self.setBigImage(slide);
1816
+ },
1817
+
1818
+ // Check if image has srcset and get the source
1819
+ // ============================================
1820
+ checkSrcset: function(slide) {
1821
+ var srcset = slide.opts.srcset || slide.opts.image.srcset,
1822
+ found,
1823
+ temp,
1824
+ pxRatio,
1825
+ windowWidth;
1660
1826
 
1661
1827
  // If we have "srcset", then we need to find first matching "src" value.
1662
1828
  // This is necessary, because when you set an src attribute, the browser will preload the image
@@ -1668,8 +1834,7 @@
1668
1834
  temp = srcset.split(",").map(function(el) {
1669
1835
  var ret = {};
1670
1836
 
1671
- el
1672
- .trim()
1837
+ el.trim()
1673
1838
  .split(/\s+/)
1674
1839
  .forEach(function(el, i) {
1675
1840
  var value = parseInt(el.substring(0, el.length - 1), 10);
@@ -1712,43 +1877,13 @@
1712
1877
 
1713
1878
  // If we have default width/height values, we can calculate height for matching source
1714
1879
  if (slide.width && slide.height && found.postfix == "w") {
1715
- slide.height = slide.width / slide.height * found.value;
1880
+ slide.height = (slide.width / slide.height) * found.value;
1716
1881
  slide.width = found.value;
1717
1882
  }
1718
1883
 
1719
1884
  slide.opts.srcset = srcset;
1720
1885
  }
1721
1886
  }
1722
-
1723
- // This will be wrapper containing both ghost and actual image
1724
- slide.$content = $('<div class="fancybox-content"></div>')
1725
- .addClass("fancybox-is-hidden")
1726
- .appendTo(slide.$slide.addClass("fancybox-slide--image"));
1727
-
1728
- // If we have a thumbnail, we can display it while actual image is loading
1729
- // Users will not stare at black screen and actual image will appear gradually
1730
- thumbSrc = slide.opts.thumb || (slide.opts.$thumb && slide.opts.$thumb.length ? slide.opts.$thumb.attr("src") : false);
1731
-
1732
- if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && thumbSrc) {
1733
- slide.width = slide.opts.width;
1734
- slide.height = slide.opts.height;
1735
-
1736
- slide.$ghost = $("<img />")
1737
- .one("error", function() {
1738
- $(this).remove();
1739
-
1740
- slide.$ghost = null;
1741
- })
1742
- .one("load", function() {
1743
- self.afterLoad(slide);
1744
- })
1745
- .addClass("fancybox-image")
1746
- .appendTo(slide.$content)
1747
- .attr("src", thumbSrc);
1748
- }
1749
-
1750
- // Start loading actual image
1751
- self.setBigImage(slide);
1752
1887
  },
1753
1888
 
1754
1889
  // Create full-size image
@@ -1756,7 +1891,8 @@
1756
1891
 
1757
1892
  setBigImage: function(slide) {
1758
1893
  var self = this,
1759
- $img = $("<img />");
1894
+ img = document.createElement("img"),
1895
+ $img = $(img);
1760
1896
 
1761
1897
  slide.$image = $img
1762
1898
  .one("error", function() {
@@ -1771,12 +1907,6 @@
1771
1907
  self.afterLoad(slide);
1772
1908
  }
1773
1909
 
1774
- // Clear timeout that checks if loading icon needs to be displayed
1775
- if (slide.timouts) {
1776
- clearTimeout(slide.timouts);
1777
- slide.timouts = null;
1778
- }
1779
-
1780
1910
  if (self.isClosing) {
1781
1911
  return;
1782
1912
  }
@@ -1786,7 +1916,7 @@
1786
1916
 
1787
1917
  if (!sizes || sizes === "auto") {
1788
1918
  sizes =
1789
- (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? "100" : Math.round(slide.width / slide.height * 100)) +
1919
+ (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? "100" : Math.round((slide.width / slide.height) * 100)) +
1790
1920
  "vw";
1791
1921
  }
1792
1922
 
@@ -1808,9 +1938,9 @@
1808
1938
  .attr("src", slide.src)
1809
1939
  .appendTo(slide.$content);
1810
1940
 
1811
- if (($img[0].complete || $img[0].readyState == "complete") && $img[0].naturalWidth && $img[0].naturalHeight) {
1941
+ if ((img.complete || img.readyState == "complete") && $img.naturalWidth && $img.naturalHeight) {
1812
1942
  $img.trigger("load");
1813
- } else if ($img[0].error) {
1943
+ } else if (img.error) {
1814
1944
  $img.trigger("error");
1815
1945
  }
1816
1946
  },
@@ -1828,11 +1958,11 @@
1828
1958
 
1829
1959
  if (maxWidth > 0) {
1830
1960
  slide.width = maxWidth;
1831
- slide.height = Math.floor(maxWidth * imgHeight / imgWidth);
1961
+ slide.height = Math.floor((maxWidth * imgHeight) / imgWidth);
1832
1962
  }
1833
1963
 
1834
1964
  if (maxHeight > 0) {
1835
- slide.width = Math.floor(maxHeight * imgWidth / imgHeight);
1965
+ slide.width = Math.floor((maxHeight * imgWidth) / imgHeight);
1836
1966
  slide.height = maxHeight;
1837
1967
  }
1838
1968
  },
@@ -1846,6 +1976,11 @@
1846
1976
  $slide = slide.$slide,
1847
1977
  $iframe;
1848
1978
 
1979
+ // Fix responsive iframes on iOS (along with `position:absolute;` for iframe element)
1980
+ if ($.fancybox.isMobile) {
1981
+ opts.css.overflow = "scroll";
1982
+ }
1983
+
1849
1984
  slide.$content = $('<div class="fancybox-content' + (opts.preload ? " fancybox-is-hidden" : "") + '"></div>')
1850
1985
  .css(opts.css)
1851
1986
  .appendTo($slide);
@@ -1891,32 +2026,34 @@
1891
2026
 
1892
2027
  // Calculate contnet dimensions if it is accessible
1893
2028
  if ($body && $body.length && $body.children().length) {
2029
+ // Avoid scrolling to top (if multiple instances)
2030
+ $slide.css("overflow", "visible");
2031
+
1894
2032
  $content.css({
1895
- width: "",
1896
- height: ""
2033
+ width: "100%",
2034
+ "max-width": "100%",
2035
+ height: "9999px"
1897
2036
  });
1898
2037
 
1899
2038
  if (frameWidth === undefined) {
1900
2039
  frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true)));
1901
2040
  }
1902
2041
 
1903
- if (frameWidth) {
1904
- $content.width(frameWidth);
1905
- }
2042
+ $content.css("width", frameWidth ? frameWidth : "").css("max-width", "");
1906
2043
 
1907
2044
  if (frameHeight === undefined) {
1908
2045
  frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true)));
1909
2046
  }
1910
2047
 
1911
- if (frameHeight) {
1912
- $content.height(frameHeight);
1913
- }
2048
+ $content.css("height", frameHeight ? frameHeight : "");
2049
+
2050
+ $slide.css("overflow", "auto");
1914
2051
  }
1915
2052
 
1916
2053
  $content.removeClass("fancybox-is-hidden");
1917
2054
  });
1918
2055
  } else {
1919
- this.afterLoad(slide);
2056
+ self.afterLoad(slide);
1920
2057
  }
1921
2058
 
1922
2059
  $iframe.attr("src", slide.src);
@@ -1937,6 +2074,7 @@
1937
2074
  .empty();
1938
2075
 
1939
2076
  slide.isLoaded = false;
2077
+ slide.isRevealed = false;
1940
2078
  });
1941
2079
  },
1942
2080
 
@@ -1962,10 +2100,9 @@
1962
2100
  // The placeholder is created so we will know where to put it back.
1963
2101
  if (isQuery(content) && content.parent().length) {
1964
2102
  // Make sure content is not already moved to fancyBox
1965
- content
1966
- .parent()
1967
- .parent(".fancybox-slide--inline")
1968
- .trigger("onReset");
2103
+ if (content.hasClass("fancybox-content") || content.parent().hasClass("fancybox-content")) {
2104
+ content.parents(".fancybox-slide").trigger("onReset");
2105
+ }
1969
2106
 
1970
2107
  // Create temporary element marking original place of the content
1971
2108
  slide.$placeholder = $("<div>")
@@ -1980,11 +2117,6 @@
1980
2117
  content = $("<div>")
1981
2118
  .append($.trim(content))
1982
2119
  .contents();
1983
-
1984
- // If we have text node, then add wrapping element to make vertical alignment work
1985
- if (content[0].nodeType === 3) {
1986
- content = $("<div>").html(content);
1987
- }
1988
2120
  }
1989
2121
 
1990
2122
  // If "filter" option is provided, then filter content
@@ -2003,7 +2135,7 @@
2003
2135
 
2004
2136
  // Put content back
2005
2137
  if (slide.$placeholder) {
2006
- slide.$placeholder.after(content.hide()).remove();
2138
+ slide.$placeholder.after(content.removeClass("fancybox-content").hide()).remove();
2007
2139
 
2008
2140
  slide.$placeholder = null;
2009
2141
  }
@@ -2020,6 +2152,7 @@
2020
2152
  $(this).empty();
2021
2153
 
2022
2154
  slide.isLoaded = false;
2155
+ slide.isRevealed = false;
2023
2156
  }
2024
2157
  });
2025
2158
 
@@ -2038,13 +2171,25 @@
2038
2171
 
2039
2172
  slide.$content = slide.$slide
2040
2173
  .children()
2041
- .filter("div,form,main,video,audio")
2042
- .first()
2043
- .addClass("fancybox-content");
2174
+ .filter("div,form,main,video,audio,article,.fancybox-content")
2175
+ .first();
2176
+
2177
+ slide.$content.siblings().hide();
2178
+
2179
+ // Re-check if there is a valid content
2180
+ // (in some cases, ajax response can contain various elements or plain text)
2181
+ if (!slide.$content.length) {
2182
+ slide.$content = slide.$slide
2183
+ .wrapInner("<div></div>")
2184
+ .children()
2185
+ .first();
2186
+ }
2187
+
2188
+ slide.$content.addClass("fancybox-content");
2044
2189
 
2045
2190
  slide.$slide.addClass("fancybox-slide--" + slide.contentType);
2046
2191
 
2047
- this.afterLoad(slide);
2192
+ self.afterLoad(slide);
2048
2193
  },
2049
2194
 
2050
2195
  // Display error message
@@ -2076,7 +2221,10 @@
2076
2221
  slide = slide || self.current;
2077
2222
 
2078
2223
  if (slide && !slide.$spinner) {
2079
- slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)).appendTo(slide.$slide);
2224
+ slide.$spinner = $(self.translate(self, self.opts.spinnerTpl))
2225
+ .appendTo(slide.$slide)
2226
+ .hide()
2227
+ .fadeIn("fast");
2080
2228
  }
2081
2229
  },
2082
2230
 
@@ -2089,7 +2237,7 @@
2089
2237
  slide = slide || self.current;
2090
2238
 
2091
2239
  if (slide && slide.$spinner) {
2092
- slide.$spinner.remove();
2240
+ slide.$spinner.stop().remove();
2093
2241
 
2094
2242
  delete slide.$spinner;
2095
2243
  }
@@ -2112,16 +2260,13 @@
2112
2260
 
2113
2261
  self.hideLoading(slide);
2114
2262
 
2115
- if (slide.pos === self.currPos) {
2116
- self.updateCursor();
2117
- }
2118
-
2263
+ // Add small close button
2119
2264
  if (slide.opts.smallBtn && (!slide.$smallBtn || !slide.$smallBtn.length)) {
2120
- slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).prependTo(slide.$content);
2265
+ slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).appendTo(slide.$content);
2121
2266
  }
2122
2267
 
2268
+ // Disable right click
2123
2269
  if (slide.opts.protect && slide.$content && !slide.hasError) {
2124
- // Disable right click
2125
2270
  slide.$content.on("contextmenu.fb", function(e) {
2126
2271
  if (e.button == 2) {
2127
2272
  e.preventDefault();
@@ -2137,9 +2282,86 @@
2137
2282
  }
2138
2283
  }
2139
2284
 
2285
+ self.adjustCaption(slide);
2286
+
2287
+ self.adjustLayout(slide);
2288
+
2289
+ if (slide.pos === self.currPos) {
2290
+ self.updateCursor();
2291
+ }
2292
+
2140
2293
  self.revealContent(slide);
2141
2294
  },
2142
2295
 
2296
+ // Prevent caption overlap,
2297
+ // fix css inconsistency across browsers
2298
+ // =====================================
2299
+
2300
+ adjustCaption: function(slide) {
2301
+ var self = this,
2302
+ current = slide || self.current,
2303
+ caption = current.opts.caption,
2304
+ $caption = self.$refs.caption,
2305
+ captionH = false;
2306
+
2307
+ if (current.opts.preventCaptionOverlap && caption && caption.length) {
2308
+ if (current.pos !== self.currPos) {
2309
+ $caption = $caption
2310
+ .clone()
2311
+ .empty()
2312
+ .appendTo($caption.parent());
2313
+
2314
+ $caption.html(caption);
2315
+
2316
+ captionH = $caption.outerHeight(true);
2317
+
2318
+ $caption.empty().remove();
2319
+ } else if (self.$caption) {
2320
+ captionH = self.$caption.outerHeight(true);
2321
+ }
2322
+
2323
+ current.$slide.css("padding-bottom", captionH || "");
2324
+ }
2325
+ },
2326
+
2327
+ // Simple hack to fix inconsistency across browsers, described here (affects Edge, too):
2328
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=748518
2329
+ // ====================================================================================
2330
+
2331
+ adjustLayout: function(slide) {
2332
+ var self = this,
2333
+ current = slide || self.current,
2334
+ scrollHeight,
2335
+ marginBottom,
2336
+ inlinePadding,
2337
+ actualPadding;
2338
+
2339
+ if (current.isLoaded && current.opts.disableLayoutFix !== true) {
2340
+ current.$content.css("margin-bottom", "");
2341
+
2342
+ // If we would always set margin-bottom for the content,
2343
+ // then it would potentially break vertical align
2344
+ if (current.$content.outerHeight() > current.$slide.height() + 0.5) {
2345
+ inlinePadding = current.$slide[0].style["padding-bottom"];
2346
+ actualPadding = current.$slide.css("padding-bottom");
2347
+
2348
+ if (parseFloat(actualPadding) > 0) {
2349
+ scrollHeight = current.$slide[0].scrollHeight;
2350
+
2351
+ current.$slide.css("padding-bottom", 0);
2352
+
2353
+ if (Math.abs(scrollHeight - current.$slide[0].scrollHeight) < 1) {
2354
+ marginBottom = actualPadding;
2355
+ }
2356
+
2357
+ current.$slide.css("padding-bottom", inlinePadding);
2358
+ }
2359
+ }
2360
+
2361
+ current.$content.css("margin-bottom", marginBottom);
2362
+ }
2363
+ },
2364
+
2143
2365
  // Make content visible
2144
2366
  // This method is called right after content has been loaded or
2145
2367
  // user navigates gallery and transition should start
@@ -2150,26 +2372,21 @@
2150
2372
  $slide = slide.$slide,
2151
2373
  end = false,
2152
2374
  start = false,
2375
+ isMoved = self.isMoved(slide),
2376
+ isRevealed = slide.isRevealed,
2153
2377
  effect,
2154
2378
  effectClassName,
2155
2379
  duration,
2156
2380
  opacity;
2157
2381
 
2382
+ slide.isRevealed = true;
2383
+
2158
2384
  effect = slide.opts[self.firstRun ? "animationEffect" : "transitionEffect"];
2159
2385
  duration = slide.opts[self.firstRun ? "animationDuration" : "transitionDuration"];
2160
2386
 
2161
2387
  duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10);
2162
2388
 
2163
- // Do not animate if revealing the same slide
2164
- if (slide.pos === self.currPos) {
2165
- if (slide.isComplete) {
2166
- effect = false;
2167
- } else {
2168
- self.isAnimating = true;
2169
- }
2170
- }
2171
-
2172
- if (slide.isMoved || slide.pos !== self.currPos || !duration) {
2389
+ if (isMoved || slide.pos !== self.currPos || !duration) {
2173
2390
  effect = false;
2174
2391
  }
2175
2392
 
@@ -2185,6 +2402,8 @@
2185
2402
  // Zoom animation
2186
2403
  // ==============
2187
2404
  if (effect === "zoom") {
2405
+ self.isAnimating = true;
2406
+
2188
2407
  end.scaleX = end.width / start.width;
2189
2408
  end.scaleY = end.height / start.height;
2190
2409
 
@@ -2217,14 +2436,15 @@
2217
2436
 
2218
2437
  self.updateSlide(slide);
2219
2438
 
2220
- // Simply show content
2221
- // ===================
2222
-
2439
+ // Simply show content if no effect
2440
+ // ================================
2223
2441
  if (!effect) {
2224
- forceRedraw($slide);
2225
-
2226
2442
  slide.$content.removeClass("fancybox-is-hidden");
2227
2443
 
2444
+ if (!isRevealed && isMoved && slide.type === "image" && !slide.hasError) {
2445
+ slide.$content.hide().fadeIn("fast");
2446
+ }
2447
+
2228
2448
  if (slide.pos === self.currPos) {
2229
2449
  self.complete();
2230
2450
  }
@@ -2232,26 +2452,33 @@
2232
2452
  return;
2233
2453
  }
2234
2454
 
2455
+ // Prepare for CSS transiton
2456
+ // =========================
2235
2457
  $.fancybox.stop($slide);
2236
2458
 
2237
- effectClassName = "fancybox-animated fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-fx-" + effect;
2459
+ //effectClassName = "fancybox-animated fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-fx-" + effect;
2460
+ effectClassName = "fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-animated fancybox-fx-" + effect;
2238
2461
 
2239
- $slide
2240
- .removeAttr("style")
2241
- .removeClass("fancybox-slide--current fancybox-slide--next fancybox-slide--previous")
2242
- .addClass(effectClassName);
2462
+ $slide.addClass(effectClassName).removeClass("fancybox-slide--current"); //.addClass(effectClassName);
2243
2463
 
2244
2464
  slide.$content.removeClass("fancybox-is-hidden");
2245
2465
 
2246
- // Force reflow for CSS3 transitions
2466
+ // Force reflow
2247
2467
  forceRedraw($slide);
2248
2468
 
2469
+ if (slide.type !== "image") {
2470
+ slide.$content.hide().show(0);
2471
+ }
2472
+
2249
2473
  $.fancybox.animate(
2250
2474
  $slide,
2251
2475
  "fancybox-slide--current",
2252
2476
  duration,
2253
- function(e) {
2254
- $slide.removeClass(effectClassName).removeAttr("style");
2477
+ function() {
2478
+ $slide.removeClass(effectClassName).css({
2479
+ transform: "",
2480
+ opacity: ""
2481
+ });
2255
2482
 
2256
2483
  if (slide.pos === self.currPos) {
2257
2484
  self.complete();
@@ -2265,57 +2492,35 @@
2265
2492
  //================================================
2266
2493
 
2267
2494
  getThumbPos: function(slide) {
2268
- var self = this,
2269
- rez = false,
2270
- $thumb = slide.opts.$thumb,
2271
- thumbPos = $thumb && $thumb.length && $thumb[0].ownerDocument === document ? $thumb.offset() : 0,
2272
- slidePos;
2273
-
2274
- // Check if element is inside the viewport by at least 1 pixel
2275
- var isElementVisible = function($el) {
2276
- var element = $el[0],
2277
- elementRect = element.getBoundingClientRect(),
2278
- parentRects = [],
2279
- visibleInAllParents;
2280
-
2281
- while (element.parentElement !== null) {
2282
- if ($(element.parentElement).css("overflow") === "hidden" || $(element.parentElement).css("overflow") === "auto") {
2283
- parentRects.push(element.parentElement.getBoundingClientRect());
2284
- }
2285
-
2286
- element = element.parentElement;
2287
- }
2495
+ var rez = false,
2496
+ $thumb = slide.$thumb,
2497
+ thumbPos,
2498
+ btw,
2499
+ brw,
2500
+ bbw,
2501
+ blw;
2502
+
2503
+ if (!$thumb || !inViewport($thumb[0])) {
2504
+ return false;
2505
+ }
2288
2506
 
2289
- visibleInAllParents = parentRects.every(function(parentRect) {
2290
- var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
2291
- var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
2507
+ thumbPos = $.fancybox.getTranslate($thumb);
2292
2508
 
2293
- return visiblePixelX > 0 && visiblePixelY > 0;
2294
- });
2509
+ btw = parseFloat($thumb.css("border-top-width") || 0);
2510
+ brw = parseFloat($thumb.css("border-right-width") || 0);
2511
+ bbw = parseFloat($thumb.css("border-bottom-width") || 0);
2512
+ blw = parseFloat($thumb.css("border-left-width") || 0);
2295
2513
 
2296
- return (
2297
- visibleInAllParents &&
2298
- elementRect.bottom > 0 &&
2299
- elementRect.right > 0 &&
2300
- elementRect.left < $(window).width() &&
2301
- elementRect.top < $(window).height()
2302
- );
2514
+ rez = {
2515
+ top: thumbPos.top + btw,
2516
+ left: thumbPos.left + blw,
2517
+ width: thumbPos.width - brw - blw,
2518
+ height: thumbPos.height - btw - bbw,
2519
+ scaleX: 1,
2520
+ scaleY: 1
2303
2521
  };
2304
2522
 
2305
- if (thumbPos && isElementVisible($thumb)) {
2306
- slidePos = self.$refs.stage.offset();
2307
-
2308
- rez = {
2309
- top: thumbPos.top - slidePos.top + parseFloat($thumb.css("border-top-width") || 0),
2310
- left: thumbPos.left - slidePos.left + parseFloat($thumb.css("border-left-width") || 0),
2311
- width: $thumb.width(),
2312
- height: $thumb.height(),
2313
- scaleX: 1,
2314
- scaleY: 1
2315
- };
2316
- }
2317
-
2318
- return rez;
2523
+ return thumbPos.width > 0 && thumbPos.height > 0 ? rez : false;
2319
2524
  },
2320
2525
 
2321
2526
  // Final adjustments after current gallery item is moved to position
@@ -2325,9 +2530,10 @@
2325
2530
  complete: function() {
2326
2531
  var self = this,
2327
2532
  current = self.current,
2328
- slides = {};
2533
+ slides = {},
2534
+ $el;
2329
2535
 
2330
- if (current.isMoved || !current.isLoaded) {
2536
+ if (self.isMoved() || !current.isLoaded) {
2331
2537
  return;
2332
2538
  }
2333
2539
 
@@ -2338,7 +2544,7 @@
2338
2544
 
2339
2545
  self.preload("inline");
2340
2546
 
2341
- // Trigger any CSS3 transiton inside the slide
2547
+ // Trigger any CSS transiton inside the slide
2342
2548
  forceRedraw(current.$slide);
2343
2549
 
2344
2550
  current.$slide.addClass("fancybox-slide--complete");
@@ -2363,19 +2569,35 @@
2363
2569
 
2364
2570
  self.trigger("afterShow");
2365
2571
 
2366
- // Play first html5 video/audio
2367
- current.$slide
2368
- .find("video,audio")
2369
- .filter(":visible:first")
2370
- .trigger("play");
2572
+ // Autoplay first html5 video/audio
2573
+ if (!!current.opts.video.autoStart) {
2574
+ current.$slide
2575
+ .find("video,audio")
2576
+ .filter(":visible:first")
2577
+ .trigger("play")
2578
+ .one("ended", function() {
2579
+ if (this.webkitExitFullscreen) {
2580
+ this.webkitExitFullscreen();
2581
+ }
2582
+
2583
+ self.next();
2584
+ });
2585
+ }
2371
2586
 
2372
2587
  // Try to focus on the first focusable element
2373
- if (
2374
- $(document.activeElement).is("[disabled]") ||
2375
- (current.opts.autoFocus && !(current.type == "image" || current.type === "iframe"))
2376
- ) {
2377
- self.focus();
2588
+ if (current.opts.autoFocus && current.contentType === "html") {
2589
+ // Look for the first input with autofocus attribute
2590
+ $el = current.$content.find("input[autofocus]:enabled:visible:first");
2591
+
2592
+ if ($el.length) {
2593
+ $el.trigger("focus");
2594
+ } else {
2595
+ self.focus(null, true);
2596
+ }
2378
2597
  }
2598
+
2599
+ // Avoid jumping
2600
+ current.$slide.scrollTop(0).scrollLeft(0);
2379
2601
  },
2380
2602
 
2381
2603
  // Preload next and previous slides
@@ -2383,40 +2605,84 @@
2383
2605
 
2384
2606
  preload: function(type) {
2385
2607
  var self = this,
2386
- next = self.slides[self.currPos + 1],
2387
- prev = self.slides[self.currPos - 1];
2608
+ prev,
2609
+ next;
2388
2610
 
2389
- if (next && next.type === type) {
2390
- self.loadSlide(next);
2611
+ if (self.group.length < 2) {
2612
+ return;
2391
2613
  }
2392
2614
 
2615
+ next = self.slides[self.currPos + 1];
2616
+ prev = self.slides[self.currPos - 1];
2617
+
2393
2618
  if (prev && prev.type === type) {
2394
2619
  self.loadSlide(prev);
2395
2620
  }
2621
+
2622
+ if (next && next.type === type) {
2623
+ self.loadSlide(next);
2624
+ }
2396
2625
  },
2397
2626
 
2398
2627
  // Try to find and focus on the first focusable element
2399
2628
  // ====================================================
2400
2629
 
2401
- focus: function() {
2402
- var current = this.current,
2403
- $el;
2630
+ focus: function(e, firstRun) {
2631
+ var self = this,
2632
+ focusableStr = [
2633
+ "a[href]",
2634
+ "area[href]",
2635
+ 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
2636
+ "select:not([disabled]):not([aria-hidden])",
2637
+ "textarea:not([disabled]):not([aria-hidden])",
2638
+ "button:not([disabled]):not([aria-hidden])",
2639
+ "iframe",
2640
+ "object",
2641
+ "embed",
2642
+ "[contenteditable]",
2643
+ '[tabindex]:not([tabindex^="-"])'
2644
+ ].join(","),
2645
+ focusableItems,
2646
+ focusedItemIndex;
2404
2647
 
2405
- if (this.isClosing) {
2648
+ if (self.isClosing) {
2406
2649
  return;
2407
2650
  }
2408
2651
 
2409
- if (current && current.isComplete && current.$content) {
2410
- // Look for first input with autofocus attribute
2411
- $el = current.$content.find("input[autofocus]:enabled:visible:first");
2652
+ if (e || !self.current || !self.current.isComplete) {
2653
+ // Focus on any element inside fancybox
2654
+ focusableItems = self.$refs.container.find("*:visible");
2655
+ } else {
2656
+ // Focus inside current slide
2657
+ focusableItems = self.current.$slide.find("*:visible" + (firstRun ? ":not(.fancybox-close-small)" : ""));
2658
+ }
2412
2659
 
2413
- if (!$el.length) {
2414
- $el = current.$content.find("button,:input,[tabindex],a").filter(":enabled:visible:first");
2415
- }
2660
+ focusableItems = focusableItems.filter(focusableStr).filter(function() {
2661
+ return $(this).css("visibility") !== "hidden" && !$(this).hasClass("disabled");
2662
+ });
2663
+
2664
+ if (focusableItems.length) {
2665
+ focusedItemIndex = focusableItems.index(document.activeElement);
2666
+
2667
+ if (e && e.shiftKey) {
2668
+ // Back tab
2669
+ if (focusedItemIndex < 0 || focusedItemIndex == 0) {
2670
+ e.preventDefault();
2416
2671
 
2417
- $el = $el && $el.length ? $el : current.$content;
2672
+ focusableItems.eq(focusableItems.length - 1).trigger("focus");
2673
+ }
2674
+ } else {
2675
+ // Outside or Forward tab
2676
+ if (focusedItemIndex < 0 || focusedItemIndex == focusableItems.length - 1) {
2677
+ if (e) {
2678
+ e.preventDefault();
2679
+ }
2418
2680
 
2419
- $el.trigger("focus");
2681
+ focusableItems.eq(0).trigger("focus");
2682
+ }
2683
+ }
2684
+ } else {
2685
+ self.$refs.container.trigger("focus");
2420
2686
  }
2421
2687
  },
2422
2688
 
@@ -2494,19 +2760,19 @@
2494
2760
  // If there are multiple instances, they will be set again by "activate" method
2495
2761
  self.removeEvents();
2496
2762
 
2497
- if (current.timouts) {
2498
- clearTimeout(current.timouts);
2499
- }
2500
-
2501
2763
  $content = current.$content;
2502
2764
  effect = current.opts.animationEffect;
2503
2765
  duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0;
2504
2766
 
2505
- // Remove other slides
2506
- current.$slide
2507
- .off(transitionEnd)
2508
- .removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated");
2767
+ current.$slide.removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated");
2768
+
2769
+ if (e !== true) {
2770
+ $.fancybox.stop(current.$slide);
2771
+ } else {
2772
+ effect = false;
2773
+ }
2509
2774
 
2775
+ // Remove other slides
2510
2776
  current.$slide
2511
2777
  .siblings()
2512
2778
  .trigger("onReset")
@@ -2514,20 +2780,23 @@
2514
2780
 
2515
2781
  // Trigger animations
2516
2782
  if (duration) {
2517
- self.$refs.container.removeClass("fancybox-is-open").addClass("fancybox-is-closing");
2783
+ self.$refs.container
2784
+ .removeClass("fancybox-is-open")
2785
+ .addClass("fancybox-is-closing")
2786
+ .css("transition-duration", duration + "ms");
2518
2787
  }
2519
2788
 
2520
2789
  // Clean up
2521
2790
  self.hideLoading(current);
2522
2791
 
2523
- self.hideControls();
2792
+ self.hideControls(true);
2524
2793
 
2525
2794
  self.updateCursor();
2526
2795
 
2527
2796
  // Check if possible to zoom-out
2528
2797
  if (
2529
2798
  effect === "zoom" &&
2530
- !(e !== true && $content && duration && current.type === "image" && !current.hasError && (end = self.getThumbPos(current)))
2799
+ !($content && duration && current.type === "image" && !self.isMoved() && !current.hasError && (end = self.getThumbPos(current)))
2531
2800
  ) {
2532
2801
  effect = "fade";
2533
2802
  }
@@ -2567,19 +2836,19 @@
2567
2836
  }
2568
2837
 
2569
2838
  if (effect && duration) {
2839
+ $.fancybox.animate(
2840
+ current.$slide.addClass("fancybox-slide--previous").removeClass("fancybox-slide--current"),
2841
+ "fancybox-animated fancybox-fx-" + effect,
2842
+ duration,
2843
+ done
2844
+ );
2845
+ } else {
2570
2846
  // If skip animation
2571
2847
  if (e === true) {
2572
2848
  setTimeout(done, duration);
2573
2849
  } else {
2574
- $.fancybox.animate(
2575
- current.$slide.removeClass("fancybox-slide--current"),
2576
- "fancybox-animated fancybox-slide--previous fancybox-fx-" + effect,
2577
- duration,
2578
- done
2579
- );
2850
+ done();
2580
2851
  }
2581
- } else {
2582
- done();
2583
2852
  }
2584
2853
 
2585
2854
  return true;
@@ -2590,9 +2859,10 @@
2590
2859
 
2591
2860
  cleanUp: function(e) {
2592
2861
  var self = this,
2593
- $body = $("body"),
2594
2862
  instance,
2595
- scrollTop;
2863
+ $focus = self.current.opts.$orig,
2864
+ x,
2865
+ y;
2596
2866
 
2597
2867
  self.current.$slide.trigger("onReset");
2598
2868
 
@@ -2601,8 +2871,21 @@
2601
2871
  self.trigger("afterClose", e);
2602
2872
 
2603
2873
  // Place back focus
2604
- if (self.$lastFocus && !!self.current.opts.backFocus) {
2605
- self.$lastFocus.trigger("focus");
2874
+ if (!!self.current.opts.backFocus) {
2875
+ if (!$focus || !$focus.length || !$focus.is(":visible")) {
2876
+ $focus = self.$trigger;
2877
+ }
2878
+
2879
+ if ($focus && $focus.length) {
2880
+ x = window.scrollX;
2881
+ y = window.scrollY;
2882
+
2883
+ $focus.trigger("focus");
2884
+
2885
+ $("html, body")
2886
+ .scrollTop(y)
2887
+ .scrollLeft(x);
2888
+ }
2606
2889
  }
2607
2890
 
2608
2891
  self.current = null;
@@ -2613,7 +2896,7 @@
2613
2896
  if (instance) {
2614
2897
  instance.activate();
2615
2898
  } else {
2616
- $body.removeClass("fancybox-active compensate-for-scrollbar");
2899
+ $("body").removeClass("fancybox-active compensate-for-scrollbar");
2617
2900
 
2618
2901
  $("#fancybox-style-noscroll").remove();
2619
2902
  }
@@ -2654,20 +2937,20 @@
2654
2937
  // Update infobar values, navigation button states and reveal caption
2655
2938
  // ==================================================================
2656
2939
 
2657
- updateControls: function(force) {
2940
+ updateControls: function() {
2658
2941
  var self = this,
2659
2942
  current = self.current,
2660
2943
  index = current.index,
2661
- caption = current.opts.caption,
2662
2944
  $container = self.$refs.container,
2663
- $caption = self.$refs.caption;
2945
+ $caption = self.$refs.caption,
2946
+ caption = current.opts.caption;
2664
2947
 
2665
2948
  // Recalculate content dimensions
2666
2949
  current.$slide.trigger("refresh");
2667
2950
 
2668
2951
  self.$caption = caption && caption.length ? $caption.html(caption) : null;
2669
2952
 
2670
- if (!self.isHiddenControls && !self.isIdle) {
2953
+ if (!self.hasHiddenControls && !self.isIdle) {
2671
2954
  self.showControls();
2672
2955
  }
2673
2956
 
@@ -2675,8 +2958,8 @@
2675
2958
  $container.find("[data-fancybox-count]").html(self.group.length);
2676
2959
  $container.find("[data-fancybox-index]").html(index + 1);
2677
2960
 
2678
- $container.find("[data-fancybox-prev]").toggleClass("disabled", !current.opts.loop && index <= 0);
2679
- $container.find("[data-fancybox-next]").toggleClass("disabled", !current.opts.loop && index >= self.group.length - 1);
2961
+ $container.find("[data-fancybox-prev]").prop("disabled", !current.opts.loop && index <= 0);
2962
+ $container.find("[data-fancybox-next]").prop("disabled", !current.opts.loop && index >= self.group.length - 1);
2680
2963
 
2681
2964
  if (current.type === "image") {
2682
2965
  // Re-enable buttons; update download button source
@@ -2690,15 +2973,33 @@
2690
2973
  } else if (current.opts.toolbar) {
2691
2974
  $container.find("[data-fancybox-download],[data-fancybox-zoom]").hide();
2692
2975
  }
2976
+
2977
+ // Make sure focus is not on disabled button/element
2978
+ if ($(document.activeElement).is(":hidden,[disabled]")) {
2979
+ self.$refs.container.trigger("focus");
2980
+ }
2693
2981
  },
2694
2982
 
2695
2983
  // Hide toolbar and caption
2696
2984
  // ========================
2697
2985
 
2698
- hideControls: function() {
2699
- this.isHiddenControls = true;
2986
+ hideControls: function(andCaption) {
2987
+ var self = this,
2988
+ arr = ["infobar", "toolbar", "nav"];
2989
+
2990
+ if (andCaption || !self.current.opts.preventCaptionOverlap) {
2991
+ arr.push("caption");
2992
+ }
2993
+
2994
+ this.$refs.container.removeClass(
2995
+ arr
2996
+ .map(function(i) {
2997
+ return "fancybox-show-" + i;
2998
+ })
2999
+ .join(" ")
3000
+ );
2700
3001
 
2701
- this.$refs.container.removeClass("fancybox-show-infobar fancybox-show-toolbar fancybox-show-caption fancybox-show-nav");
3002
+ this.hasHiddenControls = true;
2702
3003
  },
2703
3004
 
2704
3005
  showControls: function() {
@@ -2706,27 +3007,22 @@
2706
3007
  opts = self.current ? self.current.opts : self.opts,
2707
3008
  $container = self.$refs.container;
2708
3009
 
2709
- self.isHiddenControls = false;
3010
+ self.hasHiddenControls = false;
2710
3011
  self.idleSecondsCounter = 0;
2711
3012
 
2712
3013
  $container
2713
3014
  .toggleClass("fancybox-show-toolbar", !!(opts.toolbar && opts.buttons))
2714
3015
  .toggleClass("fancybox-show-infobar", !!(opts.infobar && self.group.length > 1))
3016
+ .toggleClass("fancybox-show-caption", !!self.$caption)
2715
3017
  .toggleClass("fancybox-show-nav", !!(opts.arrows && self.group.length > 1))
2716
3018
  .toggleClass("fancybox-is-modal", !!opts.modal);
2717
-
2718
- if (self.$caption) {
2719
- $container.addClass("fancybox-show-caption ");
2720
- } else {
2721
- $container.removeClass("fancybox-show-caption");
2722
- }
2723
3019
  },
2724
3020
 
2725
3021
  // Toggle toolbar and caption
2726
3022
  // ==========================
2727
3023
 
2728
3024
  toggleControls: function() {
2729
- if (this.isHiddenControls) {
3025
+ if (this.hasHiddenControls) {
2730
3026
  this.showControls();
2731
3027
  } else {
2732
3028
  this.hideControls();
@@ -2784,9 +3080,8 @@
2784
3080
  instance.close();
2785
3081
 
2786
3082
  // Try to find and close next instance
2787
-
2788
3083
  if (all === true) {
2789
- this.close();
3084
+ this.close(all);
2790
3085
  }
2791
3086
  }
2792
3087
  },
@@ -2803,8 +3098,7 @@
2803
3098
  // Try to detect mobile devices
2804
3099
  // ============================
2805
3100
 
2806
- isMobile:
2807
- document.createTouch !== undefined && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
3101
+ isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
2808
3102
 
2809
3103
  // Detect if 'translate3d' support is available
2810
3104
  // ============================================
@@ -2869,7 +3163,9 @@
2869
3163
  }
2870
3164
 
2871
3165
  if (props.scaleX !== undefined && props.scaleY !== undefined) {
2872
- str = (str.length ? str + " " : "") + "scale(" + props.scaleX + ", " + props.scaleY + ")";
3166
+ str += " scale(" + props.scaleX + ", " + props.scaleY + ")";
3167
+ } else if (props.scaleX !== undefined) {
3168
+ str += " scaleX(" + props.scaleX + ")";
2873
3169
  }
2874
3170
 
2875
3171
  if (str.length) {
@@ -2895,18 +3191,17 @@
2895
3191
  // =============================
2896
3192
 
2897
3193
  animate: function($el, to, duration, callback, leaveAnimationName) {
2898
- var final = false;
3194
+ var self = this,
3195
+ from;
2899
3196
 
2900
3197
  if ($.isFunction(duration)) {
2901
3198
  callback = duration;
2902
3199
  duration = null;
2903
3200
  }
2904
3201
 
2905
- if (!$.isPlainObject(to)) {
2906
- $el.removeAttr("style");
2907
- }
3202
+ self.stop($el);
2908
3203
 
2909
- $.fancybox.stop($el);
3204
+ from = self.getTranslate($el);
2910
3205
 
2911
3206
  $el.on(transitionEnd, function(e) {
2912
3207
  // Skip events from child elements and z-index change
@@ -2914,15 +3209,22 @@
2914
3209
  return;
2915
3210
  }
2916
3211
 
2917
- $.fancybox.stop($el);
3212
+ self.stop($el);
2918
3213
 
2919
- if (final) {
2920
- $.fancybox.setTranslate($el, final);
3214
+ if ($.isNumeric(duration)) {
3215
+ $el.css("transition-duration", "");
2921
3216
  }
2922
3217
 
2923
3218
  if ($.isPlainObject(to)) {
2924
- if (leaveAnimationName === false) {
2925
- $el.removeAttr("style");
3219
+ if (to.scaleX !== undefined && to.scaleY !== undefined) {
3220
+ self.setTranslate($el, {
3221
+ top: to.top,
3222
+ left: to.left,
3223
+ width: from.width * to.scaleX,
3224
+ height: from.height * to.scaleY,
3225
+ scaleX: 1,
3226
+ scaleY: 1
3227
+ });
2926
3228
  }
2927
3229
  } else if (leaveAnimationName !== true) {
2928
3230
  $el.removeClass(to);
@@ -2940,13 +3242,6 @@
2940
3242
  // Start animation by changing CSS properties or class name
2941
3243
  if ($.isPlainObject(to)) {
2942
3244
  if (to.scaleX !== undefined && to.scaleY !== undefined) {
2943
- final = $.extend({}, to, {
2944
- width: $el.width() * to.scaleX,
2945
- height: $el.height() * to.scaleY,
2946
- scaleX: 1,
2947
- scaleY: 1
2948
- });
2949
-
2950
3245
  delete to.width;
2951
3246
  delete to.height;
2952
3247
 
@@ -2964,16 +3259,20 @@
2964
3259
  $el.data(
2965
3260
  "timer",
2966
3261
  setTimeout(function() {
2967
- $el.trigger("transitionend");
2968
- }, duration + 16)
3262
+ $el.trigger(transitionEnd);
3263
+ }, duration + 33)
2969
3264
  );
2970
3265
  },
2971
3266
 
2972
- stop: function($el) {
3267
+ stop: function($el, callCallback) {
2973
3268
  if ($el && $el.length) {
2974
3269
  clearTimeout($el.data("timer"));
2975
3270
 
2976
- $el.off("transitionend").css("transition-duration", "");
3271
+ if (callCallback) {
3272
+ $el.trigger(transitionEnd);
3273
+ }
3274
+
3275
+ $el.off(transitionEnd).css("transition-duration", "");
2977
3276
 
2978
3277
  $el.parent().removeClass("fancybox-is-scaling");
2979
3278
  }
@@ -2987,7 +3286,8 @@
2987
3286
  var items = [],
2988
3287
  index = 0,
2989
3288
  $target,
2990
- value;
3289
+ value,
3290
+ instance;
2991
3291
 
2992
3292
  // Avoid opening multiple times
2993
3293
  if (e && e.isDefaultPrevented()) {
@@ -2996,27 +3296,44 @@
2996
3296
 
2997
3297
  e.preventDefault();
2998
3298
 
2999
- opts = e && e.data ? e.data.options : opts || {};
3299
+ opts = opts || {};
3000
3300
 
3001
- $target = opts.$target || $(e.currentTarget);
3002
- value = $target.attr("data-fancybox") || "";
3301
+ if (e && e.data) {
3302
+ opts = mergeOpts(e.data.options, opts);
3303
+ }
3304
+
3305
+ $target = opts.$target || $(e.currentTarget).trigger("blur");
3306
+ instance = $.fancybox.getInstance();
3003
3307
 
3004
- // Get all related items and find index for clicked one
3005
- if (value) {
3006
- items = opts.selector ? $(opts.selector) : e.data ? e.data.items : [];
3007
- items = items.length ? items.filter('[data-fancybox="' + value + '"]') : $('[data-fancybox="' + value + '"]');
3308
+ if (instance && instance.$trigger && instance.$trigger.is($target)) {
3309
+ return;
3310
+ }
3008
3311
 
3009
- index = items.index($target);
3312
+ if (opts.selector) {
3313
+ items = $(opts.selector);
3314
+ } else {
3315
+ // Get all related items and find index for clicked one
3316
+ value = $target.attr("data-fancybox") || "";
3010
3317
 
3011
- // Sometimes current item can not be found (for example, if some script clones items)
3012
- if (index < 0) {
3013
- index = 0;
3318
+ if (value) {
3319
+ items = e.data ? e.data.items : [];
3320
+ items = items.length ? items.filter('[data-fancybox="' + value + '"]') : $('[data-fancybox="' + value + '"]');
3321
+ } else {
3322
+ items = [$target];
3014
3323
  }
3015
- } else {
3016
- items = [$target];
3017
3324
  }
3018
3325
 
3019
- $.fancybox.open(items, opts, index);
3326
+ index = $(items).index($target);
3327
+
3328
+ // Sometimes current item can not be found
3329
+ if (index < 0) {
3330
+ index = 0;
3331
+ }
3332
+
3333
+ instance = $.fancybox.open(items, opts, index);
3334
+
3335
+ // Save last active element
3336
+ instance.$trigger = $target;
3020
3337
  }
3021
3338
 
3022
3339
  // Create a jQuery plugin
@@ -3055,10 +3372,40 @@
3055
3372
  // Enable "trigger elements"
3056
3373
  // =========================
3057
3374
 
3058
- $D.on("click.fb-start", "[data-trigger]", function(e) {
3059
- _run(e, {
3060
- $target: $('[data-fancybox="' + $(e.currentTarget).attr("data-trigger") + '"]').eq($(e.currentTarget).attr("data-index") || 0),
3061
- $trigger: $(this)
3062
- });
3375
+ $D.on("click.fb-start", "[data-fancybox-trigger]", function(e) {
3376
+ $('[data-fancybox="' + $(this).attr("data-fancybox-trigger") + '"]')
3377
+ .eq($(this).attr("data-fancybox-index") || 0)
3378
+ .trigger("click.fb-start", {
3379
+ $trigger: $(this)
3380
+ });
3063
3381
  });
3064
- })(window, document, window.jQuery || jQuery);
3382
+
3383
+ // Track focus event for better accessibility styling
3384
+ // ==================================================
3385
+ (function() {
3386
+ var buttonStr = ".fancybox-button",
3387
+ focusStr = "fancybox-focus",
3388
+ $pressed = null;
3389
+
3390
+ $D.on("mousedown mouseup focus blur", buttonStr, function(e) {
3391
+ switch (e.type) {
3392
+ case "mousedown":
3393
+ $pressed = $(this);
3394
+ break;
3395
+ case "mouseup":
3396
+ $pressed = null;
3397
+ break;
3398
+ case "focusin":
3399
+ $(buttonStr).removeClass(focusStr);
3400
+
3401
+ if (!$(this).is($pressed) && !$(this).is("[disabled]")) {
3402
+ $(this).addClass(focusStr);
3403
+ }
3404
+ break;
3405
+ case "focusout":
3406
+ $(buttonStr).removeClass(focusStr);
3407
+ break;
3408
+ }
3409
+ });
3410
+ })();
3411
+ })(window, document, jQuery);